build fixes from DTS
[asdcplib.git] / src / MXFTypes.cpp
1 /*
2 Copyright (c) 2005-2008, 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
36 using Kumu::DefaultLogSink;
37
38 //------------------------------------------------------------------------------------------
39 //
40
41 const char*
42 ASDCP::UL::EncodeString(char* str_buf, ui32_t buf_len) const
43 {
44   if ( buf_len > 38 ) // room for dotted notation?
45     {
46       snprintf(str_buf, buf_len,
47                "%02x%02x%02x%02x.%02x%02x.%02x%02x.%02x%02x%02x%02x.%02x%02x%02x%02x",
48                m_Value[0],  m_Value[1],  m_Value[2],  m_Value[3],
49                m_Value[4],  m_Value[5],  m_Value[6],  m_Value[7],
50                m_Value[8],  m_Value[9],  m_Value[10], m_Value[11],
51                m_Value[12], m_Value[13], m_Value[14], m_Value[15]
52                );
53
54       return str_buf;
55     }
56   else if ( buf_len > 32 ) // room for compact?
57     {
58       snprintf(str_buf, buf_len,
59                "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
60                m_Value[0],  m_Value[1],  m_Value[2],  m_Value[3],
61                m_Value[4],  m_Value[5],  m_Value[6],  m_Value[7],
62                m_Value[8],  m_Value[9],  m_Value[10], m_Value[11],
63                m_Value[12], m_Value[13], m_Value[14], m_Value[15]
64                );
65
66       return str_buf;
67     }
68
69   return 0;
70 }
71
72 //
73 void
74 ASDCP::UMID::MakeUMID(int Type)
75 {
76   UUID AssetID;
77   Kumu::GenRandomValue(AssetID);
78   MakeUMID(Type, AssetID);
79 }
80
81 //
82 void
83 ASDCP::UMID::MakeUMID(int Type, const UUID& AssetID)
84 {
85   // Set the non-varying base of the UMID
86   static const byte_t UMIDBase[10] = { 0x06, 0x0a, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
87   memcpy(m_Value, UMIDBase, 10);
88   m_Value[10] = Type;  // Material Type
89   m_Value[12] = 0x13;  // length
90
91   // preserved for compatibility with mfxlib
92   if( Type > 4 ) m_Value[7] = 5;
93   m_Value[11] = 0x20; // UUID/UL method, number gen undefined
94
95   // Instance Number
96   m_Value[13] = m_Value[14] = m_Value[15] = 0;
97   
98   memcpy(&m_Value[16], AssetID.Value(), AssetID.Size());
99   m_HasValue = true;
100 }
101
102
103 // Write the timestamp value to the given buffer in the form 2004-05-01 13:20:00.000
104 // returns 0 if the buffer is smaller than DateTimeLen
105 const char*
106 ASDCP::UMID::EncodeString(char* str_buf, ui32_t buf_len) const
107 {
108   assert(str_buf);
109
110   snprintf(str_buf, buf_len, "[%02x%02x%02x%02x.%02x%02x.%02x%02x.%02x%02x%02x%02x],%02x,%02x,%02x,%02x,",
111            m_Value[0],  m_Value[1],  m_Value[2],  m_Value[3],
112            m_Value[4],  m_Value[5],  m_Value[6],  m_Value[7],
113            m_Value[8],  m_Value[9],  m_Value[10], m_Value[11],
114            m_Value[12], m_Value[13], m_Value[14], m_Value[15]
115            );
116
117   ui32_t offset = strlen(str_buf);
118
119   if ( ( m_Value[8] & 0x80 ) == 0 )
120     {
121       // half-swapped UL, use [bbaa9988.ddcc.ffee.00010203.04050607]
122       snprintf(str_buf + offset, buf_len - offset,
123                "[%02x%02x%02x%02x.%02x%02x.%02x%02x.%02x%02x%02x%02x.%02x%02x%02x%02x]",
124                m_Value[24], m_Value[25], m_Value[26], m_Value[27],
125                m_Value[28], m_Value[29], m_Value[30], m_Value[31],
126                m_Value[16], m_Value[17], m_Value[18], m_Value[19],
127                m_Value[20], m_Value[21], m_Value[22], m_Value[23]
128                );
129     }
130   else
131     {
132       // UUID, use {00112233-4455-6677-8899-aabbccddeeff}
133       snprintf(str_buf + offset, buf_len - offset,
134                "{%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
135                m_Value[16], m_Value[17], m_Value[18], m_Value[19],
136                m_Value[20], m_Value[21], m_Value[22], m_Value[23],
137                m_Value[24], m_Value[25], m_Value[26], m_Value[27],
138                m_Value[28], m_Value[29], m_Value[30], m_Value[31]
139                );
140     }
141
142   return str_buf;
143 }
144
145 //------------------------------------------------------------------------------------------
146 //
147
148 //
149 const ASDCP::MXF::UTF16String&
150 ASDCP::MXF::UTF16String::operator=(const char* sz)
151 {
152   if ( sz == 0 || *sz == 0 )
153     erase();
154
155   else
156     this->assign(sz);
157   
158   return *this;
159 }
160
161 //
162 const ASDCP::MXF::UTF16String&
163 ASDCP::MXF::UTF16String::operator=(const std::string& str)
164 {
165   this->assign(str);
166   return *this;
167 }
168
169 //
170 const char*
171 ASDCP::MXF::UTF16String::EncodeString(char* str_buf, ui32_t buf_len) const
172 {
173   ui32_t write_len = Kumu::xmin(buf_len - 1, (ui32_t)size());
174   strncpy(str_buf, c_str(), write_len);
175   str_buf[write_len] = 0;
176   return str_buf;
177 }
178
179 //
180 bool
181 ASDCP::MXF::UTF16String::Unarchive(Kumu::MemIOReader* Reader)
182 {
183   erase();
184   const ui16_t* p = (ui16_t*)Reader->CurrentData();
185   ui32_t length = Reader->Remainder() / 2;
186   char mb_buf[MB_LEN_MAX+1];
187
188   for ( ui32_t i = 0; i < length; i++ )
189     {
190       int count = wctomb(mb_buf, KM_i16_BE(p[i]));
191
192       if ( count == -1 )
193         {
194           DefaultLogSink().Error("Unable to decode wide character 0x%04hx\n", p[i]);
195           return false;
196         }
197
198       assert(count <= MB_LEN_MAX);
199       mb_buf[count] = 0;
200       this->append(mb_buf);
201     }
202
203   Reader->SkipOffset(length*2);
204   return true;
205 }
206
207 //
208 bool
209 ASDCP::MXF::UTF16String::Archive(Kumu::MemIOWriter* Writer) const
210 {
211   if ( size() > IdentBufferLen )
212     {
213       DefaultLogSink().Error("String length exceeds maximum %u bytes\n", IdentBufferLen);
214       return false;
215     }
216
217   const char* mbp = c_str();
218   wchar_t wcp;
219   ui32_t remainder = size();
220   ui32_t length = size();
221   ui32_t i = 0;
222
223   while ( i < length )
224     {
225       int count = mbtowc(&wcp, mbp+i, remainder);
226
227       if ( count == -1 )
228         {
229           DefaultLogSink().Error("Error decoding multi-byte sequence starting at offset %u\n", i);
230           return false;
231         }
232       else if ( count  == 0 )
233         break;
234
235       bool result = Writer->WriteUi16BE((ui16_t)wcp);
236
237       if ( result == false )
238         {
239           DefaultLogSink().Error("No more space in memory IO writer\n");
240           return false;
241         }
242
243       i += count;
244       remainder -= count;
245     }
246
247   return true;
248 }
249
250
251 //------------------------------------------------------------------------------------------
252 //
253
254 #ifdef WIN32
255
256 #define TIMESTAMP_TO_SYSTIME(ts, t) \
257   (t)->wYear    = (ts).Year;   /* year */ \
258   (t)->wMonth   = (ts).Month;  /* month of year (1 - 12) */ \
259   (t)->wDay     = (ts).Day;    /* day of month (1 - 31) */ \
260   (t)->wHour    = (ts).Hour;   /* hours (0 - 23) */ \
261   (t)->wMinute  = (ts).Minute; /* minutes (0 - 59) */ \
262   (t)->wSecond  = (ts).Second; /* seconds (0 - 60) */ \
263   (t)->wDayOfWeek = 0; \
264   (t)->wMilliseconds = ((ts).Tick * 4);
265
266 #define SYSTIME_TO_TIMESTAMP(t, ts) \
267   (ts).Year   = (t)->wYear;    /* year */ \
268   (ts).Month  = (t)->wMonth;   /* month of year (1 - 12) */ \
269   (ts).Day    = (t)->wDay;     /* day of month (1 - 31) */ \
270   (ts).Hour   = (t)->wHour;    /* hours (0 - 23) */ \
271   (ts).Minute = (t)->wMinute;  /* minutes (0 - 59) */ \
272   (ts).Second = (t)->wSecond;  /* seconds (0 - 60) */ \
273   (ts).Tick   = (t)->wMilliseconds / 4;
274
275 //
276 ASDCP::MXF::Timestamp::Timestamp() :
277   Year(0), Month(0),  Day(0), Hour(0), Minute(0), Second(0), Tick(0)
278 {
279   SYSTEMTIME sys_time;
280   GetSystemTime(&sys_time);
281   SYSTIME_TO_TIMESTAMP(&sys_time, *this);
282 }
283
284 //
285 bool
286 ASDCP::MXF::Timestamp::operator<(const Timestamp& rhs) const
287 {
288   SYSTEMTIME lhst, rhst;
289   FILETIME lft, rft;
290
291   TIMESTAMP_TO_SYSTIME(*this, &lhst);
292   TIMESTAMP_TO_SYSTIME(rhs, &rhst);
293   SystemTimeToFileTime(&lhst, &lft);
294   SystemTimeToFileTime(&rhst, &rft);
295   return ( CompareFileTime(&lft, &rft) == -1 );
296 }
297
298 inline ui64_t
299 seconds_to_ns100(ui32_t seconds)
300 {
301   return ((ui64_t)seconds * 10000000);
302 }
303
304 //
305 void
306 ASDCP::MXF::Timestamp::AddDays(i32_t days)
307 {
308   SYSTEMTIME current_st;
309   FILETIME current_ft;
310   ULARGE_INTEGER current_ul;
311
312   if ( days != 0 )
313     {
314       TIMESTAMP_TO_SYSTIME(*this, &current_st);
315       SystemTimeToFileTime(&current_st, &current_ft);
316       memcpy(&current_ul, &current_ft, sizeof(current_ul));
317       current_ul.QuadPart += ( seconds_to_ns100(86400) * (ui64_t)days );
318       memcpy(&current_ft, &current_ul, sizeof(current_ft));
319       FileTimeToSystemTime(&current_ft, &current_st);
320       SYSTIME_TO_TIMESTAMP(&current_st, *this);
321     }
322 }
323
324 //
325 void
326 ASDCP::MXF::Timestamp::AddHours(i32_t hours)
327 {
328   SYSTEMTIME current_st;
329   FILETIME current_ft;
330   ULARGE_INTEGER current_ul;
331
332   if ( hours != 0 )
333     {
334       TIMESTAMP_TO_SYSTIME(*this, &current_st);
335       SystemTimeToFileTime(&current_st, &current_ft);
336       memcpy(&current_ul, &current_ft, sizeof(current_ul));
337       current_ul.QuadPart += ( seconds_to_ns100(3600) * (ui64_t)hours );
338       memcpy(&current_ft, &current_ul, sizeof(current_ft));
339       FileTimeToSystemTime(&current_ft, &current_st);
340       SYSTIME_TO_TIMESTAMP(&current_st, *this);
341     }
342 }
343
344 #else // KM_WIN32
345
346 #include <time.h>
347
348 #define TIMESTAMP_TO_TM(ts, t) \
349   (t)->tm_year = (ts).Year - 1900;   /* year - 1900 */ \
350   (t)->tm_mon  = (ts).Month - 1;     /* month of year (0 - 11) */ \
351   (t)->tm_mday = (ts).Day;           /* day of month (1 - 31) */ \
352   (t)->tm_hour = (ts).Hour;          /* hours (0 - 23) */ \
353   (t)->tm_min  = (ts).Minute;        /* minutes (0 - 59) */ \
354   (t)->tm_sec  = (ts).Second;        /* seconds (0 - 60) */
355
356 #define TM_TO_TIMESTAMP(t, ts) \
357   (ts).Year   = (t)->tm_year + 1900;    /* year - 1900 */ \
358   (ts).Month  = (t)->tm_mon + 1;     /* month of year (0 - 11) */ \
359   (ts).Day    = (t)->tm_mday;    /* day of month (1 - 31) */ \
360   (ts).Hour   = (t)->tm_hour;    /* hours (0 - 23) */ \
361   (ts).Minute = (t)->tm_min;     /* minutes (0 - 59) */ \
362   (ts).Second = (t)->tm_sec;     /* seconds (0 - 60) */
363
364 //
365 ASDCP::MXF::Timestamp::Timestamp() :
366   Year(0), Month(0),  Day(0), Hour(0), Minute(0), Second(0)
367 {
368   time_t t_now = time(0);
369   struct tm*  now = gmtime(&t_now);
370   TM_TO_TIMESTAMP(now, *this);
371 }
372
373 //
374 bool
375 ASDCP::MXF::Timestamp::operator<(const Timestamp& rhs) const
376 {
377   struct tm lhtm, rhtm;
378   TIMESTAMP_TO_TM(*this, &lhtm);
379   TIMESTAMP_TO_TM(rhs, &rhtm);
380   return ( timegm(&lhtm) < timegm(&rhtm) );
381 }
382
383 //
384 void
385 ASDCP::MXF::Timestamp::AddDays(i32_t days)
386 {
387   struct tm current;
388
389   if ( days != 0 )
390     {
391       TIMESTAMP_TO_TM(*this, &current);
392       time_t adj_time = timegm(&current);
393       adj_time += 86400 * days;
394       struct tm*  now = gmtime(&adj_time);
395       TM_TO_TIMESTAMP(now, *this);
396     }
397 }
398
399 //
400 void
401 ASDCP::MXF::Timestamp::AddHours(i32_t hours)
402 {
403   struct tm current;
404
405   if ( hours != 0 )
406     {
407       TIMESTAMP_TO_TM(*this, &current);
408       time_t adj_time = timegm(&current);
409       adj_time += 3600 * hours;
410       struct tm*  now = gmtime(&adj_time);
411       TM_TO_TIMESTAMP(now, *this);
412     }
413 }
414
415 #endif // KM_WIN32
416
417
418 ASDCP::MXF::Timestamp::Timestamp(const Timestamp& rhs)
419 {
420   Year   = rhs.Year;
421   Month  = rhs.Month;
422   Day    = rhs.Day;
423   Hour   = rhs.Hour;
424   Minute = rhs.Minute;
425   Second = rhs.Second;
426 }
427
428 ASDCP::MXF::Timestamp::~Timestamp()
429 {
430 }
431
432 //
433 const ASDCP::MXF::Timestamp&
434 ASDCP::MXF::Timestamp::operator=(const Timestamp& rhs)
435 {
436   Year   = rhs.Year;
437   Month  = rhs.Month;
438   Day    = rhs.Day;
439   Hour   = rhs.Hour;
440   Minute = rhs.Minute;
441   Second = rhs.Second;
442   return *this;
443 }
444
445 //
446 bool
447 ASDCP::MXF::Timestamp::operator==(const Timestamp& rhs) const
448 {
449   if ( Year == rhs.Year
450        && Month  == rhs.Month
451        && Day    == rhs.Day
452        && Hour   == rhs.Hour
453        && Minute == rhs.Minute
454        && Second == rhs.Second )
455     return true;
456
457   return false;
458 }
459
460 //
461 bool
462 ASDCP::MXF::Timestamp::operator!=(const Timestamp& rhs) const
463 {
464   if ( Year != rhs.Year
465        || Month  != rhs.Month
466        || Day    != rhs.Day
467        || Hour   != rhs.Hour
468        || Minute != rhs.Minute
469        || Second != rhs.Second )
470     return true;
471
472   return false;
473 }
474
475 //
476 const char*
477 ASDCP::MXF::Timestamp::EncodeString(char* str_buf, ui32_t buf_len) const
478 {
479   // 2004-05-01 13:20:00.000
480   snprintf(str_buf, buf_len,
481            "%04hu-%02hu-%02hu %02hu:%02hu:%02hu.000",
482            Year, Month, Day, Hour, Minute, Second);
483   
484   return str_buf;
485 }
486
487 //------------------------------------------------------------------------------------------
488 //
489
490 ASDCP::MXF::TLVReader::TLVReader(const byte_t* p, ui32_t c, IPrimerLookup* PrimerLookup) :
491   MemIOReader(p, c), m_Lookup(PrimerLookup)
492 {
493   Result_t result = RESULT_OK;
494
495   while ( Remainder() > 0 && ASDCP_SUCCESS(result) )
496     {
497       TagValue Tag;
498       ui16_t pkt_len = 0;
499
500       if ( MemIOReader::ReadUi8(&Tag.a) )
501         if ( MemIOReader::ReadUi8(&Tag.b) )
502           if ( MemIOReader::ReadUi16BE(&pkt_len) )
503             {
504               m_ElementMap.insert(TagMap::value_type(Tag, ItemInfo(m_size, pkt_len)));
505               if ( SkipOffset(pkt_len) )
506                 continue;;
507             }
508
509       DefaultLogSink().Error("Malformed Set\n");
510       m_ElementMap.clear();
511       result = RESULT_KLV_CODING;
512     }
513 }
514
515 //
516 bool
517 ASDCP::MXF::TLVReader::FindTL(const MDDEntry& Entry)
518 {
519   if ( m_Lookup == 0 )
520     {
521       DefaultLogSink().Error("No Lookup service\n");
522       return false;
523     }
524   
525   TagValue TmpTag;
526
527   if ( m_Lookup->TagForKey(Entry.ul, TmpTag) != RESULT_OK )
528     {
529       if ( Entry.tag.a == 0 )
530         {
531           //      DefaultLogSink().Debug("No such UL in this TL list: %s (%02x %02x)\n",
532           //                             Entry.name, Entry.tag.a, Entry.tag.b);
533           return false;
534         }
535
536       TmpTag = Entry.tag;
537     }
538
539   TagMap::iterator e_i = m_ElementMap.find(TmpTag);
540
541   if ( e_i != m_ElementMap.end() )
542     {
543       m_size = (*e_i).second.first;
544       m_capacity = m_size + (*e_i).second.second;
545       return true;
546     }
547
548   //  DefaultLogSink().Debug("Not Found (%02x %02x): %s\n", TmpTag.a, TmpTag.b, Entry.name);
549   return false;
550 }
551
552 //
553 ASDCP::Result_t
554 ASDCP::MXF::TLVReader::ReadObject(const MDDEntry& Entry, Kumu::IArchive* Object)
555 {
556   ASDCP_TEST_NULL(Object);
557
558   if ( FindTL(Entry) )
559     {
560       if ( m_size < m_capacity ) // don't try to unarchive an empty item
561         return Object->Unarchive(this) ? RESULT_OK : RESULT_KLV_CODING;
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_KLV_CODING;
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_KLV_CODING;
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_KLV_CODING;
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_KLV_CODING;
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;
643   if ( ! MemIOWriter::WriteUi8(TmpTag.b) ) return RESULT_KLV_CODING;
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;
664
665       ui32_t before = Length();
666       if ( ! Object->Archive(this) ) return RESULT_KLV_CODING;
667       if ( (Length() - before) > 0xffffL ) return RESULT_KLV_CODING;
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;
684       if ( ! MemIOWriter::WriteUi8(*value) ) return RESULT_KLV_CODING;
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;
700       if ( ! MemIOWriter::WriteUi16BE(*value) ) return RESULT_KLV_CODING;
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;
716       if ( ! MemIOWriter::WriteUi32BE(*value) ) return RESULT_KLV_CODING;
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;
732       if ( ! MemIOWriter::WriteUi64BE(*value) ) return RESULT_KLV_CODING;
733     }
734
735   return result;
736 }
737
738
739 //----------------------------------------------------------------------------------------------------
740 //
741
742 ASDCP::MXF::Raw::Raw()
743 {
744   Capacity(256);
745 }
746
747 ASDCP::MXF::Raw::~Raw()
748 {
749 }
750
751 //
752 bool
753 ASDCP::MXF::Raw::Unarchive(Kumu::MemIOReader* Reader)
754 {
755   ui32_t payload_size = Reader->Remainder();
756   if ( payload_size == 0 ) return false;
757   if ( KM_FAILURE(Capacity(payload_size)) ) return false;
758
759   memcpy(Data(), Reader->CurrentData(), payload_size);
760   Length(payload_size);
761   return true;
762 }
763
764 //
765 bool
766 ASDCP::MXF::Raw::Archive(Kumu::MemIOWriter* Writer) const
767 {
768   return Writer->WriteRaw(RoData(), Length());
769 }
770
771 //
772 const char*
773 ASDCP::MXF::Raw::EncodeString(char* str_buf, ui32_t buf_len) const
774 {
775   *str_buf = 0;
776   Kumu::bin2hex(RoData(), Length(), str_buf, buf_len);
777   return str_buf;
778 }
779
780 //
781 // end MXFTypes.cpp
782 //