From a2ae6f8f8b0204145be9a6da08bad8a0899ed300 Mon Sep 17 00:00:00 2001
From: Hans de Goede <j.w.r.degoede@gmail.com>
Date: Thu, 1 May 2014 20:56:48 +0200
Subject: [PATCH] libaudtag: Verify tag length info against decoder length

Some mp3 files have wrong TLEN tags, one example is:
http://ia700209.us.archive.org/0/items/freemusiccharts.songs2010/2010-08-garmisch-glimmeralbumVersion.mp3

Which has an extremely wrong TLEN tag, but I've also seen mp3 files where
TLEN is set the album length instead of the track length.

To stop audacious from showing a completely wrong length in these cases add
some FIELD_LENGTH sanity checks. This fixes both issues for me.
---
 src/libaudtag/id3/id3-common.c | 21 +++++++++++++++++++++
 src/libaudtag/id3/id3-common.h |  1 +
 src/libaudtag/id3/id3v22.c     |  2 +-
 src/libaudtag/id3/id3v24.c     |  2 +-
 4 files changed, 24 insertions(+), 2 deletions(-)

diff --git a/src/libaudtag/id3/id3-common.c b/src/libaudtag/id3/id3-common.c
index 2a8a87e..f482c49 100644
--- a/src/libaudtag/id3/id3-common.c
+++ b/src/libaudtag/id3/id3-common.c
@@ -114,6 +114,27 @@ void id3_associate_int (Tuple * tuple, int field, const char * data, int size)
     str_unref (text);
 }
 
+/* associate_int for FIELD_LENGTH which sanity checks the length */
+void id3_associate_length (Tuple * tuple, const char * data, int size)
+{
+    char * text = id3_decode_text (data, size);
+    int decoder_length, tag_length;
+
+    if (text && atoi (text) >= 0) {
+	    decoder_length = tuple_get_int (tuple, FIELD_LENGTH);
+	    tag_length = atoi (text);
+
+	    /* If the decoder has already set an (approximate) length, use it to
+	     * verify the length from the tag, as that is sometimes bogus */
+	    if (decoder_length <= 0 ||
+		    (tag_length > (decoder_length / 2) &&
+		     tag_length < (decoder_length * 2)))
+                tuple_set_int (tuple, FIELD_LENGTH, atoi (text));
+    }
+
+    str_unref (text);
+}
+
 void id3_decode_genre (Tuple * tuple, const char * data, int size)
 {
     char * text = id3_decode_text (data, size);
diff --git a/src/libaudtag/id3/id3-common.h b/src/libaudtag/id3/id3-common.h
index 1b100ab..893f4dd 100644
--- a/src/libaudtag/id3/id3-common.h
+++ b/src/libaudtag/id3/id3-common.h
@@ -25,6 +25,7 @@
 
 void id3_associate_string (Tuple * tuple, int field, const char * data, int size);
 void id3_associate_int (Tuple * tuple, int field, const char * data, int size);
+void id3_associate_length (Tuple * tuple, const char * data, int size);
 void id3_decode_genre (Tuple * tuple, const char * data, int size);
 void id3_decode_comment (Tuple * tuple, const char * data, int size);
 void id3_decode_rva (Tuple * tuple, const char * data, int size);
diff --git a/src/libaudtag/id3/id3v22.c b/src/libaudtag/id3/id3v22.c
index 7e886fd..caae55f 100644
--- a/src/libaudtag/id3/id3v22.c
+++ b/src/libaudtag/id3/id3v22.c
@@ -249,7 +249,7 @@ bool_t id3v22_read_tag (Tuple * tuple, VFSFile * handle)
             id3_associate_string (tuple, FIELD_DATE, data, size);
             break;
           case ID3_LENGTH:
-            id3_associate_int (tuple, FIELD_LENGTH, data, size);
+            id3_associate_length (tuple, data, size);
             break;
           case ID3_FUCKO_ARTIST:
           case ID3_ARTIST:
diff --git a/src/libaudtag/id3/id3v24.c b/src/libaudtag/id3/id3v24.c
index fac1a44..d413f4d 100644
--- a/src/libaudtag/id3/id3v24.c
+++ b/src/libaudtag/id3/id3v24.c
@@ -653,7 +653,7 @@ static bool_t id3v24_read_tag (Tuple * tuple, VFSFile * handle)
             id3_associate_string (tuple, FIELD_DATE, data, size);
             break;
           case ID3_LENGTH:
-            id3_associate_int (tuple, FIELD_LENGTH, data, size);
+            id3_associate_length (tuple, data, size);
             break;
           case ID3_ARTIST:
             id3_associate_string (tuple, FIELD_ARTIST, data, size);
-- 
1.9.0

