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