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.
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) )
110 DefaultLogSink().Error("KLV format error, BER decode failure.\n");
114 m_ValueLength = tmp_size;
115 m_KLLength = SMPTE_UL_LENGTH + Kumu::BER_length(buf + SMPTE_UL_LENGTH);
117 m_ValueStart = buf + m_KLLength;
123 ASDCP::KLVPacket::HasUL(const byte_t* ul)
125 if ( m_KeyStart != 0 )
127 return UL(ul) == UL(m_KeyStart);
130 if ( m_UL.HasValue() )
132 return UL(ul) == m_UL;
140 ASDCP::KLVPacket::WriteKLToBuffer(ASDCP::FrameBuffer& Buffer, const UL& label, ui32_t length)
142 assert(label.HasValue());
144 if ( Buffer.Size() + kl_length > Buffer.Capacity() )
146 DefaultLogSink().Error("Small write buffer\n");
150 memcpy(Buffer.Data() + Buffer.Size(), label.Value(), label.Size());
152 if ( ! Kumu::write_BER(Buffer.Data() + Buffer.Size() + SMPTE_UL_LENGTH, length, MXF_BER_LENGTH) )
155 Buffer.Size(Buffer.Size() + kl_length);
161 ASDCP::KLVPacket::Dump(FILE* stream, const Dictionary& Dict, bool show_value)
168 if ( m_KeyStart != 0 )
170 assert(m_ValueStart);
171 UL TmpUL(m_KeyStart);
172 fprintf(stream, "%s", TmpUL.EncodeString(buf, 64));
174 const MDDEntry* Entry = Dict.FindUL(m_KeyStart);
175 fprintf(stream, " len: %7qu (%s)\n", m_ValueLength, (Entry ? Entry->name : "Unknown"));
177 if ( show_value && m_ValueLength < 1000 )
178 Kumu::hexdump(m_ValueStart, Kumu::xmin(m_ValueLength, (ui64_t)128), stream);
180 else if ( m_UL.HasValue() )
182 fprintf(stream, "%s\n", m_UL.EncodeString(buf, 64));
186 fprintf(stream, "*** Malformed KLV packet ***\n");
192 ASDCP::KLVFilePacket::InitFromFile(const Kumu::FileReader& Reader, const UL& label)
194 Result_t result = KLVFilePacket::InitFromFile(Reader);
196 if ( ASDCP_SUCCESS(result) )
197 result = ( UL(m_KeyStart) == label ) ? RESULT_OK : RESULT_FAIL;
202 // TODO: refactor to use InitFromBuffer
204 ASDCP::KLVFilePacket::InitFromFile(const Kumu::FileReader& Reader)
207 byte_t tmp_data[tmp_read_size];
209 m_KeyStart = m_ValueStart = 0;
210 m_KLLength = m_ValueLength = 0;
213 Result_t result = Reader.Read(tmp_data, tmp_read_size, &read_count);
215 if ( ASDCP_FAILURE(result) )
218 if ( read_count < (SMPTE_UL_LENGTH + 1) )
220 DefaultLogSink().Error("Short read of Key and Length got %u\n", read_count);
221 return RESULT_READFAIL;
224 if ( memcmp(tmp_data, SMPTE_UL_START, 4) != 0 )
226 DefaultLogSink().Error("Unexpected UL preamble: %02x.%02x.%02x.%02x\n",
227 tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]);
231 if ( ! Kumu::read_BER(tmp_data + SMPTE_UL_LENGTH, &tmp_size) )
233 DefaultLogSink().Error("BER Length decoding error\n");
237 if ( tmp_size > MAX_KLV_PACKET_LENGTH )
239 Kumu::ui64Printer tmp_size_str(tmp_size);
240 DefaultLogSink().Error("Packet length %s exceeds internal limit\n", tmp_size_str.c_str());
244 ui32_t remainder = 0;
245 ui32_t ber_len = Kumu::BER_length(tmp_data + SMPTE_UL_LENGTH);
246 m_KLLength = SMPTE_UL_LENGTH + ber_len;
247 assert(tmp_size <= 0xFFFFFFFFL);
248 m_ValueLength = (ui32_t) tmp_size;
249 ui32_t packet_length = m_ValueLength + m_KLLength;
251 result = m_Buffer.Capacity(packet_length);
253 if ( ASDCP_FAILURE(result) )
256 m_KeyStart = m_Buffer.Data();
257 m_ValueStart = m_Buffer.Data() + m_KLLength;
258 m_Buffer.Size(packet_length);
260 // is the whole packet in the tmp buf?
261 if ( packet_length <= tmp_read_size )
263 assert(packet_length <= read_count);
264 memcpy(m_Buffer.Data(), tmp_data, packet_length);
266 if ( (remainder = read_count - packet_length) != 0 )
268 DefaultLogSink().Warn("Repositioning pointer for short packet\n");
269 Kumu::fpos_t pos = Reader.Tell();
270 assert(pos > remainder);
271 result = Reader.Seek(pos - remainder);
276 if ( read_count < tmp_read_size )
278 DefaultLogSink().Error("Short read of packet body, expecting %u, got %u\n",
279 m_Buffer.Size(), read_count);
280 return RESULT_READFAIL;
283 memcpy(m_Buffer.Data(), tmp_data, tmp_read_size);
284 remainder = m_Buffer.Size() - tmp_read_size;
288 result = Reader.Read(m_Buffer.Data() + tmp_read_size, remainder, &read_count);
290 if ( read_count != remainder )
292 DefaultLogSink().Error("Short read of packet body, expecting %u, got %u\n",
293 remainder+tmp_read_size, read_count+tmp_read_size);
294 result = RESULT_READFAIL;
304 ASDCP::KLVFilePacket::WriteKLToFile(Kumu::FileWriter& Writer, const UL& label, ui32_t length)
306 byte_t buffer[kl_length];
307 memcpy(buffer, label.Value(), label.Size());
309 if ( ! Kumu::write_BER(buffer+SMPTE_UL_LENGTH, length, MXF_BER_LENGTH) )
313 Writer.Write(buffer, kl_length, &write_count);
314 assert(write_count == kl_length);