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

23
ios.h
View File

@@ -27,16 +27,23 @@
#ifndef ios_hpp #ifndef ios_hpp
#define ios_hpp #define ios_hpp
#include <string> #if __APPLE__
# include <TargetConditionals.h>
# if TARGET_OS_IPHONE
# include <string>
namespace date namespace date
{ {
namespace iOSUtils namespace iOSUtils
{ {
std::string get_tzdata_path(); std::string get_tzdata_path();
} // namespace iOSUtils } // namespace iOSUtils
} // namespace date } // namespace date
# endif // TARGET_OS_IPHONE
#else // !__APPLE__
# define TARGET_OS_IPHONE 0
#endif // !__APPLE__
#endif // ios_hpp #endif // ios_hpp

221
ios.mm
View File

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

10
tz.cpp
View File

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