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 //------------------------------------------------------------------------------------------
39 ASDCP::UID::operator=(const UMID& rhs)
47 ASDCP::UMID::MakeUMID(int Type)
50 AssetID.GenRandomValue();
51 MakeUMID(Type, AssetID);
56 ASDCP::UMID::MakeUMID(int Type, const UUID& AssetID)
58 // Set the non-varying base of the UMID
59 static const byte_t UMIDBase[10] = { 0x06, 0x0a, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
60 memcpy(m_Value, UMIDBase, 10);
62 // Correct to v5 dictionary for new (330M-2003) types
69 // We are using a GUID for material number, and no defined instance method
72 // Length of UMID "Value" is 19 bytes
75 // Set instance number to zero as this is the first instance of this material
76 m_Value[13] = m_Value[14] = m_Value[15] = 0;
78 memcpy(&m_Value[16], AssetID.Value(), AssetID.Size());
82 // Write the timestamp value to the given buffer in the form 2004-05-01 13:20:00.000
83 // returns 0 if the buffer is smaller than DateTimeLen
85 ASDCP::UMID::ToString(char* str_buf) const
89 snprintf(str_buf, IdentBufferLen, "[%02x%02x%02x%02x.%02x%02x.%02x%02x.%02x%02x%02x%02x],%02x,%02x,%02x,%02x,",
90 m_Value[0], m_Value[1], m_Value[2], m_Value[3], m_Value[4], m_Value[5], m_Value[6], m_Value[7],
91 m_Value[8], m_Value[9], m_Value[10], m_Value[11], m_Value[12], m_Value[13], m_Value[14], m_Value[15]
94 ui32_t offset = strlen(str_buf);
96 if ( ( m_Value[8] & 0x80 ) == 0 )
98 // half-swapped UL, use [bbaa9988.ddcc.ffee.00010203.04050607]
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[24], m_Value[25], m_Value[26], m_Value[27], m_Value[28], m_Value[29], m_Value[30], m_Value[31],
102 m_Value[16], m_Value[17], m_Value[18], m_Value[19], m_Value[20], m_Value[21], m_Value[22], m_Value[23]
107 // UUID, use {00112233-4455-6677-8899-aabbccddeeff}
108 snprintf(str_buf + offset, IdentBufferLen - offset,
109 "{%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
110 m_Value[16], m_Value[17], m_Value[18], m_Value[19], m_Value[20], m_Value[21], m_Value[22], m_Value[23],
111 m_Value[24], m_Value[25], m_Value[26], m_Value[27], m_Value[28], m_Value[29], m_Value[30], m_Value[31]
120 ASDCP::UUID::GenRandomValue()
123 RNG.FillRandom(m_Value, UUIDlen);
124 m_Value[6] &= 0x0f; // clear bits 4-7
125 m_Value[6] |= 0x40; // set UUID version
126 m_Value[8] &= 0x3f; // clear bits 6&7
127 m_Value[8] |= 0x80; // set bit 7
131 //------------------------------------------------------------------------------------------
134 const ASDCP::MXF::UTF16String&
135 ASDCP::MXF::UTF16String::operator=(const char* sz)
137 if ( sz == 0 || *sz == 0 )
144 ui32_t len = xmin((ui32_t)strlen(sz), (IdentBufferLen - 1));
146 memcpy(m_buffer, sz, m_length);
147 m_buffer[m_length] = 0;
156 ASDCP::MXF::UTF16String::Unarchive(ASDCP::MemIOReader& Reader)
158 const byte_t* p = Reader.Data() + Reader.Offset();
159 /// cheating - for all use cases, we know the previous two bytes are the length
160 m_length = ASDCP_i16_BE(cp2i<ui16_t>(p-2));
161 assert(m_length % 2 == 0);
163 assert(IdentBufferLen >= m_length);
166 for ( i = 0; i < m_length; i++ )
167 m_buffer[i] = p[(i*2)+1];
171 Reader.SkipOffset(m_length*2);
177 ASDCP::MXF::UTF16String::Archive(ASDCP::MemIOWriter& Writer)
179 byte_t* p = Writer.Data() + Writer.Size();
181 m_length = strlen(m_buffer);
182 memset(p, 0, m_length*2);
184 for ( i = 0; i < m_length; i++ )
185 p[(i*2)+1] = m_buffer[i];
187 Writer.AddOffset(m_length * 2 );
192 //------------------------------------------------------------------------------------------
197 #define TIMESTAMP_TO_SYSTIME(ts, t) \
198 (t)->wYear = (ts).Year; /* year */ \
199 (t)->wMonth = (ts).Month; /* month of year (1 - 12) */ \
200 (t)->wDay = (ts).Day; /* day of month (1 - 31) */ \
201 (t)->wHour = (ts).Hour; /* hours (0 - 23) */ \
202 (t)->wMinute = (ts).Minute; /* minutes (0 - 59) */ \
203 (t)->wSecond = (ts).Second; /* seconds (0 - 60) */ \
204 (t)->wDayOfWeek = 0; \
205 (t)->wMilliseconds = ((ts).Tick * 4);
207 #define SYSTIME_TO_TIMESTAMP(t, ts) \
208 (ts).Year = (t)->wYear; /* year */ \
209 (ts).Month = (t)->wMonth; /* month of year (1 - 12) */ \
210 (ts).Day = (t)->wDay; /* day of month (1 - 31) */ \
211 (ts).Hour = (t)->wHour; /* hours (0 - 23) */ \
212 (ts).Minute = (t)->wMinute; /* minutes (0 - 59) */ \
213 (ts).Second = (t)->wSecond; /* seconds (0 - 60) */ \
214 (ts).Tick = (t)->wMilliseconds / 4;
217 ASDCP::MXF::Timestamp::Timestamp() :
218 Year(0), Month(0), Day(0), Hour(0), Minute(0), Second(0), Tick(0)
221 GetSystemTime(&sys_time);
222 SYSTIME_TO_TIMESTAMP(&sys_time, *this);
227 ASDCP::MXF::Timestamp::operator<(const Timestamp& rhs) const
229 SYSTEMTIME lhst, rhst;
232 TIMESTAMP_TO_SYSTIME(*this, &lhst);
233 TIMESTAMP_TO_SYSTIME(rhs, &rhst);
234 SystemTimeToFileTime(&lhst, &lft);
235 SystemTimeToFileTime(&rhst, &rft);
236 return ( CompareFileTime(&lft, &rft) == -1 );
240 seconds_to_ns100(ui32_t seconds)
242 return ((ui64_t)seconds * 10000000);
247 ASDCP::MXF::Timestamp::AddDays(i32_t days)
249 SYSTEMTIME current_st;
251 ULARGE_INTEGER current_ul;
255 TIMESTAMP_TO_SYSTIME(*this, ¤t_st);
256 SystemTimeToFileTime(¤t_st, ¤t_ft);
257 memcpy(¤t_ul, ¤t_ft, sizeof(current_ul));
258 current_ul.QuadPart += ( seconds_to_ns100(86400) * (ui64_t)days );
259 memcpy(¤t_ft, ¤t_ul, sizeof(current_ft));
260 FileTimeToSystemTime(¤t_ft, ¤t_st);
261 SYSTIME_TO_TIMESTAMP(¤t_st, *this);
267 ASDCP::MXF::Timestamp::AddHours(i32_t hours)
269 SYSTEMTIME current_st;
271 ULARGE_INTEGER current_ul;
275 TIMESTAMP_TO_SYSTIME(*this, ¤t_st);
276 SystemTimeToFileTime(¤t_st, ¤t_ft);
277 memcpy(¤t_ul, ¤t_ft, sizeof(current_ul));
278 current_ul.QuadPart += ( seconds_to_ns100(3600) * (ui64_t)hours );
279 memcpy(¤t_ft, ¤t_ul, sizeof(current_ft));
280 FileTimeToSystemTime(¤t_ft, ¤t_st);
281 SYSTIME_TO_TIMESTAMP(¤t_st, *this);
289 #define TIMESTAMP_TO_TM(ts, t) \
290 (t)->tm_year = (ts).Year - 1900; /* year - 1900 */ \
291 (t)->tm_mon = (ts).Month - 1; /* month of year (0 - 11) */ \
292 (t)->tm_mday = (ts).Day; /* day of month (1 - 31) */ \
293 (t)->tm_hour = (ts).Hour; /* hours (0 - 23) */ \
294 (t)->tm_min = (ts).Minute; /* minutes (0 - 59) */ \
295 (t)->tm_sec = (ts).Second; /* seconds (0 - 60) */
297 #define TM_TO_TIMESTAMP(t, ts) \
298 (ts).Year = (t)->tm_year + 1900; /* year - 1900 */ \
299 (ts).Month = (t)->tm_mon + 1; /* month of year (0 - 11) */ \
300 (ts).Day = (t)->tm_mday; /* day of month (1 - 31) */ \
301 (ts).Hour = (t)->tm_hour; /* hours (0 - 23) */ \
302 (ts).Minute = (t)->tm_min; /* minutes (0 - 59) */ \
303 (ts).Second = (t)->tm_sec; /* seconds (0 - 60) */
306 ASDCP::MXF::Timestamp::Timestamp() :
307 Year(0), Month(0), Day(0), Hour(0), Minute(0), Second(0)
309 time_t t_now = time(0);
310 struct tm* now = gmtime(&t_now);
311 TM_TO_TIMESTAMP(now, *this);
316 ASDCP::MXF::Timestamp::operator<(const Timestamp& rhs) const
318 struct tm lhtm, rhtm;
319 TIMESTAMP_TO_TM(*this, &lhtm);
320 TIMESTAMP_TO_TM(rhs, &rhtm);
321 return ( timegm(&lhtm) < timegm(&rhtm) );
326 ASDCP::MXF::Timestamp::AddDays(i32_t days)
332 TIMESTAMP_TO_TM(*this, ¤t);
333 time_t adj_time = timegm(¤t);
334 adj_time += 86400 * days;
335 struct tm* now = gmtime(&adj_time);
336 TM_TO_TIMESTAMP(now, *this);
342 ASDCP::MXF::Timestamp::AddHours(i32_t hours)
348 TIMESTAMP_TO_TM(*this, ¤t);
349 time_t adj_time = timegm(¤t);
350 adj_time += 3600 * hours;
351 struct tm* now = gmtime(&adj_time);
352 TM_TO_TIMESTAMP(now, *this);
359 ASDCP::MXF::Timestamp::Timestamp(const Timestamp& rhs)
369 ASDCP::MXF::Timestamp::~Timestamp()
374 const ASDCP::MXF::Timestamp&
375 ASDCP::MXF::Timestamp::operator=(const Timestamp& rhs)
388 ASDCP::MXF::Timestamp::operator==(const Timestamp& rhs) const
390 if ( Year == rhs.Year
391 && Month == rhs.Month
394 && Minute == rhs.Minute
395 && Second == rhs.Second )
403 ASDCP::MXF::Timestamp::operator!=(const Timestamp& rhs) const
405 if ( Year != rhs.Year
406 || Month != rhs.Month
409 || Minute != rhs.Minute
410 || Second != rhs.Second )
418 ASDCP::MXF::Timestamp::ToString(char* str_buf) const
420 // 2004-05-01 13:20:00.000
421 snprintf(str_buf, IntBufferLen,
422 "%04hu-%02hu-%02hu %02hu:%02hu:%02hu.000",
423 Year, Month, Day, Hour, Minute, Second, Tick);
428 //------------------------------------------------------------------------------------------
431 ASDCP::MXF::TLVReader::TLVReader(const byte_t* p, ui32_t c, IPrimerLookup* PrimerLookup) :
432 MemIOReader(p, c), m_Lookup(PrimerLookup)
434 Result_t result = RESULT_OK;
436 while ( Remainder() > 0 && ASDCP_SUCCESS(result) )
441 result = MemIOReader::ReadUi8(&Tag.a);
443 if ( ASDCP_SUCCESS(result) )
444 result = MemIOReader::ReadUi8(&Tag.b);
446 if ( ASDCP_SUCCESS(result) )
447 result = MemIOReader::ReadUi16BE(&pkt_len);
449 if ( ASDCP_SUCCESS(result) )
451 m_ElementMap.insert(TagMap::value_type(Tag, ItemInfo(m_size, pkt_len)));
452 result = SkipOffset(pkt_len);
455 if ( ASDCP_FAILURE(result) )
457 DefaultLogSink().Error("Malformed Set\n");
458 m_ElementMap.clear();
466 ASDCP::MXF::TLVReader::FindTL(const MDDEntry& Entry)
470 DefaultLogSink().Error("No Lookup service\n");
476 if ( m_Lookup->TagForKey(Entry.ul, TmpTag) != RESULT_OK )
478 if ( Entry.tag.a == 0 )
480 DefaultLogSink().Info("No such UL in this TL list: %s (%02x %02x)\n",
481 Entry.name, Entry.tag.a, Entry.tag.b);
488 TagMap::iterator e_i = m_ElementMap.find(TmpTag);
490 if ( e_i != m_ElementMap.end() )
492 m_size = (*e_i).second.first;
493 m_capacity = m_size + (*e_i).second.second;
497 DefaultLogSink().Info("Not Found (%02x %02x): %s\n", TmpTag.a, TmpTag.b, Entry.name);
503 ASDCP::MXF::TLVReader::ReadObject(const MDDEntry& Entry, IArchive* Object)
505 ASDCP_TEST_NULL(Object);
508 return Object->Unarchive(*this);
515 ASDCP::MXF::TLVReader::ReadUi8(const MDDEntry& Entry, ui8_t* value)
517 ASDCP_TEST_NULL(value);
520 return MemIOReader::ReadUi8(value);
527 ASDCP::MXF::TLVReader::ReadUi16(const MDDEntry& Entry, ui16_t* value)
529 ASDCP_TEST_NULL(value);
532 return MemIOReader::ReadUi16BE(value);
539 ASDCP::MXF::TLVReader::ReadUi32(const MDDEntry& Entry, ui32_t* value)
541 ASDCP_TEST_NULL(value);
544 return MemIOReader::ReadUi32BE(value);
551 ASDCP::MXF::TLVReader::ReadUi64(const MDDEntry& Entry, ui64_t* value)
553 ASDCP_TEST_NULL(value);
556 return MemIOReader::ReadUi64BE(value);
561 //------------------------------------------------------------------------------------------
564 ASDCP::MXF::TLVWriter::TLVWriter(byte_t* p, ui32_t c, IPrimerLookup* PrimerLookup) :
565 MemIOWriter(p, c), m_Lookup(PrimerLookup)
572 ASDCP::MXF::TLVWriter::WriteTag(const MDDEntry& Entry)
576 DefaultLogSink().Error("No Primer object available\n");
582 if ( m_Lookup->InsertTag(Entry, TmpTag) != RESULT_OK )
584 DefaultLogSink().Error("No tag for entry %s\n", Entry.name);
588 Result_t result = MemIOWriter::WriteUi8(TmpTag.a);
589 if ( ASDCP_SUCCESS(result) ) MemIOWriter::WriteUi8(TmpTag.b);
596 ASDCP::MXF::TLVWriter::WriteObject(const MDDEntry& Entry, IArchive* Object)
598 ASDCP_TEST_NULL(Object);
599 Result_t result = WriteTag(Entry);
601 // write a temp length
602 byte_t* l_p = CurrentData();
604 if ( ASDCP_SUCCESS(result) )
605 MemIOWriter::WriteUi16BE(0);
607 if ( ASDCP_SUCCESS(result) )
609 ui32_t before = Size();
610 result = Object->Archive(*this);
612 if ( ASDCP_SUCCESS(result) )
613 i2p<ui16_t>(ASDCP_i16_BE( Size() - before), l_p);
621 ASDCP::MXF::TLVWriter::WriteUi8(const MDDEntry& Entry, ui8_t* value)
623 ASDCP_TEST_NULL(value);
624 Result_t result = WriteTag(Entry);
625 if ( ASDCP_SUCCESS(result) ) MemIOWriter::WriteUi16BE(sizeof(ui8_t));
626 if ( ASDCP_SUCCESS(result) ) MemIOWriter::WriteUi8(*value);
632 ASDCP::MXF::TLVWriter::WriteUi16(const MDDEntry& Entry, ui16_t* value)
634 ASDCP_TEST_NULL(value);
635 Result_t result = WriteTag(Entry);
636 if ( ASDCP_SUCCESS(result) ) MemIOWriter::WriteUi16BE(sizeof(ui16_t));
637 if ( ASDCP_SUCCESS(result) ) MemIOWriter::WriteUi16BE(*value);
643 ASDCP::MXF::TLVWriter::WriteUi32(const MDDEntry& Entry, ui32_t* value)
645 ASDCP_TEST_NULL(value);
646 Result_t result = WriteTag(Entry);
647 if ( ASDCP_SUCCESS(result) ) MemIOWriter::WriteUi16BE(sizeof(ui32_t));
648 if ( ASDCP_SUCCESS(result) ) MemIOWriter::WriteUi32BE(*value);
654 ASDCP::MXF::TLVWriter::WriteUi64(const MDDEntry& Entry, ui64_t* value)
656 ASDCP_TEST_NULL(value);
657 Result_t result = WriteTag(Entry);
658 if ( ASDCP_SUCCESS(result) ) MemIOWriter::WriteUi16BE(sizeof(ui64_t));
659 if ( ASDCP_SUCCESS(result) ) MemIOWriter::WriteUi64BE(*value);