Fix some comparisons of signed with unsigned.
[asdcplib-cth.git] / src / MXFTypes.cpp
1 /*
2 Copyright (c) 2005-2015, 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: MXFTypes.cpp,v 1.33 2015/10/12 15:30:46 jhurst Exp $
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::ExactMatch(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+1];
283
284   for ( ui32_t i = 0; i < length; i++ )
285     {
286       int count = wctomb(mb_buf, KM_i16_BE(p[i]));
287
288       if ( count == -1 )
289         {
290           DefaultLogSink().Error("Unable to decode wide character 0x%04hx\n", p[i]);
291           return false;
292         }
293
294       assert(count <= MB_LEN_MAX);
295       mb_buf[count] = 0;
296       this->append(mb_buf);
297     }
298
299   Reader->SkipOffset(length*2);
300   return true;
301 }
302
303 //
304 bool
305 ASDCP::MXF::UTF16String::Archive(Kumu::MemIOWriter* Writer) const
306 {
307   if ( size() > IdentBufferLen )
308     {
309       DefaultLogSink().Error("String length exceeds maximum %u bytes\n", IdentBufferLen);
310       return false;
311     }
312
313   const char* mbp = c_str();
314   wchar_t wcp;
315   ui32_t remainder = size();
316   ui32_t length = size();
317   ui32_t i = 0;
318
319   while ( i < length )
320     {
321       int count = mbtowc(&wcp, mbp+i, remainder);
322
323       if ( count == -1 )
324         {
325           DefaultLogSink().Error("Error decoding multi-byte sequence starting at offset %u\n", i);
326           return false;
327         }
328       else if ( count  == 0 )
329         {
330           break;
331         }
332
333       bool result = Writer->WriteUi16BE((ui16_t)wcp);
334
335       if ( result == false )
336         {
337           DefaultLogSink().Error("No more space in memory IO writer\n");
338           return false;
339         }
340
341       i += count;
342       remainder -= count;
343     }
344
345   return true;
346 }
347
348 //------------------------------------------------------------------------------------------
349 //
350
351 //
352 ASDCP::MXF::ISO8String::ISO8String(const char* sz)
353 {
354   if ( sz != 0 && *sz != 0 )
355     {
356       this->assign(sz);
357     }
358 }
359
360 ASDCP::MXF::ISO8String::ISO8String(const std::string& str)
361 {
362   this->assign(str);
363 }
364
365
366 //
367 const ASDCP::MXF::ISO8String&
368 ASDCP::MXF::ISO8String::operator=(const char* sz)
369 {
370   if ( sz == 0 || *sz == 0 )
371     erase();
372
373   else
374     this->assign(sz);
375   
376   return *this;
377 }
378
379 //
380 const ASDCP::MXF::ISO8String&
381 ASDCP::MXF::ISO8String::operator=(const std::string& str)
382 {
383   this->assign(str);
384   return *this;
385 }
386
387 //
388 const char*
389 ASDCP::MXF::ISO8String::EncodeString(char* str_buf, ui32_t buf_len) const
390 {
391   ui32_t write_len = Kumu::xmin(buf_len - 1, (ui32_t)size());
392   strncpy(str_buf, c_str(), write_len);
393   str_buf[write_len] = 0;
394   return str_buf;
395 }
396
397 //
398 bool
399 ASDCP::MXF::ISO8String::Unarchive(Kumu::MemIOReader* Reader)
400 {
401   assign((char*)Reader->CurrentData(), Reader->Remainder());
402   return true;
403 }
404
405 //
406 bool
407 ASDCP::MXF::ISO8String::Archive(Kumu::MemIOWriter* Writer) const
408 {
409   if ( size() > IdentBufferLen )
410     {
411       DefaultLogSink().Error("String length exceeds maximum %u bytes\n", IdentBufferLen);
412       return false;
413     }
414
415   return Writer->WriteRaw((const byte_t*)c_str(), size());
416 }
417
418 //------------------------------------------------------------------------------------------
419 //
420
421 ASDCP::MXF::TLVReader::TLVReader(const byte_t* p, ui32_t c, IPrimerLookup* PrimerLookup) :
422   MemIOReader(p, c), m_Lookup(PrimerLookup)
423 {
424   Result_t result = RESULT_OK;
425
426   while ( Remainder() > 0 && ASDCP_SUCCESS(result) )
427     {
428       TagValue Tag;
429       ui16_t pkt_len = 0;
430
431       if ( MemIOReader::ReadUi8(&Tag.a) )
432         if ( MemIOReader::ReadUi8(&Tag.b) )
433           if ( MemIOReader::ReadUi16BE(&pkt_len) )
434             {
435               m_ElementMap.insert(TagMap::value_type(Tag, ItemInfo(m_size, pkt_len)));
436               if ( SkipOffset(pkt_len) )
437                 continue;;
438             }
439
440       DefaultLogSink().Error("Malformed Set\n");
441       m_ElementMap.clear();
442       result = RESULT_KLV_CODING(__LINE__, __FILE__);
443     }
444 }
445
446 //
447 bool
448 ASDCP::MXF::TLVReader::FindTL(const MDDEntry& Entry)
449 {
450   if ( m_Lookup == 0 )
451     {
452       DefaultLogSink().Error("No Lookup service\n");
453       return false;
454     }
455   
456   TagValue TmpTag;
457
458   if ( m_Lookup->TagForKey(Entry.ul, TmpTag) != RESULT_OK )
459     {
460       if ( Entry.tag.a == 0 )
461         {
462           //      DefaultLogSink().Debug("No such UL in this TL list: %s (%02x %02x)\n",
463           //                             Entry.name, Entry.tag.a, Entry.tag.b);
464           return false;
465         }
466
467       TmpTag = Entry.tag;
468     }
469
470   TagMap::iterator e_i = m_ElementMap.find(TmpTag);
471
472   if ( e_i != m_ElementMap.end() )
473     {
474       m_size = (*e_i).second.first;
475       m_capacity = m_size + (*e_i).second.second;
476       return true;
477     }
478
479   //  DefaultLogSink().Debug("Not Found (%02x %02x): %s\n", TmpTag.a, TmpTag.b, Entry.name);
480   return false;
481 }
482
483 //
484 ASDCP::Result_t
485 ASDCP::MXF::TLVReader::ReadObject(const MDDEntry& Entry, Kumu::IArchive* Object)
486 {
487   ASDCP_TEST_NULL(Object);
488
489   if ( FindTL(Entry) )
490     {
491       if ( m_size < m_capacity ) // don't try to unarchive an empty item
492         {
493           // TODO: carry on if uachive fails
494           return Object->Unarchive(this) ? RESULT_OK : RESULT_FALSE(__LINE__, __FILE__);
495         }
496     }
497
498   return RESULT_FALSE;
499 }
500
501 //
502 ASDCP::Result_t
503 ASDCP::MXF::TLVReader::ReadUi8(const MDDEntry& Entry, ui8_t* value)
504 {
505   ASDCP_TEST_NULL(value);
506
507   if ( FindTL(Entry) )
508     return MemIOReader::ReadUi8(value) ? RESULT_OK : RESULT_FALSE(__LINE__, __FILE__);
509
510   return RESULT_FALSE;
511 }
512
513 //
514 ASDCP::Result_t
515 ASDCP::MXF::TLVReader::ReadUi16(const MDDEntry& Entry, ui16_t* value)
516 {
517   ASDCP_TEST_NULL(value);
518
519   if ( FindTL(Entry) )
520     return MemIOReader::ReadUi16BE(value) ? RESULT_OK : RESULT_FALSE(__LINE__, __FILE__);
521
522   return RESULT_FALSE;
523 }
524
525 //
526 ASDCP::Result_t
527 ASDCP::MXF::TLVReader::ReadUi32(const MDDEntry& Entry, ui32_t* value)
528 {
529   ASDCP_TEST_NULL(value);
530
531   if ( FindTL(Entry) )
532     return MemIOReader::ReadUi32BE(value) ? RESULT_OK : RESULT_FALSE(__LINE__, __FILE__);
533
534   return RESULT_FALSE;
535 }
536
537 //
538 ASDCP::Result_t
539 ASDCP::MXF::TLVReader::ReadUi64(const MDDEntry& Entry, ui64_t* value)
540 {
541   ASDCP_TEST_NULL(value);
542
543   if ( FindTL(Entry) )
544     return MemIOReader::ReadUi64BE(value) ? RESULT_OK : RESULT_FALSE(__LINE__, __FILE__);
545
546   return RESULT_FALSE;
547 }
548
549 //------------------------------------------------------------------------------------------
550 //
551
552 ASDCP::MXF::TLVWriter::TLVWriter(byte_t* p, ui32_t c, IPrimerLookup* PrimerLookup) :
553   MemIOWriter(p, c), m_Lookup(PrimerLookup)
554 {
555   assert(c > 3);
556 }
557
558 //
559 ASDCP::Result_t
560 ASDCP::MXF::TLVWriter::WriteTag(const MDDEntry& Entry)
561 {
562   if ( m_Lookup == 0 )
563     {
564       DefaultLogSink().Error("No Primer object available\n");
565       return RESULT_FAIL;
566     }
567
568   TagValue TmpTag;
569
570   if ( m_Lookup->InsertTag(Entry, TmpTag) != RESULT_OK )
571     {
572       DefaultLogSink().Error("No tag for entry %s\n", Entry.name);
573       return RESULT_FAIL;
574     }
575
576   if ( ! MemIOWriter::WriteUi8(TmpTag.a) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
577   if ( ! MemIOWriter::WriteUi8(TmpTag.b) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
578   return RESULT_OK;
579 }
580
581 //
582 ASDCP::Result_t
583 ASDCP::MXF::TLVWriter::WriteObject(const MDDEntry& Entry, Kumu::IArchive* Object)
584 {
585   ASDCP_TEST_NULL(Object);
586
587   if ( Entry.optional && ! Object->HasValue() )
588     return RESULT_OK;
589
590   Result_t result = WriteTag(Entry);
591
592   if ( ASDCP_SUCCESS(result) )
593     {
594       // write a temp length
595       byte_t* l_p = CurrentData();
596
597       if ( ! MemIOWriter::WriteUi16BE(0) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
598
599       ui32_t before = Length();
600       if ( ! Object->Archive(this) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
601       if ( (Length() - before) > 0xffffL ) return RESULT_KLV_CODING(__LINE__, __FILE__);
602       Kumu::i2p<ui16_t>(KM_i16_BE(Length() - before), l_p);
603     }
604
605   return result;
606 }
607
608 //
609 ASDCP::Result_t
610 ASDCP::MXF::TLVWriter::WriteUi8(const MDDEntry& Entry, ui8_t* value)
611 {
612   ASDCP_TEST_NULL(value);
613   Result_t result = WriteTag(Entry);
614
615   if ( ASDCP_SUCCESS(result) )
616     {
617       if ( ! MemIOWriter::WriteUi16BE(sizeof(ui8_t)) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
618       if ( ! MemIOWriter::WriteUi8(*value) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
619     }
620   
621   return result;
622 }
623
624 //
625 ASDCP::Result_t
626 ASDCP::MXF::TLVWriter::WriteUi16(const MDDEntry& Entry, ui16_t* value)
627 {
628   ASDCP_TEST_NULL(value);
629   Result_t result = WriteTag(Entry);
630
631   if ( KM_SUCCESS(result) )
632     {
633       if ( ! MemIOWriter::WriteUi16BE(sizeof(ui16_t)) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
634       if ( ! MemIOWriter::WriteUi16BE(*value) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
635     }
636
637   return result;
638 }
639
640 //
641 ASDCP::Result_t
642 ASDCP::MXF::TLVWriter::WriteUi32(const MDDEntry& Entry, ui32_t* value)
643 {
644   ASDCP_TEST_NULL(value);
645   Result_t result = WriteTag(Entry);
646
647   if ( KM_SUCCESS(result) )
648     {
649       if ( ! MemIOWriter::WriteUi16BE(sizeof(ui32_t)) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
650       if ( ! MemIOWriter::WriteUi32BE(*value) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
651     }
652
653   return result;
654 }
655
656 //
657 ASDCP::Result_t
658 ASDCP::MXF::TLVWriter::WriteUi64(const MDDEntry& Entry, ui64_t* value)
659 {
660   ASDCP_TEST_NULL(value);
661   Result_t result = WriteTag(Entry);
662
663   if ( KM_SUCCESS(result) )
664     {
665       if ( ! MemIOWriter::WriteUi16BE(sizeof(ui64_t)) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
666       if ( ! MemIOWriter::WriteUi64BE(*value) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
667     }
668
669   return result;
670 }
671
672
673 //----------------------------------------------------------------------------------------------------
674 //
675
676
677 ASDCP::MXF::RGBALayout::RGBALayout()
678 {
679   memset(m_value, 0, RGBAValueLength);
680 }
681
682 ASDCP::MXF::RGBALayout::RGBALayout(const byte_t* value)
683 {
684   memcpy(m_value, value, RGBAValueLength);
685 }
686
687 ASDCP::MXF::RGBALayout::~RGBALayout()
688 {
689 }
690
691 static char
692 get_char_for_code(byte_t c)
693 {
694   for ( int i = 0; ASDCP::MXF::RGBALayoutTable[i].code != 0; ++i )
695     {
696       if ( ASDCP::MXF::RGBALayoutTable[i].code == c )
697         {
698           return ASDCP::MXF::RGBALayoutTable[i].symbol;
699         }
700     }
701
702   return '_';
703 }
704
705 //
706 const char*
707 ASDCP::MXF::RGBALayout::EncodeString(char* buf, ui32_t buf_len) const
708 {
709   std::string tmp_str;
710   char tmp_buf[64];
711
712   for ( size_t i = 0; i < RGBAValueLength && m_value[i] != 0; i += 2 )
713     {
714       snprintf(tmp_buf, 64, "%c(%d)", get_char_for_code(m_value[i]), m_value[i+1]);
715
716       if ( ! tmp_str.empty() )
717         {
718           tmp_str += " ";
719         }
720
721       tmp_str += tmp_buf;
722     }
723
724   assert(tmp_str.size() < buf_len);
725   strncpy(buf, tmp_str.c_str(), tmp_str.size());
726   return buf;
727 }
728
729
730 //----------------------------------------------------------------------------------------------------
731 //
732
733 ASDCP::MXF::Raw::Raw()
734 {
735   Capacity(256);
736 }
737
738 ASDCP::MXF::Raw::~Raw()
739 {
740 }
741
742 //
743 bool
744 ASDCP::MXF::Raw::Unarchive(Kumu::MemIOReader* Reader)
745 {
746   ui32_t payload_size = Reader->Remainder();
747   if ( payload_size == 0 ) return false;
748   if ( KM_FAILURE(Capacity(payload_size)) ) return false;
749
750   memcpy(Data(), Reader->CurrentData(), payload_size);
751   Length(payload_size);
752   return true;
753 }
754
755 //
756 bool
757 ASDCP::MXF::Raw::Archive(Kumu::MemIOWriter* Writer) const
758 {
759   return Writer->WriteRaw(RoData(), Length());
760 }
761
762 //
763 const char*
764 ASDCP::MXF::Raw::EncodeString(char* str_buf, ui32_t buf_len) const
765 {
766   *str_buf = 0;
767   Kumu::bin2hex(RoData(), Length(), str_buf, buf_len);
768   return str_buf;
769 }
770
771 //
772 // end MXFTypes.cpp
773 //