29#include <Foundation/Foundation.h>
39#define INTERNAL_DIR "Library"
40#define TZDATA_DIR "tzdata"
41#define TARGZ_EXTENSION "tar.gz"
43#define TAR_BLOCK_SIZE 512
44#define TAR_TYPE_POSITION 156
45#define TAR_NAME_POSITION 0
46#define TAR_NAME_SIZE 100
47#define TAR_SIZE_POSITION 124
48#define TAR_SIZE_SIZE 12
59 size_t realContentSize;
60 size_t blocksContentSize;
64 std::string convertCFStringRefPathToCStringPath(CFStringRef ref);
65 bool extractTzdata(CFURLRef homeUrl, CFURLRef archiveUrl, std::string destPath);
66 TarInfo getTarObjectInfo(std::ifstream &readStream);
67 std::string getTarObject(std::ifstream &readStream, int64_t size);
68 bool writeFile(
const std::string &tzdataPath,
const std::string &fileName,
69 const std::string &data,
size_t realContentSize);
72 get_current_timezone()
74 CFTimeZoneRef tzRef = CFTimeZoneCopySystem();
75 CFStringRef tzNameRef = CFTimeZoneGetName(tzRef);
76 CFIndex bufferSize = CFStringGetLength(tzNameRef) + 1;
77 char buffer[bufferSize];
79 if (CFStringGetCString(tzNameRef, buffer, bufferSize, kCFStringEncodingUTF8))
82 return std::string(buffer);
93 CFURLRef homeUrlRef = CFCopyHomeDirectoryURL();
94 CFStringRef homePath = CFURLCopyPath(homeUrlRef);
95 std::string path(std::string(convertCFStringRefPathToCStringPath(homePath)) +
96 INTERNAL_DIR +
"/" + TZDATA_DIR);
97 std::string result_path(std::string(convertCFStringRefPathToCStringPath(homePath)) +
100 if (access(path.c_str(), F_OK) == 0)
103 printf(
"tzdata dir exists\n");
105 CFRelease(homeUrlRef);
111 CFBundleRef mainBundle = CFBundleGetMainBundle();
112 CFArrayRef paths = CFBundleCopyResourceURLsOfType(mainBundle, CFSTR(TARGZ_EXTENSION),
115 if (CFArrayGetCount(paths) != 0)
118 CFURLRef archiveUrl =
static_cast<CFURLRef
>(CFArrayGetValueAtIndex(paths, 0));
119 CFStringRef archiveName = CFURLCopyPath(archiveUrl);
120 archiveUrl = CFBundleCopyResourceURL(mainBundle, archiveName, NULL, NULL);
122 extractTzdata(homeUrlRef, archiveUrl, path);
124 CFRelease(archiveUrl);
125 CFRelease(archiveName);
128 CFRelease(homeUrlRef);
136 convertCFStringRefPathToCStringPath(CFStringRef ref)
138 CFIndex bufferSize = CFStringGetMaximumSizeOfFileSystemRepresentation(ref);
139 char *buffer =
new char[bufferSize];
140 CFStringGetFileSystemRepresentation(ref, buffer, bufferSize);
141 auto result = std::string(buffer);
147 extractTzdata(CFURLRef homeUrl, CFURLRef archiveUrl, std::string destPath)
149 std::string TAR_TMP_PATH =
"/tmp.tar";
151 CFStringRef homeStringRef = CFURLCopyPath(homeUrl);
152 auto homePath = convertCFStringRefPathToCStringPath(homeStringRef);
153 CFRelease(homeStringRef);
155 CFStringRef archiveStringRef = CFURLCopyPath(archiveUrl);
156 auto archivePath = convertCFStringRefPathToCStringPath(archiveStringRef);
157 CFRelease(archiveStringRef);
160 auto libraryPath = homePath + INTERNAL_DIR;
163 auto tzdataPath = libraryPath +
"/" + TZDATA_DIR;
166 const std::string search =
"%20";
167 const std::string replacement =
" ";
170 while ((pos = archivePath.find(search, pos)) != std::string::npos) {
171 archivePath.replace(pos, search.length(), replacement);
172 pos += replacement.length();
175 gzFile tarFile = gzopen(archivePath.c_str(),
"rb");
178 auto tarPath = libraryPath + TAR_TMP_PATH;
181 mkdir(destPath.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
185 std::ofstream os(tarPath.c_str(), std::ofstream::out | std::ofstream::app);
186 unsigned int bufferLength = 1024 * 256;
187 unsigned char *buffer = (
unsigned char *)malloc(bufferLength);
192 int readBytes = gzread(tarFile, buffer, bufferLength);
196 os.write((
char *) &buffer[0], readBytes);
206 printf(
"decompression failed\n");
212 printf(
"unexpected zlib state\n");
224 remove(tarPath.c_str());
230 uint64_t location = 0;
233 struct stat stat_buf;
234 int res = stat(tarPath.c_str(), &stat_buf);
237 printf(
"error file size\n");
238 remove(tarPath.c_str());
241 int64_t tarSize = stat_buf.st_size;
244 std::ifstream is(tarPath.c_str(), std::ifstream::in | std::ifstream::binary);
247 while (location < tarSize)
249 TarInfo info = getTarObjectInfo(is);
251 if (!info.success || info.realContentSize == 0)
256 switch (info.objType)
261 std::string obj = getTarObject(is, info.blocksContentSize);
263 size += info.realContentSize;
264 printf(
"#%i %s file size %lld written total %ld from %lld\n", ++count,
265 info.objName.c_str(), info.realContentSize, size, tarSize);
267 writeFile(tzdataPath, info.objName, obj, info.realContentSize);
268 location += info.blocksContentSize;
275 remove(tarPath.c_str());
281 getTarObjectInfo(std::ifstream &readStream)
283 int64_t length = TAR_BLOCK_SIZE;
286 char name[TAR_NAME_SIZE + 1];
287 char sizeBuf[TAR_SIZE_SIZE + 1];
289 readStream.read(buffer, length);
291 memcpy(&type, &buffer[TAR_TYPE_POSITION], 1);
293 memset(&
name,
'\0', TAR_NAME_SIZE + 1);
294 memcpy(&
name, &buffer[TAR_NAME_POSITION], TAR_NAME_SIZE);
296 memset(&sizeBuf,
'\0', TAR_SIZE_SIZE + 1);
297 memcpy(&sizeBuf, &buffer[TAR_SIZE_POSITION], TAR_SIZE_SIZE);
298 size_t realSize = strtol(sizeBuf, NULL, 8);
299 size_t blocksSize = realSize + (TAR_BLOCK_SIZE - (realSize % TAR_BLOCK_SIZE));
301 return {type, std::string(
name), realSize, blocksSize,
true};
305 getTarObject(std::ifstream &readStream, int64_t size)
308 readStream.read(buffer, size);
309 return std::string(buffer);
313 writeFile(
const std::string &tzdataPath,
const std::string &fileName,
const std::string &data,
314 size_t realContentSize)
316 std::ofstream os(tzdataPath +
"/" + fileName, std::ofstream::out | std::ofstream::binary);
323 char trimmedData[realContentSize + 1];
324 memset(&trimmedData,
'\0', realContentSize);
325 memcpy(&trimmedData, data.c_str(), realContentSize);
328 os.write(trimmedData, realContentSize);