From f179e83502b74e8880d885af54e942aab2776f3f Mon Sep 17 00:00:00 2001 From: Ozkan Sezer Date: Sat, 7 Dec 2019 14:10:02 +0300 Subject: [PATCH] music_mad.c: Tag detection fixes, updates and cleanups: - Fix APE header presence detection: APEv2 doesn't guarantee a header. We rely on bit31 of the flags field of the header/footer, instead. - Add a note that the 'Extended ID3v1' thingy is non-standard: we must not assume any additional tags before it. (should we drop support??) - The 'APE before ID3v1' is duplicated code (because we just return if we detect a TAG+ thingy): removed it. - Add a FIXME note about handling possible double-ID3v1 tags. - possibly a few minor tidy-ups. --- music_mad.c | 72 ++++++++++++++++++----------------------------------- 1 file changed, 24 insertions(+), 48 deletions(-) diff --git a/music_mad.c b/music_mad.c index 60e5bf03..0e626cd5 100644 --- a/music_mad.c +++ b/music_mad.c @@ -170,7 +170,7 @@ static __inline__ SDL_bool is_id3v2(const unsigned char *data, int length) } return SDL_TRUE; } -static __inline__ int get_id3v2_len(const unsigned char *data, long length) +static __inline__ int get_id3v2_len(const unsigned char *data, int length) { /* size is a 'synchsafe' integer (see above) */ int size = (int)((data[6]<<21) + (data[7]<<14) + (data[8]<<7) + data[9]); @@ -207,11 +207,14 @@ static __inline__ SDL_bool is_apetag(const unsigned char *data, int length) } return SDL_TRUE; } -static __inline__ int get_ape_len(const unsigned char *data, int datalen, Uint32 *version) +static __inline__ int get_ape_len(const unsigned char *data) { + Uint32 flags, version; int size = (int)((data[15]<<24) | (data[14]<<16) | (data[13]<<8) | data[12]); - *version = (data[11]<<24) | (data[10]<<16) | (data[9]<<8) | data[8]; - return size; /* caller will handle the additional v2 header length */ + version = (data[11]<<24) | (data[10]<<16) | (data[9]<<8) | data[8]; + flags = (data[23]<<24) | (data[22]<<16) | (data[21]<<8) | data[20]; + if (version == 2000U && (flags & (1U<<31))) size += 32; /* header present. */ + return size; } static int skip_tags(mad_data *music) @@ -229,11 +232,10 @@ static int skip_tags(mad_data *music) music->length -= len; MAD_RWseek(music, 0, RW_SEEK_SET); } - /* APE tag _might_ be at the start: read the header */ + /* APE tag _might_ be at the start (discouraged + * but not forbidden, either.) read the header. */ else if (is_apetag(music->input_buffer, readsize)) { - Uint32 v; - len = get_ape_len(music->input_buffer, readsize, &v); - len += 32; /* we're at top: have a header. */ + len = get_ape_len(music->input_buffer); if (len >= music->length) return -1; music->start += len; music->length -= len; @@ -249,29 +251,10 @@ static int skip_tags(mad_data *music) if (is_id3v1(music->input_buffer, 128)) { music->length -= 128; - /* APE tag may be before the ID3v1: read the footer */ - if (music->length < 32) goto end; - MAD_RWseek(music, -32, RW_SEEK_END); - readsize = MAD_RWread(music, music->input_buffer, 1, 32); - MAD_RWseek(music, 0, RW_SEEK_SET); - if (readsize != 32) return -1; - if (is_apetag(music->input_buffer, 32)) { - Uint32 v; - len = get_ape_len(music->input_buffer, readsize, &v); - if (v == 2000U) len += 32; /* header */ - if (len >= music->length) return -1; - if (v == 2000U) { /* verify header : */ - MAD_RWseek(music, -len, RW_SEEK_END); - readsize = MAD_RWread(music, music->input_buffer, 1, 32); - MAD_RWseek(music, 0, RW_SEEK_SET); - if (readsize != 32) return -1; - if (!is_apetag(music->input_buffer, 32)) return -1; - } - music->length -= len; - goto end; - } - /* extended ID3v1 just before the ID3v1 tag? (unlikely) */ - if (music->length < 227) goto end; + /* extended ID3v1 just before the ID3v1 tag? (unlikely) + * if found, assume no additional tags: this stupidity + * is non-standard.. */ + if (music->length < 227) goto ape; MAD_RWseek(music, -227, RW_SEEK_END); readsize = MAD_RWread(music, music->input_buffer, 1, 227); MAD_RWseek(music, 0, RW_SEEK_SET); @@ -280,7 +263,10 @@ static int skip_tags(mad_data *music) music->length -= 227; goto end; } + + /* FIXME: handle possible double-ID3v1 tags? */ } + ape: /* APE tag may be at the end: read the footer */ if (music->length >= 32) { MAD_RWseek(music, -32, RW_SEEK_END); @@ -288,17 +274,8 @@ static int skip_tags(mad_data *music) MAD_RWseek(music, 0, RW_SEEK_SET); if (readsize != 32) return -1; if (is_apetag(music->input_buffer, 32)) { - Uint32 v; - len = get_ape_len(music->input_buffer, readsize, &v); - if (v == 2000U) len += 32; /* header */ + len = get_ape_len(music->input_buffer); if (len >= music->length) return -1; - if (v == 2000U) { /* verify header : */ - MAD_RWseek(music, -len, RW_SEEK_END); - readsize = MAD_RWread(music, music->input_buffer, 1, 32); - MAD_RWseek(music, 0, RW_SEEK_SET); - if (readsize != 32) return -1; - if (!is_apetag(music->input_buffer, 32)) return -1; - } music->length -= len; } } @@ -325,7 +302,7 @@ read_next_frame(mad_data *mp3_mad) { memmove(mp3_mad->input_buffer, mp3_mad->stream.next_frame, remaining); read_start = mp3_mad->input_buffer + remaining; read_size = MAD_INPUT_BUFFER_SIZE - remaining; - + } else { read_size = MAD_INPUT_BUFFER_SIZE; read_start = mp3_mad->input_buffer; @@ -334,7 +311,7 @@ read_next_frame(mad_data *mp3_mad) { /* Now read additional bytes from the input file. */ read_size = MAD_RWread(mp3_mad, read_start, 1, read_size); - + if (read_size <= 0) { if ((mp3_mad->status & (MS_input_eof | MS_input_error)) == 0) { if (read_size == 0) { @@ -342,14 +319,14 @@ read_next_frame(mad_data *mp3_mad) { } else { mp3_mad->status |= MS_input_error; } - + /* At the end of the file, we must stuff MAD_BUFFER_GUARD number of 0 bytes. */ memset(read_start + read_size, 0, MAD_BUFFER_GUARD); read_size += MAD_BUFFER_GUARD; } } - + /* Now feed those bytes into the libmad stream. */ mad_stream_buffer(&mp3_mad->stream, mp3_mad->input_buffer, read_size + remaining); @@ -362,10 +339,10 @@ read_next_frame(mad_data *mp3_mad) { if (MAD_RECOVERABLE(mp3_mad->stream.error)) { mad_stream_sync(&mp3_mad->stream); /* to frame seek mode */ return 0; - + } else if (mp3_mad->stream.error == MAD_ERROR_BUFLEN) { return 0; - + } else { mp3_mad->status |= MS_decode_error; return 0; @@ -402,7 +379,6 @@ decode_frame(mad_data *mp3_mad) { unsigned int nchannels, nsamples; mad_fixed_t const *left_ch, *right_ch; unsigned char *out; - int ret; mad_synth_frame(&mp3_mad->synth, &mp3_mad->frame); pcm = &mp3_mad->synth.pcm;