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