metadata reformed...
[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 <hex_utils.h>
34
35
36 // This is how much we read when we're reading from a file and we don't know
37 // how long the packet is. This gives us the K (16 bytes) and L (4-9 bytes)
38 // and the remaining bytes for an even read (tmp_read_size % 16 == 0)
39 const ui32_t kl_length = ASDCP::SMPTE_UL_LENGTH + ASDCP::MXF_BER_LENGTH;
40 const ui32_t tmp_read_size = 32;
41
42 //------------------------------------------------------------------------------------------
43 //
44
45 // 
46 ASDCP::Result_t
47 ASDCP::KLVPacket::InitFromBuffer(const byte_t* buf, ui32_t buf_len, const byte_t* label)
48 {
49   Result_t result = KLVPacket::InitFromBuffer(buf, buf_len);
50
51   if ( ASDCP_SUCCESS(result) )
52     result = ( memcmp(m_KeyStart, label, SMPTE_UL_LENGTH) == 0 ) ?
53       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   ui64_t tmp_size;
73   if ( ! read_BER(buf + SMPTE_UL_LENGTH, &tmp_size) )
74        return RESULT_FAIL;
75
76   m_ValueLength = tmp_size;
77   m_KLLength = SMPTE_UL_LENGTH + BER_length(buf + SMPTE_UL_LENGTH);
78   m_KeyStart = buf;
79   m_ValueStart = buf + m_KLLength;
80   return RESULT_OK;
81 }
82
83 //
84 bool
85 ASDCP::KLVPacket::HasUL(const byte_t* ul)
86 {
87   if ( m_KeyStart == 0 )
88     return false;
89
90   return ( memcmp(ul, m_KeyStart, SMPTE_UL_LENGTH) == 0 ) ? true : false;
91 }
92
93 //
94 ASDCP::Result_t
95 ASDCP::KLVPacket::WriteKLToBuffer(ASDCP::FrameBuffer& Buffer, const byte_t* label, ui32_t length)
96 {
97   if ( Buffer.Size() + kl_length > Buffer.Capacity() )
98     {
99       DefaultLogSink().Error("Small write buffer\n");
100       return RESULT_FAIL;
101     }
102   
103   memcpy(Buffer.Data() + Buffer.Size(), label, SMPTE_UL_LENGTH);
104
105   if ( ! write_BER(Buffer.Data() + Buffer.Size() + SMPTE_UL_LENGTH, length, MXF_BER_LENGTH) )
106     return RESULT_FAIL;
107
108   Buffer.Size(Buffer.Size() + kl_length);
109   return RESULT_OK;
110 }
111
112 //
113 void
114 ASDCP::KLVPacket::Dump(FILE* stream, bool show_hex)
115 {
116   if ( stream == 0 )
117     stream = stderr;
118
119   if ( m_KeyStart != 0 )
120     {
121       assert(m_ValueStart);
122
123       for ( ui32_t i = 0; i < SMPTE_UL_LENGTH; i++ )
124         fprintf(stream, "%02x.", m_KeyStart[i]);
125
126       const MDDEntry* Entry = Dict::FindUL(m_KeyStart);
127       fprintf(stream, "\b  len: %7lu (%s)\n", m_ValueLength, (Entry ? Entry->name : "Unknown"));
128
129       if ( show_hex && m_ValueLength < 1000 )
130         hexdump(m_ValueStart, ASDCP::xmin(m_ValueLength, (ui32_t)64), stream);
131     }
132   else
133     {
134       fprintf(stream, "*** Malformed packet ***\n");
135     }
136 }
137
138 // 
139 ASDCP::Result_t
140 ASDCP::KLVFilePacket::InitFromFile(const FileReader& Reader, const byte_t* label)
141 {
142   Result_t result = KLVFilePacket::InitFromFile(Reader);
143
144   if ( ASDCP_SUCCESS(result) )
145     result = ( memcmp(m_KeyStart, label, SMPTE_UL_LENGTH) == 0 ) ?
146       RESULT_OK : RESULT_FAIL;
147
148   return result;
149 }
150
151 //
152 ASDCP::Result_t
153 ASDCP::KLVFilePacket::InitFromFile(const FileReader& Reader)
154 {
155   ui32_t read_count;
156   byte_t tmp_data[tmp_read_size];
157   ui64_t tmp_size;
158   m_KeyStart = m_ValueStart = 0;
159   m_KLLength = m_ValueLength = 0;
160   m_Buffer.Size(0);
161
162   Result_t result = Reader.Read(tmp_data, tmp_read_size, &read_count);
163
164   if ( ASDCP_FAILURE(result) )
165     return result;
166
167   if ( read_count < (SMPTE_UL_LENGTH + 1) )
168     {
169       DefaultLogSink().Error("Short read of Key and Length got %lu\n", read_count);
170       return RESULT_READFAIL;
171     }
172
173   if ( memcmp(tmp_data, SMPTE_UL_START, 4) != 0 )
174     {
175       DefaultLogSink().Error("Unexpected UL preamble: %02x.%02x.%02x.%02x\n",
176                              tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]);
177       return RESULT_FAIL;
178     }
179
180   if ( ! read_BER(tmp_data + SMPTE_UL_LENGTH, &tmp_size) )
181     {
182       DefaultLogSink().Error("BER Length decoding error\n");
183       return RESULT_FAIL;
184     }
185
186   if ( tmp_size > MAX_KLV_PACKET_LENGTH )
187     {
188       char intbuf[IntBufferLen];
189       DefaultLogSink().Error("Packet length %s exceeds internal limit\n",
190                              ui64sz(tmp_size, intbuf));
191       return RESULT_FAIL;
192     }
193
194   ui32_t remainder = 0;
195   ui32_t ber_len = BER_length(tmp_data + SMPTE_UL_LENGTH);
196   m_KLLength = SMPTE_UL_LENGTH + ber_len;
197   m_ValueLength = tmp_size;
198   ui32_t packet_length = m_ValueLength + m_KLLength;
199
200   result = m_Buffer.Capacity(packet_length);
201
202   if ( ASDCP_FAILURE(result) )
203     return result;
204
205   m_KeyStart = m_Buffer.Data();
206   m_ValueStart = m_Buffer.Data() + m_KLLength;
207   m_Buffer.Size(packet_length);
208
209   // is the whole packet in the tmp buf?
210   if ( packet_length <= tmp_read_size )
211     {
212       assert(packet_length <= read_count);
213       memcpy(m_Buffer.Data(), tmp_data, packet_length);
214
215       if ( (remainder = read_count - packet_length) != 0 )
216         {
217           DefaultLogSink().Warn("Repositioning pointer for short packet\n");
218           ASDCP::fpos_t pos = Reader.Tell();
219           assert(pos > remainder);
220           result = Reader.Seek(pos - remainder);
221         }
222     }
223   else
224     {
225       if ( read_count < tmp_read_size )
226         {
227           DefaultLogSink().Error("Short read of packet body, expecting %lu, got %lu\n",
228                                  m_Buffer.Size(), read_count);
229           return RESULT_READFAIL;
230         }
231
232       memcpy(m_Buffer.Data(), tmp_data, tmp_read_size);
233       remainder = m_Buffer.Size() - tmp_read_size;
234
235       if ( remainder > 0 )
236         {
237           result = Reader.Read(m_Buffer.Data() + tmp_read_size, remainder, &read_count);
238       
239           if ( read_count != remainder )
240             {
241               DefaultLogSink().Error("Short read of packet body, expecting %lu, got %lu\n",
242                                      remainder+tmp_read_size, read_count+tmp_read_size);
243               result = RESULT_READFAIL;
244             }
245         }
246     }
247
248   return result;
249 }
250
251 //
252 ASDCP::Result_t
253 ASDCP::KLVFilePacket::WriteKLToFile(FileWriter& Writer, const byte_t* label, ui32_t length)
254 {
255   byte_t buffer[kl_length];
256   memcpy(buffer, label, SMPTE_UL_LENGTH);
257
258   if ( ! write_BER(buffer+SMPTE_UL_LENGTH, length, MXF_BER_LENGTH) )
259     return RESULT_FAIL;
260
261   ui32_t write_count;
262   Writer.Write(buffer, kl_length, &write_count);
263   assert(write_count == kl_length);
264   return RESULT_OK;
265 }
266
267
268 //
269 // end KLV.cpp
270 //