2 Copyright (c) 2004-2005, John Hurst
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
8 1. Redistributions of source code must retain the above copyright
9 notice, this list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13 3. The name of the author may not be used to endorse or promote products
14 derived from this software without specific prior written permission.
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 \brief AS-DCP library, misc classes and subroutines
32 #include <AS_DCP_system.h>
33 #include "hex_utils.h"
37 static const ui32_t s_MessageCount = 27;
38 static const char* s_ErrorMessages[] =
40 "An undefined error was detected.",
41 "An unexpected NULL pointer was given.",
42 "An unexpected empty string was given.",
43 "The given frame buffer is too small.",
44 "The object is not yet initialized.",
46 "The requested file does not exist on the system.",
47 "Insufficient privilege exists to perform the operation.",
49 "The file contains errors or is not OP-Atom/AS-DCP.",
50 "An invalid file location was requested.",
54 "Unknown raw essence file type.",
55 "Raw essence format invalid.",
56 "Object state error.",
58 "Attempt to read past end of file.",
59 "Invalid configuration option detected.",
60 "Frame number out of range.",
61 "AESEncContext required when writing to encrypted file",
62 "Plaintext offset exceeds frame buffer size",
64 "Error allocating memory",
65 "Cannot resize externally allocated memory",
66 "The check value did not decrypt correctly",
67 "HMAC authentication failure",
68 "HMAC context required",
70 "Error initializing block cipher context",
71 "Attempted to write an empty frame buffer"
75 //------------------------------------------------------------------------------------------
78 class StderrLogSink : public ASDCP::ILogSink
84 StderrLogSink() : show_info(false), show_debug(false) {}
87 void Error(const char* fmt, ...) {
90 vLogf(LOG_ERROR, fmt, &args);
94 void Warn(const char* fmt, ...) {
97 vLogf(LOG_WARN, fmt, &args);
101 void Info(const char* fmt, ...) {
104 vLogf(LOG_INFO, fmt, &args);
108 void Debug(const char* fmt, ...) {
111 vLogf(LOG_DEBUG, fmt, &args);
115 void Logf(ASDCP::ILogSink::LogType_t type, const char* fmt, ...) {
118 vLogf(type, fmt, &args);
122 void vLogf(ASDCP::ILogSink::LogType_t type, const char* fmt, va_list* list) {
123 FILE* stream = stderr;
127 case LOG_ERROR: fputs("Error: ", stream); break;
128 case LOG_WARN: fputs("Warning: ", stream); break;
130 if ( ! show_info ) return;
131 fputs("Info: ", stream);
134 if ( ! show_debug ) return;
135 fputs("Debug: ", stream);
139 vfprintf(stream, fmt, *list);
145 static ASDCP::ILogSink* s_DefaultLogSink = 0;
149 ASDCP::SetDefaultLogSink(ILogSink* Sink)
151 s_DefaultLogSink = Sink;
154 // bootleg entry for debug enthusiasts
156 set_debug_mode(bool info_mode, bool debug_mode)
158 s_StderrLogSink.show_info = info_mode;
159 s_StderrLogSink.show_debug = debug_mode;
162 // Returns the internal default sink.
164 ASDCP::DefaultLogSink()
166 if ( s_DefaultLogSink == 0 )
167 s_DefaultLogSink = &s_StderrLogSink;
169 return *s_DefaultLogSink;
176 sprintf(ver, "%lu.%lu.%lu", VERSION_MAJOR, VERSION_APIMINOR, VERSION_IMPMINOR);
181 // Returns a pointer to an English language string describing the given result code.
182 // If the result code is not a valid member of the Result_t enum, the string
183 // "**UNKNOWN**" will be returned.
185 ASDCP::GetResultString(Result_t result)
190 ui32_t idx = (- result);
192 if ( idx > s_MessageCount )
193 return "**UNKNOWN**";
195 return s_ErrorMessages[--idx];
199 // convert utf-8 hext string to bin
201 ASDCP::hex2bin(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* conv_size)
203 ASDCP_TEST_NULL(str);
204 ASDCP_TEST_NULL(buf);
205 ASDCP_TEST_NULL(conv_size);
209 if ( str[0] == 0 ) // nothing to convert
212 for ( int j = 0; str[j]; j++ )
214 if ( isxdigit(str[j]) )
218 if ( *conv_size & 0x01 ) (*conv_size)++;
221 if ( *conv_size > buf_len )// maximum possible data size
226 int phase = 0; // track high/low nybble
228 // for each character, fill in the high nybble then the low
229 for ( int i = 0; str[i]; i++ )
231 if ( ! isxdigit(str[i]) )
234 byte_t val = str[i] - ( isdigit(str[i]) ? 0x30 : ( isupper(str[i]) ? 0x37 : 0x57 ) );
238 buf[*conv_size] = val << 4;
243 buf[*conv_size] |= val;
253 // convert a memory region to a NULL-terminated hexadecimal string
256 ASDCP::bin2hex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len)
260 || ((bin_len * 2) + 1) > str_len )
265 for ( ui32_t i = 0; i < bin_len; i++ )
267 *p = (bin_buf[i] >> 4) & 0x0f;
268 *p += *p < 10 ? 0x30 : 0x61 - 10;
271 *p = bin_buf[i] & 0x0f;
272 *p += *p < 10 ? 0x30 : 0x61 - 10;
281 // spew a range of bin data as hex
283 ASDCP::hexdump(const byte_t* buf, ui32_t dump_len, FILE* stream)
291 static ui32_t row_len = 16;
292 const byte_t* p = buf;
293 const byte_t* end_p = p + dump_len;
295 for ( ui32_t line = 0; p < end_p; line++ )
297 fprintf(stream, " %06x: ", line);
301 for ( pp = p, i = 0; i < row_len && pp < end_p; i++, pp++ )
302 fprintf(stream, "%02x ", *pp);
304 while ( i++ < row_len )
307 for ( pp = p, i = 0; i < row_len && pp < end_p; i++, pp++ )
308 fputc((isprint(*pp) ? *pp : '.'), stream);
315 //------------------------------------------------------------------------------------------
317 // read a ber value from the buffer and compare with test value.
318 // Advances buffer to first character after BER value.
321 ASDCP::read_test_BER(byte_t **buf, ui64_t test_value)
326 if ( ( **buf & 0x80 ) == 0 )
330 ui8_t ber_size = ( **buf & 0x0f ) + 1;
335 for ( ui8_t i = 1; i < ber_size; i++ )
338 val |= (ui64_t)((*buf)[i]) << ( ( ( ber_size - 1 ) - i ) * 8 );
342 return ( val == test_value );
348 ASDCP::read_BER(const byte_t* buf, ui64_t* val)
352 if ( buf == 0 || val == 0 )
355 if ( ( *buf & 0x80 ) == 0 )
359 ber_size = ( *buf & 0x0f ) + 1;
364 for ( i = 1; i < ber_size; i++ )
367 *val |= (ui64_t)buf[i] << ( ( ( ber_size - 1 ) - i ) * 8 );
374 static const ui64_t ber_masks[9] =
375 { ui64_C(0xffffffffffffffff), ui64_C(0xffffffffffffff00),
376 ui64_C(0xffffffffffff0000), ui64_C(0xffffffffff000000),
377 ui64_C(0xffffffff00000000), ui64_C(0xffffff0000000000),
378 ui64_C(0xffff000000000000), ui64_C(0xff00000000000000),
385 ASDCP::write_BER(byte_t* buf, ui64_t val, ui32_t ber_len)
391 { // calculate default length
392 if ( val < 0x01000000L )
394 else if ( val < ui64_C(0x0100000000000000) )
400 { // sanity check BER length
403 DefaultLogSink().Error("BER size %lu exceeds maximum size of 9\n", ber_len);
407 if ( val & ber_masks[ber_len - 1] )
409 char intbuf[IntBufferLen];
410 DefaultLogSink().Error("BER size %lu too small for value %s\n",
411 ber_len, ui64sz(val, intbuf));
416 buf[0] = 0x80 + ( ber_len - 1 );
418 for ( ui32_t i = ber_len - 1; i > 0; i-- )
420 buf[i] = (ui8_t)(val & 0xff);
427 //------------------------------------------------------------------------------------------
429 // frame buffer base class implementation
431 ASDCP::FrameBuffer::FrameBuffer() :
432 m_Data(0), m_Capacity(0), m_OwnMem(false), m_Size(0),
433 m_FrameNumber(0), m_SourceLength(0), m_PlaintextOffset(0)
437 ASDCP::FrameBuffer::~FrameBuffer()
439 if ( m_OwnMem && m_Data != 0 )
443 // Instructs the object to use an externally allocated buffer. The external
444 // buffer will not be cleaned up by the frame buffer when it is destroyed.
445 // Call with (0,0) to revert to internally allocated buffer.
446 // Returns error if the buf_addr argument is NULL and either buf_size is
447 // non-zero or internally allocated memory is in use.
449 ASDCP::FrameBuffer::SetData(byte_t* buf_addr, ui32_t buf_size)
451 // if buf_addr is null and we have an external memory reference,
452 // drop the reference and place the object in the initialized-
453 // but-no-buffer-allocated state
456 if ( buf_size > 0 || m_OwnMem )
460 m_Capacity = m_Size = 0;
465 if ( m_OwnMem && m_Data != 0 )
469 m_Capacity = buf_size;
476 // Sets the size of the internally allocate buffer. Returns RESULT_CAPEXTMEM
477 // if the object is using an externally allocated buffer via SetData();
478 // Resets content size to zero.
480 ASDCP::FrameBuffer::Capacity(ui32_t cap_size)
482 if ( ! m_OwnMem && m_Data != 0 )
483 return RESULT_CAPEXTMEM; // cannot resize external memory
485 if ( m_Capacity < cap_size )
493 m_Data = (byte_t*)malloc(cap_size);
498 m_Capacity = cap_size;