NumeRe v1.1.4
NumeRe: Framework für Numerische Rechnungen
ios.mm
Go to the documentation of this file.
1//
2// The MIT License (MIT)
3//
4// Copyright (c) 2016 Alexander Kormanovsky
5//
6// Permission is hereby granted, free of charge, to any person obtaining a copy
7// of this software and associated documentation files (the "Software"), to deal
8// in the Software without restriction, including without limitation the rights
9// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10// copies of the Software, and to permit persons to whom the Software is
11// furnished to do so, subject to the following conditions:
12//
13// The above copyright notice and this permission notice shall be included in all
14// copies or substantial portions of the Software.
15//
16// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22// SOFTWARE.
23//
24
25#include "date/ios.h"
26
27#if TARGET_OS_IPHONE
28
29#include <Foundation/Foundation.h>
30
31#include <fstream>
32#include <zlib.h>
33#include <sys/stat.h>
34
35#ifndef TAR_DEBUG
36# define TAR_DEBUG 0
37#endif
38
39#define INTERNAL_DIR "Library"
40#define TZDATA_DIR "tzdata"
41#define TARGZ_EXTENSION "tar.gz"
42
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
49
50namespace date
51{
52 namespace iOSUtils
53 {
54
55 struct TarInfo
56 {
57 char objType;
58 std::string objName;
59 size_t realContentSize; // writable size without padding zeroes
60 size_t blocksContentSize; // adjusted size to 512 bytes blocks
61 bool success;
62 };
63
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);
70
71 std::string
72 get_current_timezone()
73 {
74 CFTimeZoneRef tzRef = CFTimeZoneCopySystem();
75 CFStringRef tzNameRef = CFTimeZoneGetName(tzRef);
76 CFIndex bufferSize = CFStringGetLength(tzNameRef) + 1;
77 char buffer[bufferSize];
78
79 if (CFStringGetCString(tzNameRef, buffer, bufferSize, kCFStringEncodingUTF8))
80 {
81 CFRelease(tzRef);
82 return std::string(buffer);
83 }
84
85 CFRelease(tzRef);
86
87 return "";
88 }
89
90 std::string
91 get_tzdata_path()
92 {
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)) +
98 INTERNAL_DIR);
99
100 if (access(path.c_str(), F_OK) == 0)
101 {
102#if TAR_DEBUG
103 printf("tzdata dir exists\n");
104#endif
105 CFRelease(homeUrlRef);
106 CFRelease(homePath);
107
108 return result_path;
109 }
110
111 CFBundleRef mainBundle = CFBundleGetMainBundle();
112 CFArrayRef paths = CFBundleCopyResourceURLsOfType(mainBundle, CFSTR(TARGZ_EXTENSION),
113 NULL);
114
115 if (CFArrayGetCount(paths) != 0)
116 {
117 // get archive path, assume there is no other tar.gz in bundle
118 CFURLRef archiveUrl = static_cast<CFURLRef>(CFArrayGetValueAtIndex(paths, 0));
119 CFStringRef archiveName = CFURLCopyPath(archiveUrl);
120 archiveUrl = CFBundleCopyResourceURL(mainBundle, archiveName, NULL, NULL);
121
122 extractTzdata(homeUrlRef, archiveUrl, path);
123
124 CFRelease(archiveUrl);
125 CFRelease(archiveName);
126 }
127
128 CFRelease(homeUrlRef);
129 CFRelease(homePath);
130 CFRelease(paths);
131
132 return result_path;
133 }
134
135 std::string
136 convertCFStringRefPathToCStringPath(CFStringRef ref)
137 {
138 CFIndex bufferSize = CFStringGetMaximumSizeOfFileSystemRepresentation(ref);
139 char *buffer = new char[bufferSize];
140 CFStringGetFileSystemRepresentation(ref, buffer, bufferSize);
141 auto result = std::string(buffer);
142 delete[] buffer;
143 return result;
144 }
145
146 bool
147 extractTzdata(CFURLRef homeUrl, CFURLRef archiveUrl, std::string destPath)
148 {
149 std::string TAR_TMP_PATH = "/tmp.tar";
150
151 CFStringRef homeStringRef = CFURLCopyPath(homeUrl);
152 auto homePath = convertCFStringRefPathToCStringPath(homeStringRef);
153 CFRelease(homeStringRef);
154
155 CFStringRef archiveStringRef = CFURLCopyPath(archiveUrl);
156 auto archivePath = convertCFStringRefPathToCStringPath(archiveStringRef);
157 CFRelease(archiveStringRef);
158
159 // create Library path
160 auto libraryPath = homePath + INTERNAL_DIR;
161
162 // create tzdata path
163 auto tzdataPath = libraryPath + "/" + TZDATA_DIR;
164
165 // -- replace %20 with " "
166 const std::string search = "%20";
167 const std::string replacement = " ";
168 size_t pos = 0;
169
170 while ((pos = archivePath.find(search, pos)) != std::string::npos) {
171 archivePath.replace(pos, search.length(), replacement);
172 pos += replacement.length();
173 }
174
175 gzFile tarFile = gzopen(archivePath.c_str(), "rb");
176
177 // create tar unpacking path
178 auto tarPath = libraryPath + TAR_TMP_PATH;
179
180 // create tzdata directory
181 mkdir(destPath.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
182
183 // ======= extract tar ========
184
185 std::ofstream os(tarPath.c_str(), std::ofstream::out | std::ofstream::app);
186 unsigned int bufferLength = 1024 * 256; // 256Kb
187 unsigned char *buffer = (unsigned char *)malloc(bufferLength);
188 bool success = true;
189
190 while (true)
191 {
192 int readBytes = gzread(tarFile, buffer, bufferLength);
193
194 if (readBytes > 0)
195 {
196 os.write((char *) &buffer[0], readBytes);
197 }
198 else
199 if (readBytes == 0)
200 {
201 break;
202 }
203 else
204 if (readBytes == -1)
205 {
206 printf("decompression failed\n");
207 success = false;
208 break;
209 }
210 else
211 {
212 printf("unexpected zlib state\n");
213 success = false;
214 break;
215 }
216 }
217
218 os.close();
219 free(buffer);
220 gzclose(tarFile);
221
222 if (!success)
223 {
224 remove(tarPath.c_str());
225 return false;
226 }
227
228 // ======== extract files =========
229
230 uint64_t location = 0; // Position in the file
231
232 // get file size
233 struct stat stat_buf;
234 int res = stat(tarPath.c_str(), &stat_buf);
235 if (res != 0)
236 {
237 printf("error file size\n");
238 remove(tarPath.c_str());
239 return false;
240 }
241 int64_t tarSize = stat_buf.st_size;
242
243 // create read stream
244 std::ifstream is(tarPath.c_str(), std::ifstream::in | std::ifstream::binary);
245
246 // process files
247 while (location < tarSize)
248 {
249 TarInfo info = getTarObjectInfo(is);
250
251 if (!info.success || info.realContentSize == 0)
252 {
253 break; // something wrong or all files are read
254 }
255
256 switch (info.objType)
257 {
258 case '0': // file
259 case '\0': //
260 {
261 std::string obj = getTarObject(is, info.blocksContentSize);
262#if TAR_DEBUG
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);
266#endif
267 writeFile(tzdataPath, info.objName, obj, info.realContentSize);
268 location += info.blocksContentSize;
269
270 break;
271 }
272 }
273 }
274
275 remove(tarPath.c_str());
276
277 return true;
278 }
279
280 TarInfo
281 getTarObjectInfo(std::ifstream &readStream)
282 {
283 int64_t length = TAR_BLOCK_SIZE;
284 char buffer[length];
285 char type;
286 char name[TAR_NAME_SIZE + 1];
287 char sizeBuf[TAR_SIZE_SIZE + 1];
288
289 readStream.read(buffer, length);
290
291 memcpy(&type, &buffer[TAR_TYPE_POSITION], 1);
292
293 memset(&name, '\0', TAR_NAME_SIZE + 1);
294 memcpy(&name, &buffer[TAR_NAME_POSITION], TAR_NAME_SIZE);
295
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));
300
301 return {type, std::string(name), realSize, blocksSize, true};
302 }
303
304 std::string
305 getTarObject(std::ifstream &readStream, int64_t size)
306 {
307 char buffer[size];
308 readStream.read(buffer, size);
309 return std::string(buffer);
310 }
311
312 bool
313 writeFile(const std::string &tzdataPath, const std::string &fileName, const std::string &data,
314 size_t realContentSize)
315 {
316 std::ofstream os(tzdataPath + "/" + fileName, std::ofstream::out | std::ofstream::binary);
317
318 if (!os) {
319 return false;
320 }
321
322 // trim empty space
323 char trimmedData[realContentSize + 1];
324 memset(&trimmedData, '\0', realContentSize);
325 memcpy(&trimmedData, data.c_str(), realContentSize);
326
327 // write
328 os.write(trimmedData, realContentSize);
329 os.close();
330
331 return true;
332 }
333
334 } // namespace iOSUtils
335} // namespace date
336
337#endif // TARGET_OS_IPHONE
Definition: date.h:88
char name[32]
Definition: resampler.cpp:371