1/*  libasf - An Advanced Systems Format media file parser
2 *  Copyright (C) 2006-2010 Juho Vähä-Herttua
3 *
4 *  This library is free software; you can redistribute it and/or
5 *  modify it under the terms of the GNU Lesser General Public
6 *  License as published by the Free Software Foundation; either
7 *  version 2.1 of the License, or (at your option) any later version.
8 *
9 *  This library is distributed in the hope that it will be useful,
10 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 *  Lesser General Public License for more details.
13 *
14 *  You should have received a copy of the GNU Lesser General Public
15 *  License along with this library; if not, write to the Free Software
16 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19#include <stdlib.h>
20#include <string.h>
21
22#include "asfint.h"
23#include "byteio.h"
24#include "data.h"
25#include "parse.h"
26#include "debug.h"
27
28static int
29asf_data_read_packet_fields(asf_packet_t *packet, uint8_t flags,
30                            uint8_t *data, uint32_t len)
31{
32	uint8_t datalen;
33
34	datalen = GETLEN2b((flags >> 1) & 0x03) +
35	          GETLEN2b((flags >> 3) & 0x03) +
36	          GETLEN2b((flags >> 5) & 0x03) + 6;
37
38	if (datalen > len) {
39		return ASF_ERROR_INVALID_LENGTH;
40	}
41
42	packet->length = GETVALUE2b((flags >> 5) & 0x03, data);
43	data += GETLEN2b((flags >> 5) & 0x03);
44	packet->sequence = GETVALUE2b((flags >> 1) & 0x03, data);
45	data += GETLEN2b((flags >> 1) & 0x03);
46	packet->padding_length = GETVALUE2b((flags >> 3) & 0x03, data);
47	data += GETLEN2b((flags >> 3) & 0x03);
48	packet->send_time = GetDWLE(data);
49	data += 4;
50	packet->duration = GetWLE(data);
51	data += 2;
52
53	return datalen;
54}
55
56static int
57asf_data_read_payload_fields(asf_payload_t *payload, uint8_t flags, uint8_t *data, int size)
58{
59	uint8_t datalen;
60
61	datalen = GETLEN2b(flags & 0x03) +
62	          GETLEN2b((flags >> 2) & 0x03) +
63	          GETLEN2b((flags >> 4) & 0x03);
64
65	if (datalen > size) {
66		return ASF_ERROR_INVALID_LENGTH;
67	}
68
69	payload->media_object_number = GETVALUE2b((flags >> 4) & 0x03, data);
70	data += GETLEN2b((flags >> 4) & 0x03);
71	payload->media_object_offset = GETVALUE2b((flags >> 2) & 0x03, data);
72	data += GETLEN2b((flags >> 2) & 0x03);
73	payload->replicated_length = GETVALUE2b(flags & 0x03, data);
74	data += GETLEN2b(flags & 0x03);
75
76	return datalen;
77}
78
79static int
80asf_data_read_payloads(asf_packet_t *packet,
81                       uint64_t preroll,
82                       uint8_t multiple,
83                       uint8_t flags,
84                       uint8_t *data,
85                       uint32_t datalen)
86{
87	asf_payload_t pl;
88        uint32_t skip;
89	int i, tmp;
90
91	skip = 0, i = 0;
92	while (i < packet->payload_count) {
93		uint8_t pts_delta = 0;
94		int compressed = 0;
95
96		if (skip+1 > datalen) {
97			return ASF_ERROR_INVALID_LENGTH;
98		}
99		pl.stream_number = data[skip] & 0x7f;
100		pl.key_frame = !!(data[skip] & 0x80);
101		skip++;
102
103		tmp = asf_data_read_payload_fields(&pl, flags, data + skip, datalen - skip);
104		if (tmp < 0) {
105			return tmp;
106		}
107		skip += tmp;
108
109		if (pl.replicated_length > 1) {
110			if (pl.replicated_length < 8 || pl.replicated_length + skip > datalen) {
111				/* not enough data */
112				return ASF_ERROR_INVALID_LENGTH;
113			}
114			pl.replicated_data = data + skip;
115			skip += pl.replicated_length;
116
117			pl.pts = GetDWLE(pl.replicated_data + 4);
118		} else if (pl.replicated_length == 1) {
119			if (skip+1 > datalen) {
120				/* not enough data */
121				return ASF_ERROR_INVALID_LENGTH;
122			}
123
124			/* in compressed payload object offset is actually pts */
125			pl.pts = pl.media_object_offset;
126			pl.media_object_offset = 0;
127
128			pl.replicated_length = 0;
129			pl.replicated_data = NULL;
130
131			pts_delta = data[skip];
132			skip++;
133			compressed = 1;
134		} else {
135			pl.pts = packet->send_time;
136			pl.replicated_data = NULL;
137		}
138
139		/* substract preroll value from pts since it's counted in */
140		if (pl.pts > preroll) {
141			pl.pts -= preroll;
142		} else {
143			pl.pts = 0;
144		}
145
146		if (multiple) {
147			if (skip + 2 > datalen) {
148				/* not enough data */
149				return ASF_ERROR_INVALID_LENGTH;
150			}
151			pl.datalen = GetWLE(data + skip);
152			skip += 2;
153		} else {
154			pl.datalen = datalen - skip;
155		}
156
157		if (compressed) {
158			uint32_t start = skip, used = 0;
159			int payloads, idx;
160
161			/* count how many compressed payloads this payload includes */
162			for (payloads=0; used < pl.datalen; payloads++) {
163				used += 1 + data[start + used];
164			}
165
166			if (used != pl.datalen) {
167				/* invalid compressed data size */
168				return ASF_ERROR_INVALID_LENGTH;
169			}
170
171			/* add additional payloads excluding the already allocated one */
172			packet->payload_count += payloads - 1;
173			if (packet->payload_count > packet->payloads_size) {
174				void *tempptr;
175
176				tempptr = realloc(packet->payloads,
177				                  packet->payload_count * sizeof(asf_payload_t));
178				if (!tempptr) {
179					return ASF_ERROR_OUTOFMEM;
180				}
181				packet->payloads = tempptr;
182				packet->payloads_size = packet->payload_count;
183			}
184
185			for (idx = 0; idx < payloads; idx++) {
186				pl.datalen = data[skip];
187				skip++;
188
189				/* Set data correctly */
190				pl.data = data + skip;
191				skip += pl.datalen;
192
193				/* Copy the final payload and update the PTS */
194				memcpy(&packet->payloads[i], &pl, sizeof(asf_payload_t));
195				packet->payloads[i].pts = pl.pts + idx * pts_delta;
196				i++;
197
198				debug_printf("payload(%d/%d) stream: %d, key frame: %d, object: %d, offset: %d, pts: %d, datalen: %d",
199					     i, packet->payload_count, pl.stream_number, (int) pl.key_frame, pl.media_object_number,
200					     pl.media_object_offset, pl.pts + idx * pts_delta, pl.datalen);
201			}
202		} else {
203			pl.data = data + skip;
204			memcpy(&packet->payloads[i], &pl, sizeof(asf_payload_t));
205
206			/* update the skipped data amount and payload index */
207			skip += pl.datalen;
208			i++;
209
210			debug_printf("payload(%d/%d) stream: %d, key frame: %d, object: %d, offset: %d, pts: %d, datalen: %d",
211				     i, packet->payload_count, pl.stream_number, (int) pl.key_frame, pl.media_object_number,
212				     pl.media_object_offset, pl.pts, pl.datalen);
213		}
214	}
215
216	return skip;
217}
218
219void
220asf_data_init_packet(asf_packet_t *packet)
221{
222	packet->ec_length = 0;
223	packet->ec_data = NULL;
224
225	packet->length = 0;
226	packet->padding_length = 0;
227	packet->send_time = 0;
228	packet->duration = 0;
229
230	packet->payload_count = 0;
231	packet->payloads = NULL;
232	packet->payloads_size = 0;
233
234	packet->payload_data_len = 0;
235	packet->payload_data = NULL;
236
237	packet->data = NULL;
238	packet->data_size = 0;
239}
240
241int
242asf_data_get_packet(asf_packet_t *packet, asf_file_t *file)
243{
244	asf_iostream_t *iostream;
245	uint32_t read = 0;
246	int packet_flags, packet_property;
247	void *tmpptr;
248	int tmp;
249
250	iostream = &file->iostream;
251	if (file->packet_size == 0) {
252		return ASF_ERROR_INVALID_LENGTH;
253	}
254
255	/* If the internal data is not allocated, allocate it */
256	if (packet->data_size < file->packet_size) {
257		tmpptr = realloc(packet->data, file->packet_size);
258		if (!tmpptr) {
259			return ASF_ERROR_OUTOFMEM;
260		}
261		packet->data = tmpptr;
262		packet->data_size = file->packet_size;
263	}
264
265	tmp = asf_byteio_read(iostream, packet->data, file->packet_size);
266	if (tmp < 0) {
267		/* Error reading packet data */
268		return tmp;
269	}
270
271	tmp = packet->data[read++];
272	if (tmp & 0x80) {
273		uint8_t opaque_data, ec_length_type;
274
275		packet->ec_length = tmp & 0x0f;
276		opaque_data = (tmp >> 4) & 0x01;
277		ec_length_type = (tmp >> 5) & 0x03;
278
279		if (ec_length_type != 0x00 ||
280		    opaque_data != 0 ||
281		    packet->ec_length != 0x02) {
282			/* incorrect error correction flags */
283			return ASF_ERROR_INVALID_VALUE;
284		}
285
286		if (read+packet->ec_length > file->packet_size) {
287			return ASF_ERROR_INVALID_LENGTH;
288		}
289		packet->ec_data = &packet->data[read];
290		read += packet->ec_length;
291	} else {
292		packet->ec_length = 0;
293		packet->ec_data = NULL;
294	}
295
296	if (read+2 > file->packet_size) {
297		return ASF_ERROR_INVALID_LENGTH;
298	}
299	packet_flags = packet->data[read++];
300	packet_property = packet->data[read++];
301
302	tmp = asf_data_read_packet_fields(packet, packet_flags,
303	                                  packet->data + read,
304	                                  file->packet_size - read);
305	if (tmp < 0) {
306		return tmp;
307	}
308	read += tmp;
309
310	/* this is really idiotic, packet length can (and often will) be
311	 * undefined and we just have to use the header packet size as the size
312	 * value */
313	if (((packet_flags >> 5) & 0x03) == 0) {
314		packet->length = file->packet_size;
315	}
316
317	/* this is also really idiotic, if packet length is smaller than packet
318	 * size, we need to manually add the additional bytes into padding length
319	 * because the padding bytes only count up to packet length value */
320	if (packet->length < file->packet_size) {
321		packet->padding_length += file->packet_size - packet->length;
322		packet->length = file->packet_size;
323	}
324
325	if (packet->length != file->packet_size) {
326		/* packet with invalid length value */
327		return ASF_ERROR_INVALID_LENGTH;
328	}
329
330	/* check if we have multiple payloads */
331	if (packet_flags & 0x01) {
332		int payload_length_type;
333
334		if (read+1 > packet->length) {
335			return ASF_ERROR_INVALID_LENGTH;
336		}
337		tmp = packet->data[read++];
338
339		packet->payload_count = tmp & 0x3f;
340		payload_length_type = (tmp >> 6) & 0x03;
341
342		if (packet->payload_count == 0) {
343			/* there should always be at least one payload */
344			return ASF_ERROR_INVALID_VALUE;
345		}
346
347		if (payload_length_type != 0x02) {
348			/* in multiple payloads datalen should always be a word */
349			return ASF_ERROR_INVALID_VALUE;
350		}
351	} else {
352		packet->payload_count = 1;
353	}
354	packet->payload_data_len = packet->length - read;
355
356	if (packet->payload_count > packet->payloads_size) {
357		tmpptr = realloc(packet->payloads,
358		                 packet->payload_count * sizeof(asf_payload_t));
359		if (!tmpptr) {
360			return ASF_ERROR_OUTOFMEM;
361		}
362		packet->payloads = tmpptr;
363		packet->payloads_size = packet->payload_count;
364	}
365
366	packet->payload_data = &packet->data[read];
367	read += packet->payload_data_len;
368
369	/* The return value will be consumed bytes, not including the padding */
370	tmp = asf_data_read_payloads(packet, file->preroll, packet_flags & 0x01,
371	                             packet_property, packet->payload_data,
372	                             packet->payload_data_len - packet->padding_length);
373	if (tmp < 0) {
374		return tmp;
375	}
376
377	debug_printf("packet read %d bytes, eclen: %d, length: %d, padding: %d, time %d, duration: %d, payloads: %d",
378	             read, packet->ec_length, packet->length, packet->padding_length, packet->send_time,
379	             packet->duration, packet->payload_count);
380
381	return read;
382}
383
384void
385asf_data_free_packet(asf_packet_t *packet)
386{
387	if (!packet)
388		return;
389
390	free(packet->payloads);
391	free(packet->data);
392
393	packet->ec_data = NULL;
394	packet->payloads = NULL;
395	packet->payload_data = NULL;
396	packet->data = NULL;
397}
398