Namespaces, ios macro

This commit is contained in:
schmidt9
2016-08-21 21:37:24 +03:00
parent 952857e721
commit 927fc619ef
2 changed files with 330 additions and 52 deletions

378
ios.mm
View File

@@ -1,7 +1,4 @@
// //
// ios.cpp
// DateTimeLib
//
// The MIT License (MIT) // The MIT License (MIT)
// //
// Copyright (c) 2016 Alexander Kormanovsky // Copyright (c) 2016 Alexander Kormanovsky
@@ -23,68 +20,349 @@
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE. // SOFTWARE.
//
#if HAS_IOS #ifdef TARGET_OS_IPHONE
#include <Foundation/Foundation.h>
#include <iostream>
#include <zlib.h>
#include <sys/stat.h>
#include "ios.h" #include "ios.h"
#include "NVHTarGzip.h"
#define TAR_DEBUG
#define DIR_NAME "tzdata"
#define INTERNAL_DIR "Library/tzdata"
#define TARGZ_EXTENSION "tar.gz"
#define TAR_BLOCK_SIZE 512
#define TAR_TYPE_POSITION 156
#define TAR_NAME_POSITION 0
#define TAR_NAME_SIZE 100
#define TAR_SIZE_POSITION 124
#define TAR_SIZE_SIZE 12
namespace date namespace date
{ {
namespace iOSUtils namespace iOSUtils
{ {
std::string
get_tzdata_path()
{
static NSString *result = @"";
NSFileManager *manager = [NSFileManager defaultManager];
static dispatch_once_t onceToken;
dispatch_once(&onceToken,
^{
NSArray *paths = [NSBundle pathsForResourcesOfType:@"tar.gz"
inDirectory:[[NSBundle mainBundle] bundlePath]];
if (paths.count != 0) 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()
{ {
NSString *archivePath = paths[0]; CFURLRef ref = CFCopyHomeDirectoryURL();
NSURL *docsURL = [[[NSFileManager defaultManager] CFStringRef homePath = CFURLCopyPath(CFCopyHomeDirectoryURL());
URLsForDirectory:NSDocumentDirectory std::string tzdata_path(std::string(convertCFStringRefPathToCStringPath(homePath)) + INTERNAL_DIR);
inDomains:NSUserDomainMask] lastObject];
NSString *path = [[docsURL URLByAppendingPathComponent:@"tzdata"] path]; if (access(tzdata_path.c_str(), F_OK) == 0) {
#ifdef TAR_DEBUG
if ([manager fileExistsAtPath:path]) printf("tzdata exists\n");
{ #endif
result = path; return tzdata_path;
return;
} }
[manager createDirectoryAtPath:path withIntermediateDirectories:NO CFBundleRef mainBundle = CFBundleGetMainBundle();
attributes:nil error:nil]; CFArrayRef paths = CFBundleCopyResourceURLsOfType(mainBundle, CFSTR(TARGZ_EXTENSION), NULL);
NSError *error; if (CFArrayGetCount(paths) != 0) {
// get archive path, assume there is no other tar.gz in bundle
[[NVHTarGzip sharedInstance] unTarGzipFileAtPath:archivePath CFURLRef archiveUrl = static_cast<CFURLRef>(CFArrayGetValueAtIndex(paths, 0));
toPath:path error:&error]; CFStringRef archiveName= CFURLCopyPath(archiveUrl);
archiveUrl = CFBundleCopyResourceURL(mainBundle, archiveName, NULL, NULL);
if (error != nil)
{ extractTzdata(CFCopyHomeDirectoryURL(), archiveUrl, tzdata_path);
NSLog(@"%s Error extracting %@", __func__, error);
}
else
{
result = path;
} }
return tzdata_path;
} }
});
char* convertCFStringRefPathToCStringPath(CFStringRef ref)
return [result UTF8String]; {
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);
}
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);
printf("write stream error %i\n", err.error);
}
CFWriteStreamClose(writeStream);
CFRelease(writeStream);
writeStream = NULL;
return true;
}
}
} }
} // namespace iOSUtils
} // namespace date
#endif #endif

4
tz.cpp
View File

@@ -117,7 +117,7 @@
# endif //!USE_SHELL_API # endif //!USE_SHELL_API
#endif // !WIN32 #endif // !WIN32
#ifdef HAS_IOS #ifdef TARGET_OS_IPHONE
#include "ios.h" #include "ios.h"
#endif #endif
@@ -184,7 +184,7 @@ static
std::string std::string
expand_path(std::string path) expand_path(std::string path)
{ {
#ifndef HAS_IOS #ifndef TARGET_OS_IPHONE
::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);