2 Copyright (c) 2005-2009, John Hurst
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
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.
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.
27 /*! \file MXFTypes.cpp
36 using Kumu::DefaultLogSink;
38 //------------------------------------------------------------------------------------------
42 ASDCP::UL::operator==(const UL& rhs) const
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]
68 ASDCP::UL::EncodeString(char* str_buf, ui32_t buf_len) const
70 if ( buf_len > 38 ) // room for dotted notation?
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]
82 else if ( buf_len > 32 ) // room for compact?
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]
100 ASDCP::UMID::MakeUMID(int Type)
103 Kumu::GenRandomValue(AssetID);
104 MakeUMID(Type, AssetID);
109 ASDCP::UMID::MakeUMID(int Type, const UUID& AssetID)
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
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
122 m_Value[13] = m_Value[14] = m_Value[15] = 0;
124 memcpy(&m_Value[16], AssetID.Value(), AssetID.Size());
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
132 ASDCP::UMID::EncodeString(char* str_buf, ui32_t buf_len) const
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]
143 ui32_t offset = strlen(str_buf);
145 if ( ( m_Value[8] & 0x80 ) == 0 )
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]
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]
171 //------------------------------------------------------------------------------------------
175 const ASDCP::MXF::UTF16String&
176 ASDCP::MXF::UTF16String::operator=(const char* sz)
178 if ( sz == 0 || *sz == 0 )
188 const ASDCP::MXF::UTF16String&
189 ASDCP::MXF::UTF16String::operator=(const std::string& str)
197 ASDCP::MXF::UTF16String::EncodeString(char* str_buf, ui32_t buf_len) const
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;
207 ASDCP::MXF::UTF16String::Unarchive(Kumu::MemIOReader* Reader)
210 const ui16_t* p = (ui16_t*)Reader->CurrentData();
211 ui32_t length = Reader->Remainder() / 2;
212 char mb_buf[MB_LEN_MAX+1];
214 for ( ui32_t i = 0; i < length; i++ )
216 int count = wctomb(mb_buf, KM_i16_BE(p[i]));
220 DefaultLogSink().Error("Unable to decode wide character 0x%04hx\n", p[i]);
224 assert(count <= MB_LEN_MAX);
226 this->append(mb_buf);
229 Reader->SkipOffset(length*2);
235 ASDCP::MXF::UTF16String::Archive(Kumu::MemIOWriter* Writer) const
237 if ( size() > IdentBufferLen )
239 DefaultLogSink().Error("String length exceeds maximum %u bytes\n", IdentBufferLen);
243 const char* mbp = c_str();
245 ui32_t remainder = size();
246 ui32_t length = size();
251 int count = mbtowc(&wcp, mbp+i, remainder);
255 DefaultLogSink().Error("Error decoding multi-byte sequence starting at offset %u\n", i);
258 else if ( count == 0 )
261 bool result = Writer->WriteUi16BE((ui16_t)wcp);
263 if ( result == false )
265 DefaultLogSink().Error("No more space in memory IO writer\n");
277 //------------------------------------------------------------------------------------------
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);
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;
302 ASDCP::MXF::Timestamp::Timestamp() :
303 Year(0), Month(0), Day(0), Hour(0), Minute(0), Second(0), Tick(0)
306 GetSystemTime(&sys_time);
307 SYSTIME_TO_TIMESTAMP(&sys_time, *this);
312 ASDCP::MXF::Timestamp::operator<(const Timestamp& rhs) const
314 SYSTEMTIME lhst, rhst;
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 );
325 seconds_to_ns100(ui32_t seconds)
327 return ((ui64_t)seconds * 10000000);
332 ASDCP::MXF::Timestamp::AddDays(i32_t days)
334 SYSTEMTIME current_st;
336 ULARGE_INTEGER current_ul;
340 TIMESTAMP_TO_SYSTIME(*this, ¤t_st);
341 SystemTimeToFileTime(¤t_st, ¤t_ft);
342 memcpy(¤t_ul, ¤t_ft, sizeof(current_ul));
343 current_ul.QuadPart += ( seconds_to_ns100(86400) * (ui64_t)days );
344 memcpy(¤t_ft, ¤t_ul, sizeof(current_ft));
345 FileTimeToSystemTime(¤t_ft, ¤t_st);
346 SYSTIME_TO_TIMESTAMP(¤t_st, *this);
352 ASDCP::MXF::Timestamp::AddHours(i32_t hours)
354 SYSTEMTIME current_st;
356 ULARGE_INTEGER current_ul;
360 TIMESTAMP_TO_SYSTIME(*this, ¤t_st);
361 SystemTimeToFileTime(¤t_st, ¤t_ft);
362 memcpy(¤t_ul, ¤t_ft, sizeof(current_ul));
363 current_ul.QuadPart += ( seconds_to_ns100(3600) * (ui64_t)hours );
364 memcpy(¤t_ft, ¤t_ul, sizeof(current_ft));
365 FileTimeToSystemTime(¤t_ft, ¤t_st);
366 SYSTIME_TO_TIMESTAMP(¤t_st, *this);
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) */
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) */
391 ASDCP::MXF::Timestamp::Timestamp() :
392 Year(0), Month(0), Day(0), Hour(0), Minute(0), Second(0)
394 time_t t_now = time(0);
395 struct tm* now = gmtime(&t_now);
396 TM_TO_TIMESTAMP(now, *this);
401 ASDCP::MXF::Timestamp::operator<(const Timestamp& rhs) const
403 struct tm lhtm, rhtm;
404 TIMESTAMP_TO_TM(*this, &lhtm);
405 TIMESTAMP_TO_TM(rhs, &rhtm);
406 return ( timegm(&lhtm) < timegm(&rhtm) );
411 ASDCP::MXF::Timestamp::AddDays(i32_t days)
417 TIMESTAMP_TO_TM(*this, ¤t);
418 time_t adj_time = timegm(¤t);
419 adj_time += 86400 * days;
420 struct tm* now = gmtime(&adj_time);
421 TM_TO_TIMESTAMP(now, *this);
427 ASDCP::MXF::Timestamp::AddHours(i32_t hours)
433 TIMESTAMP_TO_TM(*this, ¤t);
434 time_t adj_time = timegm(¤t);
435 adj_time += 3600 * hours;
436 struct tm* now = gmtime(&adj_time);
437 TM_TO_TIMESTAMP(now, *this);
444 ASDCP::MXF::Timestamp::Timestamp(const Timestamp& rhs) : IArchive()
454 ASDCP::MXF::Timestamp::~Timestamp()
459 const ASDCP::MXF::Timestamp&
460 ASDCP::MXF::Timestamp::operator=(const Timestamp& rhs)
473 ASDCP::MXF::Timestamp::operator==(const Timestamp& rhs) const
475 if ( Year == rhs.Year
476 && Month == rhs.Month
479 && Minute == rhs.Minute
480 && Second == rhs.Second )
488 ASDCP::MXF::Timestamp::operator!=(const Timestamp& rhs) const
490 if ( Year != rhs.Year
491 || Month != rhs.Month
494 || Minute != rhs.Minute
495 || Second != rhs.Second )
503 ASDCP::MXF::Timestamp::EncodeString(char* str_buf, ui32_t buf_len) const
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);
513 //------------------------------------------------------------------------------------------
516 ASDCP::MXF::TLVReader::TLVReader(const byte_t* p, ui32_t c, IPrimerLookup* PrimerLookup) :
517 MemIOReader(p, c), m_Lookup(PrimerLookup)
519 Result_t result = RESULT_OK;
521 while ( Remainder() > 0 && ASDCP_SUCCESS(result) )
526 if ( MemIOReader::ReadUi8(&Tag.a) )
527 if ( MemIOReader::ReadUi8(&Tag.b) )
528 if ( MemIOReader::ReadUi16BE(&pkt_len) )
530 m_ElementMap.insert(TagMap::value_type(Tag, ItemInfo(m_size, pkt_len)));
531 if ( SkipOffset(pkt_len) )
535 DefaultLogSink().Error("Malformed Set\n");
536 m_ElementMap.clear();
537 result = RESULT_KLV_CODING;
543 ASDCP::MXF::TLVReader::FindTL(const MDDEntry& Entry)
547 DefaultLogSink().Error("No Lookup service\n");
553 if ( m_Lookup->TagForKey(Entry.ul, TmpTag) != RESULT_OK )
555 if ( Entry.tag.a == 0 )
557 // DefaultLogSink().Debug("No such UL in this TL list: %s (%02x %02x)\n",
558 // Entry.name, Entry.tag.a, Entry.tag.b);
565 TagMap::iterator e_i = m_ElementMap.find(TmpTag);
567 if ( e_i != m_ElementMap.end() )
569 m_size = (*e_i).second.first;
570 m_capacity = m_size + (*e_i).second.second;
574 // DefaultLogSink().Debug("Not Found (%02x %02x): %s\n", TmpTag.a, TmpTag.b, Entry.name);
580 ASDCP::MXF::TLVReader::ReadObject(const MDDEntry& Entry, Kumu::IArchive* Object)
582 ASDCP_TEST_NULL(Object);
586 if ( m_size < m_capacity ) // don't try to unarchive an empty item
587 return Object->Unarchive(this) ? RESULT_OK : RESULT_KLV_CODING;
595 ASDCP::MXF::TLVReader::ReadUi8(const MDDEntry& Entry, ui8_t* value)
597 ASDCP_TEST_NULL(value);
600 return MemIOReader::ReadUi8(value) ? RESULT_OK : RESULT_KLV_CODING;
607 ASDCP::MXF::TLVReader::ReadUi16(const MDDEntry& Entry, ui16_t* value)
609 ASDCP_TEST_NULL(value);
612 return MemIOReader::ReadUi16BE(value) ? RESULT_OK : RESULT_KLV_CODING;
619 ASDCP::MXF::TLVReader::ReadUi32(const MDDEntry& Entry, ui32_t* value)
621 ASDCP_TEST_NULL(value);
624 return MemIOReader::ReadUi32BE(value) ? RESULT_OK : RESULT_KLV_CODING;
631 ASDCP::MXF::TLVReader::ReadUi64(const MDDEntry& Entry, ui64_t* value)
633 ASDCP_TEST_NULL(value);
636 return MemIOReader::ReadUi64BE(value) ? RESULT_OK : RESULT_KLV_CODING;
641 //------------------------------------------------------------------------------------------
644 ASDCP::MXF::TLVWriter::TLVWriter(byte_t* p, ui32_t c, IPrimerLookup* PrimerLookup) :
645 MemIOWriter(p, c), m_Lookup(PrimerLookup)
652 ASDCP::MXF::TLVWriter::WriteTag(const MDDEntry& Entry)
656 DefaultLogSink().Error("No Primer object available\n");
662 if ( m_Lookup->InsertTag(Entry, TmpTag) != RESULT_OK )
664 DefaultLogSink().Error("No tag for entry %s\n", Entry.name);
668 if ( ! MemIOWriter::WriteUi8(TmpTag.a) ) return RESULT_KLV_CODING;
669 if ( ! MemIOWriter::WriteUi8(TmpTag.b) ) return RESULT_KLV_CODING;
675 ASDCP::MXF::TLVWriter::WriteObject(const MDDEntry& Entry, Kumu::IArchive* Object)
677 ASDCP_TEST_NULL(Object);
679 if ( Entry.optional && ! Object->HasValue() )
682 Result_t result = WriteTag(Entry);
684 if ( ASDCP_SUCCESS(result) )
686 // write a temp length
687 byte_t* l_p = CurrentData();
689 if ( ! MemIOWriter::WriteUi16BE(0) ) return RESULT_KLV_CODING;
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);
702 ASDCP::MXF::TLVWriter::WriteUi8(const MDDEntry& Entry, ui8_t* value)
704 ASDCP_TEST_NULL(value);
705 Result_t result = WriteTag(Entry);
707 if ( ASDCP_SUCCESS(result) )
709 if ( ! MemIOWriter::WriteUi16BE(sizeof(ui8_t)) ) return RESULT_KLV_CODING;
710 if ( ! MemIOWriter::WriteUi8(*value) ) return RESULT_KLV_CODING;
718 ASDCP::MXF::TLVWriter::WriteUi16(const MDDEntry& Entry, ui16_t* value)
720 ASDCP_TEST_NULL(value);
721 Result_t result = WriteTag(Entry);
723 if ( KM_SUCCESS(result) )
725 if ( ! MemIOWriter::WriteUi16BE(sizeof(ui16_t)) ) return RESULT_KLV_CODING;
726 if ( ! MemIOWriter::WriteUi16BE(*value) ) return RESULT_KLV_CODING;
734 ASDCP::MXF::TLVWriter::WriteUi32(const MDDEntry& Entry, ui32_t* value)
736 ASDCP_TEST_NULL(value);
737 Result_t result = WriteTag(Entry);
739 if ( KM_SUCCESS(result) )
741 if ( ! MemIOWriter::WriteUi16BE(sizeof(ui32_t)) ) return RESULT_KLV_CODING;
742 if ( ! MemIOWriter::WriteUi32BE(*value) ) return RESULT_KLV_CODING;
750 ASDCP::MXF::TLVWriter::WriteUi64(const MDDEntry& Entry, ui64_t* value)
752 ASDCP_TEST_NULL(value);
753 Result_t result = WriteTag(Entry);
755 if ( KM_SUCCESS(result) )
757 if ( ! MemIOWriter::WriteUi16BE(sizeof(ui64_t)) ) return RESULT_KLV_CODING;
758 if ( ! MemIOWriter::WriteUi64BE(*value) ) return RESULT_KLV_CODING;
765 //----------------------------------------------------------------------------------------------------
768 ASDCP::MXF::Raw::Raw()
773 ASDCP::MXF::Raw::~Raw()
779 ASDCP::MXF::Raw::Unarchive(Kumu::MemIOReader* Reader)
781 ui32_t payload_size = Reader->Remainder();
782 if ( payload_size == 0 ) return false;
783 if ( KM_FAILURE(Capacity(payload_size)) ) return false;
785 memcpy(Data(), Reader->CurrentData(), payload_size);
786 Length(payload_size);
792 ASDCP::MXF::Raw::Archive(Kumu::MemIOWriter* Writer) const
794 return Writer->WriteRaw(RoData(), Length());
799 ASDCP::MXF::Raw::EncodeString(char* str_buf, ui32_t buf_len) const
802 Kumu::bin2hex(RoData(), Length(), str_buf, buf_len);