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