mp3_skiptags: let it consume all the tags at file end (bug #4907): SDL-1.2
authorOzkan Sezer
Fri, 20 Dec 2019 15:55:00 +0300
branchSDL-1.2
changeset 1104d9a665f67ce0
parent 1082 83da6758753b
child 1110 0d4f21a5b678
mp3_skiptags: let it consume all the tags at file end (bug #4907):

[backport from default/2.0 commit 4e1c2282e6f1]

We do not know the order of ape, or lyrics3, or musicmatch tags,
so we loop until we consume all, scanning for each tag type once.
I don't yet care about freaky broken mp3 files with double tags.

<rant> MP3 standard has no metadata format, so everyone invented
their own thing, even with extensions, until ID3v2 became dominant:
Hence the impossible mess there.</rant>

Also remove inline directive from a few detection procedures there.
mp3utils.c
     1.1 --- a/mp3utils.c	Sat Dec 14 18:21:50 2019 +0300
     1.2 +++ b/mp3utils.c	Fri Dec 20 15:55:00 2019 +0300
     1.3 @@ -1,6 +1,6 @@
     1.4  /*
     1.5    SDL_mixer:  An audio mixer library based on the SDL library
     1.6 -  Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
     1.7 +  Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
     1.8  
     1.9    This software is provided 'as-is', without any express or implied
    1.10    warranty.  In no event will the authors be held liable for any damages
    1.11 @@ -68,7 +68,7 @@
    1.12      }
    1.13      return SDL_TRUE;
    1.14  }
    1.15 -static __inline__ SDL_bool is_id3v2(const unsigned char *data, int length)
    1.16 +static SDL_bool is_id3v2(const unsigned char *data, int length)
    1.17  {
    1.18      /* ID3v2 header is 10 bytes:  http://id3.org/id3v2.4.0-structure */
    1.19      /* bytes 0-2: "ID3" identifier */
    1.20 @@ -87,7 +87,7 @@
    1.21      }
    1.22      return SDL_TRUE;
    1.23  }
    1.24 -static __inline__ int get_id3v2_len(const unsigned char *data, int length)
    1.25 +static int get_id3v2_len(const unsigned char *data, int length)
    1.26  {
    1.27      /* size is a 'synchsafe' integer (see above) */
    1.28      int size = (int)((data[6]<<21) + (data[7]<<14) + (data[8]<<7) + data[9]);
    1.29 @@ -104,7 +104,7 @@
    1.30      }
    1.31      return size;
    1.32  }
    1.33 -static __inline__ SDL_bool is_apetag(const unsigned char *data, int length)
    1.34 +static SDL_bool is_apetag(const unsigned char *data, int length)
    1.35  {
    1.36     /* http://wiki.hydrogenaud.io/index.php?title=APEv2_specification
    1.37      * Header/footer is 32 bytes: bytes 0-7 ident, bytes 8-11 version,
    1.38 @@ -124,7 +124,7 @@
    1.39      }
    1.40      return SDL_TRUE;
    1.41  }
    1.42 -static __inline__ int get_ape_len(const unsigned char *data)
    1.43 +static int get_ape_len(const unsigned char *data)
    1.44  {
    1.45      Uint32 flags, version;
    1.46      int size = (int)((data[15]<<24) | (data[14]<<16) | (data[13]<<8) | data[12]);
    1.47 @@ -141,7 +141,7 @@
    1.48      if (SDL_memcmp(data+6,"LYRICSEND",9) == 0) return 1; /* v1 */
    1.49      return 0;
    1.50  }
    1.51 -static __inline__ int get_lyrics3v1_len(struct mp3file_t *m) {
    1.52 +static int get_lyrics3v1_len(struct mp3file_t *m) {
    1.53      const char *p; int i, len;
    1.54      char buf[5104];
    1.55      /* needs manual search:  http://id3.org/Lyrics3 */
    1.56 @@ -163,13 +163,13 @@
    1.57      if (length != 6) return 0;
    1.58      return SDL_strtol((const char *)data, NULL, 10) + 15;
    1.59  }
    1.60 -static __inline__ SDL_bool verify_lyrics3v2(const unsigned char *data, int length) {
    1.61 +static SDL_bool verify_lyrics3v2(const unsigned char *data, int length) {
    1.62      if (length < 11) return SDL_FALSE;
    1.63      if (SDL_memcmp(data,"LYRICSBEGIN",11) == 0) return SDL_TRUE;
    1.64      return SDL_FALSE;
    1.65  }
    1.66  #define MMTAG_PARANOID
    1.67 -static __inline__ SDL_bool is_musicmatch(const unsigned char *data, int length) {
    1.68 +static SDL_bool is_musicmatch(const unsigned char *data, int length) {
    1.69    /* From docs/musicmatch.txt in id3lib: https://sourceforge.net/projects/id3lib/
    1.70       Overall tag structure:
    1.71  
    1.72 @@ -212,7 +212,7 @@
    1.73      #endif
    1.74      return SDL_TRUE;
    1.75  }
    1.76 -static __inline__ int get_musicmatch_len(struct mp3file_t *m) {
    1.77 +static int get_musicmatch_len(struct mp3file_t *m) {
    1.78      const Sint32 metasizes[4] = { 7868, 7936, 8004, 8132 };
    1.79      const unsigned char syncstr[10] = {'1','8','2','7','3','6','4','5',0,0};
    1.80      unsigned char buf[256];
    1.81 @@ -279,12 +279,90 @@
    1.82      return len + 256; /* header is present. */
    1.83  }
    1.84  
    1.85 +static int probe_id3v1(struct mp3file_t *fil, unsigned char *buf) {
    1.86 +    if (fil->length >= 128) {
    1.87 +        MP3_RWseek(fil, -128, RW_SEEK_END);
    1.88 +        if (MP3_RWread(fil, buf, 1, 128) != 128)
    1.89 +            return -1;
    1.90 +        if (is_id3v1(buf, 128)) {
    1.91 +            fil->length -= 128;
    1.92 +            return 1;
    1.93 +            /* FIXME: handle possible double-ID3v1 tags?? */
    1.94 +        }
    1.95 +    }
    1.96 +    return 0;
    1.97 +}
    1.98 +static int probe_mmtag(struct mp3file_t *fil, unsigned char *buf) {
    1.99 +    int len;
   1.100 +    if (fil->length >= 68) {
   1.101 +        MP3_RWseek(fil, -48, RW_SEEK_END);
   1.102 +        if (MP3_RWread(fil, buf, 1, 48) != 48)
   1.103 +            return -1;
   1.104 +        if (is_musicmatch(buf, 48)) {
   1.105 +            len = get_musicmatch_len(fil);
   1.106 +            if (len < 0) return -1;
   1.107 +            if (len >= fil->length) return -1;
   1.108 +            fil->length -= len;
   1.109 +            return 1;
   1.110 +        }
   1.111 +    }
   1.112 +    return 0;
   1.113 +}
   1.114 +static int probe_apetag(struct mp3file_t *fil, unsigned char *buf) {
   1.115 +    int len;
   1.116 +    if (fil->length >= 32) {
   1.117 +        MP3_RWseek(fil, -32, RW_SEEK_END);
   1.118 +        if (MP3_RWread(fil, buf, 1, 32) != 32)
   1.119 +            return -1;
   1.120 +        if (is_apetag(buf, 32)) {
   1.121 +            len = get_ape_len(buf);
   1.122 +            if (len >= fil->length) return -1;
   1.123 +            fil->length -= len;
   1.124 +            return 1;
   1.125 +        }
   1.126 +    }
   1.127 +    return 0;
   1.128 +}
   1.129 +static int probe_lyrics3(struct mp3file_t *fil, unsigned char *buf) {
   1.130 +    int len;
   1.131 +    if (fil->length >= 15) {
   1.132 +        MP3_RWseek(fil, -15, RW_SEEK_END);
   1.133 +        if (MP3_RWread(fil, buf, 1, 15) != 15)
   1.134 +            return -1;
   1.135 +        len = is_lyrics3tag(buf, 15);
   1.136 +        if (len == 2) {
   1.137 +            len = get_lyrics3v2_len(buf, 6);
   1.138 +            if (len >= fil->length) return -1;
   1.139 +            if (len < 15) return -1;
   1.140 +            MP3_RWseek(fil, -len, RW_SEEK_END);
   1.141 +            if (MP3_RWread(fil, buf, 1, 11)!= 11)
   1.142 +                return -1;
   1.143 +            if (!verify_lyrics3v2(buf, 11)) return -1;
   1.144 +            fil->length -= len;
   1.145 +            return 1;
   1.146 +        }
   1.147 +        else if (len == 1) {
   1.148 +            len = get_lyrics3v1_len(fil);
   1.149 +            if (len < 0) return -1;
   1.150 +            fil->length -= len;
   1.151 +            return 1;
   1.152 +        }
   1.153 +    }
   1.154 +    return 0;
   1.155 +}
   1.156 +
   1.157  int mp3_skiptags(struct mp3file_t *fil)
   1.158  {
   1.159      unsigned char buf[128];
   1.160      int len, readsize;
   1.161 +    int c_id3, c_ape, c_lyr, c_mm;
   1.162      int rc = -1;
   1.163  
   1.164 +    /* MP3 standard has no metadata format, so everyone invented
   1.165 +     * their own thing, even with extensions, until ID3v2 became
   1.166 +     * dominant: Hence the impossible mess here.
   1.167 +     */
   1.168 +
   1.169      readsize = MP3_RWread(fil, buf, 1, 128);
   1.170      if (readsize <= 0) goto fail;
   1.171  
   1.172 @@ -304,71 +382,44 @@
   1.173          fil->length -= len;
   1.174      }
   1.175  
   1.176 -    /* ID3v1 tag is at the end */
   1.177 -    if (fil->length >= 128) {
   1.178 -        MP3_RWseek(fil, -128, RW_SEEK_END);
   1.179 -        readsize = MP3_RWread(fil, buf, 1, 128);
   1.180 -        if (readsize != 128) goto fail;
   1.181 -        if (is_id3v1(buf, 128)) {
   1.182 -            fil->length -= 128;
   1.183 -            /* FIXME: handle possible double-ID3v1 tags?? */
   1.184 -        }
   1.185 +    /* it's not impossible that _old_ MusicMatch tag
   1.186 +     * placing itself after ID3v1. */
   1.187 +    if ((c_mm = probe_mmtag(fil, buf)) < 0) {
   1.188 +        goto fail;
   1.189      }
   1.190 -
   1.191 -    /* do we know whether ape or lyrics3 is the first?
   1.192 -     * well, we don't: we need to handle that later... */
   1.193 -
   1.194 -    /* check for the _old_ MusicMatch tag at end. */
   1.195 -    if (fil->length >= 68) {
   1.196 -        MP3_RWseek(fil, -48, RW_SEEK_END);
   1.197 -        readsize = MP3_RWread(fil, buf, 1, 48);
   1.198 -        if (readsize != 48) goto fail;
   1.199 -        if (is_musicmatch(buf, 48)) {
   1.200 -            len = get_musicmatch_len(fil);
   1.201 -            if (len < 0) goto fail;
   1.202 -            if (len >= fil->length) goto fail;
   1.203 -            fil->length -= len;
   1.204 -        }
   1.205 +    /* ID3v1 tag is at the end */
   1.206 +    if ((c_id3 = probe_id3v1(fil, buf)) < 0) {
   1.207 +        goto fail;
   1.208      }
   1.209 -
   1.210 -    /* APE tag may be at the end: read the footer */
   1.211 -    if (fil->length >= 32) {
   1.212 -        MP3_RWseek(fil, -32, RW_SEEK_END);
   1.213 -        readsize = MP3_RWread(fil, buf, 1, 32);
   1.214 -        if (readsize != 32) goto fail;
   1.215 -        if (is_apetag(buf, 32)) {
   1.216 -            len = get_ape_len(buf);
   1.217 -            if (len >= fil->length) goto fail;
   1.218 -            fil->length -= len;
   1.219 +    /* we do not know the order of ape or lyrics3
   1.220 +     * or musicmatch tags, hence the loop here.. */
   1.221 +    c_ape = 0;
   1.222 +    c_lyr = 0;
   1.223 +    for (;;) {
   1.224 +        if (!c_lyr) {
   1.225 +        /* care about mp3s with double Lyrics3 tags? */
   1.226 +            if ((c_lyr = probe_lyrics3(fil, buf)) < 0)
   1.227 +                goto fail;
   1.228 +            if (c_lyr) continue;
   1.229          }
   1.230 -    }
   1.231 -
   1.232 -    if (fil->length >= 15) {
   1.233 -        MP3_RWseek(fil, -15, RW_SEEK_END);
   1.234 -        readsize = MP3_RWread(fil, buf, 1, 15);
   1.235 -        if (readsize != 15) goto fail;
   1.236 -        len = is_lyrics3tag(buf, 15);
   1.237 -        if (len == 2) {
   1.238 -            len = get_lyrics3v2_len(buf, 6);
   1.239 -            if (len >= fil->length) goto fail;
   1.240 -            if (len < 15) goto fail;
   1.241 -            MP3_RWseek(fil, -len, RW_SEEK_END);
   1.242 -            readsize = MP3_RWread(fil, buf, 1, 11);
   1.243 -            if (readsize != 11) goto fail;
   1.244 -            if (!verify_lyrics3v2(buf, 11)) goto fail;
   1.245 -            fil->length -= len;
   1.246 +        if (!c_mm) {
   1.247 +            if ((c_mm = probe_mmtag(fil, buf)) < 0)
   1.248 +                goto fail;
   1.249 +            if (c_mm) continue;
   1.250          }
   1.251 -        else if (len == 1) {
   1.252 -            len = get_lyrics3v1_len(fil);
   1.253 -            if (len < 0) goto fail;
   1.254 -            fil->length -= len;
   1.255 +        if (!c_ape) {
   1.256 +            if ((c_ape = probe_apetag(fil, buf)) < 0)
   1.257 +                goto fail;
   1.258 +            if (c_ape) continue;
   1.259          }
   1.260 -    }
   1.261 +        break;
   1.262 +    } /* for (;;) */
   1.263  
   1.264      rc = (fil->length > 0)? 0 : -1;
   1.265      fail:
   1.266      MP3_RWseek(fil, 0, RW_SEEK_SET);
   1.267      return rc;
   1.268  }
   1.269 +#endif /* MP3_???_MUSIC */
   1.270  
   1.271 -#endif /* MP3_???_MUSIC */
   1.272 +/* vi: set ts=4 sw=4 expandtab: */