more printf format fixes
[asdcplib.git] / src / KLV.cpp
1 /*
2 Copyright (c) 2005-2006, 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 byte_t* label)
49 {
50   Result_t result = KLVPacket::InitFromBuffer(buf, buf_len);
51
52   if ( ASDCP_SUCCESS(result) )
53     result = ( memcmp(m_KeyStart, label, SMPTE_UL_LENGTH) == 0 ) ?
54       RESULT_OK : RESULT_FAIL;
55
56   return result;
57 }
58
59 //
60 ASDCP::Result_t
61 ASDCP::KLVPacket::InitFromBuffer(const byte_t* buf, ui32_t buf_len)
62 {
63   m_KeyStart = m_ValueStart = 0;
64   m_KLLength = m_ValueLength = 0;
65
66   if ( memcmp(buf, SMPTE_UL_START, 4) != 0 )
67     {
68       DefaultLogSink().Error("Unexpected UL preamble: %02x.%02x.%02x.%02x\n",
69                              buf[0], buf[1], buf[2], buf[3]);
70       return RESULT_FAIL;
71     }
72
73   ui32_t ber_len = Kumu::BER_length(buf + SMPTE_UL_LENGTH);
74
75   if ( ber_len > ( buf_len - SMPTE_UL_LENGTH ) )
76     {
77       DefaultLogSink().Error("BER encoding length exceeds buffer size\n");
78       return RESULT_FAIL;
79     }
80
81   if ( ber_len == 0 )
82     {
83       DefaultLogSink().Error("KLV format error, zero BER length not allowed\n");
84       return RESULT_FAIL;
85     }
86
87   ui64_t tmp_size;
88   if ( ! Kumu::read_BER(buf + SMPTE_UL_LENGTH, &tmp_size) )
89        return RESULT_FAIL;
90
91   m_ValueLength = 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 byte_t* 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, SMPTE_UL_LENGTH);
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, bool show_hex)
130 {
131   if ( stream == 0 )
132     stream = stderr;
133
134   if ( m_KeyStart != 0 )
135     {
136       assert(m_ValueStart);
137
138       for ( ui32_t i = 0; i < SMPTE_UL_LENGTH; i++ )
139         fprintf(stream, "%02x.", m_KeyStart[i]);
140
141       const MDDEntry* Entry = Dict::FindUL(m_KeyStart);
142       fprintf(stream, "\b  len: %7u (%s)\n", m_ValueLength, (Entry ? Entry->name : "Unknown"));
143
144       if ( show_hex && m_ValueLength < 1000 )
145         Kumu::hexdump(m_ValueStart, Kumu::xmin(m_ValueLength, (ui32_t)64), 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 byte_t* label)
156 {
157   Result_t result = KLVFilePacket::InitFromFile(Reader);
158
159   if ( ASDCP_SUCCESS(result) )
160     result = ( memcmp(m_KeyStart, label, SMPTE_UL_LENGTH) == 0 ) ?
161       RESULT_OK : RESULT_FAIL;
162
163   return result;
164 }
165
166 // TODO: refactor to use InitFromBuffer
167 ASDCP::Result_t
168 ASDCP::KLVFilePacket::InitFromFile(const Kumu::FileReader& Reader)
169 {
170   ui32_t read_count;
171   byte_t tmp_data[tmp_read_size];
172   ui64_t tmp_size;
173   m_KeyStart = m_ValueStart = 0;
174   m_KLLength = m_ValueLength = 0;
175   m_Buffer.Size(0);
176
177   Result_t result = Reader.Read(tmp_data, tmp_read_size, &read_count);
178
179   if ( ASDCP_FAILURE(result) )
180     return result;
181
182   if ( read_count < (SMPTE_UL_LENGTH + 1) )
183     {
184       DefaultLogSink().Error("Short read of Key and Length got %u\n", read_count);
185       return RESULT_READFAIL;
186     }
187
188   if ( memcmp(tmp_data, SMPTE_UL_START, 4) != 0 )
189     {
190       DefaultLogSink().Error("Unexpected UL preamble: %02x.%02x.%02x.%02x\n",
191                              tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]);
192       return RESULT_FAIL;
193     }
194
195   if ( ! Kumu::read_BER(tmp_data + SMPTE_UL_LENGTH, &tmp_size) )
196     {
197       DefaultLogSink().Error("BER Length decoding error\n");
198       return RESULT_FAIL;
199     }
200
201   if ( tmp_size > MAX_KLV_PACKET_LENGTH )
202     {
203       Kumu::ui64Printer tmp_size_str(tmp_size);
204       DefaultLogSink().Error("Packet length %s exceeds internal limit\n", tmp_size_str.c_str());
205       return RESULT_FAIL;
206     }
207
208   ui32_t remainder = 0;
209   ui32_t ber_len = Kumu::BER_length(tmp_data + SMPTE_UL_LENGTH);
210   m_KLLength = SMPTE_UL_LENGTH + ber_len;
211   m_ValueLength = 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 byte_t* label, ui32_t length)
268 {
269   byte_t buffer[kl_length];
270   memcpy(buffer, label, SMPTE_UL_LENGTH);
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 //