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