2 Copyright (c) 2005-2016, 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
37 using Kumu::DefaultLogSink;
39 //------------------------------------------------------------------------------------------
44 ASDCP::UL::operator==(const UL& rhs) const
46 if ( m_Value[0] == rhs.m_Value[0] &&
47 m_Value[1] == rhs.m_Value[1] &&
48 m_Value[2] == rhs.m_Value[2] &&
49 m_Value[3] == rhs.m_Value[3] &&
50 m_Value[4] == rhs.m_Value[4] &&
51 m_Value[5] == rhs.m_Value[5] &&
52 m_Value[6] == rhs.m_Value[6] &&
53 // m_Value[7] == rhs.m_Value[7] && // version is ignored when performing lookups
54 m_Value[8] == rhs.m_Value[8] &&
55 m_Value[9] == rhs.m_Value[9] &&
56 m_Value[10] == rhs.m_Value[10] &&
57 m_Value[11] == rhs.m_Value[11] &&
58 m_Value[12] == rhs.m_Value[12] &&
59 m_Value[13] == rhs.m_Value[13] &&
60 m_Value[14] == rhs.m_Value[14] &&
61 m_Value[15] == rhs.m_Value[15]
70 ASDCP::UL::MatchIgnoreStream(const UL& rhs) const
72 if ( m_Value[0] == rhs.m_Value[0] &&
73 m_Value[1] == rhs.m_Value[1] &&
74 m_Value[2] == rhs.m_Value[2] &&
75 m_Value[3] == rhs.m_Value[3] &&
76 m_Value[4] == rhs.m_Value[4] &&
77 m_Value[5] == rhs.m_Value[5] &&
78 m_Value[6] == rhs.m_Value[6] &&
79 // m_Value[7] == rhs.m_Value[7] && // version is ignored when performing lookups
80 m_Value[8] == rhs.m_Value[8] &&
81 m_Value[9] == rhs.m_Value[9] &&
82 m_Value[10] == rhs.m_Value[10] &&
83 m_Value[11] == rhs.m_Value[11] &&
84 m_Value[12] == rhs.m_Value[12] &&
85 m_Value[13] == rhs.m_Value[13] &&
86 m_Value[14] == rhs.m_Value[14]
87 // m_Value[15] == rhs.m_Value[15] // ignore stream number
96 ASDCP::UL::MatchExact(const UL& rhs) const
98 if ( m_Value[0] == rhs.m_Value[0] &&
99 m_Value[1] == rhs.m_Value[1] &&
100 m_Value[2] == rhs.m_Value[2] &&
101 m_Value[3] == rhs.m_Value[3] &&
102 m_Value[4] == rhs.m_Value[4] &&
103 m_Value[5] == rhs.m_Value[5] &&
104 m_Value[6] == rhs.m_Value[6] &&
105 m_Value[7] == rhs.m_Value[7] &&
106 m_Value[8] == rhs.m_Value[8] &&
107 m_Value[9] == rhs.m_Value[9] &&
108 m_Value[10] == rhs.m_Value[10] &&
109 m_Value[11] == rhs.m_Value[11] &&
110 m_Value[12] == rhs.m_Value[12] &&
111 m_Value[13] == rhs.m_Value[13] &&
112 m_Value[14] == rhs.m_Value[14] &&
113 m_Value[15] == rhs.m_Value[15]
121 ASDCP::UL::EncodeString(char* str_buf, ui32_t buf_len) const
123 if ( buf_len > 38 ) // room for dotted notation?
125 snprintf(str_buf, buf_len,
126 "%02x%02x%02x%02x.%02x%02x%02x%02x.%02x%02x%02x%02x.%02x%02x%02x%02x",
127 m_Value[0], m_Value[1], m_Value[2], m_Value[3],
128 m_Value[4], m_Value[5], m_Value[6], m_Value[7],
129 m_Value[8], m_Value[9], m_Value[10], m_Value[11],
130 m_Value[12], m_Value[13], m_Value[14], m_Value[15]
135 else if ( buf_len > 32 ) // room for compact?
137 snprintf(str_buf, buf_len,
138 "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
139 m_Value[0], m_Value[1], m_Value[2], m_Value[3],
140 m_Value[4], m_Value[5], m_Value[6], m_Value[7],
141 m_Value[8], m_Value[9], m_Value[10], m_Value[11],
142 m_Value[12], m_Value[13], m_Value[14], m_Value[15]
153 ASDCP::UMID::MakeUMID(int Type)
156 Kumu::GenRandomValue(AssetID);
157 MakeUMID(Type, AssetID);
162 ASDCP::UMID::MakeUMID(int Type, const UUID& AssetID)
164 // Set the non-varying base of the UMID
165 static const byte_t UMIDBase[10] = { 0x06, 0x0a, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
166 memcpy(m_Value, UMIDBase, 10);
167 m_Value[10] = Type; // Material Type
168 m_Value[12] = 0x13; // length
170 // preserved for compatibility with mfxlib
171 if( Type > 4 ) m_Value[7] = 5;
172 m_Value[11] = 0x20; // UUID/UL method, number gen undefined
175 m_Value[13] = m_Value[14] = m_Value[15] = 0;
177 memcpy(&m_Value[16], AssetID.Value(), AssetID.Size());
182 // Write the UMID value to the given buffer in the form
183 // [00000000.0000.0000.00000000],00,00,00,00,00000000.0000.0000.00000000.00000000]
185 // [00000000.0000.0000.00000000],00,00,00,00,00000000-0000-0000-0000-000000000000]
186 // returns 0 if the buffer is smaller than DateTimeLen
188 ASDCP::UMID::EncodeString(char* str_buf, ui32_t buf_len) const
192 snprintf(str_buf, buf_len, "[%02x%02x%02x%02x.%02x%02x%02x%02x.%02x%02x%02x%02x],%02x,%02x,%02x,%02x,",
193 m_Value[0], m_Value[1], m_Value[2], m_Value[3],
194 m_Value[4], m_Value[5], m_Value[6], m_Value[7],
195 m_Value[8], m_Value[9], m_Value[10], m_Value[11],
196 m_Value[12], m_Value[13], m_Value[14], m_Value[15]
199 ui32_t offset = strlen(str_buf);
201 if ( ( m_Value[8] & 0x80 ) == 0 )
203 // half-swapped UL, use [bbaa9988.ddcc.ffee.00010203.04050607]
204 snprintf(str_buf + offset, buf_len - offset,
205 "[%02x%02x%02x%02x.%02x%02x%02x%02x.%02x%02x%02x%02x.%02x%02x%02x%02x]",
206 m_Value[24], m_Value[25], m_Value[26], m_Value[27],
207 m_Value[28], m_Value[29], m_Value[30], m_Value[31],
208 m_Value[16], m_Value[17], m_Value[18], m_Value[19],
209 m_Value[20], m_Value[21], m_Value[22], m_Value[23]
214 // UUID, use {00112233-4455-6677-8899-aabbccddeeff}
215 snprintf(str_buf + offset, buf_len - offset,
216 "{%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
217 m_Value[16], m_Value[17], m_Value[18], m_Value[19],
218 m_Value[20], m_Value[21], m_Value[22], m_Value[23],
219 m_Value[24], m_Value[25], m_Value[26], m_Value[27],
220 m_Value[28], m_Value[29], m_Value[30], m_Value[31]
227 //------------------------------------------------------------------------------------------
231 ASDCP::MXF::UTF16String::UTF16String(const char* sz)
233 if ( sz != 0 && *sz != 0 )
239 ASDCP::MXF::UTF16String::UTF16String(const std::string& str)
245 const ASDCP::MXF::UTF16String&
246 ASDCP::MXF::UTF16String::operator=(const char* sz)
248 if ( sz == 0 || *sz == 0 )
258 const ASDCP::MXF::UTF16String&
259 ASDCP::MXF::UTF16String::operator=(const std::string& str)
267 ASDCP::MXF::UTF16String::EncodeString(char* str_buf, ui32_t buf_len) const
269 ui32_t write_len = Kumu::xmin(buf_len - 1, (ui32_t)size());
270 strncpy(str_buf, c_str(), write_len);
271 str_buf[write_len] = 0;
277 ASDCP::MXF::UTF16String::Unarchive(Kumu::MemIOReader* Reader)
280 const ui16_t* p = (ui16_t*)Reader->CurrentData();
281 ui32_t length = Reader->Remainder() / 2;
282 char mb_buf[MB_LEN_MAX];
285 memset(&ps, 0, sizeof(mbstate_t));
287 for ( ui32_t i = 0; i < length; i++ )
289 int count = wcrtomb(mb_buf, KM_i16_BE(p[i]), &ps);
293 DefaultLogSink().Error("Unable to decode wide character 0x%04hx\n", p[i]);
297 assert(count <= MB_LEN_MAX);
299 this->append(mb_buf);
302 Reader->SkipOffset(length*2);
308 ASDCP::MXF::UTF16String::Archive(Kumu::MemIOWriter* Writer) const
310 if ( size() > IdentBufferLen )
312 DefaultLogSink().Error("String length exceeds maximum %u bytes\n", IdentBufferLen);
316 const char* mbp = c_str();
318 ui32_t remainder = size();
319 ui32_t length = size();
323 memset(&ps, 0, sizeof(mbstate_t));
327 int count = mbrtowc(&wcp, mbp+i, remainder, &ps);
331 DefaultLogSink().Error("Error decoding multi-byte sequence starting at offset %u\n", i);
334 else if ( count == 0 )
339 bool result = Writer->WriteUi16BE((ui16_t)wcp);
341 if ( result == false )
343 DefaultLogSink().Error("No more space in memory IO writer\n");
354 //------------------------------------------------------------------------------------------
358 ASDCP::MXF::ISO8String::ISO8String(const char* sz)
360 if ( sz != 0 && *sz != 0 )
366 ASDCP::MXF::ISO8String::ISO8String(const std::string& str)
373 const ASDCP::MXF::ISO8String&
374 ASDCP::MXF::ISO8String::operator=(const char* sz)
376 if ( sz == 0 || *sz == 0 )
386 const ASDCP::MXF::ISO8String&
387 ASDCP::MXF::ISO8String::operator=(const std::string& str)
395 ASDCP::MXF::ISO8String::EncodeString(char* str_buf, ui32_t buf_len) const
397 ui32_t write_len = Kumu::xmin(buf_len - 1, (ui32_t)size());
398 strncpy(str_buf, c_str(), write_len);
399 str_buf[write_len] = 0;
405 ASDCP::MXF::ISO8String::Unarchive(Kumu::MemIOReader* Reader)
407 assign((char*)Reader->CurrentData(), Reader->Remainder());
413 ASDCP::MXF::ISO8String::Archive(Kumu::MemIOWriter* Writer) const
415 if ( size() > IdentBufferLen )
417 DefaultLogSink().Error("String length exceeds maximum %u bytes\n", IdentBufferLen);
421 return Writer->WriteRaw((const byte_t*)c_str(), size());
424 //------------------------------------------------------------------------------------------
427 ASDCP::MXF::TLVReader::TLVReader(const byte_t* p, ui32_t c, IPrimerLookup* PrimerLookup) :
428 MemIOReader(p, c), m_Lookup(PrimerLookup)
430 Result_t result = RESULT_OK;
432 while ( Remainder() > 0 && ASDCP_SUCCESS(result) )
437 if ( MemIOReader::ReadUi8(&Tag.a) )
438 if ( MemIOReader::ReadUi8(&Tag.b) )
439 if ( MemIOReader::ReadUi16BE(&pkt_len) )
441 m_ElementMap.insert(TagMap::value_type(Tag, ItemInfo(m_size, pkt_len)));
442 if ( SkipOffset(pkt_len) )
446 DefaultLogSink().Error("Malformed Set\n");
447 m_ElementMap.clear();
448 result = RESULT_KLV_CODING(__LINE__, __FILE__);
454 ASDCP::MXF::TLVReader::FindTL(const MDDEntry& Entry)
458 DefaultLogSink().Error("No Lookup service\n");
464 if ( m_Lookup->TagForKey(Entry.ul, TmpTag) != RESULT_OK )
466 if ( Entry.tag.a == 0 )
468 // DefaultLogSink().Debug("No such UL in this TL list: %s (%02x %02x)\n",
469 // Entry.name, Entry.tag.a, Entry.tag.b);
476 TagMap::iterator e_i = m_ElementMap.find(TmpTag);
478 if ( e_i != m_ElementMap.end() )
480 m_size = (*e_i).second.first;
481 m_capacity = m_size + (*e_i).second.second;
485 // DefaultLogSink().Debug("Not Found (%02x %02x): %s\n", TmpTag.a, TmpTag.b, Entry.name);
491 ASDCP::MXF::TLVReader::ReadObject(const MDDEntry& Entry, Kumu::IArchive* Object)
493 ASDCP_TEST_NULL(Object);
497 if ( m_size < m_capacity ) // don't try to unarchive an empty item
499 // TODO: carry on if uachive fails
500 return Object->Unarchive(this) ? RESULT_OK : RESULT_FALSE(__LINE__, __FILE__);
509 ASDCP::MXF::TLVReader::ReadUi8(const MDDEntry& Entry, ui8_t* value)
511 ASDCP_TEST_NULL(value);
514 return MemIOReader::ReadUi8(value) ? RESULT_OK : RESULT_FALSE(__LINE__, __FILE__);
521 ASDCP::MXF::TLVReader::ReadUi16(const MDDEntry& Entry, ui16_t* value)
523 ASDCP_TEST_NULL(value);
526 return MemIOReader::ReadUi16BE(value) ? RESULT_OK : RESULT_FALSE(__LINE__, __FILE__);
533 ASDCP::MXF::TLVReader::ReadUi32(const MDDEntry& Entry, ui32_t* value)
535 ASDCP_TEST_NULL(value);
538 return MemIOReader::ReadUi32BE(value) ? RESULT_OK : RESULT_FALSE(__LINE__, __FILE__);
545 ASDCP::MXF::TLVReader::ReadUi64(const MDDEntry& Entry, ui64_t* value)
547 ASDCP_TEST_NULL(value);
550 return MemIOReader::ReadUi64BE(value) ? RESULT_OK : RESULT_FALSE(__LINE__, __FILE__);
555 //------------------------------------------------------------------------------------------
558 ASDCP::MXF::TLVWriter::TLVWriter(byte_t* p, ui32_t c, IPrimerLookup* PrimerLookup) :
559 MemIOWriter(p, c), m_Lookup(PrimerLookup)
566 ASDCP::MXF::TLVWriter::WriteTag(const MDDEntry& Entry)
570 DefaultLogSink().Error("No Primer object available.\n");
576 if ( m_Lookup->InsertTag(Entry, TmpTag) != RESULT_OK )
578 DefaultLogSink().Error("No tag for entry %s\n", Entry.name);
582 if ( ! MemIOWriter::WriteUi8(TmpTag.a) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
583 if ( ! MemIOWriter::WriteUi8(TmpTag.b) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
589 ASDCP::MXF::TLVWriter::WriteObject(const MDDEntry& Entry, Kumu::IArchive* Object)
591 ASDCP_TEST_NULL(Object);
593 if ( Entry.optional && ! Object->HasValue() )
596 Result_t result = WriteTag(Entry);
598 if ( ASDCP_SUCCESS(result) )
600 // write a temp length
601 byte_t* l_p = CurrentData();
603 if ( ! MemIOWriter::WriteUi16BE(0) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
605 ui32_t before = Length();
606 if ( ! Object->Archive(this) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
607 if ( (Length() - before) > 0xffffL ) return RESULT_KLV_CODING(__LINE__, __FILE__);
608 Kumu::i2p<ui16_t>(KM_i16_BE(Length() - before), l_p);
616 ASDCP::MXF::TLVWriter::WriteUi8(const MDDEntry& Entry, ui8_t* value)
618 ASDCP_TEST_NULL(value);
619 Result_t result = WriteTag(Entry);
621 if ( ASDCP_SUCCESS(result) )
623 if ( ! MemIOWriter::WriteUi16BE(sizeof(ui8_t)) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
624 if ( ! MemIOWriter::WriteUi8(*value) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
632 ASDCP::MXF::TLVWriter::WriteUi16(const MDDEntry& Entry, ui16_t* value)
634 ASDCP_TEST_NULL(value);
635 Result_t result = WriteTag(Entry);
637 if ( KM_SUCCESS(result) )
639 if ( ! MemIOWriter::WriteUi16BE(sizeof(ui16_t)) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
640 if ( ! MemIOWriter::WriteUi16BE(*value) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
648 ASDCP::MXF::TLVWriter::WriteUi32(const MDDEntry& Entry, ui32_t* value)
650 ASDCP_TEST_NULL(value);
651 Result_t result = WriteTag(Entry);
653 if ( KM_SUCCESS(result) )
655 if ( ! MemIOWriter::WriteUi16BE(sizeof(ui32_t)) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
656 if ( ! MemIOWriter::WriteUi32BE(*value) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
664 ASDCP::MXF::TLVWriter::WriteUi64(const MDDEntry& Entry, ui64_t* value)
666 ASDCP_TEST_NULL(value);
667 Result_t result = WriteTag(Entry);
669 if ( KM_SUCCESS(result) )
671 if ( ! MemIOWriter::WriteUi16BE(sizeof(ui64_t)) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
672 if ( ! MemIOWriter::WriteUi64BE(*value) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
679 //----------------------------------------------------------------------------------------------------
683 ASDCP::MXF::RGBALayout::RGBALayout()
685 memset(m_value, 0, RGBAValueLength);
688 ASDCP::MXF::RGBALayout::RGBALayout(const byte_t* value)
690 memcpy(m_value, value, RGBAValueLength);
693 ASDCP::MXF::RGBALayout::~RGBALayout()
698 get_char_for_code(byte_t c)
700 for ( int i = 0; ASDCP::MXF::RGBALayoutTable[i].code != 0; ++i )
702 if ( ASDCP::MXF::RGBALayoutTable[i].code == c )
704 return ASDCP::MXF::RGBALayoutTable[i].symbol;
713 ASDCP::MXF::RGBALayout::EncodeString(char* buf, ui32_t buf_len) const
718 for ( int i = 0; i < RGBAValueLength && m_value[i] != 0; i += 2 )
720 snprintf(tmp_buf, 64, "%c(%d)", get_char_for_code(m_value[i]), m_value[i+1]);
722 if ( ! tmp_str.empty() )
730 assert(tmp_str.size() < buf_len);
731 strncpy(buf, tmp_str.c_str(), tmp_str.size());
736 //----------------------------------------------------------------------------------------------------
739 ASDCP::MXF::Raw::Raw()
744 ASDCP::MXF::Raw::~Raw()
750 ASDCP::MXF::Raw::Unarchive(Kumu::MemIOReader* Reader)
752 ui32_t payload_size = Reader->Remainder();
753 if ( payload_size == 0 ) return false;
754 if ( KM_FAILURE(Capacity(payload_size)) ) return false;
756 memcpy(Data(), Reader->CurrentData(), payload_size);
757 Length(payload_size);
763 ASDCP::MXF::Raw::Archive(Kumu::MemIOWriter* Writer) const
765 return Writer->WriteRaw(RoData(), Length());
770 ASDCP::MXF::Raw::EncodeString(char* str_buf, ui32_t buf_len) const
773 Kumu::bin2hex(RoData(), Length(), str_buf, buf_len);