changeset 34631:fde6f34c5eb0

Detect ID3v2 tag at the end of the file and stop demuxing before its start. Avoids trying to decode its data as MP3. Patch by Benot Thbaudeau [benoit thebaudeau {} advansee com].
author reimar
date Mon, 13 Feb 2012 19:36:01 +0000
parents e50affe874a9
children e0c6b271d55b
files help/help_mp-en.h libmpdemux/demux_audio.c
diffstat 2 files changed, 53 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/help/help_mp-en.h	Mon Feb 13 19:33:48 2012 +0000
+++ b/help/help_mp-en.h	Mon Feb 13 19:36:01 2012 +0000
@@ -1470,6 +1470,8 @@
 #define MSGTR_MPDEMUX_AVIHDR_IdxFileSaved "Saved index file: %s\n"
 
 // demux_audio.c
+#define MSGTR_MPDEMUX_AUDIO_BadID3v2TagSize "Audio demuxer: bad ID3v2 tag size: larger than stream (%u).\n"
+#define MSGTR_MPDEMUX_AUDIO_DamagedAppendedID3v2Tag "Audio demuxer: damaged appended ID3v2 tag detected.\n"
 #define MSGTR_MPDEMUX_AUDIO_UnknownFormat "Audio demuxer: unknown format %d.\n"
 
 // demux_demuxers.c
--- a/libmpdemux/demux_audio.c	Mon Feb 13 19:33:48 2012 +0000
+++ b/libmpdemux/demux_audio.c	Mon Feb 13 19:36:01 2012 +0000
@@ -323,6 +323,34 @@
   return 0;
 }
 
+/**
+ * @brief Determine the total size of an ID3v2 tag.
+ *
+ * @param maj_ver major version of the ID3v2 tag
+ * @param s stream to be read, assumed to be positioned at revision byte
+ *
+ * @return 0 (error or malformed tag) or tag size
+ */
+static unsigned int id3v2_tag_size(uint8_t maj_ver, stream_t *s) {
+  unsigned int header_footer_size;
+  unsigned int size;
+  int i;
+
+  if(stream_read_char(s) == 0xff)
+    return 0;
+  header_footer_size = ((stream_read_char(s) & 0x10) && maj_ver >= 4) ? 20 : 10;
+
+  size = 0;
+  for(i = 0; i < 4; i++) {
+    uint8_t data = stream_read_char(s);
+    if (data & 0x80)
+      return 0;
+    size = size << 7 | data;
+  }
+
+  return header_footer_size + size;
+}
+
 static int demux_audio_open(demuxer_t* demuxer) {
   stream_t *s;
   sh_audio_t* sh_audio;
@@ -356,12 +384,10 @@
       // We found wav header. Now we can have 'fmt ' or a mp3 header
       // empty the buffer
 	step = 4;
-    } else if( hdr[0] == 'I' && hdr[1] == 'D' && hdr[2] == '3' && (hdr[3] >= 2)) {
-      int len;
-      stream_skip(s,2);
-      stream_read(s,hdr,4);
-      len = (hdr[0]<<21) | (hdr[1]<<14) | (hdr[2]<<7) | hdr[3];
-      stream_skip(s,len);
+    } else if( hdr[0] == 'I' && hdr[1] == 'D' && hdr[2] == '3' && hdr[3] >= 2 && hdr[3] != 0xff) {
+      unsigned int len = id3v2_tag_size(hdr[3], s);
+      if(len > 0)
+        stream_skip(s,len-10);
       step = 4;
     } else if( found_WAVE && hdr[0] == 'f' && hdr[1] == 'm' && hdr[2] == 't' && hdr[3] == ' ' ) {
       frmt = WAV;
@@ -444,6 +470,25 @@
 	g = stream_read_char(s);
 	demux_info_add(demuxer,"Genre",genres[g]);
       }
+      stream_seek(s,demuxer->movi_end-10);
+      stream_read(s,hdr,4);
+      if(!memcmp(hdr,"3DI",3) && hdr[3] >= 4 && hdr[3] != 0xff) {
+        unsigned int len = id3v2_tag_size(hdr[3], s);
+        if(len > 0) {
+          if(len > demuxer->movi_end - demuxer->movi_start) {
+            mp_msg(MSGT_DEMUX,MSGL_WARN,MSGTR_MPDEMUX_AUDIO_BadID3v2TagSize,len);
+            len = FFMIN(10,demuxer->movi_end-demuxer->movi_start);
+          } else {
+            stream_seek(s,demuxer->movi_end-len);
+            stream_read(s,hdr,4);
+            if(memcmp(hdr,"ID3",3) || hdr[3] < 4 || hdr[3] == 0xff || id3v2_tag_size(hdr[3], s) != len) {
+              mp_msg(MSGT_DEMUX,MSGL_WARN,MSGTR_MPDEMUX_AUDIO_DamagedAppendedID3v2Tag);
+              len = FFMIN(10,demuxer->movi_end-demuxer->movi_start);
+            }
+          }
+          demuxer->movi_end -= len;
+        }
+      }
     }
     if (duration && demuxer->movi_end && demuxer->movi_end > demuxer->movi_start) sh_audio->wf->nAvgBytesPerSec = (demuxer->movi_end - demuxer->movi_start) / duration;
     sh_audio->i_bps = sh_audio->wf->nAvgBytesPerSec;