From 516693fcc9a35eeae86422a17ac9d2be4bbe899c Mon Sep 17 00:00:00 2001 From: Dave Bryant Date: Sun, 5 Dec 2010 19:25:32 +0000 Subject: make WavPack library check the extent of the block that it is parsing so that it cannot run into the next block; also enhance the metadata code to handle the case of files with non-audio blocks at the beginning (which can happen if the source WAV file has lots of RIFF data) git-svn-id: svn://svn.rockbox.org/rockbox/trunk@28736 a1c6a512-1295-4272-9138-f99709370657 --- apps/codecs/libwavpack/metadata.c | 9 +++- apps/codecs/libwavpack/wavpack.h | 1 + apps/codecs/libwavpack/wputils.c | 4 ++ apps/metadata/wavpack.c | 108 +++++++++++++++++++++++--------------- 4 files changed, 77 insertions(+), 45 deletions(-) diff --git a/apps/codecs/libwavpack/metadata.c b/apps/codecs/libwavpack/metadata.c index c944093b19..4dce10100f 100644 --- a/apps/codecs/libwavpack/metadata.c +++ b/apps/codecs/libwavpack/metadata.c @@ -19,15 +19,16 @@ int read_metadata_buff (WavpackContext *wpc, WavpackMetadata *wpmd) uint32_t bytes_to_read; uchar tchar; - if (!wpc->infile (&wpmd->id, 1) || !wpc->infile (&tchar, 1)) + if (wpc->stream.block_bytes_left < 2 || !wpc->infile (&wpmd->id, 1) || !wpc->infile (&tchar, 1)) return FALSE; wpmd->byte_length = tchar << 1; + wpc->stream.block_bytes_left -= 2; if (wpmd->id & ID_LARGE) { wpmd->id &= ~ID_LARGE; - if (!wpc->infile (&tchar, 1)) + if (wpc->stream.block_bytes_left < 2 || !wpc->infile (&tchar, 1)) return FALSE; wpmd->byte_length += (int32_t) tchar << 9; @@ -36,8 +37,12 @@ int read_metadata_buff (WavpackContext *wpc, WavpackMetadata *wpmd) return FALSE; wpmd->byte_length += (int32_t) tchar << 17; + wpc->stream.block_bytes_left -= 2; } + if ((wpc->stream.block_bytes_left -= wpmd->byte_length) < 0) + return FALSE; + if (wpmd->id & ID_ODD_SIZE) { wpmd->id &= ~ID_ODD_SIZE; wpmd->byte_length--; diff --git a/apps/codecs/libwavpack/wavpack.h b/apps/codecs/libwavpack/wavpack.h index ee7c969b4c..b15a176f33 100644 --- a/apps/codecs/libwavpack/wavpack.h +++ b/apps/codecs/libwavpack/wavpack.h @@ -205,6 +205,7 @@ typedef struct { int num_terms, mute_error; uint32_t sample_index, crc; + int32_t block_bytes_left; uchar int32_sent_bits, int32_zeros, int32_ones, int32_dups; uchar float_flags, float_shift, float_max_exp, float_norm_exp; diff --git a/apps/codecs/libwavpack/wputils.c b/apps/codecs/libwavpack/wputils.c index 7fabc7ab34..b0ccd3ba83 100644 --- a/apps/codecs/libwavpack/wputils.c +++ b/apps/codecs/libwavpack/wputils.c @@ -69,6 +69,8 @@ WavpackContext *WavpackOpenFileInput (read_stream infile, char *error) return NULL; } + wps->block_bytes_left = wps->wphdr.ckSize - 24; + if ((wps->wphdr.flags & UNKNOWN_FLAGS) || wps->wphdr.version < MIN_STREAM_VERS || wps->wphdr.version > MAX_STREAM_VERS) { strcpy_loc (error, "invalid WavPack file!"); @@ -171,6 +173,8 @@ uint32_t WavpackUnpackSamples (WavpackContext *wpc, int32_t *buffer, uint32_t sa if (bcount == (uint32_t) -1) break; + wps->block_bytes_left = wps->wphdr.ckSize - 24; + if (wps->wphdr.version < MIN_STREAM_VERS || wps->wphdr.version > MAX_STREAM_VERS) { strcpy_loc (wpc->error_message, "invalid WavPack file!"); break; diff --git a/apps/metadata/wavpack.c b/apps/metadata/wavpack.c index bb181b8d3f..7d19435543 100644 --- a/apps/metadata/wavpack.c +++ b/apps/metadata/wavpack.c @@ -47,14 +47,16 @@ static const long wavpack_sample_rates [] = * now works with self-extrating WavPack files and also will scan the * metadata for non-standard sampling rates. This no longer fails on * WavPack files containing floating-point audio data because these are - * now converted to standard Rockbox format in the decoder. + * now converted to standard Rockbox format in the decoder, and also + * handles the case where up to 15 non-audio blocks might occur at the + * beginning of the file. */ bool get_wavpack_metadata(int fd, struct mp3entry* id3) { /* Use the trackname part of the id3 structure as a temporary buffer */ unsigned char* buf = (unsigned char *)id3->path; - uint32_t totalsamples, blocksamples, flags; + uint32_t totalsamples = (uint32_t) -1; int i; for (i = 0; i < 256; ++i) { @@ -78,66 +80,86 @@ bool get_wavpack_metadata(int fd, struct mp3entry* id3) id3->vbr = true; /* All WavPack files are VBR */ id3->filesize = filesize (fd); - totalsamples = get_long_le(&buf[12]); - blocksamples = get_long_le(&buf[20]); - flags = get_long_le(&buf[24]); - if (blocksamples) { - int srindx = ((buf [26] >> 7) & 1) + ((buf [27] << 1) & 14); + /* check up to 16 headers before we give up finding one with audio */ - if (srindx == 15) { - uint32_t meta_bytes = buf [4] + (buf [5] << 8) + (buf [6] << 16) - 24; - uint32_t meta_size; + for (i = 0; i < 16; ++i) { + uint32_t trial_totalsamples = get_long_le(&buf[12]); + uint32_t blockindex = get_long_le(&buf[16]); + uint32_t blocksamples = get_long_le(&buf[20]); + uint32_t flags = get_long_le(&buf[24]); - id3->frequency = 44100; + if (totalsamples == (uint32_t) -1 && trial_totalsamples != (uint32_t) -1 && blockindex == 0) + totalsamples = trial_totalsamples; - while (meta_bytes >= 6) { - if (read(fd, buf, 2) < 2) - break; + if (blocksamples) { + int srindx = ((buf [26] >> 7) & 1) + ((buf [27] << 1) & 14); + + if (srindx == 15) { + uint32_t meta_bytes = buf [4] + (buf [5] << 8) + (buf [6] << 16) - 24; + uint32_t meta_size; - if (buf [0] & ID_LARGE) { - if (read(fd, buf + 2, 2) < 2) + id3->frequency = 44100; + + while (meta_bytes >= 6) { + if (read(fd, buf, 2) < 2) break; - meta_size = (buf [1] << 1) + (buf [2] << 9) + (buf [3] << 17); - meta_bytes -= meta_size + 4; - } - else { - meta_size = buf [1] << 1; - meta_bytes -= meta_size + 2; + if (buf [0] & ID_LARGE) { + if (read(fd, buf + 2, 2) < 2) + break; - if ((buf [0] & ID_UNIQUE) == ID_SAMPLE_RATE) { - if (meta_size == 4 && read(fd, buf + 2, 4) == 4) - id3->frequency = buf [2] + (buf [3] << 8) + (buf [4] << 16); + meta_size = (buf [1] << 1) + (buf [2] << 9) + (buf [3] << 17); + meta_bytes -= meta_size + 4; + } + else { + meta_size = buf [1] << 1; + meta_bytes -= meta_size + 2; - break; + if ((buf [0] & ID_UNIQUE) == ID_SAMPLE_RATE) { + if (meta_size == 4 && read(fd, buf + 2, 4) == 4) + id3->frequency = buf [2] + (buf [3] << 8) + (buf [4] << 16); + + break; + } } - } - if (meta_size > 0 && lseek(fd, meta_size, SEEK_CUR) < 0) - break; + if (meta_size > 0 && lseek(fd, meta_size, SEEK_CUR) < 0) + break; + } } - } - else - id3->frequency = wavpack_sample_rates[srindx]; + else + id3->frequency = wavpack_sample_rates[srindx]; + + /* if the total number of samples is still unknown, make a guess on the high side (for now) */ + + if (totalsamples == (uint32_t) -1) { + totalsamples = filesize (fd) * 3; - /* if the total number of samples is unknown, make a guess on the high side (for now) */ + if (!(flags & HYBRID_FLAG)) + totalsamples /= 2; - if (totalsamples == (uint32_t) -1) { - totalsamples = filesize (fd) * 3; + if (!(flags & MONO_FLAG)) + totalsamples /= 2; + } - if (!(flags & HYBRID_FLAG)) - totalsamples /= 2; + id3->length = ((int64_t) totalsamples * 1000) / id3->frequency; + id3->bitrate = filesize (fd) / (id3->length / 8); - if (!(flags & MONO_FLAG)) - totalsamples /= 2; + read_ape_tags(fd, id3); + return true; } + else { /* block did not contain audio, so seek to the end and see if there's another */ + uint32_t meta_bytes = buf [4] + (buf [5] << 8) + (buf [6] << 16) - 24; - id3->length = ((int64_t) totalsamples * 1000) / id3->frequency; - id3->bitrate = filesize (fd) / (id3->length / 8); + if ((meta_bytes > 0 && lseek(fd, meta_bytes, SEEK_CUR) < 0) || + read(fd, buf, 32) < 32) + break; - read_ape_tags(fd, id3); - return true; + if (memcmp (buf, "wvpk", 4) != 0 || buf [9] != 4 || + buf [8] < 2 || buf [8] > 0x10) + break; + } } return false; -- cgit v1.2.3