mirror of
https://github.com/HowardHinnant/date.git
synced 2025-01-14 01:37:57 +08:00
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:
parent
927fc619ef
commit
7e9d9075d9
23
ios.h
23
ios.h
@ -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
|
||||||
|
633
ios.mm
633
ios.mm
@ -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,322 +48,358 @@
|
|||||||
|
|
||||||
namespace date
|
namespace date
|
||||||
{
|
{
|
||||||
namespace iOSUtils
|
namespace iOSUtils
|
||||||
|
{
|
||||||
|
|
||||||
|
struct TarInfo
|
||||||
|
{
|
||||||
|
char objType;
|
||||||
|
std::string objName;
|
||||||
|
int64_t realContentSize; // writable size without padding zeroes
|
||||||
|
int64_t blocksContentSize; // adjusted size to 512 bytes blocks
|
||||||
|
bool success;
|
||||||
|
};
|
||||||
|
|
||||||
|
char* convertCFStringRefPathToCStringPath(CFStringRef ref);
|
||||||
|
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);
|
||||||
|
|
||||||
|
std::string
|
||||||
|
date::iOSUtils::get_tzdata_path()
|
||||||
|
{
|
||||||
|
CFURLRef ref = CFCopyHomeDirectoryURL();
|
||||||
|
CFStringRef homePath = CFURLCopyPath(CFCopyHomeDirectoryURL());
|
||||||
|
std::string tzdata_path(std::string(convertCFStringRefPathToCStringPath(homePath)) +
|
||||||
|
INTERNAL_DIR);
|
||||||
|
|
||||||
|
if (access(tzdata_path.c_str(), F_OK) == 0)
|
||||||
{
|
{
|
||||||
|
#if TAR_DEBUG
|
||||||
struct TarInfo {
|
printf("tzdata exists\n");
|
||||||
char objType;
|
|
||||||
std::string objName;
|
|
||||||
int64_t realContentSize; // writable size without padding zeroes
|
|
||||||
int64_t blocksContentSize; // adjusted size to 512 bytes blocks
|
|
||||||
bool success;
|
|
||||||
};
|
|
||||||
|
|
||||||
char* convertCFStringRefPathToCStringPath(CFStringRef ref);
|
|
||||||
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);
|
|
||||||
|
|
||||||
std::string
|
|
||||||
date::iOSUtils::get_tzdata_path()
|
|
||||||
{
|
|
||||||
CFURLRef ref = CFCopyHomeDirectoryURL();
|
|
||||||
CFStringRef homePath = CFURLCopyPath(CFCopyHomeDirectoryURL());
|
|
||||||
std::string tzdata_path(std::string(convertCFStringRefPathToCStringPath(homePath)) + INTERNAL_DIR);
|
|
||||||
|
|
||||||
if (access(tzdata_path.c_str(), F_OK) == 0) {
|
|
||||||
#ifdef TAR_DEBUG
|
|
||||||
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) {
|
|
||||||
// get archive path, assume there is no other tar.gz in bundle
|
if (CFArrayGetCount(paths) != 0)
|
||||||
CFURLRef archiveUrl = static_cast<CFURLRef>(CFArrayGetValueAtIndex(paths, 0));
|
{
|
||||||
CFStringRef archiveName= CFURLCopyPath(archiveUrl);
|
// get archive path, assume there is no other tar.gz in bundle
|
||||||
archiveUrl = CFBundleCopyResourceURL(mainBundle, archiveName, NULL, NULL);
|
CFURLRef archiveUrl = static_cast<CFURLRef>(CFArrayGetValueAtIndex(paths, 0));
|
||||||
|
CFStringRef archiveName= CFURLCopyPath(archiveUrl);
|
||||||
extractTzdata(CFCopyHomeDirectoryURL(), archiveUrl, tzdata_path);
|
archiveUrl = CFBundleCopyResourceURL(mainBundle, archiveName, NULL, NULL);
|
||||||
}
|
|
||||||
|
extractTzdata(CFCopyHomeDirectoryURL(), archiveUrl, tzdata_path);
|
||||||
return tzdata_path;
|
}
|
||||||
|
|
||||||
|
return tzdata_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
char*
|
||||||
|
convertCFStringRefPathToCStringPath(CFStringRef ref)
|
||||||
|
{
|
||||||
|
CFIndex bufferSize = CFStringGetMaximumSizeOfFileSystemRepresentation(ref);
|
||||||
|
char *buffer = new char[bufferSize];
|
||||||
|
CFStringGetFileSystemRepresentation(ref, buffer, bufferSize);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool extractTzdata(CFURLRef homeUrl, CFURLRef archiveUrl, std::string destPath)
|
||||||
|
{
|
||||||
|
const char *TAR_TMP_PATH = "/tmp.tar";
|
||||||
|
|
||||||
|
// create Library path
|
||||||
|
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);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
const char *tarPath = convertCFStringRefPathToCStringPath(CFURLCopyPath(tarUrl));
|
||||||
|
|
||||||
|
// create tzdata directory
|
||||||
|
mkdir(destPath.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
|
||||||
|
|
||||||
|
// create stream
|
||||||
|
CFWriteStreamRef writeStream = CFWriteStreamCreateWithFile(NULL, tarUrl);
|
||||||
|
bool success = true;
|
||||||
|
|
||||||
|
if (!CFWriteStreamOpen(writeStream))
|
||||||
|
{
|
||||||
|
CFStreamError err = CFWriteStreamGetError(writeStream);
|
||||||
|
|
||||||
|
if (err.domain == kCFStreamErrorDomainPOSIX)
|
||||||
|
{
|
||||||
|
printf("kCFStreamErrorDomainPOSIX %i\n", err.error);
|
||||||
|
}
|
||||||
|
else if(err.domain == kCFStreamErrorDomainMacOSStatus)
|
||||||
|
{
|
||||||
|
printf("kCFStreamErrorDomainMacOSStatus %i\n", err.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
char* convertCFStringRefPathToCStringPath(CFStringRef ref)
|
success = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
remove(tarPath);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ======= extract tar ========
|
||||||
|
|
||||||
|
unsigned int bufferLength = 1024 * 256; // 256Kb
|
||||||
|
void *buffer = malloc(bufferLength);
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
int readBytes = gzread(tarFile, buffer, bufferLength);
|
||||||
|
|
||||||
|
if (readBytes > 0)
|
||||||
{
|
{
|
||||||
CFIndex bufferSize = CFStringGetMaximumSizeOfFileSystemRepresentation(ref);
|
CFIndex writtenBytes = CFWriteStreamWrite(writeStream, (unsigned char*)buffer,
|
||||||
char *buffer = new char[bufferSize];
|
readBytes);
|
||||||
CFStringGetFileSystemRepresentation(ref, buffer, bufferSize);
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool extractTzdata(CFURLRef homeUrl, CFURLRef archiveUrl, std::string destPath)
|
|
||||||
{
|
|
||||||
const char *TAR_TMP_PATH = "/tmp.tar";
|
|
||||||
|
|
||||||
// create Library path
|
if (writtenBytes < 0)
|
||||||
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);
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
const char *tarPath = convertCFStringRefPathToCStringPath(CFURLCopyPath(tarUrl));
|
|
||||||
|
|
||||||
// create tzdata directory
|
|
||||||
mkdir(destPath.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
|
|
||||||
|
|
||||||
// create stream
|
|
||||||
CFWriteStreamRef writeStream = CFWriteStreamCreateWithFile(NULL, tarUrl);
|
|
||||||
bool success = true;
|
|
||||||
|
|
||||||
if (!CFWriteStreamOpen(writeStream)) {
|
|
||||||
CFStreamError err = CFWriteStreamGetError(writeStream);
|
|
||||||
|
|
||||||
if (err.domain == kCFStreamErrorDomainPOSIX) {
|
|
||||||
printf("kCFStreamErrorDomainPOSIX %i\n", err.error);
|
|
||||||
} else if(err.domain == kCFStreamErrorDomainMacOSStatus) {
|
|
||||||
printf("kCFStreamErrorDomainMacOSStatus %i\n", err.error);
|
|
||||||
}
|
|
||||||
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!success) {
|
|
||||||
remove(tarPath);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ======= extract tar ========
|
|
||||||
|
|
||||||
unsigned int bufferLength = 1024 * 256; // 256Kb
|
|
||||||
void *buffer = malloc(bufferLength);
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
int readBytes = gzread(tarFile, buffer, bufferLength);
|
|
||||||
|
|
||||||
if (readBytes > 0) {
|
|
||||||
CFIndex writtenBytes = CFWriteStreamWrite(writeStream, (unsigned char*)buffer, readBytes);
|
|
||||||
|
|
||||||
if (writtenBytes < 0) {
|
|
||||||
CFStreamError err = CFWriteStreamGetError(writeStream);
|
|
||||||
printf("write stream error %i\n", err.error);
|
|
||||||
success = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if (readBytes == 0) {
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
if (readBytes == -1) {
|
|
||||||
printf("decompression failed\n");
|
|
||||||
success = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
printf("unexpected zlib state\n");
|
|
||||||
success = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CFWriteStreamClose(writeStream);
|
|
||||||
CFRelease(writeStream);
|
|
||||||
free(buffer);
|
|
||||||
gzclose(tarFile);
|
|
||||||
|
|
||||||
if (!success) {
|
|
||||||
remove(tarPath);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ======== extract files =========
|
|
||||||
|
|
||||||
uint64_t location = 0; // Position in the file
|
|
||||||
|
|
||||||
// get file size
|
|
||||||
struct stat stat_buf;
|
|
||||||
int res = stat(tarPath, &stat_buf);
|
|
||||||
if (res != 0) {
|
|
||||||
printf("error file size\n");
|
|
||||||
remove(tarPath);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
int64_t tarSize = stat_buf.st_size;
|
|
||||||
|
|
||||||
// create read stream
|
|
||||||
CFReadStreamRef readStream = CFReadStreamCreateWithFile(kCFAllocatorDefault, tarUrl);
|
|
||||||
|
|
||||||
if (!CFReadStreamOpen(readStream)) {
|
|
||||||
CFStreamError err = CFReadStreamGetError(readStream);
|
|
||||||
|
|
||||||
if (err.domain == kCFStreamErrorDomainPOSIX) {
|
|
||||||
printf("kCFStreamErrorDomainPOSIX %i", err.error);
|
|
||||||
} else if(err.domain == kCFStreamErrorDomainMacOSStatus) {
|
|
||||||
printf("kCFStreamErrorDomainMacOSStatus %i", err.error);
|
|
||||||
}
|
|
||||||
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!success) {
|
|
||||||
CFRelease(readStream);
|
|
||||||
remove(tarPath);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int count = 0;
|
|
||||||
long size = 0;
|
|
||||||
|
|
||||||
// process files
|
|
||||||
while (location < tarSize) {
|
|
||||||
TarInfo info = getTarObjectInfo(readStream, location);
|
|
||||||
|
|
||||||
if (!info.success || info.realContentSize == 0) {
|
|
||||||
break; // something wrong or all files are read
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (info.objType) {
|
|
||||||
case '0': // file
|
|
||||||
case '\0': //
|
|
||||||
{
|
|
||||||
std::string obj = getTarObject(readStream, info.blocksContentSize);
|
|
||||||
#ifdef 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);
|
|
||||||
#endif
|
|
||||||
writeFile(tzdataPathUrl, info.objName, obj, info.realContentSize);
|
|
||||||
location += info.blocksContentSize;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CFReadStreamClose(readStream);
|
|
||||||
CFRelease(readStream);
|
|
||||||
|
|
||||||
remove(tarPath);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
TarInfo getTarObjectInfo(CFReadStreamRef readStream, int64_t location)
|
|
||||||
{
|
|
||||||
int64_t length = TAR_BLOCK_SIZE;
|
|
||||||
uint8_t buffer[length];
|
|
||||||
|
|
||||||
char type;
|
|
||||||
char name[TAR_NAME_SIZE + 1];
|
|
||||||
char sizeBuf[TAR_SIZE_SIZE + 1];
|
|
||||||
CFIndex bytesRead;
|
|
||||||
|
|
||||||
bool avail = CFReadStreamHasBytesAvailable(readStream);
|
|
||||||
|
|
||||||
bytesRead = CFReadStreamRead(readStream, buffer, length);
|
|
||||||
|
|
||||||
if (bytesRead < 0) {
|
|
||||||
CFStreamError err = CFReadStreamGetError(readStream);
|
|
||||||
printf("error reading tar object info %i", err.error);
|
|
||||||
return {false};
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(&type, &buffer[TAR_TYPE_POSITION], 1);
|
|
||||||
|
|
||||||
memset(&name, '\0', TAR_NAME_SIZE + 1);
|
|
||||||
memcpy(&name, &buffer[TAR_NAME_POSITION], TAR_NAME_SIZE);
|
|
||||||
|
|
||||||
memset(&sizeBuf, '\0', TAR_SIZE_SIZE + 1);
|
|
||||||
memcpy(&sizeBuf, &buffer[TAR_SIZE_POSITION], TAR_SIZE_SIZE);
|
|
||||||
int64_t realSize = strtol(sizeBuf, NULL, 8);
|
|
||||||
int64_t blocksSize = realSize + (TAR_BLOCK_SIZE - (realSize % TAR_BLOCK_SIZE));
|
|
||||||
|
|
||||||
return {type, std::string(name), realSize, blocksSize, true};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string getTarObject(CFReadStreamRef readStream, int64_t size)
|
|
||||||
{
|
|
||||||
uint8_t buffer[size];
|
|
||||||
|
|
||||||
CFIndex bytesRead = CFReadStreamRead(readStream, buffer, size);
|
|
||||||
|
|
||||||
if (bytesRead < 0) {
|
|
||||||
CFStreamError err = CFReadStreamGetError(readStream);
|
|
||||||
printf("error reading tar object info %i", err.error);
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::string((char *)buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
CFWriteStreamRef writeStream = CFWriteStreamCreateWithFile(NULL, url);
|
|
||||||
|
|
||||||
// open stream
|
|
||||||
if (!CFWriteStreamOpen(writeStream)) {
|
|
||||||
CFStreamError err = CFWriteStreamGetError(writeStream);
|
|
||||||
|
|
||||||
if (err.domain == kCFStreamErrorDomainPOSIX) {
|
|
||||||
printf("kCFStreamErrorDomainPOSIX %i\n", err.error);
|
|
||||||
} else if(err.domain == kCFStreamErrorDomainMacOSStatus) {
|
|
||||||
printf("kCFStreamErrorDomainMacOSStatus %i\n", err.error);
|
|
||||||
}
|
|
||||||
|
|
||||||
CFRelease(writeStream);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// trim empty space
|
|
||||||
uint8_t trimmedData[realContentSize + 1];
|
|
||||||
memset(&trimmedData, '\0', realContentSize);
|
|
||||||
memcpy(&trimmedData, data.c_str(), realContentSize);
|
|
||||||
|
|
||||||
// write
|
|
||||||
CFIndex writtenBytes = CFWriteStreamWrite(writeStream, trimmedData, realContentSize);
|
|
||||||
|
|
||||||
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;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
CFWriteStreamClose(writeStream);
|
else if (readBytes == 0)
|
||||||
CFRelease(writeStream);
|
{
|
||||||
writeStream = NULL;
|
break;
|
||||||
|
}
|
||||||
return true;
|
else if (readBytes == -1)
|
||||||
|
{
|
||||||
|
printf("decompression failed\n");
|
||||||
|
success = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("unexpected zlib state\n");
|
||||||
|
success = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CFWriteStreamClose(writeStream);
|
||||||
|
CFRelease(writeStream);
|
||||||
|
free(buffer);
|
||||||
|
gzclose(tarFile);
|
||||||
|
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
remove(tarPath);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ======== extract files =========
|
||||||
|
|
||||||
|
uint64_t location = 0; // Position in the file
|
||||||
|
|
||||||
|
// get file size
|
||||||
|
struct stat stat_buf;
|
||||||
|
int res = stat(tarPath, &stat_buf);
|
||||||
|
if (res != 0)
|
||||||
|
{
|
||||||
|
printf("error file size\n");
|
||||||
|
remove(tarPath);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int64_t tarSize = stat_buf.st_size;
|
||||||
|
|
||||||
|
// create read stream
|
||||||
|
CFReadStreamRef readStream = CFReadStreamCreateWithFile(kCFAllocatorDefault, tarUrl);
|
||||||
|
|
||||||
|
if (!CFReadStreamOpen(readStream))
|
||||||
|
{
|
||||||
|
CFStreamError err = CFReadStreamGetError(readStream);
|
||||||
|
|
||||||
|
if (err.domain == kCFStreamErrorDomainPOSIX)
|
||||||
|
{
|
||||||
|
printf("kCFStreamErrorDomainPOSIX %i", err.error);
|
||||||
|
}
|
||||||
|
else if(err.domain == kCFStreamErrorDomainMacOSStatus)
|
||||||
|
{
|
||||||
|
printf("kCFStreamErrorDomainMacOSStatus %i", err.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
success = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
CFRelease(readStream);
|
||||||
|
remove(tarPath);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
long size = 0;
|
||||||
|
|
||||||
|
// process files
|
||||||
|
while (location < tarSize)
|
||||||
|
{
|
||||||
|
TarInfo info = getTarObjectInfo(readStream, location);
|
||||||
|
|
||||||
|
if (!info.success || info.realContentSize == 0)
|
||||||
|
{
|
||||||
|
break; // something wrong or all files are read
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (info.objType)
|
||||||
|
{
|
||||||
|
case '0': // file
|
||||||
|
case '\0': //
|
||||||
|
{
|
||||||
|
std::string obj = getTarObject(readStream, info.blocksContentSize);
|
||||||
|
#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);
|
||||||
|
#endif
|
||||||
|
writeFile(tzdataPathUrl, info.objName, obj, info.realContentSize);
|
||||||
|
location += info.blocksContentSize;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CFReadStreamClose(readStream);
|
||||||
|
CFRelease(readStream);
|
||||||
|
|
||||||
|
remove(tarPath);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
TarInfo
|
||||||
|
getTarObjectInfo(CFReadStreamRef readStream, int64_t location)
|
||||||
|
{
|
||||||
|
int64_t length = TAR_BLOCK_SIZE;
|
||||||
|
uint8_t buffer[length];
|
||||||
|
|
||||||
|
char type;
|
||||||
|
char name[TAR_NAME_SIZE + 1];
|
||||||
|
char sizeBuf[TAR_SIZE_SIZE + 1];
|
||||||
|
CFIndex bytesRead;
|
||||||
|
|
||||||
|
bool avail = CFReadStreamHasBytesAvailable(readStream);
|
||||||
|
|
||||||
|
bytesRead = CFReadStreamRead(readStream, buffer, length);
|
||||||
|
|
||||||
|
if (bytesRead < 0)
|
||||||
|
{
|
||||||
|
CFStreamError err = CFReadStreamGetError(readStream);
|
||||||
|
printf("error reading tar object info %i", err.error);
|
||||||
|
return {false};
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&type, &buffer[TAR_TYPE_POSITION], 1);
|
||||||
|
|
||||||
|
memset(&name, '\0', TAR_NAME_SIZE + 1);
|
||||||
|
memcpy(&name, &buffer[TAR_NAME_POSITION], TAR_NAME_SIZE);
|
||||||
|
|
||||||
|
memset(&sizeBuf, '\0', TAR_SIZE_SIZE + 1);
|
||||||
|
memcpy(&sizeBuf, &buffer[TAR_SIZE_POSITION], TAR_SIZE_SIZE);
|
||||||
|
int64_t realSize = strtol(sizeBuf, NULL, 8);
|
||||||
|
int64_t blocksSize = realSize + (TAR_BLOCK_SIZE - (realSize % TAR_BLOCK_SIZE));
|
||||||
|
|
||||||
|
return {type, std::string(name), realSize, blocksSize, true};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
std::string
|
||||||
|
getTarObject(CFReadStreamRef readStream, int64_t size)
|
||||||
|
{
|
||||||
|
uint8_t buffer[size];
|
||||||
|
|
||||||
|
CFIndex bytesRead = CFReadStreamRead(readStream, buffer, size);
|
||||||
|
|
||||||
|
if (bytesRead < 0)
|
||||||
|
{
|
||||||
|
CFStreamError err = CFReadStreamGetError(readStream);
|
||||||
|
printf("error reading tar object info %i", err.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::string((char *)buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
CFWriteStreamRef writeStream = CFWriteStreamCreateWithFile(NULL, url);
|
||||||
|
|
||||||
|
// open stream
|
||||||
|
if (!CFWriteStreamOpen(writeStream))
|
||||||
|
{
|
||||||
|
CFStreamError err = CFWriteStreamGetError(writeStream);
|
||||||
|
|
||||||
|
if (err.domain == kCFStreamErrorDomainPOSIX)
|
||||||
|
{
|
||||||
|
printf("kCFStreamErrorDomainPOSIX %i\n", err.error);
|
||||||
|
}
|
||||||
|
else if(err.domain == kCFStreamErrorDomainMacOSStatus)
|
||||||
|
{
|
||||||
|
printf("kCFStreamErrorDomainMacOSStatus %i\n", err.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
CFRelease(writeStream);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// trim empty space
|
||||||
|
uint8_t trimmedData[realContentSize + 1];
|
||||||
|
memset(&trimmedData, '\0', realContentSize);
|
||||||
|
memcpy(&trimmedData, data.c_str(), realContentSize);
|
||||||
|
|
||||||
|
// write
|
||||||
|
CFIndex writtenBytes = CFWriteStreamWrite(writeStream, trimmedData, realContentSize);
|
||||||
|
|
||||||
|
if (writtenBytes < 0)
|
||||||
|
{
|
||||||
|
CFStreamError err = CFWriteStreamGetError(writeStream);
|
||||||
|
printf("write stream error %i\n", err.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
CFWriteStreamClose(writeStream);
|
||||||
|
CFRelease(writeStream);
|
||||||
|
writeStream = NULL;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace iOSUtils
|
||||||
|
} // namespace date
|
||||||
|
|
||||||
|
#endif // TARGET_OS_IPHONE
|
||||||
|
10
tz.cpp
10
tz.cpp
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user