changeset 5984:55c714a8fb00 libavformat

Make the IFF demuxer a little more standards-compliant, e.g. respect the size fields of common media header chunks (these can have different sizes depending on the type of IFF file you read), better handle odd sizes (like RIFF, every field is padded to word) and handle headerchunks after the BODY chunk. Patch by Sebastian Vater <cdgs.basty googlemail com>.
author rbultje
date Tue, 27 Apr 2010 14:03:47 +0000
parents cb7e1e218016
children 35c3858d457f
files iff.c
diffstat 1 files changed, 23 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/iff.c	Mon Apr 26 22:36:51 2010 +0000
+++ b/iff.c	Tue Apr 27 14:03:47 2010 +0000
@@ -2,6 +2,7 @@
  * IFF (.iff) file demuxer
  * Copyright (c) 2008 Jaikrishnan Menon <realityman@gmx.net>
  * Copyright (c) 2010 Peter Ross <pross@xvid.org>
+ * Copyright (c) 2010 Sebastian Vater <cdgs.basty@googlemail.com>
  *
  * This file is part of FFmpeg.
  *
@@ -72,6 +73,7 @@
 } bitmap_compression_type;
 
 typedef struct {
+    uint64_t  body_pos;
     uint32_t  body_size;
     uint32_t  sent_bytes;
     uint32_t  audio_frame_count;
@@ -107,7 +109,6 @@
     ByteIOContext *pb = s->pb;
     AVStream *st;
     uint32_t chunk_id, data_size;
-    int padding, done = 0;
     int compression = -1;
     char *buf;
 
@@ -120,27 +121,34 @@
     // codec_tag used by ByteRun1 decoder to distinguish progressive (PBM) and interlaced (ILBM) content
     st->codec->codec_tag = get_le32(pb);
 
-    while(!done && !url_feof(pb)) {
+    while(!url_feof(pb)) {
+        uint64_t orig_pos;
         chunk_id = get_le32(pb);
         data_size = get_be32(pb);
-        padding = data_size & 1;
+        orig_pos = url_ftell(pb);
 
         switch(chunk_id) {
         case ID_VHDR:
             st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+
+            if (data_size < 14)
+                return AVERROR_INVALIDDATA;
             url_fskip(pb, 12);
             st->codec->sample_rate = get_be16(pb);
+            if (data_size >= 16) {
             url_fskip(pb, 1);
             compression            = get_byte(pb);
-            url_fskip(pb, 4);
+            }
             break;
 
         case ID_BODY:
+            iff->body_pos = url_ftell(pb);
             iff->body_size = data_size;
-            done = 1;
             break;
 
         case ID_CHAN:
+            if (data_size < 4)
+                return AVERROR_INVALIDDATA;
             st->codec->channels = (get_be32(pb) < 6) ? 1 : 2;
             break;
 
@@ -155,16 +163,21 @@
 
         case ID_BMHD:
             st->codec->codec_type            = AVMEDIA_TYPE_VIDEO;
+            if (data_size <= 8)
+                return AVERROR_INVALIDDATA;
             st->codec->width                 = get_be16(pb);
             st->codec->height                = get_be16(pb);
             url_fskip(pb, 4); // x, y offset
             st->codec->bits_per_coded_sample = get_byte(pb);
+            if (data_size >= 11) {
             url_fskip(pb, 1); // masking
             compression                      = get_byte(pb);
+            }
+            if (data_size >= 16) {
             url_fskip(pb, 3); // paddding, transparent
             st->sample_aspect_ratio.num      = get_byte(pb);
             st->sample_aspect_ratio.den      = get_byte(pb);
-            url_fskip(pb, 4); // source page width, height
+            }
             break;
 
         case ID_ANNO:
@@ -175,13 +188,13 @@
             buf[data_size] = 0;
             av_metadata_set2(&s->metadata, "comment", buf, AV_METADATA_DONT_STRDUP_VAL);
             break;
+        }
 
-        default:
-            url_fseek(pb, data_size + padding, SEEK_CUR);
-            break;
-        }
+        url_fskip(pb, data_size - (url_ftell(pb) - orig_pos) + (data_size & 1));
     }
 
+    url_fseek(pb, iff->body_pos, SEEK_SET);
+
     switch(st->codec->codec_type) {
     case AVMEDIA_TYPE_AUDIO:
         av_set_pts_info(st, 32, 1, st->codec->sample_rate);