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());
102 // Write the timestamp value to the given buffer in the form 2004-05-01 13:20:00.000
103 // returns 0 if the buffer is smaller than DateTimeLen
105 ASDCP::UMID::EncodeString(char* str_buf, ui32_t buf_len) const
109 snprintf(str_buf, buf_len, "[%02x%02x%02x%02x.%02x%02x.%02x%02x.%02x%02x%02x%02x],%02x,%02x,%02x,%02x,",
110 m_Value[0], m_Value[1], m_Value[2], m_Value[3],
111 m_Value[4], m_Value[5], m_Value[6], m_Value[7],
112 m_Value[8], m_Value[9], m_Value[10], m_Value[11],
113 m_Value[12], m_Value[13], m_Value[14], m_Value[15]
116 ui32_t offset = strlen(str_buf);
118 if ( ( m_Value[8] & 0x80 ) == 0 )
120 // half-swapped UL, use [bbaa9988.ddcc.ffee.00010203.04050607]
121 snprintf(str_buf + offset, buf_len - offset,
122 "[%02x%02x%02x%02x.%02x%02x.%02x%02x.%02x%02x%02x%02x.%02x%02x%02x%02x]",
123 m_Value[24], m_Value[25], m_Value[26], m_Value[27],
124 m_Value[28], m_Value[29], m_Value[30], m_Value[31],
125 m_Value[16], m_Value[17], m_Value[18], m_Value[19],
126 m_Value[20], m_Value[21], m_Value[22], m_Value[23]
131 // UUID, use {00112233-4455-6677-8899-aabbccddeeff}
132 snprintf(str_buf + offset, buf_len - offset,
133 "{%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
134 m_Value[16], m_Value[17], m_Value[18], m_Value[19],
135 m_Value[20], m_Value[21], m_Value[22], m_Value[23],
136 m_Value[24], m_Value[25], m_Value[26], m_Value[27],
137 m_Value[28], m_Value[29], m_Value[30], m_Value[31]
144 //------------------------------------------------------------------------------------------
147 const ASDCP::MXF::UTF16String&
148 ASDCP::MXF::UTF16String::operator=(const char* sz)
150 if ( sz == 0 || *sz == 0 )
157 ui32_t len = Kumu::xmin((ui32_t)strlen(sz), (IdentBufferLen - 1));
159 memcpy(m_buffer, sz, m_length);
160 m_buffer[m_length] = 0;
169 ASDCP::MXF::UTF16String::Unarchive(Kumu::MemIOReader* Reader)
171 const byte_t* p = Reader->CurrentData();
172 m_length = Reader->Remainder();
173 assert(m_length % 2 == 0);
175 assert(IdentBufferLen >= m_length);
178 for ( i = 0; i < m_length; i++ )
179 m_buffer[i] = p[(i*2)+1];
183 Reader->SkipOffset(m_length*2);
189 ASDCP::MXF::UTF16String::Archive(Kumu::MemIOWriter* Writer) const
191 byte_t* p = Writer->Data() + Writer->Length();
193 memset(p, 0, (m_length*2)+2);
195 for ( i = 0; i < m_length; i++ )
196 p[(i*2)+1] = m_buffer[i];
198 Writer->AddOffset(m_length * 2);
203 //------------------------------------------------------------------------------------------
208 #define TIMESTAMP_TO_SYSTIME(ts, t) \
209 (t)->wYear = (ts).Year; /* year */ \
210 (t)->wMonth = (ts).Month; /* month of year (1 - 12) */ \
211 (t)->wDay = (ts).Day; /* day of month (1 - 31) */ \
212 (t)->wHour = (ts).Hour; /* hours (0 - 23) */ \
213 (t)->wMinute = (ts).Minute; /* minutes (0 - 59) */ \
214 (t)->wSecond = (ts).Second; /* seconds (0 - 60) */ \
215 (t)->wDayOfWeek = 0; \
216 (t)->wMilliseconds = ((ts).Tick * 4);
218 #define SYSTIME_TO_TIMESTAMP(t, ts) \
219 (ts).Year = (t)->wYear; /* year */ \
220 (ts).Month = (t)->wMonth; /* month of year (1 - 12) */ \
221 (ts).Day = (t)->wDay; /* day of month (1 - 31) */ \
222 (ts).Hour = (t)->wHour; /* hours (0 - 23) */ \
223 (ts).Minute = (t)->wMinute; /* minutes (0 - 59) */ \
224 (ts).Second = (t)->wSecond; /* seconds (0 - 60) */ \
225 (ts).Tick = (t)->wMilliseconds / 4;
228 ASDCP::MXF::Timestamp::Timestamp() :
229 Year(0), Month(0), Day(0), Hour(0), Minute(0), Second(0), Tick(0)
232 GetSystemTime(&sys_time);
233 SYSTIME_TO_TIMESTAMP(&sys_time, *this);
238 ASDCP::MXF::Timestamp::operator<(const Timestamp& rhs) const
240 SYSTEMTIME lhst, rhst;
243 TIMESTAMP_TO_SYSTIME(*this, &lhst);
244 TIMESTAMP_TO_SYSTIME(rhs, &rhst);
245 SystemTimeToFileTime(&lhst, &lft);
246 SystemTimeToFileTime(&rhst, &rft);
247 return ( CompareFileTime(&lft, &rft) == -1 );
251 seconds_to_ns100(ui32_t seconds)
253 return ((ui64_t)seconds * 10000000);
258 ASDCP::MXF::Timestamp::AddDays(i32_t days)
260 SYSTEMTIME current_st;
262 ULARGE_INTEGER current_ul;
266 TIMESTAMP_TO_SYSTIME(*this, ¤t_st);
267 SystemTimeToFileTime(¤t_st, ¤t_ft);
268 memcpy(¤t_ul, ¤t_ft, sizeof(current_ul));
269 current_ul.QuadPart += ( seconds_to_ns100(86400) * (ui64_t)days );
270 memcpy(¤t_ft, ¤t_ul, sizeof(current_ft));
271 FileTimeToSystemTime(¤t_ft, ¤t_st);
272 SYSTIME_TO_TIMESTAMP(¤t_st, *this);
278 ASDCP::MXF::Timestamp::AddHours(i32_t hours)
280 SYSTEMTIME current_st;
282 ULARGE_INTEGER current_ul;
286 TIMESTAMP_TO_SYSTIME(*this, ¤t_st);
287 SystemTimeToFileTime(¤t_st, ¤t_ft);
288 memcpy(¤t_ul, ¤t_ft, sizeof(current_ul));
289 current_ul.QuadPart += ( seconds_to_ns100(3600) * (ui64_t)hours );
290 memcpy(¤t_ft, ¤t_ul, sizeof(current_ft));
291 FileTimeToSystemTime(¤t_ft, ¤t_st);
292 SYSTIME_TO_TIMESTAMP(¤t_st, *this);
300 #define TIMESTAMP_TO_TM(ts, t) \
301 (t)->tm_year = (ts).Year - 1900; /* year - 1900 */ \
302 (t)->tm_mon = (ts).Month - 1; /* month of year (0 - 11) */ \
303 (t)->tm_mday = (ts).Day; /* day of month (1 - 31) */ \
304 (t)->tm_hour = (ts).Hour; /* hours (0 - 23) */ \
305 (t)->tm_min = (ts).Minute; /* minutes (0 - 59) */ \
306 (t)->tm_sec = (ts).Second; /* seconds (0 - 60) */
308 #define TM_TO_TIMESTAMP(t, ts) \
309 (ts).Year = (t)->tm_year + 1900; /* year - 1900 */ \
310 (ts).Month = (t)->tm_mon + 1; /* month of year (0 - 11) */ \
311 (ts).Day = (t)->tm_mday; /* day of month (1 - 31) */ \
312 (ts).Hour = (t)->tm_hour; /* hours (0 - 23) */ \
313 (ts).Minute = (t)->tm_min; /* minutes (0 - 59) */ \
314 (ts).Second = (t)->tm_sec; /* seconds (0 - 60) */
317 ASDCP::MXF::Timestamp::Timestamp() :
318 Year(0), Month(0), Day(0), Hour(0), Minute(0), Second(0)
320 time_t t_now = time(0);
321 struct tm* now = gmtime(&t_now);
322 TM_TO_TIMESTAMP(now, *this);
327 ASDCP::MXF::Timestamp::operator<(const Timestamp& rhs) const
329 struct tm lhtm, rhtm;
330 TIMESTAMP_TO_TM(*this, &lhtm);
331 TIMESTAMP_TO_TM(rhs, &rhtm);
332 return ( timegm(&lhtm) < timegm(&rhtm) );
337 ASDCP::MXF::Timestamp::AddDays(i32_t days)
343 TIMESTAMP_TO_TM(*this, ¤t);
344 time_t adj_time = timegm(¤t);
345 adj_time += 86400 * days;
346 struct tm* now = gmtime(&adj_time);
347 TM_TO_TIMESTAMP(now, *this);
353 ASDCP::MXF::Timestamp::AddHours(i32_t hours)
359 TIMESTAMP_TO_TM(*this, ¤t);
360 time_t adj_time = timegm(¤t);
361 adj_time += 3600 * hours;
362 struct tm* now = gmtime(&adj_time);
363 TM_TO_TIMESTAMP(now, *this);
370 ASDCP::MXF::Timestamp::Timestamp(const Timestamp& rhs)
380 ASDCP::MXF::Timestamp::~Timestamp()
385 const ASDCP::MXF::Timestamp&
386 ASDCP::MXF::Timestamp::operator=(const Timestamp& rhs)
399 ASDCP::MXF::Timestamp::operator==(const Timestamp& rhs) const
401 if ( Year == rhs.Year
402 && Month == rhs.Month
405 && Minute == rhs.Minute
406 && Second == rhs.Second )
414 ASDCP::MXF::Timestamp::operator!=(const Timestamp& rhs) const
416 if ( Year != rhs.Year
417 || Month != rhs.Month
420 || Minute != rhs.Minute
421 || Second != rhs.Second )
429 ASDCP::MXF::Timestamp::EncodeString(char* str_buf, ui32_t buf_len) const
431 // 2004-05-01 13:20:00.000
432 snprintf(str_buf, buf_len,
433 "%04hu-%02hu-%02hu %02hu:%02hu:%02hu.000",
434 Year, Month, Day, Hour, Minute, Second);
439 //------------------------------------------------------------------------------------------
442 ASDCP::MXF::TLVReader::TLVReader(const byte_t* p, ui32_t c, IPrimerLookup* PrimerLookup) :
443 MemIOReader(p, c), m_Lookup(PrimerLookup)
445 Result_t result = RESULT_OK;
447 while ( Remainder() > 0 && ASDCP_SUCCESS(result) )
452 if ( MemIOReader::ReadUi8(&Tag.a) )
453 if ( MemIOReader::ReadUi8(&Tag.b) )
454 if ( MemIOReader::ReadUi16BE(&pkt_len) )
456 m_ElementMap.insert(TagMap::value_type(Tag, ItemInfo(m_size, pkt_len)));
457 if ( SkipOffset(pkt_len) )
461 DefaultLogSink().Error("Malformed Set\n");
462 m_ElementMap.clear();
463 result = RESULT_KLV_CODING;
469 ASDCP::MXF::TLVReader::FindTL(const MDDEntry& Entry)
473 DefaultLogSink().Error("No Lookup service\n");
479 if ( m_Lookup->TagForKey(Entry.ul, TmpTag) != RESULT_OK )
481 if ( Entry.tag.a == 0 )
483 // DefaultLogSink().Debug("No such UL in this TL list: %s (%02x %02x)\n",
484 // Entry.name, Entry.tag.a, Entry.tag.b);
491 TagMap::iterator e_i = m_ElementMap.find(TmpTag);
493 if ( e_i != m_ElementMap.end() )
495 m_size = (*e_i).second.first;
496 m_capacity = m_size + (*e_i).second.second;
500 // DefaultLogSink().Debug("Not Found (%02x %02x): %s\n", TmpTag.a, TmpTag.b, Entry.name);
506 ASDCP::MXF::TLVReader::ReadObject(const MDDEntry& Entry, Kumu::IArchive* Object)
508 ASDCP_TEST_NULL(Object);
512 if ( m_size < m_capacity ) // don't try to unarchive an empty item
513 return Object->Unarchive(this) ? RESULT_OK : RESULT_KLV_CODING;
521 ASDCP::MXF::TLVReader::ReadUi8(const MDDEntry& Entry, ui8_t* value)
523 ASDCP_TEST_NULL(value);
526 return MemIOReader::ReadUi8(value) ? RESULT_OK : RESULT_KLV_CODING;
533 ASDCP::MXF::TLVReader::ReadUi16(const MDDEntry& Entry, ui16_t* value)
535 ASDCP_TEST_NULL(value);
538 return MemIOReader::ReadUi16BE(value) ? RESULT_OK : RESULT_KLV_CODING;
545 ASDCP::MXF::TLVReader::ReadUi32(const MDDEntry& Entry, ui32_t* value)
547 ASDCP_TEST_NULL(value);
550 return MemIOReader::ReadUi32BE(value) ? RESULT_OK : RESULT_KLV_CODING;
557 ASDCP::MXF::TLVReader::ReadUi64(const MDDEntry& Entry, ui64_t* value)
559 ASDCP_TEST_NULL(value);
562 return MemIOReader::ReadUi64BE(value) ? RESULT_OK : RESULT_KLV_CODING;
567 //------------------------------------------------------------------------------------------
570 ASDCP::MXF::TLVWriter::TLVWriter(byte_t* p, ui32_t c, IPrimerLookup* PrimerLookup) :
571 MemIOWriter(p, c), m_Lookup(PrimerLookup)
578 ASDCP::MXF::TLVWriter::WriteTag(const MDDEntry& Entry)
582 DefaultLogSink().Error("No Primer object available\n");
588 if ( m_Lookup->InsertTag(Entry, TmpTag) != RESULT_OK )
590 DefaultLogSink().Error("No tag for entry %s\n", Entry.name);
594 if ( ! MemIOWriter::WriteUi8(TmpTag.a) ) return RESULT_KLV_CODING;
595 if ( ! MemIOWriter::WriteUi8(TmpTag.b) ) return RESULT_KLV_CODING;
601 ASDCP::MXF::TLVWriter::WriteObject(const MDDEntry& Entry, Kumu::IArchive* Object)
603 ASDCP_TEST_NULL(Object);
605 if ( Entry.optional && ! Object->HasValue() )
608 Result_t result = WriteTag(Entry);
610 if ( ASDCP_SUCCESS(result) )
612 // write a temp length
613 byte_t* l_p = CurrentData();
615 if ( ! MemIOWriter::WriteUi16BE(0) ) return RESULT_KLV_CODING;
617 ui32_t before = Length();
618 if ( ! Object->Archive(this) ) return RESULT_KLV_CODING;
619 if ( (Length() - before) > 0xffffL ) return RESULT_KLV_CODING;
620 Kumu::i2p<ui16_t>(KM_i16_BE(Length() - before), l_p);
628 ASDCP::MXF::TLVWriter::WriteUi8(const MDDEntry& Entry, ui8_t* value)
630 ASDCP_TEST_NULL(value);
631 Result_t result = WriteTag(Entry);
633 if ( ASDCP_SUCCESS(result) )
635 if ( ! MemIOWriter::WriteUi16BE(sizeof(ui8_t)) ) return RESULT_KLV_CODING;
636 if ( ! MemIOWriter::WriteUi8(*value) ) return RESULT_KLV_CODING;
644 ASDCP::MXF::TLVWriter::WriteUi16(const MDDEntry& Entry, ui16_t* value)
646 ASDCP_TEST_NULL(value);
647 Result_t result = WriteTag(Entry);
649 if ( KM_SUCCESS(result) )
651 if ( ! MemIOWriter::WriteUi16BE(sizeof(ui16_t)) ) return RESULT_KLV_CODING;
652 if ( ! MemIOWriter::WriteUi16BE(*value) ) return RESULT_KLV_CODING;
660 ASDCP::MXF::TLVWriter::WriteUi32(const MDDEntry& Entry, ui32_t* value)
662 ASDCP_TEST_NULL(value);
663 Result_t result = WriteTag(Entry);
665 if ( KM_SUCCESS(result) )
667 if ( ! MemIOWriter::WriteUi16BE(sizeof(ui32_t)) ) return RESULT_KLV_CODING;
668 if ( ! MemIOWriter::WriteUi32BE(*value) ) return RESULT_KLV_CODING;
676 ASDCP::MXF::TLVWriter::WriteUi64(const MDDEntry& Entry, ui64_t* value)
678 ASDCP_TEST_NULL(value);
679 Result_t result = WriteTag(Entry);
681 if ( KM_SUCCESS(result) )
683 if ( ! MemIOWriter::WriteUi16BE(sizeof(ui64_t)) ) return RESULT_KLV_CODING;
684 if ( ! MemIOWriter::WriteUi64BE(*value) ) return RESULT_KLV_CODING;
691 //----------------------------------------------------------------------------------------------------
694 ASDCP::MXF::Raw::Raw()
699 ASDCP::MXF::Raw::~Raw()
705 ASDCP::MXF::Raw::Unarchive(Kumu::MemIOReader* Reader)
707 ui32_t payload_size = Reader->Remainder();
708 if ( payload_size == 0 ) return false;
709 if ( KM_FAILURE(Capacity(payload_size)) ) return false;
711 memcpy(Data(), Reader->CurrentData(), payload_size);
712 Length(payload_size);
718 ASDCP::MXF::Raw::Archive(Kumu::MemIOWriter* Writer) const
720 return Writer->WriteRaw(RoData(), Length());
725 ASDCP::MXF::Raw::EncodeString(char* str_buf, ui32_t buf_len) const
728 Kumu::bin2hex(RoData(), Length(), str_buf, buf_len);