fixed encryption for timed text
authorjhurst <jhurst@cinecert.com>
Fri, 8 Jun 2007 02:24:37 +0000 (02:24 +0000)
committerjhurst <>
Fri, 8 Jun 2007 02:24:37 +0000 (02:24 +0000)
27 files changed:
AS_DCP_TimedText.h
src/AS_DCP.h
src/AS_DCP_JP2K.cpp
src/AS_DCP_MPEG2.cpp
src/AS_DCP_MXF.cpp
src/AS_DCP_PCM.cpp
src/AS_DCP_TimedText.cpp
src/AS_DCP_internal.h
src/Index.cpp
src/KM_fileio.cpp
src/KM_fileio.h
src/KM_xml.cpp
src/KM_xml.h
src/MDD.cpp
src/MDD.h
src/MXF.cpp
src/MXF.h
src/MXFTypes.cpp
src/MXFTypes.h
src/Metadata.cpp
src/Metadata.h
src/TimedText_Parser.cpp
src/asdcp-test.cpp
src/h__Reader.cpp
src/h__Writer.cpp
src/klvwalk.cpp
src/path-test.cpp [new file with mode: 0644]

index ab39528ca240614ac0537bae3d906dbbc51bc695..b175683738caf80413637948b36ab9952241d986 100644 (file)
@@ -32,6 +32,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include <AS_DCP.h>
+#include <list>
 
 
 #ifndef _AS_DCP_SUBTITLE_H_
@@ -43,10 +44,28 @@ namespace ASDCP {
   //
   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
       {
-       std::string NamespaceName;
-       ui32_t      ResourceCount;
+       Rational       EditRate;                // 
+       ui32_t         ContainerDuration;
+       byte_t         AssetID[UUIDlen];
+       std::string    NamespaceName; // NULL-terminated string
+       std::string    EncodingName;
+       ResourceList_t ResourceList;
+
+      TimedTextDescriptor() : ContainerDuration(0), EncodingName("UTF-8") {} // D-Cinema format is always UTF-8
       };
 
       // Print debugging information to stream (stderr default)
@@ -54,49 +73,39 @@ namespace ASDCP {
 
       //
       class FrameBuffer : public ASDCP::FrameBuffer
-       {
-         ASDCP_NO_COPY_CONSTRUCT(FrameBuffer); // TODO: should have copy construct
-
-       protected:
-         std::string m_MIMEType;
-         byte_t      m_AssetID[UUIDlen];
-
-       public:
-         FrameBuffer() { memset(m_AssetID, 0, UUIDlen); }
-         FrameBuffer(ui32_t size) { Capacity(size); memset(m_AssetID, 0, UUIDlen); }
-         virtual ~FrameBuffer() {}
-       
-         const char*   MIMEType() { return m_MIMEType.c_str(); }
-         void          MIMEType(const char* s) { m_MIMEType = s; }
-         const byte_t* AssetID() { return m_AssetID; }
-         void          AssetID(const byte_t* buf) { memcpy(m_AssetID, buf, UUIDlen); }
-
-         // Print debugging information to stream (stderr default)
-         void Dump(FILE* = 0, ui32_t dump_bytes = 0) const;
-       };
+      {
+       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;
+      };
 
       //
-      // NOTE: The ReadFrame() and WriteFrame() methods below do not stricly handle "frames".
-      // They are named for continuity with other AS-DCP lib modules. The methods actually
-      // handle complete assets, such as XML documents, PNG images and fonts.
-      //
-
-      // An object which opens and reads a SMPTE 428-7 (or T.I. CineCanvas (TM)) subtitle file.
-      // The call to OpenRead() reads metadata from the file and populates an internal TimedTextDescriptor
-      // object. The first call to ReadFrame() returns the XML document. Each subsequent call to
-      // ReadFrame() reads exactly one resource file (if any) referenced by the XML into the given
-      // FrameBuffer object.
       class DCSubtitleParser
        {
-         class h__DCSubtitleParser;
-         mem_ptr<h__DCSubtitleParser> m_Parser;
+         class h__SubtitleParser;
+         mem_ptr<h__SubtitleParser> m_Parser;
          ASDCP_NO_COPY_CONSTRUCT(DCSubtitleParser);
 
        public:
          DCSubtitleParser();
          virtual ~DCSubtitleParser();
 
-         // Opens the XML file for reading, parses enough data to provide a complete
+         // Opens the XML file for reading, parse data to provide a complete
          // set of stream metadata for the MXFWriter below.
          Result_t OpenRead(const char* filename) const;
 
@@ -104,16 +113,14 @@ namespace ASDCP {
          // Returns RESULT_INIT if the file is not open.
          Result_t FillDescriptor(TimedTextDescriptor&) const;
 
-         // Reset the contents of the internal TimedTextDescriptor
-         Result_t Reset() const;
+         // Reads the complete Timed Text Resource into the given string.
+         Result_t ReadTimedTextResource(std::string&) const;
 
-         // Reads the next subtitle resource in the list taken from the XML file.
-         // Fails if the buffer is too small or the file list has been exhausted.
-         // The XML file itself is returned in the first call.
-         Result_t ReadFrame(FrameBuffer&) const;
+         // Reads the Ancillary Resource having the given ID. Fails if the buffer
+         // is too small or the resource does not exist.
+         Result_t ReadAncillaryResource(const byte_t* uuid, FrameBuffer&) const;
        };
 
-
       //
       class MXFWriter
        {
@@ -131,11 +138,21 @@ namespace ASDCP {
          Result_t OpenWrite(const char* filename, const WriterInfo&,
                             const TimedTextDescriptor&, ui32_t HeaderSize = 16384);
 
-         // Writes a timed-text resource to the MXF file. If the optional AESEncContext
+         // 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_t WriteFrame(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0);
+         // 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();
@@ -167,14 +184,28 @@ namespace ASDCP {
          // Returns RESULT_INIT if the file is not open.
          Result_t FillWriterInfo(WriterInfo&) const;
 
-         // Reads a timed-text resource from the MXF file. If the optional AESEncContext
+         // 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 ReadFrame(ui32_t frame_number, FrameBuffer&, AESDecContext* = 0, HMACContext* = 0) const;
+         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;
index 05b1e651294b79905558b744f15ebe1962a44c88..9dc7f5b755e233103550e47949d644ce92041dcd 100755 (executable)
@@ -144,7 +144,7 @@ namespace ASDCP {
   // 1.0.1. If changes were also required in AS_DCP.h, the new version would be 1.1.1.
   const ui32_t VERSION_MAJOR = 1;
   const ui32_t VERSION_APIMINOR = 1;
-  const ui32_t VERSION_IMPMINOR = 14;
+  const ui32_t VERSION_IMPMINOR = 15;
   const char* Version();
 
   // UUIDs are passed around as strings of UUIDlen bytes
@@ -202,6 +202,7 @@ namespace ASDCP {
     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
   };
 
   // Determine the type of essence contained in the given MXF file. RESULT_OK
index 0986a1dc9c6b254ad14e3dceb3ba6624e09aaf05..c45f78518791cf47250d25fd6b0bd0c3f2aada2b 100755 (executable)
@@ -119,7 +119,6 @@ public:
   h__Reader() : m_EssenceDescriptor(0), m_EssenceSubDescriptor(0) {}
   Result_t    OpenRead(const char*);
   Result_t    ReadFrame(ui32_t, FrameBuffer&, AESDecContext*, HMACContext*);
-  Result_t    ReadFrameGOPStart(ui32_t, FrameBuffer&, AESDecContext*, HMACContext*);
   Result_t    MD_to_JP2K_PDesc(JP2K::PictureDescriptor& PDesc);
 };
 
@@ -206,7 +205,7 @@ ASDCP::JP2K::MXFReader::h__Reader::ReadFrame(ui32_t FrameNum, FrameBuffer& Frame
   if ( ! m_File.IsOpen() )
     return RESULT_INIT;
 
-  return ReadEKLVPacket(FrameNum, FrameBuf, Dict::ul(MDD_JPEG2000Essence), Ctx, HMAC);
+  return ReadEKLVFrame(FrameNum, FrameBuf, Dict::ul(MDD_JPEG2000Essence), Ctx, HMAC);
 }
 
 //------------------------------------------------------------------------------------------
index b3044f63f3d2551f641331543af037e4a8892138..d2f288573553b3d32ea9aa1a52fec56169fb3852 100755 (executable)
@@ -230,7 +230,7 @@ ASDCP::MPEG2::MXFReader::h__Reader::ReadFrame(ui32_t FrameNum, FrameBuffer& Fram
   if ( ! m_File.IsOpen() )
     return RESULT_INIT;
 
-  Result_t result = ReadEKLVPacket(FrameNum, FrameBuf, Dict::ul(MDD_MPEG2Essence), Ctx, HMAC);
+  Result_t result = ReadEKLVFrame(FrameNum, FrameBuf, Dict::ul(MDD_MPEG2Essence), Ctx, HMAC);
 
   if ( ASDCP_FAILURE(result) )
     return result;
index 68d9d6be2ea2a3af8286eb1a48b9a5091dc656bc..9525cff2b1efd70c45753cfdf0aafd18a0b905d7 100755 (executable)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2004-2006, John Hurst
+Copyright (c) 2004-2007, John Hurst
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -30,6 +30,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include <KM_fileio.h>
+#include <KM_xml.h>
 #include "AS_DCP_internal.h"
 #include "JP2K.h"
 #include "MPEG.h"
@@ -156,6 +157,11 @@ ASDCP::EssenceType(const char* filename, EssenceType_t& type)
            {
              if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(MPEG2VideoDescriptor))) )
                type = ESS_MPEG2_VES;
+             else
+               {
+                 if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(DCTimedTextDescriptor))) )
+                   type = ESS_TIMED_TEXT;
+               }
            }
        }
     }
@@ -173,6 +179,8 @@ ASDCP::RawEssenceType(const char* filename, EssenceType_t& type)
   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
@@ -190,12 +198,17 @@ ASDCP::RawEssenceType(const char* filename, EssenceType_t& type)
       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 ( TmpElement.TestString((const char*)p, FB.Size()) )
+           type = ESS_TIMED_TEXT;
+
          else if ( ASDCP_SUCCESS(WavHeader.ReadFromBuffer(p, read_count, &data_offset)) )
            type = ESS_PCM_24b_48k;
 
index 38bf8e478c09781f2a1338cfed0fac3617e5487b..815de31bd4ee5de26c853ff9fec7fc0a5efd414f 100755 (executable)
@@ -202,7 +202,7 @@ ASDCP::PCM::MXFReader::h__Reader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameB
   if ( ! m_File.IsOpen() )
     return RESULT_INIT;
 
-  return ReadEKLVPacket(FrameNum, FrameBuf, Dict::ul(MDD_WAVEssence), Ctx, HMAC);
+  return ReadEKLVFrame(FrameNum, FrameBuf, Dict::ul(MDD_WAVEssence), Ctx, HMAC);
 }
 
 //------------------------------------------------------------------------------------------
index ccb7c3e49d96db35947d50f5c79e0d96be9df362..3e6108c005596c672d6e19d76ff87f95b2063c14 100644 (file)
@@ -34,12 +34,50 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "AS_DCP_TimedText.h"
 #include "KM_xml.h"
 
-using namespace Kumu;
-using namespace ASDCP;
+static std::string TIMED_TEXT_PACKAGE_LABEL = "File Package: SMPTE 429-5 frame 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-opentype";
+
+  return "application/octet-stream";
+}
+
+//
+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: %lu\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
@@ -49,7 +87,7 @@ ASDCP::TimedText::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
 
   UUID TmpID(m_AssetID);
   char buf[64];
-  fprintf(stream, "ID: %s (type %s)\n", TmpID.EncodeHex(buf, 64), m_MIMEType.c_str());
+  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);
@@ -57,22 +95,192 @@ ASDCP::TimedText::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
 
 //------------------------------------------------------------------------------------------
 
+typedef std::map<UUID, UUID> ResourceMap_t;
+
 class ASDCP::TimedText::MXFReader::h__Reader : public ASDCP::h__Reader
 {
-  TimedTextDescriptor*        m_EssenceDescriptor;
+  TimedTextDescriptor*  m_EssenceDescriptor;
+  ResourceMap_t         m_ResourceMap;
 
   ASDCP_NO_COPY_CONSTRUCT(h__Reader);
 
 public:
   TimedTextDescriptor m_TDesc;    
 
-  h__Reader() : m_EssenceDescriptor(0) {}
+  h__Reader() : m_EssenceDescriptor(0) {
+    memset(&m_TDesc.AssetID, 0, UUIDlen);
+  }
+
   Result_t    OpenRead(const char*);
-  Result_t    ReadFrame(ui32_t, FrameBuffer&, AESDecContext*, HMACContext*);
-  Result_t    ReadFrameGOPStart(ui32_t, FrameBuffer&, AESDecContext*, HMACContext*);
-  Result_t    MD_to_TimedText_PDesc(TimedText::TimedTextDescriptor& TDesc);
+  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::DCTimedTextDescriptor* TDescObj = (MXF::DCTimedTextDescriptor*)m_EssenceDescriptor;
+
+  TDesc.EditRate = TDescObj->SampleRate;
+  TDesc.ContainerDuration = TDescObj->ContainerDuration;
+  TDesc.NamespaceName = TDescObj->RootNamespaceName;
+  TDesc.EncodingName = TDescObj->UTFEncoding;
+
+  Batch<UUID>::const_iterator sdi = TDescObj->SubDescriptors.begin();
+  DCTimedTextResourceDescriptor* DescObject = 0;
+  Result_t result = RESULT_OK;
+
+  for ( ; sdi != TDescObj->SubDescriptors.end() && KM_SUCCESS(result); sdi++ )
+    {
+      result = m_HeaderPart.GetMDObjectByID(*sdi, (InterchangeObject**)&DescObject);
+
+      if ( KM_SUCCESS(result) )
+       {
+         TimedTextResourceDescriptor TmpResource;
+         memcpy(TmpResource.ResourceID, DescObject->ResourcePackageID.Value(), UUIDlen);
+
+         if ( DescObject->ResourceMIMEType.find("font/") != std::string::npos )
+           TmpResource.Type = MT_OPENTYPE;
+
+         else if ( DescObject->ResourceMIMEType.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->ResourcePackageID, *sdi));
+       }
+      else
+       {
+         DefaultLogSink().Error("Broken sub-descriptor link\n");
+         return RESULT_FORMAT;
+       }
+    }
+
+  return RESULT_OK;
+}
+
+//
+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 )
+         m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(DCTimedTextDescriptor), (InterchangeObject**)&m_EssenceDescriptor);
+
+      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;
+
+  return ReadEKLVFrame(0, FrameBuf, Dict::ul(MDD_DCTimedTextEssence), Ctx, HMAC);
+}
+
+//
+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_FORMAT;
+    }
+
+  DCTimedTextResourceDescriptor* DescObject = 0;
+  // get the subdescriptor
+  Result_t result = m_HeaderPart.GetMDObjectByID((*ri).second, (InterchangeObject**)&DescObject);
+
+  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 distance in because this is the sequence value needed to 
+      // complete the HMAC
+      //      result = m_HeaderPart.m_RIP.GetPairBySID(DescObject->ResourceSID, TmpPair);
+      for ( pi = m_HeaderPart.m_RIP.PairArray.begin(); pi != m_HeaderPart.m_RIP.PairArray.end(); pi++, sequence++ )
+       {
+         if ( (*pi).BodySID == DescObject->ResourceSID )
+           {
+             TmpPair = *pi;
+             break;
+           }
+       }
+
+      if ( TmpPair.ByteOffset == 0 )
+       {
+         DefaultLogSink().Error("Body SID not found in RIP set: %d\n", DescObject->ResourceSID);
+         return RESULT_FORMAT;
+       }
+
+      if ( KM_SUCCESS(result) )
+       {
+         FrameBuf.AssetID(uuid);
+         FrameBuf.MIMEType(DescObject->ResourceMIMEType);
+
+         // 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;
+         result = GSPart.InitFromFile(m_File);
+
+         if( ASDCP_SUCCESS(result) )
+           {
+             // check the SID
+             if ( DescObject->ResourceSID != 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
+             if( ASDCP_SUCCESS(result) )
+               result = ReadEKLVPacket(0, FrameBuf, Dict::ul(MDD_DCTimedTextDescriptor), Ctx, HMAC);
+           }
+       }
+    }
+
+  return result;
+}
+
+
 //------------------------------------------------------------------------------------------
 
 ASDCP::TimedText::MXFReader::MXFReader()
@@ -93,18 +301,6 @@ ASDCP::TimedText::MXFReader::OpenRead(const char* filename) const
   return m_Reader->OpenRead(filename);
 }
 
-//
-ASDCP::Result_t
-ASDCP::TimedText::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
@@ -119,7 +315,6 @@ ASDCP::TimedText::MXFReader::FillDescriptor(TimedText::TimedTextDescriptor& TDes
   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
@@ -134,6 +329,43 @@ ASDCP::TimedText::MXFReader::FillWriterInfo(WriterInfo& Info) const
   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
@@ -160,10 +392,11 @@ class ASDCP::TimedText::MXFWriter::h__Writer : public ASDCP::h__Writer
 public:
   TimedTextDescriptor m_TDesc;
   byte_t              m_EssenceUL[SMPTE_UL_LENGTH];
+  ui32_t              m_ResourceSID;
 
   ASDCP_NO_COPY_CONSTRUCT(h__Writer);
 
-  h__Writer() {
+  h__Writer() : m_ResourceSID(10) {
     memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
   }
 
@@ -171,11 +404,172 @@ public:
 
   Result_t OpenWrite(const char*, ui32_t HeaderSize);
   Result_t SetSourceStream(const TimedTextDescriptor&);
-  Result_t WriteFrame(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0);
+  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_PDesc_to_MD(TimedText::TimedTextDescriptor& PDesc);
+  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);
+  //  assert(m_EssenceSubDescriptor);
+  MXF::DCTimedTextDescriptor* TDescObj = (MXF::DCTimedTextDescriptor*)m_EssenceDescriptor;
+
+  TDescObj->SampleRate = TDesc.EditRate;
+  TDescObj->ContainerDuration = TDesc.ContainerDuration;
+  TDescObj->RootNamespaceName = TDesc.NamespaceName;
+  TDescObj->UTFEncoding = 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 DCTimedTextDescriptor();
+      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++ )
+    {
+      DCTimedTextResourceDescriptor* resourceSubdescriptor = new DCTimedTextResourceDescriptor;
+      GenRandomValue(resourceSubdescriptor->InstanceUID);
+      resourceSubdescriptor->ResourcePackageID.Set((*ri).ResourceID);
+      resourceSubdescriptor->ResourceMIMEType = MIME2str((*ri).Type);
+      resourceSubdescriptor->ResourceSID = m_ResourceSID++;
+      m_EssenceSubDescriptorList.push_back((FileDescriptor*)resourceSubdescriptor);
+      m_EssenceDescriptor->SubDescriptors.push_back(resourceSubdescriptor->InstanceUID);
+    }
+
+  m_ResourceSID = 10;
+
+  if ( ASDCP_SUCCESS(result) )
+    {
+      InitHeader();
+      AddDMSegment(m_TDesc.EditRate, 24, TIMED_TEXT_DEF_LABEL,
+                  UL(Dict::ul(MDD_PictureDataDef)), TIMED_TEXT_PACKAGE_LABEL);
+
+      AddEssenceDescriptor(UL(Dict::ul(MDD_DCTimedTextWrapping)));
+
+      result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize);
+      
+      if ( KM_SUCCESS(result) )
+       result = CreateBodyPart(m_TDesc.EditRate);
+    }
+
+  if ( ASDCP_SUCCESS(result) )
+    {
+      memcpy(m_EssenceUL, Dict::ul(MDD_DCTimedTextEssence), 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();
+
+  // create generic stream partition header
+  MXF::Partition GSPart;
+
+  GSPart.ThisPartition = here;
+  GSPart.PreviousPartition = m_HeaderPart.m_RIP.PairArray.back().ByteOffset;
+  GSPart.BodySID = m_ResourceSID;
+  GSPart.OperationalPattern = m_HeaderPart.OperationalPattern;
+
+  m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(m_ResourceSID++, here));
+  GSPart.EssenceContainers.push_back(UL(Dict::ul(MDD_DCTimedTextEssence)));
+  UL TmpUL(Dict::ul(MDD_GenericStreamPartition));
+  Result_t result = GSPart.WriteToFile(m_File, TmpUL);
+
+  if ( ASDCP_SUCCESS(result) )
+    result = WriteEKLVPacket(FrameBuf, m_EssenceUL, 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();
+}
+
 
 //------------------------------------------------------------------------------------------
 
@@ -194,6 +588,12 @@ 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;
   
   Result_t result = m_Writer->OpenWrite(filename, HeaderSize);
@@ -210,18 +610,24 @@ ASDCP::TimedText::MXFWriter::OpenWrite(const char* filename, const WriterInfo& I
   return result;
 }
 
+//
+ASDCP::Result_t
+ASDCP::TimedText::MXFWriter::WriteTimedTextResource(const std::string& XMLDoc, AESEncContext* Ctx, HMACContext* HMAC)
+{
+  if ( m_Writer.empty() )
+    return RESULT_INIT;
 
-// 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.
+  return m_Writer->WriteTimedTextResource(XMLDoc, Ctx, HMAC);
+}
+
+//
 ASDCP::Result_t
-ASDCP::TimedText::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
+ASDCP::TimedText::MXFWriter::WriteAncillaryResource(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
 {
   if ( m_Writer.empty() )
     return RESULT_INIT;
 
-  return m_Writer->WriteFrame(FrameBuf, Ctx, HMAC);
+  return m_Writer->WriteAncillaryResource(FrameBuf, Ctx, HMAC);
 }
 
 // Closes the MXF file, writing the index and other closing information.
index 177a74da00f6d0291e088923beefa8c8a0e09a4f..ff86d4022c65d377353e7a44fbc927621fbbdac9 100755 (executable)
@@ -111,6 +111,12 @@ namespace ASDCP
       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, ASDCP::FrameBuffer& FrameBuf,
                              const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC);
       void     Close();
@@ -152,6 +158,8 @@ namespace ASDCP
       inline Result_t Goto_FINAL()   { Goto_body(ST_RUNNING, ST_FINAL); }
     };
 
+  typedef std::list<ui64_t*> DurationElementList_t;
+
   //
   class h__Writer
     {
@@ -166,16 +174,7 @@ namespace ASDCP
       ui64_t             m_EssenceStart;
 
       MaterialPackage*   m_MaterialPackage;
-      Sequence*          m_MPTCSequence;
-      TimecodeComponent* m_MPTimecode;
-      Sequence*          m_MPClSequence;
-      SourceClip*        m_MPClip;                     //! Material Package SourceClip for each essence stream 
-
       SourcePackage*     m_FilePackage;
-      Sequence*          m_FPTCSequence;
-      TimecodeComponent* m_FPTimecode;
-      Sequence*          m_FPClSequence;
-      SourceClip*        m_FPClip;                     //! File Package SourceClip for each essence stream 
 
       FileDescriptor*    m_EssenceDescriptor;
       std::list<FileDescriptor*> m_EssenceSubDescriptorList;
@@ -185,10 +184,22 @@ namespace ASDCP
       ASDCP::FrameBuffer m_CtFrameBuf;
       h__WriterState     m_State;
       WriterInfo         m_Info;
+      DurationElementList_t m_DurationUpdateList;
 
       h__Writer();
       virtual ~h__Writer();
 
+      void InitHeader();
+      void AddSourceClip(const MXF::Rational& EditRate, ui32_t TCFrameRate,
+                        const std::string& TrackName, 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& DataDefinition,
                              const MXF::Rational& EditRate,
index c37db1b2ff959a7ef60c973218be5b61e1e0af89..5e0743c8333ed1e0d89b5e8a6ba5f76392b2e1d4 100755 (executable)
@@ -125,7 +125,7 @@ ASDCP::MXF::IndexTableSegment::Dump(FILE* stream)
     }
   else
     {
-      fprintf(stream, "  IndexEntryArray: %u entries\n", IndexEntryArray.size());
+      fprintf(stream, "  IndexEntryArray: %lu entries\n", IndexEntryArray.size());
     }
 }
 
index e01b01ffee0973e47618b03c379d3b792ab78ce3..50e01d65199659394ff4f8ed5ed744832fc464cf 100644 (file)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2004-2006, John Hurst
+Copyright (c) 2004-2007, John Hurst
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -53,6 +53,33 @@ struct iovec {
 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 != NULL )
+    {
+      char* cp = new char[(r-pstr)+1];
+      memcpy(cp, pstr, (r-pstr));
+      cp[(r-pstr)] = '\0';
+
+      if( strlen(cp) > 0 )
+       {
+         std::string s(cp);
+         components.push_back(s);
+       }
+
+      delete[] cp;
+      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)
@@ -104,14 +131,29 @@ do_fstat(HANDLE handle, fstat_t* stat_info)
 
 //
 bool
-Kumu::PathIsFile(const char* pathname)
+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 == 0 || *pathname == 0 )
+  if ( pathname.empty() )
     return false;
 
   fstat_t info;
 
-  if ( KM_SUCCESS(do_stat(pathname, &info)) )
+  if ( KM_SUCCESS(do_stat(pathname.c_str(), &info)) )
     {
       if ( info.st_mode & ( S_IFREG|S_IFLNK ) )
         return true;
@@ -123,14 +165,14 @@ Kumu::PathIsFile(const char* pathname)
 
 //
 bool
-Kumu::PathIsDirectory(const char* pathname)
+Kumu::PathIsDirectory(const std::string& pathname)
 {
-  if ( pathname == 0 || *pathname == 0 )
+  if ( pathname.empty() )
     return false;
 
   fstat_t info;
 
-  if ( KM_SUCCESS(do_stat(pathname, &info)) )
+  if ( KM_SUCCESS(do_stat(pathname.c_str(), &info)) )
     {
       if ( info.st_mode & S_IFDIR )
         return true;
@@ -139,17 +181,16 @@ Kumu::PathIsDirectory(const char* pathname)
   return false;
 }
 
-
 //
 Kumu::fsize_t
-Kumu::FileSize(const char* pathname)
+Kumu::FileSize(const std::string& pathname)
 {
-  if ( pathname == 0 || *pathname == 0 )
-    return false;
+  if ( pathname.empty() )
+    return 0;
 
   fstat_t info;
 
-  if ( KM_SUCCESS(do_stat(pathname, &info)) )
+  if ( KM_SUCCESS(do_stat(pathname.c_str(), &info)) )
     {
       if ( info.st_mode & ( S_IFREG|S_IFLNK ) )
         return(info.st_size);
@@ -158,6 +199,346 @@ Kumu::FileSize(const char* pathname)
   return 0;
 }
 
+//
+static PathCompList_t&
+s_PathMakeCanonical(PathCompList_t& CList, char separator, 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), 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;
+  CList.push_back(cwd_buf);
+  CList.push_back(Path);
+
+  return ComponentsToAbsolutePath(s_PathMakeCanonical(CList, separator, 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;
+}
+
+//
+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) {
+  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) {
+  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
 
@@ -438,7 +819,7 @@ Kumu::FileWriter::Write(const byte_t* buf, ui32_t buf_len, ui32_t* bytes_written
   BOOL result = ::WriteFile(m_Handle, buf, buf_len, (DWORD*)bytes_written, NULL);
   ::SetErrorMode(prev);
 
-  if ( result == 0 || bytes_written != buf_len )
+  if ( result == 0 || *bytes_written != buf_len )
     return Kumu::RESULT_WRITEFAIL;
 
   return Kumu::RESULT_OK;
index 96cdf00fa0276d5782510d710f5f87aac522ed62..43b164df2c5fc58681dfdf12222712717a5ba228 100755 (executable)
@@ -42,6 +42,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 # include <unistd.h>
 # include <time.h>
 # include <sys/types.h>
+#include <regex.h>
 #endif
 
 #include <sys/stat.h>
@@ -50,36 +51,24 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 namespace Kumu
 {
-#ifdef KM_WIN32
   //
   class DirScanner
     {
     public:
+#ifdef KM_WIN32
       __int64               m_Handle;
       struct _finddatai64_t m_FileInfo;
+#else
+      DIR*       m_Handle;
+#endif
 
       DirScanner()  {};
       ~DirScanner() { Close(); }
+
       Result_t Open(const char*);
       Result_t Close();
       Result_t GetNext(char*);
     };
-#else // KM_WIN32
-  // POSIX directory scanner
-  //
-  class DirScanner
-    {
-    public:
-      DIR*       m_Handle;
-
-      DirScanner() : m_Handle(NULL) {}
-      ~DirScanner() { Close(); }
-      
-      Result_t  Open(const char*);
-      Result_t  Close();
-      Result_t  GetNext(char*);
-    };
-#endif // KM_WIN32
 
 #ifdef KM_WIN32
   typedef __int64  fsize_t;
@@ -109,10 +98,86 @@ namespace Kumu
 
   const ui32_t MaxFilePath = Kilobyte;
 
-  bool     PathIsFile(const char* pathname);
-  bool     PathIsDirectory(const char* pathname);
-  fsize_t  FileSize(const char* pathname);
+  // Path Manglers
+  //
+  typedef std::list<std::string> PathCompList_t; // a list of path components
+  typedef std::list<std::string> PathList_t; // a list of paths
+
+  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
+
+  // split and reassemble pats 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 '..'
+
+  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
 
+  //
+  //
+  class IPathMatch
+  {
+  public:
+    virtual ~IPathMatch() {}
+    virtual bool Match(const std::string& s) const = 0;
+  };
+
+ class PathMatchAny : public IPathMatch
+  {
+  public:
+    virtual ~PathMatchAny() {}
+    inline bool Match(const std::string& s) const { return true; }
+  };
+
+ 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;
+  };
+
+ 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;
+  };
+
+  // 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, char separator);
+
+  PathList_t& FindInPaths(const IPathMatch& Pattern, const PathList_t& SearchPaths,
+                         PathList_t& FoundPaths, bool one_shot = false, char separator = '/');
+
+
+  // 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);
 
index 605ea11abed74a6ba7d7629e78c3402f71484669..03102919b664d17ce1d0ae2d8b9d56fe7d07d32b 100644 (file)
@@ -30,10 +30,36 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include <KM_xml.h>
+#include <KM_log.h>
+#include <stack>
+#include <map>
 
+#ifdef ASDCP_USE_EXPAT
+#include <expat.h>
+#endif
 
+using namespace Kumu;
 
-Kumu::XMLElement::XMLElement(const char* name)
+
+class ns_map : public std::map<std::string, XMLNamespace*>
+{
+public:
+  ns_map() {}
+  ~ns_map()
+  {
+    ns_map::iterator ni = begin();
+
+    while (ni != end() )
+      {
+       //      fprintf(stderr, "deleting namespace %s:%s\n", ni->second->Prefix().c_str(), ni->second->Name().c_str());
+       delete ni->second;
+       ni++;
+      }
+  }
+};
+
+
+Kumu::XMLElement::XMLElement(const char* name) : m_Namespace(0), m_NamespaceOwner(0)
 {
   m_Name = name;
 }
@@ -42,6 +68,9 @@ Kumu::XMLElement::~XMLElement()
 {
   for ( Elem_i i = m_ChildList.begin(); i != m_ChildList.end(); i++ )
     delete *i;
+
+  if ( m_NamespaceOwner != 0 )
+    delete (ns_map*)m_NamespaceOwner;
 }
 
 //
@@ -71,6 +100,13 @@ 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;
+}
+
 //
 Kumu::XMLElement*
 Kumu::XMLElement::AddChildWithContent(const char* name, const char* value)
@@ -105,7 +141,7 @@ Kumu::XMLElement::AddComment(const char* value)
 
 //
 void
-Kumu::XMLElement::Render(std::string& outbuf)
+Kumu::XMLElement::Render(std::string& outbuf) const
 {
   outbuf = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
   RenderElement(outbuf, 0);
@@ -121,7 +157,7 @@ add_spacer(std::string& outbuf, i32_t depth)
 
 //
 void
-Kumu::XMLElement::RenderElement(std::string& outbuf, ui32_t depth)
+Kumu::XMLElement::RenderElement(std::string& outbuf, ui32_t depth) const
 {
   add_spacer(outbuf, depth);
 
@@ -164,6 +200,293 @@ Kumu::XMLElement::RenderElement(std::string& outbuf, ui32_t depth)
   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;
+}
+
+//----------------------------------------------------------------------------------------------------
+
+#ifdef ASDCP_USE_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 std::string& document)
+{
+  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.c_str(), document.size(), 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* name, const XML_Char** attrs)
+{
+  assert(p);
+  xph_test_wrapper* Wrapper = (xph_test_wrapper*)p;
+
+  Wrapper->Status = true;
+  XML_StopParser(Wrapper->Parser, false);
+}
+
+
+//
+bool
+Kumu::XMLElement::TestString(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;
+}
+
+#else // no XML parser support
+
+//
+bool
+Kumu::XMLElement::ParseString(const std::string& document)
+{
+  DefaultLogSink().Error("asdcplib compiled without XML parser support.\n");
+  return false;
+}
+
+//
+bool
+Kumu::XMLElement::TestString(const char* document, ui32_t len)
+{
+  DefaultLogSink().Error("asdcplib compiled without XML parser support.\n");
+  return false;
+}
+
+#endif
+
 
 //
 // end KM_xml.cpp
index ae24ac1b4ec0c9b6a34849146c284be128e7f03d..31f506471cabacffe1e714a224e0590b1db172e9 100644 (file)
@@ -41,41 +41,79 @@ namespace Kumu
 {
   class XMLElement;
 
+  //
   struct NVPair
   {
     std::string name;
     std::string value;
   };
 
+  //
   typedef std::list<NVPair> AttributeList;
-  typedef AttributeList::iterator Attr_i;
+  typedef AttributeList::const_iterator Attr_i;
   typedef std::list<XMLElement*> ElementList;
-  typedef ElementList::iterator Elem_i;
+  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
     {
-      AttributeList m_AttrList;
-      ElementList   m_ChildList;
+      AttributeList       m_AttrList;
+      ElementList         m_ChildList;
+      const XMLNamespace* m_Namespace;
+      void*               m_NamespaceOwner;
+
+      std::string   m_Name;
+      std::string   m_Body;
 
       KM_NO_COPY_CONSTRUCT(XMLElement);
       XMLElement();
 
     public:
-      std::string   m_Name;
-      std::string   m_Body;
-
       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 std::string& document);
+      bool        TestString(const char* document, ui32_t len = 0);
+
+      // building
+      void        SetName(const char* name);
+      void        AppendBody(const std::string& value);
       void        SetAttr(const char* name, const char* value);
       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&);
-      void        RenderElement(std::string& outbuf, ui32_t depth);
+      void        Render(std::string&) const;
+      void        RenderElement(std::string& outbuf, ui32_t depth) const;
+
+      // querying
+      inline const std::string& GetBody() const { return m_Body; }
+      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;
+
     };
 } // namespace Kumu
 
index 9195df20a0525ed64c6bc46814398c7fda05bc8c..db43df0080599ecd45c2de42d66ff5fe42e8d063 100644 (file)
@@ -798,10 +798,49 @@ static const ASDCP::MDDEntry s_MDD_Table[] = {
   { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x09, // 254
       0x02, 0x09, 0x03, 0x01, 0x02, 0x00, 0x00, 0x00 },
       {0}, false, "CryptographicContext_CryptographicKeyID" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x00, 0x01, 0x01, 0x01, // 255
+      0x0d, 0x01, 0x03, 0x01, 0xfa, 0xce, 0x00, 0x00 },
+      {0}, false, "DCTimedTextWrapping" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x00, 0x01, 0x01, 0x01, // 256
+      0x0d, 0x01, 0x03, 0x01, 0xfa, 0xce, 0x00, 0x01 },
+      {0}, false, "DCTimedTextEssence" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x00, 0x01, 0x01, 0x01, // 257
+      0x0d, 0x01, 0x03, 0x01, 0xfa, 0xce, 0x00, 0x02 },
+      {0}, false, "DCTimedTextDescriptor" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x00, 0x01, 0x01, 0x01, // 258
+      0x0d, 0x01, 0x03, 0x01, 0xfa, 0xce, 0x00, 0x03 },
+      {0}, false, "DCTimedTextDescriptor_UTFEncoding" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x00, 0x01, 0x01, 0x01, // 259
+      0x0d, 0x01, 0x03, 0x01, 0xfa, 0xce, 0x00, 0x04 },
+      {0}, false, "DCTimedTextDescriptor_RootNamespaceName" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x00, 0x01, 0x01, 0x01, // 260
+      0x0d, 0x01, 0x03, 0x01, 0xfa, 0xce, 0x00, 0x05 },
+      {0}, false, "DCTimedTextResourceDescriptor" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x00, 0x01, 0x01, 0x01, // 261
+      0x0d, 0x01, 0x03, 0x01, 0xfa, 0xce, 0x00, 0x06 },
+      {0}, false, "DCTimedTextResourceDescriptor_ResourcePackageID" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x00, 0x01, 0x01, 0x01, // 262
+      0x0d, 0x01, 0x03, 0x01, 0xfa, 0xce, 0x00, 0x07 },
+      {0}, false, "DCTimedTextResourceDescriptor_ResourceMIMEType" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x00, 0x01, 0x01, 0x01, // 263
+      0x0d, 0x01, 0x03, 0x01, 0xfa, 0xce, 0x00, 0x08 },
+    {0}, false, "DCTimedTextResourceDescriptor_ResourceSID" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 264
+      0x06, 0x10, 0x10, 0x05, 0x01, 0x02, 0x11, 0x00 },
+    {0}, false, "GenericStreamPartition" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 265
+      0x04, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 },
+    {0x02, 0x01}, false, "DMSegment_DataDefinition" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 266
+      0x07, 0x02, 0x02, 0x01, 0x01, 0x03, 0x00, 0x00 },
+    {0x02, 0x02}, true, "DMSegment_Duration" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 267
+      0x01, 0x07, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00 },
+    {0x61, 0x02}, false, "DMSegment_TrackIDList" },
   { {0}, {0}, false, 0 }
 };
 
-const ui32_t s_MDD_Table_size = 255;
+const ui32_t s_MDD_Table_size = 268;
 
 //
 // end MDD.cpp
index 90a777734ed77a681c5fc9aed2ea3358fc595179..dec65cfcef93eb15965dd17d3656e41b584b7d94 100755 (executable)
--- a/src/MDD.h
+++ b/src/MDD.h
@@ -290,6 +290,19 @@ namespace ASDCP {
         MDD_CryptographicContext_CipherAlgorithm,  // 252
         MDD_CryptographicContext_MICAlgorithm,  // 253
         MDD_CryptographicContext_CryptographicKeyID,  // 254
+       MDD_DCTimedTextWrapping, // 255
+       MDD_DCTimedTextEssence, // 256
+       MDD_DCTimedTextDescriptor, // 257
+       MDD_DCTimedTextDescriptor_UTFEncoding, // 258
+       MDD_DCTimedTextDescriptor_RootNamespaceName, // 259
+       MDD_DCTimedTextResourceDescriptor, // 260
+       MDD_DCTimedTextResourceDescriptor_ResourcePackageID, // 261
+       MDD_DCTimedTextResourceDescriptor_ResourceMIMEType, // 262
+       MDD_DCTimedTextResourceDescriptor_ResourceSID, //263
+       MDD_GenericStreamPartition, // 264
+       MDD_DMSegment_DataDefinition, // 265
+       MDD_DMSegment_Duration, // 266
+       MDD_DMSegment_TrackIDList, // 267
     }; // enum MDD_t
 } // namespaceASDCP
 
index fb32e8af2a31800a75cf0cf4c9a7c80380b38801..fd0b709d7573c90825b6eb2111e321851128a58e 100755 (executable)
@@ -30,6 +30,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include "MXF.h"
+#include "Metadata.h"
 #include <KM_log.h>
 using Kumu::DefaultLogSink;
 
@@ -89,6 +90,23 @@ ASDCP::MXF::SeekToRIP(const Kumu::FileReader& Reader)
   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)
@@ -176,6 +194,23 @@ public:
     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)
   {
@@ -195,6 +230,21 @@ public:
 
     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;
+  }
 };
 
 //------------------------------------------------------------------------------------------
@@ -503,7 +553,7 @@ ASDCP::MXF::Primer::Dump(FILE* stream)
 
   KLVPacket::Dump(stream, false);
   fprintf(stream, "Primer: %u %s\n",
-         LocalTagEntryBatch.size(),
+         (ui32_t)LocalTagEntryBatch.size(),
          ( LocalTagEntryBatch.size() == 1 ? "entry" : "entries" ));
   
   Batch<LocalTagEntry>::iterator i = LocalTagEntryBatch.begin();
@@ -619,15 +669,15 @@ ASDCP::MXF::OPAtomHeader::InitFromFile(const Kumu::FileReader& Reader)
          DefaultLogSink().Error("RIP contains no Pairs.\n");
          result = RESULT_FORMAT;
        }
-      else if ( test_s < 2 || test_s > 3 )
-       {
-         // OP-Atom states that there will be either two or three partitions,
-         // one closed header and one closed footer with an optional body
-         DefaultLogSink().Error("RIP count is not 2 or 3: %u\n", test_s);
-         return RESULT_FORMAT;
-       }
       else
        {
+         if ( test_s < 2 || test_s > 3 )
+           {
+             // OP-Atom states that there will be either two or three partitions:
+             // one closed header and one closed footer with an optional body
+             DefaultLogSink().Warn("RIP count is not 2 or 3: %u\n", test_s);
+           }
+
          m_HasRIP = true;
       
          if ( m_RIP.PairArray.front().ByteOffset !=  0 )
@@ -730,6 +780,12 @@ ASDCP::MXF::OPAtomHeader::InitFromFile(const Kumu::FileReader& Reader)
   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)
@@ -742,6 +798,13 @@ ASDCP::MXF::OPAtomHeader::GetMDObjectByType(const byte_t* ObjectID, InterchangeO
   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()
@@ -994,8 +1057,8 @@ ASDCP::MXF::OPAtomIndexFooter::WriteToFile(Kumu::FileWriter& Writer, ui64_t dura
 
   if ( ASDCP_SUCCESS(result) )
     {
-      ui32_t write_count;
-      Writer.Write(FooterBuffer.RoData(), FooterBuffer.Size(), &write_count);
+      ui32_t write_count = 0;
+      result = Writer.Write(FooterBuffer.RoData(), FooterBuffer.Size(), &write_count);
       assert(write_count == FooterBuffer.Size());
     }
 
@@ -1206,6 +1269,84 @@ ASDCP::MXF::InterchangeObject::IsA(const byte_t* label)
 }
 
 
+//------------------------------------------------------------------------------------------
+
+
+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 byte_t* label)
+{
+  if ( label == 0 )
+    return 0;
+
+  if ( ! s_TypesInit )
+    {
+      Kumu::AutoMutex BlockLock(s_InitLock);
+
+      if ( ! s_TypesInit )
+       {
+         MXF::Metadata_InitTypes();
+         s_TypesInit = true;
+       }
+    }
+
+  FLi_t i = s_FactoryList.find(label);
+
+  if ( i == s_FactoryList.end() )
+    return new InterchangeObject;
+
+  return i->second();
+}
+
+
+
 //
 // end MXF.cpp
 //
index ed7fb0dc4fa8a39e791978c7af1c3f8cc13c133e..05b04992b21a83f62661a36565f47dbb2e80ed3f 100755 (executable)
--- a/src/MXF.h
+++ b/src/MXF.h
@@ -40,6 +40,16 @@ namespace ASDCP
     {
       class InterchangeObject;
 
+      //
+      typedef ASDCP::MXF::InterchangeObject* (*MXFObjectFactory_t)();
+
+      //
+      void SetObjectFactory(UL label, MXFObjectFactory_t factory);
+
+      //
+      InterchangeObject* CreateObject(const byte_t* label);
+
+
       // seek an open file handle to the start of the RIP KLV packet
       Result_t SeekToRIP(const Kumu::FileReader&);
       
@@ -89,6 +99,7 @@ namespace ASDCP
          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);
        };
 
@@ -200,9 +211,6 @@ namespace ASDCP
          virtual void     Dump(FILE* stream = 0);
        };
 
-      //
-      InterchangeObject* CreateObject(const byte_t* label);
-
       //
       class Preface : public InterchangeObject
        {
@@ -314,7 +322,9 @@ namespace ASDCP
          virtual Result_t InitFromFile(const Kumu::FileReader& Reader);
          virtual Result_t WriteToFile(Kumu::FileWriter& Writer, ui32_t HeaderLength = 16384);
          virtual void     Dump(FILE* = 0);
+         virtual Result_t 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);
          Identification*  GetIdentification();
          SourcePackage*   GetSourcePackage();
        };
index 625a2e2c05b78cda8545939a61c94ca5c0f5cc51..3ef22942c3bce4dd367a051c8941d908e7edf262 100755 (executable)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2005-2006, John Hurst
+Copyright (c) 2005-2007, John Hurst
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -32,6 +32,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <KM_prng.h>
 #include "MXFTypes.h"
 #include <KM_log.h>
+
 using Kumu::DefaultLogSink;
 
 //------------------------------------------------------------------------------------------
@@ -144,43 +145,62 @@ ASDCP::UMID::EncodeString(char* str_buf, ui32_t buf_len) const
 //------------------------------------------------------------------------------------------
 //
 
+//
 const ASDCP::MXF::UTF16String&
 ASDCP::MXF::UTF16String::operator=(const char* sz)
 {
   if ( sz == 0 || *sz == 0 )
-    {
-      m_length = 0;
-      *m_buffer = 0;
-    }
+    clear();
+
   else
-    {
-      ui32_t len = Kumu::xmin((ui32_t)strlen(sz), (IdentBufferLen - 1));
-      m_length = len;
-      memcpy(m_buffer, sz, m_length);
-      m_buffer[m_length] = 0;
-    }
+    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)
 {
-  const byte_t* p = Reader->CurrentData();
-  m_length = Reader->Remainder();
-  assert(m_length % 2 == 0);
-  m_length /= 2;
-  assert(IdentBufferLen >= m_length);
-  ui32_t i = 0;
+  clear();
+  const ui16_t* p = (ui16_t*)Reader->CurrentData();
+  ui32_t length = Reader->Remainder() / 2;
+  char mb_buf[MB_LEN_MAX+1];
 
-  for ( i = 0; i < m_length; i++ )
-    m_buffer[i] = p[(i*2)+1];
+  for ( ui32_t i = 0; i < length; i++ )
+    {
+      int count = wctomb(mb_buf, KM_i16_BE(p[i]));
 
-  m_buffer[i] = 0;
+      if ( count == -1 )
+       {
+         DefaultLogSink().Error("Unable to decode wide character 0x%04hx\n", p[i]);
+         return false;
+       }
 
-  Reader->SkipOffset(m_length*2);
+      assert(count <= MB_LEN_MAX);
+      mb_buf[count] = 0;
+      this->append(mb_buf);
+    }
+
+  Reader->SkipOffset(length*2);
   return true;
 }
 
@@ -188,14 +208,42 @@ ASDCP::MXF::UTF16String::Unarchive(Kumu::MemIOReader* Reader)
 bool
 ASDCP::MXF::UTF16String::Archive(Kumu::MemIOWriter* Writer) const
 {
-  byte_t* p = Writer->Data() + Writer->Length();
+  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;
-  memset(p, 0, (m_length*2)+2);
 
-  for ( i = 0; i < m_length; i++ )
-    p[(i*2)+1] = m_buffer[i];
+  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;
+    }
 
-  Writer->AddOffset(m_length * 2);
   return true;
 }
 
index c5541be13a193981a873997a8c22475ad761eac5..c6617aa96a536759dd453c5093f1ee814344805a 100755 (executable)
@@ -265,27 +265,18 @@ namespace ASDCP
        };
 
       //
-      class UTF16String : public Kumu::IArchive
+    class UTF16String : public std::string, public Kumu::IArchive
        {
-         ui16_t m_length;
-         char   m_buffer[IdentBufferLen];
-         ASDCP_NO_COPY_CONSTRUCT(UTF16String);
-         
        public:
-         UTF16String() : m_length(0) { *m_buffer = 0; }
+         UTF16String() {}
          ~UTF16String() {}
 
          const UTF16String& operator=(const char*);
+         const UTF16String& operator=(const std::string&);
 
-         //
-         const char* EncodeString(char* str_buf, ui32_t buf_len) const {
-           strncpy(str_buf, m_buffer, Kumu::xmin(buf_len, ((ui32_t)m_length+1)));
-           str_buf[buf_len-1] = 0;
-           return str_buf;
-         }
-
+         const char* EncodeString(char* str_buf, ui32_t buf_len) const;
          virtual bool Unarchive(Kumu::MemIOReader* Reader);
-         inline virtual bool HasValue() const { return m_length > 0; }
+         inline virtual bool HasValue() const { return ! empty(); }
          virtual bool Archive(Kumu::MemIOWriter* Writer) const;
        };
 
index 3290b1b51201274446d537bbfe1850c96114620f..9509926141da85780a3e138795460757f536d640 100755 (executable)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2005-2006, John Hurst
+Copyright (c) 2005-2007, John Hurst
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -33,138 +33,72 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #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;
 
 //------------------------------------------------------------------------------------------
 
-//
-enum FLT_t
-  {
-    FLT_Preface,
-    FLT_IndexTableSegment,
-    FLT_Identification,
-    FLT_ContentStorage,
-    FLT_EssenceContainerData,
-    FLT_MaterialPackage,
-    FLT_SourcePackage,
-    FLT_StaticTrack,
-    FLT_Track,
-    FLT_Sequence,
-    FLT_SourceClip,
-    FLT_TimecodeComponent,
-    FLT_FileDescriptor,
-    FLT_GenericSoundEssenceDescriptor,
-    FLT_WaveAudioDescriptor,
-    FLT_GenericPictureEssenceDescriptor,
-    FLT_RGBAEssenceDescriptor,
-    FLT_JPEG2000PictureSubDescriptor,
-    FLT_CDCIEssenceDescriptor,
-    FLT_MPEG2VideoDescriptor,
-    FLT_DMSegment,
-    FLT_CryptographicFramework,
-    FLT_CryptographicContext,
-  };
-
-//
-typedef std::map<ASDCP::UL, FLT_t>::iterator FLi_t;
-
-class FactoryList : public std::map<ASDCP::UL, FLT_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();
-  }
-
-};
-
-//
-static FactoryList s_FactoryList;
-
-//
-ASDCP::MXF::InterchangeObject*
-ASDCP::MXF::CreateObject(const byte_t* label)
-{
-  if ( label == 0 )
-    return 0;
-
-  if ( s_FactoryList.empty() )
-    {
-      s_FactoryList.insert(FactoryList::value_type(Dict::ul(MDD_Preface), FLT_Preface));
-      s_FactoryList.insert(FactoryList::value_type(Dict::ul(MDD_IndexTableSegment), FLT_IndexTableSegment));
-      s_FactoryList.insert(FactoryList::value_type(Dict::ul(MDD_Identification), FLT_Identification));
-      s_FactoryList.insert(FactoryList::value_type(Dict::ul(MDD_ContentStorage), FLT_ContentStorage));
-      s_FactoryList.insert(FactoryList::value_type(Dict::ul(MDD_EssenceContainerData), FLT_EssenceContainerData));
-      s_FactoryList.insert(FactoryList::value_type(Dict::ul(MDD_MaterialPackage), FLT_MaterialPackage));
-      s_FactoryList.insert(FactoryList::value_type(Dict::ul(MDD_SourcePackage), FLT_SourcePackage));
-      s_FactoryList.insert(FactoryList::value_type(Dict::ul(MDD_StaticTrack), FLT_StaticTrack));
-      s_FactoryList.insert(FactoryList::value_type(Dict::ul(MDD_Track), FLT_Track));
-      s_FactoryList.insert(FactoryList::value_type(Dict::ul(MDD_Sequence), FLT_Sequence));
-      s_FactoryList.insert(FactoryList::value_type(Dict::ul(MDD_SourceClip), FLT_SourceClip));
-      s_FactoryList.insert(FactoryList::value_type(Dict::ul(MDD_TimecodeComponent), FLT_TimecodeComponent));
-      s_FactoryList.insert(FactoryList::value_type(Dict::ul(MDD_FileDescriptor), FLT_FileDescriptor));
-      s_FactoryList.insert(FactoryList::value_type(Dict::ul(MDD_GenericSoundEssenceDescriptor), FLT_GenericSoundEssenceDescriptor));
-      s_FactoryList.insert(FactoryList::value_type(Dict::ul(MDD_WaveAudioDescriptor), FLT_WaveAudioDescriptor));
-      s_FactoryList.insert(FactoryList::value_type(Dict::ul(MDD_GenericPictureEssenceDescriptor), FLT_GenericPictureEssenceDescriptor));
-      s_FactoryList.insert(FactoryList::value_type(Dict::ul(MDD_RGBAEssenceDescriptor), FLT_RGBAEssenceDescriptor));
-      s_FactoryList.insert(FactoryList::value_type(Dict::ul(MDD_JPEG2000PictureSubDescriptor), FLT_JPEG2000PictureSubDescriptor));
-      s_FactoryList.insert(FactoryList::value_type(Dict::ul(MDD_CDCIEssenceDescriptor), FLT_CDCIEssenceDescriptor));
-      s_FactoryList.insert(FactoryList::value_type(Dict::ul(MDD_MPEG2VideoDescriptor), FLT_MPEG2VideoDescriptor));
-      s_FactoryList.insert(FactoryList::value_type(Dict::ul(MDD_DMSegment), FLT_DMSegment));
-      s_FactoryList.insert(FactoryList::value_type(Dict::ul(MDD_CryptographicFramework), FLT_CryptographicFramework));
-      s_FactoryList.insert(FactoryList::value_type(Dict::ul(MDD_CryptographicContext), FLT_CryptographicContext));
-    }
-
-  FLi_t i = s_FactoryList.find(label);
-
-  if ( i == s_FactoryList.end() )
-    return new InterchangeObject;
-
-  switch ( i->second )
-    {
-      case FLT_Preface: return new Preface;
-      case FLT_IndexTableSegment: return new IndexTableSegment;
-      case FLT_Identification: return new Identification;
-      case FLT_ContentStorage: return new ContentStorage;
-      case FLT_EssenceContainerData: return new EssenceContainerData;
-      case FLT_MaterialPackage: return new MaterialPackage;
-      case FLT_SourcePackage: return new SourcePackage;
-      case FLT_StaticTrack: return new StaticTrack;
-      case FLT_Track: return new Track;
-      case FLT_Sequence: return new Sequence;
-      case FLT_SourceClip: return new SourceClip;
-      case FLT_TimecodeComponent: return new TimecodeComponent;
-      case FLT_FileDescriptor: return new FileDescriptor;
-      case FLT_GenericSoundEssenceDescriptor: return new GenericSoundEssenceDescriptor;
-      case FLT_WaveAudioDescriptor: return new WaveAudioDescriptor;
-      case FLT_GenericPictureEssenceDescriptor: return new GenericPictureEssenceDescriptor;
-      case FLT_RGBAEssenceDescriptor: return new RGBAEssenceDescriptor;
-      case FLT_JPEG2000PictureSubDescriptor: return new JPEG2000PictureSubDescriptor;
-      case FLT_CDCIEssenceDescriptor: return new CDCIEssenceDescriptor;
-      case FLT_MPEG2VideoDescriptor: return new MPEG2VideoDescriptor;
-      case FLT_DMSegment: return new DMSegment;
-      case FLT_CryptographicFramework: return new CryptographicFramework;
-      case FLT_CryptographicContext: return new CryptographicContext;
-    }
-
-  return 0;
-}
+static InterchangeObject* Preface_Factory() { return new Preface; }
+static InterchangeObject* IndexTableSegment_Factory() { return new IndexTableSegment; }
+
+static InterchangeObject* Identification_Factory() { return new Identification; }
+static InterchangeObject* ContentStorage_Factory() { return new ContentStorage; }
+static InterchangeObject* EssenceContainerData_Factory() { return new EssenceContainerData; }
+static InterchangeObject* MaterialPackage_Factory() { return new MaterialPackage; }
+static InterchangeObject* SourcePackage_Factory() { return new SourcePackage; }
+static InterchangeObject* StaticTrack_Factory() { return new StaticTrack; }
+static InterchangeObject* Track_Factory() { return new Track; }
+static InterchangeObject* Sequence_Factory() { return new Sequence; }
+static InterchangeObject* SourceClip_Factory() { return new SourceClip; }
+static InterchangeObject* TimecodeComponent_Factory() { return new TimecodeComponent; }
+static InterchangeObject* FileDescriptor_Factory() { return new FileDescriptor; }
+static InterchangeObject* GenericSoundEssenceDescriptor_Factory() { return new GenericSoundEssenceDescriptor; }
+static InterchangeObject* WaveAudioDescriptor_Factory() { return new WaveAudioDescriptor; }
+static InterchangeObject* GenericPictureEssenceDescriptor_Factory() { return new GenericPictureEssenceDescriptor; }
+static InterchangeObject* RGBAEssenceDescriptor_Factory() { return new RGBAEssenceDescriptor; }
+static InterchangeObject* JPEG2000PictureSubDescriptor_Factory() { return new JPEG2000PictureSubDescriptor; }
+static InterchangeObject* CDCIEssenceDescriptor_Factory() { return new CDCIEssenceDescriptor; }
+static InterchangeObject* MPEG2VideoDescriptor_Factory() { return new MPEG2VideoDescriptor; }
+static InterchangeObject* DMSegment_Factory() { return new DMSegment; }
+static InterchangeObject* CryptographicFramework_Factory() { return new CryptographicFramework; }
+static InterchangeObject* CryptographicContext_Factory() { return new CryptographicContext; }
+static InterchangeObject* GenericDataEssenceDescriptor_Factory() { return new GenericDataEssenceDescriptor; }
+static InterchangeObject* DCTimedTextDescriptor_Factory() { return new DCTimedTextDescriptor; }
+static InterchangeObject* DCTimedTextResourceDescriptor_Factory() { return new DCTimedTextResourceDescriptor; }
 
+void
+ASDCP::MXF::Metadata_InitTypes()
+{
+  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_DCTimedTextDescriptor), DCTimedTextDescriptor_Factory);
+  SetObjectFactory(Dict::ul(MDD_DCTimedTextResourceDescriptor), DCTimedTextResourceDescriptor_Factory);
+}
 
 //------------------------------------------------------------------------------------------
 // KLV Sets
@@ -176,7 +110,7 @@ ASDCP::MXF::CreateObject(const byte_t* label)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::Identification::InitFromTLVSet(TLVReader& TLVSet)
+Identification::InitFromTLVSet(TLVReader& TLVSet)
 {
   Result_t result = InterchangeObject::InitFromTLVSet(TLVSet);
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Identification, ThisGenerationUID));
@@ -193,7 +127,7 @@ ASDCP::MXF::Identification::InitFromTLVSet(TLVReader& TLVSet)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::Identification::WriteToTLVSet(TLVWriter& TLVSet)
+Identification::WriteToTLVSet(TLVWriter& TLVSet)
 {
   Result_t result = InterchangeObject::WriteToTLVSet(TLVSet);
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Identification, ThisGenerationUID));
@@ -210,7 +144,7 @@ ASDCP::MXF::Identification::WriteToTLVSet(TLVWriter& TLVSet)
 
 //
 void
-ASDCP::MXF::Identification::Dump(FILE* stream)
+Identification::Dump(FILE* stream)
 {
   char identbuf[IdentBufferLen];
   *identbuf = 0;
@@ -232,7 +166,7 @@ ASDCP::MXF::Identification::Dump(FILE* stream)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::Identification::InitFromBuffer(const byte_t* p, ui32_t l)
+Identification::InitFromBuffer(const byte_t* p, ui32_t l)
 {
   m_Typeinfo = &Dict::Type(MDD_Identification);
   return InterchangeObject::InitFromBuffer(p, l);
@@ -240,7 +174,7 @@ ASDCP::MXF::Identification::InitFromBuffer(const byte_t* p, ui32_t l)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::Identification::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+Identification::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
 {
   m_Typeinfo = &Dict::Type(MDD_Identification);
   return InterchangeObject::WriteToBuffer(Buffer);
@@ -251,7 +185,7 @@ ASDCP::MXF::Identification::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::ContentStorage::InitFromTLVSet(TLVReader& TLVSet)
+ContentStorage::InitFromTLVSet(TLVReader& TLVSet)
 {
   Result_t result = InterchangeObject::InitFromTLVSet(TLVSet);
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(ContentStorage, Packages));
@@ -261,7 +195,7 @@ ASDCP::MXF::ContentStorage::InitFromTLVSet(TLVReader& TLVSet)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::ContentStorage::WriteToTLVSet(TLVWriter& TLVSet)
+ContentStorage::WriteToTLVSet(TLVWriter& TLVSet)
 {
   Result_t result = InterchangeObject::WriteToTLVSet(TLVSet);
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(ContentStorage, Packages));
@@ -271,7 +205,7 @@ ASDCP::MXF::ContentStorage::WriteToTLVSet(TLVWriter& TLVSet)
 
 //
 void
-ASDCP::MXF::ContentStorage::Dump(FILE* stream)
+ContentStorage::Dump(FILE* stream)
 {
   char identbuf[IdentBufferLen];
   *identbuf = 0;
@@ -288,7 +222,7 @@ ASDCP::MXF::ContentStorage::Dump(FILE* stream)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::ContentStorage::InitFromBuffer(const byte_t* p, ui32_t l)
+ContentStorage::InitFromBuffer(const byte_t* p, ui32_t l)
 {
   m_Typeinfo = &Dict::Type(MDD_ContentStorage);
   return InterchangeObject::InitFromBuffer(p, l);
@@ -296,7 +230,7 @@ ASDCP::MXF::ContentStorage::InitFromBuffer(const byte_t* p, ui32_t l)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::ContentStorage::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+ContentStorage::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
 {
   m_Typeinfo = &Dict::Type(MDD_ContentStorage);
   return InterchangeObject::WriteToBuffer(Buffer);
@@ -307,7 +241,7 @@ ASDCP::MXF::ContentStorage::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::EssenceContainerData::InitFromTLVSet(TLVReader& TLVSet)
+EssenceContainerData::InitFromTLVSet(TLVReader& TLVSet)
 {
   Result_t result = InterchangeObject::InitFromTLVSet(TLVSet);
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(EssenceContainerData, LinkedPackageUID));
@@ -318,7 +252,7 @@ ASDCP::MXF::EssenceContainerData::InitFromTLVSet(TLVReader& TLVSet)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::EssenceContainerData::WriteToTLVSet(TLVWriter& TLVSet)
+EssenceContainerData::WriteToTLVSet(TLVWriter& TLVSet)
 {
   Result_t result = InterchangeObject::WriteToTLVSet(TLVSet);
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(EssenceContainerData, LinkedPackageUID));
@@ -329,7 +263,7 @@ ASDCP::MXF::EssenceContainerData::WriteToTLVSet(TLVWriter& TLVSet)
 
 //
 void
-ASDCP::MXF::EssenceContainerData::Dump(FILE* stream)
+EssenceContainerData::Dump(FILE* stream)
 {
   char identbuf[IdentBufferLen];
   *identbuf = 0;
@@ -345,7 +279,7 @@ ASDCP::MXF::EssenceContainerData::Dump(FILE* stream)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::EssenceContainerData::InitFromBuffer(const byte_t* p, ui32_t l)
+EssenceContainerData::InitFromBuffer(const byte_t* p, ui32_t l)
 {
   m_Typeinfo = &Dict::Type(MDD_EssenceContainerData);
   return InterchangeObject::InitFromBuffer(p, l);
@@ -353,7 +287,7 @@ ASDCP::MXF::EssenceContainerData::InitFromBuffer(const byte_t* p, ui32_t l)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::EssenceContainerData::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+EssenceContainerData::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
 {
   m_Typeinfo = &Dict::Type(MDD_EssenceContainerData);
   return InterchangeObject::WriteToBuffer(Buffer);
@@ -364,7 +298,7 @@ ASDCP::MXF::EssenceContainerData::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::GenericPackage::InitFromTLVSet(TLVReader& TLVSet)
+GenericPackage::InitFromTLVSet(TLVReader& TLVSet)
 {
   Result_t result = InterchangeObject::InitFromTLVSet(TLVSet);
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(GenericPackage, PackageUID));
@@ -377,7 +311,7 @@ ASDCP::MXF::GenericPackage::InitFromTLVSet(TLVReader& TLVSet)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::GenericPackage::WriteToTLVSet(TLVWriter& TLVSet)
+GenericPackage::WriteToTLVSet(TLVWriter& TLVSet)
 {
   Result_t result = InterchangeObject::WriteToTLVSet(TLVSet);
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(GenericPackage, PackageUID));
@@ -390,7 +324,7 @@ ASDCP::MXF::GenericPackage::WriteToTLVSet(TLVWriter& TLVSet)
 
 //
 void
-ASDCP::MXF::GenericPackage::Dump(FILE* stream)
+GenericPackage::Dump(FILE* stream)
 {
   char identbuf[IdentBufferLen];
   *identbuf = 0;
@@ -413,7 +347,7 @@ ASDCP::MXF::GenericPackage::Dump(FILE* stream)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::MaterialPackage::InitFromTLVSet(TLVReader& TLVSet)
+MaterialPackage::InitFromTLVSet(TLVReader& TLVSet)
 {
   Result_t result = GenericPackage::InitFromTLVSet(TLVSet);
   return result;
@@ -421,7 +355,7 @@ ASDCP::MXF::MaterialPackage::InitFromTLVSet(TLVReader& TLVSet)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::MaterialPackage::WriteToTLVSet(TLVWriter& TLVSet)
+MaterialPackage::WriteToTLVSet(TLVWriter& TLVSet)
 {
   Result_t result = GenericPackage::WriteToTLVSet(TLVSet);
   return result;
@@ -429,7 +363,7 @@ ASDCP::MXF::MaterialPackage::WriteToTLVSet(TLVWriter& TLVSet)
 
 //
 void
-ASDCP::MXF::MaterialPackage::Dump(FILE* stream)
+MaterialPackage::Dump(FILE* stream)
 {
   char identbuf[IdentBufferLen];
   *identbuf = 0;
@@ -442,7 +376,7 @@ ASDCP::MXF::MaterialPackage::Dump(FILE* stream)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::MaterialPackage::InitFromBuffer(const byte_t* p, ui32_t l)
+MaterialPackage::InitFromBuffer(const byte_t* p, ui32_t l)
 {
   m_Typeinfo = &Dict::Type(MDD_MaterialPackage);
   return InterchangeObject::InitFromBuffer(p, l);
@@ -450,7 +384,7 @@ ASDCP::MXF::MaterialPackage::InitFromBuffer(const byte_t* p, ui32_t l)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::MaterialPackage::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+MaterialPackage::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
 {
   m_Typeinfo = &Dict::Type(MDD_MaterialPackage);
   return InterchangeObject::WriteToBuffer(Buffer);
@@ -461,7 +395,7 @@ ASDCP::MXF::MaterialPackage::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::SourcePackage::InitFromTLVSet(TLVReader& TLVSet)
+SourcePackage::InitFromTLVSet(TLVReader& TLVSet)
 {
   Result_t result = GenericPackage::InitFromTLVSet(TLVSet);
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(SourcePackage, Descriptor));
@@ -470,7 +404,7 @@ ASDCP::MXF::SourcePackage::InitFromTLVSet(TLVReader& TLVSet)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::SourcePackage::WriteToTLVSet(TLVWriter& TLVSet)
+SourcePackage::WriteToTLVSet(TLVWriter& TLVSet)
 {
   Result_t result = GenericPackage::WriteToTLVSet(TLVSet);
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(SourcePackage, Descriptor));
@@ -479,7 +413,7 @@ ASDCP::MXF::SourcePackage::WriteToTLVSet(TLVWriter& TLVSet)
 
 //
 void
-ASDCP::MXF::SourcePackage::Dump(FILE* stream)
+SourcePackage::Dump(FILE* stream)
 {
   char identbuf[IdentBufferLen];
   *identbuf = 0;
@@ -493,7 +427,7 @@ ASDCP::MXF::SourcePackage::Dump(FILE* stream)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::SourcePackage::InitFromBuffer(const byte_t* p, ui32_t l)
+SourcePackage::InitFromBuffer(const byte_t* p, ui32_t l)
 {
   m_Typeinfo = &Dict::Type(MDD_SourcePackage);
   return InterchangeObject::InitFromBuffer(p, l);
@@ -501,7 +435,7 @@ ASDCP::MXF::SourcePackage::InitFromBuffer(const byte_t* p, ui32_t l)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::SourcePackage::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+SourcePackage::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
 {
   m_Typeinfo = &Dict::Type(MDD_SourcePackage);
   return InterchangeObject::WriteToBuffer(Buffer);
@@ -512,7 +446,7 @@ ASDCP::MXF::SourcePackage::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::GenericTrack::InitFromTLVSet(TLVReader& TLVSet)
+GenericTrack::InitFromTLVSet(TLVReader& TLVSet)
 {
   Result_t result = InterchangeObject::InitFromTLVSet(TLVSet);
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(GenericTrack, TrackID));
@@ -524,7 +458,7 @@ ASDCP::MXF::GenericTrack::InitFromTLVSet(TLVReader& TLVSet)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::GenericTrack::WriteToTLVSet(TLVWriter& TLVSet)
+GenericTrack::WriteToTLVSet(TLVWriter& TLVSet)
 {
   Result_t result = InterchangeObject::WriteToTLVSet(TLVSet);
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(GenericTrack, TrackID));
@@ -536,7 +470,7 @@ ASDCP::MXF::GenericTrack::WriteToTLVSet(TLVWriter& TLVSet)
 
 //
 void
-ASDCP::MXF::GenericTrack::Dump(FILE* stream)
+GenericTrack::Dump(FILE* stream)
 {
   char identbuf[IdentBufferLen];
   *identbuf = 0;
@@ -557,7 +491,7 @@ ASDCP::MXF::GenericTrack::Dump(FILE* stream)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::StaticTrack::InitFromTLVSet(TLVReader& TLVSet)
+StaticTrack::InitFromTLVSet(TLVReader& TLVSet)
 {
   Result_t result = GenericTrack::InitFromTLVSet(TLVSet);
   return result;
@@ -565,7 +499,7 @@ ASDCP::MXF::StaticTrack::InitFromTLVSet(TLVReader& TLVSet)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::StaticTrack::WriteToTLVSet(TLVWriter& TLVSet)
+StaticTrack::WriteToTLVSet(TLVWriter& TLVSet)
 {
   Result_t result = GenericTrack::WriteToTLVSet(TLVSet);
   return result;
@@ -573,7 +507,7 @@ ASDCP::MXF::StaticTrack::WriteToTLVSet(TLVWriter& TLVSet)
 
 //
 void
-ASDCP::MXF::StaticTrack::Dump(FILE* stream)
+StaticTrack::Dump(FILE* stream)
 {
   char identbuf[IdentBufferLen];
   *identbuf = 0;
@@ -586,7 +520,7 @@ ASDCP::MXF::StaticTrack::Dump(FILE* stream)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::StaticTrack::InitFromBuffer(const byte_t* p, ui32_t l)
+StaticTrack::InitFromBuffer(const byte_t* p, ui32_t l)
 {
   m_Typeinfo = &Dict::Type(MDD_StaticTrack);
   return InterchangeObject::InitFromBuffer(p, l);
@@ -594,7 +528,7 @@ ASDCP::MXF::StaticTrack::InitFromBuffer(const byte_t* p, ui32_t l)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::StaticTrack::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+StaticTrack::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
 {
   m_Typeinfo = &Dict::Type(MDD_StaticTrack);
   return InterchangeObject::WriteToBuffer(Buffer);
@@ -605,7 +539,7 @@ ASDCP::MXF::StaticTrack::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::Track::InitFromTLVSet(TLVReader& TLVSet)
+Track::InitFromTLVSet(TLVReader& TLVSet)
 {
   Result_t result = GenericTrack::InitFromTLVSet(TLVSet);
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Track, EditRate));
@@ -615,7 +549,7 @@ ASDCP::MXF::Track::InitFromTLVSet(TLVReader& TLVSet)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::Track::WriteToTLVSet(TLVWriter& TLVSet)
+Track::WriteToTLVSet(TLVWriter& TLVSet)
 {
   Result_t result = GenericTrack::WriteToTLVSet(TLVSet);
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Track, EditRate));
@@ -625,7 +559,7 @@ ASDCP::MXF::Track::WriteToTLVSet(TLVWriter& TLVSet)
 
 //
 void
-ASDCP::MXF::Track::Dump(FILE* stream)
+Track::Dump(FILE* stream)
 {
   char identbuf[IdentBufferLen];
   *identbuf = 0;
@@ -640,7 +574,7 @@ ASDCP::MXF::Track::Dump(FILE* stream)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::Track::InitFromBuffer(const byte_t* p, ui32_t l)
+Track::InitFromBuffer(const byte_t* p, ui32_t l)
 {
   m_Typeinfo = &Dict::Type(MDD_Track);
   return InterchangeObject::InitFromBuffer(p, l);
@@ -648,7 +582,7 @@ ASDCP::MXF::Track::InitFromBuffer(const byte_t* p, ui32_t l)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::Track::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+Track::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
 {
   m_Typeinfo = &Dict::Type(MDD_Track);
   return InterchangeObject::WriteToBuffer(Buffer);
@@ -659,7 +593,7 @@ ASDCP::MXF::Track::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::StructuralComponent::InitFromTLVSet(TLVReader& TLVSet)
+StructuralComponent::InitFromTLVSet(TLVReader& TLVSet)
 {
   Result_t result = InterchangeObject::InitFromTLVSet(TLVSet);
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(StructuralComponent, DataDefinition));
@@ -669,7 +603,7 @@ ASDCP::MXF::StructuralComponent::InitFromTLVSet(TLVReader& TLVSet)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::StructuralComponent::WriteToTLVSet(TLVWriter& TLVSet)
+StructuralComponent::WriteToTLVSet(TLVWriter& TLVSet)
 {
   Result_t result = InterchangeObject::WriteToTLVSet(TLVSet);
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(StructuralComponent, DataDefinition));
@@ -679,7 +613,7 @@ ASDCP::MXF::StructuralComponent::WriteToTLVSet(TLVWriter& TLVSet)
 
 //
 void
-ASDCP::MXF::StructuralComponent::Dump(FILE* stream)
+StructuralComponent::Dump(FILE* stream)
 {
   char identbuf[IdentBufferLen];
   *identbuf = 0;
@@ -698,7 +632,7 @@ ASDCP::MXF::StructuralComponent::Dump(FILE* stream)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::Sequence::InitFromTLVSet(TLVReader& TLVSet)
+Sequence::InitFromTLVSet(TLVReader& TLVSet)
 {
   Result_t result = StructuralComponent::InitFromTLVSet(TLVSet);
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Sequence, StructuralComponents));
@@ -707,7 +641,7 @@ ASDCP::MXF::Sequence::InitFromTLVSet(TLVReader& TLVSet)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::Sequence::WriteToTLVSet(TLVWriter& TLVSet)
+Sequence::WriteToTLVSet(TLVWriter& TLVSet)
 {
   Result_t result = StructuralComponent::WriteToTLVSet(TLVSet);
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Sequence, StructuralComponents));
@@ -716,7 +650,7 @@ ASDCP::MXF::Sequence::WriteToTLVSet(TLVWriter& TLVSet)
 
 //
 void
-ASDCP::MXF::Sequence::Dump(FILE* stream)
+Sequence::Dump(FILE* stream)
 {
   char identbuf[IdentBufferLen];
   *identbuf = 0;
@@ -731,7 +665,7 @@ ASDCP::MXF::Sequence::Dump(FILE* stream)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::Sequence::InitFromBuffer(const byte_t* p, ui32_t l)
+Sequence::InitFromBuffer(const byte_t* p, ui32_t l)
 {
   m_Typeinfo = &Dict::Type(MDD_Sequence);
   return InterchangeObject::InitFromBuffer(p, l);
@@ -739,7 +673,7 @@ ASDCP::MXF::Sequence::InitFromBuffer(const byte_t* p, ui32_t l)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::Sequence::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+Sequence::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
 {
   m_Typeinfo = &Dict::Type(MDD_Sequence);
   return InterchangeObject::WriteToBuffer(Buffer);
@@ -750,7 +684,7 @@ ASDCP::MXF::Sequence::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::SourceClip::InitFromTLVSet(TLVReader& TLVSet)
+SourceClip::InitFromTLVSet(TLVReader& TLVSet)
 {
   Result_t result = StructuralComponent::InitFromTLVSet(TLVSet);
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi64(OBJ_READ_ARGS(SourceClip, StartPosition));
@@ -761,7 +695,7 @@ ASDCP::MXF::SourceClip::InitFromTLVSet(TLVReader& TLVSet)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::SourceClip::WriteToTLVSet(TLVWriter& TLVSet)
+SourceClip::WriteToTLVSet(TLVWriter& TLVSet)
 {
   Result_t result = StructuralComponent::WriteToTLVSet(TLVSet);
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi64(OBJ_WRITE_ARGS(SourceClip, StartPosition));
@@ -772,7 +706,7 @@ ASDCP::MXF::SourceClip::WriteToTLVSet(TLVWriter& TLVSet)
 
 //
 void
-ASDCP::MXF::SourceClip::Dump(FILE* stream)
+SourceClip::Dump(FILE* stream)
 {
   char identbuf[IdentBufferLen];
   *identbuf = 0;
@@ -788,7 +722,7 @@ ASDCP::MXF::SourceClip::Dump(FILE* stream)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::SourceClip::InitFromBuffer(const byte_t* p, ui32_t l)
+SourceClip::InitFromBuffer(const byte_t* p, ui32_t l)
 {
   m_Typeinfo = &Dict::Type(MDD_SourceClip);
   return InterchangeObject::InitFromBuffer(p, l);
@@ -796,7 +730,7 @@ ASDCP::MXF::SourceClip::InitFromBuffer(const byte_t* p, ui32_t l)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::SourceClip::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+SourceClip::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
 {
   m_Typeinfo = &Dict::Type(MDD_SourceClip);
   return InterchangeObject::WriteToBuffer(Buffer);
@@ -807,7 +741,7 @@ ASDCP::MXF::SourceClip::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::TimecodeComponent::InitFromTLVSet(TLVReader& TLVSet)
+TimecodeComponent::InitFromTLVSet(TLVReader& TLVSet)
 {
   Result_t result = StructuralComponent::InitFromTLVSet(TLVSet);
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi16(OBJ_READ_ARGS(TimecodeComponent, RoundedTimecodeBase));
@@ -818,7 +752,7 @@ ASDCP::MXF::TimecodeComponent::InitFromTLVSet(TLVReader& TLVSet)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::TimecodeComponent::WriteToTLVSet(TLVWriter& TLVSet)
+TimecodeComponent::WriteToTLVSet(TLVWriter& TLVSet)
 {
   Result_t result = StructuralComponent::WriteToTLVSet(TLVSet);
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi16(OBJ_WRITE_ARGS(TimecodeComponent, RoundedTimecodeBase));
@@ -829,7 +763,7 @@ ASDCP::MXF::TimecodeComponent::WriteToTLVSet(TLVWriter& TLVSet)
 
 //
 void
-ASDCP::MXF::TimecodeComponent::Dump(FILE* stream)
+TimecodeComponent::Dump(FILE* stream)
 {
   char identbuf[IdentBufferLen];
   *identbuf = 0;
@@ -845,7 +779,7 @@ ASDCP::MXF::TimecodeComponent::Dump(FILE* stream)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::TimecodeComponent::InitFromBuffer(const byte_t* p, ui32_t l)
+TimecodeComponent::InitFromBuffer(const byte_t* p, ui32_t l)
 {
   m_Typeinfo = &Dict::Type(MDD_TimecodeComponent);
   return InterchangeObject::InitFromBuffer(p, l);
@@ -853,7 +787,7 @@ ASDCP::MXF::TimecodeComponent::InitFromBuffer(const byte_t* p, ui32_t l)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::TimecodeComponent::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+TimecodeComponent::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
 {
   m_Typeinfo = &Dict::Type(MDD_TimecodeComponent);
   return InterchangeObject::WriteToBuffer(Buffer);
@@ -864,7 +798,7 @@ ASDCP::MXF::TimecodeComponent::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::GenericDescriptor::InitFromTLVSet(TLVReader& TLVSet)
+GenericDescriptor::InitFromTLVSet(TLVReader& TLVSet)
 {
   Result_t result = InterchangeObject::InitFromTLVSet(TLVSet);
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(GenericDescriptor, Locators));
@@ -874,7 +808,7 @@ ASDCP::MXF::GenericDescriptor::InitFromTLVSet(TLVReader& TLVSet)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::GenericDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
+GenericDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
 {
   Result_t result = InterchangeObject::WriteToTLVSet(TLVSet);
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(GenericDescriptor, Locators));
@@ -884,7 +818,7 @@ ASDCP::MXF::GenericDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
 
 //
 void
-ASDCP::MXF::GenericDescriptor::Dump(FILE* stream)
+GenericDescriptor::Dump(FILE* stream)
 {
   char identbuf[IdentBufferLen];
   *identbuf = 0;
@@ -905,7 +839,7 @@ ASDCP::MXF::GenericDescriptor::Dump(FILE* stream)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::FileDescriptor::InitFromTLVSet(TLVReader& TLVSet)
+FileDescriptor::InitFromTLVSet(TLVReader& TLVSet)
 {
   Result_t result = GenericDescriptor::InitFromTLVSet(TLVSet);
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(FileDescriptor, LinkedTrackID));
@@ -918,7 +852,7 @@ ASDCP::MXF::FileDescriptor::InitFromTLVSet(TLVReader& TLVSet)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::FileDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
+FileDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
 {
   Result_t result = GenericDescriptor::WriteToTLVSet(TLVSet);
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(FileDescriptor, LinkedTrackID));
@@ -931,7 +865,7 @@ ASDCP::MXF::FileDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
 
 //
 void
-ASDCP::MXF::FileDescriptor::Dump(FILE* stream)
+FileDescriptor::Dump(FILE* stream)
 {
   char identbuf[IdentBufferLen];
   *identbuf = 0;
@@ -949,7 +883,7 @@ ASDCP::MXF::FileDescriptor::Dump(FILE* stream)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::FileDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
+FileDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
 {
   m_Typeinfo = &Dict::Type(MDD_FileDescriptor);
   return InterchangeObject::InitFromBuffer(p, l);
@@ -957,7 +891,7 @@ ASDCP::MXF::FileDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::FileDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+FileDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
 {
   m_Typeinfo = &Dict::Type(MDD_FileDescriptor);
   return InterchangeObject::WriteToBuffer(Buffer);
@@ -968,7 +902,7 @@ ASDCP::MXF::FileDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::GenericSoundEssenceDescriptor::InitFromTLVSet(TLVReader& TLVSet)
+GenericSoundEssenceDescriptor::InitFromTLVSet(TLVReader& TLVSet)
 {
   Result_t result = FileDescriptor::InitFromTLVSet(TLVSet);
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(GenericSoundEssenceDescriptor, AudioSamplingRate));
@@ -982,7 +916,7 @@ ASDCP::MXF::GenericSoundEssenceDescriptor::InitFromTLVSet(TLVReader& TLVSet)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::GenericSoundEssenceDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
+GenericSoundEssenceDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
 {
   Result_t result = FileDescriptor::WriteToTLVSet(TLVSet);
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(GenericSoundEssenceDescriptor, AudioSamplingRate));
@@ -996,7 +930,7 @@ ASDCP::MXF::GenericSoundEssenceDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
 
 //
 void
-ASDCP::MXF::GenericSoundEssenceDescriptor::Dump(FILE* stream)
+GenericSoundEssenceDescriptor::Dump(FILE* stream)
 {
   char identbuf[IdentBufferLen];
   *identbuf = 0;
@@ -1015,7 +949,7 @@ ASDCP::MXF::GenericSoundEssenceDescriptor::Dump(FILE* stream)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::GenericSoundEssenceDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
+GenericSoundEssenceDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
 {
   m_Typeinfo = &Dict::Type(MDD_GenericSoundEssenceDescriptor);
   return InterchangeObject::InitFromBuffer(p, l);
@@ -1023,7 +957,7 @@ ASDCP::MXF::GenericSoundEssenceDescriptor::InitFromBuffer(const byte_t* p, ui32_
 
 //
 ASDCP::Result_t
-ASDCP::MXF::GenericSoundEssenceDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+GenericSoundEssenceDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
 {
   m_Typeinfo = &Dict::Type(MDD_GenericSoundEssenceDescriptor);
   return InterchangeObject::WriteToBuffer(Buffer);
@@ -1034,7 +968,7 @@ ASDCP::MXF::GenericSoundEssenceDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buf
 
 //
 ASDCP::Result_t
-ASDCP::MXF::WaveAudioDescriptor::InitFromTLVSet(TLVReader& TLVSet)
+WaveAudioDescriptor::InitFromTLVSet(TLVReader& TLVSet)
 {
   Result_t result = GenericSoundEssenceDescriptor::InitFromTLVSet(TLVSet);
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi16(OBJ_READ_ARGS(WaveAudioDescriptor, BlockAlign));
@@ -1045,7 +979,7 @@ ASDCP::MXF::WaveAudioDescriptor::InitFromTLVSet(TLVReader& TLVSet)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::WaveAudioDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
+WaveAudioDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
 {
   Result_t result = GenericSoundEssenceDescriptor::WriteToTLVSet(TLVSet);
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi16(OBJ_WRITE_ARGS(WaveAudioDescriptor, BlockAlign));
@@ -1056,7 +990,7 @@ ASDCP::MXF::WaveAudioDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
 
 //
 void
-ASDCP::MXF::WaveAudioDescriptor::Dump(FILE* stream)
+WaveAudioDescriptor::Dump(FILE* stream)
 {
   char identbuf[IdentBufferLen];
   *identbuf = 0;
@@ -1072,7 +1006,7 @@ ASDCP::MXF::WaveAudioDescriptor::Dump(FILE* stream)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::WaveAudioDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
+WaveAudioDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
 {
   m_Typeinfo = &Dict::Type(MDD_WaveAudioDescriptor);
   return InterchangeObject::InitFromBuffer(p, l);
@@ -1080,7 +1014,7 @@ ASDCP::MXF::WaveAudioDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::WaveAudioDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+WaveAudioDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
 {
   m_Typeinfo = &Dict::Type(MDD_WaveAudioDescriptor);
   return InterchangeObject::WriteToBuffer(Buffer);
@@ -1091,7 +1025,7 @@ ASDCP::MXF::WaveAudioDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::GenericPictureEssenceDescriptor::InitFromTLVSet(TLVReader& TLVSet)
+GenericPictureEssenceDescriptor::InitFromTLVSet(TLVReader& TLVSet)
 {
   Result_t result = FileDescriptor::InitFromTLVSet(TLVSet);
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi8(OBJ_READ_ARGS(GenericPictureEssenceDescriptor, FrameLayout));
@@ -1103,7 +1037,7 @@ ASDCP::MXF::GenericPictureEssenceDescriptor::InitFromTLVSet(TLVReader& TLVSet)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::GenericPictureEssenceDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
+GenericPictureEssenceDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
 {
   Result_t result = FileDescriptor::WriteToTLVSet(TLVSet);
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi8(OBJ_WRITE_ARGS(GenericPictureEssenceDescriptor, FrameLayout));
@@ -1115,7 +1049,7 @@ ASDCP::MXF::GenericPictureEssenceDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
 
 //
 void
-ASDCP::MXF::GenericPictureEssenceDescriptor::Dump(FILE* stream)
+GenericPictureEssenceDescriptor::Dump(FILE* stream)
 {
   char identbuf[IdentBufferLen];
   *identbuf = 0;
@@ -1132,7 +1066,7 @@ ASDCP::MXF::GenericPictureEssenceDescriptor::Dump(FILE* stream)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::GenericPictureEssenceDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
+GenericPictureEssenceDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
 {
   m_Typeinfo = &Dict::Type(MDD_GenericPictureEssenceDescriptor);
   return InterchangeObject::InitFromBuffer(p, l);
@@ -1140,7 +1074,7 @@ ASDCP::MXF::GenericPictureEssenceDescriptor::InitFromBuffer(const byte_t* p, ui3
 
 //
 ASDCP::Result_t
-ASDCP::MXF::GenericPictureEssenceDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+GenericPictureEssenceDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
 {
   m_Typeinfo = &Dict::Type(MDD_GenericPictureEssenceDescriptor);
   return InterchangeObject::WriteToBuffer(Buffer);
@@ -1151,7 +1085,7 @@ ASDCP::MXF::GenericPictureEssenceDescriptor::WriteToBuffer(ASDCP::FrameBuffer& B
 
 //
 ASDCP::Result_t
-ASDCP::MXF::RGBAEssenceDescriptor::InitFromTLVSet(TLVReader& TLVSet)
+RGBAEssenceDescriptor::InitFromTLVSet(TLVReader& TLVSet)
 {
   Result_t result = GenericPictureEssenceDescriptor::InitFromTLVSet(TLVSet);
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(RGBAEssenceDescriptor, ComponentMaxRef));
@@ -1161,7 +1095,7 @@ ASDCP::MXF::RGBAEssenceDescriptor::InitFromTLVSet(TLVReader& TLVSet)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::RGBAEssenceDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
+RGBAEssenceDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
 {
   Result_t result = GenericPictureEssenceDescriptor::WriteToTLVSet(TLVSet);
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(RGBAEssenceDescriptor, ComponentMaxRef));
@@ -1171,7 +1105,7 @@ ASDCP::MXF::RGBAEssenceDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
 
 //
 void
-ASDCP::MXF::RGBAEssenceDescriptor::Dump(FILE* stream)
+RGBAEssenceDescriptor::Dump(FILE* stream)
 {
   char identbuf[IdentBufferLen];
   *identbuf = 0;
@@ -1186,7 +1120,7 @@ ASDCP::MXF::RGBAEssenceDescriptor::Dump(FILE* stream)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::RGBAEssenceDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
+RGBAEssenceDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
 {
   m_Typeinfo = &Dict::Type(MDD_RGBAEssenceDescriptor);
   return InterchangeObject::InitFromBuffer(p, l);
@@ -1194,7 +1128,7 @@ ASDCP::MXF::RGBAEssenceDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::RGBAEssenceDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+RGBAEssenceDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
 {
   m_Typeinfo = &Dict::Type(MDD_RGBAEssenceDescriptor);
   return InterchangeObject::WriteToBuffer(Buffer);
@@ -1205,7 +1139,7 @@ ASDCP::MXF::RGBAEssenceDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::JPEG2000PictureSubDescriptor::InitFromTLVSet(TLVReader& TLVSet)
+JPEG2000PictureSubDescriptor::InitFromTLVSet(TLVReader& TLVSet)
 {
   Result_t result = InterchangeObject::InitFromTLVSet(TLVSet);
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi16(OBJ_READ_ARGS(JPEG2000PictureSubDescriptor, Rsize));
@@ -1226,7 +1160,7 @@ ASDCP::MXF::JPEG2000PictureSubDescriptor::InitFromTLVSet(TLVReader& TLVSet)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::JPEG2000PictureSubDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
+JPEG2000PictureSubDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
 {
   Result_t result = InterchangeObject::WriteToTLVSet(TLVSet);
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi16(OBJ_WRITE_ARGS(JPEG2000PictureSubDescriptor, Rsize));
@@ -1247,7 +1181,7 @@ ASDCP::MXF::JPEG2000PictureSubDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
 
 //
 void
-ASDCP::MXF::JPEG2000PictureSubDescriptor::Dump(FILE* stream)
+JPEG2000PictureSubDescriptor::Dump(FILE* stream)
 {
   char identbuf[IdentBufferLen];
   *identbuf = 0;
@@ -1273,7 +1207,7 @@ ASDCP::MXF::JPEG2000PictureSubDescriptor::Dump(FILE* stream)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::JPEG2000PictureSubDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
+JPEG2000PictureSubDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
 {
   m_Typeinfo = &Dict::Type(MDD_JPEG2000PictureSubDescriptor);
   return InterchangeObject::InitFromBuffer(p, l);
@@ -1281,7 +1215,7 @@ ASDCP::MXF::JPEG2000PictureSubDescriptor::InitFromBuffer(const byte_t* p, ui32_t
 
 //
 ASDCP::Result_t
-ASDCP::MXF::JPEG2000PictureSubDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+JPEG2000PictureSubDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
 {
   m_Typeinfo = &Dict::Type(MDD_JPEG2000PictureSubDescriptor);
   return InterchangeObject::WriteToBuffer(Buffer);
@@ -1292,7 +1226,7 @@ ASDCP::MXF::JPEG2000PictureSubDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buff
 
 //
 ASDCP::Result_t
-ASDCP::MXF::CDCIEssenceDescriptor::InitFromTLVSet(TLVReader& TLVSet)
+CDCIEssenceDescriptor::InitFromTLVSet(TLVReader& TLVSet)
 {
   Result_t result = GenericPictureEssenceDescriptor::InitFromTLVSet(TLVSet);
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(CDCIEssenceDescriptor, ComponentDepth));
@@ -1304,7 +1238,7 @@ ASDCP::MXF::CDCIEssenceDescriptor::InitFromTLVSet(TLVReader& TLVSet)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::CDCIEssenceDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
+CDCIEssenceDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
 {
   Result_t result = GenericPictureEssenceDescriptor::WriteToTLVSet(TLVSet);
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(CDCIEssenceDescriptor, ComponentDepth));
@@ -1316,7 +1250,7 @@ ASDCP::MXF::CDCIEssenceDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
 
 //
 void
-ASDCP::MXF::CDCIEssenceDescriptor::Dump(FILE* stream)
+CDCIEssenceDescriptor::Dump(FILE* stream)
 {
   char identbuf[IdentBufferLen];
   *identbuf = 0;
@@ -1333,7 +1267,7 @@ ASDCP::MXF::CDCIEssenceDescriptor::Dump(FILE* stream)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::CDCIEssenceDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
+CDCIEssenceDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
 {
   m_Typeinfo = &Dict::Type(MDD_CDCIEssenceDescriptor);
   return InterchangeObject::InitFromBuffer(p, l);
@@ -1341,7 +1275,7 @@ ASDCP::MXF::CDCIEssenceDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::CDCIEssenceDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+CDCIEssenceDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
 {
   m_Typeinfo = &Dict::Type(MDD_CDCIEssenceDescriptor);
   return InterchangeObject::WriteToBuffer(Buffer);
@@ -1352,7 +1286,7 @@ ASDCP::MXF::CDCIEssenceDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::MPEG2VideoDescriptor::InitFromTLVSet(TLVReader& TLVSet)
+MPEG2VideoDescriptor::InitFromTLVSet(TLVReader& TLVSet)
 {
   Result_t result = CDCIEssenceDescriptor::InitFromTLVSet(TLVSet);
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi8(OBJ_READ_ARGS(MPEG2VideoDescriptor, CodedContentType));
@@ -1364,7 +1298,7 @@ ASDCP::MXF::MPEG2VideoDescriptor::InitFromTLVSet(TLVReader& TLVSet)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::MPEG2VideoDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
+MPEG2VideoDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
 {
   Result_t result = CDCIEssenceDescriptor::WriteToTLVSet(TLVSet);
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi8(OBJ_WRITE_ARGS(MPEG2VideoDescriptor, CodedContentType));
@@ -1376,7 +1310,7 @@ ASDCP::MXF::MPEG2VideoDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
 
 //
 void
-ASDCP::MXF::MPEG2VideoDescriptor::Dump(FILE* stream)
+MPEG2VideoDescriptor::Dump(FILE* stream)
 {
   char identbuf[IdentBufferLen];
   *identbuf = 0;
@@ -1393,7 +1327,7 @@ ASDCP::MXF::MPEG2VideoDescriptor::Dump(FILE* stream)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::MPEG2VideoDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
+MPEG2VideoDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
 {
   m_Typeinfo = &Dict::Type(MDD_MPEG2VideoDescriptor);
   return InterchangeObject::InitFromBuffer(p, l);
@@ -1401,7 +1335,7 @@ ASDCP::MXF::MPEG2VideoDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::MPEG2VideoDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+MPEG2VideoDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
 {
   m_Typeinfo = &Dict::Type(MDD_MPEG2VideoDescriptor);
   return InterchangeObject::WriteToBuffer(Buffer);
@@ -1412,10 +1346,12 @@ ASDCP::MXF::MPEG2VideoDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::DMSegment::InitFromTLVSet(TLVReader& TLVSet)
+DMSegment::InitFromTLVSet(TLVReader& TLVSet)
 {
   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;
@@ -1423,10 +1359,12 @@ ASDCP::MXF::DMSegment::InitFromTLVSet(TLVReader& TLVSet)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::DMSegment::WriteToTLVSet(TLVWriter& TLVSet)
+DMSegment::WriteToTLVSet(TLVWriter& TLVSet)
 {
   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;
@@ -1434,7 +1372,7 @@ ASDCP::MXF::DMSegment::WriteToTLVSet(TLVWriter& TLVSet)
 
 //
 void
-ASDCP::MXF::DMSegment::Dump(FILE* stream)
+DMSegment::Dump(FILE* stream)
 {
   char identbuf[IdentBufferLen];
   *identbuf = 0;
@@ -1443,14 +1381,16 @@ ASDCP::MXF::DMSegment::Dump(FILE* stream)
     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
-ASDCP::MXF::DMSegment::InitFromBuffer(const byte_t* p, ui32_t l)
+DMSegment::InitFromBuffer(const byte_t* p, ui32_t l)
 {
   m_Typeinfo = &Dict::Type(MDD_DMSegment);
   return InterchangeObject::InitFromBuffer(p, l);
@@ -1458,7 +1398,7 @@ ASDCP::MXF::DMSegment::InitFromBuffer(const byte_t* p, ui32_t l)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::DMSegment::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+DMSegment::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
 {
   m_Typeinfo = &Dict::Type(MDD_DMSegment);
   return InterchangeObject::WriteToBuffer(Buffer);
@@ -1469,7 +1409,7 @@ ASDCP::MXF::DMSegment::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::CryptographicFramework::InitFromTLVSet(TLVReader& TLVSet)
+CryptographicFramework::InitFromTLVSet(TLVReader& TLVSet)
 {
   Result_t result = InterchangeObject::InitFromTLVSet(TLVSet);
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(CryptographicFramework, ContextSR));
@@ -1478,7 +1418,7 @@ ASDCP::MXF::CryptographicFramework::InitFromTLVSet(TLVReader& TLVSet)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::CryptographicFramework::WriteToTLVSet(TLVWriter& TLVSet)
+CryptographicFramework::WriteToTLVSet(TLVWriter& TLVSet)
 {
   Result_t result = InterchangeObject::WriteToTLVSet(TLVSet);
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(CryptographicFramework, ContextSR));
@@ -1487,7 +1427,7 @@ ASDCP::MXF::CryptographicFramework::WriteToTLVSet(TLVWriter& TLVSet)
 
 //
 void
-ASDCP::MXF::CryptographicFramework::Dump(FILE* stream)
+CryptographicFramework::Dump(FILE* stream)
 {
   char identbuf[IdentBufferLen];
   *identbuf = 0;
@@ -1501,7 +1441,7 @@ ASDCP::MXF::CryptographicFramework::Dump(FILE* stream)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::CryptographicFramework::InitFromBuffer(const byte_t* p, ui32_t l)
+CryptographicFramework::InitFromBuffer(const byte_t* p, ui32_t l)
 {
   m_Typeinfo = &Dict::Type(MDD_CryptographicFramework);
   return InterchangeObject::InitFromBuffer(p, l);
@@ -1509,7 +1449,7 @@ ASDCP::MXF::CryptographicFramework::InitFromBuffer(const byte_t* p, ui32_t l)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::CryptographicFramework::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+CryptographicFramework::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
 {
   m_Typeinfo = &Dict::Type(MDD_CryptographicFramework);
   return InterchangeObject::WriteToBuffer(Buffer);
@@ -1520,7 +1460,7 @@ ASDCP::MXF::CryptographicFramework::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::CryptographicContext::InitFromTLVSet(TLVReader& TLVSet)
+CryptographicContext::InitFromTLVSet(TLVReader& TLVSet)
 {
   Result_t result = InterchangeObject::InitFromTLVSet(TLVSet);
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(CryptographicContext, ContextID));
@@ -1533,7 +1473,7 @@ ASDCP::MXF::CryptographicContext::InitFromTLVSet(TLVReader& TLVSet)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::CryptographicContext::WriteToTLVSet(TLVWriter& TLVSet)
+CryptographicContext::WriteToTLVSet(TLVWriter& TLVSet)
 {
   Result_t result = InterchangeObject::WriteToTLVSet(TLVSet);
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(CryptographicContext, ContextID));
@@ -1546,7 +1486,7 @@ ASDCP::MXF::CryptographicContext::WriteToTLVSet(TLVWriter& TLVSet)
 
 //
 void
-ASDCP::MXF::CryptographicContext::Dump(FILE* stream)
+CryptographicContext::Dump(FILE* stream)
 {
   char identbuf[IdentBufferLen];
   *identbuf = 0;
@@ -1564,7 +1504,7 @@ ASDCP::MXF::CryptographicContext::Dump(FILE* stream)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::CryptographicContext::InitFromBuffer(const byte_t* p, ui32_t l)
+CryptographicContext::InitFromBuffer(const byte_t* p, ui32_t l)
 {
   m_Typeinfo = &Dict::Type(MDD_CryptographicContext);
   return InterchangeObject::InitFromBuffer(p, l);
@@ -1572,12 +1512,175 @@ ASDCP::MXF::CryptographicContext::InitFromBuffer(const byte_t* p, ui32_t l)
 
 //
 ASDCP::Result_t
-ASDCP::MXF::CryptographicContext::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+CryptographicContext::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
 {
   m_Typeinfo = &Dict::Type(MDD_CryptographicContext);
   return InterchangeObject::WriteToBuffer(Buffer);
 }
 
+//------------------------------------------------------------------------------------------
+// GenericDataEssenceDescriptor
+
+//
+ASDCP::Result_t
+GenericDataEssenceDescriptor::InitFromTLVSet(TLVReader& TLVSet)
+{
+  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)
+{
+  Result_t result = FileDescriptor::WriteToTLVSet(TLVSet);
+  if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(GenericDataEssenceDescriptor, DataEssenceCoding));
+  return result;
+}
+
+//
+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)
+{
+  m_Typeinfo = &Dict::Type(MDD_GenericDataEssenceDescriptor);
+  return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+GenericDataEssenceDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+  m_Typeinfo = &Dict::Type(MDD_GenericDataEssenceDescriptor);
+  return InterchangeObject::WriteToBuffer(Buffer);
+}
+
+//------------------------------------------------------------------------------------------
+// DCTimedTextDescriptor
+
+//
+ASDCP::Result_t
+DCTimedTextDescriptor::InitFromTLVSet(TLVReader& TLVSet)
+{
+  Result_t result = GenericDataEssenceDescriptor::InitFromTLVSet(TLVSet);
+  if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(DCTimedTextDescriptor, UTFEncoding));
+  if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(DCTimedTextDescriptor, RootNamespaceName));
+  return result;
+}
+
+//
+ASDCP::Result_t
+DCTimedTextDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
+{
+  Result_t result = GenericDataEssenceDescriptor::WriteToTLVSet(TLVSet);
+  if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(DCTimedTextDescriptor, UTFEncoding));
+  if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(DCTimedTextDescriptor, RootNamespaceName));
+  return result;
+}
+
+//
+void
+DCTimedTextDescriptor::Dump(FILE* stream)
+{
+  char identbuf[IdentBufferLen];
+  *identbuf = 0;
+
+  if ( stream == 0 )
+    stream = stderr;
+
+  GenericDataEssenceDescriptor::Dump(stream);
+  fprintf(stream, "  %22s = %s\n",  "UTFEncoding", UTFEncoding.EncodeString(identbuf, IdentBufferLen));
+  fprintf(stream, "  %22s = %s\n",  "RootNamespaceName", RootNamespaceName.EncodeString(identbuf, IdentBufferLen));
+}
+
+//
+ASDCP::Result_t
+DCTimedTextDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+  m_Typeinfo = &Dict::Type(MDD_DCTimedTextDescriptor);
+  return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+DCTimedTextDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+  m_Typeinfo = &Dict::Type(MDD_DCTimedTextDescriptor);
+  return InterchangeObject::WriteToBuffer(Buffer);
+}
+
+//------------------------------------------------------------------------------------------
+// DCTimedTextResourceDescriptor
+
+//
+ASDCP::Result_t
+DCTimedTextResourceDescriptor::InitFromTLVSet(TLVReader& TLVSet)
+{
+  Result_t result = InterchangeObject::InitFromTLVSet(TLVSet);
+  if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(DCTimedTextResourceDescriptor, ResourcePackageID));
+  if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(DCTimedTextResourceDescriptor, ResourceMIMEType));
+  if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(DCTimedTextResourceDescriptor, ResourceSID));
+  return result;
+}
+
+//
+ASDCP::Result_t
+DCTimedTextResourceDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
+{
+  Result_t result = InterchangeObject::WriteToTLVSet(TLVSet);
+  if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(DCTimedTextResourceDescriptor, ResourcePackageID));
+  if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(DCTimedTextResourceDescriptor, ResourceMIMEType));
+  if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(DCTimedTextResourceDescriptor, ResourceSID));
+  return result;
+}
+
+//
+void
+DCTimedTextResourceDescriptor::Dump(FILE* stream)
+{
+  char identbuf[IdentBufferLen];
+  *identbuf = 0;
+
+  if ( stream == 0 )
+    stream = stderr;
+
+  InterchangeObject::Dump(stream);
+  fprintf(stream, "  %22s = %s\n",  "ResourcePackageID", ResourcePackageID.EncodeString(identbuf, IdentBufferLen));
+  fprintf(stream, "  %22s = %s\n",  "ResourceMIMEType", ResourceMIMEType.EncodeString(identbuf, IdentBufferLen));
+  fprintf(stream, "  %22s = %d\n",  "ResourceSID", ResourceSID);
+}
+
+//
+ASDCP::Result_t
+DCTimedTextResourceDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+  m_Typeinfo = &Dict::Type(MDD_DCTimedTextResourceDescriptor);
+  return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+DCTimedTextResourceDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+  m_Typeinfo = &Dict::Type(MDD_DCTimedTextResourceDescriptor);
+  return InterchangeObject::WriteToBuffer(Buffer);
+}
+
+
 //
 // end Metadata.cpp
 //
index f15819402c89c20011fc2d3de71601b2286e65d4..fbbe2165c074c9f84546d3208e74d4c61e7c3bd0 100755 (executable)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2005-2006, John Hurst
+Copyright (c) 2005-2007, John Hurst
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -29,8 +29,8 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     \brief   MXF metadata objects
 */
 
-#ifndef _METADATA_H_
-#define _METADATA_H_
+#ifndef _Metadata_H_
+#define _Metadata_H_
 
 #include "MXF.h"
 
@@ -38,6 +38,8 @@ namespace ASDCP
 {
   namespace MXF
     {
+      void Metadata_InitTypes();
+
       //
 
       //
@@ -490,11 +492,13 @@ namespace ASDCP
          ASDCP_NO_COPY_CONSTRUCT(DMSegment);
 
        public:
+          UL DataDefinition;
           ui64_t EventStartPosition;
+          ui64_t Duration;
           UTF16String EventComment;
           UUID DMFramework;
 
-         DMSegment() : EventStartPosition(0) {}
+         DMSegment() : EventStartPosition(0), Duration(0) {}
          virtual ~DMSegment() {}
           virtual const char* HasName() { return "DMSegment"; }
           virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
@@ -544,11 +548,67 @@ namespace ASDCP
          virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
        };
 
+      //
+      class GenericDataEssenceDescriptor : public FileDescriptor
+       {
+         ASDCP_NO_COPY_CONSTRUCT(GenericDataEssenceDescriptor);
+
+       public:
+          UL DataEssenceCoding;
+
+         GenericDataEssenceDescriptor() {}
+         virtual ~GenericDataEssenceDescriptor() {}
+          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 DCTimedTextDescriptor : public GenericDataEssenceDescriptor
+       {
+         ASDCP_NO_COPY_CONSTRUCT(DCTimedTextDescriptor);
+
+       public:
+          UTF16String UTFEncoding;
+          UTF16String RootNamespaceName;
+
+         DCTimedTextDescriptor() {}
+         virtual ~DCTimedTextDescriptor() {}
+          virtual const char* HasName() { return "DCTimedTextDescriptor"; }
+          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 DCTimedTextResourceDescriptor : public InterchangeObject
+       {
+         ASDCP_NO_COPY_CONSTRUCT(DCTimedTextResourceDescriptor);
+
+       public:
+          UUID ResourcePackageID;
+          UTF16String ResourceMIMEType;
+          ui32_t ResourceSID;
+
+         DCTimedTextResourceDescriptor() : ResourceSID(0) {}
+         virtual ~DCTimedTextResourceDescriptor() {}
+          virtual const char* HasName() { return "DCTimedTextResourceDescriptor"; }
+          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_
+#endif // _Metadata_H_
 
 //
 // end Metadata.h
index 86236d5ce482846ae166c31cdb66852d8f630281..a2683f9ecbcf245bd363bb64cb847d33d9451db9 100644 (file)
@@ -32,43 +32,226 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "AS_DCP_internal.h"
 #include "AS_DCP_TimedText.h"
+#include "S12MTimecode.h"
 #include "KM_xml.h"
 
 using namespace Kumu;
 using namespace ASDCP;
 
+const char* c_dcst_namespace_name = "http://www.smpte-ra.org/schemas/428-7/2007/DCST";
+
+
 //------------------------------------------------------------------------------------------
 
-class ASDCP::TimedText::DCSubtitleParser::h__DCSubtitleParser
+typedef std::map<Kumu::UUID, TimedText::MIMEType_t> ResourceTypeMap_t;
+
+class ASDCP::TimedText::DCSubtitleParser::h__SubtitleParser
 {
-  ui32_t             m_FileReadCount;
+  XMLElement  m_Root;
+  ResourceTypeMap_t m_ResourceTypes;
 
-  ASDCP_NO_COPY_CONSTRUCT(h__DCSubtitleParser);
+  ASDCP_NO_COPY_CONSTRUCT(h__SubtitleParser);
 
 public:
+  std::string m_XMLDoc;
   TimedTextDescriptor  m_TDesc;
 
-  h__DCSubtitleParser() : m_FileReadCount(0)
+  h__SubtitleParser() : m_Root("**ParserRoot**")
   {
-    memset(&m_TDesc, 0, sizeof(m_TDesc));
+    memset(&m_TDesc.AssetID, 0, UUIDlen);
   }
 
-  ~h__DCSubtitleParser()
-  {
-    Close();
-  }
+  ~h__SubtitleParser() {}
 
   Result_t OpenRead(const char* filename);
-  void     Close() {}
+  Result_t ReadAncillaryResource(const byte_t* uuid, FrameBuffer& FrameBuf) const;
+};
 
-  Result_t Reset()
-  {
-    m_FileReadCount = 0;
-    return RESULT_OK;
-  }
+//
+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);
+}
 
-  Result_t ReadFrame(FrameBuffer&);
-};
+//
+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);
+}
+
+//
+ui32_t
+CalculateSubtitleDuration(const XMLElement* begin, const XMLElement* end)
+{
+  assert(begin); assert(end);
+
+  S12MTimecode
+    beginTC(begin->GetAttrWithName("TimeIn"), 24),
+    endTC(end->GetAttrWithName("TimeOut"), 24);
+
+  if ( endTC < beginTC )
+    return 0;
+
+  return endTC.GetFrames() - beginTC.GetFrames();
+}
+
+//
+Result_t
+ASDCP::TimedText::DCSubtitleParser::h__SubtitleParser::OpenRead(const char* filename)
+{
+  Result_t result = ReadFileIntoString(filename, m_XMLDoc);
+
+  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());
+
+  // 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));
+    }
+
+  // duration
+  ElementList InstanceList;
+  m_Root.GetChildrenWithName("Subtitle", InstanceList);
+  m_TDesc.ContainerDuration = CalculateSubtitleDuration(InstanceList.front(), InstanceList.back());
+
+  return RESULT_OK;
+}
+
+
+//
+Result_t
+ASDCP::TimedText::DCSubtitleParser::h__SubtitleParser::ReadAncillaryResource(const byte_t* uuid, FrameBuffer& FrameBuf) const
+{
+  FrameBuf.AssetID(uuid);
+  UUID TmpID(uuid);
+  char buf[64];
+  FileReader Reader;
+
+  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 = Reader.OpenRead(TmpID.EncodeHex(buf, 64));
+
+  if ( KM_SUCCESS(result) )
+    {
+      ui32_t read_count = 0;
+      result = Reader.Read(FrameBuf.Data(), FrameBuf.Capacity(), &read_count);
+
+      if ( KM_SUCCESS(result) )
+       {
+         FrameBuf.Size(read_count);
+
+         if ( (*rmi).second == MT_PNG )
+           FrameBuf.MIMEType("image/png");
+             
+         else if ( (*rmi).second == MT_OPENTYPE )
+           FrameBuf.MIMEType("application/x-opentype");
+
+         else
+           FrameBuf.MIMEType("application/octet-stream");
+       }
+    }
+  else
+    {
+      DefaultLogSink(). Error("Error opening resource file %s.\n", buf);
+    }
+
+  return result;
+}
 
 //------------------------------------------------------------------------------------------
 
@@ -85,47 +268,49 @@ ASDCP::TimedText::DCSubtitleParser::~DCSubtitleParser()
 ASDCP::Result_t
 ASDCP::TimedText::DCSubtitleParser::OpenRead(const char* filename) const
 {
-  const_cast<ASDCP::TimedText::DCSubtitleParser*>(this)->m_Parser = new h__DCSubtitleParser;
+  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.release();
+    const_cast<ASDCP::TimedText::DCSubtitleParser*>(this)->m_Parser = 0;
 
   return result;
 }
 
-// Rewinds the stream to the beginning.
+//
 ASDCP::Result_t
-ASDCP::TimedText::DCSubtitleParser::Reset() const
+ASDCP::TimedText::DCSubtitleParser::FillDescriptor(TimedTextDescriptor& TDesc) const
 {
   if ( m_Parser.empty() )
     return RESULT_INIT;
 
-  return m_Parser->Reset();
+  TDesc = m_Parser->m_TDesc;
+  return RESULT_OK;
 }
 
-// Places a frame of data in the frame buffer. Fails if the buffer is too small
-// or the stream is empty.
+// Reads the complete Timed Text Resource into the given string.
 ASDCP::Result_t
-ASDCP::TimedText::DCSubtitleParser::ReadFrame(FrameBuffer& FB) const
+ASDCP::TimedText::DCSubtitleParser::ReadTimedTextResource(std::string& s) const
 {
   if ( m_Parser.empty() )
     return RESULT_INIT;
 
-  return m_Parser->ReadFrame(FB);
+  s = m_Parser->m_XMLDoc;
+  return RESULT_OK;
 }
 
+//
 ASDCP::Result_t
-ASDCP::TimedText::DCSubtitleParser::FillDescriptor(TimedTextDescriptor& PDesc) const
+ASDCP::TimedText::DCSubtitleParser::ReadAncillaryResource(const byte_t* uuid, FrameBuffer& FrameBuf) const
 {
 if ( m_Parser.empty() )
+ if ( m_Parser.empty() )
     return RESULT_INIT;
 
-  PDesc = m_Parser->m_TDesc;
-  return RESULT_OK;
+ return m_Parser->ReadAncillaryResource(uuid, FrameBuf);
 }
 
+
 //
 // end AS_DCP_timedText.cpp
 //
index a2901da3f719751a408a1ed443c5dda993e0a945..4a1a58633b9f89d575bc410179279498806366b5 100755 (executable)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2003-2006, John Hurst
+Copyright (c) 2003-2007, John Hurst
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -56,6 +56,11 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <WavFileWriter.h>
 #include <MXF.h>
 #include <Metadata.h>
+
+#ifdef ASDCP_WITH_TIMED_TEXT
+#include <AS_DCP_TimedText.h>
+#endif
+
 #include <openssl/sha.h>
 
 using namespace ASDCP;
@@ -1099,6 +1104,201 @@ read_PCM_file(CommandOptions& Options)
 }
 
 
+#ifdef ASDCP_WITH_TIMED_TEXT
+
+//------------------------------------------------------------------------------------------
+// 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.FillDescriptor(TDesc);
+      FrameBuffer.Capacity(2*Kumu::Megabyte);
+
+      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
+      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.FillDescriptor(TDesc);
+      FrameBuffer.Capacity(2*Kumu::Megabyte);
+
+      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;
+  TimedText::ResourceList_t::const_iterator ri;
+
+  result = Reader.ReadTimedTextResource(XMLDoc, Context, HMAC);
+
+  // do something with the XML here
+  fprintf(stderr, "XMLDoc size: %lu\n", XMLDoc.size());
+
+  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) )
+       {
+         //      if ( Options.verbose_flag )
+           FrameBuffer.Dump(stderr, Options.fb_dump_size);
+
+         // do something with the resource data here
+       }
+    }
+
+  return result;
+}
+#endif // ASDCP_WITH_TIMED_TEXT
+
 //------------------------------------------------------------------------------------------
 //
 
@@ -1143,6 +1343,19 @@ class MyAudioDescriptor : public PCM::AudioDescriptor
   }
 };
 
+#ifdef ASDCP_WITH_TIMED_TEXT
+class MyTextDescriptor : public TimedText::TimedTextDescriptor
+{
+ public:
+  void FillDescriptor(TimedText::MXFReader& Reader) {
+    Reader.FillDescriptor(*this);
+  }
+
+  void Dump(FILE* stream) {
+    TimedText::DescriptorDump(*this, stream);
+  }
+};
+#endif
 
 // MSVC didn't like the function template, so now it's a static class method
 template<class ReaderT, class DescriptorT>
@@ -1209,6 +1422,13 @@ show_file_info(CommandOptions& Options)
       fputs("File essence type is JPEG 2000 pictures.\n", stdout);
       FileInfoWrapper<ASDCP::JP2K::MXFReader, MyPictureDescriptor>::file_info(Options);
     }
+#ifdef ASDCP_WITH_TIMED_TEXT
+  else if ( EssenceType == ESS_TIMED_TEXT )
+    {
+      fputs("File essence type is Timed Text.\n", stdout);
+      FileInfoWrapper<ASDCP::TimedText::MXFReader, MyTextDescriptor>::file_info(Options);
+    }
+#endif
   else
     {
       fprintf(stderr, "File is not AS-DCP: %s\n", Options.filenames[0]);
@@ -1358,6 +1578,14 @@ main(int argc, const char** argv)
              result = read_PCM_file(Options);
              break;
 
+           case ESS_TIMED_TEXT:
+#ifdef ASDCP_WITH_TIMED_TEXT
+             result = read_timed_text_file(Options);
+             break;
+#else
+             fprintf(stderr, "asdcplib compiled without timed text support.\n");
+             return 7;
+#endif
            default:
              fprintf(stderr, "%s: Unknown file type, not ASDCP essence.\n", Options.filenames[0]);
              return 5;
@@ -1391,6 +1619,15 @@ main(int argc, const char** argv)
              result = write_PCM_file(Options);
              break;
 
+           case ESS_TIMED_TEXT:
+#ifdef ASDCP_WITH_TIMED_TEXT
+             result = write_timed_text_file(Options);
+             break;
+#else
+             fprintf(stderr, "asdcplib compiled without timed text support.\n");
+             return 7;
+#endif
+
            default:
              fprintf(stderr, "%s: Unknown file type, not ASDCP-compatible essence.\n",
                      Options.filenames[0]);
index 2179ca68459675a5ef6bc1ce233c9e3e0fb49ce8..7bc89554190cb13f63fcf56b8f2a1cf34f8c8365 100755 (executable)
@@ -112,7 +112,7 @@ ASDCP::h__Reader::OpenMXFRead(const char* filename)
     {
       // if this is a three partition file, go to the body
       // partition and read the partition pack
-      if ( m_HeaderPart.m_RIP.PairArray.size() == 3 )
+      if ( m_HeaderPart.m_RIP.PairArray.size() > 2 )
        {
          Array<RIP::Pair>::iterator r_i = m_HeaderPart.m_RIP.PairArray.begin();
          r_i++;
@@ -182,8 +182,8 @@ public:
 
 // standard method of reading a plaintext or encrypted frame
 Result_t
-ASDCP::h__Reader::ReadEKLVPacket(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf,
-                                const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC)
+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;
@@ -195,9 +195,8 @@ ASDCP::h__Reader::ReadEKLVPacket(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf,
     }
 
   // get frame position and go read the frame's key and length
-  Result_t result = RESULT_OK;
-  KLReader Reader;
   Kumu::fpos_t FilePosition = m_EssenceStart + TmpEntry.StreamOffset;
+  Result_t result = RESULT_OK;
 
   if ( FilePosition != m_LastPosition )
     {
@@ -205,8 +204,19 @@ ASDCP::h__Reader::ReadEKLVPacket(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf,
       result = m_File.Seek(FilePosition);
     }
 
-  if ( ASDCP_SUCCESS(result) )
-    result = Reader.ReadKLFromFile(m_File);
+  if( ASDCP_SUCCESS(result) )
+    result = ReadEKLVPacket(FrameNum, FrameBuf, EssenceUL, Ctx, HMAC);
+
+  return result;
+}
+
+
+Result_t
+ASDCP::h__Reader::ReadEKLVPacket(ui32_t FrameNum, 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;
index 1105e039de873964c7c937bb25b5efe035829f4d..1bada6b070a20d2640872ab47c2d978ee243b89c 100755 (executable)
@@ -45,8 +45,8 @@ using namespace ASDCP::MXF;
 //
 ASDCP::h__Writer::h__Writer() :
   m_HeaderSize(0), m_EssenceStart(0),
-  m_MaterialPackage(0), m_MPTCSequence(0), m_MPTimecode(0), m_MPClSequence(0), m_MPClip(0),
-  m_FilePackage(0), m_FPTCSequence(0), m_FPTimecode(0), m_FPClSequence(0), m_FPClip(0),
+  //  m_MaterialPackage(0), m_MPTCSequence(0), m_MPTimecode(0), m_MPClSequence(0), m_MPClip(0),
+  //  m_FilePackage(0), m_FPTCSequence(0), m_FPTimecode(0), m_FPClSequence(0), m_FPClip(0),
   m_EssenceDescriptor(0), m_FramesWritten(0), m_StreamOffset(0)
 {
 }
@@ -93,13 +93,10 @@ AddDMScrypt(Partition& HeaderPart, SourcePackage& Package, WriterInfo& Descr, co
 }
 
 //
-Result_t
-ASDCP::h__Writer::WriteMXFHeader(const std::string& PackageLabel, const UL& WrappingUL,
-                                const std::string& TrackName, const UL& DataDefinition,
-                                const MXF::Rational& EditRate,
-                                ui32_t TCFrameRate, ui32_t BytesPerEditUnit)
+void
+ASDCP::h__Writer::InitHeader()
 {
-  ASDCP_TEST_NULL(m_EssenceDescriptor);
+  assert(m_EssenceDescriptor);
 
   m_HeaderPart.m_Primer.ClearTagList();
   m_HeaderPart.m_Preface = new Preface;
@@ -134,7 +131,69 @@ ASDCP::h__Writer::WriteMXFHeader(const std::string& PackageLabel, const UL& Wrap
   Ident->ToolkitVersion.Patch = VERSION_IMPMINOR;
   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)
+{
+  TrackSet<ClipT> NewTrack;
+
+  NewTrack.Track = new Track;
+  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;
+  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)
+{
+  UL TCUL(Dict::ul(MDD_TimecodeDataDef));
+
+  TrackSet<TimecodeComponent> NewTrack = CreateTrackAndSequence<PackageT, TimecodeComponent>(Header, Package, "Timecode Track", EditRate, TCUL, 1);
+
+  NewTrack.Clip = new TimecodeComponent;
+  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& DataDefinition,
+                               const std::string& PackageLabel)
+{
   //
   ContentStorage* Storage = new ContentStorage;
   m_HeaderPart.AddChildObject(Storage);
@@ -146,119 +205,158 @@ ASDCP::h__Writer::WriteMXFHeader(const std::string& PackageLabel, const UL& Wrap
   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
   //
-  UMID PackageUMID;
-  PackageUMID.MakeUMID(0x0f); // unidentified essence
   m_MaterialPackage = new MaterialPackage;
   m_MaterialPackage->Name = "AS-DCP Material Package";
-  m_MaterialPackage->PackageUID = PackageUMID;
+  m_MaterialPackage->PackageUID = MaterialPackageUMID;
   m_HeaderPart.AddChildObject(m_MaterialPackage);
   Storage->Packages.push_back(m_MaterialPackage->InstanceUID);
 
-  // Timecode Track
-  Track* NewTrack = new Track;
-  m_HeaderPart.AddChildObject(NewTrack);
-  NewTrack->EditRate = EditRate;
-  m_MaterialPackage->Tracks.push_back(NewTrack->InstanceUID);
-  NewTrack->TrackID = 1;
-  NewTrack->TrackName = "Timecode Track";
-
-  m_MPTCSequence = new Sequence;
-  m_HeaderPart.AddChildObject(m_MPTCSequence);
-  NewTrack->Sequence = m_MPTCSequence->InstanceUID;
-  m_MPTCSequence->DataDefinition = UL(Dict::ul(MDD_TimecodeDataDef));
-
-  m_MPTimecode = new TimecodeComponent;
-  m_HeaderPart.AddChildObject(m_MPTimecode);
-  m_MPTCSequence->StructuralComponents.push_back(m_MPTimecode->InstanceUID);
-  m_MPTimecode->RoundedTimecodeBase = TCFrameRate;
-  m_MPTimecode->StartTimecode = ui64_C(0);
-  m_MPTimecode->DataDefinition = UL(Dict::ul(MDD_TimecodeDataDef));
+  TrackSet<TimecodeComponent> MPTCTrack = CreateTimecodeTrack<MaterialPackage>(m_HeaderPart, *m_MaterialPackage,
+                                                                              EditRate, TCFrameRate, 0);
+  m_DurationUpdateList.push_back(&(MPTCTrack.Sequence->Duration));
+  m_DurationUpdateList.push_back(&(MPTCTrack.Clip->Duration));
 
-  // Essence Track
-  NewTrack = new Track;
-  m_HeaderPart.AddChildObject(NewTrack);
-  NewTrack->EditRate = EditRate;
-  m_MaterialPackage->Tracks.push_back(NewTrack->InstanceUID);
-  NewTrack->TrackID = 2;
-  NewTrack->TrackName = TrackName.c_str();
-
-  m_MPClSequence = new Sequence;
-  m_HeaderPart.AddChildObject(m_MPClSequence);
-  NewTrack->Sequence = m_MPClSequence->InstanceUID;
-  m_MPClSequence->DataDefinition = DataDefinition;
-
-  m_MPClip = new SourceClip;
-  m_HeaderPart.AddChildObject(m_MPClip);
-  m_MPClSequence->StructuralComponents.push_back(m_MPClip->InstanceUID);
-  m_MPClip->DataDefinition = DataDefinition;
+  TrackSet<SourceClip> MPTrack = CreateTrackAndSequence<MaterialPackage, SourceClip>(m_HeaderPart, *m_MaterialPackage,
+                                                                          TrackName, EditRate, DataDefinition, 2);
+  m_DurationUpdateList.push_back(&(MPTrack.Sequence->Duration));
+
+  MPTrack.Clip = new SourceClip;
+  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_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_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_DurationUpdateList.push_back(&(FPTrack.Sequence->Duration));
+
+  FPTrack.Clip = new SourceClip;
+  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_HeaderPart.AddChildObject(Storage);
+  m_HeaderPart.m_Preface->ContentStorage = Storage->InstanceUID;
+
+  EssenceContainerData* ECD = new EssenceContainerData;
+  m_HeaderPart.AddChildObject(ECD);
+  Storage->EssenceContainerData.push_back(ECD->InstanceUID);
+  ECD->IndexSID = 129;
+  ECD->BodySID = 1;
+
   UUID assetUUID(m_Info.AssetUUID);
-  PackageUMID.MakeUMID(0x0f, assetUUID);
+  UMID SourcePackageUMID, MaterialPackageUMID;
+  SourcePackageUMID.MakeUMID(0x0f, assetUUID);
+  MaterialPackageUMID.MakeUMID(0x0f); // unidentified essence
+
+  //
+  // Material Package
+  //
+  m_MaterialPackage = new MaterialPackage;
+  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_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_DurationUpdateList.push_back(&(MPTrack.Sequence->Duration));
+
+  MPTrack.Clip = new DMSegment;
+  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_FilePackage->Name = PackageLabel.c_str();
-  m_FilePackage->PackageUID = PackageUMID;
-  ECD->LinkedPackageUID = PackageUMID;
-
-  m_MPClip->SourcePackageID = PackageUMID;
-  m_MPClip->SourceTrackID = 2;
+  m_FilePackage->PackageUID = SourcePackageUMID;
+  ECD->LinkedPackageUID = SourcePackageUMID;
 
   m_HeaderPart.AddChildObject(m_FilePackage);
   Storage->Packages.push_back(m_FilePackage->InstanceUID);
 
-  // Timecode Track
-  NewTrack = new Track;
-  m_HeaderPart.AddChildObject(NewTrack);
-  NewTrack->EditRate = EditRate;
-  m_FilePackage->Tracks.push_back(NewTrack->InstanceUID);
-  NewTrack->TrackID = 1;
-  NewTrack->TrackName = "Timecode Track";
-
-  m_FPTCSequence = new Sequence;
-  m_HeaderPart.AddChildObject(m_FPTCSequence);
-  NewTrack->Sequence = m_FPTCSequence->InstanceUID;
-  m_FPTCSequence->DataDefinition = UL(Dict::ul(MDD_TimecodeDataDef));
-
-  m_FPTimecode = new TimecodeComponent;
-  m_HeaderPart.AddChildObject(m_FPTimecode);
-  m_FPTCSequence->StructuralComponents.push_back(m_FPTimecode->InstanceUID);
-  m_FPTimecode->RoundedTimecodeBase = TCFrameRate;
-  m_FPTimecode->StartTimecode = ui64_C(86400); // 01:00:00:00
-  m_FPTimecode->DataDefinition = UL(Dict::ul(MDD_TimecodeDataDef));
+  TrackSet<TimecodeComponent> FPTCTrack = CreateTimecodeTrack<SourcePackage>(m_HeaderPart, *m_FilePackage,
+                                                                            EditRate, TCFrameRate, ui64_C(3600) * TCFrameRate);
+  m_DurationUpdateList.push_back(&(FPTCTrack.Sequence->Duration));
+  m_DurationUpdateList.push_back(&(FPTCTrack.Clip->Duration));
 
-  // Essence Track
-  NewTrack = new Track;
-  m_HeaderPart.AddChildObject(NewTrack);
-  NewTrack->EditRate = EditRate;
-  m_FilePackage->Tracks.push_back(NewTrack->InstanceUID);
-  NewTrack->TrackID = 2;
-  NewTrack->TrackName = TrackName.c_str();
-
-  m_FPClSequence = new Sequence;
-  m_HeaderPart.AddChildObject(m_FPClSequence);
-  NewTrack->Sequence = m_FPClSequence->InstanceUID;
-  m_FPClSequence->DataDefinition = DataDefinition;
-
-  m_FPClip = new SourceClip;
-  m_HeaderPart.AddChildObject(m_FPClip);
-  m_FPClSequence->StructuralComponents.push_back(m_FPClip->InstanceUID);
-  m_FPClip->DataDefinition = DataDefinition;
+  TrackSet<DMSegment> FPTrack = CreateTrackAndSequence<SourcePackage, DMSegment>(m_HeaderPart, *m_FilePackage,
+                                                                                TrackName, EditRate, DataDefinition, 2);
+  m_DurationUpdateList.push_back(&(FPTrack.Sequence->Duration));
 
-  // for now we do not allow setting this value, so all files will be 'original'
-  m_FPClip->SourceTrackID = 0;
-  m_FPClip->SourcePackageID = NilUMID;
+  FPTrack.Clip = new DMSegment;
+  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_EssenceDescriptor->LinkedTrackID = NewTrack->TrackID;
   m_HeaderPart.m_Preface->PrimaryPackage = m_FilePackage->InstanceUID;
 
   //
@@ -282,15 +380,19 @@ ASDCP::h__Writer::WriteMXFHeader(const std::string& PackageLabel, const UL& Wrap
 
   std::list<FileDescriptor*>::iterator sdli = m_EssenceSubDescriptorList.begin();
   for ( ; sdli != m_EssenceSubDescriptorList.end(); sdli++ )
-    m_HeaderPart.AddChildObject(*sdli);
+      m_HeaderPart.AddChildObject(*sdli);
 
   m_FilePackage->Descriptor = m_EssenceDescriptor->InstanceUID;
+}
 
-  // Write the header partition
-  Result_t result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize);
+//
+Result_t
+ASDCP::h__Writer::CreateBodyPart(const MXF::Rational& EditRate, ui32_t BytesPerEditUnit)
+{
+  Result_t result = RESULT_OK;
 
-  // create a body partition of we're writing proper 429-3/OP-Atom
-  if ( ASDCP_SUCCESS(result) && m_Info.LabelSetType == LS_MXF_SMPTE )
+  // 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;
@@ -323,6 +425,23 @@ ASDCP::h__Writer::WriteMXFHeader(const std::string& PackageLabel, const UL& Wrap
   return result;
 }
 
+//
+Result_t
+ASDCP::h__Writer::WriteMXFHeader(const std::string& PackageLabel, const UL& WrappingUL,
+                                const std::string& TrackName, const UL& DataDefinition,
+                                const MXF::Rational& EditRate, ui32_t TCFrameRate, ui32_t BytesPerEditUnit)
+{
+  InitHeader();
+  AddSourceClip(EditRate, TCFrameRate, TrackName, 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
@@ -446,9 +565,16 @@ 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 = 
-    m_EssenceDescriptor->ContainerDuration = m_FramesWritten;
+  //  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
@@ -463,11 +589,6 @@ ASDCP::h__Writer::WriteMXFFooter()
   m_HeaderPart.OperationalPattern = OPAtomUL;
   m_HeaderPart.m_Preface->OperationalPattern = m_HeaderPart.OperationalPattern;
 
-  if ( m_Info.LabelSetType == LS_MXF_SMPTE )
-    m_FooterPart.PreviousPartition = m_BodyPart.ThisPartition;
-  else
-    m_FooterPart.PreviousPartition = m_HeaderPart.ThisPartition;
-
   m_FooterPart.OperationalPattern = m_HeaderPart.OperationalPattern;
   m_FooterPart.EssenceContainers = m_HeaderPart.EssenceContainers;
   m_FooterPart.FooterPartition = here;
index 467eff938fc9e37633b481b37e33f29277169db7..bf9d9fb430721be2993ef1ad8d6d57465b216d09 100755 (executable)
@@ -192,7 +192,7 @@ main(int argc, const char** argv)
       if (Options.verbose_flag)
        fprintf(stderr, "Opening file %s\n", ((*fi).c_str()));
       
-      if ( Options.read_mxf_flag )
+      if ( Options.read_mxf_flag ) // dump MXF
        {
          Kumu::FileReader        Reader;
          ASDCP::MXF::OPAtomHeader Header;
@@ -204,6 +204,25 @@ main(int argc, const char** argv)
          
          Header.Dump(stdout);
          
+         if ( ASDCP_SUCCESS(result) && Header.m_RIP.PairArray.size() > 3 )
+           {
+             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;
+                     result = TmpPart.InitFromFile(Reader);
+
+                     if ( ASDCP_SUCCESS(result) && TmpPart.BodySID > 0 )
+                       TmpPart.Dump(stdout);
+                   }
+               }
+           }
+
          if ( ASDCP_SUCCESS(result) )
            {
              ASDCP::MXF::OPAtomIndexFooter Index;
diff --git a/src/path-test.cpp b/src/path-test.cpp
new file mode 100644 (file)
index 0000000..bc0af33
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+Copyright (c) 2004-2007, 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$
+  \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);
+  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");
+
+  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;
+
+  cerr << "OK" << endl;
+
+  return 0;
+}
+
+//
+// end path-test.cpp
+//