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