music_mad.c: Initial work to skip Lyrics3 v1 / v2 tags.
authorOzkan Sezer
Sun, 08 Dec 2019 10:20:40 +0300
changeset 10644af81ffd6909
parent 1062 bee60e95153e
child 1065 58707cd78f95
music_mad.c: Initial work to skip Lyrics3 v1 / v2 tags.

Based on specs from http://id3.org/Lyrics3 and http://id3.org/Lyrics3v2
src/codecs/music_mad.c
     1.1 --- a/src/codecs/music_mad.c	Sat Dec 07 14:51:10 2019 +0300
     1.2 +++ b/src/codecs/music_mad.c	Sun Dec 08 10:20:40 2019 +0300
     1.3 @@ -303,6 +303,42 @@
     1.4      if (version == 2000U && (flags & (1U<<31))) size += 32; /* header present. */
     1.5      return size;
     1.6  }
     1.7 +static SDL_INLINE int is_lyrics3tag(const unsigned char *data, long length) {
     1.8 +    /* http://id3.org/Lyrics3
     1.9 +     * http://id3.org/Lyrics3v2 */
    1.10 +    if (length < 15) return 0;
    1.11 +    if (SDL_memcmp(data+6,"LYRICS200",9) == 0) return 2; /* v2 */
    1.12 +    if (SDL_memcmp(data+6,"LYRICSEND",9) == 0) return 1; /* v1 */
    1.13 +    return 0;
    1.14 +}
    1.15 +static SDL_INLINE long get_lyrics3v1_len(MAD_Music *m) {
    1.16 +    const char *p; long i, len;
    1.17 +    /* needs manual search:  http://id3.org/Lyrics3 */
    1.18 +    /* this relies on the input_buffer size >= 5100 */
    1.19 +    if (m->length < 20) return -1;
    1.20 +    len = (m->length > 5109)? 5109 : (long)m->length;
    1.21 +    MAD_RWseek(m, -len, RW_SEEK_END);
    1.22 +    MAD_RWread(m, m->input_buffer, 1, (len -= 9)); /* exclude footer */
    1.23 +    MAD_RWseek(m, 0, RW_SEEK_SET);
    1.24 +    /* strstr() won't work here. */
    1.25 +    for (i = len - 11, p = (const char*)m->input_buffer; i >= 0; --i, ++p) {
    1.26 +        if (SDL_memcmp(p, "LYRICSBEGIN", 11) == 0)
    1.27 +            break;
    1.28 +    }
    1.29 +    if (i < 0) return -1;
    1.30 +    return len - (long)(p - (const char*)m->input_buffer) + 9 /* footer */;
    1.31 +}
    1.32 +static SDL_INLINE long get_lyrics3v2_len(const unsigned char *data, long length) {
    1.33 +    /* 6 bytes before the end marker is size in decimal format -
    1.34 +     * does not include the 9 bytes end marker and size field. */
    1.35 +    if (length != 6) return 0;
    1.36 +    return SDL_strtol((const char *)data, NULL, 10) + 15;
    1.37 +}
    1.38 +static SDL_INLINE SDL_bool verify_lyrics3v2(const unsigned char *data, long length) {
    1.39 +    if (length < 11) return SDL_FALSE;
    1.40 +    if (SDL_memcmp(data,"LYRICSBEGIN",11) == 0) return SDL_TRUE;
    1.41 +    return SDL_FALSE;
    1.42 +}
    1.43  
    1.44  static int skip_tags(MAD_Music *music)
    1.45  {
    1.46 @@ -341,9 +377,8 @@
    1.47          /* FIXME: handle possible double-ID3v1 tags?? */
    1.48      }
    1.49  
    1.50 -    /* FIXME: handle Lyrics3 tags?
    1.51 -     * http://id3.org/Lyrics3
    1.52 -     * http://id3.org/Lyrics3v2 */
    1.53 +    /* do we know whether ape or lyrics3 is the first?
    1.54 +     * well, we don't: we need to handle that later... */
    1.55  
    1.56      ape: /* APE tag may be at the end: read the footer */
    1.57      if (music->length >= 32) {
    1.58 @@ -358,6 +393,30 @@
    1.59          }
    1.60      }
    1.61  
    1.62 +    if (music->length >= 15) {
    1.63 +        MAD_RWseek(music, -15, RW_SEEK_END);
    1.64 +        readsize = MAD_RWread(music, music->input_buffer, 1, 15);
    1.65 +        MAD_RWseek(music, 0, RW_SEEK_SET);
    1.66 +        if (readsize != 15) return -1;
    1.67 +        len = is_lyrics3tag(music->input_buffer, 15);
    1.68 +        if (len == 2) {
    1.69 +            len = get_lyrics3v2_len(music->input_buffer, 6);
    1.70 +            if (len >= music->length) return -1;
    1.71 +            if (len < 15) return -1;
    1.72 +            MAD_RWseek(music, -len, RW_SEEK_END);
    1.73 +            readsize = MAD_RWread(music, music->input_buffer, 1, 11);
    1.74 +            MAD_RWseek(music, 0, RW_SEEK_SET);
    1.75 +            if (readsize != 11) return -1;
    1.76 +            if (!verify_lyrics3v2(music->input_buffer, 11)) return -1;
    1.77 +            music->length -= len;
    1.78 +        }
    1.79 +        else if (len == 1) {
    1.80 +            len = get_lyrics3v1_len(music);
    1.81 +            if (len < 0) return -1;
    1.82 +            music->length -= len;
    1.83 +        }
    1.84 +    }
    1.85 +
    1.86      return (music->length > 0)? 0: -1;
    1.87  }
    1.88