1 //==================================================================//
2 /*
3 AtomicParsley - util.cpp
4
5 AtomicParsley is GPL software; you can freely distribute,
6 redistribute, modify & use under the terms of the GNU General
7 Public License; either version 2 or its successor.
8
9 AtomicParsley is distributed under the GPL "AS IS", without
10 any warranty; without the implied warranty of merchantability
11 or fitness for either an expressed or implied particular purpose.
12
13 Please see the included GNU General Public License (GPL) for
14 your rights and further details; see the file COPYING. If you
15 cannot, write to the Free Software Foundation, 59 Temple Place
16 Suite 330, Boston, MA 02111-1307, USA. Or www.fsf.org
17
18 Copyright (C) 2006-2007 puck_lock
19 with contributions from others; see the CREDITS file
20
21 ----------------------
22 Code Contributions by:
23
24 * SLarew - prevent writing past array in Convert_multibyteUTF16_to_wchar
25 bugfix
26
27 */
28 //==================================================================//
29
30 #include "AtomicParsley.h"
31
32 ///////////////////////////////////////////////////////////////////////////////////////
33 // Filesytem routines //
34 ///////////////////////////////////////////////////////////////////////////////////////
35
36 /*----------------------
37 findFileSize
38 utf8_filepath - a pointer to a string (possibly utf8) of the full path to the
39 file
40
41 take an ascii/utf8 filepath (which if under a unicode enabled Win32 OS was
42 already converted from utf16le to utf8 at program start) and test if AP is
43 running on a unicode enabled Win32 OS. If it is and converted to utf8 (rather
44 than just stripped), convert the utf8 filepath to a utf16 (native-endian)
45 filepath & pass that to a wide stat. Or stat it with a utf8 filepath on Unixen &
46 win32 (stripped utf8).
47 ----------------------*/
findFileSize(const char * utf8_filepath)48 uint64_t findFileSize(const char *utf8_filepath) {
49 #if defined(_WIN32) && !defined(__CYGWIN__)
50 if (IsUnicodeWinOS() && UnicodeOutputStatus == WIN32_UTF16) {
51 wchar_t *utf16_filepath = Convert_multibyteUTF8_to_wchar(utf8_filepath);
52
53 struct _stati64 fileStats;
54 _wstati64(utf16_filepath, &fileStats);
55
56 free(utf16_filepath);
57 utf16_filepath = NULL;
58 return fileStats.st_size;
59 } else
60 #endif
61 {
62 struct stat fileStats;
63 stat(utf8_filepath, &fileStats);
64 return fileStats.st_size;
65 }
66 return 0; // won't ever get here.... unless this is win32, set to utf8 and the
67 // folder/file had unicode.... TODO (? use isUTF8() for high ascii?)
68 }
69
70 /*----------------------
71 APar_OpenFile
72 utf8_filepath - a pointer to a string (possibly utf8) of the full path to the
73 file file_flags - 3 bytes max for the flags to open the file with (read, write,
74 binary mode....)
75
76 take an ascii/utf8 filepath (which if under a unicode enabled Win32 OS was
77 already converted from utf16le to utf8 at program start) and test if AP is
78 running on a unicode enabled Win32 OS. If it is, convert the utf8 filepath to a
79 utf16 (native-endian) filepath & pass that to a wide fopen with the 8-bit file
80 flags changed to 16-bit file flags. Or open a utf8 file with vanilla fopen on
81 Unixen.
82 ----------------------*/
APar_OpenFile(const char * utf8_filepath,const char * file_flags)83 FILE *APar_OpenFile(const char *utf8_filepath, const char *file_flags) {
84 FILE *aFile = NULL;
85 #if defined(_WIN32) && !defined(__CYGWIN__)
86 if (IsUnicodeWinOS() && UnicodeOutputStatus == WIN32_UTF16) {
87 wchar_t *Lfile_flags = (wchar_t *)malloc(sizeof(wchar_t) * 4);
88 memset(Lfile_flags, 0, sizeof(wchar_t) * 4);
89 mbstowcs(Lfile_flags, file_flags, strlen(file_flags));
90
91 wchar_t *utf16_filepath = Convert_multibyteUTF8_to_wchar(utf8_filepath);
92
93 aFile = _wfopen(utf16_filepath, Lfile_flags);
94
95 free(Lfile_flags);
96 Lfile_flags = NULL;
97 free(utf16_filepath);
98 utf16_filepath = NULL;
99 } else
100 #endif
101 {
102 aFile = fopen(utf8_filepath, file_flags);
103 }
104
105 if (!aFile) {
106 fprintf(stdout,
107 "AP error trying to fopen %s: %s\n",
108 utf8_filepath,
109 strerror(errno));
110 }
111 return aFile;
112 }
113
114 /*----------------------
115 openSomeFile
116 utf8_filepath - a pointer to a string (possibly utf8) of the full path to the
117 file open - flag to either open or close (function does both)
118
119 take an ascii/utf8 filepath and either open or close it; used for the main
120 ISO Base Media File; store the resulting FILE* in a global source_file
121 ----------------------*/
APar_OpenISOBaseMediaFile(const char * utf8file,bool open)122 FILE *APar_OpenISOBaseMediaFile(const char *utf8file, bool open) {
123 if (open && !file_opened) {
124 source_file = APar_OpenFile(utf8file, "rb");
125 if (source_file != nullptr) {
126 file_opened = true;
127 }
128 } else if (file_opened) {
129 fclose(source_file);
130 file_opened = false;
131 source_file = nullptr;
132 }
133 return source_file;
134 }
135
TestFileExistence(const char * filePath,bool errorOut)136 void TestFileExistence(const char *filePath, bool errorOut) {
137 FILE *a_file = NULL;
138 a_file = APar_OpenFile(filePath, "rb");
139 if ((a_file == NULL) && errorOut) {
140 fprintf(stderr,
141 "AtomicParsley error: can't open %s for reading: %s\n",
142 filePath,
143 strerror(errno));
144 exit(1);
145 } else {
146 if (a_file == NULL) {
147 fprintf(stderr,
148 "AtomicParsley warning: can't open %s for reading but continuing "
149 "anyway: %s\n",
150 filePath,
151 strerror(errno));
152 } else {
153 fclose(a_file);
154 }
155 }
156 }
157
158 #ifndef HAVE_FSEEKO
159 #ifdef _WIN32
fseeko(FILE * stream,off_t pos,int whence)160 int fseeko(FILE *stream, off_t pos, int whence) {
161 return _fseeki64(stream, pos, whence);
162 }
163
ftello(FILE * stream)164 off_t ftello(FILE *stream) { return _ftelli64(stream); }
165
166 #else
fseeko(FILE * stream,off_t pos,int whence)167 int fseeko(FILE *stream, off_t pos, int whence) {
168 return fseek(stream, pos, whence);
169 }
170
ftello(FILE * stream)171 off_t ftello(FILE *stream) { return ftell(stream); }
172 #endif
173 #endif
174
175 #if defined(_WIN32)
176
177 ///////////////////////////////////////////////////////////////////////////////////////
178 // Win32 functions //
179 ///////////////////////////////////////////////////////////////////////////////////////
180
181 /*----------------------
182 APar_OpenFileWin32
183 utf8_filepath - a pointer to a string (possibly utf8) of the full path
184 to the file
185 ... - passed on to the CreateFile function
186
187 take an ascii/utf8 filepath (which if under a unicode enabled Win32 OS
188 was already converted from utf16le to utf8 at program start) and test if AP is
189 running on a unicode enabled Win32 OS. If it is, convert the utf8 filepath to a
190 utf16 (native-endian) filepath & pass that to a wide CreateFile with the 8-bit
191 file flags changed to 16-bit file flags, otherwise pass the utf8 filepath to an
192 ANSI CreateFile
193 ----------------------*/
APar_OpenFileWin32(const char * utf8_filepath,DWORD dwDesiredAccess,DWORD dwShareMode,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD dwCreationDisposition,DWORD dwFlagsAndAttributes,HANDLE hTemplateFile)194 HANDLE APar_OpenFileWin32(const char *utf8_filepath,
195 DWORD dwDesiredAccess,
196 DWORD dwShareMode,
197 LPSECURITY_ATTRIBUTES lpSecurityAttributes,
198 DWORD dwCreationDisposition,
199 DWORD dwFlagsAndAttributes,
200 HANDLE hTemplateFile) {
201 if (IsUnicodeWinOS() && UnicodeOutputStatus == WIN32_UTF16) {
202 HANDLE hFile = NULL;
203 wchar_t *utf16_filepath = Convert_multibyteUTF8_to_wchar(utf8_filepath);
204 hFile = CreateFileW(utf16_filepath,
205 dwDesiredAccess,
206 dwShareMode,
207 lpSecurityAttributes,
208 dwCreationDisposition,
209 dwFlagsAndAttributes,
210 hTemplateFile);
211 free(utf16_filepath);
212 return hFile;
213 } else {
214 return CreateFileA(utf8_filepath,
215 dwDesiredAccess,
216 dwShareMode,
217 lpSecurityAttributes,
218 dwCreationDisposition,
219 dwFlagsAndAttributes,
220 hTemplateFile);
221 }
222 }
223
224 #endif
225
226 // http://www.flipcode.com/articles/article_advstrings01.shtml
IsUnicodeWinOS()227 bool IsUnicodeWinOS() {
228 #if defined(_WIN32)
229 OSVERSIONINFOW os;
230 memset(&os, 0, sizeof(OSVERSIONINFOW));
231 os.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
232 return (GetVersionExW(&os) != 0);
233 #else
234 return false;
235 #endif
236 }
237
238 ///////////////////////////////////////////////////////////////////////////////////////
239 // File reading routines //
240 ///////////////////////////////////////////////////////////////////////////////////////
241
APar_strferror(FILE * f)242 const char *APar_strferror(FILE *f) {
243 if (feof(f) && ferror(f))
244 return "error and end of file";
245 else if (feof(f))
246 return "end of file";
247 else if (ferror(f))
248 return "error";
249 else
250 return "neither error nor end of file";
251 }
252
APar_read8(FILE * ISObasemediafile,uint64_t pos)253 uint8_t APar_read8(FILE *ISObasemediafile, uint64_t pos) {
254 uint8_t a_byte = 0;
255 size_t size;
256 fseeko(ISObasemediafile, pos, SEEK_SET);
257 size = fread(&a_byte, 1, 1, ISObasemediafile);
258 if (size != 1) {
259 printf("%s read failed, expect 1, got %u: %s\n",
260 __FUNCTION__,
261 (unsigned int)size,
262 APar_strferror(ISObasemediafile));
263 exit(1);
264 }
265 return a_byte;
266 }
267
APar_read16(char * buffer,FILE * ISObasemediafile,uint64_t pos)268 uint16_t APar_read16(char *buffer, FILE *ISObasemediafile, uint64_t pos) {
269 size_t size;
270 fseeko(ISObasemediafile, pos, SEEK_SET);
271 size = fread(buffer, 1, 2, ISObasemediafile);
272 if (size != 2) {
273 printf("%s read failed, expect 2, got %u: %s\n",
274 __FUNCTION__,
275 (unsigned int)size,
276 APar_strferror(ISObasemediafile));
277 exit(1);
278 }
279 return UInt16FromBigEndian(buffer);
280 }
281
APar_read32(char * buffer,FILE * ISObasemediafile,uint64_t pos)282 uint32_t APar_read32(char *buffer, FILE *ISObasemediafile, uint64_t pos) {
283 size_t size;
284 fseeko(ISObasemediafile, pos, SEEK_SET);
285 size = fread(buffer, 1, 4, ISObasemediafile);
286 if (size != 4) {
287 printf("%s read failed, expect 4, got %u: %s\n",
288 __FUNCTION__,
289 (unsigned int)size,
290 APar_strferror(ISObasemediafile));
291 exit(1);
292 }
293 return UInt32FromBigEndian(buffer);
294 }
295
APar_read64(char * buffer,FILE * ISObasemediafile,uint64_t pos)296 uint64_t APar_read64(char *buffer, FILE *ISObasemediafile, uint64_t pos) {
297 size_t size;
298 fseeko(ISObasemediafile, pos, SEEK_SET);
299 size = fread(buffer, 1, 8, ISObasemediafile);
300 if (size != 8) {
301 printf("%s read failed, expect 8, got %u: %s\n",
302 __FUNCTION__,
303 (unsigned int)size,
304 APar_strferror(ISObasemediafile));
305 exit(1);
306 }
307 return UInt64FromBigEndian(buffer);
308 }
309
APar_readX_noseek(char * buffer,FILE * ISObasemediafile,uint32_t length)310 void APar_readX_noseek(char *buffer, FILE *ISObasemediafile, uint32_t length) {
311 size_t size;
312 size = fread(buffer, 1, length, ISObasemediafile);
313 if (size != length) {
314 printf("%s read failed, expect %" PRIu32 ", got %" PRIu32 ": %s\n",
315 __FUNCTION__,
316 length,
317 (uint32_t)size,
318 APar_strferror(ISObasemediafile));
319 exit(1);
320 }
321 return;
322 }
323
APar_readX(char * buffer,FILE * ISObasemediafile,uint64_t pos,uint32_t length)324 void APar_readX(char *buffer,
325 FILE *ISObasemediafile,
326 uint64_t pos,
327 uint32_t length) {
328 size_t size;
329 fseeko(ISObasemediafile, pos, SEEK_SET);
330 size = fread(buffer, 1, length, ISObasemediafile);
331 if (size != length) {
332 printf("%s read failed, expect %" PRIu32 ", got %" PRIu32 ": %s\n",
333 __FUNCTION__,
334 length,
335 (uint32_t)size,
336 APar_strferror(ISObasemediafile));
337 exit(1);
338 }
339 return;
340 }
341
342 uint32_t
APar_ReadFile(char * destination_buffer,FILE * a_file,uint32_t bytes_to_read)343 APar_ReadFile(char *destination_buffer, FILE *a_file, uint32_t bytes_to_read) {
344 uint32_t bytes_read = 0;
345 if (destination_buffer != NULL) {
346 fseeko(a_file, 0, SEEK_SET); // not that 2gb support is required - malloc
347 // would probably have a few issues
348 bytes_read = fread(destination_buffer, 1, bytes_to_read, a_file);
349 file_size += bytes_read; // accommodate huge files embedded within small
350 // files for APar_Validate
351 }
352 return bytes_read;
353 }
354
APar_FindValueInAtom(char * uint32_buffer,FILE * ISObasemediafile,short an_atom,uint64_t start_position,uint32_t eval_number)355 uint32_t APar_FindValueInAtom(char *uint32_buffer,
356 FILE *ISObasemediafile,
357 short an_atom,
358 uint64_t start_position,
359 uint32_t eval_number) {
360 uint64_t current_pos = start_position;
361 memset(uint32_buffer, 0, 5);
362 while (current_pos <= parsedAtoms[an_atom].AtomicLength) {
363 current_pos++;
364 if (eval_number > 65535) {
365 // current_pos +=4;
366 if (APar_read32(uint32_buffer,
367 ISObasemediafile,
368 parsedAtoms[an_atom].AtomicStart + current_pos) ==
369 eval_number) {
370 break;
371 }
372 } else {
373 // current_pos +=2;
374 if (APar_read16(uint32_buffer,
375 ISObasemediafile,
376 parsedAtoms[an_atom].AtomicStart + current_pos) ==
377 (uint16_t)eval_number) {
378 break;
379 }
380 }
381 if (current_pos >= parsedAtoms[an_atom].AtomicLength) {
382 current_pos = 0;
383 break;
384 }
385 }
386 return (uint32_t)current_pos;
387 }
388
389 ///////////////////////////////////////////////////////////////////////////////////////
390 // Language specifics //
391 ///////////////////////////////////////////////////////////////////////////////////////
392
APar_UnpackLanguage(unsigned char lang_code[],uint16_t packed_language)393 void APar_UnpackLanguage(unsigned char lang_code[], uint16_t packed_language) {
394 lang_code[3] = 0;
395 lang_code[2] = (packed_language & 0x1F) + 0x60;
396 lang_code[1] = ((packed_language >> 5) & 0x1F) + 0x60;
397 lang_code[0] = ((packed_language >> 10) & 0x1F) + 0x60;
398 return;
399 }
400
PackLanguage(const char * language_code,uint8_t lang_offset)401 uint16_t PackLanguage(
402 const char *language_code,
403 uint8_t lang_offset) { //?? is there a problem here? und does't work
404 // http://www.w3.org/WAI/ER/IG/ert/iso639.htm
405 // I think Apple's 3gp asses decoder is a little off. First, it doesn't
406 // support a lot of those 3 letter language codes above on that page. for
407 // example 'zul' blocks *all* metadata from showing up. 'fre' is a no-no, but
408 // 'fra' is fine. then, the spec calls for all strings to be null terminated.
409 // So then why does a '� 2005' (with a NULL at the end) show up as '� 2005' in
410 // 'pol', but '� 2005 ?' in 'fas' Farsi? Must be Apple's implementation,
411 // because the files are identical except for the uint16_t lang setting.
412
413 uint16_t packed_language = 0;
414
415 // fprintf(stdout, "%i, %i, %i\n", language_code[0+lang_offset],
416 // language_code[1+lang_offset], language_code[2+lang_offset]);
417
418 if (language_code[0 + lang_offset] < 97 ||
419 language_code[0 + lang_offset] > 122 ||
420 language_code[1 + lang_offset] < 97 ||
421 language_code[1 + lang_offset] > 122 ||
422 language_code[2 + lang_offset] < 97 ||
423 language_code[2 + lang_offset] > 122) {
424
425 return packed_language;
426 }
427
428 packed_language = (((language_code[0 + lang_offset] - 0x60) & 0x1F) << 10) |
429 (((language_code[1 + lang_offset] - 0x60) & 0x1F) << 5) |
430 ((language_code[2 + lang_offset] - 0x60) & 0x1F);
431 return packed_language;
432 }
433
434 ///////////////////////////////////////////////////////////////////////////////////////
435 // platform specifics //
436 ///////////////////////////////////////////////////////////////////////////////////////
437
438 #ifndef HAVE_STRSEP
439 // use glibc's strsep only on windows when cygwin & libc are undefined;
440 // otherwise the internal strsep will be used This marks the point where a
441 // ./configure & makefile combo would make this easier
442
443 /* Copyright (C) 1992, 93, 96, 97, 98, 99, 2004 Free Software Foundation, Inc.
444 This strsep function is part of the GNU C Library - v2.3.5; LGPL.
445 */
446
strsep(char ** stringp,const char * delim)447 char *strsep(char **stringp, const char *delim) {
448 char *begin, *end;
449
450 begin = *stringp;
451 if (begin == NULL)
452 return NULL;
453
454 // A frequent case is when the delimiter string contains only one character.
455 // Here we don't need to call the expensive `strpbrk' function and instead
456 // work using `strchr'.
457 if (delim[0] == '\0' || delim[1] == '\0') {
458 char ch = delim[0];
459
460 if (ch == '\0')
461 end = NULL;
462 else {
463 if (*begin == ch)
464 end = begin;
465 else if (*begin == '\0')
466 end = NULL;
467 else
468 end = strchr(begin + 1, ch);
469 }
470 } else
471
472 end = strpbrk(begin, delim); // Find the end of the token.
473
474 if (end) {
475 *end++ = '\0'; // Terminate the token and set *STRINGP past NUL character.
476 *stringp = end;
477 } else
478 *stringp = NULL; // No more delimiters; this is the last token.
479
480 return begin;
481 }
482 #endif
483
determine_MonthDay(int literal_day,int & month,int & day)484 void determine_MonthDay(int literal_day, int &month, int &day) {
485 if (literal_day <= 31) {
486 month = 1;
487 day = literal_day;
488
489 } else if (literal_day <= 59) {
490 month = 2;
491 day = literal_day - 31;
492
493 } else if (literal_day <= 90) {
494 month = 3;
495 day = literal_day - 59;
496
497 } else if (literal_day <= 120) {
498 month = 4;
499 day = literal_day - 90;
500
501 } else if (literal_day <= 151) {
502 month = 5;
503 day = literal_day - 120;
504
505 } else if (literal_day <= 181) {
506 month = 6;
507 day = literal_day - 151;
508
509 } else if (literal_day <= 212) {
510 month = 7;
511 day = literal_day - 181;
512
513 } else if (literal_day <= 243) {
514 month = 8;
515 day = literal_day - 212;
516
517 } else if (literal_day <= 273) {
518 month = 9;
519 day = literal_day - 243;
520
521 } else if (literal_day <= 304) {
522 month = 10;
523 day = literal_day - 273;
524
525 } else if (literal_day <= 334) {
526 month = 11;
527 day = literal_day - 304;
528
529 } else if (literal_day <= 365) {
530 month = 12;
531 day = literal_day - 334;
532 }
533 return;
534 }
535
APar_gmtime64(uint64_t total_secs,char * utc_time)536 char *APar_gmtime64(uint64_t total_secs, char *utc_time) {
537 // this will probably be off between Jan 1 & Feb 28 on a leap year by a
538 // day.... I'll somehow cope & deal.
539 struct tm timeinfo = {0, 0, 0, 0, 0};
540
541 int offset_year =
542 (int)(total_secs / 31536000); // 60 * 60 * 24 * 365 (ordinary year in
543 // seconds; doesn't account for leap year)
544 int literal_year = 1904 + offset_year;
545 int literal_days_into_year = ((total_secs % 31536000) / 86400) -
546 (offset_year / 4); // accounts for the leap year
547
548 uint32_t literal_seconds_into_day = total_secs % 86400;
549
550 int month = 0;
551 int days = 0;
552
553 determine_MonthDay(literal_days_into_year, month, days);
554
555 if (literal_days_into_year < 0) {
556 literal_year -= 1;
557 literal_days_into_year = 31 + literal_days_into_year;
558 month = 12;
559 days = literal_days_into_year;
560 }
561
562 int hours = literal_seconds_into_day / 3600;
563
564 timeinfo.tm_year = literal_year - 1900;
565 timeinfo.tm_yday = literal_days_into_year;
566 timeinfo.tm_mon = month - 1;
567 timeinfo.tm_mday = days;
568 timeinfo.tm_wday = (((total_secs / 86400) - (offset_year / 4)) - 5) % 7;
569
570 timeinfo.tm_hour = hours;
571 timeinfo.tm_min = (literal_seconds_into_day - (hours * 3600)) / 60;
572 timeinfo.tm_sec = (int)(literal_seconds_into_day % 60);
573
574 strftime(utc_time, 50, "%a %b %d %H:%M:%S %Y", &timeinfo);
575 return utc_time;
576 }
577
578 /*----------------------
579 ExtractUTC
580 total_secs - the time in seconds (from Jan 1, 1904)
581
582 Convert the seconds to a calendar date with seconds.
583 ----------------------*/
APar_extract_UTC(uint64_t total_secs)584 char *APar_extract_UTC(uint64_t total_secs) {
585 // 2082844800 seconds between 01/01/1904 & 01/01/1970
586 // 2,081,376,000 (60 seconds * 60 minutes * 24 hours * 365 days * 66 years)
587 // + 1,468,800 (60 * 60 * 24 * 17 leap days in 01/01/1904 to 01/01/1970
588 // duration)
589 //= 2,082,844,800
590 static char utc_time[50];
591 memset(utc_time, 0, 50);
592
593 if (total_secs > MAXTIME_32) {
594 return APar_gmtime64(total_secs, utc_time);
595 } else {
596 if (total_secs < 2082844800) {
597 return APar_gmtime64(total_secs, utc_time); // less than Unix epoch
598 } else {
599 total_secs -= 2082844800;
600 time_t reduced_seconds = (time_t)total_secs;
601 strftime(
602 *&utc_time, 50, "%a %b %d %H:%M:%S %Y", gmtime(&reduced_seconds));
603 return *&utc_time;
604 }
605 }
606 return *&utc_time;
607 }
608
APar_get_mpeg4_time()609 uint32_t APar_get_mpeg4_time() {
610 #if defined(_WIN32) && !defined(__CYGWIN__)
611 FILETIME file_time;
612 uint64_t wintime = 0;
613 GetSystemTimeAsFileTime(&file_time);
614 wintime =
615 (((uint64_t)file_time.dwHighDateTime << 32) | file_time.dwLowDateTime) /
616 10000000;
617 wintime -= 9561628800ULL;
618 return (uint32_t)wintime;
619
620 #else
621 uint32_t current_time_in_seconds = 0;
622 struct timeval tv;
623 gettimeofday(&tv, NULL);
624 current_time_in_seconds = tv.tv_sec;
625 return current_time_in_seconds + 2082844800;
626
627 #endif
628 return 0;
629 }
630
631 /*----------------------
632 APar_StandardTime
633 formed_time - the destination string
634
635 Print the ISO 8601 Coordinated Universal Time (UTC) timestamp (in
636 YYYY-MM-DDTHH:MM:SSZ form)
637 ----------------------*/
APar_StandardTime(char * & formed_time)638 void APar_StandardTime(char *&formed_time) {
639 time_t rawtime;
640 struct tm *timeinfo;
641
642 time(&rawtime);
643 timeinfo = gmtime(&rawtime);
644 strftime(formed_time,
645 100,
646 "%Y-%m-%dT%H:%M:%SZ",
647 timeinfo); // that hanging Z is there; denotes the UTC
648
649 return;
650 }
651
652 ///////////////////////////////////////////////////////////////////////////////////////
653 // strings //
654 ///////////////////////////////////////////////////////////////////////////////////////
655
656 wchar_t *
Convert_multibyteUTF16_to_wchar(char * input_unicode,size_t glyph_length,bool skip_BOM)657 Convert_multibyteUTF16_to_wchar(char *input_unicode,
658 size_t glyph_length,
659 bool skip_BOM) { // TODO: is this like wcstombs?
660 int BOM_mark_bytes = 0;
661 if (skip_BOM) {
662 BOM_mark_bytes = 2;
663 }
664
665 wchar_t *utf16_data = (wchar_t *)malloc(
666 sizeof(wchar_t) *
667 (glyph_length + 1)); // just to be sure there will be a trailing NULL
668 wmemset(utf16_data, 0, glyph_length + 1);
669
670 for (size_t i = 0; i < glyph_length; i++) {
671 #if defined(__ppc__) || defined(__ppc64__)
672 utf16_data[i] = (input_unicode[2 * i + BOM_mark_bytes] & 0x00ff) << 8 |
673 (input_unicode[2 * i + 1 + BOM_mark_bytes])
674 << 0; //+2 & +3 to skip over the BOM
675 #else
676 utf16_data[i] = (input_unicode[2 * i + BOM_mark_bytes] << 8) |
677 ((input_unicode[2 * i + 1 + BOM_mark_bytes]) & 0x00ff)
678 << 0; //+2 & +3 to skip over the BOM
679 #endif
680 }
681 return utf16_data;
682 }
683
Convert_multibyteUTF16_to_UTF8(char * input_utf16,size_t glyph_length,size_t byte_count)684 unsigned char *Convert_multibyteUTF16_to_UTF8(char *input_utf16,
685 size_t glyph_length,
686 size_t byte_count) {
687 unsigned char *utf8_data =
688 (unsigned char *)malloc(sizeof(unsigned char) * glyph_length);
689 memset(utf8_data, 0, glyph_length);
690
691 UTF16BEToUTF8(
692 utf8_data, glyph_length, (unsigned char *)input_utf16 + 2, byte_count);
693 return utf8_data;
694 }
695
Convert_multibyteUTF8_to_wchar(const char * input_utf8)696 wchar_t *Convert_multibyteUTF8_to_wchar(
697 const char *input_utf8) { // TODO: is this like mbstowcs?
698 wchar_t *return_val = NULL;
699 size_t string_length = strlen(input_utf8) + 1; // account for terminating NULL
700 size_t char_glyphs = mbstowcs(
701 NULL,
702 input_utf8,
703 string_length); // passing NULL pre-calculates the size of wchar_t needed
704
705 unsigned char *utf16_conversion =
706 (unsigned char *)malloc(sizeof(unsigned char) * string_length * 2);
707 memset(utf16_conversion, 0, string_length * 2);
708
709 int utf_16_glyphs = UTF8ToUTF16BE(utf16_conversion,
710 char_glyphs * 2,
711 (unsigned char *)input_utf8,
712 string_length) /
713 2; // returned value is in bytes
714 return_val = Convert_multibyteUTF16_to_wchar(
715 (char *)utf16_conversion, (size_t)utf_16_glyphs, false);
716 free(utf16_conversion);
717 utf16_conversion = NULL;
718 return (return_val);
719 }
720
721 // these flags from id3v2 2.4
722 // 0x00 = ISO-8859-1 & terminate with 0x00.
723 // 0x01 = UTF-16 with BOM. All frames have same encoding & terminate with
724 // 0x0000. 0x02 = UTF-16BE without BOM & terminate with 0x0000. 0x03 = UTF-8 &
725 // terminated with 0x00. buffer can hold either ut8 or utf16 carried on 8-bit
726 // char which requires a cast
727 /*----------------------
728 findstringNULLterm
729 in_string - pointer to location of a string (can be either 8859-1, utf8 or
730 utf16be/utf16be needing a cast to wchar) encodingFlag - used to denote the
731 encoding of instring (derived from id3v2 2.4 encoding flags) max_len - the
732 length of given string - there may be no NULL terminaiton, in which case it will
733 only count to max_len
734
735 Either find the NULL if it exists and return how many bytes into in_string
736 that NULL exists, or it won't find a NULL and return max_len
737 ----------------------*/
738 uint32_t
findstringNULLterm(char * in_string,uint8_t encodingFlag,uint32_t max_len)739 findstringNULLterm(char *in_string, uint8_t encodingFlag, uint32_t max_len) {
740 uint32_t byte_count = 0;
741
742 if (encodingFlag == 0x00 || encodingFlag == 0x03) {
743 char *bufptr = in_string;
744 while (bufptr <= in_string + max_len) {
745 if (*bufptr == 0x00) {
746 break;
747 }
748 bufptr++;
749 byte_count++;
750 }
751 } else if ((encodingFlag == 0x01 || encodingFlag == 0x02) && max_len >= 2) {
752 short wbufptr;
753 while (byte_count <= max_len) {
754 wbufptr =
755 (*(in_string + byte_count) << 8) | *(in_string + byte_count + 1);
756 if (wbufptr == 0x0000) {
757 break;
758 }
759 byte_count += 2;
760 }
761 }
762 if (byte_count > max_len)
763 return max_len;
764 return byte_count;
765 }
766
skipNULLterm(char * in_string,uint8_t encodingFlag,uint32_t max_len)767 uint32_t skipNULLterm(char *in_string, uint8_t encodingFlag, uint32_t max_len) {
768 uint32_t byte_count = 0;
769
770 if (encodingFlag == 0x00 || encodingFlag == 0x03) {
771 char *bufptr = in_string;
772 while (bufptr <= in_string + max_len) {
773 if (*bufptr == 0x00) {
774 byte_count++;
775 break;
776 }
777 bufptr++;
778 }
779 } else if ((encodingFlag == 0x01 || encodingFlag == 0x02) && max_len >= 2) {
780 short wbufptr;
781 while (byte_count <= max_len) {
782 wbufptr =
783 (*(in_string + byte_count) << 8) | *(in_string + byte_count + 1);
784 if (wbufptr == 0x0000) {
785 byte_count += 2;
786 break;
787 }
788 }
789 }
790 return byte_count;
791 }
792
793 ///////////////////////////////////////////////////////////////////////////////////////
794 // generics //
795 ///////////////////////////////////////////////////////////////////////////////////////
796
UInt16FromBigEndian(const char * string)797 uint16_t UInt16FromBigEndian(const char *string) {
798 #if defined(__ppc__) || defined(__ppc64__)
799 uint16_t test;
800 memcpy(&test, string, 2);
801 return test;
802 #else
803 return (((string[0] & 0xff) << 8) | (string[1] & 0xff) << 0);
804 #endif
805 }
806
UInt32FromBigEndian(const char * string)807 uint32_t UInt32FromBigEndian(const char *string) {
808 #if defined(__ppc__) || defined(__ppc64__)
809 uint32_t test;
810 memcpy(&test, string, 4);
811 return test;
812 #else
813 return (((string[0] & 0xff) << 24) | ((string[1] & 0xff) << 16) |
814 ((string[2] & 0xff) << 8) | (string[3] & 0xff) << 0);
815 #endif
816 }
817
UInt64FromBigEndian(const char * string)818 uint64_t UInt64FromBigEndian(const char *string) {
819 #if defined(__ppc__) || defined(__ppc64__)
820 uint64_t test;
821 memcpy(&test, string, 8);
822 return test;
823 #else
824 return (uint64_t)(string[0] & 0xff) << 54 |
825 (uint64_t)(string[1] & 0xff) << 48 |
826 (uint64_t)(string[2] & 0xff) << 40 |
827 (uint64_t)(string[3] & 0xff) << 32 |
828 (uint64_t)(string[4] & 0xff) << 24 |
829 (uint64_t)(string[5] & 0xff) << 16 |
830 (uint64_t)(string[6] & 0xff) << 8 | (uint64_t)(string[7] & 0xff) << 0;
831 #endif
832 }
833
UInt16_TO_String2(uint16_t snum,char * data)834 void UInt16_TO_String2(uint16_t snum, char *data) {
835 data[0] = (snum >> 8) & 0xff;
836 data[1] = (snum >> 0) & 0xff;
837 return;
838 }
839
UInt32_TO_String4(uint32_t lnum,char * data)840 void UInt32_TO_String4(uint32_t lnum, char *data) {
841 data[0] = (lnum >> 24) & 0xff;
842 data[1] = (lnum >> 16) & 0xff;
843 data[2] = (lnum >> 8) & 0xff;
844 data[3] = (lnum >> 0) & 0xff;
845 return;
846 }
847
UInt64_TO_String8(uint64_t ullnum,char * data)848 void UInt64_TO_String8(uint64_t ullnum, char *data) {
849 data[0] = (ullnum >> 56) & 0xff;
850 data[1] = (ullnum >> 48) & 0xff;
851 data[2] = (ullnum >> 40) & 0xff;
852 data[3] = (ullnum >> 32) & 0xff;
853 data[4] = (ullnum >> 24) & 0xff;
854 data[5] = (ullnum >> 16) & 0xff;
855 data[6] = (ullnum >> 8) & 0xff;
856 data[7] = (ullnum >> 0) & 0xff;
857 return;
858 }
859
860 ///////////////////////////////////////////////////////////////////////////////////////
861 // 3gp asset support (for 'loci') //
862 ///////////////////////////////////////////////////////////////////////////////////////
863
float_to_16x16bit_fixed_point(double floating_val)864 uint32_t float_to_16x16bit_fixed_point(double floating_val) {
865 uint32_t fixedpoint_16bit = 0;
866 int16_t long_integer = (int16_t)floating_val;
867 // to get a fixed 16-bit decimal, work on the decimal part along; multiply by
868 // (2^8 * 2) which moves the decimal over 16 bits to create our int16_t now
869 // while the degrees can be negative (requiring a int16_6), the decimal
870 // portion is always positive (and thus requiring a uint16_t)
871 uint16_t long_decimal =
872 (int16_t)((floating_val - long_integer) * (double)(65536));
873 fixedpoint_16bit =
874 long_integer * 65536 +
875 long_decimal; // same as bitshifting, less headache doing it
876 return fixedpoint_16bit;
877 }
878
fixed_point_16x16bit_to_double(uint32_t fixed_point)879 double fixed_point_16x16bit_to_double(uint32_t fixed_point) {
880 double return_val = 0.0;
881 int16_t long_integer = fixed_point / 65536;
882 uint16_t long_decimal = fixed_point - (long_integer * 65536);
883 return_val = long_integer + ((double)long_decimal / 65536);
884
885 if (return_val < 0.0) {
886 return_val -= 1.0;
887 }
888
889 return return_val;
890 }
891
widechar_len(char * instring,uint32_t _bytes_)892 uint32_t widechar_len(char *instring, uint32_t _bytes_) {
893 uint32_t wstring_len = 0;
894 for (uint32_t i = 0; i <= _bytes_ / 2; i++) {
895 if (instring[0] == 0 && instring[1] == 0) {
896 break;
897 } else {
898 instring += 2;
899 wstring_len++;
900 }
901 }
902 return wstring_len;
903 }
904
APar_assert(bool expression,int error_msg,const char * supplemental_info)905 bool APar_assert(bool expression,
906 int error_msg,
907 const char *supplemental_info) {
908 bool force_break = true;
909 if (!expression) {
910 force_break = false;
911 switch (error_msg) {
912 case 1: { // trying to set an iTunes-style metadata tag on an
913 // 3GP/MobileMPEG-4
914 fprintf(stdout,
915 "AP warning:\n\tSetting the %s tag is for ordinary MPEG-4 "
916 "files.\n\tIt is not supported on 3gp/amc files.\nSkipping\n",
917 supplemental_info);
918 break;
919 }
920
921 case 2: { // trying to set a 3gp asset on an mpeg-4 file with the improper
922 // brand
923 fprintf(stdout,
924 "AP warning:\n\tSetting the %s asset is only available on 3GPP "
925 "files branded 3gp6 or later.\nSkipping\n",
926 supplemental_info);
927 break;
928 }
929
930 case 3: { // trying to set 'meta' on a file without a iso2 or mp42
931 // compatible brand.
932 fprintf(stdout,
933 "AtomicParsley warning: ID3 tags requires a v2 "
934 "compatible file, which was not found.\nSkipping.\n");
935 break;
936 }
937 case 4: { // trying to set a 3gp album asset on an early 3gp file that only
938 // came into being with 3gp6
939 fprintf(stdout, "Major brand of given file: %s\n", supplemental_info);
940 break;
941 }
942 case 5: { // trying to set metadata on track 33 when there are only 3 tracks
943 fprintf(stdout,
944 "AP warning: skipping non-existing track number setting user "
945 "data atom: %s.\n",
946 supplemental_info);
947 break;
948 }
949 case 6: { // trying to set id3 metadata on track 33 when there are only 3
950 // tracks
951 fprintf(stdout,
952 "AP error: skipping non-existing track number setting frame %s "
953 "for ID32 atom.\n",
954 supplemental_info);
955 break;
956 }
957 case 7: { // trying to set id3 metadata on track 33 when there are only 3
958 // tracks
959 fprintf(stdout,
960 "AP warning: the 'meta' atom is being hangled by a %s handler.\n "
961 " Remove the 'meta' atom and its contents and try again.\n",
962 supplemental_info);
963 break;
964 }
965 case 8: { // trying to create an ID32 atom when there is a primary item atom
966 // present signaling referenced data (local or external)
967 fprintf(stdout,
968 "AP warning: unsupported external or referenced items were "
969 "detected. Skipping this frame: %s\n",
970 supplemental_info);
971 break;
972 }
973 case 9: { // trying to eliminate an id3 frame that doesn't exist
974 fprintf(stdout,
975 "AP warning: id3 frame %s cannot be deleted because it does not "
976 "exist.\n",
977 supplemental_info);
978 break;
979 }
980 case 10: { // trying to eliminate an id3 frame that doesn't exist
981 fprintf(stdout,
982 "AP warning: skipping setting unknown %s frame\n",
983 supplemental_info);
984 break;
985 }
986 case 11: { // insuffient memory to malloc an id3 field (probably picture or
987 // encapuslated object)
988 fprintf(stdout,
989 "AP error: memory was not alloctated for frame %s. Exiting.\n",
990 supplemental_info);
991 break;
992 }
993 }
994 }
995 return force_break;
996 }
997
998 /* http://wwwmaths.anu.edu.au/~brent/random.html */
999 /* xorgens.c version 3.04, R. P. Brent, 20060628. */
1000
1001 /* For type definitions see xorgens.h */
1002
1003 typedef unsigned long xorgenUINT;
1004
xor4096i()1005 unsigned long xor4096i() {
1006 /* 32-bit or 64-bit integer random number generator
1007 with period at least 2**4096-1.
1008
1009 It is assumed that "xorgenUINT" is a 32-bit or 64-bit integer
1010 (see typedef statements in xorgens.h).
1011
1012 xor4096i should be called exactly once with nonzero seed, and
1013 thereafter with zero seed.
1014
1015 One random number uniformly distributed in [0..2**wlen) is returned,
1016 where wlen = 8*sizeof(xorgenUINT) = 32 or 64.
1017
1018 R. P. Brent, 20060628.
1019 */
1020
1021 /* UINT64 is TRUE if 64-bit xorgenUINT,
1022 UINT32 is TRUE otherwise (assumed to be 32-bit xorgenUINT). */
1023
1024 #define UINT64 (sizeof(xorgenUINT) >> 3)
1025 #define UINT32 (1 - UINT64)
1026
1027 #define wlen (64 * UINT64 + 32 * UINT32)
1028 #define r (64 * UINT64 + 128 * UINT32)
1029 #define s (53 * UINT64 + 95 * UINT32)
1030 #define a (33 * UINT64 + 17 * UINT32)
1031 #define b (26 * UINT64 + 12 * UINT32)
1032 #define c (27 * UINT64 + 13 * UINT32)
1033 #define d (29 * UINT64 + 15 * UINT32)
1034 #define ws (27 * UINT64 + 16 * UINT32)
1035
1036 xorgenUINT seed = 0;
1037
1038 static xorgenUINT w, weyl, zero = 0, x[r];
1039 xorgenUINT t, v;
1040 static int i = -1; /* i < 0 indicates first call */
1041 int k;
1042
1043 if (i < 0) {
1044 #if defined HAVE_SRANDDEV
1045 sranddev();
1046 #else
1047 srand((int)time(NULL));
1048 #endif
1049 double doubleseed = ((double)rand() / ((double)(RAND_MAX) + (double)(1)));
1050 seed = (xorgenUINT)(doubleseed * rand());
1051 }
1052
1053 if ((i < 0) || (seed != zero)) { /* Initialisation necessary */
1054
1055 /* weyl = odd approximation to 2**wlen*(sqrt(5)-1)/2. */
1056
1057 if (UINT32)
1058 weyl = 0x61c88647;
1059 else
1060 weyl = ((((xorgenUINT)0x61c88646) << 16) << 16) + (xorgenUINT)0x80b583eb;
1061
1062 v = (seed != zero) ? seed : ~seed; /* v must be nonzero */
1063
1064 for (k = wlen; k > 0; k--) { /* Avoid correlations for close seeds */
1065 v ^= v << 10;
1066 v ^= v >> 15; /* Recurrence has period 2**wlen-1 */
1067 v ^= v << 4;
1068 v ^= v >> 13; /* for wlen = 32 or 64 */
1069 }
1070 for (w = v, k = 0; (xorgenUINT)k < r; k++) { /* Initialise circular array */
1071 v ^= v << 10;
1072 v ^= v >> 15;
1073 v ^= v << 4;
1074 v ^= v >> 13;
1075 x[k] = v + (w += weyl);
1076 }
1077 for (i = r - 1, k = 4 * r; k > 0; k--) { /* Discard first 4*r results */
1078 t = x[i = (i + 1) & (r - 1)];
1079 t ^= t << a;
1080 t ^= t >> b;
1081 v = x[(i + (r - s)) & (r - 1)];
1082 v ^= v << c;
1083 v ^= v >> d;
1084 x[i] = t ^ v;
1085 }
1086 }
1087
1088 /* Apart from initialisation (above), this is the generator */
1089
1090 t = x[i = (i + 1) & (r - 1)]; /* Assumes that r is a power of two */
1091 v = x[(i + (r - s)) & (r - 1)]; /* Index is (i-s) mod r */
1092 t ^= t << a;
1093 t ^= t >> b; /* (I + L^a)(I + R^b) */
1094 v ^= v << c;
1095 v ^= v >> d; /* (I + L^c)(I + R^d) */
1096 x[i] = (v ^= t); /* Update circular array */
1097 w += weyl; /* Update Weyl generator */
1098 return (v + (w ^ (w >> ws))); /* Return combination */
1099
1100 #undef UINT64
1101 #undef UINT32
1102 #undef wlen
1103 #undef r
1104 #undef s
1105 #undef a
1106 #undef b
1107 #undef c
1108 #undef d
1109 #undef ws
1110 }
1111