Updated on behalf of schmidt9

This commit is contained in:
Howard Hinnant
2017-11-26 14:41:40 -05:00
parent 543315b700
commit 15a63ec819

View File

@@ -28,7 +28,7 @@
#include <Foundation/Foundation.h> #include <Foundation/Foundation.h>
#include <iostream> #include <fstream>
#include <zlib.h> #include <zlib.h>
#include <sys/stat.h> #include <sys/stat.h>
@@ -49,28 +49,28 @@
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 size_t realContentSize; // writable size without padding zeroes
int64_t blocksContentSize; // adjusted size to 512 bytes blocks size_t blocksContentSize; // adjusted size to 512 bytes blocks
bool success; bool success;
}; };
std::string convertCFStringRefPathToCStringPath(CFStringRef ref); std::string 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(std::ifstream &readStream);
std::string getTarObject(CFReadStreamRef readStream, int64_t size); std::string getTarObject(std::ifstream &readStream, int64_t size);
bool writeFile(CFURLRef tzdataUrl, std::string fileName, std::string data, bool writeFile(const std::string &tzdataPath, const std::string &fileName,
int64_t realContentSize); const std::string &data, size_t realContentSize);
std::string std::string
get_current_timezone() get_current_timezone()
{ {
CFTimeZoneRef tzRef = CFTimeZoneCopySystem(); CFTimeZoneRef tzRef = CFTimeZoneCopySystem();
CFStringRef tzNameRef = CFTimeZoneGetName(tzRef); CFStringRef tzNameRef = CFTimeZoneGetName(tzRef);
CFIndex bufferSize = CFStringGetLength(tzNameRef) + 1; CFIndex bufferSize = CFStringGetLength(tzNameRef) + 1;
@@ -85,11 +85,11 @@ get_current_timezone()
CFRelease(tzRef); CFRelease(tzRef);
return ""; return "";
} }
std::string std::string
get_tzdata_path() get_tzdata_path()
{ {
CFURLRef homeUrlRef = CFCopyHomeDirectoryURL(); CFURLRef homeUrlRef = CFCopyHomeDirectoryURL();
CFStringRef homePath = CFURLCopyPath(homeUrlRef); CFStringRef homePath = CFURLCopyPath(homeUrlRef);
std::string path(std::string(convertCFStringRefPathToCStringPath(homePath)) + std::string path(std::string(convertCFStringRefPathToCStringPath(homePath)) +
@@ -130,90 +130,62 @@ get_tzdata_path()
CFRelease(paths); CFRelease(paths);
return result_path; return result_path;
} }
std::string std::string
convertCFStringRefPathToCStringPath(CFStringRef ref) 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);
auto result = std::string(buffer); auto result = std::string(buffer);
delete[] buffer; delete[] buffer;
return result; return result;
} }
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"; {
std::string TAR_TMP_PATH = "/tmp.tar";
CFStringRef homeStringRef = CFURLCopyPath(homeUrl);
auto homePath = convertCFStringRefPathToCStringPath(homeStringRef);
CFRelease(homeStringRef);
CFStringRef archiveStringRef = CFURLCopyPath(archiveUrl);
auto archivePath = convertCFStringRefPathToCStringPath(archiveStringRef);
CFRelease(archiveStringRef);
// create Library path // create Library path
CFStringRef libraryStr = CFStringCreateWithCString(NULL, INTERNAL_DIR, auto libraryPath = homePath + INTERNAL_DIR;
CFStringGetSystemEncoding());
CFURLRef libraryUrl = CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault,
homeUrl, libraryStr,
false);
// create tzdata path // create tzdata path
CFStringRef tzdataPathRef = CFStringCreateWithCString(NULL, std::string(std::string(INTERNAL_DIR) + "/" + TZDATA_DIR).c_str(), auto tzdataPath = libraryPath + "/" + TZDATA_DIR;
CFStringGetSystemEncoding());
CFURLRef tzdataPathUrl = CFURLCreateCopyAppendingPathComponent(NULL, homeUrl,
tzdataPathRef, false);
// create src archive path // -- replace %20 with " "
CFStringRef archivePath = CFURLCopyPath(archiveUrl); const std::string search = "%20";
gzFile tarFile = gzopen(convertCFStringRefPathToCStringPath(archivePath).c_str(), "rb"); const std::string replacement = " ";
size_t pos = 0;
while ((pos = archivePath.find(search, pos)) != std::string::npos) {
archivePath.replace(pos, search.length(), replacement);
pos += replacement.length();
}
gzFile tarFile = gzopen(archivePath.c_str(), "rb");
// create tar unpacking path // create tar unpacking path
CFStringRef tarName = CFStringCreateWithCString(NULL, TAR_TMP_PATH, auto tarPath = libraryPath + TAR_TMP_PATH;
CFStringGetSystemEncoding());
CFURLRef tarUrl = CFURLCreateCopyAppendingPathComponent(NULL, libraryUrl, tarName,
false);
CFStringRef tarPathRef = CFURLCopyPath(tarUrl);
auto tarPath = convertCFStringRefPathToCStringPath(tarPathRef);
// create tzdata directory // create tzdata directory
mkdir(destPath.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); mkdir(destPath.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
// create stream
CFWriteStreamRef writeStream = CFWriteStreamCreateWithFile(NULL, tarUrl);
bool success = true;
CFRelease(libraryStr);
CFRelease(libraryUrl);
CFRelease(tzdataPathRef);
CFRelease(archivePath);
CFRelease(tarName);
CFRelease(tarPathRef);
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)
{
CFRelease(tarUrl);
CFRelease(tzdataPathUrl);
CFRelease(writeStream);
return false;
}
// ======= extract tar ======== // ======= extract tar ========
std::ofstream os(tarPath.c_str(), std::ofstream::out | std::ofstream::app);
unsigned int bufferLength = 1024 * 256; // 256Kb unsigned int bufferLength = 1024 * 256; // 256Kb
void *buffer = malloc(bufferLength); unsigned char *buffer = (unsigned char *)malloc(bufferLength);
bool success = true;
while (true) while (true)
{ {
@@ -221,22 +193,15 @@ bool extractTzdata(CFURLRef homeUrl, CFURLRef archiveUrl, std::string destPath)
if (readBytes > 0) if (readBytes > 0)
{ {
CFIndex writtenBytes = CFWriteStreamWrite(writeStream, (unsigned char*)buffer, os.write((char *) &buffer[0], readBytes);
readBytes);
if (writtenBytes < 0)
{
CFStreamError err = CFWriteStreamGetError(writeStream);
printf("write stream error %i\n", err.error);
success = false;
break;
} }
} else
else if (readBytes == 0) 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;
@@ -250,15 +215,13 @@ bool extractTzdata(CFURLRef homeUrl, CFURLRef archiveUrl, std::string destPath)
} }
} }
CFWriteStreamClose(writeStream); os.close();
CFRelease(writeStream);
free(buffer); free(buffer);
gzclose(tarFile); gzclose(tarFile);
if (!success) if (!success)
{ {
CFRelease(tarUrl); remove(tarPath.c_str());
CFRelease(tzdataPathUrl);
return false; return false;
} }
@@ -272,43 +235,18 @@ bool extractTzdata(CFURLRef homeUrl, CFURLRef archiveUrl, std::string destPath)
if (res != 0) if (res != 0)
{ {
printf("error file size\n"); printf("error file size\n");
CFRelease(tarUrl); remove(tarPath.c_str());
CFRelease(tzdataPathUrl);
return false; return false;
} }
int64_t tarSize = stat_buf.st_size; int64_t tarSize = stat_buf.st_size;
// create read stream // create read stream
CFReadStreamRef readStream = CFReadStreamCreateWithFile(kCFAllocatorDefault, tarUrl); std::ifstream is(tarPath.c_str(), std::ifstream::in | std::ifstream::binary);
CFRelease(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(tzdataPathUrl);
CFRelease(readStream);
return false;
}
// process files // process files
while (location < tarSize) while (location < tarSize)
{ {
TarInfo info = getTarObjectInfo(readStream, location); TarInfo info = getTarObjectInfo(is);
if (!info.success || info.realContentSize == 0) if (!info.success || info.realContentSize == 0)
{ {
@@ -320,13 +258,13 @@ bool extractTzdata(CFURLRef homeUrl, CFURLRef archiveUrl, std::string destPath)
case '0': // file case '0': // file
case '\0': // case '\0': //
{ {
std::string obj = getTarObject(readStream, info.blocksContentSize); std::string obj = getTarObject(is, info.blocksContentSize);
#if TAR_DEBUG #if TAR_DEBUG
size += info.realContentSize; size += info.realContentSize;
printf("#%i %s file size %lld written total %ld from %lld\n", ++count, printf("#%i %s file size %lld written total %ld from %lld\n", ++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(tzdataPath, info.objName, obj, info.realContentSize);
location += info.blocksContentSize; location += info.blocksContentSize;
break; break;
@@ -334,32 +272,21 @@ bool extractTzdata(CFURLRef homeUrl, CFURLRef archiveUrl, std::string destPath)
} }
} }
CFRelease(tzdataPathUrl); remove(tarPath.c_str());
CFReadStreamClose(readStream);
CFRelease(readStream);
return true; return true;
} }
TarInfo TarInfo
getTarObjectInfo(CFReadStreamRef readStream, int64_t location) getTarObjectInfo(std::ifstream &readStream)
{ {
int64_t length = TAR_BLOCK_SIZE; int64_t length = TAR_BLOCK_SIZE;
uint8_t buffer[length]; char buffer[length];
char type; char type;
char name[TAR_NAME_SIZE + 1]; char name[TAR_NAME_SIZE + 1];
char sizeBuf[TAR_SIZE_SIZE + 1]; char sizeBuf[TAR_SIZE_SIZE + 1];
CFIndex bytesRead;
bytesRead = CFReadStreamRead(readStream, buffer, length); readStream.read(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); memcpy(&type, &buffer[TAR_TYPE_POSITION], 1);
@@ -368,82 +295,43 @@ getTarObjectInfo(CFReadStreamRef readStream, int64_t location)
memset(&sizeBuf, '\0', TAR_SIZE_SIZE + 1); memset(&sizeBuf, '\0', TAR_SIZE_SIZE + 1);
memcpy(&sizeBuf, &buffer[TAR_SIZE_POSITION], TAR_SIZE_SIZE); memcpy(&sizeBuf, &buffer[TAR_SIZE_POSITION], TAR_SIZE_SIZE);
int64_t realSize = strtol(sizeBuf, NULL, 8); size_t realSize = strtol(sizeBuf, NULL, 8);
int64_t blocksSize = realSize + (TAR_BLOCK_SIZE - (realSize % TAR_BLOCK_SIZE)); size_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)
{
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); std::string
} getTarObject(std::ifstream &readStream, int64_t size)
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);
CFRelease(fileNameRef);
CFRelease(url);
// open stream
if (!CFWriteStreamOpen(writeStream))
{ {
CFStreamError err = CFWriteStreamGetError(writeStream); char buffer[size];
readStream.read(buffer, size);
if (err.domain == kCFStreamErrorDomainPOSIX) return std::string(buffer);
{
printf("kCFStreamErrorDomainPOSIX %i\n", err.error);
}
else if(err.domain == kCFStreamErrorDomainMacOSStatus)
{
printf("kCFStreamErrorDomainMacOSStatus %i\n", err.error);
} }
CFRelease(writeStream); bool
writeFile(const std::string &tzdataPath, const std::string &fileName, const std::string &data,
size_t realContentSize)
{
std::ofstream os(tzdataPath + "/" + fileName, std::ofstream::out | std::ofstream::binary);
if (!os) {
return false; return false;
} }
// trim empty space // trim empty space
uint8_t trimmedData[realContentSize + 1]; char trimmedData[realContentSize + 1];
memset(&trimmedData, '\0', realContentSize); memset(&trimmedData, '\0', realContentSize);
memcpy(&trimmedData, data.c_str(), realContentSize); memcpy(&trimmedData, data.c_str(), realContentSize);
// write // write
CFIndex writtenBytes = CFWriteStreamWrite(writeStream, trimmedData, realContentSize); os.write(trimmedData, realContentSize);
os.close();
if (writtenBytes < 0)
{
CFStreamError err = CFWriteStreamGetError(writeStream);
printf("write stream error %i\n", err.error);
}
CFWriteStreamClose(writeStream);
CFRelease(writeStream);
writeStream = NULL;
return true; return true;
} }
} // namespace iOSUtils } // namespace iOSUtils
} // namespace date } // namespace date
#endif // TARGET_OS_IPHONE #endif // TARGET_OS_IPHONE