diff options
| author | jhurst <jhurst@cinecert.com> | 2006-04-05 23:03:55 +0000 |
|---|---|---|
| committer | jhurst <> | 2006-04-05 23:03:55 +0000 |
| commit | bfedf725dac9d13f3a02fe69f45c302ab29d2b1e (patch) | |
| tree | 4a746f759dcb62ebeb6309373e7579d6048f4af6 /src | |
| parent | fdf31e0105bf8272a6b7fa9c4039941dff37a271 (diff) | |
ginormo merge-back with Kumu, SMPTE MIC key and MPEG parser fix
Diffstat (limited to 'src')
46 files changed, 5146 insertions, 1317 deletions
diff --git a/src/AS_DCP.cpp b/src/AS_DCP.cpp index a5187d6..12765c6 100755 --- a/src/AS_DCP.cpp +++ b/src/AS_DCP.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2004-2005, John Hurst +Copyright (c) 2004-2006, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without @@ -29,146 +29,9 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \brief AS-DCP library, misc classes and subroutines */ -#include <AS_DCP_system.h> -#include "hex_utils.h" +#include "AS_DCP_internal.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() { @@ -178,252 +41,6 @@ ASDCP::Version() } -// 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 diff --git a/src/AS_DCP.h b/src/AS_DCP.h index e65b029..f6574ac 100755 --- a/src/AS_DCP.h +++ b/src/AS_DCP.h @@ -72,9 +72,10 @@ This project depends upon the following library: */ -#ifndef _AS_DCP_H__ -#define _AS_DCP_H__ +#ifndef _AS_DCP_H_ +#define _AS_DCP_H_ +#include <KM_error.h> #include <stdio.h> #include <stdarg.h> #include <iostream> @@ -128,7 +129,6 @@ typedef unsigned int ui32_t; T(const T&); \ T& operator=(const T&) - //-------------------------------------------------------------------------------- // All library components are defined in the namespace ASDCP // @@ -142,8 +142,8 @@ namespace ASDCP { // in file format, and if no changes were made to AS_DCP.h, the new version would be // 1.0.1. If changes were also required in AS_DCP.h, the new version would be 1.1.1. const ui32_t VERSION_MAJOR = 1; - const ui32_t VERSION_APIMINOR = 0; - const ui32_t VERSION_IMPMINOR = 5; + const ui32_t VERSION_APIMINOR = 1; + const ui32_t VERSION_IMPMINOR = 7; const char* Version(); // UUIDs are passed around as strings of UUIDlen bytes @@ -153,75 +153,42 @@ namespace ASDCP { const ui32_t KeyLen = 16; //--------------------------------------------------------------------------------- - // message logging - - // Error and debug messages will be delivered to an object having this interface. - // The default implementation sends only LOG_ERROR and LOG_WARN messages to stderr. - // To receive LOG_INFO or LOG_DEBUG messages, or to send messages somewhere other - // than stderr, implement this interface and register an instance of your new class - // by calling SetDefaultLogSink(). - class ILogSink - { - public: - enum LogType_t { LOG_ERROR, LOG_WARN, LOG_INFO, LOG_DEBUG }; - - virtual ~ILogSink() {} - virtual void Error(const char*, ...) = 0; // receives error messges - virtual void Warn(const char*, ...) = 0; // receives warning messges - virtual void Info(const char*, ...) = 0; // receives info messages - virtual void Debug(const char*, ...) = 0; // receives debug messages - virtual void Logf(LogType_t, const char*, ...) = 0; // log a formatted string with positional parameters - virtual void vLogf(LogType_t, const char*, va_list*) = 0; // log a formatted string with a va_list struct - }; - - // Sets the internal default sink to the given receiver. If the given value - // is zero, sets the default sink to the internally allocated stderr sink. - void SetDefaultLogSink(ILogSink* = 0); - - // Returns the internal default sink. - ILogSink& DefaultLogSink(); - - //--------------------------------------------------------------------------------- // return values - // Each method or subroutine in this library that is not void or does not directly - // return a value will instead return a result code from this enumeration. - enum Result_t { - RESULT_FALSE = 1, // successful but negative - RESULT_OK = 0, // No errors detected - RESULT_FAIL = -1, // An undefined error was detected - RESULT_PTR = -2, // An unexpected NULL pointer was given - RESULT_NULL_STR = -3, // An unexpected empty string was given - RESULT_SMALLBUF = -4, // The given frame buffer is too small - RESULT_INIT = -5, // The object is not yet initialized - RESULT_NOT_FOUND = -6, // The requested file does not exist on the system - RESULT_NO_PERM = -7, // Insufficient privilege exists to perform the operation - RESULT_FILEOPEN = -8, // Failure opening file - RESULT_FORMAT = -9, // The file format is not proper OP-Atom/AS-DCP - RESULT_BADSEEK = -10, // An invalid file location was requested - RESULT_READFAIL = -11, // File read error - RESULT_WRITEFAIL = -12, // File write error - RESULT_RAW_ESS = -13, // Unknown raw essence file type - RESULT_RAW_FORMAT = -14, // Raw essence format invalid - RESULT_STATE = -15, // Object state error - RESULT_ENDOFFILE = -16, // Attempt to read past end of file - RESULT_CONFIG = -17, // Invalid configuration option detected - RESULT_RANGE = -18, // Frame number out of range - RESULT_CRYPT_CTX = -19, // AESEncContext required when writing to encrypted file - RESULT_LARGE_PTO = -20, // Plaintext offset exceeds frame buffer size - RESULT_ALLOC = -21, // Error allocating memory - RESULT_CAPEXTMEM = -22, // Cannot resize externally allocated memory - RESULT_CHECKFAIL = -23, // The check value did not decrypt correctly - RESULT_HMACFAIL = -24, // HMAC authentication failure - RESULT_HMAC_CTX = -25, // HMAC context required - RESULT_CRYPT_INIT = -26, // Error initializing block cipher context - RESULT_EMPTY_FB = -27, // Attempted to write an empty frame buffer - }; - - // 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* GetResultString(Result_t); + using Kumu::Result_t; + + using Kumu::RESULT_FALSE; + using Kumu::RESULT_OK; + using Kumu::RESULT_FAIL; + using Kumu::RESULT_PTR; + using Kumu::RESULT_NULL_STR; + using Kumu::RESULT_ALLOC; + using Kumu::RESULT_PARAM; + using Kumu::RESULT_SMALLBUF; + using Kumu::RESULT_INIT; + using Kumu::RESULT_NOT_FOUND; + using Kumu::RESULT_NO_PERM; + using Kumu::RESULT_FILEOPEN; + using Kumu::RESULT_BADSEEK; + using Kumu::RESULT_READFAIL; + using Kumu::RESULT_WRITEFAIL; + using Kumu::RESULT_STATE; + using Kumu::RESULT_ENDOFFILE; + using Kumu::RESULT_CONFIG; + + const Kumu::Result_t RESULT_FORMAT (-101, "The file format is not proper OP-Atom/AS-DCP."); + const Kumu::Result_t RESULT_RAW_ESS (-102, "Unknown raw essence file type."); + const Kumu::Result_t RESULT_RAW_FORMAT (-103, "Raw essence format invalid."); + const Kumu::Result_t RESULT_RANGE (-104, "Frame number out of range."); + const Kumu::Result_t RESULT_CRYPT_CTX (-105, "AESEncContext required when writing to encrypted file."); + const Kumu::Result_t RESULT_LARGE_PTO (-106, "Plaintext offset exceeds frame buffer size."); + const Kumu::Result_t RESULT_CAPEXTMEM (-107, "Cannot resize externally allocated memory."); + const Kumu::Result_t RESULT_CHECKFAIL (-108, "The check value did not decrypt correctly."); + const Kumu::Result_t RESULT_HMACFAIL (-109, "HMAC authentication failure."); + const Kumu::Result_t RESULT_HMAC_CTX (-110, "HMAC context required."); + const Kumu::Result_t RESULT_CRYPT_INIT (-111, "Error initializing block cipher context."); + const Kumu::Result_t RESULT_EMPTY_FB (-112, "Empty frame buffer."); + const Kumu::Result_t RESULT_KLV_CODING (-113, "KLV coding error."); //--------------------------------------------------------------------------------- // file identification @@ -232,7 +199,10 @@ namespace ASDCP { ESS_UNKNOWN, // the file is not a supported AS-DCP essence container ESS_MPEG2_VES, // the file contains an MPEG video elementary stream ESS_JPEG_2000, // the file contains one or more JPEG 2000 codestreams - ESS_PCM_24b_48k // the file contains one or more PCM audio pairs + ESS_PCM_24b_48k, // the file contains one or more PCM audio pairs + ESS_PCM_24b_96k, // the file contains one or more PCM audio pairs + ESS_UTF8_XML, // the file contains UTF-8 encoded XML data + ESS_PNG // the file contains a Portable Network Graphics image }; // Determine the type of essence contained in the given MXF file. RESULT_OK @@ -301,6 +271,69 @@ namespace ASDCP { inline bool empty() const { return m_p == 0; } }; + + //--------------------------------------------------------------------------------- + // WriterInfo class - encapsulates writer identification details used for + // OpenWrite() calls. Replace these values at runtime to identify your product. + // + // MXF files use SMPTE Universal Labels to identify data items. The set of Labels + // in a file is determined by the MXF Operational Pattern and any constraining + // documentation. There are currently two flavors of AS-DCP file in use: MXF Interop + // and SMPTE. The two differ only in the values of two labels: + // + // OP Atom / Interop : 06 0e 2b 34 04 01 01 01 0d 01 02 01 10 00 00 00 + // OP Atom / SMPTE : 06 0e 2b 34 04 01 01 02 0d 01 02 01 10 00 00 00 + // and + // EKLV Packet / Interop : 06 0e 2b 34 02 04 01 07 0d 01 03 01 02 7e 01 00 + // EKLV Packet / SMPTE : 06 0e 2b 34 02 04 01 01 0d 01 03 01 02 7e 01 00 + // + // asdcplib will read any (otherwise valid) file which has any combination of the + // above values. When writing files, MXF Interop labels are used by default. To + // write a file containing SMPTE labels, replace the default label set value in + // the WriterInfo before calling OpenWrite() + // + enum LabelSet_t + { + LS_MXF_UNKNOWN, + LS_MXF_INTEROP, + LS_MXF_SMPTE + }; + + // + struct WriterInfo + { + byte_t ProductUUID[UUIDlen]; + byte_t AssetUUID[UUIDlen]; + byte_t ContextID[UUIDlen]; + byte_t CryptographicKeyID[UUIDlen]; + bool EncryptedEssence; // true if essence data is (or is going to be) encrypted + bool UsesHMAC; // true if HMAC exists or is to be calculated + std::string ProductVersion; + std::string CompanyName; + std::string ProductName; + LabelSet_t LabelSetType; + + WriterInfo() : EncryptedEssence(false), UsesHMAC(false), LabelSetType(LS_MXF_INTEROP) + { + static byte_t default_ProductUUID_Data[UUIDlen] = { + 0x43, 0x05, 0x9a, 0x1d, 0x04, 0x32, 0x41, 0x01, + 0xb8, 0x3f, 0x73, 0x68, 0x15, 0xac, 0xf3, 0x1d }; + + memcpy(ProductUUID, default_ProductUUID_Data, UUIDlen); + memset(AssetUUID, 0, UUIDlen); + memset(ContextID, 0, UUIDlen); + memset(CryptographicKeyID, 0, UUIDlen); + + ProductVersion = "Unreleased "; + ProductVersion += Version(); + CompanyName = "DCI"; + ProductName = "asdcplib"; + } + }; + + // Print WriterInfo to stream, stderr by default. + void WriterInfoDump(const WriterInfo&, FILE* = 0); + //--------------------------------------------------------------------------------- // cryptographic support @@ -376,7 +409,7 @@ namespace ASDCP { // Initializes HMAC context. The key argument must point to a binary // key that is CBC_KEY_SIZE bytes in length. Returns error if the key // argument is NULL. - Result_t InitKey(const byte_t* key); + Result_t InitKey(const byte_t* key, LabelSet_t = LS_MXF_INTEROP); // Reset internal state, allows repeated cycles of Update -> Finalize void Reset(); @@ -400,68 +433,6 @@ namespace ASDCP { }; //--------------------------------------------------------------------------------- - // WriterInfo class - encapsulates writer identification details used for - // OpenWrite() calls. Replace these values at runtime to identify your product. - // - // MXF files use SMPTE Universal Labels to identify data items. The set of Labels - // in a file is determined by the MXF Operational Pattern and any constraining - // documentation. There are currently two flavors of AS-DCP file in use: MXF Interop - // and SMPTE. The two differ only in the values of two labels: - // - // OP Atom / Interop : 06 0e 2b 34 04 01 01 01 0d 01 02 01 10 00 00 00 - // OP Atom / SMPTE : 06 0e 2b 34 04 01 01 02 0d 01 02 01 10 00 00 00 - // and - // EKLV Packet / Interop : 06 0e 2b 34 02 04 01 07 0d 01 03 01 02 7e 01 00 - // EKLV Packet / SMPTE : 06 0e 2b 34 02 04 01 01 0d 01 03 01 02 7e 01 00 - // - // asdcplib will read any (otherwise valid) file which has any combination of the - // above values. When writing files, MXF Interop labels are used by default. To - // write a file containing SMPTE labels, replace the default label set value in - // the WriterInfo before calling OpenWrite() - // - enum LabelSet_t - { - LS_MXF_UNKNOWN, - LS_MXF_INTEROP, - LS_MXF_SMPTE - }; - - // - struct WriterInfo - { - byte_t ProductUUID[UUIDlen]; - byte_t AssetUUID[UUIDlen]; - byte_t ContextID[UUIDlen]; - byte_t CryptographicKeyID[UUIDlen]; - bool EncryptedEssence; // true if essence data is (or is going to be) encrypted - bool UsesHMAC; // true if HMAC exists or is to be calculated - std::string ProductVersion; - std::string CompanyName; - std::string ProductName; - LabelSet_t LabelSetType; - - WriterInfo() : EncryptedEssence(false), UsesHMAC(false), LabelSetType(LS_MXF_INTEROP) - { - static byte_t default_ProductUUID_Data[UUIDlen] = { - 0x43, 0x05, 0x9a, 0x1d, 0x04, 0x32, 0x41, 0x01, - 0xb8, 0x3f, 0x73, 0x68, 0x15, 0xac, 0xf3, 0x1d }; - - memcpy(ProductUUID, default_ProductUUID_Data, UUIDlen); - memset(AssetUUID, 0, UUIDlen); - memset(ContextID, 0, UUIDlen); - memset(CryptographicKeyID, 0, UUIDlen); - - ProductVersion = "Unreleased "; - ProductVersion += Version(); - CompanyName = "DCI"; - ProductName = "asdcplib"; - } - }; - - // Print WriterInfo to stream, stderr by default. - void WriterInfoDump(const WriterInfo&, FILE* = 0); - - //--------------------------------------------------------------------------------- // frame buffer base class // // The supported essence types are stored using per-frame KLV packetization. The @@ -1103,7 +1074,7 @@ namespace ASDCP { } // namespace ASDCP -#endif // _AS_DCP_H__ +#endif // _AS_DCP_H_ // // end AS_DCP.h diff --git a/src/AS_DCP_AES.cpp b/src/AS_DCP_AES.cpp index e21dba1..fc10425 100755 --- a/src/AS_DCP_AES.cpp +++ b/src/AS_DCP_AES.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2004, John Hurst +Copyright (c) 2004-2006, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without @@ -32,6 +32,8 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <assert.h> #include <AS_DCP.h> +#include <KM_log.h> +using Kumu::DefaultLogSink; using namespace ASDCP; const int KEY_SIZE_BITS = 128; @@ -39,6 +41,7 @@ const int KEY_SIZE_BITS = 128; #include <openssl/aes.h> #include <openssl/sha.h> +#include <openssl/bn.h> #include <openssl/err.h> void @@ -255,9 +258,76 @@ public: h__HMACContext() : m_Final(false) {} ~h__HMACContext() {} - // + // SMPTE 429.6 MIC key generation void SetKey(const byte_t* key) { + // FIPS 186-2 Sec. 3.1 as modified by Change 1, section entitled "General Purpose Random Number Generation" + // + + static byte_t t[SHA_DIGEST_LENGTH] = { + 0x67, 0x45, 0x23, 0x01, 0xef, 0xcd, 0xab, 0x89, + 0x98, 0xba, 0xdc, 0xfe, 0x10, 0x32, 0x54, 0x76, + 0xc3, 0xd2, 0xe1, 0xf0 + }; + + byte_t sha_buf0[SHA_DIGEST_LENGTH]; + byte_t sha_buf1[SHA_DIGEST_LENGTH]; + SHA_CTX SHA; + BN_CTX* ctx1 = BN_CTX_new(); // used by BN_* functions + assert(ctx1); + + // create the 2^160 constant + BIGNUM c_2powb, c_2, c_160; + BN_init(&c_2powb); BN_init(&c_2); BN_init(&c_160); + BN_set_word(&c_2, 2); + BN_set_word(&c_160, 160); + BN_exp(&c_2powb, &c_2, &c_160, ctx1); + + // ROUND 1 + // step a -- SMPTE 429.6 sets XSEED = 0, so no need to do anything for this step + // step b -- (key mod 2^160) is moot because the input value is only 128 bits in length + + // step c -- x = G(t,xkey) + SHA1_Init(&SHA); + SHA1_Update(&SHA, t, SHA_DIGEST_LENGTH); + SHA1_Update(&SHA, key, KeyLen); + SHA1_Final(sha_buf0, &SHA); + + // step d ... + BIGNUM xkey1, xkey2, x0; + BN_init(&xkey1); BN_init(&xkey2); BN_init(&x0); + + BN_bin2bn(key, KeyLen, &xkey1); + BN_bin2bn(sha_buf0, SHA_DIGEST_LENGTH, &x0); + BN_add_word(&xkey1, 1); // xkey += 1 + BN_add(&xkey2, &xkey1, &x0); // xkey += x + BN_mod(&xkey1, &xkey2, &c_2powb, ctx1); // xkey = xkey mod (2^160) + + // ROUND 2 + // step a -- SMPTE 429.6 sets XSEED = 0, so no need to do anything for this step + // step b -- (key mod 2^160) is moot because xkey1 is the result of the same operation + + byte_t bin_buf[SHA_DIGEST_LENGTH+1]; // we need xkey1 in bin form for use by SHA1_Update + ui32_t bin_buf_len = BN_num_bytes(&xkey1); + assert(bin_buf_len < SHA_DIGEST_LENGTH+1); + BN_bn2bin(&xkey1, bin_buf); + + // step c -- x = G(t,xkey) + SHA1_Init(&SHA); + SHA1_Update(&SHA, t, SHA_DIGEST_LENGTH); + SHA1_Update(&SHA, bin_buf, bin_buf_len); + SHA1_Final(sha_buf1, &SHA); + + assert(memcmp(sha_buf1, sha_buf0, SHA_DIGEST_LENGTH) != 0); // are x0 and x1 different? + + BN_CTX_free(ctx1); + memcpy(m_key, sha_buf1, KeyLen); + Reset(); + } + + // MXF Interop MIC key generation + void SetInteropKey(const byte_t* key) + { static byte_t key_nonce[KeyLen] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }; byte_t sha_buf[SHA_DIGEST_LENGTH]; @@ -334,12 +404,21 @@ HMACContext::~HMACContext() // Result_t -HMACContext::InitKey(const byte_t* key) +HMACContext::InitKey(const byte_t* key, LabelSet_t SetType) { ASDCP_TEST_NULL(key); m_Context = new h__HMACContext; - m_Context->SetKey(key); + + switch ( SetType ) + { + case LS_MXF_INTEROP: m_Context->SetInteropKey(key); break; + case LS_MXF_SMPTE: m_Context->SetKey(key); break; + default: + m_Context = 0; + return RESULT_INIT; + } + return RESULT_OK; } diff --git a/src/AS_DCP_JP2K.cpp b/src/AS_DCP_JP2K.cpp index f08203a..02d1d91 100755 --- a/src/AS_DCP_JP2K.cpp +++ b/src/AS_DCP_JP2K.cpp @@ -92,15 +92,13 @@ ASDCP::JP2K::PictureDescriptorDump(const PictureDescriptor& PDesc, FILE* stream) if ( PDesc.CodingStyleLength ) fprintf(stream, "Default Coding (%lu): %s\n", PDesc.CodingStyleLength, - bin2hex(PDesc.CodingStyle, PDesc.CodingStyleLength, - tmp_buf, tmp_buf_len) + Kumu::bin2hex(PDesc.CodingStyle, PDesc.CodingStyleLength, tmp_buf, tmp_buf_len) ); if ( PDesc.QuantDefaultLength ) fprintf(stream, "Quantization Default (%lu): %s\n", PDesc.QuantDefaultLength, - bin2hex(PDesc.QuantDefault, PDesc.QuantDefaultLength, - tmp_buf, tmp_buf_len) + Kumu::bin2hex(PDesc.QuantDefault, PDesc.QuantDefaultLength, tmp_buf, tmp_buf_len) ); } @@ -152,7 +150,7 @@ ASDCP::JP2K::MXFReader::h__Reader::MD_to_JP2K_PDesc(JP2K::PictureDescriptor& PDe PDesc.Csize = m_EssenceSubDescriptor->Csize; // PictureComponentSizing - ui32_t tmp_size = m_EssenceSubDescriptor->PictureComponentSizing.Size(); + ui32_t tmp_size = m_EssenceSubDescriptor->PictureComponentSizing.Length(); if ( tmp_size == 17 ) // ( 2 * sizeof(ui32_t) ) + 3 components * 3 byte each memcpy(&PDesc.ImageComponents, m_EssenceSubDescriptor->PictureComponentSizing.RoData() + 8, tmp_size - 8); @@ -161,11 +159,11 @@ ASDCP::JP2K::MXFReader::h__Reader::MD_to_JP2K_PDesc(JP2K::PictureDescriptor& PDe DefaultLogSink().Error("Unexpected PictureComponentSizing size: %lu, should be 17\n", tmp_size); // CodingStyleDefault - if ( ( PDesc.CodingStyleLength = m_EssenceSubDescriptor->CodingStyleDefault.Size() ) != 0 ) + if ( ( PDesc.CodingStyleLength = m_EssenceSubDescriptor->CodingStyleDefault.Length() ) != 0 ) memcpy(PDesc.CodingStyle, m_EssenceSubDescriptor->CodingStyleDefault.RoData(), PDesc.CodingStyleLength); // QuantizationDefault - if ( ( PDesc.QuantDefaultLength = m_EssenceSubDescriptor->QuantizationDefault.Size() ) != 0 ) + if ( ( PDesc.QuantDefaultLength = m_EssenceSubDescriptor->QuantizationDefault.Length() ) != 0 ) memcpy(PDesc.QuantDefault, m_EssenceSubDescriptor->QuantizationDefault.RoData(), PDesc.QuantDefaultLength); } @@ -226,7 +224,7 @@ ASDCP::JP2K::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const fputc('\n', stream); if ( dump_len > 0 ) - hexdump(m_Data, dump_len, stream); + Kumu::hexdump(m_Data, dump_len, stream); } @@ -368,18 +366,18 @@ ASDCP::JP2K::MXFWriter::h__Writer::JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDe const ui32_t tmp_buffer_len = 64; byte_t tmp_buffer[tmp_buffer_len]; - *(ui32_t*)tmp_buffer = ASDCP_i32_BE(3L); // three components - *(ui32_t*)(tmp_buffer+4) = ASDCP_i32_BE(3L); + *(ui32_t*)tmp_buffer = KM_i32_BE(3L); // three components + *(ui32_t*)(tmp_buffer+4) = KM_i32_BE(3L); memcpy(tmp_buffer + 8, &PDesc.ImageComponents, sizeof(ASDCP::JP2K::ImageComponent) * 3L); memcpy(m_EssenceSubDescriptor->PictureComponentSizing.Data(), tmp_buffer, 17); - m_EssenceSubDescriptor->PictureComponentSizing.Size(17); + m_EssenceSubDescriptor->PictureComponentSizing.Length(17); memcpy(m_EssenceSubDescriptor->CodingStyleDefault.Data(), PDesc.CodingStyle, PDesc.CodingStyleLength); - m_EssenceSubDescriptor->CodingStyleDefault.Size(PDesc.CodingStyleLength); + m_EssenceSubDescriptor->CodingStyleDefault.Length(PDesc.CodingStyleLength); memcpy(m_EssenceSubDescriptor->QuantizationDefault.Data(), PDesc.QuantDefault, PDesc.QuantDefaultLength); - m_EssenceSubDescriptor->QuantizationDefault.Size(PDesc.QuantDefaultLength); + m_EssenceSubDescriptor->QuantizationDefault.Length(PDesc.QuantDefaultLength); return RESULT_OK; } diff --git a/src/AS_DCP_MPEG2.cpp b/src/AS_DCP_MPEG2.cpp index e265848..83f7bbe 100755 --- a/src/AS_DCP_MPEG2.cpp +++ b/src/AS_DCP_MPEG2.cpp @@ -273,7 +273,7 @@ ASDCP::MPEG2::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const fputc('\n', stream); if ( dump_len > 0 ) - hexdump(m_Data, dump_len, stream); + Kumu::hexdump(m_Data, dump_len, stream); } diff --git a/src/AS_DCP_MXF.cpp b/src/AS_DCP_MXF.cpp index 92f76bb..1c8b6e9 100755 --- a/src/AS_DCP_MXF.cpp +++ b/src/AS_DCP_MXF.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2004-2005, John Hurst +Copyright (c) 2004-2006, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without @@ -29,9 +29,8 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \brief AS-DCP library, misc classes and subroutines */ +#include <KM_fileio.h> #include "AS_DCP_internal.h" -#include "FileIO.h" -#include "DirScanner.h" #include "JP2K.h" #include "Wav.h" @@ -49,7 +48,7 @@ ASDCP::WriterInfoDump(const WriterInfo& Info, FILE* stream) char str_buf[40]; - fprintf(stream," ProductUUID: %s\n", bin2hex(Info.ProductUUID, 16, str_buf, 40)); + fprintf(stream," ProductUUID: %s\n", UUID(Info.ProductUUID).EncodeHex(str_buf, 40)); fprintf(stream,"\ ProductVersion: %s\n\ CompanyName: %s\n\ @@ -64,11 +63,11 @@ ASDCP::WriterInfoDump(const WriterInfo& Info, FILE* stream) if ( Info.EncryptedEssence ) { fprintf(stream, " HMAC: %s\n", ( Info.UsesHMAC ? "Yes" : "No")); - fprintf(stream, " ContextID: %s\n", bin2hex(Info.ContextID, 16, str_buf, 40)); - fprintf(stream, "CryptographicKeyID: %s\n", bin2hex(Info.CryptographicKeyID, 16, str_buf, 40)); + fprintf(stream, " ContextID: %s\n", UUID(Info.ContextID).EncodeHex(str_buf, 40)); + fprintf(stream, "CryptographicKeyID: %s\n", UUID(Info.CryptographicKeyID).EncodeHex(str_buf, 40)); } - fprintf(stream," AssetUUID: %s\n", bin2hex(Info.AssetUUID, 16, str_buf, 40)); + fprintf(stream," AssetUUID: %s\n", UUID(Info.AssetUUID).EncodeHex(str_buf, 40)); fprintf(stream," Label Set Type: %s\n", ( Info.LabelSetType == LS_MXF_SMPTE ? "SMPTE" : ( Info.LabelSetType == LS_MXF_INTEROP ? "MXF Interop" : "Unknown" ) )); @@ -86,13 +85,13 @@ ASDCP::MD_to_WriterInfo(Identification* InfoObj, WriterInfo& Info) Info.CompanyName = "Unknown Company"; memset(Info.ProductUUID, 0, UUIDlen); - InfoObj->ProductName.ToString(tmp_str); + InfoObj->ProductName.EncodeString(tmp_str, IdentBufferLen); if ( *tmp_str ) Info.ProductName = tmp_str; - InfoObj->VersionString.ToString(tmp_str); + InfoObj->VersionString.EncodeString(tmp_str, IdentBufferLen); if ( *tmp_str ) Info.ProductVersion = tmp_str; - InfoObj->CompanyName.ToString(tmp_str); + InfoObj->CompanyName.EncodeString(tmp_str, IdentBufferLen); if ( *tmp_str ) Info.CompanyName = tmp_str; memcpy(Info.ProductUUID, InfoObj->ProductUID.Value(), UUIDlen); @@ -135,7 +134,7 @@ ASDCP::Result_t ASDCP::EssenceType(const char* filename, EssenceType_t& type) { ASDCP_TEST_NULL_STR(filename); - FileReader Reader; + Kumu::FileReader Reader; OPAtomHeader TestHeader; Result_t result = Reader.OpenRead(filename); @@ -163,7 +162,6 @@ ASDCP::EssenceType(const char* filename, EssenceType_t& type) return result; } - // ASDCP::Result_t ASDCP::RawEssenceType(const char* filename, EssenceType_t& type) @@ -171,11 +169,11 @@ ASDCP::RawEssenceType(const char* filename, EssenceType_t& type) ASDCP_TEST_NULL_STR(filename); type = ESS_UNKNOWN; ASDCP::FrameBuffer FB; - FileReader Reader; + Kumu::FileReader Reader; ui32_t read_count; Result_t result = FB.Capacity(Wav::MaxWavHeader); // using Wav max because everything else is much smaller - if ( ASDCP::PathIsFile(filename) ) + if ( Kumu::PathIsFile(filename) ) { result = Reader.OpenRead(filename); @@ -202,10 +200,10 @@ ASDCP::RawEssenceType(const char* filename, EssenceType_t& type) type = ESS_PCM_24b_48k; } } - else if ( ASDCP::PathIsDirectory(filename) ) + else if ( Kumu::PathIsDirectory(filename) ) { - char next_file[ASDCP_MAX_PATH]; - DirScanner Scanner; + char next_file[Kumu::MaxFilePath]; + Kumu::DirScanner Scanner; Result_t result = Scanner.Open(filename); if ( ASDCP_SUCCESS(result) ) @@ -397,7 +395,7 @@ ASDCP::IntegrityPack::CalcValues(const ASDCP::FrameBuffer& FB, byte_t* AssetID, p += MXF_BER_LENGTH; // sequence number - i2p<ui64_t>(ASDCP_i64_BE(sequence), p); + Kumu::i2p<ui64_t>(KM_i64_BE(sequence), p); p += sizeof(ui64_t); // HMAC length @@ -429,7 +427,7 @@ ASDCP::IntegrityPack::TestValues(const ASDCP::FrameBuffer& FB, byte_t* AssetID, byte_t* p = (byte_t*)FB.RoData() + ( FB.Size() - klv_intpack_size ); // test the AssetID length - if ( ! read_test_BER(&p, UUIDlen) ) + if ( ! Kumu::read_test_BER(&p, UUIDlen) ) return RESULT_HMACFAIL; // test the AssetID @@ -441,10 +439,10 @@ ASDCP::IntegrityPack::TestValues(const ASDCP::FrameBuffer& FB, byte_t* AssetID, p += UUIDlen; // test the sequence length - if ( ! read_test_BER(&p, sizeof(ui64_t)) ) + if ( ! Kumu::read_test_BER(&p, sizeof(ui64_t)) ) return RESULT_HMACFAIL; - ui32_t test_sequence = (ui32_t)ASDCP_i64_BE(cp2i<ui64_t>(p)); + ui32_t test_sequence = (ui32_t)KM_i64_BE(Kumu::cp2i<ui64_t>(p)); // test the sequence value if ( test_sequence != sequence ) @@ -456,7 +454,7 @@ ASDCP::IntegrityPack::TestValues(const ASDCP::FrameBuffer& FB, byte_t* AssetID, p += sizeof(ui64_t); // test the HMAC length - if ( ! read_test_BER(&p, HMAC_SIZE) ) + if ( ! Kumu::read_test_BER(&p, HMAC_SIZE) ) return RESULT_HMACFAIL; // test the HMAC diff --git a/src/AS_DCP_PCM.cpp b/src/AS_DCP_PCM.cpp index 8036745..a4f9b5f 100755 --- a/src/AS_DCP_PCM.cpp +++ b/src/AS_DCP_PCM.cpp @@ -219,7 +219,7 @@ ASDCP::PCM::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const m_FrameNumber, m_Size); if ( dump_len ) - hexdump(m_Data, dump_len, stream); + Kumu::hexdump(m_Data, dump_len, stream); } //------------------------------------------------------------------------------------------ diff --git a/src/AS_DCP_internal.h b/src/AS_DCP_internal.h index 173540d..4a00ba0 100755 --- a/src/AS_DCP_internal.h +++ b/src/AS_DCP_internal.h @@ -29,14 +29,16 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \brief AS-DCP library, non-public common elements */ -#ifndef _AS_DCP_INTERNAL_H__ -#define _AS_DCP_INTERNAL_H__ +#ifndef _AS_DCP_INTERNAL_H_ +#define _AS_DCP_INTERNAL_H_ -#include "AS_DCP_system.h" +#include <KM_platform.h> +#include <KM_util.h> +#include <KM_log.h> #include "Metadata.h" -#include "hex_utils.h" -using namespace std; +using Kumu::DefaultLogSink; +// using namespace std; using namespace ASDCP; using namespace ASDCP::MXF; @@ -45,7 +47,6 @@ using namespace ASDCP::MXF; namespace ASDCP { // constant values used to calculate KLV and EKLV packet sizes - static const ui32_t klv_cryptinfo_size = MXF_BER_LENGTH + UUIDlen /* ContextID */ @@ -95,7 +96,7 @@ namespace ASDCP ASDCP_NO_COPY_CONSTRUCT(h__Reader); public: - FileReader m_File; + Kumu::FileReader m_File; OPAtomHeader m_HeaderPart; Partition m_BodyPart; OPAtomIndexFooter m_FooterPart; @@ -157,7 +158,7 @@ namespace ASDCP ASDCP_NO_COPY_CONSTRUCT(h__Writer); public: - FileWriter m_File; + Kumu::FileWriter m_File; ui32_t m_HeaderSize; OPAtomHeader m_HeaderPart; Partition m_BodyPart; @@ -220,7 +221,7 @@ namespace ASDCP } // namespace ASDCP -#endif // _AS_DCP_INTERNAL_H__ +#endif // _AS_DCP_INTERNAL_H_ // diff --git a/src/Dict.cpp b/src/Dict.cpp index fa51fbd..e2aadcb 100755 --- a/src/Dict.cpp +++ b/src/Dict.cpp @@ -30,12 +30,12 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "Mutex.h" +#include "KM_mutex.h" #include "KLV.h" #include "MDD.cpp" #include <map> -static ASDCP::Mutex s_Lock; +static Kumu::Mutex s_Lock; static bool s_md_init = false; static std::map<ASDCP::UL, ui32_t> s_md_lookup; @@ -56,7 +56,8 @@ ASDCP::Dict::FindUL(const byte_t* ul_buf) { if ( ! s_md_init ) { - AutoMutex AL(s_Lock); + Kumu::AutoMutex AL(s_Lock); + if ( ! s_md_init ) { for ( ui32_t x = 0; x < s_MDD_Table_size; x++ ) diff --git a/src/Index.cpp b/src/Index.cpp index 0f243f8..a7bedb1 100755 --- a/src/Index.cpp +++ b/src/Index.cpp @@ -60,22 +60,6 @@ ASDCP::MXF::IndexTableSegment::InitFromTLVSet(TLVReader& TLVSet) if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi8(OBJ_READ_ARGS(IndexTableSegmentBase, PosTableCount)); if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(IndexTableSegment, DeltaEntryArray)); if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(IndexTableSegment, IndexEntryArray)); - -#if 0 - if ( ASDCP_SUCCESS(result) ) - { - Batch<IndexEntry>::iterator i; - ui32_t offset = 0; - for ( i = IndexEntryArray.begin(); i != IndexEntryArray.end(); i++ ) - { - if ( (*i).Flags == 0x40 ) - offset = 0; - - (*i).KeyFrameOffset = offset++; - } - } -#endif - return result; } @@ -123,7 +107,7 @@ ASDCP::MXF::IndexTableSegment::Dump(FILE* stream) stream = stderr; InterchangeObject::Dump(stream); - fprintf(stream, " IndexEditRate = %s\n", IndexEditRate.ToString(identbuf)); + fprintf(stream, " IndexEditRate = %s\n", IndexEditRate.EncodeString(identbuf, IdentBufferLen)); fprintf(stream, " IndexStartPosition = %s\n", i64sz(IndexStartPosition, identbuf)); fprintf(stream, " IndexDuration = %s\n", i64sz(IndexDuration, identbuf)); fprintf(stream, " EditUnitByteCount = %lu\n", EditUnitByteCount); @@ -150,30 +134,30 @@ ASDCP::MXF::IndexTableSegment::Dump(FILE* stream) // const char* -ASDCP::MXF::IndexTableSegment::DeltaEntry::ToString(char* str_buf) const +ASDCP::MXF::IndexTableSegment::DeltaEntry::EncodeString(char* str_buf, ui32_t buf_len) const { - snprintf(str_buf, IdentBufferLen, "%3i %-3hu %-3lu", PosTableIndex, Slice, ElementData); + snprintf(str_buf, buf_len, "%3i %-3hu %-3lu", PosTableIndex, Slice, ElementData); return str_buf; } // -ASDCP::Result_t -ASDCP::MXF::IndexTableSegment::DeltaEntry::Unarchive(ASDCP::MemIOReader& Reader) +bool +ASDCP::MXF::IndexTableSegment::DeltaEntry::Unarchive(Kumu::MemIOReader* Reader) { - Result_t result = Reader.ReadUi8((ui8_t*)&PosTableIndex); - if ( ASDCP_SUCCESS(result) ) result = Reader.ReadUi8(&Slice); - if ( ASDCP_SUCCESS(result) ) result = Reader.ReadUi32BE(&ElementData); - return result; + if ( ! Reader->ReadUi8((ui8_t*)&PosTableIndex) ) return false; + if ( ! Reader->ReadUi8(&Slice) ) return false; + if ( ! Reader->ReadUi32BE(&ElementData) ) return false; + return true; } // -ASDCP::Result_t -ASDCP::MXF::IndexTableSegment::DeltaEntry::Archive(ASDCP::MemIOWriter& Writer) const +bool +ASDCP::MXF::IndexTableSegment::DeltaEntry::Archive(Kumu::MemIOWriter* Writer) const { - Result_t result = Writer.WriteUi8((ui8_t)PosTableIndex); - if ( ASDCP_SUCCESS(result) ) result = Writer.WriteUi8(Slice); - if ( ASDCP_SUCCESS(result) ) result = Writer.WriteUi32BE(ElementData); - return result; + if ( ! Writer->WriteUi8((ui8_t)PosTableIndex) ) return false; + if ( ! Writer->WriteUi8(Slice) ) return false; + if ( ! Writer->WriteUi32BE(ElementData) ) return false; + return true; } //------------------------------------------------------------------------------------------ @@ -193,7 +177,7 @@ ASDCP::MXF::IndexTableSegment::DeltaEntry::Archive(ASDCP::MemIOWriter& Writer) c // const char* -ASDCP::MXF::IndexTableSegment::IndexEntry::ToString(char* str_buf) const +ASDCP::MXF::IndexTableSegment::IndexEntry::EncodeString(char* str_buf, ui32_t buf_len) const { char intbuf[IntBufferLen]; char txt_flags[6]; @@ -205,33 +189,33 @@ ASDCP::MXF::IndexTableSegment::IndexEntry::ToString(char* str_buf) const txt_flags[4] = ( (Flags & 0x0f) == 3 ) ? 'B' : ( (Flags & 0x0f) == 2 ) ? 'P' : 'I'; txt_flags[5] = 0; - snprintf(str_buf, IdentBufferLen, "%3i %-3hu %s %s", - TemporalOffset, KeyFrameOffset, txt_flags, - i64sz(StreamOffset, intbuf)); + snprintf(str_buf, buf_len, "%3i %-3hu %s %s", + TemporalOffset, KeyFrameOffset, txt_flags, + i64sz(StreamOffset, intbuf)); return str_buf; } // -ASDCP::Result_t -ASDCP::MXF::IndexTableSegment::IndexEntry::Unarchive(ASDCP::MemIOReader& Reader) +bool +ASDCP::MXF::IndexTableSegment::IndexEntry::Unarchive(Kumu::MemIOReader* Reader) { - Result_t result = Reader.ReadUi8((ui8_t*)&TemporalOffset); - if ( ASDCP_SUCCESS(result) ) result = Reader.ReadUi8((ui8_t*)&KeyFrameOffset); - if ( ASDCP_SUCCESS(result) ) result = Reader.ReadUi8(&Flags); - if ( ASDCP_SUCCESS(result) ) result = Reader.ReadUi64BE(&StreamOffset); - return result; + if ( ! Reader->ReadUi8((ui8_t*)&TemporalOffset) ) return false; + if ( ! Reader->ReadUi8((ui8_t*)&KeyFrameOffset) ) return false; + if ( ! Reader->ReadUi8(&Flags) ) return false; + if ( ! Reader->ReadUi64BE(&StreamOffset) ) return false; + return true; } // -ASDCP::Result_t -ASDCP::MXF::IndexTableSegment::IndexEntry::Archive(ASDCP::MemIOWriter& Writer) const +bool +ASDCP::MXF::IndexTableSegment::IndexEntry::Archive(Kumu::MemIOWriter* Writer) const { - Result_t result = Writer.WriteUi8((ui8_t)TemporalOffset); - if ( ASDCP_SUCCESS(result) ) result = Writer.WriteUi8((ui8_t)KeyFrameOffset); - if ( ASDCP_SUCCESS(result) ) result = Writer.WriteUi8(Flags); - if ( ASDCP_SUCCESS(result) ) result = Writer.WriteUi64BE(StreamOffset); - return result; + if ( ! Writer->WriteUi8((ui8_t)TemporalOffset) ) return false; + if ( ! Writer->WriteUi8((ui8_t)KeyFrameOffset) ) return false; + if ( ! Writer->WriteUi8(Flags) ) return false; + if ( ! Writer->WriteUi64BE(StreamOffset) ) return false; + return true; } diff --git a/src/JP2K.cpp b/src/JP2K.cpp index 20ec891..ee979ba 100755 --- a/src/JP2K.cpp +++ b/src/JP2K.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2005, John Hurst +Copyright (c) 2005-2006, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without @@ -33,7 +33,8 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include <JP2K.h> -#include <hex_utils.h> +#include <KM_log.h> +using Kumu::DefaultLogSink; // when indexed with the second byte of a marker code, this table will procuce one of @@ -161,7 +162,7 @@ ASDCP::JP2K::Accessor::COM::Dump(FILE* stream) } else { - hexdump(CommentData(), CommentSize(), stream); + Kumu::hexdump(CommentData(), CommentSize(), stream); } } @@ -218,5 +219,5 @@ ASDCP::JP2K::GetMarkerString(Marker_t m) } // -// end +// end JP2K.cpp // @@ -36,8 +36,9 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define _JP2K_H_ // AS_DCP.h is included only for it's base type definitions. -#include <AS_DCP_system.h> -#include <hex_utils.h> +#include <KM_platform.h> +#include <KM_util.h> +#include <AS_DCP.h> #include <assert.h> namespace ASDCP @@ -76,7 +77,7 @@ namespace JP2K // class Marker { - ASDCP_NO_COPY_CONSTRUCT(Marker); + KM_NO_COPY_CONSTRUCT(Marker); public: Marker_t m_Type; @@ -100,7 +101,7 @@ namespace JP2K class SIZ { const byte_t* m_MarkerData; - ASDCP_NO_COPY_CONSTRUCT(SIZ); + KM_NO_COPY_CONSTRUCT(SIZ); SIZ(); public: @@ -112,16 +113,16 @@ namespace JP2K ~SIZ() {} - inline ui16_t Rsize() { return ASDCP_i16_BE(*(ui16_t*)m_MarkerData); } - inline ui32_t Xsize() { return ASDCP_i32_BE(*(ui32_t*)(m_MarkerData + 2)); } - inline ui32_t Ysize() { return ASDCP_i32_BE(*(ui32_t*)(m_MarkerData + 6)); } - inline ui32_t XOsize() { return ASDCP_i32_BE(*(ui32_t*)(m_MarkerData + 10)); } - inline ui32_t YOsize() { return ASDCP_i32_BE(*(ui32_t*)(m_MarkerData + 14)); } - inline ui32_t XTsize() { return ASDCP_i32_BE(*(ui32_t*)(m_MarkerData + 18)); } - inline ui32_t YTsize() { return ASDCP_i32_BE(*(ui32_t*)(m_MarkerData + 22)); } - inline ui32_t XTOsize() { return ASDCP_i32_BE(*(ui32_t*)(m_MarkerData + 26)); } - inline ui32_t YTOsize() { return ASDCP_i32_BE(*(ui32_t*)(m_MarkerData + 30)); } - inline ui16_t Csize() { return ASDCP_i16_BE(*(ui16_t*)(m_MarkerData + 34)); } + inline ui16_t Rsize() { return KM_i16_BE(*(ui16_t*)m_MarkerData); } + inline ui32_t Xsize() { return KM_i32_BE(*(ui32_t*)(m_MarkerData + 2)); } + inline ui32_t Ysize() { return KM_i32_BE(*(ui32_t*)(m_MarkerData + 6)); } + inline ui32_t XOsize() { return KM_i32_BE(*(ui32_t*)(m_MarkerData + 10)); } + inline ui32_t YOsize() { return KM_i32_BE(*(ui32_t*)(m_MarkerData + 14)); } + inline ui32_t XTsize() { return KM_i32_BE(*(ui32_t*)(m_MarkerData + 18)); } + inline ui32_t YTsize() { return KM_i32_BE(*(ui32_t*)(m_MarkerData + 22)); } + inline ui32_t XTOsize() { return KM_i32_BE(*(ui32_t*)(m_MarkerData + 26)); } + inline ui32_t YTOsize() { return KM_i32_BE(*(ui32_t*)(m_MarkerData + 30)); } + inline ui16_t Csize() { return KM_i16_BE(*(ui16_t*)(m_MarkerData + 34)); } void ReadComponent(ui32_t index, ImageComponent& IC); void Dump(FILE* stream = 0); }; @@ -133,7 +134,7 @@ namespace JP2K const byte_t* m_MarkerData; ui32_t m_DataSize; - ASDCP_NO_COPY_CONSTRUCT(COM); + KM_NO_COPY_CONSTRUCT(COM); COM(); public: diff --git a/src/JP2K_Codestream_Parser.cpp b/src/JP2K_Codestream_Parser.cpp index 216827b..700233f 100755 --- a/src/JP2K_Codestream_Parser.cpp +++ b/src/JP2K_Codestream_Parser.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2004, John Hurst +Copyright (c) 2004-2006, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without @@ -29,10 +29,12 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \brief AS-DCP library, JPEG 2000 codestream essence reader implementation */ +#include <KM_fileio.h> #include <AS_DCP.h> -#include <FileIO.h> #include <JP2K.h> #include <assert.h> +#include <KM_log.h> +using Kumu::DefaultLogSink; //------------------------------------------------------------------------------------------ @@ -42,7 +44,7 @@ class ASDCP::JP2K::CodestreamParser::h__CodestreamParser public: PictureDescriptor m_PDesc; - FileReader m_File; + Kumu::FileReader m_File; h__CodestreamParser() { @@ -61,7 +63,7 @@ public: if ( ASDCP_SUCCESS(result) ) { - fsize_t file_size = m_File.Size(); + Kumu::fsize_t file_size = m_File.Size(); if ( FB.Capacity() < file_size ) { diff --git a/src/JP2K_Sequence_Parser.cpp b/src/JP2K_Sequence_Parser.cpp index 8d1b63c..cd93583 100755 --- a/src/JP2K_Sequence_Parser.cpp +++ b/src/JP2K_Sequence_Parser.cpp @@ -30,8 +30,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include <AS_DCP.h> -#include <FileIO.h> -#include <DirScanner.h> +#include <KM_fileio.h> #include <list> #include <string> #include <algorithm> @@ -54,8 +53,8 @@ public: // Result_t InitFromDirectory(const char* path) { - char next_file[ASDCP_MAX_PATH]; - DirScanner Scanner; + char next_file[Kumu::MaxFilePath]; + Kumu::DirScanner Scanner; Result_t result = Scanner.Open(path); @@ -139,7 +138,7 @@ ASDCP::JP2K::SequenceParser::h__SequenceParser::OpenRead(const char* filename) CodestreamParser Parser; FrameBuffer TmpBuffer; - fsize_t file_size = FileSize((*m_CurrentFile).c_str()); + Kumu::fsize_t file_size = Kumu::FileSize((*m_CurrentFile).c_str()); if ( file_size == 0 ) result = RESULT_NOT_FOUND; diff --git a/src/KLV.cpp b/src/KLV.cpp index 63c1e54..f4a1580 100755 --- a/src/KLV.cpp +++ b/src/KLV.cpp @@ -30,7 +30,8 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "KLV.h" -#include <hex_utils.h> +#include <KM_log.h> +using Kumu::DefaultLogSink; // This is how much we read when we're reading from a file and we don't know @@ -69,7 +70,7 @@ ASDCP::KLVPacket::InitFromBuffer(const byte_t* buf, ui32_t buf_len) return RESULT_FAIL; } - ui32_t ber_len = BER_length(buf + SMPTE_UL_LENGTH); + ui32_t ber_len = Kumu::BER_length(buf + SMPTE_UL_LENGTH); if ( ber_len > ( buf_len - SMPTE_UL_LENGTH ) ) { @@ -79,16 +80,16 @@ ASDCP::KLVPacket::InitFromBuffer(const byte_t* buf, ui32_t buf_len) if ( ber_len == 0 ) { - ASDCP::DefaultLogSink().Error("KLV format error, zero BER length not allowed\n"); + DefaultLogSink().Error("KLV format error, zero BER length not allowed\n"); return RESULT_FAIL; } ui64_t tmp_size; - if ( ! read_BER(buf + SMPTE_UL_LENGTH, &tmp_size) ) + if ( ! Kumu::read_BER(buf + SMPTE_UL_LENGTH, &tmp_size) ) return RESULT_FAIL; m_ValueLength = tmp_size; - m_KLLength = SMPTE_UL_LENGTH + BER_length(buf + SMPTE_UL_LENGTH); + m_KLLength = SMPTE_UL_LENGTH + Kumu::BER_length(buf + SMPTE_UL_LENGTH); m_KeyStart = buf; m_ValueStart = buf + m_KLLength; return RESULT_OK; @@ -116,7 +117,7 @@ ASDCP::KLVPacket::WriteKLToBuffer(ASDCP::FrameBuffer& Buffer, const byte_t* labe memcpy(Buffer.Data() + Buffer.Size(), label, SMPTE_UL_LENGTH); - if ( ! write_BER(Buffer.Data() + Buffer.Size() + SMPTE_UL_LENGTH, length, MXF_BER_LENGTH) ) + if ( ! Kumu::write_BER(Buffer.Data() + Buffer.Size() + SMPTE_UL_LENGTH, length, MXF_BER_LENGTH) ) return RESULT_FAIL; Buffer.Size(Buffer.Size() + kl_length); @@ -141,7 +142,7 @@ ASDCP::KLVPacket::Dump(FILE* stream, bool show_hex) fprintf(stream, "\b len: %7lu (%s)\n", m_ValueLength, (Entry ? Entry->name : "Unknown")); if ( show_hex && m_ValueLength < 1000 ) - hexdump(m_ValueStart, ASDCP::xmin(m_ValueLength, (ui32_t)64), stream); + Kumu::hexdump(m_ValueStart, Kumu::xmin(m_ValueLength, (ui32_t)64), stream); } else { @@ -151,7 +152,7 @@ ASDCP::KLVPacket::Dump(FILE* stream, bool show_hex) // ASDCP::Result_t -ASDCP::KLVFilePacket::InitFromFile(const FileReader& Reader, const byte_t* label) +ASDCP::KLVFilePacket::InitFromFile(const Kumu::FileReader& Reader, const byte_t* label) { Result_t result = KLVFilePacket::InitFromFile(Reader); @@ -164,7 +165,7 @@ ASDCP::KLVFilePacket::InitFromFile(const FileReader& Reader, const byte_t* label // TODO: refactor to use InitFromBuffer ASDCP::Result_t -ASDCP::KLVFilePacket::InitFromFile(const FileReader& Reader) +ASDCP::KLVFilePacket::InitFromFile(const Kumu::FileReader& Reader) { ui32_t read_count; byte_t tmp_data[tmp_read_size]; @@ -191,7 +192,7 @@ ASDCP::KLVFilePacket::InitFromFile(const FileReader& Reader) return RESULT_FAIL; } - if ( ! read_BER(tmp_data + SMPTE_UL_LENGTH, &tmp_size) ) + if ( ! Kumu::read_BER(tmp_data + SMPTE_UL_LENGTH, &tmp_size) ) { DefaultLogSink().Error("BER Length decoding error\n"); return RESULT_FAIL; @@ -199,14 +200,13 @@ ASDCP::KLVFilePacket::InitFromFile(const FileReader& Reader) if ( tmp_size > MAX_KLV_PACKET_LENGTH ) { - char intbuf[IntBufferLen]; - DefaultLogSink().Error("Packet length %s exceeds internal limit\n", - ui64sz(tmp_size, intbuf)); + Kumu::ui64Printer tmp_size_str(tmp_size); + DefaultLogSink().Error("Packet length %s exceeds internal limit\n", tmp_size_str.c_str()); return RESULT_FAIL; } ui32_t remainder = 0; - ui32_t ber_len = BER_length(tmp_data + SMPTE_UL_LENGTH); + ui32_t ber_len = Kumu::BER_length(tmp_data + SMPTE_UL_LENGTH); m_KLLength = SMPTE_UL_LENGTH + ber_len; m_ValueLength = tmp_size; ui32_t packet_length = m_ValueLength + m_KLLength; @@ -229,7 +229,7 @@ ASDCP::KLVFilePacket::InitFromFile(const FileReader& Reader) if ( (remainder = read_count - packet_length) != 0 ) { DefaultLogSink().Warn("Repositioning pointer for short packet\n"); - ASDCP::fpos_t pos = Reader.Tell(); + Kumu::fpos_t pos = Reader.Tell(); assert(pos > remainder); result = Reader.Seek(pos - remainder); } @@ -264,12 +264,12 @@ ASDCP::KLVFilePacket::InitFromFile(const FileReader& Reader) // ASDCP::Result_t -ASDCP::KLVFilePacket::WriteKLToFile(FileWriter& Writer, const byte_t* label, ui32_t length) +ASDCP::KLVFilePacket::WriteKLToFile(Kumu::FileWriter& Writer, const byte_t* label, ui32_t length) { byte_t buffer[kl_length]; memcpy(buffer, label, SMPTE_UL_LENGTH); - if ( ! write_BER(buffer+SMPTE_UL_LENGTH, length, MXF_BER_LENGTH) ) + if ( ! Kumu::write_BER(buffer+SMPTE_UL_LENGTH, length, MXF_BER_LENGTH) ) return RESULT_FAIL; ui32_t write_count; @@ -32,8 +32,9 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef _KLV_H_ #define _KLV_H_ -#include "FileIO.h" -#include "MemIO.h" +#include <KM_fileio.h> +#include <KM_memio.h> +#include "AS_DCP.h" #include "MDD.h" @@ -48,6 +49,30 @@ namespace ASDCP const ui32_t IdentBufferLen = 128; +const ui32_t IntBufferLen = 64; + +inline const char* i64sz(i64_t i, char* buf) +{ + assert(buf); +#ifdef WIN32 + snprintf(buf, IntBufferLen, "%I64d", i); +#else + snprintf(buf, IntBufferLen, "%lld", i); +#endif + return buf; +} + +inline const char* ui64sz(ui64_t i, char* buf) +{ + assert(buf); +#ifdef WIN32 + snprintf(buf, IntBufferLen, "%I64u", i); +#else + snprintf(buf, IntBufferLen, "%llu", i); +#endif + return buf; +} + struct TagValue { byte_t a; @@ -66,21 +91,47 @@ namespace ASDCP } }; - // - class IArchive + using Kumu::UUID; + + // Universal Label + class UL : public Kumu::Identifier<SMPTE_UL_LENGTH> { public: - virtual ~IArchive() {} - virtual Result_t Unarchive(ASDCP::MemIOReader& Reader) = 0; - virtual bool HasValue() const = 0; - virtual Result_t Archive(ASDCP::MemIOWriter& Writer) const = 0; + UL() {} + UL(const byte_t* rhs) { + assert(rhs); + Set(rhs); + } + + UL(const UL& rhs) { + Set(rhs.m_Value); + } + + virtual ~UL() {} + + bool operator==(const UL& rhs) const { + return ( memcmp(m_Value, rhs.m_Value, SMPTE_UL_LENGTH) == 0 ) ? true : false; + } + + const char* EncodeString(char* str_buf, ui32_t buf_len) const; + }; + + // UMID + class UMID : public Kumu::Identifier<SMPTE_UMID_LENGTH> + { + public: + UMID() {} + UMID(const UMID &rhs) { + Set(rhs.m_Value); + }; + virtual ~UMID() {} + + void MakeUMID(int Type); + void MakeUMID(int Type, const UUID& ID); + const char* EncodeString(char* str_buf, ui32_t buf_len) const; }; -} // namespace ASDCP -#include "Identifier.h" -namespace ASDCP -{ // struct MDDEntry { @@ -164,9 +215,9 @@ namespace ASDCP KLVFilePacket() {} virtual ~KLVFilePacket() {} - virtual Result_t InitFromFile(const FileReader&); - virtual Result_t InitFromFile(const FileReader&, const byte_t* label); - virtual Result_t WriteKLToFile(FileWriter& Writer, const byte_t* label, ui32_t length); + virtual Result_t InitFromFile(const Kumu::FileReader&); + virtual Result_t InitFromFile(const Kumu::FileReader&, const byte_t* label); + virtual Result_t WriteKLToFile(Kumu::FileWriter& Writer, const byte_t* label, ui32_t length); }; } // namespace ASDCP diff --git a/src/KM_error.h b/src/KM_error.h new file mode 100755 index 0000000..612a92c --- /dev/null +++ b/src/KM_error.h @@ -0,0 +1,117 @@ +/* +Copyright (c) 2004-2006, 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 KM_error.h + \version $Id$ + \brief error reporting support + */ + + + +#ifndef _KM_ERROR_H_ +#define _KM_ERROR_H_ + +namespace Kumu +{ + // Result code container. Both a signed integer and a text string are stored in the object. + // When defining your own codes your choice of integer values is mostly unconstrained, but pay + // attention to the numbering in the other libraries that use Kumu. Values between -99 and 99 + // are reserved for Kumu. + + class Result_t + { + long value; + const char* label; + Result_t(); + + public: + Result_t(long v, const char* l) : value(v), label(l) {} + inline bool operator==(const Result_t& rhs) const { return value == rhs.value; } + inline bool operator!=(const Result_t& rhs) const { return value != rhs.value; } + inline bool Success() { return ( value >= 0 ); } + inline bool Failure() { return ( value < 0 ); } + + inline long Value() { return value; } + inline operator long() const { return value; } + + inline const char* Label() { return label; } + inline operator const char*() const { return label; } + }; + + const Result_t RESULT_FALSE ( 1, "Successful but not true."); + const Result_t RESULT_OK ( 0, "Success."); + const Result_t RESULT_FAIL (-1, "An undefined error was detected."); + const Result_t RESULT_PTR (-2, "An unexpected NULL pointer was given."); + const Result_t RESULT_NULL_STR (-3, "An unexpected empty string was given."); + const Result_t RESULT_ALLOC (-4, "Error allocating memory."); + const Result_t RESULT_PARAM (-5, "Invalid parameter."); + const Result_t RESULT_NOTIMPL (-6, "Unimplemented Feature."); + const Result_t RESULT_SMALLBUF (-7, "The given buffer is too small."); + const Result_t RESULT_INIT (-8, "The object is not yet initialized."); + const Result_t RESULT_NOT_FOUND (-9, "The requested file does not exist on the system."); + const Result_t RESULT_NO_PERM (-10, "Insufficient privilege exists to perform the operation."); + const Result_t RESULT_STATE (-11, "Object state error."); + const Result_t RESULT_CONFIG (-12, "Invalid configuration option detected."); + const Result_t RESULT_FILEOPEN (-13, "File open failure."); + const Result_t RESULT_BADSEEK (-14, "An invalid file location was requested."); + const Result_t RESULT_READFAIL (-15, "File read error."); + const Result_t RESULT_WRITEFAIL (-16, "File write error."); + const Result_t RESULT_ENDOFFILE (-17, "Attempt to read past end of file."); + const Result_t RESULT_FILEEXISTS (-18, "Filename already exists."); + const Result_t RESULT_NOTAFILE (-19, "Filename not found."); +} // namespace Kumu + +//-------------------------------------------------------------------------------- +// convenience macros + +// Convenience macros for managing return values in predicates +# define KM_SUCCESS(v) (((v) < 0) ? 0 : 1) +# define KM_FAILURE(v) (((v) < 0) ? 1 : 0) + + +// Returns RESULT_PTR if the given argument is NULL. +// See Result_t above for an explanation of RESULT_* symbols. +# define KM_TEST_NULL(p) \ + if ( (p) == 0 ) { \ + return Kumu::RESULT_PTR; \ + } + +// Returns RESULT_PTR if the given argument is NULL. See Result_t +// in WaimeaCore for an explanation of RESULT_* symbols. It then assumes +// that the argument is a pointer to a string and returns +// RESULT_NULL_STR if the first character is '\0'. +// +# define KM_TEST_NULL_STR(p) \ + KM_TEST_NULL(p); \ + if ( (p)[0] == '\0' ) { \ + return Kumu::RESULT_NULL_STR; \ + } + +#endif // _KM_ERROR_H_ + +// +// end KM_error.h +// diff --git a/src/KM_fileio.cpp b/src/KM_fileio.cpp new file mode 100644 index 0000000..1ed32fb --- /dev/null +++ b/src/KM_fileio.cpp @@ -0,0 +1,801 @@ +/* +Copyright (c) 2004-2006, 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 KM_fileio.cpp + \version $Id$ + \brief portable file i/o + */ + +#include <KM_fileio.h> +#include <KM_log.h> +#include <fcntl.h> +#include <assert.h> + +using namespace Kumu; + +#ifdef KM_WIN32 +typedef struct _stati64 fstat_t; + +// AFAIK, there is no iovec equivalent in the win32 API +struct iovec { + char* iov_base; // stupid iovec uses char* + int iov_len; +}; +#else +#include <sys/uio.h> +typedef struct stat fstat_t; +#endif + +// +static Kumu::Result_t +do_stat(const char* path, fstat_t* stat_info) +{ + KM_TEST_NULL_STR(path); + KM_TEST_NULL(stat_info); + + Kumu::Result_t result = Kumu::RESULT_OK; + +#ifdef KM_WIN32 + UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX); + + if ( _stati64(path, stat_info) == (__int64)-1 ) + result = Kumu::RESULT_FILEOPEN; + + ::SetErrorMode( prev ); +#else + if ( stat(path, stat_info) == -1L ) + result = Kumu::RESULT_FILEOPEN; + + if ( stat_info->st_mode & (S_IFREG|S_IFLNK|S_IFDIR) == 0 ) + result = Kumu::RESULT_FILEOPEN; +#endif + + return result; +} + +#ifndef KM_WIN32 + +// +static Kumu::Result_t +do_fstat(HANDLE handle, fstat_t* stat_info) +{ + KM_TEST_NULL(stat_info); + + Kumu::Result_t result = Kumu::RESULT_OK; + + if ( fstat(handle, stat_info) == -1L ) + result = Kumu::RESULT_FILEOPEN; + + if ( stat_info->st_mode & (S_IFREG|S_IFLNK|S_IFDIR) == 0 ) + result = Kumu::RESULT_FILEOPEN; + + return result; +} + +#endif + + +// +bool +Kumu::PathIsFile(const char* pathname) +{ + assert(pathname); + fstat_t info; + + if ( KM_SUCCESS(do_stat(pathname, &info)) ) + { + if ( info.st_mode & S_IFREG ) + return true; + } + + return false; +} + + +// +bool +Kumu::PathIsDirectory(const char* pathname) +{ + assert(pathname); + fstat_t info; + + if ( KM_SUCCESS(do_stat(pathname, &info)) ) + { + if ( info.st_mode & S_IFDIR ) + return true; + } + + return false; +} + + +// +Kumu::fsize_t +Kumu::FileSize(const char* pathname) +{ + assert(pathname); + fstat_t info; + + if ( KM_SUCCESS(do_stat(pathname, &info)) ) + { + if ( info.st_mode & S_IFREG ) + return(info.st_size); + } + + return 0; +} + +//------------------------------------------------------------------------------------------ +// portable aspects of the file classes + +const int IOVecMaxEntries = 32; // we never use more that 3, but that number seems somehow small... + +// +class Kumu::FileWriter::h__iovec +{ +public: + int m_Count; + struct iovec m_iovec[IOVecMaxEntries]; + h__iovec() : m_Count(0) {} +}; + + + +// +Kumu::fsize_t +Kumu::FileReader::Size() const +{ +#ifdef KM_WIN32 + return FileSize(m_Filename.c_str()); +#else + fstat_t info; + + if ( KM_SUCCESS(do_fstat(m_Handle, &info)) ) + { + if ( info.st_mode & S_IFREG ) + return(info.st_size); + } +#endif + + return 0; +} + +// these are declared here instead of in the header file +// because we have a mem_ptr that is managing a hidden class +Kumu::FileWriter::FileWriter() {} +Kumu::FileWriter::~FileWriter() {} + +// +Kumu::Result_t +Kumu::FileWriter::Writev(const byte_t* buf, ui32_t buf_len) +{ + assert( ! m_IOVec.empty() ); + register h__iovec* iov = m_IOVec; + KM_TEST_NULL(buf); + + if ( iov->m_Count >= IOVecMaxEntries ) + { + DefaultLogSink().Error("The iovec is full! Only %lu entries allowed before a flush.\n", + IOVecMaxEntries); + return RESULT_FAIL; + } + + iov->m_iovec[iov->m_Count].iov_base = (char*)buf; // stupid iovec uses char* + iov->m_iovec[iov->m_Count].iov_len = buf_len; + iov->m_Count++; + + return RESULT_OK; +} + + +#ifdef KM_WIN32 +//------------------------------------------------------------------------------------------ +// + +Kumu::Result_t +Kumu::FileReader::OpenRead(const char* filename) const +{ + KM_TEST_NULL_STR(filename); + const_cast<FileReader*>(this)->m_Filename = filename; + + // suppress popup window on error + UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX); + + const_cast<FileReader*>(this)->m_Handle = ::CreateFile(filename, + (GENERIC_READ), // open for reading + FILE_SHARE_READ, // share for reading + NULL, // no security + OPEN_EXISTING, // read + FILE_ATTRIBUTE_NORMAL, // normal file + NULL // no template file + ); + + ::SetErrorMode(prev); + + return ( m_Handle == INVALID_HANDLE_VALUE ) ? + Kumu::RESULT_FILEOPEN : Kumu::RESULT_OK; +} + +// +Kumu::Result_t +Kumu::FileReader::Close() const +{ + if ( m_Handle == INVALID_HANDLE_VALUE ) + return Kumu::RESULT_FILEOPEN; + + // suppress popup window on error + UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX); + BOOL result = ::CloseHandle(m_Handle); + ::SetErrorMode(prev); + const_cast<FileReader*>(this)->m_Handle = INVALID_HANDLE_VALUE; + + return ( result == 0 ) ? Kumu::RESULT_FAIL : Kumu::RESULT_OK; +} + +// +Kumu::Result_t +Kumu::FileReader::Seek(Kumu::fpos_t position, SeekPos_t whence) const +{ + if ( m_Handle == INVALID_HANDLE_VALUE ) + return Kumu::RESULT_STATE; + + LARGE_INTEGER in; + UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX); + in.QuadPart = position; + in.LowPart = ::SetFilePointer(m_Handle, in.LowPart, &in.HighPart, whence); + HRESULT LastError = GetLastError(); + ::SetErrorMode(prev); + + if ( (LastError != NO_ERROR + && (in.LowPart == INVALID_SET_FILE_POINTER + || in.LowPart == ERROR_NEGATIVE_SEEK )) ) + return Kumu::RESULT_READFAIL; + + return Kumu::RESULT_OK; +} + +// +Kumu::Result_t +Kumu::FileReader::Tell(Kumu::fpos_t* pos) const +{ + KM_TEST_NULL(pos); + + if ( m_Handle == (HANDLE)-1L ) + return Kumu::RESULT_FILEOPEN; + + LARGE_INTEGER in; + UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX); + in.QuadPart = (__int64)0; + in.LowPart = ::SetFilePointer(m_Handle, in.LowPart, &in.HighPart, FILE_CURRENT); + HRESULT LastError = GetLastError(); + ::SetErrorMode(prev); + + if ( (LastError != NO_ERROR + && (in.LowPart == INVALID_SET_FILE_POINTER + || in.LowPart == ERROR_NEGATIVE_SEEK )) ) + return Kumu::RESULT_READFAIL; + + *pos = (Kumu::fpos_t)in.QuadPart; + return Kumu::RESULT_OK; +} + +// +Kumu::Result_t +Kumu::FileReader::Read(byte_t* buf, ui32_t buf_len, ui32_t* read_count) const +{ + KM_TEST_NULL(buf); + Result_t result = Kumu::RESULT_OK; + DWORD tmp_count; + ui32_t tmp_int; + + if ( read_count == 0 ) + read_count = &tmp_int; + + *read_count = 0; + + if ( m_Handle == INVALID_HANDLE_VALUE ) + return Kumu::RESULT_FILEOPEN; + + UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX); + if ( ::ReadFile(m_Handle, buf, buf_len, &tmp_count, NULL) == 0 ) + result = Kumu::RESULT_READFAIL; + + ::SetErrorMode(prev); + + if ( tmp_count == 0 ) /* EOF */ + result = Kumu::RESULT_ENDOFFILE; + + if ( KM_SUCCESS(result) ) + *read_count = tmp_count; + + return result; +} + + + +//------------------------------------------------------------------------------------------ +// + +// +Kumu::Result_t +Kumu::FileWriter::OpenWrite(const char* filename) +{ + KM_TEST_NULL_STR(filename); + m_Filename = filename; + + // suppress popup window on error + UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX); + + m_Handle = ::CreateFile(filename, + (GENERIC_WRITE|GENERIC_READ), // open for reading + FILE_SHARE_READ, // share for reading + NULL, // no security + CREATE_ALWAYS, // overwrite (beware!) + FILE_ATTRIBUTE_NORMAL, // normal file + NULL // no template file + ); + + ::SetErrorMode(prev); + + if ( m_Handle == INVALID_HANDLE_VALUE ) + return Kumu::RESULT_FILEOPEN; + + m_IOVec = new h__iovec; + return Kumu::RESULT_OK; +} + +// +Kumu::Result_t +Kumu::FileWriter::Writev(ui32_t* bytes_written) +{ + assert( ! m_IOVec.empty() ); + register h__iovec* iov = m_IOVec; + ui32_t tmp_int; + + if ( bytes_written == 0 ) + bytes_written = &tmp_int; + + if ( m_Handle == INVALID_HANDLE_VALUE ) + return Kumu::RESULT_STATE; + + *bytes_written = 0; + UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX); + Result_t result = Kumu::RESULT_OK; + + // AFAIK, there is no writev() equivalent in the win32 API + for ( register int i = 0; i < iov->m_Count; i++ ) + { + ui32_t tmp_count = 0; + BOOL wr_result = ::WriteFile(m_Handle, + iov->m_iovec[i].iov_base, + iov->m_iovec[i].iov_len, + (DWORD*)&tmp_count, + NULL); + + if ( wr_result == 0 ) + { + result = Kumu::RESULT_WRITEFAIL; + break; + } + + assert(iov->m_iovec[i].iov_len == tmp_count); + *bytes_written += tmp_count; + } + + ::SetErrorMode(prev); + iov->m_Count = 0; // error nor not, all is lost + + return result; +} + +// +Kumu::Result_t +Kumu::FileWriter::Write(const byte_t* buf, ui32_t buf_len, ui32_t* bytes_written) +{ + KM_TEST_NULL(buf); + ui32_t tmp_int; + + if ( bytes_written == 0 ) + bytes_written = &tmp_int; + + if ( m_Handle == INVALID_HANDLE_VALUE ) + return Kumu::RESULT_STATE; + + // suppress popup window on error + UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX); + BOOL result = ::WriteFile(m_Handle, buf, buf_len, (DWORD*)bytes_written, NULL); + ::SetErrorMode(prev); + + return ( result == 0 ) ? Kumu::RESULT_WRITEFAIL : Kumu::RESULT_OK; +} + +#else // KM_WIN32 +//------------------------------------------------------------------------------------------ +// POSIX + +// +Kumu::Result_t +Kumu::FileReader::OpenRead(const char* filename) const +{ + KM_TEST_NULL_STR(filename); + const_cast<FileReader*>(this)->m_Filename = filename; + const_cast<FileReader*>(this)->m_Handle = open(filename, O_RDONLY, 0); + return ( m_Handle == -1L ) ? RESULT_FILEOPEN : RESULT_OK; +} + +// +Kumu::Result_t +Kumu::FileReader::Close() const +{ + if ( m_Handle == -1L ) + return RESULT_FILEOPEN; + + close(m_Handle); + const_cast<FileReader*>(this)->m_Handle = -1L; + return RESULT_OK; +} + +// +Kumu::Result_t +Kumu::FileReader::Seek(Kumu::fpos_t position, SeekPos_t whence) const +{ + if ( m_Handle == -1L ) + return RESULT_FILEOPEN; + + if ( lseek(m_Handle, position, whence) == -1L ) + return RESULT_BADSEEK; + + return RESULT_OK; +} + +// +Kumu::Result_t +Kumu::FileReader::Tell(Kumu::fpos_t* pos) const +{ + KM_TEST_NULL(pos); + + if ( m_Handle == -1L ) + return RESULT_FILEOPEN; + + Kumu::fpos_t tmp_pos; + + if ( (tmp_pos = lseek(m_Handle, 0, SEEK_CUR)) == -1 ) + return RESULT_READFAIL; + + *pos = tmp_pos; + return RESULT_OK; +} + +// +Kumu::Result_t +Kumu::FileReader::Read(byte_t* buf, ui32_t buf_len, ui32_t* read_count) const +{ + KM_TEST_NULL(buf); + i32_t tmp_count = 0; + ui32_t tmp_int = 0; + + if ( read_count == 0 ) + read_count = &tmp_int; + + *read_count = 0; + + if ( m_Handle == -1L ) + return RESULT_FILEOPEN; + + if ( (tmp_count = read(m_Handle, buf, buf_len)) == -1L ) + return RESULT_READFAIL; + + *read_count = tmp_count; + return (tmp_count == 0 ? RESULT_ENDOFFILE : RESULT_OK); +} + + +//------------------------------------------------------------------------------------------ +// + +// +Kumu::Result_t +Kumu::FileWriter::OpenWrite(const char* filename) +{ + KM_TEST_NULL_STR(filename); + m_Filename = filename; + m_Handle = open(filename, O_RDWR|O_CREAT|O_TRUNC, 0644); + + if ( m_Handle == -1L ) + { + DefaultLogSink().Error("Error opening file %s: %s\n", filename, strerror(errno)); + return RESULT_FILEOPEN; + } + + m_IOVec = new h__iovec; + return RESULT_OK; +} + +// +Kumu::Result_t +Kumu::FileWriter::OpenModify(const char* filename) +{ + KM_TEST_NULL_STR(filename); + m_Filename = filename; + m_Handle = open(filename, O_RDWR|O_CREAT, 0644); + + if ( m_Handle == -1L ) + { + DefaultLogSink().Error("Error opening file %s: %s\n", filename, strerror(errno)); + return RESULT_FILEOPEN; + } + + m_IOVec = new h__iovec; + return RESULT_OK; +} + +// +Kumu::Result_t +Kumu::FileWriter::Writev(ui32_t* bytes_written) +{ + assert( ! m_IOVec.empty() ); + register h__iovec* iov = m_IOVec; + ui32_t tmp_int; + + if ( bytes_written == 0 ) + bytes_written = &tmp_int; + + if ( m_Handle == -1L ) + return RESULT_STATE; + + int read_size = writev(m_Handle, iov->m_iovec, iov->m_Count); + + if ( read_size == -1L ) + return RESULT_WRITEFAIL; + + iov->m_Count = 0; + *bytes_written = read_size; + return RESULT_OK; +} + +// +Kumu::Result_t +Kumu::FileWriter::Write(const byte_t* buf, ui32_t buf_len, ui32_t* bytes_written) +{ + KM_TEST_NULL(buf); + ui32_t tmp_int; + + if ( bytes_written == 0 ) + bytes_written = &tmp_int; + + // TODO: flush iovec + + + if ( m_Handle == -1L ) + return RESULT_STATE; + + int read_size = write(m_Handle, buf, buf_len); + + if ( read_size == -1L ) + return RESULT_WRITEFAIL; + + *bytes_written = read_size; + return RESULT_OK; +} + + +#endif // KM_WIN32 + +//------------------------------------------------------------------------------------------ + + +// +Kumu::Result_t +Kumu::ReadFileIntoString(const char* filename, std::string& outString, ui32_t max_size) +{ + fsize_t fsize = 0; + ui32_t read_size; + FileReader File; + ByteString ReadBuf; + + KM_TEST_NULL_STR(filename); + + Result_t result = File.OpenRead(filename); + + if ( KM_SUCCESS(result) ) + { + fsize = File.Size(); + + if ( fsize > max_size ) + return RESULT_ALLOC; + + result = ReadBuf.Capacity((ui32_t)fsize); + } + + if ( KM_SUCCESS(result) ) + result = File.Read(ReadBuf.Data(), ReadBuf.Capacity(), &read_size); + + if ( KM_SUCCESS(result) ) + outString.assign((const char*)ReadBuf.RoData(), read_size); + + return result; +} + + +//------------------------------------------------------------------------------------------ +// + +// Win32 directory scanner +// +#ifdef KM_WIN32 + +// +// +Result_t +Kumu::DirScanner::Open(const char* filename) +{ + KM_TEST_NULL_STR(filename); + + // we need to append a '*' to read the entire directory + ui32_t fn_len = strlen(filename); + char* tmp_file = (char*)malloc(fn_len + 8); + + if ( tmp_file == 0 ) + return RESULT_ALLOC; + + strcpy(tmp_file, filename); + char* p = &tmp_file[fn_len] - 1; + + if ( *p != '/' && *p != '\\' ) + { + p++; + *p++ = '/'; + } + + *p++ = '*'; + *p = 0; + // whew... + + m_Handle = _findfirsti64(tmp_file, &m_FileInfo); + Result_t result = RESULT_OK; + + if ( m_Handle == -1 ) + result = RESULT_NOT_FOUND; + + return result; +} + + +// +// +Result_t +Kumu::DirScanner::Close() +{ + if ( m_Handle == -1 ) + return RESULT_FILEOPEN; + + if ( _findclose((long)m_Handle) == -1 ) + return RESULT_FAIL; + + m_Handle = -1; + return RESULT_OK; +} + + +// This sets filename param to the same per-instance buffer every time, so +// the value will change on the next call +Result_t +Kumu::DirScanner::GetNext(char* filename) +{ + KM_TEST_NULL(filename); + + if ( m_Handle == -1 ) + return RESULT_FILEOPEN; + + if ( m_FileInfo.name[0] == '\0' ) + return RESULT_ENDOFFILE; + + strncpy(filename, m_FileInfo.name, MaxFilePath); + Result_t result = RESULT_OK; + + if ( _findnexti64((long)m_Handle, &m_FileInfo) == -1 ) + { + m_FileInfo.name[0] = '\0'; + + if ( errno != ENOENT ) + result = RESULT_FAIL; + } + + return result; +} + + +#else // KM_WIN32 + +// POSIX directory scanner + +// +Result_t +Kumu::DirScanner::Open(const char* filename) +{ + KM_TEST_NULL_STR(filename); + + Result_t result = RESULT_OK; + + if ( ( m_Handle = opendir(filename) ) == NULL ) + { + if ( errno == ENOENT ) + result = RESULT_ENDOFFILE; + + else + result = RESULT_FAIL; + } + + return result; +} + + +// +Result_t +Kumu::DirScanner::Close() +{ + if ( m_Handle == NULL ) + return RESULT_FILEOPEN; + + if ( closedir(m_Handle) == -1 ) + return RESULT_FAIL; + + m_Handle = NULL; + return RESULT_OK; +} + + +// +Result_t +Kumu::DirScanner::GetNext(char* filename) +{ + KM_TEST_NULL(filename); + + if ( m_Handle == NULL ) + return RESULT_FILEOPEN; + + struct dirent* entry; + + for (;;) + { + if ( ( entry = readdir(m_Handle)) == NULL ) + return RESULT_ENDOFFILE; + + break; + } + + strncpy(filename, entry->d_name, MaxFilePath); + return RESULT_OK; +} + + +#endif // KM_WIN32 + + + +// +// end KM_fileio.cpp +// diff --git a/src/KM_fileio.h b/src/KM_fileio.h new file mode 100755 index 0000000..9c79d49 --- /dev/null +++ b/src/KM_fileio.h @@ -0,0 +1,186 @@ +/* +Copyright (c) 2004-2006, 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 KM_fileio.h + \version $Id$ + \brief portable file i/o + */ + +#ifndef _KM_FILEIO_H_ +#define _KM_FILEIO_H_ + +#include <KM_util.h> +#include <string> + +#ifdef KM_WIN32 +# include <io.h> +#else +# include <dirent.h> +# include <unistd.h> +# include <time.h> +# include <sys/types.h> +#endif + +#include <sys/stat.h> + + + +namespace Kumu +{ +#ifdef KM_WIN32 + // + class DirScanner + { + public: + __int64 m_Handle; + struct _finddatai64_t m_FileInfo; + + DirScanner() {}; + ~DirScanner() { Close(); } + Result_t Open(const char*); + Result_t Close(); + Result_t GetNext(char*); + }; +#else // KM_WIN32 + // POSIX directory scanner + // + class DirScanner + { + public: + DIR* m_Handle; + + DirScanner() : m_Handle(NULL) {} + ~DirScanner() { Close(); } + + Result_t Open(const char*); + Result_t Close(); + Result_t GetNext(char*); + }; +#endif // KM_WIN32 + +#ifdef KM_WIN32 + typedef __int64 fsize_t; + typedef __int64 fpos_t; + + enum SeekPos_t { + SP_BEGIN = FILE_BEGIN, + SP_POS = FILE_CURRENT, + SP_END = FILE_END + }; +#else + typedef off_t fsize_t; + typedef off_t fpos_t; + typedef int HANDLE; + const HANDLE INVALID_HANDLE_VALUE = -1L; + + enum SeekPos_t { + SP_BEGIN = SEEK_SET, + SP_POS = SEEK_CUR, + SP_END = SEEK_END + }; +#endif + + const ui32_t Kilobyte = 1024; + const ui32_t Megabyte = Kilobyte * Kilobyte; + const ui32_t Gigabyte = Megabyte * Kilobyte; + + const ui32_t MaxFilePath = Kilobyte; + + bool PathIsFile(const char* pathname); + bool PathIsDirectory(const char* pathname); + fsize_t FileSize(const char* pathname); + + // reads an entire file into a string + Result_t ReadFileIntoString(const char* filename, std::string& outString, ui32_t max_size = 256 * Kilobyte); + + // + class FileReader + { + KM_NO_COPY_CONSTRUCT(FileReader); + + protected: + std::string m_Filename; + HANDLE m_Handle; + + public: + FileReader() : m_Handle(INVALID_HANDLE_VALUE) {} + virtual ~FileReader() { Close(); } + + Result_t OpenRead(const char*) const; // open the file for reading + Result_t Close() const; // close the file + fsize_t Size() const; // returns the file's current size + Result_t Seek(Kumu::fpos_t = 0, SeekPos_t = SP_BEGIN) const; // move the file pointer + Result_t Tell(Kumu::fpos_t* pos) const; // report the file pointer's location + Result_t Read(byte_t*, ui32_t, ui32_t* = 0) const; // read a buffer of data + + inline Kumu::fpos_t Tell() const // report the file pointer's location + { + Kumu::fpos_t tmp_pos; + Tell(&tmp_pos); + return tmp_pos; + } + + inline bool IsOpen() { // returns true if the file is open + return (m_Handle != INVALID_HANDLE_VALUE); + } + }; + + // + class FileWriter : public FileReader + { + class h__iovec; + mem_ptr<h__iovec> m_IOVec; + KM_NO_COPY_CONSTRUCT(FileWriter); + + public: + FileWriter(); + virtual ~FileWriter(); + + Result_t OpenWrite(const char*); // open a new file, overwrites existing + Result_t OpenModify(const char*); // open a file for read/write + + // this part of the interface takes advantage of the iovec structure on + // platforms that support it. For each call to Writev(const byte_t*, ui32_t, ui32_t*), + // the given buffer is added to an internal iovec struct. All items on the list + // are written to disk by a call to Writev(); + Result_t Writev(const byte_t*, ui32_t); // queue buffer for "gather" write + Result_t Writev(ui32_t* = 0); // write all queued buffers + + // if you call this while there are unwritten items on the iovec list, + // the iovec list will be written to disk before the given buffer,as though + // you had called Writev() first. + Result_t Write(const byte_t*, ui32_t, ui32_t* = 0); // write buffer to disk + }; + +} // namespace Kumu + + +#endif // _KM_FILEIO_H_ + + +// +// end KM_fileio.h +// diff --git a/src/KM_log.cpp b/src/KM_log.cpp new file mode 100755 index 0000000..a76df09 --- /dev/null +++ b/src/KM_log.cpp @@ -0,0 +1,155 @@ +/* +Copyright (c) 2004-2006, 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 KM_log.cpp + \version $Id$ + \brief message logging API + */ + +#include <KM_util.h> +#include <KM_log.h> +#include <sys/types.h> +#include <string.h> +#include <stdarg.h> + +#ifdef KM_WIN32 +#define getpid GetCurrentProcessId +#else +#include <unistd.h> +#endif + + +void +Kumu::StdioLogSink::vLogf(ILogSink::LogType_t type, const char* fmt, va_list* list) +{ + AutoMutex L(m_Lock); + + switch ( type ) + { + case LOG_CRIT: fprintf(m_stream, "[%d CRT]: ", getpid()); break; + case LOG_ALERT: fprintf(m_stream, "[%d ALR]: ", getpid()); break; + case LOG_NOTICE: fprintf(m_stream, "[%d NTC]: ", getpid()); break; + case LOG_ERROR: fprintf(m_stream, "[%d ERR]: ", getpid()); break; + case LOG_WARN: fprintf(m_stream, "[%d WRN]: ", getpid()); break; + case LOG_INFO: fprintf(m_stream, "[%d INF]: ", getpid()); break; + case LOG_DEBUG: fprintf(m_stream, "[%d DBG]: ", getpid()); break; + default: fprintf(m_stream, "[%d DFL]: ", getpid()); + } + + vfprintf(m_stream, fmt, *list); +} + +static Kumu::ILogSink* s_DefaultLogSink; +static Kumu::StdioLogSink s_StderrLogSink; + +// +void +Kumu::SetDefaultLogSink(ILogSink* Sink) +{ + s_DefaultLogSink = Sink; +} + +// Returns the internal default sink. +Kumu::ILogSink& +Kumu::DefaultLogSink() +{ + if ( s_DefaultLogSink == 0 ) + s_DefaultLogSink = &s_StderrLogSink; + + return *s_DefaultLogSink; +} + +//--------------------------------------------------------------------------------- +#ifdef KM_WIN32 + +// +void +Kumu::WinDbgLogSink::vLogf(ILogSink::LogType_t type, const char* fmt, va_list* list) +{ + AutoMutex L(m_Lock); + char msg_buf[MaxLogLength]; + + DWORD pid = GetCurrentProcessId(); + + switch ( type ) + { + case LOG_CRIT: snprintf(msg_buf, MaxLogLength, "[%d CRT]: ", pid); break; + case LOG_ALERT: snprintf(msg_buf, MaxLogLength, "[%d ALR]: ", pid); break; + case LOG_NOTICE: snprintf(msg_buf, MaxLogLength, "[%d NTC]: ", pid); break; + case LOG_ERROR: snprintf(msg_buf, MaxLogLength, "[%d ERR]: ", pid); break; + case LOG_WARN: snprintf(msg_buf, MaxLogLength, "[%d WRN]: ", pid); break; + case LOG_INFO: snprintf(msg_buf, MaxLogLength, "[%d INF]: ", pid); break; + case LOG_DEBUG: snprintf(msg_buf, MaxLogLength, "[%d DBG]: ", pid); break; + default: snprintf(msg_buf, MaxLogLength, "[%d DFL]: ", pid); + } + + ui32_t len = strlen(msg_buf); + vsnprintf(msg_buf + len, MaxLogLength - len, fmt, *list); + msg_buf[MaxLogLength-1] = 0; + ::OutputDebugString(msg_buf); +} + +#else + +void +Kumu::StreamLogSink::vLogf(ILogSink::LogType_t type, const char* fmt, va_list* list) +{ + AutoMutex L(m_Lock); + char msg_buf[MaxLogLength]; + char ts_buf[MaxLogLength]; + Timestamp Now; + + switch ( type ) + { + case LOG_CRIT: snprintf(msg_buf, MaxLogLength, "[%s %d CRT]: ", + Now.EncodeString(ts_buf, MaxLogLength), getpid()); break; + case LOG_ALERT: snprintf(msg_buf, MaxLogLength, "[%s %d ALR]: ", + Now.EncodeString(ts_buf, MaxLogLength), getpid()); break; + case LOG_NOTICE: snprintf(msg_buf, MaxLogLength, "[%s %d NTC]: ", + Now.EncodeString(ts_buf, MaxLogLength), getpid()); break; + case LOG_ERROR: snprintf(msg_buf, MaxLogLength, "[%s %d ERR]: ", + Now.EncodeString(ts_buf, MaxLogLength), getpid()); break; + case LOG_WARN: snprintf(msg_buf, MaxLogLength, "[%s %d WRN]: ", + Now.EncodeString(ts_buf, MaxLogLength), getpid()); break; + case LOG_INFO: snprintf(msg_buf, MaxLogLength, "[%s %d INF]: ", + Now.EncodeString(ts_buf, MaxLogLength), getpid()); break; + case LOG_DEBUG: snprintf(msg_buf, MaxLogLength, "[%s %d DBG]: ", + Now.EncodeString(ts_buf, MaxLogLength), getpid()); break; + default: snprintf(msg_buf, MaxLogLength, "[%s %d DFL]: ", + Now.EncodeString(ts_buf, MaxLogLength), getpid()); + } + + ui32_t len = strlen(msg_buf); + vsnprintf(msg_buf + len, MaxLogLength - len, fmt, *list); + msg_buf[MaxLogLength-1] = 0; + write(m_fd, msg_buf, strlen(msg_buf)); +} +#endif + + +// +// end +// diff --git a/src/KM_log.h b/src/KM_log.h new file mode 100755 index 0000000..2bbc330 --- /dev/null +++ b/src/KM_log.h @@ -0,0 +1,133 @@ +/* +Copyright (c) 2004-2006, 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 KM_log.h + \version $Id$ + \brief message logging API + */ + + +#ifndef _KM_LOG_H_ +#define _KM_LOG_H_ + +#include <KM_platform.h> +#include <KM_mutex.h> +#include <stdarg.h> +#include <errno.h> + +#define LOG_MSG_IMPL(t) va_list args; va_start(args, fmt); vLogf((t), fmt, &args); va_end(args) + + +namespace Kumu +{ + // no log message will exceed this length + const ui32_t MaxLogLength = 512; + + //--------------------------------------------------------------------------------- + // message logging + + // Error and debug messages will be delivered to an object having this interface. + // The default implementation sends only LOG_ERROR and LOG_WARN messages to stderr. + // To receive LOG_INFO or LOG_DEBUG messages, or to send messages somewhere other + // than stderr, implement this interface and register an instance of your new class + // by calling SetDefaultLogSink(). + class ILogSink + { + public: + enum LogType_t { LOG_DEBUG, LOG_INFO, LOG_WARN, LOG_ERROR, + LOG_NOTICE, LOG_ALERT, LOG_CRIT }; + + virtual ~ILogSink() {} + + void Critical(const char* fmt, ...) { LOG_MSG_IMPL(LOG_CRIT); } + void Alert(const char* fmt, ...) { LOG_MSG_IMPL(LOG_ALERT); } + void Notice(const char* fmt, ...) { LOG_MSG_IMPL(LOG_NOTICE); } + void Error(const char* fmt, ...) { LOG_MSG_IMPL(LOG_ERROR); } + void Warn(const char* fmt, ...) { LOG_MSG_IMPL(LOG_WARN); } + void Info(const char* fmt, ...) { LOG_MSG_IMPL(LOG_INFO); } + void Debug(const char* fmt, ...) { LOG_MSG_IMPL(LOG_DEBUG); } + void Logf(ILogSink::LogType_t type, const char* fmt, ...) { LOG_MSG_IMPL(type); } + virtual void vLogf(LogType_t, const char*, va_list*) = 0; // log a formatted string with a va_list struct + }; + + // Sets the internal default sink to the given receiver. If the given value + // is zero, sets the default sink to the internally allocated stderr sink. + void SetDefaultLogSink(ILogSink* = 0); + + // Returns the internal default sink. + ILogSink& DefaultLogSink(); + + // + class StdioLogSink : public ILogSink + { + Mutex m_Lock; + FILE* m_stream; + KM_NO_COPY_CONSTRUCT(StdioLogSink); + + public: + StdioLogSink() : m_stream(stderr) {}; + StdioLogSink(FILE* stream) : m_stream(stream) {} + virtual ~StdioLogSink() {} + virtual void vLogf(LogType_t, const char*, va_list*); + }; + +#ifdef KM_WIN32 + // + class WinDbgLogSink : public ILogSink + { + Mutex m_Lock; + KM_NO_COPY_CONSTRUCT(WinDbgLogSink); + + public: + WinDbgLogSink() {} + virtual ~WinDbgLogSink() {} + virtual void vLogf(LogType_t, const char*, va_list*); + }; + +#else + + // + class StreamLogSink : public ILogSink + { + Mutex m_Lock; + int m_fd; + KM_NO_COPY_CONSTRUCT(StreamLogSink); + StreamLogSink(); + + public: + StreamLogSink(int fd) : m_fd(fd) {} + virtual ~StreamLogSink() {} + virtual void vLogf(LogType_t, const char*, va_list*); + }; +#endif + +} // namespace Kumu + +#endif // _KM_LOG_H_ + +// +// end KM_log.h +// diff --git a/src/KM_memio.h b/src/KM_memio.h new file mode 100755 index 0000000..8416b57 --- /dev/null +++ b/src/KM_memio.h @@ -0,0 +1,216 @@ +/* +Copyright (c) 2006, 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 KM_memio.h + \version $Id$ + \brief abstraction for byte-oriented conversion of integers and objects + */ + +#ifndef _KM_MEMIO_H_ +#define _KM_MEMIO_H_ + +#include <KM_platform.h> +#include <string.h> + +namespace Kumu +{ + class ByteString; + + // + class MemIOWriter + { + KM_NO_COPY_CONSTRUCT(MemIOWriter); + MemIOWriter(); + + protected: + byte_t* m_p; + ui32_t m_capacity; + ui32_t m_size; + + public: + MemIOWriter(byte_t* p, ui32_t c) : m_p(p), m_capacity(c), m_size(0) { + assert(m_p); assert(m_capacity); + } + + MemIOWriter(ByteString* Buf); + ~MemIOWriter() {} + + inline void Reset() { m_size = 0; } + inline byte_t* Data() { return m_p; } + inline byte_t* CurrentData() { return m_p + m_size; } + inline ui32_t Length() { return m_size; } + inline ui32_t Remainder() { return m_capacity - m_size; } + + inline bool AddOffset(ui32_t offset) { + if ( ( m_size + offset ) > m_capacity ) + return false; + + m_size += offset; + return true; + + } + + inline bool WriteRaw(const byte_t* p, ui32_t buf_len) { + if ( ( m_size + buf_len ) > m_capacity ) + return false; + + memcpy(m_p + m_size, p, buf_len); + m_size += buf_len; + return true; + } + + bool WriteBER(ui64_t i, ui32_t ber_len); + + inline bool WriteUi8(ui8_t i) { + if ( ( m_size + 1 ) > m_capacity ) + return false; + + *(m_p + m_size) = i; + m_size++; + return true; + } + + inline bool WriteUi16BE(ui16_t i) { + if ( ( m_size + sizeof(ui16_t) ) > m_capacity ) + return false; + + i2p<ui16_t>(KM_i16_BE(i), m_p + m_size); + m_size += sizeof(ui16_t); + return true; + } + + inline bool WriteUi32BE(ui32_t i) { + if ( ( m_size + sizeof(ui32_t) ) > m_capacity ) + return false; + + i2p<ui32_t>(KM_i32_BE(i), m_p + m_size); + m_size += sizeof(ui32_t); + return true; + } + + inline bool WriteUi64BE(ui64_t i) { + if ( ( m_size + sizeof(ui64_t) ) > m_capacity ) + return false; + + i2p<ui64_t>(KM_i64_BE(i), m_p + m_size); + m_size += sizeof(ui64_t); + return true; + } + }; + + // + class MemIOReader + { + KM_NO_COPY_CONSTRUCT(MemIOReader); + MemIOReader(); + + protected: + const byte_t* m_p; + ui32_t m_capacity; + ui32_t m_size; // this is sort of a misnomer, when we are reading it measures offset + + public: + MemIOReader(const byte_t* p, ui32_t c) : + m_p(p), m_capacity(c), m_size(0) { + assert(m_p); assert(m_capacity); + } + + MemIOReader(const ByteString* Buf); + ~MemIOReader() {} + + inline void Reset() { m_size = 0; } + inline const byte_t* Data() { return m_p; } + inline const byte_t* CurrentData() { return m_p + m_size; } + inline ui32_t Offset() { return m_size; } + inline ui32_t Remainder() { return m_capacity - m_size; } + + inline bool SkipOffset(ui32_t offset) { + if ( ( m_size + offset ) > m_capacity ) + return false; + + m_size += offset; + return true; + } + + inline bool ReadRaw(byte_t* p, ui32_t buf_len) { + if ( ( m_size + buf_len ) > m_capacity ) + return false; + + memcpy(p, m_p + m_size, buf_len); + m_size += buf_len; + return true; + } + + bool ReadBER(ui64_t* i, ui32_t* ber_len); + + inline bool ReadUi8(ui8_t* i) { + assert(i); + if ( ( m_size + 1 ) > m_capacity ) + return false; + + *i = *(m_p + m_size); + m_size++; + return true; + } + + inline bool ReadUi16BE(ui16_t* i) { + assert(i); + if ( ( m_size + sizeof(ui16_t) ) > m_capacity ) + return false; + + *i = KM_i16_BE(cp2i<ui16_t>(m_p + m_size)); + m_size += sizeof(ui16_t); + return true; + } + + inline bool ReadUi32BE(ui32_t* i) { + assert(i); + if ( ( m_size + sizeof(ui32_t) ) > m_capacity ) + return false; + + *i = KM_i32_BE(cp2i<ui32_t>(m_p + m_size)); + m_size += sizeof(ui32_t); + return true; + } + + inline bool ReadUi64BE(ui64_t* i) { + assert(i); + if ( ( m_size + sizeof(ui64_t) ) > m_capacity ) + return false; + + *i = KM_i64_BE(cp2i<ui64_t>(m_p + m_size)); + m_size += sizeof(ui64_t); + return true; + } + }; + +} // namespace Kumu + +#endif // _KM_MEMIO_H_ + +// +// end KM_memio.h +// diff --git a/src/KM_mutex.h b/src/KM_mutex.h new file mode 100755 index 0000000..513b504 --- /dev/null +++ b/src/KM_mutex.h @@ -0,0 +1,89 @@ +/* +Copyright (c) 2004-2006, 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 KM_mutex.h + \version $Id$ + \brief platform portability + */ + +#ifndef _KM_MUTEX_H_ +#define _KM_MUTEX_H_ + +#include <KM_platform.h> + +#ifndef KM_WIN32 +# include <pthread.h> +#endif + +namespace Kumu +{ +#ifdef KM_WIN32 + class Mutex + { + CRITICAL_SECTION m_Mutex; + KM_NO_COPY_CONSTRUCT(Mutex); + + public: + inline Mutex() { ::InitializeCriticalSection(&m_Mutex); } + inline ~Mutex() { ::DeleteCriticalSection(&m_Mutex); } + inline void Lock() { ::EnterCriticalSection(&m_Mutex); } + inline void Unlock() { ::LeaveCriticalSection(&m_Mutex); } + }; +#else // KM_WIN32 + class Mutex + { + pthread_mutex_t m_Mutex; + KM_NO_COPY_CONSTRUCT(Mutex); + + public: + inline Mutex() { pthread_mutex_init(&m_Mutex, 0); } + inline ~Mutex() { pthread_mutex_destroy(&m_Mutex); } + inline void Lock() { pthread_mutex_lock(&m_Mutex); } + inline void Unlock() { pthread_mutex_unlock(&m_Mutex); } + }; +#endif // KM_WIN32 + + // automatic Mutex management within a block - + // the mutex is created by the constructor and + // released by the destructor + class AutoMutex + { + Mutex& m_Mutex; + AutoMutex(); + KM_NO_COPY_CONSTRUCT(AutoMutex); + + public: + AutoMutex(Mutex& Mtx) : m_Mutex(Mtx) { m_Mutex.Lock(); } + ~AutoMutex() { m_Mutex.Unlock(); } + }; + +} // namespace Kumu + +#endif // _KM_MUTEX_H_ + +// +// end KM_mutex.h +// diff --git a/src/KM_platform.h b/src/KM_platform.h new file mode 100644 index 0000000..0c577a1 --- /dev/null +++ b/src/KM_platform.h @@ -0,0 +1,189 @@ +/* +Copyright (c) 2004-2006, 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 KM_platform.h + \version $Id$ + \brief platform portability + */ + +#ifndef _KM_PLATFORM_H_ +# define _KM_PLATFORM_H_ + +# ifdef __APPLE__ +# ifdef __BIG_ENDIAN__ +# define KM_BIG_ENDIAN +# endif +# endif + +# ifdef KM_WIN32 +# define WIN32_LEAN_AND_MEAN +# define VC_EXTRALEAN +# include <windows.h> +# include <stdlib.h> +# pragma warning(disable:4786) // Ignore "identifer > 255 characters" warning + +typedef unsigned __int64 ui64_t; +typedef __int64 i64_t; +# define i64_C(c) (i64_t)(c) +# define ui64_C(c) (ui64_t)(c) +# define snprintf _snprintf +# define vsnprintf _vsnprintf + +# else // KM_WIN32 +typedef unsigned long long ui64_t; +typedef long long i64_t; +# define i64_C(c) c##LL +# define ui64_C(c) c##ULL + +# endif // KM_WIN32 + +# include <stdio.h> +# include <assert.h> +# include <stdlib.h> +# include <limits.h> + +typedef unsigned char byte_t; +typedef char i8_t; +typedef unsigned char ui8_t; +typedef short i16_t; +typedef unsigned short ui16_t; +typedef int i32_t; +typedef unsigned int ui32_t; + + +namespace Kumu +{ + inline ui16_t Swap2(ui16_t i) + { + return ( (i << 8) | (( i & 0xff00) >> 8) ); + } + + inline ui32_t Swap4(ui32_t i) + { + return + ( (i & 0x000000ffUL) << 24 ) | + ( (i & 0xff000000UL) >> 24 ) | + ( (i & 0x0000ff00UL) << 8 ) | + ( (i & 0x00ff0000UL) >> 8 ); + } + + inline ui64_t Swap8(ui64_t i) + { + return + ( (i & ui64_C(0x00000000000000FF)) << 56 ) | + ( (i & ui64_C(0xFF00000000000000)) >> 56 ) | + ( (i & ui64_C(0x000000000000FF00)) << 40 ) | + ( (i & ui64_C(0x00FF000000000000)) >> 40 ) | + ( (i & ui64_C(0x0000000000FF0000)) << 24 ) | + ( (i & ui64_C(0x0000FF0000000000)) >> 24 ) | + ( (i & ui64_C(0x00000000FF000000)) << 8 ) | + ( (i & ui64_C(0x000000FF00000000)) >> 8 ); + } + + // + template<class T> + inline T xmin(T lhs, T rhs) { + return (lhs < rhs) ? lhs : rhs; + } + + // + template<class T> + inline T xmax(T lhs, T rhs) { + return (lhs > rhs) ? lhs : rhs; + } + + // + template<class T> + inline T xclamp(T v, T l, T h) { + if ( v < l ) return l; + if ( v > h ) return h; + return v; + } + + + // read an integer from byte-structured storage + template<class T> + inline T cp2i(const byte_t* p) { return *(T*)p; } + + // write an integer to byte-structured storage + template<class T> + inline void i2p(T i, byte_t* p) { *(T*)p = i; } + +# ifdef KM_BIG_ENDIAN +# define KM_i16_LE(i) Kumu::Swap2(i) +# define KM_i32_LE(i) Kumu::Swap4(i) +# define KM_i64_LE(i) Kumu::Swap8(i) +# define KM_i16_BE(i) (i) +# define KM_i32_BE(i) (i) +# define KM_i64_BE(i) (i) +# else +# define KM_i16_LE(i) (i) +# define KM_i32_LE(i) (i) +# define KM_i64_LE(i) (i) +# define KM_i16_BE(i) Kumu::Swap2(i) +# define KM_i32_BE(i) Kumu::Swap4(i) +# define KM_i64_BE(i) Kumu::Swap8(i) +# endif // KM_BIG_ENDIAN + + // A non-reference counting, auto-delete container for internal + // member object pointers. + template <class T> + class mem_ptr + { + mem_ptr(T&); + + protected: + T* m_p; // the thing we point to + + public: + mem_ptr() : m_p(0) {} + mem_ptr(T* p) : m_p(p) {} + ~mem_ptr() { delete m_p; } + + inline T& operator*() const { return *m_p; } + inline T* operator->() const { return m_p; } + inline operator T*()const { return m_p; } + inline const mem_ptr<T>& operator=(T* p) { set(p); return *this; } + inline T* set(T* p) { delete m_p; m_p = p; return m_p; } + inline T* get() const { return m_p; } + inline void release() { m_p = 0; } + inline bool empty() const { return m_p == 0; } + }; + +} // namespace Kumu + +// Produces copy constructor boilerplate. Allows convenient private +// declatarion of copy constructors to prevent the compiler from +// silently manufacturing default methods. +# define KM_NO_COPY_CONSTRUCT(T) \ + T(const T&); \ + T& operator=(const T&) + +#endif // _KM_PLATFORM_H_ + +// +// KM_platform.h +// diff --git a/src/KM_prng.cpp b/src/KM_prng.cpp new file mode 100755 index 0000000..5e3dd48 --- /dev/null +++ b/src/KM_prng.cpp @@ -0,0 +1,214 @@ +/* +Copyright (c) 2006, 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 KM_prng.cpp + \version $Id$ + \brief Fortuna pseudo-random number generator + */ + +#include <KM_prng.h> +#include <KM_log.h> +#include <KM_mutex.h> +#include <string.h> +#include <assert.h> +#include <openssl/aes.h> +#include <openssl/sha.h> + +using namespace Kumu; + + +#ifdef KM_WIN32 + +// make up a byte by sampling the perf counter LSB +static byte_t get_perf_byte() +{ + LARGE_INTEGER ticks; + byte_t retval; + + for ( int i = 0; i < 8; i++ ) + { + QueryPerformanceCounter(&ticks); + retval |= (ticks.LowPart & 0x00000001) << i; + } + + return retval; +} + +#else // KM_WIN32 + +#include <KM_fileio.h> +const char* DEV_URANDOM = "/dev/urandom"; + +#endif // KM_WIN32 + + +const ui32_t RNG_KEY_SIZE = 512UL; +const ui32_t RNG_KEY_SIZE_BITS = 256UL; +const ui32_t RNG_BLOCK_SIZE = 16UL; +const ui32_t MAX_SEQUENCE_LEN = 0x00040000UL; + + +// internal implementation class +class h__RNG +{ + KM_NO_COPY_CONSTRUCT(h__RNG); + +public: + AES_KEY m_Context; + byte_t m_ctr_buf[RNG_BLOCK_SIZE]; + Mutex m_Lock; + + h__RNG() + { + memset(m_ctr_buf, 0, RNG_BLOCK_SIZE); + byte_t rng_key[RNG_KEY_SIZE]; + + { // this block scopes the following AutoMutex so that it will be + // released before the call to set_key() below. + AutoMutex Lock(m_Lock); + +#ifdef KM_WIN32 + for ( ui32_t i = 0; i < RNG_KEY_SIZE; i++ ) + rng_key[i] = get_perf_byte(); + +#else // KM_WIN32 + // on POSIX systems we simply read some seed from /dev/urandom + FileReader URandom; + + Result_t result = URandom.OpenRead(DEV_URANDOM); + + if ( KM_SUCCESS(result) ) + { + ui32_t read_count; + result = URandom.Read(rng_key, RNG_KEY_SIZE, &read_count); + } + + if ( KM_FAILURE(result) ) + DefaultLogSink().Error("Error opening random device: %s\n", DEV_URANDOM); + +#endif // KM_WIN32 + } // end AutoMutex context + + set_key(rng_key); + } + + // + void + set_key(const byte_t* key_fodder) + { + assert(key_fodder); + byte_t sha_buf[20]; + SHA_CTX SHA; + SHA1_Init(&SHA); + + SHA1_Update(&SHA, (byte_t*)&m_Context, sizeof(m_Context)); + SHA1_Update(&SHA, key_fodder, RNG_KEY_SIZE); + SHA1_Final(sha_buf, &SHA); + + AutoMutex Lock(m_Lock); + AES_set_encrypt_key(sha_buf, RNG_KEY_SIZE_BITS, &m_Context); + *(ui32_t*)(m_ctr_buf + 12) = 1; + } + + // + void + fill_rand(byte_t* buf, ui32_t len) + { + assert(len <= MAX_SEQUENCE_LEN); + ui32_t gen_count = 0; + AutoMutex Lock(m_Lock); + + while ( gen_count + RNG_BLOCK_SIZE <= len ) + { + AES_encrypt(m_ctr_buf, buf + gen_count, &m_Context); + *(ui32_t*)(m_ctr_buf + 12) += 1; + gen_count += RNG_BLOCK_SIZE; + } + + if ( len != gen_count ) // partial count needed? + { + byte_t tmp[RNG_BLOCK_SIZE]; + AES_encrypt(m_ctr_buf, tmp, &m_Context); + *(ui32_t*)(m_ctr_buf + 12) += 1; + memcpy(buf, tmp, len - gen_count); + } + } +}; + + +static h__RNG* s_RNG = 0; + + +//------------------------------------------------------------------------------------------ +// +// public interface + +Kumu::FortunaRNG::FortunaRNG() +{ + if ( s_RNG == 0 ) + s_RNG = new h__RNG; +} + +Kumu::FortunaRNG::~FortunaRNG() {} + +// +const byte_t* +Kumu::FortunaRNG::FillRandom(byte_t* buf, ui32_t len) +{ + assert(buf); + assert(s_RNG); + + while ( len ) + { + // 2^20 bytes max per seeding, use 2^19 to save + // room for generating reseed values + ui32_t gen_size = xmin(len, MAX_SEQUENCE_LEN); + s_RNG->fill_rand(buf, gen_size); + buf += gen_size; + len -= gen_size; + + // re-seed the generator + byte_t rng_key[RNG_KEY_SIZE]; + s_RNG->fill_rand(rng_key, RNG_KEY_SIZE); + s_RNG->set_key(rng_key); + } + + return buf; +} + +// +const byte_t* +Kumu::FortunaRNG::FillRandom(Kumu::ByteString& Buffer) +{ + FillRandom(Buffer.Data(), Buffer.Capacity()); + Buffer.Length(Buffer.Capacity()); + return Buffer.Data(); +} + + +// +// end KM_prng.cpp +// diff --git a/src/KM_prng.h b/src/KM_prng.h new file mode 100755 index 0000000..f7dfa2b --- /dev/null +++ b/src/KM_prng.h @@ -0,0 +1,57 @@ +/* +Copyright (c) 2006, 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 KM_prng.h + \version $Id$ + \brief Fortuna pseudo-random number generator + */ + +#ifndef _KM_PRNG_H_ +#define _KM_PRNG_H_ + +#include <KM_util.h> + +namespace Kumu +{ + class FortunaRNG + { + KM_NO_COPY_CONSTRUCT(FortunaRNG); + + public: + FortunaRNG(); + ~FortunaRNG(); + const byte_t* FillRandom(byte_t* buf, ui32_t len); + const byte_t* FillRandom(ByteString&); + }; +} // namespace Kumu + + + +#endif // _KM_PRNG_H_ + +// +// end KM_prng.h +// diff --git a/src/KM_util.cpp b/src/KM_util.cpp new file mode 100755 index 0000000..c8cbb1c --- /dev/null +++ b/src/KM_util.cpp @@ -0,0 +1,921 @@ +/* +Copyright (c) 2005-2006, 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 KM_util.cpp + \version $Id$ + \brief Utility functions + */ + +#include <KM_util.h> +#include <KM_prng.h> +#include <KM_memio.h> +#include <KM_fileio.h> +#include <KM_log.h> +#include <ctype.h> +#include <list> +#include <string> + +//------------------------------------------------------------------------------------------ + + +const char fill = '='; +const char* base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +const byte_t decode_map[] = +{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 62, 0xff, 0xff, 0xff, 63, + 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, + 0xff, 0, 1, 2, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; + + +// Convert a binary string to NULL-terminated UTF-8 hexadecimal, returns the buffer +// if the binary buffer was large enough to hold the result. If the output buffer +// is too small or any of the pointer arguments are NULL, the subroutine will +// return 0. +// +const char* +Kumu::base64encode(const byte_t* buf, ui32_t buf_len, char* strbuf, ui32_t strbuf_len) +{ + ui32_t out_char = 0; + ui32_t i, block_len, diff; + + if ( buf == 0 || strbuf == 0 ) + return 0; + + if ( strbuf_len < base64_encode_length(buf_len) + 1 ) + return 0; + + block_len = buf_len; + + while ( block_len % 3 ) + block_len--; + + for ( i = 0; i < block_len; i += 3 ) + { + strbuf[out_char++] = base64_chars[( buf[0] >> 2 )]; + strbuf[out_char++] = base64_chars[( ( ( buf[0] & 0x03 ) << 4 ) | ( buf[1] >> 4 ) )]; + strbuf[out_char++] = base64_chars[( ( ( buf[1] & 0x0f ) << 2 ) | ( buf[2] >> 6 ) )]; + strbuf[out_char++] = base64_chars[( buf[2] & 0x3f )]; + buf += 3; + } + + if ( i < buf_len ) + { + diff = buf_len - i; + assert(diff > 0); + assert(diff < 3); + + strbuf[out_char++] = base64_chars[( buf[0] >> 2 )]; + + if ( diff == 1 ) + { + strbuf[out_char++] = base64_chars[( ( ( buf[0] & 0x03 ) << 4 ) )]; + strbuf[out_char++] = fill; + } + else if ( diff == 2 ) + { + strbuf[out_char++] = base64_chars[( ( ( buf[0] & 0x03 ) << 4 ) | ( buf[1] >> 4 ) )]; + strbuf[out_char++] = base64_chars[( ( ( buf[1] & 0x0f ) << 2 ) )]; + } + + strbuf[out_char++] = fill; + } + + strbuf[out_char] = 0; + return strbuf;; +} + + + + +// Convert NULL-terminated UTF-8 Base64 string to binary, returns 0 if +// the binary buffer was large enough to hold the result. The output parameter +// 'char_count' will contain the length of the converted string. If the output +// buffer is too small or any of the pointer arguments are NULL, the subroutine +// will return -1 and set 'char_count' to the required buffer size. No data will +// be written to 'buf' if the subroutine fails. +// +i32_t +Kumu::base64decode(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* char_count) +{ + register byte_t c = 0, d = 0; + register ui32_t phase = 0, i = 0; + + if ( str == 0 || buf == 0 || char_count == 0 ) + return -1; + + while ( *str != 0 && i < buf_len ) + { + c = decode_map[(int)*str++]; + if ( c == 0xff ) continue; + if ( c == 0xfe ) break; + + switch ( phase++ ) + { + case 0: + buf[i++] = c << 2; + break; + + case 1: + buf[i - 1] |= c >> 4; + d = c; + break; + + case 2: + buf[i++] = ( d << 4 ) | ( c >> 2 ); + d = c; + break; + + case 3: + buf[i++] = ( d << 6 ) | c; + phase = 0; + break; + } + } + + *char_count = i; + return 0; +} + +//------------------------------------------------------------------------------------------ + +// convert utf-8 hext string to bin +i32_t +Kumu::hex2bin(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* conv_size) +{ + KM_TEST_NULL(str); + KM_TEST_NULL(buf); + KM_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* +Kumu::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 +Kumu::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; + } +} + +// +const char* +Kumu::bin2UUIDhex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len) +{ + ui32_t i, j, k; + + if ( str_len < 34 || bin_len != UUID_Length ) + return 0; + + if ( bin2hex(bin_buf, bin_len, str_buf, str_len) == 0 ) + return 0; + + // shift the node id + for ( k = 19, i = 12; i > 0; i-- ) + str_buf[k+i+4] = str_buf[k+i]; + + // shift the time (mid+hi+clk) + for ( k = 15, j = 3; k > 6; k -= 4, j-- ) + { + for ( i = 4; i > 0; i-- ) + str_buf[k+i+j] = str_buf[k+i]; + } + + // add in the hyphens and trainling null + for ( i = 8; i < 24; i += 5 ) + str_buf[i] = '-'; + + str_buf[36] = 0; + return str_buf; +} + +// +void +Kumu::GenRandomValue(UUID& ID) +{ + byte_t tmp_buf[UUID_Length]; + GenRandomUUID(tmp_buf); + ID.Set(tmp_buf); +} + +// +void +Kumu::GenRandomUUID(byte_t* buf) +{ + FortunaRNG RNG; + RNG.FillRandom(buf, UUID_Length); + buf[6] &= 0x0f; // clear bits 4-7 + buf[6] |= 0x40; // set UUID version + buf[8] &= 0x3f; // clear bits 6&7 + buf[8] |= 0x80; // set bit 7 +} + +// +void +Kumu::GenRandomValue(SymmetricKey& ID) +{ + byte_t tmp_buf[SymmetricKey_Length]; + FortunaRNG RNG; + RNG.FillRandom(tmp_buf, SymmetricKey_Length); + ID.Set(tmp_buf); +} + + +//------------------------------------------------------------------------------------------ +// read a ber value from the buffer and compare with test value. +// Advances buffer to first character after BER value. + +// read a ber value from the buffer and compare with test value. +// Advances buffer to first character after BER value. +// +bool +Kumu::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 +Kumu::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 +Kumu::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] ) + { + ui64Printer tmp_i(val); + DefaultLogSink().Error("BER size %lu too small for value %s\n", tmp_i.c_str()); + 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; +} + + +//------------------------------------------------------------------------------------------ +#ifdef KM_WIN32 + +#define TIMESTAMP_TO_SYSTIME(ts, t) \ + (t)->wYear = (ts).Year; /* year */ \ + (t)->wMonth = (ts).Month; /* month of year (1 - 12) */ \ + (t)->wDay = (ts).Day; /* day of month (1 - 31) */ \ + (t)->wHour = (ts).Hour; /* hours (0 - 23) */ \ + (t)->wMinute = (ts).Minute; /* minutes (0 - 59) */ \ + (t)->wSecond = (ts).Second; /* seconds (0 - 60) */ \ + (t)->wDayOfWeek = 0; \ + (t)->wMilliseconds = 0 + +#define SYSTIME_TO_TIMESTAMP(t, ts) \ + (ts).Year = (t)->wYear; /* year */ \ + (ts).Month = (t)->wMonth; /* month of year (1 - 12) */ \ + (ts).Day = (t)->wDay; /* day of month (1 - 31) */ \ + (ts).Hour = (t)->wHour; /* hours (0 - 23) */ \ + (ts).Minute = (t)->wMinute; /* minutes (0 - 59) */ \ + (ts).Second = (t)->wSecond; /* seconds (0 - 60) */ + +// +Kumu::Timestamp::Timestamp() : + Year(0), Month(0), Day(0), Hour(0), Minute(0), Second(0) +{ + SYSTEMTIME sys_time; + GetSystemTime(&sys_time); + SYSTIME_TO_TIMESTAMP(&sys_time, *this); +} + +// +bool +Kumu::Timestamp::operator<(const Timestamp& rhs) const +{ + SYSTEMTIME lhst, rhst; + FILETIME lft, rft; + + TIMESTAMP_TO_SYSTIME(*this, &lhst); + TIMESTAMP_TO_SYSTIME(rhs, &rhst); + SystemTimeToFileTime(&lhst, &lft); + SystemTimeToFileTime(&rhst, &rft); + return ( CompareFileTime(&lft, &rft) == -1 ); +} + +inline ui64_t +seconds_to_ns100(ui32_t seconds) +{ + return ((ui64_t)seconds * 10000000); +} + +// +void +Kumu::Timestamp::AddDays(i32_t days) +{ + SYSTEMTIME current_st; + FILETIME current_ft; + ULARGE_INTEGER current_ul; + + if ( days != 0 ) + { + TIMESTAMP_TO_SYSTIME(*this, ¤t_st); + SystemTimeToFileTime(¤t_st, ¤t_ft); + memcpy(¤t_ul, ¤t_ft, sizeof(current_ul)); + current_ul.QuadPart += ( seconds_to_ns100(86400) * (ui64_t)days ); + memcpy(¤t_ft, ¤t_ul, sizeof(current_ft)); + FileTimeToSystemTime(¤t_ft, ¤t_st); + SYSTIME_TO_TIMESTAMP(¤t_st, *this); + } +} + +// +void +Kumu::Timestamp::AddHours(i32_t hours) +{ + SYSTEMTIME current_st; + FILETIME current_ft; + ULARGE_INTEGER current_ul; + + if ( hours != 0 ) + { + TIMESTAMP_TO_SYSTIME(*this, ¤t_st); + SystemTimeToFileTime(¤t_st, ¤t_ft); + memcpy(¤t_ul, ¤t_ft, sizeof(current_ul)); + current_ul.QuadPart += ( seconds_to_ns100(3600) * (ui64_t)hours ); + memcpy(¤t_ft, ¤t_ul, sizeof(current_ft)); + FileTimeToSystemTime(¤t_ft, ¤t_st); + SYSTIME_TO_TIMESTAMP(¤t_st, *this); + } +} + +#else // KM_WIN32 + +#include <time.h> + +#define TIMESTAMP_TO_TM(ts, t) \ + (t)->tm_year = (ts).Year - 1900; /* year - 1900 */ \ + (t)->tm_mon = (ts).Month - 1; /* month of year (0 - 11) */ \ + (t)->tm_mday = (ts).Day; /* day of month (1 - 31) */ \ + (t)->tm_hour = (ts).Hour; /* hours (0 - 23) */ \ + (t)->tm_min = (ts).Minute; /* minutes (0 - 59) */ \ + (t)->tm_sec = (ts).Second; /* seconds (0 - 60) */ + +#define TM_TO_TIMESTAMP(t, ts) \ + (ts).Year = (t)->tm_year + 1900; /* year - 1900 */ \ + (ts).Month = (t)->tm_mon + 1; /* month of year (0 - 11) */ \ + (ts).Day = (t)->tm_mday; /* day of month (1 - 31) */ \ + (ts).Hour = (t)->tm_hour; /* hours (0 - 23) */ \ + (ts).Minute = (t)->tm_min; /* minutes (0 - 59) */ \ + (ts).Second = (t)->tm_sec; /* seconds (0 - 60) */ + +// +Kumu::Timestamp::Timestamp() : + Year(0), Month(0), Day(0), Hour(0), Minute(0), Second(0) +{ + time_t t_now = time(0); + struct tm* now = gmtime(&t_now); + TM_TO_TIMESTAMP(now, *this); +} + +// +bool +Kumu::Timestamp::operator<(const Timestamp& rhs) const +{ + struct tm lhtm, rhtm; + TIMESTAMP_TO_TM(*this, &lhtm); + TIMESTAMP_TO_TM(rhs, &rhtm); + return ( timegm(&lhtm) < timegm(&rhtm) ); +} + +// +void +Kumu::Timestamp::AddDays(i32_t days) +{ + struct tm current; + + if ( days != 0 ) + { + TIMESTAMP_TO_TM(*this, ¤t); + time_t adj_time = timegm(¤t); + adj_time += 86400 * days; + struct tm* now = gmtime(&adj_time); + TM_TO_TIMESTAMP(now, *this); + } +} + +// +void +Kumu::Timestamp::AddHours(i32_t hours) +{ + struct tm current; + + if ( hours != 0 ) + { + TIMESTAMP_TO_TM(*this, ¤t); + time_t adj_time = timegm(¤t); + adj_time += 3600 * hours; + struct tm* now = gmtime(&adj_time); + TM_TO_TIMESTAMP(now, *this); + } +} + +#endif // KM_WIN32 + + +Kumu::Timestamp::Timestamp(const Timestamp& rhs) +{ + Year = rhs.Year; + Month = rhs.Month; + Day = rhs.Day; + Hour = rhs.Hour; + Minute = rhs.Minute; + Second = rhs.Second; +} + +Kumu::Timestamp::~Timestamp() +{ +} + +// +const Kumu::Timestamp& +Kumu::Timestamp::operator=(const Timestamp& rhs) +{ + Year = rhs.Year; + Month = rhs.Month; + Day = rhs.Day; + Hour = rhs.Hour; + Minute = rhs.Minute; + Second = rhs.Second; + return *this; +} + +// +bool +Kumu::Timestamp::operator==(const Timestamp& rhs) const +{ + if ( Year == rhs.Year + && Month == rhs.Month + && Day == rhs.Day + && Hour == rhs.Hour + && Minute == rhs.Minute + && Second == rhs.Second ) + return true; + + return false; +} + +// +bool +Kumu::Timestamp::operator!=(const Timestamp& rhs) const +{ + if ( Year != rhs.Year + || Month != rhs.Month + || Day != rhs.Day + || Hour != rhs.Hour + || Minute != rhs.Minute + || Second != rhs.Second ) + return true; + + return false; +} + +// +const char* +Kumu::Timestamp::EncodeString(char* str_buf, ui32_t buf_len) const +{ + if ( buf_len < ( DateTimeLen + 1 ) ) + return 0; + + // 2004-05-01T13:20:00-00:00 + snprintf(str_buf, buf_len, + "%04hu-%02hu-%02huT%02hu:%02hu:%02hu-00:00", + Year, Month, Day, Hour, Minute, Second); + + return str_buf; +} + +// +bool +Kumu::Timestamp::HasValue() const +{ + if ( Year || Month || Day || Hour || Minute || Second ) + return true; + + return false; +} + +// +bool +Kumu::Timestamp::Unarchive(MemIOReader* Reader) +{ + assert(Reader); + if ( ! Reader->ReadUi16BE(&Year) ) return false; + if ( ! Reader->ReadRaw(&Month, 6) ) return false; + return true; +} + +// +bool +Kumu::Timestamp::Archive(MemIOWriter* Writer) const +{ + assert(Writer); + if ( ! Writer->WriteUi16BE(Year) ) return false; + if ( ! Writer->WriteRaw(&Month, 6) ) return false; + return true; +} + +#if 0 +// +bool +Kumu::UnarchiveString(MemIOReader* Reader, std::string&) +{ + assert(Reader); + ui32_t str_length; + if ( ! Reader->ReadUi32BE(&str_length) ) return false; + assign((const char*)Reader->CurrentData(), str_length); + if ( ! Reader->SkipOffset(str_length) ) return false; + return true; +} + +// +bool +Kumu::String::Archive(MemIOWriter* Writer) const +{ + assert(Writer); + if ( ! Writer->WriteUi32BE(length()) ) return false; + if ( ! Writer->WriteRaw((const byte_t*)c_str(), length()) ) return false; + + return true; +} +#endif + +//------------------------------------------------------------------------------------------ + +Kumu::MemIOWriter::MemIOWriter(ByteString* Buf) + : m_p(0), m_capacity(0), m_size(0) +{ + m_p = Buf->Data(); + m_capacity = Buf->Capacity(); + assert(m_p); assert(m_capacity); +} + +bool +Kumu::MemIOWriter:: WriteBER(ui64_t i, ui32_t ber_len) +{ + if ( ( m_size + ber_len ) > m_capacity ) + return false; + + if ( ! write_BER(m_p + m_size, i, ber_len) ) + return false; + + m_size += ber_len; + return true; +} + + +Kumu::MemIOReader::MemIOReader(const ByteString* Buf) + : m_p(0), m_capacity(0), m_size(0) +{ + m_p = Buf->RoData(); + m_capacity = Buf->Capacity(); + assert(m_p); assert(m_capacity); +} + +bool +Kumu::MemIOReader::ReadBER(ui64_t* i, ui32_t* ber_len) +{ + if ( i == 0 || ber_len == 0 ) return false; + + if ( ( *ber_len = BER_length(m_p + m_size) ) == 0 ) + return false; + + if ( ( m_size + *ber_len ) > m_capacity ) + return false; + + if ( ! read_BER(m_p + m_size, i) ) + return false; + + m_size += *ber_len; + return true; +} + +//------------------------------------------------------------------------------------------ + +Kumu::ByteString::ByteString() : m_Data(0), m_Capacity(0), m_Length(0) {} + +Kumu::ByteString::ByteString(ui32_t cap) : m_Data(0), m_Capacity(0), m_Length(0) +{ + Capacity(cap); +} + +Kumu::ByteString::~ByteString() +{ + if ( m_Data != 0 ) + free(m_Data); +} + + +// copy the given data into the ByteString, set Length value. +// Returns error if the ByteString is too small. +Kumu::Result_t +Kumu::ByteString::Set(const byte_t* buf, ui32_t buf_len) +{ + if ( m_Capacity < buf_len ) + return RESULT_ALLOC; + + memcpy(m_Data, buf, buf_len); + m_Length = buf_len; + return RESULT_OK; +} + + +// Sets the size of the internally allocate buffer. +// Resets content length to zero. +Kumu::Result_t +Kumu::ByteString::Capacity(ui32_t cap_size) +{ + if ( m_Capacity < cap_size ) + { + if ( m_Data != 0 ) + free(m_Data); + + m_Data = (byte_t*)malloc(cap_size); + + if ( m_Data == 0 ) + return RESULT_ALLOC; + + m_Capacity = cap_size; + m_Length = 0; + } + + return RESULT_OK; +} + +// +Kumu::Result_t +Kumu::ByteString::Append(const ByteString& Buf) +{ + Result_t result = RESULT_OK; + ui32_t diff = m_Capacity - m_Length; + + if ( diff < Buf.Length() ) + result = Capacity(m_Capacity + Buf.Length()); + + if ( KM_SUCCESS(result) ) + { + memcpy(m_Data + m_Length, Buf.RoData(), Buf.Length()); + m_Length += Buf.Length(); + } + + return result; +} + +// +Kumu::Result_t +Kumu::ByteString::Append(const byte_t* buf, ui32_t buf_len) +{ + Result_t result = RESULT_OK; + ui32_t diff = m_Capacity - m_Length; + + if ( diff < buf_len ) + result = Capacity(m_Capacity + buf_len); + + if ( KM_SUCCESS(result) ) + { + memcpy(m_Data + m_Length, buf, buf_len); + m_Length += buf_len; + } + + return result; +} + + +// +// end KM_util.cpp +// diff --git a/src/KM_util.h b/src/KM_util.h new file mode 100755 index 0000000..a27296b --- /dev/null +++ b/src/KM_util.h @@ -0,0 +1,392 @@ +/* +Copyright (c) 2005-2006, 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 KM_util.h + \version $Id$ + \brief Utility functions + */ + +#ifndef _KM_UTIL_H_ +#define _KM_UTIL_H_ + +#include <KM_memio.h> +#include <KM_error.h> +#include <string.h> +#include <string> + +namespace Kumu +{ + + template <class T, int SIZE = 16> + class IntPrinter : public std::string + { + protected: + IntPrinter(); + char m_strbuf[SIZE]; + + public: + inline const char* c_str() { return m_strbuf; } + + IntPrinter(const char* format, T value) { + snprintf(m_strbuf, SIZE, format, value); + } + }; + + struct i8Printer : public IntPrinter<i8_t> { + i8Printer(i8_t value) : IntPrinter<i8_t>("%hd", value) {} + }; + + struct ui8Printer : public IntPrinter<ui8_t> { + ui8Printer(ui8_t value) : IntPrinter<ui8_t>("%hu", value) {} + }; + + struct i16Printer : public IntPrinter<i16_t> { + i16Printer(i16_t value) : IntPrinter<i16_t>("%hd", value) {} + }; + + struct ui16Printer : public IntPrinter<ui16_t> { + ui16Printer(ui16_t value) : IntPrinter<ui16_t>("%hu", value) {} + }; + + struct i32Printer : public IntPrinter<i32_t> { + i32Printer(i32_t value) : IntPrinter<i32_t>("%d", value) {} + }; + + struct ui32Printer : public IntPrinter<ui32_t> { + ui32Printer(ui32_t value) : IntPrinter<ui32_t>("%u", value) {} + }; + +#ifdef KM_WIN32 + struct i64Printer : public IntPrinter<i64_t, 32> { + i64Printer(i64_t value) : IntPrinter<i64_t, 32>("%I64d", value) {} + }; + + struct ui64Printer : public IntPrinter<ui64_t, 32> { + ui64Printer(ui64_t value) : IntPrinter<ui64_t, 32>("%I64u", value) {} + }; +#else + struct i64Printer : public IntPrinter<i64_t, 32> { + i64Printer(i64_t value) : IntPrinter<i64_t, 32>("%qd", value) {} + }; + + struct ui64Printer : public IntPrinter<ui64_t, 32> { + ui64Printer(ui64_t value) : IntPrinter<ui64_t, 32>("%qu", value) {} + }; +#endif + + // Convert NULL-terminated UTF-8 hexadecimal string to binary, returns 0 if + // the binary buffer was large enough to hold the result. The output parameter + // 'char_count' will contain the length of the converted string. If the output + // buffer is too small or any of the pointer arguments are NULL, the subroutine + // will return -1 and set 'char_count' to the required buffer size. No data will + // be written to 'buf' if the subroutine fails. + i32_t hex2bin(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* char_count); + + // Convert a binary string to NULL-terminated UTF-8 hexadecimal, returns the buffer + // if the binary buffer was large enough to hold the result. If the output buffer + // is too small or any of the pointer arguments are NULL, the subroutine will + // return 0. + // + const char* bin2hex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len); + + const char* bin2UUIDhex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len); + + // same as above for base64 text + i32_t base64decode(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* char_count); + const char* base64encode(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len); + + // returns the length of a Base64 encoding of a buffer of the given length + inline ui32_t base64_encode_length(ui32_t length) { + while ( ( length % 3 ) != 0 ) + length++; + + return ( length / 3 ) * 4; + } + + // print buffer contents to a stream as hexadecimal values in numbered + // rows of 16-bytes each. + // + void hexdump(const byte_t* buf, ui32_t dump_len, FILE* stream = 0); + + // Return the length in bytes of a BER encoded value + inline ui32_t BER_length(const byte_t* buf) + { + if ( buf == 0 || (*buf & 0xf0) != 0x80 ) + return 0; + + return (*buf & 0x0f) + 1; + } + + // read a BER value + bool read_BER(const byte_t* buf, ui64_t* val); + + // decode a ber value and compare it to a test value + bool read_test_BER(byte_t **buf, ui64_t test_value); + + // create BER encoding of integer value + bool write_BER(byte_t* buf, ui64_t val, ui32_t ber_len = 0); + + //---------------------------------------------------------------- + // + + class IArchive + { + public: + virtual ~IArchive(){} + virtual bool HasValue() const = 0; + virtual bool Archive(MemIOWriter* Writer) const = 0; + virtual bool Unarchive(MemIOReader* Reader) = 0; + }; + + + // + // the base of all identifier classes + template <ui32_t SIZE> + class Identifier : public IArchive + { + protected: + bool m_HasValue; + byte_t m_Value[SIZE]; + + public: + Identifier() : m_HasValue(false) { memset(m_Value, 0, SIZE); } + Identifier(const byte_t* value) : m_HasValue(true) { memcpy(m_Value, value, SIZE); } + Identifier(const Identifier& rhs) : m_HasValue(true) { memcpy(m_Value, rhs.m_Value, SIZE); } + virtual ~Identifier() {} + + const Identifier& operator=(const Identifier& rhs) { + m_HasValue = true; + memcpy(m_Value, rhs.m_Value, SIZE); + return *this; + } + + inline void Set(const byte_t* value) { m_HasValue = true; memcpy(m_Value, value, SIZE); } + inline const byte_t* Value() const { return m_Value; } + inline ui32_t Size() const { return SIZE; } + + inline bool operator<(const Identifier& rhs) const + { + ui32_t test_size = xmin(rhs.Size(), SIZE); + for ( ui32_t i = 0; i < test_size; i++ ) + { + if ( m_Value[i] != rhs.m_Value[i] ) + return m_Value[i] < rhs.m_Value[i]; + } + + return false; + } + + inline bool operator==(const Identifier& rhs) const + { + if ( rhs.Size() != SIZE ) return false; + return ( memcmp(m_Value, rhs.m_Value, SIZE) == 0 ); + } + + inline bool operator!=(const Identifier& rhs) const + { + if ( rhs.Size() != SIZE ) return true; + return ( memcmp(m_Value, rhs.m_Value, SIZE) != 0 ); + } + + inline bool DecodeHex(const char* str) + { + ui32_t char_count; + if ( hex2bin(str, m_Value, SIZE, &char_count) != 0 ) + return false; + + m_HasValue = true; + return true; + } + + inline const char* EncodeHex(char* buf, ui32_t buf_len) const + { + return bin2hex(m_Value, SIZE, buf, buf_len); + } + + inline const char* EncodeString(char* str_buf, ui32_t buf_len) const { + return EncodeHex(str_buf, buf_len); + } + + inline bool DecodeBase64(const char* str) + { + ui32_t char_count; + if ( base64decode(str, m_Value, SIZE, &char_count) != 0 ) + return false; + + m_HasValue = true; + return true; + } + + inline const char* EncodeBase64(char* buf, ui32_t buf_len) const + { + return base64encode(m_Value, SIZE, buf, buf_len); + } + + inline virtual bool HasValue() const { return m_HasValue; } + + inline virtual bool Unarchive(Kumu::MemIOReader* Reader) { + if ( ! Reader->ReadRaw(m_Value, SIZE) ) return false; + m_HasValue = true; + return true; + } + + inline virtual bool Archive(Kumu::MemIOWriter* Writer) const { + return Writer->WriteRaw(m_Value, SIZE); + } + }; + + + // UUID + // + const ui32_t UUID_Length = 16; + class UUID : public Identifier<UUID_Length> + { + public: + UUID() {} + UUID(const byte_t* value) : Identifier<UUID_Length>(value) {} + UUID(const UUID& rhs) : Identifier<UUID_Length>(rhs) {} + virtual ~UUID() {} + + inline const char* EncodeHex(char* buf, ui32_t buf_len) const { + return bin2UUIDhex(m_Value, Size(), buf, buf_len); + } + }; + + void GenRandomUUID(byte_t* buf); + void GenRandomValue(UUID&); + + // a self-wiping key container + // + const ui32_t SymmetricKey_Length = 16; + const byte_t NilKey[SymmetricKey_Length] = { + 0xfa, 0xce, 0xfa, 0xce, 0xfa, 0xce, 0xfa, 0xce, + 0xfa, 0xce, 0xfa, 0xce, 0xfa, 0xce, 0xfa, 0xce + }; + + class SymmetricKey : public Identifier<SymmetricKey_Length> + { + public: + SymmetricKey() {} + SymmetricKey(const byte_t* value) : Identifier<SymmetricKey_Length>(value) {} + SymmetricKey(const UUID& rhs) : Identifier<SymmetricKey_Length>(rhs) {} + virtual ~SymmetricKey() { memcpy(m_Value, NilKey, 16); m_HasValue = false; } + }; + + void GenRandomValue(SymmetricKey&); + + // + // 2004-05-01T13:20:00-00:00 + const ui32_t DateTimeLen = 25; // the number of chars in the xs:dateTime format (sans milliseconds) + + // UTC time+date representation + class Timestamp : public IArchive + { + public: + ui16_t Year; + ui8_t Month; + ui8_t Day; + ui8_t Hour; + ui8_t Minute; + ui8_t Second; + + Timestamp(); + Timestamp(const Timestamp& rhs); + Timestamp(const char* datestr); + virtual ~Timestamp(); + + const Timestamp& operator=(const Timestamp& rhs); + bool operator<(const Timestamp& rhs) const; + bool operator==(const Timestamp& rhs) const; + bool operator!=(const Timestamp& rhs) const; + + // Write the timestamp value to the given buffer in the form 2004-05-01T13:20:00-00:00 + // returns 0 if the buffer is smaller than DateTimeLen + const char* EncodeString(char* str_buf, ui32_t buf_len) const; + + // decode and set value from string formatted by EncodeString + Result_t SetFromString(const char* datestr); + + // add the given number of days or hours to the timestamp value. Values less than zero + // will cause the value to decrease + void AddDays(i32_t); + void AddHours(i32_t); + + // Read and write the timestamp value as a byte string + virtual bool HasValue() const; + virtual bool Archive(MemIOWriter* Writer) const; + virtual bool Unarchive(MemIOReader* Reader); + }; + + // + class ByteString + { + KM_NO_COPY_CONSTRUCT(ByteString); + + protected: + byte_t* m_Data; // pointer to memory area containing frame data + ui32_t m_Capacity; // size of memory area pointed to by m_Data + ui32_t m_Length; // length of byte string in memory area pointed to by m_Data + + public: + ByteString(); + ByteString(ui32_t cap); + virtual ~ByteString(); + + // Sets the size of the internally allocated buffer. + // Resets content Size to zero. + Result_t Capacity(ui32_t cap); + + Result_t Append(const ByteString&); + Result_t Append(const byte_t* buf, ui32_t buf_len); + + // returns the size of the buffer + inline ui32_t Capacity() const { return m_Capacity; } + + // returns a const pointer to the essence data + inline const byte_t* RoData() const { return m_Data; } + + // returns a non-const pointer to the essence data + inline byte_t* Data() { return m_Data; } + + // set the length of the buffer's contents + inline ui32_t Length(ui32_t l) { return m_Length = l; } + + // returns the length of the buffer's contents + inline ui32_t Length() const { return m_Length; } + + // copy the given data into the ByteString, set Length value. + // Returns error if the ByteString is too small. + Result_t Set(const byte_t* buf, ui32_t buf_len); + }; + +} // namespace Kumu + + +#endif // _KM_UTIL_H_ + +// +// end KM_util.h +// diff --git a/src/MPEG.cpp b/src/MPEG.cpp index 0f60a8f..0c4e49c 100755 --- a/src/MPEG.cpp +++ b/src/MPEG.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2005, John Hurst +Copyright (c) 2005-2006, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without @@ -30,6 +30,8 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include <MPEG.h> +#include <KM_log.h> +using Kumu::DefaultLogSink; // walk a buffer stopping at the end of the buffer or the end of a VES // start code '00 00 01'. If successful, returns address of first byte @@ -103,9 +105,9 @@ public: h__StreamState() : m_State(ST_IDLE) {} ~h__StreamState() {} - void Goto_START_HEADER() { m_State = ST_START_HEADER; } - void Goto_IN_HEADER() { m_State = ST_IN_HEADER; } - void Goto_IDLE() { m_State = ST_IDLE; } + void Goto_START_HEADER() { m_State = ST_START_HEADER; } + void Goto_IN_HEADER() { m_State = ST_IN_HEADER; } + void Goto_IDLE() { m_State = ST_IDLE; } bool Test_IDLE() { return m_State == ST_IDLE; } bool Test_START_HEADER() { return m_State == ST_START_HEADER; } bool Test_IN_HEADER() { return m_State == ST_IN_HEADER; } @@ -115,7 +117,7 @@ public: ASDCP::MPEG2::VESParser::VESParser() : - m_Delegate(0), m_HBufLen(0), m_ZeroCount(0), m_Partial(false) + m_Delegate(0), m_HBufLen(0), m_ZeroCount(0) { m_State = new h__StreamState; } @@ -139,7 +141,6 @@ ASDCP::MPEG2::VESParser::Reset() m_State->Goto_IDLE(); m_HBufLen = 0; m_ZeroCount = 0; - m_Partial = false; } // @@ -149,17 +150,18 @@ ASDCP::MPEG2::VESParser::Parse(const byte_t* buf, ui32_t buf_len) ASDCP_TEST_NULL(buf); ASDCP_TEST_NULL(m_Delegate); - Result_t result; - const byte_t* end_p = buf + buf_len; - const byte_t* run_pos = buf; // track runs of uninteresting data as a position and count - ui32_t run_len = 0; + Result_t result = RESULT_OK; + register const byte_t* end_p = buf + buf_len; + register const byte_t* run_pos = buf; // track runs of uninteresting data using a position and count + register ui32_t run_len = 0; // search for MPEG2 headers // copy interesting data to a buffer and pass to delegate for processing - for ( const byte_t* p = buf; p < end_p; p++ ) + for ( register const byte_t* p = buf; p < end_p; p++ ) { if ( m_State->Test_IN_HEADER() ) { + assert(run_len==0); m_HBuf[m_HBufLen++] = *p; assert(m_HBufLen < VESHeaderBufSize); } @@ -170,8 +172,44 @@ ASDCP::MPEG2::VESParser::Parse(const byte_t* buf, ui32_t buf_len) if ( m_State->Test_START_HEADER() ) // *p is a start code { - // Do we already have a header? We need to flush it... - if ( m_HBufLen > 0) + if ( m_HBufLen == 0) // not already collecting a header + { + m_HBuf[0] = m_HBuf[1] = 0; m_HBuf[2] = 1; m_HBuf[3] = *p; + + // is this one we want? + if ( *p == PIC_START || *p == SEQ_START || *p == EXT_START || *p == GOP_START ) + { + m_HBufLen = 4; + m_State->Goto_IN_HEADER(); + + switch ( run_len ) + { + case 1: // we suppressed writing 001 when exiting from the last call + case 4: // we have exactly 001x + break; + case 2: // we have 1x + case 3: // we have 01x + m_Delegate->Data(this, run_pos, (run_len == 2 ? -2 : -1)); + break; + + default: + m_Delegate->Data(this, run_pos, run_len - 4); + } + + run_len = 0; + } + else + { + m_State->Goto_IDLE(); + + if ( run_len == 1 ) // did we suppress writing 001 when exiting from the last call? + { + m_Delegate->Data(this, m_HBuf, 4); + run_len = 0; + } + } + } + else // currently collecting a header, requires a flush before handling { m_HBufLen -= 3; // remove the current partial start code @@ -189,48 +227,38 @@ ASDCP::MPEG2::VESParser::Parse(const byte_t* buf, ui32_t buf_len) result = RESULT_RAW_FORMAT; } - // the next run starts with the start code that got us here - run_len = 4; - run_pos = p-3; - m_HBufLen = 0; - // Parser handlers return RESULT_FALSE to teriminate without error if ( result != RESULT_OK ) { m_State->Goto_IDLE(); return result; } - } - - // all headers start with this same start code: 00 00 01 xx - m_HBuf[0] = m_HBuf[1] = 0; m_HBuf[2] = 1; m_HBuf[3] = *p; + + m_HBuf[0] = m_HBuf[1] = 0; m_HBuf[2] = 1; m_HBuf[3] = *p; // 001x + run_len = 0; - // is this a header we want? - if ( *p == PIC_START || *p == SEQ_START || *p == EXT_START || *p == GOP_START ) - { - // we're starting a new header, flush the current run - if ( run_len > 4 ) + // is this a header we want? + if ( *p == PIC_START || *p == SEQ_START || *p == EXT_START || *p == GOP_START ) { - m_Delegate->Data(this, run_pos, run_len - 4); - run_len = 0; + m_HBufLen = 4; + m_State->Goto_IN_HEADER(); } + else + { + m_HBufLen = 0; + m_State->Goto_IDLE(); - m_Partial = false; - m_HBufLen = 4; - m_State->Goto_IN_HEADER(); - } - else - { - if ( *p == FIRST_SLICE ) - result = m_Delegate->Slice(this); + if ( *p >= FIRST_SLICE && *p <= LAST_SLICE ) + { + result = m_Delegate->Slice(this, *p); - if ( m_Partial ) - { - m_Partial = false; - m_Delegate->Data(this, m_HBuf, 3); + if ( result != RESULT_OK ) + return result; + } + + m_Delegate->Data(this, m_HBuf, 4); + run_pos = p+1; } - - m_State->Goto_IDLE(); } } else if ( *p == 0 ) @@ -248,9 +276,9 @@ ASDCP::MPEG2::VESParser::Parse(const byte_t* buf, ui32_t buf_len) if ( run_len > 0 ) { - if ( m_State->Test_START_HEADER() ) + if ( m_State->Test_START_HEADER() && run_len != 0 ) { - m_Partial = true; // 'partial' means we have a partial header in progress + assert(run_len > 2); run_len -= 3; } @@ -29,10 +29,11 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \brief MPEG2 VES parser interface */ -#ifndef _ASDCP_MPEG_H_ -#define _ASDCP_MPEG_H_ +#ifndef _MPEG_H_ +#define _MPEG_H_ -#include <AS_DCP_system.h> +#include <KM_platform.h> +#include "AS_DCP.h" #include <stdio.h> #include <assert.h> @@ -48,6 +49,7 @@ namespace ASDCP EXT_START = 0xb5, GOP_START = 0xb8, FIRST_SLICE = 0x01, + LAST_SLICE = 0xaf, INVALID = 0xff }; @@ -90,7 +92,7 @@ namespace ASDCP class VESParser { class h__StreamState; - mem_ptr<h__StreamState> m_State; + Kumu::mem_ptr<h__StreamState> m_State; VESParserDelegate* m_Delegate; ui32_t m_HBufLen; // temp space for partial header contents @@ -106,7 +108,7 @@ namespace ASDCP void SetDelegate(VESParserDelegate*); // you must call this before Parse() Result_t Parse(const byte_t*, ui32_t); // call repeatedly - void Reset(); // resets the internal state machine and counters + void Reset(); // resets the internal state machine and counters, return to the top of the file }; // Parser Event Delegate Interface @@ -114,7 +116,7 @@ namespace ASDCP // Create a concrete subclass and give it to the parser by calling SetDelegate(). // The respective method will be called when a header of the named type is found. // Handler methods should return RESULT_OK to continue processing or RESULT_FALSE - // to stop without error. + // to terminate parsing without signaling an error. // class VESParserDelegate { @@ -122,17 +124,20 @@ namespace ASDCP virtual ~VESParserDelegate() {} // header handlers - virtual Result_t Picture(VESParser*, const byte_t*, ui32_t) = 0; + virtual Result_t Picture(VESParser* Caller, const byte_t* header_buf, ui32_t header_len) = 0; virtual Result_t Extension(VESParser*, const byte_t*, ui32_t) = 0; virtual Result_t Sequence(VESParser*, const byte_t*, ui32_t) = 0; virtual Result_t GOP(VESParser*, const byte_t*, ui32_t) = 0; // this is not a header handler, it is a signal that actual picture data // has started. All Slice data is reported via the Data() method. - virtual Result_t Slice(VESParser*) = 0; + virtual Result_t Slice(VESParser*, byte_t slice_id) = 0; // Any data not given to the header handlers above is reported here - virtual Result_t Data(VESParser*, const byte_t*, ui32_t) = 0; + // This method may be called with a value of -1 or -2. This will happen + // when processing a start code that has one or two leading zeros + // in the preceding buffer + virtual Result_t Data(VESParser*, const byte_t*, i32_t) = 0; }; @@ -141,7 +146,9 @@ namespace ASDCP // // For use within parser delegate methods. The constructor expects a pointer to a buffer // containing two zero bytes, a one byte, a start code and some number of header bytes. - // They are not documented further as they should be self-explanatory. + // They are not documented further as it is hoped that they are self-explanatory. + + // namespace Accessor { // decoding tables @@ -169,7 +176,7 @@ namespace ASDCP }; // - class SequenceEx + class SequenceEx // tension { const byte_t* m_p; ASDCP_NO_COPY_CONSTRUCT(SequenceEx); @@ -230,7 +237,7 @@ namespace ASDCP } // namespace ASDCP -#endif // ASDCP_MPEG_H_ +#endif // _MPEG_H_ // // end MPEG.h diff --git a/src/MPEG2_Parser.cpp b/src/MPEG2_Parser.cpp index f6e0089..af7396f 100755 --- a/src/MPEG2_Parser.cpp +++ b/src/MPEG2_Parser.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2004, John Hurst +Copyright (c) 2004-2006, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without @@ -29,14 +29,17 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \brief AS-DCP library, MPEG2 raw essence reader implementation */ -#include <FileIO.h> +#include <KM_fileio.h> #include <MPEG.h> +#include <KM_log.h> +using Kumu::DefaultLogSink; + using namespace ASDCP; using namespace ASDCP::MPEG2; // data will be read from a VES file in chunks of this size -const ui32_t VESReadSize = 4096; +const ui32_t VESReadSize = 4 * Kumu::Kilobyte; //------------------------------------------------------------------------------------------ @@ -59,11 +62,11 @@ class h__ParserState ASDCP_NO_COPY_CONSTRUCT(h__ParserState); public: - h__ParserState() : m_State(::ST_INIT) {} + h__ParserState() : m_State(ST_INIT) {} ~h__ParserState() {} - bool Test_SLICE() { return m_State == ST_SLICE; } - void Reset() { m_State = ST_INIT; } + inline bool Test_SLICE() { return m_State == ST_SLICE; } + inline void Reset() { m_State = ST_INIT; } // inline Result_t Goto_SEQ() @@ -75,6 +78,7 @@ class h__ParserState return RESULT_OK; } + DefaultLogSink().Error("SEQ follows 0x%02x\n", m_State); return RESULT_STATE; } @@ -90,6 +94,7 @@ class h__ParserState return RESULT_OK; } + DefaultLogSink().Error("Slice follows 0x%02x\n", m_State); return RESULT_STATE; } @@ -107,23 +112,25 @@ class h__ParserState return RESULT_OK; } + DefaultLogSink().Error("PIC follows 0x%02x\n", m_State); return RESULT_STATE; } // inline Result_t Goto_GOP() - { - switch ( m_State ) - { - case ST_EXT: - case ST_SEQ: - m_State = ST_GOP; - return RESULT_OK; - } - - return RESULT_STATE; - } + { + switch ( m_State ) + { + case ST_EXT: + case ST_SEQ: + m_State = ST_GOP; + return RESULT_OK; + } + + DefaultLogSink().Error("GOP follows 0x%02x\n", m_State); + return RESULT_STATE; + } // inline Result_t Goto_EXT() @@ -138,6 +145,7 @@ class h__ParserState return RESULT_OK; } + DefaultLogSink().Error("EXT follows 0x%02x\n", m_State); return RESULT_STATE; } }; @@ -216,8 +224,8 @@ public: Result_t GOP(VESParser*, const byte_t*, ui32_t) { return RESULT_FALSE; } Result_t Picture(VESParser*, const byte_t*, ui32_t) { return RESULT_FALSE; } - Result_t Slice(VESParser*) { return RESULT_FALSE; } - Result_t Data(VESParser*, const byte_t*, ui32_t) { return RESULT_OK; } + Result_t Slice(VESParser*, byte_t) { return RESULT_FALSE; } + Result_t Data(VESParser*, const byte_t*, i32_t) { return RESULT_OK; } }; @@ -258,7 +266,7 @@ public: m_PlaintextOffset = 0; m_FrameType = FRAME_U; m_State.Reset(); - } + } Result_t Sequence(VESParser*, const byte_t* b, ui32_t s) { @@ -287,10 +295,15 @@ public: return m_State.Goto_PIC(); } - Result_t Slice(VESParser*) + Result_t Slice(VESParser*, byte_t slice_id) { - m_PlaintextOffset = m_FrameSize; - return m_State.Goto_SLICE(); + if ( slice_id == FIRST_SLICE ) + { + m_PlaintextOffset = m_FrameSize; + return m_State.Goto_SLICE(); + } + + return m_State.Test_SLICE() ? RESULT_OK : RESULT_FAIL; } Result_t Extension(VESParser*, const byte_t* b, ui32_t s) @@ -308,7 +321,7 @@ public: return m_State.Goto_GOP(); } - Result_t Data(VESParser*, const byte_t* b, ui32_t s) + Result_t Data(VESParser*, const byte_t* b, i32_t s) { m_FrameSize += s; return RESULT_OK; @@ -324,13 +337,12 @@ public: // - any frame that begins with a picture header is either an I, B or P frame // and is assumed to contain a complete picture header and picture data - class ASDCP::MPEG2::Parser::h__Parser { StreamParams m_ParamsDelegate; FrameParser m_ParserDelegate; VESParser m_Parser; - FileReader m_FileReader; + Kumu::FileReader m_FileReader; ui32_t m_FrameNumber; bool m_EOF; ASDCP::MPEG2::FrameBuffer m_TmpBuffer; @@ -387,9 +399,9 @@ ASDCP::MPEG2::Parser::h__Parser::OpenRead(const char* filename) // Since no one complained and that's the easiest thing to implement, // I have left it that way. Let me know if you want to be able to // locate the first GOP in the stream. - if ( p[0] != 0 || p[1] != 0 || p[2] != 1 ) + if ( p[0] != 0 || p[1] != 0 || p[2] != 1 || ! ( p[3] == SEQ_START || p[3] == PIC_START ) ) { - DefaultLogSink().Error("Frame buffer does not begin with a start code.\n"); + DefaultLogSink().Error("Frame buffer does not begin with a PIC or SEQ start code.\n"); return RESULT_RAW_FORMAT; } @@ -412,8 +424,8 @@ ASDCP::MPEG2::Parser::h__Parser::OpenRead(const char* filename) m_FileReader.Close(); } - return result; -} + return result;} + // // @@ -434,6 +446,7 @@ ASDCP::MPEG2::Parser::h__Parser::ReadFrame(FrameBuffer& FB) // the input file is exhausted. The partial next frame is cached for the // next call. m_ParserDelegate.Reset(); + m_Parser.Reset(); if ( m_TmpBuffer.Size() > 0 ) { @@ -443,7 +456,7 @@ ASDCP::MPEG2::Parser::h__Parser::ReadFrame(FrameBuffer& FB) m_TmpBuffer.Size(0); } - while ( ! m_ParserDelegate.m_CompletePicture && ASDCP_SUCCESS(result) ) + while ( ! m_ParserDelegate.m_CompletePicture && result == RESULT_OK ) { if ( FB.Capacity() < ( write_offset + VESReadSize ) ) { @@ -454,7 +467,7 @@ ASDCP::MPEG2::Parser::h__Parser::ReadFrame(FrameBuffer& FB) result = m_FileReader.Read(FB.Data() + write_offset, VESReadSize, &read_count); - if ( result == RESULT_ENDOFFILE ) + if ( result == RESULT_ENDOFFILE || read_count == 0 ) { m_EOF = true; @@ -471,6 +484,7 @@ ASDCP::MPEG2::Parser::h__Parser::ReadFrame(FrameBuffer& FB) if ( m_EOF ) break; } + assert(m_ParserDelegate.m_FrameSize <= write_offset); if ( ASDCP_SUCCESS(result) && m_ParserDelegate.m_FrameSize < write_offset ) @@ -478,21 +492,20 @@ ASDCP::MPEG2::Parser::h__Parser::ReadFrame(FrameBuffer& FB) assert(m_TmpBuffer.Size() == 0); ui32_t diff = write_offset - m_ParserDelegate.m_FrameSize; assert(diff <= m_TmpBuffer.Capacity()); + memcpy(m_TmpBuffer.Data(), FB.RoData() + m_ParserDelegate.m_FrameSize, diff); m_TmpBuffer.Size(diff); } -#ifndef NDEBUG if ( ASDCP_SUCCESS(result) ) { const byte_t* p = FB.RoData(); - if ( p[0] != 0 || p[1] != 0 || p[2] != 1 ) - { - DefaultLogSink().Error("Parsed frame buffer does not begin with a start code.\n"); - return RESULT_RAW_FORMAT; - } + if ( p[0] != 0 || p[1] != 0 || p[2] != 1 || ! ( p[3] == SEQ_START || p[3] == PIC_START ) ) + { + DefaultLogSink().Error("Frame buffer does not begin with a PIC or SEQ start code.\n"); + return RESULT_RAW_FORMAT; + } } -#endif if ( ASDCP_SUCCESS(result) ) { @@ -573,5 +586,5 @@ ASDCP::MPEG2::Parser::FillVideoDescriptor(VideoDescriptor& VDesc) const } // -// end AS_DCP_MPEG2_Parser.cpp +// end MPEG2_Parser.cpp // diff --git a/src/MXF.cpp b/src/MXF.cpp index ed16cab..ab30389 100755 --- a/src/MXF.cpp +++ b/src/MXF.cpp @@ -30,8 +30,8 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "MXF.h" -#include "hex_utils.h" - +#include <KM_log.h> +using Kumu::DefaultLogSink; //------------------------------------------------------------------------------------------ // @@ -40,12 +40,12 @@ const ui32_t kl_length = ASDCP::SMPTE_UL_LENGTH + ASDCP::MXF_BER_LENGTH; // ASDCP::Result_t -ASDCP::MXF::SeekToRIP(const ASDCP::FileReader& Reader) +ASDCP::MXF::SeekToRIP(const Kumu::FileReader& Reader) { - ASDCP::fpos_t end_pos; + Kumu::fpos_t end_pos; // go to the end - 4 bytes - Result_t result = Reader.Seek(0, ASDCP::SP_END); + Result_t result = Reader.Seek(0, Kumu::SP_END); if ( ASDCP_SUCCESS(result) ) result = Reader.Tell(&end_pos); @@ -72,7 +72,7 @@ ASDCP::MXF::SeekToRIP(const ASDCP::FileReader& Reader) if ( ASDCP_SUCCESS(result) ) { - rip_size = ASDCP_i32_BE(cp2i<ui32_t>(intbuf)); + rip_size = KM_i32_BE(Kumu::cp2i<ui32_t>(intbuf)); if ( rip_size > end_pos ) // RIP can't be bigger than the file return RESULT_FAIL; @@ -87,14 +87,14 @@ ASDCP::MXF::SeekToRIP(const ASDCP::FileReader& Reader) // ASDCP::Result_t -ASDCP::MXF::RIP::InitFromFile(const ASDCP::FileReader& Reader) +ASDCP::MXF::RIP::InitFromFile(const Kumu::FileReader& Reader) { Result_t result = KLVFilePacket::InitFromFile(Reader, Dict::ul(MDD_RandomIndexMetadata)); if ( ASDCP_SUCCESS(result) ) { - MemIOReader MemRDR(m_ValueStart, m_ValueLength - 4); - result = PairArray.Unarchive(MemRDR); + Kumu::MemIOReader MemRDR(m_ValueStart, m_ValueLength - 4); + result = PairArray.Unarchive(&MemRDR) ? RESULT_OK : RESULT_KLV_CODING; } if ( ASDCP_FAILURE(result) ) @@ -105,7 +105,7 @@ ASDCP::MXF::RIP::InitFromFile(const ASDCP::FileReader& Reader) // ASDCP::Result_t -ASDCP::MXF::RIP::WriteToFile(ASDCP::FileWriter& Writer) +ASDCP::MXF::RIP::WriteToFile(Kumu::FileWriter& Writer) { ASDCP::FrameBuffer Buffer; ui32_t RIPSize = ( PairArray.size() * (sizeof(ui32_t) + sizeof(ui64_t)) ) + 4; @@ -116,14 +116,15 @@ ASDCP::MXF::RIP::WriteToFile(ASDCP::FileWriter& Writer) if ( ASDCP_SUCCESS(result) ) { - MemIOWriter MemWRT(Buffer.Data(), Buffer.Capacity()); - result = PairArray.Archive(MemWRT); - - if ( ASDCP_SUCCESS(result) ) - MemWRT.WriteUi32BE(RIPSize + 20); + result = RESULT_KLV_CODING; - if ( ASDCP_SUCCESS(result) ) - Buffer.Size(MemWRT.Size()); + Kumu::MemIOWriter MemWRT(Buffer.Data(), Buffer.Capacity()); + if ( PairArray.Archive(&MemWRT) ) + if ( MemWRT.WriteUi32BE(RIPSize + 20) ) + { + Buffer.Size(MemWRT.Length()); + result = RESULT_OK; + } } if ( ASDCP_SUCCESS(result) ) @@ -215,14 +216,14 @@ ASDCP::MXF::Partition::AddChildObject(InterchangeObject* Object) { assert(Object); UUID TmpID; - TmpID.GenRandomValue(); + Kumu::GenRandomValue(TmpID); Object->InstanceUID = TmpID; m_PacketList->AddPacket(Object); } // ASDCP::Result_t -ASDCP::MXF::Partition::InitFromFile(const ASDCP::FileReader& Reader) +ASDCP::MXF::Partition::InitFromFile(const Kumu::FileReader& Reader) { Result_t result = KLVFilePacket::InitFromFile(Reader); // test the UL @@ -230,20 +231,23 @@ ASDCP::MXF::Partition::InitFromFile(const ASDCP::FileReader& Reader) if ( ASDCP_SUCCESS(result) ) { - MemIOReader MemRDR(m_ValueStart, m_ValueLength); - result = MemRDR.ReadUi16BE(&MajorVersion); - if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi16BE(&MinorVersion); - if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi32BE(&KAGSize); - if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64BE(&ThisPartition); - if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64BE(&PreviousPartition); - if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64BE(&FooterPartition); - if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64BE(&HeaderByteCount); - if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64BE(&IndexByteCount); - if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi32BE(&IndexSID); - if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64BE(&BodyOffset); - if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi32BE(&BodySID); - if ( ASDCP_SUCCESS(result) ) result = OperationalPattern.Unarchive(MemRDR); - if ( ASDCP_SUCCESS(result) ) result = EssenceContainers.Unarchive(MemRDR); + Kumu::MemIOReader MemRDR(m_ValueStart, m_ValueLength); + result = RESULT_KLV_CODING; + + if ( MemRDR.ReadUi16BE(&MajorVersion) ) + if ( MemRDR.ReadUi16BE(&MinorVersion) ) + if ( MemRDR.ReadUi32BE(&KAGSize) ) + if ( MemRDR.ReadUi64BE(&ThisPartition) ) + if ( MemRDR.ReadUi64BE(&PreviousPartition) ) + if ( MemRDR.ReadUi64BE(&FooterPartition) ) + if ( MemRDR.ReadUi64BE(&HeaderByteCount) ) + if ( MemRDR.ReadUi64BE(&IndexByteCount) ) + if ( MemRDR.ReadUi32BE(&IndexSID) ) + if ( MemRDR.ReadUi64BE(&BodyOffset) ) + if ( MemRDR.ReadUi32BE(&BodySID) ) + if ( OperationalPattern.Unarchive(&MemRDR) ) + if ( EssenceContainers.Unarchive(&MemRDR) ) + result = RESULT_OK; } if ( ASDCP_FAILURE(result) ) @@ -254,28 +258,32 @@ ASDCP::MXF::Partition::InitFromFile(const ASDCP::FileReader& Reader) // ASDCP::Result_t -ASDCP::MXF::Partition::WriteToFile(ASDCP::FileWriter& Writer, UL& PartitionLabel) +ASDCP::MXF::Partition::WriteToFile(Kumu::FileWriter& Writer, UL& PartitionLabel) { ASDCP::FrameBuffer Buffer; Result_t result = Buffer.Capacity(1024); if ( ASDCP_SUCCESS(result) ) { - MemIOWriter MemWRT(Buffer.Data(), Buffer.Capacity()); - result = MemWRT.WriteUi16BE(MajorVersion); - if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi16BE(MinorVersion); - if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi32BE(KAGSize); - if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi64BE(ThisPartition); - if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi64BE(PreviousPartition); - if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi64BE(FooterPartition); - if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi64BE(HeaderByteCount); - if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi64BE(IndexByteCount); - if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi32BE(IndexSID); - if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi64BE(BodyOffset); - if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi32BE(BodySID); - if ( ASDCP_SUCCESS(result) ) result = OperationalPattern.Archive(MemWRT); - if ( ASDCP_SUCCESS(result) ) result = EssenceContainers.Archive(MemWRT); - if ( ASDCP_SUCCESS(result) ) Buffer.Size(MemWRT.Size()); + Kumu::MemIOWriter MemWRT(Buffer.Data(), Buffer.Capacity()); + result = RESULT_KLV_CODING; + if ( MemWRT.WriteUi16BE(MajorVersion) ) + if ( MemWRT.WriteUi16BE(MinorVersion) ) + if ( MemWRT.WriteUi32BE(KAGSize) ) + if ( MemWRT.WriteUi64BE(ThisPartition) ) + if ( MemWRT.WriteUi64BE(PreviousPartition) ) + if ( MemWRT.WriteUi64BE(FooterPartition) ) + if ( MemWRT.WriteUi64BE(HeaderByteCount) ) + if ( MemWRT.WriteUi64BE(IndexByteCount) ) + if ( MemWRT.WriteUi32BE(IndexSID) ) + if ( MemWRT.WriteUi64BE(BodyOffset) ) + if ( MemWRT.WriteUi32BE(BodySID) ) + if ( OperationalPattern.Archive(&MemWRT) ) + if ( EssenceContainers.Archive(&MemWRT) ) + { + Buffer.Size(MemWRT.Length()); + result = RESULT_OK; + } } if ( ASDCP_SUCCESS(result) ) @@ -310,7 +318,6 @@ void ASDCP::MXF::Partition::Dump(FILE* stream) { char identbuf[IdentBufferLen]; - char intbuf[IntBufferLen]; if ( stream == 0 ) stream = stderr; @@ -319,15 +326,15 @@ ASDCP::MXF::Partition::Dump(FILE* stream) fprintf(stream, " MajorVersion = %hu\n", MajorVersion); fprintf(stream, " MinorVersion = %hu\n", MinorVersion); fprintf(stream, " KAGSize = %lu\n", KAGSize); - fprintf(stream, " ThisPartition = %s\n", ui64sz(ThisPartition, intbuf)); - fprintf(stream, " PreviousPartition = %s\n", ui64sz(PreviousPartition, intbuf)); - fprintf(stream, " FooterPartition = %s\n", ui64sz(FooterPartition, intbuf)); - fprintf(stream, " HeaderByteCount = %s\n", ui64sz(HeaderByteCount, intbuf)); - fprintf(stream, " IndexByteCount = %s\n", ui64sz(IndexByteCount, intbuf)); + fprintf(stream, " ThisPartition = %s\n", ui64sz(ThisPartition, identbuf)); + fprintf(stream, " PreviousPartition = %s\n", ui64sz(PreviousPartition, identbuf)); + fprintf(stream, " FooterPartition = %s\n", ui64sz(FooterPartition, identbuf)); + fprintf(stream, " HeaderByteCount = %s\n", ui64sz(HeaderByteCount, identbuf)); + fprintf(stream, " IndexByteCount = %s\n", ui64sz(IndexByteCount, identbuf)); fprintf(stream, " IndexSID = %lu\n", IndexSID); - fprintf(stream, " BodyOffset = %s\n", ui64sz(BodyOffset, intbuf)); + fprintf(stream, " BodyOffset = %s\n", ui64sz(BodyOffset, identbuf)); fprintf(stream, " BodySID = %lu\n", BodySID); - fprintf(stream, " OperationalPattern = %s\n", OperationalPattern.ToString(identbuf)); + fprintf(stream, " OperationalPattern = %s\n", OperationalPattern.EncodeString(identbuf, IdentBufferLen)); fputs("Essence Containers:\n", stream); EssenceContainers.Dump(stream, false); fputs("==========================================================================\n", stream); @@ -372,8 +379,8 @@ ASDCP::MXF::Primer::InitFromBuffer(const byte_t* p, ui32_t l) if ( ASDCP_SUCCESS(result) ) { - MemIOReader MemRDR(m_ValueStart, m_ValueLength); - result = LocalTagEntryBatch.Unarchive(MemRDR); + Kumu::MemIOReader MemRDR(m_ValueStart, m_ValueLength); + result = LocalTagEntryBatch.Unarchive(&MemRDR) ? RESULT_OK : RESULT_KLV_CODING; } if ( ASDCP_SUCCESS(result) ) @@ -390,7 +397,7 @@ ASDCP::MXF::Primer::InitFromBuffer(const byte_t* p, ui32_t l) // ASDCP::Result_t -ASDCP::MXF::Primer::WriteToFile(ASDCP::FileWriter& Writer) +ASDCP::MXF::Primer::WriteToFile(Kumu::FileWriter& Writer) { ASDCP::FrameBuffer Buffer; Result_t result = Buffer.Capacity(128*1024); @@ -409,12 +416,12 @@ ASDCP::Result_t ASDCP::MXF::Primer::WriteToBuffer(ASDCP::FrameBuffer& Buffer) { ASDCP::FrameBuffer LocalTagBuffer; - MemIOWriter MemWRT(Buffer.Data() + kl_length, Buffer.Capacity() - kl_length); - Result_t result = LocalTagEntryBatch.Archive(MemWRT); + Kumu::MemIOWriter MemWRT(Buffer.Data() + kl_length, Buffer.Capacity() - kl_length); + Result_t result = LocalTagEntryBatch.Archive(&MemWRT) ? RESULT_OK : RESULT_KLV_CODING; if ( ASDCP_SUCCESS(result) ) { - ui32_t packet_length = MemWRT.Size(); + ui32_t packet_length = MemWRT.Length(); result = WriteKLToBuffer(Buffer, Dict::ul(MDD_Primer), packet_length); if ( ASDCP_SUCCESS(result) ) @@ -498,7 +505,7 @@ ASDCP::MXF::Primer::Dump(FILE* stream) for ( ; i != LocalTagEntryBatch.end(); i++ ) { const MDDEntry* Entry = Dict::FindUL((*i).UL.Value()); - fprintf(stream, " %s %s\n", (*i).ToString(identbuf), (Entry ? Entry->name : "Unknown")); + fprintf(stream, " %s %s\n", (*i).EncodeString(identbuf, IdentBufferLen), (Entry ? Entry->name : "Unknown")); } fputs("==========================================================================\n", stream); @@ -568,13 +575,13 @@ ASDCP::MXF::Preface::Dump(FILE* stream) stream = stderr; InterchangeObject::Dump(stream); - fprintf(stream, " %22s = %s\n", "LastModifiedDate", LastModifiedDate.ToString(identbuf)); + fprintf(stream, " %22s = %s\n", "LastModifiedDate", LastModifiedDate.EncodeString(identbuf, IdentBufferLen)); fprintf(stream, " %22s = %hu\n", "Version", Version); fprintf(stream, " %22s = %lu\n", "ObjectModelVersion", ObjectModelVersion); - fprintf(stream, " %22s = %s\n", "PrimaryPackage", PrimaryPackage.ToString(identbuf)); + fprintf(stream, " %22s = %s\n", "PrimaryPackage", PrimaryPackage.EncodeHex(identbuf, IdentBufferLen)); fprintf(stream, " %22s:\n", "Identifications"); Identifications.Dump(stream); - fprintf(stream, " %22s = %s\n", "ContentStorage", ContentStorage.ToString(identbuf)); - fprintf(stream, " %22s = %s\n", "OperationalPattern", OperationalPattern.ToString(identbuf)); + fprintf(stream, " %22s = %s\n", "ContentStorage", ContentStorage.EncodeHex(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "OperationalPattern", OperationalPattern.EncodeString(identbuf, IdentBufferLen)); fprintf(stream, " %22s:\n", "EssenceContainers"); EssenceContainers.Dump(stream); fprintf(stream, " %22s:\n", "DMSchemes"); DMSchemes.Dump(stream); } @@ -587,7 +594,7 @@ ASDCP::MXF::OPAtomHeader::~OPAtomHeader() {} // ASDCP::Result_t -ASDCP::MXF::OPAtomHeader::InitFromFile(const ASDCP::FileReader& Reader) +ASDCP::MXF::OPAtomHeader::InitFromFile(const Kumu::FileReader& Reader) { m_HasRIP = false; Result_t result = SeekToRIP(Reader); @@ -637,18 +644,16 @@ ASDCP::MXF::OPAtomHeader::InitFromFile(const ASDCP::FileReader& Reader) if ( ASDCP_SUCCESS(result) ) result = Partition::InitFromFile(Reader); // test UL and OP - Partition::Dump(); - // is it really OP-Atom? UL OPAtomUL(Dict::ul(MDD_OPAtom)); UL InteropOPAtomUL(Dict::ul(MDD_MXFInterop_OPAtom)); if ( ! ( OperationalPattern == OPAtomUL || OperationalPattern == InteropOPAtomUL ) ) { - char strbuf[IntBufferLen]; + char strbuf[IdentBufferLen]; const MDDEntry* Entry = Dict::FindUL(OperationalPattern.Value()); if ( Entry == 0 ) - DefaultLogSink().Warn("Operational pattern is not OP-Atom: %s\n", OperationalPattern.ToString(strbuf)); + DefaultLogSink().Warn("Operational pattern is not OP-Atom: %s\n", OperationalPattern.EncodeString(strbuf, IdentBufferLen)); else DefaultLogSink().Warn("Operational pattern is not OP-Atom: %s\n", Entry->name); } @@ -760,7 +765,7 @@ ASDCP::MXF::OPAtomHeader::GetSourcePackage() // ASDCP::Result_t -ASDCP::MXF::OPAtomHeader::WriteToFile(ASDCP::FileWriter& Writer, ui32_t HeaderSize) +ASDCP::MXF::OPAtomHeader::WriteToFile(Kumu::FileWriter& Writer, ui32_t HeaderSize) { if ( m_Preface == 0 ) return RESULT_STATE; @@ -808,9 +813,9 @@ ASDCP::MXF::OPAtomHeader::WriteToFile(ASDCP::FileWriter& Writer, ui32_t HeaderSi // KLV Fill if ( ASDCP_SUCCESS(result) ) { - ASDCP::fpos_t pos = Writer.Tell(); + Kumu::fpos_t pos = Writer.Tell(); - if ( pos > (ASDCP::fpos_t)HeaderByteCount ) + if ( pos > (Kumu::fpos_t)HeaderByteCount ) { char intbuf[IntBufferLen]; DefaultLogSink().Error("Header size %s exceeds specified value %lu\n", @@ -884,7 +889,7 @@ ASDCP::MXF::OPAtomIndexFooter::~OPAtomIndexFooter() {} ASDCP::Result_t -ASDCP::MXF::OPAtomIndexFooter::InitFromFile(const ASDCP::FileReader& Reader) +ASDCP::MXF::OPAtomIndexFooter::InitFromFile(const Kumu::FileReader& Reader) { Result_t result = Partition::InitFromFile(Reader); // test UL and OP @@ -936,7 +941,7 @@ ASDCP::MXF::OPAtomIndexFooter::InitFromFile(const ASDCP::FileReader& Reader) // ASDCP::Result_t -ASDCP::MXF::OPAtomIndexFooter::WriteToFile(ASDCP::FileWriter& Writer, ui64_t duration) +ASDCP::MXF::OPAtomIndexFooter::WriteToFile(Kumu::FileWriter& Writer, ui64_t duration) { ASDCP::FrameBuffer FooterBuffer; ui32_t footer_size = m_PacketList->m_List.size() * MaxIndexSegmentSize; // segment-count * max-segment-size @@ -1059,7 +1064,7 @@ ASDCP::MXF::OPAtomIndexFooter::SetIndexParamsCBR(IPrimerLookup* lookup, ui32_t s // void -ASDCP::MXF::OPAtomIndexFooter::SetIndexParamsVBR(IPrimerLookup* lookup, const Rational& Rate, fpos_t offset) +ASDCP::MXF::OPAtomIndexFooter::SetIndexParamsVBR(IPrimerLookup* lookup, const Rational& Rate, Kumu::fpos_t offset) { assert(lookup); m_Lookup = lookup; @@ -1132,7 +1137,7 @@ ASDCP::Result_t ASDCP::MXF::InterchangeObject::InitFromBuffer(const byte_t* p, ui32_t l) { ASDCP_TEST_NULL(p); - Result_t result; + Result_t result = RESULT_FALSE; if ( m_Typeinfo == 0 ) { @@ -1164,7 +1169,7 @@ ASDCP::MXF::InterchangeObject::WriteToBuffer(ASDCP::FrameBuffer& Buffer) if ( ASDCP_SUCCESS(result) ) { - ui32_t packet_length = MemWRT.Size(); + ui32_t packet_length = MemWRT.Length(); result = WriteKLToBuffer(Buffer, m_Typeinfo->ul, packet_length); if ( ASDCP_SUCCESS(result) ) @@ -1182,8 +1187,8 @@ ASDCP::MXF::InterchangeObject::Dump(FILE* stream) fputc('\n', stream); KLVPacket::Dump(stream, false); - fprintf(stream, " InstanceUID = %s\n", InstanceUID.ToString(identbuf)); - fprintf(stream, " GenerationUID = %s\n", GenerationUID.ToString(identbuf)); + fprintf(stream, " InstanceUID = %s\n", InstanceUID.EncodeHex(identbuf, IdentBufferLen)); + fprintf(stream, " GenerationUID = %s\n", GenerationUID.EncodeHex(identbuf, IdentBufferLen)); } // @@ -41,7 +41,7 @@ namespace ASDCP class InterchangeObject; // seek an open file handle to the start of the RIP KLV packet - Result_t SeekToRIP(const FileReader&); + Result_t SeekToRIP(const Kumu::FileReader&); // class RIP : public ASDCP::KLVFilePacket @@ -50,7 +50,7 @@ namespace ASDCP public: // - class Pair : public IArchive + class Pair : public Kumu::IArchive { public: ui32_t BodySID; @@ -58,33 +58,28 @@ namespace ASDCP Pair() : BodySID(0), ByteOffset(0) {} Pair(ui32_t sid, ui64_t offset) : BodySID(sid), ByteOffset(offset) {} + virtual ~Pair() {} ui32_t Size() { return sizeof(ui32_t) + sizeof(ui64_t); } - inline const char* ToString(char* str_buf) const { - char intbuf[IntBufferLen]; - snprintf(str_buf, IdentBufferLen, "%-6lu: %s", BodySID, ui64sz(ByteOffset, intbuf)); + inline const char* EncodeString(char* str_buf, ui32_t buf_len) const { + Kumu::ui64Printer offset_str(ByteOffset); + snprintf(str_buf, buf_len, "%-6lu: %s", BodySID, offset_str.c_str()); return str_buf; } - inline Result_t Unarchive(ASDCP::MemIOReader& Reader) { - Result_t result = Reader.ReadUi32BE(&BodySID); - - if ( ASDCP_SUCCESS(result) ) - result = Reader.ReadUi64BE(&ByteOffset); - - return result; + inline virtual bool Unarchive(Kumu::MemIOReader* Reader) { + if ( ! Reader->ReadUi32BE(&BodySID) ) return false; + if ( ! Reader->ReadUi64BE(&ByteOffset) ) return false; + return true; } - inline bool HasValue() const { return true; } + inline virtual bool HasValue() const { return true; } - inline Result_t Archive(ASDCP::MemIOWriter& Writer) const { - Result_t result = Writer.WriteUi32BE(BodySID); - - if ( ASDCP_SUCCESS(result) ) - result = Writer.WriteUi64BE(ByteOffset); - - return result; + inline virtual bool Archive(Kumu::MemIOWriter* Writer) const { + if ( ! Writer->WriteUi32BE(BodySID) ) return false; + if ( ! Writer->WriteUi64BE(ByteOffset) ) return false; + return true; } }; @@ -92,15 +87,15 @@ namespace ASDCP RIP() {} virtual ~RIP() {} - virtual Result_t InitFromFile(const ASDCP::FileReader& Reader); - virtual Result_t WriteToFile(ASDCP::FileWriter& Writer); + virtual Result_t InitFromFile(const Kumu::FileReader& Reader); + virtual Result_t WriteToFile(Kumu::FileWriter& Writer); virtual void Dump(FILE* = 0); }; // class Partition : public ASDCP::KLVFilePacket - { + { ASDCP_NO_COPY_CONSTRUCT(Partition); protected: @@ -125,8 +120,8 @@ namespace ASDCP Partition(); virtual ~Partition(); virtual void AddChildObject(InterchangeObject*); - virtual Result_t InitFromFile(const ASDCP::FileReader& Reader); - virtual Result_t WriteToFile(ASDCP::FileWriter& Writer, UL& PartitionLabel); + virtual Result_t InitFromFile(const Kumu::FileReader& Reader); + virtual Result_t WriteToFile(Kumu::FileWriter& Writer, UL& PartitionLabel); virtual ui32_t ArchiveSize(); // returns the size of the archived structure virtual void Dump(FILE* = 0); }; @@ -148,24 +143,22 @@ namespace ASDCP TagValue Tag; ASDCP::UL UL; - inline const char* ToString(char* str_buf) const { - snprintf(str_buf, IdentBufferLen, "%02x %02x: ", Tag.a, Tag.b); - UL.ToString(str_buf + strlen(str_buf)); + inline const char* EncodeString(char* str_buf, ui32_t buf_len) const { + snprintf(str_buf, buf_len, "%02x %02x: ", Tag.a, Tag.b); + UL.EncodeString(str_buf + strlen(str_buf), buf_len - strlen(str_buf)); return str_buf; } - inline Result_t Unarchive(ASDCP::MemIOReader& Reader) { - Result_t result = Reader.ReadUi8(&Tag.a); - if ( ASDCP_SUCCESS(result) ) result = Reader.ReadUi8(&Tag.b); - if ( ASDCP_SUCCESS(result) ) result = UL.Unarchive(Reader); - return result; + inline bool Unarchive(Kumu::MemIOReader* Reader) { + if ( ! Reader->ReadUi8(&Tag.a) ) return false; + if ( ! Reader->ReadUi8(&Tag.b) ) return false; + return UL.Unarchive(Reader); } - inline Result_t Archive(ASDCP::MemIOWriter& Writer) const { - Result_t result = Writer.WriteUi8(Tag.a); - if ( ASDCP_SUCCESS(result) ) result = Writer.WriteUi8(Tag.b); - if ( ASDCP_SUCCESS(result) ) result = UL.Archive(Writer); - return result; + inline bool Archive(Kumu::MemIOWriter* Writer) const { + if ( ! Writer->WriteUi8(Tag.a) ) return false; + if ( ! Writer->WriteUi8(Tag.b) ) return false; + return UL.Archive(Writer); } }; @@ -180,7 +173,7 @@ namespace ASDCP virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); - virtual Result_t WriteToFile(ASDCP::FileWriter& Writer); + virtual Result_t WriteToFile(Kumu::FileWriter& Writer); virtual void Dump(FILE* = 0); }; @@ -253,9 +246,9 @@ namespace ASDCP ui32_t ElementData; DeltaEntry() : PosTableIndex(-1), Slice(0), ElementData(0) {} - Result_t Unarchive(ASDCP::MemIOReader& Reader); - Result_t Archive(ASDCP::MemIOWriter& Writer) const; - const char* ToString(char* str_buf) const; + bool Unarchive(Kumu::MemIOReader* Reader); + bool Archive(Kumu::MemIOWriter* Writer) const; + const char* EncodeString(char* str_buf, ui32_t buf_len) const; }; // @@ -270,9 +263,9 @@ namespace ASDCP // Array<Rational> PosTable; IndexEntry() : TemporalOffset(0), KeyFrameOffset(0), Flags(0), StreamOffset() {} - Result_t Unarchive(ASDCP::MemIOReader& Reader); - Result_t Archive(ASDCP::MemIOWriter& Writer) const; - const char* ToString(char* str_buf) const; + bool Unarchive(Kumu::MemIOReader* Reader); + bool Archive(Kumu::MemIOWriter* Writer) const; + const char* EncodeString(char* str_buf, ui32_t buf_len) const; }; Rational IndexEditRate; @@ -315,8 +308,8 @@ namespace ASDCP OPAtomHeader(); virtual ~OPAtomHeader(); - virtual Result_t InitFromFile(const ASDCP::FileReader& Reader); - virtual Result_t WriteToFile(ASDCP::FileWriter& Writer, ui32_t HeaderLength = 16384); + virtual Result_t InitFromFile(const Kumu::FileReader& Reader); + virtual Result_t WriteToFile(Kumu::FileWriter& Writer, ui32_t HeaderLength = 16384); virtual void Dump(FILE* = 0); virtual Result_t GetMDObjectByType(const byte_t*, InterchangeObject** = 0); Identification* GetIdentification(); @@ -339,8 +332,8 @@ namespace ASDCP OPAtomIndexFooter(); virtual ~OPAtomIndexFooter(); - virtual Result_t InitFromFile(const ASDCP::FileReader& Reader); - virtual Result_t WriteToFile(ASDCP::FileWriter& Writer, ui64_t duration); + virtual Result_t InitFromFile(const Kumu::FileReader& Reader); + virtual Result_t WriteToFile(Kumu::FileWriter& Writer, ui64_t duration); virtual void Dump(FILE* = 0); virtual Result_t Lookup(ui32_t frame_num, IndexTableSegment::IndexEntry&); diff --git a/src/MXFTypes.cpp b/src/MXFTypes.cpp index 111d493..c2352fd 100755 --- a/src/MXFTypes.cpp +++ b/src/MXFTypes.cpp @@ -29,19 +29,51 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \brief MXF objects */ +#include <KM_prng.h> #include "MXFTypes.h" -#include "FortunaRNG.h" +#include <KM_log.h> +using Kumu::DefaultLogSink; //------------------------------------------------------------------------------------------ // +const char* +ASDCP::UL::EncodeString(char* str_buf, ui32_t buf_len) const +{ + if ( buf_len > 38 ) // room for dotted notation? + { + snprintf(str_buf, buf_len, + "%02x%02x%02x%02x.%02x%02x.%02x%02x.%02x%02x%02x%02x.%02x%02x%02x%02x", + m_Value[0], m_Value[1], m_Value[2], m_Value[3], + m_Value[4], m_Value[5], m_Value[6], m_Value[7], + m_Value[8], m_Value[9], m_Value[10], m_Value[11], + m_Value[12], m_Value[13], m_Value[14], m_Value[15] + ); + + return str_buf; + } + else if ( buf_len > 32 ) // room for compact? + { + snprintf(str_buf, buf_len, + "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + m_Value[0], m_Value[1], m_Value[2], m_Value[3], + m_Value[4], m_Value[5], m_Value[6], m_Value[7], + m_Value[8], m_Value[9], m_Value[10], m_Value[11], + m_Value[12], m_Value[13], m_Value[14], m_Value[15] + ); + + return str_buf; + } + + return 0; +} // void ASDCP::UMID::MakeUMID(int Type) { UUID AssetID; - AssetID.GenRandomValue(); + Kumu::GenRandomValue(AssetID); MakeUMID(Type, AssetID); } @@ -69,11 +101,11 @@ ASDCP::UMID::MakeUMID(int Type, const UUID& AssetID) // Write the timestamp value to the given buffer in the form 2004-05-01 13:20:00.000 // returns 0 if the buffer is smaller than DateTimeLen const char* -ASDCP::UMID::ToString(char* str_buf) const +ASDCP::UMID::EncodeString(char* str_buf, ui32_t buf_len) const { assert(str_buf); - snprintf(str_buf, IdentBufferLen, "[%02x%02x%02x%02x.%02x%02x.%02x%02x.%02x%02x%02x%02x],%02x,%02x,%02x,%02x,", + snprintf(str_buf, buf_len, "[%02x%02x%02x%02x.%02x%02x.%02x%02x.%02x%02x%02x%02x],%02x,%02x,%02x,%02x,", m_Value[0], m_Value[1], m_Value[2], m_Value[3], m_Value[4], m_Value[5], m_Value[6], m_Value[7], m_Value[8], m_Value[9], m_Value[10], m_Value[11], @@ -85,7 +117,7 @@ ASDCP::UMID::ToString(char* str_buf) const if ( ( m_Value[8] & 0x80 ) == 0 ) { // half-swapped UL, use [bbaa9988.ddcc.ffee.00010203.04050607] - snprintf(str_buf + offset, IdentBufferLen - offset, + snprintf(str_buf + offset, buf_len - offset, "[%02x%02x%02x%02x.%02x%02x.%02x%02x.%02x%02x%02x%02x.%02x%02x%02x%02x]", m_Value[24], m_Value[25], m_Value[26], m_Value[27], m_Value[28], m_Value[29], m_Value[30], m_Value[31], @@ -96,7 +128,7 @@ ASDCP::UMID::ToString(char* str_buf) const else { // UUID, use {00112233-4455-6677-8899-aabbccddeeff} - snprintf(str_buf + offset, IdentBufferLen - offset, + snprintf(str_buf + offset, buf_len - offset, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x}", m_Value[16], m_Value[17], m_Value[18], m_Value[19], m_Value[20], m_Value[21], m_Value[22], m_Value[23], @@ -108,20 +140,6 @@ ASDCP::UMID::ToString(char* str_buf) const return str_buf; } -// -void -ASDCP::UUID::GenRandomValue() -{ - FortunaRNG RNG; - RNG.FillRandom(m_Value, UUIDlen); - m_Value[6] &= 0x0f; // clear bits 4-7 - m_Value[6] |= 0x40; // set UUID version - m_Value[8] &= 0x3f; // clear bits 6&7 - m_Value[8] |= 0x80; // set bit 7 - m_HasValue = true; -} - - //------------------------------------------------------------------------------------------ // @@ -135,7 +153,7 @@ ASDCP::MXF::UTF16String::operator=(const char* sz) } else { - ui32_t len = xmin((ui32_t)strlen(sz), (IdentBufferLen - 1)); + ui32_t len = Kumu::xmin((ui32_t)strlen(sz), (IdentBufferLen - 1)); m_length = len; memcpy(m_buffer, sz, m_length); m_buffer[m_length] = 0; @@ -146,11 +164,11 @@ ASDCP::MXF::UTF16String::operator=(const char* sz) // -ASDCP::Result_t -ASDCP::MXF::UTF16String::Unarchive(ASDCP::MemIOReader& Reader) +bool +ASDCP::MXF::UTF16String::Unarchive(Kumu::MemIOReader* Reader) { - const byte_t* p = Reader.CurrentData(); - m_length = Reader.Remainder(); + const byte_t* p = Reader->CurrentData(); + m_length = Reader->Remainder(); assert(m_length % 2 == 0); m_length /= 2; assert(IdentBufferLen >= m_length); @@ -161,23 +179,23 @@ ASDCP::MXF::UTF16String::Unarchive(ASDCP::MemIOReader& Reader) m_buffer[i] = 0; - Reader.SkipOffset(m_length*2); - return RESULT_OK; + Reader->SkipOffset(m_length*2); + return true; } // -ASDCP::Result_t -ASDCP::MXF::UTF16String::Archive(ASDCP::MemIOWriter& Writer) const +bool +ASDCP::MXF::UTF16String::Archive(Kumu::MemIOWriter* Writer) const { - byte_t* p = Writer.Data() + Writer.Size(); + byte_t* p = Writer->Data() + Writer->Length(); ui32_t i = 0; memset(p, 0, (m_length*2)+2); for ( i = 0; i < m_length; i++ ) p[(i*2)+1] = m_buffer[i]; - Writer.AddOffset(m_length * 2); - return RESULT_OK; + Writer->AddOffset(m_length * 2); + return true; } @@ -274,7 +292,7 @@ ASDCP::MXF::Timestamp::AddHours(i32_t hours) } } -#else // WM_WIN32 +#else // KM_WIN32 #include <time.h> @@ -345,7 +363,7 @@ ASDCP::MXF::Timestamp::AddHours(i32_t hours) } } -#endif // WM_WIN32 +#endif // KM_WIN32 ASDCP::MXF::Timestamp::Timestamp(const Timestamp& rhs) @@ -407,11 +425,11 @@ ASDCP::MXF::Timestamp::operator!=(const Timestamp& rhs) const // const char* -ASDCP::MXF::Timestamp::ToString(char* str_buf) const +ASDCP::MXF::Timestamp::EncodeString(char* str_buf, ui32_t buf_len) const { // 2004-05-01 13:20:00.000 - snprintf(str_buf, IntBufferLen, - "%04hu-%02hu-%02hu %02hu:%02hu:%02hu.000", + snprintf(str_buf, buf_len, + "%04hu-%02hu-%02hu %02hu:%02hu:%02hu.000", Year, Month, Day, Hour, Minute, Second, Tick); return str_buf; @@ -430,26 +448,18 @@ ASDCP::MXF::TLVReader::TLVReader(const byte_t* p, ui32_t c, IPrimerLookup* Prime TagValue Tag; ui16_t pkt_len = 0; - result = MemIOReader::ReadUi8(&Tag.a); - - if ( ASDCP_SUCCESS(result) ) - result = MemIOReader::ReadUi8(&Tag.b); - - if ( ASDCP_SUCCESS(result) ) - result = MemIOReader::ReadUi16BE(&pkt_len); - - if ( ASDCP_SUCCESS(result) ) - { - m_ElementMap.insert(TagMap::value_type(Tag, ItemInfo(m_size, pkt_len))); - result = SkipOffset(pkt_len); - } - - if ( ASDCP_FAILURE(result) ) - { - DefaultLogSink().Error("Malformed Set\n"); - m_ElementMap.clear(); - break; - } + if ( MemIOReader::ReadUi8(&Tag.a) ) + if ( MemIOReader::ReadUi8(&Tag.b) ) + if ( MemIOReader::ReadUi16BE(&pkt_len) ) + { + m_ElementMap.insert(TagMap::value_type(Tag, ItemInfo(m_size, pkt_len))); + if ( SkipOffset(pkt_len) ) + continue;; + } + + DefaultLogSink().Error("Malformed Set\n"); + m_ElementMap.clear(); + result = RESULT_KLV_CODING; } } @@ -469,8 +479,8 @@ ASDCP::MXF::TLVReader::FindTL(const MDDEntry& Entry) { if ( Entry.tag.a == 0 ) { - DefaultLogSink().Info("No such UL in this TL list: %s (%02x %02x)\n", - Entry.name, Entry.tag.a, Entry.tag.b); + // DefaultLogSink().Debug("No such UL in this TL list: %s (%02x %02x)\n", + // Entry.name, Entry.tag.a, Entry.tag.b); return false; } @@ -486,20 +496,20 @@ ASDCP::MXF::TLVReader::FindTL(const MDDEntry& Entry) return true; } - DefaultLogSink().Info("Not Found (%02x %02x): %s\n", TmpTag.a, TmpTag.b, Entry.name); + // DefaultLogSink().Debug("Not Found (%02x %02x): %s\n", TmpTag.a, TmpTag.b, Entry.name); return false; } // ASDCP::Result_t -ASDCP::MXF::TLVReader::ReadObject(const MDDEntry& Entry, IArchive* Object) +ASDCP::MXF::TLVReader::ReadObject(const MDDEntry& Entry, Kumu::IArchive* Object) { ASDCP_TEST_NULL(Object); if ( FindTL(Entry) ) { if ( m_size < m_capacity ) // don't try to unarchive an empty item - return Object->Unarchive(*this); + return Object->Unarchive(this) ? RESULT_OK : RESULT_KLV_CODING; } return RESULT_FALSE; @@ -512,7 +522,7 @@ ASDCP::MXF::TLVReader::ReadUi8(const MDDEntry& Entry, ui8_t* value) ASDCP_TEST_NULL(value); if ( FindTL(Entry) ) - return MemIOReader::ReadUi8(value); + return MemIOReader::ReadUi8(value) ? RESULT_OK : RESULT_KLV_CODING; return RESULT_FALSE; } @@ -524,7 +534,7 @@ ASDCP::MXF::TLVReader::ReadUi16(const MDDEntry& Entry, ui16_t* value) ASDCP_TEST_NULL(value); if ( FindTL(Entry) ) - return MemIOReader::ReadUi16BE(value); + return MemIOReader::ReadUi16BE(value) ? RESULT_OK : RESULT_KLV_CODING; return RESULT_FALSE; } @@ -536,7 +546,7 @@ ASDCP::MXF::TLVReader::ReadUi32(const MDDEntry& Entry, ui32_t* value) ASDCP_TEST_NULL(value); if ( FindTL(Entry) ) - return MemIOReader::ReadUi32BE(value); + return MemIOReader::ReadUi32BE(value) ? RESULT_OK : RESULT_KLV_CODING; return RESULT_FALSE; } @@ -548,7 +558,7 @@ ASDCP::MXF::TLVReader::ReadUi64(const MDDEntry& Entry, ui64_t* value) ASDCP_TEST_NULL(value); if ( FindTL(Entry) ) - return MemIOReader::ReadUi64BE(value); + return MemIOReader::ReadUi64BE(value) ? RESULT_OK : RESULT_KLV_CODING; return RESULT_FALSE; } @@ -580,15 +590,14 @@ ASDCP::MXF::TLVWriter::WriteTag(const MDDEntry& Entry) return RESULT_FAIL; } - Result_t result = MemIOWriter::WriteUi8(TmpTag.a); - if ( ASDCP_SUCCESS(result) ) MemIOWriter::WriteUi8(TmpTag.b); - - return result; + if ( ! MemIOWriter::WriteUi8(TmpTag.a) ) return RESULT_KLV_CODING; + if ( ! MemIOWriter::WriteUi8(TmpTag.b) ) return RESULT_KLV_CODING; + return RESULT_OK; } // ASDCP::Result_t -ASDCP::MXF::TLVWriter::WriteObject(const MDDEntry& Entry, IArchive* Object) +ASDCP::MXF::TLVWriter::WriteObject(const MDDEntry& Entry, Kumu::IArchive* Object) { ASDCP_TEST_NULL(Object); @@ -600,19 +609,12 @@ ASDCP::MXF::TLVWriter::WriteObject(const MDDEntry& Entry, IArchive* Object) // write a temp length byte_t* l_p = CurrentData(); - if ( ASDCP_SUCCESS(result) ) - MemIOWriter::WriteUi16BE(0); + if ( ! MemIOWriter::WriteUi16BE(0) ) return RESULT_KLV_CODING; - if ( ASDCP_SUCCESS(result) ) - { - ui32_t before = Size(); - result = Object->Archive(*this); - - if ( ASDCP_SUCCESS(result) ) - i2p<ui16_t>(ASDCP_i16_BE( Size() - before), l_p); - } - - return result; + ui32_t before = Length(); + if ( ! Object->Archive(this) ) return RESULT_KLV_CODING; + Kumu::i2p<ui16_t>(KM_i16_BE( Length() - before), l_p); + return RESULT_OK; } // @@ -621,8 +623,13 @@ ASDCP::MXF::TLVWriter::WriteUi8(const MDDEntry& Entry, ui8_t* value) { ASDCP_TEST_NULL(value); Result_t result = WriteTag(Entry); - if ( ASDCP_SUCCESS(result) ) MemIOWriter::WriteUi16BE(sizeof(ui8_t)); - if ( ASDCP_SUCCESS(result) ) MemIOWriter::WriteUi8(*value); + + if ( ASDCP_SUCCESS(result) ) + { + if ( ! MemIOWriter::WriteUi16BE(sizeof(ui8_t)) ) return RESULT_KLV_CODING; + if ( ! MemIOWriter::WriteUi8(*value) ) return RESULT_KLV_CODING; + } + return result; } @@ -632,8 +639,13 @@ ASDCP::MXF::TLVWriter::WriteUi16(const MDDEntry& Entry, ui16_t* value) { ASDCP_TEST_NULL(value); Result_t result = WriteTag(Entry); - if ( ASDCP_SUCCESS(result) ) MemIOWriter::WriteUi16BE(sizeof(ui16_t)); - if ( ASDCP_SUCCESS(result) ) MemIOWriter::WriteUi16BE(*value); + + if ( KM_SUCCESS(result) ) + { + if ( ! MemIOWriter::WriteUi16BE(sizeof(ui16_t)) ) return RESULT_KLV_CODING; + if ( ! MemIOWriter::WriteUi16BE(*value) ) return RESULT_KLV_CODING; + } + return result; } @@ -643,8 +655,13 @@ ASDCP::MXF::TLVWriter::WriteUi32(const MDDEntry& Entry, ui32_t* value) { ASDCP_TEST_NULL(value); Result_t result = WriteTag(Entry); - if ( ASDCP_SUCCESS(result) ) MemIOWriter::WriteUi16BE(sizeof(ui32_t)); - if ( ASDCP_SUCCESS(result) ) MemIOWriter::WriteUi32BE(*value); + + if ( KM_SUCCESS(result) ) + { + if ( ! MemIOWriter::WriteUi16BE(sizeof(ui32_t)) ) return RESULT_KLV_CODING; + if ( ! MemIOWriter::WriteUi32BE(*value) ) return RESULT_KLV_CODING; + } + return result; } @@ -654,8 +671,13 @@ ASDCP::MXF::TLVWriter::WriteUi64(const MDDEntry& Entry, ui64_t* value) { ASDCP_TEST_NULL(value); Result_t result = WriteTag(Entry); - if ( ASDCP_SUCCESS(result) ) MemIOWriter::WriteUi16BE(sizeof(ui64_t)); - if ( ASDCP_SUCCESS(result) ) MemIOWriter::WriteUi64BE(*value); + + if ( KM_SUCCESS(result) ) + { + if ( ! MemIOWriter::WriteUi16BE(sizeof(ui64_t)) ) return RESULT_KLV_CODING; + if ( ! MemIOWriter::WriteUi64BE(*value) ) return RESULT_KLV_CODING; + } + return result; } @@ -673,39 +695,31 @@ ASDCP::MXF::Raw::~Raw() } // -ASDCP::Result_t -ASDCP::MXF::Raw::Unarchive(ASDCP::MemIOReader& Reader) +bool +ASDCP::MXF::Raw::Unarchive(Kumu::MemIOReader* Reader) { - ui32_t payload_size = Reader.Remainder(); - - if ( payload_size == 0 ) - return RESULT_OK; + ui32_t payload_size = Reader->Remainder(); + if ( payload_size == 0 ) return false; + if ( KM_FAILURE(Capacity(payload_size)) ) return false; - Result_t result = Capacity(payload_size); - - if ( ASDCP_SUCCESS(result) ) - { - memcpy(Data(), Reader.CurrentData(), payload_size); - Size(payload_size); - } - - return result; + memcpy(Data(), Reader->CurrentData(), payload_size); + Length(payload_size); + return true; } // -ASDCP::Result_t -ASDCP::MXF::Raw::Archive(ASDCP::MemIOWriter& Writer) const +bool +ASDCP::MXF::Raw::Archive(Kumu::MemIOWriter* Writer) const { - return Writer.WriteRaw(RoData(), Size()); + return Writer->WriteRaw(RoData(), Length()); } // const char* -ASDCP::MXF::Raw::ToString(char* str_buf) const +ASDCP::MXF::Raw::EncodeString(char* str_buf, ui32_t buf_len) const { *str_buf = 0; - bin2hex(RoData(), Size(), str_buf, IdentBufferLen); - snprintf(str_buf, IdentBufferLen, "%s\n", str_buf); + Kumu::bin2hex(RoData(), Length(), str_buf, buf_len); return str_buf; } diff --git a/src/MXFTypes.h b/src/MXFTypes.h index e78b55c..5bb8ca4 100755 --- a/src/MXFTypes.h +++ b/src/MXFTypes.h @@ -54,7 +54,7 @@ namespace ASDCP typedef std::map<TagValue, ItemInfo> TagMap; // - class TLVReader : public ASDCP::MemIOReader + class TLVReader : public Kumu::MemIOReader { TagMap m_ElementMap; @@ -66,7 +66,7 @@ namespace ASDCP public: TLVReader(const byte_t* p, ui32_t c, IPrimerLookup* = 0); - Result_t ReadObject(const MDDEntry&, IArchive*); + Result_t ReadObject(const MDDEntry&, Kumu::IArchive*); Result_t ReadUi8(const MDDEntry&, ui8_t*); Result_t ReadUi16(const MDDEntry&, ui16_t*); Result_t ReadUi32(const MDDEntry&, ui32_t*); @@ -74,7 +74,7 @@ namespace ASDCP }; // - class TLVWriter : public ASDCP::MemIOWriter + class TLVWriter : public Kumu::MemIOWriter { TagMap m_ElementMap; @@ -86,7 +86,7 @@ namespace ASDCP public: TLVWriter(byte_t* p, ui32_t c, IPrimerLookup* = 0); - Result_t WriteObject(const MDDEntry&, IArchive*); + Result_t WriteObject(const MDDEntry&, Kumu::IArchive*); Result_t WriteUi8(const MDDEntry&, ui8_t*); Result_t WriteUi16(const MDDEntry&, ui16_t*); Result_t WriteUi32(const MDDEntry&, ui32_t*); @@ -95,58 +95,55 @@ namespace ASDCP // template <class T> - class Batch : public std::vector<T>, public IArchive + class Batch : public std::vector<T>, public Kumu::IArchive { public: Batch() {} ~Batch() {} // - Result_t Unarchive(ASDCP::MemIOReader& Reader) { + virtual bool Unarchive(Kumu::MemIOReader* Reader) { ui32_t ItemCount, ItemSize; - Result_t result = Reader.ReadUi32BE(&ItemCount); - - if ( ASDCP_SUCCESS(result) ) - result = Reader.ReadUi32BE(&ItemSize); + if ( ! Reader->ReadUi32BE(&ItemCount) ) return false; + if ( ! Reader->ReadUi32BE(&ItemSize) ) return false; if ( ( ItemCount > 65536 ) || ( ItemSize > 1024 ) ) - return RESULT_FAIL; + return false; - for ( ui32_t i = 0; i < ItemCount && ASDCP_SUCCESS(result); i++ ) + bool result = true; + for ( ui32_t i = 0; i < ItemCount && result; i++ ) { T Tmp; result = Tmp.Unarchive(Reader); - if ( ASDCP_SUCCESS(result) ) + if ( result ) push_back(Tmp); } return result; } - inline bool HasValue() const { return ! this->empty(); } + inline virtual bool HasValue() const { return ! this->empty(); } // - Result_t Archive(ASDCP::MemIOWriter& Writer) const { - Result_t result = Writer.WriteUi32BE(size()); - byte_t* p = Writer.CurrentData(); - - if ( ASDCP_SUCCESS(result) ) - result = Writer.WriteUi32BE(0); + virtual bool Archive(Kumu::MemIOWriter* Writer) const { + if ( ! Writer->WriteUi32BE(this->size()) ) return false; + byte_t* p = Writer->CurrentData(); - if ( ASDCP_FAILURE(result) || this->empty() ) - return result; + if ( ! Writer->WriteUi32BE(0) ) return false; + if ( this->empty() ) return true; typename std::vector<T>::const_iterator l_i = this->begin(); assert(l_i != this->end()); - ui32_t ItemSize = Writer.Remainder(); - result = (*l_i).Archive(Writer); - ItemSize -= Writer.Remainder(); - i2p<ui32_t>(ASDCP_i32_BE(ItemSize), p); + ui32_t ItemSize = Writer->Remainder(); + if ( ! (*l_i).Archive(Writer) ) return false; + ItemSize -= Writer->Remainder(); + Kumu::i2p<ui32_t>(KM_i32_BE(ItemSize), p); l_i++; - for ( ; l_i != this->end() && ASDCP_SUCCESS(result); l_i++ ) + bool result = true; + for ( ; l_i != this->end() && result; l_i++ ) result = (*l_i).Archive(Writer); return result; @@ -162,39 +159,41 @@ namespace ASDCP typename std::vector<T>::iterator i = this->begin(); for ( ; i != this->end(); i++ ) - fprintf(stream, " %s\n", (*i).ToString(identbuf)); + fprintf(stream, " %s\n", (*i).EncodeString(identbuf, IdentBufferLen)); } }; // template <class T> - class Array : public std::list<T>, public IArchive + class Array : public std::list<T>, public Kumu::IArchive { public: Array() {} ~Array() {} // - Result_t Unarchive(ASDCP::MemIOReader& Reader) + virtual bool Unarchive(Kumu::MemIOReader* Reader) { - while ( Reader.Remainder() > 0 ) + bool result = true; + + while ( Reader->Remainder() > 0 && result ) { T Tmp; - Tmp.Unarchive(Reader); + result = Tmp.Unarchive(Reader); push_back(Tmp); } - return RESULT_OK; + return result; } - inline bool HasValue() const { return ! this->empty(); } + inline virtual bool HasValue() const { return ! this->empty(); } // - Result_t Archive(ASDCP::MemIOWriter& Writer) const { - Result_t result = RESULT_OK; + virtual bool Archive(Kumu::MemIOWriter* Writer) const { + bool result = true; typename std::list<T>::const_iterator l_i = this->begin(); - for ( ; l_i != this->end() && ASDCP_SUCCESS(result); l_i++ ) + for ( ; l_i != this->end() && result; l_i++ ) result = (*l_i).Archive(Writer); return result; @@ -210,12 +209,12 @@ namespace ASDCP typename std::list<T>::iterator i = this->begin(); for ( ; i != this->end(); i++ ) - fprintf(stream, " %s\n", (*i).ToString(identbuf)); + fprintf(stream, " %s\n", (*i).EncodeString(identbuf, IdentBufferLen)); } }; // - class Timestamp : public IArchive + class Timestamp : public Kumu::IArchive { public: ui16_t Year; @@ -246,33 +245,27 @@ namespace ASDCP // Write the timestamp value to the given buffer in the form 2004-05-01 13:20:00.000 // returns 0 if the buffer is smaller than DateTimeLen - const char* ToString(char* str_buf) const; + const char* EncodeString(char* str_buf, ui32_t buf_len) const; // - inline Result_t Unarchive(ASDCP::MemIOReader& Reader) { - Result_t result = Reader.ReadUi16BE(&Year); - - if ( ASDCP_SUCCESS(result) ) - result = Reader.ReadRaw(&Month, 6); - - return result; + inline virtual bool Unarchive(Kumu::MemIOReader* Reader) { + if ( ! Reader->ReadUi16BE(&Year) ) return false; + if ( ! Reader->ReadRaw(&Month, 6) ) return false; + return true; } - inline bool HasValue() const { return true; } + inline virtual bool HasValue() const { return true; } // - inline Result_t Archive(ASDCP::MemIOWriter& Writer) const { - Result_t result = Writer.WriteUi16BE(Year); - - if ( ASDCP_SUCCESS(result) ) - result = Writer.WriteRaw(&Month, 6); - - return result; + inline virtual bool Archive(Kumu::MemIOWriter* Writer) const { + if ( ! Writer->WriteUi16BE(Year) ) return false; + if ( ! Writer->WriteRaw(&Month, 6) ) return false; + return true; } }; // - class UTF16String : public IArchive + class UTF16String : public Kumu::IArchive { ui16_t m_length; char m_buffer[IdentBufferLen]; @@ -285,18 +278,19 @@ namespace ASDCP const UTF16String& operator=(const char*); // - const char* ToString(char* str_buf) const { - strncpy(str_buf, m_buffer, m_length+1); + const char* EncodeString(char* str_buf, ui32_t buf_len) const { + strncpy(str_buf, m_buffer, Kumu::xmin(buf_len, ((ui32_t)m_length+1))); + str_buf[buf_len-1] = 0; return str_buf; } - Result_t Unarchive(ASDCP::MemIOReader& Reader); - inline bool HasValue() const { return m_length > 0; } - Result_t Archive(ASDCP::MemIOWriter& Writer) const; + virtual bool Unarchive(Kumu::MemIOReader* Reader); + inline virtual bool HasValue() const { return m_length > 0; } + virtual bool Archive(Kumu::MemIOWriter* Writer) const; }; // - class Rational : public ASDCP::Rational, public IArchive + class Rational : public ASDCP::Rational, public Kumu::IArchive { public: Rational() {} @@ -325,34 +319,28 @@ namespace ASDCP } // - const char* ToString(char* str_buf) const { - snprintf(str_buf, IdentBufferLen, "%lu/%lu", Numerator, Denominator); + inline const char* EncodeString(char* str_buf, ui32_t buf_len) const { + snprintf(str_buf, buf_len, "%lu/%lu", Numerator, Denominator); return str_buf; } - Result_t Unarchive(ASDCP::MemIOReader& Reader) { - Result_t result = Reader.ReadUi32BE((ui32_t*)&Numerator); - - if ( ASDCP_SUCCESS(result) ) - result = Reader.ReadUi32BE((ui32_t*)&Denominator); - - return result; + inline virtual bool Unarchive(Kumu::MemIOReader* Reader) { + if ( ! Reader->ReadUi32BE((ui32_t*)&Numerator) ) return false; + if ( ! Reader->ReadUi32BE((ui32_t*)&Denominator) ) return false; + return true; } - inline bool HasValue() const { return true; } + inline virtual bool HasValue() const { return true; } - Result_t Archive(ASDCP::MemIOWriter& Writer) const { - Result_t result = Writer.WriteUi32BE((ui32_t)Numerator); - - if ( ASDCP_SUCCESS(result) ) - result = Writer.WriteUi32BE((ui32_t)Denominator); - - return result; + inline virtual bool Archive(Kumu::MemIOWriter* Writer) const { + if ( ! Writer->WriteUi32BE((ui32_t)Numerator) ) return false; + if ( ! Writer->WriteUi32BE((ui32_t)Denominator) ) return false; + return true; } }; // - class VersionType : public IArchive + class VersionType : public Kumu::IArchive { ASDCP_NO_COPY_CONSTRUCT(VersionType); @@ -368,40 +356,36 @@ namespace ASDCP ~VersionType() {} void Dump(FILE* = 0); - const char* ToString(char* str_buf) const { - snprintf(str_buf, IdentBufferLen, "%hu.%hu.%hu.%hur%hu", Major, Minor, Patch, Build, Release); + const char* EncodeString(char* str_buf, ui32_t buf_len) const { + snprintf(str_buf, buf_len, "%hu.%hu.%hu.%hur%hu", Major, Minor, Patch, Build, Release); return str_buf; } - Result_t Unarchive(ASDCP::MemIOReader& Reader) { - Result_t result = Reader.ReadUi16BE(&Major); - if ( ASDCP_SUCCESS(result) ) result = Reader.ReadUi16BE(&Minor); - if ( ASDCP_SUCCESS(result) ) result = Reader.ReadUi16BE(&Patch); - if ( ASDCP_SUCCESS(result) ) result = Reader.ReadUi16BE(&Build); - if ( ASDCP_SUCCESS(result) ) - { - ui16_t tmp_release; - result = Reader.ReadUi16BE(&tmp_release); - Release = (Release_t)tmp_release; - } - - return result; + virtual bool Unarchive(Kumu::MemIOReader* Reader) { + if ( ! Reader->ReadUi16BE(&Major) ) return false; + if ( ! Reader->ReadUi16BE(&Minor) ) return false; + if ( ! Reader->ReadUi16BE(&Patch) ) return false; + if ( ! Reader->ReadUi16BE(&Build) ) return false; + ui16_t tmp_release; + if ( ! Reader->ReadUi16BE(&tmp_release) ) return false; + Release = (Release_t)tmp_release; + return true; } - inline bool HasValue() const { return true; } + inline virtual bool HasValue() const { return true; } - Result_t Archive(ASDCP::MemIOWriter& Writer) const { - Result_t result = Writer.WriteUi16BE(Major); - if ( ASDCP_SUCCESS(result) ) result = Writer.WriteUi16BE(Minor); - if ( ASDCP_SUCCESS(result) ) result = Writer.WriteUi16BE(Patch); - if ( ASDCP_SUCCESS(result) ) result = Writer.WriteUi16BE(Build); - if ( ASDCP_SUCCESS(result) ) result = Writer.WriteUi16BE((ui16_t)(Release & 0x0000ffffL)); - return result; + virtual bool Archive(Kumu::MemIOWriter* Writer) const { + if ( ! Writer->WriteUi16BE(Major) ) return false; + if ( ! Writer->WriteUi16BE(Minor) ) return false; + if ( ! Writer->WriteUi16BE(Patch) ) return false; + if ( ! Writer->WriteUi16BE(Build) ) return false; + if ( ! Writer->WriteUi16BE((ui16_t)(Release & 0x0000ffffL)) ) return false; + return true; } }; // - class Raw : public ASDCP::FrameBuffer, public IArchive + class Raw : public Kumu::ByteString, public Kumu::IArchive { ASDCP_NO_COPY_CONSTRUCT(Raw); @@ -410,10 +394,10 @@ namespace ASDCP ~Raw(); // - Result_t Unarchive(ASDCP::MemIOReader& Reader); - inline bool HasValue() const { return Size() > 0; } - Result_t Archive(ASDCP::MemIOWriter& Writer) const; - const char* ToString(char* str_buf) const; + virtual bool Unarchive(Kumu::MemIOReader* Reader); + inline virtual bool HasValue() const { return Length() > 0; } + virtual bool Archive(Kumu::MemIOWriter* Writer) const; + const char* EncodeString(char* str_buf, ui32_t buf_len) const; }; } // namespace MXF diff --git a/src/Metadata.cpp b/src/Metadata.cpp index d4cc819..3290b1b 100755 --- a/src/Metadata.cpp +++ b/src/Metadata.cpp @@ -30,9 +30,8 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include <KM_mutex.h> #include "Metadata.h" -#include "Mutex.h" -#include "hex_utils.h" const ui32_t kl_length = ASDCP::SMPTE_UL_LENGTH + ASDCP::MXF_BER_LENGTH; @@ -71,24 +70,24 @@ typedef std::map<ASDCP::UL, FLT_t>::iterator FLi_t; class FactoryList : public std::map<ASDCP::UL, FLT_t> { - ASDCP::Mutex m_Lock; + Kumu::Mutex m_Lock; public: FactoryList() {} ~FactoryList() {} bool Empty() { - ASDCP::AutoMutex BlockLock(m_Lock); + Kumu::AutoMutex BlockLock(m_Lock); return empty(); } FLi_t Find(const byte_t* label) { - ASDCP::AutoMutex BlockLock(m_Lock); + Kumu::AutoMutex BlockLock(m_Lock); return find(label); } FLi_t End() { - ASDCP::AutoMutex BlockLock(m_Lock); + Kumu::AutoMutex BlockLock(m_Lock); return end(); } @@ -220,15 +219,15 @@ ASDCP::MXF::Identification::Dump(FILE* stream) stream = stderr; InterchangeObject::Dump(stream); - fprintf(stream, " %22s = %s\n", "ThisGenerationUID", ThisGenerationUID.ToString(identbuf)); - fprintf(stream, " %22s = %s\n", "CompanyName", CompanyName.ToString(identbuf)); - fprintf(stream, " %22s = %s\n", "ProductName", ProductName.ToString(identbuf)); - fprintf(stream, " %22s = %s\n", "ProductVersion", ProductVersion.ToString(identbuf)); - fprintf(stream, " %22s = %s\n", "VersionString", VersionString.ToString(identbuf)); - fprintf(stream, " %22s = %s\n", "ProductUID", ProductUID.ToString(identbuf)); - fprintf(stream, " %22s = %s\n", "ModificationDate", ModificationDate.ToString(identbuf)); - fprintf(stream, " %22s = %s\n", "ToolkitVersion", ToolkitVersion.ToString(identbuf)); - fprintf(stream, " %22s = %s\n", "Platform", Platform.ToString(identbuf)); + fprintf(stream, " %22s = %s\n", "ThisGenerationUID", ThisGenerationUID.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "CompanyName", CompanyName.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "ProductName", ProductName.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "ProductVersion", ProductVersion.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "VersionString", VersionString.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "ProductUID", ProductUID.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "ModificationDate", ModificationDate.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "ToolkitVersion", ToolkitVersion.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "Platform", Platform.EncodeString(identbuf, IdentBufferLen)); } // @@ -339,7 +338,7 @@ ASDCP::MXF::EssenceContainerData::Dump(FILE* stream) stream = stderr; InterchangeObject::Dump(stream); - fprintf(stream, " %22s = %s\n", "LinkedPackageUID", LinkedPackageUID.ToString(identbuf)); + fprintf(stream, " %22s = %s\n", "LinkedPackageUID", LinkedPackageUID.EncodeString(identbuf, IdentBufferLen)); fprintf(stream, " %22s = %d\n", "IndexSID", IndexSID); fprintf(stream, " %22s = %d\n", "BodySID", BodySID); } @@ -400,10 +399,10 @@ ASDCP::MXF::GenericPackage::Dump(FILE* stream) stream = stderr; InterchangeObject::Dump(stream); - fprintf(stream, " %22s = %s\n", "PackageUID", PackageUID.ToString(identbuf)); - fprintf(stream, " %22s = %s\n", "Name", Name.ToString(identbuf)); - fprintf(stream, " %22s = %s\n", "PackageCreationDate", PackageCreationDate.ToString(identbuf)); - fprintf(stream, " %22s = %s\n", "PackageModifiedDate", PackageModifiedDate.ToString(identbuf)); + fprintf(stream, " %22s = %s\n", "PackageUID", PackageUID.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "Name", Name.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "PackageCreationDate", PackageCreationDate.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "PackageModifiedDate", PackageModifiedDate.EncodeString(identbuf, IdentBufferLen)); fprintf(stream, " %22s:\n", "Tracks"); Tracks.Dump(stream); } @@ -489,7 +488,7 @@ ASDCP::MXF::SourcePackage::Dump(FILE* stream) stream = stderr; GenericPackage::Dump(stream); - fprintf(stream, " %22s = %s\n", "Descriptor", Descriptor.ToString(identbuf)); + fprintf(stream, " %22s = %s\n", "Descriptor", Descriptor.EncodeString(identbuf, IdentBufferLen)); } // @@ -548,8 +547,8 @@ ASDCP::MXF::GenericTrack::Dump(FILE* stream) InterchangeObject::Dump(stream); fprintf(stream, " %22s = %d\n", "TrackID", TrackID); fprintf(stream, " %22s = %d\n", "TrackNumber", TrackNumber); - fprintf(stream, " %22s = %s\n", "TrackName", TrackName.ToString(identbuf)); - fprintf(stream, " %22s = %s\n", "Sequence", Sequence.ToString(identbuf)); + fprintf(stream, " %22s = %s\n", "TrackName", TrackName.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "Sequence", Sequence.EncodeString(identbuf, IdentBufferLen)); } @@ -635,7 +634,7 @@ ASDCP::MXF::Track::Dump(FILE* stream) stream = stderr; GenericTrack::Dump(stream); - fprintf(stream, " %22s = %s\n", "EditRate", EditRate.ToString(identbuf)); + fprintf(stream, " %22s = %s\n", "EditRate", EditRate.EncodeString(identbuf, IdentBufferLen)); fprintf(stream, " %22s = %s\n", "Origin", i64sz(Origin, identbuf)); } @@ -689,7 +688,7 @@ ASDCP::MXF::StructuralComponent::Dump(FILE* stream) stream = stderr; InterchangeObject::Dump(stream); - fprintf(stream, " %22s = %s\n", "DataDefinition", DataDefinition.ToString(identbuf)); + fprintf(stream, " %22s = %s\n", "DataDefinition", DataDefinition.EncodeString(identbuf, IdentBufferLen)); fprintf(stream, " %22s = %s\n", "Duration", i64sz(Duration, identbuf)); } @@ -783,7 +782,7 @@ ASDCP::MXF::SourceClip::Dump(FILE* stream) StructuralComponent::Dump(stream); fprintf(stream, " %22s = %s\n", "StartPosition", i64sz(StartPosition, identbuf)); - fprintf(stream, " %22s = %s\n", "SourcePackageID", SourcePackageID.ToString(identbuf)); + fprintf(stream, " %22s = %s\n", "SourcePackageID", SourcePackageID.EncodeString(identbuf, IdentBufferLen)); fprintf(stream, " %22s = %d\n", "SourceTrackID", SourceTrackID); } @@ -942,10 +941,10 @@ ASDCP::MXF::FileDescriptor::Dump(FILE* stream) GenericDescriptor::Dump(stream); fprintf(stream, " %22s = %d\n", "LinkedTrackID", LinkedTrackID); - fprintf(stream, " %22s = %s\n", "SampleRate", SampleRate.ToString(identbuf)); + fprintf(stream, " %22s = %s\n", "SampleRate", SampleRate.EncodeString(identbuf, IdentBufferLen)); fprintf(stream, " %22s = %s\n", "ContainerDuration", i64sz(ContainerDuration, identbuf)); - fprintf(stream, " %22s = %s\n", "EssenceContainer", EssenceContainer.ToString(identbuf)); - fprintf(stream, " %22s = %s\n", "Codec", Codec.ToString(identbuf)); + fprintf(stream, " %22s = %s\n", "EssenceContainer", EssenceContainer.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "Codec", Codec.EncodeString(identbuf, IdentBufferLen)); } // @@ -1006,7 +1005,7 @@ ASDCP::MXF::GenericSoundEssenceDescriptor::Dump(FILE* stream) stream = stderr; FileDescriptor::Dump(stream); - fprintf(stream, " %22s = %s\n", "AudioSamplingRate", AudioSamplingRate.ToString(identbuf)); + fprintf(stream, " %22s = %s\n", "AudioSamplingRate", AudioSamplingRate.EncodeString(identbuf, IdentBufferLen)); fprintf(stream, " %22s = %d\n", "Locked", Locked); fprintf(stream, " %22s = %d\n", "AudioRefLevel", AudioRefLevel); fprintf(stream, " %22s = %d\n", "ChannelCount", ChannelCount); @@ -1128,7 +1127,7 @@ ASDCP::MXF::GenericPictureEssenceDescriptor::Dump(FILE* stream) fprintf(stream, " %22s = %d\n", "FrameLayout", FrameLayout); fprintf(stream, " %22s = %d\n", "StoredWidth", StoredWidth); fprintf(stream, " %22s = %d\n", "StoredHeight", StoredHeight); - fprintf(stream, " %22s = %s\n", "AspectRatio", AspectRatio.ToString(identbuf)); + fprintf(stream, " %22s = %s\n", "AspectRatio", AspectRatio.EncodeString(identbuf, IdentBufferLen)); } // @@ -1267,9 +1266,9 @@ ASDCP::MXF::JPEG2000PictureSubDescriptor::Dump(FILE* stream) fprintf(stream, " %22s = %d\n", "XTOsize", XTOsize); fprintf(stream, " %22s = %d\n", "YTOsize", YTOsize); fprintf(stream, " %22s = %d\n", "Csize", Csize); - fprintf(stream, " %22s = %s\n", "PictureComponentSizing", PictureComponentSizing.ToString(identbuf)); - fprintf(stream, " %22s = %s\n", "CodingStyleDefault", CodingStyleDefault.ToString(identbuf)); - fprintf(stream, " %22s = %s\n", "QuantizationDefault", QuantizationDefault.ToString(identbuf)); + fprintf(stream, " %22s = %s\n", "PictureComponentSizing", PictureComponentSizing.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "CodingStyleDefault", CodingStyleDefault.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "QuantizationDefault", QuantizationDefault.EncodeString(identbuf, IdentBufferLen)); } // @@ -1445,8 +1444,8 @@ ASDCP::MXF::DMSegment::Dump(FILE* stream) InterchangeObject::Dump(stream); fprintf(stream, " %22s = %s\n", "EventStartPosition", i64sz(EventStartPosition, identbuf)); - fprintf(stream, " %22s = %s\n", "EventComment", EventComment.ToString(identbuf)); - fprintf(stream, " %22s = %s\n", "DMFramework", DMFramework.ToString(identbuf)); + fprintf(stream, " %22s = %s\n", "EventComment", EventComment.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "DMFramework", DMFramework.EncodeString(identbuf, IdentBufferLen)); } // @@ -1497,7 +1496,7 @@ ASDCP::MXF::CryptographicFramework::Dump(FILE* stream) stream = stderr; InterchangeObject::Dump(stream); - fprintf(stream, " %22s = %s\n", "ContextSR", ContextSR.ToString(identbuf)); + fprintf(stream, " %22s = %s\n", "ContextSR", ContextSR.EncodeString(identbuf, IdentBufferLen)); } // @@ -1556,11 +1555,11 @@ ASDCP::MXF::CryptographicContext::Dump(FILE* stream) stream = stderr; InterchangeObject::Dump(stream); - fprintf(stream, " %22s = %s\n", "ContextID", ContextID.ToString(identbuf)); - fprintf(stream, " %22s = %s\n", "SourceEssenceContainer", SourceEssenceContainer.ToString(identbuf)); - fprintf(stream, " %22s = %s\n", "CipherAlgorithm", CipherAlgorithm.ToString(identbuf)); - fprintf(stream, " %22s = %s\n", "MICAlgorithm", MICAlgorithm.ToString(identbuf)); - fprintf(stream, " %22s = %s\n", "CryptographicKeyID", CryptographicKeyID.ToString(identbuf)); + fprintf(stream, " %22s = %s\n", "ContextID", ContextID.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "SourceEssenceContainer", SourceEssenceContainer.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "CipherAlgorithm", CipherAlgorithm.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "MICAlgorithm", MICAlgorithm.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "CryptographicKeyID", CryptographicKeyID.EncodeString(identbuf, IdentBufferLen)); } // @@ -1580,5 +1579,5 @@ ASDCP::MXF::CryptographicContext::WriteToBuffer(ASDCP::FrameBuffer& Buffer) } // -// end MXF.cpp +// end Metadata.cpp // diff --git a/src/PCM_Parser.cpp b/src/PCM_Parser.cpp index 331bebf..f3e32db 100755 --- a/src/PCM_Parser.cpp +++ b/src/PCM_Parser.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2004, John Hurst +Copyright (c) 2004-2006, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without @@ -31,6 +31,8 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <Wav.h> #include <assert.h> +#include <KM_log.h> +using Kumu::DefaultLogSink; using namespace ASDCP; using namespace ASDCP::PCM; @@ -42,7 +44,7 @@ using namespace ASDCP::Wav; // class ASDCP::PCM::WAVParser::h__WAVParser { - FileReader m_FileReader; + Kumu::FileReader m_FileReader; bool m_EOF; ui32_t m_DataStart; ui32_t m_DataLength; diff --git a/src/Wav.cpp b/src/Wav.cpp index ce64a78..92bd5e7 100755 --- a/src/Wav.cpp +++ b/src/Wav.cpp @@ -30,8 +30,9 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "Wav.h" -#include "hex_utils.h" #include <assert.h> +#include <KM_log.h> +using Kumu::DefaultLogSink; const ui32_t SimpleWavHeaderLength = 46; @@ -69,7 +70,7 @@ ASDCP::Wav::SimpleWaveHeader::FillADesc(ASDCP::PCM::AudioDescriptor& ADesc, ASDC // ASDCP::Result_t -ASDCP::Wav::SimpleWaveHeader::WriteToFile(ASDCP::FileWriter& OutFile) const +ASDCP::Wav::SimpleWaveHeader::WriteToFile(Kumu::FileWriter& OutFile) const { ui32_t write_count; byte_t tmp_header[SimpleWavHeaderLength]; @@ -87,26 +88,26 @@ ASDCP::Wav::SimpleWaveHeader::WriteToFile(ASDCP::FileWriter& OutFile) const ui32_t RIFF_len = data_len + SimpleWavHeaderLength - 8; memcpy(p, &FCC_RIFF, sizeof(fourcc)); p += 4; - *((ui32_t*)p) = ASDCP_i32_LE(RIFF_len); p += 4; + *((ui32_t*)p) = KM_i32_LE(RIFF_len); p += 4; memcpy(p, &FCC_WAVE, sizeof(fourcc)); p += 4; memcpy(p, &FCC_fmt_, sizeof(fourcc)); p += 4; - *((ui32_t*)p) = ASDCP_i32_LE(fmt_len); p += 4; - *((ui16_t*)p) = ASDCP_i16_LE(format); p += 2; - *((ui16_t*)p) = ASDCP_i16_LE(nchannels); p += 2; - *((ui32_t*)p) = ASDCP_i32_LE(samplespersec); p += 4; - *((ui32_t*)p) = ASDCP_i32_LE(avgbps); p += 4; - *((ui16_t*)p) = ASDCP_i16_LE(blockalign); p += 2; - *((ui16_t*)p) = ASDCP_i16_LE(bitspersample); p += 2; - *((ui16_t*)p) = ASDCP_i16_LE(cbsize); p += 2; + *((ui32_t*)p) = KM_i32_LE(fmt_len); p += 4; + *((ui16_t*)p) = KM_i16_LE(format); p += 2; + *((ui16_t*)p) = KM_i16_LE(nchannels); p += 2; + *((ui32_t*)p) = KM_i32_LE(samplespersec); p += 4; + *((ui32_t*)p) = KM_i32_LE(avgbps); p += 4; + *((ui16_t*)p) = KM_i16_LE(blockalign); p += 2; + *((ui16_t*)p) = KM_i16_LE(bitspersample); p += 2; + *((ui16_t*)p) = KM_i16_LE(cbsize); p += 2; memcpy(p, &FCC_data, sizeof(fourcc)); p += 4; - *((ui32_t*)p) = ASDCP_i32_LE(data_len); p += 4; + *((ui32_t*)p) = KM_i32_LE(data_len); p += 4; return OutFile.Write(tmp_header, SimpleWavHeaderLength, &write_count); } // ASDCP::Result_t -ASDCP::Wav::SimpleWaveHeader::ReadFromFile(const ASDCP::FileReader& InFile, ui32_t* data_start) +ASDCP::Wav::SimpleWaveHeader::ReadFromFile(const Kumu::FileReader& InFile, ui32_t* data_start) { ui32_t read_count = 0; ui32_t local_data_start = 0; @@ -140,7 +141,7 @@ ASDCP::Wav::SimpleWaveHeader::ReadFromBuffer(const byte_t* buf, ui32_t buf_len, return RESULT_RAW_FORMAT; } - ui32_t RIFF_len = ASDCP_i32_LE(*(ui32_t*)p); p += 4; + ui32_t RIFF_len = KM_i32_LE(*(ui32_t*)p); p += 4; fourcc test_WAVE(p); p += 4; if ( test_WAVE != FCC_WAVE ) @@ -154,7 +155,7 @@ ASDCP::Wav::SimpleWaveHeader::ReadFromBuffer(const byte_t* buf, ui32_t buf_len, while ( p < end_p ) { test_fcc = fourcc(p); p += 4; - ui32_t chunk_size = ASDCP_i32_LE(*(ui32_t*)p); p += 4; + ui32_t chunk_size = KM_i32_LE(*(ui32_t*)p); p += 4; if ( test_fcc == FCC_data ) { @@ -171,7 +172,7 @@ ASDCP::Wav::SimpleWaveHeader::ReadFromBuffer(const byte_t* buf, ui32_t buf_len, if ( test_fcc == FCC_fmt_ ) { - ui16_t format = ASDCP_i16_LE(*(ui16_t*)p); p += 2; + ui16_t format = KM_i16_LE(*(ui16_t*)p); p += 2; if ( format != 1 ) { @@ -179,11 +180,11 @@ ASDCP::Wav::SimpleWaveHeader::ReadFromBuffer(const byte_t* buf, ui32_t buf_len, return RESULT_RAW_FORMAT; } - nchannels = ASDCP_i16_LE(*(ui16_t*)p); p += 2; - samplespersec = ASDCP_i32_LE(*(ui32_t*)p); p += 4; - avgbps = ASDCP_i32_LE(*(ui32_t*)p); p += 4; - blockalign = ASDCP_i16_LE(*(ui16_t*)p); p += 2; - bitspersample = ASDCP_i16_LE(*(ui16_t*)p); p += 2; + nchannels = KM_i16_LE(*(ui16_t*)p); p += 2; + samplespersec = KM_i32_LE(*(ui32_t*)p); p += 4; + avgbps = KM_i32_LE(*(ui32_t*)p); p += 4; + blockalign = KM_i16_LE(*(ui16_t*)p); p += 2; + bitspersample = KM_i16_LE(*(ui16_t*)p); p += 2; p += chunk_size - 16; } else @@ -230,7 +231,7 @@ Rat_to_extended(ASDCP::Rational rate, byte_t* buf) value <<= 1; } - *(ui32_t*)(buf+2) = ASDCP_i32_BE(value); + *(ui32_t*)(buf+2) = KM_i32_BE(value); } // @@ -238,7 +239,7 @@ ASDCP::Rational extended_to_Rat(const byte_t* buf) { ui32_t last = 0; - ui32_t mantissa = ASDCP_i32_BE(*(ui32_t*)(buf+2)); + ui32_t mantissa = KM_i32_BE(*(ui32_t*)(buf+2)); byte_t exp = 30 - *(buf+1); @@ -271,7 +272,7 @@ ASDCP::AIFF::SimpleAIFFHeader::FillADesc(ASDCP::PCM::AudioDescriptor& ADesc, ASD // ASDCP::Result_t -ASDCP::AIFF::SimpleAIFFHeader::ReadFromFile(const ASDCP::FileReader& InFile, ui32_t* data_start) +ASDCP::AIFF::SimpleAIFFHeader::ReadFromFile(const Kumu::FileReader& InFile, ui32_t* data_start) { ui32_t read_count = 0; ui32_t local_data_start = 0; @@ -306,7 +307,7 @@ ASDCP::AIFF::SimpleAIFFHeader::ReadFromBuffer(const byte_t* buf, ui32_t buf_len, return RESULT_RAW_FORMAT; } - ui32_t RIFF_len = ASDCP_i32_BE(*(ui32_t*)p); p += 4; + ui32_t RIFF_len = KM_i32_BE(*(ui32_t*)p); p += 4; fourcc test_AIFF(p); p += 4; if ( test_AIFF != FCC_AIFF ) @@ -320,13 +321,13 @@ ASDCP::AIFF::SimpleAIFFHeader::ReadFromBuffer(const byte_t* buf, ui32_t buf_len, while ( p < end_p ) { test_fcc = fourcc(p); p += 4; - ui32_t chunk_size = ASDCP_i32_BE(*(ui32_t*)p); p += 4; + ui32_t chunk_size = KM_i32_BE(*(ui32_t*)p); p += 4; if ( test_fcc == FCC_COMM ) { - numChannels = ASDCP_i16_BE(*(ui16_t*)p); p += 2; - numSampleFrames = ASDCP_i32_BE(*(ui32_t*)p); p += 4; - sampleSize = ASDCP_i16_BE(*(ui16_t*)p); p += 2; + numChannels = KM_i16_BE(*(ui16_t*)p); p += 2; + numSampleFrames = KM_i32_BE(*(ui32_t*)p); p += 4; + sampleSize = KM_i16_BE(*(ui16_t*)p); p += 2; memcpy(sampleRate, p, 10); p += 10; } @@ -338,7 +339,7 @@ ASDCP::AIFF::SimpleAIFFHeader::ReadFromBuffer(const byte_t* buf, ui32_t buf_len, return RESULT_RAW_FORMAT; } - ui32_t offset = ASDCP_i32_BE(*(ui32_t*)p); p += 4; + ui32_t offset = KM_i32_BE(*(ui32_t*)p); p += 4; p += 4; // blockSize; data_len = chunk_size - 8; @@ -32,7 +32,8 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef _WAV_H_ #define _WAV_H_ -#include <FileIO.h> +#include <KM_fileio.h> +#include <AS_DCP.h> namespace ASDCP { @@ -73,7 +74,7 @@ namespace ASDCP } Result_t ReadFromBuffer(const byte_t* buf, ui32_t buf_len, ui32_t* data_start); - Result_t ReadFromFile(const ASDCP::FileReader& InFile, ui32_t* data_start); + Result_t ReadFromFile(const Kumu::FileReader& InFile, ui32_t* data_start); void FillADesc(ASDCP::PCM::AudioDescriptor& ADesc, Rational PictureRate) const; }; @@ -108,8 +109,8 @@ namespace ASDCP SimpleWaveHeader(ASDCP::PCM::AudioDescriptor& ADesc); Result_t ReadFromBuffer(const byte_t* buf, ui32_t buf_len, ui32_t* data_start); - Result_t ReadFromFile(const ASDCP::FileReader& InFile, ui32_t* data_start); - Result_t WriteToFile(ASDCP::FileWriter& OutFile) const; + Result_t ReadFromFile(const Kumu::FileReader& InFile, ui32_t* data_start); + Result_t WriteToFile(Kumu::FileWriter& OutFile) const; void FillADesc(ASDCP::PCM::AudioDescriptor& ADesc, Rational PictureRate) const; }; diff --git a/src/WavFileWriter.h b/src/WavFileWriter.h index 40d23ba..b246f3c 100755 --- a/src/WavFileWriter.h +++ b/src/WavFileWriter.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2005, John Hurst +Copyright (c) 2005-2006, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without @@ -29,7 +29,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \brief demux and write PCM data to WAV file(s) */ -#include <FileIO.h> +#include <KM_fileio.h> #include <Wav.h> #include <list> @@ -40,7 +40,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. class WavFileWriter { ASDCP::PCM::AudioDescriptor m_ADesc; - std::list<ASDCP::FileWriter*> m_OutFile; + std::list<Kumu::FileWriter*> m_OutFile; ASDCP_NO_COPY_CONSTRUCT(WavFileWriter); public: @@ -73,7 +73,7 @@ class WavFileWriter for ( ui32_t i = 0; i < file_count && ASDCP_SUCCESS(result); i++ ) { snprintf(filename, 256, "%s_%lu.wav", file_root, (i + 1)); - m_OutFile.push_back(new ASDCP::FileWriter); + m_OutFile.push_back(new Kumu::FileWriter); result = m_OutFile.back()->OpenWrite(filename); if ( ASDCP_SUCCESS(result) ) @@ -91,7 +91,7 @@ class WavFileWriter { ui32_t write_count; ASDCP::Result_t result = ASDCP::RESULT_OK; - std::list<ASDCP::FileWriter*>::iterator fi; + std::list<Kumu::FileWriter*>::iterator fi; assert(! m_OutFile.empty()); ui32_t sample_size = ASDCP::PCM::CalcSampleSize(m_ADesc); diff --git a/src/asdcp-test.cpp b/src/asdcp-test.cpp index c048a30..50a02ef 100755 --- a/src/asdcp-test.cpp +++ b/src/asdcp-test.cpp @@ -50,11 +50,10 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <iostream> #include <assert.h> -#include <FileIO.h> +#include <KM_fileio.h> +#include <KM_prng.h> #include <PCMParserList.h> #include <WavFileWriter.h> -#include <hex_utils.h> -#include <AS_DCP_UUID.h> #include <MXF.h> #include <Metadata.h> @@ -138,46 +137,46 @@ USAGE: %s [-i [-H, -n]|-c <filename> [-p <rate>, -e, -M, -R]|-x <root-name> [-m] fprintf(stream, "\ Major modes:\n\ - -i - show file info\n\ - -c <filename> - create AS-DCP file from input(s)\n\ - -x <root-name> - extract essence from AS-DCP file to named file(s)\n\ - -g - generate a random 16 byte value to stdout\n\ - -u - generate a random UUID value to stdout\n\ + -i - Show file info\n\ + -c <filename> - Create AS-DCP file from input(s)\n\ + -x <root-name> - Extract essence from AS-DCP file to named file(s)\n\ + -g - Generate a random 16 byte value to stdout\n\ + -u - Generate a random UUID value to stdout\n\ -G - Perform GOP start lookup test on MPEG file\n\ - -V - show version\n\ - -h - show help\n\ + -V - Show version\n\ + -h - Show help\n\ \n"); fprintf(stream, "\ Security Options:\n\ - -j <key-id-str> - write key ID instead of creating a random value\n\ - -k <key-string> - use key for ciphertext operations\n\ - -e - encrypt MPEG or JP2K headers (default)\n\ - -E - do not encrypt MPEG or JP2K headers\n\ - -M - do not create HMAC values when writing\n\ + -j <key-id-str> - Write key ID instead of creating a random value\n\ + -k <key-string> - Use key for ciphertext operations\n\ + -e - Encrypt MPEG or JP2K headers (default)\n\ + -E - Do not encrypt MPEG or JP2K headers\n\ + -M - Do not create HMAC values when writing\n\ -m - verify HMAC values when reading\n\ \n"); fprintf(stream, "\ Read/Write Options:\n\ -b <buf-size> - Size (in bytes) of the picture frame buffer, default: 2097152 (2MB)\n\ - -f <frame-num> - starting frame number, default 0\n\ - -d <duration> - number of frames to process, default all\n\ + -f <frame-num> - Starting frame number, default 0\n\ + -d <duration> - Number of frames to process, default all\n\ -p <rate> - fps of picture when wrapping PCM or JP2K:, use one of [23|24|48], 24 is default\n\ -L - Write SMPTE UL values instead of MXF Interop\n\ -R - Repeat the first frame over the entire file (picture essence only, requires -c, -d)\n\ -S - Split Wave essence to stereo WAV files during extract (default = multichannel WAV)\n\ - -W - read input file only, do not write source file\n\ + -W - Read input file only, do not write source file\n\ \n"); fprintf(stream, "\ Info Options:\n\ - -H - show MXF header metadata, used with option -i\n\ - -n - show index, used with option -i\n\ + -H - Show MXF header metadata, used with option -i\n\ + -n - Show index, used with option -i\n\ \n\ Other Options:\n\ - -s <number> - number of bytes of frame buffer to be dumped as hex to stderr (use with -v)\n\ - -v - verbose, show extra detail during run\n\ + -s <number> - Number of bytes of frame buffer to be dumped as hex to stderr (use with -v)\n\ + -v - Verbose, show extra detail during run\n\ \n\ NOTES: o There is no option grouping, all options must be distinct arguments.\n\ o All option arguments must be separated from the option by whitespace.\n\ @@ -296,7 +295,7 @@ public: TEST_EXTRA_ARG(i, 'k'); { ui32_t length; - hex2bin(argv[i], key_value, KeyLen, &length); + Kumu::hex2bin(argv[i], key_value, KeyLen, &length); if ( length != KeyLen ) { @@ -310,7 +309,7 @@ public: TEST_EXTRA_ARG(i, 'j'); { ui32_t length; - hex2bin(argv[i], key_id_value, UUIDlen, &length); + Kumu::hex2bin(argv[i], key_id_value, UUIDlen, &length); if ( length != UUIDlen ) { @@ -402,7 +401,7 @@ write_MPEG2_file(CommandOptions& Options) MPEG2::MXFWriter Writer; MPEG2::VideoDescriptor VDesc; byte_t IV_buf[CBC_BLOCK_SIZE]; - FortunaRNG RNG; + Kumu::FortunaRNG RNG; // set up essence parser Result_t result = Parser.OpenRead(Options.filenames[0]); @@ -424,18 +423,18 @@ write_MPEG2_file(CommandOptions& Options) if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag ) { WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here - GenRandomUUID(RNG, Info.AssetUUID); + Kumu::GenRandomUUID(Info.AssetUUID); if ( Options.use_smpte_labels ) { - Info.LabelSetType = LS_MXF_INTEROP; + Info.LabelSetType = LS_MXF_SMPTE; fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n"); } // configure encryption if( Options.key_flag ) { - GenRandomUUID(RNG, Info.ContextID); + Kumu::GenRandomUUID(Info.ContextID); Info.EncryptedEssence = true; if ( Options.key_id_flag ) @@ -453,7 +452,7 @@ write_MPEG2_file(CommandOptions& Options) { Info.UsesHMAC = true; HMAC = new HMACContext; - result = HMAC->InitKey(Options.key_value); + result = HMAC->InitKey(Options.key_value, Info.LabelSetType); } } @@ -517,7 +516,7 @@ read_MPEG2_file(CommandOptions& Options) HMACContext* HMAC = 0; MPEG2::MXFReader Reader; MPEG2::FrameBuffer FrameBuffer(Options.fb_size); - FileWriter OutFile; + Kumu::FileWriter OutFile; ui32_t frame_count = 0; Result_t result = Reader.OpenRead(Options.filenames[0]); @@ -555,7 +554,7 @@ read_MPEG2_file(CommandOptions& Options) if ( Info.UsesHMAC ) { HMAC = new HMACContext; - result = HMAC->InitKey(Options.key_value); + result = HMAC->InitKey(Options.key_value, Info.LabelSetType); } else { @@ -649,8 +648,8 @@ write_JP2K_file(CommandOptions& Options) JP2K::FrameBuffer FrameBuffer(Options.fb_size); JP2K::PictureDescriptor PDesc; JP2K::SequenceParser Parser; - byte_t IV_buf[CBC_BLOCK_SIZE]; - FortunaRNG RNG; + byte_t IV_buf[CBC_BLOCK_SIZE]; + Kumu::FortunaRNG RNG; // set up essence parser Result_t result = Parser.OpenRead(Options.filenames[0]); @@ -673,18 +672,18 @@ write_JP2K_file(CommandOptions& Options) if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag ) { WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here - GenRandomUUID(RNG, Info.AssetUUID); + Kumu::GenRandomUUID(Info.AssetUUID); if ( Options.use_smpte_labels ) { - Info.LabelSetType = LS_MXF_INTEROP; + Info.LabelSetType = LS_MXF_SMPTE; fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n"); } // configure encryption if( Options.key_flag ) { - GenRandomUUID(RNG, Info.ContextID); + Kumu::GenRandomUUID(Info.ContextID); Info.EncryptedEssence = true; if ( Options.key_id_flag ) @@ -702,7 +701,7 @@ write_JP2K_file(CommandOptions& Options) { Info.UsesHMAC = true; HMAC = new HMACContext; - result = HMAC->InitKey(Options.key_value); + result = HMAC->InitKey(Options.key_value, Info.LabelSetType); } } @@ -796,7 +795,7 @@ read_JP2K_file(CommandOptions& Options) if ( Info.UsesHMAC ) { HMAC = new HMACContext; - result = HMAC->InitKey(Options.key_value); + result = HMAC->InitKey(Options.key_value, Info.LabelSetType); } else { @@ -815,7 +814,7 @@ read_JP2K_file(CommandOptions& Options) if ( ASDCP_SUCCESS(result) ) { - FileWriter OutFile; + Kumu::FileWriter OutFile; char filename[256]; ui32_t write_count; snprintf(filename, 256, "%s%06lu.j2c", Options.file_root, i); @@ -842,15 +841,15 @@ read_JP2K_file(CommandOptions& Options) Result_t write_PCM_file(CommandOptions& Options) { - AESEncContext* Context = 0; - HMACContext* HMAC = 0; - PCMParserList Parser; - PCM::MXFWriter Writer; - PCM::FrameBuffer FrameBuffer; + AESEncContext* Context = 0; + HMACContext* HMAC = 0; + PCMParserList Parser; + PCM::MXFWriter Writer; + PCM::FrameBuffer FrameBuffer; PCM::AudioDescriptor ADesc; - Rational PictureRate = Options.PictureRate(); - byte_t IV_buf[CBC_BLOCK_SIZE]; - FortunaRNG RNG; + Rational PictureRate = Options.PictureRate(); + byte_t IV_buf[CBC_BLOCK_SIZE]; + Kumu::FortunaRNG RNG; // set up essence parser Result_t result = Parser.OpenRead(Options.file_count, Options.filenames, PictureRate); @@ -876,18 +875,18 @@ write_PCM_file(CommandOptions& Options) if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag ) { WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here - GenRandomUUID(RNG, Info.AssetUUID); + Kumu::GenRandomUUID(Info.AssetUUID); if ( Options.use_smpte_labels ) { - Info.LabelSetType = LS_MXF_INTEROP; + Info.LabelSetType = LS_MXF_SMPTE; fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n"); } // configure encryption if( Options.key_flag ) { - GenRandomUUID(RNG, Info.ContextID); + Kumu::GenRandomUUID(Info.ContextID); Info.EncryptedEssence = true; if ( Options.key_id_flag ) @@ -905,7 +904,7 @@ write_PCM_file(CommandOptions& Options) { Info.UsesHMAC = true; HMAC = new HMACContext; - result = HMAC->InitKey(Options.key_value); + result = HMAC->InitKey(Options.key_value, Info.LabelSetType); } } @@ -1006,7 +1005,7 @@ read_PCM_file(CommandOptions& Options) return RESULT_FAIL; } - last_frame = xmin(Options.start_frame + last_frame, ADesc.ContainerDuration); + last_frame = Kumu::xmin(Options.start_frame + last_frame, ADesc.ContainerDuration); } ADesc.ContainerDuration = last_frame - Options.start_frame; @@ -1026,7 +1025,7 @@ read_PCM_file(CommandOptions& Options) if ( Info.UsesHMAC ) { HMAC = new HMACContext; - result = HMAC->InitKey(Options.key_value); + result = HMAC->InitKey(Options.key_value, Info.LabelSetType); } else { @@ -1165,7 +1164,7 @@ show_file_info(CommandOptions& Options) else { fprintf(stderr, "File is not AS-DCP: %s\n", Options.filenames[0]); - FileReader Reader; + Kumu::FileReader Reader; MXF::OPAtomHeader TestHeader; result = Reader.OpenRead(Options.filenames[0]); @@ -1226,22 +1225,19 @@ main(int argc, const char** argv) } else if ( Options.genkey_flag ) { - FortunaRNG RNG; + Kumu::FortunaRNG RNG; byte_t bin_buf[KeyLen]; char str_buf[40]; RNG.FillRandom(bin_buf, KeyLen); - printf("%s\n", bin2hex(bin_buf, KeyLen, str_buf, 40)); + printf("%s\n", Kumu::bin2hex(bin_buf, KeyLen, str_buf, 40)); } else if ( Options.genid_flag ) { - FortunaRNG RNG; - byte_t bin_buf[KeyLen]; + UUID TmpID; + Kumu::GenRandomValue(TmpID); char str_buf[40]; - - GenRandomUUID(RNG, bin_buf); - bin2hex(bin_buf, KeyLen, str_buf, 40); - printf("%s\n", hyphenate_UUID(str_buf, 40)); + printf("%s\n", TmpID.EncodeHex(str_buf, 40)); } else if ( Options.extract_flag ) { @@ -1305,13 +1301,13 @@ main(int argc, const char** argv) } } - if ( result != RESULT_OK ) + if ( ASDCP_FAILURE(result) ) { fputs("Program stopped on error.\n", stderr); if ( result != RESULT_FAIL ) { - fputs(GetResultString(result), stderr); + fputs(result, stderr); fputc('\n', stderr); } diff --git a/src/blackwave.cpp b/src/blackwave.cpp new file mode 100644 index 0000000..c84774f --- /dev/null +++ b/src/blackwave.cpp @@ -0,0 +1,245 @@ +/* +Copyright (c) 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 wavsplit.cpp + \version $Id$ + \brief Black WAV file generator +*/ + +#include "Wav.h" +#include <assert.h> + +using namespace ASDCP; + +//------------------------------------------------------------------------------------------ +// +// command line option parser class + +static const char* PACKAGE = "wavsplit"; // program name for messages + +// Macros used to test command option data state. + +// Increment the iterator, test for an additional non-option command line argument. +// Causes the caller to return if there are no remaining arguments or if the next +// argument begins with '-'. +#define TEST_EXTRA_ARG(i,c) if ( ++i >= argc || argv[(i)][0] == '-' ) \ + { \ + fprintf(stderr, "Argument not found for option %c.\n", (c)); \ + return; \ + } +// +void +banner(FILE* stream = stderr) +{ + fprintf(stream, "\n\ +%s (asdcplib %s)\n\n\ +Copyright (c) 2005-2006 John Hurst\n\n\ +wavesplit is part of asdcplib.\n\ +asdcplib may be copied only under the terms of the license found at\n\ +the top of every file in the asdcplib distribution kit.\n\n\ +Specify the -h (help) option for further information about %s\n\n", + PACKAGE, ASDCP::Version(), PACKAGE); +} + +// +void +usage(FILE* stream = stderr) +{ + fprintf(stream, "\ +USAGE: %s [-v|-h[-d]] <filename>\n\ +\n\ + -V - Show version\n\ + -h - Show help\n\ + -d <duration> - Number of 2k-sample frames to process, default 1440\n\ +\n\ +Other Options:\n\ + -v - Verbose, show extra detail during run\n\ +\n\ + NOTES: o There is no option grouping, all options must be distinct arguments.\n\ + o All option arguments must be separated from the option by whitespace.\n\ +\n", PACKAGE); +} + +// +// +class CommandOptions +{ + CommandOptions(); + +public: + bool error_flag; // true if the given options are in error or not complete + bool verbose_flag; // true if the verbose option was selected + bool version_flag; // true if the version display option was selected + bool help_flag; // true if the help display option was selected + ui32_t duration; // number of frames to be processed + const char* filename; // filename prefix for files written by the extract mode + + CommandOptions(int argc, const char** argv) : + error_flag(true), verbose_flag(false), version_flag(false), help_flag(false), + duration(1440), filename(0) + { + for ( int i = 1; i < argc; i++ ) + { + if ( argv[i][0] == '-' && isalpha(argv[i][1]) && argv[i][2] == 0 ) + { + switch ( argv[i][1] ) + { + case 'V': version_flag = true; break; + case 'h': help_flag = true; break; + case 'v': verbose_flag = true; break; + + case 'd': + TEST_EXTRA_ARG(i, 'd'); + duration = atoi(argv[i]); // TODO: test for negative value, should use strtol() + break; + + default: + fprintf(stderr, "Unrecognized option: %c\n", argv[i][1]); + return; + } + } + else + { + if ( filename ) + { + fprintf(stderr, "Unexpected extra filename.\n"); + return; + } + + filename = argv[i]; + } + } + + if ( filename == 0 ) + { + fputs("Output filename required.\n", stderr); + return; + } + + error_flag = false; + } +}; + + +// +// +Result_t +make_black_wav_file(CommandOptions& Options) +{ + PCM::FrameBuffer FrameBuffer; + PCM::AudioDescriptor ADesc; + + ADesc.SampleRate = Rational(24,1); + ADesc.AudioSamplingRate = ASDCP::SampleRate_48k; + ADesc.Locked = 0; + ADesc.ChannelCount = 1; + ADesc.QuantizationBits = 24; + ADesc.BlockAlign = 18; + ADesc.AvgBps = 86400; + ADesc.LinkedTrackID = 1; + ADesc.ContainerDuration = Options.duration; + + // fill the frame buffer with a frame (2000 samples) of black + FrameBuffer.Capacity(PCM::CalcFrameBufferSize(ADesc)); + memset(FrameBuffer.Data(), 0, FrameBuffer.Capacity()); + FrameBuffer.Size(FrameBuffer.Capacity()); + + if ( 1 ) // Options.verbose_flag ) + { + fprintf(stderr, "48Khz PCM Audio, %s fps (%lu spf)\n", "24", + PCM::CalcSamplesPerFrame(ADesc)); + fputs("AudioDescriptor:\n", stderr); + PCM::AudioDescriptorDump(ADesc); + } + + // set up output file + Kumu::FileWriter OutFile; + Result_t result = OutFile.OpenWrite(Options.filename); + + if ( ASDCP_SUCCESS(result) ) + { + Wav::SimpleWaveHeader WavHeader(ADesc); + result = WavHeader.WriteToFile(OutFile); + } + + if ( ASDCP_SUCCESS(result) ) + { + ui32_t write_count = 0; + ui32_t duration = 0; + + while ( ASDCP_SUCCESS(result) && (duration++ < Options.duration) ) + { + result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count); + } + + if ( result == RESULT_ENDOFFILE ) + result = RESULT_OK; + } + + return RESULT_OK; +} + + +// +int +main(int argc, const char** argv) +{ + Result_t result = RESULT_OK; + CommandOptions Options(argc, argv); + + if ( Options.help_flag ) + { + usage(); + return 0; + } + + if ( Options.error_flag ) + return 3; + + if ( Options.version_flag ) + banner(); + + else + result = make_black_wav_file(Options); + + if ( result != RESULT_OK ) + { + fputs("Program stopped on error.\n", stderr); + + if ( result != RESULT_FAIL ) + { + fputs(result, stderr); + fputc('\n', stderr); + } + + return 1; + } + + return 0; +} + + +// diff --git a/src/h__Reader.cpp b/src/h__Reader.cpp index 7851953..268f308 100755 --- a/src/h__Reader.cpp +++ b/src/h__Reader.cpp @@ -112,15 +112,11 @@ ASDCP::h__Reader::OpenMXFRead(const char* filename) // partition and read off the partition pack if ( m_HeaderPart.m_RIP.PairArray.size() == 3 ) { - fprintf(stderr, "Three part!\n"); Array<RIP::Pair>::iterator r_i = m_HeaderPart.m_RIP.PairArray.begin(); r_i++; m_File.Seek((*r_i).ByteOffset); result = m_BodyPart.InitFromFile(m_File); - m_BodyPart.Dump(); - // TODO: check the partition pack to make sure it is - // really a body with a single essence container } m_EssenceStart = m_File.Tell(); @@ -163,7 +159,7 @@ public: inline const ui64_t Length() { return m_ValueLength; } inline const ui64_t KLLength() { return m_KLLength; } - Result_t ReadKLFromFile(ASDCP::FileReader& Reader) + Result_t ReadKLFromFile(Kumu::FileReader& Reader) { ui32_t read_count; ui32_t header_length = SMPTE_UL_LENGTH + MXF_BER_LENGTH; @@ -197,7 +193,7 @@ ASDCP::h__Reader::ReadEKLVPacket(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf, // get frame position and go read the frame's key and length Result_t result = RESULT_OK; KLReader Reader; - ASDCP::fpos_t FilePosition = m_EssenceStart + TmpEntry.StreamOffset; + Kumu::fpos_t FilePosition = m_EssenceStart + TmpEntry.StreamOffset; if ( FilePosition != m_LastPosition ) { @@ -244,7 +240,7 @@ ASDCP::h__Reader::ReadEKLVPacket(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf, byte_t* ess_p = m_CtFrameBuf.Data(); // read context ID length - if ( ! read_test_BER(&ess_p, UUIDlen) ) + if ( ! Kumu::read_test_BER(&ess_p, UUIDlen) ) return RESULT_FORMAT; // test the context ID @@ -256,14 +252,14 @@ ASDCP::h__Reader::ReadEKLVPacket(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf, ess_p += UUIDlen; // read PlaintextOffset length - if ( ! read_test_BER(&ess_p, sizeof(ui64_t)) ) + if ( ! Kumu::read_test_BER(&ess_p, sizeof(ui64_t)) ) return RESULT_FORMAT; - ui32_t PlaintextOffset = (ui32_t)ASDCP_i64_BE(cp2i<ui64_t>(ess_p)); + ui32_t PlaintextOffset = (ui32_t)KM_i64_BE(Kumu::cp2i<ui64_t>(ess_p)); ess_p += sizeof(ui64_t); // read essence UL length - if ( ! read_test_BER(&ess_p, SMPTE_UL_LENGTH) ) + if ( ! Kumu::read_test_BER(&ess_p, SMPTE_UL_LENGTH) ) return RESULT_FORMAT; // test essence UL @@ -272,7 +268,7 @@ ASDCP::h__Reader::ReadEKLVPacket(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf, char strbuf[IntBufferLen]; const MDDEntry* Entry = Dict::FindUL(Key.Value()); if ( Entry == 0 ) - DefaultLogSink().Warn("Unexpected Essence UL found: %s.\n", Key.ToString(strbuf)); + DefaultLogSink().Warn("Unexpected Essence UL found: %s.\n", Key.EncodeString(strbuf, IntBufferLen)); else DefaultLogSink().Warn("Unexpected Essence UL found: %s.\n", Entry->name); return RESULT_FORMAT; @@ -280,10 +276,10 @@ ASDCP::h__Reader::ReadEKLVPacket(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf, ess_p += SMPTE_UL_LENGTH; // read SourceLength length - if ( ! read_test_BER(&ess_p, sizeof(ui64_t)) ) + if ( ! Kumu::read_test_BER(&ess_p, sizeof(ui64_t)) ) return RESULT_FORMAT; - ui32_t SourceLength = (ui32_t)ASDCP_i64_BE(cp2i<ui64_t>(ess_p)); + ui32_t SourceLength = (ui32_t)KM_i64_BE(Kumu::cp2i<ui64_t>(ess_p)); ess_p += sizeof(ui64_t); assert(SourceLength); @@ -296,7 +292,7 @@ ASDCP::h__Reader::ReadEKLVPacket(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf, ui32_t esv_length = calc_esv_length(SourceLength, PlaintextOffset); // read ESV length - if ( ! read_test_BER(&ess_p, esv_length) ) + if ( ! Kumu::read_test_BER(&ess_p, esv_length) ) { DefaultLogSink().Error("read_test_BER did not return %lu\n", esv_length); return RESULT_FORMAT; @@ -377,7 +373,7 @@ ASDCP::h__Reader::ReadEKLVPacket(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf, char strbuf[IntBufferLen]; const MDDEntry* Entry = Dict::FindUL(Key.Value()); if ( Entry == 0 ) - DefaultLogSink().Warn("Unexpected Essence UL found: %s.\n", Key.ToString(strbuf)); + DefaultLogSink().Warn("Unexpected Essence UL found: %s.\n", Key.EncodeString(strbuf, IntBufferLen)); else DefaultLogSink().Warn("Unexpected Essence UL found: %s.\n", Entry->name); return RESULT_FORMAT; diff --git a/src/h__Writer.cpp b/src/h__Writer.cpp index 1449748..7d874c0 100755 --- a/src/h__Writer.cpp +++ b/src/h__Writer.cpp @@ -30,7 +30,6 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "AS_DCP_internal.h" -#include "MemIO.h" #include "KLV.h" using namespace ASDCP; @@ -120,7 +119,7 @@ ASDCP::h__Writer::WriteMXFHeader(const std::string& PackageLabel, const UL& Wrap m_HeaderPart.AddChildObject(Ident); m_HeaderPart.m_Preface->Identifications.push_back(Ident->InstanceUID); - Ident->ThisGenerationUID.GenRandomValue(); + Kumu::GenRandomValue(Ident->ThisGenerationUID); Ident->CompanyName = m_Info.CompanyName.c_str(); Ident->ProductName = m_Info.ProductName.c_str(); Ident->VersionString = m_Info.ProductVersion.c_str(); @@ -315,11 +314,11 @@ Result_t ASDCP::h__Writer::WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf, const byte_t* EssenceUL, AESEncContext* Ctx, HMACContext* HMAC) { - Result_t result; + Result_t result = RESULT_OK; IntegrityPack IntPack; byte_t overhead[128]; - MemIOWriter Overhead(overhead, 128); + Kumu::MemIOWriter Overhead(overhead, 128); if ( FrameBuf.Size() == 0 ) { @@ -371,12 +370,12 @@ ASDCP::h__Writer::WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf, const byte Overhead.WriteUi64BE(FrameBuf.Size()); // write SourceLength Overhead.WriteBER(m_CtFrameBuf.Size(), MXF_BER_LENGTH); // write ESV length - result = m_File.Writev(Overhead.Data(), Overhead.Size()); + result = m_File.Writev(Overhead.Data(), Overhead.Length()); } if ( ASDCP_SUCCESS(result) ) { - m_StreamOffset += Overhead.Size(); + m_StreamOffset += Overhead.Length(); // write encrypted source value result = m_File.Writev((byte_t*)m_CtFrameBuf.RoData(), m_CtFrameBuf.Size()); } @@ -386,7 +385,7 @@ ASDCP::h__Writer::WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf, const byte m_StreamOffset += m_CtFrameBuf.Size(); byte_t hmoverhead[512]; - MemIOWriter HMACOverhead(hmoverhead, 512); + Kumu::MemIOWriter HMACOverhead(hmoverhead, 512); // write the HMAC if ( m_Info.UsesHMAC ) @@ -400,21 +399,21 @@ ASDCP::h__Writer::WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf, const byte } // write HMAC - result = m_File.Writev(HMACOverhead.Data(), HMACOverhead.Size()); - m_StreamOffset += HMACOverhead.Size(); + result = m_File.Writev(HMACOverhead.Data(), HMACOverhead.Length()); + m_StreamOffset += HMACOverhead.Length(); } } else { Overhead.WriteRaw((byte_t*)EssenceUL, SMPTE_UL_LENGTH); Overhead.WriteBER(FrameBuf.Size(), MXF_BER_LENGTH); - result = m_File.Writev(Overhead.Data(), Overhead.Size()); + result = m_File.Writev(Overhead.Data(), Overhead.Length()); if ( ASDCP_SUCCESS(result) ) result = m_File.Writev((byte_t*)FrameBuf.RoData(), FrameBuf.Size()); if ( ASDCP_SUCCESS(result) ) - m_StreamOffset += Overhead.Size() + FrameBuf.Size(); + m_StreamOffset += Overhead.Length() + FrameBuf.Size(); } if ( ASDCP_SUCCESS(result) ) diff --git a/src/klvwalk.cpp b/src/klvwalk.cpp index b5b3cea..395aa54 100755 --- a/src/klvwalk.cpp +++ b/src/klvwalk.cpp @@ -31,7 +31,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "AS_DCP.h" #include "MXF.h" -#include "hex_utils.h" +#include <KM_log.h> #include <stdlib.h> #include <string.h> #include <ctype.h> @@ -40,15 +40,14 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <sys/stat.h> using namespace ASDCP; +using Kumu::DefaultLogSink; + +const char* PACKAGE = "klvwalk"; //------------------------------------------------------------------------------------------ // -// There is no header file thet defines this function. -// You just have to know it's there... -void set_debug_mode(bool info_mode, bool debug_mode); - int main(int argc, char** argv) @@ -56,19 +55,24 @@ main(int argc, char** argv) Result_t result = RESULT_OK; bool read_mxf = false; int arg_i = 1; - set_debug_mode(true, true); - if ( strcmp(argv[1], "-r") == 0 ) + if ( argc > arg_i && strcmp(argv[1], "-r") == 0 ) { read_mxf = true; arg_i++; } + if ( argc - arg_i != 1 ) + { + fprintf(stderr, "usage: %s [-r] <infile>\n", PACKAGE); + return 1; + } + fprintf(stderr, "Opening file %s\n", argv[arg_i]); if ( read_mxf ) { - ASDCP::FileReader Reader; + Kumu::FileReader Reader; ASDCP::MXF::OPAtomHeader Header; result = Reader.OpenRead(argv[arg_i]); @@ -95,7 +99,7 @@ main(int argc, char** argv) } else // dump klv { - ASDCP::FileReader Reader; + Kumu::FileReader Reader; KLVFilePacket KP; result = Reader.OpenRead(argv[arg_i]); @@ -119,7 +123,7 @@ main(int argc, char** argv) if ( result != RESULT_FAIL ) { - fputs(GetResultString(result), stderr); + fputs(result, stderr); fputc('\n', stderr); } diff --git a/src/wavesplit.cpp b/src/wavesplit.cpp new file mode 100755 index 0000000..2a40e1e --- /dev/null +++ b/src/wavesplit.cpp @@ -0,0 +1,369 @@ +/* +Copyright (c) 2005-2006, 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 wavesplit.cpp + \version $Id$ + \brief WAV file splitter +*/ + +#include <AS_DCP.h> +#include <WavFileWriter.h> +#include <assert.h> + +using namespace ASDCP; + +//------------------------------------------------------------------------------------------ +// +// command line option parser class + +static const char* PACKAGE = "wavesplit"; // program name for messages + +// Macros used to test command option data state. + +// True if a major mode has already been selected. +#define TEST_MAJOR_MODE() ( create_flag ) + +// Causes the caller to return if a major mode has already been selected, +// otherwise sets the given flag. +#define TEST_SET_MAJOR_MODE(f) if ( TEST_MAJOR_MODE() ) \ + { \ + fputs("Conflicting major mode, choose one of -(ic)).\n", stderr); \ + return; \ + } \ + (f) = true; + +// Increment the iterator, test for an additional non-option command line argument. +// Causes the caller to return if there are no remaining arguments or if the next +// argument begins with '-'. +#define TEST_EXTRA_ARG(i,c) if ( ++i >= argc || argv[(i)][0] == '-' ) \ + { \ + fprintf(stderr, "Argument not found for option %c.\n", (c)); \ + return; \ + } +// +void +banner(FILE* stream = stderr) +{ + fprintf(stream, "\n\ +%s (asdcplib %s)\n\n\ +Copyright (c) 2005-2006 John Hurst\n\n\ +wavesplit is part of asdcplib.\n\ +asdcplib may be copied only under the terms of the license found at\n\ +the top of every file in the asdcplib distribution kit.\n\n\ +Specify the -h (help) option for further information about %s\n\n", + PACKAGE, ASDCP::Version(), PACKAGE, PACKAGE); +} + +// +void +usage(FILE* stream = stderr) +{ + fprintf(stream, "\ +USAGE: %s [-i|-c <root-name> [-v]] <filename>\n\ +\n\ +Major modes:\n\ + -c <root-name> - Create a WAV file for each channel in the input file (default is two channel files)\n\ + -V - Show version\n\ + -h - Show help\n\ +\n\ +Read/Write Options:\n\ + -f <frame-num> - Starting frame number, default 0\n\ + -d <duration> - Number of frames to process, default all\n\ + -v - Print extra info while processing\n\ +\n\ + NOTES: o There is no option grouping, all options must be distinct arguments.\n\ + o All option arguments must be separated from the option by whitespace.\n\ +\n", PACKAGE); +} + +// +// +class CommandOptions +{ + CommandOptions(); + +public: + bool error_flag; // true if the given options are in error or not complete + bool create_flag; // true if the file create mode was selected + bool version_flag; // true if the version display option was selected + bool help_flag; // true if the help display option was selected + bool verbose_flag; // true for extra info during procesing + ui32_t start_frame; // frame number to begin processing + ui32_t duration; // number of frames to be processed + const char* file_root; // filename prefix for files written by the extract mode + const char* filename; // filename to be processed + + CommandOptions(int argc, const char** argv) : + error_flag(true), create_flag(false), + version_flag(false), help_flag(false), start_frame(0), + duration(0xffffffff), file_root(0), filename(0) + { + for ( int i = 1; i < argc; i++ ) + { + if ( argv[i][0] == '-' && isalpha(argv[i][1]) && argv[i][2] == 0 ) + { + switch ( argv[i][1] ) + { + case 'V': version_flag = true; break; + case 'h': help_flag = true; break; + case 'c': + TEST_SET_MAJOR_MODE(create_flag); + TEST_EXTRA_ARG(i, 'c'); + file_root = argv[i]; + break; + + case 'f': + TEST_EXTRA_ARG(i, 'f'); + start_frame = atoi(argv[i]); // TODO: test for negative value, should use strtol() + break; + + case 'd': + TEST_EXTRA_ARG(i, 'd'); + duration = atoi(argv[i]); // TODO: test for negative value, should use strtol() + break; + + default: + fprintf(stderr, "Unrecognized option: %c\n", argv[i][1]); + return; + } + } + else + { + if ( filename ) + { + fprintf(stderr, "Unexpected extra filename.\n"); + return; + } + + filename = argv[i]; + } + } + + if ( TEST_MAJOR_MODE() ) + { + if ( filename == 0 ) + { + fputs("Input filename required.\n", stderr); + return; + } + } + + if ( ! TEST_MAJOR_MODE() && ! help_flag && ! version_flag ) + { + fputs("No operation selected (use one of -(ic) or -h for help).\n", stderr); + return; + } + + error_flag = false; + } +}; + + +// +// +void +split_buffer(ui32_t sample_size, PCM::FrameBuffer& FrameBuffer, + PCM::FrameBuffer& L_FrameBuffer, PCM::FrameBuffer& R_FrameBuffer) +{ + assert((FrameBuffer.Size() % 2) == 0); + byte_t* p = FrameBuffer.Data(); + byte_t* end_p = p + FrameBuffer.Size(); + byte_t* lp = L_FrameBuffer.Data(); + byte_t* rp = R_FrameBuffer.Data(); + + for ( ; p < end_p; ) + { + memcpy(lp, p, sample_size); + lp += sample_size; + p += sample_size; + memcpy(rp, p, sample_size); + rp += sample_size; + p += sample_size; + } + + L_FrameBuffer.Size(L_FrameBuffer.Capacity()); + R_FrameBuffer.Size(R_FrameBuffer.Capacity()); +} + + +// +// +Result_t +split_wav_file(CommandOptions& Options) +{ + PCM::FrameBuffer FrameBuffer; + PCM::FrameBuffer L_FrameBuffer; + PCM::FrameBuffer R_FrameBuffer; + PCM::AudioDescriptor ADesc; + Rational PictureRate = EditRate_24; + PCM::WAVParser Parser; + + // set up essence parser + Result_t result = Parser.OpenRead(Options.filename, PictureRate); + + if ( ASDCP_SUCCESS(result) ) + { + Parser.FillAudioDescriptor(ADesc); + + ADesc.SampleRate = PictureRate; + ui32_t fb_size = PCM::CalcFrameBufferSize(ADesc); + assert((fb_size % 2) == 0); + FrameBuffer.Capacity(fb_size); + L_FrameBuffer.Capacity(fb_size/2); + R_FrameBuffer.Capacity(fb_size/2); + + if ( Options.verbose_flag ) + { + fprintf(stderr, "48Khz PCM Audio, %s fps (%lu spf)\n", "24", + PCM::CalcSamplesPerFrame(ADesc)); + fputs("AudioDescriptor:\n", stderr); + PCM::AudioDescriptorDump(ADesc); + } + + ADesc.ChannelCount = 1; + } + + // set up output files + Kumu::FileWriter L_OutFile; + Kumu::FileWriter R_OutFile; + + if ( ASDCP_SUCCESS(result) ) + { + char filename[256]; + sprintf(filename, "%s_l.wav", Options.file_root); + result = L_OutFile.OpenWrite(filename); + + if ( ASDCP_SUCCESS(result) ) + { + sprintf(filename, "%s_r.wav", Options.file_root); + result = R_OutFile.OpenWrite(filename); + } + } + + + if ( ASDCP_SUCCESS(result) ) + { + Wav::SimpleWaveHeader WavHeader(ADesc); + result = WavHeader.WriteToFile(L_OutFile); + + if ( ASDCP_SUCCESS(result) ) + result = WavHeader.WriteToFile(R_OutFile); + } + + if ( ASDCP_SUCCESS(result) ) + { + ui32_t write_count = 0; + ui32_t duration = 0; + + while ( ASDCP_SUCCESS(result) && (duration++ < Options.duration) ) + { + result = Parser.ReadFrame(FrameBuffer); + + if ( FrameBuffer.Size() != FrameBuffer.Capacity() ) + { + fprintf(stderr, "WARNING: Last frame read was short, PCM input is possibly not frame aligned.\n"); + fprintf(stderr, "Expecting %lu bytes, got %lu.\n", FrameBuffer.Capacity(), FrameBuffer.Size()); + result = RESULT_ENDOFFILE; + continue; + } + + if ( Options.verbose_flag ) + FrameBuffer.Dump(stderr); + + if ( ASDCP_SUCCESS(result) ) + { + split_buffer(PCM::CalcSampleSize(ADesc), FrameBuffer, L_FrameBuffer, R_FrameBuffer); + result = L_OutFile.Write(L_FrameBuffer.Data(), L_FrameBuffer.Size(), &write_count); + + if ( ASDCP_SUCCESS(result) ) + result = R_OutFile.Write(R_FrameBuffer.Data(), R_FrameBuffer.Size(), &write_count); + } + } + + if ( result == RESULT_ENDOFFILE ) + result = RESULT_OK; + + if ( ASDCP_SUCCESS(result) ) + { + ADesc.ContainerDuration = duration; + Wav::SimpleWaveHeader WavHeader(ADesc); + L_OutFile.Seek(); + + if ( ASDCP_SUCCESS(result) ) + result = R_OutFile.Seek(); + + if ( ASDCP_SUCCESS(result) ) + result = WavHeader.WriteToFile(L_OutFile); + + if ( ASDCP_SUCCESS(result) ) + result = WavHeader.WriteToFile(R_OutFile); + } + } + + return RESULT_OK; +} + + +// +int +main(int argc, const char** argv) +{ + Result_t result = RESULT_OK; + CommandOptions Options(argc, argv); + + if ( Options.help_flag ) + { + usage(); + return 0; + } + + if ( Options.error_flag ) + return 3; + + if ( Options.version_flag ) + banner(); + + if ( Options.create_flag ) + result = split_wav_file(Options); + + if ( result != RESULT_OK ) + { + fputs("Program stopped on error.\n", stderr); + + if ( result != RESULT_FAIL ) + { + fputs(result, stderr); + fputc('\n', stderr); + } + + return 1; + } + + return 0; +} + + +// |
