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::EncodeString(char* str_buf, ui32_t buf_len) const
44 if ( buf_len > 38 ) // room for dotted notation?
46 snprintf(str_buf, buf_len,
47 "%02x%02x%02x%02x.%02x%02x.%02x%02x.%02x%02x%02x%02x.%02x%02x%02x%02x",
48 m_Value[0], m_Value[1], m_Value[2], m_Value[3],
49 m_Value[4], m_Value[5], m_Value[6], m_Value[7],
50 m_Value[8], m_Value[9], m_Value[10], m_Value[11],
51 m_Value[12], m_Value[13], m_Value[14], m_Value[15]
56 else if ( buf_len > 32 ) // room for compact?
58 snprintf(str_buf, buf_len,
59 "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
60 m_Value[0], m_Value[1], m_Value[2], m_Value[3],
61 m_Value[4], m_Value[5], m_Value[6], m_Value[7],
62 m_Value[8], m_Value[9], m_Value[10], m_Value[11],
63 m_Value[12], m_Value[13], m_Value[14], m_Value[15]
74 ASDCP::UMID::MakeUMID(int Type)
77 Kumu::GenRandomValue(AssetID);
78 MakeUMID(Type, AssetID);
83 ASDCP::UMID::MakeUMID(int Type, const UUID& AssetID)
85 // Set the non-varying base of the UMID
86 static const byte_t UMIDBase[10] = { 0x06, 0x0a, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
87 memcpy(m_Value, UMIDBase, 10);
88 m_Value[10] = Type; // Material Type
89 m_Value[12] = 0x13; // length
91 // preserved for compatibility with mfxlib
92 if( Type > 4 ) m_Value[7] = 5;
93 m_Value[11] = 0x20; // UUID/UL method, number gen undefined
96 m_Value[13] = m_Value[14] = m_Value[15] = 0;
98 memcpy(&m_Value[16], AssetID.Value(), AssetID.Size());
103 // Write the timestamp value to the given buffer in the form 2004-05-01 13:20:00.000
104 // returns 0 if the buffer is smaller than DateTimeLen
106 ASDCP::UMID::EncodeString(char* str_buf, ui32_t buf_len) const
110 snprintf(str_buf, buf_len, "[%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]
117 ui32_t offset = strlen(str_buf);
119 if ( ( m_Value[8] & 0x80 ) == 0 )
121 // half-swapped UL, use [bbaa9988.ddcc.ffee.00010203.04050607]
122 snprintf(str_buf + offset, buf_len - offset,
123 "[%02x%02x%02x%02x.%02x%02x.%02x%02x.%02x%02x%02x%02x.%02x%02x%02x%02x]",
124 m_Value[24], m_Value[25], m_Value[26], m_Value[27],
125 m_Value[28], m_Value[29], m_Value[30], m_Value[31],
126 m_Value[16], m_Value[17], m_Value[18], m_Value[19],
127 m_Value[20], m_Value[21], m_Value[22], m_Value[23]
132 // UUID, use {00112233-4455-6677-8899-aabbccddeeff}
133 snprintf(str_buf + offset, buf_len - offset,
134 "{%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
135 m_Value[16], m_Value[17], m_Value[18], m_Value[19],
136 m_Value[20], m_Value[21], m_Value[22], m_Value[23],
137 m_Value[24], m_Value[25], m_Value[26], m_Value[27],
138 m_Value[28], m_Value[29], m_Value[30], m_Value[31]
145 //------------------------------------------------------------------------------------------
149 const ASDCP::MXF::UTF16String&
150 ASDCP::MXF::UTF16String::operator=(const char* sz)
152 if ( sz == 0 || *sz == 0 )
162 const ASDCP::MXF::UTF16String&
163 ASDCP::MXF::UTF16String::operator=(const std::string& str)
171 ASDCP::MXF::UTF16String::EncodeString(char* str_buf, ui32_t buf_len) const
173 ui32_t write_len = Kumu::xmin(buf_len - 1, (ui32_t)size());
174 strncpy(str_buf, c_str(), write_len);
175 str_buf[write_len] = 0;
181 ASDCP::MXF::UTF16String::Unarchive(Kumu::MemIOReader* Reader)
184 const ui16_t* p = (ui16_t*)Reader->CurrentData();
185 ui32_t length = Reader->Remainder() / 2;
186 char mb_buf[MB_LEN_MAX+1];
188 for ( ui32_t i = 0; i < length; i++ )
190 int count = wctomb(mb_buf, KM_i16_BE(p[i]));
194 DefaultLogSink().Error("Unable to decode wide character 0x%04hx\n", p[i]);
198 assert(count <= MB_LEN_MAX);
200 this->append(mb_buf);
203 Reader->SkipOffset(length*2);
209 ASDCP::MXF::UTF16String::Archive(Kumu::MemIOWriter* Writer) const
211 if ( size() > IdentBufferLen )
213 DefaultLogSink().Error("String length exceeds maximum %u bytes\n", IdentBufferLen);
217 const char* mbp = c_str();
219 ui32_t remainder = size();
220 ui32_t length = size();
225 int count = mbtowc(&wcp, mbp+i, remainder);
229 DefaultLogSink().Error("Error decoding multi-byte sequence starting at offset %u\n", i);
232 else if ( count == 0 )
235 bool result = Writer->WriteUi16BE((ui16_t)wcp);
237 if ( result == false )
239 DefaultLogSink().Error("No more space in memory IO writer\n");
251 //------------------------------------------------------------------------------------------
256 #define TIMESTAMP_TO_SYSTIME(ts, t) \
257 (t)->wYear = (ts).Year; /* year */ \
258 (t)->wMonth = (ts).Month; /* month of year (1 - 12) */ \
259 (t)->wDay = (ts).Day; /* day of month (1 - 31) */ \
260 (t)->wHour = (ts).Hour; /* hours (0 - 23) */ \
261 (t)->wMinute = (ts).Minute; /* minutes (0 - 59) */ \
262 (t)->wSecond = (ts).Second; /* seconds (0 - 60) */ \
263 (t)->wDayOfWeek = 0; \
264 (t)->wMilliseconds = ((ts).Tick * 4);
266 #define SYSTIME_TO_TIMESTAMP(t, ts) \
267 (ts).Year = (t)->wYear; /* year */ \
268 (ts).Month = (t)->wMonth; /* month of year (1 - 12) */ \
269 (ts).Day = (t)->wDay; /* day of month (1 - 31) */ \
270 (ts).Hour = (t)->wHour; /* hours (0 - 23) */ \
271 (ts).Minute = (t)->wMinute; /* minutes (0 - 59) */ \
272 (ts).Second = (t)->wSecond; /* seconds (0 - 60) */ \
273 (ts).Tick = (t)->wMilliseconds / 4;
276 ASDCP::MXF::Timestamp::Timestamp() :
277 Year(0), Month(0), Day(0), Hour(0), Minute(0), Second(0), Tick(0)
280 GetSystemTime(&sys_time);
281 SYSTIME_TO_TIMESTAMP(&sys_time, *this);
286 ASDCP::MXF::Timestamp::operator<(const Timestamp& rhs) const
288 SYSTEMTIME lhst, rhst;
291 TIMESTAMP_TO_SYSTIME(*this, &lhst);
292 TIMESTAMP_TO_SYSTIME(rhs, &rhst);
293 SystemTimeToFileTime(&lhst, &lft);
294 SystemTimeToFileTime(&rhst, &rft);
295 return ( CompareFileTime(&lft, &rft) == -1 );
299 seconds_to_ns100(ui32_t seconds)
301 return ((ui64_t)seconds * 10000000);
306 ASDCP::MXF::Timestamp::AddDays(i32_t days)
308 SYSTEMTIME current_st;
310 ULARGE_INTEGER current_ul;
314 TIMESTAMP_TO_SYSTIME(*this, ¤t_st);
315 SystemTimeToFileTime(¤t_st, ¤t_ft);
316 memcpy(¤t_ul, ¤t_ft, sizeof(current_ul));
317 current_ul.QuadPart += ( seconds_to_ns100(86400) * (ui64_t)days );
318 memcpy(¤t_ft, ¤t_ul, sizeof(current_ft));
319 FileTimeToSystemTime(¤t_ft, ¤t_st);
320 SYSTIME_TO_TIMESTAMP(¤t_st, *this);
326 ASDCP::MXF::Timestamp::AddHours(i32_t hours)
328 SYSTEMTIME current_st;
330 ULARGE_INTEGER current_ul;
334 TIMESTAMP_TO_SYSTIME(*this, ¤t_st);
335 SystemTimeToFileTime(¤t_st, ¤t_ft);
336 memcpy(¤t_ul, ¤t_ft, sizeof(current_ul));
337 current_ul.QuadPart += ( seconds_to_ns100(3600) * (ui64_t)hours );
338 memcpy(¤t_ft, ¤t_ul, sizeof(current_ft));
339 FileTimeToSystemTime(¤t_ft, ¤t_st);
340 SYSTIME_TO_TIMESTAMP(¤t_st, *this);
348 #define TIMESTAMP_TO_TM(ts, t) \
349 (t)->tm_year = (ts).Year - 1900; /* year - 1900 */ \
350 (t)->tm_mon = (ts).Month - 1; /* month of year (0 - 11) */ \
351 (t)->tm_mday = (ts).Day; /* day of month (1 - 31) */ \
352 (t)->tm_hour = (ts).Hour; /* hours (0 - 23) */ \
353 (t)->tm_min = (ts).Minute; /* minutes (0 - 59) */ \
354 (t)->tm_sec = (ts).Second; /* seconds (0 - 60) */
356 #define TM_TO_TIMESTAMP(t, ts) \
357 (ts).Year = (t)->tm_year + 1900; /* year - 1900 */ \
358 (ts).Month = (t)->tm_mon + 1; /* month of year (0 - 11) */ \
359 (ts).Day = (t)->tm_mday; /* day of month (1 - 31) */ \
360 (ts).Hour = (t)->tm_hour; /* hours (0 - 23) */ \
361 (ts).Minute = (t)->tm_min; /* minutes (0 - 59) */ \
362 (ts).Second = (t)->tm_sec; /* seconds (0 - 60) */
365 ASDCP::MXF::Timestamp::Timestamp() :
366 Year(0), Month(0), Day(0), Hour(0), Minute(0), Second(0)
368 time_t t_now = time(0);
369 struct tm* now = gmtime(&t_now);
370 TM_TO_TIMESTAMP(now, *this);
375 ASDCP::MXF::Timestamp::operator<(const Timestamp& rhs) const
377 struct tm lhtm, rhtm;
378 TIMESTAMP_TO_TM(*this, &lhtm);
379 TIMESTAMP_TO_TM(rhs, &rhtm);
380 return ( timegm(&lhtm) < timegm(&rhtm) );
385 ASDCP::MXF::Timestamp::AddDays(i32_t days)
391 TIMESTAMP_TO_TM(*this, ¤t);
392 time_t adj_time = timegm(¤t);
393 adj_time += 86400 * days;
394 struct tm* now = gmtime(&adj_time);
395 TM_TO_TIMESTAMP(now, *this);
401 ASDCP::MXF::Timestamp::AddHours(i32_t hours)
407 TIMESTAMP_TO_TM(*this, ¤t);
408 time_t adj_time = timegm(¤t);
409 adj_time += 3600 * hours;
410 struct tm* now = gmtime(&adj_time);
411 TM_TO_TIMESTAMP(now, *this);
418 ASDCP::MXF::Timestamp::Timestamp(const Timestamp& rhs) : IArchive()
428 ASDCP::MXF::Timestamp::~Timestamp()
433 const ASDCP::MXF::Timestamp&
434 ASDCP::MXF::Timestamp::operator=(const Timestamp& rhs)
447 ASDCP::MXF::Timestamp::operator==(const Timestamp& rhs) const
449 if ( Year == rhs.Year
450 && Month == rhs.Month
453 && Minute == rhs.Minute
454 && Second == rhs.Second )
462 ASDCP::MXF::Timestamp::operator!=(const Timestamp& rhs) const
464 if ( Year != rhs.Year
465 || Month != rhs.Month
468 || Minute != rhs.Minute
469 || Second != rhs.Second )
477 ASDCP::MXF::Timestamp::EncodeString(char* str_buf, ui32_t buf_len) const
479 // 2004-05-01 13:20:00.000
480 snprintf(str_buf, buf_len,
481 "%04hu-%02hu-%02hu %02hu:%02hu:%02hu.000",
482 Year, Month, Day, Hour, Minute, Second);
487 //------------------------------------------------------------------------------------------
490 ASDCP::MXF::TLVReader::TLVReader(const byte_t* p, ui32_t c, IPrimerLookup* PrimerLookup) :
491 MemIOReader(p, c), m_Lookup(PrimerLookup)
493 Result_t result = RESULT_OK;
495 while ( Remainder() > 0 && ASDCP_SUCCESS(result) )
500 if ( MemIOReader::ReadUi8(&Tag.a) )
501 if ( MemIOReader::ReadUi8(&Tag.b) )
502 if ( MemIOReader::ReadUi16BE(&pkt_len) )
504 m_ElementMap.insert(TagMap::value_type(Tag, ItemInfo(m_size, pkt_len)));
505 if ( SkipOffset(pkt_len) )
509 DefaultLogSink().Error("Malformed Set\n");
510 m_ElementMap.clear();
511 result = RESULT_KLV_CODING;
517 ASDCP::MXF::TLVReader::FindTL(const MDDEntry& Entry)
521 DefaultLogSink().Error("No Lookup service\n");
527 if ( m_Lookup->TagForKey(Entry.ul, TmpTag) != RESULT_OK )
529 if ( Entry.tag.a == 0 )
531 // DefaultLogSink().Debug("No such UL in this TL list: %s (%02x %02x)\n",
532 // Entry.name, Entry.tag.a, Entry.tag.b);
539 TagMap::iterator e_i = m_ElementMap.find(TmpTag);
541 if ( e_i != m_ElementMap.end() )
543 m_size = (*e_i).second.first;
544 m_capacity = m_size + (*e_i).second.second;
548 // DefaultLogSink().Debug("Not Found (%02x %02x): %s\n", TmpTag.a, TmpTag.b, Entry.name);
554 ASDCP::MXF::TLVReader::ReadObject(const MDDEntry& Entry, Kumu::IArchive* Object)
556 ASDCP_TEST_NULL(Object);
560 if ( m_size < m_capacity ) // don't try to unarchive an empty item
561 return Object->Unarchive(this) ? RESULT_OK : RESULT_KLV_CODING;
569 ASDCP::MXF::TLVReader::ReadUi8(const MDDEntry& Entry, ui8_t* value)
571 ASDCP_TEST_NULL(value);
574 return MemIOReader::ReadUi8(value) ? RESULT_OK : RESULT_KLV_CODING;
581 ASDCP::MXF::TLVReader::ReadUi16(const MDDEntry& Entry, ui16_t* value)
583 ASDCP_TEST_NULL(value);
586 return MemIOReader::ReadUi16BE(value) ? RESULT_OK : RESULT_KLV_CODING;
593 ASDCP::MXF::TLVReader::ReadUi32(const MDDEntry& Entry, ui32_t* value)
595 ASDCP_TEST_NULL(value);
598 return MemIOReader::ReadUi32BE(value) ? RESULT_OK : RESULT_KLV_CODING;
605 ASDCP::MXF::TLVReader::ReadUi64(const MDDEntry& Entry, ui64_t* value)
607 ASDCP_TEST_NULL(value);
610 return MemIOReader::ReadUi64BE(value) ? RESULT_OK : RESULT_KLV_CODING;
615 //------------------------------------------------------------------------------------------
618 ASDCP::MXF::TLVWriter::TLVWriter(byte_t* p, ui32_t c, IPrimerLookup* PrimerLookup) :
619 MemIOWriter(p, c), m_Lookup(PrimerLookup)
626 ASDCP::MXF::TLVWriter::WriteTag(const MDDEntry& Entry)
630 DefaultLogSink().Error("No Primer object available\n");
636 if ( m_Lookup->InsertTag(Entry, TmpTag) != RESULT_OK )
638 DefaultLogSink().Error("No tag for entry %s\n", Entry.name);
642 if ( ! MemIOWriter::WriteUi8(TmpTag.a) ) return RESULT_KLV_CODING;
643 if ( ! MemIOWriter::WriteUi8(TmpTag.b) ) return RESULT_KLV_CODING;
649 ASDCP::MXF::TLVWriter::WriteObject(const MDDEntry& Entry, Kumu::IArchive* Object)
651 ASDCP_TEST_NULL(Object);
653 if ( Entry.optional && ! Object->HasValue() )
656 Result_t result = WriteTag(Entry);
658 if ( ASDCP_SUCCESS(result) )
660 // write a temp length
661 byte_t* l_p = CurrentData();
663 if ( ! MemIOWriter::WriteUi16BE(0) ) return RESULT_KLV_CODING;
665 ui32_t before = Length();
666 if ( ! Object->Archive(this) ) return RESULT_KLV_CODING;
667 if ( (Length() - before) > 0xffffL ) return RESULT_KLV_CODING;
668 Kumu::i2p<ui16_t>(KM_i16_BE(Length() - before), l_p);
676 ASDCP::MXF::TLVWriter::WriteUi8(const MDDEntry& Entry, ui8_t* value)
678 ASDCP_TEST_NULL(value);
679 Result_t result = WriteTag(Entry);
681 if ( ASDCP_SUCCESS(result) )
683 if ( ! MemIOWriter::WriteUi16BE(sizeof(ui8_t)) ) return RESULT_KLV_CODING;
684 if ( ! MemIOWriter::WriteUi8(*value) ) return RESULT_KLV_CODING;
692 ASDCP::MXF::TLVWriter::WriteUi16(const MDDEntry& Entry, ui16_t* value)
694 ASDCP_TEST_NULL(value);
695 Result_t result = WriteTag(Entry);
697 if ( KM_SUCCESS(result) )
699 if ( ! MemIOWriter::WriteUi16BE(sizeof(ui16_t)) ) return RESULT_KLV_CODING;
700 if ( ! MemIOWriter::WriteUi16BE(*value) ) return RESULT_KLV_CODING;
708 ASDCP::MXF::TLVWriter::WriteUi32(const MDDEntry& Entry, ui32_t* value)
710 ASDCP_TEST_NULL(value);
711 Result_t result = WriteTag(Entry);
713 if ( KM_SUCCESS(result) )
715 if ( ! MemIOWriter::WriteUi16BE(sizeof(ui32_t)) ) return RESULT_KLV_CODING;
716 if ( ! MemIOWriter::WriteUi32BE(*value) ) return RESULT_KLV_CODING;
724 ASDCP::MXF::TLVWriter::WriteUi64(const MDDEntry& Entry, ui64_t* value)
726 ASDCP_TEST_NULL(value);
727 Result_t result = WriteTag(Entry);
729 if ( KM_SUCCESS(result) )
731 if ( ! MemIOWriter::WriteUi16BE(sizeof(ui64_t)) ) return RESULT_KLV_CODING;
732 if ( ! MemIOWriter::WriteUi64BE(*value) ) return RESULT_KLV_CODING;
739 //----------------------------------------------------------------------------------------------------
742 ASDCP::MXF::Raw::Raw()
747 ASDCP::MXF::Raw::~Raw()
753 ASDCP::MXF::Raw::Unarchive(Kumu::MemIOReader* Reader)
755 ui32_t payload_size = Reader->Remainder();
756 if ( payload_size == 0 ) return false;
757 if ( KM_FAILURE(Capacity(payload_size)) ) return false;
759 memcpy(Data(), Reader->CurrentData(), payload_size);
760 Length(payload_size);
766 ASDCP::MXF::Raw::Archive(Kumu::MemIOWriter* Writer) const
768 return Writer->WriteRaw(RoData(), Length());
773 ASDCP::MXF::Raw::EncodeString(char* str_buf, ui32_t buf_len) const
776 Kumu::bin2hex(RoData(), Length(), str_buf, buf_len);