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 if ( ASDCP_SUCCESS(result) )
611 // write a temp length
612 byte_t* l_p = CurrentData();
614 if ( ! MemIOWriter::WriteUi16BE(0) ) return RESULT_KLV_CODING;
616 ui32_t before = Length();
617 if ( ! Object->Archive(this) ) return RESULT_KLV_CODING;
618 Kumu::i2p<ui16_t>(KM_i16_BE( Length() - before), l_p);
626 ASDCP::MXF::TLVWriter::WriteUi8(const MDDEntry& Entry, ui8_t* value)
628 ASDCP_TEST_NULL(value);
629 Result_t result = WriteTag(Entry);
631 if ( ASDCP_SUCCESS(result) )
633 if ( ! MemIOWriter::WriteUi16BE(sizeof(ui8_t)) ) return RESULT_KLV_CODING;
634 if ( ! MemIOWriter::WriteUi8(*value) ) return RESULT_KLV_CODING;
642 ASDCP::MXF::TLVWriter::WriteUi16(const MDDEntry& Entry, ui16_t* value)
644 ASDCP_TEST_NULL(value);
645 Result_t result = WriteTag(Entry);
647 if ( KM_SUCCESS(result) )
649 if ( ! MemIOWriter::WriteUi16BE(sizeof(ui16_t)) ) return RESULT_KLV_CODING;
650 if ( ! MemIOWriter::WriteUi16BE(*value) ) return RESULT_KLV_CODING;
658 ASDCP::MXF::TLVWriter::WriteUi32(const MDDEntry& Entry, ui32_t* value)
660 ASDCP_TEST_NULL(value);
661 Result_t result = WriteTag(Entry);
663 if ( KM_SUCCESS(result) )
665 if ( ! MemIOWriter::WriteUi16BE(sizeof(ui32_t)) ) return RESULT_KLV_CODING;
666 if ( ! MemIOWriter::WriteUi32BE(*value) ) return RESULT_KLV_CODING;
674 ASDCP::MXF::TLVWriter::WriteUi64(const MDDEntry& Entry, ui64_t* value)
676 ASDCP_TEST_NULL(value);
677 Result_t result = WriteTag(Entry);
679 if ( KM_SUCCESS(result) )
681 if ( ! MemIOWriter::WriteUi16BE(sizeof(ui64_t)) ) return RESULT_KLV_CODING;
682 if ( ! MemIOWriter::WriteUi64BE(*value) ) return RESULT_KLV_CODING;
689 //----------------------------------------------------------------------------------------------------
692 ASDCP::MXF::Raw::Raw()
697 ASDCP::MXF::Raw::~Raw()
703 ASDCP::MXF::Raw::Unarchive(Kumu::MemIOReader* Reader)
705 ui32_t payload_size = Reader->Remainder();
706 if ( payload_size == 0 ) return false;
707 if ( KM_FAILURE(Capacity(payload_size)) ) return false;
709 memcpy(Data(), Reader->CurrentData(), payload_size);
710 Length(payload_size);
716 ASDCP::MXF::Raw::Archive(Kumu::MemIOWriter* Writer) const
718 return Writer->WriteRaw(RoData(), Length());
723 ASDCP::MXF::Raw::EncodeString(char* str_buf, ui32_t buf_len) const
726 Kumu::bin2hex(RoData(), Length(), str_buf, buf_len);