in Audio/WAVFileReader.cpp [135:301]
HRESULT WaveFindFormatAndData(
_In_reads_bytes_(wavDataSize) const uint8_t* wavData,
_In_ size_t wavDataSize,
_Outptr_ const WAVEFORMATEX** pwfx,
_Outptr_ const uint8_t** pdata,
_Out_ uint32_t* dataSize,
_Out_ bool& dpds,
_Out_ bool& seek) noexcept
{
if (!wavData || !pwfx)
return E_POINTER;
dpds = seek = false;
if (wavDataSize < (sizeof(RIFFChunk) * 2 + sizeof(uint32_t) + sizeof(WAVEFORMAT)))
{
return E_FAIL;
}
const uint8_t* wavEnd = wavData + wavDataSize;
// Locate RIFF 'WAVE'
auto riffChunk = FindChunk(wavData, wavDataSize, FOURCC_RIFF_TAG);
if (!riffChunk || riffChunk->size < 4)
{
return E_FAIL;
}
auto riffHeader = reinterpret_cast<const RIFFChunkHeader*>(riffChunk);
if (riffHeader->riff != FOURCC_WAVE_FILE_TAG && riffHeader->riff != FOURCC_XWMA_FILE_TAG)
{
return E_FAIL;
}
// Locate 'fmt '
auto ptr = reinterpret_cast<const uint8_t*>(riffHeader) + sizeof(RIFFChunkHeader);
if ((ptr + sizeof(RIFFChunk)) > wavEnd)
{
return HRESULT_FROM_WIN32(ERROR_HANDLE_EOF);
}
auto fmtChunk = FindChunk(ptr, riffHeader->size, FOURCC_FORMAT_TAG);
if (!fmtChunk || fmtChunk->size < sizeof(PCMWAVEFORMAT))
{
return E_FAIL;
}
ptr = reinterpret_cast<const uint8_t*>(fmtChunk) + sizeof(RIFFChunk);
if (ptr + fmtChunk->size > wavEnd)
{
return HRESULT_FROM_WIN32(ERROR_HANDLE_EOF);
}
auto wf = reinterpret_cast<const WAVEFORMAT*>(ptr);
// Validate WAVEFORMAT (focused on chunk size and format tag, not other data that XAUDIO2 will validate)
switch (wf->wFormatTag)
{
case WAVE_FORMAT_PCM:
case WAVE_FORMAT_IEEE_FLOAT:
// Can be a PCMWAVEFORMAT (16 bytes) or WAVEFORMATEX (18 bytes)
// We validiated chunk as at least sizeof(PCMWAVEFORMAT) above
break;
default:
{
if (fmtChunk->size < sizeof(WAVEFORMATEX))
{
return E_FAIL;
}
auto wfx = reinterpret_cast<const WAVEFORMATEX*>(ptr);
if (fmtChunk->size < (sizeof(WAVEFORMATEX) + wfx->cbSize))
{
return E_FAIL;
}
switch (wfx->wFormatTag)
{
case WAVE_FORMAT_WMAUDIO2:
case WAVE_FORMAT_WMAUDIO3:
dpds = true;
break;
case 0x166 /*WAVE_FORMAT_XMA2*/: // XMA2 is supported by Xbox One
if ((fmtChunk->size < 52 /*sizeof(XMA2WAVEFORMATEX)*/) || (wfx->cbSize < 34 /*( sizeof(XMA2WAVEFORMATEX) - sizeof(WAVEFORMATEX) )*/))
{
return E_FAIL;
}
seek = true;
break;
case WAVE_FORMAT_ADPCM:
if ((fmtChunk->size < (sizeof(WAVEFORMATEX) + 32)) || (wfx->cbSize < 32 /*MSADPCM_FORMAT_EXTRA_BYTES*/))
{
return E_FAIL;
}
break;
case WAVE_FORMAT_EXTENSIBLE:
if ((fmtChunk->size < sizeof(WAVEFORMATEXTENSIBLE)) || (wfx->cbSize < (sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))))
{
return E_FAIL;
}
else
{
static const GUID s_wfexBase = { 0x00000000, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 } };
auto wfex = reinterpret_cast<const WAVEFORMATEXTENSIBLE*>(ptr);
if (memcmp(reinterpret_cast<const BYTE*>(&wfex->SubFormat) + sizeof(DWORD),
reinterpret_cast<const BYTE*>(&s_wfexBase) + sizeof(DWORD), sizeof(GUID) - sizeof(DWORD)) != 0)
{
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
}
switch (wfex->SubFormat.Data1)
{
case WAVE_FORMAT_PCM:
case WAVE_FORMAT_IEEE_FLOAT:
break;
// MS-ADPCM and XMA2 are not supported as WAVEFORMATEXTENSIBLE
case WAVE_FORMAT_WMAUDIO2:
case WAVE_FORMAT_WMAUDIO3:
dpds = true;
break;
default:
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
}
}
break;
default:
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
}
}
}
// Locate 'data'
ptr = reinterpret_cast<const uint8_t*>(riffHeader) + sizeof(RIFFChunkHeader);
if ((ptr + sizeof(RIFFChunk)) > wavEnd)
{
return HRESULT_FROM_WIN32(ERROR_HANDLE_EOF);
}
auto dataChunk = FindChunk(ptr, riffChunk->size, FOURCC_DATA_TAG);
if (!dataChunk || !dataChunk->size)
{
return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
}
ptr = reinterpret_cast<const uint8_t*>(dataChunk) + sizeof(RIFFChunk);
if (ptr + dataChunk->size > wavEnd)
{
return HRESULT_FROM_WIN32(ERROR_HANDLE_EOF);
}
*pwfx = reinterpret_cast<const WAVEFORMATEX*>(wf);
*pdata = ptr;
*dataSize = dataChunk->size;
return S_OK;
}