From cc99951fdbda56140222b88a4c228e434c7deaa3 Mon Sep 17 00:00:00 2001 From: David Reid Date: Fri, 10 Dec 2021 19:06:12 +1000 Subject: [PATCH 1/2] Update dr_libs. --- extras/dr_flac.h | 14 +- extras/dr_mp3.h | 155 +++++---- extras/dr_wav.h | 825 +++++++++++++++++++++++++++++++++-------------- miniaudio.h | 676 ++++++++++++++++++++++++++------------ 4 files changed, 1156 insertions(+), 514 deletions(-) diff --git a/extras/dr_flac.h b/extras/dr_flac.h index a797350a..e0b3649a 100644 --- a/extras/dr_flac.h +++ b/extras/dr_flac.h @@ -1,6 +1,6 @@ /* FLAC audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file. -dr_flac - v0.12.29 - 2021-04-02 +dr_flac - v0.12.31 - 2021-08-16 David Reid - mackron@gmail.com @@ -232,7 +232,7 @@ extern "C" { #define DRFLAC_VERSION_MAJOR 0 #define DRFLAC_VERSION_MINOR 12 -#define DRFLAC_VERSION_REVISION 29 +#define DRFLAC_VERSION_REVISION 31 #define DRFLAC_VERSION_STRING DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MAJOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MINOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_REVISION) #include /* For size_t. */ @@ -261,7 +261,7 @@ typedef unsigned int drflac_uint32; #pragma GCC diagnostic pop #endif #endif -#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) +#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(_M_ARM64) || defined(__powerpc64__) typedef drflac_uint64 drflac_uintptr; #else typedef drflac_uint32 drflac_uintptr; @@ -11516,7 +11516,7 @@ static type* drflac__full_read_and_close_ ## extension (drflac* pFlac, unsigned DRFLAC_ZERO_MEMORY(pSampleData + (totalPCMFrameCount*pFlac->channels), (size_t)(sampleDataBufferSize - totalPCMFrameCount*pFlac->channels*sizeof(type))); \ } else { \ drflac_uint64 dataSize = totalPCMFrameCount*pFlac->channels*sizeof(type); \ - if (dataSize > DRFLAC_SIZE_MAX) { \ + if (dataSize > (drflac_uint64)DRFLAC_SIZE_MAX) { \ goto on_error; /* The decoded data is too big. */ \ } \ \ @@ -11851,6 +11851,12 @@ DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterat /* REVISION HISTORY ================ +v0.12.31 - 2021-08-16 + - Silence some warnings. + +v0.12.30 - 2021-07-31 + - Fix platform detection for ARM64. + v0.12.29 - 2021-04-02 - Fix a bug where the running PCM frame index is set to an invalid value when over-seeking. - Fix a decoding error due to an incorrect validation check. diff --git a/extras/dr_mp3.h b/extras/dr_mp3.h index e28f318b..7d752d07 100644 --- a/extras/dr_mp3.h +++ b/extras/dr_mp3.h @@ -1,6 +1,6 @@ /* MP3 audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file. -dr_mp3 - v0.6.27 - 2021-02-21 +dr_mp3 - v0.6.31 - 2021-08-22 David Reid - mackron@gmail.com @@ -95,7 +95,7 @@ extern "C" { #define DRMP3_VERSION_MAJOR 0 #define DRMP3_VERSION_MINOR 6 -#define DRMP3_VERSION_REVISION 27 +#define DRMP3_VERSION_REVISION 31 #define DRMP3_VERSION_STRING DRMP3_XSTRINGIFY(DRMP3_VERSION_MAJOR) "." DRMP3_XSTRINGIFY(DRMP3_VERSION_MINOR) "." DRMP3_XSTRINGIFY(DRMP3_VERSION_REVISION) #include /* For size_t. */ @@ -124,7 +124,7 @@ typedef unsigned int drmp3_uint32; #pragma GCC diagnostic pop #endif #endif -#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) +#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(_M_ARM64) || defined(__powerpc64__) typedef drmp3_uint64 drmp3_uintptr; #else typedef drmp3_uint32 drmp3_uintptr; @@ -701,7 +701,7 @@ static int drmp3_have_simd(void) #if defined(__ARM_ARCH) && (__ARM_ARCH >= 6) && !defined(__aarch64__) && !defined(_M_ARM64) #define DRMP3_HAVE_ARMV6 1 -static __inline__ __attribute__((always_inline)) drmp3_int32 drmp3_clip_int16_arm(int32_t a) +static __inline__ __attribute__((always_inline)) drmp3_int32 drmp3_clip_int16_arm(drmp3_int32 a) { drmp3_int32 x = 0; __asm__ ("ssat %0, #16, %1" : "=r"(x) : "r"(a)); @@ -712,6 +712,31 @@ static __inline__ __attribute__((always_inline)) drmp3_int32 drmp3_clip_int16_ar #endif +/* Standard library stuff. */ +#ifndef DRMP3_ASSERT +#include +#define DRMP3_ASSERT(expression) assert(expression) +#endif +#ifndef DRMP3_COPY_MEMORY +#define DRMP3_COPY_MEMORY(dst, src, sz) memcpy((dst), (src), (sz)) +#endif +#ifndef DRMP3_MOVE_MEMORY +#define DRMP3_MOVE_MEMORY(dst, src, sz) memmove((dst), (src), (sz)) +#endif +#ifndef DRMP3_ZERO_MEMORY +#define DRMP3_ZERO_MEMORY(p, sz) memset((p), 0, (sz)) +#endif +#define DRMP3_ZERO_OBJECT(p) DRMP3_ZERO_MEMORY((p), sizeof(*(p))) +#ifndef DRMP3_MALLOC +#define DRMP3_MALLOC(sz) malloc((sz)) +#endif +#ifndef DRMP3_REALLOC +#define DRMP3_REALLOC(p, sz) realloc((p), (sz)) +#endif +#ifndef DRMP3_FREE +#define DRMP3_FREE(p) free((p)) +#endif + typedef struct { const drmp3_uint8 *buf; @@ -978,7 +1003,7 @@ static int drmp3_L12_dequantize_granule(float *grbuf, drmp3_bs *bs, drmp3_L12_sc static void drmp3_L12_apply_scf_384(drmp3_L12_scale_info *sci, const float *scf, float *dst) { int i, k; - memcpy(dst + 576 + sci->stereo_bands*18, dst + sci->stereo_bands*18, (sci->total_bands - sci->stereo_bands)*18*sizeof(float)); + DRMP3_COPY_MEMORY(dst + 576 + sci->stereo_bands*18, dst + sci->stereo_bands*18, (sci->total_bands - sci->stereo_bands)*18*sizeof(float)); for (i = 0; i < sci->total_bands; i++, dst += 18, scf += 6) { for (k = 0; k < 12; k++) @@ -1123,14 +1148,14 @@ static void drmp3_L3_read_scalefactors(drmp3_uint8 *scf, drmp3_uint8 *ist_pos, c int cnt = scf_count[i]; if (scfsi & 8) { - memcpy(scf, ist_pos, cnt); + DRMP3_COPY_MEMORY(scf, ist_pos, cnt); } else { int bits = scf_size[i]; if (!bits) { - memset(scf, 0, cnt); - memset(ist_pos, 0, cnt); + DRMP3_ZERO_MEMORY(scf, cnt); + DRMP3_ZERO_MEMORY(ist_pos, cnt); } else { int max_scf = (scfsi < 0) ? (1 << bits) - 1 : -1; @@ -1390,12 +1415,22 @@ static void drmp3_L3_midside_stereo(float *left, int n) int i = 0; float *right = left + 576; #if DRMP3_HAVE_SIMD - if (drmp3_have_simd()) for (; i < n - 3; i += 4) + if (drmp3_have_simd()) { - drmp3_f4 vl = DRMP3_VLD(left + i); - drmp3_f4 vr = DRMP3_VLD(right + i); - DRMP3_VSTORE(left + i, DRMP3_VADD(vl, vr)); - DRMP3_VSTORE(right + i, DRMP3_VSUB(vl, vr)); + for (; i < n - 3; i += 4) + { + drmp3_f4 vl = DRMP3_VLD(left + i); + drmp3_f4 vr = DRMP3_VLD(right + i); + DRMP3_VSTORE(left + i, DRMP3_VADD(vl, vr)); + DRMP3_VSTORE(right + i, DRMP3_VSUB(vl, vr)); + } +#ifdef __GNUC__ + /* Workaround for spurious -Waggressive-loop-optimizations warning from gcc. + * For more info see: https://github.com/lieff/minimp3/issues/88 + */ + if (__builtin_constant_p(n % 4 == 0) && n % 4 == 0) + return; +#endif } #endif for (; i < n; i++) @@ -1505,7 +1540,7 @@ static void drmp3_L3_reorder(float *grbuf, float *scratch, const drmp3_uint8 *sf *dst++ = src[2*len]; } } - memcpy(grbuf, scratch, (dst - scratch)*sizeof(float)); + DRMP3_COPY_MEMORY(grbuf, scratch, (dst - scratch)*sizeof(float)); } static void drmp3_L3_antialias(float *grbuf, int nbands) @@ -1674,8 +1709,8 @@ static void drmp3_L3_imdct_short(float *grbuf, float *overlap, int nbands) for (;nbands > 0; nbands--, overlap += 9, grbuf += 18) { float tmp[18]; - memcpy(tmp, grbuf, sizeof(tmp)); - memcpy(grbuf, overlap, 6*sizeof(float)); + DRMP3_COPY_MEMORY(tmp, grbuf, sizeof(tmp)); + DRMP3_COPY_MEMORY(grbuf, overlap, 6*sizeof(float)); drmp3_L3_imdct12(tmp, grbuf + 6, overlap + 6); drmp3_L3_imdct12(tmp + 1, grbuf + 12, overlap + 6); drmp3_L3_imdct12(tmp + 2, overlap, overlap + 6); @@ -1719,7 +1754,7 @@ static void drmp3_L3_save_reservoir(drmp3dec *h, drmp3dec_scratch *s) } if (remains > 0) { - memmove(h->reserv_buf, s->maindata + pos, remains); + DRMP3_MOVE_MEMORY(h->reserv_buf, s->maindata + pos, remains); } h->reserv = remains; } @@ -1728,8 +1763,8 @@ static int drmp3_L3_restore_reservoir(drmp3dec *h, drmp3_bs *bs, drmp3dec_scratc { int frame_bytes = (bs->limit - bs->pos)/8; int bytes_have = DRMP3_MIN(h->reserv, main_data_begin); - memcpy(s->maindata, h->reserv_buf + DRMP3_MAX(0, h->reserv - main_data_begin), DRMP3_MIN(h->reserv, main_data_begin)); - memcpy(s->maindata + bytes_have, bs->buf + bs->pos/8, frame_bytes); + DRMP3_COPY_MEMORY(s->maindata, h->reserv_buf + DRMP3_MAX(0, h->reserv - main_data_begin), DRMP3_MIN(h->reserv, main_data_begin)); + DRMP3_COPY_MEMORY(s->maindata + bytes_have, bs->buf + bs->pos/8, frame_bytes); drmp3_bs_init(&s->bs, s->maindata, bytes_have + frame_bytes); return h->reserv >= main_data_begin; } @@ -2136,7 +2171,7 @@ static void drmp3d_synth_granule(float *qmf_state, float *grbuf, int nbands, int drmp3d_DCT_II(grbuf + 576*i, nbands); } - memcpy(lins, qmf_state, sizeof(float)*15*64); + DRMP3_COPY_MEMORY(lins, qmf_state, sizeof(float)*15*64); for (i = 0; i < nbands; i += 2) { @@ -2152,7 +2187,7 @@ static void drmp3d_synth_granule(float *qmf_state, float *grbuf, int nbands, int } else #endif { - memcpy(qmf_state, lins + nbands*64, sizeof(float)*15*64); + DRMP3_COPY_MEMORY(qmf_state, lins + nbands*64, sizeof(float)*15*64); } } @@ -2230,7 +2265,7 @@ DRMP3_API int drmp3dec_decode_frame(drmp3dec *dec, const drmp3_uint8 *mp3, int m } if (!frame_size) { - memset(dec, 0, sizeof(drmp3dec)); + DRMP3_ZERO_MEMORY(dec, sizeof(drmp3dec)); i = drmp3d_find_frame(mp3, mp3_bytes, &dec->free_format_bytes, &frame_size); if (!frame_size || i + frame_size > mp3_bytes) { @@ -2240,7 +2275,7 @@ DRMP3_API int drmp3dec_decode_frame(drmp3dec *dec, const drmp3_uint8 *mp3, int m } hdr = mp3 + i; - memcpy(dec->header, hdr, DRMP3_HDR_SIZE); + DRMP3_COPY_MEMORY(dec->header, hdr, DRMP3_HDR_SIZE); info->frame_bytes = i + frame_size; info->channels = DRMP3_HDR_IS_MONO(hdr) ? 1 : 2; info->hz = drmp3_hdr_sample_rate_hz(hdr); @@ -2266,7 +2301,7 @@ DRMP3_API int drmp3dec_decode_frame(drmp3dec *dec, const drmp3_uint8 *mp3, int m { for (igr = 0; igr < (DRMP3_HDR_TEST_MPEG1(hdr) ? 2 : 1); igr++, pcm = DRMP3_OFFSET_PTR(pcm, sizeof(drmp3d_sample_t)*576*info->channels)) { - memset(scratch.grbuf[0], 0, 576*2*sizeof(float)); + DRMP3_ZERO_MEMORY(scratch.grbuf[0], 576*2*sizeof(float)); drmp3_L3_decode(dec, &scratch, scratch.gr_info + igr*info->channels, info->channels); drmp3d_synth_granule(dec->qmf_state, scratch.grbuf[0], 18, info->channels, (drmp3d_sample_t*)pcm, scratch.syn[0]); } @@ -2285,7 +2320,7 @@ DRMP3_API int drmp3dec_decode_frame(drmp3dec *dec, const drmp3_uint8 *mp3, int m drmp3_L12_read_scale_info(hdr, bs_frame, sci); - memset(scratch.grbuf[0], 0, 576*2*sizeof(float)); + DRMP3_ZERO_MEMORY(scratch.grbuf[0], 576*2*sizeof(float)); for (i = 0, igr = 0; igr < 3; igr++) { if (12 == (i += drmp3_L12_dequantize_granule(scratch.grbuf[0] + i, bs_frame, sci, info->layer | 1))) @@ -2293,7 +2328,7 @@ DRMP3_API int drmp3dec_decode_frame(drmp3dec *dec, const drmp3_uint8 *mp3, int m i = 0; drmp3_L12_apply_scf_384(sci, sci->scf + igr, scratch.grbuf[0]); drmp3d_synth_granule(dec->qmf_state, scratch.grbuf[0], 12, info->channels, (drmp3d_sample_t*)pcm, scratch.syn[0]); - memset(scratch.grbuf[0], 0, 576*2*sizeof(float)); + DRMP3_ZERO_MEMORY(scratch.grbuf[0], 576*2*sizeof(float)); pcm = DRMP3_OFFSET_PTR(pcm, sizeof(drmp3d_sample_t)*384*info->channels); } if (bs_frame->pos > bs_frame->limit) @@ -2396,28 +2431,6 @@ DRMP3_API void drmp3dec_f32_to_s16(const float *in, drmp3_int16 *out, size_t num #endif -/* Standard library stuff. */ -#ifndef DRMP3_ASSERT -#include -#define DRMP3_ASSERT(expression) assert(expression) -#endif -#ifndef DRMP3_COPY_MEMORY -#define DRMP3_COPY_MEMORY(dst, src, sz) memcpy((dst), (src), (sz)) -#endif -#ifndef DRMP3_ZERO_MEMORY -#define DRMP3_ZERO_MEMORY(p, sz) memset((p), 0, (sz)) -#endif -#define DRMP3_ZERO_OBJECT(p) DRMP3_ZERO_MEMORY((p), sizeof(*(p))) -#ifndef DRMP3_MALLOC -#define DRMP3_MALLOC(sz) malloc((sz)) -#endif -#ifndef DRMP3_REALLOC -#define DRMP3_REALLOC(p, sz) realloc((p), (sz)) -#endif -#ifndef DRMP3_FREE -#define DRMP3_FREE(p) free((p)) -#endif - #define DRMP3_COUNTOF(x) (sizeof(x) / sizeof(x[0])) #define DRMP3_CLAMP(x, lo, hi) (DRMP3_MAX(lo, DRMP3_MIN(x, hi))) @@ -2649,7 +2662,7 @@ static drmp3_uint32 drmp3_decode_next_frame_ex__callbacks(drmp3* pMP3, drmp3d_sa /* First we need to move the data down. */ if (pMP3->pData != NULL) { - memmove(pMP3->pData, pMP3->pData + pMP3->dataConsumed, pMP3->dataSize); + DRMP3_MOVE_MEMORY(pMP3->pData, pMP3->pData + pMP3->dataConsumed, pMP3->dataSize); } pMP3->dataConsumed = 0; @@ -2709,7 +2722,7 @@ static drmp3_uint32 drmp3_decode_next_frame_ex__callbacks(drmp3* pMP3, drmp3d_sa size_t bytesRead; /* First we need to move the data down. */ - memmove(pMP3->pData, pMP3->pData + pMP3->dataConsumed, pMP3->dataSize); + DRMP3_MOVE_MEMORY(pMP3->pData, pMP3->pData + pMP3->dataConsumed, pMP3->dataSize); pMP3->dataConsumed = 0; if (pMP3->dataCapacity == pMP3->dataSize) { @@ -2754,12 +2767,22 @@ static drmp3_uint32 drmp3_decode_next_frame_ex__memory(drmp3* pMP3, drmp3d_sampl return 0; } - pcmFramesRead = drmp3dec_decode_frame(&pMP3->decoder, pMP3->memory.pData + pMP3->memory.currentReadPos, (int)(pMP3->memory.dataSize - pMP3->memory.currentReadPos), pPCMFrames, &info); - if (pcmFramesRead > 0) { - pMP3->pcmFramesConsumedInMP3Frame = 0; - pMP3->pcmFramesRemainingInMP3Frame = pcmFramesRead; - pMP3->mp3FrameChannels = info.channels; - pMP3->mp3FrameSampleRate = info.hz; + for (;;) { + pcmFramesRead = drmp3dec_decode_frame(&pMP3->decoder, pMP3->memory.pData + pMP3->memory.currentReadPos, (int)(pMP3->memory.dataSize - pMP3->memory.currentReadPos), pPCMFrames, &info); + if (pcmFramesRead > 0) { + pcmFramesRead = drmp3_hdr_frame_samples(pMP3->decoder.header); + pMP3->pcmFramesConsumedInMP3Frame = 0; + pMP3->pcmFramesRemainingInMP3Frame = pcmFramesRead; + pMP3->mp3FrameChannels = info.channels; + pMP3->mp3FrameSampleRate = info.hz; + break; + } else if (info.frame_bytes > 0) { + /* No frames were read, but it looks like we skipped past one. Read the next MP3 frame. */ + pMP3->memory.currentReadPos += (size_t)info.frame_bytes; + } else { + /* Nothing at all was read. Abort. */ + break; + } } /* Consume the data. */ @@ -2822,7 +2845,7 @@ static drmp3_bool32 drmp3_init_internal(drmp3* pMP3, drmp3_read_proc onRead, drm } /* Decode the first frame to confirm that it is indeed a valid MP3 stream. */ - if (!drmp3_decode_next_frame(pMP3)) { + if (drmp3_decode_next_frame(pMP3) == 0) { drmp3__free_from_callbacks(pMP3->pData, &pMP3->allocationCallbacks); /* The call above may have allocated memory. Need to make sure it's freed before aborting. */ return DRMP3_FALSE; /* Not a valid MP3 stream. */ } @@ -4177,7 +4200,7 @@ static float* drmp3__full_read_and_close_f32(drmp3* pMP3, drmp3_config* pConfig, oldFramesBufferSize = framesCapacity * pMP3->channels * sizeof(float); newFramesBufferSize = newFramesCap * pMP3->channels * sizeof(float); - if (newFramesBufferSize > DRMP3_SIZE_MAX) { + if (newFramesBufferSize > (drmp3_uint64)DRMP3_SIZE_MAX) { break; } @@ -4244,7 +4267,7 @@ static drmp3_int16* drmp3__full_read_and_close_s16(drmp3* pMP3, drmp3_config* pC oldFramesBufferSize = framesCapacity * pMP3->channels * sizeof(drmp3_int16); newFramesBufferSize = newFramesCap * pMP3->channels * sizeof(drmp3_int16); - if (newFramesBufferSize > DRMP3_SIZE_MAX) { + if (newFramesBufferSize > (drmp3_uint64)DRMP3_SIZE_MAX) { break; } @@ -4450,6 +4473,20 @@ counts rather than sample counts. /* REVISION HISTORY ================ +v0.6.31 - 2021-08-22 + - Fix a bug when loading from memory. + +v0.6.30 - 2021-08-16 + - Silence some warnings. + - Replace memory operations with DRMP3_* macros. + +v0.6.29 - 2021-08-08 + - Bring up to date with minimp3. + +v0.6.28 - 2021-07-31 + - Fix platform detection for ARM64. + - Fix a compilation error with C89. + v0.6.27 - 2021-02-21 - Fix a warning due to referencing _MSC_VER when it is undefined. diff --git a/extras/dr_wav.h b/extras/dr_wav.h index 7e50e4b1..a119d66a 100644 --- a/extras/dr_wav.h +++ b/extras/dr_wav.h @@ -1,6 +1,6 @@ /* WAV audio loader and writer. Choice of public domain or MIT-0. See license statements at the end of this file. -dr_wav - v0.13.0 - 2021-07-01 +dr_wav - v0.13.4 - 2021-12-08 David Reid - mackron@gmail.com @@ -125,7 +125,7 @@ extern "C" { #define DRWAV_VERSION_MAJOR 0 #define DRWAV_VERSION_MINOR 13 -#define DRWAV_VERSION_REVISION 0 +#define DRWAV_VERSION_REVISION 4 #define DRWAV_VERSION_STRING DRWAV_XSTRINGIFY(DRWAV_VERSION_MAJOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_MINOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_REVISION) #include /* For size_t. */ @@ -154,7 +154,7 @@ typedef unsigned int drwav_uint32; #pragma GCC diagnostic pop #endif #endif -#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) +#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(_M_ARM64) || defined(__powerpc64__) typedef drwav_uint64 drwav_uintptr; #else typedef drwav_uint32 drwav_uintptr; @@ -1335,6 +1335,7 @@ DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b); #define drwav_min(a, b) (((a) < (b)) ? (a) : (b)) #define drwav_max(a, b) (((a) > (b)) ? (a) : (b)) #define drwav_clamp(x, lo, hi) (drwav_max((lo), drwav_min((hi), (x)))) +#define drwav_offset_ptr(p, offset) (((drwav_uint8*)(p)) + (offset)) #define DRWAV_MAX_SIMD_VECTOR_SIZE 64 /* 64 for AVX-512 in the future. */ @@ -1633,6 +1634,10 @@ static DRWAV_INLINE void drwav__bswap_samples_pcm(void* pSamples, drwav_uint64 s /* Assumes integer PCM. Floating point PCM is done in drwav__bswap_samples_ieee(). */ switch (bytesPerSample) { + case 1: /* u8 */ + { + /* no-op. */ + } break; case 2: /* s16, s12 (loosely packed) */ { drwav__bswap_samples_s16((drwav_int16*)pSamples, sampleCount); @@ -2162,13 +2167,14 @@ DRWAV_PRIVATE size_t drwav__metadata_parser_read(drwav__metadata_parser* pParser } } -DRWAV_PRIVATE drwav_uint64 drwav__read_smpl_to_metadata_obj(drwav__metadata_parser* pParser, drwav_metadata* pMetadata) +DRWAV_PRIVATE drwav_uint64 drwav__read_smpl_to_metadata_obj(drwav__metadata_parser* pParser, const drwav_chunk_header* pChunkHeader, drwav_metadata* pMetadata) { drwav_uint8 smplHeaderData[DRWAV_SMPL_BYTES]; drwav_uint64 totalBytesRead = 0; size_t bytesJustRead = drwav__metadata_parser_read(pParser, smplHeaderData, sizeof(smplHeaderData), &totalBytesRead); DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read); + DRWAV_ASSERT(pChunkHeader != NULL); if (bytesJustRead == sizeof(smplHeaderData)) { drwav_uint32 iSampleLoop; @@ -2183,36 +2189,43 @@ DRWAV_PRIVATE drwav_uint64 drwav__read_smpl_to_metadata_obj(drwav__metadata_pars pMetadata->data.smpl.smpteOffset = drwav_bytes_to_u32(smplHeaderData + 24); pMetadata->data.smpl.sampleLoopCount = drwav_bytes_to_u32(smplHeaderData + 28); pMetadata->data.smpl.samplerSpecificDataSizeInBytes = drwav_bytes_to_u32(smplHeaderData + 32); - pMetadata->data.smpl.pLoops = (drwav_smpl_loop*)drwav__metadata_get_memory(pParser, sizeof(drwav_smpl_loop) * pMetadata->data.smpl.sampleLoopCount, DRWAV_METADATA_ALIGNMENT); - for (iSampleLoop = 0; iSampleLoop < pMetadata->data.smpl.sampleLoopCount; ++iSampleLoop) { - drwav_uint8 smplLoopData[DRWAV_SMPL_LOOP_BYTES]; - bytesJustRead = drwav__metadata_parser_read(pParser, smplLoopData, sizeof(smplLoopData), &totalBytesRead); + /* + The loop count needs to be validated against the size of the chunk for safety so we don't + attempt to read over the boundary of the chunk. + */ + if (pMetadata->data.smpl.sampleLoopCount == (pChunkHeader->sizeInBytes - DRWAV_SMPL_BYTES) / DRWAV_SMPL_LOOP_BYTES) { + pMetadata->data.smpl.pLoops = (drwav_smpl_loop*)drwav__metadata_get_memory(pParser, sizeof(drwav_smpl_loop) * pMetadata->data.smpl.sampleLoopCount, DRWAV_METADATA_ALIGNMENT); - if (bytesJustRead == sizeof(smplLoopData)) { - pMetadata->data.smpl.pLoops[iSampleLoop].cuePointId = drwav_bytes_to_u32(smplLoopData + 0); - pMetadata->data.smpl.pLoops[iSampleLoop].type = drwav_bytes_to_u32(smplLoopData + 4); - pMetadata->data.smpl.pLoops[iSampleLoop].firstSampleByteOffset = drwav_bytes_to_u32(smplLoopData + 8); - pMetadata->data.smpl.pLoops[iSampleLoop].lastSampleByteOffset = drwav_bytes_to_u32(smplLoopData + 12); - pMetadata->data.smpl.pLoops[iSampleLoop].sampleFraction = drwav_bytes_to_u32(smplLoopData + 16); - pMetadata->data.smpl.pLoops[iSampleLoop].playCount = drwav_bytes_to_u32(smplLoopData + 20); - } else { - break; + for (iSampleLoop = 0; iSampleLoop < pMetadata->data.smpl.sampleLoopCount; ++iSampleLoop) { + drwav_uint8 smplLoopData[DRWAV_SMPL_LOOP_BYTES]; + bytesJustRead = drwav__metadata_parser_read(pParser, smplLoopData, sizeof(smplLoopData), &totalBytesRead); + + if (bytesJustRead == sizeof(smplLoopData)) { + pMetadata->data.smpl.pLoops[iSampleLoop].cuePointId = drwav_bytes_to_u32(smplLoopData + 0); + pMetadata->data.smpl.pLoops[iSampleLoop].type = drwav_bytes_to_u32(smplLoopData + 4); + pMetadata->data.smpl.pLoops[iSampleLoop].firstSampleByteOffset = drwav_bytes_to_u32(smplLoopData + 8); + pMetadata->data.smpl.pLoops[iSampleLoop].lastSampleByteOffset = drwav_bytes_to_u32(smplLoopData + 12); + pMetadata->data.smpl.pLoops[iSampleLoop].sampleFraction = drwav_bytes_to_u32(smplLoopData + 16); + pMetadata->data.smpl.pLoops[iSampleLoop].playCount = drwav_bytes_to_u32(smplLoopData + 20); + } else { + break; + } } - } - if (pMetadata->data.smpl.samplerSpecificDataSizeInBytes > 0) { - pMetadata->data.smpl.pSamplerSpecificData = drwav__metadata_get_memory(pParser, pMetadata->data.smpl.samplerSpecificDataSizeInBytes, 1); - DRWAV_ASSERT(pMetadata->data.smpl.pSamplerSpecificData != NULL); + if (pMetadata->data.smpl.samplerSpecificDataSizeInBytes > 0) { + pMetadata->data.smpl.pSamplerSpecificData = drwav__metadata_get_memory(pParser, pMetadata->data.smpl.samplerSpecificDataSizeInBytes, 1); + DRWAV_ASSERT(pMetadata->data.smpl.pSamplerSpecificData != NULL); - bytesJustRead = drwav__metadata_parser_read(pParser, pMetadata->data.smpl.pSamplerSpecificData, pMetadata->data.smpl.samplerSpecificDataSizeInBytes, &totalBytesRead); + drwav__metadata_parser_read(pParser, pMetadata->data.smpl.pSamplerSpecificData, pMetadata->data.smpl.samplerSpecificDataSizeInBytes, &totalBytesRead); + } } } return totalBytesRead; } -DRWAV_PRIVATE drwav_uint64 drwav__read_cue_to_metadata_obj(drwav__metadata_parser* pParser, drwav_metadata* pMetadata) +DRWAV_PRIVATE drwav_uint64 drwav__read_cue_to_metadata_obj(drwav__metadata_parser* pParser, const drwav_chunk_header* pChunkHeader, drwav_metadata* pMetadata) { drwav_uint8 cueHeaderSectionData[DRWAV_CUE_BYTES]; drwav_uint64 totalBytesRead = 0; @@ -2223,28 +2236,35 @@ DRWAV_PRIVATE drwav_uint64 drwav__read_cue_to_metadata_obj(drwav__metadata_parse if (bytesJustRead == sizeof(cueHeaderSectionData)) { pMetadata->type = drwav_metadata_type_cue; pMetadata->data.cue.cuePointCount = drwav_bytes_to_u32(cueHeaderSectionData); - pMetadata->data.cue.pCuePoints = (drwav_cue_point*)drwav__metadata_get_memory(pParser, sizeof(drwav_cue_point) * pMetadata->data.cue.cuePointCount, DRWAV_METADATA_ALIGNMENT); - DRWAV_ASSERT(pMetadata->data.cue.pCuePoints != NULL); - if (pMetadata->data.cue.cuePointCount > 0) { - drwav_uint32 iCuePoint; + /* + We need to validate the cue point count against the size of the chunk so we don't read + beyond the chunk. + */ + if (pMetadata->data.cue.cuePointCount == (pChunkHeader->sizeInBytes - DRWAV_CUE_BYTES) / DRWAV_CUE_POINT_BYTES) { + pMetadata->data.cue.pCuePoints = (drwav_cue_point*)drwav__metadata_get_memory(pParser, sizeof(drwav_cue_point) * pMetadata->data.cue.cuePointCount, DRWAV_METADATA_ALIGNMENT); + DRWAV_ASSERT(pMetadata->data.cue.pCuePoints != NULL); - for (iCuePoint = 0; iCuePoint < pMetadata->data.cue.cuePointCount; ++iCuePoint) { - drwav_uint8 cuePointData[DRWAV_CUE_POINT_BYTES]; - bytesJustRead = drwav__metadata_parser_read(pParser, cuePointData, sizeof(cuePointData), &totalBytesRead); + if (pMetadata->data.cue.cuePointCount > 0) { + drwav_uint32 iCuePoint; - if (bytesJustRead == sizeof(cuePointData)) { - pMetadata->data.cue.pCuePoints[iCuePoint].id = drwav_bytes_to_u32(cuePointData + 0); - pMetadata->data.cue.pCuePoints[iCuePoint].playOrderPosition = drwav_bytes_to_u32(cuePointData + 4); - pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[0] = cuePointData[8]; - pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[1] = cuePointData[9]; - pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[2] = cuePointData[10]; - pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[3] = cuePointData[11]; - pMetadata->data.cue.pCuePoints[iCuePoint].chunkStart = drwav_bytes_to_u32(cuePointData + 12); - pMetadata->data.cue.pCuePoints[iCuePoint].blockStart = drwav_bytes_to_u32(cuePointData + 16); - pMetadata->data.cue.pCuePoints[iCuePoint].sampleByteOffset = drwav_bytes_to_u32(cuePointData + 20); - } else { - break; + for (iCuePoint = 0; iCuePoint < pMetadata->data.cue.cuePointCount; ++iCuePoint) { + drwav_uint8 cuePointData[DRWAV_CUE_POINT_BYTES]; + bytesJustRead = drwav__metadata_parser_read(pParser, cuePointData, sizeof(cuePointData), &totalBytesRead); + + if (bytesJustRead == sizeof(cuePointData)) { + pMetadata->data.cue.pCuePoints[iCuePoint].id = drwav_bytes_to_u32(cuePointData + 0); + pMetadata->data.cue.pCuePoints[iCuePoint].playOrderPosition = drwav_bytes_to_u32(cuePointData + 4); + pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[0] = cuePointData[8]; + pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[1] = cuePointData[9]; + pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[2] = cuePointData[10]; + pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[3] = cuePointData[11]; + pMetadata->data.cue.pCuePoints[iCuePoint].chunkStart = drwav_bytes_to_u32(cuePointData + 12); + pMetadata->data.cue.pCuePoints[iCuePoint].blockStart = drwav_bytes_to_u32(cuePointData + 16); + pMetadata->data.cue.pCuePoints[iCuePoint].sampleByteOffset = drwav_bytes_to_u32(cuePointData + 20); + } else { + break; + } } } } @@ -2296,7 +2316,7 @@ DRWAV_PRIVATE drwav_uint64 drwav__read_acid_to_metadata_obj(drwav__metadata_pars return bytesRead; } -DRWAV_PRIVATE size_t drwav__strlen_clamped(char* str, size_t maxToRead) +DRWAV_PRIVATE size_t drwav__strlen_clamped(const char* str, size_t maxToRead) { size_t result = 0; @@ -2307,7 +2327,7 @@ DRWAV_PRIVATE size_t drwav__strlen_clamped(char* str, size_t maxToRead) return result; } -DRWAV_PRIVATE char* drwav__metadata_copy_string(drwav__metadata_parser* pParser, char* str, size_t maxToRead) +DRWAV_PRIVATE char* drwav__metadata_copy_string(drwav__metadata_parser* pParser, const char* str, size_t maxToRead) { size_t len = drwav__strlen_clamped(str, maxToRead); @@ -2324,77 +2344,183 @@ DRWAV_PRIVATE char* drwav__metadata_copy_string(drwav__metadata_parser* pParser, } } +typedef struct +{ + const void* pBuffer; + size_t sizeInBytes; + size_t cursor; +} drwav_buffer_reader; + +DRWAV_PRIVATE drwav_result drwav_buffer_reader_init(const void* pBuffer, size_t sizeInBytes, drwav_buffer_reader* pReader) +{ + DRWAV_ASSERT(pBuffer != NULL); + DRWAV_ASSERT(pReader != NULL); + + DRWAV_ZERO_OBJECT(pReader); + + pReader->pBuffer = pBuffer; + pReader->sizeInBytes = sizeInBytes; + pReader->cursor = 0; + + return DRWAV_SUCCESS; +} + +DRWAV_PRIVATE const void* drwav_buffer_reader_ptr(const drwav_buffer_reader* pReader) +{ + DRWAV_ASSERT(pReader != NULL); + + return drwav_offset_ptr(pReader->pBuffer, pReader->cursor); +} + +DRWAV_PRIVATE drwav_result drwav_buffer_reader_seek(drwav_buffer_reader* pReader, size_t bytesToSeek) +{ + DRWAV_ASSERT(pReader != NULL); + + if (pReader->cursor + bytesToSeek > pReader->sizeInBytes) { + return DRWAV_BAD_SEEK; /* Seeking too far forward. */ + } + + pReader->cursor += bytesToSeek; + + return DRWAV_SUCCESS; +} + +DRWAV_PRIVATE drwav_result drwav_buffer_reader_read(drwav_buffer_reader* pReader, void* pDst, size_t bytesToRead, size_t* pBytesRead) +{ + drwav_result result = DRWAV_SUCCESS; + size_t bytesRemaining; + + DRWAV_ASSERT(pReader != NULL); + + if (pBytesRead != NULL) { + *pBytesRead = 0; + } + + bytesRemaining = (pReader->sizeInBytes - pReader->cursor); + if (bytesToRead > bytesRemaining) { + bytesToRead = bytesRemaining; + } + + if (pDst == NULL) { + /* Seek. */ + result = drwav_buffer_reader_seek(pReader, bytesToRead); + } else { + /* Read. */ + DRWAV_COPY_MEMORY(pDst, drwav_buffer_reader_ptr(pReader), bytesToRead); + pReader->cursor += bytesToRead; + } + + DRWAV_ASSERT(pReader->cursor <= pReader->sizeInBytes); + + if (result == DRWAV_SUCCESS) { + if (pBytesRead != NULL) { + *pBytesRead = bytesToRead; + } + } + + return DRWAV_SUCCESS; +} + +DRWAV_PRIVATE drwav_result drwav_buffer_reader_read_u16(drwav_buffer_reader* pReader, drwav_uint16* pDst) +{ + drwav_result result; + size_t bytesRead; + drwav_uint8 data[2]; + + DRWAV_ASSERT(pReader != NULL); + DRWAV_ASSERT(pDst != NULL); + + *pDst = 0; /* Safety. */ + + result = drwav_buffer_reader_read(pReader, data, sizeof(*pDst), &bytesRead); + if (result != DRWAV_SUCCESS || bytesRead != sizeof(*pDst)) { + return result; + } + + *pDst = drwav_bytes_to_u16(data); + + return DRWAV_SUCCESS; +} + +DRWAV_PRIVATE drwav_result drwav_buffer_reader_read_u32(drwav_buffer_reader* pReader, drwav_uint32* pDst) +{ + drwav_result result; + size_t bytesRead; + drwav_uint8 data[4]; + + DRWAV_ASSERT(pReader != NULL); + DRWAV_ASSERT(pDst != NULL); + + *pDst = 0; /* Safety. */ + + result = drwav_buffer_reader_read(pReader, data, sizeof(*pDst), &bytesRead); + if (result != DRWAV_SUCCESS || bytesRead != sizeof(*pDst)) { + return result; + } + + *pDst = drwav_bytes_to_u32(data); + + return DRWAV_SUCCESS; +} + + + DRWAV_PRIVATE drwav_uint64 drwav__read_bext_to_metadata_obj(drwav__metadata_parser* pParser, drwav_metadata* pMetadata, drwav_uint64 chunkSize) { drwav_uint8 bextData[DRWAV_BEXT_BYTES]; - drwav_uint64 bytesRead = drwav__metadata_parser_read(pParser, bextData, sizeof(bextData), NULL); + size_t bytesRead = drwav__metadata_parser_read(pParser, bextData, sizeof(bextData), NULL); DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read); if (bytesRead == sizeof(bextData)) { - drwav_uint8* pReadPointer; + drwav_buffer_reader reader; drwav_uint32 timeReferenceLow; drwav_uint32 timeReferenceHigh; size_t extraBytes; pMetadata->type = drwav_metadata_type_bext; - pReadPointer = bextData; - pMetadata->data.bext.pDescription = drwav__metadata_copy_string(pParser, (char*)(pReadPointer), DRWAV_BEXT_DESCRIPTION_BYTES); - pReadPointer += DRWAV_BEXT_DESCRIPTION_BYTES; + if (drwav_buffer_reader_init(bextData, bytesRead, &reader) == DRWAV_SUCCESS) { + pMetadata->data.bext.pDescription = drwav__metadata_copy_string(pParser, (const char*)drwav_buffer_reader_ptr(&reader), DRWAV_BEXT_DESCRIPTION_BYTES); + drwav_buffer_reader_seek(&reader, DRWAV_BEXT_DESCRIPTION_BYTES); - pMetadata->data.bext.pOriginatorName = drwav__metadata_copy_string(pParser, (char*)(pReadPointer), DRWAV_BEXT_ORIGINATOR_NAME_BYTES); - pReadPointer += DRWAV_BEXT_ORIGINATOR_NAME_BYTES; + pMetadata->data.bext.pOriginatorName = drwav__metadata_copy_string(pParser, (const char*)drwav_buffer_reader_ptr(&reader), DRWAV_BEXT_ORIGINATOR_NAME_BYTES); + drwav_buffer_reader_seek(&reader, DRWAV_BEXT_ORIGINATOR_NAME_BYTES); - pMetadata->data.bext.pOriginatorReference = drwav__metadata_copy_string(pParser, (char*)(pReadPointer), DRWAV_BEXT_ORIGINATOR_REF_BYTES); - pReadPointer += DRWAV_BEXT_ORIGINATOR_REF_BYTES; + pMetadata->data.bext.pOriginatorReference = drwav__metadata_copy_string(pParser, (const char*)drwav_buffer_reader_ptr(&reader), DRWAV_BEXT_ORIGINATOR_REF_BYTES); + drwav_buffer_reader_seek(&reader, DRWAV_BEXT_ORIGINATOR_REF_BYTES); - memcpy(pReadPointer, pMetadata->data.bext.pOriginationDate, sizeof(pMetadata->data.bext.pOriginationDate)); - pReadPointer += sizeof(pMetadata->data.bext.pOriginationDate); + drwav_buffer_reader_read(&reader, pMetadata->data.bext.pOriginationDate, sizeof(pMetadata->data.bext.pOriginationDate), NULL); + drwav_buffer_reader_read(&reader, pMetadata->data.bext.pOriginationTime, sizeof(pMetadata->data.bext.pOriginationTime), NULL); - memcpy(pReadPointer, pMetadata->data.bext.pOriginationTime, sizeof(pMetadata->data.bext.pOriginationTime)); - pReadPointer += sizeof(pMetadata->data.bext.pOriginationTime); + drwav_buffer_reader_read_u32(&reader, &timeReferenceLow); + drwav_buffer_reader_read_u32(&reader, &timeReferenceHigh); + pMetadata->data.bext.timeReference = ((drwav_uint64)timeReferenceHigh << 32) + timeReferenceLow; - timeReferenceLow = drwav_bytes_to_u32(pReadPointer); - pReadPointer += sizeof(drwav_uint32); - timeReferenceHigh = drwav_bytes_to_u32(pReadPointer); - pReadPointer += sizeof(drwav_uint32); - pMetadata->data.bext.timeReference = ((drwav_uint64)timeReferenceHigh << 32) + timeReferenceLow; + drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.version); - pMetadata->data.bext.version = drwav_bytes_to_u16(pReadPointer); - pReadPointer += sizeof(drwav_uint16); + pMetadata->data.bext.pUMID = drwav__metadata_get_memory(pParser, DRWAV_BEXT_UMID_BYTES, 1); + drwav_buffer_reader_read(&reader, pMetadata->data.bext.pUMID, DRWAV_BEXT_UMID_BYTES, NULL); - pMetadata->data.bext.pUMID = drwav__metadata_get_memory(pParser, DRWAV_BEXT_UMID_BYTES, 1); - memcpy(pMetadata->data.bext.pUMID, pReadPointer, DRWAV_BEXT_UMID_BYTES); - pReadPointer += DRWAV_BEXT_UMID_BYTES; + drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.loudnessValue); + drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.loudnessRange); + drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.maxTruePeakLevel); + drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.maxMomentaryLoudness); + drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.maxShortTermLoudness); - pMetadata->data.bext.loudnessValue = drwav_bytes_to_u16(pReadPointer); - pReadPointer += sizeof(drwav_uint16); + DRWAV_ASSERT((drwav_offset_ptr(drwav_buffer_reader_ptr(&reader), DRWAV_BEXT_RESERVED_BYTES)) == (bextData + DRWAV_BEXT_BYTES)); - pMetadata->data.bext.loudnessRange = drwav_bytes_to_u16(pReadPointer); - pReadPointer += sizeof(drwav_uint16); + extraBytes = (size_t)(chunkSize - DRWAV_BEXT_BYTES); + if (extraBytes > 0) { + pMetadata->data.bext.pCodingHistory = (char*)drwav__metadata_get_memory(pParser, extraBytes + 1, 1); + DRWAV_ASSERT(pMetadata->data.bext.pCodingHistory != NULL); - pMetadata->data.bext.maxTruePeakLevel = drwav_bytes_to_u16(pReadPointer); - pReadPointer += sizeof(drwav_uint16); - - pMetadata->data.bext.maxMomentaryLoudness = drwav_bytes_to_u16(pReadPointer); - pReadPointer += sizeof(drwav_uint16); - - pMetadata->data.bext.maxShortTermLoudness = drwav_bytes_to_u16(pReadPointer); - pReadPointer += sizeof(drwav_uint16); - - DRWAV_ASSERT((pReadPointer + DRWAV_BEXT_RESERVED_BYTES) == (bextData + DRWAV_BEXT_BYTES)); - - extraBytes = (size_t)(chunkSize - DRWAV_BEXT_BYTES); - if (extraBytes > 0) { - pMetadata->data.bext.pCodingHistory = (char*)drwav__metadata_get_memory(pParser, extraBytes + 1, 1); - DRWAV_ASSERT(pMetadata->data.bext.pCodingHistory != NULL); - - bytesRead += drwav__metadata_parser_read(pParser, pMetadata->data.bext.pCodingHistory, extraBytes, NULL); - pMetadata->data.bext.codingHistorySize = (drwav_uint32)strlen(pMetadata->data.bext.pCodingHistory); - } else { - pMetadata->data.bext.pCodingHistory = NULL; - pMetadata->data.bext.codingHistorySize = 0; + bytesRead += drwav__metadata_parser_read(pParser, pMetadata->data.bext.pCodingHistory, extraBytes, NULL); + pMetadata->data.bext.codingHistorySize = (drwav_uint32)strlen(pMetadata->data.bext.pCodingHistory); + } else { + pMetadata->data.bext.pCodingHistory = NULL; + pMetadata->data.bext.codingHistorySize = 0; + } } } @@ -2421,7 +2547,7 @@ DRWAV_PRIVATE drwav_uint64 drwav__read_list_label_or_note_to_metadata_obj(drwav_ pMetadata->data.labelOrNote.pString = (char*)drwav__metadata_get_memory(pParser, sizeIncludingNullTerminator, 1); DRWAV_ASSERT(pMetadata->data.labelOrNote.pString != NULL); - bytesJustRead = drwav__metadata_parser_read(pParser, pMetadata->data.labelOrNote.pString, sizeIncludingNullTerminator, &totalBytesRead); + drwav__metadata_parser_read(pParser, pMetadata->data.labelOrNote.pString, sizeIncludingNullTerminator, &totalBytesRead); } else { pMetadata->data.labelOrNote.stringLength = 0; pMetadata->data.labelOrNote.pString = NULL; @@ -2460,7 +2586,7 @@ DRWAV_PRIVATE drwav_uint64 drwav__read_list_labelled_cue_region_to_metadata_obj( pMetadata->data.labelledCueRegion.pString = (char*)drwav__metadata_get_memory(pParser, sizeIncludingNullTerminator, 1); DRWAV_ASSERT(pMetadata->data.labelledCueRegion.pString != NULL); - bytesJustRead = drwav__metadata_parser_read(pParser, pMetadata->data.labelledCueRegion.pString, sizeIncludingNullTerminator, &totalBytesRead); + drwav__metadata_parser_read(pParser, pMetadata->data.labelledCueRegion.pString, sizeIncludingNullTerminator, &totalBytesRead); } else { pMetadata->data.labelledCueRegion.stringLength = 0; pMetadata->data.labelledCueRegion.pString = NULL; @@ -2540,12 +2666,12 @@ DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_unknown_chunk(drwav__metadata return bytesRead; } -DRWAV_PRIVATE drwav_bool32 drwav__chunk_matches(drwav_uint64 allowedMetadataTypes, const drwav_uint8* pChunkID, drwav_metadata_type type, const char* pID) +DRWAV_PRIVATE drwav_bool32 drwav__chunk_matches(drwav_metadata_type allowedMetadataTypes, const drwav_uint8* pChunkID, drwav_metadata_type type, const char* pID) { return (allowedMetadataTypes & type) && drwav_fourcc_equal(pChunkID, pID); } -DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_chunk(drwav__metadata_parser* pParser, const drwav_chunk_header* pChunkHeader, drwav_uint64 allowedMetadataTypes) +DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_chunk(drwav__metadata_parser* pParser, const drwav_chunk_header* pChunkHeader, drwav_metadata_type allowedMetadataTypes) { const drwav_uint8 *pChunkID = pChunkHeader->id.fourcc; drwav_uint64 bytesRead = 0; @@ -2564,18 +2690,25 @@ DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_chunk(drwav__metadata_parser* bytesJustRead = drwav__metadata_parser_read(pParser, buffer, sizeof(buffer), &bytesRead); if (bytesJustRead == sizeof(buffer)) { drwav_uint32 loopCount = drwav_bytes_to_u32(buffer); + drwav_uint64 calculatedLoopCount; - bytesJustRead = drwav__metadata_parser_read(pParser, buffer, sizeof(buffer), &bytesRead); - if (bytesJustRead == sizeof(buffer)) { - drwav_uint32 samplerSpecificDataSizeInBytes = drwav_bytes_to_u32(buffer); + /* The loop count must be validated against the size of the chunk. */ + calculatedLoopCount = (pChunkHeader->sizeInBytes - DRWAV_SMPL_BYTES) / DRWAV_SMPL_LOOP_BYTES; + if (calculatedLoopCount == loopCount) { + bytesJustRead = drwav__metadata_parser_read(pParser, buffer, sizeof(buffer), &bytesRead); + if (bytesJustRead == sizeof(buffer)) { + drwav_uint32 samplerSpecificDataSizeInBytes = drwav_bytes_to_u32(buffer); - pParser->metadataCount += 1; - drwav__metadata_request_extra_memory_for_stage_2(pParser, sizeof(drwav_smpl_loop) * loopCount, DRWAV_METADATA_ALIGNMENT); - drwav__metadata_request_extra_memory_for_stage_2(pParser, samplerSpecificDataSizeInBytes, 1); - } + pParser->metadataCount += 1; + drwav__metadata_request_extra_memory_for_stage_2(pParser, sizeof(drwav_smpl_loop) * loopCount, DRWAV_METADATA_ALIGNMENT); + drwav__metadata_request_extra_memory_for_stage_2(pParser, samplerSpecificDataSizeInBytes, 1); + } + } else { + /* Loop count in header does not match the size of the chunk. */ + } } } else { - bytesRead = drwav__read_smpl_to_metadata_obj(pParser, &pParser->pMetadata[pParser->metadataCursor]); + bytesRead = drwav__read_smpl_to_metadata_obj(pParser, pChunkHeader, &pParser->pMetadata[pParser->metadataCursor]); if (bytesRead == pChunkHeader->sizeInBytes) { pParser->metadataCursor += 1; } else { @@ -2624,7 +2757,7 @@ DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_chunk(drwav__metadata_parser* cueCount = (size_t)(pChunkHeader->sizeInBytes - DRWAV_CUE_BYTES) / DRWAV_CUE_POINT_BYTES; drwav__metadata_request_extra_memory_for_stage_2(pParser, sizeof(drwav_cue_point) * cueCount, DRWAV_METADATA_ALIGNMENT); } else { - bytesRead = drwav__read_cue_to_metadata_obj(pParser, &pParser->pMetadata[pParser->metadataCursor]); + bytesRead = drwav__read_cue_to_metadata_obj(pParser, pChunkHeader, &pParser->pMetadata[pParser->metadataCursor]); if (bytesRead == pChunkHeader->sizeInBytes) { pParser->metadataCursor += 1; } else { @@ -2767,7 +2900,7 @@ DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_chunk(drwav__metadata_parser* subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize, drwav_metadata_type_list_info_album); } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_tracknumber, "ITRK")) { subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize, drwav_metadata_type_list_info_tracknumber); - } else if (allowedMetadataTypes & drwav_metadata_type_unknown) { + } else if ((allowedMetadataTypes & drwav_metadata_type_unknown) != 0) { subchunkBytesRead = drwav__metadata_process_unknown_chunk(pParser, subchunkId, subchunkDataSize, listType); } @@ -2790,7 +2923,7 @@ DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_chunk(drwav__metadata_parser* bytesRead += 1; } } - } else if (allowedMetadataTypes & drwav_metadata_type_unknown) { + } else if ((allowedMetadataTypes & drwav_metadata_type_unknown) != 0) { bytesRead = drwav__metadata_process_unknown_chunk(pParser, pChunkID, pChunkHeader->sizeInBytes, drwav_metadata_location_top_level); } @@ -2800,16 +2933,27 @@ DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_chunk(drwav__metadata_parser* DRWAV_PRIVATE drwav_uint32 drwav_get_bytes_per_pcm_frame(drwav* pWav) { + drwav_uint32 bytesPerFrame; + /* The bytes per frame is a bit ambiguous. It can be either be based on the bits per sample, or the block align. The way I'm doing it here is that if the bits per sample is a multiple of 8, use floor(bitsPerSample*channels/8), otherwise fall back to the block align. */ if ((pWav->bitsPerSample & 0x7) == 0) { /* Bits per sample is a multiple of 8. */ - return (pWav->bitsPerSample * pWav->fmt.channels) >> 3; + bytesPerFrame = (pWav->bitsPerSample * pWav->fmt.channels) >> 3; } else { - return pWav->fmt.blockAlign; + bytesPerFrame = pWav->fmt.blockAlign; } + + /* Validation for known formats. a-law and mu-law should be 1 byte per channel. If it's not, it's not decodable. */ + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW || pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) { + if (bytesPerFrame != pWav->fmt.channels) { + return 0; /* Invalid file. */ + } + } + + return bytesPerFrame; } DRWAV_API drwav_uint16 drwav_fmt_get_format(const drwav_fmt* pFMT) @@ -3207,7 +3351,12 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on if (sampleCountFromFactChunk != 0) { pWav->totalPCMFrameCount = sampleCountFromFactChunk; } else { - pWav->totalPCMFrameCount = dataChunkSize / drwav_get_bytes_per_pcm_frame(pWav); + drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return DRWAV_FALSE; /* Invalid file. */ + } + + pWav->totalPCMFrameCount = dataChunkSize / bytesPerFrame; if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { drwav_uint64 totalBlockHeaderSizeInBytes; @@ -3247,6 +3396,11 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on } } + /* The number of bytes per frame must be known. If not, it's an invalid file and not decodable. */ + if (drwav_get_bytes_per_pcm_frame(pWav) == 0) { + return DRWAV_FALSE; + } + #ifdef DR_WAV_LIBSNDFILE_COMPAT /* I use libsndfile as a benchmark for testing, however in the version I'm using (from the Windows installer on the libsndfile website), @@ -5115,6 +5269,7 @@ DRWAV_API drwav_result drwav_uninit(drwav* pWav) DRWAV_API size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOut) { size_t bytesRead; + drwav_uint32 bytesPerFrame; if (pWav == NULL || bytesToRead == 0) { return 0; /* Invalid args. */ @@ -5128,6 +5283,11 @@ DRWAV_API size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOu return 0; /* At end. */ } + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return 0; /* Could not determine the bytes per frame. */ + } + if (pBufferOut != NULL) { bytesRead = pWav->onRead(pWav->pUserData, pBufferOut, bytesToRead); } else { @@ -5164,7 +5324,7 @@ DRWAV_API size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOu } } - pWav->readCursorInPCMFrames += bytesRead / drwav_get_bytes_per_pcm_frame(pWav); + pWav->readCursorInPCMFrames += bytesRead / bytesPerFrame; pWav->bytesRemaining -= bytesRead; return bytesRead; @@ -5213,7 +5373,12 @@ DRWAV_API drwav_uint64 drwav_read_pcm_frames_be(drwav* pWav, drwav_uint64 frames drwav_uint64 framesRead = drwav_read_pcm_frames_le(pWav, framesToRead, pBufferOut); if (pBufferOut != NULL) { - drwav__bswap_samples(pBufferOut, framesRead*pWav->channels, drwav_get_bytes_per_pcm_frame(pWav)/pWav->channels, pWav->translatedFormatTag); + drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return 0; /* Could not get the bytes per frame which means bytes per sample cannot be determined and we don't know how to byte swap. */ + } + + drwav__bswap_samples(pBufferOut, framesRead*pWav->channels, bytesPerFrame/pWav->channels, pWav->translatedFormatTag); } return framesRead; @@ -5328,12 +5493,18 @@ DRWAV_API drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetF drwav_uint64 currentBytePos; drwav_uint64 targetBytePos; drwav_uint64 offset; + drwav_uint32 bytesPerFrame; - totalSizeInBytes = pWav->totalPCMFrameCount * drwav_get_bytes_per_pcm_frame(pWav); + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return DRWAV_FALSE; /* Not able to calculate offset. */ + } + + totalSizeInBytes = pWav->totalPCMFrameCount * bytesPerFrame; DRWAV_ASSERT(totalSizeInBytes >= pWav->bytesRemaining); currentBytePos = totalSizeInBytes - pWav->bytesRemaining; - targetBytePos = targetFrameIndex * drwav_get_bytes_per_pcm_frame(pWav); + targetBytePos = targetFrameIndex * bytesPerFrame; if (currentBytePos < targetBytePos) { /* Offset forwards. */ @@ -5352,7 +5523,7 @@ DRWAV_API drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetF return DRWAV_FALSE; } - pWav->readCursorInPCMFrames += offset32 / drwav_get_bytes_per_pcm_frame(pWav); + pWav->readCursorInPCMFrames += offset32 / bytesPerFrame; pWav->bytesRemaining -= offset32; offset -= offset32; } @@ -5468,6 +5639,9 @@ DRWAV_API drwav_uint64 drwav_write_pcm_frames_be(drwav* pWav, drwav_uint64 frame pRunningData = (const drwav_uint8*)pData; bytesPerSample = drwav_get_bytes_per_pcm_frame(pWav) / pWav->channels; + if (bytesPerSample == 0) { + return 0; /* Cannot determine bytes per sample, or bytes per sample is less than one byte. */ + } while (bytesToWrite > 0) { drwav_uint8 temp[4096]; @@ -5743,7 +5917,7 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uin } pWav->ima.predictor[0] = drwav_bytes_to_s16(header + 0); - pWav->ima.stepIndex[0] = header[2]; + pWav->ima.stepIndex[0] = drwav_clamp(header[2], 0, (drwav_int32)drwav_countof(stepTable)-1); /* Clamp not necessary because we checked above, but adding here to silence a static analysis warning. */ pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 1] = pWav->ima.predictor[0]; pWav->ima.cachedFrameCount = 1; } else { @@ -5761,9 +5935,9 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uin } pWav->ima.predictor[0] = drwav_bytes_to_s16(header + 0); - pWav->ima.stepIndex[0] = header[2]; + pWav->ima.stepIndex[0] = drwav_clamp(header[2], 0, (drwav_int32)drwav_countof(stepTable)-1); /* Clamp not necessary because we checked above, but adding here to silence a static analysis warning. */ pWav->ima.predictor[1] = drwav_bytes_to_s16(header + 4); - pWav->ima.stepIndex[1] = header[6]; + pWav->ima.stepIndex[1] = drwav_clamp(header[6], 0, (drwav_int32)drwav_countof(stepTable)-1); /* Clamp not necessary because we checked above, but adding here to silence a static analysis warning. */ pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 2] = pWav->ima.predictor[0]; pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 1] = pWav->ima.predictor[1]; @@ -5908,7 +6082,7 @@ static DRWAV_INLINE drwav_int16 drwav__mulaw_to_s16(drwav_uint8 sampleIn) DRWAV_PRIVATE void drwav__pcm_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample) { - unsigned int i; + size_t i; /* Special case for 8-bit sample data because it's treated as unsigned. */ if (bytesPerSample == 1) { @@ -5976,8 +6150,10 @@ DRWAV_PRIVATE void drwav__ieee_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__pcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; + drwav_uint8 sampleData[4096] = {0}; drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; /* Fast path. */ if ((pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM && pWav->bitsPerSample == 16) || pBufferOut == NULL) { @@ -5989,17 +6165,32 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__pcm(drwav* pWav, drwav_uin return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; /* Only byte-aligned formats are supported. */ + } + totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav__pcm_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels); + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */ - pBufferOut += framesRead*pWav->channels; + /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */ + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); /* This should never happen with a valid file. */ + break; + } + + drwav__pcm_to_s16(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample); + + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -6010,8 +6201,10 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__pcm(drwav* pWav, drwav_uin DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ieee(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; + drwav_uint8 sampleData[4096] = {0}; drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; if (pBufferOut == NULL) { return drwav_read_pcm_frames(pWav, framesToRead, NULL); @@ -6022,17 +6215,32 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ieee(drwav* pWav, drwav_ui return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; /* Only byte-aligned formats are supported. */ + } + totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav__ieee_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels); + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */ - pBufferOut += framesRead*pWav->channels; + /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */ + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); /* This should never happen with a valid file. */ + break; + } + + drwav__ieee_to_s16(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample); /* Safe cast. */ + + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -6043,8 +6251,10 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ieee(drwav* pWav, drwav_ui DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__alaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; + drwav_uint8 sampleData[4096] = {0}; drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; if (pBufferOut == NULL) { return drwav_read_pcm_frames(pWav, framesToRead, NULL); @@ -6055,17 +6265,32 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__alaw(drwav* pWav, drwav_ui return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; /* Only byte-aligned formats are supported. */ + } + totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav_alaw_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */ - pBufferOut += framesRead*pWav->channels; + /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */ + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); /* This should never happen with a valid file. */ + break; + } + + drwav_alaw_to_s16(pBufferOut, sampleData, (size_t)samplesRead); + + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -6076,8 +6301,10 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__alaw(drwav* pWav, drwav_ui DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__mulaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; + drwav_uint8 sampleData[4096] = {0}; drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; if (pBufferOut == NULL) { return drwav_read_pcm_frames(pWav, framesToRead, NULL); @@ -6088,17 +6315,32 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__mulaw(drwav* pWav, drwav_u return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; /* Only byte-aligned formats are supported. */ + } + totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav_mulaw_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */ - pBufferOut += framesRead*pWav->channels; + /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */ + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); /* This should never happen with a valid file. */ + break; + } + + drwav_mulaw_to_s16(pBufferOut, sampleData, (size_t)samplesRead); + + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -6322,24 +6564,42 @@ DRWAV_PRIVATE void drwav__ieee_to_f32(float* pOut, const drwav_uint8* pIn, size_ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__pcm(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; - drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + drwav_uint8 sampleData[4096] = {0}; + drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); if (bytesPerFrame == 0) { return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; /* Only byte-aligned formats are supported. */ + } + totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav__pcm_to_f32(pBufferOut, sampleData, (size_t)framesRead*pWav->channels, bytesPerFrame/pWav->channels); + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */ - pBufferOut += framesRead*pWav->channels; + /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */ + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); /* This should never happen with a valid file. */ + break; + } + + drwav__pcm_to_f32(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample); + + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -6347,45 +6607,25 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__pcm(drwav* pWav, drwav_uin return totalFramesRead; } -DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__msadpcm(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__msadpcm_ima(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) { /* We're just going to borrow the implementation from the drwav_read_s16() since ADPCM is a little bit more complicated than other formats and I don't want to duplicate that code. */ - drwav_uint64 totalFramesRead = 0; + drwav_uint64 totalFramesRead; drwav_int16 samples16[2048]; + totalFramesRead = 0; + while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels); + drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, framesToReadThisIteration, samples16); if (framesRead == 0) { break; } - drwav_s16_to_f32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); /* <-- Safe cast because we're clamping to 2048. */ - - pBufferOut += framesRead*pWav->channels; - framesToRead -= framesRead; - totalFramesRead += framesRead; - } - - return totalFramesRead; -} - -DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__ima(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) -{ - /* - We're just going to borrow the implementation from the drwav_read_s16() since IMA-ADPCM is a little bit more complicated than other formats and I don't - want to duplicate that code. - */ - drwav_uint64 totalFramesRead = 0; - drwav_int16 samples16[2048]; - - while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16); - if (framesRead == 0) { - break; - } + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */ drwav_s16_to_f32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); /* <-- Safe cast because we're clamping to 2048. */ @@ -6400,8 +6640,10 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__ima(drwav* pWav, drwav_uin DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__ieee(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; + drwav_uint8 sampleData[4096] = {0}; drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; /* Fast path. */ if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT && pWav->bitsPerSample == 32) { @@ -6413,17 +6655,32 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__ieee(drwav* pWav, drwav_ui return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; /* Only byte-aligned formats are supported. */ + } + totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav__ieee_to_f32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels); + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */ - pBufferOut += framesRead*pWav->channels; + /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */ + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); /* This should never happen with a valid file. */ + break; + } + + drwav__ieee_to_f32(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample); + + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -6434,24 +6691,42 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__ieee(drwav* pWav, drwav_ui DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__alaw(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; - drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + drwav_uint8 sampleData[4096] = {0}; + drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); if (bytesPerFrame == 0) { return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; /* Only byte-aligned formats are supported. */ + } + totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav_alaw_to_f32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */ - pBufferOut += framesRead*pWav->channels; + /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */ + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); /* This should never happen with a valid file. */ + break; + } + + drwav_alaw_to_f32(pBufferOut, sampleData, (size_t)samplesRead); + + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -6462,24 +6737,42 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__alaw(drwav* pWav, drwav_ui DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__mulaw(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; - drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + drwav_uint8 sampleData[4096] = {0}; + drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); if (bytesPerFrame == 0) { return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; /* Only byte-aligned formats are supported. */ + } + totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav_mulaw_to_f32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */ - pBufferOut += framesRead*pWav->channels; + /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */ + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); /* This should never happen with a valid file. */ + break; + } + + drwav_mulaw_to_f32(pBufferOut, sampleData, (size_t)samplesRead); + + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -6506,8 +6799,8 @@ DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32(drwav* pWav, drwav_uint64 frame return drwav_read_pcm_frames_f32__pcm(pWav, framesToRead, pBufferOut); } - if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { - return drwav_read_pcm_frames_f32__msadpcm(pWav, framesToRead, pBufferOut); + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM || pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { + return drwav_read_pcm_frames_f32__msadpcm_ima(pWav, framesToRead, pBufferOut); } if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) { @@ -6522,10 +6815,6 @@ DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32(drwav* pWav, drwav_uint64 frame return drwav_read_pcm_frames_f32__mulaw(pWav, framesToRead, pBufferOut); } - if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { - return drwav_read_pcm_frames_f32__ima(pWav, framesToRead, pBufferOut); - } - return 0; } @@ -6734,8 +7023,10 @@ DRWAV_PRIVATE void drwav__ieee_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__pcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; + drwav_uint8 sampleData[4096] = {0}; drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; /* Fast path. */ if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM && pWav->bitsPerSample == 32) { @@ -6747,17 +7038,32 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__pcm(drwav* pWav, drwav_uin return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; /* Only byte-aligned formats are supported. */ + } + totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav__pcm_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels); + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */ - pBufferOut += framesRead*pWav->channels; + /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */ + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); /* This should never happen with a valid file. */ + break; + } + + drwav__pcm_to_s32(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample); + + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -6765,7 +7071,7 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__pcm(drwav* pWav, drwav_uin return totalFramesRead; } -DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__msadpcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__msadpcm_ima(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) { /* We're just going to borrow the implementation from the drwav_read_s16() since ADPCM is a little bit more complicated than other formats and I don't @@ -6775,35 +7081,13 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__msadpcm(drwav* pWav, drwav drwav_int16 samples16[2048]; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels); + drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, framesToReadThisIteration, samples16); if (framesRead == 0) { break; } - drwav_s16_to_s32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); /* <-- Safe cast because we're clamping to 2048. */ - - pBufferOut += framesRead*pWav->channels; - framesToRead -= framesRead; - totalFramesRead += framesRead; - } - - return totalFramesRead; -} - -DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__ima(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) -{ - /* - We're just going to borrow the implementation from the drwav_read_s16() since IMA-ADPCM is a little bit more complicated than other formats and I don't - want to duplicate that code. - */ - drwav_uint64 totalFramesRead = 0; - drwav_int16 samples16[2048]; - - while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16); - if (framesRead == 0) { - break; - } + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */ drwav_s16_to_s32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); /* <-- Safe cast because we're clamping to 2048. */ @@ -6818,24 +7102,42 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__ima(drwav* pWav, drwav_uin DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__ieee(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; - drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + drwav_uint8 sampleData[4096] = {0}; + drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); if (bytesPerFrame == 0) { return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; /* Only byte-aligned formats are supported. */ + } + totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav__ieee_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels); + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */ - pBufferOut += framesRead*pWav->channels; + /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */ + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); /* This should never happen with a valid file. */ + break; + } + + drwav__ieee_to_s32(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample); + + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -6846,24 +7148,42 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__ieee(drwav* pWav, drwav_ui DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__alaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; - drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + drwav_uint8 sampleData[4096] = {0}; + drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); if (bytesPerFrame == 0) { return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; /* Only byte-aligned formats are supported. */ + } + totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav_alaw_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */ - pBufferOut += framesRead*pWav->channels; + /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */ + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); /* This should never happen with a valid file. */ + break; + } + + drwav_alaw_to_s32(pBufferOut, sampleData, (size_t)samplesRead); + + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -6874,24 +7194,42 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__alaw(drwav* pWav, drwav_ui DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__mulaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; - drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + drwav_uint8 sampleData[4096] = {0}; + drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); if (bytesPerFrame == 0) { return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; /* Only byte-aligned formats are supported. */ + } + totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav_mulaw_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */ - pBufferOut += framesRead*pWav->channels; + /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */ + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); /* This should never happen with a valid file. */ + break; + } + + drwav_mulaw_to_s32(pBufferOut, sampleData, (size_t)samplesRead); + + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -6918,8 +7256,8 @@ DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32(drwav* pWav, drwav_uint64 frame return drwav_read_pcm_frames_s32__pcm(pWav, framesToRead, pBufferOut); } - if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { - return drwav_read_pcm_frames_s32__msadpcm(pWav, framesToRead, pBufferOut); + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM || pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { + return drwav_read_pcm_frames_s32__msadpcm_ima(pWav, framesToRead, pBufferOut); } if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) { @@ -6934,10 +7272,6 @@ DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32(drwav* pWav, drwav_uint64 frame return drwav_read_pcm_frames_s32__mulaw(pWav, framesToRead, pBufferOut); } - if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { - return drwav_read_pcm_frames_s32__ima(pWav, framesToRead, pBufferOut); - } - return 0; } @@ -7525,6 +7859,21 @@ DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b) /* REVISION HISTORY ================ +v0.13.4 - 2021-12-08 + - Fix some static analysis warnings. + +v0.13.3 - 2021-11-24 + - Fix an incorrect assertion when trying to endian swap 1-byte sample formats. This is now a no-op + rather than a failed assertion. + - Fix a bug with parsing of the bext chunk. + - Fix some static analysis warnings. + +v0.13.2 - 2021-10-02 + - Fix a possible buffer overflow when reading from compressed formats. + +v0.13.1 - 2021-07-31 + - Fix platform detection for ARM64. + v0.13.0 - 2021-07-01 - Improve support for reading and writing metadata. Use the `_with_metadata()` APIs to initialize a WAV decoder and store the metadata within the `drwav` object. Use the `pMetadata` and diff --git a/miniaudio.h b/miniaudio.h index 67778552..63f093e4 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -9153,7 +9153,7 @@ typedef unsigned char c89atomic_bool; #define C89ATOMIC_X64 #elif defined(__i386) || defined(_M_IX86) #define C89ATOMIC_X86 -#elif defined(__arm__) || defined(_M_ARM) +#elif defined(__arm__) || defined(_M_ARM) || defined(__arm64) || defined(__arm64__) || defined(__aarch64__) || defined(_M_ARM64) #define C89ATOMIC_ARM #endif #if defined(_MSC_VER) @@ -45993,7 +45993,7 @@ extern "C" { #define DRWAV_XSTRINGIFY(x) DRWAV_STRINGIFY(x) #define DRWAV_VERSION_MAJOR 0 #define DRWAV_VERSION_MINOR 13 -#define DRWAV_VERSION_REVISION 1 +#define DRWAV_VERSION_REVISION 4 #define DRWAV_VERSION_STRING DRWAV_XSTRINGIFY(DRWAV_VERSION_MAJOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_MINOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_REVISION) #include typedef signed char drwav_int8; @@ -52853,6 +52853,7 @@ code below please report the bug to the respective repository for the relevant p #define drwav_min(a, b) (((a) < (b)) ? (a) : (b)) #define drwav_max(a, b) (((a) > (b)) ? (a) : (b)) #define drwav_clamp(x, lo, hi) (drwav_max((lo), drwav_min((hi), (x)))) +#define drwav_offset_ptr(p, offset) (((drwav_uint8*)(p)) + (offset)) #define DRWAV_MAX_SIMD_VECTOR_SIZE 64 #if defined(__x86_64__) || defined(_M_X64) #define DRWAV_X64 @@ -53096,6 +53097,9 @@ static DRWAV_INLINE void drwav__bswap_samples_pcm(void* pSamples, drwav_uint64 s { switch (bytesPerSample) { + case 1: + { + } break; case 2: { drwav__bswap_samples_s16((drwav_int16*)pSamples, sampleCount); @@ -53506,12 +53510,13 @@ DRWAV_PRIVATE size_t drwav__metadata_parser_read(drwav__metadata_parser* pParser return pParser->onRead(pParser->pReadSeekUserData, pBufferOut, bytesToRead); } } -DRWAV_PRIVATE drwav_uint64 drwav__read_smpl_to_metadata_obj(drwav__metadata_parser* pParser, drwav_metadata* pMetadata) +DRWAV_PRIVATE drwav_uint64 drwav__read_smpl_to_metadata_obj(drwav__metadata_parser* pParser, const drwav_chunk_header* pChunkHeader, drwav_metadata* pMetadata) { drwav_uint8 smplHeaderData[DRWAV_SMPL_BYTES]; drwav_uint64 totalBytesRead = 0; size_t bytesJustRead = drwav__metadata_parser_read(pParser, smplHeaderData, sizeof(smplHeaderData), &totalBytesRead); DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read); + DRWAV_ASSERT(pChunkHeader != NULL); if (bytesJustRead == sizeof(smplHeaderData)) { drwav_uint32 iSampleLoop; pMetadata->type = drwav_metadata_type_smpl; @@ -53524,30 +53529,32 @@ DRWAV_PRIVATE drwav_uint64 drwav__read_smpl_to_metadata_obj(drwav__metadata_pars pMetadata->data.smpl.smpteOffset = drwav_bytes_to_u32(smplHeaderData + 24); pMetadata->data.smpl.sampleLoopCount = drwav_bytes_to_u32(smplHeaderData + 28); pMetadata->data.smpl.samplerSpecificDataSizeInBytes = drwav_bytes_to_u32(smplHeaderData + 32); - pMetadata->data.smpl.pLoops = (drwav_smpl_loop*)drwav__metadata_get_memory(pParser, sizeof(drwav_smpl_loop) * pMetadata->data.smpl.sampleLoopCount, DRWAV_METADATA_ALIGNMENT); - for (iSampleLoop = 0; iSampleLoop < pMetadata->data.smpl.sampleLoopCount; ++iSampleLoop) { - drwav_uint8 smplLoopData[DRWAV_SMPL_LOOP_BYTES]; - bytesJustRead = drwav__metadata_parser_read(pParser, smplLoopData, sizeof(smplLoopData), &totalBytesRead); - if (bytesJustRead == sizeof(smplLoopData)) { - pMetadata->data.smpl.pLoops[iSampleLoop].cuePointId = drwav_bytes_to_u32(smplLoopData + 0); - pMetadata->data.smpl.pLoops[iSampleLoop].type = drwav_bytes_to_u32(smplLoopData + 4); - pMetadata->data.smpl.pLoops[iSampleLoop].firstSampleByteOffset = drwav_bytes_to_u32(smplLoopData + 8); - pMetadata->data.smpl.pLoops[iSampleLoop].lastSampleByteOffset = drwav_bytes_to_u32(smplLoopData + 12); - pMetadata->data.smpl.pLoops[iSampleLoop].sampleFraction = drwav_bytes_to_u32(smplLoopData + 16); - pMetadata->data.smpl.pLoops[iSampleLoop].playCount = drwav_bytes_to_u32(smplLoopData + 20); - } else { - break; + if (pMetadata->data.smpl.sampleLoopCount == (pChunkHeader->sizeInBytes - DRWAV_SMPL_BYTES) / DRWAV_SMPL_LOOP_BYTES) { + pMetadata->data.smpl.pLoops = (drwav_smpl_loop*)drwav__metadata_get_memory(pParser, sizeof(drwav_smpl_loop) * pMetadata->data.smpl.sampleLoopCount, DRWAV_METADATA_ALIGNMENT); + for (iSampleLoop = 0; iSampleLoop < pMetadata->data.smpl.sampleLoopCount; ++iSampleLoop) { + drwav_uint8 smplLoopData[DRWAV_SMPL_LOOP_BYTES]; + bytesJustRead = drwav__metadata_parser_read(pParser, smplLoopData, sizeof(smplLoopData), &totalBytesRead); + if (bytesJustRead == sizeof(smplLoopData)) { + pMetadata->data.smpl.pLoops[iSampleLoop].cuePointId = drwav_bytes_to_u32(smplLoopData + 0); + pMetadata->data.smpl.pLoops[iSampleLoop].type = drwav_bytes_to_u32(smplLoopData + 4); + pMetadata->data.smpl.pLoops[iSampleLoop].firstSampleByteOffset = drwav_bytes_to_u32(smplLoopData + 8); + pMetadata->data.smpl.pLoops[iSampleLoop].lastSampleByteOffset = drwav_bytes_to_u32(smplLoopData + 12); + pMetadata->data.smpl.pLoops[iSampleLoop].sampleFraction = drwav_bytes_to_u32(smplLoopData + 16); + pMetadata->data.smpl.pLoops[iSampleLoop].playCount = drwav_bytes_to_u32(smplLoopData + 20); + } else { + break; + } + } + if (pMetadata->data.smpl.samplerSpecificDataSizeInBytes > 0) { + pMetadata->data.smpl.pSamplerSpecificData = drwav__metadata_get_memory(pParser, pMetadata->data.smpl.samplerSpecificDataSizeInBytes, 1); + DRWAV_ASSERT(pMetadata->data.smpl.pSamplerSpecificData != NULL); + drwav__metadata_parser_read(pParser, pMetadata->data.smpl.pSamplerSpecificData, pMetadata->data.smpl.samplerSpecificDataSizeInBytes, &totalBytesRead); } - } - if (pMetadata->data.smpl.samplerSpecificDataSizeInBytes > 0) { - pMetadata->data.smpl.pSamplerSpecificData = drwav__metadata_get_memory(pParser, pMetadata->data.smpl.samplerSpecificDataSizeInBytes, 1); - DRWAV_ASSERT(pMetadata->data.smpl.pSamplerSpecificData != NULL); - bytesJustRead = drwav__metadata_parser_read(pParser, pMetadata->data.smpl.pSamplerSpecificData, pMetadata->data.smpl.samplerSpecificDataSizeInBytes, &totalBytesRead); } } return totalBytesRead; } -DRWAV_PRIVATE drwav_uint64 drwav__read_cue_to_metadata_obj(drwav__metadata_parser* pParser, drwav_metadata* pMetadata) +DRWAV_PRIVATE drwav_uint64 drwav__read_cue_to_metadata_obj(drwav__metadata_parser* pParser, const drwav_chunk_header* pChunkHeader, drwav_metadata* pMetadata) { drwav_uint8 cueHeaderSectionData[DRWAV_CUE_BYTES]; drwav_uint64 totalBytesRead = 0; @@ -53556,25 +53563,27 @@ DRWAV_PRIVATE drwav_uint64 drwav__read_cue_to_metadata_obj(drwav__metadata_parse if (bytesJustRead == sizeof(cueHeaderSectionData)) { pMetadata->type = drwav_metadata_type_cue; pMetadata->data.cue.cuePointCount = drwav_bytes_to_u32(cueHeaderSectionData); - pMetadata->data.cue.pCuePoints = (drwav_cue_point*)drwav__metadata_get_memory(pParser, sizeof(drwav_cue_point) * pMetadata->data.cue.cuePointCount, DRWAV_METADATA_ALIGNMENT); - DRWAV_ASSERT(pMetadata->data.cue.pCuePoints != NULL); - if (pMetadata->data.cue.cuePointCount > 0) { - drwav_uint32 iCuePoint; - for (iCuePoint = 0; iCuePoint < pMetadata->data.cue.cuePointCount; ++iCuePoint) { - drwav_uint8 cuePointData[DRWAV_CUE_POINT_BYTES]; - bytesJustRead = drwav__metadata_parser_read(pParser, cuePointData, sizeof(cuePointData), &totalBytesRead); - if (bytesJustRead == sizeof(cuePointData)) { - pMetadata->data.cue.pCuePoints[iCuePoint].id = drwav_bytes_to_u32(cuePointData + 0); - pMetadata->data.cue.pCuePoints[iCuePoint].playOrderPosition = drwav_bytes_to_u32(cuePointData + 4); - pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[0] = cuePointData[8]; - pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[1] = cuePointData[9]; - pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[2] = cuePointData[10]; - pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[3] = cuePointData[11]; - pMetadata->data.cue.pCuePoints[iCuePoint].chunkStart = drwav_bytes_to_u32(cuePointData + 12); - pMetadata->data.cue.pCuePoints[iCuePoint].blockStart = drwav_bytes_to_u32(cuePointData + 16); - pMetadata->data.cue.pCuePoints[iCuePoint].sampleByteOffset = drwav_bytes_to_u32(cuePointData + 20); - } else { - break; + if (pMetadata->data.cue.cuePointCount == (pChunkHeader->sizeInBytes - DRWAV_CUE_BYTES) / DRWAV_CUE_POINT_BYTES) { + pMetadata->data.cue.pCuePoints = (drwav_cue_point*)drwav__metadata_get_memory(pParser, sizeof(drwav_cue_point) * pMetadata->data.cue.cuePointCount, DRWAV_METADATA_ALIGNMENT); + DRWAV_ASSERT(pMetadata->data.cue.pCuePoints != NULL); + if (pMetadata->data.cue.cuePointCount > 0) { + drwav_uint32 iCuePoint; + for (iCuePoint = 0; iCuePoint < pMetadata->data.cue.cuePointCount; ++iCuePoint) { + drwav_uint8 cuePointData[DRWAV_CUE_POINT_BYTES]; + bytesJustRead = drwav__metadata_parser_read(pParser, cuePointData, sizeof(cuePointData), &totalBytesRead); + if (bytesJustRead == sizeof(cuePointData)) { + pMetadata->data.cue.pCuePoints[iCuePoint].id = drwav_bytes_to_u32(cuePointData + 0); + pMetadata->data.cue.pCuePoints[iCuePoint].playOrderPosition = drwav_bytes_to_u32(cuePointData + 4); + pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[0] = cuePointData[8]; + pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[1] = cuePointData[9]; + pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[2] = cuePointData[10]; + pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[3] = cuePointData[11]; + pMetadata->data.cue.pCuePoints[iCuePoint].chunkStart = drwav_bytes_to_u32(cuePointData + 12); + pMetadata->data.cue.pCuePoints[iCuePoint].blockStart = drwav_bytes_to_u32(cuePointData + 16); + pMetadata->data.cue.pCuePoints[iCuePoint].sampleByteOffset = drwav_bytes_to_u32(cuePointData + 20); + } else { + break; + } } } } @@ -53616,7 +53625,7 @@ DRWAV_PRIVATE drwav_uint64 drwav__read_acid_to_metadata_obj(drwav__metadata_pars } return bytesRead; } -DRWAV_PRIVATE size_t drwav__strlen_clamped(char* str, size_t maxToRead) +DRWAV_PRIVATE size_t drwav__strlen_clamped(const char* str, size_t maxToRead) { size_t result = 0; while (*str++ && result < maxToRead) { @@ -53624,7 +53633,7 @@ DRWAV_PRIVATE size_t drwav__strlen_clamped(char* str, size_t maxToRead) } return result; } -DRWAV_PRIVATE char* drwav__metadata_copy_string(drwav__metadata_parser* pParser, char* str, size_t maxToRead) +DRWAV_PRIVATE char* drwav__metadata_copy_string(drwav__metadata_parser* pParser, const char* str, size_t maxToRead) { size_t len = drwav__strlen_clamped(str, maxToRead); if (len) { @@ -53637,58 +53646,134 @@ DRWAV_PRIVATE char* drwav__metadata_copy_string(drwav__metadata_parser* pParser, return NULL; } } +typedef struct +{ + const void* pBuffer; + size_t sizeInBytes; + size_t cursor; +} drwav_buffer_reader; +DRWAV_PRIVATE drwav_result drwav_buffer_reader_init(const void* pBuffer, size_t sizeInBytes, drwav_buffer_reader* pReader) +{ + DRWAV_ASSERT(pBuffer != NULL); + DRWAV_ASSERT(pReader != NULL); + DRWAV_ZERO_OBJECT(pReader); + pReader->pBuffer = pBuffer; + pReader->sizeInBytes = sizeInBytes; + pReader->cursor = 0; + return DRWAV_SUCCESS; +} +DRWAV_PRIVATE const void* drwav_buffer_reader_ptr(const drwav_buffer_reader* pReader) +{ + DRWAV_ASSERT(pReader != NULL); + return drwav_offset_ptr(pReader->pBuffer, pReader->cursor); +} +DRWAV_PRIVATE drwav_result drwav_buffer_reader_seek(drwav_buffer_reader* pReader, size_t bytesToSeek) +{ + DRWAV_ASSERT(pReader != NULL); + if (pReader->cursor + bytesToSeek > pReader->sizeInBytes) { + return DRWAV_BAD_SEEK; + } + pReader->cursor += bytesToSeek; + return DRWAV_SUCCESS; +} +DRWAV_PRIVATE drwav_result drwav_buffer_reader_read(drwav_buffer_reader* pReader, void* pDst, size_t bytesToRead, size_t* pBytesRead) +{ + drwav_result result = DRWAV_SUCCESS; + size_t bytesRemaining; + DRWAV_ASSERT(pReader != NULL); + if (pBytesRead != NULL) { + *pBytesRead = 0; + } + bytesRemaining = (pReader->sizeInBytes - pReader->cursor); + if (bytesToRead > bytesRemaining) { + bytesToRead = bytesRemaining; + } + if (pDst == NULL) { + result = drwav_buffer_reader_seek(pReader, bytesToRead); + } else { + DRWAV_COPY_MEMORY(pDst, drwav_buffer_reader_ptr(pReader), bytesToRead); + pReader->cursor += bytesToRead; + } + DRWAV_ASSERT(pReader->cursor <= pReader->sizeInBytes); + if (result == DRWAV_SUCCESS) { + if (pBytesRead != NULL) { + *pBytesRead = bytesToRead; + } + } + return DRWAV_SUCCESS; +} +DRWAV_PRIVATE drwav_result drwav_buffer_reader_read_u16(drwav_buffer_reader* pReader, drwav_uint16* pDst) +{ + drwav_result result; + size_t bytesRead; + drwav_uint8 data[2]; + DRWAV_ASSERT(pReader != NULL); + DRWAV_ASSERT(pDst != NULL); + *pDst = 0; + result = drwav_buffer_reader_read(pReader, data, sizeof(*pDst), &bytesRead); + if (result != DRWAV_SUCCESS || bytesRead != sizeof(*pDst)) { + return result; + } + *pDst = drwav_bytes_to_u16(data); + return DRWAV_SUCCESS; +} +DRWAV_PRIVATE drwav_result drwav_buffer_reader_read_u32(drwav_buffer_reader* pReader, drwav_uint32* pDst) +{ + drwav_result result; + size_t bytesRead; + drwav_uint8 data[4]; + DRWAV_ASSERT(pReader != NULL); + DRWAV_ASSERT(pDst != NULL); + *pDst = 0; + result = drwav_buffer_reader_read(pReader, data, sizeof(*pDst), &bytesRead); + if (result != DRWAV_SUCCESS || bytesRead != sizeof(*pDst)) { + return result; + } + *pDst = drwav_bytes_to_u32(data); + return DRWAV_SUCCESS; +} DRWAV_PRIVATE drwav_uint64 drwav__read_bext_to_metadata_obj(drwav__metadata_parser* pParser, drwav_metadata* pMetadata, drwav_uint64 chunkSize) { drwav_uint8 bextData[DRWAV_BEXT_BYTES]; - drwav_uint64 bytesRead = drwav__metadata_parser_read(pParser, bextData, sizeof(bextData), NULL); + size_t bytesRead = drwav__metadata_parser_read(pParser, bextData, sizeof(bextData), NULL); DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read); if (bytesRead == sizeof(bextData)) { - drwav_uint8* pReadPointer; + drwav_buffer_reader reader; drwav_uint32 timeReferenceLow; drwav_uint32 timeReferenceHigh; size_t extraBytes; pMetadata->type = drwav_metadata_type_bext; - pReadPointer = bextData; - pMetadata->data.bext.pDescription = drwav__metadata_copy_string(pParser, (char*)(pReadPointer), DRWAV_BEXT_DESCRIPTION_BYTES); - pReadPointer += DRWAV_BEXT_DESCRIPTION_BYTES; - pMetadata->data.bext.pOriginatorName = drwav__metadata_copy_string(pParser, (char*)(pReadPointer), DRWAV_BEXT_ORIGINATOR_NAME_BYTES); - pReadPointer += DRWAV_BEXT_ORIGINATOR_NAME_BYTES; - pMetadata->data.bext.pOriginatorReference = drwav__metadata_copy_string(pParser, (char*)(pReadPointer), DRWAV_BEXT_ORIGINATOR_REF_BYTES); - pReadPointer += DRWAV_BEXT_ORIGINATOR_REF_BYTES; - memcpy(pReadPointer, pMetadata->data.bext.pOriginationDate, sizeof(pMetadata->data.bext.pOriginationDate)); - pReadPointer += sizeof(pMetadata->data.bext.pOriginationDate); - memcpy(pReadPointer, pMetadata->data.bext.pOriginationTime, sizeof(pMetadata->data.bext.pOriginationTime)); - pReadPointer += sizeof(pMetadata->data.bext.pOriginationTime); - timeReferenceLow = drwav_bytes_to_u32(pReadPointer); - pReadPointer += sizeof(drwav_uint32); - timeReferenceHigh = drwav_bytes_to_u32(pReadPointer); - pReadPointer += sizeof(drwav_uint32); - pMetadata->data.bext.timeReference = ((drwav_uint64)timeReferenceHigh << 32) + timeReferenceLow; - pMetadata->data.bext.version = drwav_bytes_to_u16(pReadPointer); - pReadPointer += sizeof(drwav_uint16); - pMetadata->data.bext.pUMID = drwav__metadata_get_memory(pParser, DRWAV_BEXT_UMID_BYTES, 1); - memcpy(pMetadata->data.bext.pUMID, pReadPointer, DRWAV_BEXT_UMID_BYTES); - pReadPointer += DRWAV_BEXT_UMID_BYTES; - pMetadata->data.bext.loudnessValue = drwav_bytes_to_u16(pReadPointer); - pReadPointer += sizeof(drwav_uint16); - pMetadata->data.bext.loudnessRange = drwav_bytes_to_u16(pReadPointer); - pReadPointer += sizeof(drwav_uint16); - pMetadata->data.bext.maxTruePeakLevel = drwav_bytes_to_u16(pReadPointer); - pReadPointer += sizeof(drwav_uint16); - pMetadata->data.bext.maxMomentaryLoudness = drwav_bytes_to_u16(pReadPointer); - pReadPointer += sizeof(drwav_uint16); - pMetadata->data.bext.maxShortTermLoudness = drwav_bytes_to_u16(pReadPointer); - pReadPointer += sizeof(drwav_uint16); - DRWAV_ASSERT((pReadPointer + DRWAV_BEXT_RESERVED_BYTES) == (bextData + DRWAV_BEXT_BYTES)); - extraBytes = (size_t)(chunkSize - DRWAV_BEXT_BYTES); - if (extraBytes > 0) { - pMetadata->data.bext.pCodingHistory = (char*)drwav__metadata_get_memory(pParser, extraBytes + 1, 1); - DRWAV_ASSERT(pMetadata->data.bext.pCodingHistory != NULL); - bytesRead += drwav__metadata_parser_read(pParser, pMetadata->data.bext.pCodingHistory, extraBytes, NULL); - pMetadata->data.bext.codingHistorySize = (drwav_uint32)strlen(pMetadata->data.bext.pCodingHistory); - } else { - pMetadata->data.bext.pCodingHistory = NULL; - pMetadata->data.bext.codingHistorySize = 0; + if (drwav_buffer_reader_init(bextData, bytesRead, &reader) == DRWAV_SUCCESS) { + pMetadata->data.bext.pDescription = drwav__metadata_copy_string(pParser, (const char*)drwav_buffer_reader_ptr(&reader), DRWAV_BEXT_DESCRIPTION_BYTES); + drwav_buffer_reader_seek(&reader, DRWAV_BEXT_DESCRIPTION_BYTES); + pMetadata->data.bext.pOriginatorName = drwav__metadata_copy_string(pParser, (const char*)drwav_buffer_reader_ptr(&reader), DRWAV_BEXT_ORIGINATOR_NAME_BYTES); + drwav_buffer_reader_seek(&reader, DRWAV_BEXT_ORIGINATOR_NAME_BYTES); + pMetadata->data.bext.pOriginatorReference = drwav__metadata_copy_string(pParser, (const char*)drwav_buffer_reader_ptr(&reader), DRWAV_BEXT_ORIGINATOR_REF_BYTES); + drwav_buffer_reader_seek(&reader, DRWAV_BEXT_ORIGINATOR_REF_BYTES); + drwav_buffer_reader_read(&reader, pMetadata->data.bext.pOriginationDate, sizeof(pMetadata->data.bext.pOriginationDate), NULL); + drwav_buffer_reader_read(&reader, pMetadata->data.bext.pOriginationTime, sizeof(pMetadata->data.bext.pOriginationTime), NULL); + drwav_buffer_reader_read_u32(&reader, &timeReferenceLow); + drwav_buffer_reader_read_u32(&reader, &timeReferenceHigh); + pMetadata->data.bext.timeReference = ((drwav_uint64)timeReferenceHigh << 32) + timeReferenceLow; + drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.version); + pMetadata->data.bext.pUMID = drwav__metadata_get_memory(pParser, DRWAV_BEXT_UMID_BYTES, 1); + drwav_buffer_reader_read(&reader, pMetadata->data.bext.pUMID, DRWAV_BEXT_UMID_BYTES, NULL); + drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.loudnessValue); + drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.loudnessRange); + drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.maxTruePeakLevel); + drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.maxMomentaryLoudness); + drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.maxShortTermLoudness); + DRWAV_ASSERT((drwav_offset_ptr(drwav_buffer_reader_ptr(&reader), DRWAV_BEXT_RESERVED_BYTES)) == (bextData + DRWAV_BEXT_BYTES)); + extraBytes = (size_t)(chunkSize - DRWAV_BEXT_BYTES); + if (extraBytes > 0) { + pMetadata->data.bext.pCodingHistory = (char*)drwav__metadata_get_memory(pParser, extraBytes + 1, 1); + DRWAV_ASSERT(pMetadata->data.bext.pCodingHistory != NULL); + bytesRead += drwav__metadata_parser_read(pParser, pMetadata->data.bext.pCodingHistory, extraBytes, NULL); + pMetadata->data.bext.codingHistorySize = (drwav_uint32)strlen(pMetadata->data.bext.pCodingHistory); + } else { + pMetadata->data.bext.pCodingHistory = NULL; + pMetadata->data.bext.codingHistorySize = 0; + } } } return bytesRead; @@ -53708,7 +53793,7 @@ DRWAV_PRIVATE drwav_uint64 drwav__read_list_label_or_note_to_metadata_obj(drwav_ pMetadata->data.labelOrNote.stringLength = sizeIncludingNullTerminator - 1; pMetadata->data.labelOrNote.pString = (char*)drwav__metadata_get_memory(pParser, sizeIncludingNullTerminator, 1); DRWAV_ASSERT(pMetadata->data.labelOrNote.pString != NULL); - bytesJustRead = drwav__metadata_parser_read(pParser, pMetadata->data.labelOrNote.pString, sizeIncludingNullTerminator, &totalBytesRead); + drwav__metadata_parser_read(pParser, pMetadata->data.labelOrNote.pString, sizeIncludingNullTerminator, &totalBytesRead); } else { pMetadata->data.labelOrNote.stringLength = 0; pMetadata->data.labelOrNote.pString = NULL; @@ -53740,7 +53825,7 @@ DRWAV_PRIVATE drwav_uint64 drwav__read_list_labelled_cue_region_to_metadata_obj( pMetadata->data.labelledCueRegion.stringLength = sizeIncludingNullTerminator - 1; pMetadata->data.labelledCueRegion.pString = (char*)drwav__metadata_get_memory(pParser, sizeIncludingNullTerminator, 1); DRWAV_ASSERT(pMetadata->data.labelledCueRegion.pString != NULL); - bytesJustRead = drwav__metadata_parser_read(pParser, pMetadata->data.labelledCueRegion.pString, sizeIncludingNullTerminator, &totalBytesRead); + drwav__metadata_parser_read(pParser, pMetadata->data.labelledCueRegion.pString, sizeIncludingNullTerminator, &totalBytesRead); } else { pMetadata->data.labelledCueRegion.stringLength = 0; pMetadata->data.labelledCueRegion.pString = NULL; @@ -53806,11 +53891,11 @@ DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_unknown_chunk(drwav__metadata } return bytesRead; } -DRWAV_PRIVATE drwav_bool32 drwav__chunk_matches(drwav_uint64 allowedMetadataTypes, const drwav_uint8* pChunkID, drwav_metadata_type type, const char* pID) +DRWAV_PRIVATE drwav_bool32 drwav__chunk_matches(drwav_metadata_type allowedMetadataTypes, const drwav_uint8* pChunkID, drwav_metadata_type type, const char* pID) { return (allowedMetadataTypes & type) && drwav_fourcc_equal(pChunkID, pID); } -DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_chunk(drwav__metadata_parser* pParser, const drwav_chunk_header* pChunkHeader, drwav_uint64 allowedMetadataTypes) +DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_chunk(drwav__metadata_parser* pParser, const drwav_chunk_header* pChunkHeader, drwav_metadata_type allowedMetadataTypes) { const drwav_uint8 *pChunkID = pChunkHeader->id.fourcc; drwav_uint64 bytesRead = 0; @@ -53826,16 +53911,21 @@ DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_chunk(drwav__metadata_parser* bytesJustRead = drwav__metadata_parser_read(pParser, buffer, sizeof(buffer), &bytesRead); if (bytesJustRead == sizeof(buffer)) { drwav_uint32 loopCount = drwav_bytes_to_u32(buffer); - bytesJustRead = drwav__metadata_parser_read(pParser, buffer, sizeof(buffer), &bytesRead); - if (bytesJustRead == sizeof(buffer)) { - drwav_uint32 samplerSpecificDataSizeInBytes = drwav_bytes_to_u32(buffer); - pParser->metadataCount += 1; - drwav__metadata_request_extra_memory_for_stage_2(pParser, sizeof(drwav_smpl_loop) * loopCount, DRWAV_METADATA_ALIGNMENT); - drwav__metadata_request_extra_memory_for_stage_2(pParser, samplerSpecificDataSizeInBytes, 1); + drwav_uint64 calculatedLoopCount; + calculatedLoopCount = (pChunkHeader->sizeInBytes - DRWAV_SMPL_BYTES) / DRWAV_SMPL_LOOP_BYTES; + if (calculatedLoopCount == loopCount) { + bytesJustRead = drwav__metadata_parser_read(pParser, buffer, sizeof(buffer), &bytesRead); + if (bytesJustRead == sizeof(buffer)) { + drwav_uint32 samplerSpecificDataSizeInBytes = drwav_bytes_to_u32(buffer); + pParser->metadataCount += 1; + drwav__metadata_request_extra_memory_for_stage_2(pParser, sizeof(drwav_smpl_loop) * loopCount, DRWAV_METADATA_ALIGNMENT); + drwav__metadata_request_extra_memory_for_stage_2(pParser, samplerSpecificDataSizeInBytes, 1); + } + } else { } } } else { - bytesRead = drwav__read_smpl_to_metadata_obj(pParser, &pParser->pMetadata[pParser->metadataCursor]); + bytesRead = drwav__read_smpl_to_metadata_obj(pParser, pChunkHeader, &pParser->pMetadata[pParser->metadataCursor]); if (bytesRead == pChunkHeader->sizeInBytes) { pParser->metadataCursor += 1; } else { @@ -53877,7 +53967,7 @@ DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_chunk(drwav__metadata_parser* cueCount = (size_t)(pChunkHeader->sizeInBytes - DRWAV_CUE_BYTES) / DRWAV_CUE_POINT_BYTES; drwav__metadata_request_extra_memory_for_stage_2(pParser, sizeof(drwav_cue_point) * cueCount, DRWAV_METADATA_ALIGNMENT); } else { - bytesRead = drwav__read_cue_to_metadata_obj(pParser, &pParser->pMetadata[pParser->metadataCursor]); + bytesRead = drwav__read_cue_to_metadata_obj(pParser, pChunkHeader, &pParser->pMetadata[pParser->metadataCursor]); if (bytesRead == pChunkHeader->sizeInBytes) { pParser->metadataCursor += 1; } else { @@ -53992,7 +54082,7 @@ DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_chunk(drwav__metadata_parser* subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize, drwav_metadata_type_list_info_album); } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_tracknumber, "ITRK")) { subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize, drwav_metadata_type_list_info_tracknumber); - } else if (allowedMetadataTypes & drwav_metadata_type_unknown) { + } else if ((allowedMetadataTypes & drwav_metadata_type_unknown) != 0) { subchunkBytesRead = drwav__metadata_process_unknown_chunk(pParser, subchunkId, subchunkDataSize, listType); } bytesRead += subchunkBytesRead; @@ -54011,18 +54101,25 @@ DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_chunk(drwav__metadata_parser* bytesRead += 1; } } - } else if (allowedMetadataTypes & drwav_metadata_type_unknown) { + } else if ((allowedMetadataTypes & drwav_metadata_type_unknown) != 0) { bytesRead = drwav__metadata_process_unknown_chunk(pParser, pChunkID, pChunkHeader->sizeInBytes, drwav_metadata_location_top_level); } return bytesRead; } DRWAV_PRIVATE drwav_uint32 drwav_get_bytes_per_pcm_frame(drwav* pWav) { + drwav_uint32 bytesPerFrame; if ((pWav->bitsPerSample & 0x7) == 0) { - return (pWav->bitsPerSample * pWav->fmt.channels) >> 3; + bytesPerFrame = (pWav->bitsPerSample * pWav->fmt.channels) >> 3; } else { - return pWav->fmt.blockAlign; + bytesPerFrame = pWav->fmt.blockAlign; } + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW || pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) { + if (bytesPerFrame != pWav->fmt.channels) { + return 0; + } + } + return bytesPerFrame; } DRWAV_API drwav_uint16 drwav_fmt_get_format(const drwav_fmt* pFMT) { @@ -54303,7 +54400,11 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on if (sampleCountFromFactChunk != 0) { pWav->totalPCMFrameCount = sampleCountFromFactChunk; } else { - pWav->totalPCMFrameCount = dataChunkSize / drwav_get_bytes_per_pcm_frame(pWav); + drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return DRWAV_FALSE; + } + pWav->totalPCMFrameCount = dataChunkSize / bytesPerFrame; if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { drwav_uint64 totalBlockHeaderSizeInBytes; drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign; @@ -54329,6 +54430,9 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on return DRWAV_FALSE; } } + if (drwav_get_bytes_per_pcm_frame(pWav) == 0) { + return DRWAV_FALSE; + } #ifdef DR_WAV_LIBSNDFILE_COMPAT if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign; @@ -55830,6 +55934,7 @@ DRWAV_API drwav_result drwav_uninit(drwav* pWav) DRWAV_API size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOut) { size_t bytesRead; + drwav_uint32 bytesPerFrame; if (pWav == NULL || bytesToRead == 0) { return 0; } @@ -55839,6 +55944,10 @@ DRWAV_API size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOu if (bytesToRead == 0) { return 0; } + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return 0; + } if (pBufferOut != NULL) { bytesRead = pWav->onRead(pWav->pUserData, pBufferOut, bytesToRead); } else { @@ -55867,7 +55976,7 @@ DRWAV_API size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOu } } } - pWav->readCursorInPCMFrames += bytesRead / drwav_get_bytes_per_pcm_frame(pWav); + pWav->readCursorInPCMFrames += bytesRead / bytesPerFrame; pWav->bytesRemaining -= bytesRead; return bytesRead; } @@ -55898,7 +56007,11 @@ DRWAV_API drwav_uint64 drwav_read_pcm_frames_be(drwav* pWav, drwav_uint64 frames { drwav_uint64 framesRead = drwav_read_pcm_frames_le(pWav, framesToRead, pBufferOut); if (pBufferOut != NULL) { - drwav__bswap_samples(pBufferOut, framesRead*pWav->channels, drwav_get_bytes_per_pcm_frame(pWav)/pWav->channels, pWav->translatedFormatTag); + drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return 0; + } + drwav__bswap_samples(pBufferOut, framesRead*pWav->channels, bytesPerFrame/pWav->channels, pWav->translatedFormatTag); } return framesRead; } @@ -55978,10 +56091,15 @@ DRWAV_API drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetF drwav_uint64 currentBytePos; drwav_uint64 targetBytePos; drwav_uint64 offset; - totalSizeInBytes = pWav->totalPCMFrameCount * drwav_get_bytes_per_pcm_frame(pWav); + drwav_uint32 bytesPerFrame; + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return DRWAV_FALSE; + } + totalSizeInBytes = pWav->totalPCMFrameCount * bytesPerFrame; DRWAV_ASSERT(totalSizeInBytes >= pWav->bytesRemaining); currentBytePos = totalSizeInBytes - pWav->bytesRemaining; - targetBytePos = targetFrameIndex * drwav_get_bytes_per_pcm_frame(pWav); + targetBytePos = targetFrameIndex * bytesPerFrame; if (currentBytePos < targetBytePos) { offset = (targetBytePos - currentBytePos); } else { @@ -55995,7 +56113,7 @@ DRWAV_API drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetF if (!pWav->onSeek(pWav->pUserData, offset32, drwav_seek_origin_current)) { return DRWAV_FALSE; } - pWav->readCursorInPCMFrames += offset32 / drwav_get_bytes_per_pcm_frame(pWav); + pWav->readCursorInPCMFrames += offset32 / bytesPerFrame; pWav->bytesRemaining -= offset32; offset -= offset32; } @@ -56081,6 +56199,9 @@ DRWAV_API drwav_uint64 drwav_write_pcm_frames_be(drwav* pWav, drwav_uint64 frame bytesWritten = 0; pRunningData = (const drwav_uint8*)pData; bytesPerSample = drwav_get_bytes_per_pcm_frame(pWav) / pWav->channels; + if (bytesPerSample == 0) { + return 0; + } while (bytesToWrite > 0) { drwav_uint8 temp[4096]; drwav_uint32 sampleCount; @@ -56279,7 +56400,7 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uin return totalFramesRead; } pWav->ima.predictor[0] = drwav_bytes_to_s16(header + 0); - pWav->ima.stepIndex[0] = header[2]; + pWav->ima.stepIndex[0] = drwav_clamp(header[2], 0, (drwav_int32)drwav_countof(stepTable)-1); pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 1] = pWav->ima.predictor[0]; pWav->ima.cachedFrameCount = 1; } else { @@ -56294,9 +56415,9 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uin return totalFramesRead; } pWav->ima.predictor[0] = drwav_bytes_to_s16(header + 0); - pWav->ima.stepIndex[0] = header[2]; + pWav->ima.stepIndex[0] = drwav_clamp(header[2], 0, (drwav_int32)drwav_countof(stepTable)-1); pWav->ima.predictor[1] = drwav_bytes_to_s16(header + 4); - pWav->ima.stepIndex[1] = header[6]; + pWav->ima.stepIndex[1] = drwav_clamp(header[6], 0, (drwav_int32)drwav_countof(stepTable)-1); pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 2] = pWav->ima.predictor[0]; pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 1] = pWav->ima.predictor[1]; pWav->ima.cachedFrameCount = 1; @@ -56410,7 +56531,7 @@ static DRWAV_INLINE drwav_int16 drwav__mulaw_to_s16(drwav_uint8 sampleIn) } DRWAV_PRIVATE void drwav__pcm_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample) { - unsigned int i; + size_t i; if (bytesPerSample == 1) { drwav_u8_to_s16(pOut, pIn, totalSampleCount); return; @@ -56462,8 +56583,10 @@ DRWAV_PRIVATE void drwav__ieee_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__pcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; + drwav_uint8 sampleData[4096] = {0}; drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; if ((pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM && pWav->bitsPerSample == 16) || pBufferOut == NULL) { return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut); } @@ -56471,14 +56594,25 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__pcm(drwav* pWav, drwav_uin if (bytesPerFrame == 0) { return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; + } totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav__pcm_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels); - pBufferOut += framesRead*pWav->channels; + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); + break; + } + drwav__pcm_to_s16(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample); + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -56487,8 +56621,10 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__pcm(drwav* pWav, drwav_uin DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ieee(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; + drwav_uint8 sampleData[4096] = {0}; drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; if (pBufferOut == NULL) { return drwav_read_pcm_frames(pWav, framesToRead, NULL); } @@ -56496,14 +56632,25 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ieee(drwav* pWav, drwav_ui if (bytesPerFrame == 0) { return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; + } totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav__ieee_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels); - pBufferOut += framesRead*pWav->channels; + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); + break; + } + drwav__ieee_to_s16(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample); + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -56512,8 +56659,10 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ieee(drwav* pWav, drwav_ui DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__alaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; + drwav_uint8 sampleData[4096] = {0}; drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; if (pBufferOut == NULL) { return drwav_read_pcm_frames(pWav, framesToRead, NULL); } @@ -56521,14 +56670,25 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__alaw(drwav* pWav, drwav_ui if (bytesPerFrame == 0) { return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; + } totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav_alaw_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); - pBufferOut += framesRead*pWav->channels; + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); + break; + } + drwav_alaw_to_s16(pBufferOut, sampleData, (size_t)samplesRead); + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -56537,8 +56697,10 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__alaw(drwav* pWav, drwav_ui DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__mulaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; + drwav_uint8 sampleData[4096] = {0}; drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; if (pBufferOut == NULL) { return drwav_read_pcm_frames(pWav, framesToRead, NULL); } @@ -56546,14 +56708,25 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__mulaw(drwav* pWav, drwav_u if (bytesPerFrame == 0) { return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; + } totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav_mulaw_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); - pBufferOut += framesRead*pWav->channels; + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); + break; + } + drwav_mulaw_to_s16(pBufferOut, sampleData, (size_t)samplesRead); + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -56734,49 +56907,50 @@ DRWAV_PRIVATE void drwav__ieee_to_f32(float* pOut, const drwav_uint8* pIn, size_ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__pcm(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; - drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + drwav_uint8 sampleData[4096] = {0}; + drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); if (bytesPerFrame == 0) { return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; + } totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav__pcm_to_f32(pBufferOut, sampleData, (size_t)framesRead*pWav->channels, bytesPerFrame/pWav->channels); - pBufferOut += framesRead*pWav->channels; + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); + break; + } + drwav__pcm_to_f32(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample); + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } return totalFramesRead; } -DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__msadpcm(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__msadpcm_ima(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) { - drwav_uint64 totalFramesRead = 0; + drwav_uint64 totalFramesRead; drwav_int16 samples16[2048]; + totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16); - if (framesRead == 0) { - break; - } - drwav_s16_to_f32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); - pBufferOut += framesRead*pWav->channels; - framesToRead -= framesRead; - totalFramesRead += framesRead; - } - return totalFramesRead; -} -DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__ima(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) -{ - drwav_uint64 totalFramesRead = 0; - drwav_int16 samples16[2048]; - while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels); + drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, framesToReadThisIteration, samples16); if (framesRead == 0) { break; } + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); drwav_s16_to_f32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); pBufferOut += framesRead*pWav->channels; framesToRead -= framesRead; @@ -56787,8 +56961,10 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__ima(drwav* pWav, drwav_uin DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__ieee(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; + drwav_uint8 sampleData[4096] = {0}; drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT && pWav->bitsPerSample == 32) { return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut); } @@ -56796,14 +56972,25 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__ieee(drwav* pWav, drwav_ui if (bytesPerFrame == 0) { return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; + } totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav__ieee_to_f32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels); - pBufferOut += framesRead*pWav->channels; + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); + break; + } + drwav__ieee_to_f32(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample); + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -56812,19 +56999,33 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__ieee(drwav* pWav, drwav_ui DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__alaw(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; - drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + drwav_uint8 sampleData[4096] = {0}; + drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); if (bytesPerFrame == 0) { return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; + } totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav_alaw_to_f32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); - pBufferOut += framesRead*pWav->channels; + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); + break; + } + drwav_alaw_to_f32(pBufferOut, sampleData, (size_t)samplesRead); + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -56833,19 +57034,33 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__alaw(drwav* pWav, drwav_ui DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__mulaw(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; - drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + drwav_uint8 sampleData[4096] = {0}; + drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); if (bytesPerFrame == 0) { return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; + } totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav_mulaw_to_f32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); - pBufferOut += framesRead*pWav->channels; + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); + break; + } + drwav_mulaw_to_f32(pBufferOut, sampleData, (size_t)samplesRead); + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -56865,8 +57080,8 @@ DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32(drwav* pWav, drwav_uint64 frame if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) { return drwav_read_pcm_frames_f32__pcm(pWav, framesToRead, pBufferOut); } - if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { - return drwav_read_pcm_frames_f32__msadpcm(pWav, framesToRead, pBufferOut); + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM || pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { + return drwav_read_pcm_frames_f32__msadpcm_ima(pWav, framesToRead, pBufferOut); } if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) { return drwav_read_pcm_frames_f32__ieee(pWav, framesToRead, pBufferOut); @@ -56877,9 +57092,6 @@ DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32(drwav* pWav, drwav_uint64 frame if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) { return drwav_read_pcm_frames_f32__mulaw(pWav, framesToRead, pBufferOut); } - if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { - return drwav_read_pcm_frames_f32__ima(pWav, framesToRead, pBufferOut); - } return 0; } DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32le(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) @@ -57036,8 +57248,10 @@ DRWAV_PRIVATE void drwav__ieee_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__pcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; + drwav_uint8 sampleData[4096] = {0}; drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM && pWav->bitsPerSample == 32) { return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut); } @@ -57045,44 +57259,41 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__pcm(drwav* pWav, drwav_uin if (bytesPerFrame == 0) { return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; + } totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav__pcm_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels); - pBufferOut += framesRead*pWav->channels; + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); + break; + } + drwav__pcm_to_s32(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample); + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } return totalFramesRead; } -DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__msadpcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__msadpcm_ima(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) { drwav_uint64 totalFramesRead = 0; drwav_int16 samples16[2048]; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16); - if (framesRead == 0) { - break; - } - drwav_s16_to_s32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); - pBufferOut += framesRead*pWav->channels; - framesToRead -= framesRead; - totalFramesRead += framesRead; - } - return totalFramesRead; -} -DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__ima(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) -{ - drwav_uint64 totalFramesRead = 0; - drwav_int16 samples16[2048]; - while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels); + drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, framesToReadThisIteration, samples16); if (framesRead == 0) { break; } + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); drwav_s16_to_s32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); pBufferOut += framesRead*pWav->channels; framesToRead -= framesRead; @@ -57093,19 +57304,33 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__ima(drwav* pWav, drwav_uin DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__ieee(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; - drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + drwav_uint8 sampleData[4096] = {0}; + drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); if (bytesPerFrame == 0) { return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; + } totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav__ieee_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels); - pBufferOut += framesRead*pWav->channels; + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); + break; + } + drwav__ieee_to_s32(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample); + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -57114,19 +57339,33 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__ieee(drwav* pWav, drwav_ui DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__alaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; - drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + drwav_uint8 sampleData[4096] = {0}; + drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); if (bytesPerFrame == 0) { return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; + } totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav_alaw_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); - pBufferOut += framesRead*pWav->channels; + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); + break; + } + drwav_alaw_to_s32(pBufferOut, sampleData, (size_t)samplesRead); + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -57135,19 +57374,33 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__alaw(drwav* pWav, drwav_ui DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__mulaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; - drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + drwav_uint8 sampleData[4096] = {0}; + drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); if (bytesPerFrame == 0) { return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; + } totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav_mulaw_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); - pBufferOut += framesRead*pWav->channels; + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); + break; + } + drwav_mulaw_to_s32(pBufferOut, sampleData, (size_t)samplesRead); + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -57167,8 +57420,8 @@ DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32(drwav* pWav, drwav_uint64 frame if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) { return drwav_read_pcm_frames_s32__pcm(pWav, framesToRead, pBufferOut); } - if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { - return drwav_read_pcm_frames_s32__msadpcm(pWav, framesToRead, pBufferOut); + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM || pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { + return drwav_read_pcm_frames_s32__msadpcm_ima(pWav, framesToRead, pBufferOut); } if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) { return drwav_read_pcm_frames_s32__ieee(pWav, framesToRead, pBufferOut); @@ -57179,9 +57432,6 @@ DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32(drwav* pWav, drwav_uint64 frame if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) { return drwav_read_pcm_frames_s32__mulaw(pWav, framesToRead, pBufferOut); } - if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { - return drwav_read_pcm_frames_s32__ima(pWav, framesToRead, pBufferOut); - } return 0; } DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32le(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) From 8686f52e6625e562f4756b946696692c016324ab Mon Sep 17 00:00:00 2001 From: David Reid Date: Fri, 10 Dec 2021 19:07:29 +1000 Subject: [PATCH 2/2] Version 0.10.43 --- extras/miniaudio_split/miniaudio.c | 695 ++++++++++++++++++++--------- extras/miniaudio_split/miniaudio.h | 4 +- miniaudio.h | 6 +- 3 files changed, 478 insertions(+), 227 deletions(-) diff --git a/extras/miniaudio_split/miniaudio.c b/extras/miniaudio_split/miniaudio.c index 5a856243..8a4e7fb8 100644 --- a/extras/miniaudio_split/miniaudio.c +++ b/extras/miniaudio_split/miniaudio.c @@ -1,6 +1,6 @@ /* Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file. -miniaudio - v0.10.42 - 2021-08-22 +miniaudio - v0.10.43 - 2021-12-10 David Reid - mackron@gmail.com @@ -2624,7 +2624,7 @@ typedef unsigned char c89atomic_bool; #define C89ATOMIC_X64 #elif defined(__i386) || defined(_M_IX86) #define C89ATOMIC_X86 -#elif defined(__arm__) || defined(_M_ARM) +#elif defined(__arm__) || defined(_M_ARM) || defined(__arm64) || defined(__arm64__) || defined(__aarch64__) || defined(_M_ARM64) #define C89ATOMIC_ARM #endif #if defined(_MSC_VER) @@ -13863,10 +13863,11 @@ static ma_result ma_context_enumerate_devices__alsa(ma_context* pContext, ma_enu /* Some devices are both playback and capture, but they are only enumerated by ALSA once. We need to fire the callback - again for the other device type in this case. We do this for known devices. + again for the other device type in this case. We do this for known devices and where the IOID hint is NULL, which + means both Input and Output. */ if (cbResult) { - if (ma_is_common_device_name__alsa(NAME)) { + if (ma_is_common_device_name__alsa(NAME) || IOID == NULL) { if (deviceType == ma_device_type_playback) { if (!ma_is_capture_device_blacklisted__alsa(NAME)) { cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData); @@ -14684,7 +14685,7 @@ static ma_result ma_device_wait_write__alsa(ma_device* pDevice) static ma_result ma_device_read__alsa(ma_device* pDevice, void* pFramesOut, ma_uint32 frameCount, ma_uint32* pFramesRead) { - ma_snd_pcm_sframes_t resultALSA; + ma_snd_pcm_sframes_t resultALSA = 0; MA_ASSERT(pDevice != NULL); MA_ASSERT(pFramesOut != NULL); @@ -14738,7 +14739,7 @@ static ma_result ma_device_read__alsa(ma_device* pDevice, void* pFramesOut, ma_u static ma_result ma_device_write__alsa(ma_device* pDevice, const void* pFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten) { - ma_snd_pcm_sframes_t resultALSA; + ma_snd_pcm_sframes_t resultALSA = 0; MA_ASSERT(pDevice != NULL); MA_ASSERT(pFrames != NULL); @@ -16935,7 +16936,7 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi attr = *pActualAttr; } - pDescriptorPlayback->periodCount = attr.maxlength / attr.tlength; + pDescriptorPlayback->periodCount = ma_max(attr.maxlength / attr.tlength, 1); pDescriptorPlayback->periodSizeInFrames = attr.maxlength / ma_get_bytes_per_frame(pDescriptorPlayback->format, pDescriptorPlayback->channels) / pDescriptorPlayback->periodCount; ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[PulseAudio] Playback actual attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; internalPeriodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDescriptorPlayback->periodSizeInFrames); @@ -25770,7 +25771,7 @@ static ma_result ma_device_init_by_type__webaudio(ma_device* pDevice, const ma_d var isCapture = $3; var pDevice = $4; - if (typeof(miniaudio) === 'undefined') { + if (typeof(window.miniaudio) === 'undefined') { return -1; /* Context not initialized. */ } @@ -26067,8 +26068,8 @@ static ma_result ma_context_init__webaudio(ma_context* pContext, const ma_contex return 0; /* Web Audio not supported. */ } - if (typeof(miniaudio) === 'undefined') { - miniaudio = {}; + if (typeof(window.miniaudio) === 'undefined') { + window.miniaudio = {}; miniaudio.devices = []; /* Device cache for mapping devices to indexes for JavaScript/C interop. */ miniaudio.track_device = function(device) { @@ -39463,7 +39464,7 @@ extern "C" { #define DRWAV_XSTRINGIFY(x) DRWAV_STRINGIFY(x) #define DRWAV_VERSION_MAJOR 0 #define DRWAV_VERSION_MINOR 13 -#define DRWAV_VERSION_REVISION 1 +#define DRWAV_VERSION_REVISION 4 #define DRWAV_VERSION_STRING DRWAV_XSTRINGIFY(DRWAV_VERSION_MAJOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_MINOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_REVISION) #include typedef signed char drwav_int8; @@ -46323,6 +46324,7 @@ code below please report the bug to the respective repository for the relevant p #define drwav_min(a, b) (((a) < (b)) ? (a) : (b)) #define drwav_max(a, b) (((a) > (b)) ? (a) : (b)) #define drwav_clamp(x, lo, hi) (drwav_max((lo), drwav_min((hi), (x)))) +#define drwav_offset_ptr(p, offset) (((drwav_uint8*)(p)) + (offset)) #define DRWAV_MAX_SIMD_VECTOR_SIZE 64 #if defined(__x86_64__) || defined(_M_X64) #define DRWAV_X64 @@ -46566,6 +46568,9 @@ static DRWAV_INLINE void drwav__bswap_samples_pcm(void* pSamples, drwav_uint64 s { switch (bytesPerSample) { + case 1: + { + } break; case 2: { drwav__bswap_samples_s16((drwav_int16*)pSamples, sampleCount); @@ -46976,12 +46981,13 @@ DRWAV_PRIVATE size_t drwav__metadata_parser_read(drwav__metadata_parser* pParser return pParser->onRead(pParser->pReadSeekUserData, pBufferOut, bytesToRead); } } -DRWAV_PRIVATE drwav_uint64 drwav__read_smpl_to_metadata_obj(drwav__metadata_parser* pParser, drwav_metadata* pMetadata) +DRWAV_PRIVATE drwav_uint64 drwav__read_smpl_to_metadata_obj(drwav__metadata_parser* pParser, const drwav_chunk_header* pChunkHeader, drwav_metadata* pMetadata) { drwav_uint8 smplHeaderData[DRWAV_SMPL_BYTES]; drwav_uint64 totalBytesRead = 0; size_t bytesJustRead = drwav__metadata_parser_read(pParser, smplHeaderData, sizeof(smplHeaderData), &totalBytesRead); DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read); + DRWAV_ASSERT(pChunkHeader != NULL); if (bytesJustRead == sizeof(smplHeaderData)) { drwav_uint32 iSampleLoop; pMetadata->type = drwav_metadata_type_smpl; @@ -46994,30 +47000,32 @@ DRWAV_PRIVATE drwav_uint64 drwav__read_smpl_to_metadata_obj(drwav__metadata_pars pMetadata->data.smpl.smpteOffset = drwav_bytes_to_u32(smplHeaderData + 24); pMetadata->data.smpl.sampleLoopCount = drwav_bytes_to_u32(smplHeaderData + 28); pMetadata->data.smpl.samplerSpecificDataSizeInBytes = drwav_bytes_to_u32(smplHeaderData + 32); - pMetadata->data.smpl.pLoops = (drwav_smpl_loop*)drwav__metadata_get_memory(pParser, sizeof(drwav_smpl_loop) * pMetadata->data.smpl.sampleLoopCount, DRWAV_METADATA_ALIGNMENT); - for (iSampleLoop = 0; iSampleLoop < pMetadata->data.smpl.sampleLoopCount; ++iSampleLoop) { - drwav_uint8 smplLoopData[DRWAV_SMPL_LOOP_BYTES]; - bytesJustRead = drwav__metadata_parser_read(pParser, smplLoopData, sizeof(smplLoopData), &totalBytesRead); - if (bytesJustRead == sizeof(smplLoopData)) { - pMetadata->data.smpl.pLoops[iSampleLoop].cuePointId = drwav_bytes_to_u32(smplLoopData + 0); - pMetadata->data.smpl.pLoops[iSampleLoop].type = drwav_bytes_to_u32(smplLoopData + 4); - pMetadata->data.smpl.pLoops[iSampleLoop].firstSampleByteOffset = drwav_bytes_to_u32(smplLoopData + 8); - pMetadata->data.smpl.pLoops[iSampleLoop].lastSampleByteOffset = drwav_bytes_to_u32(smplLoopData + 12); - pMetadata->data.smpl.pLoops[iSampleLoop].sampleFraction = drwav_bytes_to_u32(smplLoopData + 16); - pMetadata->data.smpl.pLoops[iSampleLoop].playCount = drwav_bytes_to_u32(smplLoopData + 20); - } else { - break; + if (pMetadata->data.smpl.sampleLoopCount == (pChunkHeader->sizeInBytes - DRWAV_SMPL_BYTES) / DRWAV_SMPL_LOOP_BYTES) { + pMetadata->data.smpl.pLoops = (drwav_smpl_loop*)drwav__metadata_get_memory(pParser, sizeof(drwav_smpl_loop) * pMetadata->data.smpl.sampleLoopCount, DRWAV_METADATA_ALIGNMENT); + for (iSampleLoop = 0; iSampleLoop < pMetadata->data.smpl.sampleLoopCount; ++iSampleLoop) { + drwav_uint8 smplLoopData[DRWAV_SMPL_LOOP_BYTES]; + bytesJustRead = drwav__metadata_parser_read(pParser, smplLoopData, sizeof(smplLoopData), &totalBytesRead); + if (bytesJustRead == sizeof(smplLoopData)) { + pMetadata->data.smpl.pLoops[iSampleLoop].cuePointId = drwav_bytes_to_u32(smplLoopData + 0); + pMetadata->data.smpl.pLoops[iSampleLoop].type = drwav_bytes_to_u32(smplLoopData + 4); + pMetadata->data.smpl.pLoops[iSampleLoop].firstSampleByteOffset = drwav_bytes_to_u32(smplLoopData + 8); + pMetadata->data.smpl.pLoops[iSampleLoop].lastSampleByteOffset = drwav_bytes_to_u32(smplLoopData + 12); + pMetadata->data.smpl.pLoops[iSampleLoop].sampleFraction = drwav_bytes_to_u32(smplLoopData + 16); + pMetadata->data.smpl.pLoops[iSampleLoop].playCount = drwav_bytes_to_u32(smplLoopData + 20); + } else { + break; + } + } + if (pMetadata->data.smpl.samplerSpecificDataSizeInBytes > 0) { + pMetadata->data.smpl.pSamplerSpecificData = drwav__metadata_get_memory(pParser, pMetadata->data.smpl.samplerSpecificDataSizeInBytes, 1); + DRWAV_ASSERT(pMetadata->data.smpl.pSamplerSpecificData != NULL); + drwav__metadata_parser_read(pParser, pMetadata->data.smpl.pSamplerSpecificData, pMetadata->data.smpl.samplerSpecificDataSizeInBytes, &totalBytesRead); } - } - if (pMetadata->data.smpl.samplerSpecificDataSizeInBytes > 0) { - pMetadata->data.smpl.pSamplerSpecificData = drwav__metadata_get_memory(pParser, pMetadata->data.smpl.samplerSpecificDataSizeInBytes, 1); - DRWAV_ASSERT(pMetadata->data.smpl.pSamplerSpecificData != NULL); - bytesJustRead = drwav__metadata_parser_read(pParser, pMetadata->data.smpl.pSamplerSpecificData, pMetadata->data.smpl.samplerSpecificDataSizeInBytes, &totalBytesRead); } } return totalBytesRead; } -DRWAV_PRIVATE drwav_uint64 drwav__read_cue_to_metadata_obj(drwav__metadata_parser* pParser, drwav_metadata* pMetadata) +DRWAV_PRIVATE drwav_uint64 drwav__read_cue_to_metadata_obj(drwav__metadata_parser* pParser, const drwav_chunk_header* pChunkHeader, drwav_metadata* pMetadata) { drwav_uint8 cueHeaderSectionData[DRWAV_CUE_BYTES]; drwav_uint64 totalBytesRead = 0; @@ -47026,25 +47034,27 @@ DRWAV_PRIVATE drwav_uint64 drwav__read_cue_to_metadata_obj(drwav__metadata_parse if (bytesJustRead == sizeof(cueHeaderSectionData)) { pMetadata->type = drwav_metadata_type_cue; pMetadata->data.cue.cuePointCount = drwav_bytes_to_u32(cueHeaderSectionData); - pMetadata->data.cue.pCuePoints = (drwav_cue_point*)drwav__metadata_get_memory(pParser, sizeof(drwav_cue_point) * pMetadata->data.cue.cuePointCount, DRWAV_METADATA_ALIGNMENT); - DRWAV_ASSERT(pMetadata->data.cue.pCuePoints != NULL); - if (pMetadata->data.cue.cuePointCount > 0) { - drwav_uint32 iCuePoint; - for (iCuePoint = 0; iCuePoint < pMetadata->data.cue.cuePointCount; ++iCuePoint) { - drwav_uint8 cuePointData[DRWAV_CUE_POINT_BYTES]; - bytesJustRead = drwav__metadata_parser_read(pParser, cuePointData, sizeof(cuePointData), &totalBytesRead); - if (bytesJustRead == sizeof(cuePointData)) { - pMetadata->data.cue.pCuePoints[iCuePoint].id = drwav_bytes_to_u32(cuePointData + 0); - pMetadata->data.cue.pCuePoints[iCuePoint].playOrderPosition = drwav_bytes_to_u32(cuePointData + 4); - pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[0] = cuePointData[8]; - pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[1] = cuePointData[9]; - pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[2] = cuePointData[10]; - pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[3] = cuePointData[11]; - pMetadata->data.cue.pCuePoints[iCuePoint].chunkStart = drwav_bytes_to_u32(cuePointData + 12); - pMetadata->data.cue.pCuePoints[iCuePoint].blockStart = drwav_bytes_to_u32(cuePointData + 16); - pMetadata->data.cue.pCuePoints[iCuePoint].sampleByteOffset = drwav_bytes_to_u32(cuePointData + 20); - } else { - break; + if (pMetadata->data.cue.cuePointCount == (pChunkHeader->sizeInBytes - DRWAV_CUE_BYTES) / DRWAV_CUE_POINT_BYTES) { + pMetadata->data.cue.pCuePoints = (drwav_cue_point*)drwav__metadata_get_memory(pParser, sizeof(drwav_cue_point) * pMetadata->data.cue.cuePointCount, DRWAV_METADATA_ALIGNMENT); + DRWAV_ASSERT(pMetadata->data.cue.pCuePoints != NULL); + if (pMetadata->data.cue.cuePointCount > 0) { + drwav_uint32 iCuePoint; + for (iCuePoint = 0; iCuePoint < pMetadata->data.cue.cuePointCount; ++iCuePoint) { + drwav_uint8 cuePointData[DRWAV_CUE_POINT_BYTES]; + bytesJustRead = drwav__metadata_parser_read(pParser, cuePointData, sizeof(cuePointData), &totalBytesRead); + if (bytesJustRead == sizeof(cuePointData)) { + pMetadata->data.cue.pCuePoints[iCuePoint].id = drwav_bytes_to_u32(cuePointData + 0); + pMetadata->data.cue.pCuePoints[iCuePoint].playOrderPosition = drwav_bytes_to_u32(cuePointData + 4); + pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[0] = cuePointData[8]; + pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[1] = cuePointData[9]; + pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[2] = cuePointData[10]; + pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[3] = cuePointData[11]; + pMetadata->data.cue.pCuePoints[iCuePoint].chunkStart = drwav_bytes_to_u32(cuePointData + 12); + pMetadata->data.cue.pCuePoints[iCuePoint].blockStart = drwav_bytes_to_u32(cuePointData + 16); + pMetadata->data.cue.pCuePoints[iCuePoint].sampleByteOffset = drwav_bytes_to_u32(cuePointData + 20); + } else { + break; + } } } } @@ -47086,7 +47096,7 @@ DRWAV_PRIVATE drwav_uint64 drwav__read_acid_to_metadata_obj(drwav__metadata_pars } return bytesRead; } -DRWAV_PRIVATE size_t drwav__strlen_clamped(char* str, size_t maxToRead) +DRWAV_PRIVATE size_t drwav__strlen_clamped(const char* str, size_t maxToRead) { size_t result = 0; while (*str++ && result < maxToRead) { @@ -47094,7 +47104,7 @@ DRWAV_PRIVATE size_t drwav__strlen_clamped(char* str, size_t maxToRead) } return result; } -DRWAV_PRIVATE char* drwav__metadata_copy_string(drwav__metadata_parser* pParser, char* str, size_t maxToRead) +DRWAV_PRIVATE char* drwav__metadata_copy_string(drwav__metadata_parser* pParser, const char* str, size_t maxToRead) { size_t len = drwav__strlen_clamped(str, maxToRead); if (len) { @@ -47107,58 +47117,134 @@ DRWAV_PRIVATE char* drwav__metadata_copy_string(drwav__metadata_parser* pParser, return NULL; } } +typedef struct +{ + const void* pBuffer; + size_t sizeInBytes; + size_t cursor; +} drwav_buffer_reader; +DRWAV_PRIVATE drwav_result drwav_buffer_reader_init(const void* pBuffer, size_t sizeInBytes, drwav_buffer_reader* pReader) +{ + DRWAV_ASSERT(pBuffer != NULL); + DRWAV_ASSERT(pReader != NULL); + DRWAV_ZERO_OBJECT(pReader); + pReader->pBuffer = pBuffer; + pReader->sizeInBytes = sizeInBytes; + pReader->cursor = 0; + return DRWAV_SUCCESS; +} +DRWAV_PRIVATE const void* drwav_buffer_reader_ptr(const drwav_buffer_reader* pReader) +{ + DRWAV_ASSERT(pReader != NULL); + return drwav_offset_ptr(pReader->pBuffer, pReader->cursor); +} +DRWAV_PRIVATE drwav_result drwav_buffer_reader_seek(drwav_buffer_reader* pReader, size_t bytesToSeek) +{ + DRWAV_ASSERT(pReader != NULL); + if (pReader->cursor + bytesToSeek > pReader->sizeInBytes) { + return DRWAV_BAD_SEEK; + } + pReader->cursor += bytesToSeek; + return DRWAV_SUCCESS; +} +DRWAV_PRIVATE drwav_result drwav_buffer_reader_read(drwav_buffer_reader* pReader, void* pDst, size_t bytesToRead, size_t* pBytesRead) +{ + drwav_result result = DRWAV_SUCCESS; + size_t bytesRemaining; + DRWAV_ASSERT(pReader != NULL); + if (pBytesRead != NULL) { + *pBytesRead = 0; + } + bytesRemaining = (pReader->sizeInBytes - pReader->cursor); + if (bytesToRead > bytesRemaining) { + bytesToRead = bytesRemaining; + } + if (pDst == NULL) { + result = drwav_buffer_reader_seek(pReader, bytesToRead); + } else { + DRWAV_COPY_MEMORY(pDst, drwav_buffer_reader_ptr(pReader), bytesToRead); + pReader->cursor += bytesToRead; + } + DRWAV_ASSERT(pReader->cursor <= pReader->sizeInBytes); + if (result == DRWAV_SUCCESS) { + if (pBytesRead != NULL) { + *pBytesRead = bytesToRead; + } + } + return DRWAV_SUCCESS; +} +DRWAV_PRIVATE drwav_result drwav_buffer_reader_read_u16(drwav_buffer_reader* pReader, drwav_uint16* pDst) +{ + drwav_result result; + size_t bytesRead; + drwav_uint8 data[2]; + DRWAV_ASSERT(pReader != NULL); + DRWAV_ASSERT(pDst != NULL); + *pDst = 0; + result = drwav_buffer_reader_read(pReader, data, sizeof(*pDst), &bytesRead); + if (result != DRWAV_SUCCESS || bytesRead != sizeof(*pDst)) { + return result; + } + *pDst = drwav_bytes_to_u16(data); + return DRWAV_SUCCESS; +} +DRWAV_PRIVATE drwav_result drwav_buffer_reader_read_u32(drwav_buffer_reader* pReader, drwav_uint32* pDst) +{ + drwav_result result; + size_t bytesRead; + drwav_uint8 data[4]; + DRWAV_ASSERT(pReader != NULL); + DRWAV_ASSERT(pDst != NULL); + *pDst = 0; + result = drwav_buffer_reader_read(pReader, data, sizeof(*pDst), &bytesRead); + if (result != DRWAV_SUCCESS || bytesRead != sizeof(*pDst)) { + return result; + } + *pDst = drwav_bytes_to_u32(data); + return DRWAV_SUCCESS; +} DRWAV_PRIVATE drwav_uint64 drwav__read_bext_to_metadata_obj(drwav__metadata_parser* pParser, drwav_metadata* pMetadata, drwav_uint64 chunkSize) { drwav_uint8 bextData[DRWAV_BEXT_BYTES]; - drwav_uint64 bytesRead = drwav__metadata_parser_read(pParser, bextData, sizeof(bextData), NULL); + size_t bytesRead = drwav__metadata_parser_read(pParser, bextData, sizeof(bextData), NULL); DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read); if (bytesRead == sizeof(bextData)) { - drwav_uint8* pReadPointer; + drwav_buffer_reader reader; drwav_uint32 timeReferenceLow; drwav_uint32 timeReferenceHigh; size_t extraBytes; pMetadata->type = drwav_metadata_type_bext; - pReadPointer = bextData; - pMetadata->data.bext.pDescription = drwav__metadata_copy_string(pParser, (char*)(pReadPointer), DRWAV_BEXT_DESCRIPTION_BYTES); - pReadPointer += DRWAV_BEXT_DESCRIPTION_BYTES; - pMetadata->data.bext.pOriginatorName = drwav__metadata_copy_string(pParser, (char*)(pReadPointer), DRWAV_BEXT_ORIGINATOR_NAME_BYTES); - pReadPointer += DRWAV_BEXT_ORIGINATOR_NAME_BYTES; - pMetadata->data.bext.pOriginatorReference = drwav__metadata_copy_string(pParser, (char*)(pReadPointer), DRWAV_BEXT_ORIGINATOR_REF_BYTES); - pReadPointer += DRWAV_BEXT_ORIGINATOR_REF_BYTES; - memcpy(pReadPointer, pMetadata->data.bext.pOriginationDate, sizeof(pMetadata->data.bext.pOriginationDate)); - pReadPointer += sizeof(pMetadata->data.bext.pOriginationDate); - memcpy(pReadPointer, pMetadata->data.bext.pOriginationTime, sizeof(pMetadata->data.bext.pOriginationTime)); - pReadPointer += sizeof(pMetadata->data.bext.pOriginationTime); - timeReferenceLow = drwav_bytes_to_u32(pReadPointer); - pReadPointer += sizeof(drwav_uint32); - timeReferenceHigh = drwav_bytes_to_u32(pReadPointer); - pReadPointer += sizeof(drwav_uint32); - pMetadata->data.bext.timeReference = ((drwav_uint64)timeReferenceHigh << 32) + timeReferenceLow; - pMetadata->data.bext.version = drwav_bytes_to_u16(pReadPointer); - pReadPointer += sizeof(drwav_uint16); - pMetadata->data.bext.pUMID = drwav__metadata_get_memory(pParser, DRWAV_BEXT_UMID_BYTES, 1); - memcpy(pMetadata->data.bext.pUMID, pReadPointer, DRWAV_BEXT_UMID_BYTES); - pReadPointer += DRWAV_BEXT_UMID_BYTES; - pMetadata->data.bext.loudnessValue = drwav_bytes_to_u16(pReadPointer); - pReadPointer += sizeof(drwav_uint16); - pMetadata->data.bext.loudnessRange = drwav_bytes_to_u16(pReadPointer); - pReadPointer += sizeof(drwav_uint16); - pMetadata->data.bext.maxTruePeakLevel = drwav_bytes_to_u16(pReadPointer); - pReadPointer += sizeof(drwav_uint16); - pMetadata->data.bext.maxMomentaryLoudness = drwav_bytes_to_u16(pReadPointer); - pReadPointer += sizeof(drwav_uint16); - pMetadata->data.bext.maxShortTermLoudness = drwav_bytes_to_u16(pReadPointer); - pReadPointer += sizeof(drwav_uint16); - DRWAV_ASSERT((pReadPointer + DRWAV_BEXT_RESERVED_BYTES) == (bextData + DRWAV_BEXT_BYTES)); - extraBytes = (size_t)(chunkSize - DRWAV_BEXT_BYTES); - if (extraBytes > 0) { - pMetadata->data.bext.pCodingHistory = (char*)drwav__metadata_get_memory(pParser, extraBytes + 1, 1); - DRWAV_ASSERT(pMetadata->data.bext.pCodingHistory != NULL); - bytesRead += drwav__metadata_parser_read(pParser, pMetadata->data.bext.pCodingHistory, extraBytes, NULL); - pMetadata->data.bext.codingHistorySize = (drwav_uint32)strlen(pMetadata->data.bext.pCodingHistory); - } else { - pMetadata->data.bext.pCodingHistory = NULL; - pMetadata->data.bext.codingHistorySize = 0; + if (drwav_buffer_reader_init(bextData, bytesRead, &reader) == DRWAV_SUCCESS) { + pMetadata->data.bext.pDescription = drwav__metadata_copy_string(pParser, (const char*)drwav_buffer_reader_ptr(&reader), DRWAV_BEXT_DESCRIPTION_BYTES); + drwav_buffer_reader_seek(&reader, DRWAV_BEXT_DESCRIPTION_BYTES); + pMetadata->data.bext.pOriginatorName = drwav__metadata_copy_string(pParser, (const char*)drwav_buffer_reader_ptr(&reader), DRWAV_BEXT_ORIGINATOR_NAME_BYTES); + drwav_buffer_reader_seek(&reader, DRWAV_BEXT_ORIGINATOR_NAME_BYTES); + pMetadata->data.bext.pOriginatorReference = drwav__metadata_copy_string(pParser, (const char*)drwav_buffer_reader_ptr(&reader), DRWAV_BEXT_ORIGINATOR_REF_BYTES); + drwav_buffer_reader_seek(&reader, DRWAV_BEXT_ORIGINATOR_REF_BYTES); + drwav_buffer_reader_read(&reader, pMetadata->data.bext.pOriginationDate, sizeof(pMetadata->data.bext.pOriginationDate), NULL); + drwav_buffer_reader_read(&reader, pMetadata->data.bext.pOriginationTime, sizeof(pMetadata->data.bext.pOriginationTime), NULL); + drwav_buffer_reader_read_u32(&reader, &timeReferenceLow); + drwav_buffer_reader_read_u32(&reader, &timeReferenceHigh); + pMetadata->data.bext.timeReference = ((drwav_uint64)timeReferenceHigh << 32) + timeReferenceLow; + drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.version); + pMetadata->data.bext.pUMID = drwav__metadata_get_memory(pParser, DRWAV_BEXT_UMID_BYTES, 1); + drwav_buffer_reader_read(&reader, pMetadata->data.bext.pUMID, DRWAV_BEXT_UMID_BYTES, NULL); + drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.loudnessValue); + drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.loudnessRange); + drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.maxTruePeakLevel); + drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.maxMomentaryLoudness); + drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.maxShortTermLoudness); + DRWAV_ASSERT((drwav_offset_ptr(drwav_buffer_reader_ptr(&reader), DRWAV_BEXT_RESERVED_BYTES)) == (bextData + DRWAV_BEXT_BYTES)); + extraBytes = (size_t)(chunkSize - DRWAV_BEXT_BYTES); + if (extraBytes > 0) { + pMetadata->data.bext.pCodingHistory = (char*)drwav__metadata_get_memory(pParser, extraBytes + 1, 1); + DRWAV_ASSERT(pMetadata->data.bext.pCodingHistory != NULL); + bytesRead += drwav__metadata_parser_read(pParser, pMetadata->data.bext.pCodingHistory, extraBytes, NULL); + pMetadata->data.bext.codingHistorySize = (drwav_uint32)strlen(pMetadata->data.bext.pCodingHistory); + } else { + pMetadata->data.bext.pCodingHistory = NULL; + pMetadata->data.bext.codingHistorySize = 0; + } } } return bytesRead; @@ -47178,7 +47264,7 @@ DRWAV_PRIVATE drwav_uint64 drwav__read_list_label_or_note_to_metadata_obj(drwav_ pMetadata->data.labelOrNote.stringLength = sizeIncludingNullTerminator - 1; pMetadata->data.labelOrNote.pString = (char*)drwav__metadata_get_memory(pParser, sizeIncludingNullTerminator, 1); DRWAV_ASSERT(pMetadata->data.labelOrNote.pString != NULL); - bytesJustRead = drwav__metadata_parser_read(pParser, pMetadata->data.labelOrNote.pString, sizeIncludingNullTerminator, &totalBytesRead); + drwav__metadata_parser_read(pParser, pMetadata->data.labelOrNote.pString, sizeIncludingNullTerminator, &totalBytesRead); } else { pMetadata->data.labelOrNote.stringLength = 0; pMetadata->data.labelOrNote.pString = NULL; @@ -47210,7 +47296,7 @@ DRWAV_PRIVATE drwav_uint64 drwav__read_list_labelled_cue_region_to_metadata_obj( pMetadata->data.labelledCueRegion.stringLength = sizeIncludingNullTerminator - 1; pMetadata->data.labelledCueRegion.pString = (char*)drwav__metadata_get_memory(pParser, sizeIncludingNullTerminator, 1); DRWAV_ASSERT(pMetadata->data.labelledCueRegion.pString != NULL); - bytesJustRead = drwav__metadata_parser_read(pParser, pMetadata->data.labelledCueRegion.pString, sizeIncludingNullTerminator, &totalBytesRead); + drwav__metadata_parser_read(pParser, pMetadata->data.labelledCueRegion.pString, sizeIncludingNullTerminator, &totalBytesRead); } else { pMetadata->data.labelledCueRegion.stringLength = 0; pMetadata->data.labelledCueRegion.pString = NULL; @@ -47276,11 +47362,11 @@ DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_unknown_chunk(drwav__metadata } return bytesRead; } -DRWAV_PRIVATE drwav_bool32 drwav__chunk_matches(drwav_uint64 allowedMetadataTypes, const drwav_uint8* pChunkID, drwav_metadata_type type, const char* pID) +DRWAV_PRIVATE drwav_bool32 drwav__chunk_matches(drwav_metadata_type allowedMetadataTypes, const drwav_uint8* pChunkID, drwav_metadata_type type, const char* pID) { return (allowedMetadataTypes & type) && drwav_fourcc_equal(pChunkID, pID); } -DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_chunk(drwav__metadata_parser* pParser, const drwav_chunk_header* pChunkHeader, drwav_uint64 allowedMetadataTypes) +DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_chunk(drwav__metadata_parser* pParser, const drwav_chunk_header* pChunkHeader, drwav_metadata_type allowedMetadataTypes) { const drwav_uint8 *pChunkID = pChunkHeader->id.fourcc; drwav_uint64 bytesRead = 0; @@ -47296,16 +47382,21 @@ DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_chunk(drwav__metadata_parser* bytesJustRead = drwav__metadata_parser_read(pParser, buffer, sizeof(buffer), &bytesRead); if (bytesJustRead == sizeof(buffer)) { drwav_uint32 loopCount = drwav_bytes_to_u32(buffer); - bytesJustRead = drwav__metadata_parser_read(pParser, buffer, sizeof(buffer), &bytesRead); - if (bytesJustRead == sizeof(buffer)) { - drwav_uint32 samplerSpecificDataSizeInBytes = drwav_bytes_to_u32(buffer); - pParser->metadataCount += 1; - drwav__metadata_request_extra_memory_for_stage_2(pParser, sizeof(drwav_smpl_loop) * loopCount, DRWAV_METADATA_ALIGNMENT); - drwav__metadata_request_extra_memory_for_stage_2(pParser, samplerSpecificDataSizeInBytes, 1); + drwav_uint64 calculatedLoopCount; + calculatedLoopCount = (pChunkHeader->sizeInBytes - DRWAV_SMPL_BYTES) / DRWAV_SMPL_LOOP_BYTES; + if (calculatedLoopCount == loopCount) { + bytesJustRead = drwav__metadata_parser_read(pParser, buffer, sizeof(buffer), &bytesRead); + if (bytesJustRead == sizeof(buffer)) { + drwav_uint32 samplerSpecificDataSizeInBytes = drwav_bytes_to_u32(buffer); + pParser->metadataCount += 1; + drwav__metadata_request_extra_memory_for_stage_2(pParser, sizeof(drwav_smpl_loop) * loopCount, DRWAV_METADATA_ALIGNMENT); + drwav__metadata_request_extra_memory_for_stage_2(pParser, samplerSpecificDataSizeInBytes, 1); + } + } else { } } } else { - bytesRead = drwav__read_smpl_to_metadata_obj(pParser, &pParser->pMetadata[pParser->metadataCursor]); + bytesRead = drwav__read_smpl_to_metadata_obj(pParser, pChunkHeader, &pParser->pMetadata[pParser->metadataCursor]); if (bytesRead == pChunkHeader->sizeInBytes) { pParser->metadataCursor += 1; } else { @@ -47347,7 +47438,7 @@ DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_chunk(drwav__metadata_parser* cueCount = (size_t)(pChunkHeader->sizeInBytes - DRWAV_CUE_BYTES) / DRWAV_CUE_POINT_BYTES; drwav__metadata_request_extra_memory_for_stage_2(pParser, sizeof(drwav_cue_point) * cueCount, DRWAV_METADATA_ALIGNMENT); } else { - bytesRead = drwav__read_cue_to_metadata_obj(pParser, &pParser->pMetadata[pParser->metadataCursor]); + bytesRead = drwav__read_cue_to_metadata_obj(pParser, pChunkHeader, &pParser->pMetadata[pParser->metadataCursor]); if (bytesRead == pChunkHeader->sizeInBytes) { pParser->metadataCursor += 1; } else { @@ -47462,7 +47553,7 @@ DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_chunk(drwav__metadata_parser* subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize, drwav_metadata_type_list_info_album); } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_tracknumber, "ITRK")) { subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize, drwav_metadata_type_list_info_tracknumber); - } else if (allowedMetadataTypes & drwav_metadata_type_unknown) { + } else if ((allowedMetadataTypes & drwav_metadata_type_unknown) != 0) { subchunkBytesRead = drwav__metadata_process_unknown_chunk(pParser, subchunkId, subchunkDataSize, listType); } bytesRead += subchunkBytesRead; @@ -47481,18 +47572,25 @@ DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_chunk(drwav__metadata_parser* bytesRead += 1; } } - } else if (allowedMetadataTypes & drwav_metadata_type_unknown) { + } else if ((allowedMetadataTypes & drwav_metadata_type_unknown) != 0) { bytesRead = drwav__metadata_process_unknown_chunk(pParser, pChunkID, pChunkHeader->sizeInBytes, drwav_metadata_location_top_level); } return bytesRead; } DRWAV_PRIVATE drwav_uint32 drwav_get_bytes_per_pcm_frame(drwav* pWav) { + drwav_uint32 bytesPerFrame; if ((pWav->bitsPerSample & 0x7) == 0) { - return (pWav->bitsPerSample * pWav->fmt.channels) >> 3; + bytesPerFrame = (pWav->bitsPerSample * pWav->fmt.channels) >> 3; } else { - return pWav->fmt.blockAlign; + bytesPerFrame = pWav->fmt.blockAlign; } + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW || pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) { + if (bytesPerFrame != pWav->fmt.channels) { + return 0; + } + } + return bytesPerFrame; } DRWAV_API drwav_uint16 drwav_fmt_get_format(const drwav_fmt* pFMT) { @@ -47773,7 +47871,11 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on if (sampleCountFromFactChunk != 0) { pWav->totalPCMFrameCount = sampleCountFromFactChunk; } else { - pWav->totalPCMFrameCount = dataChunkSize / drwav_get_bytes_per_pcm_frame(pWav); + drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return DRWAV_FALSE; + } + pWav->totalPCMFrameCount = dataChunkSize / bytesPerFrame; if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { drwav_uint64 totalBlockHeaderSizeInBytes; drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign; @@ -47799,6 +47901,9 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on return DRWAV_FALSE; } } + if (drwav_get_bytes_per_pcm_frame(pWav) == 0) { + return DRWAV_FALSE; + } #ifdef DR_WAV_LIBSNDFILE_COMPAT if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign; @@ -49300,6 +49405,7 @@ DRWAV_API drwav_result drwav_uninit(drwav* pWav) DRWAV_API size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOut) { size_t bytesRead; + drwav_uint32 bytesPerFrame; if (pWav == NULL || bytesToRead == 0) { return 0; } @@ -49309,6 +49415,10 @@ DRWAV_API size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOu if (bytesToRead == 0) { return 0; } + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return 0; + } if (pBufferOut != NULL) { bytesRead = pWav->onRead(pWav->pUserData, pBufferOut, bytesToRead); } else { @@ -49337,7 +49447,7 @@ DRWAV_API size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOu } } } - pWav->readCursorInPCMFrames += bytesRead / drwav_get_bytes_per_pcm_frame(pWav); + pWav->readCursorInPCMFrames += bytesRead / bytesPerFrame; pWav->bytesRemaining -= bytesRead; return bytesRead; } @@ -49368,7 +49478,11 @@ DRWAV_API drwav_uint64 drwav_read_pcm_frames_be(drwav* pWav, drwav_uint64 frames { drwav_uint64 framesRead = drwav_read_pcm_frames_le(pWav, framesToRead, pBufferOut); if (pBufferOut != NULL) { - drwav__bswap_samples(pBufferOut, framesRead*pWav->channels, drwav_get_bytes_per_pcm_frame(pWav)/pWav->channels, pWav->translatedFormatTag); + drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return 0; + } + drwav__bswap_samples(pBufferOut, framesRead*pWav->channels, bytesPerFrame/pWav->channels, pWav->translatedFormatTag); } return framesRead; } @@ -49448,10 +49562,15 @@ DRWAV_API drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetF drwav_uint64 currentBytePos; drwav_uint64 targetBytePos; drwav_uint64 offset; - totalSizeInBytes = pWav->totalPCMFrameCount * drwav_get_bytes_per_pcm_frame(pWav); + drwav_uint32 bytesPerFrame; + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return DRWAV_FALSE; + } + totalSizeInBytes = pWav->totalPCMFrameCount * bytesPerFrame; DRWAV_ASSERT(totalSizeInBytes >= pWav->bytesRemaining); currentBytePos = totalSizeInBytes - pWav->bytesRemaining; - targetBytePos = targetFrameIndex * drwav_get_bytes_per_pcm_frame(pWav); + targetBytePos = targetFrameIndex * bytesPerFrame; if (currentBytePos < targetBytePos) { offset = (targetBytePos - currentBytePos); } else { @@ -49465,7 +49584,7 @@ DRWAV_API drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetF if (!pWav->onSeek(pWav->pUserData, offset32, drwav_seek_origin_current)) { return DRWAV_FALSE; } - pWav->readCursorInPCMFrames += offset32 / drwav_get_bytes_per_pcm_frame(pWav); + pWav->readCursorInPCMFrames += offset32 / bytesPerFrame; pWav->bytesRemaining -= offset32; offset -= offset32; } @@ -49551,6 +49670,9 @@ DRWAV_API drwav_uint64 drwav_write_pcm_frames_be(drwav* pWav, drwav_uint64 frame bytesWritten = 0; pRunningData = (const drwav_uint8*)pData; bytesPerSample = drwav_get_bytes_per_pcm_frame(pWav) / pWav->channels; + if (bytesPerSample == 0) { + return 0; + } while (bytesToWrite > 0) { drwav_uint8 temp[4096]; drwav_uint32 sampleCount; @@ -49749,7 +49871,7 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uin return totalFramesRead; } pWav->ima.predictor[0] = drwav_bytes_to_s16(header + 0); - pWav->ima.stepIndex[0] = header[2]; + pWav->ima.stepIndex[0] = drwav_clamp(header[2], 0, (drwav_int32)drwav_countof(stepTable)-1); pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 1] = pWav->ima.predictor[0]; pWav->ima.cachedFrameCount = 1; } else { @@ -49764,9 +49886,9 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uin return totalFramesRead; } pWav->ima.predictor[0] = drwav_bytes_to_s16(header + 0); - pWav->ima.stepIndex[0] = header[2]; + pWav->ima.stepIndex[0] = drwav_clamp(header[2], 0, (drwav_int32)drwav_countof(stepTable)-1); pWav->ima.predictor[1] = drwav_bytes_to_s16(header + 4); - pWav->ima.stepIndex[1] = header[6]; + pWav->ima.stepIndex[1] = drwav_clamp(header[6], 0, (drwav_int32)drwav_countof(stepTable)-1); pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 2] = pWav->ima.predictor[0]; pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 1] = pWav->ima.predictor[1]; pWav->ima.cachedFrameCount = 1; @@ -49880,7 +50002,7 @@ static DRWAV_INLINE drwav_int16 drwav__mulaw_to_s16(drwav_uint8 sampleIn) } DRWAV_PRIVATE void drwav__pcm_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample) { - unsigned int i; + size_t i; if (bytesPerSample == 1) { drwav_u8_to_s16(pOut, pIn, totalSampleCount); return; @@ -49932,8 +50054,10 @@ DRWAV_PRIVATE void drwav__ieee_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__pcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; + drwav_uint8 sampleData[4096] = {0}; drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; if ((pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM && pWav->bitsPerSample == 16) || pBufferOut == NULL) { return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut); } @@ -49941,14 +50065,25 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__pcm(drwav* pWav, drwav_uin if (bytesPerFrame == 0) { return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; + } totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav__pcm_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels); - pBufferOut += framesRead*pWav->channels; + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); + break; + } + drwav__pcm_to_s16(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample); + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -49957,8 +50092,10 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__pcm(drwav* pWav, drwav_uin DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ieee(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; + drwav_uint8 sampleData[4096] = {0}; drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; if (pBufferOut == NULL) { return drwav_read_pcm_frames(pWav, framesToRead, NULL); } @@ -49966,14 +50103,25 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ieee(drwav* pWav, drwav_ui if (bytesPerFrame == 0) { return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; + } totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav__ieee_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels); - pBufferOut += framesRead*pWav->channels; + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); + break; + } + drwav__ieee_to_s16(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample); + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -49982,8 +50130,10 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ieee(drwav* pWav, drwav_ui DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__alaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; + drwav_uint8 sampleData[4096] = {0}; drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; if (pBufferOut == NULL) { return drwav_read_pcm_frames(pWav, framesToRead, NULL); } @@ -49991,14 +50141,25 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__alaw(drwav* pWav, drwav_ui if (bytesPerFrame == 0) { return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; + } totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav_alaw_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); - pBufferOut += framesRead*pWav->channels; + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); + break; + } + drwav_alaw_to_s16(pBufferOut, sampleData, (size_t)samplesRead); + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -50007,8 +50168,10 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__alaw(drwav* pWav, drwav_ui DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__mulaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; + drwav_uint8 sampleData[4096] = {0}; drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; if (pBufferOut == NULL) { return drwav_read_pcm_frames(pWav, framesToRead, NULL); } @@ -50016,14 +50179,25 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__mulaw(drwav* pWav, drwav_u if (bytesPerFrame == 0) { return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; + } totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav_mulaw_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); - pBufferOut += framesRead*pWav->channels; + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); + break; + } + drwav_mulaw_to_s16(pBufferOut, sampleData, (size_t)samplesRead); + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -50204,49 +50378,50 @@ DRWAV_PRIVATE void drwav__ieee_to_f32(float* pOut, const drwav_uint8* pIn, size_ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__pcm(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; - drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + drwav_uint8 sampleData[4096] = {0}; + drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); if (bytesPerFrame == 0) { return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; + } totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav__pcm_to_f32(pBufferOut, sampleData, (size_t)framesRead*pWav->channels, bytesPerFrame/pWav->channels); - pBufferOut += framesRead*pWav->channels; + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); + break; + } + drwav__pcm_to_f32(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample); + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } return totalFramesRead; } -DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__msadpcm(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__msadpcm_ima(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) { - drwav_uint64 totalFramesRead = 0; + drwav_uint64 totalFramesRead; drwav_int16 samples16[2048]; + totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16); - if (framesRead == 0) { - break; - } - drwav_s16_to_f32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); - pBufferOut += framesRead*pWav->channels; - framesToRead -= framesRead; - totalFramesRead += framesRead; - } - return totalFramesRead; -} -DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__ima(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) -{ - drwav_uint64 totalFramesRead = 0; - drwav_int16 samples16[2048]; - while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels); + drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, framesToReadThisIteration, samples16); if (framesRead == 0) { break; } + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); drwav_s16_to_f32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); pBufferOut += framesRead*pWav->channels; framesToRead -= framesRead; @@ -50257,8 +50432,10 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__ima(drwav* pWav, drwav_uin DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__ieee(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; + drwav_uint8 sampleData[4096] = {0}; drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT && pWav->bitsPerSample == 32) { return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut); } @@ -50266,14 +50443,25 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__ieee(drwav* pWav, drwav_ui if (bytesPerFrame == 0) { return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; + } totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav__ieee_to_f32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels); - pBufferOut += framesRead*pWav->channels; + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); + break; + } + drwav__ieee_to_f32(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample); + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -50282,19 +50470,33 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__ieee(drwav* pWav, drwav_ui DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__alaw(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; - drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + drwav_uint8 sampleData[4096] = {0}; + drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); if (bytesPerFrame == 0) { return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; + } totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav_alaw_to_f32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); - pBufferOut += framesRead*pWav->channels; + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); + break; + } + drwav_alaw_to_f32(pBufferOut, sampleData, (size_t)samplesRead); + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -50303,19 +50505,33 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__alaw(drwav* pWav, drwav_ui DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__mulaw(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; - drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + drwav_uint8 sampleData[4096] = {0}; + drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); if (bytesPerFrame == 0) { return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; + } totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav_mulaw_to_f32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); - pBufferOut += framesRead*pWav->channels; + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); + break; + } + drwav_mulaw_to_f32(pBufferOut, sampleData, (size_t)samplesRead); + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -50335,8 +50551,8 @@ DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32(drwav* pWav, drwav_uint64 frame if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) { return drwav_read_pcm_frames_f32__pcm(pWav, framesToRead, pBufferOut); } - if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { - return drwav_read_pcm_frames_f32__msadpcm(pWav, framesToRead, pBufferOut); + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM || pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { + return drwav_read_pcm_frames_f32__msadpcm_ima(pWav, framesToRead, pBufferOut); } if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) { return drwav_read_pcm_frames_f32__ieee(pWav, framesToRead, pBufferOut); @@ -50347,9 +50563,6 @@ DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32(drwav* pWav, drwav_uint64 frame if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) { return drwav_read_pcm_frames_f32__mulaw(pWav, framesToRead, pBufferOut); } - if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { - return drwav_read_pcm_frames_f32__ima(pWav, framesToRead, pBufferOut); - } return 0; } DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32le(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) @@ -50506,8 +50719,10 @@ DRWAV_PRIVATE void drwav__ieee_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__pcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; + drwav_uint8 sampleData[4096] = {0}; drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM && pWav->bitsPerSample == 32) { return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut); } @@ -50515,44 +50730,41 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__pcm(drwav* pWav, drwav_uin if (bytesPerFrame == 0) { return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; + } totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav__pcm_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels); - pBufferOut += framesRead*pWav->channels; + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); + break; + } + drwav__pcm_to_s32(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample); + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } return totalFramesRead; } -DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__msadpcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__msadpcm_ima(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) { drwav_uint64 totalFramesRead = 0; drwav_int16 samples16[2048]; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16); - if (framesRead == 0) { - break; - } - drwav_s16_to_s32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); - pBufferOut += framesRead*pWav->channels; - framesToRead -= framesRead; - totalFramesRead += framesRead; - } - return totalFramesRead; -} -DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__ima(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) -{ - drwav_uint64 totalFramesRead = 0; - drwav_int16 samples16[2048]; - while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels); + drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, framesToReadThisIteration, samples16); if (framesRead == 0) { break; } + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); drwav_s16_to_s32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); pBufferOut += framesRead*pWav->channels; framesToRead -= framesRead; @@ -50563,19 +50775,33 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__ima(drwav* pWav, drwav_uin DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__ieee(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; - drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + drwav_uint8 sampleData[4096] = {0}; + drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); if (bytesPerFrame == 0) { return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; + } totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav__ieee_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels); - pBufferOut += framesRead*pWav->channels; + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); + break; + } + drwav__ieee_to_s32(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample); + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -50584,19 +50810,33 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__ieee(drwav* pWav, drwav_ui DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__alaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; - drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + drwav_uint8 sampleData[4096] = {0}; + drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); if (bytesPerFrame == 0) { return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; + } totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav_alaw_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); - pBufferOut += framesRead*pWav->channels; + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); + break; + } + drwav_alaw_to_s32(pBufferOut, sampleData, (size_t)samplesRead); + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -50605,19 +50845,33 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__alaw(drwav* pWav, drwav_ui DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__mulaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; - drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + drwav_uint8 sampleData[4096] = {0}; + drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); if (bytesPerFrame == 0) { return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; + } totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav_mulaw_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); - pBufferOut += framesRead*pWav->channels; + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); + break; + } + drwav_mulaw_to_s32(pBufferOut, sampleData, (size_t)samplesRead); + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -50637,8 +50891,8 @@ DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32(drwav* pWav, drwav_uint64 frame if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) { return drwav_read_pcm_frames_s32__pcm(pWav, framesToRead, pBufferOut); } - if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { - return drwav_read_pcm_frames_s32__msadpcm(pWav, framesToRead, pBufferOut); + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM || pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { + return drwav_read_pcm_frames_s32__msadpcm_ima(pWav, framesToRead, pBufferOut); } if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) { return drwav_read_pcm_frames_s32__ieee(pWav, framesToRead, pBufferOut); @@ -50649,9 +50903,6 @@ DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32(drwav* pWav, drwav_uint64 frame if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) { return drwav_read_pcm_frames_s32__mulaw(pWav, framesToRead, pBufferOut); } - if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { - return drwav_read_pcm_frames_s32__ima(pWav, framesToRead, pBufferOut); - } return 0; } DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32le(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) diff --git a/extras/miniaudio_split/miniaudio.h b/extras/miniaudio_split/miniaudio.h index ff633187..b71993b5 100644 --- a/extras/miniaudio_split/miniaudio.h +++ b/extras/miniaudio_split/miniaudio.h @@ -1,6 +1,6 @@ /* Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file. -miniaudio - v0.10.42 - 2021-08-22 +miniaudio - v0.10.43 - 2021-12-10 David Reid - mackron@gmail.com @@ -20,7 +20,7 @@ extern "C" { #define MA_VERSION_MAJOR 0 #define MA_VERSION_MINOR 10 -#define MA_VERSION_REVISION 42 +#define MA_VERSION_REVISION 43 #define MA_VERSION_STRING MA_XSTRINGIFY(MA_VERSION_MAJOR) "." MA_XSTRINGIFY(MA_VERSION_MINOR) "." MA_XSTRINGIFY(MA_VERSION_REVISION) #if defined(_MSC_VER) && !defined(__clang__) diff --git a/miniaudio.h b/miniaudio.h index 63f093e4..f8a36182 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -1,6 +1,6 @@ /* Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file. -miniaudio - v0.10.43 - TBD +miniaudio - v0.10.43 - 2021-12-10 David Reid - mackron@gmail.com @@ -69690,8 +69690,8 @@ The following miscellaneous changes have also been made. /* REVISION HISTORY ================ -v0.10.43 - TBD - - ALSA: Fix use of uninitialized variables +v0.10.43 - 2021-12-10 + - ALSA: Fix use of uninitialized variables. - ALSA: Fix enumeration of devices that support both playback and capture. - PulseAudio: Fix a possible division by zero. - WebAudio: Fix errors in strict mode.