code-generated metadata!
[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 #include "Mutex.h"
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 //
677 ASDCP::MXF::Identification*
678 ASDCP::MXF::OPAtomHeader::GetIdentification()
679 {
680   InterchangeObject* Object;
681
682   if ( ASDCP_SUCCESS(GetMDObjectByType(OBJ_TYPE_ARGS(Identification), &Object)) )
683     return (Identification*)Object;
684
685   return 0;
686 }
687
688 //
689 ASDCP::MXF::SourcePackage*
690 ASDCP::MXF::OPAtomHeader::GetSourcePackage()
691 {
692   InterchangeObject* Object;
693
694   if ( ASDCP_SUCCESS(GetMDObjectByType(OBJ_TYPE_ARGS(SourcePackage), &Object)) )
695     return (SourcePackage*)Object;
696
697   return 0;
698 }
699
700 //
701 ASDCP::Result_t
702 ASDCP::MXF::OPAtomHeader::WriteToFile(ASDCP::FileWriter& Writer, ui32_t HeaderSize)
703 {
704   if ( HeaderSize < 4096 ) 
705     {
706       DefaultLogSink().Error("HeaderSize %lu is too small. Must be >= 4096\n");
707       return RESULT_FAIL;
708     }
709
710   ASDCP::FrameBuffer HeaderBuffer;
711
712   Result_t result = HeaderBuffer.Capacity(HeaderSize);
713   HeaderByteCount = HeaderSize;
714
715   if ( ASDCP_SUCCESS(result) )
716     {
717       assert(m_Preface);
718       m_Preface->m_Lookup = &m_Primer;
719       result = m_Preface->WriteToBuffer(HeaderBuffer);
720     }
721 #if 0
722   std::list<InterchangeObject*>::iterator pl_i = m_PacketList->m_List.begin();
723   for ( ; pl_i != m_PacketList->m_List.end() && ASDCP_SUCCESS(result); pl_i++ )
724     {
725       InterchangeObject* object = *pl_i;
726       object->m_Lookup = &m_Primer;
727       result = object->WriteToBuffer(HeaderBuffer);
728     }
729 #endif
730   if ( ASDCP_SUCCESS(result) )
731     result = Partition::WriteToFile(Writer);
732
733   //  if ( ASDCP_SUCCESS(result) )
734     //    result = m_Primer.WriteToFile(Writer);
735
736   if ( ASDCP_SUCCESS(result) )
737     {
738       ui32_t write_count;
739       Writer.Write(HeaderBuffer.RoData(), HeaderBuffer.Size(), &write_count);
740       assert(write_count == HeaderBuffer.Size());
741     }
742
743   // KLV Fill
744   if ( ASDCP_SUCCESS(result) )
745     {
746       ASDCP::fpos_t pos = Writer.Tell();
747
748       if ( pos > HeaderSize )
749         {
750           char intbuf[IntBufferLen];
751           DefaultLogSink().Error("Header size %s exceeds specified value %lu\n",
752                                  ui64sz(pos, intbuf),
753                                  HeaderSize);
754           return RESULT_FAIL;
755         }
756
757       ASDCP::FrameBuffer NilBuf;
758       ui32_t klv_fill_length = HeaderSize - (ui32_t)pos;
759
760       if ( klv_fill_length < kl_length )
761         {
762           DefaultLogSink().Error("Remaining region too small for KLV Fill header\n");
763           return RESULT_FAIL;
764         }
765
766       klv_fill_length -= kl_length;
767       result = WriteKLToFile(Writer, s_MDD_Table[MDDindex_KLVFill].ul, klv_fill_length);
768
769       if ( ASDCP_SUCCESS(result) )
770         result = NilBuf.Capacity(klv_fill_length);
771
772       if ( ASDCP_SUCCESS(result) )
773         {
774           memset(NilBuf.Data(), 0, klv_fill_length);
775           ui32_t write_count;
776           Writer.Write(NilBuf.RoData(), klv_fill_length, &write_count);
777           assert(write_count == klv_fill_length);
778         }
779     }
780
781   return result;
782 }
783
784 //
785 void
786 ASDCP::MXF::OPAtomHeader::Dump(FILE* stream)
787 {
788   if ( stream == 0 )
789     stream = stderr;
790
791   if ( m_HasRIP )
792     m_RIP.Dump(stream);
793
794   Partition::Dump(stream);
795   m_Primer.Dump(stream);
796   assert(m_Preface);
797   m_Preface->Dump(stream);
798
799   std::list<InterchangeObject*>::iterator i = m_PacketList->m_List.begin();
800   for ( ; i != m_PacketList->m_List.end(); i++ )
801     (*i)->Dump(stream);
802 }
803
804 //------------------------------------------------------------------------------------------
805 //
806
807 ASDCP::MXF::OPAtomIndexFooter::OPAtomIndexFooter() : m_Lookup(0)
808 {
809   m_PacketList = new h__PacketList;
810 }
811
812
813 ASDCP::MXF::OPAtomIndexFooter::~OPAtomIndexFooter()
814 {
815 }
816
817
818 ASDCP::Result_t
819 ASDCP::MXF::OPAtomIndexFooter::InitFromFile(const ASDCP::FileReader& Reader)
820 {
821   Result_t result = Partition::InitFromFile(Reader); // test UL and OP
822
823   // slurp up the remainder of the footer
824   ui32_t read_count;
825
826   if ( ASDCP_SUCCESS(result) )
827     result = m_Buffer.Capacity(IndexByteCount);
828
829   if ( ASDCP_SUCCESS(result) )
830     result = Reader.Read(m_Buffer.Data(), m_Buffer.Capacity(), &read_count);
831
832   if ( ASDCP_SUCCESS(result) && read_count != m_Buffer.Capacity() )
833     {
834       DefaultLogSink().Error("Short read of footer partition: got %lu, expecting %lu\n",
835                              read_count, m_Buffer.Capacity());
836       return RESULT_FAIL;
837     }
838
839   const byte_t* p = m_Buffer.RoData();
840   const byte_t* end_p = p + m_Buffer.Capacity();
841   
842   while ( ASDCP_SUCCESS(result) && p < end_p )
843     {
844       // parse the packets and index them by uid, discard KLVFill items
845       InterchangeObject* object = CreateObject(p);
846       assert(object);
847
848       object->m_Lookup = m_Lookup;
849       result = object->InitFromBuffer(p, end_p - p);
850       p += object->PacketLength();
851
852       if ( ASDCP_SUCCESS(result) )
853         {
854           m_PacketList->AddPacket(object);
855         }
856       else
857         {
858           DefaultLogSink().Error("Error initializing packet\n");
859           delete object;
860         }
861     }
862
863   if ( ASDCP_FAILURE(result) )
864     DefaultLogSink().Error("Failed to initialize OPAtomIndexFooter\n");
865
866   return result;
867 }
868
869 //
870 ASDCP::Result_t
871 ASDCP::MXF::OPAtomIndexFooter::WriteToFile(ASDCP::FileWriter& Writer)
872 {
873   Result_t result = WriteKLToFile(Writer, s_MDD_Table[MDDindex_CompleteFooter].ul, 0);
874   return result;
875 }
876
877 //
878 void
879 ASDCP::MXF::OPAtomIndexFooter::Dump(FILE* stream)
880 {
881   if ( stream == 0 )
882     stream = stderr;
883
884   Partition::Dump(stream);
885
886   std::list<InterchangeObject*>::iterator i = m_PacketList->m_List.begin();
887   for ( ; i != m_PacketList->m_List.end(); i++ )
888     (*i)->Dump(stream);
889 }
890
891 //
892 ASDCP::Result_t
893 ASDCP::MXF::OPAtomIndexFooter::Lookup(ui32_t frame_num, IndexTableSegment::IndexEntry& Entry)
894 {
895   std::list<InterchangeObject*>::iterator li;
896   for ( li = m_PacketList->m_List.begin(); li != m_PacketList->m_List.end(); li++ )
897     {
898       if ( (*li)->IsA(OBJ_TYPE_ARGS(IndexTableSegment)) )
899         {
900           IndexTableSegment* Segment = (IndexTableSegment*)(*li);
901           ui64_t start_pos = Segment->IndexStartPosition;
902
903           if ( Segment->EditUnitByteCount > 0 )
904             {
905               if ( m_PacketList->m_List.size() > 1 )
906                 DefaultLogSink().Error("Unexpected multiple IndexTableSegment in CBR file\n");
907
908               if ( ! Segment->IndexEntryArray.empty() )
909                 DefaultLogSink().Error("Unexpected IndexEntryArray contents in CBR file\n");
910
911               Entry.StreamOffset = (ui64_t)frame_num * Segment->EditUnitByteCount;
912               return RESULT_OK;
913             }
914           else if ( (ui64_t)frame_num >= start_pos
915                     && (ui64_t)frame_num < (start_pos + Segment->IndexDuration) )
916             {
917               Entry = Segment->IndexEntryArray[frame_num];
918               return RESULT_OK;
919             }
920         }
921     }
922
923   return RESULT_FAIL;
924 }
925
926
927 //------------------------------------------------------------------------------------------
928 //
929
930 //
931 ASDCP::Result_t
932 ASDCP::MXF::InterchangeObject::InitFromTLVSet(TLVReader& TLVSet)
933 {
934   Result_t result = TLVSet.ReadObject(OBJ_READ_ARGS(InterchangeObject, InstanceUID));
935   if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(GenerationInterchangeObject, GenerationUID));
936   return result;
937 }
938
939 //
940 ASDCP::Result_t
941 ASDCP::MXF::InterchangeObject::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
942 {
943   if ( Buffer.Capacity() < (Buffer.Size() + m_KLLength + m_ValueLength) )
944     {
945       DefaultLogSink().Error("InterchangeObject::WriteToBuffer: Buffer too small\n");
946       Dump();
947       return RESULT_READFAIL;
948     }
949
950   Result_t result = WriteKLToBuffer(Buffer, m_KeyStart, m_ValueLength);
951
952   if ( ASDCP_SUCCESS(result) )
953     {
954       memcpy(Buffer.Data() + Buffer.Size(), m_ValueStart, m_ValueLength);
955       Buffer.Size(Buffer.Size() + m_ValueLength);
956     }
957
958   return result;
959 }
960
961 //
962 bool
963 ASDCP::MXF::InterchangeObject::IsA(const byte_t* label)
964 {
965   if ( m_KLLength == 0 )
966     return false;
967
968   return ( memcmp(label, m_KeyStart, SMPTE_UL_LENGTH) == 0 );
969 }
970
971
972 //------------------------------------------------------------------------------------------
973 //
974
975 //
976 enum FLT_t
977   {
978     FLT_Preface,
979     FLT_Identification,
980     FLT_ContentStorage,
981     FLT_MaterialPackage,
982     FLT_SourcePackage,
983     FLT_Track,
984     FLT_Sequence,
985     FLT_SourceClip,
986     FLT_TimecodeComponent,
987     FLT_FileDescriptor,
988     FLT_WaveAudioDescriptor,
989     FLT_GenericPictureEssenceDescriptor,
990     FLT_MPEG2VideoDescriptor,
991     FLT_RGBAEssenceDescriptor,
992     FLT_JPEG2000PictureSubDescriptor,
993     FLT_IndexTableSegment,
994     FLT_CryptographicFramework,
995     FLT_CryptographicContext
996   };
997
998 //
999 typedef std::map<ASDCP::UL, FLT_t>::iterator FLi_t;
1000
1001 class FactoryList : public std::map<ASDCP::UL, FLT_t>
1002 {
1003   ASDCP::Mutex m_Lock;
1004
1005 public:
1006   FactoryList() {}
1007   ~FactoryList() {}
1008
1009   bool Empty() {
1010     ASDCP::AutoMutex BlockLock(m_Lock);
1011     return empty();
1012   }
1013
1014   FLi_t Find(const byte_t* label) {
1015     ASDCP::AutoMutex BlockLock(m_Lock);
1016     return find(label);
1017   }
1018
1019   FLi_t End() {
1020     ASDCP::AutoMutex BlockLock(m_Lock);
1021     return end();
1022   }
1023
1024 };
1025
1026 //
1027 static FactoryList s_FactoryList;
1028
1029 #define SETUP_IDX(t) const ui32_t FLT_##t = v;
1030 #define SETUP_FACTORY(t) s_FactoryList.insert(FactoryList::value_type(s_MDD_Table[MDDindex_##t].ul, FLT_##t));
1031 #define CASE_FACTORY(t)  case FLT_##t: return new t
1032
1033 //
1034 ASDCP::MXF::InterchangeObject*
1035 ASDCP::MXF::CreateObject(const byte_t* label)
1036 {
1037   if ( label == 0 )
1038     return 0;
1039
1040   if ( s_FactoryList.empty() )
1041     {
1042       SETUP_FACTORY(Preface);
1043       SETUP_FACTORY(Identification);
1044       SETUP_FACTORY(ContentStorage);
1045       SETUP_FACTORY(MaterialPackage);
1046       SETUP_FACTORY(SourcePackage);
1047       SETUP_FACTORY(Track);
1048       SETUP_FACTORY(Sequence);
1049       SETUP_FACTORY(SourceClip);
1050       SETUP_FACTORY(TimecodeComponent);
1051       SETUP_FACTORY(FileDescriptor);
1052       SETUP_FACTORY(WaveAudioDescriptor);
1053       SETUP_FACTORY(GenericPictureEssenceDescriptor);
1054       SETUP_FACTORY(MPEG2VideoDescriptor);
1055       SETUP_FACTORY(RGBAEssenceDescriptor);
1056       SETUP_FACTORY(JPEG2000PictureSubDescriptor);
1057       SETUP_FACTORY(IndexTableSegment);
1058       SETUP_FACTORY(CryptographicFramework);
1059       SETUP_FACTORY(CryptographicContext);
1060     }
1061
1062   FLi_t i = s_FactoryList.find(label);
1063
1064   if ( i == s_FactoryList.end() )
1065     return new InterchangeObject;
1066
1067   switch ( i->second )
1068     {
1069       CASE_FACTORY(Preface);
1070       CASE_FACTORY(Identification);
1071       CASE_FACTORY(ContentStorage);
1072       CASE_FACTORY(MaterialPackage);
1073       CASE_FACTORY(SourcePackage);
1074       CASE_FACTORY(Track);
1075       CASE_FACTORY(Sequence);
1076       CASE_FACTORY(SourceClip);
1077       CASE_FACTORY(TimecodeComponent);
1078       CASE_FACTORY(FileDescriptor);
1079       CASE_FACTORY(WaveAudioDescriptor);
1080       CASE_FACTORY(GenericPictureEssenceDescriptor);
1081       CASE_FACTORY(MPEG2VideoDescriptor);
1082       CASE_FACTORY(RGBAEssenceDescriptor);
1083       CASE_FACTORY(JPEG2000PictureSubDescriptor);
1084       CASE_FACTORY(IndexTableSegment);
1085       CASE_FACTORY(CryptographicFramework);
1086       CASE_FACTORY(CryptographicContext);
1087     }
1088   
1089   return new InterchangeObject;
1090 }
1091
1092 //
1093 // end MXF.cpp
1094 //