1 /* libasf - An Advanced Systems Format media file parser
2 * Copyright (C) 2006-2010 Juho Vähä-Herttua
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.
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.
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
30 * Read next object from buffer pointed by data. Notice that
31 * no buffer overflow checks are done! This function always
32 * expects to have 24 bytes available, which is the size of
33 * the object header (GUID + data size)
36 asf_parse_read_object(asfint_object_t
*obj
, uint8_t *data
)
38 GetGUID(data
, &obj
->guid
);
39 obj
->type
= asf_guid_get_type(&obj
->guid
);
40 obj
->size
= GetQWLE(data
+ 16);
41 obj
->full_data
= data
;
46 if (obj
->type
== GUID_UNKNOWN
) {
47 debug_printf("unknown object: %x-%x-%x-%02x%02x%02x%02x%02x%02x%02x%02x, %ld bytes",
48 obj
->guid
.v1
, obj
->guid
.v2
, obj
->guid
.v3
, obj
->guid
.v4
[0],
49 obj
->guid
.v4
[1], obj
->guid
.v4
[2], obj
->guid
.v4
[3], obj
->guid
.v4
[4],
50 obj
->guid
.v4
[5], obj
->guid
.v4
[6], obj
->guid
.v4
[7], (long) obj
->size
);
55 * Parse header extension object. Takes a pointer to a newly allocated
56 * header extension structure, a pointer to the data buffer and the
57 * length of the data buffer as its parameters. Subobject contents are
58 * not parsed, but they are added as a linked list to the header object.
61 asf_parse_headerext(asf_object_headerext_t
*header
, uint8_t *buf
, uint64_t buflen
)
66 if (header
->size
< 46) {
67 /* invalide size for headerext */
68 return ASF_ERROR_INVALID_OBJECT_SIZE
;
71 /* Read reserved and datalen fields from the buffer */
72 GetGUID(buf
+ 24, &header
->reserved1
);
73 header
->reserved2
= GetWLE(buf
+ 40);
74 header
->datalen
= GetDWLE(buf
+ 42);
76 if (header
->datalen
!= header
->size
- 46) {
77 /* invalid header extension data length value */
78 return ASF_ERROR_INVALID_LENGTH
;
80 header
->data
= buf
+ 46;
82 debug_printf("parsing header extension subobjects");
84 datalen
= header
->datalen
;
87 asfint_object_t
*current
;
90 /* not enough data for reading a new object */
94 /* Allocate a new subobject */
95 current
= malloc(sizeof(asfint_object_t
));
97 return ASF_ERROR_OUTOFMEM
;
100 asf_parse_read_object(current
, data
);
101 if (current
->size
> datalen
|| current
->size
< 24) {
102 /* invalid object size */
105 current
->datalen
= current
->size
- 24;
106 current
->data
= data
+ 24;
108 /* add to the list of subobjects */
109 if (!header
->first
) {
110 header
->first
= current
;
111 header
->last
= current
;
113 header
->last
->next
= current
;
114 header
->last
= current
;
117 data
+= current
->size
;
118 datalen
-= current
->size
;
122 /* not enough data for reading the whole object */
123 return ASF_ERROR_INVALID_LENGTH
;
126 debug_printf("header extension subobjects parsed successfully");
132 * Takes an initialized asf_file_t structure file as a parameter. Allocates
133 * a new asf_object_header_t in file->header and uses the file->iostream to
134 * read all fields and subobjects into it. Finally calls the
135 * asf_parse_header_validate function to validate the values and parse the
136 * commonly used values into the asf_file_t struct itself.
139 asf_parse_header(asf_file_t
*file
)
141 asf_object_header_t
*header
;
142 asf_iostream_t
*iostream
;
147 iostream
= &file
->iostream
;
149 /* object minimum is 24 bytes and header needs to have
150 * the subobject count field and two reserved fields */
151 tmp
= asf_byteio_read(iostream
, hdata
, 30);
153 /* not enough data to read the header object */
157 file
->header
= malloc(sizeof(asf_object_header_t
));
158 header
= file
->header
;
160 return ASF_ERROR_OUTOFMEM
;
163 /* read the object and check its size value */
164 asf_parse_read_object((asfint_object_t
*) header
, hdata
);
165 if (header
->size
< 30) {
166 /* invalid size for header object */
167 return ASF_ERROR_INVALID_OBJECT_SIZE
;
170 /* read header object specific compulsory fields */
171 header
->subobjects
= GetDWLE(hdata
+ 24);
172 header
->reserved1
= hdata
[28];
173 header
->reserved2
= hdata
[29];
175 /* clear header extension object and subobject list */
177 header
->first
= NULL
;
180 /* the header data needs to be allocated for reading */
181 header
->datalen
= header
->size
- 30;
182 header
->data
= malloc(header
->datalen
* sizeof(uint8_t));
184 return ASF_ERROR_OUTOFMEM
;
187 tmp
= asf_byteio_read(iostream
, header
->data
, header
->datalen
);
192 if (header
->subobjects
> 0) {
197 debug_printf("starting to read subobjects");
199 /* use temporary variables for use during the read */
200 datalen
= header
->datalen
;
202 for (i
=0; i
<header
->subobjects
; i
++) {
203 asfint_object_t
*current
;
206 /* not enough data for reading object */
210 current
= malloc(sizeof(asfint_object_t
));
212 return ASF_ERROR_OUTOFMEM
;
215 asf_parse_read_object(current
, data
);
216 if (current
->size
> datalen
|| current
->size
< 24) {
217 /* invalid object size */
221 /* Check if the current subobject is a header extension
222 * object or just a normal subobject */
223 if (current
->type
== GUID_HEADER_EXTENSION
&& !header
->ext
) {
225 asf_object_headerext_t
*headerext
;
227 /* we handle header extension separately because it has
228 * some subobjects as well */
229 current
= realloc(current
, sizeof(asf_object_headerext_t
));
230 headerext
= (asf_object_headerext_t
*) current
;
231 headerext
->first
= NULL
;
232 headerext
->last
= NULL
;
233 ret
= asf_parse_headerext(headerext
, data
, datalen
);
236 /* error parsing header extension */
240 header
->ext
= headerext
;
242 if (current
->type
== GUID_HEADER_EXTENSION
) {
243 debug_printf("WARNING! Second header extension object found, ignoring it!");
246 current
->datalen
= current
->size
- 24;
247 current
->data
= data
+ 24;
249 /* add to list of subobjects */
250 if (!header
->first
) {
251 header
->first
= current
;
252 header
->last
= current
;
254 header
->last
->next
= current
;
255 header
->last
= current
;
259 data
+= current
->size
;
260 datalen
-= current
->size
;
263 if (i
!= header
->subobjects
|| datalen
!= 0) {
264 /* header data size doesn't match given subobject count */
265 return ASF_ERROR_INVALID_VALUE
;
268 debug_printf("%d subobjects read successfully", i
);
271 tmp
= asf_parse_header_validate(file
, file
->header
);
273 /* header read ok but doesn't validate correctly */
277 debug_printf("header validated correctly");
283 * Takes an initialized asf_file_t structure file as a parameter. Allocates
284 * a new asf_object_data_t in file->data and uses the file->iostream to
285 * read all its compulsory fields into it. Notice that the actual data is
286 * not read in any way, because we need to be able to work with non-seekable
290 asf_parse_data(asf_file_t
*file
)
292 asf_object_data_t
*data
;
293 asf_iostream_t
*iostream
;
298 iostream
= &file
->iostream
;
300 /* object minimum is 24 bytes and data object needs to have
301 * 26 additional bytes for its internal fields */
302 tmp
= asf_byteio_read(iostream
, ddata
, 50);
307 file
->data
= malloc(sizeof(asf_object_data_t
));
310 return ASF_ERROR_OUTOFMEM
;
313 /* read the object and check its size value */
314 asf_parse_read_object((asfint_object_t
*) data
, ddata
);
315 if (data
->size
< 50) {
316 /* invalid size for data object */
317 return ASF_ERROR_INVALID_OBJECT_SIZE
;
320 /* read data object specific compulsory fields */
321 GetGUID(ddata
+ 24, &data
->file_id
);
322 data
->total_data_packets
= GetQWLE(ddata
+ 40);
323 data
->reserved
= GetWLE(ddata
+ 48);
324 data
->packets_position
= file
->position
+ 50;
326 /* If the file_id GUID in data object doesn't match the
327 * file_id GUID in headers, the file is corrupted */
328 if (!asf_guid_equals(&data
->file_id
, &file
->file_id
)) {
329 return ASF_ERROR_INVALID_VALUE
;
332 /* if data->total_data_packets is non-zero (not a stream) and
333 the data packets count doesn't match, return error */
334 if (data
->total_data_packets
&&
335 data
->total_data_packets
!= file
->data_packets_count
) {
336 return ASF_ERROR_INVALID_VALUE
;
343 * Takes an initialized asf_file_t structure file as a parameter. Allocates
344 * a new asf_object_index_t in file->index and uses the file->iostream to
345 * read all its compulsory fields into it. Notice that the actual data is
346 * not read in any way, because we need to be able to work with non-seekable
350 asf_parse_index(asf_file_t
*file
)
352 asf_object_index_t
*index
;
353 asf_iostream_t
*iostream
;
355 uint64_t entry_data_size
;
356 uint8_t *entry_data
= NULL
;
360 iostream
= &file
->iostream
;
362 /* read the raw data of an index header */
363 tmp
= asf_byteio_read(iostream
, idata
, 56);
365 printf("Could not read index header\n");
369 /* allocate the index object */
370 index
= malloc(sizeof(asf_object_index_t
));
372 return ASF_ERROR_OUTOFMEM
;
375 asf_parse_read_object((asfint_object_t
*) index
, idata
);
376 if (index
->type
!= GUID_INDEX
) {
380 /* The guid type was wrong, just return the bytes to skip */
384 if (index
->size
< 56) {
385 /* invalid size for index object */
387 return ASF_ERROR_INVALID_OBJECT_SIZE
;
390 GetGUID(idata
+ 24, &index
->file_id
);
391 index
->entry_time_interval
= GetQWLE(idata
+ 40);
392 index
->max_packet_count
= GetDWLE(idata
+ 48);
393 index
->entry_count
= GetDWLE(idata
+ 52);
396 printf("Total Index Entries %d\n",index
->entry_count
);
397 printf("Index Size in bytes %Ld\n",index
->size
);
398 printf("Index Max Packet Count %d\n",index
->max_packet_count
);
399 printf("Index Entry Time Interval %Ld\n",index
->entry_time_interval
);
401 if (index
->entry_count
== 0) {
402 printf("Index has no entries\n");
407 if (index
->entry_count
* 6 + 56 > index
->size
) {
409 return ASF_ERROR_INVALID_LENGTH
;
412 entry_data_size
= index
->entry_count
* 6;
413 entry_data
= malloc(entry_data_size
* sizeof(uint8_t));
416 return ASF_ERROR_OUTOFMEM
;
418 tmp
= asf_byteio_read(iostream
, entry_data
, entry_data_size
);
420 printf("Could not read entry data\n");
426 index
->entries
= malloc(index
->entry_count
* sizeof(asf_index_entry_t
));
427 if (!index
->entries
) {
430 return ASF_ERROR_OUTOFMEM
;
433 for (i
=0; i
<index
->entry_count
; i
++) {
434 index
->entries
[i
].packet_index
= GetDWLE(entry_data
+ i
*6);
435 index
->entries
[i
].packet_count
= GetWLE(entry_data
+ i
*6 + 4);