2 Copyright (c) 2005-2009, 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.
28 \version $Id: KLV.cpp,v 1.13 2012/02/03 19:49:56 jhurst Exp $
34 using Kumu::DefaultLogSink;
37 // This is how much we read when we're reading from a file and we don't know
38 // how long the packet is. This gives us the K (16 bytes) and L (4-9 bytes)
39 // and the remaining bytes for an even read (tmp_read_size % 16 == 0)
40 const ui32_t kl_length = ASDCP::SMPTE_UL_LENGTH + ASDCP::MXF_BER_LENGTH;
41 const ui32_t tmp_read_size = 32;
43 //------------------------------------------------------------------------------------------
48 ASDCP::KLVPacket::InitFromBuffer(const byte_t* buf, ui32_t buf_len, const UL& label)
50 Result_t result = KLVPacket::InitFromBuffer(buf, buf_len);
52 if ( ASDCP_SUCCESS(result) )
53 result = ( UL(m_KeyStart) == label ) ? RESULT_OK : RESULT_FAIL;
60 ASDCP::KLVPacket::GetUL()
62 if ( m_KeyStart != 0 )
63 return UL(m_KeyStart);
70 ASDCP::KLVPacket::SetUL(const UL& new_ul)
72 if ( m_KeyStart != 0 )
81 ASDCP::KLVPacket::InitFromBuffer(const byte_t* buf, ui32_t buf_len)
83 m_KeyStart = m_ValueStart = 0;
84 m_KLLength = m_ValueLength = 0;
86 if ( memcmp(buf, SMPTE_UL_START, 4) != 0 )
88 DefaultLogSink().Error("Unexpected UL preamble: %02x.%02x.%02x.%02x\n",
89 buf[0], buf[1], buf[2], buf[3]);
93 ui32_t ber_len = Kumu::BER_length(buf + SMPTE_UL_LENGTH);
95 if ( ber_len > ( buf_len - SMPTE_UL_LENGTH ) )
97 DefaultLogSink().Error("BER encoding length exceeds buffer size\n");
103 DefaultLogSink().Error("KLV format error, zero BER length not allowed\n");
108 if ( ! Kumu::read_BER(buf + SMPTE_UL_LENGTH, &tmp_size) )
111 assert (tmp_size <= 0xFFFFFFFFL);
112 m_ValueLength = (ui32_t) tmp_size;
113 m_KLLength = SMPTE_UL_LENGTH + Kumu::BER_length(buf + SMPTE_UL_LENGTH);
115 m_ValueStart = buf + m_KLLength;
121 ASDCP::KLVPacket::HasUL(const byte_t* ul)
123 if ( m_KeyStart != 0 )
125 return ( memcmp(ul, m_KeyStart, SMPTE_UL_LENGTH) == 0 ) ? true : false;
128 if ( m_UL.HasValue() )
130 return UL(ul) == m_UL;
138 ASDCP::KLVPacket::WriteKLToBuffer(ASDCP::FrameBuffer& Buffer, const UL& label, ui32_t length)
140 assert(label.HasValue());
142 if ( Buffer.Size() + kl_length > Buffer.Capacity() )
144 DefaultLogSink().Error("Small write buffer\n");
148 memcpy(Buffer.Data() + Buffer.Size(), label.Value(), label.Size());
150 if ( ! Kumu::write_BER(Buffer.Data() + Buffer.Size() + SMPTE_UL_LENGTH, length, MXF_BER_LENGTH) )
153 Buffer.Size(Buffer.Size() + kl_length);
159 ASDCP::KLVPacket::Dump(FILE* stream, const Dictionary& Dict, bool show_value)
166 if ( m_KeyStart != 0 )
168 assert(m_ValueStart);
169 UL TmpUL(m_KeyStart);
170 fprintf(stream, "%s", TmpUL.EncodeString(buf, 64));
172 const MDDEntry* Entry = Dict.FindUL(m_KeyStart);
173 fprintf(stream, " len: %7u (%s)\n", m_ValueLength, (Entry ? Entry->name : "Unknown"));
175 if ( show_value && m_ValueLength < 1000 )
176 Kumu::hexdump(m_ValueStart, Kumu::xmin(m_ValueLength, (ui32_t)128), stream);
178 else if ( m_UL.HasValue() )
180 fprintf(stream, "%s\n", m_UL.EncodeString(buf, 64));
184 fprintf(stream, "*** Malformed KLV packet ***\n");
190 ASDCP::KLVFilePacket::InitFromFile(const Kumu::FileReader& Reader, const UL& label)
192 Result_t result = KLVFilePacket::InitFromFile(Reader);
194 if ( ASDCP_SUCCESS(result) )
195 result = ( UL(m_KeyStart) == label ) ? RESULT_OK : RESULT_FAIL;
200 // TODO: refactor to use InitFromBuffer
202 ASDCP::KLVFilePacket::InitFromFile(const Kumu::FileReader& Reader)
205 byte_t tmp_data[tmp_read_size];
207 m_KeyStart = m_ValueStart = 0;
208 m_KLLength = m_ValueLength = 0;
211 Result_t result = Reader.Read(tmp_data, tmp_read_size, &read_count);
213 if ( ASDCP_FAILURE(result) )
216 if ( read_count < (SMPTE_UL_LENGTH + 1) )
218 DefaultLogSink().Error("Short read of Key and Length got %u\n", read_count);
219 return RESULT_READFAIL;
222 if ( memcmp(tmp_data, SMPTE_UL_START, 4) != 0 )
224 DefaultLogSink().Error("Unexpected UL preamble: %02x.%02x.%02x.%02x\n",
225 tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]);
229 if ( ! Kumu::read_BER(tmp_data + SMPTE_UL_LENGTH, &tmp_size) )
231 DefaultLogSink().Error("BER Length decoding error\n");
235 if ( tmp_size > MAX_KLV_PACKET_LENGTH )
237 Kumu::ui64Printer tmp_size_str(tmp_size);
238 DefaultLogSink().Error("Packet length %s exceeds internal limit\n", tmp_size_str.c_str());
242 ui32_t remainder = 0;
243 ui32_t ber_len = Kumu::BER_length(tmp_data + SMPTE_UL_LENGTH);
244 m_KLLength = SMPTE_UL_LENGTH + ber_len;
245 assert(tmp_size <= 0xFFFFFFFFL);
246 m_ValueLength = (ui32_t) tmp_size;
247 ui32_t packet_length = m_ValueLength + m_KLLength;
249 result = m_Buffer.Capacity(packet_length);
251 if ( ASDCP_FAILURE(result) )
254 m_KeyStart = m_Buffer.Data();
255 m_ValueStart = m_Buffer.Data() + m_KLLength;
256 m_Buffer.Size(packet_length);
258 // is the whole packet in the tmp buf?
259 if ( packet_length <= tmp_read_size )
261 assert(packet_length <= read_count);
262 memcpy(m_Buffer.Data(), tmp_data, packet_length);
264 if ( (remainder = read_count - packet_length) != 0 )
266 DefaultLogSink().Warn("Repositioning pointer for short packet\n");
267 Kumu::fpos_t pos = Reader.Tell();
268 assert(pos > remainder);
269 result = Reader.Seek(pos - remainder);
274 if ( read_count < tmp_read_size )
276 DefaultLogSink().Error("Short read of packet body, expecting %u, got %u\n",
277 m_Buffer.Size(), read_count);
278 return RESULT_READFAIL;
281 memcpy(m_Buffer.Data(), tmp_data, tmp_read_size);
282 remainder = m_Buffer.Size() - tmp_read_size;
286 result = Reader.Read(m_Buffer.Data() + tmp_read_size, remainder, &read_count);
288 if ( read_count != remainder )
290 DefaultLogSink().Error("Short read of packet body, expecting %u, got %u\n",
291 remainder+tmp_read_size, read_count+tmp_read_size);
292 result = RESULT_READFAIL;
302 ASDCP::KLVFilePacket::WriteKLToFile(Kumu::FileWriter& Writer, const UL& label, ui32_t length)
304 byte_t buffer[kl_length];
305 memcpy(buffer, label.Value(), label.Size());
307 if ( ! Kumu::write_BER(buffer+SMPTE_UL_LENGTH, length, MXF_BER_LENGTH) )
311 Writer.Write(buffer, kl_length, &write_count);
312 assert(write_count == kl_length);