//==================================================================// /* AtomicParsley - util.cpp AtomicParsley is GPL software; you can freely distribute, redistribute, modify & use under the terms of the GNU General Public License; either version 2 or its successor. AtomicParsley is distributed under the GPL "AS IS", without any warranty; without the implied warranty of merchantability or fitness for either an expressed or implied particular purpose. Please see the included GNU General Public License (GPL) for your rights and further details; see the file COPYING. If you cannot, write to the Free Software Foundation, 59 Temple Place Suite 330, Boston, MA 02111-1307, USA. Or www.fsf.org Copyright (C) 2006-2007 puck_lock with contributions from others; see the CREDITS file ---------------------- Code Contributions by: * SLarew - prevent writing past array in Convert_multibyteUTF16_to_wchar bugfix */ //==================================================================// #include "AtomicParsley.h" /////////////////////////////////////////////////////////////////////////////////////// // Filesytem routines // /////////////////////////////////////////////////////////////////////////////////////// /*---------------------- findFileSize utf8_filepath - a pointer to a string (possibly utf8) of the full path to the file take an ascii/utf8 filepath (which if under a unicode enabled Win32 OS was already converted from utf16le to utf8 at program start) and test if AP is running on a unicode enabled Win32 OS. If it is and converted to utf8 (rather than just stripped), convert the utf8 filepath to a utf16 (native-endian) filepath & pass that to a wide stat. Or stat it with a utf8 filepath on Unixen & win32 (stripped utf8). ----------------------*/ uint64_t findFileSize(const char *utf8_filepath) { #if defined(_WIN32) && !defined(__CYGWIN__) if (IsUnicodeWinOS() && UnicodeOutputStatus == WIN32_UTF16) { wchar_t *utf16_filepath = Convert_multibyteUTF8_to_wchar(utf8_filepath); struct _stati64 fileStats; _wstati64(utf16_filepath, &fileStats); free(utf16_filepath); utf16_filepath = NULL; return fileStats.st_size; } else #endif { struct stat fileStats; stat(utf8_filepath, &fileStats); return fileStats.st_size; } return 0; // won't ever get here.... unless this is win32, set to utf8 and the // folder/file had unicode.... TODO (? use isUTF8() for high ascii?) } /*---------------------- APar_OpenFile utf8_filepath - a pointer to a string (possibly utf8) of the full path to the file file_flags - 3 bytes max for the flags to open the file with (read, write, binary mode....) take an ascii/utf8 filepath (which if under a unicode enabled Win32 OS was already converted from utf16le to utf8 at program start) and test if AP is running on a unicode enabled Win32 OS. If it is, convert the utf8 filepath to a utf16 (native-endian) filepath & pass that to a wide fopen with the 8-bit file flags changed to 16-bit file flags. Or open a utf8 file with vanilla fopen on Unixen. ----------------------*/ FILE *APar_OpenFile(const char *utf8_filepath, const char *file_flags) { FILE *aFile = NULL; #if defined(_WIN32) && !defined(__CYGWIN__) if (IsUnicodeWinOS() && UnicodeOutputStatus == WIN32_UTF16) { wchar_t *Lfile_flags = (wchar_t *)malloc(sizeof(wchar_t) * 4); memset(Lfile_flags, 0, sizeof(wchar_t) * 4); mbstowcs(Lfile_flags, file_flags, strlen(file_flags)); wchar_t *utf16_filepath = Convert_multibyteUTF8_to_wchar(utf8_filepath); aFile = _wfopen(utf16_filepath, Lfile_flags); free(Lfile_flags); Lfile_flags = NULL; free(utf16_filepath); utf16_filepath = NULL; } else #endif { aFile = fopen(utf8_filepath, file_flags); } if (!aFile) { fprintf(stdout, "AP error trying to fopen %s: %s\n", utf8_filepath, strerror(errno)); } return aFile; } /*---------------------- openSomeFile utf8_filepath - a pointer to a string (possibly utf8) of the full path to the file open - flag to either open or close (function does both) take an ascii/utf8 filepath and either open or close it; used for the main ISO Base Media File; store the resulting FILE* in a global source_file ----------------------*/ FILE *APar_OpenISOBaseMediaFile(const char *utf8file, bool open) { if (open && !file_opened) { source_file = APar_OpenFile(utf8file, "rb"); if (source_file != nullptr) { file_opened = true; } } else if (file_opened) { fclose(source_file); file_opened = false; source_file = nullptr; } return source_file; } void TestFileExistence(const char *filePath, bool errorOut) { FILE *a_file = NULL; a_file = APar_OpenFile(filePath, "rb"); if ((a_file == NULL) && errorOut) { fprintf(stderr, "AtomicParsley error: can't open %s for reading: %s\n", filePath, strerror(errno)); exit(1); } else { if (a_file == NULL) { fprintf(stderr, "AtomicParsley warning: can't open %s for reading but continuing " "anyway: %s\n", filePath, strerror(errno)); } else { fclose(a_file); } } } #ifndef HAVE_FSEEKO #ifdef _WIN32 int fseeko(FILE *stream, off_t pos, int whence) { return _fseeki64(stream, pos, whence); } off_t ftello(FILE *stream) { return _ftelli64(stream); } #else int fseeko(FILE *stream, off_t pos, int whence) { return fseek(stream, pos, whence); } off_t ftello(FILE *stream) { return ftell(stream); } #endif #endif #if defined(_WIN32) /////////////////////////////////////////////////////////////////////////////////////// // Win32 functions // /////////////////////////////////////////////////////////////////////////////////////// /*---------------------- APar_OpenFileWin32 utf8_filepath - a pointer to a string (possibly utf8) of the full path to the file ... - passed on to the CreateFile function take an ascii/utf8 filepath (which if under a unicode enabled Win32 OS was already converted from utf16le to utf8 at program start) and test if AP is running on a unicode enabled Win32 OS. If it is, convert the utf8 filepath to a utf16 (native-endian) filepath & pass that to a wide CreateFile with the 8-bit file flags changed to 16-bit file flags, otherwise pass the utf8 filepath to an ANSI CreateFile ----------------------*/ HANDLE APar_OpenFileWin32(const char *utf8_filepath, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) { if (IsUnicodeWinOS() && UnicodeOutputStatus == WIN32_UTF16) { HANDLE hFile = NULL; wchar_t *utf16_filepath = Convert_multibyteUTF8_to_wchar(utf8_filepath); hFile = CreateFileW(utf16_filepath, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); free(utf16_filepath); return hFile; } else { return CreateFileA(utf8_filepath, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); } } #endif // http://www.flipcode.com/articles/article_advstrings01.shtml bool IsUnicodeWinOS() { #if defined(_WIN32) OSVERSIONINFOW os; memset(&os, 0, sizeof(OSVERSIONINFOW)); os.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW); return (GetVersionExW(&os) != 0); #else return false; #endif } /////////////////////////////////////////////////////////////////////////////////////// // File reading routines // /////////////////////////////////////////////////////////////////////////////////////// const char *APar_strferror(FILE *f) { if (feof(f) && ferror(f)) return "error and end of file"; else if (feof(f)) return "end of file"; else if (ferror(f)) return "error"; else return "neither error nor end of file"; } uint8_t APar_read8(FILE *ISObasemediafile, uint64_t pos) { uint8_t a_byte = 0; size_t size; fseeko(ISObasemediafile, pos, SEEK_SET); size = fread(&a_byte, 1, 1, ISObasemediafile); if (size != 1) { printf("%s read failed, expect 1, got %u: %s\n", __FUNCTION__, (unsigned int)size, APar_strferror(ISObasemediafile)); exit(1); } return a_byte; } uint16_t APar_read16(char *buffer, FILE *ISObasemediafile, uint64_t pos) { size_t size; fseeko(ISObasemediafile, pos, SEEK_SET); size = fread(buffer, 1, 2, ISObasemediafile); if (size != 2) { printf("%s read failed, expect 2, got %u: %s\n", __FUNCTION__, (unsigned int)size, APar_strferror(ISObasemediafile)); exit(1); } return UInt16FromBigEndian(buffer); } uint32_t APar_read32(char *buffer, FILE *ISObasemediafile, uint64_t pos) { size_t size; fseeko(ISObasemediafile, pos, SEEK_SET); size = fread(buffer, 1, 4, ISObasemediafile); if (size != 4) { printf("%s read failed, expect 4, got %u: %s\n", __FUNCTION__, (unsigned int)size, APar_strferror(ISObasemediafile)); exit(1); } return UInt32FromBigEndian(buffer); } uint64_t APar_read64(char *buffer, FILE *ISObasemediafile, uint64_t pos) { size_t size; fseeko(ISObasemediafile, pos, SEEK_SET); size = fread(buffer, 1, 8, ISObasemediafile); if (size != 8) { printf("%s read failed, expect 8, got %u: %s\n", __FUNCTION__, (unsigned int)size, APar_strferror(ISObasemediafile)); exit(1); } return UInt64FromBigEndian(buffer); } void APar_readX_noseek(char *buffer, FILE *ISObasemediafile, uint32_t length) { size_t size; size = fread(buffer, 1, length, ISObasemediafile); if (size != length) { printf("%s read failed, expect %" PRIu32 ", got %" PRIu32 ": %s\n", __FUNCTION__, length, (uint32_t)size, APar_strferror(ISObasemediafile)); exit(1); } return; } void APar_readX(char *buffer, FILE *ISObasemediafile, uint64_t pos, uint32_t length) { size_t size; fseeko(ISObasemediafile, pos, SEEK_SET); size = fread(buffer, 1, length, ISObasemediafile); if (size != length) { printf("%s read failed, expect %" PRIu32 ", got %" PRIu32 ": %s\n", __FUNCTION__, length, (uint32_t)size, APar_strferror(ISObasemediafile)); exit(1); } return; } uint32_t APar_ReadFile(char *destination_buffer, FILE *a_file, uint32_t bytes_to_read) { uint32_t bytes_read = 0; if (destination_buffer != NULL) { fseeko(a_file, 0, SEEK_SET); // not that 2gb support is required - malloc // would probably have a few issues bytes_read = fread(destination_buffer, 1, bytes_to_read, a_file); file_size += bytes_read; // accommodate huge files embedded within small // files for APar_Validate } return bytes_read; } uint32_t APar_FindValueInAtom(char *uint32_buffer, FILE *ISObasemediafile, short an_atom, uint64_t start_position, uint32_t eval_number) { uint64_t current_pos = start_position; memset(uint32_buffer, 0, 5); while (current_pos <= parsedAtoms[an_atom].AtomicLength) { current_pos++; if (eval_number > 65535) { // current_pos +=4; if (APar_read32(uint32_buffer, ISObasemediafile, parsedAtoms[an_atom].AtomicStart + current_pos) == eval_number) { break; } } else { // current_pos +=2; if (APar_read16(uint32_buffer, ISObasemediafile, parsedAtoms[an_atom].AtomicStart + current_pos) == (uint16_t)eval_number) { break; } } if (current_pos >= parsedAtoms[an_atom].AtomicLength) { current_pos = 0; break; } } return (uint32_t)current_pos; } /////////////////////////////////////////////////////////////////////////////////////// // Language specifics // /////////////////////////////////////////////////////////////////////////////////////// void APar_UnpackLanguage(unsigned char lang_code[], uint16_t packed_language) { lang_code[3] = 0; lang_code[2] = (packed_language & 0x1F) + 0x60; lang_code[1] = ((packed_language >> 5) & 0x1F) + 0x60; lang_code[0] = ((packed_language >> 10) & 0x1F) + 0x60; return; } uint16_t PackLanguage( const char *language_code, uint8_t lang_offset) { //?? is there a problem here? und does't work // http://www.w3.org/WAI/ER/IG/ert/iso639.htm // I think Apple's 3gp asses decoder is a little off. First, it doesn't // support a lot of those 3 letter language codes above on that page. for // example 'zul' blocks *all* metadata from showing up. 'fre' is a no-no, but // 'fra' is fine. then, the spec calls for all strings to be null terminated. // So then why does a '© 2005' (with a NULL at the end) show up as '© 2005' in // 'pol', but '© 2005 ?' in 'fas' Farsi? Must be Apple's implementation, // because the files are identical except for the uint16_t lang setting. uint16_t packed_language = 0; // fprintf(stdout, "%i, %i, %i\n", language_code[0+lang_offset], // language_code[1+lang_offset], language_code[2+lang_offset]); if (language_code[0 + lang_offset] < 97 || language_code[0 + lang_offset] > 122 || language_code[1 + lang_offset] < 97 || language_code[1 + lang_offset] > 122 || language_code[2 + lang_offset] < 97 || language_code[2 + lang_offset] > 122) { return packed_language; } packed_language = (((language_code[0 + lang_offset] - 0x60) & 0x1F) << 10) | (((language_code[1 + lang_offset] - 0x60) & 0x1F) << 5) | ((language_code[2 + lang_offset] - 0x60) & 0x1F); return packed_language; } /////////////////////////////////////////////////////////////////////////////////////// // platform specifics // /////////////////////////////////////////////////////////////////////////////////////// #ifndef HAVE_STRSEP // use glibc's strsep only on windows when cygwin & libc are undefined; // otherwise the internal strsep will be used This marks the point where a // ./configure & makefile combo would make this easier /* Copyright (C) 1992, 93, 96, 97, 98, 99, 2004 Free Software Foundation, Inc. This strsep function is part of the GNU C Library - v2.3.5; LGPL. */ char *strsep(char **stringp, const char *delim) { char *begin, *end; begin = *stringp; if (begin == NULL) return NULL; // A frequent case is when the delimiter string contains only one character. // Here we don't need to call the expensive `strpbrk' function and instead // work using `strchr'. if (delim[0] == '\0' || delim[1] == '\0') { char ch = delim[0]; if (ch == '\0') end = NULL; else { if (*begin == ch) end = begin; else if (*begin == '\0') end = NULL; else end = strchr(begin + 1, ch); } } else end = strpbrk(begin, delim); // Find the end of the token. if (end) { *end++ = '\0'; // Terminate the token and set *STRINGP past NUL character. *stringp = end; } else *stringp = NULL; // No more delimiters; this is the last token. return begin; } #endif void determine_MonthDay(int literal_day, int &month, int &day) { if (literal_day <= 31) { month = 1; day = literal_day; } else if (literal_day <= 59) { month = 2; day = literal_day - 31; } else if (literal_day <= 90) { month = 3; day = literal_day - 59; } else if (literal_day <= 120) { month = 4; day = literal_day - 90; } else if (literal_day <= 151) { month = 5; day = literal_day - 120; } else if (literal_day <= 181) { month = 6; day = literal_day - 151; } else if (literal_day <= 212) { month = 7; day = literal_day - 181; } else if (literal_day <= 243) { month = 8; day = literal_day - 212; } else if (literal_day <= 273) { month = 9; day = literal_day - 243; } else if (literal_day <= 304) { month = 10; day = literal_day - 273; } else if (literal_day <= 334) { month = 11; day = literal_day - 304; } else if (literal_day <= 365) { month = 12; day = literal_day - 334; } return; } char *APar_gmtime64(uint64_t total_secs, char *utc_time) { // this will probably be off between Jan 1 & Feb 28 on a leap year by a // day.... I'll somehow cope & deal. struct tm timeinfo = {0, 0, 0, 0, 0}; int offset_year = (int)(total_secs / 31536000); // 60 * 60 * 24 * 365 (ordinary year in // seconds; doesn't account for leap year) int literal_year = 1904 + offset_year; int literal_days_into_year = ((total_secs % 31536000) / 86400) - (offset_year / 4); // accounts for the leap year uint32_t literal_seconds_into_day = total_secs % 86400; int month = 0; int days = 0; determine_MonthDay(literal_days_into_year, month, days); if (literal_days_into_year < 0) { literal_year -= 1; literal_days_into_year = 31 + literal_days_into_year; month = 12; days = literal_days_into_year; } int hours = literal_seconds_into_day / 3600; timeinfo.tm_year = literal_year - 1900; timeinfo.tm_yday = literal_days_into_year; timeinfo.tm_mon = month - 1; timeinfo.tm_mday = days; timeinfo.tm_wday = (((total_secs / 86400) - (offset_year / 4)) - 5) % 7; timeinfo.tm_hour = hours; timeinfo.tm_min = (literal_seconds_into_day - (hours * 3600)) / 60; timeinfo.tm_sec = (int)(literal_seconds_into_day % 60); strftime(utc_time, 50, "%a %b %d %H:%M:%S %Y", &timeinfo); return utc_time; } /*---------------------- ExtractUTC total_secs - the time in seconds (from Jan 1, 1904) Convert the seconds to a calendar date with seconds. ----------------------*/ char *APar_extract_UTC(uint64_t total_secs) { // 2082844800 seconds between 01/01/1904 & 01/01/1970 // 2,081,376,000 (60 seconds * 60 minutes * 24 hours * 365 days * 66 years) // + 1,468,800 (60 * 60 * 24 * 17 leap days in 01/01/1904 to 01/01/1970 // duration) //= 2,082,844,800 static char utc_time[50]; memset(utc_time, 0, 50); if (total_secs > MAXTIME_32) { return APar_gmtime64(total_secs, utc_time); } else { if (total_secs < 2082844800) { return APar_gmtime64(total_secs, utc_time); // less than Unix epoch } else { total_secs -= 2082844800; time_t reduced_seconds = (time_t)total_secs; strftime( *&utc_time, 50, "%a %b %d %H:%M:%S %Y", gmtime(&reduced_seconds)); return *&utc_time; } } return *&utc_time; } uint32_t APar_get_mpeg4_time() { #if defined(_WIN32) && !defined(__CYGWIN__) FILETIME file_time; uint64_t wintime = 0; GetSystemTimeAsFileTime(&file_time); wintime = (((uint64_t)file_time.dwHighDateTime << 32) | file_time.dwLowDateTime) / 10000000; wintime -= 9561628800ULL; return (uint32_t)wintime; #else uint32_t current_time_in_seconds = 0; struct timeval tv; gettimeofday(&tv, NULL); current_time_in_seconds = tv.tv_sec; return current_time_in_seconds + 2082844800; #endif return 0; } /*---------------------- APar_StandardTime formed_time - the destination string Print the ISO 8601 Coordinated Universal Time (UTC) timestamp (in YYYY-MM-DDTHH:MM:SSZ form) ----------------------*/ void APar_StandardTime(char *&formed_time) { time_t rawtime; struct tm *timeinfo; time(&rawtime); timeinfo = gmtime(&rawtime); strftime(formed_time, 100, "%Y-%m-%dT%H:%M:%SZ", timeinfo); // that hanging Z is there; denotes the UTC return; } /////////////////////////////////////////////////////////////////////////////////////// // strings // /////////////////////////////////////////////////////////////////////////////////////// wchar_t * Convert_multibyteUTF16_to_wchar(char *input_unicode, size_t glyph_length, bool skip_BOM) { // TODO: is this like wcstombs? int BOM_mark_bytes = 0; if (skip_BOM) { BOM_mark_bytes = 2; } wchar_t *utf16_data = (wchar_t *)malloc( sizeof(wchar_t) * (glyph_length + 1)); // just to be sure there will be a trailing NULL wmemset(utf16_data, 0, glyph_length + 1); for (size_t i = 0; i < glyph_length; i++) { #if defined(__ppc__) || defined(__ppc64__) utf16_data[i] = (input_unicode[2 * i + BOM_mark_bytes] & 0x00ff) << 8 | (input_unicode[2 * i + 1 + BOM_mark_bytes]) << 0; //+2 & +3 to skip over the BOM #else utf16_data[i] = (input_unicode[2 * i + BOM_mark_bytes] << 8) | ((input_unicode[2 * i + 1 + BOM_mark_bytes]) & 0x00ff) << 0; //+2 & +3 to skip over the BOM #endif } return utf16_data; } unsigned char *Convert_multibyteUTF16_to_UTF8(char *input_utf16, size_t glyph_length, size_t byte_count) { unsigned char *utf8_data = (unsigned char *)malloc(sizeof(unsigned char) * glyph_length); memset(utf8_data, 0, glyph_length); UTF16BEToUTF8( utf8_data, glyph_length, (unsigned char *)input_utf16 + 2, byte_count); return utf8_data; } wchar_t *Convert_multibyteUTF8_to_wchar( const char *input_utf8) { // TODO: is this like mbstowcs? wchar_t *return_val = NULL; size_t string_length = strlen(input_utf8) + 1; // account for terminating NULL size_t char_glyphs = mbstowcs( NULL, input_utf8, string_length); // passing NULL pre-calculates the size of wchar_t needed unsigned char *utf16_conversion = (unsigned char *)malloc(sizeof(unsigned char) * string_length * 2); memset(utf16_conversion, 0, string_length * 2); int utf_16_glyphs = UTF8ToUTF16BE(utf16_conversion, char_glyphs * 2, (unsigned char *)input_utf8, string_length) / 2; // returned value is in bytes return_val = Convert_multibyteUTF16_to_wchar( (char *)utf16_conversion, (size_t)utf_16_glyphs, false); free(utf16_conversion); utf16_conversion = NULL; return (return_val); } // these flags from id3v2 2.4 // 0x00 = ISO-8859-1 & terminate with 0x00. // 0x01 = UTF-16 with BOM. All frames have same encoding & terminate with // 0x0000. 0x02 = UTF-16BE without BOM & terminate with 0x0000. 0x03 = UTF-8 & // terminated with 0x00. buffer can hold either ut8 or utf16 carried on 8-bit // char which requires a cast /*---------------------- findstringNULLterm in_string - pointer to location of a string (can be either 8859-1, utf8 or utf16be/utf16be needing a cast to wchar) encodingFlag - used to denote the encoding of instring (derived from id3v2 2.4 encoding flags) max_len - the length of given string - there may be no NULL terminaiton, in which case it will only count to max_len Either find the NULL if it exists and return how many bytes into in_string that NULL exists, or it won't find a NULL and return max_len ----------------------*/ uint32_t findstringNULLterm(char *in_string, uint8_t encodingFlag, uint32_t max_len) { uint32_t byte_count = 0; if (encodingFlag == 0x00 || encodingFlag == 0x03) { char *bufptr = in_string; while (bufptr <= in_string + max_len) { if (*bufptr == 0x00) { break; } bufptr++; byte_count++; } } else if ((encodingFlag == 0x01 || encodingFlag == 0x02) && max_len >= 2) { short wbufptr; while (byte_count <= max_len) { wbufptr = (*(in_string + byte_count) << 8) | *(in_string + byte_count + 1); if (wbufptr == 0x0000) { break; } byte_count += 2; } } if (byte_count > max_len) return max_len; return byte_count; } uint32_t skipNULLterm(char *in_string, uint8_t encodingFlag, uint32_t max_len) { uint32_t byte_count = 0; if (encodingFlag == 0x00 || encodingFlag == 0x03) { char *bufptr = in_string; while (bufptr <= in_string + max_len) { if (*bufptr == 0x00) { byte_count++; break; } bufptr++; } } else if ((encodingFlag == 0x01 || encodingFlag == 0x02) && max_len >= 2) { short wbufptr; while (byte_count <= max_len) { wbufptr = (*(in_string + byte_count) << 8) | *(in_string + byte_count + 1); if (wbufptr == 0x0000) { byte_count += 2; break; } } } return byte_count; } /////////////////////////////////////////////////////////////////////////////////////// // generics // /////////////////////////////////////////////////////////////////////////////////////// uint16_t UInt16FromBigEndian(const char *string) { #if defined(__ppc__) || defined(__ppc64__) uint16_t test; memcpy(&test, string, 2); return test; #else return (((string[0] & 0xff) << 8) | (string[1] & 0xff) << 0); #endif } uint32_t UInt32FromBigEndian(const char *string) { #if defined(__ppc__) || defined(__ppc64__) uint32_t test; memcpy(&test, string, 4); return test; #else return (((string[0] & 0xff) << 24) | ((string[1] & 0xff) << 16) | ((string[2] & 0xff) << 8) | (string[3] & 0xff) << 0); #endif } uint64_t UInt64FromBigEndian(const char *string) { #if defined(__ppc__) || defined(__ppc64__) uint64_t test; memcpy(&test, string, 8); return test; #else return (uint64_t)(string[0] & 0xff) << 54 | (uint64_t)(string[1] & 0xff) << 48 | (uint64_t)(string[2] & 0xff) << 40 | (uint64_t)(string[3] & 0xff) << 32 | (uint64_t)(string[4] & 0xff) << 24 | (uint64_t)(string[5] & 0xff) << 16 | (uint64_t)(string[6] & 0xff) << 8 | (uint64_t)(string[7] & 0xff) << 0; #endif } void UInt16_TO_String2(uint16_t snum, char *data) { data[0] = (snum >> 8) & 0xff; data[1] = (snum >> 0) & 0xff; return; } void UInt32_TO_String4(uint32_t lnum, char *data) { data[0] = (lnum >> 24) & 0xff; data[1] = (lnum >> 16) & 0xff; data[2] = (lnum >> 8) & 0xff; data[3] = (lnum >> 0) & 0xff; return; } void UInt64_TO_String8(uint64_t ullnum, char *data) { data[0] = (ullnum >> 56) & 0xff; data[1] = (ullnum >> 48) & 0xff; data[2] = (ullnum >> 40) & 0xff; data[3] = (ullnum >> 32) & 0xff; data[4] = (ullnum >> 24) & 0xff; data[5] = (ullnum >> 16) & 0xff; data[6] = (ullnum >> 8) & 0xff; data[7] = (ullnum >> 0) & 0xff; return; } /////////////////////////////////////////////////////////////////////////////////////// // 3gp asset support (for 'loci') // /////////////////////////////////////////////////////////////////////////////////////// uint32_t float_to_16x16bit_fixed_point(double floating_val) { uint32_t fixedpoint_16bit = 0; int16_t long_integer = (int16_t)floating_val; // to get a fixed 16-bit decimal, work on the decimal part along; multiply by // (2^8 * 2) which moves the decimal over 16 bits to create our int16_t now // while the degrees can be negative (requiring a int16_6), the decimal // portion is always positive (and thus requiring a uint16_t) uint16_t long_decimal = (int16_t)((floating_val - long_integer) * (double)(65536)); fixedpoint_16bit = long_integer * 65536 + long_decimal; // same as bitshifting, less headache doing it return fixedpoint_16bit; } double fixed_point_16x16bit_to_double(uint32_t fixed_point) { double return_val = 0.0; int16_t long_integer = fixed_point / 65536; uint16_t long_decimal = fixed_point - (long_integer * 65536); return_val = long_integer + ((double)long_decimal / 65536); if (return_val < 0.0) { return_val -= 1.0; } return return_val; } uint32_t widechar_len(char *instring, uint32_t _bytes_) { uint32_t wstring_len = 0; for (uint32_t i = 0; i <= _bytes_ / 2; i++) { if (instring[0] == 0 && instring[1] == 0) { break; } else { instring += 2; wstring_len++; } } return wstring_len; } bool APar_assert(bool expression, int error_msg, const char *supplemental_info) { bool force_break = true; if (!expression) { force_break = false; switch (error_msg) { case 1: { // trying to set an iTunes-style metadata tag on an // 3GP/MobileMPEG-4 fprintf(stdout, "AP warning:\n\tSetting the %s tag is for ordinary MPEG-4 " "files.\n\tIt is not supported on 3gp/amc files.\nSkipping\n", supplemental_info); break; } case 2: { // trying to set a 3gp asset on an mpeg-4 file with the improper // brand fprintf(stdout, "AP warning:\n\tSetting the %s asset is only available on 3GPP " "files branded 3gp6 or later.\nSkipping\n", supplemental_info); break; } case 3: { // trying to set 'meta' on a file without a iso2 or mp42 // compatible brand. fprintf(stdout, "AtomicParsley warning: ID3 tags requires a v2 " "compatible file, which was not found.\nSkipping.\n"); break; } case 4: { // trying to set a 3gp album asset on an early 3gp file that only // came into being with 3gp6 fprintf(stdout, "Major brand of given file: %s\n", supplemental_info); break; } case 5: { // trying to set metadata on track 33 when there are only 3 tracks fprintf(stdout, "AP warning: skipping non-existing track number setting user " "data atom: %s.\n", supplemental_info); break; } case 6: { // trying to set id3 metadata on track 33 when there are only 3 // tracks fprintf(stdout, "AP error: skipping non-existing track number setting frame %s " "for ID32 atom.\n", supplemental_info); break; } case 7: { // trying to set id3 metadata on track 33 when there are only 3 // tracks fprintf(stdout, "AP warning: the 'meta' atom is being hangled by a %s handler.\n " " Remove the 'meta' atom and its contents and try again.\n", supplemental_info); break; } case 8: { // trying to create an ID32 atom when there is a primary item atom // present signaling referenced data (local or external) fprintf(stdout, "AP warning: unsupported external or referenced items were " "detected. Skipping this frame: %s\n", supplemental_info); break; } case 9: { // trying to eliminate an id3 frame that doesn't exist fprintf(stdout, "AP warning: id3 frame %s cannot be deleted because it does not " "exist.\n", supplemental_info); break; } case 10: { // trying to eliminate an id3 frame that doesn't exist fprintf(stdout, "AP warning: skipping setting unknown %s frame\n", supplemental_info); break; } case 11: { // insuffient memory to malloc an id3 field (probably picture or // encapuslated object) fprintf(stdout, "AP error: memory was not alloctated for frame %s. Exiting.\n", supplemental_info); break; } } } return force_break; } /* http://wwwmaths.anu.edu.au/~brent/random.html */ /* xorgens.c version 3.04, R. P. Brent, 20060628. */ /* For type definitions see xorgens.h */ typedef unsigned long xorgenUINT; unsigned long xor4096i() { /* 32-bit or 64-bit integer random number generator with period at least 2**4096-1. It is assumed that "xorgenUINT" is a 32-bit or 64-bit integer (see typedef statements in xorgens.h). xor4096i should be called exactly once with nonzero seed, and thereafter with zero seed. One random number uniformly distributed in [0..2**wlen) is returned, where wlen = 8*sizeof(xorgenUINT) = 32 or 64. R. P. Brent, 20060628. */ /* UINT64 is TRUE if 64-bit xorgenUINT, UINT32 is TRUE otherwise (assumed to be 32-bit xorgenUINT). */ #define UINT64 (sizeof(xorgenUINT) >> 3) #define UINT32 (1 - UINT64) #define wlen (64 * UINT64 + 32 * UINT32) #define r (64 * UINT64 + 128 * UINT32) #define s (53 * UINT64 + 95 * UINT32) #define a (33 * UINT64 + 17 * UINT32) #define b (26 * UINT64 + 12 * UINT32) #define c (27 * UINT64 + 13 * UINT32) #define d (29 * UINT64 + 15 * UINT32) #define ws (27 * UINT64 + 16 * UINT32) xorgenUINT seed = 0; static xorgenUINT w, weyl, zero = 0, x[r]; xorgenUINT t, v; static int i = -1; /* i < 0 indicates first call */ int k; if (i < 0) { #if defined HAVE_SRANDDEV sranddev(); #else srand((int)time(NULL)); #endif double doubleseed = ((double)rand() / ((double)(RAND_MAX) + (double)(1))); seed = (xorgenUINT)(doubleseed * rand()); } if ((i < 0) || (seed != zero)) { /* Initialisation necessary */ /* weyl = odd approximation to 2**wlen*(sqrt(5)-1)/2. */ if (UINT32) weyl = 0x61c88647; else weyl = ((((xorgenUINT)0x61c88646) << 16) << 16) + (xorgenUINT)0x80b583eb; v = (seed != zero) ? seed : ~seed; /* v must be nonzero */ for (k = wlen; k > 0; k--) { /* Avoid correlations for close seeds */ v ^= v << 10; v ^= v >> 15; /* Recurrence has period 2**wlen-1 */ v ^= v << 4; v ^= v >> 13; /* for wlen = 32 or 64 */ } for (w = v, k = 0; (xorgenUINT)k < r; k++) { /* Initialise circular array */ v ^= v << 10; v ^= v >> 15; v ^= v << 4; v ^= v >> 13; x[k] = v + (w += weyl); } for (i = r - 1, k = 4 * r; k > 0; k--) { /* Discard first 4*r results */ t = x[i = (i + 1) & (r - 1)]; t ^= t << a; t ^= t >> b; v = x[(i + (r - s)) & (r - 1)]; v ^= v << c; v ^= v >> d; x[i] = t ^ v; } } /* Apart from initialisation (above), this is the generator */ t = x[i = (i + 1) & (r - 1)]; /* Assumes that r is a power of two */ v = x[(i + (r - s)) & (r - 1)]; /* Index is (i-s) mod r */ t ^= t << a; t ^= t >> b; /* (I + L^a)(I + R^b) */ v ^= v << c; v ^= v >> d; /* (I + L^c)(I + R^d) */ x[i] = (v ^= t); /* Update circular array */ w += weyl; /* Update Weyl generator */ return (v + (w ^ (w >> ws))); /* Return combination */ #undef UINT64 #undef UINT32 #undef wlen #undef r #undef s #undef a #undef b #undef c #undef d #undef ws }