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+1];
284 for ( ui32_t i = 0; i < length; i++ )
286 int count = wctomb(mb_buf, KM_i16_BE(p[i]));
290 DefaultLogSink().Error("Unable to decode wide character 0x%04hx\n", p[i]);
294 assert(count <= MB_LEN_MAX);
296 this->append(mb_buf);
299 Reader->SkipOffset(length*2);
305 ASDCP::MXF::UTF16String::Archive(Kumu::MemIOWriter* Writer) const
307 if ( size() > IdentBufferLen )
309 DefaultLogSink().Error("String length exceeds maximum %u bytes\n", IdentBufferLen);
313 const char* mbp = c_str();
315 ui32_t remainder = size();
316 ui32_t length = size();
321 int count = mbtowc(&wcp, mbp+i, remainder);
325 DefaultLogSink().Error("Error decoding multi-byte sequence starting at offset %u\n", i);
328 else if ( count == 0 )
333 bool result = Writer->WriteUi16BE((ui16_t)wcp);
335 if ( result == false )
337 DefaultLogSink().Error("No more space in memory IO writer\n");
348 //------------------------------------------------------------------------------------------
352 ASDCP::MXF::ISO8String::ISO8String(const char* sz)
354 if ( sz != 0 && *sz != 0 )
360 ASDCP::MXF::ISO8String::ISO8String(const std::string& str)
367 const ASDCP::MXF::ISO8String&
368 ASDCP::MXF::ISO8String::operator=(const char* sz)
370 if ( sz == 0 || *sz == 0 )
380 const ASDCP::MXF::ISO8String&
381 ASDCP::MXF::ISO8String::operator=(const std::string& str)
389 ASDCP::MXF::ISO8String::EncodeString(char* str_buf, ui32_t buf_len) const
391 ui32_t write_len = Kumu::xmin(buf_len - 1, (ui32_t)size());
392 strncpy(str_buf, c_str(), write_len);
393 str_buf[write_len] = 0;
399 ASDCP::MXF::ISO8String::Unarchive(Kumu::MemIOReader* Reader)
401 assign((char*)Reader->CurrentData(), Reader->Remainder());
407 ASDCP::MXF::ISO8String::Archive(Kumu::MemIOWriter* Writer) const
409 if ( size() > IdentBufferLen )
411 DefaultLogSink().Error("String length exceeds maximum %u bytes\n", IdentBufferLen);
415 return Writer->WriteRaw((const byte_t*)c_str(), size());
418 //------------------------------------------------------------------------------------------
421 ASDCP::MXF::TLVReader::TLVReader(const byte_t* p, ui32_t c, IPrimerLookup* PrimerLookup) :
422 MemIOReader(p, c), m_Lookup(PrimerLookup)
424 Result_t result = RESULT_OK;
426 while ( Remainder() > 0 && ASDCP_SUCCESS(result) )
431 if ( MemIOReader::ReadUi8(&Tag.a) )
432 if ( MemIOReader::ReadUi8(&Tag.b) )
433 if ( MemIOReader::ReadUi16BE(&pkt_len) )
435 m_ElementMap.insert(TagMap::value_type(Tag, ItemInfo(m_size, pkt_len)));
436 if ( SkipOffset(pkt_len) )
440 DefaultLogSink().Error("Malformed Set\n");
441 m_ElementMap.clear();
442 result = RESULT_KLV_CODING(__LINE__, __FILE__);
448 ASDCP::MXF::TLVReader::FindTL(const MDDEntry& Entry)
452 DefaultLogSink().Error("No Lookup service\n");
458 if ( m_Lookup->TagForKey(Entry.ul, TmpTag) != RESULT_OK )
460 if ( Entry.tag.a == 0 )
462 // DefaultLogSink().Debug("No such UL in this TL list: %s (%02x %02x)\n",
463 // Entry.name, Entry.tag.a, Entry.tag.b);
470 TagMap::iterator e_i = m_ElementMap.find(TmpTag);
472 if ( e_i != m_ElementMap.end() )
474 m_size = (*e_i).second.first;
475 m_capacity = m_size + (*e_i).second.second;
479 // DefaultLogSink().Debug("Not Found (%02x %02x): %s\n", TmpTag.a, TmpTag.b, Entry.name);
485 ASDCP::MXF::TLVReader::ReadObject(const MDDEntry& Entry, Kumu::IArchive* Object)
487 ASDCP_TEST_NULL(Object);
491 if ( m_size < m_capacity ) // don't try to unarchive an empty item
493 // TODO: carry on if uachive fails
494 return Object->Unarchive(this) ? RESULT_OK : RESULT_FALSE(__LINE__, __FILE__);
503 ASDCP::MXF::TLVReader::ReadUi8(const MDDEntry& Entry, ui8_t* value)
505 ASDCP_TEST_NULL(value);
508 return MemIOReader::ReadUi8(value) ? RESULT_OK : RESULT_FALSE(__LINE__, __FILE__);
515 ASDCP::MXF::TLVReader::ReadUi16(const MDDEntry& Entry, ui16_t* value)
517 ASDCP_TEST_NULL(value);
520 return MemIOReader::ReadUi16BE(value) ? RESULT_OK : RESULT_FALSE(__LINE__, __FILE__);
527 ASDCP::MXF::TLVReader::ReadUi32(const MDDEntry& Entry, ui32_t* value)
529 ASDCP_TEST_NULL(value);
532 return MemIOReader::ReadUi32BE(value) ? RESULT_OK : RESULT_FALSE(__LINE__, __FILE__);
539 ASDCP::MXF::TLVReader::ReadUi64(const MDDEntry& Entry, ui64_t* value)
541 ASDCP_TEST_NULL(value);
544 return MemIOReader::ReadUi64BE(value) ? RESULT_OK : RESULT_FALSE(__LINE__, __FILE__);
549 //------------------------------------------------------------------------------------------
552 ASDCP::MXF::TLVWriter::TLVWriter(byte_t* p, ui32_t c, IPrimerLookup* PrimerLookup) :
553 MemIOWriter(p, c), m_Lookup(PrimerLookup)
560 ASDCP::MXF::TLVWriter::WriteTag(const MDDEntry& Entry)
564 DefaultLogSink().Error("No Primer object available.\n");
570 if ( m_Lookup->InsertTag(Entry, TmpTag) != RESULT_OK )
572 DefaultLogSink().Error("No tag for entry %s\n", Entry.name);
576 if ( ! MemIOWriter::WriteUi8(TmpTag.a) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
577 if ( ! MemIOWriter::WriteUi8(TmpTag.b) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
583 ASDCP::MXF::TLVWriter::WriteObject(const MDDEntry& Entry, Kumu::IArchive* Object)
585 ASDCP_TEST_NULL(Object);
587 if ( Entry.optional && ! Object->HasValue() )
590 Result_t result = WriteTag(Entry);
592 if ( ASDCP_SUCCESS(result) )
594 // write a temp length
595 byte_t* l_p = CurrentData();
597 if ( ! MemIOWriter::WriteUi16BE(0) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
599 ui32_t before = Length();
600 if ( ! Object->Archive(this) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
601 if ( (Length() - before) > 0xffffL ) return RESULT_KLV_CODING(__LINE__, __FILE__);
602 Kumu::i2p<ui16_t>(KM_i16_BE(Length() - before), l_p);
610 ASDCP::MXF::TLVWriter::WriteUi8(const MDDEntry& Entry, ui8_t* value)
612 ASDCP_TEST_NULL(value);
613 Result_t result = WriteTag(Entry);
615 if ( ASDCP_SUCCESS(result) )
617 if ( ! MemIOWriter::WriteUi16BE(sizeof(ui8_t)) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
618 if ( ! MemIOWriter::WriteUi8(*value) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
626 ASDCP::MXF::TLVWriter::WriteUi16(const MDDEntry& Entry, ui16_t* value)
628 ASDCP_TEST_NULL(value);
629 Result_t result = WriteTag(Entry);
631 if ( KM_SUCCESS(result) )
633 if ( ! MemIOWriter::WriteUi16BE(sizeof(ui16_t)) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
634 if ( ! MemIOWriter::WriteUi16BE(*value) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
642 ASDCP::MXF::TLVWriter::WriteUi32(const MDDEntry& Entry, ui32_t* value)
644 ASDCP_TEST_NULL(value);
645 Result_t result = WriteTag(Entry);
647 if ( KM_SUCCESS(result) )
649 if ( ! MemIOWriter::WriteUi16BE(sizeof(ui32_t)) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
650 if ( ! MemIOWriter::WriteUi32BE(*value) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
658 ASDCP::MXF::TLVWriter::WriteUi64(const MDDEntry& Entry, ui64_t* value)
660 ASDCP_TEST_NULL(value);
661 Result_t result = WriteTag(Entry);
663 if ( KM_SUCCESS(result) )
665 if ( ! MemIOWriter::WriteUi16BE(sizeof(ui64_t)) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
666 if ( ! MemIOWriter::WriteUi64BE(*value) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
673 //----------------------------------------------------------------------------------------------------
677 ASDCP::MXF::RGBALayout::RGBALayout()
679 memset(m_value, 0, RGBAValueLength);
682 ASDCP::MXF::RGBALayout::RGBALayout(const byte_t* value)
684 memcpy(m_value, value, RGBAValueLength);
687 ASDCP::MXF::RGBALayout::~RGBALayout()
692 get_char_for_code(byte_t c)
694 for ( int i = 0; ASDCP::MXF::RGBALayoutTable[i].code != 0; ++i )
696 if ( ASDCP::MXF::RGBALayoutTable[i].code == c )
698 return ASDCP::MXF::RGBALayoutTable[i].symbol;
707 ASDCP::MXF::RGBALayout::EncodeString(char* buf, ui32_t buf_len) const
712 for ( int i = 0; i < RGBAValueLength && m_value[i] != 0; i += 2 )
714 snprintf(tmp_buf, 64, "%c(%d)", get_char_for_code(m_value[i]), m_value[i+1]);
716 if ( ! tmp_str.empty() )
724 assert(tmp_str.size() < buf_len);
725 strncpy(buf, tmp_str.c_str(), tmp_str.size());
730 //----------------------------------------------------------------------------------------------------
733 ASDCP::MXF::Raw::Raw()
738 ASDCP::MXF::Raw::~Raw()
744 ASDCP::MXF::Raw::Unarchive(Kumu::MemIOReader* Reader)
746 ui32_t payload_size = Reader->Remainder();
747 if ( payload_size == 0 ) return false;
748 if ( KM_FAILURE(Capacity(payload_size)) ) return false;
750 memcpy(Data(), Reader->CurrentData(), payload_size);
751 Length(payload_size);
757 ASDCP::MXF::Raw::Archive(Kumu::MemIOWriter* Writer) const
759 return Writer->WriteRaw(RoData(), Length());
764 ASDCP::MXF::Raw::EncodeString(char* str_buf, ui32_t buf_len) const
767 Kumu::bin2hex(RoData(), Length(), str_buf, buf_len);