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) )
113 m_ValueLength = tmp_size;
114 m_KLLength = SMPTE_UL_LENGTH + Kumu::BER_length(buf + SMPTE_UL_LENGTH);
116 m_ValueStart = buf + m_KLLength;
122 ASDCP::KLVPacket::HasUL(const byte_t* ul)
124 if ( m_KeyStart != 0 )
126 return UL(ul) == UL(m_KeyStart);
129 if ( m_UL.HasValue() )
131 return UL(ul) == m_UL;
139 ASDCP::KLVPacket::WriteKLToBuffer(ASDCP::FrameBuffer& Buffer, const UL& label, ui32_t length)
141 assert(label.HasValue());
143 if ( Buffer.Size() + kl_length > Buffer.Capacity() )
145 DefaultLogSink().Error("Small write buffer\n");
149 memcpy(Buffer.Data() + Buffer.Size(), label.Value(), label.Size());
151 if ( ! Kumu::write_BER(Buffer.Data() + Buffer.Size() + SMPTE_UL_LENGTH, length, MXF_BER_LENGTH) )
154 Buffer.Size(Buffer.Size() + kl_length);
160 ASDCP::KLVPacket::Dump(FILE* stream, const Dictionary& Dict, bool show_value)
167 if ( m_KeyStart != 0 )
169 assert(m_ValueStart);
170 UL TmpUL(m_KeyStart);
171 fprintf(stream, "%s", TmpUL.EncodeString(buf, 64));
173 const MDDEntry* Entry = Dict.FindUL(m_KeyStart);
174 fprintf(stream, " len: %7qu (%s)\n", m_ValueLength, (Entry ? Entry->name : "Unknown"));
176 if ( show_value && m_ValueLength < 1000 )
177 Kumu::hexdump(m_ValueStart, Kumu::xmin(m_ValueLength, (ui64_t)128), stream);
179 else if ( m_UL.HasValue() )
181 fprintf(stream, "%s\n", m_UL.EncodeString(buf, 64));
185 fprintf(stream, "*** Malformed KLV packet ***\n");
191 ASDCP::KLVFilePacket::InitFromFile(const Kumu::FileReader& Reader, const UL& label)
193 Result_t result = KLVFilePacket::InitFromFile(Reader);
195 if ( ASDCP_SUCCESS(result) )
196 result = ( UL(m_KeyStart) == label ) ? RESULT_OK : RESULT_FAIL;
201 // TODO: refactor to use InitFromBuffer
203 ASDCP::KLVFilePacket::InitFromFile(const Kumu::FileReader& Reader)
206 byte_t tmp_data[tmp_read_size];
208 m_KeyStart = m_ValueStart = 0;
209 m_KLLength = m_ValueLength = 0;
212 Result_t result = Reader.Read(tmp_data, tmp_read_size, &read_count);
214 if ( ASDCP_FAILURE(result) )
217 if ( read_count < (SMPTE_UL_LENGTH + 1) )
219 DefaultLogSink().Error("Short read of Key and Length got %u\n", read_count);
220 return RESULT_READFAIL;
223 if ( memcmp(tmp_data, SMPTE_UL_START, 4) != 0 )
225 DefaultLogSink().Error("Unexpected UL preamble: %02x.%02x.%02x.%02x\n",
226 tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]);
230 if ( ! Kumu::read_BER(tmp_data + SMPTE_UL_LENGTH, &tmp_size) )
232 DefaultLogSink().Error("BER Length decoding error\n");
236 if ( tmp_size > MAX_KLV_PACKET_LENGTH )
238 Kumu::ui64Printer tmp_size_str(tmp_size);
239 DefaultLogSink().Error("Packet length %s exceeds internal limit\n", tmp_size_str.c_str());
243 ui32_t remainder = 0;
244 ui32_t ber_len = Kumu::BER_length(tmp_data + SMPTE_UL_LENGTH);
245 m_KLLength = SMPTE_UL_LENGTH + ber_len;
246 assert(tmp_size <= 0xFFFFFFFFL);
247 m_ValueLength = (ui32_t) tmp_size;
248 ui32_t packet_length = m_ValueLength + m_KLLength;
250 result = m_Buffer.Capacity(packet_length);
252 if ( ASDCP_FAILURE(result) )
255 m_KeyStart = m_Buffer.Data();
256 m_ValueStart = m_Buffer.Data() + m_KLLength;
257 m_Buffer.Size(packet_length);
259 // is the whole packet in the tmp buf?
260 if ( packet_length <= tmp_read_size )
262 assert(packet_length <= read_count);
263 memcpy(m_Buffer.Data(), tmp_data, packet_length);
265 if ( (remainder = read_count - packet_length) != 0 )
267 DefaultLogSink().Warn("Repositioning pointer for short packet\n");
268 Kumu::fpos_t pos = Reader.Tell();
269 assert(pos > remainder);
270 result = Reader.Seek(pos - remainder);
275 if ( read_count < tmp_read_size )
277 DefaultLogSink().Error("Short read of packet body, expecting %u, got %u\n",
278 m_Buffer.Size(), read_count);
279 return RESULT_READFAIL;
282 memcpy(m_Buffer.Data(), tmp_data, tmp_read_size);
283 remainder = m_Buffer.Size() - tmp_read_size;
287 result = Reader.Read(m_Buffer.Data() + tmp_read_size, remainder, &read_count);
289 if ( read_count != remainder )
291 DefaultLogSink().Error("Short read of packet body, expecting %u, got %u\n",
292 remainder+tmp_read_size, read_count+tmp_read_size);
293 result = RESULT_READFAIL;
303 ASDCP::KLVFilePacket::WriteKLToFile(Kumu::FileWriter& Writer, const UL& label, ui32_t length)
305 byte_t buffer[kl_length];
306 memcpy(buffer, label.Value(), label.Size());
308 if ( ! Kumu::write_BER(buffer+SMPTE_UL_LENGTH, length, MXF_BER_LENGTH) )
312 Writer.Write(buffer, kl_length, &write_count);
313 assert(write_count == kl_length);