summaryrefslogtreecommitdiff
path: root/asdcplib/src
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2015-01-14 17:39:32 +0000
committerCarl Hetherington <cth@carlh.net>2015-01-20 11:20:25 +0000
commit3f630fb8334238ab8a58fbe1a0f513ae2c00de80 (patch)
tree4b773b91029d6374bfd4f2194053d3e249d597cd /asdcplib/src
parent49cafda01b3e07c47e3b20dd5ee91e1426446aea (diff)
Simplify time representation; better in-tree DCP subtitle parser.
Diffstat (limited to 'asdcplib/src')
-rwxr-xr-xasdcplib/src/AS_DCP.cpp124
-rwxr-xr-xasdcplib/src/AS_DCP.h1570
-rwxr-xr-xasdcplib/src/AS_DCP_AES.cpp446
-rwxr-xr-xasdcplib/src/AS_DCP_JP2K.cpp1384
-rwxr-xr-xasdcplib/src/AS_DCP_MPEG2.cpp727
-rwxr-xr-xasdcplib/src/AS_DCP_MXF.cpp542
-rwxr-xr-xasdcplib/src/AS_DCP_PCM.cpp671
-rw-r--r--asdcplib/src/AS_DCP_TimedText.cpp770
-rwxr-xr-xasdcplib/src/AS_DCP_internal.h274
-rwxr-xr-xasdcplib/src/Dict.cpp321
-rwxr-xr-xasdcplib/src/Index.cpp243
-rwxr-xr-xasdcplib/src/JP2K.cpp224
-rwxr-xr-xasdcplib/src/JP2K.h164
-rwxr-xr-xasdcplib/src/JP2K_Codestream_Parser.cpp270
-rwxr-xr-xasdcplib/src/JP2K_Sequence_Parser.cpp392
-rwxr-xr-xasdcplib/src/KLV.cpp319
-rwxr-xr-xasdcplib/src/KLV.h256
-rwxr-xr-xasdcplib/src/KM_error.h171
-rw-r--r--asdcplib/src/KM_fileio.cpp1546
-rwxr-xr-xasdcplib/src/KM_fileio.h342
-rwxr-xr-xasdcplib/src/KM_log.cpp379
-rwxr-xr-xasdcplib/src/KM_log.h321
-rwxr-xr-xasdcplib/src/KM_memio.h249
-rwxr-xr-xasdcplib/src/KM_mutex.h89
-rw-r--r--asdcplib/src/KM_platform.h270
-rwxr-xr-xasdcplib/src/KM_prng.cpp271
-rwxr-xr-xasdcplib/src/KM_prng.h64
-rw-r--r--asdcplib/src/KM_tai.cpp221
-rw-r--r--asdcplib/src/KM_tai.h107
-rwxr-xr-xasdcplib/src/KM_util.cpp1141
-rwxr-xr-xasdcplib/src/KM_util.h547
-rw-r--r--asdcplib/src/KM_xml.cpp1012
-rw-r--r--asdcplib/src/KM_xml.h141
-rw-r--r--asdcplib/src/MDD.cpp925
-rwxr-xr-xasdcplib/src/MDD.h353
-rwxr-xr-xasdcplib/src/MPEG.cpp295
-rwxr-xr-xasdcplib/src/MPEG.h244
-rwxr-xr-xasdcplib/src/MPEG2_Parser.cpp639
-rwxr-xr-xasdcplib/src/MXF.cpp1489
-rwxr-xr-xasdcplib/src/MXF.h410
-rwxr-xr-xasdcplib/src/MXFTypes.cpp682
-rwxr-xr-xasdcplib/src/MXFTypes.h409
-rw-r--r--asdcplib/src/Makefile.am249
-rw-r--r--asdcplib/src/Makefile.in1516
-rwxr-xr-xasdcplib/src/Metadata.cpp2893
-rwxr-xr-xasdcplib/src/Metadata.h900
-rwxr-xr-xasdcplib/src/PCMParserList.cpp285
-rwxr-xr-xasdcplib/src/PCMParserList.h89
-rwxr-xr-xasdcplib/src/PCM_Parser.cpp236
-rw-r--r--asdcplib/src/S12MTimecode.h158
-rw-r--r--asdcplib/src/TimedText_Parser.cpp447
-rwxr-xr-xasdcplib/src/Wav.cpp370
-rwxr-xr-xasdcplib/src/Wav.h127
-rwxr-xr-xasdcplib/src/WavFileWriter.h198
-rwxr-xr-xasdcplib/src/asdcp-info.cpp428
-rwxr-xr-xasdcplib/src/asdcp-mem-test.cpp148
-rwxr-xr-xasdcplib/src/asdcp-test.cpp2087
-rwxr-xr-xasdcplib/src/asdcp-unwrap.cpp896
-rwxr-xr-xasdcplib/src/asdcp-util.cpp294
-rwxr-xr-xasdcplib/src/asdcp-version.cpp46
-rwxr-xr-xasdcplib/src/asdcp-wrap.cpp1151
-rw-r--r--asdcplib/src/blackwave.cpp245
-rwxr-xr-xasdcplib/src/fips-186-rng-test.cpp96
-rwxr-xr-xasdcplib/src/fips-186-test-harness.pl1318
-rwxr-xr-xasdcplib/src/gen-tst.sh28
-rwxr-xr-xasdcplib/src/h__Reader.cpp460
-rwxr-xr-xasdcplib/src/h__Writer.cpp710
-rwxr-xr-xasdcplib/src/j2c-test.cpp234
-rwxr-xr-xasdcplib/src/jp2k-crypt-tst.sh58
-rwxr-xr-xasdcplib/src/jp2k-stereo-crypt-tst.sh56
-rwxr-xr-xasdcplib/src/jp2k-stereo-tst.sh47
-rwxr-xr-xasdcplib/src/jp2k-tst.sh54
-rwxr-xr-xasdcplib/src/klvwalk.cpp287
-rwxr-xr-xasdcplib/src/kmfilegen.cpp616
-rw-r--r--asdcplib/src/kmrandgen.cpp292
-rw-r--r--asdcplib/src/kmuuidgen.cpp195
-rwxr-xr-xasdcplib/src/mpeg-crypt-tst.sh52
-rwxr-xr-xasdcplib/src/mpeg-tst.sh49
-rw-r--r--asdcplib/src/path-test.cpp145
-rwxr-xr-xasdcplib/src/rng-tst.sh28
-rwxr-xr-xasdcplib/src/wav-crypt-tst.sh69
-rwxr-xr-xasdcplib/src/wav-tst.sh42
-rwxr-xr-xasdcplib/src/wavesplit.cpp397
-rw-r--r--asdcplib/src/wscript71
84 files changed, 39081 insertions, 0 deletions
diff --git a/asdcplib/src/AS_DCP.cpp b/asdcplib/src/AS_DCP.cpp
new file mode 100755
index 0000000..0ae9a1f
--- /dev/null
+++ b/asdcplib/src/AS_DCP.cpp
@@ -0,0 +1,124 @@
+/*
+Copyright (c) 2004-2009, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file AS_DCP.cpp
+ \version $Id: AS_DCP.cpp,v 1.6 2009/04/09 19:16:49 msheby Exp $
+ \brief AS-DCP library, misc classes and subroutines
+*/
+
+#include "AS_DCP_internal.h"
+#include <assert.h>
+
+const char*
+ASDCP::Version()
+{
+ return PACKAGE_VERSION;
+}
+
+
+//------------------------------------------------------------------------------------------
+//
+// frame buffer base class implementation
+
+ASDCP::FrameBuffer::FrameBuffer() :
+ m_Data(0), m_Capacity(0), m_OwnMem(false), m_Size(0),
+ m_FrameNumber(0), m_SourceLength(0), m_PlaintextOffset(0)
+{
+}
+
+ASDCP::FrameBuffer::~FrameBuffer()
+{
+ if ( m_OwnMem && m_Data != 0 )
+ free(m_Data);
+}
+
+// Instructs the object to use an externally allocated buffer. The external
+// buffer will not be cleaned up by the frame buffer when it is destroyed.
+// Call with (0,0) to revert to internally allocated buffer.
+// Returns error if the buf_addr argument is NULL and either buf_size is
+// non-zero or internally allocated memory is in use.
+ASDCP::Result_t
+ASDCP::FrameBuffer::SetData(byte_t* buf_addr, ui32_t buf_size)
+{
+ // if buf_addr is null and we have an external memory reference,
+ // drop the reference and place the object in the initialized-
+ // but-no-buffer-allocated state
+ if ( buf_addr == 0 )
+ {
+ if ( buf_size > 0 || m_OwnMem )
+ return RESULT_PTR;
+
+ m_OwnMem = false;
+ m_Capacity = m_Size = 0;
+ m_Data = 0;
+ return RESULT_OK;
+ }
+
+ if ( m_OwnMem && m_Data != 0 )
+ free(m_Data);
+
+ m_OwnMem = false;
+ m_Capacity = buf_size;
+ m_Data = buf_addr;
+ m_Size = 0;
+
+ return RESULT_OK;
+}
+
+// Sets the size of the internally allocate buffer. Returns RESULT_CAPEXTMEM
+// if the object is using an externally allocated buffer via SetData();
+// Resets content size to zero.
+ASDCP::Result_t
+ASDCP::FrameBuffer::Capacity(ui32_t cap_size)
+{
+ if ( ! m_OwnMem && m_Data != 0 )
+ return RESULT_CAPEXTMEM; // cannot resize external memory
+
+ if ( m_Capacity < cap_size )
+ {
+ if ( m_Data != 0 )
+ {
+ assert(m_OwnMem);
+ free(m_Data);
+ }
+
+ m_Data = (byte_t*)malloc(cap_size);
+
+ if ( m_Data == 0 )
+ return RESULT_ALLOC;
+
+ m_Capacity = cap_size;
+ m_OwnMem = true;
+ m_Size = 0;
+ }
+
+ return RESULT_OK;
+}
+
+
+//
+// end AS_DCP.cpp
+//
diff --git a/asdcplib/src/AS_DCP.h b/asdcplib/src/AS_DCP.h
new file mode 100755
index 0000000..eb2ce6e
--- /dev/null
+++ b/asdcplib/src/AS_DCP.h
@@ -0,0 +1,1570 @@
+/*
+Copyright (c) 2003-2012, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file AS_DCP.h
+ \version $Id: AS_DCP.h,v 1.43 2012/02/02 01:58:43 jhurst Exp $
+ \brief AS-DCP library, public interface
+
+The asdcplib library is a set of file access objects that offer simplified
+access to files conforming to the standards published by the SMPTE
+D-Cinema Technology Committee 21DC. The file format, labeled AS-DCP,
+is described in series of separate documents which include but may not
+be be limited to:
+
+ o SMPTE ST 429-2:2011 DCP Operational Constraints
+ o SMPTE ST 429-3:2006 Sound and Picture Track File
+ o SMPTE ST 429-4:2006 MXF JPEG 2000 Application
+ o SMPTE ST 429-5:2009 Timed Text Track File
+ o SMPTE ST 429-6:2006 MXF Track File Essence Encryption
+ o SMPTE ST 429-10:2008 Stereoscopic Picture Track File
+ o SMPTE ST 330:2004 - UMID
+ o SMPTE ST 336:2001 - KLV
+ o SMPTE ST 377-1:2011 - MXF
+ o SMPTE ST 377-4:2012 - MXF Multichannel Audio Labeling Framework
+ o SMPTE ST 390:2011 - MXF OP-Atom
+ o SMPTE ST 379-1:2009 - MXF Generic Container (GC)
+ o SMPTE ST 381-1:2005 - MPEG2 picture in GC
+ o SMPTE ST 422:2006 - JPEG 2000 picture in GC
+ o SMPTE ST 382:2007 - WAV/PCM sound in GC
+ o IETF RFC 2104 - HMAC/SHA1
+ o NIST FIPS 197 - AES (Rijndael) (via OpenSSL)
+
+ o MXF Interop Track File Specification
+ o MXF Interop Track File Essence Encryption Specification
+ o MXF Interop Operational Constraints Specification
+ - Note: the MXF Interop documents are not formally published.
+ Contact the asdcplib support address to get copies.
+
+The following use cases are supported by the library:
+
+ o Write essence to a plaintext or ciphertext AS-DCP file:
+ MPEG2 Video Elementary Stream
+ JPEG 2000 codestreams
+ JPEG 2000 stereoscopic codestream pairs
+ PCM audio streams
+ SMPTE 429-7 Timed Text XML with font and image resources
+
+ o Read essence from a plaintext or ciphertext AS-DCP file:
+ MPEG2 Video Elementary Stream
+ JPEG 2000 codestreams
+ JPEG 2000 stereoscopic codestream pairs
+ PCM audio streams
+ SMPTE 429-7 Timed Text XML with font and image resources
+
+ o Read header metadata from an AS-DCP file
+
+This project depends upon the following libraries:
+ - OpenSSL http://www.openssl.org/
+ - Expat http://expat.sourceforge.net/ or
+ Xerces-C http://xerces.apache.org/xerces-c/
+ An XML library is not needed if you don't need support for SMPTE ST 429-5:2009.
+*/
+
+#ifndef _AS_DCP_H_
+#define _AS_DCP_H_
+
+#include <KM_error.h>
+#include <KM_platform.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <math.h>
+#include <iosfwd>
+#include <string>
+#include <cstring>
+#include <list>
+
+//--------------------------------------------------------------------------------
+// common integer types
+// supply your own by defining ASDCP_NO_BASE_TYPES
+
+#ifndef ASDCP_NO_BASE_TYPES
+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;
+#endif
+
+
+//--------------------------------------------------------------------------------
+// convenience macros
+
+// Convenience macros for managing return values in predicates
+#define ASDCP_SUCCESS(v) (((v) < 0) ? 0 : 1)
+#define ASDCP_FAILURE(v) (((v) < 0) ? 1 : 0)
+
+
+// Returns RESULT_PTR if the given argument is NULL.
+// See Result_t below for an explanation of RESULT_* symbols.
+#define ASDCP_TEST_NULL(p) \
+ if ( (p) == 0 ) { \
+ return ASDCP::RESULT_PTR; \
+ }
+
+// Returns RESULT_PTR if the given argument is NULL. See Result_t
+// below 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 ASDCP_TEST_NULL_STR(p) \
+ ASDCP_TEST_NULL(p); \
+ if ( (p)[0] == '\0' ) { \
+ return ASDCP::RESULT_NULL_STR; \
+ }
+
+// Produces copy constructor boilerplate. Allows convenient private
+// declatarion of copy constructors to prevent the compiler from
+// silently manufacturing default methods.
+#define ASDCP_NO_COPY_CONSTRUCT(T) \
+ T(const T&); \
+ T& operator=(const T&)
+
+//--------------------------------------------------------------------------------
+// All library components are defined in the namespace ASDCP
+//
+namespace ASDCP {
+ //
+ // The version number declaration and explanation have moved to ../configure.ac
+ const char* Version();
+
+ // UUIDs are passed around as strings of UUIDlen bytes
+ const ui32_t UUIDlen = 16;
+
+ // Encryption keys are passed around as strings of KeyLen bytes
+ const ui32_t KeyLen = 16;
+
+ //---------------------------------------------------------------------------------
+ // return values
+
+ 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;
+
+ KM_DECLARE_RESULT(FORMAT, -101, "The file format is not proper OP-Atom/AS-DCP.");
+ KM_DECLARE_RESULT(RAW_ESS, -102, "Unknown raw essence file type.");
+ KM_DECLARE_RESULT(RAW_FORMAT, -103, "Raw essence format invalid.");
+ KM_DECLARE_RESULT(RANGE, -104, "Frame number out of range.");
+ KM_DECLARE_RESULT(CRYPT_CTX, -105, "AESEncContext required when writing to encrypted file.");
+ KM_DECLARE_RESULT(LARGE_PTO, -106, "Plaintext offset exceeds frame buffer size.");
+ KM_DECLARE_RESULT(CAPEXTMEM, -107, "Cannot resize externally allocated memory.");
+ KM_DECLARE_RESULT(CHECKFAIL, -108, "The check value did not decrypt correctly.");
+ KM_DECLARE_RESULT(HMACFAIL, -109, "HMAC authentication failure.");
+ KM_DECLARE_RESULT(HMAC_CTX, -110, "HMAC context required.");
+ KM_DECLARE_RESULT(CRYPT_INIT, -111, "Error initializing block cipher context.");
+ KM_DECLARE_RESULT(EMPTY_FB, -112, "Empty frame buffer.");
+ KM_DECLARE_RESULT(KLV_CODING, -113, "KLV coding error.");
+ KM_DECLARE_RESULT(SPHASE, -114, "Stereoscopic phase mismatch.");
+ KM_DECLARE_RESULT(SFORMAT, -115, "Rate mismatch, file may contain stereoscopic essence.");
+
+ //---------------------------------------------------------------------------------
+ // file identification
+
+ // The file accessors in this library implement a bounded set of essence types.
+ // This list will be expanded when support for new types is added to the library.
+ enum EssenceType_t {
+ 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_96k, // the file contains one or more PCM audio pairs
+ ESS_TIMED_TEXT, // the file contains an XML timed text document and one or more resources
+ ESS_JPEG_2000_S, // the file contains one or more JPEG 2000 codestream pairs (stereoscopic)
+ };
+
+ // Determine the type of essence contained in the given MXF file. RESULT_OK
+ // is returned if the file is successfully opened and contains a valid MXF
+ // stream. If there is an error, the result code will indicate the reason.
+ Result_t EssenceType(const char* filename, EssenceType_t& type);
+
+ // Determine the type of essence contained in the given raw file. RESULT_OK
+ // is returned if the file is successfully opened and contains a known
+ // stream type. If there is an error, the result code will indicate the reason.
+ Result_t RawEssenceType(const char* filename, EssenceType_t& type);
+
+
+ //---------------------------------------------------------------------------------
+ // base types
+
+ // A simple container for rational numbers.
+ class Rational
+ {
+ public:
+ i32_t Numerator;
+ i32_t Denominator;
+
+ Rational() : Numerator(0), Denominator(0) {}
+ Rational(i32_t n, i32_t d) : Numerator(n), Denominator(d) {}
+
+ inline double Quotient() const {
+ return (double)Numerator / (double)Denominator;
+ }
+
+ inline bool operator==(const Rational& rhs) const {
+ return ( rhs.Numerator == Numerator && rhs.Denominator == Denominator );
+ }
+
+ inline bool operator!=(const Rational& rhs) const {
+ return ( rhs.Numerator != Numerator || rhs.Denominator != Denominator );
+ }
+
+ inline bool operator<(const Rational& rhs) {
+ if ( Numerator < rhs.Numerator ) return true;
+ if ( Numerator == rhs.Numerator && Denominator < rhs.Denominator ) return true;
+ return false;
+ }
+
+ inline bool operator>(const Rational& rhs) {
+ if ( Numerator > rhs.Numerator ) return true;
+ if ( Numerator == rhs.Numerator && Denominator > rhs.Denominator ) return true;
+ return false;
+ }
+ };
+
+ // common edit rates, use these instead of hard coded constants
+ const Rational EditRate_24 = Rational(24,1);
+ const Rational EditRate_23_98 = Rational(24000,1001); // Not a DCI-compliant value!
+ const Rational EditRate_48 = Rational(48,1);
+ const Rational SampleRate_48k = Rational(48000,1);
+ const Rational SampleRate_96k = Rational(96000,1);
+
+ // Additional frame rates, see ST 428-11, ST 429-13
+ // These rates are new and not supported by all systems. Do not assume that
+ // a package made using one of these rates will work just anywhere!
+ const Rational EditRate_25 = Rational(25,1);
+ const Rational EditRate_30 = Rational(30,1);
+ const Rational EditRate_50 = Rational(50,1);
+ const Rational EditRate_60 = Rational(60,1);
+ const Rational EditRate_96 = Rational(96,1);
+ const Rational EditRate_100 = Rational(100,1);
+ const Rational EditRate_120 = Rational(120,1);
+
+ // Non-reference counting container for internal member objects.
+ // Please do not use this class for any other purpose.
+ template <class T>
+ class mem_ptr
+ {
+ T* m_p; // the thing we point to
+ mem_ptr(T&);
+
+ 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; }
+ };
+
+
+ //---------------------------------------------------------------------------------
+ // 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
+ // (AKA JPEG Interop) and SMPTE. The two differ in the values of three labels:
+ //
+ // OPAtom
+ // Interop : 06 0e 2b 34 04 01 01 01 0d 01 02 01 10 00 00 00
+ // SMPTE : 06 0e 2b 34 04 01 01 02 0d 01 02 01 10 00 00 00
+ //
+ // EKLV Packet:
+ // Interop : 06 0e 2b 34 02 04 01 07 0d 01 03 01 02 7e 01 00
+ // SMPTE : 06 0e 2b 34 02 04 01 01 0d 01 03 01 02 7e 01 00
+ //
+ // GenericDescriptor/SubDescriptors:
+ // Interop : 06 0e 2b 34 01 01 01 02 06 01 01 04 06 10 00 00
+ // SMPTE : 06 0e 2b 34 01 01 01 09 06 01 01 04 06 10 00 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 std::ostream
+ std::ostream& operator << (std::ostream& strm, const WriterInfo& winfo);
+ // Print WriterInfo to stream, stderr by default.
+ void WriterInfoDump(const WriterInfo&, FILE* = 0);
+
+ //---------------------------------------------------------------------------------
+ // cryptographic support
+
+ // The following classes define interfaces to Rijndael contexts having the following properties:
+ // o 16 byte key
+ // o CBC mode with 16 byte block size
+ const ui32_t CBC_KEY_SIZE = 16;
+ const ui32_t CBC_BLOCK_SIZE = 16;
+ const ui32_t HMAC_SIZE = 20;
+
+ //
+ class AESEncContext
+ {
+ class h__AESContext;
+ mem_ptr<h__AESContext> m_Context;
+ ASDCP_NO_COPY_CONSTRUCT(AESEncContext);
+
+ public:
+ AESEncContext();
+ ~AESEncContext();
+
+ // Initializes Rijndael CBC encryption context.
+ // Returns error if the key argument is NULL.
+ Result_t InitKey(const byte_t* key);
+
+ // Initializes 16 byte CBC Initialization Vector. This operation may be performed
+ // any number of times for a given key.
+ // Returns error if the i_vec argument is NULL.
+ Result_t SetIVec(const byte_t* i_vec);
+ Result_t GetIVec(byte_t* i_vec) const;
+
+ // Encrypt a block of data. The block size must be a multiple of CBC_BLOCK_SIZE.
+ // Returns error if either argument is NULL.
+ Result_t EncryptBlock(const byte_t* pt_buf, byte_t* ct_buf, ui32_t block_size);
+ };
+
+ //
+ class AESDecContext
+ {
+ class h__AESContext;
+ mem_ptr<h__AESContext> m_Context;
+ ASDCP_NO_COPY_CONSTRUCT(AESDecContext);
+
+ public:
+ AESDecContext();
+ ~AESDecContext();
+
+ // Initializes Rijndael CBC decryption context.
+ // Returns error if the key argument is NULL.
+ Result_t InitKey(const byte_t* key);
+
+ // Initializes 16 byte CBC Initialization Vector. This operation may be performed
+ // any number of times for a given key.
+ // Returns error if the i_vec argument is NULL.
+ Result_t SetIVec(const byte_t* i_vec);
+
+ // Decrypt a block of data. The block size must be a multiple of CBC_BLOCK_SIZE.
+ // Returns error if either argument is NULL.
+ Result_t DecryptBlock(const byte_t* ct_buf, byte_t* pt_buf, ui32_t block_size);
+ };
+
+ //
+ class HMACContext
+ {
+ class h__HMACContext;
+ mem_ptr<h__HMACContext> m_Context;
+ ASDCP_NO_COPY_CONSTRUCT(HMACContext);
+
+ public:
+ HMACContext();
+ ~HMACContext();
+
+ // 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, LabelSet_t);
+
+ // Reset internal state, allows repeated cycles of Update -> Finalize
+ void Reset();
+
+ // Add data to the digest. Returns error if the key argument is NULL or
+ // if the digest has been finalized.
+ Result_t Update(const byte_t* buf, ui32_t buf_len);
+
+ // Finalize digest. Returns error if the digest has already been finalized.
+ Result_t Finalize();
+
+ // Writes HMAC value to given buffer. buf must point to a writable area of
+ // memory that is at least HMAC_SIZE bytes in length. Returns error if the
+ // buf argument is NULL or if the digest has not been finalized.
+ Result_t GetHMACValue(byte_t* buf) const;
+
+ // Tests the given value against the finalized value in the object. buf must
+ // point to a readable area of memory that is at least HMAC_SIZE bytes in length.
+ // Returns error if the buf argument is NULL or if the values do ot match.
+ Result_t TestHMACValue(const byte_t* buf) const;
+ };
+
+ //---------------------------------------------------------------------------------
+ // frame buffer base class
+ //
+ // The supported essence types are stored using per-frame KLV packetization. The
+ // following class implements essence-neutral functionality for managing a buffer
+ // containing a frame of essence.
+
+ class FrameBuffer
+ {
+ ASDCP_NO_COPY_CONSTRUCT(FrameBuffer);
+
+ 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
+ bool m_OwnMem; // if false, m_Data points to externally allocated memory
+ ui32_t m_Size; // size of frame data in memory area pointed to by m_Data
+ ui32_t m_FrameNumber; // delivery-order frame number
+
+ // It is possible to read raw ciphertext from an encrypted AS-DCP file.
+ // After reading an encrypted AS-DCP file in raw mode, the frame buffer will
+ // contain the encrypted source value portion of the Encrypted Triplet, followed
+ // by the integrity pack, if it exists.
+ // The buffer will begin with the IV and CheckValue, followed by encrypted essence
+ // and optional integrity pack
+ // The SourceLength and PlaintextOffset values from the packet will be held in the
+ // following variables:
+ ui32_t m_SourceLength; // plaintext length (delivered plaintext+decrypted ciphertext)
+ ui32_t m_PlaintextOffset; // offset to first byte of ciphertext
+
+ public:
+ FrameBuffer();
+ virtual ~FrameBuffer();
+
+ // Instructs the object to use an externally allocated buffer. The external
+ // buffer will not be cleaned up by the frame buffer when it exits.
+ // Call with (0,0) to revert to internally allocated buffer.
+ // Returns error if the buf_addr argument is NULL and buf_size is non-zero.
+ Result_t SetData(byte_t* buf_addr, ui32_t buf_size);
+
+ // Sets the size of the internally allocate buffer. Returns RESULT_CAPEXTMEM
+ // if the object is using an externally allocated buffer via SetData();
+ // Resets content size to zero.
+ Result_t Capacity(ui32_t cap);
+
+ // 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 size of the buffer's contents
+ inline ui32_t Size(ui32_t size) { return m_Size = size; }
+
+ // returns the size of the buffer's contents
+ inline ui32_t Size() const { return m_Size; }
+
+ // Sets the absolute frame number of this frame in the file in delivery order.
+ inline void FrameNumber(ui32_t num) { m_FrameNumber = num; }
+
+ // Returns the absolute frame number of this frame in the file in delivery order.
+ inline ui32_t FrameNumber() const { return m_FrameNumber; }
+
+ // Sets the length of the plaintext essence data
+ inline void SourceLength(ui32_t len) { m_SourceLength = len; }
+
+ // When this value is 0 (zero), the buffer contains only plaintext. When it is
+ // non-zero, the buffer contains raw ciphertext and the return value is the length
+ // of the original plaintext.
+ inline ui32_t SourceLength() const { return m_SourceLength; }
+
+ // Sets the offset into the buffer at which encrypted data begins
+ inline void PlaintextOffset(ui32_t ofst) { m_PlaintextOffset = ofst; }
+
+ // Returns offset into buffer of first byte of ciphertext.
+ inline ui32_t PlaintextOffset() const { return m_PlaintextOffset; }
+ };
+
+ //---------------------------------------------------------------------------------
+ // Accessors in the MXFReader and MXFWriter classes below return these types to
+ // provide direct access to MXF metadata structures declared in MXF.h and Metadata.h
+
+ namespace MXF {
+ // #include<Metadata.h> to use these
+ class OPAtomHeader;
+ class OPAtomIndexFooter;
+ };
+
+ //---------------------------------------------------------------------------------
+ // MPEG2 video elementary stream support
+
+ //
+ namespace MPEG2
+ {
+ // MPEG picture coding type
+ enum FrameType_t {
+ FRAME_U = 0x00, // Unknown
+ FRAME_I = 0x01, // I-Frame
+ FRAME_P = 0x02, // P-Frame
+ FRAME_B = 0x03 // B-Frame
+ };
+
+ // convert FrameType_t to char
+ inline char FrameTypeChar(FrameType_t type)
+ {
+ switch ( type )
+ {
+ case FRAME_I: return 'I';
+ case FRAME_B: return 'B';
+ case FRAME_P: return 'P';
+ default: return 'U';
+ }
+ }
+
+ // Structure represents the metadata elements in the file header's
+ // MPEG2VideoDescriptor object.
+ struct VideoDescriptor
+ {
+ Rational EditRate; //
+ ui32_t FrameRate; //
+ Rational SampleRate; //
+ ui8_t FrameLayout; //
+ ui32_t StoredWidth; //
+ ui32_t StoredHeight; //
+ Rational AspectRatio; //
+ ui32_t ComponentDepth; //
+ ui32_t HorizontalSubsampling; //
+ ui32_t VerticalSubsampling; //
+ ui8_t ColorSiting; //
+ ui8_t CodedContentType; //
+ bool LowDelay; //
+ ui32_t BitRate; //
+ ui8_t ProfileAndLevel; //
+ ui32_t ContainerDuration; //
+ };
+
+ // Print VideoDescriptor to std::ostream
+ std::ostream& operator << (std::ostream& strm, const VideoDescriptor& vdesc);
+ // Print VideoDescriptor to stream, stderr by default.
+ void VideoDescriptorDump(const VideoDescriptor&, FILE* = 0);
+
+ // A container for MPEG frame data.
+ class FrameBuffer : public ASDCP::FrameBuffer
+ {
+ ASDCP_NO_COPY_CONSTRUCT(FrameBuffer); // TODO: should have copy construct
+
+ protected:
+ FrameType_t m_FrameType;
+ ui8_t m_TemporalOffset;
+ bool m_ClosedGOP;
+ bool m_GOPStart;
+
+ public:
+ FrameBuffer() :
+ m_FrameType(FRAME_U), m_TemporalOffset(0),
+ m_ClosedGOP(false), m_GOPStart(false) {}
+
+ FrameBuffer(ui32_t size) :
+ m_FrameType(FRAME_U), m_TemporalOffset(0),
+ m_ClosedGOP(false), m_GOPStart(false)
+ {
+ Capacity(size);
+ }
+
+ virtual ~FrameBuffer() {}
+
+ // Sets the MPEG frame type of the picture data in the frame buffer.
+ inline void FrameType(FrameType_t type) { m_FrameType = type; }
+
+ // Returns the MPEG frame type of the picture data in the frame buffer.
+ inline FrameType_t FrameType() const { return m_FrameType; }
+
+ // Sets the MPEG temporal offset of the picture data in the frame buffer.
+ inline void TemporalOffset(ui8_t offset) { m_TemporalOffset = offset; }
+
+ // Returns the MPEG temporal offset of the picture data in the frame buffer.
+ inline ui8_t TemporalOffset() const { return m_TemporalOffset; }
+
+ // Sets the MPEG GOP 'start' attribute for the frame buffer.
+ inline void GOPStart(bool start) { m_GOPStart = start; }
+
+ // True if the frame in the buffer is the first in the GOP (in transport order)
+ inline bool GOPStart() const { return m_GOPStart; }
+
+ // Sets the MPEG GOP 'closed' attribute for the frame buffer.
+ inline void ClosedGOP(bool closed) { m_ClosedGOP = closed; }
+
+ // Returns true if the frame in the buffer is from a closed GOP, false if
+ // the frame is from an open GOP. Always returns false unless GOPStart()
+ // returns true.
+ inline bool ClosedGOP() const { return m_ClosedGOP; }
+
+ // Print object state to stream, include n bytes of frame data if indicated.
+ // Default stream is stderr.
+ void Dump(FILE* = 0, ui32_t dump_len = 0) const;
+ };
+
+
+ // An object which opens and reads an MPEG2 Video Elementary Stream file. The call to
+ // OpenRead() reads metadata from the file and populates an internal VideoDescriptor object.
+ // Each subsequent call to ReadFrame() reads exactly one frame from the stream into the
+ // given FrameBuffer object.
+ class Parser
+ {
+ class h__Parser;
+ mem_ptr<h__Parser> m_Parser;
+ ASDCP_NO_COPY_CONSTRUCT(Parser);
+
+ public:
+ Parser();
+ virtual ~Parser();
+
+ // Opens the stream for reading, parses enough data to provide a complete
+ // set of stream metadata for the MXFWriter below.
+ Result_t OpenRead(const char* filename) const;
+
+ // Fill a VideoDescriptor struct with the values from the file's header.
+ // Returns RESULT_INIT if the file is not open.
+ Result_t FillVideoDescriptor(VideoDescriptor&) const;
+
+ // Rewind the stream to the beginning.
+ Result_t Reset() const;
+
+ // Reads the next sequential frame in the input file and places it in the
+ // frame buffer. Fails if the buffer is too small or the stream is empty.
+ // The frame buffer's PlaintextOffset parameter will be set to the first
+ // data byte of the first slice. Set this value to zero if you want
+ // encrypted headers.
+ Result_t ReadFrame(FrameBuffer&) const;
+ };
+
+ // A class which creates and writes MPEG frame data to an AS-DCP format MXF file.
+ // Not yet implemented
+ class MXFWriter
+ {
+ class h__Writer;
+ mem_ptr<h__Writer> m_Writer;
+ ASDCP_NO_COPY_CONSTRUCT(MXFWriter);
+
+ public:
+ MXFWriter();
+ virtual ~MXFWriter();
+
+ // Warning: direct manipulation of MXF structures can interfere
+ // with the normal operation of the wrapper. Caveat emptor!
+ virtual MXF::OPAtomHeader& OPAtomHeader();
+ virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter();
+
+ // Open the file for writing. The file must not exist. Returns error if
+ // the operation cannot be completed or if nonsensical data is discovered
+ // in the essence descriptor.
+ Result_t OpenWrite(const char* filename, const WriterInfo&,
+ const VideoDescriptor&, ui32_t HeaderSize = 16384);
+
+ // Writes a frame of essence to the MXF file. If the optional AESEncContext
+ // argument is present, the essence is encrypted prior to writing.
+ // Fails if the file is not open, is finalized, or an operating system
+ // error occurs.
+ Result_t WriteFrame(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0);
+
+ // Closes the MXF file, writing the index and revised header.
+ Result_t Finalize();
+ };
+
+ // A class which reads MPEG frame data from an AS-DCP format MXF file.
+ class MXFReader
+ {
+ class h__Reader;
+ mem_ptr<h__Reader> m_Reader;
+ ASDCP_NO_COPY_CONSTRUCT(MXFReader);
+
+ public:
+ MXFReader();
+ virtual ~MXFReader();
+
+ // Warning: direct manipulation of MXF structures can interfere
+ // with the normal operation of the wrapper. Caveat emptor!
+ virtual MXF::OPAtomHeader& OPAtomHeader();
+ virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter();
+
+ // Open the file for reading. The file must exist. Returns error if the
+ // operation cannot be completed.
+ Result_t OpenRead(const char* filename) const;
+
+ // Returns RESULT_INIT if the file is not open.
+ Result_t Close() const;
+
+ // Fill a VideoDescriptor struct with the values from the file's header.
+ // Returns RESULT_INIT if the file is not open.
+ Result_t FillVideoDescriptor(VideoDescriptor&) const;
+
+ // Fill a WriterInfo struct with the values from the file's header.
+ // Returns RESULT_INIT if the file is not open.
+ Result_t FillWriterInfo(WriterInfo&) const;
+
+ // Reads a frame of essence from the MXF file. If the optional AESEncContext
+ // argument is present, the essence is decrypted after reading. If the MXF
+ // file is encrypted and the AESDecContext argument is NULL, the frame buffer
+ // will contain the ciphertext frame data. If the HMACContext argument is
+ // not NULL, the HMAC will be calculated (if the file supports it).
+ // Returns RESULT_INIT if the file is not open, failure if the frame number is
+ // out of range, or if optional decrypt or HAMC operations fail.
+ Result_t ReadFrame(ui32_t frame_number, FrameBuffer&, AESDecContext* = 0, HMACContext* = 0) const;
+
+ // Calculates the first frame in transport order of the GOP in which the requested
+ // frame is located. Calls ReadFrame() to fetch the frame at the calculated position.
+ // Returns RESULT_INIT if the file is not open.
+ Result_t ReadFrameGOPStart(ui32_t frame_number, FrameBuffer&, AESDecContext* = 0, HMACContext* = 0) const;
+
+ // Calculates the first frame in transport order of the GOP in which the requested
+ // frame is located. Sets key_frame_number to the number of the frame at the calculated position.
+ // Returns RESULT_INIT if the file is not open.
+ Result_t FindFrameGOPStart(ui32_t frame_number, ui32_t& key_frame_number) const;
+
+ // Returns the type of the frame at the given position.
+ // Returns RESULT_INIT if the file is not open or RESULT_RANGE if the index is out of range.
+ Result_t FrameType(ui32_t frame_number, FrameType_t&) const;
+
+ // Print debugging information to stream
+ void DumpHeaderMetadata(FILE* = 0) const;
+ void DumpIndex(FILE* = 0) const;
+ };
+ } // namespace MPEG2
+
+ //---------------------------------------------------------------------------------
+ //
+
+
+
+ namespace PCM
+ {
+ // The default value of the ChannelFormat element of the AudioDescriptor struct
+ // is CF_NONE. If the value is set to one of the other ChannelFormat_t enum
+ // values, the file's Wave Audio Descriptor will contain a Channel Assignment
+ // element.
+ //
+ // The channel format should be one of (CF_CFG_1, CF_CFG_2, or CF_CFG_3) for
+ // SMPTE 429-2 files. It should normally be CF_NONE for JPEG Interop files, but
+ // the 429-2 may also be used.
+ //
+ enum ChannelFormat_t {
+ CF_NONE,
+ CF_CFG_1, // 5.1 with optional HI/VI
+ CF_CFG_2, // 6.1 (5.1 + center surround) with optional HI/VI
+ CF_CFG_3, // 7.1 (SDDS) with optional HI/VI
+ CF_CFG_4, // Wild Track Format
+ CF_CFG_5, // 7.1 DS with optional HI/VI
+ };
+
+ struct AudioDescriptor
+ {
+ Rational EditRate; // rate of frame wrapping
+ Rational AudioSamplingRate; // rate of audio sample
+ ui32_t Locked; //
+ ui32_t ChannelCount; // number of channels
+ ui32_t QuantizationBits; // number of bits per single-channel sample
+ ui32_t BlockAlign; // number of bytes ber sample, all channels
+ ui32_t AvgBps; //
+ ui32_t LinkedTrackID; //
+ ui32_t ContainerDuration; // number of frames
+ ChannelFormat_t ChannelFormat; // audio channel arrangement
+ };
+
+ // Print AudioDescriptor to std::ostream
+ std::ostream& operator << (std::ostream& strm, const AudioDescriptor& adesc);
+ // Print debugging information to stream (stderr default)
+ void AudioDescriptorDump(const AudioDescriptor&, FILE* = 0);
+
+ // Returns size in bytes of a single sample of data described by ADesc
+ inline ui32_t CalcSampleSize(const AudioDescriptor& ADesc)
+ {
+ return (ADesc.QuantizationBits / 8) * ADesc.ChannelCount;
+ }
+
+ // Returns number of samples per frame of data described by ADesc
+ inline ui32_t CalcSamplesPerFrame(const AudioDescriptor& ADesc)
+ {
+ double tmpd = ADesc.AudioSamplingRate.Quotient() / ADesc.EditRate.Quotient();
+ return (ui32_t)ceil(tmpd);
+ }
+
+ // Returns the size in bytes of a frame of data described by ADesc
+ inline ui32_t CalcFrameBufferSize(const AudioDescriptor& ADesc)
+ {
+ return CalcSampleSize(ADesc) * CalcSamplesPerFrame(ADesc);
+ }
+
+ //
+ class FrameBuffer : public ASDCP::FrameBuffer
+ {
+ public:
+ FrameBuffer() {}
+ FrameBuffer(ui32_t size) { Capacity(size); }
+ virtual ~FrameBuffer() {}
+
+ // Print debugging information to stream (stderr default)
+ void Dump(FILE* = 0, ui32_t dump_bytes = 0) const;
+ };
+
+ // An object which opens and reads a WAV file. The call to OpenRead() reads metadata from
+ // the file and populates an internal AudioDescriptor object. Each subsequent call to
+ // ReadFrame() reads exactly one frame from the stream into the given FrameBuffer object.
+ // A "frame" is either 2000 or 2002 samples, depending upon the value of PictureRate.
+ class WAVParser
+ {
+ class h__WAVParser;
+ mem_ptr<h__WAVParser> m_Parser;
+ ASDCP_NO_COPY_CONSTRUCT(WAVParser);
+
+ public:
+ WAVParser();
+ virtual ~WAVParser();
+
+ // Opens the stream for reading, parses enough data to provide a complete
+ // set of stream metadata for the MXFWriter below. PictureRate controls
+ // ther frame rate for the MXF frame wrapping option.
+ Result_t OpenRead(const char* filename, const Rational& PictureRate) const;
+
+ // Fill an AudioDescriptor struct with the values from the file's header.
+ // Returns RESULT_INIT if the file is not open.
+ Result_t FillAudioDescriptor(AudioDescriptor&) const;
+
+ // Rewind the stream to the beginning.
+ Result_t Reset() const;
+
+ // Reads the next sequential frame in the input file and places it in the
+ // frame buffer. Fails if the buffer is too small or the stream is empty.
+ Result_t ReadFrame(FrameBuffer&) const;
+ };
+
+
+ //
+ class MXFWriter
+ {
+ class h__Writer;
+ mem_ptr<h__Writer> m_Writer;
+ ASDCP_NO_COPY_CONSTRUCT(MXFWriter);
+
+ public:
+ MXFWriter();
+ virtual ~MXFWriter();
+
+ // Warning: direct manipulation of MXF structures can interfere
+ // with the normal operation of the wrapper. Caveat emptor!
+ virtual MXF::OPAtomHeader& OPAtomHeader();
+ virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter();
+
+ // Open the file for writing. The file must not exist. Returns error if
+ // the operation cannot be completed or if nonsensical data is discovered
+ // in the essence descriptor.
+ Result_t OpenWrite(const char* filename, const WriterInfo&,
+ const AudioDescriptor&, ui32_t HeaderSize = 16384);
+
+ // Writes a frame of essence to the MXF file. If the optional AESEncContext
+ // argument is present, the essence is encrypted prior to writing.
+ // Fails if the file is not open, is finalized, or an operating system
+ // error occurs.
+ Result_t WriteFrame(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0);
+
+ // Closes the MXF file, writing the index and revised header.
+ Result_t Finalize();
+ };
+
+ //
+ class MXFReader
+ {
+ class h__Reader;
+ mem_ptr<h__Reader> m_Reader;
+ ASDCP_NO_COPY_CONSTRUCT(MXFReader);
+
+ public:
+ MXFReader();
+ virtual ~MXFReader();
+
+ // Warning: direct manipulation of MXF structures can interfere
+ // with the normal operation of the wrapper. Caveat emptor!
+ virtual MXF::OPAtomHeader& OPAtomHeader();
+ virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter();
+
+ // Open the file for reading. The file must exist. Returns error if the
+ // operation cannot be completed.
+ Result_t OpenRead(const char* filename) const;
+
+ // Returns RESULT_INIT if the file is not open.
+ Result_t Close() const;
+
+ // Fill an AudioDescriptor struct with the values from the file's header.
+ // Returns RESULT_INIT if the file is not open.
+ Result_t FillAudioDescriptor(AudioDescriptor&) const;
+
+ // Fill a WriterInfo struct with the values from the file's header.
+ // Returns RESULT_INIT if the file is not open.
+ Result_t FillWriterInfo(WriterInfo&) const;
+
+ // Reads a frame of essence from the MXF file. If the optional AESEncContext
+ // argument is present, the essence is decrypted after reading. If the MXF
+ // file is encrypted and the AESDecContext argument is NULL, the frame buffer
+ // will contain the ciphertext frame data. If the HMACContext argument is
+ // not NULL, the HMAC will be calculated (if the file supports it).
+ // Returns RESULT_INIT if the file is not open, failure if the frame number is
+ // out of range, or if optional decrypt or HAMC operations fail.
+ Result_t ReadFrame(ui32_t frame_number, FrameBuffer&, AESDecContext* = 0, HMACContext* = 0) const;
+
+ // Print debugging information to stream
+ void DumpHeaderMetadata(FILE* = 0) const;
+ void DumpIndex(FILE* = 0) const;
+ };
+ } // namespace PCM
+
+ //---------------------------------------------------------------------------------
+ //
+ namespace JP2K
+ {
+ const ui32_t MaxComponents = 3;
+ const ui32_t MaxPrecincts = 32; // ISO 15444-1 Annex A.6.1
+ const ui32_t MaxDefaults = 256; // made up
+
+#pragma pack(1)
+ struct ImageComponent_t // ISO 15444-1 Annex A.5.1
+ {
+ ui8_t Ssize;
+ ui8_t XRsize;
+ ui8_t YRsize;
+ };
+
+ struct CodingStyleDefault_t // ISO 15444-1 Annex A.6.1
+ {
+ ui8_t Scod;
+
+ struct
+ {
+ ui8_t ProgressionOrder;
+ ui8_t NumberOfLayers[sizeof(ui16_t)];
+ ui8_t MultiCompTransform;
+ } SGcod;
+
+ struct
+ {
+ ui8_t DecompositionLevels;
+ ui8_t CodeblockWidth;
+ ui8_t CodeblockHeight;
+ ui8_t CodeblockStyle;
+ ui8_t Transformation;
+ ui8_t PrecinctSize[MaxPrecincts];
+ } SPcod;
+ };
+
+ struct QuantizationDefault_t // ISO 15444-1 Annex A.6.4
+ {
+ ui8_t Sqcd;
+ ui8_t SPqcd[MaxDefaults];
+ ui8_t SPqcdLength;
+ };
+#pragma pack()
+
+ struct PictureDescriptor
+ {
+ Rational EditRate;
+ ui32_t ContainerDuration;
+ Rational SampleRate;
+ ui32_t StoredWidth;
+ ui32_t StoredHeight;
+ Rational AspectRatio;
+ ui16_t Rsize;
+ ui32_t Xsize;
+ ui32_t Ysize;
+ ui32_t XOsize;
+ ui32_t YOsize;
+ ui32_t XTsize;
+ ui32_t YTsize;
+ ui32_t XTOsize;
+ ui32_t YTOsize;
+ ui16_t Csize;
+ ImageComponent_t ImageComponents[MaxComponents];
+ CodingStyleDefault_t CodingStyleDefault;
+ QuantizationDefault_t QuantizationDefault;
+ };
+
+ // Print debugging information to std::ostream
+ std::ostream& operator << (std::ostream& strm, const PictureDescriptor& pdesc);
+ // Print debugging information to stream (stderr default)
+ void PictureDescriptorDump(const PictureDescriptor&, FILE* = 0);
+
+ //
+ class FrameBuffer : public ASDCP::FrameBuffer
+ {
+ public:
+ FrameBuffer() {}
+ FrameBuffer(ui32_t size) { Capacity(size); }
+ virtual ~FrameBuffer() {}
+
+ // Print debugging information to stream (stderr default)
+ void Dump(FILE* = 0, ui32_t dump_bytes = 0) const;
+ };
+
+
+ // An object which opens and reads a JPEG 2000 codestream file. The file is expected
+ // to contain exactly one complete frame of picture essence as an unwrapped (raw)
+ // ISO/IEC 15444 codestream.
+ class CodestreamParser
+ {
+ class h__CodestreamParser;
+ mem_ptr<h__CodestreamParser> m_Parser;
+ ASDCP_NO_COPY_CONSTRUCT(CodestreamParser);
+
+ public:
+ CodestreamParser();
+ virtual ~CodestreamParser();
+
+ // Opens a file for reading, parses enough data to provide a complete
+ // set of stream metadata for the MXFWriter below.
+ // The frame buffer's PlaintextOffset parameter will be set to the first
+ // byte of the data segment. Set this value to zero if you want
+ // encrypted headers.
+ Result_t OpenReadFrame(const char* filename, FrameBuffer&) const;
+
+ Result_t OpenReadFrame(const unsigned char * data, unsigned int size, FrameBuffer&) const;
+
+ // Fill a PictureDescriptor struct with the values from the file's codestream.
+ // Returns RESULT_INIT if the file is not open.
+ Result_t FillPictureDescriptor(PictureDescriptor&) const;
+ };
+
+ // Parses the data in the frame buffer to fill in the picture descriptor. Copies
+ // the offset of the image data into start_of_data. Returns error if the parser fails.
+ Result_t ParseMetadataIntoDesc(const FrameBuffer&, PictureDescriptor&, byte_t* start_of_data = 0);
+
+ // An object which reads a sequence of files containing JPEG 2000 pictures.
+ class SequenceParser
+ {
+ class h__SequenceParser;
+ mem_ptr<h__SequenceParser> m_Parser;
+ ASDCP_NO_COPY_CONSTRUCT(SequenceParser);
+
+ public:
+ SequenceParser();
+ virtual ~SequenceParser();
+
+ // Opens a directory for reading. The directory is expected to contain one or
+ // more files, each containing the codestream for exactly one picture. The
+ // files must be named such that the frames are in temporal order when sorted
+ // alphabetically by filename. The parser will automatically parse enough data
+ // from the first file to provide a complete set of stream metadata for the
+ // MXFWriter below. If the "pedantic" parameter is given and is true, the
+ // parser will check the metadata for each codestream and fail if a
+ // mismatch is detected.
+ Result_t OpenRead(const char* filename, bool pedantic = false) const;
+
+ // Opens a file sequence for reading. The sequence is expected to contain one or
+ // more filenames, each naming a file containing the codestream for exactly one
+ // picture. The parser will automatically parse enough data
+ // from the first file to provide a complete set of stream metadata for the
+ // MXFWriter below. If the "pedantic" parameter is given and is true, the
+ // parser will check the metadata for each codestream and fail if a
+ // mismatch is detected.
+ Result_t OpenRead(const std::list<std::string>& file_list, bool pedantic = false) const;
+
+ // Fill a PictureDescriptor struct with the values from the first file's codestream.
+ // Returns RESULT_INIT if the directory is not open.
+ Result_t FillPictureDescriptor(PictureDescriptor&) const;
+
+ // Rewind the directory to the beginning.
+ Result_t Reset() const;
+
+ // Reads the next sequential frame in the directory and places it in the
+ // frame buffer. Fails if the buffer is too small or the direcdtory
+ // contains no more files.
+ // The frame buffer's PlaintextOffset parameter will be set to the first
+ // byte of the data segment. Set this value to zero if you want
+ // encrypted headers.
+ Result_t ReadFrame(FrameBuffer&) const;
+ };
+
+
+ //
+ class MXFWriter
+ {
+ class h__Writer;
+ mem_ptr<h__Writer> m_Writer;
+ ASDCP_NO_COPY_CONSTRUCT(MXFWriter);
+
+ public:
+ MXFWriter();
+ virtual ~MXFWriter();
+
+ // Warning: direct manipulation of MXF structures can interfere
+ // with the normal operation of the wrapper. Caveat emptor!
+ virtual MXF::OPAtomHeader& OPAtomHeader();
+ virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter();
+
+ // Open the file for writing. The file must not exist unless overwrite is true. Returns error if
+ // the operation cannot be completed or if nonsensical data is discovered
+ // in the essence descriptor.
+ Result_t OpenWrite(const char* filename, const WriterInfo&,
+ const PictureDescriptor&, ui32_t HeaderSize, bool overwrite);
+
+ // Writes a frame of essence to the MXF file. If the optional AESEncContext
+ // argument is present, the essence is encrypted prior to writing.
+ // A MD5 hash of the data that we write is written to hash if it is not 0
+ // Fails if the file is not open, is finalized, or an operating system
+ // error occurs.
+ Result_t WriteFrame(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0, std::string* hash = 0);
+
+ Result_t FakeWriteFrame(int size);
+
+ // Closes the MXF file, writing the index and revised header.
+ Result_t Finalize();
+
+ // Return the current file offset in the MXF file that we are writing
+ ui64_t Tell() const;
+ };
+
+ //
+ class MXFReader
+ {
+ class h__Reader;
+ mem_ptr<h__Reader> m_Reader;
+ ASDCP_NO_COPY_CONSTRUCT(MXFReader);
+
+ public:
+ MXFReader();
+ virtual ~MXFReader();
+
+ // Warning: direct manipulation of MXF structures can interfere
+ // with the normal operation of the wrapper. Caveat emptor!
+ virtual MXF::OPAtomHeader& OPAtomHeader();
+ virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter();
+
+ // Open the file for reading. The file must exist. Returns error if the
+ // operation cannot be completed.
+ Result_t OpenRead(const char* filename) const;
+
+ // Returns RESULT_INIT if the file is not open.
+ Result_t Close() const;
+
+ // Fill an AudioDescriptor struct with the values from the file's header.
+ // Returns RESULT_INIT if the file is not open.
+ Result_t FillPictureDescriptor(PictureDescriptor&) const;
+
+ // Fill a WriterInfo struct with the values from the file's header.
+ // Returns RESULT_INIT if the file is not open.
+ Result_t FillWriterInfo(WriterInfo&) const;
+
+ // Reads a frame of essence from the MXF file. If the optional AESEncContext
+ // argument is present, the essence is decrypted after reading. If the MXF
+ // file is encrypted and the AESDecContext argument is NULL, the frame buffer
+ // will contain the ciphertext frame data. If the HMACContext argument is
+ // not NULL, the HMAC will be calculated (if the file supports it).
+ // Returns RESULT_INIT if the file is not open, failure if the frame number is
+ // out of range, or if optional decrypt or HAMC operations fail.
+ Result_t ReadFrame(ui32_t frame_number, FrameBuffer&, AESDecContext* = 0, HMACContext* = 0) const;
+
+ // Print debugging information to stream
+ void DumpHeaderMetadata(FILE* = 0) const;
+ void DumpIndex(FILE* = 0) const;
+ };
+
+
+ // Stereoscopic Image support
+ //
+
+ enum StereoscopicPhase_t
+ {
+ SP_LEFT,
+ SP_RIGHT
+ };
+
+ struct SFrameBuffer
+ {
+ JP2K::FrameBuffer Left;
+ JP2K::FrameBuffer Right;
+
+ SFrameBuffer(ui32_t size) {
+ Left.Capacity(size);
+ Right.Capacity(size);
+ }
+ };
+
+ class MXFSWriter
+ {
+ class h__SWriter;
+ mem_ptr<h__SWriter> m_Writer;
+ ASDCP_NO_COPY_CONSTRUCT(MXFSWriter);
+
+ public:
+ MXFSWriter();
+ virtual ~MXFSWriter();
+
+ // Warning: direct manipulation of MXF structures can interfere
+ // with the normal operation of the wrapper. Caveat emptor!
+ virtual MXF::OPAtomHeader& OPAtomHeader();
+ virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter();
+
+ // Open the file for writing. The file must not exist unless overwrite is true. Returns error if
+ // the operation cannot be completed or if nonsensical data is discovered
+ // in the essence descriptor.
+ Result_t OpenWrite(const char* filename, const WriterInfo&,
+ const PictureDescriptor&, ui32_t HeaderSize, bool overwrite);
+
+ // Writes a pair of frames of essence to the MXF file. If the optional AESEncContext
+ // argument is present, the essence is encrypted prior to writing.
+ // Fails if the file is not open, is finalized, or an operating system
+ // error occurs.
+ Result_t WriteFrame(const SFrameBuffer&, AESEncContext* = 0, HMACContext* = 0);
+
+ // Writes a frame of essence to the MXF file. If the optional AESEncContext
+ // argument is present, the essence is encrypted prior to writing.
+ // Fails if the file is not open, is finalized, or an operating system
+ // error occurs. Frames must be written in the proper phase (L-R-L-R),
+ // RESULT_SPHASE will be returned if phase is reversed. The first frame
+ // written must be left eye.
+ Result_t WriteFrame(const FrameBuffer&, StereoscopicPhase_t phase,
+ AESEncContext* = 0, HMACContext* = 0, std::string* hash = 0);
+
+ Result_t FakeWriteFrame(int size, StereoscopicPhase_t phase);
+
+ // Closes the MXF file, writing the index and revised header. Returns
+ // RESULT_SPHASE if WriteFrame was called an odd number of times.
+ Result_t Finalize();
+
+ // Return the current file offset in the MXF file that we are writing
+ ui64_t Tell() const;
+ };
+
+ //
+ class MXFSReader
+ {
+ class h__SReader;
+ mem_ptr<h__SReader> m_Reader;
+ ASDCP_NO_COPY_CONSTRUCT(MXFSReader);
+
+ public:
+ MXFSReader();
+ virtual ~MXFSReader();
+
+ // Warning: direct manipulation of MXF structures can interfere
+ // with the normal operation of the wrapper. Caveat emptor!
+ virtual MXF::OPAtomHeader& OPAtomHeader();
+ virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter();
+
+ // Open the file for reading. The file must exist. Returns error if the
+ // operation cannot be completed.
+ Result_t OpenRead(const char* filename) const;
+
+ // Returns RESULT_INIT if the file is not open.
+ Result_t Close() const;
+
+ // Fill an AudioDescriptor struct with the values from the file's header.
+ // Returns RESULT_INIT if the file is not open.
+ Result_t FillPictureDescriptor(PictureDescriptor&) const;
+
+ // Fill a WriterInfo struct with the values from the file's header.
+ // Returns RESULT_INIT if the file is not open.
+ Result_t FillWriterInfo(WriterInfo&) const;
+
+ // Reads a pair of frames of essence from the MXF file. If the optional AESEncContext
+ // argument is present, the essence is decrypted after reading. If the MXF
+ // file is encrypted and the AESDecContext argument is NULL, the frame buffer
+ // will contain the ciphertext frame data. If the HMACContext argument is
+ // not NULL, the HMAC will be calculated (if the file supports it).
+ // Returns RESULT_INIT if the file is not open, failure if the frame number is
+ // out of range, or if optional decrypt or HAMC operations fail.
+ Result_t ReadFrame(ui32_t frame_number, SFrameBuffer&, AESDecContext* = 0, HMACContext* = 0) const;
+
+ // Reads a frame of essence from the MXF file. If the optional AESEncContext
+ // argument is present, the essence is decrypted after reading. If the MXF
+ // file is encrypted and the AESDecContext argument is NULL, the frame buffer
+ // will contain the ciphertext frame data. If the HMACContext argument is
+ // not NULL, the HMAC will be calculated (if the file supports it).
+ // Returns RESULT_INIT if the file is not open, failure if the frame number is
+ // out of range, or if optional decrypt or HAMC operations fail.
+ Result_t ReadFrame(ui32_t frame_number, StereoscopicPhase_t phase,
+ FrameBuffer&, AESDecContext* = 0, HMACContext* = 0) const;
+
+ // Print debugging information to stream
+ void DumpHeaderMetadata(FILE* = 0) const;
+ void DumpIndex(FILE* = 0) const;
+ };
+ } // namespace JP2K
+
+ //---------------------------------------------------------------------------------
+ //
+ namespace TimedText
+ {
+ enum MIMEType_t { MT_BIN, MT_PNG, MT_OPENTYPE };
+
+ struct TimedTextResourceDescriptor
+ {
+ byte_t ResourceID[UUIDlen];
+ MIMEType_t Type;
+
+ TimedTextResourceDescriptor() : Type(MT_BIN) {}
+ };
+
+ typedef std::list<TimedTextResourceDescriptor> ResourceList_t;
+
+ struct TimedTextDescriptor
+ {
+ Rational EditRate; //
+ ui32_t ContainerDuration;
+ byte_t AssetID[UUIDlen];
+ std::string NamespaceName;
+ std::string EncodingName;
+ ResourceList_t ResourceList;
+
+ TimedTextDescriptor() : ContainerDuration(0), EncodingName("UTF-8") {} // D-Cinema format is always UTF-8
+ };
+
+ // Print debugging information to std::ostream
+ std::ostream& operator << (std::ostream& strm, const TimedTextDescriptor& tinfo);
+ // Print debugging information to stream (stderr default)
+ void DescriptorDump(const TimedTextDescriptor&, FILE* = 0);
+
+ //
+ class FrameBuffer : public ASDCP::FrameBuffer
+ {
+ ASDCP_NO_COPY_CONSTRUCT(FrameBuffer); // TODO: should have copy construct
+
+ protected:
+ byte_t m_AssetID[UUIDlen];
+ std::string m_MIMEType;
+
+ public:
+ FrameBuffer() { memset(m_AssetID, 0, UUIDlen); }
+ FrameBuffer(ui32_t size) { Capacity(size); memset(m_AssetID, 0, UUIDlen); }
+ virtual ~FrameBuffer() {}
+
+ inline const byte_t* AssetID() const { return m_AssetID; }
+ inline void AssetID(const byte_t* buf) { memcpy(m_AssetID, buf, UUIDlen); }
+ inline const char* MIMEType() const { return m_MIMEType.c_str(); }
+ inline void MIMEType(const std::string& s) { m_MIMEType = s; }
+
+ // Print debugging information to stream (stderr default)
+ void Dump(FILE* = 0, ui32_t dump_bytes = 0) const;
+ };
+
+ //
+ class IResourceResolver
+ {
+ public:
+ virtual ~IResourceResolver() {}
+ virtual Result_t ResolveRID(const byte_t* uuid, FrameBuffer&) const = 0; // return data for RID
+ };
+
+ //
+ class DCSubtitleParser
+ {
+ class h__SubtitleParser;
+ mem_ptr<h__SubtitleParser> m_Parser;
+ ASDCP_NO_COPY_CONSTRUCT(DCSubtitleParser);
+
+ public:
+ DCSubtitleParser();
+ virtual ~DCSubtitleParser();
+
+ // Opens an XML file for reading, parses data to provide a complete
+ // set of stream metadata for the MXFWriter below.
+ Result_t OpenRead(const char* filename) const;
+
+ // Parses an XML document to provide a complete set of stream metadata
+ // for the MXFWriter below. The optional filename argument is used to
+ // initialize the default resource resolver (see ReadAncillaryResource).
+ Result_t OpenRead(const std::string& xml_doc, const char* filename = 0) const;
+
+ // Fill a TimedTextDescriptor struct with the values from the file's contents.
+ // Returns RESULT_INIT if the file is not open.
+ Result_t FillTimedTextDescriptor(TimedTextDescriptor&) const;
+
+ // Reads the complete Timed Text Resource into the given string.
+ Result_t ReadTimedTextResource(std::string&) const;
+
+ // Reads the Ancillary Resource having the given ID. Fails if the buffer
+ // is too small or the resource does not exist. The optional Resolver
+ // argument can be provided which will be used to retrieve the resource
+ // having a particulat UUID. If a Resolver is not supplied, the default
+ // internal resolver will return the contents of the file having the UUID
+ // as the filename. The filename must exist in the same directory as the
+ // XML file opened with OpenRead().
+ Result_t ReadAncillaryResource(const byte_t* uuid, FrameBuffer&,
+ const IResourceResolver* Resolver = 0) const;
+ };
+
+ //
+ class MXFWriter
+ {
+ class h__Writer;
+ mem_ptr<h__Writer> m_Writer;
+ ASDCP_NO_COPY_CONSTRUCT(MXFWriter);
+
+ public:
+ MXFWriter();
+ virtual ~MXFWriter();
+
+ // Warning: direct manipulation of MXF structures can interfere
+ // with the normal operation of the wrapper. Caveat emptor!
+ virtual MXF::OPAtomHeader& OPAtomHeader();
+ virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter();
+
+ // Open the file for writing. The file must not exist. Returns error if
+ // the operation cannot be completed or if nonsensical data is discovered
+ // in the essence descriptor.
+ Result_t OpenWrite(const char* filename, const WriterInfo&,
+ const TimedTextDescriptor&, ui32_t HeaderSize = 16384);
+
+ // Writes the Timed-Text Resource to the MXF file. The file must be UTF-8
+ // encoded. If the optional AESEncContext argument is present, the essence
+ // is encrypted prior to writing. Fails if the file is not open, is finalized,
+ // or an operating system error occurs.
+ // This method may only be called once, and it must be called before any
+ // call to WriteAncillaryResource(). RESULT_STATE will be returned if these
+ // conditions are not met.
+ Result_t WriteTimedTextResource(const std::string& XMLDoc, AESEncContext* = 0, HMACContext* = 0);
+
+ // Writes an Ancillary Resource to the MXF file. If the optional AESEncContext
+ // argument is present, the essence is encrypted prior to writing.
+ // Fails if the file is not open, is finalized, or an operating system
+ // error occurs. RESULT_STATE will be returned if the method is called before
+ // WriteTimedTextResource()
+ Result_t WriteAncillaryResource(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0);
+
+ // Closes the MXF file, writing the index and revised header.
+ Result_t Finalize();
+ };
+
+ //
+ class MXFReader
+ {
+ class h__Reader;
+ mem_ptr<h__Reader> m_Reader;
+ ASDCP_NO_COPY_CONSTRUCT(MXFReader);
+
+ public:
+ MXFReader();
+ virtual ~MXFReader();
+
+ // Warning: direct manipulation of MXF structures can interfere
+ // with the normal operation of the wrapper. Caveat emptor!
+ virtual MXF::OPAtomHeader& OPAtomHeader();
+ virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter();
+
+ // Open the file for reading. The file must exist. Returns error if the
+ // operation cannot be completed.
+ Result_t OpenRead(const char* filename) const;
+
+ // Returns RESULT_INIT if the file is not open.
+ Result_t Close() const;
+
+ // Fill a TimedTextDescriptor struct with the values from the file's header.
+ // Returns RESULT_INIT if the file is not open.
+ Result_t FillTimedTextDescriptor(TimedTextDescriptor&) const;
+
+ // Fill a WriterInfo struct with the values from the file's header.
+ // Returns RESULT_INIT if the file is not open.
+ Result_t FillWriterInfo(WriterInfo&) const;
+
+ // Reads the complete Timed Text Resource into the given string. Fails if the resource
+ // is encrypted and AESDecContext is NULL (use the following method to retrieve the
+ // raw ciphertet block).
+ Result_t ReadTimedTextResource(std::string&, AESDecContext* = 0, HMACContext* = 0) const;
+
+ // Reads the complete Timed Text Resource from the MXF file. If the optional AESEncContext
+ // argument is present, the resource is decrypted after reading. If the MXF
+ // file is encrypted and the AESDecContext argument is NULL, the frame buffer
+ // will contain the ciphertext frame data. If the HMACContext argument is
+ // not NULL, the HMAC will be calculated (if the file supports it).
+ // Returns RESULT_INIT if the file is not open, failure if the frame number is
+ // out of range, or if optional decrypt or HAMC operations fail.
+ Result_t ReadTimedTextResource(FrameBuffer&, AESDecContext* = 0, HMACContext* = 0) const;
+
+ // Reads the timed-text resource having the given UUID from the MXF file. If the
+ // optional AESEncContext argument is present, the resource is decrypted after
+ // reading. If the MXF file is encrypted and the AESDecContext argument is NULL,
+ // the frame buffer will contain the ciphertext frame data. If the HMACContext
+ // argument is not NULL, the HMAC will be calculated (if the file supports it).
+ // Returns RESULT_INIT if the file is not open, failure if the frame number is
+ // out of range, or if optional decrypt or HAMC operations fail.
+ Result_t ReadAncillaryResource(const byte_t* uuid, FrameBuffer&, AESDecContext* = 0, HMACContext* = 0) const;
+
+ // Print debugging information to stream
+ void DumpHeaderMetadata(FILE* = 0) const;
+ void DumpIndex(FILE* = 0) const;
+ };
+ } // namespace TimedText
+
+
+} // namespace ASDCP
+
+
+#endif // _AS_DCP_H_
+
+//
+// end AS_DCP.h
+//
diff --git a/asdcplib/src/AS_DCP_AES.cpp b/asdcplib/src/AS_DCP_AES.cpp
new file mode 100755
index 0000000..bb2a400
--- /dev/null
+++ b/asdcplib/src/AS_DCP_AES.cpp
@@ -0,0 +1,446 @@
+/*
+Copyright (c) 2004-2009, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file AS_DCP_AES.h
+ \version $Id: AS_DCP_AES.cpp,v 1.13 2009/10/15 17:31:27 jhurst Exp $
+ \brief AS-DCP library, AES wrapper
+*/
+
+
+#include <assert.h>
+#include <AS_DCP.h>
+#include <KM_log.h>
+#include <KM_prng.h>
+using Kumu::DefaultLogSink;
+
+using namespace ASDCP;
+const int KEY_SIZE_BITS = 128;
+
+#include <openssl/aes.h>
+#include <openssl/sha.h>
+#include <openssl/bn.h>
+#include <openssl/err.h>
+
+
+void
+print_ssl_error()
+{
+ char err_buf[256];
+ unsigned long errval = ERR_get_error();
+ DefaultLogSink().Error("OpenSSL: %s\n", ERR_error_string(errval, err_buf));
+}
+
+//------------------------------------------------------------------------------------------
+
+class ASDCP::AESEncContext::h__AESContext : public AES_KEY
+{
+public:
+ byte_t m_IVec[CBC_BLOCK_SIZE];
+};
+
+
+ASDCP::AESEncContext::AESEncContext() {}
+ASDCP::AESEncContext::~AESEncContext() {}
+
+// Initializes Rijndael CBC encryption context.
+// Returns error if the key argument is NULL.
+ASDCP::Result_t
+ASDCP::AESEncContext::InitKey(const byte_t* key)
+{
+ KM_TEST_NULL_L(key);
+
+ if ( m_Context )
+ return RESULT_INIT;
+
+ m_Context = new h__AESContext;
+
+ if ( AES_set_encrypt_key(key, KEY_SIZE_BITS, m_Context) )
+ {
+ print_ssl_error();
+ return RESULT_CRYPT_INIT;
+ }
+
+ return RESULT_OK;
+}
+
+
+// Set the value of the 16 byte CBC Initialization Vector. This operation may be performed
+// any number of times for a given key.
+// Returns error if the i_vec argument is NULL.
+ASDCP::Result_t
+ASDCP::AESEncContext::SetIVec(const byte_t* i_vec)
+{
+ KM_TEST_NULL_L(i_vec);
+
+ if ( ! m_Context )
+ return RESULT_INIT;
+
+ memcpy(m_Context->m_IVec, i_vec, CBC_BLOCK_SIZE);
+ return RESULT_OK;
+}
+
+
+// Retrieve the value of the 16 byte CBC Initialization Vector.
+// Returns error if the i_vec argument is NULL.
+ASDCP::Result_t
+ASDCP::AESEncContext::GetIVec(byte_t* i_vec) const
+{
+ KM_TEST_NULL_L(i_vec);
+
+ if ( ! m_Context )
+ return RESULT_INIT;
+
+ memcpy(i_vec, m_Context->m_IVec, CBC_BLOCK_SIZE);
+ return RESULT_OK;
+}
+
+
+// Encrypt a 16 byte block of data.
+// Returns error if either argument is NULL.
+ASDCP::Result_t
+ASDCP::AESEncContext::EncryptBlock(const byte_t* pt_buf, byte_t* ct_buf, ui32_t block_size)
+{
+ KM_TEST_NULL_L(pt_buf);
+ KM_TEST_NULL_L(ct_buf);
+ assert(block_size > 0);
+ assert( block_size % CBC_BLOCK_SIZE == 0 );
+
+ if ( m_Context.empty() )
+ return RESULT_INIT;
+
+ h__AESContext* Ctx = m_Context;
+ byte_t tmp_buf[CBC_BLOCK_SIZE];
+ const byte_t* in_p = pt_buf;
+ byte_t* out_p = ct_buf;
+
+ while ( block_size )
+ {
+ // xor with the previous block
+ for ( ui32_t i = 0; i < CBC_BLOCK_SIZE; i++ )
+ tmp_buf[i] = in_p[i] ^ Ctx->m_IVec[i];
+
+ AES_encrypt(tmp_buf, Ctx->m_IVec, Ctx);
+ memcpy(out_p, Ctx->m_IVec, CBC_BLOCK_SIZE);
+
+ in_p += CBC_BLOCK_SIZE;
+ out_p += CBC_BLOCK_SIZE;
+ block_size -= CBC_BLOCK_SIZE;
+ }
+
+ return RESULT_OK;
+}
+
+
+//------------------------------------------------------------------------------------------
+
+class ASDCP::AESDecContext::h__AESContext : public AES_KEY
+{
+public:
+ byte_t m_IVec[CBC_BLOCK_SIZE];
+};
+
+ASDCP::AESDecContext::AESDecContext() {}
+ASDCP::AESDecContext::~AESDecContext() {}
+
+
+// Initializes Rijndael CBC decryption context.
+// Returns error if the key argument is NULL.
+ASDCP::Result_t
+ASDCP::AESDecContext::InitKey(const byte_t* key)
+{
+ KM_TEST_NULL_L(key);
+
+ if ( m_Context )
+ return RESULT_INIT;
+
+ m_Context = new h__AESContext;
+
+ if ( AES_set_decrypt_key(key, KEY_SIZE_BITS, m_Context) )
+ {
+ print_ssl_error();
+ return RESULT_CRYPT_INIT;
+ }
+
+ return RESULT_OK;
+}
+
+// Initializes 16 byte CBC Initialization Vector. This operation may be performed
+// any number of times for a given key.
+// Returns error if the i_vec argument is NULL.
+ASDCP::Result_t
+ASDCP::AESDecContext::SetIVec(const byte_t* i_vec)
+{
+ KM_TEST_NULL_L(i_vec);
+
+ if ( ! m_Context )
+ return RESULT_INIT;
+
+ memcpy(m_Context->m_IVec, i_vec, CBC_BLOCK_SIZE);
+ return RESULT_OK;
+}
+
+// Decrypt a 16 byte block of data.
+// Returns error if either argument is NULL.
+ASDCP::Result_t
+ASDCP::AESDecContext::DecryptBlock(const byte_t* ct_buf, byte_t* pt_buf, ui32_t block_size)
+{
+ KM_TEST_NULL_L(ct_buf);
+ KM_TEST_NULL_L(pt_buf);
+ assert(block_size > 0);
+ assert( block_size % CBC_BLOCK_SIZE == 0 );
+
+ if ( m_Context.empty() )
+ return RESULT_INIT;
+
+ register h__AESContext* Ctx = m_Context;
+
+ const byte_t* in_p = ct_buf;
+ byte_t* out_p = pt_buf;
+
+ while ( block_size )
+ {
+ AES_decrypt(in_p, out_p, Ctx);
+
+ for ( ui32_t i = 0; i < CBC_BLOCK_SIZE; i++ )
+ out_p[i] ^= Ctx->m_IVec[i];
+
+ memcpy(Ctx->m_IVec, in_p, CBC_BLOCK_SIZE);
+
+ in_p += CBC_BLOCK_SIZE;
+ out_p += CBC_BLOCK_SIZE;
+ block_size -= CBC_BLOCK_SIZE;
+ }
+
+ return RESULT_OK;
+}
+
+//------------------------------------------------------------------------------------------
+
+static const ui32_t B_len = 64; // rfc 2104, Sec. 2
+
+static byte_t const ipad_const = 0x36;
+static byte_t const opad_const = 0x5c;
+
+class HMACContext::h__HMACContext
+{
+ SHA_CTX m_SHA;
+ byte_t m_key[KeyLen];
+ ASDCP_NO_COPY_CONSTRUCT(h__HMACContext);
+
+public:
+ byte_t m_SHAValue[HMAC_SIZE];
+ bool m_Final;
+
+ h__HMACContext() : m_Final(false) {}
+ ~h__HMACContext() {}
+
+ // SMPTE 429.6 MIC key generation
+ void SetKey(const byte_t* key)
+ {
+ byte_t rng_buf[SHA_DIGEST_LENGTH*2];
+ Kumu::Gen_FIPS_186_Value(key, KeyLen, rng_buf, SHA_DIGEST_LENGTH*2);
+
+ // rng_buf contains two rounds, x0 and x1 (each 160 bits).
+ // Use x1 per SMPTE 430-6-2006 Sec. 7.10
+ memcpy(m_key, rng_buf+SHA_DIGEST_LENGTH, 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];
+
+ // 7.10: MICKey = trunc( SHA1 ( key, key_nonce ) )
+ SHA_CTX SHA;
+ SHA1_Init(&SHA);
+ SHA1_Update(&SHA, key, KeyLen);
+ SHA1_Update(&SHA, key_nonce, KeyLen);
+ SHA1_Final(sha_buf, &SHA);
+ memcpy(m_key, sha_buf, KeyLen);
+ Reset();
+ }
+
+ //
+ void
+ Reset()
+ {
+ byte_t xor_buf[B_len];
+ memset(xor_buf, 0, B_len);
+ memcpy(xor_buf, m_key, KeyLen);
+
+ 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 < B_len; i++ )
+ xor_buf[i] ^= ipad_const;
+
+ SHA1_Update(&m_SHA, xor_buf, B_len);
+ }
+
+ //
+ void
+ Update(const byte_t* buf, ui32_t buf_len)
+ {
+ // H(K XOR opad, H(K XOR ipad, text))
+ // ^^^^
+ SHA1_Update(&m_SHA, buf, buf_len);
+ }
+
+ //
+ void
+ Finalize()
+ {
+ SHA_CTX SHA;
+ SHA1_Init(&SHA);
+
+ byte_t xor_buf[B_len];
+ memset(xor_buf, 0, B_len);
+ memcpy(xor_buf, m_key, KeyLen);
+
+ SHA1_Init(&SHA);
+
+ // H(K XOR opad, H(K XOR ipad, text))
+ // ^^^^^^^^^^
+ for ( ui32_t i = 0; i < B_len; i++ )
+ xor_buf[i] ^= opad_const;
+
+ SHA1_Update(&SHA, xor_buf, B_len);
+
+ // H(K XOR opad, H(K XOR ipad, text))
+ // ^
+ SHA1_Final(m_SHAValue, &m_SHA);
+ SHA1_Update(&SHA, m_SHAValue, HMAC_SIZE);
+
+ // H(K XOR opad, H(K XOR ipad, text))
+ // ^
+ SHA1_Final(m_SHAValue, &SHA);
+ m_Final = true;
+ }
+};
+
+
+HMACContext::HMACContext()
+{
+}
+
+HMACContext::~HMACContext()
+{
+}
+
+
+//
+Result_t
+HMACContext::InitKey(const byte_t* key, LabelSet_t SetType)
+{
+ KM_TEST_NULL_L(key);
+
+ m_Context = new h__HMACContext;
+
+ 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;
+}
+
+
+//
+void
+HMACContext::Reset()
+{
+ if ( ! m_Context.empty() )
+ m_Context->Reset();
+}
+
+
+//
+Result_t
+HMACContext::Update(const byte_t* buf, ui32_t buf_len)
+{
+ KM_TEST_NULL_L(buf);
+
+ if ( m_Context.empty() || m_Context->m_Final )
+ return RESULT_INIT;
+
+ m_Context->Update(buf, buf_len);
+ return RESULT_OK;
+}
+
+
+//
+Result_t
+HMACContext::Finalize()
+{
+ if ( m_Context.empty() || m_Context->m_Final )
+ return RESULT_INIT;
+
+ m_Context->Finalize();
+ return RESULT_OK;
+}
+
+
+//
+Result_t
+HMACContext::GetHMACValue(byte_t* buf) const
+{
+ KM_TEST_NULL_L(buf);
+
+ if ( m_Context.empty() || ! m_Context->m_Final )
+ return RESULT_INIT;
+
+ memcpy(buf, m_Context->m_SHAValue, HMAC_SIZE);
+ return RESULT_OK;
+}
+
+
+//
+Result_t
+HMACContext::TestHMACValue(const byte_t* buf) const
+{
+ KM_TEST_NULL_L(buf);
+
+ if ( m_Context.empty() || ! m_Context->m_Final )
+ return RESULT_INIT;
+
+ return ( memcmp(buf, m_Context->m_SHAValue, HMAC_SIZE) == 0 ) ? RESULT_OK : RESULT_HMACFAIL;
+}
+
+
+
+//
+// end AS_DCP_AES.cpp
+//
diff --git a/asdcplib/src/AS_DCP_JP2K.cpp b/asdcplib/src/AS_DCP_JP2K.cpp
new file mode 100755
index 0000000..05166d6
--- /dev/null
+++ b/asdcplib/src/AS_DCP_JP2K.cpp
@@ -0,0 +1,1384 @@
+/* -*- c-basic-offset: 2; -*- */
+
+/*
+Copyright (c) 2004-2012, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file AS_DCP_JP2k.cpp
+ \version $Id: AS_DCP_JP2K.cpp,v 1.54 2012/02/07 18:54:24 jhurst Exp $
+ \brief AS-DCP library, JPEG 2000 essence reader and writer implementation
+*/
+
+#include "AS_DCP_internal.h"
+#include <iostream>
+#include <iomanip>
+
+using std::cout;
+using namespace ASDCP::JP2K;
+using Kumu::GenRandomValue;
+
+//------------------------------------------------------------------------------------------
+
+static std::string JP2K_PACKAGE_LABEL = "File Package: SMPTE 429-4 frame wrapping of JPEG 2000 codestreams";
+static std::string JP2K_S_PACKAGE_LABEL = "File Package: SMPTE 429-10 frame wrapping of stereoscopic JPEG 2000 codestreams";
+static std::string PICT_DEF_LABEL = "Picture Track";
+
+int s_exp_lookup[16] = { 0, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024,2048, 4096, 8192, 16384, 32768 };
+
+//
+std::ostream&
+ASDCP::JP2K::operator << (std::ostream& strm, const PictureDescriptor& PDesc)
+{
+ strm << " AspectRatio: " << PDesc.AspectRatio.Numerator << "/" << PDesc.AspectRatio.Denominator << std::endl;
+ strm << " EditRate: " << PDesc.EditRate.Numerator << "/" << PDesc.EditRate.Denominator << std::endl;
+ strm << " SampleRate: " << PDesc.SampleRate.Numerator << "/" << PDesc.SampleRate.Denominator << std::endl;
+ strm << " StoredWidth: " << (unsigned) PDesc.StoredWidth << std::endl;
+ strm << " StoredHeight: " << (unsigned) PDesc.StoredHeight << std::endl;
+ strm << " Rsize: " << (unsigned) PDesc.Rsize << std::endl;
+ strm << " Xsize: " << (unsigned) PDesc.Xsize << std::endl;
+ strm << " Ysize: " << (unsigned) PDesc.Ysize << std::endl;
+ strm << " XOsize: " << (unsigned) PDesc.XOsize << std::endl;
+ strm << " YOsize: " << (unsigned) PDesc.YOsize << std::endl;
+ strm << " XTsize: " << (unsigned) PDesc.XTsize << std::endl;
+ strm << " YTsize: " << (unsigned) PDesc.YTsize << std::endl;
+ strm << " XTOsize: " << (unsigned) PDesc.XTOsize << std::endl;
+ strm << " YTOsize: " << (unsigned) PDesc.YTOsize << std::endl;
+ strm << " ContainerDuration: " << (unsigned) PDesc.ContainerDuration << std::endl;
+
+ strm << "-- JPEG 2000 Metadata --" << std::endl;
+ strm << " ImageComponents:" << std::endl;
+ strm << " bits h-sep v-sep" << std::endl;
+
+ ui32_t i;
+ for ( i = 0; i < PDesc.Csize; i++ )
+ {
+ strm << " " << std::setw(4) << PDesc.ImageComponents[i].Ssize + 1 /* See ISO 15444-1, Table A11, for the origin of '+1' */
+ << " " << std::setw(5) << PDesc.ImageComponents[i].XRsize
+ << " " << std::setw(5) << PDesc.ImageComponents[i].YRsize
+ << std::endl;
+ }
+
+ strm << " Scod: " << (short) PDesc.CodingStyleDefault.Scod << std::endl;
+ strm << " ProgressionOrder: " << (short) PDesc.CodingStyleDefault.SGcod.ProgressionOrder << std::endl;
+ strm << " NumberOfLayers: " << (short) KM_i16_BE(Kumu::cp2i<ui16_t>(PDesc.CodingStyleDefault.SGcod.NumberOfLayers)) << std::endl;
+ strm << " MultiCompTransform: " << (short) PDesc.CodingStyleDefault.SGcod.MultiCompTransform << std::endl;
+ strm << "DecompositionLevels: " << (short) PDesc.CodingStyleDefault.SPcod.DecompositionLevels << std::endl;
+ strm << " CodeblockWidth: " << (short) PDesc.CodingStyleDefault.SPcod.CodeblockWidth << std::endl;
+ strm << " CodeblockHeight: " << (short) PDesc.CodingStyleDefault.SPcod.CodeblockHeight << std::endl;
+ strm << " CodeblockStyle: " << (short) PDesc.CodingStyleDefault.SPcod.CodeblockStyle << std::endl;
+ strm << " Transformation: " << (short) PDesc.CodingStyleDefault.SPcod.Transformation << std::endl;
+
+
+ ui32_t precinct_set_size = 0;
+
+ for ( i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; i++ )
+ precinct_set_size++;
+
+ strm << " Precincts: " << (short) precinct_set_size << std::endl;
+ strm << "precinct dimensions:" << std::endl;
+
+ for ( i = 0; i < precinct_set_size; i++ )
+ strm << " " << i + 1 << ": " << s_exp_lookup[PDesc.CodingStyleDefault.SPcod.PrecinctSize[i]&0x0f] << " x "
+ << s_exp_lookup[(PDesc.CodingStyleDefault.SPcod.PrecinctSize[i]>>4)&0x0f] << std::endl;
+
+ strm << " Sqcd: " << (short) PDesc.QuantizationDefault.Sqcd << std::endl;
+
+ char tmp_buf[MaxDefaults*2];
+ strm << " SPqcd: " << Kumu::bin2hex(PDesc.QuantizationDefault.SPqcd, PDesc.QuantizationDefault.SPqcdLength, tmp_buf, MaxDefaults*2)
+ << std::endl;
+
+ return strm;
+}
+
+//
+void
+ASDCP::JP2K::PictureDescriptorDump(const PictureDescriptor& PDesc, FILE* stream)
+{
+ if ( stream == 0 )
+ stream = stderr;
+
+ fprintf(stream, "\
+ AspectRatio: %d/%d\n\
+ EditRate: %d/%d\n\
+ SampleRate: %d/%d\n\
+ StoredWidth: %u\n\
+ StoredHeight: %u\n\
+ Rsize: %u\n\
+ Xsize: %u\n\
+ Ysize: %u\n\
+ XOsize: %u\n\
+ YOsize: %u\n\
+ XTsize: %u\n\
+ YTsize: %u\n\
+ XTOsize: %u\n\
+ YTOsize: %u\n\
+ ContainerDuration: %u\n",
+ PDesc.AspectRatio.Numerator, PDesc.AspectRatio.Denominator,
+ PDesc.EditRate.Numerator, PDesc.EditRate.Denominator,
+ PDesc.SampleRate.Numerator, PDesc.SampleRate.Denominator,
+ PDesc.StoredWidth,
+ PDesc.StoredHeight,
+ PDesc.Rsize,
+ PDesc.Xsize,
+ PDesc.Ysize,
+ PDesc.XOsize,
+ PDesc.YOsize,
+ PDesc.XTsize,
+ PDesc.YTsize,
+ PDesc.XTOsize,
+ PDesc.YTOsize,
+ PDesc.ContainerDuration
+ );
+
+ fprintf(stream, "-- JPEG 2000 Metadata --\n");
+ fprintf(stream, " ImageComponents:\n");
+ fprintf(stream, " bits h-sep v-sep\n");
+
+ ui32_t i;
+ for ( i = 0; i < PDesc.Csize; i++ )
+ {
+ fprintf(stream, " %4d %5d %5d\n",
+ PDesc.ImageComponents[i].Ssize + 1, // See ISO 15444-1, Table A11, for the origin of '+1'
+ PDesc.ImageComponents[i].XRsize,
+ PDesc.ImageComponents[i].YRsize
+ );
+ }
+
+ fprintf(stream, " Scod: %hd\n", PDesc.CodingStyleDefault.Scod);
+ fprintf(stream, " ProgressionOrder: %hd\n", PDesc.CodingStyleDefault.SGcod.ProgressionOrder);
+ fprintf(stream, " NumberOfLayers: %hd\n",
+ KM_i16_BE(Kumu::cp2i<ui16_t>(PDesc.CodingStyleDefault.SGcod.NumberOfLayers)));
+
+ fprintf(stream, " MultiCompTransform: %hd\n", PDesc.CodingStyleDefault.SGcod.MultiCompTransform);
+ fprintf(stream, "DecompositionLevels: %hd\n", PDesc.CodingStyleDefault.SPcod.DecompositionLevels);
+ fprintf(stream, " CodeblockWidth: %hd\n", PDesc.CodingStyleDefault.SPcod.CodeblockWidth);
+ fprintf(stream, " CodeblockHeight: %hd\n", PDesc.CodingStyleDefault.SPcod.CodeblockHeight);
+ fprintf(stream, " CodeblockStyle: %hd\n", PDesc.CodingStyleDefault.SPcod.CodeblockStyle);
+ fprintf(stream, " Transformation: %hd\n", PDesc.CodingStyleDefault.SPcod.Transformation);
+
+
+ ui32_t precinct_set_size = 0;
+
+ for ( i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; i++ )
+ precinct_set_size++;
+
+ fprintf(stream, " Precincts: %hd\n", precinct_set_size);
+ fprintf(stream, "precinct dimensions:\n");
+
+ for ( i = 0; i < precinct_set_size; i++ )
+ fprintf(stream, " %d: %d x %d\n", i + 1,
+ s_exp_lookup[PDesc.CodingStyleDefault.SPcod.PrecinctSize[i]&0x0f],
+ s_exp_lookup[(PDesc.CodingStyleDefault.SPcod.PrecinctSize[i]>>4)&0x0f]
+ );
+
+ fprintf(stream, " Sqcd: %hd\n", PDesc.QuantizationDefault.Sqcd);
+
+ char tmp_buf[MaxDefaults*2];
+ fprintf(stream, " SPqcd: %s\n",
+ Kumu::bin2hex(PDesc.QuantizationDefault.SPqcd, PDesc.QuantizationDefault.SPqcdLength,
+ tmp_buf, MaxDefaults*2)
+ );
+}
+
+
+//------------------------------------------------------------------------------------------
+//
+// hidden, internal implementation of JPEG 2000 reader
+
+
+class lh__Reader : public ASDCP::h__Reader
+{
+ RGBAEssenceDescriptor* m_EssenceDescriptor;
+ JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
+ ASDCP::Rational m_EditRate;
+ ASDCP::Rational m_SampleRate;
+ EssenceType_t m_Format;
+
+ ASDCP_NO_COPY_CONSTRUCT(lh__Reader);
+
+public:
+ PictureDescriptor m_PDesc; // codestream parameter list
+
+ lh__Reader(const Dictionary& d) :
+ ASDCP::h__Reader(d), m_EssenceDescriptor(0), m_EssenceSubDescriptor(0), m_Format(ESS_UNKNOWN) {}
+ Result_t OpenRead(const char*, EssenceType_t);
+ Result_t ReadFrame(ui32_t, JP2K::FrameBuffer&, AESDecContext*, HMACContext*);
+ Result_t MD_to_JP2K_PDesc(JP2K::PictureDescriptor& PDesc);
+};
+
+//
+ASDCP::Result_t
+lh__Reader::MD_to_JP2K_PDesc(JP2K::PictureDescriptor& PDesc)
+{
+ memset(&PDesc, 0, sizeof(PDesc));
+ MXF::RGBAEssenceDescriptor* PDescObj = (MXF::RGBAEssenceDescriptor*)m_EssenceDescriptor;
+
+ PDesc.EditRate = m_EditRate;
+ PDesc.SampleRate = m_SampleRate;
+ assert(PDescObj->ContainerDuration <= 0xFFFFFFFFL);
+ PDesc.ContainerDuration = (ui32_t) PDescObj->ContainerDuration;
+ PDesc.StoredWidth = PDescObj->StoredWidth;
+ PDesc.StoredHeight = PDescObj->StoredHeight;
+ PDesc.AspectRatio = PDescObj->AspectRatio;
+
+ if ( m_EssenceSubDescriptor != 0 )
+ {
+ PDesc.Rsize = m_EssenceSubDescriptor->Rsize;
+ PDesc.Xsize = m_EssenceSubDescriptor->Xsize;
+ PDesc.Ysize = m_EssenceSubDescriptor->Ysize;
+ PDesc.XOsize = m_EssenceSubDescriptor->XOsize;
+ PDesc.YOsize = m_EssenceSubDescriptor->YOsize;
+ PDesc.XTsize = m_EssenceSubDescriptor->XTsize;
+ PDesc.YTsize = m_EssenceSubDescriptor->YTsize;
+ PDesc.XTOsize = m_EssenceSubDescriptor->XTOsize;
+ PDesc.YTOsize = m_EssenceSubDescriptor->YTOsize;
+ PDesc.Csize = m_EssenceSubDescriptor->Csize;
+
+ // PictureComponentSizing
+ 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);
+
+ else
+ DefaultLogSink().Error("Unexpected PictureComponentSizing size: %u, should be 17\n", tmp_size);
+
+ // CodingStyleDefault
+ memset(&PDesc.CodingStyleDefault, 0, sizeof(CodingStyleDefault_t));
+ memcpy(&PDesc.CodingStyleDefault,
+ m_EssenceSubDescriptor->CodingStyleDefault.RoData(),
+ m_EssenceSubDescriptor->CodingStyleDefault.Length());
+
+ // QuantizationDefault
+ memset(&PDesc.QuantizationDefault, 0, sizeof(QuantizationDefault_t));
+ memcpy(&PDesc.QuantizationDefault,
+ m_EssenceSubDescriptor->QuantizationDefault.RoData(),
+ m_EssenceSubDescriptor->QuantizationDefault.Length());
+
+ PDesc.QuantizationDefault.SPqcdLength = m_EssenceSubDescriptor->QuantizationDefault.Length() - 1;
+ }
+
+ return RESULT_OK;
+}
+
+//
+//
+ASDCP::Result_t
+lh__Reader::OpenRead(const char* filename, EssenceType_t type)
+{
+ Result_t result = OpenMXFRead(filename);
+
+ if( ASDCP_SUCCESS(result) )
+ {
+ InterchangeObject* tmp_iobj = 0;
+ m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(RGBAEssenceDescriptor), &tmp_iobj);
+ m_EssenceDescriptor = static_cast<RGBAEssenceDescriptor*>(tmp_iobj);
+
+ m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(JPEG2000PictureSubDescriptor), &tmp_iobj);
+ m_EssenceSubDescriptor = static_cast<JPEG2000PictureSubDescriptor*>(tmp_iobj);
+
+ std::list<InterchangeObject*> ObjectList;
+ m_HeaderPart.GetMDObjectsByType(OBJ_TYPE_ARGS(Track), ObjectList);
+
+ if ( ObjectList.empty() )
+ {
+ DefaultLogSink().Error("MXF Metadata contains no Track Sets.\n");
+ return RESULT_FORMAT;
+ }
+
+ m_EditRate = ((Track*)ObjectList.front())->EditRate;
+ m_SampleRate = m_EssenceDescriptor->SampleRate;
+
+ if ( type == ASDCP::ESS_JPEG_2000 )
+ {
+ if ( m_EditRate != m_SampleRate )
+ {
+ DefaultLogSink().Warn("EditRate and SampleRate do not match (%.03f, %.03f).\n",
+ m_EditRate.Quotient(), m_SampleRate.Quotient());
+
+ if ( (m_EditRate == EditRate_24 && m_SampleRate == EditRate_48) ||
+ (m_EditRate == EditRate_25 && m_SampleRate == EditRate_50) ||
+ (m_EditRate == EditRate_30 && m_SampleRate == EditRate_60) ||
+ (m_EditRate == EditRate_48 && m_SampleRate == EditRate_96) ||
+ (m_EditRate == EditRate_50 && m_SampleRate == EditRate_100) ||
+ (m_EditRate == EditRate_60 && m_SampleRate == EditRate_120) )
+ {
+ DefaultLogSink().Debug("File may contain JPEG Interop stereoscopic images.\n");
+ return RESULT_SFORMAT;
+ }
+
+ return RESULT_FORMAT;
+ }
+ }
+ else if ( type == ASDCP::ESS_JPEG_2000_S )
+ {
+ if ( m_EditRate == EditRate_24 )
+ {
+ if ( m_SampleRate != EditRate_48 )
+ {
+ DefaultLogSink().Error("EditRate and SampleRate not correct for 24/48 stereoscopic essence.\n");
+ return RESULT_FORMAT;
+ }
+ }
+ else if ( m_EditRate == EditRate_25 )
+ {
+ if ( m_SampleRate != EditRate_50 )
+ {
+ DefaultLogSink().Error("EditRate and SampleRate not correct for 25/50 stereoscopic essence.\n");
+ return RESULT_FORMAT;
+ }
+ }
+ else if ( m_EditRate == EditRate_30 )
+ {
+ if ( m_SampleRate != EditRate_60 )
+ {
+ DefaultLogSink().Error("EditRate and SampleRate not correct for 30/60 stereoscopic essence.\n");
+ return RESULT_FORMAT;
+ }
+ }
+ else if ( m_EditRate == EditRate_48 )
+ {
+ if ( m_SampleRate != EditRate_96 )
+ {
+ DefaultLogSink().Error("EditRate and SampleRate not correct for 48/96 stereoscopic essence.\n");
+ return RESULT_FORMAT;
+ }
+ }
+ else if ( m_EditRate == EditRate_50 )
+ {
+ if ( m_SampleRate != EditRate_100 )
+ {
+ DefaultLogSink().Error("EditRate and SampleRate not correct for 50/100 stereoscopic essence.\n");
+ return RESULT_FORMAT;
+ }
+ }
+ else if ( m_EditRate == EditRate_60 )
+ {
+ if ( m_SampleRate != EditRate_120 )
+ {
+ DefaultLogSink().Error("EditRate and SampleRate not correct for 60/120 stereoscopic essence.\n");
+ return RESULT_FORMAT;
+ }
+ }
+ else
+ {
+ DefaultLogSink().Error("EditRate not correct for stereoscopic essence: %d/%d.\n",
+ m_EditRate.Numerator, m_EditRate.Denominator);
+ return RESULT_FORMAT;
+ }
+ }
+ else
+ {
+ DefaultLogSink().Error("'type' argument unexpected: %x\n", type);
+ return RESULT_STATE;
+ }
+
+ result = MD_to_JP2K_PDesc(m_PDesc);
+ }
+
+ if( ASDCP_SUCCESS(result) )
+ result = InitMXFIndex();
+
+ if( ASDCP_SUCCESS(result) )
+ result = InitInfo();
+
+ return result;
+}
+
+//
+//
+ASDCP::Result_t
+lh__Reader::ReadFrame(ui32_t FrameNum, JP2K::FrameBuffer& FrameBuf,
+ AESDecContext* Ctx, HMACContext* HMAC)
+{
+ if ( ! m_File.IsOpen() )
+ return RESULT_INIT;
+
+ assert(m_Dict);
+ return ReadEKLVFrame(FrameNum, FrameBuf, m_Dict->ul(MDD_JPEG2000Essence), Ctx, HMAC);
+}
+
+
+//
+class ASDCP::JP2K::MXFReader::h__Reader : public lh__Reader
+{
+ ASDCP_NO_COPY_CONSTRUCT(h__Reader);
+ h__Reader();
+
+public:
+ h__Reader(const Dictionary& d) : lh__Reader(d) {}
+};
+
+
+
+//------------------------------------------------------------------------------------------
+
+
+//
+void
+ASDCP::JP2K::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
+{
+ if ( stream == 0 )
+ stream = stderr;
+
+ fprintf(stream, "Frame: %06u, %7u bytes", m_FrameNumber, m_Size);
+
+ fputc('\n', stream);
+
+ if ( dump_len > 0 )
+ Kumu::hexdump(m_Data, dump_len, stream);
+}
+
+
+//------------------------------------------------------------------------------------------
+
+ASDCP::JP2K::MXFReader::MXFReader()
+{
+ m_Reader = new h__Reader(DefaultCompositeDict());
+}
+
+
+ASDCP::JP2K::MXFReader::~MXFReader()
+{
+}
+
+// Warning: direct manipulation of MXF structures can interfere
+// with the normal operation of the wrapper. Caveat emptor!
+//
+ASDCP::MXF::OPAtomHeader&
+ASDCP::JP2K::MXFReader::OPAtomHeader()
+{
+ if ( m_Reader.empty() )
+ {
+ assert(g_OPAtomHeader);
+ return *g_OPAtomHeader;
+ }
+
+ return m_Reader->m_HeaderPart;
+}
+
+// Warning: direct manipulation of MXF structures can interfere
+// with the normal operation of the wrapper. Caveat emptor!
+//
+ASDCP::MXF::OPAtomIndexFooter&
+ASDCP::JP2K::MXFReader::OPAtomIndexFooter()
+{
+ if ( m_Reader.empty() )
+ {
+ assert(g_OPAtomIndexFooter);
+ return *g_OPAtomIndexFooter;
+ }
+
+ return m_Reader->m_FooterPart;
+}
+
+// Open the file for reading. The file must exist. Returns error if the
+// operation cannot be completed.
+ASDCP::Result_t
+ASDCP::JP2K::MXFReader::OpenRead(const char* filename) const
+{
+ return m_Reader->OpenRead(filename, ASDCP::ESS_JPEG_2000);
+}
+
+//
+ASDCP::Result_t
+ASDCP::JP2K::MXFReader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
+ AESDecContext* Ctx, HMACContext* HMAC) const
+{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC);
+
+ return RESULT_INIT;
+}
+
+
+// Fill the struct with the values from the file's header.
+// Returns RESULT_INIT if the file is not open.
+ASDCP::Result_t
+ASDCP::JP2K::MXFReader::FillPictureDescriptor(PictureDescriptor& PDesc) const
+{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ {
+ PDesc = m_Reader->m_PDesc;
+ return RESULT_OK;
+ }
+
+ return RESULT_INIT;
+}
+
+
+// Fill the struct with the values from the file's header.
+// Returns RESULT_INIT if the file is not open.
+ASDCP::Result_t
+ASDCP::JP2K::MXFReader::FillWriterInfo(WriterInfo& Info) const
+{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ {
+ Info = m_Reader->m_Info;
+ return RESULT_OK;
+ }
+
+ return RESULT_INIT;
+}
+
+//
+void
+ASDCP::JP2K::MXFReader::DumpHeaderMetadata(FILE* stream) const
+{
+ if ( m_Reader->m_File.IsOpen() )
+ m_Reader->m_HeaderPart.Dump(stream);
+}
+
+
+//
+void
+ASDCP::JP2K::MXFReader::DumpIndex(FILE* stream) const
+{
+ if ( m_Reader->m_File.IsOpen() )
+ m_Reader->m_FooterPart.Dump(stream);
+}
+
+//
+ASDCP::Result_t
+ASDCP::JP2K::MXFReader::Close() const
+{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ {
+ m_Reader->Close();
+ return RESULT_OK;
+ }
+
+ return RESULT_INIT;
+}
+
+
+//------------------------------------------------------------------------------------------
+
+
+class ASDCP::JP2K::MXFSReader::h__SReader : public lh__Reader
+{
+ ui32_t m_StereoFrameReady;
+
+public:
+ h__SReader(const Dictionary& d) : lh__Reader(d), m_StereoFrameReady(0xffffffff) {}
+
+ //
+ Result_t ReadFrame(ui32_t FrameNum, StereoscopicPhase_t phase, FrameBuffer& FrameBuf,
+ AESDecContext* Ctx, HMACContext* HMAC)
+ {
+ // 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) )
+ {
+ ui32_t SequenceNum = FrameNum * 2;
+ SequenceNum += ( phase == SP_RIGHT ) ? 2 : 1;
+ assert(m_Dict);
+ result = ReadEKLVPacket(FrameNum, SequenceNum, FrameBuf, m_Dict->ul(MDD_JPEG2000Essence), Ctx, HMAC);
+ }
+
+ return result;
+ }
+};
+
+
+
+ASDCP::JP2K::MXFSReader::MXFSReader()
+{
+ m_Reader = new h__SReader(DefaultCompositeDict());
+}
+
+
+ASDCP::JP2K::MXFSReader::~MXFSReader()
+{
+}
+
+// Warning: direct manipulation of MXF structures can interfere
+// with the normal operation of the wrapper. Caveat emptor!
+//
+ASDCP::MXF::OPAtomHeader&
+ASDCP::JP2K::MXFSReader::OPAtomHeader()
+{
+ if ( m_Reader.empty() )
+ {
+ assert(g_OPAtomHeader);
+ return *g_OPAtomHeader;
+ }
+
+ return m_Reader->m_HeaderPart;
+}
+
+// Warning: direct manipulation of MXF structures can interfere
+// with the normal operation of the wrapper. Caveat emptor!
+//
+ASDCP::MXF::OPAtomIndexFooter&
+ASDCP::JP2K::MXFSReader::OPAtomIndexFooter()
+{
+ if ( m_Reader.empty() )
+ {
+ assert(g_OPAtomIndexFooter);
+ return *g_OPAtomIndexFooter;
+ }
+
+ return m_Reader->m_FooterPart;
+}
+
+// Open the file for reading. The file must exist. Returns error if the
+// operation cannot be completed.
+ASDCP::Result_t
+ASDCP::JP2K::MXFSReader::OpenRead(const char* filename) const
+{
+ return m_Reader->OpenRead(filename, ASDCP::ESS_JPEG_2000_S);
+}
+
+//
+ASDCP::Result_t
+ASDCP::JP2K::MXFSReader::ReadFrame(ui32_t FrameNum, SFrameBuffer& FrameBuf, AESDecContext* Ctx, HMACContext* HMAC) const
+{
+ Result_t result = RESULT_INIT;
+
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ {
+ result = m_Reader->ReadFrame(FrameNum, SP_LEFT, FrameBuf.Left, Ctx, HMAC);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = m_Reader->ReadFrame(FrameNum, SP_RIGHT, FrameBuf.Right, Ctx, HMAC);
+ }
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::JP2K::MXFSReader::ReadFrame(ui32_t FrameNum, StereoscopicPhase_t phase, FrameBuffer& FrameBuf,
+ AESDecContext* Ctx, HMACContext* HMAC) const
+{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ return m_Reader->ReadFrame(FrameNum, phase, FrameBuf, Ctx, HMAC);
+
+ return RESULT_INIT;
+}
+
+// Fill the struct with the values from the file's header.
+// Returns RESULT_INIT if the file is not open.
+ASDCP::Result_t
+ASDCP::JP2K::MXFSReader::FillPictureDescriptor(PictureDescriptor& PDesc) const
+{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ {
+ PDesc = m_Reader->m_PDesc;
+ return RESULT_OK;
+ }
+
+ return RESULT_INIT;
+}
+
+
+// Fill the struct with the values from the file's header.
+// Returns RESULT_INIT if the file is not open.
+ASDCP::Result_t
+ASDCP::JP2K::MXFSReader::FillWriterInfo(WriterInfo& Info) const
+{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ {
+ Info = m_Reader->m_Info;
+ return RESULT_OK;
+ }
+
+ return RESULT_INIT;
+}
+
+//
+void
+ASDCP::JP2K::MXFSReader::DumpHeaderMetadata(FILE* stream) const
+{
+ if ( m_Reader->m_File.IsOpen() )
+ m_Reader->m_HeaderPart.Dump(stream);
+}
+
+
+//
+void
+ASDCP::JP2K::MXFSReader::DumpIndex(FILE* stream) const
+{
+ if ( m_Reader->m_File.IsOpen() )
+ m_Reader->m_FooterPart.Dump(stream);
+}
+
+//
+ASDCP::Result_t
+ASDCP::JP2K::MXFSReader::Close() const
+{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ {
+ m_Reader->Close();
+ return RESULT_OK;
+ }
+
+ return RESULT_INIT;
+}
+
+
+//------------------------------------------------------------------------------------------
+
+
+//
+class lh__Writer : public ASDCP::h__Writer
+{
+ ASDCP_NO_COPY_CONSTRUCT(lh__Writer);
+ lh__Writer();
+
+ JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
+
+public:
+ PictureDescriptor m_PDesc;
+ byte_t m_EssenceUL[SMPTE_UL_LENGTH];
+
+ lh__Writer(const Dictionary& d) : ASDCP::h__Writer(d), m_EssenceSubDescriptor(0) {
+ memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
+ }
+
+ ~lh__Writer(){}
+
+ Result_t OpenWrite(const char*, EssenceType_t type, ui32_t HeaderSize, bool);
+ Result_t SetSourceStream(const PictureDescriptor&, const std::string& label,
+ ASDCP::Rational LocalEditRate = ASDCP::Rational(0,0));
+ Result_t WriteFrame(const JP2K::FrameBuffer&, bool add_index, AESEncContext*, HMACContext*, std::string* hash = 0);
+ Result_t FakeWriteFrame(int size, bool add_index);
+ Result_t Finalize();
+ Result_t JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDesc);
+};
+
+const int VideoLineMapSize = 16; // See SMPTE 377M D.2.1
+const int PixelLayoutSize = 8*2; // See SMPTE 377M D.2.3
+static const byte_t s_PixelLayoutXYZ[PixelLayoutSize] = { 0xd8, 0x0c, 0xd9, 0x0c, 0xda, 0x0c, 0x00 };
+
+//
+ASDCP::Result_t
+lh__Writer::JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDesc)
+{
+ assert(m_EssenceDescriptor);
+ assert(m_EssenceSubDescriptor);
+ MXF::RGBAEssenceDescriptor* PDescObj = (MXF::RGBAEssenceDescriptor*)m_EssenceDescriptor;
+
+ PDescObj->ContainerDuration = PDesc.ContainerDuration;
+ PDescObj->SampleRate = PDesc.EditRate;
+ PDescObj->FrameLayout = 0;
+ PDescObj->StoredWidth = PDesc.StoredWidth;
+ PDescObj->StoredHeight = PDesc.StoredHeight;
+ PDescObj->AspectRatio = PDesc.AspectRatio;
+
+ // if ( m_Info.LabelSetType == LS_MXF_SMPTE )
+ // {
+ // PictureEssenceCoding UL =
+ // Video Line Map ui32_t[VideoLineMapSize] = { 2, 4, 0, 0 }
+ // CaptureGamma UL =
+ // ComponentMaxRef ui32_t = 4095
+ // ComponentMinRef ui32_t = 0
+ // PixelLayout byte_t[PixelLayoutSize] = s_PixelLayoutXYZ
+ // }
+
+ assert(m_Dict);
+ if ( PDesc.StoredWidth < 2049 )
+ {
+ PDescObj->PictureEssenceCoding.Set(m_Dict->ul(MDD_JP2KEssenceCompression_2K));
+ m_EssenceSubDescriptor->Rsize = 3;
+ }
+ else
+ {
+ PDescObj->PictureEssenceCoding.Set(m_Dict->ul(MDD_JP2KEssenceCompression_4K));
+ m_EssenceSubDescriptor->Rsize = 4;
+ }
+
+ m_EssenceSubDescriptor->Xsize = PDesc.Xsize;
+ m_EssenceSubDescriptor->Ysize = PDesc.Ysize;
+ m_EssenceSubDescriptor->XOsize = PDesc.XOsize;
+ m_EssenceSubDescriptor->YOsize = PDesc.YOsize;
+ m_EssenceSubDescriptor->XTsize = PDesc.XTsize;
+ m_EssenceSubDescriptor->YTsize = PDesc.YTsize;
+ m_EssenceSubDescriptor->XTOsize = PDesc.XTOsize;
+ m_EssenceSubDescriptor->YTOsize = PDesc.YTOsize;
+ m_EssenceSubDescriptor->Csize = PDesc.Csize;
+
+ const ui32_t tmp_buffer_len = 1024;
+ byte_t tmp_buffer[tmp_buffer_len];
+
+ ui32_t* tmp_buffer_ui32 = (ui32_t*) tmp_buffer;
+ *tmp_buffer_ui32 = KM_i32_BE(MaxComponents); // three components
+
+ *(ui32_t*)(tmp_buffer+4) = KM_i32_BE(sizeof(ASDCP::JP2K::ImageComponent_t));
+ memcpy(tmp_buffer + 8, &PDesc.ImageComponents, sizeof(ASDCP::JP2K::ImageComponent_t) * MaxComponents);
+
+ const ui32_t pcomp_size = (sizeof(int) * 2) + (sizeof(ASDCP::JP2K::ImageComponent_t) * MaxComponents);
+ memcpy(m_EssenceSubDescriptor->PictureComponentSizing.Data(), tmp_buffer, pcomp_size);
+ m_EssenceSubDescriptor->PictureComponentSizing.Length(pcomp_size);
+
+ ui32_t precinct_set_size = 0, i;
+ for ( i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; i++ )
+ precinct_set_size++;
+
+ ui32_t csd_size = sizeof(CodingStyleDefault_t) - MaxPrecincts + precinct_set_size;
+ memcpy(m_EssenceSubDescriptor->CodingStyleDefault.Data(), &PDesc.CodingStyleDefault, csd_size);
+ m_EssenceSubDescriptor->CodingStyleDefault.Length(csd_size);
+
+ ui32_t qdflt_size = PDesc.QuantizationDefault.SPqcdLength + 1;
+ memcpy(m_EssenceSubDescriptor->QuantizationDefault.Data(), &PDesc.QuantizationDefault, qdflt_size);
+ m_EssenceSubDescriptor->QuantizationDefault.Length(qdflt_size);
+
+ return RESULT_OK;
+}
+
+
+// Open the file for writing. The file must not exist unless overwrite is true. Returns error if
+// the operation cannot be completed.
+ASDCP::Result_t
+lh__Writer::OpenWrite(const char* filename, EssenceType_t type, ui32_t HeaderSize, bool overwrite)
+{
+ if ( ! m_State.Test_BEGIN() )
+ return RESULT_STATE;
+
+ Result_t result = RESULT_OK;
+ if (overwrite) {
+ result = m_File.OpenModify(filename);
+ m_File.Seek(0);
+ } else {
+ result = m_File.OpenWrite(filename);
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ m_HeaderSize = HeaderSize;
+ RGBAEssenceDescriptor* tmp_rgba = new RGBAEssenceDescriptor(m_Dict);
+ tmp_rgba->ComponentMaxRef = 4095;
+ tmp_rgba->ComponentMinRef = 0;
+
+ m_EssenceDescriptor = tmp_rgba;
+ m_EssenceSubDescriptor = new JPEG2000PictureSubDescriptor(m_Dict);
+ m_EssenceSubDescriptorList.push_back((InterchangeObject*)m_EssenceSubDescriptor);
+
+ GenRandomValue(m_EssenceSubDescriptor->InstanceUID);
+ m_EssenceDescriptor->SubDescriptors.push_back(m_EssenceSubDescriptor->InstanceUID);
+
+ if ( type == ASDCP::ESS_JPEG_2000_S && m_Info.LabelSetType == LS_MXF_SMPTE )
+ {
+ InterchangeObject* StereoSubDesc = new StereoscopicPictureSubDescriptor(m_Dict);
+ m_EssenceSubDescriptorList.push_back(StereoSubDesc);
+ GenRandomValue(StereoSubDesc->InstanceUID);
+ m_EssenceDescriptor->SubDescriptors.push_back(StereoSubDesc->InstanceUID);
+ }
+
+ result = m_State.Goto_INIT();
+ }
+
+ return result;
+}
+
+// Automatically sets the MXF file's metadata from the first jpeg codestream stream.
+ASDCP::Result_t
+lh__Writer::SetSourceStream(const PictureDescriptor& PDesc, const std::string& label, ASDCP::Rational LocalEditRate)
+{
+ assert(m_Dict);
+ if ( ! m_State.Test_INIT() )
+ return RESULT_STATE;
+
+ if ( LocalEditRate == ASDCP::Rational(0,0) )
+ LocalEditRate = PDesc.EditRate;
+
+ m_PDesc = PDesc;
+ Result_t result = JP2K_PDesc_to_MD(m_PDesc);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ memcpy(m_EssenceUL, m_Dict->ul(MDD_JPEG2000Essence), SMPTE_UL_LENGTH);
+ m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
+ result = m_State.Goto_READY();
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ ui32_t TCFrameRate = ( m_PDesc.EditRate == EditRate_23_98 ) ? 24 : m_PDesc.EditRate.Numerator;
+
+ result = WriteMXFHeader(label, UL(m_Dict->ul(MDD_JPEG_2000Wrapping)),
+ PICT_DEF_LABEL, UL(m_EssenceUL), UL(m_Dict->ul(MDD_PictureDataDef)),
+ LocalEditRate, TCFrameRate);
+ }
+
+ return result;
+}
+
+// Writes a frame of essence to the MXF file. If the optional AESEncContext
+// argument is present, the essence is encrypted prior to writing.
+// Fails if the file is not open, is finalized, or an operating system
+// error occurs.
+//
+ASDCP::Result_t
+lh__Writer::WriteFrame(const JP2K::FrameBuffer& FrameBuf, bool add_index,
+ AESEncContext* Ctx, HMACContext* HMAC, std::string* hash)
+{
+ Result_t result = RESULT_OK;
+
+ if ( m_State.Test_READY() )
+ result = m_State.Goto_RUNNING(); // first time through
+
+ ui64_t StreamOffset = m_StreamOffset;
+
+ if ( ASDCP_SUCCESS(result) )
+ result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC, hash);
+
+ if ( ASDCP_SUCCESS(result) && add_index )
+ {
+ IndexTableSegment::IndexEntry Entry;
+ Entry.StreamOffset = StreamOffset;
+ m_FooterPart.PushIndexEntry(Entry);
+ }
+
+ m_FramesWritten++;
+ return result;
+}
+
+Result_t
+lh__Writer::FakeWriteFrame(int size, bool add_index)
+{
+ Result_t result = RESULT_OK;
+
+ if ( m_State.Test_READY() )
+ result = m_State.Goto_RUNNING();
+
+ ui64_t StreamOffset = m_StreamOffset;
+
+ if ( ASDCP_SUCCESS(result) )
+ result = FakeWriteEKLVPacket(size);
+
+ if ( ASDCP_SUCCESS(result) && add_index )
+ {
+ IndexTableSegment::IndexEntry Entry;
+ Entry.StreamOffset = StreamOffset;
+ m_FooterPart.PushIndexEntry(Entry);
+ }
+
+ m_FramesWritten++;
+ return result;
+}
+
+
+// Closes the MXF file, writing the index and other closing information.
+//
+ASDCP::Result_t
+lh__Writer::Finalize()
+{
+ if ( ! m_State.Test_RUNNING() )
+ return RESULT_STATE;
+
+ m_State.Goto_FINAL();
+
+ return WriteMXFFooter();
+}
+
+
+//
+class ASDCP::JP2K::MXFWriter::h__Writer : public lh__Writer
+{
+ ASDCP_NO_COPY_CONSTRUCT(h__Writer);
+ h__Writer();
+
+public:
+ h__Writer(const Dictionary& d) : lh__Writer(d) {}
+};
+
+
+//------------------------------------------------------------------------------------------
+
+
+
+ASDCP::JP2K::MXFWriter::MXFWriter()
+{
+}
+
+ASDCP::JP2K::MXFWriter::~MXFWriter()
+{
+}
+
+// Warning: direct manipulation of MXF structures can interfere
+// with the normal operation of the wrapper. Caveat emptor!
+//
+ASDCP::MXF::OPAtomHeader&
+ASDCP::JP2K::MXFWriter::OPAtomHeader()
+{
+ if ( m_Writer.empty() )
+ {
+ assert(g_OPAtomHeader);
+ return *g_OPAtomHeader;
+ }
+
+ return m_Writer->m_HeaderPart;
+}
+
+// Warning: direct manipulation of MXF structures can interfere
+// with the normal operation of the wrapper. Caveat emptor!
+//
+ASDCP::MXF::OPAtomIndexFooter&
+ASDCP::JP2K::MXFWriter::OPAtomIndexFooter()
+{
+ if ( m_Writer.empty() )
+ {
+ assert(g_OPAtomIndexFooter);
+ return *g_OPAtomIndexFooter;
+ }
+
+ return m_Writer->m_FooterPart;
+}
+
+// Open the file for writing. The file must not exist unless overwrite is true. Returns error if
+// the operation cannot be completed.
+ASDCP::Result_t
+ASDCP::JP2K::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info,
+ const PictureDescriptor& PDesc, ui32_t HeaderSize, bool overwrite)
+{
+ if ( Info.LabelSetType == LS_MXF_SMPTE )
+ m_Writer = new h__Writer(DefaultSMPTEDict());
+ else
+ m_Writer = new h__Writer(DefaultInteropDict());
+
+ m_Writer->m_Info = Info;
+
+ Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000, HeaderSize, overwrite);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = m_Writer->SetSourceStream(PDesc, JP2K_PACKAGE_LABEL);
+
+ if ( ASDCP_FAILURE(result) )
+ m_Writer.release();
+
+ return result;
+}
+
+
+// Writes a frame of essence to the MXF file. If the optional AESEncContext
+// argument is present, the essence is encrypted prior to writing.
+// Fails if the file is not open, is finalized, or an operating system
+// error occurs.
+ASDCP::Result_t
+ASDCP::JP2K::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC, std::string* hash)
+{
+ if ( m_Writer.empty() )
+ return RESULT_INIT;
+
+ return m_Writer->WriteFrame(FrameBuf, true, Ctx, HMAC, hash);
+}
+
+ASDCP::Result_t
+ASDCP::JP2K::MXFWriter::FakeWriteFrame(int size)
+{
+ if ( m_Writer.empty() )
+ return RESULT_INIT;
+
+ return m_Writer->FakeWriteFrame(size, true);
+}
+
+// Closes the MXF file, writing the index and other closing information.
+ASDCP::Result_t
+ASDCP::JP2K::MXFWriter::Finalize()
+{
+ if ( m_Writer.empty() )
+ return RESULT_INIT;
+
+ return m_Writer->Finalize();
+}
+
+ui64_t
+ASDCP::JP2K::MXFWriter::Tell() const
+{
+ return m_Writer->m_File.Tell();
+}
+
+
+//------------------------------------------------------------------------------------------
+//
+
+//
+class ASDCP::JP2K::MXFSWriter::h__SWriter : public lh__Writer
+{
+ ASDCP_NO_COPY_CONSTRUCT(h__SWriter);
+ h__SWriter();
+ StereoscopicPhase_t m_NextPhase;
+
+public:
+ h__SWriter(const Dictionary& d) : lh__Writer(d), m_NextPhase(SP_LEFT) {}
+
+ //
+ Result_t WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
+ AESEncContext* Ctx, HMACContext* HMAC, std::string* hash)
+ {
+ if ( m_NextPhase != phase )
+ return RESULT_SPHASE;
+
+ if ( phase == SP_LEFT )
+ {
+ m_NextPhase = SP_RIGHT;
+ return lh__Writer::WriteFrame(FrameBuf, true, Ctx, HMAC, hash);
+ }
+
+ m_NextPhase = SP_LEFT;
+ return lh__Writer::WriteFrame(FrameBuf, false, Ctx, HMAC, hash);
+ }
+
+ Result_t FakeWriteFrame(int size, StereoscopicPhase_t phase)
+ {
+ if (m_NextPhase != phase)
+ {
+ return RESULT_SPHASE;
+ }
+
+ if (phase == SP_LEFT)
+ {
+ m_NextPhase = SP_RIGHT;
+ return lh__Writer::FakeWriteFrame(size, true);
+ }
+
+ m_NextPhase = SP_LEFT;
+ return lh__Writer::FakeWriteFrame(size, false);
+ }
+
+ //
+ Result_t Finalize()
+ {
+ if ( m_NextPhase != SP_LEFT )
+ return RESULT_SPHASE;
+
+ assert( m_FramesWritten % 2 == 0 );
+ m_FramesWritten /= 2;
+ return lh__Writer::Finalize();
+ }
+};
+
+
+//
+ASDCP::JP2K::MXFSWriter::MXFSWriter()
+{
+}
+
+ASDCP::JP2K::MXFSWriter::~MXFSWriter()
+{
+}
+
+// Warning: direct manipulation of MXF structures can interfere
+// with the normal operation of the wrapper. Caveat emptor!
+//
+ASDCP::MXF::OPAtomHeader&
+ASDCP::JP2K::MXFSWriter::OPAtomHeader()
+{
+ if ( m_Writer.empty() )
+ {
+ assert(g_OPAtomHeader);
+ return *g_OPAtomHeader;
+ }
+
+ return m_Writer->m_HeaderPart;
+}
+
+// Warning: direct manipulation of MXF structures can interfere
+// with the normal operation of the wrapper. Caveat emptor!
+//
+ASDCP::MXF::OPAtomIndexFooter&
+ASDCP::JP2K::MXFSWriter::OPAtomIndexFooter()
+{
+ if ( m_Writer.empty() )
+ {
+ assert(g_OPAtomIndexFooter);
+ return *g_OPAtomIndexFooter;
+ }
+
+ return m_Writer->m_FooterPart;
+}
+
+// Open the file for writing. The file must not exist. Returns error if
+// the operation cannot be completed.
+ASDCP::Result_t
+ASDCP::JP2K::MXFSWriter::OpenWrite(const char* filename, const WriterInfo& Info,
+ const PictureDescriptor& PDesc, ui32_t HeaderSize, bool overwrite)
+{
+ if ( Info.LabelSetType == LS_MXF_SMPTE )
+ m_Writer = new h__SWriter(DefaultSMPTEDict());
+ else
+ m_Writer = new h__SWriter(DefaultInteropDict());
+
+ if ( PDesc.EditRate != ASDCP::EditRate_24
+ && PDesc.EditRate != ASDCP::EditRate_25
+ && PDesc.EditRate != ASDCP::EditRate_30
+ && PDesc.EditRate != ASDCP::EditRate_48
+ && PDesc.EditRate != ASDCP::EditRate_50
+ && PDesc.EditRate != ASDCP::EditRate_60 )
+ {
+ DefaultLogSink().Error("Stereoscopic wrapping requires 24, 25, 30, 48, 50 or 60 fps input streams.\n");
+ return RESULT_FORMAT;
+ }
+
+ if ( PDesc.StoredWidth > 2048 )
+ DefaultLogSink().Warn("Wrapping non-standard 4K stereoscopic content. I hope you know what you are doing!\n");
+
+ m_Writer->m_Info = Info;
+
+ Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000_S, HeaderSize, overwrite);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ PictureDescriptor TmpPDesc = PDesc;
+
+ if ( PDesc.EditRate == ASDCP::EditRate_24 )
+ TmpPDesc.EditRate = ASDCP::EditRate_48;
+
+ else if ( PDesc.EditRate == ASDCP::EditRate_25 )
+ TmpPDesc.EditRate = ASDCP::EditRate_50;
+
+ else if ( PDesc.EditRate == ASDCP::EditRate_30 )
+ TmpPDesc.EditRate = ASDCP::EditRate_60;
+
+ else if ( PDesc.EditRate == ASDCP::EditRate_48 )
+ TmpPDesc.EditRate = ASDCP::EditRate_96;
+
+ else if ( PDesc.EditRate == ASDCP::EditRate_50 )
+ TmpPDesc.EditRate = ASDCP::EditRate_100;
+
+ else if ( PDesc.EditRate == ASDCP::EditRate_60 )
+ TmpPDesc.EditRate = ASDCP::EditRate_120;
+
+ result = m_Writer->SetSourceStream(TmpPDesc, JP2K_S_PACKAGE_LABEL, PDesc.EditRate);
+ }
+
+ if ( ASDCP_FAILURE(result) )
+ m_Writer.release();
+
+ return result;
+}
+
+ASDCP::Result_t
+ASDCP::JP2K::MXFSWriter::WriteFrame(const SFrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
+{
+ if ( m_Writer.empty() )
+ return RESULT_INIT;
+
+ Result_t result = m_Writer->WriteFrame(FrameBuf.Left, SP_LEFT, Ctx, HMAC, 0);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = m_Writer->WriteFrame(FrameBuf.Right, SP_RIGHT, Ctx, HMAC, 0);
+
+ return result;
+}
+
+// Writes a frame of essence to the MXF file. If the optional AESEncContext
+// argument is present, the essence is encrypted prior to writing.
+// Fails if the file is not open, is finalized, or an operating system
+// error occurs.
+ASDCP::Result_t
+ASDCP::JP2K::MXFSWriter::WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
+ AESEncContext* Ctx, HMACContext* HMAC, std::string* hash)
+{
+ if ( m_Writer.empty() )
+ return RESULT_INIT;
+
+ return m_Writer->WriteFrame(FrameBuf, phase, Ctx, HMAC, hash);
+}
+
+ASDCP::Result_t
+ASDCP::JP2K::MXFSWriter::FakeWriteFrame(int size, StereoscopicPhase_t phase)
+{
+ if ( m_Writer.empty() )
+ return RESULT_INIT;
+
+ return m_Writer->FakeWriteFrame(size, phase);
+}
+
+// Closes the MXF file, writing the index and other closing information.
+ASDCP::Result_t
+ASDCP::JP2K::MXFSWriter::Finalize()
+{
+ if ( m_Writer.empty() )
+ return RESULT_INIT;
+
+ return m_Writer->Finalize();
+}
+
+ui64_t
+ASDCP::JP2K::MXFSWriter::Tell() const
+{
+ return m_Writer->m_File.Tell();
+}
+
+//
+// end AS_DCP_JP2K.cpp
+//
diff --git a/asdcplib/src/AS_DCP_MPEG2.cpp b/asdcplib/src/AS_DCP_MPEG2.cpp
new file mode 100755
index 0000000..bc64c1e
--- /dev/null
+++ b/asdcplib/src/AS_DCP_MPEG2.cpp
@@ -0,0 +1,727 @@
+/*
+Copyright (c) 2004-2012, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file AS_DCP_MPEG2.cpp
+ \version $Id: AS_DCP_MPEG2.cpp,v 1.34 2012/02/07 18:54:24 jhurst Exp $
+ \brief AS-DCP library, MPEG2 essence reader and writer implementation
+*/
+
+#include "AS_DCP_internal.h"
+#include <iostream>
+#include <iomanip>
+
+
+//------------------------------------------------------------------------------------------
+
+static std::string MPEG_PACKAGE_LABEL = "File Package: SMPTE 381M frame wrapping of MPEG2 video elementary stream";
+static std::string PICT_DEF_LABEL = "Picture Track";
+
+//
+ASDCP::Result_t
+MD_to_MPEG2_VDesc(MXF::MPEG2VideoDescriptor* VDescObj, MPEG2::VideoDescriptor& VDesc)
+{
+ ASDCP_TEST_NULL(VDescObj);
+
+ VDesc.SampleRate = VDescObj->SampleRate;
+ VDesc.EditRate = VDescObj->SampleRate;
+ VDesc.FrameRate = VDescObj->SampleRate.Numerator;
+ assert(VDescObj->ContainerDuration <= 0xFFFFFFFFL);
+ VDesc.ContainerDuration = (ui32_t) VDescObj->ContainerDuration;
+
+ VDesc.FrameLayout = VDescObj->FrameLayout;
+ VDesc.StoredWidth = VDescObj->StoredWidth;
+ VDesc.StoredHeight = VDescObj->StoredHeight;
+ VDesc.AspectRatio = VDescObj->AspectRatio;
+
+ VDesc.ComponentDepth = VDescObj->ComponentDepth;
+ VDesc.HorizontalSubsampling = VDescObj->HorizontalSubsampling;
+ VDesc.VerticalSubsampling = VDescObj->VerticalSubsampling;
+ VDesc.ColorSiting = VDescObj->ColorSiting;
+ VDesc.CodedContentType = VDescObj->CodedContentType;
+
+ VDesc.LowDelay = VDescObj->LowDelay == 0 ? false : true;
+ VDesc.BitRate = VDescObj->BitRate;
+ VDesc.ProfileAndLevel = VDescObj->ProfileAndLevel;
+ return RESULT_OK;
+}
+
+
+//
+ASDCP::Result_t
+MPEG2_VDesc_to_MD(MPEG2::VideoDescriptor& VDesc, MXF::MPEG2VideoDescriptor* VDescObj)
+{
+ ASDCP_TEST_NULL(VDescObj);
+
+ VDescObj->SampleRate = VDesc.SampleRate;
+ VDescObj->ContainerDuration = VDesc.ContainerDuration;
+
+ VDescObj->FrameLayout = VDesc.FrameLayout;
+ VDescObj->StoredWidth = VDesc.StoredWidth;
+ VDescObj->StoredHeight = VDesc.StoredHeight;
+ VDescObj->AspectRatio = VDesc.AspectRatio;
+
+ VDescObj->ComponentDepth = VDesc.ComponentDepth;
+ VDescObj->HorizontalSubsampling = VDesc.HorizontalSubsampling;
+ VDescObj->VerticalSubsampling = VDesc.VerticalSubsampling;
+ VDescObj->ColorSiting = VDesc.ColorSiting;
+ VDescObj->CodedContentType = VDesc.CodedContentType;
+
+ VDescObj->LowDelay = VDesc.LowDelay ? 1 : 0;
+ VDescObj->BitRate = VDesc.BitRate;
+ VDescObj->ProfileAndLevel = VDesc.ProfileAndLevel;
+ return RESULT_OK;
+}
+
+//
+std::ostream&
+ASDCP::MPEG2::operator << (std::ostream& strm, const VideoDescriptor& VDesc)
+{
+ strm << " SampleRate: " << VDesc.SampleRate.Numerator << "/" << VDesc.SampleRate.Denominator << std::endl;
+ strm << " FrameLayout: " << (unsigned) VDesc.FrameLayout << std::endl;
+ strm << " StoredWidth: " << (unsigned) VDesc.StoredWidth << std::endl;
+ strm << " StoredHeight: " << (unsigned) VDesc.StoredHeight << std::endl;
+ strm << " AspectRatio: " << VDesc.AspectRatio.Numerator << "/" << VDesc.AspectRatio.Denominator << std::endl;
+ strm << " ComponentDepth: " << (unsigned) VDesc.ComponentDepth << std::endl;
+ strm << " HorizontalSubsmpl: " << (unsigned) VDesc.HorizontalSubsampling << std::endl;
+ strm << " VerticalSubsmpl: " << (unsigned) VDesc.VerticalSubsampling << std::endl;
+ strm << " ColorSiting: " << (unsigned) VDesc.ColorSiting << std::endl;
+ strm << " CodedContentType: " << (unsigned) VDesc.CodedContentType << std::endl;
+ strm << " LowDelay: " << (unsigned) VDesc.LowDelay << std::endl;
+ strm << " BitRate: " << (unsigned) VDesc.BitRate << std::endl;
+ strm << " ProfileAndLevel: " << (unsigned) VDesc.ProfileAndLevel << std::endl;
+ strm << " ContainerDuration: " << (unsigned) VDesc.ContainerDuration << std::endl;
+
+ return strm;
+}
+
+//
+void
+ASDCP::MPEG2::VideoDescriptorDump(const VideoDescriptor& VDesc, FILE* stream)
+{
+ if ( stream == 0 )
+ stream = stderr;
+
+ fprintf(stream, "\
+ SampleRate: %d/%d\n\
+ FrameLayout: %u\n\
+ StoredWidth: %u\n\
+ StoredHeight: %u\n\
+ AspectRatio: %d/%d\n\
+ ComponentDepth: %u\n\
+ HorizontalSubsmpl: %u\n\
+ VerticalSubsmpl: %u\n\
+ ColorSiting: %u\n\
+ CodedContentType: %u\n\
+ LowDelay: %u\n\
+ BitRate: %u\n\
+ ProfileAndLevel: %u\n\
+ ContainerDuration: %u\n",
+ VDesc.SampleRate.Numerator ,VDesc.SampleRate.Denominator,
+ VDesc.FrameLayout,
+ VDesc.StoredWidth,
+ VDesc.StoredHeight,
+ VDesc.AspectRatio.Numerator ,VDesc.AspectRatio.Denominator,
+ VDesc.ComponentDepth,
+ VDesc.HorizontalSubsampling,
+ VDesc.VerticalSubsampling,
+ VDesc.ColorSiting,
+ VDesc.CodedContentType,
+ VDesc.LowDelay,
+ VDesc.BitRate,
+ VDesc.ProfileAndLevel,
+ VDesc.ContainerDuration
+ );
+}
+
+//------------------------------------------------------------------------------------------
+//
+// hidden, internal implementation of MPEG2 reader
+
+class ASDCP::MPEG2::MXFReader::h__Reader : public ASDCP::h__Reader
+{
+ ASDCP_NO_COPY_CONSTRUCT(h__Reader);
+ h__Reader();
+
+public:
+ VideoDescriptor m_VDesc; // video parameter list
+
+ h__Reader(const Dictionary& d) : ASDCP::h__Reader(d) {}
+ ~h__Reader() {}
+ Result_t OpenRead(const char*);
+ Result_t ReadFrame(ui32_t, FrameBuffer&, AESDecContext*, HMACContext*);
+ Result_t ReadFrameGOPStart(ui32_t, FrameBuffer&, AESDecContext*, HMACContext*);
+ Result_t FindFrameGOPStart(ui32_t, ui32_t&);
+ Result_t FrameType(ui32_t FrameNum, FrameType_t& type);
+};
+
+
+//
+//
+ASDCP::Result_t
+ASDCP::MPEG2::MXFReader::h__Reader::OpenRead(const char* filename)
+{
+ Result_t result = OpenMXFRead(filename);
+
+ if( ASDCP_SUCCESS(result) )
+ {
+ InterchangeObject* Object;
+ if ( ASDCP_SUCCESS(m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(MPEG2VideoDescriptor), &Object)) )
+ {
+ assert(Object);
+ result = MD_to_MPEG2_VDesc((MXF::MPEG2VideoDescriptor*)Object, m_VDesc);
+ }
+ }
+
+ if( ASDCP_SUCCESS(result) )
+ result = InitMXFIndex();
+
+ if( ASDCP_SUCCESS(result) )
+ result = InitInfo();
+
+ return result;
+}
+
+
+//
+//
+ASDCP::Result_t
+ASDCP::MPEG2::MXFReader::h__Reader::ReadFrameGOPStart(ui32_t FrameNum, FrameBuffer& FrameBuf,
+ AESDecContext* Ctx, HMACContext* HMAC)
+{
+ ui32_t KeyFrameNum;
+
+ Result_t result = FindFrameGOPStart(FrameNum, KeyFrameNum);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = ReadFrame(KeyFrameNum, FrameBuf, Ctx, HMAC);
+
+ return result;
+}
+
+
+//
+//
+ASDCP::Result_t
+ASDCP::MPEG2::MXFReader::h__Reader::FindFrameGOPStart(ui32_t FrameNum, ui32_t& KeyFrameNum)
+{
+ KeyFrameNum = 0;
+
+ if ( ! m_File.IsOpen() )
+ return RESULT_INIT;
+
+ // 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;
+ }
+
+ KeyFrameNum = FrameNum - TmpEntry.KeyFrameOffset;
+
+ return RESULT_OK;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MPEG2::MXFReader::h__Reader::FrameType(ui32_t FrameNum, FrameType_t& type)
+{
+ if ( ! m_File.IsOpen() )
+ return RESULT_INIT;
+
+ // 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;
+ }
+
+ type = ( (TmpEntry.Flags & 0x0f) == 3 ) ? FRAME_B : ( (TmpEntry.Flags & 0x0f) == 2 ) ? FRAME_P : FRAME_I;
+ return RESULT_OK;
+}
+
+
+//
+//
+ASDCP::Result_t
+ASDCP::MPEG2::MXFReader::h__Reader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
+ AESDecContext* Ctx, HMACContext* HMAC)
+{
+ assert(m_Dict);
+ if ( ! m_File.IsOpen() )
+ return RESULT_INIT;
+
+ Result_t result = ReadEKLVFrame(FrameNum, FrameBuf, m_Dict->ul(MDD_MPEG2Essence), Ctx, HMAC);
+
+ if ( ASDCP_FAILURE(result) )
+ return result;
+
+ IndexTableSegment::IndexEntry TmpEntry;
+ m_FooterPart.Lookup(FrameNum, TmpEntry);
+
+ switch ( ( TmpEntry.Flags >> 4 ) & 0x03 )
+ {
+ case 0: FrameBuf.FrameType(FRAME_I); break;
+ case 2: FrameBuf.FrameType(FRAME_P); break;
+ case 3: FrameBuf.FrameType(FRAME_B); break;
+ default: FrameBuf.FrameType(FRAME_U);
+ }
+
+ FrameBuf.TemporalOffset(TmpEntry.TemporalOffset);
+ FrameBuf.GOPStart(TmpEntry.Flags & 0x40 ? true : false);
+ FrameBuf.ClosedGOP(TmpEntry.Flags & 0x80 ? true : false);
+
+ return RESULT_OK;
+}
+
+//------------------------------------------------------------------------------------------
+
+
+//
+void
+ASDCP::MPEG2::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
+{
+ if ( stream == 0 )
+ stream = stderr;
+
+ fprintf(stream, "Frame: %06u, %c%-2hu, %7u bytes",
+ m_FrameNumber, FrameTypeChar(m_FrameType), m_TemporalOffset, m_Size);
+
+ if ( m_GOPStart )
+ fprintf(stream, " (start %s GOP)", ( m_ClosedGOP ? "closed" : "open"));
+
+ fputc('\n', stream);
+
+ if ( dump_len > 0 )
+ Kumu::hexdump(m_Data, dump_len, stream);
+}
+
+
+//------------------------------------------------------------------------------------------
+
+ASDCP::MPEG2::MXFReader::MXFReader()
+{
+ m_Reader = new h__Reader(DefaultCompositeDict());
+}
+
+
+ASDCP::MPEG2::MXFReader::~MXFReader()
+{
+}
+
+// Warning: direct manipulation of MXF structures can interfere
+// with the normal operation of the wrapper. Caveat emptor!
+//
+ASDCP::MXF::OPAtomHeader&
+ASDCP::MPEG2::MXFReader::OPAtomHeader()
+{
+ if ( m_Reader.empty() )
+ {
+ assert(g_OPAtomHeader);
+ return *g_OPAtomHeader;
+ }
+
+ return m_Reader->m_HeaderPart;
+}
+
+// Warning: direct manipulation of MXF structures can interfere
+// with the normal operation of the wrapper. Caveat emptor!
+//
+ASDCP::MXF::OPAtomIndexFooter&
+ASDCP::MPEG2::MXFReader::OPAtomIndexFooter()
+{
+ if ( m_Reader.empty() )
+ {
+ assert(g_OPAtomIndexFooter);
+ return *g_OPAtomIndexFooter;
+ }
+
+ return m_Reader->m_FooterPart;
+}
+
+// Open the file for reading. The file must exist. Returns error if the
+// operation cannot be completed.
+ASDCP::Result_t
+ASDCP::MPEG2::MXFReader::OpenRead(const char* filename) const
+{
+ return m_Reader->OpenRead(filename);
+}
+
+//
+ASDCP::Result_t
+ASDCP::MPEG2::MXFReader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
+ AESDecContext* Ctx, HMACContext* HMAC) const
+{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC);
+
+ return RESULT_INIT;
+}
+
+
+//
+ASDCP::Result_t
+ASDCP::MPEG2::MXFReader::ReadFrameGOPStart(ui32_t FrameNum, FrameBuffer& FrameBuf,
+ AESDecContext* Ctx, HMACContext* HMAC) const
+{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ return m_Reader->ReadFrameGOPStart(FrameNum, FrameBuf, Ctx, HMAC);
+
+ return RESULT_INIT;
+}
+
+
+//
+ASDCP::Result_t
+ASDCP::MPEG2::MXFReader::FindFrameGOPStart(ui32_t FrameNum, ui32_t& KeyFrameNum) const
+{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ return m_Reader->FindFrameGOPStart(FrameNum, KeyFrameNum);
+
+ return RESULT_INIT;
+}
+
+
+// Fill the struct with the values from the file's header.
+// Returns RESULT_INIT if the file is not open.
+ASDCP::Result_t
+ASDCP::MPEG2::MXFReader::FillVideoDescriptor(VideoDescriptor& VDesc) const
+{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ {
+ VDesc = m_Reader->m_VDesc;
+ return RESULT_OK;
+ }
+
+ return RESULT_INIT;
+}
+
+
+// Fill the struct with the values from the file's header.
+// Returns RESULT_INIT if the file is not open.
+ASDCP::Result_t
+ASDCP::MPEG2::MXFReader::FillWriterInfo(WriterInfo& Info) const
+{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ {
+ Info = m_Reader->m_Info;
+ return RESULT_OK;
+ }
+
+ return RESULT_INIT;
+}
+
+//
+void
+ASDCP::MPEG2::MXFReader::DumpHeaderMetadata(FILE* stream) const
+{
+ if ( m_Reader->m_File.IsOpen() )
+ m_Reader->m_HeaderPart.Dump(stream);
+}
+
+
+//
+void
+ASDCP::MPEG2::MXFReader::DumpIndex(FILE* stream) const
+{
+ if ( m_Reader->m_File.IsOpen() )
+ m_Reader->m_FooterPart.Dump(stream);
+}
+
+//
+ASDCP::Result_t
+ASDCP::MPEG2::MXFReader::Close() const
+{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ {
+ m_Reader->Close();
+ return RESULT_OK;
+ }
+
+ return RESULT_INIT;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MPEG2::MXFReader::FrameType(ui32_t FrameNum, FrameType_t& type) const
+{
+ if ( ! m_Reader )
+ return RESULT_INIT;
+
+ return m_Reader->FrameType(FrameNum, type);
+}
+
+
+//------------------------------------------------------------------------------------------
+
+//
+class ASDCP::MPEG2::MXFWriter::h__Writer : public ASDCP::h__Writer
+{
+ ASDCP_NO_COPY_CONSTRUCT(h__Writer);
+ h__Writer();
+
+public:
+ VideoDescriptor m_VDesc;
+ ui32_t m_GOPOffset;
+ byte_t m_EssenceUL[SMPTE_UL_LENGTH];
+
+ h__Writer(const Dictionary& d) : ASDCP::h__Writer(d), m_GOPOffset(0) {
+ memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
+ }
+
+ ~h__Writer(){}
+
+ Result_t OpenWrite(const char*, ui32_t HeaderSize);
+ Result_t SetSourceStream(const VideoDescriptor&);
+ Result_t WriteFrame(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0);
+ Result_t Finalize();
+};
+
+
+// Open the file for writing. The file must not exist. Returns error if
+// the operation cannot be completed.
+ASDCP::Result_t
+ASDCP::MPEG2::MXFWriter::h__Writer::OpenWrite(const char* filename, ui32_t HeaderSize)
+{
+ if ( ! m_State.Test_BEGIN() )
+ return RESULT_STATE;
+
+ Result_t result = m_File.OpenWrite(filename);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ m_HeaderSize = HeaderSize;
+ m_EssenceDescriptor = new MPEG2VideoDescriptor(m_Dict);
+ result = m_State.Goto_INIT();
+ }
+
+ return result;
+}
+
+// Automatically sets the MXF file's metadata from the MPEG stream.
+ASDCP::Result_t
+ASDCP::MPEG2::MXFWriter::h__Writer::SetSourceStream(const VideoDescriptor& VDesc)
+{
+ assert(m_Dict);
+ if ( ! m_State.Test_INIT() )
+ return RESULT_STATE;
+
+ m_VDesc = VDesc;
+ Result_t result = MPEG2_VDesc_to_MD(m_VDesc, (MPEG2VideoDescriptor*)m_EssenceDescriptor);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ memcpy(m_EssenceUL, m_Dict->ul(MDD_MPEG2Essence), SMPTE_UL_LENGTH);
+ m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
+ result = m_State.Goto_READY();
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ ui32_t TCFrameRate = ( m_VDesc.EditRate == EditRate_23_98 ) ? 24 : m_VDesc.EditRate.Numerator;
+
+ result = WriteMXFHeader(MPEG_PACKAGE_LABEL, UL(m_Dict->ul(MDD_MPEG2_VESWrapping)),
+ PICT_DEF_LABEL, UL(m_EssenceUL), UL(m_Dict->ul(MDD_PictureDataDef)),
+ m_VDesc.EditRate, TCFrameRate);
+ }
+
+ return result;
+}
+
+// Writes a frame of essence to the MXF file. If the optional AESEncContext
+// argument is present, the essence is encrypted prior to writing.
+// Fails if the file is not open, is finalized, or an operating system
+// error occurs.
+//
+ASDCP::Result_t
+ASDCP::MPEG2::MXFWriter::h__Writer::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx,
+ HMACContext* HMAC)
+{
+ Result_t result = RESULT_OK;
+
+ if ( m_State.Test_READY() )
+ result = m_State.Goto_RUNNING(); // first time through, get the body location
+
+ IndexTableSegment::IndexEntry Entry;
+ Entry.StreamOffset = m_StreamOffset;
+
+ if ( ASDCP_SUCCESS(result) )
+ result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC);
+
+ if ( ASDCP_FAILURE(result) )
+ return result;
+
+ // create mxflib flags
+ int Flags = 0;
+
+ switch ( FrameBuf.FrameType() )
+ {
+ case FRAME_I: Flags = 0x00; break;
+ case FRAME_P: Flags = 0x22; break;
+ case FRAME_B: Flags = 0x33; break;
+ /* Keep gcc quiet */
+ case FRAME_U: break;
+ }
+
+ if ( FrameBuf.GOPStart() )
+ {
+ m_GOPOffset = 0;
+ Flags |= 0x40;
+
+ if ( FrameBuf.ClosedGOP() )
+ Flags |= 0x80;
+ }
+
+ // update the index manager
+ Entry.TemporalOffset = - FrameBuf.TemporalOffset();
+ Entry.KeyFrameOffset = 0 - m_GOPOffset;
+ Entry.Flags = Flags;
+ /*
+ fprintf(stderr, "to: %4hd ko: %4hd c1: %4hd c2: %4hd fl: 0x%02x\n",
+ Entry.TemporalOffset, Entry.KeyFrameOffset,
+ m_GOPOffset + Entry.TemporalOffset,
+ Entry.KeyFrameOffset - Entry.TemporalOffset,
+ Entry.Flags);
+ */
+ m_FooterPart.PushIndexEntry(Entry);
+ m_FramesWritten++;
+ m_GOPOffset++;
+
+ return RESULT_OK;
+}
+
+
+// Closes the MXF file, writing the index and other closing information.
+//
+ASDCP::Result_t
+ASDCP::MPEG2::MXFWriter::h__Writer::Finalize()
+{
+ if ( ! m_State.Test_RUNNING() )
+ return RESULT_STATE;
+
+ m_State.Goto_FINAL();
+
+ return WriteMXFFooter();
+}
+
+
+//------------------------------------------------------------------------------------------
+
+
+
+ASDCP::MPEG2::MXFWriter::MXFWriter()
+{
+}
+
+ASDCP::MPEG2::MXFWriter::~MXFWriter()
+{
+}
+
+// Warning: direct manipulation of MXF structures can interfere
+// with the normal operation of the wrapper. Caveat emptor!
+//
+ASDCP::MXF::OPAtomHeader&
+ASDCP::MPEG2::MXFWriter::OPAtomHeader()
+{
+ if ( m_Writer.empty() )
+ {
+ assert(g_OPAtomHeader);
+ return *g_OPAtomHeader;
+ }
+
+ return m_Writer->m_HeaderPart;
+}
+
+// Warning: direct manipulation of MXF structures can interfere
+// with the normal operation of the wrapper. Caveat emptor!
+//
+ASDCP::MXF::OPAtomIndexFooter&
+ASDCP::MPEG2::MXFWriter::OPAtomIndexFooter()
+{
+ if ( m_Writer.empty() )
+ {
+ assert(g_OPAtomIndexFooter);
+ return *g_OPAtomIndexFooter;
+ }
+
+ return m_Writer->m_FooterPart;
+}
+
+// Open the file for writing. The file must not exist. Returns error if
+// the operation cannot be completed.
+ASDCP::Result_t
+ASDCP::MPEG2::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info,
+ const VideoDescriptor& VDesc, ui32_t HeaderSize)
+{
+ if ( Info.LabelSetType == LS_MXF_SMPTE )
+ m_Writer = new h__Writer(DefaultSMPTEDict());
+ else
+ m_Writer = new h__Writer(DefaultInteropDict());
+
+ m_Writer->m_Info = Info;
+
+ Result_t result = m_Writer->OpenWrite(filename, HeaderSize);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = m_Writer->SetSourceStream(VDesc);
+
+ if ( ASDCP_FAILURE(result) )
+ m_Writer.release();
+
+ return result;
+}
+
+
+// Writes a frame of essence to the MXF file. If the optional AESEncContext
+// argument is present, the essence is encrypted prior to writing.
+// Fails if the file is not open, is finalized, or an operating system
+// error occurs.
+ASDCP::Result_t
+ASDCP::MPEG2::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
+{
+ if ( m_Writer.empty() )
+ return RESULT_INIT;
+
+ return m_Writer->WriteFrame(FrameBuf, Ctx, HMAC);
+}
+
+// Closes the MXF file, writing the index and other closing information.
+ASDCP::Result_t
+ASDCP::MPEG2::MXFWriter::Finalize()
+{
+ if ( m_Writer.empty() )
+ return RESULT_INIT;
+
+ return m_Writer->Finalize();
+}
+
+
+//
+// end AS_DCP_MPEG2.cpp
+//
diff --git a/asdcplib/src/AS_DCP_MXF.cpp b/asdcplib/src/AS_DCP_MXF.cpp
new file mode 100755
index 0000000..da5232f
--- /dev/null
+++ b/asdcplib/src/AS_DCP_MXF.cpp
@@ -0,0 +1,542 @@
+/*
+Copyright (c) 2004-2009, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file AS_DCP_MXF.cpp
+ \version $Id: AS_DCP_MXF.cpp,v 1.31 2009/08/04 18:43:10 jhurst Exp $
+ \brief AS-DCP library, misc classes and subroutines
+*/
+
+#include <KM_fileio.h>
+#include <KM_xml.h>
+#include "AS_DCP_internal.h"
+#include "JP2K.h"
+#include "MPEG.h"
+#include "Wav.h"
+#include <iostream>
+#include <iomanip>
+
+
+//------------------------------------------------------------------------------------------
+// misc subroutines
+
+
+//
+std::ostream&
+ASDCP::operator << (std::ostream& strm, const WriterInfo& Info)
+{
+ char str_buf[40];
+
+ strm << " ProductUUID: " << UUID(Info.ProductUUID).EncodeHex(str_buf, 40) << std::endl;
+ strm << " ProductVersion: " << Info.ProductVersion << std::endl;
+ strm << " CompanyName: " << Info.CompanyName << std::endl;
+ strm << " ProductName: " << Info.ProductName << std::endl;
+ strm << " EncryptedEssence: " << (Info.EncryptedEssence ? "Yes" : "No") << std::endl;
+
+ if ( Info.EncryptedEssence )
+ {
+ strm << " HMAC: " << (Info.UsesHMAC ? "Yes" : "No") << std::endl;
+ strm << " ContextID: " << UUID(Info.ContextID).EncodeHex(str_buf, 40) << std::endl;
+ strm << "CryptographicKeyID: " << UUID(Info.CryptographicKeyID).EncodeHex(str_buf, 40) << std::endl;
+ }
+
+ strm << " AssetUUID: " << UUID(Info.AssetUUID).EncodeHex(str_buf, 40) << std::endl;
+ strm << " Label Set Type: " << (Info.LabelSetType == LS_MXF_SMPTE ? "SMPTE" :
+ (Info.LabelSetType == LS_MXF_INTEROP ? "MXF Interop" :
+ "Unknown")) << std::endl;
+ return strm;
+}
+
+//
+void
+ASDCP::WriterInfoDump(const WriterInfo& Info, FILE* stream)
+{
+ if ( stream == 0 )
+ stream = stderr;
+
+ char str_buf[40];
+
+ fprintf(stream," ProductUUID: %s\n", UUID(Info.ProductUUID).EncodeHex(str_buf, 40));
+ fprintf(stream,"\
+ ProductVersion: %s\n\
+ CompanyName: %s\n\
+ ProductName: %s\n\
+ EncryptedEssence: %s\n",
+ Info.ProductVersion.c_str(),
+ Info.CompanyName.c_str(),
+ Info.ProductName.c_str(),
+ ( Info.EncryptedEssence ? "Yes" : "No" )
+ );
+
+ if ( Info.EncryptedEssence )
+ {
+ fprintf(stream, " HMAC: %s\n", ( Info.UsesHMAC ? "Yes" : "No"));
+ 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", 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" ) ));
+}
+
+//
+Result_t
+ASDCP::MD_to_WriterInfo(Identification* InfoObj, WriterInfo& Info)
+{
+ ASDCP_TEST_NULL(InfoObj);
+ char tmp_str[IdentBufferLen];
+
+ Info.ProductName = "Unknown Product";
+ Info.ProductVersion = "Unknown Version";
+ Info.CompanyName = "Unknown Company";
+ memset(Info.ProductUUID, 0, UUIDlen);
+
+ InfoObj->ProductName.EncodeString(tmp_str, IdentBufferLen);
+ if ( *tmp_str ) Info.ProductName = tmp_str;
+
+ InfoObj->VersionString.EncodeString(tmp_str, IdentBufferLen);
+ if ( *tmp_str ) Info.ProductVersion = tmp_str;
+
+ InfoObj->CompanyName.EncodeString(tmp_str, IdentBufferLen);
+ if ( *tmp_str ) Info.CompanyName = tmp_str;
+
+ memcpy(Info.ProductUUID, InfoObj->ProductUID.Value(), UUIDlen);
+
+ return RESULT_OK;
+}
+
+
+//
+Result_t
+ASDCP::MD_to_CryptoInfo(CryptographicContext* InfoObj, WriterInfo& Info, const Dictionary& Dict)
+{
+ ASDCP_TEST_NULL(InfoObj);
+
+ Info.EncryptedEssence = true;
+ memcpy(Info.ContextID, InfoObj->ContextID.Value(), UUIDlen);
+ memcpy(Info.CryptographicKeyID, InfoObj->CryptographicKeyID.Value(), UUIDlen);
+
+ UL MIC_SHA1(Dict.ul(MDD_MICAlgorithm_HMAC_SHA1));
+ UL MIC_NONE(Dict.ul(MDD_MICAlgorithm_NONE));
+
+ if ( InfoObj->MICAlgorithm == MIC_SHA1 )
+ Info.UsesHMAC = true;
+
+ else if ( InfoObj->MICAlgorithm == MIC_NONE )
+ Info.UsesHMAC = false;
+
+ else
+ {
+ DefaultLogSink().Error("Unexpected MICAlgorithm UL.\n");
+ return RESULT_FORMAT;
+ }
+
+ return RESULT_OK;
+}
+
+//
+//
+ASDCP::Result_t
+ASDCP::EssenceType(const char* filename, EssenceType_t& type)
+{
+ const Dictionary* m_Dict = &DefaultCompositeDict();
+ assert(m_Dict);
+
+ ASDCP_TEST_NULL_STR(filename);
+ Kumu::FileReader Reader;
+ OPAtomHeader TestHeader(m_Dict);
+
+ Result_t result = Reader.OpenRead(filename);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = TestHeader.InitFromFile(Reader); // test UL and OP
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ type = ESS_UNKNOWN;
+ if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(RGBAEssenceDescriptor))) )
+ {
+ if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(StereoscopicPictureSubDescriptor))) )
+ type = ESS_JPEG_2000_S;
+ else
+ type = ESS_JPEG_2000;
+ }
+ else if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(WaveAudioDescriptor))) )
+ type = ESS_PCM_24b_48k;
+ else if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(MPEG2VideoDescriptor))) )
+ type = ESS_MPEG2_VES;
+ else if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(TimedTextDescriptor))) )
+ type = ESS_TIMED_TEXT;
+ }
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::RawEssenceType(const char* filename, EssenceType_t& type)
+{
+ ASDCP_TEST_NULL_STR(filename);
+ type = ESS_UNKNOWN;
+ ASDCP::FrameBuffer FB;
+ Kumu::FileReader Reader;
+ ASDCP::Wav::SimpleWaveHeader WavHeader;
+ ASDCP::AIFF::SimpleAIFFHeader AIFFHeader;
+ Kumu::XMLElement TmpElement("Tmp");
+
+ ui32_t data_offset;
+ ui32_t read_count;
+ Result_t result = FB.Capacity(Wav::MaxWavHeader); // using Wav max because everything else is much smaller
+
+ if ( Kumu::PathIsFile(filename) )
+ {
+ result = Reader.OpenRead(filename);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ result = Reader.Read(FB.Data(), FB.Capacity(), &read_count);
+ Reader.Close();
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ const byte_t* p = FB.RoData();
+ FB.Size(read_count);
+
+ ui32_t i = 0;
+ while ( p[i] == 0 ) i++;
+
+ 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 ( memcmp(FB.RoData(), ASDCP::JP2K::Magic, sizeof(ASDCP::JP2K::Magic)) == 0 )
+ {
+ type = ESS_JPEG_2000;
+ }
+ else if ( ASDCP_SUCCESS(WavHeader.ReadFromBuffer(FB.RoData(), read_count, &data_offset)) )
+ {
+ switch ( WavHeader.samplespersec )
+ {
+ case 48000: type = ESS_PCM_24b_48k; break;
+ case 96000: type = ESS_PCM_24b_96k; break;
+ default:
+ return RESULT_FORMAT;
+ }
+ }
+ else if ( ASDCP_SUCCESS(AIFFHeader.ReadFromBuffer(FB.RoData(), read_count, &data_offset)) )
+ {
+ type = ESS_PCM_24b_48k;
+ }
+ else if ( Kumu::StringIsXML((const char*)FB.RoData(), FB.Size()) )
+ {
+ type = ESS_TIMED_TEXT;
+ }
+ }
+ }
+ else if ( Kumu::PathIsDirectory(filename) )
+ {
+ char next_file[Kumu::MaxFilePath];
+ Kumu::DirScanner Scanner;
+ Result_t result = Scanner.Open(filename);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ while ( ASDCP_SUCCESS(Scanner.GetNext(next_file)) )
+ {
+ if ( next_file[0] == '.' ) // no hidden files or internal links
+ continue;
+
+ std::string Str(filename);
+ Str += "/";
+ Str += next_file;
+ result = Reader.OpenRead(Str.c_str());
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ result = Reader.Read(FB.Data(), FB.Capacity(), &read_count);
+ Reader.Close();
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ if ( memcmp(FB.RoData(), ASDCP::JP2K::Magic, sizeof(ASDCP::JP2K::Magic)) == 0 )
+ {
+ type = ESS_JPEG_2000;
+ }
+ else if ( ASDCP_SUCCESS(WavHeader.ReadFromBuffer(FB.RoData(), read_count, &data_offset)) )
+ {
+ switch ( WavHeader.samplespersec )
+ {
+ case 48000: type = ESS_PCM_24b_48k; break;
+ case 96000: type = ESS_PCM_24b_96k; break;
+ default:
+ return RESULT_FORMAT;
+ }
+ }
+ }
+
+ break;
+ }
+ }
+ }
+
+ return result;
+}
+
+//
+Result_t
+ASDCP::EncryptFrameBuffer(const ASDCP::FrameBuffer& FBin, ASDCP::FrameBuffer& FBout, AESEncContext* Ctx)
+{
+ ASDCP_TEST_NULL(Ctx);
+ FBout.Size(0);
+
+ // size the buffer
+ Result_t result = FBout.Capacity(calc_esv_length(FBin.Size(), FBin.PlaintextOffset()));
+
+ // write the IV
+ byte_t* p = FBout.Data();
+
+ // write the IV to the frame buffer
+ Ctx->GetIVec(p);
+ p += CBC_BLOCK_SIZE;
+
+
+ // encrypt the check value to the frame buffer
+ if ( ASDCP_SUCCESS(result) )
+ {
+ result = Ctx->EncryptBlock(ESV_CheckValue, p, CBC_BLOCK_SIZE);
+ p += CBC_BLOCK_SIZE;
+ }
+
+ // write optional plaintext region
+ if ( FBin.PlaintextOffset() > 0 )
+ {
+ assert(FBin.PlaintextOffset() <= FBin.Size());
+ memcpy(p, FBin.RoData(), FBin.PlaintextOffset());
+ p += FBin.PlaintextOffset();
+ }
+
+ ui32_t ct_size = FBin.Size() - FBin.PlaintextOffset();
+ ui32_t diff = ct_size % CBC_BLOCK_SIZE;
+ ui32_t block_size = ct_size - diff;
+ assert((block_size % CBC_BLOCK_SIZE) == 0);
+
+ // encrypt the ciphertext region essence data
+ if ( ASDCP_SUCCESS(result) )
+ {
+ result = Ctx->EncryptBlock(FBin.RoData() + FBin.PlaintextOffset(), p, block_size);
+ p += block_size;
+ }
+
+ // construct and encrypt the padding
+ if ( ASDCP_SUCCESS(result) )
+ {
+ byte_t the_last_block[CBC_BLOCK_SIZE];
+
+ if ( diff > 0 )
+ memcpy(the_last_block, FBin.RoData() + FBin.PlaintextOffset() + block_size, diff);
+
+ for (ui32_t i = 0; diff < CBC_BLOCK_SIZE; diff++, i++ )
+ the_last_block[diff] = i;
+
+ result = Ctx->EncryptBlock(the_last_block, p, CBC_BLOCK_SIZE);
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ FBout.Size(calc_esv_length(FBin.Size(), FBin.PlaintextOffset()));
+
+ return result;
+}
+
+//
+Result_t
+ASDCP::DecryptFrameBuffer(const ASDCP::FrameBuffer& FBin, ASDCP::FrameBuffer& FBout, AESDecContext* Ctx)
+{
+ ASDCP_TEST_NULL(Ctx);
+ assert(FBout.Capacity() >= FBin.SourceLength());
+
+ ui32_t ct_size = FBin.SourceLength() - FBin.PlaintextOffset();
+ ui32_t diff = ct_size % CBC_BLOCK_SIZE;
+ ui32_t block_size = ct_size - diff;
+ assert(block_size);
+ assert((block_size % CBC_BLOCK_SIZE) == 0);
+
+ const byte_t* buf = FBin.RoData();
+
+ // get ivec
+ Ctx->SetIVec(buf);
+ buf += CBC_BLOCK_SIZE;
+
+ // decrypt and test check value
+ byte_t CheckValue[CBC_BLOCK_SIZE];
+ Result_t result = Ctx->DecryptBlock(buf, CheckValue, CBC_BLOCK_SIZE);
+ buf += CBC_BLOCK_SIZE;
+
+ if ( memcmp(CheckValue, ESV_CheckValue, CBC_BLOCK_SIZE) != 0 )
+ return RESULT_CHECKFAIL;
+
+ // copy plaintext region
+ if ( FBin.PlaintextOffset() > 0 )
+ {
+ memcpy(FBout.Data(), buf, FBin.PlaintextOffset());
+ buf += FBin.PlaintextOffset();
+ }
+
+ // decrypt all but last block
+ if ( ASDCP_SUCCESS(result) )
+ {
+ result = Ctx->DecryptBlock(buf, FBout.Data() + FBin.PlaintextOffset(), block_size);
+ buf += block_size;
+ }
+
+ // decrypt last block
+ if ( ASDCP_SUCCESS(result) )
+ {
+ byte_t the_last_block[CBC_BLOCK_SIZE];
+ result = Ctx->DecryptBlock(buf, the_last_block, CBC_BLOCK_SIZE);
+
+ if ( the_last_block[diff] != 0 )
+ {
+ DefaultLogSink().Error("Unexpected non-zero padding value.\n");
+ return RESULT_FORMAT;
+ }
+
+ if ( diff > 0 )
+ memcpy(FBout.Data() + FBin.PlaintextOffset() + block_size, the_last_block, diff);
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ FBout.Size(FBin.SourceLength());
+
+ return result;
+}
+
+
+//
+Result_t
+ASDCP::IntegrityPack::CalcValues(const ASDCP::FrameBuffer& FB, byte_t* AssetID,
+ ui32_t sequence, HMACContext* HMAC)
+{
+ ASDCP_TEST_NULL(AssetID);
+ ASDCP_TEST_NULL(HMAC);
+ byte_t* p = Data;
+ HMAC->Reset();
+
+ static byte_t ber_4[MXF_BER_LENGTH] = {0x83, 0, 0, 0};
+
+ // update HMAC with essence data
+ HMAC->Update(FB.RoData(), FB.Size());
+
+ // track file ID length
+ memcpy(p, ber_4, MXF_BER_LENGTH);
+ *(p+3) = UUIDlen;;
+ p += MXF_BER_LENGTH;
+
+ // track file ID
+ memcpy(p, AssetID, UUIDlen);
+ p += UUIDlen;
+
+ // sequence length
+ memcpy(p, ber_4, MXF_BER_LENGTH);
+ *(p+3) = sizeof(ui64_t);
+ p += MXF_BER_LENGTH;
+
+ // sequence number
+ Kumu::i2p<ui64_t>(KM_i64_BE(sequence), p);
+ p += sizeof(ui64_t);
+
+ // HMAC length
+ memcpy(p, ber_4, MXF_BER_LENGTH);
+ *(p+3) = HMAC_SIZE;
+ p += MXF_BER_LENGTH;
+
+ // update HMAC with intpack values
+ HMAC->Update(Data, klv_intpack_size - HMAC_SIZE);
+
+ // finish & write HMAC
+ HMAC->Finalize();
+ HMAC->GetHMACValue(p);
+
+ assert(p + HMAC_SIZE == Data + klv_intpack_size);
+
+ return RESULT_OK;
+}
+
+
+Result_t
+ASDCP::IntegrityPack::TestValues(const ASDCP::FrameBuffer& FB, byte_t* AssetID,
+ ui32_t sequence, HMACContext* HMAC)
+{
+ ASDCP_TEST_NULL(AssetID);
+ ASDCP_TEST_NULL(HMAC);
+
+ // find the start of the intpack
+ byte_t* p = (byte_t*)FB.RoData() + ( FB.Size() - klv_intpack_size );
+
+ // test the AssetID length
+ if ( ! Kumu::read_test_BER(&p, UUIDlen) )
+ return RESULT_HMACFAIL;
+
+ // test the AssetID
+ if ( memcmp(p, AssetID, UUIDlen) != 0 )
+ {
+ DefaultLogSink().Error("IntegrityPack failure: AssetID mismatch.\n");
+ return RESULT_HMACFAIL;
+ }
+ p += UUIDlen;
+
+ // test the sequence length
+ if ( ! Kumu::read_test_BER(&p, sizeof(ui64_t)) )
+ return RESULT_HMACFAIL;
+
+ ui32_t test_sequence = (ui32_t)KM_i64_BE(Kumu::cp2i<ui64_t>(p));
+
+ // test the sequence value
+ if ( test_sequence != sequence )
+ {
+ DefaultLogSink().Error("IntegrityPack failure: sequence is %u, expecting %u.\n", test_sequence, sequence);
+ return RESULT_HMACFAIL;
+ }
+
+ p += sizeof(ui64_t);
+
+ // test the HMAC length
+ if ( ! Kumu::read_test_BER(&p, HMAC_SIZE) )
+ return RESULT_HMACFAIL;
+
+ // test the HMAC
+ HMAC->Reset();
+ HMAC->Update(FB.RoData(), FB.Size() - HMAC_SIZE);
+ HMAC->Finalize();
+
+ return HMAC->TestHMACValue(p);
+}
+
+//
+// end AS_DCP_MXF.cpp
+//
diff --git a/asdcplib/src/AS_DCP_PCM.cpp b/asdcplib/src/AS_DCP_PCM.cpp
new file mode 100755
index 0000000..385d903
--- /dev/null
+++ b/asdcplib/src/AS_DCP_PCM.cpp
@@ -0,0 +1,671 @@
+/*
+Copyright (c) 2004-2012, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file AS_DCP_PCM.cpp
+ \version $Id: AS_DCP_PCM.cpp,v 1.36 2012/02/07 18:54:25 jhurst Exp $
+ \brief AS-DCP library, PCM essence reader and writer implementation
+*/
+
+#include "AS_DCP_internal.h"
+#include <map>
+#include <iostream>
+#include <iomanip>
+
+//------------------------------------------------------------------------------------------
+
+static std::string PCM_PACKAGE_LABEL = "File Package: SMPTE 382M frame wrapping of wave audio";
+static std::string SOUND_DEF_LABEL = "Sound Track";
+
+//
+Result_t
+PCM_ADesc_to_MD(PCM::AudioDescriptor& ADesc, MXF::WaveAudioDescriptor* ADescObj)
+{
+ ASDCP_TEST_NULL(ADescObj);
+ ADescObj->SampleRate = ADesc.EditRate;
+ ADescObj->AudioSamplingRate = ADesc.AudioSamplingRate;
+ ADescObj->Locked = ADesc.Locked;
+ ADescObj->ChannelCount = ADesc.ChannelCount;
+ ADescObj->QuantizationBits = ADesc.QuantizationBits;
+ ADescObj->BlockAlign = ADesc.BlockAlign;
+ ADescObj->AvgBps = ADesc.AvgBps;
+ ADescObj->LinkedTrackID = ADesc.LinkedTrackID;
+ ADescObj->ContainerDuration = ADesc.ContainerDuration;
+
+ ADescObj->ChannelAssignment.Reset();
+
+ switch ( ADesc.ChannelFormat )
+ {
+ case PCM::CF_CFG_1:
+ ADescObj->ChannelAssignment = DefaultSMPTEDict().Type(MDD_DCAudioChannelCfg_1_5p1).ul;
+ break;
+
+ case PCM::CF_CFG_2:
+ ADescObj->ChannelAssignment = DefaultSMPTEDict().Type(MDD_DCAudioChannelCfg_2_6p1).ul;
+ break;
+
+ case PCM::CF_CFG_3:
+ ADescObj->ChannelAssignment = DefaultSMPTEDict().Type(MDD_DCAudioChannelCfg_3_7p1).ul;
+ break;
+
+ case PCM::CF_CFG_4:
+ ADescObj->ChannelAssignment = DefaultSMPTEDict().Type(MDD_DCAudioChannelCfg_4_WTF).ul;
+ break;
+
+ case PCM::CF_CFG_5:
+ ADescObj->ChannelAssignment = DefaultSMPTEDict().Type(MDD_DCAudioChannelCfg_5_7p1_DS).ul;
+ break;
+
+ case PCM::CF_NONE:
+ /* Keep gcc quiet */
+ break;
+ }
+
+ return RESULT_OK;
+}
+
+//
+ASDCP::Result_t
+MD_to_PCM_ADesc(MXF::WaveAudioDescriptor* ADescObj, PCM::AudioDescriptor& ADesc)
+{
+ ASDCP_TEST_NULL(ADescObj);
+ ADesc.EditRate = ADescObj->SampleRate;
+ ADesc.AudioSamplingRate = ADescObj->AudioSamplingRate;
+ ADesc.Locked = ADescObj->Locked;
+ ADesc.ChannelCount = ADescObj->ChannelCount;
+ ADesc.QuantizationBits = ADescObj->QuantizationBits;
+ ADesc.BlockAlign = ADescObj->BlockAlign;
+ ADesc.AvgBps = ADescObj->AvgBps;
+ ADesc.LinkedTrackID = ADescObj->LinkedTrackID;
+ assert(ADescObj->ContainerDuration <= 0xFFFFFFFFL);
+ ADesc.ContainerDuration = (ui32_t) ADescObj->ContainerDuration;
+
+ ADesc.ChannelFormat = PCM::CF_NONE;
+
+ if ( ADescObj->ChannelAssignment.HasValue() )
+ {
+ if ( ADescObj->ChannelAssignment == DefaultSMPTEDict().Type(MDD_DCAudioChannelCfg_1_5p1).ul )
+ ADesc.ChannelFormat = PCM::CF_CFG_1;
+
+ else if ( ADescObj->ChannelAssignment == DefaultSMPTEDict().Type(MDD_DCAudioChannelCfg_2_6p1).ul )
+ ADesc.ChannelFormat = PCM::CF_CFG_2;
+
+ else if ( ADescObj->ChannelAssignment == DefaultSMPTEDict().Type(MDD_DCAudioChannelCfg_3_7p1).ul )
+ ADesc.ChannelFormat = PCM::CF_CFG_3;
+
+ else if ( ADescObj->ChannelAssignment == DefaultSMPTEDict().Type(MDD_DCAudioChannelCfg_4_WTF).ul )
+ ADesc.ChannelFormat = PCM::CF_CFG_4;
+
+ else if ( ADescObj->ChannelAssignment == DefaultSMPTEDict().Type(MDD_DCAudioChannelCfg_5_7p1_DS).ul )
+ ADesc.ChannelFormat = PCM::CF_CFG_5;
+ }
+
+ return RESULT_OK;
+}
+
+//
+std::ostream&
+ASDCP::PCM::operator << (std::ostream& strm, const AudioDescriptor& ADesc)
+{
+ strm << " SampleRate: " << ADesc.EditRate.Numerator << "/" << ADesc.EditRate.Denominator << std::endl;
+ strm << " AudioSamplingRate: " << ADesc.AudioSamplingRate.Numerator << "/" << ADesc.AudioSamplingRate.Denominator << std::endl;
+ strm << " Locked: " << (unsigned) ADesc.Locked << std::endl;
+ strm << " ChannelCount: " << (unsigned) ADesc.ChannelCount << std::endl;
+ strm << " QuantizationBits: " << (unsigned) ADesc.QuantizationBits << std::endl;
+ strm << " BlockAlign: " << (unsigned) ADesc.BlockAlign << std::endl;
+ strm << " AvgBps: " << (unsigned) ADesc.AvgBps << std::endl;
+ strm << " LinkedTrackID: " << (unsigned) ADesc.LinkedTrackID << std::endl;
+ strm << " ContainerDuration: " << (unsigned) ADesc.ContainerDuration << std::endl;
+
+ return strm;
+}
+
+//
+void
+ASDCP::PCM::AudioDescriptorDump(const AudioDescriptor& ADesc, FILE* stream)
+{
+ if ( stream == 0 )
+ stream = stderr;
+
+ fprintf(stream, "\
+ EditRate: %d/%d\n\
+ AudioSamplingRate: %d/%d\n\
+ Locked: %u\n\
+ ChannelCount: %u\n\
+ QuantizationBits: %u\n\
+ BlockAlign: %u\n\
+ AvgBps: %u\n\
+ LinkedTrackID: %u\n\
+ ContainerDuration: %u\n",
+ ADesc.EditRate.Numerator, ADesc.EditRate.Denominator,
+ ADesc.AudioSamplingRate.Numerator, ADesc.AudioSamplingRate.Denominator,
+ ADesc.Locked,
+ ADesc.ChannelCount,
+ ADesc.QuantizationBits,
+ ADesc.BlockAlign,
+ ADesc.AvgBps,
+ ADesc.LinkedTrackID,
+ ADesc.ContainerDuration
+ );
+}
+
+
+//
+//
+static ui32_t
+calc_CBR_frame_size(ASDCP::WriterInfo& Info, const ASDCP::PCM::AudioDescriptor& ADesc)
+{
+ ui32_t CBR_frame_size = 0;
+
+ if ( Info.EncryptedEssence )
+ {
+ CBR_frame_size =
+ SMPTE_UL_LENGTH
+ + MXF_BER_LENGTH
+ + klv_cryptinfo_size
+ + calc_esv_length(ASDCP::PCM::CalcFrameBufferSize(ADesc), 0)
+ + ( Info.UsesHMAC ? klv_intpack_size : (MXF_BER_LENGTH * 3) );
+ }
+ else
+ {
+ CBR_frame_size = ASDCP::PCM::CalcFrameBufferSize(ADesc) + SMPTE_UL_LENGTH + MXF_BER_LENGTH;
+ }
+
+ return CBR_frame_size;
+}
+
+
+//------------------------------------------------------------------------------------------
+
+
+class ASDCP::PCM::MXFReader::h__Reader : public ASDCP::h__Reader
+{
+ ASDCP_NO_COPY_CONSTRUCT(h__Reader);
+ h__Reader();
+
+public:
+ AudioDescriptor m_ADesc;
+
+ h__Reader(const Dictionary& d) : ASDCP::h__Reader(d) {}
+ ~h__Reader() {}
+ Result_t OpenRead(const char*);
+ Result_t ReadFrame(ui32_t, FrameBuffer&, AESDecContext*, HMACContext*);
+};
+
+
+//
+//
+ASDCP::Result_t
+ASDCP::PCM::MXFReader::h__Reader::OpenRead(const char* filename)
+{
+ Result_t result = OpenMXFRead(filename);
+
+ if( ASDCP_SUCCESS(result) )
+ {
+ InterchangeObject* Object;
+ if ( ASDCP_SUCCESS(m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(WaveAudioDescriptor), &Object)) )
+ {
+ assert(Object);
+ result = MD_to_PCM_ADesc((MXF::WaveAudioDescriptor*)Object, m_ADesc);
+ }
+ }
+
+ /* This check has been removed so that DCP-o-matic can use any edit rate
+ it wants.
+ */
+#if 0
+ // check for sample/frame rate sanity
+ if ( ASDCP_SUCCESS(result)
+ && m_ADesc.EditRate != EditRate_24
+ && m_ADesc.EditRate != EditRate_25
+ && m_ADesc.EditRate != EditRate_30
+ && m_ADesc.EditRate != EditRate_48
+ && m_ADesc.EditRate != EditRate_50
+ && m_ADesc.EditRate != EditRate_60
+ && m_ADesc.EditRate != EditRate_96
+ && m_ADesc.EditRate != EditRate_100
+ && m_ADesc.EditRate != EditRate_120
+ && m_ADesc.EditRate != EditRate_23_98 )
+ {
+ DefaultLogSink().Error("PCM file EditRate is not a supported value: %d/%d\n", // lu
+ m_ADesc.EditRate.Numerator, m_ADesc.EditRate.Denominator);
+
+ // oh, they gave us the audio sampling rate instead, assume 24/1
+ if ( m_ADesc.EditRate == SampleRate_48k )
+ {
+ DefaultLogSink().Warn("adjusting EditRate to 24/1\n");
+ m_ADesc.EditRate = EditRate_24;
+ }
+ else
+ {
+ // or we just drop the hammer
+ return RESULT_FORMAT;
+ }
+ }
+#endif
+
+ if( ASDCP_SUCCESS(result) )
+ result = InitMXFIndex();
+
+ if( ASDCP_SUCCESS(result) )
+ result = InitInfo();
+
+ // TODO: test file for sane CBR index BytesPerEditUnit
+
+ return result;
+}
+
+
+//
+//
+ASDCP::Result_t
+ASDCP::PCM::MXFReader::h__Reader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
+ AESDecContext* Ctx, HMACContext* HMAC)
+{
+ if ( ! m_File.IsOpen() )
+ return RESULT_INIT;
+
+ assert(m_Dict);
+ return ReadEKLVFrame(FrameNum, FrameBuf, m_Dict->ul(MDD_WAVEssence), Ctx, HMAC);
+}
+
+//------------------------------------------------------------------------------------------
+
+
+//
+void
+ASDCP::PCM::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
+{
+ if ( stream == 0 )
+ stream = stderr;
+
+ fprintf(stream, "Frame: %06u, %7u bytes\n",
+ m_FrameNumber, m_Size);
+
+ if ( dump_len )
+ Kumu::hexdump(m_Data, dump_len, stream);
+}
+
+//------------------------------------------------------------------------------------------
+
+ASDCP::PCM::MXFReader::MXFReader()
+{
+ m_Reader = new h__Reader(DefaultCompositeDict());
+}
+
+
+ASDCP::PCM::MXFReader::~MXFReader()
+{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ m_Reader->Close();
+}
+
+// Warning: direct manipulation of MXF structures can interfere
+// with the normal operation of the wrapper. Caveat emptor!
+//
+ASDCP::MXF::OPAtomHeader&
+ASDCP::PCM::MXFReader::OPAtomHeader()
+{
+ if ( m_Reader.empty() )
+ {
+ assert(g_OPAtomHeader);
+ return *g_OPAtomHeader;
+ }
+
+ return m_Reader->m_HeaderPart;
+}
+
+// Warning: direct manipulation of MXF structures can interfere
+// with the normal operation of the wrapper. Caveat emptor!
+//
+ASDCP::MXF::OPAtomIndexFooter&
+ASDCP::PCM::MXFReader::OPAtomIndexFooter()
+{
+ if ( m_Reader.empty() )
+ {
+ assert(g_OPAtomIndexFooter);
+ return *g_OPAtomIndexFooter;
+ }
+
+ return m_Reader->m_FooterPart;
+}
+
+// Open the file for reading. The file must exist. Returns error if the
+// operation cannot be completed.
+ASDCP::Result_t
+ASDCP::PCM::MXFReader::OpenRead(const char* filename) const
+{
+ return m_Reader->OpenRead(filename);
+}
+
+// Reads a frame of essence from the MXF file. If the optional AESEncContext
+// argument is present, the essence is decrypted after reading. If the MXF
+// file is encrypted and the AESDecContext argument is NULL, the frame buffer
+// will contain the ciphertext frame data.
+ASDCP::Result_t
+ASDCP::PCM::MXFReader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
+ AESDecContext* Ctx, HMACContext* HMAC) const
+{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC);
+
+ return RESULT_INIT;
+}
+
+
+// Fill the struct with the values from the file's header.
+// Returns RESULT_INIT if the file is not open.
+ASDCP::Result_t
+ASDCP::PCM::MXFReader::FillAudioDescriptor(AudioDescriptor& ADesc) const
+{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ {
+ ADesc = m_Reader->m_ADesc;
+ return RESULT_OK;
+ }
+
+ return RESULT_INIT;
+}
+
+// Fill the struct with the values from the file's header.
+// Returns RESULT_INIT if the file is not open.
+ASDCP::Result_t
+ASDCP::PCM::MXFReader::FillWriterInfo(WriterInfo& Info) const
+{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ {
+ Info = m_Reader->m_Info;
+ return RESULT_OK;
+ }
+
+ return RESULT_INIT;
+}
+
+//
+void
+ASDCP::PCM::MXFReader::DumpHeaderMetadata(FILE* stream) const
+{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ m_Reader->m_HeaderPart.Dump(stream);
+}
+
+
+//
+void
+ASDCP::PCM::MXFReader::DumpIndex(FILE* stream) const
+{
+ if ( m_Reader->m_File.IsOpen() )
+ m_Reader->m_FooterPart.Dump(stream);
+}
+
+//
+ASDCP::Result_t
+ASDCP::PCM::MXFReader::Close() const
+{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ {
+ m_Reader->Close();
+ return RESULT_OK;
+ }
+
+ return RESULT_INIT;
+}
+
+
+//------------------------------------------------------------------------------------------
+
+//
+class ASDCP::PCM::MXFWriter::h__Writer : public ASDCP::h__Writer
+{
+ ASDCP_NO_COPY_CONSTRUCT(h__Writer);
+ h__Writer();
+
+public:
+ AudioDescriptor m_ADesc;
+ byte_t m_EssenceUL[SMPTE_UL_LENGTH];
+
+ h__Writer(const Dictionary& d) : ASDCP::h__Writer(d) {
+ memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
+ }
+
+ ~h__Writer(){}
+
+ Result_t OpenWrite(const char*, ui32_t HeaderSize);
+ Result_t SetSourceStream(const AudioDescriptor&);
+ Result_t WriteFrame(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0);
+ Result_t Finalize();
+};
+
+
+
+// Open the file for writing. The file must not exist. Returns error if
+// the operation cannot be completed.
+ASDCP::Result_t
+ASDCP::PCM::MXFWriter::h__Writer::OpenWrite(const char* filename, ui32_t HeaderSize)
+{
+ if ( ! m_State.Test_BEGIN() )
+ return RESULT_STATE;
+
+ Result_t result = m_File.OpenWrite(filename);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ m_HeaderSize = HeaderSize;
+ m_EssenceDescriptor = new WaveAudioDescriptor(m_Dict);
+ result = m_State.Goto_INIT();
+ }
+
+ return result;
+}
+
+
+// Automatically sets the MXF file's metadata from the WAV parser info.
+ASDCP::Result_t
+ASDCP::PCM::MXFWriter::h__Writer::SetSourceStream(const AudioDescriptor& ADesc)
+{
+ if ( ! m_State.Test_INIT() )
+ return RESULT_STATE;
+
+#if 0
+ /* This check has been removed so that DCP-o-matic can use anye dit rate
+ it wants.
+ */
+ if ( ADesc.EditRate != EditRate_24
+ && ADesc.EditRate != EditRate_25
+ && ADesc.EditRate != EditRate_30
+ && ADesc.EditRate != EditRate_48
+ && ADesc.EditRate != EditRate_50
+ && ADesc.EditRate != EditRate_60
+ && ADesc.EditRate != EditRate_96
+ && ADesc.EditRate != EditRate_100
+ && ADesc.EditRate != EditRate_120
+ && ADesc.EditRate != EditRate_23_98 )
+ {
+ DefaultLogSink().Error("AudioDescriptor.EditRate is not a supported value: %d/%d\n",
+ ADesc.EditRate.Numerator, ADesc.EditRate.Denominator);
+ return RESULT_RAW_FORMAT;
+ }
+#endif
+
+ if ( ADesc.AudioSamplingRate != SampleRate_48k && ADesc.AudioSamplingRate != SampleRate_96k )
+ {
+ DefaultLogSink().Error("AudioDescriptor.AudioSamplingRate is not 48000/1 or 96000/1: %d/%d\n",
+ ADesc.AudioSamplingRate.Numerator, ADesc.AudioSamplingRate.Denominator);
+ return RESULT_RAW_FORMAT;
+ }
+
+ assert(m_Dict);
+ m_ADesc = ADesc;
+
+ Result_t result = PCM_ADesc_to_MD(m_ADesc, (WaveAudioDescriptor*)m_EssenceDescriptor);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ memcpy(m_EssenceUL, m_Dict->ul(MDD_WAVEssence), SMPTE_UL_LENGTH);
+ m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
+ result = m_State.Goto_READY();
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ ui32_t TCFrameRate = ( m_ADesc.EditRate == EditRate_23_98 ) ? 24 : m_ADesc.EditRate.Numerator;
+
+ result = WriteMXFHeader(PCM_PACKAGE_LABEL, UL(m_Dict->ul(MDD_WAVWrapping)),
+ SOUND_DEF_LABEL, UL(m_EssenceUL), UL(m_Dict->ul(MDD_SoundDataDef)),
+ m_ADesc.EditRate, TCFrameRate, calc_CBR_frame_size(m_Info, m_ADesc));
+ }
+
+ return result;
+}
+
+
+//
+//
+ASDCP::Result_t
+ASDCP::PCM::MXFWriter::h__Writer::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx,
+ HMACContext* HMAC)
+{
+ Result_t result = RESULT_OK;
+
+ if ( m_State.Test_READY() )
+ result = m_State.Goto_RUNNING(); // first time through
+
+ if ( ASDCP_SUCCESS(result) )
+ result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC);
+
+ if ( ASDCP_SUCCESS(result) )
+ m_FramesWritten++;
+
+ return result;
+}
+
+// Closes the MXF file, writing the index and other closing information.
+//
+ASDCP::Result_t
+ASDCP::PCM::MXFWriter::h__Writer::Finalize()
+{
+ if ( ! m_State.Test_RUNNING() )
+ return RESULT_STATE;
+
+ m_State.Goto_FINAL();
+
+ return WriteMXFFooter();
+}
+
+
+//------------------------------------------------------------------------------------------
+//
+
+
+
+ASDCP::PCM::MXFWriter::MXFWriter()
+{
+}
+
+ASDCP::PCM::MXFWriter::~MXFWriter()
+{
+}
+
+// Warning: direct manipulation of MXF structures can interfere
+// with the normal operation of the wrapper. Caveat emptor!
+//
+ASDCP::MXF::OPAtomHeader&
+ASDCP::PCM::MXFWriter::OPAtomHeader()
+{
+ if ( m_Writer.empty() )
+ {
+ assert(g_OPAtomHeader);
+ return *g_OPAtomHeader;
+ }
+
+ return m_Writer->m_HeaderPart;
+}
+
+// Warning: direct manipulation of MXF structures can interfere
+// with the normal operation of the wrapper. Caveat emptor!
+//
+ASDCP::MXF::OPAtomIndexFooter&
+ASDCP::PCM::MXFWriter::OPAtomIndexFooter()
+{
+ if ( m_Writer.empty() )
+ {
+ assert(g_OPAtomIndexFooter);
+ return *g_OPAtomIndexFooter;
+ }
+
+ return m_Writer->m_FooterPart;
+}
+
+// Open the file for writing. The file must not exist. Returns error if
+// the operation cannot be completed.
+ASDCP::Result_t
+ASDCP::PCM::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info,
+ const AudioDescriptor& ADesc, ui32_t HeaderSize)
+{
+ if ( Info.LabelSetType == LS_MXF_SMPTE )
+ m_Writer = new h__Writer(DefaultSMPTEDict());
+ else
+ m_Writer = new h__Writer(DefaultInteropDict());
+
+ m_Writer->m_Info = Info;
+
+ Result_t result = m_Writer->OpenWrite(filename, HeaderSize);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = m_Writer->SetSourceStream(ADesc);
+
+ if ( ASDCP_FAILURE(result) )
+ m_Writer.release();
+
+ return result;
+}
+
+// Writes a frame of essence to the MXF file. If the optional AESEncContext
+// argument is present, the essence is encrypted prior to writing.
+// Fails if the file is not open, is finalized, or an operating system
+// error occurs.
+ASDCP::Result_t
+ASDCP::PCM::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
+{
+ if ( m_Writer.empty() )
+ return RESULT_INIT;
+
+ return m_Writer->WriteFrame(FrameBuf, Ctx, HMAC);
+}
+
+// Closes the MXF file, writing the index and other closing information.
+ASDCP::Result_t
+ASDCP::PCM::MXFWriter::Finalize()
+{
+ if ( m_Writer.empty() )
+ return RESULT_INIT;
+
+ return m_Writer->Finalize();
+}
+
+//
+// end AS_DCP_PCM.cpp
+//
+
diff --git a/asdcplib/src/AS_DCP_TimedText.cpp b/asdcplib/src/AS_DCP_TimedText.cpp
new file mode 100644
index 0000000..98ecce1
--- /dev/null
+++ b/asdcplib/src/AS_DCP_TimedText.cpp
@@ -0,0 +1,770 @@
+/*
+Copyright (c) 2008-2012, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file AS_DCP_TimedText.cpp
+ \version $Id: AS_DCP_TimedText.cpp,v 1.26 2012/02/07 18:54:25 jhurst Exp $
+ \brief AS-DCP library, PCM essence reader and writer implementation
+*/
+
+
+#include "AS_DCP_internal.h"
+#include "KM_xml.h"
+#include <iostream>
+#include <iomanip>
+
+using Kumu::GenRandomValue;
+
+static std::string TIMED_TEXT_PACKAGE_LABEL = "File Package: SMPTE 429-5 clip wrapping of D-Cinema Timed Text data";
+static std::string TIMED_TEXT_DEF_LABEL = "Timed Text Track";
+
+
+//------------------------------------------------------------------------------------------
+
+const char*
+MIME2str(TimedText::MIMEType_t m)
+{
+ if ( m == TimedText::MT_PNG )
+ return "image/png";
+
+ else if ( m == TimedText::MT_OPENTYPE )
+ return "application/x-font-opentype";
+
+ return "application/octet-stream";
+}
+
+//
+std::ostream&
+ASDCP::TimedText::operator << (std::ostream& strm, const TimedTextDescriptor& TDesc)
+{
+ UUID TmpID(TDesc.AssetID);
+ char buf[64];
+
+ strm << " EditRate: " << (unsigned) TDesc.EditRate.Numerator << "/" << (unsigned) TDesc.EditRate.Denominator << std::endl;
+ strm << "ContainerDuration: " << (unsigned) TDesc.ContainerDuration << std::endl;
+ strm << " AssetID: " << TmpID.EncodeHex(buf, 64) << std::endl;
+ strm << " NamespaceName: " << TDesc.NamespaceName << std::endl;
+ strm << " ResourceCount: " << (unsigned long) TDesc.ResourceList.size() << std::endl;
+
+ TimedText::ResourceList_t::const_iterator ri;
+ for ( ri = TDesc.ResourceList.begin() ; ri != TDesc.ResourceList.end(); ri++ )
+ {
+ TmpID.Set((*ri).ResourceID);
+ strm << " " << TmpID.EncodeHex(buf, 64) << ": " << MIME2str((*ri).Type) << std::endl;
+ }
+
+ return strm;
+}
+
+//
+void
+ASDCP::TimedText::DescriptorDump(ASDCP::TimedText::TimedTextDescriptor const& TDesc, FILE* stream)
+{
+ if ( stream == 0 )
+ stream = stderr;
+
+ UUID TmpID(TDesc.AssetID);
+ char buf[64];
+
+ fprintf(stream, " EditRate: %u/%u\n", TDesc.EditRate.Numerator, TDesc.EditRate.Denominator);
+ fprintf(stream, "ContainerDuration: %u\n", TDesc.ContainerDuration);
+ fprintf(stream, " AssetID: %s\n", TmpID.EncodeHex(buf, 64));
+ fprintf(stream, " NamespaceName: %s\n", TDesc.NamespaceName.c_str());
+ fprintf(stream, " ResourceCount: %zu\n", TDesc.ResourceList.size());
+
+ TimedText::ResourceList_t::const_iterator ri;
+ for ( ri = TDesc.ResourceList.begin() ; ri != TDesc.ResourceList.end(); ri++ )
+ {
+ TmpID.Set((*ri).ResourceID);
+ fprintf(stream, " %s: %s\n",
+ TmpID.EncodeHex(buf, 64),
+ MIME2str((*ri).Type));
+ }
+}
+
+//
+void
+ASDCP::TimedText::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
+{
+ if ( stream == 0 )
+ stream = stderr;
+
+ UUID TmpID(m_AssetID);
+ char buf[64];
+ fprintf(stream, "%s | %s | %u\n", TmpID.EncodeHex(buf, 64), m_MIMEType.c_str(), Size());
+
+ if ( dump_len > 0 )
+ Kumu::hexdump(m_Data, dump_len, stream);
+}
+
+//------------------------------------------------------------------------------------------
+
+typedef std::map<UUID, UUID> ResourceMap_t;
+
+class ASDCP::TimedText::MXFReader::h__Reader : public ASDCP::h__Reader
+{
+ MXF::TimedTextDescriptor* m_EssenceDescriptor;
+ ResourceMap_t m_ResourceMap;
+
+ ASDCP_NO_COPY_CONSTRUCT(h__Reader);
+
+public:
+ TimedTextDescriptor m_TDesc;
+
+ h__Reader(const Dictionary& d) : ASDCP::h__Reader(d), m_EssenceDescriptor(0) {
+ memset(&m_TDesc.AssetID, 0, UUIDlen);
+ }
+
+ Result_t OpenRead(const char*);
+ Result_t MD_to_TimedText_TDesc(TimedText::TimedTextDescriptor& TDesc);
+ Result_t ReadTimedTextResource(FrameBuffer& FrameBuf, AESDecContext* Ctx, HMACContext* HMAC);
+ Result_t ReadAncillaryResource(const byte_t*, FrameBuffer& FrameBuf, AESDecContext* Ctx, HMACContext* HMAC);
+};
+
+//
+ASDCP::Result_t
+ASDCP::TimedText::MXFReader::h__Reader::MD_to_TimedText_TDesc(TimedText::TimedTextDescriptor& TDesc)
+{
+ assert(m_EssenceDescriptor);
+ memset(&m_TDesc.AssetID, 0, UUIDlen);
+ MXF::TimedTextDescriptor* TDescObj = (MXF::TimedTextDescriptor*)m_EssenceDescriptor;
+
+ TDesc.EditRate = TDescObj->SampleRate;
+ assert(TDescObj->ContainerDuration <= 0xFFFFFFFFL);
+ TDesc.ContainerDuration = (ui32_t) TDescObj->ContainerDuration;
+ memcpy(TDesc.AssetID, TDescObj->ResourceID.Value(), UUIDlen);
+ TDesc.NamespaceName = TDescObj->NamespaceURI;
+ TDesc.EncodingName = TDescObj->UCSEncoding;
+
+ Batch<UUID>::const_iterator sdi = TDescObj->SubDescriptors.begin();
+ TimedTextResourceSubDescriptor* DescObject = 0;
+ Result_t result = RESULT_OK;
+
+ for ( ; sdi != TDescObj->SubDescriptors.end() && KM_SUCCESS(result); sdi++ )
+ {
+ InterchangeObject* tmp_iobj = 0;
+ result = m_HeaderPart.GetMDObjectByID(*sdi, &tmp_iobj);
+ DescObject = static_cast<TimedTextResourceSubDescriptor*>(tmp_iobj);
+
+ if ( KM_SUCCESS(result) )
+ {
+ TimedTextResourceDescriptor TmpResource;
+ memcpy(TmpResource.ResourceID, DescObject->AncillaryResourceID.Value(), UUIDlen);
+
+ if ( DescObject->MIMEMediaType.find("application/x-font-opentype") != std::string::npos
+ || DescObject->MIMEMediaType.find("application/x-opentype") != std::string::npos
+ || DescObject->MIMEMediaType.find("font/opentype") != std::string::npos )
+ TmpResource.Type = MT_OPENTYPE;
+
+ else if ( DescObject->MIMEMediaType.find("image/png") != std::string::npos )
+ TmpResource.Type = MT_PNG;
+
+ else
+ TmpResource.Type = MT_BIN;
+
+ TDesc.ResourceList.push_back(TmpResource);
+ m_ResourceMap.insert(ResourceMap_t::value_type(DescObject->AncillaryResourceID, *sdi));
+ }
+ else
+ {
+ DefaultLogSink().Error("Broken sub-descriptor link\n");
+ return RESULT_FORMAT;
+ }
+ }
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::TimedText::MXFReader::h__Reader::OpenRead(char const* filename)
+{
+ Result_t result = OpenMXFRead(filename);
+
+ if( ASDCP_SUCCESS(result) )
+ {
+ if ( m_EssenceDescriptor == 0 )
+ {
+ InterchangeObject* tmp_iobj = 0;
+ result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(TimedTextDescriptor), &tmp_iobj);
+ m_EssenceDescriptor = static_cast<MXF::TimedTextDescriptor*>(tmp_iobj);
+ }
+
+ if( ASDCP_SUCCESS(result) )
+ result = MD_to_TimedText_TDesc(m_TDesc);
+ }
+
+ if( ASDCP_SUCCESS(result) )
+ result = InitMXFIndex();
+
+ if( ASDCP_SUCCESS(result) )
+ result = InitInfo();
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::TimedText::MXFReader::h__Reader::ReadTimedTextResource(FrameBuffer& FrameBuf,
+ AESDecContext* Ctx, HMACContext* HMAC)
+{
+ if ( ! m_File.IsOpen() )
+ return RESULT_INIT;
+
+ assert(m_Dict);
+ Result_t result = ReadEKLVFrame(0, FrameBuf, m_Dict->ul(MDD_TimedTextEssence), Ctx, HMAC);
+
+ if( ASDCP_SUCCESS(result) )
+ {
+ FrameBuf.AssetID(m_TDesc.AssetID);
+ FrameBuf.MIMEType("text/xml");
+ }
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::TimedText::MXFReader::h__Reader::ReadAncillaryResource(const byte_t* uuid, FrameBuffer& FrameBuf,
+ AESDecContext* Ctx, HMACContext* HMAC)
+{
+ KM_TEST_NULL_L(uuid);
+ UUID RID(uuid);
+
+ ResourceMap_t::const_iterator ri = m_ResourceMap.find(RID);
+ if ( ri == m_ResourceMap.end() )
+ {
+ char buf[64];
+ DefaultLogSink().Error("No such resource: %s\n", RID.EncodeHex(buf, 64));
+ return RESULT_RANGE;
+ }
+
+ TimedTextResourceSubDescriptor* DescObject = 0;
+ // get the subdescriptor
+ InterchangeObject* tmp_iobj = 0;
+ Result_t result = m_HeaderPart.GetMDObjectByID((*ri).second, &tmp_iobj);
+ DescObject = static_cast<TimedTextResourceSubDescriptor*>(tmp_iobj);
+
+ if ( KM_SUCCESS(result) )
+ {
+ Array<RIP::Pair>::const_iterator pi;
+ RIP::Pair TmpPair;
+ ui32_t sequence = 1;
+
+ // Look up the partition start in the RIP using the SID.
+ // Count the sequence length in because this is the sequence
+ // value needed to complete the HMAC.
+ for ( pi = m_HeaderPart.m_RIP.PairArray.begin(); pi != m_HeaderPart.m_RIP.PairArray.end(); pi++, sequence++ )
+ {
+ if ( (*pi).BodySID == DescObject->EssenceStreamID )
+ {
+ TmpPair = *pi;
+ break;
+ }
+ }
+
+ if ( TmpPair.ByteOffset == 0 )
+ {
+ DefaultLogSink().Error("Body SID not found in RIP set: %d\n", DescObject->EssenceStreamID);
+ return RESULT_FORMAT;
+ }
+
+ if ( KM_SUCCESS(result) )
+ {
+ FrameBuf.AssetID(uuid);
+ FrameBuf.MIMEType(DescObject->MIMEMediaType);
+
+ // seek tp the start of the partition
+ if ( (Kumu::fpos_t)TmpPair.ByteOffset != m_LastPosition )
+ {
+ m_LastPosition = TmpPair.ByteOffset;
+ result = m_File.Seek(TmpPair.ByteOffset);
+ }
+
+ // read the partition header
+ MXF::Partition GSPart(m_Dict);
+ result = GSPart.InitFromFile(m_File);
+
+ if( ASDCP_SUCCESS(result) )
+ {
+ // check the SID
+ if ( DescObject->EssenceStreamID != GSPart.BodySID )
+ {
+ char buf[64];
+ DefaultLogSink().Error("Generic stream partition body differs: %s\n", RID.EncodeHex(buf, 64));
+ return RESULT_FORMAT;
+ }
+
+ // read the essence packet
+ assert(m_Dict);
+ if( ASDCP_SUCCESS(result) )
+ result = ReadEKLVPacket(0, 1, FrameBuf, m_Dict->ul(MDD_GenericStream_DataElement), Ctx, HMAC);
+ }
+ }
+ }
+
+ return result;
+}
+
+
+//------------------------------------------------------------------------------------------
+
+ASDCP::TimedText::MXFReader::MXFReader()
+{
+ m_Reader = new h__Reader(DefaultSMPTEDict());
+}
+
+
+ASDCP::TimedText::MXFReader::~MXFReader()
+{
+}
+
+// Warning: direct manipulation of MXF structures can interfere
+// with the normal operation of the wrapper. Caveat emptor!
+//
+ASDCP::MXF::OPAtomHeader&
+ASDCP::TimedText::MXFReader::OPAtomHeader()
+{
+ if ( m_Reader.empty() )
+ {
+ assert(g_OPAtomHeader);
+ return *g_OPAtomHeader;
+ }
+
+ return m_Reader->m_HeaderPart;
+}
+
+// Warning: direct manipulation of MXF structures can interfere
+// with the normal operation of the wrapper. Caveat emptor!
+//
+ASDCP::MXF::OPAtomIndexFooter&
+ASDCP::TimedText::MXFReader::OPAtomIndexFooter()
+{
+ if ( m_Reader.empty() )
+ {
+ assert(g_OPAtomIndexFooter);
+ return *g_OPAtomIndexFooter;
+ }
+
+ return m_Reader->m_FooterPart;
+}
+
+// Open the file for reading. The file must exist. Returns error if the
+// operation cannot be completed.
+ASDCP::Result_t
+ASDCP::TimedText::MXFReader::OpenRead(const char* filename) const
+{
+ return m_Reader->OpenRead(filename);
+}
+
+// Fill the struct with the values from the file's header.
+// Returns RESULT_INIT if the file is not open.
+ASDCP::Result_t
+ASDCP::TimedText::MXFReader::FillTimedTextDescriptor(TimedText::TimedTextDescriptor& TDesc) const
+{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ {
+ TDesc = m_Reader->m_TDesc;
+ return RESULT_OK;
+ }
+
+ return RESULT_INIT;
+}
+
+// Fill the struct with the values from the file's header.
+// Returns RESULT_INIT if the file is not open.
+ASDCP::Result_t
+ASDCP::TimedText::MXFReader::FillWriterInfo(WriterInfo& Info) const
+{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ {
+ Info = m_Reader->m_Info;
+ return RESULT_OK;
+ }
+
+ return RESULT_INIT;
+}
+
+//
+ASDCP::Result_t
+ASDCP::TimedText::MXFReader::ReadTimedTextResource(std::string& s, AESDecContext* Ctx, HMACContext* HMAC) const
+{
+ FrameBuffer FrameBuf(2*Kumu::Megabyte);
+
+ Result_t result = ReadTimedTextResource(FrameBuf, Ctx, HMAC);
+
+ if ( ASDCP_SUCCESS(result) )
+ s.assign((char*)FrameBuf.Data(), FrameBuf.Size());
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::TimedText::MXFReader::ReadTimedTextResource(FrameBuffer& FrameBuf,
+ AESDecContext* Ctx, HMACContext* HMAC) const
+{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ return m_Reader->ReadTimedTextResource(FrameBuf, Ctx, HMAC);
+
+ return RESULT_INIT;
+}
+
+//
+ASDCP::Result_t
+ASDCP::TimedText::MXFReader::ReadAncillaryResource(const byte_t* uuid, FrameBuffer& FrameBuf,
+ AESDecContext* Ctx, HMACContext* HMAC) const
+{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ return m_Reader->ReadAncillaryResource(uuid, FrameBuf, Ctx, HMAC);
+
+ return RESULT_INIT;
+}
+
+
+//
+void
+ASDCP::TimedText::MXFReader::DumpHeaderMetadata(FILE* stream) const
+{
+ if ( m_Reader->m_File.IsOpen() )
+ m_Reader->m_HeaderPart.Dump(stream);
+}
+
+
+//
+void
+ASDCP::TimedText::MXFReader::DumpIndex(FILE* stream) const
+{
+ if ( m_Reader->m_File.IsOpen() )
+ m_Reader->m_FooterPart.Dump(stream);
+}
+
+//
+ASDCP::Result_t
+ASDCP::TimedText::MXFReader::Close() const
+{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ {
+ m_Reader->Close();
+ return RESULT_OK;
+ }
+
+ return RESULT_INIT;
+}
+
+
+//------------------------------------------------------------------------------------------
+
+
+//
+class ASDCP::TimedText::MXFWriter::h__Writer : public ASDCP::h__Writer
+{
+ ASDCP_NO_COPY_CONSTRUCT(h__Writer);
+ h__Writer();
+
+public:
+ TimedTextDescriptor m_TDesc;
+ byte_t m_EssenceUL[SMPTE_UL_LENGTH];
+ ui32_t m_EssenceStreamID;
+
+ h__Writer(const Dictionary& d) : ASDCP::h__Writer(d), m_EssenceStreamID(10) {
+ memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
+ }
+
+ ~h__Writer(){}
+
+ Result_t OpenWrite(const char*, ui32_t HeaderSize);
+ Result_t SetSourceStream(const TimedTextDescriptor&);
+ Result_t WriteTimedTextResource(const std::string& XMLDoc, AESEncContext* = 0, HMACContext* = 0);
+ Result_t WriteAncillaryResource(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0);
+ Result_t Finalize();
+ Result_t TimedText_TDesc_to_MD(TimedText::TimedTextDescriptor& TDesc);
+};
+
+//
+ASDCP::Result_t
+ASDCP::TimedText::MXFWriter::h__Writer::TimedText_TDesc_to_MD(TimedText::TimedTextDescriptor& TDesc)
+{
+ assert(m_EssenceDescriptor);
+ MXF::TimedTextDescriptor* TDescObj = (MXF::TimedTextDescriptor*)m_EssenceDescriptor;
+
+ TDescObj->SampleRate = TDesc.EditRate;
+ TDescObj->ContainerDuration = TDesc.ContainerDuration;
+ TDescObj->ResourceID.Set(TDesc.AssetID);
+ TDescObj->NamespaceURI = TDesc.NamespaceName;
+ TDescObj->UCSEncoding = TDesc.EncodingName;
+
+ return RESULT_OK;
+}
+
+//
+ASDCP::Result_t
+ASDCP::TimedText::MXFWriter::h__Writer::OpenWrite(char const* filename, ui32_t HeaderSize)
+{
+ if ( ! m_State.Test_BEGIN() )
+ return RESULT_STATE;
+
+ Result_t result = m_File.OpenWrite(filename);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ m_HeaderSize = HeaderSize;
+ m_EssenceDescriptor = new MXF::TimedTextDescriptor(m_Dict);
+ result = m_State.Goto_INIT();
+ }
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::TimedText::MXFWriter::h__Writer::SetSourceStream(ASDCP::TimedText::TimedTextDescriptor const& TDesc)
+{
+ if ( ! m_State.Test_INIT() )
+ return RESULT_STATE;
+
+ m_TDesc = TDesc;
+ ResourceList_t::const_iterator ri;
+ Result_t result = TimedText_TDesc_to_MD(m_TDesc);
+
+ for ( ri = m_TDesc.ResourceList.begin() ; ri != m_TDesc.ResourceList.end() && ASDCP_SUCCESS(result); ri++ )
+ {
+ TimedTextResourceSubDescriptor* resourceSubdescriptor = new TimedTextResourceSubDescriptor(m_Dict);
+ GenRandomValue(resourceSubdescriptor->InstanceUID);
+ resourceSubdescriptor->AncillaryResourceID.Set((*ri).ResourceID);
+ resourceSubdescriptor->MIMEMediaType = MIME2str((*ri).Type);
+ resourceSubdescriptor->EssenceStreamID = m_EssenceStreamID++;
+ m_EssenceSubDescriptorList.push_back((FileDescriptor*)resourceSubdescriptor);
+ m_EssenceDescriptor->SubDescriptors.push_back(resourceSubdescriptor->InstanceUID);
+ }
+
+ m_EssenceStreamID = 10;
+ assert(m_Dict);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ InitHeader();
+ AddDMSegment(m_TDesc.EditRate, 24, TIMED_TEXT_DEF_LABEL,
+ UL(m_Dict->ul(MDD_PictureDataDef)), TIMED_TEXT_PACKAGE_LABEL);
+
+ AddEssenceDescriptor(UL(m_Dict->ul(MDD_TimedTextWrapping)));
+
+ result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize);
+
+ if ( KM_SUCCESS(result) )
+ result = CreateBodyPart(m_TDesc.EditRate);
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ memcpy(m_EssenceUL, m_Dict->ul(MDD_TimedTextEssence), SMPTE_UL_LENGTH);
+ m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
+ result = m_State.Goto_READY();
+ }
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::TimedText::MXFWriter::h__Writer::WriteTimedTextResource(const std::string& XMLDoc,
+ ASDCP::AESEncContext* Ctx, ASDCP::HMACContext* HMAC)
+{
+ Result_t result = m_State.Goto_RUNNING();
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ // TODO: make sure it's XML
+
+ ui32_t str_size = XMLDoc.size();
+ FrameBuffer FrameBuf(str_size);
+
+ memcpy(FrameBuf.Data(), XMLDoc.c_str(), str_size);
+ FrameBuf.Size(str_size);
+
+ IndexTableSegment::IndexEntry Entry;
+ Entry.StreamOffset = m_StreamOffset;
+
+ if ( ASDCP_SUCCESS(result) )
+ result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ m_FooterPart.PushIndexEntry(Entry);
+ m_FramesWritten++;
+ }
+ }
+
+ return result;
+}
+
+
+//
+ASDCP::Result_t
+ASDCP::TimedText::MXFWriter::h__Writer::WriteAncillaryResource(const ASDCP::TimedText::FrameBuffer& FrameBuf,
+ ASDCP::AESEncContext* Ctx, ASDCP::HMACContext* HMAC)
+{
+ if ( ! m_State.Test_RUNNING() )
+ return RESULT_STATE;
+
+ Kumu::fpos_t here = m_File.Tell();
+ assert(m_Dict);
+
+ // create generic stream partition header
+ static UL GenericStream_DataElement(m_Dict->ul(MDD_GenericStream_DataElement));
+ MXF::Partition GSPart(m_Dict);
+
+ GSPart.ThisPartition = here;
+ GSPart.PreviousPartition = m_HeaderPart.m_RIP.PairArray.back().ByteOffset;
+ GSPart.BodySID = m_EssenceStreamID;
+ GSPart.OperationalPattern = m_HeaderPart.OperationalPattern;
+
+ m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(m_EssenceStreamID++, here));
+ GSPart.EssenceContainers.push_back(UL(m_Dict->ul(MDD_TimedTextEssence)));
+ UL TmpUL(m_Dict->ul(MDD_GenericStreamPartition));
+ Result_t result = GSPart.WriteToFile(m_File, TmpUL);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = WriteEKLVPacket(FrameBuf, GenericStream_DataElement.Value(), Ctx, HMAC);
+
+ m_FramesWritten++;
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::TimedText::MXFWriter::h__Writer::Finalize()
+{
+ if ( ! m_State.Test_RUNNING() )
+ return RESULT_STATE;
+
+ m_FramesWritten = m_TDesc.ContainerDuration;
+ m_State.Goto_FINAL();
+
+ return WriteMXFFooter();
+}
+
+
+//------------------------------------------------------------------------------------------
+
+ASDCP::TimedText::MXFWriter::MXFWriter()
+{
+}
+
+ASDCP::TimedText::MXFWriter::~MXFWriter()
+{
+}
+
+// Warning: direct manipulation of MXF structures can interfere
+// with the normal operation of the wrapper. Caveat emptor!
+//
+ASDCP::MXF::OPAtomHeader&
+ASDCP::TimedText::MXFWriter::OPAtomHeader()
+{
+ if ( m_Writer.empty() )
+ {
+ assert(g_OPAtomHeader);
+ return *g_OPAtomHeader;
+ }
+
+ return m_Writer->m_HeaderPart;
+}
+
+// Warning: direct manipulation of MXF structures can interfere
+// with the normal operation of the wrapper. Caveat emptor!
+//
+ASDCP::MXF::OPAtomIndexFooter&
+ASDCP::TimedText::MXFWriter::OPAtomIndexFooter()
+{
+ if ( m_Writer.empty() )
+ {
+ assert(g_OPAtomIndexFooter);
+ return *g_OPAtomIndexFooter;
+ }
+
+ return m_Writer->m_FooterPart;
+}
+
+// Open the file for writing. The file must not exist. Returns error if
+// the operation cannot be completed.
+ASDCP::Result_t
+ASDCP::TimedText::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info,
+ const TimedTextDescriptor& TDesc, ui32_t HeaderSize)
+{
+ if ( Info.LabelSetType != LS_MXF_SMPTE )
+ {
+ DefaultLogSink().Error("Timed Text support requires LS_MXF_SMPTE\n");
+ return RESULT_FORMAT;
+ }
+
+ m_Writer = new h__Writer(DefaultSMPTEDict());
+ m_Writer->m_Info = Info;
+
+ Result_t result = m_Writer->OpenWrite(filename, HeaderSize);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = m_Writer->SetSourceStream(TDesc);
+
+ if ( ASDCP_FAILURE(result) )
+ m_Writer.release();
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::TimedText::MXFWriter::WriteTimedTextResource(const std::string& XMLDoc, AESEncContext* Ctx, HMACContext* HMAC)
+{
+ if ( m_Writer.empty() )
+ return RESULT_INIT;
+
+ return m_Writer->WriteTimedTextResource(XMLDoc, Ctx, HMAC);
+}
+
+//
+ASDCP::Result_t
+ASDCP::TimedText::MXFWriter::WriteAncillaryResource(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
+{
+ if ( m_Writer.empty() )
+ return RESULT_INIT;
+
+ return m_Writer->WriteAncillaryResource(FrameBuf, Ctx, HMAC);
+}
+
+// Closes the MXF file, writing the index and other closing information.
+ASDCP::Result_t
+ASDCP::TimedText::MXFWriter::Finalize()
+{
+ if ( m_Writer.empty() )
+ return RESULT_INIT;
+
+ return m_Writer->Finalize();
+}
+
+
+
+//
+// end AS_DCP_timedText.cpp
+//
diff --git a/asdcplib/src/AS_DCP_internal.h b/asdcplib/src/AS_DCP_internal.h
new file mode 100755
index 0000000..73106a2
--- /dev/null
+++ b/asdcplib/src/AS_DCP_internal.h
@@ -0,0 +1,274 @@
+/*
+Copyright (c) 2004-2012, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file AS_DCP_internal.h
+ \version $Id: AS_DCP_internal.h,v 1.27 2012/02/07 18:54:25 jhurst Exp $
+ \brief AS-DCP library, non-public common elements
+*/
+
+#ifndef _AS_DCP_INTERNAL_H_
+#define _AS_DCP_INTERNAL_H_
+
+#include <KM_platform.h>
+#include <KM_util.h>
+#include <KM_log.h>
+#include "Metadata.h"
+
+using Kumu::DefaultLogSink;
+// using namespace std;
+using namespace ASDCP;
+using namespace ASDCP::MXF;
+
+#ifdef DEFAULT_MD_DECL
+ASDCP::MXF::OPAtomHeader *g_OPAtomHeader;
+ASDCP::MXF::OPAtomIndexFooter *g_OPAtomIndexFooter;
+#else
+extern MXF::OPAtomHeader *g_OPAtomHeader;
+extern MXF::OPAtomIndexFooter *g_OPAtomIndexFooter;
+#endif
+
+
+namespace ASDCP
+{
+ void default_md_object_init();
+
+
+ // constant values used to calculate KLV and EKLV packet sizes
+ static const ui32_t klv_cryptinfo_size =
+ MXF_BER_LENGTH
+ + UUIDlen /* ContextID */
+ + MXF_BER_LENGTH
+ + sizeof(ui64_t) /* PlaintextOffset */
+ + MXF_BER_LENGTH
+ + SMPTE_UL_LENGTH /* SourceKey */
+ + MXF_BER_LENGTH
+ + sizeof(ui64_t) /* SourceLength */
+ + MXF_BER_LENGTH /* ESV length */ ;
+
+ static const ui32_t klv_intpack_size =
+ MXF_BER_LENGTH
+ + UUIDlen /* TrackFileID */
+ + MXF_BER_LENGTH
+ + sizeof(ui64_t) /* SequenceNumber */
+ + MXF_BER_LENGTH
+ + 20; /* HMAC length*/
+
+ // calculate size of encrypted essence with IV, CheckValue, and padding
+ inline ui32_t
+ calc_esv_length(ui32_t source_length, ui32_t plaintext_offset)
+ {
+ ui32_t ct_size = source_length - plaintext_offset;
+ ui32_t diff = ct_size % CBC_BLOCK_SIZE;
+ ui32_t block_size = ct_size - diff;
+ return plaintext_offset + block_size + (CBC_BLOCK_SIZE * 3);
+ }
+
+ // the check value for EKLV packets
+ // CHUKCHUKCHUKCHUK
+ static const byte_t ESV_CheckValue[CBC_BLOCK_SIZE] =
+ { 0x43, 0x48, 0x55, 0x4b, 0x43, 0x48, 0x55, 0x4b,
+ 0x43, 0x48, 0x55, 0x4b, 0x43, 0x48, 0x55, 0x4b };
+
+ //------------------------------------------------------------------------------------------
+ //
+
+ Result_t MD_to_WriterInfo(MXF::Identification*, WriterInfo&);
+ Result_t MD_to_CryptoInfo(MXF::CryptographicContext*, WriterInfo&, const Dictionary&);
+ 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 byte_t* Key() { return m_KeyBuf; }
+ inline ui64_t Length() { return m_ValueLength; }
+ inline ui64_t KLLength() { return m_KLLength; }
+
+ Result_t ReadKLFromFile(Kumu::FileReader& Reader);
+ };
+
+ //
+ class h__Reader
+ {
+ ASDCP_NO_COPY_CONSTRUCT(h__Reader);
+ h__Reader();
+
+ public:
+ const Dictionary* m_Dict;
+ Kumu::FileReader m_File;
+ OPAtomHeader m_HeaderPart;
+ Partition m_BodyPart;
+ OPAtomIndexFooter m_FooterPart;
+ ui64_t m_EssenceStart;
+ WriterInfo m_Info;
+ ASDCP::FrameBuffer m_CtFrameBuf;
+ Kumu::fpos_t m_LastPosition;
+
+ h__Reader(const Dictionary&);
+ virtual ~h__Reader();
+
+ Result_t InitInfo();
+ Result_t OpenMXFRead(const char* filename);
+ Result_t InitMXFIndex();
+
+ // positions file before reading
+ Result_t ReadEKLVFrame(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf,
+ const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC);
+
+ // reads from current position
+ Result_t ReadEKLVPacket(ui32_t FrameNum, ui32_t SequenceNum, ASDCP::FrameBuffer& FrameBuf,
+ const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC);
+ void Close();
+ };
+
+
+ // state machine for mxf writer
+ enum WriterState_t {
+ ST_BEGIN, // waiting for Open()
+ ST_INIT, // waiting for SetSourceStream()
+ ST_READY, // ready to write frames
+ ST_RUNNING, // one or more frames written
+ ST_FINAL, // index written, file closed
+ };
+
+ // implementation of h__WriterState class Goto_* methods
+#define Goto_body(s1,s2) if ( m_State != (s1) ) \
+ return RESULT_STATE; \
+ m_State = (s2); \
+ return RESULT_OK
+ //
+ class h__WriterState
+ {
+ ASDCP_NO_COPY_CONSTRUCT(h__WriterState);
+
+ public:
+ WriterState_t m_State;
+ h__WriterState() : m_State(ST_BEGIN) {}
+ ~h__WriterState() {}
+
+ inline bool Test_BEGIN() { return m_State == ST_BEGIN; }
+ inline bool Test_INIT() { return m_State == ST_INIT; }
+ inline bool Test_READY() { return m_State == ST_READY;}
+ inline bool Test_RUNNING() { return m_State == ST_RUNNING; }
+ inline bool Test_FINAL() { return m_State == ST_FINAL; }
+ inline Result_t Goto_INIT() { Goto_body(ST_BEGIN, ST_INIT); }
+ inline Result_t Goto_READY() { Goto_body(ST_INIT, ST_READY); }
+ inline Result_t Goto_RUNNING() { Goto_body(ST_READY, ST_RUNNING); }
+ inline Result_t Goto_FINAL() { Goto_body(ST_RUNNING, ST_FINAL); }
+ };
+
+ typedef std::list<ui64_t*> DurationElementList_t;
+
+ //
+ class h__Writer
+ {
+ ASDCP_NO_COPY_CONSTRUCT(h__Writer);
+ h__Writer();
+
+ public:
+ const Dictionary* m_Dict;
+ Kumu::FileWriter m_File;
+ ui32_t m_HeaderSize;
+ OPAtomHeader m_HeaderPart;
+ Partition m_BodyPart;
+ OPAtomIndexFooter m_FooterPart;
+ ui64_t m_EssenceStart;
+
+ MaterialPackage* m_MaterialPackage;
+ SourcePackage* m_FilePackage;
+
+ FileDescriptor* m_EssenceDescriptor;
+ std::list<InterchangeObject*> m_EssenceSubDescriptorList;
+
+ ui32_t m_FramesWritten;
+ ui64_t m_StreamOffset;
+ ASDCP::FrameBuffer m_CtFrameBuf;
+ h__WriterState m_State;
+ WriterInfo m_Info;
+ DurationElementList_t m_DurationUpdateList;
+
+ h__Writer(const Dictionary&);
+ virtual ~h__Writer();
+
+ void InitHeader();
+ void AddSourceClip(const MXF::Rational& EditRate, ui32_t TCFrameRate,
+ const std::string& TrackName, const UL& EssenceUL,
+ const UL& DataDefinition, const std::string& PackageLabel);
+ void AddDMSegment(const MXF::Rational& EditRate, ui32_t TCFrameRate,
+ const std::string& TrackName, const UL& DataDefinition,
+ const std::string& PackageLabel);
+ void AddEssenceDescriptor(const UL& WrappingUL);
+ Result_t CreateBodyPart(const MXF::Rational& EditRate, ui32_t BytesPerEditUnit = 0);
+
+ // all the above for a single source clip
+ Result_t WriteMXFHeader(const std::string& PackageLabel, const UL& WrappingUL,
+ const std::string& TrackName, const UL& EssenceUL,
+ const UL& DataDefinition, const MXF::Rational& EditRate,
+ ui32_t TCFrameRate, ui32_t BytesPerEditUnit = 0);
+
+ Result_t WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf,
+ const byte_t* EssenceUL, AESEncContext* Ctx, HMACContext* HMAC, std::string* hash = 0);
+
+ Result_t FakeWriteEKLVPacket(int size);
+
+ Result_t WriteMXFFooter();
+
+ };
+
+
+ // helper class for calculating Integrity Packs, used by WriteEKLVPacket() below.
+ //
+ class IntegrityPack
+ {
+ public:
+ byte_t Data[klv_intpack_size];
+
+ IntegrityPack() {
+ memset(Data, 0, klv_intpack_size);
+ }
+
+ ~IntegrityPack() {}
+
+ Result_t CalcValues(const ASDCP::FrameBuffer&, byte_t* AssetID, ui32_t sequence, HMACContext* HMAC);
+ Result_t TestValues(const ASDCP::FrameBuffer&, byte_t* AssetID, ui32_t sequence, HMACContext* HMAC);
+ };
+
+
+} // namespace ASDCP
+
+#endif // _AS_DCP_INTERNAL_H_
+
+
+//
+// end AS_DCP_internal.h
+//
diff --git a/asdcplib/src/Dict.cpp b/asdcplib/src/Dict.cpp
new file mode 100755
index 0000000..c046aa7
--- /dev/null
+++ b/asdcplib/src/Dict.cpp
@@ -0,0 +1,321 @@
+/*
+Copyright (c) 2006-2009, 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 Dict.cpp
+ \version $Id: Dict.cpp,v 1.15 2012/02/08 02:59:21 jhurst Exp $
+ \brief MXF dictionary
+*/
+
+
+#include "KM_mutex.h"
+#include "KM_log.h"
+#include "KLV.h"
+#include "MDD.cpp"
+
+//------------------------------------------------------------------------------------------
+
+// The composite dict is the union of the SMPTE and Interop dicts
+//
+static ASDCP::Dictionary s_CompositeDict;
+static Kumu::Mutex s_CompositeDictLock;
+static bool s_CompositeDictInit = false;
+
+//
+const ASDCP::Dictionary&
+ASDCP::DefaultCompositeDict()
+{
+ if ( ! s_CompositeDictInit )
+ {
+ Kumu::AutoMutex AL(s_CompositeDictLock);
+
+ if ( ! s_CompositeDictInit )
+ {
+ s_CompositeDict.Init();
+ s_CompositeDictInit = true;
+ }
+ }
+
+ return s_CompositeDict;
+}
+
+//
+//
+static ASDCP::Dictionary s_InteropDict;
+static Kumu::Mutex s_InteropDictLock;
+static bool s_InteropDictInit = false;
+
+//
+const ASDCP::Dictionary&
+ASDCP::DefaultInteropDict()
+{
+ if ( ! s_InteropDictInit )
+ {
+ Kumu::AutoMutex AL(s_InteropDictLock);
+
+ if ( ! s_InteropDictInit )
+ {
+ s_InteropDict.Init();
+
+ s_InteropDict.DeleteEntry(MDD_MXFInterop_OPAtom);
+ s_InteropDict.DeleteEntry(MDD_MXFInterop_CryptEssence);
+ s_InteropDict.DeleteEntry(MDD_MXFInterop_GenericDescriptor_SubDescriptors);
+
+ s_InteropDict.AddEntry(s_MDD_Table[MDD_MXFInterop_OPAtom], MDD_OPAtom);
+ s_InteropDict.AddEntry(s_MDD_Table[MDD_MXFInterop_CryptEssence], MDD_CryptEssence);
+ s_InteropDict.AddEntry(s_MDD_Table[MDD_MXFInterop_GenericDescriptor_SubDescriptors],
+ MDD_GenericDescriptor_SubDescriptors);
+
+ s_InteropDictInit = true;
+ }
+ }
+
+ return s_InteropDict;
+}
+
+//
+//
+static ASDCP::Dictionary s_SMPTEDict;
+static Kumu::Mutex s_SMPTEDictLock;
+static bool s_SMPTEDictInit = false;
+
+//
+const ASDCP::Dictionary&
+ASDCP::DefaultSMPTEDict()
+{
+ if ( ! s_SMPTEDictInit )
+ {
+ Kumu::AutoMutex AL(s_SMPTEDictLock);
+
+ if ( ! s_SMPTEDictInit )
+ {
+ s_SMPTEDict.Init();
+
+ s_SMPTEDict.DeleteEntry(MDD_MXFInterop_OPAtom);
+ s_SMPTEDict.DeleteEntry(MDD_MXFInterop_CryptEssence);
+ s_SMPTEDict.DeleteEntry(MDD_MXFInterop_GenericDescriptor_SubDescriptors);
+
+ s_SMPTEDictInit = true;
+ }
+ }
+
+ return s_SMPTEDict;
+}
+
+//
+const ASDCP::MDDEntry&
+ASDCP::MXFInterop_OPAtom_Entry() {
+ return s_MDD_Table[MDD_MXFInterop_OPAtom];
+}
+
+//
+const ASDCP::MDDEntry&
+ASDCP::SMPTE_390_OPAtom_Entry() {
+ return s_MDD_Table[MDD_OPAtom];
+}
+
+
+//------------------------------------------------------------------------------------------
+//
+
+ASDCP::Dictionary::Dictionary() {}
+ASDCP::Dictionary::~Dictionary() {}
+
+//
+void
+ASDCP::Dictionary::Init()
+{
+ m_md_lookup.clear();
+ memset(m_MDD_Table, 0, sizeof(m_MDD_Table));
+
+ for ( ui32_t x = 0; x < (ui32_t)ASDCP::MDD_Max; x++ )
+ {
+ if ( x == MDD_PartitionMetadata_IndexSID_DEPRECATED // 30
+ || x == MDD_PartitionMetadata_BodySID_DEPRECATED // 32
+ || x == MDD_PartitionMetadata_EssenceContainers_DEPRECATED // 34
+ || x == MDD_IndexTableSegmentBase_IndexSID_DEPRECATED // 56
+ || x == MDD_IndexTableSegmentBase_BodySID_DEPRECATED // 57
+ || x == MDD_PartitionArray_RandomIndexMetadata_BodySID_DEPRECATED // 73
+ || x == MDD_Preface_EssenceContainers_DEPRECATED // 85
+ || x == MDD_EssenceContainerData_IndexSID_DEPRECATED // 103
+ || x == MDD_EssenceContainerData_BodySID_DEPRECATED // 104
+ || x == MDD_DMSegment_DataDefinition_DEPRECATED // 266
+ || x == MDD_DMSegment_Duration_DEPRECATED // 267
+ || x == MDD_PartitionMetadata_OperationalPattern_DEPRECATED // 33
+ || x == MDD_Preface_OperationalPattern_DEPRECATED // 84
+ || x == MDD_TimedTextResourceSubDescriptor_EssenceStreamID_DEPRECATED // 264
+ )
+ continue;
+
+ AddEntry(s_MDD_Table[x], x);
+ }
+}
+
+//
+bool
+ASDCP::Dictionary::AddEntry(const MDDEntry& Entry, ui32_t index)
+{
+ if ( index >= (ui32_t)MDD_Max )
+ {
+ Kumu::DefaultLogSink().Warn("UL Dictionary: index exceeds maximum: %d\n", index);
+ return false;
+ }
+
+ bool result = true;
+ // is this index already there?
+ std::map<ui32_t, ASDCP::UL>::iterator rii = m_md_rev_lookup.find(index);
+
+ if ( rii != m_md_rev_lookup.end() )
+ {
+ DeleteEntry(index);
+ result = false;
+ }
+
+ UL TmpUL(Entry.ul);
+
+#ifdef MDD_AUTHORING_MODE
+ char buf[64];
+ std::map<ASDCP::UL, ui32_t>::iterator ii = m_md_lookup.find(TmpUL);
+ if ( ii != m_md_lookup.end() )
+ {
+ fprintf(stderr, "DUPE! %s (%02x, %02x) %s | (%02x, %02x) %s\n",
+ TmpUL.EncodeString(buf, 64),
+ m_MDD_Table[ii->second].tag.a, m_MDD_Table[ii->second].tag.b,
+ m_MDD_Table[ii->second].name,
+ Entry.tag.a, Entry.tag.b, Entry.name);
+ }
+#endif
+
+ m_md_lookup.insert(std::map<UL, ui32_t>::value_type(TmpUL, index));
+ m_md_rev_lookup.insert(std::map<ui32_t, UL>::value_type(index, TmpUL));
+ m_md_sym_lookup.insert(std::map<std::string, ui32_t>::value_type(Entry.name, index));
+ m_MDD_Table[index] = Entry;
+
+ return result;
+}
+
+//
+bool
+ASDCP::Dictionary::DeleteEntry(ui32_t index)
+{
+ std::map<ui32_t, ASDCP::UL>::iterator rii = m_md_rev_lookup.find(index);
+ if ( rii != m_md_rev_lookup.end() )
+ {
+ std::map<ASDCP::UL, ui32_t>::iterator ii = m_md_lookup.find(rii->second);
+ assert(ii != m_md_lookup.end());
+
+ MDDEntry NilEntry;
+ memset(&NilEntry, 0, sizeof(NilEntry));
+
+ m_md_lookup.erase(ii);
+ m_md_rev_lookup.erase(rii);
+ m_MDD_Table[index] = NilEntry;
+ return true;
+ }
+
+ return false;
+}
+
+//
+const ASDCP::MDDEntry&
+ASDCP::Dictionary::Type(MDD_t type_id) const
+{
+ assert(m_MDD_Table[0].name[0]);
+ std::map<ui32_t, ASDCP::UL>::const_iterator rii = m_md_rev_lookup.find(type_id);
+
+ if ( rii == m_md_rev_lookup.end() )
+ Kumu::DefaultLogSink().Warn("UL Dictionary: unknown UL type_id: %d\n", type_id);
+
+ return m_MDD_Table[type_id];
+}
+
+//
+const ASDCP::MDDEntry*
+ASDCP::Dictionary::FindUL(const byte_t* ul_buf) const
+{
+ assert(m_MDD_Table[0].name[0]);
+ std::map<UL, ui32_t>::const_iterator i = m_md_lookup.find(UL(ul_buf));
+
+ if ( i == m_md_lookup.end() )
+ {
+ byte_t tmp_ul[SMPTE_UL_LENGTH];
+ memcpy(tmp_ul, ul_buf, SMPTE_UL_LENGTH);
+ tmp_ul[SMPTE_UL_LENGTH-1] = 0;
+
+ i = m_md_lookup.find(UL(tmp_ul));
+
+ if ( i == m_md_lookup.end() )
+ {
+ char buf[64];
+ UL TmpUL(ul_buf);
+ Kumu::DefaultLogSink().Warn("UL Dictionary: unknown UL: %s\n", TmpUL.EncodeString(buf, 64));
+ return 0;
+ }
+ }
+
+ return &m_MDD_Table[i->second];
+}
+
+//
+const ASDCP::MDDEntry*
+ASDCP::Dictionary::FindSymbol(const std::string& str) const
+{
+ assert(m_MDD_Table[0].name[0]);
+ std::map<std::string, ui32_t>::const_iterator i = m_md_sym_lookup.find(str);
+
+ if ( i == m_md_sym_lookup.end() )
+ {
+ Kumu::DefaultLogSink().Warn("UL Dictionary: unknown symbol: %s\n", str.c_str());
+ return 0;
+ }
+
+ return &m_MDD_Table[i->second];
+}
+
+//
+void
+ASDCP::Dictionary::Dump(FILE* stream) const
+{
+ if ( stream == 0 )
+ stream = stderr;
+
+ MDD_t di = (MDD_t)0;
+ char str_buf[64];
+
+ while ( di < MDD_Max )
+ {
+ if ( m_MDD_Table[di].name != 0 )
+ {
+ UL TmpUL(m_MDD_Table[di].ul);
+ fprintf(stream, "%s: %s\n", TmpUL.EncodeString(str_buf, 64), m_MDD_Table[di].name);
+ }
+
+ di = (MDD_t)(di + 1);
+ }
+}
+
+//
+// end Dict.cpp
+//
diff --git a/asdcplib/src/Index.cpp b/asdcplib/src/Index.cpp
new file mode 100755
index 0000000..702b185
--- /dev/null
+++ b/asdcplib/src/Index.cpp
@@ -0,0 +1,243 @@
+/*
+Copyright (c) 2005-2012, 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 Index.cpp
+ \version $Id: Index.cpp,v 1.21 2012/02/03 19:49:56 jhurst Exp $
+ \brief MXF index segment objects
+*/
+
+#include "MXF.h"
+const ui32_t kl_length = ASDCP::SMPTE_UL_LENGTH + ASDCP::MXF_BER_LENGTH;
+
+
+//
+ASDCP::MXF::IndexTableSegment::IndexTableSegment(const Dictionary*& d) :
+ InterchangeObject(d), m_Dict(d),
+ IndexStartPosition(0), IndexDuration(0), EditUnitByteCount(0),
+ IndexSID(129), BodySID(1), SliceCount(0), PosTableCount(0)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_IndexTableSegment);
+}
+
+//
+ASDCP::MXF::IndexTableSegment::~IndexTableSegment()
+{
+}
+
+//
+void
+ASDCP::MXF::IndexTableSegment::Copy(const IndexTableSegment& rhs)
+{
+ InterchangeObject::Copy(rhs);
+ IndexEditRate = rhs.IndexEditRate;
+ IndexStartPosition = rhs.IndexStartPosition;
+ IndexDuration = rhs.IndexDuration;
+ EditUnitByteCount = rhs.EditUnitByteCount;
+ IndexSID = rhs.IndexSID;
+ BodySID = rhs.BodySID;
+ SliceCount = rhs.SliceCount;
+ PosTableCount = rhs.PosTableCount;
+ DeltaEntryArray = rhs.DeltaEntryArray;
+ IndexEntryArray = rhs.IndexEntryArray;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::IndexTableSegment::InitFromTLVSet(TLVReader& TLVSet)
+{
+ Result_t result = InterchangeObject::InitFromTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(IndexTableSegmentBase, IndexEditRate));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi64(OBJ_READ_ARGS(IndexTableSegmentBase, IndexStartPosition));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi64(OBJ_READ_ARGS(IndexTableSegmentBase, IndexDuration));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(IndexTableSegmentBase, EditUnitByteCount));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(IndexTableSegmentBase, IndexSID));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(EssenceContainerData, BodySID));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi8(OBJ_READ_ARGS(IndexTableSegmentBase, SliceCount));
+ 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));
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::IndexTableSegment::WriteToTLVSet(TLVWriter& TLVSet)
+{
+ Result_t result = InterchangeObject::WriteToTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(IndexTableSegmentBase, IndexEditRate));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi64(OBJ_WRITE_ARGS(IndexTableSegmentBase, IndexStartPosition));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi64(OBJ_WRITE_ARGS(IndexTableSegmentBase, IndexDuration));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(IndexTableSegmentBase, EditUnitByteCount));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(IndexTableSegmentBase, IndexSID));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(EssenceContainerData, BodySID));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi8(OBJ_WRITE_ARGS(IndexTableSegmentBase, SliceCount));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi8(OBJ_WRITE_ARGS(IndexTableSegmentBase, PosTableCount));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(IndexTableSegment, DeltaEntryArray));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(IndexTableSegment, IndexEntryArray));
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::IndexTableSegment::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::IndexTableSegment::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return InterchangeObject::WriteToBuffer(Buffer);
+}
+
+//
+void
+ASDCP::MXF::IndexTableSegment::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ InterchangeObject::Dump(stream);
+ 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 = %u\n", EditUnitByteCount);
+ fprintf(stream, " IndexSID = %u\n", IndexSID);
+ fprintf(stream, " BodySID = %u\n", BodySID);
+ fprintf(stream, " SliceCount = %hu\n", SliceCount);
+ fprintf(stream, " PosTableCount = %hu\n", PosTableCount);
+
+ fprintf(stream, " DeltaEntryArray:\n"); DeltaEntryArray.Dump(stream);
+
+ if ( IndexEntryArray.size() < 100 )
+ {
+ fprintf(stream, " IndexEntryArray:\n");
+ IndexEntryArray.Dump(stream);
+ }
+ else
+ {
+ fprintf(stream, " IndexEntryArray: %zu entries\n", IndexEntryArray.size());
+ }
+}
+
+//------------------------------------------------------------------------------------------
+//
+
+//
+const char*
+ASDCP::MXF::IndexTableSegment::DeltaEntry::EncodeString(char* str_buf, ui32_t buf_len) const
+{
+ snprintf(str_buf, buf_len, "%3d %-3hu %-3u", PosTableIndex, Slice, ElementData);
+ return str_buf;
+}
+
+//
+bool
+ASDCP::MXF::IndexTableSegment::DeltaEntry::Unarchive(Kumu::MemIOReader* Reader)
+{
+ if ( ! Reader->ReadUi8((ui8_t*)&PosTableIndex) ) return false;
+ if ( ! Reader->ReadUi8(&Slice) ) return false;
+ if ( ! Reader->ReadUi32BE(&ElementData) ) return false;
+ return true;
+}
+
+//
+bool
+ASDCP::MXF::IndexTableSegment::DeltaEntry::Archive(Kumu::MemIOWriter* Writer) const
+{
+ if ( ! Writer->WriteUi8((ui8_t)PosTableIndex) ) return false;
+ if ( ! Writer->WriteUi8(Slice) ) return false;
+ if ( ! Writer->WriteUi32BE(ElementData) ) return false;
+ return true;
+}
+
+//------------------------------------------------------------------------------------------
+//
+
+// Flags:
+// Bit 7: Random Access
+// Bit 6: Sequence Header
+// Bit 5: forward prediction flag
+// Bit 4: backward prediction flag
+// e.g.
+// 00== I frame (no prediction)
+// 10== P frame(forward prediction from previous frame)
+// 01== B frame (backward prediction from future frame)
+// 11== B frame (forward & backward prediction)
+// Bits 0-3: reserved [RP210 Flags to indicate coding of elements in this edit unit]
+
+//
+const char*
+ASDCP::MXF::IndexTableSegment::IndexEntry::EncodeString(char* str_buf, ui32_t buf_len) const
+{
+ char intbuf[IntBufferLen];
+ char txt_flags[6];
+
+ txt_flags[0] = ( (Flags & 0x80) != 0 ) ? 'r' : ' ';
+ txt_flags[1] = ( (Flags & 0x40) != 0 ) ? 's' : ' ';
+ txt_flags[2] = ( (Flags & 0x20) != 0 ) ? 'f' : ' ';
+ txt_flags[3] = ( (Flags & 0x10) != 0 ) ? 'b' : ' ';
+ txt_flags[4] = ( (Flags & 0x0f) == 3 ) ? 'B' : ( (Flags & 0x0f) == 2 ) ? 'P' : 'I';
+ txt_flags[5] = 0;
+
+ snprintf(str_buf, buf_len, "%3i %-3hu %s %s",
+ TemporalOffset, KeyFrameOffset, txt_flags,
+ i64sz(StreamOffset, intbuf));
+
+ return str_buf;
+}
+
+//
+bool
+ASDCP::MXF::IndexTableSegment::IndexEntry::Unarchive(Kumu::MemIOReader* Reader)
+{
+ 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;
+}
+
+//
+bool
+ASDCP::MXF::IndexTableSegment::IndexEntry::Archive(Kumu::MemIOWriter* Writer) const
+{
+ 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;
+}
+
+
+//
+// end Index.cpp
+//
+
diff --git a/asdcplib/src/JP2K.cpp b/asdcplib/src/JP2K.cpp
new file mode 100755
index 0000000..4cc0e50
--- /dev/null
+++ b/asdcplib/src/JP2K.cpp
@@ -0,0 +1,224 @@
+/*
+Copyright (c) 2005-2009, 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 JP2K.cpp
+ \version $Id: JP2K.cpp,v 1.8 2010/06/17 03:33:17 jhurst Exp $
+ \brief JPEG 2000 parser implementation
+
+ This is not a complete implementation of all things JP2K. There is just enough here to
+ support parsing picture metadata from a codestream header.
+*/
+
+#include <JP2K.h>
+#include <KM_log.h>
+using Kumu::DefaultLogSink;
+
+
+// when indexed with the second byte of a marker code, this table will procuce one of
+// two values:
+// 0 - the marker is a standalone marker
+// 1 - the marker designates a marker segment
+//
+const byte_t MarkerSegmentMap[] =
+ {
+ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0
+ /* 1 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
+ /* 2 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2
+ /* 3 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3
+ /* 4 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4
+ /* 5 */ 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, // 5
+ /* 6 */ 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6
+ /* 7 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8
+ /* 9 */ 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9
+ /* a */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // a
+ /* b */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // b
+ /* c */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // c
+ /* d */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // d
+ /* e */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // e
+ /* f */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // f
+ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
+ };
+
+
+//
+ASDCP::Result_t
+ASDCP::JP2K::GetNextMarker(const byte_t** buf, JP2K::Marker& Marker)
+{
+ assert((buf != 0) && (*buf != 0 ));
+
+ if ( **buf != 0xff )
+ return ASDCP::RESULT_FAIL;
+
+ Marker.m_IsSegment = (MarkerSegmentMap[*(++(*buf))] == 1);
+ Marker.m_Type = (Marker_t)(0xff00 | *(*buf)++);
+
+ if ( Marker.m_IsSegment )
+ {
+ Marker.m_DataSize = *(*buf)++ << 8;
+ Marker.m_DataSize |= *(*buf)++;
+ Marker.m_DataSize -= 2;
+ Marker.m_Data = *buf;
+ *buf += Marker.m_DataSize;
+ }
+
+
+ if ( Marker.m_DataSize != 0 && Marker.m_DataSize < 3 )
+ {
+ DefaultLogSink().Error("Illegal data size: %u\n", Marker.m_DataSize);
+ return ASDCP::RESULT_FAIL;
+ }
+
+ return ASDCP::RESULT_OK;
+}
+
+
+//-------------------------------------------------------------------------------------------------------
+//
+
+//
+void
+ASDCP::JP2K::Accessor::SIZ::ReadComponent(ui32_t index, ASDCP::JP2K::ImageComponent_t& IC)
+{
+ assert ( index < Csize() );
+ const byte_t* p = m_MarkerData + 36 + (index * 3);
+ IC.Ssize = *p++;
+ IC.XRsize = *p++;
+ IC.YRsize = *p;
+}
+
+//
+void
+ASDCP::JP2K::Accessor::SIZ::Dump(FILE* stream)
+{
+ if ( stream == 0 )
+ stream = stderr;
+
+ fprintf(stream, "SIZ: \n");
+ fprintf(stream, " Rsize: %hu\n", Rsize());
+ fprintf(stream, " Xsize: %u\n", Xsize());
+ fprintf(stream, " Ysize: %u\n", Ysize());
+ fprintf(stream, " XOsize: %u\n", XOsize());
+ fprintf(stream, " YOsize: %u\n", YOsize());
+ fprintf(stream, " XTsize: %u\n", XTsize());
+ fprintf(stream, " YTsize: %u\n", YTsize());
+ fprintf(stream, "XTOsize: %u\n", XTOsize());
+ fprintf(stream, "YTOsize: %u\n", YTOsize());
+ fprintf(stream, " Csize: %u\n", Csize());
+
+ if ( Csize() > 0 )
+ {
+ fprintf(stream, "Components\n");
+
+ for ( ui32_t i = 0; i < Csize(); i++ )
+ {
+ ImageComponent_t TmpComp;
+ ReadComponent(i, TmpComp);
+ fprintf(stream, "%u: ", i);
+ fprintf(stream, "%u, %u, %u\n", TmpComp.Ssize, TmpComp.XRsize, TmpComp.YRsize);
+ }
+ }
+}
+
+//
+void
+ASDCP::JP2K::Accessor::COM::Dump(FILE* stream)
+{
+ if ( stream == 0 )
+ stream = stderr;
+
+ if ( IsText() )
+ {
+ char* t_str = (char*)malloc(CommentSize() + 1);
+ assert( t_str != 0 );
+ ui32_t cs = CommentSize();
+ memcpy(t_str, CommentData(), cs);
+ t_str[cs] = 0;
+ fprintf(stream, "COM:%s\n", t_str);
+ }
+ else
+ {
+ fprintf(stream, "COM:\n");
+ Kumu::hexdump(CommentData(), CommentSize(), stream);
+ }
+}
+
+
+//-------------------------------------------------------------------------------------------------------
+//
+
+
+//
+void
+ASDCP::JP2K::Marker::Dump(FILE* stream) const
+{
+ if ( stream == 0 )
+ stream = stderr;
+
+ fprintf(stream, "Marker%s 0x%04x: %s", (m_IsSegment ? " segment" : ""), m_Type, GetMarkerString(m_Type));
+
+ if ( m_IsSegment )
+ fprintf(stream, ", 0x%0x bytes", m_DataSize);
+
+ fputc('\n', stream);
+}
+
+//
+const char*
+ASDCP::JP2K::GetMarkerString(Marker_t m)
+{
+ switch ( m )
+ {
+ case MRK_NIL: return "NIL"; break;
+ case MRK_SOC: return "SOC: Start of codestream"; break;
+ case MRK_SOT: return "SOT: Start of tile-part"; break;
+ case MRK_SOD: return "SOD: Start of data"; break;
+ case MRK_EOC: return "EOC: End of codestream"; break;
+ case MRK_SIZ: return "SIZ: Image and tile size"; break;
+ case MRK_COD: return "COD: Coding style default"; break;
+ case MRK_COC: return "COC: Coding style component"; break;
+ case MRK_RGN: return "RGN: Region of interest"; break;
+ case MRK_QCD: return "QCD: Quantization default"; break;
+ case MRK_QCC: return "QCC: Quantization component"; break;
+ case MRK_POC: return "POC: Progression order change"; break;
+ case MRK_TLM: return "TLM: Tile-part lengths"; break;
+ case MRK_PLM: return "PLM: Packet length, main header"; break;
+ case MRK_PLT: return "PLT: Packet length, tile-part header"; break;
+ case MRK_PPM: return "PPM: Packed packet headers, main header"; break;
+ case MRK_PPT: return "PPT: Packed packet headers, tile-part header"; break;
+ case MRK_SOP: return "SOP: Start of packet"; break;
+ case MRK_EPH: return "EPH: End of packet header"; break;
+ case MRK_CRG: return "CRG: Component registration"; break;
+ case MRK_COM: return "COM: Comment"; break;
+ }
+
+ return "Unknown marker code";
+}
+
+//
+// end JP2K.cpp
+//
diff --git a/asdcplib/src/JP2K.h b/asdcplib/src/JP2K.h
new file mode 100755
index 0000000..d30dbad
--- /dev/null
+++ b/asdcplib/src/JP2K.h
@@ -0,0 +1,164 @@
+/*
+Copyright (c) 2005-2009, 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 JP2K.h
+ \version $Id: JP2K.h,v 1.4 2009/04/09 19:24:14 msheby Exp $
+ \brief JPEG 2000 constants and data structures
+
+ This is not a complete enumeration of all things JP2K. There is just enough here to
+ support parsing picture metadata from a codestream header.
+*/
+
+#ifndef _JP2K_H_
+#define _JP2K_H_
+
+// AS_DCP.h is included only for it's base type definitions.
+#include <KM_platform.h>
+#include <KM_util.h>
+#include <AS_DCP.h>
+#include <assert.h>
+
+namespace ASDCP
+{
+namespace JP2K
+{
+ const byte_t Magic[] = {0xff, 0x4f, 0xff};
+
+ enum Marker_t
+ {
+ MRK_NIL = 0,
+ MRK_SOC = 0xff4f, // Start of codestream
+ MRK_SOT = 0xff90, // Start of tile-part
+ MRK_SOD = 0xff93, // Start of data
+ MRK_EOC = 0xffd9, // End of codestream
+ MRK_SIZ = 0xff51, // Image and tile size
+ MRK_COD = 0xff52, // Coding style default
+ MRK_COC = 0xff53, // Coding style component
+ MRK_RGN = 0xff5e, // Region of interest
+ MRK_QCD = 0xff5c, // Quantization default
+ MRK_QCC = 0xff5d, // Quantization component
+ MRK_POC = 0xff5f, // Progression order change
+ MRK_TLM = 0xff55, // Tile-part lengths
+ MRK_PLM = 0xff57, // Packet length, main header
+ MRK_PLT = 0xff58, // Packet length, tile-part header
+ MRK_PPM = 0xff60, // Packed packet headers, main header
+ MRK_PPT = 0xff61, // Packed packet headers, tile-part header
+ MRK_SOP = 0xff91, // Start of packet
+ MRK_EPH = 0xff92, // End of packet header
+ MRK_CRG = 0xff63, // Component registration
+ MRK_COM = 0xff64, // Comment
+ };
+
+ const char* GetMarkerString(Marker_t m);
+
+ //
+ class Marker
+ {
+ KM_NO_COPY_CONSTRUCT(Marker);
+
+ public:
+ Marker_t m_Type;
+ bool m_IsSegment;
+ ui32_t m_DataSize;
+ const byte_t* m_Data;
+
+ Marker() : m_Type(MRK_NIL), m_IsSegment(false), m_DataSize(0), m_Data(0) {}
+ ~Marker() {}
+
+ void Dump(FILE* stream = 0) const;
+ };
+
+ //
+ ASDCP::Result_t GetNextMarker(const byte_t**, Marker&);
+
+ // accessor objects for marker segments
+ namespace Accessor
+ {
+ // image size
+ class SIZ
+ {
+ const byte_t* m_MarkerData;
+ KM_NO_COPY_CONSTRUCT(SIZ);
+ SIZ();
+
+ public:
+ SIZ(const Marker& M)
+ {
+ assert(M.m_Type == MRK_SIZ);
+ m_MarkerData = M.m_Data;
+ }
+
+ ~SIZ() {}
+
+ 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_t& IC);
+ void Dump(FILE* stream = 0);
+ };
+
+ // a comment
+ class COM
+ {
+ bool m_IsText;
+ const byte_t* m_MarkerData;
+ ui32_t m_DataSize;
+
+ KM_NO_COPY_CONSTRUCT(COM);
+ COM();
+
+ public:
+ COM(const Marker& M)
+ {
+ assert(M.m_Type == MRK_COM);
+ m_IsText = M.m_Data[1] == 1;
+ m_MarkerData = M.m_Data + 2;
+ m_DataSize = M.m_DataSize - 2;
+ }
+
+ ~COM() {}
+
+ inline bool IsText() { return m_IsText; }
+ inline const byte_t* CommentData() { return m_MarkerData; }
+ inline ui32_t CommentSize() { return m_DataSize; }
+ void Dump(FILE* stream = 0);
+ };
+ } // namespace Accessor
+} // namespace JP2K
+} // namespace ASDCP
+
+#endif // _JP2K_H_
+
+//
+// end JP2K.h
+//
diff --git a/asdcplib/src/JP2K_Codestream_Parser.cpp b/asdcplib/src/JP2K_Codestream_Parser.cpp
new file mode 100755
index 0000000..5ab7a32
--- /dev/null
+++ b/asdcplib/src/JP2K_Codestream_Parser.cpp
@@ -0,0 +1,270 @@
+/*
+Copyright (c) 2004-2009, 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 Codestream_Parser.cpp
+ \version $Id: JP2K_Codestream_Parser.cpp,v 1.7 2009/04/09 19:16:49 msheby Exp $
+ \brief AS-DCP library, JPEG 2000 codestream essence reader implementation
+*/
+
+#include <KM_fileio.h>
+#include <AS_DCP.h>
+#include <JP2K.h>
+#include <assert.h>
+#include <KM_log.h>
+using Kumu::DefaultLogSink;
+
+//------------------------------------------------------------------------------------------
+
+class ASDCP::JP2K::CodestreamParser::h__CodestreamParser
+{
+ ASDCP_NO_COPY_CONSTRUCT(h__CodestreamParser);
+
+public:
+ PictureDescriptor m_PDesc;
+ Kumu::FileReader m_File;
+
+ h__CodestreamParser()
+ {
+ memset(&m_PDesc, 0, sizeof(m_PDesc));
+ m_PDesc.EditRate = Rational(24,1);
+ m_PDesc.SampleRate = m_PDesc.EditRate;
+ }
+
+ ~h__CodestreamParser() {}
+
+ Result_t OpenReadFrame(const char* filename, FrameBuffer& FB)
+ {
+ ASDCP_TEST_NULL_STR(filename);
+ m_File.Close();
+ Result_t result = m_File.OpenRead(filename);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ Kumu::fsize_t file_size = m_File.Size();
+
+ if ( FB.Capacity() < file_size )
+ {
+ DefaultLogSink().Error("FrameBuf.Capacity: %u frame length: %u\n", FB.Capacity(), (ui32_t)file_size);
+ return RESULT_SMALLBUF;
+ }
+ }
+
+ ui32_t read_count;
+
+ if ( ASDCP_SUCCESS(result) )
+ result = m_File.Read(FB.Data(), FB.Capacity(), &read_count);
+
+ if ( ASDCP_SUCCESS(result) )
+ FB.Size(read_count);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ byte_t start_of_data = 0; // out param
+ result = ParseMetadataIntoDesc(FB, m_PDesc, &start_of_data);
+
+ if ( ASDCP_SUCCESS(result) )
+ FB.PlaintextOffset(start_of_data);
+ }
+
+ return result;
+ }
+
+ Result_t OpenReadFrame(const unsigned char * data, unsigned int size, FrameBuffer& FB)
+ {
+ if ( FB.Capacity() < size )
+ {
+ DefaultLogSink().Error("FrameBuf.Capacity: %u frame length: %u\n", FB.Capacity(), (ui32_t) size);
+ return RESULT_SMALLBUF;
+ }
+
+ memcpy (FB.Data(), data, size);
+ FB.Size(size);
+
+ byte_t start_of_data = 0; // out param
+ const Result_t result = ParseMetadataIntoDesc(FB, m_PDesc, &start_of_data);
+
+ if ( ASDCP_SUCCESS(result) )
+ FB.PlaintextOffset(start_of_data);
+
+ return result;
+ }
+};
+
+ASDCP::Result_t
+ASDCP::JP2K::ParseMetadataIntoDesc(const FrameBuffer& FB, PictureDescriptor& PDesc, byte_t* start_of_data)
+{
+ Result_t result = RESULT_OK;
+ Marker NextMarker;
+ ui32_t i;
+ const byte_t* p = FB.RoData();
+ const byte_t* end_p = p + FB.Size();
+
+ while ( p < end_p && ASDCP_SUCCESS(result) )
+ {
+ result = GetNextMarker(&p, NextMarker);
+
+ if ( ASDCP_FAILURE(result) )
+ {
+ result = RESULT_RAW_ESS;
+ break;
+ }
+
+ switch ( NextMarker.m_Type )
+ {
+ case MRK_SOD:
+ if ( start_of_data != 0 )
+ *start_of_data = p - FB.RoData();
+
+ p = end_p;
+ break;
+
+ case MRK_SIZ:
+ {
+ Accessor::SIZ SIZ_(NextMarker);
+ PDesc.StoredWidth = SIZ_.Xsize();
+ PDesc.StoredHeight = SIZ_.Ysize();
+ PDesc.AspectRatio = Rational(SIZ_.Xsize(), SIZ_.Ysize());
+ PDesc.Rsize = SIZ_.Rsize();
+ PDesc.Xsize = SIZ_.Xsize();
+ PDesc.Ysize = SIZ_.Ysize();
+ PDesc.XOsize = SIZ_.XOsize();
+ PDesc.YOsize = SIZ_.YOsize();
+ PDesc.XTsize = SIZ_.XTsize();
+ PDesc.YTsize = SIZ_.YTsize();
+ PDesc.XTOsize = SIZ_.XTOsize();
+ PDesc.YTOsize = SIZ_.YTOsize();
+ PDesc.Csize = SIZ_.Csize();
+
+ if ( PDesc.Csize != 3 )
+ {
+ DefaultLogSink().Error("Unexpected number of components: %u\n", PDesc.Csize);
+ return RESULT_RAW_FORMAT;
+ }
+
+ for ( i = 0; i < PDesc.Csize; i++ )
+ SIZ_.ReadComponent(i, PDesc.ImageComponents[i]);
+ }
+ break;
+
+ case MRK_COD:
+ memset(&PDesc.CodingStyleDefault, 0, sizeof(CodingStyleDefault_t));
+
+ if ( NextMarker.m_DataSize > sizeof(CodingStyleDefault_t) )
+ {
+ DefaultLogSink().Error("Unexpectedly large CodingStyle data: %u\n", NextMarker.m_DataSize);
+ return RESULT_RAW_FORMAT;
+ }
+
+ memcpy(&PDesc.CodingStyleDefault, NextMarker.m_Data, NextMarker.m_DataSize);
+ break;
+
+ case MRK_QCD:
+ memset(&PDesc.QuantizationDefault, 0, sizeof(QuantizationDefault_t));
+
+ if ( NextMarker.m_DataSize < 16 )
+ {
+ DefaultLogSink().Error("No quantization signaled\n");
+ return RESULT_RAW_FORMAT;
+ }
+
+ if ( NextMarker.m_DataSize > MaxDefaults )
+ {
+ DefaultLogSink().Error("Quantization Default length exceeds maximum %d\n", NextMarker.m_DataSize);
+ return RESULT_RAW_FORMAT;
+ }
+
+ memcpy(&PDesc.QuantizationDefault, NextMarker.m_Data, NextMarker.m_DataSize);
+ PDesc.QuantizationDefault.SPqcdLength = NextMarker.m_DataSize - 1;
+ break;
+
+ case MRK_NIL:
+ case MRK_SOC:
+ case MRK_SOT:
+ case MRK_EOC:
+ case MRK_COC:
+ case MRK_RGN:
+ case MRK_QCC:
+ case MRK_POC:
+ case MRK_TLM:
+ case MRK_PLM:
+ case MRK_PLT:
+ case MRK_PPM:
+ case MRK_PPT:
+ case MRK_SOP:
+ case MRK_EPH:
+ case MRK_CRG:
+ case MRK_COM:
+ /* Keep gcc quiet */
+ break;
+ }
+ }
+
+ return result;
+}
+
+//------------------------------------------------------------------------------------------
+
+ASDCP::JP2K::CodestreamParser::CodestreamParser()
+{
+}
+
+ASDCP::JP2K::CodestreamParser::~CodestreamParser()
+{
+}
+
+// Opens the stream for reading, parses enough data to provide a complete
+// set of stream metadata for the MXFWriter below.
+ASDCP::Result_t
+ASDCP::JP2K::CodestreamParser::OpenReadFrame(const char* filename, FrameBuffer& FB) const
+{
+ const_cast<ASDCP::JP2K::CodestreamParser*>(this)->m_Parser = new h__CodestreamParser;
+ return m_Parser->OpenReadFrame(filename, FB);
+}
+
+// Opens the stream for reading, parses enough data to provide a complete
+// set of stream metadata for the MXFWriter below.
+ASDCP::Result_t
+ASDCP::JP2K::CodestreamParser::OpenReadFrame(const unsigned char* data, unsigned int size, FrameBuffer& FB) const
+{
+ const_cast<ASDCP::JP2K::CodestreamParser*>(this)->m_Parser = new h__CodestreamParser;
+ return m_Parser->OpenReadFrame(data, size, FB);
+}
+
+//
+ASDCP::Result_t
+ASDCP::JP2K::CodestreamParser::FillPictureDescriptor(PictureDescriptor& PDesc) const
+{
+ if ( m_Parser.empty() )
+ return RESULT_INIT;
+
+ PDesc = m_Parser->m_PDesc;
+ return RESULT_OK;
+}
+
+
+//
+// end Codestream_Parser.cpp
+//
diff --git a/asdcplib/src/JP2K_Sequence_Parser.cpp b/asdcplib/src/JP2K_Sequence_Parser.cpp
new file mode 100755
index 0000000..3b422d4
--- /dev/null
+++ b/asdcplib/src/JP2K_Sequence_Parser.cpp
@@ -0,0 +1,392 @@
+/*
+Copyright (c) 2004-2011, 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 JP2K_Sequence_Parser.cpp
+ \version $Id: JP2K_Sequence_Parser.cpp,v 1.8 2011/05/13 01:50:19 jhurst Exp $
+ \brief AS-DCP library, JPEG 2000 codestream essence reader implementation
+*/
+
+#include <AS_DCP.h>
+#include <KM_fileio.h>
+#include <KM_log.h>
+#include <list>
+#include <string>
+#include <algorithm>
+#include <string.h>
+#include <assert.h>
+
+using namespace ASDCP;
+
+
+//------------------------------------------------------------------------------------------
+
+class FileList : public std::list<std::string>
+{
+ std::string m_DirName;
+
+public:
+ FileList() {}
+ ~FileList() {}
+
+ const FileList& operator=(const std::list<std::string>& pathlist) {
+ std::list<std::string>::const_iterator i;
+ for ( i = pathlist.begin(); i != pathlist.end(); i++ )
+ push_back(*i);
+ return *this;
+ }
+
+ //
+ Result_t InitFromDirectory(const char* path)
+ {
+ char next_file[Kumu::MaxFilePath];
+ Kumu::DirScanner Scanner;
+
+ Result_t result = Scanner.Open(path);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ m_DirName = path;
+
+ while ( ASDCP_SUCCESS(Scanner.GetNext(next_file)) )
+ {
+ if ( next_file[0] == '.' ) // no hidden files or internal links
+ continue;
+
+ std::string Str(m_DirName);
+ Str += "/";
+ Str += next_file;
+
+ if ( ! Kumu::PathIsDirectory(Str) )
+ push_back(Str);
+ }
+
+ sort();
+ }
+
+ return result;
+ }
+};
+
+//------------------------------------------------------------------------------------------
+
+class ASDCP::JP2K::SequenceParser::h__SequenceParser
+{
+ ui32_t m_FramesRead;
+ Rational m_PictureRate;
+ FileList m_FileList;
+ FileList::iterator m_CurrentFile;
+ CodestreamParser m_Parser;
+ bool m_Pedantic;
+
+ Result_t OpenRead();
+
+ ASDCP_NO_COPY_CONSTRUCT(h__SequenceParser);
+
+public:
+ PictureDescriptor m_PDesc;
+
+ h__SequenceParser() : m_FramesRead(0), m_Pedantic(false)
+ {
+ memset(&m_PDesc, 0, sizeof(m_PDesc));
+ m_PDesc.EditRate = Rational(24,1);
+ }
+
+ ~h__SequenceParser()
+ {
+ Close();
+ }
+
+ Result_t OpenRead(const char* filename, bool pedantic);
+ Result_t OpenRead(const std::list<std::string>& file_list, bool pedantic);
+ void Close() {}
+
+ Result_t Reset()
+ {
+ m_FramesRead = 0;
+ m_CurrentFile = m_FileList.begin();
+ return RESULT_OK;
+ }
+
+ Result_t ReadFrame(FrameBuffer&);
+};
+
+
+//
+ASDCP::Result_t
+ASDCP::JP2K::SequenceParser::h__SequenceParser::OpenRead()
+{
+ if ( m_FileList.empty() )
+ return RESULT_ENDOFFILE;
+
+ m_CurrentFile = m_FileList.begin();
+ CodestreamParser Parser;
+ FrameBuffer TmpBuffer;
+
+ Kumu::fsize_t file_size = Kumu::FileSize((*m_CurrentFile).c_str());
+
+ if ( file_size == 0 )
+ return RESULT_NOT_FOUND;
+
+ assert(file_size <= 0xFFFFFFFFL);
+ Result_t result = TmpBuffer.Capacity((ui32_t) file_size);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Parser.OpenReadFrame((*m_CurrentFile).c_str(), TmpBuffer);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Parser.FillPictureDescriptor(m_PDesc);
+
+ // how big is it?
+ if ( ASDCP_SUCCESS(result) )
+ m_PDesc.ContainerDuration = m_FileList.size();
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::JP2K::SequenceParser::h__SequenceParser::OpenRead(const char* filename, bool pedantic)
+{
+ ASDCP_TEST_NULL_STR(filename);
+ m_Pedantic = pedantic;
+
+ Result_t result = m_FileList.InitFromDirectory(filename);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = OpenRead();
+
+ return result;
+}
+
+
+//
+ASDCP::Result_t
+ASDCP::JP2K::SequenceParser::h__SequenceParser::OpenRead(const std::list<std::string>& file_list, bool pedantic)
+{
+ m_Pedantic = pedantic;
+ m_FileList = file_list;
+ return OpenRead();
+}
+
+
+//
+bool
+operator==(const ASDCP::JP2K::ImageComponent_t& lhs, const ASDCP::JP2K::ImageComponent_t& rhs)
+{
+ if ( lhs.Ssize != rhs.Ssize ) return false;
+ if ( lhs.XRsize != rhs.XRsize ) return false;
+ if ( lhs.YRsize != rhs.YRsize ) return false;
+ return true;
+}
+
+//
+bool
+operator==(const ASDCP::JP2K::QuantizationDefault_t& lhs, const ASDCP::JP2K::QuantizationDefault_t& rhs)
+{
+ if ( lhs.Sqcd != rhs.Sqcd ) return false;
+ if ( lhs.SPqcdLength != rhs.SPqcdLength ) return false;
+
+ for ( ui32_t i = 0; i < JP2K::MaxDefaults; i++ )
+ {
+ if ( lhs.SPqcd[i] != rhs.SPqcd[i] )
+ return false;
+ }
+
+ return true;
+}
+
+//
+bool
+operator==(const ASDCP::JP2K::CodingStyleDefault_t& lhs, const ASDCP::JP2K::CodingStyleDefault_t& rhs)
+{
+ if ( lhs.Scod != rhs.Scod ) return false;
+
+ // SGcod
+ if ( lhs.SGcod.ProgressionOrder != rhs.SGcod.ProgressionOrder ) return false;
+ if ( lhs.SGcod.MultiCompTransform != rhs.SGcod.MultiCompTransform ) return false;
+
+ for ( ui32_t i = 0; i < sizeof(ui16_t); i++ )
+ {
+ if ( lhs.SGcod.NumberOfLayers[i] != lhs.SGcod.NumberOfLayers[i] )
+ return false;
+ }
+
+ // SPcod
+ if ( lhs.SPcod.DecompositionLevels != rhs.SPcod.DecompositionLevels ) return false;
+ if ( lhs.SPcod.CodeblockWidth != rhs.SPcod.CodeblockWidth ) return false;
+ if ( lhs.SPcod.CodeblockHeight != rhs.SPcod.CodeblockHeight ) return false;
+ if ( lhs.SPcod.CodeblockStyle != rhs.SPcod.CodeblockStyle ) return false;
+ if ( lhs.SPcod.Transformation != rhs.SPcod.Transformation ) return false;
+
+ for ( ui32_t i = 0; i < JP2K::MaxPrecincts; i++ )
+ {
+ if ( lhs.SPcod.PrecinctSize[i] != rhs.SPcod.PrecinctSize[i] )
+ return false;
+ }
+
+ return true;
+}
+
+//
+bool
+operator==(const ASDCP::JP2K::PictureDescriptor& lhs, const ASDCP::JP2K::PictureDescriptor& rhs)
+{
+ if ( lhs.EditRate != rhs.EditRate ) return false;
+ // if ( lhs.ContainerDuration != rhs.ContainerDuration ) return false;
+ if ( lhs.SampleRate != rhs.SampleRate ) return false;
+ if ( lhs.StoredWidth != rhs.StoredWidth ) return false;
+ if ( lhs.StoredHeight != rhs.StoredHeight ) return false;
+ if ( lhs.AspectRatio != rhs.AspectRatio ) return false;
+ if ( lhs.Rsize != rhs.Rsize ) return false;
+ if ( lhs.Xsize != rhs.Xsize ) return false;
+ if ( lhs.Ysize != rhs.Ysize ) return false;
+ if ( lhs.XOsize != rhs.XOsize ) return false;
+ if ( lhs.YOsize != rhs.YOsize ) return false;
+ if ( lhs.XTsize != rhs.XTsize ) return false;
+ if ( lhs.YTsize != rhs.YTsize ) return false;
+ if ( lhs.XTOsize != rhs.XTOsize ) return false;
+ if ( lhs.YTOsize != rhs.YTOsize ) return false;
+ if ( lhs.Csize != rhs.Csize ) return false;
+ if ( ! ( lhs.CodingStyleDefault == rhs.CodingStyleDefault ) ) return false;
+ if ( ! ( lhs.QuantizationDefault == rhs.QuantizationDefault ) ) return false;
+
+ for ( ui32_t i = 0; i < JP2K::MaxComponents; i++ )
+ {
+ if ( ! ( lhs.ImageComponents[i] == rhs.ImageComponents[i] ) )
+ return false;
+ }
+
+ return true;
+}
+
+//
+ASDCP::Result_t
+ASDCP::JP2K::SequenceParser::h__SequenceParser::ReadFrame(FrameBuffer& FB)
+{
+ if ( m_CurrentFile == m_FileList.end() )
+ return RESULT_ENDOFFILE;
+
+ // open the file
+ Result_t result = m_Parser.OpenReadFrame((*m_CurrentFile).c_str(), FB);
+
+ if ( ASDCP_SUCCESS(result) && m_Pedantic )
+ {
+ PictureDescriptor PDesc;
+ result = m_Parser.FillPictureDescriptor(PDesc);
+
+ if ( ASDCP_SUCCESS(result) && ! ( m_PDesc == PDesc ) )
+ {
+ Kumu::DefaultLogSink().Error("JPEG-2000 codestream parameters do not match at frame %d\n", m_FramesRead + 1);
+ result = RESULT_RAW_FORMAT;
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ FB.FrameNumber(m_FramesRead++);
+ m_CurrentFile++;
+ }
+
+ return result;
+}
+
+
+//------------------------------------------------------------------------------------------
+
+ASDCP::JP2K::SequenceParser::SequenceParser()
+{
+}
+
+ASDCP::JP2K::SequenceParser::~SequenceParser()
+{
+}
+
+// Opens the stream for reading, parses enough data to provide a complete
+// set of stream metadata for the MXFWriter below.
+ASDCP::Result_t
+ASDCP::JP2K::SequenceParser::OpenRead(const char* filename, bool pedantic) const
+{
+ const_cast<ASDCP::JP2K::SequenceParser*>(this)->m_Parser = new h__SequenceParser;
+
+ Result_t result = m_Parser->OpenRead(filename, pedantic);
+
+ if ( ASDCP_FAILURE(result) )
+ const_cast<ASDCP::JP2K::SequenceParser*>(this)->m_Parser.release();
+
+ return result;
+}
+
+//
+Result_t
+ASDCP::JP2K::SequenceParser::OpenRead(const std::list<std::string>& file_list, bool pedantic) const
+{
+ const_cast<ASDCP::JP2K::SequenceParser*>(this)->m_Parser = new h__SequenceParser;
+
+ Result_t result = m_Parser->OpenRead(file_list, pedantic);
+
+ if ( ASDCP_FAILURE(result) )
+ const_cast<ASDCP::JP2K::SequenceParser*>(this)->m_Parser.release();
+
+ return result;
+}
+
+
+// Rewinds the stream to the beginning.
+ASDCP::Result_t
+ASDCP::JP2K::SequenceParser::Reset() const
+{
+ if ( m_Parser.empty() )
+ return RESULT_INIT;
+
+ return m_Parser->Reset();
+}
+
+// Places a frame of data in the frame buffer. Fails if the buffer is too small
+// or the stream is empty.
+ASDCP::Result_t
+ASDCP::JP2K::SequenceParser::ReadFrame(FrameBuffer& FB) const
+{
+ if ( m_Parser.empty() )
+ return RESULT_INIT;
+
+ return m_Parser->ReadFrame(FB);
+}
+
+//
+ASDCP::Result_t
+ASDCP::JP2K::SequenceParser::FillPictureDescriptor(PictureDescriptor& PDesc) const
+{
+ if ( m_Parser.empty() )
+ return RESULT_INIT;
+
+ PDesc = m_Parser->m_PDesc;
+ return RESULT_OK;
+}
+
+
+//
+// end JP2K_Sequence_Parser.cpp
+//
diff --git a/asdcplib/src/KLV.cpp b/asdcplib/src/KLV.cpp
new file mode 100755
index 0000000..46a8a7a
--- /dev/null
+++ b/asdcplib/src/KLV.cpp
@@ -0,0 +1,319 @@
+/*
+Copyright (c) 2005-2009, 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 KLV.cpp
+ \version $Id: KLV.cpp,v 1.13 2012/02/03 19:49:56 jhurst Exp $
+ \brief KLV objects
+*/
+
+#include "KLV.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
+// how long the packet is. This gives us the K (16 bytes) and L (4-9 bytes)
+// and the remaining bytes for an even read (tmp_read_size % 16 == 0)
+const ui32_t kl_length = ASDCP::SMPTE_UL_LENGTH + ASDCP::MXF_BER_LENGTH;
+const ui32_t tmp_read_size = 32;
+
+//------------------------------------------------------------------------------------------
+//
+
+//
+ASDCP::Result_t
+ASDCP::KLVPacket::InitFromBuffer(const byte_t* buf, ui32_t buf_len, const UL& label)
+{
+ Result_t result = KLVPacket::InitFromBuffer(buf, buf_len);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = ( UL(m_KeyStart) == label ) ? RESULT_OK : RESULT_FAIL;
+
+ return result;
+}
+
+//
+ASDCP::UL
+ASDCP::KLVPacket::GetUL()
+{
+ if ( m_KeyStart != 0 )
+ return UL(m_KeyStart);
+
+ return m_UL;
+}
+
+//
+bool
+ASDCP::KLVPacket::SetUL(const UL& new_ul)
+{
+ if ( m_KeyStart != 0 )
+ return false;
+
+ m_UL = new_ul;
+ return true;
+}
+
+//
+ASDCP::Result_t
+ASDCP::KLVPacket::InitFromBuffer(const byte_t* buf, ui32_t buf_len)
+{
+ m_KeyStart = m_ValueStart = 0;
+ m_KLLength = m_ValueLength = 0;
+
+ if ( memcmp(buf, SMPTE_UL_START, 4) != 0 )
+ {
+ DefaultLogSink().Error("Unexpected UL preamble: %02x.%02x.%02x.%02x\n",
+ buf[0], buf[1], buf[2], buf[3]);
+ return RESULT_FAIL;
+ }
+
+ ui32_t ber_len = Kumu::BER_length(buf + SMPTE_UL_LENGTH);
+
+ if ( ber_len > ( buf_len - SMPTE_UL_LENGTH ) )
+ {
+ DefaultLogSink().Error("BER encoding length exceeds buffer size\n");
+ return RESULT_FAIL;
+ }
+
+ if ( ber_len == 0 )
+ {
+ DefaultLogSink().Error("KLV format error, zero BER length not allowed\n");
+ return RESULT_FAIL;
+ }
+
+ ui64_t tmp_size;
+ if ( ! Kumu::read_BER(buf + SMPTE_UL_LENGTH, &tmp_size) )
+ return RESULT_FAIL;
+
+ assert (tmp_size <= 0xFFFFFFFFL);
+ m_ValueLength = (ui32_t) tmp_size;
+ m_KLLength = SMPTE_UL_LENGTH + Kumu::BER_length(buf + SMPTE_UL_LENGTH);
+ m_KeyStart = buf;
+ m_ValueStart = buf + m_KLLength;
+ return RESULT_OK;
+}
+
+//
+bool
+ASDCP::KLVPacket::HasUL(const byte_t* ul)
+{
+ if ( m_KeyStart != 0 )
+ {
+ return ( memcmp(ul, m_KeyStart, SMPTE_UL_LENGTH) == 0 ) ? true : false;
+ }
+
+ if ( m_UL.HasValue() )
+ {
+ return UL(ul) == m_UL;
+ }
+
+ return false;
+}
+
+//
+ASDCP::Result_t
+ASDCP::KLVPacket::WriteKLToBuffer(ASDCP::FrameBuffer& Buffer, const UL& label, ui32_t length)
+{
+ assert(label.HasValue());
+
+ if ( Buffer.Size() + kl_length > Buffer.Capacity() )
+ {
+ DefaultLogSink().Error("Small write buffer\n");
+ return RESULT_FAIL;
+ }
+
+ memcpy(Buffer.Data() + Buffer.Size(), label.Value(), label.Size());
+
+ if ( ! Kumu::write_BER(Buffer.Data() + Buffer.Size() + SMPTE_UL_LENGTH, length, MXF_BER_LENGTH) )
+ return RESULT_FAIL;
+
+ Buffer.Size(Buffer.Size() + kl_length);
+ return RESULT_OK;
+}
+
+//
+void
+ASDCP::KLVPacket::Dump(FILE* stream, const Dictionary& Dict, bool show_value)
+{
+ char buf[64];
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ if ( m_KeyStart != 0 )
+ {
+ assert(m_ValueStart);
+ UL TmpUL(m_KeyStart);
+ fprintf(stream, "%s", TmpUL.EncodeString(buf, 64));
+
+ const MDDEntry* Entry = Dict.FindUL(m_KeyStart);
+ fprintf(stream, " len: %7u (%s)\n", m_ValueLength, (Entry ? Entry->name : "Unknown"));
+
+ if ( show_value && m_ValueLength < 1000 )
+ Kumu::hexdump(m_ValueStart, Kumu::xmin(m_ValueLength, (ui32_t)128), stream);
+ }
+ else if ( m_UL.HasValue() )
+ {
+ fprintf(stream, "%s\n", m_UL.EncodeString(buf, 64));
+ }
+ else
+ {
+ fprintf(stream, "*** Malformed KLV packet ***\n");
+ }
+}
+
+//
+ASDCP::Result_t
+ASDCP::KLVFilePacket::InitFromFile(const Kumu::FileReader& Reader, const UL& label)
+{
+ Result_t result = KLVFilePacket::InitFromFile(Reader);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = ( UL(m_KeyStart) == label ) ? RESULT_OK : RESULT_FAIL;
+
+ return result;
+}
+
+// TODO: refactor to use InitFromBuffer
+ASDCP::Result_t
+ASDCP::KLVFilePacket::InitFromFile(const Kumu::FileReader& Reader)
+{
+ ui32_t read_count;
+ byte_t tmp_data[tmp_read_size];
+ ui64_t tmp_size;
+ m_KeyStart = m_ValueStart = 0;
+ m_KLLength = m_ValueLength = 0;
+ m_Buffer.Size(0);
+
+ Result_t result = Reader.Read(tmp_data, tmp_read_size, &read_count);
+
+ if ( ASDCP_FAILURE(result) )
+ return result;
+
+ if ( read_count < (SMPTE_UL_LENGTH + 1) )
+ {
+ DefaultLogSink().Error("Short read of Key and Length got %u\n", read_count);
+ return RESULT_READFAIL;
+ }
+
+ if ( memcmp(tmp_data, SMPTE_UL_START, 4) != 0 )
+ {
+ DefaultLogSink().Error("Unexpected UL preamble: %02x.%02x.%02x.%02x\n",
+ tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]);
+ return RESULT_FAIL;
+ }
+
+ if ( ! Kumu::read_BER(tmp_data + SMPTE_UL_LENGTH, &tmp_size) )
+ {
+ DefaultLogSink().Error("BER Length decoding error\n");
+ return RESULT_FAIL;
+ }
+
+ if ( tmp_size > MAX_KLV_PACKET_LENGTH )
+ {
+ 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 = Kumu::BER_length(tmp_data + SMPTE_UL_LENGTH);
+ m_KLLength = SMPTE_UL_LENGTH + ber_len;
+ assert(tmp_size <= 0xFFFFFFFFL);
+ m_ValueLength = (ui32_t) tmp_size;
+ ui32_t packet_length = m_ValueLength + m_KLLength;
+
+ result = m_Buffer.Capacity(packet_length);
+
+ if ( ASDCP_FAILURE(result) )
+ return result;
+
+ m_KeyStart = m_Buffer.Data();
+ m_ValueStart = m_Buffer.Data() + m_KLLength;
+ m_Buffer.Size(packet_length);
+
+ // is the whole packet in the tmp buf?
+ if ( packet_length <= tmp_read_size )
+ {
+ assert(packet_length <= read_count);
+ memcpy(m_Buffer.Data(), tmp_data, packet_length);
+
+ if ( (remainder = read_count - packet_length) != 0 )
+ {
+ DefaultLogSink().Warn("Repositioning pointer for short packet\n");
+ Kumu::fpos_t pos = Reader.Tell();
+ assert(pos > remainder);
+ result = Reader.Seek(pos - remainder);
+ }
+ }
+ else
+ {
+ if ( read_count < tmp_read_size )
+ {
+ DefaultLogSink().Error("Short read of packet body, expecting %u, got %u\n",
+ m_Buffer.Size(), read_count);
+ return RESULT_READFAIL;
+ }
+
+ memcpy(m_Buffer.Data(), tmp_data, tmp_read_size);
+ remainder = m_Buffer.Size() - tmp_read_size;
+
+ if ( remainder > 0 )
+ {
+ result = Reader.Read(m_Buffer.Data() + tmp_read_size, remainder, &read_count);
+
+ if ( read_count != remainder )
+ {
+ DefaultLogSink().Error("Short read of packet body, expecting %u, got %u\n",
+ remainder+tmp_read_size, read_count+tmp_read_size);
+ result = RESULT_READFAIL;
+ }
+ }
+ }
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::KLVFilePacket::WriteKLToFile(Kumu::FileWriter& Writer, const UL& label, ui32_t length)
+{
+ byte_t buffer[kl_length];
+ memcpy(buffer, label.Value(), label.Size());
+
+ if ( ! Kumu::write_BER(buffer+SMPTE_UL_LENGTH, length, MXF_BER_LENGTH) )
+ return RESULT_FAIL;
+
+ ui32_t write_count;
+ Writer.Write(buffer, kl_length, &write_count);
+ assert(write_count == kl_length);
+ return RESULT_OK;
+}
+
+
+//
+// end KLV.cpp
+//
diff --git a/asdcplib/src/KLV.h b/asdcplib/src/KLV.h
new file mode 100755
index 0000000..ec34321
--- /dev/null
+++ b/asdcplib/src/KLV.h
@@ -0,0 +1,256 @@
+/*
+Copyright (c) 2005-2011, 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 KLV.h
+ \version $Id: KLV.h,v 1.25 2012/02/08 02:59:21 jhurst Exp $
+ \brief KLV objects
+*/
+
+#ifndef _KLV_H_
+#define _KLV_H_
+
+#include <KM_fileio.h>
+#include <KM_memio.h>
+#include "AS_DCP.h"
+#include "MDD.h"
+#include <map>
+
+
+namespace ASDCP
+{
+ const ui32_t MXF_BER_LENGTH = 4;
+ const ui32_t MXF_TAG_LENGTH = 2;
+ const ui32_t SMPTE_UL_LENGTH = 16;
+ const ui32_t SMPTE_UMID_LENGTH = 32;
+ const byte_t SMPTE_UL_START[4] = { 0x06, 0x0e, 0x2b, 0x34 };
+
+#ifndef MAX_KLV_PACKET_LENGTH
+ const ui32_t MAX_KLV_PACKET_LENGTH = 1024*1024*64;
+#endif
+
+ 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;
+ byte_t b;
+
+ inline bool operator<(const TagValue& rhs) const {
+ if ( a < rhs.a ) return true;
+ if ( a == rhs.a && b < rhs.b ) return true;
+ return false;
+ }
+
+ inline bool operator==(const TagValue& rhs) const {
+ if ( a != rhs.a ) return false;
+ if ( b != rhs.b ) return false;
+ return true;
+ }
+ };
+
+ using Kumu::UUID;
+
+ // Universal Label
+ class UL : public Kumu::Identifier<SMPTE_UL_LENGTH>
+ {
+ public:
+ UL() {}
+ UL(const UL& rhs) : Kumu::Identifier<SMPTE_UL_LENGTH>(rhs) {}
+ UL(const byte_t* value) : Kumu::Identifier<SMPTE_UL_LENGTH>(value) {}
+ virtual ~UL() {}
+
+ const char* EncodeString(char* str_buf, ui32_t buf_len) const;
+ bool operator==(const UL& rhs) const;
+ bool MatchIgnoreStream(const UL& rhs) const;
+ bool ExactMatch(const UL& rhs) const;
+ };
+
+ // UMID
+ class UMID : public Kumu::Identifier<SMPTE_UMID_LENGTH>
+ {
+ public:
+ UMID() {}
+ UMID(const UMID& rhs) : Kumu::Identifier<SMPTE_UMID_LENGTH>(rhs) {}
+ UMID(const byte_t* value) : Kumu::Identifier<SMPTE_UMID_LENGTH>(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;
+ };
+
+ const byte_t nil_UMID[SMPTE_UMID_LENGTH] = {0};
+ const UMID NilUMID(nil_UMID);
+
+ //
+ struct MDDEntry
+ {
+ byte_t ul[SMPTE_UL_LENGTH];
+ TagValue tag;
+ bool optional;
+ const char* name;
+ };
+
+ const MDDEntry& MXFInterop_OPAtom_Entry();
+ const MDDEntry& SMPTE_390_OPAtom_Entry();
+
+ //
+ class Dictionary
+ {
+ std::map<ASDCP::UL, ui32_t> m_md_lookup;
+ std::map<std::string, ui32_t> m_md_sym_lookup;
+ std::map<ui32_t, ASDCP::UL> m_md_rev_lookup;
+ MDDEntry m_MDD_Table[(ui32_t)ASDCP::MDD_Max];
+
+ ASDCP_NO_COPY_CONSTRUCT(Dictionary);
+
+ public:
+ Dictionary();
+ ~Dictionary();
+
+ // bool operator==(const Dictionary& rhs) const { return this == &rhs; }
+
+ void Init();
+ bool AddEntry(const MDDEntry& Entry, ui32_t index);
+ bool DeleteEntry(ui32_t index);
+
+ const MDDEntry* FindUL(const byte_t*) const;
+ const MDDEntry* FindSymbol(const std::string&) const;
+ const MDDEntry& Type(MDD_t type_id) const;
+
+ inline const byte_t* ul(MDD_t type_id) const {
+ return Type(type_id).ul;
+ }
+
+ void Dump(FILE* = 0) const;
+ };
+
+
+ const Dictionary& DefaultSMPTEDict();
+ const Dictionary& DefaultInteropDict();
+ const Dictionary& DefaultCompositeDict();
+
+
+ //
+ class IPrimerLookup
+ {
+ public:
+ virtual ~IPrimerLookup() {}
+ virtual void ClearTagList() = 0;
+ virtual Result_t InsertTag(const MDDEntry& Entry, ASDCP::TagValue& Tag) = 0;
+ virtual Result_t TagForKey(const ASDCP::UL& Key, ASDCP::TagValue& Tag) = 0;
+ };
+
+ //
+ class KLVPacket
+ {
+ ASDCP_NO_COPY_CONSTRUCT(KLVPacket);
+
+ protected:
+ const byte_t* m_KeyStart;
+ ui32_t m_KLLength;
+ const byte_t* m_ValueStart;
+ ui32_t m_ValueLength;
+ UL m_UL;
+
+ public:
+ KLVPacket() : m_KeyStart(0), m_KLLength(0), m_ValueStart(0), m_ValueLength(0) {}
+ virtual ~KLVPacket() {}
+
+ ui32_t PacketLength() {
+ return m_KLLength + m_ValueLength;
+ }
+
+ ui32_t ValueLength() {
+ return m_ValueLength;
+ }
+
+ ui32_t KLLength() {
+ return m_KLLength;
+ }
+
+ virtual UL GetUL();
+ virtual bool SetUL(const UL&);
+ virtual bool HasUL(const byte_t*);
+ virtual Result_t InitFromBuffer(const byte_t*, ui32_t);
+ virtual Result_t InitFromBuffer(const byte_t*, ui32_t, const UL& label);
+ virtual Result_t WriteKLToBuffer(ASDCP::FrameBuffer&, const UL& label, ui32_t length);
+ virtual Result_t WriteKLToBuffer(ASDCP::FrameBuffer& fb, ui32_t length) {
+ if ( ! m_UL.HasValue() )
+ return RESULT_STATE;
+ return WriteKLToBuffer(fb, m_UL, length); }
+
+ virtual void Dump(FILE*, const Dictionary& Dict, bool show_value);
+ };
+
+ //
+ class KLVFilePacket : public KLVPacket
+ {
+ ASDCP_NO_COPY_CONSTRUCT(KLVFilePacket);
+
+ protected:
+ ASDCP::FrameBuffer m_Buffer;
+
+ public:
+ KLVFilePacket() {}
+ virtual ~KLVFilePacket() {}
+
+ virtual Result_t InitFromFile(const Kumu::FileReader&);
+ virtual Result_t InitFromFile(const Kumu::FileReader&, const UL& label);
+ virtual Result_t WriteKLToFile(Kumu::FileWriter& Writer, const UL& label, ui32_t length);
+ };
+
+} // namespace ASDCP
+
+#endif // _KLV_H_
+
+
+//
+// end KLV.h
+//
diff --git a/asdcplib/src/KM_error.h b/asdcplib/src/KM_error.h
new file mode 100755
index 0000000..7639797
--- /dev/null
+++ b/asdcplib/src/KM_error.h
@@ -0,0 +1,171 @@
+/*
+Copyright (c) 2004-2011, 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: KM_error.h,v 1.12 2011/05/16 04:33:31 jhurst Exp $
+ \brief error reporting support
+ */
+
+
+
+#ifndef _KM_ERROR_H_
+#define _KM_ERROR_H_
+
+#define KM_DECLARE_RESULT(sym, i, l) const Result_t RESULT_##sym = Result_t(i, #sym, l);
+
+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
+ {
+ int value;
+ const char* label;
+ const char* symbol;
+ Result_t();
+
+ public:
+ // Return registered Result_t for the given "value" code.
+ static const Result_t& Find(int value);
+
+ // Unregister the Result_t matching the given "value" code. Returns
+ // RESULT_FALSE if "value" does not match a registered Result_t.
+ // Returns RESULT_FAIL if ( value < -99 || value > 99 ) (Kumu core
+ // codes may not be deleted).
+ static Result_t Delete(int value);
+
+ // Iteration through registered result codes, not thread safe.
+ // Get accepts contiguous values from 0 to End() - 1.
+ static unsigned int End();
+ static const Result_t& Get(unsigned int);
+
+ Result_t(int v, const char* s, const char* l);
+ ~Result_t();
+
+ 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() const { return ( value >= 0 ); }
+ inline bool Failure() const { return ( value < 0 ); }
+
+ inline int Value() const { return value; }
+ inline operator int() const { return value; }
+
+ inline const char* Label() const { return label; }
+ inline operator const char*() const { return label; }
+
+ inline const char* Symbol() const { return symbol; }
+ };
+
+ KM_DECLARE_RESULT(FALSE, 1, "Successful but not true.");
+ KM_DECLARE_RESULT(OK, 0, "Success.");
+ KM_DECLARE_RESULT(FAIL, -1, "An undefined error was detected.");
+ KM_DECLARE_RESULT(PTR, -2, "An unexpected NULL pointer was given.");
+ KM_DECLARE_RESULT(NULL_STR, -3, "An unexpected empty string was given.");
+ KM_DECLARE_RESULT(ALLOC, -4, "Error allocating memory.");
+ KM_DECLARE_RESULT(PARAM, -5, "Invalid parameter.");
+ KM_DECLARE_RESULT(NOTIMPL, -6, "Unimplemented Feature.");
+ KM_DECLARE_RESULT(SMALLBUF, -7, "The given buffer is too small.");
+ KM_DECLARE_RESULT(INIT, -8, "The object is not yet initialized.");
+ KM_DECLARE_RESULT(NOT_FOUND, -9, "The requested file does not exist on the system.");
+ KM_DECLARE_RESULT(NO_PERM, -10, "Insufficient privilege exists to perform the operation.");
+ KM_DECLARE_RESULT(STATE, -11, "Object state error.");
+ KM_DECLARE_RESULT(CONFIG, -12, "Invalid configuration option detected.");
+ KM_DECLARE_RESULT(FILEOPEN, -13, "File open failure.");
+ KM_DECLARE_RESULT(BADSEEK, -14, "An invalid file location was requested.");
+ KM_DECLARE_RESULT(READFAIL, -15, "File read error.");
+ KM_DECLARE_RESULT(WRITEFAIL, -16, "File write error.");
+ KM_DECLARE_RESULT(ENDOFFILE, -17, "Attempt to read past end of file.");
+ KM_DECLARE_RESULT(FILEEXISTS, -18, "Filename already exists.");
+ KM_DECLARE_RESULT(NOTAFILE, -19, "Filename not found.");
+ KM_DECLARE_RESULT(UNKNOWN, -20, "Unknown result code.");
+ KM_DECLARE_RESULT(DIR_CREATE, -21, "Unable to create directory.");
+ // -22 is reserved
+
+} // 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; \
+ }
+
+namespace Kumu
+{
+ // simple tracing mechanism
+ class DTrace_t
+ {
+ DTrace_t();
+
+ protected:
+ const char* m_Label;
+ Result_t* m_Watch;
+ int m_Line;
+ const char* m_File;
+ int m_Sequence;
+
+ public:
+ DTrace_t(const char* Label, Result_t* Watch, int Line, const char* File);
+ ~DTrace_t();
+ };
+}
+
+#ifdef KM_TRACE
+#define WDTRACE(l) DTrace_t __wl__Trace__((l), 0, __LINE__, __FILE__)
+#define WDTRACER(l,r) DTrace_t __wl__Trace__((l), &(r), __LINE__, __FILE__)
+#else
+#define WDTRACE(l)
+#define WDTRACER(l,r)
+#endif
+
+
+#endif // _KM_ERROR_H_
+
+//
+// end KM_error.h
+//
diff --git a/asdcplib/src/KM_fileio.cpp b/asdcplib/src/KM_fileio.cpp
new file mode 100644
index 0000000..b20ff7f
--- /dev/null
+++ b/asdcplib/src/KM_fileio.cpp
@@ -0,0 +1,1546 @@
+/*
+Copyright (c) 2004-2011, 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: KM_fileio.cpp,v 1.31 2011/03/08 19:03:47 jhurst Exp $
+ \brief portable file i/o
+ */
+
+#include <KM_fileio.h>
+#include <KM_log.h>
+#include <fcntl.h>
+#include <sstream>
+#include <iomanip>
+
+#include <assert.h>
+
+#ifdef KM_WIN32
+#include <direct.h>
+#else
+#define _getcwd getcwd
+#define _unlink unlink
+#define _rmdir rmdir
+#endif
+
+using namespace Kumu;
+
+#ifdef KM_WIN32
+typedef struct _stati64 fstat_t;
+#define S_IFLNK 0
+
+// win32 has WriteFileGather() and ReadFileScatter() but they
+// demand page alignment and page sizing, making them unsuitable
+// for use with arbitrary buffer sizes.
+struct iovec {
+ char* iov_base; // stupid iovec uses char*
+ int iov_len;
+};
+#else
+# if defined(__linux__)
+# include <sys/statfs.h>
+# else
+# include <sys/param.h>
+# include <sys/mount.h>
+# endif
+
+#include <sys/stat.h>
+#include <sys/uio.h>
+typedef struct stat fstat_t;
+#endif
+
+//
+static void
+split(const std::string& str, char separator, std::list<std::string>& components)
+{
+ const char* pstr = str.c_str();
+ const char* r = strchr(pstr, separator);
+
+ while ( r != 0 )
+ {
+ assert(r >= pstr);
+ if ( r > pstr )
+ {
+ std::string tmp_str;
+ tmp_str.assign(pstr, (r - pstr));
+ components.push_back(tmp_str);
+ }
+
+ pstr = r + 1;
+ r = strchr(pstr, separator);
+ }
+
+ if( strlen(pstr) > 0 )
+ components.push_back(std::string(pstr));
+}
+
+
+//
+static Kumu::Result_t
+do_stat(const char* path, fstat_t* stat_info)
+{
+ KM_TEST_NULL_STR_L(path);
+ KM_TEST_NULL_L(stat_info);
+
+ Kumu::Result_t result = Kumu::RESULT_OK;
+
+#ifdef KM_WIN32
+ UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
+
+ int const wn = MultiByteToWideChar (CP_UTF8, 0, path, -1, 0, 0);
+ wchar_t* buffer = new wchar_t[wn];
+ if (MultiByteToWideChar (CP_UTF8, 0, path, -1, buffer, wn) == 0) {
+ delete[] buffer;
+ return Kumu::RESULT_FAIL;
+ }
+
+ if ( _wstati64(buffer, stat_info) == (__int64)-1 )
+ result = Kumu::RESULT_FILEOPEN;
+
+ delete[] buffer;
+
+ ::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(FileHandle handle, fstat_t* stat_info)
+{
+ KM_TEST_NULL_L(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::PathExists(const std::string& pathname)
+{
+ if ( pathname.empty() )
+ return false;
+
+ fstat_t info;
+
+ if ( KM_SUCCESS(do_stat(pathname.c_str(), &info)) )
+ return true;
+
+ return false;
+}
+
+//
+bool
+Kumu::PathIsFile(const std::string& pathname)
+{
+ if ( pathname.empty() )
+ return false;
+
+ fstat_t info;
+
+ if ( KM_SUCCESS(do_stat(pathname.c_str(), &info)) )
+ {
+ if ( info.st_mode & ( S_IFREG|S_IFLNK ) )
+ return true;
+ }
+
+ return false;
+}
+
+
+//
+bool
+Kumu::PathIsDirectory(const std::string& pathname)
+{
+ if ( pathname.empty() )
+ return false;
+
+ fstat_t info;
+
+ if ( KM_SUCCESS(do_stat(pathname.c_str(), &info)) )
+ {
+ if ( info.st_mode & S_IFDIR )
+ return true;
+ }
+
+ return false;
+}
+
+//
+Kumu::fsize_t
+Kumu::FileSize(const std::string& pathname)
+{
+ if ( pathname.empty() )
+ return 0;
+
+ fstat_t info;
+
+ if ( KM_SUCCESS(do_stat(pathname.c_str(), &info)) )
+ {
+ if ( info.st_mode & ( S_IFREG|S_IFLNK ) )
+ return(info.st_size);
+ }
+
+ return 0;
+}
+
+//
+static PathCompList_t&
+s_PathMakeCanonical(PathCompList_t& CList, bool is_absolute)
+{
+ PathCompList_t::iterator ci, ri; // component and removal iterators
+
+ for ( ci = CList.begin(); ci != CList.end(); ci++ )
+ {
+ if ( *ci == "." && ( CList.size() > 1 || is_absolute ) )
+ {
+ ri = ci++;
+ CList.erase(ri);
+ }
+ else if ( *ci == ".." && ci != CList.begin() )
+ {
+ ri = ci;
+ ri--;
+
+ if ( *ri != ".." )
+ {
+ CList.erase(ri);
+ ri = ci++;
+ CList.erase(ri);
+ }
+ }
+ }
+
+ return CList;
+}
+
+//
+std::string
+Kumu::PathMakeCanonical(const std::string& Path, char separator)
+{
+ PathCompList_t CList;
+ bool is_absolute = PathIsAbsolute(Path, separator);
+ s_PathMakeCanonical(PathToComponents(Path, CList, separator), is_absolute);
+
+ if ( is_absolute )
+ return ComponentsToAbsolutePath(CList, separator);
+
+ return ComponentsToPath(CList, separator);
+}
+
+//
+bool
+Kumu::PathsAreEquivalent(const std::string& lhs, const std::string& rhs)
+{
+ return PathMakeCanonical(lhs) == PathMakeCanonical(rhs);
+}
+
+//
+Kumu::PathCompList_t&
+Kumu::PathToComponents(const std::string& Path, PathCompList_t& CList, char separator)
+{
+ split(Path, separator, CList);
+ return CList;
+}
+
+//
+std::string
+Kumu::ComponentsToPath(const PathCompList_t& CList, char separator)
+{
+ if ( CList.empty() )
+ return "";
+
+ PathCompList_t::const_iterator ci = CList.begin();
+ std::string out_path = *ci;
+
+ for ( ci++; ci != CList.end(); ci++ )
+ out_path += separator + *ci;
+
+ return out_path;
+}
+
+//
+std::string
+Kumu::ComponentsToAbsolutePath(const PathCompList_t& CList, char separator)
+{
+ std::string out_path;
+
+ if ( CList.empty() )
+ out_path = separator;
+ else
+ {
+ PathCompList_t::const_iterator ci;
+
+ for ( ci = CList.begin(); ci != CList.end(); ci++ )
+ out_path += separator + *ci;
+ }
+
+ return out_path;
+}
+
+//
+bool
+Kumu::PathHasComponents(const std::string& Path, char separator)
+{
+ if ( strchr(Path.c_str(), separator) == 0 )
+ return false;
+
+ return true;
+}
+
+//
+bool
+Kumu::PathIsAbsolute(const std::string& Path, char separator)
+{
+ if ( Path.empty() )
+ return false;
+
+ if ( Path[0] == separator)
+ return true;
+
+ return false;
+}
+
+//
+std::string
+Kumu::PathMakeAbsolute(const std::string& Path, char separator)
+{
+ if ( Path.empty() )
+ {
+ std::string out_path;
+ out_path = separator;
+ return out_path;
+ }
+
+ if ( PathIsAbsolute(Path, separator) )
+ return Path;
+
+ char cwd_buf [MaxFilePath];
+ if ( _getcwd(cwd_buf, MaxFilePath) == 0 )
+ {
+ DefaultLogSink().Error("Error retrieving current working directory.");
+ return "";
+ }
+
+ PathCompList_t CList;
+ PathToComponents(cwd_buf, CList);
+ CList.push_back(Path);
+
+ return ComponentsToAbsolutePath(s_PathMakeCanonical(CList, true), separator);
+}
+
+//
+std::string
+Kumu::PathMakeLocal(const std::string& Path, const std::string& Parent)
+{
+ size_t pos = Path.find(Parent);
+
+ if ( pos == 0 ) // Parent found at offset 0
+ return Path.substr(Parent.size()+1);
+
+ return Path;
+}
+
+//
+std::string
+Kumu::PathBasename(const std::string& Path, char separator)
+{
+ PathCompList_t CList;
+ PathToComponents(Path, CList, separator);
+
+ if ( CList.empty() )
+ return "";
+
+ return CList.back();
+}
+
+//
+std::string
+Kumu::PathDirname(const std::string& Path, char separator)
+{
+ PathCompList_t CList;
+ bool is_absolute = PathIsAbsolute(Path, separator);
+ PathToComponents(Path, CList, separator);
+
+ if ( CList.empty() )
+ return is_absolute ? "/" : "";
+
+ CList.pop_back();
+
+ if ( is_absolute )
+ return ComponentsToAbsolutePath(CList, separator);
+
+ return ComponentsToPath(CList, separator);
+}
+
+//
+std::string
+Kumu::PathGetExtension(const std::string& Path)
+{
+ std::string Basename = PathBasename(Path);
+ const char* p = strrchr(Basename.c_str(), '.');
+
+ if ( p++ == 0 )
+ return "";
+
+ return p;
+}
+
+//
+std::string
+Kumu::PathSetExtension(const std::string& Path, const std::string& Extension) // empty extension removes
+{
+ std::string Basename = PathBasename(Path);
+ const char* p = strrchr(Basename.c_str(), '.');
+
+ if ( p != 0 )
+ Basename = Basename.substr(0, p - Basename.c_str());
+
+ if ( Extension.empty() )
+ return Basename;
+
+ return Basename + "." + Extension;
+}
+
+//
+std::string
+Kumu::PathJoin(const std::string& Path1, const std::string& Path2, char separator)
+{
+ return Path1 + separator + Path2;
+}
+
+//
+std::string
+Kumu::PathJoin(const std::string& Path1, const std::string& Path2, const std::string& Path3, char separator)
+{
+ return Path1 + separator + Path2 + separator + Path3;
+}
+
+//
+std::string
+Kumu::PathJoin(const std::string& Path1, const std::string& Path2,
+ const std::string& Path3, const std::string& Path4, char separator)
+{
+ return Path1 + separator + Path2 + separator + Path3 + separator + Path4;
+}
+
+//
+Kumu::PathList_t&
+Kumu::FindInPaths(const IPathMatch& Pattern, const Kumu::PathList_t& SearchPaths,
+ Kumu::PathList_t& FoundPaths, bool one_shot, char separator)
+{
+ PathList_t::const_iterator si;
+ for ( si = SearchPaths.begin(); si != SearchPaths.end(); si++ )
+ {
+ FindInPath(Pattern, *si, FoundPaths, one_shot, separator);
+
+ if ( one_shot && ! FoundPaths.empty() )
+ break;
+ }
+
+ return FoundPaths;
+}
+
+//
+Kumu::PathList_t&
+Kumu::FindInPath(const IPathMatch& Pattern, const std::string& SearchDir,
+ Kumu::PathList_t& FoundPaths, bool one_shot, char separator)
+{
+ char name_buf[MaxFilePath];
+ DirScanner Dir;
+
+ if ( KM_SUCCESS(Dir.Open(SearchDir.c_str())) )
+ {
+ while ( KM_SUCCESS(Dir.GetNext(name_buf)) )
+ {
+ if ( name_buf[0] == '.' ) continue; // no hidden files
+ std::string tmp_path = SearchDir + separator + name_buf;
+
+ if ( PathIsDirectory(tmp_path.c_str()) )
+ FindInPath(Pattern, tmp_path, FoundPaths, one_shot, separator);
+
+ else if ( Pattern.Match(name_buf) )
+ {
+ FoundPaths.push_back(SearchDir + separator + name_buf);
+ if ( one_shot )
+ break;
+ }
+ }
+ }
+
+ return FoundPaths;
+}
+
+
+#ifndef KM_WIN32
+
+//
+Kumu::PathMatchRegex::PathMatchRegex(const std::string& s)
+{
+ int result = regcomp(&m_regex, s.c_str(), REG_NOSUB); // (REG_EXTENDED|REG_NOSUB|REG_NEWLINE));
+
+ if ( result )
+ {
+ char buf[128];
+ regerror(result, &m_regex, buf, 128);
+ DefaultLogSink().Error("PathMatchRegex: %s\n", buf);
+ regfree(&m_regex);
+ }
+}
+
+Kumu::PathMatchRegex::PathMatchRegex(const PathMatchRegex& rhs) : IPathMatch() {
+ m_regex = rhs.m_regex;
+}
+
+Kumu::PathMatchRegex::~PathMatchRegex() {
+ regfree(&m_regex);
+}
+
+bool
+Kumu::PathMatchRegex::Match(const std::string& s) const {
+ return ( regexec(&m_regex, s.c_str(), 0, 0, 0) == 0 );
+}
+
+
+
+//
+Kumu::PathMatchGlob::PathMatchGlob(const std::string& glob)
+{
+ std::string regex; // convert glob to regex
+
+ for ( const char* p = glob.c_str(); *p != 0; p++ )
+ {
+ switch (*p)
+ {
+ case '.': regex += "\\."; break;
+ case '*': regex += ".*"; break;
+ case '?': regex += ".?"; break;
+ default: regex += *p;
+ }
+ }
+ regex += '$';
+
+ int result = regcomp(&m_regex, regex.c_str(), REG_NOSUB);
+
+ if ( result )
+ {
+ char buf[128];
+ regerror(result, &m_regex, buf, 128);
+ DefaultLogSink().Error("PathMatchRegex: %s\n", buf);
+ regfree(&m_regex);
+ }
+}
+
+Kumu::PathMatchGlob::PathMatchGlob(const PathMatchGlob& rhs) : IPathMatch() {
+ m_regex = rhs.m_regex;
+}
+
+Kumu::PathMatchGlob::~PathMatchGlob() {
+ regfree(&m_regex);
+}
+
+bool
+Kumu::PathMatchGlob::Match(const std::string& s) const {
+ return ( regexec(&m_regex, s.c_str(), 0, 0, 0) == 0 );
+}
+
+#endif
+
+//------------------------------------------------------------------------------------------
+// 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|S_IFLNK ) )
+ 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()
+ : m_Hashing (false)
+{}
+
+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_L(buf);
+
+ if ( iov->m_Count >= IOVecMaxEntries )
+ {
+ DefaultLogSink().Error("The iovec is full! Only %u entries allowed before a flush.\n",
+ IOVecMaxEntries);
+ return RESULT_WRITEFAIL;
+ }
+
+ 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;
+}
+
+void
+Kumu::FileWriter::StartHashing()
+{
+ m_Hashing = true;
+ MD5_Init (&m_MD5Context);
+}
+
+void
+Kumu::FileWriter::MaybeHash(void const * data, int size)
+{
+ if (m_Hashing) {
+ MD5_Update (&m_MD5Context, data, size);
+ }
+}
+
+std::string
+Kumu::FileWriter::StopHashing()
+{
+ m_Hashing = false;
+
+ unsigned char digest[MD5_DIGEST_LENGTH];
+ MD5_Final (digest, &m_MD5Context);
+
+ std::stringstream s;
+ for (int i = 0; i < MD5_DIGEST_LENGTH; ++i) {
+ s << std::hex << std::setfill('0') << std::setw(2) << ((int) digest[i]);
+ }
+
+ return s.str ();
+}
+
+
+#ifdef KM_WIN32
+//------------------------------------------------------------------------------------------
+//
+
+/** @param filename File name (UTF-8 encoded) */
+Kumu::Result_t
+Kumu::FileReader::OpenRead(const char* filename) const
+{
+ KM_TEST_NULL_STR_L(filename);
+ const_cast<FileReader*>(this)->m_Filename = filename;
+
+ // suppress popup window on error
+ UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
+
+ int const wn = MultiByteToWideChar (CP_UTF8, 0, filename, -1, 0, 0);
+ wchar_t* buffer = new wchar_t[wn];
+ if (MultiByteToWideChar (CP_UTF8, 0, filename, -1, buffer, wn) == 0) {
+ delete[] buffer;
+ return Kumu::RESULT_FAIL;
+ }
+ const_cast<FileReader*>(this)->m_Handle = ::CreateFileW(buffer,
+ (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
+ );
+
+ delete[] buffer;
+
+ ::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_L(pos);
+
+ if ( m_Handle == INVALID_HANDLE_VALUE )
+ 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_L(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;
+}
+
+
+
+//------------------------------------------------------------------------------------------
+//
+
+/** @param filename File name (UTF-8 encoded) */
+Kumu::Result_t
+Kumu::FileWriter::OpenWrite(const char* filename)
+{
+ KM_TEST_NULL_STR_L(filename);
+ m_Filename = filename;
+
+ // suppress popup window on error
+ UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
+
+ int const wn = MultiByteToWideChar (CP_UTF8, 0, filename, -1, 0, 0);
+ wchar_t* buffer = new wchar_t[wn];
+ if (MultiByteToWideChar (CP_UTF8, 0, filename, -1, buffer, wn) == 0) {
+ delete[] buffer;
+ return Kumu::RESULT_FAIL;
+ }
+
+ m_Handle = ::CreateFileW(buffer,
+ (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
+ );
+
+ delete[] buffer;
+
+ ::SetErrorMode(prev);
+
+ if ( m_Handle == INVALID_HANDLE_VALUE )
+ return Kumu::RESULT_FILEOPEN;
+
+ m_IOVec = new h__iovec;
+ return Kumu::RESULT_OK;
+}
+
+/** @param filename File name (UTF-8 encoded) */
+Kumu::Result_t
+Kumu::FileWriter::OpenModify(const char* filename)
+{
+ KM_TEST_NULL_STR_L(filename);
+ m_Filename = filename;
+
+ // suppress popup window on error
+ UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
+
+ int const wn = MultiByteToWideChar (CP_UTF8, 0, filename, -1, 0, 0);
+ wchar_t* buffer = new wchar_t[wn];
+ if (MultiByteToWideChar (CP_UTF8, 0, filename, -1, buffer, wn) == 0) {
+ delete[] buffer;
+ return Kumu::RESULT_FAIL;
+ }
+
+ m_Handle = ::CreateFileW(buffer,
+ (GENERIC_WRITE|GENERIC_READ), // open for reading
+ FILE_SHARE_READ, // share for reading
+ NULL, // no security
+ OPEN_ALWAYS, // don't truncate existing
+ FILE_ATTRIBUTE_NORMAL, // normal file
+ NULL // no template file
+ );
+
+ delete[] buffer;
+
+ ::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 || tmp_count != iov->m_iovec[i].iov_len)
+ {
+ result = Kumu::RESULT_WRITEFAIL;
+ break;
+ }
+
+ MaybeHash (iov->m_iovec[i].iov_base, iov->m_iovec[i].iov_len);
+ *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_L(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);
+
+ if ( result == 0 || *bytes_written != buf_len )
+ return Kumu::RESULT_WRITEFAIL;
+
+ MaybeHash (buf, buf_len);
+
+ return Kumu::RESULT_OK;
+}
+
+#else // KM_WIN32
+//------------------------------------------------------------------------------------------
+// POSIX
+
+//
+Kumu::Result_t
+Kumu::FileReader::OpenRead(const char* filename) const
+{
+ KM_TEST_NULL_STR_L(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_L(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_L(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_L(filename);
+ m_Filename = filename;
+ m_Handle = open(filename, O_RDWR|O_CREAT|O_TRUNC, 0664);
+
+ 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_L(filename);
+ m_Filename = filename;
+ m_Handle = open(filename, O_RDWR|O_CREAT, 0664);
+
+ 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 total_size = 0;
+ for ( int i = 0; i < iov->m_Count; i++ )
+ total_size += iov->m_iovec[i].iov_len;
+
+ int write_size = writev(m_Handle, iov->m_iovec, iov->m_Count);
+
+ if ( write_size == -1L || write_size != total_size )
+ return RESULT_WRITEFAIL;
+
+ for (int i = 0; i < iov->m_Count; ++i) {
+ MaybeHash (iov->m_iovec[i].iov_base, iov->m_iovec[i].iov_len);
+ }
+
+ iov->m_Count = 0;
+ *bytes_written = write_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_L(buf);
+ ui32_t tmp_int;
+
+ if ( bytes_written == 0 )
+ bytes_written = &tmp_int;
+
+ if ( m_Handle == -1L )
+ return RESULT_STATE;
+
+ int write_size = write(m_Handle, buf, buf_len);
+ MaybeHash (buf, buf_len);
+
+ if ( write_size == -1L || (ui32_t)write_size != buf_len )
+ return RESULT_WRITEFAIL;
+
+ *bytes_written = write_size;
+ return RESULT_OK;
+}
+
+
+#endif
+
+//------------------------------------------------------------------------------------------
+
+
+//
+Kumu::Result_t
+Kumu::ReadFileIntoString(const char* filename, std::string& outString, ui32_t max_size)
+{
+ fsize_t fsize = 0;
+ ui32_t read_size = 0;
+ FileReader File;
+ ByteString ReadBuf;
+
+ KM_TEST_NULL_STR_L(filename);
+
+ Result_t result = File.OpenRead(filename);
+
+ if ( KM_SUCCESS(result) )
+ {
+ fsize = File.Size();
+
+ if ( fsize > (Kumu::fpos_t)max_size )
+ {
+ DefaultLogSink().Error("%s: exceeds available buffer size (%u)\n", filename, max_size);
+ return RESULT_ALLOC;
+ }
+
+ if ( fsize == 0 )
+ {
+ DefaultLogSink().Error("%s: zero file size\n", filename);
+ return RESULT_READFAIL;
+ }
+
+ 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;
+}
+
+
+//
+Kumu::Result_t
+Kumu::WriteStringIntoFile(const char* filename, const std::string& inString)
+{
+ FileWriter File;
+ ui32_t write_count = 0;
+ KM_TEST_NULL_STR_L(filename);
+
+ Result_t result = File.OpenWrite(filename);
+
+ if ( KM_SUCCESS(result) )
+ result = File.Write((byte_t*)inString.c_str(), inString.length(), &write_count);
+
+ return result;
+}
+
+//------------------------------------------------------------------------------------------
+
+
+//
+Kumu::Result_t
+Kumu::ReadFileIntoObject(const std::string& Filename, Kumu::IArchive& Object, ui32_t)
+{
+ ByteString Buffer;
+ ui32_t file_size = static_cast<ui32_t>(FileSize(Filename));
+ Result_t result = Buffer.Capacity(file_size);
+
+ if ( KM_SUCCESS(result) )
+ {
+ ui32_t read_count = 0;
+ FileWriter Reader;
+
+ result = Reader.OpenRead(Filename.c_str());
+
+ if ( KM_SUCCESS(result) )
+ result = Reader.Read(Buffer.Data(), file_size, &read_count);
+
+ if ( KM_SUCCESS(result) )
+ {
+ assert(file_size == read_count);
+ Buffer.Length(read_count);
+ MemIOReader MemReader(&Buffer);
+ result = Object.Unarchive(&MemReader) ? RESULT_OK : RESULT_READFAIL;
+ }
+ }
+
+ return result;
+}
+
+//
+Kumu::Result_t
+Kumu::WriteObjectIntoFile(const Kumu::IArchive& Object, const std::string& Filename)
+{
+ ByteString Buffer;
+ Result_t result = Buffer.Capacity(Object.ArchiveLength());
+
+ if ( KM_SUCCESS(result) )
+ {
+ ui32_t write_count = 0;
+ FileWriter Writer;
+ MemIOWriter MemWriter(&Buffer);
+
+ result = Object.Archive(&MemWriter) ? RESULT_OK : RESULT_WRITEFAIL;
+
+ if ( KM_SUCCESS(result) )
+ {
+ Buffer.Length(MemWriter.Length());
+ result = Writer.OpenWrite(Filename.c_str());
+ }
+
+ if ( KM_SUCCESS(result) )
+ result = Writer.Write(Buffer.RoData(), Buffer.Length(), &write_count);
+ }
+
+ return result;
+}
+
+//------------------------------------------------------------------------------------------
+//
+
+//
+Result_t
+Kumu::ReadFileIntoBuffer(const std::string& Filename, Kumu::ByteString& Buffer, ui32_t)
+{
+ ui32_t file_size = FileSize(Filename);
+ Result_t result = Buffer.Capacity(file_size);
+
+ if ( KM_SUCCESS(result) )
+ {
+ ui32_t read_count = 0;
+ FileWriter Reader;
+
+ result = Reader.OpenRead(Filename.c_str());
+
+ if ( KM_SUCCESS(result) )
+ result = Reader.Read(Buffer.Data(), file_size, &read_count);
+
+ if ( KM_SUCCESS(result) )
+ {
+ if ( file_size != read_count)
+ return RESULT_READFAIL;
+
+ Buffer.Length(read_count);
+ }
+ }
+
+ return result;
+}
+
+//
+Result_t
+Kumu::WriteBufferIntoFile(const Kumu::ByteString& Buffer, const std::string& Filename)
+{
+ ui32_t write_count = 0;
+ FileWriter Writer;
+
+ Result_t result = Writer.OpenWrite(Filename.c_str());
+
+ if ( KM_SUCCESS(result) )
+ result = Writer.Write(Buffer.RoData(), Buffer.Length(), &write_count);
+
+ if ( KM_SUCCESS(result) && Buffer.Length() != write_count)
+ return RESULT_WRITEFAIL;
+
+ return result;
+}
+
+//------------------------------------------------------------------------------------------
+//
+
+Kumu::DirScanner::DirScanner()
+{
+
+}
+
+Result_t
+Kumu::DirScanner::Open (const char* filename)
+{
+ KM_TEST_NULL_L (filename);
+
+ if (!boost::filesystem::is_directory(filename)) {
+ return RESULT_NOT_FOUND;
+ }
+
+ _iterator = boost::filesystem::directory_iterator (filename);
+ return RESULT_OK;
+}
+
+Result_t
+Kumu::DirScanner::GetNext (char* filename)
+{
+ KM_TEST_NULL_L (filename);
+
+ if (_iterator == boost::filesystem::directory_iterator()) {
+ return RESULT_ENDOFFILE;
+ }
+
+#if BOOST_FILESYSTEM_VERSION == 3
+ std::string f = boost::filesystem::path(*_iterator).filename().generic_string();
+#else
+ std::string f = boost::filesystem::path(*_iterator).filename();
+#endif
+ strncpy (filename, f.c_str(), MaxFilePath);
+ ++_iterator;
+ return RESULT_OK;
+}
+
+//------------------------------------------------------------------------------------------
+
+//
+// Attention Windows users: make sure to use the proper separator character
+// with these functions.
+//
+
+// given a path string, create any missing directories so that PathIsDirectory(Path) is true.
+//
+Result_t
+Kumu::CreateDirectoriesInPath(const std::string& Path)
+{
+ bool abs = PathIsAbsolute(Path);
+ PathCompList_t PathComps, TmpPathComps;
+
+ PathToComponents(Path, PathComps);
+
+ while ( ! PathComps.empty() )
+ {
+ TmpPathComps.push_back(PathComps.front());
+ PathComps.pop_front();
+ std::string tmp_path = abs ? ComponentsToAbsolutePath(TmpPathComps) : ComponentsToPath(TmpPathComps);
+
+ if ( ! PathIsDirectory(tmp_path) )
+ {
+#ifdef KM_WIN32
+ if ( _mkdir(tmp_path.c_str()) != 0 )
+#else // KM_WIN32
+ if ( mkdir(tmp_path.c_str(), 0775) != 0 )
+#endif // KM_WIN32
+ {
+ DefaultLogSink().Error("CreateDirectoriesInPath mkdir %s: %s\n",
+ tmp_path.c_str(), strerror(errno));
+ return RESULT_DIR_CREATE;
+ }
+ }
+ }
+
+ return RESULT_OK;
+}
+
+
+//
+Result_t
+Kumu::DeleteFile(const std::string& filename)
+{
+ if ( _unlink(filename.c_str()) == 0 )
+ return RESULT_OK;
+
+ switch ( errno )
+ {
+ case ENOENT:
+ case ENOTDIR: return RESULT_NOTAFILE;
+
+ case EROFS:
+ case EBUSY:
+ case EACCES:
+ case EPERM: return RESULT_NO_PERM;
+ }
+
+ DefaultLogSink().Error("DeleteFile %s: %s\n", filename.c_str(), strerror(errno));
+ return RESULT_FAIL;
+}
+
+//
+Result_t
+h__DeletePath(const std::string& pathname)
+{
+ if ( pathname.empty() )
+ return RESULT_NULL_STR;
+
+ Result_t result = RESULT_OK;
+
+ if ( ! PathIsDirectory(pathname) )
+ {
+ result = DeleteFile(pathname);
+ }
+ else
+ {
+ {
+ DirScanner TestDir;
+ char next_file[Kumu::MaxFilePath];
+ result = TestDir.Open(pathname.c_str());
+
+ while ( KM_SUCCESS(result) && KM_SUCCESS(TestDir.GetNext(next_file)) )
+ {
+ if ( next_file[0] == '.' )
+ {
+ if ( next_file[1] == 0 )
+ continue; // don't delete 'this'
+
+ if ( next_file[1] == '.' && next_file[2] == 0 )
+ continue; // don't delete 'this' parent
+ }
+
+ result = h__DeletePath(pathname + std::string("/") + next_file);
+ }
+ }
+
+ if ( _rmdir(pathname.c_str()) != 0 )
+ {
+ switch ( errno )
+ {
+ case ENOENT:
+ case ENOTDIR:
+ result = RESULT_NOTAFILE;
+ break;
+
+ case EROFS:
+ case EBUSY:
+ case EACCES:
+ case EPERM:
+ result = RESULT_NO_PERM;
+ break;
+
+ default:
+ DefaultLogSink().Error("DeletePath %s: %s\n", pathname.c_str(), strerror(errno));
+ result = RESULT_FAIL;
+ }
+ }
+ }
+
+ return result;
+}
+
+//
+Result_t
+Kumu::DeletePath(const std::string& pathname)
+{
+ std::string c_pathname = PathMakeAbsolute(PathMakeCanonical(pathname));
+ DefaultLogSink().Debug("DeletePath (%s) c(%s)\n", pathname.c_str(), c_pathname.c_str());
+ return h__DeletePath(c_pathname);
+}
+
+
+//------------------------------------------------------------------------------------------
+//
+
+
+Result_t
+Kumu::FreeSpaceForPath(const std::string& path, Kumu::fsize_t& free_space, Kumu::fsize_t& total_space)
+{
+#ifdef KM_WIN32
+ ULARGE_INTEGER lTotalNumberOfBytes;
+ ULARGE_INTEGER lTotalNumberOfFreeBytes;
+
+ BOOL fResult = ::GetDiskFreeSpaceExA(path.c_str(), NULL, &lTotalNumberOfBytes, &lTotalNumberOfFreeBytes);
+ if (fResult) {
+ free_space = static_cast<Kumu::fsize_t>(lTotalNumberOfFreeBytes.QuadPart);
+ total_space = static_cast<Kumu::fsize_t>(lTotalNumberOfBytes.QuadPart);
+ return RESULT_OK;
+ }
+ HRESULT LastError = ::GetLastError();
+
+ DefaultLogSink().Error("FreeSpaceForPath GetDiskFreeSpaceEx %s: %lu\n", path.c_str(), ::GetLastError());
+ return RESULT_FAIL;
+#else // KM_WIN32
+ struct statfs s;
+
+ if ( statfs(path.c_str(), &s) == 0 )
+ {
+ if ( s.f_blocks < 1 )
+ {
+ DefaultLogSink().Error("File system %s has impossible size: %ld\n",
+ path.c_str(), s.f_blocks);
+ return RESULT_FAIL;
+ }
+
+ free_space = (Kumu::fsize_t)s.f_bsize * (Kumu::fsize_t)s.f_bavail;
+ total_space = (Kumu::fsize_t)s.f_bsize * (Kumu::fsize_t)s.f_blocks;
+ return RESULT_OK;
+ }
+
+ switch ( errno )
+ {
+ case ENOENT:
+ case ENOTDIR: return RESULT_NOTAFILE;
+ case EACCES: return RESULT_NO_PERM;
+ }
+
+ DefaultLogSink().Error("FreeSpaceForPath statfs %s: %s\n", path.c_str(), strerror(errno));
+ return RESULT_FAIL;
+#endif // KM_WIN32
+}
+
+
+//
+// end KM_fileio.cpp
+//
diff --git a/asdcplib/src/KM_fileio.h b/asdcplib/src/KM_fileio.h
new file mode 100755
index 0000000..cb00acc
--- /dev/null
+++ b/asdcplib/src/KM_fileio.h
@@ -0,0 +1,342 @@
+/*
+Copyright (c) 2004-2009, 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: KM_fileio.h,v 1.17 2009/06/22 05:49:02 jhurst Exp $
+ \brief portable file i/o
+ */
+
+#ifndef _KM_FILEIO_H_
+#define _KM_FILEIO_H_
+
+#include <KM_util.h>
+#include <string>
+#include <boost/filesystem.hpp>
+#include <openssl/md5.h>
+
+#ifdef KM_WIN32
+# include <io.h>
+#else
+# include <dirent.h>
+# include <unistd.h>
+# include <time.h>
+# include <sys/types.h>
+#include <regex.h>
+#endif
+
+#include <sys/stat.h>
+
+
+
+namespace Kumu
+{
+ class DirScanner
+ {
+ public:
+ DirScanner();
+ Result_t Open(const char *);
+ Result_t GetNext(char *);
+ Result_t Close();
+ private:
+ boost::filesystem::directory_iterator _iterator;
+ };
+
+#ifdef KM_WIN32
+ typedef __int64 fsize_t;
+ typedef __int64 fpos_t;
+ typedef HANDLE FileHandle;
+
+ 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 FileHandle;
+ const FileHandle INVALID_HANDLE_VALUE = -1L;
+
+ enum SeekPos_t {
+ SP_BEGIN = SEEK_SET,
+ SP_POS = SEEK_CUR,
+ SP_END = SEEK_END
+ };
+#endif
+
+ //
+#ifndef KM_SMALL_FILES_OK
+ template <bool sizecheck> void compile_time_size_checker();
+ template <> inline void compile_time_size_checker<false>() {}
+ //
+ // READ THIS if your compiler is complaining about a previously declared implementation of
+ // compile_time_size_checker(). For example, GCC 4.0.1 looks like this:
+ //
+ // error: 'void Kumu::compile_time_size_checker() [with bool sizecheck = false]' previously declared here
+ //
+ // This is happening because the equality being tested below is false. The reason for this
+ // will depend on your OS, but on Linux it is probably because you have not used -D_FILE_OFFSET_BITS=64
+ // Adding this magic macro to your CFLAGS will get you going again. If you are on a system that
+ // does not support 64-bit files, you can disable this check by using -DKM_SMALL_FILES_OK. You
+ // will then of course be limited to file sizes < 4GB.
+ //
+ template <> inline void compile_time_size_checker<sizeof(Kumu::fsize_t)==sizeof(ui64_t)>() {}
+#endif
+ //
+
+ const ui32_t Kilobyte = 1024;
+ const ui32_t Megabyte = Kilobyte * Kilobyte;
+ const ui32_t Gigabyte = Megabyte * Kilobyte;
+
+ const ui32_t MaxFilePath = Kilobyte;
+
+
+ //------------------------------------------------------------------------------------------
+ // Path Manglers
+ //------------------------------------------------------------------------------------------
+
+ // types
+ typedef std::list<std::string> PathCompList_t; // a list of path components
+ typedef std::list<std::string> PathList_t; // a list of paths
+
+ // tests
+ bool PathExists(const std::string& Path); // true if the path exists in the filesystem
+ bool PathIsFile(const std::string& Path); // true if the path exists in the filesystem and is a file
+ bool PathIsDirectory(const std::string& Path); // true if the path exists in the filesystem and is a directory
+ fsize_t FileSize(const std::string& Path); // returns the size of a regular file, 0 for a directory or device
+ bool PathsAreEquivalent(const std::string& lhs, const std::string& rhs); // true if paths point to the same filesystem entry
+
+ // Returns free space and total space available for the given path
+ Result_t FreeSpaceForPath(const std::string& path, Kumu::fsize_t& free_space, Kumu::fsize_t& total_space);
+
+ // split and reassemble paths as lists of path components
+ PathCompList_t& PathToComponents(const std::string& Path, PathCompList_t& CList, char separator = '/'); // removes '//'
+ std::string ComponentsToPath(const PathCompList_t& CList, char separator = '/');
+ std::string ComponentsToAbsolutePath(const PathCompList_t& CList, char separator = '/'); // add separator to the front
+ bool PathHasComponents(const std::string& Path, char separator = '/'); // true if paths starts with separator
+
+ bool PathIsAbsolute(const std::string& Path, char separator = '/'); // true if path begins with separator
+ std::string PathMakeAbsolute(const std::string& Path, char separator = '/'); // compute position of relative path using getcwd()
+ std::string PathMakeLocal(const std::string& Path, const std::string& Parent); // remove Parent from front of Path, if it exists
+ std::string PathMakeCanonical(const std::string& Path, char separator = '/'); // remove '.' and '..'
+
+ // common operations
+ std::string PathBasename(const std::string& Path, char separator = '/'); // returns right-most path element (list back())
+ std::string PathDirname(const std::string& Path, char separator = '/'); // returns everything but the right-most element
+ std::string PathGetExtension(const std::string& Path); // returns everything in the right-most element following the right-most '.'
+ std::string PathSetExtension(const std::string& Path, const std::string& Extension); // empty extension removes '.' as well
+
+ std::string PathJoin(const std::string& Path1, const std::string& Path2, char separator = '/');
+ std::string PathJoin(const std::string& Path1, const std::string& Path2, const std::string& Path3, char separator = '/');
+ std::string PathJoin(const std::string& Path1, const std::string& Path2,
+ const std::string& Path3, const std::string& Path4, char separator = '/');
+
+
+ //------------------------------------------------------------------------------------------
+ // Path Search
+ //------------------------------------------------------------------------------------------
+
+ // An interface for a path matching function, used by FindInPath() and FindInPaths() below
+ //
+ class IPathMatch
+ {
+ public:
+ virtual ~IPathMatch() {}
+ virtual bool Match(const std::string& s) const = 0;
+ };
+
+ // matches any pathname
+ class PathMatchAny : public IPathMatch
+ {
+ public:
+ virtual ~PathMatchAny() {}
+ inline bool Match(const std::string&) const { return true; }
+ };
+
+#ifndef KM_WIN32
+ // matches pathnames using a regular expression
+ class PathMatchRegex : public IPathMatch
+ {
+ regex_t m_regex;
+ PathMatchRegex();
+ const PathMatchRegex& operator=(const PathMatchRegex&);
+
+ public:
+ PathMatchRegex(const std::string& Pattern);
+ PathMatchRegex(const PathMatchRegex&);
+ virtual ~PathMatchRegex();
+ bool Match(const std::string& s) const;
+ };
+
+ // matches pathnames using a Bourne shell glob expression
+ class PathMatchGlob : public IPathMatch
+ {
+ regex_t m_regex;
+ PathMatchGlob();
+ const PathMatchGlob& operator=(const PathMatchGlob&);
+
+ public:
+ PathMatchGlob(const std::string& Pattern);
+ PathMatchGlob(const PathMatchGlob&);
+ 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.
+ PathList_t& FindInPath(const IPathMatch& Pattern, const std::string& SearchDir,
+ PathList_t& FoundPaths, bool one_shot = false, char separator = '/');
+
+ PathList_t& FindInPaths(const IPathMatch& Pattern, const PathList_t& SearchPaths,
+ PathList_t& FoundPaths, bool one_shot = false, char separator = '/');
+
+ //------------------------------------------------------------------------------------------
+ // Directory Manipulation
+ //------------------------------------------------------------------------------------------
+
+ // Create a directory, creates intermediate directories as necessary
+ Result_t CreateDirectoriesInPath(const std::string& Path);
+
+ // Delete a file (fails if the path points to a directory)
+ Result_t DeleteFile(const std::string& filename);
+
+ // Recursively remove a file or directory
+ Result_t DeletePath(const std::string& pathname);
+
+ //------------------------------------------------------------------------------------------
+ // File I/O Wrappers
+ //------------------------------------------------------------------------------------------
+
+ // Instant IO for strings
+ //
+ // Reads an entire file into a string.
+ Result_t ReadFileIntoString(const char* filename, std::string& outString, ui32_t max_size = 8 * Megabyte);
+
+ // Writes a string to a file, overwrites the existing file if present.
+ Result_t WriteStringIntoFile(const char* filename, const std::string& inString);
+
+ // Instant IO for archivable objects
+ //
+ // Unarchives a file into an object
+ Result_t ReadFileIntoObject(const std::string& Filename, IArchive& Object, ui32_t max_size = 8 * Kumu::Megabyte);
+
+ // Archives an object into a file
+ Result_t WriteObjectIntoFile(const IArchive& Object, const std::string& Filename);
+
+ // Instant IO for memory buffers
+ //
+ // Unarchives a file into a buffer
+ Result_t ReadFileIntoBuffer(const std::string& Filename, Kumu::ByteString& Buffer,
+ ui32_t max_size = 8 * Kumu::Megabyte);
+
+ // Archives a buffer into a file
+ Result_t WriteBufferIntoFile(const Kumu::ByteString& Buffer, const std::string& Filename);
+
+
+ //------------------------------------------------------------------------------------------
+ // File I/O
+ //------------------------------------------------------------------------------------------
+
+ //
+ class FileReader
+ {
+ KM_NO_COPY_CONSTRUCT(FileReader);
+
+ protected:
+ std::string m_Filename;
+ FileHandle 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);
+ bool m_Hashing;
+ MD5_CTX m_MD5Context;
+
+ 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
+
+ void StartHashing();
+ void MaybeHash(void const *, int);
+ std::string StopHashing();
+ };
+
+ Result_t CreateDirectoriesInPath(const std::string& Path);
+ Result_t FreeSpaceForPath(const std::string& path, Kumu::fsize_t& free_space, Kumu::fsize_t& total_space);
+ Result_t DeleteFile(const std::string& filename);
+ Result_t DeletePath(const std::string& pathname);
+
+} // namespace Kumu
+
+
+#endif // _KM_FILEIO_H_
+
+
+//
+// end KM_fileio.h
+//
diff --git a/asdcplib/src/KM_log.cpp b/asdcplib/src/KM_log.cpp
new file mode 100755
index 0000000..7bd5926
--- /dev/null
+++ b/asdcplib/src/KM_log.cpp
@@ -0,0 +1,379 @@
+/*
+Copyright (c) 2004-2011, 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: KM_log.cpp,v 1.15 2011/03/08 19:03:47 jhurst Exp $
+ \brief message logging API
+ */
+
+#include <KM_util.h>
+#include <KM_log.h>
+#include <KM_mutex.h>
+#include <sys/types.h>
+#include <string.h>
+#include <stdarg.h>
+#include <iostream>
+#include <sstream>
+
+#ifdef KM_WIN32
+#define getpid GetCurrentProcessId
+#else
+#include <unistd.h>
+#endif
+
+//------------------------------------------------------------------------------------------
+//
+
+void
+Kumu::ILogSink::vLogf(LogType_t type, const char* fmt, va_list* list)
+{
+ char buf[MaxLogLength];
+ vsnprintf(buf, MaxLogLength, fmt, *list);
+
+ WriteEntry(LogEntry(getpid(), type, buf));
+}
+
+//------------------------------------------------------------------------------------------
+//
+
+static Kumu::Mutex s_DefaultLogSinkLock;
+static Kumu::ILogSink* s_DefaultLogSink = 0;
+static Kumu::StdioLogSink s_StderrLogSink;
+
+//
+void
+Kumu::SetDefaultLogSink(ILogSink* Sink)
+{
+ AutoMutex L(s_DefaultLogSinkLock);
+ s_DefaultLogSink = Sink;
+}
+
+// Returns the internal default sink.
+Kumu::ILogSink&
+Kumu::DefaultLogSink()
+{
+ AutoMutex L(s_DefaultLogSinkLock);
+
+ if ( s_DefaultLogSink == 0 )
+ s_DefaultLogSink = &s_StderrLogSink;
+
+ return *s_DefaultLogSink;
+}
+
+
+//------------------------------------------------------------------------------------------
+//
+
+void
+Kumu::EntryListLogSink::WriteEntry(const LogEntry& Entry)
+{
+ AutoMutex L(m_Lock);
+
+ if ( Entry.TestFilter(m_filter) )
+ m_Target.push_back(Entry);
+}
+
+//------------------------------------------------------------------------------------------
+//
+
+void
+Kumu::StdioLogSink::WriteEntry(const LogEntry& Entry)
+{
+ AutoMutex L(m_Lock);
+ std::string buf;
+
+ if ( Entry.TestFilter(m_filter) )
+ {
+ Entry.CreateStringWithOptions(buf, m_options);
+ fputs(buf.c_str(), m_stream);
+ }
+}
+
+//---------------------------------------------------------------------------------
+
+#ifdef KM_WIN32
+//
+// http://www.codeguru.com/forum/showthread.php?t=231165
+//
+void
+Kumu::WinDbgLogSink::WriteEntry(const LogEntry& Entry)
+{
+ AutoMutex L(m_Lock);
+ std::string buf;
+
+ if ( Entry.TestFilter(m_filter) )
+ {
+ Entry.CreateStringWithOptions(buf, m_options);
+ ::OutputDebugStringA(buf.c_str());
+ }
+}
+#endif
+
+//------------------------------------------------------------------------------------------
+//
+
+#ifndef KM_WIN32
+//
+void
+Kumu::StreamLogSink::WriteEntry(const LogEntry& Entry)
+{
+ AutoMutex L(m_Lock);
+ std::string buf;
+
+ if ( Entry.TestFilter(m_filter) )
+ {
+ Entry.CreateStringWithOptions(buf, m_options);
+ write(m_fd, buf.c_str(), buf.size());
+ }
+}
+
+// foolin with symbols
+//------------------------------------------------------------------------------------------
+#include <syslog.h>
+int const SYSLOG_ALERT = LOG_ALERT;
+int const SYSLOG_CRIT = LOG_CRIT;
+int const SYSLOG_ERR = LOG_ERR;
+int const SYSLOG_WARNING = LOG_WARNING;
+int const SYSLOG_NOTICE = LOG_NOTICE;
+int const SYSLOG_INFO = LOG_INFO;
+int const SYSLOG_DEBUG = LOG_DEBUG;
+#undef LOG_ALERT
+#undef LOG_CRIT
+#undef LOG_ERR
+#undef LOG_WARNING
+#undef LOG_NOTICE
+#undef LOG_INFO
+#undef LOG_DEBUG
+//------------------------------------------------------------------------------------------
+
+Kumu::SyslogLogSink::SyslogLogSink(const std::string& source_name, int facility)
+{
+ if ( facility == 0 )
+ facility = LOG_DAEMON;
+
+ openlog(source_name.c_str(), LOG_CONS|LOG_NDELAY||LOG_PID, facility);
+}
+
+Kumu::SyslogLogSink::~SyslogLogSink()
+{
+ closelog();
+}
+
+//
+void
+Kumu::SyslogLogSink::WriteEntry(const LogEntry& Entry)
+{
+ int priority = 0;
+
+ switch ( Entry.Type )
+ {
+ case Kumu::LOG_ALERT: priority = SYSLOG_ALERT; break;
+ case Kumu::LOG_CRIT: priority = SYSLOG_CRIT; break;
+ case Kumu::LOG_ERROR: priority = SYSLOG_ERR; break;
+ case Kumu::LOG_WARN: priority = SYSLOG_WARNING; break;
+ case Kumu::LOG_NOTICE: priority = SYSLOG_NOTICE; break;
+ case Kumu::LOG_INFO: priority = SYSLOG_INFO; break;
+ case Kumu::LOG_DEBUG: priority = SYSLOG_DEBUG; break;
+ }
+
+ AutoMutex L(m_Lock);
+
+ if ( Entry.TestFilter(m_filter) )
+ {
+ syslog(priority, "%s", Entry.Msg.substr(0, Entry.Msg.size() - 1).c_str());
+ }
+}
+
+//
+int
+Kumu::SyslogNameToFacility(const std::string& facility_name)
+{
+ if ( facility_name == "LOG_DAEMON" ) return LOG_DAEMON;
+ if ( facility_name == "LOG_LOCAL0" ) return LOG_LOCAL0;
+ if ( facility_name == "LOG_LOCAL1" ) return LOG_LOCAL1;
+ if ( facility_name == "LOG_LOCAL2" ) return LOG_LOCAL2;
+ if ( facility_name == "LOG_LOCAL3" ) return LOG_LOCAL3;
+ if ( facility_name == "LOG_LOCAL4" ) return LOG_LOCAL4;
+ if ( facility_name == "LOG_LOCAL5" ) return LOG_LOCAL5;
+ if ( facility_name == "LOG_LOCAL6" ) return LOG_LOCAL6;
+ if ( facility_name == "LOG_LOCAL7" ) return LOG_LOCAL7;
+
+ DefaultLogSink().Error("Unsupported facility name: %s, using default value LOG_DAEMON\n", facility_name.c_str());
+ return LOG_DAEMON;
+}
+
+#endif
+
+//------------------------------------------------------------------------------------------
+
+//
+std::basic_ostream<char, std::char_traits<char> >&
+Kumu::operator<<(std::basic_ostream<char, std::char_traits<char> >& strm, LogEntry const& Entry)
+{
+ std::basic_ostringstream<char, std::char_traits<char> > s;
+ s.copyfmt(strm);
+ s.width(0);
+ std::string buf;
+
+ s << Entry.CreateStringWithOptions(buf, LOG_OPTION_ALL);
+
+ strm << s.str();
+ return strm;
+}
+
+//------------------------------------------------------------------------------------------
+
+
+//
+bool
+Kumu::LogEntry::TestFilter(i32_t filter) const
+{
+ switch ( Type )
+ {
+ case LOG_CRIT:
+ if ( (filter & LOG_ALLOW_CRIT) == 0 )
+ return false;
+ break;
+
+ case LOG_ALERT:
+ if ( (filter & LOG_ALLOW_ALERT) == 0 )
+ return false;
+ break;
+
+ case LOG_NOTICE:
+ if ( (filter & LOG_ALLOW_NOTICE) == 0 )
+ return false;
+ break;
+
+ case LOG_ERROR:
+ if ( (filter & LOG_ALLOW_ERROR) == 0 )
+ return false;
+ break;
+
+ case LOG_WARN:
+ if ( (filter & LOG_ALLOW_WARN) == 0 )
+ return false;
+ break;
+
+ case LOG_INFO:
+ if ( (filter & LOG_ALLOW_INFO) == 0 )
+ return false;
+ break;
+
+ case LOG_DEBUG:
+ if ( (filter & LOG_ALLOW_DEBUG) == 0 )
+ return false;
+ break;
+
+ }
+
+ return true;
+}
+
+//
+std::string&
+Kumu::LogEntry::CreateStringWithOptions(std::string& out_buf, i32_t opt) const
+{
+ out_buf.erase();
+
+ if ( opt != 0 )
+ {
+ char buf[64];
+
+ if ( (opt & LOG_OPTION_TIMESTAMP) != 0 )
+ {
+ Timestamp Now;
+ out_buf += Now.EncodeString(buf, 64);
+ }
+
+ if ( (opt & LOG_OPTION_PID) != 0 )
+ {
+ if ( ! out_buf.empty() ) out_buf += " ";
+ snprintf(buf, 64, "%d", PID);
+ out_buf += buf;
+ }
+
+ if ( (opt & LOG_OPTION_TYPE) != 0 )
+ {
+ if ( ! out_buf.empty() ) out_buf += " ";
+
+ switch ( Type )
+ {
+ case LOG_CRIT: out_buf += "CRT"; break;
+ case LOG_ALERT: out_buf += "ALR"; break;
+ case LOG_NOTICE: out_buf += "NTC"; break;
+ case LOG_ERROR: out_buf += "ERR"; break;
+ case LOG_WARN: out_buf += "WRN"; break;
+ case LOG_INFO: out_buf += "INF"; break;
+ case LOG_DEBUG: out_buf += "DBG"; break;
+ default: out_buf += "DFL"; break;
+ }
+ }
+
+ out_buf.insert(0, "[");
+ out_buf += "]: ";
+ }
+
+ out_buf += Msg;
+ return out_buf;
+}
+
+
+//
+ui32_t
+Kumu::LogEntry::ArchiveLength() const
+{
+ return sizeof(ui32_t)
+ + EventTime.ArchiveLength()
+ + sizeof(ui32_t)
+ + sizeof(ui32_t) + Msg.size();
+}
+
+//
+bool
+Kumu::LogEntry::Archive(Kumu::MemIOWriter* Writer) const
+{
+ if ( ! Writer->WriteUi32BE(PID) ) return false;
+ if ( ! EventTime.Archive(Writer) ) return false;
+ if ( ! Writer->WriteUi32BE(Type) ) return false;
+ if ( ! ArchiveString(*Writer, Msg) ) return false;
+ return true;
+}
+
+//
+bool
+Kumu::LogEntry::Unarchive(Kumu::MemIOReader* Reader)
+{
+ if ( ! Reader->ReadUi32BE(&PID) ) return false;
+ if ( ! EventTime.Unarchive(Reader) ) return false;
+ if ( ! Reader->ReadUi32BE((ui32_t*)&Type) ) return false;
+ if ( ! UnarchiveString(*Reader, Msg) ) return false;
+ return true;
+}
+
+//
+// end
+//
diff --git a/asdcplib/src/KM_log.h b/asdcplib/src/KM_log.h
new file mode 100755
index 0000000..4981b17
--- /dev/null
+++ b/asdcplib/src/KM_log.h
@@ -0,0 +1,321 @@
+/*
+Copyright (c) 2004-2009, 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: KM_log.h,v 1.13 2011/03/05 19:15:35 jhurst Exp $
+ \brief message logging API
+ */
+
+
+#ifndef _KM_LOG_H_
+#define _KM_LOG_H_
+
+#include <KM_platform.h>
+#include <KM_mutex.h>
+#include <KM_util.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <iosfwd>
+
+#define LOG_MSG_IMPL(t) \
+ va_list args; \
+ va_start(args, fmt); \
+ vLogf((t), fmt, &args); \
+ va_end(args)
+
+// Returns RESULT_PTR if the given argument is NULL.
+# define KM_TEST_NULL_L(p) \
+ if ( (p) == 0 ) { \
+ DefaultLogSink().Error("NULL pointer in file %s, line %d\n", __FILE__, __LINE__); \
+ return Kumu::RESULT_PTR; \
+ }
+
+// Returns RESULT_PTR if the given argument is NULL. 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_L(p) \
+ KM_TEST_NULL_L(p); \
+ if ( (p)[0] == '\0' ) { \
+ DefaultLogSink().Error("Empty string in file %s, line %d\n", __FILE__, __LINE__); \
+ return Kumu::RESULT_NULL_STR; \
+ }
+
+
+namespace Kumu
+{
+ // no log message will exceed this length
+ const ui32_t MaxLogLength = 512;
+
+ //---------------------------------------------------------------------------------
+ // message logging
+
+ // Log messages are recorded by objects which implement the interface given
+ // in the class ILogSink below. The library maintains a pointer to a default
+ // log sink which is used by the library to report messages.
+ //
+
+ // types of log messages
+ enum LogType_t {
+ LOG_DEBUG, // detailed developer info
+ LOG_INFO, // developer info
+ LOG_WARN, // library non-fatal or near-miss error
+ LOG_ERROR, // library fatal error
+ LOG_NOTICE, // application user info
+ LOG_ALERT, // application non-fatal or near-miss error
+ LOG_CRIT, // application fatal error
+ };
+
+
+ // OR these values together to come up with sink filter flags.
+ // The default mask is LOG_ALLOW_ALL (all messages).
+ const i32_t LOG_ALLOW_DEBUG = 0x00000001;
+ const i32_t LOG_ALLOW_INFO = 0x00000002;
+ const i32_t LOG_ALLOW_WARN = 0x00000004;
+ const i32_t LOG_ALLOW_ERROR = 0x00000008;
+ const i32_t LOG_ALLOW_NOTICE = 0x00000010;
+ const i32_t LOG_ALLOW_ALERT = 0x00000020;
+ const i32_t LOG_ALLOW_CRIT = 0x00000040;
+ const i32_t LOG_ALLOW_NONE = 0x00000000;
+ const i32_t LOG_ALLOW_ALL = 0x000fffff;
+
+ // options are used to control display format default is 0.
+ const i32_t LOG_OPTION_TYPE = 0x01000000;
+ const i32_t LOG_OPTION_TIMESTAMP = 0x02000000;
+ const i32_t LOG_OPTION_PID = 0x04000000;
+ const i32_t LOG_OPTION_NONE = 0x00000000;
+ const i32_t LOG_OPTION_ALL = 0xfff00000;
+
+ // A log message with environmental metadata
+ class LogEntry : public IArchive
+ {
+ public:
+ ui32_t PID;
+ Timestamp EventTime;
+ LogType_t Type;
+ std::string Msg;
+
+ LogEntry() {}
+ LogEntry(ui32_t pid, LogType_t t, const char* m) : PID(pid), Type(t), Msg(m) { assert(m); }
+ virtual ~LogEntry() {}
+
+ // returns true if the message Type is present in the mask
+ bool TestFilter(i32_t mask_value) const;
+
+ // renders the message into outstr using the given dispaly options
+ // returns outstr&
+ std::string& CreateStringWithOptions(std::string& outstr, i32_t mask_value) const;
+
+ // IArchive
+ bool HasValue() const { return ! Msg.empty(); }
+ ui32_t ArchiveLength() const;
+ bool Archive(MemIOWriter* Writer) const;
+ bool Unarchive(MemIOReader* Reader);
+ };
+
+ //
+ std::basic_ostream<char, std::char_traits<char> >&
+ operator<<(std::basic_ostream<char, std::char_traits<char> >& strm, LogEntry const& Entry);
+
+
+ typedef ArchivableList<LogEntry> LogEntryList;
+
+ //
+ class ILogSink
+ {
+ protected:
+ i32_t m_filter;
+ i32_t m_options;
+
+ public:
+ ILogSink() : m_filter(LOG_ALLOW_ALL), m_options(LOG_OPTION_NONE) {}
+ virtual ~ILogSink() {}
+
+ void SetFilterFlag(i32_t f) { m_filter |= f; }
+ void UnsetFilterFlag(i32_t f) { m_filter &= ~f; }
+ bool TestFilterFlag(i32_t f) const { return ((m_filter & f) == f); }
+
+ void SetOptionFlag(i32_t o) { m_options |= o; }
+ void UnsetOptionFlag(i32_t o) { m_options &= ~o; }
+ bool TestOptionFlag(i32_t o) const { return ((m_options & o) == o); }
+
+ // library messages
+ 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); }
+
+ // application messages
+ 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); }
+
+ // message with type
+ void Logf(LogType_t type, const char* fmt, ...) { LOG_MSG_IMPL(type); }
+
+ // actual log sink input
+ virtual void vLogf(LogType_t, const char*, va_list*);
+ virtual void WriteEntry(const LogEntry&) = 0;
+ };
+
+
+ // 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();
+
+
+ // Sets a log sink as the default until the object is destroyed.
+ // The original default sink is saved and then restored on delete.
+ class LogSinkContext
+ {
+ KM_NO_COPY_CONSTRUCT(LogSinkContext);
+ LogSinkContext();
+ ILogSink* m_orig;
+
+ public:
+ LogSinkContext(ILogSink& sink) {
+ m_orig = &DefaultLogSink();
+ SetDefaultLogSink(&sink);
+ }
+
+ ~LogSinkContext() {
+ SetDefaultLogSink(m_orig);
+ }
+ };
+
+ //------------------------------------------------------------------------------------------
+ //
+
+ // write messages to two subordinate log sinks
+ class TeeLogSink : public ILogSink
+ {
+ KM_NO_COPY_CONSTRUCT(TeeLogSink);
+ TeeLogSink();
+
+ ILogSink& m_a;
+ ILogSink& m_b;
+
+ public:
+ TeeLogSink(ILogSink& a, ILogSink& b) : m_a(a), m_b(b) {}
+ virtual ~TeeLogSink() {}
+
+ void WriteEntry(const LogEntry& Entry) {
+ m_a.WriteEntry(Entry);
+ m_b.WriteEntry(Entry);
+ }
+ };
+
+ // collect log messages into the given list, does not test filter
+ class EntryListLogSink : public ILogSink
+ {
+ Mutex m_Lock;
+ LogEntryList& m_Target;
+ KM_NO_COPY_CONSTRUCT(EntryListLogSink);
+ EntryListLogSink();
+
+ public:
+ EntryListLogSink(LogEntryList& target) : m_Target(target) {}
+ virtual ~EntryListLogSink() {}
+
+ void WriteEntry(const LogEntry& Entry);
+ };
+
+
+ // write messages to a POSIX stdio stream
+ 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() {}
+
+ void WriteEntry(const LogEntry&);
+ };
+
+#ifdef KM_WIN32
+ // write messages to the Win32 debug stream
+ class WinDbgLogSink : public ILogSink
+ {
+ Mutex m_Lock;
+ KM_NO_COPY_CONSTRUCT(WinDbgLogSink);
+
+ public:
+ WinDbgLogSink() {}
+ virtual ~WinDbgLogSink() {}
+
+ void WriteEntry(const LogEntry&);
+ };
+#endif
+
+#ifndef KM_WIN32
+ // write messages to a POSIX file descriptor
+ 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() {}
+
+ void WriteEntry(const LogEntry&);
+ };
+
+ // write messages to the syslog facility
+ class SyslogLogSink : public ILogSink
+ {
+ Mutex m_Lock;
+ KM_NO_COPY_CONSTRUCT(SyslogLogSink);
+ SyslogLogSink();
+
+ public:
+ SyslogLogSink(const std::string& source_name, int facility);
+ virtual ~SyslogLogSink();
+ void WriteEntry(const LogEntry&);
+ };
+
+ // convert a string into the appropriate syslog facility id
+ int SyslogNameToFacility(const std::string& facility_name);
+
+#endif
+
+
+} // namespace Kumu
+
+#endif // _KM_LOG_H_
+
+//
+// end KM_log.h
+//
diff --git a/asdcplib/src/KM_memio.h b/asdcplib/src/KM_memio.h
new file mode 100755
index 0000000..69942c7
--- /dev/null
+++ b/asdcplib/src/KM_memio.h
@@ -0,0 +1,249 @@
+/*
+Copyright (c) 2006-2011, 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: KM_memio.h,v 1.9 2011/03/07 06:46:36 jhurst Exp $
+ \brief abstraction for byte-oriented conversion of integers and objects
+ */
+
+#ifndef _KM_MEMIO_H_
+#define _KM_MEMIO_H_
+
+#include <KM_platform.h>
+#include <string>
+#include <cstring>
+
+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 const byte_t* RoData() const { return m_p; }
+ inline byte_t* CurrentData() { return m_p + m_size; }
+ inline ui32_t Length() const { return m_size; }
+ inline ui32_t Remainder() const { 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;
+ }
+
+ inline bool WriteString(const std::string& str) {
+ ui32_t len = static_cast<ui32_t>(str.length());
+ if ( ! WriteUi32BE(len) ) return false;
+ if ( ! WriteRaw((const byte_t*)str.c_str(), len) ) return false;
+ 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() const { return m_p; }
+ inline const byte_t* CurrentData() const { return m_p + m_size; }
+ inline ui32_t Offset() const { return m_size; }
+ inline ui32_t Remainder() const { 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;
+ }
+
+ inline bool ReadString(std::string& str)
+ {
+ ui32_t str_length;
+ if ( ! ReadUi32BE(&str_length) ) return false;
+ if ( ( m_size + str_length ) > m_capacity ) return false;
+ str.assign((const char*)CurrentData(), str_length);
+ if ( ! SkipOffset(str_length) ) return false;
+ return true;
+ }
+ };
+
+ //
+ inline bool
+ UnarchiveString(MemIOReader& Reader, std::string& str) {
+ return Reader.ReadString(str);
+ }
+
+ //
+ inline bool
+ ArchiveString(MemIOWriter& Writer, const std::string& str)
+ {
+ return Writer.WriteString(str);
+ }
+
+
+} // namespace Kumu
+
+#endif // _KM_MEMIO_H_
+
+//
+// end KM_memio.h
+//
diff --git a/asdcplib/src/KM_mutex.h b/asdcplib/src/KM_mutex.h
new file mode 100755
index 0000000..396531d
--- /dev/null
+++ b/asdcplib/src/KM_mutex.h
@@ -0,0 +1,89 @@
+/*
+Copyright (c) 2004-2009, 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: KM_mutex.h,v 1.2 2009/04/09 19:16:49 msheby Exp $
+ \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/asdcplib/src/KM_platform.h b/asdcplib/src/KM_platform.h
new file mode 100644
index 0000000..266c01a
--- /dev/null
+++ b/asdcplib/src/KM_platform.h
@@ -0,0 +1,270 @@
+/*
+Copyright (c) 2004-2009, 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: KM_platform.h,v 1.6 2010/09/14 19:21:47 msheby Exp $
+ \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>
+/* we like the "SendMessage" name, so get rid of the preprocessor define
+ * and replace with an inline function */
+# undef SendMessage
+#ifdef UNICODE
+inline
+WINUSERAPI
+LRESULT
+WINAPI
+SendMessage(
+ HWND hWnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ return SendMessageW(hWnd, Msg, wParam, lParam);
+}
+#else
+inline
+WINUSERAPI
+LRESULT
+WINAPI
+SendMessage(
+ HWND hWnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ return SendMessageA(hWnd, Msg, wParam, lParam);
+}
+#endif // !UNICODE
+
+# include <stdlib.h>
+# include <stdio.h>
+# include <stdarg.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) { this->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&)
+
+/*
+// Example
+ class foo
+ {
+ KM_NO_COPY_CONSTRUCT(foo); // accessing private mthods will cause compile time error
+ public:
+ // ...
+ };
+*/
+
+// Produces copy constructor boilerplate. Implements
+// copy and assignment, see example below
+# define KM_EXPLICIT_COPY_CONSTRUCT(T) \
+ T(const T&); \
+ const T& operator=(const T&)
+
+# define KM_EXPLICIT_COPY_CONSTRUCT_IMPL_START(N, T) \
+ void T##_copy_impl(N::T& lhs, const N::T& rhs) \
+ {
+
+#define KM_COPY_ITEM(I) lhs.I = rhs.I;
+
+# define KM_EXPLICIT_COPY_CONSTRUCT_IMPL_END(N, T) \
+ } \
+ N::T::T(const N::T& rhs) { T##_copy_impl(*this, rhs); } \
+ const N::T& N::T::operator=(const N::T& rhs) { T##_copy_impl(*this, rhs); return *this; }
+
+/*
+// Example
+namespace bar {
+ class foo
+ {
+ public:
+ std::string param_a;
+ int param_b;
+
+ KM_EXPLICIT_COPY_CONSTRUCT(foo);
+ // ...
+ };
+}
+
+//
+KM_EXPLICIT_COPY_CONSTRUCT_IMPL_START(bar, foo)
+KM_COPY_ITEM(param_a)
+KM_COPY_ITEM(param_b)
+KM_EXPLICIT_COPY_CONSTRUCT_IMPL_END(bar, foo)
+*/
+
+#endif // _KM_PLATFORM_H_
+
+//
+// KM_platform.h
+//
diff --git a/asdcplib/src/KM_prng.cpp b/asdcplib/src/KM_prng.cpp
new file mode 100755
index 0000000..4e85cc5
--- /dev/null
+++ b/asdcplib/src/KM_prng.cpp
@@ -0,0 +1,271 @@
+/* -*- c-basic-offset: 2; -*- */
+
+/*
+Copyright (c) 2006-2009, 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: KM_prng.cpp,v 1.9 2011/06/14 23:38:33 jhurst Exp $
+ \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>
+#include <openssl/bn.h>
+
+using namespace Kumu;
+
+
+#ifdef KM_WIN32
+# include <wincrypt.h>
+#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;
+ unsigned int m_libdcp_test_rng_state;
+
+ 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
+ HCRYPTPROV hProvider = 0;
+ CryptAcquireContext(&hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
+ CryptGenRandom(hProvider, RNG_KEY_SIZE, rng_key);
+#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);
+ memcpy(buf + gen_count, tmp, len - gen_count);
+ }
+
+ }
+};
+
+
+static h__RNG* s_RNG = 0;
+
+
+//------------------------------------------------------------------------------------------
+//
+// Fortuna 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);
+ const byte_t* front_of_buffer = buf;
+
+ 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 front_of_buffer;
+}
+
+//
+const byte_t*
+Kumu::FortunaRNG::FillRandom(Kumu::ByteString& Buffer)
+{
+ FillRandom(Buffer.Data(), Buffer.Capacity());
+ Buffer.Length(Buffer.Capacity());
+ return Buffer.Data();
+}
+
+//------------------------------------------------------------------------------------------
+
+//
+// FIPS 186-2 Sec. 3.1 as modified by Change 1, section entitled "General Purpose Random Number Generation"
+void
+Kumu::Gen_FIPS_186_Value(const byte_t* key, ui32_t key_size, byte_t* out_buf, ui32_t out_buf_len)
+{
+ byte_t sha_buf[SHA_DIGEST_LENGTH];
+ ui32_t const xkey_len = 64; // 512/8
+ byte_t xkey[xkey_len];
+ BN_CTX* ctx1 = BN_CTX_new(); // used by BN_* functions
+ assert(ctx1);
+
+ if ( key_size > xkey_len )
+ DefaultLogSink().Warn("Key too large for FIPS 186 seed, truncating to 64 bytes.\n");
+
+ // init key
+ memset(xkey, 0, xkey_len);
+ memcpy(xkey, key, xmin<ui32_t>(key_size, xkey_len));
+
+ if ( key_size < SHA_DIGEST_LENGTH )
+ key_size = SHA_DIGEST_LENGTH; // pad short key ( b < 160 )
+
+ // create the 2^b constant
+ BIGNUM c_2powb, c_2, c_b;
+ BN_init(&c_2powb); BN_init(&c_2); BN_init(&c_b);
+ BN_set_word(&c_2, 2);
+ BN_set_word(&c_b, key_size * 8);
+ BN_exp(&c_2powb, &c_2, &c_b, ctx1);
+
+ for (;;)
+ {
+ SHA_CTX SHA;
+
+ // step c -- x = G(t,xkey)
+ SHA1_Init(&SHA); // set t
+ SHA1_Update(&SHA, xkey, xkey_len);
+
+ ui32_t* buf_p = (ui32_t*)sha_buf;
+ *buf_p++ = KM_i32_BE(SHA.h0);
+ *buf_p++ = KM_i32_BE(SHA.h1);
+ *buf_p++ = KM_i32_BE(SHA.h2);
+ *buf_p++ = KM_i32_BE(SHA.h3);
+ *buf_p++ = KM_i32_BE(SHA.h4);
+ memcpy(out_buf, sha_buf, xmin<ui32_t>(out_buf_len, SHA_DIGEST_LENGTH));
+
+ if ( out_buf_len <= SHA_DIGEST_LENGTH )
+ break;
+
+ out_buf_len -= SHA_DIGEST_LENGTH;
+ out_buf += SHA_DIGEST_LENGTH;
+
+ // step d -- XKEY = (1 + XKEY + x) mod 2^b
+ BIGNUM bn_tmp, bn_xkey, bn_x_n;
+ BN_init(&bn_tmp); BN_init(&bn_xkey); BN_init(&bn_x_n);
+
+ BN_bin2bn(xkey, key_size, &bn_xkey);
+ BN_bin2bn(sha_buf, SHA_DIGEST_LENGTH, &bn_x_n);
+ BN_add_word(&bn_xkey, 1); // xkey += 1
+ BN_add(&bn_tmp, &bn_xkey, &bn_x_n); // xkey += x
+ BN_mod(&bn_xkey, &bn_tmp, &c_2powb, ctx1); // xkey = xkey mod (2^b)
+
+ memset(xkey, 0, xkey_len);
+ ui32_t bn_buf_len = BN_num_bytes(&bn_xkey);
+ ui32_t idx = ( bn_buf_len < key_size ) ? key_size - bn_buf_len : 0;
+ BN_bn2bin(&bn_xkey, &xkey[idx]);
+ }
+
+ BN_CTX_free(ctx1);
+}
+
+//
+// end KM_prng.cpp
+//
diff --git a/asdcplib/src/KM_prng.h b/asdcplib/src/KM_prng.h
new file mode 100755
index 0000000..0b941f3
--- /dev/null
+++ b/asdcplib/src/KM_prng.h
@@ -0,0 +1,64 @@
+/*
+Copyright (c) 2006-2009, 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: KM_prng.h,v 1.4 2009/04/09 19:24:14 msheby Exp $
+ \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&);
+#ifdef LIBDCP_POSIX
+ void Reset();
+#endif
+ };
+
+
+ // key_len must be <= 64 (larger values will be truncated)
+ void Gen_FIPS_186_Value(const byte_t* key_in, ui32_t key_len, byte_t* buf, ui32_t buf_len);
+} // namespace Kumu
+
+
+
+#endif // _KM_PRNG_H_
+
+//
+// end KM_prng.h
+//
diff --git a/asdcplib/src/KM_tai.cpp b/asdcplib/src/KM_tai.cpp
new file mode 100644
index 0000000..2cbd125
--- /dev/null
+++ b/asdcplib/src/KM_tai.cpp
@@ -0,0 +1,221 @@
+/*
+
+THIS IS A SUBSET OF THE FULL LIBTAI. CHANGES HAVE BEEN MADE TO SUIT
+LIBKUMU STYLE AND TYPE CONVENTIONS. ALL BUGS BELONG TO JOHN HURST.
+THE FOLLOWING IS FOR ATTRIBUTION, THANK YOU MR. BERNSTEIN FOR WRITING
+AND DISTRIBUTING SUCH GREAT SOFTWARE:
+
+libtai 0.60, alpha.
+19981013
+Copyright 1998
+D. J. Bernstein, djb@pobox.com
+http://pobox.com/~djb/libtai.html
+
+
+libtai is a library for storing and manipulating dates and times.
+
+libtai supports two time scales: (1) TAI64, covering a few hundred
+billion years with 1-second precision; (2) TAI64NA, covering the same
+period with 1-attosecond precision. Both scales are defined in terms of
+TAI, the current international real time standard.
+
+libtai provides an internal format for TAI64, struct tai, designed for
+fast time manipulations. The tai_pack() and tai_unpack() routines
+convert between struct tai and a portable 8-byte TAI64 storage format.
+libtai provides similar internal and external formats for TAI64NA.
+
+libtai provides struct caldate to store dates in year-month-day form. It
+can convert struct caldate, under the Gregorian calendar, to a modified
+Julian day number for easy date arithmetic.
+
+libtai provides struct caltime to store calendar dates and times along
+with UTC offsets. It can convert from struct tai to struct caltime in
+UTC, accounting for leap seconds, for accurate date and time display. It
+can also convert back from struct caltime to struct tai for user input.
+Its overall UTC-to-TAI conversion speed is 100x better than the usual
+UNIX mktime() implementation.
+
+This version of libtai requires a UNIX system with gettimeofday(). It
+will be easy to port to other operating systems with compilers
+supporting 64-bit arithmetic.
+
+The libtai source code is in the public domain.
+
+*/
+
+ /*! \file KM_tai.cpp
+ \version $Id: KM_tai.cpp,v 1.5 2012/03/07 17:30:52 mikey Exp $
+ \brief portable time functions
+ */
+
+#include <KM_tai.h>
+#ifdef KM_WIN32
+#include <time.h>
+#else
+#include <sys/time.h>
+#endif
+
+//
+void
+caldate_frommjd(Kumu::TAI::caldate* cd, i32_t day)
+{
+ assert(cd);
+ i32_t year, month, yday;
+
+ year = day / 146097L;
+ day %= 146097L;
+ day += 678881L;
+ while (day >= 146097L) { day -= 146097L; ++year; }
+
+ /* year * 146097 + day - 678881 is MJD; 0 <= day < 146097 */
+ /* 2000-03-01, MJD 51604, is year 5, day 0 */
+
+ year *= 4;
+ if (day == 146096L) { year += 3; day = 36524L; }
+ else { year += day / 36524L; day %= 36524L; }
+ year *= 25;
+ year += day / 1461;
+ day %= 1461;
+ year *= 4;
+
+ yday = (day < 306);
+ if (day == 1460) { year += 3; day = 365; }
+ else { year += day / 365; day %= 365; }
+ yday += day;
+
+ day *= 10;
+ month = (day + 5) / 306;
+ day = (day + 5) % 306;
+ day /= 10;
+ if (month >= 10) { yday -= 306; ++year; month -= 10; }
+ else { yday += 59; month += 2; }
+
+ cd->year = year;
+ cd->month = month + 1;
+ cd->day = day + 1;
+}
+
+//
+static ui32_t times365[4] = { 0, 365, 730, 1095 } ;
+static ui32_t times36524[4] = { 0, 36524UL, 73048UL, 109572UL } ;
+static ui32_t montab[12] =
+{ 0, 31, 61, 92, 122, 153, 184, 214, 245, 275, 306, 337 } ;
+/* month length after february is (306 * m + 5) / 10 */
+
+//
+i32_t
+caldate_mjd(const Kumu::TAI::caldate* cd)
+{
+ assert(cd);
+ i32_t y, m, d;
+
+ d = cd->day - 678882L;
+ m = cd->month - 1;
+ y = cd->year;
+
+ d += 146097L * (y / 400);
+ y %= 400;
+
+ if (m >= 2) m -= 2; else { m += 10; --y; }
+
+ y += (m / 12);
+ m %= 12;
+ if (m < 0) { m += 12; --y; }
+
+ d += montab[m];
+
+ d += 146097L * (y / 400);
+ y %= 400;
+ if (y < 0) { y += 400; d -= 146097L; }
+
+ d += times365[y & 3];
+ y >>= 2;
+
+ d += 1461L * (y % 25);
+ y /= 25;
+
+ d += times36524[y & 3];
+
+ return d;
+}
+
+
+//
+void
+caltime_utc(Kumu::TAI::caltime* ct, const Kumu::TAI::tai* t)
+{
+ assert(ct&&t);
+ Kumu::TAI::tai t2 = *t;
+ ui64_t u = t2.x + 58486;
+ i32_t s = (i32_t)(u % ui64_C(86400));
+
+ ct->second = (s % 60); s /= 60;
+ ct->minute = s % 60; s /= 60;
+ ct->hour = s;
+
+ u /= ui64_C(86400);
+ caldate_frommjd(&ct->date,/*XXX*/(i32_t) (u - ui64_C(53375995543064)));
+
+ ct->offset = 0;
+}
+
+//
+void
+caltime_tai(const Kumu::TAI::caltime* ct, Kumu::TAI::tai* t)
+{
+ assert(ct&&t);
+ i32_t day, s;
+
+ /* XXX: check for overflow? */
+
+ day = caldate_mjd(&ct->date);
+
+ s = ct->hour * 60 + ct->minute;
+ s = (s - ct->offset) * 60 + ct->second;
+
+ t->x = day * ui64_C(86400) + ui64_C(4611686014920671114) + (i64_t)s;
+}
+
+//
+void
+Kumu::TAI::tai::now()
+{
+#ifdef KM_WIN32
+ SYSTEMTIME st;
+ ::GetSystemTime(&st);
+ TAI::caltime ct;
+ ct.date.year = st.wYear;
+ ct.date.month = st.wMonth;
+ ct.date.day = st.wDay;
+ ct.hour = st.wHour;
+ ct.minute = st.wMinute;
+ ct.second = st.wSecond;
+ caltime_tai(&ct, this);
+#else
+ struct timeval now;
+ gettimeofday(&now, 0);
+ x = ui64_C(4611686018427387914) + (ui64_t)now.tv_sec;
+#endif
+}
+
+
+//
+const Kumu::TAI::tai&
+Kumu::TAI::tai::operator=(const Kumu::TAI::caltime& rhs)
+{
+ caltime_tai(&rhs, this);
+ return *this;
+}
+
+//
+const Kumu::TAI::caltime&
+Kumu::TAI::caltime::operator=(const Kumu::TAI::tai& rhs)
+{
+ caltime_utc(this, &rhs);
+ return *this;
+}
+
+
+//
+// end KM_tai.cpp
+//
diff --git a/asdcplib/src/KM_tai.h b/asdcplib/src/KM_tai.h
new file mode 100644
index 0000000..a274e8d
--- /dev/null
+++ b/asdcplib/src/KM_tai.h
@@ -0,0 +1,107 @@
+/*
+
+THIS IS A SUBSET OF THE FULL LIBTAI. CHANGES HAVE BEEN MADE TO SUIT
+LIBKUMU STYLE AND TYPE CONVENTIONS. ALL BUGS BELONG TO JOHN HURST.
+THE FOLLOWING IS FOR ATTRIBUTION, THANK YOU MR. BERNSTEIN FOR WRITING
+AND DISTRIBUTING SUCH GREAT SOFTWARE:
+
+libtai 0.60, alpha.
+19981013
+Copyright 1998
+D. J. Bernstein, djb@pobox.com
+http://pobox.com/~djb/libtai.html
+
+
+libtai is a library for storing and manipulating dates and times.
+
+libtai supports two time scales: (1) TAI64, covering a few hundred
+billion years with 1-second precision; (2) TAI64NA, covering the same
+period with 1-attosecond precision. Both scales are defined in terms of
+TAI, the current international real time standard.
+
+libtai provides an internal format for TAI64, struct tai, designed for
+fast time manipulations. The tai_pack() and tai_unpack() routines
+convert between struct tai and a portable 8-byte TAI64 storage format.
+libtai provides similar internal and external formats for TAI64NA.
+
+libtai provides struct caldate to store dates in year-month-day form. It
+can convert struct caldate, under the Gregorian calendar, to a modified
+Julian day number for easy date arithmetic.
+
+libtai provides struct caltime to store calendar dates and times along
+with UTC offsets. It can convert from struct tai to struct caltime in
+UTC, accounting for leap seconds, for accurate date and time display. It
+can also convert back from struct caltime to struct tai for user input.
+Its overall UTC-to-TAI conversion speed is 100x better than the usual
+UNIX mktime() implementation.
+
+This version of libtai requires a UNIX system with gettimeofday(). It
+will be easy to port to other operating systems with compilers
+supporting 64-bit arithmetic.
+
+The libtai source code is in the public domain.
+
+*/
+
+ /*! \file KM_tai.h
+ \version $Id: KM_tai.h,v 1.5 2012/02/21 02:09:30 jhurst Exp $
+ \brief portable time functions
+ */
+
+#ifndef _KUMU_TAI_H_
+#define _KUMU_TAI_H_
+
+#include <KM_platform.h>
+
+//
+namespace Kumu
+{
+ namespace TAI
+ {
+ class caltime;
+
+ //
+ struct tai
+ {
+ ui64_t x;
+ inline void add_seconds(i32_t s) { x += s; }
+ inline void add_minutes(i32_t m) { x += m * 60; }
+ inline void add_hours(i32_t h) { x += h * 3600; }
+ inline void add_days(i32_t d) { x += d * 86400; }
+ void now();
+
+ const tai& operator=(const caltime& rhs);
+ };
+
+ //
+ struct caldate
+ {
+ i32_t year;
+ i32_t month;
+ i32_t day;
+ };
+
+ //
+ class caltime
+ {
+ public:
+ caldate date;
+ i32_t hour;
+ i32_t minute;
+ i32_t second;
+ i32_t offset;
+
+ const caltime& operator=(const tai& rhs);
+ };
+
+
+ } // namespace TAI
+
+} // namespace Kumu
+
+
+#endif // _KUMU_TAI_H_
+
+//
+// end KM_tai.h
+//
diff --git a/asdcplib/src/KM_util.cpp b/asdcplib/src/KM_util.cpp
new file mode 100755
index 0000000..b181484
--- /dev/null
+++ b/asdcplib/src/KM_util.cpp
@@ -0,0 +1,1141 @@
+/*
+Copyright (c) 2005-2012, 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: KM_util.cpp,v 1.40 2012/02/22 19:20:33 jhurst Exp $
+ \brief Utility functions
+ */
+
+#include <KM_util.h>
+#include <KM_prng.h>
+#include <KM_memio.h>
+#include <KM_fileio.h>
+#include <KM_log.h>
+#include <KM_mutex.h>
+#include <ctype.h>
+#include <list>
+#include <map>
+#include <string>
+
+bool Kumu::libdcp_test = false;
+
+const char*
+Kumu::Version()
+{
+ return PACKAGE_VERSION;
+}
+
+
+//------------------------------------------------------------------------------------------
+
+// Result_t Internals
+
+struct map_entry_t
+{
+ int rcode;
+ Kumu::Result_t* result;
+};
+
+
+// WIN32 does not init this in time for use with Result_t(...) below, so it is
+// now a pointer that Result_t(...) fills in when it needs it.
+static Kumu::Mutex* s_MapLock = 0;
+
+static ui32_t s_MapSize = 0;
+static const ui32_t MapMax = 2048;
+static struct map_entry_t s_ResultMap[MapMax];
+
+
+//
+const Kumu::Result_t&
+Kumu::Result_t::Find(int v)
+{
+ if ( v == 0 )
+ return RESULT_OK;
+
+ assert(s_MapLock);
+ AutoMutex L(*s_MapLock);
+
+ for ( ui32_t i = 0; i < s_MapSize; ++i )
+ {
+ if ( s_ResultMap[i].rcode == v )
+ return *s_ResultMap[i].result;
+ }
+
+ return RESULT_UNKNOWN;
+}
+
+//
+Kumu::Result_t
+Kumu::Result_t::Delete(int v)
+{
+ if ( v < -99 || v > 99 )
+ {
+ DefaultLogSink().Error("Cannot delete core result code: %ld\n", v);
+ return RESULT_FAIL;
+ }
+
+ assert(s_MapLock);
+ AutoMutex L(*s_MapLock);
+
+ for ( ui32_t i = 0; i < s_MapSize; ++i )
+ {
+ if ( s_ResultMap[i].rcode == v )
+ {
+ for ( ++i; i < s_MapSize; ++i )
+ s_ResultMap[i-1] = s_ResultMap[i];
+
+ --s_MapSize;
+ return RESULT_OK;
+ }
+ }
+
+ return RESULT_FALSE;
+}
+
+//
+unsigned int
+Kumu::Result_t::End()
+{
+ return s_MapSize;
+}
+
+//
+const Kumu::Result_t&
+Kumu::Result_t::Get(unsigned int i)
+{
+ return *s_ResultMap[i].result;
+}
+
+//
+Kumu::Result_t::Result_t(int v, const char* s, const char* l) : value(v), label(l), symbol(s)
+{
+ assert(l);
+ assert(s);
+
+ if ( v == 0 )
+ return;
+
+ // This may seem tricky, but it is certain that the static values declared in KM_error.h will
+ // be created (and thus this method will be called) before main(...) is called. It is not
+ // until then that threads could be created, thus the mutex will exist before multi-threaded
+ // access could occur.
+ if ( s_MapLock == 0 )
+ s_MapLock = new Kumu::Mutex;
+
+ assert(s_MapLock);
+ AutoMutex L(*s_MapLock);
+
+ for ( ui32_t i = 0; i < s_MapSize; ++i )
+ {
+ if ( s_ResultMap[i].rcode == v )
+ return;
+ }
+
+ assert(s_MapSize+1 < MapMax);
+
+ s_ResultMap[s_MapSize].rcode = v;
+ s_ResultMap[s_MapSize].result = this;
+ ++s_MapSize;
+
+ return;
+}
+
+Kumu::Result_t::~Result_t() {}
+
+
+//------------------------------------------------------------------------------------------
+// DTrace internals
+
+static int s_DTraceSequence = 0;
+
+Kumu::DTrace_t::DTrace_t(const char* Label, Kumu::Result_t* Watch, int Line, const char* File)
+ : m_Label(Label), m_Watch(Watch), m_Line(Line), m_File(File)
+{
+ m_Sequence = s_DTraceSequence++;
+ DefaultLogSink().Debug("@enter %s[%d] (%s at %d)\n", m_Label, m_Sequence, m_File, m_Line);
+}
+
+Kumu::DTrace_t::~DTrace_t()
+{
+ if ( m_Watch != 0 )
+ DefaultLogSink().Debug("@exit %s[%d]: %s\n", m_Label, m_Sequence, m_Watch->Label());
+ else
+ DefaultLogSink().Debug("@exit %s[%d]\n", m_Label, m_Sequence);
+}
+
+//------------------------------------------------------------------------------------------
+
+
+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_L(str);
+ KM_TEST_NULL_L(buf);
+ KM_TEST_NULL_L(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;
+}
+
+#ifdef CONFIG_RANDOM_UUID
+
+// convert a memory region to a NULL-terminated hexadecimal string
+//
+static const char*
+bin2hex_rand(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;
+ Kumu::mem_ptr<byte_t> rand_buf = new byte_t[bin_len];
+ Kumu::FortunaRNG RNG;
+ RNG.FillRandom(rand_buf, bin_len);
+
+ for ( ui32_t i = 0; i < bin_len; i++ )
+ {
+ *p = (bin_buf[i] >> 4) & 0x0f;
+ *p += *p < 10 ? 0x30 : (( ((rand_buf[i] & 0x01) == 0) ? 0x61 : 0x41 ) - 10);
+ p++;
+
+ *p = bin_buf[i] & 0x0f;
+ *p += *p < 10 ? 0x30 : (( (((rand_buf[i] >> 1) & 0x01) == 0) ? 0x61 : 0x41 ) - 10);
+ p++;
+ }
+
+ *p = '\0';
+ return str_buf;
+}
+#endif
+
+// 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;
+
+#ifdef CONFIG_RANDOM_UUID
+ const char* use_random_uuid = getenv("KM_USE_RANDOM_UUID");
+ if ( use_random_uuid != 0 && use_random_uuid[0] != 0 && use_random_uuid[0] != '0' )
+ return bin2hex_rand(bin_buf, bin_len, str_buf, str_len);
+#endif
+
+ 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);
+}
+
+#ifdef LIBDCP_POSIX
+void
+Kumu::ResetTestRNG()
+{
+ FortunaRNG RNG;
+ RNG.Reset();
+}
+#endif
+
+//
+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& Key)
+{
+ byte_t tmp_buf[SymmetricKey_Length];
+ FortunaRNG RNG;
+ RNG.FillRandom(tmp_buf, SymmetricKey_Length);
+ Key.Set(tmp_buf);
+}
+
+
+//------------------------------------------------------------------------------------------
+// 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
+ };
+
+//
+ui32_t
+Kumu::get_BER_length_for_value(ui64_t val)
+{
+ for ( ui32_t i = 0; i < 9; i++ )
+ {
+ if ( ( val & ber_masks[i] ) == 0 )
+ return i + 1;
+ }
+
+ ui64Printer tmp_i(val);
+ DefaultLogSink().Error("BER integer encoding not supported for large value %s\n", tmp_i.c_str());
+ return 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 integer length %u exceeds maximum size of 9\n", ber_len);
+ return false;
+ }
+
+ if ( ( val & ber_masks[ber_len - 1] ) != 0 )
+ {
+ ui64Printer tmp_i(val);
+ DefaultLogSink().Error("BER integer length %u too small for value %s\n", ber_len, 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;
+}
+
+
+//------------------------------------------------------------------------------------------
+
+#ifndef KM_WIN32
+#include <time.h>
+#endif
+
+//
+Kumu::Timestamp::Timestamp() : m_TZOffsetMinutes(0) {
+ if (libdcp_test)
+ {
+ m_Timestamp.x = 42;
+ }
+ else
+ {
+ m_Timestamp.now();
+ }
+}
+
+Kumu::Timestamp::Timestamp(const Timestamp& rhs) {
+ m_Timestamp = rhs.m_Timestamp;
+ m_TZOffsetMinutes = rhs.m_TZOffsetMinutes;
+}
+
+Kumu::Timestamp::Timestamp(const char* datestr) : m_TZOffsetMinutes(0) {
+ DecodeString(datestr);
+}
+
+Kumu::Timestamp::~Timestamp() {
+}
+
+//
+const Kumu::Timestamp&
+Kumu::Timestamp::operator=(const Timestamp& rhs)
+{
+ m_Timestamp = rhs.m_Timestamp;
+ m_TZOffsetMinutes = rhs.m_TZOffsetMinutes;
+ return *this;
+}
+
+bool Kumu::Timestamp::operator<(const Timestamp& rhs) const {
+ return m_Timestamp.x < rhs.m_Timestamp.x;
+}
+
+bool Kumu::Timestamp::operator>(const Timestamp& rhs) const {
+ return m_Timestamp.x > rhs.m_Timestamp.x;
+}
+
+bool Kumu::Timestamp::operator==(const Timestamp& rhs) const {
+ return m_Timestamp.x == rhs.m_Timestamp.x;
+}
+
+bool Kumu::Timestamp::operator!=(const Timestamp& rhs) const {
+ return m_Timestamp.x != rhs.m_Timestamp.x;
+}
+
+//
+void
+Kumu::Timestamp::GetComponents(ui16_t& Year, ui8_t& Month, ui8_t& Day,
+ ui8_t& Hour, ui8_t& Minute, ui8_t& Second) const
+{
+ TAI::caltime ct;
+ ct = m_Timestamp;
+ Year = ct.date.year;
+ Month = ct.date.month;
+ Day = ct.date.day;
+ Hour = ct.hour;
+ Minute = ct.minute;
+ Second = ct.second;
+}
+
+//
+void
+Kumu::Timestamp::SetComponents(const ui16_t& Year, const ui8_t& Month, const ui8_t& Day,
+ const ui8_t& Hour, const ui8_t& Minute, const ui8_t& Second)
+{
+ TAI::caltime ct;
+ ct.date.year = Year;
+ ct.date.month = Month;
+ ct.date.day = Day;
+ ct.hour = Hour;
+ ct.minute = Minute;
+ ct.second = Second;
+ ct.offset = 0;
+ m_Timestamp = ct;
+ m_TZOffsetMinutes = 0;
+}
+
+// returns false if the requested adjustment is out of range
+bool
+Kumu::Timestamp::SetTZOffsetMinutes(const i32_t& minutes)
+{
+ static const i32_t tz_limit = 14 * 60 * 60;
+
+ if ( minutes < ( - tz_limit) || minutes > tz_limit )
+ return false;
+
+ m_TZOffsetMinutes = minutes;
+ return true;
+}
+
+//
+const char*
+Kumu::Timestamp::EncodeString(char* str_buf, ui32_t buf_len) const
+{
+ if ( buf_len < ( DateTimeLen + 1 ) )
+ return 0;
+
+ ui16_t year;
+ ui8_t month, day, hour, minute, second;
+ ui32_t ofst_hours = 0, ofst_minutes = 0;
+ char direction = '+';
+
+ if ( m_TZOffsetMinutes == 0 )
+ {
+ GetComponents(year, month, day, hour, minute, second);
+ }
+ else
+ {
+ // calculate local time
+ Kumu::Timestamp tmp_t(*this);
+ tmp_t.AddMinutes(m_TZOffsetMinutes);
+ tmp_t.GetComponents(year, month, day, hour, minute, second);
+
+ ofst_hours = abs(m_TZOffsetMinutes) / 60;
+ ofst_minutes = abs(m_TZOffsetMinutes) % 60;
+
+ if ( m_TZOffsetMinutes < 0 )
+ direction = '-';
+ }
+
+ // 2004-05-01T13:20:00+00:00
+ snprintf(str_buf, buf_len,
+ "%04hu-%02hu-%02huT%02hu:%02hu:%02hu%c%02hu:%02hu",
+ year, month, day, hour, minute, second,
+ direction, ofst_hours, ofst_minutes);
+
+ return str_buf;
+}
+
+//
+bool
+Kumu::Timestamp::DecodeString(const char* datestr)
+{
+ if ( ! ( isdigit(datestr[0]) && isdigit(datestr[1]) && isdigit(datestr[2]) && isdigit(datestr[3]) )
+ || datestr[4] != '-'
+ || ! ( isdigit(datestr[5]) && isdigit(datestr[6]) )
+ || datestr[7] != '-'
+ || ! ( isdigit(datestr[8]) && isdigit(datestr[9]) ) )
+ return false;
+
+ ui32_t char_count = 10;
+ TAI::caltime YMDhms;
+ YMDhms.offset = 0;
+ YMDhms.date.year = atoi(datestr);
+ YMDhms.date.month = atoi(datestr + 5);
+ YMDhms.date.day = atoi(datestr + 8);
+
+ if ( datestr[10] == 'T' )
+ {
+ if ( ! ( isdigit(datestr[11]) && isdigit(datestr[12]) )
+ || datestr[13] != ':'
+ || ! ( isdigit(datestr[14]) && isdigit(datestr[15]) ) )
+ return false;
+
+ char_count += 6;
+ YMDhms.hour = atoi(datestr + 11);
+ YMDhms.minute = atoi(datestr + 14);
+
+ if ( datestr[16] == ':' )
+ {
+ if ( ! ( isdigit(datestr[17]) && isdigit(datestr[18]) ) )
+ return false;
+
+ char_count += 3;
+ YMDhms.second = atoi(datestr + 17);
+ }
+
+ if ( datestr[19] == '.' )
+ {
+ if ( ! ( isdigit(datestr[20]) && isdigit(datestr[21]) && isdigit(datestr[22]) ) )
+ return false;
+
+ // we don't carry the ms value
+ datestr += 4;
+ }
+
+ if ( datestr[19] == '-' || datestr[19] == '+' )
+ {
+ if ( ! ( isdigit(datestr[20]) && isdigit(datestr[21]) )
+ || datestr[22] != ':'
+ || ! ( isdigit(datestr[23]) && isdigit(datestr[24]) ) )
+ return false;
+
+ char_count += 6;
+
+ ui32_t TZ_hh = atoi(datestr + 20);
+ ui32_t TZ_mm = atoi(datestr + 23);
+ if ((TZ_hh > 14) || (TZ_mm > 59) || ((TZ_hh == 14) && (TZ_mm > 0)))
+ return false;
+
+ i32_t TZ_offset = 60 * TZ_hh + TZ_mm;
+ if (datestr[19] == '-')
+ TZ_offset = -TZ_offset;
+ /* at this point, TZ_offset reflects the contents of the string */
+
+ /* a negative offset is behind UTC and so needs to increment to
+ * convert, while a positive offset must do the reverse */
+ YMDhms.offset = TZ_offset;
+ }
+ else if (datestr[19] == 'Z')
+ {
+ /* act as if the offset were +00:00 */
+ char_count++;
+ }
+ }
+
+ if ( datestr[char_count] != 0 )
+ {
+ Kumu::DefaultLogSink().Error("Unexpected extra characters in string: %s (%ld)\n",
+ datestr, char_count);
+ return false;
+ }
+
+ m_Timestamp = YMDhms;
+ m_TZOffsetMinutes = YMDhms.offset;
+ return true;
+}
+
+//
+bool
+Kumu::Timestamp::HasValue() const
+{
+ return true;
+}
+
+//
+bool
+Kumu::Timestamp::Unarchive(MemIOReader* Reader)
+{
+ ui16_t year;
+ ui8_t month, day, hour, minute, second, tick;
+
+ assert(Reader);
+ if ( ! Reader->ReadUi16BE(&year) ) return false;
+ if ( ! Reader->ReadUi8(&month) ) return false;
+ if ( ! Reader->ReadUi8(&day) ) return false;
+ if ( ! Reader->ReadUi8(&hour) ) return false;
+ if ( ! Reader->ReadUi8(&minute) ) return false;
+ if ( ! Reader->ReadUi8(&second) ) return false;
+ if ( ! Reader->ReadUi8(&tick) ) return false;
+ SetComponents(year, month, day, hour, minute, second);
+ return true;
+}
+
+//
+bool
+Kumu::Timestamp::Archive(MemIOWriter* Writer) const
+{
+ assert(Writer);
+
+ ui16_t year;
+ ui8_t month, day, hour, minute, second, tick = 0;
+ GetComponents(year, month, day, hour, minute, second);
+
+ if ( ! Writer->WriteUi16BE(year) ) return false;
+ if ( ! Writer->WriteUi8(month) ) return false;
+ if ( ! Writer->WriteUi8(day) ) return false;
+ if ( ! Writer->WriteUi8(hour) ) return false;
+ if ( ! Writer->WriteUi8(minute) ) return false;
+ if ( ! Writer->WriteUi8(second) ) return false;
+ if ( ! Writer->WriteUi8(tick) ) return false;
+ return true;
+}
+
+//
+ui64_t
+Kumu::Timestamp::GetCTime() const
+{
+ return m_Timestamp.x - ui64_C(4611686018427387914);
+}
+
+
+//------------------------------------------------------------------------------------------
+
+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->Length();
+ 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;
+}
+
+
+// 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 ByteString& Buf)
+{
+ if ( m_Capacity < Buf.m_Capacity )
+ return RESULT_ALLOC;
+
+ memcpy(m_Data, Buf.m_Data, Buf.m_Length);
+ m_Length = Buf.m_Length;
+ return RESULT_OK;
+}
+
+
+// Sets the size of the internally allocate buffer.
+Kumu::Result_t
+Kumu::ByteString::Capacity(ui32_t cap_size)
+{
+ if ( m_Capacity >= cap_size )
+ return RESULT_OK;
+
+ byte_t* tmp_data = 0;
+ if ( m_Data != 0 )
+ {
+ if ( m_Length > 0 )
+ tmp_data = m_Data;
+ else
+ free(m_Data);
+ }
+
+ if ( ( m_Data = (byte_t*)malloc(cap_size) ) == 0 )
+ return RESULT_ALLOC;
+
+ if ( tmp_data != 0 )
+ {
+ assert(m_Length > 0);
+ memcpy(m_Data, tmp_data, m_Length);
+ free(tmp_data);
+ }
+
+ m_Capacity = cap_size;
+ 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/asdcplib/src/KM_util.h b/asdcplib/src/KM_util.h
new file mode 100755
index 0000000..a9793ba
--- /dev/null
+++ b/asdcplib/src/KM_util.h
@@ -0,0 +1,547 @@
+/*
+Copyright (c) 2005-2012, 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: KM_util.h,v 1.32 2012/02/21 02:09:30 jhurst Exp $
+ \brief Utility functions
+ */
+
+#ifndef _KM_UTIL_H_
+#define _KM_UTIL_H_
+
+#include <KM_memio.h>
+#include <KM_error.h>
+#include <KM_tai.h>
+#include <string.h>
+#include <string>
+#include <list>
+
+namespace Kumu
+{
+ extern bool libdcp_test;
+
+ // The version number declaration and explanation are in ../configure.ac
+ const char* Version();
+
+ // a class that represents the string form of a value
+ template <class T, int SIZE = 16>
+ class IntPrinter : public std::string
+ {
+ KM_NO_COPY_CONSTRUCT(IntPrinter);
+ IntPrinter();
+
+ protected:
+ const char* m_format;
+ char m_strbuf[SIZE];
+
+ public:
+ IntPrinter(const char* format, T value) {
+ assert(format);
+ m_format = format;
+ snprintf(m_strbuf, SIZE, m_format, value);
+ }
+
+ inline operator const char*() { return m_strbuf; }
+ inline const char* c_str() { return m_strbuf; }
+ inline const char* set_value(T value) {
+ snprintf(m_strbuf, SIZE, m_format, value);
+ return m_strbuf;
+ }
+ };
+
+ 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 output 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;
+ }
+
+ // Return the BER length required to encode value. A return value of zero
+ // indicates a value too large for this library.
+ ui32_t get_BER_length_for_value(ui64_t valuse);
+
+ // 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);
+
+ //----------------------------------------------------------------
+ //
+
+ // an abstract base class that objects implement to serialize state
+ // to and from a binary stream.
+ class IArchive
+ {
+ public:
+ virtual ~IArchive(){}
+ virtual bool HasValue() const = 0;
+ virtual ui32_t ArchiveLength() const = 0;
+ virtual bool Archive(MemIOWriter* Writer) const = 0;
+ virtual bool Unarchive(MemIOReader* Reader) = 0;
+ };
+
+ //
+ template <class T>
+ class ArchivableList : public std::list<T>, public IArchive
+ {
+ public:
+ ArchivableList() {}
+ virtual ~ArchivableList() {}
+
+ bool HasValue() const { return ! this->empty(); }
+
+ ui32_t ArchiveLength() const
+ {
+ ui32_t arch_size = sizeof(ui32_t);
+
+ typename ArchivableList<T>::const_iterator i = this->begin();
+ for ( ; i != this->end(); i++ )
+ arch_size += i->ArchiveLength();
+
+ return arch_size;
+ }
+
+ bool Unarchive(Kumu::MemIOReader* Reader)
+ {
+ if ( Reader == 0 ) return false;
+ ui32_t read_size = 0;
+ if ( ! Reader->ReadUi32BE(&read_size) ) return false;
+ for ( ui32_t i = 0; i < read_size; i++ )
+ {
+ T TmpTP;
+ if ( ! TmpTP.Unarchive(Reader) ) return false;
+ this->push_back(TmpTP);
+ }
+
+ return true;
+ }
+
+ bool Archive(Kumu::MemIOWriter* Writer) const
+ {
+ if ( Writer == 0 ) return false;
+ if ( ! Writer->WriteUi32BE(static_cast<ui32_t>(this->size())) ) return false;
+ typename ArchivableList<T>::const_iterator i = this->begin();
+ for ( ; i != this->end(); i++ )
+ if ( ! i->Archive(Writer) ) return false;
+
+ return true;
+ }
+ };
+
+ // archivable version of std::string
+
+ //
+ class ArchivableString : public std::string, public Kumu::IArchive
+ {
+
+ public:
+ ArchivableString() {}
+ ArchivableString(const char* sz) : std::string(sz) {}
+ ArchivableString(const std::string& s) : std::string(s) {}
+ virtual ~ArchivableString() {}
+
+ bool HasValue() const { return ! this->empty(); }
+ ui32_t ArchiveLength() const { return static_cast<ui32_t>((sizeof(ui32_t) + this->size())|0xffffffff); }
+
+ bool Archive(MemIOWriter* Writer) const {
+ if ( Writer == 0 ) return false;
+ return Writer->WriteString(*this);
+ }
+
+ bool Unarchive(MemIOReader* Reader) {
+ if ( Reader == 0 ) return false;
+ return Reader->ReadString(*this);
+ }
+ };
+
+ //
+ typedef Kumu::ArchivableList<ArchivableString> StringList;
+
+ //
+ // the base of all identifier classes, Identifier is not usually used directly
+ // see UUID and SymmetricKey below for more detail.
+ //
+ 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) : IArchive() {
+ m_HasValue = rhs.m_HasValue;
+ memcpy(m_Value, rhs.m_Value, SIZE);
+ }
+
+ virtual ~Identifier() {}
+
+ const Identifier& operator=(const Identifier& rhs) {
+ m_HasValue = rhs.m_HasValue;
+ 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 void Reset() { m_HasValue = false; memset(m_Value, 0, 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;
+ m_HasValue = ( hex2bin(str, m_Value, SIZE, &char_count) == 0 );
+ if ( m_HasValue && char_count != SIZE )
+ m_HasValue = false;
+ return m_HasValue;
+ }
+
+ 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;
+ m_HasValue = ( base64decode(str, m_Value, SIZE, &char_count) == 0 );
+ if ( m_HasValue && char_count != SIZE )
+ m_HasValue = false;
+ return m_HasValue;
+ }
+
+ inline const char* EncodeBase64(char* buf, ui32_t buf_len) const {
+ return base64encode(m_Value, SIZE, buf, buf_len);
+ }
+
+ inline bool HasValue() const { return m_HasValue; }
+
+ inline ui32_t ArchiveLength() const { return SIZE; }
+
+ inline bool Unarchive(Kumu::MemIOReader* Reader) {
+ m_HasValue = Reader->ReadRaw(m_Value, SIZE);
+ return m_HasValue;
+ }
+
+ inline 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* EncodeString(char* buf, ui32_t buf_len) const {
+ return bin2UUIDhex(m_Value, Size(), buf, buf_len);
+ }
+
+ inline const char* EncodeHex(char* buf, ui32_t buf_len) const {
+ return bin2UUIDhex(m_Value, Size(), buf, buf_len);
+ }
+ };
+
+ void GenRandomUUID(byte_t* buf); // buf must be UUID_Length or longer
+ void GenRandomValue(UUID&);
+#ifdef LIBDCP_POSIX
+ void ResetTestRNG();
+#endif
+
+ typedef ArchivableList<UUID> UUIDList;
+
+ // 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
+ {
+ TAI::tai m_Timestamp; // always UTC
+ i32_t m_TZOffsetMinutes;
+
+ public:
+ Timestamp();
+ Timestamp(const Timestamp& rhs);
+ Timestamp(const char* datestr);
+ Timestamp(const ui16_t& Year, const ui8_t& Month, const ui8_t& Day);
+ Timestamp(const ui16_t& Year, const ui8_t& Month, const ui8_t& Day,
+ const ui8_t& Hour, const ui8_t& Minute, const ui8_t& Second);
+ 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;
+ bool operator!=(const Timestamp& rhs) const;
+
+ // always UTC
+ void GetComponents(ui16_t& Year, ui8_t& Month, ui8_t& Day,
+ ui8_t& Hour, ui8_t& Minute, ui8_t& Second) const;
+ void SetComponents(const ui16_t& Year, const ui8_t& Month, const ui8_t& Day,
+ const ui8_t& Hour, const ui8_t& Minute, const ui8_t& Second);
+
+ // 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
+ bool DecodeString(const char* datestr);
+
+ // Add the given number of days, hours, minutes, or seconds to the timestamp value.
+ // Values less than zero will cause the timestamp to decrease
+ inline void AddDays(const i32_t& d) { m_Timestamp.add_days(d); }
+ inline void AddHours(const i32_t& h) { m_Timestamp.add_hours(h); }
+ inline void AddMinutes(const i32_t& m) { m_Timestamp.add_minutes(m); }
+ inline void AddSeconds(const i32_t& s) { m_Timestamp.add_seconds(s); }
+
+ // returns false if the requested adjustment is out of range
+ bool SetTZOffsetMinutes(const i32_t& minutes);
+ inline i32_t GetTZOffsetMinutes() const { return m_TZOffsetMinutes; }
+
+ // Return the number of seconds since the Unix epoch UTC (1970-01-01T00:00:00+00:00)
+ ui64_t GetCTime() const;
+
+ // Read and write the timestamp (always UTC) value as a byte string having
+ // the following format:
+ // | 16 bits int, big-endian | 8 bits | 8 bits | 8 bits | 8 bits | 8 bits |
+ // | Year A.D | Month(1-12) | Day(1-31) | Hour(0-23) | Minute(0-59) | Second(0-59) |
+ //
+ virtual bool HasValue() const;
+ virtual ui32_t ArchiveLength() const { return 8L; }
+ virtual bool Archive(MemIOWriter* Writer) const;
+ virtual bool Unarchive(MemIOReader* Reader);
+ };
+
+ //
+ class ByteString : public IArchive
+ {
+ 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 or resets the size of the internally allocated buffer.
+ 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 { assert(m_Data); return m_Data; }
+
+ // returns a non-const pointer to the essence data
+ inline byte_t* Data() { assert(m_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);
+ Result_t Set(const ByteString& Buf);
+
+ inline virtual bool HasValue() const { return m_Length > 0; }
+
+ inline virtual ui32_t ArchiveLength() const { return m_Length; }
+
+ inline virtual bool Archive(MemIOWriter* Writer) const {
+ assert(Writer);
+ if ( ! Writer->WriteUi32BE(m_Length) ) return false;
+ if ( ! Writer->WriteRaw(m_Data, m_Length) ) return false;
+ return true;
+ }
+
+ inline virtual bool Unarchive(MemIOReader* Reader) {
+ assert(Reader);
+ ui32_t tmp_len;
+ if ( ! Reader->ReadUi32BE(&tmp_len) ) return false;
+ if ( KM_FAILURE(Capacity(tmp_len)) ) return false;
+ if ( ! Reader->ReadRaw(m_Data, tmp_len) ) return false;
+ m_Length = tmp_len;
+ return true;
+ }
+ };
+
+ inline void hexdump(const ByteString& buf, FILE*) {
+ hexdump(buf.RoData(), buf.Length());
+ }
+
+
+} // namespace Kumu
+
+
+#endif // _KM_UTIL_H_
+
+//
+// end KM_util.h
+//
diff --git a/asdcplib/src/KM_xml.cpp b/asdcplib/src/KM_xml.cpp
new file mode 100644
index 0000000..98dccc4
--- /dev/null
+++ b/asdcplib/src/KM_xml.cpp
@@ -0,0 +1,1012 @@
+/*
+Copyright (c) 2005-2010, 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_xml.cpp
+ \version $Id: KM_xml.cpp,v 1.19 2011/12/01 18:42:39 jhurst Exp $
+ \brief XML writer
+*/
+
+#include <KM_xml.h>
+#include <KM_log.h>
+#include <KM_mutex.h>
+#include <stack>
+#include <map>
+
+#ifdef HAVE_EXPAT
+# ifdef HAVE_XERCES_C
+# error "Both HAVE_EXPAT and HAVE_XERCES_C defined"
+# endif
+#include <expat.h>
+#endif
+
+#ifdef HAVE_XERCES_C
+# ifdef HAVE_EXPAT
+# error "Both HAVE_EXPAT and HAVE_XERCES_C defined"
+# endif
+
+#include <xercesc/util/PlatformUtils.hpp>
+#include <xercesc/util/XMLString.hpp>
+#include <xercesc/util/TransService.hpp>
+#include <xercesc/sax/AttributeList.hpp>
+#include <xercesc/sax/HandlerBase.hpp>
+#include <xercesc/sax/ErrorHandler.hpp>
+#include <xercesc/sax/SAXParseException.hpp>
+#include <xercesc/parsers/SAXParser.hpp>
+#include <xercesc/framework/MemBufInputSource.hpp>
+#include <xercesc/framework/XMLPScanToken.hpp>
+
+
+XERCES_CPP_NAMESPACE_USE
+
+namespace Kumu {
+ void init_xml_dom();
+ typedef std::basic_string<XMLCh> XercesString;
+ bool UTF_8_to_XercesString(const std::string& in_str, XercesString& out_str);
+ bool UTF_8_to_XercesString(const char* in_str, XercesString& out_str);
+ bool XercesString_to_UTF_8(const XercesString& in_str, std::string& out_str);
+ bool XercesString_to_UTF_8(const XMLCh* in_str, std::string& out_str);
+}
+
+#endif
+
+using namespace Kumu;
+
+
+class ns_map : public std::map<std::string, XMLNamespace*>
+{
+public:
+ ~ns_map()
+ {
+ while ( ! empty() )
+ {
+ ns_map::iterator ni = begin();
+ delete ni->second;
+ erase(ni);
+ }
+ }
+};
+
+
+Kumu::XMLElement::XMLElement(const char* name) : m_Namespace(0), m_NamespaceOwner(0)
+{
+ m_Name = name;
+}
+
+Kumu::XMLElement::~XMLElement()
+{
+ for ( Elem_i i = m_ChildList.begin(); i != m_ChildList.end(); i++ )
+ delete *i;
+
+ delete (ns_map*)m_NamespaceOwner;
+}
+
+//
+void
+Kumu::XMLElement::SetAttr(const char* name, const char* value)
+{
+ NVPair TmpVal;
+ TmpVal.name = name;
+ TmpVal.value = value;
+
+ m_AttrList.push_back(TmpVal);
+}
+
+//
+Kumu::XMLElement*
+Kumu::XMLElement::AddChild(Kumu::XMLElement* element)
+{
+ m_ChildList.push_back(element); // takes posession!
+ return element;
+}
+
+//
+Kumu::XMLElement*
+Kumu::XMLElement::AddChild(const char* name)
+{
+ XMLElement* tmpE = new XMLElement(name);
+ m_ChildList.push_back(tmpE);
+ return tmpE;
+}
+
+//
+Kumu::XMLElement*
+Kumu::XMLElement::AddChildWithContent(const char* name, const std::string& value)
+{
+ return AddChildWithContent(name, value.c_str());
+}
+
+//
+void
+Kumu::XMLElement::AppendBody(const std::string& value)
+{
+ m_Body += value;
+}
+
+//
+void
+Kumu::XMLElement::SetBody(const std::string& value)
+{
+ m_Body = value;
+}
+
+//
+Kumu::XMLElement*
+Kumu::XMLElement::AddChildWithContent(const char* name, const char* value)
+{
+ assert(name);
+ assert(value);
+ XMLElement* tmpE = new XMLElement(name);
+ tmpE->m_Body = value;
+ m_ChildList.push_back(tmpE);
+ return tmpE;
+}
+
+//
+Kumu::XMLElement*
+Kumu::XMLElement::AddChildWithPrefixedContent(const char* name, const char* prefix, const char* value)
+{
+ XMLElement* tmpE = new XMLElement(name);
+ tmpE->m_Body = prefix;
+ tmpE->m_Body += value;
+ m_ChildList.push_back(tmpE);
+ return tmpE;
+}
+
+//
+void
+Kumu::XMLElement::AddComment(const char* value)
+{
+ m_Body += " <!-- ";
+ m_Body += value;
+ m_Body += " -->\n";
+}
+
+//
+void
+Kumu::XMLElement::Render(std::string& outbuf) const
+{
+ outbuf = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
+ RenderElement(outbuf, 0);
+}
+
+//
+inline void
+add_spacer(std::string& outbuf, i32_t depth)
+{
+ while ( depth-- )
+ outbuf+= " ";
+}
+
+//
+void
+Kumu::XMLElement::RenderElement(std::string& outbuf, ui32_t depth) const
+{
+ add_spacer(outbuf, depth);
+
+ outbuf += "<";
+ outbuf += m_Name;
+
+ // render attributes
+ for ( Attr_i i = m_AttrList.begin(); i != m_AttrList.end(); i++ )
+ {
+ outbuf += " ";
+ outbuf += (*i).name;
+ outbuf += "=\"";
+ outbuf += (*i).value;
+ outbuf += "\"";
+ }
+
+ outbuf += ">";
+
+ // body contents and children
+ if ( ! m_ChildList.empty() )
+ {
+ outbuf += "\n";
+
+ // render body
+ if ( m_Body.length() > 0 )
+ outbuf += m_Body;
+
+ for ( Elem_i i = m_ChildList.begin(); i != m_ChildList.end(); i++ )
+ (*i)->RenderElement(outbuf, depth + 1);
+
+ add_spacer(outbuf, depth);
+ }
+ else if ( m_Body.length() > 0 )
+ {
+ outbuf += m_Body;
+ }
+
+ outbuf += "</";
+ outbuf += m_Name;
+ outbuf += ">\n";
+}
+
+//
+bool
+Kumu::XMLElement::HasName(const char* name) const
+{
+ if ( name == 0 || *name == 0 )
+ return false;
+
+ return (m_Name == name);
+}
+
+
+void
+Kumu::XMLElement::SetName(const char* name)
+{
+ if ( name != 0)
+ m_Name = name;
+}
+
+//
+const char*
+Kumu::XMLElement::GetAttrWithName(const char* name) const
+{
+ for ( Attr_i i = m_AttrList.begin(); i != m_AttrList.end(); i++ )
+ {
+ if ( (*i).name == name )
+ return (*i).value.c_str();
+ }
+
+ return 0;
+}
+
+//
+Kumu::XMLElement*
+Kumu::XMLElement::GetChildWithName(const char* name) const
+{
+ for ( Elem_i i = m_ChildList.begin(); i != m_ChildList.end(); i++ )
+ {
+ if ( (*i)->HasName(name) )
+ return *i;
+ }
+
+ return 0;
+}
+
+//
+const Kumu::ElementList&
+Kumu::XMLElement::GetChildrenWithName(const char* name, ElementList& outList) const
+{
+ assert(name);
+ for ( Elem_i i = m_ChildList.begin(); i != m_ChildList.end(); i++ )
+ {
+ if ( (*i)->HasName(name) )
+ outList.push_back(*i);
+
+ if ( ! (*i)->m_ChildList.empty() )
+ (*i)->GetChildrenWithName(name, outList);
+ }
+
+ return outList;
+}
+
+//
+void
+Kumu::XMLElement::DeleteAttributes()
+{
+ m_AttrList.clear();
+}
+
+//
+void
+Kumu::XMLElement::DeleteAttrWithName(const char* name)
+{
+ assert(name);
+ AttributeList::iterator i = m_AttrList.begin();
+
+ while ( i != m_AttrList.end() )
+ {
+ if ( i->name == std::string(name) )
+ m_AttrList.erase(i++);
+ else
+ ++i;
+ }
+}
+
+//
+void
+Kumu::XMLElement::DeleteChildren()
+{
+ while ( ! m_ChildList.empty() )
+ {
+ delete m_ChildList.back();
+ m_ChildList.pop_back();
+ }
+}
+
+//
+void
+Kumu::XMLElement::DeleteChild(const XMLElement* element)
+{
+ if ( element != 0 )
+ {
+ for ( ElementList::iterator i = m_ChildList.begin(); i != m_ChildList.end(); i++ )
+ {
+ if ( *i == element )
+ {
+ delete *i;
+ m_ChildList.erase(i);
+ return;
+ }
+ }
+ }
+}
+
+//
+void
+Kumu::XMLElement::ForgetChild(const XMLElement* element)
+{
+ if ( element != 0 )
+ {
+ for ( ElementList::iterator i = m_ChildList.begin(); i != m_ChildList.end(); i++ )
+ {
+ if ( *i == element )
+ {
+ m_ChildList.erase(i);
+ return;
+ }
+ }
+ }
+}
+
+//
+bool
+Kumu::XMLElement::ParseString(const ByteString& document)
+{
+ return ParseString((const char*)document.RoData(), document.Length());
+}
+
+//
+bool
+Kumu::XMLElement::ParseString(const std::string& document)
+{
+ return ParseString(document.c_str(), document.size());
+}
+
+
+//----------------------------------------------------------------------------------------------------
+
+#ifdef HAVE_EXPAT
+
+
+class ExpatParseContext
+{
+ KM_NO_COPY_CONSTRUCT(ExpatParseContext);
+ ExpatParseContext();
+public:
+ ns_map* Namespaces;
+ std::stack<XMLElement*> Scope;
+ XMLElement* Root;
+
+ ExpatParseContext(XMLElement* root) : Root(root) {
+ Namespaces = new ns_map;
+ assert(Root);
+ }
+
+ ~ExpatParseContext() {}
+};
+
+// expat wrapper functions
+//
+static void
+xph_start(void* p, const XML_Char* name, const XML_Char** attrs)
+{
+ assert(p); assert(name); assert(attrs);
+ ExpatParseContext* Ctx = (ExpatParseContext*)p;
+ XMLElement* Element;
+
+ const char* ns_root = name;
+ const char* local_name = strchr(name, '|');
+ if ( local_name != 0 )
+ name = local_name + 1;
+
+ if ( Ctx->Scope.empty() )
+ {
+ Ctx->Scope.push(Ctx->Root);
+ }
+ else
+ {
+ Element = Ctx->Scope.top();
+ Ctx->Scope.push(Element->AddChild(name));
+ }
+
+ Element = Ctx->Scope.top();
+ Element->SetName(name);
+
+ // map the namespace
+ std::string key;
+ if ( ns_root != name )
+ key.assign(ns_root, name - ns_root - 1);
+
+ ns_map::iterator ni = Ctx->Namespaces->find(key);
+ if ( ni != Ctx->Namespaces->end() )
+ Element->SetNamespace(ni->second);
+
+ // set attributes
+ for ( int i = 0; attrs[i] != 0; i += 2 )
+ {
+ if ( ( local_name = strchr(attrs[i], '|') ) == 0 )
+ local_name = attrs[i];
+ else
+ local_name++;
+
+ Element->SetAttr(local_name, attrs[i+1]);
+ }
+}
+
+//
+static void
+xph_end(void* p, const XML_Char* name)
+{
+ assert(p); assert(name);
+ ExpatParseContext* Ctx = (ExpatParseContext*)p;
+ Ctx->Scope.pop();
+}
+
+//
+static void
+xph_char(void* p, const XML_Char* data, int len)
+{
+ assert(p); assert(data);
+ ExpatParseContext* Ctx = (ExpatParseContext*)p;
+
+ if ( len > 0 )
+ {
+ std::string tmp_str;
+ tmp_str.assign(data, len);
+ Ctx->Scope.top()->AppendBody(tmp_str);
+ }
+}
+
+//
+void
+xph_namespace_start(void* p, const XML_Char* ns_prefix, const XML_Char* ns_name)
+{
+ assert(p); assert(ns_name);
+ ExpatParseContext* Ctx = (ExpatParseContext*)p;
+
+ if ( ns_prefix == 0 )
+ ns_prefix = "";
+
+ ns_map::iterator ni = Ctx->Namespaces->find(ns_name);
+
+ if ( ni != Ctx->Namespaces->end() )
+ {
+ if ( ni->second->Name() != std::string(ns_name) )
+ {
+ DefaultLogSink().Error("Duplicate prefix: %s\n", ns_prefix);
+ return;
+ }
+ }
+ else
+ {
+ XMLNamespace* Namespace = new XMLNamespace(ns_prefix, ns_name);
+ Ctx->Namespaces->insert(ns_map::value_type(ns_name, Namespace));
+ }
+}
+
+//
+bool
+Kumu::XMLElement::ParseString(const char* document, ui32_t doc_len)
+{
+ XML_Parser Parser = XML_ParserCreateNS("UTF-8", '|');
+
+ if ( Parser == 0 )
+ {
+ DefaultLogSink().Error("Error allocating memory for XML parser.\n");
+ return false;
+ }
+
+ ExpatParseContext Ctx(this);
+ XML_SetUserData(Parser, (void*)&Ctx);
+ XML_SetElementHandler(Parser, xph_start, xph_end);
+ XML_SetCharacterDataHandler(Parser, xph_char);
+ XML_SetStartNamespaceDeclHandler(Parser, xph_namespace_start);
+
+ if ( ! XML_Parse(Parser, document, doc_len, 1) )
+ {
+ XML_ParserFree(Parser);
+ DefaultLogSink().Error("XML Parse error on line %d: %s\n",
+ XML_GetCurrentLineNumber(Parser),
+ XML_ErrorString(XML_GetErrorCode(Parser)));
+ return false;
+ }
+
+ XML_ParserFree(Parser);
+
+ if ( ! Ctx.Namespaces->empty() )
+ m_NamespaceOwner = (void*)Ctx.Namespaces;
+
+ return true;
+}
+
+//------------------------------------------------------------------------------------------
+
+struct xph_test_wrapper
+{
+ XML_Parser Parser;
+ bool Status;
+
+ xph_test_wrapper(XML_Parser p) : Parser(p), Status(false) {}
+};
+
+// expat wrapper functions, map callbacks to IASAXHandler
+//
+static void
+xph_test_start(void* p, const XML_Char*, const XML_Char**)
+{
+ assert(p);
+ xph_test_wrapper* Wrapper = (xph_test_wrapper*)p;
+
+ Wrapper->Status = true;
+ XML_StopParser(Wrapper->Parser, false);
+}
+
+
+//
+bool
+Kumu::StringIsXML(const char* document, ui32_t len)
+{
+ if ( document == 0 )
+ return false;
+
+ if ( len == 0 )
+ len = strlen(document);
+
+ XML_Parser Parser = XML_ParserCreate("UTF-8");
+
+ if ( Parser == 0 )
+ {
+ DefaultLogSink().Error("Error allocating memory for XML parser.\n");
+ return false;
+ }
+
+ xph_test_wrapper Wrapper(Parser);
+ XML_SetUserData(Parser, (void*)&Wrapper);
+ XML_SetStartElementHandler(Parser, xph_test_start);
+
+ XML_Parse(Parser, document, len, 1);
+ XML_ParserFree(Parser);
+ return Wrapper.Status;
+}
+
+#endif
+
+//----------------------------------------------------------------------------------------------------
+
+#ifdef HAVE_XERCES_C
+
+static Mutex sg_xerces_init_lock; // protect the xerces initialized
+static bool sg_xml_init = false; // signal initialization
+static Mutex sg_coder_lock; // protect the transcoder context
+static XMLTranscoder* sg_coder = 0;
+static const int sg_coder_buf_len = 128 * 1024;
+static char sg_coder_buf[sg_coder_buf_len + 8];
+static unsigned char sg_coder_counts[sg_coder_buf_len / sizeof(XMLCh)]; // see XMLTranscoder::transcodeFrom
+
+static const XMLCh sg_LS[] = { chLatin_L, chLatin_S, chNull };
+static const XMLCh sg_label_UTF_8[] = { chLatin_U, chLatin_T, chLatin_F,
+ chDash, chDigit_8, chNull};
+
+//
+void
+Kumu::init_xml_dom()
+{
+ if ( ! sg_xml_init )
+ {
+ AutoMutex AL(sg_xerces_init_lock);
+
+ if ( ! sg_xml_init )
+ {
+ try
+ {
+ XMLPlatformUtils::Initialize();
+ sg_xml_init = true;
+
+ XMLTransService::Codes ret;
+ sg_coder = XMLPlatformUtils::fgTransService->makeNewTranscoderFor(sg_label_UTF_8, ret, sg_coder_buf_len);
+
+ if ( ret != XMLTransService::Ok )
+ {
+ const char* message = "Undefined Error";
+
+ switch ( ret )
+ {
+ case XMLTransService::UnsupportedEncoding: message = "Unsupported encoding"; break;
+ case XMLTransService::InternalFailure: message = "Internal failure"; break;
+ case XMLTransService::SupportFilesNotFound: message = "Support files not found"; break;
+ }
+
+ DefaultLogSink().Error("Xerces transform initialization error: %s\n", message);
+ }
+ }
+ catch (const XMLException &e)
+ {
+ DefaultLogSink().Error("Xerces initialization error: %s\n", e.getMessage());
+ }
+ }
+ }
+}
+
+//
+bool
+Kumu::XercesString_to_UTF_8(const Kumu::XercesString& in_str, std::string& out_str) {
+ return XercesString_to_UTF_8(in_str.c_str(), out_str);
+}
+
+//
+bool
+Kumu::XercesString_to_UTF_8(const XMLCh* in_str, std::string& out_str)
+{
+ assert(in_str);
+ assert(sg_xml_init);
+ AutoMutex AL(sg_coder_lock);
+ ui32_t str_len = XMLString::stringLen(in_str);
+ ui32_t read_total = 0;
+
+ try
+ {
+ while ( str_len > 0 )
+ {
+#if XERCES_VERSION_MAJOR < 3
+ ui32_t read_count = 0;
+#else
+ XMLSize_t read_count = 0;
+#endif
+ ui32_t write_count = sg_coder->transcodeTo(in_str + read_total, str_len,
+ (XMLByte*)sg_coder_buf, sg_coder_buf_len,
+ read_count, XMLTranscoder::UnRep_Throw);
+
+ out_str.append(sg_coder_buf, write_count);
+ str_len -= read_count;
+ read_total += read_count;
+ assert(str_len >= 0);
+ }
+ }
+ catch (...)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+//
+bool
+Kumu::UTF_8_to_XercesString(const std::string& in_str, Kumu::XercesString& out_str) {
+ return UTF_8_to_XercesString(in_str.c_str(), out_str);
+}
+
+//
+bool
+Kumu::UTF_8_to_XercesString(const char* in_str, Kumu::XercesString& out_str)
+{
+ assert(in_str);
+ assert(sg_xml_init);
+ AutoMutex AL(sg_coder_lock);
+ ui32_t str_len = strlen(in_str);
+ ui32_t read_total = 0;
+
+ try
+ {
+ while ( str_len > 0 )
+ {
+#if XERCES_VERSION_MAJOR < 3
+ ui32_t read_count = 0;
+#else
+ XMLSize_t read_count = 0;
+#endif
+ ui32_t write_count = sg_coder->transcodeFrom((const XMLByte*)(in_str + read_total), str_len,
+ (XMLCh*)sg_coder_buf, sg_coder_buf_len / sizeof(XMLCh),
+ read_count, sg_coder_counts);
+
+ out_str.append((XMLCh*)sg_coder_buf, write_count * sizeof(XMLCh));
+ str_len -= read_count;
+ read_total += read_count;
+ assert(str_len >= 0);
+ }
+ }
+ catch (...)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+//
+class MyTreeHandler : public HandlerBase
+{
+ ns_map* m_Namespaces;
+ std::stack<XMLElement*> m_Scope;
+ XMLElement* m_Root;
+ bool m_HasEncodeErrors;
+
+public:
+ MyTreeHandler(XMLElement* root) : m_Namespaces(0), m_Root(root), m_HasEncodeErrors(false)
+ {
+ assert(m_Root);
+ m_Namespaces = new ns_map;
+ }
+
+ ~MyTreeHandler() {
+ delete m_Namespaces;
+ }
+
+ bool HasEncodeErrors() const { return m_HasEncodeErrors; }
+
+ ns_map* TakeNamespaceMap()
+ {
+ if ( m_Namespaces == 0 || m_Namespaces->empty() )
+ return 0;
+
+ ns_map* ret = m_Namespaces;
+ m_Namespaces = 0;
+ return ret;
+ }
+
+ //
+ void AddNamespace(const char* ns_prefix, const char* ns_name)
+ {
+ assert(ns_prefix);
+ assert(ns_name);
+
+ if ( ns_prefix[0] == ':' )
+ {
+ ns_prefix++;
+ }
+ else
+ {
+ assert(ns_prefix[0] == 0);
+ ns_prefix = "";
+ }
+
+ ns_map::iterator ni = m_Namespaces->find(ns_name);
+
+ if ( ni != m_Namespaces->end() )
+ {
+ if ( ni->second->Name() != std::string(ns_name) )
+ {
+ DefaultLogSink().Error("Duplicate prefix: %s\n", ns_prefix);
+ return;
+ }
+ }
+ else
+ {
+ XMLNamespace* Namespace = new XMLNamespace(ns_prefix, ns_name);
+ m_Namespaces->insert(ns_map::value_type(ns_prefix, Namespace));
+ }
+
+ assert(!m_Namespaces->empty());
+ }
+
+ //
+ void startElement(const XMLCh* const x_name,
+ XERCES_CPP_NAMESPACE::AttributeList& attributes)
+ {
+ assert(x_name);
+ std::string tx_name;
+
+ if ( ! XercesString_to_UTF_8(x_name, tx_name) )
+ m_HasEncodeErrors = true;
+
+ const char* name = tx_name.c_str();
+ XMLElement* Element;
+ const char* ns_root = name;
+ const char* local_name = strchr(name, ':');
+
+ if ( local_name != 0 )
+ name = local_name + 1;
+
+ if ( m_Scope.empty() )
+ {
+ m_Scope.push(m_Root);
+ }
+ else
+ {
+ Element = m_Scope.top();
+ m_Scope.push(Element->AddChild(name));
+ }
+
+ Element = m_Scope.top();
+ Element->SetName(name);
+
+ // set attributes
+ ui32_t a_len = attributes.getLength();
+
+ for ( ui32_t i = 0; i < a_len; i++)
+ {
+ std::string aname, value;
+ if ( ! XercesString_to_UTF_8(attributes.getName(i), aname) )
+ m_HasEncodeErrors = true;
+
+ if ( ! XercesString_to_UTF_8(attributes.getValue(i), value) )
+ m_HasEncodeErrors = true;
+
+ const char* x_aname = aname.c_str();
+ const char* x_value = value.c_str();
+
+ if ( strncmp(x_aname, "xmlns", 5) == 0 )
+ AddNamespace(x_aname+5, x_value);
+
+ if ( ( local_name = strchr(x_aname, ':') ) == 0 )
+ local_name = x_aname;
+ else
+ local_name++;
+
+ Element->SetAttr(local_name, x_value);
+ }
+
+ // map the namespace
+ std::string key;
+ if ( ns_root != name )
+ key.assign(ns_root, name - ns_root - 1);
+
+ ns_map::iterator ni = m_Namespaces->find(key);
+ if ( ni != m_Namespaces->end() )
+ Element->SetNamespace(ni->second);
+ }
+
+ void endElement(const XMLCh *const name) {
+ m_Scope.pop();
+ }
+
+ void characters(const XMLCh *const chars, const unsigned int length)
+ {
+ if ( length > 0 )
+ {
+ std::string tmp;
+ if ( ! XercesString_to_UTF_8(chars, tmp) )
+ m_HasEncodeErrors = true;
+
+ m_Scope.top()->AppendBody(tmp);
+ }
+ }
+};
+
+//
+bool
+Kumu::XMLElement::ParseString(const char* document, ui32_t doc_len)
+{
+ if ( doc_len == 0 )
+ return false;
+
+ init_xml_dom();
+
+ int errorCount = 0;
+ SAXParser* parser = new SAXParser();
+
+ parser->setValidationScheme(SAXParser::Val_Always);
+ parser->setDoNamespaces(true); // optional
+
+ MyTreeHandler* docHandler = new MyTreeHandler(this);
+ parser->setDocumentHandler(docHandler);
+ parser->setErrorHandler(docHandler);
+
+ try
+ {
+ MemBufInputSource xmlSource(reinterpret_cast<const XMLByte*>(document),
+ static_cast<const unsigned int>(doc_len),
+ "pidc_rules_file");
+
+ parser->parse(xmlSource);
+ }
+ catch (const XMLException& e)
+ {
+ char* message = XMLString::transcode(e.getMessage());
+ DefaultLogSink().Error("Parser error: %s\n", message);
+ XMLString::release(&message);
+ errorCount++;
+ }
+ catch (const SAXParseException& e)
+ {
+ char* message = XMLString::transcode(e.getMessage());
+ DefaultLogSink().Error("Parser error: %s at line %d\n", message, e.getLineNumber());
+ XMLString::release(&message);
+ errorCount++;
+ }
+ catch (...)
+ {
+ DefaultLogSink().Error("Unexpected XML parser error\n");
+ errorCount++;
+ }
+
+ if ( errorCount == 0 )
+ m_NamespaceOwner = (void*)docHandler->TakeNamespaceMap();
+
+ delete parser;
+ delete docHandler;
+
+ return errorCount > 0 ? false : true;
+}
+
+//
+bool
+Kumu::StringIsXML(const char* document, ui32_t len)
+{
+ if ( document == 0 || *document == 0 )
+ return false;
+
+ init_xml_dom();
+
+ if ( len == 0 )
+ len = strlen(document);
+
+ SAXParser parser;
+ XMLPScanToken token;
+ bool status = false;
+
+ try
+ {
+ MemBufInputSource xmlSource(reinterpret_cast<const XMLByte*>(document),
+ static_cast<const unsigned int>(len),
+ "pidc_rules_file");
+
+ if ( parser.parseFirst(xmlSource, token) )
+ {
+ if ( parser.parseNext(token) )
+ status = true;
+ }
+ }
+ catch (...)
+ {
+ }
+
+ return status;
+}
+
+
+#endif
+
+//----------------------------------------------------------------------------------------------------
+
+#if ! defined(HAVE_EXPAT) && ! defined(HAVE_XERCES_C)
+
+//
+bool
+Kumu::XMLElement::ParseString(const char*, ui32_t)
+{
+ DefaultLogSink().Error("Kumu compiled without XML parser support.\n");
+ return false;
+}
+
+//
+bool
+Kumu::StringIsXML(const char*, ui32_t)
+{
+ DefaultLogSink().Error("Kumu compiled without XML parser support.\n");
+ return false;
+}
+
+#endif
+
+
+//
+// end KM_xml.cpp
+//
diff --git a/asdcplib/src/KM_xml.h b/asdcplib/src/KM_xml.h
new file mode 100644
index 0000000..cf77366
--- /dev/null
+++ b/asdcplib/src/KM_xml.h
@@ -0,0 +1,141 @@
+/*
+Copyright (c) 2005-2011, 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_xml.h
+ \version $Id: KM_xml.h,v 1.8 2011/08/15 23:03:26 jhurst Exp $
+ \brief XML writer
+*/
+
+
+#ifndef _KM_XML_H_
+#define _KM_XML_H_
+
+#include <KM_util.h>
+#include <list>
+#include <string>
+
+namespace Kumu
+{
+ class XMLElement;
+
+ // Return true if the given string contains an XML document (or the start of one).
+ bool StringIsXML(const char* document, ui32_t len = 0);
+
+ //
+ struct NVPair
+ {
+ std::string name;
+ std::string value;
+ };
+
+ //
+ typedef std::list<NVPair> AttributeList;
+ typedef AttributeList::const_iterator Attr_i;
+ typedef std::list<XMLElement*> ElementList;
+ typedef ElementList::const_iterator Elem_i;
+
+ //
+ class XMLNamespace
+ {
+ std::string m_Prefix;
+ std::string m_Name;
+
+ KM_NO_COPY_CONSTRUCT(XMLNamespace);
+ XMLNamespace();
+
+ public:
+ XMLNamespace(const char* prefix, const char* name) : m_Prefix(prefix), m_Name(name) {}
+ ~XMLNamespace() {}
+
+ inline const std::string& Prefix() const { return m_Prefix; }
+ inline const std::string& Name() const { return m_Name; }
+ };
+
+ //
+ class XMLElement
+ {
+ KM_NO_COPY_CONSTRUCT(XMLElement);
+ XMLElement();
+
+ protected:
+ AttributeList m_AttrList;
+ ElementList m_ChildList;
+ const XMLNamespace* m_Namespace;
+ void* m_NamespaceOwner;
+
+ std::string m_Name;
+ std::string m_Body;
+
+ public:
+ XMLElement(const char* name);
+ ~XMLElement();
+
+ inline const XMLNamespace* Namespace() const { return m_Namespace; }
+ inline void SetNamespace(const XMLNamespace* ns) { assert(ns); m_Namespace = ns; }
+
+ bool ParseString(const char* document, ui32_t doc_len);
+ bool ParseString(const ByteString& document);
+ bool ParseString(const std::string& document);
+
+ // building
+ void SetName(const char* name);
+ void SetBody(const std::string& value);
+ void AppendBody(const std::string& value);
+ void SetAttr(const char* name, const char* value);
+ void SetAttr(const char* name, const std::string& value) { SetAttr(name, value.c_str()); }
+ XMLElement* AddChild(XMLElement* element);
+ XMLElement* AddChild(const char* name);
+ XMLElement* AddChildWithContent(const char* name, const char* value);
+ XMLElement* AddChildWithContent(const char* name, const std::string& value);
+ XMLElement* AddChildWithPrefixedContent(const char* name, const char* prefix, const char* value);
+ void AddComment(const char* value);
+ void Render(std::string&) const;
+ void RenderElement(std::string& outbuf, ui32_t depth) const;
+
+ // querying
+ inline const std::string& GetBody() const { return m_Body; }
+ inline const ElementList& GetChildren() const { return m_ChildList; }
+ inline const std::string& GetName() const { return m_Name; }
+ inline const AttributeList& GetAttributes() const { return m_AttrList; }
+ const char* GetAttrWithName(const char* name) const;
+ XMLElement* GetChildWithName(const char* name) const;
+ const ElementList& GetChildrenWithName(const char* name, ElementList& outList) const;
+ bool HasName(const char* name) const;
+
+ // altering
+ void DeleteAttributes();
+ void DeleteAttrWithName(const char* name);
+ void DeleteChildren();
+ void DeleteChild(const XMLElement* element);
+ void ForgetChild(const XMLElement* element);
+ };
+} // namespace Kumu
+
+#endif // _KM_XML_H_
+
+//
+// end KM_xml.h
+//
diff --git a/asdcplib/src/MDD.cpp b/asdcplib/src/MDD.cpp
new file mode 100644
index 0000000..ac8f0dd
--- /dev/null
+++ b/asdcplib/src/MDD.cpp
@@ -0,0 +1,925 @@
+/*
+Copyright (c) 2006-2012, 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 MDD.[h|cpp]
+ \version $Id: MDD.cpp,v 1.34 2012/02/02 01:58:43 jhurst Exp $
+ \brief MXF Metadata Dictionary
+*/
+//
+// MDD.cpp
+//
+
+#include "KLV.h"
+
+static const ASDCP::MDDEntry s_MDD_Table[] = {
+ { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "MICAlgorithm_NONE" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, // 1
+ 0x0d, 0x01, 0x02, 0x01, 0x10, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "MXFInterop_OPAtom" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x02, // 2
+ 0x0d, 0x01, 0x02, 0x01, 0x10, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "OPAtom" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, // 3
+ 0x0d, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x00 },
+ {0, 0}, false, "OP1a" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x03, // 4
+ 0x0d, 0x01, 0x03, 0x01, 0x02, 0x7f, 0x01, 0x00 },
+ {0, 0}, false, "GCMulti" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, // 5
+ 0x01, 0x03, 0x02, 0x02, 0x01, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "PictureDataDef" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, // 6
+ 0x01, 0x03, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "SoundDataDef" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, // 7
+ 0x01, 0x03, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "TimecodeDataDef" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, // 8
+ 0x01, 0x03, 0x02, 0x01, 0x10, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "DescriptiveMetaDataDef" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, // 9
+ 0x0d, 0x01, 0x03, 0x01, 0x02, 0x06, 0x01, 0x00 },
+ {0, 0}, false, "WAVWrapping" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x02, // 10
+ 0x0d, 0x01, 0x03, 0x01, 0x02, 0x04, 0x60, 0x00 },
+ {0, 0}, false, "MPEG2_VESWrapping" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x07, // 11
+ 0x0d, 0x01, 0x03, 0x01, 0x02, 0x0c, 0x01, 0x00 },
+ {0, 0}, false, "JPEG_2000Wrapping" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x02, 0x01, 0x01, // 12
+ 0x0d, 0x01, 0x03, 0x01, 0x15, 0x01, 0x08, 0x00 },
+ {0, 0}, false, "JPEG2000Essence" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x02, 0x01, 0x01, // 13
+ 0x0d, 0x01, 0x03, 0x01, 0x15, 0x01, 0x05, 0x00 },
+ {0, 0}, false, "MPEG2Essence" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x04, 0x01, 0x07, // 14
+ 0x0d, 0x01, 0x03, 0x01, 0x02, 0x7e, 0x01, 0x00 },
+ {0, 0}, false, "MXFInterop_CryptEssence" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x04, 0x01, 0x01, // 15
+ 0x0d, 0x01, 0x03, 0x01, 0x02, 0x7e, 0x01, 0x00 },
+ {0, 0}, false, "CryptEssence" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x02, 0x01, 0x01, // 16
+ 0x0d, 0x01, 0x03, 0x01, 0x16, 0x01, 0x01, 0x00 },
+ {0, 0}, false, "WAVEssence" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x09, // 17
+ 0x04, 0x01, 0x02, 0x02, 0x03, 0x01, 0x01, 0x03 },
+ {0, 0}, false, "JP2KEssenceCompression_2K" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x09, // 18
+ 0x04, 0x01, 0x02, 0x02, 0x03, 0x01, 0x01, 0x04 },
+ {0, 0}, false, "JP2KEssenceCompression_4K" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x07, // 19
+ 0x02, 0x09, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "CipherAlgorithm_AES" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x07, // 20
+ 0x02, 0x09, 0x02, 0x02, 0x01, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "MICAlgorithm_HMAC_SHA1" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 21
+ 0x03, 0x01, 0x02, 0x10, 0x01, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "KLVFill" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 22
+ 0x03, 0x01, 0x02, 0x01, 0x06, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "PartitionMetadata_MajorVersion" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 23
+ 0x03, 0x01, 0x02, 0x01, 0x07, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "PartitionMetadata_MinorVersion" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 24
+ 0x03, 0x01, 0x02, 0x01, 0x09, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "PartitionMetadata_KAGSize" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 25
+ 0x06, 0x10, 0x10, 0x03, 0x01, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "PartitionMetadata_ThisPartition" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 26
+ 0x06, 0x10, 0x10, 0x02, 0x01, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "PartitionMetadata_PreviousPartition" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 27
+ 0x06, 0x10, 0x10, 0x05, 0x01, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "PartitionMetadata_FooterPartition" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 28
+ 0x04, 0x06, 0x09, 0x01, 0x00, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "PartitionMetadata_HeaderByteCount" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 29
+ 0x04, 0x06, 0x09, 0x02, 0x00, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "PartitionMetadata_IndexByteCount" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 30
+ 0x01, 0x03, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "PartitionMetadata_IndexSID" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 31
+ 0x06, 0x08, 0x01, 0x02, 0x01, 0x03, 0x00, 0x00 },
+ {0, 0}, false, "PartitionMetadata_BodyOffset" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 32
+ 0x01, 0x03, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "PartitionMetadata_BodySID" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 33
+ 0x01, 0x02, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "PartitionMetadata_OperationalPattern" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 34
+ 0x01, 0x02, 0x02, 0x10, 0x02, 0x01, 0x00, 0x00 },
+ {0, 0}, false, "PartitionMetadata_EssenceContainers" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01, // 35
+ 0x0d, 0x01, 0x02, 0x01, 0x01, 0x02, 0x01, 0x00 },
+ {0, 0}, false, "OpenHeader" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01, // 36
+ 0x0d, 0x01, 0x02, 0x01, 0x01, 0x02, 0x03, 0x00 },
+ {0, 0}, false, "OpenCompleteHeader" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01, // 37
+ 0x0d, 0x01, 0x02, 0x01, 0x01, 0x02, 0x02, 0x00 },
+ {0, 0}, false, "ClosedHeader" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01, // 38
+ 0x0d, 0x01, 0x02, 0x01, 0x01, 0x02, 0x04, 0x00 },
+ {0, 0}, false, "ClosedCompleteHeader" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01, // 39
+ 0x0d, 0x01, 0x02, 0x01, 0x01, 0x03, 0x01, 0x00 },
+ {0, 0}, false, "OpenBodyPartition" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01, // 40
+ 0x0d, 0x01, 0x02, 0x01, 0x01, 0x03, 0x03, 0x00 },
+ {0, 0}, false, "OpenCompleteBodyPartition" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01, // 41
+ 0x0d, 0x01, 0x02, 0x01, 0x01, 0x03, 0x02, 0x00 },
+ {0, 0}, false, "ClosedBodyPartition" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01, // 42
+ 0x0d, 0x01, 0x02, 0x01, 0x01, 0x03, 0x04, 0x00 },
+ {0, 0}, false, "ClosedCompleteBodyPartition" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01, // 43
+ 0x0d, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x00 },
+ {0, 0}, false, "Footer" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01, // 44
+ 0x0d, 0x01, 0x02, 0x01, 0x01, 0x04, 0x04, 0x00 },
+ {0, 0}, false, "CompleteFooter" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01, // 45
+ 0x0d, 0x01, 0x02, 0x01, 0x01, 0x05, 0x01, 0x00 },
+ {0, 0}, false, "Primer" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 46
+ 0x06, 0x01, 0x01, 0x07, 0x15, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "Primer_LocalTagEntryBatch" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 47
+ 0x01, 0x03, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "LocalTagEntryBatch_Primer_LocalTag" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 48
+ 0x01, 0x03, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "LocalTagEntryBatch_Primer_UID" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 49
+ 0x01, 0x01, 0x15, 0x02, 0x00, 0x00, 0x00, 0x00 },
+ {0x3c, 0x0a}, false, "InterchangeObject_InstanceUID" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 50
+ 0x05, 0x20, 0x07, 0x01, 0x08, 0x00, 0x00, 0x00 },
+ {0x01, 0x02}, true, "GenerationInterchangeObject_GenerationUID" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 51
+ 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "DefaultObject" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 52
+ 0x05, 0x30, 0x04, 0x06, 0x00, 0x00, 0x00, 0x00 },
+ {0x3f, 0x0b}, false, "IndexTableSegmentBase_IndexEditRate" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 53
+ 0x07, 0x02, 0x01, 0x03, 0x01, 0x0a, 0x00, 0x00 },
+ {0x3f, 0x0c}, false, "IndexTableSegmentBase_IndexStartPosition" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 54
+ 0x07, 0x02, 0x02, 0x01, 0x01, 0x02, 0x00, 0x00 },
+ {0x3f, 0x0d}, false, "IndexTableSegmentBase_IndexDuration" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 55
+ 0x04, 0x06, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00 },
+ {0x3f, 0x05}, false, "IndexTableSegmentBase_EditUnitByteCount" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 56
+ 0x01, 0x03, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00 },
+ {0x3f, 0x06}, false, "IndexTableSegmentBase_IndexSID" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 57
+ 0x01, 0x03, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00 },
+ {0x3f, 0x07}, false, "IndexTableSegmentBase_BodySID" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 58
+ 0x04, 0x04, 0x04, 0x01, 0x01, 0x00, 0x00, 0x00 },
+ {0x3f, 0x08}, false, "IndexTableSegmentBase_SliceCount" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 59
+ 0x04, 0x04, 0x04, 0x01, 0x07, 0x00, 0x00, 0x00 },
+ {0x3f, 0x0e}, true, "IndexTableSegmentBase_PosTableCount" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 60
+ 0x0d, 0x01, 0x02, 0x01, 0x01, 0x10, 0x01, 0x00 },
+ {0, 0}, false, "IndexTableSegment" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 61
+ 0x04, 0x04, 0x04, 0x01, 0x06, 0x00, 0x00, 0x00 },
+ {0x3f, 0x09}, true, "IndexTableSegment_DeltaEntryArray" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 62
+ 0x04, 0x04, 0x04, 0x01, 0x04, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "DeltaEntryArray_IndexTableSegment_PosTableIndex" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 63
+ 0x04, 0x04, 0x04, 0x01, 0x02, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "DeltaEntryArray_IndexTableSegment_Slice" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 64
+ 0x04, 0x04, 0x04, 0x01, 0x03, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "DeltaEntryArray_IndexTableSegment_ElementDelta" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 65
+ 0x04, 0x04, 0x04, 0x02, 0x05, 0x00, 0x00, 0x00 },
+ {0x3f, 0x0a}, false, "IndexTableSegment_IndexEntryArray" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 66
+ 0x04, 0x04, 0x04, 0x02, 0x03, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "IndexEntryArray_IndexTableSegment_TemporalOffset" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 67
+ 0x04, 0x04, 0x04, 0x02, 0x04, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "IndexEntryArray_IndexTableSegment_AnchorOffset" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 68
+ 0x04, 0x04, 0x04, 0x02, 0x02, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "IndexEntryArray_IndexTableSegment_Flags" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 69
+ 0x04, 0x04, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "IndexEntryArray_IndexTableSegment_StreamOffset" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 70
+ 0x04, 0x04, 0x04, 0x01, 0x05, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "IndexEntryArray_IndexTableSegment_SliceOffsetArray" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 71
+ 0x04, 0x04, 0x04, 0x01, 0x08, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "IndexEntryArray_IndexTableSegment_PosTableArray" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01, // 72
+ 0x0d, 0x01, 0x02, 0x01, 0x01, 0x11, 0x01, 0x00 },
+ {0, 0}, false, "RandomIndexMetadata" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 73
+ 0x01, 0x03, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "PartitionArray_RandomIndexMetadata_BodySID" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 74
+ 0x06, 0x09, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "PartitionArray_RandomIndexMetadata_ByteOffset" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 75
+ 0x04, 0x06, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "RandomIndexMetadata_Length" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01, // 76
+ 0x0d, 0x01, 0x02, 0x01, 0x01, 0x11, 0x00, 0x00 },
+ {0, 0}, false, "RandomIndexMetadataV10" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 77
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x2f, 0x00 },
+ {0, 0}, false, "Preface" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 78
+ 0x07, 0x02, 0x01, 0x10, 0x02, 0x04, 0x00, 0x00 },
+ {0x3b, 0x02}, false, "Preface_LastModifiedDate" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 79
+ 0x03, 0x01, 0x02, 0x01, 0x05, 0x00, 0x00, 0x00 },
+ {0x3b, 0x05}, false, "Preface_Version" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 80
+ 0x03, 0x01, 0x02, 0x01, 0x04, 0x00, 0x00, 0x00 },
+ {0x3b, 0x07}, true, "Preface_ObjectModelVersion" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 81
+ 0x06, 0x01, 0x01, 0x04, 0x01, 0x08, 0x00, 0x00 },
+ {0x3b, 0x08}, true, "Preface_PrimaryPackage" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 82
+ 0x06, 0x01, 0x01, 0x04, 0x06, 0x04, 0x00, 0x00 },
+ {0x3b, 0x06}, false, "Preface_Identifications" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 83
+ 0x06, 0x01, 0x01, 0x04, 0x02, 0x01, 0x00, 0x00 },
+ {0x3b, 0x03}, false, "Preface_ContentStorage" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 84
+ 0x01, 0x02, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00 },
+ {0x3b, 0x09}, false, "Preface_OperationalPattern" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 85
+ 0x01, 0x02, 0x02, 0x10, 0x02, 0x01, 0x00, 0x00 },
+ {0x3b, 0x0a}, false, "Preface_EssenceContainers" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 86
+ 0x01, 0x02, 0x02, 0x10, 0x02, 0x02, 0x00, 0x00 },
+ {0x3b, 0x0b}, false, "Preface_DMSchemes" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 87
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x30, 0x00 },
+ {0, 0}, false, "Identification" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 88
+ 0x05, 0x20, 0x07, 0x01, 0x01, 0x00, 0x00, 0x00 },
+ {0x3c, 0x09}, false, "Identification_ThisGenerationUID" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 89
+ 0x05, 0x20, 0x07, 0x01, 0x02, 0x01, 0x00, 0x00 },
+ {0x3c, 0x01}, false, "Identification_CompanyName" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 90
+ 0x05, 0x20, 0x07, 0x01, 0x03, 0x01, 0x00, 0x00 },
+ {0x3c, 0x02}, false, "Identification_ProductName" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 91
+ 0x05, 0x20, 0x07, 0x01, 0x04, 0x00, 0x00, 0x00 },
+ {0x3c, 0x03}, true, "Identification_ProductVersion" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 92
+ 0x05, 0x20, 0x07, 0x01, 0x05, 0x01, 0x00, 0x00 },
+ {0x3c, 0x04}, false, "Identification_VersionString" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 93
+ 0x05, 0x20, 0x07, 0x01, 0x07, 0x00, 0x00, 0x00 },
+ {0x3c, 0x05}, false, "Identification_ProductUID" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 94
+ 0x07, 0x02, 0x01, 0x10, 0x02, 0x03, 0x00, 0x00 },
+ {0x3c, 0x06}, false, "Identification_ModificationDate" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 95
+ 0x05, 0x20, 0x07, 0x01, 0x0a, 0x00, 0x00, 0x00 },
+ {0x3c, 0x07}, true, "Identification_ToolkitVersion" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 96
+ 0x05, 0x20, 0x07, 0x01, 0x06, 0x01, 0x00, 0x00 },
+ {0x3c, 0x08}, true, "Identification_Platform" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 97
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x18, 0x00 },
+ {0, 0}, false, "ContentStorage" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 98
+ 0x06, 0x01, 0x01, 0x04, 0x05, 0x01, 0x00, 0x00 },
+ {0x19, 0x01}, false, "ContentStorage_Packages" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 99
+ 0x06, 0x01, 0x01, 0x04, 0x05, 0x02, 0x00, 0x00 },
+ {0x19, 0x02}, true, "ContentStorage_EssenceContainerData" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 100
+ 0x06, 0x01, 0x01, 0x04, 0x05, 0x00, 0x00, 0x00 },
+ {0x19, 0x01}, false, "ContentStorageKludge_V10Packages" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 101
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x23, 0x00 },
+ {0, 0}, false, "EssenceContainerData" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 102
+ 0x06, 0x01, 0x01, 0x06, 0x01, 0x00, 0x00, 0x00 },
+ {0x27, 0x01}, false, "EssenceContainerData_LinkedPackageUID" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 103
+ 0x01, 0x03, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00 },
+ {0x3f, 0x06}, true, "EssenceContainerData_IndexSID" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 104
+ 0x01, 0x03, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00 },
+ {0x3f, 0x07}, false, "EssenceContainerData_BodySID" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 105
+ 0x01, 0x01, 0x15, 0x10, 0x00, 0x00, 0x00, 0x00 },
+ {0x44, 0x01}, false, "GenericPackage_PackageUID" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 106
+ 0x01, 0x03, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00 },
+ {0x44, 0x02}, true, "GenericPackage_Name" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 107
+ 0x07, 0x02, 0x01, 0x10, 0x01, 0x03, 0x00, 0x00 },
+ {0x44, 0x05}, false, "GenericPackage_PackageCreationDate" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 108
+ 0x07, 0x02, 0x01, 0x10, 0x02, 0x05, 0x00, 0x00 },
+ {0x44, 0x04}, false, "GenericPackage_PackageModifiedDate" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 109
+ 0x06, 0x01, 0x01, 0x04, 0x06, 0x05, 0x00, 0x00 },
+ {0x44, 0x03}, false, "GenericPackage_Tracks" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 110
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x32, 0x00 },
+ {0, 0}, false, "NetworkLocator" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 111
+ 0x01, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00 },
+ {0x40, 0x01}, false, "NetworkLocator_URLString" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 112
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x33, 0x00 },
+ {0, 0}, false, "TextLocator" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 113
+ 0x01, 0x04, 0x01, 0x02, 0x01, 0x00, 0x00, 0x00 },
+ {0x41, 0x01}, false, "TextLocator_LocatorName" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 114
+ 0x01, 0x07, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00 },
+ {0x48, 0x01}, false, "GenericTrack_TrackID" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 115
+ 0x01, 0x04, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00 },
+ {0x48, 0x04}, false, "GenericTrack_TrackNumber" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 116
+ 0x01, 0x07, 0x01, 0x02, 0x01, 0x00, 0x00, 0x00 },
+ {0x48, 0x02}, true, "GenericTrack_TrackName" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 117
+ 0x06, 0x01, 0x01, 0x04, 0x02, 0x04, 0x00, 0x00 },
+ {0x48, 0x03}, false, "GenericTrack_Sequence" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 118
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x3a, 0x00 },
+ {0, 0}, false, "StaticTrack" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 119
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x3b, 0x00 },
+ {0, 0}, false, "Track" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 120
+ 0x05, 0x30, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00 },
+ {0x4b, 0x01}, false, "Track_EditRate" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 121
+ 0x07, 0x02, 0x01, 0x03, 0x01, 0x03, 0x00, 0x00 },
+ {0x4b, 0x02}, false, "Track_Origin" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 122
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x39, 0x00 },
+ {0, 0}, false, "EventTrack" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 123
+ 0x05, 0x30, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00 },
+ {0x49, 0x01}, false, "EventTrack_EventEditRate" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 124
+ 0x07, 0x02, 0x01, 0x03, 0x01, 0x0b, 0x00, 0x00 },
+ {0x49, 0x02}, true, "EventTrack_EventOrigin" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 125
+ 0x04, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ {0x02, 0x01}, false, "StructuralComponent_DataDefinition" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 126
+ 0x07, 0x02, 0x02, 0x01, 0x01, 0x03, 0x00, 0x00 },
+ {0x02, 0x02}, false, "StructuralComponent_Duration" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 127
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x0f, 0x00 },
+ {0, 0}, false, "Sequence" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 128
+ 0x06, 0x01, 0x01, 0x04, 0x06, 0x09, 0x00, 0x00 },
+ {0x10, 0x01}, false, "Sequence_StructuralComponents" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 129
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x14, 0x00 },
+ {0, 0}, false, "TimecodeComponent" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 130
+ 0x04, 0x04, 0x01, 0x01, 0x02, 0x06, 0x00, 0x00 },
+ {0x15, 0x02}, false, "TimecodeComponent_RoundedTimecodeBase" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 131
+ 0x07, 0x02, 0x01, 0x03, 0x01, 0x05, 0x00, 0x00 },
+ {0x15, 0x01}, false, "TimecodeComponent_StartTimecode" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 132
+ 0x04, 0x04, 0x01, 0x01, 0x05, 0x00, 0x00, 0x00 },
+ {0x15, 0x03}, false, "TimecodeComponent_DropFrame" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 133
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x11, 0x00 },
+ {0, 0}, false, "SourceClip" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 134
+ 0x07, 0x02, 0x01, 0x03, 0x01, 0x04, 0x00, 0x00 },
+ {0x12, 0x01}, false, "SourceClip_StartPosition" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 135
+ 0x06, 0x01, 0x01, 0x03, 0x01, 0x00, 0x00, 0x00 },
+ {0x11, 0x01}, false, "SourceClip_SourcePackageID" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 136
+ 0x06, 0x01, 0x01, 0x03, 0x02, 0x00, 0x00, 0x00 },
+ {0x11, 0x02}, false, "SourceClip_SourceTrackID" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 137
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x41, 0x00 },
+ {0, 0}, false, "DMSegment" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 138
+ 0x07, 0x02, 0x01, 0x03, 0x03, 0x03, 0x00, 0x00 },
+ {0x06, 0x01}, false, "DMSegment_EventStartPosition" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 139
+ 0x05, 0x30, 0x04, 0x04, 0x01, 0x00, 0x00, 0x00 },
+ {0x06, 0x02}, true, "DMSegment_EventComment" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 140
+ 0x01, 0x07, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00 },
+ {0x61, 0x02}, false, "DMSegment_TrackIDs" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 141
+ 0x06, 0x01, 0x01, 0x04, 0x02, 0x0c, 0x00, 0x00 },
+ {0x61, 0x01}, false, "DMSegment_DMFramework" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 142
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x45, 0x00 },
+ {0, 0}, false, "DMSourceClip" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 143
+ 0x01, 0x07, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00 },
+ {0x61, 0x03}, true, "DMSourceClip_DMSourceClipTrackIDs" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 144
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x36, 0x00 },
+ {0, 0}, false, "MaterialPackage" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 145
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x37, 0x00 },
+ {0, 0}, false, "SourcePackage" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 146
+ 0x06, 0x01, 0x01, 0x04, 0x02, 0x03, 0x00, 0x00 },
+ {0x47, 0x01}, false, "SourcePackage_Descriptor" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 147
+ 0x06, 0x01, 0x01, 0x04, 0x06, 0x03, 0x00, 0x00 },
+ {0x2f, 0x01}, true, "GenericDescriptor_Locators" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x09, // 148
+ 0x06, 0x01, 0x01, 0x04, 0x06, 0x10, 0x00, 0x00 },
+ {0, 0}, true, "GenericDescriptor_SubDescriptors" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 149
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x25, 0x00 },
+ {0, 0}, false, "FileDescriptor" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 150
+ 0x06, 0x01, 0x01, 0x03, 0x05, 0x00, 0x00, 0x00 },
+ {0x30, 0x06}, true, "FileDescriptor_LinkedTrackID" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 151
+ 0x04, 0x06, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00 },
+ {0x30, 0x01}, false, "FileDescriptor_SampleRate" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 152
+ 0x04, 0x06, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00 },
+ {0x30, 0x02}, true, "FileDescriptor_ContainerDuration" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 153
+ 0x06, 0x01, 0x01, 0x04, 0x01, 0x02, 0x00, 0x00 },
+ {0x30, 0x04}, false, "FileDescriptor_EssenceContainer" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 154
+ 0x06, 0x01, 0x01, 0x04, 0x01, 0x03, 0x00, 0x00 },
+ {0x30, 0x05}, true, "FileDescriptor_Codec" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 155
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x27, 0x00 },
+ {0, 0}, false, "GenericPictureEssenceDescriptor" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 156
+ 0x04, 0x05, 0x01, 0x13, 0x00, 0x00, 0x00, 0x00 },
+ {0x32, 0x15}, true, "GenericPictureEssenceDescriptor_SignalStandard" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 157
+ 0x04, 0x01, 0x03, 0x01, 0x04, 0x00, 0x00, 0x00 },
+ {0x32, 0x0c}, false, "GenericPictureEssenceDescriptor_FrameLayout" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 158
+ 0x04, 0x01, 0x05, 0x02, 0x02, 0x00, 0x00, 0x00 },
+ {0x32, 0x03}, false, "GenericPictureEssenceDescriptor_StoredWidth" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 159
+ 0x04, 0x01, 0x05, 0x02, 0x01, 0x00, 0x00, 0x00 },
+ {0x32, 0x02}, false, "GenericPictureEssenceDescriptor_StoredHeight" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 160
+ 0x04, 0x01, 0x03, 0x02, 0x08, 0x00, 0x00, 0x00 },
+ {0x32, 0x16}, true, "GenericPictureEssenceDescriptor_StoredF2Offset" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 161
+ 0x04, 0x01, 0x05, 0x01, 0x08, 0x00, 0x00, 0x00 },
+ {0x32, 0x05}, true, "GenericPictureEssenceDescriptor_SampledWidth" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 162
+ 0x04, 0x01, 0x05, 0x01, 0x07, 0x00, 0x00, 0x00 },
+ {0x32, 0x04}, true, "GenericPictureEssenceDescriptor_SampledHeight" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 163
+ 0x04, 0x01, 0x05, 0x01, 0x09, 0x00, 0x00, 0x00 },
+ {0x32, 0x06}, true, "GenericPictureEssenceDescriptor_SampledXOffset" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 164
+ 0x04, 0x01, 0x05, 0x01, 0x0a, 0x00, 0x00, 0x00 },
+ {0x32, 0x07}, true, "GenericPictureEssenceDescriptor_SampledYOffset" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 165
+ 0x04, 0x01, 0x05, 0x01, 0x0b, 0x00, 0x00, 0x00 },
+ {0x32, 0x08}, true, "GenericPictureEssenceDescriptor_DisplayHeight" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 166
+ 0x04, 0x01, 0x05, 0x01, 0x0c, 0x00, 0x00, 0x00 },
+ {0x32, 0x09}, true, "GenericPictureEssenceDescriptor_DisplayWidth" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 167
+ 0x04, 0x01, 0x05, 0x01, 0x0d, 0x00, 0x00, 0x00 },
+ {0x32, 0x0a}, true, "GenericPictureEssenceDescriptor_DisplayXOffset" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 168
+ 0x04, 0x01, 0x05, 0x01, 0x0e, 0x00, 0x00, 0x00 },
+ {0x32, 0x0b}, true, "GenericPictureEssenceDescriptor_DisplayYOffset" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 169
+ 0x04, 0x01, 0x03, 0x02, 0x07, 0x00, 0x00, 0x00 },
+ {0x32, 0x17}, true, "GenericPictureEssenceDescriptor_DisplayF2Offset" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 170
+ 0x04, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00 },
+ {0x32, 0x0e}, false, "GenericPictureEssenceDescriptor_AspectRatio" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 171
+ 0x04, 0x01, 0x03, 0x02, 0x09, 0x00, 0x00, 0x00 },
+ {0x32, 0x18}, true, "GenericPictureEssenceDescriptor_ActiveFormatDescriptor" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 172
+ 0x04, 0x01, 0x03, 0x02, 0x05, 0x00, 0x00, 0x00 },
+ {0x32, 0x0d}, false, "GenericPictureEssenceDescriptor_VideoLineMap" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 173
+ 0x05, 0x20, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00 },
+ {0x32, 0x0f}, true, "GenericPictureEssenceDescriptor_AlphaTransparency" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 174
+ 0x04, 0x01, 0x02, 0x01, 0x01, 0x01, 0x02, 0x00 },
+ {0x32, 0x10}, true, "GenericPictureEssenceDescriptor_Gamma" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 175
+ 0x04, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00 },
+ {0x32, 0x11}, true, "GenericPictureEssenceDescriptor_ImageAlignmentOffset" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 176
+ 0x04, 0x18, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00 },
+ {0x32, 0x13}, true, "GenericPictureEssenceDescriptor_ImageStartOffset" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 177
+ 0x04, 0x18, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00 },
+ {0x32, 0x14}, true, "GenericPictureEssenceDescriptor_ImageEndOffset" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 178
+ 0x04, 0x01, 0x03, 0x01, 0x06, 0x00, 0x00, 0x00 },
+ {0x32, 0x12}, true, "GenericPictureEssenceDescriptor_FieldDominance" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 179
+ 0x04, 0x01, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00 },
+ {0x32, 0x01}, false, "GenericPictureEssenceDescriptor_PictureEssenceCoding" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 180
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x28, 0x00 },
+ {0, 0}, false, "CDCIEssenceDescriptor" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 181
+ 0x04, 0x01, 0x05, 0x03, 0x0a, 0x00, 0x00, 0x00 },
+ {0x33, 0x01}, false, "CDCIEssenceDescriptor_ComponentDepth" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 182
+ 0x04, 0x01, 0x05, 0x01, 0x05, 0x00, 0x00, 0x00 },
+ {0x33, 0x02}, false, "CDCIEssenceDescriptor_HorizontalSubsampling" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 183
+ 0x04, 0x01, 0x05, 0x01, 0x10, 0x00, 0x00, 0x00 },
+ {0x33, 0x08}, true, "CDCIEssenceDescriptor_VerticalSubsampling" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 184
+ 0x04, 0x01, 0x05, 0x01, 0x06, 0x00, 0x00, 0x00 },
+ {0x33, 0x03}, true, "CDCIEssenceDescriptor_ColorSiting" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 185
+ 0x03, 0x01, 0x02, 0x01, 0x0a, 0x00, 0x00, 0x00 },
+ {0x33, 0x0b}, true, "CDCIEssenceDescriptor_ReversedByteOrder" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 186
+ 0x04, 0x18, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00 },
+ {0x33, 0x07}, true, "CDCIEssenceDescriptor_PaddingBits" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 187
+ 0x04, 0x01, 0x05, 0x03, 0x07, 0x00, 0x00, 0x00 },
+ {0x33, 0x09}, true, "CDCIEssenceDescriptor_AlphaSampleDepth" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 188
+ 0x04, 0x01, 0x05, 0x03, 0x03, 0x00, 0x00, 0x00 },
+ {0x33, 0x04}, true, "CDCIEssenceDescriptor_BlackRefLevel" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 189
+ 0x04, 0x01, 0x05, 0x03, 0x04, 0x00, 0x00, 0x00 },
+ {0x33, 0x05}, true, "CDCIEssenceDescriptor_WhiteReflevel" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 190
+ 0x04, 0x01, 0x05, 0x03, 0x05, 0x00, 0x00, 0x00 },
+ {0x33, 0x06}, true, "CDCIEssenceDescriptor_ColorRange" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 191
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x29, 0x00 },
+ {0, 0}, false, "RGBAEssenceDescriptor" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 192
+ 0x04, 0x01, 0x05, 0x03, 0x0b, 0x00, 0x00, 0x00 },
+ {0x34, 0x06}, true, "RGBAEssenceDescriptor_ComponentMaxRef" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 193
+ 0x04, 0x01, 0x05, 0x03, 0x0c, 0x00, 0x00, 0x00 },
+ {0x34, 0x07}, true, "RGBAEssenceDescriptor_ComponentMinRef" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 194
+ 0x04, 0x01, 0x05, 0x03, 0x0d, 0x00, 0x00, 0x00 },
+ {0x34, 0x08}, true, "RGBAEssenceDescriptor_AlphaMaxRef" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 195
+ 0x04, 0x01, 0x05, 0x03, 0x0e, 0x00, 0x00, 0x00 },
+ {0x34, 0x09}, true, "RGBAEssenceDescriptor_AlphaMinRef" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 196
+ 0x04, 0x01, 0x04, 0x04, 0x01, 0x00, 0x00, 0x00 },
+ {0x34, 0x05}, true, "RGBAEssenceDescriptor_ScanningDirection" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 197
+ 0x04, 0x01, 0x05, 0x03, 0x06, 0x00, 0x00, 0x00 },
+ {0x34, 0x01}, false, "RGBAEssenceDescriptor_PixelLayout" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 198
+ 0x04, 0x01, 0x05, 0x03, 0x08, 0x00, 0x00, 0x00 },
+ {0x34, 0x03}, true, "RGBAEssenceDescriptor_Palette" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 199
+ 0x04, 0x01, 0x05, 0x03, 0x09, 0x00, 0x00, 0x00 },
+ {0x34, 0x04}, true, "RGBAEssenceDescriptor_PaletteLayout" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 200
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x42, 0x00 },
+ {0, 0}, false, "GenericSoundEssenceDescriptor" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 201
+ 0x04, 0x02, 0x03, 0x01, 0x01, 0x01, 0x00, 0x00 },
+ {0x3d, 0x03}, false, "GenericSoundEssenceDescriptor_AudioSamplingRate" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 202
+ 0x04, 0x02, 0x03, 0x01, 0x04, 0x00, 0x00, 0x00 },
+ {0x3d, 0x02}, false, "GenericSoundEssenceDescriptor_Locked" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 203
+ 0x04, 0x02, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00 },
+ {0x3d, 0x04}, true, "GenericSoundEssenceDescriptor_AudioRefLevel" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 204
+ 0x04, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00 },
+ {0x3d, 0x05}, true, "GenericSoundEssenceDescriptor_ElectroSpatialFormulation" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 205
+ 0x04, 0x02, 0x01, 0x01, 0x04, 0x00, 0x00, 0x00 },
+ {0x3d, 0x07}, false, "GenericSoundEssenceDescriptor_ChannelCount" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 206
+ 0x04, 0x02, 0x03, 0x03, 0x04, 0x00, 0x00, 0x00 },
+ {0x3d, 0x01}, false, "GenericSoundEssenceDescriptor_QuantizationBits" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 207
+ 0x04, 0x02, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00 },
+ {0x3d, 0x0c}, true, "GenericSoundEssenceDescriptor_DialNorm" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 208
+ 0x04, 0x02, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00 },
+ {0x3d, 0x06}, false, "GenericSoundEssenceDescriptor_SoundEssenceCompression" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 209
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x43, 0x00 },
+ {0, 0}, false, "GenericDataEssenceDescriptor" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 210
+ 0x04, 0x03, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00 },
+ {0x3e, 0x01}, false, "GenericDataEssenceDescriptor_DataEssenceCoding" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 211
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x44, 0x00 },
+ {0, 0}, false, "MultipleDescriptor" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 212
+ 0x06, 0x01, 0x01, 0x04, 0x06, 0x0b, 0x00, 0x00 },
+ {0x3f, 0x01}, false, "MultipleDescriptor_SubDescriptorUIDs" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 213
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x51, 0x00 },
+ {0, 0}, false, "MPEG2VideoDescriptor" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 214
+ 0x04, 0x01, 0x06, 0x02, 0x01, 0x02, 0x00, 0x00 },
+ {0, 0}, true, "MPEG2VideoDescriptor_SingleSequence" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 215
+ 0x04, 0x01, 0x06, 0x02, 0x01, 0x03, 0x00, 0x00 },
+ {0, 0}, true, "MPEG2VideoDescriptor_ConstantBFrames" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 216
+ 0x04, 0x01, 0x06, 0x02, 0x01, 0x04, 0x00, 0x00 },
+ {0, 0}, true, "MPEG2VideoDescriptor_CodedContentType" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 217
+ 0x04, 0x01, 0x06, 0x02, 0x01, 0x05, 0x00, 0x00 },
+ {0, 0}, true, "MPEG2VideoDescriptor_LowDelay" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 218
+ 0x04, 0x01, 0x06, 0x02, 0x01, 0x06, 0x00, 0x00 },
+ {0, 0}, true, "MPEG2VideoDescriptor_ClosedGOP" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 219
+ 0x04, 0x01, 0x06, 0x02, 0x01, 0x07, 0x00, 0x00 },
+ {0, 0}, true, "MPEG2VideoDescriptor_IdenticalGOP" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 220
+ 0x04, 0x01, 0x06, 0x02, 0x01, 0x08, 0x00, 0x00 },
+ {0, 0}, true, "MPEG2VideoDescriptor_MaxGOP" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 221
+ 0x04, 0x01, 0x06, 0x02, 0x01, 0x09, 0x00, 0x00 },
+ {0, 0}, true, "MPEG2VideoDescriptor_BPictureCount" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 222
+ 0x04, 0x01, 0x06, 0x02, 0x01, 0x0b, 0x00, 0x00 },
+ {0, 0}, true, "MPEG2VideoDescriptor_BitRate" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 223
+ 0x04, 0x01, 0x06, 0x02, 0x01, 0x0a, 0x00, 0x00 },
+ {0, 0}, true, "MPEG2VideoDescriptor_ProfileAndLevel" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 224
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x48, 0x00 },
+ {0, 0}, false, "WaveAudioDescriptor" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 225
+ 0x04, 0x02, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00 },
+ {0x3d, 0x0a}, false, "WaveAudioDescriptor_BlockAlign" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 226
+ 0x04, 0x02, 0x03, 0x02, 0x02, 0x00, 0x00, 0x00 },
+ {0x3d, 0x0b}, true, "WaveAudioDescriptor_SequenceOffset" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 227
+ 0x04, 0x02, 0x03, 0x03, 0x05, 0x00, 0x00, 0x00 },
+ {0x3d, 0x09}, false, "WaveAudioDescriptor_AvgBps" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 228
+ 0x04, 0x02, 0x03, 0x01, 0x0e, 0x00, 0x00, 0x00 },
+ {0x3d, 0x0e}, true, "WaveAudioDescriptor_PeakEnvelope" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 229
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x5a, 0x00 },
+ {0, 0}, false, "JPEG2000PictureSubDescriptor" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0a, // 230
+ 0x04, 0x01, 0x06, 0x03, 0x01, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "JPEG2000PictureSubDescriptor_Rsize" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0a, // 231
+ 0x04, 0x01, 0x06, 0x03, 0x02, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "JPEG2000PictureSubDescriptor_Xsize" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0a, // 232
+ 0x04, 0x01, 0x06, 0x03, 0x03, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "JPEG2000PictureSubDescriptor_Ysize" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0a, // 233
+ 0x04, 0x01, 0x06, 0x03, 0x04, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "JPEG2000PictureSubDescriptor_XOsize" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0a, // 234
+ 0x04, 0x01, 0x06, 0x03, 0x05, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "JPEG2000PictureSubDescriptor_YOsize" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0a, // 235
+ 0x04, 0x01, 0x06, 0x03, 0x06, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "JPEG2000PictureSubDescriptor_XTsize" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0a, // 236
+ 0x04, 0x01, 0x06, 0x03, 0x07, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "JPEG2000PictureSubDescriptor_YTsize" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0a, // 237
+ 0x04, 0x01, 0x06, 0x03, 0x08, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "JPEG2000PictureSubDescriptor_XTOsize" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0a, // 238
+ 0x04, 0x01, 0x06, 0x03, 0x09, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "JPEG2000PictureSubDescriptor_YTOsize" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0a, // 239
+ 0x04, 0x01, 0x06, 0x03, 0x0a, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "JPEG2000PictureSubDescriptor_Csize" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0a, // 240
+ 0x04, 0x01, 0x06, 0x03, 0x0b, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "JPEG2000PictureSubDescriptor_PictureComponentSizing" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0a, // 241
+ 0x04, 0x01, 0x06, 0x03, 0x0c, 0x00, 0x00, 0x00 },
+ {0, 0}, true, "JPEG2000PictureSubDescriptor_CodingStyleDefault" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0a, // 242
+ 0x04, 0x01, 0x06, 0x03, 0x0d, 0x00, 0x00, 0x00 },
+ {0, 0}, true, "JPEG2000PictureSubDescriptor_QuantizationDefault" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 243
+ 0x0d, 0x01, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "DM_Framework" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 244
+ 0x0d, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "DM_Set" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x07, // 245
+ 0x0d, 0x01, 0x03, 0x01, 0x02, 0x0b, 0x01, 0x00 },
+ {0, 0}, false, "EncryptedContainerLabel" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x07, // 246
+ 0x0d, 0x01, 0x04, 0x01, 0x02, 0x01, 0x01, 0x00 },
+ {0, 0}, false, "CryptographicFrameworkLabel" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 247
+ 0x0d, 0x01, 0x04, 0x01, 0x02, 0x01, 0x00, 0x00 },
+ {0, 0}, false, "CryptographicFramework" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x09, // 248
+ 0x06, 0x01, 0x01, 0x04, 0x02, 0x0d, 0x00, 0x00 },
+ {0, 0}, false, "CryptographicFramework_ContextSR" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 249
+ 0x0d, 0x01, 0x04, 0x01, 0x02, 0x02, 0x00, 0x00 },
+ {0, 0}, false, "CryptographicContext" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x09, // 250
+ 0x01, 0x01, 0x15, 0x11, 0x00, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "CryptographicContext_ContextID" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x09, // 251
+ 0x06, 0x01, 0x01, 0x02, 0x02, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "CryptographicContext_SourceEssenceContainer" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x09, // 252
+ 0x02, 0x09, 0x03, 0x01, 0x01, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "CryptographicContext_CipherAlgorithm" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x09, // 253
+ 0x02, 0x09, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "CryptographicContext_MICAlgorithm" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x09, // 254
+ 0x02, 0x09, 0x03, 0x01, 0x02, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "CryptographicContext_CryptographicKeyID" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0a, // 255
+ 0x0d, 0x01, 0x03, 0x01, 0x02, 0x13, 0x01, 0x01 },
+ {0, 0}, false, "TimedTextWrapping" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x02, 0x01, 0x01, // 256
+ 0x0d, 0x01, 0x03, 0x01, 0x17, 0x01, 0x0b, 0x01 },
+ {0, 0}, false, "TimedTextEssence" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 257
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x64, 0x00 },
+ {0, 0}, false, "TimedTextDescriptor" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0c, // 258
+ 0x01, 0x01, 0x15, 0x12, 0x00, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "TimedTextDescriptor_ResourceID" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0c, // 259
+ 0x04, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "TimedTextDescriptor_UCSEncoding" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x08, // 260
+ 0x01, 0x02, 0x01, 0x05, 0x01, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "TimedTextDescriptor_NamespaceURI" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 261
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x65, 0x00 },
+ {0, 0}, false, "TimedTextResourceSubDescriptor" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0c, // 262
+ 0x01, 0x01, 0x15, 0x13, 0x00, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "TimedTextResourceSubDescriptor_AncillaryResourceID" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x07, // 263
+ 0x04, 0x09, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "TimedTextResourceSubDescriptor_MIMEMediaType" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 264
+ 0x01, 0x03, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "TimedTextResourceSubDescriptor_EssenceStreamID" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01, // 265
+ 0x0d, 0x01, 0x02, 0x01, 0x01, 0x03, 0x11, 0x00 },
+ {0, 0}, false, "GenericStreamPartition" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 266
+ 0x04, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ {0x02, 0x01}, false, "DMSegment_DataDefinition" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 267
+ 0x07, 0x02, 0x02, 0x01, 0x01, 0x03, 0x00, 0x00 },
+ {0x02, 0x02}, true, "DMSegment_Duration" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 268
+ 0x01, 0x07, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00 },
+ {0x61, 0x02}, false, "DMSegment_TrackIDList" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x0c, // 269
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x63, 0x00 },
+ {0, 0}, false, "StereoscopicPictureSubDescriptor" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x07, // 270
+ 0x04, 0x02, 0x01, 0x01, 0x05, 0x00, 0x00, 0x00 },
+ {0x3d, 0x32}, true, "WaveAudioDescriptor_ChannelAssignment" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0c, // 271
+ 0x0d, 0x01, 0x05, 0x09, 0x01, 0x00, 0x00, 0x00 },
+ {0x00, 0x00}, false, "GenericStream_DataElement" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 272
+ 0x06, 0x01, 0x01, 0x04, 0x06, 0x10, 0x00, 0x00 },
+ {0, 0}, true, "MXFInterop_GenericDescriptor_SubDescriptors" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 273
+ 0x01, 0x03, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00 },
+ {0x3f, 0x07}, false, "BodySID" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 274
+ 0x01, 0x03, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00 },
+ {0x3f, 0x06}, false, "IndexSID" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 275
+ 0x01, 0x02, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00 },
+ {0x3b, 0x09}, false, "OperationalPattern" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 276
+ 0x01, 0x02, 0x02, 0x10, 0x02, 0x01, 0x00, 0x00 },
+ {0x3b, 0x0a}, false, "EssenceContainers" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0b, // 277
+ 0x04, 0x02, 0x02, 0x10, 0x03, 0x01, 0x01, 0x00 },
+ {0, 0}, false, "DCAudioChannelCfg_1_5p1" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0b, // 278
+ 0x04, 0x02, 0x02, 0x10, 0x03, 0x01, 0x02, 0x00 },
+ {0, 0}, false, "DCAudioChannelCfg_2_6p1" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0b, // 279
+ 0x04, 0x02, 0x02, 0x10, 0x03, 0x01, 0x03, 0x00 },
+ {0, 0}, false, "DCAudioChannelCfg_3_7p1" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0b, // 280
+ 0x04, 0x02, 0x02, 0x10, 0x03, 0x01, 0x04, 0x00 },
+ {0, 0}, false, "DCAudioChannelCfg_4_WTF" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0b, // 281
+ 0x04, 0x02, 0x02, 0x10, 0x03, 0x01, 0x05, 0x00 },
+ {0, 0}, false, "DCAudioChannelCfg_5_7p1_DS" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 282
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x6a, 0x00 },
+ {0, 0}, false, "MCALabelSubDescriptor" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 283
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x6b, 0x00 },
+ {0, 0}, false, "AudioChannelLabelSubDescriptor" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 284
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x6c, 0x00 },
+ {0, 0}, false, "SoundfieldGroupLabelSubDescriptor" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 285
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x6d, 0x00 },
+ {0, 0}, false, "GroupOfSoundfieldGroupsLabelSubDescriptor" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0e, // 286
+ 0x01, 0x03, 0x07, 0x01, 0x01, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "MCALabelSubDescriptor_MCALabelDictionaryID" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0e, // 287
+ 0x01, 0x03, 0x07, 0x01, 0x05, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "MCALabelSubDescriptor_MCALinkID" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0e, // 288
+ 0x01, 0x03, 0x07, 0x01, 0x02, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "MCALabelSubDescriptor_MCATagSymbol" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0e, // 289
+ 0x01, 0x03, 0x07, 0x01, 0x03, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "MCALabelSubDescriptor_MCATagName" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0e, // 290
+ 0x01, 0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "MCALabelSubDescriptor_MCAChannelID" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0d, // 291
+ 0x03, 0x01, 0x01, 0x02, 0x03, 0x15, 0x00, 0x00 },
+ {0, 0}, false, "MCALabelSubDescriptor_RFC5646SpokenLanguage" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0d, // 292
+ 0x01, 0x03, 0x07, 0x01, 0x03, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "AudioChannelLabelSubDescriptor_SoundfieldGroupLinkID" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0d, // 293
+ 0x01, 0x03, 0x07, 0x01, 0x04, 0x00, 0x00, 0x00 },
+ {0, 0}, false, "SoundfieldGroupLabelSubDescriptor_GroupOfSoundfieldGroupsLinkID" },
+ { {0, 0}, {0, 0}, false, 0 }
+};
+
+//
+// end MDD.cpp
+//
diff --git a/asdcplib/src/MDD.h b/asdcplib/src/MDD.h
new file mode 100755
index 0000000..595fd54
--- /dev/null
+++ b/asdcplib/src/MDD.h
@@ -0,0 +1,353 @@
+/*
+Copyright (c) 2006-2012, 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 MDD.[h|cpp]
+ \version $Id: MDD.h,v 1.25 2012/02/02 01:58:43 jhurst Exp $
+ \brief MXF Metadata Dictionary
+*/
+
+#ifndef _MDD_H_
+#define _MDD_H_
+
+//
+namespace ASDCP {
+ enum MDD_t {
+ MDD_MICAlgorithm_NONE, // 0
+ MDD_MXFInterop_OPAtom, // 1
+ MDD_OPAtom, // 2
+ MDD_OP1a, // 3
+ MDD_GCMulti, // 4
+ MDD_PictureDataDef, // 5
+ MDD_SoundDataDef, // 6
+ MDD_TimecodeDataDef, // 7
+ MDD_DescriptiveMetaDataDef, // 8
+ MDD_WAVWrapping, // 9
+ MDD_MPEG2_VESWrapping, // 10
+ MDD_JPEG_2000Wrapping, // 11
+ MDD_JPEG2000Essence, // 12
+ MDD_MPEG2Essence, // 13
+ MDD_MXFInterop_CryptEssence, // 14
+ MDD_CryptEssence, // 15
+ MDD_WAVEssence, // 16
+ MDD_JP2KEssenceCompression_2K, // 17
+ MDD_JP2KEssenceCompression_4K, // 18
+ MDD_CipherAlgorithm_AES, // 19
+ MDD_MICAlgorithm_HMAC_SHA1, // 20
+ MDD_KLVFill, // 21
+ MDD_PartitionMetadata_MajorVersion, // 22
+ MDD_PartitionMetadata_MinorVersion, // 23
+ MDD_PartitionMetadata_KAGSize, // 24
+ MDD_PartitionMetadata_ThisPartition, // 25
+ MDD_PartitionMetadata_PreviousPartition, // 26
+ MDD_PartitionMetadata_FooterPartition, // 27
+ MDD_PartitionMetadata_HeaderByteCount, // 28
+ MDD_PartitionMetadata_IndexByteCount, // 29
+ MDD_PartitionMetadata_IndexSID_DEPRECATED, // 30
+ MDD_PartitionMetadata_BodyOffset, // 31
+ MDD_PartitionMetadata_BodySID_DEPRECATED, // 32
+ MDD_PartitionMetadata_OperationalPattern_DEPRECATED, // 33
+ MDD_PartitionMetadata_EssenceContainers_DEPRECATED, // 34
+ MDD_OpenHeader, // 35
+ MDD_OpenCompleteHeader, // 36
+ MDD_ClosedHeader, // 37
+ MDD_ClosedCompleteHeader, // 38
+ MDD_OpenBodyPartition, // 39
+ MDD_OpenCompleteBodyPartition, // 40
+ MDD_ClosedBodyPartition, // 41
+ MDD_ClosedCompleteBodyPartition, // 42
+ MDD_Footer, // 43
+ MDD_CompleteFooter, // 44
+ MDD_Primer, // 45
+ MDD_Primer_LocalTagEntryBatch, // 46
+ MDD_LocalTagEntryBatch_Primer_LocalTag, // 47
+ MDD_LocalTagEntryBatch_Primer_UID, // 48
+ MDD_InterchangeObject_InstanceUID, // 49
+ MDD_GenerationInterchangeObject_GenerationUID, // 50
+ MDD_DefaultObject, // 51
+ MDD_IndexTableSegmentBase_IndexEditRate, // 52
+ MDD_IndexTableSegmentBase_IndexStartPosition, // 53
+ MDD_IndexTableSegmentBase_IndexDuration, // 54
+ MDD_IndexTableSegmentBase_EditUnitByteCount, // 55
+ MDD_IndexTableSegmentBase_IndexSID_DEPRECATED, // 56
+ MDD_IndexTableSegmentBase_BodySID_DEPRECATED, // 57
+ MDD_IndexTableSegmentBase_SliceCount, // 58
+ MDD_IndexTableSegmentBase_PosTableCount, // 59
+ MDD_IndexTableSegment, // 60
+ MDD_IndexTableSegment_DeltaEntryArray, // 61
+ MDD_DeltaEntryArray_IndexTableSegment_PosTableIndex, // 62
+ MDD_DeltaEntryArray_IndexTableSegment_Slice, // 63
+ MDD_DeltaEntryArray_IndexTableSegment_ElementDelta, // 64
+ MDD_IndexTableSegment_IndexEntryArray, // 65
+ MDD_IndexEntryArray_IndexTableSegment_TemporalOffset, // 66
+ MDD_IndexEntryArray_IndexTableSegment_AnchorOffset, // 67
+ MDD_IndexEntryArray_IndexTableSegment_Flags, // 68
+ MDD_IndexEntryArray_IndexTableSegment_StreamOffset, // 69
+ MDD_IndexEntryArray_IndexTableSegment_SliceOffsetArray, // 70
+ MDD_IndexEntryArray_IndexTableSegment_PosTableArray, // 71
+ MDD_RandomIndexMetadata, // 72
+ MDD_PartitionArray_RandomIndexMetadata_BodySID_DEPRECATED, // 73
+ MDD_PartitionArray_RandomIndexMetadata_ByteOffset, // 74
+ MDD_RandomIndexMetadata_Length, // 75
+ MDD_RandomIndexMetadataV10, // 76
+ MDD_Preface, // 77
+ MDD_Preface_LastModifiedDate, // 78
+ MDD_Preface_Version, // 79
+ MDD_Preface_ObjectModelVersion, // 80
+ MDD_Preface_PrimaryPackage, // 81
+ MDD_Preface_Identifications, // 82
+ MDD_Preface_ContentStorage, // 83
+ MDD_Preface_OperationalPattern_DEPRECATED, // 84
+ MDD_Preface_EssenceContainers_DEPRECATED, // 85
+ MDD_Preface_DMSchemes, // 86
+ MDD_Identification, // 87
+ MDD_Identification_ThisGenerationUID, // 88
+ MDD_Identification_CompanyName, // 89
+ MDD_Identification_ProductName, // 90
+ MDD_Identification_ProductVersion, // 91
+ MDD_Identification_VersionString, // 92
+ MDD_Identification_ProductUID, // 93
+ MDD_Identification_ModificationDate, // 94
+ MDD_Identification_ToolkitVersion, // 95
+ MDD_Identification_Platform, // 96
+ MDD_ContentStorage, // 97
+ MDD_ContentStorage_Packages, // 98
+ MDD_ContentStorage_EssenceContainerData, // 99
+ MDD_ContentStorageKludge_V10Packages, // 100
+ MDD_EssenceContainerData, // 101
+ MDD_EssenceContainerData_LinkedPackageUID, // 102
+ MDD_EssenceContainerData_IndexSID_DEPRECATED, // 103
+ MDD_EssenceContainerData_BodySID_DEPRECATED, // 104
+ MDD_GenericPackage_PackageUID, // 105
+ MDD_GenericPackage_Name, // 106
+ MDD_GenericPackage_PackageCreationDate, // 107
+ MDD_GenericPackage_PackageModifiedDate, // 108
+ MDD_GenericPackage_Tracks, // 109
+ MDD_NetworkLocator, // 110
+ MDD_NetworkLocator_URLString, // 111
+ MDD_TextLocator, // 112
+ MDD_TextLocator_LocatorName, // 113
+ MDD_GenericTrack_TrackID, // 114
+ MDD_GenericTrack_TrackNumber, // 115
+ MDD_GenericTrack_TrackName, // 116
+ MDD_GenericTrack_Sequence, // 117
+ MDD_StaticTrack, // 118
+ MDD_Track, // 119
+ MDD_Track_EditRate, // 120
+ MDD_Track_Origin, // 121
+ MDD_EventTrack, // 122
+ MDD_EventTrack_EventEditRate, // 123
+ MDD_EventTrack_EventOrigin, // 124
+ MDD_StructuralComponent_DataDefinition, // 125
+ MDD_StructuralComponent_Duration, // 126
+ MDD_Sequence, // 127
+ MDD_Sequence_StructuralComponents, // 128
+ MDD_TimecodeComponent, // 129
+ MDD_TimecodeComponent_RoundedTimecodeBase, // 130
+ MDD_TimecodeComponent_StartTimecode, // 131
+ MDD_TimecodeComponent_DropFrame, // 132
+ MDD_SourceClip, // 133
+ MDD_SourceClip_StartPosition, // 134
+ MDD_SourceClip_SourcePackageID, // 135
+ MDD_SourceClip_SourceTrackID, // 136
+ MDD_DMSegment, // 137
+ MDD_DMSegment_EventStartPosition, // 138
+ MDD_DMSegment_EventComment, // 139
+ MDD_DMSegment_TrackIDs, // 140
+ MDD_DMSegment_DMFramework, // 141
+ MDD_DMSourceClip, // 142
+ MDD_DMSourceClip_DMSourceClipTrackIDs, // 143
+ MDD_MaterialPackage, // 144
+ MDD_SourcePackage, // 145
+ MDD_SourcePackage_Descriptor, // 146
+ MDD_GenericDescriptor_Locators, // 147
+ MDD_GenericDescriptor_SubDescriptors, // 148
+ MDD_FileDescriptor, // 149
+ MDD_FileDescriptor_LinkedTrackID, // 150
+ MDD_FileDescriptor_SampleRate, // 151
+ MDD_FileDescriptor_ContainerDuration, // 152
+ MDD_FileDescriptor_EssenceContainer, // 153
+ MDD_FileDescriptor_Codec, // 154
+ MDD_GenericPictureEssenceDescriptor, // 155
+ MDD_GenericPictureEssenceDescriptor_SignalStandard, // 156
+ MDD_GenericPictureEssenceDescriptor_FrameLayout, // 157
+ MDD_GenericPictureEssenceDescriptor_StoredWidth, // 158
+ MDD_GenericPictureEssenceDescriptor_StoredHeight, // 159
+ MDD_GenericPictureEssenceDescriptor_StoredF2Offset, // 160
+ MDD_GenericPictureEssenceDescriptor_SampledWidth, // 161
+ MDD_GenericPictureEssenceDescriptor_SampledHeight, // 162
+ MDD_GenericPictureEssenceDescriptor_SampledXOffset, // 163
+ MDD_GenericPictureEssenceDescriptor_SampledYOffset, // 164
+ MDD_GenericPictureEssenceDescriptor_DisplayHeight, // 165
+ MDD_GenericPictureEssenceDescriptor_DisplayWidth, // 166
+ MDD_GenericPictureEssenceDescriptor_DisplayXOffset, // 167
+ MDD_GenericPictureEssenceDescriptor_DisplayYOffset, // 168
+ MDD_GenericPictureEssenceDescriptor_DisplayF2Offset, // 169
+ MDD_GenericPictureEssenceDescriptor_AspectRatio, // 170
+ MDD_GenericPictureEssenceDescriptor_ActiveFormatDescriptor, // 171
+ MDD_GenericPictureEssenceDescriptor_VideoLineMap, // 172
+ MDD_GenericPictureEssenceDescriptor_AlphaTransparency, // 173
+ MDD_GenericPictureEssenceDescriptor_Gamma, // 174
+ MDD_GenericPictureEssenceDescriptor_ImageAlignmentOffset, // 175
+ MDD_GenericPictureEssenceDescriptor_ImageStartOffset, // 176
+ MDD_GenericPictureEssenceDescriptor_ImageEndOffset, // 177
+ MDD_GenericPictureEssenceDescriptor_FieldDominance, // 178
+ MDD_GenericPictureEssenceDescriptor_PictureEssenceCoding, // 179
+ MDD_CDCIEssenceDescriptor, // 180
+ MDD_CDCIEssenceDescriptor_ComponentDepth, // 181
+ MDD_CDCIEssenceDescriptor_HorizontalSubsampling, // 182
+ MDD_CDCIEssenceDescriptor_VerticalSubsampling, // 183
+ MDD_CDCIEssenceDescriptor_ColorSiting, // 184
+ MDD_CDCIEssenceDescriptor_ReversedByteOrder, // 185
+ MDD_CDCIEssenceDescriptor_PaddingBits, // 186
+ MDD_CDCIEssenceDescriptor_AlphaSampleDepth, // 187
+ MDD_CDCIEssenceDescriptor_BlackRefLevel, // 188
+ MDD_CDCIEssenceDescriptor_WhiteReflevel, // 189
+ MDD_CDCIEssenceDescriptor_ColorRange, // 190
+ MDD_RGBAEssenceDescriptor, // 191
+ MDD_RGBAEssenceDescriptor_ComponentMaxRef, // 192
+ MDD_RGBAEssenceDescriptor_ComponentMinRef, // 193
+ MDD_RGBAEssenceDescriptor_AlphaMaxRef, // 194
+ MDD_RGBAEssenceDescriptor_AlphaMinRef, // 195
+ MDD_RGBAEssenceDescriptor_ScanningDirection, // 196
+ MDD_RGBAEssenceDescriptor_PixelLayout, // 197
+ MDD_RGBAEssenceDescriptor_Palette, // 198
+ MDD_RGBAEssenceDescriptor_PaletteLayout, // 199
+ MDD_GenericSoundEssenceDescriptor, // 200
+ MDD_GenericSoundEssenceDescriptor_AudioSamplingRate, // 201
+ MDD_GenericSoundEssenceDescriptor_Locked, // 202
+ MDD_GenericSoundEssenceDescriptor_AudioRefLevel, // 203
+ MDD_GenericSoundEssenceDescriptor_ElectroSpatialFormulation, // 204
+ MDD_GenericSoundEssenceDescriptor_ChannelCount, // 205
+ MDD_GenericSoundEssenceDescriptor_QuantizationBits, // 206
+ MDD_GenericSoundEssenceDescriptor_DialNorm, // 207
+ MDD_GenericSoundEssenceDescriptor_SoundEssenceCompression, // 208
+ MDD_GenericDataEssenceDescriptor, // 209
+ MDD_GenericDataEssenceDescriptor_DataEssenceCoding, // 210
+ MDD_MultipleDescriptor, // 211
+ MDD_MultipleDescriptor_SubDescriptorUIDs, // 212
+ MDD_MPEG2VideoDescriptor, // 213
+ MDD_MPEG2VideoDescriptor_SingleSequence, // 214
+ MDD_MPEG2VideoDescriptor_ConstantBFrames, // 215
+ MDD_MPEG2VideoDescriptor_CodedContentType, // 216
+ MDD_MPEG2VideoDescriptor_LowDelay, // 217
+ MDD_MPEG2VideoDescriptor_ClosedGOP, // 218
+ MDD_MPEG2VideoDescriptor_IdenticalGOP, // 219
+ MDD_MPEG2VideoDescriptor_MaxGOP, // 220
+ MDD_MPEG2VideoDescriptor_BPictureCount, // 221
+ MDD_MPEG2VideoDescriptor_BitRate, // 222
+ MDD_MPEG2VideoDescriptor_ProfileAndLevel, // 223
+ MDD_WaveAudioDescriptor, // 224
+ MDD_WaveAudioDescriptor_BlockAlign, // 225
+ MDD_WaveAudioDescriptor_SequenceOffset, // 226
+ MDD_WaveAudioDescriptor_AvgBps, // 227
+ MDD_WaveAudioDescriptor_PeakEnvelope, // 228
+ MDD_JPEG2000PictureSubDescriptor, // 229
+ MDD_JPEG2000PictureSubDescriptor_Rsize, // 230
+ MDD_JPEG2000PictureSubDescriptor_Xsize, // 231
+ MDD_JPEG2000PictureSubDescriptor_Ysize, // 232
+ MDD_JPEG2000PictureSubDescriptor_XOsize, // 233
+ MDD_JPEG2000PictureSubDescriptor_YOsize, // 234
+ MDD_JPEG2000PictureSubDescriptor_XTsize, // 235
+ MDD_JPEG2000PictureSubDescriptor_YTsize, // 236
+ MDD_JPEG2000PictureSubDescriptor_XTOsize, // 237
+ MDD_JPEG2000PictureSubDescriptor_YTOsize, // 238
+ MDD_JPEG2000PictureSubDescriptor_Csize, // 239
+ MDD_JPEG2000PictureSubDescriptor_PictureComponentSizing, // 240
+ MDD_JPEG2000PictureSubDescriptor_CodingStyleDefault, // 241
+ MDD_JPEG2000PictureSubDescriptor_QuantizationDefault, // 242
+ MDD_DM_Framework, // 243
+ MDD_DM_Set, // 244
+ MDD_EncryptedContainerLabel, // 245
+ MDD_CryptographicFrameworkLabel, // 246
+ MDD_CryptographicFramework, // 247
+ MDD_CryptographicFramework_ContextSR, // 248
+ MDD_CryptographicContext, // 249
+ MDD_CryptographicContext_ContextID, // 250
+ MDD_CryptographicContext_SourceEssenceContainer, // 251
+ MDD_CryptographicContext_CipherAlgorithm, // 252
+ MDD_CryptographicContext_MICAlgorithm, // 253
+ MDD_CryptographicContext_CryptographicKeyID, // 254
+ MDD_TimedTextWrapping, // 255
+ MDD_TimedTextEssence, // 256
+ MDD_TimedTextDescriptor, // 257
+ MDD_TimedTextDescriptor_ResourceID, // 258
+ MDD_TimedTextDescriptor_UCSEncoding, // 259
+ MDD_TimedTextDescriptor_NamespaceURI, // 260
+ MDD_TimedTextResourceSubDescriptor, // 261
+ MDD_TimedTextResourceSubDescriptor_AncillaryResourceID, // 262
+ MDD_TimedTextResourceSubDescriptor_MIMEMediaType, // 263
+ MDD_TimedTextResourceSubDescriptor_EssenceStreamID_DEPRECATED, // 264
+ MDD_GenericStreamPartition, // 265
+ MDD_DMSegment_DataDefinition_DEPRECATED, // 266
+ MDD_DMSegment_Duration_DEPRECATED, // 267
+ MDD_DMSegment_TrackIDList, // 268
+ MDD_StereoscopicPictureSubDescriptor, // 269
+ MDD_WaveAudioDescriptor_ChannelAssignment, // 270
+ MDD_GenericStream_DataElement, // 271
+ MDD_MXFInterop_GenericDescriptor_SubDescriptors, // 272
+ MDD_Core_BodySID, // 273
+ MDD_Core_IndexSID, // 274
+ MDD_Core_OperationalPattern, // 275
+ MDD_Core_EssenceContainers, // 276
+ MDD_DCAudioChannelCfg_1_5p1, // 277
+ MDD_DCAudioChannelCfg_2_6p1, // 278
+ MDD_DCAudioChannelCfg_3_7p1, // 279
+ MDD_DCAudioChannelCfg_4_WTF, // 280
+ MDD_DCAudioChannelCfg_5_7p1_DS, // 281
+ MDD_MCALabelSubDescriptor, // 282
+ MDD_AudioChannelLabelSubDescriptor, // 283
+ MDD_SoundfieldGroupLabelSubDescriptor, // 284
+ MDD_GroupOfSoundfieldGroupsLabelSubDescriptor, // 285
+ MDD_MCALabelSubDescriptor_MCALabelDictionaryID, // 286
+ MDD_MCALabelSubDescriptor_MCALinkID, // 287
+ MDD_MCALabelSubDescriptor_MCATagSymbol, // 288
+ MDD_MCALabelSubDescriptor_MCATagName, // 289
+ MDD_MCALabelSubDescriptor_MCAChannelID, // 290
+ MDD_MCALabelSubDescriptor_RFC5646SpokenLanguage, // 291
+ MDD_AudioChannelLabelSubDescriptor_SoundfieldGroupLinkID, // 292
+ MDD_SoundfieldGroupLabelSubDescriptor_GroupOfSoundfieldGroupsLinkID, // 293
+ MDD_Max
+
+ }; // enum MDD_t
+
+ //
+ const MDD_t MDD_EssenceContainerData_BodySID = MDD_Core_BodySID;
+ const MDD_t MDD_IndexTableSegmentBase_IndexSID = MDD_Core_IndexSID;
+ const MDD_t MDD_EssenceContainerData_IndexSID = MDD_Core_IndexSID;
+ const MDD_t MDD_DMSegment_DataDefinition = MDD_StructuralComponent_DataDefinition;
+ const MDD_t MDD_DMSegment_Duration = MDD_StructuralComponent_Duration;
+ const MDD_t MDD_Preface_EssenceContainers = MDD_Core_EssenceContainers;
+ const MDD_t MDD_Preface_OperationalPattern = MDD_Core_OperationalPattern;
+ const MDD_t MDD_TimedTextResourceSubDescriptor_EssenceStreamID = MDD_Core_BodySID;
+
+} // namespaceASDCP
+
+
+#endif // _MDD_H_
+
+//
+// end MDD.h
+//
diff --git a/asdcplib/src/MPEG.cpp b/asdcplib/src/MPEG.cpp
new file mode 100755
index 0000000..918b16d
--- /dev/null
+++ b/asdcplib/src/MPEG.cpp
@@ -0,0 +1,295 @@
+/*
+Copyright (c) 2005-2009, 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 MPEG.cpp
+ \version $Id: MPEG.cpp,v 1.4 2009/04/09 19:16:49 msheby Exp $
+ \brief MPEG2 VES parser
+*/
+
+#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
+// of start code
+ASDCP::Result_t
+ASDCP::MPEG2::FindVESStartCode(const byte_t* buf, ui32_t buf_len, StartCode_t* sc, const byte_t** new_pos)
+{
+ ASDCP_TEST_NULL(buf);
+ ASDCP_TEST_NULL(new_pos);
+
+ ui32_t zero_i = 0;
+ const byte_t* p = buf;
+ const byte_t* end_p = buf + buf_len;
+
+ for ( ; p < end_p; p++ )
+ {
+ if ( *p == 0 )
+ zero_i++;
+
+ else if ( *p == 1 && zero_i > 1 )
+ {
+ // 2 or more 0 bytes followed by a 1, start code is next
+ if ( ++p == end_p )
+ return RESULT_FAIL;
+
+ *new_pos = p - 3;
+ *sc = (StartCode_t)*p;
+ return RESULT_OK;
+ }
+ else
+ zero_i = 0;
+ }
+
+ *new_pos = buf + buf_len;
+ return RESULT_FAIL;
+}
+
+
+//------------------------------------------------------------------------------------------
+
+//
+ASDCP::Rational
+ASDCP::MPEG2::Accessor::Sequence::AspectRatio()
+{
+ switch ( m_p[3] & 0xf0 )
+ {
+ case 0x10: return Rational(1,1);
+ case 0x20: return Rational(4,3);
+ case 0x30: return Rational(16,9);
+ case 0x40: return Rational(221,100);
+ }
+
+ DefaultLogSink().Error("Unknown AspectRatio value: %02x\n", m_p[3]);
+ return Rational(0,0);
+}
+
+//------------------------------------------------------------------------------------------
+
+enum State_t {
+ ST_IDLE,
+ ST_START_HEADER,
+ ST_IN_HEADER,
+};
+
+
+//
+class ASDCP::MPEG2::VESParser::h__StreamState
+{
+public:
+ State_t m_State;
+ 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; }
+ 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; }
+};
+
+//------------------------------------------------------------------------------------------
+
+
+ASDCP::MPEG2::VESParser::VESParser() :
+ m_Delegate(0), m_HBufLen(0), m_ZeroCount(0)
+{
+ m_State = new h__StreamState;
+}
+
+ASDCP::MPEG2::VESParser::~VESParser()
+{
+}
+
+
+//
+void
+ASDCP::MPEG2::VESParser::SetDelegate(VESParserDelegate* Delegate)
+{
+ m_Delegate = Delegate;
+}
+
+//
+void
+ASDCP::MPEG2::VESParser::Reset()
+{
+ m_State->Goto_IDLE();
+ m_HBufLen = 0;
+ m_ZeroCount = 0;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MPEG2::VESParser::Parse(const byte_t* buf, ui32_t buf_len)
+{
+ ASDCP_TEST_NULL(buf);
+ ASDCP_TEST_NULL(m_Delegate);
+
+ 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 ( 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);
+ }
+ else
+ {
+ run_len++;
+ }
+
+ if ( m_State->Test_START_HEADER() ) // *p is a start code
+ {
+ 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
+
+ // let the delegate handle the header
+ switch( m_HBuf[3] )
+ {
+ case PIC_START: result = m_Delegate->Picture(this, m_HBuf, m_HBufLen); break;
+ case EXT_START: result = m_Delegate->Extension(this, m_HBuf, m_HBufLen); break;
+ case SEQ_START: result = m_Delegate->Sequence(this, m_HBuf, m_HBufLen); break;
+ case GOP_START: result = m_Delegate->GOP(this, m_HBuf, m_HBufLen); break;
+
+ default:
+ DefaultLogSink().Error("Unexpected start code: %02x at byte %u\n",
+ m_HBuf[3], (ui32_t)(p - buf));
+ result = RESULT_RAW_FORMAT;
+ }
+
+ // Parser handlers return RESULT_FALSE to teriminate without error
+ if ( result != RESULT_OK )
+ {
+ m_State->Goto_IDLE();
+ return result;
+ }
+
+ 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 )
+ {
+ m_HBufLen = 4;
+ m_State->Goto_IN_HEADER();
+ }
+ else
+ {
+ m_HBufLen = 0;
+ m_State->Goto_IDLE();
+
+ if ( *p >= FIRST_SLICE && *p <= LAST_SLICE )
+ {
+ result = m_Delegate->Slice(this, *p);
+
+ if ( result != RESULT_OK )
+ return result;
+ }
+
+ m_Delegate->Data(this, m_HBuf, 4);
+ run_pos = p+1;
+ }
+ }
+ }
+ else if ( *p == 0 )
+ {
+ m_ZeroCount++;
+ }
+ else
+ {
+ if ( *p == 1 && m_ZeroCount > 1 )
+ m_State->Goto_START_HEADER();
+
+ m_ZeroCount = 0;
+ }
+ }
+
+ if ( run_len > 0 )
+ {
+ if ( m_State->Test_START_HEADER() && run_len != 0 )
+ {
+ assert(run_len > 2);
+ run_len -= 3;
+ }
+
+ // flush the current run
+ m_Delegate->Data(this, run_pos, run_len);
+ }
+
+ return RESULT_OK;
+}
+
+
+//
+// end MPEG.cpp
+//
diff --git a/asdcplib/src/MPEG.h b/asdcplib/src/MPEG.h
new file mode 100755
index 0000000..b629b62
--- /dev/null
+++ b/asdcplib/src/MPEG.h
@@ -0,0 +1,244 @@
+/*
+Copyright (c) 2005-2011, 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 MPEG.h
+ \version $Id: MPEG.h,v 1.5 2011/08/30 17:04:25 jhurst Exp $
+ \brief MPEG2 VES parser interface
+*/
+
+#ifndef _MPEG_H_
+#define _MPEG_H_
+
+#include <KM_platform.h>
+#include "AS_DCP.h"
+#include <stdio.h>
+#include <assert.h>
+
+
+namespace ASDCP
+{
+ namespace MPEG2
+ {
+ //
+ enum StartCode_t {
+ PIC_START = 0x00,
+ SEQ_START = 0xb3,
+ EXT_START = 0xb5,
+ GOP_START = 0xb8,
+ FIRST_SLICE = 0x01,
+ LAST_SLICE = 0xaf,
+ INVALID = 0xff
+ };
+
+ //
+ enum RateCode_t {
+ RATE_23_976 = 0x01,
+ RATE_24 = 0x02,
+ RATE_25 = 0x03,
+ RATE_29_97 = 0x04,
+ RATE_30 = 0x05
+ };
+
+ //
+ enum ExtCode_t {
+ EXT_SEQ = 0x01
+ };
+
+ //------------------------------------------------------------------------------------------
+ // VES Parser
+
+ // find the location in the buffer of the next VES packet, returns RESULT_FAIL
+ // if no start code is found
+ Result_t FindVESStartCode(const byte_t* buf, ui32_t buf_len, StartCode_t* sc, const byte_t** new_pos);
+
+ // return the extension code of an extension header
+ inline ExtCode_t ParseExtensionCode(const byte_t* buf)
+ {
+ assert(buf);
+ return (ExtCode_t)(buf[4] >> 4);
+ }
+
+ //
+ class VESParserDelegate; // the delegate is declared later
+ const ui32_t VESHeaderBufSize = 1024*32; // should be larger than any expected header
+
+ // MPEG VES parser class - call Parse() as many times as you want with buffers
+ // of any size. State is maintained between calls. When complete headers are
+ // available for examination, the respective delegate method will be called.
+ // All other data is given to the delegate's Data() method.
+ class VESParser
+ {
+ class h__StreamState;
+ Kumu::mem_ptr<h__StreamState> m_State;
+ VESParserDelegate* m_Delegate;
+
+ ui32_t m_HBufLen; // temp space for partial header contents
+ byte_t m_HBuf[VESHeaderBufSize];
+ ui32_t m_ZeroCount;
+ bool m_Partial;
+
+ ASDCP_NO_COPY_CONSTRUCT(VESParser);
+
+ public:
+ VESParser();
+ ~VESParser();
+
+ 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, return to the top of the file
+ };
+
+ // Parser Event Delegate Interface
+ //
+ // 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 terminate parsing without signaling an error.
+ //
+ class VESParserDelegate
+ {
+ public:
+ virtual ~VESParserDelegate() {}
+
+ // header handlers
+ 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*, byte_t slice_id) = 0;
+
+ // Any data not given to the header handlers above is reported here
+ // 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;
+ };
+
+
+ //------------------------------------------------------------------------------------------
+ // VES header accessor objects
+ //
+ // 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 it is hoped that they are self-explanatory.
+
+ //
+ namespace Accessor
+ {
+ // decoding tables
+ static i16_t FrameRateLUT[] = { 0, 24, 24, 25, 30, 30, 50, 60, 60};
+ static bool PulldownLUT[] = { false, true, false, false, true, false, false, true, false};
+
+ //
+ class Sequence
+ {
+ const byte_t* m_p;
+ ASDCP_NO_COPY_CONSTRUCT(Sequence);
+
+ public:
+ Sequence(const byte_t* p) { assert(p); m_p = p + 4; }
+ inline ui16_t HorizontalSize() { return (ui16_t)( ( m_p[0] << 4 ) | ( m_p[1] >> 4 ) ); }
+ inline ui16_t VerticalSize() { return (ui16_t)( ( ( m_p[1] & 0x0f ) << 8 ) | m_p[2] ); }
+ inline RateCode_t RateCode() { return (RateCode_t)( m_p[3] & 0x0f ); }
+ inline ui16_t FrameRate() { return FrameRateLUT[RateCode()]; }
+ inline bool Pulldown() { return PulldownLUT[RateCode()] != 0; }
+ inline i32_t BitRate() {
+ return ( ( (i32_t)m_p[4] << 10 ) + ( (i32_t)m_p[5] << 2 ) + ( m_p[6] >> 6 ) ) * 400;
+ }
+
+ Rational AspectRatio();
+ };
+
+ //
+ class SequenceEx // tension
+ {
+ const byte_t* m_p;
+ ASDCP_NO_COPY_CONSTRUCT(SequenceEx);
+
+ public:
+ SequenceEx(const byte_t* p)
+ {
+ assert(p);
+ assert(ParseExtensionCode(p) == EXT_SEQ);
+ m_p = p + 4;
+ }
+
+ inline ui16_t ProfileAndLevel() { return ( m_p[0] << 4) | ( m_p[1] >> 4 ); }
+ inline ui8_t ChromaFormat() { return ( m_p[1] >> 1 ) & 0x03; }
+ inline bool Progressive() { return ( ( m_p[1] >> 3 ) & 0x01 ) > 0; }
+ inline ui32_t HorizontalSizeExt() {
+ return ( ( m_p[1] & 0x01 ) << 13 ) | ( ( m_p[2] & 0x80 ) << 5 );
+ }
+ inline ui32_t VerticalSizeExt() { return ( m_p[2] & 0x60 ) << 7; }
+ inline ui32_t BitRateExt() {
+ return ( ( m_p[2] & 0x1f ) << 25 ) | ( ( m_p[3] & 0xfe ) << 17 );
+ }
+
+ inline bool LowDelay() { return ( m_p[5] & 0x80 ) > 0; }
+ };
+
+ //
+ class GOP
+ {
+ const byte_t* m_p;
+ ASDCP_NO_COPY_CONSTRUCT(GOP);
+
+ public:
+ GOP(const byte_t* p) { assert(p); m_p = p + 4; }
+ inline bool Closed() { return ( ( m_p[3] ) >> 6 ) & 0x01; }
+ };
+
+ //
+ class Picture
+ {
+ const byte_t* m_p;
+ ASDCP_NO_COPY_CONSTRUCT(Picture);
+
+ public:
+ Picture(const byte_t* p) { assert(p); m_p = p + 4; }
+ inline i16_t TemporalRef() {
+ return ( (i16_t)( m_p[0] << 2 ) ) | ( ( (i16_t)m_p[1] & 0x00c0 ) >> 6 );
+ }
+
+ inline FrameType_t FrameType() {
+ return (FrameType_t)( ( m_p[1] & 0x38 ) >> 3 );
+ }
+ };
+
+ } // namespace Accessor
+
+ } // namespace MPEG2
+
+} // namespace ASDCP
+
+#endif // _MPEG_H_
+
+//
+// end MPEG.h
+//
diff --git a/asdcplib/src/MPEG2_Parser.cpp b/asdcplib/src/MPEG2_Parser.cpp
new file mode 100755
index 0000000..3b81f5a
--- /dev/null
+++ b/asdcplib/src/MPEG2_Parser.cpp
@@ -0,0 +1,639 @@
+/*
+Copyright (c) 2004-2011, 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 MPEG2_Parser.cpp
+ \version $Id: MPEG2_Parser.cpp,v 1.11 2011/08/30 17:04:25 jhurst Exp $
+ \brief AS-DCP library, MPEG2 raw essence reader implementation
+*/
+
+#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 = 4 * Kumu::Kilobyte;
+
+
+//------------------------------------------------------------------------------------------
+
+//
+enum ParserState_t {
+ ST_INIT,
+ ST_SEQ,
+ ST_PIC,
+ ST_GOP,
+ ST_EXT,
+ ST_SLICE,
+};
+
+const char*
+StringParserState(ParserState_t state)
+{
+ switch ( state )
+ {
+ case ST_INIT: return "INIT";
+ case ST_SEQ: return "SEQ";
+ case ST_PIC: return "PIC";
+ case ST_GOP: return "GOP";
+ case ST_EXT: return "EXT";
+ case ST_SLICE: return "SLICE";
+ }
+
+ return "*UNKNOWN*";
+}
+
+
+
+//
+class h__ParserState
+{
+ ParserState_t m_State;
+ ASDCP_NO_COPY_CONSTRUCT(h__ParserState);
+
+ public:
+ h__ParserState() : m_State(ST_INIT) {}
+ ~h__ParserState() {}
+
+ inline bool Test_SLICE() { return m_State == ST_SLICE; }
+ inline void Reset() { m_State = ST_INIT; }
+
+ //
+ inline Result_t Goto_SEQ()
+ {
+ switch ( m_State )
+ {
+ case ST_INIT:
+ case ST_EXT:
+ m_State = ST_SEQ;
+ return RESULT_OK;
+ case ST_SEQ:
+ case ST_PIC:
+ case ST_GOP:
+ case ST_SLICE:
+ /* Keep gcc quiet */
+ break;
+ }
+
+ DefaultLogSink().Error("SEQ follows %s\n", StringParserState(m_State));
+ return RESULT_STATE;
+ }
+
+
+ //
+ inline Result_t Goto_SLICE()
+ {
+ switch ( m_State )
+ {
+ case ST_PIC:
+ case ST_EXT:
+ m_State = ST_SLICE;
+ return RESULT_OK;
+ case ST_INIT:
+ case ST_SEQ:
+ case ST_GOP:
+ case ST_SLICE:
+ /* Keep gcc quiet */
+ break;
+ }
+
+ DefaultLogSink().Error("Slice follows %s\n", StringParserState(m_State));
+ return RESULT_STATE;
+ }
+
+
+ //
+ inline Result_t Goto_PIC()
+ {
+ switch ( m_State )
+ {
+ case ST_INIT:
+ case ST_SEQ:
+ case ST_GOP:
+ case ST_EXT:
+ m_State = ST_PIC;
+ return RESULT_OK;
+ case ST_PIC:
+ case ST_SLICE:
+ /* Keep gcc quiet */
+ break;
+ }
+
+ DefaultLogSink().Error("PIC follows %s\n", StringParserState(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;
+ case ST_INIT:
+ case ST_PIC:
+ case ST_GOP:
+ case ST_SLICE:
+ /* Keep gcc quiet */
+ break;
+ }
+
+ DefaultLogSink().Error("GOP follows %s\n", StringParserState(m_State));
+ return RESULT_STATE;
+ }
+
+ //
+ inline Result_t Goto_EXT()
+ {
+ switch ( m_State )
+ {
+ case ST_PIC:
+ case ST_EXT:
+ case ST_SEQ:
+ case ST_GOP:
+ m_State = ST_EXT;
+ return RESULT_OK;
+ case ST_INIT:
+ case ST_SLICE:
+ /* Keep gcc quiet */
+ break;
+ }
+
+ DefaultLogSink().Error("EXT follows %s\n", StringParserState(m_State));
+ return RESULT_STATE;
+ }
+};
+
+//------------------------------------------------------------------------------------------
+
+// This is a parser delagate that reads the stream params from a
+// sequence header and sequence extension header. The parser is
+// commanded to return after processing the sequence extension
+// header.
+class StreamParams : public VESParserDelegate
+{
+ h__ParserState m_State;
+
+ ASDCP_NO_COPY_CONSTRUCT(StreamParams);
+
+public:
+ VideoDescriptor m_VDesc;
+
+ StreamParams()
+ {
+ m_VDesc.ContainerDuration = 0;
+ m_VDesc.ComponentDepth = 8;
+ }
+
+ ~StreamParams() {}
+
+ //
+ Result_t Sequence(VESParser*, const byte_t* b, ui32_t)
+ {
+ Result_t result = m_State.Goto_SEQ();
+
+ if ( ASDCP_FAILURE(result) )
+ return result;
+
+ Accessor::Sequence SEQ(b);
+ m_VDesc.AspectRatio = SEQ.AspectRatio();
+ m_VDesc.FrameRate = SEQ.FrameRate();
+ m_VDesc.StoredWidth = SEQ.HorizontalSize();
+ m_VDesc.StoredHeight = SEQ.VerticalSize();
+ m_VDesc.BitRate = SEQ.BitRate();
+ m_VDesc.EditRate = SEQ.Pulldown() ? Rational(SEQ.FrameRate() * 1000, 1001) : Rational(SEQ.FrameRate(), 1);
+ m_VDesc.SampleRate = m_VDesc.EditRate;
+ return RESULT_OK;
+ }
+
+ //
+ Result_t Extension(VESParser*, const byte_t* b, ui32_t)
+ {
+ Result_t result = m_State.Goto_EXT();
+
+ if ( ASDCP_FAILURE(result) )
+ return result;
+
+ Accessor::SequenceEx SEQX(b);
+ m_VDesc.ProfileAndLevel = SEQX.ProfileAndLevel();
+ m_VDesc.FrameLayout = SEQX.Progressive() ? 0 : 1;
+ m_VDesc.CodedContentType = SEQX.Progressive() ? 1 : 2;
+ m_VDesc.LowDelay = SEQX.LowDelay();
+ m_VDesc.HorizontalSubsampling = SEQX.ChromaFormat() == 3 ? 1 : 2;
+ m_VDesc.VerticalSubsampling = SEQX.ChromaFormat() >= 3 ? 1 : 2;
+
+ if ( ( m_VDesc.HorizontalSubsampling == 2 ) && ( m_VDesc.VerticalSubsampling == 2 ) )
+ m_VDesc.ColorSiting = 3; // 4:2:0
+
+ else if ( ( m_VDesc.HorizontalSubsampling == 2 ) && ( m_VDesc.VerticalSubsampling == 1 ) )
+ m_VDesc.ColorSiting = 4; // 4:2:2
+
+ else if ( ( m_VDesc.HorizontalSubsampling == 1 ) && ( m_VDesc.VerticalSubsampling == 1 ) )
+ m_VDesc.ColorSiting = 0; // 4:4:4
+
+ // TODO: get H&V size and bit rate extensions
+
+ return RESULT_FALSE;
+ }
+
+ 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*, byte_t) { return RESULT_FALSE; }
+ Result_t Data(VESParser*, const byte_t*, i32_t) { return RESULT_OK; }
+};
+
+
+//------------------------------------------------------------------------------------------
+
+// This is a parser delagate that reads a VES stream and sets public
+// instance variables to indicate state. It is used below to read an
+// entire frame into a buffer. The delegate retains metadata about the
+// frame for later access.
+//
+class FrameParser : public VESParserDelegate
+{
+ h__ParserState m_State;
+ ASDCP_NO_COPY_CONSTRUCT(FrameParser);
+
+public:
+ ui32_t m_FrameSize;
+ bool m_CompletePicture;
+ bool m_HasGOP;
+ bool m_ClosedGOP;
+ ui8_t m_TemporalRef;
+ ui32_t m_PlaintextOffset;
+ FrameType_t m_FrameType;
+
+ FrameParser()
+ {
+ Reset();
+ }
+
+ ~FrameParser() {}
+
+ void Reset()
+ {
+ m_FrameSize = 0;
+ m_HasGOP = m_ClosedGOP = false;
+ m_CompletePicture = false;
+ m_TemporalRef = 0;
+ m_PlaintextOffset = 0;
+ m_FrameType = FRAME_U;
+ m_State.Reset();
+ }
+
+ Result_t Sequence(VESParser*, const byte_t*, ui32_t s)
+ {
+ if ( m_State.Test_SLICE() )
+ {
+ m_CompletePicture = true;
+ return RESULT_FALSE;
+ }
+
+ m_FrameSize += s;
+ return m_State.Goto_SEQ();
+ }
+
+ Result_t Picture(VESParser*, const byte_t* b, ui32_t s)
+ {
+ if ( m_State.Test_SLICE() )
+ {
+ m_CompletePicture = true;
+ return RESULT_FALSE;
+ }
+
+ Accessor::Picture pic(b);
+ m_TemporalRef = pic.TemporalRef();
+ m_FrameType = pic.FrameType();
+ m_FrameSize += s;
+ return m_State.Goto_PIC();
+ }
+
+ Result_t Slice(VESParser*, byte_t slice_id)
+ {
+ 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*, ui32_t s)
+ {
+ m_FrameSize += s;
+ return m_State.Goto_EXT();
+ }
+
+ Result_t GOP(VESParser*, const byte_t* b, ui32_t s)
+ {
+ Accessor::GOP GOP(b);
+ m_ClosedGOP = GOP.Closed();
+ m_HasGOP = true;
+ m_FrameSize += s;
+ return m_State.Goto_GOP();
+ }
+
+ Result_t Data(VESParser*, const byte_t*, i32_t s)
+ {
+ m_FrameSize += s;
+ return RESULT_OK;
+ }
+};
+
+//------------------------------------------------------------------------------------------
+
+// The following code assumes the following things:
+// - each frame will begin with a picture header or a sequence header
+// - any frame that begins with a sequence header is an I frame and is
+// assumed to contain a GOP header, a picture header and complete picture data
+// - 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;
+ Kumu::FileReader m_FileReader;
+ ui32_t m_FrameNumber;
+ bool m_EOF;
+ ASDCP::MPEG2::FrameBuffer m_TmpBuffer;
+
+ ASDCP_NO_COPY_CONSTRUCT(h__Parser);
+
+public:
+ h__Parser() : m_TmpBuffer(VESReadSize*8) {}
+ ~h__Parser() { Close(); }
+
+ Result_t OpenRead(const char* filename);
+ void Close();
+ Result_t Reset();
+ Result_t ReadFrame(FrameBuffer&);
+ Result_t FillVideoDescriptor(VideoDescriptor&);
+};
+
+
+//
+Result_t
+ASDCP::MPEG2::Parser::h__Parser::Reset()
+{
+ m_FrameNumber = 0;
+ m_EOF = false;
+ m_FileReader.Seek(0);
+ m_ParserDelegate.Reset();
+ return RESULT_OK;
+}
+
+//
+void
+ASDCP::MPEG2::Parser::h__Parser::Close()
+{
+ m_FileReader.Close();
+}
+
+//
+ASDCP::Result_t
+ASDCP::MPEG2::Parser::h__Parser::OpenRead(const char* filename)
+{
+ ASDCP_TEST_NULL_STR(filename)
+ ui32_t read_count = 0;
+
+ Result_t result = m_FileReader.OpenRead(filename);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = m_FileReader.Read(m_TmpBuffer.Data(), m_TmpBuffer.Capacity(), &read_count);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ const byte_t* p = m_TmpBuffer.RoData();
+
+ // the mxflib parser demanded the file start with a sequence header.
+ // 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.
+ ui32_t i = 0;
+ while ( p[i] == 0 ) i++;
+
+ if ( i < 2 || p[i] != 1 || ! ( p[i+1] == SEQ_START || p[i+1] == PIC_START ) )
+ {
+ DefaultLogSink().Error("Frame buffer does not begin with a PIC or SEQ start code.\n");
+ return RESULT_RAW_FORMAT;
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ m_Parser.SetDelegate(&m_ParamsDelegate);
+ result = m_Parser.Parse(p, read_count);
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ ui64_t tmp = m_FileReader.Size() / 65536; // a gross approximation
+ m_ParamsDelegate.m_VDesc.ContainerDuration = (ui32_t) tmp;
+ m_Parser.SetDelegate(&m_ParserDelegate);
+ m_FileReader.Seek(0);
+ }
+
+ if ( ASDCP_FAILURE(result) )
+ {
+ DefaultLogSink().Error("Unable to identify a wrapping mode for the essence in file \"%s\"\n", filename);
+ m_FileReader.Close();
+ }
+
+ return result;}
+
+
+//
+//
+ASDCP::Result_t
+ASDCP::MPEG2::Parser::h__Parser::ReadFrame(FrameBuffer& FB)
+{
+ Result_t result = RESULT_OK;
+ ui32_t write_offset = 0;
+ ui32_t read_count = 0;
+
+ FB.Size(0);
+
+ if ( m_EOF )
+ return RESULT_ENDOFFILE;
+
+ // Data is read in VESReadSize chunks. Each chunk is parsed, and the
+ // process is stopped when a Sequence or Picture header is found or when
+ // 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 )
+ {
+ memcpy(FB.Data(), m_TmpBuffer.RoData(), m_TmpBuffer.Size());
+ result = m_Parser.Parse(FB.RoData(), m_TmpBuffer.Size());
+ write_offset = m_TmpBuffer.Size();
+ m_TmpBuffer.Size(0);
+ }
+
+ while ( ! m_ParserDelegate.m_CompletePicture && result == RESULT_OK )
+ {
+ if ( FB.Capacity() < ( write_offset + VESReadSize ) )
+ {
+ DefaultLogSink().Error("FrameBuf.Capacity: %u FrameLength: %u\n",
+ FB.Capacity(), ( write_offset + VESReadSize ));
+ return RESULT_SMALLBUF;
+ }
+
+ result = m_FileReader.Read(FB.Data() + write_offset, VESReadSize, &read_count);
+
+ if ( result == RESULT_ENDOFFILE || read_count == 0 )
+ {
+ m_EOF = true;
+
+ if ( write_offset > 0 )
+ result = RESULT_OK;
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ result = m_Parser.Parse(FB.RoData() + write_offset, read_count);
+ write_offset += read_count;
+ }
+
+ if ( m_EOF )
+ break;
+ }
+ assert(m_ParserDelegate.m_FrameSize <= write_offset);
+
+ if ( ASDCP_SUCCESS(result)
+ && m_ParserDelegate.m_FrameSize < write_offset )
+ {
+ 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);
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ const byte_t* p = FB.RoData();
+ 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;
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ FB.Size(m_ParserDelegate.m_FrameSize);
+ FB.TemporalOffset(m_ParserDelegate.m_TemporalRef);
+ FB.FrameType(m_ParserDelegate.m_FrameType);
+ FB.PlaintextOffset(m_ParserDelegate.m_PlaintextOffset);
+ FB.FrameNumber(m_FrameNumber++);
+ FB.GOPStart(m_ParserDelegate.m_HasGOP);
+ FB.ClosedGOP(m_ParserDelegate.m_ClosedGOP);
+ }
+
+ return result;
+}
+
+
+// Fill a VideoDescriptor struct with the values from the file's header.
+ASDCP::Result_t
+ASDCP::MPEG2::Parser::h__Parser::FillVideoDescriptor(VideoDescriptor& VDesc)
+{
+ VDesc = m_ParamsDelegate.m_VDesc;
+ return RESULT_OK;
+}
+
+//------------------------------------------------------------------------------------------
+
+ASDCP::MPEG2::Parser::Parser()
+{
+}
+
+ASDCP::MPEG2::Parser::~Parser()
+{
+}
+
+// Opens the stream for reading, parses enough data to provide a complete
+// set of stream metadata for the MXFWriter below.
+ASDCP::Result_t
+ASDCP::MPEG2::Parser::OpenRead(const char* filename) const
+{
+ const_cast<ASDCP::MPEG2::Parser*>(this)->m_Parser = new h__Parser;
+
+ Result_t result = m_Parser->OpenRead(filename);
+
+ if ( ASDCP_FAILURE(result) )
+ const_cast<ASDCP::MPEG2::Parser*>(this)->m_Parser.release();
+
+ return result;
+}
+
+// Rewinds the stream to the beginning.
+ASDCP::Result_t
+ASDCP::MPEG2::Parser::Reset() const
+{
+ if ( m_Parser.empty() )
+ return RESULT_INIT;
+
+ return m_Parser->Reset();
+}
+
+// Places a frame of data in the frame buffer. Fails if the buffer is too small
+// or the stream is empty.
+ASDCP::Result_t
+ASDCP::MPEG2::Parser::ReadFrame(FrameBuffer& FB) const
+{
+ if ( m_Parser.empty() )
+ return RESULT_INIT;
+
+ return m_Parser->ReadFrame(FB);
+}
+
+ASDCP::Result_t
+ASDCP::MPEG2::Parser::FillVideoDescriptor(VideoDescriptor& VDesc) const
+{
+ if ( m_Parser.empty() )
+ return RESULT_INIT;
+
+ return m_Parser->FillVideoDescriptor(VDesc);
+}
+
+//
+// end MPEG2_Parser.cpp
+//
diff --git a/asdcplib/src/MXF.cpp b/asdcplib/src/MXF.cpp
new file mode 100755
index 0000000..c35c1d2
--- /dev/null
+++ b/asdcplib/src/MXF.cpp
@@ -0,0 +1,1489 @@
+/*
+Copyright (c) 2005-2012, 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 MXF.cpp
+ \version $Id: MXF.cpp,v 1.62 2012/03/05 13:11:47 jhurst Exp $
+ \brief MXF objects
+*/
+
+#include "MXF.h"
+#include "Metadata.h"
+#include <KM_log.h>
+
+using Kumu::DefaultLogSink;
+using Kumu::GenRandomValue;
+
+// index segments must be < 64K
+// NOTE: this value may too high if advanced index entry elements are used.
+const ui32_t CBRIndexEntriesPerSegment = 5000;
+
+//------------------------------------------------------------------------------------------
+//
+
+const ui32_t kl_length = ASDCP::SMPTE_UL_LENGTH + ASDCP::MXF_BER_LENGTH;
+
+//
+ASDCP::Result_t
+ASDCP::MXF::SeekToRIP(const Kumu::FileReader& Reader)
+{
+ Kumu::fpos_t end_pos;
+
+ // go to the end - 4 bytes
+ Result_t result = Reader.Seek(0, Kumu::SP_END);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Reader.Tell(&end_pos);
+
+ if ( ASDCP_SUCCESS(result)
+ && end_pos < (SMPTE_UL_LENGTH+MXF_BER_LENGTH) )
+ result = RESULT_FAIL; // File is smaller than an empty packet!
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Reader.Seek(end_pos - 4);
+
+ // get the ui32_t RIP length
+ ui32_t read_count;
+ byte_t intbuf[MXF_BER_LENGTH];
+ ui32_t rip_size = 0;
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ result = Reader.Read(intbuf, MXF_BER_LENGTH, &read_count);
+
+ if ( ASDCP_SUCCESS(result) && read_count != 4 )
+ result = RESULT_FAIL;
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ 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;
+ }
+
+ // reposition to start of RIP
+ if ( ASDCP_SUCCESS(result) )
+ result = Reader.Seek(end_pos - rip_size);
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::RIP::GetPairBySID(ui32_t SID, Pair& outPair) const
+{
+ Array<Pair>::const_iterator pi = PairArray.begin();
+ for ( ; pi != PairArray.end(); pi++ )
+ {
+ if ( (*pi).BodySID == SID )
+ {
+ outPair = *pi;
+ return RESULT_OK;
+ }
+ }
+
+ return RESULT_FAIL;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::RIP::InitFromFile(const Kumu::FileReader& Reader)
+{
+ assert(m_Dict);
+ Result_t result = KLVFilePacket::InitFromFile(Reader, m_Dict->ul(MDD_RandomIndexMetadata));
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ Kumu::MemIOReader MemRDR(m_ValueStart, m_ValueLength - 4);
+ result = PairArray.Unarchive(&MemRDR) ? RESULT_OK : RESULT_KLV_CODING;
+ }
+
+ if ( ASDCP_FAILURE(result) )
+ DefaultLogSink().Error("Failed to initialize RIP\n");
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::RIP::WriteToFile(Kumu::FileWriter& Writer)
+{
+ assert(m_Dict);
+ ASDCP::FrameBuffer Buffer;
+ ui32_t RIPSize = ( PairArray.size() * (sizeof(ui32_t) + sizeof(ui64_t)) ) + 4;
+ Result_t result = Buffer.Capacity(RIPSize);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = WriteKLToFile(Writer, m_Dict->ul(MDD_RandomIndexMetadata), RIPSize);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ result = RESULT_KLV_CODING;
+
+ 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) )
+ result = Writer.Write(Buffer.RoData(), Buffer.Size());
+
+ return result;
+}
+
+//
+void
+ASDCP::MXF::RIP::Dump(FILE* stream)
+{
+ if ( stream == 0 )
+ stream = stderr;
+
+ KLVFilePacket::Dump(stream, *m_Dict, false);
+ PairArray.Dump(stream, false);
+}
+
+//------------------------------------------------------------------------------------------
+//
+
+//
+class ASDCP::MXF::Partition::h__PacketList
+{
+public:
+ std::list<InterchangeObject*> m_List;
+ std::map<UUID, InterchangeObject*> m_Map;
+
+ ~h__PacketList() {
+ while ( ! m_List.empty() )
+ {
+ delete m_List.back();
+ m_List.pop_back();
+ }
+ }
+
+ //
+ void AddPacket(InterchangeObject* ThePacket) // takes ownership
+ {
+ assert(ThePacket);
+ m_Map.insert(std::map<UUID, InterchangeObject*>::value_type(ThePacket->InstanceUID, ThePacket));
+ m_List.push_back(ThePacket);
+ }
+
+ //
+ Result_t GetMDObjectByID(const UUID& ObjectID, InterchangeObject** Object)
+ {
+ ASDCP_TEST_NULL(Object);
+
+ std::map<UUID, InterchangeObject*>::iterator mi = m_Map.find(ObjectID);
+
+ if ( mi == m_Map.end() )
+ {
+ *Object = 0;
+ return RESULT_FAIL;
+ }
+
+ *Object = (*mi).second;
+ return RESULT_OK;
+ }
+
+ //
+ Result_t GetMDObjectByType(const byte_t* ObjectID, InterchangeObject** Object)
+ {
+ ASDCP_TEST_NULL(ObjectID);
+ ASDCP_TEST_NULL(Object);
+ std::list<InterchangeObject*>::iterator li;
+ *Object = 0;
+
+ for ( li = m_List.begin(); li != m_List.end(); li++ )
+ {
+ if ( (*li)->HasUL(ObjectID) )
+ {
+ *Object = *li;
+ return RESULT_OK;
+ }
+ }
+
+ return RESULT_FAIL;
+ }
+
+ //
+ Result_t GetMDObjectsByType(const byte_t* ObjectID, std::list<InterchangeObject*>& ObjectList)
+ {
+ ASDCP_TEST_NULL(ObjectID);
+ std::list<InterchangeObject*>::iterator li;
+
+ for ( li = m_List.begin(); li != m_List.end(); li++ )
+ {
+ if ( (*li)->HasUL(ObjectID) )
+ ObjectList.push_back(*li);
+ }
+
+ return ObjectList.empty() ? RESULT_FAIL : RESULT_OK;
+ }
+};
+
+//------------------------------------------------------------------------------------------
+//
+
+
+ASDCP::MXF::Partition::Partition(const Dictionary*& d) :
+ m_Dict(d),
+ MajorVersion(1), MinorVersion(2),
+ KAGSize(1), ThisPartition(0), PreviousPartition(0),
+ FooterPartition(0), HeaderByteCount(0), IndexByteCount(0), IndexSID(0),
+ BodyOffset(0), BodySID(0)
+{
+ m_PacketList = new h__PacketList;
+}
+
+ASDCP::MXF::Partition::~Partition()
+{
+}
+
+// takes ownership
+void
+ASDCP::MXF::Partition::AddChildObject(InterchangeObject* Object)
+{
+ assert(Object);
+
+ if ( ! Object->InstanceUID.HasValue() )
+ GenRandomValue(Object->InstanceUID);
+
+ m_PacketList->AddPacket(Object);
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::Partition::InitFromFile(const Kumu::FileReader& Reader)
+{
+ Result_t result = KLVFilePacket::InitFromFile(Reader);
+ // test the UL
+ // could be one of several values
+ if ( ASDCP_SUCCESS(result) )
+ result = ASDCP::MXF::Partition::InitFromBuffer(m_ValueStart, m_ValueLength);
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::Partition::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ Kumu::MemIOReader MemRDR(p, l);
+ Result_t 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) )
+ DefaultLogSink().Error("Failed to initialize Partition\n");
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::Partition::WriteToFile(Kumu::FileWriter& Writer, UL& PartitionLabel)
+{
+ ASDCP::FrameBuffer Buffer;
+ Result_t result = Buffer.Capacity(1024);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ 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) )
+ {
+ ui32_t write_count;
+ result = WriteKLToFile(Writer, PartitionLabel.Value(), Buffer.Size());
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Writer.Write(Buffer.RoData(), Buffer.Size(), &write_count);
+ }
+
+ return result;
+}
+
+//
+ui32_t
+ASDCP::MXF::Partition::ArchiveSize()
+{
+ return ( kl_length
+ + sizeof(ui16_t) + sizeof(ui16_t)
+ + sizeof(ui32_t)
+ + sizeof(ui64_t) + sizeof(ui64_t) + sizeof(ui64_t) + sizeof(ui64_t) + sizeof(ui64_t)
+ + sizeof(ui32_t)
+ + sizeof(ui64_t)
+ + sizeof(ui32_t)
+ + SMPTE_UL_LENGTH
+ + sizeof(ui32_t) + sizeof(ui32_t) + ( UUIDlen * EssenceContainers.size() ) );
+}
+
+//
+void
+ASDCP::MXF::Partition::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ KLVFilePacket::Dump(stream, *m_Dict, false);
+ fprintf(stream, " MajorVersion = %hu\n", MajorVersion);
+ fprintf(stream, " MinorVersion = %hu\n", MinorVersion);
+ fprintf(stream, " KAGSize = %u\n", KAGSize);
+ 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 = %u\n", IndexSID);
+ fprintf(stream, " BodyOffset = %s\n", ui64sz(BodyOffset, identbuf));
+ fprintf(stream, " BodySID = %u\n", BodySID);
+ fprintf(stream, " OperationalPattern = %s\n", OperationalPattern.EncodeString(identbuf, IdentBufferLen));
+ fputs("Essence Containers:\n", stream); EssenceContainers.Dump(stream);
+}
+
+
+//------------------------------------------------------------------------------------------
+//
+
+class ASDCP::MXF::Primer::h__PrimerLookup : public std::map<UL, TagValue>
+{
+public:
+ void InitWithBatch(ASDCP::MXF::Batch<ASDCP::MXF::Primer::LocalTagEntry>& Batch)
+ {
+ ASDCP::MXF::Batch<ASDCP::MXF::Primer::LocalTagEntry>::iterator i = Batch.begin();
+
+ for ( ; i != Batch.end(); i++ )
+ insert(std::map<UL, TagValue>::value_type((*i).UL, (*i).Tag));
+ }
+};
+
+
+//
+ASDCP::MXF::Primer::Primer(const Dictionary*& d) : m_LocalTag(0xff), m_Dict(d) {
+ m_UL = m_Dict->ul(MDD_Primer);
+}
+
+//
+ASDCP::MXF::Primer::~Primer() {}
+
+//
+void
+ASDCP::MXF::Primer::ClearTagList()
+{
+ LocalTagEntryBatch.clear();
+ m_Lookup = new h__PrimerLookup;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::Primer::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ assert(m_Dict);
+ Result_t result = KLVPacket::InitFromBuffer(p, l, m_Dict->ul(MDD_Primer));
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ Kumu::MemIOReader MemRDR(m_ValueStart, m_ValueLength);
+ result = LocalTagEntryBatch.Unarchive(&MemRDR) ? RESULT_OK : RESULT_KLV_CODING;
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ m_Lookup = new h__PrimerLookup;
+ m_Lookup->InitWithBatch(LocalTagEntryBatch);
+ }
+
+ if ( ASDCP_FAILURE(result) )
+ DefaultLogSink().Error("Failed to initialize Primer\n");
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::Primer::WriteToFile(Kumu::FileWriter& Writer)
+{
+ ASDCP::FrameBuffer Buffer;
+ Result_t result = Buffer.Capacity(128*1024);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = WriteToBuffer(Buffer);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Writer.Write(Buffer.RoData(), Buffer.Size());
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::Primer::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ assert(m_Dict);
+ ASDCP::FrameBuffer LocalTagBuffer;
+ 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.Length();
+ result = WriteKLToBuffer(Buffer, packet_length);
+
+ if ( ASDCP_SUCCESS(result) )
+ Buffer.Size(Buffer.Size() + packet_length);
+ }
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::Primer::InsertTag(const MDDEntry& Entry, ASDCP::TagValue& Tag)
+{
+ assert(m_Lookup);
+ UL TestUL(Entry.ul);
+ std::map<UL, TagValue>::iterator i = m_Lookup->find(TestUL);
+
+ if ( i == m_Lookup->end() )
+ {
+ if ( Entry.tag.a == 0 && Entry.tag.b == 0 )
+ {
+ Tag.a = 0xff;
+ Tag.b = m_LocalTag--;
+ }
+ else
+ {
+ Tag.a = Entry.tag.a;
+ Tag.b = Entry.tag.b;
+ }
+
+ LocalTagEntry TmpEntry;
+ TmpEntry.UL = TestUL;
+ TmpEntry.Tag = Tag;
+
+ LocalTagEntryBatch.push_back(TmpEntry);
+ m_Lookup->insert(std::map<UL, TagValue>::value_type(TmpEntry.UL, TmpEntry.Tag));
+ }
+ else
+ {
+ Tag = (*i).second;
+ }
+
+ return RESULT_OK;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::Primer::TagForKey(const ASDCP::UL& Key, ASDCP::TagValue& Tag)
+{
+ assert(m_Lookup);
+ if ( m_Lookup.empty() )
+ {
+ DefaultLogSink().Error("Primer lookup is empty\n");
+ return RESULT_FAIL;
+ }
+
+ std::map<UL, TagValue>::iterator i = m_Lookup->find(Key);
+
+ if ( i == m_Lookup->end() )
+ return RESULT_FALSE;
+
+ Tag = (*i).second;
+ return RESULT_OK;
+}
+
+//
+void
+ASDCP::MXF::Primer::Dump(FILE* stream)
+{
+ assert(m_Dict);
+ char identbuf[IdentBufferLen];
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ KLVPacket::Dump(stream, *m_Dict, false);
+ fprintf(stream, "Primer: %u %s\n",
+ (ui32_t)LocalTagEntryBatch.size(),
+ ( LocalTagEntryBatch.size() == 1 ? "entry" : "entries" ));
+
+ Batch<LocalTagEntry>::iterator i = LocalTagEntryBatch.begin();
+ for ( ; i != LocalTagEntryBatch.end(); i++ )
+ {
+ const MDDEntry* Entry = m_Dict->FindUL((*i).UL.Value());
+ fprintf(stream, " %s %s\n", (*i).EncodeString(identbuf, IdentBufferLen), (Entry ? Entry->name : "Unknown"));
+ }
+}
+
+
+//------------------------------------------------------------------------------------------
+//
+
+//
+ASDCP::MXF::Preface::Preface(const Dictionary*& d) :
+ InterchangeObject(d), m_Dict(d), Version(258), ObjectModelVersion(0)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->Type(MDD_Preface).ul;
+}
+
+//
+void
+ASDCP::MXF::Preface::Copy(const Preface& rhs)
+{
+ InterchangeObject::Copy(rhs);
+
+ LastModifiedDate = rhs.LastModifiedDate;
+ Version = rhs.Version;
+ ObjectModelVersion = rhs.ObjectModelVersion;
+ PrimaryPackage = rhs.PrimaryPackage;
+ Identifications = rhs.Identifications;
+ ContentStorage = rhs.ContentStorage;
+ OperationalPattern = rhs.OperationalPattern;
+ EssenceContainers = rhs.EssenceContainers;
+ DMSchemes = rhs.DMSchemes;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::Preface::InitFromTLVSet(TLVReader& TLVSet)
+{
+ Result_t result = InterchangeObject::InitFromTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, LastModifiedDate));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi16(OBJ_READ_ARGS(Preface, Version));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(Preface, ObjectModelVersion));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, PrimaryPackage));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, Identifications));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, ContentStorage));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, OperationalPattern));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, EssenceContainers));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, DMSchemes));
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::Preface::WriteToTLVSet(TLVWriter& TLVSet)
+{
+ Result_t result = InterchangeObject::WriteToTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, LastModifiedDate));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi16(OBJ_WRITE_ARGS(Preface, Version));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(Preface, ObjectModelVersion));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, PrimaryPackage));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, Identifications));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, ContentStorage));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, OperationalPattern));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, EssenceContainers));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, DMSchemes));
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::Preface::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::Preface::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return InterchangeObject::WriteToBuffer(Buffer);
+}
+
+//
+void
+ASDCP::MXF::Preface::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ InterchangeObject::Dump(stream);
+ fprintf(stream, " %22s = %s\n", "LastModifiedDate", LastModifiedDate.EncodeString(identbuf, IdentBufferLen));
+ fprintf(stream, " %22s = %hu\n", "Version", Version);
+ fprintf(stream, " %22s = %u\n", "ObjectModelVersion", ObjectModelVersion);
+ 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.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);
+}
+
+//------------------------------------------------------------------------------------------
+//
+
+ASDCP::MXF::OPAtomHeader::OPAtomHeader(const Dictionary*& d) : Partition(d), m_Dict(d), m_RIP(d), m_Primer(d), m_Preface(0), m_HasRIP(false) {}
+ASDCP::MXF::OPAtomHeader::~OPAtomHeader() {}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::OPAtomHeader::InitFromFile(const Kumu::FileReader& Reader)
+{
+ m_HasRIP = false;
+ Result_t result = SeekToRIP(Reader);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ result = m_RIP.InitFromFile(Reader);
+ ui32_t test_s = m_RIP.PairArray.size();
+
+ if ( ASDCP_FAILURE(result) )
+ {
+ DefaultLogSink().Error("File contains no RIP\n");
+ result = RESULT_OK;
+ }
+ else if ( test_s == 0 )
+ {
+ DefaultLogSink().Error("RIP contains no Pairs.\n");
+ result = RESULT_FORMAT;
+ }
+ else
+ {
+ if ( test_s < 2 )
+ {
+ // OP-Atom states that there will be either two or three partitions:
+ // one closed header and one closed footer with an optional body
+ // SMPTE 429-5 files may have many partitions, see SMPTE 410M
+ DefaultLogSink().Warn("RIP count is less than 2: %u\n", test_s);
+ }
+
+ m_HasRIP = true;
+
+ if ( m_RIP.PairArray.front().ByteOffset != 0 )
+ {
+ DefaultLogSink().Error("First Partition in RIP is not at offset 0.\n");
+ result = RESULT_FORMAT;
+ }
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Reader.Seek(0);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Partition::InitFromFile(Reader); // test UL and OP
+
+ if ( ASDCP_FAILURE(result) )
+ return result;
+
+ // is it really OP-Atom?
+ assert(m_Dict);
+ UL OPAtomUL(SMPTE_390_OPAtom_Entry().ul);
+ UL InteropOPAtomUL(MXFInterop_OPAtom_Entry().ul);
+
+ if ( OperationalPattern.ExactMatch(OPAtomUL) ) // SMPTE
+ {
+ if ( m_Dict == &DefaultCompositeDict() )
+ m_Dict = &DefaultSMPTEDict();
+ }
+ else if ( OperationalPattern.ExactMatch(InteropOPAtomUL) ) // Interop
+ {
+ if ( m_Dict == &DefaultCompositeDict() )
+ m_Dict = &DefaultInteropDict();
+ }
+ else
+ {
+ char strbuf[IdentBufferLen];
+ const MDDEntry* Entry = m_Dict->FindUL(OperationalPattern.Value());
+ if ( Entry == 0 )
+ 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);
+ }
+
+ // slurp up the remainder of the header
+ if ( HeaderByteCount < 1024 )
+ DefaultLogSink().Warn("Improbably small HeaderByteCount value: %u\n", HeaderByteCount);
+
+ assert (HeaderByteCount <= 0xFFFFFFFFL);
+ result = m_Buffer.Capacity((ui32_t) HeaderByteCount);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ ui32_t read_count;
+ result = Reader.Read(m_Buffer.Data(), m_Buffer.Capacity(), &read_count);
+
+ if ( ASDCP_FAILURE(result) )
+ return result;
+
+ if ( read_count != m_Buffer.Capacity() )
+ {
+ DefaultLogSink().Error("Short read of OP-Atom header metadata; wanted %u, got %u\n",
+ m_Buffer.Capacity(), read_count);
+ return RESULT_KLV_CODING;
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ result = InitFromBuffer(m_Buffer.RoData(), m_Buffer.Capacity());
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::OPAtomHeader::InitFromPartitionBuffer(const byte_t* p, ui32_t l)
+{
+ Result_t result = KLVPacket::InitFromBuffer(p, l);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Partition::InitFromBuffer(m_ValueStart, m_ValueLength); // test UL and OP
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ ui32_t pp_len = KLVPacket::PacketLength();
+ result = InitFromBuffer(p + pp_len, l - pp_len);
+ }
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::OPAtomHeader::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ assert(m_Dict);
+ Result_t result = RESULT_OK;
+ const byte_t* end_p = p + l;
+
+ while ( ASDCP_SUCCESS(result) && p < end_p )
+ {
+ // parse the packets and index them by uid, discard KLVFill items
+ InterchangeObject* object = CreateObject(m_Dict, p);
+ assert(object);
+
+ object->m_Lookup = &m_Primer;
+ result = object->InitFromBuffer(p, end_p - p);
+ const byte_t* redo_p = p;
+ p += object->PacketLength();
+ // hexdump(p, object->PacketLength());
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ if ( object->IsA(m_Dict->ul(MDD_KLVFill)) )
+ {
+ delete object;
+ }
+ else if ( object->IsA(m_Dict->ul(MDD_Primer)) ) // TODO: only one primer should be found
+ {
+ delete object;
+ result = m_Primer.InitFromBuffer(redo_p, end_p - redo_p);
+ }
+ else
+ {
+ m_PacketList->AddPacket(object); // takes ownership
+
+ if ( object->IsA(m_Dict->ul(MDD_Preface)) && m_Preface == 0 )
+ m_Preface = (Preface*)object;
+ }
+ }
+ else
+ {
+ DefaultLogSink().Error("Error initializing packet\n");
+ delete object;
+ }
+ }
+
+ return result;
+}
+
+ASDCP::Result_t
+ASDCP::MXF::OPAtomHeader::GetMDObjectByID(const UUID& ObjectID, InterchangeObject** Object)
+{
+ return m_PacketList->GetMDObjectByID(ObjectID, Object);
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::OPAtomHeader::GetMDObjectByType(const byte_t* ObjectID, InterchangeObject** Object)
+{
+ InterchangeObject* TmpObject;
+
+ if ( Object == 0 )
+ Object = &TmpObject;
+
+ return m_PacketList->GetMDObjectByType(ObjectID, Object);
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::OPAtomHeader::GetMDObjectsByType(const byte_t* ObjectID, std::list<InterchangeObject*>& ObjectList)
+{
+ return m_PacketList->GetMDObjectsByType(ObjectID, ObjectList);
+}
+
+//
+ASDCP::MXF::Identification*
+ASDCP::MXF::OPAtomHeader::GetIdentification()
+{
+ InterchangeObject* Object;
+
+ if ( ASDCP_SUCCESS(GetMDObjectByType(OBJ_TYPE_ARGS(Identification), &Object)) )
+ return (Identification*)Object;
+
+ return 0;
+}
+
+//
+ASDCP::MXF::SourcePackage*
+ASDCP::MXF::OPAtomHeader::GetSourcePackage()
+{
+ InterchangeObject* Object;
+
+ if ( ASDCP_SUCCESS(GetMDObjectByType(OBJ_TYPE_ARGS(SourcePackage), &Object)) )
+ return (SourcePackage*)Object;
+
+ return 0;
+}
+
+//
+ASDCP::MXF::RIP&
+ASDCP::MXF::OPAtomHeader::GetRIP() { return m_RIP; }
+
+//
+ASDCP::Result_t
+ASDCP::MXF::OPAtomHeader::WriteToFile(Kumu::FileWriter& Writer, ui32_t HeaderSize)
+{
+ assert(m_Dict);
+ if ( m_Preface == 0 )
+ return RESULT_STATE;
+
+ if ( HeaderSize < 4096 )
+ {
+ DefaultLogSink().Error("HeaderSize %u is too small. Must be >= 4096\n", HeaderSize);
+ return RESULT_FAIL;
+ }
+
+ ASDCP::FrameBuffer HeaderBuffer;
+ HeaderByteCount = HeaderSize - ArchiveSize();
+ assert (HeaderByteCount <= 0xFFFFFFFFL);
+ Result_t result = HeaderBuffer.Capacity((ui32_t) HeaderByteCount);
+ m_Preface->m_Lookup = &m_Primer;
+
+ std::list<InterchangeObject*>::iterator pl_i = m_PacketList->m_List.begin();
+ for ( ; pl_i != m_PacketList->m_List.end() && ASDCP_SUCCESS(result); pl_i++ )
+ {
+ InterchangeObject* object = *pl_i;
+ object->m_Lookup = &m_Primer;
+
+ ASDCP::FrameBuffer WriteWrapper;
+ WriteWrapper.SetData(HeaderBuffer.Data() + HeaderBuffer.Size(),
+ HeaderBuffer.Capacity() - HeaderBuffer.Size());
+ result = object->WriteToBuffer(WriteWrapper);
+ HeaderBuffer.Size(HeaderBuffer.Size() + WriteWrapper.Size());
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ UL TmpUL(m_Dict->ul(MDD_ClosedCompleteHeader));
+ result = Partition::WriteToFile(Writer, TmpUL);
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ result = m_Primer.WriteToFile(Writer);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ ui32_t write_count;
+ Writer.Write(HeaderBuffer.RoData(), HeaderBuffer.Size(), &write_count);
+ assert(write_count == HeaderBuffer.Size());
+ }
+
+ // KLV Fill
+ if ( ASDCP_SUCCESS(result) )
+ {
+ Kumu::fpos_t pos = Writer.Tell();
+
+ if ( pos > (Kumu::fpos_t)HeaderByteCount )
+ {
+ char intbuf[IntBufferLen];
+ DefaultLogSink().Error("Header size %s exceeds specified value %u\n",
+ ui64sz(pos, intbuf),
+ HeaderSize);
+ return RESULT_FAIL;
+ }
+
+ ASDCP::FrameBuffer NilBuf;
+ ui32_t klv_fill_length = HeaderSize - (ui32_t)pos;
+
+ if ( klv_fill_length < kl_length )
+ {
+ DefaultLogSink().Error("Remaining region too small for KLV Fill header\n");
+ return RESULT_FAIL;
+ }
+
+ klv_fill_length -= kl_length;
+ result = WriteKLToFile(Writer, m_Dict->ul(MDD_KLVFill), klv_fill_length);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = NilBuf.Capacity(klv_fill_length);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ memset(NilBuf.Data(), 0, klv_fill_length);
+ ui32_t write_count;
+ Writer.Write(NilBuf.RoData(), klv_fill_length, &write_count);
+ assert(write_count == klv_fill_length);
+ }
+ }
+
+ return result;
+}
+
+//
+void
+ASDCP::MXF::OPAtomHeader::Dump(FILE* stream)
+{
+ if ( stream == 0 )
+ stream = stderr;
+
+ Partition::Dump(stream);
+ m_Primer.Dump(stream);
+
+ if ( m_Preface == 0 )
+ fputs("No Preface loaded\n", stream);
+
+ std::list<InterchangeObject*>::iterator i = m_PacketList->m_List.begin();
+ for ( ; i != m_PacketList->m_List.end(); i++ )
+ (*i)->Dump(stream);
+}
+
+//------------------------------------------------------------------------------------------
+//
+
+ASDCP::MXF::OPAtomIndexFooter::OPAtomIndexFooter(const Dictionary*& d) :
+ Partition(d),
+ m_CurrentSegment(0), m_BytesPerEditUnit(0), m_BodySID(0), m_Dict(d),
+ m_ECOffset(0), m_Lookup(0)
+{
+ BodySID = 0;
+ IndexSID = 129;
+}
+
+ASDCP::MXF::OPAtomIndexFooter::~OPAtomIndexFooter() {}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::OPAtomIndexFooter::InitFromFile(const Kumu::FileReader& Reader)
+{
+ Result_t result = Partition::InitFromFile(Reader); // test UL and OP
+
+ // slurp up the remainder of the footer
+ ui32_t read_count;
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ assert (IndexByteCount <= 0xFFFFFFFFL);
+ result = m_Buffer.Capacity((ui32_t) IndexByteCount);
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Reader.Read(m_Buffer.Data(), m_Buffer.Capacity(), &read_count);
+
+ if ( ASDCP_SUCCESS(result) && read_count != m_Buffer.Capacity() )
+ {
+ DefaultLogSink().Error("Short read of footer partition: got %u, expecting %u\n",
+ read_count, m_Buffer.Capacity());
+ return RESULT_FAIL;
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ result = InitFromBuffer(m_Buffer.RoData(), m_Buffer.Capacity());
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::OPAtomIndexFooter::InitFromPartitionBuffer(const byte_t* p, ui32_t l)
+{
+ Result_t result = KLVPacket::InitFromBuffer(p, l);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Partition::InitFromBuffer(m_ValueStart, m_ValueLength); // test UL and OP
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ ui32_t pp_len = KLVPacket::PacketLength();
+ result = InitFromBuffer(p + pp_len, l - pp_len);
+ }
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::OPAtomIndexFooter::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ Result_t result = RESULT_OK;
+ const byte_t* end_p = p + l;
+
+ while ( ASDCP_SUCCESS(result) && p < end_p )
+ {
+ // parse the packets and index them by uid, discard KLVFill items
+ InterchangeObject* object = CreateObject(m_Dict, p);
+ assert(object);
+
+ object->m_Lookup = m_Lookup;
+ result = object->InitFromBuffer(p, end_p - p);
+ p += object->PacketLength();
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ m_PacketList->AddPacket(object); // takes ownership
+ }
+ else
+ {
+ DefaultLogSink().Error("Error initializing packet\n");
+ delete object;
+ }
+ }
+
+ if ( ASDCP_FAILURE(result) )
+ DefaultLogSink().Error("Failed to initialize OPAtomIndexFooter\n");
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::OPAtomIndexFooter::WriteToFile(Kumu::FileWriter& Writer, ui64_t duration)
+{
+ assert(m_Dict);
+ ASDCP::FrameBuffer FooterBuffer;
+ ui32_t footer_size = m_PacketList->m_List.size() * MaxIndexSegmentSize; // segment-count * max-segment-size
+ Result_t result = FooterBuffer.Capacity(footer_size);
+ ui32_t iseg_count = 0;
+
+ if ( m_CurrentSegment != 0 )
+ {
+ m_CurrentSegment->IndexDuration = m_CurrentSegment->IndexEntryArray.size();
+ m_CurrentSegment = 0;
+ }
+
+ std::list<InterchangeObject*>::iterator pl_i = m_PacketList->m_List.begin();
+ for ( ; pl_i != m_PacketList->m_List.end() && ASDCP_SUCCESS(result); pl_i++ )
+ {
+ if ( (*pl_i)->IsA(OBJ_TYPE_ARGS(IndexTableSegment)) )
+ {
+ iseg_count++;
+ IndexTableSegment* Segment = (IndexTableSegment*)(*pl_i);
+
+ if ( m_BytesPerEditUnit != 0 )
+ {
+ if ( iseg_count != 1 )
+ return RESULT_STATE;
+
+ Segment->IndexDuration = duration;
+ }
+ }
+
+ InterchangeObject* object = *pl_i;
+ object->m_Lookup = m_Lookup;
+
+ ASDCP::FrameBuffer WriteWrapper;
+ WriteWrapper.SetData(FooterBuffer.Data() + FooterBuffer.Size(),
+ FooterBuffer.Capacity() - FooterBuffer.Size());
+ result = object->WriteToBuffer(WriteWrapper);
+ FooterBuffer.Size(FooterBuffer.Size() + WriteWrapper.Size());
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ IndexByteCount = FooterBuffer.Size();
+ UL FooterUL(m_Dict->ul(MDD_CompleteFooter));
+ result = Partition::WriteToFile(Writer, FooterUL);
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ ui32_t write_count = 0;
+ result = Writer.Write(FooterBuffer.RoData(), FooterBuffer.Size(), &write_count);
+ assert(write_count == FooterBuffer.Size());
+ }
+
+ return result;
+}
+
+//
+void
+ASDCP::MXF::OPAtomIndexFooter::Dump(FILE* stream)
+{
+ if ( stream == 0 )
+ stream = stderr;
+
+ Partition::Dump(stream);
+
+ std::list<InterchangeObject*>::iterator i = m_PacketList->m_List.begin();
+ for ( ; i != m_PacketList->m_List.end(); i++ )
+ (*i)->Dump(stream);
+}
+
+ASDCP::Result_t
+ASDCP::MXF::OPAtomIndexFooter::GetMDObjectByID(const UUID& ObjectID, InterchangeObject** Object)
+{
+ return m_PacketList->GetMDObjectByID(ObjectID, Object);
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::OPAtomIndexFooter::GetMDObjectByType(const byte_t* ObjectID, InterchangeObject** Object)
+{
+ InterchangeObject* TmpObject;
+
+ if ( Object == 0 )
+ Object = &TmpObject;
+
+ return m_PacketList->GetMDObjectByType(ObjectID, Object);
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::OPAtomIndexFooter::GetMDObjectsByType(const byte_t* ObjectID, std::list<InterchangeObject*>& ObjectList)
+{
+ return m_PacketList->GetMDObjectsByType(ObjectID, ObjectList);
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::OPAtomIndexFooter::Lookup(ui32_t frame_num, IndexTableSegment::IndexEntry& Entry) const
+{
+ std::list<InterchangeObject*>::iterator li;
+ for ( li = m_PacketList->m_List.begin(); li != m_PacketList->m_List.end(); li++ )
+ {
+ if ( (*li)->IsA(OBJ_TYPE_ARGS(IndexTableSegment)) )
+ {
+ IndexTableSegment* Segment = (IndexTableSegment*)(*li);
+ ui64_t start_pos = Segment->IndexStartPosition;
+
+ if ( Segment->EditUnitByteCount > 0 )
+ {
+ if ( m_PacketList->m_List.size() > 1 )
+ DefaultLogSink().Error("Unexpected multiple IndexTableSegment in CBR file\n");
+
+ if ( ! Segment->IndexEntryArray.empty() )
+ DefaultLogSink().Error("Unexpected IndexEntryArray contents in CBR file\n");
+
+ Entry.StreamOffset = (ui64_t)frame_num * Segment->EditUnitByteCount;
+ return RESULT_OK;
+ }
+ else if ( (ui64_t)frame_num >= start_pos
+ && (ui64_t)frame_num < (start_pos + Segment->IndexDuration) )
+ {
+ ui64_t tmp = frame_num - start_pos;
+ assert(tmp <= 0xFFFFFFFFL);
+ Entry = Segment->IndexEntryArray[(ui32_t) tmp];
+ return RESULT_OK;
+ }
+ }
+ }
+
+ return RESULT_FAIL;
+}
+
+//
+void
+ASDCP::MXF::OPAtomIndexFooter::SetIndexParamsCBR(IPrimerLookup* lookup, ui32_t size, const Rational& Rate)
+{
+ assert(lookup);
+ m_Lookup = lookup;
+ m_BytesPerEditUnit = size;
+ m_EditRate = Rate;
+
+ IndexTableSegment* Index = new IndexTableSegment(m_Dict);
+ AddChildObject(Index);
+ Index->EditUnitByteCount = m_BytesPerEditUnit;
+ Index->IndexEditRate = Rate;
+}
+
+//
+void
+ASDCP::MXF::OPAtomIndexFooter::SetIndexParamsVBR(IPrimerLookup* lookup, const Rational& Rate, Kumu::fpos_t offset)
+{
+ assert(lookup);
+ m_Lookup = lookup;
+ m_BytesPerEditUnit = 0;
+ m_EditRate = Rate;
+ m_ECOffset = offset;
+}
+
+//
+void
+ASDCP::MXF::OPAtomIndexFooter::PushIndexEntry(const IndexTableSegment::IndexEntry& Entry)
+{
+ if ( m_BytesPerEditUnit != 0 ) // are we CBR? that's bad
+ {
+ DefaultLogSink().Error("Call to PushIndexEntry() failed: index is CBR\n");
+ return;
+ }
+
+ // do we have an available segment?
+ if ( m_CurrentSegment == 0 )
+ { // no, set up a new segment
+ m_CurrentSegment = new IndexTableSegment(m_Dict);
+ assert(m_CurrentSegment);
+ AddChildObject(m_CurrentSegment);
+ m_CurrentSegment->DeltaEntryArray.push_back(IndexTableSegment::DeltaEntry());
+ m_CurrentSegment->IndexEditRate = m_EditRate;
+ m_CurrentSegment->IndexStartPosition = 0;
+ }
+ else if ( m_CurrentSegment->IndexEntryArray.size() >= CBRIndexEntriesPerSegment )
+ { // no, this one is full, start another
+ m_CurrentSegment->IndexDuration = m_CurrentSegment->IndexEntryArray.size();
+ ui64_t StartPosition = m_CurrentSegment->IndexStartPosition + m_CurrentSegment->IndexDuration;
+
+ m_CurrentSegment = new IndexTableSegment(m_Dict);
+ assert(m_CurrentSegment);
+ AddChildObject(m_CurrentSegment);
+ m_CurrentSegment->DeltaEntryArray.push_back(IndexTableSegment::DeltaEntry());
+ m_CurrentSegment->IndexEditRate = m_EditRate;
+ m_CurrentSegment->IndexStartPosition = StartPosition;
+ }
+
+ m_CurrentSegment->IndexEntryArray.push_back(Entry);
+}
+
+//------------------------------------------------------------------------------------------
+//
+
+//
+void
+ASDCP::MXF::InterchangeObject::Copy(const InterchangeObject& rhs)
+{
+ m_UL = rhs.m_UL;
+ InstanceUID = rhs.InstanceUID;
+ GenerationUID = rhs.GenerationUID;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::InterchangeObject::InitFromTLVSet(TLVReader& TLVSet)
+{
+ Result_t result = TLVSet.ReadObject(OBJ_READ_ARGS(InterchangeObject, InstanceUID));
+ if ( ASDCP_SUCCESS(result) )
+ result = TLVSet.ReadObject(OBJ_READ_ARGS(GenerationInterchangeObject, GenerationUID));
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::InterchangeObject::WriteToTLVSet(TLVWriter& TLVSet)
+{
+ Result_t result = TLVSet.WriteObject(OBJ_WRITE_ARGS(InterchangeObject, InstanceUID));
+ if ( ASDCP_SUCCESS(result) )
+ result = TLVSet.WriteObject(OBJ_WRITE_ARGS(GenerationInterchangeObject, GenerationUID));
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::InterchangeObject::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ ASDCP_TEST_NULL(p);
+ Result_t result = RESULT_FALSE;
+
+ if ( m_UL.HasValue() )
+ {
+ result = KLVPacket::InitFromBuffer(p, l, m_UL);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ TLVReader MemRDR(m_ValueStart, m_ValueLength, m_Lookup);
+ result = InitFromTLVSet(MemRDR);
+ }
+ }
+ else
+ {
+ result = KLVPacket::InitFromBuffer(p, l);
+ }
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::InterchangeObject::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ if ( ! m_UL.HasValue() )
+ return RESULT_STATE;
+
+ TLVWriter MemWRT(Buffer.Data() + kl_length, Buffer.Capacity() - kl_length, m_Lookup);
+ Result_t result = WriteToTLVSet(MemWRT);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ ui32_t packet_length = MemWRT.Length();
+ result = WriteKLToBuffer(Buffer, packet_length);
+
+ if ( ASDCP_SUCCESS(result) )
+ Buffer.Size(Buffer.Size() + packet_length);
+ }
+
+ return result;
+}
+
+//
+void
+ASDCP::MXF::InterchangeObject::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+
+ fputc('\n', stream);
+ KLVPacket::Dump(stream, *m_Dict, false);
+ fprintf(stream, " InstanceUID = %s\n", InstanceUID.EncodeHex(identbuf, IdentBufferLen));
+ fprintf(stream, " GenerationUID = %s\n", GenerationUID.EncodeHex(identbuf, IdentBufferLen));
+}
+
+//
+bool
+ASDCP::MXF::InterchangeObject::IsA(const byte_t* label)
+{
+ if ( m_KLLength == 0 )
+ return false;
+
+ return ( memcmp(label, m_KeyStart, SMPTE_UL_LENGTH) == 0 );
+}
+
+
+//------------------------------------------------------------------------------------------
+
+
+typedef std::map<ASDCP::UL, ASDCP::MXF::MXFObjectFactory_t>FactoryMap_t;
+typedef FactoryMap_t::iterator FLi_t;
+
+//
+class FactoryList : public FactoryMap_t
+{
+ Kumu::Mutex m_Lock;
+
+public:
+ FactoryList() {}
+ ~FactoryList() {}
+
+ bool Empty() {
+ Kumu::AutoMutex BlockLock(m_Lock);
+ return empty();
+ }
+
+ FLi_t Find(const byte_t* label) {
+ Kumu::AutoMutex BlockLock(m_Lock);
+ return find(label);
+ }
+
+ FLi_t End() {
+ Kumu::AutoMutex BlockLock(m_Lock);
+ return end();
+ }
+
+ void Insert(ASDCP::UL label, ASDCP::MXF::MXFObjectFactory_t factory) {
+ Kumu::AutoMutex BlockLock(m_Lock);
+ insert(FactoryList::value_type(label, factory));
+ }
+};
+
+//
+static FactoryList s_FactoryList;
+static Kumu::Mutex s_InitLock;
+static bool s_TypesInit = false;
+
+
+//
+void
+ASDCP::MXF::SetObjectFactory(ASDCP::UL label, ASDCP::MXF::MXFObjectFactory_t factory)
+{
+ s_FactoryList.Insert(label, factory);
+}
+
+//
+ASDCP::MXF::InterchangeObject*
+ASDCP::MXF::CreateObject(const Dictionary*& Dict, const UL& label)
+{
+ if ( ! s_TypesInit )
+ {
+ Kumu::AutoMutex BlockLock(s_InitLock);
+
+ if ( ! s_TypesInit )
+ {
+ MXF::Metadata_InitTypes(Dict);
+ s_TypesInit = true;
+ }
+ }
+
+ FLi_t i = s_FactoryList.find(label.Value());
+
+ if ( i == s_FactoryList.end() )
+ return new InterchangeObject(Dict);
+
+ return i->second(Dict);
+}
+
+
+//
+// end MXF.cpp
+//
diff --git a/asdcplib/src/MXF.h b/asdcplib/src/MXF.h
new file mode 100755
index 0000000..c170a2d
--- /dev/null
+++ b/asdcplib/src/MXF.h
@@ -0,0 +1,410 @@
+/*
+Copyright (c) 2005-2012, 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 MXF.h
+ \version $Id: MXF.h,v 1.42 2012/03/05 13:11:47 jhurst Exp $
+ \brief MXF objects
+*/
+
+#ifndef _MXF_H_
+#define _MXF_H_
+
+#include "MXFTypes.h"
+
+namespace ASDCP
+{
+ namespace MXF
+ {
+ class InterchangeObject;
+
+ //
+ typedef ASDCP::MXF::InterchangeObject* (*MXFObjectFactory_t)(const Dictionary*&);
+
+ //
+ void SetObjectFactory(UL label, MXFObjectFactory_t factory);
+
+ //
+ InterchangeObject* CreateObject(const Dictionary*& Dict, const UL& label);
+
+
+ // seek an open file handle to the start of the RIP KLV packet
+ Result_t SeekToRIP(const Kumu::FileReader&);
+
+ //
+ class RIP : public ASDCP::KLVFilePacket
+ {
+ ASDCP_NO_COPY_CONSTRUCT(RIP);
+ RIP();
+
+ public:
+ //
+ class Pair : public Kumu::IArchive
+ {
+ public:
+ ui32_t BodySID;
+ ui64_t ByteOffset;
+
+ 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* EncodeString(char* str_buf, ui32_t buf_len) const {
+ Kumu::ui64Printer offset_str(ByteOffset);
+ snprintf(str_buf, buf_len, "%-6u: %s", BodySID, offset_str.c_str());
+ return str_buf;
+ }
+
+ inline bool HasValue() const { return true; }
+ inline ui32_t ArchiveLength() const { return sizeof(ui32_t) + sizeof(ui64_t); }
+
+ inline bool Unarchive(Kumu::MemIOReader* Reader) {
+ if ( ! Reader->ReadUi32BE(&BodySID) ) return false;
+ if ( ! Reader->ReadUi64BE(&ByteOffset) ) return false;
+ return true;
+ }
+
+ inline bool Archive(Kumu::MemIOWriter* Writer) const {
+ if ( ! Writer->WriteUi32BE(BodySID) ) return false;
+ if ( ! Writer->WriteUi64BE(ByteOffset) ) return false;
+ return true;
+ }
+ };
+
+ const Dictionary*& m_Dict;
+ Array<Pair> PairArray;
+
+ RIP(const Dictionary*& d) : m_Dict(d) {}
+ virtual ~RIP() {}
+ virtual Result_t InitFromFile(const Kumu::FileReader& Reader);
+ virtual Result_t WriteToFile(Kumu::FileWriter& Writer);
+ virtual Result_t GetPairBySID(ui32_t, Pair&) const;
+ virtual void Dump(FILE* = 0);
+ };
+
+
+ //
+ class Partition : public ASDCP::KLVFilePacket
+ {
+ ASDCP_NO_COPY_CONSTRUCT(Partition);
+ Partition();
+
+ protected:
+ class h__PacketList;
+ mem_ptr<h__PacketList> m_PacketList;
+
+ public:
+ const Dictionary*& m_Dict;
+
+ ui16_t MajorVersion;
+ ui16_t MinorVersion;
+ ui32_t KAGSize;
+ ui64_t ThisPartition;
+ ui64_t PreviousPartition;
+ ui64_t FooterPartition;
+ ui64_t HeaderByteCount;
+ ui64_t IndexByteCount;
+ ui32_t IndexSID;
+ ui64_t BodyOffset;
+ ui32_t BodySID;
+ UL OperationalPattern;
+ Batch<UL> EssenceContainers;
+
+ Partition(const Dictionary*&);
+ virtual ~Partition();
+ virtual void AddChildObject(InterchangeObject*); // takes ownership
+ virtual Result_t InitFromFile(const Kumu::FileReader& Reader);
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ 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);
+ };
+
+
+ //
+ class Primer : public ASDCP::KLVFilePacket, public ASDCP::IPrimerLookup
+ {
+ class h__PrimerLookup;
+ mem_ptr<h__PrimerLookup> m_Lookup;
+ ui8_t m_LocalTag;
+ ASDCP_NO_COPY_CONSTRUCT(Primer);
+ Primer();
+
+ public:
+ //
+ class LocalTagEntry : Kumu::IArchive
+ {
+ public:
+ TagValue Tag;
+ ASDCP::UL UL;
+
+ LocalTagEntry() { Tag.a = Tag.b = 0; }
+ LocalTagEntry(const TagValue& tag, ASDCP::UL& ul) : Tag(tag), UL(ul) {}
+
+ 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 bool HasValue() const { return UL.HasValue(); }
+ inline ui32_t ArchiveLength() const { return 2 + UL.ArchiveLength(); }
+
+ 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 bool Archive(Kumu::MemIOWriter* Writer) const {
+ if ( ! Writer->WriteUi8(Tag.a) ) return false;
+ if ( ! Writer->WriteUi8(Tag.b) ) return false;
+ return UL.Archive(Writer);
+ }
+ };
+
+ Batch<LocalTagEntry> LocalTagEntryBatch;
+ const Dictionary*& m_Dict;
+
+ Primer(const Dictionary*&);
+ virtual ~Primer();
+
+ virtual void ClearTagList();
+ virtual Result_t InsertTag(const MDDEntry& Entry, ASDCP::TagValue& Tag);
+ virtual Result_t TagForKey(const ASDCP::UL& Key, ASDCP::TagValue& Tag);
+
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ virtual Result_t WriteToFile(Kumu::FileWriter& Writer);
+ virtual void Dump(FILE* = 0);
+ };
+
+
+ //
+ class InterchangeObject : public ASDCP::KLVPacket
+ {
+ InterchangeObject();
+
+ public:
+ const Dictionary*& m_Dict;
+ IPrimerLookup* m_Lookup;
+ UUID InstanceUID;
+ UUID GenerationUID;
+
+ InterchangeObject(const Dictionary*& d) : m_Dict(d), m_Lookup(0) {}
+ virtual ~InterchangeObject() {}
+
+ virtual void Copy(const InterchangeObject& rhs);
+ virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ virtual bool IsA(const byte_t* label);
+ virtual const char* ObjectName() { return "InterchangeObject"; }
+ virtual void Dump(FILE* stream = 0);
+ };
+
+ //
+ class Preface : public InterchangeObject
+ {
+ ASDCP_NO_COPY_CONSTRUCT(Preface);
+ Preface();
+
+ public:
+ const Dictionary*& m_Dict;
+ Kumu::Timestamp LastModifiedDate;
+ ui16_t Version;
+ ui32_t ObjectModelVersion;
+ UUID PrimaryPackage;
+ Batch<UUID> Identifications;
+ UUID ContentStorage;
+ UL OperationalPattern;
+ Batch<UL> EssenceContainers;
+ Batch<UL> DMSchemes;
+
+ Preface(const Dictionary*& d);
+ virtual ~Preface() {}
+
+ virtual void Copy(const Preface& rhs);
+ virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ virtual void Dump(FILE* = 0);
+ };
+
+ const ui32_t MaxIndexSegmentSize = 65536;
+
+ //
+ class IndexTableSegment : public InterchangeObject
+ {
+ ASDCP_NO_COPY_CONSTRUCT(IndexTableSegment);
+
+ public:
+ //
+ class DeltaEntry : public Kumu::IArchive
+ {
+ public:
+ i8_t PosTableIndex;
+ ui8_t Slice;
+ ui32_t ElementData;
+
+ DeltaEntry() : PosTableIndex(-1), Slice(0), ElementData(0) {}
+ DeltaEntry(i8_t pos, ui8_t slice, ui32_t data) : PosTableIndex(pos), Slice(slice), ElementData(data) {}
+ inline bool HasValue() const { return true; }
+ ui32_t ArchiveLength() const { return sizeof(ui32_t) + 2; }
+ bool Unarchive(Kumu::MemIOReader* Reader);
+ bool Archive(Kumu::MemIOWriter* Writer) const;
+ const char* EncodeString(char* str_buf, ui32_t buf_len) const;
+ };
+
+ //
+ class IndexEntry : public Kumu::IArchive
+ {
+ public:
+ i8_t TemporalOffset;
+ i8_t KeyFrameOffset;
+ ui8_t Flags;
+ ui64_t StreamOffset;
+
+ // if you use these, you will need to change CBRIndexEntriesPerSegment in MXF.cpp
+ // to a more suitable value
+ // std::list<ui32_t> SliceOffset;
+ // Array<Rational> PosTable;
+
+ IndexEntry() : TemporalOffset(0), KeyFrameOffset(0), Flags(0), StreamOffset(0) {}
+ IndexEntry(i8_t t_ofst, i8_t k_ofst, ui8_t flags, ui64_t s_ofst) :
+ TemporalOffset(t_ofst), KeyFrameOffset(k_ofst), Flags(flags), StreamOffset(s_ofst) {}
+ inline bool HasValue() const { return true; }
+ ui32_t ArchiveLength() const { return sizeof(ui64_t) + 3; };
+ bool Unarchive(Kumu::MemIOReader* Reader);
+ bool Archive(Kumu::MemIOWriter* Writer) const;
+ const char* EncodeString(char* str_buf, ui32_t buf_len) const;
+ };
+
+ const Dictionary*& m_Dict;
+
+ Rational IndexEditRate;
+ ui64_t IndexStartPosition;
+ ui64_t IndexDuration;
+ ui32_t EditUnitByteCount;
+ ui32_t IndexSID;
+ ui32_t BodySID;
+ ui8_t SliceCount;
+ ui8_t PosTableCount;
+ Batch<DeltaEntry> DeltaEntryArray;
+ Batch<IndexEntry> IndexEntryArray;
+
+ IndexTableSegment(const Dictionary*&);
+ virtual ~IndexTableSegment();
+
+ virtual void Copy(const IndexTableSegment& rhs);
+ virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ virtual void Dump(FILE* = 0);
+ };
+
+ //---------------------------------------------------------------------------------
+ //
+ class Identification;
+ class SourcePackage;
+
+ //
+ class OPAtomHeader : public Partition
+ {
+ ASDCP_NO_COPY_CONSTRUCT(OPAtomHeader);
+ OPAtomHeader();
+
+ public:
+ const Dictionary*& m_Dict;
+ ASDCP::MXF::RIP m_RIP;
+ ASDCP::MXF::Primer m_Primer;
+ Preface* m_Preface;
+ ASDCP::FrameBuffer m_Buffer;
+ bool m_HasRIP;
+
+ OPAtomHeader(const Dictionary*&);
+ virtual ~OPAtomHeader();
+ virtual Result_t InitFromFile(const Kumu::FileReader& Reader);
+ virtual Result_t InitFromPartitionBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToFile(Kumu::FileWriter& Writer, ui32_t HeaderLength = 16384);
+ virtual void Dump(FILE* = 0);
+ virtual Result_t GetMDObjectByID(const UUID&, InterchangeObject** = 0);
+ virtual Result_t GetMDObjectByType(const byte_t*, InterchangeObject** = 0);
+ virtual Result_t GetMDObjectsByType(const byte_t* ObjectID, std::list<InterchangeObject*>& ObjectList);
+ virtual ASDCP::MXF::RIP& GetRIP();
+ Identification* GetIdentification();
+ SourcePackage* GetSourcePackage();
+ };
+
+ //
+ class OPAtomIndexFooter : public Partition
+ {
+ IndexTableSegment* m_CurrentSegment;
+ ASDCP::FrameBuffer m_Buffer;
+ ui32_t m_BytesPerEditUnit;
+ Rational m_EditRate;
+ ui32_t m_BodySID;
+
+ ASDCP_NO_COPY_CONSTRUCT(OPAtomIndexFooter);
+ OPAtomIndexFooter();
+
+ public:
+ const Dictionary*& m_Dict;
+ Kumu::fpos_t m_ECOffset;
+ IPrimerLookup* m_Lookup;
+
+ OPAtomIndexFooter(const Dictionary*&);
+ virtual ~OPAtomIndexFooter();
+ virtual Result_t InitFromFile(const Kumu::FileReader& Reader);
+ virtual Result_t InitFromPartitionBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToFile(Kumu::FileWriter& Writer, ui64_t duration);
+ virtual void Dump(FILE* = 0);
+
+ virtual Result_t GetMDObjectByID(const UUID&, InterchangeObject** = 0);
+ virtual Result_t GetMDObjectByType(const byte_t*, InterchangeObject** = 0);
+ virtual Result_t GetMDObjectsByType(const byte_t* ObjectID, std::list<InterchangeObject*>& ObjectList);
+
+ 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);
+ };
+
+ } // namespace MXF
+} // namespace ASDCP
+
+
+#endif // _MXF_H_
+
+//
+// end MXF.h
+//
diff --git a/asdcplib/src/MXFTypes.cpp b/asdcplib/src/MXFTypes.cpp
new file mode 100755
index 0000000..13bdaa0
--- /dev/null
+++ b/asdcplib/src/MXFTypes.cpp
@@ -0,0 +1,682 @@
+/*
+Copyright (c) 2005-2012, 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 MXFTypes.cpp
+ \version $Id: MXFTypes.cpp,v 1.27 2012/02/21 02:09:31 jhurst Exp $
+ \brief MXF objects
+*/
+
+#include <KM_prng.h>
+#include <KM_tai.h>
+#include "MXFTypes.h"
+#include <KM_log.h>
+
+using Kumu::DefaultLogSink;
+
+//------------------------------------------------------------------------------------------
+//
+
+//
+bool
+ASDCP::UL::operator==(const UL& rhs) const
+{
+ if ( m_Value[0] == rhs.m_Value[0] &&
+ m_Value[1] == rhs.m_Value[1] &&
+ m_Value[2] == rhs.m_Value[2] &&
+ m_Value[3] == rhs.m_Value[3] &&
+ m_Value[4] == rhs.m_Value[4] &&
+ m_Value[5] == rhs.m_Value[5] &&
+ m_Value[6] == rhs.m_Value[6] &&
+ // m_Value[7] == rhs.m_Value[7] && // version is ignored when performing lookups
+ m_Value[8] == rhs.m_Value[8] &&
+ m_Value[9] == rhs.m_Value[9] &&
+ m_Value[10] == rhs.m_Value[10] &&
+ m_Value[11] == rhs.m_Value[11] &&
+ m_Value[12] == rhs.m_Value[12] &&
+ m_Value[13] == rhs.m_Value[13] &&
+ m_Value[14] == rhs.m_Value[14] &&
+ m_Value[15] == rhs.m_Value[15]
+ )
+ return true;
+
+ return false;
+}
+
+//
+bool
+ASDCP::UL::MatchIgnoreStream(const UL& rhs) const
+{
+ if ( m_Value[0] == rhs.m_Value[0] &&
+ m_Value[1] == rhs.m_Value[1] &&
+ m_Value[2] == rhs.m_Value[2] &&
+ m_Value[3] == rhs.m_Value[3] &&
+ m_Value[4] == rhs.m_Value[4] &&
+ m_Value[5] == rhs.m_Value[5] &&
+ m_Value[6] == rhs.m_Value[6] &&
+ // m_Value[7] == rhs.m_Value[7] && // version is ignored when performing lookups
+ m_Value[8] == rhs.m_Value[8] &&
+ m_Value[9] == rhs.m_Value[9] &&
+ m_Value[10] == rhs.m_Value[10] &&
+ m_Value[11] == rhs.m_Value[11] &&
+ m_Value[12] == rhs.m_Value[12] &&
+ m_Value[13] == rhs.m_Value[13] &&
+ m_Value[14] == rhs.m_Value[14]
+ // m_Value[15] == rhs.m_Value[15] // ignore stream number
+ )
+ return true;
+
+ return false;
+}
+
+//
+bool
+ASDCP::UL::ExactMatch(const UL& rhs) const
+{
+ if ( m_Value[0] == rhs.m_Value[0] &&
+ m_Value[1] == rhs.m_Value[1] &&
+ m_Value[2] == rhs.m_Value[2] &&
+ m_Value[3] == rhs.m_Value[3] &&
+ m_Value[4] == rhs.m_Value[4] &&
+ m_Value[5] == rhs.m_Value[5] &&
+ m_Value[6] == rhs.m_Value[6] &&
+ m_Value[7] == rhs.m_Value[7] &&
+ m_Value[8] == rhs.m_Value[8] &&
+ m_Value[9] == rhs.m_Value[9] &&
+ m_Value[10] == rhs.m_Value[10] &&
+ m_Value[11] == rhs.m_Value[11] &&
+ m_Value[12] == rhs.m_Value[12] &&
+ m_Value[13] == rhs.m_Value[13] &&
+ m_Value[14] == rhs.m_Value[14] &&
+ m_Value[15] == rhs.m_Value[15]
+ )
+ return true;
+
+ return false;
+}
+
+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;
+ Kumu::GenRandomValue(AssetID);
+ MakeUMID(Type, AssetID);
+}
+
+//
+void
+ASDCP::UMID::MakeUMID(int Type, const UUID& AssetID)
+{
+ // Set the non-varying base of the UMID
+ static const byte_t UMIDBase[10] = { 0x06, 0x0a, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
+ memcpy(m_Value, UMIDBase, 10);
+ m_Value[10] = Type; // Material Type
+ m_Value[12] = 0x13; // length
+
+ // preserved for compatibility with mfxlib
+ if( Type > 4 ) m_Value[7] = 5;
+ m_Value[11] = 0x20; // UUID/UL method, number gen undefined
+
+ // Instance Number
+ m_Value[13] = m_Value[14] = m_Value[15] = 0;
+
+ memcpy(&m_Value[16], AssetID.Value(), AssetID.Size());
+ m_HasValue = true;
+}
+
+
+// Write the UMID value to the given buffer in the form
+// [00000000.0000.0000.00000000],00,00,00,00,00000000.0000.0000.00000000.00000000]
+// or
+// [00000000.0000.0000.00000000],00,00,00,00,00000000-0000-0000-0000-000000000000]
+// returns 0 if the buffer is smaller than DateTimeLen
+const char*
+ASDCP::UMID::EncodeString(char* str_buf, ui32_t buf_len) const
+{
+ assert(str_buf);
+
+ 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]
+ );
+
+ ui32_t offset = strlen(str_buf);
+
+ if ( ( m_Value[8] & 0x80 ) == 0 )
+ {
+ // half-swapped UL, use [bbaa9988.ddcc.ffee.00010203.04050607]
+ 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],
+ m_Value[16], m_Value[17], m_Value[18], m_Value[19],
+ m_Value[20], m_Value[21], m_Value[22], m_Value[23]
+ );
+ }
+ else
+ {
+ // UUID, use {00112233-4455-6677-8899-aabbccddeeff}
+ 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],
+ m_Value[24], m_Value[25], m_Value[26], m_Value[27],
+ m_Value[28], m_Value[29], m_Value[30], m_Value[31]
+ );
+ }
+
+ return str_buf;
+}
+
+//------------------------------------------------------------------------------------------
+//
+
+//
+const ASDCP::MXF::UTF16String&
+ASDCP::MXF::UTF16String::operator=(const char* sz)
+{
+ if ( sz == 0 || *sz == 0 )
+ erase();
+
+ else
+ this->assign(sz);
+
+ return *this;
+}
+
+//
+const ASDCP::MXF::UTF16String&
+ASDCP::MXF::UTF16String::operator=(const std::string& str)
+{
+ this->assign(str);
+ return *this;
+}
+
+//
+const char*
+ASDCP::MXF::UTF16String::EncodeString(char* str_buf, ui32_t buf_len) const
+{
+ ui32_t write_len = Kumu::xmin(buf_len - 1, (ui32_t)size());
+ strncpy(str_buf, c_str(), write_len);
+ str_buf[write_len] = 0;
+ return str_buf;
+}
+
+//
+bool
+ASDCP::MXF::UTF16String::Unarchive(Kumu::MemIOReader* Reader)
+{
+ erase();
+ const ui16_t* p = (ui16_t*)Reader->CurrentData();
+ ui32_t length = Reader->Remainder() / 2;
+ char mb_buf[MB_LEN_MAX+1];
+
+ for ( ui32_t i = 0; i < length; i++ )
+ {
+ int count = wctomb(mb_buf, KM_i16_BE(p[i]));
+
+ if ( count == -1 )
+ {
+ DefaultLogSink().Error("Unable to decode wide character 0x%04hx\n", p[i]);
+ return false;
+ }
+
+ assert(count <= MB_LEN_MAX);
+ mb_buf[count] = 0;
+ this->append(mb_buf);
+ }
+
+ Reader->SkipOffset(length*2);
+ return true;
+}
+
+//
+bool
+ASDCP::MXF::UTF16String::Archive(Kumu::MemIOWriter* Writer) const
+{
+ if ( size() > IdentBufferLen )
+ {
+ DefaultLogSink().Error("String length exceeds maximum %u bytes\n", IdentBufferLen);
+ return false;
+ }
+
+ const char* mbp = c_str();
+ wchar_t wcp;
+ ui32_t remainder = size();
+ ui32_t length = size();
+ ui32_t i = 0;
+
+ while ( i < length )
+ {
+ int count = mbtowc(&wcp, mbp+i, remainder);
+
+ if ( count == -1 )
+ {
+ DefaultLogSink().Error("Error decoding multi-byte sequence starting at offset %u\n", i);
+ return false;
+ }
+ else if ( count == 0 )
+ break;
+
+ bool result = Writer->WriteUi16BE((ui16_t)wcp);
+
+ if ( result == false )
+ {
+ DefaultLogSink().Error("No more space in memory IO writer\n");
+ return false;
+ }
+
+ i += count;
+ remainder -= count;
+ }
+
+ return true;
+}
+
+//------------------------------------------------------------------------------------------
+//
+
+//
+const ASDCP::MXF::ISO8String&
+ASDCP::MXF::ISO8String::operator=(const char* sz)
+{
+ if ( sz == 0 || *sz == 0 )
+ erase();
+
+ else
+ this->assign(sz);
+
+ return *this;
+}
+
+//
+const ASDCP::MXF::ISO8String&
+ASDCP::MXF::ISO8String::operator=(const std::string& str)
+{
+ this->assign(str);
+ return *this;
+}
+
+//
+const char*
+ASDCP::MXF::ISO8String::EncodeString(char* str_buf, ui32_t buf_len) const
+{
+ ui32_t write_len = Kumu::xmin(buf_len - 1, (ui32_t)size());
+ strncpy(str_buf, c_str(), write_len);
+ str_buf[write_len] = 0;
+ return str_buf;
+}
+
+//
+bool
+ASDCP::MXF::ISO8String::Unarchive(Kumu::MemIOReader* Reader)
+{
+ assign((char*)Reader->CurrentData(), Reader->Remainder());
+ return true;
+}
+
+//
+bool
+ASDCP::MXF::ISO8String::Archive(Kumu::MemIOWriter* Writer) const
+{
+ if ( size() > IdentBufferLen )
+ {
+ DefaultLogSink().Error("String length exceeds maximum %u bytes\n", IdentBufferLen);
+ return false;
+ }
+
+ return Writer->WriteString(*this);
+}
+
+//------------------------------------------------------------------------------------------
+//
+
+ASDCP::MXF::TLVReader::TLVReader(const byte_t* p, ui32_t c, IPrimerLookup* PrimerLookup) :
+ MemIOReader(p, c), m_Lookup(PrimerLookup)
+{
+ Result_t result = RESULT_OK;
+
+ while ( Remainder() > 0 && ASDCP_SUCCESS(result) )
+ {
+ TagValue Tag;
+ ui16_t pkt_len = 0;
+
+ 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;
+ }
+}
+
+//
+bool
+ASDCP::MXF::TLVReader::FindTL(const MDDEntry& Entry)
+{
+ if ( m_Lookup == 0 )
+ {
+ DefaultLogSink().Error("No Lookup service\n");
+ return false;
+ }
+
+ TagValue TmpTag;
+
+ if ( m_Lookup->TagForKey(Entry.ul, TmpTag) != RESULT_OK )
+ {
+ if ( Entry.tag.a == 0 )
+ {
+ // DefaultLogSink().Debug("No such UL in this TL list: %s (%02x %02x)\n",
+ // Entry.name, Entry.tag.a, Entry.tag.b);
+ return false;
+ }
+
+ TmpTag = Entry.tag;
+ }
+
+ TagMap::iterator e_i = m_ElementMap.find(TmpTag);
+
+ if ( e_i != m_ElementMap.end() )
+ {
+ m_size = (*e_i).second.first;
+ m_capacity = m_size + (*e_i).second.second;
+ return true;
+ }
+
+ // 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, 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) ? RESULT_OK : RESULT_KLV_CODING;
+ }
+
+ return RESULT_FALSE;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::TLVReader::ReadUi8(const MDDEntry& Entry, ui8_t* value)
+{
+ ASDCP_TEST_NULL(value);
+
+ if ( FindTL(Entry) )
+ return MemIOReader::ReadUi8(value) ? RESULT_OK : RESULT_KLV_CODING;
+
+ return RESULT_FALSE;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::TLVReader::ReadUi16(const MDDEntry& Entry, ui16_t* value)
+{
+ ASDCP_TEST_NULL(value);
+
+ if ( FindTL(Entry) )
+ return MemIOReader::ReadUi16BE(value) ? RESULT_OK : RESULT_KLV_CODING;
+
+ return RESULT_FALSE;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::TLVReader::ReadUi32(const MDDEntry& Entry, ui32_t* value)
+{
+ ASDCP_TEST_NULL(value);
+
+ if ( FindTL(Entry) )
+ return MemIOReader::ReadUi32BE(value) ? RESULT_OK : RESULT_KLV_CODING;
+
+ return RESULT_FALSE;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::TLVReader::ReadUi64(const MDDEntry& Entry, ui64_t* value)
+{
+ ASDCP_TEST_NULL(value);
+
+ if ( FindTL(Entry) )
+ return MemIOReader::ReadUi64BE(value) ? RESULT_OK : RESULT_KLV_CODING;
+
+ return RESULT_FALSE;
+}
+
+//------------------------------------------------------------------------------------------
+//
+
+ASDCP::MXF::TLVWriter::TLVWriter(byte_t* p, ui32_t c, IPrimerLookup* PrimerLookup) :
+ MemIOWriter(p, c), m_Lookup(PrimerLookup)
+{
+ assert(c > 3);
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::TLVWriter::WriteTag(const MDDEntry& Entry)
+{
+ if ( m_Lookup == 0 )
+ {
+ DefaultLogSink().Error("No Primer object available\n");
+ return RESULT_FAIL;
+ }
+
+ TagValue TmpTag;
+
+ if ( m_Lookup->InsertTag(Entry, TmpTag) != RESULT_OK )
+ {
+ DefaultLogSink().Error("No tag for entry %s\n", Entry.name);
+ return RESULT_FAIL;
+ }
+
+ 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, Kumu::IArchive* Object)
+{
+ ASDCP_TEST_NULL(Object);
+
+ if ( Entry.optional && ! Object->HasValue() )
+ return RESULT_OK;
+
+ Result_t result = WriteTag(Entry);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ // write a temp length
+ byte_t* l_p = CurrentData();
+
+ if ( ! MemIOWriter::WriteUi16BE(0) ) return RESULT_KLV_CODING;
+
+ ui32_t before = Length();
+ if ( ! Object->Archive(this) ) return RESULT_KLV_CODING;
+ if ( (Length() - before) > 0xffffL ) return RESULT_KLV_CODING;
+ Kumu::i2p<ui16_t>(KM_i16_BE(Length() - before), l_p);
+ }
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::TLVWriter::WriteUi8(const MDDEntry& Entry, ui8_t* value)
+{
+ ASDCP_TEST_NULL(value);
+ Result_t result = WriteTag(Entry);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ if ( ! MemIOWriter::WriteUi16BE(sizeof(ui8_t)) ) return RESULT_KLV_CODING;
+ if ( ! MemIOWriter::WriteUi8(*value) ) return RESULT_KLV_CODING;
+ }
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::TLVWriter::WriteUi16(const MDDEntry& Entry, ui16_t* value)
+{
+ ASDCP_TEST_NULL(value);
+ Result_t result = WriteTag(Entry);
+
+ if ( KM_SUCCESS(result) )
+ {
+ if ( ! MemIOWriter::WriteUi16BE(sizeof(ui16_t)) ) return RESULT_KLV_CODING;
+ if ( ! MemIOWriter::WriteUi16BE(*value) ) return RESULT_KLV_CODING;
+ }
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::TLVWriter::WriteUi32(const MDDEntry& Entry, ui32_t* value)
+{
+ ASDCP_TEST_NULL(value);
+ Result_t result = WriteTag(Entry);
+
+ if ( KM_SUCCESS(result) )
+ {
+ if ( ! MemIOWriter::WriteUi16BE(sizeof(ui32_t)) ) return RESULT_KLV_CODING;
+ if ( ! MemIOWriter::WriteUi32BE(*value) ) return RESULT_KLV_CODING;
+ }
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::TLVWriter::WriteUi64(const MDDEntry& Entry, ui64_t* value)
+{
+ ASDCP_TEST_NULL(value);
+ Result_t result = WriteTag(Entry);
+
+ if ( KM_SUCCESS(result) )
+ {
+ if ( ! MemIOWriter::WriteUi16BE(sizeof(ui64_t)) ) return RESULT_KLV_CODING;
+ if ( ! MemIOWriter::WriteUi64BE(*value) ) return RESULT_KLV_CODING;
+ }
+
+ return result;
+}
+
+
+//----------------------------------------------------------------------------------------------------
+//
+
+ASDCP::MXF::Raw::Raw()
+{
+ Capacity(256);
+}
+
+ASDCP::MXF::Raw::~Raw()
+{
+}
+
+//
+bool
+ASDCP::MXF::Raw::Unarchive(Kumu::MemIOReader* Reader)
+{
+ ui32_t payload_size = Reader->Remainder();
+ if ( payload_size == 0 ) return false;
+ if ( KM_FAILURE(Capacity(payload_size)) ) return false;
+
+ memcpy(Data(), Reader->CurrentData(), payload_size);
+ Length(payload_size);
+ return true;
+}
+
+//
+bool
+ASDCP::MXF::Raw::Archive(Kumu::MemIOWriter* Writer) const
+{
+ return Writer->WriteRaw(RoData(), Length());
+}
+
+//
+const char*
+ASDCP::MXF::Raw::EncodeString(char* str_buf, ui32_t buf_len) const
+{
+ *str_buf = 0;
+ Kumu::bin2hex(RoData(), Length(), str_buf, buf_len);
+ return str_buf;
+}
+
+//
+// end MXFTypes.cpp
+//
diff --git a/asdcplib/src/MXFTypes.h b/asdcplib/src/MXFTypes.h
new file mode 100755
index 0000000..4ab6772
--- /dev/null
+++ b/asdcplib/src/MXFTypes.h
@@ -0,0 +1,409 @@
+/*
+Copyright (c) 2005-2012, 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 MXFTypes.h
+ \version $Id: MXFTypes.h,v 1.29 2012/02/21 02:09:31 jhurst Exp $
+ \brief MXF objects
+*/
+
+#ifndef _MXFTYPES_H_
+#define _MXFTYPES_H_
+
+#include "KLV.h"
+#include <list>
+#include <vector>
+#include <map>
+#include <wchar.h>
+
+// used with TLVReader::Read*
+//
+// these are used below to manufacture arguments
+#define OBJ_READ_ARGS(s,l) m_Dict->Type(MDD_##s##_##l), &l
+#define OBJ_WRITE_ARGS(s,l) m_Dict->Type(MDD_##s##_##l), &l
+#define OBJ_TYPE_ARGS(t) m_Dict->Type(MDD_##t).ul
+
+
+namespace ASDCP
+{
+ namespace MXF
+ {
+ typedef std::pair<ui32_t, ui32_t> ItemInfo;
+ typedef std::map<TagValue, ItemInfo> TagMap;
+
+ //
+ class TLVReader : public Kumu::MemIOReader
+ {
+
+ TagMap m_ElementMap;
+ IPrimerLookup* m_Lookup;
+
+ TLVReader();
+ ASDCP_NO_COPY_CONSTRUCT(TLVReader);
+ bool FindTL(const MDDEntry&);
+
+ public:
+ TLVReader(const byte_t* p, ui32_t c, IPrimerLookup* = 0);
+ 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*);
+ Result_t ReadUi64(const MDDEntry&, ui64_t*);
+ };
+
+ //
+ class TLVWriter : public Kumu::MemIOWriter
+ {
+
+ TagMap m_ElementMap;
+ IPrimerLookup* m_Lookup;
+
+ TLVWriter();
+ ASDCP_NO_COPY_CONSTRUCT(TLVWriter);
+ Result_t WriteTag(const MDDEntry&);
+
+ public:
+ TLVWriter(byte_t* p, ui32_t c, IPrimerLookup* = 0);
+ 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*);
+ Result_t WriteUi64(const MDDEntry&, ui64_t*);
+ };
+
+ //
+ template <class T>
+ class Batch : public std::vector<T>, public Kumu::IArchive
+ {
+ public:
+ Batch() {}
+ ~Batch() {}
+
+ //
+ virtual bool Unarchive(Kumu::MemIOReader* Reader) {
+ ui32_t ItemCount, ItemSize;
+ if ( ! Reader->ReadUi32BE(&ItemCount) ) return false;
+ if ( ! Reader->ReadUi32BE(&ItemSize) ) return false;
+
+ if ( ( ItemCount > 65536 ) || ( ItemSize > 1024 ) )
+ return false;
+
+ bool result = true;
+ for ( ui32_t i = 0; i < ItemCount && result; i++ )
+ {
+ T Tmp;
+ result = Tmp.Unarchive(Reader);
+
+ if ( result )
+ this->push_back(Tmp);
+ }
+
+ return result;
+ }
+
+ inline virtual bool HasValue() const { return ! this->empty(); }
+
+ virtual ui32_t ArchiveLength() const {
+ ui32_t arch_size = sizeof(ui32_t)*2;
+
+ typename std::vector<T>::const_iterator l_i = this->begin();
+ assert(l_i != this->end());
+
+ for ( ; l_i != this->end(); l_i++ )
+ arch_size += l_i->ArchiveLength();
+
+ return arch_size;
+ }
+
+ //
+ virtual bool Archive(Kumu::MemIOWriter* Writer) const {
+ if ( ! Writer->WriteUi32BE(this->size()) ) return false;
+ byte_t* p = Writer->CurrentData();
+
+ 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();
+ if ( ! (*l_i).Archive(Writer) ) return false;
+ ItemSize -= Writer->Remainder();
+ Kumu::i2p<ui32_t>(KM_i32_BE(ItemSize), p);
+ l_i++;
+
+ bool result = true;
+ for ( ; l_i != this->end() && result; l_i++ )
+ result = (*l_i).Archive(Writer);
+
+ return result;
+ }
+
+ //
+ void Dump(FILE* stream = 0, ui32_t = 0)
+ {
+ char identbuf[IdentBufferLen];
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ typename std::vector<T>::iterator i = this->begin();
+ for ( ; i != this->end(); i++ )
+ fprintf(stream, " %s\n", (*i).EncodeString(identbuf, IdentBufferLen));
+ }
+ };
+
+ //
+ template <class T>
+ class Array : public std::list<T>, public Kumu::IArchive
+ {
+ public:
+ Array() {}
+ ~Array() {}
+
+ //
+ virtual bool Unarchive(Kumu::MemIOReader* Reader)
+ {
+ bool result = true;
+
+ while ( Reader->Remainder() > 0 && result )
+ {
+ T Tmp;
+ result = Tmp.Unarchive(Reader);
+ this->push_back(Tmp);
+ }
+
+ return result;
+ }
+
+ inline virtual bool HasValue() const { return ! this->empty(); }
+
+ virtual ui32_t ArchiveLength() const {
+ ui32_t arch_size = 0;
+
+ typename std::list<T>::const_iterator l_i = this->begin();
+
+ for ( ; l_i != this->end(); l_i++ )
+ arch_size += l_i->ArchiveLength();
+
+ return arch_size;
+ }
+
+ //
+ 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() && result; l_i++ )
+ result = (*l_i).Archive(Writer);
+
+ return result;
+ }
+
+ //
+ void Dump(FILE* stream = 0, ui32_t = 0)
+ {
+ char identbuf[IdentBufferLen];
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ typename std::list<T>::iterator i = this->begin();
+ for ( ; i != this->end(); i++ )
+ fprintf(stream, " %s\n", (*i).EncodeString(identbuf, IdentBufferLen));
+ }
+ };
+
+ //
+ class ISO8String : public std::string, public Kumu::IArchive
+ {
+ public:
+ ISO8String() {}
+ ~ISO8String() {}
+
+ const ISO8String& operator=(const char*);
+ const ISO8String& operator=(const std::string&);
+
+ const char* EncodeString(char* str_buf, ui32_t buf_len) const;
+ inline virtual bool HasValue() const { return ! empty(); }
+ inline virtual ui32_t ArchiveLength() const { return sizeof(ui32_t) + size(); }
+ virtual bool Unarchive(Kumu::MemIOReader* Reader);
+ virtual bool Archive(Kumu::MemIOWriter* Writer) const;
+ };
+
+ //
+ class UTF16String : public std::string, public Kumu::IArchive
+ {
+ public:
+ UTF16String() {}
+ ~UTF16String() {}
+
+ const UTF16String& operator=(const char*);
+ const UTF16String& operator=(const std::string&);
+
+ const char* EncodeString(char* str_buf, ui32_t buf_len) const;
+ inline virtual bool HasValue() const { return ! empty(); }
+ inline virtual ui32_t ArchiveLength() const { return sizeof(ui32_t) + size(); }
+ virtual bool Unarchive(Kumu::MemIOReader* Reader);
+ virtual bool Archive(Kumu::MemIOWriter* Writer) const;
+ };
+
+ //
+ class Rational : public ASDCP::Rational, public Kumu::IArchive
+ {
+ public:
+ Rational() {}
+ ~Rational() {}
+
+ Rational(const Rational& rhs) : ASDCP::Rational(), IArchive() {
+ Numerator = rhs.Numerator;
+ Denominator = rhs.Denominator;
+ }
+
+ const Rational& operator=(const Rational& rhs) {
+ Numerator = rhs.Numerator;
+ Denominator = rhs.Denominator;
+ return *this;
+ }
+
+ Rational(const ASDCP::Rational& rhs) {
+ Numerator = rhs.Numerator;
+ Denominator = rhs.Denominator;
+ }
+
+ const Rational& operator=(const ASDCP::Rational& rhs) {
+ Numerator = rhs.Numerator;
+ Denominator = rhs.Denominator;
+ return *this;
+ }
+
+ //
+ inline const char* EncodeString(char* str_buf, ui32_t buf_len) const {
+ snprintf(str_buf, buf_len, "%d/%d", Numerator, Denominator);
+ return str_buf;
+ }
+
+ 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 virtual bool HasValue() const { return true; }
+ inline virtual ui32_t ArchiveLength() const { return sizeof(ui32_t)*2; }
+
+ 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 Kumu::IArchive
+ {
+ public:
+ enum Release_t { RL_UNKNOWN, RL_RELEASE, RL_DEVELOPMENT, RL_PATCHED, RL_BETA, RL_PRIVATE };
+ ui16_t Major;
+ ui16_t Minor;
+ ui16_t Patch;
+ ui16_t Build;
+ Release_t Release;
+
+ VersionType() : Major(0), Minor(0), Patch(0), Build(0), Release(RL_UNKNOWN) {}
+ VersionType(const VersionType& rhs) { Copy(rhs); }
+ virtual ~VersionType() {}
+
+ const VersionType& operator=(const VersionType& rhs) { Copy(rhs); return *this; }
+ void Copy(const VersionType& rhs) {
+ Major = rhs.Major;
+ Minor = rhs.Minor;
+ Patch = rhs.Patch;
+ Build = rhs.Build;
+ Release = rhs.Release;
+ }
+
+ void Dump(FILE* = 0);
+
+ 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;
+ }
+
+ 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 virtual bool HasValue() const { return true; }
+ inline virtual ui32_t ArchiveLength() const { return sizeof(ui16_t)*5; }
+
+ 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 Kumu::ByteString
+ {
+ public:
+ Raw();
+ Raw(const Raw& rhs) : Kumu::ByteString () { Copy(rhs); }
+ virtual ~Raw();
+
+ const Raw& operator=(const Raw& rhs) { Copy(rhs); return *this; }
+ void Copy(const Raw& rhs) {
+ if ( KM_SUCCESS(Capacity(rhs.Length())) )
+ {
+ Set(rhs);
+ }
+ }
+
+ //
+ virtual bool Unarchive(Kumu::MemIOReader* Reader);
+ virtual bool Archive(Kumu::MemIOWriter* Writer) const;
+ const char* EncodeString(char* str_buf, ui32_t buf_len) const;
+ };
+
+ } // namespace MXF
+} // namespace ASDCP
+
+
+#endif //_MXFTYPES_H_
+
+//
+// end MXFTypes.h
+//
diff --git a/asdcplib/src/Makefile.am b/asdcplib/src/Makefile.am
new file mode 100644
index 0000000..85c1e9f
--- /dev/null
+++ b/asdcplib/src/Makefile.am
@@ -0,0 +1,249 @@
+## Makefile.am -- Process this file with automake to produce Makefile.in
+#
+# $Id: Makefile.am,v 1.53 2012/02/05 21:30:18 jhurst Exp $
+# Copyright (c) 2007-2011 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.
+
+# Allow for configure's changes to this makefile
+AM_CPPFLAGS =
+AM_LDFLAGS =
+
+if OPENBSD_HOST
+AM_CPPFLAGS += -I/var/local/include -I/usr/local/include
+AM_LDFLAGS += -L./.libs -L/var/local/lib -L/usr/local/lib
+endif
+
+if ENABLE_RANDOM_UUID
+AM_CPPFLAGS += -DCONFIG_RANDOM_UUID
+endif
+
+# list of all the header files that should be installed
+include_HEADERS = KM_error.h KM_fileio.h KM_log.h KM_memio.h KM_mutex.h \
+ KM_platform.h KM_prng.h KM_util.h KM_tai.h KM_xml.h AS_DCP.h
+if DEV_HEADERS
+include_HEADERS += S12MTimecode.h MDD.h Metadata.h KLV.h MXFTypes.h MXF.h Wav.h \
+ PCMParserList.h
+nodist_include_HEADERS = TimedText_Transform.h
+endif
+
+# list of the libraries to build and install
+lib_LTLIBRARIES = libkumu.la libasdcp.la
+# sources for a library
+libkumu_la_SOURCES = KM_error.h KM_fileio.cpp KM_fileio.h KM_log.cpp KM_log.h \
+ KM_memio.h KM_mutex.h KM_platform.h KM_prng.cpp KM_prng.h KM_util.cpp \
+ KM_util.h KM_xml.cpp KM_xml.h KM_tai.h KM_tai.cpp
+
+# linker flags (*not* including libraries to link against) for a library
+libkumu_la_LDFLAGS = -release @VERSION@
+
+# sources for a library that don't get added to a distribution
+nodist_libasdcp_la_SOURCES = Metadata_h.tt2 Metadata_cpp.tt2 \
+ mxfgen.pl MXF_def.pl ullist.pl ULList.xml dict.xml DMS_Crypto.xml
+
+libasdcp_la_SOURCES = MPEG2_Parser.cpp MPEG.cpp JP2K_Codestream_Parser.cpp \
+ JP2K_Sequence_Parser.cpp JP2K.cpp PCM_Parser.cpp Wav.cpp \
+ TimedText_Parser.cpp KLV.cpp Dict.cpp MXFTypes.cpp MXF.cpp \
+ Index.cpp Metadata.cpp AS_DCP.cpp AS_DCP_MXF.cpp AS_DCP_AES.cpp \
+ h__Reader.cpp h__Writer.cpp AS_DCP_MPEG2.cpp AS_DCP_JP2K.cpp \
+ AS_DCP_PCM.cpp AS_DCP_TimedText.cpp PCMParserList.cpp \
+ Wav.h WavFileWriter.h MXF.h Metadata.h \
+ JP2K.h AS_DCP.h AS_DCP_internal.h KLV.h MPEG.h MXFTypes.h MDD.h \
+ PCMParserList.h S12MTimecode.h MDD.cpp
+
+if DEV_HEADERS
+nodist_libasdcp_la_SOURCES += TimedText_Transform.h TimedText_Transform.cpp
+endif
+
+libasdcp_la_LDFLAGS = -release @VERSION@
+
+# additional libraries to link against for a library
+libasdcp_la_LIBADD = libkumu.la
+libasdcp_la_CPPFLAGS = -DASDCP_PLATFORM=\"@host@\"
+
+# Python extension
+if PYTHON_USE
+lib_LTLIBRARIES += libpyasdcp.la
+#### libnapali.la
+
+nodist_libpyasdcp_la_SOURCES = \
+ kumu_python.cpp \
+ kumu_python.h \
+ asdcp_python.cpp \
+ asdcp_python.h \
+ asdcp_python_descriptor.cpp \
+ asdcp_python_misc.cpp \
+ asdcp_python_writerinfo.h \
+ asdcp_wrappers.h \
+ asdcp_python_mxf.cpp \
+ asdcp_python_mxf_text.cpp \
+ asdcp_python_mxf_metadata.cpp
+
+####nodist_libnapali_la_SOURCES = \
+#### napali_python.cpp napali_python.h
+
+libpyasdcp_la_CPPFLAGS = @PYTHON_CPPFLAGS@
+libpyasdcp_la_LDFLAGS = @PYTHON_LSPEC@ -release @VERSION@
+libpyasdcp_la_LIBADD = libkumu.la libasdcp.la
+
+####libnapali_la_CPPFLAGS = @PYTHON_CPPFLAGS@
+####libnapali_la_LDFLAGS = @PYTHON_LSPEC@ -release @VERSION@
+####libnapali_la_LIBADD = libkumu.la libasdcp.la
+
+pyexecdir = @PYTHON_EXECDIR@
+pyexec_includedir = $(PYTHON_PREFIX)/include/python$(PYTHON_SHORTVERSION)
+nodist_pyexec_include_HEADERS = kumu_python.h asdcp_python.h asdcp_wrappers.h
+pyexec_LTLIBRARIES = kumu.la asdcp.la
+#### napali_python.h napali.la
+
+nodist_kumu_la_SOURCES = pykumu.cpp kumu_python.h
+kumu_la_CPPFLAGS = @PYTHON_CPPFLAGS@
+kumu_la_LDFLAGS = @PYTHON_LSPEC@ -avoid-version -module
+kumu_la_LIBADD = libpyasdcp.la
+
+nodist_asdcp_la_SOURCES = pyasdcp.cpp kumu_python.h asdcp_python.h asdcp_wrappers.h
+asdcp_la_CPPFLAGS = @PYTHON_CPPFLAGS@
+asdcp_la_LDFLAGS = @PYTHON_LSPEC@ -avoid-version -module
+asdcp_la_LIBADD = libpyasdcp.la
+
+####nodist_napali_la_SOURCES = pynapali.cpp kumu_python.h napali_python.h
+####napali_la_CPPFLAGS = @PYTHON_CPPFLAGS@
+####napali_la_LDFLAGS = @PYTHON_LSPEC@ -avoid-version -module
+####napali_la_LIBADD = libnapali.la libpyasdcp.la
+endif
+
+# list of programs to be built and installed
+bin_PROGRAMS = \
+ asdcp-wrap asdcp-unwrap asdcp-util asdcp-info asdcp-test \
+ j2c-test blackwave klvwalk wavesplit \
+ kmfilegen kmrandgen kmuuidgen
+
+# sources and linkage for CLI utilities
+asdcp_test_SOURCES = asdcp-test.cpp
+asdcp_test_LDADD = libasdcp.la
+
+asdcp_wrap_SOURCES = asdcp-wrap.cpp
+asdcp_wrap_LDADD = libasdcp.la
+
+asdcp_unwrap_SOURCES = asdcp-unwrap.cpp
+asdcp_unwrap_LDADD = libasdcp.la
+
+asdcp_util_SOURCES = asdcp-util.cpp
+asdcp_util_LDADD = libasdcp.la
+
+asdcp_info_SOURCES = asdcp-info.cpp
+asdcp_info_LDADD = libasdcp.la
+
+kmfilegen_SOURCES = kmfilegen.cpp
+kmfilegen_LDADD = libkumu.la
+
+kmrandgen_SOURCES = kmrandgen.cpp
+kmrandgen_LDADD = libkumu.la
+
+kmuuidgen_SOURCES = kmuuidgen.cpp
+kmuuidgen_LDADD = libkumu.la
+
+blackwave_SOURCES = blackwave.cpp
+blackwave_LDADD = libasdcp.la
+
+klvwalk_SOURCES = klvwalk.cpp
+klvwalk_LDADD = libasdcp.la
+
+wavesplit_SOURCES = wavesplit.cpp
+wavesplit_LDADD = libasdcp.la
+
+j2c_test_SOURCES = j2c-test.cpp
+j2c_test_LDADD = libasdcp.la
+
+# list of programs that need to be compiled for use in test suite
+check_PROGRAMS = asdcp-mem-test path-test \
+ fips-186-rng-test asdcp-version
+if DEV_HEADERS
+check_PROGRAMS += tt-xform
+endif
+
+# sources for a test program
+# list of libraries to link against for a test program
+asdcp_mem_test_SOURCES = asdcp-mem-test.cpp
+asdcp_mem_test_LDADD = libasdcp.la
+
+path_test_SOURCES = path-test.cpp
+path_test_LDADD = libkumu.la
+
+fips_186_rng_test_SOURCES = fips-186-rng-test.cpp
+fips_186_rng_test_LDADD = libasdcp.la
+
+asdcp_version_SOURCES = asdcp-version.cpp
+asdcp_version_LDADD = libkumu.la
+
+if DEV_HEADERS
+nodist_tt_xform_SOURCES = tt-xform.cpp
+tt_xform_LDADD = libasdcp.la
+endif
+
+
+# list of test scripts to execute during "make check"
+TESTS = rng-tst.sh gen-tst.sh \
+ jp2k-tst.sh jp2k-crypt-tst.sh jp2k-stereo-tst.sh jp2k-stereo-crypt-tst.sh \
+ wav-tst.sh wav-crypt-tst.sh mpeg-tst.sh mpeg-crypt-tst.sh
+
+# environment variables to pass to above tests
+TESTS_ENVIRONMENT = BUILD_DIR="." TEST_FILES=../tests TEST_FILE_PREFIX=DCPd1-M1 \
+ CRYPT_KEY=70e0de21c98fbd455ad5b8042edb41a6 CRYPT_KEY_B=aa2d05475d568cd52cb3415e65cba76f \
+ JP2K_PREFIX=MM_2k_XYZ_
+
+# files to include in the distribution that automake doesn't automatically include
+EXTRA_DIST = fips-186-test-harness.pl $(TESTS)
+if !FREEDIST
+if DEV_HEADERS
+EXTRA_DIST += $(nodist_libasdcp_la_SOURCES) $(nodist_tt_xform_SOURCES)
+#### $(nodist_napali_la_SOURCES) $(nodist_libnapali_la_SOURCES)
+endif
+if PYTHON_USE
+EXTRA_DIST += $(nodist_pyexec_include_HEADERS) $(nodist_libpyasdcp_la_SOURCES) $(nodist_kumu_la_SOURCES) $(nodist_asdcp_la_SOURCES)
+#### $(nodist_napali_la_SOURCES) $(nodist_libnapali_la_SOURCES)
+endif
+endif
+
+# source files that are themselves built
+BUILT_SOURCES = Metadata.h Metadata.cpp MDD.h MDD.cpp
+# files to be removed with "make maintainer-clean"
+MAINTAINERCLEANFILES = Metadata.h Metadata.cpp MDD.h MDD.cpp
+
+# build commands for built sources
+# dependencies: $(srcdir)/ullist.pl $(srcdir)/ULList.xml $(srcdir)/dict.xml $(srcdir)/DMS_Crypto.xml
+MDD.h:
+ $(srcdir)/ullist.pl $(srcdir)/ULList.xml $(srcdir)/dict.xml $(srcdir)/DMS_Crypto.xml > MDD.h
+# dependencies: $(srcdir)/ullist.pl $(srcdir)/ULList.xml $(srcdir)/dict.xml $(srcdir)/DMS_Crypto.xml
+MDD.cpp:
+ $(srcdir)/ullist.pl -s $(srcdir)/ULList.xml $(srcdir)/dict.xml $(srcdir)/DMS_Crypto.xml > MDD.cpp
+# dependencies: $(srcdir)/Metadata_h.tt2 $(srcdir)/mxfgen.pl $(srcdir)/MXF_def.pl
+Metadata.h:
+ $(srcdir)/mxfgen.pl $(srcdir)/MXF_def.pl $(srcdir)/Metadata_h.tt2 > Metadata.h
+# dependencies: Metadata.h $(srcdir)/Metadata_cpp.tt2
+Metadata.cpp:
+ $(srcdir)/mxfgen.pl $(srcdir)/MXF_def.pl $(srcdir)/Metadata_cpp.tt2 > Metadata.cpp
+
+#
+#
+#
diff --git a/asdcplib/src/Makefile.in b/asdcplib/src/Makefile.in
new file mode 100644
index 0000000..f086f49
--- /dev/null
+++ b/asdcplib/src/Makefile.in
@@ -0,0 +1,1516 @@
+# Makefile.in generated by automake 1.11.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#
+# $Id: Makefile.am,v 1.53 2012/02/05 21:30:18 jhurst Exp $
+# Copyright (c) 2007-2011 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.
+
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@OPENBSD_HOST_TRUE@am__append_1 = -I/var/local/include -I/usr/local/include
+@OPENBSD_HOST_TRUE@am__append_2 = -L./.libs -L/var/local/lib -L/usr/local/lib
+@ENABLE_RANDOM_UUID_TRUE@am__append_3 = -DCONFIG_RANDOM_UUID
+@DEV_HEADERS_TRUE@am__append_4 = S12MTimecode.h MDD.h Metadata.h KLV.h MXFTypes.h MXF.h Wav.h \
+@DEV_HEADERS_TRUE@ PCMParserList.h
+
+@DEV_HEADERS_TRUE@am__append_5 = TimedText_Transform.h TimedText_Transform.cpp
+
+# Python extension
+@PYTHON_USE_TRUE@am__append_6 = libpyasdcp.la
+bin_PROGRAMS = asdcp-wrap$(EXEEXT) asdcp-unwrap$(EXEEXT) \
+ asdcp-util$(EXEEXT) asdcp-info$(EXEEXT) asdcp-test$(EXEEXT) \
+ j2c-test$(EXEEXT) blackwave$(EXEEXT) klvwalk$(EXEEXT) \
+ wavesplit$(EXEEXT) kmfilegen$(EXEEXT) kmrandgen$(EXEEXT) \
+ kmuuidgen$(EXEEXT)
+check_PROGRAMS = asdcp-mem-test$(EXEEXT) path-test$(EXEEXT) \
+ fips-186-rng-test$(EXEEXT) asdcp-version$(EXEEXT) \
+ $(am__EXEEXT_1)
+@DEV_HEADERS_TRUE@am__append_7 = tt-xform
+@DEV_HEADERS_TRUE@@FREEDIST_FALSE@am__append_8 = $(nodist_libasdcp_la_SOURCES) $(nodist_tt_xform_SOURCES)
+#### $(nodist_napali_la_SOURCES) $(nodist_libnapali_la_SOURCES)
+@FREEDIST_FALSE@@PYTHON_USE_TRUE@am__append_9 = $(nodist_pyexec_include_HEADERS) $(nodist_libpyasdcp_la_SOURCES) $(nodist_kumu_la_SOURCES) $(nodist_asdcp_la_SOURCES)
+subdir = src
+DIST_COMMON = $(am__include_HEADERS_DIST) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_expat.m4 \
+ $(top_srcdir)/m4/ax_lib_openssl.m4 \
+ $(top_srcdir)/m4/ax_lib_xerces.m4 \
+ $(top_srcdir)/m4/az_python.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pyexecdir)" \
+ "$(DESTDIR)$(bindir)" "$(DESTDIR)$(includedir)" \
+ "$(DESTDIR)$(includedir)" "$(DESTDIR)$(pyexec_includedir)"
+LTLIBRARIES = $(lib_LTLIBRARIES) $(pyexec_LTLIBRARIES)
+@PYTHON_USE_TRUE@asdcp_la_DEPENDENCIES = libpyasdcp.la
+@PYTHON_USE_TRUE@nodist_asdcp_la_OBJECTS = asdcp_la-pyasdcp.lo
+asdcp_la_OBJECTS = $(nodist_asdcp_la_OBJECTS)
+asdcp_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(asdcp_la_LDFLAGS) $(LDFLAGS) -o $@
+@PYTHON_USE_TRUE@am_asdcp_la_rpath = -rpath $(pyexecdir)
+@PYTHON_USE_TRUE@kumu_la_DEPENDENCIES = libpyasdcp.la
+@PYTHON_USE_TRUE@nodist_kumu_la_OBJECTS = kumu_la-pykumu.lo
+kumu_la_OBJECTS = $(nodist_kumu_la_OBJECTS)
+kumu_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(kumu_la_LDFLAGS) $(LDFLAGS) -o $@
+@PYTHON_USE_TRUE@am_kumu_la_rpath = -rpath $(pyexecdir)
+libasdcp_la_DEPENDENCIES = libkumu.la
+am_libasdcp_la_OBJECTS = libasdcp_la-MPEG2_Parser.lo \
+ libasdcp_la-MPEG.lo libasdcp_la-JP2K_Codestream_Parser.lo \
+ libasdcp_la-JP2K_Sequence_Parser.lo libasdcp_la-JP2K.lo \
+ libasdcp_la-PCM_Parser.lo libasdcp_la-Wav.lo \
+ libasdcp_la-TimedText_Parser.lo libasdcp_la-KLV.lo \
+ libasdcp_la-Dict.lo libasdcp_la-MXFTypes.lo libasdcp_la-MXF.lo \
+ libasdcp_la-Index.lo libasdcp_la-Metadata.lo \
+ libasdcp_la-AS_DCP.lo libasdcp_la-AS_DCP_MXF.lo \
+ libasdcp_la-AS_DCP_AES.lo libasdcp_la-h__Reader.lo \
+ libasdcp_la-h__Writer.lo libasdcp_la-AS_DCP_MPEG2.lo \
+ libasdcp_la-AS_DCP_JP2K.lo libasdcp_la-AS_DCP_PCM.lo \
+ libasdcp_la-AS_DCP_TimedText.lo libasdcp_la-PCMParserList.lo \
+ libasdcp_la-MDD.lo
+@DEV_HEADERS_TRUE@am__objects_1 = libasdcp_la-TimedText_Transform.lo
+nodist_libasdcp_la_OBJECTS = $(am__objects_1)
+libasdcp_la_OBJECTS = $(am_libasdcp_la_OBJECTS) \
+ $(nodist_libasdcp_la_OBJECTS)
+libasdcp_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(libasdcp_la_LDFLAGS) $(LDFLAGS) -o $@
+libkumu_la_LIBADD =
+am_libkumu_la_OBJECTS = KM_fileio.lo KM_log.lo KM_prng.lo KM_util.lo \
+ KM_xml.lo KM_tai.lo
+libkumu_la_OBJECTS = $(am_libkumu_la_OBJECTS)
+libkumu_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(libkumu_la_LDFLAGS) $(LDFLAGS) -o $@
+@PYTHON_USE_TRUE@libpyasdcp_la_DEPENDENCIES = libkumu.la libasdcp.la
+@PYTHON_USE_TRUE@nodist_libpyasdcp_la_OBJECTS = \
+@PYTHON_USE_TRUE@ libpyasdcp_la-kumu_python.lo \
+@PYTHON_USE_TRUE@ libpyasdcp_la-asdcp_python.lo \
+@PYTHON_USE_TRUE@ libpyasdcp_la-asdcp_python_descriptor.lo \
+@PYTHON_USE_TRUE@ libpyasdcp_la-asdcp_python_misc.lo \
+@PYTHON_USE_TRUE@ libpyasdcp_la-asdcp_python_mxf.lo \
+@PYTHON_USE_TRUE@ libpyasdcp_la-asdcp_python_mxf_text.lo \
+@PYTHON_USE_TRUE@ libpyasdcp_la-asdcp_python_mxf_metadata.lo
+libpyasdcp_la_OBJECTS = $(nodist_libpyasdcp_la_OBJECTS)
+libpyasdcp_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(libpyasdcp_la_LDFLAGS) $(LDFLAGS) -o $@
+@PYTHON_USE_TRUE@am_libpyasdcp_la_rpath = -rpath $(libdir)
+@DEV_HEADERS_TRUE@am__EXEEXT_1 = tt-xform$(EXEEXT)
+PROGRAMS = $(bin_PROGRAMS)
+am_asdcp_info_OBJECTS = asdcp-info.$(OBJEXT)
+asdcp_info_OBJECTS = $(am_asdcp_info_OBJECTS)
+asdcp_info_DEPENDENCIES = libasdcp.la
+am_asdcp_mem_test_OBJECTS = asdcp-mem-test.$(OBJEXT)
+asdcp_mem_test_OBJECTS = $(am_asdcp_mem_test_OBJECTS)
+asdcp_mem_test_DEPENDENCIES = libasdcp.la
+am_asdcp_test_OBJECTS = asdcp-test.$(OBJEXT)
+asdcp_test_OBJECTS = $(am_asdcp_test_OBJECTS)
+asdcp_test_DEPENDENCIES = libasdcp.la
+am_asdcp_unwrap_OBJECTS = asdcp-unwrap.$(OBJEXT)
+asdcp_unwrap_OBJECTS = $(am_asdcp_unwrap_OBJECTS)
+asdcp_unwrap_DEPENDENCIES = libasdcp.la
+am_asdcp_util_OBJECTS = asdcp-util.$(OBJEXT)
+asdcp_util_OBJECTS = $(am_asdcp_util_OBJECTS)
+asdcp_util_DEPENDENCIES = libasdcp.la
+am_asdcp_version_OBJECTS = asdcp-version.$(OBJEXT)
+asdcp_version_OBJECTS = $(am_asdcp_version_OBJECTS)
+asdcp_version_DEPENDENCIES = libkumu.la
+am_asdcp_wrap_OBJECTS = asdcp-wrap.$(OBJEXT)
+asdcp_wrap_OBJECTS = $(am_asdcp_wrap_OBJECTS)
+asdcp_wrap_DEPENDENCIES = libasdcp.la
+am_blackwave_OBJECTS = blackwave.$(OBJEXT)
+blackwave_OBJECTS = $(am_blackwave_OBJECTS)
+blackwave_DEPENDENCIES = libasdcp.la
+am_fips_186_rng_test_OBJECTS = fips-186-rng-test.$(OBJEXT)
+fips_186_rng_test_OBJECTS = $(am_fips_186_rng_test_OBJECTS)
+fips_186_rng_test_DEPENDENCIES = libasdcp.la
+am_j2c_test_OBJECTS = j2c-test.$(OBJEXT)
+j2c_test_OBJECTS = $(am_j2c_test_OBJECTS)
+j2c_test_DEPENDENCIES = libasdcp.la
+am_klvwalk_OBJECTS = klvwalk.$(OBJEXT)
+klvwalk_OBJECTS = $(am_klvwalk_OBJECTS)
+klvwalk_DEPENDENCIES = libasdcp.la
+am_kmfilegen_OBJECTS = kmfilegen.$(OBJEXT)
+kmfilegen_OBJECTS = $(am_kmfilegen_OBJECTS)
+kmfilegen_DEPENDENCIES = libkumu.la
+am_kmrandgen_OBJECTS = kmrandgen.$(OBJEXT)
+kmrandgen_OBJECTS = $(am_kmrandgen_OBJECTS)
+kmrandgen_DEPENDENCIES = libkumu.la
+am_kmuuidgen_OBJECTS = kmuuidgen.$(OBJEXT)
+kmuuidgen_OBJECTS = $(am_kmuuidgen_OBJECTS)
+kmuuidgen_DEPENDENCIES = libkumu.la
+am_path_test_OBJECTS = path-test.$(OBJEXT)
+path_test_OBJECTS = $(am_path_test_OBJECTS)
+path_test_DEPENDENCIES = libkumu.la
+@DEV_HEADERS_TRUE@nodist_tt_xform_OBJECTS = tt-xform.$(OBJEXT)
+tt_xform_OBJECTS = $(nodist_tt_xform_OBJECTS)
+@DEV_HEADERS_TRUE@tt_xform_DEPENDENCIES = libasdcp.la
+am_wavesplit_OBJECTS = wavesplit.$(OBJEXT)
+wavesplit_OBJECTS = $(am_wavesplit_OBJECTS)
+wavesplit_DEPENDENCIES = libasdcp.la
+DEFAULT_INCLUDES = -I.@am__isrc@
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+SOURCES = $(nodist_asdcp_la_SOURCES) $(nodist_kumu_la_SOURCES) \
+ $(libasdcp_la_SOURCES) $(nodist_libasdcp_la_SOURCES) \
+ $(libkumu_la_SOURCES) $(nodist_libpyasdcp_la_SOURCES) \
+ $(asdcp_info_SOURCES) $(asdcp_mem_test_SOURCES) \
+ $(asdcp_test_SOURCES) $(asdcp_unwrap_SOURCES) \
+ $(asdcp_util_SOURCES) $(asdcp_version_SOURCES) \
+ $(asdcp_wrap_SOURCES) $(blackwave_SOURCES) \
+ $(fips_186_rng_test_SOURCES) $(j2c_test_SOURCES) \
+ $(klvwalk_SOURCES) $(kmfilegen_SOURCES) $(kmrandgen_SOURCES) \
+ $(kmuuidgen_SOURCES) $(path_test_SOURCES) \
+ $(nodist_tt_xform_SOURCES) $(wavesplit_SOURCES)
+DIST_SOURCES = $(libasdcp_la_SOURCES) $(libkumu_la_SOURCES) \
+ $(asdcp_info_SOURCES) $(asdcp_mem_test_SOURCES) \
+ $(asdcp_test_SOURCES) $(asdcp_unwrap_SOURCES) \
+ $(asdcp_util_SOURCES) $(asdcp_version_SOURCES) \
+ $(asdcp_wrap_SOURCES) $(blackwave_SOURCES) \
+ $(fips_186_rng_test_SOURCES) $(j2c_test_SOURCES) \
+ $(klvwalk_SOURCES) $(kmfilegen_SOURCES) $(kmrandgen_SOURCES) \
+ $(kmuuidgen_SOURCES) $(path_test_SOURCES) $(wavesplit_SOURCES)
+am__include_HEADERS_DIST = KM_error.h KM_fileio.h KM_log.h KM_memio.h \
+ KM_mutex.h KM_platform.h KM_prng.h KM_util.h KM_tai.h KM_xml.h \
+ AS_DCP.h S12MTimecode.h MDD.h Metadata.h KLV.h MXFTypes.h \
+ MXF.h Wav.h PCMParserList.h
+HEADERS = $(include_HEADERS) $(nodist_include_HEADERS) \
+ $(nodist_pyexec_include_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+am__tty_colors = \
+red=; grn=; lgn=; blu=; std=
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXPAT_CFLAGS = @EXPAT_CFLAGS@
+EXPAT_LDFLAGS = @EXPAT_LDFLAGS@
+EXPAT_VERSION = @EXPAT_VERSION@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENSSL_CPPFLAGS = @OPENSSL_CPPFLAGS@
+OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@
+OPENSSL_LIBS = @OPENSSL_LIBS@
+OPENSSL_VERSION = @OPENSSL_VERSION@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PYTHON = @PYTHON@
+PYTHON_CPPFLAGS = @PYTHON_CPPFLAGS@
+PYTHON_CSPEC = @PYTHON_CSPEC@
+PYTHON_EXECDIR = @PYTHON_EXECDIR@
+PYTHON_EXECPREFIX = @PYTHON_EXECPREFIX@
+PYTHON_LDFLAGS = @PYTHON_LDFLAGS@
+PYTHON_LSPEC = @PYTHON_LSPEC@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_SHORTVERSION = @PYTHON_SHORTVERSION@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XERCES_CPPFLAGS = @XERCES_CPPFLAGS@
+XERCES_LDFLAGS = @XERCES_LDFLAGS@
+XERCES_LIBS = @XERCES_LIBS@
+XERCES_VERSION = @XERCES_VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+
+# Allow for configure's changes to this makefile
+AM_CPPFLAGS = $(am__append_1) $(am__append_3)
+AM_LDFLAGS = $(am__append_2)
+
+# list of all the header files that should be installed
+include_HEADERS = KM_error.h KM_fileio.h KM_log.h KM_memio.h \
+ KM_mutex.h KM_platform.h KM_prng.h KM_util.h KM_tai.h KM_xml.h \
+ AS_DCP.h $(am__append_4)
+@DEV_HEADERS_TRUE@nodist_include_HEADERS = TimedText_Transform.h
+
+# list of the libraries to build and install
+lib_LTLIBRARIES = libkumu.la libasdcp.la $(am__append_6)
+# sources for a library
+libkumu_la_SOURCES = KM_error.h KM_fileio.cpp KM_fileio.h KM_log.cpp KM_log.h \
+ KM_memio.h KM_mutex.h KM_platform.h KM_prng.cpp KM_prng.h KM_util.cpp \
+ KM_util.h KM_xml.cpp KM_xml.h KM_tai.h KM_tai.cpp
+
+
+# linker flags (*not* including libraries to link against) for a library
+libkumu_la_LDFLAGS = -release @VERSION@
+
+# sources for a library that don't get added to a distribution
+nodist_libasdcp_la_SOURCES = Metadata_h.tt2 Metadata_cpp.tt2 mxfgen.pl \
+ MXF_def.pl ullist.pl ULList.xml dict.xml DMS_Crypto.xml \
+ $(am__append_5)
+libasdcp_la_SOURCES = MPEG2_Parser.cpp MPEG.cpp JP2K_Codestream_Parser.cpp \
+ JP2K_Sequence_Parser.cpp JP2K.cpp PCM_Parser.cpp Wav.cpp \
+ TimedText_Parser.cpp KLV.cpp Dict.cpp MXFTypes.cpp MXF.cpp \
+ Index.cpp Metadata.cpp AS_DCP.cpp AS_DCP_MXF.cpp AS_DCP_AES.cpp \
+ h__Reader.cpp h__Writer.cpp AS_DCP_MPEG2.cpp AS_DCP_JP2K.cpp \
+ AS_DCP_PCM.cpp AS_DCP_TimedText.cpp PCMParserList.cpp \
+ Wav.h WavFileWriter.h MXF.h Metadata.h \
+ JP2K.h AS_DCP.h AS_DCP_internal.h KLV.h MPEG.h MXFTypes.h MDD.h \
+ PCMParserList.h S12MTimecode.h MDD.cpp
+
+libasdcp_la_LDFLAGS = -release @VERSION@
+
+# additional libraries to link against for a library
+libasdcp_la_LIBADD = libkumu.la
+libasdcp_la_CPPFLAGS = -DASDCP_PLATFORM=\"@host@\"
+#### libnapali.la
+@PYTHON_USE_TRUE@nodist_libpyasdcp_la_SOURCES = \
+@PYTHON_USE_TRUE@ kumu_python.cpp \
+@PYTHON_USE_TRUE@ kumu_python.h \
+@PYTHON_USE_TRUE@ asdcp_python.cpp \
+@PYTHON_USE_TRUE@ asdcp_python.h \
+@PYTHON_USE_TRUE@ asdcp_python_descriptor.cpp \
+@PYTHON_USE_TRUE@ asdcp_python_misc.cpp \
+@PYTHON_USE_TRUE@ asdcp_python_writerinfo.h \
+@PYTHON_USE_TRUE@ asdcp_wrappers.h \
+@PYTHON_USE_TRUE@ asdcp_python_mxf.cpp \
+@PYTHON_USE_TRUE@ asdcp_python_mxf_text.cpp \
+@PYTHON_USE_TRUE@ asdcp_python_mxf_metadata.cpp
+
+
+####nodist_libnapali_la_SOURCES = \
+#### napali_python.cpp napali_python.h
+@PYTHON_USE_TRUE@libpyasdcp_la_CPPFLAGS = @PYTHON_CPPFLAGS@
+@PYTHON_USE_TRUE@libpyasdcp_la_LDFLAGS = @PYTHON_LSPEC@ -release @VERSION@
+@PYTHON_USE_TRUE@libpyasdcp_la_LIBADD = libkumu.la libasdcp.la
+
+####libnapali_la_CPPFLAGS = @PYTHON_CPPFLAGS@
+####libnapali_la_LDFLAGS = @PYTHON_LSPEC@ -release @VERSION@
+####libnapali_la_LIBADD = libkumu.la libasdcp.la
+@PYTHON_USE_TRUE@pyexecdir = @PYTHON_EXECDIR@
+@PYTHON_USE_TRUE@pyexec_includedir = $(PYTHON_PREFIX)/include/python$(PYTHON_SHORTVERSION)
+@PYTHON_USE_TRUE@nodist_pyexec_include_HEADERS = kumu_python.h asdcp_python.h asdcp_wrappers.h
+@PYTHON_USE_TRUE@pyexec_LTLIBRARIES = kumu.la asdcp.la
+#### napali_python.h napali.la
+@PYTHON_USE_TRUE@nodist_kumu_la_SOURCES = pykumu.cpp kumu_python.h
+@PYTHON_USE_TRUE@kumu_la_CPPFLAGS = @PYTHON_CPPFLAGS@
+@PYTHON_USE_TRUE@kumu_la_LDFLAGS = @PYTHON_LSPEC@ -avoid-version -module
+@PYTHON_USE_TRUE@kumu_la_LIBADD = libpyasdcp.la
+@PYTHON_USE_TRUE@nodist_asdcp_la_SOURCES = pyasdcp.cpp kumu_python.h asdcp_python.h asdcp_wrappers.h
+@PYTHON_USE_TRUE@asdcp_la_CPPFLAGS = @PYTHON_CPPFLAGS@
+@PYTHON_USE_TRUE@asdcp_la_LDFLAGS = @PYTHON_LSPEC@ -avoid-version -module
+@PYTHON_USE_TRUE@asdcp_la_LIBADD = libpyasdcp.la
+
+# sources and linkage for CLI utilities
+asdcp_test_SOURCES = asdcp-test.cpp
+asdcp_test_LDADD = libasdcp.la
+asdcp_wrap_SOURCES = asdcp-wrap.cpp
+asdcp_wrap_LDADD = libasdcp.la
+asdcp_unwrap_SOURCES = asdcp-unwrap.cpp
+asdcp_unwrap_LDADD = libasdcp.la
+asdcp_util_SOURCES = asdcp-util.cpp
+asdcp_util_LDADD = libasdcp.la
+asdcp_info_SOURCES = asdcp-info.cpp
+asdcp_info_LDADD = libasdcp.la
+kmfilegen_SOURCES = kmfilegen.cpp
+kmfilegen_LDADD = libkumu.la
+kmrandgen_SOURCES = kmrandgen.cpp
+kmrandgen_LDADD = libkumu.la
+kmuuidgen_SOURCES = kmuuidgen.cpp
+kmuuidgen_LDADD = libkumu.la
+blackwave_SOURCES = blackwave.cpp
+blackwave_LDADD = libasdcp.la
+klvwalk_SOURCES = klvwalk.cpp
+klvwalk_LDADD = libasdcp.la
+wavesplit_SOURCES = wavesplit.cpp
+wavesplit_LDADD = libasdcp.la
+j2c_test_SOURCES = j2c-test.cpp
+j2c_test_LDADD = libasdcp.la
+
+# sources for a test program
+# list of libraries to link against for a test program
+asdcp_mem_test_SOURCES = asdcp-mem-test.cpp
+asdcp_mem_test_LDADD = libasdcp.la
+path_test_SOURCES = path-test.cpp
+path_test_LDADD = libkumu.la
+fips_186_rng_test_SOURCES = fips-186-rng-test.cpp
+fips_186_rng_test_LDADD = libasdcp.la
+asdcp_version_SOURCES = asdcp-version.cpp
+asdcp_version_LDADD = libkumu.la
+@DEV_HEADERS_TRUE@nodist_tt_xform_SOURCES = tt-xform.cpp
+@DEV_HEADERS_TRUE@tt_xform_LDADD = libasdcp.la
+
+# list of test scripts to execute during "make check"
+TESTS = rng-tst.sh gen-tst.sh \
+ jp2k-tst.sh jp2k-crypt-tst.sh jp2k-stereo-tst.sh jp2k-stereo-crypt-tst.sh \
+ wav-tst.sh wav-crypt-tst.sh mpeg-tst.sh mpeg-crypt-tst.sh
+
+
+# environment variables to pass to above tests
+TESTS_ENVIRONMENT = BUILD_DIR="." TEST_FILES=../tests TEST_FILE_PREFIX=DCPd1-M1 \
+ CRYPT_KEY=70e0de21c98fbd455ad5b8042edb41a6 CRYPT_KEY_B=aa2d05475d568cd52cb3415e65cba76f \
+ JP2K_PREFIX=MM_2k_XYZ_
+
+
+# files to include in the distribution that automake doesn't automatically include
+EXTRA_DIST = fips-186-test-harness.pl $(TESTS) $(am__append_8) \
+ $(am__append_9)
+#### $(nodist_napali_la_SOURCES) $(nodist_libnapali_la_SOURCES)
+
+# source files that are themselves built
+BUILT_SOURCES = Metadata.h Metadata.cpp MDD.h MDD.cpp
+# files to be removed with "make maintainer-clean"
+MAINTAINERCLEANFILES = Metadata.h Metadata.cpp MDD.h MDD.cpp
+all: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .cpp .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)"
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+ }
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+install-pyexecLTLIBRARIES: $(pyexec_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(pyexecdir)" || $(MKDIR_P) "$(DESTDIR)$(pyexecdir)"
+ @list='$(pyexec_LTLIBRARIES)'; test -n "$(pyexecdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pyexecdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pyexecdir)"; \
+ }
+
+uninstall-pyexecLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pyexec_LTLIBRARIES)'; test -n "$(pyexecdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pyexecdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pyexecdir)/$$f"; \
+ done
+
+clean-pyexecLTLIBRARIES:
+ -test -z "$(pyexec_LTLIBRARIES)" || rm -f $(pyexec_LTLIBRARIES)
+ @list='$(pyexec_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+asdcp.la: $(asdcp_la_OBJECTS) $(asdcp_la_DEPENDENCIES) $(EXTRA_asdcp_la_DEPENDENCIES)
+ $(asdcp_la_LINK) $(am_asdcp_la_rpath) $(asdcp_la_OBJECTS) $(asdcp_la_LIBADD) $(LIBS)
+kumu.la: $(kumu_la_OBJECTS) $(kumu_la_DEPENDENCIES) $(EXTRA_kumu_la_DEPENDENCIES)
+ $(kumu_la_LINK) $(am_kumu_la_rpath) $(kumu_la_OBJECTS) $(kumu_la_LIBADD) $(LIBS)
+libasdcp.la: $(libasdcp_la_OBJECTS) $(libasdcp_la_DEPENDENCIES) $(EXTRA_libasdcp_la_DEPENDENCIES)
+ $(libasdcp_la_LINK) -rpath $(libdir) $(libasdcp_la_OBJECTS) $(libasdcp_la_LIBADD) $(LIBS)
+libkumu.la: $(libkumu_la_OBJECTS) $(libkumu_la_DEPENDENCIES) $(EXTRA_libkumu_la_DEPENDENCIES)
+ $(libkumu_la_LINK) -rpath $(libdir) $(libkumu_la_OBJECTS) $(libkumu_la_LIBADD) $(LIBS)
+libpyasdcp.la: $(libpyasdcp_la_OBJECTS) $(libpyasdcp_la_DEPENDENCIES) $(EXTRA_libpyasdcp_la_DEPENDENCIES)
+ $(libpyasdcp_la_LINK) $(am_libpyasdcp_la_rpath) $(libpyasdcp_la_OBJECTS) $(libpyasdcp_la_LIBADD) $(LIBS)
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p || test -f $$p1; \
+ then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(bindir)" && rm -f $$files
+
+clean-binPROGRAMS:
+ @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+clean-checkPROGRAMS:
+ @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+asdcp-info$(EXEEXT): $(asdcp_info_OBJECTS) $(asdcp_info_DEPENDENCIES) $(EXTRA_asdcp_info_DEPENDENCIES)
+ @rm -f asdcp-info$(EXEEXT)
+ $(CXXLINK) $(asdcp_info_OBJECTS) $(asdcp_info_LDADD) $(LIBS)
+asdcp-mem-test$(EXEEXT): $(asdcp_mem_test_OBJECTS) $(asdcp_mem_test_DEPENDENCIES) $(EXTRA_asdcp_mem_test_DEPENDENCIES)
+ @rm -f asdcp-mem-test$(EXEEXT)
+ $(CXXLINK) $(asdcp_mem_test_OBJECTS) $(asdcp_mem_test_LDADD) $(LIBS)
+asdcp-test$(EXEEXT): $(asdcp_test_OBJECTS) $(asdcp_test_DEPENDENCIES) $(EXTRA_asdcp_test_DEPENDENCIES)
+ @rm -f asdcp-test$(EXEEXT)
+ $(CXXLINK) $(asdcp_test_OBJECTS) $(asdcp_test_LDADD) $(LIBS)
+asdcp-unwrap$(EXEEXT): $(asdcp_unwrap_OBJECTS) $(asdcp_unwrap_DEPENDENCIES) $(EXTRA_asdcp_unwrap_DEPENDENCIES)
+ @rm -f asdcp-unwrap$(EXEEXT)
+ $(CXXLINK) $(asdcp_unwrap_OBJECTS) $(asdcp_unwrap_LDADD) $(LIBS)
+asdcp-util$(EXEEXT): $(asdcp_util_OBJECTS) $(asdcp_util_DEPENDENCIES) $(EXTRA_asdcp_util_DEPENDENCIES)
+ @rm -f asdcp-util$(EXEEXT)
+ $(CXXLINK) $(asdcp_util_OBJECTS) $(asdcp_util_LDADD) $(LIBS)
+asdcp-version$(EXEEXT): $(asdcp_version_OBJECTS) $(asdcp_version_DEPENDENCIES) $(EXTRA_asdcp_version_DEPENDENCIES)
+ @rm -f asdcp-version$(EXEEXT)
+ $(CXXLINK) $(asdcp_version_OBJECTS) $(asdcp_version_LDADD) $(LIBS)
+asdcp-wrap$(EXEEXT): $(asdcp_wrap_OBJECTS) $(asdcp_wrap_DEPENDENCIES) $(EXTRA_asdcp_wrap_DEPENDENCIES)
+ @rm -f asdcp-wrap$(EXEEXT)
+ $(CXXLINK) $(asdcp_wrap_OBJECTS) $(asdcp_wrap_LDADD) $(LIBS)
+blackwave$(EXEEXT): $(blackwave_OBJECTS) $(blackwave_DEPENDENCIES) $(EXTRA_blackwave_DEPENDENCIES)
+ @rm -f blackwave$(EXEEXT)
+ $(CXXLINK) $(blackwave_OBJECTS) $(blackwave_LDADD) $(LIBS)
+fips-186-rng-test$(EXEEXT): $(fips_186_rng_test_OBJECTS) $(fips_186_rng_test_DEPENDENCIES) $(EXTRA_fips_186_rng_test_DEPENDENCIES)
+ @rm -f fips-186-rng-test$(EXEEXT)
+ $(CXXLINK) $(fips_186_rng_test_OBJECTS) $(fips_186_rng_test_LDADD) $(LIBS)
+j2c-test$(EXEEXT): $(j2c_test_OBJECTS) $(j2c_test_DEPENDENCIES) $(EXTRA_j2c_test_DEPENDENCIES)
+ @rm -f j2c-test$(EXEEXT)
+ $(CXXLINK) $(j2c_test_OBJECTS) $(j2c_test_LDADD) $(LIBS)
+klvwalk$(EXEEXT): $(klvwalk_OBJECTS) $(klvwalk_DEPENDENCIES) $(EXTRA_klvwalk_DEPENDENCIES)
+ @rm -f klvwalk$(EXEEXT)
+ $(CXXLINK) $(klvwalk_OBJECTS) $(klvwalk_LDADD) $(LIBS)
+kmfilegen$(EXEEXT): $(kmfilegen_OBJECTS) $(kmfilegen_DEPENDENCIES) $(EXTRA_kmfilegen_DEPENDENCIES)
+ @rm -f kmfilegen$(EXEEXT)
+ $(CXXLINK) $(kmfilegen_OBJECTS) $(kmfilegen_LDADD) $(LIBS)
+kmrandgen$(EXEEXT): $(kmrandgen_OBJECTS) $(kmrandgen_DEPENDENCIES) $(EXTRA_kmrandgen_DEPENDENCIES)
+ @rm -f kmrandgen$(EXEEXT)
+ $(CXXLINK) $(kmrandgen_OBJECTS) $(kmrandgen_LDADD) $(LIBS)
+kmuuidgen$(EXEEXT): $(kmuuidgen_OBJECTS) $(kmuuidgen_DEPENDENCIES) $(EXTRA_kmuuidgen_DEPENDENCIES)
+ @rm -f kmuuidgen$(EXEEXT)
+ $(CXXLINK) $(kmuuidgen_OBJECTS) $(kmuuidgen_LDADD) $(LIBS)
+path-test$(EXEEXT): $(path_test_OBJECTS) $(path_test_DEPENDENCIES) $(EXTRA_path_test_DEPENDENCIES)
+ @rm -f path-test$(EXEEXT)
+ $(CXXLINK) $(path_test_OBJECTS) $(path_test_LDADD) $(LIBS)
+tt-xform$(EXEEXT): $(tt_xform_OBJECTS) $(tt_xform_DEPENDENCIES) $(EXTRA_tt_xform_DEPENDENCIES)
+ @rm -f tt-xform$(EXEEXT)
+ $(CXXLINK) $(tt_xform_OBJECTS) $(tt_xform_LDADD) $(LIBS)
+wavesplit$(EXEEXT): $(wavesplit_OBJECTS) $(wavesplit_DEPENDENCIES) $(EXTRA_wavesplit_DEPENDENCIES)
+ @rm -f wavesplit$(EXEEXT)
+ $(CXXLINK) $(wavesplit_OBJECTS) $(wavesplit_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/KM_fileio.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/KM_log.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/KM_prng.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/KM_tai.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/KM_util.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/KM_xml.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asdcp-info.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asdcp-mem-test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asdcp-test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asdcp-unwrap.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asdcp-util.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asdcp-version.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asdcp-wrap.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asdcp_la-pyasdcp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blackwave.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fips-186-rng-test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/j2c-test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/klvwalk.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kmfilegen.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kmrandgen.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kmuuidgen.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kumu_la-pykumu.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-AS_DCP.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-AS_DCP_AES.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-AS_DCP_JP2K.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-AS_DCP_MPEG2.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-AS_DCP_MXF.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-AS_DCP_PCM.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-AS_DCP_TimedText.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-Dict.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-Index.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-JP2K.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-JP2K_Codestream_Parser.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-JP2K_Sequence_Parser.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-KLV.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-MDD.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-MPEG.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-MPEG2_Parser.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-MXF.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-MXFTypes.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-Metadata.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-PCMParserList.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-PCM_Parser.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-TimedText_Parser.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-TimedText_Transform.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-Wav.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-h__Reader.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-h__Writer.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpyasdcp_la-asdcp_python.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpyasdcp_la-asdcp_python_descriptor.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpyasdcp_la-asdcp_python_misc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpyasdcp_la-asdcp_python_mxf.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpyasdcp_la-asdcp_python_mxf_metadata.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpyasdcp_la-asdcp_python_mxf_text.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpyasdcp_la-kumu_python.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/path-test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tt-xform.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wavesplit.Po@am__quote@
+
+.cpp.o:
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $<
+
+.cpp.obj:
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cpp.lo:
+@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $<
+
+asdcp_la-pyasdcp.lo: pyasdcp.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(asdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT asdcp_la-pyasdcp.lo -MD -MP -MF $(DEPDIR)/asdcp_la-pyasdcp.Tpo -c -o asdcp_la-pyasdcp.lo `test -f 'pyasdcp.cpp' || echo '$(srcdir)/'`pyasdcp.cpp
+@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/asdcp_la-pyasdcp.Tpo $(DEPDIR)/asdcp_la-pyasdcp.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='pyasdcp.cpp' object='asdcp_la-pyasdcp.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(asdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o asdcp_la-pyasdcp.lo `test -f 'pyasdcp.cpp' || echo '$(srcdir)/'`pyasdcp.cpp
+
+kumu_la-pykumu.lo: pykumu.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(kumu_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT kumu_la-pykumu.lo -MD -MP -MF $(DEPDIR)/kumu_la-pykumu.Tpo -c -o kumu_la-pykumu.lo `test -f 'pykumu.cpp' || echo '$(srcdir)/'`pykumu.cpp
+@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/kumu_la-pykumu.Tpo $(DEPDIR)/kumu_la-pykumu.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='pykumu.cpp' object='kumu_la-pykumu.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(kumu_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o kumu_la-pykumu.lo `test -f 'pykumu.cpp' || echo '$(srcdir)/'`pykumu.cpp
+
+libasdcp_la-MPEG2_Parser.lo: MPEG2_Parser.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-MPEG2_Parser.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-MPEG2_Parser.Tpo -c -o libasdcp_la-MPEG2_Parser.lo `test -f 'MPEG2_Parser.cpp' || echo '$(srcdir)/'`MPEG2_Parser.cpp
+@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-MPEG2_Parser.Tpo $(DEPDIR)/libasdcp_la-MPEG2_Parser.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='MPEG2_Parser.cpp' object='libasdcp_la-MPEG2_Parser.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-MPEG2_Parser.lo `test -f 'MPEG2_Parser.cpp' || echo '$(srcdir)/'`MPEG2_Parser.cpp
+
+libasdcp_la-MPEG.lo: MPEG.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-MPEG.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-MPEG.Tpo -c -o libasdcp_la-MPEG.lo `test -f 'MPEG.cpp' || echo '$(srcdir)/'`MPEG.cpp
+@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-MPEG.Tpo $(DEPDIR)/libasdcp_la-MPEG.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='MPEG.cpp' object='libasdcp_la-MPEG.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-MPEG.lo `test -f 'MPEG.cpp' || echo '$(srcdir)/'`MPEG.cpp
+
+libasdcp_la-JP2K_Codestream_Parser.lo: JP2K_Codestream_Parser.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-JP2K_Codestream_Parser.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-JP2K_Codestream_Parser.Tpo -c -o libasdcp_la-JP2K_Codestream_Parser.lo `test -f 'JP2K_Codestream_Parser.cpp' || echo '$(srcdir)/'`JP2K_Codestream_Parser.cpp
+@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-JP2K_Codestream_Parser.Tpo $(DEPDIR)/libasdcp_la-JP2K_Codestream_Parser.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='JP2K_Codestream_Parser.cpp' object='libasdcp_la-JP2K_Codestream_Parser.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-JP2K_Codestream_Parser.lo `test -f 'JP2K_Codestream_Parser.cpp' || echo '$(srcdir)/'`JP2K_Codestream_Parser.cpp
+
+libasdcp_la-JP2K_Sequence_Parser.lo: JP2K_Sequence_Parser.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-JP2K_Sequence_Parser.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-JP2K_Sequence_Parser.Tpo -c -o libasdcp_la-JP2K_Sequence_Parser.lo `test -f 'JP2K_Sequence_Parser.cpp' || echo '$(srcdir)/'`JP2K_Sequence_Parser.cpp
+@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-JP2K_Sequence_Parser.Tpo $(DEPDIR)/libasdcp_la-JP2K_Sequence_Parser.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='JP2K_Sequence_Parser.cpp' object='libasdcp_la-JP2K_Sequence_Parser.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-JP2K_Sequence_Parser.lo `test -f 'JP2K_Sequence_Parser.cpp' || echo '$(srcdir)/'`JP2K_Sequence_Parser.cpp
+
+libasdcp_la-JP2K.lo: JP2K.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-JP2K.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-JP2K.Tpo -c -o libasdcp_la-JP2K.lo `test -f 'JP2K.cpp' || echo '$(srcdir)/'`JP2K.cpp
+@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-JP2K.Tpo $(DEPDIR)/libasdcp_la-JP2K.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='JP2K.cpp' object='libasdcp_la-JP2K.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-JP2K.lo `test -f 'JP2K.cpp' || echo '$(srcdir)/'`JP2K.cpp
+
+libasdcp_la-PCM_Parser.lo: PCM_Parser.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-PCM_Parser.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-PCM_Parser.Tpo -c -o libasdcp_la-PCM_Parser.lo `test -f 'PCM_Parser.cpp' || echo '$(srcdir)/'`PCM_Parser.cpp
+@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-PCM_Parser.Tpo $(DEPDIR)/libasdcp_la-PCM_Parser.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='PCM_Parser.cpp' object='libasdcp_la-PCM_Parser.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-PCM_Parser.lo `test -f 'PCM_Parser.cpp' || echo '$(srcdir)/'`PCM_Parser.cpp
+
+libasdcp_la-Wav.lo: Wav.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-Wav.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-Wav.Tpo -c -o libasdcp_la-Wav.lo `test -f 'Wav.cpp' || echo '$(srcdir)/'`Wav.cpp
+@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-Wav.Tpo $(DEPDIR)/libasdcp_la-Wav.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='Wav.cpp' object='libasdcp_la-Wav.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-Wav.lo `test -f 'Wav.cpp' || echo '$(srcdir)/'`Wav.cpp
+
+libasdcp_la-TimedText_Parser.lo: TimedText_Parser.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-TimedText_Parser.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-TimedText_Parser.Tpo -c -o libasdcp_la-TimedText_Parser.lo `test -f 'TimedText_Parser.cpp' || echo '$(srcdir)/'`TimedText_Parser.cpp
+@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-TimedText_Parser.Tpo $(DEPDIR)/libasdcp_la-TimedText_Parser.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='TimedText_Parser.cpp' object='libasdcp_la-TimedText_Parser.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-TimedText_Parser.lo `test -f 'TimedText_Parser.cpp' || echo '$(srcdir)/'`TimedText_Parser.cpp
+
+libasdcp_la-KLV.lo: KLV.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-KLV.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-KLV.Tpo -c -o libasdcp_la-KLV.lo `test -f 'KLV.cpp' || echo '$(srcdir)/'`KLV.cpp
+@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-KLV.Tpo $(DEPDIR)/libasdcp_la-KLV.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='KLV.cpp' object='libasdcp_la-KLV.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-KLV.lo `test -f 'KLV.cpp' || echo '$(srcdir)/'`KLV.cpp
+
+libasdcp_la-Dict.lo: Dict.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-Dict.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-Dict.Tpo -c -o libasdcp_la-Dict.lo `test -f 'Dict.cpp' || echo '$(srcdir)/'`Dict.cpp
+@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-Dict.Tpo $(DEPDIR)/libasdcp_la-Dict.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='Dict.cpp' object='libasdcp_la-Dict.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-Dict.lo `test -f 'Dict.cpp' || echo '$(srcdir)/'`Dict.cpp
+
+libasdcp_la-MXFTypes.lo: MXFTypes.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-MXFTypes.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-MXFTypes.Tpo -c -o libasdcp_la-MXFTypes.lo `test -f 'MXFTypes.cpp' || echo '$(srcdir)/'`MXFTypes.cpp
+@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-MXFTypes.Tpo $(DEPDIR)/libasdcp_la-MXFTypes.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='MXFTypes.cpp' object='libasdcp_la-MXFTypes.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-MXFTypes.lo `test -f 'MXFTypes.cpp' || echo '$(srcdir)/'`MXFTypes.cpp
+
+libasdcp_la-MXF.lo: MXF.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-MXF.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-MXF.Tpo -c -o libasdcp_la-MXF.lo `test -f 'MXF.cpp' || echo '$(srcdir)/'`MXF.cpp
+@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-MXF.Tpo $(DEPDIR)/libasdcp_la-MXF.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='MXF.cpp' object='libasdcp_la-MXF.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-MXF.lo `test -f 'MXF.cpp' || echo '$(srcdir)/'`MXF.cpp
+
+libasdcp_la-Index.lo: Index.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-Index.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-Index.Tpo -c -o libasdcp_la-Index.lo `test -f 'Index.cpp' || echo '$(srcdir)/'`Index.cpp
+@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-Index.Tpo $(DEPDIR)/libasdcp_la-Index.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='Index.cpp' object='libasdcp_la-Index.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-Index.lo `test -f 'Index.cpp' || echo '$(srcdir)/'`Index.cpp
+
+libasdcp_la-Metadata.lo: Metadata.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-Metadata.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-Metadata.Tpo -c -o libasdcp_la-Metadata.lo `test -f 'Metadata.cpp' || echo '$(srcdir)/'`Metadata.cpp
+@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-Metadata.Tpo $(DEPDIR)/libasdcp_la-Metadata.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='Metadata.cpp' object='libasdcp_la-Metadata.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-Metadata.lo `test -f 'Metadata.cpp' || echo '$(srcdir)/'`Metadata.cpp
+
+libasdcp_la-AS_DCP.lo: AS_DCP.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-AS_DCP.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-AS_DCP.Tpo -c -o libasdcp_la-AS_DCP.lo `test -f 'AS_DCP.cpp' || echo '$(srcdir)/'`AS_DCP.cpp
+@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-AS_DCP.Tpo $(DEPDIR)/libasdcp_la-AS_DCP.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='AS_DCP.cpp' object='libasdcp_la-AS_DCP.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-AS_DCP.lo `test -f 'AS_DCP.cpp' || echo '$(srcdir)/'`AS_DCP.cpp
+
+libasdcp_la-AS_DCP_MXF.lo: AS_DCP_MXF.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-AS_DCP_MXF.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-AS_DCP_MXF.Tpo -c -o libasdcp_la-AS_DCP_MXF.lo `test -f 'AS_DCP_MXF.cpp' || echo '$(srcdir)/'`AS_DCP_MXF.cpp
+@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-AS_DCP_MXF.Tpo $(DEPDIR)/libasdcp_la-AS_DCP_MXF.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='AS_DCP_MXF.cpp' object='libasdcp_la-AS_DCP_MXF.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-AS_DCP_MXF.lo `test -f 'AS_DCP_MXF.cpp' || echo '$(srcdir)/'`AS_DCP_MXF.cpp
+
+libasdcp_la-AS_DCP_AES.lo: AS_DCP_AES.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-AS_DCP_AES.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-AS_DCP_AES.Tpo -c -o libasdcp_la-AS_DCP_AES.lo `test -f 'AS_DCP_AES.cpp' || echo '$(srcdir)/'`AS_DCP_AES.cpp
+@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-AS_DCP_AES.Tpo $(DEPDIR)/libasdcp_la-AS_DCP_AES.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='AS_DCP_AES.cpp' object='libasdcp_la-AS_DCP_AES.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-AS_DCP_AES.lo `test -f 'AS_DCP_AES.cpp' || echo '$(srcdir)/'`AS_DCP_AES.cpp
+
+libasdcp_la-h__Reader.lo: h__Reader.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-h__Reader.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-h__Reader.Tpo -c -o libasdcp_la-h__Reader.lo `test -f 'h__Reader.cpp' || echo '$(srcdir)/'`h__Reader.cpp
+@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-h__Reader.Tpo $(DEPDIR)/libasdcp_la-h__Reader.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='h__Reader.cpp' object='libasdcp_la-h__Reader.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-h__Reader.lo `test -f 'h__Reader.cpp' || echo '$(srcdir)/'`h__Reader.cpp
+
+libasdcp_la-h__Writer.lo: h__Writer.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-h__Writer.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-h__Writer.Tpo -c -o libasdcp_la-h__Writer.lo `test -f 'h__Writer.cpp' || echo '$(srcdir)/'`h__Writer.cpp
+@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-h__Writer.Tpo $(DEPDIR)/libasdcp_la-h__Writer.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='h__Writer.cpp' object='libasdcp_la-h__Writer.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-h__Writer.lo `test -f 'h__Writer.cpp' || echo '$(srcdir)/'`h__Writer.cpp
+
+libasdcp_la-AS_DCP_MPEG2.lo: AS_DCP_MPEG2.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-AS_DCP_MPEG2.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-AS_DCP_MPEG2.Tpo -c -o libasdcp_la-AS_DCP_MPEG2.lo `test -f 'AS_DCP_MPEG2.cpp' || echo '$(srcdir)/'`AS_DCP_MPEG2.cpp
+@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-AS_DCP_MPEG2.Tpo $(DEPDIR)/libasdcp_la-AS_DCP_MPEG2.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='AS_DCP_MPEG2.cpp' object='libasdcp_la-AS_DCP_MPEG2.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-AS_DCP_MPEG2.lo `test -f 'AS_DCP_MPEG2.cpp' || echo '$(srcdir)/'`AS_DCP_MPEG2.cpp
+
+libasdcp_la-AS_DCP_JP2K.lo: AS_DCP_JP2K.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-AS_DCP_JP2K.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-AS_DCP_JP2K.Tpo -c -o libasdcp_la-AS_DCP_JP2K.lo `test -f 'AS_DCP_JP2K.cpp' || echo '$(srcdir)/'`AS_DCP_JP2K.cpp
+@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-AS_DCP_JP2K.Tpo $(DEPDIR)/libasdcp_la-AS_DCP_JP2K.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='AS_DCP_JP2K.cpp' object='libasdcp_la-AS_DCP_JP2K.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-AS_DCP_JP2K.lo `test -f 'AS_DCP_JP2K.cpp' || echo '$(srcdir)/'`AS_DCP_JP2K.cpp
+
+libasdcp_la-AS_DCP_PCM.lo: AS_DCP_PCM.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-AS_DCP_PCM.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-AS_DCP_PCM.Tpo -c -o libasdcp_la-AS_DCP_PCM.lo `test -f 'AS_DCP_PCM.cpp' || echo '$(srcdir)/'`AS_DCP_PCM.cpp
+@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-AS_DCP_PCM.Tpo $(DEPDIR)/libasdcp_la-AS_DCP_PCM.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='AS_DCP_PCM.cpp' object='libasdcp_la-AS_DCP_PCM.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-AS_DCP_PCM.lo `test -f 'AS_DCP_PCM.cpp' || echo '$(srcdir)/'`AS_DCP_PCM.cpp
+
+libasdcp_la-AS_DCP_TimedText.lo: AS_DCP_TimedText.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-AS_DCP_TimedText.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-AS_DCP_TimedText.Tpo -c -o libasdcp_la-AS_DCP_TimedText.lo `test -f 'AS_DCP_TimedText.cpp' || echo '$(srcdir)/'`AS_DCP_TimedText.cpp
+@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-AS_DCP_TimedText.Tpo $(DEPDIR)/libasdcp_la-AS_DCP_TimedText.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='AS_DCP_TimedText.cpp' object='libasdcp_la-AS_DCP_TimedText.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-AS_DCP_TimedText.lo `test -f 'AS_DCP_TimedText.cpp' || echo '$(srcdir)/'`AS_DCP_TimedText.cpp
+
+libasdcp_la-PCMParserList.lo: PCMParserList.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-PCMParserList.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-PCMParserList.Tpo -c -o libasdcp_la-PCMParserList.lo `test -f 'PCMParserList.cpp' || echo '$(srcdir)/'`PCMParserList.cpp
+@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-PCMParserList.Tpo $(DEPDIR)/libasdcp_la-PCMParserList.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='PCMParserList.cpp' object='libasdcp_la-PCMParserList.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-PCMParserList.lo `test -f 'PCMParserList.cpp' || echo '$(srcdir)/'`PCMParserList.cpp
+
+libasdcp_la-MDD.lo: MDD.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-MDD.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-MDD.Tpo -c -o libasdcp_la-MDD.lo `test -f 'MDD.cpp' || echo '$(srcdir)/'`MDD.cpp
+@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-MDD.Tpo $(DEPDIR)/libasdcp_la-MDD.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='MDD.cpp' object='libasdcp_la-MDD.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-MDD.lo `test -f 'MDD.cpp' || echo '$(srcdir)/'`MDD.cpp
+
+libasdcp_la-TimedText_Transform.lo: TimedText_Transform.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-TimedText_Transform.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-TimedText_Transform.Tpo -c -o libasdcp_la-TimedText_Transform.lo `test -f 'TimedText_Transform.cpp' || echo '$(srcdir)/'`TimedText_Transform.cpp
+@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-TimedText_Transform.Tpo $(DEPDIR)/libasdcp_la-TimedText_Transform.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='TimedText_Transform.cpp' object='libasdcp_la-TimedText_Transform.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-TimedText_Transform.lo `test -f 'TimedText_Transform.cpp' || echo '$(srcdir)/'`TimedText_Transform.cpp
+
+libpyasdcp_la-kumu_python.lo: kumu_python.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpyasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libpyasdcp_la-kumu_python.lo -MD -MP -MF $(DEPDIR)/libpyasdcp_la-kumu_python.Tpo -c -o libpyasdcp_la-kumu_python.lo `test -f 'kumu_python.cpp' || echo '$(srcdir)/'`kumu_python.cpp
+@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libpyasdcp_la-kumu_python.Tpo $(DEPDIR)/libpyasdcp_la-kumu_python.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='kumu_python.cpp' object='libpyasdcp_la-kumu_python.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpyasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libpyasdcp_la-kumu_python.lo `test -f 'kumu_python.cpp' || echo '$(srcdir)/'`kumu_python.cpp
+
+libpyasdcp_la-asdcp_python.lo: asdcp_python.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpyasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libpyasdcp_la-asdcp_python.lo -MD -MP -MF $(DEPDIR)/libpyasdcp_la-asdcp_python.Tpo -c -o libpyasdcp_la-asdcp_python.lo `test -f 'asdcp_python.cpp' || echo '$(srcdir)/'`asdcp_python.cpp
+@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libpyasdcp_la-asdcp_python.Tpo $(DEPDIR)/libpyasdcp_la-asdcp_python.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='asdcp_python.cpp' object='libpyasdcp_la-asdcp_python.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpyasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libpyasdcp_la-asdcp_python.lo `test -f 'asdcp_python.cpp' || echo '$(srcdir)/'`asdcp_python.cpp
+
+libpyasdcp_la-asdcp_python_descriptor.lo: asdcp_python_descriptor.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpyasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libpyasdcp_la-asdcp_python_descriptor.lo -MD -MP -MF $(DEPDIR)/libpyasdcp_la-asdcp_python_descriptor.Tpo -c -o libpyasdcp_la-asdcp_python_descriptor.lo `test -f 'asdcp_python_descriptor.cpp' || echo '$(srcdir)/'`asdcp_python_descriptor.cpp
+@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libpyasdcp_la-asdcp_python_descriptor.Tpo $(DEPDIR)/libpyasdcp_la-asdcp_python_descriptor.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='asdcp_python_descriptor.cpp' object='libpyasdcp_la-asdcp_python_descriptor.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpyasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libpyasdcp_la-asdcp_python_descriptor.lo `test -f 'asdcp_python_descriptor.cpp' || echo '$(srcdir)/'`asdcp_python_descriptor.cpp
+
+libpyasdcp_la-asdcp_python_misc.lo: asdcp_python_misc.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpyasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libpyasdcp_la-asdcp_python_misc.lo -MD -MP -MF $(DEPDIR)/libpyasdcp_la-asdcp_python_misc.Tpo -c -o libpyasdcp_la-asdcp_python_misc.lo `test -f 'asdcp_python_misc.cpp' || echo '$(srcdir)/'`asdcp_python_misc.cpp
+@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libpyasdcp_la-asdcp_python_misc.Tpo $(DEPDIR)/libpyasdcp_la-asdcp_python_misc.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='asdcp_python_misc.cpp' object='libpyasdcp_la-asdcp_python_misc.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpyasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libpyasdcp_la-asdcp_python_misc.lo `test -f 'asdcp_python_misc.cpp' || echo '$(srcdir)/'`asdcp_python_misc.cpp
+
+libpyasdcp_la-asdcp_python_mxf.lo: asdcp_python_mxf.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpyasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libpyasdcp_la-asdcp_python_mxf.lo -MD -MP -MF $(DEPDIR)/libpyasdcp_la-asdcp_python_mxf.Tpo -c -o libpyasdcp_la-asdcp_python_mxf.lo `test -f 'asdcp_python_mxf.cpp' || echo '$(srcdir)/'`asdcp_python_mxf.cpp
+@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libpyasdcp_la-asdcp_python_mxf.Tpo $(DEPDIR)/libpyasdcp_la-asdcp_python_mxf.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='asdcp_python_mxf.cpp' object='libpyasdcp_la-asdcp_python_mxf.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpyasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libpyasdcp_la-asdcp_python_mxf.lo `test -f 'asdcp_python_mxf.cpp' || echo '$(srcdir)/'`asdcp_python_mxf.cpp
+
+libpyasdcp_la-asdcp_python_mxf_text.lo: asdcp_python_mxf_text.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpyasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libpyasdcp_la-asdcp_python_mxf_text.lo -MD -MP -MF $(DEPDIR)/libpyasdcp_la-asdcp_python_mxf_text.Tpo -c -o libpyasdcp_la-asdcp_python_mxf_text.lo `test -f 'asdcp_python_mxf_text.cpp' || echo '$(srcdir)/'`asdcp_python_mxf_text.cpp
+@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libpyasdcp_la-asdcp_python_mxf_text.Tpo $(DEPDIR)/libpyasdcp_la-asdcp_python_mxf_text.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='asdcp_python_mxf_text.cpp' object='libpyasdcp_la-asdcp_python_mxf_text.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpyasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libpyasdcp_la-asdcp_python_mxf_text.lo `test -f 'asdcp_python_mxf_text.cpp' || echo '$(srcdir)/'`asdcp_python_mxf_text.cpp
+
+libpyasdcp_la-asdcp_python_mxf_metadata.lo: asdcp_python_mxf_metadata.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpyasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libpyasdcp_la-asdcp_python_mxf_metadata.lo -MD -MP -MF $(DEPDIR)/libpyasdcp_la-asdcp_python_mxf_metadata.Tpo -c -o libpyasdcp_la-asdcp_python_mxf_metadata.lo `test -f 'asdcp_python_mxf_metadata.cpp' || echo '$(srcdir)/'`asdcp_python_mxf_metadata.cpp
+@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libpyasdcp_la-asdcp_python_mxf_metadata.Tpo $(DEPDIR)/libpyasdcp_la-asdcp_python_mxf_metadata.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='asdcp_python_mxf_metadata.cpp' object='libpyasdcp_la-asdcp_python_mxf_metadata.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpyasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libpyasdcp_la-asdcp_python_mxf_metadata.lo `test -f 'asdcp_python_mxf_metadata.cpp' || echo '$(srcdir)/'`asdcp_python_mxf_metadata.cpp
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-includeHEADERS: $(include_HEADERS)
+ @$(NORMAL_INSTALL)
+ test -z "$(includedir)" || $(MKDIR_P) "$(DESTDIR)$(includedir)"
+ @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includedir)'"; \
+ $(INSTALL_HEADER) $$files "$(DESTDIR)$(includedir)" || exit $$?; \
+ done
+
+uninstall-includeHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(includedir)'; $(am__uninstall_files_from_dir)
+install-nodist_includeHEADERS: $(nodist_include_HEADERS)
+ @$(NORMAL_INSTALL)
+ test -z "$(includedir)" || $(MKDIR_P) "$(DESTDIR)$(includedir)"
+ @list='$(nodist_include_HEADERS)'; test -n "$(includedir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includedir)'"; \
+ $(INSTALL_HEADER) $$files "$(DESTDIR)$(includedir)" || exit $$?; \
+ done
+
+uninstall-nodist_includeHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(nodist_include_HEADERS)'; test -n "$(includedir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(includedir)'; $(am__uninstall_files_from_dir)
+install-nodist_pyexec_includeHEADERS: $(nodist_pyexec_include_HEADERS)
+ @$(NORMAL_INSTALL)
+ test -z "$(pyexec_includedir)" || $(MKDIR_P) "$(DESTDIR)$(pyexec_includedir)"
+ @list='$(nodist_pyexec_include_HEADERS)'; test -n "$(pyexec_includedir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pyexec_includedir)'"; \
+ $(INSTALL_HEADER) $$files "$(DESTDIR)$(pyexec_includedir)" || exit $$?; \
+ done
+
+uninstall-nodist_pyexec_includeHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(nodist_pyexec_include_HEADERS)'; test -n "$(pyexec_includedir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(pyexec_includedir)'; $(am__uninstall_files_from_dir)
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+check-TESTS: $(TESTS)
+ @failed=0; all=0; xfail=0; xpass=0; skip=0; \
+ srcdir=$(srcdir); export srcdir; \
+ list=' $(TESTS) '; \
+ $(am__tty_colors); \
+ if test -n "$$list"; then \
+ for tst in $$list; do \
+ if test -f ./$$tst; then dir=./; \
+ elif test -f $$tst; then dir=; \
+ else dir="$(srcdir)/"; fi; \
+ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
+ all=`expr $$all + 1`; \
+ case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$tst[\ \ ]*) \
+ xpass=`expr $$xpass + 1`; \
+ failed=`expr $$failed + 1`; \
+ col=$$red; res=XPASS; \
+ ;; \
+ *) \
+ col=$$grn; res=PASS; \
+ ;; \
+ esac; \
+ elif test $$? -ne 77; then \
+ all=`expr $$all + 1`; \
+ case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$tst[\ \ ]*) \
+ xfail=`expr $$xfail + 1`; \
+ col=$$lgn; res=XFAIL; \
+ ;; \
+ *) \
+ failed=`expr $$failed + 1`; \
+ col=$$red; res=FAIL; \
+ ;; \
+ esac; \
+ else \
+ skip=`expr $$skip + 1`; \
+ col=$$blu; res=SKIP; \
+ fi; \
+ echo "$${col}$$res$${std}: $$tst"; \
+ done; \
+ if test "$$all" -eq 1; then \
+ tests="test"; \
+ All=""; \
+ else \
+ tests="tests"; \
+ All="All "; \
+ fi; \
+ if test "$$failed" -eq 0; then \
+ if test "$$xfail" -eq 0; then \
+ banner="$$All$$all $$tests passed"; \
+ else \
+ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \
+ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \
+ fi; \
+ else \
+ if test "$$xpass" -eq 0; then \
+ banner="$$failed of $$all $$tests failed"; \
+ else \
+ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \
+ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \
+ fi; \
+ fi; \
+ dashes="$$banner"; \
+ skipped=""; \
+ if test "$$skip" -ne 0; then \
+ if test "$$skip" -eq 1; then \
+ skipped="($$skip test was not run)"; \
+ else \
+ skipped="($$skip tests were not run)"; \
+ fi; \
+ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+ dashes="$$skipped"; \
+ fi; \
+ report=""; \
+ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+ report="Please report to $(PACKAGE_BUGREPORT)"; \
+ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+ dashes="$$report"; \
+ fi; \
+ dashes=`echo "$$dashes" | sed s/./=/g`; \
+ if test "$$failed" -eq 0; then \
+ col="$$grn"; \
+ else \
+ col="$$red"; \
+ fi; \
+ echo "$${col}$$dashes$${std}"; \
+ echo "$${col}$$banner$${std}"; \
+ test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \
+ test -z "$$report" || echo "$${col}$$report$${std}"; \
+ echo "$${col}$$dashes$${std}"; \
+ test "$$failed" -eq 0; \
+ else :; fi
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+ $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(HEADERS)
+install-binPROGRAMS: install-libLTLIBRARIES
+
+installdirs:
+ for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pyexecdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(includedir)" "$(DESTDIR)$(includedir)" "$(DESTDIR)$(pyexec_includedir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \
+ clean-libLTLIBRARIES clean-libtool clean-pyexecLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-includeHEADERS install-nodist_includeHEADERS
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-binPROGRAMS install-libLTLIBRARIES \
+ install-nodist_pyexec_includeHEADERS install-pyexecLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS uninstall-includeHEADERS \
+ uninstall-libLTLIBRARIES uninstall-nodist_includeHEADERS \
+ uninstall-nodist_pyexec_includeHEADERS \
+ uninstall-pyexecLTLIBRARIES
+
+.MAKE: all check check-am install install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \
+ clean-binPROGRAMS clean-checkPROGRAMS clean-generic \
+ clean-libLTLIBRARIES clean-libtool clean-pyexecLTLIBRARIES \
+ ctags distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-binPROGRAMS \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-includeHEADERS install-info install-info-am \
+ install-libLTLIBRARIES install-man \
+ install-nodist_includeHEADERS \
+ install-nodist_pyexec_includeHEADERS install-pdf \
+ install-pdf-am install-ps install-ps-am \
+ install-pyexecLTLIBRARIES install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-binPROGRAMS \
+ uninstall-includeHEADERS uninstall-libLTLIBRARIES \
+ uninstall-nodist_includeHEADERS \
+ uninstall-nodist_pyexec_includeHEADERS \
+ uninstall-pyexecLTLIBRARIES
+
+
+# build commands for built sources
+# dependencies: $(srcdir)/ullist.pl $(srcdir)/ULList.xml $(srcdir)/dict.xml $(srcdir)/DMS_Crypto.xml
+MDD.h:
+ $(srcdir)/ullist.pl $(srcdir)/ULList.xml $(srcdir)/dict.xml $(srcdir)/DMS_Crypto.xml > MDD.h
+# dependencies: $(srcdir)/ullist.pl $(srcdir)/ULList.xml $(srcdir)/dict.xml $(srcdir)/DMS_Crypto.xml
+MDD.cpp:
+ $(srcdir)/ullist.pl -s $(srcdir)/ULList.xml $(srcdir)/dict.xml $(srcdir)/DMS_Crypto.xml > MDD.cpp
+# dependencies: $(srcdir)/Metadata_h.tt2 $(srcdir)/mxfgen.pl $(srcdir)/MXF_def.pl
+Metadata.h:
+ $(srcdir)/mxfgen.pl $(srcdir)/MXF_def.pl $(srcdir)/Metadata_h.tt2 > Metadata.h
+# dependencies: Metadata.h $(srcdir)/Metadata_cpp.tt2
+Metadata.cpp:
+ $(srcdir)/mxfgen.pl $(srcdir)/MXF_def.pl $(srcdir)/Metadata_cpp.tt2 > Metadata.cpp
+
+#
+#
+#
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/asdcplib/src/Metadata.cpp b/asdcplib/src/Metadata.cpp
new file mode 100755
index 0000000..a9a15e5
--- /dev/null
+++ b/asdcplib/src/Metadata.cpp
@@ -0,0 +1,2893 @@
+/*
+Copyright (c) 2005-2012, 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 Metadata.cpp
+ \version $Id: Metadata.cpp,v 1.31 2012/02/21 02:09:31 jhurst Exp $
+ \brief AS-DCP library, MXF Metadata Sets implementation
+*/
+
+
+#include <KM_mutex.h>
+#include "Metadata.h"
+
+using namespace ASDCP;
+using namespace ASDCP::MXF;
+
+const ui32_t kl_length = ASDCP::SMPTE_UL_LENGTH + ASDCP::MXF_BER_LENGTH;
+
+//------------------------------------------------------------------------------------------
+
+static InterchangeObject* Preface_Factory(const Dictionary*& Dict) { return new Preface(Dict); }
+static InterchangeObject* IndexTableSegment_Factory(const Dictionary*& Dict) { return new IndexTableSegment(Dict); }
+
+static InterchangeObject* Identification_Factory(const Dictionary*& Dict) { return new Identification(Dict); }
+static InterchangeObject* ContentStorage_Factory(const Dictionary*& Dict) { return new ContentStorage(Dict); }
+static InterchangeObject* EssenceContainerData_Factory(const Dictionary*& Dict) { return new EssenceContainerData(Dict); }
+static InterchangeObject* MaterialPackage_Factory(const Dictionary*& Dict) { return new MaterialPackage(Dict); }
+static InterchangeObject* SourcePackage_Factory(const Dictionary*& Dict) { return new SourcePackage(Dict); }
+static InterchangeObject* StaticTrack_Factory(const Dictionary*& Dict) { return new StaticTrack(Dict); }
+static InterchangeObject* Track_Factory(const Dictionary*& Dict) { return new Track(Dict); }
+static InterchangeObject* Sequence_Factory(const Dictionary*& Dict) { return new Sequence(Dict); }
+static InterchangeObject* SourceClip_Factory(const Dictionary*& Dict) { return new SourceClip(Dict); }
+static InterchangeObject* TimecodeComponent_Factory(const Dictionary*& Dict) { return new TimecodeComponent(Dict); }
+static InterchangeObject* FileDescriptor_Factory(const Dictionary*& Dict) { return new FileDescriptor(Dict); }
+static InterchangeObject* GenericSoundEssenceDescriptor_Factory(const Dictionary*& Dict) { return new GenericSoundEssenceDescriptor(Dict); }
+static InterchangeObject* WaveAudioDescriptor_Factory(const Dictionary*& Dict) { return new WaveAudioDescriptor(Dict); }
+static InterchangeObject* GenericPictureEssenceDescriptor_Factory(const Dictionary*& Dict) { return new GenericPictureEssenceDescriptor(Dict); }
+static InterchangeObject* RGBAEssenceDescriptor_Factory(const Dictionary*& Dict) { return new RGBAEssenceDescriptor(Dict); }
+static InterchangeObject* JPEG2000PictureSubDescriptor_Factory(const Dictionary*& Dict) { return new JPEG2000PictureSubDescriptor(Dict); }
+static InterchangeObject* CDCIEssenceDescriptor_Factory(const Dictionary*& Dict) { return new CDCIEssenceDescriptor(Dict); }
+static InterchangeObject* MPEG2VideoDescriptor_Factory(const Dictionary*& Dict) { return new MPEG2VideoDescriptor(Dict); }
+static InterchangeObject* DMSegment_Factory(const Dictionary*& Dict) { return new DMSegment(Dict); }
+static InterchangeObject* CryptographicFramework_Factory(const Dictionary*& Dict) { return new CryptographicFramework(Dict); }
+static InterchangeObject* CryptographicContext_Factory(const Dictionary*& Dict) { return new CryptographicContext(Dict); }
+static InterchangeObject* GenericDataEssenceDescriptor_Factory(const Dictionary*& Dict) { return new GenericDataEssenceDescriptor(Dict); }
+static InterchangeObject* TimedTextDescriptor_Factory(const Dictionary*& Dict) { return new TimedTextDescriptor(Dict); }
+static InterchangeObject* TimedTextResourceSubDescriptor_Factory(const Dictionary*& Dict) { return new TimedTextResourceSubDescriptor(Dict); }
+static InterchangeObject* StereoscopicPictureSubDescriptor_Factory(const Dictionary*& Dict) { return new StereoscopicPictureSubDescriptor(Dict); }
+static InterchangeObject* NetworkLocator_Factory(const Dictionary*& Dict) { return new NetworkLocator(Dict); }
+static InterchangeObject* MCALabelSubDescriptor_Factory(const Dictionary*& Dict) { return new MCALabelSubDescriptor(Dict); }
+static InterchangeObject* AudioChannelLabelSubDescriptor_Factory(const Dictionary*& Dict) { return new AudioChannelLabelSubDescriptor(Dict); }
+static InterchangeObject* SoundfieldGroupLabelSubDescriptor_Factory(const Dictionary*& Dict) { return new SoundfieldGroupLabelSubDescriptor(Dict); }
+static InterchangeObject* GroupOfSoundfieldGroupsLabelSubDescriptor_Factory(const Dictionary*& Dict) { return new GroupOfSoundfieldGroupsLabelSubDescriptor(Dict); }
+
+
+void
+ASDCP::MXF::Metadata_InitTypes(const Dictionary*& Dict)
+{
+ assert(Dict);
+ SetObjectFactory(Dict->ul(MDD_Preface), Preface_Factory);
+ SetObjectFactory(Dict->ul(MDD_IndexTableSegment), IndexTableSegment_Factory);
+
+ SetObjectFactory(Dict->ul(MDD_Identification), Identification_Factory);
+ SetObjectFactory(Dict->ul(MDD_ContentStorage), ContentStorage_Factory);
+ SetObjectFactory(Dict->ul(MDD_EssenceContainerData), EssenceContainerData_Factory);
+ SetObjectFactory(Dict->ul(MDD_MaterialPackage), MaterialPackage_Factory);
+ SetObjectFactory(Dict->ul(MDD_SourcePackage), SourcePackage_Factory);
+ SetObjectFactory(Dict->ul(MDD_StaticTrack), StaticTrack_Factory);
+ SetObjectFactory(Dict->ul(MDD_Track), Track_Factory);
+ SetObjectFactory(Dict->ul(MDD_Sequence), Sequence_Factory);
+ SetObjectFactory(Dict->ul(MDD_SourceClip), SourceClip_Factory);
+ SetObjectFactory(Dict->ul(MDD_TimecodeComponent), TimecodeComponent_Factory);
+ SetObjectFactory(Dict->ul(MDD_FileDescriptor), FileDescriptor_Factory);
+ SetObjectFactory(Dict->ul(MDD_GenericSoundEssenceDescriptor), GenericSoundEssenceDescriptor_Factory);
+ SetObjectFactory(Dict->ul(MDD_WaveAudioDescriptor), WaveAudioDescriptor_Factory);
+ SetObjectFactory(Dict->ul(MDD_GenericPictureEssenceDescriptor), GenericPictureEssenceDescriptor_Factory);
+ SetObjectFactory(Dict->ul(MDD_RGBAEssenceDescriptor), RGBAEssenceDescriptor_Factory);
+ SetObjectFactory(Dict->ul(MDD_JPEG2000PictureSubDescriptor), JPEG2000PictureSubDescriptor_Factory);
+ SetObjectFactory(Dict->ul(MDD_CDCIEssenceDescriptor), CDCIEssenceDescriptor_Factory);
+ SetObjectFactory(Dict->ul(MDD_MPEG2VideoDescriptor), MPEG2VideoDescriptor_Factory);
+ SetObjectFactory(Dict->ul(MDD_DMSegment), DMSegment_Factory);
+ SetObjectFactory(Dict->ul(MDD_CryptographicFramework), CryptographicFramework_Factory);
+ SetObjectFactory(Dict->ul(MDD_CryptographicContext), CryptographicContext_Factory);
+ SetObjectFactory(Dict->ul(MDD_GenericDataEssenceDescriptor), GenericDataEssenceDescriptor_Factory);
+ SetObjectFactory(Dict->ul(MDD_TimedTextDescriptor), TimedTextDescriptor_Factory);
+ SetObjectFactory(Dict->ul(MDD_TimedTextResourceSubDescriptor), TimedTextResourceSubDescriptor_Factory);
+ SetObjectFactory(Dict->ul(MDD_StereoscopicPictureSubDescriptor), StereoscopicPictureSubDescriptor_Factory);
+ SetObjectFactory(Dict->ul(MDD_NetworkLocator), NetworkLocator_Factory);
+ SetObjectFactory(Dict->ul(MDD_MCALabelSubDescriptor), MCALabelSubDescriptor_Factory);
+ SetObjectFactory(Dict->ul(MDD_AudioChannelLabelSubDescriptor), AudioChannelLabelSubDescriptor_Factory);
+ SetObjectFactory(Dict->ul(MDD_SoundfieldGroupLabelSubDescriptor), SoundfieldGroupLabelSubDescriptor_Factory);
+ SetObjectFactory(Dict->ul(MDD_GroupOfSoundfieldGroupsLabelSubDescriptor), GroupOfSoundfieldGroupsLabelSubDescriptor_Factory);
+}
+
+//------------------------------------------------------------------------------------------
+// KLV Sets
+
+
+
+//------------------------------------------------------------------------------------------
+// Identification
+
+//
+
+Identification::Identification(const Dictionary*& d) : InterchangeObject(d), m_Dict(d)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_Identification);
+}
+
+Identification::Identification(const Identification& rhs) : InterchangeObject(rhs.m_Dict), m_Dict(rhs.m_Dict)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_Identification);
+ Copy(rhs);
+}
+
+
+//
+ASDCP::Result_t
+Identification::InitFromTLVSet(TLVReader& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = InterchangeObject::InitFromTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Identification, ThisGenerationUID));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Identification, CompanyName));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Identification, ProductName));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Identification, ProductVersion));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Identification, VersionString));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Identification, ProductUID));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Identification, ModificationDate));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Identification, ToolkitVersion));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Identification, Platform));
+ return result;
+}
+
+//
+ASDCP::Result_t
+Identification::WriteToTLVSet(TLVWriter& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = InterchangeObject::WriteToTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Identification, ThisGenerationUID));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Identification, CompanyName));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Identification, ProductName));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Identification, ProductVersion));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Identification, VersionString));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Identification, ProductUID));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Identification, ModificationDate));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Identification, ToolkitVersion));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Identification, Platform));
+ return result;
+}
+
+//
+void
+Identification::Copy(const Identification& rhs)
+{
+ InterchangeObject::Copy(rhs);
+ ThisGenerationUID = rhs.ThisGenerationUID;
+ CompanyName = rhs.CompanyName;
+ ProductName = rhs.ProductName;
+ ProductVersion = rhs.ProductVersion;
+ VersionString = rhs.VersionString;
+ ProductUID = rhs.ProductUID;
+ ModificationDate = rhs.ModificationDate;
+ ToolkitVersion = rhs.ToolkitVersion;
+ Platform = rhs.Platform;
+}
+
+//
+void
+Identification::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+ *identbuf = 0;
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ InterchangeObject::Dump(stream);
+ 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));
+}
+
+//
+ASDCP::Result_t
+Identification::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+Identification::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return InterchangeObject::WriteToBuffer(Buffer);
+}
+
+//------------------------------------------------------------------------------------------
+// ContentStorage
+
+//
+
+ContentStorage::ContentStorage(const Dictionary*& d) : InterchangeObject(d), m_Dict(d)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_ContentStorage);
+}
+
+ContentStorage::ContentStorage(const ContentStorage& rhs) : InterchangeObject(rhs.m_Dict), m_Dict(rhs.m_Dict)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_ContentStorage);
+ Copy(rhs);
+}
+
+
+//
+ASDCP::Result_t
+ContentStorage::InitFromTLVSet(TLVReader& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = InterchangeObject::InitFromTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(ContentStorage, Packages));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(ContentStorage, EssenceContainerData));
+ return result;
+}
+
+//
+ASDCP::Result_t
+ContentStorage::WriteToTLVSet(TLVWriter& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = InterchangeObject::WriteToTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(ContentStorage, Packages));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(ContentStorage, EssenceContainerData));
+ return result;
+}
+
+//
+void
+ContentStorage::Copy(const ContentStorage& rhs)
+{
+ InterchangeObject::Copy(rhs);
+ Packages = rhs.Packages;
+ EssenceContainerData = rhs.EssenceContainerData;
+}
+
+//
+void
+ContentStorage::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+ *identbuf = 0;
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ InterchangeObject::Dump(stream);
+ fprintf(stream, " %22s:\n", "Packages");
+ Packages.Dump(stream);
+ fprintf(stream, " %22s:\n", "EssenceContainerData");
+ EssenceContainerData.Dump(stream);
+}
+
+//
+ASDCP::Result_t
+ContentStorage::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+ContentStorage::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return InterchangeObject::WriteToBuffer(Buffer);
+}
+
+//------------------------------------------------------------------------------------------
+// EssenceContainerData
+
+//
+
+EssenceContainerData::EssenceContainerData(const Dictionary*& d) : InterchangeObject(d), m_Dict(d), IndexSID(0), BodySID(0)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_EssenceContainerData);
+}
+
+EssenceContainerData::EssenceContainerData(const EssenceContainerData& rhs) : InterchangeObject(rhs.m_Dict), m_Dict(rhs.m_Dict)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_EssenceContainerData);
+ Copy(rhs);
+}
+
+
+//
+ASDCP::Result_t
+EssenceContainerData::InitFromTLVSet(TLVReader& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = InterchangeObject::InitFromTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(EssenceContainerData, LinkedPackageUID));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(EssenceContainerData, IndexSID));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(EssenceContainerData, BodySID));
+ return result;
+}
+
+//
+ASDCP::Result_t
+EssenceContainerData::WriteToTLVSet(TLVWriter& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = InterchangeObject::WriteToTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(EssenceContainerData, LinkedPackageUID));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(EssenceContainerData, IndexSID));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(EssenceContainerData, BodySID));
+ return result;
+}
+
+//
+void
+EssenceContainerData::Copy(const EssenceContainerData& rhs)
+{
+ InterchangeObject::Copy(rhs);
+ LinkedPackageUID = rhs.LinkedPackageUID;
+ IndexSID = rhs.IndexSID;
+ BodySID = rhs.BodySID;
+}
+
+//
+void
+EssenceContainerData::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+ *identbuf = 0;
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ InterchangeObject::Dump(stream);
+ fprintf(stream, " %22s = %s\n", "LinkedPackageUID", LinkedPackageUID.EncodeString(identbuf, IdentBufferLen));
+ fprintf(stream, " %22s = %d\n", "IndexSID", IndexSID);
+ fprintf(stream, " %22s = %d\n", "BodySID", BodySID);
+}
+
+//
+ASDCP::Result_t
+EssenceContainerData::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+EssenceContainerData::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return InterchangeObject::WriteToBuffer(Buffer);
+}
+
+//------------------------------------------------------------------------------------------
+// GenericPackage
+
+//
+GenericPackage::GenericPackage(const Dictionary*& d) : InterchangeObject(d), m_Dict(d) {}
+
+GenericPackage::GenericPackage(const GenericPackage& rhs) : InterchangeObject(rhs.m_Dict), m_Dict(rhs.m_Dict)
+{
+ Copy(rhs);
+}
+
+
+//
+ASDCP::Result_t
+GenericPackage::InitFromTLVSet(TLVReader& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = InterchangeObject::InitFromTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(GenericPackage, PackageUID));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(GenericPackage, Name));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(GenericPackage, PackageCreationDate));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(GenericPackage, PackageModifiedDate));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(GenericPackage, Tracks));
+ return result;
+}
+
+//
+ASDCP::Result_t
+GenericPackage::WriteToTLVSet(TLVWriter& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = InterchangeObject::WriteToTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(GenericPackage, PackageUID));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(GenericPackage, Name));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(GenericPackage, PackageCreationDate));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(GenericPackage, PackageModifiedDate));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(GenericPackage, Tracks));
+ return result;
+}
+
+//
+void
+GenericPackage::Copy(const GenericPackage& rhs)
+{
+ InterchangeObject::Copy(rhs);
+ PackageUID = rhs.PackageUID;
+ Name = rhs.Name;
+ PackageCreationDate = rhs.PackageCreationDate;
+ PackageModifiedDate = rhs.PackageModifiedDate;
+ Tracks = rhs.Tracks;
+}
+
+//
+void
+GenericPackage::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+ *identbuf = 0;
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ InterchangeObject::Dump(stream);
+ 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);
+}
+
+
+//------------------------------------------------------------------------------------------
+// MaterialPackage
+
+//
+
+MaterialPackage::MaterialPackage(const Dictionary*& d) : GenericPackage(d), m_Dict(d)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_MaterialPackage);
+}
+
+MaterialPackage::MaterialPackage(const MaterialPackage& rhs) : GenericPackage(rhs.m_Dict), m_Dict(rhs.m_Dict)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_MaterialPackage);
+ Copy(rhs);
+}
+
+
+//
+ASDCP::Result_t
+MaterialPackage::InitFromTLVSet(TLVReader& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = GenericPackage::InitFromTLVSet(TLVSet);
+ return result;
+}
+
+//
+ASDCP::Result_t
+MaterialPackage::WriteToTLVSet(TLVWriter& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = GenericPackage::WriteToTLVSet(TLVSet);
+ return result;
+}
+
+//
+void
+MaterialPackage::Copy(const MaterialPackage& rhs)
+{
+ GenericPackage::Copy(rhs);
+}
+
+//
+void
+MaterialPackage::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+ *identbuf = 0;
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ GenericPackage::Dump(stream);
+}
+
+//
+ASDCP::Result_t
+MaterialPackage::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+MaterialPackage::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return InterchangeObject::WriteToBuffer(Buffer);
+}
+
+//------------------------------------------------------------------------------------------
+// SourcePackage
+
+//
+
+SourcePackage::SourcePackage(const Dictionary*& d) : GenericPackage(d), m_Dict(d)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_SourcePackage);
+}
+
+SourcePackage::SourcePackage(const SourcePackage& rhs) : GenericPackage(rhs.m_Dict), m_Dict(rhs.m_Dict)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_SourcePackage);
+ Copy(rhs);
+}
+
+
+//
+ASDCP::Result_t
+SourcePackage::InitFromTLVSet(TLVReader& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = GenericPackage::InitFromTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(SourcePackage, Descriptor));
+ return result;
+}
+
+//
+ASDCP::Result_t
+SourcePackage::WriteToTLVSet(TLVWriter& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = GenericPackage::WriteToTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(SourcePackage, Descriptor));
+ return result;
+}
+
+//
+void
+SourcePackage::Copy(const SourcePackage& rhs)
+{
+ GenericPackage::Copy(rhs);
+ Descriptor = rhs.Descriptor;
+}
+
+//
+void
+SourcePackage::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+ *identbuf = 0;
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ GenericPackage::Dump(stream);
+ fprintf(stream, " %22s = %s\n", "Descriptor", Descriptor.EncodeString(identbuf, IdentBufferLen));
+}
+
+//
+ASDCP::Result_t
+SourcePackage::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+SourcePackage::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return InterchangeObject::WriteToBuffer(Buffer);
+}
+
+//------------------------------------------------------------------------------------------
+// GenericTrack
+
+//
+GenericTrack::GenericTrack(const Dictionary*& d) : InterchangeObject(d), m_Dict(d), TrackID(0), TrackNumber(0) {}
+
+GenericTrack::GenericTrack(const GenericTrack& rhs) : InterchangeObject(rhs.m_Dict), m_Dict(rhs.m_Dict)
+{
+ Copy(rhs);
+}
+
+
+//
+ASDCP::Result_t
+GenericTrack::InitFromTLVSet(TLVReader& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = InterchangeObject::InitFromTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(GenericTrack, TrackID));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(GenericTrack, TrackNumber));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(GenericTrack, TrackName));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(GenericTrack, Sequence));
+ return result;
+}
+
+//
+ASDCP::Result_t
+GenericTrack::WriteToTLVSet(TLVWriter& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = InterchangeObject::WriteToTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(GenericTrack, TrackID));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(GenericTrack, TrackNumber));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(GenericTrack, TrackName));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(GenericTrack, Sequence));
+ return result;
+}
+
+//
+void
+GenericTrack::Copy(const GenericTrack& rhs)
+{
+ InterchangeObject::Copy(rhs);
+ TrackID = rhs.TrackID;
+ TrackNumber = rhs.TrackNumber;
+ TrackName = rhs.TrackName;
+ Sequence = rhs.Sequence;
+}
+
+//
+void
+GenericTrack::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+ *identbuf = 0;
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ InterchangeObject::Dump(stream);
+ fprintf(stream, " %22s = %d\n", "TrackID", TrackID);
+ fprintf(stream, " %22s = %d\n", "TrackNumber", TrackNumber);
+ fprintf(stream, " %22s = %s\n", "TrackName", TrackName.EncodeString(identbuf, IdentBufferLen));
+ fprintf(stream, " %22s = %s\n", "Sequence", Sequence.EncodeString(identbuf, IdentBufferLen));
+}
+
+
+//------------------------------------------------------------------------------------------
+// StaticTrack
+
+//
+
+StaticTrack::StaticTrack(const Dictionary*& d) : GenericTrack(d), m_Dict(d)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_StaticTrack);
+}
+
+StaticTrack::StaticTrack(const StaticTrack& rhs) : GenericTrack(rhs.m_Dict), m_Dict(rhs.m_Dict)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_StaticTrack);
+ Copy(rhs);
+}
+
+
+//
+ASDCP::Result_t
+StaticTrack::InitFromTLVSet(TLVReader& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = GenericTrack::InitFromTLVSet(TLVSet);
+ return result;
+}
+
+//
+ASDCP::Result_t
+StaticTrack::WriteToTLVSet(TLVWriter& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = GenericTrack::WriteToTLVSet(TLVSet);
+ return result;
+}
+
+//
+void
+StaticTrack::Copy(const StaticTrack& rhs)
+{
+ GenericTrack::Copy(rhs);
+}
+
+//
+void
+StaticTrack::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+ *identbuf = 0;
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ GenericTrack::Dump(stream);
+}
+
+//
+ASDCP::Result_t
+StaticTrack::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+StaticTrack::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return InterchangeObject::WriteToBuffer(Buffer);
+}
+
+//------------------------------------------------------------------------------------------
+// Track
+
+//
+
+Track::Track(const Dictionary*& d) : GenericTrack(d), m_Dict(d), Origin(0)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_Track);
+}
+
+Track::Track(const Track& rhs) : GenericTrack(rhs.m_Dict), m_Dict(rhs.m_Dict)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_Track);
+ Copy(rhs);
+}
+
+
+//
+ASDCP::Result_t
+Track::InitFromTLVSet(TLVReader& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = GenericTrack::InitFromTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Track, EditRate));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi64(OBJ_READ_ARGS(Track, Origin));
+ return result;
+}
+
+//
+ASDCP::Result_t
+Track::WriteToTLVSet(TLVWriter& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = GenericTrack::WriteToTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Track, EditRate));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi64(OBJ_WRITE_ARGS(Track, Origin));
+ return result;
+}
+
+//
+void
+Track::Copy(const Track& rhs)
+{
+ GenericTrack::Copy(rhs);
+ EditRate = rhs.EditRate;
+ Origin = rhs.Origin;
+}
+
+//
+void
+Track::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+ *identbuf = 0;
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ GenericTrack::Dump(stream);
+ fprintf(stream, " %22s = %s\n", "EditRate", EditRate.EncodeString(identbuf, IdentBufferLen));
+ fprintf(stream, " %22s = %s\n", "Origin", i64sz(Origin, identbuf));
+}
+
+//
+ASDCP::Result_t
+Track::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+Track::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return InterchangeObject::WriteToBuffer(Buffer);
+}
+
+//------------------------------------------------------------------------------------------
+// StructuralComponent
+
+//
+StructuralComponent::StructuralComponent(const Dictionary*& d) : InterchangeObject(d), m_Dict(d), Duration(0) {}
+
+StructuralComponent::StructuralComponent(const StructuralComponent& rhs) : InterchangeObject(rhs.m_Dict), m_Dict(rhs.m_Dict)
+{
+ Copy(rhs);
+}
+
+
+//
+ASDCP::Result_t
+StructuralComponent::InitFromTLVSet(TLVReader& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = InterchangeObject::InitFromTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(StructuralComponent, DataDefinition));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi64(OBJ_READ_ARGS(StructuralComponent, Duration));
+ return result;
+}
+
+//
+ASDCP::Result_t
+StructuralComponent::WriteToTLVSet(TLVWriter& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = InterchangeObject::WriteToTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(StructuralComponent, DataDefinition));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi64(OBJ_WRITE_ARGS(StructuralComponent, Duration));
+ return result;
+}
+
+//
+void
+StructuralComponent::Copy(const StructuralComponent& rhs)
+{
+ InterchangeObject::Copy(rhs);
+ DataDefinition = rhs.DataDefinition;
+ Duration = rhs.Duration;
+}
+
+//
+void
+StructuralComponent::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+ *identbuf = 0;
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ InterchangeObject::Dump(stream);
+ fprintf(stream, " %22s = %s\n", "DataDefinition", DataDefinition.EncodeString(identbuf, IdentBufferLen));
+ fprintf(stream, " %22s = %s\n", "Duration", i64sz(Duration, identbuf));
+}
+
+
+//------------------------------------------------------------------------------------------
+// Sequence
+
+//
+
+Sequence::Sequence(const Dictionary*& d) : StructuralComponent(d), m_Dict(d)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_Sequence);
+}
+
+Sequence::Sequence(const Sequence& rhs) : StructuralComponent(rhs.m_Dict), m_Dict(rhs.m_Dict)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_Sequence);
+ Copy(rhs);
+}
+
+
+//
+ASDCP::Result_t
+Sequence::InitFromTLVSet(TLVReader& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = StructuralComponent::InitFromTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Sequence, StructuralComponents));
+ return result;
+}
+
+//
+ASDCP::Result_t
+Sequence::WriteToTLVSet(TLVWriter& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = StructuralComponent::WriteToTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Sequence, StructuralComponents));
+ return result;
+}
+
+//
+void
+Sequence::Copy(const Sequence& rhs)
+{
+ StructuralComponent::Copy(rhs);
+ StructuralComponents = rhs.StructuralComponents;
+}
+
+//
+void
+Sequence::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+ *identbuf = 0;
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ StructuralComponent::Dump(stream);
+ fprintf(stream, " %22s:\n", "StructuralComponents");
+ StructuralComponents.Dump(stream);
+}
+
+//
+ASDCP::Result_t
+Sequence::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+Sequence::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return InterchangeObject::WriteToBuffer(Buffer);
+}
+
+//------------------------------------------------------------------------------------------
+// SourceClip
+
+//
+
+SourceClip::SourceClip(const Dictionary*& d) : StructuralComponent(d), m_Dict(d), StartPosition(0), SourceTrackID(0)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_SourceClip);
+}
+
+SourceClip::SourceClip(const SourceClip& rhs) : StructuralComponent(rhs.m_Dict), m_Dict(rhs.m_Dict)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_SourceClip);
+ Copy(rhs);
+}
+
+
+//
+ASDCP::Result_t
+SourceClip::InitFromTLVSet(TLVReader& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = StructuralComponent::InitFromTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi64(OBJ_READ_ARGS(SourceClip, StartPosition));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(SourceClip, SourcePackageID));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(SourceClip, SourceTrackID));
+ return result;
+}
+
+//
+ASDCP::Result_t
+SourceClip::WriteToTLVSet(TLVWriter& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = StructuralComponent::WriteToTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi64(OBJ_WRITE_ARGS(SourceClip, StartPosition));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(SourceClip, SourcePackageID));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(SourceClip, SourceTrackID));
+ return result;
+}
+
+//
+void
+SourceClip::Copy(const SourceClip& rhs)
+{
+ StructuralComponent::Copy(rhs);
+ StartPosition = rhs.StartPosition;
+ SourcePackageID = rhs.SourcePackageID;
+ SourceTrackID = rhs.SourceTrackID;
+}
+
+//
+void
+SourceClip::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+ *identbuf = 0;
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ StructuralComponent::Dump(stream);
+ fprintf(stream, " %22s = %s\n", "StartPosition", i64sz(StartPosition, identbuf));
+ fprintf(stream, " %22s = %s\n", "SourcePackageID", SourcePackageID.EncodeString(identbuf, IdentBufferLen));
+ fprintf(stream, " %22s = %d\n", "SourceTrackID", SourceTrackID);
+}
+
+//
+ASDCP::Result_t
+SourceClip::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+SourceClip::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return InterchangeObject::WriteToBuffer(Buffer);
+}
+
+//------------------------------------------------------------------------------------------
+// TimecodeComponent
+
+//
+
+TimecodeComponent::TimecodeComponent(const Dictionary*& d) : StructuralComponent(d), m_Dict(d), RoundedTimecodeBase(0), StartTimecode(0), DropFrame(0)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_TimecodeComponent);
+}
+
+TimecodeComponent::TimecodeComponent(const TimecodeComponent& rhs) : StructuralComponent(rhs.m_Dict), m_Dict(rhs.m_Dict)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_TimecodeComponent);
+ Copy(rhs);
+}
+
+
+//
+ASDCP::Result_t
+TimecodeComponent::InitFromTLVSet(TLVReader& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = StructuralComponent::InitFromTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi16(OBJ_READ_ARGS(TimecodeComponent, RoundedTimecodeBase));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi64(OBJ_READ_ARGS(TimecodeComponent, StartTimecode));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi8(OBJ_READ_ARGS(TimecodeComponent, DropFrame));
+ return result;
+}
+
+//
+ASDCP::Result_t
+TimecodeComponent::WriteToTLVSet(TLVWriter& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = StructuralComponent::WriteToTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi16(OBJ_WRITE_ARGS(TimecodeComponent, RoundedTimecodeBase));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi64(OBJ_WRITE_ARGS(TimecodeComponent, StartTimecode));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi8(OBJ_WRITE_ARGS(TimecodeComponent, DropFrame));
+ return result;
+}
+
+//
+void
+TimecodeComponent::Copy(const TimecodeComponent& rhs)
+{
+ StructuralComponent::Copy(rhs);
+ RoundedTimecodeBase = rhs.RoundedTimecodeBase;
+ StartTimecode = rhs.StartTimecode;
+ DropFrame = rhs.DropFrame;
+}
+
+//
+void
+TimecodeComponent::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+ *identbuf = 0;
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ StructuralComponent::Dump(stream);
+ fprintf(stream, " %22s = %d\n", "RoundedTimecodeBase", RoundedTimecodeBase);
+ fprintf(stream, " %22s = %s\n", "StartTimecode", i64sz(StartTimecode, identbuf));
+ fprintf(stream, " %22s = %d\n", "DropFrame", DropFrame);
+}
+
+//
+ASDCP::Result_t
+TimecodeComponent::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+TimecodeComponent::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return InterchangeObject::WriteToBuffer(Buffer);
+}
+
+//------------------------------------------------------------------------------------------
+// GenericDescriptor
+
+//
+GenericDescriptor::GenericDescriptor(const Dictionary*& d) : InterchangeObject(d), m_Dict(d) {}
+
+GenericDescriptor::GenericDescriptor(const GenericDescriptor& rhs) : InterchangeObject(rhs.m_Dict), m_Dict(rhs.m_Dict)
+{
+ Copy(rhs);
+}
+
+
+//
+ASDCP::Result_t
+GenericDescriptor::InitFromTLVSet(TLVReader& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = InterchangeObject::InitFromTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(GenericDescriptor, Locators));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(GenericDescriptor, SubDescriptors));
+ return result;
+}
+
+//
+ASDCP::Result_t
+GenericDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = InterchangeObject::WriteToTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(GenericDescriptor, Locators));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(GenericDescriptor, SubDescriptors));
+ return result;
+}
+
+//
+void
+GenericDescriptor::Copy(const GenericDescriptor& rhs)
+{
+ InterchangeObject::Copy(rhs);
+ Locators = rhs.Locators;
+ SubDescriptors = rhs.SubDescriptors;
+}
+
+//
+void
+GenericDescriptor::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+ *identbuf = 0;
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ InterchangeObject::Dump(stream);
+ fprintf(stream, " %22s:\n", "Locators");
+ Locators.Dump(stream);
+ fprintf(stream, " %22s:\n", "SubDescriptors");
+ SubDescriptors.Dump(stream);
+}
+
+
+//------------------------------------------------------------------------------------------
+// FileDescriptor
+
+//
+
+FileDescriptor::FileDescriptor(const Dictionary*& d) : GenericDescriptor(d), m_Dict(d), LinkedTrackID(0), ContainerDuration(0)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_FileDescriptor);
+}
+
+FileDescriptor::FileDescriptor(const FileDescriptor& rhs) : GenericDescriptor(rhs.m_Dict), m_Dict(rhs.m_Dict)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_FileDescriptor);
+ Copy(rhs);
+}
+
+
+//
+ASDCP::Result_t
+FileDescriptor::InitFromTLVSet(TLVReader& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = GenericDescriptor::InitFromTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(FileDescriptor, LinkedTrackID));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(FileDescriptor, SampleRate));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi64(OBJ_READ_ARGS(FileDescriptor, ContainerDuration));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(FileDescriptor, EssenceContainer));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(FileDescriptor, Codec));
+ return result;
+}
+
+//
+ASDCP::Result_t
+FileDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = GenericDescriptor::WriteToTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(FileDescriptor, LinkedTrackID));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(FileDescriptor, SampleRate));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi64(OBJ_WRITE_ARGS(FileDescriptor, ContainerDuration));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(FileDescriptor, EssenceContainer));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(FileDescriptor, Codec));
+ return result;
+}
+
+//
+void
+FileDescriptor::Copy(const FileDescriptor& rhs)
+{
+ GenericDescriptor::Copy(rhs);
+ LinkedTrackID = rhs.LinkedTrackID;
+ SampleRate = rhs.SampleRate;
+ ContainerDuration = rhs.ContainerDuration;
+ EssenceContainer = rhs.EssenceContainer;
+ Codec = rhs.Codec;
+}
+
+//
+void
+FileDescriptor::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+ *identbuf = 0;
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ GenericDescriptor::Dump(stream);
+ fprintf(stream, " %22s = %d\n", "LinkedTrackID", LinkedTrackID);
+ 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.EncodeString(identbuf, IdentBufferLen));
+ fprintf(stream, " %22s = %s\n", "Codec", Codec.EncodeString(identbuf, IdentBufferLen));
+}
+
+//
+ASDCP::Result_t
+FileDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+FileDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return InterchangeObject::WriteToBuffer(Buffer);
+}
+
+//------------------------------------------------------------------------------------------
+// GenericSoundEssenceDescriptor
+
+//
+
+GenericSoundEssenceDescriptor::GenericSoundEssenceDescriptor(const Dictionary*& d) : FileDescriptor(d), m_Dict(d), Locked(0), AudioRefLevel(0), ChannelCount(0), QuantizationBits(0), DialNorm(0)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_GenericSoundEssenceDescriptor);
+}
+
+GenericSoundEssenceDescriptor::GenericSoundEssenceDescriptor(const GenericSoundEssenceDescriptor& rhs) : FileDescriptor(rhs.m_Dict), m_Dict(rhs.m_Dict)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_GenericSoundEssenceDescriptor);
+ Copy(rhs);
+}
+
+
+//
+ASDCP::Result_t
+GenericSoundEssenceDescriptor::InitFromTLVSet(TLVReader& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = FileDescriptor::InitFromTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(GenericSoundEssenceDescriptor, AudioSamplingRate));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi8(OBJ_READ_ARGS(GenericSoundEssenceDescriptor, Locked));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi8(OBJ_READ_ARGS(GenericSoundEssenceDescriptor, AudioRefLevel));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(GenericSoundEssenceDescriptor, ChannelCount));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(GenericSoundEssenceDescriptor, QuantizationBits));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi8(OBJ_READ_ARGS(GenericSoundEssenceDescriptor, DialNorm));
+ return result;
+}
+
+//
+ASDCP::Result_t
+GenericSoundEssenceDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = FileDescriptor::WriteToTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(GenericSoundEssenceDescriptor, AudioSamplingRate));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi8(OBJ_WRITE_ARGS(GenericSoundEssenceDescriptor, Locked));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi8(OBJ_WRITE_ARGS(GenericSoundEssenceDescriptor, AudioRefLevel));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(GenericSoundEssenceDescriptor, ChannelCount));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(GenericSoundEssenceDescriptor, QuantizationBits));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi8(OBJ_WRITE_ARGS(GenericSoundEssenceDescriptor, DialNorm));
+ return result;
+}
+
+//
+void
+GenericSoundEssenceDescriptor::Copy(const GenericSoundEssenceDescriptor& rhs)
+{
+ FileDescriptor::Copy(rhs);
+ AudioSamplingRate = rhs.AudioSamplingRate;
+ Locked = rhs.Locked;
+ AudioRefLevel = rhs.AudioRefLevel;
+ ChannelCount = rhs.ChannelCount;
+ QuantizationBits = rhs.QuantizationBits;
+ DialNorm = rhs.DialNorm;
+}
+
+//
+void
+GenericSoundEssenceDescriptor::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+ *identbuf = 0;
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ FileDescriptor::Dump(stream);
+ 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);
+ fprintf(stream, " %22s = %d\n", "QuantizationBits", QuantizationBits);
+ fprintf(stream, " %22s = %d\n", "DialNorm", DialNorm);
+}
+
+//
+ASDCP::Result_t
+GenericSoundEssenceDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+GenericSoundEssenceDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return InterchangeObject::WriteToBuffer(Buffer);
+}
+
+//------------------------------------------------------------------------------------------
+// WaveAudioDescriptor
+
+//
+
+WaveAudioDescriptor::WaveAudioDescriptor(const Dictionary*& d) : GenericSoundEssenceDescriptor(d), m_Dict(d), BlockAlign(0), SequenceOffset(0), AvgBps(0)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_WaveAudioDescriptor);
+}
+
+WaveAudioDescriptor::WaveAudioDescriptor(const WaveAudioDescriptor& rhs) : GenericSoundEssenceDescriptor(rhs.m_Dict), m_Dict(rhs.m_Dict)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_WaveAudioDescriptor);
+ Copy(rhs);
+}
+
+
+//
+ASDCP::Result_t
+WaveAudioDescriptor::InitFromTLVSet(TLVReader& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = GenericSoundEssenceDescriptor::InitFromTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi16(OBJ_READ_ARGS(WaveAudioDescriptor, BlockAlign));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi8(OBJ_READ_ARGS(WaveAudioDescriptor, SequenceOffset));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(WaveAudioDescriptor, AvgBps));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(WaveAudioDescriptor, ChannelAssignment));
+ return result;
+}
+
+//
+ASDCP::Result_t
+WaveAudioDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = GenericSoundEssenceDescriptor::WriteToTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi16(OBJ_WRITE_ARGS(WaveAudioDescriptor, BlockAlign));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi8(OBJ_WRITE_ARGS(WaveAudioDescriptor, SequenceOffset));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(WaveAudioDescriptor, AvgBps));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(WaveAudioDescriptor, ChannelAssignment));
+ return result;
+}
+
+//
+void
+WaveAudioDescriptor::Copy(const WaveAudioDescriptor& rhs)
+{
+ GenericSoundEssenceDescriptor::Copy(rhs);
+ BlockAlign = rhs.BlockAlign;
+ SequenceOffset = rhs.SequenceOffset;
+ AvgBps = rhs.AvgBps;
+ ChannelAssignment = rhs.ChannelAssignment;
+}
+
+//
+void
+WaveAudioDescriptor::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+ *identbuf = 0;
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ GenericSoundEssenceDescriptor::Dump(stream);
+ fprintf(stream, " %22s = %d\n", "BlockAlign", BlockAlign);
+ fprintf(stream, " %22s = %d\n", "SequenceOffset", SequenceOffset);
+ fprintf(stream, " %22s = %d\n", "AvgBps", AvgBps);
+ fprintf(stream, " %22s = %s\n", "ChannelAssignment", ChannelAssignment.EncodeString(identbuf, IdentBufferLen));
+}
+
+//
+ASDCP::Result_t
+WaveAudioDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+WaveAudioDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return InterchangeObject::WriteToBuffer(Buffer);
+}
+
+//------------------------------------------------------------------------------------------
+// GenericPictureEssenceDescriptor
+
+//
+
+GenericPictureEssenceDescriptor::GenericPictureEssenceDescriptor(const Dictionary*& d) : FileDescriptor(d), m_Dict(d), FrameLayout(0), StoredWidth(0), StoredHeight(0)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_GenericPictureEssenceDescriptor);
+}
+
+GenericPictureEssenceDescriptor::GenericPictureEssenceDescriptor(const GenericPictureEssenceDescriptor& rhs) : FileDescriptor(rhs.m_Dict), m_Dict(rhs.m_Dict)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_GenericPictureEssenceDescriptor);
+ Copy(rhs);
+}
+
+
+//
+ASDCP::Result_t
+GenericPictureEssenceDescriptor::InitFromTLVSet(TLVReader& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = FileDescriptor::InitFromTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi8(OBJ_READ_ARGS(GenericPictureEssenceDescriptor, FrameLayout));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(GenericPictureEssenceDescriptor, StoredWidth));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(GenericPictureEssenceDescriptor, StoredHeight));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(GenericPictureEssenceDescriptor, AspectRatio));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(GenericPictureEssenceDescriptor, PictureEssenceCoding));
+ return result;
+}
+
+//
+ASDCP::Result_t
+GenericPictureEssenceDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = FileDescriptor::WriteToTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi8(OBJ_WRITE_ARGS(GenericPictureEssenceDescriptor, FrameLayout));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(GenericPictureEssenceDescriptor, StoredWidth));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(GenericPictureEssenceDescriptor, StoredHeight));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(GenericPictureEssenceDescriptor, AspectRatio));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(GenericPictureEssenceDescriptor, PictureEssenceCoding));
+ return result;
+}
+
+//
+void
+GenericPictureEssenceDescriptor::Copy(const GenericPictureEssenceDescriptor& rhs)
+{
+ FileDescriptor::Copy(rhs);
+ FrameLayout = rhs.FrameLayout;
+ StoredWidth = rhs.StoredWidth;
+ StoredHeight = rhs.StoredHeight;
+ AspectRatio = rhs.AspectRatio;
+ PictureEssenceCoding = rhs.PictureEssenceCoding;
+}
+
+//
+void
+GenericPictureEssenceDescriptor::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+ *identbuf = 0;
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ FileDescriptor::Dump(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.EncodeString(identbuf, IdentBufferLen));
+ fprintf(stream, " %22s = %s\n", "PictureEssenceCoding", PictureEssenceCoding.EncodeString(identbuf, IdentBufferLen));
+}
+
+//
+ASDCP::Result_t
+GenericPictureEssenceDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+GenericPictureEssenceDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return InterchangeObject::WriteToBuffer(Buffer);
+}
+
+//------------------------------------------------------------------------------------------
+// RGBAEssenceDescriptor
+
+//
+
+RGBAEssenceDescriptor::RGBAEssenceDescriptor(const Dictionary*& d) : GenericPictureEssenceDescriptor(d), m_Dict(d), ComponentMaxRef(0), ComponentMinRef(0)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_RGBAEssenceDescriptor);
+}
+
+RGBAEssenceDescriptor::RGBAEssenceDescriptor(const RGBAEssenceDescriptor& rhs) : GenericPictureEssenceDescriptor(rhs.m_Dict), m_Dict(rhs.m_Dict)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_RGBAEssenceDescriptor);
+ Copy(rhs);
+}
+
+
+//
+ASDCP::Result_t
+RGBAEssenceDescriptor::InitFromTLVSet(TLVReader& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = GenericPictureEssenceDescriptor::InitFromTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(RGBAEssenceDescriptor, ComponentMaxRef));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(RGBAEssenceDescriptor, ComponentMinRef));
+ return result;
+}
+
+//
+ASDCP::Result_t
+RGBAEssenceDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = GenericPictureEssenceDescriptor::WriteToTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(RGBAEssenceDescriptor, ComponentMaxRef));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(RGBAEssenceDescriptor, ComponentMinRef));
+ return result;
+}
+
+//
+void
+RGBAEssenceDescriptor::Copy(const RGBAEssenceDescriptor& rhs)
+{
+ GenericPictureEssenceDescriptor::Copy(rhs);
+ ComponentMaxRef = rhs.ComponentMaxRef;
+ ComponentMinRef = rhs.ComponentMinRef;
+}
+
+//
+void
+RGBAEssenceDescriptor::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+ *identbuf = 0;
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ GenericPictureEssenceDescriptor::Dump(stream);
+ fprintf(stream, " %22s = %d\n", "ComponentMaxRef", ComponentMaxRef);
+ fprintf(stream, " %22s = %d\n", "ComponentMinRef", ComponentMinRef);
+}
+
+//
+ASDCP::Result_t
+RGBAEssenceDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+RGBAEssenceDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return InterchangeObject::WriteToBuffer(Buffer);
+}
+
+//------------------------------------------------------------------------------------------
+// JPEG2000PictureSubDescriptor
+
+//
+
+JPEG2000PictureSubDescriptor::JPEG2000PictureSubDescriptor(const Dictionary*& d) : InterchangeObject(d), m_Dict(d), Rsize(0), Xsize(0), Ysize(0), XOsize(0), YOsize(0), XTsize(0), YTsize(0), XTOsize(0), YTOsize(0), Csize(0)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_JPEG2000PictureSubDescriptor);
+}
+
+JPEG2000PictureSubDescriptor::JPEG2000PictureSubDescriptor(const JPEG2000PictureSubDescriptor& rhs) : InterchangeObject(rhs.m_Dict), m_Dict(rhs.m_Dict)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_JPEG2000PictureSubDescriptor);
+ Copy(rhs);
+}
+
+
+//
+ASDCP::Result_t
+JPEG2000PictureSubDescriptor::InitFromTLVSet(TLVReader& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = InterchangeObject::InitFromTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi16(OBJ_READ_ARGS(JPEG2000PictureSubDescriptor, Rsize));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(JPEG2000PictureSubDescriptor, Xsize));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(JPEG2000PictureSubDescriptor, Ysize));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(JPEG2000PictureSubDescriptor, XOsize));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(JPEG2000PictureSubDescriptor, YOsize));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(JPEG2000PictureSubDescriptor, XTsize));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(JPEG2000PictureSubDescriptor, YTsize));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(JPEG2000PictureSubDescriptor, XTOsize));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(JPEG2000PictureSubDescriptor, YTOsize));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi16(OBJ_READ_ARGS(JPEG2000PictureSubDescriptor, Csize));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(JPEG2000PictureSubDescriptor, PictureComponentSizing));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(JPEG2000PictureSubDescriptor, CodingStyleDefault));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(JPEG2000PictureSubDescriptor, QuantizationDefault));
+ return result;
+}
+
+//
+ASDCP::Result_t
+JPEG2000PictureSubDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = InterchangeObject::WriteToTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi16(OBJ_WRITE_ARGS(JPEG2000PictureSubDescriptor, Rsize));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(JPEG2000PictureSubDescriptor, Xsize));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(JPEG2000PictureSubDescriptor, Ysize));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(JPEG2000PictureSubDescriptor, XOsize));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(JPEG2000PictureSubDescriptor, YOsize));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(JPEG2000PictureSubDescriptor, XTsize));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(JPEG2000PictureSubDescriptor, YTsize));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(JPEG2000PictureSubDescriptor, XTOsize));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(JPEG2000PictureSubDescriptor, YTOsize));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi16(OBJ_WRITE_ARGS(JPEG2000PictureSubDescriptor, Csize));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(JPEG2000PictureSubDescriptor, PictureComponentSizing));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(JPEG2000PictureSubDescriptor, CodingStyleDefault));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(JPEG2000PictureSubDescriptor, QuantizationDefault));
+ return result;
+}
+
+//
+void
+JPEG2000PictureSubDescriptor::Copy(const JPEG2000PictureSubDescriptor& rhs)
+{
+ InterchangeObject::Copy(rhs);
+ Rsize = rhs.Rsize;
+ Xsize = rhs.Xsize;
+ Ysize = rhs.Ysize;
+ XOsize = rhs.XOsize;
+ YOsize = rhs.YOsize;
+ XTsize = rhs.XTsize;
+ YTsize = rhs.YTsize;
+ XTOsize = rhs.XTOsize;
+ YTOsize = rhs.YTOsize;
+ Csize = rhs.Csize;
+ PictureComponentSizing = rhs.PictureComponentSizing;
+ CodingStyleDefault = rhs.CodingStyleDefault;
+ QuantizationDefault = rhs.QuantizationDefault;
+}
+
+//
+void
+JPEG2000PictureSubDescriptor::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+ *identbuf = 0;
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ InterchangeObject::Dump(stream);
+ fprintf(stream, " %22s = %d\n", "Rsize", Rsize);
+ fprintf(stream, " %22s = %d\n", "Xsize", Xsize);
+ fprintf(stream, " %22s = %d\n", "Ysize", Ysize);
+ fprintf(stream, " %22s = %d\n", "XOsize", XOsize);
+ fprintf(stream, " %22s = %d\n", "YOsize", YOsize);
+ fprintf(stream, " %22s = %d\n", "XTsize", XTsize);
+ fprintf(stream, " %22s = %d\n", "YTsize", YTsize);
+ 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.EncodeString(identbuf, IdentBufferLen));
+ fprintf(stream, " %22s = %s\n", "CodingStyleDefault", CodingStyleDefault.EncodeString(identbuf, IdentBufferLen));
+ fprintf(stream, " %22s = %s\n", "QuantizationDefault", QuantizationDefault.EncodeString(identbuf, IdentBufferLen));
+}
+
+//
+ASDCP::Result_t
+JPEG2000PictureSubDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+JPEG2000PictureSubDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return InterchangeObject::WriteToBuffer(Buffer);
+}
+
+//------------------------------------------------------------------------------------------
+// CDCIEssenceDescriptor
+
+//
+
+CDCIEssenceDescriptor::CDCIEssenceDescriptor(const Dictionary*& d) : GenericPictureEssenceDescriptor(d), m_Dict(d), ComponentDepth(0), HorizontalSubsampling(0), VerticalSubsampling(0), ColorSiting(0)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_CDCIEssenceDescriptor);
+}
+
+CDCIEssenceDescriptor::CDCIEssenceDescriptor(const CDCIEssenceDescriptor& rhs) : GenericPictureEssenceDescriptor(rhs.m_Dict), m_Dict(rhs.m_Dict)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_CDCIEssenceDescriptor);
+ Copy(rhs);
+}
+
+
+//
+ASDCP::Result_t
+CDCIEssenceDescriptor::InitFromTLVSet(TLVReader& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = GenericPictureEssenceDescriptor::InitFromTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(CDCIEssenceDescriptor, ComponentDepth));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(CDCIEssenceDescriptor, HorizontalSubsampling));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(CDCIEssenceDescriptor, VerticalSubsampling));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi8(OBJ_READ_ARGS(CDCIEssenceDescriptor, ColorSiting));
+ return result;
+}
+
+//
+ASDCP::Result_t
+CDCIEssenceDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = GenericPictureEssenceDescriptor::WriteToTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(CDCIEssenceDescriptor, ComponentDepth));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(CDCIEssenceDescriptor, HorizontalSubsampling));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(CDCIEssenceDescriptor, VerticalSubsampling));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi8(OBJ_WRITE_ARGS(CDCIEssenceDescriptor, ColorSiting));
+ return result;
+}
+
+//
+void
+CDCIEssenceDescriptor::Copy(const CDCIEssenceDescriptor& rhs)
+{
+ GenericPictureEssenceDescriptor::Copy(rhs);
+ ComponentDepth = rhs.ComponentDepth;
+ HorizontalSubsampling = rhs.HorizontalSubsampling;
+ VerticalSubsampling = rhs.VerticalSubsampling;
+ ColorSiting = rhs.ColorSiting;
+}
+
+//
+void
+CDCIEssenceDescriptor::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+ *identbuf = 0;
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ GenericPictureEssenceDescriptor::Dump(stream);
+ fprintf(stream, " %22s = %d\n", "ComponentDepth", ComponentDepth);
+ fprintf(stream, " %22s = %d\n", "HorizontalSubsampling", HorizontalSubsampling);
+ fprintf(stream, " %22s = %d\n", "VerticalSubsampling", VerticalSubsampling);
+ fprintf(stream, " %22s = %d\n", "ColorSiting", ColorSiting);
+}
+
+//
+ASDCP::Result_t
+CDCIEssenceDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+CDCIEssenceDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return InterchangeObject::WriteToBuffer(Buffer);
+}
+
+//------------------------------------------------------------------------------------------
+// MPEG2VideoDescriptor
+
+//
+
+MPEG2VideoDescriptor::MPEG2VideoDescriptor(const Dictionary*& d) : CDCIEssenceDescriptor(d), m_Dict(d), CodedContentType(0), LowDelay(0), BitRate(0), ProfileAndLevel(0)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_MPEG2VideoDescriptor);
+}
+
+MPEG2VideoDescriptor::MPEG2VideoDescriptor(const MPEG2VideoDescriptor& rhs) : CDCIEssenceDescriptor(rhs.m_Dict), m_Dict(rhs.m_Dict)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_MPEG2VideoDescriptor);
+ Copy(rhs);
+}
+
+
+//
+ASDCP::Result_t
+MPEG2VideoDescriptor::InitFromTLVSet(TLVReader& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = CDCIEssenceDescriptor::InitFromTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi8(OBJ_READ_ARGS(MPEG2VideoDescriptor, CodedContentType));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi8(OBJ_READ_ARGS(MPEG2VideoDescriptor, LowDelay));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(MPEG2VideoDescriptor, BitRate));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi8(OBJ_READ_ARGS(MPEG2VideoDescriptor, ProfileAndLevel));
+ return result;
+}
+
+//
+ASDCP::Result_t
+MPEG2VideoDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = CDCIEssenceDescriptor::WriteToTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi8(OBJ_WRITE_ARGS(MPEG2VideoDescriptor, CodedContentType));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi8(OBJ_WRITE_ARGS(MPEG2VideoDescriptor, LowDelay));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(MPEG2VideoDescriptor, BitRate));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi8(OBJ_WRITE_ARGS(MPEG2VideoDescriptor, ProfileAndLevel));
+ return result;
+}
+
+//
+void
+MPEG2VideoDescriptor::Copy(const MPEG2VideoDescriptor& rhs)
+{
+ CDCIEssenceDescriptor::Copy(rhs);
+ CodedContentType = rhs.CodedContentType;
+ LowDelay = rhs.LowDelay;
+ BitRate = rhs.BitRate;
+ ProfileAndLevel = rhs.ProfileAndLevel;
+}
+
+//
+void
+MPEG2VideoDescriptor::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+ *identbuf = 0;
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ CDCIEssenceDescriptor::Dump(stream);
+ fprintf(stream, " %22s = %d\n", "CodedContentType", CodedContentType);
+ fprintf(stream, " %22s = %d\n", "LowDelay", LowDelay);
+ fprintf(stream, " %22s = %d\n", "BitRate", BitRate);
+ fprintf(stream, " %22s = %d\n", "ProfileAndLevel", ProfileAndLevel);
+}
+
+//
+ASDCP::Result_t
+MPEG2VideoDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+MPEG2VideoDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return InterchangeObject::WriteToBuffer(Buffer);
+}
+
+//------------------------------------------------------------------------------------------
+// DMSegment
+
+//
+
+DMSegment::DMSegment(const Dictionary*& d) : InterchangeObject(d), m_Dict(d), EventStartPosition(0), Duration(0)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_DMSegment);
+}
+
+DMSegment::DMSegment(const DMSegment& rhs) : InterchangeObject(rhs.m_Dict), m_Dict(rhs.m_Dict)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_DMSegment);
+ Copy(rhs);
+}
+
+
+//
+ASDCP::Result_t
+DMSegment::InitFromTLVSet(TLVReader& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = InterchangeObject::InitFromTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(DMSegment, DataDefinition));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi64(OBJ_READ_ARGS(DMSegment, EventStartPosition));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi64(OBJ_READ_ARGS(DMSegment, Duration));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(DMSegment, EventComment));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(DMSegment, DMFramework));
+ return result;
+}
+
+//
+ASDCP::Result_t
+DMSegment::WriteToTLVSet(TLVWriter& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = InterchangeObject::WriteToTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(DMSegment, DataDefinition));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi64(OBJ_WRITE_ARGS(DMSegment, EventStartPosition));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi64(OBJ_WRITE_ARGS(DMSegment, Duration));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(DMSegment, EventComment));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(DMSegment, DMFramework));
+ return result;
+}
+
+//
+void
+DMSegment::Copy(const DMSegment& rhs)
+{
+ InterchangeObject::Copy(rhs);
+ DataDefinition = rhs.DataDefinition;
+ EventStartPosition = rhs.EventStartPosition;
+ Duration = rhs.Duration;
+ EventComment = rhs.EventComment;
+ DMFramework = rhs.DMFramework;
+}
+
+//
+void
+DMSegment::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+ *identbuf = 0;
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ InterchangeObject::Dump(stream);
+ fprintf(stream, " %22s = %s\n", "DataDefinition", DataDefinition.EncodeString(identbuf, IdentBufferLen));
+ fprintf(stream, " %22s = %s\n", "EventStartPosition", i64sz(EventStartPosition, identbuf));
+ fprintf(stream, " %22s = %s\n", "Duration", i64sz(Duration, identbuf));
+ fprintf(stream, " %22s = %s\n", "EventComment", EventComment.EncodeString(identbuf, IdentBufferLen));
+ fprintf(stream, " %22s = %s\n", "DMFramework", DMFramework.EncodeString(identbuf, IdentBufferLen));
+}
+
+//
+ASDCP::Result_t
+DMSegment::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+DMSegment::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return InterchangeObject::WriteToBuffer(Buffer);
+}
+
+//------------------------------------------------------------------------------------------
+// CryptographicFramework
+
+//
+
+CryptographicFramework::CryptographicFramework(const Dictionary*& d) : InterchangeObject(d), m_Dict(d)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_CryptographicFramework);
+}
+
+CryptographicFramework::CryptographicFramework(const CryptographicFramework& rhs) : InterchangeObject(rhs.m_Dict), m_Dict(rhs.m_Dict)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_CryptographicFramework);
+ Copy(rhs);
+}
+
+
+//
+ASDCP::Result_t
+CryptographicFramework::InitFromTLVSet(TLVReader& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = InterchangeObject::InitFromTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(CryptographicFramework, ContextSR));
+ return result;
+}
+
+//
+ASDCP::Result_t
+CryptographicFramework::WriteToTLVSet(TLVWriter& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = InterchangeObject::WriteToTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(CryptographicFramework, ContextSR));
+ return result;
+}
+
+//
+void
+CryptographicFramework::Copy(const CryptographicFramework& rhs)
+{
+ InterchangeObject::Copy(rhs);
+ ContextSR = rhs.ContextSR;
+}
+
+//
+void
+CryptographicFramework::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+ *identbuf = 0;
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ InterchangeObject::Dump(stream);
+ fprintf(stream, " %22s = %s\n", "ContextSR", ContextSR.EncodeString(identbuf, IdentBufferLen));
+}
+
+//
+ASDCP::Result_t
+CryptographicFramework::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+CryptographicFramework::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return InterchangeObject::WriteToBuffer(Buffer);
+}
+
+//------------------------------------------------------------------------------------------
+// CryptographicContext
+
+//
+
+CryptographicContext::CryptographicContext(const Dictionary*& d) : InterchangeObject(d), m_Dict(d)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_CryptographicContext);
+}
+
+CryptographicContext::CryptographicContext(const CryptographicContext& rhs) : InterchangeObject(rhs.m_Dict), m_Dict(rhs.m_Dict)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_CryptographicContext);
+ Copy(rhs);
+}
+
+
+//
+ASDCP::Result_t
+CryptographicContext::InitFromTLVSet(TLVReader& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = InterchangeObject::InitFromTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(CryptographicContext, ContextID));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(CryptographicContext, SourceEssenceContainer));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(CryptographicContext, CipherAlgorithm));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(CryptographicContext, MICAlgorithm));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(CryptographicContext, CryptographicKeyID));
+ return result;
+}
+
+//
+ASDCP::Result_t
+CryptographicContext::WriteToTLVSet(TLVWriter& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = InterchangeObject::WriteToTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(CryptographicContext, ContextID));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(CryptographicContext, SourceEssenceContainer));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(CryptographicContext, CipherAlgorithm));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(CryptographicContext, MICAlgorithm));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(CryptographicContext, CryptographicKeyID));
+ return result;
+}
+
+//
+void
+CryptographicContext::Copy(const CryptographicContext& rhs)
+{
+ InterchangeObject::Copy(rhs);
+ ContextID = rhs.ContextID;
+ SourceEssenceContainer = rhs.SourceEssenceContainer;
+ CipherAlgorithm = rhs.CipherAlgorithm;
+ MICAlgorithm = rhs.MICAlgorithm;
+ CryptographicKeyID = rhs.CryptographicKeyID;
+}
+
+//
+void
+CryptographicContext::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+ *identbuf = 0;
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ InterchangeObject::Dump(stream);
+ 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));
+}
+
+//
+ASDCP::Result_t
+CryptographicContext::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+CryptographicContext::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return InterchangeObject::WriteToBuffer(Buffer);
+}
+
+//------------------------------------------------------------------------------------------
+// GenericDataEssenceDescriptor
+
+//
+
+GenericDataEssenceDescriptor::GenericDataEssenceDescriptor(const Dictionary*& d) : FileDescriptor(d), m_Dict(d)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_GenericDataEssenceDescriptor);
+}
+
+GenericDataEssenceDescriptor::GenericDataEssenceDescriptor(const GenericDataEssenceDescriptor& rhs) : FileDescriptor(rhs.m_Dict), m_Dict(rhs.m_Dict)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_GenericDataEssenceDescriptor);
+ Copy(rhs);
+}
+
+
+//
+ASDCP::Result_t
+GenericDataEssenceDescriptor::InitFromTLVSet(TLVReader& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = FileDescriptor::InitFromTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(GenericDataEssenceDescriptor, DataEssenceCoding));
+ return result;
+}
+
+//
+ASDCP::Result_t
+GenericDataEssenceDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = FileDescriptor::WriteToTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(GenericDataEssenceDescriptor, DataEssenceCoding));
+ return result;
+}
+
+//
+void
+GenericDataEssenceDescriptor::Copy(const GenericDataEssenceDescriptor& rhs)
+{
+ FileDescriptor::Copy(rhs);
+ DataEssenceCoding = rhs.DataEssenceCoding;
+}
+
+//
+void
+GenericDataEssenceDescriptor::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+ *identbuf = 0;
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ FileDescriptor::Dump(stream);
+ fprintf(stream, " %22s = %s\n", "DataEssenceCoding", DataEssenceCoding.EncodeString(identbuf, IdentBufferLen));
+}
+
+//
+ASDCP::Result_t
+GenericDataEssenceDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+GenericDataEssenceDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return InterchangeObject::WriteToBuffer(Buffer);
+}
+
+//------------------------------------------------------------------------------------------
+// TimedTextDescriptor
+
+//
+
+TimedTextDescriptor::TimedTextDescriptor(const Dictionary*& d) : GenericDataEssenceDescriptor(d), m_Dict(d)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_TimedTextDescriptor);
+}
+
+TimedTextDescriptor::TimedTextDescriptor(const TimedTextDescriptor& rhs) : GenericDataEssenceDescriptor(rhs.m_Dict), m_Dict(rhs.m_Dict)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_TimedTextDescriptor);
+ Copy(rhs);
+}
+
+
+//
+ASDCP::Result_t
+TimedTextDescriptor::InitFromTLVSet(TLVReader& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = GenericDataEssenceDescriptor::InitFromTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(TimedTextDescriptor, ResourceID));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(TimedTextDescriptor, UCSEncoding));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(TimedTextDescriptor, NamespaceURI));
+ return result;
+}
+
+//
+ASDCP::Result_t
+TimedTextDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = GenericDataEssenceDescriptor::WriteToTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(TimedTextDescriptor, ResourceID));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(TimedTextDescriptor, UCSEncoding));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(TimedTextDescriptor, NamespaceURI));
+ return result;
+}
+
+//
+void
+TimedTextDescriptor::Copy(const TimedTextDescriptor& rhs)
+{
+ GenericDataEssenceDescriptor::Copy(rhs);
+ ResourceID = rhs.ResourceID;
+ UCSEncoding = rhs.UCSEncoding;
+ NamespaceURI = rhs.NamespaceURI;
+}
+
+//
+void
+TimedTextDescriptor::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+ *identbuf = 0;
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ GenericDataEssenceDescriptor::Dump(stream);
+ fprintf(stream, " %22s = %s\n", "ResourceID", ResourceID.EncodeString(identbuf, IdentBufferLen));
+ fprintf(stream, " %22s = %s\n", "UCSEncoding", UCSEncoding.EncodeString(identbuf, IdentBufferLen));
+ fprintf(stream, " %22s = %s\n", "NamespaceURI", NamespaceURI.EncodeString(identbuf, IdentBufferLen));
+}
+
+//
+ASDCP::Result_t
+TimedTextDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+TimedTextDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return InterchangeObject::WriteToBuffer(Buffer);
+}
+
+//------------------------------------------------------------------------------------------
+// TimedTextResourceSubDescriptor
+
+//
+
+TimedTextResourceSubDescriptor::TimedTextResourceSubDescriptor(const Dictionary*& d) : InterchangeObject(d), m_Dict(d), EssenceStreamID(0)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_TimedTextResourceSubDescriptor);
+}
+
+TimedTextResourceSubDescriptor::TimedTextResourceSubDescriptor(const TimedTextResourceSubDescriptor& rhs) : InterchangeObject(rhs.m_Dict), m_Dict(rhs.m_Dict)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_TimedTextResourceSubDescriptor);
+ Copy(rhs);
+}
+
+
+//
+ASDCP::Result_t
+TimedTextResourceSubDescriptor::InitFromTLVSet(TLVReader& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = InterchangeObject::InitFromTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(TimedTextResourceSubDescriptor, AncillaryResourceID));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(TimedTextResourceSubDescriptor, MIMEMediaType));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(TimedTextResourceSubDescriptor, EssenceStreamID));
+ return result;
+}
+
+//
+ASDCP::Result_t
+TimedTextResourceSubDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = InterchangeObject::WriteToTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(TimedTextResourceSubDescriptor, AncillaryResourceID));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(TimedTextResourceSubDescriptor, MIMEMediaType));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(TimedTextResourceSubDescriptor, EssenceStreamID));
+ return result;
+}
+
+//
+void
+TimedTextResourceSubDescriptor::Copy(const TimedTextResourceSubDescriptor& rhs)
+{
+ InterchangeObject::Copy(rhs);
+ AncillaryResourceID = rhs.AncillaryResourceID;
+ MIMEMediaType = rhs.MIMEMediaType;
+ EssenceStreamID = rhs.EssenceStreamID;
+}
+
+//
+void
+TimedTextResourceSubDescriptor::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+ *identbuf = 0;
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ InterchangeObject::Dump(stream);
+ fprintf(stream, " %22s = %s\n", "AncillaryResourceID", AncillaryResourceID.EncodeString(identbuf, IdentBufferLen));
+ fprintf(stream, " %22s = %s\n", "MIMEMediaType", MIMEMediaType.EncodeString(identbuf, IdentBufferLen));
+ fprintf(stream, " %22s = %d\n", "EssenceStreamID", EssenceStreamID);
+}
+
+//
+ASDCP::Result_t
+TimedTextResourceSubDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+TimedTextResourceSubDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return InterchangeObject::WriteToBuffer(Buffer);
+}
+
+//------------------------------------------------------------------------------------------
+// StereoscopicPictureSubDescriptor
+
+//
+
+StereoscopicPictureSubDescriptor::StereoscopicPictureSubDescriptor(const Dictionary*& d) : InterchangeObject(d), m_Dict(d)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_StereoscopicPictureSubDescriptor);
+}
+
+StereoscopicPictureSubDescriptor::StereoscopicPictureSubDescriptor(const StereoscopicPictureSubDescriptor& rhs) : InterchangeObject(rhs.m_Dict), m_Dict(rhs.m_Dict)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_StereoscopicPictureSubDescriptor);
+ Copy(rhs);
+}
+
+
+//
+ASDCP::Result_t
+StereoscopicPictureSubDescriptor::InitFromTLVSet(TLVReader& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = InterchangeObject::InitFromTLVSet(TLVSet);
+ return result;
+}
+
+//
+ASDCP::Result_t
+StereoscopicPictureSubDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = InterchangeObject::WriteToTLVSet(TLVSet);
+ return result;
+}
+
+//
+void
+StereoscopicPictureSubDescriptor::Copy(const StereoscopicPictureSubDescriptor& rhs)
+{
+ InterchangeObject::Copy(rhs);
+}
+
+//
+void
+StereoscopicPictureSubDescriptor::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+ *identbuf = 0;
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ InterchangeObject::Dump(stream);
+}
+
+//
+ASDCP::Result_t
+StereoscopicPictureSubDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+StereoscopicPictureSubDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return InterchangeObject::WriteToBuffer(Buffer);
+}
+
+//------------------------------------------------------------------------------------------
+// NetworkLocator
+
+//
+
+NetworkLocator::NetworkLocator(const Dictionary*& d) : InterchangeObject(d), m_Dict(d)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_NetworkLocator);
+}
+
+NetworkLocator::NetworkLocator(const NetworkLocator& rhs) : InterchangeObject(rhs.m_Dict), m_Dict(rhs.m_Dict)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_NetworkLocator);
+ Copy(rhs);
+}
+
+
+//
+ASDCP::Result_t
+NetworkLocator::InitFromTLVSet(TLVReader& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = InterchangeObject::InitFromTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(NetworkLocator, URLString));
+ return result;
+}
+
+//
+ASDCP::Result_t
+NetworkLocator::WriteToTLVSet(TLVWriter& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = InterchangeObject::WriteToTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(NetworkLocator, URLString));
+ return result;
+}
+
+//
+void
+NetworkLocator::Copy(const NetworkLocator& rhs)
+{
+ InterchangeObject::Copy(rhs);
+ URLString = rhs.URLString;
+}
+
+//
+void
+NetworkLocator::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+ *identbuf = 0;
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ InterchangeObject::Dump(stream);
+ fprintf(stream, " %22s = %s\n", "URLString", URLString.EncodeString(identbuf, IdentBufferLen));
+}
+
+//
+ASDCP::Result_t
+NetworkLocator::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+NetworkLocator::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return InterchangeObject::WriteToBuffer(Buffer);
+}
+
+//------------------------------------------------------------------------------------------
+// MCALabelSubDescriptor
+
+//
+
+MCALabelSubDescriptor::MCALabelSubDescriptor(const Dictionary*& d) : InterchangeObject(d), m_Dict(d), MCAChannelID(0)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_MCALabelSubDescriptor);
+}
+
+MCALabelSubDescriptor::MCALabelSubDescriptor(const MCALabelSubDescriptor& rhs) : InterchangeObject(rhs.m_Dict), m_Dict(rhs.m_Dict)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_MCALabelSubDescriptor);
+ Copy(rhs);
+}
+
+
+//
+ASDCP::Result_t
+MCALabelSubDescriptor::InitFromTLVSet(TLVReader& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = InterchangeObject::InitFromTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(MCALabelSubDescriptor, MCALabelDictionaryID));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(MCALabelSubDescriptor, MCALinkID));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(MCALabelSubDescriptor, MCATagSymbol));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(MCALabelSubDescriptor, MCATagName));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(MCALabelSubDescriptor, MCAChannelID));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(MCALabelSubDescriptor, RFC5646SpokenLanguage));
+ return result;
+}
+
+//
+ASDCP::Result_t
+MCALabelSubDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = InterchangeObject::WriteToTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(MCALabelSubDescriptor, MCALabelDictionaryID));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(MCALabelSubDescriptor, MCALinkID));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(MCALabelSubDescriptor, MCATagSymbol));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(MCALabelSubDescriptor, MCATagName));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(MCALabelSubDescriptor, MCAChannelID));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(MCALabelSubDescriptor, RFC5646SpokenLanguage));
+ return result;
+}
+
+//
+void
+MCALabelSubDescriptor::Copy(const MCALabelSubDescriptor& rhs)
+{
+ InterchangeObject::Copy(rhs);
+ MCALabelDictionaryID = rhs.MCALabelDictionaryID;
+ MCALinkID = rhs.MCALinkID;
+ MCATagSymbol = rhs.MCATagSymbol;
+ MCATagName = rhs.MCATagName;
+ MCAChannelID = rhs.MCAChannelID;
+ RFC5646SpokenLanguage = rhs.RFC5646SpokenLanguage;
+}
+
+//
+void
+MCALabelSubDescriptor::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+ *identbuf = 0;
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ InterchangeObject::Dump(stream);
+ fprintf(stream, " %22s = %s\n", "MCALabelDictionaryID", MCALabelDictionaryID.EncodeString(identbuf, IdentBufferLen));
+ fprintf(stream, " %22s = %s\n", "MCALinkID", MCALinkID.EncodeString(identbuf, IdentBufferLen));
+ fprintf(stream, " %22s = %s\n", "MCATagSymbol", MCATagSymbol.EncodeString(identbuf, IdentBufferLen));
+ fprintf(stream, " %22s = %s\n", "MCATagName", MCATagName.EncodeString(identbuf, IdentBufferLen));
+ fprintf(stream, " %22s = %d\n", "MCAChannelID", MCAChannelID);
+ fprintf(stream, " %22s = %s\n", "RFC5646SpokenLanguage", RFC5646SpokenLanguage.EncodeString(identbuf, IdentBufferLen));
+}
+
+//
+ASDCP::Result_t
+MCALabelSubDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+MCALabelSubDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return InterchangeObject::WriteToBuffer(Buffer);
+}
+
+//------------------------------------------------------------------------------------------
+// AudioChannelLabelSubDescriptor
+
+//
+
+AudioChannelLabelSubDescriptor::AudioChannelLabelSubDescriptor(const Dictionary*& d) : MCALabelSubDescriptor(d), m_Dict(d)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_AudioChannelLabelSubDescriptor);
+}
+
+AudioChannelLabelSubDescriptor::AudioChannelLabelSubDescriptor(const AudioChannelLabelSubDescriptor& rhs) : MCALabelSubDescriptor(rhs.m_Dict), m_Dict(rhs.m_Dict)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_AudioChannelLabelSubDescriptor);
+ Copy(rhs);
+}
+
+
+//
+ASDCP::Result_t
+AudioChannelLabelSubDescriptor::InitFromTLVSet(TLVReader& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = MCALabelSubDescriptor::InitFromTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(AudioChannelLabelSubDescriptor, SoundfieldGroupLinkID));
+ return result;
+}
+
+//
+ASDCP::Result_t
+AudioChannelLabelSubDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = MCALabelSubDescriptor::WriteToTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(AudioChannelLabelSubDescriptor, SoundfieldGroupLinkID));
+ return result;
+}
+
+//
+void
+AudioChannelLabelSubDescriptor::Copy(const AudioChannelLabelSubDescriptor& rhs)
+{
+ MCALabelSubDescriptor::Copy(rhs);
+ SoundfieldGroupLinkID = rhs.SoundfieldGroupLinkID;
+}
+
+//
+void
+AudioChannelLabelSubDescriptor::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+ *identbuf = 0;
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ MCALabelSubDescriptor::Dump(stream);
+ fprintf(stream, " %22s = %s\n", "SoundfieldGroupLinkID", SoundfieldGroupLinkID.EncodeString(identbuf, IdentBufferLen));
+}
+
+//
+ASDCP::Result_t
+AudioChannelLabelSubDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+AudioChannelLabelSubDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return InterchangeObject::WriteToBuffer(Buffer);
+}
+
+//------------------------------------------------------------------------------------------
+// SoundfieldGroupLabelSubDescriptor
+
+//
+
+SoundfieldGroupLabelSubDescriptor::SoundfieldGroupLabelSubDescriptor(const Dictionary*& d) : MCALabelSubDescriptor(d), m_Dict(d)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_SoundfieldGroupLabelSubDescriptor);
+}
+
+SoundfieldGroupLabelSubDescriptor::SoundfieldGroupLabelSubDescriptor(const SoundfieldGroupLabelSubDescriptor& rhs) : MCALabelSubDescriptor(rhs.m_Dict), m_Dict(rhs.m_Dict)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_SoundfieldGroupLabelSubDescriptor);
+ Copy(rhs);
+}
+
+
+//
+ASDCP::Result_t
+SoundfieldGroupLabelSubDescriptor::InitFromTLVSet(TLVReader& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = MCALabelSubDescriptor::InitFromTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(SoundfieldGroupLabelSubDescriptor, GroupOfSoundfieldGroupsLinkID));
+ return result;
+}
+
+//
+ASDCP::Result_t
+SoundfieldGroupLabelSubDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = MCALabelSubDescriptor::WriteToTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(SoundfieldGroupLabelSubDescriptor, GroupOfSoundfieldGroupsLinkID));
+ return result;
+}
+
+//
+void
+SoundfieldGroupLabelSubDescriptor::Copy(const SoundfieldGroupLabelSubDescriptor& rhs)
+{
+ MCALabelSubDescriptor::Copy(rhs);
+ GroupOfSoundfieldGroupsLinkID = rhs.GroupOfSoundfieldGroupsLinkID;
+}
+
+//
+void
+SoundfieldGroupLabelSubDescriptor::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+ *identbuf = 0;
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ MCALabelSubDescriptor::Dump(stream);
+ fprintf(stream, " %22s:\n", "GroupOfSoundfieldGroupsLinkID");
+ GroupOfSoundfieldGroupsLinkID.Dump(stream);
+}
+
+//
+ASDCP::Result_t
+SoundfieldGroupLabelSubDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+SoundfieldGroupLabelSubDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return InterchangeObject::WriteToBuffer(Buffer);
+}
+
+//------------------------------------------------------------------------------------------
+// GroupOfSoundfieldGroupsLabelSubDescriptor
+
+//
+
+GroupOfSoundfieldGroupsLabelSubDescriptor::GroupOfSoundfieldGroupsLabelSubDescriptor(const Dictionary*& d) : MCALabelSubDescriptor(d), m_Dict(d)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_GroupOfSoundfieldGroupsLabelSubDescriptor);
+}
+
+GroupOfSoundfieldGroupsLabelSubDescriptor::GroupOfSoundfieldGroupsLabelSubDescriptor(const GroupOfSoundfieldGroupsLabelSubDescriptor& rhs) : MCALabelSubDescriptor(rhs.m_Dict), m_Dict(rhs.m_Dict)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_GroupOfSoundfieldGroupsLabelSubDescriptor);
+ Copy(rhs);
+}
+
+
+//
+ASDCP::Result_t
+GroupOfSoundfieldGroupsLabelSubDescriptor::InitFromTLVSet(TLVReader& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = MCALabelSubDescriptor::InitFromTLVSet(TLVSet);
+ return result;
+}
+
+//
+ASDCP::Result_t
+GroupOfSoundfieldGroupsLabelSubDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = MCALabelSubDescriptor::WriteToTLVSet(TLVSet);
+ return result;
+}
+
+//
+void
+GroupOfSoundfieldGroupsLabelSubDescriptor::Copy(const GroupOfSoundfieldGroupsLabelSubDescriptor& rhs)
+{
+ MCALabelSubDescriptor::Copy(rhs);
+}
+
+//
+void
+GroupOfSoundfieldGroupsLabelSubDescriptor::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+ *identbuf = 0;
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ MCALabelSubDescriptor::Dump(stream);
+}
+
+//
+ASDCP::Result_t
+GroupOfSoundfieldGroupsLabelSubDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+GroupOfSoundfieldGroupsLabelSubDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return InterchangeObject::WriteToBuffer(Buffer);
+}
+
+//
+// end Metadata.cpp
+//
diff --git a/asdcplib/src/Metadata.h b/asdcplib/src/Metadata.h
new file mode 100755
index 0000000..3360cdf
--- /dev/null
+++ b/asdcplib/src/Metadata.h
@@ -0,0 +1,900 @@
+/*
+Copyright (c) 2005-2012, 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 Metadata.h
+ \version $Id: Metadata.h,v 1.29 2012/02/21 02:09:31 jhurst Exp $
+ \brief MXF metadata objects
+*/
+
+#ifndef _Metadata_H_
+#define _Metadata_H_
+
+#include "MXF.h"
+
+namespace ASDCP
+{
+ namespace MXF
+ {
+ void Metadata_InitTypes(const Dictionary*& Dict);
+
+ //
+
+ //
+ class Identification : public InterchangeObject
+ {
+ Identification();
+
+ public:
+ const Dictionary*& m_Dict;
+ UUID ThisGenerationUID;
+ UTF16String CompanyName;
+ UTF16String ProductName;
+ VersionType ProductVersion;
+ UTF16String VersionString;
+ UUID ProductUID;
+ Kumu::Timestamp ModificationDate;
+ VersionType ToolkitVersion;
+ UTF16String Platform;
+
+ Identification(const Dictionary*& d);
+ Identification(const Identification& rhs);
+ virtual ~Identification() {}
+
+ const Identification& operator=(const Identification& rhs) { Copy(rhs); return *this; }
+ virtual void Copy(const Identification& rhs);
+ virtual const char* HasName() { return "Identification"; }
+ virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+ virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+ virtual void Dump(FILE* = 0);
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ };
+
+ //
+ class ContentStorage : public InterchangeObject
+ {
+ ContentStorage();
+
+ public:
+ const Dictionary*& m_Dict;
+ Batch<UUID> Packages;
+ Batch<UUID> EssenceContainerData;
+
+ ContentStorage(const Dictionary*& d);
+ ContentStorage(const ContentStorage& rhs);
+ virtual ~ContentStorage() {}
+
+ const ContentStorage& operator=(const ContentStorage& rhs) { Copy(rhs); return *this; }
+ virtual void Copy(const ContentStorage& rhs);
+ virtual const char* HasName() { return "ContentStorage"; }
+ virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+ virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+ virtual void Dump(FILE* = 0);
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ };
+
+ //
+ class EssenceContainerData : public InterchangeObject
+ {
+ EssenceContainerData();
+
+ public:
+ const Dictionary*& m_Dict;
+ UMID LinkedPackageUID;
+ ui32_t IndexSID;
+ ui32_t BodySID;
+
+ EssenceContainerData(const Dictionary*& d);
+ EssenceContainerData(const EssenceContainerData& rhs);
+ virtual ~EssenceContainerData() {}
+
+ const EssenceContainerData& operator=(const EssenceContainerData& rhs) { Copy(rhs); return *this; }
+ virtual void Copy(const EssenceContainerData& rhs);
+ virtual const char* HasName() { return "EssenceContainerData"; }
+ virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+ virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+ virtual void Dump(FILE* = 0);
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ };
+
+ //
+ class GenericPackage : public InterchangeObject
+ {
+ GenericPackage();
+
+ public:
+ const Dictionary*& m_Dict;
+ UMID PackageUID;
+ UTF16String Name;
+ Kumu::Timestamp PackageCreationDate;
+ Kumu::Timestamp PackageModifiedDate;
+ Batch<UUID> Tracks;
+
+ GenericPackage(const Dictionary*& d);
+ GenericPackage(const GenericPackage& rhs);
+ virtual ~GenericPackage() {}
+
+ const GenericPackage& operator=(const GenericPackage& rhs) { Copy(rhs); return *this; }
+ virtual void Copy(const GenericPackage& rhs);
+ virtual const char* HasName() { return "GenericPackage"; }
+ virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+ virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+ virtual void Dump(FILE* = 0);
+ };
+
+ //
+ class MaterialPackage : public GenericPackage
+ {
+ MaterialPackage();
+
+ public:
+ const Dictionary*& m_Dict;
+
+ MaterialPackage(const Dictionary*& d);
+ MaterialPackage(const MaterialPackage& rhs);
+ virtual ~MaterialPackage() {}
+
+ const MaterialPackage& operator=(const MaterialPackage& rhs) { Copy(rhs); return *this; }
+ virtual void Copy(const MaterialPackage& rhs);
+ virtual const char* HasName() { return "MaterialPackage"; }
+ virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+ virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+ virtual void Dump(FILE* = 0);
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ };
+
+ //
+ class SourcePackage : public GenericPackage
+ {
+ SourcePackage();
+
+ public:
+ const Dictionary*& m_Dict;
+ UUID Descriptor;
+
+ SourcePackage(const Dictionary*& d);
+ SourcePackage(const SourcePackage& rhs);
+ virtual ~SourcePackage() {}
+
+ const SourcePackage& operator=(const SourcePackage& rhs) { Copy(rhs); return *this; }
+ virtual void Copy(const SourcePackage& rhs);
+ virtual const char* HasName() { return "SourcePackage"; }
+ virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+ virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+ virtual void Dump(FILE* = 0);
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ };
+
+ //
+ class GenericTrack : public InterchangeObject
+ {
+ GenericTrack();
+
+ public:
+ const Dictionary*& m_Dict;
+ ui32_t TrackID;
+ ui32_t TrackNumber;
+ UTF16String TrackName;
+ UUID Sequence;
+
+ GenericTrack(const Dictionary*& d);
+ GenericTrack(const GenericTrack& rhs);
+ virtual ~GenericTrack() {}
+
+ const GenericTrack& operator=(const GenericTrack& rhs) { Copy(rhs); return *this; }
+ virtual void Copy(const GenericTrack& rhs);
+ virtual const char* HasName() { return "GenericTrack"; }
+ virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+ virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+ virtual void Dump(FILE* = 0);
+ };
+
+ //
+ class StaticTrack : public GenericTrack
+ {
+ StaticTrack();
+
+ public:
+ const Dictionary*& m_Dict;
+
+ StaticTrack(const Dictionary*& d);
+ StaticTrack(const StaticTrack& rhs);
+ virtual ~StaticTrack() {}
+
+ const StaticTrack& operator=(const StaticTrack& rhs) { Copy(rhs); return *this; }
+ virtual void Copy(const StaticTrack& rhs);
+ virtual const char* HasName() { return "StaticTrack"; }
+ virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+ virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+ virtual void Dump(FILE* = 0);
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ };
+
+ //
+ class Track : public GenericTrack
+ {
+ Track();
+
+ public:
+ const Dictionary*& m_Dict;
+ Rational EditRate;
+ ui64_t Origin;
+
+ Track(const Dictionary*& d);
+ Track(const Track& rhs);
+ virtual ~Track() {}
+
+ const Track& operator=(const Track& rhs) { Copy(rhs); return *this; }
+ virtual void Copy(const Track& rhs);
+ virtual const char* HasName() { return "Track"; }
+ virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+ virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+ virtual void Dump(FILE* = 0);
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ };
+
+ //
+ class StructuralComponent : public InterchangeObject
+ {
+ StructuralComponent();
+
+ public:
+ const Dictionary*& m_Dict;
+ UL DataDefinition;
+ ui64_t Duration;
+
+ StructuralComponent(const Dictionary*& d);
+ StructuralComponent(const StructuralComponent& rhs);
+ virtual ~StructuralComponent() {}
+
+ const StructuralComponent& operator=(const StructuralComponent& rhs) { Copy(rhs); return *this; }
+ virtual void Copy(const StructuralComponent& rhs);
+ virtual const char* HasName() { return "StructuralComponent"; }
+ virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+ virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+ virtual void Dump(FILE* = 0);
+ };
+
+ //
+ class Sequence : public StructuralComponent
+ {
+ Sequence();
+
+ public:
+ const Dictionary*& m_Dict;
+ Batch<UUID> StructuralComponents;
+
+ Sequence(const Dictionary*& d);
+ Sequence(const Sequence& rhs);
+ virtual ~Sequence() {}
+
+ const Sequence& operator=(const Sequence& rhs) { Copy(rhs); return *this; }
+ virtual void Copy(const Sequence& rhs);
+ virtual const char* HasName() { return "Sequence"; }
+ virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+ virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+ virtual void Dump(FILE* = 0);
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ };
+
+ //
+ class SourceClip : public StructuralComponent
+ {
+ SourceClip();
+
+ public:
+ const Dictionary*& m_Dict;
+ ui64_t StartPosition;
+ UMID SourcePackageID;
+ ui32_t SourceTrackID;
+
+ SourceClip(const Dictionary*& d);
+ SourceClip(const SourceClip& rhs);
+ virtual ~SourceClip() {}
+
+ const SourceClip& operator=(const SourceClip& rhs) { Copy(rhs); return *this; }
+ virtual void Copy(const SourceClip& rhs);
+ virtual const char* HasName() { return "SourceClip"; }
+ virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+ virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+ virtual void Dump(FILE* = 0);
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ };
+
+ //
+ class TimecodeComponent : public StructuralComponent
+ {
+ TimecodeComponent();
+
+ public:
+ const Dictionary*& m_Dict;
+ ui16_t RoundedTimecodeBase;
+ ui64_t StartTimecode;
+ ui8_t DropFrame;
+
+ TimecodeComponent(const Dictionary*& d);
+ TimecodeComponent(const TimecodeComponent& rhs);
+ virtual ~TimecodeComponent() {}
+
+ const TimecodeComponent& operator=(const TimecodeComponent& rhs) { Copy(rhs); return *this; }
+ virtual void Copy(const TimecodeComponent& rhs);
+ virtual const char* HasName() { return "TimecodeComponent"; }
+ virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+ virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+ virtual void Dump(FILE* = 0);
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ };
+
+ //
+ class GenericDescriptor : public InterchangeObject
+ {
+ GenericDescriptor();
+
+ public:
+ const Dictionary*& m_Dict;
+ Batch<UUID> Locators;
+ Batch<UUID> SubDescriptors;
+
+ GenericDescriptor(const Dictionary*& d);
+ GenericDescriptor(const GenericDescriptor& rhs);
+ virtual ~GenericDescriptor() {}
+
+ const GenericDescriptor& operator=(const GenericDescriptor& rhs) { Copy(rhs); return *this; }
+ virtual void Copy(const GenericDescriptor& rhs);
+ virtual const char* HasName() { return "GenericDescriptor"; }
+ virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+ virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+ virtual void Dump(FILE* = 0);
+ };
+
+ //
+ class FileDescriptor : public GenericDescriptor
+ {
+ FileDescriptor();
+
+ public:
+ const Dictionary*& m_Dict;
+ ui32_t LinkedTrackID;
+ Rational SampleRate;
+ ui64_t ContainerDuration;
+ UL EssenceContainer;
+ UL Codec;
+
+ FileDescriptor(const Dictionary*& d);
+ FileDescriptor(const FileDescriptor& rhs);
+ virtual ~FileDescriptor() {}
+
+ const FileDescriptor& operator=(const FileDescriptor& rhs) { Copy(rhs); return *this; }
+ virtual void Copy(const FileDescriptor& rhs);
+ virtual const char* HasName() { return "FileDescriptor"; }
+ virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+ virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+ virtual void Dump(FILE* = 0);
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ };
+
+ //
+ class GenericSoundEssenceDescriptor : public FileDescriptor
+ {
+ GenericSoundEssenceDescriptor();
+
+ public:
+ const Dictionary*& m_Dict;
+ Rational AudioSamplingRate;
+ ui8_t Locked;
+ ui8_t AudioRefLevel;
+ ui32_t ChannelCount;
+ ui32_t QuantizationBits;
+ ui8_t DialNorm;
+
+ GenericSoundEssenceDescriptor(const Dictionary*& d);
+ GenericSoundEssenceDescriptor(const GenericSoundEssenceDescriptor& rhs);
+ virtual ~GenericSoundEssenceDescriptor() {}
+
+ const GenericSoundEssenceDescriptor& operator=(const GenericSoundEssenceDescriptor& rhs) { Copy(rhs); return *this; }
+ virtual void Copy(const GenericSoundEssenceDescriptor& rhs);
+ virtual const char* HasName() { return "GenericSoundEssenceDescriptor"; }
+ virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+ virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+ virtual void Dump(FILE* = 0);
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ };
+
+ //
+ class WaveAudioDescriptor : public GenericSoundEssenceDescriptor
+ {
+ WaveAudioDescriptor();
+
+ public:
+ const Dictionary*& m_Dict;
+ ui16_t BlockAlign;
+ ui8_t SequenceOffset;
+ ui32_t AvgBps;
+ UL ChannelAssignment;
+
+ WaveAudioDescriptor(const Dictionary*& d);
+ WaveAudioDescriptor(const WaveAudioDescriptor& rhs);
+ virtual ~WaveAudioDescriptor() {}
+
+ const WaveAudioDescriptor& operator=(const WaveAudioDescriptor& rhs) { Copy(rhs); return *this; }
+ virtual void Copy(const WaveAudioDescriptor& rhs);
+ virtual const char* HasName() { return "WaveAudioDescriptor"; }
+ virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+ virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+ virtual void Dump(FILE* = 0);
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ };
+
+ //
+ class GenericPictureEssenceDescriptor : public FileDescriptor
+ {
+ GenericPictureEssenceDescriptor();
+
+ public:
+ const Dictionary*& m_Dict;
+ ui8_t FrameLayout;
+ ui32_t StoredWidth;
+ ui32_t StoredHeight;
+ Rational AspectRatio;
+ UL PictureEssenceCoding;
+
+ GenericPictureEssenceDescriptor(const Dictionary*& d);
+ GenericPictureEssenceDescriptor(const GenericPictureEssenceDescriptor& rhs);
+ virtual ~GenericPictureEssenceDescriptor() {}
+
+ const GenericPictureEssenceDescriptor& operator=(const GenericPictureEssenceDescriptor& rhs) { Copy(rhs); return *this; }
+ virtual void Copy(const GenericPictureEssenceDescriptor& rhs);
+ virtual const char* HasName() { return "GenericPictureEssenceDescriptor"; }
+ virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+ virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+ virtual void Dump(FILE* = 0);
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ };
+
+ //
+ class RGBAEssenceDescriptor : public GenericPictureEssenceDescriptor
+ {
+ RGBAEssenceDescriptor();
+
+ public:
+ const Dictionary*& m_Dict;
+ ui32_t ComponentMaxRef;
+ ui32_t ComponentMinRef;
+
+ RGBAEssenceDescriptor(const Dictionary*& d);
+ RGBAEssenceDescriptor(const RGBAEssenceDescriptor& rhs);
+ virtual ~RGBAEssenceDescriptor() {}
+
+ const RGBAEssenceDescriptor& operator=(const RGBAEssenceDescriptor& rhs) { Copy(rhs); return *this; }
+ virtual void Copy(const RGBAEssenceDescriptor& rhs);
+ virtual const char* HasName() { return "RGBAEssenceDescriptor"; }
+ virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+ virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+ virtual void Dump(FILE* = 0);
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ };
+
+ //
+ class JPEG2000PictureSubDescriptor : public InterchangeObject
+ {
+ JPEG2000PictureSubDescriptor();
+
+ public:
+ const Dictionary*& m_Dict;
+ ui16_t Rsize;
+ ui32_t Xsize;
+ ui32_t Ysize;
+ ui32_t XOsize;
+ ui32_t YOsize;
+ ui32_t XTsize;
+ ui32_t YTsize;
+ ui32_t XTOsize;
+ ui32_t YTOsize;
+ ui16_t Csize;
+ Raw PictureComponentSizing;
+ Raw CodingStyleDefault;
+ Raw QuantizationDefault;
+
+ JPEG2000PictureSubDescriptor(const Dictionary*& d);
+ JPEG2000PictureSubDescriptor(const JPEG2000PictureSubDescriptor& rhs);
+ virtual ~JPEG2000PictureSubDescriptor() {}
+
+ const JPEG2000PictureSubDescriptor& operator=(const JPEG2000PictureSubDescriptor& rhs) { Copy(rhs); return *this; }
+ virtual void Copy(const JPEG2000PictureSubDescriptor& rhs);
+ virtual const char* HasName() { return "JPEG2000PictureSubDescriptor"; }
+ virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+ virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+ virtual void Dump(FILE* = 0);
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ };
+
+ //
+ class CDCIEssenceDescriptor : public GenericPictureEssenceDescriptor
+ {
+ CDCIEssenceDescriptor();
+
+ public:
+ const Dictionary*& m_Dict;
+ ui32_t ComponentDepth;
+ ui32_t HorizontalSubsampling;
+ ui32_t VerticalSubsampling;
+ ui8_t ColorSiting;
+
+ CDCIEssenceDescriptor(const Dictionary*& d);
+ CDCIEssenceDescriptor(const CDCIEssenceDescriptor& rhs);
+ virtual ~CDCIEssenceDescriptor() {}
+
+ const CDCIEssenceDescriptor& operator=(const CDCIEssenceDescriptor& rhs) { Copy(rhs); return *this; }
+ virtual void Copy(const CDCIEssenceDescriptor& rhs);
+ virtual const char* HasName() { return "CDCIEssenceDescriptor"; }
+ virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+ virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+ virtual void Dump(FILE* = 0);
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ };
+
+ //
+ class MPEG2VideoDescriptor : public CDCIEssenceDescriptor
+ {
+ MPEG2VideoDescriptor();
+
+ public:
+ const Dictionary*& m_Dict;
+ ui8_t CodedContentType;
+ ui8_t LowDelay;
+ ui32_t BitRate;
+ ui8_t ProfileAndLevel;
+
+ MPEG2VideoDescriptor(const Dictionary*& d);
+ MPEG2VideoDescriptor(const MPEG2VideoDescriptor& rhs);
+ virtual ~MPEG2VideoDescriptor() {}
+
+ const MPEG2VideoDescriptor& operator=(const MPEG2VideoDescriptor& rhs) { Copy(rhs); return *this; }
+ virtual void Copy(const MPEG2VideoDescriptor& rhs);
+ virtual const char* HasName() { return "MPEG2VideoDescriptor"; }
+ virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+ virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+ virtual void Dump(FILE* = 0);
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ };
+
+ //
+ class DMSegment : public InterchangeObject
+ {
+ DMSegment();
+
+ public:
+ const Dictionary*& m_Dict;
+ UL DataDefinition;
+ ui64_t EventStartPosition;
+ ui64_t Duration;
+ UTF16String EventComment;
+ UUID DMFramework;
+
+ DMSegment(const Dictionary*& d);
+ DMSegment(const DMSegment& rhs);
+ virtual ~DMSegment() {}
+
+ const DMSegment& operator=(const DMSegment& rhs) { Copy(rhs); return *this; }
+ virtual void Copy(const DMSegment& rhs);
+ virtual const char* HasName() { return "DMSegment"; }
+ virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+ virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+ virtual void Dump(FILE* = 0);
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ };
+
+ //
+ class CryptographicFramework : public InterchangeObject
+ {
+ CryptographicFramework();
+
+ public:
+ const Dictionary*& m_Dict;
+ UUID ContextSR;
+
+ CryptographicFramework(const Dictionary*& d);
+ CryptographicFramework(const CryptographicFramework& rhs);
+ virtual ~CryptographicFramework() {}
+
+ const CryptographicFramework& operator=(const CryptographicFramework& rhs) { Copy(rhs); return *this; }
+ virtual void Copy(const CryptographicFramework& rhs);
+ virtual const char* HasName() { return "CryptographicFramework"; }
+ virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+ virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+ virtual void Dump(FILE* = 0);
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ };
+
+ //
+ class CryptographicContext : public InterchangeObject
+ {
+ CryptographicContext();
+
+ public:
+ const Dictionary*& m_Dict;
+ UUID ContextID;
+ UL SourceEssenceContainer;
+ UL CipherAlgorithm;
+ UL MICAlgorithm;
+ UUID CryptographicKeyID;
+
+ CryptographicContext(const Dictionary*& d);
+ CryptographicContext(const CryptographicContext& rhs);
+ virtual ~CryptographicContext() {}
+
+ const CryptographicContext& operator=(const CryptographicContext& rhs) { Copy(rhs); return *this; }
+ virtual void Copy(const CryptographicContext& rhs);
+ virtual const char* HasName() { return "CryptographicContext"; }
+ virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+ virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+ virtual void Dump(FILE* = 0);
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ };
+
+ //
+ class GenericDataEssenceDescriptor : public FileDescriptor
+ {
+ GenericDataEssenceDescriptor();
+
+ public:
+ const Dictionary*& m_Dict;
+ UL DataEssenceCoding;
+
+ GenericDataEssenceDescriptor(const Dictionary*& d);
+ GenericDataEssenceDescriptor(const GenericDataEssenceDescriptor& rhs);
+ virtual ~GenericDataEssenceDescriptor() {}
+
+ const GenericDataEssenceDescriptor& operator=(const GenericDataEssenceDescriptor& rhs) { Copy(rhs); return *this; }
+ virtual void Copy(const GenericDataEssenceDescriptor& rhs);
+ virtual const char* HasName() { return "GenericDataEssenceDescriptor"; }
+ virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+ virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+ virtual void Dump(FILE* = 0);
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ };
+
+ //
+ class TimedTextDescriptor : public GenericDataEssenceDescriptor
+ {
+ TimedTextDescriptor();
+
+ public:
+ const Dictionary*& m_Dict;
+ UUID ResourceID;
+ UTF16String UCSEncoding;
+ UTF16String NamespaceURI;
+
+ TimedTextDescriptor(const Dictionary*& d);
+ TimedTextDescriptor(const TimedTextDescriptor& rhs);
+ virtual ~TimedTextDescriptor() {}
+
+ const TimedTextDescriptor& operator=(const TimedTextDescriptor& rhs) { Copy(rhs); return *this; }
+ virtual void Copy(const TimedTextDescriptor& rhs);
+ virtual const char* HasName() { return "TimedTextDescriptor"; }
+ virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+ virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+ virtual void Dump(FILE* = 0);
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ };
+
+ //
+ class TimedTextResourceSubDescriptor : public InterchangeObject
+ {
+ TimedTextResourceSubDescriptor();
+
+ public:
+ const Dictionary*& m_Dict;
+ UUID AncillaryResourceID;
+ UTF16String MIMEMediaType;
+ ui32_t EssenceStreamID;
+
+ TimedTextResourceSubDescriptor(const Dictionary*& d);
+ TimedTextResourceSubDescriptor(const TimedTextResourceSubDescriptor& rhs);
+ virtual ~TimedTextResourceSubDescriptor() {}
+
+ const TimedTextResourceSubDescriptor& operator=(const TimedTextResourceSubDescriptor& rhs) { Copy(rhs); return *this; }
+ virtual void Copy(const TimedTextResourceSubDescriptor& rhs);
+ virtual const char* HasName() { return "TimedTextResourceSubDescriptor"; }
+ virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+ virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+ virtual void Dump(FILE* = 0);
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ };
+
+ //
+ class StereoscopicPictureSubDescriptor : public InterchangeObject
+ {
+ StereoscopicPictureSubDescriptor();
+
+ public:
+ const Dictionary*& m_Dict;
+
+ StereoscopicPictureSubDescriptor(const Dictionary*& d);
+ StereoscopicPictureSubDescriptor(const StereoscopicPictureSubDescriptor& rhs);
+ virtual ~StereoscopicPictureSubDescriptor() {}
+
+ const StereoscopicPictureSubDescriptor& operator=(const StereoscopicPictureSubDescriptor& rhs) { Copy(rhs); return *this; }
+ virtual void Copy(const StereoscopicPictureSubDescriptor& rhs);
+ virtual const char* HasName() { return "StereoscopicPictureSubDescriptor"; }
+ virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+ virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+ virtual void Dump(FILE* = 0);
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ };
+
+ //
+ class NetworkLocator : public InterchangeObject
+ {
+ NetworkLocator();
+
+ public:
+ const Dictionary*& m_Dict;
+ UTF16String URLString;
+
+ NetworkLocator(const Dictionary*& d);
+ NetworkLocator(const NetworkLocator& rhs);
+ virtual ~NetworkLocator() {}
+
+ const NetworkLocator& operator=(const NetworkLocator& rhs) { Copy(rhs); return *this; }
+ virtual void Copy(const NetworkLocator& rhs);
+ virtual const char* HasName() { return "NetworkLocator"; }
+ virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+ virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+ virtual void Dump(FILE* = 0);
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ };
+
+ //
+ class MCALabelSubDescriptor : public InterchangeObject
+ {
+ MCALabelSubDescriptor();
+
+ public:
+ const Dictionary*& m_Dict;
+ UL MCALabelDictionaryID;
+ UUID MCALinkID;
+ UTF16String MCATagSymbol;
+ UTF16String MCATagName;
+ ui32_t MCAChannelID;
+ ISO8String RFC5646SpokenLanguage;
+
+ MCALabelSubDescriptor(const Dictionary*& d);
+ MCALabelSubDescriptor(const MCALabelSubDescriptor& rhs);
+ virtual ~MCALabelSubDescriptor() {}
+
+ const MCALabelSubDescriptor& operator=(const MCALabelSubDescriptor& rhs) { Copy(rhs); return *this; }
+ virtual void Copy(const MCALabelSubDescriptor& rhs);
+ virtual const char* HasName() { return "MCALabelSubDescriptor"; }
+ virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+ virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+ virtual void Dump(FILE* = 0);
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ };
+
+ //
+ class AudioChannelLabelSubDescriptor : public MCALabelSubDescriptor
+ {
+ AudioChannelLabelSubDescriptor();
+
+ public:
+ const Dictionary*& m_Dict;
+ UUID SoundfieldGroupLinkID;
+
+ AudioChannelLabelSubDescriptor(const Dictionary*& d);
+ AudioChannelLabelSubDescriptor(const AudioChannelLabelSubDescriptor& rhs);
+ virtual ~AudioChannelLabelSubDescriptor() {}
+
+ const AudioChannelLabelSubDescriptor& operator=(const AudioChannelLabelSubDescriptor& rhs) { Copy(rhs); return *this; }
+ virtual void Copy(const AudioChannelLabelSubDescriptor& rhs);
+ virtual const char* HasName() { return "AudioChannelLabelSubDescriptor"; }
+ virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+ virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+ virtual void Dump(FILE* = 0);
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ };
+
+ //
+ class SoundfieldGroupLabelSubDescriptor : public MCALabelSubDescriptor
+ {
+ SoundfieldGroupLabelSubDescriptor();
+
+ public:
+ const Dictionary*& m_Dict;
+ Array<UUID> GroupOfSoundfieldGroupsLinkID;
+
+ SoundfieldGroupLabelSubDescriptor(const Dictionary*& d);
+ SoundfieldGroupLabelSubDescriptor(const SoundfieldGroupLabelSubDescriptor& rhs);
+ virtual ~SoundfieldGroupLabelSubDescriptor() {}
+
+ const SoundfieldGroupLabelSubDescriptor& operator=(const SoundfieldGroupLabelSubDescriptor& rhs) { Copy(rhs); return *this; }
+ virtual void Copy(const SoundfieldGroupLabelSubDescriptor& rhs);
+ virtual const char* HasName() { return "SoundfieldGroupLabelSubDescriptor"; }
+ virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+ virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+ virtual void Dump(FILE* = 0);
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ };
+
+ //
+ class GroupOfSoundfieldGroupsLabelSubDescriptor : public MCALabelSubDescriptor
+ {
+ GroupOfSoundfieldGroupsLabelSubDescriptor();
+
+ public:
+ const Dictionary*& m_Dict;
+
+ GroupOfSoundfieldGroupsLabelSubDescriptor(const Dictionary*& d);
+ GroupOfSoundfieldGroupsLabelSubDescriptor(const GroupOfSoundfieldGroupsLabelSubDescriptor& rhs);
+ virtual ~GroupOfSoundfieldGroupsLabelSubDescriptor() {}
+
+ const GroupOfSoundfieldGroupsLabelSubDescriptor& operator=(const GroupOfSoundfieldGroupsLabelSubDescriptor& rhs) { Copy(rhs); return *this; }
+ virtual void Copy(const GroupOfSoundfieldGroupsLabelSubDescriptor& rhs);
+ virtual const char* HasName() { return "GroupOfSoundfieldGroupsLabelSubDescriptor"; }
+ virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+ virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+ virtual void Dump(FILE* = 0);
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ };
+
+ } // namespace MXF
+} // namespace ASDCP
+
+
+#endif // _Metadata_H_
+
+//
+// end Metadata.h
+//
diff --git a/asdcplib/src/PCMParserList.cpp b/asdcplib/src/PCMParserList.cpp
new file mode 100755
index 0000000..444b883
--- /dev/null
+++ b/asdcplib/src/PCMParserList.cpp
@@ -0,0 +1,285 @@
+/*
+Copyright (c) 2004-2012, 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 PCMParserList.cpp
+ \version $Id: PCMParserList.cpp,v 1.9 2012/02/21 02:09:31 jhurst Exp $
+ \brief Read WAV file(s), multiplex multiple PCM frame buffers into one
+*/
+
+#include <PCMParserList.h>
+#include <KM_fileio.h>
+#include <KM_log.h>
+#include <assert.h>
+
+using namespace ASDCP;
+using namespace Kumu;
+
+
+ASDCP::ParserInstance::ParserInstance() : m_p(0), m_SampleSize(0)
+{
+}
+
+ASDCP::ParserInstance::~ParserInstance()
+{
+}
+
+// PCM::CalcSampleSize(ADesc);
+Result_t
+ASDCP::ParserInstance::OpenRead(const char* filename, const Rational& PictureRate)
+{
+ ASDCP_TEST_NULL_STR(filename);
+
+ Result_t result = Parser.OpenRead(filename, PictureRate);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Parser.FillAudioDescriptor(ADesc);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ ADesc.EditRate = PictureRate;
+ m_SampleSize = PCM::CalcSampleSize(ADesc);
+ result = FB.Capacity(PCM::CalcFrameBufferSize(ADesc));
+ }
+
+ return result;
+}
+
+
+// deposit the next available sample into the given framebuffer
+Result_t
+ASDCP::ParserInstance::PutSample(byte_t* p)
+{
+ ASDCP_TEST_NULL(p);
+
+ memcpy(p, m_p, m_SampleSize);
+ m_p += m_SampleSize;
+ return RESULT_OK;
+}
+
+
+//
+Result_t
+ASDCP::ParserInstance::ReadFrame()
+{
+ Result_t result = Parser.ReadFrame(FB);
+ m_p = ASDCP_SUCCESS(result) ? FB.RoData() : 0;
+ return result;
+}
+
+
+//------------------------------------------------------------------------------------------
+//
+
+
+//
+ASDCP::PCMParserList::PCMParserList() : m_ChannelCount(0)
+{
+}
+
+ASDCP::PCMParserList::~PCMParserList()
+{
+ while ( ! empty() )
+ {
+ delete back();
+ pop_back();
+ }
+}
+
+//
+Result_t
+ASDCP::PCMParserList::OpenRead(ui32_t argc, const char** argv, const Rational& PictureRate)
+{
+ ASDCP_TEST_NULL_STR(argv);
+ PathList_t TmpFileList;
+
+ for ( ui32_t i = 0; i < argc; ++i )
+ TmpFileList.push_back(argv[i]);
+
+ return OpenRead(TmpFileList, PictureRate);
+}
+
+//
+Result_t
+ASDCP::PCMParserList::OpenRead(const Kumu::PathList_t& argv, const Rational& PictureRate)
+{
+ Result_t result = RESULT_OK;
+ PathList_t::iterator fi;
+ Kumu::PathList_t file_list;
+
+ if ( argv.size() == 1 && PathIsDirectory(argv.front()) )
+ {
+ DirScanner Dir;
+ char name_buf[MaxFilePath];
+ result = Dir.Open(argv.front().c_str());
+
+ if ( KM_SUCCESS(result) )
+ result = Dir.GetNext(name_buf);
+
+ while ( KM_SUCCESS(result) )
+ {
+ if ( name_buf[0] != '.' ) // no hidden files
+ {
+ std::string tmp_path = argv.front() + "/" + name_buf;
+ file_list.push_back(tmp_path);
+ }
+
+ result = Dir.GetNext(name_buf);
+ }
+
+ if ( result == RESULT_ENDOFFILE )
+ {
+ result = RESULT_OK;
+ file_list.sort();
+ }
+ }
+ else
+ {
+ file_list = argv;
+ }
+
+ for ( fi = file_list.begin(); KM_SUCCESS(result) && fi != file_list.end(); ++fi )
+ {
+ mem_ptr<ParserInstance> I = new ParserInstance;
+ result = I->OpenRead(fi->c_str(), PictureRate);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ if ( fi == file_list.begin() )
+ {
+ m_ADesc = I->ADesc;
+ }
+ else
+ {
+ if ( I->ADesc.AudioSamplingRate != m_ADesc.AudioSamplingRate )
+ {
+ DefaultLogSink().Error("AudioSamplingRate mismatch in PCM parser list.");
+ return RESULT_FORMAT;
+ }
+
+ if ( I->ADesc.QuantizationBits != m_ADesc.QuantizationBits )
+ {
+ DefaultLogSink().Error("QuantizationBits mismatch in PCM parser list.");
+ return RESULT_FORMAT;
+ }
+
+ if ( I->ADesc.ContainerDuration < m_ADesc.ContainerDuration )
+ m_ADesc.ContainerDuration = I->ADesc.ContainerDuration;
+
+ m_ADesc.BlockAlign += I->ADesc.BlockAlign;
+ }
+
+ m_ChannelCount += I->ADesc.ChannelCount;
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ result = I->FB.Capacity(PCM::CalcFrameBufferSize(m_ADesc));
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ push_back(I);
+ I.release();
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ m_ADesc.ChannelCount = m_ChannelCount;
+ m_ADesc.AvgBps = (ui32_t)(ceil(m_ADesc.AudioSamplingRate.Quotient()) * m_ADesc.BlockAlign);
+ }
+ else
+ {
+ clear();
+ }
+
+ return result;
+}
+
+//
+Result_t
+ASDCP::PCMParserList::FillAudioDescriptor(PCM::AudioDescriptor& ADesc) const
+{
+ ADesc = m_ADesc;
+ return RESULT_OK;
+}
+
+//
+Result_t
+ASDCP::PCMParserList::Reset()
+{
+ Result_t result = RESULT_OK;
+ PCMParserList::iterator self_i;
+
+ for ( self_i = begin(); self_i != end() && ASDCP_SUCCESS(result) ; self_i++ )
+ result = (*self_i)->Parser.Reset();
+
+ return result;
+}
+
+
+//
+Result_t
+ASDCP::PCMParserList::ReadFrame(PCM::FrameBuffer& OutFB)
+{
+ Result_t result = RESULT_OK;
+
+ if ( size() == 1 )
+ return front()->Parser.ReadFrame(OutFB);
+
+ PCMParserList::iterator self_i;
+ assert(PCM::CalcFrameBufferSize(m_ADesc) <= OutFB.Capacity());
+
+ for ( self_i = begin(); self_i != end() && ASDCP_SUCCESS(result) ; self_i++ )
+ result = (*self_i)->ReadFrame();
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ OutFB.Size(PCM::CalcFrameBufferSize(m_ADesc));
+
+ // ui32_t sample_size = (PCM::CalcSampleSize(m_ADesc));
+ byte_t* Out_p = OutFB.Data();
+ byte_t* End_p = Out_p + OutFB.Size();
+
+ while ( Out_p < End_p && ASDCP_SUCCESS(result) )
+ {
+ self_i = begin();
+
+ while ( self_i != end() && ASDCP_SUCCESS(result) )
+ {
+ result = (*self_i)->PutSample(Out_p);
+ Out_p += (*self_i)->SampleSize();
+ self_i++;
+ }
+ }
+
+ assert(Out_p == End_p);
+ }
+
+ return result;
+}
+
+//
+// end PCMParserList.cpp
+//
diff --git a/asdcplib/src/PCMParserList.h b/asdcplib/src/PCMParserList.h
new file mode 100755
index 0000000..b744531
--- /dev/null
+++ b/asdcplib/src/PCMParserList.h
@@ -0,0 +1,89 @@
+/*
+Copyright (c) 2004-2012, 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 PCMParserList.h
+ \version $Id: PCMParserList.h,v 1.4 2012/02/03 19:49:56 jhurst Exp $
+ \brief Read WAV file(s), multiplex multiple PCM frame buffers into one
+*/
+
+#ifndef _PCMPARSERLIST_H_
+#define _PCMPARSERLIST_H_
+
+#include <KM_fileio.h>
+#include <AS_DCP.h>
+#include <vector>
+
+namespace ASDCP
+{
+ //
+ class ParserInstance
+ {
+ const byte_t* m_p;
+ ui32_t m_SampleSize;
+
+ ASDCP_NO_COPY_CONSTRUCT(ParserInstance);
+
+ public:
+ PCM::WAVParser Parser;
+ PCM::FrameBuffer FB;
+ PCM::AudioDescriptor ADesc;
+
+ ParserInstance();
+ virtual ~ParserInstance();
+
+ Result_t OpenRead(const char* filename, const Rational& PictureRate);
+ Result_t PutSample(byte_t* p);
+ Result_t ReadFrame();
+ inline ui32_t SampleSize() { return m_SampleSize; }
+ };
+
+ //
+ class PCMParserList : public std::vector<ParserInstance*>
+ {
+ ASDCP_NO_COPY_CONSTRUCT(PCMParserList);
+
+ protected:
+ PCM::AudioDescriptor m_ADesc;
+ ui32_t m_ChannelCount;
+
+ public:
+ PCMParserList();
+ virtual ~PCMParserList();
+
+ Result_t OpenRead(ui32_t argc, const char** argv, const Rational& PictureRate);
+ Result_t OpenRead(const Kumu::PathList_t& argv, const Rational& PictureRate);
+ Result_t FillAudioDescriptor(PCM::AudioDescriptor& ADesc) const;
+ Result_t Reset();
+ Result_t ReadFrame(PCM::FrameBuffer& OutFB);
+ };
+}
+
+
+#endif // _PCMPARSERLIST_H_
+
+//
+// end PCMParserList.h
+//
diff --git a/asdcplib/src/PCM_Parser.cpp b/asdcplib/src/PCM_Parser.cpp
new file mode 100755
index 0000000..e556341
--- /dev/null
+++ b/asdcplib/src/PCM_Parser.cpp
@@ -0,0 +1,236 @@
+/*
+Copyright (c) 2004-2011, 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 PCM_Parser.cpp
+ \version $Id: PCM_Parser.cpp,v 1.7 2011/05/13 01:50:19 jhurst Exp $
+ \brief AS-DCP library, PCM raw essence reader implementation
+*/
+
+#include <Wav.h>
+#include <assert.h>
+#include <KM_log.h>
+using Kumu::DefaultLogSink;
+
+using namespace ASDCP;
+using namespace ASDCP::PCM;
+using namespace ASDCP::Wav;
+
+
+//------------------------------------------------------------------------------------------
+
+//
+class ASDCP::PCM::WAVParser::h__WAVParser
+{
+ Kumu::FileReader m_FileReader;
+ bool m_EOF;
+ ui32_t m_DataStart;
+ ui32_t m_DataLength;
+ ui32_t m_ReadCount;
+ ui32_t m_FrameBufferSize;
+ ui32_t m_FramesRead;
+ Rational m_PictureRate;
+
+ ASDCP_NO_COPY_CONSTRUCT(h__WAVParser);
+
+public:
+ AudioDescriptor m_ADesc;
+
+
+ h__WAVParser() :
+ m_EOF(false), m_DataStart(0), m_DataLength(0), m_ReadCount(0),
+ m_FrameBufferSize(0), m_FramesRead(0) {}
+
+ ~h__WAVParser()
+ {
+ Close();
+ }
+
+ Result_t OpenRead(const char* filename, const Rational& PictureRate);
+ void Close();
+ void Reset();
+ Result_t ReadFrame(FrameBuffer&);
+};
+
+
+//
+void
+ASDCP::PCM::WAVParser::h__WAVParser::Close()
+{
+ m_FileReader.Close();
+}
+
+//
+void
+ASDCP::PCM::WAVParser::h__WAVParser::Reset()
+{
+ m_FileReader.Seek(m_DataStart);
+ m_FramesRead = 0;
+ m_ReadCount = 0;
+}
+
+//
+ASDCP::Result_t
+ASDCP::PCM::WAVParser::h__WAVParser::OpenRead(const char* filename, const Rational& PictureRate)
+{
+ ASDCP_TEST_NULL_STR(filename);
+
+ Result_t result = m_FileReader.OpenRead(filename);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ SimpleWaveHeader WavHeader;
+ result = WavHeader.ReadFromFile(m_FileReader, &m_DataStart);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ WavHeader.FillADesc(m_ADesc, PictureRate);
+ m_FrameBufferSize = ASDCP::PCM::CalcFrameBufferSize(m_ADesc);
+ m_DataLength = WavHeader.data_len;
+ m_ADesc.ContainerDuration = m_DataLength / m_FrameBufferSize;
+ m_ADesc.ChannelFormat = PCM::CF_NONE;
+ Reset();
+ }
+ else
+ {
+ ASDCP::AIFF::SimpleAIFFHeader AIFFHeader;
+ m_FileReader.Seek(0);
+
+ result = AIFFHeader.ReadFromFile(m_FileReader, &m_DataStart);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ AIFFHeader.FillADesc(m_ADesc, PictureRate);
+ m_FrameBufferSize = ASDCP::PCM::CalcFrameBufferSize(m_ADesc);
+ m_DataLength = AIFFHeader.data_len;
+ m_ADesc.ContainerDuration = m_DataLength / m_FrameBufferSize;
+ m_ADesc.ChannelFormat = PCM::CF_NONE;
+ Reset();
+ }
+ }
+ }
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::PCM::WAVParser::h__WAVParser::ReadFrame(FrameBuffer& FB)
+{
+ FB.Size(0);
+
+ if ( m_EOF || m_ReadCount >= m_DataLength )
+ return RESULT_ENDOFFILE;
+
+ if ( FB.Capacity() < m_FrameBufferSize )
+ {
+ DefaultLogSink().Error("FrameBuf.Capacity: %u FrameLength: %u\n",
+ FB.Capacity(), m_FrameBufferSize);
+ return RESULT_SMALLBUF;
+ }
+
+ ui32_t read_count = 0;
+ Result_t result = m_FileReader.Read(FB.Data(), m_FrameBufferSize, &read_count);
+
+ if ( result == RESULT_ENDOFFILE )
+ {
+ m_EOF = true;
+
+ if ( read_count > 0 )
+ result = RESULT_OK;
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ m_ReadCount += read_count;
+ FB.Size(read_count);
+ FB.FrameNumber(m_FramesRead++);
+ }
+
+ return result;
+}
+
+
+//------------------------------------------------------------------------------------------
+
+ASDCP::PCM::WAVParser::WAVParser()
+{
+}
+
+ASDCP::PCM::WAVParser::~WAVParser()
+{
+}
+
+// Opens the stream for reading, parses enough data to provide a complete
+// set of stream metadata for the MXFWriter below.
+ASDCP::Result_t
+ASDCP::PCM::WAVParser::OpenRead(const char* filename, const Rational& PictureRate) const
+{
+ const_cast<ASDCP::PCM::WAVParser*>(this)->m_Parser = new h__WAVParser;
+
+ Result_t result = m_Parser->OpenRead(filename, PictureRate);
+
+ if ( ASDCP_FAILURE(result) )
+ const_cast<ASDCP::PCM::WAVParser*>(this)->m_Parser.release();
+
+ return result;
+}
+
+// Rewinds the stream to the beginning.
+ASDCP::Result_t
+ASDCP::PCM::WAVParser::Reset() const
+{
+ if ( m_Parser.empty() )
+ return RESULT_INIT;
+
+ m_Parser->Reset();
+ return RESULT_OK;
+}
+
+// Places a frame of data in the frame buffer. Fails if the buffer is too small
+// or the stream is empty.
+ASDCP::Result_t
+ASDCP::PCM::WAVParser::ReadFrame(FrameBuffer& FB) const
+{
+ if ( m_Parser.empty() )
+ return RESULT_INIT;
+
+ return m_Parser->ReadFrame(FB);
+}
+
+ASDCP::Result_t
+ASDCP::PCM::WAVParser::FillAudioDescriptor(AudioDescriptor& ADesc) const
+{
+ if ( m_Parser.empty() )
+ return RESULT_INIT;
+
+ ADesc = m_Parser->m_ADesc;
+ return RESULT_OK;
+}
+
+
+//
+// end PCM_Parser.cpp
+//
diff --git a/asdcplib/src/S12MTimecode.h b/asdcplib/src/S12MTimecode.h
new file mode 100644
index 0000000..7e355a6
--- /dev/null
+++ b/asdcplib/src/S12MTimecode.h
@@ -0,0 +1,158 @@
+/*
+Copyright (c) 2007-2009, 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 S12MTimecode.cpp
+ \version $Id: S12MTimecode.h,v 1.5 2009/04/09 19:24:14 msheby Exp $
+ \brief AS-DCP library, Timecode PCM essence reader and writer implementation
+*/
+
+/*
+
+ DROP-FRAME NOT SUPPORTED!
+
+*/
+
+#ifndef _S12MTIMECODE_H_
+#define _S12MTIMECODE_H_
+
+#include "KM_util.h"
+#include "KM_memio.h"
+
+namespace ASDCP {
+
+ class S12MTimecode : public Kumu::IArchive
+{
+ protected:
+ ui32_t m_FrameCount;
+ ui32_t m_FPS;
+
+public:
+ S12MTimecode() : m_FrameCount(0), m_FPS(0) {}
+
+ S12MTimecode(ui32_t frame_count, ui32_t fps) : m_FrameCount(frame_count), m_FPS(fps) {}
+
+ S12MTimecode(const std::string& tc, ui32_t fps) : m_FrameCount(0), m_FPS(fps)
+ {
+ DecodeString(tc);
+ }
+
+ S12MTimecode(const S12MTimecode& rhs) : IArchive(), m_FrameCount(0), m_FPS(0)
+ {
+ m_FPS = rhs.m_FPS;
+ m_FrameCount = rhs.m_FrameCount;
+ }
+
+ ~S12MTimecode() {}
+
+ const S12MTimecode& operator=(const S12MTimecode& rhs)
+ {
+ assert(m_FPS != 0);
+ m_FrameCount = rhs.m_FrameCount;
+ return *this;
+ }
+
+ inline void SetFPS(ui32_t fps) { m_FPS = fps; }
+ inline ui32_t GetFPS() const { return m_FPS; }
+
+ inline void SetFrames(ui32_t frame_count) { m_FrameCount = frame_count; }
+ inline ui32_t GetFrames() const { return m_FrameCount; }
+
+ inline bool operator==(const S12MTimecode& rhs) const { return m_FrameCount == rhs.m_FrameCount; }
+ inline bool operator<(const S12MTimecode& rhs) const { return m_FrameCount < rhs.m_FrameCount; }
+
+ inline const S12MTimecode operator+(const S12MTimecode& rhs){
+ assert(m_FPS > 0);
+ assert(m_FPS == rhs.m_FPS);
+ return S12MTimecode(m_FrameCount + rhs.m_FrameCount, m_FPS);
+ }
+
+ inline const S12MTimecode operator-(const S12MTimecode& rhs){
+ assert(m_FPS > 0);
+ assert(m_FPS == rhs.m_FPS);
+ return S12MTimecode(m_FrameCount + rhs.m_FrameCount, m_FPS);
+ }
+
+
+ void DecodeString(const std::string& tc)
+ {
+ assert(m_FPS > 0);
+ const char* p = tc.c_str();
+
+ while ( *p != 0 && ! isdigit(*p) )
+ p++;
+
+ if ( *p != 0 )
+ {
+ ui32_t hours = atoi(p);
+ ui32_t minutes = atoi(p+3);
+ ui32_t seconds = atoi(p+6);
+ ui32_t frames = atoi(p+9);
+
+ m_FrameCount = (((((hours * 60) + minutes) * 60) + seconds) * m_FPS)+ frames;
+ }
+ }
+
+ const char* EncodeString(char* buf, ui32_t buf_len)
+ {
+ assert(m_FPS > 0);
+ ui32_t frames = m_FrameCount % m_FPS;
+ m_FrameCount /= m_FPS;
+ ui32_t seconds = m_FrameCount % 60;
+ m_FrameCount /= 60;
+ ui32_t minutes = m_FrameCount % 60;
+ ui32_t hours = m_FrameCount / 60;
+
+ snprintf(buf, buf_len, "%02d:%02d:%02d:%02d", hours, minutes, seconds, frames);
+ return buf;
+ }
+
+ // IArchive
+ bool HasValue() const { return (m_FPS > 0); }
+ ui32_t ArchiveLength() const { return sizeof(ui32_t)*2; }
+
+ bool Archive(Kumu::MemIOWriter* Writer) const
+ {
+ if ( ! Writer->WriteUi32BE(m_FPS) ) return false;
+ if ( ! Writer->WriteUi32BE(m_FrameCount) ) return false;
+ return true;
+ }
+
+ bool Unarchive(Kumu::MemIOReader* Reader)
+ {
+ if ( ! Reader->ReadUi32BE(&m_FPS) ) return false;
+ if ( ! Reader->ReadUi32BE(&m_FrameCount) ) return false;
+ return true;
+ }
+};
+
+
+} // namespace ASDCP
+
+#endif // _S12MTIMECODE_H_
+
+//
+// end S12MTimecode.h
+//
diff --git a/asdcplib/src/TimedText_Parser.cpp b/asdcplib/src/TimedText_Parser.cpp
new file mode 100644
index 0000000..ce16aee
--- /dev/null
+++ b/asdcplib/src/TimedText_Parser.cpp
@@ -0,0 +1,447 @@
+/*
+Copyright (c) 2007-2009, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file AS_DCP_TimedText.cpp
+ \version $Id: TimedText_Parser.cpp,v 1.15 2010/11/15 17:04:13 jhurst Exp $
+ \brief AS-DCP library, PCM essence reader and writer implementation
+*/
+
+
+#include "AS_DCP_internal.h"
+#include "S12MTimecode.h"
+#include "KM_xml.h"
+
+using namespace Kumu;
+using namespace ASDCP;
+
+using Kumu::DefaultLogSink;
+
+const char* c_dcst_namespace_name = "http://www.smpte-ra.org/schemas/428-7/2007/DCST";
+
+//------------------------------------------------------------------------------------------
+
+
+
+class FilenameResolver : public ASDCP::TimedText::IResourceResolver
+{
+ std::string m_Dirname;
+
+ FilenameResolver();
+ bool operator==(const FilenameResolver&);
+
+public:
+ FilenameResolver(const std::string& dirname)
+ {
+ if ( PathIsDirectory(dirname) )
+ {
+ m_Dirname = dirname;
+ return;
+ }
+
+ DefaultLogSink().Error("Path '%s' is not a directory, defaulting to '.'\n", dirname.c_str());
+ m_Dirname = ".";
+ }
+
+ //
+ Result_t ResolveRID(const byte_t* uuid, TimedText::FrameBuffer& FrameBuf) const
+ {
+ FileReader Reader;
+ char buf[64];
+ UUID RID(uuid);
+ std::string filename = m_Dirname + "/" + RID.EncodeHex(buf, 64);
+ DefaultLogSink().Debug("retrieving resource %s from file %s\n", buf, filename.c_str());
+
+ Result_t result = Reader.OpenRead(filename.c_str());
+
+ if ( KM_SUCCESS(result) )
+ {
+ ui32_t read_count, read_size = Reader.Size();
+
+ result = FrameBuf.Capacity(read_size);
+
+ if ( KM_SUCCESS(result) )
+ result = Reader.Read(FrameBuf.Data(), read_size, &read_count);
+
+ if ( KM_SUCCESS(result) )
+ FrameBuf.Size(read_count);
+ }
+
+ return result;
+ }
+};
+
+//------------------------------------------------------------------------------------------
+
+typedef std::map<Kumu::UUID, TimedText::MIMEType_t> ResourceTypeMap_t;
+
+class ASDCP::TimedText::DCSubtitleParser::h__SubtitleParser
+{
+ XMLElement m_Root;
+ ResourceTypeMap_t m_ResourceTypes;
+ Result_t OpenRead();
+
+ ASDCP_NO_COPY_CONSTRUCT(h__SubtitleParser);
+
+public:
+ std::string m_Filename;
+ std::string m_XMLDoc;
+ TimedTextDescriptor m_TDesc;
+ mem_ptr<FilenameResolver> m_DefaultResolver;
+
+ h__SubtitleParser() : m_Root("**ParserRoot**")
+ {
+ memset(&m_TDesc.AssetID, 0, UUIDlen);
+ }
+
+ ~h__SubtitleParser() {}
+
+ TimedText::IResourceResolver* GetDefaultResolver()
+ {
+ if ( m_DefaultResolver.empty() )
+ m_DefaultResolver = new FilenameResolver(PathDirname(m_Filename));
+
+ return m_DefaultResolver;
+ }
+
+ Result_t OpenRead(const char* filename);
+ Result_t OpenRead(const std::string& xml_doc, const char* filename);
+ Result_t ReadAncillaryResource(const byte_t* uuid, FrameBuffer& FrameBuf, const IResourceResolver& Resolver) const;
+};
+
+//
+bool
+get_UUID_from_element(XMLElement* Element, UUID& ID)
+{
+ assert(Element);
+ const char* p = Element->GetBody().c_str();
+ if ( strncmp(p, "urn:uuid:", 9) == 0 ) p += 9;
+ return ID.DecodeHex(p);
+}
+
+//
+bool
+get_UUID_from_child_element(const char* name, XMLElement* Parent, UUID& outID)
+{
+ assert(name); assert(Parent);
+ XMLElement* Child = Parent->GetChildWithName(name);
+ if ( Child == 0 ) return false;
+ return get_UUID_from_element(Child, outID);
+}
+
+//
+static ASDCP::Rational
+decode_rational(const char* str_rat)
+{
+ assert(str_rat);
+ ui32_t Num = atoi(str_rat);
+ ui32_t Den = 0;
+
+ const char* den_str = strrchr(str_rat, ' ');
+ if ( den_str != 0 )
+ Den = atoi(den_str+1);
+
+ return ASDCP::Rational(Num, Den);
+}
+
+//
+Result_t
+ASDCP::TimedText::DCSubtitleParser::h__SubtitleParser::OpenRead(const char* filename)
+{
+ Result_t result = ReadFileIntoString(filename, m_XMLDoc);
+
+ if ( KM_SUCCESS(result) )
+ result = OpenRead();
+
+ m_Filename = filename;
+ return result;
+}
+
+//
+Result_t
+ASDCP::TimedText::DCSubtitleParser::h__SubtitleParser::OpenRead(const std::string& xml_doc, const char* filename)
+{
+ m_XMLDoc = xml_doc;
+
+ if ( filename != 0 )
+ m_Filename = filename;
+ else
+ m_Filename = "<string>";
+
+ return OpenRead();
+}
+
+//
+Result_t
+ASDCP::TimedText::DCSubtitleParser::h__SubtitleParser::OpenRead()
+{
+ if ( ! m_Root.ParseString(m_XMLDoc.c_str()) )
+ return RESULT_FORMAT;
+
+ m_TDesc.EncodingName = "UTF-8"; // the XML parser demands UTF-8
+ m_TDesc.ResourceList.clear();
+ m_TDesc.ContainerDuration = 0;
+ const XMLNamespace* ns = m_Root.Namespace();
+
+ if ( ns == 0 )
+ {
+ DefaultLogSink(). Warn("Document has no namespace name, assuming %s\n", c_dcst_namespace_name);
+ m_TDesc.NamespaceName = c_dcst_namespace_name;
+ }
+ else
+ {
+ m_TDesc.NamespaceName = ns->Name();
+ }
+
+ UUID DocID;
+ if ( ! get_UUID_from_child_element("Id", &m_Root, DocID) )
+ {
+ DefaultLogSink(). Error("Id element missing from input document\n");
+ return RESULT_FORMAT;
+ }
+
+ memcpy(m_TDesc.AssetID, DocID.Value(), DocID.Size());
+ XMLElement* EditRate = m_Root.GetChildWithName("EditRate");
+
+ if ( EditRate == 0 )
+ {
+ DefaultLogSink(). Error("EditRate element missing from input document\n");
+ return RESULT_FORMAT;
+ }
+
+ m_TDesc.EditRate = decode_rational(EditRate->GetBody().c_str());
+
+ if ( m_TDesc.EditRate != EditRate_23_98
+ && m_TDesc.EditRate != EditRate_24
+ && m_TDesc.EditRate != EditRate_25
+ && m_TDesc.EditRate != EditRate_30
+ && m_TDesc.EditRate != EditRate_48
+ && m_TDesc.EditRate != EditRate_50
+ && m_TDesc.EditRate != EditRate_60 )
+ {
+ DefaultLogSink(). Error("Unexpected EditRate: %d/%d\n",
+ m_TDesc.EditRate.Numerator, m_TDesc.EditRate.Denominator);
+ return RESULT_FORMAT;
+ }
+
+ // list of fonts
+ ElementList FontList;
+ m_Root.GetChildrenWithName("LoadFont", FontList);
+
+ for ( Elem_i i = FontList.begin(); i != FontList.end(); i++ )
+ {
+ UUID AssetID;
+ if ( ! get_UUID_from_element(*i, AssetID) )
+ {
+ DefaultLogSink(). Error("LoadFont element does not contain a urn:uuid value as expected.\n");
+ return RESULT_FORMAT;
+ }
+
+ TimedTextResourceDescriptor TmpResource;
+ memcpy(TmpResource.ResourceID, AssetID.Value(), UUIDlen);
+ TmpResource.Type = MT_OPENTYPE;
+ m_TDesc.ResourceList.push_back(TmpResource);
+ m_ResourceTypes.insert(ResourceTypeMap_t::value_type(UUID(TmpResource.ResourceID), MT_OPENTYPE));
+ }
+
+ // list of images
+ ElementList ImageList;
+ m_Root.GetChildrenWithName("Image", ImageList);
+
+ for ( Elem_i i = ImageList.begin(); i != ImageList.end(); i++ )
+ {
+ UUID AssetID;
+ if ( ! get_UUID_from_element(*i, AssetID) )
+ {
+ DefaultLogSink(). Error("Image element does not contain a urn:uuid value as expected.\n");
+ return RESULT_FORMAT;
+ }
+
+ TimedTextResourceDescriptor TmpResource;
+ memcpy(TmpResource.ResourceID, AssetID.Value(), UUIDlen);
+ TmpResource.Type = MT_PNG;
+ m_TDesc.ResourceList.push_back(TmpResource);
+ m_ResourceTypes.insert(ResourceTypeMap_t::value_type(UUID(TmpResource.ResourceID), MT_PNG));
+ }
+
+ // Calculate the timeline duration.
+ // This is a little ugly because the last element in the file is not necessarily
+ // the last instance to be displayed, e.g., element n and element n-1 may have the
+ // same start time but n-1 may have a greater duration making it the last to be seen.
+ // We must scan the list to accumulate the latest TimeOut value.
+ ElementList InstanceList;
+ ElementList::const_iterator ei;
+ ui32_t end_count = 0;
+
+ m_Root.GetChildrenWithName("Subtitle", InstanceList);
+
+ if ( InstanceList.empty() )
+ {
+ DefaultLogSink(). Error("XML document contains no Subtitle elements.\n");
+ return RESULT_FORMAT;
+ }
+
+ // assumes edit rate is constrained above
+ ui32_t TCFrameRate = ( m_TDesc.EditRate == EditRate_23_98 ) ? 24 : m_TDesc.EditRate.Numerator;
+
+ S12MTimecode beginTC;
+ beginTC.SetFPS(TCFrameRate);
+ XMLElement* StartTime = m_Root.GetChildWithName("StartTime");
+
+ if ( StartTime != 0 )
+ beginTC.DecodeString(StartTime->GetBody());
+
+ for ( ei = InstanceList.begin(); ei != InstanceList.end(); ei++ )
+ {
+ S12MTimecode tmpTC((*ei)->GetAttrWithName("TimeOut"), TCFrameRate);
+ if ( end_count < tmpTC.GetFrames() )
+ end_count = tmpTC.GetFrames();
+ }
+
+ if ( end_count <= beginTC.GetFrames() )
+ {
+ DefaultLogSink(). Error("Timed Text file has zero-length timeline.\n");
+ return RESULT_FORMAT;
+ }
+
+ m_TDesc.ContainerDuration = end_count - beginTC.GetFrames();
+
+ return RESULT_OK;
+}
+
+
+//
+Result_t
+ASDCP::TimedText::DCSubtitleParser::h__SubtitleParser::ReadAncillaryResource(const byte_t* uuid, FrameBuffer& FrameBuf,
+ const IResourceResolver& Resolver) const
+{
+ FrameBuf.AssetID(uuid);
+ UUID TmpID(uuid);
+ char buf[64];
+
+ ResourceTypeMap_t::const_iterator rmi = m_ResourceTypes.find(TmpID);
+
+ if ( rmi == m_ResourceTypes.end() )
+ {
+ DefaultLogSink().Error("Unknown ancillary resource id: %s\n", TmpID.EncodeHex(buf, 64));
+ return RESULT_RANGE;
+ }
+
+ Result_t result = Resolver.ResolveRID(uuid, FrameBuf);
+
+ if ( KM_SUCCESS(result) )
+ {
+ if ( (*rmi).second == MT_PNG )
+ FrameBuf.MIMEType("image/png");
+
+ else if ( (*rmi).second == MT_OPENTYPE )
+ FrameBuf.MIMEType("application/x-font-opentype");
+
+ else
+ FrameBuf.MIMEType("application/octet-stream");
+ }
+
+ return result;
+}
+
+//------------------------------------------------------------------------------------------
+
+ASDCP::TimedText::DCSubtitleParser::DCSubtitleParser()
+{
+}
+
+ASDCP::TimedText::DCSubtitleParser::~DCSubtitleParser()
+{
+}
+
+// Opens the stream for reading, parses enough data to provide a complete
+// set of stream metadata for the MXFWriter below.
+ASDCP::Result_t
+ASDCP::TimedText::DCSubtitleParser::OpenRead(const char* filename) const
+{
+ const_cast<ASDCP::TimedText::DCSubtitleParser*>(this)->m_Parser = new h__SubtitleParser;
+
+ Result_t result = m_Parser->OpenRead(filename);
+
+ if ( ASDCP_FAILURE(result) )
+ const_cast<ASDCP::TimedText::DCSubtitleParser*>(this)->m_Parser = 0;
+
+ return result;
+}
+
+// Parses an XML document to provide a complete set of stream metadata for the MXFWriter below.
+Result_t
+ASDCP::TimedText::DCSubtitleParser::OpenRead(const std::string& xml_doc, const char* filename) const
+{
+ const_cast<ASDCP::TimedText::DCSubtitleParser*>(this)->m_Parser = new h__SubtitleParser;
+
+ Result_t result = m_Parser->OpenRead(xml_doc, filename);
+
+ if ( ASDCP_FAILURE(result) )
+ const_cast<ASDCP::TimedText::DCSubtitleParser*>(this)->m_Parser = 0;
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::TimedText::DCSubtitleParser::FillTimedTextDescriptor(TimedTextDescriptor& TDesc) const
+{
+ if ( m_Parser.empty() )
+ return RESULT_INIT;
+
+ TDesc = m_Parser->m_TDesc;
+ return RESULT_OK;
+}
+
+// Reads the complete Timed Text Resource into the given string.
+ASDCP::Result_t
+ASDCP::TimedText::DCSubtitleParser::ReadTimedTextResource(std::string& s) const
+{
+ if ( m_Parser.empty() )
+ return RESULT_INIT;
+
+ s = m_Parser->m_XMLDoc;
+ return RESULT_OK;
+}
+
+//
+ASDCP::Result_t
+ASDCP::TimedText::DCSubtitleParser::ReadAncillaryResource(const byte_t* uuid, FrameBuffer& FrameBuf,
+ const IResourceResolver* Resolver) const
+{
+ if ( m_Parser.empty() )
+ return RESULT_INIT;
+
+ if ( Resolver == 0 )
+ Resolver = m_Parser->GetDefaultResolver();
+
+ return m_Parser->ReadAncillaryResource(uuid, FrameBuf, *Resolver);
+}
+
+
+//
+// end AS_DCP_timedText.cpp
+//
diff --git a/asdcplib/src/Wav.cpp b/asdcplib/src/Wav.cpp
new file mode 100755
index 0000000..ee1e93d
--- /dev/null
+++ b/asdcplib/src/Wav.cpp
@@ -0,0 +1,370 @@
+/*
+Copyright (c) 2005-2009, 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 Wav.cpp
+ \version $Id: Wav.cpp,v 1.11 2010/02/16 18:40:57 jhurst Exp $
+ \brief Wave file common elements
+*/
+
+#include "Wav.h"
+#include <assert.h>
+#include <KM_log.h>
+using Kumu::DefaultLogSink;
+
+
+const ui32_t SimpleWavHeaderLength = 46;
+
+//
+ASDCP::Wav::SimpleWaveHeader::SimpleWaveHeader(ASDCP::PCM::AudioDescriptor& ADesc)
+{
+ format = 1;
+ nchannels = ADesc.ChannelCount;
+ bitspersample = ADesc.QuantizationBits;
+ samplespersec = (ui32_t)ceil(ADesc.AudioSamplingRate.Quotient());
+ blockalign = nchannels * (bitspersample / 8);
+ avgbps = samplespersec * blockalign;
+ cbsize = 0;
+ data_len = ASDCP::PCM::CalcFrameBufferSize(ADesc) * ADesc.ContainerDuration;
+}
+
+//
+void
+ASDCP::Wav::SimpleWaveHeader::FillADesc(ASDCP::PCM::AudioDescriptor& ADesc, ASDCP::Rational PictureRate) const
+{
+ ADesc.EditRate = PictureRate;
+
+ ADesc.LinkedTrackID = 0;
+ ADesc.Locked = 0;
+ ADesc.ChannelCount = nchannels;
+ ADesc.AudioSamplingRate = Rational(samplespersec, 1);
+ ADesc.AvgBps = avgbps;
+ ADesc.BlockAlign = blockalign;
+ ADesc.QuantizationBits = bitspersample;
+ ui32_t FrameBufferSize = ASDCP::PCM::CalcFrameBufferSize(ADesc);
+ ADesc.ContainerDuration = data_len / FrameBufferSize;
+ ADesc.ChannelFormat = PCM::CF_NONE;
+}
+
+
+//
+ASDCP::Result_t
+ASDCP::Wav::SimpleWaveHeader::WriteToFile(Kumu::FileWriter& OutFile) const
+{
+ ui32_t write_count;
+ byte_t tmp_header[SimpleWavHeaderLength];
+ byte_t* p = tmp_header;
+
+ static ui32_t fmt_len =
+ sizeof(format)
+ + sizeof(nchannels)
+ + sizeof(samplespersec)
+ + sizeof(avgbps)
+ + sizeof(blockalign)
+ + sizeof(bitspersample)
+ + sizeof(cbsize);
+
+ ui32_t RIFF_len = data_len + SimpleWavHeaderLength - 8;
+
+ memcpy(p, &FCC_RIFF, sizeof(fourcc)); 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) = 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) = KM_i32_LE(data_len); p += 4;
+
+ return OutFile.Write(tmp_header, SimpleWavHeaderLength, &write_count);
+}
+
+//
+ASDCP::Result_t
+ASDCP::Wav::SimpleWaveHeader::ReadFromFile(const Kumu::FileReader& InFile, ui32_t* data_start)
+{
+ ui32_t read_count = 0;
+ ui32_t local_data_start = 0;
+ ASDCP::PCM::FrameBuffer TmpBuffer(MaxWavHeader);
+
+ if ( data_start == 0 )
+ data_start = &local_data_start;
+
+ Result_t result = InFile.Read(TmpBuffer.Data(), TmpBuffer.Capacity(), &read_count);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = ReadFromBuffer(TmpBuffer.RoData(), read_count, data_start);
+
+ return result;
+}
+
+ASDCP::Result_t
+ASDCP::Wav::SimpleWaveHeader::ReadFromBuffer(const byte_t* buf, ui32_t buf_len, ui32_t* data_start)
+{
+ if ( buf_len < SimpleWavHeaderLength )
+ return RESULT_SMALLBUF;
+
+ *data_start = 0;
+ const byte_t* p = buf;
+ const byte_t* end_p = p + buf_len;
+
+ fourcc test_RIFF(p); p += 4;
+ if ( test_RIFF != FCC_RIFF )
+ {
+ // DefaultLogSink().Debug("File does not begin with RIFF header\n");
+ return RESULT_RAW_FORMAT;
+ }
+
+ ui32_t RIFF_len = KM_i32_LE(*(ui32_t*)p); p += 4;
+
+ fourcc test_WAVE(p); p += 4;
+ if ( test_WAVE != FCC_WAVE )
+ {
+ DefaultLogSink().Debug("File does not contain a WAVE header\n");
+ return RESULT_RAW_FORMAT;
+ }
+
+ fourcc test_fcc;
+
+ while ( p < end_p )
+ {
+ test_fcc = fourcc(p); p += 4;
+ ui32_t chunk_size = KM_i32_LE(*(ui32_t*)p); p += 4;
+
+ if ( test_fcc == FCC_data )
+ {
+ if ( chunk_size > RIFF_len )
+ {
+ DefaultLogSink().Error("Chunk size %u larger than file: %u\n", chunk_size, RIFF_len);
+ return RESULT_RAW_FORMAT;
+ }
+
+ data_len = chunk_size;
+ *data_start = p - buf;
+ break;
+ }
+
+ if ( test_fcc == FCC_fmt_ )
+ {
+ ui16_t format = KM_i16_LE(*(ui16_t*)p); p += 2;
+
+ if ( format != WAVE_FORMAT_PCM && format != WAVE_FORMAT_EXTENSIBLE )
+ {
+ DefaultLogSink().Error("Expecting uncompressed PCM data, got format type %hd\n", format);
+ return RESULT_RAW_FORMAT;
+ }
+
+ 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; // 16 is the number of bytes read in this block
+ }
+ else
+ {
+ p += chunk_size;
+ }
+ }
+
+ if ( *data_start == 0 ) // can't have no data!
+ {
+ DefaultLogSink().Error("No data chunk found, file contains no essence\n");
+ return RESULT_RAW_FORMAT;
+ }
+
+ return RESULT_OK;
+}
+
+//------------------------------------------------------------------------------------------
+// conversion algorithms from http://www.borg.com/~jglatt/tech/aiff.htm
+
+//
+void
+Rat_to_extended(ASDCP::Rational rate, byte_t* buf)
+{
+ memset(buf, 0, 10);
+ ui32_t value = (ui32_t)ceil(rate.Quotient());
+ ui32_t exp = value;
+ exp >>= 1;
+ ui8_t i = 0;
+
+ for ( ; i < 32; i++ )
+ {
+ exp >>= 1;
+ if ( ! exp )
+ break;
+ }
+
+ *(buf+1) = i;
+
+ for ( i = 32; i != 0 ; i-- )
+ {
+ if ( value & 0x80000000 )
+ break;
+ value <<= 1;
+ }
+
+ *(ui32_t*)(buf+2) = KM_i32_BE(value);
+}
+
+//
+ASDCP::Rational
+extended_to_Rat(const byte_t* buf)
+{
+ ui32_t last = 0;
+ ui32_t mantissa = KM_i32_BE(*(ui32_t*)(buf+2));
+
+ byte_t exp = 30 - *(buf+1);
+
+ while ( exp-- )
+ {
+ last = mantissa;
+ mantissa >>= 1;
+ }
+
+ if ( last & 0x00000001 )
+ mantissa++;
+
+ return ASDCP::Rational(mantissa, 1);
+}
+
+//
+void
+ASDCP::AIFF::SimpleAIFFHeader::FillADesc(ASDCP::PCM::AudioDescriptor& ADesc, ASDCP::Rational PictureRate) const
+{
+ ADesc.EditRate = PictureRate;
+
+ ADesc.ChannelCount = numChannels;
+ ADesc.AudioSamplingRate = extended_to_Rat(sampleRate);
+ ADesc.QuantizationBits = sampleSize;
+ ADesc.BlockAlign = sampleSize / 8;
+ ADesc.AvgBps = (ui32_t) (ADesc.BlockAlign * ADesc.AudioSamplingRate.Quotient());
+ ui32_t FrameBufferSize = ASDCP::PCM::CalcFrameBufferSize(ADesc);
+ ADesc.ContainerDuration = data_len / FrameBufferSize;
+ ADesc.ChannelFormat = PCM::CF_NONE;
+}
+
+//
+ASDCP::Result_t
+ASDCP::AIFF::SimpleAIFFHeader::ReadFromFile(const Kumu::FileReader& InFile, ui32_t* data_start)
+{
+ ui32_t read_count = 0;
+ ui32_t local_data_start = 0;
+ ASDCP::PCM::FrameBuffer TmpBuffer(Wav::MaxWavHeader);
+
+ if ( data_start == 0 )
+ data_start = &local_data_start;
+
+ Result_t result = InFile.Read(TmpBuffer.Data(), TmpBuffer.Capacity(), &read_count);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = ReadFromBuffer(TmpBuffer.RoData(), read_count, data_start);
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::AIFF::SimpleAIFFHeader::ReadFromBuffer(const byte_t* buf, ui32_t buf_len, ui32_t* data_start)
+{
+ if ( buf_len < 32 )
+ return RESULT_SMALLBUF;
+
+ *data_start = 0;
+ const byte_t* p = buf;
+ const byte_t* end_p = p + buf_len;
+
+ fourcc test_FORM(p); p += 4;
+ if ( test_FORM != FCC_FORM )
+ {
+ // DefaultLogSink().Debug("File does not begin with FORM header\n");
+ return RESULT_RAW_FORMAT;
+ }
+
+ ui32_t RIFF_len = KM_i32_BE(*(ui32_t*)p); p += 4;
+
+ fourcc test_AIFF(p); p += 4;
+ if ( test_AIFF != FCC_AIFF )
+ {
+ DefaultLogSink().Debug("File does not contain an AIFF header\n");
+ return RESULT_RAW_FORMAT;
+ }
+
+ fourcc test_fcc;
+
+ while ( p < end_p )
+ {
+ test_fcc = fourcc(p); p += 4;
+ ui32_t chunk_size = KM_i32_BE(*(ui32_t*)p); p += 4;
+
+ if ( test_fcc == FCC_COMM )
+ {
+ 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;
+ }
+ else if ( test_fcc == FCC_SSND )
+ {
+ if ( chunk_size > RIFF_len )
+ {
+ DefaultLogSink().Error("Chunk size %u larger than file: %u\n", chunk_size, RIFF_len);
+ return RESULT_RAW_FORMAT;
+ }
+
+ ui32_t offset = KM_i32_BE(*(ui32_t*)p); p += 4;
+ p += 4; // blockSize;
+
+ data_len = chunk_size - 8;
+ *data_start = (p - buf) + offset;
+ break;
+ }
+ else
+ {
+ p += chunk_size;
+ }
+ }
+
+ if ( *data_start == 0 ) // can't have no data!
+ {
+ DefaultLogSink().Error("No data chunk found, file contains no essence\n");
+ return RESULT_RAW_FORMAT;
+ }
+
+ return RESULT_OK;
+}
+
+
+
+//
+// end Wav.cpp
+//
diff --git a/asdcplib/src/Wav.h b/asdcplib/src/Wav.h
new file mode 100755
index 0000000..09ee48a
--- /dev/null
+++ b/asdcplib/src/Wav.h
@@ -0,0 +1,127 @@
+/*
+Copyright (c) 2005-2009, 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 Wav.h
+ \version $Id: Wav.h,v 1.5 2009/04/09 19:24:14 msheby Exp $
+ \brief Wave file common elements
+*/
+
+#ifndef _WAV_H_
+#define _WAV_H_
+
+#include <KM_fileio.h>
+#include <AS_DCP.h>
+
+namespace ASDCP
+{
+ //
+ class fourcc
+ {
+ private:
+ byte_t data[4];
+
+ public:
+ inline fourcc() { memset( data, 0, 4 ); }
+ inline fourcc( const char* v ) { memcpy( this->data, v, 4 ); }
+ inline fourcc( const byte_t* v ) { memcpy( this->data, v, 4 ); }
+ inline fourcc& operator=(const fourcc & s) { memcpy( this->data, s.data, 4); return *this; }
+ inline bool operator==(const fourcc &rhs) { return memcmp(data, rhs.data, 4) == 0 ? true : false; }
+ inline bool operator!=(const fourcc &rhs) { return memcmp(data, rhs.data, 4) != 0 ? true : false; }
+ };
+
+ namespace AIFF
+ {
+ const fourcc FCC_FORM("FORM");
+ const fourcc FCC_AIFF("AIFF");
+ const fourcc FCC_COMM("COMM");
+ const fourcc FCC_SSND("SSND");
+
+ class SimpleAIFFHeader
+ {
+ public:
+ ui16_t numChannels;
+ ui32_t numSampleFrames;
+ ui16_t sampleSize;
+ byte_t sampleRate[10]; // 80-bit IEEE 754 float
+ ui32_t data_len;
+
+ SimpleAIFFHeader() :
+ numChannels(0), numSampleFrames(0), sampleSize(0), data_len(0) {
+ memset(sampleRate, 0, 10);
+ }
+
+ Result_t ReadFromBuffer(const byte_t* buf, ui32_t buf_len, ui32_t* data_start);
+ Result_t ReadFromFile(const Kumu::FileReader& InFile, ui32_t* data_start);
+ void FillADesc(ASDCP::PCM::AudioDescriptor& ADesc, Rational PictureRate) const;
+ };
+
+ } // namespace AIFF
+
+ namespace Wav
+ {
+ const ui32_t MaxWavHeader = 1024*32; // must find "data" within this space or no happy
+
+ const fourcc FCC_RIFF("RIFF");
+ const fourcc FCC_WAVE("WAVE");
+ const fourcc FCC_fmt_("fmt ");
+ const fourcc FCC_data("data");
+
+ const ui16_t WAVE_FORMAT_PCM = 1;
+ const ui16_t WAVE_FORMAT_EXTENSIBLE = 65534;
+
+ //
+ class SimpleWaveHeader
+ {
+ public:
+ ui16_t format;
+ ui16_t nchannels;
+ ui32_t samplespersec;
+ ui32_t avgbps;
+ ui16_t blockalign;
+ ui16_t bitspersample;
+ ui16_t cbsize;
+ ui32_t data_len;
+
+ SimpleWaveHeader() :
+ format(0), nchannels(0), samplespersec(0), avgbps(0),
+ blockalign(0), bitspersample(0), cbsize(0), data_len(0) {}
+
+ SimpleWaveHeader(ASDCP::PCM::AudioDescriptor& ADesc);
+
+ Result_t ReadFromBuffer(const byte_t* buf, ui32_t buf_len, ui32_t* data_start);
+ 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;
+ };
+
+ } // namespace Wav
+} // namespace ASDCP
+
+#endif // _WAV_H_
+
+//
+// end Wav.h
+//
diff --git a/asdcplib/src/WavFileWriter.h b/asdcplib/src/WavFileWriter.h
new file mode 100755
index 0000000..daf26ea
--- /dev/null
+++ b/asdcplib/src/WavFileWriter.h
@@ -0,0 +1,198 @@
+/*
+Copyright (c) 2005-2009, 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 WavFileWriter.h
+ \version $Id: WavFileWriter.h,v 1.6 2009/04/09 19:16:49 msheby Exp $
+ \brief demux and write PCM data to WAV file(s)
+*/
+
+#include <KM_fileio.h>
+#include <KM_log.h>
+#include <Wav.h>
+#include <list>
+
+#ifndef _WAVFILEWRITER_H_
+#define _WAVFILEWRITER_H_
+
+
+//
+class WavFileElement : public Kumu::FileWriter
+{
+ ASDCP::PCM::FrameBuffer m_Buf;
+ byte_t* m_p;
+
+ WavFileElement();
+ KM_NO_COPY_CONSTRUCT(WavFileElement);
+
+public:
+ WavFileElement(ui32_t s) : m_Buf(s), m_p(0)
+ {
+ m_p = m_Buf.Data();
+ }
+
+ ~WavFileElement() {}
+
+ void WriteSample(const byte_t* sample, ui32_t sample_size)
+ {
+ memcpy(m_p, sample, sample_size);
+ m_p += sample_size;
+ }
+
+ ASDCP::Result_t Flush()
+ {
+ ui32_t write_count = 0;
+
+ if ( m_p == m_Buf.Data() )
+ return ASDCP::RESULT_EMPTY_FB;
+
+ ui32_t write_size = m_p - m_Buf.Data();
+ m_p = m_Buf.Data();
+ return Write(m_Buf.RoData(), write_size, &write_count);
+ }
+};
+
+
+//
+class WavFileWriter
+{
+ ASDCP::PCM::AudioDescriptor m_ADesc;
+ std::list<WavFileElement*> m_OutFile;
+ ui32_t m_ChannelCount;
+ ASDCP_NO_COPY_CONSTRUCT(WavFileWriter);
+
+ public:
+ WavFileWriter() : m_ChannelCount(0) {}
+ ~WavFileWriter()
+ {
+ while ( ! m_OutFile.empty() )
+ {
+ delete m_OutFile.back();
+ m_OutFile.pop_back();
+ }
+ }
+
+ //
+ enum SplitType_t {
+ ST_NONE, // write all channels to a single WAV file
+ ST_MONO, // write each channel a separate WAV file
+ ST_STEREO // write channel pairs to separate WAV files
+ };
+
+ ASDCP::Result_t
+ OpenWrite(ASDCP::PCM::AudioDescriptor &ADesc, const char* file_root, SplitType_t split = ST_NONE)
+ {
+ ASDCP_TEST_NULL_STR(file_root);
+ char filename[Kumu::MaxFilePath];
+ ui32_t file_count = 0;
+ ASDCP::Result_t result = ASDCP::RESULT_OK;
+ m_ADesc = ADesc;
+
+ switch ( split )
+ {
+ case ST_NONE:
+ file_count = 1;
+ m_ChannelCount = m_ADesc.ChannelCount;
+ break;
+
+ case ST_MONO:
+ file_count = m_ADesc.ChannelCount;
+ m_ChannelCount = 1;
+ break;
+
+ case ST_STEREO:
+ if ( m_ADesc.ChannelCount % 2 != 0 )
+ {
+ Kumu::DefaultLogSink().Error("Unable to create 2-channel splits with odd number of input channels.\n");
+ return ASDCP::RESULT_PARAM;
+ }
+
+ file_count = m_ADesc.ChannelCount / 2;
+ m_ChannelCount = 2;
+ break;
+ }
+ assert(file_count && m_ChannelCount);
+
+ ui32_t element_size = ASDCP::PCM::CalcFrameBufferSize(m_ADesc) / file_count;
+
+ for ( ui32_t i = 0; i < file_count && ASDCP_SUCCESS(result); i++ )
+ {
+ snprintf(filename, Kumu::MaxFilePath, "%s_%u.wav", file_root, (i + 1));
+ m_OutFile.push_back(new WavFileElement(element_size));
+ result = m_OutFile.back()->OpenWrite(filename);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ ASDCP::PCM::AudioDescriptor tmpDesc = m_ADesc;
+ tmpDesc.ChannelCount = m_ChannelCount;
+ ASDCP::Wav::SimpleWaveHeader Wav(tmpDesc);
+ result = Wav.WriteToFile(*(m_OutFile.back()));
+ }
+ }
+
+ return result;
+ }
+
+ ASDCP::Result_t
+ WriteFrame(ASDCP::PCM::FrameBuffer& FB)
+ {
+ if ( m_OutFile.empty() )
+ return ASDCP::RESULT_STATE;
+
+ if ( m_OutFile.size() == 1 ) // no de-interleave needed, just write out the frame
+ return m_OutFile.back()->Write(FB.RoData(), FB.Size(), 0);
+
+ std::list<WavFileElement*>::iterator fi;
+ ui32_t sample_size = m_ADesc.QuantizationBits / 8;
+ const byte_t* p = FB.RoData();
+ const byte_t* end_p = p + FB.Size();
+
+ while ( p < end_p )
+ {
+ for ( fi = m_OutFile.begin(); fi != m_OutFile.end(); fi++ )
+ {
+ for ( ui32_t c = 0; c < m_ChannelCount; c++ )
+ {
+ (*fi)->WriteSample(p, sample_size);
+ p += sample_size;
+ }
+ }
+ }
+
+ ASDCP::Result_t result = ASDCP::RESULT_OK;
+
+ for ( fi = m_OutFile.begin(); fi != m_OutFile.end() && ASDCP_SUCCESS(result); fi++ )
+ result = (*fi)->Flush();
+
+ return result;
+ }
+};
+
+
+#endif // _WAVFILEWRITER_H_
+
+//
+// end WavFileWriter.h
+//
diff --git a/asdcplib/src/asdcp-info.cpp b/asdcplib/src/asdcp-info.cpp
new file mode 100755
index 0000000..0622763
--- /dev/null
+++ b/asdcplib/src/asdcp-info.cpp
@@ -0,0 +1,428 @@
+/*
+Copyright (c) 2003-2012, 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 asdcp-info.cpp
+ \version $Id: asdcp-info.cpp,v 1.1 2012/02/03 19:49:56 jhurst Exp $
+ \brief AS-DCP file metadata utility
+
+ This program provides metadata information about an AS-DCP file.
+
+ For more information about asdcplib, please refer to the header file AS_DCP.h
+*/
+
+#include <KM_fileio.h>
+#include <AS_DCP.h>
+#include <MXF.h>
+#include <Metadata.h>
+#include <openssl/sha.h>
+
+using namespace Kumu;
+using namespace ASDCP;
+
+const ui32_t FRAME_BUFFER_SIZE = 4 * Kumu::Megabyte;
+
+//------------------------------------------------------------------------------------------
+//
+// command line option parser class
+
+static const char* PROGRAM_NAME = "asdcp-info"; // program name for messages
+
+
+// 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 = stdout)
+{
+ fprintf(stream, "\n\
+%s (asdcplib %s)\n\n\
+Copyright (c) 2003-2012 John Hurst\n\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",
+ PROGRAM_NAME, ASDCP::Version(), PROGRAM_NAME);
+}
+
+//
+void
+usage(FILE* stream = stdout)
+{
+ fprintf(stream, "\
+USAGE:%s [-h|-help] [-V]\n\
+\n\
+ %s [-3] [-H] [-n] <input-file>+\n\
+\n\
+Options:\n\
+ -3 - Force stereoscopic interpretation of a JP2K file\n\
+ -h | -help - Show help\n\
+ -H - Show MXF header metadata\n\
+ -n - Show index\n\
+ -V - Show version information\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",
+ PROGRAM_NAME, PROGRAM_NAME);
+
+}
+
+//
+class CommandOptions
+{
+ CommandOptions();
+
+public:
+ bool error_flag; // true if the given options are in error or not complete
+ bool version_flag; // true if the version display option was selected
+ bool help_flag; // true if the help display option was selected
+ PathList_t filenames; // list of filenames to be processed
+ bool showindex_flag; // true if index is to be displayed
+ bool showheader_flag; // true if MXF file header is to be displayed
+ bool stereo_image_flag; // if true, expect stereoscopic JP2K input (left eye first)
+
+ //
+ CommandOptions(int argc, const char** argv) :
+ error_flag(true), version_flag(false), help_flag(false),
+ showindex_flag(), showheader_flag(), stereo_image_flag(false)
+ {
+ for ( int i = 1; i < argc; ++i )
+ {
+
+ if ( (strcmp( argv[i], "-help") == 0) )
+ {
+ help_flag = true;
+ continue;
+ }
+
+ if ( argv[i][0] == '-'
+ && ( isalpha(argv[i][1]) || isdigit(argv[i][1]) )
+ && argv[i][2] == 0 )
+ {
+ switch ( argv[i][1] )
+ {
+ case '3': stereo_image_flag = true; break;
+ case 'H': showheader_flag = true; break;
+ case 'h': help_flag = true; break;
+ case 'n': showindex_flag = true; break;
+ case 'V': version_flag = true; break;
+
+ default:
+ fprintf(stderr, "Unrecognized option: %s\n", argv[i]);
+ return;
+ }
+ }
+ else
+ {
+ if ( argv[i][0] != '-' )
+ {
+ filenames.push_back(argv[i]);
+ }
+ else
+ {
+ fprintf(stderr, "Unrecognized argument: %s\n", argv[i]);
+ return;
+ }
+ }
+ }
+
+ if ( help_flag || version_flag )
+ return;
+
+ if ( filenames.empty() )
+ {
+ fputs("Option requires at least one filename argument.\n", stderr);
+ return;
+ }
+
+ error_flag = false;
+ }
+};
+
+//------------------------------------------------------------------------------------------
+//
+
+//
+// These classes wrap the irregular names in the asdcplib API
+// so that I can use a template to simplify the implementation
+// of show_file_info()
+
+class MyVideoDescriptor : public MPEG2::VideoDescriptor
+{
+ public:
+ void FillDescriptor(MPEG2::MXFReader& Reader) {
+ Reader.FillVideoDescriptor(*this);
+ }
+
+ void Dump(FILE* stream) {
+ MPEG2::VideoDescriptorDump(*this, stream);
+ }
+};
+
+class MyPictureDescriptor : public JP2K::PictureDescriptor
+{
+ public:
+ void FillDescriptor(JP2K::MXFReader& Reader) {
+ Reader.FillPictureDescriptor(*this);
+ }
+
+ void Dump(FILE* stream) {
+ JP2K::PictureDescriptorDump(*this, stream);
+ }
+};
+
+class MyStereoPictureDescriptor : public JP2K::PictureDescriptor
+{
+ public:
+ void FillDescriptor(JP2K::MXFSReader& Reader) {
+ Reader.FillPictureDescriptor(*this);
+ }
+
+ void Dump(FILE* stream) {
+ JP2K::PictureDescriptorDump(*this, stream);
+ }
+};
+
+class MyAudioDescriptor : public PCM::AudioDescriptor
+{
+ public:
+ void FillDescriptor(PCM::MXFReader& Reader) {
+ Reader.FillAudioDescriptor(*this);
+ }
+
+ void Dump(FILE* stream) {
+ PCM::AudioDescriptorDump(*this, stream);
+ }
+};
+
+class MyTextDescriptor : public TimedText::TimedTextDescriptor
+{
+ public:
+ void FillDescriptor(TimedText::MXFReader& Reader) {
+ Reader.FillTimedTextDescriptor(*this);
+ }
+
+ void Dump(FILE* stream) {
+ TimedText::DescriptorDump(*this, stream);
+ }
+};
+
+// MSVC didn't like the function template, so now it's a static class method
+template<class ReaderT, class DescriptorT>
+class FileInfoWrapper
+{
+public:
+ static Result_t
+ file_info(CommandOptions& Options, const char* type_string, FILE* stream = 0)
+ {
+ assert(type_string);
+ if ( stream == 0 )
+ stream = stdout;
+
+ Result_t result = RESULT_OK;
+ ReaderT Reader;
+ result = Reader.OpenRead(Options.filenames.front().c_str());
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ fprintf(stdout, "File essence type is %s.\n", type_string);
+
+ if ( Options.showheader_flag )
+ Reader.DumpHeaderMetadata(stream);
+
+ WriterInfo WI;
+ Reader.FillWriterInfo(WI);
+ WriterInfoDump(WI, stream);
+
+ DescriptorT Desc;
+ Desc.FillDescriptor(Reader);
+ Desc.Dump(stream);
+
+ if ( Options.showindex_flag )
+ Reader.DumpIndex(stream);
+ }
+ else if ( result == RESULT_FORMAT && Options.showheader_flag )
+ {
+ Reader.DumpHeaderMetadata(stream);
+ }
+
+ return result;
+ }
+};
+
+// Read header metadata from an ASDCP file
+//
+Result_t
+show_file_info(CommandOptions& Options)
+{
+ EssenceType_t EssenceType;
+ Result_t result = ASDCP::EssenceType(Options.filenames.front().c_str(), EssenceType);
+
+ if ( ASDCP_FAILURE(result) )
+ return result;
+
+ if ( EssenceType == ESS_MPEG2_VES )
+ {
+ result = FileInfoWrapper<ASDCP::MPEG2::MXFReader, MyVideoDescriptor>::file_info(Options, "MPEG2 video");
+ }
+ else if ( EssenceType == ESS_PCM_24b_48k || EssenceType == ESS_PCM_24b_96k )
+ {
+ result = FileInfoWrapper<ASDCP::PCM::MXFReader, MyAudioDescriptor>::file_info(Options, "PCM audio");
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ const Dictionary* Dict = &DefaultCompositeDict();
+ PCM::MXFReader Reader;
+ MXF::OPAtomHeader OPAtomHeader(Dict);
+ MXF::WaveAudioDescriptor *descriptor = 0;
+
+ result = Reader.OpenRead(Options.filenames.front().c_str());
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Reader.OPAtomHeader().GetMDObjectByType(Dict->ul(MDD_WaveAudioDescriptor), reinterpret_cast<MXF::InterchangeObject**>(&descriptor));
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ char buf[64];
+ fprintf(stdout, " ChannelAssignment: %s\n", descriptor->ChannelAssignment.EncodeString(buf, 64));
+ }
+ }
+ }
+ else if ( EssenceType == ESS_JPEG_2000 )
+ {
+ if ( Options.stereo_image_flag )
+ {
+ result = FileInfoWrapper<ASDCP::JP2K::MXFSReader,
+ MyStereoPictureDescriptor>::file_info(Options, "JPEG 2000 stereoscopic pictures");
+ }
+ else
+ {
+ result = FileInfoWrapper<ASDCP::JP2K::MXFReader,
+ MyPictureDescriptor>::file_info(Options, "JPEG 2000 pictures");
+ }
+ }
+ else if ( EssenceType == ESS_JPEG_2000_S )
+ {
+ result = FileInfoWrapper<ASDCP::JP2K::MXFSReader,
+ MyStereoPictureDescriptor>::file_info(Options, "JPEG 2000 stereoscopic pictures");
+ }
+ else if ( EssenceType == ESS_TIMED_TEXT )
+ {
+ result = FileInfoWrapper<ASDCP::TimedText::MXFReader, MyTextDescriptor>::file_info(Options, "Timed Text");
+ }
+ else
+ {
+ fprintf(stderr, "File is not AS-DCP: %s\n", Options.filenames.front().c_str());
+ Kumu::FileReader Reader;
+ const Dictionary* Dict = &DefaultCompositeDict();
+ MXF::OPAtomHeader TestHeader(Dict);
+
+ result = Reader.OpenRead(Options.filenames.front().c_str());
+
+ if ( ASDCP_SUCCESS(result) )
+ result = TestHeader.InitFromFile(Reader); // test UL and OP
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ TestHeader.Partition::Dump(stdout);
+
+ if ( MXF::Identification* ID = TestHeader.GetIdentification() )
+ ID->Dump(stdout);
+ else
+ fputs("File contains no Identification object.\n", stdout);
+
+ if ( MXF::SourcePackage* SP = TestHeader.GetSourcePackage() )
+ SP->Dump(stdout);
+ else
+ fputs("File contains no SourcePackage object.\n", stdout);
+ }
+ else
+ {
+ fputs("File is not MXF.\n", stdout);
+ }
+ }
+
+ return result;
+}
+
+//
+int
+main(int argc, const char** argv)
+{
+ Result_t result = RESULT_OK;
+ char str_buf[64];
+ CommandOptions Options(argc, argv);
+
+ if ( Options.version_flag )
+ banner();
+
+ if ( Options.help_flag )
+ usage();
+
+ if ( Options.version_flag || Options.help_flag )
+ return 0;
+
+ if ( Options.error_flag )
+ {
+ fprintf(stderr, "There was a problem. Type %s -h for help.\n", PROGRAM_NAME);
+ return 3;
+ }
+
+ while ( ! Options.filenames.empty() && ASDCP_SUCCESS(result) )
+ {
+ result = show_file_info(Options);
+ Options.filenames.pop_front();
+ }
+
+ if ( ASDCP_FAILURE(result) )
+ {
+ fputs("Program stopped on error.\n", stderr);
+
+ if ( result == RESULT_SFORMAT )
+ {
+ fputs("Use option '-3' to force stereoscopic mode.\n", stderr);
+ }
+ else if ( result != RESULT_FAIL )
+ {
+ fputs(result, stderr);
+ fputc('\n', stderr);
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+
+//
+// end asdcp-info.cpp
+//
diff --git a/asdcplib/src/asdcp-mem-test.cpp b/asdcplib/src/asdcp-mem-test.cpp
new file mode 100755
index 0000000..0ce6d90
--- /dev/null
+++ b/asdcplib/src/asdcp-mem-test.cpp
@@ -0,0 +1,148 @@
+/*
+Copyright (c) 2004-2009, 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 asdcp-mem-test.cpp
+ \version $Id: asdcp-mem-test.cpp,v 1.4 2009/04/09 19:24:14 msheby Exp $
+ \brief AS-DCP frame buffer allocation test
+*/
+
+
+#include <AS_DCP_internal.h>
+//#include <KM_platform.h>
+#include <KM_prng.h>
+
+#include <iostream>
+#include <assert.h>
+
+using namespace ASDCP;
+using namespace Kumu;
+
+const ui32_t buf_size = 1024;
+FortunaRNG RNG;
+
+//
+int a()
+{
+ FrameBuffer FB;
+ FB.Capacity(buf_size);
+ assert(FB.Capacity() == buf_size);
+ RNG.FillRandom(FB.Data(), FB.Capacity());
+
+ return 0;
+}
+
+//
+int b()
+{
+ byte_t* buf = (byte_t*)malloc(buf_size);
+ assert(buf);
+ RNG.FillRandom(buf, buf_size);
+
+ {
+ FrameBuffer FB;
+ FB.SetData(buf, buf_size);
+ assert(FB.Data() == buf);
+ assert(FB.Capacity() == buf_size);
+ // ~FB() is called...
+ }
+
+ free(buf);
+ return 0;
+}
+
+//
+int c()
+{
+ byte_t* buf = (byte_t*)malloc(buf_size);
+ assert(buf);
+ RNG.FillRandom(buf, buf_size);
+
+ {
+ FrameBuffer FB;
+ FB.SetData(buf, buf_size);
+ assert(FB.Data() == buf);
+ assert(FB.Capacity() == buf_size);
+
+ FB.SetData(0,0);
+ assert(FB.Data() == 0);
+ assert(FB.Capacity() == 0);
+
+ FB.Capacity(buf_size);
+ assert(FB.Capacity() == buf_size);
+ RNG.FillRandom(FB.Data(), FB.Capacity());
+ // ~FB() is called...
+ }
+
+ free(buf);
+ return 0;
+}
+
+//
+int d()
+{
+ // MPEG2::Parser mPFile;
+ MPEG2::MXFReader mRFile;
+ Result_t result = mRFile.OpenRead("../tests/write_test_mpeg.mxf");
+ assert(ASDCP_SUCCESS(result));
+
+ // MPEG2::MXFWriter mWFile;
+ JP2K::CodestreamParser jPCFile;
+ JP2K::SequenceParser jPSFile;
+ JP2K::MXFReader jRFile;
+ JP2K::MXFWriter jWFile;
+
+ PCM::WAVParser pPFile;
+ PCM::MXFReader pRFile;
+ PCM::MXFWriter pWFile;
+ return 0;
+}
+
+//
+int
+main( int argc, char **argv )
+{
+ ui32_t i = 0x00010000;
+ fputs("Watch your process monitor, memory usage should not change after startup.\n", stderr);
+
+ while ( i-- )
+ {
+ a();
+ b();
+ c();
+ d();
+
+ if ( i && ( i % 1000 ) == 0 )
+ fputc('.', stderr);
+ }
+
+ fputc('\n', stderr);
+ return 0;
+}
+
+
+//
+// end asdcp-mem-test.cpp
+//
diff --git a/asdcplib/src/asdcp-test.cpp b/asdcplib/src/asdcp-test.cpp
new file mode 100755
index 0000000..05f486f
--- /dev/null
+++ b/asdcplib/src/asdcp-test.cpp
@@ -0,0 +1,2087 @@
+/*
+Copyright (c) 2003-2012, 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 asdcp-test.cpp
+ \version $Id: asdcp-test.cpp,v 1.46 2012/02/03 19:49:56 jhurst Exp $
+ \brief AS-DCP file manipulation utility
+
+ This program provides command line access to the major features of the asdcplib
+ library, and serves as a library unit test which provides the functionality of
+ the supported use cases.
+
+ For more information about asdcplib, please refer to the header file AS_DCP.h
+
+ WARNING: While the asdcplib library attempts to provide a complete and secure
+ implementation of the cryptographic features of the AS-DCP file formats, this
+ unit test program is NOT secure and is therefore NOT SUITABLE FOR USE in a
+ production environment without some modification.
+
+ In particular, this program uses weak IV generation and externally generated
+ plaintext keys. These shortcomings exist because cryptographic-quality
+ random number generation and key management are outside the scope of the
+ asdcplib library. Developers using asdcplib for commercial implementations
+ claiming SMPTE conformance are expected to provide proper implementations of
+ these features.
+*/
+
+#include <KM_fileio.h>
+#include <KM_prng.h>
+#include <PCMParserList.h>
+#include <WavFileWriter.h>
+#include <MXF.h>
+#include <Metadata.h>
+#include <openssl/sha.h>
+
+#include <iostream>
+#include <assert.h>
+
+using namespace ASDCP;
+
+const ui32_t FRAME_BUFFER_SIZE = 4 * Kumu::Megabyte;
+
+//------------------------------------------------------------------------------------------
+//
+// command line option parser class
+
+static const char* PROGRAM_NAME = "asdcp-test"; // program name for messages
+const ui32_t MAX_IN_FILES = 16; // maximum number of input files handled by
+ // the command option parser
+
+// local program identification info written to file headers
+class MyInfo : public WriterInfo
+{
+public:
+ MyInfo()
+ {
+ static byte_t default_ProductUUID_Data[UUIDlen] =
+ { 0x7d, 0x83, 0x6e, 0x16, 0x37, 0xc7, 0x4c, 0x22,
+ 0xb2, 0xe0, 0x46, 0xa7, 0x17, 0xe8, 0x4f, 0x42 };
+
+ memcpy(ProductUUID, default_ProductUUID_Data, UUIDlen);
+ CompanyName = "WidgetCo";
+ ProductName = "asdcp-test";
+ ProductVersion = ASDCP::Version();
+ }
+} s_MyInfo;
+
+
+
+// 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 = stdout)
+{
+ fprintf(stream, "\n\
+%s (asdcplib %s)\n\n\
+Copyright (c) 2003-2012 John Hurst\n\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",
+ PROGRAM_NAME, ASDCP::Version(), PROGRAM_NAME);
+}
+
+//
+void
+usage(FILE* stream = stdout)
+{
+ fprintf(stream, "\
+USAGE: %s -c <output-file> [-3] [-a <uuid>] [-b <buffer-size>]\n\
+ [-d <duration>] [-e|-E] [-f <start-frame>] [-j <key-id-string>]\n\
+ [-k <key-string>] [-l <label>] [-L] [-M] [-p <frame-rate>] [-R]\n\
+ [-s <num>] [-v] [-W] [-z|-Z] <input-file> [<input-file-2> ...]\n\
+\n\
+ %s [-h|-help] [-V]\n\
+\n\
+ %s -i [-H] [-n] [-v] <input-file>\n\
+\n\
+ %s -g | -u\n\
+\n\
+ %s -G [-v] <input-file>\n\
+\n\
+ %s -t <input-file>\n\
+\n\
+ %s -x <file-prefix> [-3] [-b <buffer-size>] [-d <duration>]\n\
+ [-f <starting-frame>] [-m] [-p <frame-rate>] [-R] [-s <num>] [-S|-1]\n\
+ [-v] [-W] [-w] <input-file>\n\n",
+ PROGRAM_NAME, PROGRAM_NAME, PROGRAM_NAME, PROGRAM_NAME,
+ PROGRAM_NAME, PROGRAM_NAME, PROGRAM_NAME);
+
+ fprintf(stream, "\
+Major modes:\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 <output-file> - 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\
+ -h | -help - Show help\n\
+ -i - Show file info\n\
+ -t - Calculate message digest of input file\n\
+ -U - Dump UL catalog to stdout\n\
+ -u - Generate a random UUID value to stdout\n\
+ -V - Show version information\n\
+ -x <root-name> - Extract essence from AS-DCP file to named file(s)\n\
+\n");
+
+ fprintf(stream, "\
+Security Options:\n\
+ -e - Encrypt MPEG or JP2K headers (default)\n\
+ -E - Do not encrypt MPEG or JP2K headers\n\
+ -j <key-id-str> - Write key ID instead of creating a random value\n\
+ -k <key-string> - Use key for ciphertext operations\n\
+ -m - verify HMAC values when reading\n\
+ -M - Do not create HMAC values when writing\n\
+\n");
+
+ fprintf(stream, "\
+Read/Write Options:\n\
+ -a <UUID> - Specify the Asset ID of a file (with -c)\n\
+ -b <buffer-size> - Specify size in bytes of picture frame buffer.\n\
+ Defaults to 4,194,304 (4MB)\n\
+ -d <duration> - Number of frames to process, default all\n\
+ -f <start-frame> - Starting frame number, default 0\n\
+ -l <label> - Use given channel format label when writing MXF sound\n\
+ files. SMPTE 429-2 labels: '5.1', '6.1', '7.1', '7.1DS', 'WTF'.\n\
+ Default is no label (valid for Interop only).\n\
+ -L - Write SMPTE UL values instead of MXF Interop\n\
+ -p <rate> - fps of picture when wrapping PCM or JP2K:\n\
+ Use one of [23|24|25|30|48|50|60], 24 is default\n\
+ -R - Repeat the first frame over the entire file (picture\n\
+ essence only, requires -c, -d)\n\
+ -S - Split Wave essence to stereo WAV files during extract.\n\
+ Default is multichannel WAV\n\
+ -1 - Split Wave essence to mono WAV files during extract.\n\
+ Default is multichannel WAV\n\
+ -W - Read input file only, do not write source file\n\
+ -w <width> - Width of numeric element in a series of frame file names\n\
+ (use with -x, default 6).\n\
+ -z - Fail if j2c inputs have unequal parameters (default)\n\
+ -Z - Ignore unequal parameters in j2c inputs\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\
+\n\
+Other Options:\n\
+ -s <num> - Number of bytes of frame buffer to be dumped as hex to\n\
+ stderr, used with option -v\n\
+ -v - Verbose, prints informative messages to stderr\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\
+ o An argument of \"23\" to the -p option will be interpreted\n\
+ as 24000/1001 fps.\n\
+\n");
+}
+
+//
+enum MajorMode_t
+{
+ MMT_NONE,
+ MMT_INFO,
+ MMT_CREATE,
+ MMT_EXTRACT,
+ MMT_GEN_ID,
+ MMT_GEN_KEY,
+ MMT_GOP_START,
+ MMT_DIGEST,
+ MMT_UL_LIST,
+};
+
+//
+PCM::ChannelFormat_t
+decode_channel_fmt(const std::string& label_name)
+{
+ if ( label_name == "5.1" )
+ return PCM::CF_CFG_1;
+
+ else if ( label_name == "6.1" )
+ return PCM::CF_CFG_2;
+
+ else if ( label_name == "7.1" )
+ return PCM::CF_CFG_3;
+
+ else if ( label_name == "WTF" )
+ return PCM::CF_CFG_4;
+
+ else if ( label_name == "7.1DS" )
+ return PCM::CF_CFG_5;
+
+ fprintf(stderr, "Error decoding channel format string: %s\n", label_name.c_str());
+ fprintf(stderr, "Expecting '5.1', '6.1', '7.1', '7.1DS' or 'WTF'\n");
+ return PCM::CF_NONE;
+}
+
+//
+//
+class CommandOptions
+{
+ CommandOptions();
+
+public:
+ MajorMode_t mode;
+ bool error_flag; // true if the given options are in error or not complete
+ bool key_flag; // true if an encryption key was given
+ bool key_id_flag; // true if a key ID was given
+ bool asset_id_flag; // true if an asset ID was given
+ bool encrypt_header_flag; // true if mpeg headers are to be encrypted
+ bool write_hmac; // true if HMAC values are to be generated and written
+ bool read_hmac; // true if HMAC values are to be validated
+ bool split_wav; // true if PCM is to be extracted to stereo WAV files
+ bool mono_wav; // true if PCM is to be extracted to mono WAV files
+ bool verbose_flag; // true if the verbose option was selected
+ ui32_t fb_dump_size; // number of bytes of frame buffer to dump
+ bool showindex_flag; // true if index is to be displayed
+ bool showheader_flag; // true if MXF file header is to be displayed
+ bool no_write_flag; // true if no output files are to be written
+ bool version_flag; // true if the version display option was selected
+ bool help_flag; // true if the help display option was selected
+ bool stereo_image_flag; // if true, expect stereoscopic JP2K input (left eye first)
+ ui32_t number_width; // number of digits in a serialized filename (for JPEG extract)
+ ui32_t start_frame; // frame number to begin processing
+ ui32_t duration; // number of frames to be processed
+ bool duration_flag; // true if duration argument given
+ bool do_repeat; // if true and -c -d, repeat first input frame
+ bool use_smpte_labels; // if true, SMPTE UL values will be written instead of MXF Interop values
+ bool j2c_pedantic; // passed to JP2K::SequenceParser::OpenRead
+ ui32_t picture_rate; // fps of picture when wrapping PCM
+ ui32_t fb_size; // size of picture frame buffer
+ ui32_t file_count; // number of elements in filenames[]
+ const char* file_root; // filename pre for files written by the extract mode
+ const char* out_file; // name of mxf file created by create mode
+ byte_t key_value[KeyLen]; // value of given encryption key (when key_flag is true)
+ byte_t key_id_value[UUIDlen];// value of given key ID (when key_id_flag is true)
+ byte_t asset_id_value[UUIDlen];// value of asset ID (when asset_id_flag is true)
+ const char* filenames[MAX_IN_FILES]; // list of filenames to be processed
+ PCM::ChannelFormat_t channel_fmt; // audio channel arrangement
+
+ //
+ Rational PictureRate()
+ {
+ if ( picture_rate == 23 ) return EditRate_23_98;
+ if ( picture_rate == 24 ) return EditRate_24;
+ if ( picture_rate == 25 ) return EditRate_25;
+ if ( picture_rate == 30 ) return EditRate_30;
+ if ( picture_rate == 48 ) return EditRate_48;
+ if ( picture_rate == 50 ) return EditRate_50;
+ if ( picture_rate == 60 ) return EditRate_60;
+ if ( picture_rate == 96 ) return EditRate_96;
+ if ( picture_rate == 100 ) return EditRate_100;
+ if ( picture_rate == 120 ) return EditRate_120;
+ return EditRate_24;
+ }
+
+ //
+ const char* szPictureRate()
+ {
+ if ( picture_rate == 23 ) return "23.976";
+ if ( picture_rate == 24 ) return "24";
+ if ( picture_rate == 25 ) return "25";
+ if ( picture_rate == 30 ) return "30";
+ if ( picture_rate == 48 ) return "48";
+ if ( picture_rate == 50 ) return "50";
+ if ( picture_rate == 60 ) return "60";
+ if ( picture_rate == 96 ) return "96";
+ if ( picture_rate == 100 ) return "100";
+ if ( picture_rate == 120 ) return "120";
+ return "24";
+ }
+
+ //
+ CommandOptions(int argc, const char** argv) :
+ mode(MMT_NONE), error_flag(true), key_flag(false), key_id_flag(false), asset_id_flag(false),
+ encrypt_header_flag(true), write_hmac(true), read_hmac(false), split_wav(false), mono_wav(false),
+ verbose_flag(false), fb_dump_size(0), showindex_flag(false), showheader_flag(false),
+ no_write_flag(false), version_flag(false), help_flag(false), stereo_image_flag(false),
+ number_width(6), start_frame(0),
+ duration(0xffffffff), duration_flag(false), do_repeat(false), use_smpte_labels(false), j2c_pedantic(true),
+ picture_rate(24), fb_size(FRAME_BUFFER_SIZE), file_count(0), file_root(0), out_file(0),
+ channel_fmt(PCM::CF_NONE)
+ {
+ memset(key_value, 0, KeyLen);
+ memset(key_id_value, 0, UUIDlen);
+
+ for ( int i = 1; i < argc; i++ )
+ {
+
+ if ( (strcmp( argv[i], "-help") == 0) )
+ {
+ help_flag = true;
+ continue;
+ }
+
+ if ( argv[i][0] == '-'
+ && ( isalpha(argv[i][1]) || isdigit(argv[i][1]) )
+ && argv[i][2] == 0 )
+ {
+ switch ( argv[i][1] )
+ {
+ case '1': mono_wav = true; break;
+ case '2': split_wav = true; break;
+ case '3': stereo_image_flag = true; break;
+
+ case 'a':
+ asset_id_flag = true;
+ TEST_EXTRA_ARG(i, 'a');
+ {
+ ui32_t length;
+ Kumu::hex2bin(argv[i], asset_id_value, UUIDlen, &length);
+
+ if ( length != UUIDlen )
+ {
+ fprintf(stderr, "Unexpected asset ID length: %u, expecting %u characters.\n", length, UUIDlen);
+ return;
+ }
+ }
+ break;
+
+ case 'b':
+ TEST_EXTRA_ARG(i, 'b');
+ fb_size = abs(atoi(argv[i]));
+
+ if ( verbose_flag )
+ fprintf(stderr, "Frame Buffer size: %u bytes.\n", fb_size);
+
+ break;
+
+ case 'c':
+ TEST_EXTRA_ARG(i, 'c');
+ mode = MMT_CREATE;
+ out_file = argv[i];
+ break;
+
+ case 'd':
+ TEST_EXTRA_ARG(i, 'd');
+ duration_flag = true;
+ duration = abs(atoi(argv[i]));
+ break;
+
+ case 'E': encrypt_header_flag = false; break;
+ case 'e': encrypt_header_flag = true; break;
+
+ case 'f':
+ TEST_EXTRA_ARG(i, 'f');
+ start_frame = abs(atoi(argv[i]));
+ break;
+
+ case 'G': mode = MMT_GOP_START; break;
+ case 'g': mode = MMT_GEN_KEY; break;
+ case 'H': showheader_flag = true; break;
+ case 'h': help_flag = true; break;
+ case 'i': mode = MMT_INFO; break;
+
+ case 'j': key_id_flag = true;
+ TEST_EXTRA_ARG(i, 'j');
+ {
+ ui32_t length;
+ Kumu::hex2bin(argv[i], key_id_value, UUIDlen, &length);
+
+ if ( length != UUIDlen )
+ {
+ fprintf(stderr, "Unexpected key ID length: %u, expecting %u characters.\n", length, UUIDlen);
+ return;
+ }
+ }
+ break;
+
+ case 'k': key_flag = true;
+ TEST_EXTRA_ARG(i, 'k');
+ {
+ ui32_t length;
+ Kumu::hex2bin(argv[i], key_value, KeyLen, &length);
+
+ if ( length != KeyLen )
+ {
+ fprintf(stderr, "Unexpected key length: %u, expecting %u characters.\n", length, KeyLen);
+ return;
+ }
+ }
+ break;
+
+ case 'l':
+ TEST_EXTRA_ARG(i, 'l');
+ channel_fmt = decode_channel_fmt(argv[i]);
+ break;
+
+ case 'L': use_smpte_labels = true; break;
+ case 'M': write_hmac = false; break;
+ case 'm': read_hmac = true; break;
+ case 'n': showindex_flag = true; break;
+
+ case 'p':
+ TEST_EXTRA_ARG(i, 'p');
+ picture_rate = abs(atoi(argv[i]));
+ break;
+
+ case 'R': do_repeat = true; break;
+ case 'S': split_wav = true; break;
+
+ case 's':
+ TEST_EXTRA_ARG(i, 's');
+ fb_dump_size = abs(atoi(argv[i]));
+ break;
+
+ case 't': mode = MMT_DIGEST; break;
+ case 'U': mode = MMT_UL_LIST; break;
+ case 'u': mode = MMT_GEN_ID; break;
+ case 'V': version_flag = true; break;
+ case 'v': verbose_flag = true; break;
+ case 'W': no_write_flag = true; break;
+
+ case 'w':
+ TEST_EXTRA_ARG(i, 'w');
+ number_width = abs(atoi(argv[i]));
+ break;
+
+ case 'x':
+ TEST_EXTRA_ARG(i, 'x');
+ mode = MMT_EXTRACT;
+ file_root = argv[i];
+ break;
+
+ case 'Z': j2c_pedantic = false; break;
+ case 'z': j2c_pedantic = true; break;
+
+ default:
+ fprintf(stderr, "Unrecognized option: %s\n", argv[i]);
+ return;
+ }
+ }
+ else
+ {
+
+ if ( argv[i][0] != '-' )
+ {
+ filenames[file_count++] = argv[i];
+ }
+ else
+ {
+ fprintf(stderr, "Unrecognized argument: %s\n", argv[i]);
+ return;
+ }
+
+ if ( file_count >= MAX_IN_FILES )
+ {
+ fprintf(stderr, "Filename lists exceeds maximum list size: %u\n", MAX_IN_FILES);
+ return;
+ }
+ }
+ }
+
+ if ( help_flag || version_flag )
+ return;
+
+ if ( ( mode == MMT_INFO
+ || mode == MMT_CREATE
+ || mode == MMT_EXTRACT
+ || mode == MMT_GOP_START
+ || mode == MMT_DIGEST ) && file_count == 0 )
+ {
+ fputs("Option requires at least one filename argument.\n", stderr);
+ return;
+ }
+
+ if ( mode == MMT_NONE && ! help_flag && ! version_flag )
+ {
+ fputs("No operation selected (use one of -[gGcitux] or -h for help).\n", stderr);
+ return;
+ }
+
+ error_flag = false;
+ }
+};
+
+//------------------------------------------------------------------------------------------
+// MPEG2 essence
+
+// Write a plaintext MPEG2 Video Elementary Stream to a plaintext ASDCP file
+// Write a plaintext MPEG2 Video Elementary Stream to a ciphertext ASDCP file
+//
+Result_t
+write_MPEG2_file(CommandOptions& Options)
+{
+ AESEncContext* Context = 0;
+ HMACContext* HMAC = 0;
+ MPEG2::FrameBuffer FrameBuffer(Options.fb_size);
+ MPEG2::Parser Parser;
+ MPEG2::MXFWriter Writer;
+ MPEG2::VideoDescriptor VDesc;
+ byte_t IV_buf[CBC_BLOCK_SIZE];
+ Kumu::FortunaRNG RNG;
+
+ // set up essence parser
+ Result_t result = Parser.OpenRead(Options.filenames[0]);
+
+ // set up MXF writer
+ if ( ASDCP_SUCCESS(result) )
+ {
+ Parser.FillVideoDescriptor(VDesc);
+
+ if ( Options.verbose_flag )
+ {
+ fputs("MPEG-2 Pictures\n", stderr);
+ fputs("VideoDescriptor:\n", stderr);
+ fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
+ MPEG2::VideoDescriptorDump(VDesc);
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+ {
+ WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here
+ if ( Options.asset_id_flag )
+ memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen);
+ else
+ Kumu::GenRandomUUID(Info.AssetUUID);
+
+ if ( Options.use_smpte_labels )
+ {
+ Info.LabelSetType = LS_MXF_SMPTE;
+ fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n");
+ }
+
+ // configure encryption
+ if( Options.key_flag )
+ {
+ Kumu::GenRandomUUID(Info.ContextID);
+ Info.EncryptedEssence = true;
+
+ if ( Options.key_id_flag )
+ memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen);
+ else
+ RNG.FillRandom(Info.CryptographicKeyID, UUIDlen);
+
+ Context = new AESEncContext;
+ result = Context->InitKey(Options.key_value);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
+
+ if ( ASDCP_SUCCESS(result) && Options.write_hmac )
+ {
+ Info.UsesHMAC = true;
+ HMAC = new HMACContext;
+ result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Writer.OpenWrite(Options.out_file, Info, VDesc);
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ // loop through the frames
+ {
+ result = Parser.Reset();
+ ui32_t duration = 0;
+
+ while ( ASDCP_SUCCESS(result) && duration++ < Options.duration )
+ {
+ if ( ! Options.do_repeat || duration == 1 )
+ {
+ result = Parser.ReadFrame(FrameBuffer);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ if ( Options.verbose_flag )
+ FrameBuffer.Dump(stderr, Options.fb_dump_size);
+
+ if ( Options.encrypt_header_flag )
+ FrameBuffer.PlaintextOffset(0);
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+ {
+ result = Writer.WriteFrame(FrameBuffer, Context, HMAC);
+
+ // The Writer class will forward the last block of ciphertext
+ // to the encryption context for use as the IV for the next
+ // frame. If you want to use non-sequitur IV values, un-comment
+ // the following line of code.
+ // if ( ASDCP_SUCCESS(result) && Options.key_flag )
+ // Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
+ }
+ }
+
+ if ( result == RESULT_ENDOFFILE )
+ result = RESULT_OK;
+ }
+
+ if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+ result = Writer.Finalize();
+
+ return result;
+}
+
+// Read a plaintext MPEG2 Video Elementary Stream from a plaintext ASDCP file
+// Read a plaintext MPEG2 Video Elementary Stream from a ciphertext ASDCP file
+// Read a ciphertext MPEG2 Video Elementary Stream from a ciphertext ASDCP file
+//
+Result_t
+read_MPEG2_file(CommandOptions& Options)
+{
+ AESDecContext* Context = 0;
+ HMACContext* HMAC = 0;
+ MPEG2::MXFReader Reader;
+ MPEG2::FrameBuffer FrameBuffer(Options.fb_size);
+ Kumu::FileWriter OutFile;
+ ui32_t frame_count = 0;
+
+ Result_t result = Reader.OpenRead(Options.filenames[0]);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ MPEG2::VideoDescriptor VDesc;
+ Reader.FillVideoDescriptor(VDesc);
+ frame_count = VDesc.ContainerDuration;
+
+ if ( Options.verbose_flag )
+ {
+ fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
+ MPEG2::VideoDescriptorDump(VDesc);
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ char filename[256];
+ snprintf(filename, 256, "%s.ves", Options.file_root);
+ result = OutFile.OpenWrite(filename);
+ }
+
+ if ( ASDCP_SUCCESS(result) && Options.key_flag )
+ {
+ Context = new AESDecContext;
+ result = Context->InitKey(Options.key_value);
+
+ if ( ASDCP_SUCCESS(result) && Options.read_hmac )
+ {
+ WriterInfo Info;
+ Reader.FillWriterInfo(Info);
+
+ if ( Info.UsesHMAC )
+ {
+ HMAC = new HMACContext;
+ result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
+ }
+ else
+ {
+ fputs("File does not contain HMAC values, ignoring -m option.\n", stderr);
+ }
+ }
+ }
+
+ ui32_t last_frame = Options.start_frame + ( Options.duration ? Options.duration : frame_count);
+ if ( last_frame > frame_count )
+ last_frame = frame_count;
+
+ for ( ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++ )
+ {
+ result = Reader.ReadFrame(i, FrameBuffer, Context, HMAC);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ if ( Options.verbose_flag )
+ FrameBuffer.Dump(stderr, Options.fb_dump_size);
+
+ ui32_t write_count = 0;
+ result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count);
+ }
+ }
+
+ return result;
+}
+
+
+//
+Result_t
+gop_start_test(CommandOptions& Options)
+{
+ using namespace ASDCP::MPEG2;
+
+ MXFReader Reader;
+ MPEG2::FrameBuffer FrameBuffer(Options.fb_size);
+ ui32_t frame_count = 0;
+
+ Result_t result = Reader.OpenRead(Options.filenames[0]);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ MPEG2::VideoDescriptor VDesc;
+ Reader.FillVideoDescriptor(VDesc);
+ frame_count = VDesc.ContainerDuration;
+
+ if ( Options.verbose_flag )
+ {
+ fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
+ MPEG2::VideoDescriptorDump(VDesc);
+ }
+ }
+
+ ui32_t last_frame = Options.start_frame + ( Options.duration ? Options.duration : frame_count);
+ if ( last_frame > frame_count )
+ last_frame = frame_count;
+
+ for ( ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++ )
+ {
+ result = Reader.ReadFrameGOPStart(i, FrameBuffer);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ if ( Options.verbose_flag )
+ FrameBuffer.Dump(stderr, Options.fb_dump_size);
+
+ if ( FrameBuffer.FrameType() != FRAME_I )
+ fprintf(stderr, "Expecting an I frame, got %c\n", FrameTypeChar(FrameBuffer.FrameType()));
+
+ fprintf(stderr, "Requested frame %u, got %u\n", i, FrameBuffer.FrameNumber());
+ }
+ }
+
+ return result;
+}
+
+//------------------------------------------------------------------------------------------
+// JPEG 2000 essence
+
+// Write one or more plaintext JPEG 2000 stereoscopic codestream pairs to a plaintext ASDCP file
+// Write one or more plaintext JPEG 2000 stereoscopic codestream pairs to a ciphertext ASDCP file
+//
+Result_t
+write_JP2K_S_file(CommandOptions& Options)
+{
+ AESEncContext* Context = 0;
+ HMACContext* HMAC = 0;
+ JP2K::MXFSWriter Writer;
+ JP2K::FrameBuffer FrameBuffer(Options.fb_size);
+ JP2K::PictureDescriptor PDesc;
+ JP2K::SequenceParser ParserLeft, ParserRight;
+ byte_t IV_buf[CBC_BLOCK_SIZE];
+ Kumu::FortunaRNG RNG;
+
+ if ( Options.file_count != 2 )
+ {
+ fprintf(stderr, "Two inputs are required for stereoscopic option.\n");
+ return RESULT_FAIL;
+ }
+
+ // set up essence parser
+ Result_t result = ParserLeft.OpenRead(Options.filenames[0], Options.j2c_pedantic);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = ParserRight.OpenRead(Options.filenames[1], Options.j2c_pedantic);
+
+ // set up MXF writer
+ if ( ASDCP_SUCCESS(result) )
+ {
+ ParserLeft.FillPictureDescriptor(PDesc);
+ PDesc.EditRate = Options.PictureRate();
+
+ if ( Options.verbose_flag )
+ {
+ fputs("JPEG 2000 stereoscopic pictures\nPictureDescriptor:\n", stderr);
+ fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
+ JP2K::PictureDescriptorDump(PDesc);
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+ {
+ WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here
+ if ( Options.asset_id_flag )
+ memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen);
+ else
+ Kumu::GenRandomUUID(Info.AssetUUID);
+
+ if ( Options.use_smpte_labels )
+ {
+ Info.LabelSetType = LS_MXF_SMPTE;
+ fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n");
+ }
+
+ // configure encryption
+ if( Options.key_flag )
+ {
+ Kumu::GenRandomUUID(Info.ContextID);
+ Info.EncryptedEssence = true;
+
+ if ( Options.key_id_flag )
+ memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen);
+ else
+ RNG.FillRandom(Info.CryptographicKeyID, UUIDlen);
+
+ Context = new AESEncContext;
+ result = Context->InitKey(Options.key_value);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
+
+ if ( ASDCP_SUCCESS(result) && Options.write_hmac )
+ {
+ Info.UsesHMAC = true;
+ HMAC = new HMACContext;
+ result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Writer.OpenWrite(Options.out_file, Info, PDesc);
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ ui32_t duration = 0;
+ result = ParserLeft.Reset();
+ if ( ASDCP_SUCCESS(result) ) result = ParserRight.Reset();
+
+ while ( ASDCP_SUCCESS(result) && duration++ < Options.duration )
+ {
+ result = ParserLeft.ReadFrame(FrameBuffer);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ if ( Options.verbose_flag )
+ FrameBuffer.Dump(stderr, Options.fb_dump_size);
+
+ if ( Options.encrypt_header_flag )
+ FrameBuffer.PlaintextOffset(0);
+ }
+
+ if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+ result = Writer.WriteFrame(FrameBuffer, JP2K::SP_LEFT, Context, HMAC);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = ParserRight.ReadFrame(FrameBuffer);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ if ( Options.verbose_flag )
+ FrameBuffer.Dump(stderr, Options.fb_dump_size);
+
+ if ( Options.encrypt_header_flag )
+ FrameBuffer.PlaintextOffset(0);
+ }
+
+ if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+ result = Writer.WriteFrame(FrameBuffer, JP2K::SP_RIGHT, Context, HMAC);
+ }
+
+ if ( result == RESULT_ENDOFFILE )
+ result = RESULT_OK;
+ }
+
+ if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+ result = Writer.Finalize();
+
+ return result;
+}
+
+// Read one or more plaintext JPEG 2000 stereoscopic codestream pairs from a plaintext ASDCP file
+// Read one or more plaintext JPEG 2000 stereoscopic codestream pairs from a ciphertext ASDCP file
+// Read one or more ciphertext JPEG 2000 stereoscopic codestream pairs from a ciphertext ASDCP file
+Result_t
+read_JP2K_S_file(CommandOptions& Options)
+{
+ AESDecContext* Context = 0;
+ HMACContext* HMAC = 0;
+ JP2K::MXFSReader Reader;
+ JP2K::FrameBuffer FrameBuffer(Options.fb_size);
+ ui32_t frame_count = 0;
+
+ Result_t result = Reader.OpenRead(Options.filenames[0]);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ JP2K::PictureDescriptor PDesc;
+ Reader.FillPictureDescriptor(PDesc);
+
+ frame_count = PDesc.ContainerDuration;
+
+ if ( Options.verbose_flag )
+ {
+ fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
+ JP2K::PictureDescriptorDump(PDesc);
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) && Options.key_flag )
+ {
+ Context = new AESDecContext;
+ result = Context->InitKey(Options.key_value);
+
+ if ( ASDCP_SUCCESS(result) && Options.read_hmac )
+ {
+ WriterInfo Info;
+ Reader.FillWriterInfo(Info);
+
+ if ( Info.UsesHMAC )
+ {
+ HMAC = new HMACContext;
+ result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
+ }
+ else
+ {
+ fputs("File does not contain HMAC values, ignoring -m option.\n", stderr);
+ }
+ }
+ }
+
+ const int filename_max = 1024;
+ char filename[filename_max];
+ ui32_t last_frame = Options.start_frame + ( Options.duration ? Options.duration : frame_count);
+ if ( last_frame > frame_count )
+ last_frame = frame_count;
+
+ char left_format[64]; char right_format[64];
+ snprintf(left_format, 64, "%%s%%0%duL.j2c", Options.number_width);
+ snprintf(right_format, 64, "%%s%%0%duR.j2c", Options.number_width);
+
+ for ( ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++ )
+ {
+ result = Reader.ReadFrame(i, JP2K::SP_LEFT, FrameBuffer, Context, HMAC);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ Kumu::FileWriter OutFile;
+ ui32_t write_count;
+ snprintf(filename, filename_max, left_format, Options.file_root, i);
+ result = OutFile.OpenWrite(filename);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count);
+
+ if ( Options.verbose_flag )
+ FrameBuffer.Dump(stderr, Options.fb_dump_size);
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Reader.ReadFrame(i, JP2K::SP_RIGHT, FrameBuffer, Context, HMAC);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ Kumu::FileWriter OutFile;
+ ui32_t write_count;
+ snprintf(filename, filename_max, right_format, Options.file_root, i);
+ result = OutFile.OpenWrite(filename);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count);
+ }
+ }
+
+ return result;
+}
+
+
+
+// Write one or more plaintext JPEG 2000 codestreams to a plaintext ASDCP file
+// Write one or more plaintext JPEG 2000 codestreams to a ciphertext ASDCP file
+//
+Result_t
+write_JP2K_file(CommandOptions& Options)
+{
+ AESEncContext* Context = 0;
+ HMACContext* HMAC = 0;
+ JP2K::MXFWriter Writer;
+ JP2K::FrameBuffer FrameBuffer(Options.fb_size);
+ JP2K::PictureDescriptor PDesc;
+ JP2K::SequenceParser Parser;
+ byte_t IV_buf[CBC_BLOCK_SIZE];
+ Kumu::FortunaRNG RNG;
+
+ // set up essence parser
+ Result_t result = Parser.OpenRead(Options.filenames[0], Options.j2c_pedantic);
+
+ // set up MXF writer
+ if ( ASDCP_SUCCESS(result) )
+ {
+ Parser.FillPictureDescriptor(PDesc);
+ PDesc.EditRate = Options.PictureRate();
+
+ if ( Options.verbose_flag )
+ {
+ fprintf(stderr, "JPEG 2000 pictures\n");
+ fputs("PictureDescriptor:\n", stderr);
+ fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
+ JP2K::PictureDescriptorDump(PDesc);
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+ {
+ WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here
+ if ( Options.asset_id_flag )
+ memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen);
+ else
+ Kumu::GenRandomUUID(Info.AssetUUID);
+
+ if ( Options.use_smpte_labels )
+ {
+ Info.LabelSetType = LS_MXF_SMPTE;
+ fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n");
+ }
+
+ // configure encryption
+ if( Options.key_flag )
+ {
+ Kumu::GenRandomUUID(Info.ContextID);
+ Info.EncryptedEssence = true;
+
+ if ( Options.key_id_flag )
+ memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen);
+ else
+ RNG.FillRandom(Info.CryptographicKeyID, UUIDlen);
+
+ Context = new AESEncContext;
+ result = Context->InitKey(Options.key_value);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
+
+ if ( ASDCP_SUCCESS(result) && Options.write_hmac )
+ {
+ Info.UsesHMAC = true;
+ HMAC = new HMACContext;
+ result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Writer.OpenWrite(Options.out_file, Info, PDesc);
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ ui32_t duration = 0;
+ result = Parser.Reset();
+
+ while ( ASDCP_SUCCESS(result) && duration++ < Options.duration )
+ {
+ if ( ! Options.do_repeat || duration == 1 )
+ {
+ result = Parser.ReadFrame(FrameBuffer);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ if ( Options.verbose_flag )
+ FrameBuffer.Dump(stderr, Options.fb_dump_size);
+
+ if ( Options.encrypt_header_flag )
+ FrameBuffer.PlaintextOffset(0);
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+ {
+ result = Writer.WriteFrame(FrameBuffer, Context, HMAC);
+
+ // The Writer class will forward the last block of ciphertext
+ // to the encryption context for use as the IV for the next
+ // frame. If you want to use non-sequitur IV values, un-comment
+ // the following line of code.
+ // if ( ASDCP_SUCCESS(result) && Options.key_flag )
+ // Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
+ }
+ }
+
+ if ( result == RESULT_ENDOFFILE )
+ result = RESULT_OK;
+ }
+
+ if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+ result = Writer.Finalize();
+
+ return result;
+}
+
+// Read one or more plaintext JPEG 2000 codestreams from a plaintext ASDCP file
+// Read one or more plaintext JPEG 2000 codestreams from a ciphertext ASDCP file
+// Read one or more ciphertext JPEG 2000 codestreams from a ciphertext ASDCP file
+//
+Result_t
+read_JP2K_file(CommandOptions& Options)
+{
+ AESDecContext* Context = 0;
+ HMACContext* HMAC = 0;
+ JP2K::MXFReader Reader;
+ JP2K::FrameBuffer FrameBuffer(Options.fb_size);
+ ui32_t frame_count = 0;
+
+ Result_t result = Reader.OpenRead(Options.filenames[0]);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ JP2K::PictureDescriptor PDesc;
+ Reader.FillPictureDescriptor(PDesc);
+
+ frame_count = PDesc.ContainerDuration;
+
+ if ( Options.verbose_flag )
+ {
+ fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
+ JP2K::PictureDescriptorDump(PDesc);
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) && Options.key_flag )
+ {
+ Context = new AESDecContext;
+ result = Context->InitKey(Options.key_value);
+
+ if ( ASDCP_SUCCESS(result) && Options.read_hmac )
+ {
+ WriterInfo Info;
+ Reader.FillWriterInfo(Info);
+
+ if ( Info.UsesHMAC )
+ {
+ HMAC = new HMACContext;
+ result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
+ }
+ else
+ {
+ fputs("File does not contain HMAC values, ignoring -m option.\n", stderr);
+ }
+ }
+ }
+
+ ui32_t last_frame = Options.start_frame + ( Options.duration ? Options.duration : frame_count);
+ if ( last_frame > frame_count )
+ last_frame = frame_count;
+
+ char name_format[64];
+ snprintf(name_format, 64, "%%s%%0%du.j2c", Options.number_width);
+
+ for ( ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++ )
+ {
+ result = Reader.ReadFrame(i, FrameBuffer, Context, HMAC);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ Kumu::FileWriter OutFile;
+ char filename[256];
+ ui32_t write_count;
+ snprintf(filename, 256, name_format, Options.file_root, i);
+ result = OutFile.OpenWrite(filename);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count);
+
+ if ( Options.verbose_flag )
+ FrameBuffer.Dump(stderr, Options.fb_dump_size);
+ }
+ }
+
+ return result;
+}
+
+//------------------------------------------------------------------------------------------
+// PCM essence
+
+
+// Write one or more plaintext PCM audio streams to a plaintext ASDCP file
+// Write one or more plaintext PCM audio streams to a ciphertext ASDCP file
+//
+Result_t
+write_PCM_file(CommandOptions& Options)
+{
+ 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];
+ Kumu::FortunaRNG RNG;
+
+ // set up essence parser
+ Result_t result = Parser.OpenRead(Options.file_count, Options.filenames, PictureRate);
+
+ // set up MXF writer
+ if ( ASDCP_SUCCESS(result) )
+ {
+ Parser.FillAudioDescriptor(ADesc);
+
+ ADesc.EditRate = PictureRate;
+ FrameBuffer.Capacity(PCM::CalcFrameBufferSize(ADesc));
+ ADesc.ChannelFormat = Options.channel_fmt;
+
+ if ( Options.use_smpte_labels && ADesc.ChannelFormat == PCM::CF_NONE)
+ {
+ fprintf(stderr, "ATTENTION! Writing SMPTE audio without ChannelAssignment property (see option -l)\n");
+ }
+
+ if ( Options.verbose_flag )
+ {
+ fprintf(stderr, "%.1fkHz PCM Audio, %s fps (%u spf)\n",
+ ADesc.AudioSamplingRate.Quotient() / 1000.0,
+ Options.szPictureRate(),
+ PCM::CalcSamplesPerFrame(ADesc));
+ fputs("AudioDescriptor:\n", stderr);
+ PCM::AudioDescriptorDump(ADesc);
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+ {
+ WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here
+ if ( Options.asset_id_flag )
+ memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen);
+ else
+ Kumu::GenRandomUUID(Info.AssetUUID);
+
+ if ( Options.use_smpte_labels )
+ {
+ Info.LabelSetType = LS_MXF_SMPTE;
+ fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n");
+ }
+
+ // configure encryption
+ if( Options.key_flag )
+ {
+ Kumu::GenRandomUUID(Info.ContextID);
+ Info.EncryptedEssence = true;
+
+ if ( Options.key_id_flag )
+ memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen);
+ else
+ RNG.FillRandom(Info.CryptographicKeyID, UUIDlen);
+
+ Context = new AESEncContext;
+ result = Context->InitKey(Options.key_value);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
+
+ if ( ASDCP_SUCCESS(result) && Options.write_hmac )
+ {
+ Info.UsesHMAC = true;
+ HMAC = new HMACContext;
+ result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Writer.OpenWrite(Options.out_file, Info, ADesc);
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ result = Parser.Reset();
+ ui32_t duration = 0;
+
+ while ( ASDCP_SUCCESS(result) && duration++ < Options.duration )
+ {
+ result = Parser.ReadFrame(FrameBuffer);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ if ( FrameBuffer.Size() != FrameBuffer.Capacity() )
+ {
+ fprintf(stderr, "WARNING: Last frame read was short, PCM input is possibly not frame aligned.\n");
+ fprintf(stderr, "Expecting %u bytes, got %u.\n", FrameBuffer.Capacity(), FrameBuffer.Size());
+ result = RESULT_ENDOFFILE;
+ continue;
+ }
+
+ if ( Options.verbose_flag )
+ FrameBuffer.Dump(stderr, Options.fb_dump_size);
+
+ if ( ! Options.no_write_flag )
+ {
+ result = Writer.WriteFrame(FrameBuffer, Context, HMAC);
+
+ // The Writer class will forward the last block of ciphertext
+ // to the encryption context for use as the IV for the next
+ // frame. If you want to use non-sequitur IV values, un-comment
+ // the following line of code.
+ // if ( ASDCP_SUCCESS(result) && Options.key_flag )
+ // Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
+ }
+ }
+ }
+
+ if ( result == RESULT_ENDOFFILE )
+ result = RESULT_OK;
+ }
+
+ if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+ result = Writer.Finalize();
+
+ return result;
+}
+
+// Read one or more plaintext PCM audio streams from a plaintext ASDCP file
+// Read one or more plaintext PCM audio streams from a ciphertext ASDCP file
+// Read one or more ciphertext PCM audio streams from a ciphertext ASDCP file
+//
+Result_t
+read_PCM_file(CommandOptions& Options)
+{
+ AESDecContext* Context = 0;
+ HMACContext* HMAC = 0;
+ PCM::MXFReader Reader;
+ PCM::FrameBuffer FrameBuffer;
+ WavFileWriter OutWave;
+ PCM::AudioDescriptor ADesc;
+ ui32_t last_frame = 0;
+
+ Result_t result = Reader.OpenRead(Options.filenames[0]);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ Reader.FillAudioDescriptor(ADesc);
+
+ if ( ADesc.EditRate != EditRate_23_98
+ && ADesc.EditRate != EditRate_24
+ && ADesc.EditRate != EditRate_25
+ && ADesc.EditRate != EditRate_30
+ && ADesc.EditRate != EditRate_48
+ && ADesc.EditRate != EditRate_50
+ && ADesc.EditRate != EditRate_60 )
+ ADesc.EditRate = Options.PictureRate();
+
+ FrameBuffer.Capacity(PCM::CalcFrameBufferSize(ADesc));
+
+ if ( Options.verbose_flag )
+ PCM::AudioDescriptorDump(ADesc);
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ last_frame = ADesc.ContainerDuration;
+
+ if ( Options.duration > 0 && Options.duration < last_frame )
+ last_frame = Options.duration;
+
+ if ( Options.start_frame > 0 )
+ {
+ if ( Options.start_frame > ADesc.ContainerDuration )
+ {
+ fprintf(stderr, "Start value greater than file duration.\n");
+ return RESULT_FAIL;
+ }
+
+ last_frame = Kumu::xmin(Options.start_frame + last_frame, ADesc.ContainerDuration);
+ }
+
+ ADesc.ContainerDuration = last_frame - Options.start_frame;
+ OutWave.OpenWrite(ADesc, Options.file_root,
+ ( Options.split_wav ? WavFileWriter::ST_STEREO :
+ ( Options.mono_wav ? WavFileWriter::ST_MONO : WavFileWriter::ST_NONE ) ));
+ }
+
+ if ( ASDCP_SUCCESS(result) && Options.key_flag )
+ {
+ Context = new AESDecContext;
+ result = Context->InitKey(Options.key_value);
+
+ if ( ASDCP_SUCCESS(result) && Options.read_hmac )
+ {
+ WriterInfo Info;
+ Reader.FillWriterInfo(Info);
+
+ if ( Info.UsesHMAC )
+ {
+ HMAC = new HMACContext;
+ result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
+ }
+ else
+ {
+ fputs("File does not contain HMAC values, ignoring -m option.\n", stderr);
+ }
+ }
+ }
+
+ for ( ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++ )
+ {
+ result = Reader.ReadFrame(i, FrameBuffer, Context, HMAC);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ if ( Options.verbose_flag )
+ FrameBuffer.Dump(stderr, Options.fb_dump_size);
+
+ result = OutWave.WriteFrame(FrameBuffer);
+ }
+ }
+
+ return result;
+}
+
+
+//------------------------------------------------------------------------------------------
+// TimedText essence
+
+
+// Write one or more plaintext timed text streams to a plaintext ASDCP file
+// Write one or more plaintext timed text streams to a ciphertext ASDCP file
+//
+Result_t
+write_timed_text_file(CommandOptions& Options)
+{
+ AESEncContext* Context = 0;
+ HMACContext* HMAC = 0;
+ TimedText::DCSubtitleParser Parser;
+ TimedText::MXFWriter Writer;
+ TimedText::FrameBuffer FrameBuffer;
+ TimedText::TimedTextDescriptor TDesc;
+ byte_t IV_buf[CBC_BLOCK_SIZE];
+ Kumu::FortunaRNG RNG;
+
+ // set up essence parser
+ Result_t result = Parser.OpenRead(Options.filenames[0]);
+
+ // set up MXF writer
+ if ( ASDCP_SUCCESS(result) )
+ {
+ Parser.FillTimedTextDescriptor(TDesc);
+ FrameBuffer.Capacity(Options.fb_size);
+
+ if ( Options.verbose_flag )
+ {
+ fputs("D-Cinema Timed-Text Descriptor:\n", stderr);
+ TimedText::DescriptorDump(TDesc);
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+ {
+ WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here
+ if ( Options.asset_id_flag )
+ memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen);
+ else
+ Kumu::GenRandomUUID(Info.AssetUUID);
+
+ if ( Options.use_smpte_labels )
+ {
+ Info.LabelSetType = LS_MXF_SMPTE;
+ fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n");
+ }
+
+ // configure encryption
+ if( Options.key_flag )
+ {
+ Kumu::GenRandomUUID(Info.ContextID);
+ Info.EncryptedEssence = true;
+
+ if ( Options.key_id_flag )
+ memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen);
+ else
+ RNG.FillRandom(Info.CryptographicKeyID, UUIDlen);
+
+ Context = new AESEncContext;
+ result = Context->InitKey(Options.key_value);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
+
+ if ( ASDCP_SUCCESS(result) && Options.write_hmac )
+ {
+ Info.UsesHMAC = true;
+ HMAC = new HMACContext;
+ result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Writer.OpenWrite(Options.out_file, Info, TDesc);
+ }
+
+ if ( ASDCP_FAILURE(result) )
+ return result;
+
+ std::string XMLDoc;
+ TimedText::ResourceList_t::const_iterator ri;
+
+ result = Parser.ReadTimedTextResource(XMLDoc);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Writer.WriteTimedTextResource(XMLDoc, Context, HMAC);
+
+ for ( ri = TDesc.ResourceList.begin() ; ri != TDesc.ResourceList.end() && ASDCP_SUCCESS(result); ri++ )
+ {
+ result = Parser.ReadAncillaryResource((*ri).ResourceID, FrameBuffer);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ if ( Options.verbose_flag )
+ FrameBuffer.Dump(stderr, Options.fb_dump_size);
+
+ if ( ! Options.no_write_flag )
+ {
+ result = Writer.WriteAncillaryResource(FrameBuffer, Context, HMAC);
+
+ // The Writer class will forward the last block of ciphertext
+ // to the encryption context for use as the IV for the next
+ // frame. If you want to use non-sequitur IV values, un-comment
+ // the following line of code.
+ // if ( ASDCP_SUCCESS(result) && Options.key_flag )
+ // Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
+ }
+ }
+
+ if ( result == RESULT_ENDOFFILE )
+ result = RESULT_OK;
+ }
+
+ if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+ result = Writer.Finalize();
+
+ return result;
+}
+
+
+// Read one or more timed text streams from a plaintext ASDCP file
+// Read one or more timed text streams from a ciphertext ASDCP file
+// Read one or more timed text streams from a ciphertext ASDCP file
+//
+Result_t
+read_timed_text_file(CommandOptions& Options)
+{
+ AESDecContext* Context = 0;
+ HMACContext* HMAC = 0;
+ TimedText::MXFReader Reader;
+ TimedText::FrameBuffer FrameBuffer;
+ TimedText::TimedTextDescriptor TDesc;
+
+ Result_t result = Reader.OpenRead(Options.filenames[0]);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ Reader.FillTimedTextDescriptor(TDesc);
+ FrameBuffer.Capacity(Options.fb_size);
+
+ if ( Options.verbose_flag )
+ TimedText::DescriptorDump(TDesc);
+ }
+
+ if ( ASDCP_SUCCESS(result) && Options.key_flag )
+ {
+ Context = new AESDecContext;
+ result = Context->InitKey(Options.key_value);
+
+ if ( ASDCP_SUCCESS(result) && Options.read_hmac )
+ {
+ WriterInfo Info;
+ Reader.FillWriterInfo(Info);
+
+ if ( Info.UsesHMAC )
+ {
+ HMAC = new HMACContext;
+ result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
+ }
+ else
+ {
+ fputs("File does not contain HMAC values, ignoring -m option.\n", stderr);
+ }
+ }
+ }
+
+ if ( ASDCP_FAILURE(result) )
+ return result;
+
+ std::string XMLDoc;
+ std::string out_path = Kumu::PathDirname(Options.file_root);
+ ui32_t write_count;
+ char buf[64];
+ TimedText::ResourceList_t::const_iterator ri;
+
+ result = Reader.ReadTimedTextResource(XMLDoc, Context, HMAC);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ Kumu::FileWriter Writer;
+ result = Writer.OpenWrite(Options.file_root);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Writer.Write(reinterpret_cast<const byte_t*>(XMLDoc.c_str()), XMLDoc.size(), &write_count);
+ }
+
+ for ( ri = TDesc.ResourceList.begin() ; ri != TDesc.ResourceList.end() && ASDCP_SUCCESS(result); ri++ )
+ {
+ result = Reader.ReadAncillaryResource(ri->ResourceID, FrameBuffer, Context, HMAC);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ Kumu::FileWriter Writer;
+ result = Writer.OpenWrite(Kumu::PathJoin(out_path, Kumu::UUID(ri->ResourceID).EncodeHex(buf, 64)).c_str());
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ if ( Options.verbose_flag )
+ FrameBuffer.Dump(stderr, Options.fb_dump_size);
+
+ result = Writer.Write(FrameBuffer.RoData(), FrameBuffer.Size(), &write_count);
+ }
+ }
+ }
+
+ return result;
+}
+
+//------------------------------------------------------------------------------------------
+//
+
+//
+// These classes wrap the irregular names in the asdcplib API
+// so that I can use a template to simplify the implementation
+// of show_file_info()
+
+class MyVideoDescriptor : public MPEG2::VideoDescriptor
+{
+ public:
+ void FillDescriptor(MPEG2::MXFReader& Reader) {
+ Reader.FillVideoDescriptor(*this);
+ }
+
+ void Dump(FILE* stream) {
+ MPEG2::VideoDescriptorDump(*this, stream);
+ }
+};
+
+class MyPictureDescriptor : public JP2K::PictureDescriptor
+{
+ public:
+ void FillDescriptor(JP2K::MXFReader& Reader) {
+ Reader.FillPictureDescriptor(*this);
+ }
+
+ void Dump(FILE* stream) {
+ JP2K::PictureDescriptorDump(*this, stream);
+ }
+};
+
+class MyStereoPictureDescriptor : public JP2K::PictureDescriptor
+{
+ public:
+ void FillDescriptor(JP2K::MXFSReader& Reader) {
+ Reader.FillPictureDescriptor(*this);
+ }
+
+ void Dump(FILE* stream) {
+ JP2K::PictureDescriptorDump(*this, stream);
+ }
+};
+
+class MyAudioDescriptor : public PCM::AudioDescriptor
+{
+ public:
+ void FillDescriptor(PCM::MXFReader& Reader) {
+ Reader.FillAudioDescriptor(*this);
+ }
+
+ void Dump(FILE* stream) {
+ PCM::AudioDescriptorDump(*this, stream);
+ }
+};
+
+class MyTextDescriptor : public TimedText::TimedTextDescriptor
+{
+ public:
+ void FillDescriptor(TimedText::MXFReader& Reader) {
+ Reader.FillTimedTextDescriptor(*this);
+ }
+
+ void Dump(FILE* stream) {
+ TimedText::DescriptorDump(*this, stream);
+ }
+};
+
+// MSVC didn't like the function template, so now it's a static class method
+template<class ReaderT, class DescriptorT>
+class FileInfoWrapper
+{
+public:
+ static Result_t
+ file_info(CommandOptions& Options, const char* type_string, FILE* stream = 0)
+ {
+ assert(type_string);
+ if ( stream == 0 )
+ stream = stdout;
+
+ Result_t result = RESULT_OK;
+
+ if ( Options.verbose_flag || Options.showheader_flag )
+ {
+ ReaderT Reader;
+ result = Reader.OpenRead(Options.filenames[0]);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ fprintf(stdout, "File essence type is %s.\n", type_string);
+
+ if ( Options.showheader_flag )
+ Reader.DumpHeaderMetadata(stream);
+
+ WriterInfo WI;
+ Reader.FillWriterInfo(WI);
+ WriterInfoDump(WI, stream);
+
+ DescriptorT Desc;
+ Desc.FillDescriptor(Reader);
+ Desc.Dump(stream);
+
+ if ( Options.showindex_flag )
+ Reader.DumpIndex(stream);
+ }
+ else if ( result == RESULT_FORMAT && Options.showheader_flag )
+ {
+ Reader.DumpHeaderMetadata(stream);
+ }
+ }
+
+ return result;
+ }
+};
+
+// Read header metadata from an ASDCP file
+//
+Result_t
+show_file_info(CommandOptions& Options)
+{
+ EssenceType_t EssenceType;
+ Result_t result = ASDCP::EssenceType(Options.filenames[0], EssenceType);
+
+ if ( ASDCP_FAILURE(result) )
+ return result;
+
+ if ( EssenceType == ESS_MPEG2_VES )
+ {
+ result = FileInfoWrapper<ASDCP::MPEG2::MXFReader, MyVideoDescriptor>::file_info(Options, "MPEG2 video");
+ }
+ else if ( EssenceType == ESS_PCM_24b_48k || EssenceType == ESS_PCM_24b_96k )
+ {
+ result = FileInfoWrapper<ASDCP::PCM::MXFReader, MyAudioDescriptor>::file_info(Options, "PCM audio");
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ const Dictionary* Dict = &DefaultCompositeDict();
+ PCM::MXFReader Reader;
+ MXF::OPAtomHeader OPAtomHeader(Dict);
+ MXF::WaveAudioDescriptor *descriptor = 0;
+
+ result = Reader.OpenRead(Options.filenames[0]);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Reader.OPAtomHeader().GetMDObjectByType(Dict->ul(MDD_WaveAudioDescriptor), reinterpret_cast<MXF::InterchangeObject**>(&descriptor));
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ char buf[64];
+ fprintf(stdout, " ChannelAssignment: %s\n", descriptor->ChannelAssignment.EncodeString(buf, 64));
+ }
+ }
+ }
+ else if ( EssenceType == ESS_JPEG_2000 )
+ {
+ if ( Options.stereo_image_flag )
+ {
+ result = FileInfoWrapper<ASDCP::JP2K::MXFSReader,
+ MyStereoPictureDescriptor>::file_info(Options, "JPEG 2000 stereoscopic pictures");
+ }
+ else
+ {
+ result = FileInfoWrapper<ASDCP::JP2K::MXFReader,
+ MyPictureDescriptor>::file_info(Options, "JPEG 2000 pictures");
+ }
+ }
+ else if ( EssenceType == ESS_JPEG_2000_S )
+ {
+ result = FileInfoWrapper<ASDCP::JP2K::MXFSReader,
+ MyStereoPictureDescriptor>::file_info(Options, "JPEG 2000 stereoscopic pictures");
+ }
+ else if ( EssenceType == ESS_TIMED_TEXT )
+ {
+ result = FileInfoWrapper<ASDCP::TimedText::MXFReader, MyTextDescriptor>::file_info(Options, "Timed Text");
+ }
+ else
+ {
+ fprintf(stderr, "File is not AS-DCP: %s\n", Options.filenames[0]);
+ Kumu::FileReader Reader;
+ const Dictionary* Dict = &DefaultCompositeDict();
+ MXF::OPAtomHeader TestHeader(Dict);
+
+ result = Reader.OpenRead(Options.filenames[0]);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = TestHeader.InitFromFile(Reader); // test UL and OP
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ TestHeader.Partition::Dump(stdout);
+
+ if ( MXF::Identification* ID = TestHeader.GetIdentification() )
+ ID->Dump(stdout);
+ else
+ fputs("File contains no Identification object.\n", stdout);
+
+ if ( MXF::SourcePackage* SP = TestHeader.GetSourcePackage() )
+ SP->Dump(stdout);
+ else
+ fputs("File contains no SourcePackage object.\n", stdout);
+ }
+ else
+ {
+ fputs("File is not MXF.\n", stdout);
+ }
+ }
+
+ return result;
+}
+
+
+//
+Result_t
+digest_file(const char* filename)
+{
+ using namespace Kumu;
+
+ ASDCP_TEST_NULL_STR(filename);
+ FileReader Reader;
+ SHA_CTX Ctx;
+ SHA1_Init(&Ctx);
+ ByteString Buf(8192);
+
+ Result_t result = Reader.OpenRead(filename);
+
+ while ( ASDCP_SUCCESS(result) )
+ {
+ ui32_t read_count = 0;
+ result = Reader.Read(Buf.Data(), Buf.Capacity(), &read_count);
+
+ if ( result == RESULT_ENDOFFILE )
+ {
+ result = RESULT_OK;
+ break;
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ SHA1_Update(&Ctx, Buf.Data(), read_count);
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ const ui32_t sha_len = 20;
+ byte_t bin_buf[sha_len];
+ char sha_buf[64];
+ SHA1_Final(bin_buf, &Ctx);
+
+ fprintf(stdout, "%s %s\n", base64encode(bin_buf, sha_len, sha_buf, 64), filename);
+ }
+
+ return result;
+}
+
+//
+int
+main(int argc, const char** argv)
+{
+ Result_t result = RESULT_OK;
+ char str_buf[64];
+ CommandOptions Options(argc, argv);
+
+ if ( Options.version_flag )
+ banner();
+
+ if ( Options.help_flag )
+ usage();
+
+ if ( Options.version_flag || Options.help_flag )
+ return 0;
+
+ if ( Options.error_flag )
+ {
+ fprintf(stderr, "There was a problem. Type %s -h for help.\n", PROGRAM_NAME);
+ return 3;
+ }
+
+ if ( Options.mode == MMT_INFO )
+ {
+ result = show_file_info(Options);
+
+ for ( int i = 1; ASDCP_SUCCESS(result) && i < Options.file_count; ++i )
+ {
+ Options.filenames[0] = Options.filenames[i]; // oh-so hackish
+ result = show_file_info(Options);
+ }
+ }
+ else if ( Options.mode == MMT_GOP_START )
+ {
+ result = gop_start_test(Options);
+ }
+ else if ( Options.mode == MMT_GEN_KEY )
+ {
+ Kumu::FortunaRNG RNG;
+ byte_t bin_buf[KeyLen];
+
+ RNG.FillRandom(bin_buf, KeyLen);
+ printf("%s\n", Kumu::bin2hex(bin_buf, KeyLen, str_buf, 64));
+ }
+ else if ( Options.mode == MMT_GEN_ID )
+ {
+ UUID TmpID;
+ Kumu::GenRandomValue(TmpID);
+ printf("%s\n", TmpID.EncodeHex(str_buf, 64));
+ }
+ else if ( Options.mode == MMT_DIGEST )
+ {
+ for ( ui32_t i = 0; i < Options.file_count && ASDCP_SUCCESS(result); i++ )
+ result = digest_file(Options.filenames[i]);
+ }
+ else if ( Options.mode == MMT_UL_LIST )
+ {
+ if ( Options.use_smpte_labels )
+ DefaultSMPTEDict().Dump(stdout);
+ else
+ DefaultInteropDict().Dump(stdout);
+ }
+ else if ( Options.mode == MMT_EXTRACT )
+ {
+ EssenceType_t EssenceType;
+ result = ASDCP::EssenceType(Options.filenames[0], EssenceType);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ switch ( EssenceType )
+ {
+ case ESS_MPEG2_VES:
+ result = read_MPEG2_file(Options);
+ break;
+
+ case ESS_JPEG_2000:
+ if ( Options.stereo_image_flag )
+ result = read_JP2K_S_file(Options);
+ else
+ result = read_JP2K_file(Options);
+ break;
+
+ case ESS_JPEG_2000_S:
+ result = read_JP2K_S_file(Options);
+ break;
+
+ case ESS_PCM_24b_48k:
+ case ESS_PCM_24b_96k:
+ result = read_PCM_file(Options);
+ break;
+
+ case ESS_TIMED_TEXT:
+ result = read_timed_text_file(Options);
+ break;
+
+ default:
+ fprintf(stderr, "%s: Unknown file type, not ASDCP essence.\n", Options.filenames[0]);
+ return 5;
+ }
+ }
+ }
+ else if ( Options.mode == MMT_CREATE )
+ {
+ if ( Options.do_repeat && ! Options.duration_flag )
+ {
+ fputs("Option -R requires -d <duration>\n", stderr);
+ return RESULT_FAIL;
+ }
+
+ EssenceType_t EssenceType;
+ result = ASDCP::RawEssenceType(Options.filenames[0], EssenceType);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ switch ( EssenceType )
+ {
+ case ESS_MPEG2_VES:
+ result = write_MPEG2_file(Options);
+ break;
+
+ case ESS_JPEG_2000:
+ if ( Options.stereo_image_flag )
+ result = write_JP2K_S_file(Options);
+
+ else
+ result = write_JP2K_file(Options);
+
+ break;
+
+ case ESS_PCM_24b_48k:
+ case ESS_PCM_24b_96k:
+ result = write_PCM_file(Options);
+ break;
+
+ case ESS_TIMED_TEXT:
+ result = write_timed_text_file(Options);
+ break;
+
+ default:
+ fprintf(stderr, "%s: Unknown file type, not ASDCP-compatible essence.\n",
+ Options.filenames[0]);
+ return 5;
+ }
+ }
+ }
+ else
+ {
+ fprintf(stderr, "Unhandled mode: %d.\n", Options.mode);
+ return 6;
+ }
+
+ if ( ASDCP_FAILURE(result) )
+ {
+ fputs("Program stopped on error.\n", stderr);
+
+ if ( result == RESULT_SFORMAT )
+ {
+ fputs("Use option '-3' to force stereoscopic mode.\n", stderr);
+ }
+ else if ( result != RESULT_FAIL )
+ {
+ fputs(result, stderr);
+ fputc('\n', stderr);
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+
+//
+// end asdcp-test.cpp
+//
diff --git a/asdcplib/src/asdcp-unwrap.cpp b/asdcplib/src/asdcp-unwrap.cpp
new file mode 100755
index 0000000..b7b7fef
--- /dev/null
+++ b/asdcplib/src/asdcp-unwrap.cpp
@@ -0,0 +1,896 @@
+/*
+Copyright (c) 2003-2012, 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 asdcp-unwrap.cpp
+ \version $Id: asdcp-unwrap.cpp,v 1.1 2012/02/03 19:49:57 jhurst Exp $
+ \brief AS-DCP file manipulation utility
+
+ This program extracts picture, sound and text essence from AS-DCP files.
+
+ For more information about asdcplib, please refer to the header file AS_DCP.h
+*/
+
+#include <KM_fileio.h>
+#include <WavFileWriter.h>
+
+using namespace ASDCP;
+
+const ui32_t FRAME_BUFFER_SIZE = 4 * Kumu::Megabyte;
+
+//------------------------------------------------------------------------------------------
+//
+// command line option parser class
+
+static const char* PROGRAM_NAME = "asdcp-unwrap"; // program name for messages
+
+// 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 = stdout)
+{
+ fprintf(stream, "\n\
+%s (asdcplib %s)\n\n\
+Copyright (c) 2003-2012 John Hurst\n\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",
+ PROGRAM_NAME, ASDCP::Version(), PROGRAM_NAME);
+}
+
+//
+void
+usage(FILE* stream = stdout)
+{
+ fprintf(stream, "\
+USAGE: %s [-h|-help] [-V]\n\
+\n\
+ %s -G [-v] <input-file>\n\
+\n\
+ %s [-1|-2] [-3] [-b <buffer-size>] [-d <duration>]\n\
+ [-f <starting-frame>] [-m] [-p <frame-rate>] [-R] [-s <size>] [-v] [-W]\n\
+ [-w] <input-file> [<file-prefix>]\n\n",
+ PROGRAM_NAME, PROGRAM_NAME, PROGRAM_NAME);
+
+ fprintf(stream, "\
+Options:\n\
+ -1 - Split Wave essence to mono WAV files during extract.\n\
+ Default is multichannel WAV\n\
+ -2 - Split Wave essence to stereo WAV files during extract.\n\
+ Default is multichannel WAV\n\
+ -3 - Force stereoscopic interpretation of a JP2K file.\n\
+ -b <buffer-size> - Specify size in bytes of picture frame buffer.\n\
+ Defaults to 4,194,304 (4MB)\n\
+ -d <duration> - Number of frames to process, default all\n\
+ -f <start-frame> - Starting frame number, default 0\n\
+ -G - Perform GOP start lookup test on MXF+Interop MPEG file\n\
+ -h | -help - Show help\n\
+ -k <key-string> - Use key for ciphertext operations\n\
+ -m - verify HMAC values when reading\n\
+ -p <rate> - fps of picture when wrapping PCM or JP2K:\n\
+ Use one of [23|24|25|30|48|50|60], 24 is default\n\
+ -s <size> - Number of bytes to dump to output when -v is given\n\
+ -V - Show version information\n\
+ -v - Verbose, prints informative messages to stderr\n\
+ -W - Read input file only, do not write destination file\n\
+ -w <width> - Width of numeric element in a series of frame file names\n\
+ (default 6).\n\
+ -z - Fail if j2c inputs have unequal parameters (default)\n\
+ -Z - Ignore unequal parameters in j2c inputs\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\
+ o An argument of \"23\" to the -p option will be interpreted\n\
+ as 24000/1001 fps.\n\n");
+}
+
+//
+enum MajorMode_t
+{
+ MMT_NONE,
+ MMT_EXTRACT,
+ MMT_GOP_START,
+};
+
+//
+class CommandOptions
+{
+ CommandOptions();
+
+public:
+ MajorMode_t mode;
+ bool error_flag; // true if the given options are in error or not complete
+ bool key_flag; // true if an encryption key was given
+ bool read_hmac; // true if HMAC values are to be validated
+ bool split_wav; // true if PCM is to be extracted to stereo WAV files
+ bool mono_wav; // true if PCM is to be extracted to mono WAV files
+ bool verbose_flag; // true if the verbose option was selected
+ ui32_t fb_dump_size; // number of bytes of frame buffer to dump
+ bool no_write_flag; // true if no output files are to be written
+ bool version_flag; // true if the version display option was selected
+ bool help_flag; // true if the help display option was selected
+ bool stereo_image_flag; // if true, expect stereoscopic JP2K input (left eye first)
+ ui32_t number_width; // number of digits in a serialized filename (for JPEG extract)
+ ui32_t start_frame; // frame number to begin processing
+ ui32_t duration; // number of frames to be processed
+ bool duration_flag; // true if duration argument given
+ bool j2c_pedantic; // passed to JP2K::SequenceParser::OpenRead
+ ui32_t picture_rate; // fps of picture when wrapping PCM
+ ui32_t fb_size; // size of picture frame buffer
+ const char* file_prefix; // filename pre for files written by the extract mode
+ byte_t key_value[KeyLen]; // value of given encryption key (when key_flag is true)
+ byte_t key_id_value[UUIDlen];// value of given key ID (when key_id_flag is true)
+ PCM::ChannelFormat_t channel_fmt; // audio channel arrangement
+ const char* input_filename;
+ std::string prefix_buffer;
+
+ //
+ Rational PictureRate()
+ {
+ if ( picture_rate == 23 ) return EditRate_23_98;
+ if ( picture_rate == 24 ) return EditRate_24;
+ if ( picture_rate == 25 ) return EditRate_25;
+ if ( picture_rate == 30 ) return EditRate_30;
+ if ( picture_rate == 48 ) return EditRate_48;
+ if ( picture_rate == 50 ) return EditRate_50;
+ if ( picture_rate == 60 ) return EditRate_60;
+ if ( picture_rate == 96 ) return EditRate_96;
+ if ( picture_rate == 100 ) return EditRate_100;
+ if ( picture_rate == 120 ) return EditRate_120;
+ return EditRate_24;
+ }
+
+ //
+ CommandOptions(int argc, const char** argv) :
+ mode(MMT_EXTRACT), error_flag(true), key_flag(false), read_hmac(false), split_wav(false),
+ mono_wav(false), verbose_flag(false), fb_dump_size(0), no_write_flag(false),
+ version_flag(false), help_flag(false), stereo_image_flag(false), number_width(6),
+ start_frame(0), duration(0xffffffff), duration_flag(false), j2c_pedantic(true),
+ picture_rate(24), fb_size(FRAME_BUFFER_SIZE), file_prefix(0),
+ channel_fmt(PCM::CF_NONE), input_filename(0)
+ {
+ memset(key_value, 0, KeyLen);
+ memset(key_id_value, 0, UUIDlen);
+
+ for ( int i = 1; i < argc; ++i )
+ {
+
+ if ( (strcmp( argv[i], "-help") == 0) )
+ {
+ help_flag = true;
+ continue;
+ }
+
+ if ( argv[i][0] == '-'
+ && ( isalpha(argv[i][1]) || isdigit(argv[i][1]) )
+ && argv[i][2] == 0 )
+ {
+ switch ( argv[i][1] )
+ {
+ case '1': mono_wav = true; break;
+ case '2': split_wav = true; break;
+ case '3': stereo_image_flag = true; break;
+
+ case 'b':
+ TEST_EXTRA_ARG(i, 'b');
+ fb_size = abs(atoi(argv[i]));
+
+ if ( verbose_flag )
+ fprintf(stderr, "Frame Buffer size: %u bytes.\n", fb_size);
+
+ break;
+
+ case 'd':
+ TEST_EXTRA_ARG(i, 'd');
+ duration_flag = true;
+ duration = abs(atoi(argv[i]));
+ break;
+
+ case 'f':
+ TEST_EXTRA_ARG(i, 'f');
+ start_frame = abs(atoi(argv[i]));
+ break;
+
+ case 'G': mode = MMT_GOP_START; break;
+ case 'h': help_flag = true; break;
+
+ case 'm': read_hmac = true; break;
+
+ case 'p':
+ TEST_EXTRA_ARG(i, 'p');
+ picture_rate = abs(atoi(argv[i]));
+ break;
+
+ case 's':
+ TEST_EXTRA_ARG(i, 's');
+ fb_dump_size = abs(atoi(argv[i]));
+ break;
+
+ case 'V': version_flag = true; break;
+ case 'v': verbose_flag = true; break;
+ case 'W': no_write_flag = true; break;
+
+ case 'w':
+ TEST_EXTRA_ARG(i, 'w');
+ number_width = abs(atoi(argv[i]));
+ break;
+
+ case 'Z': j2c_pedantic = false; break;
+ case 'z': j2c_pedantic = true; break;
+
+ default:
+ fprintf(stderr, "Unrecognized option: %s\n", argv[i]);
+ return;
+ }
+ }
+ else
+ {
+ if ( argv[i][0] != '-' )
+ {
+ if ( input_filename == 0 )
+ {
+ input_filename = argv[i];
+ }
+ else if ( file_prefix == 0 )
+ {
+ file_prefix = argv[i];
+ }
+ }
+ else
+ {
+ fprintf(stderr, "Unrecognized argument: %s\n", argv[i]);
+ return;
+ }
+ }
+ }
+
+ if ( help_flag || version_flag )
+ return;
+
+ if ( ( mode == MMT_EXTRACT || mode == MMT_GOP_START ) && input_filename == 0 )
+ {
+ fputs("Option requires at least one filename argument.\n", stderr);
+ return;
+ }
+
+ if ( mode == MMT_EXTRACT && file_prefix == 0 )
+ {
+ prefix_buffer = Kumu::PathSetExtension(input_filename, "") + "_";
+ file_prefix = prefix_buffer.c_str();
+ }
+
+ error_flag = false;
+ }
+};
+
+//------------------------------------------------------------------------------------------
+// MPEG2 essence
+
+// Read a plaintext MPEG2 Video Elementary Stream from a plaintext ASDCP file
+// Read a plaintext MPEG2 Video Elementary Stream from a ciphertext ASDCP file
+// Read a ciphertext MPEG2 Video Elementary Stream from a ciphertext ASDCP file
+//
+Result_t
+read_MPEG2_file(CommandOptions& Options)
+{
+ AESDecContext* Context = 0;
+ HMACContext* HMAC = 0;
+ MPEG2::MXFReader Reader;
+ MPEG2::FrameBuffer FrameBuffer(Options.fb_size);
+ Kumu::FileWriter OutFile;
+ ui32_t frame_count = 0;
+
+ Result_t result = Reader.OpenRead(Options.input_filename);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ MPEG2::VideoDescriptor VDesc;
+ Reader.FillVideoDescriptor(VDesc);
+ frame_count = VDesc.ContainerDuration;
+
+ if ( Options.verbose_flag )
+ {
+ fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
+ MPEG2::VideoDescriptorDump(VDesc);
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ char filename[256];
+ snprintf(filename, 256, "%s.ves", Options.file_prefix);
+ result = OutFile.OpenWrite(filename);
+ }
+
+ if ( ASDCP_SUCCESS(result) && Options.key_flag )
+ {
+ Context = new AESDecContext;
+ result = Context->InitKey(Options.key_value);
+
+ if ( ASDCP_SUCCESS(result) && Options.read_hmac )
+ {
+ WriterInfo Info;
+ Reader.FillWriterInfo(Info);
+
+ if ( Info.UsesHMAC )
+ {
+ HMAC = new HMACContext;
+ result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
+ }
+ else
+ {
+ fputs("File does not contain HMAC values, ignoring -m option.\n", stderr);
+ }
+ }
+ }
+
+ ui32_t last_frame = Options.start_frame + ( Options.duration ? Options.duration : frame_count);
+ if ( last_frame > frame_count )
+ last_frame = frame_count;
+
+ for ( ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++ )
+ {
+ result = Reader.ReadFrame(i, FrameBuffer, Context, HMAC);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ if ( Options.verbose_flag )
+ FrameBuffer.Dump(stderr, Options.fb_dump_size);
+
+ ui32_t write_count = 0;
+ result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count);
+ }
+ }
+
+ return result;
+}
+
+
+//
+Result_t
+gop_start_test(CommandOptions& Options)
+{
+ using namespace ASDCP::MPEG2;
+
+ MXFReader Reader;
+ MPEG2::FrameBuffer FrameBuffer(Options.fb_size);
+ ui32_t frame_count = 0;
+
+ Result_t result = Reader.OpenRead(Options.input_filename);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ MPEG2::VideoDescriptor VDesc;
+ Reader.FillVideoDescriptor(VDesc);
+ frame_count = VDesc.ContainerDuration;
+
+ if ( Options.verbose_flag )
+ {
+ fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
+ MPEG2::VideoDescriptorDump(VDesc);
+ }
+ }
+
+ ui32_t last_frame = Options.start_frame + ( Options.duration ? Options.duration : frame_count);
+ if ( last_frame > frame_count )
+ last_frame = frame_count;
+
+ for ( ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++ )
+ {
+ result = Reader.ReadFrameGOPStart(i, FrameBuffer);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ if ( Options.verbose_flag )
+ FrameBuffer.Dump(stderr, Options.fb_dump_size);
+
+ if ( FrameBuffer.FrameType() != FRAME_I )
+ fprintf(stderr, "Expecting an I frame, got %c\n", FrameTypeChar(FrameBuffer.FrameType()));
+
+ fprintf(stderr, "Requested frame %u, got %u\n", i, FrameBuffer.FrameNumber());
+ }
+ }
+
+ return result;
+}
+
+//------------------------------------------------------------------------------------------
+// JPEG 2000 essence
+
+
+// Read one or more plaintext JPEG 2000 stereoscopic codestream pairs from a plaintext ASDCP file
+// Read one or more plaintext JPEG 2000 stereoscopic codestream pairs from a ciphertext ASDCP file
+// Read one or more ciphertext JPEG 2000 stereoscopic codestream pairs from a ciphertext ASDCP file
+Result_t
+read_JP2K_S_file(CommandOptions& Options)
+{
+ AESDecContext* Context = 0;
+ HMACContext* HMAC = 0;
+ JP2K::MXFSReader Reader;
+ JP2K::FrameBuffer FrameBuffer(Options.fb_size);
+ ui32_t frame_count = 0;
+
+ Result_t result = Reader.OpenRead(Options.input_filename);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ JP2K::PictureDescriptor PDesc;
+ Reader.FillPictureDescriptor(PDesc);
+
+ frame_count = PDesc.ContainerDuration;
+
+ if ( Options.verbose_flag )
+ {
+ fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
+ JP2K::PictureDescriptorDump(PDesc);
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) && Options.key_flag )
+ {
+ Context = new AESDecContext;
+ result = Context->InitKey(Options.key_value);
+
+ if ( ASDCP_SUCCESS(result) && Options.read_hmac )
+ {
+ WriterInfo Info;
+ Reader.FillWriterInfo(Info);
+
+ if ( Info.UsesHMAC )
+ {
+ HMAC = new HMACContext;
+ result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
+ }
+ else
+ {
+ fputs("File does not contain HMAC values, ignoring -m option.\n", stderr);
+ }
+ }
+ }
+
+ const int filename_max = 1024;
+ char filename[filename_max];
+ ui32_t last_frame = Options.start_frame + ( Options.duration ? Options.duration : frame_count);
+ if ( last_frame > frame_count )
+ last_frame = frame_count;
+
+ char left_format[64]; char right_format[64];
+ snprintf(left_format, 64, "%%s%%0%duL.j2c", Options.number_width);
+ snprintf(right_format, 64, "%%s%%0%duR.j2c", Options.number_width);
+
+ for ( ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++ )
+ {
+ result = Reader.ReadFrame(i, JP2K::SP_LEFT, FrameBuffer, Context, HMAC);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ Kumu::FileWriter OutFile;
+ ui32_t write_count;
+ snprintf(filename, filename_max, left_format, Options.file_prefix, i);
+ result = OutFile.OpenWrite(filename);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count);
+
+ if ( Options.verbose_flag )
+ FrameBuffer.Dump(stderr, Options.fb_dump_size);
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Reader.ReadFrame(i, JP2K::SP_RIGHT, FrameBuffer, Context, HMAC);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ Kumu::FileWriter OutFile;
+ ui32_t write_count;
+ snprintf(filename, filename_max, right_format, Options.file_prefix, i);
+ result = OutFile.OpenWrite(filename);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count);
+ }
+ }
+
+ return result;
+}
+
+// Read one or more plaintext JPEG 2000 codestreams from a plaintext ASDCP file
+// Read one or more plaintext JPEG 2000 codestreams from a ciphertext ASDCP file
+// Read one or more ciphertext JPEG 2000 codestreams from a ciphertext ASDCP file
+//
+Result_t
+read_JP2K_file(CommandOptions& Options)
+{
+ AESDecContext* Context = 0;
+ HMACContext* HMAC = 0;
+ JP2K::MXFReader Reader;
+ JP2K::FrameBuffer FrameBuffer(Options.fb_size);
+ ui32_t frame_count = 0;
+
+ Result_t result = Reader.OpenRead(Options.input_filename);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ JP2K::PictureDescriptor PDesc;
+ Reader.FillPictureDescriptor(PDesc);
+
+ frame_count = PDesc.ContainerDuration;
+
+ if ( Options.verbose_flag )
+ {
+ fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
+ JP2K::PictureDescriptorDump(PDesc);
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) && Options.key_flag )
+ {
+ Context = new AESDecContext;
+ result = Context->InitKey(Options.key_value);
+
+ if ( ASDCP_SUCCESS(result) && Options.read_hmac )
+ {
+ WriterInfo Info;
+ Reader.FillWriterInfo(Info);
+
+ if ( Info.UsesHMAC )
+ {
+ HMAC = new HMACContext;
+ result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
+ }
+ else
+ {
+ fputs("File does not contain HMAC values, ignoring -m option.\n", stderr);
+ }
+ }
+ }
+
+ ui32_t last_frame = Options.start_frame + ( Options.duration ? Options.duration : frame_count);
+ if ( last_frame > frame_count )
+ last_frame = frame_count;
+
+ char name_format[64];
+ snprintf(name_format, 64, "%%s%%0%du.j2c", Options.number_width);
+
+ for ( ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++ )
+ {
+ result = Reader.ReadFrame(i, FrameBuffer, Context, HMAC);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ Kumu::FileWriter OutFile;
+ char filename[256];
+ ui32_t write_count;
+ snprintf(filename, 256, name_format, Options.file_prefix, i);
+ result = OutFile.OpenWrite(filename);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count);
+
+ if ( Options.verbose_flag )
+ FrameBuffer.Dump(stderr, Options.fb_dump_size);
+ }
+ }
+
+ return result;
+}
+
+//------------------------------------------------------------------------------------------
+// PCM essence
+
+// Read one or more plaintext PCM audio streams from a plaintext ASDCP file
+// Read one or more plaintext PCM audio streams from a ciphertext ASDCP file
+// Read one or more ciphertext PCM audio streams from a ciphertext ASDCP file
+//
+Result_t
+read_PCM_file(CommandOptions& Options)
+{
+ AESDecContext* Context = 0;
+ HMACContext* HMAC = 0;
+ PCM::MXFReader Reader;
+ PCM::FrameBuffer FrameBuffer;
+ WavFileWriter OutWave;
+ PCM::AudioDescriptor ADesc;
+ ui32_t last_frame = 0;
+
+ Result_t result = Reader.OpenRead(Options.input_filename);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ Reader.FillAudioDescriptor(ADesc);
+
+ if ( ADesc.EditRate != EditRate_23_98
+ && ADesc.EditRate != EditRate_24
+ && ADesc.EditRate != EditRate_25
+ && ADesc.EditRate != EditRate_30
+ && ADesc.EditRate != EditRate_48
+ && ADesc.EditRate != EditRate_50
+ && ADesc.EditRate != EditRate_60 )
+ ADesc.EditRate = Options.PictureRate();
+
+ FrameBuffer.Capacity(PCM::CalcFrameBufferSize(ADesc));
+
+ if ( Options.verbose_flag )
+ PCM::AudioDescriptorDump(ADesc);
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ last_frame = ADesc.ContainerDuration;
+
+ if ( Options.duration > 0 && Options.duration < last_frame )
+ last_frame = Options.duration;
+
+ if ( Options.start_frame > 0 )
+ {
+ if ( Options.start_frame > ADesc.ContainerDuration )
+ {
+ fprintf(stderr, "Start value greater than file duration.\n");
+ return RESULT_FAIL;
+ }
+
+ last_frame = Kumu::xmin(Options.start_frame + last_frame, ADesc.ContainerDuration);
+ }
+
+ ADesc.ContainerDuration = last_frame - Options.start_frame;
+ OutWave.OpenWrite(ADesc, Options.file_prefix,
+ ( Options.split_wav ? WavFileWriter::ST_STEREO :
+ ( Options.mono_wav ? WavFileWriter::ST_MONO : WavFileWriter::ST_NONE ) ));
+ }
+
+ if ( ASDCP_SUCCESS(result) && Options.key_flag )
+ {
+ Context = new AESDecContext;
+ result = Context->InitKey(Options.key_value);
+
+ if ( ASDCP_SUCCESS(result) && Options.read_hmac )
+ {
+ WriterInfo Info;
+ Reader.FillWriterInfo(Info);
+
+ if ( Info.UsesHMAC )
+ {
+ HMAC = new HMACContext;
+ result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
+ }
+ else
+ {
+ fputs("File does not contain HMAC values, ignoring -m option.\n", stderr);
+ }
+ }
+ }
+
+ for ( ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++ )
+ {
+ result = Reader.ReadFrame(i, FrameBuffer, Context, HMAC);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ if ( Options.verbose_flag )
+ FrameBuffer.Dump(stderr, Options.fb_dump_size);
+
+ result = OutWave.WriteFrame(FrameBuffer);
+ }
+ }
+
+ return result;
+}
+
+
+//------------------------------------------------------------------------------------------
+// TimedText essence
+
+// Read one or more timed text streams from a plaintext ASDCP file
+// Read one or more timed text streams from a ciphertext ASDCP file
+// Read one or more timed text streams from a ciphertext ASDCP file
+//
+Result_t
+read_timed_text_file(CommandOptions& Options)
+{
+ AESDecContext* Context = 0;
+ HMACContext* HMAC = 0;
+ TimedText::MXFReader Reader;
+ TimedText::FrameBuffer FrameBuffer;
+ TimedText::TimedTextDescriptor TDesc;
+
+ Result_t result = Reader.OpenRead(Options.input_filename);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ Reader.FillTimedTextDescriptor(TDesc);
+ FrameBuffer.Capacity(Options.fb_size);
+
+ if ( Options.verbose_flag )
+ TimedText::DescriptorDump(TDesc);
+ }
+
+ if ( ASDCP_SUCCESS(result) && Options.key_flag )
+ {
+ Context = new AESDecContext;
+ result = Context->InitKey(Options.key_value);
+
+ if ( ASDCP_SUCCESS(result) && Options.read_hmac )
+ {
+ WriterInfo Info;
+ Reader.FillWriterInfo(Info);
+
+ if ( Info.UsesHMAC )
+ {
+ HMAC = new HMACContext;
+ result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
+ }
+ else
+ {
+ fputs("File does not contain HMAC values, ignoring -m option.\n", stderr);
+ }
+ }
+ }
+
+ if ( ASDCP_FAILURE(result) )
+ return result;
+
+ std::string XMLDoc;
+ std::string out_path = Kumu::PathDirname(Options.file_prefix);
+ ui32_t write_count;
+ char buf[64];
+ TimedText::ResourceList_t::const_iterator ri;
+
+ result = Reader.ReadTimedTextResource(XMLDoc, Context, HMAC);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ Kumu::FileWriter Writer;
+ result = Writer.OpenWrite(Options.file_prefix);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Writer.Write(reinterpret_cast<const byte_t*>(XMLDoc.c_str()), XMLDoc.size(), &write_count);
+ }
+
+ for ( ri = TDesc.ResourceList.begin() ; ri != TDesc.ResourceList.end() && ASDCP_SUCCESS(result); ri++ )
+ {
+ result = Reader.ReadAncillaryResource(ri->ResourceID, FrameBuffer, Context, HMAC);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ Kumu::FileWriter Writer;
+ result = Writer.OpenWrite(Kumu::PathJoin(out_path, Kumu::UUID(ri->ResourceID).EncodeHex(buf, 64)).c_str());
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ if ( Options.verbose_flag )
+ FrameBuffer.Dump(stderr, Options.fb_dump_size);
+
+ result = Writer.Write(FrameBuffer.RoData(), FrameBuffer.Size(), &write_count);
+ }
+ }
+ }
+
+ return result;
+}
+
+//
+int
+main(int argc, const char** argv)
+{
+ Result_t result = RESULT_OK;
+ char str_buf[64];
+ CommandOptions Options(argc, argv);
+
+ if ( Options.version_flag )
+ banner();
+
+ if ( Options.help_flag )
+ usage();
+
+ if ( Options.version_flag || Options.help_flag )
+ return 0;
+
+ if ( Options.error_flag )
+ {
+ fprintf(stderr, "There was a problem. Type %s -h for help.\n", PROGRAM_NAME);
+ return 3;
+ }
+
+ if ( Options.mode == MMT_GOP_START )
+ {
+ result = gop_start_test(Options);
+ }
+ else if ( Options.mode == MMT_EXTRACT )
+ {
+ EssenceType_t EssenceType;
+ result = ASDCP::EssenceType(Options.input_filename, EssenceType);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ switch ( EssenceType )
+ {
+ case ESS_MPEG2_VES:
+ result = read_MPEG2_file(Options);
+ break;
+
+ case ESS_JPEG_2000:
+ if ( Options.stereo_image_flag )
+ result = read_JP2K_S_file(Options);
+ else
+ result = read_JP2K_file(Options);
+ break;
+
+ case ESS_JPEG_2000_S:
+ result = read_JP2K_S_file(Options);
+ break;
+
+ case ESS_PCM_24b_48k:
+ case ESS_PCM_24b_96k:
+ result = read_PCM_file(Options);
+ break;
+
+ case ESS_TIMED_TEXT:
+ result = read_timed_text_file(Options);
+ break;
+
+ default:
+ fprintf(stderr, "%s: Unknown file type, not ASDCP essence.\n", Options.input_filename);
+ return 5;
+ }
+ }
+ }
+ else
+ {
+ fprintf(stderr, "Unhandled mode: %d.\n", Options.mode);
+ return 6;
+ }
+
+ if ( ASDCP_FAILURE(result) )
+ {
+ fputs("Program stopped on error.\n", stderr);
+
+ if ( result == RESULT_SFORMAT )
+ {
+ fputs("Use option '-3' to force stereoscopic mode.\n", stderr);
+ }
+ else if ( result != RESULT_FAIL )
+ {
+ fputs(result, stderr);
+ fputc('\n', stderr);
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+
+//
+// end asdcp-unwrap.cpp
+//
diff --git a/asdcplib/src/asdcp-util.cpp b/asdcplib/src/asdcp-util.cpp
new file mode 100755
index 0000000..0d9ed4c
--- /dev/null
+++ b/asdcplib/src/asdcp-util.cpp
@@ -0,0 +1,294 @@
+/*
+Copyright (c) 2003-2012, 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 asdcp-util.cpp
+ \version $Id: asdcp-util.cpp,v 1.1 2012/02/03 19:49:57 jhurst Exp $
+ \brief Utility functions for working with AS-DCP files
+
+ This program provides utility features commonly useful in DCP workflows.
+
+ For more information about asdcplib, please refer to the header file AS_DCP.h
+*/
+
+#include <KM_fileio.h>
+#include <KM_prng.h>
+#include <AS_DCP.h>
+#include <openssl/sha.h>
+
+using namespace Kumu;
+
+
+//------------------------------------------------------------------------------------------
+//
+// command line option parser class
+
+static const char* PROGRAM_NAME = "asdcp-util"; // program name for messages
+
+// 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 = stdout)
+{
+ fprintf(stream, "\n\
+%s (asdcplib %s)\n\n\
+Copyright (c) 2003-2012 John Hurst\n\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",
+ PROGRAM_NAME, ASDCP::Version(), PROGRAM_NAME);
+}
+
+//
+void
+usage(FILE* stream = stdout)
+{
+ fprintf(stream, "\
+USAGE: %s [-h|-help] [-V]\n\
+\n\
+ %s -d <input-file>\n\
+\n\
+ %s -g | -u\n\
+\n\
+ %s -u\n\n",
+ PROGRAM_NAME, PROGRAM_NAME, PROGRAM_NAME, PROGRAM_NAME);
+
+ fprintf(stream, "\
+Major modes:\n\
+ -d - Calculate message digest of input file\n\
+ -g - Generate a random 16 byte value to stdout\n\
+ -h | -help - Show help\n\
+ -u - Generate a random UUID value to stdout\n\
+ -V - Show version information\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");
+}
+
+//
+enum MajorMode_t
+{
+ MMT_NONE,
+ MMT_GEN_ID,
+ MMT_GEN_KEY,
+ MMT_DIGEST,
+};
+
+//
+class CommandOptions
+{
+ CommandOptions();
+
+public:
+ MajorMode_t mode;
+ bool error_flag; // true if the given options are in error or not complete
+ bool version_flag; // true if the version display option was selected
+ bool help_flag; // true if the help display option was selected
+ PathList_t filenames; // list of filenames to be processed
+
+ //
+ CommandOptions(int argc, const char** argv) :
+ mode(MMT_NONE), error_flag(true), version_flag(false), help_flag(false)
+ {
+ for ( int i = 1; i < argc; ++i )
+ {
+
+ if ( (strcmp( argv[i], "-help") == 0) )
+ {
+ help_flag = true;
+ continue;
+ }
+
+ if ( argv[i][0] == '-'
+ && ( isalpha(argv[i][1]) || isdigit(argv[i][1]) )
+ && argv[i][2] == 0 )
+ {
+ switch ( argv[i][1] )
+ {
+ case 'd': mode = MMT_DIGEST; break;
+ case 'g': mode = MMT_GEN_KEY; break;
+ case 'h': help_flag = true; break;
+ case 'u': mode = MMT_GEN_ID; break;
+ case 'V': version_flag = true; break;
+
+ default:
+ fprintf(stderr, "Unrecognized option: %s\n", argv[i]);
+ return;
+ }
+ }
+ else
+ {
+ if ( argv[i][0] != '-' )
+ {
+ filenames.push_back(argv[i]);
+ }
+ else
+ {
+ fprintf(stderr, "Unrecognized argument: %s\n", argv[i]);
+ return;
+ }
+ }
+ }
+
+ if ( help_flag || version_flag )
+ return;
+
+ if ( ( mode == MMT_DIGEST ) && filenames.empty() )
+ {
+ fputs("Option requires at least one filename argument.\n", stderr);
+ return;
+ }
+
+ if ( mode == MMT_NONE && ! help_flag && ! version_flag )
+ {
+ fputs("No operation selected (use one of -[dgu] or -h for help).\n", stderr);
+ return;
+ }
+
+ error_flag = false;
+ }
+};
+
+//
+Result_t
+digest_file(const std::string& filename)
+{
+ FileReader Reader;
+ SHA_CTX Ctx;
+ SHA1_Init(&Ctx);
+ ByteString Buf(8192);
+
+ Result_t result = Reader.OpenRead(filename.c_str());
+
+ while ( ASDCP_SUCCESS(result) )
+ {
+ ui32_t read_count = 0;
+ result = Reader.Read(Buf.Data(), Buf.Capacity(), &read_count);
+
+ if ( result == RESULT_ENDOFFILE )
+ {
+ result = RESULT_OK;
+ break;
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ SHA1_Update(&Ctx, Buf.Data(), read_count);
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ const ui32_t sha_len = 20;
+ byte_t bin_buf[sha_len];
+ char sha_buf[64];
+ SHA1_Final(bin_buf, &Ctx);
+
+ fprintf(stdout, "%s %s\n",
+ base64encode(bin_buf, sha_len, sha_buf, 64),
+ filename.c_str());
+ }
+
+ return result;
+}
+
+//
+int
+main(int argc, const char** argv)
+{
+ Result_t result = RESULT_OK;
+ char str_buf[64];
+ CommandOptions Options(argc, argv);
+
+ if ( Options.version_flag )
+ banner();
+
+ if ( Options.help_flag )
+ usage();
+
+ if ( Options.version_flag || Options.help_flag )
+ return 0;
+
+ if ( Options.error_flag )
+ {
+ fprintf(stderr, "There was a problem. Type %s -h for help.\n",
+ PROGRAM_NAME);
+ return 3;
+ }
+
+ if ( Options.mode == MMT_GEN_KEY )
+ {
+ Kumu::FortunaRNG RNG;
+ byte_t bin_buf[ASDCP::KeyLen];
+
+ RNG.FillRandom(bin_buf, ASDCP::KeyLen);
+ printf("%s\n", Kumu::bin2hex(bin_buf, ASDCP::KeyLen, str_buf, 64));
+ }
+ else if ( Options.mode == MMT_GEN_ID )
+ {
+ UUID TmpID;
+ Kumu::GenRandomValue(TmpID);
+ printf("%s\n", TmpID.EncodeHex(str_buf, 64));
+ }
+ else if ( Options.mode == MMT_DIGEST )
+ {
+ PathList_t::iterator i;
+
+ for ( i = Options.filenames.begin();
+ i != Options.filenames.end() && ASDCP_SUCCESS(result); ++i )
+ result = digest_file(*i);
+ }
+ else
+ {
+ fprintf(stderr, "Unhandled mode: %d.\n", Options.mode);
+ return 6;
+ }
+
+ if ( ASDCP_FAILURE(result) )
+ {
+ fputs("Program stopped on error.\n", stderr);
+
+ if ( result != RESULT_FAIL )
+ {
+ fputs(result, stderr);
+ fputc('\n', stderr);
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+
+//
+// end asdcp-util.cpp
+//
diff --git a/asdcplib/src/asdcp-version.cpp b/asdcplib/src/asdcp-version.cpp
new file mode 100755
index 0000000..621eec3
--- /dev/null
+++ b/asdcplib/src/asdcp-version.cpp
@@ -0,0 +1,46 @@
+/*
+Copyright (c) 2004-2009, 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 asdcp-version.cpp
+ \version $Id: asdcp-version.cpp,v 1.4 2009/04/09 19:24:14 msheby Exp $
+ \brief AS-DCP library version annunciator
+*/
+
+#include <AS_DCP.h>
+using namespace ASDCP;
+
+//
+int
+main()
+{
+ printf("%s", VERSION);
+ return 0;
+}
+
+
+//
+// end asdcp-version.cpp
+//
diff --git a/asdcplib/src/asdcp-wrap.cpp b/asdcplib/src/asdcp-wrap.cpp
new file mode 100755
index 0000000..e1182ae
--- /dev/null
+++ b/asdcplib/src/asdcp-wrap.cpp
@@ -0,0 +1,1151 @@
+/*
+Copyright (c) 2003-2012, 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 asdcp-wrap.cpp
+ \version $Id: asdcp-wrap.cpp,v 1.5 2012/03/07 18:47:02 mikey Exp $
+ \brief AS-DCP file manipulation utility
+
+ This program wraps d-cinema essence (picture, sound or text) in t an AS-DCP
+ MXF file.
+
+ For more information about asdcplib, please refer to the header file AS_DCP.h
+
+ WARNING: While the asdcplib library attempts to provide a complete and secure
+ implementation of the cryptographic features of the AS-DCP file formats, this
+ unit test program is NOT secure and is therefore NOT SUITABLE FOR USE in a
+ production environment without some modification.
+
+ In particular, this program uses weak IV generation and externally generated
+ plaintext keys. These shortcomings exist because cryptographic-quality
+ random number generation and key management are outside the scope of the
+ asdcplib library. Developers using asdcplib for commercial implementations
+ claiming SMPTE conformance are expected to provide proper implementations of
+ these features.
+*/
+
+#include <KM_fileio.h>
+#include <KM_prng.h>
+#include <AS_DCP.h>
+#include <PCMParserList.h>
+#include <Metadata.h>
+
+using namespace ASDCP;
+
+const ui32_t FRAME_BUFFER_SIZE = 4 * Kumu::Megabyte;
+
+//------------------------------------------------------------------------------------------
+//
+// command line option parser class
+
+static const char* PROGRAM_NAME = "asdcp-wrap"; // program name for messages
+
+// local program identification info written to file headers
+class MyInfo : public WriterInfo
+{
+public:
+ MyInfo()
+ {
+ static byte_t default_ProductUUID_Data[UUIDlen] =
+ { 0x7d, 0x83, 0x6e, 0x16, 0x37, 0xc7, 0x4c, 0x22,
+ 0xb2, 0xe0, 0x46, 0xa7, 0x17, 0xe8, 0x4f, 0x42 };
+
+ memcpy(ProductUUID, default_ProductUUID_Data, UUIDlen);
+ CompanyName = "WidgetCo";
+ ProductName = "asdcp-wrap";
+ ProductVersion = ASDCP::Version();
+ }
+} s_MyInfo;
+
+
+
+// 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 = stdout)
+{
+ fprintf(stream, "\n\
+%s (asdcplib %s)\n\n\
+Copyright (c) 2003-2012 John Hurst\n\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",
+ PROGRAM_NAME, ASDCP::Version(), PROGRAM_NAME);
+}
+
+//
+void
+usage(FILE* stream = stdout)
+{
+ fprintf(stream, "\
+USAGE: %s [-h|-help] [-V]\n\
+\n\
+ %s [-3] [-a <uuid>] [-b <buffer-size>] [-C <UL>] [-d <duration>]\n\
+ [-e|-E] [-f <start-frame>] [-j <key-id-string>] [-k <key-string>]\n\
+ [-l <label>] [-L] [-M] [-p <frame-rate>] [-s <num>] [-v] [-W]\n\
+ [-z|-Z] <input-file>+ <output-file>\n\n",
+ PROGRAM_NAME, PROGRAM_NAME);
+
+ fprintf(stream, "\
+Options:\n\
+ -3 - 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\
+ -C <UL> - Set ChannelAssignment UL value\n\
+ -h | -help - Show help\n\
+ -V - Show version information\n\
+ -e - Encrypt MPEG or JP2K headers (default)\n\
+ -E - Do not encrypt MPEG or JP2K headers\n\
+ -j <key-id-str> - Write key ID instead of creating a random value\n\
+ -k <key-string> - Use key for ciphertext operations\n\
+ -M - Do not create HMAC values when writing\n\
+ -a <UUID> - Specify the Asset ID of a file (with -c)\n\
+ -b <buffer-size> - Specify size in bytes of picture frame buffer.\n\
+ Defaults to 4,194,304 (4MB)\n\
+ -d <duration> - Number of frames to process, default all\n\
+ -f <start-frame> - Starting frame number, default 0\n\
+ -l <label> - Use given channel format label when writing MXF sound\n\
+ files. SMPTE 429-2 labels: '5.1', '6.1', '7.1',\n\
+ '7.1DS', 'WTF'\n\
+ Default is no label (valid for Interop only).\n\
+ -L - Write SMPTE UL values instead of MXF Interop\n\
+ -p <rate> - fps of picture when wrapping PCM or JP2K:\n\
+ Use one of [23|24|25|30|48|50|60], 24 is default\n\
+ -v - Verbose, prints informative messages to stderr\n\
+ -W - Read input file only, do not write source file\n\
+ -z - Fail if j2c inputs have unequal parameters (default)\n\
+ -Z - Ignore unequal parameters in j2c inputs\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\
+ o An argument of \"23\" to the -p option will be interpreted\n\
+ as 24000/1001 fps.\n\
+\n");
+}
+
+//
+PCM::ChannelFormat_t
+decode_channel_fmt(const std::string& label_name)
+{
+ if ( label_name == "5.1" )
+ return PCM::CF_CFG_1;
+
+ else if ( label_name == "6.1" )
+ return PCM::CF_CFG_2;
+
+ else if ( label_name == "7.1" )
+ return PCM::CF_CFG_3;
+
+ else if ( label_name == "WTF" )
+ return PCM::CF_CFG_4;
+
+ else if ( label_name == "7.1DS" )
+ return PCM::CF_CFG_5;
+
+ fprintf(stderr, "Error decoding channel format string: %s\n", label_name.c_str());
+ fprintf(stderr, "Expecting '5.1', '6.1', '7.1', '7.1DS' or 'WTF'\n");
+ return PCM::CF_NONE;
+}
+
+//
+//
+class CommandOptions
+{
+ CommandOptions();
+
+public:
+ bool error_flag; // true if the given options are in error or not complete
+ bool key_flag; // true if an encryption key was given
+ bool asset_id_flag; // true if an asset ID was given
+ bool encrypt_header_flag; // true if mpeg headers are to be encrypted
+ bool write_hmac; // true if HMAC values are to be generated and written
+ /// bool read_hmac; // true if HMAC values are to be validated
+ /// bool split_wav; // true if PCM is to be extracted to stereo WAV files
+ /// bool mono_wav; // true if PCM is to be extracted to mono WAV files
+ bool verbose_flag; // true if the verbose option was selected
+ ui32_t fb_dump_size; // number of bytes of frame buffer to dump
+ /// bool showindex_flag; // true if index is to be displayed
+ /// bool showheader_flag; // true if MXF file header is to be displayed
+ bool no_write_flag; // true if no output files are to be written
+ bool version_flag; // true if the version display option was selected
+ bool help_flag; // true if the help display option was selected
+ bool stereo_image_flag; // if true, expect stereoscopic JP2K input (left eye first)
+ /// ui32_t number_width; // number of digits in a serialized filename (for JPEG extract)
+ ui32_t start_frame; // frame number to begin processing
+ ui32_t duration; // number of frames to be processed
+ bool use_smpte_labels; // if true, SMPTE UL values will be written instead of MXF Interop values
+ bool j2c_pedantic; // passed to JP2K::SequenceParser::OpenRead
+ ui32_t picture_rate; // fps of picture when wrapping PCM
+ ui32_t fb_size; // size of picture frame buffer
+ byte_t key_value[KeyLen]; // value of given encryption key (when key_flag is true)
+ bool key_id_flag; // true if a key ID was given
+ byte_t key_id_value[UUIDlen];// value of given key ID (when key_id_flag is true)
+ byte_t asset_id_value[UUIDlen];// value of asset ID (when asset_id_flag is true)
+ PCM::ChannelFormat_t channel_fmt; // audio channel arrangement
+ std::string out_file; //
+ bool show_ul_values; /// if true, dump the UL table before going tp work.
+ Kumu::PathList_t filenames; // list of filenames to be processed
+ UL channel_assignment;
+
+ //
+ Rational PictureRate()
+ {
+ if ( picture_rate == 23 ) return EditRate_23_98;
+ if ( picture_rate == 24 ) return EditRate_24;
+ if ( picture_rate == 25 ) return EditRate_25;
+ if ( picture_rate == 30 ) return EditRate_30;
+ if ( picture_rate == 48 ) return EditRate_48;
+ if ( picture_rate == 50 ) return EditRate_50;
+ if ( picture_rate == 60 ) return EditRate_60;
+ if ( picture_rate == 96 ) return EditRate_96;
+ if ( picture_rate == 100 ) return EditRate_100;
+ if ( picture_rate == 120 ) return EditRate_120;
+ return EditRate_24;
+ }
+
+ //
+ const char* szPictureRate()
+ {
+ if ( picture_rate == 23 ) return "23.976";
+ if ( picture_rate == 24 ) return "24";
+ if ( picture_rate == 25 ) return "25";
+ if ( picture_rate == 30 ) return "30";
+ if ( picture_rate == 48 ) return "48";
+ if ( picture_rate == 50 ) return "50";
+ if ( picture_rate == 60 ) return "60";
+ if ( picture_rate == 96 ) return "96";
+ if ( picture_rate == 100 ) return "100";
+ if ( picture_rate == 120 ) return "120";
+ return "24";
+ }
+
+ //
+ CommandOptions(int argc, const char** argv) :
+ error_flag(true), key_flag(false), key_id_flag(false), asset_id_flag(false),
+ encrypt_header_flag(true), write_hmac(true),
+ verbose_flag(false), fb_dump_size(0),
+ no_write_flag(false), version_flag(false), help_flag(false), stereo_image_flag(false),
+ start_frame(0),
+ duration(0xffffffff), use_smpte_labels(false), j2c_pedantic(true),
+ fb_size(FRAME_BUFFER_SIZE),
+ channel_fmt(PCM::CF_NONE),
+ show_ul_values(false)
+ {
+ memset(key_value, 0, KeyLen);
+ memset(key_id_value, 0, UUIDlen);
+
+ for ( int i = 1; i < argc; i++ )
+ {
+
+ if ( (strcmp( argv[i], "-help") == 0) )
+ {
+ help_flag = true;
+ continue;
+ }
+
+ if ( argv[i][0] == '-'
+ && ( isalpha(argv[i][1]) || isdigit(argv[i][1]) )
+ && argv[i][2] == 0 )
+ {
+ switch ( argv[i][1] )
+ {
+ case '3': stereo_image_flag = true; break;
+
+ case 'a':
+ asset_id_flag = true;
+ TEST_EXTRA_ARG(i, 'a');
+ {
+ ui32_t length;
+ Kumu::hex2bin(argv[i], asset_id_value, UUIDlen, &length);
+
+ if ( length != UUIDlen )
+ {
+ fprintf(stderr, "Unexpected asset ID length: %u, expecting %u characters.\n", length, UUIDlen);
+ return;
+ }
+ }
+ break;
+
+ case 'b':
+ TEST_EXTRA_ARG(i, 'b');
+ fb_size = abs(atoi(argv[i]));
+
+ if ( verbose_flag )
+ fprintf(stderr, "Frame Buffer size: %u bytes.\n", fb_size);
+
+ break;
+
+ case 'C':
+ TEST_EXTRA_ARG(i, 'U');
+ if ( ! channel_assignment.DecodeHex(argv[i]) )
+ {
+ fprintf(stderr, "Error decoding UL value: %s\n", argv[i]);
+ return;
+ }
+ break;
+
+ case 'd':
+ TEST_EXTRA_ARG(i, 'd');
+ duration = abs(atoi(argv[i]));
+ break;
+
+ case 'E': encrypt_header_flag = false; break;
+ case 'e': encrypt_header_flag = true; break;
+
+ case 'f':
+ TEST_EXTRA_ARG(i, 'f');
+ start_frame = abs(atoi(argv[i]));
+ break;
+
+ case 'h': help_flag = true; break;
+
+ case 'j': key_id_flag = true;
+ TEST_EXTRA_ARG(i, 'j');
+ {
+ ui32_t length;
+ Kumu::hex2bin(argv[i], key_id_value, UUIDlen, &length);
+
+ if ( length != UUIDlen )
+ {
+ fprintf(stderr, "Unexpected key ID length: %u, expecting %u characters.\n", length, UUIDlen);
+ return;
+ }
+ }
+ break;
+
+ case 'k': key_flag = true;
+ TEST_EXTRA_ARG(i, 'k');
+ {
+ ui32_t length;
+ Kumu::hex2bin(argv[i], key_value, KeyLen, &length);
+
+ if ( length != KeyLen )
+ {
+ fprintf(stderr, "Unexpected key length: %u, expecting %u characters.\n", length, KeyLen);
+ return;
+ }
+ }
+ break;
+
+ case 'l':
+ TEST_EXTRA_ARG(i, 'l');
+ channel_fmt = decode_channel_fmt(argv[i]);
+ break;
+
+ case 'L': use_smpte_labels = true; break;
+ case 'M': write_hmac = false; break;
+
+ case 'p':
+ TEST_EXTRA_ARG(i, 'p');
+ picture_rate = abs(atoi(argv[i]));
+ break;
+
+ case 'V': version_flag = true; break;
+ case 'v': verbose_flag = true; break;
+ case 'W': no_write_flag = true; break;
+ case 'Z': j2c_pedantic = false; break;
+ case 'z': j2c_pedantic = true; break;
+
+ default:
+ fprintf(stderr, "Unrecognized option: %s\n", argv[i]);
+ return;
+ }
+ }
+ else
+ {
+
+ if ( argv[i][0] != '-' )
+ {
+ filenames.push_back(argv[i]);
+ }
+ else
+ {
+ fprintf(stderr, "Unrecognized argument: %s\n", argv[i]);
+ return;
+ }
+ }
+ }
+
+ if ( help_flag || version_flag )
+ return;
+
+ if ( filenames.size() < 2 )
+ {
+ fputs("Option requires at least two filename arguments: <input-file> <output-file>\n", stderr);
+ return;
+ }
+
+ out_file = filenames.back();
+ filenames.pop_back();
+ error_flag = false;
+ }
+};
+
+//------------------------------------------------------------------------------------------
+// MPEG2 essence
+
+// Write a plaintext MPEG2 Video Elementary Stream to a plaintext ASDCP file
+// Write a plaintext MPEG2 Video Elementary Stream to a ciphertext ASDCP file
+//
+Result_t
+write_MPEG2_file(CommandOptions& Options)
+{
+ AESEncContext* Context = 0;
+ HMACContext* HMAC = 0;
+ MPEG2::FrameBuffer FrameBuffer(Options.fb_size);
+ MPEG2::Parser Parser;
+ MPEG2::MXFWriter Writer;
+ MPEG2::VideoDescriptor VDesc;
+ byte_t IV_buf[CBC_BLOCK_SIZE];
+ Kumu::FortunaRNG RNG;
+
+ // set up essence parser
+ Result_t result = Parser.OpenRead(Options.filenames.front().c_str());
+
+ // set up MXF writer
+ if ( ASDCP_SUCCESS(result) )
+ {
+ Parser.FillVideoDescriptor(VDesc);
+
+ if ( Options.verbose_flag )
+ {
+ fputs("MPEG-2 Pictures\n", stderr);
+ fputs("VideoDescriptor:\n", stderr);
+ fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
+ MPEG2::VideoDescriptorDump(VDesc);
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+ {
+ WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here
+ if ( Options.asset_id_flag )
+ memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen);
+ else
+ Kumu::GenRandomUUID(Info.AssetUUID);
+
+ if ( Options.use_smpte_labels )
+ {
+ Info.LabelSetType = LS_MXF_SMPTE;
+ fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n");
+ }
+
+ // configure encryption
+ if( Options.key_flag )
+ {
+ Kumu::GenRandomUUID(Info.ContextID);
+ Info.EncryptedEssence = true;
+
+ if ( Options.key_id_flag )
+ memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen);
+ else
+ RNG.FillRandom(Info.CryptographicKeyID, UUIDlen);
+
+ Context = new AESEncContext;
+ result = Context->InitKey(Options.key_value);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
+
+ if ( ASDCP_SUCCESS(result) && Options.write_hmac )
+ {
+ Info.UsesHMAC = true;
+ HMAC = new HMACContext;
+ result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Writer.OpenWrite(Options.out_file.c_str(), Info, VDesc);
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ // loop through the frames
+ {
+ result = Parser.Reset();
+ ui32_t duration = 0;
+
+ while ( ASDCP_SUCCESS(result) && duration++ < Options.duration )
+ {
+ if ( duration == 1 )
+ {
+ result = Parser.ReadFrame(FrameBuffer);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ if ( Options.verbose_flag )
+ FrameBuffer.Dump(stderr, Options.fb_dump_size);
+
+ if ( Options.encrypt_header_flag )
+ FrameBuffer.PlaintextOffset(0);
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+ {
+ result = Writer.WriteFrame(FrameBuffer, Context, HMAC);
+
+ // The Writer class will forward the last block of ciphertext
+ // to the encryption context for use as the IV for the next
+ // frame. If you want to use non-sequitur IV values, un-comment
+ // the following line of code.
+ // if ( ASDCP_SUCCESS(result) && Options.key_flag )
+ // Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
+ }
+ }
+
+ if ( result == RESULT_ENDOFFILE )
+ result = RESULT_OK;
+ }
+
+ if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+ result = Writer.Finalize();
+
+ return result;
+}
+
+
+//------------------------------------------------------------------------------------------
+// JPEG 2000 essence
+
+// Write one or more plaintext JPEG 2000 stereoscopic codestream pairs to a plaintext ASDCP file
+// Write one or more plaintext JPEG 2000 stereoscopic codestream pairs to a ciphertext ASDCP file
+//
+Result_t
+write_JP2K_S_file(CommandOptions& Options)
+{
+ AESEncContext* Context = 0;
+ HMACContext* HMAC = 0;
+ JP2K::MXFSWriter Writer;
+ JP2K::FrameBuffer FrameBuffer(Options.fb_size);
+ JP2K::PictureDescriptor PDesc;
+ JP2K::SequenceParser ParserLeft, ParserRight;
+ byte_t IV_buf[CBC_BLOCK_SIZE];
+ Kumu::FortunaRNG RNG;
+
+ if ( Options.filenames.size() != 2 )
+ {
+ fprintf(stderr, "Two inputs are required for stereoscopic option.\n");
+ return RESULT_FAIL;
+ }
+
+ // set up essence parser
+ Result_t result = ParserLeft.OpenRead(Options.filenames.front().c_str(), Options.j2c_pedantic);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ Options.filenames.pop_front();
+ result = ParserRight.OpenRead(Options.filenames.front().c_str(), Options.j2c_pedantic);
+ }
+
+ // set up MXF writer
+ if ( ASDCP_SUCCESS(result) )
+ {
+ ParserLeft.FillPictureDescriptor(PDesc);
+ PDesc.EditRate = Options.PictureRate();
+
+ if ( Options.verbose_flag )
+ {
+ fputs("JPEG 2000 stereoscopic pictures\nPictureDescriptor:\n", stderr);
+ fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
+ JP2K::PictureDescriptorDump(PDesc);
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+ {
+ WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here
+ if ( Options.asset_id_flag )
+ memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen);
+ else
+ Kumu::GenRandomUUID(Info.AssetUUID);
+
+ if ( Options.use_smpte_labels )
+ {
+ Info.LabelSetType = LS_MXF_SMPTE;
+ fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n");
+ }
+
+ // configure encryption
+ if( Options.key_flag )
+ {
+ Kumu::GenRandomUUID(Info.ContextID);
+ Info.EncryptedEssence = true;
+
+ if ( Options.key_id_flag )
+ memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen);
+ else
+ RNG.FillRandom(Info.CryptographicKeyID, UUIDlen);
+
+ Context = new AESEncContext;
+ result = Context->InitKey(Options.key_value);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
+
+ if ( ASDCP_SUCCESS(result) && Options.write_hmac )
+ {
+ Info.UsesHMAC = true;
+ HMAC = new HMACContext;
+ result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Writer.OpenWrite(Options.out_file.c_str(), Info, PDesc);
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ ui32_t duration = 0;
+ result = ParserLeft.Reset();
+ if ( ASDCP_SUCCESS(result) ) result = ParserRight.Reset();
+
+ while ( ASDCP_SUCCESS(result) && duration++ < Options.duration )
+ {
+ result = ParserLeft.ReadFrame(FrameBuffer);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ if ( Options.verbose_flag )
+ FrameBuffer.Dump(stderr, Options.fb_dump_size);
+
+ if ( Options.encrypt_header_flag )
+ FrameBuffer.PlaintextOffset(0);
+ }
+
+ if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+ result = Writer.WriteFrame(FrameBuffer, JP2K::SP_LEFT, Context, HMAC);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = ParserRight.ReadFrame(FrameBuffer);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ if ( Options.verbose_flag )
+ FrameBuffer.Dump(stderr, Options.fb_dump_size);
+
+ if ( Options.encrypt_header_flag )
+ FrameBuffer.PlaintextOffset(0);
+ }
+
+ if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+ result = Writer.WriteFrame(FrameBuffer, JP2K::SP_RIGHT, Context, HMAC);
+ }
+
+ if ( result == RESULT_ENDOFFILE )
+ result = RESULT_OK;
+ }
+
+ if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+ result = Writer.Finalize();
+
+ return result;
+}
+
+// Write one or more plaintext JPEG 2000 codestreams to a plaintext ASDCP file
+// Write one or more plaintext JPEG 2000 codestreams to a ciphertext ASDCP file
+//
+Result_t
+write_JP2K_file(CommandOptions& Options)
+{
+ AESEncContext* Context = 0;
+ HMACContext* HMAC = 0;
+ JP2K::MXFWriter Writer;
+ JP2K::FrameBuffer FrameBuffer(Options.fb_size);
+ JP2K::PictureDescriptor PDesc;
+ JP2K::SequenceParser Parser;
+ byte_t IV_buf[CBC_BLOCK_SIZE];
+ Kumu::FortunaRNG RNG;
+
+ // set up essence parser
+ Result_t result = Parser.OpenRead(Options.filenames.front().c_str(), Options.j2c_pedantic);
+
+ // set up MXF writer
+ if ( ASDCP_SUCCESS(result) )
+ {
+ Parser.FillPictureDescriptor(PDesc);
+ PDesc.EditRate = Options.PictureRate();
+
+ if ( Options.verbose_flag )
+ {
+ fprintf(stderr, "JPEG 2000 pictures\n");
+ fputs("PictureDescriptor:\n", stderr);
+ fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
+ JP2K::PictureDescriptorDump(PDesc);
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+ {
+ WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here
+ if ( Options.asset_id_flag )
+ memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen);
+ else
+ Kumu::GenRandomUUID(Info.AssetUUID);
+
+ if ( Options.use_smpte_labels )
+ {
+ Info.LabelSetType = LS_MXF_SMPTE;
+ fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n");
+ }
+
+ // configure encryption
+ if( Options.key_flag )
+ {
+ Kumu::GenRandomUUID(Info.ContextID);
+ Info.EncryptedEssence = true;
+
+ if ( Options.key_id_flag )
+ memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen);
+ else
+ RNG.FillRandom(Info.CryptographicKeyID, UUIDlen);
+
+ Context = new AESEncContext;
+ result = Context->InitKey(Options.key_value);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
+
+ if ( ASDCP_SUCCESS(result) && Options.write_hmac )
+ {
+ Info.UsesHMAC = true;
+ HMAC = new HMACContext;
+ result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Writer.OpenWrite(Options.out_file.c_str(), Info, PDesc);
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ ui32_t duration = 0;
+ result = Parser.Reset();
+
+ while ( ASDCP_SUCCESS(result) && duration++ < Options.duration )
+ {
+ if ( duration == 1 )
+ {
+ result = Parser.ReadFrame(FrameBuffer);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ if ( Options.verbose_flag )
+ FrameBuffer.Dump(stderr, Options.fb_dump_size);
+
+ if ( Options.encrypt_header_flag )
+ FrameBuffer.PlaintextOffset(0);
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+ {
+ result = Writer.WriteFrame(FrameBuffer, Context, HMAC);
+
+ // The Writer class will forward the last block of ciphertext
+ // to the encryption context for use as the IV for the next
+ // frame. If you want to use non-sequitur IV values, un-comment
+ // the following line of code.
+ // if ( ASDCP_SUCCESS(result) && Options.key_flag )
+ // Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
+ }
+ }
+
+ if ( result == RESULT_ENDOFFILE )
+ result = RESULT_OK;
+ }
+
+ if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+ result = Writer.Finalize();
+
+ return result;
+}
+
+//------------------------------------------------------------------------------------------
+// PCM essence
+
+
+// Write one or more plaintext PCM audio streams to a plaintext ASDCP file
+// Write one or more plaintext PCM audio streams to a ciphertext ASDCP file
+//
+Result_t
+write_PCM_file(CommandOptions& Options)
+{
+ 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];
+ Kumu::FortunaRNG RNG;
+
+ // set up essence parser
+ Result_t result = Parser.OpenRead(Options.filenames, PictureRate);
+
+ // set up MXF writer
+ if ( ASDCP_SUCCESS(result) )
+ {
+ Parser.FillAudioDescriptor(ADesc);
+
+ ADesc.EditRate = PictureRate;
+ FrameBuffer.Capacity(PCM::CalcFrameBufferSize(ADesc));
+ ADesc.ChannelFormat = Options.channel_fmt;
+
+ if ( Options.use_smpte_labels && ADesc.ChannelFormat == PCM::CF_NONE)
+ {
+ fprintf(stderr, "ATTENTION! Writing SMPTE audio without ChannelAssignment property (see option -l)\n");
+ }
+
+ if ( Options.verbose_flag )
+ {
+ fprintf(stderr, "%.1fkHz PCM Audio, %s fps (%u spf)\n",
+ ADesc.AudioSamplingRate.Quotient() / 1000.0,
+ Options.szPictureRate(),
+ PCM::CalcSamplesPerFrame(ADesc));
+ fputs("AudioDescriptor:\n", stderr);
+ PCM::AudioDescriptorDump(ADesc);
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+ {
+ WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here
+ if ( Options.asset_id_flag )
+ memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen);
+ else
+ Kumu::GenRandomUUID(Info.AssetUUID);
+
+ if ( Options.use_smpte_labels )
+ {
+ Info.LabelSetType = LS_MXF_SMPTE;
+ fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n");
+ }
+
+ // configure encryption
+ if( Options.key_flag )
+ {
+ Kumu::GenRandomUUID(Info.ContextID);
+ Info.EncryptedEssence = true;
+
+ if ( Options.key_id_flag )
+ memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen);
+ else
+ RNG.FillRandom(Info.CryptographicKeyID, UUIDlen);
+
+ Context = new AESEncContext;
+ result = Context->InitKey(Options.key_value);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
+
+ if ( ASDCP_SUCCESS(result) && Options.write_hmac )
+ {
+ Info.UsesHMAC = true;
+ HMAC = new HMACContext;
+ result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Writer.OpenWrite(Options.out_file.c_str(), Info, ADesc);
+
+ if ( ASDCP_SUCCESS(result) && Options.channel_assignment.HasValue() )
+ {
+ MXF::WaveAudioDescriptor *descriptor = 0;
+ Writer.OPAtomHeader().GetMDObjectByType(DefaultSMPTEDict().ul(MDD_WaveAudioDescriptor),
+ reinterpret_cast<MXF::InterchangeObject**>(&descriptor));
+ descriptor->ChannelAssignment = Options.channel_assignment;
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ result = Parser.Reset();
+ ui32_t duration = 0;
+
+ while ( ASDCP_SUCCESS(result) && duration++ < Options.duration )
+ {
+ result = Parser.ReadFrame(FrameBuffer);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ if ( FrameBuffer.Size() != FrameBuffer.Capacity() )
+ {
+ fprintf(stderr, "WARNING: Last frame read was short, PCM input is possibly not frame aligned.\n");
+ fprintf(stderr, "Expecting %u bytes, got %u.\n", FrameBuffer.Capacity(), FrameBuffer.Size());
+ result = RESULT_ENDOFFILE;
+ continue;
+ }
+
+ if ( Options.verbose_flag )
+ FrameBuffer.Dump(stderr, Options.fb_dump_size);
+
+ if ( ! Options.no_write_flag )
+ {
+ result = Writer.WriteFrame(FrameBuffer, Context, HMAC);
+
+ // The Writer class will forward the last block of ciphertext
+ // to the encryption context for use as the IV for the next
+ // frame. If you want to use non-sequitur IV values, un-comment
+ // the following line of code.
+ // if ( ASDCP_SUCCESS(result) && Options.key_flag )
+ // Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
+ }
+ }
+ }
+
+ if ( result == RESULT_ENDOFFILE )
+ result = RESULT_OK;
+ }
+
+ if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+ result = Writer.Finalize();
+
+ return result;
+}
+
+
+//------------------------------------------------------------------------------------------
+// TimedText essence
+
+
+// Write one or more plaintext timed text streams to a plaintext ASDCP file
+// Write one or more plaintext timed text streams to a ciphertext ASDCP file
+//
+Result_t
+write_timed_text_file(CommandOptions& Options)
+{
+ AESEncContext* Context = 0;
+ HMACContext* HMAC = 0;
+ TimedText::DCSubtitleParser Parser;
+ TimedText::MXFWriter Writer;
+ TimedText::FrameBuffer FrameBuffer;
+ TimedText::TimedTextDescriptor TDesc;
+ byte_t IV_buf[CBC_BLOCK_SIZE];
+ Kumu::FortunaRNG RNG;
+
+ // set up essence parser
+ Result_t result = Parser.OpenRead(Options.filenames.front().c_str());
+
+ // set up MXF writer
+ if ( ASDCP_SUCCESS(result) )
+ {
+ Parser.FillTimedTextDescriptor(TDesc);
+ FrameBuffer.Capacity(Options.fb_size);
+
+ if ( Options.verbose_flag )
+ {
+ fputs("D-Cinema Timed-Text Descriptor:\n", stderr);
+ TimedText::DescriptorDump(TDesc);
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+ {
+ WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here
+ if ( Options.asset_id_flag )
+ memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen);
+ else
+ Kumu::GenRandomUUID(Info.AssetUUID);
+
+ if ( Options.use_smpte_labels )
+ {
+ Info.LabelSetType = LS_MXF_SMPTE;
+ fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n");
+ }
+
+ // configure encryption
+ if( Options.key_flag )
+ {
+ Kumu::GenRandomUUID(Info.ContextID);
+ Info.EncryptedEssence = true;
+
+ if ( Options.key_id_flag )
+ memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen);
+ else
+ RNG.FillRandom(Info.CryptographicKeyID, UUIDlen);
+
+ Context = new AESEncContext;
+ result = Context->InitKey(Options.key_value);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
+
+ if ( ASDCP_SUCCESS(result) && Options.write_hmac )
+ {
+ Info.UsesHMAC = true;
+ HMAC = new HMACContext;
+ result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Writer.OpenWrite(Options.out_file.c_str(), Info, TDesc);
+ }
+
+ if ( ASDCP_FAILURE(result) )
+ return result;
+
+ std::string XMLDoc;
+ TimedText::ResourceList_t::const_iterator ri;
+
+ result = Parser.ReadTimedTextResource(XMLDoc);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Writer.WriteTimedTextResource(XMLDoc, Context, HMAC);
+
+ for ( ri = TDesc.ResourceList.begin() ; ri != TDesc.ResourceList.end() && ASDCP_SUCCESS(result); ri++ )
+ {
+ result = Parser.ReadAncillaryResource((*ri).ResourceID, FrameBuffer);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ if ( Options.verbose_flag )
+ FrameBuffer.Dump(stderr, Options.fb_dump_size);
+
+ if ( ! Options.no_write_flag )
+ {
+ result = Writer.WriteAncillaryResource(FrameBuffer, Context, HMAC);
+
+ // The Writer class will forward the last block of ciphertext
+ // to the encryption context for use as the IV for the next
+ // frame. If you want to use non-sequitur IV values, un-comment
+ // the following line of code.
+ // if ( ASDCP_SUCCESS(result) && Options.key_flag )
+ // Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
+ }
+ }
+
+ if ( result == RESULT_ENDOFFILE )
+ result = RESULT_OK;
+ }
+
+ if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+ result = Writer.Finalize();
+
+ return result;
+}
+
+//
+int
+main(int argc, const char** argv)
+{
+ Result_t result = RESULT_OK;
+ char str_buf[64];
+ CommandOptions Options(argc, argv);
+
+ if ( Options.version_flag )
+ banner();
+
+ if ( Options.help_flag )
+ usage();
+
+ if ( Options.version_flag || Options.help_flag )
+ return 0;
+
+ if ( Options.error_flag )
+ {
+ fprintf(stderr, "There was a problem. Type %s -h for help.\n", PROGRAM_NAME);
+ return 3;
+ }
+
+ if ( Options.show_ul_values )
+ {
+ if ( Options.use_smpte_labels )
+ DefaultSMPTEDict().Dump(stdout);
+ else
+ DefaultInteropDict().Dump(stdout);
+ }
+
+ EssenceType_t EssenceType;
+ result = ASDCP::RawEssenceType(Options.filenames.front().c_str(), EssenceType);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ switch ( EssenceType )
+ {
+ case ESS_MPEG2_VES:
+ result = write_MPEG2_file(Options);
+ break;
+
+ case ESS_JPEG_2000:
+ if ( Options.stereo_image_flag )
+ {
+ result = write_JP2K_S_file(Options);
+ }
+ else
+ {
+ result = write_JP2K_file(Options);
+ }
+ break;
+
+ case ESS_PCM_24b_48k:
+ case ESS_PCM_24b_96k:
+ result = write_PCM_file(Options);
+ break;
+
+ case ESS_TIMED_TEXT:
+ result = write_timed_text_file(Options);
+ break;
+
+ default:
+ fprintf(stderr, "%s: Unknown file type, not ASDCP-compatible essence.\n",
+ Options.filenames.front().c_str());
+ return 5;
+ }
+ }
+
+ if ( ASDCP_FAILURE(result) )
+ {
+ fputs("Program stopped on error.\n", stderr);
+
+ if ( result != RESULT_FAIL )
+ {
+ fputs(result, stderr);
+ fputc('\n', stderr);
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+
+//
+// end asdcp-wrap.cpp
+//
diff --git a/asdcplib/src/blackwave.cpp b/asdcplib/src/blackwave.cpp
new file mode 100644
index 0000000..8498655
--- /dev/null
+++ b/asdcplib/src/blackwave.cpp
@@ -0,0 +1,245 @@
+/*
+Copyright (c) 2005-2009, 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: blackwave.cpp,v 1.10 2010/02/16 18:40:57 jhurst Exp $
+ \brief Black WAV file generator
+*/
+
+#include "Wav.h"
+#include <assert.h>
+
+using namespace ASDCP;
+
+//------------------------------------------------------------------------------------------
+//
+// command line option parser class
+
+static const char* PROGRAM_NAME = "blackwave"; // 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-2009 John Hurst\n\n\
+%s 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",
+ PROGRAM_NAME, ASDCP::Version(), PROGRAM_NAME, PROGRAM_NAME);
+}
+
+//
+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", PROGRAM_NAME);
+}
+
+//
+//
+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.EditRate = Rational(24,1);
+ ADesc.AudioSamplingRate = ASDCP::SampleRate_48k;
+ ADesc.Locked = 0;
+ ADesc.ChannelCount = 1;
+ ADesc.QuantizationBits = 24;
+ ADesc.BlockAlign = 3;
+ ADesc.AvgBps = 14400;
+ 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 ( Options.verbose_flag )
+ {
+ fprintf(stderr, "48Khz PCM Audio, %s fps (%u 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/asdcplib/src/fips-186-rng-test.cpp b/asdcplib/src/fips-186-rng-test.cpp
new file mode 100755
index 0000000..aef3b87
--- /dev/null
+++ b/asdcplib/src/fips-186-rng-test.cpp
@@ -0,0 +1,96 @@
+/*
+Copyright (c) 2007-2009, 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 fips-186-rng-test.cpp
+ \version $Id: fips-186-rng-test.cpp,v 1.4 2009/10/08 15:58:16 jhurst Exp $
+ \brief FIPS 186-2 RNG test wrapper
+*/
+
+#include <KM_util.h>
+#include <KM_prng.h>
+#include <openssl/sha.h>
+
+using namespace Kumu;
+
+//
+int
+main(int argc, const char** argv)
+{
+ if ( argc != 5 )
+ {
+ fprintf(stderr, "USAGE: fips-186-test <rounds> <b> <XKey-hex> <X-hex>\n");
+ return 2;
+ }
+
+ ui32_t const X_buf_len = 1024;
+ byte_t XKey_buf[X_buf_len];
+ byte_t X_test_buf[X_buf_len];
+ ui32_t char_count;
+
+ char* end = 0;
+ ui32_t rounds = strtol(argv[1], &end, 10);
+ ui32_t B = strtol(argv[2], &end, 10) / 8;
+
+ if ( hex2bin(argv[3], XKey_buf, X_buf_len, &char_count) != 0 )
+ {
+ fprintf(stderr, "Error parsing <XKey-hex> value\n");
+ return 3;
+ }
+
+ if ( char_count != B )
+ {
+ fprintf(stderr, "Incorrect length for <XKey-hex> value (expecting %d decoded bytes)\n", B);
+ return 3;
+ }
+
+ if ( hex2bin(argv[4], X_test_buf, X_buf_len, &char_count) != 0 )
+ {
+ fprintf(stderr, "Error parsing <X-hex> value\n");
+ return 3;
+ }
+
+ ui32_t const meg = 1024*1024;
+ ui32_t out_size = char_count;
+ byte_t X_buf[meg];
+ ui32_t fill_size = rounds * 20;
+ assert(fill_size < meg);
+ Gen_FIPS_186_Value(XKey_buf, B, X_buf, fill_size);
+
+ byte_t* test_key = &X_buf[fill_size - out_size];
+
+ if ( memcmp(test_key, X_test_buf, char_count) != 0 )
+ {
+ fprintf(stderr, "Test vector value does not match:\n");
+ hexdump(test_key, char_count);
+ return 4;
+ }
+
+ return 0;
+}
+
+//
+// end rng.cpp
+//
diff --git a/asdcplib/src/fips-186-test-harness.pl b/asdcplib/src/fips-186-test-harness.pl
new file mode 100755
index 0000000..1fb458a
--- /dev/null
+++ b/asdcplib/src/fips-186-test-harness.pl
@@ -0,0 +1,1318 @@
+#!/usr/bin/env perl
+#
+# Copyright (c) 2003-2009, 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.
+#
+#
+#
+# $Id: fips-186-test-harness.pl,v 1.4 2009/10/08 15:58:16 jhurst Exp $
+#
+
+
+
+use strict;
+my $rng_prog = $ARGV[0];
+
+die "Expecting RNG program name as argument" unless ( -x $rng_prog );
+
+my $test_count = 0;
+my $rounds = 2;
+my $i = 0;
+
+while ( my $line = <DATA> ) {
+ if ( $line =~ /^<MCT>/ ) {
+ $rounds = 10000;
+ next;
+ }
+
+# next if ($rounds == 2);
+
+ if ( $line =~ /^b = (\d+)/ ) {
+ my $vlen = $1;
+
+ my $XKey = <DATA>;
+ die if ( $XKey !~ /^XKey = (\w+)/ );
+ $XKey = $1;
+
+ my $XSeed = <DATA>;
+
+ my $Xval = <DATA>;
+ die if ( $Xval !~ /^X = (\w+)/ );
+ $Xval = $1;
+
+ system("$rng_prog $rounds $vlen $XKey $Xval");
+ my $ret = $?;
+ die "\nTest vector failure at test $test_count: r=$rounds b=$vlen k=$XKey v=$Xval ($ret)\n" if ( $ret != 0 );
+ print STDERR '.';
+ $test_count++;
+ }
+}
+
+print STDERR "\nfound $test_count test cases\n"
+
+
+# FIPS186_VSTGEN_XChange_Sha1.txt
+__DATA__
+[Xchange - SHA1]
+
+COUNT = 0
+b = 160
+XKey = 8000000000000000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = da39a3ee5e6b4b0d3255bfef95601890afd8070992d5f201dc6e0e4efff2fabad419d4bf7e41fa58
+
+COUNT = 1
+b = 160
+XKey = c000000000000000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = fccbeb651889c0c4836c2f94ebf67bbe59af0ef8f21ae5a3ff0c67ed1c578a6f1223fd2130f5638a
+
+COUNT = 2
+b = 160
+XKey = e000000000000000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = b0f74533c0072c2c99d241a4c5f4c73bc396fdf247dcb245b337d3cf9531142a8f2a1d132a3b72c1
+
+COUNT = 3
+b = 160
+XKey = f000000000000000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 3f87039d81ff007b02d2a4cbf1eb28be42ad9fc3e793c4c4403c8183b7b063b1ff2a476c86a29150
+
+COUNT = 4
+b = 160
+XKey = f800000000000000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 76aae1571999ccf26fc1d8050da716fcd1d4601ed4032c82f7e5331aecca066455117e6c8eec204e
+
+COUNT = 5
+b = 160
+XKey = fc00000000000000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 28de1e50400afdd50328f7d165a6664989fb8a27d952a36ea896bfcd1e3135c544194985fd436b69
+
+COUNT = 6
+b = 160
+XKey = fe00000000000000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = faf212c7824683ba4c58ea4de177714250bbbaa1b9bf77a7ccf493955f00dff8902fd8fd0af446d9
+
+COUNT = 7
+b = 160
+XKey = ff00000000000000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 3c48a3452a597b40b448ee99eef36221b91a9fc98cfc3f73c492cd2dcb4c8512d7ce16198f41d9e0
+
+COUNT = 8
+b = 160
+XKey = ff80000000000000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 02db90873dafeddd6b909280cb08ad51b7ac97782aafa0e44b2ecfbe98648fbdc70388e6c4bc138e
+
+COUNT = 9
+b = 160
+XKey = ffc0000000000000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 7dcfc01746dede2322bad50d179a069a7808ab2272cd1b8a0fb3b8504ed443ce30a109a2af82abf5
+
+COUNT = 10
+b = 160
+XKey = ffe0000000000000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 290b3a3b277cccc4bc9893835b017bad8c0cf5be20ec5fbe6ca4174fbcacf1f2ce325270974e2782
+
+COUNT = 11
+b = 160
+XKey = fff0000000000000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = dc8397bfd2baad0409746d9e4c3bb0ce32b981b09b7ed6dafaa1d11f4a063d55c315572796f92a3a
+
+COUNT = 12
+b = 160
+XKey = fff8000000000000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = a422b968f8864f33e73a7d248ba5e664d312796cb229e54cc63a7429da530f4df0732d2cb1f17e66
+
+COUNT = 13
+b = 160
+XKey = fffc000000000000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = dafa5baadb51bc19fa716e066ec6cfb476cf4d66ea2e3a41c0d192080efc71bbaa74e15f3671333c
+
+COUNT = 14
+b = 160
+XKey = fffe000000000000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = f4107d1d55ce2f2eea18e62f36e67c6cb834072989882745f96d2b055d73aa511a72930862816a3c
+
+COUNT = 15
+b = 160
+XKey = ffff000000000000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = bec44e48afa08c1ddd4d003d731eb3fa92ccfba7a22e2b34133693c520647cbdb5c67662400a78ab
+
+COUNT = 16
+b = 160
+XKey = ffff800000000000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 4d74c089c13a33eb2870dd2c57baa69c8d13d9bdd086c5ed1eee776e1b405fed8187ec338ff2e404
+
+COUNT = 17
+b = 160
+XKey = ffffc00000000000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 35fd5500ed91ea2750740be274fa9819997c246d6e4568f78f0de506c7eb89a82cfd7b7a38d89752
+
+COUNT = 18
+b = 160
+XKey = ffffe00000000000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = d7f5a4bf869c4dda9967e10e15e45d713ad616e7135e579e8feec4c3295118d0f2b102ce44746d2f
+
+COUNT = 19
+b = 160
+XKey = fffff00000000000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = d875ec45e85c07e11996b56fee6e7efab3f152c36092d82e4f560c907b286da58325a61900cbe98b
+
+COUNT = 20
+b = 160
+XKey = fffff80000000000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 6485831589eee689e84dcb9af46aa3a124d85657ba82f2ad8cf01bcbbc75ba775366b535d7a47896
+
+COUNT = 21
+b = 160
+XKey = fffffc0000000000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 17e0dd120fa8cb7a16eb17228270e338f37b158ea22c0c486d4b1992d6d5f20636ca838271805440
+
+COUNT = 22
+b = 160
+XKey = fffffe0000000000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 919d8d62befb49c68520c5a458b00d0577033f47b6ac4fe8b8abf3d9991696bc6fe213960c645a42
+
+COUNT = 23
+b = 160
+XKey = ffffff0000000000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 56e2e117e2c73527e3971c9d3bffb5379cef75d157f93aff7b051dd7fdd8611666689a3e3526c0ce
+
+COUNT = 24
+b = 160
+XKey = ffffff8000000000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = fcf9e6f9bfc8cf6d46c760ed213331594d95a895c47beeeaa4b7129ca8c4b249e477a46af5e16ac9
+
+COUNT = 25
+b = 160
+XKey = ffffffc000000000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = e01170df33061c4cb1d123fb0a9e186af468a87696ea8e48f5f1697e51595f58d1e6e7e3440f1407
+
+COUNT = 26
+b = 160
+XKey = ffffffe000000000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 936940fd12fc688855f8a6d0be2722e4294bb0d0af94aa51b0a2f0d93f080daeaf9bfcd8f4c01e82
+
+COUNT = 27
+b = 160
+XKey = fffffff000000000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 6e0abd8f57f876296a237fc17b2181a5bbe0d6e82a7a36d59c9a68e13e40e9e8136d4c0ccf0acd6b
+
+COUNT = 28
+b = 160
+XKey = fffffff800000000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = dd7de50650bbd6b86e88eba9ea428f0a2b340cc0a361f0053cd1447a4c9d4d5e2d42f114d033eafe
+
+COUNT = 29
+b = 160
+XKey = fffffffc00000000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 52bb6338b2b72fd29167b40caa34123232f770ab7808cfe6f3cb148502d89ff5a80b4ac0778faaeb
+
+COUNT = 30
+b = 160
+XKey = fffffffe00000000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = ae017f7b0e253701216941e1c9d7821f077bfdc3bcd4a02603a2d63d1849072801d78482fa84dc50
+
+COUNT = 31
+b = 160
+XKey = ffffffff00000000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 6bca6679907d54bd1254ee87ded30591305d436c2f552f28f4ec1f7fbac29a25c3dcb7e630cc41e1
+
+COUNT = 32
+b = 160
+XKey = ffffffff80000000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 72253fe10d13536bc715464d28ae70cd8dcea9451e6140ee837caddb81de309497e7f95d0fcf09d6
+
+COUNT = 33
+b = 160
+XKey = ffffffffc0000000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 5784b0627abe62043f7b9fb08e54eaf067c7c6a8f8dbcae34dcd15a7f9bf9b52fef7ff90b792a8f8
+
+COUNT = 34
+b = 160
+XKey = ffffffffe0000000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 815abfe389de4cb500ea789dd04042f81817fcae3d7a9fbb50b251676653ef671eb29f47cce6ff65
+
+COUNT = 35
+b = 160
+XKey = fffffffff0000000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 3152b9db05fb216edc61782d254a38533988200d02b72cf15cd4404f7e9f4f823544e693889ea3ca
+
+COUNT = 36
+b = 160
+XKey = fffffffff8000000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 1158d881597e94db9cdfb79997a571740ae24386dcb0cbafe2e20d2b6cca811a98dc0ebb65028296
+
+COUNT = 37
+b = 160
+XKey = fffffffffc000000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 7a252c33152e04374a51c36a8ff386a9125983993d0bfaa073738384128969404434b3ad3badf8dc
+
+COUNT = 38
+b = 160
+XKey = fffffffffe000000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = f22ee43a5dafca77e87b0d2eb6fe202ce0fcc83da391d6a9ca5cd6865744256866d09531ccd9c1a9
+
+COUNT = 39
+b = 160
+XKey = ffffffffff000000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = ac6fffbb332e9e733de0f3a85404e22d0c9c53cfc2226a3cb08df3747e541904d9909f05d5932cee
+
+COUNT = 40
+b = 160
+XKey = ffffffffff800000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 909649b02d9bbf2da624a40a4c5dcec233e58f41ffc0d1b8c0810a1cce89f25cebf40d576f27b808
+
+COUNT = 41
+b = 160
+XKey = ffffffffffc00000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 7328500ca54c4fb9eddf8e3ecf2e851b0f8821ac5f1823e77dd73e8cb2e4727ba9e7f2de71737c0c
+
+COUNT = 42
+b = 160
+XKey = ffffffffffe00000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 2bf06c06d4c1c11276718320c886c74dabb7fd92ccf743e2023909a6d33ff8a42a56f8879804219e
+
+COUNT = 43
+b = 160
+XKey = fffffffffff00000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = a812af3c2f0ee5615688b966b8885e75a7c76be5e5c9518347f6f23475ed601f556f50a253f64463
+
+COUNT = 44
+b = 160
+XKey = fffffffffff80000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = d9e4f7719a31e05bc6f07779b4eed313c94346d6a1485c5847f0e7ed5dbd8bf5c4e5ea847207739b
+
+COUNT = 45
+b = 160
+XKey = fffffffffffc0000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 4b3f3951c0eac34ee8562fb4b7f2d5e7787b0ba705ba474fc13ec9d99f7877ad4b934d7111ee1ccc
+
+COUNT = 46
+b = 160
+XKey = fffffffffffe0000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 41212672a59e2f50dc0e55107df6fe6e1a6f0806012517058efa8678e1b5709579aeff58d4523a1f
+
+COUNT = 47
+b = 160
+XKey = ffffffffffff0000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = d279d878c380f846f5790f32881f689d3463ef4f577c7bedb83dcdae06aeefe0acf28bc6abc398d6
+
+COUNT = 48
+b = 160
+XKey = ffffffffffff8000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = cc2adbd3e9389f19a44bc74585c926de5383f0aaf7591019deffb70cf2106934a09b7c3bb7d36a57
+
+COUNT = 49
+b = 160
+XKey = ffffffffffffc000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = aab87ca3ecfd8b84cf2a804d7dfd79f181657c6660e1cffaf9bce87899064b9ef85f4d4edd5b9c97
+
+COUNT = 50
+b = 160
+XKey = ffffffffffffe000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = d05170a4077035b188e903decf7cd0c8d738c65ebf3d345962da2e10cc480a0e6dac962e784437ea
+
+COUNT = 51
+b = 160
+XKey = fffffffffffff000000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = df094f91e6e721f7f5c8920cc8699d50d6d2e26677e0595f7ed1fbec275013d9eaec9f8ff0192eba
+
+COUNT = 52
+b = 160
+XKey = fffffffffffff800000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 840b7bf475412aec0ed426bfc95dbff1dfb3c01993744a1cd5cd57ee1c72157c4576f6fc868e4d67
+
+COUNT = 53
+b = 160
+XKey = fffffffffffffc00000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 081c963bfa542131e47a6f824702c81d036170c059d320a7347371e92e8019b0a5a6b674626d1e91
+
+COUNT = 54
+b = 160
+XKey = fffffffffffffe00000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 68f04715ea256ee6e48c02d2916a1488d40ec866e1d6a5add4abaef3b8323e62b6693514f14c3db7
+
+COUNT = 55
+b = 160
+XKey = ffffffffffffff00000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = d3d213d73d9738b9179949641a17cd7a2e4866623e01941575430a978c5edf326cd5215b3bd74e30
+
+COUNT = 56
+b = 160
+XKey = ffffffffffffff80000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 68c5582035c3644249e3412eb70336617bc4a593850312fed7a20d25115d1f001f9abbfd118c7753
+
+COUNT = 57
+b = 160
+XKey = ffffffffffffffc0000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 12d6de348e76dd0f6380b13bd88d43ea2d5b7c443d794a3fb7758590a1dfa5f34cd9dfff104cbbf5
+
+COUNT = 58
+b = 160
+XKey = ffffffffffffffe0000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = a9f1c1cad88416a12c6108de1971198fbd6057f3efe49495894a4e2a69a5ea8714cb3a57b37b93ac
+
+COUNT = 59
+b = 160
+XKey = fffffffffffffff0000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 789e072cc3185a627d92945339bb1950e915e989dc1490d2b59a054ca1c20017c1bee4aaf9757b5f
+
+COUNT = 60
+b = 160
+XKey = fffffffffffffff8000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 5509de87994a508680b545fa58aab69cb142f2badf1021645e7430d02cdf6111b0afe66cb7678af0
+
+COUNT = 61
+b = 160
+XKey = fffffffffffffffc000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 802cae54caf47f45d5ab352f10cd47774a5895bf29b60f2bb7d20da67d2ee5943de44ddda445367c
+
+COUNT = 62
+b = 160
+XKey = fffffffffffffffe000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 18001b828028eb44228fa7421cceaba5e12b4feb1ad7c57483d64c39d5d99f737002be9f13162c89
+
+COUNT = 63
+b = 160
+XKey = ffffffffffffffff000000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = cb8128e1cbc093306b23da2814d1265dd0d2f9774dd164f011e4fedc044c308b8800057c18ab5a4e
+
+COUNT = 64
+b = 160
+XKey = ffffffffffffffff800000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = d7aec22fb3704dd2ddc721c4d715630a400a15fd192cd7e3627387b47b58fc39d5be4064822b3aad
+
+COUNT = 65
+b = 160
+XKey = ffffffffffffffffc00000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 45e7933ada2666ca8cd76e4778f290bf41378c217e0286bb1e95ee2f2f7c1eb698248e821b4a0656
+
+COUNT = 66
+b = 160
+XKey = ffffffffffffffffe00000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 9eba05157ea9936e6521eb5807b0026c8542d607ea8bce39861123448752f40b4d2fc456d53c34f4
+
+COUNT = 67
+b = 160
+XKey = fffffffffffffffff00000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 07b692581741a1e7ee37425c524b1d82662e46b155889af1b444290e586edba269f0f38042ebe9b5
+
+COUNT = 68
+b = 160
+XKey = fffffffffffffffff80000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = c71b439ca40ac57e1ec5d9ad4383ee8b61d370b5807590d7fdbfdca963f1b1d4b29092cbb598d1f6
+
+COUNT = 69
+b = 160
+XKey = fffffffffffffffffc0000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 3b49c50cd7d319774f91275892f751d1c3bc50a38fb3ee13955c718d67c917307a8888dbd1f55339
+
+COUNT = 70
+b = 160
+XKey = fffffffffffffffffe0000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = aece9cdcd70b4f65d63c9c2d10a612ac4f24725d0111932147bddee3436d37d15b7354240685bdee
+
+COUNT = 71
+b = 160
+XKey = ffffffffffffffffff0000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = ac4b24ba0c7976303566e2a0a51959849958db04a001d82153acd09e33ee71efebe458c4f9543119
+
+COUNT = 72
+b = 160
+XKey = ffffffffffffffffff8000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 495660a402a40de3f1375ae40e076c7c2aa044287d9930572bb6b13ce419f22a6bf9ae63fd603b3a
+
+COUNT = 73
+b = 160
+XKey = ffffffffffffffffffc000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = d985a58306469ecc0651d039ac8610fc9e71ccd4cdf9c6d1715c4197850e11e39bd27e2ec49801d4
+
+COUNT = 74
+b = 160
+XKey = ffffffffffffffffffe000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 42aa31de6a5ce807b14c2e3ad91d91589119da04103cfc7c94860eebe6b4bcae6ba069033c0366ad
+
+COUNT = 75
+b = 160
+XKey = fffffffffffffffffff000000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 6e8cb43e720c5533ba5fc017c4df8c6f278f2dad63ae8154a2720e077cf423b995c835b068e27fa5
+
+COUNT = 76
+b = 160
+XKey = fffffffffffffffffff800000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = d038ba69be6edad3cb10e5ef9638214e4da3aa23571c1fd2ce9d56b294ab48738339876367af37c1
+
+COUNT = 77
+b = 160
+XKey = fffffffffffffffffffc00000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = d0404a3aa63f64da9dd9ac380b6610a7a49c0e342f98bdc235fb6055ff3d786602bf62cdd8add78e
+
+COUNT = 78
+b = 160
+XKey = fffffffffffffffffffe00000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = be00ae42cbaf9b94b803549533607a0f69154c0008d2de3b583b2616c74b36566ae767ff34b86654
+
+COUNT = 79
+b = 160
+XKey = ffffffffffffffffffff00000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 2f02675d18bc26297f4368b634e1ebdf2c5ab677e84f33d437481adebdc5e7bfc556fe6f45072c6a
+
+COUNT = 80
+b = 160
+XKey = ffffffffffffffffffff80000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = f633f34bb5166cebfecde2295ce7648dec442ff159765c7a86332beb46f7842133f5a3ed6960a3f0
+
+COUNT = 81
+b = 160
+XKey = ffffffffffffffffffffc0000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = fdd3881997edbedfe956fc8a013afd072a73c70bbb31390a0fd756b7337863b43fd820ae4e257180
+
+COUNT = 82
+b = 160
+XKey = ffffffffffffffffffffe0000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 7d5b95d8bd5db5df0b91df0edb1f287118a57d459b94a90a6e1a0524fd141be752e802c5c6f5fa61
+
+COUNT = 83
+b = 160
+XKey = fffffffffffffffffffff0000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = bf8d570e5f9299df9dd93db0c809ff6bfbb35481e2283705a9676727a84d02e2b8883828a05f1bdc
+
+COUNT = 84
+b = 160
+XKey = fffffffffffffffffffff8000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = bdcabf104dfec16b2a484df9596abda1d4b72afcf8cee6bf749c4bc0c124df9b29b11785d487d54f
+
+COUNT = 85
+b = 160
+XKey = fffffffffffffffffffffc000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 79d4b08aa8efc652f2f81a5f58d1af456806686fe495d25db5ed36dd034d3e71eb0fcb35d7b0b903
+
+COUNT = 86
+b = 160
+XKey = fffffffffffffffffffffe000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = a8d1aef1f8cf16a0c6dbe31542ca390e77bc5be962c1e7cbfb0ef37196b95236b8e105b96da055de
+
+COUNT = 87
+b = 160
+XKey = ffffffffffffffffffffff000000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 13df68dd0de319394623acd11181384072c2b120a6dc9f090faeaa03484d0862e50cbd2502d963c6
+
+COUNT = 88
+b = 160
+XKey = ffffffffffffffffffffff800000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 07cc9dbedb074f9ecce0e3ea54f59d943f57c4fa4909c59e7b2c513f77d4b7c0c30d10bb77e0617f
+
+COUNT = 89
+b = 160
+XKey = ffffffffffffffffffffffc00000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 6b5da347070676406474673f0ca9ca10624f01d965cbdf2975442fc134c0c50ef1bf2ae000ec67a5
+
+COUNT = 90
+b = 160
+XKey = ffffffffffffffffffffffe00000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 3dec2b91ba61d60714bba70628413436e238fb0ca9178e7b50ffcadeeb1c3c72536b90ea2d2ce965
+
+COUNT = 91
+b = 160
+XKey = fffffffffffffffffffffff00000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = f69d9a2891892b60cfeb504f17fb6ee0a30cbee1cb27802af04191e8386e7a0f612f2bd4d6665f3b
+
+COUNT = 92
+b = 160
+XKey = fffffffffffffffffffffff80000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 4f78f5e39217be13e1d57aa3f4d55e5955a8ef5c5a98e8e02fb7807b4a885c2de8f64bbb42390302
+
+COUNT = 93
+b = 160
+XKey = fffffffffffffffffffffffc0000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = df5c9790c61dde09a272c5c5f5c78e867b10a2e0e18ed67114e130c3af1442d3fe13c53e3072ac60
+
+COUNT = 94
+b = 160
+XKey = fffffffffffffffffffffffe0000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = ce06588dccb3d9b8fd40076e57c29bc22d90bd4d56676d8dad83d750be12da19b3a7fea0dde986f4
+
+COUNT = 95
+b = 160
+XKey = ffffffffffffffffffffffff0000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = afca72d4d8eeac89452c2d8240611385de4dd1d05d9db6a1b1d0e7df7fa49075c44fd3df0a8f4797
+
+COUNT = 96
+b = 160
+XKey = ffffffffffffffffffffffff8000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 65d921596731fb52bc87a79d8996475530015bbd3fb24e206cffb17f8cb92a20cbb434cc13aafbd4
+
+COUNT = 97
+b = 160
+XKey = ffffffffffffffffffffffffc000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 3ff9c54cc76869bd329ea6fe65935e036900e82df945466a0875379c065121fc5e5620a51adb48bb
+
+COUNT = 98
+b = 160
+XKey = ffffffffffffffffffffffffe000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = c30a129ddf99ca2ddf8aa065607facbcf86b3b9382cf694fdcb2f55321a52c87c7ab0d701fcf0ab9
+
+COUNT = 99
+b = 160
+XKey = fffffffffffffffffffffffff000000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = c81cb8b066027949826b69b919960c0096e0e9f2eeb9e53d2acbd3b40a92470a5665d31582a38b93
+
+COUNT = 100
+b = 160
+XKey = fffffffffffffffffffffffff800000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = eba40737de37c4fb7f9931fd455bc6c32a184dd44f524c7dd9681ba0b995df8d7fe461c5df6c3c2b
+
+COUNT = 101
+b = 160
+XKey = fffffffffffffffffffffffffc00000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 4d4d5aa335b046fcdf9ea069e938f9b662f22286a6a9146296843a0579c5ce81f338517cd7baef4e
+
+COUNT = 102
+b = 160
+XKey = fffffffffffffffffffffffffe00000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 885b0b6662bc6a1315020e801f4b0400e202fae240441a93e3aa4117745ecb7cd870a77b5fec12f6
+
+COUNT = 103
+b = 160
+XKey = ffffffffffffffffffffffffff00000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = d27612b331bf2ebd86c6b018020a284d58dbbd8a90216cdc7d5292c8d69361d19bdfe54da83ff0a8
+
+COUNT = 104
+b = 160
+XKey = ffffffffffffffffffffffffff80000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 77fc40d4b1690236b746fdca741541467344caa0715ce6d2abeb8288a3913499e82425717a013d5c
+
+COUNT = 105
+b = 160
+XKey = ffffffffffffffffffffffffffc0000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = ff32e03b70d7bd9786dc0515cfca1e0f94bee4f22cceead4066accae3d9ee320aeca667367a84acb
+
+COUNT = 106
+b = 160
+XKey = ffffffffffffffffffffffffffe0000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = e66d2df35bfd3e697069825d96d9d60d113c032f2f772136624475e024f18c5e14b3172155307af3
+
+COUNT = 107
+b = 160
+XKey = fffffffffffffffffffffffffff0000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 1c903f71d11d598fe1bf4a79e98b7e7d5d1cb3f700dd7a1dd476ae9bb3d49ec940f56ea03a22659c
+
+COUNT = 108
+b = 160
+XKey = fffffffffffffffffffffffffff8000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 074c8a6168c9c7df3a87bc57f6eb23251ba7052049ac327af36b12fdbaa4b4b055bc8d680cb8d3f9
+
+COUNT = 109
+b = 160
+XKey = fffffffffffffffffffffffffffc000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 8534b835c335c2866bf8e5ddf686c6d4a2a1d4802454314f1e1eedad06355a3c6b39b44c3aa7ecc9
+
+COUNT = 110
+b = 160
+XKey = fffffffffffffffffffffffffffe000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 6adcebdf6badfdbaf3675ae97d7da3da4d4a93122c7da68c74f19d3404f143e8c8f7cfb74bbd6415
+
+COUNT = 111
+b = 160
+XKey = ffffffffffffffffffffffffffff000000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 8fc7605166aeed6c1d9795bb5aff9a44c6aba7dfca1b0d8b101c78fdc7e3bfd65f4076ca600c1288
+
+COUNT = 112
+b = 160
+XKey = ffffffffffffffffffffffffffff800000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 52798b5b8df1b2bfa466713b346961906c210b0bbc40e5b7a62bb4c70ae41a9447b224537ddd14de
+
+COUNT = 113
+b = 160
+XKey = ffffffffffffffffffffffffffffc00000000000
+XSeed = 0000000000000000000000000000000000000000
+X = a0f58dafbc95601dd59de0dd47cadfe1ea34e9925ba468099308a9450fb52c97db57b4214e58bdce
+
+COUNT = 114
+b = 160
+XKey = ffffffffffffffffffffffffffffe00000000000
+XSeed = 0000000000000000000000000000000000000000
+X = e19df3f756485974d6381865503eaba161c90d0cecfa163e27fffd5248d31f5bb7a1b92a862b3ad3
+
+COUNT = 115
+b = 160
+XKey = fffffffffffffffffffffffffffff00000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 35c284d7dcb6d6623ea34be1371db0b325b3920564e55828a288be312d610666af76f44254964077
+
+COUNT = 116
+b = 160
+XKey = fffffffffffffffffffffffffffff80000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 989ce65ed122d1405de7a57664f7ac705cb9b5aaed3b6f05e227229c23c575c4b18e88335eb2c81a
+
+COUNT = 117
+b = 160
+XKey = fffffffffffffffffffffffffffffc0000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 05d73bc99c91150aa39840544b5bd3b46251bbced56f79000c63f0166d0ca62ed4b9cd3b17afc68b
+
+COUNT = 118
+b = 160
+XKey = fffffffffffffffffffffffffffffe0000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 758355389548decb4d674f76b286cdfc71f85b7169be18b6b7ac546847056f2a9c9f096dffb27afc
+
+COUNT = 119
+b = 160
+XKey = ffffffffffffffffffffffffffffff0000000000
+XSeed = 0000000000000000000000000000000000000000
+X = da754c2f1101e44c12a64ce93d7e038531c114df55ce1b0ef8d213ad6f2f43d210e91e1a93f655bf
+
+COUNT = 120
+b = 160
+XKey = ffffffffffffffffffffffffffffff8000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 2ff3dc5be596d44376eba1b07c8a0048f66d2782b0a1340d919ce12b5dbf2f36c7ce543c55a24dea
+
+COUNT = 121
+b = 160
+XKey = ffffffffffffffffffffffffffffffc000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 75e6528a68783de77204a15162f84d71f180abba9d9a8e6d239531595f028a116ec0e2c835675762
+
+COUNT = 122
+b = 160
+XKey = ffffffffffffffffffffffffffffffe000000000
+XSeed = 0000000000000000000000000000000000000000
+X = 0a1a7503b77852574e366b0117eb3861e8515dfbb3d2dd9fb374146930c4d25590214777c782e203
+
+COUNT = 123
+b = 160
+XKey = fffffffffffffffffffffffffffffff000000000
+XSeed = 0000000000000000000000000000000000000000
+X = bc36f8b79d84ab9263f87eaed6252f6bca8fe8df30c91e9427fe4d3d41842460c7a3450c2f300045
+
+COUNT = 124
+b = 160
+XKey = fffffffffffffffffffffffffffffff800000000
+XSeed = 0000000000000000000000000000000000000000
+X = 0d824e023491df1aabaeb6737dd61d5aed1b2c874dfda9d4a5b84acd3176e132dd6c29bc47c125f8
+
+COUNT = 125
+b = 160
+XKey = fffffffffffffffffffffffffffffffc00000000
+XSeed = 0000000000000000000000000000000000000000
+X = 512664fb393f2b5621292dd26815a78d220847fa1ea1ce8935a07da2e1b12e7299c24b806f24d431
+
+COUNT = 126
+b = 160
+XKey = fffffffffffffffffffffffffffffffe00000000
+XSeed = 0000000000000000000000000000000000000000
+X = 950f07a99423ef6afef65ee6da5afc9689f4ad74ce4c86a684398596230f42aee9ad7a185c335347
+
+COUNT = 127
+b = 160
+XKey = ffffffffffffffffffffffffffffffff00000000
+XSeed = 0000000000000000000000000000000000000000
+X = 411e11e04b566e3b991613ac2fc1937ca252a7430d18d62106b6088e384a9df4740aca77e822d484
+
+COUNT = 128
+b = 160
+XKey = ffffffffffffffffffffffffffffffff80000000
+XSeed = 0000000000000000000000000000000000000000
+X = 7f7aaa087a285980a31c1db915b6bb499e1d9d0a8bdc7f7cbec229a634d9d1a90ca57dcc2fa70f21
+
+COUNT = 129
+b = 160
+XKey = ffffffffffffffffffffffffffffffffc0000000
+XSeed = 0000000000000000000000000000000000000000
+X = d3d39e0f1128aca1a6d509730d6eb42cadaf249fc287351728912d33ab57a6665db1b96ebceddd19
+
+COUNT = 130
+b = 160
+XKey = ffffffffffffffffffffffffffffffffe0000000
+XSeed = 0000000000000000000000000000000000000000
+X = 3ac0800d44e2f327fdcbd61cdcd7075afce0676f04526a0d0fa9617d8e243ea592af8092db30f5d6
+
+COUNT = 131
+b = 160
+XKey = fffffffffffffffffffffffffffffffff0000000
+XSeed = 0000000000000000000000000000000000000000
+X = e742ad48abc285207e067251344b1c68155dab1d59d2c0b1210e1cfae4a5f27ae29d3d9515ec5d11
+
+COUNT = 132
+b = 160
+XKey = fffffffffffffffffffffffffffffffff8000000
+XSeed = 0000000000000000000000000000000000000000
+X = b32b0cc4e26f0bcc19ba1aa95533a816d362389af8f81600805c0647d5d8cd64f43d85090e0d200a
+
+COUNT = 133
+b = 160
+XKey = fffffffffffffffffffffffffffffffffc000000
+XSeed = 0000000000000000000000000000000000000000
+X = 30e347b89c94e6ab2baaadc98f299b24b00ddc8a615def35bfd9194cedbd64d6e924a9ff7a06f33a
+
+COUNT = 134
+b = 160
+XKey = fffffffffffffffffffffffffffffffffe000000
+XSeed = 0000000000000000000000000000000000000000
+X = c32afe8f42a86036e221607635baa6cbcaf3aeda185a17ba1af4707a84977edfb73e42c3d731f3a5
+
+COUNT = 135
+b = 160
+XKey = ffffffffffffffffffffffffffffffffff000000
+XSeed = 0000000000000000000000000000000000000000
+X = f6f062e0f58342e472de9f624373541656b77cacebf5a2db800646f03ede6316a08985f95d554d17
+
+COUNT = 136
+b = 160
+XKey = ffffffffffffffffffffffffffffffffff800000
+XSeed = 0000000000000000000000000000000000000000
+X = d5a9fec94ed0a7840d9d93d1978c89bbdefff4524a091f4dc4ef6834f787ba5dcccd20b6a22c945f
+
+COUNT = 137
+b = 160
+XKey = ffffffffffffffffffffffffffffffffffc00000
+XSeed = 0000000000000000000000000000000000000000
+X = 8a0bc648ba06d5d56f77e31610f41808fce53b436b8b2016c7d788aed7c832c7672d7edad73c75b4
+
+COUNT = 138
+b = 160
+XKey = ffffffffffffffffffffffffffffffffffe00000
+XSeed = 0000000000000000000000000000000000000000
+X = 90f3cfc64efc79e0acc670373a89960800775edac7d130c5f80c0bdc7f393fbc898deae1032d5de1
+
+COUNT = 139
+b = 160
+XKey = fffffffffffffffffffffffffffffffffff00000
+XSeed = 0000000000000000000000000000000000000000
+X = 182b43626fb350fb68ecdb2e7e468d2297e0faf86b79954c04c253f9aebc8e24837b0a3098bcd501
+
+COUNT = 140
+b = 160
+XKey = fffffffffffffffffffffffffffffffffff80000
+XSeed = 0000000000000000000000000000000000000000
+X = f2142110ad487a61e4284154ad9326f7bb21496f6759340d991c96df76648d82e7f9939304d10f3f
+
+COUNT = 141
+b = 160
+XKey = fffffffffffffffffffffffffffffffffffc0000
+XSeed = 0000000000000000000000000000000000000000
+X = 1175fd3fc41d7339a3003087664c97569a8c230b148a898071b3cbe97e5a285249bfae8a1b4d5535
+
+COUNT = 142
+b = 160
+XKey = fffffffffffffffffffffffffffffffffffe0000
+XSeed = 0000000000000000000000000000000000000000
+X = 95942d02ee8f3dd6a341e393d977a90d9d0ef6c3e365ecde89fedecd0219698f4de70d37d939d07e
+
+COUNT = 143
+b = 160
+XKey = ffffffffffffffffffffffffffffffffffff0000
+XSeed = 0000000000000000000000000000000000000000
+X = dc3d4ab9764f3e7b25784c64c22452c03dabd02ca03c1f871dd8c5ebcf525e9946a2c1d5d259de01
+
+COUNT = 144
+b = 160
+XKey = ffffffffffffffffffffffffffffffffffff8000
+XSeed = 0000000000000000000000000000000000000000
+X = cf11ac36a96972cdbb7f35150dd344e4d1341325ee4a44ff09bd9c53108998b5d04b5f07f2bd5300
+
+COUNT = 145
+b = 160
+XKey = ffffffffffffffffffffffffffffffffffffc000
+XSeed = 0000000000000000000000000000000000000000
+X = 5fe0bd81f1801a3ffa3d3e493075d4120c952f53cca22cbd803abe278f9fdb124502de6066021ad0
+
+COUNT = 146
+b = 160
+XKey = ffffffffffffffffffffffffffffffffffffe000
+XSeed = 0000000000000000000000000000000000000000
+X = 7859276d44f3a10f844010a375d3eb078e443d28da1de77d77dc3cfe79739027c8f448952df50b76
+
+COUNT = 147
+b = 160
+XKey = fffffffffffffffffffffffffffffffffffff000
+XSeed = 0000000000000000000000000000000000000000
+X = b6f311fce947d8de23b678566ca64cddc3404c1da4a888c3b19781d904b437534d397307e6f6d41b
+
+COUNT = 148
+b = 160
+XKey = fffffffffffffffffffffffffffffffffffff800
+XSeed = 0000000000000000000000000000000000000000
+X = 7af5b5e370d5be661bdd57cdfb81b2aa165ec0e47cec20bddfcaf0fc48711c1d12530e3b5b439cb1
+
+COUNT = 149
+b = 160
+XKey = fffffffffffffffffffffffffffffffffffffc00
+XSeed = 0000000000000000000000000000000000000000
+X = 2a738e1979d44cb91c43734026208d39bc20e48cabfa98d32debed67ac44349ef7def37d69a59ab2
+
+COUNT = 150
+b = 160
+XKey = fffffffffffffffffffffffffffffffffffffe00
+XSeed = 0000000000000000000000000000000000000000
+X = a660765d616ba5b347c6ed86a7009c42ffd9f746f0ab945b21ec5e4a65de2866f89534aed10fb5f8
+
+COUNT = 151
+b = 160
+XKey = ffffffffffffffffffffffffffffffffffffff00
+XSeed = 0000000000000000000000000000000000000000
+X = 71cd5ad24edfaeacc9daa6b7670e449b52e0766e2a86db40ecf512883ed1d3d28e1bb6b8dc763c9e
+
+COUNT = 152
+b = 160
+XKey = ffffffffffffffffffffffffffffffffffffff80
+XSeed = 0000000000000000000000000000000000000000
+X = 42f628ec7de1c6f7a2a08232512d8369fbc79d1d9211928ad40bd0fee4fcd0b27099ea868024f97c
+
+COUNT = 153
+b = 160
+XKey = ffffffffffffffffffffffffffffffffffffffc0
+XSeed = 0000000000000000000000000000000000000000
+X = e02365404191d8469d5e3022921027f0d27aa372f3d76956b261390f3f880f2fa32a8440a5301c82
+
+COUNT = 154
+b = 160
+XKey = ffffffffffffffffffffffffffffffffffffffe0
+XSeed = 0000000000000000000000000000000000000000
+X = 439347cebc1782cc675e2bc25c0cacafe2d3a1b40305f10889ee9cdb4c58ef68d970e94b08556636
+
+COUNT = 155
+b = 160
+XKey = fffffffffffffffffffffffffffffffffffffff0
+XSeed = 0000000000000000000000000000000000000000
+X = 59626e8b9318c3c9f46e1a8fac4693faca8ee1ea548a98ab441c6c088ddb58b03d2b5a69708bc26d
+
+COUNT = 156
+b = 160
+XKey = fffffffffffffffffffffffffffffffffffffff8
+XSeed = 0000000000000000000000000000000000000000
+X = ffd98581d37523fbc53de4a87d5abe516420343f62277bfc3956607d759e63dd89728ef434dc902d
+
+COUNT = 157
+b = 160
+XKey = fffffffffffffffffffffffffffffffffffffffc
+XSeed = 0000000000000000000000000000000000000000
+X = 624048e1eeb7325f7e3251da67f79341bdbd00b0005951d0fec9b327eeb5ff178a7f502d8f57c42b
+
+COUNT = 158
+b = 160
+XKey = fffffffffffffffffffffffffffffffffffffffe
+XSeed = 0000000000000000000000000000000000000000
+X = 089fc77cf8929c246fcee00b92c27676cca08e7598a1213777c0cda53c7016b09667e974f4b1173b
+
+COUNT = 159
+b = 160
+XKey = ffffffffffffffffffffffffffffffffffffffff
+XSeed = 0000000000000000000000000000000000000000
+X = ce8dd97eb53de8b8997d71af15eed31ffc822deb269cb566a0a9645811a3d9c977c5d8fbe8ddf6bb
+
+# CAVS 5.0
+# "FIPS 186 - General Purpose" information for "rngtestvalues"
+# Generators selected: Xorg Xchange
+# G-Functions selected: SHA-1 DES
+# Generated on Wed Feb 08 15:20:53 2006
+
+<MCT>
+[Xorg - SHA1]
+
+COUNT = 0
+b = 160
+XKey = 1c670cfd3b421f21fdb0f3885a204eb659ca9740
+XSeed = 0000000000000000000000000000000000000000
+X = e5121116d1a99e62902ffd279261500e0e16b0f3
+
+COUNT = 1
+b = 168
+XKey = d87f639afea75ba44bbc6bd0fb5ac84a12c2c6ed95
+XSeed = 000000000000000000000000000000000000000000
+X = 09328f082e48135784d39f9f0ec67911ef708788
+
+COUNT = 2
+b = 176
+XKey = f0ecfa38f93823dcf6c918432d1d72731f02d74cbafa
+XSeed = 00000000000000000000000000000000000000000000
+X = 1675536299b8a05236cc460944e691e952adbb80
+
+COUNT = 3
+b = 184
+XKey = 574508895ccfdcf4a1ad8284ad94eb3321f5d1a4a6244b
+XSeed = 0000000000000000000000000000000000000000000000
+X = f90c11ae695df29ae707a187a2eeeea92dcbd84b
+
+COUNT = 4
+b = 192
+XKey = 6e9d90254b9534d3ae680c9ab38d434114a58715fd00758b
+XSeed = 000000000000000000000000000000000000000000000000
+X = d562e8d50a86de701d6fb076a378282bae721849
+
+COUNT = 5
+b = 200
+XKey = 3477f6949b5278183169e9decf0010e683be87afe3b1b357a1
+XSeed = 00000000000000000000000000000000000000000000000000
+X = d954bc9c0537484f8ec13f4dde1905e3441dbac0
+
+COUNT = 6
+b = 208
+XKey = 533acb38c61100b152c326c7b4ea027df73b07c94309ca3cf60a
+XSeed = 0000000000000000000000000000000000000000000000000000
+X = 14b266d8c1fd4871104dd4f91c6d6d15c8e76c37
+
+COUNT = 7
+b = 216
+XKey = 21392b55c4e3af82523cdf81eaf1868055bd3e3ea18236c30b9833
+XSeed = 000000000000000000000000000000000000000000000000000000
+X = 7318576beb22084349f749d7ca615f1333f6bff4
+
+COUNT = 8
+b = 224
+XKey = b33ba749e3057b7a8aa61f3c78771655710157323bc1fecef62842d5
+XSeed = 00000000000000000000000000000000000000000000000000000000
+X = a24fa133c2e5ae5a2378af37e6097e1b5f503dd0
+
+COUNT = 9
+b = 232
+XKey = 2c685c7482c85777d9de02ee550fc2f5aa0e0f76319f27043ba10407a5
+XSeed = 0000000000000000000000000000000000000000000000000000000000
+X = fceae60fcdda5782a43916d23c133d4aa59588f9
+
+COUNT = 10
+b = 240
+XKey = aaa6e9a6525a0dbebf306a487f168bb31411ac5b3d761e5b775deda2c253
+XSeed = 000000000000000000000000000000000000000000000000000000000000
+X = c87d4f6f1dfff1c7c0517a3ba478ea3db40c915d
+
+COUNT = 11
+b = 248
+XKey = 5061d23eb06b7844fcad7e0b55d6abd6455775cca2bc0cf1b53d9a559c90c9
+XSeed = 00000000000000000000000000000000000000000000000000000000000000
+X = 96116ca45240c44249b8265d736572a3555d4bd8
+
+COUNT = 12
+b = 256
+XKey = b436c1e06d76015c85d145cfb2f513f2dbffa7682b3ea09f6539f8f777f33926
+XSeed = 0000000000000000000000000000000000000000000000000000000000000000
+X = 8123d23bdb6379a8383a25fda023af25ec0dd8d0
+
+COUNT = 13
+b = 264
+XKey = b6fb9e128dc5985f3a49ab84ee0336f8954318a9b681bbef9bf052beb3555e2134
+XSeed = 000000000000000000000000000000000000000000000000000000000000000000
+X = dcbd4dc592d2eadff08c532614ae28c030e9b60c
+
+COUNT = 14
+b = 272
+XKey = fe9e57d121e2bd431c41f1f757d2bd5b141c98daa47e795fdbcfed15c14168728a8b
+XSeed = 00000000000000000000000000000000000000000000000000000000000000000000
+X = 1945ac66fd792852da50b72e33bac69ed3ce9bbd
+
+COUNT = 15
+b = 280
+XKey = 635debc0f6a35bea4b6de3db176b06600370d9840375feb1e3e1d6172308f35104f1cc
+XSeed = 0000000000000000000000000000000000000000000000000000000000000000000000
+X = 72b363e7676288180c41d42a0934714c745bdbb0
+
+COUNT = 16
+b = 288
+XKey = 66682eeb3ba396a7654d5e3e1230376d9c8d710f00bb13e493112a92f00661e93597d26b
+XSeed = 000000000000000000000000000000000000000000000000000000000000000000000000
+X = 1d7d5a287a2198fc2ed407838521c6be1d7cd11d
+
+COUNT = 17
+b = 296
+XKey = 575289a193c212b874e690bf22d807b568c63a66b9eaccf871bca5c05e66975a7f7841f80b
+XSeed = 00000000000000000000000000000000000000000000000000000000000000000000000000
+X = 5c9f11ba4939c6ce67bdc0c35aaa418151b0b9d0
+
+COUNT = 18
+b = 304
+XKey = 6df2a963884ec9a615e398d010cc91026060845b01c0de2362ac2b490c9bd910850a3f057414
+XSeed = 0000000000000000000000000000000000000000000000000000000000000000000000000000
+X = 6a244d9944384feb512d4e080d308096ddfe8066
+
+COUNT = 19
+b = 312
+XKey = 2c4b6df63cb790996f0c032657e608a76b2af9d9ff30df77732841bbaab63a23bde0ce71f12a7e
+XSeed = 000000000000000000000000000000000000000000000000000000000000000000000000000000
+X = f2c6c8fe88d73a1940d0de419ffebc5b2070c5c7
+
+COUNT = 20
+b = 320
+XKey = dfb6bfe8d24fd6395c811928a7953aee1a2de5d6e484f69fd9f7e9227ec591355f130dcea933f96c
+XSeed = 00000000000000000000000000000000000000000000000000000000000000000000000000000000
+X = 54c4809627894c7be99d752be77a41a71e1177bc
+
+COUNT = 21
+b = 328
+XKey = 5ae22f47f7301856ada0553c6191977adfb39b64791df5d4f19a0d1f9a446748b95527743139d49e60
+XSeed = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000
+X = 44ed62cc4a46740532b1178c75919e55598a3094
+
+COUNT = 22
+b = 336
+XKey = ee2ef8ae409bc544bda6637166568b93721db4d7a9b194ac0e17e378c000628922591c4e3a1eebc7576f
+XSeed = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+X = 98e18826178499f6b5e9f7dbbc7fbb5ea8ece400
+
+COUNT = 23
+b = 344
+XKey = d071c39a5d2e9a2aaf716f1ad84c16ba74411d3597615dcd04b6cf68a0dfa14c26fa89271bc75a520509d5
+XSeed = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+X = 5f8264026559da35e0bea1fdab8bc967079b1fd9
+
+COUNT = 24
+b = 352
+XKey = 369b80c1a1c6fb9d69a01c727cece3547371544418631d4a252079c44f1d54fd831fb00170ae47b045c67212
+XSeed = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+X = 148e0ecee150cb59b1ee70586e0f493b74dda65d
+
+COUNT = 25
+b = 360
+XKey = d0a014bda380b171255b36e40f20a69821957dae52eff01229a077f36b708976f6cfa6abed699bc015fc02747f
+XSeed = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+X = 1a67a8bcdffd0e07606288fb0bb0726b36b259bf
+
+COUNT = 26
+b = 368
+XKey = aae6ae0f2eb856f812733764e7ec1cfc7d49e92e61703738a5c03f83dffef933749285fc17f3c9378c605c35b2d1
+XSeed = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+X = 10b3ebf6cd54131ce1e902829a0ab251f193eb24
+
+COUNT = 27
+b = 376
+XKey = f36b395eb02579985875f6183210e452b91c20bd58e4172772d1e44ba596b8a550aa7f8552fbc06315e1c572cc50fd
+XSeed = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+X = 110bb9281f2e1ffac8252473be9f1ef2629513f0
+
+COUNT = 28
+b = 384
+XKey = 7af1449287ffbf7428814dd6217aee8695d7f463760a121e40f6b642e70b98720db293f279ebb56ac53492e656aedd20
+XSeed = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+X = 08ea8feab6b529788d904bdbd43b9db583c95b3c
+
+COUNT = 29
+b = 392
+XKey = 94a62f890e754bda69b6d2a71a9c7cda337b99902d80f76ee4a00638e3ce3a9fe271b15b8d15167a8760c5f8af482f8fa2
+XSeed = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+X = c65ba4525e3bb1f083ac1bd971d952d8fb4ea820
+
+COUNT = 30
+b = 400
+XKey = 417891bdbf562d87c93ca9c53aac522161c793e8a762bcbe725b0391492dc9cb38c31ecc768a869745cafdcb1a363ad6fec2
+XSeed = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+X = 09ffcbaca867d86fb5a90e44ad5d60b96b52e090
+
+COUNT = 31
+b = 408
+XKey = 999a1eeca775bdbe61f3772f6cfc28ff95f13745ac35100e95ecd4479c024edd096f2a22f4ba61735bbcf81872a7ea6b3a4763
+XSeed = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+X = f2fef1651d92847c0facc14799153aac54289afc
+
+COUNT = 32
+b = 416
+XKey = 41f80eca8e883ceb6a772453131c922d542749c2a93248a4a4994c2c8f8c96275362eecd9930e8f32e9b6681acea5e255760de49
+XSeed = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+X = e750fd8a3815189e7b1ffba65760c6896773195f
+
+COUNT = 33
+b = 424
+XKey = 7eae482dcfa5e02acf05e105db48283f440640439a24ca3b2a482228c58f3f32c383db3c4847d4bcc615d3cac3eb2b77dd80045f0b
+XSeed = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+X = 26e00f1ea68d5bde0c820837c18f564347507dc9
+
+COUNT = 34
+b = 432
+XKey = d8143b6190d098d8c0b9af5c175344b602e6d086732e6b96e054ef688e1d5b110f62754a0ac0b4c53a905cbdb919ebd17f05b4122512
+XSeed = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+X = 60ac25c92a8c7da14edfebde25a97646474c9009
+
+COUNT = 35
+b = 440
+XKey = 6f54f8051f7c172493f282be71942d4a65285560bca1b61b2f9effc1fc3483a63ced314d7010c6d15d2341831aaf97d56743a97740bb73
+XSeed = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+X = 1130c281c88ecad60736ac5bf6c9db4fc2e8334a
+
+COUNT = 36
+b = 448
+XKey = ca82c17fc3ac423e00c8b7c6f48bd0976d9e60c973f460fe735c37959d5239208a1b6d18221193d0bd3b65a888201e832bdd397ba8767bd3
+XSeed = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+X = 8da6754cadeb3f9121239381de1ff40061abe07e
+
+COUNT = 37
+b = 456
+XKey = 058f0d2e2a8b17581ab00d8b7ed2fef2e21dfaa60b120fd28acc771591880f2706640bc0d667e8b58cc2a3642255295316750e14c1ed816ce5
+XSeed = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+X = 5fd13163fb1fe4417fe96d7fb13ef2577f5868b2
+
+COUNT = 38
+b = 464
+XKey = a8806c3e36700c4b8b45555dc9679bcb036fa3924fe85a3d1d57c708c77a3f4469ced8fdf25320db7b930e46d8e138cd6ddf47c94343a83d5cda
+XSeed = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+X = 5704c42642beaa28896816eb196d2cf6b3de61f6
+
+COUNT = 39
+b = 472
+XKey = 1a02d007f03b34ed427631283eb614db4d521f555136e7e42b4cfbee8134c63dbe3bb79b5a8b9f9f5b9f5ac61cfab1c54d197f1e3ba613f251eed6
+XSeed = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+X = f6f672ba423d82f4e86d1c7a41b4547972e859de
+
+COUNT = 40
+b = 480
+XKey = 28c1adb2742ac3b9c15d22f737ac5ffd34d0e5d79ee6ea3677b7a2cfb13cb2fe4462e7af7f0a287e9b54a91d961d62f63fc6c0128d379a3a3424665c
+XSeed = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+X = 4596045105a7e36296b9ad7353723ba306353004
+
+COUNT = 41
+b = 488
+XKey = 195adc728e0ec4f0b210b57658b448860e219231ad9d56812e0b7815bfb1b50b163f9223060d922050a5ac72bb81fc136716b9af5e1167076ce04e9731
+XSeed = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+X = 3e573f2a097c3568c9cf52f20eb141e63f9f776e
+
+COUNT = 42
+b = 496
+XKey = 866db552cf4745908fdf35d4c0967428d56039b1f223df315c61f2d12f178a1e4fe5d751a06efed37a022300577bc72ccf6455e3c761f775e5caaeb2479a
+XSeed = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+X = 0077207b39f67aa80cb2ea90818440d4e5ccc414
+
+COUNT = 43
+b = 504
+XKey = 641846ce2ba4396a391651179231d553c9061c6619bd4545b29228b6511e8bb513d89a168bdb916d12eabc2b5eb1a109574d7caa250feb7b8e7debdf7f9a03
+XSeed = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+X = 2166c4e99be5dc0cdc747c7c6d27105a8e115ba5
+
+COUNT = 44
+b = 512
+XKey = 5cbb6d193c13bd62f5658ed4304774c6b1faf5b3dce432487840cabab415fb5d67640a739ca6e5414e760869708a9d7331e7e7ad7d55e035c711215406c3030d
+XSeed = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+X = a2322c754fe789af3afae00b9fbbbd613076ea9f
+
diff --git a/asdcplib/src/gen-tst.sh b/asdcplib/src/gen-tst.sh
new file mode 100755
index 0000000..31ed12d
--- /dev/null
+++ b/asdcplib/src/gen-tst.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+#
+# $Id: gen-tst.sh,v 1.3 2009/04/09 19:16:49 msheby Exp $
+# Copyright (c) 2007-2009 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.
+
+${BUILD_DIR}/asdcp-test${EXEEXT} -g
diff --git a/asdcplib/src/h__Reader.cpp b/asdcplib/src/h__Reader.cpp
new file mode 100755
index 0000000..ebf3443
--- /dev/null
+++ b/asdcplib/src/h__Reader.cpp
@@ -0,0 +1,460 @@
+/*
+Copyright (c) 2004-2012, 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 h__Reader.cpp
+ \version $Id: h__Reader.cpp,v 1.31 2012/02/07 18:54:25 jhurst Exp $
+ \brief MXF file reader base class
+*/
+
+#define DEFAULT_MD_DECL
+#include "AS_DCP_internal.h"
+#include "KLV.h"
+
+using namespace ASDCP;
+using namespace ASDCP::MXF;
+
+static Kumu::Mutex sg_DefaultMDInitLock;
+static bool sg_DefaultMDTypesInit = false;
+static const ASDCP::Dictionary *sg_dict;
+
+//
+void
+ASDCP::default_md_object_init()
+{
+ if ( ! sg_DefaultMDTypesInit )
+ {
+ Kumu::AutoMutex BlockLock(sg_DefaultMDInitLock);
+
+ if ( ! sg_DefaultMDTypesInit )
+ {
+ sg_dict = &DefaultSMPTEDict();
+ g_OPAtomHeader = new ASDCP::MXF::OPAtomHeader(sg_dict);
+ g_OPAtomIndexFooter = new ASDCP::MXF::OPAtomIndexFooter(sg_dict);
+ sg_DefaultMDTypesInit = true;
+ }
+ }
+}
+
+
+//
+ASDCP::h__Reader::h__Reader(const Dictionary& d) :
+ m_Dict(&d), m_HeaderPart(m_Dict), m_BodyPart(m_Dict), m_FooterPart(m_Dict), m_EssenceStart(0)
+{
+ default_md_object_init();
+}
+
+ASDCP::h__Reader::~h__Reader()
+{
+ Close();
+}
+
+void
+ASDCP::h__Reader::Close()
+{
+ m_File.Close();
+}
+
+//------------------------------------------------------------------------------------------
+//
+
+//
+Result_t
+ASDCP::h__Reader::InitInfo()
+{
+ assert(m_Dict);
+ InterchangeObject* Object;
+
+ m_Info.LabelSetType = LS_MXF_UNKNOWN;
+
+ if ( m_HeaderPart.OperationalPattern.ExactMatch(MXFInterop_OPAtom_Entry().ul) )
+ m_Info.LabelSetType = LS_MXF_INTEROP;
+ else if ( m_HeaderPart.OperationalPattern.ExactMatch(SMPTE_390_OPAtom_Entry().ul) )
+ m_Info.LabelSetType = LS_MXF_SMPTE;
+
+ // Identification
+ Result_t result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(Identification), &Object);
+
+ if( ASDCP_SUCCESS(result) )
+ MD_to_WriterInfo((Identification*)Object, m_Info);
+
+ // SourcePackage
+ if( ASDCP_SUCCESS(result) )
+ result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(SourcePackage), &Object);
+
+ if( ASDCP_SUCCESS(result) )
+ {
+ SourcePackage* SP = (SourcePackage*)Object;
+ memcpy(m_Info.AssetUUID, SP->PackageUID.Value() + 16, UUIDlen);
+ }
+
+ // optional CryptographicContext
+ if( ASDCP_SUCCESS(result) )
+ {
+ Result_t cr_result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(CryptographicContext), &Object);
+
+ if( ASDCP_SUCCESS(cr_result) )
+ MD_to_CryptoInfo((CryptographicContext*)Object, m_Info, *m_Dict);
+ }
+
+ return result;
+}
+
+
+// standard method of opening an MXF file for read
+Result_t
+ASDCP::h__Reader::OpenMXFRead(const char* filename)
+{
+ m_LastPosition = 0;
+ Result_t result = m_File.OpenRead(filename);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = m_HeaderPart.InitFromFile(m_File);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ // if this is a three partition file, go to the body
+ // partition and read the partition pack
+ if ( m_HeaderPart.m_RIP.PairArray.size() > 2 )
+ {
+ 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_EssenceStart = m_File.Tell();
+ }
+
+ return result;
+}
+
+
+// standard method of populating the in-memory index
+Result_t
+ASDCP::h__Reader::InitMXFIndex()
+{
+ if ( ! m_File.IsOpen() )
+ return RESULT_INIT;
+
+ Result_t result = m_File.Seek(m_HeaderPart.FooterPartition);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ m_FooterPart.m_Lookup = &m_HeaderPart.m_Primer;
+ result = m_FooterPart.InitFromFile(m_File);
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ m_File.Seek(m_EssenceStart);
+
+ return result;
+}
+
+//
+Result_t
+ASDCP::KLReader::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 ( ASDCP_FAILURE(result) )
+ return result;
+
+ if ( read_count != header_length )
+ return RESULT_READFAIL;
+
+ const byte_t* ber_start = m_KeyBuf + SMPTE_UL_LENGTH;
+
+ if ( ( *ber_start & 0x80 ) == 0 )
+ {
+ DefaultLogSink().Error("BER encoding error.\n");
+ return RESULT_FORMAT;
+ }
+
+ ui8_t ber_size = ( *ber_start & 0x0f ) + 1;
+
+ if ( ber_size > 9 )
+ {
+ DefaultLogSink().Error("BER size encoding error.\n");
+ return RESULT_FORMAT;
+ }
+
+ if ( ber_size < MXF_BER_LENGTH )
+ {
+ DefaultLogSink().Error("BER size %d shorter than AS-DCP minimum %d.\n",
+ ber_size, MXF_BER_LENGTH);
+ return RESULT_FORMAT;
+ }
+
+ if ( ber_size > MXF_BER_LENGTH )
+ {
+ ui32_t diff = ber_size - MXF_BER_LENGTH;
+ assert((SMPTE_UL_LENGTH + MXF_BER_LENGTH + diff) <= (SMPTE_UL_LENGTH * 2));
+ result = Reader.Read(m_KeyBuf + SMPTE_UL_LENGTH + MXF_BER_LENGTH, diff, &read_count);
+
+ if ( ASDCP_FAILURE(result) )
+ return result;
+
+ if ( read_count != diff )
+ return RESULT_READFAIL;
+
+ header_length += diff;
+ }
+
+ return InitFromBuffer(m_KeyBuf, header_length);
+}
+
+// standard method of reading a plaintext or encrypted frame
+Result_t
+ASDCP::h__Reader::ReadEKLVFrame(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf,
+ const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC)
+{
+ // 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 and go read the frame's key and length
+ Kumu::fpos_t FilePosition = m_EssenceStart + TmpEntry.StreamOffset;
+ Result_t result = RESULT_OK;
+
+ if ( FilePosition != m_LastPosition )
+ {
+ m_LastPosition = FilePosition;
+ result = m_File.Seek(FilePosition);
+ }
+
+ if( ASDCP_SUCCESS(result) )
+ result = ReadEKLVPacket(FrameNum, FrameNum + 1, FrameBuf, EssenceUL, Ctx, HMAC);
+
+ return result;
+}
+
+
+Result_t
+ASDCP::h__Reader::ReadEKLVPacket(ui32_t FrameNum, ui32_t SequenceNum, ASDCP::FrameBuffer& FrameBuf,
+ const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC)
+{
+ KLReader Reader;
+ Result_t result = Reader.ReadKLFromFile(m_File);
+
+ if ( ASDCP_FAILURE(result) )
+ return result;
+
+ UL Key(Reader.Key());
+ ui64_t PacketLength = Reader.Length();
+ m_LastPosition = m_LastPosition + Reader.KLLength() + PacketLength;
+ assert(m_Dict);
+
+ if ( Key.MatchIgnoreStream(m_Dict->ul(MDD_CryptEssence)) ) // ignore the stream numbers
+ {
+ if ( ! m_Info.EncryptedEssence )
+ {
+ DefaultLogSink().Error("EKLV packet found, no Cryptographic Context in header.\n");
+ return RESULT_FORMAT;
+ }
+
+ // read encrypted triplet value into internal buffer
+ assert(PacketLength <= 0xFFFFFFFFL);
+ m_CtFrameBuf.Capacity((ui32_t) PacketLength);
+ ui32_t read_count;
+ result = m_File.Read(m_CtFrameBuf.Data(), (ui32_t) PacketLength,
+ &read_count);
+
+ if ( ASDCP_FAILURE(result) )
+ return result;
+
+ if ( read_count != PacketLength )
+ {
+ DefaultLogSink().Error("read length is smaller than EKLV packet length.\n");
+ return RESULT_FORMAT;
+ }
+
+ m_CtFrameBuf.Size((ui32_t) PacketLength);
+
+ // should be const but mxflib::ReadBER is not
+ byte_t* ess_p = m_CtFrameBuf.Data();
+
+ // read context ID length
+ if ( ! Kumu::read_test_BER(&ess_p, UUIDlen) )
+ return RESULT_FORMAT;
+
+ // test the context ID
+ if ( memcmp(ess_p, m_Info.ContextID, UUIDlen) != 0 )
+ {
+ DefaultLogSink().Error("Packet's Cryptographic Context ID does not match the header.\n");
+ return RESULT_FORMAT;
+ }
+ ess_p += UUIDlen;
+
+ // read PlaintextOffset length
+ if ( ! Kumu::read_test_BER(&ess_p, sizeof(ui64_t)) )
+ return RESULT_FORMAT;
+
+ ui32_t PlaintextOffset = (ui32_t)KM_i64_BE(Kumu::cp2i<ui64_t>(ess_p));
+ ess_p += sizeof(ui64_t);
+
+ // read essence UL length
+ if ( ! Kumu::read_test_BER(&ess_p, SMPTE_UL_LENGTH) )
+ return RESULT_FORMAT;
+
+ // test essence UL
+ if ( ! UL(ess_p).MatchIgnoreStream(EssenceUL) ) // ignore the stream number
+ {
+ char strbuf[IntBufferLen];
+ const MDDEntry* Entry = m_Dict->FindUL(Key.Value());
+ if ( Entry == 0 )
+ DefaultLogSink().Warn("Unexpected Encrypted Essence UL found: %s.\n", Key.EncodeString(strbuf, IntBufferLen));
+ else
+ DefaultLogSink().Warn("Unexpected Encrypted Essence UL found: %s.\n", Entry->name);
+ return RESULT_FORMAT;
+ }
+ ess_p += SMPTE_UL_LENGTH;
+
+ // read SourceLength length
+ if ( ! Kumu::read_test_BER(&ess_p, sizeof(ui64_t)) )
+ return RESULT_FORMAT;
+
+ ui32_t SourceLength = (ui32_t)KM_i64_BE(Kumu::cp2i<ui64_t>(ess_p));
+ ess_p += sizeof(ui64_t);
+ assert(SourceLength);
+
+ if ( FrameBuf.Capacity() < SourceLength )
+ {
+ DefaultLogSink().Error("FrameBuf.Capacity: %u SourceLength: %u\n", FrameBuf.Capacity(), SourceLength);
+ return RESULT_SMALLBUF;
+ }
+
+ ui32_t esv_length = calc_esv_length(SourceLength, PlaintextOffset);
+
+ // read ESV length
+ if ( ! Kumu::read_test_BER(&ess_p, esv_length) )
+ {
+ DefaultLogSink().Error("read_test_BER did not return %u\n", esv_length);
+ return RESULT_FORMAT;
+ }
+
+ ui32_t tmp_len = esv_length + (m_Info.UsesHMAC ? klv_intpack_size : 0);
+
+ if ( PacketLength < tmp_len )
+ {
+ DefaultLogSink().Error("Frame length is larger than EKLV packet length.\n");
+ return RESULT_FORMAT;
+ }
+
+ if ( Ctx )
+ {
+ // wrap the pointer and length as a FrameBuffer for use by
+ // DecryptFrameBuffer() and TestValues()
+ FrameBuffer TmpWrapper;
+ TmpWrapper.SetData(ess_p, tmp_len);
+ TmpWrapper.Size(tmp_len);
+ TmpWrapper.SourceLength(SourceLength);
+ TmpWrapper.PlaintextOffset(PlaintextOffset);
+
+ result = DecryptFrameBuffer(TmpWrapper, FrameBuf, Ctx);
+ FrameBuf.FrameNumber(FrameNum);
+
+ // detect and test integrity pack
+ if ( ASDCP_SUCCESS(result) && m_Info.UsesHMAC && HMAC )
+ {
+ IntegrityPack IntPack;
+ result = IntPack.TestValues(TmpWrapper, m_Info.AssetUUID, SequenceNum, HMAC);
+ }
+ }
+ else // return ciphertext to caller
+ {
+ if ( FrameBuf.Capacity() < tmp_len )
+ {
+ char intbuf[IntBufferLen];
+ DefaultLogSink().Error("FrameBuf.Capacity: %u FrameLength: %s\n",
+ FrameBuf.Capacity(), ui64sz(PacketLength, intbuf));
+ return RESULT_SMALLBUF;
+ }
+
+ memcpy(FrameBuf.Data(), ess_p, tmp_len);
+ FrameBuf.Size(tmp_len);
+ FrameBuf.FrameNumber(FrameNum);
+ FrameBuf.SourceLength(SourceLength);
+ FrameBuf.PlaintextOffset(PlaintextOffset);
+ }
+ }
+ else if ( Key.MatchIgnoreStream(EssenceUL) ) // ignore the stream number
+ { // read plaintext frame
+ if ( FrameBuf.Capacity() < PacketLength )
+ {
+ char intbuf[IntBufferLen];
+ DefaultLogSink().Error("FrameBuf.Capacity: %u FrameLength: %s\n",
+ FrameBuf.Capacity(), ui64sz(PacketLength, intbuf));
+ return RESULT_SMALLBUF;
+ }
+
+ // read the data into the supplied buffer
+ ui32_t read_count;
+ assert(PacketLength <= 0xFFFFFFFFL);
+ result = m_File.Read(FrameBuf.Data(), (ui32_t) PacketLength, &read_count);
+
+ if ( ASDCP_FAILURE(result) )
+ return result;
+
+ if ( read_count != PacketLength )
+ {
+ char intbuf1[IntBufferLen];
+ char intbuf2[IntBufferLen];
+ DefaultLogSink().Error("read_count: %s != FrameLength: %s\n",
+ ui64sz(read_count, intbuf1),
+ ui64sz(PacketLength, intbuf2) );
+
+ return RESULT_READFAIL;
+ }
+
+ FrameBuf.FrameNumber(FrameNum);
+ FrameBuf.Size(read_count);
+ }
+ else
+ {
+ char strbuf[IntBufferLen];
+ const MDDEntry* Entry = m_Dict->FindUL(Key.Value());
+ if ( Entry == 0 )
+ 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;
+ }
+
+ return result;
+}
+
+
+//
+// end h__Reader.cpp
+//
diff --git a/asdcplib/src/h__Writer.cpp b/asdcplib/src/h__Writer.cpp
new file mode 100755
index 0000000..d743e30
--- /dev/null
+++ b/asdcplib/src/h__Writer.cpp
@@ -0,0 +1,710 @@
+/*
+Copyright (c) 2004-2012, 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 h__Writer.cpp
+ \version $Id: h__Writer.cpp,v 1.51 2012/02/07 18:54:25 jhurst Exp $
+ \brief MXF file writer base class
+*/
+
+#include "AS_DCP_internal.h"
+#include "KLV.h"
+
+using std::cout;
+using namespace ASDCP;
+using namespace ASDCP::MXF;
+
+// a magic number identifying asdcplib
+#ifndef ASDCP_BUILD_NUMBER
+#define ASDCP_BUILD_NUMBER 0x6A68
+#endif
+
+
+static std::vector<int>
+version_split(const char* str)
+{
+ std::vector<int> result;
+
+ const char* pstr = str;
+ const char* r = strchr(pstr, '.');
+
+ while ( r != 0 )
+ {
+ assert(r >= pstr);
+ if ( r > pstr )
+ result.push_back(atoi(pstr));
+
+ pstr = r + 1;
+ r = strchr(pstr, '.');
+ }
+
+ if( strlen(pstr) > 0 )
+ result.push_back(atoi(pstr));
+
+ assert(result.size() == 3);
+ return result;
+}
+
+
+//
+ASDCP::h__Writer::h__Writer(const Dictionary& d) :
+ m_Dict(&d), m_HeaderSize(0), m_HeaderPart(m_Dict),
+ m_BodyPart(m_Dict), m_FooterPart(m_Dict), m_EssenceStart(0),
+ m_EssenceDescriptor(0), m_FramesWritten(0), m_StreamOffset(0)
+{
+ default_md_object_init();
+}
+
+ASDCP::h__Writer::~h__Writer()
+{
+}
+
+//
+// add DMS CryptographicFramework entry to source package
+void
+AddDMScrypt(Partition& HeaderPart, SourcePackage& Package,
+ WriterInfo& Descr, const UL& WrappingUL, const Dictionary*& Dict)
+{
+ assert(Dict);
+ // Essence Track
+ StaticTrack* NewTrack = new StaticTrack(Dict);
+ HeaderPart.AddChildObject(NewTrack);
+ Package.Tracks.push_back(NewTrack->InstanceUID);
+ NewTrack->TrackName = "Descriptive Track";
+ NewTrack->TrackID = 3;
+
+ Sequence* Seq = new Sequence(Dict);
+ HeaderPart.AddChildObject(Seq);
+ NewTrack->Sequence = Seq->InstanceUID;
+ Seq->DataDefinition = UL(Dict->ul(MDD_DescriptiveMetaDataDef));
+
+ DMSegment* Segment = new DMSegment(Dict);
+ HeaderPart.AddChildObject(Segment);
+ Seq->StructuralComponents.push_back(Segment->InstanceUID);
+ Segment->EventComment = "AS-DCP KLV Encryption";
+
+ CryptographicFramework* CFW = new CryptographicFramework(Dict);
+ HeaderPart.AddChildObject(CFW);
+ Segment->DMFramework = CFW->InstanceUID;
+
+ CryptographicContext* Context = new CryptographicContext(Dict);
+ HeaderPart.AddChildObject(Context);
+ CFW->ContextSR = Context->InstanceUID;
+
+ Context->ContextID.Set(Descr.ContextID);
+ Context->SourceEssenceContainer = WrappingUL; // ??????
+ Context->CipherAlgorithm.Set(Dict->ul(MDD_CipherAlgorithm_AES));
+ Context->MICAlgorithm.Set( Descr.UsesHMAC ? Dict->ul(MDD_MICAlgorithm_HMAC_SHA1) : Dict->ul(MDD_MICAlgorithm_NONE) );
+ Context->CryptographicKeyID.Set(Descr.CryptographicKeyID);
+}
+
+//
+void
+ASDCP::h__Writer::InitHeader()
+{
+ assert(m_Dict);
+ assert(m_EssenceDescriptor);
+
+ m_HeaderPart.m_Primer.ClearTagList();
+ m_HeaderPart.m_Preface = new Preface(m_Dict);
+ m_HeaderPart.AddChildObject(m_HeaderPart.m_Preface);
+
+ // Set the Operational Pattern label -- we're just starting and have no RIP or index,
+ // so we tell the world by using OP1a
+ m_HeaderPart.m_Preface->OperationalPattern = UL(m_Dict->ul(MDD_OP1a));
+ m_HeaderPart.OperationalPattern = m_HeaderPart.m_Preface->OperationalPattern;
+
+ // First RIP Entry
+ if ( m_Info.LabelSetType == LS_MXF_SMPTE )
+ m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(0, 0)); // 3-part, no essence in header
+ else
+ m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(1, 0)); // 2-part, essence in header
+
+ //
+ // Identification
+ //
+ Identification* Ident = new Identification(m_Dict);
+ m_HeaderPart.AddChildObject(Ident);
+ m_HeaderPart.m_Preface->Identifications.push_back(Ident->InstanceUID);
+
+ 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();
+ Ident->ProductUID.Set(m_Info.ProductUUID);
+ Ident->Platform = ASDCP_PLATFORM;
+
+ std::vector<int> version = version_split(Version());
+
+ Ident->ToolkitVersion.Major = version[0];
+ Ident->ToolkitVersion.Minor = version[1];
+ Ident->ToolkitVersion.Patch = version[2];
+ Ident->ToolkitVersion.Build = ASDCP_BUILD_NUMBER;
+ Ident->ToolkitVersion.Release = VersionType::RL_RELEASE;
+}
+
+//
+template <class ClipT>
+struct TrackSet
+{
+ MXF::Track* Track;
+ MXF::Sequence* Sequence;
+ ClipT* Clip;
+
+ TrackSet() : Track(0), Sequence(0), Clip(0) {}
+};
+
+//
+template <class PackageT, class ClipT>
+TrackSet<ClipT>
+CreateTrackAndSequence(OPAtomHeader& Header, PackageT& Package, const std::string TrackName,
+ const MXF::Rational& EditRate, const UL& Definition, ui32_t TrackID, const Dictionary*& Dict)
+{
+ TrackSet<ClipT> NewTrack;
+
+ NewTrack.Track = new Track(Dict);
+ Header.AddChildObject(NewTrack.Track);
+ NewTrack.Track->EditRate = EditRate;
+ Package.Tracks.push_back(NewTrack.Track->InstanceUID);
+ NewTrack.Track->TrackID = TrackID;
+ NewTrack.Track->TrackName = TrackName.c_str();
+
+ NewTrack.Sequence = new Sequence(Dict);
+ Header.AddChildObject(NewTrack.Sequence);
+ NewTrack.Track->Sequence = NewTrack.Sequence->InstanceUID;
+ NewTrack.Sequence->DataDefinition = Definition;
+
+ return NewTrack;
+}
+
+//
+template <class PackageT>
+TrackSet<TimecodeComponent>
+CreateTimecodeTrack(OPAtomHeader& Header, PackageT& Package,
+ const MXF::Rational& EditRate, ui32_t TCFrameRate, ui64_t TCStart, const Dictionary*& Dict)
+{
+ assert(Dict);
+ UL TCUL(Dict->ul(MDD_TimecodeDataDef));
+
+ TrackSet<TimecodeComponent> NewTrack = CreateTrackAndSequence<PackageT, TimecodeComponent>(Header, Package, "Timecode Track", EditRate, TCUL, 1, Dict);
+
+ NewTrack.Clip = new TimecodeComponent(Dict);
+ Header.AddChildObject(NewTrack.Clip);
+ NewTrack.Sequence->StructuralComponents.push_back(NewTrack.Clip->InstanceUID);
+ NewTrack.Clip->RoundedTimecodeBase = TCFrameRate;
+ NewTrack.Clip->StartTimecode = TCStart;
+ NewTrack.Clip->DataDefinition = TCUL;
+
+ return NewTrack;
+}
+
+
+//
+void
+ASDCP::h__Writer::AddSourceClip(const MXF::Rational& EditRate, ui32_t TCFrameRate,
+ const std::string& TrackName, const UL& EssenceUL,
+ const UL& DataDefinition, const std::string& PackageLabel)
+{
+ //
+ ContentStorage* Storage = new ContentStorage(m_Dict);
+ m_HeaderPart.AddChildObject(Storage);
+ m_HeaderPart.m_Preface->ContentStorage = Storage->InstanceUID;
+
+ EssenceContainerData* ECD = new EssenceContainerData(m_Dict);
+ m_HeaderPart.AddChildObject(ECD);
+ Storage->EssenceContainerData.push_back(ECD->InstanceUID);
+ ECD->IndexSID = 129;
+ ECD->BodySID = 1;
+
+ UUID assetUUID(m_Info.AssetUUID);
+ UMID SourcePackageUMID, MaterialPackageUMID;
+ SourcePackageUMID.MakeUMID(0x0f, assetUUID);
+ MaterialPackageUMID.MakeUMID(0x0f); // unidentified essence
+
+ //
+ // Material Package
+ //
+ m_MaterialPackage = new MaterialPackage(m_Dict);
+ m_MaterialPackage->Name = "AS-DCP Material Package";
+ m_MaterialPackage->PackageUID = MaterialPackageUMID;
+ m_HeaderPart.AddChildObject(m_MaterialPackage);
+ Storage->Packages.push_back(m_MaterialPackage->InstanceUID);
+
+ TrackSet<TimecodeComponent> MPTCTrack =
+ CreateTimecodeTrack<MaterialPackage>(m_HeaderPart, *m_MaterialPackage,
+ EditRate, TCFrameRate, 0, m_Dict);
+ m_DurationUpdateList.push_back(&(MPTCTrack.Sequence->Duration));
+ m_DurationUpdateList.push_back(&(MPTCTrack.Clip->Duration));
+
+ TrackSet<SourceClip> MPTrack =
+ CreateTrackAndSequence<MaterialPackage, SourceClip>(m_HeaderPart, *m_MaterialPackage,
+ TrackName, EditRate, DataDefinition,
+ 2, m_Dict);
+ m_DurationUpdateList.push_back(&(MPTrack.Sequence->Duration));
+
+ MPTrack.Clip = new SourceClip(m_Dict);
+ m_HeaderPart.AddChildObject(MPTrack.Clip);
+ MPTrack.Sequence->StructuralComponents.push_back(MPTrack.Clip->InstanceUID);
+ MPTrack.Clip->DataDefinition = DataDefinition;
+ MPTrack.Clip->SourcePackageID = SourcePackageUMID;
+ MPTrack.Clip->SourceTrackID = 2;
+ m_DurationUpdateList.push_back(&(MPTrack.Clip->Duration));
+
+
+ //
+ // File (Source) Package
+ //
+ m_FilePackage = new SourcePackage(m_Dict);
+ m_FilePackage->Name = PackageLabel.c_str();
+ m_FilePackage->PackageUID = SourcePackageUMID;
+ ECD->LinkedPackageUID = SourcePackageUMID;
+
+ m_HeaderPart.AddChildObject(m_FilePackage);
+ Storage->Packages.push_back(m_FilePackage->InstanceUID);
+
+ TrackSet<TimecodeComponent> FPTCTrack =
+ CreateTimecodeTrack<SourcePackage>(m_HeaderPart, *m_FilePackage,
+ EditRate, TCFrameRate,
+ ui64_C(3600) * TCFrameRate, m_Dict);
+ m_DurationUpdateList.push_back(&(FPTCTrack.Sequence->Duration));
+ m_DurationUpdateList.push_back(&(FPTCTrack.Clip->Duration));
+ TrackSet<SourceClip> FPTrack =
+ CreateTrackAndSequence<SourcePackage, SourceClip>(m_HeaderPart, *m_FilePackage,
+ TrackName, EditRate, DataDefinition,
+ 2, m_Dict);
+ m_DurationUpdateList.push_back(&(FPTrack.Sequence->Duration));
+
+ // Consult ST 379:2004 Sec. 6.3, "Element to track relationship" to see where "12" comes from.
+ FPTrack.Track->TrackNumber = KM_i32_BE(Kumu::cp2i<ui32_t>((EssenceUL.Value() + 12)));
+
+ FPTrack.Clip = new SourceClip(m_Dict);
+ m_HeaderPart.AddChildObject(FPTrack.Clip);
+ FPTrack.Sequence->StructuralComponents.push_back(FPTrack.Clip->InstanceUID);
+ FPTrack.Clip->DataDefinition = DataDefinition;
+
+ // for now we do not allow setting this value, so all files will be 'original'
+ FPTrack.Clip->SourceTrackID = 0;
+ FPTrack.Clip->SourcePackageID = NilUMID;
+ m_DurationUpdateList.push_back(&(FPTrack.Clip->Duration));
+
+ m_EssenceDescriptor->LinkedTrackID = FPTrack.Track->TrackID;
+}
+
+//
+void
+ASDCP::h__Writer::AddDMSegment(const MXF::Rational& EditRate, ui32_t TCFrameRate,
+ const std::string& TrackName, const UL& DataDefinition,
+ const std::string& PackageLabel)
+{
+ //
+ ContentStorage* Storage = new ContentStorage(m_Dict);
+ m_HeaderPart.AddChildObject(Storage);
+ m_HeaderPart.m_Preface->ContentStorage = Storage->InstanceUID;
+
+ EssenceContainerData* ECD = new EssenceContainerData(m_Dict);
+ m_HeaderPart.AddChildObject(ECD);
+ Storage->EssenceContainerData.push_back(ECD->InstanceUID);
+ ECD->IndexSID = 129;
+ ECD->BodySID = 1;
+
+ UUID assetUUID(m_Info.AssetUUID);
+ UMID SourcePackageUMID, MaterialPackageUMID;
+ SourcePackageUMID.MakeUMID(0x0f, assetUUID);
+ MaterialPackageUMID.MakeUMID(0x0f); // unidentified essence
+
+ //
+ // Material Package
+ //
+ m_MaterialPackage = new MaterialPackage(m_Dict);
+ m_MaterialPackage->Name = "AS-DCP Material Package";
+ m_MaterialPackage->PackageUID = MaterialPackageUMID;
+ m_HeaderPart.AddChildObject(m_MaterialPackage);
+ Storage->Packages.push_back(m_MaterialPackage->InstanceUID);
+
+ TrackSet<TimecodeComponent> MPTCTrack =
+ CreateTimecodeTrack<MaterialPackage>(m_HeaderPart, *m_MaterialPackage,
+ EditRate, TCFrameRate, 0, m_Dict);
+ m_DurationUpdateList.push_back(&(MPTCTrack.Sequence->Duration));
+ m_DurationUpdateList.push_back(&(MPTCTrack.Clip->Duration));
+
+ TrackSet<DMSegment> MPTrack =
+ CreateTrackAndSequence<MaterialPackage, DMSegment>(m_HeaderPart, *m_MaterialPackage,
+ TrackName, EditRate, DataDefinition,
+ 2, m_Dict);
+ m_DurationUpdateList.push_back(&(MPTrack.Sequence->Duration));
+
+ MPTrack.Clip = new DMSegment(m_Dict);
+ m_HeaderPart.AddChildObject(MPTrack.Clip);
+ MPTrack.Sequence->StructuralComponents.push_back(MPTrack.Clip->InstanceUID);
+ MPTrack.Clip->DataDefinition = DataDefinition;
+ // MPTrack.Clip->SourcePackageID = SourcePackageUMID;
+ // MPTrack.Clip->SourceTrackID = 2;
+ m_DurationUpdateList.push_back(&(MPTrack.Clip->Duration));
+
+
+ //
+ // File (Source) Package
+ //
+ m_FilePackage = new SourcePackage(m_Dict);
+ m_FilePackage->Name = PackageLabel.c_str();
+ m_FilePackage->PackageUID = SourcePackageUMID;
+ ECD->LinkedPackageUID = SourcePackageUMID;
+
+ m_HeaderPart.AddChildObject(m_FilePackage);
+ Storage->Packages.push_back(m_FilePackage->InstanceUID);
+
+ TrackSet<TimecodeComponent> FPTCTrack =
+ CreateTimecodeTrack<SourcePackage>(m_HeaderPart, *m_FilePackage,
+ EditRate, TCFrameRate,
+ ui64_C(3600) * TCFrameRate, m_Dict);
+ m_DurationUpdateList.push_back(&(FPTCTrack.Sequence->Duration));
+ m_DurationUpdateList.push_back(&(FPTCTrack.Clip->Duration));
+
+ TrackSet<DMSegment> FPTrack =
+ CreateTrackAndSequence<SourcePackage, DMSegment>(m_HeaderPart, *m_FilePackage,
+ TrackName, EditRate, DataDefinition,
+ 2, m_Dict);
+ m_DurationUpdateList.push_back(&(FPTrack.Sequence->Duration));
+
+ FPTrack.Clip = new DMSegment(m_Dict);
+ m_HeaderPart.AddChildObject(FPTrack.Clip);
+ FPTrack.Sequence->StructuralComponents.push_back(FPTrack.Clip->InstanceUID);
+ FPTrack.Clip->DataDefinition = DataDefinition;
+ FPTrack.Clip->EventComment = "D-Cinema Timed Text";
+
+ m_DurationUpdateList.push_back(&(FPTrack.Clip->Duration));
+ m_EssenceDescriptor->LinkedTrackID = FPTrack.Track->TrackID;
+}
+
+//
+void
+ASDCP::h__Writer::AddEssenceDescriptor(const UL& WrappingUL)
+{
+ //
+ // Essence Descriptor
+ //
+ m_EssenceDescriptor->EssenceContainer = WrappingUL;
+ m_HeaderPart.m_Preface->PrimaryPackage = m_FilePackage->InstanceUID;
+
+ //
+ // Essence Descriptors
+ //
+ assert(m_Dict);
+ UL GenericContainerUL(m_Dict->ul(MDD_GCMulti));
+ m_HeaderPart.EssenceContainers.push_back(GenericContainerUL);
+
+ if ( m_Info.EncryptedEssence )
+ {
+ UL CryptEssenceUL(m_Dict->ul(MDD_EncryptedContainerLabel));
+ m_HeaderPart.EssenceContainers.push_back(CryptEssenceUL);
+ m_HeaderPart.m_Preface->DMSchemes.push_back(UL(m_Dict->ul(MDD_CryptographicFrameworkLabel)));
+ AddDMScrypt(m_HeaderPart, *m_FilePackage, m_Info, WrappingUL, m_Dict);
+ }
+ else
+ {
+ m_HeaderPart.EssenceContainers.push_back(WrappingUL);
+ }
+
+ m_HeaderPart.m_Preface->EssenceContainers = m_HeaderPart.EssenceContainers;
+ m_HeaderPart.AddChildObject(m_EssenceDescriptor);
+
+ std::list<InterchangeObject*>::iterator sdli = m_EssenceSubDescriptorList.begin();
+ for ( ; sdli != m_EssenceSubDescriptorList.end(); sdli++ )
+ m_HeaderPart.AddChildObject(*sdli);
+
+ m_FilePackage->Descriptor = m_EssenceDescriptor->InstanceUID;
+}
+
+//
+Result_t
+ASDCP::h__Writer::CreateBodyPart(const MXF::Rational& EditRate, ui32_t BytesPerEditUnit)
+{
+ assert(m_Dict);
+ Result_t result = RESULT_OK;
+
+ // create a body partition if we're writing proper 429-3/OP-Atom
+ if ( m_Info.LabelSetType == LS_MXF_SMPTE )
+ {
+ // Body Partition
+ m_BodyPart.EssenceContainers = m_HeaderPart.EssenceContainers;
+ m_BodyPart.ThisPartition = m_File.Tell();
+ m_BodyPart.BodySID = 1;
+ UL OPAtomUL(m_Dict->ul(MDD_OPAtom));
+ m_BodyPart.OperationalPattern = OPAtomUL;
+ m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(1, m_BodyPart.ThisPartition)); // Second RIP Entry
+
+ UL BodyUL(m_Dict->ul(MDD_ClosedCompleteBodyPartition));
+ result = m_BodyPart.WriteToFile(m_File, BodyUL);
+ }
+ else
+ {
+ m_HeaderPart.BodySID = 1;
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ // Index setup
+ Kumu::fpos_t ECoffset = m_File.Tell();
+ m_FooterPart.IndexSID = 129;
+
+ if ( BytesPerEditUnit == 0 )
+ m_FooterPart.SetIndexParamsVBR(&m_HeaderPart.m_Primer, EditRate, ECoffset);
+ else
+ m_FooterPart.SetIndexParamsCBR(&m_HeaderPart.m_Primer, BytesPerEditUnit, EditRate);
+ }
+
+ return result;
+}
+
+//
+Result_t
+ASDCP::h__Writer::WriteMXFHeader(const std::string& PackageLabel, const UL& WrappingUL,
+ const std::string& TrackName, const UL& EssenceUL, const UL& DataDefinition,
+ const MXF::Rational& EditRate, ui32_t TCFrameRate, ui32_t BytesPerEditUnit)
+{
+ InitHeader();
+ AddSourceClip(EditRate, TCFrameRate, TrackName, EssenceUL, DataDefinition, PackageLabel);
+ AddEssenceDescriptor(WrappingUL);
+
+ Result_t result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize);
+
+ if ( KM_SUCCESS(result) )
+ result = CreateBodyPart(EditRate, BytesPerEditUnit);
+
+ return result;
+}
+
+
+// standard method of writing a plaintext or encrypted frame
+Result_t
+ASDCP::h__Writer::WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf, const byte_t* EssenceUL,
+ AESEncContext* Ctx, HMACContext* HMAC, std::string* hash)
+{
+ Result_t result = RESULT_OK;
+ IntegrityPack IntPack;
+
+ m_File.StartHashing();
+
+ byte_t overhead[128];
+ Kumu::MemIOWriter Overhead(overhead, 128);
+ assert(m_Dict);
+
+ if ( FrameBuf.Size() == 0 )
+ {
+ DefaultLogSink().Error("Cannot write empty frame buffer\n");
+ return RESULT_EMPTY_FB;
+ }
+
+ if ( m_Info.EncryptedEssence )
+ {
+ if ( ! Ctx )
+ return RESULT_CRYPT_CTX;
+
+ if ( m_Info.UsesHMAC && ! HMAC )
+ return RESULT_HMAC_CTX;
+
+ if ( FrameBuf.PlaintextOffset() > FrameBuf.Size() )
+ return RESULT_LARGE_PTO;
+
+ // encrypt the essence data (create encrypted source value)
+ result = EncryptFrameBuffer(FrameBuf, m_CtFrameBuf, Ctx);
+
+ // create HMAC
+ if ( ASDCP_SUCCESS(result) && m_Info.UsesHMAC )
+ result = IntPack.CalcValues(m_CtFrameBuf, m_Info.AssetUUID, m_FramesWritten + 1, HMAC);
+
+ if ( ASDCP_SUCCESS(result) )
+ { // write UL
+ Overhead.WriteRaw(m_Dict->ul(MDD_CryptEssence), SMPTE_UL_LENGTH);
+
+ // construct encrypted triplet header
+ ui32_t ETLength = klv_cryptinfo_size + m_CtFrameBuf.Size();
+ ui32_t BER_length = MXF_BER_LENGTH;
+
+ if ( m_Info.UsesHMAC )
+ ETLength += klv_intpack_size;
+ else
+ ETLength += (MXF_BER_LENGTH * 3); // for empty intpack
+
+ if ( ETLength > 0x00ffffff ) // Need BER integer longer than MXF_BER_LENGTH bytes
+ {
+ BER_length = Kumu::get_BER_length_for_value(ETLength);
+
+ // the packet is longer by the difference in expected vs. actual BER length
+ ETLength += BER_length - MXF_BER_LENGTH;
+
+ if ( BER_length == 0 )
+ result = RESULT_KLV_CODING;
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ if ( ! ( Overhead.WriteBER(ETLength, BER_length) // write encrypted triplet length
+ && Overhead.WriteBER(UUIDlen, MXF_BER_LENGTH) // write ContextID length
+ && Overhead.WriteRaw(m_Info.ContextID, UUIDlen) // write ContextID
+ && Overhead.WriteBER(sizeof(ui64_t), MXF_BER_LENGTH) // write PlaintextOffset length
+ && Overhead.WriteUi64BE(FrameBuf.PlaintextOffset()) // write PlaintextOffset
+ && Overhead.WriteBER(SMPTE_UL_LENGTH, MXF_BER_LENGTH) // write essence UL length
+ && Overhead.WriteRaw((byte_t*)EssenceUL, SMPTE_UL_LENGTH) // write the essence UL
+ && Overhead.WriteBER(sizeof(ui64_t), MXF_BER_LENGTH) // write SourceLength length
+ && Overhead.WriteUi64BE(FrameBuf.Size()) // write SourceLength
+ && Overhead.WriteBER(m_CtFrameBuf.Size(), BER_length) ) ) // write ESV length
+ {
+ result = RESULT_KLV_CODING;
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ result = m_File.Writev(Overhead.Data(), Overhead.Length());
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ m_StreamOffset += Overhead.Length();
+ // write encrypted source value
+ result = m_File.Writev((byte_t*)m_CtFrameBuf.RoData(), m_CtFrameBuf.Size());
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ m_StreamOffset += m_CtFrameBuf.Size();
+
+ byte_t hmoverhead[512];
+ Kumu::MemIOWriter HMACOverhead(hmoverhead, 512);
+
+ // write the HMAC
+ if ( m_Info.UsesHMAC )
+ {
+ HMACOverhead.WriteRaw(IntPack.Data, klv_intpack_size);
+ }
+ else
+ { // we still need the var-pack length values if the intpack is empty
+ for ( ui32_t i = 0; i < 3 ; i++ )
+ HMACOverhead.WriteBER(0, MXF_BER_LENGTH);
+ }
+
+ // write HMAC
+ result = m_File.Writev(HMACOverhead.Data(), HMACOverhead.Length());
+ m_StreamOffset += HMACOverhead.Length();
+ }
+ }
+ else
+ {
+ ui32_t BER_length = MXF_BER_LENGTH;
+
+ if ( FrameBuf.Size() > 0x00ffffff ) // Need BER integer longer than MXF_BER_LENGTH bytes
+ {
+ BER_length = Kumu::get_BER_length_for_value(FrameBuf.Size());
+
+ if ( BER_length == 0 )
+ result = RESULT_KLV_CODING;
+ }
+
+ Overhead.WriteRaw((byte_t*)EssenceUL, SMPTE_UL_LENGTH);
+ Overhead.WriteBER(FrameBuf.Size(), BER_length);
+
+ if ( ASDCP_SUCCESS(result) )
+ 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.Length() + FrameBuf.Size();
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ result = m_File.Writev();
+
+ if (hash) {
+ *hash = m_File.StopHashing();
+ }
+
+ return result;
+}
+
+Result_t
+ASDCP::h__Writer::FakeWriteEKLVPacket(int size)
+{
+ Result_t result = RESULT_OK;
+
+ m_StreamOffset += size;
+ m_File.Seek(size, Kumu::SP_POS);
+
+ return result;
+}
+
+
+// standard method of writing the header and footer of a completed MXF file
+//
+Result_t
+ASDCP::h__Writer::WriteMXFFooter()
+{
+ // Set top-level file package correctly for OP-Atom
+
+ // m_MPTCSequence->Duration = m_MPTimecode->Duration = m_MPClSequence->Duration = m_MPClip->Duration =
+ // m_FPTCSequence->Duration = m_FPTimecode->Duration = m_FPClSequence->Duration = m_FPClip->Duration =
+
+ DurationElementList_t::iterator dli = m_DurationUpdateList.begin();
+
+ for (; dli != m_DurationUpdateList.end(); dli++ )
+ **dli = m_FramesWritten;
+
+ m_EssenceDescriptor->ContainerDuration = m_FramesWritten;
+ m_FooterPart.PreviousPartition = m_HeaderPart.m_RIP.PairArray.back().ByteOffset;
+
+ Kumu::fpos_t here = m_File.Tell();
+ m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(0, here)); // Last RIP Entry
+ m_HeaderPart.FooterPartition = here;
+
+ assert(m_Dict);
+ // re-label the partition
+ UL OPAtomUL(m_Dict->ul(MDD_OPAtom));
+ m_HeaderPart.OperationalPattern = OPAtomUL;
+ m_HeaderPart.m_Preface->OperationalPattern = m_HeaderPart.OperationalPattern;
+
+ m_FooterPart.OperationalPattern = m_HeaderPart.OperationalPattern;
+ m_FooterPart.EssenceContainers = m_HeaderPart.EssenceContainers;
+ m_FooterPart.FooterPartition = here;
+ m_FooterPart.ThisPartition = here;
+
+ Result_t result = m_FooterPart.WriteToFile(m_File, m_FramesWritten);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = m_HeaderPart.m_RIP.WriteToFile(m_File);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = m_File.Seek(0);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize);
+
+ m_File.Close();
+ return result;
+}
+
+//
+// end h__Writer.cpp
+//
diff --git a/asdcplib/src/j2c-test.cpp b/asdcplib/src/j2c-test.cpp
new file mode 100755
index 0000000..8f02826
--- /dev/null
+++ b/asdcplib/src/j2c-test.cpp
@@ -0,0 +1,234 @@
+/*
+Copyright (c) 2005-2010, 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 j2c-test.cpp
+ \version $Id: j2c-test.cpp,v 1.6 2010/06/17 20:11:42 jhurst Exp $
+ \brief JP2K parser test
+*/
+
+#include <AS_DCP.h>
+#include <KM_fileio.h>
+#include <KM_util.h>
+#include <JP2K.h>
+
+using namespace Kumu;
+using namespace ASDCP;
+using namespace ASDCP::JP2K;
+
+
+
+//------------------------------------------------------------------------------------------
+//
+// command line option parser class
+
+static const char* PROGRAM_NAME = "j2c-test"; // 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-2010 John Hurst\n\n\
+%s 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",
+ PROGRAM_NAME, ASDCP::Version(), PROGRAM_NAME, PROGRAM_NAME);
+}
+
+//
+void
+usage(FILE* stream = stderr)
+{
+ fprintf(stream, "\
+USAGE: %s [-h|-help] [-V]\n\
+\n\
+ %s [-r] [-v] <filename> [...]\n\
+\n\
+ -V - Show version\n\
+ -h - Show help\n\
+ -r - Show raw data\n\
+ -v - Print extra detail\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", PROGRAM_NAME, PROGRAM_NAME);
+}
+
+//
+//
+class CommandOptions
+{
+ CommandOptions();
+
+public:
+ bool error_flag; // true if the given options are in error or not complete
+ bool version_flag; // true if the version display option was selected
+ bool verbose_flag; // true if the verbose option was selected
+ bool detail_flag; // true if the version display option was selected
+ bool help_flag; // true if the help display option was selected
+ std::list<std::string> filename_list;
+
+ CommandOptions(int argc, const char** argv) :
+ error_flag(true), version_flag(false), verbose_flag(false),
+ detail_flag(false), help_flag(false)
+ {
+ 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 'r': detail_flag = true; break;
+ case 'v': verbose_flag = true; break;
+
+ default:
+ fprintf(stderr, "Unrecognized option: %c\n", argv[i][1]);
+ return;
+ }
+ }
+ else
+ {
+ filename_list.push_back(argv[i]);
+ }
+ }
+
+ if ( filename_list.empty() )
+ {
+ fputs("Input j2c filename(s) required.\n", stderr);
+ return;
+ }
+
+ error_flag = false;
+ }
+};
+
+
+
+
+//
+int
+main(int argc, const char** argv)
+{
+ CommandOptions Options(argc, argv);
+
+ if ( Options.version_flag )
+ banner();
+
+ if ( Options.help_flag )
+ usage();
+
+ if ( Options.version_flag || Options.help_flag )
+ return 0;
+
+ if ( Options.error_flag )
+ {
+ fprintf(stderr, "There was a problem. Type %s -h for help.\n", PROGRAM_NAME);
+ return 3;
+ }
+
+ ASDCP::JP2K::FrameBuffer FB;
+ Marker MyMarker;
+ CodestreamParser Parser;
+ std::list<std::string>::iterator i;
+
+ Result_t result = FB.Capacity(1024*1024*4);
+
+ for ( i = Options.filename_list.begin(); ASDCP_SUCCESS(result) && i != Options.filename_list.end(); i++ )
+ {
+ result = Parser.OpenReadFrame(i->c_str(), FB);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ const byte_t* p = FB.RoData();
+ const byte_t* end_p = p + FB.Size();
+
+ while ( p < end_p && ASDCP_SUCCESS(GetNextMarker(&p, MyMarker)) )
+ {
+ if ( Options.verbose_flag )
+ {
+ MyMarker.Dump(stdout);
+
+ if ( Options.detail_flag )
+ hexdump(MyMarker.m_Data - 2, MyMarker.m_DataSize + 2, stdout);
+ }
+
+ switch ( MyMarker.m_Type )
+ {
+ case MRK_SOD:
+ p = end_p;
+ break;
+
+ case MRK_SIZ:
+ {
+ Accessor::SIZ SIZ_(MyMarker);
+ SIZ_.Dump(stdout);
+ }
+ break;
+
+ case MRK_COM:
+ {
+ Accessor::COM COM_(MyMarker);
+ COM_.Dump(stdout);
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ if ( ASDCP_FAILURE(result) )
+ {
+ fputs("Program stopped on error.\n", stderr);
+
+ if ( result != RESULT_FAIL )
+ {
+ fputs(result, stderr);
+ fputc('\n', stderr);
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+//
+// end j2c-test.cpp
+//
diff --git a/asdcplib/src/jp2k-crypt-tst.sh b/asdcplib/src/jp2k-crypt-tst.sh
new file mode 100755
index 0000000..1836fef
--- /dev/null
+++ b/asdcplib/src/jp2k-crypt-tst.sh
@@ -0,0 +1,58 @@
+#!/bin/sh
+#
+# $Id: jp2k-crypt-tst.sh,v 1.4 2009/04/09 19:16:49 msheby Exp $
+# Copyright (c) 2007-2009 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.
+
+# crypto JPEG 2000 tests
+
+${BUILD_DIR}/asdcp-test${EXEEXT} -k ${CRYPT_KEY} \
+ -c ${TEST_FILES}/write_crypt_test_jp2k.mxf ${TEST_FILES}/${TEST_FILE_PREFIX}
+if [ $? -ne 0 ]; then
+ exit 1
+fi
+${BUILD_DIR}/asdcp-test${EXEEXT} -i ${TEST_FILES}/write_crypt_test_jp2k.mxf
+if [ $? -ne 0 ]; then
+ exit 1
+fi
+
+
+(${BUILD_DIR}/asdcp-test${EXEEXT} -k ${CRYPT_KEY_B} \
+ -x ${TEST_FILES}/plaintext ${TEST_FILES}/write_crypt_test_jp2k.mxf; \
+ if [ $? -eq 1 ]; then exit 0; fi; exit 1 )
+if [ $? -ne 0 ]; then
+ exit 1
+fi
+${BUILD_DIR}/asdcp-test${EXEEXT} -m -k ${CRYPT_KEY} \
+ -x ${TEST_FILES}/plaintext/${JP2K_PREFIX} ${TEST_FILES}/write_crypt_test_jp2k.mxf
+if [ $? -ne 0 ]; then
+ exit 1
+fi
+for file in `ls ${TEST_FILES}/${TEST_FILE_PREFIX}`; do \
+ echo "$file"; \
+ cmp ${TEST_FILES}/${TEST_FILE_PREFIX}/$file ${TEST_FILES}/plaintext/$file; \
+ if [ $? -ne 0 ]; then \
+ exit 1; \
+ fi; \
+done
diff --git a/asdcplib/src/jp2k-stereo-crypt-tst.sh b/asdcplib/src/jp2k-stereo-crypt-tst.sh
new file mode 100755
index 0000000..e8324a0
--- /dev/null
+++ b/asdcplib/src/jp2k-stereo-crypt-tst.sh
@@ -0,0 +1,56 @@
+#!/bin/sh
+#
+# $Id: jp2k-stereo-crypt-tst.sh,v 1.4 2009/04/09 19:16:49 msheby Exp $
+# Copyright (c) 2007-2009 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.
+
+# crypto JPEG 2000 stereoscopic tests
+
+${BUILD_DIR}/asdcp-test${EXEEXT} -k ${CRYPT_KEY} \
+ -3 -c ${TEST_FILES}/write_crypt_test_jp2k.mxf \
+ ${TEST_FILES}/${TEST_FILE_PREFIX} ${TEST_FILES}/${TEST_FILE_PREFIX}
+if [ $? -ne 0 ]; then
+ exit 1
+fi
+${BUILD_DIR}/asdcp-test${EXEEXT} -i ${TEST_FILES}/write_crypt_test_jp2k.mxf
+if [ $? -ne 0 ]; then
+ exit 1
+fi
+
+
+(${BUILD_DIR}/asdcp-test${EXEEXT} -k ${CRYPT_KEY_B} \
+ -3 -x ${TEST_FILES}/plaintext ${TEST_FILES}/write_crypt_test_jp2k.mxf; \
+ if [ $? -eq 1 ]; then exit 0; fi; exit 1 )
+${BUILD_DIR}/asdcp-test${EXEEXT} -m -k ${CRYPT_KEY} \
+ -3 -x ${TEST_FILES}/plaintext/${JP2K_PREFIX} ${TEST_FILES}/write_crypt_test_jp2k.mxf
+if [ $? -ne 0 ]; then
+ exit 1
+fi
+for file in `ls ${TEST_FILES}/${TEST_FILE_PREFIX}`; do \
+ echo "$file"; \
+ cmp ${TEST_FILES}/${TEST_FILE_PREFIX}/$file ${TEST_FILES}/plaintext/$file; \
+ if [ $? -ne 0 ]; then \
+ exit 1; \
+ fi; \
+done
diff --git a/asdcplib/src/jp2k-stereo-tst.sh b/asdcplib/src/jp2k-stereo-tst.sh
new file mode 100755
index 0000000..eacd090
--- /dev/null
+++ b/asdcplib/src/jp2k-stereo-tst.sh
@@ -0,0 +1,47 @@
+#!/bin/sh
+#
+# $Id: jp2k-stereo-tst.sh,v 1.3 2009/04/09 19:16:49 msheby Exp $
+# Copyright (c) 2007-2009 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.
+
+# JPEG 2000 stereoscopic tests
+
+${BUILD_DIR}/asdcp-test${EXEEXT} -3 -c ${TEST_FILES}/write_test_jp2k.mxf \
+ ${TEST_FILES}/${TEST_FILE_PREFIX} ${TEST_FILES}/${TEST_FILE_PREFIX}
+if [ $? -ne 0 ]; then
+ exit 1
+fi
+
+
+${BUILD_DIR}/asdcp-test${EXEEXT} -3 -x ${TEST_FILES}/extract/${JP2K_PREFIX} ${TEST_FILES}/write_test_jp2k.mxf
+if [ $? -ne 0 ]; then
+ exit 1
+fi
+for file in `ls ${TEST_FILES}/${TEST_FILE_PREFIX}`; do \
+ echo "$file"; \
+ cmp ${TEST_FILES}/${TEST_FILE_PREFIX}/$file ${TEST_FILES}/extract/$file; \
+ if [ $? -ne 0 ]; then \
+ exit 1; \
+ fi; \
+done
diff --git a/asdcplib/src/jp2k-tst.sh b/asdcplib/src/jp2k-tst.sh
new file mode 100755
index 0000000..ee8a18d
--- /dev/null
+++ b/asdcplib/src/jp2k-tst.sh
@@ -0,0 +1,54 @@
+#!/bin/sh
+#
+# $Id: jp2k-tst.sh,v 1.5 2010/01/05 04:12:15 jhurst Exp $
+# Copyright (c) 2007-2009 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.
+
+# JPEG 2000 tests
+
+mkdir -p ${TEST_FILES}/extract ${TEST_FILES}/plaintext
+
+${BUILD_DIR}/asdcp-test${EXEEXT} -c ${TEST_FILES}/write_test_jp2k.mxf ${TEST_FILES}/${TEST_FILE_PREFIX}
+if [ $? -ne 0 ]; then
+ exit 1
+fi
+
+
+${BUILD_DIR}/asdcp-test${EXEEXT} -x ${TEST_FILES}/extract/${JP2K_PREFIX} ${TEST_FILES}/write_test_jp2k.mxf
+if [ $? -ne 0 ]; then
+ exit 1
+fi
+for file in `ls ${TEST_FILES}/${TEST_FILE_PREFIX}`; do \
+ echo "$file"; \
+ cmp ${TEST_FILES}/${TEST_FILE_PREFIX}/$file ${TEST_FILES}/extract/$file; \
+ if [ $? -ne 0 ]; then \
+ exit 1; \
+ fi; \
+done
+
+
+#${BUILD_DIR}/j2c-test${EXEEXT} ${TEST_FILES}/${TEST_FILE_PREFIX}/MM_2k_XYZ_000000.j2c
+#if [ $? -ne 0 ]; then
+# exit 1
+#fi
diff --git a/asdcplib/src/klvwalk.cpp b/asdcplib/src/klvwalk.cpp
new file mode 100755
index 0000000..299cb02
--- /dev/null
+++ b/asdcplib/src/klvwalk.cpp
@@ -0,0 +1,287 @@
+/*
+Copyright (c) 2005-2009, 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 klvwalk.cpp
+ \version $Id: klvwalk.cpp,v 1.18 2010/11/15 17:04:13 jhurst Exp $
+ \brief KLV+MXF test
+*/
+
+#include "AS_DCP.h"
+#include "MXF.h"
+#include <KM_log.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+using namespace ASDCP;
+using Kumu::DefaultLogSink;
+
+
+//------------------------------------------------------------------------------------------
+//
+// command line option parser class
+
+static const char* PROGRAM_NAME = "klvwalk"; // program name for messages
+typedef std::list<std::string> FileList_t;
+
+// 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 = stdout)
+{
+ fprintf(stream, "\n\
+%s (asdcplib %s)\n\n\
+Copyright (c) 2005-2009 John Hurst\n\
+%s is part of the asdcplib DCP tools package.\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",
+ PROGRAM_NAME, ASDCP::Version(), PROGRAM_NAME, PROGRAM_NAME);
+}
+
+//
+void
+usage(FILE* stream = stdout)
+{
+ fprintf(stream, "\
+USAGE: %s [-r] [-v] <input-file> [<input-file2> ...]\n\
+\n\
+ %s [-h|-help] [-V]\n\
+\n\
+ -h | -help - Show help\n\
+ -r - When KLV data is an MXF OPAtom file, display OPAtom headers\n\
+ -v - Verbose. Prints informative messages to stderr\n\
+ -V - Show version information\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", PROGRAM_NAME, PROGRAM_NAME);
+}
+
+//
+//
+ class CommandOptions
+ {
+ CommandOptions();
+
+ public:
+ bool error_flag; // true if the given options are in error or not complete
+ 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 if the informative messages option was selected
+ bool read_mxf_flag; // true if the -r option was selected
+ FileList_t inFileList; // File to operate on
+
+ CommandOptions(int argc, const char** argv) :
+ error_flag(true), version_flag(false), help_flag(false), verbose_flag(false), read_mxf_flag(false)
+ {
+ for ( int i = 1; i < argc; i++ )
+ {
+
+ if ( (strcmp( argv[i], "-help") == 0) )
+ {
+ help_flag = true;
+ continue;
+ }
+
+ if ( argv[i][0] == '-' && isalpha(argv[i][1]) && argv[i][2] == 0 )
+ {
+ switch ( argv[i][1] )
+ {
+ case 'h': help_flag = true; break;
+ case 'r': read_mxf_flag = true; break;
+ case 'V': version_flag = true; break;
+ case 'v': verbose_flag = true; break;
+
+ default:
+ fprintf(stderr, "Unrecognized option: %s\n", argv[i]);
+ return;
+ }
+ }
+ else
+ {
+ if ( argv[i][0] != '-' )
+ inFileList.push_back(argv[i]);
+
+ else
+ {
+ fprintf(stderr, "Unrecognized option: %s\n", argv[i]);
+ return;
+ }
+ }
+ }
+
+ if ( help_flag || version_flag )
+ return;
+
+ if ( inFileList.empty() )
+ {
+ fputs("Input filename(s) required.\n", stderr);
+ return;
+ }
+
+ error_flag = false;
+ }
+ };
+
+
+//---------------------------------------------------------------------------------------------------
+//
+
+int
+main(int argc, const char** argv)
+{
+ CommandOptions Options(argc, argv);
+
+ if ( Options.version_flag )
+ banner();
+
+ if ( Options.help_flag )
+ usage();
+
+ if ( Options.version_flag || Options.help_flag )
+ return 0;
+
+ if ( Options.error_flag )
+ {
+ fprintf(stderr, "There was a problem. Type %s -h for help.\n", PROGRAM_NAME);
+ return 3;
+ }
+
+ FileList_t::iterator fi;
+ Result_t result = RESULT_OK;
+
+ for ( fi = Options.inFileList.begin(); ASDCP_SUCCESS(result) && fi != Options.inFileList.end(); fi++ )
+ {
+ if (Options.verbose_flag)
+ fprintf(stderr, "Opening file %s\n", ((*fi).c_str()));
+
+ if ( Options.read_mxf_flag ) // dump MXF
+ {
+ Kumu::FileReader Reader;
+ const Dictionary* Dict = &DefaultCompositeDict();
+ ASDCP::MXF::OPAtomHeader Header(Dict);
+
+ result = Reader.OpenRead((*fi).c_str());
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Header.InitFromFile(Reader);
+
+ if ( ASDCP_SUCCESS(result) )
+ Header.Dump(stdout);
+
+ if ( ASDCP_SUCCESS(result) && Header.m_RIP.PairArray.size() > 2 )
+ {
+ MXF::Array<MXF::RIP::Pair>::const_iterator pi = Header.m_RIP.PairArray.begin();
+
+ for ( pi++; pi != Header.m_RIP.PairArray.end() && ASDCP_SUCCESS(result); pi++ )
+ {
+ result = Reader.Seek((*pi).ByteOffset);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ MXF::Partition TmpPart(Dict);
+ result = TmpPart.InitFromFile(Reader);
+
+ if ( ASDCP_SUCCESS(result) && TmpPart.BodySID > 0 )
+ TmpPart.Dump(stdout);
+ }
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ ASDCP::MXF::OPAtomIndexFooter Index(Dict);
+ result = Reader.Seek(Header.FooterPartition);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ Index.m_Lookup = &Header.m_Primer;
+ result = Index.InitFromFile(Reader);
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ Index.Dump(stdout);
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ Header.m_RIP.Dump(stdout);
+ }
+ else // dump klv
+ {
+ Kumu::FileReader Reader;
+ KLVFilePacket KP;
+ ui64_t pos = 0;
+
+ result = Reader.OpenRead((*fi).c_str());
+
+ if ( ASDCP_SUCCESS(result) )
+ result = KP.InitFromFile(Reader);
+
+ while ( ASDCP_SUCCESS(result) )
+ {
+ fprintf(stdout, "@0x%08qx: ", pos);
+ KP.Dump(stdout, DefaultCompositeDict(), true);
+ pos = Reader.Tell();
+ result = KP.InitFromFile(Reader);
+ }
+
+ if( result == RESULT_ENDOFFILE )
+ result = RESULT_OK;
+ }
+ }
+
+ if ( ASDCP_FAILURE(result) )
+ {
+ fputs("Program stopped on error.\n", stderr);
+
+ if ( result != RESULT_FAIL )
+ {
+ fputs(result, stderr);
+ fputc('\n', stderr);
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+
+//
+// end klvwalk.cpp
+//
diff --git a/asdcplib/src/kmfilegen.cpp b/asdcplib/src/kmfilegen.cpp
new file mode 100755
index 0000000..fb4360e
--- /dev/null
+++ b/asdcplib/src/kmfilegen.cpp
@@ -0,0 +1,616 @@
+/*
+Copyright (c) 2005-2009, 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 kmfilegen.cpp
+ \version $Id: kmfilegen.cpp,v 1.8 2009/03/04 17:52:45 jhurst Exp $
+ \brief large file test program
+*/
+
+
+#include "AS_DCP.h"
+#include <iostream>
+#include <KM_fileio.h>
+#include <KM_prng.h>
+#include <openssl/aes.h>
+#include <assert.h>
+
+using namespace Kumu;
+
+// constants
+static const char* PROGRAM_NAME = "kmfilegen"; // program name for messages
+const ui32_t RNG_KEY_SIZE = 16;
+const ui32_t RNG_KEY_SIZE_BITS = 128;
+const ui32_t RNG_BLOCK_SIZE = 16;
+
+// globals
+ui32_t s_Nonce = 0;
+FortunaRNG s_RNG;
+
+
+//------------------------------------------------------------------------------------------
+//
+// command line option parser class
+
+// 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 = stdout)
+{
+ fprintf(stream, "\n\
+%s (asdcplib %s)\n\n\
+Copyright (c) 2005-2009 John Hurst\n\
+%s is part of the asdcplib DCP tools package.\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",
+ PROGRAM_NAME, Kumu::Version(), PROGRAM_NAME, PROGRAM_NAME);
+}
+
+
+//
+void
+usage(FILE* stream = stdout)
+{
+ fprintf(stream, "\
+USAGE: %s [-c <file-size>] [-v] <output-file>\n\
+\n\
+ %s [-o <fwd|rev|rand>] [-v] <input-file>\n\
+\n\
+ %s [-w <output-file>] [-v] <input-file>\n\
+\n\
+ %s [-h|-help] [-V]\n\
+\n\
+ -c <file-size> - Create test file containing <file-size> megabytes of data\n\
+ -h | -help - Show help\n\
+ -o <fwd|rev|rand> - Specify order used when validating a file.\n\
+ One of fwd|rev|rand, default is rand\n\
+ -v - Verbose. Prints informative messages to stderr\n\
+ -V - Show version information\n\
+ -w <output-file> - Read-Validate-Write - file is written to <output-file>\n\
+ (sequential read only)\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", PROGRAM_NAME, PROGRAM_NAME, PROGRAM_NAME, PROGRAM_NAME);
+}
+
+enum MajorMode_t {
+ MMT_NONE,
+ MMT_CREATE,
+ MMT_VALIDATE,
+ MMT_VAL_WRITE
+};
+
+//
+class CommandOptions
+{
+ CommandOptions();
+
+public:
+ bool error_flag; // true if the given options are in error or not complete
+ const char* order; // one of fwd|rev|rand
+ 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
+ const char* filename; // filename to be processed
+ const char* write_filename; // filename to write with val_write_flag
+ ui32_t chunk_count;
+ MajorMode_t mode; // MajorMode selector
+
+ //
+ CommandOptions(int argc, const char** argv) :
+ error_flag(true), order(""), verbose_flag(false), version_flag(false), help_flag(false),
+ filename(""), write_filename(""), chunk_count(0), mode(MMT_VALIDATE)
+ {
+ // order = "rand";
+
+ for ( int i = 1; i < argc; i++ )
+ {
+
+ if ( (strcmp( argv[i], "-help") == 0) )
+ {
+ help_flag = true;
+ continue;
+ }
+
+ if ( argv[i][0] == '-' && isalpha(argv[i][1]) && argv[i][2] == 0 )
+ {
+ switch ( argv[i][1] )
+ {
+ case 'c':
+ mode = MMT_CREATE;
+ TEST_EXTRA_ARG(i, 'c');
+ chunk_count = atoi(argv[i]);
+ break;
+
+ case 'V': version_flag = true; break;
+ case 'h': help_flag = true; break;
+ case 'v': verbose_flag = true; break;
+
+ case 'o':
+ TEST_EXTRA_ARG(i, 'o');
+ order = argv[i];
+
+ if ( strcmp(order, "fwd" ) != 0
+ && strcmp(order, "rev" ) != 0
+ && strcmp(order, "rand" ) != 0 )
+ {
+ fprintf(stderr, "Unexpected order token: %s, expecting fwd|rev|rand\n", order);
+ return;
+ }
+
+ break;
+
+ case 'w':
+ mode = MMT_VAL_WRITE;
+ TEST_EXTRA_ARG(i, 'w');
+ write_filename = argv[i];
+ break;
+
+ default:
+ fprintf(stderr, "Unrecognized option: %s\n", argv[i]);
+ return;
+ }
+ }
+ else
+ {
+ if (argv[i][0] != '-' )
+ {
+ if ( filename != "" )
+ {
+ fprintf(stderr, "Extra filename found: %s\n", argv[i]);
+ return;
+ }
+ else
+ filename = argv[i];
+ }
+ else
+ {
+ fprintf(stderr, "Unrecognized option: %s\n", argv[i]);
+ return;
+ }
+ }
+ }
+
+ if ( help_flag || version_flag )
+ return;
+
+ if ( strlen ( filename ) == 0 )
+ {
+ fprintf(stderr, "Filename required.\n");
+ return;
+ }
+
+ if ( mode != MMT_VALIDATE && strcmp(order, "") != 0 )
+ {
+ fprintf(stderr, "-o option not valid with -c or -w options.\n");
+ return;
+ }
+ else
+ if ( strcmp(order, "") == 0 )
+ order = "rand";
+
+ if ( strcmp ( filename, write_filename ) == 0 )
+ {
+ fprintf(stderr, "Output and input files must be different.\n");
+ return;
+ }
+
+ error_flag = false;
+ }
+};
+
+//------------------------------------------------------------------------------------------
+
+
+//
+#pragma pack(4)
+class CTR_Setup
+{
+ AES_KEY m_Context;
+ byte_t m_key[RNG_KEY_SIZE];
+ byte_t m_preamble[8];
+ ui32_t m_nonce;
+ ui32_t m_ctr;
+
+ KM_NO_COPY_CONSTRUCT(CTR_Setup);
+
+public:
+ CTR_Setup() {}
+ ~CTR_Setup() {}
+
+ inline ui32_t Nonce() { return KM_i32_LE(m_nonce); }
+ inline ui32_t WriteSize() { return ( sizeof(m_key) + sizeof(m_preamble)
+ + sizeof(m_nonce) + sizeof(m_ctr) ); }
+
+ //
+ void SetupWrite(byte_t* buf)
+ {
+ assert(buf);
+ s_RNG.FillRandom(m_key, WriteSize());
+ assert(s_Nonce > 0);
+ m_nonce = KM_i32_LE(s_Nonce--);
+ m_ctr &= KM_i32_LE(0x7fffffff); // make sure we have 2GB headroom
+ memcpy(buf, m_key, WriteSize());
+ AES_set_encrypt_key(m_key, RNG_KEY_SIZE_BITS, &m_Context);
+ }
+
+ //
+ void SetupRead(const byte_t* buf)
+ {
+ assert(buf);
+ memcpy(m_key, buf, WriteSize());
+ AES_set_encrypt_key(m_key, RNG_KEY_SIZE_BITS, &m_Context);
+ }
+
+ //
+ void FillRandom(byte_t* buf, ui32_t buf_len)
+ {
+ ui32_t gen_count = 0;
+ while ( gen_count + RNG_BLOCK_SIZE <= buf_len )
+ {
+ AES_encrypt(m_preamble, buf + gen_count, &m_Context);
+ m_ctr = KM_i32_LE(KM_i32_LE(m_ctr) + 1);
+ gen_count += RNG_BLOCK_SIZE;
+ }
+ }
+};
+
+//
+Result_t
+CreateLargeFile(CommandOptions& Options)
+{
+ ui32_t write_total = 0;
+ ui32_t write_count = 0;
+ FileWriter Writer;
+ ByteString FB;
+
+ FB.Capacity(Megabyte);
+ assert(FB.Capacity() == Megabyte);
+
+ fprintf(stderr, "Writing %u chunks:\n", Options.chunk_count);
+ s_Nonce = Options.chunk_count;
+ Result_t result = Writer.OpenWrite(Options.filename);
+
+ while ( KM_SUCCESS(result) && write_total < Options.chunk_count )
+ {
+ if ( KM_SUCCESS(result))
+ {
+ CTR_Setup CTR;
+ CTR.SetupWrite(FB.Data());
+ CTR.FillRandom(FB.Data() + CTR.WriteSize(), Megabyte - CTR.WriteSize());
+ result = Writer.Write(FB.RoData(), Megabyte, &write_count);
+ assert(write_count == Megabyte);
+ fprintf(stderr, "\r%8u ", ++write_total);
+ }
+ }
+
+ fputs("\n", stderr);
+
+ return result;
+}
+
+//
+Result_t
+validate_chunk(ByteString& FB, ByteString& CB, ui32_t* nonce_value)
+{
+ assert(nonce_value);
+ CTR_Setup CTR;
+ CTR.SetupRead(FB.RoData());
+
+ CTR.FillRandom(CB.Data() + CTR.WriteSize(),
+ Megabyte - CTR.WriteSize());
+
+ if ( memcmp(FB.RoData() + CTR.WriteSize(),
+ CB.RoData() + CTR.WriteSize(),
+ Megabyte - CTR.WriteSize()) != 0 )
+ {
+ fprintf(stderr, "Check data mismatched in chunk\n");
+ return RESULT_FAIL;
+ }
+
+ *nonce_value = CTR.Nonce();
+
+ return RESULT_OK;
+}
+
+//
+struct read_list_t
+{
+ ui32_t nonce;
+ Kumu::fpos_t position;
+};
+
+//
+void
+randomize_list(read_list_t* read_list, ui32_t check_total)
+{
+ static ui32_t tmp_ints[4];
+ static ui32_t seq = 0;
+
+ for ( ui32_t j = 0; j < check_total; j++ )
+ {
+ if ( seq > 3 )
+ seq = 0;
+
+ if ( seq == 0 )
+ s_RNG.FillRandom((byte_t*)tmp_ints, 16);
+
+ ui32_t i = tmp_ints[seq++] % (check_total - 1);
+
+ if ( i == j )
+ continue;
+
+ read_list_t t = read_list[i];
+ read_list[i] = read_list[j];
+ read_list[j] = t;
+ }
+}
+
+//
+Result_t
+ReadValidateWriteLargeFile(CommandOptions& Options)
+{
+ assert(Options.write_filename);
+ ui32_t check_total = 0;
+ ui32_t write_total = 0;
+ ui32_t read_count = 0;
+ ui32_t write_count = 0;
+ FileReader Reader;
+ FileWriter Writer;
+ ByteString FB, CB; // Frame Buffer and Check Buffer
+
+
+ FB.Capacity(Megabyte);
+ assert(FB.Capacity() == Megabyte);
+ CB.Capacity(Megabyte);
+ assert(CB.Capacity() == Megabyte);
+
+ Result_t result = Reader.OpenRead(Options.filename);
+
+ if ( KM_SUCCESS(result) )
+ result = Writer.OpenWrite(Options.write_filename);
+
+ // read the first chunk and get set up
+ while ( KM_SUCCESS(result) )
+ {
+ result = Reader.Read(FB.Data(), Megabyte, &read_count);
+
+ if ( KM_SUCCESS(result) )
+ {
+ if ( read_count < Megabyte )
+ {
+ fprintf(stderr, "Read() returned short buffer: %u\n", read_count);
+ result = RESULT_FAIL;
+ }
+
+ result = validate_chunk(FB, CB, &check_total);
+
+ if ( KM_SUCCESS(result) )
+ {
+ result = Writer.Write(FB.RoData(), Megabyte, &write_count);
+ assert(write_count == Megabyte);
+ fprintf(stderr, "\r%8u ", ++write_total);
+ }
+ }
+ else if ( result == RESULT_ENDOFFILE )
+ {
+ result = RESULT_OK;
+ break;
+ }
+ }
+
+ fputs("\n", stderr);
+ return result;
+}
+
+
+//
+Result_t
+ValidateLargeFile(CommandOptions& Options)
+{
+ ui32_t check_total = 0;
+ ui32_t read_count = 0;
+ ui32_t read_list_i = 0;
+ read_list_t* read_list = 0;
+ FileReader Reader;
+ ByteString FB, CB; // Frame Buffer and Check Buffer
+
+ FB.Capacity(Megabyte);
+ assert(FB.Capacity() == Megabyte);
+ CB.Capacity(Megabyte);
+ assert(CB.Capacity() == Megabyte);
+
+ Result_t result = Reader.OpenRead(Options.filename);
+
+ // read the first chunk and get set up
+ if ( KM_SUCCESS(result) )
+ {
+ result = Reader.Read(FB.Data(), Megabyte, &read_count);
+
+ if ( read_count < Megabyte )
+ {
+ fprintf(stderr, "Read() returned short buffer: %u\n", read_count);
+ result = RESULT_FAIL;
+ }
+ else if ( KM_SUCCESS(result) )
+ result = validate_chunk(FB, CB, &check_total);
+
+ if ( KM_SUCCESS(result) )
+ {
+ fprintf(stderr, "Validating %u chunk%s in %s order:\n",
+ check_total, (check_total == 1 ? "" : "s"), Options.order);
+ assert(read_list == 0);
+ read_list = (read_list_t*)malloc(check_total * sizeof(read_list_t));
+ assert(read_list);
+
+ // Set up an index to the chunks. The chunks are written
+ // to the file in order of descending nonce value.
+ if ( strcmp(Options.order, "fwd") == 0 )
+ {
+ for ( ui32_t i = 0; i < check_total; i++ )
+ {
+ read_list[i].nonce = check_total - i;
+ Kumu::fpos_t ofst = check_total - read_list[i].nonce;
+ read_list[i].position = ofst * (Kumu::fpos_t)Megabyte;
+ }
+ }
+ else
+ {
+ for ( ui32_t i = 0; i < check_total; i++ )
+ {
+ read_list[i].nonce = i + 1;
+ Kumu::fpos_t ofst = check_total - read_list[i].nonce;
+ read_list[i].position = ofst * (Kumu::fpos_t)Megabyte;
+ }
+
+ if ( strcmp(Options.order, "rand") == 0 )
+ randomize_list(read_list, check_total); // this makes it random
+ }
+ }
+ }
+
+ if ( KM_SUCCESS(result) )
+ {
+ assert(read_list);
+ ui32_t nonce = 0;
+
+ for ( read_list_i = 0;
+ read_list_i < check_total && KM_SUCCESS(result);
+ read_list_i++ )
+ {
+ fprintf(stderr, "\r%8u [%8u] ", read_list_i+1, read_list[read_list_i].nonce);
+ result = Reader.Seek(read_list[read_list_i].position);
+
+ if ( KM_SUCCESS(result) )
+ result = Reader.Read(FB.Data(), Megabyte, &read_count);
+
+ if ( result == RESULT_ENDOFFILE )
+ break;
+
+ else if ( read_count < Megabyte )
+ {
+ fprintf(stderr, "Read() returned short buffer: %u\n", read_count);
+ result = RESULT_FAIL;
+ }
+ else if ( KM_SUCCESS(result) )
+ {
+ result = validate_chunk(FB, CB, &nonce);
+
+ if ( nonce != read_list[read_list_i].nonce )
+ {
+ fprintf(stderr, "Nonce mismatch: expecting %u, got %u\n",
+ nonce, read_list[read_list_i].nonce);
+
+ return RESULT_FAIL;
+ }
+ }
+ }
+ }
+
+ fputs("\n", stderr);
+
+ if ( result == RESULT_ENDOFFILE )
+ {
+ if ( check_total == read_list_i )
+ result = RESULT_OK;
+ else
+ {
+ fprintf(stderr, "Unexpected chunk count, got %u, wanted %u\n",
+ read_list_i, check_total);
+ result = RESULT_FAIL;
+ }
+ }
+
+ return result;
+}
+
+//
+int
+main(int argc, const char **argv)
+{
+ Result_t result = RESULT_FAIL;
+ CommandOptions Options(argc, argv);
+
+ if ( Options.version_flag )
+ banner();
+
+ if ( Options.help_flag )
+ usage();
+
+ if ( Options.version_flag || Options.help_flag )
+ return 0;
+
+ if ( Options.error_flag )
+ {
+ fprintf(stderr, "There was a problem. Type %s -h for help.\n", PROGRAM_NAME);
+ return 3;
+ }
+
+ switch ( Options.mode )
+ {
+
+ case MMT_CREATE:
+ result = CreateLargeFile(Options);
+ break;
+
+ case MMT_VALIDATE:
+ result = ValidateLargeFile(Options);
+ break;
+
+ case MMT_VAL_WRITE:
+ result = ReadValidateWriteLargeFile(Options);
+ break;
+ }
+
+ if ( result != RESULT_OK )
+ {
+ fputs("Program stopped on error.\n", stderr);
+
+ if ( result != RESULT_FAIL )
+ {
+ fputs(result.Label(), stderr);
+ fputc('\n', stderr);
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+
+//
+// end kmfilegen.cpp
+//
diff --git a/asdcplib/src/kmrandgen.cpp b/asdcplib/src/kmrandgen.cpp
new file mode 100644
index 0000000..560fa6e
--- /dev/null
+++ b/asdcplib/src/kmrandgen.cpp
@@ -0,0 +1,292 @@
+/*
+Copyright (c) 2005-2009, 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 kmrandgen.cpp
+ \version $Id: kmrandgen.cpp,v 1.8 2009/03/04 17:52:45 jhurst Exp $
+ \brief psuedo-random number generation utility
+ */
+
+#include "AS_DCP.h"
+#include <KM_fileio.h>
+#include <KM_prng.h>
+#include <ctype.h>
+
+using namespace Kumu;
+
+const ui32_t RandBlockSize = 16;
+const char* PROGRAM_NAME = "kmrandgen";
+
+// 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 = stdout)
+{
+ fprintf(stream, "\n\
+%s (asdcplib %s)\n\n\
+Copyright (c) 2003-2009 John Hurst\n\n\
+%s is part of the asdcp DCP tools package.\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",
+ PROGRAM_NAME, Kumu::Version(), PROGRAM_NAME, PROGRAM_NAME);
+}
+
+//
+void
+usage(FILE* stream = stdout)
+{
+ fprintf(stream, "\
+USAGE: %s [-b|-B|-c|-x] [-n] [-s <size>] [-v]\n\
+\n\
+ %s [-h|-help] [-V]\n\
+\n\
+ -b - Output a stream of binary data\n\
+ -B - Output a Base64 string\n\
+ -c - Output a C-language struct containing the values\n\
+ -h | -help - Show help\n\
+ -n - Suppress newlines\n\
+ -s <size> - Number of random bytes to generate (default 32)\n\
+ -v - Verbose. Prints informative messages to stderr\n\
+ -V - Show version information\n\
+ -x - Output hexadecimal (default)\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", PROGRAM_NAME, PROGRAM_NAME);
+}
+
+enum OutputFormat_t {
+ OF_HEX,
+ OF_BINARY,
+ OF_BASE64,
+ OF_CSTRUCT
+};
+
+//
+class CommandOptions
+{
+ CommandOptions();
+
+public:
+ bool error_flag; // true if the given options are in error or not complete
+ bool no_newline_flag; //
+ 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
+ OutputFormat_t format; //
+ ui32_t request_size;
+
+ //
+ CommandOptions(int argc, const char** argv) :
+ error_flag(true), no_newline_flag(false), verbose_flag(false),
+ version_flag(false), help_flag(false), format(OF_HEX), request_size(RandBlockSize*2)
+ {
+ for ( int i = 1; i < argc; i++ )
+ {
+
+ if ( (strcmp( argv[i], "-help") == 0) )
+ {
+ help_flag = true;
+ continue;
+ }
+
+ if ( argv[i][0] == '-' && isalpha(argv[i][1]) && argv[i][2] == 0 )
+ {
+ switch ( argv[i][1] )
+ {
+ case 'b': format = OF_BINARY; break;
+ case 'B': format = OF_BASE64; break;
+ case 'c': format = OF_CSTRUCT; break;
+ case 'n': no_newline_flag = true; break;
+ case 'h': help_flag = true; break;
+
+ case 's':
+ TEST_EXTRA_ARG(i, 's');
+ request_size = abs(atoi(argv[i]));
+ break;
+
+ case 'v': verbose_flag = true; break;
+ case 'V': version_flag = true; break;
+ case 'x': format = OF_HEX; break;
+
+ default:
+ fprintf(stderr, "Unrecognized option: %s\n", argv[i]);
+ return;
+ }
+ }
+ else
+ {
+ fprintf(stderr, "Unrecognized option: %s\n", argv[i]);
+ return;
+ }
+ }
+
+ if ( help_flag || version_flag )
+ return;
+
+ if ( request_size == 0 )
+ {
+ fprintf(stderr, "Please use a non-zero request size\n");
+ return;
+ }
+
+ error_flag = false;
+ }
+};
+
+
+//
+int
+main(int argc, const char** argv)
+{
+ CommandOptions Options(argc, argv);
+
+ if ( Options.version_flag )
+ banner();
+
+ if ( Options.help_flag )
+ usage();
+
+ if ( Options.version_flag || Options.help_flag )
+ return 0;
+
+ if ( Options.error_flag )
+ {
+ fprintf(stderr, "There was a problem. Type %s -h for help.\n", PROGRAM_NAME);
+ return 3;
+ }
+
+ FortunaRNG RandGen;
+ ByteString Buf(Kumu::Kilobyte);
+
+ if ( Options.verbose_flag )
+ fprintf(stderr, "Generating %d random byte%s.\n", Options.request_size, (Options.request_size == 1 ? "" : "s"));
+
+ if ( Options.format == OF_BINARY )
+ {
+ if ( KM_FAILURE(Buf.Capacity(Options.request_size)) )
+ {
+ fprintf(stderr, "randbuf: %s\n", RESULT_ALLOC.Label());
+ return 1;
+ }
+
+ RandGen.FillRandom(Buf.Data(), Options.request_size);
+ fwrite((byte_t*)Buf.Data(), 1, Options.request_size, stdout);
+ }
+ else if ( Options.format == OF_CSTRUCT )
+ {
+ ui32_t line_count = 0;
+ byte_t* p = Buf.Data();
+ printf("byte_t rand_buf[%u] = {\n", Options.request_size);
+
+ if ( Options.request_size > 128 )
+ fputs(" // 0x00000000\n", stdout);
+
+ while ( Options.request_size > 0 )
+ {
+ if ( line_count > 0 && (line_count % (RandBlockSize*8)) == 0 )
+ fprintf(stdout, " // 0x%08x\n", line_count);
+
+ RandGen.FillRandom(p, RandBlockSize);
+ fputc(' ', stdout);
+
+ for ( ui32_t i = 0; i < RandBlockSize && Options.request_size > 0; i++, Options.request_size-- )
+ printf(" 0x%02x,", p[i]);
+
+ fputc('\n', stdout);
+ line_count += RandBlockSize;
+ }
+
+ fputs("};", stdout);
+
+ if ( ! Options.no_newline_flag )
+ fputc('\n', stdout);
+ }
+ else if ( Options.format == OF_BASE64 )
+ {
+ if ( KM_FAILURE(Buf.Capacity(Options.request_size)) )
+ {
+ fprintf(stderr, "randbuf: %s\n", RESULT_ALLOC.Label());
+ return 1;
+ }
+
+ ByteString Strbuf;
+ ui32_t e_len = base64_encode_length(Options.request_size) + 1;
+
+ if ( KM_FAILURE(Strbuf.Capacity(e_len)) )
+ {
+ fprintf(stderr, "strbuf: %s\n", RESULT_ALLOC.Label());
+ return 1;
+ }
+
+ RandGen.FillRandom(Buf.Data(), Options.request_size);
+
+ if ( base64encode(Buf.RoData(), Options.request_size, (char*)Strbuf.Data(), Strbuf.Capacity()) == 0 )
+ {
+ fprintf(stderr, "encode error\n");
+ return 2;
+ }
+
+ fputs((const char*)Strbuf.RoData(), stdout);
+
+ if ( ! Options.no_newline_flag )
+ fputs("\n", stdout);
+ }
+ else // OF_HEX
+ {
+ byte_t* p = Buf.Data();
+ char hex_buf[64];
+
+ while ( Options.request_size > 0 )
+ {
+ ui32_t x_len = xmin(Options.request_size, RandBlockSize);
+ RandGen.FillRandom(p, RandBlockSize);
+ bin2hex(p, x_len, hex_buf, 64);
+ fputs(hex_buf, stdout);
+
+ if ( ! Options.no_newline_flag )
+ fputc('\n', stdout);
+
+ Options.request_size -= x_len;
+ }
+
+ }
+
+ return 0;
+}
+
+
+//
+// end kmrandgen.cpp
+//
diff --git a/asdcplib/src/kmuuidgen.cpp b/asdcplib/src/kmuuidgen.cpp
new file mode 100644
index 0000000..d57154b
--- /dev/null
+++ b/asdcplib/src/kmuuidgen.cpp
@@ -0,0 +1,195 @@
+/*
+Copyright (c) 2005-2009, 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 kmuuidgen.cpp
+ \version $Id: kmuuidgen.cpp,v 1.7 2009/03/04 17:52:45 jhurst Exp $
+ \brief UUID generation utility
+ */
+
+#include "AS_DCP.h"
+#include <KM_util.h>
+#include <ctype.h>
+
+
+const char* PROGRAM_NAME = "kmuuidgen";
+
+// 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 = stdout)
+{
+ fprintf(stream, "\n\
+%s (asdcplib %s)\n\n\
+Copyright (c) 2003-2009 John Hurst\n\n\
+%s is part of the asdcp DCP tools package.\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",
+ PROGRAM_NAME, Kumu::Version(), PROGRAM_NAME, PROGRAM_NAME);
+}
+
+//
+void
+usage(FILE* stream = stdout)
+{
+ fprintf(stream, "\
+USAGE: %s [-c] [-n] [-v]\n\
+\n\
+ %s [-h|-help] [-V]\n\
+\n\
+ -c - Output a C-language struct containing the value\n\
+ -h | -help - Show help\n\
+ -n - Suppress the newline\n\
+ -v - Verbose. Prints informative messages to stderr\n\
+ -V - Show version information\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", PROGRAM_NAME, PROGRAM_NAME);
+}
+
+//
+class CommandOptions
+{
+ CommandOptions();
+
+public:
+ bool error_flag; // true if the given options are in error or not complete
+ bool no_newline_flag; //
+ bool c_array_flag; //
+ 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 if the verbose flag was selected
+
+ //
+ CommandOptions(int argc, const char** argv) :
+ error_flag(true), no_newline_flag(false), c_array_flag(false), version_flag(false),
+ help_flag(false), verbose_flag(false)
+ {
+ for ( int i = 1; i < argc; i++ )
+ {
+
+ if ( (strcmp( argv[i], "-help") == 0) )
+ {
+ help_flag = true;
+ continue;
+ }
+
+ if ( argv[i][0] == '-' && isalpha(argv[i][1]) && argv[i][2] == 0 )
+ {
+ switch ( argv[i][1] )
+ {
+ case 'c': c_array_flag = true; break;
+ case 'n': no_newline_flag = true; break;
+ case 'h': help_flag = true; break;
+ case 'v': verbose_flag = true; break;
+ case 'V': version_flag = true; break;
+
+ default:
+ fprintf(stderr, "Unrecognized option: %s\n", argv[i]);
+ return;
+ }
+ }
+ else
+ {
+ fprintf(stderr, "Unrecognized option: %s\n", argv[i]);
+ return;
+ }
+ }
+
+ if ( help_flag || version_flag )
+ return;
+
+ error_flag = false;
+ }
+};
+
+
+
+//
+int
+main(int argc, const char** argv)
+{
+ CommandOptions Options(argc, argv);
+
+ if ( Options.version_flag )
+ banner();
+
+ if ( Options.help_flag )
+ usage();
+
+ if ( Options.version_flag || Options.help_flag )
+ return 0;
+
+ if ( Options.error_flag )
+ {
+ fprintf(stderr, "There was a problem. Type %s -h for help.\n", PROGRAM_NAME);
+ return 3;
+ }
+
+ Kumu::UUID UUID;
+ Kumu::GenRandomValue(UUID);
+ char uuid_buf[40];
+
+ if ( Options.c_array_flag )
+ {
+ const byte_t* p = UUID.Value();
+
+ printf("\
+byte_t uuid_buf[] = {\n\
+ // %s\n ",
+ UUID.EncodeHex(uuid_buf, 40));
+
+ for ( ui32_t i = 0; i < 16; i++ )
+ printf(" 0x%02x,", p[i]);
+
+ printf("\n");
+ printf("};\n");
+ return 0;
+ }
+ else
+ {
+ fputs(UUID.EncodeHex(uuid_buf, 40), stdout);
+ }
+
+ if ( Options.no_newline_flag == 0 )
+ printf("\n");
+
+ return 0;
+}
+
+
+//
+// end kmuuidgen.cpp
+//
diff --git a/asdcplib/src/mpeg-crypt-tst.sh b/asdcplib/src/mpeg-crypt-tst.sh
new file mode 100755
index 0000000..3a952f7
--- /dev/null
+++ b/asdcplib/src/mpeg-crypt-tst.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+#
+# $Id: mpeg-crypt-tst.sh,v 1.3 2009/04/09 19:16:49 msheby Exp $
+# Copyright (c) 2007-2009 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.
+
+# crypto MPEG tests
+
+${BUILD_DIR}/asdcp-test${EXEEXT} -k ${CRYPT_KEY} \
+ -c ${TEST_FILES}/write_crypt_test_mpeg.mxf ${TEST_FILES}/${TEST_FILE_PREFIX}.mpg
+if [ $? -ne 0 ]; then
+ exit 1
+fi
+${BUILD_DIR}/asdcp-test${EXEEXT} -i ${TEST_FILES}/write_crypt_test_mpeg.mxf
+if [ $? -ne 0 ]; then
+ exit 1
+fi
+
+
+(${BUILD_DIR}/asdcp-test${EXEEXT} -k ${CRYPT_KEY_B} \
+ -x ${TEST_FILES}/plaintext ${TEST_FILES}/write_crypt_test_mpeg.mxf; \
+ if [ $? -eq 1 ]; then exit 0; fi; exit 1 )
+${BUILD_DIR}/asdcp-test${EXEEXT} -m -k ${CRYPT_KEY} \
+ -x ${TEST_FILES}/plaintext ${TEST_FILES}/write_crypt_test_mpeg.mxf
+if [ $? -ne 0 ]; then
+ exit 1
+fi
+cmp ${TEST_FILES}/${TEST_FILE_PREFIX}.mpg ${TEST_FILES}/plaintext.ves
+if [ $? -ne 0 ]; then
+ exit 1
+fi
diff --git a/asdcplib/src/mpeg-tst.sh b/asdcplib/src/mpeg-tst.sh
new file mode 100755
index 0000000..94d7ba6
--- /dev/null
+++ b/asdcplib/src/mpeg-tst.sh
@@ -0,0 +1,49 @@
+#!/bin/sh
+#
+# $Id: mpeg-tst.sh,v 1.3 2009/04/09 19:16:49 msheby Exp $
+# Copyright (c) 2007-2009 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.
+
+# MPEG tests
+
+${BUILD_DIR}/asdcp-test${EXEEXT} -c ${TEST_FILES}/write_test_mpeg.mxf ${TEST_FILES}/${TEST_FILE_PREFIX}.mpg
+if [ $? -ne 0 ]; then
+ exit 1
+fi
+
+
+${BUILD_DIR}/asdcp-test${EXEEXT} -x ${TEST_FILES}/extract ${TEST_FILES}/write_test_mpeg.mxf
+if [ $? -ne 0 ]; then
+ exit 1
+fi
+cmp ${TEST_FILES}/${TEST_FILE_PREFIX}.mpg ${TEST_FILES}/extract.ves
+if [ $? -ne 0 ]; then
+ exit 1
+fi
+
+
+#${BUILD_DIR}/asdcp-test${EXEEXT} -G ${TEST_FILES}/write_test_mpeg.mxf
+#if [ $? -ne 0 ]; then
+# exit 1
+#fi
diff --git a/asdcplib/src/path-test.cpp b/asdcplib/src/path-test.cpp
new file mode 100644
index 0000000..b556bdd
--- /dev/null
+++ b/asdcplib/src/path-test.cpp
@@ -0,0 +1,145 @@
+/*
+Copyright (c) 2004-2009, 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 path-test.cpp
+ \version $Id: path-test.cpp,v 1.8 2009/07/10 18:14:01 jhurst Exp $
+ \brief test harness for path manglers defined in KM_fileio.h
+*/
+
+
+#include <KM_fileio.h>
+#include <iostream>
+
+using namespace std;
+using namespace Kumu;
+
+
+//
+int
+main(int argc, const char** argv)
+{
+
+ string Path_1 = "path-test.cpp";
+ assert(PathExists(Path_1));
+ assert(PathIsFile(Path_1));
+ assert(!PathIsDirectory(Path_1));
+
+ string Path_2 = ".";
+ assert(PathExists(Path_2));
+ assert(!PathIsFile(Path_2));
+ assert(PathIsDirectory(Path_2));
+
+ string Path_3 = "/foo/bar/baz.buz"; // must have 3 elements
+ PathCompList_t PathList_3;
+ PathToComponents(Path_3, PathList_3);
+
+ assert(PathList_3.size() == 3);
+
+ string Path_4 = ComponentsToPath(PathList_3);
+ string Path_5 = PathMakeAbsolute(Path_4);
+
+ fprintf(stderr, "PathMakeAbsolute in: %s\n", Path_4.c_str());
+ fprintf(stderr, "PathMakeAbsolute out: %s\n", Path_5.c_str());
+
+ string Path_6 = ComponentsToAbsolutePath(PathList_3);
+ assert(Path_3 == Path_6);
+ assert(PathsAreEquivalent(Path_3, Path_6));
+ assert(!PathsAreEquivalent(Path_3, Path_4));
+
+ assert(!PathHasComponents(PathList_3.back()));
+ assert(PathHasComponents(Path_3));
+
+ assert(!PathIsAbsolute(Path_4));
+ assert(PathIsAbsolute(Path_5));
+ assert(PathMakeLocal(Path_3, "/foo") == "bar/baz.buz");
+
+ assert(PathsAreEquivalent("/foo/bar/baz", "/foo/bar/./baz"));
+ assert(PathsAreEquivalent("/foo/baz", "/foo/bar/../baz"));
+
+ assert(PathBasename(Path_3) == "baz.buz");
+ assert(PathDirname(Path_3) == "/foo/bar");
+ assert(PathDirname("/foo") == "/");
+
+ assert(PathGetExtension(Path_3) == "buz");
+ assert(PathGetExtension("foo") == "");
+ assert(PathSetExtension("foo.bar", "") == "foo");
+ assert(PathSetExtension(Path_3, "xml") == "baz.xml");
+
+ string Path_7 = "//tmp///////fooo";
+
+ PathCompList_t PathList_7;
+ PathToComponents(Path_7, PathList_7);
+ for ( PathCompList_t::const_iterator i = PathList_7.begin(); i != PathList_7.end(); i++ )
+ fprintf(stderr, "xx: \"%s\"\n", i->c_str());
+ assert(PathsAreEquivalent(PathMakeLocal(PathMakeCanonical(Path_7), "/tmp"), "fooo"));
+
+ string Path_8 = "tmp/foo/bar/ack";
+ CreateDirectoriesInPath(Path_8);
+ assert(PathExists(Path_8));
+ DeletePath(Path_8);
+ assert(!PathExists(Path_8));
+
+ PathList_t InList, OutList;
+ InList.push_back("tmp");
+ InList.push_back("Darwin");
+ InList.push_back(".");
+
+ cerr << "----------------------------------" << endl;
+ FindInPaths(PathMatchAny(), InList, OutList);
+ PathList_t::iterator pi;
+
+ for ( pi = OutList.begin(); pi != OutList.end(); pi++ )
+ cerr << *pi << endl;
+
+ cerr << "----------------------------------" << endl;
+ OutList.clear();
+ FindInPaths(PathMatchRegex("^[A-J].*\\.h$"), InList, OutList);
+
+ for ( pi = OutList.begin(); pi != OutList.end(); pi++ )
+ cerr << *pi << endl;
+
+ cerr << "----------------------------------" << endl;
+ OutList.clear();
+ FindInPaths(PathMatchGlob("*.h"), InList, OutList);
+
+ for ( pi = OutList.begin(); pi != OutList.end(); pi++ )
+ cerr << *pi << endl;
+
+ cerr << "----------------------------------" << endl;
+
+ fsize_t free_space, total_space;
+ FreeSpaceForPath("/", free_space, total_space);
+ cerr << "Free space: " << free_space << endl;
+ cerr << "Total space: " << total_space << endl;
+
+ cerr << "OK" << endl;
+
+ return 0;
+}
+
+//
+// end path-test.cpp
+//
diff --git a/asdcplib/src/rng-tst.sh b/asdcplib/src/rng-tst.sh
new file mode 100755
index 0000000..b0b35c8
--- /dev/null
+++ b/asdcplib/src/rng-tst.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+#
+# $Id: rng-tst.sh,v 1.3 2009/04/09 19:16:49 msheby Exp $
+# Copyright (c) 2007-2009 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.
+
+${srcdir}/fips-186-test-harness.pl ${BUILD_DIR}/fips-186-rng-test${EXEEXT}
diff --git a/asdcplib/src/wav-crypt-tst.sh b/asdcplib/src/wav-crypt-tst.sh
new file mode 100755
index 0000000..fce54c0
--- /dev/null
+++ b/asdcplib/src/wav-crypt-tst.sh
@@ -0,0 +1,69 @@
+#!/bin/sh
+#
+# $Id: wav-crypt-tst.sh,v 1.3 2009/04/09 19:16:49 msheby Exp $
+# Copyright (c) 2007-2009 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.
+
+# crypto WAV tests
+
+${BUILD_DIR}/asdcp-test${EXEEXT} -k ${CRYPT_KEY} \
+ -c ${TEST_FILES}/write_crypt_test_wav.mxf ${TEST_FILES}/${TEST_FILE_PREFIX}.wav
+if [ $? -ne 0 ]; then
+ exit 1
+fi
+${BUILD_DIR}/asdcp-test${EXEEXT} -i ${TEST_FILES}/write_crypt_test_wav.mxf
+if [ $? -ne 0 ]; then
+ exit 1
+fi
+${BUILD_DIR}/asdcp-test${EXEEXT} -p 23 -k ${CRYPT_KEY} \
+ -c ${TEST_FILES}/write_crypt_test_2398_wav.mxf ${TEST_FILES}/${TEST_FILE_PREFIX}.wav
+if [ $? -ne 0 ]; then
+ exit 1
+fi
+${BUILD_DIR}/asdcp-test${EXEEXT} -i ${TEST_FILES}/write_crypt_test_2398_wav.mxf
+if [ $? -ne 0 ]; then
+ exit 1
+fi
+
+
+( ${BUILD_DIR}/asdcp-test${EXEEXT} -k ${CRYPT_KEY_B} \
+ -x ${TEST_FILES}/plaintext ${TEST_FILES}/write_crypt_test_wav.mxf; \
+ if [ $? -eq 1 ]; then exit 0; fi; exit 1 )
+${BUILD_DIR}/asdcp-test${EXEEXT} -m -k ${CRYPT_KEY} \
+ -x ${TEST_FILES}/plaintext ${TEST_FILES}/write_crypt_test_wav.mxf
+if [ $? -ne 0 ]; then
+ exit 1
+fi
+cmp ${TEST_FILES}/${TEST_FILE_PREFIX}.wav ${TEST_FILES}/plaintext_1.wav
+if [ $? -ne 0 ]; then
+ exit 1
+fi
+( ${BUILD_DIR}/asdcp-test${EXEEXT} -k ${CRYPT_KEY_B} \
+ -x ${TEST_FILES}/plaintext_2398 ${TEST_FILES}/write_crypt_test_2398_wav.mxf; \
+ if [ $? -eq 1 ]; then exit 0; fi; exit 1 )
+${BUILD_DIR}/asdcp-test${EXEEXT} -m -k ${CRYPT_KEY} \
+ -x ${TEST_FILES}/plaintext_2398 ${TEST_FILES}/write_crypt_test_2398_wav.mxf
+if [ $? -ne 0 ]; then
+ exit 1
+fi
diff --git a/asdcplib/src/wav-tst.sh b/asdcplib/src/wav-tst.sh
new file mode 100755
index 0000000..e124e8e
--- /dev/null
+++ b/asdcplib/src/wav-tst.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+#
+# $Id: wav-tst.sh,v 1.3 2009/04/09 19:16:49 msheby Exp $
+# Copyright (c) 2007-2009 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.
+
+# WAV tests
+
+${BUILD_DIR}/asdcp-test${EXEEXT} -c ${TEST_FILES}/write_test_wav.mxf ${TEST_FILES}/${TEST_FILE_PREFIX}.wav
+if [ $? -ne 0 ]; then
+ exit 1
+fi
+
+${BUILD_DIR}/asdcp-test${EXEEXT} -x ${TEST_FILES}/extract ${TEST_FILES}/write_test_wav.mxf
+if [ $? -ne 0 ]; then
+ exit 1
+fi
+cmp ${TEST_FILES}/${TEST_FILE_PREFIX}.wav ${TEST_FILES}/extract_1.wav
+if [ $? -ne 0 ]; then
+ exit 1
+fi
diff --git a/asdcplib/src/wavesplit.cpp b/asdcplib/src/wavesplit.cpp
new file mode 100755
index 0000000..8785198
--- /dev/null
+++ b/asdcplib/src/wavesplit.cpp
@@ -0,0 +1,397 @@
+/*
+Copyright (c) 2005-2009, 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: wavesplit.cpp,v 1.11 2010/02/16 18:40:57 jhurst Exp $
+ \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* PROGRAM_NAME = "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 || info_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-2009 John Hurst\n\n\
+%s 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",
+ PROGRAM_NAME, ASDCP::Version(), PROGRAM_NAME, PROGRAM_NAME);
+}
+
+//
+void
+usage(FILE* stream = stderr)
+{
+ fprintf(stream, "\
+USAGE: %s [-v] -V\n\
+ %s [-v] -c <root-name> [-d <duration>] [-f <start-frame>] <filename>\n\
+ %s [-v] -i <filename>\n\
+\n\
+Major modes:\n\
+ -c <root-name> - Create a WAV file for each channel in the input file\n\
+ (default is two-channel files)\n\
+ -d <duration> - Number of frames to process, default all\n\
+ -f <frame-num> - Starting frame number, default 0\n\
+ -h - Show help\n\
+ -i - Show input file metadata (no output created)\n\
+ -V - Show version\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", PROGRAM_NAME, PROGRAM_NAME, PROGRAM_NAME);
+}
+
+//
+//
+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 info_flag; // true if the file info 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), info_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 'c':
+ TEST_SET_MAJOR_MODE(create_flag);
+ TEST_EXTRA_ARG(i, 'c');
+ file_root = argv[i];
+ break;
+
+ case 'd':
+ TEST_EXTRA_ARG(i, 'd');
+ duration = atoi(argv[i]); // TODO: test for negative value, should use strtol()
+ break;
+
+ case 'f':
+ TEST_EXTRA_ARG(i, 'f');
+ start_frame = atoi(argv[i]); // TODO: test for negative value, should use strtol()
+ break;
+
+ case 'h': help_flag = true; break;
+ case 'i': TEST_SET_MAJOR_MODE(info_flag); break;
+ case 'V': version_flag = true; 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;
+ }
+};
+
+//
+Result_t
+wav_file_info(CommandOptions& Options)
+{
+ 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.EditRate = PictureRate;
+ fprintf(stderr, "48Khz PCM Audio, %s fps (%u spf)\n", "24",
+ PCM::CalcSamplesPerFrame(ADesc));
+ fputs("AudioDescriptor:\n", stderr);
+ PCM::AudioDescriptorDump(ADesc);
+ }
+
+ return result;
+}
+
+//
+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.EditRate = 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 (%u 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];
+ snprintf(filename, 256, "%s_l.wav", Options.file_root);
+ result = L_OutFile.OpenWrite(filename);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ snprintf(filename, 256, "%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 %u bytes, got %u.\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.info_flag )
+ result = wav_file_info(Options);
+
+ else 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;
+}
+
+
+//
diff --git a/asdcplib/src/wscript b/asdcplib/src/wscript
new file mode 100644
index 0000000..7c78616
--- /dev/null
+++ b/asdcplib/src/wscript
@@ -0,0 +1,71 @@
+def configure(conf):
+ conf.env.append_value('CXXFLAGS', '-D_FILE_OFFSET_BITS=64')
+ conf.env.append_value('CXXFLAGS', '-DPACKAGE_VERSION="1.9.45-carlh"')
+ if conf.options.target_windows:
+ conf.env.append_value('CXXFLAGS', '-DASDCP_PLATFORM="win32"')
+ conf.env.append_value('CXXFLAGS', '-DKM_WIN32')
+ else:
+ conf.env.append_value('CXXFLAGS', '-DASDCP_PLATFORM="linux"')
+
+def build(bld):
+ if bld.env.STATIC:
+ obj = bld(features = 'cxx cxxstlib')
+ else:
+ obj = bld(features = 'cxx cxxshlib')
+
+ obj.name = 'libkumu-libsub'
+ obj.target = 'kumu-libsub'
+ obj.uselib = 'OPENSSL BOOST_FILESYSTEM'
+ obj.includes = ['.']
+ obj.export_includes = ['.']
+ obj.source = """
+ KM_fileio.cpp
+ KM_log.cpp
+ KM_util.cpp
+ KM_xml.cpp
+ KM_tai.cpp
+ KM_prng.cpp
+ """
+
+ if bld.env.STATIC:
+ obj = bld(features = 'cxx cxxstlib')
+ else:
+ obj = bld(features = 'cxx cxxshlib')
+
+ obj.name = 'libasdcp-libsub'
+ obj.target = 'asdcp-libsub'
+ obj.uselib = 'OPENSSL'
+ obj.use = 'libkumu-libsub'
+ obj.includes = ['.']
+ obj.export_includes = ['.']
+ obj.source = """
+ MPEG2_Parser.cpp
+ MPEG.cpp
+ JP2K_Codestream_Parser.cpp
+ JP2K_Sequence_Parser.cpp
+ JP2K.cpp
+ PCM_Parser.cpp
+ Wav.cpp
+ TimedText_Parser.cpp
+ KLV.cpp
+ Dict.cpp
+ MXFTypes.cpp
+ MXF.cpp
+ Index.cpp
+ Metadata.cpp
+ AS_DCP.cpp
+ AS_DCP_MXF.cpp
+ AS_DCP_AES.cpp
+ h__Reader.cpp
+ h__Writer.cpp
+ AS_DCP_MPEG2.cpp
+ AS_DCP_JP2K.cpp
+ AS_DCP_PCM.cpp
+ AS_DCP_TimedText.cpp
+ PCMParserList.cpp
+ MDD.cpp
+ """
+
+ if bld.env.STATIC:
+ bld.install_files('${PREFIX}/lib', 'libkumu-libsub.a')
+ bld.install_files('${PREFIX}/lib', 'libasdcp-libsub.a')