2 Copyright (c) 2005-2011, 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::ExactMatch(const UL& rhs) const
70 if ( m_Value[0] == rhs.m_Value[0] &&
71 m_Value[1] == rhs.m_Value[1] &&
72 m_Value[2] == rhs.m_Value[2] &&
73 m_Value[3] == rhs.m_Value[3] &&
74 m_Value[4] == rhs.m_Value[4] &&
75 m_Value[5] == rhs.m_Value[5] &&
76 m_Value[6] == rhs.m_Value[6] &&
77 m_Value[7] == rhs.m_Value[7] &&
78 m_Value[8] == rhs.m_Value[8] &&
79 m_Value[9] == rhs.m_Value[9] &&
80 m_Value[10] == rhs.m_Value[10] &&
81 m_Value[11] == rhs.m_Value[11] &&
82 m_Value[12] == rhs.m_Value[12] &&
83 m_Value[13] == rhs.m_Value[13] &&
84 m_Value[14] == rhs.m_Value[14] &&
85 m_Value[15] == rhs.m_Value[15]
93 ASDCP::UL::EncodeString(char* str_buf, ui32_t buf_len) const
95 if ( buf_len > 38 ) // room for dotted notation?
97 snprintf(str_buf, buf_len,
98 "%02x%02x%02x%02x.%02x%02x.%02x%02x.%02x%02x%02x%02x.%02x%02x%02x%02x",
99 m_Value[0], m_Value[1], m_Value[2], m_Value[3],
100 m_Value[4], m_Value[5], m_Value[6], m_Value[7],
101 m_Value[8], m_Value[9], m_Value[10], m_Value[11],
102 m_Value[12], m_Value[13], m_Value[14], m_Value[15]
107 else if ( buf_len > 32 ) // room for compact?
109 snprintf(str_buf, buf_len,
110 "%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]
125 ASDCP::UMID::MakeUMID(int Type)
128 Kumu::GenRandomValue(AssetID);
129 MakeUMID(Type, AssetID);
134 ASDCP::UMID::MakeUMID(int Type, const UUID& AssetID)
136 // Set the non-varying base of the UMID
137 static const byte_t UMIDBase[10] = { 0x06, 0x0a, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
138 memcpy(m_Value, UMIDBase, 10);
139 m_Value[10] = Type; // Material Type
140 m_Value[12] = 0x13; // length
142 // preserved for compatibility with mfxlib
143 if( Type > 4 ) m_Value[7] = 5;
144 m_Value[11] = 0x20; // UUID/UL method, number gen undefined
147 m_Value[13] = m_Value[14] = m_Value[15] = 0;
149 memcpy(&m_Value[16], AssetID.Value(), AssetID.Size());
154 // Write the timestamp value to the given buffer in the form 2004-05-01 13:20:00.000
155 // returns 0 if the buffer is smaller than DateTimeLen
157 ASDCP::UMID::EncodeString(char* str_buf, ui32_t buf_len) const
161 snprintf(str_buf, buf_len, "[%02x%02x%02x%02x.%02x%02x.%02x%02x.%02x%02x%02x%02x],%02x,%02x,%02x,%02x,",
162 m_Value[0], m_Value[1], m_Value[2], m_Value[3],
163 m_Value[4], m_Value[5], m_Value[6], m_Value[7],
164 m_Value[8], m_Value[9], m_Value[10], m_Value[11],
165 m_Value[12], m_Value[13], m_Value[14], m_Value[15]
168 ui32_t offset = strlen(str_buf);
170 if ( ( m_Value[8] & 0x80 ) == 0 )
172 // half-swapped UL, use [bbaa9988.ddcc.ffee.00010203.04050607]
173 snprintf(str_buf + offset, buf_len - offset,
174 "[%02x%02x%02x%02x.%02x%02x.%02x%02x.%02x%02x%02x%02x.%02x%02x%02x%02x]",
175 m_Value[24], m_Value[25], m_Value[26], m_Value[27],
176 m_Value[28], m_Value[29], m_Value[30], m_Value[31],
177 m_Value[16], m_Value[17], m_Value[18], m_Value[19],
178 m_Value[20], m_Value[21], m_Value[22], m_Value[23]
183 // UUID, use {00112233-4455-6677-8899-aabbccddeeff}
184 snprintf(str_buf + offset, buf_len - offset,
185 "{%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
186 m_Value[16], m_Value[17], m_Value[18], m_Value[19],
187 m_Value[20], m_Value[21], m_Value[22], m_Value[23],
188 m_Value[24], m_Value[25], m_Value[26], m_Value[27],
189 m_Value[28], m_Value[29], m_Value[30], m_Value[31]
196 //------------------------------------------------------------------------------------------
200 const ASDCP::MXF::UTF16String&
201 ASDCP::MXF::UTF16String::operator=(const char* sz)
203 if ( sz == 0 || *sz == 0 )
213 const ASDCP::MXF::UTF16String&
214 ASDCP::MXF::UTF16String::operator=(const std::string& str)
222 ASDCP::MXF::UTF16String::EncodeString(char* str_buf, ui32_t buf_len) const
224 ui32_t write_len = Kumu::xmin(buf_len - 1, (ui32_t)size());
225 strncpy(str_buf, c_str(), write_len);
226 str_buf[write_len] = 0;
232 ASDCP::MXF::UTF16String::Unarchive(Kumu::MemIOReader* Reader)
235 const ui16_t* p = (ui16_t*)Reader->CurrentData();
236 ui32_t length = Reader->Remainder() / 2;
237 char mb_buf[MB_LEN_MAX+1];
239 for ( ui32_t i = 0; i < length; i++ )
241 int count = wctomb(mb_buf, KM_i16_BE(p[i]));
245 DefaultLogSink().Error("Unable to decode wide character 0x%04hx\n", p[i]);
249 assert(count <= MB_LEN_MAX);
251 this->append(mb_buf);
254 Reader->SkipOffset(length*2);
260 ASDCP::MXF::UTF16String::Archive(Kumu::MemIOWriter* Writer) const
262 if ( size() > IdentBufferLen )
264 DefaultLogSink().Error("String length exceeds maximum %u bytes\n", IdentBufferLen);
268 const char* mbp = c_str();
270 ui32_t remainder = size();
271 ui32_t length = size();
276 int count = mbtowc(&wcp, mbp+i, remainder);
280 DefaultLogSink().Error("Error decoding multi-byte sequence starting at offset %u\n", i);
283 else if ( count == 0 )
286 bool result = Writer->WriteUi16BE((ui16_t)wcp);
288 if ( result == false )
290 DefaultLogSink().Error("No more space in memory IO writer\n");
302 //------------------------------------------------------------------------------------------
307 #define TIMESTAMP_TO_SYSTIME(ts, t) \
308 (t)->wYear = (ts).Year; /* year */ \
309 (t)->wMonth = (ts).Month; /* month of year (1 - 12) */ \
310 (t)->wDay = (ts).Day; /* day of month (1 - 31) */ \
311 (t)->wHour = (ts).Hour; /* hours (0 - 23) */ \
312 (t)->wMinute = (ts).Minute; /* minutes (0 - 59) */ \
313 (t)->wSecond = (ts).Second; /* seconds (0 - 60) */ \
314 (t)->wDayOfWeek = 0; \
315 (t)->wMilliseconds = ((ts).Tick * 4);
317 #define SYSTIME_TO_TIMESTAMP(t, ts) \
318 (ts).Year = (t)->wYear; /* year */ \
319 (ts).Month = (t)->wMonth; /* month of year (1 - 12) */ \
320 (ts).Day = (t)->wDay; /* day of month (1 - 31) */ \
321 (ts).Hour = (t)->wHour; /* hours (0 - 23) */ \
322 (ts).Minute = (t)->wMinute; /* minutes (0 - 59) */ \
323 (ts).Second = (t)->wSecond; /* seconds (0 - 60) */ \
324 (ts).Tick = (t)->wMilliseconds / 4;
327 ASDCP::MXF::Timestamp::Timestamp() :
328 Year(0), Month(0), Day(0), Hour(0), Minute(0), Second(0), Tick(0)
331 GetSystemTime(&sys_time);
332 SYSTIME_TO_TIMESTAMP(&sys_time, *this);
337 ASDCP::MXF::Timestamp::operator<(const Timestamp& rhs) const
339 SYSTEMTIME lhst, rhst;
342 TIMESTAMP_TO_SYSTIME(*this, &lhst);
343 TIMESTAMP_TO_SYSTIME(rhs, &rhst);
344 SystemTimeToFileTime(&lhst, &lft);
345 SystemTimeToFileTime(&rhst, &rft);
346 return ( CompareFileTime(&lft, &rft) == -1 );
350 seconds_to_ns100(ui32_t seconds)
352 return ((ui64_t)seconds * 10000000);
357 ASDCP::MXF::Timestamp::AddDays(i32_t days)
359 SYSTEMTIME current_st;
361 ULARGE_INTEGER current_ul;
365 TIMESTAMP_TO_SYSTIME(*this, ¤t_st);
366 SystemTimeToFileTime(¤t_st, ¤t_ft);
367 memcpy(¤t_ul, ¤t_ft, sizeof(current_ul));
368 current_ul.QuadPart += ( seconds_to_ns100(86400) * (ui64_t)days );
369 memcpy(¤t_ft, ¤t_ul, sizeof(current_ft));
370 FileTimeToSystemTime(¤t_ft, ¤t_st);
371 SYSTIME_TO_TIMESTAMP(¤t_st, *this);
377 ASDCP::MXF::Timestamp::AddHours(i32_t hours)
379 SYSTEMTIME current_st;
381 ULARGE_INTEGER current_ul;
385 TIMESTAMP_TO_SYSTIME(*this, ¤t_st);
386 SystemTimeToFileTime(¤t_st, ¤t_ft);
387 memcpy(¤t_ul, ¤t_ft, sizeof(current_ul));
388 current_ul.QuadPart += ( seconds_to_ns100(3600) * (ui64_t)hours );
389 memcpy(¤t_ft, ¤t_ul, sizeof(current_ft));
390 FileTimeToSystemTime(¤t_ft, ¤t_st);
391 SYSTIME_TO_TIMESTAMP(¤t_st, *this);
399 #define TIMESTAMP_TO_TM(ts, t) \
400 (t)->tm_year = (ts).Year - 1900; /* year - 1900 */ \
401 (t)->tm_mon = (ts).Month - 1; /* month of year (0 - 11) */ \
402 (t)->tm_mday = (ts).Day; /* day of month (1 - 31) */ \
403 (t)->tm_hour = (ts).Hour; /* hours (0 - 23) */ \
404 (t)->tm_min = (ts).Minute; /* minutes (0 - 59) */ \
405 (t)->tm_sec = (ts).Second; /* seconds (0 - 60) */
407 #define TM_TO_TIMESTAMP(t, ts) \
408 (ts).Year = (t)->tm_year + 1900; /* year - 1900 */ \
409 (ts).Month = (t)->tm_mon + 1; /* month of year (0 - 11) */ \
410 (ts).Day = (t)->tm_mday; /* day of month (1 - 31) */ \
411 (ts).Hour = (t)->tm_hour; /* hours (0 - 23) */ \
412 (ts).Minute = (t)->tm_min; /* minutes (0 - 59) */ \
413 (ts).Second = (t)->tm_sec; /* seconds (0 - 60) */
416 ASDCP::MXF::Timestamp::Timestamp() :
417 Year(0), Month(0), Day(0), Hour(0), Minute(0), Second(0)
419 time_t t_now = time(0);
420 struct tm* now = gmtime(&t_now);
421 TM_TO_TIMESTAMP(now, *this);
426 ASDCP::MXF::Timestamp::operator<(const Timestamp& rhs) const
428 struct tm lhtm, rhtm;
429 TIMESTAMP_TO_TM(*this, &lhtm);
430 TIMESTAMP_TO_TM(rhs, &rhtm);
431 return ( timegm(&lhtm) < timegm(&rhtm) );
436 ASDCP::MXF::Timestamp::AddDays(i32_t days)
442 TIMESTAMP_TO_TM(*this, ¤t);
443 time_t adj_time = timegm(¤t);
444 adj_time += 86400 * days;
445 struct tm* now = gmtime(&adj_time);
446 TM_TO_TIMESTAMP(now, *this);
452 ASDCP::MXF::Timestamp::AddHours(i32_t hours)
458 TIMESTAMP_TO_TM(*this, ¤t);
459 time_t adj_time = timegm(¤t);
460 adj_time += 3600 * hours;
461 struct tm* now = gmtime(&adj_time);
462 TM_TO_TIMESTAMP(now, *this);
469 ASDCP::MXF::Timestamp::Timestamp(const Timestamp& rhs) : IArchive()
479 ASDCP::MXF::Timestamp::~Timestamp()
484 const ASDCP::MXF::Timestamp&
485 ASDCP::MXF::Timestamp::operator=(const Timestamp& rhs)
498 ASDCP::MXF::Timestamp::operator==(const Timestamp& rhs) const
500 if ( Year == rhs.Year
501 && Month == rhs.Month
504 && Minute == rhs.Minute
505 && Second == rhs.Second )
513 ASDCP::MXF::Timestamp::operator!=(const Timestamp& rhs) const
515 if ( Year != rhs.Year
516 || Month != rhs.Month
519 || Minute != rhs.Minute
520 || Second != rhs.Second )
528 ASDCP::MXF::Timestamp::EncodeString(char* str_buf, ui32_t buf_len) const
530 // 2004-05-01 13:20:00.000
531 snprintf(str_buf, buf_len,
532 "%04hu-%02hu-%02hu %02hu:%02hu:%02hu.000",
533 Year, Month, Day, Hour, Minute, Second);
538 //------------------------------------------------------------------------------------------
541 ASDCP::MXF::TLVReader::TLVReader(const byte_t* p, ui32_t c, IPrimerLookup* PrimerLookup) :
542 MemIOReader(p, c), m_Lookup(PrimerLookup)
544 Result_t result = RESULT_OK;
546 while ( Remainder() > 0 && ASDCP_SUCCESS(result) )
551 if ( MemIOReader::ReadUi8(&Tag.a) )
552 if ( MemIOReader::ReadUi8(&Tag.b) )
553 if ( MemIOReader::ReadUi16BE(&pkt_len) )
555 m_ElementMap.insert(TagMap::value_type(Tag, ItemInfo(m_size, pkt_len)));
556 if ( SkipOffset(pkt_len) )
560 DefaultLogSink().Error("Malformed Set\n");
561 m_ElementMap.clear();
562 result = RESULT_KLV_CODING;
568 ASDCP::MXF::TLVReader::FindTL(const MDDEntry& Entry)
572 DefaultLogSink().Error("No Lookup service\n");
578 if ( m_Lookup->TagForKey(Entry.ul, TmpTag) != RESULT_OK )
580 if ( Entry.tag.a == 0 )
582 // DefaultLogSink().Debug("No such UL in this TL list: %s (%02x %02x)\n",
583 // Entry.name, Entry.tag.a, Entry.tag.b);
590 TagMap::iterator e_i = m_ElementMap.find(TmpTag);
592 if ( e_i != m_ElementMap.end() )
594 m_size = (*e_i).second.first;
595 m_capacity = m_size + (*e_i).second.second;
599 // DefaultLogSink().Debug("Not Found (%02x %02x): %s\n", TmpTag.a, TmpTag.b, Entry.name);
605 ASDCP::MXF::TLVReader::ReadObject(const MDDEntry& Entry, Kumu::IArchive* Object)
607 ASDCP_TEST_NULL(Object);
611 if ( m_size < m_capacity ) // don't try to unarchive an empty item
612 return Object->Unarchive(this) ? RESULT_OK : RESULT_KLV_CODING;
620 ASDCP::MXF::TLVReader::ReadUi8(const MDDEntry& Entry, ui8_t* value)
622 ASDCP_TEST_NULL(value);
625 return MemIOReader::ReadUi8(value) ? RESULT_OK : RESULT_KLV_CODING;
632 ASDCP::MXF::TLVReader::ReadUi16(const MDDEntry& Entry, ui16_t* value)
634 ASDCP_TEST_NULL(value);
637 return MemIOReader::ReadUi16BE(value) ? RESULT_OK : RESULT_KLV_CODING;
644 ASDCP::MXF::TLVReader::ReadUi32(const MDDEntry& Entry, ui32_t* value)
646 ASDCP_TEST_NULL(value);
649 return MemIOReader::ReadUi32BE(value) ? RESULT_OK : RESULT_KLV_CODING;
656 ASDCP::MXF::TLVReader::ReadUi64(const MDDEntry& Entry, ui64_t* value)
658 ASDCP_TEST_NULL(value);
661 return MemIOReader::ReadUi64BE(value) ? RESULT_OK : RESULT_KLV_CODING;
666 //------------------------------------------------------------------------------------------
669 ASDCP::MXF::TLVWriter::TLVWriter(byte_t* p, ui32_t c, IPrimerLookup* PrimerLookup) :
670 MemIOWriter(p, c), m_Lookup(PrimerLookup)
677 ASDCP::MXF::TLVWriter::WriteTag(const MDDEntry& Entry)
681 DefaultLogSink().Error("No Primer object available\n");
687 if ( m_Lookup->InsertTag(Entry, TmpTag) != RESULT_OK )
689 DefaultLogSink().Error("No tag for entry %s\n", Entry.name);
693 if ( ! MemIOWriter::WriteUi8(TmpTag.a) ) return RESULT_KLV_CODING;
694 if ( ! MemIOWriter::WriteUi8(TmpTag.b) ) return RESULT_KLV_CODING;
700 ASDCP::MXF::TLVWriter::WriteObject(const MDDEntry& Entry, Kumu::IArchive* Object)
702 ASDCP_TEST_NULL(Object);
704 if ( Entry.optional && ! Object->HasValue() )
707 Result_t result = WriteTag(Entry);
709 if ( ASDCP_SUCCESS(result) )
711 // write a temp length
712 byte_t* l_p = CurrentData();
714 if ( ! MemIOWriter::WriteUi16BE(0) ) return RESULT_KLV_CODING;
716 ui32_t before = Length();
717 if ( ! Object->Archive(this) ) return RESULT_KLV_CODING;
718 if ( (Length() - before) > 0xffffL ) return RESULT_KLV_CODING;
719 Kumu::i2p<ui16_t>(KM_i16_BE(Length() - before), l_p);
727 ASDCP::MXF::TLVWriter::WriteUi8(const MDDEntry& Entry, ui8_t* value)
729 ASDCP_TEST_NULL(value);
730 Result_t result = WriteTag(Entry);
732 if ( ASDCP_SUCCESS(result) )
734 if ( ! MemIOWriter::WriteUi16BE(sizeof(ui8_t)) ) return RESULT_KLV_CODING;
735 if ( ! MemIOWriter::WriteUi8(*value) ) return RESULT_KLV_CODING;
743 ASDCP::MXF::TLVWriter::WriteUi16(const MDDEntry& Entry, ui16_t* value)
745 ASDCP_TEST_NULL(value);
746 Result_t result = WriteTag(Entry);
748 if ( KM_SUCCESS(result) )
750 if ( ! MemIOWriter::WriteUi16BE(sizeof(ui16_t)) ) return RESULT_KLV_CODING;
751 if ( ! MemIOWriter::WriteUi16BE(*value) ) return RESULT_KLV_CODING;
759 ASDCP::MXF::TLVWriter::WriteUi32(const MDDEntry& Entry, ui32_t* value)
761 ASDCP_TEST_NULL(value);
762 Result_t result = WriteTag(Entry);
764 if ( KM_SUCCESS(result) )
766 if ( ! MemIOWriter::WriteUi16BE(sizeof(ui32_t)) ) return RESULT_KLV_CODING;
767 if ( ! MemIOWriter::WriteUi32BE(*value) ) return RESULT_KLV_CODING;
775 ASDCP::MXF::TLVWriter::WriteUi64(const MDDEntry& Entry, ui64_t* value)
777 ASDCP_TEST_NULL(value);
778 Result_t result = WriteTag(Entry);
780 if ( KM_SUCCESS(result) )
782 if ( ! MemIOWriter::WriteUi16BE(sizeof(ui64_t)) ) return RESULT_KLV_CODING;
783 if ( ! MemIOWriter::WriteUi64BE(*value) ) return RESULT_KLV_CODING;
790 //----------------------------------------------------------------------------------------------------
793 ASDCP::MXF::Raw::Raw()
798 ASDCP::MXF::Raw::~Raw()
804 ASDCP::MXF::Raw::Unarchive(Kumu::MemIOReader* Reader)
806 ui32_t payload_size = Reader->Remainder();
807 if ( payload_size == 0 ) return false;
808 if ( KM_FAILURE(Capacity(payload_size)) ) return false;
810 memcpy(Data(), Reader->CurrentData(), payload_size);
811 Length(payload_size);
817 ASDCP::MXF::Raw::Archive(Kumu::MemIOWriter* Writer) const
819 return Writer->WriteRaw(RoData(), Length());
824 ASDCP::MXF::Raw::EncodeString(char* str_buf, ui32_t buf_len) const
827 Kumu::bin2hex(RoData(), Length(), str_buf, buf_len);