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]
71 ASDCP::UL::operator<(const UL& rhs) const
73 if ( m_Value[0] < rhs.m_Value[0] ) return true;
74 if ( m_Value[0] == rhs.m_Value[0] )
76 if ( m_Value[1] < rhs.m_Value[1] ) return true;
77 if ( m_Value[1] == rhs.m_Value[1] )
79 if ( m_Value[2] < rhs.m_Value[2] ) return true;
80 if ( m_Value[2] == rhs.m_Value[2] )
82 if ( m_Value[3] < rhs.m_Value[3] ) return true;
83 if ( m_Value[3] == rhs.m_Value[3] )
85 if ( m_Value[4] < rhs.m_Value[4] ) return true;
86 if ( m_Value[4] == rhs.m_Value[4] )
88 if ( m_Value[5] < rhs.m_Value[5] ) return true;
89 if ( m_Value[5] == rhs.m_Value[5] )
91 if ( m_Value[6] < rhs.m_Value[6] ) return true;
92 if ( m_Value[6] == rhs.m_Value[6] )
94 if ( m_Value[8] < rhs.m_Value[8] ) return true;
95 if ( m_Value[8] == rhs.m_Value[8] )
97 if ( m_Value[9] < rhs.m_Value[9] ) return true;
98 if ( m_Value[9] == rhs.m_Value[9] )
100 if ( m_Value[10] < rhs.m_Value[10] ) return true;
101 if ( m_Value[10] == rhs.m_Value[10] )
103 if ( m_Value[11] < rhs.m_Value[11] ) return true;
104 if ( m_Value[11] == rhs.m_Value[11] )
106 if ( m_Value[12] < rhs.m_Value[12] ) return true;
107 if ( m_Value[12] == rhs.m_Value[12] )
109 if ( m_Value[13] < rhs.m_Value[13] ) return true;
110 if ( m_Value[13] == rhs.m_Value[13] )
112 if ( m_Value[14] < rhs.m_Value[14] ) return true;
113 if ( m_Value[14] == rhs.m_Value[14] )
115 if ( m_Value[15] < rhs.m_Value[15] ) return true;
136 ASDCP::UL::MatchIgnoreStream(const UL& rhs) const
138 if ( m_Value[0] == rhs.m_Value[0] &&
139 m_Value[1] == rhs.m_Value[1] &&
140 m_Value[2] == rhs.m_Value[2] &&
141 m_Value[3] == rhs.m_Value[3] &&
142 m_Value[4] == rhs.m_Value[4] &&
143 m_Value[5] == rhs.m_Value[5] &&
144 m_Value[6] == rhs.m_Value[6] &&
145 // m_Value[7] == rhs.m_Value[7] && // version is ignored when performing lookups
146 m_Value[8] == rhs.m_Value[8] &&
147 m_Value[9] == rhs.m_Value[9] &&
148 m_Value[10] == rhs.m_Value[10] &&
149 m_Value[11] == rhs.m_Value[11] &&
150 m_Value[12] == rhs.m_Value[12] &&
151 m_Value[13] == rhs.m_Value[13] &&
152 m_Value[14] == rhs.m_Value[14]
153 // m_Value[15] == rhs.m_Value[15] // ignore stream number
162 ASDCP::UL::ExactMatch(const UL& rhs) const
164 if ( m_Value[0] == rhs.m_Value[0] &&
165 m_Value[1] == rhs.m_Value[1] &&
166 m_Value[2] == rhs.m_Value[2] &&
167 m_Value[3] == rhs.m_Value[3] &&
168 m_Value[4] == rhs.m_Value[4] &&
169 m_Value[5] == rhs.m_Value[5] &&
170 m_Value[6] == rhs.m_Value[6] &&
171 m_Value[7] == rhs.m_Value[7] &&
172 m_Value[8] == rhs.m_Value[8] &&
173 m_Value[9] == rhs.m_Value[9] &&
174 m_Value[10] == rhs.m_Value[10] &&
175 m_Value[11] == rhs.m_Value[11] &&
176 m_Value[12] == rhs.m_Value[12] &&
177 m_Value[13] == rhs.m_Value[13] &&
178 m_Value[14] == rhs.m_Value[14] &&
179 m_Value[15] == rhs.m_Value[15]
187 ASDCP::UL::EncodeString(char* str_buf, ui32_t buf_len) const
189 if ( buf_len > 38 ) // room for dotted notation?
191 snprintf(str_buf, buf_len,
192 "%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]
201 else if ( buf_len > 32 ) // room for compact?
203 snprintf(str_buf, buf_len,
204 "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
205 m_Value[0], m_Value[1], m_Value[2], m_Value[3],
206 m_Value[4], m_Value[5], m_Value[6], m_Value[7],
207 m_Value[8], m_Value[9], m_Value[10], m_Value[11],
208 m_Value[12], m_Value[13], m_Value[14], m_Value[15]
219 ASDCP::UMID::MakeUMID(int Type)
222 Kumu::GenRandomValue(AssetID);
223 MakeUMID(Type, AssetID);
228 ASDCP::UMID::MakeUMID(int Type, const UUID& AssetID)
230 // Set the non-varying base of the UMID
231 static const byte_t UMIDBase[10] = { 0x06, 0x0a, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
232 memcpy(m_Value, UMIDBase, 10);
233 m_Value[10] = Type; // Material Type
234 m_Value[12] = 0x13; // length
236 // preserved for compatibility with mfxlib
237 if( Type > 4 ) m_Value[7] = 5;
238 m_Value[11] = 0x20; // UUID/UL method, number gen undefined
241 m_Value[13] = m_Value[14] = m_Value[15] = 0;
243 memcpy(&m_Value[16], AssetID.Value(), AssetID.Size());
248 // Write the UMID value to the given buffer in the form
249 // [00000000.0000.0000.00000000],00,00,00,00,00000000.0000.0000.00000000.00000000]
251 // [00000000.0000.0000.00000000],00,00,00,00,00000000-0000-0000-0000-000000000000]
252 // returns 0 if the buffer is smaller than DateTimeLen
254 ASDCP::UMID::EncodeString(char* str_buf, ui32_t buf_len) const
258 snprintf(str_buf, buf_len, "[%02x%02x%02x%02x.%02x%02x%02x%02x.%02x%02x%02x%02x],%02x,%02x,%02x,%02x,",
259 m_Value[0], m_Value[1], m_Value[2], m_Value[3],
260 m_Value[4], m_Value[5], m_Value[6], m_Value[7],
261 m_Value[8], m_Value[9], m_Value[10], m_Value[11],
262 m_Value[12], m_Value[13], m_Value[14], m_Value[15]
265 ui32_t offset = strlen(str_buf);
267 if ( ( m_Value[8] & 0x80 ) == 0 )
269 // half-swapped UL, use [bbaa9988.ddcc.ffee.00010203.04050607]
270 snprintf(str_buf + offset, buf_len - offset,
271 "[%02x%02x%02x%02x.%02x%02x%02x%02x.%02x%02x%02x%02x.%02x%02x%02x%02x]",
272 m_Value[24], m_Value[25], m_Value[26], m_Value[27],
273 m_Value[28], m_Value[29], m_Value[30], m_Value[31],
274 m_Value[16], m_Value[17], m_Value[18], m_Value[19],
275 m_Value[20], m_Value[21], m_Value[22], m_Value[23]
280 // UUID, use {00112233-4455-6677-8899-aabbccddeeff}
281 snprintf(str_buf + offset, buf_len - offset,
282 "{%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
283 m_Value[16], m_Value[17], m_Value[18], m_Value[19],
284 m_Value[20], m_Value[21], m_Value[22], m_Value[23],
285 m_Value[24], m_Value[25], m_Value[26], m_Value[27],
286 m_Value[28], m_Value[29], m_Value[30], m_Value[31]
293 //------------------------------------------------------------------------------------------
297 ASDCP::MXF::UTF16String::UTF16String(const char* sz)
299 if ( sz != 0 && *sz != 0 )
305 ASDCP::MXF::UTF16String::UTF16String(const std::string& str)
311 const ASDCP::MXF::UTF16String&
312 ASDCP::MXF::UTF16String::operator=(const char* sz)
314 if ( sz == 0 || *sz == 0 )
324 const ASDCP::MXF::UTF16String&
325 ASDCP::MXF::UTF16String::operator=(const std::string& str)
333 ASDCP::MXF::UTF16String::EncodeString(char* str_buf, ui32_t buf_len) const
335 ui32_t write_len = Kumu::xmin(buf_len - 1, (ui32_t)size());
336 strncpy(str_buf, c_str(), write_len);
337 str_buf[write_len] = 0;
343 ASDCP::MXF::UTF16String::Unarchive(Kumu::MemIOReader* Reader)
346 const ui16_t* p = (ui16_t*)Reader->CurrentData();
347 ui32_t length = Reader->Remainder() / 2;
348 char mb_buf[MB_LEN_MAX+1];
350 for ( ui32_t i = 0; i < length; i++ )
352 int count = wctomb(mb_buf, KM_i16_BE(p[i]));
356 DefaultLogSink().Error("Unable to decode wide character 0x%04hx\n", p[i]);
360 assert(count <= MB_LEN_MAX);
362 this->append(mb_buf);
365 Reader->SkipOffset(length*2);
371 ASDCP::MXF::UTF16String::Archive(Kumu::MemIOWriter* Writer) const
373 if ( size() > IdentBufferLen )
375 DefaultLogSink().Error("String length exceeds maximum %u bytes\n", IdentBufferLen);
379 const char* mbp = c_str();
381 ui32_t remainder = size();
382 ui32_t length = size();
387 int count = mbtowc(&wcp, mbp+i, remainder);
391 DefaultLogSink().Error("Error decoding multi-byte sequence starting at offset %u\n", i);
394 else if ( count == 0 )
399 bool result = Writer->WriteUi16BE((ui16_t)wcp);
401 if ( result == false )
403 DefaultLogSink().Error("No more space in memory IO writer\n");
414 //------------------------------------------------------------------------------------------
418 ASDCP::MXF::ISO8String::ISO8String(const char* sz)
420 if ( sz != 0 && *sz != 0 )
426 ASDCP::MXF::ISO8String::ISO8String(const std::string& str)
433 const ASDCP::MXF::ISO8String&
434 ASDCP::MXF::ISO8String::operator=(const char* sz)
436 if ( sz == 0 || *sz == 0 )
446 const ASDCP::MXF::ISO8String&
447 ASDCP::MXF::ISO8String::operator=(const std::string& str)
455 ASDCP::MXF::ISO8String::EncodeString(char* str_buf, ui32_t buf_len) const
457 ui32_t write_len = Kumu::xmin(buf_len - 1, (ui32_t)size());
458 strncpy(str_buf, c_str(), write_len);
459 str_buf[write_len] = 0;
465 ASDCP::MXF::ISO8String::Unarchive(Kumu::MemIOReader* Reader)
467 assign((char*)Reader->CurrentData(), Reader->Remainder());
473 ASDCP::MXF::ISO8String::Archive(Kumu::MemIOWriter* Writer) const
475 if ( size() > IdentBufferLen )
477 DefaultLogSink().Error("String length exceeds maximum %u bytes\n", IdentBufferLen);
481 return Writer->WriteRaw((const byte_t*)c_str(), size());
484 //------------------------------------------------------------------------------------------
487 ASDCP::MXF::TLVReader::TLVReader(const byte_t* p, ui32_t c, IPrimerLookup* PrimerLookup) :
488 MemIOReader(p, c), m_Lookup(PrimerLookup)
490 Result_t result = RESULT_OK;
492 while ( Remainder() > 0 && ASDCP_SUCCESS(result) )
497 if ( MemIOReader::ReadUi8(&Tag.a) )
498 if ( MemIOReader::ReadUi8(&Tag.b) )
499 if ( MemIOReader::ReadUi16BE(&pkt_len) )
501 m_ElementMap.insert(TagMap::value_type(Tag, ItemInfo(m_size, pkt_len)));
502 if ( SkipOffset(pkt_len) )
506 DefaultLogSink().Error("Malformed Set\n");
507 m_ElementMap.clear();
508 result = RESULT_KLV_CODING(__LINE__, __FILE__);
514 ASDCP::MXF::TLVReader::FindTL(const MDDEntry& Entry)
518 DefaultLogSink().Error("No Lookup service\n");
524 if ( m_Lookup->TagForKey(Entry.ul, TmpTag) != RESULT_OK )
526 if ( Entry.tag.a == 0 )
528 // DefaultLogSink().Debug("No such UL in this TL list: %s (%02x %02x)\n",
529 // Entry.name, Entry.tag.a, Entry.tag.b);
536 TagMap::iterator e_i = m_ElementMap.find(TmpTag);
538 if ( e_i != m_ElementMap.end() )
540 m_size = (*e_i).second.first;
541 m_capacity = m_size + (*e_i).second.second;
545 // DefaultLogSink().Debug("Not Found (%02x %02x): %s\n", TmpTag.a, TmpTag.b, Entry.name);
551 ASDCP::MXF::TLVReader::ReadObject(const MDDEntry& Entry, Kumu::IArchive* Object)
553 ASDCP_TEST_NULL(Object);
557 if ( m_size < m_capacity ) // don't try to unarchive an empty item
559 // TODO: carry on if uachive fails
560 return Object->Unarchive(this) ? RESULT_OK : RESULT_FALSE(__LINE__, __FILE__);
569 ASDCP::MXF::TLVReader::ReadUi8(const MDDEntry& Entry, ui8_t* value)
571 ASDCP_TEST_NULL(value);
574 return MemIOReader::ReadUi8(value) ? RESULT_OK : RESULT_FALSE(__LINE__, __FILE__);
581 ASDCP::MXF::TLVReader::ReadUi16(const MDDEntry& Entry, ui16_t* value)
583 ASDCP_TEST_NULL(value);
586 return MemIOReader::ReadUi16BE(value) ? RESULT_OK : RESULT_FALSE(__LINE__, __FILE__);
593 ASDCP::MXF::TLVReader::ReadUi32(const MDDEntry& Entry, ui32_t* value)
595 ASDCP_TEST_NULL(value);
598 return MemIOReader::ReadUi32BE(value) ? RESULT_OK : RESULT_FALSE(__LINE__, __FILE__);
605 ASDCP::MXF::TLVReader::ReadUi64(const MDDEntry& Entry, ui64_t* value)
607 ASDCP_TEST_NULL(value);
610 return MemIOReader::ReadUi64BE(value) ? RESULT_OK : RESULT_FALSE(__LINE__, __FILE__);
615 //------------------------------------------------------------------------------------------
618 ASDCP::MXF::TLVWriter::TLVWriter(byte_t* p, ui32_t c, IPrimerLookup* PrimerLookup) :
619 MemIOWriter(p, c), m_Lookup(PrimerLookup)
626 ASDCP::MXF::TLVWriter::WriteTag(const MDDEntry& Entry)
630 DefaultLogSink().Error("No Primer object available\n");
636 if ( m_Lookup->InsertTag(Entry, TmpTag) != RESULT_OK )
638 DefaultLogSink().Error("No tag for entry %s\n", Entry.name);
642 if ( ! MemIOWriter::WriteUi8(TmpTag.a) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
643 if ( ! MemIOWriter::WriteUi8(TmpTag.b) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
649 ASDCP::MXF::TLVWriter::WriteObject(const MDDEntry& Entry, Kumu::IArchive* Object)
651 ASDCP_TEST_NULL(Object);
653 if ( Entry.optional && ! Object->HasValue() )
656 Result_t result = WriteTag(Entry);
658 if ( ASDCP_SUCCESS(result) )
660 // write a temp length
661 byte_t* l_p = CurrentData();
663 if ( ! MemIOWriter::WriteUi16BE(0) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
665 ui32_t before = Length();
666 if ( ! Object->Archive(this) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
667 if ( (Length() - before) > 0xffffL ) return RESULT_KLV_CODING(__LINE__, __FILE__);
668 Kumu::i2p<ui16_t>(KM_i16_BE(Length() - before), l_p);
676 ASDCP::MXF::TLVWriter::WriteUi8(const MDDEntry& Entry, ui8_t* value)
678 ASDCP_TEST_NULL(value);
679 Result_t result = WriteTag(Entry);
681 if ( ASDCP_SUCCESS(result) )
683 if ( ! MemIOWriter::WriteUi16BE(sizeof(ui8_t)) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
684 if ( ! MemIOWriter::WriteUi8(*value) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
692 ASDCP::MXF::TLVWriter::WriteUi16(const MDDEntry& Entry, ui16_t* value)
694 ASDCP_TEST_NULL(value);
695 Result_t result = WriteTag(Entry);
697 if ( KM_SUCCESS(result) )
699 if ( ! MemIOWriter::WriteUi16BE(sizeof(ui16_t)) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
700 if ( ! MemIOWriter::WriteUi16BE(*value) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
708 ASDCP::MXF::TLVWriter::WriteUi32(const MDDEntry& Entry, ui32_t* value)
710 ASDCP_TEST_NULL(value);
711 Result_t result = WriteTag(Entry);
713 if ( KM_SUCCESS(result) )
715 if ( ! MemIOWriter::WriteUi16BE(sizeof(ui32_t)) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
716 if ( ! MemIOWriter::WriteUi32BE(*value) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
724 ASDCP::MXF::TLVWriter::WriteUi64(const MDDEntry& Entry, ui64_t* value)
726 ASDCP_TEST_NULL(value);
727 Result_t result = WriteTag(Entry);
729 if ( KM_SUCCESS(result) )
731 if ( ! MemIOWriter::WriteUi16BE(sizeof(ui64_t)) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
732 if ( ! MemIOWriter::WriteUi64BE(*value) ) return RESULT_KLV_CODING(__LINE__, __FILE__);
739 //----------------------------------------------------------------------------------------------------
743 ASDCP::MXF::RGBALayout::RGBALayout()
745 memset(m_value, 0, RGBAValueLength);
748 ASDCP::MXF::RGBALayout::RGBALayout(const byte_t* value)
750 memcpy(m_value, value, RGBAValueLength);
753 ASDCP::MXF::RGBALayout::~RGBALayout()
758 get_char_for_code(byte_t c)
760 for ( int i = 0; ASDCP::MXF::RGBALayoutTable[i].code != 0; ++i )
762 if ( ASDCP::MXF::RGBALayoutTable[i].code == c )
764 return ASDCP::MXF::RGBALayoutTable[i].symbol;
773 ASDCP::MXF::RGBALayout::EncodeString(char* buf, ui32_t buf_len) const
778 for ( int i = 0; i < RGBAValueLength && m_value[i] != 0; i += 2 )
780 snprintf(tmp_buf, 64, "%c(%d)", get_char_for_code(m_value[i]), m_value[i+1]);
782 if ( ! tmp_str.empty() )
790 assert(tmp_str.size() < buf_len);
791 strncpy(buf, tmp_str.c_str(), tmp_str.size());
796 //----------------------------------------------------------------------------------------------------
799 ASDCP::MXF::Raw::Raw()
804 ASDCP::MXF::Raw::~Raw()
810 ASDCP::MXF::Raw::Unarchive(Kumu::MemIOReader* Reader)
812 ui32_t payload_size = Reader->Remainder();
813 if ( payload_size == 0 ) return false;
814 if ( KM_FAILURE(Capacity(payload_size)) ) return false;
816 memcpy(Data(), Reader->CurrentData(), payload_size);
817 Length(payload_size);
823 ASDCP::MXF::Raw::Archive(Kumu::MemIOWriter* Writer) const
825 return Writer->WriteRaw(RoData(), Length());
830 ASDCP::MXF::Raw::EncodeString(char* str_buf, ui32_t buf_len) const
833 Kumu::bin2hex(RoData(), Length(), str_buf, buf_len);