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
33 #include "FortunaRNG.h"
35 //------------------------------------------------------------------------------------------
41 ASDCP::UMID::MakeUMID(int Type)
44 AssetID.GenRandomValue();
45 MakeUMID(Type, AssetID);
50 ASDCP::UMID::MakeUMID(int Type, const UUID& AssetID)
52 // Set the non-varying base of the UMID
53 static const byte_t UMIDBase[10] = { 0x06, 0x0a, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
54 memcpy(m_Value, UMIDBase, 10);
55 m_Value[10] = Type; // Material Type
56 m_Value[12] = 0x13; // length
58 // preserved for compatibility with mfxlib
59 if( Type > 4 ) m_Value[7] = 5;
60 m_Value[11] = 0x20; // UUID/UL method, number gen undefined
63 m_Value[13] = m_Value[14] = m_Value[15] = 0;
65 memcpy(&m_Value[16], AssetID.Value(), AssetID.Size());
69 // Write the timestamp value to the given buffer in the form 2004-05-01 13:20:00.000
70 // returns 0 if the buffer is smaller than DateTimeLen
72 ASDCP::UMID::ToString(char* str_buf) const
76 snprintf(str_buf, IdentBufferLen, "[%02x%02x%02x%02x.%02x%02x.%02x%02x.%02x%02x%02x%02x],%02x,%02x,%02x,%02x,",
77 m_Value[0], m_Value[1], m_Value[2], m_Value[3],
78 m_Value[4], m_Value[5], m_Value[6], m_Value[7],
79 m_Value[8], m_Value[9], m_Value[10], m_Value[11],
80 m_Value[12], m_Value[13], m_Value[14], m_Value[15]
83 ui32_t offset = strlen(str_buf);
85 if ( ( m_Value[8] & 0x80 ) == 0 )
87 // half-swapped UL, use [bbaa9988.ddcc.ffee.00010203.04050607]
88 snprintf(str_buf + offset, IdentBufferLen - offset,
89 "[%02x%02x%02x%02x.%02x%02x.%02x%02x.%02x%02x%02x%02x.%02x%02x%02x%02x]",
90 m_Value[24], m_Value[25], m_Value[26], m_Value[27],
91 m_Value[28], m_Value[29], m_Value[30], m_Value[31],
92 m_Value[16], m_Value[17], m_Value[18], m_Value[19],
93 m_Value[20], m_Value[21], m_Value[22], m_Value[23]
98 // UUID, use {00112233-4455-6677-8899-aabbccddeeff}
99 snprintf(str_buf + offset, IdentBufferLen - offset,
100 "{%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
101 m_Value[16], m_Value[17], m_Value[18], m_Value[19],
102 m_Value[20], m_Value[21], m_Value[22], m_Value[23],
103 m_Value[24], m_Value[25], m_Value[26], m_Value[27],
104 m_Value[28], m_Value[29], m_Value[30], m_Value[31]
113 ASDCP::UUID::GenRandomValue()
116 RNG.FillRandom(m_Value, UUIDlen);
117 m_Value[6] &= 0x0f; // clear bits 4-7
118 m_Value[6] |= 0x40; // set UUID version
119 m_Value[8] &= 0x3f; // clear bits 6&7
120 m_Value[8] |= 0x80; // set bit 7
121 // m_HasValue = true;
125 //------------------------------------------------------------------------------------------
128 const ASDCP::MXF::UTF16String&
129 ASDCP::MXF::UTF16String::operator=(const char* sz)
131 if ( sz == 0 || *sz == 0 )
138 ui32_t len = xmin((ui32_t)strlen(sz), (IdentBufferLen - 1));
140 memcpy(m_buffer, sz, m_length);
141 m_buffer[m_length] = 0;
150 ASDCP::MXF::UTF16String::Unarchive(ASDCP::MemIOReader& Reader)
152 const byte_t* p = Reader.CurrentData();
153 m_length = Reader.Remainder();
154 assert(m_length % 2 == 0);
156 assert(IdentBufferLen >= m_length);
159 for ( i = 0; i < m_length; i++ )
160 m_buffer[i] = p[(i*2)+1];
164 Reader.SkipOffset(m_length*2);
170 ASDCP::MXF::UTF16String::Archive(ASDCP::MemIOWriter& Writer) const
172 byte_t* p = Writer.Data() + Writer.Size();
174 memset(p, 0, (m_length*2)+2);
176 for ( i = 0; i < m_length; i++ )
177 p[(i*2)+1] = m_buffer[i];
179 Writer.AddOffset(m_length * 2);
184 //------------------------------------------------------------------------------------------
189 #define TIMESTAMP_TO_SYSTIME(ts, t) \
190 (t)->wYear = (ts).Year; /* year */ \
191 (t)->wMonth = (ts).Month; /* month of year (1 - 12) */ \
192 (t)->wDay = (ts).Day; /* day of month (1 - 31) */ \
193 (t)->wHour = (ts).Hour; /* hours (0 - 23) */ \
194 (t)->wMinute = (ts).Minute; /* minutes (0 - 59) */ \
195 (t)->wSecond = (ts).Second; /* seconds (0 - 60) */ \
196 (t)->wDayOfWeek = 0; \
197 (t)->wMilliseconds = ((ts).Tick * 4);
199 #define SYSTIME_TO_TIMESTAMP(t, ts) \
200 (ts).Year = (t)->wYear; /* year */ \
201 (ts).Month = (t)->wMonth; /* month of year (1 - 12) */ \
202 (ts).Day = (t)->wDay; /* day of month (1 - 31) */ \
203 (ts).Hour = (t)->wHour; /* hours (0 - 23) */ \
204 (ts).Minute = (t)->wMinute; /* minutes (0 - 59) */ \
205 (ts).Second = (t)->wSecond; /* seconds (0 - 60) */ \
206 (ts).Tick = (t)->wMilliseconds / 4;
209 ASDCP::MXF::Timestamp::Timestamp() :
210 Year(0), Month(0), Day(0), Hour(0), Minute(0), Second(0), Tick(0)
213 GetSystemTime(&sys_time);
214 SYSTIME_TO_TIMESTAMP(&sys_time, *this);
219 ASDCP::MXF::Timestamp::operator<(const Timestamp& rhs) const
221 SYSTEMTIME lhst, rhst;
224 TIMESTAMP_TO_SYSTIME(*this, &lhst);
225 TIMESTAMP_TO_SYSTIME(rhs, &rhst);
226 SystemTimeToFileTime(&lhst, &lft);
227 SystemTimeToFileTime(&rhst, &rft);
228 return ( CompareFileTime(&lft, &rft) == -1 );
232 seconds_to_ns100(ui32_t seconds)
234 return ((ui64_t)seconds * 10000000);
239 ASDCP::MXF::Timestamp::AddDays(i32_t days)
241 SYSTEMTIME current_st;
243 ULARGE_INTEGER current_ul;
247 TIMESTAMP_TO_SYSTIME(*this, ¤t_st);
248 SystemTimeToFileTime(¤t_st, ¤t_ft);
249 memcpy(¤t_ul, ¤t_ft, sizeof(current_ul));
250 current_ul.QuadPart += ( seconds_to_ns100(86400) * (ui64_t)days );
251 memcpy(¤t_ft, ¤t_ul, sizeof(current_ft));
252 FileTimeToSystemTime(¤t_ft, ¤t_st);
253 SYSTIME_TO_TIMESTAMP(¤t_st, *this);
259 ASDCP::MXF::Timestamp::AddHours(i32_t hours)
261 SYSTEMTIME current_st;
263 ULARGE_INTEGER current_ul;
267 TIMESTAMP_TO_SYSTIME(*this, ¤t_st);
268 SystemTimeToFileTime(¤t_st, ¤t_ft);
269 memcpy(¤t_ul, ¤t_ft, sizeof(current_ul));
270 current_ul.QuadPart += ( seconds_to_ns100(3600) * (ui64_t)hours );
271 memcpy(¤t_ft, ¤t_ul, sizeof(current_ft));
272 FileTimeToSystemTime(¤t_ft, ¤t_st);
273 SYSTIME_TO_TIMESTAMP(¤t_st, *this);
281 #define TIMESTAMP_TO_TM(ts, t) \
282 (t)->tm_year = (ts).Year - 1900; /* year - 1900 */ \
283 (t)->tm_mon = (ts).Month - 1; /* month of year (0 - 11) */ \
284 (t)->tm_mday = (ts).Day; /* day of month (1 - 31) */ \
285 (t)->tm_hour = (ts).Hour; /* hours (0 - 23) */ \
286 (t)->tm_min = (ts).Minute; /* minutes (0 - 59) */ \
287 (t)->tm_sec = (ts).Second; /* seconds (0 - 60) */
289 #define TM_TO_TIMESTAMP(t, ts) \
290 (ts).Year = (t)->tm_year + 1900; /* year - 1900 */ \
291 (ts).Month = (t)->tm_mon + 1; /* month of year (0 - 11) */ \
292 (ts).Day = (t)->tm_mday; /* day of month (1 - 31) */ \
293 (ts).Hour = (t)->tm_hour; /* hours (0 - 23) */ \
294 (ts).Minute = (t)->tm_min; /* minutes (0 - 59) */ \
295 (ts).Second = (t)->tm_sec; /* seconds (0 - 60) */
298 ASDCP::MXF::Timestamp::Timestamp() :
299 Year(0), Month(0), Day(0), Hour(0), Minute(0), Second(0)
301 time_t t_now = time(0);
302 struct tm* now = gmtime(&t_now);
303 TM_TO_TIMESTAMP(now, *this);
308 ASDCP::MXF::Timestamp::operator<(const Timestamp& rhs) const
310 struct tm lhtm, rhtm;
311 TIMESTAMP_TO_TM(*this, &lhtm);
312 TIMESTAMP_TO_TM(rhs, &rhtm);
313 return ( timegm(&lhtm) < timegm(&rhtm) );
318 ASDCP::MXF::Timestamp::AddDays(i32_t days)
324 TIMESTAMP_TO_TM(*this, ¤t);
325 time_t adj_time = timegm(¤t);
326 adj_time += 86400 * days;
327 struct tm* now = gmtime(&adj_time);
328 TM_TO_TIMESTAMP(now, *this);
334 ASDCP::MXF::Timestamp::AddHours(i32_t hours)
340 TIMESTAMP_TO_TM(*this, ¤t);
341 time_t adj_time = timegm(¤t);
342 adj_time += 3600 * hours;
343 struct tm* now = gmtime(&adj_time);
344 TM_TO_TIMESTAMP(now, *this);
351 ASDCP::MXF::Timestamp::Timestamp(const Timestamp& rhs)
361 ASDCP::MXF::Timestamp::~Timestamp()
366 const ASDCP::MXF::Timestamp&
367 ASDCP::MXF::Timestamp::operator=(const Timestamp& rhs)
380 ASDCP::MXF::Timestamp::operator==(const Timestamp& rhs) const
382 if ( Year == rhs.Year
383 && Month == rhs.Month
386 && Minute == rhs.Minute
387 && Second == rhs.Second )
395 ASDCP::MXF::Timestamp::operator!=(const Timestamp& rhs) const
397 if ( Year != rhs.Year
398 || Month != rhs.Month
401 || Minute != rhs.Minute
402 || Second != rhs.Second )
410 ASDCP::MXF::Timestamp::ToString(char* str_buf) const
412 // 2004-05-01 13:20:00.000
413 snprintf(str_buf, IntBufferLen,
414 "%04hu-%02hu-%02hu %02hu:%02hu:%02hu.000",
415 Year, Month, Day, Hour, Minute, Second, Tick);
420 //------------------------------------------------------------------------------------------
423 ASDCP::MXF::TLVReader::TLVReader(const byte_t* p, ui32_t c, IPrimerLookup* PrimerLookup) :
424 MemIOReader(p, c), m_Lookup(PrimerLookup)
426 Result_t result = RESULT_OK;
428 while ( Remainder() > 0 && ASDCP_SUCCESS(result) )
433 result = MemIOReader::ReadUi8(&Tag.a);
435 if ( ASDCP_SUCCESS(result) )
436 result = MemIOReader::ReadUi8(&Tag.b);
438 if ( ASDCP_SUCCESS(result) )
439 result = MemIOReader::ReadUi16BE(&pkt_len);
441 if ( ASDCP_SUCCESS(result) )
443 m_ElementMap.insert(TagMap::value_type(Tag, ItemInfo(m_size, pkt_len)));
444 result = SkipOffset(pkt_len);
447 if ( ASDCP_FAILURE(result) )
449 DefaultLogSink().Error("Malformed Set\n");
450 m_ElementMap.clear();
458 ASDCP::MXF::TLVReader::FindTL(const MDDEntry& Entry)
462 DefaultLogSink().Error("No Lookup service\n");
468 if ( m_Lookup->TagForKey(Entry.ul, TmpTag) != RESULT_OK )
470 if ( Entry.tag.a == 0 )
472 DefaultLogSink().Info("No such UL in this TL list: %s (%02x %02x)\n",
473 Entry.name, Entry.tag.a, Entry.tag.b);
480 TagMap::iterator e_i = m_ElementMap.find(TmpTag);
482 if ( e_i != m_ElementMap.end() )
484 m_size = (*e_i).second.first;
485 m_capacity = m_size + (*e_i).second.second;
489 DefaultLogSink().Info("Not Found (%02x %02x): %s\n", TmpTag.a, TmpTag.b, Entry.name);
495 ASDCP::MXF::TLVReader::ReadObject(const MDDEntry& Entry, IArchive* Object)
497 ASDCP_TEST_NULL(Object);
501 if ( m_size < m_capacity ) // don't try to unarchive an empty item
502 return Object->Unarchive(*this);
510 ASDCP::MXF::TLVReader::ReadUi8(const MDDEntry& Entry, ui8_t* value)
512 ASDCP_TEST_NULL(value);
515 return MemIOReader::ReadUi8(value);
522 ASDCP::MXF::TLVReader::ReadUi16(const MDDEntry& Entry, ui16_t* value)
524 ASDCP_TEST_NULL(value);
527 return MemIOReader::ReadUi16BE(value);
534 ASDCP::MXF::TLVReader::ReadUi32(const MDDEntry& Entry, ui32_t* value)
536 ASDCP_TEST_NULL(value);
539 return MemIOReader::ReadUi32BE(value);
546 ASDCP::MXF::TLVReader::ReadUi64(const MDDEntry& Entry, ui64_t* value)
548 ASDCP_TEST_NULL(value);
551 return MemIOReader::ReadUi64BE(value);
556 //------------------------------------------------------------------------------------------
559 ASDCP::MXF::TLVWriter::TLVWriter(byte_t* p, ui32_t c, IPrimerLookup* PrimerLookup) :
560 MemIOWriter(p, c), m_Lookup(PrimerLookup)
567 ASDCP::MXF::TLVWriter::WriteTag(const MDDEntry& Entry)
571 DefaultLogSink().Error("No Primer object available\n");
577 if ( m_Lookup->InsertTag(Entry, TmpTag) != RESULT_OK )
579 DefaultLogSink().Error("No tag for entry %s\n", Entry.name);
583 Result_t result = MemIOWriter::WriteUi8(TmpTag.a);
584 if ( ASDCP_SUCCESS(result) ) MemIOWriter::WriteUi8(TmpTag.b);
591 ASDCP::MXF::TLVWriter::WriteObject(const MDDEntry& Entry, IArchive* Object)
593 ASDCP_TEST_NULL(Object);
595 if ( Entry.optional && ! Object->HasValue() )
598 Result_t result = WriteTag(Entry);
600 // write a temp length
601 byte_t* l_p = CurrentData();
603 if ( ASDCP_SUCCESS(result) )
604 MemIOWriter::WriteUi16BE(0);
606 if ( ASDCP_SUCCESS(result) )
608 ui32_t before = Size();
609 result = Object->Archive(*this);
611 if ( ASDCP_SUCCESS(result) )
612 i2p<ui16_t>(ASDCP_i16_BE( Size() - before), l_p);
620 ASDCP::MXF::TLVWriter::WriteUi8(const MDDEntry& Entry, ui8_t* value)
622 ASDCP_TEST_NULL(value);
623 Result_t result = WriteTag(Entry);
624 if ( ASDCP_SUCCESS(result) ) MemIOWriter::WriteUi16BE(sizeof(ui8_t));
625 if ( ASDCP_SUCCESS(result) ) MemIOWriter::WriteUi8(*value);
631 ASDCP::MXF::TLVWriter::WriteUi16(const MDDEntry& Entry, ui16_t* value)
633 ASDCP_TEST_NULL(value);
634 Result_t result = WriteTag(Entry);
635 if ( ASDCP_SUCCESS(result) ) MemIOWriter::WriteUi16BE(sizeof(ui16_t));
636 if ( ASDCP_SUCCESS(result) ) MemIOWriter::WriteUi16BE(*value);
642 ASDCP::MXF::TLVWriter::WriteUi32(const MDDEntry& Entry, ui32_t* value)
644 ASDCP_TEST_NULL(value);
645 Result_t result = WriteTag(Entry);
646 if ( ASDCP_SUCCESS(result) ) MemIOWriter::WriteUi16BE(sizeof(ui32_t));
647 if ( ASDCP_SUCCESS(result) ) MemIOWriter::WriteUi32BE(*value);
653 ASDCP::MXF::TLVWriter::WriteUi64(const MDDEntry& Entry, ui64_t* value)
655 ASDCP_TEST_NULL(value);
656 Result_t result = WriteTag(Entry);
657 if ( ASDCP_SUCCESS(result) ) MemIOWriter::WriteUi16BE(sizeof(ui64_t));
658 if ( ASDCP_SUCCESS(result) ) MemIOWriter::WriteUi64BE(*value);
663 //----------------------------------------------------------------------------------------------------
666 ASDCP::MXF::Raw::Raw()
671 ASDCP::MXF::Raw::~Raw()
677 ASDCP::MXF::Raw::Unarchive(ASDCP::MemIOReader& Reader)
679 ui32_t payload_size = Reader.Remainder();
681 if ( payload_size == 0 )
684 Result_t result = Capacity(payload_size);
686 if ( ASDCP_SUCCESS(result) )
688 memcpy(Data(), Reader.CurrentData(), payload_size);
697 ASDCP::MXF::Raw::Archive(ASDCP::MemIOWriter& Writer) const
699 return Writer.WriteRaw(RoData(), Size());
704 ASDCP::MXF::Raw::ToString(char* str_buf) const
707 bin2hex(RoData(), Size(), str_buf, IdentBufferLen);
708 snprintf(str_buf, IdentBufferLen, "%s\n", str_buf);