Merge pull request #18 from wruppelx/master
[asdcplib.git] / src / MXFTypes.cpp
index 90d68c1fbee963f4601e2e65dfe9d63baac315d0..a98a4d2fd701f42c4eb17d6d3156df56000b5f0f 100755 (executable)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2005-2006, John Hurst
+Copyright (c) 2005-2016, John Hurst
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -30,20 +30,100 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include <KM_prng.h>
+#include <KM_tai.h>
 #include "MXFTypes.h"
 #include <KM_log.h>
+
 using Kumu::DefaultLogSink;
 
 //------------------------------------------------------------------------------------------
 //
 
+//
+bool
+ASDCP::UL::operator==(const UL& rhs) const
+{
+  if ( m_Value[0] == rhs.m_Value[0] &&
+       m_Value[1] == rhs.m_Value[1] &&
+       m_Value[2] == rhs.m_Value[2] &&
+       m_Value[3] == rhs.m_Value[3] &&
+       m_Value[4] == rhs.m_Value[4] &&
+       m_Value[5] == rhs.m_Value[5] &&
+       m_Value[6] == rhs.m_Value[6] &&
+       //       m_Value[7] == rhs.m_Value[7] &&  // version is ignored when performing lookups
+       m_Value[8] == rhs.m_Value[8] &&
+       m_Value[9] == rhs.m_Value[9] &&
+       m_Value[10] == rhs.m_Value[10] &&
+       m_Value[11] == rhs.m_Value[11] &&
+       m_Value[12] == rhs.m_Value[12] &&
+       m_Value[13] == rhs.m_Value[13] &&
+       m_Value[14] == rhs.m_Value[14] &&
+       m_Value[15] == rhs.m_Value[15]
+       )
+    return true;
+
+  return false;
+}
+
+//
+bool
+ASDCP::UL::MatchIgnoreStream(const UL& rhs) const
+{
+  if ( m_Value[0] == rhs.m_Value[0] &&
+       m_Value[1] == rhs.m_Value[1] &&
+       m_Value[2] == rhs.m_Value[2] &&
+       m_Value[3] == rhs.m_Value[3] &&
+       m_Value[4] == rhs.m_Value[4] &&
+       m_Value[5] == rhs.m_Value[5] &&
+       m_Value[6] == rhs.m_Value[6] &&
+       //       m_Value[7] == rhs.m_Value[7] &&  // version is ignored when performing lookups
+       m_Value[8] == rhs.m_Value[8] &&
+       m_Value[9] == rhs.m_Value[9] &&
+       m_Value[10] == rhs.m_Value[10] &&
+       m_Value[11] == rhs.m_Value[11] &&
+       m_Value[12] == rhs.m_Value[12] &&
+       m_Value[13] == rhs.m_Value[13] &&
+       m_Value[14] == rhs.m_Value[14]
+       //       m_Value[15] == rhs.m_Value[15] // ignore stream number
+       )
+    return true;
+
+  return false;
+}
+
+//
+bool
+ASDCP::UL::MatchExact(const UL& rhs) const
+{
+  if ( m_Value[0] == rhs.m_Value[0] &&
+       m_Value[1] == rhs.m_Value[1] &&
+       m_Value[2] == rhs.m_Value[2] &&
+       m_Value[3] == rhs.m_Value[3] &&
+       m_Value[4] == rhs.m_Value[4] &&
+       m_Value[5] == rhs.m_Value[5] &&
+       m_Value[6] == rhs.m_Value[6] &&
+       m_Value[7] == rhs.m_Value[7] &&
+       m_Value[8] == rhs.m_Value[8] &&
+       m_Value[9] == rhs.m_Value[9] &&
+       m_Value[10] == rhs.m_Value[10] &&
+       m_Value[11] == rhs.m_Value[11] &&
+       m_Value[12] == rhs.m_Value[12] &&
+       m_Value[13] == rhs.m_Value[13] &&
+       m_Value[14] == rhs.m_Value[14] &&
+       m_Value[15] == rhs.m_Value[15]
+       )
+    return true;
+
+  return false;
+}
+
 const char*
 ASDCP::UL::EncodeString(char* str_buf, ui32_t buf_len) const
 {
   if ( buf_len > 38 ) // room for dotted notation?
     {
       snprintf(str_buf, buf_len,
-              "%02x%02x%02x%02x.%02x%02x.%02x%02x.%02x%02x%02x%02x.%02x%02x%02x%02x",
+              "%02x%02x%02x%02x.%02x%02x%02x%02x.%02x%02x%02x%02x.%02x%02x%02x%02x",
               m_Value[0],  m_Value[1],  m_Value[2],  m_Value[3],
               m_Value[4],  m_Value[5],  m_Value[6],  m_Value[7],
               m_Value[8],  m_Value[9],  m_Value[10], m_Value[11],
@@ -99,14 +179,17 @@ ASDCP::UMID::MakeUMID(int Type, const UUID& AssetID)
 }
 
 
-// Write the timestamp value to the given buffer in the form 2004-05-01 13:20:00.000
+// Write the UMID value to the given buffer in the form
+//   [00000000.0000.0000.00000000],00,00,00,00,00000000.0000.0000.00000000.00000000]
+// or
+//   [00000000.0000.0000.00000000],00,00,00,00,00000000-0000-0000-0000-000000000000]
 // returns 0 if the buffer is smaller than DateTimeLen
 const char*
 ASDCP::UMID::EncodeString(char* str_buf, ui32_t buf_len) const
 {
   assert(str_buf);
 
-  snprintf(str_buf, buf_len, "[%02x%02x%02x%02x.%02x%02x.%02x%02x.%02x%02x%02x%02x],%02x,%02x,%02x,%02x,",
+  snprintf(str_buf, buf_len, "[%02x%02x%02x%02x.%02x%02x%02x%02x.%02x%02x%02x%02x],%02x,%02x,%02x,%02x,",
           m_Value[0],  m_Value[1],  m_Value[2],  m_Value[3],
           m_Value[4],  m_Value[5],  m_Value[6],  m_Value[7],
           m_Value[8],  m_Value[9],  m_Value[10], m_Value[11],
@@ -119,7 +202,7 @@ ASDCP::UMID::EncodeString(char* str_buf, ui32_t buf_len) const
     {
       // half-swapped UL, use [bbaa9988.ddcc.ffee.00010203.04050607]
       snprintf(str_buf + offset, buf_len - offset,
-              "[%02x%02x%02x%02x.%02x%02x.%02x%02x.%02x%02x%02x%02x.%02x%02x%02x%02x]",
+              "[%02x%02x%02x%02x.%02x%02x%02x%02x.%02x%02x%02x%02x.%02x%02x%02x%02x]",
                m_Value[24], m_Value[25], m_Value[26], m_Value[27],
               m_Value[28], m_Value[29], m_Value[30], m_Value[31],
                m_Value[16], m_Value[17], m_Value[18], m_Value[19],
@@ -144,296 +227,198 @@ ASDCP::UMID::EncodeString(char* str_buf, ui32_t buf_len) const
 //------------------------------------------------------------------------------------------
 //
 
-const ASDCP::MXF::UTF16String&
-ASDCP::MXF::UTF16String::operator=(const char* sz)
+//
+ASDCP::MXF::UTF16String::UTF16String(const char* sz)
 {
-  if ( sz == 0 || *sz == 0 )
+  if ( sz != 0 && *sz != 0 )
     {
-      m_length = 0;
-      *m_buffer = 0;
+      this->assign(sz);
     }
-  else
-    {
-      ui32_t len = Kumu::xmin((ui32_t)strlen(sz), (IdentBufferLen - 1));
-      m_length = len;
-      memcpy(m_buffer, sz, m_length);
-      m_buffer[m_length] = 0;
-    }
-  
-  return *this;
 }
 
-
-//
-bool
-ASDCP::MXF::UTF16String::Unarchive(Kumu::MemIOReader* Reader)
+ASDCP::MXF::UTF16String::UTF16String(const std::string& str)
 {
-  const byte_t* p = Reader->CurrentData();
-  m_length = Reader->Remainder();
-  assert(m_length % 2 == 0);
-  m_length /= 2;
-  assert(IdentBufferLen >= m_length);
-  ui32_t i = 0;
-
-  for ( i = 0; i < m_length; i++ )
-    m_buffer[i] = p[(i*2)+1];
-
-  m_buffer[i] = 0;
-
-  Reader->SkipOffset(m_length*2);
-  return true;
+  this->assign(str);
 }
 
 //
-bool
-ASDCP::MXF::UTF16String::Archive(Kumu::MemIOWriter* Writer) const
+const ASDCP::MXF::UTF16String&
+ASDCP::MXF::UTF16String::operator=(const char* sz)
 {
-  byte_t* p = Writer->Data() + Writer->Length();
-  ui32_t i = 0;
-  memset(p, 0, (m_length*2)+2);
-
-  for ( i = 0; i < m_length; i++ )
-    p[(i*2)+1] = m_buffer[i];
+  if ( sz == 0 || *sz == 0 )
+    erase();
 
-  Writer->AddOffset(m_length * 2);
-  return true;
+  else
+    this->assign(sz);
+  
+  return *this;
 }
 
-
-//------------------------------------------------------------------------------------------
 //
-
-#ifdef WIN32
-
-#define TIMESTAMP_TO_SYSTIME(ts, t) \
-  (t)->wYear    = (ts).Year;   /* year */ \
-  (t)->wMonth   = (ts).Month;  /* month of year (1 - 12) */ \
-  (t)->wDay     = (ts).Day;    /* day of month (1 - 31) */ \
-  (t)->wHour    = (ts).Hour;   /* hours (0 - 23) */ \
-  (t)->wMinute  = (ts).Minute; /* minutes (0 - 59) */ \
-  (t)->wSecond  = (ts).Second; /* seconds (0 - 60) */ \
-  (t)->wDayOfWeek = 0; \
-  (t)->wMilliseconds = ((ts).Tick * 4);
-
-#define SYSTIME_TO_TIMESTAMP(t, ts) \
-  (ts).Year   = (t)->wYear;    /* year */ \
-  (ts).Month  = (t)->wMonth;   /* month of year (1 - 12) */ \
-  (ts).Day    = (t)->wDay;     /* day of month (1 - 31) */ \
-  (ts).Hour   = (t)->wHour;    /* hours (0 - 23) */ \
-  (ts).Minute = (t)->wMinute;  /* minutes (0 - 59) */ \
-  (ts).Second = (t)->wSecond;  /* seconds (0 - 60) */ \
-  (ts).Tick   = (t)->wMilliseconds / 4;
+const ASDCP::MXF::UTF16String&
+ASDCP::MXF::UTF16String::operator=(const std::string& str)
+{
+  this->assign(str);
+  return *this;
+}
 
 //
-ASDCP::MXF::Timestamp::Timestamp() :
-  Year(0), Month(0),  Day(0), Hour(0), Minute(0), Second(0), Tick(0)
+const char*
+ASDCP::MXF::UTF16String::EncodeString(char* str_buf, ui32_t buf_len) const
 {
-  SYSTEMTIME sys_time;
-  GetSystemTime(&sys_time);
-  SYSTIME_TO_TIMESTAMP(&sys_time, *this);
+  ui32_t write_len = Kumu::xmin(buf_len - 1, (ui32_t)size());
+  strncpy(str_buf, c_str(), write_len);
+  str_buf[write_len] = 0;
+  return str_buf;
 }
 
 //
 bool
-ASDCP::MXF::Timestamp::operator<(const Timestamp& rhs) const
+ASDCP::MXF::UTF16String::Unarchive(Kumu::MemIOReader* Reader)
 {
-  SYSTEMTIME lhst, rhst;
-  FILETIME lft, rft;
+  erase();
+  const ui16_t* p = (ui16_t*)Reader->CurrentData();
+  ui32_t length = Reader->Remainder() / 2;
+  char mb_buf[MB_LEN_MAX];
 
-  TIMESTAMP_TO_SYSTIME(*this, &lhst);
-  TIMESTAMP_TO_SYSTIME(rhs, &rhst);
-  SystemTimeToFileTime(&lhst, &lft);
-  SystemTimeToFileTime(&rhst, &rft);
-  return ( CompareFileTime(&lft, &rft) == -1 );
-}
+  mbstate_t ps;
+  memset(&ps, 0, sizeof(mbstate_t));
 
-inline ui64_t
-seconds_to_ns100(ui32_t seconds)
-{
-  return ((ui64_t)seconds * 10000000);
-}
+  for ( ui32_t i = 0; i < length; i++ )
+    {
+      int count = wcrtomb(mb_buf, KM_i16_BE(p[i]), &ps);
 
-//
-void
-ASDCP::MXF::Timestamp::AddDays(i32_t days)
-{
-  SYSTEMTIME current_st;
-  FILETIME current_ft;
-  ULARGE_INTEGER current_ul;
+      if ( count == -1 )
+       {
+         DefaultLogSink().Error("Unable to decode wide character 0x%04hx\n", p[i]);
+         return false;
+       }
 
-  if ( days != 0 )
-    {
-      TIMESTAMP_TO_SYSTIME(*this, &current_st);
-      SystemTimeToFileTime(&current_st, &current_ft);
-      memcpy(&current_ul, &current_ft, sizeof(current_ul));
-      current_ul.QuadPart += ( seconds_to_ns100(86400) * (ui64_t)days );
-      memcpy(&current_ft, &current_ul, sizeof(current_ft));
-      FileTimeToSystemTime(&current_ft, &current_st);
-      SYSTIME_TO_TIMESTAMP(&current_st, *this);
+      assert(count <= MB_LEN_MAX);
+      mb_buf[count] = 0;
+      this->append(mb_buf);
     }
+
+  Reader->SkipOffset(length*2);
+  return true;
 }
 
 //
-void
-ASDCP::MXF::Timestamp::AddHours(i32_t hours)
+bool
+ASDCP::MXF::UTF16String::Archive(Kumu::MemIOWriter* Writer) const
 {
-  SYSTEMTIME current_st;
-  FILETIME current_ft;
-  ULARGE_INTEGER current_ul;
-
-  if ( hours != 0 )
+  if ( size() > IdentBufferLen )
     {
-      TIMESTAMP_TO_SYSTIME(*this, &current_st);
-      SystemTimeToFileTime(&current_st, &current_ft);
-      memcpy(&current_ul, &current_ft, sizeof(current_ul));
-      current_ul.QuadPart += ( seconds_to_ns100(3600) * (ui64_t)hours );
-      memcpy(&current_ft, &current_ul, sizeof(current_ft));
-      FileTimeToSystemTime(&current_ft, &current_st);
-      SYSTIME_TO_TIMESTAMP(&current_st, *this);
+      DefaultLogSink().Error("String length exceeds maximum %u bytes\n", IdentBufferLen);
+      return false;
     }
-}
 
-#else // KM_WIN32
+  const char* mbp = c_str();
+  wchar_t wcp;
+  ui32_t remainder = size();
+  ui32_t length = size();
+  ui32_t i = 0;
 
-#include <time.h>
+  mbstate_t ps;
+  memset(&ps, 0, sizeof(mbstate_t));
 
-#define TIMESTAMP_TO_TM(ts, t) \
-  (t)->tm_year = (ts).Year - 1900;   /* year - 1900 */ \
-  (t)->tm_mon  = (ts).Month - 1;     /* month of year (0 - 11) */ \
-  (t)->tm_mday = (ts).Day;           /* day of month (1 - 31) */ \
-  (t)->tm_hour = (ts).Hour;          /* hours (0 - 23) */ \
-  (t)->tm_min  = (ts).Minute;        /* minutes (0 - 59) */ \
-  (t)->tm_sec  = (ts).Second;        /* seconds (0 - 60) */
+  while ( i < length )
+    {
+      int count = mbrtowc(&wcp, mbp+i, remainder, &ps);
 
-#define TM_TO_TIMESTAMP(t, ts) \
-  (ts).Year   = (t)->tm_year + 1900;    /* year - 1900 */ \
-  (ts).Month  = (t)->tm_mon + 1;     /* month of year (0 - 11) */ \
-  (ts).Day    = (t)->tm_mday;    /* day of month (1 - 31) */ \
-  (ts).Hour   = (t)->tm_hour;    /* hours (0 - 23) */ \
-  (ts).Minute = (t)->tm_min;     /* minutes (0 - 59) */ \
-  (ts).Second = (t)->tm_sec;     /* seconds (0 - 60) */
+      if ( count == -1 )
+       {
+         DefaultLogSink().Error("Error decoding multi-byte sequence starting at offset %u\n", i);
+         return false;
+       }
+      else if ( count  == 0 )
+       {
+         break;
+       }
 
-//
-ASDCP::MXF::Timestamp::Timestamp() :
-  Year(0), Month(0),  Day(0), Hour(0), Minute(0), Second(0)
-{
-  time_t t_now = time(0);
-  struct tm*  now = gmtime(&t_now);
-  TM_TO_TIMESTAMP(now, *this);
+      bool result = Writer->WriteUi16BE((ui16_t)wcp);
+
+      if ( result == false )
+       {
+         DefaultLogSink().Error("No more space in memory IO writer\n");
+         return false;
+       }
+
+      i += count;
+      remainder -= count;
+    }
+
+  return true;
 }
 
+//------------------------------------------------------------------------------------------
 //
-bool
-ASDCP::MXF::Timestamp::operator<(const Timestamp& rhs) const
-{
-  struct tm lhtm, rhtm;
-  TIMESTAMP_TO_TM(*this, &lhtm);
-  TIMESTAMP_TO_TM(rhs, &rhtm);
-  return ( timegm(&lhtm) < timegm(&rhtm) );
-}
 
 //
-void
-ASDCP::MXF::Timestamp::AddDays(i32_t days)
+ASDCP::MXF::ISO8String::ISO8String(const char* sz)
 {
-  struct tm current;
-
-  if ( days != 0 )
+  if ( sz != 0 && *sz != 0 )
     {
-      TIMESTAMP_TO_TM(*this, &current);
-      time_t adj_time = timegm(&current);
-      adj_time += 86400 * days;
-      struct tm*  now = gmtime(&adj_time);
-      TM_TO_TIMESTAMP(now, *this);
+      this->assign(sz);
     }
 }
 
-//
-void
-ASDCP::MXF::Timestamp::AddHours(i32_t hours)
+ASDCP::MXF::ISO8String::ISO8String(const std::string& str)
 {
-  struct tm current;
-
-  if ( hours != 0 )
-    {
-      TIMESTAMP_TO_TM(*this, &current);
-      time_t adj_time = timegm(&current);
-      adj_time += 3600 * hours;
-      struct tm*  now = gmtime(&adj_time);
-      TM_TO_TIMESTAMP(now, *this);
-    }
+  this->assign(str);
 }
 
-#endif // KM_WIN32
 
-
-ASDCP::MXF::Timestamp::Timestamp(const Timestamp& rhs)
+//
+const ASDCP::MXF::ISO8String&
+ASDCP::MXF::ISO8String::operator=(const char* sz)
 {
-  Year   = rhs.Year;
-  Month  = rhs.Month;
-  Day    = rhs.Day;
-  Hour   = rhs.Hour;
-  Minute = rhs.Minute;
-  Second = rhs.Second;
-}
+  if ( sz == 0 || *sz == 0 )
+    erase();
 
-ASDCP::MXF::Timestamp::~Timestamp()
-{
+  else
+    this->assign(sz);
+  
+  return *this;
 }
 
 //
-const ASDCP::MXF::Timestamp&
-ASDCP::MXF::Timestamp::operator=(const Timestamp& rhs)
+const ASDCP::MXF::ISO8String&
+ASDCP::MXF::ISO8String::operator=(const std::string& str)
 {
-  Year   = rhs.Year;
-  Month  = rhs.Month;
-  Day    = rhs.Day;
-  Hour   = rhs.Hour;
-  Minute = rhs.Minute;
-  Second = rhs.Second;
+  this->assign(str);
   return *this;
 }
 
 //
-bool
-ASDCP::MXF::Timestamp::operator==(const Timestamp& rhs) const
-{
-  if ( Year == rhs.Year
-       && Month  == rhs.Month
-       && Day    == rhs.Day
-       && Hour   == rhs.Hour
-       && Minute == rhs.Minute
-       && Second == rhs.Second )
-    return true;
-
-  return false;
+const char*
+ASDCP::MXF::ISO8String::EncodeString(char* str_buf, ui32_t buf_len) const
+{
+  ui32_t write_len = Kumu::xmin(buf_len - 1, (ui32_t)size());
+  strncpy(str_buf, c_str(), write_len);
+  str_buf[write_len] = 0;
+  return str_buf;
 }
 
 //
 bool
-ASDCP::MXF::Timestamp::operator!=(const Timestamp& rhs) const
-{
-  if ( Year != rhs.Year
-       || Month  != rhs.Month
-       || Day    != rhs.Day
-       || Hour   != rhs.Hour
-       || Minute != rhs.Minute
-       || Second != rhs.Second )
-    return true;
-
-  return false;
+ASDCP::MXF::ISO8String::Unarchive(Kumu::MemIOReader* Reader)
+{
+  assign((char*)Reader->CurrentData(), Reader->Remainder());
+  return true;
 }
 
 //
-const char*
-ASDCP::MXF::Timestamp::EncodeString(char* str_buf, ui32_t buf_len) const
+bool
+ASDCP::MXF::ISO8String::Archive(Kumu::MemIOWriter* Writer) const
 {
-  // 2004-05-01 13:20:00.000
-  snprintf(str_buf, buf_len,
-          "%04hu-%02hu-%02hu %02hu:%02hu:%02hu.000",
-           Year, Month, Day, Hour, Minute, Second);
-  
-  return str_buf;
+  if ( size() > IdentBufferLen )
+    {
+      DefaultLogSink().Error("String length exceeds maximum %u bytes\n", IdentBufferLen);
+      return false;
+    }
+
+  return Writer->WriteRaw((const byte_t*)c_str(), size());
 }
 
 //------------------------------------------------------------------------------------------
@@ -460,7 +445,7 @@ ASDCP::MXF::TLVReader::TLVReader(const byte_t* p, ui32_t c, IPrimerLookup* Prime
 
       DefaultLogSink().Error("Malformed Set\n");
       m_ElementMap.clear();
-      result = RESULT_KLV_CODING;
+      result = RESULT_KLV_CODING(__LINE__, __FILE__);
     }
 }
 
@@ -510,7 +495,10 @@ ASDCP::MXF::TLVReader::ReadObject(const MDDEntry& Entry, Kumu::IArchive* Object)
   if ( FindTL(Entry) )
     {
       if ( m_size < m_capacity ) // don't try to unarchive an empty item
-       return Object->Unarchive(this) ? RESULT_OK : RESULT_KLV_CODING;
+       {
+         // TODO: carry on if uachive fails
+         return Object->Unarchive(this) ? RESULT_OK : RESULT_FALSE(__LINE__, __FILE__);
+       }
     }
 
   return RESULT_FALSE;
@@ -523,7 +511,7 @@ ASDCP::MXF::TLVReader::ReadUi8(const MDDEntry& Entry, ui8_t* value)
   ASDCP_TEST_NULL(value);
 
   if ( FindTL(Entry) )
-    return MemIOReader::ReadUi8(value) ? RESULT_OK : RESULT_KLV_CODING;
+    return MemIOReader::ReadUi8(value) ? RESULT_OK : RESULT_FALSE(__LINE__, __FILE__);
 
   return RESULT_FALSE;
 }
@@ -535,7 +523,7 @@ ASDCP::MXF::TLVReader::ReadUi16(const MDDEntry& Entry, ui16_t* value)
   ASDCP_TEST_NULL(value);
 
   if ( FindTL(Entry) )
-    return MemIOReader::ReadUi16BE(value) ? RESULT_OK : RESULT_KLV_CODING;
+    return MemIOReader::ReadUi16BE(value) ? RESULT_OK : RESULT_FALSE(__LINE__, __FILE__);
 
   return RESULT_FALSE;
 }
@@ -547,7 +535,7 @@ ASDCP::MXF::TLVReader::ReadUi32(const MDDEntry& Entry, ui32_t* value)
   ASDCP_TEST_NULL(value);
 
   if ( FindTL(Entry) )
-    return MemIOReader::ReadUi32BE(value) ? RESULT_OK : RESULT_KLV_CODING;
+    return MemIOReader::ReadUi32BE(value) ? RESULT_OK : RESULT_FALSE(__LINE__, __FILE__);
 
   return RESULT_FALSE;
 }
@@ -559,7 +547,7 @@ ASDCP::MXF::TLVReader::ReadUi64(const MDDEntry& Entry, ui64_t* value)
   ASDCP_TEST_NULL(value);
 
   if ( FindTL(Entry) )
-    return MemIOReader::ReadUi64BE(value) ? RESULT_OK : RESULT_KLV_CODING;
+    return MemIOReader::ReadUi64BE(value) ? RESULT_OK : RESULT_FALSE(__LINE__, __FILE__);
 
   return RESULT_FALSE;
 }
@@ -579,7 +567,7 @@ ASDCP::MXF::TLVWriter::WriteTag(const MDDEntry& Entry)
 {
   if ( m_Lookup == 0 )
     {
-      DefaultLogSink().Error("No Primer object available\n");
+      DefaultLogSink().Error("No Primer object available.\n");
       return RESULT_FAIL;
     }
 
@@ -591,8 +579,8 @@ ASDCP::MXF::TLVWriter::WriteTag(const MDDEntry& Entry)
       return RESULT_FAIL;
     }
 
-  if ( ! MemIOWriter::WriteUi8(TmpTag.a) ) return RESULT_KLV_CODING;
-  if ( ! MemIOWriter::WriteUi8(TmpTag.b) ) return RESULT_KLV_CODING;
+  if ( ! MemIOWriter::WriteUi8(TmpTag.a) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
+  if ( ! MemIOWriter::WriteUi8(TmpTag.b) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
   return RESULT_OK;
 }
 
@@ -612,11 +600,12 @@ ASDCP::MXF::TLVWriter::WriteObject(const MDDEntry& Entry, Kumu::IArchive* Object
       // write a temp length
       byte_t* l_p = CurrentData();
 
-      if ( ! MemIOWriter::WriteUi16BE(0) ) return RESULT_KLV_CODING;
+      if ( ! MemIOWriter::WriteUi16BE(0) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
 
       ui32_t before = Length();
-      if ( ! Object->Archive(this) ) return RESULT_KLV_CODING;
-      Kumu::i2p<ui16_t>(KM_i16_BE( Length() - before), l_p);
+      if ( ! Object->Archive(this) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
+      if ( (Length() - before) > 0xffffL ) return RESULT_KLV_CODING(__LINE__, __FILE__);
+      Kumu::i2p<ui16_t>(KM_i16_BE(Length() - before), l_p);
     }
 
   return result;
@@ -631,8 +620,8 @@ ASDCP::MXF::TLVWriter::WriteUi8(const MDDEntry& Entry, ui8_t* value)
 
   if ( ASDCP_SUCCESS(result) )
     {
-      if ( ! MemIOWriter::WriteUi16BE(sizeof(ui8_t)) ) return RESULT_KLV_CODING;
-      if ( ! MemIOWriter::WriteUi8(*value) ) return RESULT_KLV_CODING;
+      if ( ! MemIOWriter::WriteUi16BE(sizeof(ui8_t)) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
+      if ( ! MemIOWriter::WriteUi8(*value) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
     }
   
   return result;
@@ -647,8 +636,8 @@ ASDCP::MXF::TLVWriter::WriteUi16(const MDDEntry& Entry, ui16_t* value)
 
   if ( KM_SUCCESS(result) )
     {
-      if ( ! MemIOWriter::WriteUi16BE(sizeof(ui16_t)) ) return RESULT_KLV_CODING;
-      if ( ! MemIOWriter::WriteUi16BE(*value) ) return RESULT_KLV_CODING;
+      if ( ! MemIOWriter::WriteUi16BE(sizeof(ui16_t)) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
+      if ( ! MemIOWriter::WriteUi16BE(*value) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
     }
 
   return result;
@@ -663,8 +652,8 @@ ASDCP::MXF::TLVWriter::WriteUi32(const MDDEntry& Entry, ui32_t* value)
 
   if ( KM_SUCCESS(result) )
     {
-      if ( ! MemIOWriter::WriteUi16BE(sizeof(ui32_t)) ) return RESULT_KLV_CODING;
-      if ( ! MemIOWriter::WriteUi32BE(*value) ) return RESULT_KLV_CODING;
+      if ( ! MemIOWriter::WriteUi16BE(sizeof(ui32_t)) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
+      if ( ! MemIOWriter::WriteUi32BE(*value) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
     }
 
   return result;
@@ -679,14 +668,71 @@ ASDCP::MXF::TLVWriter::WriteUi64(const MDDEntry& Entry, ui64_t* value)
 
   if ( KM_SUCCESS(result) )
     {
-      if ( ! MemIOWriter::WriteUi16BE(sizeof(ui64_t)) ) return RESULT_KLV_CODING;
-      if ( ! MemIOWriter::WriteUi64BE(*value) ) return RESULT_KLV_CODING;
+      if ( ! MemIOWriter::WriteUi16BE(sizeof(ui64_t)) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
+      if ( ! MemIOWriter::WriteUi64BE(*value) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
     }
 
   return result;
 }
 
 
+//----------------------------------------------------------------------------------------------------
+//
+
+
+ASDCP::MXF::RGBALayout::RGBALayout()
+{
+  memset(m_value, 0, RGBAValueLength);
+}
+
+ASDCP::MXF::RGBALayout::RGBALayout(const byte_t* value)
+{
+  memcpy(m_value, value, RGBAValueLength);
+}
+
+ASDCP::MXF::RGBALayout::~RGBALayout()
+{
+}
+
+static char
+get_char_for_code(byte_t c)
+{
+  for ( int i = 0; ASDCP::MXF::RGBALayoutTable[i].code != 0; ++i )
+    {
+      if ( ASDCP::MXF::RGBALayoutTable[i].code == c )
+       {
+         return ASDCP::MXF::RGBALayoutTable[i].symbol;
+       }
+    }
+
+  return '_';
+}
+
+//
+const char*
+ASDCP::MXF::RGBALayout::EncodeString(char* buf, ui32_t buf_len) const
+{
+  std::string tmp_str;
+  char tmp_buf[64];
+
+  for ( int i = 0; i < RGBAValueLength && m_value[i] != 0; i += 2 )
+    {
+      snprintf(tmp_buf, 64, "%c(%d)", get_char_for_code(m_value[i]), m_value[i+1]);
+
+      if ( ! tmp_str.empty() )
+       {
+         tmp_str += " ";
+       }
+
+      tmp_str += tmp_buf;
+    }
+
+  assert(tmp_str.size() < buf_len);
+  strncpy(buf, tmp_str.c_str(), tmp_str.size());
+  return buf;
+}
+
+
 //----------------------------------------------------------------------------------------------------
 //