/***************************************************************** | | AP4 - Utilities | | Copyright 2002-2008 Axiomatic Systems, LLC | | | This file is part of Bento4/AP4 (MP4 Atom Processing Library). | | Unless you have obtained Bento4 under a difference license, | this version of Bento4 is Bento4|GPL. | Bento4|GPL is free software; you can redistribute it and/or modify | it under the terms of the GNU General Public License as published by | the Free Software Foundation; either version 2, or (at your option) | any later version. | | Bento4|GPL is distributed in the hope that it will be useful, | but WITHOUT ANY WARRANTY; without even the implied warranty of | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | GNU General Public License for more details. | | You should have received a copy of the GNU General Public License | along with Bento4|GPL; see the file COPYING. If not, write to the | Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA | 02111-1307, USA. | ****************************************************************/ /*---------------------------------------------------------------------- | includes +---------------------------------------------------------------------*/ #include "Ap4Utils.h" #include "Ap4Debug.h" /*---------------------------------------------------------------------- | AP4_GlobalOptions::g_Entry +---------------------------------------------------------------------*/ AP4_List* AP4_GlobalOptions::g_Entries = NULL; /*---------------------------------------------------------------------- | AP4_GlobalOptions::GetEntry +---------------------------------------------------------------------*/ AP4_GlobalOptions::Entry* AP4_GlobalOptions::GetEntry(const char* name, bool autocreate) { if (g_Entries == NULL) { g_Entries = new AP4_List; } for (AP4_List::Item* item = g_Entries->FirstItem(); item; item = item->GetNext()) { if (item->GetData()->m_Name == name) return item->GetData(); } if (autocreate) { Entry* new_entry = new Entry(); new_entry->m_Name = name; g_Entries->Add(new_entry); return new_entry; } else { return NULL; } } /*---------------------------------------------------------------------- | AP4_GlobalOptions::SetBool +---------------------------------------------------------------------*/ void AP4_GlobalOptions::SetBool(const char* name, bool value) { Entry* entry = GetEntry(name, true); entry->m_Value = value?"true":"false"; } /*---------------------------------------------------------------------- | AP4_GlobalOptions::GetBool +---------------------------------------------------------------------*/ bool AP4_GlobalOptions::GetBool(const char* name) { Entry* entry = GetEntry(name, false); if (entry) { return entry->m_Value == "true"; } else { return false; } } /*---------------------------------------------------------------------- | AP4_GlobalOptions::SetString +---------------------------------------------------------------------*/ void AP4_GlobalOptions::SetString(const char* name, const char* value) { Entry* entry = GetEntry(name, true); entry->m_Value = value; } /*---------------------------------------------------------------------- | AP4_GlobalOptions::GetString +---------------------------------------------------------------------*/ const char* AP4_GlobalOptions::GetString(const char* name) { Entry* entry = GetEntry(name, false); if (entry) { return entry->m_Value.GetChars(); } else { return NULL; } } /*---------------------------------------------------------------------- | AP4_BytesToDoubleBE +---------------------------------------------------------------------*/ double AP4_BytesToDoubleBE(const unsigned char* bytes) { AP4_UI64 i_value = AP4_BytesToUInt64BE(bytes); void* v_value = reinterpret_cast(&i_value); double* d_value = reinterpret_cast(v_value); return *d_value; } /*---------------------------------------------------------------------- | AP4_BytesToUInt64BE +---------------------------------------------------------------------*/ AP4_UI64 AP4_BytesToUInt64BE(const unsigned char* bytes) { return ( ((AP4_UI64)bytes[0])<<56 ) | ( ((AP4_UI64)bytes[1])<<48 ) | ( ((AP4_UI64)bytes[2])<<40 ) | ( ((AP4_UI64)bytes[3])<<32 ) | ( ((AP4_UI64)bytes[4])<<24 ) | ( ((AP4_UI64)bytes[5])<<16 ) | ( ((AP4_UI64)bytes[6])<<8 ) | ( ((AP4_UI64)bytes[7]) ); } /*---------------------------------------------------------------------- | AP4_BytesFromDoubleBE +---------------------------------------------------------------------*/ void AP4_BytesFromDoubleBE(unsigned char* bytes, double value) { void* v_value = reinterpret_cast(&value); AP4_UI64* i_value = reinterpret_cast(v_value); AP4_BytesFromUInt64BE(bytes, *i_value); } /*---------------------------------------------------------------------- | AP4_BytesFromUInt64BE +---------------------------------------------------------------------*/ void AP4_BytesFromUInt64BE(unsigned char* bytes, AP4_UI64 value) { bytes[0] = (unsigned char)((value >> 56) & 0xFF); bytes[1] = (unsigned char)((value >> 48) & 0xFF); bytes[2] = (unsigned char)((value >> 40) & 0xFF); bytes[3] = (unsigned char)((value >> 32) & 0xFF); bytes[4] = (unsigned char)((value >> 24) & 0xFF); bytes[5] = (unsigned char)((value >> 16) & 0xFF); bytes[6] = (unsigned char)((value >> 8) & 0xFF); bytes[7] = (unsigned char)((value ) & 0xFF); } /*---------------------------------------------------------------------- | AP4_ByteSwap16 +---------------------------------------------------------------------*/ void AP4_ByteSwap16(unsigned char* bytes, unsigned int count) { AP4_ASSERT((count & 1) == 0); for (unsigned int i = 0; i < count / 2; i++) { unsigned char tmp = bytes[0]; bytes[0] = bytes[1]; bytes[1] = tmp; bytes += 2; } } /*---------------------------------------------------------------------- | AP4_DurationMsFromUnits +---------------------------------------------------------------------*/ AP4_UI32 AP4_DurationMsFromUnits(AP4_UI64 units, AP4_UI32 units_per_second) { if (units_per_second == 0) return 0; return (AP4_UI32)(((double)units*1000.0)/(double)units_per_second); } /*---------------------------------------------------------------------- | AP4_ConvertTime +---------------------------------------------------------------------*/ AP4_UI64 AP4_ConvertTime(AP4_UI64 time_value, AP4_UI32 from_time_scale, AP4_UI32 to_time_scale) { if (from_time_scale == 0) return 0; double ratio = (double)to_time_scale/(double)from_time_scale; return ((AP4_UI64)(0.5+(double)time_value*ratio)); } /*---------------------------------------------------------------------- | AP4_FormatFourChars +---------------------------------------------------------------------*/ void AP4_FormatFourChars(char* str, AP4_UI32 value) { str[0] = (value >> 24) & 0xFF; str[1] = (value >> 16) & 0xFF; str[2] = (value >> 8) & 0xFF; str[3] = (value ) & 0xFF; str[4] = '\0'; } /*---------------------------------------------------------------------- | AP4_FormatFourCharsPrintable +---------------------------------------------------------------------*/ void AP4_FormatFourCharsPrintable(char* str, AP4_UI32 value) { AP4_FormatFourChars(str, value); for (int i=0; i<4; i++) { if (str[i]<' ' || str[i] >= 127) { str[i] = '.'; } } } /*---------------------------------------------------------------------- | AP4_SplitArgs +---------------------------------------------------------------------*/ AP4_Result AP4_SplitArgs(char* arg, char*& arg0, char*& arg1) { arg0 = arg; char* c = arg; while (*c != 0 && *c != ':') { c++; } if (*c == ':') { *c++ = '\0'; arg1 = c; return AP4_SUCCESS; } else { return AP4_FAILURE; } } /*---------------------------------------------------------------------- | AP4_SplitArgs +---------------------------------------------------------------------*/ AP4_Result AP4_SplitArgs(char* arg, char*& arg0, char*& arg1, char*& arg2) { AP4_Result result = AP4_SplitArgs(arg, arg0, arg1); if (AP4_FAILED(result)) return result; return AP4_SplitArgs(arg1, arg1, arg2); } /*---------------------------------------------------------------------- | AP4_HexNibble +---------------------------------------------------------------------*/ unsigned char AP4_HexNibble(char c) { switch (c) { case '0': return 0; case '1': return 1; case '2': return 2; case '3': return 3; case '4': return 4; case '5': return 5; case '6': return 6; case '7': return 7; case '8': return 8; case '9': return 9; case 'a': case 'A': return 10; case 'b': case 'B': return 11; case 'c': case 'C': return 12; case 'd': case 'D': return 13; case 'e': case 'E': return 14; case 'f': case 'F': return 15; default: return 0; } } /*---------------------------------------------------------------------- | AP4_NibbleHex +---------------------------------------------------------------------*/ char AP4_NibbleHex(unsigned int nibble) { if (nibble < 10) { return (char)('0'+nibble); } else if (nibble < 16) { return (char)('A'+(nibble-10)); } else { return ' '; } } /*---------------------------------------------------------------------- | AP4_ParseHex +---------------------------------------------------------------------*/ AP4_Result AP4_ParseHex(const char* hex, unsigned char* bytes, unsigned int count) { if (AP4_StringLength(hex) < 2*count) return AP4_ERROR_INVALID_PARAMETERS; for (unsigned int i=0; i>4); *hex++ = AP4_NibbleHex(data[i]&0x0F); } return AP4_SUCCESS; } /*---------------------------------------------------------------------- | AP4_BitWriter::Write +---------------------------------------------------------------------*/ void AP4_BitWriter::Write(AP4_UI32 bits, unsigned int bit_count) { unsigned char* data = m_Data; if (m_BitCount+bit_count > m_DataSize*8) return; data += m_BitCount/8; unsigned int space = 8-(m_BitCount%8); while (bit_count) { unsigned int mask = bit_count==32 ? 0xFFFFFFFF : ((1<> (bit_count-space)); ++data; m_BitCount += space; bit_count -= space; space = 8; } } } /*---------------------------------------------------------------------- | AP4_ParseIntegerU +---------------------------------------------------------------------*/ AP4_UI32 AP4_ParseIntegerU(const char* str) { if (str == NULL) { return 0; } // parse the digits AP4_UI32 value = 0; while (char c = *str++) { if (c >= '0' && c <= '9') { value = 10*value + (c-'0'); } else { return 0; } } return value; } /*---------------------------------------------------------------------- | types and macros +---------------------------------------------------------------------*/ #define AP4_WORD_BITS 32 #define AP4_WORD_BYTES 4 #define AP4_BIT_MASK(_n) ((1<<(_n))-1) #if AP4_WORD_BITS != 32 #error unsupported word size /* 64 and other word size not yet implemented */ #endif /*---------------------------------------------------------------------- | AP4_BitReader::AP4_BitReader +---------------------------------------------------------------------*/ AP4_BitReader::AP4_BitReader(const AP4_UI08* data, unsigned int data_size) : m_Position(0), m_Cache(0), m_BitsCached(0) { // make the buffer an integral mulitple of the word size m_Buffer.SetBufferSize(AP4_WORD_BYTES*((data_size+AP4_WORD_BYTES-1)/AP4_WORD_BYTES)); m_Buffer.SetData(data, data_size); if (m_Buffer.GetDataSize() != m_Buffer.GetBufferSize()) { AP4_SetMemory(m_Buffer.UseData()+m_Buffer.GetDataSize(), 0, m_Buffer.GetBufferSize()-m_Buffer.GetDataSize()); } } /*---------------------------------------------------------------------- | AP4_BitReader::~AP4_BitReader +---------------------------------------------------------------------*/ AP4_BitReader::~AP4_BitReader() { } /*---------------------------------------------------------------------- | AP4_BitReader::Reset +---------------------------------------------------------------------*/ AP4_Result AP4_BitReader::Reset() { m_Position = 0; m_Cache = 0; m_BitsCached = 0; return AP4_SUCCESS; } /*---------------------------------------------------------------------- | AP4_BitReader::GetBitsRead +---------------------------------------------------------------------*/ unsigned int AP4_BitReader::GetBitsRead() { return 8*m_Position - m_BitsCached; } /*---------------------------------------------------------------------- | AP4_BitReader::ReadCache +---------------------------------------------------------------------*/ AP4_BitReader::BitsWord AP4_BitReader::ReadCache() const { const AP4_UI08* out_ptr = m_Buffer.GetData()+m_Position; return (((AP4_BitReader::BitsWord) out_ptr[0]) << 24) | (((AP4_BitReader::BitsWord) out_ptr[1]) << 16) | (((AP4_BitReader::BitsWord) out_ptr[2]) << 8) | (((AP4_BitReader::BitsWord) out_ptr[3]) ); } /*---------------------------------------------------------------------- | AP4_BitReader::ReadBits +---------------------------------------------------------------------*/ AP4_UI32 AP4_BitReader::ReadBits(unsigned int n) { if (n == 0) return 0; AP4_BitReader::BitsWord result; if (m_BitsCached >= n) { /* we have enough bits in the cache to satisfy the request */ m_BitsCached -= n; result = (m_Cache >> m_BitsCached) & AP4_BIT_MASK(n); } else { /* not enough bits in the cache */ AP4_BitReader::BitsWord word = ReadCache(); m_Position += AP4_WORD_BYTES; /* combine the new word and the cache, and update the state */ AP4_BitReader::BitsWord cache = m_Cache & AP4_BIT_MASK(m_BitsCached); n -= m_BitsCached; m_BitsCached = AP4_WORD_BITS - n; result = m_BitsCached ? (word >> m_BitsCached) | (cache << n) : word; m_Cache = word; } return result; } /*---------------------------------------------------------------------- | AP4_BitReader::ReadBit +---------------------------------------------------------------------*/ int AP4_BitReader::ReadBit() { AP4_BitReader::BitsWord result; if (m_BitsCached == 0) { /* the cache is empty */ /* read the next word into the cache */ m_Cache = ReadCache(); m_Position += AP4_WORD_BYTES; m_BitsCached = AP4_WORD_BITS - 1; /* return the first bit */ result = m_Cache >> (AP4_WORD_BITS - 1); } else { /* get the bit from the cache */ result = (m_Cache >> (--m_BitsCached)) & 1; } return result; } /*---------------------------------------------------------------------- | AP4_BitReader::PeekBits +---------------------------------------------------------------------*/ AP4_UI32 AP4_BitReader::PeekBits(unsigned int n) { /* we have enough bits in the cache to satisfy the request */ if (m_BitsCached >= n) { return (m_Cache >> (m_BitsCached - n)) & AP4_BIT_MASK(n); } else { /* not enough bits in the cache, read the next word */ AP4_BitReader::BitsWord word = ReadCache(); /* combine the new word and the cache, and update the state */ AP4_BitReader::BitsWord cache = m_Cache & AP4_BIT_MASK(m_BitsCached); n -= m_BitsCached; return (word >> (AP4_WORD_BITS - n)) | (cache << n); } } /*---------------------------------------------------------------------- | AP4_BitReader::PeekBit +---------------------------------------------------------------------*/ int AP4_BitReader::PeekBit() { /* the cache is empty */ if (m_BitsCached == 0) { /* read the next word into the cache */ AP4_BitReader::BitsWord cache = ReadCache(); /* return the first bit */ return cache >> (AP4_WORD_BITS - 1); } else { /* get the bit from the cache */ return (m_Cache >> (m_BitsCached-1)) & 1; } } /*---------------------------------------------------------------------- | AP4_BitReader::SkipBits +---------------------------------------------------------------------*/ void AP4_BitReader::SkipBits(unsigned int n) { if (n <= m_BitsCached) { m_BitsCached -= n; } else { n -= m_BitsCached; while (n >= AP4_WORD_BITS) { m_Position += AP4_WORD_BYTES; n -= AP4_WORD_BITS; } if (n) { m_Cache = ReadCache(); m_BitsCached = AP4_WORD_BITS-n; m_Position += AP4_WORD_BYTES; } else { m_BitsCached = 0; m_Cache = 0; } } } /*---------------------------------------------------------------------- | AP4_BitReader::SkipBit +---------------------------------------------------------------------*/ void AP4_BitReader::SkipBit() { if (m_BitsCached == 0) { m_Cache = ReadCache(); m_Position += AP4_WORD_BYTES; m_BitsCached = AP4_WORD_BITS - 1; } else { --m_BitsCached; } }