45570bb07bdb0efbc01e30b03a188acc15dd724e
[asdcplib.git] / src / MXF.cpp
1 /*
2 Copyright (c) 2005-2006, John Hurst
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8 1. Redistributions of source code must retain the above copyright
9    notice, this list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright
11    notice, this list of conditions and the following disclaimer in the
12    documentation and/or other materials provided with the distribution.
13 3. The name of the author may not be used to endorse or promote products
14    derived from this software without specific prior written permission.
15
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 /*! \file    MXF.cpp
28     \version $Id$
29     \brief   MXF objects
30 */
31
32 #define ASDCP_DECLARE_MDD
33 #include "MDD.h"
34
35 #include "MXF.h"
36 #include "Metadata.h"
37 #include <hex_utils.h>
38
39 //------------------------------------------------------------------------------------------
40 //
41
42 const ui32_t kl_length = ASDCP::SMPTE_UL_LENGTH + ASDCP::MXF_BER_LENGTH;
43
44 const byte_t mdd_key[] = { 0x06, 0x0e, 0x2b, 0x34 };
45
46 //
47 const ASDCP::MDDEntry*
48 ASDCP::GetMDDEntry(const byte_t* ul_buf)
49 {
50   ui32_t t_idx = 0;
51   ui32_t k_idx = 8;
52
53   // must be a pointer to a SMPTE UL
54   if ( ul_buf == 0 || memcmp(mdd_key, ul_buf, 4) != 0 )
55     return 0;
56
57   // advance to first matching element
58   // TODO: optimize using binary search
59   while ( s_MDD_Table[t_idx].ul != 0
60           && s_MDD_Table[t_idx].ul[k_idx] != ul_buf[k_idx] )
61     t_idx++;
62
63   if ( s_MDD_Table[t_idx].ul == 0 )
64     return 0;
65
66   // match successive elements
67   while ( s_MDD_Table[t_idx].ul != 0
68           && k_idx < SMPTE_UL_LENGTH - 1
69           && s_MDD_Table[t_idx].ul[k_idx] == ul_buf[k_idx] )
70     {
71       if ( s_MDD_Table[t_idx].ul[k_idx+1] == ul_buf[k_idx+1] )
72         {
73           k_idx++;
74         }
75       else
76         {
77           while ( s_MDD_Table[t_idx].ul != 0
78                   && s_MDD_Table[t_idx].ul[k_idx] == ul_buf[k_idx]
79                   && s_MDD_Table[t_idx].ul[k_idx+1] != ul_buf[k_idx+1] )
80             t_idx++;
81               
82           while ( s_MDD_Table[t_idx].ul[k_idx] != ul_buf[k_idx] )
83             k_idx--;
84         }
85     }
86
87   return (s_MDD_Table[t_idx].ul == 0 ? 0 : &s_MDD_Table[t_idx]);
88 }
89
90 //------------------------------------------------------------------------------------------
91 //
92
93 //
94 ASDCP::Result_t
95 ASDCP::MXF::SeekToRIP(const ASDCP::FileReader& Reader)
96 {
97   ASDCP::fpos_t end_pos;
98
99   // go to the end - 4 bytes
100   Result_t result = Reader.Seek(0, ASDCP::SP_END);
101
102   if ( ASDCP_SUCCESS(result) )
103     result = Reader.Tell(&end_pos);
104
105   if ( ASDCP_SUCCESS(result)
106        && end_pos < (SMPTE_UL_LENGTH+MXF_BER_LENGTH) )
107     result = RESULT_FAIL;  // File is smaller than an empty packet!
108
109   if ( ASDCP_SUCCESS(result) )
110     result = Reader.Seek(end_pos - 4);
111
112   // get the ui32_t RIP length
113   ui32_t read_count;
114   byte_t intbuf[MXF_BER_LENGTH];
115   ui32_t rip_size = 0;
116
117   if ( ASDCP_SUCCESS(result) )
118     {
119       result = Reader.Read(intbuf, MXF_BER_LENGTH, &read_count);
120
121       if ( ASDCP_SUCCESS(result) && read_count != 4 )
122         result = RESULT_FAIL;
123     }
124
125   if ( ASDCP_SUCCESS(result) )
126     {
127       rip_size = ASDCP_i32_BE(cp2i<ui32_t>(intbuf));
128
129       if ( rip_size > end_pos ) // RIP can't be bigger than the file
130         return RESULT_FAIL;
131     }
132
133   // reposition to start of RIP
134   if ( ASDCP_SUCCESS(result) )
135     result = Reader.Seek(end_pos - rip_size);
136
137   return result;
138 }
139
140 //
141 ASDCP::Result_t
142 ASDCP::MXF::RIP::InitFromFile(const ASDCP::FileReader& Reader)
143 {
144   Result_t result = KLVFilePacket::InitFromFile(Reader, s_MDD_Table[MDDindex_RandomIndexMetadata].ul);
145
146   if ( ASDCP_SUCCESS(result) )
147     {
148       MemIOReader MemRDR(m_ValueStart, m_ValueLength - 4);
149       result =  PairArray.ReadFrom(MemRDR);
150     }
151
152   if ( ASDCP_FAILURE(result) )
153     DefaultLogSink().Error("Failed to initialize RIP\n");
154
155   return result;
156 }
157
158 //
159 ASDCP::Result_t
160 ASDCP::MXF::RIP::WriteToFile(ASDCP::FileWriter& Writer)
161 {
162   Result_t result = WriteKLToFile(Writer, s_MDD_Table[MDDindex_RandomIndexMetadata].ul, 0);
163   return result;
164 }
165
166 //
167 void
168 ASDCP::MXF::RIP::Dump(FILE* stream)
169 {
170   if ( stream == 0 )
171     stream = stderr;
172
173   KLVFilePacket::Dump(stream, false);
174   PairArray.Dump(stream, false);
175
176   fputs("==========================================================================\n", stream);
177 }
178
179 //------------------------------------------------------------------------------------------
180 //
181
182 //
183 ASDCP::Result_t
184 ASDCP::MXF::Partition::InitFromFile(const ASDCP::FileReader& Reader)
185 {
186   Result_t result = KLVFilePacket::InitFromFile(Reader);
187   // test the UL
188   // could be one of several values
189
190   if ( ASDCP_SUCCESS(result) )
191     {
192       MemIOReader MemRDR(m_ValueStart, m_ValueLength);
193       result = MemRDR.ReadUi16BE(&MajorVersion);
194       if ( ASDCP_SUCCESS(result) )  result = MemRDR.ReadUi16BE(&MinorVersion);
195       if ( ASDCP_SUCCESS(result) )  result = MemRDR.ReadUi32BE(&KAGSize);
196       if ( ASDCP_SUCCESS(result) )  result = MemRDR.ReadUi64BE(&ThisPartition);
197       if ( ASDCP_SUCCESS(result) )  result = MemRDR.ReadUi64BE(&PreviousPartition);
198       if ( ASDCP_SUCCESS(result) )  result = MemRDR.ReadUi64BE(&FooterPartition);
199       if ( ASDCP_SUCCESS(result) )  result = MemRDR.ReadUi64BE(&HeaderByteCount);
200       if ( ASDCP_SUCCESS(result) )  result = MemRDR.ReadUi64BE(&IndexByteCount);
201       if ( ASDCP_SUCCESS(result) )  result = MemRDR.ReadUi32BE(&IndexSID);
202       if ( ASDCP_SUCCESS(result) )  result = MemRDR.ReadUi64BE(&BodyOffset);
203       if ( ASDCP_SUCCESS(result) )  result = MemRDR.ReadUi32BE(&BodySID);
204       if ( ASDCP_SUCCESS(result) )  result = OperationalPattern.ReadFrom(MemRDR);
205       if ( ASDCP_SUCCESS(result) )  result = EssenceContainers.ReadFrom(MemRDR);
206     }
207
208   if ( ASDCP_FAILURE(result) )
209     DefaultLogSink().Error("Failed to initialize Partition\n");
210
211   return result;
212 }
213
214 //
215 ASDCP::Result_t
216 ASDCP::MXF::Partition::WriteToFile(ASDCP::FileWriter& Writer)
217 {
218   Result_t result = m_Buffer.Capacity(1024);
219
220   if ( ASDCP_SUCCESS(result) )
221     {
222       MemIOWriter MemWRT(m_Buffer.Data(), m_Buffer.Capacity());
223       result = MemWRT.WriteUi16BE(MajorVersion);
224       if ( ASDCP_SUCCESS(result) )  result = MemWRT.WriteUi16BE(MinorVersion);
225       if ( ASDCP_SUCCESS(result) )  result = MemWRT.WriteUi32BE(KAGSize);
226       if ( ASDCP_SUCCESS(result) )  result = MemWRT.WriteUi64BE(ThisPartition);
227       if ( ASDCP_SUCCESS(result) )  result = MemWRT.WriteUi64BE(PreviousPartition);
228       if ( ASDCP_SUCCESS(result) )  result = MemWRT.WriteUi64BE(FooterPartition);
229       if ( ASDCP_SUCCESS(result) )  result = MemWRT.WriteUi64BE(HeaderByteCount);
230       if ( ASDCP_SUCCESS(result) )  result = MemWRT.WriteUi64BE(IndexByteCount);
231       if ( ASDCP_SUCCESS(result) )  result = MemWRT.WriteUi32BE(IndexSID);
232       if ( ASDCP_SUCCESS(result) )  result = MemWRT.WriteUi64BE(BodyOffset);
233       if ( ASDCP_SUCCESS(result) )  result = MemWRT.WriteUi32BE(BodySID);
234       if ( ASDCP_SUCCESS(result) )  result = OperationalPattern.WriteTo(MemWRT);
235       if ( ASDCP_SUCCESS(result) )  result = EssenceContainers.WriteTo(MemWRT);
236       if ( ASDCP_SUCCESS(result) )  m_Buffer.Size(MemWRT.Size());
237     }
238
239   if ( ASDCP_SUCCESS(result) )
240     {
241       ui32_t write_count; // this is subclassed, so the UL is only right some of the time
242       result = WriteKLToFile(Writer, s_MDD_Table[MDDindex_ClosedCompleteHeader].ul, m_Buffer.Size());
243
244       if ( ASDCP_SUCCESS(result) )
245         result = Writer.Write(m_Buffer.RoData(), m_Buffer.Size(), &write_count);
246     }
247
248   return result;
249 }
250
251 //
252 void
253 ASDCP::MXF::Partition::Dump(FILE* stream)
254 {
255   char identbuf[IdentBufferLen];
256   char intbuf[IntBufferLen];
257
258   if ( stream == 0 )
259     stream = stderr;
260
261   KLVFilePacket::Dump(stream, false);
262   fprintf(stream, "  MajorVersion       = %hu\n", MajorVersion);
263   fprintf(stream, "  MinorVersion       = %hu\n", MinorVersion);
264   fprintf(stream, "  KAGSize            = %lu\n", KAGSize);
265   fprintf(stream, "  ThisPartition      = %s\n",  ui64sz(ThisPartition, intbuf));
266   fprintf(stream, "  PreviousPartition  = %s\n",  ui64sz(PreviousPartition, intbuf));
267   fprintf(stream, "  FooterPartition    = %s\n",  ui64sz(FooterPartition, intbuf));
268   fprintf(stream, "  HeaderByteCount    = %s\n",  ui64sz(HeaderByteCount, intbuf));
269   fprintf(stream, "  IndexByteCount     = %s\n",  ui64sz(IndexByteCount, intbuf));
270   fprintf(stream, "  IndexSID           = %lu\n", IndexSID);
271   fprintf(stream, "  BodyOffset         = %s\n",  ui64sz(BodyOffset, intbuf));
272   fprintf(stream, "  BodySID            = %lu\n", BodySID);
273   fprintf(stream, "  OperationalPattern = %s\n",  OperationalPattern.ToString(identbuf));
274   fputs("Essence Containers:\n", stream); EssenceContainers.Dump(stream, false);
275
276   fputs("==========================================================================\n", stream);
277 }
278
279
280 //------------------------------------------------------------------------------------------
281 //
282
283 class ASDCP::MXF::Primer::h__PrimerLookup : public std::map<UL, TagValue>
284 {
285 public:
286   void InitWithBatch(ASDCP::MXF::Batch<ASDCP::MXF::Primer::LocalTagEntry>& Batch)
287   {
288     ASDCP::MXF::Batch<ASDCP::MXF::Primer::LocalTagEntry>::iterator i = Batch.begin();
289
290     for ( ; i != Batch.end(); i++ )
291       insert(std::map<UL, TagValue>::value_type((*i).UL, (*i).Tag));
292   }
293 };
294
295
296 //
297 ASDCP::MXF::Primer::Primer() {}
298
299 //
300 ASDCP::MXF::Primer::~Primer() {}
301
302 //
303 void
304 ASDCP::MXF::Primer::ClearTagList()
305 {
306   LocalTagEntryBatch.clear();
307   m_Lookup = new h__PrimerLookup;
308 }
309
310 //
311 ASDCP::Result_t
312 ASDCP::MXF::Primer::InitFromBuffer(const byte_t* p, ui32_t l)
313 {
314   Result_t result = KLVPacket::InitFromBuffer(p, l, s_MDD_Table[MDDindex_Primer].ul);
315
316   if ( ASDCP_SUCCESS(result) )
317     {
318       MemIOReader MemRDR(m_ValueStart, m_ValueLength);
319       result = LocalTagEntryBatch.ReadFrom(MemRDR);
320     }
321
322   if ( ASDCP_SUCCESS(result) )
323     {
324       m_Lookup = new h__PrimerLookup;
325       m_Lookup->InitWithBatch(LocalTagEntryBatch);
326     }
327
328   if ( ASDCP_FAILURE(result) )
329     DefaultLogSink().Error("Failed to initialize Primer\n");
330
331   return result;
332 }
333
334 //
335 ASDCP::Result_t
336 ASDCP::MXF::Primer::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
337 {
338   MemIOWriter MemWRT(Buffer.Data(), Buffer.Capacity());
339   Result_t result = LocalTagEntryBatch.WriteTo(MemWRT);
340   Buffer.Size(MemWRT.Size());
341 #if 0
342   if ( ASDCP_SUCCESS(result) )
343     {
344       ui32_t write_count;
345       result = WriteKLToFile(Writer, s_MDD_Table[MDDindex_Primer].ul, Buffer.Size());
346
347       if ( ASDCP_SUCCESS(result) )
348         result = Writer.Write(Buffer.RoData(), Buffer.Size(), &write_count);
349     }
350 #endif
351
352   return result;
353 }
354
355 //
356 ASDCP::Result_t
357 ASDCP::MXF::Primer::InsertTag(const ASDCP::UL& Key, ASDCP::TagValue& Tag)
358 {
359   assert(m_Lookup);
360
361   std::map<UL, TagValue>::iterator i = m_Lookup->find(Key);
362
363   if ( i == m_Lookup->end() )
364     {
365       const MDDEntry* mdde = GetMDDEntry(Key.Data());
366       assert(mdde);
367
368       LocalTagEntry TmpEntry;
369       TmpEntry.UL = Key;
370       TmpEntry.Tag = mdde->tag;
371
372       LocalTagEntryBatch.push_back(TmpEntry);
373       m_Lookup->insert(std::map<UL, TagValue>::value_type(TmpEntry.UL, TmpEntry.Tag));
374     }
375    
376   return RESULT_OK;
377 }
378
379 //
380 ASDCP::Result_t
381 ASDCP::MXF::Primer::TagForKey(const ASDCP::UL& Key, ASDCP::TagValue& Tag)
382 {
383   assert(m_Lookup);
384   if ( m_Lookup.empty() )
385     {
386       DefaultLogSink().Error("Primer lookup is empty\n");
387       return RESULT_FAIL;
388     }
389
390   std::map<UL, TagValue>::iterator i = m_Lookup->find(Key);
391
392   if ( i == m_Lookup->end() )
393     return RESULT_FALSE;
394
395   Tag = (*i).second;
396   return RESULT_OK;
397 }
398
399 //
400 void
401 ASDCP::MXF::Primer::Dump(FILE* stream)
402 {
403   char identbuf[IdentBufferLen];
404
405   if ( stream == 0 )
406     stream = stderr;
407
408   KLVPacket::Dump(stream, false);
409   fprintf(stream, "Primer: %lu %s\n",
410           LocalTagEntryBatch.ItemCount,
411           ( LocalTagEntryBatch.ItemCount == 1 ? "entry" : "entries" ));
412   
413   Batch<LocalTagEntry>::iterator i = LocalTagEntryBatch.begin();
414   for ( ; i != LocalTagEntryBatch.end(); i++ )
415     {
416       const MDDEntry* Entry = GetMDDEntry((*i).UL.Data());
417       fprintf(stream, "  %s %s\n", (*i).ToString(identbuf), (Entry ? Entry->name : "Unknown"));
418     }
419
420   fputs("==========================================================================\n", stream);
421 }
422
423
424 //------------------------------------------------------------------------------------------
425 //
426
427 //
428 ASDCP::Result_t
429 ASDCP::MXF::Preface::InitFromBuffer(const byte_t* p, ui32_t l)
430 {
431   ASDCP_TEST_NULL(p);
432
433   Result_t result = KLVPacket::InitFromBuffer(p, l, s_MDD_Table[MDDindex_Preface].ul);
434
435   if ( ASDCP_SUCCESS(result) )
436     {
437       TLVReader MemRDR(m_ValueStart, m_ValueLength, m_Lookup);
438
439       result = MemRDR.ReadObject(OBJ_READ_ARGS(InterchangeObject, InstanceUID));
440       if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(GenerationInterchangeObject, GenerationUID));
441       if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(Preface, LastModifiedDate));
442       if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi16(OBJ_READ_ARGS(Preface, Version));
443       if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi32(OBJ_READ_ARGS(Preface, ObjectModelVersion));
444       if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(Preface, PrimaryPackage));
445       if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(Preface, Identifications));
446       if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(Preface, ContentStorage));
447       if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(Preface, OperationalPattern));
448       if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(Preface, EssenceContainers));
449       if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(Preface, DMSchemes));
450     }
451
452   if ( ASDCP_FAILURE(result) )
453     DefaultLogSink().Error("Failed to initialize Preface\n");
454
455   return result;
456 }
457
458 //
459 ASDCP::Result_t
460 ASDCP::MXF::Preface::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
461 {
462   TLVWriter MemWRT(Buffer.Data() + kl_length, Buffer.Capacity() - kl_length, m_Lookup);
463   Result_t result = MemWRT.WriteObject(OBJ_WRITE_ARGS(InterchangeObject, InstanceUID));
464   if ( ASDCP_SUCCESS(result) )  result = MemWRT.WriteObject(OBJ_WRITE_ARGS(GenerationInterchangeObject, GenerationUID));
465   if ( ASDCP_SUCCESS(result) )  result = MemWRT.WriteObject(OBJ_WRITE_ARGS(Preface, LastModifiedDate));
466   if ( ASDCP_SUCCESS(result) )  result = MemWRT.WriteUi16(OBJ_WRITE_ARGS(Preface, Version));
467   if ( ASDCP_SUCCESS(result) )  result = MemWRT.WriteUi32(OBJ_WRITE_ARGS(Preface, ObjectModelVersion));
468   if ( ASDCP_SUCCESS(result) )  result = MemWRT.WriteObject(OBJ_WRITE_ARGS(Preface, PrimaryPackage));
469   if ( ASDCP_SUCCESS(result) )  result = MemWRT.WriteObject(OBJ_WRITE_ARGS(Preface, Identifications));
470   if ( ASDCP_SUCCESS(result) )  result = MemWRT.WriteObject(OBJ_WRITE_ARGS(Preface, ContentStorage));
471   if ( ASDCP_SUCCESS(result) )  result = MemWRT.WriteObject(OBJ_WRITE_ARGS(Preface, OperationalPattern));
472   if ( ASDCP_SUCCESS(result) )  result = MemWRT.WriteObject(OBJ_WRITE_ARGS(Preface, EssenceContainers));
473   if ( ASDCP_SUCCESS(result) )  result = MemWRT.WriteObject(OBJ_WRITE_ARGS(Preface, DMSchemes));
474
475   if ( ASDCP_SUCCESS(result) )
476     {
477       ui32_t packet_length = MemWRT.Size();
478       result = WriteKLToBuffer(Buffer, s_MDD_Table[MDDindex_Preface].ul, packet_length);
479
480       if ( ASDCP_SUCCESS(result) )
481         Buffer.Size(Buffer.Size() + packet_length);
482     }
483
484   return result;
485 }
486
487 //
488 void
489 ASDCP::MXF::Preface::Dump(FILE* stream)
490 {
491   char identbuf[IdentBufferLen];
492
493   if ( stream == 0 )
494     stream = stderr;
495
496   KLVPacket::Dump(stream, false);
497   fprintf(stream, "  InstanceUID        = %s\n",  InstanceUID.ToString(identbuf));
498   fprintf(stream, "  GenerationUID      = %s\n",  GenerationUID.ToString(identbuf));
499   fprintf(stream, "  LastModifiedDate   = %s\n",  LastModifiedDate.ToString(identbuf));
500   fprintf(stream, "  Version            = %hu\n", Version);
501   fprintf(stream, "  ObjectModelVersion = %lu\n", ObjectModelVersion);
502   fprintf(stream, "  PrimaryPackage     = %s\n",  PrimaryPackage.ToString(identbuf));
503   fprintf(stream, "  Identifications:\n");  Identifications.Dump(stream);
504   fprintf(stream, "  ContentStorage     = %s\n",  ContentStorage.ToString(identbuf));
505   fprintf(stream, "  OperationalPattern = %s\n",  OperationalPattern.ToString(identbuf));
506   fprintf(stream, "  EssenceContainers:\n");  EssenceContainers.Dump(stream);
507   fprintf(stream, "  DMSchemes:\n");  DMSchemes.Dump(stream);
508
509   fputs("==========================================================================\n", stream);
510 }
511
512 //------------------------------------------------------------------------------------------
513 //
514
515 //
516 class ASDCP::MXF::h__PacketList
517 {
518 public:
519   std::list<InterchangeObject*> m_List;
520   std::map<UL, InterchangeObject*> m_Map;
521
522   ~h__PacketList() {
523     while ( ! m_List.empty() )
524       {
525         delete m_List.back();
526         m_List.pop_back();
527       }
528   }
529
530   //
531   void AddPacket(InterchangeObject* ThePacket)
532   {
533     assert(ThePacket);
534     m_Map.insert(std::map<UID, InterchangeObject*>::value_type(ThePacket->InstanceUID, ThePacket));
535     m_List.push_back(ThePacket);
536   }
537
538   //
539   Result_t GetMDObjectByType(const byte_t* ObjectID, InterchangeObject** Object)
540   {
541     ASDCP_TEST_NULL(ObjectID);
542     ASDCP_TEST_NULL(Object);
543     std::list<InterchangeObject*>::iterator li;
544     *Object = 0;
545
546     for ( li = m_List.begin(); li != m_List.end(); li++ )
547       {
548         if ( (*li)->HasUL(ObjectID) )
549           {
550             *Object = *li;
551             return RESULT_OK;
552           }
553       }
554
555     return RESULT_FAIL;
556   }
557 };
558
559 //------------------------------------------------------------------------------------------
560 //
561
562 ASDCP::MXF::OPAtomHeader::OPAtomHeader() : m_Preface(0), m_HasRIP(false)
563 {
564   m_PacketList = new h__PacketList;
565 }
566
567
568 ASDCP::MXF::OPAtomHeader::~OPAtomHeader()
569 {
570 }
571
572
573 ASDCP::Result_t
574 ASDCP::MXF::OPAtomHeader::InitFromFile(const ASDCP::FileReader& Reader)
575 {
576   m_HasRIP = false;
577   Result_t result = SeekToRIP(Reader);
578
579   if ( ASDCP_SUCCESS(result) )
580     {
581       result = m_RIP.InitFromFile(Reader);
582
583       if ( ASDCP_FAILURE(result) )
584         {
585           DefaultLogSink().Error("File contains no RIP\n");
586           result = RESULT_OK;
587         }
588       else
589         {
590           m_HasRIP = true;
591         }
592     }
593
594   if ( ASDCP_SUCCESS(result) )
595     result = Reader.Seek(0);
596
597   if ( ASDCP_SUCCESS(result) )
598     result = Partition::InitFromFile(Reader); // test UL and OP
599
600   // slurp up the remainder of the header
601   ui32_t read_count;
602
603   if ( ASDCP_SUCCESS(result) )
604     {
605       ui32_t buf_len = HeaderByteCount;
606       result = m_Buffer.Capacity(buf_len);
607     }
608
609   if ( ASDCP_SUCCESS(result) )
610     result = Reader.Read(m_Buffer.Data(), m_Buffer.Capacity(), &read_count);
611
612   if ( ASDCP_SUCCESS(result) && read_count != m_Buffer.Capacity() )
613     {
614       DefaultLogSink().Error("Short read of OP-Atom header metadata; wanted %lu, got %lu\n",
615                              m_Buffer.Capacity(), read_count);
616       return RESULT_FAIL;
617     }
618
619   const byte_t* p = m_Buffer.RoData();
620   const byte_t* end_p = p + m_Buffer.Capacity();
621
622   while ( ASDCP_SUCCESS(result) && p < end_p )
623     {
624       // parse the packets and index them by uid, discard KLVFill items
625       InterchangeObject* object = CreateObject(p);
626       assert(object);
627
628       object->m_Lookup = &m_Primer;
629       result = object->InitFromBuffer(p, end_p - p);
630       const byte_t* redo_p = p;
631       p += object->PacketLength();
632       //      hexdump(p, object->PacketLength());
633
634       if ( ASDCP_SUCCESS(result) )
635         {
636           if ( object->IsA(s_MDD_Table[MDDindex_KLVFill].ul) )
637             {
638               delete object;
639             }
640           else if ( object->IsA(s_MDD_Table[MDDindex_Primer].ul) )
641             {
642               delete object;
643               result = m_Primer.InitFromBuffer(redo_p, end_p - redo_p);
644             }
645           else if ( object->IsA(s_MDD_Table[MDDindex_Preface].ul) )
646             {
647               m_Preface = object;
648             }
649           else  
650             {
651               m_PacketList->AddPacket(object);
652             }
653         }
654       else
655         {
656           DefaultLogSink().Error("Error initializing packet\n");
657           delete object;
658         }
659     }
660
661   return result;
662 }
663
664 //
665 ASDCP::Result_t
666 ASDCP::MXF::OPAtomHeader::GetMDObjectByType(const byte_t* ObjectID, InterchangeObject** Object)
667 {
668   InterchangeObject* TmpObject;
669
670   if ( Object == 0 )
671     Object = &TmpObject;
672
673   return m_PacketList->GetMDObjectByType(ObjectID, Object);
674 }
675
676 ASDCP::MXF::Identification*
677 ASDCP::MXF::OPAtomHeader::GetIdentification()
678 {
679   InterchangeObject* Object;
680
681   if ( ASDCP_SUCCESS(GetMDObjectByType(OBJ_TYPE_ARGS(Identification), &Object)) )
682     return (Identification*)Object;
683
684   return 0;
685 }
686
687 //
688 ASDCP::Result_t
689 ASDCP::MXF::OPAtomHeader::WriteToFile(ASDCP::FileWriter& Writer, ui32_t HeaderSize)
690 {
691   if ( HeaderSize < 4096 ) 
692     {
693       DefaultLogSink().Error("HeaderSize %lu is too small. Must be >= 4096\n");
694       return RESULT_FAIL;
695     }
696
697   ASDCP::FrameBuffer HeaderBuffer;
698
699   Result_t result = HeaderBuffer.Capacity(HeaderSize);
700   HeaderByteCount = HeaderSize;
701
702   if ( ASDCP_SUCCESS(result) )
703     {
704       assert(m_Preface);
705       m_Preface->m_Lookup = &m_Primer;
706       result = m_Preface->WriteToBuffer(HeaderBuffer);
707     }
708 #if 0
709   std::list<InterchangeObject*>::iterator pl_i = m_PacketList->m_List.begin();
710   for ( ; pl_i != m_PacketList->m_List.end() && ASDCP_SUCCESS(result); pl_i++ )
711     {
712       InterchangeObject* object = *pl_i;
713       object->m_Lookup = &m_Primer;
714       result = object->WriteToBuffer(HeaderBuffer);
715     }
716 #endif
717   if ( ASDCP_SUCCESS(result) )
718     result = Partition::WriteToFile(Writer);
719
720   //  if ( ASDCP_SUCCESS(result) )
721     //    result = m_Primer.WriteToFile(Writer);
722
723   if ( ASDCP_SUCCESS(result) )
724     {
725       ui32_t write_count;
726       Writer.Write(HeaderBuffer.RoData(), HeaderBuffer.Size(), &write_count);
727       assert(write_count == HeaderBuffer.Size());
728     }
729
730   // KLV Fill
731   if ( ASDCP_SUCCESS(result) )
732     {
733       ASDCP::fpos_t pos = Writer.Tell();
734
735       if ( pos > HeaderSize )
736         {
737           char intbuf[IntBufferLen];
738           DefaultLogSink().Error("Header size %s exceeds specified value %lu\n",
739                                  ui64sz(pos, intbuf),
740                                  HeaderSize);
741           return RESULT_FAIL;
742         }
743
744       ASDCP::FrameBuffer NilBuf;
745       ui32_t klv_fill_length = HeaderSize - (ui32_t)pos;
746
747       if ( klv_fill_length < kl_length )
748         {
749           DefaultLogSink().Error("Remaining region too small for KLV Fill header\n");
750           return RESULT_FAIL;
751         }
752
753       klv_fill_length -= kl_length;
754       result = WriteKLToFile(Writer, s_MDD_Table[MDDindex_KLVFill].ul, klv_fill_length);
755
756       if ( ASDCP_SUCCESS(result) )
757         result = NilBuf.Capacity(klv_fill_length);
758
759       if ( ASDCP_SUCCESS(result) )
760         {
761           memset(NilBuf.Data(), 0, klv_fill_length);
762           ui32_t write_count;
763           Writer.Write(NilBuf.RoData(), klv_fill_length, &write_count);
764           assert(write_count == klv_fill_length);
765         }
766     }
767
768   return result;
769 }
770
771 //
772 void
773 ASDCP::MXF::OPAtomHeader::Dump(FILE* stream)
774 {
775   if ( stream == 0 )
776     stream = stderr;
777
778   if ( m_HasRIP )
779     m_RIP.Dump(stream);
780
781   Partition::Dump(stream);
782   m_Primer.Dump(stream);
783   assert(m_Preface);
784   m_Preface->Dump(stream);
785
786   std::list<InterchangeObject*>::iterator i = m_PacketList->m_List.begin();
787   for ( ; i != m_PacketList->m_List.end(); i++ )
788     (*i)->Dump(stream);
789 }
790
791 //------------------------------------------------------------------------------------------
792 //
793
794 ASDCP::MXF::OPAtomIndexFooter::OPAtomIndexFooter() : m_Lookup(0)
795 {
796   m_PacketList = new h__PacketList;
797 }
798
799
800 ASDCP::MXF::OPAtomIndexFooter::~OPAtomIndexFooter()
801 {
802 }
803
804
805 ASDCP::Result_t
806 ASDCP::MXF::OPAtomIndexFooter::InitFromFile(const ASDCP::FileReader& Reader)
807 {
808   Result_t result = Partition::InitFromFile(Reader); // test UL and OP
809
810   // slurp up the remainder of the footer
811   ui32_t read_count;
812
813   if ( ASDCP_SUCCESS(result) )
814     result = m_Buffer.Capacity(IndexByteCount);
815
816   if ( ASDCP_SUCCESS(result) )
817     result = Reader.Read(m_Buffer.Data(), m_Buffer.Capacity(), &read_count);
818
819   if ( ASDCP_SUCCESS(result) && read_count != m_Buffer.Capacity() )
820     {
821       DefaultLogSink().Error("Short read of footer partition: got %lu, expecting %lu\n",
822                              read_count, m_Buffer.Capacity());
823       return RESULT_FAIL;
824     }
825
826   const byte_t* p = m_Buffer.RoData();
827   const byte_t* end_p = p + m_Buffer.Capacity();
828   
829   while ( ASDCP_SUCCESS(result) && p < end_p )
830     {
831       // parse the packets and index them by uid, discard KLVFill items
832       InterchangeObject* object = CreateObject(p);
833       assert(object);
834
835       object->m_Lookup = m_Lookup;
836       result = object->InitFromBuffer(p, end_p - p);
837       p += object->PacketLength();
838
839       if ( ASDCP_SUCCESS(result) )
840         {
841           m_PacketList->AddPacket(object);
842         }
843       else
844         {
845           DefaultLogSink().Error("Error initializing packet\n");
846           delete object;
847         }
848     }
849
850   if ( ASDCP_FAILURE(result) )
851     DefaultLogSink().Error("Failed to initialize OPAtomIndexFooter\n");
852
853   return result;
854 }
855
856 //
857 ASDCP::Result_t
858 ASDCP::MXF::OPAtomIndexFooter::WriteToFile(ASDCP::FileWriter& Writer)
859 {
860   Result_t result = WriteKLToFile(Writer, s_MDD_Table[MDDindex_CompleteFooter].ul, 0);
861   return result;
862 }
863
864 //
865 void
866 ASDCP::MXF::OPAtomIndexFooter::Dump(FILE* stream)
867 {
868   if ( stream == 0 )
869     stream = stderr;
870
871   Partition::Dump(stream);
872
873   std::list<InterchangeObject*>::iterator i = m_PacketList->m_List.begin();
874   for ( ; i != m_PacketList->m_List.end(); i++ )
875     (*i)->Dump(stream);
876 }
877
878 //
879 ASDCP::Result_t
880 ASDCP::MXF::OPAtomIndexFooter::Lookup(ui32_t frame_num, IndexTableSegment::IndexEntry& Entry)
881 {
882   std::list<InterchangeObject*>::iterator li;
883   for ( li = m_PacketList->m_List.begin(); li != m_PacketList->m_List.end(); li++ )
884     {
885       if ( (*li)->IsA(OBJ_TYPE_ARGS(IndexTableSegment)) )
886         {
887           IndexTableSegment* Segment = (IndexTableSegment*)(*li);
888           ui64_t start_pos = Segment->IndexStartPosition;
889
890           if ( Segment->EditUnitByteCount > 0 )
891             {
892               if ( m_PacketList->m_List.size() > 1 )
893                 DefaultLogSink().Error("Unexpected multiple IndexTableSegment in CBR file\n");
894
895               if ( ! Segment->IndexEntryArray.empty() )
896                 DefaultLogSink().Error("Unexpected IndexEntryArray contents in CBR file\n");
897
898               Entry.StreamOffset = (ui64_t)frame_num * Segment->EditUnitByteCount;
899               return RESULT_OK;
900             }
901           else if ( (ui64_t)frame_num >= start_pos
902                     && (ui64_t)frame_num < (start_pos + Segment->IndexDuration) )
903             {
904               Entry = Segment->IndexEntryArray[frame_num];
905               return RESULT_OK;
906             }
907         }
908     }
909
910   return RESULT_FAIL;
911 }
912
913
914 //------------------------------------------------------------------------------------------
915 //
916
917 //
918 ASDCP::Result_t
919 ASDCP::MXF::InterchangeObject::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
920 {
921   if ( Buffer.Capacity() < (Buffer.Size() + m_KLLength + m_ValueLength) )
922     {
923       DefaultLogSink().Error("InterchangeObject::WriteToBuffer: Buffer too small\n");
924       Dump();
925       return RESULT_READFAIL;
926     }
927
928   Result_t result = WriteKLToBuffer(Buffer, m_KeyStart, m_ValueLength);
929
930   if ( ASDCP_SUCCESS(result) )
931     {
932       memcpy(Buffer.Data() + Buffer.Size(), m_ValueStart, m_ValueLength);
933       Buffer.Size(Buffer.Size() + m_ValueLength);
934     }
935
936   return result;
937 }
938
939 //
940 bool
941 ASDCP::MXF::InterchangeObject::IsA(const byte_t* label)
942 {
943   if ( m_KLLength == 0 )
944     return false;
945
946   return ( memcmp(label, m_KeyStart, SMPTE_UL_LENGTH) == 0 );
947 }
948
949
950 //------------------------------------------------------------------------------------------
951 //
952
953 //
954 enum FLT_t
955   {
956     FLT_Preface,
957     FLT_Identification,
958     FLT_ContentStorage,
959     FLT_MaterialPackage,
960     FLT_SourcePackage,
961     FLT_Track,
962     FLT_Sequence,
963     FLT_SourceClip,
964     FLT_TimecodeComponent,
965     FLT_FileDescriptor,
966     FLT_WaveAudioDescriptor,
967     FLT_GenericPictureEssenceDescriptor,
968     FLT_MPEG2VideoDescriptor,
969     FLT_RGBAEssenceDescriptor,
970     FLT_JPEG2000PictureSubDescriptor,
971     FLT_IndexTableSegment,
972     FLT_CryptographicFramework,
973     FLT_CryptographicContext
974   };
975
976 //
977 typedef std::map<ASDCP::UL, FLT_t> FactoryList;
978 #define SETUP_IDX(t) const ui32_t FLT_##t = v;
979
980 static FactoryList s_FactoryList;
981 #define SETUP_FACTORY(t) s_FactoryList.insert(FactoryList::value_type(s_MDD_Table[MDDindex_##t].ul, FLT_##t));
982 #define CASE_FACTORY(t)  case FLT_##t: return new t
983
984 //
985 ASDCP::MXF::InterchangeObject*
986 ASDCP::MXF::CreateObject(const byte_t* label)
987 {
988   if ( label == 0 )
989     return 0;
990
991   if ( s_FactoryList.empty() )
992     {
993       SETUP_FACTORY(Preface);
994       SETUP_FACTORY(Identification);
995       SETUP_FACTORY(ContentStorage);
996       SETUP_FACTORY(MaterialPackage);
997       SETUP_FACTORY(SourcePackage);
998       SETUP_FACTORY(Track);
999       SETUP_FACTORY(Sequence);
1000       SETUP_FACTORY(SourceClip);
1001       SETUP_FACTORY(TimecodeComponent);
1002       SETUP_FACTORY(FileDescriptor);
1003       SETUP_FACTORY(WaveAudioDescriptor);
1004       SETUP_FACTORY(GenericPictureEssenceDescriptor);
1005       SETUP_FACTORY(MPEG2VideoDescriptor);
1006       SETUP_FACTORY(RGBAEssenceDescriptor);
1007       SETUP_FACTORY(JPEG2000PictureSubDescriptor);
1008       SETUP_FACTORY(IndexTableSegment);
1009       SETUP_FACTORY(CryptographicFramework);
1010       SETUP_FACTORY(CryptographicContext);
1011     }
1012
1013   FactoryList::iterator i = s_FactoryList.find(label);
1014
1015   if ( i == s_FactoryList.end() )
1016     return new InterchangeObject;
1017
1018   switch ( i->second )
1019     {
1020       CASE_FACTORY(Preface);
1021       CASE_FACTORY(Identification);
1022       CASE_FACTORY(ContentStorage);
1023       CASE_FACTORY(MaterialPackage);
1024       CASE_FACTORY(SourcePackage);
1025       CASE_FACTORY(Track);
1026       CASE_FACTORY(Sequence);
1027       CASE_FACTORY(SourceClip);
1028       CASE_FACTORY(TimecodeComponent);
1029       CASE_FACTORY(FileDescriptor);
1030       CASE_FACTORY(WaveAudioDescriptor);
1031       CASE_FACTORY(GenericPictureEssenceDescriptor);
1032       CASE_FACTORY(MPEG2VideoDescriptor);
1033       CASE_FACTORY(RGBAEssenceDescriptor);
1034       CASE_FACTORY(JPEG2000PictureSubDescriptor);
1035       CASE_FACTORY(IndexTableSegment);
1036       CASE_FACTORY(CryptographicFramework);
1037       CASE_FACTORY(CryptographicContext);
1038     }
1039   
1040   return new InterchangeObject;
1041 }
1042
1043 //
1044 // end MXF.cpp
1045 //