working multi-dict
[asdcplib.git] / src / h__Reader.cpp
index 95c510c6e93b8f1ea586b06380cde67c78811b26..7a1dd12ea43e1dde757d8a99124785866bb73b19 100755 (executable)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2004-2005, John Hurst
+Copyright (c) 2004-2009, John Hurst
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -36,7 +36,8 @@ using namespace ASDCP;
 using namespace ASDCP::MXF;
 
 //
-ASDCP::h__Reader::h__Reader() : m_EssenceStart(0)
+ASDCP::h__Reader::h__Reader(const Dictionary& d) :
+  m_HeaderPart(m_Dict), m_BodyPart(m_Dict), m_FooterPart(m_Dict), m_Dict(&d), m_EssenceStart(0)
 {
 }
 
@@ -56,10 +57,19 @@ ASDCP::h__Reader::Close()
 
 //
 Result_t
-ASDCP::h__Reader::InitInfo(WriterInfo& Info)
+ASDCP::h__Reader::InitInfo()
 {
   InterchangeObject* Object;
 
+  m_Info.LabelSetType = LS_MXF_UNKNOWN;
+  UL OPAtomUL(m_Dict->ul(MDD_OPAtom));
+  UL Interop_OPAtomUL(m_Dict->ul(MDD_MXFInterop_OPAtom));
+
+  if ( m_HeaderPart.OperationalPattern == Interop_OPAtomUL )
+    m_Info.LabelSetType = LS_MXF_INTEROP;
+  else if ( m_HeaderPart.OperationalPattern == OPAtomUL )
+    m_Info.LabelSetType = LS_MXF_SMPTE;
+
   // Identification
   Result_t result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(Identification), &Object);
 
@@ -73,7 +83,7 @@ ASDCP::h__Reader::InitInfo(WriterInfo& Info)
   if( ASDCP_SUCCESS(result) )
     {
       SourcePackage* SP = (SourcePackage*)Object;
-      memcpy(Info.AssetUUID, SP->PackageUID.Value() + 16, UUIDlen);
+      memcpy(m_Info.AssetUUID, SP->PackageUID.Value() + 16, UUIDlen);
     }
 
   // optional CryptographicContext
@@ -82,7 +92,7 @@ ASDCP::h__Reader::InitInfo(WriterInfo& Info)
       Result_t cr_result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(CryptographicContext), &Object);
 
       if( ASDCP_SUCCESS(cr_result) )
-       MD_to_CryptoInfo((CryptographicContext*)Object, m_Info);
+       MD_to_CryptoInfo((CryptographicContext*)Object, m_Info, *m_Dict);
     }
 
   return result;
@@ -99,33 +109,23 @@ ASDCP::h__Reader::OpenMXFRead(const char* filename)
   if ( ASDCP_SUCCESS(result) )
     result = m_HeaderPart.InitFromFile(m_File);
 
-  // OP-Atom states that there will be either two or three partitions,
-  // one closed header and one closed footer with an optional body
-  ui32_t test_s = m_HeaderPart.m_RIP.PairArray.size();
-
-  if ( test_s < 2 || test_s > 3 )
+  if ( ASDCP_SUCCESS(result) )
     {
-      DefaultLogSink().Error("RIP count is not 2 or 3: %lu\n", test_s);
-      return RESULT_FORMAT;
-    }
+      // if this is a three partition file, go to the body
+      // partition and read the partition pack
+      if ( m_HeaderPart.m_RIP.PairArray.size() > 2 )
+       {
+         Array<RIP::Pair>::iterator r_i = m_HeaderPart.m_RIP.PairArray.begin();
+         r_i++;
+         m_File.Seek((*r_i).ByteOffset);
 
-  // it really OP-Atom?
-  //  MDObject* OpPattern = GetMDObjectByType("OperationalPattern");
-  // TODO: check the label
+         result = m_BodyPart.InitFromFile(m_File);
+       }
 
-  // if this is a three partition file, go to the body
-  // partition and read off the partition pack
-  if ( test_s == 3 )
-    {
-      DefaultLogSink().Error("RIP count is 3: must write code...\n");
-      return RESULT_FORMAT;
+      m_EssenceStart = m_File.Tell();
     }
-  // TODO: check the partition pack to make sure it is
-  //       really a body with a single essence container
 
-  m_EssenceStart = m_File.Tell();
-
-  return RESULT_OK;
+  return result;
 }
 
 
@@ -150,25 +150,43 @@ ASDCP::h__Reader::InitMXFIndex()
   return result;
 }
 
+//
+Result_t
+ASDCP::KLReader::ReadKLFromFile(Kumu::FileReader& Reader)
+{
+  ui32_t read_count;
+  ui32_t header_length = SMPTE_UL_LENGTH + MXF_BER_LENGTH;
+  Result_t result = Reader.Read(m_KeyBuf, header_length, &read_count);
+
+  if ( ASDCP_SUCCESS(result) )
+    {
+      if ( read_count != header_length )
+       result = RESULT_READFAIL;
+  
+      else
+       result = InitFromBuffer(m_KeyBuf, header_length);
+    }
+
+  return result;
+}
 
 // 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;
 
   if ( ASDCP_FAILURE(m_FooterPart.Lookup(FrameNum, TmpEntry)) )
     {
-      DefaultLogSink().Error("Frame value out of range: %lu\n", FrameNum);
+      DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
       return RESULT_RANGE;
     }
 
   // get frame position and go read the frame's key and length
+  Kumu::fpos_t FilePosition = m_EssenceStart + TmpEntry.StreamOffset;
   Result_t result = RESULT_OK;
-  ASDCP::KLVReader Reader;
-  ASDCP::fpos_t FilePosition = m_EssenceStart + TmpEntry.StreamOffset;
 
   if ( FilePosition != m_LastPosition )
     {
@@ -176,19 +194,29 @@ 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, FrameNum + 1, FrameBuf, EssenceUL, Ctx, HMAC);
+
+  return result;
+}
+
+
+Result_t
+ASDCP::h__Reader::ReadEKLVPacket(ui32_t FrameNum, ui32_t SequenceNum, ASDCP::FrameBuffer& FrameBuf,
+                                const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC)
+{
+  KLReader Reader;
+  Result_t result = Reader.ReadKLFromFile(m_File);
 
   if ( ASDCP_FAILURE(result) )
     return result;
 
   UL Key(Reader.Key());
-  UL InteropRef(CryptEssenceUL_Data);
-  UL SMPTERef(CryptEssenceUL_Data);
   ui64_t PacketLength = Reader.Length();
   m_LastPosition = m_LastPosition + Reader.KLLength() + PacketLength;
 
-  if ( Key == InteropRef || Key == SMPTERef )
+  if ( memcmp(Key.Value(), m_Dict->ul(MDD_CryptEssence), Key.Size() - 1) == 0  // ignore the stream numbers
+       || memcmp(Key.Value(), m_Dict->ul(MDD_MXFInterop_CryptEssence), Key.Size() - 1) == 0 )
     {
       if ( ! m_Info.EncryptedEssence )
        {
@@ -197,9 +225,11 @@ ASDCP::h__Reader::ReadEKLVPacket(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf,
        }
 
       // read encrypted triplet value into internal buffer
-      m_CtFrameBuf.Capacity(PacketLength);
+      assert(PacketLength <= 0xFFFFFFFFL);
+      m_CtFrameBuf.Capacity((ui32_t) PacketLength);
       ui32_t read_count;
-      result = m_File.Read(m_CtFrameBuf.Data(), PacketLength, &read_count);
+      result = m_File.Read(m_CtFrameBuf.Data(), (ui32_t) PacketLength,
+                          &read_count);
 
       if ( ASDCP_FAILURE(result) )
        return result;
@@ -210,13 +240,13 @@ ASDCP::h__Reader::ReadEKLVPacket(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf,
           return RESULT_FORMAT;
         }
 
-      m_CtFrameBuf.Size(PacketLength);
+      m_CtFrameBuf.Size((ui32_t) PacketLength);
 
       // should be const but mxflib::ReadBER is not
       byte_t* ess_p = m_CtFrameBuf.Data();
 
       // read context ID length
-      if ( ! read_test_BER(&ess_p, UUIDlen) )
+      if ( ! Kumu::read_test_BER(&ess_p, UUIDlen) )
        return RESULT_FORMAT;
 
       // test the context ID
@@ -228,39 +258,49 @@ ASDCP::h__Reader::ReadEKLVPacket(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf,
       ess_p += UUIDlen;
 
       // read PlaintextOffset length
-      if ( ! read_test_BER(&ess_p, sizeof(ui64_t)) )
+      if ( ! Kumu::read_test_BER(&ess_p, sizeof(ui64_t)) )
        return RESULT_FORMAT;
 
-      ui32_t PlaintextOffset = (ui32_t)ASDCP_i64_BE(cp2i<ui64_t>(ess_p));
+      ui32_t PlaintextOffset = (ui32_t)KM_i64_BE(Kumu::cp2i<ui64_t>(ess_p));
       ess_p += sizeof(ui64_t);
 
       // read essence UL length
-      if ( ! read_test_BER(&ess_p, klv_key_size) )
+      if ( ! Kumu::read_test_BER(&ess_p, SMPTE_UL_LENGTH) )
        return RESULT_FORMAT;
 
-      // TODO: test essence UL
-      ess_p += klv_key_size;
+      // test essence UL
+      if ( memcmp(ess_p, EssenceUL, SMPTE_UL_LENGTH - 1) != 0 ) // ignore the stream number
+       {
+         char strbuf[IntBufferLen];
+         const MDDEntry* Entry = m_Dict->FindUL(Key.Value());
+         if ( Entry == 0 )
+           DefaultLogSink().Warn("Unexpected Essence UL found: %s.\n", Key.EncodeString(strbuf, IntBufferLen));
+         else
+           DefaultLogSink().Warn("Unexpected Essence UL found: %s.\n", Entry->name);
+         return RESULT_FORMAT;
+       }
+      ess_p += SMPTE_UL_LENGTH;
 
       // read SourceLength length
-      if ( ! read_test_BER(&ess_p, sizeof(ui64_t)) )
+      if ( ! Kumu::read_test_BER(&ess_p, sizeof(ui64_t)) )
        return RESULT_FORMAT;
 
-      ui32_t SourceLength = (ui32_t)ASDCP_i64_BE(cp2i<ui64_t>(ess_p));
+      ui32_t SourceLength = (ui32_t)KM_i64_BE(Kumu::cp2i<ui64_t>(ess_p));
       ess_p += sizeof(ui64_t);
       assert(SourceLength);
          
       if ( FrameBuf.Capacity() < SourceLength )
        {
-         DefaultLogSink().Error("FrameBuf.Capacity: %lu SourceLength: %lu\n", FrameBuf.Capacity(), SourceLength);
+         DefaultLogSink().Error("FrameBuf.Capacity: %u SourceLength: %u\n", FrameBuf.Capacity(), SourceLength);
          return RESULT_SMALLBUF;
        }
 
       ui32_t esv_length = calc_esv_length(SourceLength, PlaintextOffset);
 
       // read ESV length
-      if ( ! read_test_BER(&ess_p, esv_length) )
+      if ( ! Kumu::read_test_BER(&ess_p, esv_length) )
        {
-         DefaultLogSink().Error("read_test_BER did not return %lu\n", esv_length);
+         DefaultLogSink().Error("read_test_BER did not return %u\n", esv_length);
          return RESULT_FORMAT;
        }
 
@@ -289,13 +329,18 @@ ASDCP::h__Reader::ReadEKLVPacket(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf,
          if ( ASDCP_SUCCESS(result) && m_Info.UsesHMAC && HMAC )
            {
              IntegrityPack IntPack;
-             result = IntPack.TestValues(TmpWrapper, m_Info.AssetUUID, FrameNum + 1, HMAC);
+             result = IntPack.TestValues(TmpWrapper, m_Info.AssetUUID, SequenceNum, HMAC);
            }
        }
       else // return ciphertext to caller
        {
          if ( FrameBuf.Capacity() < tmp_len )
-           return RESULT_SMALLBUF;
+           {
+             char intbuf[IntBufferLen];
+             DefaultLogSink().Error("FrameBuf.Capacity: %u FrameLength: %s\n",
+                                    FrameBuf.Capacity(), ui64sz(PacketLength, intbuf));
+             return RESULT_SMALLBUF;
+           }
 
          memcpy(FrameBuf.Data(), ess_p, tmp_len);
          FrameBuf.Size(tmp_len);
@@ -303,19 +348,20 @@ ASDCP::h__Reader::ReadEKLVPacket(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf,
          FrameBuf.PlaintextOffset(PlaintextOffset);
        }
     }
-  else if ( Key == EssenceUL )
+  else if ( memcmp(Key.Value(), EssenceUL, Key.Size() - 1) == 0 ) // ignore the stream number
     { // read plaintext frame
        if ( FrameBuf.Capacity() < PacketLength )
        {
          char intbuf[IntBufferLen];
-         DefaultLogSink().Error("FrameBuf.Capacity: %lu FrameLength: %s\n",
+         DefaultLogSink().Error("FrameBuf.Capacity: %u FrameLength: %s\n",
                                 FrameBuf.Capacity(), ui64sz(PacketLength, intbuf));
          return RESULT_SMALLBUF;
        }
 
       // read the data into the supplied buffer
       ui32_t read_count;
-      result = m_File.Read(FrameBuf.Data(), PacketLength, &read_count);
+      assert(PacketLength <= 0xFFFFFFFFL);
+      result = m_File.Read(FrameBuf.Data(), (ui32_t) PacketLength, &read_count);
          
       if ( ASDCP_FAILURE(result) )
        return result;
@@ -336,7 +382,12 @@ ASDCP::h__Reader::ReadEKLVPacket(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf,
     }
   else
     {
-      DefaultLogSink().Error("Unexpected UL found.\n");
+      char strbuf[IntBufferLen];
+      const MDDEntry* Entry = m_Dict->FindUL(Key.Value());
+      if ( Entry == 0 )
+        DefaultLogSink().Warn("Unexpected Essence UL found: %s.\n", Key.EncodeString(strbuf, IntBufferLen));
+      else
+        DefaultLogSink().Warn("Unexpected Essence UL found: %s.\n", Entry->name);
       return RESULT_FORMAT;
     }