From deadc1bf01e8bc68905c7d33578ffb77b8317c8f Mon Sep 17 00:00:00 2001 From: msheby Date: Thu, 25 Oct 2007 18:44:45 +0000 Subject: [PATCH] Win32 portability fixes --- README | 70 +++++++++++++++++++++++++------------------ src/AS_DCP_AES.cpp | 57 ++++++++++++++++++++++++++--------- src/AS_DCP_JP2K.cpp | 69 ++++++++++++++++++++++++++++++++++++++---- src/AS_DCP_MXF.cpp | 6 ++-- src/AS_DCP_internal.h | 17 +++++++++++ src/KM_fileio.cpp | 3 ++ src/KM_fileio.h | 2 ++ src/MXF.cpp | 2 +- src/MXF.h | 2 +- src/asdcp-test.cpp | 10 ++++--- src/h__Reader.cpp | 39 +++++++++--------------- 11 files changed, 195 insertions(+), 82 deletions(-) diff --git a/README b/README index 7bf5f34..2885d78 100755 --- a/README +++ b/README @@ -11,8 +11,8 @@ Initiatives, LLC (DCI). Subsequent efforts have been funded by Deluxe Laboratories, Doremi Labs, CineCert LLC, Avica Technology and others. -**The asdcplib project was housed on SourceForge. The project -has moved to http://www.cinecert.com/asdcplib/ +**The asdcplib project was originally housed on SourceForge. +The project has moved to http://www.cinecert.com/asdcplib/ The project formerly depended upon the mxflib project. Because of its focus on covering the whole of the MXF specifications, @@ -39,16 +39,16 @@ urged to use static linking (at least where you use this library) to prevent malicious in-field replacement of critical system modules. This recommendation should be considered wherever Open Source or Free software is being -used for applications having non-trivial security -requirements. +used in conjunction with critical security parameters, such +as cryptographic keys. -The author strives mightily to provide an API that is -completely independent of operating system and other -library dependencies, and which allows selective replacement -of some modules for local needs. Specifically, the essence -parsers and OpenSSL crypto functions can be replaced by -linking to alternative implementations of the ASDCP:: -objects which provide those services. +The author strives mightily to provide an API that is completely +independent of operating system and other library dependencies, +and which allows selective replacement of some modules for +local needs. Specifically, the essence parsers and OpenSSL +crypto functions can be replaced by linking to alternative +implementations of the ASDCP:: objects which provide those +services. AS_DCP.h contains the entire API. You do not need to read any of the other files, except maybe asdcp-test.cpp which @@ -78,6 +78,9 @@ total 1761 drwxr-xr-x 1 jhurst None 0 Feb 3 16:37 asdcplib drwxr-xr-x 56 jhurst None 0 Feb 2 16:35 openssl +Expat is optionally required for writing Timed Text Track Files. See +http://expat.sourceforge.net/ + To build, type 'make'. There are several test targets but you need to assemble a set of test files to use them. @@ -113,36 +116,45 @@ utilities all respond to -h. Change History -2007.06.xx - Timed Text and Bug fixes v.1.1.15 - o Added support for draft SMPTE 429-5 Timed Text Track File. See - AS_DCP_TimedText.h for the API. This is *very* experimental, so - do not use for shipping products. Timed Text support is NOT part - of the default build, run `make WITH_TIMED_TEXT=1` to enable - this part of the library. AS_DCP_TimedText.h will be combined - with AS_DCP.h when it becomes stable. Because we need an XML - parser to create the Track File, expat is now part of the Timed - Text build. Follow the XML_PARSER macro in the makefile and KM_xml - to see how you can support your favorite parser. See also - S429-5-cgi.cpp for an example that shows how to serve plaintext - MXF file elements directly via HTTP. +2007.10.22 - Timed Text, Stereoscopic Picture and Bug fixes v.1.2.16 + o Significant API changes have been made. Please read all entries + in this changelog to be sure you understand the changes. Also + note that some changes have been made to LS_MXF_SMPTE files that + are incompatible with earlier releases (e.g., EKLV HMAC). If + you are looking for a stable interop release, use v.1.1.14. + o Fixed RFC 2104 HMAC implementation for LS_MXF_SMPTE only. The + broken implementation has been maintained for Interop mode. + o Added support for draft SMPTE 429-5 Timed Text Track File. This + is still waiting for official SMPTE ULs, so do not use it for + shipping products. An XML parser is needed to create a Timed + Text Track File; Expat is now an optional part of the build. + Make with WITH_XML_PARSER=1 to link with Expat. If you do not + link with expat, you will get an error when using the TimedText:: + DCSubtitleParser class. See also S429-5-cgi.cpp for an example + that shows how to serve plaintext MXF file elements directly via + HTTP. + o Added support for draft SMPTE 429-10 Stereoscopic Picture Track + File, including the JPEG Interop version. This is still waiting + for official SMPTE ULs, so do not use it with LS_MXF_SMPTE for + shipping products. o Refactored the following files as a side-effect of the above work: AS_DCP_JP2K.cpp AS_DCP_MPEG2.cpp AS_DCP_PCM.cpp AS_DCP_MXF.cpp AS_DCP_internal.h MXF.[h|cpp] MXFTypes.[h|cpp] Metadata.[h|cpp] h__Reader.cpp h__Writer.cpp klvwalk.cpp. WARNING: While significant effort has been extended to make sure - that this work does not affect existing stable file support, + that these changes do not affect existing stable file support, users are cautioned to test this release thouroughly. - o Added a large set of path manglers to KM_fileio.h. See + o Added a large set of filesystem path manglers to KM_fileio.h. See path-test.cpp for example usage. The path manglers have not yet been tested on win32 platforms (they are currently used only by - the Timed Text module. The PathIsFile(), PathIsDirectory() and - FileSize() subroutines have been modified to accept const - std::string& instead of const char*. + the Timed Text module. + o The PathIsFile(), PathIsDirectory() and FileSize() subroutines + have been modified to accept const std::string& instead of + const char*. o Added namespace and parsing support (Expat) to Kumu::XMLElement (currently used only for Timed Text support). Also added some new accessors. o Altered MXF::UTF16String to use mbtowc() and wctomb(). - o ... 2007.03.31 - Bug fixes v.1.1.14 diff --git a/src/AS_DCP_AES.cpp b/src/AS_DCP_AES.cpp index 1146bb7..84229d5 100755 --- a/src/AS_DCP_AES.cpp +++ b/src/AS_DCP_AES.cpp @@ -239,6 +239,7 @@ ASDCP::AESDecContext::DecryptBlock(const byte_t* ct_buf, byte_t* pt_buf, ui32_t //------------------------------------------------------------------------------------------ +static const ui32_t B_len = 64; // rfc 2104, Sec. 2 static byte_t ipad[KeyLen] = { 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36 }; @@ -249,12 +250,13 @@ static byte_t opad[KeyLen] = { 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, class HMACContext::h__HMACContext { SHA_CTX m_SHA; - byte_t m_key[KeyLen]; + byte_t m_key[KeyLen]; ASDCP_NO_COPY_CONSTRUCT(h__HMACContext); public: - byte_t sha_value[HMAC_SIZE]; - bool m_Final; + byte_t m_SHAValue[HMAC_SIZE]; + LabelSet_t m_SetType; + bool m_Final; h__HMACContext() : m_Final(false) {} ~h__HMACContext() {} @@ -265,6 +267,7 @@ public: byte_t rng_buf[SHA_DIGEST_LENGTH*2]; Kumu::Gen_FIPS_186_Value(key, KeyLen, rng_buf, SHA_DIGEST_LENGTH*2); memcpy(m_key, rng_buf+SHA_DIGEST_LENGTH, KeyLen); + m_SetType = LS_MXF_SMPTE; Reset(); } @@ -282,24 +285,37 @@ public: SHA1_Update(&SHA, key_nonce, KeyLen); SHA1_Final(sha_buf, &SHA); memcpy(m_key, sha_buf, KeyLen); - + m_SetType = LS_MXF_INTEROP; Reset(); } + // void Reset() { - byte_t xor_buf[KeyLen]; - memset(sha_value, 0, HMAC_SIZE); + byte_t xor_buf[B_len]; + memset(m_SHAValue, 0, HMAC_SIZE); m_Final = false; SHA1_Init(&m_SHA); // H(K XOR opad, H(K XOR ipad, text)) // ^^^^^^^^^^ - for ( ui32_t i = 0; i < KeyLen; i++ ) + ui32_t i = 0; + + for ( ; i < KeyLen; i++ ) xor_buf[i] = m_key[i] ^ ipad[i]; - SHA1_Update(&m_SHA, xor_buf, KeyLen); + if ( m_SetType == LS_MXF_SMPTE ) + { + for ( ; i < B_len; i++ ) + xor_buf[i] = 0 ^ ipad[0]; + + SHA1_Update(&m_SHA, xor_buf, B_len); + } + else + { + SHA1_Update(&m_SHA, xor_buf, KeyLen); + } } // @@ -317,20 +333,33 @@ public: { // H(K XOR opad, H(K XOR ipad, text)) // ^^^^^^^^^^^^^^^ - SHA1_Final(sha_value, &m_SHA); + SHA1_Final(m_SHAValue, &m_SHA); SHA_CTX SHA; SHA1_Init(&SHA); byte_t xor_buf[KeyLen]; + ui32_t i = 0; - for ( ui32_t i = 0; i < KeyLen; i++ ) + for ( ; i < KeyLen; i++ ) xor_buf[i] = m_key[i] ^ opad[i]; + if ( m_SetType == LS_MXF_SMPTE ) + { + for ( ; i < B_len; i++ ) + xor_buf[i] = 0 ^ opad[0]; + + SHA1_Update(&m_SHA, xor_buf, B_len); + } + else + { + SHA1_Update(&m_SHA, xor_buf, KeyLen); + } + SHA1_Update(&SHA, xor_buf, KeyLen); - SHA1_Update(&SHA, sha_value, HMAC_SIZE); + SHA1_Update(&SHA, m_SHAValue, HMAC_SIZE); - SHA1_Final(sha_value, &SHA); + SHA1_Final(m_SHAValue, &SHA); m_Final = true; } }; @@ -410,7 +439,7 @@ HMACContext::GetHMACValue(byte_t* buf) const if ( m_Context.empty() || ! m_Context->m_Final ) return RESULT_INIT; - memcpy(buf, m_Context->sha_value, HMAC_SIZE); + memcpy(buf, m_Context->m_SHAValue, HMAC_SIZE); return RESULT_OK; } @@ -424,7 +453,7 @@ HMACContext::TestHMACValue(const byte_t* buf) const if ( m_Context.empty() || ! m_Context->m_Final ) return RESULT_INIT; - return ( memcmp(buf, m_Context->sha_value, HMAC_SIZE) == 0 ) ? RESULT_OK : RESULT_HMACFAIL; + return ( memcmp(buf, m_Context->m_SHAValue, HMAC_SIZE) == 0 ) ? RESULT_OK : RESULT_HMACFAIL; } diff --git a/src/AS_DCP_JP2K.cpp b/src/AS_DCP_JP2K.cpp index 0271d23..f5ce335 100755 --- a/src/AS_DCP_JP2K.cpp +++ b/src/AS_DCP_JP2K.cpp @@ -386,16 +386,75 @@ ASDCP::JP2K::MXFReader::DumpIndex(FILE* stream) const class ASDCP::JP2K::MXFSReader::h__SReader : public lh__Reader { - StereoscopicPhase_t m_NextPhase; + ui32_t m_StereoFrameReady; public: - h__SReader() : m_NextPhase(SP_LEFT) {} + h__SReader() : m_StereoFrameReady(0xffffffff) {} // Result_t ReadFrame(ui32_t FrameNum, StereoscopicPhase_t phase, FrameBuffer& FrameBuf, - AESDecContext* Ctx, HMACContext* HMAC) const + AESDecContext* Ctx, HMACContext* HMAC) { - return Kumu::RESULT_NOTIMPL; + // look up frame index node + IndexTableSegment::IndexEntry TmpEntry; + + if ( ASDCP_FAILURE(m_FooterPart.Lookup(FrameNum, TmpEntry)) ) + { + DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum); + return RESULT_RANGE; + } + + // get frame position + Kumu::fpos_t FilePosition = m_EssenceStart + TmpEntry.StreamOffset; + Result_t result = RESULT_OK; + + if ( phase == SP_LEFT ) + { + if ( FilePosition != m_LastPosition ) + { + m_LastPosition = FilePosition; + result = m_File.Seek(FilePosition); + } + + // the call to ReadEKLVPacket() will leave the file on an R frame + m_StereoFrameReady = FrameNum; + } + else if ( phase == SP_RIGHT ) + { + if ( m_StereoFrameReady != FrameNum ) + { + // the file is not already positioned, we must do some work + // seek to the companion SP_LEFT frame and read the frame's key and length + if ( FilePosition != m_LastPosition ) + { + m_LastPosition = FilePosition; + result = m_File.Seek(FilePosition); + } + + KLReader Reader; + result = Reader.ReadKLFromFile(m_File); + + if ( ASDCP_SUCCESS(result) ) + { + // skip over the companion SP_LEFT frame + Kumu::fpos_t new_pos = FilePosition + SMPTE_UL_LENGTH + Reader.KLLength() + Reader.Length(); + result = m_File.Seek(new_pos); + } + } + + // the call to ReadEKLVPacket() will leave the file not on an R frame + m_StereoFrameReady = 0xffffffff; + } + else + { + DefaultLogSink().Error("Unexpected stereoscopic phase value: %u\n", phase); + return RESULT_STATE; + } + + if( ASDCP_SUCCESS(result) ) + result = ReadEKLVPacket(FrameNum, FrameBuf, Dict::ul(MDD_JPEG2000Essence), Ctx, HMAC); + + return result; } }; @@ -593,7 +652,7 @@ lh__Writer::OpenWrite(const char* filename, EssenceType_t type, ui32_t HeaderSiz GenRandomValue(m_EssenceSubDescriptor->InstanceUID); m_EssenceDescriptor->SubDescriptors.push_back(m_EssenceSubDescriptor->InstanceUID); - if ( type == ASDCP::ESS_JPEG_2000_S ) + if ( type == ASDCP::ESS_JPEG_2000_S && m_Info.LabelSetType == LS_MXF_SMPTE ) { InterchangeObject* StereoSubDesc = new StereoscopicPictureSubDescriptor; m_EssenceSubDescriptorList.push_back(StereoSubDesc); diff --git a/src/AS_DCP_MXF.cpp b/src/AS_DCP_MXF.cpp index 1d4f473..2392057 100755 --- a/src/AS_DCP_MXF.cpp +++ b/src/AS_DCP_MXF.cpp @@ -202,14 +202,14 @@ ASDCP::RawEssenceType(const char* filename, EssenceType_t& type) if ( i > 1 && p[i] == 1 && (p[i+1] == ASDCP::MPEG2::SEQ_START || p[i+1] == ASDCP::MPEG2::PIC_START) ) type = ESS_MPEG2_VES; - else if ( Kumu::StringIsXML((const char*)p, FB.Size()) ) - type = ESS_TIMED_TEXT; - else if ( ASDCP_SUCCESS(WavHeader.ReadFromBuffer(p, read_count, &data_offset)) ) type = ESS_PCM_24b_48k; else if ( ASDCP_SUCCESS(AIFFHeader.ReadFromBuffer(p, read_count, &data_offset)) ) type = ESS_PCM_24b_48k; + + else if ( Kumu::StringIsXML((const char*)p, FB.Size()) ) + type = ESS_TIMED_TEXT; } } else if ( Kumu::PathIsDirectory(filename) ) diff --git a/src/AS_DCP_internal.h b/src/AS_DCP_internal.h index 7f1ef25..143bccf 100755 --- a/src/AS_DCP_internal.h +++ b/src/AS_DCP_internal.h @@ -90,6 +90,23 @@ namespace ASDCP Result_t EncryptFrameBuffer(const ASDCP::FrameBuffer&, ASDCP::FrameBuffer&, AESEncContext*); Result_t DecryptFrameBuffer(const ASDCP::FrameBuffer&, ASDCP::FrameBuffer&, AESDecContext*); + // + class KLReader : public ASDCP::KLVPacket + { + ASDCP_NO_COPY_CONSTRUCT(KLReader); + byte_t m_KeyBuf[SMPTE_UL_LENGTH*2]; + + public: + KLReader() {} + ~KLReader() {} + + inline const byte_t* Key() { return m_KeyBuf; } + inline const ui64_t Length() { return m_ValueLength; } + inline const ui64_t KLLength() { return m_KLLength; } + + Result_t ReadKLFromFile(Kumu::FileReader& Reader); + }; + // class h__Reader { diff --git a/src/KM_fileio.cpp b/src/KM_fileio.cpp index e94525e..5a56c44 100644 --- a/src/KM_fileio.cpp +++ b/src/KM_fileio.cpp @@ -33,6 +33,9 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#ifdef KM_WIN32 +#include +#endif using namespace Kumu; diff --git a/src/KM_fileio.h b/src/KM_fileio.h index 9d7cc7a..ce41672 100755 --- a/src/KM_fileio.h +++ b/src/KM_fileio.h @@ -141,6 +141,7 @@ namespace Kumu inline bool Match(const std::string& s) const { return true; } }; +#ifndef KM_WIN32 class PathMatchRegex : public IPathMatch { regex_t m_regex; @@ -166,6 +167,7 @@ namespace Kumu virtual ~PathMatchGlob(); bool Match(const std::string& s) const; }; +#endif /* !KM_WIN32 */ // Search all paths in SearchPaths for filenames matching Pattern (no directories are returned). // Put results in FoundPaths. Returns after first find if one_shot is true. diff --git a/src/MXF.cpp b/src/MXF.cpp index be5e58f..be8f031 100755 --- a/src/MXF.cpp +++ b/src/MXF.cpp @@ -1070,7 +1070,7 @@ ASDCP::MXF::OPAtomIndexFooter::Dump(FILE* stream) // ASDCP::Result_t -ASDCP::MXF::OPAtomIndexFooter::Lookup(ui32_t frame_num, IndexTableSegment::IndexEntry& Entry) +ASDCP::MXF::OPAtomIndexFooter::Lookup(ui32_t frame_num, IndexTableSegment::IndexEntry& Entry) const { std::list::iterator li; for ( li = m_PacketList->m_List.begin(); li != m_PacketList->m_List.end(); li++ ) diff --git a/src/MXF.h b/src/MXF.h index b43fc84..f3c2449 100755 --- a/src/MXF.h +++ b/src/MXF.h @@ -348,7 +348,7 @@ namespace ASDCP 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&); + virtual Result_t Lookup(ui32_t frame_num, IndexTableSegment::IndexEntry&) const; virtual void PushIndexEntry(const IndexTableSegment::IndexEntry&); virtual void SetIndexParamsCBR(IPrimerLookup* lookup, ui32_t size, const Rational& Rate); virtual void SetIndexParamsVBR(IPrimerLookup* lookup, const Rational& Rate, Kumu::fpos_t offset); diff --git a/src/asdcp-test.cpp b/src/asdcp-test.cpp index 22743aa..ffd3246 100755 --- a/src/asdcp-test.cpp +++ b/src/asdcp-test.cpp @@ -60,7 +60,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using namespace ASDCP; -const ui32_t FRAME_BUFFER_SIZE = 4*1024*1024; +const ui32_t FRAME_BUFFER_SIZE = 4 * Kumu::Megabyte; //------------------------------------------------------------------------------------------ // @@ -133,16 +133,18 @@ USAGE: %s -c [-3] [-b ] [-d ] [-e|-E]\n\ \n\ %s -t \n\ \n\ - %s -x [-b ] [-d ]\n\ + %s -x [-3] [-b ] [-d ]\n\ [-f ] [-m] [-p ] [-R] [-s ] [-S|-1]\n\ [-v] [-W] \n\ \n", PACKAGE, PACKAGE, PACKAGE, PACKAGE, PACKAGE, PACKAGE, PACKAGE); fprintf(stream, "\ Major modes:\n\ - -3 - Create a stereoscopic image file. Expects two dir-\n\ - ectories of JP2K codestreams (directories must have\n\ + -3 - With -c, create a stereoscopic image file. Expects two\n\ + directories of JP2K codestreams (directories must have\n\ an equal number of frames; left eye is first).\n\ + - With -x, force stereoscopic interpretation of a JP2K\n\ + track file.\n\ -c - Create an AS-DCP track file from input(s)\n\ -g - Generate a random 16 byte value to stdout\n\ -G - Perform GOP start lookup test on MXF+Interop MPEG file\n\ diff --git a/src/h__Reader.cpp b/src/h__Reader.cpp index 7bc8955..8035ac8 100755 --- a/src/h__Reader.cpp +++ b/src/h__Reader.cpp @@ -150,35 +150,24 @@ ASDCP::h__Reader::InitMXFIndex() } // -class KLReader : public ASDCP::KLVPacket +Result_t +ASDCP::KLReader::ReadKLFromFile(Kumu::FileReader& Reader) { - ASDCP_NO_COPY_CONSTRUCT(KLReader); - byte_t m_KeyBuf[32]; - -public: - KLReader() {} - ~KLReader() {} - - inline const byte_t* Key() { return m_KeyBuf; } - inline const ui64_t Length() { return m_ValueLength; } - inline const ui64_t KLLength() { return m_KLLength; } + ui32_t read_count; + ui32_t header_length = SMPTE_UL_LENGTH + MXF_BER_LENGTH; + Result_t result = Reader.Read(m_KeyBuf, header_length, &read_count); - Result_t ReadKLFromFile(Kumu::FileReader& Reader) - { - ui32_t read_count; - ui32_t header_length = SMPTE_UL_LENGTH + MXF_BER_LENGTH; - Result_t result = Reader.Read(m_KeyBuf, header_length, &read_count); - - if ( read_count != header_length ) - return RESULT_READFAIL; + if ( ASDCP_SUCCESS(result) ) + { + if ( read_count != header_length ) + result = RESULT_READFAIL; - if ( ASDCP_SUCCESS(result) ) - result = InitFromBuffer(m_KeyBuf, header_length); - - return result; - } -}; + else + result = InitFromBuffer(m_KeyBuf, header_length); + } + return result; +} // standard method of reading a plaintext or encrypted frame Result_t -- 2.30.2