2 Copyright (c) 2005-2006, 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
35 using Kumu::DefaultLogSink;
37 //------------------------------------------------------------------------------------------
41 ASDCP::UL::EncodeString(char* str_buf, ui32_t buf_len) const
43 if ( buf_len > 38 ) // room for dotted notation?
45 snprintf(str_buf, buf_len,
46 "%02x%02x%02x%02x.%02x%02x.%02x%02x.%02x%02x%02x%02x.%02x%02x%02x%02x",
47 m_Value[0], m_Value[1], m_Value[2], m_Value[3],
48 m_Value[4], m_Value[5], m_Value[6], m_Value[7],
49 m_Value[8], m_Value[9], m_Value[10], m_Value[11],
50 m_Value[12], m_Value[13], m_Value[14], m_Value[15]
55 else if ( buf_len > 32 ) // room for compact?
57 snprintf(str_buf, buf_len,
58 "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
59 m_Value[0], m_Value[1], m_Value[2], m_Value[3],
60 m_Value[4], m_Value[5], m_Value[6], m_Value[7],
61 m_Value[8], m_Value[9], m_Value[10], m_Value[11],
62 m_Value[12], m_Value[13], m_Value[14], m_Value[15]
73 ASDCP::UMID::MakeUMID(int Type)
76 Kumu::GenRandomValue(AssetID);
77 MakeUMID(Type, AssetID);
82 ASDCP::UMID::MakeUMID(int Type, const UUID& AssetID)
84 // Set the non-varying base of the UMID
85 static const byte_t UMIDBase[10] = { 0x06, 0x0a, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
86 memcpy(m_Value, UMIDBase, 10);
87 m_Value[10] = Type; // Material Type
88 m_Value[12] = 0x13; // length
90 // preserved for compatibility with mfxlib
91 if( Type > 4 ) m_Value[7] = 5;
92 m_Value[11] = 0x20; // UUID/UL method, number gen undefined
95 m_Value[13] = m_Value[14] = m_Value[15] = 0;
97 memcpy(&m_Value[16], AssetID.Value(), AssetID.Size());
101 // Write the timestamp value to the given buffer in the form 2004-05-01 13:20:00.000
102 // returns 0 if the buffer is smaller than DateTimeLen
104 ASDCP::UMID::EncodeString(char* str_buf, ui32_t buf_len) const
108 snprintf(str_buf, buf_len, "[%02x%02x%02x%02x.%02x%02x.%02x%02x.%02x%02x%02x%02x],%02x,%02x,%02x,%02x,",
109 m_Value[0], m_Value[1], m_Value[2], m_Value[3],
110 m_Value[4], m_Value[5], m_Value[6], m_Value[7],
111 m_Value[8], m_Value[9], m_Value[10], m_Value[11],
112 m_Value[12], m_Value[13], m_Value[14], m_Value[15]
115 ui32_t offset = strlen(str_buf);
117 if ( ( m_Value[8] & 0x80 ) == 0 )
119 // half-swapped UL, use [bbaa9988.ddcc.ffee.00010203.04050607]
120 snprintf(str_buf + offset, buf_len - offset,
121 "[%02x%02x%02x%02x.%02x%02x.%02x%02x.%02x%02x%02x%02x.%02x%02x%02x%02x]",
122 m_Value[24], m_Value[25], m_Value[26], m_Value[27],
123 m_Value[28], m_Value[29], m_Value[30], m_Value[31],
124 m_Value[16], m_Value[17], m_Value[18], m_Value[19],
125 m_Value[20], m_Value[21], m_Value[22], m_Value[23]
130 // UUID, use {00112233-4455-6677-8899-aabbccddeeff}
131 snprintf(str_buf + offset, buf_len - offset,
132 "{%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
133 m_Value[16], m_Value[17], m_Value[18], m_Value[19],
134 m_Value[20], m_Value[21], m_Value[22], m_Value[23],
135 m_Value[24], m_Value[25], m_Value[26], m_Value[27],
136 m_Value[28], m_Value[29], m_Value[30], m_Value[31]
143 //------------------------------------------------------------------------------------------
146 const ASDCP::MXF::UTF16String&
147 ASDCP::MXF::UTF16String::operator=(const char* sz)
149 if ( sz == 0 || *sz == 0 )
156 ui32_t len = Kumu::xmin((ui32_t)strlen(sz), (IdentBufferLen - 1));
158 memcpy(m_buffer, sz, m_length);
159 m_buffer[m_length] = 0;
168 ASDCP::MXF::UTF16String::Unarchive(Kumu::MemIOReader* Reader)
170 const byte_t* p = Reader->CurrentData();
171 m_length = Reader->Remainder();
172 assert(m_length % 2 == 0);
174 assert(IdentBufferLen >= m_length);
177 for ( i = 0; i < m_length; i++ )
178 m_buffer[i] = p[(i*2)+1];
182 Reader->SkipOffset(m_length*2);
188 ASDCP::MXF::UTF16String::Archive(Kumu::MemIOWriter* Writer) const
190 byte_t* p = Writer->Data() + Writer->Length();
192 memset(p, 0, (m_length*2)+2);
194 for ( i = 0; i < m_length; i++ )
195 p[(i*2)+1] = m_buffer[i];
197 Writer->AddOffset(m_length * 2);
202 //------------------------------------------------------------------------------------------
207 #define TIMESTAMP_TO_SYSTIME(ts, t) \
208 (t)->wYear = (ts).Year; /* year */ \
209 (t)->wMonth = (ts).Month; /* month of year (1 - 12) */ \
210 (t)->wDay = (ts).Day; /* day of month (1 - 31) */ \
211 (t)->wHour = (ts).Hour; /* hours (0 - 23) */ \
212 (t)->wMinute = (ts).Minute; /* minutes (0 - 59) */ \
213 (t)->wSecond = (ts).Second; /* seconds (0 - 60) */ \
214 (t)->wDayOfWeek = 0; \
215 (t)->wMilliseconds = ((ts).Tick * 4);
217 #define SYSTIME_TO_TIMESTAMP(t, ts) \
218 (ts).Year = (t)->wYear; /* year */ \
219 (ts).Month = (t)->wMonth; /* month of year (1 - 12) */ \
220 (ts).Day = (t)->wDay; /* day of month (1 - 31) */ \
221 (ts).Hour = (t)->wHour; /* hours (0 - 23) */ \
222 (ts).Minute = (t)->wMinute; /* minutes (0 - 59) */ \
223 (ts).Second = (t)->wSecond; /* seconds (0 - 60) */ \
224 (ts).Tick = (t)->wMilliseconds / 4;
227 ASDCP::MXF::Timestamp::Timestamp() :
228 Year(0), Month(0), Day(0), Hour(0), Minute(0), Second(0), Tick(0)
231 GetSystemTime(&sys_time);
232 SYSTIME_TO_TIMESTAMP(&sys_time, *this);
237 ASDCP::MXF::Timestamp::operator<(const Timestamp& rhs) const
239 SYSTEMTIME lhst, rhst;
242 TIMESTAMP_TO_SYSTIME(*this, &lhst);
243 TIMESTAMP_TO_SYSTIME(rhs, &rhst);
244 SystemTimeToFileTime(&lhst, &lft);
245 SystemTimeToFileTime(&rhst, &rft);
246 return ( CompareFileTime(&lft, &rft) == -1 );
250 seconds_to_ns100(ui32_t seconds)
252 return ((ui64_t)seconds * 10000000);
257 ASDCP::MXF::Timestamp::AddDays(i32_t days)
259 SYSTEMTIME current_st;
261 ULARGE_INTEGER current_ul;
265 TIMESTAMP_TO_SYSTIME(*this, ¤t_st);
266 SystemTimeToFileTime(¤t_st, ¤t_ft);
267 memcpy(¤t_ul, ¤t_ft, sizeof(current_ul));
268 current_ul.QuadPart += ( seconds_to_ns100(86400) * (ui64_t)days );
269 memcpy(¤t_ft, ¤t_ul, sizeof(current_ft));
270 FileTimeToSystemTime(¤t_ft, ¤t_st);
271 SYSTIME_TO_TIMESTAMP(¤t_st, *this);
277 ASDCP::MXF::Timestamp::AddHours(i32_t hours)
279 SYSTEMTIME current_st;
281 ULARGE_INTEGER current_ul;
285 TIMESTAMP_TO_SYSTIME(*this, ¤t_st);
286 SystemTimeToFileTime(¤t_st, ¤t_ft);
287 memcpy(¤t_ul, ¤t_ft, sizeof(current_ul));
288 current_ul.QuadPart += ( seconds_to_ns100(3600) * (ui64_t)hours );
289 memcpy(¤t_ft, ¤t_ul, sizeof(current_ft));
290 FileTimeToSystemTime(¤t_ft, ¤t_st);
291 SYSTIME_TO_TIMESTAMP(¤t_st, *this);
299 #define TIMESTAMP_TO_TM(ts, t) \
300 (t)->tm_year = (ts).Year - 1900; /* year - 1900 */ \
301 (t)->tm_mon = (ts).Month - 1; /* month of year (0 - 11) */ \
302 (t)->tm_mday = (ts).Day; /* day of month (1 - 31) */ \
303 (t)->tm_hour = (ts).Hour; /* hours (0 - 23) */ \
304 (t)->tm_min = (ts).Minute; /* minutes (0 - 59) */ \
305 (t)->tm_sec = (ts).Second; /* seconds (0 - 60) */
307 #define TM_TO_TIMESTAMP(t, ts) \
308 (ts).Year = (t)->tm_year + 1900; /* year - 1900 */ \
309 (ts).Month = (t)->tm_mon + 1; /* month of year (0 - 11) */ \
310 (ts).Day = (t)->tm_mday; /* day of month (1 - 31) */ \
311 (ts).Hour = (t)->tm_hour; /* hours (0 - 23) */ \
312 (ts).Minute = (t)->tm_min; /* minutes (0 - 59) */ \
313 (ts).Second = (t)->tm_sec; /* seconds (0 - 60) */
316 ASDCP::MXF::Timestamp::Timestamp() :
317 Year(0), Month(0), Day(0), Hour(0), Minute(0), Second(0)
319 time_t t_now = time(0);
320 struct tm* now = gmtime(&t_now);
321 TM_TO_TIMESTAMP(now, *this);
326 ASDCP::MXF::Timestamp::operator<(const Timestamp& rhs) const
328 struct tm lhtm, rhtm;
329 TIMESTAMP_TO_TM(*this, &lhtm);
330 TIMESTAMP_TO_TM(rhs, &rhtm);
331 return ( timegm(&lhtm) < timegm(&rhtm) );
336 ASDCP::MXF::Timestamp::AddDays(i32_t days)
342 TIMESTAMP_TO_TM(*this, ¤t);
343 time_t adj_time = timegm(¤t);
344 adj_time += 86400 * days;
345 struct tm* now = gmtime(&adj_time);
346 TM_TO_TIMESTAMP(now, *this);
352 ASDCP::MXF::Timestamp::AddHours(i32_t hours)
358 TIMESTAMP_TO_TM(*this, ¤t);
359 time_t adj_time = timegm(¤t);
360 adj_time += 3600 * hours;
361 struct tm* now = gmtime(&adj_time);
362 TM_TO_TIMESTAMP(now, *this);
369 ASDCP::MXF::Timestamp::Timestamp(const Timestamp& rhs)
379 ASDCP::MXF::Timestamp::~Timestamp()
384 const ASDCP::MXF::Timestamp&
385 ASDCP::MXF::Timestamp::operator=(const Timestamp& rhs)
398 ASDCP::MXF::Timestamp::operator==(const Timestamp& rhs) const
400 if ( Year == rhs.Year
401 && Month == rhs.Month
404 && Minute == rhs.Minute
405 && Second == rhs.Second )
413 ASDCP::MXF::Timestamp::operator!=(const Timestamp& rhs) const
415 if ( Year != rhs.Year
416 || Month != rhs.Month
419 || Minute != rhs.Minute
420 || Second != rhs.Second )
428 ASDCP::MXF::Timestamp::EncodeString(char* str_buf, ui32_t buf_len) const
430 // 2004-05-01 13:20:00.000
431 snprintf(str_buf, buf_len,
432 "%04hu-%02hu-%02hu %02hu:%02hu:%02hu.000",
433 Year, Month, Day, Hour, Minute, Second, Tick);
438 //------------------------------------------------------------------------------------------
441 ASDCP::MXF::TLVReader::TLVReader(const byte_t* p, ui32_t c, IPrimerLookup* PrimerLookup) :
442 MemIOReader(p, c), m_Lookup(PrimerLookup)
444 Result_t result = RESULT_OK;
446 while ( Remainder() > 0 && ASDCP_SUCCESS(result) )
451 if ( MemIOReader::ReadUi8(&Tag.a) )
452 if ( MemIOReader::ReadUi8(&Tag.b) )
453 if ( MemIOReader::ReadUi16BE(&pkt_len) )
455 m_ElementMap.insert(TagMap::value_type(Tag, ItemInfo(m_size, pkt_len)));
456 if ( SkipOffset(pkt_len) )
460 DefaultLogSink().Error("Malformed Set\n");
461 m_ElementMap.clear();
462 result = RESULT_KLV_CODING;
468 ASDCP::MXF::TLVReader::FindTL(const MDDEntry& Entry)
472 DefaultLogSink().Error("No Lookup service\n");
478 if ( m_Lookup->TagForKey(Entry.ul, TmpTag) != RESULT_OK )
480 if ( Entry.tag.a == 0 )
482 // DefaultLogSink().Debug("No such UL in this TL list: %s (%02x %02x)\n",
483 // Entry.name, Entry.tag.a, Entry.tag.b);
490 TagMap::iterator e_i = m_ElementMap.find(TmpTag);
492 if ( e_i != m_ElementMap.end() )
494 m_size = (*e_i).second.first;
495 m_capacity = m_size + (*e_i).second.second;
499 // DefaultLogSink().Debug("Not Found (%02x %02x): %s\n", TmpTag.a, TmpTag.b, Entry.name);
505 ASDCP::MXF::TLVReader::ReadObject(const MDDEntry& Entry, Kumu::IArchive* Object)
507 ASDCP_TEST_NULL(Object);
511 if ( m_size < m_capacity ) // don't try to unarchive an empty item
512 return Object->Unarchive(this) ? RESULT_OK : RESULT_KLV_CODING;
520 ASDCP::MXF::TLVReader::ReadUi8(const MDDEntry& Entry, ui8_t* value)
522 ASDCP_TEST_NULL(value);
525 return MemIOReader::ReadUi8(value) ? RESULT_OK : RESULT_KLV_CODING;
532 ASDCP::MXF::TLVReader::ReadUi16(const MDDEntry& Entry, ui16_t* value)
534 ASDCP_TEST_NULL(value);
537 return MemIOReader::ReadUi16BE(value) ? RESULT_OK : RESULT_KLV_CODING;
544 ASDCP::MXF::TLVReader::ReadUi32(const MDDEntry& Entry, ui32_t* value)
546 ASDCP_TEST_NULL(value);
549 return MemIOReader::ReadUi32BE(value) ? RESULT_OK : RESULT_KLV_CODING;
556 ASDCP::MXF::TLVReader::ReadUi64(const MDDEntry& Entry, ui64_t* value)
558 ASDCP_TEST_NULL(value);
561 return MemIOReader::ReadUi64BE(value) ? RESULT_OK : RESULT_KLV_CODING;
566 //------------------------------------------------------------------------------------------
569 ASDCP::MXF::TLVWriter::TLVWriter(byte_t* p, ui32_t c, IPrimerLookup* PrimerLookup) :
570 MemIOWriter(p, c), m_Lookup(PrimerLookup)
577 ASDCP::MXF::TLVWriter::WriteTag(const MDDEntry& Entry)
581 DefaultLogSink().Error("No Primer object available\n");
587 if ( m_Lookup->InsertTag(Entry, TmpTag) != RESULT_OK )
589 DefaultLogSink().Error("No tag for entry %s\n", Entry.name);
593 if ( ! MemIOWriter::WriteUi8(TmpTag.a) ) return RESULT_KLV_CODING;
594 if ( ! MemIOWriter::WriteUi8(TmpTag.b) ) return RESULT_KLV_CODING;
600 ASDCP::MXF::TLVWriter::WriteObject(const MDDEntry& Entry, Kumu::IArchive* Object)
602 ASDCP_TEST_NULL(Object);
604 if ( Entry.optional && ! Object->HasValue() )
607 Result_t result = WriteTag(Entry);
609 // write a temp length
610 byte_t* l_p = CurrentData();
612 if ( ! MemIOWriter::WriteUi16BE(0) ) return RESULT_KLV_CODING;
614 ui32_t before = Length();
615 if ( ! Object->Archive(this) ) return RESULT_KLV_CODING;
616 Kumu::i2p<ui16_t>(KM_i16_BE( Length() - before), l_p);
622 ASDCP::MXF::TLVWriter::WriteUi8(const MDDEntry& Entry, ui8_t* value)
624 ASDCP_TEST_NULL(value);
625 Result_t result = WriteTag(Entry);
627 if ( ASDCP_SUCCESS(result) )
629 if ( ! MemIOWriter::WriteUi16BE(sizeof(ui8_t)) ) return RESULT_KLV_CODING;
630 if ( ! MemIOWriter::WriteUi8(*value) ) return RESULT_KLV_CODING;
638 ASDCP::MXF::TLVWriter::WriteUi16(const MDDEntry& Entry, ui16_t* value)
640 ASDCP_TEST_NULL(value);
641 Result_t result = WriteTag(Entry);
643 if ( KM_SUCCESS(result) )
645 if ( ! MemIOWriter::WriteUi16BE(sizeof(ui16_t)) ) return RESULT_KLV_CODING;
646 if ( ! MemIOWriter::WriteUi16BE(*value) ) return RESULT_KLV_CODING;
654 ASDCP::MXF::TLVWriter::WriteUi32(const MDDEntry& Entry, ui32_t* value)
656 ASDCP_TEST_NULL(value);
657 Result_t result = WriteTag(Entry);
659 if ( KM_SUCCESS(result) )
661 if ( ! MemIOWriter::WriteUi16BE(sizeof(ui32_t)) ) return RESULT_KLV_CODING;
662 if ( ! MemIOWriter::WriteUi32BE(*value) ) return RESULT_KLV_CODING;
670 ASDCP::MXF::TLVWriter::WriteUi64(const MDDEntry& Entry, ui64_t* value)
672 ASDCP_TEST_NULL(value);
673 Result_t result = WriteTag(Entry);
675 if ( KM_SUCCESS(result) )
677 if ( ! MemIOWriter::WriteUi16BE(sizeof(ui64_t)) ) return RESULT_KLV_CODING;
678 if ( ! MemIOWriter::WriteUi64BE(*value) ) return RESULT_KLV_CODING;
685 //----------------------------------------------------------------------------------------------------
688 ASDCP::MXF::Raw::Raw()
693 ASDCP::MXF::Raw::~Raw()
699 ASDCP::MXF::Raw::Unarchive(Kumu::MemIOReader* Reader)
701 ui32_t payload_size = Reader->Remainder();
702 if ( payload_size == 0 ) return false;
703 if ( KM_FAILURE(Capacity(payload_size)) ) return false;
705 memcpy(Data(), Reader->CurrentData(), payload_size);
706 Length(payload_size);
712 ASDCP::MXF::Raw::Archive(Kumu::MemIOWriter* Writer) const
714 return Writer->WriteRaw(RoData(), Length());
719 ASDCP::MXF::Raw::EncodeString(char* str_buf, ui32_t buf_len) const
722 Kumu::bin2hex(RoData(), Length(), str_buf, buf_len);