diff options
| author | jhurst <jhurst@cinecert.com> | 2005-12-20 01:55:40 +0000 |
|---|---|---|
| committer | jhurst <> | 2005-12-20 01:55:40 +0000 |
| commit | 8095eaa320551b6795d0368c0ad0c227a3167caa (patch) | |
| tree | e522d5137671fffbc8fcc084831b5d8806ef44f2 /src/AS_DCP.cpp | |
wheee!
Diffstat (limited to 'src/AS_DCP.cpp')
| -rwxr-xr-x | src/AS_DCP.cpp | 509 |
1 files changed, 509 insertions, 0 deletions
diff --git a/src/AS_DCP.cpp b/src/AS_DCP.cpp new file mode 100755 index 0000000..4b5acd6 --- /dev/null +++ b/src/AS_DCP.cpp @@ -0,0 +1,509 @@ +/* +Copyright (c) 2004-2005, John Hurst +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/*! \file AS_DCP.cpp + \version $Id$ + \brief AS-DCP library, misc classes and subroutines +*/ + +#include <AS_DCP_system.h> +#include "hex_utils.h" +#include <assert.h> + + +static const ui32_t s_MessageCount = 27; +static const char* s_ErrorMessages[] = +{ + "An undefined error was detected.", + "An unexpected NULL pointer was given.", + "An unexpected empty string was given.", + "The given frame buffer is too small.", + "The object is not yet initialized.", + + "The requested file does not exist on the system.", + "Insufficient privilege exists to perform the operation.", + "File open error.", + "The file contains errors or is not OP-Atom/AS-DCP.", + "An invalid file location was requested.", + + "File read error.", + "File write error.", + "Unknown raw essence file type.", + "Raw essence format invalid.", + "Object state error.", + + "Attempt to read past end of file.", + "Invalid configuration option detected.", + "Frame number out of range.", + "AESEncContext required when writing to encrypted file", + "Plaintext offset exceeds frame buffer size", + + "Error allocating memory", + "Cannot resize externally allocated memory", + "The check value did not decrypt correctly", + "HMAC authentication failure", + "HMAC context required", + + "Error initializing block cipher context", + "Attempted to write an empty frame buffer" +}; + + +//------------------------------------------------------------------------------------------ + +// +class StderrLogSink : public ASDCP::ILogSink +{ +public: + bool show_info; + bool show_debug; + + StderrLogSink() : show_info(false), show_debug(false) {} + ~StderrLogSink() {} + + void Error(const char* fmt, ...) { + va_list args; + va_start(args, fmt); + vLogf(LOG_ERROR, fmt, &args); + va_end(args); + } + + void Warn(const char* fmt, ...) { + va_list args; + va_start(args, fmt); + vLogf(LOG_WARN, fmt, &args); + va_end(args); + } + + void Info(const char* fmt, ...) { + va_list args; + va_start(args, fmt); + vLogf(LOG_INFO, fmt, &args); + va_end(args); + } + + void Debug(const char* fmt, ...) { + va_list args; + va_start(args, fmt); + vLogf(LOG_DEBUG, fmt, &args); + va_end(args); + } + + void Logf(ASDCP::ILogSink::LogType_t type, const char* fmt, ...) { + va_list args; + va_start(args, fmt); + vLogf(type, fmt, &args); + va_end(args); + } + + void vLogf(ASDCP::ILogSink::LogType_t type, const char* fmt, va_list* list) { + FILE* stream = stderr; + + switch ( type ) + { + case LOG_ERROR: fputs("Error: ", stream); break; + case LOG_WARN: fputs("Warning: ", stream); break; + case LOG_INFO: + if ( ! show_info ) return; + fputs("Info: ", stream); + break; + case LOG_DEBUG: + if ( ! show_debug ) return; + fputs("Debug: ", stream); + break; + } + + vfprintf(stream, fmt, *list); + } + +} s_StderrLogSink; + +// +static ASDCP::ILogSink* s_DefaultLogSink = 0; + +// +void +ASDCP::SetDefaultLogSink(ILogSink* Sink) +{ + s_DefaultLogSink = Sink; +} + +// bootleg entry for debug enthusiasts +void +set_debug_mode(bool info_mode, bool debug_mode) +{ + s_StderrLogSink.show_info = info_mode; + s_StderrLogSink.show_debug = debug_mode; +} + +// Returns the internal default sink. +ASDCP::ILogSink& +ASDCP::DefaultLogSink() +{ + if ( s_DefaultLogSink == 0 ) + s_DefaultLogSink = &s_StderrLogSink; + + return *s_DefaultLogSink; +} + +const char* +ASDCP::Version() +{ + static char ver[16]; + sprintf(ver, "%lu.%lu.%lu", VERSION_MAJOR, VERSION_APIMINOR, VERSION_IMPMINOR); + return ver; +} + + +// Returns a pointer to an English language string describing the given result code. +// If the result code is not a valid member of the Result_t enum, the string +// "**UNKNOWN**" will be returned. +const char* +ASDCP::GetResultString(Result_t result) +{ + if ( result >= 0 ) + return "No error."; + + ui32_t idx = (- result); + + if ( idx > s_MessageCount ) + return "**UNKNOWN**"; + + return s_ErrorMessages[--idx]; +} + + +// convert utf-8 hext string to bin +i32_t +ASDCP::hex2bin(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* conv_size) +{ + ASDCP_TEST_NULL(str); + ASDCP_TEST_NULL(buf); + ASDCP_TEST_NULL(conv_size); + + *conv_size = 0; + + if ( str[0] == 0 ) // nothing to convert + return 0; + + for ( int j = 0; str[j]; j++ ) + { + if ( isxdigit(str[j]) ) + (*conv_size)++; + } + + if ( *conv_size & 0x01 ) (*conv_size)++; + *conv_size /= 2; + + if ( *conv_size > buf_len )// maximum possible data size + return -1; + + *conv_size = 0; + + int phase = 0; // track high/low nybble + + // for each character, fill in the high nybble then the low + for ( int i = 0; str[i]; i++ ) + { + if ( ! isxdigit(str[i]) ) + continue; + + byte_t val = str[i] - ( isdigit(str[i]) ? 0x30 : ( isupper(str[i]) ? 0x37 : 0x57 ) ); + + if ( phase == 0 ) + { + buf[*conv_size] = val << 4; + phase++; + } + else + { + buf[*conv_size] |= val; + phase = 0; + (*conv_size)++; + } + } + + return 0; +} + + +// convert a memory region to a NULL-terminated hexadecimal string +// +const char* +ASDCP::bin2hex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len) +{ + if ( bin_buf == 0 + || str_buf == 0 + || ((bin_len * 2) + 1) > str_len ) + return 0; + + char* p = str_buf; + + for ( ui32_t i = 0; i < bin_len; i++ ) + { + *p = (bin_buf[i] >> 4) & 0x0f; + *p += *p < 10 ? 0x30 : 0x61 - 10; + p++; + + *p = bin_buf[i] & 0x0f; + *p += *p < 10 ? 0x30 : 0x61 - 10; + p++; + } + + *p = '\0'; + return str_buf; +} + + +// spew a range of bin data as hex +void +ASDCP::hexdump(const byte_t* buf, ui32_t dump_len, FILE* stream) +{ + if ( buf == 0 ) + return; + + if ( stream == 0 ) + stream = stderr; + + static ui32_t row_len = 16; + const byte_t* p = buf; + const byte_t* end_p = p + dump_len; + + for ( ui32_t line = 0; p < end_p; line++ ) + { + fprintf(stream, " %06x: ", line); + ui32_t i; + const byte_t* pp; + + for ( pp = p, i = 0; i < row_len && pp < end_p; i++, pp++ ) + fprintf(stream, "%02x ", *pp); + + while ( i++ < row_len ) + fputs(" ", stream); + + for ( pp = p, i = 0; i < row_len && pp < end_p; i++, pp++ ) + fputc((isprint(*pp) ? *pp : '.'), stream); + + fputc('\n', stream); + p += row_len; + } +} + +//------------------------------------------------------------------------------------------ + +// read a ber value from the buffer and compare with test value. +// Advances buffer to first character after BER value. +// +bool +ASDCP::read_test_BER(byte_t **buf, ui64_t test_value) +{ + if ( buf == 0 ) + return false; + + if ( ( **buf & 0x80 ) == 0 ) + return false; + + ui64_t val = 0; + ui8_t ber_size = ( **buf & 0x0f ) + 1; + + if ( ber_size > 9 ) + return false; + + for ( ui8_t i = 1; i < ber_size; i++ ) + { + if ( (*buf)[i] > 0 ) + val |= (ui64_t)((*buf)[i]) << ( ( ( ber_size - 1 ) - i ) * 8 ); + } + + *buf += ber_size; + return ( val == test_value ); +} + + +// +bool +ASDCP::read_BER(const byte_t* buf, ui64_t* val) +{ + ui8_t ber_size, i; + + if ( buf == 0 || val == 0 ) + return false; + + if ( ( *buf & 0x80 ) == 0 ) + return false; + + *val = 0; + ber_size = ( *buf & 0x0f ) + 1; + + if ( ber_size > 9 ) + return false; + + for ( i = 1; i < ber_size; i++ ) + { + if ( buf[i] > 0 ) + *val |= (ui64_t)buf[i] << ( ( ( ber_size - 1 ) - i ) * 8 ); + } + + return true; +} + + +static const ui64_t ber_masks[9] = + { ui64_C(0xffffffffffffffff), ui64_C(0xffffffffffffff00), + ui64_C(0xffffffffffff0000), ui64_C(0xffffffffff000000), + ui64_C(0xffffffff00000000), ui64_C(0xffffff0000000000), + ui64_C(0xffff000000000000), ui64_C(0xff00000000000000), + 0 + }; + + +// +bool +ASDCP::write_BER(byte_t* buf, ui64_t val, ui32_t ber_len) +{ + if ( buf == 0 ) + return false; + + if ( ber_len == 0 ) + { // calculate default length + if ( val < 0x01000000L ) + ber_len = 4; + else if ( val < ui64_C(0x0100000000000000) ) + ber_len = 8; + else + ber_len = 9; + } + else + { // sanity check BER length + if ( ber_len > 9 ) + { + DefaultLogSink().Error("BER size %lu exceeds maximum size of 9\n", ber_len); + return false; + } + + if ( val & ber_masks[ber_len - 1] ) + { + char intbuf[IntBufferLen]; + DefaultLogSink().Error("BER size %lu too small for value %s\n", + ber_len, ui64sz(val, intbuf)); + return false; + } + } + + buf[0] = 0x80 + ( ber_len - 1 ); + + for ( ui32_t i = ber_len - 1; i > 0; i-- ) + { + buf[i] = (ui8_t)(val & 0xff); + val >>= 8; + } + + return true; +} + +//------------------------------------------------------------------------------------------ +// +// frame buffer base class implementation + +ASDCP::FrameBuffer::FrameBuffer() : + m_Data(0), m_Capacity(0), m_OwnMem(false), m_Size(0), + m_FrameNumber(0), m_SourceLength(0), m_PlaintextOffset(0) +{ +} + +ASDCP::FrameBuffer::~FrameBuffer() +{ + if ( m_OwnMem && m_Data != 0 ) + free(m_Data); +} + +// Instructs the object to use an externally allocated buffer. The external +// buffer will not be cleaned up by the frame buffer when it is destroyed. +// Call with (0,0) to revert to internally allocated buffer. +// Returns error if the buf_addr argument is NULL and either buf_size is +// non-zero or internally allocated memory is in use. +ASDCP::Result_t +ASDCP::FrameBuffer::SetData(byte_t* buf_addr, ui32_t buf_size) +{ + // if buf_addr is null and we have an external memory reference, + // drop the reference and place the object in the initialized- + // but-no-buffer-allocated state + if ( buf_addr == 0 ) + { + if ( buf_size > 0 || m_OwnMem ) + return RESULT_PTR; + + m_OwnMem = false; + m_Capacity = m_Size = 0; + m_Data = 0; + return RESULT_OK; + } + + if ( m_OwnMem && m_Data != 0 ) + free(m_Data); + + m_OwnMem = false; + m_Capacity = buf_size; + m_Data = buf_addr; + m_Size = 0; + + return RESULT_OK; +} + +// Sets the size of the internally allocate buffer. Returns RESULT_CAPEXTMEM +// if the object is using an externally allocated buffer via SetData(); +// Resets content size to zero. +ASDCP::Result_t +ASDCP::FrameBuffer::Capacity(ui32_t cap_size) +{ + if ( ! m_OwnMem && m_Data != 0 ) + return RESULT_CAPEXTMEM; // cannot resize external memory + + if ( m_Capacity < cap_size ) + { + if ( m_Data != 0 ) + { + assert(m_OwnMem); + free(m_Data); + } + + m_Data = (byte_t*)malloc(cap_size); + + if ( m_Data == 0 ) + return RESULT_ALLOC; + + m_Capacity = cap_size; + m_OwnMem = true; + m_Size = 0; + } + + return RESULT_OK; +} + + +// +// end AS_DCP.cpp +// |
