i suck
[asdcplib.git] / src / KLV.cpp
1 /*
2 Copyright (c) 2005-2009, John Hurst
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
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.
15
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.
26 */
27 /*! \file    KLV.cpp
28   \version $Id$
29   \brief   KLV objects
30 */
31
32 #include "KLV.h"
33 #include <KM_log.h>
34 using Kumu::DefaultLogSink;
35
36
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;
42
43 //------------------------------------------------------------------------------------------
44 //
45
46 // 
47 ASDCP::Result_t
48 ASDCP::KLVPacket::InitFromBuffer(const byte_t* buf, ui32_t buf_len, const UL& label)
49 {
50   Result_t result = KLVPacket::InitFromBuffer(buf, buf_len);
51
52   if ( ASDCP_SUCCESS(result) )
53     result = ( UL(m_KeyStart) == label ) ? RESULT_OK : RESULT_FAIL;
54
55   return result;
56 }
57
58 //
59 ASDCP::Result_t
60 ASDCP::KLVPacket::InitFromBuffer(const byte_t* buf, ui32_t buf_len)
61 {
62   m_KeyStart = m_ValueStart = 0;
63   m_KLLength = m_ValueLength = 0;
64
65   if ( memcmp(buf, SMPTE_UL_START, 4) != 0 )
66     {
67       DefaultLogSink().Error("Unexpected UL preamble: %02x.%02x.%02x.%02x\n",
68                              buf[0], buf[1], buf[2], buf[3]);
69       return RESULT_FAIL;
70     }
71
72   ui32_t ber_len = Kumu::BER_length(buf + SMPTE_UL_LENGTH);
73
74   if ( ber_len > ( buf_len - SMPTE_UL_LENGTH ) )
75     {
76       DefaultLogSink().Error("BER encoding length exceeds buffer size\n");
77       return RESULT_FAIL;
78     }
79
80   if ( ber_len == 0 )
81     {
82       DefaultLogSink().Error("KLV format error, zero BER length not allowed\n");
83       return RESULT_FAIL;
84     }
85
86   ui64_t tmp_size;
87   if ( ! Kumu::read_BER(buf + SMPTE_UL_LENGTH, &tmp_size) )
88        return RESULT_FAIL;
89
90   assert (tmp_size <= 0xFFFFFFFFL);
91   m_ValueLength = (ui32_t) tmp_size;
92   m_KLLength = SMPTE_UL_LENGTH + Kumu::BER_length(buf + SMPTE_UL_LENGTH);
93   m_KeyStart = buf;
94   m_ValueStart = buf + m_KLLength;
95   return RESULT_OK;
96 }
97
98 //
99 bool
100 ASDCP::KLVPacket::HasUL(const byte_t* ul)
101 {
102   if ( m_KeyStart == 0 )
103     return false;
104
105   return ( memcmp(ul, m_KeyStart, SMPTE_UL_LENGTH) == 0 ) ? true : false;
106 }
107
108 //
109 ASDCP::Result_t
110 ASDCP::KLVPacket::WriteKLToBuffer(ASDCP::FrameBuffer& Buffer, const UL& label, ui32_t length)
111 {
112   if ( Buffer.Size() + kl_length > Buffer.Capacity() )
113     {
114       DefaultLogSink().Error("Small write buffer\n");
115       return RESULT_FAIL;
116     }
117   
118   memcpy(Buffer.Data() + Buffer.Size(), label.Value(), label.Size());
119
120   if ( ! Kumu::write_BER(Buffer.Data() + Buffer.Size() + SMPTE_UL_LENGTH, length, MXF_BER_LENGTH) )
121     return RESULT_FAIL;
122
123   Buffer.Size(Buffer.Size() + kl_length);
124   return RESULT_OK;
125 }
126
127 //
128 void
129 ASDCP::KLVPacket::Dump(FILE* stream, const Dictionary& Dict, bool show_value)
130 {
131   if ( stream == 0 )
132     stream = stderr;
133
134   if ( m_KeyStart != 0 )
135     {
136       assert(m_ValueStart);
137       UL TmpUL(m_KeyStart);
138       char buf[64];
139       fprintf(stream, "%s", TmpUL.EncodeString(buf, 64));
140
141       const MDDEntry* Entry = Dict.FindUL(m_KeyStart);
142       fprintf(stream, "  len: %7u (%s)\n", m_ValueLength, (Entry ? Entry->name : "Unknown"));
143
144       if ( show_value && m_ValueLength < 1000 )
145         Kumu::hexdump(m_ValueStart, Kumu::xmin(m_ValueLength, (ui32_t)128), stream);
146     }
147   else
148     {
149       fprintf(stream, "*** Malformed KLV packet ***\n");
150     }
151 }
152
153 // 
154 ASDCP::Result_t
155 ASDCP::KLVFilePacket::InitFromFile(const Kumu::FileReader& Reader, const UL& label)
156 {
157   Result_t result = KLVFilePacket::InitFromFile(Reader);
158
159   if ( ASDCP_SUCCESS(result) )
160     result = ( UL(m_KeyStart) == label ) ? RESULT_OK : RESULT_FAIL;
161
162   return result;
163 }
164
165 // TODO: refactor to use InitFromBuffer
166 ASDCP::Result_t
167 ASDCP::KLVFilePacket::InitFromFile(const Kumu::FileReader& Reader)
168 {
169   ui32_t read_count;
170   byte_t tmp_data[tmp_read_size];
171   ui64_t tmp_size;
172   m_KeyStart = m_ValueStart = 0;
173   m_KLLength = m_ValueLength = 0;
174   m_Buffer.Size(0);
175
176   Result_t result = Reader.Read(tmp_data, tmp_read_size, &read_count);
177
178   if ( ASDCP_FAILURE(result) )
179     return result;
180
181   if ( read_count < (SMPTE_UL_LENGTH + 1) )
182     {
183       DefaultLogSink().Error("Short read of Key and Length got %u\n", read_count);
184       return RESULT_READFAIL;
185     }
186
187   if ( memcmp(tmp_data, SMPTE_UL_START, 4) != 0 )
188     {
189       DefaultLogSink().Error("Unexpected UL preamble: %02x.%02x.%02x.%02x\n",
190                              tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]);
191       return RESULT_FAIL;
192     }
193
194   if ( ! Kumu::read_BER(tmp_data + SMPTE_UL_LENGTH, &tmp_size) )
195     {
196       DefaultLogSink().Error("BER Length decoding error\n");
197       return RESULT_FAIL;
198     }
199
200   if ( tmp_size > MAX_KLV_PACKET_LENGTH )
201     {
202       Kumu::ui64Printer tmp_size_str(tmp_size);
203       DefaultLogSink().Error("Packet length %s exceeds internal limit\n", tmp_size_str.c_str());
204       return RESULT_FAIL;
205     }
206
207   ui32_t remainder = 0;
208   ui32_t ber_len = Kumu::BER_length(tmp_data + SMPTE_UL_LENGTH);
209   m_KLLength = SMPTE_UL_LENGTH + ber_len;
210   assert(tmp_size <= 0xFFFFFFFFL);
211   m_ValueLength = (ui32_t) tmp_size;
212   ui32_t packet_length = m_ValueLength + m_KLLength;
213
214   result = m_Buffer.Capacity(packet_length);
215
216   if ( ASDCP_FAILURE(result) )
217     return result;
218
219   m_KeyStart = m_Buffer.Data();
220   m_ValueStart = m_Buffer.Data() + m_KLLength;
221   m_Buffer.Size(packet_length);
222
223   // is the whole packet in the tmp buf?
224   if ( packet_length <= tmp_read_size )
225     {
226       assert(packet_length <= read_count);
227       memcpy(m_Buffer.Data(), tmp_data, packet_length);
228
229       if ( (remainder = read_count - packet_length) != 0 )
230         {
231           DefaultLogSink().Warn("Repositioning pointer for short packet\n");
232           Kumu::fpos_t pos = Reader.Tell();
233           assert(pos > remainder);
234           result = Reader.Seek(pos - remainder);
235         }
236     }
237   else
238     {
239       if ( read_count < tmp_read_size )
240         {
241           DefaultLogSink().Error("Short read of packet body, expecting %u, got %u\n",
242                                  m_Buffer.Size(), read_count);
243           return RESULT_READFAIL;
244         }
245
246       memcpy(m_Buffer.Data(), tmp_data, tmp_read_size);
247       remainder = m_Buffer.Size() - tmp_read_size;
248
249       if ( remainder > 0 )
250         {
251           result = Reader.Read(m_Buffer.Data() + tmp_read_size, remainder, &read_count);
252       
253           if ( read_count != remainder )
254             {
255               DefaultLogSink().Error("Short read of packet body, expecting %u, got %u\n",
256                                      remainder+tmp_read_size, read_count+tmp_read_size);
257               result = RESULT_READFAIL;
258             }
259         }
260     }
261
262   return result;
263 }
264
265 //
266 ASDCP::Result_t
267 ASDCP::KLVFilePacket::WriteKLToFile(Kumu::FileWriter& Writer, const UL& label, ui32_t length)
268 {
269   byte_t buffer[kl_length];
270   memcpy(buffer, label.Value(), label.Size());
271
272   if ( ! Kumu::write_BER(buffer+SMPTE_UL_LENGTH, length, MXF_BER_LENGTH) )
273     return RESULT_FAIL;
274
275   ui32_t write_count;
276   Writer.Write(buffer, kl_length, &write_count);
277   assert(write_count == kl_length);
278   return RESULT_OK;
279 }
280
281
282 //
283 // end KLV.cpp
284 //