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