Miscellaneous changes while enabling iOS support

Put all of the logic for discovering iOS in one place in ios.h.

Make TAR_DEBUG configurable and default it to 0.

Various whitespace style pickiness.
This commit is contained in:
Howard Hinnant
2016-08-23 20:55:13 -04:00
parent 927fc619ef
commit 7e9d9075d9
3 changed files with 354 additions and 312 deletions

7
ios.h
View File

@@ -27,6 +27,9 @@
#ifndef ios_hpp
#define ios_hpp
#if __APPLE__
# include <TargetConditionals.h>
# if TARGET_OS_IPHONE
# include <string>
namespace date
@@ -39,4 +42,8 @@ std::string get_tzdata_path();
} // namespace iOSUtils
} // namespace date
# endif // TARGET_OS_IPHONE
#else // !__APPLE__
# define TARGET_OS_IPHONE 0
#endif // !__APPLE__
#endif // ios_hpp

179
ios.mm
View File

@@ -22,7 +22,9 @@
// SOFTWARE.
//
#ifdef TARGET_OS_IPHONE
#include "ios.h"
#if TARGET_OS_IPHONE
#include <Foundation/Foundation.h>
@@ -30,11 +32,10 @@
#include <zlib.h>
#include <sys/stat.h>
#include "ios.h"
#ifndef TAR_DEBUG
# define TAR_DEBUG 0
#endif
#define TAR_DEBUG
#define DIR_NAME "tzdata"
#define INTERNAL_DIR "Library/tzdata"
#define TARGZ_EXTENSION "tar.gz"
@@ -50,7 +51,8 @@ namespace date
namespace iOSUtils
{
struct TarInfo {
struct TarInfo
{
char objType;
std::string objName;
int64_t realContentSize; // writable size without padding zeroes
@@ -62,26 +64,31 @@ namespace date
bool extractTzdata(CFURLRef homeUrl, CFURLRef archiveUrl, std::string destPath);
TarInfo getTarObjectInfo(CFReadStreamRef readStream, int64_t location);
std::string getTarObject(CFReadStreamRef readStream, int64_t size);
bool writeFile(CFURLRef tzdataUrl, std::string fileName, std::string data, int64_t realContentSize);
bool writeFile(CFURLRef tzdataUrl, std::string fileName, std::string data,
int64_t realContentSize);
std::string
date::iOSUtils::get_tzdata_path()
{
CFURLRef ref = CFCopyHomeDirectoryURL();
CFStringRef homePath = CFURLCopyPath(CFCopyHomeDirectoryURL());
std::string tzdata_path(std::string(convertCFStringRefPathToCStringPath(homePath)) + INTERNAL_DIR);
std::string tzdata_path(std::string(convertCFStringRefPathToCStringPath(homePath)) +
INTERNAL_DIR);
if (access(tzdata_path.c_str(), F_OK) == 0) {
#ifdef TAR_DEBUG
if (access(tzdata_path.c_str(), F_OK) == 0)
{
#if TAR_DEBUG
printf("tzdata exists\n");
#endif
return tzdata_path;
}
CFBundleRef mainBundle = CFBundleGetMainBundle();
CFArrayRef paths = CFBundleCopyResourceURLsOfType(mainBundle, CFSTR(TARGZ_EXTENSION), NULL);
CFArrayRef paths = CFBundleCopyResourceURLsOfType(mainBundle, CFSTR(TARGZ_EXTENSION),
NULL);
if (CFArrayGetCount(paths) != 0) {
if (CFArrayGetCount(paths) != 0)
{
// get archive path, assume there is no other tar.gz in bundle
CFURLRef archiveUrl = static_cast<CFURLRef>(CFArrayGetValueAtIndex(paths, 0));
CFStringRef archiveName= CFURLCopyPath(archiveUrl);
@@ -93,7 +100,8 @@ namespace date
return tzdata_path;
}
char* convertCFStringRefPathToCStringPath(CFStringRef ref)
char*
convertCFStringRefPathToCStringPath(CFStringRef ref)
{
CFIndex bufferSize = CFStringGetMaximumSizeOfFileSystemRepresentation(ref);
char *buffer = new char[bufferSize];
@@ -106,20 +114,27 @@ namespace date
const char *TAR_TMP_PATH = "/tmp.tar";
// create Library path
CFStringRef libraryStr = CFStringCreateWithCString(NULL, "Library", CFStringGetSystemEncoding());
CFURLRef libraryUrl = CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault, homeUrl, libraryStr, false);
CFStringRef libraryStr = CFStringCreateWithCString(NULL, "Library",
CFStringGetSystemEncoding());
CFURLRef libraryUrl = CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault,
homeUrl, libraryStr,
false);
// create tzdata path
CFStringRef tzdataPathRef = CFStringCreateWithCString(NULL, INTERNAL_DIR, CFStringGetSystemEncoding());
CFURLRef tzdataPathUrl = CFURLCreateCopyAppendingPathComponent(NULL, homeUrl, tzdataPathRef, false);
CFStringRef tzdataPathRef = CFStringCreateWithCString(NULL, INTERNAL_DIR,
CFStringGetSystemEncoding());
CFURLRef tzdataPathUrl = CFURLCreateCopyAppendingPathComponent(NULL, homeUrl,
tzdataPathRef, false);
// create src archive path
CFStringRef archivePath = CFURLCopyPath(archiveUrl);
gzFile tarFile = gzopen(convertCFStringRefPathToCStringPath(archivePath), "rb");
// create tar unpacking path
CFStringRef tarName = CFStringCreateWithCString(NULL, TAR_TMP_PATH, CFStringGetSystemEncoding());
CFURLRef tarUrl = CFURLCreateCopyAppendingPathComponent(NULL, libraryUrl, tarName, false);
CFStringRef tarName = CFStringCreateWithCString(NULL, TAR_TMP_PATH,
CFStringGetSystemEncoding());
CFURLRef tarUrl = CFURLCreateCopyAppendingPathComponent(NULL, libraryUrl, tarName,
false);
const char *tarPath = convertCFStringRefPathToCStringPath(CFURLCopyPath(tarUrl));
// create tzdata directory
@@ -129,19 +144,24 @@ namespace date
CFWriteStreamRef writeStream = CFWriteStreamCreateWithFile(NULL, tarUrl);
bool success = true;
if (!CFWriteStreamOpen(writeStream)) {
if (!CFWriteStreamOpen(writeStream))
{
CFStreamError err = CFWriteStreamGetError(writeStream);
if (err.domain == kCFStreamErrorDomainPOSIX) {
if (err.domain == kCFStreamErrorDomainPOSIX)
{
printf("kCFStreamErrorDomainPOSIX %i\n", err.error);
} else if(err.domain == kCFStreamErrorDomainMacOSStatus) {
}
else if(err.domain == kCFStreamErrorDomainMacOSStatus)
{
printf("kCFStreamErrorDomainMacOSStatus %i\n", err.error);
}
success = false;
}
if (!success) {
if (!success)
{
remove(tarPath);
return false;
}
@@ -151,40 +171,48 @@ namespace date
unsigned int bufferLength = 1024 * 256; // 256Kb
void *buffer = malloc(bufferLength);
while (true) {
while (true)
{
int readBytes = gzread(tarFile, buffer, bufferLength);
if (readBytes > 0) {
CFIndex writtenBytes = CFWriteStreamWrite(writeStream, (unsigned char*)buffer, readBytes);
if (readBytes > 0)
{
CFIndex writtenBytes = CFWriteStreamWrite(writeStream, (unsigned char*)buffer,
readBytes);
if (writtenBytes < 0) {
if (writtenBytes < 0)
{
CFStreamError err = CFWriteStreamGetError(writeStream);
printf("write stream error %i\n", err.error);
success = false;
break;
}
} else if (readBytes == 0) {
}
else if (readBytes == 0)
{
break;
} else {
if (readBytes == -1) {
}
else if (readBytes == -1)
{
printf("decompression failed\n");
success = false;
break;
}
else {
else
{
printf("unexpected zlib state\n");
success = false;
break;
}
}
}
CFWriteStreamClose(writeStream);
CFRelease(writeStream);
free(buffer);
gzclose(tarFile);
if (!success) {
if (!success)
{
remove(tarPath);
return false;
}
@@ -196,7 +224,8 @@ namespace date
// get file size
struct stat stat_buf;
int res = stat(tarPath, &stat_buf);
if (res != 0) {
if (res != 0)
{
printf("error file size\n");
remove(tarPath);
return false;
@@ -206,19 +235,24 @@ namespace date
// create read stream
CFReadStreamRef readStream = CFReadStreamCreateWithFile(kCFAllocatorDefault, tarUrl);
if (!CFReadStreamOpen(readStream)) {
if (!CFReadStreamOpen(readStream))
{
CFStreamError err = CFReadStreamGetError(readStream);
if (err.domain == kCFStreamErrorDomainPOSIX) {
if (err.domain == kCFStreamErrorDomainPOSIX)
{
printf("kCFStreamErrorDomainPOSIX %i", err.error);
} else if(err.domain == kCFStreamErrorDomainMacOSStatus) {
}
else if(err.domain == kCFStreamErrorDomainMacOSStatus)
{
printf("kCFStreamErrorDomainMacOSStatus %i", err.error);
}
success = false;
}
if (!success) {
if (!success)
{
CFRelease(readStream);
remove(tarPath);
return false;
@@ -228,29 +262,31 @@ namespace date
long size = 0;
// process files
while (location < tarSize) {
while (location < tarSize)
{
TarInfo info = getTarObjectInfo(readStream, location);
if (!info.success || info.realContentSize == 0) {
if (!info.success || info.realContentSize == 0)
{
break; // something wrong or all files are read
}
switch (info.objType) {
switch (info.objType)
{
case '0': // file
case '\0': //
{
std::string obj = getTarObject(readStream, info.blocksContentSize);
#ifdef TAR_DEBUG
#if TAR_DEBUG
size += info.realContentSize;
printf("#%i %s file size %lld written total %ld from %lld\n",
++count, info.objName.c_str(), info.realContentSize, size, tarSize);
printf("#%i %s file size %lld written total %ld from %lld\n", ++count,
info.objName.c_str(), info.realContentSize, size, tarSize);
#endif
writeFile(tzdataPathUrl, info.objName, obj, info.realContentSize);
location += info.blocksContentSize;
break;
}
}
}
@@ -262,7 +298,8 @@ namespace date
return true;
}
TarInfo getTarObjectInfo(CFReadStreamRef readStream, int64_t location)
TarInfo
getTarObjectInfo(CFReadStreamRef readStream, int64_t location)
{
int64_t length = TAR_BLOCK_SIZE;
uint8_t buffer[length];
@@ -276,7 +313,8 @@ namespace date
bytesRead = CFReadStreamRead(readStream, buffer, length);
if (bytesRead < 0) {
if (bytesRead < 0)
{
CFStreamError err = CFReadStreamGetError(readStream);
printf("error reading tar object info %i", err.error);
return {false};
@@ -295,13 +333,15 @@ namespace date
return {type, std::string(name), realSize, blocksSize, true};
}
std::string getTarObject(CFReadStreamRef readStream, int64_t size)
std::string
getTarObject(CFReadStreamRef readStream, int64_t size)
{
uint8_t buffer[size];
CFIndex bytesRead = CFReadStreamRead(readStream, buffer, size);
if (bytesRead < 0) {
if (bytesRead < 0)
{
CFStreamError err = CFReadStreamGetError(readStream);
printf("error reading tar object info %i", err.error);
}
@@ -309,20 +349,28 @@ namespace date
return std::string((char *)buffer);
}
bool writeFile(CFURLRef tzdataUrl, std::string fileName, std::string data, int64_t realContentSize)
bool
writeFile(CFURLRef tzdataUrl, std::string fileName, std::string data,
int64_t realContentSize)
{
// create stream
CFStringRef fileNameRef = CFStringCreateWithCString(NULL, fileName.c_str(), CFStringGetSystemEncoding());
CFURLRef url = CFURLCreateCopyAppendingPathComponent(NULL, tzdataUrl, fileNameRef, false);
CFStringRef fileNameRef = CFStringCreateWithCString(NULL, fileName.c_str(),
CFStringGetSystemEncoding());
CFURLRef url = CFURLCreateCopyAppendingPathComponent(NULL, tzdataUrl, fileNameRef,
false);
CFWriteStreamRef writeStream = CFWriteStreamCreateWithFile(NULL, url);
// open stream
if (!CFWriteStreamOpen(writeStream)) {
if (!CFWriteStreamOpen(writeStream))
{
CFStreamError err = CFWriteStreamGetError(writeStream);
if (err.domain == kCFStreamErrorDomainPOSIX) {
if (err.domain == kCFStreamErrorDomainPOSIX)
{
printf("kCFStreamErrorDomainPOSIX %i\n", err.error);
} else if(err.domain == kCFStreamErrorDomainMacOSStatus) {
}
else if(err.domain == kCFStreamErrorDomainMacOSStatus)
{
printf("kCFStreamErrorDomainMacOSStatus %i\n", err.error);
}
@@ -338,7 +386,8 @@ namespace date
// write
CFIndex writtenBytes = CFWriteStreamWrite(writeStream, trimmedData, realContentSize);
if (writtenBytes < 0) {
if (writtenBytes < 0)
{
CFStreamError err = CFWriteStreamGetError(writeStream);
printf("write stream error %i\n", err.error);
}
@@ -350,19 +399,7 @@ namespace date
return true;
}
}
}
#endif
} // namespace iOSUtils
} // namespace date
#endif // TARGET_OS_IPHONE

10
tz.cpp
View File

@@ -75,6 +75,7 @@
#endif // _WIN32
#include "tz_private.h"
#include "ios.h"
#include <algorithm>
#include <cctype>
@@ -117,9 +118,6 @@
# endif //!USE_SHELL_API
#endif // !WIN32
#ifdef TARGET_OS_IPHONE
#include "ios.h"
#endif
#if HAS_REMOTE_API
// Note curl includes windows.h so we must include curl AFTER definitions of things
@@ -184,15 +182,15 @@ static
std::string
expand_path(std::string path)
{
#ifndef TARGET_OS_IPHONE
#if TARGET_OS_IPHONE
return date::iOSUtils::get_tzdata_path();
#else
::wordexp_t w{};
::wordexp(path.c_str(), &w, 0);
assert(w.we_wordc == 1);
path = w.we_wordv[0];
::wordfree(&w);
return path;
#else
return date::iOSUtils::get_tzdata_path();
#endif
}