From 56658f2ce0344e262e804ff3e7275a0bff7498f2 Mon Sep 17 00:00:00 2001 From: Jerome Martinez Date: Sun, 18 May 2025 22:34:58 +0200 Subject: [PATCH 1/3] RF64 support --- Project/GNU/CLI/test/test1.txt | 4 ++ Source/Lib/Uncompressed/WAV/WAV.cpp | 101 ++++++++++++++++++++++------ Source/Lib/Uncompressed/WAV/WAV.h | 5 ++ 3 files changed, 89 insertions(+), 21 deletions(-) diff --git a/Project/GNU/CLI/test/test1.txt b/Project/GNU/CLI/test/test1.txt index 2993471a..6b546918 100644 --- a/Project/GNU/CLI/test/test1.txt +++ b/Project/GNU/CLI/test/test1.txt @@ -267,6 +267,10 @@ Formats/WAV/Features/4ExtraNullBytesInFmtChunk/4ExtraNullBytesInFmtChunk.wav pas Formats/WAV/Features/ChannelMask/48000_24_1_LE_0x00000000.wav pass Formats/WAV/Features/ChannelMask/48000_24_2_LE_0x00000000.wav pass Formats/WAV/Features/ChannelMask/48000_24_6_LE_0x00000000.wav pass +Formats/WAV/Features/RF64/rf64_data_size.wav pass +Formats/WAV/Features/RF64/rf64_extra_after_RIFF.wav pass +Formats/WAV/Features/RF64/rf64_normal.wav pass +Formats/WAV/Features/RF64/rf64_tablelength.wav fail Formats/WAV/Flavors/44100_8_1_U/44100_8_1_U.wav pass Formats/WAV/Flavors/44100_8_2_U/44100_8_2_U.wav pass Formats/WAV/Flavors/44100_8_4_U/44100_8_4_U.wav pass diff --git a/Source/Lib/Uncompressed/WAV/WAV.cpp b/Source/Lib/Uncompressed/WAV/WAV.cpp index 5f0a3564..f7ab082d 100644 --- a/Source/Lib/Uncompressed/WAV/WAV.cpp +++ b/Source/Lib/Uncompressed/WAV/WAV.cpp @@ -22,6 +22,9 @@ static const char* MessageText[] = "file smaller than expected", "RIFF chunk size", "fmt chunk size", + "data chunk not found", + "ds64 size", + "ds64 dataSize not same as data size", "truncated chunk", }; @@ -30,6 +33,9 @@ enum code : uint8_t BufferOverflow, RIFF_ChunkSize, fmt__ChunkSize, + data_Presence, + ds64_size, + ds64_dataSize, TruncatedChunk, Max }; @@ -44,7 +50,7 @@ namespace unsupported static const char* MessageText[] = { // Unsupported - "RF64 (4GB+ WAV)", + "RF64 tableLength", "fmt FormatTag not WAVE_FORMAT_PCM 1 or 3", "fmt AvgBytesPerSec", "fmt BlockAlign", @@ -54,13 +60,15 @@ static const char* MessageText[] = "fmt ChannelMask", "fmt SubFormat not KSDATAFORMAT_SUBTYPE_PCM 00000001-0000-0010-8000-00AA00389B71", "fmt chunk not before data chunk", + "ds64 chunk not before data chunk", "Flavor (SamplesPerSec / BitDepth / Channels / Endianness combination)", "data chunk size is not a multiple of BlockAlign", + "extra data is big", }; enum code : uint8_t { - RF64, + ds64_tableLength, fmt__FormatTag, fmt__AvgBytesPerSec, fmt__BlockAlign, @@ -70,8 +78,10 @@ enum code : uint8_t fmt__ChannelMask, fmt__SubFormat, fmt__Location, + ds64__Location, Flavor, data_Size, + extra_big, Max }; @@ -236,6 +246,7 @@ ELEMENT_END() ELEMENT_BEGIN(WAVE) ELEMENT_VOID(64617461, WAVE_data) +ELEMENT_VOID(64733634, WAVE_ds64) ELEMENT_VOID(666D7420, WAVE_fmt_) ELEMENT_END() @@ -261,14 +272,13 @@ void wav::ParseBuffer() { if (Buffer.Size() < 12) return; - if (Buffer[8] != 'W' || Buffer[9] != 'A' || Buffer[10] != 'V' || Buffer[11] != 'E') - return; - if (Buffer[0] == 'R' && Buffer[1] == 'F' && Buffer[2] == '6' && Buffer[3] == '4') - { - Unsupported(unsupported::RF64); - return; - } - if (Buffer[0] != 'R' || Buffer[1] != 'I' || Buffer[2] != 'F' || Buffer[3] != 'F') + + Buffer_Offset = 0; + auto FirstName = Get_B4(); + Buffer_Offset += 4; + auto FirstRealName = Get_B4(); + IsRF64 = FirstName == 0x52463634; + if ((FirstName != 0x52494646 && !IsRF64) || FirstRealName != 0x57415645) // "RIFF", "RF64", "WAVE" return; SetDetected(); @@ -276,7 +286,7 @@ void wav::ParseBuffer() Buffer_Offset = 0; Levels[0].Offset_End = Buffer.Size(); Levels[0].SubElements = &wav::SubElements__; - Level=1; + Level = 1; while (Buffer_Offset < Buffer.Size()) { @@ -291,32 +301,52 @@ void wav::ParseBuffer() // Parse the chunk header uint64_t Name; uint64_t Size; - if (Buffer_Offset + 8 > End) + if (End - Buffer_Offset < 8) { Undecodable(undecodable::TruncatedChunk); return; } Name = Get_B4(); Size = Get_L4(); - if (Name == 0x52494646) // "RIFF" + if (Level == 1) { - if (Size < 4 || Buffer_Offset + 4 > End) + if (Name == 0x52463634) // "RF64" + Name = 0x52494646; + if (Name == 0x52494646) // "RIFF" { - Undecodable(undecodable::RIFF_ChunkSize); - return; + if (Size < 4 || Buffer_Offset + 4 > End) + { + Undecodable(undecodable::RIFF_ChunkSize); + return; + } + Name <<= 32; + Name |= Get_B4(); + Size -= 4; + ds64_riffOffset = Buffer_Offset - 4; + } + if (DataIsParsed) + { + // Data after the WAVE chunk, we ignore everything + Size = Levels[0].Offset_End - Buffer_Offset; } - Name <<= 32; - Name |= Get_B4(); - Size -= 4; } - if (Buffer_Offset + Size > End) + if (Level == 2) + { + if (IsRF64 && Levels[1].SubElements == &wav::SubElements_WAVE && Name == 0x64617461) // "data" + { + if (Size != 0xFFFFFFFF && Size != ds64_dataSize) + Undecodable(undecodable::ds64_dataSize); + Size = ds64_dataSize; + } + } + if (Size > End - Buffer_Offset) { if (!Actions[Action_AcceptTruncated]) { Undecodable(undecodable::TruncatedChunk); return; } - Size = Levels[Level - 1].Offset_End - Buffer_Offset; + Size = End - Buffer_Offset; } // Parse the chunk content @@ -340,6 +370,9 @@ void wav::ParseBuffer() if (Buffer_Offset < Levels[Level].Offset_End) Level++; } + + if (!DataIsParsed) + Undecodable(undecodable::data_Presence); } //--------------------------------------------------------------------------- @@ -356,6 +389,8 @@ void wav::WAVE() //--------------------------------------------------------------------------- void wav::WAVE_data() { + DataIsParsed = true; + // Test if fmt chunk was parsed if (!HasErrors() && Flavor == (decltype(Flavor))-1) Unsupported(unsupported::fmt__Location); @@ -370,6 +405,8 @@ void wav::WAVE_data() if (InputInfo && !InputInfo->SampleCount) InputInfo->SampleCount = Size / BlockAlign; } + if (!Actions[Action_AcceptTruncated] && Levels[0].Offset_End - Levels[Level].Offset_End > 0x04000000) + Unsupported(unsupported::extra_big); // Can we compress? if (!HasErrors()) @@ -398,6 +435,28 @@ void wav::WAVE_data() } } +//--------------------------------------------------------------------------- +void wav::WAVE_ds64() +{ + // Coherency test + if (Buffer.Size() < 28) + { + Undecodable(undecodable::ds64_size); + return; + } + + auto ds64_riffSize = Get_L8(); + Levels[Level - 1].Offset_End = ds64_riffOffset + ds64_riffSize; + ds64_dataSize = Get_L8(); + Buffer_Offset += 8; + auto tableLength = Get_L4(); + if (tableLength) + { + Unsupported(unsupported::ds64_tableLength); + return; + } +} + //--------------------------------------------------------------------------- void wav::WAVE_fmt_() { diff --git a/Source/Lib/Uncompressed/WAV/WAV.h b/Source/Lib/Uncompressed/WAV/WAV.h index 4fc4b6d5..d42f31ba 100644 --- a/Source/Lib/Uncompressed/WAV/WAV.h +++ b/Source/Lib/Uncompressed/WAV/WAV.h @@ -131,7 +131,11 @@ class wav : public input_base_uncompressed_audio bool IsList; // Temp + uint64_t ds64_riffOffset = 0; + uint64_t ds64_dataSize = 0; uint32_t BlockAlign = 0; + bool IsRF64 = false; + bool DataIsParsed = false; #define WAV_ELEMENT(_NAME) \ void _NAME(); \ @@ -140,6 +144,7 @@ class wav : public input_base_uncompressed_audio WAV_ELEMENT(_); WAV_ELEMENT(WAVE); WAV_ELEMENT(WAVE_data); + WAV_ELEMENT(WAVE_ds64); WAV_ELEMENT(WAVE_fmt_); WAV_ELEMENT(Void); }; From e0aaae8109d57ef642a063f2ced6eb4e89f6b017 Mon Sep 17 00:00:00 2001 From: Jerome Martinez Date: Mon, 19 May 2025 09:15:55 +0200 Subject: [PATCH 2/3] Fix int32_t to uint64_t promotion issues --- Source/Lib/Utils/FileIO/Input_Base.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Lib/Utils/FileIO/Input_Base.cpp b/Source/Lib/Utils/FileIO/Input_Base.cpp index 1bd39e7f..ef82fedd 100644 --- a/Source/Lib/Utils/FileIO/Input_Base.cpp +++ b/Source/Lib/Utils/FileIO/Input_Base.cpp @@ -143,7 +143,7 @@ uint64_t input_base::Get_L8() { TEST_BUFFEROVERFLOW(8); - uint64_t ToReturn = Buffer[Buffer_Offset + 0] | (Buffer[Buffer_Offset + 1] << 8) | (Buffer[Buffer_Offset + 2] << 16) | (Buffer[Buffer_Offset + 3] << 24) | ((uint64_t)Buffer[Buffer_Offset + 4] << 32) | ((uint64_t)Buffer[Buffer_Offset + 5] << 40) | ((uint64_t)Buffer[Buffer_Offset + 6] << 48) | ((uint64_t)Buffer[Buffer_Offset + 7] << 56); + uint64_t ToReturn = ((uint64_t)Buffer[Buffer_Offset + 0]) | (((uint64_t)Buffer[Buffer_Offset + 1]) << 8) | (((uint64_t)Buffer[Buffer_Offset + 2]) << 16) | (((uint64_t)Buffer[Buffer_Offset + 3]) << 24) | (((uint64_t)Buffer[Buffer_Offset + 4]) << 32) | (((uint64_t)Buffer[Buffer_Offset + 5]) << 40) | (((uint64_t)Buffer[Buffer_Offset + 6]) << 48) | (((uint64_t)Buffer[Buffer_Offset + 7]) << 56); Buffer_Offset += 8; return ToReturn; } @@ -153,7 +153,7 @@ uint64_t input_base::Get_B8() { TEST_BUFFEROVERFLOW(8); - uint64_t ToReturn = ((uint64_t)Buffer[Buffer_Offset + 0] << 56) | ((uint64_t)Buffer[Buffer_Offset + 1] << 48) | ((uint64_t)Buffer[Buffer_Offset + 2] << 40) | ((uint64_t)Buffer[Buffer_Offset + 3] << 32) | (Buffer[Buffer_Offset + 4] << 24) | (Buffer[Buffer_Offset + 5] << 16) | (Buffer[Buffer_Offset + 6] << 8) | Buffer[Buffer_Offset + 7]; + uint64_t ToReturn = ((uint64_t)Buffer[Buffer_Offset + 0] << 56) | ((uint64_t)Buffer[Buffer_Offset + 1] << 48) | ((uint64_t)Buffer[Buffer_Offset + 2] << 40) | ((uint64_t)Buffer[Buffer_Offset + 3] << 32) | (((uint64_t)Buffer[Buffer_Offset + 4]) << 24) | (((uint64_t)Buffer[Buffer_Offset + 5]) << 16) | (((uint64_t)Buffer[Buffer_Offset + 6]) << 8) | ((uint64_t)Buffer[Buffer_Offset + 7]); Buffer_Offset += 8; return ToReturn; } From a7943fda5fd5b18a32ce704dbb12904555a15a7f Mon Sep 17 00:00:00 2001 From: Jerome Martinez Date: Mon, 19 May 2025 09:35:02 +0200 Subject: [PATCH 3/3] Fix compiler warning --- Source/CLI/Main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/CLI/Main.cpp b/Source/CLI/Main.cpp index f63b82fd..f24b2468 100644 --- a/Source/CLI/Main.cpp +++ b/Source/CLI/Main.cpp @@ -822,7 +822,7 @@ int main(int argc, const char* argv[]) const string& FileName = IsTemplate ? Output.Streams[i].FileName_Template : Output.Streams[i].FileName; #if defined(_WIN32) || defined(_WINDOWS) auto FileName2 = FileName.substr(PrefixSize); - auto Pos = 0; + size_t Pos = 0; for (;;) { Pos = FileName2.find('\\');