3rdparty/licenseReport: Add seperate LGPL checks
[haiku.git] / src / add-ons / media / plugins / asf_reader / libasf / header.c
bloba547c400fe199ffa4e1d61b6e899ee1f955c729c
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 <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
23 #include "asfint.h"
24 #include "utf.h"
25 #include "header.h"
26 #include "guid.h"
27 #include "byteio.h"
28 #include "debug.h"
30 /**
31 * Finds an object with the corresponding GUID type from header object. If
32 * not found, just returns NULL.
34 static asfint_object_t *
35 asf_header_get_object(asf_object_header_t *header, const guid_type_t type)
37 asfint_object_t *current;
39 current = header->first;
40 while (current) {
41 if (current->type == type) {
42 return current;
44 current = current->next;
47 return NULL;
50 /**
51 * Reads the stream properties object's data into the equivalent
52 * data structure, and stores it in asf_stream_t structure
53 * with the equivalent stream type. Needs the stream properties
54 * object data as its input.
56 static int
57 asf_parse_header_stream_properties(asf_stream_t *stream,
58 uint8_t *objdata,
59 uint32_t objsize)
61 asf_guid_t guid;
62 guid_type_t type;
63 uint32_t datalen;
64 uint8_t *data;
66 if (objsize < 78) {
67 return ASF_ERROR_INVALID_LENGTH;
70 GetGUID(objdata, &guid);
71 type = asf_guid_get_stream_type(&guid);
73 datalen = GetDWLE(objdata + 40);
74 if (datalen > objsize - 78) {
75 return ASF_ERROR_INVALID_LENGTH;
77 data = objdata + 54;
79 if (type == GUID_STREAM_TYPE_EXTENDED) {
80 /* FIXME: Need to find out what actually is here...
81 but for now we can just skip the extended part */
82 if (datalen < 64)
83 return ASF_ERROR_INVALID_LENGTH;
85 data += 64;
86 datalen -= 64;
88 /* update the stream type with correct one */
89 GetGUID(objdata, &guid);
90 type = asf_guid_get_stream_type(&guid);
93 switch (type) {
94 case GUID_STREAM_TYPE_AUDIO:
95 case GUID_STREAM_TYPE_EXTENDED_AUDIO:
97 asf_waveformatex_t *wfx;
99 stream->type = ASF_STREAM_TYPE_AUDIO;
101 if (datalen < 18) {
102 return ASF_ERROR_INVALID_LENGTH;
104 if (GetWLE(data + 16) > datalen - 16) {
105 return ASF_ERROR_INVALID_LENGTH;
108 /* this should be freed in asf_close function */
109 stream->properties = malloc(sizeof(asf_waveformatex_t));
110 if (!stream->properties)
111 return ASF_ERROR_OUTOFMEM;
112 stream->flags |= ASF_STREAM_FLAG_AVAILABLE;
114 wfx = stream->properties;
115 wfx->wFormatTag = GetWLE(data);
116 wfx->nChannels = GetWLE(data + 2);
117 wfx->nSamplesPerSec = GetDWLE(data + 4);
118 wfx->nAvgBytesPerSec = GetDWLE(data + 8);
119 wfx->nBlockAlign = GetWLE(data + 12);
120 wfx->wBitsPerSample = GetWLE(data + 14);
121 wfx->cbSize = GetWLE(data + 16);
122 wfx->data = data + 18;
124 if (wfx->cbSize > datalen - 18) {
125 debug_printf("Invalid waveformatex data length, truncating!");
126 wfx->cbSize = datalen - 18;
129 break;
131 case GUID_STREAM_TYPE_VIDEO:
133 asf_bitmapinfoheader_t *bmih;
134 uint32_t width, height, flags, data_size;
136 stream->type = ASF_STREAM_TYPE_VIDEO;
138 if (datalen < 51) {
139 return ASF_ERROR_INVALID_LENGTH;
142 width = GetDWLE(data);
143 height = GetDWLE(data + 4);
144 flags = data[8];
145 data_size = GetWLE(data + 9);
147 data += 11;
148 datalen -= 11;
150 if (GetDWLE(data) != datalen) {
151 return ASF_ERROR_INVALID_LENGTH;
153 if (width != GetDWLE(data + 4) ||
154 height != GetDWLE(data + 8) ||
155 flags != 2) {
156 return ASF_ERROR_INVALID_VALUE;
159 /* this should be freed in asf_close function */
160 stream->properties = malloc(sizeof(asf_bitmapinfoheader_t));
161 if (!stream->properties)
162 return ASF_ERROR_OUTOFMEM;
163 stream->flags |= ASF_STREAM_FLAG_AVAILABLE;
165 bmih = stream->properties;
166 bmih->biSize = GetDWLE(data);
167 bmih->biWidth = GetDWLE(data + 4);
168 bmih->biHeight = GetDWLE(data + 8);
169 bmih->biPlanes = GetDWLE(data + 12);
170 bmih->biBitCount = GetDWLE(data + 14);
171 bmih->biCompression = GetDWLE(data + 16);
172 bmih->biSizeImage = GetDWLE(data + 20);
173 bmih->biXPelsPerMeter = GetDWLE(data + 24);
174 bmih->biYPelsPerMeter = GetDWLE(data + 28);
175 bmih->biClrUsed = GetDWLE(data + 32);
176 bmih->biClrImportant = GetDWLE(data + 36);
177 bmih->data = data + 40;
179 if (bmih->biSize > datalen) {
180 debug_printf("Invalid bitmapinfoheader data length, truncating!");
181 bmih->biSize = datalen;
184 break;
186 case GUID_STREAM_TYPE_COMMAND:
187 stream->type = ASF_STREAM_TYPE_COMMAND;
188 break;
189 default:
190 stream->type = ASF_STREAM_TYPE_UNKNOWN;
191 break;
194 return 0;
197 static int
198 asf_parse_header_extended_stream_properties(asf_stream_t *stream,
199 uint8_t *objdata,
200 uint32_t objsize)
202 asf_stream_extended_properties_t ext;
203 uint32_t datalen;
204 uint8_t *data;
205 uint16_t flags;
206 int i;
208 ext.start_time = GetQWLE(objdata);
209 ext.end_time = GetQWLE(objdata + 8);
210 ext.data_bitrate = GetDWLE(objdata + 16);
211 ext.buffer_size = GetDWLE(objdata + 20);
212 ext.initial_buf_fullness = GetDWLE(objdata + 24);
213 ext.data_bitrate2 = GetDWLE(objdata + 28);
214 ext.buffer_size2 = GetDWLE(objdata + 32);
215 ext.initial_buf_fullness2 = GetDWLE(objdata + 36);
216 ext.max_obj_size = GetDWLE(objdata + 40);
217 ext.flags = GetDWLE(objdata + 44);
218 ext.stream_num = GetWLE(objdata + 48);
219 ext.lang_idx = GetWLE(objdata + 50);
220 ext.avg_time_per_frame = GetQWLE(objdata + 52);
221 ext.stream_name_count = GetWLE(objdata + 60);
222 ext.num_payload_ext = GetWLE(objdata + 62);
224 datalen = objsize - 88;
225 data = objdata + 64;
227 /* iterate through all name strings */
228 for (i=0; i<ext.stream_name_count; i++) {
229 uint16_t strlen;
231 if (datalen < 4) {
232 return ASF_ERROR_INVALID_VALUE;
235 strlen = GetWLE(data + 2);
236 if (strlen > datalen) {
237 return ASF_ERROR_INVALID_LENGTH;
240 /* skip the current name string */
241 data += 4 + strlen;
242 datalen -= 4 + strlen;
245 /* iterate through all extension systems */
246 for (i=0; i<ext.num_payload_ext; i++) {
247 uint32_t extsyslen;
249 if (datalen < 22) {
250 return ASF_ERROR_INVALID_VALUE;
253 extsyslen = GetDWLE(data + 18);
254 if (extsyslen > datalen) {
255 return ASF_ERROR_INVALID_LENGTH;
258 /* skip the current extension system */
259 data += 22 + extsyslen;
260 datalen -= 22 + extsyslen;
263 if (datalen > 0) {
264 asf_guid_t guid;
266 debug_printf("hidden stream properties object found!");
268 /* this is almost same as in stream properties handler */
269 if (datalen < 78) {
270 return ASF_ERROR_INVALID_OBJECT_SIZE;
273 /* check that we really have a stream properties object */
274 GetGUID(data, &guid);
275 if (asf_guid_get_type(&guid) != GUID_STREAM_PROPERTIES) {
276 return ASF_ERROR_INVALID_OBJECT;
278 if (GetQWLE(data + 16) != datalen) {
279 return ASF_ERROR_INVALID_OBJECT_SIZE;
282 flags = GetWLE(data + 72);
284 if ((flags & 0x7f) != ext.stream_num || stream->type) {
285 /* only one stream object per stream allowed and
286 * stream ids have to match with both objects*/
287 return ASF_ERROR_INVALID_OBJECT;
288 } else {
289 int ret;
291 stream->flags |= ASF_STREAM_FLAG_HIDDEN;
292 ret = asf_parse_header_stream_properties(stream,
293 data + 24,
294 datalen);
296 if (ret < 0) {
297 return ret;
302 stream->extended_properties = malloc(sizeof(asf_stream_extended_properties_t));
303 if (!stream->extended_properties) {
304 return ASF_ERROR_OUTOFMEM;
306 stream->flags |= ASF_STREAM_FLAG_EXTENDED;
307 memcpy(stream->extended_properties, &ext, sizeof(ext));
309 return 0;
313 * Reads the file properties object contents to the asf_file_t structure,
314 * parses the useful values from stream properties object to the equivalent
315 * stream properties info structure and validates that all known header
316 * subobjects have only legal values.
319 asf_parse_header_validate(asf_file_t *file, asf_object_header_t *header)
321 /* some flags for mandatory subobjects */
322 int fileprop = 0, streamprop = 0;
323 asfint_object_t *current;
325 if (header->first) {
326 current = header->first;
327 while (current) {
328 uint64_t size = current->size;
330 switch (current->type) {
331 case GUID_FILE_PROPERTIES:
333 uint32_t max_packet_size;
334 if (size < 104)
335 return ASF_ERROR_INVALID_OBJECT_SIZE;
337 if (fileprop) {
338 /* multiple file properties objects not allowed */
339 return ASF_ERROR_INVALID_OBJECT;
342 fileprop = 1;
343 GetGUID(current->data, &file->file_id);
344 file->file_size = GetQWLE(current->data + 16);
345 file->creation_date = GetQWLE(current->data + 24);
346 file->data_packets_count = GetQWLE(current->data + 32);
347 file->play_duration = GetQWLE(current->data + 40);
348 file->send_duration = GetQWLE(current->data + 48);
349 file->preroll = GetQWLE(current->data + 56);
350 file->flags = GetDWLE(current->data + 64);
351 file->packet_size = GetDWLE(current->data + 68);
352 file->max_bitrate = GetQWLE(current->data + 76);
354 max_packet_size = GetDWLE(current->data + 72);
355 if (file->packet_size != max_packet_size) {
356 /* in ASF file minimum packet size and maximum
357 * packet size have to be same apparently...
358 * stupid, eh? */
359 return ASF_ERROR_INVALID_VALUE;
361 break;
363 case GUID_STREAM_PROPERTIES:
365 uint16_t flags;
366 asf_stream_t *stream;
367 int ret;
369 if (size < 78)
370 return ASF_ERROR_INVALID_OBJECT_SIZE;
372 streamprop = 1;
373 flags = GetWLE(current->data + 48);
374 stream = &file->streams[flags & 0x7f];
376 if (stream->type) {
377 /* only one stream object per stream allowed */
378 return ASF_ERROR_INVALID_OBJECT;
381 ret = asf_parse_header_stream_properties(stream,
382 current->data,
383 size);
385 if (ret < 0) {
386 return ret;
388 break;
390 case GUID_CONTENT_DESCRIPTION:
392 uint32_t stringlen = 0;
394 if (size < 34)
395 return ASF_ERROR_INVALID_OBJECT_SIZE;
397 stringlen += GetWLE(current->data);
398 stringlen += GetWLE(current->data + 2);
399 stringlen += GetWLE(current->data + 4);
400 stringlen += GetWLE(current->data + 6);
401 stringlen += GetWLE(current->data + 8);
403 if (size < stringlen + 34) {
404 /* invalid string length values */
405 return ASF_ERROR_INVALID_LENGTH;
407 break;
409 case GUID_MARKER:
410 break;
411 case GUID_CODEC_LIST:
412 if (size < 44)
413 return ASF_ERROR_INVALID_OBJECT_SIZE;
414 break;
415 case GUID_STREAM_BITRATE_PROPERTIES:
416 if (size < 26)
417 return ASF_ERROR_INVALID_OBJECT_SIZE;
418 break;
419 case GUID_PADDING:
420 break;
421 case GUID_EXTENDED_CONTENT_DESCRIPTION:
422 if (size < 26)
423 return ASF_ERROR_INVALID_OBJECT_SIZE;
424 break;
425 case GUID_UNKNOWN:
426 /* unknown guid type */
427 break;
428 default:
429 /* identified type in wrong place */
430 return ASF_ERROR_INVALID_OBJECT;
433 current = current->next;
437 if (header->ext) {
438 current = header->ext->first;
439 while (current) {
440 uint64_t size = current->size;
442 switch (current->type) {
443 case GUID_METADATA:
444 if (size < 26)
445 return ASF_ERROR_INVALID_OBJECT_SIZE;
446 break;
447 case GUID_LANGUAGE_LIST:
448 if (size < 26)
449 return ASF_ERROR_INVALID_OBJECT_SIZE;
450 break;
451 case GUID_EXTENDED_STREAM_PROPERTIES:
453 uint16_t stream_num;
454 asf_stream_t *stream;
455 int ret;
457 if (size < 88)
458 return ASF_ERROR_INVALID_OBJECT_SIZE;
460 stream_num = GetWLE(current->data + 48);
461 stream = &file->streams[stream_num];
463 ret = asf_parse_header_extended_stream_properties(stream,
464 current->data,
465 size);
467 if (ret < 0) {
468 return ret;
470 break;
472 case GUID_ADVANCED_MUTUAL_EXCLUSION:
473 if (size < 42)
474 return ASF_ERROR_INVALID_OBJECT_SIZE;
475 break;
476 case GUID_STREAM_PRIORITIZATION:
477 if (size < 26)
478 return ASF_ERROR_INVALID_OBJECT_SIZE;
479 break;
480 case GUID_UNKNOWN:
481 /* unknown guid type */
482 break;
483 default:
484 /* identified type in wrong place */
485 break;
488 current = current->next;
492 if (!fileprop || !streamprop || !header->ext) {
493 /* mandatory subobject missing */
494 return ASF_ERROR_INVALID_OBJECT;
497 return 1;
501 * Destroy the header and all subobjects
503 void
504 asf_free_header(asf_object_header_t *header)
506 if (!header)
507 return;
509 if (header->first) {
510 asfint_object_t *current = header->first, *next;
511 while (current) {
512 next = current->next;
513 free(current);
514 current = next;
518 if (header->ext) {
519 asfint_object_t *current = header->ext->first, *next;
520 while (current) {
521 next = current->next;
522 free(current);
523 current = next;
526 free(header->data);
527 free(header->ext);
528 free(header);
532 * Allocates a metadata struct and parses the contents from
533 * the header object raw data. All strings are in UTF-8 encoded
534 * format. The returned struct needs to be freed using the
535 * asf_header_metadata_destroy function. Returns NULL on failure.
537 asf_metadata_t *
538 asf_header_metadata(asf_object_header_t *header)
540 asfint_object_t *current;
541 asf_metadata_t *ret;
543 /* allocate the metadata struct */
544 ret = calloc(1, sizeof(asf_metadata_t));
545 if (!ret) {
546 return NULL;
549 current = asf_header_get_object(header, GUID_CONTENT_DESCRIPTION);
550 if (current) {
551 char *str;
552 uint16_t strlen;
553 int i, read = 0;
555 /* The validity of the object is already checked so we can assume
556 * there's always enough data to read and there are no overflows */
557 for (i=0; i<5; i++) {
558 strlen = GetWLE(current->data + i*2);
559 if (!strlen)
560 continue;
562 str = asf_utf8_from_utf16le(current->data + 10 + read, strlen);
563 read += strlen;
565 switch (i) {
566 case 0:
567 ret->title = str;
568 break;
569 case 1:
570 ret->artist = str;
571 break;
572 case 2:
573 ret->copyright = str;
574 break;
575 case 3:
576 ret->description = str;
577 break;
578 case 4:
579 ret->rating = str;
580 break;
581 default:
582 free(str);
583 break;
588 current = asf_header_get_object(header, GUID_EXTENDED_CONTENT_DESCRIPTION);
589 if (current) {
590 int i, j, position;
592 ret->extended_count = GetWLE(current->data);
593 ret->extended = calloc(ret->extended_count, sizeof(asf_metadata_entry_t));
594 if (!ret->extended) {
595 /* Clean up the already allocated parts and return */
596 free(ret->title);
597 free(ret->artist);
598 free(ret->copyright);
599 free(ret->description);
600 free(ret->rating);
601 free(ret);
603 return NULL;
606 position = 2;
607 for (i=0; i<ret->extended_count; i++) {
608 uint16_t length, type;
610 length = GetWLE(current->data + position);
611 position += 2;
613 ret->extended[i].key = asf_utf8_from_utf16le(current->data + position, length);
614 position += length;
616 type = GetWLE(current->data + position);
617 position += 2;
619 length = GetWLE(current->data + position);
620 position += 2;
622 switch (type) {
623 case 0:
624 /* type of the value is a string */
625 ret->extended[i].value = asf_utf8_from_utf16le(current->data + position, length);
626 break;
627 case 1:
628 /* type of the value is a data block */
629 ret->extended[i].value = malloc((length*2 + 1) * sizeof(char));
630 for (j=0; j<length; j++) {
631 static const char hex[16] = "0123456789ABCDEF";
632 ret->extended[i].value[j*2+0] = hex[current->data[position]>>4];
633 ret->extended[i].value[j*2+1] = hex[current->data[position]&0x0f];
635 ret->extended[i].value[j*2] = '\0';
636 break;
637 case 2:
638 /* type of the value is a boolean */
639 ret->extended[i].value = malloc(6 * sizeof(char));
640 sprintf(ret->extended[i].value, "%s",
641 *current->data ? "true" : "false");
642 break;
643 case 3:
644 /* type of the value is a signed 32-bit integer */
645 ret->extended[i].value = malloc(11 * sizeof(char));
646 sprintf(ret->extended[i].value, "%u",
647 GetDWLE(current->data + position));
648 break;
649 case 4:
650 /* FIXME: This doesn't print whole 64-bit integer */
651 ret->extended[i].value = malloc(21 * sizeof(char));
652 sprintf(ret->extended[i].value, "%u",
653 (uint32_t) GetQWLE(current->data + position));
654 break;
655 case 5:
656 /* type of the value is a signed 16-bit integer */
657 ret->extended[i].value = malloc(6 * sizeof(char));
658 sprintf(ret->extended[i].value, "%u",
659 GetWLE(current->data + position));
660 break;
661 default:
662 /* Unknown value type... */
663 ret->extended[i].value = NULL;
664 break;
666 position += length;
670 return ret;
674 * Free the metadata struct and all fields it includes
676 void
677 asf_header_free_metadata(asf_metadata_t *metadata)
679 int i;
681 free(metadata->title);
682 free(metadata->artist);
683 free(metadata->copyright);
684 free(metadata->description);
685 free(metadata->rating);
686 for (i=0; i<metadata->extended_count; i++) {
687 free(metadata->extended[i].key);
688 free(metadata->extended[i].value);
690 free(metadata->extended);
691 free(metadata);