9e481e2e35f5c6e63aad8038af26cefc54775cc7
[asdcplib.git] / src / MXFTypes.cpp
1 /*
2 Copyright (c) 2005-2016, 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    MXFTypes.cpp
28     \version $Id$
29     \brief   MXF objects
30 */
31
32 #include <KM_prng.h>
33 #include <KM_tai.h>
34 #include "MXFTypes.h"
35 #include <KM_log.h>
36
37 using Kumu::DefaultLogSink;
38
39 //------------------------------------------------------------------------------------------
40 //
41
42 //
43 bool
44 ASDCP::UL::operator==(const UL& rhs) const
45 {
46   if ( m_Value[0] == rhs.m_Value[0] &&
47        m_Value[1] == rhs.m_Value[1] &&
48        m_Value[2] == rhs.m_Value[2] &&
49        m_Value[3] == rhs.m_Value[3] &&
50        m_Value[4] == rhs.m_Value[4] &&
51        m_Value[5] == rhs.m_Value[5] &&
52        m_Value[6] == rhs.m_Value[6] &&
53        //       m_Value[7] == rhs.m_Value[7] &&  // version is ignored when performing lookups
54        m_Value[8] == rhs.m_Value[8] &&
55        m_Value[9] == rhs.m_Value[9] &&
56        m_Value[10] == rhs.m_Value[10] &&
57        m_Value[11] == rhs.m_Value[11] &&
58        m_Value[12] == rhs.m_Value[12] &&
59        m_Value[13] == rhs.m_Value[13] &&
60        m_Value[14] == rhs.m_Value[14] &&
61        m_Value[15] == rhs.m_Value[15]
62        )
63     return true;
64
65   return false;
66 }
67
68
69 //
70 bool
71 ASDCP::UL::operator<(const UL& rhs) const
72 {
73   if ( m_Value[0] < rhs.m_Value[0] ) return true;
74   if ( m_Value[0] == rhs.m_Value[0] )
75     {
76       if ( m_Value[1] < rhs.m_Value[1] ) return true;
77       if ( m_Value[1] == rhs.m_Value[1] )
78         {
79           if ( m_Value[2] < rhs.m_Value[2] ) return true;
80           if ( m_Value[2] == rhs.m_Value[2] )
81             {
82               if ( m_Value[3] < rhs.m_Value[3] ) return true;
83               if ( m_Value[3] == rhs.m_Value[3] )
84                 {
85                   if ( m_Value[4] < rhs.m_Value[4] ) return true;
86                   if ( m_Value[4] == rhs.m_Value[4] )
87                     {
88                       if ( m_Value[5] < rhs.m_Value[5] ) return true;
89                       if ( m_Value[5] == rhs.m_Value[5] )
90                         {
91                           if ( m_Value[6] < rhs.m_Value[6] ) return true;
92                           if ( m_Value[6] == rhs.m_Value[6] )
93                             {
94                               if ( m_Value[8] < rhs.m_Value[8] ) return true;
95                               if ( m_Value[8] == rhs.m_Value[8] )
96                                 {
97                                   if ( m_Value[9] < rhs.m_Value[9] ) return true;
98                                   if ( m_Value[9] == rhs.m_Value[9] )
99                                     {
100                                       if ( m_Value[10] < rhs.m_Value[10] ) return true;
101                                       if ( m_Value[10] == rhs.m_Value[10] )
102                                         {
103                                           if ( m_Value[11] < rhs.m_Value[11] ) return true;
104                                           if ( m_Value[11] == rhs.m_Value[11] )
105                                             {
106                                               if ( m_Value[12] < rhs.m_Value[12] ) return true;
107                                               if ( m_Value[12] == rhs.m_Value[12] )
108                                                 {
109                                                   if ( m_Value[13] < rhs.m_Value[13] ) return true;
110                                                   if ( m_Value[13] == rhs.m_Value[13] )
111                                                     {
112                                                       if ( m_Value[14] < rhs.m_Value[14] ) return true;
113                                                       if ( m_Value[14] == rhs.m_Value[14] )
114                                                         {
115                                                           if ( m_Value[15] < rhs.m_Value[15] ) return true;
116                                                         }
117                                                     }
118                                                 }
119                                             }
120                                         }
121                                     }
122                                 }
123                             }
124                         }
125                     }
126                 }
127             }
128         }
129     }
130
131   return false;
132 }
133
134 //
135 bool
136 ASDCP::UL::MatchIgnoreStream(const UL& rhs) const
137 {
138   if ( m_Value[0] == rhs.m_Value[0] &&
139        m_Value[1] == rhs.m_Value[1] &&
140        m_Value[2] == rhs.m_Value[2] &&
141        m_Value[3] == rhs.m_Value[3] &&
142        m_Value[4] == rhs.m_Value[4] &&
143        m_Value[5] == rhs.m_Value[5] &&
144        m_Value[6] == rhs.m_Value[6] &&
145        //       m_Value[7] == rhs.m_Value[7] &&  // version is ignored when performing lookups
146        m_Value[8] == rhs.m_Value[8] &&
147        m_Value[9] == rhs.m_Value[9] &&
148        m_Value[10] == rhs.m_Value[10] &&
149        m_Value[11] == rhs.m_Value[11] &&
150        m_Value[12] == rhs.m_Value[12] &&
151        m_Value[13] == rhs.m_Value[13] &&
152        m_Value[14] == rhs.m_Value[14]
153        //       m_Value[15] == rhs.m_Value[15] // ignore stream number
154        )
155     return true;
156
157   return false;
158 }
159
160 //
161 bool
162 ASDCP::UL::ExactMatch(const UL& rhs) const
163 {
164   if ( m_Value[0] == rhs.m_Value[0] &&
165        m_Value[1] == rhs.m_Value[1] &&
166        m_Value[2] == rhs.m_Value[2] &&
167        m_Value[3] == rhs.m_Value[3] &&
168        m_Value[4] == rhs.m_Value[4] &&
169        m_Value[5] == rhs.m_Value[5] &&
170        m_Value[6] == rhs.m_Value[6] &&
171        m_Value[7] == rhs.m_Value[7] &&
172        m_Value[8] == rhs.m_Value[8] &&
173        m_Value[9] == rhs.m_Value[9] &&
174        m_Value[10] == rhs.m_Value[10] &&
175        m_Value[11] == rhs.m_Value[11] &&
176        m_Value[12] == rhs.m_Value[12] &&
177        m_Value[13] == rhs.m_Value[13] &&
178        m_Value[14] == rhs.m_Value[14] &&
179        m_Value[15] == rhs.m_Value[15]
180        )
181     return true;
182
183   return false;
184 }
185
186 const char*
187 ASDCP::UL::EncodeString(char* str_buf, ui32_t buf_len) const
188 {
189   if ( buf_len > 38 ) // room for dotted notation?
190     {
191       snprintf(str_buf, buf_len,
192                "%02x%02x%02x%02x.%02x%02x%02x%02x.%02x%02x%02x%02x.%02x%02x%02x%02x",
193                m_Value[0],  m_Value[1],  m_Value[2],  m_Value[3],
194                m_Value[4],  m_Value[5],  m_Value[6],  m_Value[7],
195                m_Value[8],  m_Value[9],  m_Value[10], m_Value[11],
196                m_Value[12], m_Value[13], m_Value[14], m_Value[15]
197                );
198
199       return str_buf;
200     }
201   else if ( buf_len > 32 ) // room for compact?
202     {
203       snprintf(str_buf, buf_len,
204                "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
205                m_Value[0],  m_Value[1],  m_Value[2],  m_Value[3],
206                m_Value[4],  m_Value[5],  m_Value[6],  m_Value[7],
207                m_Value[8],  m_Value[9],  m_Value[10], m_Value[11],
208                m_Value[12], m_Value[13], m_Value[14], m_Value[15]
209                );
210
211       return str_buf;
212     }
213
214   return 0;
215 }
216
217 //
218 void
219 ASDCP::UMID::MakeUMID(int Type)
220 {
221   UUID AssetID;
222   Kumu::GenRandomValue(AssetID);
223   MakeUMID(Type, AssetID);
224 }
225
226 //
227 void
228 ASDCP::UMID::MakeUMID(int Type, const UUID& AssetID)
229 {
230   // Set the non-varying base of the UMID
231   static const byte_t UMIDBase[10] = { 0x06, 0x0a, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
232   memcpy(m_Value, UMIDBase, 10);
233   m_Value[10] = Type;  // Material Type
234   m_Value[12] = 0x13;  // length
235
236   // preserved for compatibility with mfxlib
237   if( Type > 4 ) m_Value[7] = 5;
238   m_Value[11] = 0x20; // UUID/UL method, number gen undefined
239
240   // Instance Number
241   m_Value[13] = m_Value[14] = m_Value[15] = 0;
242   
243   memcpy(&m_Value[16], AssetID.Value(), AssetID.Size());
244   m_HasValue = true;
245 }
246
247
248 // Write the UMID value to the given buffer in the form
249 //   [00000000.0000.0000.00000000],00,00,00,00,00000000.0000.0000.00000000.00000000]
250 // or
251 //   [00000000.0000.0000.00000000],00,00,00,00,00000000-0000-0000-0000-000000000000]
252 // returns 0 if the buffer is smaller than DateTimeLen
253 const char*
254 ASDCP::UMID::EncodeString(char* str_buf, ui32_t buf_len) const
255 {
256   assert(str_buf);
257
258   snprintf(str_buf, buf_len, "[%02x%02x%02x%02x.%02x%02x%02x%02x.%02x%02x%02x%02x],%02x,%02x,%02x,%02x,",
259            m_Value[0],  m_Value[1],  m_Value[2],  m_Value[3],
260            m_Value[4],  m_Value[5],  m_Value[6],  m_Value[7],
261            m_Value[8],  m_Value[9],  m_Value[10], m_Value[11],
262            m_Value[12], m_Value[13], m_Value[14], m_Value[15]
263            );
264
265   ui32_t offset = strlen(str_buf);
266
267   if ( ( m_Value[8] & 0x80 ) == 0 )
268     {
269       // half-swapped UL, use [bbaa9988.ddcc.ffee.00010203.04050607]
270       snprintf(str_buf + offset, buf_len - offset,
271                "[%02x%02x%02x%02x.%02x%02x%02x%02x.%02x%02x%02x%02x.%02x%02x%02x%02x]",
272                m_Value[24], m_Value[25], m_Value[26], m_Value[27],
273                m_Value[28], m_Value[29], m_Value[30], m_Value[31],
274                m_Value[16], m_Value[17], m_Value[18], m_Value[19],
275                m_Value[20], m_Value[21], m_Value[22], m_Value[23]
276                );
277     }
278   else
279     {
280       // UUID, use {00112233-4455-6677-8899-aabbccddeeff}
281       snprintf(str_buf + offset, buf_len - offset,
282                "{%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
283                m_Value[16], m_Value[17], m_Value[18], m_Value[19],
284                m_Value[20], m_Value[21], m_Value[22], m_Value[23],
285                m_Value[24], m_Value[25], m_Value[26], m_Value[27],
286                m_Value[28], m_Value[29], m_Value[30], m_Value[31]
287                );
288     }
289
290   return str_buf;
291 }
292
293 //------------------------------------------------------------------------------------------
294 //
295
296 //
297 ASDCP::MXF::UTF16String::UTF16String(const char* sz)
298 {
299   if ( sz != 0 && *sz != 0 )
300     {
301       this->assign(sz);
302     }
303 }
304
305 ASDCP::MXF::UTF16String::UTF16String(const std::string& str)
306 {
307   this->assign(str);
308 }
309
310 //
311 const ASDCP::MXF::UTF16String&
312 ASDCP::MXF::UTF16String::operator=(const char* sz)
313 {
314   if ( sz == 0 || *sz == 0 )
315     erase();
316
317   else
318     this->assign(sz);
319   
320   return *this;
321 }
322
323 //
324 const ASDCP::MXF::UTF16String&
325 ASDCP::MXF::UTF16String::operator=(const std::string& str)
326 {
327   this->assign(str);
328   return *this;
329 }
330
331 //
332 const char*
333 ASDCP::MXF::UTF16String::EncodeString(char* str_buf, ui32_t buf_len) const
334 {
335   ui32_t write_len = Kumu::xmin(buf_len - 1, (ui32_t)size());
336   strncpy(str_buf, c_str(), write_len);
337   str_buf[write_len] = 0;
338   return str_buf;
339 }
340
341 //
342 bool
343 ASDCP::MXF::UTF16String::Unarchive(Kumu::MemIOReader* Reader)
344 {
345   erase();
346   const ui16_t* p = (ui16_t*)Reader->CurrentData();
347   ui32_t length = Reader->Remainder() / 2;
348   char mb_buf[MB_LEN_MAX+1];
349
350   for ( ui32_t i = 0; i < length; i++ )
351     {
352       int count = wctomb(mb_buf, KM_i16_BE(p[i]));
353
354       if ( count == -1 )
355         {
356           DefaultLogSink().Error("Unable to decode wide character 0x%04hx\n", p[i]);
357           return false;
358         }
359
360       assert(count <= MB_LEN_MAX);
361       mb_buf[count] = 0;
362       this->append(mb_buf);
363     }
364
365   Reader->SkipOffset(length*2);
366   return true;
367 }
368
369 //
370 bool
371 ASDCP::MXF::UTF16String::Archive(Kumu::MemIOWriter* Writer) const
372 {
373   if ( size() > IdentBufferLen )
374     {
375       DefaultLogSink().Error("String length exceeds maximum %u bytes\n", IdentBufferLen);
376       return false;
377     }
378
379   const char* mbp = c_str();
380   wchar_t wcp;
381   ui32_t remainder = size();
382   ui32_t length = size();
383   ui32_t i = 0;
384
385   while ( i < length )
386     {
387       int count = mbtowc(&wcp, mbp+i, remainder);
388
389       if ( count == -1 )
390         {
391           DefaultLogSink().Error("Error decoding multi-byte sequence starting at offset %u\n", i);
392           return false;
393         }
394       else if ( count  == 0 )
395         {
396           break;
397         }
398
399       bool result = Writer->WriteUi16BE((ui16_t)wcp);
400
401       if ( result == false )
402         {
403           DefaultLogSink().Error("No more space in memory IO writer\n");
404           return false;
405         }
406
407       i += count;
408       remainder -= count;
409     }
410
411   return true;
412 }
413
414 //------------------------------------------------------------------------------------------
415 //
416
417 //
418 ASDCP::MXF::ISO8String::ISO8String(const char* sz)
419 {
420   if ( sz != 0 && *sz != 0 )
421     {
422       this->assign(sz);
423     }
424 }
425
426 ASDCP::MXF::ISO8String::ISO8String(const std::string& str)
427 {
428   this->assign(str);
429 }
430
431
432 //
433 const ASDCP::MXF::ISO8String&
434 ASDCP::MXF::ISO8String::operator=(const char* sz)
435 {
436   if ( sz == 0 || *sz == 0 )
437     erase();
438
439   else
440     this->assign(sz);
441   
442   return *this;
443 }
444
445 //
446 const ASDCP::MXF::ISO8String&
447 ASDCP::MXF::ISO8String::operator=(const std::string& str)
448 {
449   this->assign(str);
450   return *this;
451 }
452
453 //
454 const char*
455 ASDCP::MXF::ISO8String::EncodeString(char* str_buf, ui32_t buf_len) const
456 {
457   ui32_t write_len = Kumu::xmin(buf_len - 1, (ui32_t)size());
458   strncpy(str_buf, c_str(), write_len);
459   str_buf[write_len] = 0;
460   return str_buf;
461 }
462
463 //
464 bool
465 ASDCP::MXF::ISO8String::Unarchive(Kumu::MemIOReader* Reader)
466 {
467   assign((char*)Reader->CurrentData(), Reader->Remainder());
468   return true;
469 }
470
471 //
472 bool
473 ASDCP::MXF::ISO8String::Archive(Kumu::MemIOWriter* Writer) const
474 {
475   if ( size() > IdentBufferLen )
476     {
477       DefaultLogSink().Error("String length exceeds maximum %u bytes\n", IdentBufferLen);
478       return false;
479     }
480
481   return Writer->WriteRaw((const byte_t*)c_str(), size());
482 }
483
484 //------------------------------------------------------------------------------------------
485 //
486
487 ASDCP::MXF::TLVReader::TLVReader(const byte_t* p, ui32_t c, IPrimerLookup* PrimerLookup) :
488   MemIOReader(p, c), m_Lookup(PrimerLookup)
489 {
490   Result_t result = RESULT_OK;
491
492   while ( Remainder() > 0 && ASDCP_SUCCESS(result) )
493     {
494       TagValue Tag;
495       ui16_t pkt_len = 0;
496
497       if ( MemIOReader::ReadUi8(&Tag.a) )
498         if ( MemIOReader::ReadUi8(&Tag.b) )
499           if ( MemIOReader::ReadUi16BE(&pkt_len) )
500             {
501               m_ElementMap.insert(TagMap::value_type(Tag, ItemInfo(m_size, pkt_len)));
502               if ( SkipOffset(pkt_len) )
503                 continue;;
504             }
505
506       DefaultLogSink().Error("Malformed Set\n");
507       m_ElementMap.clear();
508       result = RESULT_KLV_CODING(__LINE__, __FILE__);
509     }
510 }
511
512 //
513 bool
514 ASDCP::MXF::TLVReader::FindTL(const MDDEntry& Entry)
515 {
516   if ( m_Lookup == 0 )
517     {
518       DefaultLogSink().Error("No Lookup service\n");
519       return false;
520     }
521   
522   TagValue TmpTag;
523
524   if ( m_Lookup->TagForKey(Entry.ul, TmpTag) != RESULT_OK )
525     {
526       if ( Entry.tag.a == 0 )
527         {
528           //      DefaultLogSink().Debug("No such UL in this TL list: %s (%02x %02x)\n",
529           //                             Entry.name, Entry.tag.a, Entry.tag.b);
530           return false;
531         }
532
533       TmpTag = Entry.tag;
534     }
535
536   TagMap::iterator e_i = m_ElementMap.find(TmpTag);
537
538   if ( e_i != m_ElementMap.end() )
539     {
540       m_size = (*e_i).second.first;
541       m_capacity = m_size + (*e_i).second.second;
542       return true;
543     }
544
545   //  DefaultLogSink().Debug("Not Found (%02x %02x): %s\n", TmpTag.a, TmpTag.b, Entry.name);
546   return false;
547 }
548
549 //
550 ASDCP::Result_t
551 ASDCP::MXF::TLVReader::ReadObject(const MDDEntry& Entry, Kumu::IArchive* Object)
552 {
553   ASDCP_TEST_NULL(Object);
554
555   if ( FindTL(Entry) )
556     {
557       if ( m_size < m_capacity ) // don't try to unarchive an empty item
558         {
559           // TODO: carry on if uachive fails
560           return Object->Unarchive(this) ? RESULT_OK : RESULT_FALSE(__LINE__, __FILE__);
561         }
562     }
563
564   return RESULT_FALSE;
565 }
566
567 //
568 ASDCP::Result_t
569 ASDCP::MXF::TLVReader::ReadUi8(const MDDEntry& Entry, ui8_t* value)
570 {
571   ASDCP_TEST_NULL(value);
572
573   if ( FindTL(Entry) )
574     return MemIOReader::ReadUi8(value) ? RESULT_OK : RESULT_FALSE(__LINE__, __FILE__);
575
576   return RESULT_FALSE;
577 }
578
579 //
580 ASDCP::Result_t
581 ASDCP::MXF::TLVReader::ReadUi16(const MDDEntry& Entry, ui16_t* value)
582 {
583   ASDCP_TEST_NULL(value);
584
585   if ( FindTL(Entry) )
586     return MemIOReader::ReadUi16BE(value) ? RESULT_OK : RESULT_FALSE(__LINE__, __FILE__);
587
588   return RESULT_FALSE;
589 }
590
591 //
592 ASDCP::Result_t
593 ASDCP::MXF::TLVReader::ReadUi32(const MDDEntry& Entry, ui32_t* value)
594 {
595   ASDCP_TEST_NULL(value);
596
597   if ( FindTL(Entry) )
598     return MemIOReader::ReadUi32BE(value) ? RESULT_OK : RESULT_FALSE(__LINE__, __FILE__);
599
600   return RESULT_FALSE;
601 }
602
603 //
604 ASDCP::Result_t
605 ASDCP::MXF::TLVReader::ReadUi64(const MDDEntry& Entry, ui64_t* value)
606 {
607   ASDCP_TEST_NULL(value);
608
609   if ( FindTL(Entry) )
610     return MemIOReader::ReadUi64BE(value) ? RESULT_OK : RESULT_FALSE(__LINE__, __FILE__);
611
612   return RESULT_FALSE;
613 }
614
615 //------------------------------------------------------------------------------------------
616 //
617
618 ASDCP::MXF::TLVWriter::TLVWriter(byte_t* p, ui32_t c, IPrimerLookup* PrimerLookup) :
619   MemIOWriter(p, c), m_Lookup(PrimerLookup)
620 {
621   assert(c > 3);
622 }
623
624 //
625 ASDCP::Result_t
626 ASDCP::MXF::TLVWriter::WriteTag(const MDDEntry& Entry)
627 {
628   if ( m_Lookup == 0 )
629     {
630       DefaultLogSink().Error("No Primer object available\n");
631       return RESULT_FAIL;
632     }
633
634   TagValue TmpTag;
635
636   if ( m_Lookup->InsertTag(Entry, TmpTag) != RESULT_OK )
637     {
638       DefaultLogSink().Error("No tag for entry %s\n", Entry.name);
639       return RESULT_FAIL;
640     }
641
642   if ( ! MemIOWriter::WriteUi8(TmpTag.a) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
643   if ( ! MemIOWriter::WriteUi8(TmpTag.b) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
644   return RESULT_OK;
645 }
646
647 //
648 ASDCP::Result_t
649 ASDCP::MXF::TLVWriter::WriteObject(const MDDEntry& Entry, Kumu::IArchive* Object)
650 {
651   ASDCP_TEST_NULL(Object);
652
653   if ( Entry.optional && ! Object->HasValue() )
654     return RESULT_OK;
655
656   Result_t result = WriteTag(Entry);
657
658   if ( ASDCP_SUCCESS(result) )
659     {
660       // write a temp length
661       byte_t* l_p = CurrentData();
662
663       if ( ! MemIOWriter::WriteUi16BE(0) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
664
665       ui32_t before = Length();
666       if ( ! Object->Archive(this) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
667       if ( (Length() - before) > 0xffffL ) return RESULT_KLV_CODING(__LINE__, __FILE__);
668       Kumu::i2p<ui16_t>(KM_i16_BE(Length() - before), l_p);
669     }
670
671   return result;
672 }
673
674 //
675 ASDCP::Result_t
676 ASDCP::MXF::TLVWriter::WriteUi8(const MDDEntry& Entry, ui8_t* value)
677 {
678   ASDCP_TEST_NULL(value);
679   Result_t result = WriteTag(Entry);
680
681   if ( ASDCP_SUCCESS(result) )
682     {
683       if ( ! MemIOWriter::WriteUi16BE(sizeof(ui8_t)) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
684       if ( ! MemIOWriter::WriteUi8(*value) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
685     }
686   
687   return result;
688 }
689
690 //
691 ASDCP::Result_t
692 ASDCP::MXF::TLVWriter::WriteUi16(const MDDEntry& Entry, ui16_t* value)
693 {
694   ASDCP_TEST_NULL(value);
695   Result_t result = WriteTag(Entry);
696
697   if ( KM_SUCCESS(result) )
698     {
699       if ( ! MemIOWriter::WriteUi16BE(sizeof(ui16_t)) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
700       if ( ! MemIOWriter::WriteUi16BE(*value) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
701     }
702
703   return result;
704 }
705
706 //
707 ASDCP::Result_t
708 ASDCP::MXF::TLVWriter::WriteUi32(const MDDEntry& Entry, ui32_t* value)
709 {
710   ASDCP_TEST_NULL(value);
711   Result_t result = WriteTag(Entry);
712
713   if ( KM_SUCCESS(result) )
714     {
715       if ( ! MemIOWriter::WriteUi16BE(sizeof(ui32_t)) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
716       if ( ! MemIOWriter::WriteUi32BE(*value) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
717     }
718
719   return result;
720 }
721
722 //
723 ASDCP::Result_t
724 ASDCP::MXF::TLVWriter::WriteUi64(const MDDEntry& Entry, ui64_t* value)
725 {
726   ASDCP_TEST_NULL(value);
727   Result_t result = WriteTag(Entry);
728
729   if ( KM_SUCCESS(result) )
730     {
731       if ( ! MemIOWriter::WriteUi16BE(sizeof(ui64_t)) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
732       if ( ! MemIOWriter::WriteUi64BE(*value) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
733     }
734
735   return result;
736 }
737
738
739 //----------------------------------------------------------------------------------------------------
740 //
741
742
743 ASDCP::MXF::RGBALayout::RGBALayout()
744 {
745   memset(m_value, 0, RGBAValueLength);
746 }
747
748 ASDCP::MXF::RGBALayout::RGBALayout(const byte_t* value)
749 {
750   memcpy(m_value, value, RGBAValueLength);
751 }
752
753 ASDCP::MXF::RGBALayout::~RGBALayout()
754 {
755 }
756
757 static char
758 get_char_for_code(byte_t c)
759 {
760   for ( int i = 0; ASDCP::MXF::RGBALayoutTable[i].code != 0; ++i )
761     {
762       if ( ASDCP::MXF::RGBALayoutTable[i].code == c )
763         {
764           return ASDCP::MXF::RGBALayoutTable[i].symbol;
765         }
766     }
767
768   return '_';
769 }
770
771 //
772 const char*
773 ASDCP::MXF::RGBALayout::EncodeString(char* buf, ui32_t buf_len) const
774 {
775   std::string tmp_str;
776   char tmp_buf[64];
777
778   for ( int i = 0; i < RGBAValueLength && m_value[i] != 0; i += 2 )
779     {
780       snprintf(tmp_buf, 64, "%c(%d)", get_char_for_code(m_value[i]), m_value[i+1]);
781
782       if ( ! tmp_str.empty() )
783         {
784           tmp_str += " ";
785         }
786
787       tmp_str += tmp_buf;
788     }
789
790   assert(tmp_str.size() < buf_len);
791   strncpy(buf, tmp_str.c_str(), tmp_str.size());
792   return buf;
793 }
794
795
796 //----------------------------------------------------------------------------------------------------
797 //
798
799 ASDCP::MXF::Raw::Raw()
800 {
801   Capacity(256);
802 }
803
804 ASDCP::MXF::Raw::~Raw()
805 {
806 }
807
808 //
809 bool
810 ASDCP::MXF::Raw::Unarchive(Kumu::MemIOReader* Reader)
811 {
812   ui32_t payload_size = Reader->Remainder();
813   if ( payload_size == 0 ) return false;
814   if ( KM_FAILURE(Capacity(payload_size)) ) return false;
815
816   memcpy(Data(), Reader->CurrentData(), payload_size);
817   Length(payload_size);
818   return true;
819 }
820
821 //
822 bool
823 ASDCP::MXF::Raw::Archive(Kumu::MemIOWriter* Writer) const
824 {
825   return Writer->WriteRaw(RoData(), Length());
826 }
827
828 //
829 const char*
830 ASDCP::MXF::Raw::EncodeString(char* str_buf, ui32_t buf_len) const
831 {
832   *str_buf = 0;
833   Kumu::bin2hex(RoData(), Length(), str_buf, buf_len);
834   return str_buf;
835 }
836
837 //
838 // end MXFTypes.cpp
839 //