ginormo merge-back with Kumu, SMPTE MIC key and MPEG parser fix
[asdcplib.git] / src / MXFTypes.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    MXFTypes.cpp
28     \version $Id$
29     \brief   MXF objects
30 */
31
32 #include <KM_prng.h>
33 #include "MXFTypes.h"
34 #include <KM_log.h>
35 using Kumu::DefaultLogSink;
36
37 //------------------------------------------------------------------------------------------
38 //
39
40 const char*
41 ASDCP::UL::EncodeString(char* str_buf, ui32_t buf_len) const
42 {
43   if ( buf_len > 38 ) // room for dotted notation?
44     {
45       snprintf(str_buf, buf_len,
46                "%02x%02x%02x%02x.%02x%02x.%02x%02x.%02x%02x%02x%02x.%02x%02x%02x%02x",
47                m_Value[0],  m_Value[1],  m_Value[2],  m_Value[3],
48                m_Value[4],  m_Value[5],  m_Value[6],  m_Value[7],
49                m_Value[8],  m_Value[9],  m_Value[10], m_Value[11],
50                m_Value[12], m_Value[13], m_Value[14], m_Value[15]
51                );
52
53       return str_buf;
54     }
55   else if ( buf_len > 32 ) // room for compact?
56     {
57       snprintf(str_buf, buf_len,
58                "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
59                m_Value[0],  m_Value[1],  m_Value[2],  m_Value[3],
60                m_Value[4],  m_Value[5],  m_Value[6],  m_Value[7],
61                m_Value[8],  m_Value[9],  m_Value[10], m_Value[11],
62                m_Value[12], m_Value[13], m_Value[14], m_Value[15]
63                );
64
65       return str_buf;
66     }
67
68   return 0;
69 }
70
71 //
72 void
73 ASDCP::UMID::MakeUMID(int Type)
74 {
75   UUID AssetID;
76   Kumu::GenRandomValue(AssetID);
77   MakeUMID(Type, AssetID);
78 }
79
80 //
81 void
82 ASDCP::UMID::MakeUMID(int Type, const UUID& AssetID)
83 {
84   // Set the non-varying base of the UMID
85   static const byte_t UMIDBase[10] = { 0x06, 0x0a, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
86   memcpy(m_Value, UMIDBase, 10);
87   m_Value[10] = Type;  // Material Type
88   m_Value[12] = 0x13;  // length
89
90   // preserved for compatibility with mfxlib
91   if( Type > 4 ) m_Value[7] = 5;
92   m_Value[11] = 0x20; // UUID/UL method, number gen undefined
93
94   // Instance Number
95   m_Value[13] = m_Value[14] = m_Value[15] = 0;
96   
97   memcpy(&m_Value[16], AssetID.Value(), AssetID.Size());
98 }
99
100
101 // Write the timestamp value to the given buffer in the form 2004-05-01 13:20:00.000
102 // returns 0 if the buffer is smaller than DateTimeLen
103 const char*
104 ASDCP::UMID::EncodeString(char* str_buf, ui32_t buf_len) const
105 {
106   assert(str_buf);
107
108   snprintf(str_buf, buf_len, "[%02x%02x%02x%02x.%02x%02x.%02x%02x.%02x%02x%02x%02x],%02x,%02x,%02x,%02x,",
109            m_Value[0],  m_Value[1],  m_Value[2],  m_Value[3],
110            m_Value[4],  m_Value[5],  m_Value[6],  m_Value[7],
111            m_Value[8],  m_Value[9],  m_Value[10], m_Value[11],
112            m_Value[12], m_Value[13], m_Value[14], m_Value[15]
113            );
114
115   ui32_t offset = strlen(str_buf);
116
117   if ( ( m_Value[8] & 0x80 ) == 0 )
118     {
119       // half-swapped UL, use [bbaa9988.ddcc.ffee.00010203.04050607]
120       snprintf(str_buf + offset, buf_len - offset,
121                "[%02x%02x%02x%02x.%02x%02x.%02x%02x.%02x%02x%02x%02x.%02x%02x%02x%02x]",
122                m_Value[24], m_Value[25], m_Value[26], m_Value[27],
123                m_Value[28], m_Value[29], m_Value[30], m_Value[31],
124                m_Value[16], m_Value[17], m_Value[18], m_Value[19],
125                m_Value[20], m_Value[21], m_Value[22], m_Value[23]
126                );
127     }
128   else
129     {
130       // UUID, use {00112233-4455-6677-8899-aabbccddeeff}
131       snprintf(str_buf + offset, buf_len - offset,
132                "{%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
133                m_Value[16], m_Value[17], m_Value[18], m_Value[19],
134                m_Value[20], m_Value[21], m_Value[22], m_Value[23],
135                m_Value[24], m_Value[25], m_Value[26], m_Value[27],
136                m_Value[28], m_Value[29], m_Value[30], m_Value[31]
137                );
138     }
139
140   return str_buf;
141 }
142
143 //------------------------------------------------------------------------------------------
144 //
145
146 const ASDCP::MXF::UTF16String&
147 ASDCP::MXF::UTF16String::operator=(const char* sz)
148 {
149   if ( sz == 0 || *sz == 0 )
150     {
151       m_length = 0;
152       *m_buffer = 0;
153     }
154   else
155     {
156       ui32_t len = Kumu::xmin((ui32_t)strlen(sz), (IdentBufferLen - 1));
157       m_length = len;
158       memcpy(m_buffer, sz, m_length);
159       m_buffer[m_length] = 0;
160     }
161   
162   return *this;
163 }
164
165
166 //
167 bool
168 ASDCP::MXF::UTF16String::Unarchive(Kumu::MemIOReader* Reader)
169 {
170   const byte_t* p = Reader->CurrentData();
171   m_length = Reader->Remainder();
172   assert(m_length % 2 == 0);
173   m_length /= 2;
174   assert(IdentBufferLen >= m_length);
175   ui32_t i = 0;
176
177   for ( i = 0; i < m_length; i++ )
178     m_buffer[i] = p[(i*2)+1];
179
180   m_buffer[i] = 0;
181
182   Reader->SkipOffset(m_length*2);
183   return true;
184 }
185
186 //
187 bool
188 ASDCP::MXF::UTF16String::Archive(Kumu::MemIOWriter* Writer) const
189 {
190   byte_t* p = Writer->Data() + Writer->Length();
191   ui32_t i = 0;
192   memset(p, 0, (m_length*2)+2);
193
194   for ( i = 0; i < m_length; i++ )
195     p[(i*2)+1] = m_buffer[i];
196
197   Writer->AddOffset(m_length * 2);
198   return true;
199 }
200
201
202 //------------------------------------------------------------------------------------------
203 //
204
205 #ifdef WIN32
206
207 #define TIMESTAMP_TO_SYSTIME(ts, t) \
208   (t)->wYear    = (ts).Year;   /* year */ \
209   (t)->wMonth   = (ts).Month;  /* month of year (1 - 12) */ \
210   (t)->wDay     = (ts).Day;    /* day of month (1 - 31) */ \
211   (t)->wHour    = (ts).Hour;   /* hours (0 - 23) */ \
212   (t)->wMinute  = (ts).Minute; /* minutes (0 - 59) */ \
213   (t)->wSecond  = (ts).Second; /* seconds (0 - 60) */ \
214   (t)->wDayOfWeek = 0; \
215   (t)->wMilliseconds = ((ts).Tick * 4);
216
217 #define SYSTIME_TO_TIMESTAMP(t, ts) \
218   (ts).Year   = (t)->wYear;    /* year */ \
219   (ts).Month  = (t)->wMonth;   /* month of year (1 - 12) */ \
220   (ts).Day    = (t)->wDay;     /* day of month (1 - 31) */ \
221   (ts).Hour   = (t)->wHour;    /* hours (0 - 23) */ \
222   (ts).Minute = (t)->wMinute;  /* minutes (0 - 59) */ \
223   (ts).Second = (t)->wSecond;  /* seconds (0 - 60) */ \
224   (ts).Tick   = (t)->wMilliseconds / 4;
225
226 //
227 ASDCP::MXF::Timestamp::Timestamp() :
228   Year(0), Month(0),  Day(0), Hour(0), Minute(0), Second(0), Tick(0)
229 {
230   SYSTEMTIME sys_time;
231   GetSystemTime(&sys_time);
232   SYSTIME_TO_TIMESTAMP(&sys_time, *this);
233 }
234
235 //
236 bool
237 ASDCP::MXF::Timestamp::operator<(const Timestamp& rhs) const
238 {
239   SYSTEMTIME lhst, rhst;
240   FILETIME lft, rft;
241
242   TIMESTAMP_TO_SYSTIME(*this, &lhst);
243   TIMESTAMP_TO_SYSTIME(rhs, &rhst);
244   SystemTimeToFileTime(&lhst, &lft);
245   SystemTimeToFileTime(&rhst, &rft);
246   return ( CompareFileTime(&lft, &rft) == -1 );
247 }
248
249 inline ui64_t
250 seconds_to_ns100(ui32_t seconds)
251 {
252   return ((ui64_t)seconds * 10000000);
253 }
254
255 //
256 void
257 ASDCP::MXF::Timestamp::AddDays(i32_t days)
258 {
259   SYSTEMTIME current_st;
260   FILETIME current_ft;
261   ULARGE_INTEGER current_ul;
262
263   if ( days != 0 )
264     {
265       TIMESTAMP_TO_SYSTIME(*this, &current_st);
266       SystemTimeToFileTime(&current_st, &current_ft);
267       memcpy(&current_ul, &current_ft, sizeof(current_ul));
268       current_ul.QuadPart += ( seconds_to_ns100(86400) * (ui64_t)days );
269       memcpy(&current_ft, &current_ul, sizeof(current_ft));
270       FileTimeToSystemTime(&current_ft, &current_st);
271       SYSTIME_TO_TIMESTAMP(&current_st, *this);
272     }
273 }
274
275 //
276 void
277 ASDCP::MXF::Timestamp::AddHours(i32_t hours)
278 {
279   SYSTEMTIME current_st;
280   FILETIME current_ft;
281   ULARGE_INTEGER current_ul;
282
283   if ( hours != 0 )
284     {
285       TIMESTAMP_TO_SYSTIME(*this, &current_st);
286       SystemTimeToFileTime(&current_st, &current_ft);
287       memcpy(&current_ul, &current_ft, sizeof(current_ul));
288       current_ul.QuadPart += ( seconds_to_ns100(3600) * (ui64_t)hours );
289       memcpy(&current_ft, &current_ul, sizeof(current_ft));
290       FileTimeToSystemTime(&current_ft, &current_st);
291       SYSTIME_TO_TIMESTAMP(&current_st, *this);
292     }
293 }
294
295 #else // KM_WIN32
296
297 #include <time.h>
298
299 #define TIMESTAMP_TO_TM(ts, t) \
300   (t)->tm_year = (ts).Year - 1900;   /* year - 1900 */ \
301   (t)->tm_mon  = (ts).Month - 1;     /* month of year (0 - 11) */ \
302   (t)->tm_mday = (ts).Day;           /* day of month (1 - 31) */ \
303   (t)->tm_hour = (ts).Hour;          /* hours (0 - 23) */ \
304   (t)->tm_min  = (ts).Minute;        /* minutes (0 - 59) */ \
305   (t)->tm_sec  = (ts).Second;        /* seconds (0 - 60) */
306
307 #define TM_TO_TIMESTAMP(t, ts) \
308   (ts).Year   = (t)->tm_year + 1900;    /* year - 1900 */ \
309   (ts).Month  = (t)->tm_mon + 1;     /* month of year (0 - 11) */ \
310   (ts).Day    = (t)->tm_mday;    /* day of month (1 - 31) */ \
311   (ts).Hour   = (t)->tm_hour;    /* hours (0 - 23) */ \
312   (ts).Minute = (t)->tm_min;     /* minutes (0 - 59) */ \
313   (ts).Second = (t)->tm_sec;     /* seconds (0 - 60) */
314
315 //
316 ASDCP::MXF::Timestamp::Timestamp() :
317   Year(0), Month(0),  Day(0), Hour(0), Minute(0), Second(0)
318 {
319   time_t t_now = time(0);
320   struct tm*  now = gmtime(&t_now);
321   TM_TO_TIMESTAMP(now, *this);
322 }
323
324 //
325 bool
326 ASDCP::MXF::Timestamp::operator<(const Timestamp& rhs) const
327 {
328   struct tm lhtm, rhtm;
329   TIMESTAMP_TO_TM(*this, &lhtm);
330   TIMESTAMP_TO_TM(rhs, &rhtm);
331   return ( timegm(&lhtm) < timegm(&rhtm) );
332 }
333
334 //
335 void
336 ASDCP::MXF::Timestamp::AddDays(i32_t days)
337 {
338   struct tm current;
339
340   if ( days != 0 )
341     {
342       TIMESTAMP_TO_TM(*this, &current);
343       time_t adj_time = timegm(&current);
344       adj_time += 86400 * days;
345       struct tm*  now = gmtime(&adj_time);
346       TM_TO_TIMESTAMP(now, *this);
347     }
348 }
349
350 //
351 void
352 ASDCP::MXF::Timestamp::AddHours(i32_t hours)
353 {
354   struct tm current;
355
356   if ( hours != 0 )
357     {
358       TIMESTAMP_TO_TM(*this, &current);
359       time_t adj_time = timegm(&current);
360       adj_time += 3600 * hours;
361       struct tm*  now = gmtime(&adj_time);
362       TM_TO_TIMESTAMP(now, *this);
363     }
364 }
365
366 #endif // KM_WIN32
367
368
369 ASDCP::MXF::Timestamp::Timestamp(const Timestamp& rhs)
370 {
371   Year   = rhs.Year;
372   Month  = rhs.Month;
373   Day    = rhs.Day;
374   Hour   = rhs.Hour;
375   Minute = rhs.Minute;
376   Second = rhs.Second;
377 }
378
379 ASDCP::MXF::Timestamp::~Timestamp()
380 {
381 }
382
383 //
384 const ASDCP::MXF::Timestamp&
385 ASDCP::MXF::Timestamp::operator=(const Timestamp& rhs)
386 {
387   Year   = rhs.Year;
388   Month  = rhs.Month;
389   Day    = rhs.Day;
390   Hour   = rhs.Hour;
391   Minute = rhs.Minute;
392   Second = rhs.Second;
393   return *this;
394 }
395
396 //
397 bool
398 ASDCP::MXF::Timestamp::operator==(const Timestamp& rhs) const
399 {
400   if ( Year == rhs.Year
401        && Month  == rhs.Month
402        && Day    == rhs.Day
403        && Hour   == rhs.Hour
404        && Minute == rhs.Minute
405        && Second == rhs.Second )
406     return true;
407
408   return false;
409 }
410
411 //
412 bool
413 ASDCP::MXF::Timestamp::operator!=(const Timestamp& rhs) const
414 {
415   if ( Year != rhs.Year
416        || Month  != rhs.Month
417        || Day    != rhs.Day
418        || Hour   != rhs.Hour
419        || Minute != rhs.Minute
420        || Second != rhs.Second )
421     return true;
422
423   return false;
424 }
425
426 //
427 const char*
428 ASDCP::MXF::Timestamp::EncodeString(char* str_buf, ui32_t buf_len) const
429 {
430   // 2004-05-01 13:20:00.000
431   snprintf(str_buf, buf_len,
432            "%04hu-%02hu-%02hu %02hu:%02hu:%02hu.000",
433            Year, Month, Day, Hour, Minute, Second, Tick);
434   
435   return str_buf;
436 }
437
438 //------------------------------------------------------------------------------------------
439 //
440
441 ASDCP::MXF::TLVReader::TLVReader(const byte_t* p, ui32_t c, IPrimerLookup* PrimerLookup) :
442   MemIOReader(p, c), m_Lookup(PrimerLookup)
443 {
444   Result_t result = RESULT_OK;
445
446   while ( Remainder() > 0 && ASDCP_SUCCESS(result) )
447     {
448       TagValue Tag;
449       ui16_t pkt_len = 0;
450
451       if ( MemIOReader::ReadUi8(&Tag.a) )
452         if ( MemIOReader::ReadUi8(&Tag.b) )
453           if ( MemIOReader::ReadUi16BE(&pkt_len) )
454             {
455               m_ElementMap.insert(TagMap::value_type(Tag, ItemInfo(m_size, pkt_len)));
456               if ( SkipOffset(pkt_len) )
457                 continue;;
458             }
459
460       DefaultLogSink().Error("Malformed Set\n");
461       m_ElementMap.clear();
462       result = RESULT_KLV_CODING;
463     }
464 }
465
466 //
467 bool
468 ASDCP::MXF::TLVReader::FindTL(const MDDEntry& Entry)
469 {
470   if ( m_Lookup == 0 )
471     {
472       DefaultLogSink().Error("No Lookup service\n");
473       return false;
474     }
475   
476   TagValue TmpTag;
477
478   if ( m_Lookup->TagForKey(Entry.ul, TmpTag) != RESULT_OK )
479     {
480       if ( Entry.tag.a == 0 )
481         {
482           //      DefaultLogSink().Debug("No such UL in this TL list: %s (%02x %02x)\n",
483           //                             Entry.name, Entry.tag.a, Entry.tag.b);
484           return false;
485         }
486
487       TmpTag = Entry.tag;
488     }
489
490   TagMap::iterator e_i = m_ElementMap.find(TmpTag);
491
492   if ( e_i != m_ElementMap.end() )
493     {
494       m_size = (*e_i).second.first;
495       m_capacity = m_size + (*e_i).second.second;
496       return true;
497     }
498
499   //  DefaultLogSink().Debug("Not Found (%02x %02x): %s\n", TmpTag.a, TmpTag.b, Entry.name);
500   return false;
501 }
502
503 //
504 ASDCP::Result_t
505 ASDCP::MXF::TLVReader::ReadObject(const MDDEntry& Entry, Kumu::IArchive* Object)
506 {
507   ASDCP_TEST_NULL(Object);
508
509   if ( FindTL(Entry) )
510     {
511       if ( m_size < m_capacity ) // don't try to unarchive an empty item
512         return Object->Unarchive(this) ? RESULT_OK : RESULT_KLV_CODING;
513     }
514
515   return RESULT_FALSE;
516 }
517
518 //
519 ASDCP::Result_t
520 ASDCP::MXF::TLVReader::ReadUi8(const MDDEntry& Entry, ui8_t* value)
521 {
522   ASDCP_TEST_NULL(value);
523
524   if ( FindTL(Entry) )
525     return MemIOReader::ReadUi8(value) ? RESULT_OK : RESULT_KLV_CODING;
526
527   return RESULT_FALSE;
528 }
529
530 //
531 ASDCP::Result_t
532 ASDCP::MXF::TLVReader::ReadUi16(const MDDEntry& Entry, ui16_t* value)
533 {
534   ASDCP_TEST_NULL(value);
535
536   if ( FindTL(Entry) )
537     return MemIOReader::ReadUi16BE(value) ? RESULT_OK : RESULT_KLV_CODING;
538
539   return RESULT_FALSE;
540 }
541
542 //
543 ASDCP::Result_t
544 ASDCP::MXF::TLVReader::ReadUi32(const MDDEntry& Entry, ui32_t* value)
545 {
546   ASDCP_TEST_NULL(value);
547
548   if ( FindTL(Entry) )
549     return MemIOReader::ReadUi32BE(value) ? RESULT_OK : RESULT_KLV_CODING;
550
551   return RESULT_FALSE;
552 }
553
554 //
555 ASDCP::Result_t
556 ASDCP::MXF::TLVReader::ReadUi64(const MDDEntry& Entry, ui64_t* value)
557 {
558   ASDCP_TEST_NULL(value);
559
560   if ( FindTL(Entry) )
561     return MemIOReader::ReadUi64BE(value) ? RESULT_OK : RESULT_KLV_CODING;
562
563   return RESULT_FALSE;
564 }
565
566 //------------------------------------------------------------------------------------------
567 //
568
569 ASDCP::MXF::TLVWriter::TLVWriter(byte_t* p, ui32_t c, IPrimerLookup* PrimerLookup) :
570   MemIOWriter(p, c), m_Lookup(PrimerLookup)
571 {
572   assert(c > 3);
573 }
574
575 //
576 ASDCP::Result_t
577 ASDCP::MXF::TLVWriter::WriteTag(const MDDEntry& Entry)
578 {
579   if ( m_Lookup == 0 )
580     {
581       DefaultLogSink().Error("No Primer object available\n");
582       return RESULT_FAIL;
583     }
584
585   TagValue TmpTag;
586
587   if ( m_Lookup->InsertTag(Entry, TmpTag) != RESULT_OK )
588     {
589       DefaultLogSink().Error("No tag for entry %s\n", Entry.name);
590       return RESULT_FAIL;
591     }
592
593   if ( ! MemIOWriter::WriteUi8(TmpTag.a) ) return RESULT_KLV_CODING;
594   if ( ! MemIOWriter::WriteUi8(TmpTag.b) ) return RESULT_KLV_CODING;
595   return RESULT_OK;
596 }
597
598 //
599 ASDCP::Result_t
600 ASDCP::MXF::TLVWriter::WriteObject(const MDDEntry& Entry, Kumu::IArchive* Object)
601 {
602   ASDCP_TEST_NULL(Object);
603
604   if ( Entry.optional && ! Object->HasValue() )
605     return RESULT_OK;
606
607   Result_t result = WriteTag(Entry);
608
609   // write a temp length
610   byte_t* l_p = CurrentData();
611
612   if ( ! MemIOWriter::WriteUi16BE(0) ) return RESULT_KLV_CODING;
613
614   ui32_t before = Length();
615   if ( ! Object->Archive(this) ) return RESULT_KLV_CODING;
616   Kumu::i2p<ui16_t>(KM_i16_BE( Length() - before), l_p);
617   return RESULT_OK;
618 }
619
620 //
621 ASDCP::Result_t
622 ASDCP::MXF::TLVWriter::WriteUi8(const MDDEntry& Entry, ui8_t* value)
623 {
624   ASDCP_TEST_NULL(value);
625   Result_t result = WriteTag(Entry);
626
627   if ( ASDCP_SUCCESS(result) )
628     {
629       if ( ! MemIOWriter::WriteUi16BE(sizeof(ui8_t)) ) return RESULT_KLV_CODING;
630       if ( ! MemIOWriter::WriteUi8(*value) ) return RESULT_KLV_CODING;
631     }
632   
633   return result;
634 }
635
636 //
637 ASDCP::Result_t
638 ASDCP::MXF::TLVWriter::WriteUi16(const MDDEntry& Entry, ui16_t* value)
639 {
640   ASDCP_TEST_NULL(value);
641   Result_t result = WriteTag(Entry);
642
643   if ( KM_SUCCESS(result) )
644     {
645       if ( ! MemIOWriter::WriteUi16BE(sizeof(ui16_t)) ) return RESULT_KLV_CODING;
646       if ( ! MemIOWriter::WriteUi16BE(*value) ) return RESULT_KLV_CODING;
647     }
648
649   return result;
650 }
651
652 //
653 ASDCP::Result_t
654 ASDCP::MXF::TLVWriter::WriteUi32(const MDDEntry& Entry, ui32_t* value)
655 {
656   ASDCP_TEST_NULL(value);
657   Result_t result = WriteTag(Entry);
658
659   if ( KM_SUCCESS(result) )
660     {
661       if ( ! MemIOWriter::WriteUi16BE(sizeof(ui32_t)) ) return RESULT_KLV_CODING;
662       if ( ! MemIOWriter::WriteUi32BE(*value) ) return RESULT_KLV_CODING;
663     }
664
665   return result;
666 }
667
668 //
669 ASDCP::Result_t
670 ASDCP::MXF::TLVWriter::WriteUi64(const MDDEntry& Entry, ui64_t* value)
671 {
672   ASDCP_TEST_NULL(value);
673   Result_t result = WriteTag(Entry);
674
675   if ( KM_SUCCESS(result) )
676     {
677       if ( ! MemIOWriter::WriteUi16BE(sizeof(ui64_t)) ) return RESULT_KLV_CODING;
678       if ( ! MemIOWriter::WriteUi64BE(*value) ) return RESULT_KLV_CODING;
679     }
680
681   return result;
682 }
683
684
685 //----------------------------------------------------------------------------------------------------
686 //
687
688 ASDCP::MXF::Raw::Raw()
689 {
690   Capacity(256);
691 }
692
693 ASDCP::MXF::Raw::~Raw()
694 {
695 }
696
697 //
698 bool
699 ASDCP::MXF::Raw::Unarchive(Kumu::MemIOReader* Reader)
700 {
701   ui32_t payload_size = Reader->Remainder();
702   if ( payload_size == 0 ) return false;
703   if ( KM_FAILURE(Capacity(payload_size)) ) return false;
704
705   memcpy(Data(), Reader->CurrentData(), payload_size);
706   Length(payload_size);
707   return true;
708 }
709
710 //
711 bool
712 ASDCP::MXF::Raw::Archive(Kumu::MemIOWriter* Writer) const
713 {
714   return Writer->WriteRaw(RoData(), Length());
715 }
716
717 //
718 const char*
719 ASDCP::MXF::Raw::EncodeString(char* str_buf, ui32_t buf_len) const
720 {
721   *str_buf = 0;
722   Kumu::bin2hex(RoData(), Length(), str_buf, buf_len);
723   return str_buf;
724 }
725
726 //
727 // end MXFTypes.cpp
728 //