From 1611d2c44cce7a27f23a27e14d19caad2012f6dd Mon Sep 17 00:00:00 2001 From: David Reid Date: Tue, 11 Sep 2018 19:19:54 +1000 Subject: [PATCH] Update external libraries. --- extras/dr_flac.h | 620 +++++++++++++++++++++++++++++++++++------------ extras/dr_mp3.h | 10 +- extras/dr_wav.h | 37 +-- 3 files changed, 501 insertions(+), 166 deletions(-) diff --git a/extras/dr_flac.h b/extras/dr_flac.h index b2e21e15..fa727aca 100644 --- a/extras/dr_flac.h +++ b/extras/dr_flac.h @@ -1,5 +1,5 @@ // FLAC audio decoder. Public domain. See "unlicense" statement at the end of this file. -// dr_flac - v0.9.11 - 2018-08-29 +// dr_flac - v0.10.0 - 2018-09-11 // // David Reid - mackron@gmail.com @@ -80,16 +80,11 @@ // #define these options before including this file. // // #define DR_FLAC_NO_STDIO -// Disable drflac_open_file(). +// Disable drflac_open_file() and family. // // #define DR_FLAC_NO_OGG // Disables support for Ogg/FLAC streams. // -// #define DR_FLAC_NO_WIN32_IO -// In the Win32 build, dr_flac uses the Win32 IO APIs for drflac_open_file() by default. This setting will make it use the -// standard FILE APIs instead. Ignored when DR_FLAC_NO_STDIO is #defined. (The rationale for this configuration is that -// there's a bug in one compiler's Win32 implementation of the FILE APIs which is not present in the Win32 IO APIs.) -// // #define DR_FLAC_BUFFER_SIZE // Defines the size of the internal buffer to store data from onRead(). This buffer is used to reduce the number of calls // back to the client for more data. Larger values means more memory, but better performance. My tests show diminishing @@ -109,8 +104,6 @@ // - dr_flac does not currently support changing the sample rate nor channel count mid stream. // - Audio data is output as signed 32-bit PCM, regardless of the bits per sample the FLAC stream is encoded as. // - This has not been tested on big-endian architectures. -// - Rice codes in unencoded binary form (see https://xiph.org/flac/format.html#rice_partition) has not been tested. If anybody -// knows where I can find some test files for this, let me know. // - dr_flac is not thread-safe, but its APIs can be called from any thread so long as you do your own synchronization. // - When using Ogg encapsulation, a corrupted metadata block will result in drflac_open_with_metadata() and drflac_open() // returning inconsistent samples. @@ -276,7 +269,7 @@ typedef struct drflac_uint32 vendorLength; const char* vendor; drflac_uint32 commentCount; - const char* comments; + const void* pComments; } vorbis_comment; struct @@ -285,7 +278,7 @@ typedef struct drflac_uint64 leadInSampleCount; drflac_bool32 isCD; drflac_uint8 trackCount; - const drflac_uint8* pTrackData; + const void* pTrackData; } cuesheet; struct @@ -728,13 +721,49 @@ typedef struct // Initializes a vorbis comment iterator. This can be used for iterating over the vorbis comments in a VORBIS_COMMENT // metadata block. -void drflac_init_vorbis_comment_iterator(drflac_vorbis_comment_iterator* pIter, drflac_uint32 commentCount, const char* pComments); +void drflac_init_vorbis_comment_iterator(drflac_vorbis_comment_iterator* pIter, drflac_uint32 commentCount, const void* pComments); // Goes to the next vorbis comment in the given iterator. If null is returned it means there are no more comments. The // returned string is NOT null terminated. const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, drflac_uint32* pCommentLengthOut); +// Structure representing an iterator for cuesheet tracks in a CUESHEET metadata block. +typedef struct +{ + drflac_uint32 countRemaining; + const char* pRunningData; +} drflac_cuesheet_track_iterator; + +// Packing is important on this structure because we map this directly to the raw data within the CUESHEET metadata block. +#pragma pack(4) +typedef struct +{ + drflac_uint64 offset; + drflac_uint8 index; + drflac_uint8 reserved[3]; +} drflac_cuesheet_track_index; +#pragma pack() + +typedef struct +{ + drflac_uint64 offset; + drflac_uint8 trackNumber; + char ISRC[12]; + drflac_bool8 isAudio; + drflac_bool8 preEmphasis; + drflac_uint8 indexCount; + const drflac_cuesheet_track_index* pIndexPoints; +} drflac_cuesheet_track; + +// Initializes a cuesheet track iterator. This can be used for iterating over the cuesheet tracks in a CUESHEET metadata +// block. +void drflac_init_cuesheet_track_iterator(drflac_cuesheet_track_iterator* pIter, drflac_uint32 trackCount, const void* pTrackData); + +// Goes to the next cuesheet track in the given iterator. If DRFLAC_FALSE is returned it means there are no more comments. +drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterator* pIter, drflac_cuesheet_track* pCuesheetTrack); + + #ifdef __cplusplus } @@ -750,10 +779,10 @@ const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, dr #ifdef DR_FLAC_IMPLEMENTATION #ifdef __linux__ #ifndef _BSD_SOURCE - #define _BSD_SOURCE + #define _BSD_SOURCE #endif #ifndef __USE_BSD - #define __USE_BSD + #define __USE_BSD #endif #include #endif @@ -763,11 +792,11 @@ const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, dr // CPU architecture. #if defined(__x86_64__) || defined(_M_X64) -#define DRFLAC_X64 + #define DRFLAC_X64 #elif defined(__i386) || defined(_M_IX86) -#define DRFLAC_X86 + #define DRFLAC_X86 #elif defined(__arm__) || defined(_M_ARM) -#define DRFLAC_ARM + #define DRFLAC_ARM #endif // Compile-time CPU feature support. @@ -809,7 +838,7 @@ const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, dr #endif #endif #else -#define DRFLAC_NO_CPUID + #define DRFLAC_NO_CPUID #endif @@ -1293,20 +1322,17 @@ static DRFLAC_INLINE drflac_uint16 drflac_crc16(drflac_uint16 crc, drflac_cache_ // is a 32- or 64-bit unsigned integer (depending on whether or not a 32- or 64-bit build is being compiled) and the L2 is an // array of "cache lines", with each cache line being the same size as the L1. The L2 is a buffer of about 4KB and is where data // from onRead() is read into. -#define DRFLAC_CACHE_L1_SIZE_BYTES(bs) (sizeof((bs)->cache)) -#define DRFLAC_CACHE_L1_SIZE_BITS(bs) (sizeof((bs)->cache)*8) -#define DRFLAC_CACHE_L1_BITS_REMAINING(bs) (DRFLAC_CACHE_L1_SIZE_BITS(bs) - ((bs)->consumedBits)) -#ifdef DRFLAC_64BIT -#define DRFLAC_CACHE_L1_SELECTION_MASK(_bitCount) (~(((drflac_uint64)-1LL) >> (_bitCount))) -#else -#define DRFLAC_CACHE_L1_SELECTION_MASK(_bitCount) (~(((drflac_uint32)-1) >> (_bitCount))) -#endif -#define DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, _bitCount) (DRFLAC_CACHE_L1_SIZE_BITS(bs) - (_bitCount)) -#define DRFLAC_CACHE_L1_SELECT(bs, _bitCount) (((bs)->cache) & DRFLAC_CACHE_L1_SELECTION_MASK(_bitCount)) -#define DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, _bitCount) (DRFLAC_CACHE_L1_SELECT((bs), _bitCount) >> DRFLAC_CACHE_L1_SELECTION_SHIFT((bs), _bitCount)) -#define DRFLAC_CACHE_L2_SIZE_BYTES(bs) (sizeof((bs)->cacheL2)) -#define DRFLAC_CACHE_L2_LINE_COUNT(bs) (DRFLAC_CACHE_L2_SIZE_BYTES(bs) / sizeof((bs)->cacheL2[0])) -#define DRFLAC_CACHE_L2_LINES_REMAINING(bs) (DRFLAC_CACHE_L2_LINE_COUNT(bs) - (bs)->nextL2Line) +#define DRFLAC_CACHE_L1_SIZE_BYTES(bs) (sizeof((bs)->cache)) +#define DRFLAC_CACHE_L1_SIZE_BITS(bs) (sizeof((bs)->cache)*8) +#define DRFLAC_CACHE_L1_BITS_REMAINING(bs) (DRFLAC_CACHE_L1_SIZE_BITS(bs) - (bs)->consumedBits) +#define DRFLAC_CACHE_L1_SELECTION_MASK(_bitCount) (~((~(drflac_cache_t)0) >> (_bitCount))) +#define DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, _bitCount) (DRFLAC_CACHE_L1_SIZE_BITS(bs) - (_bitCount)) +#define DRFLAC_CACHE_L1_SELECT(bs, _bitCount) (((bs)->cache) & DRFLAC_CACHE_L1_SELECTION_MASK(_bitCount)) +#define DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, _bitCount) (DRFLAC_CACHE_L1_SELECT((bs), (_bitCount)) >> DRFLAC_CACHE_L1_SELECTION_SHIFT((bs), (_bitCount))) +#define DRFLAC_CACHE_L1_SELECT_AND_SHIFT_SAFE(bs, _bitCount)(DRFLAC_CACHE_L1_SELECT((bs), (_bitCount)) >> (DRFLAC_CACHE_L1_SELECTION_SHIFT((bs), (_bitCount)) & (DRFLAC_CACHE_L1_SIZE_BITS(bs)-1))) +#define DRFLAC_CACHE_L2_SIZE_BYTES(bs) (sizeof((bs)->cacheL2)) +#define DRFLAC_CACHE_L2_LINE_COUNT(bs) (DRFLAC_CACHE_L2_SIZE_BYTES(bs) / sizeof((bs)->cacheL2[0])) +#define DRFLAC_CACHE_L2_LINES_REMAINING(bs) (DRFLAC_CACHE_L2_LINE_COUNT(bs) - (bs)->nextL2Line) #ifndef DR_FLAC_NO_CRC @@ -1418,6 +1444,7 @@ static drflac_bool32 drflac__reload_cache(drflac_bs* bs) // data from the unaligned cache. size_t bytesRead = bs->unalignedByteCount; if (bytesRead == 0) { + bs->consumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs); // <-- The stream has been exhausted, so marked the bits as consumed. return DRFLAC_FALSE; } @@ -1425,7 +1452,7 @@ static drflac_bool32 drflac__reload_cache(drflac_bs* bs) bs->consumedBits = (drflac_uint32)(DRFLAC_CACHE_L1_SIZE_BYTES(bs) - bytesRead) * 8; bs->cache = drflac__be2host__cache_line(bs->unalignedCache); - bs->cache &= DRFLAC_CACHE_L1_SELECTION_MASK(DRFLAC_CACHE_L1_SIZE_BITS(bs) - bs->consumedBits); // <-- Make sure the consumed bits are always set to zero. Other parts of the library depend on this property. + bs->cache &= DRFLAC_CACHE_L1_SELECTION_MASK(DRFLAC_CACHE_L1_BITS_REMAINING(bs)); // <-- Make sure the consumed bits are always set to zero. Other parts of the library depend on this property. bs->unalignedByteCount = 0; // <-- At this point the unaligned bytes have been moved into the cache and we thus have no more unaligned bytes. #ifndef DR_FLAC_NO_CRC @@ -1464,15 +1491,26 @@ static DRFLAC_INLINE drflac_bool32 drflac__read_uint32(drflac_bs* bs, unsigned i } if (bitCount <= DRFLAC_CACHE_L1_BITS_REMAINING(bs)) { + // If we want to load all 32-bits from a 32-bit cache we need to do it slightly differently because we can't do + // a 32-bit shift on a 32-bit integer. This will never be the case on 64-bit caches, so we can have a slightly + // more optimal solution for this. +#ifdef DRFLAC_64BIT + *pResultOut = (drflac_uint32)DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCount); + bs->consumedBits += bitCount; + bs->cache <<= bitCount; +#else if (bitCount < DRFLAC_CACHE_L1_SIZE_BITS(bs)) { *pResultOut = (drflac_uint32)DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCount); bs->consumedBits += bitCount; bs->cache <<= bitCount; } else { + // Cannot shift by 32-bits, so need to do it differently. *pResultOut = (drflac_uint32)bs->cache; bs->consumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs); bs->cache = 0; } +#endif + return DRFLAC_TRUE; } else { // It straddles the cached data. It will never cover more than the next chunk. We just read the number in two parts and combine them. @@ -1784,6 +1822,8 @@ static DRFLAC_INLINE drflac_uint32 drflac__clz_lzcnt(drflac_cache_t x) #endif #ifdef DRFLAC_IMPLEMENT_CLZ_MSVC +#include // For BitScanReverse(). + static DRFLAC_INLINE drflac_uint32 drflac__clz_msvc(drflac_cache_t x) { drflac_uint32 n; @@ -1805,11 +1845,11 @@ static DRFLAC_INLINE drflac_uint32 drflac__clz(drflac_cache_t x) } else #endif { - #ifdef DRFLAC_IMPLEMENT_CLZ_MSVC +#ifdef DRFLAC_IMPLEMENT_CLZ_MSVC return drflac__clz_msvc(x); - #else +#else return drflac__clz_software(x); - #endif +#endif } } @@ -2250,9 +2290,9 @@ static drflac_bool32 drflac__read_rice_parts__reference(drflac_bs* bs, drflac_ui static DRFLAC_INLINE drflac_bool32 drflac__read_rice_parts(drflac_bs* bs, drflac_uint8 riceParam, drflac_uint32* pZeroCounterOut, drflac_uint32* pRiceParamPartOut) { - drflac_cache_t riceParamMask = DRFLAC_CACHE_L1_SELECTION_MASK(riceParam); - drflac_cache_t resultHiShift = DRFLAC_CACHE_L1_SIZE_BITS(bs) - riceParam; + drflac_assert(riceParam > 0); // <-- riceParam should never be 0. drflac__read_rice_parts__param_equals_zero() should be used instead for this case. + drflac_cache_t riceParamMask = DRFLAC_CACHE_L1_SELECTION_MASK(riceParam); drflac_uint32 zeroCounter = 0; while (bs->cache == 0) { @@ -2270,29 +2310,27 @@ static DRFLAC_INLINE drflac_bool32 drflac__read_rice_parts(drflac_bs* bs, drflac drflac_uint32 riceParamPart; drflac_uint32 riceLength = setBitOffsetPlus1 + riceParam; if (riceLength < DRFLAC_CACHE_L1_BITS_REMAINING(bs)) { - riceParamPart = (drflac_uint32)((bs->cache & (riceParamMask >> setBitOffsetPlus1)) >> (DRFLAC_CACHE_L1_SIZE_BITS(bs) - riceLength)); + riceParamPart = (drflac_uint32)((bs->cache & (riceParamMask >> setBitOffsetPlus1)) >> DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, riceLength)); bs->consumedBits += riceLength; bs->cache <<= riceLength; } else { bs->consumedBits += riceLength; - if (setBitOffsetPlus1 < DRFLAC_CACHE_L1_SIZE_BITS(bs)) { - bs->cache <<= setBitOffsetPlus1; - } + bs->cache <<= setBitOffsetPlus1 & (DRFLAC_CACHE_L1_SIZE_BITS(bs)-1); // <-- Equivalent to "if (setBitOffsetPlus1 < DRFLAC_CACHE_L1_SIZE_BITS(bs)) { bs->cache <<= setBitOffsetPlus1; }" // It straddles the cached data. It will never cover more than the next chunk. We just read the number in two parts and combine them. drflac_uint32 bitCountLo = bs->consumedBits - DRFLAC_CACHE_L1_SIZE_BITS(bs); - drflac_cache_t resultHi = bs->cache & riceParamMask; // <-- This mask is OK because all bits after the first bits are always zero. + drflac_cache_t resultHi = DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, riceParam); // <-- Use DRFLAC_CACHE_L1_SELECT_AND_SHIFT_SAFE() if ever this function allows riceParam=0. if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) { - #ifndef DR_FLAC_NO_CRC +#ifndef DR_FLAC_NO_CRC drflac__update_crc16(bs); - #endif +#endif bs->cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]); bs->consumedBits = 0; - #ifndef DR_FLAC_NO_CRC +#ifndef DR_FLAC_NO_CRC bs->crc16Cache = bs->cache; - #endif +#endif } else { // Slow path. We need to fetch more data from the client. if (!drflac__reload_cache(bs)) { @@ -2300,7 +2338,62 @@ static DRFLAC_INLINE drflac_bool32 drflac__read_rice_parts(drflac_bs* bs, drflac } } - riceParamPart = (drflac_uint32)((resultHi >> resultHiShift) | DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCountLo)); + riceParamPart = (drflac_uint32)(resultHi | DRFLAC_CACHE_L1_SELECT_AND_SHIFT_SAFE(bs, bitCountLo)); + + bs->consumedBits += bitCountLo; + bs->cache <<= bitCountLo; + } + + *pZeroCounterOut = zeroCounter; + *pRiceParamPartOut = riceParamPart; + return DRFLAC_TRUE; +} + +static DRFLAC_INLINE drflac_bool32 drflac__read_rice_parts__param_equals_zero(drflac_bs* bs, drflac_uint32* pZeroCounterOut, drflac_uint32* pRiceParamPartOut) +{ + drflac_cache_t riceParamMask = DRFLAC_CACHE_L1_SELECTION_MASK(0); + + drflac_uint32 zeroCounter = 0; + while (bs->cache == 0) { + zeroCounter += (drflac_uint32)DRFLAC_CACHE_L1_BITS_REMAINING(bs); + if (!drflac__reload_cache(bs)) { + return DRFLAC_FALSE; + } + } + + drflac_uint32 setBitOffsetPlus1 = drflac__clz(bs->cache); + zeroCounter += setBitOffsetPlus1; + setBitOffsetPlus1 += 1; + + + drflac_uint32 riceParamPart; + drflac_uint32 riceLength = setBitOffsetPlus1; + if (riceLength < DRFLAC_CACHE_L1_BITS_REMAINING(bs)) { + riceParamPart = (drflac_uint32)((bs->cache & (riceParamMask >> setBitOffsetPlus1)) >> DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, riceLength)); + + bs->consumedBits += riceLength; + bs->cache <<= riceLength; + } else { + // It straddles the cached data. It will never cover more than the next chunk. We just read the number in two parts and combine them. + drflac_uint32 bitCountLo = riceLength + bs->consumedBits - DRFLAC_CACHE_L1_SIZE_BITS(bs); + + if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) { +#ifndef DR_FLAC_NO_CRC + drflac__update_crc16(bs); +#endif + bs->cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]); + bs->consumedBits = 0; +#ifndef DR_FLAC_NO_CRC + bs->crc16Cache = bs->cache; +#endif + } else { + // Slow path. We need to fetch more data from the client. + if (!drflac__reload_cache(bs)) { + return DRFLAC_FALSE; + } + } + + riceParamPart = (drflac_uint32)(DRFLAC_CACHE_L1_SELECT_AND_SHIFT_SAFE(bs, bitCountLo)); bs->consumedBits += bitCountLo; bs->cache <<= bitCountLo; @@ -2391,12 +2484,94 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__simple(drflac_b return DRFLAC_TRUE; } +static drflac_bool32 drflac__decode_samples_with_residual__rice__param_equals_zero(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) +{ + drflac_assert(bs != NULL); + drflac_assert(count > 0); + drflac_assert(pSamplesOut != NULL); + + static drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF}; + + drflac_uint32 zeroCountPart0; + drflac_uint32 zeroCountPart1; + drflac_uint32 zeroCountPart2; + drflac_uint32 zeroCountPart3; + drflac_uint32 riceParamPart0; + drflac_uint32 riceParamPart1; + drflac_uint32 riceParamPart2; + drflac_uint32 riceParamPart3; + drflac_uint32 i4 = 0; + drflac_uint32 count4 = count >> 2; + while (i4 < count4) { + // Rice extraction. + if (!drflac__read_rice_parts__param_equals_zero(bs, &zeroCountPart0, &riceParamPart0) || + !drflac__read_rice_parts__param_equals_zero(bs, &zeroCountPart1, &riceParamPart1) || + !drflac__read_rice_parts__param_equals_zero(bs, &zeroCountPart2, &riceParamPart2) || + !drflac__read_rice_parts__param_equals_zero(bs, &zeroCountPart3, &riceParamPart3)) { + return DRFLAC_FALSE; + } + + riceParamPart0 |= zeroCountPart0; + riceParamPart1 |= zeroCountPart1; + riceParamPart2 |= zeroCountPart2; + riceParamPart3 |= zeroCountPart3; + + riceParamPart0 = (riceParamPart0 >> 1) ^ t[riceParamPart0 & 0x01]; + riceParamPart1 = (riceParamPart1 >> 1) ^ t[riceParamPart1 & 0x01]; + riceParamPart2 = (riceParamPart2 >> 1) ^ t[riceParamPart2 & 0x01]; + riceParamPart3 = (riceParamPart3 >> 1) ^ t[riceParamPart3 & 0x01]; + + if (bitsPerSample > 16) { + pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + 0); + pSamplesOut[1] = riceParamPart1 + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + 1); + pSamplesOut[2] = riceParamPart2 + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + 2); + pSamplesOut[3] = riceParamPart3 + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + 3); + } else { + pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + 0); + pSamplesOut[1] = riceParamPart1 + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + 1); + pSamplesOut[2] = riceParamPart2 + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + 2); + pSamplesOut[3] = riceParamPart3 + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + 3); + } + + i4 += 1; + pSamplesOut += 4; + } + + drflac_uint32 i = i4 << 2; + while (i < count) { + // Rice extraction. + if (!drflac__read_rice_parts__param_equals_zero(bs, &zeroCountPart0, &riceParamPart0)) { + return DRFLAC_FALSE; + } + + // Rice reconstruction. + riceParamPart0 |= zeroCountPart0; + riceParamPart0 = (riceParamPart0 >> 1) ^ t[riceParamPart0 & 0x01]; + + // Sample reconstruction. + if (bitsPerSample > 16) { + pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + 0); + } else { + pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + 0); + } + + i += 1; + pSamplesOut += 1; + } + + return DRFLAC_TRUE; +} + static drflac_bool32 drflac__decode_samples_with_residual__rice(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) { #if 0 return drflac__decode_samples_with_residual__rice__reference(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut); #else - return drflac__decode_samples_with_residual__rice__simple(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut); + if (riceParam != 0) { + return drflac__decode_samples_with_residual__rice__simple(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut); + } else { + return drflac__decode_samples_with_residual__rice__param_equals_zero(bs, bitsPerSample, count, order, shift, coefficients, pSamplesOut); + } #endif } @@ -2406,11 +2581,20 @@ static drflac_bool32 drflac__read_and_seek_residual__rice(drflac_bs* bs, drflac_ drflac_assert(bs != NULL); drflac_assert(count > 0); - for (drflac_uint32 i = 0; i < count; ++i) { - drflac_uint32 zeroCountPart; - drflac_uint32 riceParamPart; - if (!drflac__read_rice_parts(bs, riceParam, &zeroCountPart, &riceParamPart)) { - return DRFLAC_FALSE; + drflac_uint32 zeroCountPart; + drflac_uint32 riceParamPart; + + if (riceParam != 0) { + for (drflac_uint32 i = 0; i < count; ++i) { + if (!drflac__read_rice_parts(bs, riceParam, &zeroCountPart, &riceParamPart)) { + return DRFLAC_FALSE; + } + } + } else { + for (drflac_uint32 i = 0; i < count; ++i) { + if (!drflac__read_rice_parts__param_equals_zero(bs, &zeroCountPart, &riceParamPart)) { + return DRFLAC_FALSE; + } } } @@ -2421,12 +2605,16 @@ static drflac_bool32 drflac__decode_samples_with_residual__unencoded(drflac_bs* { drflac_assert(bs != NULL); drflac_assert(count > 0); - drflac_assert(unencodedBitsPerSample > 0 && unencodedBitsPerSample <= 32); + drflac_assert(unencodedBitsPerSample <= 31); // <-- unencodedBitsPerSample is a 5 bit number, so cannot exceed 31. drflac_assert(pSamplesOut != NULL); for (unsigned int i = 0; i < count; ++i) { - if (!drflac__read_int32(bs, unencodedBitsPerSample, pSamplesOut + i)) { - return DRFLAC_FALSE; + if (unencodedBitsPerSample > 0) { + if (!drflac__read_int32(bs, unencodedBitsPerSample, pSamplesOut + i)) { + return DRFLAC_FALSE; + } + } else { + pSamplesOut[i] = 0; } if (bitsPerSample > 16) { @@ -2486,14 +2674,14 @@ static drflac_bool32 drflac__decode_samples_with_residual(drflac_bs* bs, drflac_ if (!drflac__read_uint8(bs, 4, &riceParam)) { return DRFLAC_FALSE; } - if (riceParam == 16) { + if (riceParam == 15) { riceParam = 0xFF; } } else if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) { if (!drflac__read_uint8(bs, 5, &riceParam)) { return DRFLAC_FALSE; } - if (riceParam == 32) { + if (riceParam == 31) { riceParam = 0xFF; } } @@ -2552,6 +2740,17 @@ static drflac_bool32 drflac__read_and_seek_residual(drflac_bs* bs, drflac_uint32 return DRFLAC_FALSE; } + // From the FLAC spec: + // The Rice partition order in a Rice-coded residual section must be less than or equal to 8. + if (partitionOrder > 8) { + return DRFLAC_FALSE; + } + + // Validation check. + if ((blockSize / (1 << partitionOrder)) <= order) { + return DRFLAC_FALSE; + } + drflac_uint32 samplesInPartition = (blockSize / (1 << partitionOrder)) - order; drflac_uint32 partitionsRemaining = (1 << partitionOrder); for (;;) @@ -2561,14 +2760,14 @@ static drflac_bool32 drflac__read_and_seek_residual(drflac_bs* bs, drflac_uint32 if (!drflac__read_uint8(bs, 4, &riceParam)) { return DRFLAC_FALSE; } - if (riceParam == 16) { + if (riceParam == 15) { riceParam = 0xFF; } } else if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) { if (!drflac__read_uint8(bs, 5, &riceParam)) { return DRFLAC_FALSE; } - if (riceParam == 32) { + if (riceParam == 31) { riceParam = 0xFF; } } @@ -2725,6 +2924,9 @@ static drflac_bool32 drflac__read_next_frame_header(drflac_bs* bs, drflac_uint8 if (!drflac__read_uint8(bs, 1, &reserved)) { return DRFLAC_FALSE; } + if (reserved == 1) { + continue; + } crc8 = drflac_crc8(crc8, reserved, 1); @@ -2739,6 +2941,9 @@ static drflac_bool32 drflac__read_next_frame_header(drflac_bs* bs, drflac_uint8 if (!drflac__read_uint8(bs, 4, &blockSize)) { return DRFLAC_FALSE; } + if (blockSize == 0) { + continue; + } crc8 = drflac_crc8(crc8, blockSize, 4); @@ -2753,6 +2958,9 @@ static drflac_bool32 drflac__read_next_frame_header(drflac_bs* bs, drflac_uint8 if (!drflac__read_uint8(bs, 4, &channelAssignment)) { return DRFLAC_FALSE; } + if (channelAssignment > 10) { + continue; + } crc8 = drflac_crc8(crc8, channelAssignment, 4); @@ -2760,12 +2968,18 @@ static drflac_bool32 drflac__read_next_frame_header(drflac_bs* bs, drflac_uint8 if (!drflac__read_uint8(bs, 3, &bitsPerSample)) { return DRFLAC_FALSE; } + if (bitsPerSample == 3 || bitsPerSample == 7) { + continue; + } crc8 = drflac_crc8(crc8, bitsPerSample, 3); if (!drflac__read_uint8(bs, 1, &reserved)) { return DRFLAC_FALSE; } + if (reserved == 1) { + continue; + } crc8 = drflac_crc8(crc8, reserved, 1); @@ -2853,11 +3067,11 @@ static drflac_bool32 drflac__read_next_frame_header(drflac_bs* bs, drflac_uint8 return DRFLAC_FALSE; } - #ifndef DR_FLAC_NO_CRC +#ifndef DR_FLAC_NO_CRC if (header->crc8 != crc8) { continue; // CRC mismatch. Loop back to the top and find the next sync code. } - #endif +#endif return DRFLAC_TRUE; } } @@ -2931,6 +3145,9 @@ static drflac_bool32 drflac__decode_subframe(drflac_bs* bs, drflac_frame* frame, } // Need to handle wasted bits per sample. + if (pSubframe->wastedBitsPerSample >= pSubframe->bitsPerSample) { + return DRFLAC_FALSE; + } pSubframe->bitsPerSample -= pSubframe->wastedBitsPerSample; pSubframe->pDecodedSamples = pDecodedSamplesOut; @@ -2981,6 +3198,9 @@ static drflac_bool32 drflac__seek_subframe(drflac_bs* bs, drflac_frame* frame, i } // Need to handle wasted bits per sample. + if (pSubframe->wastedBitsPerSample >= pSubframe->bitsPerSample) { + return DRFLAC_FALSE; + } pSubframe->bitsPerSample -= pSubframe->wastedBitsPerSample; pSubframe->pDecodedSamples = NULL; @@ -3533,6 +3753,10 @@ drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, drflac_s { case DRFLAC_METADATA_BLOCK_TYPE_APPLICATION: { + if (blockSize < 4) { + return DRFLAC_FALSE; + } + if (onMeta) { void* pRawData = DRFLAC_MALLOC(blockSize); if (pRawData == NULL) { @@ -3592,6 +3816,10 @@ drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, drflac_s case DRFLAC_METADATA_BLOCK_TYPE_VORBIS_COMMENT: { + if (blockSize < 8) { + return DRFLAC_FALSE; + } + if (onMeta) { void* pRawData = DRFLAC_MALLOC(blockSize); if (pRawData == NULL) { @@ -3607,10 +3835,39 @@ drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, drflac_s metadata.rawDataSize = blockSize; const char* pRunningData = (const char*)pRawData; - metadata.data.vorbis_comment.vendorLength = drflac__le2host_32(*(drflac_uint32*)pRunningData); pRunningData += 4; - metadata.data.vorbis_comment.vendor = pRunningData; pRunningData += metadata.data.vorbis_comment.vendorLength; - metadata.data.vorbis_comment.commentCount = drflac__le2host_32(*(drflac_uint32*)pRunningData); pRunningData += 4; - metadata.data.vorbis_comment.comments = pRunningData; + const char* const pRunningDataEnd = (const char*)pRawData + blockSize; + + metadata.data.vorbis_comment.vendorLength = drflac__le2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + + // Need space for the rest of the block + if ((pRunningDataEnd - pRunningData) - 4 < (drflac_int64)metadata.data.vorbis_comment.vendorLength) { // <-- Note the order of operations to avoid overflow to a valid value + DRFLAC_FREE(pRawData); + return DRFLAC_FALSE; + } + metadata.data.vorbis_comment.vendor = pRunningData; pRunningData += metadata.data.vorbis_comment.vendorLength; + metadata.data.vorbis_comment.commentCount = drflac__le2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + + // Need space for 'commentCount' comments after the block, which at minimum is a drflac_uint32 per comment + if ((pRunningDataEnd - pRunningData) / sizeof(drflac_uint32) < metadata.data.vorbis_comment.commentCount) { // <-- Note the order of operations to avoid overflow to a valid value + DRFLAC_FREE(pRawData); + return DRFLAC_FALSE; + } + metadata.data.vorbis_comment.pComments = pRunningData; + + // Check that the comments section is valid before passing it to the callback + for (drflac_uint32 i = 0; i < metadata.data.vorbis_comment.commentCount; ++i) { + if (pRunningDataEnd - pRunningData < 4) { + DRFLAC_FREE(pRawData); + return DRFLAC_FALSE; + } + const drflac_uint32 commentLength = drflac__le2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + if (pRunningDataEnd - pRunningData < (drflac_int64)commentLength) { // <-- Note the order of operations to avoid overflow to a valid value + DRFLAC_FREE(pRawData); + return DRFLAC_FALSE; + } + pRunningData += commentLength; + } + onMeta(pUserDataMD, &metadata); DRFLAC_FREE(pRawData); @@ -3619,6 +3876,10 @@ drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, drflac_s case DRFLAC_METADATA_BLOCK_TYPE_CUESHEET: { + if (blockSize < 396) { + return DRFLAC_FALSE; + } + if (onMeta) { void* pRawData = DRFLAC_MALLOC(blockSize); if (pRawData == NULL) { @@ -3633,12 +3894,39 @@ drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, drflac_s metadata.pRawData = pRawData; metadata.rawDataSize = blockSize; - const char* pRunningData = (const char*)pRawData; - drflac_copy_memory(metadata.data.cuesheet.catalog, pRunningData, 128); pRunningData += 128; - metadata.data.cuesheet.leadInSampleCount = drflac__be2host_64(*(drflac_uint64*)pRunningData); pRunningData += 4; - metadata.data.cuesheet.isCD = ((pRunningData[0] & 0x80) >> 7) != 0; pRunningData += 259; - metadata.data.cuesheet.trackCount = pRunningData[0]; pRunningData += 1; - metadata.data.cuesheet.pTrackData = (const drflac_uint8*)pRunningData; + char* pRunningData = (char*)pRawData; + const char* const pRunningDataEnd = (const char*)pRawData + blockSize; + + drflac_copy_memory(metadata.data.cuesheet.catalog, pRunningData, 128); pRunningData += 128; + metadata.data.cuesheet.leadInSampleCount = drflac__be2host_64(*(const drflac_uint64*)pRunningData); pRunningData += 8; + metadata.data.cuesheet.isCD = (pRunningData[0] & 0x80) != 0; pRunningData += 259; + metadata.data.cuesheet.trackCount = pRunningData[0]; pRunningData += 1; + metadata.data.cuesheet.pTrackData = pRunningData; + + // Check that the cuesheet tracks are valid before passing it to the callback + for (drflac_uint8 i = 0; i < metadata.data.cuesheet.trackCount; ++i) { + if (pRunningDataEnd - pRunningData < 36) { + DRFLAC_FREE(pRawData); + return DRFLAC_FALSE; + } + + // Skip to the index point count + pRunningData += 35; + const drflac_uint8 indexCount = pRunningData[0]; pRunningData += 1; + const drflac_uint32 indexPointSize = indexCount * sizeof(drflac_cuesheet_track_index); + if (pRunningDataEnd - pRunningData < (drflac_int64)indexPointSize) { + DRFLAC_FREE(pRawData); + return DRFLAC_FALSE; + } + + // Endian swap. + for (drflac_uint8 index = 0; index < indexCount; ++index) { + drflac_cuesheet_track_index* pTrack = (drflac_cuesheet_track_index*)pRunningData; + pRunningData += sizeof(drflac_cuesheet_track_index); + pTrack->offset = drflac__be2host_64(pTrack->offset); + } + } + onMeta(pUserDataMD, &metadata); DRFLAC_FREE(pRawData); @@ -3647,6 +3935,10 @@ drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, drflac_s case DRFLAC_METADATA_BLOCK_TYPE_PICTURE: { + if (blockSize < 32) { + return DRFLAC_FALSE; + } + if (onMeta) { void* pRawData = DRFLAC_MALLOC(blockSize); if (pRawData == NULL) { @@ -3662,17 +3954,38 @@ drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, drflac_s metadata.rawDataSize = blockSize; const char* pRunningData = (const char*)pRawData; - metadata.data.picture.type = drflac__be2host_32(*(drflac_uint32*)pRunningData); pRunningData += 4; - metadata.data.picture.mimeLength = drflac__be2host_32(*(drflac_uint32*)pRunningData); pRunningData += 4; - metadata.data.picture.mime = pRunningData; pRunningData += metadata.data.picture.mimeLength; - metadata.data.picture.descriptionLength = drflac__be2host_32(*(drflac_uint32*)pRunningData); pRunningData += 4; - metadata.data.picture.description = pRunningData; - metadata.data.picture.width = drflac__be2host_32(*(drflac_uint32*)pRunningData); pRunningData += 4; - metadata.data.picture.height = drflac__be2host_32(*(drflac_uint32*)pRunningData); pRunningData += 4; - metadata.data.picture.colorDepth = drflac__be2host_32(*(drflac_uint32*)pRunningData); pRunningData += 4; - metadata.data.picture.indexColorCount = drflac__be2host_32(*(drflac_uint32*)pRunningData); pRunningData += 4; - metadata.data.picture.pictureDataSize = drflac__be2host_32(*(drflac_uint32*)pRunningData); pRunningData += 4; + const char* const pRunningDataEnd = (const char*)pRawData + blockSize; + + metadata.data.picture.type = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + metadata.data.picture.mimeLength = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + + // Need space for the rest of the block + if ((pRunningDataEnd - pRunningData) - 24 < (drflac_int64)metadata.data.picture.mimeLength) { // <-- Note the order of operations to avoid overflow to a valid value + DRFLAC_FREE(pRawData); + return DRFLAC_FALSE; + } + metadata.data.picture.mime = pRunningData; pRunningData += metadata.data.picture.mimeLength; + metadata.data.picture.descriptionLength = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + + // Need space for the rest of the block + if ((pRunningDataEnd - pRunningData) - 20 < (drflac_int64)metadata.data.picture.descriptionLength) { // <-- Note the order of operations to avoid overflow to a valid value + DRFLAC_FREE(pRawData); + return DRFLAC_FALSE; + } + metadata.data.picture.description = pRunningData; pRunningData += metadata.data.picture.descriptionLength; + metadata.data.picture.width = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + metadata.data.picture.height = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + metadata.data.picture.colorDepth = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + metadata.data.picture.indexColorCount = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + metadata.data.picture.pictureDataSize = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; metadata.data.picture.pPictureData = (const drflac_uint8*)pRunningData; + + // Need space for the picture after the block + if (pRunningDataEnd - pRunningData < (drflac_int64)metadata.data.picture.pictureDataSize) { // <-- Note the order of operations to avoid overflow to a valid value + DRFLAC_FREE(pRawData); + return DRFLAC_FALSE; + } + onMeta(pUserDataMD, &metadata); DRFLAC_FREE(pRawData); @@ -4265,7 +4578,7 @@ static drflac_bool32 drflac__on_seek_ogg(void* pUserData, int offset, drflac_see { drflac_oggbs* oggbs = (drflac_oggbs*)pUserData; drflac_assert(oggbs != NULL); - drflac_assert(offset > 0 || (offset == 0 && origin == drflac_seek_origin_start)); + drflac_assert(offset >= 0); // <-- Never seek backwards. // Seeking is always forward which makes things a lot simpler. if (origin == drflac_seek_origin_start) { @@ -4819,6 +5132,7 @@ drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac_seek_p // We need to seek back to where we were. If this fails it's a critical error. if (!pFlac->bs.onSeek(pFlac->bs.pUserData, (int)pFlac->firstFramePos, drflac_seek_origin_start)) { + DRFLAC_FREE(pFlac); return NULL; } } else { @@ -4861,9 +5175,6 @@ drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac_seek_p #ifndef DR_FLAC_NO_STDIO -typedef void* drflac_file; - -#if defined(DR_FLAC_NO_WIN32_IO) || !defined(_WIN32) #include static size_t drflac__on_read_stdio(void* pUserData, void* bufferOut, size_t bytesToRead) @@ -4873,12 +5184,12 @@ static size_t drflac__on_read_stdio(void* pUserData, void* bufferOut, size_t byt static drflac_bool32 drflac__on_seek_stdio(void* pUserData, int offset, drflac_seek_origin origin) { - drflac_assert(offset > 0 || (offset == 0 && origin == drflac_seek_origin_start)); + drflac_assert(offset >= 0); // <-- Never seek backwards. return fseek((FILE*)pUserData, offset, (origin == drflac_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0; } -static drflac_file drflac__open_file_handle(const char* filename) +static FILE* drflac__fopen(const char* filename) { FILE* pFile; #ifdef _MSC_VER @@ -4892,65 +5203,20 @@ static drflac_file drflac__open_file_handle(const char* filename) } #endif - return (drflac_file)pFile; + return pFile; } -static void drflac__close_file_handle(drflac_file file) -{ - fclose((FILE*)file); -} -#else -#include - -// This doesn't seem to be defined for VC6. -#ifndef INVALID_SET_FILE_POINTER -#define INVALID_SET_FILE_POINTER ((DWORD)-1) -#endif - -static size_t drflac__on_read_stdio(void* pUserData, void* bufferOut, size_t bytesToRead) -{ - drflac_assert(bytesToRead < 0xFFFFFFFF); // dr_flac will never request huge amounts of data at a time. This is a safe assertion. - - DWORD bytesRead; - ReadFile((HANDLE)pUserData, bufferOut, (DWORD)bytesToRead, &bytesRead, NULL); - - return (size_t)bytesRead; -} - -static drflac_bool32 drflac__on_seek_stdio(void* pUserData, int offset, drflac_seek_origin origin) -{ - drflac_assert(offset > 0 || (offset == 0 && origin == drflac_seek_origin_start)); - - return SetFilePointer((HANDLE)pUserData, offset, NULL, (origin == drflac_seek_origin_current) ? FILE_CURRENT : FILE_BEGIN) != INVALID_SET_FILE_POINTER; -} - -static drflac_file drflac__open_file_handle(const char* filename) -{ - HANDLE hFile = CreateFileA(filename, FILE_GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (hFile == INVALID_HANDLE_VALUE) { - return NULL; - } - - return (drflac_file)hFile; -} - -static void drflac__close_file_handle(drflac_file file) -{ - CloseHandle((HANDLE)file); -} -#endif - drflac* drflac_open_file(const char* filename) { - drflac_file file = drflac__open_file_handle(filename); + FILE* file = drflac__fopen(filename); if (file == NULL) { return NULL; } drflac* pFlac = drflac_open(drflac__on_read_stdio, drflac__on_seek_stdio, (void*)file); if (pFlac == NULL) { - drflac__close_file_handle(file); + fclose(file); return NULL; } @@ -4959,14 +5225,14 @@ drflac* drflac_open_file(const char* filename) drflac* drflac_open_file_with_metadata(const char* filename, drflac_meta_proc onMeta, void* pUserData) { - drflac_file file = drflac__open_file_handle(filename); + FILE* file = drflac__fopen(filename); if (file == NULL) { return NULL; } drflac* pFlac = drflac_open_with_metadata_private(drflac__on_read_stdio, drflac__on_seek_stdio, onMeta, drflac_container_unknown, (void*)file, pUserData); if (pFlac == NULL) { - drflac__close_file_handle(file); + fclose(file); return pFlac; } @@ -4997,20 +5263,23 @@ static drflac_bool32 drflac__on_seek_memory(void* pUserData, int offset, drflac_ { drflac__memory_stream* memoryStream = (drflac__memory_stream*)pUserData; drflac_assert(memoryStream != NULL); - drflac_assert(offset > 0 || (offset == 0 && origin == drflac_seek_origin_start)); - drflac_assert(offset <= (drflac_int64)memoryStream->dataSize); + drflac_assert(offset >= 0); // <-- Never seek backwards. + + if (offset > (drflac_int64)memoryStream->dataSize) { + return DRFLAC_FALSE; + } if (origin == drflac_seek_origin_current) { if (memoryStream->currentReadPos + offset <= memoryStream->dataSize) { memoryStream->currentReadPos += offset; } else { - memoryStream->currentReadPos = memoryStream->dataSize; // Trying to seek too far forward. + return DRFLAC_FALSE; // Trying to seek too far forward. } } else { if ((drflac_uint32)offset <= memoryStream->dataSize) { memoryStream->currentReadPos = offset; } else { - memoryStream->currentReadPos = memoryStream->dataSize; // Trying to seek too far forward. + return DRFLAC_FALSE; // Trying to seek too far forward. } } @@ -5105,7 +5374,7 @@ void drflac_close(drflac* pFlac) // If we opened the file with drflac_open_file() we will want to close the file handle. We can know whether or not drflac_open_file() // was used by looking at the callbacks. if (pFlac->bs.onRead == drflac__on_read_stdio) { - drflac__close_file_handle((drflac_file)pFlac->bs.pUserData); + fclose((FILE*)pFlac->bs.pUserData); } #ifndef DR_FLAC_NO_OGG @@ -5114,7 +5383,7 @@ void drflac_close(drflac* pFlac) drflac_assert(pFlac->bs.onRead == drflac__on_read_ogg); drflac_oggbs* oggbs = (drflac_oggbs*)pFlac->_oggbs; if (oggbs->onRead == drflac__on_read_stdio) { - drflac__close_file_handle((drflac_file)oggbs->pUserData); + fclose((FILE*)oggbs->pUserData); } } #endif @@ -5476,13 +5745,13 @@ drflac_bool32 drflac_seek_to_sample(drflac* pFlac, drflac_uint64 sampleIndex) // Different techniques depending on encapsulation. Using the native FLAC seektable with Ogg encapsulation is a bit awkward so // we'll instead use Ogg's natural seeking facility. - #ifndef DR_FLAC_NO_OGG +#ifndef DR_FLAC_NO_OGG if (pFlac->container == drflac_container_ogg) { wasSuccessful = drflac_ogg__seek_to_sample(pFlac, sampleIndex); } else - #endif +#endif { // First try seeking via the seek table. If this fails, fall back to a brute force seek which is much slower. wasSuccessful = drflac__seek_to_sample__seek_table(pFlac, sampleIndex); @@ -5718,14 +5987,14 @@ void drflac_free(void* pSampleDataReturnedByOpenAndDecode) -void drflac_init_vorbis_comment_iterator(drflac_vorbis_comment_iterator* pIter, drflac_uint32 commentCount, const char* pComments) +void drflac_init_vorbis_comment_iterator(drflac_vorbis_comment_iterator* pIter, drflac_uint32 commentCount, const void* pComments) { if (pIter == NULL) { return; } pIter->countRemaining = commentCount; - pIter->pRunningData = pComments; + pIter->pRunningData = (const char*)pComments; } const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, drflac_uint32* pCommentLengthOut) @@ -5737,7 +6006,7 @@ const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, dr return NULL; } - drflac_uint32 length = drflac__le2host_32(*(drflac_uint32*)pIter->pRunningData); + drflac_uint32 length = drflac__le2host_32(*(const drflac_uint32*)pIter->pRunningData); pIter->pRunningData += 4; const char* pComment = pIter->pRunningData; @@ -5747,11 +6016,62 @@ const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, dr if (pCommentLengthOut) *pCommentLengthOut = length; return pComment; } + + + + +void drflac_init_cuesheet_track_iterator(drflac_cuesheet_track_iterator* pIter, drflac_uint32 trackCount, const void* pTrackData) +{ + if (pIter == NULL) { + return; + } + + pIter->countRemaining = trackCount; + pIter->pRunningData = (const char*)pTrackData; +} + +drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterator* pIter, drflac_cuesheet_track* pCuesheetTrack) +{ + if (pIter == NULL || pIter->countRemaining == 0 || pIter->pRunningData == NULL) { + return DRFLAC_FALSE; + } + + drflac_cuesheet_track cuesheetTrack; + + const char* pRunningData = pIter->pRunningData; + + drflac_uint64 offsetHi = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + drflac_uint64 offsetLo = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + cuesheetTrack.offset = offsetLo | (offsetHi << 32); + cuesheetTrack.trackNumber = pRunningData[0]; pRunningData += 1; + drflac_copy_memory(cuesheetTrack.ISRC, pRunningData, sizeof(cuesheetTrack.ISRC)); pRunningData += 12; + cuesheetTrack.isAudio = (pRunningData[0] & 0x80) != 0; + cuesheetTrack.preEmphasis = (pRunningData[0] & 0x40) != 0; pRunningData += 14; + cuesheetTrack.indexCount = pRunningData[0]; pRunningData += 1; + cuesheetTrack.pIndexPoints = (const drflac_cuesheet_track_index*)pRunningData; pRunningData += cuesheetTrack.indexCount * sizeof(drflac_cuesheet_track_index); + + pIter->pRunningData = pRunningData; + pIter->countRemaining -= 1; + + if (pCuesheetTrack) *pCuesheetTrack = cuesheetTrack; + return DRFLAC_TRUE; +} #endif //DR_FLAC_IMPLEMENTATION // REVISION HISTORY // +// v0.10.0 - 2018-09-11 +// - Remove the DR_FLAC_NO_WIN32_IO option and the Win32 file IO functionality. If you need to use Win32 file IO you +// need to do it yourself via the callback API. +// - Fix the clang build. +// - Fix undefined behavior. +// - Fix errors with CUESHEET metdata blocks. +// - Add an API for iterating over each cuesheet track in the CUESHEET metadata block. This works the same way as the +// Vorbis comment API. +// - Other miscellaneous bug fixes, mostly relating to invalid FLAC streams. +// - Minor optimizations. +// // v0.9.11 - 2018-08-29 // - Fix a bug with sample reconstruction. // diff --git a/extras/dr_mp3.h b/extras/dr_mp3.h index f5e58bd8..cd8920a1 100644 --- a/extras/dr_mp3.h +++ b/extras/dr_mp3.h @@ -1,5 +1,5 @@ // MP3 audio decoder. Public domain. See "unlicense" statement at the end of this file. -// dr_mp3 - v0.3.1 - 2018-08-25 +// dr_mp3 - v0.3.2 - 2018-09-11 // // David Reid - mackron@gmail.com // @@ -315,7 +315,9 @@ void drmp3_free(void* p); #define DRMP3_OFFSET_PTR(p, offset) ((void*)((drmp3_uint8*)(p) + (offset))) #define DRMP3_MAX_FREE_FORMAT_FRAME_SIZE 2304 /* more than ISO spec's */ +#ifndef DRMP3_MAX_FRAME_SYNC_MATCHES #define DRMP3_MAX_FRAME_SYNC_MATCHES 10 +#endif #define DRMP3_MAX_L3_FRAME_PAYLOAD_BYTES DRMP3_MAX_FREE_FORMAT_FRAME_SIZE /* MUST be >= 320000/8/32000*1152 = 1440 */ @@ -2583,11 +2585,13 @@ drmp3_bool32 drmp3_init_internal(drmp3* pMP3, drmp3_read_proc onRead, drmp3_seek srcConfig.channels = pMP3->channels; srcConfig.algorithm = drmp3_src_algorithm_linear; if (!drmp3_src_init(&srcConfig, drmp3_read_src, pMP3, &pMP3->src)) { + drmp3_uninit(pMP3); return DRMP3_FALSE; } // Decode the first frame to confirm that it is indeed a valid MP3 stream. if (!drmp3_decode_next_frame(pMP3)) { + drmp3_uninit(pMP3); return DRMP3_FALSE; // Not a valid MP3 stream. } @@ -2888,6 +2892,10 @@ void drmp3_free(void* p) // REVISION HISTORY // =============== // +// v0.3.2 - 2018-09-11 +// - Fix a couple of memory leaks. +// - Bring up to date with minimp3. +// // v0.3.1 - 2018-08-25 // - Fix C++ build. // diff --git a/extras/dr_wav.h b/extras/dr_wav.h index c13a98db..6aff80a9 100644 --- a/extras/dr_wav.h +++ b/extras/dr_wav.h @@ -1,5 +1,5 @@ // WAV audio loader and writer. Public domain. See "unlicense" statement at the end of this file. -// dr_wav - v0.8.4 - 2018-08-07 +// dr_wav - v0.8.5 - 2018-09-11 // // David Reid - mackron@gmail.com @@ -909,13 +909,16 @@ static drwav_bool32 drwav__read_fmt(drwav_read_proc onRead, drwav_seek_proc onSe // Skip non-fmt chunks. - if ((container == drwav_container_riff && !drwav__fourcc_equal(header.id.fourcc, "fmt ")) || (container == drwav_container_w64 && !drwav__guid_equal(header.id.guid, drwavGUID_W64_FMT))) { + while ((container == drwav_container_riff && !drwav__fourcc_equal(header.id.fourcc, "fmt ")) || (container == drwav_container_w64 && !drwav__guid_equal(header.id.guid, drwavGUID_W64_FMT))) { if (!drwav__seek_forward(onSeek, header.sizeInBytes + header.paddingSize, pUserData)) { return DRWAV_FALSE; } *pRunningBytesReadOut += header.sizeInBytes + header.paddingSize; - return drwav__read_fmt(onRead, onSeek, pUserData, container, pRunningBytesReadOut, fmtOut); + // Try the next header. + if (!drwav__read_chunk_header(onRead, pUserData, container, pRunningBytesReadOut, &header)) { + return DRWAV_FALSE; + } } @@ -1140,11 +1143,11 @@ static drwav_bool32 drwav__on_seek_memory(void* pUserData, int offset, drwav_see if (origin == drwav_seek_origin_current) { if (offset > 0) { if (memory->currentReadPos + offset > memory->dataSize) { - offset = (int)(memory->dataSize - memory->currentReadPos); // Trying to seek too far forward. + return DRWAV_FALSE; // Trying to seek too far forward. } } else { if (memory->currentReadPos < (size_t)-offset) { - offset = -(int)memory->currentReadPos; // Trying to seek too far backwards. + return DRWAV_FALSE; // Trying to seek too far backwards. } } @@ -1154,7 +1157,7 @@ static drwav_bool32 drwav__on_seek_memory(void* pUserData, int offset, drwav_see if ((drwav_uint32)offset <= memory->dataSize) { memory->currentReadPos = offset; } else { - memory->currentReadPos = memory->dataSize; // Trying to seek too far forward. + return DRWAV_FALSE; // Trying to seek too far forward. } } @@ -2424,7 +2427,7 @@ static void drwav__pcm_to_s16(drwav_int16* pOut, const unsigned char* pIn, size_ // Slightly more optimal implementation for common formats. if (bytesPerSample == 2) { for (unsigned int i = 0; i < totalSampleCount; ++i) { - *pOut++ = ((drwav_int16*)pIn)[i]; + *pOut++ = ((const drwav_int16*)pIn)[i]; } return; } @@ -2464,10 +2467,10 @@ static void drwav__pcm_to_s16(drwav_int16* pOut, const unsigned char* pIn, size_ static void drwav__ieee_to_s16(drwav_int16* pOut, const unsigned char* pIn, size_t totalSampleCount, unsigned short bytesPerSample) { if (bytesPerSample == 4) { - drwav_f32_to_s16(pOut, (float*)pIn, totalSampleCount); + drwav_f32_to_s16(pOut, (const float*)pIn, totalSampleCount); return; } else if (bytesPerSample == 8) { - drwav_f64_to_s16(pOut, (double*)pIn, totalSampleCount); + drwav_f64_to_s16(pOut, (const double*)pIn, totalSampleCount); return; } else { // Only supporting 32- and 64-bit float. Output silence in all other cases. Contributions welcome for 16-bit float. @@ -2614,7 +2617,7 @@ void drwav_s24_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCo { int r; for (size_t i = 0; i < sampleCount; ++i) { - int x = ((int)(((unsigned int)(((unsigned char*)pIn)[i*3+0]) << 8) | ((unsigned int)(((unsigned char*)pIn)[i*3+1]) << 16) | ((unsigned int)(((unsigned char*)pIn)[i*3+2])) << 24)) >> 8; + int x = ((int)(((unsigned int)(((const unsigned char*)pIn)[i*3+0]) << 8) | ((unsigned int)(((const unsigned char*)pIn)[i*3+1]) << 16) | ((unsigned int)(((const unsigned char*)pIn)[i*3+2])) << 24)) >> 8; r = x >> 8; pOut[i] = (short)r; } @@ -2724,11 +2727,11 @@ static void drwav__ieee_to_f32(float* pOut, const unsigned char* pIn, size_t sam { if (bytesPerSample == 4) { for (unsigned int i = 0; i < sampleCount; ++i) { - *pOut++ = ((float*)pIn)[i]; + *pOut++ = ((const float*)pIn)[i]; } return; } else if (bytesPerSample == 8) { - drwav_f64_to_f32(pOut, (double*)pIn, sampleCount); + drwav_f64_to_f32(pOut, (const double*)pIn, sampleCount); return; } else { // Only supporting 32- and 64-bit float. Output silence in all other cases. Contributions welcome for 16-bit float. @@ -3034,7 +3037,7 @@ static void drwav__pcm_to_s32(drwav_int32* pOut, const unsigned char* pIn, size_ } if (bytesPerSample == 4) { for (unsigned int i = 0; i < totalSampleCount; ++i) { - *pOut++ = ((drwav_int32*)pIn)[i]; + *pOut++ = ((const drwav_int32*)pIn)[i]; } return; } @@ -3066,10 +3069,10 @@ static void drwav__pcm_to_s32(drwav_int32* pOut, const unsigned char* pIn, size_ static void drwav__ieee_to_s32(drwav_int32* pOut, const unsigned char* pIn, size_t totalSampleCount, unsigned short bytesPerSample) { if (bytesPerSample == 4) { - drwav_f32_to_s32(pOut, (float*)pIn, totalSampleCount); + drwav_f32_to_s32(pOut, (const float*)pIn, totalSampleCount); return; } else if (bytesPerSample == 8) { - drwav_f64_to_s32(pOut, (double*)pIn, totalSampleCount); + drwav_f64_to_s32(pOut, (const double*)pIn, totalSampleCount); return; } else { // Only supporting 32- and 64-bit float. Output silence in all other cases. Contributions welcome for 16-bit float. @@ -3581,6 +3584,10 @@ void drwav_free(void* pDataReturnedByOpenAndRead) // REVISION HISTORY // +// v0.8.5 - 2018-09-11 +// - Const correctness. +// - Fix a potential stack overflow. +// // v0.8.4 - 2018-08-07 // - Improve 64-bit detection. //