vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / media / plugins / asf_reader / libasf / parse.c
blobf2a3f34b4916904144cd6fc33f9885601b85f9d9
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
19 #include <stdlib.h>
20 #include <string.h>
22 #include "asf.h"
23 #include "asfint.h"
24 #include "byteio.h"
25 #include "header.h"
26 #include "guid.h"
27 #include "debug.h"
29 /**
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)
35 static void
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;
42 obj->datalen = 0;
43 obj->data = NULL;
44 obj->next = NULL;
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);
54 /**
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.
60 static int
61 asf_parse_headerext(asf_object_headerext_t *header, uint8_t *buf, uint64_t buflen)
63 int64_t datalen;
64 uint8_t *data;
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;
85 data = header->data;
86 while (datalen > 0) {
87 asfint_object_t *current;
89 if (datalen < 24) {
90 /* not enough data for reading a new object */
91 break;
94 /* Allocate a new subobject */
95 current = malloc(sizeof(asfint_object_t));
96 if (!current) {
97 return ASF_ERROR_OUTOFMEM;
100 asf_parse_read_object(current, data);
101 if (current->size > datalen || current->size < 24) {
102 /* invalid object size */
103 break;
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;
112 } else {
113 header->last->next = current;
114 header->last = current;
117 data += current->size;
118 datalen -= current->size;
121 if (datalen != 0) {
122 /* not enough data for reading the whole object */
123 return ASF_ERROR_INVALID_LENGTH;
126 debug_printf("header extension subobjects parsed successfully");
128 return header->size;
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;
143 uint8_t hdata[30];
144 int tmp;
146 file->header = NULL;
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);
152 if (tmp < 0) {
153 /* not enough data to read the header object */
154 return tmp;
157 file->header = malloc(sizeof(asf_object_header_t));
158 header = file->header;
159 if (!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 */
176 header->ext = NULL;
177 header->first = NULL;
178 header->last = 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));
183 if (!header->data) {
184 return ASF_ERROR_OUTOFMEM;
187 tmp = asf_byteio_read(iostream, header->data, header->datalen);
188 if (tmp < 0) {
189 return tmp;
192 if (header->subobjects > 0) {
193 uint64_t datalen;
194 uint8_t *data;
195 int i;
197 debug_printf("starting to read subobjects");
199 /* use temporary variables for use during the read */
200 datalen = header->datalen;
201 data = header->data;
202 for (i=0; i<header->subobjects; i++) {
203 asfint_object_t *current;
205 if (datalen < 24) {
206 /* not enough data for reading object */
207 break;
210 current = malloc(sizeof(asfint_object_t));
211 if (!current) {
212 return ASF_ERROR_OUTOFMEM;
215 asf_parse_read_object(current, data);
216 if (current->size > datalen || current->size < 24) {
217 /* invalid object size */
218 break;
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) {
224 int ret;
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);
235 if (ret < 0) {
236 /* error parsing header extension */
237 return ret;
240 header->ext = headerext;
241 } else {
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;
253 } else {
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);
272 if (tmp < 0) {
273 /* header read ok but doesn't validate correctly */
274 return tmp;
277 debug_printf("header validated correctly");
279 return header->size;
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
287 * streams as well.
290 asf_parse_data(asf_file_t *file)
292 asf_object_data_t *data;
293 asf_iostream_t *iostream;
294 uint8_t ddata[50];
295 int tmp;
297 file->data = NULL;
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);
303 if (tmp < 0) {
304 return tmp;
307 file->data = malloc(sizeof(asf_object_data_t));
308 data = file->data;
309 if (!data) {
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;
339 return 50;
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
347 * streams as well.
350 asf_parse_index(asf_file_t *file)
352 asf_object_index_t *index;
353 asf_iostream_t *iostream;
354 uint8_t idata[56];
355 uint64_t entry_data_size;
356 uint8_t *entry_data = NULL;
357 int tmp, i;
359 file->index = NULL;
360 iostream = &file->iostream;
362 /* read the raw data of an index header */
363 tmp = asf_byteio_read(iostream, idata, 56);
364 if (tmp < 0) {
365 printf("Could not read index header\n");
366 return tmp;
369 /* allocate the index object */
370 index = malloc(sizeof(asf_object_index_t));
371 if (!index) {
372 return ASF_ERROR_OUTOFMEM;
375 asf_parse_read_object((asfint_object_t *) index, idata);
376 if (index->type != GUID_INDEX) {
377 tmp = index->size;
378 free(index);
380 /* The guid type was wrong, just return the bytes to skip */
381 return tmp;
384 if (index->size < 56) {
385 /* invalid size for index object */
386 free(index);
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);
395 printf("INDEX\n");
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");
403 file->index = index;
404 return index->size;
407 if (index->entry_count * 6 + 56 > index->size) {
408 free(index);
409 return ASF_ERROR_INVALID_LENGTH;
412 entry_data_size = index->entry_count * 6;
413 entry_data = malloc(entry_data_size * sizeof(uint8_t));
414 if (!entry_data) {
415 free(index);
416 return ASF_ERROR_OUTOFMEM;
418 tmp = asf_byteio_read(iostream, entry_data, entry_data_size);
419 if (tmp < 0) {
420 printf("Could not read entry data\n");
421 free(index);
422 free(entry_data);
423 return tmp;
426 index->entries = malloc(index->entry_count * sizeof(asf_index_entry_t));
427 if (!index->entries) {
428 free(index);
429 free(entry_data);
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);
438 free(entry_data);
439 file->index = index;
441 return index->size;