From 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d Mon Sep 17 00:00:00 2001 From: Jef Date: Tue, 24 Sep 2024 14:54:57 +0200 Subject: Initial community commit --- .../openmpt-trunk/include/ancient/LICENSE | 25 + .../openmpt-trunk/include/ancient/OpenMPT.txt | 2 + .../include/ancient/api/ancient/ancient.hpp | 148 ++++ .../include/ancient/src/ACCADecompressor.cpp | 112 +++ .../include/ancient/src/ACCADecompressor.hpp | 31 + .../openmpt-trunk/include/ancient/src/API.cpp | 189 +++++ .../include/ancient/src/ARTMDecompressor.cpp | 122 +++ .../include/ancient/src/ARTMDecompressor.hpp | 31 + .../include/ancient/src/BLZWDecompressor.cpp | 127 ++++ .../include/ancient/src/BLZWDecompressor.hpp | 34 + .../include/ancient/src/BZIP2Decompressor.cpp | 399 ++++++++++ .../include/ancient/src/BZIP2Decompressor.hpp | 44 ++ .../include/ancient/src/BZIP2Table.hpp | 78 ++ .../include/ancient/src/CBR0Decompressor.cpp | 64 ++ .../include/ancient/src/CBR0Decompressor.hpp | 32 + .../include/ancient/src/CRMDecompressor.cpp | 245 ++++++ .../include/ancient/src/CRMDecompressor.hpp | 46 ++ .../include/ancient/src/CYB2Decoder.cpp | 62 ++ .../include/ancient/src/CYB2Decoder.hpp | 33 + .../include/ancient/src/DEFLATEDecompressor.cpp | 386 ++++++++++ .../include/ancient/src/DEFLATEDecompressor.hpp | 57 ++ .../include/ancient/src/DLTADecode.cpp | 62 ++ .../include/ancient/src/DLTADecode.hpp | 35 + .../include/ancient/src/DMSDecompressor.cpp | 718 ++++++++++++++++++ .../include/ancient/src/DMSDecompressor.hpp | 56 ++ .../include/ancient/src/Decompressor.cpp | 108 +++ .../include/ancient/src/Decompressor.hpp | 86 +++ .../include/ancient/src/DynamicHuffmanDecoder.hpp | 226 ++++++ .../include/ancient/src/FASTDecompressor.cpp | 78 ++ .../include/ancient/src/FASTDecompressor.hpp | 31 + .../include/ancient/src/FBR2Decompressor.cpp | 98 +++ .../include/ancient/src/FBR2Decompressor.hpp | 31 + .../include/ancient/src/FRLEDecompressor.cpp | 67 ++ .../include/ancient/src/FRLEDecompressor.hpp | 31 + .../include/ancient/src/HFMNDecompressor.cpp | 91 +++ .../include/ancient/src/HFMNDecompressor.hpp | 34 + .../include/ancient/src/HUFFDecompressor.cpp | 84 +++ .../include/ancient/src/HUFFDecompressor.hpp | 31 + .../include/ancient/src/HuffmanDecoder.hpp | 228 ++++++ .../include/ancient/src/ILZRDecompressor.cpp | 73 ++ .../include/ancient/src/ILZRDecompressor.hpp | 33 + .../include/ancient/src/IMPDecompressor.cpp | 294 ++++++++ .../include/ancient/src/IMPDecompressor.hpp | 44 ++ .../include/ancient/src/InputStream.cpp | 113 +++ .../include/ancient/src/InputStream.hpp | 236 ++++++ .../include/ancient/src/LHLBDecompressor.cpp | 108 +++ .../include/ancient/src/LHLBDecompressor.hpp | 31 + .../include/ancient/src/LIN1Decompressor.cpp | 123 +++ .../include/ancient/src/LIN1Decompressor.hpp | 33 + .../include/ancient/src/LIN2Decompressor.cpp | 224 ++++++ .../include/ancient/src/LIN2Decompressor.hpp | 35 + .../include/ancient/src/LZBSDecompressor.cpp | 75 ++ .../include/ancient/src/LZBSDecompressor.hpp | 31 + .../include/ancient/src/LZCBDecompressor.cpp | 326 ++++++++ .../include/ancient/src/LZCBDecompressor.hpp | 31 + .../include/ancient/src/LZW2Decompressor.cpp | 74 ++ .../include/ancient/src/LZW2Decompressor.hpp | 33 + .../include/ancient/src/LZW4Decompressor.cpp | 72 ++ .../include/ancient/src/LZW4Decompressor.hpp | 31 + .../include/ancient/src/LZW5Decompressor.cpp | 100 +++ .../include/ancient/src/LZW5Decompressor.hpp | 31 + .../include/ancient/src/LZXDecompressor.cpp | 245 ++++++ .../include/ancient/src/LZXDecompressor.hpp | 37 + .../include/ancient/src/Lzh/LH1Decompressor.cpp | 90 +++ .../include/ancient/src/Lzh/LH1Decompressor.hpp | 30 + .../include/ancient/src/Lzh/LH2Decompressor.cpp | 126 ++++ .../include/ancient/src/Lzh/LH2Decompressor.hpp | 30 + .../include/ancient/src/Lzh/LH3Decompressor.cpp | 149 ++++ .../include/ancient/src/Lzh/LH3Decompressor.hpp | 30 + .../include/ancient/src/Lzh/LHXDecompressor.cpp | 191 +++++ .../include/ancient/src/Lzh/LHXDecompressor.hpp | 34 + .../include/ancient/src/Lzh/LZ5Decompressor.cpp | 86 +++ .../include/ancient/src/Lzh/LZ5Decompressor.hpp | 30 + .../include/ancient/src/Lzh/LZHDecompressor.cpp | 167 +++++ .../include/ancient/src/Lzh/LZHDecompressor.hpp | 32 + .../include/ancient/src/Lzh/LZSDecompressor.cpp | 70 ++ .../include/ancient/src/Lzh/LZSDecompressor.hpp | 30 + .../include/ancient/src/Lzh/PMDecompressor.cpp | 424 +++++++++++ .../include/ancient/src/Lzh/PMDecompressor.hpp | 39 + .../include/ancient/src/MASHDecompressor.cpp | 121 +++ .../include/ancient/src/MASHDecompressor.hpp | 31 + .../include/ancient/src/MMCMPDecompressor.cpp | 254 +++++++ .../include/ancient/src/MMCMPDecompressor.hpp | 39 + .../include/ancient/src/NONEDecompressor.cpp | 47 ++ .../include/ancient/src/NONEDecompressor.hpp | 31 + .../include/ancient/src/NUKEDecompressor.cpp | 131 ++++ .../include/ancient/src/NUKEDecompressor.hpp | 33 + .../include/ancient/src/OutputStream.cpp | 124 +++ .../include/ancient/src/OutputStream.hpp | 61 ++ .../include/ancient/src/PPDecompressor.cpp | 192 +++++ .../include/ancient/src/PPDecompressor.hpp | 56 ++ .../include/ancient/src/RAKEDecompressor.cpp | 147 ++++ .../include/ancient/src/RAKEDecompressor.hpp | 34 + .../include/ancient/src/RDCNDecompressor.cpp | 101 +++ .../include/ancient/src/RDCNDecompressor.hpp | 31 + .../include/ancient/src/RLENDecompressor.cpp | 62 ++ .../include/ancient/src/RLENDecompressor.hpp | 31 + .../include/ancient/src/RNCDecompressor.cpp | 457 ++++++++++++ .../include/ancient/src/RNCDecompressor.hpp | 51 ++ .../include/ancient/src/RangeDecoder.cpp | 65 ++ .../include/ancient/src/RangeDecoder.hpp | 40 + .../include/ancient/src/SDHCDecompressor.cpp | 126 ++++ .../include/ancient/src/SDHCDecompressor.hpp | 33 + .../include/ancient/src/SHR3Decompressor.cpp | 326 ++++++++ .../include/ancient/src/SHR3Decompressor.hpp | 48 ++ .../include/ancient/src/SHRIDecompressor.cpp | 338 +++++++++ .../include/ancient/src/SHRIDecompressor.hpp | 50 ++ .../include/ancient/src/SLZ3Decompressor.cpp | 71 ++ .../include/ancient/src/SLZ3Decompressor.hpp | 31 + .../include/ancient/src/SMPLDecompressor.cpp | 78 ++ .../include/ancient/src/SMPLDecompressor.hpp | 31 + .../include/ancient/src/SQSHDecompressor.cpp | 218 ++++++ .../include/ancient/src/SQSHDecompressor.hpp | 33 + .../include/ancient/src/SXSCDecompressor.cpp | 829 +++++++++++++++++++++ .../include/ancient/src/SXSCDecompressor.hpp | 51 ++ .../ancient/src/StoneCrackerDecompressor.cpp | 695 +++++++++++++++++ .../ancient/src/StoneCrackerDecompressor.hpp | 52 ++ .../include/ancient/src/TDCSDecompressor.cpp | 96 +++ .../include/ancient/src/TDCSDecompressor.hpp | 31 + .../include/ancient/src/TPWMDecompressor.cpp | 92 +++ .../include/ancient/src/TPWMDecompressor.hpp | 36 + .../include/ancient/src/XPKDecompressor.cpp | 25 + .../include/ancient/src/XPKDecompressor.hpp | 48 ++ .../openmpt-trunk/include/ancient/src/XPKMain.cpp | 342 +++++++++ .../openmpt-trunk/include/ancient/src/XPKMain.hpp | 54 ++ .../include/ancient/src/ZENODecompressor.cpp | 130 ++++ .../include/ancient/src/ZENODecompressor.hpp | 34 + .../ancient/src/Zip/ImplodeDecompressor.cpp | 130 ++++ .../ancient/src/Zip/ImplodeDecompressor.hpp | 32 + .../include/ancient/src/Zip/ReduceDecompressor.cpp | 115 +++ .../include/ancient/src/Zip/ReduceDecompressor.hpp | 32 + .../include/ancient/src/Zip/ShrinkDecompressor.cpp | 137 ++++ .../include/ancient/src/Zip/ShrinkDecompressor.hpp | 30 + .../include/ancient/src/Zip/ZIPDecompressor.cpp | 117 +++ .../include/ancient/src/Zip/ZIPDecompressor.hpp | 33 + .../include/ancient/src/common/Buffer.cpp | 112 +++ .../include/ancient/src/common/Buffer.hpp | 80 ++ .../include/ancient/src/common/CRC16.cpp | 44 ++ .../include/ancient/src/common/CRC16.hpp | 21 + .../include/ancient/src/common/CRC32.cpp | 115 +++ .../include/ancient/src/common/CRC32.hpp | 27 + .../include/ancient/src/common/Common.cpp | 28 + .../include/ancient/src/common/Common.hpp | 46 ++ .../include/ancient/src/common/MemoryBuffer.cpp | 70 ++ .../include/ancient/src/common/MemoryBuffer.hpp | 34 + .../include/ancient/src/common/OverflowCheck.hpp | 32 + .../include/ancient/src/common/StaticBuffer.cpp | 41 + .../include/ancient/src/common/StaticBuffer.hpp | 72 ++ .../include/ancient/src/common/SubBuffer.cpp | 21 + .../include/ancient/src/common/SubBuffer.hpp | 75 ++ .../ancient/src/common/WrappedVectorBuffer.cpp | 45 ++ .../ancient/src/common/WrappedVectorBuffer.hpp | 35 + 152 files changed, 15914 insertions(+) create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/LICENSE create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/OpenMPT.txt create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/api/ancient/ancient.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/ACCADecompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/ACCADecompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/API.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/ARTMDecompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/ARTMDecompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/BLZWDecompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/BLZWDecompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/BZIP2Decompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/BZIP2Decompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/BZIP2Table.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/CBR0Decompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/CBR0Decompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/CRMDecompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/CRMDecompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/CYB2Decoder.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/CYB2Decoder.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/DEFLATEDecompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/DEFLATEDecompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/DLTADecode.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/DLTADecode.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/DMSDecompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/DMSDecompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/Decompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/Decompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/DynamicHuffmanDecoder.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/FASTDecompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/FASTDecompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/FBR2Decompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/FBR2Decompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/FRLEDecompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/FRLEDecompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/HFMNDecompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/HFMNDecompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/HUFFDecompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/HUFFDecompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/HuffmanDecoder.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/ILZRDecompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/ILZRDecompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/IMPDecompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/IMPDecompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/InputStream.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/InputStream.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/LHLBDecompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/LHLBDecompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/LIN1Decompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/LIN1Decompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/LIN2Decompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/LIN2Decompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/LZBSDecompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/LZBSDecompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/LZCBDecompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/LZCBDecompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/LZW2Decompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/LZW2Decompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/LZW4Decompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/LZW4Decompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/LZW5Decompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/LZW5Decompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/LZXDecompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/LZXDecompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/LH1Decompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/LH1Decompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/LH2Decompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/LH2Decompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/LH3Decompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/LH3Decompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/LHXDecompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/LHXDecompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/LZ5Decompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/LZ5Decompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/LZHDecompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/LZHDecompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/LZSDecompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/LZSDecompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/PMDecompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/PMDecompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/MASHDecompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/MASHDecompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/MMCMPDecompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/MMCMPDecompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/NONEDecompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/NONEDecompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/NUKEDecompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/NUKEDecompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/OutputStream.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/OutputStream.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/PPDecompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/PPDecompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/RAKEDecompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/RAKEDecompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/RDCNDecompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/RDCNDecompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/RLENDecompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/RLENDecompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/RNCDecompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/RNCDecompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/RangeDecoder.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/RangeDecoder.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/SDHCDecompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/SDHCDecompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/SHR3Decompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/SHR3Decompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/SHRIDecompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/SHRIDecompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/SLZ3Decompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/SLZ3Decompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/SMPLDecompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/SMPLDecompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/SQSHDecompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/SQSHDecompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/SXSCDecompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/SXSCDecompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/StoneCrackerDecompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/StoneCrackerDecompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/TDCSDecompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/TDCSDecompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/TPWMDecompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/TPWMDecompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/XPKDecompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/XPKDecompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/XPKMain.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/XPKMain.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/ZENODecompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/ZENODecompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/Zip/ImplodeDecompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/Zip/ImplodeDecompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/Zip/ReduceDecompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/Zip/ReduceDecompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/Zip/ShrinkDecompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/Zip/ShrinkDecompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/Zip/ZIPDecompressor.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/Zip/ZIPDecompressor.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/common/Buffer.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/common/Buffer.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/common/CRC16.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/common/CRC16.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/common/CRC32.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/common/CRC32.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/common/Common.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/common/Common.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/common/MemoryBuffer.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/common/MemoryBuffer.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/common/OverflowCheck.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/common/StaticBuffer.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/common/StaticBuffer.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/common/SubBuffer.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/common/SubBuffer.hpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/common/WrappedVectorBuffer.cpp create mode 100644 Src/external_dependencies/openmpt-trunk/include/ancient/src/common/WrappedVectorBuffer.hpp (limited to 'Src/external_dependencies/openmpt-trunk/include/ancient') diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/LICENSE b/Src/external_dependencies/openmpt-trunk/include/ancient/LICENSE new file mode 100644 index 00000000..d7a1d610 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/LICENSE @@ -0,0 +1,25 @@ +BSD 2-Clause License + +Copyright (c) 2017-2022, Teemu Suutari +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/OpenMPT.txt b/Src/external_dependencies/openmpt-trunk/include/ancient/OpenMPT.txt new file mode 100644 index 00000000..b52f9edf --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/OpenMPT.txt @@ -0,0 +1,2 @@ + * ancient v2.0.0 (2022-01-12) + * Unnecssary files have been removed. diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/api/ancient/ancient.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/api/ancient/ancient.hpp new file mode 100644 index 00000000..cdef5034 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/api/ancient/ancient.hpp @@ -0,0 +1,148 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef ANCIENT_ANCIENT_HPP +#define ANCIENT_ANCIENT_HPP + +#ifndef ANCIENT_API +#if defined(ANCIENT_API_DECLSPEC_DLLEXPORT) +#define ANCIENT_API __declspec(dllexport) +#endif +#if defined(ANCIENT_API_DECLSPEC_DLLIMPORT) +#define ANCIENT_API __declspec(dllimport) +#endif +#if defined(ANCIENT_API_VISIBILITY_DEFAULT_USED) +#define ANCIENT_API __attribute__((visibility("default"))) __attribute__((used)) +#endif +#if defined(ANCIENT_API_VISIBILITY_DEFAULT) +#define ANCIENT_API __attribute__((visibility("default"))) +#endif +#if defined(ANCIENT_API_VISIBILITY_HIDDEN) +#define ANCIENT_API __attribute__((visibility("hidden"))) +#endif +#ifndef ANCIENT_API +#define ANCIENT_API +#endif +#endif + +#include +#include +#include +#include +#include + +#include +#include + +namespace ancient +{ + +namespace internal +{ +namespace APIv2 +{ +class DecompressorImpl; +} +} + +inline namespace APIv2 +{ + +// just a base class to easily catch all the errors +class ANCIENT_API Error : public std::exception +{ +public: + Error() noexcept; + virtual ~Error(); +}; + +class ANCIENT_API InvalidFormatError : public Error +{ +public: + InvalidFormatError() noexcept; + virtual ~InvalidFormatError(); +}; + +class ANCIENT_API DecompressionError : public Error +{ +public: + DecompressionError() noexcept; + virtual ~DecompressionError(); +}; + +class ANCIENT_API VerificationError : public Error +{ +public: + VerificationError() noexcept; + virtual ~VerificationError(); +}; + +class ANCIENT_API Decompressor final +{ + +public: + + // Detect signature whether it matches to any known compressor + // This does not guarantee the data is decompressable though, only signature is read + static bool detect(const std::vector &packedData) noexcept; + static bool detect(const uint8_t *packedData,size_t packedSize) noexcept; + + // Main entrypoint + // if verify=true then check the packedData for errors: CRC or other checksum if available + // check exactSizeKnown from size documentation + // can throw InvalidFormatError if stream is not recognized or it is invalid + // can throw VerificationError if verify enabled and checksum does not match + explicit Decompressor(const std::vector &packedData,bool exactSizeKnown,bool verify); + explicit Decompressor(const uint8_t *packedData,size_t packedSize,bool exactSizeKnown,bool verify); + + // Name returned is human readable long name + const std::string &getName() const noexcept; + + // the functions are there to protect against "accidental" large files when parsing headers + // a.k.a. 16M should be enough for everybody (sizes do not have to accurate i.e. + // compressors can exclude header content for simplification) + // This entirely ok for the context of "old computers" and their files, + // for other usages these need to be tuned up + static size_t getMaxPackedSize() noexcept; + static size_t getMaxRawSize() noexcept; + + // PackedSize or RawSize are taken from the stream if available, std::nullopt otherwise. + // for those compressors having no known sizes, running decompression will update + // the values. + // There are exceptions: Some decompressors need to exact size of the packed data + // in order to decompress. For those providing a indefinitely size packed stream + // will not work + // use the "exactSizeKnown" flag for create to tell whether you know the size or not + std::optional getPackedSize() const noexcept; + std::optional getRawSize() const noexcept; + + // in case of disk image based formats the data does not necessarily start + // from logical beginnig of the image but it is offsetted inside the logical image (f.e. DMS). + // getDataOffset will return the offset which can also be 0, or std::nullopt if not image-based format. + // getImageSize will return the size of the the logical image, or std::nullopt if not image-based format. + std::optional getImageSize() const noexcept; + std::optional getImageOffset() const noexcept; + + // Actual decompression. + // verify checksum if verify==true + // can throw DecompressionError if stream cant be unpacked + // can throw VerificationError if verify enabled and checksum does not match + std::vector decompress(bool verify); + + ~Decompressor(); + +private: + + std::unique_ptr m_impl; + +private: + + Decompressor(const Decompressor&)=delete; + Decompressor& operator=(const Decompressor&)=delete; + +}; + +} + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/ACCADecompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/ACCADecompressor.cpp new file mode 100644 index 00000000..5e815804 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/ACCADecompressor.cpp @@ -0,0 +1,112 @@ +/* Copyright (C) Teemu Suutari */ + +#include "ACCADecompressor.hpp" +#include "InputStream.hpp" +#include "OutputStream.hpp" +#include "common/Common.hpp" + + +namespace ancient::internal +{ + +bool ACCADecompressor::detectHeaderXPK(uint32_t hdr) noexcept +{ + return hdr==FourCC("ACCA"); +} + +std::shared_ptr ACCADecompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) +{ + return std::make_shared(hdr,recursionLevel,packedData,state,verify); +} + +ACCADecompressor::ACCADecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) : + XPKDecompressor(recursionLevel), + _packedData(packedData) +{ + if (!detectHeaderXPK(hdr)) throw Decompressor::InvalidFormatError(); +} + +ACCADecompressor::~ACCADecompressor() +{ + // nothing needed +} + +const std::string &ACCADecompressor::getSubName() const noexcept +{ + static std::string name="XPK-ACCA: Andre's code compression algorithm"; + return name; +} + +void ACCADecompressor::decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) +{ + ForwardInputStream inputStream(_packedData,0,_packedData.size()); + MSBBitReader bitReader(inputStream); + auto readBit=[&]()->uint32_t + { + return bitReader.readBitsBE16(1); + }; + auto readByte=[&]()->uint8_t + { + return inputStream.readByte(); + }; + + ForwardOutputStream outputStream(rawData,0,rawData.size()); + + while (!outputStream.eof()) + { + if (!readBit()) + { + outputStream.writeByte(readByte()); + } else { + static const uint8_t staticBytes[16]={ + 0x00,0x01,0x02,0x03,0x04,0x08,0x10,0x20, + 0x40,0x55,0x60,0x80,0xaa,0xc0,0xe0,0xff}; + + uint8_t tmp=readByte(); + uint32_t count=tmp&0xf; + uint32_t code=tmp>>4; + uint32_t distance=0; + uint8_t repeatChar=0; + bool doRLE=false; + switch (code) + { + case 0: + repeatChar=readByte(); + case 14: + count+=3; + doRLE=true; + break; + + case 1: + count=(count|(uint32_t(readByte())<<4))+19; + repeatChar=readByte(); + doRLE=true; + break; + + case 2: + repeatChar=staticBytes[count]; + count=2; + doRLE=true; + break; + + case 15: + distance=(count|(uint32_t(readByte())<<4))+3; + count=uint32_t(readByte())+14; + break; + + default: /* 3 to 13 */ + distance=(count|(uint32_t(readByte())<<4))+3; + count=code; + break; + } + if (doRLE) + { + for (uint32_t i=0;i &state,bool verify); + + virtual ~ACCADecompressor(); + + virtual const std::string &getSubName() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) override final; + + static bool detectHeaderXPK(uint32_t hdr) noexcept; + static std::shared_ptr create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + +private: + const Buffer &_packedData; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/API.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/API.cpp new file mode 100644 index 00000000..996e0f32 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/API.cpp @@ -0,0 +1,189 @@ +/* Copyright (C) Teemu Suutari */ + +#include "ancient.hpp" +#include "Decompressor.hpp" +#include "common/Buffer.hpp" +#include "common/StaticBuffer.hpp" +#include "common/WrappedVectorBuffer.hpp" + +#include + +namespace ancient +{ + +namespace internal +{ + +namespace APIv2 +{ + +class DecompressorImpl +{ +public: + ConstStaticBuffer _buffer; + std::shared_ptr _decompressor; +public: + DecompressorImpl(const std::vector &packedData,bool exactSizeKnown,bool verify) : + _buffer(packedData.data(), packedData.size()), + _decompressor(Decompressor::create(_buffer, exactSizeKnown, verify)) + { + return; + } + DecompressorImpl(const uint8_t *packedData,size_t packedSize,bool exactSizeKnown,bool verify) : + _buffer(packedData, packedSize), + _decompressor(Decompressor::create(_buffer, exactSizeKnown, verify)) + { + return; + } +}; + +} + +} + +inline namespace APIv2 +{ + +Error::Error() noexcept +{ + // nothing needed +} + +Error::~Error() +{ + // nothing needed +} + +InvalidFormatError::InvalidFormatError() noexcept +{ + // nothing needed +} + +InvalidFormatError::~InvalidFormatError() +{ + // nothing needed +} + +DecompressionError::DecompressionError() noexcept +{ + // nothing needed +} + +DecompressionError::~DecompressionError() +{ + // nothing needed +} + +VerificationError::VerificationError() noexcept +{ + // nothing needed +} + +VerificationError::~VerificationError() +{ + // nothing needed +} + +// --- + +bool Decompressor::detect(const std::vector &packedData) noexcept +{ + return internal::Decompressor::detect(internal::ConstStaticBuffer(packedData.data(), packedData.size())); +} + +bool Decompressor::detect(const uint8_t *packedData, size_t packedSize) noexcept +{ + return internal::Decompressor::detect(internal::ConstStaticBuffer(packedData, packedSize)); +} + +Decompressor::Decompressor(const std::vector &packedData,bool exactSizeKnown,bool verify) : + m_impl(std::make_unique(packedData, exactSizeKnown, verify)) +{ + return; +} + +Decompressor::Decompressor(const uint8_t *packedData,size_t packedSize,bool exactSizeKnown,bool verify) : + m_impl(std::make_unique(packedData, packedSize, exactSizeKnown, verify)) +{ + return; +} + +const std::string &Decompressor::getName() const noexcept +{ + return m_impl->_decompressor->getName(); +} + +size_t Decompressor::getMaxPackedSize() noexcept +{ + return internal::Decompressor::getMaxPackedSize(); +} + +size_t Decompressor::getMaxRawSize() noexcept +{ + return internal::Decompressor::getMaxRawSize(); +} + +std::optional Decompressor::getPackedSize() const noexcept +{ + size_t packedSize=m_impl->_decompressor->getPackedSize(); + if (packedSize==0) + { + return std::nullopt; + } + return packedSize; +} + +std::optional Decompressor::getRawSize() const noexcept +{ + size_t rawSize=m_impl->_decompressor->getRawSize(); + if (rawSize==0) + { + return std::nullopt; + } + return rawSize; +} + +std::optional Decompressor::getImageSize() const noexcept +{ + size_t imageSize=m_impl->_decompressor->getImageSize(); + size_t imageOffset=m_impl->_decompressor->getImageOffset(); + bool isImage=((imageSize>0)||(imageOffset>0)); + if (!isImage) + { + return std::nullopt; + } + return imageSize; +} + +std::optional Decompressor::getImageOffset() const noexcept +{ + size_t imageSize=m_impl->_decompressor->getImageSize(); + size_t imageOffset=m_impl->_decompressor->getImageOffset(); + bool isImage=((imageSize>0)||(imageOffset>0)); + if (!isImage) + { + return std::nullopt; + } + return imageOffset; +} + +std::vector Decompressor::decompress(bool verify) +{ + std::vector result((m_impl->_decompressor->getRawSize())?m_impl->_decompressor->getRawSize():m_impl->_decompressor->getMaxRawSize()); + { + internal::WrappedVectorBuffer buffer(result); + m_impl->_decompressor->decompress(buffer, verify); + } + result.resize(m_impl->_decompressor->getRawSize()); + result.shrink_to_fit(); + return result; +} + +Decompressor::~Decompressor() +{ + // nothing needed +} + +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/ARTMDecompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/ARTMDecompressor.cpp new file mode 100644 index 00000000..6a84e7cc --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/ARTMDecompressor.cpp @@ -0,0 +1,122 @@ +/* Copyright (C) Teemu Suutari */ + +#include "ARTMDecompressor.hpp" +#include "RangeDecoder.hpp" +#include "InputStream.hpp" +#include "OutputStream.hpp" +#include "common/Common.hpp" + + +namespace ancient::internal +{ + +bool ARTMDecompressor::detectHeaderXPK(uint32_t hdr) noexcept +{ + return hdr==FourCC("ARTM"); +} + +std::shared_ptr ARTMDecompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) +{ + return std::make_shared(hdr,recursionLevel,packedData,state,verify); +} + +ARTMDecompressor::ARTMDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) : + XPKDecompressor(recursionLevel), + _packedData(packedData) +{ + if (!detectHeaderXPK(hdr)) throw Decompressor::InvalidFormatError(); + if (packedData.size()<2) throw Decompressor::InvalidFormatError(); +} + +ARTMDecompressor::~ARTMDecompressor() +{ + // nothing needed +} + +const std::string &ARTMDecompressor::getSubName() const noexcept +{ + static std::string name="XPK-ARTM: Arithmetic encoding compressor"; + return name; +} + +// There really is not much to see here. +// Except maybe for the fact that there is extra symbol defined but never used. +// It is used in the original implementation as a terminator. In here it is considered as an error. +// Logically it would decode into null-character (practically it would be instant buffer overflow) +void ARTMDecompressor::decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) +{ + class BitReader : public RangeDecoder::BitReader + { + public: + BitReader(ForwardInputStream &stream) : + _reader(stream) + { + // nothing needed + } + + virtual ~BitReader() + { + // nothing needed + } + + virtual uint32_t readBit() override final + { + return _reader.readBits8(1); + } + + private: + LSBBitReader _reader; + }; + + + ForwardInputStream inputStream(_packedData,0,_packedData.size(),true); + ForwardOutputStream outputStream(rawData,0,rawData.size()); + BitReader bitReader(inputStream); + + uint16_t initialValue=0; + for (uint32_t i=0;i<16;i++) initialValue=(initialValue<<1)|bitReader.readBit(); + RangeDecoder decoder(bitReader,initialValue); + + uint8_t characters[256]; + uint16_t frequencies[256]; + uint16_t frequencySums[256]; + + for (uint32_t i=0;i<256;i++) + { + characters[i]=i; + frequencies[i]=1; + frequencySums[i]=256-i; + } + uint16_t frequencyTotal=257; + + while (!outputStream.eof()) + { + uint16_t value=decoder.decode(frequencyTotal); + uint16_t symbol; + for (symbol=0;symbol<256;symbol++) + if (frequencySums[symbol]<=value) break; + if (symbol==256) throw Decompressor::DecompressionError(); + decoder.scale(frequencySums[symbol],frequencySums[symbol]+frequencies[symbol],frequencyTotal); + outputStream.writeByte(characters[symbol]); + + if (frequencyTotal==0x3fffU) + { + frequencyTotal=1; + for (int32_t i=255;i>=0;i--) + { + frequencySums[i]=frequencyTotal; + frequencyTotal+=frequencies[i]=(frequencies[i]+1)>>1; + } + } + + uint16_t i; + for (i=symbol;i&&frequencies[i-1]==frequencies[i];i--); + if (i!=symbol) + std::swap(characters[symbol],characters[i]); + frequencies[i]++; + while (i--) frequencySums[i]++; + frequencyTotal++; + } +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/ARTMDecompressor.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/ARTMDecompressor.hpp new file mode 100644 index 00000000..7a9c6b5a --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/ARTMDecompressor.hpp @@ -0,0 +1,31 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef ARTMDECOMPRESSOR_HPP +#define ARTMDECOMPRESSOR_HPP + +#include "XPKDecompressor.hpp" + +namespace ancient::internal +{ + +class ARTMDecompressor : public XPKDecompressor +{ +public: + ARTMDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + + virtual ~ARTMDecompressor(); + + virtual const std::string &getSubName() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) override final; + + static bool detectHeaderXPK(uint32_t hdr) noexcept; + static std::shared_ptr create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + +private: + const Buffer &_packedData; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/BLZWDecompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/BLZWDecompressor.cpp new file mode 100644 index 00000000..7cc35e9f --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/BLZWDecompressor.cpp @@ -0,0 +1,127 @@ +/* Copyright (C) Teemu Suutari */ + +#include "BLZWDecompressor.hpp" +#include "InputStream.hpp" +#include "OutputStream.hpp" +#include "common/Common.hpp" + + +namespace ancient::internal +{ + +bool BLZWDecompressor::detectHeaderXPK(uint32_t hdr) +{ + return hdr==FourCC("BLZW"); +} + +std::shared_ptr BLZWDecompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) +{ + return std::make_shared(hdr,recursionLevel,packedData,state,verify); +} + +BLZWDecompressor::BLZWDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) : + XPKDecompressor(recursionLevel), + _packedData(packedData) +{ + if (!detectHeaderXPK(hdr)) throw Decompressor::InvalidFormatError(); + _maxBits=_packedData.readBE16(0); + if (_maxBits<9 || _maxBits>20) throw Decompressor::InvalidFormatError();; + _stackLength=uint32_t(_packedData.readBE16(2))+5; +} + +BLZWDecompressor::~BLZWDecompressor() +{ + // nothing needed +} + +const std::string &BLZWDecompressor::getSubName() const noexcept +{ + static std::string name="XPK-BLZW: LZW-compressor"; + return name; +} + +void BLZWDecompressor::decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) +{ + ForwardInputStream inputStream(_packedData,4,_packedData.size()); + MSBBitReader bitReader(inputStream); + auto readBits=[&](uint32_t count)->uint32_t + { + return bitReader.readBits8(count); + }; + + ForwardOutputStream outputStream(rawData,0,rawData.size()); + + uint32_t maxCode=1<<_maxBits; + auto prefix=std::make_unique(maxCode-259); + auto suffix=std::make_unique(maxCode-259); + auto stack=std::make_unique(_stackLength); + + uint32_t freeIndex,codeBits,prevCode,newCode; + + auto suffixLookup=[&](uint32_t code)->uint32_t + { + if (code>=freeIndex) throw Decompressor::DecompressionError(); + return (code<259)?code:suffix[code-259]; + }; + + auto insert=[&](uint32_t code) + { + uint32_t stackPos=0; + newCode=suffixLookup(code); + while (code>=259) + { + if (stackPos+1>=_stackLength) throw Decompressor::DecompressionError(); + stack[stackPos++]=newCode; + code=prefix[code-259]; + newCode=suffixLookup(code); + } + stack[stackPos++]=newCode; + while (stackPos) outputStream.writeByte(stack[--stackPos]); + }; + + auto init=[&]() + { + codeBits=9; + freeIndex=259; + prevCode=readBits(codeBits); + insert(prevCode); + }; + + init(); + while (!outputStream.eof()) + { + uint32_t code=readBits(codeBits); + switch (code) + { + case 256: + throw Decompressor::DecompressionError(); + break; + + case 257: + init(); + break; + + case 258: + codeBits++; + break; + + default: + if (code>=freeIndex) + { + uint32_t tmp=newCode; + insert(prevCode); + outputStream.writeByte(tmp); + } else insert(code); + if (freeIndex &state,bool verify); + + virtual ~BLZWDecompressor(); + + virtual const std::string &getSubName() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) override final; + + static bool detectHeaderXPK(uint32_t hdr); + static std::shared_ptr create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + +private: + const Buffer &_packedData; + + uint32_t _maxBits=0; + size_t _stackLength=0; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/BZIP2Decompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/BZIP2Decompressor.cpp new file mode 100644 index 00000000..65a24aef --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/BZIP2Decompressor.cpp @@ -0,0 +1,399 @@ +/* Copyright (C) Teemu Suutari */ + +#include +#include + +#include "BZIP2Decompressor.hpp" +#include "HuffmanDecoder.hpp" +#include "InputStream.hpp" +#include "OutputStream.hpp" +#include "common/MemoryBuffer.hpp" +#include "common/CRC32.hpp" +#include "common/Common.hpp" + + +namespace ancient::internal +{ + +bool BZIP2Decompressor::detectHeader(uint32_t hdr) noexcept +{ + return ((hdr&0xffff'ff00U)==FourCC("BZh\0") && (hdr&0xffU)>='1' && (hdr&0xffU)<='9'); +} + +bool BZIP2Decompressor::detectHeaderXPK(uint32_t hdr) noexcept +{ + return (hdr==FourCC("BZP2")); +} + +std::shared_ptr BZIP2Decompressor::create(const Buffer &packedData,bool exactSizeKnown,bool verify) +{ + return std::make_shared(packedData,exactSizeKnown,verify); +} + +std::shared_ptr BZIP2Decompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) +{ + return std::make_shared(hdr,recursionLevel,packedData,state,verify); +} + +BZIP2Decompressor::BZIP2Decompressor(const Buffer &packedData,bool exactSizeKnown,bool verify) : + _packedData(packedData), + _packedSize(0) +{ + uint32_t hdr=packedData.readBE32(0); + if (!detectHeader(hdr)) throw Decompressor::InvalidFormatError();; + _blockSize=((hdr&0xffU)-'0')*100'000; +} + +BZIP2Decompressor::BZIP2Decompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) : + XPKDecompressor(recursionLevel), + _packedData(packedData), + _packedSize(_packedData.size()) +{ + uint32_t blockHdr=packedData.readBE32(0); + if (!detectHeader(blockHdr)) throw Decompressor::InvalidFormatError();; + _blockSize=((blockHdr&0xffU)-'0')*100'000; +} + +BZIP2Decompressor::~BZIP2Decompressor() +{ + // nothing needed +} + +const std::string &BZIP2Decompressor::getName() const noexcept +{ + static std::string name="bz2: bzip2"; + return name; +} + +const std::string &BZIP2Decompressor::getSubName() const noexcept +{ + static std::string name="XPK-BZP2: bzip2"; + return name; +} + +size_t BZIP2Decompressor::getPackedSize() const noexcept +{ + // no way to know before decompressing + return _packedSize; +} + + +size_t BZIP2Decompressor::getRawSize() const noexcept +{ + // same thing, decompression needed first + return _rawSize; +} + +void BZIP2Decompressor::decompressImpl(Buffer &rawData,bool verify) +{ + size_t packedSize=_packedSize?_packedSize:_packedData.size(); + size_t rawSize=_rawSize?_rawSize:rawData.size(); + + ForwardInputStream inputStream(_packedData,4,packedSize); + MSBBitReader bitReader(inputStream); + auto readBits=[&](uint32_t count)->uint32_t + { + return bitReader.readBits8(count); + }; + auto readBit=[&]()->uint32_t + { + return bitReader.readBits8(1); + }; + + ForwardOutputStream outputStream(rawData,0,rawSize); + + // stream verification + // + // there is so much wrong in bzip2 CRC-calculation :( + // 1. The bit ordering is opposite what everyone else does with CRC32 + // 2. The block CRCs are calculated separately, no way of calculating a complete + // CRC without knowing the block layout + // 3. The CRC is the end of the stream and the stream is bit aligned. You + // can't read CRC without decompressing the stream. + uint32_t crc=0; + auto calculateBlockCRC=[&](size_t blockPos,size_t blockSize) + { + crc=(crc<<1)|(crc>>31); + crc^=CRC32Rev(rawData,blockPos,blockSize,0); + }; + + HuffmanDecoder selectorDecoder + { + // incomplete Huffman table. errors possible + HuffmanCode{1,0b000000,0}, + HuffmanCode{2,0b000010,1}, + HuffmanCode{3,0b000110,2}, + HuffmanCode{4,0b001110,3}, + HuffmanCode{5,0b011110,4}, + HuffmanCode{6,0b111110,5} + }; + + HuffmanDecoder deltaDecoder + { + HuffmanCode{1,0b00,0}, + HuffmanCode{2,0b10,1}, + HuffmanCode{2,0b11,-1} + }; + + MemoryBuffer tmpBuffer(_blockSize); + uint8_t *tmpBufferPtr=tmpBuffer.data(); + + // This is the dark, ancient secret of bzip2. + // versions before 0.9.5 had a data randomization for "too regular" + // data problematic for the bwt-implementation at that time. + // although it is never utilized anymore, the support is still there + // And this is exactly the kind of ancient stuff we want to support :) + // + // On this specific part (since it is a table of magic numbers) + // we have no way other than copying it from the original reference + +// Table has a separate copyright, lets have it as a separate file as well +#include "BZIP2Table.hpp" + + for (;;) + { + uint32_t blockHdrHigh=readBits(32); + uint32_t blockHdrLow=readBits(16); + if (blockHdrHigh==0x31415926U && blockHdrLow==0x5359U) + { + // a block + + // this is rather spaghetti... + readBits(32); // block crc, not interested + bool randomized=readBit(); + + // basically the random inserted is one LSB after n-th bytes + // per defined in the table. + uint32_t randomPos=1; + uint32_t randomCounter=randomTable[0]-1; + auto randomBit=[&]()->bool + { + // Beauty is in the eye of the beholder: this is smallest form to hide the ugliness + return (!randomCounter--)?randomCounter=randomTable[randomPos++&511]:false; + }; + + uint32_t currentPtr=readBits(24); + + uint32_t currentBlockSize=0; + { + uint32_t numHuffmanItems=2; + uint32_t huffmanValues[256]; + + { + // this is just a little bit inefficient but still we reading bit by bit since + // reference does it. (bitsream format details do not spill over) + std::vector usedMap(16); + for (uint32_t i=0;i<16;i++) usedMap[i]=readBit(); + + std::vector huffmanMap(256); + for (uint32_t i=0;i<16;i++) + { + for (uint32_t j=0;j<16;j++) + huffmanMap[i*16+j]=(usedMap[i])?readBit():false; + } + + for (uint32_t i=0;i<256;i++) if (huffmanMap[i]) numHuffmanItems++; + if (numHuffmanItems==2) throw DecompressionError(); + + for (uint32_t currentValue=0,i=0;i<256;i++) + if (huffmanMap[i]) huffmanValues[currentValue++]=i; + } + + uint32_t huffmanGroups=readBits(3); + if (huffmanGroups<2 || huffmanGroups>6) throw DecompressionError(); + + uint32_t selectorsUsed=readBits(15); + if (!selectorsUsed) throw DecompressionError(); + + MemoryBuffer huffmanSelectorList(selectorsUsed); + + auto unMTF=[](uint8_t value,uint8_t map[])->uint8_t + { + uint8_t ret=map[value]; + if (value) + { + uint8_t tmp=map[value]; + for (uint32_t i=value;i;i--) + map[i]=map[i-1]; + map[0]=tmp; + } + return ret; + }; + + // create Huffman selectors + uint8_t selectorMTFMap[6]={0,1,2,3,4,5}; + + for (uint32_t i=0;i=huffmanGroups) throw DecompressionError(); + huffmanSelectorList[i]=item; + } + + typedef HuffmanDecoder BZIP2Decoder; + std::vector dataDecoders(huffmanGroups); + + // Create all tables + for (uint32_t i=0;i20) throw DecompressionError(); + bitLengths[j]=currentBits; + } + + dataDecoders[i].createOrderlyHuffmanTable(bitLengths,numHuffmanItems); + } + + // Huffman decode + unRLE + unMTF + BZIP2Decoder *currentHuffmanDecoder=nullptr; + uint32_t currentHuffmanIndex=0; + uint8_t dataMTFMap[256]; + for (uint32_t i=0;i_blockSize) throw DecompressionError(); + for (uint32_t i=0;i=selectorsUsed) throw DecompressionError(); + currentHuffmanDecoder=&dataDecoders[huffmanSelectorList[currentHuffmanIndex++]]; + } + uint32_t symbolMTF=currentHuffmanDecoder->decode(readBit); + // stop marker is referenced only once, and it is the last one + // This means we do no have to un-MTF it for detection + if (symbolMTF==numHuffmanItems-1) break; + if (currentBlockSize>=_blockSize) throw DecompressionError(); + if (symbolMTF<2) + { + currentRunLength+=currentRLEWeight<=_blockSize) throw DecompressionError(); + tmpBufferPtr[currentBlockSize++]=huffmanValues[symbol]; + } + } + decodeRLE(); + if (currentPtr>=currentBlockSize) throw DecompressionError(); + } + + // inverse BWT + final RLE decoding. + // there are a few dark corners here as well + // 1. Can the stream end at 4 literals without count? I assume it is a valid optimization (and that this does not spillover to next block) + // 2. Can the RLE-step include counts 252 to 255 even if reference does not do them? I assume yes here as here as well + // 3. Can the stream be empty? We do not take issue here about that (that should be culled out earlier already) + uint32_t sums[256]; + for (uint32_t i=0;i<256;i++) sums[i]=0; + + for (uint32_t i=0;i(); + for (uint32_t i=0;i &state,bool verify); + virtual ~BZIP2Decompressor(); + + virtual size_t getRawSize() const noexcept override final; + virtual size_t getPackedSize() const noexcept override final; + + virtual const std::string &getName() const noexcept override final; + virtual const std::string &getSubName() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,bool verify) override final; + virtual void decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) override final; + + static bool detectHeader(uint32_t hdr) noexcept; + static bool detectHeaderXPK(uint32_t hdr) noexcept; + + static std::shared_ptr create(const Buffer &packedData,bool exactSizeKnown,bool verify); + static std::shared_ptr create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + +private: + const Buffer &_packedData; + + size_t _blockSize=0; + size_t _packedSize=0; + size_t _rawSize=0; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/BZIP2Table.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/BZIP2Table.hpp new file mode 100644 index 00000000..59a65092 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/BZIP2Table.hpp @@ -0,0 +1,78 @@ +/* +-------------------------------------------------------------------------- + +This program, "bzip2", the associated library "libbzip2", and all +documentation, are copyright (C) 1996-2010 Julian R Seward. All +rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + +3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + +4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS +OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Julian Seward, jseward@bzip.org +bzip2/libbzip2 version 1.0.6 of 6 September 2010 + +-------------------------------------------------------------------------- +*/ + +// content formatted, numbers -1 (i.e. this is altered version by clause 3) + static const uint16_t randomTable[512]={ + 619-1,720-1,127-1,481-1,931-1,816-1,813-1,233-1,566-1,247-1,985-1,724-1,205-1,454-1,863-1,491-1, + 741-1,242-1,949-1,214-1,733-1,859-1,335-1,708-1,621-1,574-1, 73-1,654-1,730-1,472-1,419-1,436-1, + 278-1,496-1,867-1,210-1,399-1,680-1,480-1, 51-1,878-1,465-1,811-1,169-1,869-1,675-1,611-1,697-1, + 867-1,561-1,862-1,687-1,507-1,283-1,482-1,129-1,807-1,591-1,733-1,623-1,150-1,238-1, 59-1,379-1, + 684-1,877-1,625-1,169-1,643-1,105-1,170-1,607-1,520-1,932-1,727-1,476-1,693-1,425-1,174-1,647-1, + 73-1,122-1,335-1,530-1,442-1,853-1,695-1,249-1,445-1,515-1,909-1,545-1,703-1,919-1,874-1,474-1, + 882-1,500-1,594-1,612-1,641-1,801-1,220-1,162-1,819-1,984-1,589-1,513-1,495-1,799-1,161-1,604-1, + 958-1,533-1,221-1,400-1,386-1,867-1,600-1,782-1,382-1,596-1,414-1,171-1,516-1,375-1,682-1,485-1, + 911-1,276-1, 98-1,553-1,163-1,354-1,666-1,933-1,424-1,341-1,533-1,870-1,227-1,730-1,475-1,186-1, + 263-1,647-1,537-1,686-1,600-1,224-1,469-1, 68-1,770-1,919-1,190-1,373-1,294-1,822-1,808-1,206-1, + 184-1,943-1,795-1,384-1,383-1,461-1,404-1,758-1,839-1,887-1,715-1, 67-1,618-1,276-1,204-1,918-1, + 873-1,777-1,604-1,560-1,951-1,160-1,578-1,722-1, 79-1,804-1, 96-1,409-1,713-1,940-1,652-1,934-1, + 970-1,447-1,318-1,353-1,859-1,672-1,112-1,785-1,645-1,863-1,803-1,350-1,139-1, 93-1,354-1, 99-1, + 820-1,908-1,609-1,772-1,154-1,274-1,580-1,184-1, 79-1,626-1,630-1,742-1,653-1,282-1,762-1,623-1, + 680-1, 81-1,927-1,626-1,789-1,125-1,411-1,521-1,938-1,300-1,821-1, 78-1,343-1,175-1,128-1,250-1, + 170-1,774-1,972-1,275-1,999-1,639-1,495-1, 78-1,352-1,126-1,857-1,956-1,358-1,619-1,580-1,124-1, + 737-1,594-1,701-1,612-1,669-1,112-1,134-1,694-1,363-1,992-1,809-1,743-1,168-1,974-1,944-1,375-1, + 748-1, 52-1,600-1,747-1,642-1,182-1,862-1, 81-1,344-1,805-1,988-1,739-1,511-1,655-1,814-1,334-1, + 249-1,515-1,897-1,955-1,664-1,981-1,649-1,113-1,974-1,459-1,893-1,228-1,433-1,837-1,553-1,268-1, + 926-1,240-1,102-1,654-1,459-1, 51-1,686-1,754-1,806-1,760-1,493-1,403-1,415-1,394-1,687-1,700-1, + 946-1,670-1,656-1,610-1,738-1,392-1,760-1,799-1,887-1,653-1,978-1,321-1,576-1,617-1,626-1,502-1, + 894-1,679-1,243-1,440-1,680-1,879-1,194-1,572-1,640-1,724-1,926-1, 56-1,204-1,700-1,707-1,151-1, + 457-1,449-1,797-1,195-1,791-1,558-1,945-1,679-1,297-1, 59-1, 87-1,824-1,713-1,663-1,412-1,693-1, + 342-1,606-1,134-1,108-1,571-1,364-1,631-1,212-1,174-1,643-1,304-1,329-1,343-1, 97-1,430-1,751-1, + 497-1,314-1,983-1,374-1,822-1,928-1,140-1,206-1, 73-1,263-1,980-1,736-1,876-1,478-1,430-1,305-1, + 170-1,514-1,364-1,692-1,829-1, 82-1,855-1,953-1,676-1,246-1,369-1,970-1,294-1,750-1,807-1,827-1, + 150-1,790-1,288-1,923-1,804-1,378-1,215-1,828-1,592-1,281-1,565-1,555-1,710-1, 82-1,896-1,831-1, + 547-1,261-1,524-1,462-1,293-1,465-1,502-1, 56-1,661-1,821-1,976-1,991-1,658-1,869-1,905-1,758-1, + 745-1,193-1,768-1,550-1,608-1,933-1,378-1,286-1,215-1,979-1,792-1,961-1, 61-1,688-1,793-1,644-1, + 986-1,403-1,106-1,366-1,905-1,644-1,372-1,567-1,466-1,434-1,645-1,210-1,389-1,550-1,919-1,135-1, + 780-1,773-1,635-1,389-1,707-1,100-1,626-1,958-1,165-1,504-1,920-1,176-1,193-1,713-1,857-1,265-1, + 203-1, 50-1,668-1,108-1,645-1,990-1,626-1,197-1,510-1,357-1,358-1,850-1,858-1,364-1,936-1,638-1}; diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/CBR0Decompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/CBR0Decompressor.cpp new file mode 100644 index 00000000..3d4a65c7 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/CBR0Decompressor.cpp @@ -0,0 +1,64 @@ +/* Copyright (C) Teemu Suutari */ + +#include "CBR0Decompressor.hpp" +#include "InputStream.hpp" +#include "OutputStream.hpp" +#include "common/Common.hpp" + + +namespace ancient::internal +{ + +bool CBR0Decompressor::detectHeaderXPK(uint32_t hdr) noexcept +{ + // CBR1 is practical joke: it is the same as CBR0 but with ID changed + return hdr==FourCC("CBR0") || hdr==FourCC("CBR1"); +} + +std::shared_ptr CBR0Decompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) +{ + return std::make_shared(hdr,recursionLevel,packedData,state,verify); +} + +CBR0Decompressor::CBR0Decompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) : + XPKDecompressor(recursionLevel), + _packedData(packedData), + _isCBR0(hdr==FourCC("CBR0")) +{ + if (!detectHeaderXPK(hdr)) throw Decompressor::InvalidFormatError(); +} + +CBR0Decompressor::~CBR0Decompressor() +{ + // nothing needed +} + +const std::string &CBR0Decompressor::getSubName() const noexcept +{ + static std::string nameCBR0="XPK-CBR0: RLE-compressor"; + static std::string nameCBR1="XPK-CBR1: RLE-compressor"; + return (_isCBR0)?nameCBR0:nameCBR1; +} + +void CBR0Decompressor::decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) +{ + ForwardInputStream inputStream(_packedData,0,_packedData.size()); + ForwardOutputStream outputStream(rawData,0,rawData.size()); + + // barely different than RLEN, however the count is well defined here. + while (!outputStream.eof()) + { + uint32_t count=inputStream.readByte(); + if (count<128) + { + count++; + for (uint32_t i=0;i &state,bool verify); + + virtual ~CBR0Decompressor(); + + virtual const std::string &getSubName() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) override final; + + static bool detectHeaderXPK(uint32_t hdr) noexcept; + static std::shared_ptr create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + +private: + const Buffer &_packedData; + bool _isCBR0; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/CRMDecompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/CRMDecompressor.cpp new file mode 100644 index 00000000..a866d452 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/CRMDecompressor.cpp @@ -0,0 +1,245 @@ +/* Copyright (C) Teemu Suutari */ + +#include "CRMDecompressor.hpp" +#include "HuffmanDecoder.hpp" +#include "DLTADecode.hpp" +#include "InputStream.hpp" +#include "OutputStream.hpp" +#include "common/OverflowCheck.hpp" +#include "common/Common.hpp" + + +namespace ancient::internal +{ + +bool CRMDecompressor::detectHeader(uint32_t hdr) noexcept +{ + switch (hdr) + { + case FourCC("CrM!"): + case FourCC("CrM2"): + case FourCC("Crm!"): + case FourCC("Crm2"): + return true; + + default: + return false; + } +} + +bool CRMDecompressor::detectHeaderXPK(uint32_t hdr) noexcept +{ + return hdr==FourCC("CRM2") || hdr==FourCC("CRMS"); +} + +std::shared_ptr CRMDecompressor::create(const Buffer &packedData,bool exactSizeKnown,bool verify) +{ + return std::make_shared(packedData,0,verify); +} + +std::shared_ptr CRMDecompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) +{ + return std::make_shared(hdr,recursionLevel,packedData,state,verify); +} + +CRMDecompressor::CRMDecompressor(const Buffer &packedData,uint32_t recursionLevel,bool verify) : + XPKDecompressor(recursionLevel), + _packedData(packedData) +{ + uint32_t hdr=packedData.readBE32(0); + if (!detectHeader(hdr) || packedData.size()<20) + throw Decompressor::InvalidFormatError(); + + _rawSize=packedData.readBE32(6); + _packedSize=packedData.readBE32(10); + if (!_rawSize || !_packedSize || + _rawSize>getMaxRawSize() || _packedSize>getMaxPackedSize() || + OverflowCheck::sum(_packedSize,14U)>packedData.size()) throw Decompressor::InvalidFormatError(); + if (((hdr>>8)&0xff)=='m') _isSampled=true; + if ((hdr&0xff)=='2') _isLZH=true; +} + +CRMDecompressor::CRMDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) : + CRMDecompressor(packedData,recursionLevel,verify) +{ + _isXPKDelta=(hdr==FourCC("CRMS")); +} + +CRMDecompressor::~CRMDecompressor() +{ + // nothing needed +} + +const std::string &CRMDecompressor::getName() const noexcept +{ + static std::string names[4]={ + "CrM!: Crunch-Mania standard-mode", + "Crm!: Crunch-Mania standard-mode, sampled", + "CrM2: Crunch-Mania LZH-mode", + "Crm2: Crunch-Mania LZH-mode, sampled"}; + return names[(_isLZH?2:0)+(_isSampled?1:0)]; +} + +const std::string &CRMDecompressor::getSubName() const noexcept +{ + // the XPK-id is not used in decompressing process, + // but there is a real id inside the stream + // This means we can have frankenstein configurations, + // although in practice we don't + static std::string names[2]={ + "XPK-CRM2: Crunch-Mania LZH-mode", + "XPK-CRMS: Crunch-Mania LZH-mode, sampled"}; + return names[(_isXPKDelta?1:0)]; +} + +size_t CRMDecompressor::getPackedSize() const noexcept +{ + return _packedSize+14; +} + +size_t CRMDecompressor::getRawSize() const noexcept +{ + return _rawSize; +} + +void CRMDecompressor::decompressImpl(Buffer &rawData,bool verify) +{ + if (rawData.size()<_rawSize) throw Decompressor::DecompressionError(); + + BackwardInputStream inputStream(_packedData,14,_packedSize+14-6); + LSBBitReader bitReader(inputStream); + { + // There are empty bits?!? at the start of the stream. take them out + size_t bufOffset=_packedSize+14-6; + uint32_t originalBitsContent=_packedData.readBE32(bufOffset); + uint16_t originalShift=_packedData.readBE16(bufOffset+4); + uint8_t bufBitsLength=originalShift+16; + uint32_t bufBitsContent=originalBitsContent>>(16-originalShift); + bitReader.reset(bufBitsContent,bufBitsLength); + } + auto readBits=[&](uint32_t count)->uint32_t + { + return bitReader.readBits8(count); + }; + auto readBit=[&]()->uint32_t + { + return bitReader.readBits8(1); + }; + + BackwardOutputStream outputStream(rawData,0,_rawSize); + + if (_isLZH) + { + typedef HuffmanDecoder CRMHuffmanDecoder; + + auto readHuffmanTable=[&](CRMHuffmanDecoder &dec,uint32_t codeLength) + { + uint32_t maxDepth=readBits(4); + if (!maxDepth) throw Decompressor::DecompressionError(); + uint32_t lengthTable[15]; + for (uint32_t i=0;i{depth,code>>(maxDepth-depth),value}); + code+=1<<(maxDepth-depth); + } + } + }; + + + do { + CRMHuffmanDecoder lengthDecoder,distanceDecoder; + readHuffmanTable(lengthDecoder,9); + readHuffmanTable(distanceDecoder,4); + + uint32_t items=readBits(16)+1; + for (uint32_t i=0;i lengthDecoder + { + HuffmanCode{1,0b000,0}, + HuffmanCode{2,0b010,1}, + HuffmanCode{3,0b110,2}, + HuffmanCode{3,0b111,3} + }; + + HuffmanDecoder distanceDecoder + { + HuffmanCode{1,0b00,0}, + HuffmanCode{2,0b10,1}, + HuffmanCode{2,0b11,2} + }; + + while (!outputStream.eof()) + { + if (readBit()) + { + outputStream.writeByte(readBits(8)); + } else { + uint8_t lengthIndex=lengthDecoder.decode(readBit); + + static const uint8_t lengthBits[4]={1,2,4,8}; + static const uint32_t lengthAdditions[4]={2,4,8,24}; + uint32_t count=readBits(lengthBits[lengthIndex])+lengthAdditions[lengthIndex]; + if (count==23) + { + if (readBit()) + { + count=readBits(5)+15; + } else { + count=readBits(14)+15; + } + for (uint32_t i=0;i23) count--; + + uint8_t distanceIndex=distanceDecoder.decode(readBit); + + static const uint8_t distanceBits[3]={9,5,14}; + static const uint32_t distanceAdditions[3]={32,0,544}; + uint32_t distance=readBits(distanceBits[distanceIndex])+distanceAdditions[distanceIndex]; + + outputStream.copy(distance,count); + } + } + } + } + + if (!outputStream.eof()) throw Decompressor::DecompressionError(); + if (_isSampled) + DLTADecode::decode(rawData,rawData,0,_rawSize); +} + +void CRMDecompressor::decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) +{ + if (rawData.size()!=_rawSize) throw Decompressor::DecompressionError(); + return decompressImpl(rawData,verify); +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/CRMDecompressor.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/CRMDecompressor.hpp new file mode 100644 index 00000000..1b4c4f35 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/CRMDecompressor.hpp @@ -0,0 +1,46 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef CRMDECOMPRESSOR_HPP +#define CRMDECOMPRESSOR_HPP + +#include "Decompressor.hpp" +#include "XPKDecompressor.hpp" + +namespace ancient::internal +{ + +class CRMDecompressor : public Decompressor, public XPKDecompressor +{ +public: + CRMDecompressor(const Buffer &packedData,uint32_t recursionLevel,bool verify); + CRMDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + virtual ~CRMDecompressor(); + + virtual const std::string &getName() const noexcept override final; + virtual const std::string &getSubName() const noexcept override final; + + virtual size_t getPackedSize() const noexcept override final; + virtual size_t getRawSize() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,bool verify) override final; + virtual void decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) override final; + + static bool detectHeader(uint32_t hdr) noexcept; + static bool detectHeaderXPK(uint32_t hdr) noexcept; + + static std::shared_ptr create(const Buffer &packedData,bool exactSizeKnown,bool verify); + static std::shared_ptr create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + +private: + const Buffer &_packedData; + + uint32_t _packedSize=0; + uint32_t _rawSize=0; + bool _isLZH=false; // "normal" compression or LZH compression + bool _isSampled=false; // normal or "sampled" i.e. obsfuscated + bool _isXPKDelta=false; // If delta encoding defined in XPK +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/CYB2Decoder.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/CYB2Decoder.cpp new file mode 100644 index 00000000..2deca68f --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/CYB2Decoder.cpp @@ -0,0 +1,62 @@ +/* Copyright (C) Teemu Suutari */ + +#include + +#include "common/SubBuffer.hpp" +#include "CYB2Decoder.hpp" +#include "XPKMain.hpp" +#include "common/Common.hpp" + + +namespace ancient::internal +{ + +bool CYB2Decoder::detectHeaderXPK(uint32_t hdr) noexcept +{ + return hdr==FourCC("CYB2"); +} + +std::shared_ptr CYB2Decoder::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) +{ + return std::make_shared(hdr,recursionLevel,packedData,state,verify); +} + +CYB2Decoder::CYB2Decoder(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) : + XPKDecompressor(recursionLevel), + _packedData(packedData) +{ + if (!detectHeaderXPK(hdr) || _packedData.size()<=10) throw Decompressor::InvalidFormatError(); + _blockHeader=_packedData.readBE32(0); + // after the block header, the next 6 bytes seem to be + // 00 64 00 00 00 00 + // Those bytes do not seem to be terribly important though... + + if (verify) + { + // trigger child checks... + ConstSubBuffer blockData(_packedData,10,_packedData.size()-10); + std::shared_ptr state; + auto sub=XPKMain::createDecompressor(_blockHeader,_recursionLevel+1,blockData,state,true); + } +} + +CYB2Decoder::~CYB2Decoder() +{ + // nothing needed +} + +const std::string &CYB2Decoder::getSubName() const noexcept +{ + static std::string name="XPK-CYB2: xpkCybPrefs container"; + return name; +} + +void CYB2Decoder::decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) +{ + ConstSubBuffer blockData(_packedData,10,_packedData.size()-10); + std::shared_ptr state; + auto sub=XPKMain::createDecompressor(_blockHeader,_recursionLevel+1,blockData,state,verify); + sub->decompressImpl(rawData,previousData,verify); +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/CYB2Decoder.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/CYB2Decoder.hpp new file mode 100644 index 00000000..33f7f56f --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/CYB2Decoder.hpp @@ -0,0 +1,33 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef CYB2DECODER_HPP +#define CYB2DECODER_HPP + +#include "XPKDecompressor.hpp" + +namespace ancient::internal +{ + +class CYB2Decoder : public XPKDecompressor +{ +public: + CYB2Decoder(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + + virtual ~CYB2Decoder(); + + virtual const std::string &getSubName() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) override final; + + static bool detectHeaderXPK(uint32_t hdr) noexcept; + static std::shared_ptr create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + +private: + const Buffer &_packedData; + + uint32_t _blockHeader; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/DEFLATEDecompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/DEFLATEDecompressor.cpp new file mode 100644 index 00000000..d4dc635c --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/DEFLATEDecompressor.cpp @@ -0,0 +1,386 @@ +/* Copyright (C) Teemu Suutari */ + +#include +#include + +#include "DEFLATEDecompressor.hpp" +#include "HuffmanDecoder.hpp" +#include "InputStream.hpp" +#include "OutputStream.hpp" +#include "common/CRC32.hpp" +#include "common/OverflowCheck.hpp" +#include "common/Common.hpp" + + +namespace ancient::internal +{ + +static uint32_t Adler32(const Buffer &buffer,size_t offset,size_t len) +{ + if (!len || OverflowCheck::sum(offset,len)>buffer.size()) throw Buffer::OutOfBoundsError(); + const uint8_t *ptr=buffer.data()+offset; + + uint32_t s1=1,s2=0; + for (size_t i=0;i=65521) s1-=65521; + s2+=s1; + if (s2>=65521) s2-=65521; + } + return (s2<<16)|s1; +} + +bool DEFLATEDecompressor::detectHeader(uint32_t hdr) noexcept +{ + return ((hdr>>16)==0x1f8b); +} + +bool DEFLATEDecompressor::detectHeaderXPK(uint32_t hdr) noexcept +{ + return (hdr==FourCC("GZIP")); +} + +std::shared_ptr DEFLATEDecompressor::create(const Buffer &packedData,bool exactSizeKnown,bool verify) +{ + return std::make_shared(packedData,exactSizeKnown,verify); +} + +std::shared_ptr DEFLATEDecompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) +{ + return std::make_shared(hdr,recursionLevel,packedData,state,verify); +} + +bool DEFLATEDecompressor::detectZLib() +{ + if (_packedData.size()<6) return false; + + // no knowledge about rawSize, before decompression + // packedSize told by decompressor + _packedSize=uint32_t(_packedData.size()); + _packedOffset=2; + + uint8_t cm=_packedData.read8(0); + if ((cm&0xf)!=8) return false; + if ((cm&0xf0)>0x70) return false; + + uint8_t flags=_packedData.read8(1); + if (flags&0x20) + { + if (_packedSize<8) return false; + _packedOffset+=4; + } + + if (((uint16_t(cm)<<8)|uint16_t(flags))%31) return false; + + _type=Type::ZLib; + return true; +} + +DEFLATEDecompressor::DEFLATEDecompressor(const Buffer &packedData,bool exactSizeKnown,bool verify) : + _packedData(packedData), + _exactSizeKnown(exactSizeKnown) +{ + if (_packedData.size()<18) throw InvalidFormatError(); + uint32_t hdr=_packedData.readBE32(0); + if (!detectHeader(hdr)) throw InvalidFormatError(); + + uint8_t cm=_packedData.read8(2); + if (cm!=8) throw InvalidFormatError();; + + uint8_t flags=_packedData.read8(3); + if (flags&0xe0) throw InvalidFormatError();; + + uint32_t currentOffset=10; + + if (flags&4) + { + uint16_t xlen=_packedData.readLE16(currentOffset); + currentOffset+=uint32_t(xlen)+2; + } + + auto skipString=[&]() + { + uint8_t ch; + do { + ch=_packedData.read8(currentOffset); + currentOffset++; + } while (ch); + }; + + if (flags&8) skipString(); // FNAME + if (flags&16) skipString(); // FCOMMENT + + if (flags&2) currentOffset+=2; // FHCRC, not using that since it is only for header + _packedOffset=currentOffset; + + if (OverflowCheck::sum(currentOffset,8U)>_packedData.size()) throw InvalidFormatError(); + + if (_exactSizeKnown) + { + _packedSize=_packedData.size(); + _rawSize=_packedData.readLE32(_packedData.size()-4); + if (!_rawSize) throw InvalidFormatError(); + } + + _type=Type::GZIP; +} + +DEFLATEDecompressor::DEFLATEDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) : + XPKDecompressor(recursionLevel), + _packedData(packedData) +{ + if (!detectZLib()) + { + _packedSize=packedData.size(); + _packedOffset=0; + _type=Type::Raw; + } +} + +DEFLATEDecompressor::DEFLATEDecompressor(const Buffer &packedData,size_t packedSize,size_t rawSize,bool isZlib,bool verify,bool deflate64) : + _packedData(packedData), + _deflate64(deflate64) +{ + _packedSize=packedSize; + if (_packedSize>_packedData.size()) throw InvalidFormatError(); + if (isZlib) + { + // if it is not real zlib-stream fail. + if (!detectZLib()) throw InvalidFormatError(); + } else { + // raw stream + _packedOffset=0; + _rawSize=rawSize; + _type=Type::Raw; + } +} + +DEFLATEDecompressor::~DEFLATEDecompressor() +{ + // nothing needed +} + + +const std::string &DEFLATEDecompressor::getName() const noexcept +{ + static std::string names[3]={ + "gzip: Deflate", + "zlib: Deflate", + "raw: Deflate/Deflate64"}; + return names[static_cast(_type)]; +} + +const std::string &DEFLATEDecompressor::getSubName() const noexcept +{ + static std::string name="XPK-GZIP: Deflate"; + return name; +} + +size_t DEFLATEDecompressor::getPackedSize() const noexcept +{ + // no way to know before decompressing + return _packedSize; +} + + +size_t DEFLATEDecompressor::getRawSize() const noexcept +{ + // same thing, decompression needed first + return _rawSize; +} + +void DEFLATEDecompressor::decompressImpl(Buffer &rawData,bool verify) +{ + size_t packedSize=_packedSize?_packedSize:_packedData.size(); + size_t rawSize=_rawSize?_rawSize:rawData.size(); + + ForwardInputStream inputStream(_packedData,_packedOffset,packedSize); + LSBBitReader bitReader(inputStream); + auto readBits=[&](uint32_t count)->uint32_t + { + return bitReader.readBits8(count); + }; + auto readBit=[&]()->uint32_t + { + return bitReader.readBits8(1); + }; + + ForwardOutputStream outputStream(rawData,0,rawSize); + + bool final; + do { + final=readBit(); + uint8_t blockType=readBits(2); + if (!blockType) + { + bitReader.reset(); + uint16_t len=inputStream.readByte(); + len|=uint16_t(inputStream.readByte())<<8; + uint16_t nlen=inputStream.readByte(); + nlen|=uint16_t(inputStream.readByte())<<8; + if (len!=(nlen^0xffffU)) throw DecompressionError(); + outputStream.produce(inputStream.consume(len),len); + } else if (blockType==1 || blockType==2) { + typedef HuffmanDecoder DEFLATEDecoder; + DEFLATEDecoder llDecoder; + DEFLATEDecoder distanceDecoder; + + if (blockType==1) + { + for (uint32_t i=0;i<24;i++) llDecoder.insert(HuffmanCode{7,i,int32_t(i+256)}); + for (uint32_t i=0;i<144;i++) llDecoder.insert(HuffmanCode{8,i+0x30,int32_t(i)}); + for (uint32_t i=0;i<8;i++) llDecoder.insert(HuffmanCode{8,i+0xc0,int32_t(i+280)}); + for (uint32_t i=0;i<112;i++) llDecoder.insert(HuffmanCode{9,i+0x190,int32_t(i+144)}); + + for (uint32_t i=0;i<32;i++) distanceDecoder.insert(HuffmanCode{5,i,int32_t(i)}); + } else { + uint32_t hlit=readBits(5)+257; + // lets just error here, it is simpler + if (hlit>=287) throw DecompressionError(); + uint32_t hdist=readBits(5)+1; + uint32_t hclen=readBits(4)+4; + + uint8_t lengthTable[19]; + for (uint32_t i=0;i<19;i++) lengthTable[i]=0; + static const uint8_t lengthTableOrder[19]={ + 16,17,18, 0, 8, 7, 9, 6, + 10, 5,11, 4,12, 3,13, 2, + 14, 1,15}; + for (uint32_t i=0;i=hlit+hdist) throw DecompressionError(); + if (i>=hlit) distanceTableBits[i-hlit]=value; + else llTableBits[i]=value; + prevValue=value; + i++; + }; + + int32_t code=bitLengthDecoder.decode(readBit); + if (code<16) { + insert(code); + } else switch (code) { + case 16: + if (i) + { + uint32_t count=readBits(2)+3; + for (uint32_t j=0;j(_deflate64?31:29)) throw DecompressionError(); + static const uint32_t distanceAdditions[32]={ + 1,2,3,4,5,7,9,13, + 0x11,0x19,0x21,0x31,0x41,0x61,0x81,0xc1, + 0x101,0x181,0x201,0x301,0x401,0x601,0x801,0xc01, + 0x1001,0x1801,0x2001,0x3001,0x4001,0x6001, + 0x8001,0xc001}; + static const uint32_t distanceBits[32]={ + 0,0,0,0,1,1,2,2, + 3,3,4,4,5,5,6,6, + 7,7,8,8,9,9,10,10, + 11,11,12,12,13,13, + 14,14}; + uint32_t distance=readBits(distanceBits[distCode])+distanceAdditions[distCode]; + outputStream.copy(distance,count); + } + } + } else { + throw DecompressionError(); + } + } while (!final); + + if (!_rawSize) _rawSize=outputStream.getOffset(); + if (_type==Type::GZIP) + { + if (OverflowCheck::sum(inputStream.getOffset(),8U)>packedSize) throw DecompressionError(); + if (!_packedSize) + _packedSize=inputStream.getOffset()+8; + } else if (_type==Type::ZLib) { + if (OverflowCheck::sum(inputStream.getOffset(),4U)>packedSize) throw DecompressionError(); + if (!_packedSize) + _packedSize=inputStream.getOffset()+4; + } else { + if (!_packedSize) + _packedSize=inputStream.getOffset(); + } + if (_rawSize!=outputStream.getOffset()) throw DecompressionError(); + + if (verify) + { + if (_type==Type::GZIP) + { + uint32_t crc=_packedData.readLE32(inputStream.getOffset()); + if (CRC32(rawData,0,_rawSize,0)!=crc) throw VerificationError(); + } else if (_type==Type::ZLib) { + uint32_t adler=_packedData.readBE32(inputStream.getOffset()); + if (Adler32(rawData,0,_rawSize)!=adler) throw VerificationError(); + } + } +} + +void DEFLATEDecompressor::decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) +{ + decompressImpl(rawData,verify); +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/DEFLATEDecompressor.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/DEFLATEDecompressor.hpp new file mode 100644 index 00000000..b4ee7a45 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/DEFLATEDecompressor.hpp @@ -0,0 +1,57 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef DEFLATEDECOMPRESSOR_HPP +#define DEFLATEDECOMPRESSOR_HPP + +#include "Decompressor.hpp" +#include "XPKDecompressor.hpp" + +namespace ancient::internal +{ + +class DEFLATEDecompressor : public Decompressor, public XPKDecompressor +{ +public: + DEFLATEDecompressor(const Buffer &packedData,bool exactSizeKnown,bool verify); + DEFLATEDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + DEFLATEDecompressor(const Buffer &packedData,size_t packedSize,size_t rawSize,bool isZlib,bool verify,bool deflate64); // zlib or completely raw stream + virtual ~DEFLATEDecompressor(); + + virtual size_t getRawSize() const noexcept override final; + virtual size_t getPackedSize() const noexcept override final; + + virtual const std::string &getName() const noexcept override final; + virtual const std::string &getSubName() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,bool verify) override final; + virtual void decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) override final; + + static bool detectHeader(uint32_t hdr) noexcept; + static bool detectHeaderXPK(uint32_t hdr) noexcept; + + static std::shared_ptr create(const Buffer &packedData,bool exactSizeKnown,bool verify); + static std::shared_ptr create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + +private: + bool detectZLib(); + + enum class Type + { + GZIP=0, + ZLib, + Raw + }; + + const Buffer &_packedData; + + size_t _packedSize=0; + size_t _packedOffset=0; + size_t _rawSize=0; + Type _type; + bool _exactSizeKnown=true; + bool _deflate64=false; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/DLTADecode.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/DLTADecode.cpp new file mode 100644 index 00000000..5cd8f1ce --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/DLTADecode.cpp @@ -0,0 +1,62 @@ +/* Copyright (C) Teemu Suutari */ + +#include "DLTADecode.hpp" + +#include "common/OverflowCheck.hpp" +#include "common/Common.hpp" + + +namespace ancient::internal +{ + +bool DLTADecode::detectHeaderXPK(uint32_t hdr) noexcept +{ + return hdr==FourCC("DLTA"); +} + +std::shared_ptr DLTADecode::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) +{ + return std::make_shared(hdr,recursionLevel,packedData,state,verify); +} + +DLTADecode::DLTADecode(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) : + XPKDecompressor(recursionLevel), + _packedData(packedData) +{ + if (!detectHeaderXPK(hdr)) throw Decompressor::InvalidFormatError(); +} + +DLTADecode::~DLTADecode() +{ + // nothing needed +} + +const std::string &DLTADecode::getSubName() const noexcept +{ + static std::string name="XPK-DLTA: Delta encoding"; + return name; +} + +void DLTADecode::decode(Buffer &bufferDest,const Buffer &bufferSrc,size_t offset,size_t size) +{ + if (OverflowCheck::sum(offset,size)>bufferSrc.size()) throw Buffer::OutOfBoundsError(); + if (OverflowCheck::sum(offset,size)>bufferDest.size()) throw Buffer::OutOfBoundsError(); + const uint8_t *src=bufferSrc.data()+offset; + uint8_t *dest=bufferDest.data()+offset; + + uint8_t ctr=0; + for (size_t i=0;i &state,bool verify); + + virtual ~DLTADecode(); + + virtual const std::string &getSubName() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) override final; + + static bool detectHeaderXPK(uint32_t hdr) noexcept; + static std::shared_ptr create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + + // static method for easy external usage. Buffers can be the same for in-place replacement + static void decode(Buffer &bufferDest,const Buffer &bufferSrc,size_t offset,size_t size); + +private: + const Buffer &_packedData; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/DMSDecompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/DMSDecompressor.cpp new file mode 100644 index 00000000..ded83c6c --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/DMSDecompressor.cpp @@ -0,0 +1,718 @@ +/* Copyright (C) Teemu Suutari */ + +#include +#include + +#include "DMSDecompressor.hpp" + +#include "HuffmanDecoder.hpp" +#include "DynamicHuffmanDecoder.hpp" +#include "InputStream.hpp" +#include "OutputStream.hpp" + +#include "common/MemoryBuffer.hpp" +#include "common/CRC16.hpp" +#include "common/OverflowCheck.hpp" +#include "common/Common.hpp" + + +namespace ancient::internal +{ + +bool DMSDecompressor::detectHeader(uint32_t hdr) noexcept +{ + return hdr==FourCC("DMS!"); +} + +std::shared_ptr DMSDecompressor::create(const Buffer &packedData,bool exactSizeKnown,bool verify) +{ + return std::make_shared(packedData,verify); +} + +DMSDecompressor::DMSDecompressor(const Buffer &packedData,bool verify) : + _packedData(packedData) +{ + uint32_t hdr=packedData.readBE32(0); + if (!detectHeader(hdr) || packedData.size()<56) throw InvalidFormatError(); + + if (verify && CRC16(packedData,4,50,0)!=packedData.readBE16(54)) + throw VerificationError(); + + uint16_t info=packedData.readBE16(10); + _isObsfuscated=info&2; // using 16 bit key is not encryption, it is obsfuscation + _isHD=info&16; + if (info&32) throw InvalidFormatError(); // MS-DOS disk + + // packed data in header is useless, as is rawsize and track numbers + // they are not always filled + + if (packedData.readBE16(50)>6) throw InvalidFormatError(); // either FMS or unknown + + // now calculate the real packed size, including headers + uint32_t offset=56; + uint32_t accountedSize=0; + uint32_t lastTrackSize=0; + uint32_t numTracks=0; + uint32_t minTrack=80; + uint32_t prevTrack=0; + while (offset+206) throw InvalidFormatError(); + static const uint32_t contextSizes[7]={0,0,256,16384,16384,4096,8192}; + _contextBufferSize=std::max(_contextBufferSize,contextSizes[mode]); + + uint8_t flags=_packedData.read8(offset+12); + if ((mode>=2 && mode<=4) || (mode>=5 && (flags&4))) + { + _tmpBufferSize=std::max(_tmpBufferSize,uint32_t(_packedData.readBE16(offset+8))); + } + uint32_t packedChunkLength=packedData.readBE16(offset+6); + if (OverflowCheck::sum(offset,20U,packedChunkLength)>packedData.size()) + throw InvalidFormatError(); + if (verify && CRC16(packedData,offset+20,packedChunkLength,0)!=packedData.readBE16(offset+16)) + throw VerificationError(); + + if (trackNo<80) + { + if (trackNo>=numTracks) lastTrackSize=_packedData.readBE16(offset+10); + minTrack=std::min(minTrack,trackNo); + numTracks=std::max(numTracks,trackNo); + prevTrack=trackNo; + } + + offset+=packedChunkLength+20; + accountedSize+=packedChunkLength; + // this is the real exit critea, unfortunately + if (trackNo>=79 && trackNo<0x8000U) break; + } + uint32_t trackSize=(_isHD)?22528:11264; + _rawOffset=minTrack*trackSize; + if (minTrack>=numTracks) + throw InvalidFormatError(); + _minTrack=minTrack; + _rawSize=(numTracks-minTrack)*trackSize+lastTrackSize; + _imageSize=trackSize*80; + + _packedSize=offset; + if (_packedSize>getMaxPackedSize()) + throw InvalidFormatError(); +} + +DMSDecompressor::~DMSDecompressor() +{ + // nothing needed +} + +const std::string &DMSDecompressor::getName() const noexcept +{ + static std::string name="DMS: Disk Masher System"; + return name; +} + +size_t DMSDecompressor::getPackedSize() const noexcept +{ + return _packedSize; +} + +size_t DMSDecompressor::getRawSize() const noexcept +{ + return _rawSize; +} + +size_t DMSDecompressor::getImageSize() const noexcept +{ + return _imageSize; +} + +size_t DMSDecompressor::getImageOffset() const noexcept +{ + return _rawOffset; +} + +void DMSDecompressor::decompressImpl(Buffer &rawData,bool verify) +{ + uint32_t restartPosition=0; + if (!_isObsfuscated) + { + decompressImpl(rawData,verify,restartPosition); + } else { + while (restartPosition<0x20000U) + { + // more than single run here is really rare. It means that first track CRC succeeds + // but later something else fails + try + { + decompressImpl(rawData,verify,restartPosition); + return; + } catch (const Buffer::Error &) { + // just continue + } catch (const Decompressor::Error &) { + // just continue + } + restartPosition++; + } + throw DecompressionError(); + } +} + +// TODO: Too much state for a single method. too convoluted +// needs to be split +void DMSDecompressor::decompressImpl(Buffer &rawData,bool verify,uint32_t &restartPosition) +{ + if (rawData.size()<_rawSize) throw DecompressionError(); + MemoryBuffer contextBuffer(_contextBufferSize); + MemoryBuffer tmpBuffer(_tmpBufferSize); + uint32_t limitedDecompress=~0U; + + class UnObsfuscator + { + public: + UnObsfuscator(ForwardInputStream &inputStream) : + _inputStream(inputStream) + { + // nothing needed + } + + uint8_t readByte() + { + if (_inputStream.eof()) throw ShortInputError(); + uint8_t ch=_inputStream.readByte(); + if (!_obsfuscate) + { + return ch; + } else { + uint8_t ret=ch^_passAccumulator; + _passAccumulator=(_passAccumulator>>1)+uint16_t(ch); + return ret; + } + } + + void setCode(uint16_t passAccumulator) + { + _passAccumulator=passAccumulator; + } + + void setObsfuscate(bool obsfuscate) { _obsfuscate=obsfuscate; } + bool eof() const { return _inputStream.getOffset()==_inputStream.getEndOffset(); } + + // not cool, but works (does not need wraparound check) + bool eofMinus1() const { return _inputStream.getOffset()+1==_inputStream.getEndOffset(); } + bool eofMinus1Plus() const { return _inputStream.getOffset()+1>=_inputStream.getEndOffset(); } + bool eofMinus2Plus() const { return _inputStream.getOffset()+2>=_inputStream.getEndOffset(); } + + private: + ForwardInputStream &_inputStream; + bool _obsfuscate=false; + uint16_t _passAccumulator=0; + }; + + ForwardInputStream inputStream(_packedData,0,0); + UnObsfuscator inputUnObsfuscator(inputStream); + MSBBitReader bitReader(inputUnObsfuscator); + auto initInputStream=[&](const Buffer &buffer,uint32_t start,uint32_t length,bool obsfuscate) + { + inputStream=ForwardInputStream(buffer,start,OverflowCheck::sum(start,length)); + inputUnObsfuscator.setObsfuscate(obsfuscate); + bitReader.reset(); + }; + auto finishStream=[&]() + { + if (_isObsfuscated && limitedDecompress==~0U) + while (!inputUnObsfuscator.eof()) + inputUnObsfuscator.readByte(); + }; + auto readBits=[&](uint32_t count)->uint32_t + { + return bitReader.readBits8(count); + }; + auto readBit=[&]()->uint32_t + { + return bitReader.readBits8(1); + }; + + ForwardOutputStream outputStream(rawData,0,0); + auto initOutputStream=[&](Buffer &buffer,uint32_t start,uint32_t length) + { + outputStream=ForwardOutputStream(buffer,start,OverflowCheck::sum(start,length)); + }; + + // fill unused tracks with zeros + std::memset(rawData.data(),0,_rawSize); + + auto checksum=[](const uint8_t *src,uint32_t srcLength)->uint16_t + { + uint16_t ret=0; + for (uint32_t i=0;iuint32_t + { + // hacky, hacky, hacky + while (!inputUnObsfuscator.eof()) + { + if (outputStream.getOffset()>=limitedDecompress) return 0; + if (lastCharMissing && inputUnObsfuscator.eofMinus1()) + { + if (outputStream.getOffset()+1!=outputStream.getEndOffset()) + throw DecompressionError(); + return 1; + } + uint8_t ch=inputUnObsfuscator.readByte(); + uint32_t count=1; + if (ch==0x90U) + { + if (inputUnObsfuscator.eof()) throw DecompressionError(); + if (lastCharMissing && inputUnObsfuscator.eofMinus1()) + { + // only possible way this can work + if (outputStream.getOffset()+1!=outputStream.getEndOffset()) throw DecompressionError(); + count=0; + } else count=inputUnObsfuscator.readByte(); + if (!count) + { + count=1; + } else { + + if (inputUnObsfuscator.eof()) throw DecompressionError(); + if (lastCharMissing && inputUnObsfuscator.eofMinus1()) + { + if (count==0xffU || outputStream.getOffset()+count!=outputStream.getEndOffset()) throw DecompressionError(); + return count; + } + ch=inputUnObsfuscator.readByte(); + } + if (count==0xffU) + { + if (inputUnObsfuscator.eofMinus1Plus()) throw DecompressionError(); + if (lastCharMissing && inputUnObsfuscator.eofMinus2Plus()) + { + count=uint32_t(outputStream.getEndOffset()-outputStream.getOffset()); + } else { + count=uint32_t(inputUnObsfuscator.readByte())<<8; + count|=inputUnObsfuscator.readByte(); + } + } + } + for (uint32_t i=0;i> deepDecoder; + auto initContext=[&]() + { + if (doInitContext) + { + if (_contextBufferSize) std::memset(contextBuffer.data(),0,_contextBufferSize); + quickContextLocation=251; + mediumContextLocation=16318; + deepContextLocation=16324; + deepDecoder.reset(); + heavyContextLocation=0; + doInitContext=false; + } + }; + + auto unpackQuick=[&]() + { + initContext(); + + while (!outputStream.eof()) + { + if (outputStream.getOffset()>=limitedDecompress) return; + if (readBits(1)) + { + outputStream.writeByte(contextBufferPtr[quickContextLocation++]=readBits(8)); + } else { + uint32_t count=readBits(2)+2; + uint8_t offset=quickContextLocation-readBits(8)-1; + for (uint32_t i=0;iuint32_t + { + return (((code<uint32_t + { + return (uint32_t(lengthTable[code])<<8)| + uint32_t(((code<=limitedDecompress) return; + if (readBits(1)) + { + outputStream.writeByte(contextBufferPtr[mediumContextLocation++]=readBits(8)); + mediumContextLocation&=0x3fffU; + } else { + uint32_t code=readBits(8); + uint32_t count=lengthTable[code]+3; + + uint32_t tmp=decodeLengthValueFull(decodeLengthValueHalf(code)); + + uint32_t offset=mediumContextLocation-tmp-1; + for (uint32_t i=0;i>(); + + while (!outputStream.eof()) + { + if (outputStream.getOffset()>=limitedDecompress) return; + uint32_t symbol=deepDecoder->decode(readBit); + if (deepDecoder->getMaxFrequency()==0x8000U) deepDecoder->halve(); + deepDecoder->update(symbol); + if (symbol<256) + { + outputStream.writeByte(contextBufferPtr[deepContextLocation++]=symbol); + deepContextLocation&=0x3fffU; + } else { + uint32_t count=symbol-253; // minimum repeat is 3 + uint32_t offset=deepContextLocation-decodeLengthValueFull(readBits(8))-1; + + for (uint32_t i=0;i> symbolDecoder,offsetDecoder; + bool heavyLastInitialized=false; // this is part of initContext on some implementations. screwy!!! + uint32_t heavyLastOffset; + auto unpackHeavy=[&](bool initTables,bool use8kDict) + { + initContext(); + // well, this works. Why this works? dunno + if (!heavyLastInitialized) + { + heavyLastOffset=use8kDict?0U:~0U; + heavyLastInitialized=true; + } + + auto readTable=[&](std::unique_ptr> &decoder,uint32_t countBits,uint32_t valueBits) + { + decoder=std::make_unique>(); + uint32_t count=readBits(countBits); + if (count) + { + uint8_t lengthBuffer[512]; + // in order to speed up the deObsfuscation, do not send the hopeless + // data into slow CreateOrderlyHuffmanTable + uint64_t sum=0; + for (uint32_t i=0;i(uint64_t(1U)<<32)) + throw DecompressionError(); + } + lengthBuffer[i]=bits; + } + decoder->createOrderlyHuffmanTable(lengthBuffer,count); + } else { + uint32_t index=readBits(countBits); + decoder->setEmpty(index); + } + }; + + if (initTables) + { + readTable(symbolDecoder,9,5); + readTable(offsetDecoder,5,4); + } + + uint32_t mask=use8kDict?0x1fffU:0xfffU; + uint32_t bitLength=use8kDict?14:13; + + while (!outputStream.eof()) + { + if (outputStream.getOffset()>=limitedDecompress) return; + uint32_t symbol=symbolDecoder->decode(readBit); + if (symbol<256) + { + outputStream.writeByte(contextBufferPtr[heavyContextLocation++]=symbol); + heavyContextLocation&=mask; + } else { + uint32_t count=symbol-253; // minimum repeat is 3 + uint32_t offsetLength=offsetDecoder->decode(readBit); + uint32_t rawOffset=heavyLastOffset; + if (offsetLength!=bitLength) + { + if (offsetLength) rawOffset=(1<<(offsetLength-1))|readBits(offsetLength-1); + else rawOffset=0; + heavyLastOffset=rawOffset; + } + uint32_t offset=heavyContextLocation-rawOffset-1; + for (uint32_t i=0;i=0x8000U) + { + initInputStream(_packedData,packedOffset+20,packedChunkLength,_isObsfuscated); + finishStream(); + continue; + } + if (rawChunkLength>trackLength) throw DecompressionError(); + if (trackNo>80) throw DecompressionError(); // should not happen, already excluded + + uint32_t dataOffset=trackNo*trackLength; + if (_rawOffset>dataOffset) throw DecompressionError(); + + // this is screwy, but it is, what it is + auto processBlock=[&](bool doRLE,auto func,auto&&... params) + { + initInputStream(_packedData,packedOffset+20,packedChunkLength,_isObsfuscated); + if (doRLE) + { + try + { + initOutputStream(tmpBuffer,0,tmpChunkLength); + func(params...); + finishStream(); + initInputStream(tmpBuffer,0,tmpChunkLength,false); + initOutputStream(rawData,dataOffset-_rawOffset,rawChunkLength); + unRLE(false); + } catch (const ShortInputError &) { + // if this error happens on repeat/offset instead of char, though luck :( + // missing last char on src we can fix :) + initInputStream(tmpBuffer,0,tmpChunkLength,false); + initOutputStream(rawData,dataOffset-_rawOffset,rawChunkLength); + uint32_t missingNo=unRLE(true); + if (missingNo) + { + uint32_t protoSum=checksum(&rawData[dataOffset-_rawOffset],rawChunkLength-missingNo); + uint32_t fileSum=_packedData.readBE16(packedOffset+14); + uint8_t ch=((fileSum>=protoSum)?fileSum-protoSum:(0x10000U+fileSum-protoSum))/missingNo; + for (uint32_t i=0;i create(const Buffer &packedData,bool exactSizeKnown,bool verify); + +private: + void decompressImpl(Buffer &rawData,bool verify,uint32_t &restartPosition); + + class ShortInputError : public Error + { + // nothing needed + }; + + const Buffer &_packedData; + + uint32_t _packedSize=0; + uint32_t _rawSize=0; + uint32_t _contextBufferSize=0; + uint32_t _tmpBufferSize=0; + uint32_t _imageSize; + uint32_t _rawOffset; + uint32_t _minTrack; + bool _isHD; + bool _isObsfuscated; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/Decompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/Decompressor.cpp new file mode 100644 index 00000000..6f0b976c --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/Decompressor.cpp @@ -0,0 +1,108 @@ +/* Copyright (C) Teemu Suutari */ + +#include "Decompressor.hpp" + +#include +#include + +#include "BZIP2Decompressor.hpp" +#include "CRMDecompressor.hpp" +#include "DEFLATEDecompressor.hpp" +#include "DMSDecompressor.hpp" +#include "IMPDecompressor.hpp" +#include "MMCMPDecompressor.hpp" +#include "PPDecompressor.hpp" +#include "RNCDecompressor.hpp" +#include "StoneCrackerDecompressor.hpp" +#include "TPWMDecompressor.hpp" +#include "XPKMain.hpp" + +namespace ancient::internal +{ + +// --- + +static std::vector(*)(const Buffer&,bool,bool)>> decompressors={ + {BZIP2Decompressor::detectHeader,BZIP2Decompressor::create}, + {CRMDecompressor::detectHeader,CRMDecompressor::create}, + {DEFLATEDecompressor::detectHeader,DEFLATEDecompressor::create}, + {DMSDecompressor::detectHeader,DMSDecompressor::create}, + {IMPDecompressor::detectHeader,IMPDecompressor::create}, + {MMCMPDecompressor::detectHeader,MMCMPDecompressor::create}, + {PPDecompressor::detectHeader,PPDecompressor::create}, + {RNCDecompressor::detectHeader,RNCDecompressor::create}, + {StoneCrackerDecompressor::detectHeader,StoneCrackerDecompressor::create}, + {TPWMDecompressor::detectHeader,TPWMDecompressor::create}, + {XPKMain::detectHeader,XPKMain::create}}; + +Decompressor::Decompressor() noexcept +{ + // nothing needed +} + +Decompressor::~Decompressor() +{ + // nothing needed +} + +std::shared_ptr Decompressor::create(const Buffer &packedData,bool exactSizeKnown,bool verify) +{ + try + { + uint32_t hdr=packedData.readBE32(0); + for (auto &it : decompressors) + { + if (it.first(hdr)) return it.second(packedData,exactSizeKnown,verify); + } + throw InvalidFormatError(); + } catch (const Buffer::Error&) { + throw InvalidFormatError(); + } +} + +bool Decompressor::detect(const Buffer &packedData) noexcept +{ + try + { + uint32_t hdr=packedData.readBE32(0); + for (auto &it : decompressors) + if (it.first(hdr)) return true; + return false; + } catch (const Buffer::Error&) { + return false; + } +} + +void Decompressor::decompress(Buffer &rawData,bool verify) +{ + // Simplifying the implementation of sub-decompressors. Just let the buffer-exception pass here, + // and that will get translated into Decompressor exceptions + try + { + decompressImpl(rawData,verify); + } catch (const Buffer::Error&) { + throw DecompressionError(); + } +} + +size_t Decompressor::getImageSize() const noexcept +{ + return 0; +} + +size_t Decompressor::getImageOffset() const noexcept +{ + return 0; +} + +size_t Decompressor::getMaxPackedSize() noexcept +{ + return 0x100'0000U; +} + +size_t Decompressor::getMaxRawSize() noexcept +{ + return 0x100'0000U; +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/Decompressor.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/Decompressor.hpp new file mode 100644 index 00000000..fd0af8bd --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/Decompressor.hpp @@ -0,0 +1,86 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef DECOMPRESSOR_HPP +#define DECOMPRESSOR_HPP + +#include +#include + +#include +#include + +#include "common/Buffer.hpp" +#include "ancient.hpp" + +namespace ancient::internal +{ + +class Decompressor +{ +protected: + Decompressor() noexcept; + +public: + + using Error = ancient::Error; + using InvalidFormatError = ancient::InvalidFormatError; + using DecompressionError = ancient::DecompressionError; + using VerificationError = ancient::VerificationError; + + Decompressor(const Decompressor&)=delete; + Decompressor& operator=(const Decompressor&)=delete; + + virtual ~Decompressor(); + + // Name returned is human readable long name + virtual const std::string &getName() const noexcept=0; + + // PackedSize or RawSize are taken from the stream if available, 0 otherwise. + // for those compressors having 0 sizes, running decompression will update + // the values. (make sure to allocate big-enough buffer for decompression) + // There are exceptions: Some decompressors need to exact size of the packed data + // in order to decompress. For those providing a indefinitely size packed stream + // will not work + // use the "exactSizeKnown" flag for create to tell whether you know the size or not + virtual size_t getPackedSize() const noexcept=0; + virtual size_t getRawSize() const noexcept=0; + + // Actual decompression. + // verify checksum if verify==true + // can throw DecompressionError if stream cant be unpacked + // can throw VerificationError if verify enabled and checksum does not match + void decompress(Buffer &rawData,bool verify); + + // in case of disk image based formats the data does not necessarily start + // from logical beginnig of the image but it is offsetted inside the logical image + // (f.e. DMS). getDataOffset will return the offset (or 0 if not relevant or if offset does not exist) + // getImageSize will return the size of the the logical image, or 0 if not image-based format + virtual size_t getImageSize() const noexcept; + virtual size_t getImageOffset() const noexcept; + + // the functions are there to protect against "accidental" large files when parsing headers + // a.k.a. 16M should be enough for everybody (sizes do not have to accurate i.e. + // compressors can exclude header content for simplification) + // This entirely ok for the context of "old computers" and their files, + // for other usages these need to be tuned up + static size_t getMaxPackedSize() noexcept; + static size_t getMaxRawSize() noexcept; + + // Main entrypoint + // if verify=true then check the packedData for errors: CRC or other checksum if available + // check exactSizeKnown from size documentation + // can throw InvalidFormatError if stream is not recognized or it is invalid + // can throw VerificationError if verify enabled and checksum does not match + static std::shared_ptr create(const Buffer &packedData,bool exactSizeKnown,bool verify); + + // Detect signature whether it matches to any known compressor + // This does not guarantee the data is decompressable though, only signature is read + static bool detect(const Buffer &packedData) noexcept; + +protected: + virtual void decompressImpl(Buffer &rawData,bool verify)=0; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/DynamicHuffmanDecoder.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/DynamicHuffmanDecoder.hpp new file mode 100644 index 00000000..41936d5e --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/DynamicHuffmanDecoder.hpp @@ -0,0 +1,226 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef DYNAMICHUFFMANDECODER_HPP +#define DYNAMICHUFFMANDECODER_HPP + +#include +#include + +// For exception +#include "Decompressor.hpp" + +namespace ancient::internal +{ + +template +class DynamicHuffmanDecoder +{ +public: + DynamicHuffmanDecoder(uint32_t initialCount=maxCount) : + _initialCount(initialCount) + { + if (_initialCount>maxCount) throw Decompressor::DecompressionError(); + reset(); + } + + ~DynamicHuffmanDecoder() + { + // nothing needed + } + + void reset() + { + _count=_initialCount; + if (!_count) return; + for (uint32_t i=0;i<_count;i++) + { + _nodes[i].frequency=1; + _nodes[i].index=i+(maxCount-_count)*2; + _nodes[i].parent=maxCount*2-_count+(i>>1); + _nodes[i].leaves[0]=0; + _nodes[i].leaves[1]=0; + _codeMap[i+(maxCount-_count)*2]=i; + } + for (uint32_t i=maxCount*2-_count,j=0;i=_count)?j+(maxCount-_count)*2:j; + uint32_t r=(j+1>=_count)?j+1+(maxCount-_count)*2:(j+1); + _nodes[i].frequency=_nodes[l].frequency+_nodes[r].frequency; + _nodes[i].index=i; + _nodes[i].parent=maxCount+(i>>1); + _nodes[i].leaves[0]=l; + _nodes[i].leaves[1]=r; + _codeMap[i]=i; + } + } + + template + uint32_t decode(F bitReader) const + { + if (!_count) throw Decompressor::DecompressionError(); + if (_count==1) return 0; + uint32_t code=maxCount*2-2; + while (code>=maxCount) + code=_nodes[code].leaves[bitReader()?1:0]; + return code; + } + + void update(uint32_t code) + { + + if (code>=_count) throw Decompressor::DecompressionError(); + // this is a bug in LH2. Nobody else uses this codepath, so we can let it be... + if (_count==1) + { + _nodes[0].frequency=1; + return; + } + + while (code!=maxCount*2-2) + { + _nodes[code].frequency++; + + uint32_t index=_nodes[code].index; + uint32_t destIndex=index; + uint32_t freq=_nodes[code].frequency; + + while (destIndex!=maxCount*2-2 && freq>_nodes[_codeMap[destIndex+1]].frequency) destIndex++; + if (index!=destIndex) + { + auto getParentLeaf=[&](uint32_t currentCode)->uint32_t& + { + Node &parent=_nodes[_nodes[currentCode].parent]; + return parent.leaves[(parent.leaves[0]==currentCode)?0:1]; + }; + + uint32_t destCode=_codeMap[destIndex]; + std::swap(_nodes[code].index,_nodes[destCode].index); + std::swap(_codeMap[index],_codeMap[destIndex]); + std::swap(getParentLeaf(code),getParentLeaf(destCode)); + std::swap(_nodes[code].parent,_nodes[destCode].parent); + } + code=_nodes[code].parent; + } + _nodes[code].frequency++; + } + + // halve the frequencies rounding upwards + void halve() + { + if (!_count) return; + else if (_count==1) + { + _nodes[0].frequency=(_nodes[0].frequency+1)>>1; + return; + } + + for (uint32_t i=(maxCount-_count)*2,j=(maxCount-_count)*2;i>1; + _nodes[i].parent=maxCount+(_nodes[i].index>>1); + _codeMap[_nodes[i].index]=i; + } + for (uint32_t i=maxCount*2-_count,j=(maxCount-_count)*2;i>1); + _nodes[i].leaves[0]=l; + _nodes[i].leaves[1]=r; + _codeMap[i]=i; + + for (uint32_t k=i;freq<_nodes[_codeMap[k-1]].frequency;k--) + { + uint32_t &code=_codeMap[k]; + uint32_t &destCode=_codeMap[k-1]; + std::swap(_nodes[code].index,_nodes[destCode].index); + std::swap(_nodes[code].parent,_nodes[destCode].parent); + std::swap(code,destCode); + } + } + } + + // Defined as in LH2 + void addCode() + { + if (_count>=maxCount) throw Decompressor::DecompressionError(); + uint32_t newIndex=(maxCount-_count-1)*2; + if (!_count) + { + _nodes[0].frequency=0; + _nodes[0].index=newIndex-1; + _nodes[0].parent=maxCount*2-2; + _nodes[0].leaves[0]=0; + _nodes[0].leaves[1]=0; + _codeMap[newIndex-1]=0; + _count++; + } else { + _nodes[_count].frequency=0; + _nodes[_count].index=newIndex; + _nodes[_count].parent=maxCount*2-_count-1; + _nodes[_count].leaves[0]=0; + _nodes[_count].leaves[1]=0; + _codeMap[newIndex]=_count; + + uint32_t insertIndex=newIndex+2; + + uint32_t repNode; + uint32_t parentNode; + uint32_t insertNode=maxCount*2-_count-1; + if (_count>1) + { + _codeMap[insertIndex-1]=_codeMap[insertIndex]; + _nodes[_codeMap[insertIndex-1]].index--; + + repNode=_codeMap[(maxCount-_count)*2]; + parentNode=_nodes[repNode].parent; + _nodes[parentNode].leaves[(_nodes[parentNode].leaves[0]==repNode)?0:1]=insertNode; + _nodes[repNode].parent=insertNode; + } else { + repNode=0; + parentNode=maxCount*2-1; + } + + _nodes[insertNode].frequency=_nodes[repNode].frequency; + _nodes[insertNode].index=insertIndex; + _nodes[insertNode].parent=parentNode; + _nodes[insertNode].leaves[0]=_count; + _nodes[insertNode].leaves[1]=repNode; + _codeMap[insertIndex]=insertNode; + + Node &parent=_nodes[parentNode]; + if (_count>1 && _nodes[parent.leaves[0]].index>_nodes[parent.leaves[1]].index) + std::swap(parent.leaves[0],parent.leaves[1]); + _count++; + } + } + + uint32_t getMaxFrequency() const + { + return _nodes[maxCount*2-2].frequency; + } + +private: + struct Node + { + uint32_t frequency; + uint32_t index; + uint32_t parent; + uint32_t leaves[2]; + }; + + uint32_t _initialCount; + uint32_t _count; + Node _nodes[maxCount*2-1]; + uint32_t _codeMap[maxCount*2-1]; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/FASTDecompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/FASTDecompressor.cpp new file mode 100644 index 00000000..c2308c5e --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/FASTDecompressor.cpp @@ -0,0 +1,78 @@ +/* Copyright (C) Teemu Suutari */ + +#include "FASTDecompressor.hpp" +#include "InputStream.hpp" +#include "OutputStream.hpp" +#include "common/Common.hpp" + + +namespace ancient::internal +{ + +bool FASTDecompressor::detectHeaderXPK(uint32_t hdr) noexcept +{ + return hdr==FourCC("FAST"); +} + +std::shared_ptr FASTDecompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) +{ + return std::make_shared(hdr,recursionLevel,packedData,state,verify); +} + +FASTDecompressor::FASTDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) : + XPKDecompressor(recursionLevel), + _packedData(packedData) +{ + if (!detectHeaderXPK(hdr)) throw Decompressor::InvalidFormatError(); +} + +FASTDecompressor::~FASTDecompressor() +{ + // nothing needed +} + +const std::string &FASTDecompressor::getSubName() const noexcept +{ + static std::string name="XPK-FAST: Fast LZ77 compressor"; + return name; +} + +void FASTDecompressor::decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) +{ + ForwardInputStream forwardInputStream(_packedData,0,_packedData.size()); + BackwardInputStream backwardInputStream(_packedData,0,_packedData.size()); + forwardInputStream.link(backwardInputStream); + backwardInputStream.link(forwardInputStream); + MSBBitReader bitReader(backwardInputStream); + auto readBit=[&]()->uint32_t + { + return bitReader.readBitsBE16(1); + }; + auto readByte=[&]()->uint8_t + { + return forwardInputStream.readByte(); + }; + auto readShort=[&]()->uint16_t + { + const uint8_t *buf=backwardInputStream.consume(2); + uint16_t ret=uint16_t(buf[0])<<8; + return ret|uint16_t(buf[1]); + }; + + ForwardOutputStream outputStream(rawData,0,rawData.size()); + + while (!outputStream.eof()) + { + if (!readBit()) + { + outputStream.writeByte(readByte()); + } else { + uint16_t ld=readShort(); + uint32_t count=std::min(18U-(ld&0xf),uint32_t(outputStream.getEndOffset()-outputStream.getOffset())); + uint32_t distance=ld>>4; + outputStream.copy(distance,count); + } + } +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/FASTDecompressor.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/FASTDecompressor.hpp new file mode 100644 index 00000000..d16f091f --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/FASTDecompressor.hpp @@ -0,0 +1,31 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef FASTDECOMPRESSOR_HPP +#define FASTDECOMPRESSOR_HPP + +#include "XPKDecompressor.hpp" + +namespace ancient::internal +{ + +class FASTDecompressor : public XPKDecompressor +{ +public: + FASTDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + + virtual ~FASTDecompressor(); + + virtual const std::string &getSubName() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) override final; + + static bool detectHeaderXPK(uint32_t hdr) noexcept; + static std::shared_ptr create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + +private: + const Buffer &_packedData; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/FBR2Decompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/FBR2Decompressor.cpp new file mode 100644 index 00000000..68ad2cb0 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/FBR2Decompressor.cpp @@ -0,0 +1,98 @@ +/* Copyright (C) Teemu Suutari */ + +#include "FBR2Decompressor.hpp" +#include "InputStream.hpp" +#include "OutputStream.hpp" +#include "common/Common.hpp" + + +namespace ancient::internal +{ + +bool FBR2Decompressor::detectHeaderXPK(uint32_t hdr) noexcept +{ + return hdr==FourCC("FBR2"); +} + +std::shared_ptr FBR2Decompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) +{ + return std::make_shared(hdr,recursionLevel,packedData,state,verify); +} + +FBR2Decompressor::FBR2Decompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) : + XPKDecompressor(recursionLevel), + _packedData(packedData) +{ + if (!detectHeaderXPK(hdr)) throw Decompressor::InvalidFormatError();; +} + +FBR2Decompressor::~FBR2Decompressor() +{ + // nothing needed +} + +const std::string &FBR2Decompressor::getSubName() const noexcept +{ + static std::string name="XPK-FBR2: FBR2 CyberYAFA compressor"; + return name; +} + +void FBR2Decompressor::decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) +{ + ForwardInputStream inputStream(_packedData,0,_packedData.size()); + + ForwardOutputStream outputStream(rawData,0,rawData.size()); + + uint8_t mode=inputStream.readByte(); + while (!outputStream.eof()) + { + bool doCopy=false; + uint32_t count=0; + switch (mode) + { + case 33: + count=uint32_t(inputStream.readByte())<<24; + count|=uint32_t(inputStream.readByte())<<16; + count|=uint32_t(inputStream.readByte())<<8; + count|=uint32_t(inputStream.readByte()); + if (count>=0x8000'0000) + { + doCopy=true; + count=0-count; + } + break; + + case 67: + count=uint32_t(inputStream.readByte())<<8; + count|=uint32_t(inputStream.readByte()); + if (count>=0x8000) + { + doCopy=true; + count=0x10000-count; + } + break; + + case 100: + count=uint32_t(inputStream.readByte()); + if (count>=0x80) + { + doCopy=true; + count=0x100-count; + } + break; + + default: + throw Decompressor::DecompressionError(); + } + + count++; + if (doCopy) { + for (uint32_t i=0;i &state,bool verify); + + virtual ~FBR2Decompressor(); + + virtual const std::string &getSubName() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) override final; + + static bool detectHeaderXPK(uint32_t hdr) noexcept; + static std::shared_ptr create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + +private: + const Buffer &_packedData; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/FRLEDecompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/FRLEDecompressor.cpp new file mode 100644 index 00000000..43639dfc --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/FRLEDecompressor.cpp @@ -0,0 +1,67 @@ +/* Copyright (C) Teemu Suutari */ + +#include "FRLEDecompressor.hpp" +#include "InputStream.hpp" +#include "OutputStream.hpp" +#include "common/Common.hpp" + + +namespace ancient::internal +{ + +bool FRLEDecompressor::detectHeaderXPK(uint32_t hdr) noexcept +{ + return hdr==FourCC("FRLE"); +} + +std::shared_ptr FRLEDecompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) +{ + return std::make_shared(hdr,recursionLevel,packedData,state,verify); +} + +FRLEDecompressor::FRLEDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) : + XPKDecompressor(recursionLevel), + _packedData(packedData) +{ + if (!detectHeaderXPK(hdr)) throw Decompressor::InvalidFormatError(); +} + +FRLEDecompressor::~FRLEDecompressor() +{ + // nothing needed +} + +const std::string &FRLEDecompressor::getSubName() const noexcept +{ + static std::string name="XPK-FRLE: RLE-compressor"; + return name; +} + +void FRLEDecompressor::decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) +{ + ForwardInputStream inputStream(_packedData,0,_packedData.size()); + + ForwardOutputStream outputStream(rawData,0,rawData.size()); + + while (!outputStream.eof()) + { + auto countMod=[](uint32_t count)->uint32_t + { + return (32-(count&0x1f))+(count&0x60); + }; + + uint32_t count=uint32_t(inputStream.readByte()); + + if (count<128) + { + count=countMod(count); + for (uint32_t i=0;i &state,bool verify); + + virtual ~FRLEDecompressor(); + + virtual const std::string &getSubName() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,const Buffer &previousData,bool override) override final; + + static bool detectHeaderXPK(uint32_t hdr) noexcept; + static std::shared_ptr create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + +private: + const Buffer &_packedData; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/HFMNDecompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/HFMNDecompressor.cpp new file mode 100644 index 00000000..ce72f075 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/HFMNDecompressor.cpp @@ -0,0 +1,91 @@ +/* Copyright (C) Teemu Suutari */ + +#include "HFMNDecompressor.hpp" +#include "HuffmanDecoder.hpp" +#include "InputStream.hpp" +#include "OutputStream.hpp" +#include "common/OverflowCheck.hpp" +#include "common/Common.hpp" + + +namespace ancient::internal +{ + +bool HFMNDecompressor::detectHeaderXPK(uint32_t hdr) noexcept +{ + return hdr==FourCC("HFMN"); +} + +std::shared_ptr HFMNDecompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) +{ + return std::make_shared(hdr,recursionLevel,packedData,state,verify); +} + +HFMNDecompressor::HFMNDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) : + XPKDecompressor(recursionLevel), + _packedData(packedData) +{ + if (!detectHeaderXPK(hdr) || packedData.size()<4) + throw Decompressor::InvalidFormatError(); + uint16_t tmp=packedData.readBE16(0); + if (tmp&3U) throw Decompressor::InvalidFormatError(); // header is being written in 4 byte chunks + _headerSize=tmp&0x1ffU; // the top 7 bits are flags. No definition what they are and they are ignored in decoder... + if (OverflowCheck::sum(_headerSize,4U)>packedData.size()) throw Decompressor::InvalidFormatError(); + _rawSize=packedData.readBE16(_headerSize+2U); + if (!_rawSize) throw Decompressor::InvalidFormatError(); + _headerSize+=4; +} + +HFMNDecompressor::~HFMNDecompressor() +{ + // nothing needed +} + +const std::string &HFMNDecompressor::getSubName() const noexcept +{ + static std::string name="XPK-HFMN: Huffman compressor"; + return name; +} + +void HFMNDecompressor::decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) +{ + if (rawData.size()!=_rawSize) throw Decompressor::DecompressionError(); + ForwardInputStream inputStream(_packedData,2,_headerSize); + MSBBitReader bitReader(inputStream); + auto readBit=[&]()->uint32_t + { + return bitReader.readBits8(1); + }; + + ForwardOutputStream outputStream(rawData,0,rawData.size()); + + HuffmanDecoder decoder; + uint32_t code=1; + uint32_t codeBits=1; + for (;;) + { + if (!readBit()) + { + uint32_t lit=0; + for (uint32_t i=0;i<8;i++) lit|=readBit()<{codeBits,code,lit}); + while (!(code&1) && codeBits) + { + codeBits--; + code>>=1; + } + if (!codeBits) break; + code--; + } else { + code=(code<<1)+1; + codeBits++; + } + } + inputStream=ForwardInputStream(_packedData,_headerSize,_packedData.size()); + bitReader.reset(); + + while (!outputStream.eof()) + outputStream.writeByte(decoder.decode(readBit)); +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/HFMNDecompressor.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/HFMNDecompressor.hpp new file mode 100644 index 00000000..76f1b4ba --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/HFMNDecompressor.hpp @@ -0,0 +1,34 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef HFMNDECOMPRESSOR_HPP +#define HFMNDECOMPRESSOR_HPP + +#include "XPKDecompressor.hpp" + +namespace ancient::internal +{ + +class HFMNDecompressor : public XPKDecompressor +{ +public: + HFMNDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + + virtual ~HFMNDecompressor(); + + virtual const std::string &getSubName() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) override final; + + static bool detectHeaderXPK(uint32_t hdr) noexcept; + static std::shared_ptr create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + +private: + const Buffer &_packedData; + + size_t _headerSize; + size_t _rawSize; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/HUFFDecompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/HUFFDecompressor.cpp new file mode 100644 index 00000000..6daa632b --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/HUFFDecompressor.cpp @@ -0,0 +1,84 @@ +/* Copyright (C) Teemu Suutari */ + +#include "HUFFDecompressor.hpp" +#include "HuffmanDecoder.hpp" +#include "InputStream.hpp" +#include "OutputStream.hpp" +#include "common/Common.hpp" + + +namespace ancient::internal +{ + +bool HUFFDecompressor::detectHeaderXPK(uint32_t hdr) noexcept +{ + return hdr==FourCC("HUFF"); +} + +std::shared_ptr HUFFDecompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) +{ + return std::make_shared(hdr,recursionLevel,packedData,state,verify); +} + +HUFFDecompressor::HUFFDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) : + XPKDecompressor(recursionLevel), + _packedData(packedData) +{ + if (!detectHeaderXPK(hdr) || packedData.size()<6) + throw Decompressor::InvalidFormatError(); + // version: only 0 is defined + uint16_t ver=packedData.readBE16(0); + if (ver) throw Decompressor::InvalidFormatError(); + // password: we do not support it... + uint32_t pwd=packedData.readBE32(2); + if (pwd!=0xabadcafe) throw Decompressor::InvalidFormatError(); +} + +HUFFDecompressor::~HUFFDecompressor() +{ + // nothing needed +} + +const std::string &HUFFDecompressor::getSubName() const noexcept +{ + static std::string name="XPK-HUFF: Huffman compressor"; + return name; +} + +void HUFFDecompressor::decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) +{ + ForwardInputStream inputStream(_packedData,6,_packedData.size()); + MSBBitReader bitReader(inputStream); + auto readBit=[&]()->uint32_t + { + return bitReader.readBits8(1); + }; + auto readByte=[&]()->uint8_t + { + return inputStream.readByte(); + }; + + ForwardOutputStream outputStream(rawData,0,rawData.size()); + + HuffmanDecoder decoder; + for (uint32_t i=0;i<256;i++) + { + uint8_t codeBits=readByte()+1; + if (!codeBits) continue; + if (codeBits>32) throw Decompressor::DecompressionError(); + uint32_t code=0; + int32_t shift=-codeBits; + for (uint32_t j=0;j>shift)&((1<{codeBits,code,i}); + } + + while (!outputStream.eof()) + outputStream.writeByte(decoder.decode(readBit)); +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/HUFFDecompressor.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/HUFFDecompressor.hpp new file mode 100644 index 00000000..fba47bd6 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/HUFFDecompressor.hpp @@ -0,0 +1,31 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef HUFFDECOMPRESSOR_HPP +#define HUFFDECOMPRESSOR_HPP + +#include "XPKDecompressor.hpp" + +namespace ancient::internal +{ + +class HUFFDecompressor : public XPKDecompressor +{ +public: + HUFFDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + + virtual ~HUFFDecompressor(); + + virtual const std::string &getSubName() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) override final; + + static bool detectHeaderXPK(uint32_t hdr) noexcept; + static std::shared_ptr create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + +private: + const Buffer &_packedData; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/HuffmanDecoder.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/HuffmanDecoder.hpp new file mode 100644 index 00000000..e47649ba --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/HuffmanDecoder.hpp @@ -0,0 +1,228 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef HUFFMANDECODER_HPP +#define HUFFMANDECODER_HPP + +#include +#include + +#include +#include + +// For exception +#include "Decompressor.hpp" + +#include "common/MemoryBuffer.hpp" + +namespace ancient::internal +{ + +template +struct HuffmanCode +{ + uint32_t length; + uint32_t code; + + T value; +}; + +template class OptionalHuffmanDecoder; + +template +class HuffmanDecoder +{ +friend class OptionalHuffmanDecoder; +private: + struct Node + { + uint32_t sub[2]; + T value; + + Node(uint32_t _sub0,uint32_t _sub1,T _value) : + sub{_sub0,_sub1}, + value(_value) + { + // nothing needed + } + + Node(Node &&source) : + sub{source.sub[0],source.sub[1]}, + value(source.value) + { + // nothing needed + } + + Node& operator=(Node &&source) + { + if (this!=&source) + { + sub[0]=source.sub[0]; + sub[1]=source.sub[1]; + value=source.value; + } + return *this; + } + }; + +public: + HuffmanDecoder() + { + // nothing needed + } + + template + HuffmanDecoder(const Args&& ...args) : + HuffmanDecoder() + { + const HuffmanCode list[sizeof...(args)]={args...}; + for (auto &item : list) + insert(item); + } + + ~HuffmanDecoder() + { + } + + void reset() + { + _table.clear(); + } + + template + const T &decode(F bitReader) const + { + if (!_table.size()) throw Decompressor::DecompressionError(); + uint32_t i=0; + while (_table[i].sub[0] || _table[i].sub[1]) + { + i=_table[i].sub[bitReader()?1:0]; + if (!i) throw Decompressor::DecompressionError(); + } + return _table[i].value; + } + + void insert(const HuffmanCode &code) + { + uint32_t i=0,length=uint32_t(_table.size()); + for (int32_t currentBit=code.length;currentBit>=0;currentBit--) + { + uint32_t codeBit=(currentBit && ((code.code>>(currentBit-1U))&1U))?1U:0; + if (i!=length) + { + if (!currentBit || (!_table[i].sub[0] && !_table[i].sub[1])) throw Decompressor::DecompressionError(); + uint32_t &tmp=_table[i].sub[codeBit]; + if (!tmp) tmp=i=length; + else i=tmp; + } else { + _table.emplace_back((currentBit&&!codeBit)?length+1:0,(currentBit&&codeBit)?length+1:0,currentBit?T():code.value); + length++; + i++; + } + } + } + + // create orderly Huffman table, as used by Deflate and Bzip2 + void createOrderlyHuffmanTable(const uint8_t *bitLengths,uint32_t bitTableLength) + { + uint8_t minDepth=32,maxDepth=0; + // some optimization: more tables + uint16_t firstIndex[33],lastIndex[33]; + MemoryBuffer nextIndexBuffer(bitTableLength*sizeof(uint16_t)); + uint16_t *nextIndex=nextIndexBuffer.cast(); + for (uint32_t i=1;i<33;i++) + firstIndex[i]=0xffffU; + + uint32_t realItems=0; + for (uint32_t i=0;i32) throw Decompressor::DecompressionError(); + if (length) + { + if (lengthmaxDepth) maxDepth=length; + if (firstIndex[length]==0xffffU) + { + firstIndex[length]=i; + lastIndex[length]=i; + } else { + nextIndex[lastIndex[length]]=i; + lastIndex[length]=i; + } + realItems++; + } + } + if (!maxDepth) throw Decompressor::DecompressionError(); + // optimization, the multiple depends how sparse the tree really is. (minimum is *2) + // usually it is sparse. + _table.reserve(realItems*3); + + uint32_t code=0; + for (uint32_t depth=minDepth;depth<=maxDepth;depth++) + { + if (firstIndex[depth]!=0xffffU) + nextIndex[lastIndex[depth]]=bitTableLength; + + for (uint32_t i=firstIndex[depth];i{depth,code>>(maxDepth-depth),(T)i}); + code+=1<<(maxDepth-depth); + } + } + } + +private: + std::vector _table; +}; + +template +class OptionalHuffmanDecoder +{ +public: + OptionalHuffmanDecoder() : + _base() + { + // nothing needed + } + + ~OptionalHuffmanDecoder() + { + // nothing needed + } + + void reset() + { + _base.reset(); + } + + void setEmpty(T value) + { + reset(); + _emptyValue=value; + } + + template + T decode(F bitReader) const + { + if (!_base._table.size()) return _emptyValue; + else return _base.decode(bitReader); + } + + void insert(const HuffmanCode &code) + { + _base.insert(code); + } + + void createOrderlyHuffmanTable(const uint8_t *bitLengths,uint32_t bitTableLength) + { + _base.createOrderlyHuffmanTable(bitLengths,bitTableLength); + } + +private: + HuffmanDecoder _base; + T _emptyValue=0; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/ILZRDecompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/ILZRDecompressor.cpp new file mode 100644 index 00000000..b6fb93ed --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/ILZRDecompressor.cpp @@ -0,0 +1,73 @@ +/* Copyright (C) Teemu Suutari */ + +#include "ILZRDecompressor.hpp" +#include "InputStream.hpp" +#include "OutputStream.hpp" +#include "common/Common.hpp" + + +namespace ancient::internal +{ + +bool ILZRDecompressor::detectHeaderXPK(uint32_t hdr) noexcept +{ + return hdr==FourCC("ILZR"); +} + +std::shared_ptr ILZRDecompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) +{ + return std::make_shared(hdr,recursionLevel,packedData,state,verify); +} + +ILZRDecompressor::ILZRDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) : + XPKDecompressor(recursionLevel), + _packedData(packedData) +{ + if (!detectHeaderXPK(hdr) || packedData.size()<2) + throw Decompressor::InvalidFormatError(); + _rawSize=_packedData.readBE16(0); + if (!_rawSize) throw Decompressor::InvalidFormatError(); +} + +ILZRDecompressor::~ILZRDecompressor() +{ + // nothing needed +} + +const std::string &ILZRDecompressor::getSubName() const noexcept +{ + static std::string name="XPK-ILZR: Incremental Lempel-Ziv-Renau compressor"; + return name; +} + +void ILZRDecompressor::decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) +{ + if (rawData.size()!=_rawSize) throw Decompressor::DecompressionError(); + + ForwardInputStream inputStream(_packedData,2,_packedData.size()); + MSBBitReader bitReader(inputStream); + auto readBits=[&](uint32_t count)->uint32_t + { + return bitReader.readBits8(count); + }; + + ForwardOutputStream outputStream(rawData,0,rawData.size()); + + uint32_t bits=8; + while (!outputStream.eof()) + { + if (readBits(1)) + { + outputStream.writeByte(readBits(8)); + } else { + while (outputStream.getOffset()>(1ULL<=outputStream.getOffset()) throw Decompressor::DecompressionError(); + outputStream.copy(outputStream.getOffset()-position,count); + } + } +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/ILZRDecompressor.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/ILZRDecompressor.hpp new file mode 100644 index 00000000..2dbdf042 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/ILZRDecompressor.hpp @@ -0,0 +1,33 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef ILZRDECOMPRESSOR_HPP +#define ILZRDECOMPRESSOR_HPP + +#include "XPKDecompressor.hpp" + +namespace ancient::internal +{ + +class ILZRDecompressor : public XPKDecompressor +{ +public: + ILZRDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + + virtual ~ILZRDecompressor(); + + virtual const std::string &getSubName() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) override final; + + static bool detectHeaderXPK(uint32_t hdr) noexcept; + static std::shared_ptr create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + +private: + const Buffer &_packedData; + + size_t _rawSize=0; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/IMPDecompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/IMPDecompressor.cpp new file mode 100644 index 00000000..991f1d36 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/IMPDecompressor.cpp @@ -0,0 +1,294 @@ +/* Copyright (C) Teemu Suutari */ + +#include "IMPDecompressor.hpp" +#include "HuffmanDecoder.hpp" +#include "InputStream.hpp" +#include "OutputStream.hpp" +#include "common/Common.hpp" +#include "common/OverflowCheck.hpp" + + +namespace ancient::internal +{ + +static bool readIMPHeader(uint32_t hdr,uint32_t &addition) noexcept +{ + switch (hdr) + { + case FourCC("ATN!"): + case FourCC("EDAM"): + case FourCC("IMP!"): + case FourCC("M.H."): + addition=7; + return true; + + case FourCC("BDPI"): + addition=0x6e8; + return true; + + case FourCC("CHFI"): + addition=0xfe4; + return true; + + case FourCC("RDC9"): // Files do not contain checksum + + // I haven't got these files to be sure what is the addition + case FourCC("Dupa"): + case FourCC("FLT!"): + case FourCC("PARA"): + addition=0; // disable checksum for now + return true; + + default: + return false; + } +} + +bool IMPDecompressor::detectHeader(uint32_t hdr) noexcept +{ + uint32_t dummy; + return readIMPHeader(hdr,dummy); +} + +bool IMPDecompressor::detectHeaderXPK(uint32_t hdr) noexcept +{ + return hdr==FourCC("IMPL"); +} + +std::shared_ptr IMPDecompressor::create(const Buffer &packedData,bool exactSizeKnown,bool verify) +{ + return std::make_shared(packedData,verify); +} + +std::shared_ptr IMPDecompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) +{ + return std::make_shared(hdr,recursionLevel,packedData,state,verify); +} + +IMPDecompressor::IMPDecompressor(const Buffer &packedData,bool verify) : + _packedData(packedData) +{ + uint32_t hdr=packedData.readBE32(0); + uint32_t checksumAddition; + if (!readIMPHeader(hdr,checksumAddition) || packedData.size()<0x32) throw InvalidFormatError(); + + _rawSize=packedData.readBE32(4); + _endOffset=packedData.readBE32(8); + if ((_endOffset&1) || _endOffset<0xc || _endOffset+0x32>packedData.size() || + !_rawSize || !_endOffset || + _rawSize>getMaxRawSize() || _endOffset>getMaxPackedSize()) throw InvalidFormatError(); + uint32_t checksum=packedData.readBE32(_endOffset+0x2e); + if (verify && checksumAddition) + { + // size is divisible by 2 + uint32_t sum=checksumAddition; + for (uint32_t i=0;i<_endOffset+0x2e;i+=2) + { + // TODO: slow, optimize + uint16_t tmp=_packedData.readBE16(i); + sum+=uint32_t(tmp); + } + if (checksum!=sum) throw InvalidFormatError(); + } +} + +IMPDecompressor::IMPDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) : + XPKDecompressor(recursionLevel), + _packedData(packedData) +{ + if (!detectHeaderXPK(hdr) || packedData.size()<0x2e) throw InvalidFormatError(); + + _rawSize=packedData.readBE32(4); + _endOffset=packedData.readBE32(8); + if ((_endOffset&1) || _endOffset<0xc || OverflowCheck::sum(_endOffset,0x2eU)>packedData.size()) throw InvalidFormatError(); + _isXPK=true; +} + +IMPDecompressor::~IMPDecompressor() +{ + // nothing needed +} + +const std::string &IMPDecompressor::getName() const noexcept +{ + static std::string name="IMP: File Imploder"; + return name; +} + +const std::string &IMPDecompressor::getSubName() const noexcept +{ + static std::string name="XPK-IMPL: File Imploder"; + return name; +} + +size_t IMPDecompressor::getPackedSize() const noexcept +{ + return _endOffset+0x32; +} + +size_t IMPDecompressor::getRawSize() const noexcept +{ + return _rawSize; +} + +void IMPDecompressor::decompressImpl(Buffer &rawData,bool verify) +{ + if (rawData.size()<_rawSize) throw DecompressionError(); + + class IMPInputStream + { + public: + IMPInputStream(const Buffer &buffer,size_t startOffset,size_t endOffset) : + _bufPtr(buffer.data()), + _currentOffset(endOffset), + _endOffset(startOffset), + _refOffset(endOffset) + { + if (_currentOffset<_endOffset || _currentOffset>buffer.size() || _endOffset>buffer.size()) throw Decompressor::DecompressionError(); + uint8_t markerByte=buffer.read8(_currentOffset+16); + if (!(markerByte&0x80)) + { + if (_currentOffset==_endOffset) throw Decompressor::DecompressionError(); + _currentOffset--; + } + } + + ~IMPInputStream() + { + // nothing needed + } + + uint8_t readByte() + { + // streamreader with funny ordering + auto sourceOffset=[&](size_t i)->size_t + { + if (i>=12) + { + return i; + } else { + if (i<4) + { + return i+_refOffset+8; + } else if (i<8) { + return i+_refOffset; + } else { + return i+_refOffset-8; + } + } + }; + if (_currentOffset<=_endOffset) throw Decompressor::DecompressionError(); + return _bufPtr[sourceOffset(--_currentOffset)]; + } + + bool eof() const { return _currentOffset==_endOffset; } + + private: + const uint8_t *_bufPtr; + size_t _currentOffset; + size_t _endOffset; + size_t _refOffset; + }; + + IMPInputStream inputStream(_packedData,0,_endOffset); + MSBBitReader bitReader(inputStream); + auto readBits=[&](uint32_t count)->uint32_t + { + return bitReader.readBits8(count); + }; + auto readBit=[&]()->uint32_t + { + return bitReader.readBits8(1); + }; + auto readByte=[&]()->uint8_t + { + return inputStream.readByte(); + }; + // the anchor-bit does not seem always to be at the correct place + { + uint8_t halfByte=_packedData.read8(_endOffset+17); + for (uint32_t i=0;i<7;i++) + if (halfByte&(1<>(i+1),7-i); + break; + } + } + + BackwardOutputStream outputStream(rawData,0,_rawSize); + + // tables + uint16_t distanceValues[2][4]; + for (uint32_t i=0;i<8;i++) + distanceValues[i>>2][i&3]=_packedData.readBE16(_endOffset+18+i*2); + uint8_t distanceBits[3][4]; + for (uint32_t i=0;i<12;i++) + distanceBits[i>>2][i&3]=_packedData.read8(_endOffset+34+i); + + // length, distance & literal counts are all intertwined + HuffmanDecoder lldDecoder + { + HuffmanCode{1,0b00000,0}, + HuffmanCode{2,0b00010,1}, + HuffmanCode{3,0b00110,2}, + HuffmanCode{4,0b01110,3}, + HuffmanCode{5,0b11110,4}, + HuffmanCode{5,0b11111,5} + }; + + HuffmanDecoder lldDecoder2 + { + HuffmanCode{1,0b00,0}, + HuffmanCode{2,0b10,1}, + HuffmanCode{2,0b11,2} + }; + + // finally loop + uint32_t litLength=_packedData.readBE32(_endOffset+12); + + for (;;) + { + for (uint32_t i=0;i &state,bool verify); + virtual ~IMPDecompressor(); + + virtual const std::string &getName() const noexcept override final; + virtual const std::string &getSubName() const noexcept override final; + + virtual size_t getPackedSize() const noexcept override final; + virtual size_t getRawSize() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,bool verify) override final; + virtual void decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) override final; + + static bool detectHeader(uint32_t hdr) noexcept; + static bool detectHeaderXPK(uint32_t hdr) noexcept; + + static std::shared_ptr create(const Buffer &packedData,bool exactSizeKnown,bool verify); + static std::shared_ptr create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + +private: + const Buffer &_packedData; + + uint32_t _rawSize=0; + uint32_t _endOffset=0; + bool _isXPK=false; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/InputStream.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/InputStream.cpp new file mode 100644 index 00000000..42657197 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/InputStream.cpp @@ -0,0 +1,113 @@ +/* Copyright (C) Teemu Suutari */ + +#include "InputStream.hpp" +// for exceptions +#include "Decompressor.hpp" +#include "common/OverflowCheck.hpp" + + +namespace ancient::internal +{ + +ForwardInputStream::ForwardInputStream(const Buffer &buffer,size_t startOffset,size_t endOffset,bool allowOverrun) : + _bufPtr(buffer.data()), + _currentOffset(startOffset), + _endOffset(endOffset), + _allowOverrun(allowOverrun) +{ + if (_currentOffset>_endOffset || _currentOffset>buffer.size() || _endOffset>buffer.size()) throw Decompressor::DecompressionError(); +} + +ForwardInputStream::~ForwardInputStream() +{ + // nothing needed +} + +uint8_t ForwardInputStream::readByte() +{ + if (_currentOffset>=_endOffset) + { + if (_allowOverrun) + { + _currentOffset++; + return 0; + } + throw Decompressor::DecompressionError(); + } + uint8_t ret=_bufPtr[_currentOffset++]; + if (_linkedInputStream) _linkedInputStream->setOffset(_currentOffset); + return ret; +} + +const uint8_t *ForwardInputStream::consume(size_t bytes,uint8_t *buffer) +{ + if (OverflowCheck::sum(_currentOffset,bytes)>_endOffset) + { + if (_allowOverrun && buffer) + { + for (size_t i=0;isetOffset(_currentOffset); + return ret; +} + +BackwardInputStream::BackwardInputStream(const Buffer &buffer,size_t startOffset,size_t endOffset,bool allowOverrun) : + _bufPtr(buffer.data()), + _currentOffset(endOffset), + _endOffset(startOffset), + _allowOverrun(allowOverrun) +{ + if (_currentOffset<_endOffset || _currentOffset>buffer.size() || _endOffset>buffer.size()) throw Decompressor::DecompressionError(); +} + +BackwardInputStream::~BackwardInputStream() +{ + // nothing needed +} + +uint8_t BackwardInputStream::readByte() +{ + if (_currentOffset<=_endOffset) + { + if (_allowOverrun) + { + --_currentOffset; + return 0; + } + throw Decompressor::DecompressionError(); + } + uint8_t ret=_bufPtr[--_currentOffset]; + if (_linkedInputStream) _linkedInputStream->setOffset(_currentOffset); + return ret; +} + +const uint8_t *BackwardInputStream::consume(size_t bytes,uint8_t *buffer) +{ + if (_currentOffset_endOffset)?_bufPtr[_currentOffset-1]:0; + --_currentOffset; + } + return buffer; + } + throw Decompressor::DecompressionError(); + } + _currentOffset-=bytes; + if (_linkedInputStream) _linkedInputStream->setOffset(_currentOffset); + return &_bufPtr[_currentOffset]; +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/InputStream.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/InputStream.hpp new file mode 100644 index 00000000..21019be9 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/InputStream.hpp @@ -0,0 +1,236 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef INPUTSTREAM_HPP +#define INPUTSTREAM_HPP + +#include +#include + +#include + +#include "common/Buffer.hpp" + +namespace ancient::internal +{ + +class BackwardInputStream; + +class ForwardInputStream +{ + friend class BackwardInputStream; + +public: + ForwardInputStream(const Buffer &buffer,size_t startOffset,size_t endOffset,bool allowOverrun=false); + ~ForwardInputStream(); + + uint8_t readByte(); + const uint8_t *consume(size_t bytes,uint8_t *buffer=nullptr); + + bool eof() const { return _currentOffset==_endOffset; } + size_t getOffset() const { return _currentOffset; } + size_t getEndOffset() const { return _endOffset; } + void link(BackwardInputStream &stream) { _linkedInputStream=&stream; } + +private: + void setOffset(size_t offset) { _endOffset=offset; } + + const uint8_t *_bufPtr; + size_t _currentOffset; + size_t _endOffset; + bool _allowOverrun; + + BackwardInputStream *_linkedInputStream=nullptr; +}; + + +class BackwardInputStream +{ + friend class ForwardInputStream; +public: + BackwardInputStream(const Buffer &buffer,size_t startOffset,size_t endOffset,bool allowOverrun=false); + ~BackwardInputStream(); + + uint8_t readByte(); + const uint8_t *consume(size_t bytes,uint8_t *buffer=nullptr); + + bool eof() const { return _currentOffset==_endOffset; } + size_t getOffset() const { return _currentOffset; } + void link(ForwardInputStream &stream) { _linkedInputStream=&stream; } + +private: + void setOffset(size_t offset) { _endOffset=offset; } + + const uint8_t *_bufPtr; + size_t _currentOffset; + size_t _endOffset; + bool _allowOverrun; + + ForwardInputStream *_linkedInputStream=nullptr; +}; + + +template +class LSBBitReader +{ +public: + LSBBitReader(T &inputStream) : + _inputStream(inputStream) + { + // nothing needed + } + + ~LSBBitReader() + { + // nothing needed + } + + uint32_t readBits8(uint32_t count) + { + return readBitsInternal(count,[&](){ + _bufContent=_inputStream.readByte(); + _bufLength=8; + }); + } + + uint32_t readBitsBE16(uint32_t count) + { + return readBitsInternal(count,[&](){ + uint8_t tmp[2]; + const uint8_t *buf=_inputStream.consume(2,tmp); + _bufContent=(uint32_t(buf[0])<<8)|uint32_t(buf[1]); + _bufLength=16; + }); + } + + uint32_t readBitsBE32(uint32_t count) + { + return readBitsInternal(count,[&](){ + uint8_t tmp[4]; + const uint8_t *buf=_inputStream.consume(4,tmp); + _bufContent=(uint32_t(buf[0])<<24)|(uint32_t(buf[1])<<16)| + (uint32_t(buf[2])<<8)|uint32_t(buf[3]); + _bufLength=32; + }); + } + + // RNC + uint32_t readBits16Limit(uint32_t count) + { + return readBitsInternal(count,[&](){ + _bufContent=_inputStream.readByte(); + if (_inputStream.eof()) + { + _bufLength=8; + } else { + _bufContent=_bufContent|(uint32_t(_inputStream.readByte())<<8); + _bufLength=16; + } + }); + } + + void reset(uint32_t bufContent=0,uint8_t bufLength=0) + { + _bufContent=bufContent; + _bufLength=bufLength; + } + +private: + template + uint32_t readBitsInternal(uint32_t count,F readWord) + { + uint32_t ret=0,pos=0; + while (count) + { + if (!_bufLength) + readWord(); + uint8_t maxCount=std::min(uint8_t(count),_bufLength); + ret|=(_bufContent&((1<>=maxCount; + _bufLength-=maxCount; + count-=maxCount; + pos+=maxCount; + } + return ret; + } + + T &_inputStream; + uint32_t _bufContent=0; + uint8_t _bufLength=0; +}; + + +template +class MSBBitReader +{ +public: + MSBBitReader(T &inputStream) : + _inputStream(inputStream) + { + // nothing needed + } + + ~MSBBitReader() + { + // nothing needed + } + + uint32_t readBits8(uint32_t count) + { + return readBitsInternal(count,[&](){ + _bufContent=_inputStream.readByte(); + _bufLength=8; + }); + } + + uint32_t readBitsBE16(uint32_t count) + { + return readBitsInternal(count,[&](){ + uint8_t tmp[2]; + const uint8_t *buf=_inputStream.consume(2,tmp); + _bufContent=(uint32_t(buf[0])<<8)|uint32_t(buf[1]); + _bufLength=16; + }); + } + + uint32_t readBitsBE32(uint32_t count) + { + return readBitsInternal(count,[&](){ + uint8_t tmp[4]; + const uint8_t *buf=_inputStream.consume(4,tmp); + _bufContent=(uint32_t(buf[0])<<24)|(uint32_t(buf[1])<<16)| + (uint32_t(buf[2])<<8)|uint32_t(buf[3]); + _bufLength=32; + }); + } + + void reset(uint32_t bufContent=0,uint8_t bufLength=0) + { + _bufContent=bufContent; + _bufLength=bufLength; + } + +private: + template + uint32_t readBitsInternal(uint32_t count,F readWord) + { + uint32_t ret=0; + while (count) + { + if (!_bufLength) + readWord(); + uint8_t maxCount=std::min(uint8_t(count),_bufLength); + _bufLength-=maxCount; + ret=(ret<>_bufLength)&((1< LHLBDecompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) +{ + return std::make_shared(hdr,recursionLevel,packedData,state,verify); +} + +LHLBDecompressor::LHLBDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) : + XPKDecompressor(recursionLevel), + _packedData(packedData) +{ + if (!detectHeaderXPK(hdr)) throw Decompressor::InvalidFormatError(); +} + +LHLBDecompressor::~LHLBDecompressor() +{ + // nothing needed +} + +const std::string &LHLBDecompressor::getSubName() const noexcept +{ + static std::string name="XPK-LHLB: LZRW-compressor"; + return name; +} + +void LHLBDecompressor::decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) +{ + ForwardInputStream inputStream(_packedData,0,_packedData.size()); + MSBBitReader bitReader(inputStream); + auto readBits=[&](uint32_t count)->uint32_t + { + return bitReader.readBits8(count); + }; + auto readBit=[&]()->uint32_t + { + return bitReader.readBits8(1); + }; + + ForwardOutputStream outputStream(rawData,0,rawData.size()); + + // Same logic as in Choloks pascal implementation + // Differences to LH1: + // - LHLB does not halve probabilities at 32k + // - 314 vs. 317 sized huffman entry + // - no end code + // - different distance/count logic + + DynamicHuffmanDecoder<317> decoder; + + while (!outputStream.eof()) + { + uint32_t code=decoder.decode(readBit); + if (code==316) break; + if (decoder.getMaxFrequency()<0x8000U) decoder.update(code); + + if (code<256) + { + outputStream.writeByte(code); + } else { + static const uint8_t distanceHighBits[256]={ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, + 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, + + 10,10,10,10,10,10,10,10, 11,11,11,11,11,11,11,11, + 12,12,12,12,13,13,13,13, 14,14,14,14,15,15,15,15, + 16,16,16,16,17,17,17,17, 18,18,18,18,19,19,19,19, + 20,20,20,20,21,21,21,21, 22,22,22,22,23,23,23,23, + 24,24,25,25,26,26,27,27, 28,28,29,29,30,30,31,31, + 32,32,33,33,34,34,35,35, 36,36,37,37,38,38,39,39, + 40,40,41,41,42,42,43,43, 44,44,45,45,46,46,47,47, + 48,49,50,51,52,53,54,55, 56,57,58,59,60,61,62,63}; + static const uint8_t distanceBits[16]={1,1,2,2,2,3,3,3,3,4,4,4,5,5,5,6}; + + uint32_t tmp=readBits(8); + uint32_t distance=uint32_t(distanceHighBits[tmp])<<6; + uint32_t bits=distanceBits[tmp>>4]; + tmp=(tmp< &state,bool verify); + + virtual ~LHLBDecompressor(); + + virtual const std::string &getSubName() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) override final; + + static bool detectHeaderXPK(uint32_t hdr) noexcept; + static std::shared_ptr create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + +private: + const Buffer &_packedData; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/LIN1Decompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/LIN1Decompressor.cpp new file mode 100644 index 00000000..b2f8cd54 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/LIN1Decompressor.cpp @@ -0,0 +1,123 @@ +/* Copyright (C) Teemu Suutari */ + +#include "LIN1Decompressor.hpp" + +#include "InputStream.hpp" +#include "OutputStream.hpp" +#include "common/Common.hpp" + + +namespace ancient::internal +{ + +bool LIN1Decompressor::detectHeaderXPK(uint32_t hdr) noexcept +{ + return hdr==FourCC("LIN1") || hdr==FourCC("LIN3"); +} + +std::shared_ptr LIN1Decompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) +{ + return std::make_shared(hdr,recursionLevel,packedData,state,verify); +} + +LIN1Decompressor::LIN1Decompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) : + XPKDecompressor(recursionLevel), + _packedData(packedData) +{ + if (!detectHeaderXPK(hdr)) throw Decompressor::InvalidFormatError(); + _ver=(hdr==FourCC("LIN1"))?1:3; + if (packedData.size()<5) throw Decompressor::InvalidFormatError(); + + uint32_t tmp=packedData.readBE32(0); + if (tmp) throw Decompressor::InvalidFormatError(); // password set +} + +LIN1Decompressor::~LIN1Decompressor() +{ + // nothing needed +} + +const std::string &LIN1Decompressor::getSubName() const noexcept +{ + static std::string name1="XPK-LIN1: LIN1 LINO packer"; + static std::string name3="XPK-LIN3: LIN3 LINO packer"; + return (_ver==1)?name1:name3; +} + +void LIN1Decompressor::decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) +{ + ForwardInputStream inputStream(_packedData,5,_packedData.size()); + MSBBitReader bitReader(inputStream); + auto readBits=[&](uint32_t count)->uint32_t + { + return bitReader.readBits8(count); + }; + auto readByte=[&]()->uint8_t + { + return inputStream.readByte(); + }; + + size_t rawSize=rawData.size(); + ForwardOutputStream outputStream(rawData,0,rawSize); + + while (!outputStream.eof()) + { + if (!readBits(1)) + { + outputStream.writeByte(readByte()^0x55); + } else { + uint32_t count=3; + if (readBits(1)) + { + count=readBits(2); + if (count==3) + { + count=readBits(3); + if (count==7) + { + count=readBits(4); + if (count==15) + { + count=readByte(); + if (count==0xff) throw Decompressor::DecompressionError(); + count+=3; + } else count+=14; + } else count+=7; + } else count+=4; + } + uint32_t distance = 0; + switch (readBits(2)) + { + case 0: + distance=readByte()+1; + break; + + case 1: + distance=uint32_t(readBits(2))<<8; + distance|=readByte(); + distance+=0x101; + break; + + case 2: + distance=uint32_t(readBits(4))<<8; + distance|=readByte(); + distance+=0x501; + break; + + case 3: + distance=uint32_t(readBits(6))<<8; + distance|=readByte(); + distance+=0x1501; + break; + } + + // buggy compressors + count=std::min(count,uint32_t(rawSize-outputStream.getOffset())); + if (!count) throw Decompressor::DecompressionError(); + + outputStream.copy(distance,count); + } + } +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/LIN1Decompressor.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/LIN1Decompressor.hpp new file mode 100644 index 00000000..ed1967f8 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/LIN1Decompressor.hpp @@ -0,0 +1,33 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef LIN1DECOMPRESSOR_HPP +#define LIN1DECOMPRESSOR_HPP + +#include "XPKDecompressor.hpp" + +namespace ancient::internal +{ + +class LIN1Decompressor : public XPKDecompressor +{ +public: + LIN1Decompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + + virtual ~LIN1Decompressor(); + + virtual const std::string &getSubName() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) override final; + + static bool detectHeaderXPK(uint32_t hdr) noexcept; + static std::shared_ptr create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + +private: + const Buffer &_packedData; + + uint32_t _ver=0; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/LIN2Decompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/LIN2Decompressor.cpp new file mode 100644 index 00000000..d69b65bf --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/LIN2Decompressor.cpp @@ -0,0 +1,224 @@ +/* Copyright (C) Teemu Suutari */ + +#include "LIN2Decompressor.hpp" +#include "HuffmanDecoder.hpp" +#include "InputStream.hpp" +#include "OutputStream.hpp" +#include "common/Common.hpp" +#include "common/OverflowCheck.hpp" + + +namespace ancient::internal +{ + +bool LIN2Decompressor::detectHeaderXPK(uint32_t hdr) noexcept +{ + return hdr==FourCC("LIN2") || hdr==FourCC("LIN4"); +} + +std::shared_ptr LIN2Decompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) +{ + return std::make_shared(hdr,recursionLevel,packedData,state,verify); +} + +LIN2Decompressor::LIN2Decompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) : + XPKDecompressor(recursionLevel), + _packedData(packedData) +{ + if (!detectHeaderXPK(hdr)) throw Decompressor::InvalidFormatError(); + _ver=(hdr==FourCC("LIN2"))?2:4; + if (packedData.size()<10) throw Decompressor::InvalidFormatError(); + + uint32_t tmp=packedData.readBE32(0); + if (tmp) throw Decompressor::InvalidFormatError(); // password set + + // LIN4 is very similar to LIN2 - it only has 5 bit literals instead of 4 bit literals + // (and thus larger table at the end of the stream) + // Also, the huffman decoder for length is different + + _endStreamOffset=packedData.size()-1; + const uint8_t *bufPtr=_packedData.data(); + while (_endStreamOffset && bufPtr[--_endStreamOffset]!=0xffU); + // end stream + // 1 byte, byte before 0xff + // 0x10 bytes/0x20 for table + if (_endStreamOffset<0x11+0xa) throw Decompressor::InvalidFormatError(); + _endStreamOffset-=(_ver==2)?0x11:0x21; + + size_t midStreamOffset=(_ver==2)?0x16:0x26; + // midstream + // from endstream without + // add 0x10/0x20 byte back to point after table + // add 6 bytes to point to correct place + + tmp=packedData.readBE32(4); + if (OverflowCheck::sum(_endStreamOffset,midStreamOffset) bitsReader(forwardInputStream); + MSBBitReader bitReader(middleInputStream); + auto readBits=[&](uint32_t count)->uint32_t + { + return bitsReader.readBits8(count); + }; + + { + uint8_t tmp=middleInputStream.readByte(); + if (tmp>8) throw Decompressor::DecompressionError(); + bitReader.reset(middleInputStream.readByte()>>tmp,8-tmp); + } + auto readBit=[&]()->uint8_t + { + return bitReader.readBits8(1); + }; + + bool buf4Incomplete=false; + uint8_t nibbleContent=0; + { + uint8_t tmp=_packedData.read8(9); + buf4Incomplete=!!tmp; + if (buf4Incomplete) + nibbleContent=backwardInputStream.readByte(); + } + // this is a rather strange thing... + auto read4Bits=[&](bool fullByte)->uint8_t + { + if (!fullByte) + { + buf4Incomplete=!buf4Incomplete; + if (!buf4Incomplete) + { + return nibbleContent&0xf; + } else { + nibbleContent=backwardInputStream.readByte(); + return nibbleContent>>4; + } + } else { + if (buf4Incomplete) + { + uint8_t ret=nibbleContent&0xf; + nibbleContent=backwardInputStream.readByte(); + ret|=nibbleContent&0xf0U; + return ret; + } else { + return backwardInputStream.readByte(); + } + } + }; + + const uint8_t *literalTable=&_packedData[_endStreamOffset]; + + size_t rawSize=rawData.size(); + ForwardOutputStream outputStream(rawData,0,rawSize); + + // little meh to initialize both (intentionally deleted copy/assign) + HuffmanDecoder lengthDecoder2 + { + HuffmanCode{1,0b000000,3}, + HuffmanCode{3,0b000100,4}, + HuffmanCode{3,0b000101,5}, + HuffmanCode{3,0b000110,6}, + HuffmanCode{6,0b111000,7}, + HuffmanCode{6,0b111001,8}, + HuffmanCode{6,0b111010,9}, + HuffmanCode{6,0b111011,10}, + HuffmanCode{6,0b111100,11}, + HuffmanCode{6,0b111101,12}, + HuffmanCode{6,0b111110,13}, + HuffmanCode{6,0b111111,0} + }; + + HuffmanDecoder lengthDecoder4 + { + HuffmanCode{2,0b0000000,3}, + HuffmanCode{2,0b0000001,4}, + HuffmanCode{2,0b0000010,5}, + HuffmanCode{4,0b0001100,6}, + HuffmanCode{4,0b0001101,7}, + HuffmanCode{4,0b0001110,8}, + HuffmanCode{7,0b1111000,9}, + HuffmanCode{7,0b1111001,10}, + HuffmanCode{7,0b1111010,11}, + HuffmanCode{7,0b1111011,12}, + HuffmanCode{7,0b1111100,13}, + HuffmanCode{7,0b1111101,14}, + HuffmanCode{7,0b1111110,15}, + HuffmanCode{7,0b1111111,0} + }; + auto &lengthDecoder=(_ver==2)?lengthDecoder2:lengthDecoder4; + + uint32_t minBits=1; + + while (!outputStream.eof()) + { + if (!readBits(1)) + { + if (readBit()) + { + outputStream.writeByte(read4Bits(true)); + } else { + if (_ver==4) + { + outputStream.writeByte(literalTable[(read4Bits(false)<<1)+readBit()]); + } else outputStream.writeByte(literalTable[read4Bits(false)]); + } + } else { + uint32_t count=lengthDecoder.decode([&](){return readBits(1);}); + if (!count) + { + count=readBits(4); + if (count==0xfU) + { + count=readBits(8); + if (count==0xffU) throw Decompressor::DecompressionError(); + else count+=3; + } else count+=(_ver==2)?14:16; + } + + uint32_t distance; + bool isMax=false; + do { + uint32_t bits=readBits(3)+minBits; + distance=readBits(bits); + isMax=(distance==((1U< &state,bool verify); + + virtual ~LIN2Decompressor(); + + virtual const std::string &getSubName() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) override final; + + static bool detectHeaderXPK(uint32_t hdr) noexcept; + static std::shared_ptr create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + +private: + const Buffer &_packedData; + + uint32_t _ver=0; + size_t _endStreamOffset=0; + size_t _midStreamOffset=0; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/LZBSDecompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/LZBSDecompressor.cpp new file mode 100644 index 00000000..fc3a826f --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/LZBSDecompressor.cpp @@ -0,0 +1,75 @@ +/* Copyright (C) Teemu Suutari */ + +#include "LZBSDecompressor.hpp" +#include "InputStream.hpp" +#include "OutputStream.hpp" +#include "common/Common.hpp" + + +namespace ancient::internal +{ + +bool LZBSDecompressor::detectHeaderXPK(uint32_t hdr) noexcept +{ + return hdr==FourCC("LZBS"); +} + +std::shared_ptr LZBSDecompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) +{ + return std::make_shared(hdr,recursionLevel,packedData,state,verify); +} + +LZBSDecompressor::LZBSDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) : + XPKDecompressor(recursionLevel), + _packedData(packedData) +{ + if (!detectHeaderXPK(hdr) || _packedData.size()<1) throw Decompressor::InvalidFormatError(); +} + +LZBSDecompressor::~LZBSDecompressor() +{ + // nothing needed +} + +const std::string &LZBSDecompressor::getSubName() const noexcept +{ + static std::string name="XPK-LZBS: LZBS CyberYAFA compressor"; + return name; +} + +void LZBSDecompressor::decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) +{ + ForwardInputStream inputStream(_packedData,1,_packedData.size()); + MSBBitReader bitReader(inputStream); + auto readBits=[&](uint32_t count)->uint32_t + { + return rotateBits(bitReader.readBits8(count),count); + }; + + ForwardOutputStream outputStream(rawData,0,rawData.size()); + + uint32_t bits=0,maxBits=uint32_t(_packedData[0]); + while (!outputStream.eof()) + { + if (!readBits(1)) + { + outputStream.writeByte(readBits(8)); + } else { + uint32_t count=readBits(8)+2; + if (count==2) + { + count=readBits(12); + if (!count) throw Decompressor::DecompressionError(); + for (uint32_t i=0;i=(1ULL< &state,bool verify); + + virtual ~LZBSDecompressor(); + + virtual const std::string &getSubName() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) override final; + + static bool detectHeaderXPK(uint32_t hdr) noexcept; + static std::shared_ptr create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + +private: + const Buffer &_packedData; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/LZCBDecompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/LZCBDecompressor.cpp new file mode 100644 index 00000000..298ebd29 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/LZCBDecompressor.cpp @@ -0,0 +1,326 @@ +/* Copyright (C) Teemu Suutari */ + +#include + +#include "LZCBDecompressor.hpp" +#include "RangeDecoder.hpp" +#include "InputStream.hpp" +#include "OutputStream.hpp" +#include "common/Common.hpp" + + +namespace ancient::internal +{ + +template +class FrequencyTree +{ +public: + FrequencyTree() + { + for (uint32_t i=0;i<_size;i++) + _tree[i]=0; + } + + ~FrequencyTree() + { + // nothing needed + } + + uint16_t decode(uint16_t value,uint16_t &low,uint16_t &freq) const + { + if (value>=_tree[_size-1]) + throw Decompressor::DecompressionError(); + uint16_t symbol=0; + low=0; + for (uint32_t i=_levels-2;;i--) + { + uint16_t tmp=_tree[_levelOffsets[i]+symbol]; + if (uint32_t(symbol+1)<_levelSizes[i] && value>=tmp) + { + symbol++; + low+=tmp; + value-=tmp; + } + if (!i) break; + symbol<<=1; + } + freq=_tree[symbol]; + return symbol; + } + + bool exists(uint16_t symbol) const + { + return _tree[symbol]; + } + + void increment(uint16_t symbol) + { + for (uint16_t i=0;i<_levels;i++) + { + _tree[_levelOffsets[i]+symbol]++; + symbol>>=1; + } + } + + void halve() + { + // non-standard way + for (uint32_t i=0;i>=1; + for (uint32_t i=T;i<_size;i++) + _tree[i]=0; + for (uint32_t i=0,length=T;i<_levels-1;i++,length=(length+1)>>1) + { + for (uint32_t j=0;j>1)]+=_tree[_levelOffsets[i]+j]; + } + } + + uint32_t getTotal() const + { + return _tree[_size-1]; + } + +private: + static constexpr uint32_t levelSize(uint32_t level) + { + uint32_t ret=T; + for (uint32_t i=0;i>1; + } + return ret; + } + + static constexpr uint32_t levels() + { + uint32_t ret=0; + while (levelSize(ret)!=1) ret++; + return ret+1; + } + + static constexpr uint32_t size() + { + uint32_t ret=0; + for (uint32_t i=0;i + static constexpr auto makeLevelOffsetSequence(std::integer_sequence) + { + return std::integer_sequence{}; + } + + template + static constexpr auto makeLevelSizeSequence(std::integer_sequence) + { + return std::integer_sequence{}; + } + + template + static constexpr std::array makeArray(std::integer_sequence) + { + return std::array{{I...}}; + } + + static constexpr uint32_t _size=size(); + static constexpr uint32_t _levels=levels(); + static constexpr std::array _levelOffsets=makeArray(makeLevelOffsetSequence(std::make_integer_sequence{})); + static constexpr std::array _levelSizes=makeArray(makeLevelSizeSequence(std::make_integer_sequence{})); + + uint16_t _tree[size()]; +}; + +template +class FrequencyDecoder +{ +public: + FrequencyDecoder(RangeDecoder &decoder) : + _decoder(decoder) + { + // nothing needed + } + + ~FrequencyDecoder() + { + // nothing needed + } + + template + uint16_t decode(F readFunc) + { + uint16_t freq=0,symbol,value=_decoder.decode(_threshold+_tree.getTotal()); + if (value>=_threshold) + { + uint16_t low; + symbol=_tree.decode(value-_threshold,low,freq); + _decoder.scale(_threshold+low,_threshold+low+freq,_threshold+_tree.getTotal()); + if (freq==1 && _threshold>1) + _threshold--; + } else { + _decoder.scale(0,_threshold,_threshold+_tree.getTotal()); + symbol=readFunc(); + // A bug in the encoder + if (!symbol && _tree.exists(symbol)) symbol=T; + _threshold++; + } + _tree.increment(symbol); + if (_threshold+_tree.getTotal()>=0x3ffdU) + { + _tree.halve(); + _threshold=(_threshold>>1)+1; + } + return symbol; + } + +private: + RangeDecoder &_decoder; + FrequencyTree _tree; + uint16_t _threshold=1; +}; + +bool LZCBDecompressor::detectHeaderXPK(uint32_t hdr) noexcept +{ + return hdr==FourCC("LZCB"); +} + +std::shared_ptr LZCBDecompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) +{ + return std::make_shared(hdr,recursionLevel,packedData,state,verify); +} + +LZCBDecompressor::LZCBDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) : + XPKDecompressor(recursionLevel), + _packedData(packedData) +{ + if (packedData.size()<2) throw Decompressor::InvalidFormatError(); +} + +LZCBDecompressor::~LZCBDecompressor() +{ + // nothing needed +} + +const std::string &LZCBDecompressor::getSubName() const noexcept +{ + static std::string name="XPK-LZCB: LZ-compressor"; + return name; +} + +void LZCBDecompressor::decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) +{ + class BitReader : public RangeDecoder::BitReader + { + public: + BitReader(ForwardInputStream &stream) : + _reader(stream) + { + // nothing needed + } + + virtual ~BitReader() + { + // nothing needed + } + + virtual uint32_t readBit() override final + { + return _reader.readBitsBE32(1); + } + + uint32_t readBits(uint32_t bitCount) + { + return _reader.readBitsBE32(bitCount); + } + + private: + MSBBitReader _reader; + }; + + ForwardInputStream inputStream(_packedData,0,_packedData.size(),true); + ForwardOutputStream outputStream(rawData,0,rawData.size()); + BitReader bitReader(inputStream); + + RangeDecoder rangeDecoder(bitReader,bitReader.readBits(16)); + + // Ugly duplicates + auto readByte=[&]()->uint16_t + { + uint16_t ret=rangeDecoder.decode(0x100U); + rangeDecoder.scale(ret,ret+1,0x100U); + return ret; + }; + + auto readCount=[&]()->uint16_t + { + uint16_t ret=rangeDecoder.decode(0x101U); + rangeDecoder.scale(ret,ret+1,0x101U); + return ret; + }; + + FrequencyDecoder<256> baseLiteralDecoder(rangeDecoder); + FrequencyDecoder<257> repeatCountDecoder(rangeDecoder); + FrequencyDecoder<257> literalCountDecoder(rangeDecoder); + FrequencyDecoder<256> distanceDecoder(rangeDecoder); + + std::unique_ptr> literalDecoders[256]; + + uint8_t ch=uint8_t(baseLiteralDecoder.decode(readByte)); + outputStream.writeByte(ch); + bool lastIsLiteral=true; + while (!outputStream.eof()) + { + uint32_t count=repeatCountDecoder.decode(readCount); + if (count) + { + if (count==0x100U) + { + uint32_t tmp; + do + { + tmp=readByte(); + count+=tmp; + } while (tmp==0xffU); + } + count+=lastIsLiteral?5:4; + + uint32_t distance=distanceDecoder.decode(readByte)<<8; + distance|=readByte(); + + ch=outputStream.copy(distance,count); + lastIsLiteral=false; + } else { + uint16_t literalCount; + do + { + literalCount=literalCountDecoder.decode(readCount); + if (!literalCount) throw Decompressor::DecompressionError(); + + for (uint32_t i=0;i>(rangeDecoder); + ch=uint8_t(literalDecoder->decode([&]() + { + return baseLiteralDecoder.decode(readByte); + })); + outputStream.writeByte(ch); + } + } while (literalCount==0x100U); + lastIsLiteral=true; + } + } +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/LZCBDecompressor.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/LZCBDecompressor.hpp new file mode 100644 index 00000000..bbd8958f --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/LZCBDecompressor.hpp @@ -0,0 +1,31 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef LZCBDECOMPRESSOR_HPP +#define LZCBDECOMPRESSOR_HPP + +#include "XPKDecompressor.hpp" + +namespace ancient::internal +{ + +class LZCBDecompressor : public XPKDecompressor +{ +public: + LZCBDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + + virtual ~LZCBDecompressor(); + + virtual const std::string &getSubName() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) override final; + + static bool detectHeaderXPK(uint32_t hdr) noexcept; + static std::shared_ptr create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + +private: + const Buffer &_packedData; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/LZW2Decompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/LZW2Decompressor.cpp new file mode 100644 index 00000000..2d68abf3 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/LZW2Decompressor.cpp @@ -0,0 +1,74 @@ +/* Copyright (C) Teemu Suutari */ + +#include "LZW2Decompressor.hpp" +#include "InputStream.hpp" +#include "OutputStream.hpp" +#include "common/Common.hpp" + + +namespace ancient::internal +{ + +bool LZW2Decompressor::detectHeaderXPK(uint32_t hdr) noexcept +{ + return hdr==FourCC("LZW2") || hdr==FourCC("LZW3"); +} + +std::shared_ptr LZW2Decompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) +{ + return std::make_shared(hdr,recursionLevel,packedData,state,verify); +} + +LZW2Decompressor::LZW2Decompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) : + XPKDecompressor(recursionLevel), + _packedData(packedData) +{ + if (!detectHeaderXPK(hdr)) throw Decompressor::InvalidFormatError(); + _ver=(hdr==FourCC("LZW2"))?2:3; +} + +LZW2Decompressor::~LZW2Decompressor() +{ + // nothing needed +} + +const std::string &LZW2Decompressor::getSubName() const noexcept +{ + static std::string name2="XPK-LZW2: LZW2 CyberYAFA compressor"; + static std::string name3="XPK-LZW3: LZW3 CyberYAFA compressor"; + return (_ver==2)?name2:name3; +} + +void LZW2Decompressor::decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) +{ + ForwardInputStream inputStream(_packedData,0,_packedData.size()); + LSBBitReader bitReader(inputStream); + auto readBit=[&]()->uint32_t + { + return bitReader.readBitsBE32(1); + }; + auto readByte=[&]()->uint8_t + { + return inputStream.readByte(); + }; + + ForwardOutputStream outputStream(rawData,0,rawData.size()); + + while (!outputStream.eof()) + { + if (!readBit()) + { + outputStream.writeByte(readByte()); + } else { + uint32_t distance=uint32_t(readByte())<<8; + distance|=uint32_t(readByte()); + if (!distance) throw Decompressor::DecompressionError(); + distance=65536-distance; + uint32_t count=uint32_t(readByte())+4; + + outputStream.copy(distance,count); + } + } +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/LZW2Decompressor.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/LZW2Decompressor.hpp new file mode 100644 index 00000000..79d251bc --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/LZW2Decompressor.hpp @@ -0,0 +1,33 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef LZW2DECOMPRESSOR_HPP +#define LZW2DECOMPRESSOR_HPP + +#include "XPKDecompressor.hpp" + +namespace ancient::internal +{ + +class LZW2Decompressor : public XPKDecompressor +{ +public: + LZW2Decompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + + virtual ~LZW2Decompressor(); + + virtual const std::string &getSubName() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) override final; + + static bool detectHeaderXPK(uint32_t hdr) noexcept; + static std::shared_ptr create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + +private: + const Buffer &_packedData; + + uint32_t _ver=0; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/LZW4Decompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/LZW4Decompressor.cpp new file mode 100644 index 00000000..02c6c443 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/LZW4Decompressor.cpp @@ -0,0 +1,72 @@ +/* Copyright (C) Teemu Suutari */ + +#include "LZW4Decompressor.hpp" +#include "InputStream.hpp" +#include "OutputStream.hpp" +#include "common/Common.hpp" + + +namespace ancient::internal +{ + +bool LZW4Decompressor::detectHeaderXPK(uint32_t hdr) noexcept +{ + return hdr==FourCC("LZW4"); +} + +std::shared_ptr LZW4Decompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) +{ + return std::make_shared(hdr,recursionLevel,packedData,state,verify); +} + +LZW4Decompressor::LZW4Decompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) : + XPKDecompressor(recursionLevel), + _packedData(packedData) +{ + if (!detectHeaderXPK(hdr)) throw Decompressor::InvalidFormatError(); +} + +LZW4Decompressor::~LZW4Decompressor() +{ + // nothing needed +} + +const std::string &LZW4Decompressor::getSubName() const noexcept +{ + static std::string name="XPK-LZW4: LZW4 CyberYAFA compressor"; + return name; +} + +void LZW4Decompressor::decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) +{ + ForwardInputStream inputStream(_packedData,0,_packedData.size()); + MSBBitReader bitReader(inputStream); + auto readBit=[&]()->uint32_t + { + return bitReader.readBitsBE32(1); + }; + auto readByte=[&]()->uint8_t + { + return inputStream.readByte(); + }; + + ForwardOutputStream outputStream(rawData,0,rawData.size()); + + while (!outputStream.eof()) + { + if (!readBit()) + { + outputStream.writeByte(readByte()); + } else { + uint32_t distance=uint32_t(readByte())<<8; + distance|=uint32_t(readByte()); + if (!distance) throw Decompressor::DecompressionError(); + distance=65536-distance; + uint32_t count=uint32_t(readByte())+3; + + outputStream.copy(distance,count); + } + } +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/LZW4Decompressor.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/LZW4Decompressor.hpp new file mode 100644 index 00000000..6bd0abf2 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/LZW4Decompressor.hpp @@ -0,0 +1,31 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef LZW4DECOMPRESSOR_HPP +#define LZW4DECOMPRESSOR_HPP + +#include "XPKDecompressor.hpp" + +namespace ancient::internal +{ + +class LZW4Decompressor : public XPKDecompressor +{ +public: + LZW4Decompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + + virtual ~LZW4Decompressor(); + + virtual const std::string &getSubName() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) override final; + + static bool detectHeaderXPK(uint32_t hdr) noexcept; + static std::shared_ptr create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + +private: + const Buffer &_packedData; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/LZW5Decompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/LZW5Decompressor.cpp new file mode 100644 index 00000000..b32fa10e --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/LZW5Decompressor.cpp @@ -0,0 +1,100 @@ +/* Copyright (C) Teemu Suutari */ + +#include "LZW5Decompressor.hpp" +#include "InputStream.hpp" +#include "OutputStream.hpp" +#include "common/Common.hpp" + + +namespace ancient::internal +{ + +bool LZW5Decompressor::detectHeaderXPK(uint32_t hdr) noexcept +{ + return hdr==FourCC("LZW5"); +} + +std::shared_ptr LZW5Decompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) +{ + return std::make_shared(hdr,recursionLevel,packedData,state,verify); +} + +LZW5Decompressor::LZW5Decompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) : + XPKDecompressor(recursionLevel), + _packedData(packedData) +{ + if (!detectHeaderXPK(hdr)) throw Decompressor::InvalidFormatError(); +} + +LZW5Decompressor::~LZW5Decompressor() +{ + // nothing needed +} + +const std::string &LZW5Decompressor::getSubName() const noexcept +{ + static std::string name="XPK-LZW5: LZW5 CyberYAFA compressor"; + return name; +} + +void LZW5Decompressor::decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) +{ + ForwardInputStream inputStream(_packedData,0,_packedData.size()); + MSBBitReader bitReader(inputStream); + auto read2Bits=[&]()->uint32_t + { + return bitReader.readBitsBE32(2); + }; + auto readByte=[&]()->uint8_t + { + return inputStream.readByte(); + }; + + ForwardOutputStream outputStream(rawData,0,rawData.size()); + + while (!outputStream.eof()) + { + uint32_t distance,count; + + auto readld=[&]()->uint32_t + { + uint32_t ret=uint32_t(readByte())<<8; + ret|=uint32_t(readByte()); + if (!ret) throw Decompressor::DecompressionError(); + return ret; + }; + + switch (read2Bits()) + { + case 0: + outputStream.writeByte(readByte()); + break; + + case 1: + distance=readld(); + count=(distance&3)+2; + distance=0x4000-(distance>>2); + outputStream.copy(distance,count); + break; + + case 2: + distance=readld(); + count=(distance&15)+2; + distance=0x1000-(distance>>4); + outputStream.copy(distance,count); + break; + + case 3: + distance=readld(); + count=uint32_t(readByte())+3; + distance=0x10000-distance; + outputStream.copy(distance,count); + break; + + default: + throw Decompressor::DecompressionError(); + } + } +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/LZW5Decompressor.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/LZW5Decompressor.hpp new file mode 100644 index 00000000..8ce65b41 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/LZW5Decompressor.hpp @@ -0,0 +1,31 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef LZW5DECOMPRESSOR_HPP +#define LZW5DECOMPRESSOR_HPP + +#include "XPKDecompressor.hpp" + +namespace ancient::internal +{ + +class LZW5Decompressor : public XPKDecompressor +{ +public: + LZW5Decompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + + virtual ~LZW5Decompressor(); + + virtual const std::string &getSubName() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) override final; + + static bool detectHeaderXPK(uint32_t hdr) noexcept; + static std::shared_ptr create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + +private: + const Buffer &_packedData; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/LZXDecompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/LZXDecompressor.cpp new file mode 100644 index 00000000..cdd29cb7 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/LZXDecompressor.cpp @@ -0,0 +1,245 @@ +/* Copyright (C) Teemu Suutari */ + +#include +#include + +#include "LZXDecompressor.hpp" +#include "HuffmanDecoder.hpp" +#include "DLTADecode.hpp" +#include "InputStream.hpp" +#include "OutputStream.hpp" +#include "common/CRC32.hpp" +#include "common/Common.hpp" +#include "common/OverflowCheck.hpp" + + +namespace ancient::internal +{ + +bool LZXDecompressor::detectHeaderXPK(uint32_t hdr) noexcept +{ + return hdr==FourCC("ELZX") || hdr==FourCC("SLZX"); +} + +std::shared_ptr LZXDecompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) +{ + return std::make_shared(hdr,recursionLevel,packedData,state,verify); +} + +LZXDecompressor::LZXDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) : + XPKDecompressor(recursionLevel), + _packedData(packedData) +{ + if (!detectHeaderXPK(hdr)) throw Decompressor::InvalidFormatError(); + if (hdr==FourCC("SLZX")) _isSampled=true; + // There is no good spec on the LZX header content -> lots of unknowns here + if (_packedData.size()<41) throw Decompressor::InvalidFormatError(); + // XPK LZX compression is embedded single file of LZX -> read first file. Ignore rest + // this will include flags, which need to be zero anyway + uint32_t streamHdr=_packedData.readBE32(0); + if (streamHdr!=FourCC("LZX\0")) throw Decompressor::InvalidFormatError(); + + _rawSize=_packedData.readLE32(12); + _packedSize=_packedData.readLE32(16); + + _rawCRC=_packedData.readLE32(32); + uint32_t headerCRC=_packedData.readLE32(36); + + uint8_t tmp=_packedData.read8(21); + if (tmp && tmp!=2) throw Decompressor::InvalidFormatError(); + if (tmp==2) _isCompressed=true; + + _packedOffset=41U+_packedData.read8(40U); + _packedOffset+=_packedData.read8(24U); + _packedSize+=_packedOffset; + + if (_packedSize>_packedData.size()) throw Decompressor::InvalidFormatError(); + if (verify) + { + uint32_t crc=CRC32(_packedData,10,26,0); + for (uint32_t i=0;i<4;i++) crc=CRC32Byte(0,crc); + crc=CRC32(_packedData,40,_packedOffset-40,crc); + if (crc!=headerCRC) throw Decompressor::VerificationError(); + } +} + +LZXDecompressor::~LZXDecompressor() +{ + // nothing needed +} + +const std::string &LZXDecompressor::getSubName() const noexcept +{ + static std::string nameE="XPK-ELZX: LZX-compressor"; + static std::string nameS="XPK-SLZX: LZX-compressor with delta encoding"; + return (_isSampled)?nameS:nameE; +} + +void LZXDecompressor::decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) +{ + if (rawData.size()!=_rawSize) throw Decompressor::DecompressionError(); + if (!_isCompressed) + { + if (_packedSize!=_rawSize) throw Decompressor::DecompressionError(); + std::memcpy(rawData.data(),_packedData.data()+_packedOffset,_rawSize); + return; + } + + ForwardInputStream inputStream(_packedData,_packedOffset,_packedSize); + LSBBitReader bitReader(inputStream); + auto readBits=[&](uint32_t count)->uint32_t + { + return bitReader.readBitsBE16(count); + }; + auto readBit=[&]()->uint32_t + { + return bitReader.readBitsBE16(1); + }; + + ForwardOutputStream outputStream(rawData,0,rawData.size()); + + typedef HuffmanDecoder LZXDecoder; + + // possibly padded/reused later if multiple blocks + uint8_t literalTable[768]; + for (uint32_t i=0;i<768;i++) literalTable[i]=0; + LZXDecoder literalDecoder; + uint32_t previousDistance=1; + + while (!outputStream.eof()) + { + + auto createHuffmanTable=[&](LZXDecoder &dec,const uint8_t *bitLengths,uint32_t bitTableLength) + { + uint8_t minDepth=16,maxDepth=0; + for (uint32_t i=0;imaxDepth) maxDepth=bitLengths[i]; + } + if (!maxDepth) return; + + dec.createOrderlyHuffmanTable(bitLengths,bitTableLength); + }; + + uint32_t method=readBits(3); + if (method<1 || method>3) throw Decompressor::DecompressionError(); + + LZXDecoder distanceDecoder; + if (method==3) + { + uint8_t bitLengths[8]; + for (uint32_t i=0;i<8;i++) bitLengths[i]=readBits(3); + createHuffmanTable(distanceDecoder,bitLengths,8); + } + + size_t blockLength=readBits(8)<<16; + blockLength|=readBits(8)<<8; + blockLength|=readBits(8); + if (OverflowCheck::sum(blockLength,outputStream.getOffset())>_rawSize) throw Decompressor::DecompressionError(); + + if (method!=1) + { + literalDecoder.reset(); + for (uint32_t pos=0,block=0;block<2;block++) + { + uint32_t adjust=(block)?0:1; + uint32_t maxPos=(block)?768:256; + LZXDecoder bitLengthDecoder; + { + uint8_t lengthTable[20]; + for (uint32_t i=0;i<20;i++) lengthTable[i]=readBits(4); + createHuffmanTable(bitLengthDecoder,lengthTable,20); + } + while (posmaxPos-pos) count=maxPos-pos; + while (count--) literalTable[pos++]=value; + }; + + auto symDecode=[&](uint32_t value)->uint32_t + { + return (literalTable[pos]+17-value)%17; + }; + + switch (symbol) + { + case 17: + doRepeat(readBits(4)+3+adjust,0); + break; + + case 18: + doRepeat(readBits(6-adjust)+19+adjust,0); + break; + + case 19: + { + uint32_t count=readBit()+3+adjust; + doRepeat(count,symDecode(bitLengthDecoder.decode(readBit))); + } + break; + + default: + literalTable[pos++]=symDecode(symbol); + break; + } + } + } + createHuffmanTable(literalDecoder,literalTable,768); + } + + while (blockLength) + { + uint32_t symbol=literalDecoder.decode(readBit); + if (symbol<256) { + outputStream.writeByte(symbol); + blockLength--; + } else { + // both of these tables are almost too regular to be tables... + static const uint8_t ldBits[32]={ + 0,0,0,0,1,1,2,2, + 3,3,4,4,5,5,6,6, + 7,7,8,8,9,9,10,10, + 11,11,12,12,13,13,14,14}; + static const uint32_t ldAdditions[32]={ + 0x0, + 0x1, 0x2, 0x3, 0x4, 0x6, 0x8, 0xc, 0x10, + 0x18, 0x20, 0x30, 0x40, 0x60, 0x80, 0xc0, 0x100, + 0x180, 0x200, 0x300, 0x400, 0x600, 0x800, 0xc00,0x1000, + 0x1800,0x2000,0x3000,0x4000,0x6000,0x8000,0xc000}; + + symbol-=256; + uint32_t bits=ldBits[symbol&0x1f]; + uint32_t distance=ldAdditions[symbol&0x1f]; + if (bits>=3 && method==3) + { + distance+=readBits(bits-3)<<3; + uint32_t tmp=distanceDecoder.decode(readBit); + distance+=tmp; + } else { + distance+=readBits(bits); + if (!distance) distance=previousDistance; + } + previousDistance=distance; + + uint32_t count=ldAdditions[symbol>>5]+readBits(ldBits[symbol>>5])+3; + if (count>blockLength) throw Decompressor::DecompressionError(); + outputStream.copy(distance,count); + blockLength-=count; + } + } + } + if (verify) + { + uint32_t crc=CRC32(rawData,0,_rawSize,0); + if (crc!=_rawCRC) throw Decompressor::VerificationError(); + } + if (_isSampled) + DLTADecode::decode(rawData,rawData,0,_rawSize); +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/LZXDecompressor.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/LZXDecompressor.hpp new file mode 100644 index 00000000..396b8220 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/LZXDecompressor.hpp @@ -0,0 +1,37 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef LZXDECOMPRESSOR_HPP +#define LZXDECOMPRESSOR_HPP + +#include "XPKDecompressor.hpp" + +namespace ancient::internal +{ + +class LZXDecompressor : public XPKDecompressor +{ +public: + LZXDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + virtual ~LZXDecompressor(); + + virtual const std::string &getSubName() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) override final; + + static bool detectHeaderXPK(uint32_t hdr) noexcept; + static std::shared_ptr create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + +private: + const Buffer &_packedData; + + bool _isSampled=false; + bool _isCompressed=false; + size_t _packedSize=0; + size_t _packedOffset=0; + size_t _rawSize=0; + uint32_t _rawCRC=0; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/LH1Decompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/LH1Decompressor.cpp new file mode 100644 index 00000000..db1917e4 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/LH1Decompressor.cpp @@ -0,0 +1,90 @@ +/* Copyright (C) Teemu Suutari */ + +#include "LH1Decompressor.hpp" + +#include "../HuffmanDecoder.hpp" +#include "../DynamicHuffmanDecoder.hpp" +#include "../InputStream.hpp" +#include "../OutputStream.hpp" + +namespace ancient::internal +{ + +LH1Decompressor::LH1Decompressor(const Buffer &packedData) : + _packedData(packedData) +{ + // nothing needed +} + +LH1Decompressor::~LH1Decompressor() +{ + // nothing needed +} + +size_t LH1Decompressor::getRawSize() const noexcept +{ + // N/A + return 0; +} + +size_t LH1Decompressor::getPackedSize() const noexcept +{ + // N/A + return 0; +} + +const std::string &LH1Decompressor::getName() const noexcept +{ + static std::string name="LHA: LH1"; + return name; +} + +void LH1Decompressor::decompressImpl(Buffer &rawData,bool verify) +{ + ForwardInputStream inputStream(_packedData,0,_packedData.size()); + MSBBitReader bitReader(inputStream); + auto readBits=[&](uint32_t count)->uint32_t + { + return bitReader.readBits8(count); + }; + auto readBit=[&]()->uint32_t + { + return bitReader.readBits8(1); + }; + + ForwardOutputStream outputStream(rawData,0,rawData.size()); + + DynamicHuffmanDecoder<314> decoder; + + static const uint8_t distanceHighBits[64]={ + 3,4,4,4,5,5,5,5, 5,5,5,5,6,6,6,6, + 6,6,6,6,6,6,6,6, 7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7, + 8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8 + }; + + HuffmanDecoder distanceDecoder; + distanceDecoder.createOrderlyHuffmanTable(distanceHighBits,64); + + while (!outputStream.eof()) + { + uint32_t code=decoder.decode(readBit); + if (decoder.getMaxFrequency()==0x8000U) decoder.halve(); + decoder.update(code); + + if (code<256) + { + outputStream.writeByte(code); + } else { + uint32_t distance=distanceDecoder.decode(readBit); + distance=(distance<<6)|readBits(6); + distance++; + + uint32_t count=code-253; + + outputStream.copy(distance,count,0x20); + } + } +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/LH1Decompressor.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/LH1Decompressor.hpp new file mode 100644 index 00000000..6b098538 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/LH1Decompressor.hpp @@ -0,0 +1,30 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef LH1DECOMPRESSOR_HPP +#define LH1DECOMPRESSOR_HPP + +#include "Decompressor.hpp" + +namespace ancient::internal +{ + +class LH1Decompressor : public Decompressor +{ +public: + LH1Decompressor(const Buffer &packedData); + virtual ~LH1Decompressor(); + + virtual size_t getRawSize() const noexcept override final; + virtual size_t getPackedSize() const noexcept override final; + + virtual const std::string &getName() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,bool verify) override final; + +private: + const Buffer &_packedData; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/LH2Decompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/LH2Decompressor.cpp new file mode 100644 index 00000000..d9cf96da --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/LH2Decompressor.cpp @@ -0,0 +1,126 @@ +/* Copyright (C) Teemu Suutari */ + +#include "LH2Decompressor.hpp" + +#include "../HuffmanDecoder.hpp" +#include "../DynamicHuffmanDecoder.hpp" +#include "../InputStream.hpp" +#include "../OutputStream.hpp" + + +namespace ancient::internal +{ + +LH2Decompressor::LH2Decompressor(const Buffer &packedData) : + _packedData(packedData) +{ + // nothing needed +} + +LH2Decompressor::~LH2Decompressor() +{ + // nothing needed +} + +size_t LH2Decompressor::getRawSize() const noexcept +{ + // N/A + return 0; +} + +size_t LH2Decompressor::getPackedSize() const noexcept +{ + // N/A + return 0; +} + +const std::string &LH2Decompressor::getName() const noexcept +{ + static std::string name="LHA: LH2"; + return name; +} + +// This is probably fishiest of the fishy formats I've worked with +// Basically it uses Dynamic Huffman decoder but instead of static +// size, it is dynamically growing. However, that part is not well +// defined. Thus +// a. It is very hard to use LH2 using generic implementation +// instead of the specific one used by LHA +// b. There are bugs in encoder which need to be baked in the decoder +// as well (Probably there is lots of unneccesary stuff in addCode, +// but better safe than sorry) +// c. LH 1.9x and UNLHA32 refuse to use LH2 beyond 8k files. Thus +// we can only guess if the wraparound is correct, since nothing +// should use it +// jLHA in theory supports LH2 without limitations, but it produces +// broken bitstream. +// +// So far this works with the files I've tried from "official" LHA +void LH2Decompressor::decompressImpl(Buffer &rawData,bool verify) +{ + ForwardInputStream inputStream(_packedData,0,_packedData.size()); + MSBBitReader bitReader(inputStream); + auto readBits=[&](uint32_t count)->uint32_t + { + return bitReader.readBits8(count); + }; + auto readBit=[&]()->uint32_t + { + return bitReader.readBits8(1); + }; + + ForwardOutputStream outputStream(rawData,0,rawData.size()); + + DynamicHuffmanDecoder<286> valueDecoder; + DynamicHuffmanDecoder<128> distanceDecoder(0); + uint32_t distancePosition=0; + + uint32_t distCount=0; + while (!outputStream.eof()) + { + uint32_t code=valueDecoder.decode(readBit); + if (valueDecoder.getMaxFrequency()==0x8000U) valueDecoder.halve(); + valueDecoder.update(code); + + if (code<256) + { + outputStream.writeByte(code); + } else { + if (code==285) code+=readBits(8); + uint32_t count=code-253; + + // Bug in LH2 where count does not match frequency. + // Makes things more complicated + auto updateDist=[&](uint32_t code) + { + if (distCount==0x8000U) + { + distanceDecoder.halve(); + distCount=distanceDecoder.getMaxFrequency(); + } + distanceDecoder.update(code); + distCount++; + }; + + uint32_t maxDist=std::min(uint32_t((outputStream.getOffset()+63)>>6),128U); + if (distancePosition!=maxDist) + { + for (uint32_t i=distancePosition;i bitReader(inputStream); + auto readBits=[&](uint32_t count)->uint32_t + { + return bitReader.readBits8(count); + }; + auto readBit=[&]()->uint32_t + { + return bitReader.readBits8(1); + }; + + ForwardOutputStream outputStream(rawData,0,rawData.size()); + + OptionalHuffmanDecoder decoder; + + static const uint8_t distanceHighBits[128]={ + 2,4,4,5,5,5,6,6, 6,6,6,6,6,7,7,7, + 7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,8, + 8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8, + + 8,8,8,8,8,8,8,8, 8,8,8,8,8,8,9,9, + 9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9 + }; + + OptionalHuffmanDecoder distanceDecoder; + + uint32_t blockRemaining=0; + while (!outputStream.eof()) + { + if (!blockRemaining) + { + blockRemaining=readBits(16); + if (!blockRemaining) blockRemaining=0x10000; + + // not strictly needed as a lambda, but cleaner this way + auto createDecoderTable=[&]() + { + decoder.reset(); + + uint8_t symbolBits[286]; + uint32_t oneCount=0; + for (uint32_t i=0;i<286;i++) + { + if (readBit()) symbolBits[i]=readBits(4)+1; + else symbolBits[i]=0; + if (symbolBits[i]==1) oneCount++; + if (i==2 && oneCount==3) + { + decoder.setEmpty(readBits(9)); + return; + } + } + decoder.createOrderlyHuffmanTable(symbolBits,286); + }; + + // ditto + auto createDistanceDecoderTable=[&]() + { + distanceDecoder.reset(); + + if (readBit()) + { + uint8_t symbolBits[128]; + uint32_t oneCount=0; + for (uint32_t i=0;i<128;i++) + { + symbolBits[i]=readBits(4); + if (symbolBits[i]==1) oneCount++; + if (i==2 && oneCount==3) + { + // 7 bits would be fine, but whatever + distanceDecoder.setEmpty(readBits(9)); + return; + } + } + distanceDecoder.createOrderlyHuffmanTable(symbolBits,128); + } else distanceDecoder.createOrderlyHuffmanTable(distanceHighBits,128); + }; + + createDecoderTable(); + createDistanceDecoderTable(); + } + blockRemaining--; + + uint32_t code=decoder.decode(readBit); + + if (code<256) + { + outputStream.writeByte(code); + } else { + if (code==285) code+=readBits(8); + uint32_t distance=distanceDecoder.decode(readBit); + distance=(distance<<6)|readBits(6); + distance++; + + uint32_t count=code-253; + + outputStream.copy(distance,count,0x20); + } + } +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/LH3Decompressor.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/LH3Decompressor.hpp new file mode 100644 index 00000000..8676c1fe --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/LH3Decompressor.hpp @@ -0,0 +1,30 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef LH3DECOMPRESSOR_HPP +#define LH3DECOMPRESSOR_HPP + +#include "Decompressor.hpp" + +namespace ancient::internal +{ + +class LH3Decompressor : public Decompressor +{ +public: + LH3Decompressor(const Buffer &packedData); + virtual ~LH3Decompressor(); + + virtual size_t getRawSize() const noexcept override final; + virtual size_t getPackedSize() const noexcept override final; + + virtual const std::string &getName() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,bool verify) override final; + +private: + const Buffer &_packedData; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/LHXDecompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/LHXDecompressor.cpp new file mode 100644 index 00000000..144005e9 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/LHXDecompressor.cpp @@ -0,0 +1,191 @@ +/* Copyright (C) Teemu Suutari */ + +#include "LHXDecompressor.hpp" + +#include "../HuffmanDecoder.hpp" +#include "../InputStream.hpp" +#include "../OutputStream.hpp" + + +namespace ancient::internal +{ + +LHXDecompressor::LHXDecompressor(const Buffer &packedData) : + _packedData(packedData), + _method(0) +{ + // nothing needed +} + +LHXDecompressor::LHXDecompressor(const Buffer &packedData,uint32_t method) : + _packedData(packedData), + _method(method-3) +{ + if (method<4 || method>8) throw InvalidFormatError(); +} + +LHXDecompressor::~LHXDecompressor() +{ + // nothing needed +} + +size_t LHXDecompressor::getRawSize() const noexcept +{ + // N/A + return 0; +} + +size_t LHXDecompressor::getPackedSize() const noexcept +{ + // N/A + return 0; +} + +const std::string &LHXDecompressor::getName() const noexcept +{ + static std::string name="LHA: LH4, LH5, LH6, LH7, LH8, LHX"; + return name; +} + +void LHXDecompressor::decompressImpl(Buffer &rawData,bool verify) +{ + ForwardInputStream inputStream(_packedData,0,_packedData.size()); + MSBBitReader bitReader(inputStream); + auto readBits=[&](uint32_t count)->uint32_t + { + return bitReader.readBits8(count); + }; + auto readBit=[&]()->uint32_t + { + return bitReader.readBits8(1); + }; + + ForwardOutputStream outputStream(rawData,0,rawData.size()); + + OptionalHuffmanDecoder decoder; + OptionalHuffmanDecoder distanceDecoder; + + static const struct { + uint32_t mask; + uint32_t distanceTableSize; + uint32_t distanceBits; + } methodTable[6] = { + {0x7ffffU,20,5}, // LHX + {0xfffU,14,4}, // LH4 + {0x1fffU,14,4}, // LH5 + {0x7fffU,16,5}, // LH6 + {0xffffU,17,5}, // LH7 + {0xffffU,17,5} // LH8 + // LH8 is the only Joe Jared method seen. + // It exists in early versions of LH7-tool + // In those versions LH8 is just synonym for LH7 + // However, LH9+ is something I have not seen at + // all (i.e. not in DLH7021Q/WLH7021Q.) + // There would be one more version (0.21R) but + // that seems lost. Most likely minor bump from Q->R + // do not enable those formats either and the LH9+ + // formats are nothing but hopes for "future work" + // that never materialized (until I'm proven wrong ofc) + }; + + uint32_t blockRemaining=0; + while (!outputStream.eof()) + { + if (!blockRemaining) + { + blockRemaining=readBits(16); + if (!blockRemaining) blockRemaining=0x10000; + + auto createTable=[&](OptionalHuffmanDecoder &dest,uint32_t count,uint32_t bits,bool enableHole) + { + uint8_t symbolBits[20]; + uint32_t length=readBits(bits); + if (!length) + { + dest.setEmpty(readBits(bits)); + } else if (length<=count) { + for (uint32_t i=0;i32) throw DecompressionError(); + symbolBits[i++]=value; + if (i==3 && enableHole) + { + uint32_t zeros=readBits(2); + if (i+zeros>length) throw DecompressionError(); + for (uint32_t j=0;j tmpDecoder; + createTable(tmpDecoder,19,5,true); + + decoder.reset(); + + uint8_t symbolBits[511]; + uint32_t length=readBits(9); + if (!length) + { + decoder.setEmpty(readBits(9)); + } else { + for (uint32_t i=0;ilength) throw DecompressionError(); + for (uint32_t j=0;j bitReader(inputStream); + auto readBit=[&]()->uint32_t + { + return bitReader.readBits8(1); + }; + auto readByte=[&]()->uint32_t + { + return inputStream.readByte(); + }; + + ForwardOutputStream outputStream(rawData,0,rawData.size()); + StaticBuffer<4096> prevBuffer; + { + uint8_t *bufPtr=prevBuffer.data(); + + for (uint32_t i=0;i<18;i++) *(bufPtr++)=0; + for (uint32_t i=0;i<256;i++) + for (uint32_t j=0;j<13;j++) *(bufPtr++)=i; + for (uint32_t i=0;i<256;i++) *(bufPtr++)=i; + for (uint32_t i=0;i<256;i++) *(bufPtr++)=255-i; + for (uint32_t i=0;i<128;i++) *(bufPtr++)=0; + for (uint32_t i=0;i<110;i++) *(bufPtr++)=' '; + } + + while (!outputStream.eof()) + { + if (readBit()) + { + outputStream.writeByte(readByte()); + } else { + uint32_t byte1=readByte(); + uint32_t byte2=readByte(); + uint32_t distance=((outputStream.getOffset()-byte1-((byte2&0xf0U)<<4)-19)&0xfffU)+1; + uint32_t count=(byte2&0xfU)+3; + + outputStream.copy(distance,count,prevBuffer); + } + } +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/LZ5Decompressor.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/LZ5Decompressor.hpp new file mode 100644 index 00000000..7141a36f --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/LZ5Decompressor.hpp @@ -0,0 +1,30 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef LZ5DECOMPRESSOR_HPP +#define LZ5DECOMPRESSOR_HPP + +#include "Decompressor.hpp" + +namespace ancient::internal +{ + +class LZ5Decompressor : public Decompressor +{ +public: + LZ5Decompressor(const Buffer &packedData); + virtual ~LZ5Decompressor(); + + virtual size_t getRawSize() const noexcept override final; + virtual size_t getPackedSize() const noexcept override final; + + virtual const std::string &getName() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,bool verify) override final; + +private: + const Buffer &_packedData; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/LZHDecompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/LZHDecompressor.cpp new file mode 100644 index 00000000..9d7a9be3 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/LZHDecompressor.cpp @@ -0,0 +1,167 @@ +/* Copyright (C) Teemu Suutari */ + +#include +#include + +#include + +#include "LZHDecompressor.hpp" + +#include "LH1Decompressor.hpp" +#include "LH2Decompressor.hpp" +#include "LH3Decompressor.hpp" +#include "LHXDecompressor.hpp" +#include "LZ5Decompressor.hpp" +#include "LZSDecompressor.hpp" +#include "PMDecompressor.hpp" + + +namespace ancient::internal +{ + +LZHDecompressor::LZHDecompressor(const Buffer &packedData,const std::string &method) : + _packedData(packedData), + _method(method) +{ + // nothing needed +} + +LZHDecompressor::~LZHDecompressor() +{ + // nothing needed +} + +size_t LZHDecompressor::getRawSize() const noexcept +{ + // N/A + return 0; +} + +size_t LZHDecompressor::getPackedSize() const noexcept +{ + // N/A + return 0; +} + +const std::string &LZHDecompressor::getName() const noexcept +{ + static std::string name="Lzh"; + return name; +} + +void LZHDecompressor::decompressImpl(Buffer &rawData,bool verify) +{ + enum class Compressor + { + LH0=0, + LH1, + LH2, + LH3, + LH4, + LH5, + LH6, + LH7, + LH8, + LHX, + LZ4, + LZ5, + LZS, + PM0, + PM1, + PM2 + }; + + static std::map compressorMap{ + {"-lh0-",Compressor::LH0}, + {"-lh1-",Compressor::LH1}, + {"-lh2-",Compressor::LH2}, + {"-lh3-",Compressor::LH3}, + {"-lh4-",Compressor::LH4}, + {"-lh5-",Compressor::LH5}, + {"-lh6-",Compressor::LH6}, + {"-lh7-",Compressor::LH7}, + {"-lh8-",Compressor::LH8}, + {"-lhx-",Compressor::LHX}, + {"-lz4-",Compressor::LZ4}, + {"-lz5-",Compressor::LZ5}, + {"-lzs-",Compressor::LZS}, + {"-pm0-",Compressor::PM0}, + {"-pm1-",Compressor::PM1}, + {"-pm2-",Compressor::PM2} + }; + + auto it=compressorMap.find(_method); + if (it==compressorMap.end()) throw DecompressionError(); + switch (it->second) + { + case Compressor::LH0: + case Compressor::LZ4: + case Compressor::PM0: + if (rawData.size()!=_packedData.size()) throw DecompressionError(); + std::memcpy(rawData.data(),_packedData.data(),rawData.size()); + break; + + case Compressor::LH1: + { + LH1Decompressor dec(_packedData); + dec.decompress(rawData,verify); + } + break; + + case Compressor::LH2: + { + LH2Decompressor dec(_packedData); + dec.decompress(rawData,verify); + } + break; + + case Compressor::LH3: + { + LH3Decompressor dec(_packedData); + dec.decompress(rawData,verify); + } + break; + + case Compressor::LH4: + case Compressor::LH5: + case Compressor::LH6: + case Compressor::LH7: + case Compressor::LH8: + { + LHXDecompressor dec(_packedData,static_cast(it->second)-static_cast(Compressor::LH4)+4); + dec.decompress(rawData,verify); + } + break; + + case Compressor::LHX: + { + LHXDecompressor dec(_packedData); + dec.decompress(rawData,verify); + } + break; + + case Compressor::LZ5: + { + LZ5Decompressor dec(_packedData); + dec.decompress(rawData,verify); + } + break; + + case Compressor::LZS: + { + LZSDecompressor dec(_packedData); + dec.decompress(rawData,verify); + } + break; + + case Compressor::PM1: + case Compressor::PM2: + { + PMDecompressor dec(_packedData,static_cast(it->second)-static_cast(Compressor::PM1)+1); + dec.decompress(rawData,verify); + } + break; + } +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/LZHDecompressor.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/LZHDecompressor.hpp new file mode 100644 index 00000000..130487af --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/LZHDecompressor.hpp @@ -0,0 +1,32 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef LZHDECOMPRESSOR_HPP +#define LZHDECOMPRESSOR_HPP + +#include "Decompressor.hpp" + +namespace ancient::internal +{ + +class LZHDecompressor : public Decompressor +{ +public: + LZHDecompressor(const Buffer &packedData,const std::string &method); + virtual ~LZHDecompressor(); + + virtual size_t getRawSize() const noexcept override final; + virtual size_t getPackedSize() const noexcept override final; + + virtual const std::string &getName() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,bool verify) override final; + +private: + const Buffer &_packedData; + + std::string _method; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/LZSDecompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/LZSDecompressor.cpp new file mode 100644 index 00000000..3f48d486 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/LZSDecompressor.cpp @@ -0,0 +1,70 @@ +/* Copyright (C) Teemu Suutari */ + +#include "LZSDecompressor.hpp" + +#include "../InputStream.hpp" +#include "../OutputStream.hpp" + + +namespace ancient::internal +{ + +LZSDecompressor::LZSDecompressor(const Buffer &packedData) : + _packedData(packedData) +{ + // nothing needed +} + +LZSDecompressor::~LZSDecompressor() +{ + // nothing needed +} + +size_t LZSDecompressor::getRawSize() const noexcept +{ + // N/A + return 0; +} + +size_t LZSDecompressor::getPackedSize() const noexcept +{ + // N/A + return 0; +} + +const std::string &LZSDecompressor::getName() const noexcept +{ + static std::string name="LHA: LZS"; + return name; +} + +void LZSDecompressor::decompressImpl(Buffer &rawData,bool verify) +{ + ForwardInputStream inputStream(_packedData,0,_packedData.size()); + MSBBitReader bitReader(inputStream); + auto readBits=[&](uint32_t count)->uint32_t + { + return bitReader.readBits8(count); + }; + auto readBit=[&]()->uint32_t + { + return bitReader.readBits8(1); + }; + + ForwardOutputStream outputStream(rawData,0,rawData.size()); + + while (!outputStream.eof()) + { + if (readBit()) + { + outputStream.writeByte(readBits(8)); + } else { + uint32_t distance=((outputStream.getOffset()-readBits(11)-18)&0x7ffU)+1; + uint32_t count=readBits(4)+2; + + outputStream.copy(distance,count,0x20); + } + } +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/LZSDecompressor.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/LZSDecompressor.hpp new file mode 100644 index 00000000..f0a0c9a7 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/LZSDecompressor.hpp @@ -0,0 +1,30 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef LZSDECOMPRESSOR_HPP +#define LZSDECOMPRESSOR_HPP + +#include "Decompressor.hpp" + +namespace ancient::internal +{ + +class LZSDecompressor : public Decompressor +{ +public: + LZSDecompressor(const Buffer &packedData); + virtual ~LZSDecompressor(); + + virtual size_t getRawSize() const noexcept override final; + virtual size_t getPackedSize() const noexcept override final; + + virtual const std::string &getName() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,bool verify) override final; + +private: + const Buffer &_packedData; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/PMDecompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/PMDecompressor.cpp new file mode 100644 index 00000000..60d9013b --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/Lzh/PMDecompressor.cpp @@ -0,0 +1,424 @@ +/* Copyright (C) Teemu Suutari */ + +#include "PMDecompressor.hpp" + +#include "../HuffmanDecoder.hpp" +#include "../InputStream.hpp" +#include "../OutputStream.hpp" + + +namespace ancient::internal +{ + +PMDecompressor::PMDecompressor(const Buffer &packedData,uint32_t version) : + _packedData(packedData), + _version(version) +{ + if (version!=1 && version!=2) throw InvalidFormatError(); +} + +PMDecompressor::~PMDecompressor() +{ + // nothing needed +} + +size_t PMDecompressor::getRawSize() const noexcept +{ + // N/A + return 0; +} + +size_t PMDecompressor::getPackedSize() const noexcept +{ + // N/A + return 0; +} + +const std::string &PMDecompressor::getName() const noexcept +{ + static std::string name="LHA: PM1, PM2"; + return name; +} + +uint8_t PMDecompressor::decodeMTF(uint8_t value,uint8_t map[]) +{ + return map[value]; +} + +void PMDecompressor::updateMTF(uint8_t value,uint8_t map[]) +{ + for (uint32_t i=0;;i++) + { + if (map[i]==value) + { + value=i; + break; + } + } + if (value) + { + uint8_t tmp=map[value]; + for (uint32_t i=value;i;i--) + map[i]=map[i-1]; + map[0]=tmp; + } +} + +void PMDecompressor::createMTFMap(uint8_t map[]) +{ + for (uint32_t i=0,j=0x20;j<0x80;i++,j++) map[i]=j; + for (uint32_t i=0x60,j=0;j<0x20;i++,j++) map[i]=j; + for (uint32_t i=0x80,j=0xa0;j<0xe0;i++,j++) map[i]=j; + for (uint32_t i=0xc0,j=0x80;j<0xa0;i++,j++) map[i]=j; + for (uint32_t i=0xe0,j=0xe0;j<0x100;i++,j++) map[i]=j; +} + +void PMDecompressor::decompressImpl(Buffer &rawData,bool verify) +{ + if (_version==1) decompressImplPM1(rawData,verify); + else decompressImplPM2(rawData,verify); +} + +void PMDecompressor::decompressImplPM1(Buffer &rawData,bool verify) +{ + static const struct { + uint8_t length; + uint8_t code; + } treeDefinitions[32][6] { + // This is madness, I had to write a special program to decode this. + // Also, in the original there is a bug @ index 17, as identified by + // lhasa (we fix it when creating the decoder) + {{4, 0b0000},{4, 0b0001},{3, 0b001},{2, 0b01},{2, 0b10},{2, 0b11}}, + {{3, 0b000},{3, 0b001},{3, 0b010},{2, 0b10},{2, 0b11},{3, 0b011}}, + {{3, 0b000},{3, 0b001},{2, 0b01},{2, 0b10},{3, 0b110},{3, 0b111}}, + {{2, 0b00},{3, 0b010},{3, 0b011},{2, 0b10},{3, 0b110},{3, 0b111}}, + {{2, 0b00},{3, 0b010},{2, 0b10},{3, 0b011},{3, 0b110},{3, 0b111}}, + {{2, 0b00},{3, 0b010},{2, 0b10},{2, 0b11},{4, 0b0110},{4, 0b0111}}, + {{2, 0b00},{2, 0b01},{3, 0b100},{3, 0b101},{3, 0b110},{3, 0b111}}, + {{2, 0b00},{2, 0b01},{3, 0b100},{2, 0b11},{4, 0b1010},{4, 0b1011}}, + + {{2, 0b00},{2, 0b01},{2, 0b10},{3, 0b110},{4, 0b1110},{4, 0b1111}}, + {{1, 0b0},{4, 0b1000},{3, 0b101},{3, 0b110},{3, 0b111},{4, 0b1001}}, + {{1, 0b0},{4, 0b1000},{3, 0b101},{2, 0b11},{5,0b10010},{5,0b10011}}, + {{1, 0b0},{4, 0b1000},{4, 0b1001},{3, 0b101},{3, 0b110},{3, 0b111}}, + {{1, 0b0},{3, 0b100},{4, 0b1010},{3, 0b110},{3, 0b111},{4, 0b1011}}, + {{1, 0b0},{3, 0b100},{3, 0b101},{3, 0b110},{4, 0b1110},{4, 0b1111}}, + {{1, 0b0},{3, 0b100},{2, 0b11},{4, 0b1010},{5,0b10110},{5,0b10111}}, + {{1, 0b0},{2, 0b10},{4, 0b1100},{4, 0b1101},{4, 0b1110},{4, 0b1111}}, + + {{1, 0b0},{2, 0b10},{3, 0b110},{4, 0b1110},{5,0b11110},{5,0b11111}}, + {{3, 0b000},{3, 0b001},{2, 0b01},{2, 0b10},{2, 0b11},{0, 0b0}}, + {{2, 0b00},{3, 0b010},{2, 0b10},{2, 0b11},{3, 0b011},{0, 0b0}}, + {{2, 0b00},{2, 0b01},{2, 0b10},{3, 0b110},{3, 0b111},{0, 0b0}}, + {{1, 0b0},{4, 0b1000},{3, 0b101},{2, 0b11},{4, 0b1001},{0, 0b0}}, + {{1, 0b0},{3, 0b100},{3, 0b101},{3, 0b110},{3, 0b111},{0, 0b0}}, + {{1, 0b0},{3, 0b100},{2, 0b11},{4, 0b1010},{4, 0b1011},{0, 0b0}}, + {{1, 0b0},{2, 0b10},{3, 0b110},{4, 0b1110},{4, 0b1111},{0, 0b0}}, + + {{3, 0b000},{3, 0b001},{2, 0b01},{1, 0b1},{0, 0b0},{0, 0b0}}, + {{2, 0b00},{3, 0b010},{1, 0b1},{3, 0b011},{0, 0b0},{0, 0b0}}, + {{2, 0b00},{2, 0b01},{2, 0b10},{2, 0b11},{0, 0b0},{0, 0b0}}, + {{1, 0b0},{3, 0b100},{2, 0b11},{3, 0b101},{0, 0b0},{0, 0b0}}, + {{1, 0b0},{2, 0b10},{3, 0b110},{3, 0b111},{0, 0b0},{0, 0b0}}, + {{1, 0b0},{2, 0b10},{2, 0b11},{0, 0b0},{0, 0b0},{0, 0b0}}, + {{1, 0b0},{1, 0b1},{0, 0b0},{0, 0b0},{0, 0b0},{0, 0b0}}, + {{0, 0b0},{1, 0b1},{0, 0b0},{0, 0b0},{0, 0b0},{0, 0b0}} + }; + + ForwardInputStream inputStream(_packedData,0,_packedData.size(),true); + + MSBBitReader bitReader(inputStream); + auto readBits=[&](uint32_t count)->uint32_t + { + return bitReader.readBits8(count); + }; + auto readBit=[&]()->uint32_t + { + return bitReader.readBits8(1); + }; + + size_t rawSize=rawData.size(); + ForwardOutputStream outputStream(rawData,0,rawSize); + + OptionalHuffmanDecoder decoder; + { + uint32_t treeIndex=readBits(5); + for (uint32_t i=0;i<6;i++) + { + uint32_t length=treeDefinitions[treeIndex][i].length; + uint32_t code=treeDefinitions[treeIndex][i].code; + if (!length) + { + if (!i) decoder.setEmpty(0); + break; + } + if (treeIndex==17 && i<2) decoder.insert(HuffmanCode{length,code,i+3}); + else decoder.insert(HuffmanCode{length,code,i}); + } + } + + uint8_t dataMTFMap[256]; + createMTFMap(dataMTFMap); + + auto processOutput=[&](uint8_t value)->uint8_t + { + updateMTF(value,dataMTFMap); + return value; + }; + + while (!outputStream.eof()) + { + bool doCopy=true; + if (readBit()) + { + uint32_t count=readBits(2)+1; + if (count==4) + { + count=readBits(3)+4; + if (count==11) + { + count=readBits(4)+11; + if (count==25) + { + count=readBits(6)+25; + } else if (count==26) { + count=readBits(7)+89; + } + } + } + + count=std::min(count,uint32_t(rawSize-outputStream.getOffset())); + for (uint32_t i=0;i=0x240?readBit():0) + { + code=4; + if (offset<0x340) code=7; + else if (offset<0x440) code=8; + else if (offset<0x640) code=9; + } else { + code=offset>=0x40?readBit():0; + count=2; + } + } else { + if (offset>=0x40?!readBit():0) + { + code=3; + if (offset<0x140) code=6; + } else if (offset>=0xa40?readBit():1) { + code=2; + } else { + code=5; + if (offset<0xb40) code=10; + else if (offset<0xc40) code=11; + else if (offset<0xe40) code=12; + else if (offset<0x1240) code=13; + else if (offset<0x1a40) code=14; + } + } + if (code>=2) + { + count=readBits(2)+3; + if (count==6) + { + count=readBits(3)+6; + if (count==11) + { + count=readBits(2)+11; + } else if (count==12) { + count=readBits(3)+15; + } else if (count==13) { + count=readBits(6)+23; + if (count==85) { + count=readBits(5)+85; + } else if (count==86) + count=readBits(7)+117; + } + } + } + static const uint32_t distanceAdditions[15]={ + 1,0x41,1,0x41,0x241,0xa41,0x41,0x241,0x241,0x241,0xa41,0xa41,0xa41,0xa41,0xa41}; + static const uint32_t distanceBits[15]={ + 6,8,6,9,11,13,8,8,9,10,8,9,10,11,12}; + uint32_t distance=readBits(distanceBits[code])+distanceAdditions[code]; + + count=std::min(count,uint32_t(rawSize-outputStream.getOffset())); + outputStream.copy(distance,count,0x20); + const uint8_t *block=outputStream.history(count); + for (uint32_t i=0;i bitReader(inputStream); + auto readBits=[&](uint32_t count)->uint32_t + { + return bitReader.readBits8(count); + }; + auto readBit=[&]()->uint32_t + { + return bitReader.readBits8(1); + }; + + ForwardOutputStream outputStream(rawData,0,rawData.size()); + + OptionalHuffmanDecoder decoder; + OptionalHuffmanDecoder distanceDecoder; + + auto createDecoder=[&]()->bool + { + decoder.reset(); + + // codes beyond 29 are going to fault anyway, but maybe they are not used? + uint8_t symbols[31]; + uint32_t numCodes=readBits(5); + uint32_t minLength=readBits(3); + + bool ret=(numCodes>=10)&&(numCodes!=29||minLength); + + if (!minLength) + { + if (!numCodes) throw DecompressionError(); + decoder.setEmpty(numCodes-1); + } else { + uint32_t codeLength=readBits(3); + for (uint32_t i=0;iuint8_t + { + offset++; // we are interested offset after the update + updateMTF(value,dataMTFMap); + if (!(offset&0x3ffU)) + { + switch (offset>>10) + { + case 1: + if (distanceTreeRequired) createDistanceDecoder(6); + break; + + case 2: + if (distanceTreeRequired) createDistanceDecoder(7); + break; + + case 4: + if (readBit()) distanceTreeRequired=createDecoder(); + if (distanceTreeRequired) createDistanceDecoder(8); + break; + + default: + if (!(offset&0xfffU) && (offset>>12)>=2) + { + if (readBit()) + { + distanceTreeRequired=createDecoder(); + if (distanceTreeRequired) createDistanceDecoder(8); + } + } + break; + } + } + return value; + }; + + readBit(); // ignore first bit + distanceTreeRequired=createDecoder(); + if (distanceTreeRequired) createDistanceDecoder(5); + while (!outputStream.eof()) + { + uint32_t code=decoder.decode(readBit); + if (code<8) + { + static const uint32_t symbolAdditions[8]={0,8,16,32,64,96,128,192}; + static const uint32_t symbolBits[8]={3,3,4,5,5,5,6,6}; + outputStream.writeByte(processOutput(outputStream.getOffset(),decodeMTF(readBits(symbolBits[code])+symbolAdditions[code],dataMTFMap))); + } else { + code-=8; + + uint32_t count; + if (code<15) + { + count=code+2; + } else { + if (code>=21) throw DecompressionError(); + static const uint32_t countAdditions[6]={17,25,33,65,129,256}; + static const uint32_t countBits[6]={3,3,5,6,7,0}; + count=readBits(countBits[code-15])+countAdditions[code-15]; + } + + uint32_t distance; + if (!code) + { + distance=readBits(6)+1; + } else if (code<20) { + uint32_t tmp=distanceDecoder.decode(readBit); + if (!tmp) distance=readBits(6)+1; + else distance=readBits(tmp+5)+(1<<(tmp+5))+1; + } else distance=1; + + outputStream.copy(distance,count,0x20); + const uint8_t *block=outputStream.history(count); + size_t offset=outputStream.getOffset()-count; + for (uint32_t i=0;i MASHDecompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) +{ + return std::make_shared(hdr,recursionLevel,packedData,state,verify); +} + +MASHDecompressor::MASHDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) : + XPKDecompressor(recursionLevel), + _packedData(packedData) +{ + if (!detectHeaderXPK(hdr)) throw Decompressor::InvalidFormatError(); +} + +MASHDecompressor::~MASHDecompressor() +{ + // nothing needed +} + +const std::string &MASHDecompressor::getSubName() const noexcept +{ + static std::string name="XPK-MASH: LZRW-compressor"; + return name; +} + +void MASHDecompressor::decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) +{ + ForwardInputStream inputStream(_packedData,0,_packedData.size()); + MSBBitReader bitReader(inputStream); + auto readBits=[&](uint32_t count)->uint32_t + { + return bitReader.readBits8(count); + }; + auto readBit=[&]()->uint32_t + { + return bitReader.readBits8(1); + }; + auto readByte=[&]()->uint8_t + { + return inputStream.readByte(); + }; + + size_t rawSize=rawData.size(); + ForwardOutputStream outputStream(rawData,0,rawSize); + + HuffmanDecoder litDecoder + { + HuffmanCode{1,0b000000,0}, + HuffmanCode{2,0b000010,1}, + HuffmanCode{3,0b000110,2}, + HuffmanCode{4,0b001110,3}, + HuffmanCode{5,0b011110,4}, + HuffmanCode{6,0b111110,5}, + HuffmanCode{6,0b111111,6} + }; + + while (!outputStream.eof()) + { + uint32_t litLength=litDecoder.decode(readBit); + if (litLength==6) + { + uint32_t litBits; + for (litBits=1;litBits<=17;litBits++) if (!readBit()) break; + if (litBits==17) throw Decompressor::DecompressionError(); + litLength=readBits(litBits)+(1< &state,bool verify); + + virtual ~MASHDecompressor(); + + virtual const std::string &getSubName() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) override final; + + static bool detectHeaderXPK(uint32_t hdr) noexcept; + static std::shared_ptr create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + +private: + const Buffer &_packedData; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/MMCMPDecompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/MMCMPDecompressor.cpp new file mode 100644 index 00000000..49d8cbf2 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/MMCMPDecompressor.cpp @@ -0,0 +1,254 @@ +/* Copyright (C) Teemu Suutari */ + +#include + +#include "MMCMPDecompressor.hpp" +#include "InputStream.hpp" +#include "OutputStream.hpp" +#include "common/OverflowCheck.hpp" +#include "common/Common.hpp" + + +namespace ancient::internal +{ + +bool MMCMPDecompressor::detectHeader(uint32_t hdr) noexcept +{ + return hdr==FourCC("ziRC"); +} + +std::shared_ptr MMCMPDecompressor::create(const Buffer &packedData,bool exactSizeKnown,bool verify) +{ + return std::make_shared(packedData,exactSizeKnown,verify); +} + +MMCMPDecompressor::MMCMPDecompressor(const Buffer &packedData,bool exactSizeKnown,bool verify) : + _packedData(packedData) +{ + if (!detectHeader(packedData.readBE32(0)) || packedData.readBE32(4U)!=FourCC("ONia") || + packedData.readLE16(8U)!=14U || packedData.size()<24U) + throw InvalidFormatError(); + _version=packedData.readLE16(10U); + _blocks=packedData.readLE16(12U); + _blocksOffset=packedData.readLE32(18U); + _rawSize=packedData.readLE32(14U); + if (OverflowCheck::sum(_blocksOffset,uint32_t(_blocks)*4U)>packedData.size()) + throw InvalidFormatError(); + + _packedSize=0; + for (uint32_t i=0;i<_blocks;i++) + { + uint32_t blockAddr=packedData.readLE32(OverflowCheck::sum(_blocksOffset,i*4U)); + if (OverflowCheck::sum(blockAddr,20U)>=packedData.size()) + throw InvalidFormatError(); + uint32_t blockSize=packedData.readLE32(blockAddr+4U)+uint32_t(packedData.readLE16(blockAddr+12U))*8U+20U; + _packedSize=std::max(_packedSize,OverflowCheck::sum(blockAddr,blockSize)); + } + if (_packedSize>packedData.size()) + throw InvalidFormatError(); +} + +MMCMPDecompressor::~MMCMPDecompressor() +{ + // nothing needed +} + +const std::string &MMCMPDecompressor::getName() const noexcept +{ + static std::string name="MMCMP: Music Module Compressor"; + return name; +} + +size_t MMCMPDecompressor::getPackedSize() const noexcept +{ + return _packedSize; +} + +size_t MMCMPDecompressor::getRawSize() const noexcept +{ + return _rawSize; +} + +void MMCMPDecompressor::decompressImpl(Buffer &rawData,bool verify) +{ + if (rawData.size()<_rawSize) throw DecompressionError(); + // MMCMP allows gaps in data. Although not used in practice still we memset before decompressing to be sure + std::memset(rawData.data(),0,rawData.size()); + + uint8_t *rawDataPtr=rawData.data(); + for (uint32_t i=0;i<_blocks;i++) + { + uint32_t blockAddr=_packedData.readLE32(_blocksOffset+i*4U); + + uint32_t unpackedBlockSize=_packedData.readLE32(blockAddr); + uint32_t packedBlockSize=_packedData.readLE32(blockAddr+4U); + uint32_t fileChecksum=_packedData.readLE32(blockAddr+8U); + uint32_t subBlocks=_packedData.readLE16(blockAddr+12U); + uint16_t flags=_packedData.readLE16(blockAddr+14U); + + uint32_t packTableSize=_packedData.readLE16(blockAddr+16U); + if (packTableSize>packedBlockSize) + throw DecompressionError(); + uint16_t bitCount=_packedData.readLE16(blockAddr+18U); + + ForwardInputStream inputStream(_packedData,OverflowCheck::sum(blockAddr,subBlocks*8U,20U,packTableSize),OverflowCheck::sum(blockAddr,subBlocks*8U,20U,packedBlockSize)); + LSBBitReader bitReader(inputStream); + auto readBits=[&](uint32_t count)->uint32_t + { + return bitReader.readBits8(count); + }; + + uint32_t currentSubBlock=0; + uint32_t outputOffset=0,outputSize=0; + auto readNextSubBlock=[&]() + { + if (currentSubBlock>=subBlocks) + throw DecompressionError(); + outputOffset=_packedData.readLE32(blockAddr+currentSubBlock*8U+20U); + outputSize=_packedData.readLE32(blockAddr+currentSubBlock*8U+24U); + if (OverflowCheck::sum(outputOffset,outputSize)>_rawSize) + throw DecompressionError(); + currentSubBlock++; + }; + + uint32_t checksum=0,checksumPartial=0,checksumRot=0; + auto writeByte=[&](uint8_t value,bool allowOverrun=false) + { + while (!outputSize) + { + if (allowOverrun && currentSubBlock>=subBlocks) return; + readNextSubBlock(); + } + outputSize--; + rawDataPtr[outputOffset++]=value; + if (verify) + { + if (_version>=0x1310) + { + checksum^=value; + checksum=(checksum<<1)|(checksum>>31); + } else { + checksumPartial|=((uint32_t)value)<=8) + throw DecompressionError(); + uint8_t oldValue[2]={0,0}; + uint32_t chIndex=0; + const uint8_t *tablePtr=&_packedData[blockAddr+subBlocks*8U+20U]; + for (uint32_t j=0;j=valueThresholds[bitCount]) + { + uint32_t newBitCount=readBits(extraBits[bitCount])+((value-valueThresholds[bitCount])<=packTableSize) + throw DecompressionError(); + value=tablePtr[value]; + if (flags&0x2U) + { + // delta + value+=oldValue[chIndex]; + oldValue[chIndex]=value; + if (flags&0x100U) chIndex^=1U; // stereo + } + writeByte(value); + j++; + } + } else { + // 16 bit compression + + // shameless copy-paste from 8-bit variant, with minor changes + static const uint16_t valueThresholds[16]={ + 0x1U, 0x3U, 0x7U, 0xfU, 0x1eU, 0x3cU, 0x78U, 0xf0U, + 0x1f0U, 0x3f0U, 0x7f0U, 0xff0U,0x1ff0U,0x3ff0U,0x7ff0U,0xfff0U + }; + static const uint8_t extraBits[16]={4,4,4,4, 3,2,1,0, 0,0,0,0, 0,0,0,0}; + + if (bitCount>=16) + throw DecompressionError(); + int16_t oldValue[2]={0,0}; + uint32_t chIndex=0; + for (uint32_t j=0;j=valueThresholds[bitCount]) + { + uint32_t newBitCount=readBits(extraBits[bitCount])+((value-valueThresholds[bitCount])<>=1; + if (flags&0x2U) + { + // delta + value+=oldValue[chIndex]; + oldValue[chIndex]=value; + if (flags&0x100U) chIndex^=1U; // stereo + } else if (!(flags&0x200U)) value^=0x8000U; // abs16 + if (flags&0x400U) + { + // big ending + writeByte(value>>8U); + writeByte(value,true); + } else { + // little endian + writeByte(value); + writeByte(value>>8U,true); + } + j+=2; + } + } + if (verify && checksum!=fileChecksum) + throw VerificationError(); + } +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/MMCMPDecompressor.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/MMCMPDecompressor.hpp new file mode 100644 index 00000000..8c9a497f --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/MMCMPDecompressor.hpp @@ -0,0 +1,39 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef MMCMPDECOMPRESSOR_HPP +#define MMCMPDECOMPRESSOR_HPP + +#include "Decompressor.hpp" + +namespace ancient::internal +{ + +class MMCMPDecompressor : public Decompressor +{ +public: + MMCMPDecompressor(const Buffer &packedData,bool exactSizeKnown,bool verify); + + virtual ~MMCMPDecompressor(); + + virtual const std::string &getName() const noexcept override final; + virtual size_t getPackedSize() const noexcept override final; + virtual size_t getRawSize() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,bool verify) override final; + + static bool detectHeader(uint32_t hdr) noexcept; + static std::shared_ptr create(const Buffer &packedData,bool exactSizeKnown,bool verify); + +private: + const Buffer &_packedData; + + uint32_t _packedSize=0; + uint32_t _rawSize=0; + uint32_t _blocksOffset=0; + uint32_t _blocks=0; + uint16_t _version=0; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/NONEDecompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/NONEDecompressor.cpp new file mode 100644 index 00000000..22ed94f1 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/NONEDecompressor.cpp @@ -0,0 +1,47 @@ +/* Copyright (C) Teemu Suutari */ + +#include + +#include "NONEDecompressor.hpp" +#include "common/Common.hpp" + + +namespace ancient::internal +{ + +bool NONEDecompressor::detectHeaderXPK(uint32_t hdr) noexcept +{ + return hdr==FourCC("NONE"); +} + +std::shared_ptr NONEDecompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) +{ + return std::make_shared(hdr,recursionLevel,packedData,state,verify); +} + +NONEDecompressor::NONEDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) : + XPKDecompressor(recursionLevel), + _packedData(packedData) +{ + if (!detectHeaderXPK(hdr)) throw Decompressor::InvalidFormatError(); +} + +NONEDecompressor::~NONEDecompressor() +{ + // nothing needed +} + +const std::string &NONEDecompressor::getSubName() const noexcept +{ + static std::string name="XPK-NONE: Null compressor"; + return name; +} + +void NONEDecompressor::decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) +{ + if (rawData.size()!=_packedData.size()) throw Decompressor::DecompressionError(); + + std::memcpy(rawData.data(),_packedData.data(),_packedData.size()); +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/NONEDecompressor.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/NONEDecompressor.hpp new file mode 100644 index 00000000..978e6a6d --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/NONEDecompressor.hpp @@ -0,0 +1,31 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef NONEDECOMPRESSOR_HPP +#define NONEDECOMPRESSOR_HPP + +#include "XPKDecompressor.hpp" + +namespace ancient::internal +{ + +class NONEDecompressor : public XPKDecompressor +{ +public: + NONEDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + + virtual ~NONEDecompressor(); + + virtual const std::string &getSubName() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) override final; + + static bool detectHeaderXPK(uint32_t hdr) noexcept; + static std::shared_ptr create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + +private: + const Buffer &_packedData; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/NUKEDecompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/NUKEDecompressor.cpp new file mode 100644 index 00000000..25cebbc9 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/NUKEDecompressor.cpp @@ -0,0 +1,131 @@ +/* Copyright (C) Teemu Suutari */ + +#include + +#include "NUKEDecompressor.hpp" +#include "DLTADecode.hpp" +#include "InputStream.hpp" +#include "OutputStream.hpp" +#include "common/Common.hpp" + + +namespace ancient::internal +{ + +bool NUKEDecompressor::detectHeaderXPK(uint32_t hdr) noexcept +{ + return hdr==FourCC("NUKE") || hdr==FourCC("DUKE"); +} + +std::shared_ptr NUKEDecompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) +{ + return std::make_shared(hdr,recursionLevel,packedData,state,verify); +} + +NUKEDecompressor::NUKEDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) : + XPKDecompressor(recursionLevel), + _packedData(packedData) +{ + if (!detectHeaderXPK(hdr)) throw Decompressor::InvalidFormatError(); + if (hdr==FourCC("DUKE")) _isDUKE=true; +} + +NUKEDecompressor::~NUKEDecompressor() +{ + // nothing needed +} + +const std::string &NUKEDecompressor::getSubName() const noexcept +{ + static std::string nameN="XPK-NUKE: LZ77-compressor"; + static std::string nameD="XPK-DUKE: LZ77-compressor with delta encoding"; + return (_isDUKE)?nameD:nameN; +} + +void NUKEDecompressor::decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) +{ + // there are 2 streams, reverse stream for bytes and + // normal stream for bits, the bit stream is divided + // into single bit, 2 bit, 4 bit and random accumulator + ForwardInputStream forwardInputStream(_packedData,0,_packedData.size()); + BackwardInputStream backwardInputStream(_packedData,0,_packedData.size()); + forwardInputStream.link(backwardInputStream); + backwardInputStream.link(forwardInputStream); + MSBBitReader bit1Reader(forwardInputStream); + MSBBitReader bit2Reader(forwardInputStream); + LSBBitReader bit4Reader(forwardInputStream); + MSBBitReader bitXReader(forwardInputStream); + auto readBit=[&]()->uint32_t + { + return bit1Reader.readBitsBE16(1); + }; + auto read2Bits=[&]()->uint32_t + { + return bit2Reader.readBitsBE16(2); + }; + auto read4Bits=[&]()->uint32_t + { + return bit4Reader.readBitsBE32(4); + }; + auto readBits=[&](uint32_t count)->uint32_t + { + return bitXReader.readBitsBE16(count); + }; + auto readByte=[&]()->uint8_t + { + return backwardInputStream.readByte(); + }; + + ForwardOutputStream outputStream(rawData,0,rawData.size()); + + for (;;) + { + if (!readBit()) + { + uint32_t count=0; + if (readBit()) + { + count=1; + } else { + uint32_t tmp; + do { + tmp=read2Bits(); + if (tmp) count+=5-tmp; + else count+=3; + } while (!tmp); + } + for (uint32_t i=0;i &state,bool verify); + + virtual ~NUKEDecompressor(); + + virtual const std::string &getSubName() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) override final; + + static bool detectHeaderXPK(uint32_t hdr) noexcept; + static std::shared_ptr create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + +private: + const Buffer &_packedData; + + bool _isDUKE=false; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/OutputStream.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/OutputStream.cpp new file mode 100644 index 00000000..c2bad30a --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/OutputStream.cpp @@ -0,0 +1,124 @@ +/* Copyright (C) Teemu Suutari */ + +#include + +#include + +#include "OutputStream.hpp" +// for exceptions +#include "Decompressor.hpp" +#include "common/Common.hpp" +#include "common/OverflowCheck.hpp" + + +namespace ancient::internal +{ + +ForwardOutputStream::ForwardOutputStream(Buffer &buffer,size_t startOffset,size_t endOffset) : + _bufPtr(buffer.data()), + _startOffset(startOffset), + _currentOffset(startOffset), + _endOffset(endOffset) +{ + if (_startOffset>_endOffset || _currentOffset>buffer.size() || _endOffset>buffer.size()) throw Decompressor::DecompressionError(); +} + +ForwardOutputStream::~ForwardOutputStream() +{ + // nothing needed +} + +void ForwardOutputStream::writeByte(uint8_t value) +{ + if (_currentOffset>=_endOffset) throw Decompressor::DecompressionError(); + _bufPtr[_currentOffset++]=value; +} + +uint8_t ForwardOutputStream::copy(size_t distance,size_t count) +{ + if (!distance || OverflowCheck::sum(_startOffset,distance)>_currentOffset || OverflowCheck::sum(_currentOffset,count)>_endOffset) throw Decompressor::DecompressionError(); + uint8_t ret=0; + for (size_t i=0;i_endOffset) throw Decompressor::DecompressionError(); + size_t prevCount=0; + uint8_t ret=0; + if (OverflowCheck::sum(_startOffset,distance)>_currentOffset) + { + size_t prevSize=prevBuffer.size(); + if (_startOffset+distance>_currentOffset+prevSize) throw Decompressor::DecompressionError(); + size_t prevDist=_startOffset+distance-_currentOffset; + prevCount=std::min(count,prevDist); + const uint8_t *prev=&prevBuffer[prevSize-prevDist]; + for (size_t i=0;i_endOffset) throw Decompressor::DecompressionError(); + size_t prevCount=0; + uint8_t ret=0; + if (OverflowCheck::sum(_startOffset,distance)>_currentOffset) + { + prevCount=std::min(count,_startOffset+distance-_currentOffset); + for (size_t i=0;i_currentOffset) throw Decompressor::DecompressionError(); + return &_bufPtr[_currentOffset-distance]; +} + +void ForwardOutputStream::produce(const uint8_t *src,size_t bytes) +{ + if (OverflowCheck::sum(_currentOffset,bytes)>_endOffset) throw Decompressor::DecompressionError(); + std::memcpy(&_bufPtr[_currentOffset],src,bytes); + _currentOffset+=bytes; +} + +BackwardOutputStream::BackwardOutputStream(Buffer &buffer,size_t startOffset,size_t endOffset) : + _bufPtr(buffer.data()), + _startOffset(startOffset), + _currentOffset(endOffset), + _endOffset(endOffset) +{ + if (_startOffset>_endOffset || _currentOffset>buffer.size() || _endOffset>buffer.size()) throw Decompressor::DecompressionError(); +} + +BackwardOutputStream::~BackwardOutputStream() +{ + // nothing needed +} + +void BackwardOutputStream::writeByte(uint8_t value) +{ + if (_currentOffset<=_startOffset) throw Decompressor::DecompressionError(); + _bufPtr[--_currentOffset]=value; +} + +uint8_t BackwardOutputStream::copy(size_t distance,size_t count) +{ + if (!distance || OverflowCheck::sum(_startOffset,count)>_currentOffset || OverflowCheck::sum(_currentOffset,distance)>_endOffset) throw Decompressor::DecompressionError(); + uint8_t ret=0; + for (size_t i=0;i +#include + +#include "common/Buffer.hpp" + +namespace ancient::internal +{ + +class ForwardOutputStream +{ +public: + ForwardOutputStream(Buffer &buffer,size_t startOffset,size_t endOffset); + ~ForwardOutputStream(); + + void writeByte(uint8_t value); + + uint8_t copy(size_t distance,size_t count); + uint8_t copy(size_t distance,size_t count,const Buffer &prevBuffer); + uint8_t copy(size_t distance,size_t count,uint8_t defaultChar); + const uint8_t *history(size_t distance) const; + void produce(const uint8_t *src,size_t bytes); + + bool eof() const { return _currentOffset==_endOffset; } + size_t getOffset() const { return _currentOffset; } + size_t getEndOffset() const { return _endOffset; } + +private: + uint8_t *_bufPtr; + size_t _startOffset; + size_t _currentOffset; + size_t _endOffset; +}; + +class BackwardOutputStream +{ +public: + BackwardOutputStream(Buffer &buffer,size_t startOffset,size_t endOffset); + ~BackwardOutputStream(); + + void writeByte(uint8_t value); + + uint8_t copy(size_t distance,size_t count); + + bool eof() const { return _currentOffset==_startOffset; } + size_t getOffset() const { return _currentOffset; } + +private: + uint8_t *_bufPtr; + size_t _startOffset; + size_t _currentOffset; + size_t _endOffset; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/PPDecompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/PPDecompressor.cpp new file mode 100644 index 00000000..f050ea91 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/PPDecompressor.cpp @@ -0,0 +1,192 @@ +/* Copyright (C) Teemu Suutari */ + +#include "PPDecompressor.hpp" +#include "InputStream.hpp" +#include "OutputStream.hpp" +#include "common/Common.hpp" + + +namespace ancient::internal +{ + +PPDecompressor::PPState::PPState(uint32_t mode) : + _cachedMode(mode) +{ + // nothing needed +} + +PPDecompressor::PPState::~PPState() +{ + // nothing needed +} + +bool PPDecompressor::detectHeader(uint32_t hdr) noexcept +{ + return (hdr==FourCC("PP11") || hdr==FourCC("PP20")); +} + +bool PPDecompressor::detectHeaderXPK(uint32_t hdr) noexcept +{ + return hdr==FourCC("PWPK"); +} + +std::shared_ptr PPDecompressor::create(const Buffer &packedData,bool exactSizeKnown,bool verify) +{ + return std::make_shared(packedData,exactSizeKnown,verify); +} + +std::shared_ptr PPDecompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) +{ + return std::make_shared(hdr,recursionLevel,packedData,state,verify); +} + +PPDecompressor::PPDecompressor(const Buffer &packedData,bool exactSizeKnown,bool verify) : + _packedData(packedData) +{ + if (!exactSizeKnown || packedData.size()<0x10) + throw InvalidFormatError(); // no scanning support + _dataStart=_packedData.size()-4; + + uint32_t hdr=packedData.readBE32(0); + if (!detectHeader(hdr)) throw InvalidFormatError(); + uint32_t mode=packedData.readBE32(4); + if (mode!=0x9090909 && mode!=0x90a0a0a && mode!=0x90a0b0b && mode!=0x90a0c0c && mode!=0x90a0c0d) throw InvalidFormatError(); + for (uint32_t i=0;i<4;i++) + { + _modeTable[i]=mode>>24; + mode<<=8; + } + + uint32_t tmp=packedData.readBE32(_dataStart); + + _rawSize=tmp>>8; + _startShift=tmp&0xff; + if (!_rawSize || _startShift>=0x20 || + _rawSize>getMaxRawSize()) throw InvalidFormatError(); +} + +PPDecompressor::PPDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) : + XPKDecompressor(recursionLevel), + _packedData(packedData) +{ + if (!detectHeaderXPK(hdr) || packedData.size()<0x10) + throw InvalidFormatError(); + _dataStart=_packedData.size()-4; + + uint32_t mode; + if (state.get()) + { + mode=static_cast(state.get())->_cachedMode; + } else { + mode=packedData.readBE32(_dataStart); + if (mode>4) throw InvalidFormatError(); + state.reset(new PPState(mode)); + _dataStart-=4; + } + + static const uint32_t modeMap[5]={0x9090909,0x90a0a0a,0x90a0b0b,0x90a0c0c,0x90a0c0d}; + mode=modeMap[mode]; + for (uint32_t i=0;i<4;i++) + { + _modeTable[i]=mode>>24; + mode<<=8; + } + + uint32_t tmp=packedData.readBE32(_dataStart); + + _rawSize=tmp>>8; + _startShift=tmp&0xff; + if (!_rawSize || _startShift>=0x20 || _rawSize>getMaxRawSize()) + throw InvalidFormatError(); + + _isXPK=true; +} + +PPDecompressor::~PPDecompressor() +{ + // nothing needed +} + +const std::string &PPDecompressor::getName() const noexcept +{ + static std::string name="PP: PowerPacker"; + return name; +} + +const std::string &PPDecompressor::getSubName() const noexcept +{ + static std::string name="XPK-PWPK: PowerPacker"; + return name; +} + +size_t PPDecompressor::getPackedSize() const noexcept +{ + return 0; +} + +size_t PPDecompressor::getRawSize() const noexcept +{ + return _rawSize; +} + +void PPDecompressor::decompressImpl(Buffer &rawData,bool verify) +{ + if (rawData.size()<_rawSize) throw DecompressionError(); + + BackwardInputStream inputStream(_packedData,_isXPK?0:8,_dataStart); + LSBBitReader bitReader(inputStream); + auto readBits=[&](uint32_t count)->uint32_t + { + return rotateBits(bitReader.readBitsBE32(count),count); + }; + auto readBit=[&]()->uint32_t + { + return bitReader.readBitsBE32(1); + }; + readBits(_startShift); + + BackwardOutputStream outputStream(rawData,0,_rawSize); + + for (;;) + { + if (!readBit()) + { + uint32_t count=1; + // This does not make much sense I know. But it is what it is... + for (;;) + { + uint32_t tmp=readBits(2); + count+=tmp; + if (tmp<3) break; + } + for (uint32_t i=0;i &state,bool verify); + virtual ~PPDecompressor(); + + virtual const std::string &getName() const noexcept override final; + virtual const std::string &getSubName() const noexcept override final; + + virtual size_t getPackedSize() const noexcept override final; + virtual size_t getRawSize() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,bool verify) override final; + virtual void decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) override final; + + static bool detectHeader(uint32_t hdr) noexcept; + static bool detectHeaderXPK(uint32_t hdr) noexcept; + + static std::shared_ptr create(const Buffer &packedData,bool exactSizeKnown,bool verify); + static std::shared_ptr create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + +private: + const Buffer &_packedData; + + size_t _dataStart=0; + size_t _rawSize=0; + uint8_t _startShift=0; + uint8_t _modeTable[4]; + bool _isXPK=false; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/RAKEDecompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/RAKEDecompressor.cpp new file mode 100644 index 00000000..1e07c13f --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/RAKEDecompressor.cpp @@ -0,0 +1,147 @@ +/* Copyright (C) Teemu Suutari */ + +#include "RAKEDecompressor.hpp" +#include "HuffmanDecoder.hpp" +#include "InputStream.hpp" +#include "OutputStream.hpp" +#include "common/Common.hpp" + + +namespace ancient::internal +{ + +bool RAKEDecompressor::detectHeaderXPK(uint32_t hdr) noexcept +{ + return (hdr==FourCC("FRHT") || hdr==FourCC("RAKE")); +} + +std::shared_ptr RAKEDecompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) +{ + return std::make_shared(hdr,recursionLevel,packedData,state,verify); +} + +RAKEDecompressor::RAKEDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) : + XPKDecompressor(recursionLevel), + _packedData(packedData), + _isRAKE(hdr==FourCC("RAKE")) +{ + if (!detectHeaderXPK(hdr) || packedData.size()<4) + throw Decompressor::InvalidFormatError(); + + _midStreamOffset=packedData.readBE16(2); + if (_midStreamOffset>=packedData.size()) throw Decompressor::InvalidFormatError(); +} + +RAKEDecompressor::~RAKEDecompressor() +{ + // nothing needed +} + +const std::string &RAKEDecompressor::getSubName() const noexcept +{ + static std::string nameFRHT="XPK-FRHT: LZ77-compressor"; + static std::string nameRAKE="XPK-RAKE: LZ77-compressor"; + return (_isRAKE)?nameRAKE:nameFRHT; +} + +void RAKEDecompressor::decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) +{ + // 2 streams + // 1st: bit stream starting from _midStreamOffset(+1) going to packedSize + // 2nd: byte stream starting from _midStreamOffset going backwards to 4 + ForwardInputStream forwardInputStream(_packedData,_midStreamOffset+(_midStreamOffset&1),_packedData.size()); + BackwardInputStream backwardInputStream(_packedData,4,_midStreamOffset); + MSBBitReader bitReader(forwardInputStream); + auto readBits=[&](uint32_t count)->uint32_t + { + return bitReader.readBitsBE32(count); + }; + auto readBit=[&]()->uint32_t + { + return bitReader.readBitsBE32(1); + }; + auto readByte=[&]()->uint8_t + { + return backwardInputStream.readByte(); + }; + { + uint16_t tmp=_packedData.readBE16(0); + if (tmp>32) throw Decompressor::DecompressionError(); + const uint8_t *buf=forwardInputStream.consume(4); + uint32_t content=(uint32_t(buf[0])<<24)|(uint32_t(buf[1])<<16)| + (uint32_t(buf[2])<<8)|uint32_t(buf[3]); + bitReader.reset(content>>tmp,32-tmp); + } + + BackwardOutputStream outputStream(rawData,0,rawData.size()); + + HuffmanDecoder lengthDecoder; + // is there some logic into this? + static const uint8_t decTable[255][2]={ + { 1,0x01},{ 3,0x03},{ 5,0x05},{ 6,0x09},{ 7,0x0c},{ 9,0x13},{12,0x34},{18,0xc0}, + {18,0xc2},{18,0xc3},{18,0xc6},{16,0x79},{18,0xc7},{18,0xd6},{18,0xd7},{18,0xd8}, + {17,0xa8},{17,0x92},{17,0x8a},{17,0x82},{16,0x6c},{17,0x94},{18,0xda},{18,0xca}, + {16,0x7b},{13,0x36},{13,0x39},{13,0x48},{14,0x49},{14,0x50},{15,0x62},{15,0x5e}, + {16,0x6f},{17,0x83},{17,0x87},{15,0x56},{11,0x21},{12,0x31},{13,0x38},{13,0x3d}, + { 8,0x0f},{ 4,0x04},{ 6,0x08},{10,0x1c},{12,0x27},{13,0x42},{13,0x3a},{12,0x30}, + {12,0x32},{ 9,0x16},{ 8,0x11},{ 7,0x0b},{ 5,0x06},{10,0x19},{10,0x1a},{10,0x18}, + {11,0x26},{17,0x98},{17,0x99},{17,0x9b},{17,0x9e},{17,0x9f},{17,0xa6},{16,0x73}, + {17,0x7f},{17,0x81},{17,0x84},{17,0x85},{15,0x5d},{14,0x4d},{14,0x4f},{13,0x45}, + {13,0x3c},{ 9,0x17},{10,0x1d},{12,0xff},{13,0x41},{17,0x8c},{18,0xaa},{19,0xdb}, + {19,0xdc},{16,0x77},{15,0x63},{16,0x7c},{16,0x76},{16,0x71},{16,0x7d},{12,0x2c}, + {13,0x3b},{16,0x7a},{16,0x75},{15,0x55},{15,0x60},{16,0x74},{17,0xa4},{18,0xab}, + {18,0xac},{ 7,0x0a},{ 6,0x07},{ 9,0x15},{11,0x20},{11,0x24},{10,0x1b},{ 8,0x10}, + { 9,0x12},{12,0x33},{14,0x4b},{15,0x53},{19,0xdd},{19,0xde},{18,0xad},{19,0xdf}, + {19,0xe0},{18,0xae},{17,0x88},{18,0xaf},{19,0xe1},{19,0xe2},{13,0x37},{12,0x2e}, + {18,0xb0},{18,0xb1},{19,0xe3},{19,0xe4},{18,0xb2},{18,0xb3},{19,0xe5},{19,0xe6}, + {19,0xe7},{19,0xe8},{18,0xb4},{17,0x9a},{18,0xb5},{18,0xb6},{18,0xb7},{19,0xe9}, + {19,0xea},{18,0xb8},{19,0xeb},{19,0xec},{19,0xed},{19,0xee},{18,0xb9},{19,0xef}, + {19,0xf0},{18,0xbb},{18,0xbc},{19,0xf1},{19,0xf2},{18,0xbd},{18,0xbe},{19,0xf3}, + {19,0xf4},{18,0xbf},{18,0xc1},{19,0xf5},{19,0xf6},{18,0xc4},{18,0xc5},{17,0x95}, + {18,0xc8},{18,0xc9},{19,0xf7},{19,0xf8},{18,0xcb},{18,0xcc},{19,0xf9},{19,0xfa}, + {18,0xcd},{18,0xce},{17,0x96},{18,0xcf},{18,0xd0},{19,0xfb},{19,0xfc},{18,0xd1}, + {18,0xd2},{18,0xd3},{17,0x9c},{17,0x9d},{18,0xd4},{18,0xd5},{17,0xa0},{17,0xa1}, + {17,0xa2},{17,0xa3},{17,0xa5},{19,0xfd},{19,0xfe},{18,0xd9},{17,0xa7},{16,0x66}, + {15,0x54},{15,0x57},{16,0x6b},{16,0x68},{14,0x4c},{14,0x4e},{12,0x28},{11,0x23}, + { 8,0x0e},{ 7,0x0d},{10,0x1f},{13,0x47},{15,0x64},{15,0x58},{15,0x59},{15,0x5a}, + {12,0x29},{13,0x3e},{15,0x5f},{17,0x8e},{18,0xba},{18,0xa9},{16,0x70},{14,0x4a}, + {12,0x2a},{ 9,0x14},{11,0x22},{12,0x2f},{16,0x7e},{16,0x67},{16,0x69},{16,0x65}, + {15,0x51},{16,0x78},{16,0x6a},{13,0x46},{11,0x25},{16,0x72},{16,0x6e},{15,0x5b}, + {15,0x61},{15,0x52},{13,0x40},{13,0x43},{13,0x44},{13,0x3f},{15,0x5c},{17,0x93}, + {17,0x80},{17,0x8d},{17,0x8b},{17,0x86},{17,0x89},{17,0x97},{17,0x8f},{17,0x90}, + {17,0x91},{16,0x6d},{12,0x2b},{12,0x2d},{12,0x35},{10,0x1e},{ 3,0x02}}; + + uint32_t hufCode=0; + for (auto &it: decTable) + { + lengthDecoder.insert(HuffmanCode{it[0],hufCode>>(32-it[0]),it[1]}); + hufCode+=1<<(32-it[0]); + } + + while (!outputStream.eof()) + { + if (!readBit()) + { + outputStream.writeByte(readByte()); + } else { + uint32_t count=lengthDecoder.decode(readBit); + count+=2; + + uint32_t distance; + if (!readBit()) + { + distance=uint32_t(readByte())+1; + } else { + if (!readBit()) + { + distance=((readBits(3)<<8)|uint32_t(readByte()))+0x101; + } else { + distance=((readBits(6)<<8)|uint32_t(readByte()))+0x901; + } + } + outputStream.copy(distance,count); + } + } +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/RAKEDecompressor.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/RAKEDecompressor.hpp new file mode 100644 index 00000000..562aafea --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/RAKEDecompressor.hpp @@ -0,0 +1,34 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef RAKEDECOMPRESSOR_HPP +#define RAKEDECOMPRESSOR_HPP + +#include "XPKDecompressor.hpp" + +namespace ancient::internal +{ + +class RAKEDecompressor : public XPKDecompressor +{ +public: + RAKEDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + + virtual ~RAKEDecompressor(); + + virtual const std::string &getSubName() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) override final; + + static bool detectHeaderXPK(uint32_t hdr) noexcept; + static std::shared_ptr create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + +private: + const Buffer &_packedData; + + bool _isRAKE; + size_t _midStreamOffset=0; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/RDCNDecompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/RDCNDecompressor.cpp new file mode 100644 index 00000000..ec2e75a1 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/RDCNDecompressor.cpp @@ -0,0 +1,101 @@ +/* Copyright (C) Teemu Suutari */ + +#include "RDCNDecompressor.hpp" +#include "InputStream.hpp" +#include "OutputStream.hpp" +#include "common/Common.hpp" + + +namespace ancient::internal +{ + +bool RDCNDecompressor::detectHeaderXPK(uint32_t hdr) noexcept +{ + return hdr==FourCC("RDCN"); +} + +std::shared_ptr RDCNDecompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) +{ + return std::make_shared(hdr,recursionLevel,packedData,state,verify); +} + +RDCNDecompressor::RDCNDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) : + XPKDecompressor(recursionLevel), + _packedData(packedData) +{ + if (!detectHeaderXPK(hdr)) throw Decompressor::InvalidFormatError(); +} + +RDCNDecompressor::~RDCNDecompressor() +{ + // nothing needed +} + +const std::string &RDCNDecompressor::getSubName() const noexcept +{ + static std::string name="XPK-RDCN: Ross data compression"; + return name; +} + +void RDCNDecompressor::decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) +{ + ForwardInputStream inputStream(_packedData,0,_packedData.size()); + MSBBitReader bitReader(inputStream); + auto readBit=[&]()->uint32_t + { + return bitReader.readBitsBE16(1); + }; + auto readByte=[&]()->uint8_t + { + return inputStream.readByte(); + }; + + ForwardOutputStream outputStream(rawData,0,rawData.size()); + + while (!outputStream.eof()) + { + if (!readBit()) + { + outputStream.writeByte(readByte()); + } else { + uint8_t tmp=readByte(); + uint32_t count=tmp&0xf; + uint32_t code=tmp>>4; + uint32_t distance=0; + uint8_t repeatChar=0; + bool doRLE=false; + switch (code) + { + case 0: + repeatChar=readByte(); + count+=3; + doRLE=true; + break; + + case 1: + count=(count|(uint32_t(readByte())<<4))+19; + repeatChar=readByte(); + doRLE=true; + break; + + case 2: + distance=(count|(uint32_t(readByte())<<4))+3; + count=uint32_t(readByte())+16; + break; + + default: /* 3 to 15 */ + distance=(count|(uint32_t(readByte())<<4))+3; + count=code; + break; + } + if (doRLE) + { + for (uint32_t i=0;i &state,bool verify); + + virtual ~RDCNDecompressor(); + + virtual const std::string &getSubName() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) override final; + + static bool detectHeaderXPK(uint32_t hdr) noexcept; + static std::shared_ptr create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + +private: + const Buffer &_packedData; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/RLENDecompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/RLENDecompressor.cpp new file mode 100644 index 00000000..6b1b0209 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/RLENDecompressor.cpp @@ -0,0 +1,62 @@ +/* Copyright (C) Teemu Suutari */ + +#include "RLENDecompressor.hpp" +#include "InputStream.hpp" +#include "OutputStream.hpp" +#include "common/Common.hpp" + + +namespace ancient::internal +{ + +bool RLENDecompressor::detectHeaderXPK(uint32_t hdr) noexcept +{ + return hdr==FourCC("RLEN"); +} + +std::shared_ptr RLENDecompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) +{ + return std::make_shared(hdr,recursionLevel,packedData,state,verify); +} + +RLENDecompressor::RLENDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) : + XPKDecompressor(recursionLevel), + _packedData(packedData) +{ + if (!detectHeaderXPK(hdr)) throw Decompressor::InvalidFormatError(); +} + +RLENDecompressor::~RLENDecompressor() +{ + // nothing needed +} + +const std::string &RLENDecompressor::getSubName() const noexcept +{ + static std::string name="XPK-RLEN: RLE-compressor"; + return name; +} + +void RLENDecompressor::decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) +{ + ForwardInputStream inputStream(_packedData,0,_packedData.size()); + ForwardOutputStream outputStream(rawData,0,rawData.size()); + + while (!outputStream.eof()) + { + uint32_t count=uint32_t(inputStream.readByte()); + if (count<128) + { + if (!count) throw Decompressor::DecompressionError(); // lets have this as error... + for (uint32_t i=0;i &state,bool verify); + + virtual ~RLENDecompressor(); + + virtual const std::string &getSubName() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) override final; + + static bool detectHeaderXPK(uint32_t hdr) noexcept; + static std::shared_ptr create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + +private: + const Buffer &_packedData; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/RNCDecompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/RNCDecompressor.cpp new file mode 100644 index 00000000..83d82dfd --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/RNCDecompressor.cpp @@ -0,0 +1,457 @@ +/* Copyright (C) Teemu Suutari */ + +#include + +#include "RNCDecompressor.hpp" +#include "HuffmanDecoder.hpp" +#include "InputStream.hpp" +#include "OutputStream.hpp" +#include "common/CRC16.hpp" +#include "common/OverflowCheck.hpp" +#include "common/Common.hpp" + +// This allows decompression of pc compressed files from unonfficial (and unpatched) compressor +// PC games do not need chunk count, and are happy to read these files. +// Official tools put it and amiga decompressors require it +#define ALLOW_MISSING_CHUNKS 1 + +namespace ancient::internal +{ + +bool RNCDecompressor::detectHeader(uint32_t hdr) noexcept +{ + return hdr==FourCC("RNC\001") || hdr==FourCC("RNC\002"); +} + +std::shared_ptr RNCDecompressor::create(const Buffer &packedData,bool exactSizeKnown,bool verify) +{ + return std::make_shared(packedData,verify); +} + +RNCDecompressor::RNCDecompressor(const Buffer &packedData,bool verify) : + _packedData(packedData) +{ + uint32_t hdr=packedData.readBE32(0); + _rawSize=packedData.readBE32(4); + _packedSize=packedData.readBE32(8); + if (!_rawSize || !_packedSize || + _rawSize>getMaxRawSize() || _packedSize>getMaxPackedSize()) throw InvalidFormatError(); + + bool verified=false; + if (hdr==FourCC("RNC\001")) + { + // now detect between old and new version + // since the old and the new version share the same id, there is no foolproof way + // to tell them apart. It is easier to prove that it is not something by finding + // specific invalid bitstream content. + + // well, this is silly though but lets assume someone has made old format RNC1 with total size less than 19 + if (packedData.size()<19) + { + _ver=Version::RNC1Old; + } else { + uint8_t newStreamStart=packedData.read8(18); + uint8_t oldStreamStart=packedData.read8(_packedSize+11); + + // Check that stream starts with a literal(s) + if (!(oldStreamStart&0x80)) + _ver=Version::RNC1New; + + // New stream have two bits in start as a filler on new stream. Those are always 0 + // (although this is not strictly mandated) + // + + // Even though it is possible to make new RNC1 stream which starts with zero literal table size, + // it is extremely unlikely + else if ((newStreamStart&3) || !(newStreamStart&0x7c)) + _ver=Version::RNC1Old; + + // now the last resort: check CRC. + else if (_packedData.size()>=_packedSize+18 && CRC16(_packedData,18,_packedSize,0)==packedData.readBE16(14)) + { + _ver=Version::RNC1New; + verified=true; + } else _ver=Version::RNC1Old; + } + } else if (hdr==FourCC("RNC\002")) { + _ver=Version::RNC2; + } else throw InvalidFormatError(); + + uint32_t hdrSize=(_ver==Version::RNC1Old)?12:18; + if (OverflowCheck::sum(_packedSize,hdrSize)>packedData.size()) throw InvalidFormatError(); + + if (_ver!=Version::RNC1Old) + { + _rawCRC=packedData.readBE16(12); + _chunks=packedData.read8(17); + if (verify && !verified) + { + if (CRC16(_packedData,18,_packedSize,0)!=packedData.readBE16(14)) + throw VerificationError(); + } + } +} + +RNCDecompressor::~RNCDecompressor() +{ + // nothing needed +} + +const std::string &RNCDecompressor::getName() const noexcept +{ + static std::string names[3]={ + "RNC1: Rob Northen RNC1 Compressor (old)", + "RNC1: Rob Northen RNC1 Compressor ", + "RNC2: Rob Northen RNC2 Compressor"}; + return names[static_cast(_ver)]; +} + +size_t RNCDecompressor::getPackedSize() const noexcept +{ + if (_ver==Version::RNC1Old) return _packedSize+12; + else return _packedSize+18; +} + +size_t RNCDecompressor::getRawSize() const noexcept +{ + return _rawSize; +} + +void RNCDecompressor::decompressImpl(Buffer &rawData,bool verify) +{ + if (rawData.size()<_rawSize) throw DecompressionError(); + + switch (_ver) + { + case Version::RNC1Old: + return RNC1DecompressOld(rawData,verify); + + case Version::RNC1New: + return RNC1DecompressNew(rawData,verify); + + case Version::RNC2: + return RNC2Decompress(rawData,verify); + + default: + throw DecompressionError(); + } +} + +void RNCDecompressor::RNC1DecompressOld(Buffer &rawData,bool verify) +{ + BackwardInputStream inputStream(_packedData,12,_packedSize+12); + MSBBitReader bitReader(inputStream); + auto readBits=[&](uint32_t count)->uint32_t + { + return bitReader.readBits8(count); + }; + auto readBit=[&]()->uint32_t + { + return bitReader.readBits8(1); + }; + auto readByte=[&]()->uint8_t + { + return inputStream.readByte(); + }; + // the anchor-bit does not seem always to be at the correct place + { + uint8_t halfByte=readByte(); + for (uint32_t i=0;i<7;i++) + if (halfByte&(1<>(i+1),7-i); + break; + } + } + + BackwardOutputStream outputStream(rawData,0,_rawSize); + + HuffmanDecoder litDecoder + { + HuffmanCode{1,0b00,0}, + HuffmanCode{2,0b10,1}, + HuffmanCode{2,0b11,2} + }; + + HuffmanDecoder lengthDecoder + { + HuffmanCode{1,0b0000,0}, + HuffmanCode{2,0b0010,1}, + HuffmanCode{3,0b0110,2}, + HuffmanCode{4,0b1110,3}, + HuffmanCode{4,0b1111,4} + }; + + HuffmanDecoder distanceDecoder + { + HuffmanCode{1,0b00,0}, + HuffmanCode{2,0b10,1}, + HuffmanCode{2,0b11,2} + }; + + for (;;) + { + uint32_t litLength=litDecoder.decode(readBit); + + if (litLength==2) + { + static const uint32_t litBitLengths[4]={2,2,3,10}; + static const uint32_t litAdditions[4]={2,5,8,15}; + for (uint32_t i=0;i<4;i++) + { + litLength=readBits(litBitLengths[i]); + if (litLength!=(1U< bitReader(inputStream); + auto readBits=[&](uint32_t count)->uint32_t + { + return bitReader.readBits16Limit(count); + }; + auto readByte=[&]()->uint8_t + { + return inputStream.readByte(); + }; + + ForwardOutputStream outputStream(rawData,0,_rawSize); + + typedef HuffmanDecoder RNC1HuffmanDecoder; + + // helpers + auto readHuffmanTable=[&](RNC1HuffmanDecoder &dec) + { + uint32_t length=readBits(5); + if (!length) return; + uint32_t maxDepth=0; + uint8_t lengthTable[31]; + for (uint32_t i=0;imaxDepth) maxDepth=lengthTable[i]; + } + + dec.createOrderlyHuffmanTable(lengthTable,length); + }; + + auto huffmanDecode=[&](const RNC1HuffmanDecoder &dec)->int32_t + { + // this is kind of non-specced + uint32_t ret=dec.decode([&]()->uint32_t{return readBits(1);}); + if (ret>=2) + ret=(1<<(ret-1))|readBits(ret-1); + return ret; + }; + + auto processLiterals=[&](const RNC1HuffmanDecoder &dec) + { + uint32_t litLength=huffmanDecode(dec); + for (uint32_t i=0;i bitReader(inputStream); + auto readBit=[&]()->uint32_t + { + return bitReader.readBits8(1); + }; + auto readByte=[&]()->uint8_t + { + return inputStream.readByte(); + }; + + ForwardOutputStream outputStream(rawData,0,_rawSize); + + // Huffman decoding + enum class Cmd + { + LIT=0, // 0, Literal + MOV, // 10, Move bytes + length + distance, Get bytes if length=9 + 4bits + MV2, // 110, Move 2 bytes + MV3, // 1110, Move 3 bytes + CND // 1111, Conditional copy, or EOF + + }; + + HuffmanDecoder cmdDecoder + { + HuffmanCode{1,0b0000,Cmd::LIT}, + HuffmanCode{2,0b0010,Cmd::MOV}, + HuffmanCode{3,0b0110,Cmd::MV2}, + HuffmanCode{4,0b1110,Cmd::MV3}, + HuffmanCode{4,0b1111,Cmd::CND} + }; + + /* length of 9 is a marker for literals */ + HuffmanDecoder lengthDecoder + { + HuffmanCode{2,0b000,4}, + HuffmanCode{2,0b010,5}, + HuffmanCode{3,0b010,6}, + HuffmanCode{3,0b011,7}, + HuffmanCode{3,0b110,8}, + HuffmanCode{3,0b111,9} + }; + + HuffmanDecoder distanceDecoder + { + HuffmanCode{1,0b000000,0}, + HuffmanCode{3,0b000110,1}, + HuffmanCode{4,0b001000,2}, + HuffmanCode{4,0b001001,3}, + HuffmanCode{5,0b010101,4}, + HuffmanCode{5,0b010111,5}, + HuffmanCode{5,0b011101,6}, + HuffmanCode{5,0b011111,7}, + HuffmanCode{6,0b101000,8}, + HuffmanCode{6,0b101001,9}, + HuffmanCode{6,0b101100,10}, + HuffmanCode{6,0b101101,11}, + HuffmanCode{6,0b111000,12}, + HuffmanCode{6,0b111001,13}, + HuffmanCode{6,0b111100,14}, + HuffmanCode{6,0b111101,15} + }; + + + // helpers + auto readDistance=[&]()->uint32_t + { + int8_t distMult=distanceDecoder.decode(readBit); + if (distMult<0) throw DecompressionError(); + uint8_t distByte=readByte(); + return (uint32_t(distByte)|(uint32_t(distMult)<<8))+1; + }; + + auto moveBytes=[&](uint32_t distance,uint32_t count)->void + { + if (!count) throw DecompressionError(); + outputStream.copy(distance,count); + }; + + readBit(); + readBit(); + uint8_t foundChunks=0; + bool done=false; + while (!done && foundChunks<_chunks) + { + Cmd cmd=cmdDecoder.decode(readBit); + switch (cmd) { + case Cmd::LIT: + outputStream.writeByte(readByte()); + break; + + case Cmd::MOV: + { + uint8_t count=lengthDecoder.decode(readBit); + if (count!=9) + moveBytes(readDistance(),count); + else { + uint32_t rep=0; + for (uint32_t i=0;i<4;i++) + rep=(rep<<1)|readBit(); + rep=(rep+3)*4; + for (uint32_t i=0;i create(const Buffer &packedData,bool exactSizeKnown,bool verify); + +private: + enum class Version + { + RNC1Old=0, + RNC1New, + RNC2 + }; + + void RNC1DecompressOld(Buffer &rawData,bool verify); + void RNC1DecompressNew(Buffer &rawData,bool verify); + void RNC2Decompress(Buffer &rawData,bool verify); + + const Buffer &_packedData; + + uint32_t _rawSize=0; + uint32_t _packedSize=0; + uint16_t _rawCRC=0; + uint8_t _chunks=0; + Version _ver; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/RangeDecoder.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/RangeDecoder.cpp new file mode 100644 index 00000000..061c4edc --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/RangeDecoder.cpp @@ -0,0 +1,65 @@ +/* Copyright (C) Teemu Suutari */ + +#include "RangeDecoder.hpp" + + +namespace ancient::internal +{ + +RangeDecoder::BitReader::BitReader() +{ + // nothing needed +} + +RangeDecoder::BitReader::~BitReader() +{ + // nothing needed +} + +RangeDecoder::RangeDecoder(BitReader &bitReader,uint16_t initialValue) : + _bitReader(bitReader), + _stream(initialValue) +{ + // nothing needed +} + +RangeDecoder::~RangeDecoder() +{ + // nothing needed +} + +uint16_t RangeDecoder::decode(uint16_t length) +{ + return ((uint32_t(_stream-_low)+1)*length-1)/(uint32_t(_high-_low)+1); +} + +void RangeDecoder::scale(uint16_t newLow,uint16_t newHigh,uint16_t newRange) +{ + uint32_t range=uint32_t(_high-_low)+1; + _high=(range*newHigh)/newRange+_low-1; + _low=(range*newLow)/newRange+_low; + + auto doubleContext=[&](uint16_t decr) + { + _low-=decr; + _high-=decr; + _stream-=decr; + _low<<=1; + _high=(_high<<1)|1U; + _stream=(_stream<<1)|_bitReader.readBit(); + }; + + for (;;) + { + if (_high<0x8000U) + { + doubleContext(0U); + } else if (_low>=0x8000U) { + doubleContext(0x8000U); + } else if (_low>=0x4000U && _high<0xc000U) { + doubleContext(0x4000U); + } else break; + } +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/RangeDecoder.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/RangeDecoder.hpp new file mode 100644 index 00000000..a68512cf --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/RangeDecoder.hpp @@ -0,0 +1,40 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef RANGEDECODER_HPP +#define RANGEDECODER_HPP + +#include + +namespace ancient::internal +{ + +// used by too many compressors... +class RangeDecoder +{ +public: + class BitReader + { + public: + BitReader(); + virtual ~BitReader(); + + virtual uint32_t readBit()=0; + }; + + RangeDecoder(BitReader &bitReader,uint16_t initialValue); + ~RangeDecoder(); + + uint16_t decode(uint16_t length); + void scale(uint16_t newLow,uint16_t newHigh,uint16_t newRange); + +private: + BitReader &_bitReader; + + uint16_t _low=0; + uint16_t _high=0xffffU; + uint16_t _stream; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/SDHCDecompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/SDHCDecompressor.cpp new file mode 100644 index 00000000..4d10cdbc --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/SDHCDecompressor.cpp @@ -0,0 +1,126 @@ +/* Copyright (C) Teemu Suutari */ + +#include + +#include "common/SubBuffer.hpp" +#include "SDHCDecompressor.hpp" +#include "XPKMain.hpp" +#include "DLTADecode.hpp" +#include "common/Common.hpp" + + +namespace ancient::internal +{ + +bool SDHCDecompressor::detectHeaderXPK(uint32_t hdr) noexcept +{ + return hdr==FourCC("SDHC"); +} + +std::shared_ptr SDHCDecompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) +{ + return std::make_shared(hdr,recursionLevel,packedData,state,verify); +} + +SDHCDecompressor::SDHCDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) : + XPKDecompressor(recursionLevel), + _packedData(packedData) +{ + if (!detectHeaderXPK(hdr) || _packedData.size()<2) + throw Decompressor::InvalidFormatError(); + _mode=_packedData.readBE16(0); + if (verify && (_mode&0x8000U)) + { + ConstSubBuffer src(_packedData,2,_packedData.size()-2); + XPKMain main(src,_recursionLevel+1,true); + } +} + +SDHCDecompressor::~SDHCDecompressor() +{ + // nothing needed +} + +const std::string &SDHCDecompressor::getSubName() const noexcept +{ + static std::string name="XPK-SDHC: Sample delta huffman compressor"; + return name; +} + +void SDHCDecompressor::decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) +{ + ConstSubBuffer src(_packedData,2,_packedData.size()-2); + if (_mode&0x8000U) + { + XPKMain main(src,_recursionLevel+1,false); + main.decompress(rawData,verify); + } else { + if (src.size()!=rawData.size()) throw Decompressor::DecompressionError(); + std::memcpy(rawData.data(),src.data(),src.size()); + } + + size_t length=rawData.size()&~3U; + + auto deltaDecodeMono=[&]() + { + uint8_t *buf=rawData.data(); + + uint16_t ctr=0; + for (size_t i=0;i>8; + buf[i+1]=ctr&0xff; + } + }; + + auto deltaDecodeStereo=[&]() + { + uint8_t *buf=rawData.data(); + + uint16_t ctr1=0,ctr2=0; + for (size_t i=0;i>8; + buf[i+1]=ctr1&0xff; + buf[i+2]=ctr2>>8; + buf[i+3]=ctr2&0xff; + } + }; + + switch (_mode&15) + { + case 1: + DLTADecode::decode(rawData,rawData,0,length); + // intentional fall through + case 0: + DLTADecode::decode(rawData,rawData,0,length); + break; + + case 3: + deltaDecodeMono(); + // intentional fall through + case 2: + deltaDecodeMono(); + break; + + case 11: + deltaDecodeStereo(); + // intentional fall through + case 10: + deltaDecodeStereo(); + break; + + default: + throw Decompressor::DecompressionError(); + } +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/SDHCDecompressor.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/SDHCDecompressor.hpp new file mode 100644 index 00000000..d64c840c --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/SDHCDecompressor.hpp @@ -0,0 +1,33 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef SDHCDECOMPRESSOR_HPP +#define SDHCDECOMPRESSOR_HPP + +#include "XPKDecompressor.hpp" + +namespace ancient::internal +{ + +class SDHCDecompressor : public XPKDecompressor +{ +public: + SDHCDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + + virtual ~SDHCDecompressor(); + + virtual const std::string &getSubName() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) override final; + + static bool detectHeaderXPK(uint32_t hdr) noexcept; + static std::shared_ptr create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + +private: + const Buffer &_packedData; + + uint16_t _mode=0; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/SHR3Decompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/SHR3Decompressor.cpp new file mode 100644 index 00000000..1ca4d66c --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/SHR3Decompressor.cpp @@ -0,0 +1,326 @@ +/* Copyright (C) Teemu Suutari */ + +#include "SHR3Decompressor.hpp" +#include "InputStream.hpp" +#include "OutputStream.hpp" +#include "common/Common.hpp" + + +namespace ancient::internal +{ + +SHR3Decompressor::SHR3State::SHR3State() noexcept +{ + for (uint32_t i=0;i<999;i++) ar[i]=0; +} + +SHR3Decompressor::SHR3State::~SHR3State() +{ + // nothing needed +} + +bool SHR3Decompressor::detectHeaderXPK(uint32_t hdr) noexcept +{ + return hdr==FourCC("SHR3"); +} + +std::shared_ptr SHR3Decompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) +{ + return std::make_shared(hdr,recursionLevel,packedData,state,verify); +} + +SHR3Decompressor::SHR3Decompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) : + XPKDecompressor(recursionLevel), + _packedData(packedData), + _state(state) +{ + if (!detectHeaderXPK(hdr) || _packedData.size()<6) throw Decompressor::InvalidFormatError(); + _ver=_packedData.read8(0); + if (!_ver || _ver>2) throw Decompressor::InvalidFormatError(); + + if (!_state) + { + if (_ver==2) throw Decompressor::InvalidFormatError(); + _state.reset(new SHR3State()); + } +} + +SHR3Decompressor::~SHR3Decompressor() +{ + // nothing needed +} + +const std::string &SHR3Decompressor::getSubName() const noexcept +{ + static std::string name="XPK-SHR3: LZ-compressor with arithmetic encoding"; + return name; +} + +void SHR3Decompressor::decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) +{ + ForwardInputStream inputStream(_packedData,1,_packedData.size()); + auto readByte=[&]()->uint8_t + { + return inputStream.readByte(); + }; + + ForwardOutputStream outputStream(rawData,0,rawData.size()); + + // This follows quite closely Choloks pascal reference + uint32_t ar[999]; + + auto resum=[&]() + { + for (uint32_t i=498;i;i--) + ar[i]=ar[i*2]+ar[i*2+1]; + }; + + auto init=[&]() + { + for (uint32_t i=0;i<499;i++) ar[i]=0; + for (uint32_t i=0;i<256;i++) ar[i+499]=(i<32||i>126)?1:3; + for (uint32_t i=256+499;i<999;i++) ar[i]=0; + resum(); + }; + + auto update=[&](uint32_t updateIndex,uint32_t increment) + { + if (updateIndex>=499) return; + updateIndex+=499; + while (updateIndex) + { + ar[updateIndex]+=increment; + updateIndex>>=1; + } + if (ar[1]>=0x2000) + { + for (uint32_t i=499;i<998;i++) + if (ar[i]) ar[i]=(ar[i]>>1)+1; + resum(); + } + }; + + auto scale=[&](uint32_t b,uint32_t mult)->uint32_t + { + if (!b) throw Decompressor::DecompressionError(); + uint32_t tmp=(0x10000U/b); + uint32_t tmp2=((0x10000U%b)<<16)/b; + return ((mult&0xffffU)*tmp>>16)+((mult>>16)*tmp2>>16)+(mult>>16)*tmp; + }; + + uint32_t vlen=0,vnext=0; + + auto upgrade=[&]() + { + if (vnext>=65532) + { + vnext=~0U; + } else if (!vlen) { + vnext=1; + } else { + uint32_t vvalue=vnext-1; + if (vvalue<48) update(vvalue+256,1); + uint32_t bits=0,compare=4; + while (vvalue>=compare) + { + vvalue-=compare; + compare<<=1; + bits++; + } + if (bits>=14) + { + vnext=~0U; + } else { + if (!vvalue) + { + if (bits<7) + { + for (uint32_t i=304;i<=307;i++) + update((bits<<2)+i,1); + } + if (bits<13) + { + for (uint32_t i=332;i<=333;i++) + update((bits<<1)+i,1); + } + static const uint32_t updates1[6]={358,359,386,387,414,415}; + static const uint32_t updates2[4]={442,456,470,484}; + for (auto it : updates1) + update((bits<<1)+it,1); + for (auto it : updates2) + update(bits+it,1); + } + if (vnext<49) + { + vnext++; + } else if (vnext==49) { + vnext=61; + } else { + vnext=(vnext<<1)+3; + } + } + } + }; + + uint32_t stream=0,shift=0; + + auto refillStream=[&]() + { + while (shift<0x100'0000) + { + stream=(stream<<8)|uint32_t(readByte()); + shift<<=8; + } + }; + + auto getSymbol=[&]()->uint32_t + { + if (!(shift>>16)) throw Decompressor::DecompressionError(); + uint32_t vvalue=(stream/(shift>>16))&0xffff; + uint32_t threshold=(ar[1]*vvalue)>>16; + uint32_t arIndex=1; + uint32_t result=0; + do { + arIndex<<=1; + uint32_t tmp=ar[arIndex]+result; + if (threshold>=tmp) + { + result=tmp; + arIndex++; + } + } while (arIndex<499); + uint32_t rawValue=scale(ar[1],shift); + uint32_t newValue=rawValue*result; + if (newValue>stream) + { + while (newValue>stream) + { + if (--arIndex<499) arIndex+=499; + result-=ar[arIndex]; + newValue=rawValue*result; + } + } else { + result+=ar[arIndex]; + while (result=998) arIndex-=499; + result+=ar[arIndex]; + newValue=compare; + } + } + stream-=newValue; + shift=rawValue*ar[arIndex]; + uint32_t addition=(ar[1]>>10)+3; + arIndex-=499; + update(arIndex,addition); + refillStream(); + return arIndex; + }; + + auto getCode=[&](uint32_t size)->uint32_t + { + uint32_t ret=0; + while (size--) + { + ret<<=1; + shift>>=1; + if (stream>=shift) + { + ret++; + stream-=shift; + } + refillStream(); + } + return ret; + }; + + if (_ver==1) + { + init(); + update(498,1); + + shift=0x8000'0000U; + } else { + SHR3State *state=static_cast(_state.get()); + vlen=state->vlen; + vnext=state->vnext; + shift=state->shift; + for (uint32_t i=0;i<999;i++) ar[i]=state->ar[i]; + } + + { + const uint8_t *buf=inputStream.consume(4); + stream=(uint32_t(buf[0])<<24)|(uint32_t(buf[1])<<16)| + (uint32_t(buf[2])<<8)|uint32_t(buf[3]); + } + + while (!outputStream.eof()) + { + while (vlen>=vnext) upgrade(); + uint32_t code=getSymbol(); + if (code<256) + { + outputStream.writeByte(code); + vlen++; + } else { + auto distanceAddition=[](uint32_t i)->uint32_t + { + return ((1<<(i+2))-1)&~0x3U; + }; + + uint32_t count,distance; + if (code<304) + { + count=2; + distance=code-255; + } else if (code<332) { + uint32_t tmp=code-304; + uint32_t extra=getCode(tmp>>2); + distance=((extra<<2)|(tmp&3))+distanceAddition(tmp>>2)+1; + count=3; + } else if (code<358) { + uint32_t tmp=code-332; + uint32_t extra=getCode((tmp>>1)+1); + distance=((extra<<1)|(tmp&1))+distanceAddition(tmp>>1)+1; + count=4; + } else if (code<386) { + uint32_t tmp=code-358; + uint32_t extra=getCode((tmp>>1)+1); + distance=((extra<<1)|(tmp&1))+distanceAddition(tmp>>1)+1; + count=5; + } else if (code<414) { + uint32_t tmp=code-386; + uint32_t extra=getCode((tmp>>1)+1); + distance=((extra<<1)|(tmp&1))+distanceAddition(tmp>>1)+1; + count=6; + } else if (code<442) { + uint32_t tmp=code-414; + uint32_t extra=getCode((tmp>>1)+1); + distance=((extra<<1)|(tmp&1))+distanceAddition(tmp>>1)+1; + count=7; + } else if (code<498) { + uint32_t tmp=code-442; + uint32_t d=tmp/14; + uint32_t m=tmp%14; + count=getCode(d+2)+distanceAddition(d)+8; + distance=getCode(m+2)+distanceAddition(m)+1; + } else { + count=getCode(16); + distance=getCode(16); + } + vlen+=count; + if (!count) throw Decompressor::DecompressionError(); + outputStream.copy(distance,count,previousData); + } + } + + SHR3State *state=static_cast(_state.get()); + state->vlen=vlen; + state->vnext=vnext; + state->shift=shift; + for (uint32_t i=0;i<999;i++) state->ar[i]=ar[i]; +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/SHR3Decompressor.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/SHR3Decompressor.hpp new file mode 100644 index 00000000..2ea24191 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/SHR3Decompressor.hpp @@ -0,0 +1,48 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef SHR3DECOMPRESSOR_HPP +#define SHR3DECOMPRESSOR_HPP + +#include "XPKDecompressor.hpp" + +namespace ancient::internal +{ + +class SHR3Decompressor : public XPKDecompressor +{ +private: + class SHR3State : public XPKDecompressor::State + { + public: + SHR3State() noexcept; + virtual ~SHR3State(); + + uint32_t vlen=0; + uint32_t vnext=0; + uint32_t shift=0; + uint32_t ar[999]; + }; + +public: + SHR3Decompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + + virtual ~SHR3Decompressor(); + + virtual const std::string &getSubName() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) override final; + + static bool detectHeaderXPK(uint32_t hdr) noexcept; + static std::shared_ptr create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + +private: + const Buffer &_packedData; + + uint32_t _ver=0; + + std::shared_ptr &_state; // reference!!! +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/SHRIDecompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/SHRIDecompressor.cpp new file mode 100644 index 00000000..92723cb6 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/SHRIDecompressor.cpp @@ -0,0 +1,338 @@ +/* Copyright (C) Teemu Suutari */ + +#include "SHRIDecompressor.hpp" +#include "InputStream.hpp" +#include "OutputStream.hpp" +#include "common/Common.hpp" + + +namespace ancient::internal +{ + +SHRIDecompressor::SHRIState::SHRIState() noexcept +{ + for (uint32_t i=0;i<999;i++) ar[i]=0; +} + +SHRIDecompressor::SHRIState::~SHRIState() +{ + // nothing needed +} + +bool SHRIDecompressor::detectHeaderXPK(uint32_t hdr) noexcept +{ + return hdr==FourCC("SHRI"); +} + +std::shared_ptr SHRIDecompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) +{ + return std::make_shared(hdr,recursionLevel,packedData,state,verify); +} + +SHRIDecompressor::SHRIDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) : + XPKDecompressor(recursionLevel), + _packedData(packedData), + _state(state) +{ + if (!detectHeaderXPK(hdr) || _packedData.size()<6) throw Decompressor::InvalidFormatError(); + _ver=_packedData.read8(0); + if (!_ver || _ver>2) throw Decompressor::InvalidFormatError(); + + // second byte defines something that does not seem to be terribly important... + uint8_t tmp=_packedData.read8(2); + if (tmp<0x80) + { + _rawSize=_packedData.readBE16(2); + _startOffset=4; + } else { + _rawSize=~_packedData.readBE32(2)+1U; + _startOffset=6; + } + + if (!_state) + { + if (_ver==2) throw Decompressor::InvalidFormatError(); + _state.reset(new SHRIState()); + } +} + +SHRIDecompressor::~SHRIDecompressor() +{ + // nothing needed +} + +const std::string &SHRIDecompressor::getSubName() const noexcept +{ + static std::string name="XPK-SHRI: LZ-compressor with arithmetic encoding"; + return name; +} + +void SHRIDecompressor::decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) +{ + if (rawData.size()!=_rawSize) throw Decompressor::DecompressionError(); + + ForwardInputStream inputStream(_packedData,_startOffset,_packedData.size()); + auto readByte=[&]()->uint8_t + { + return inputStream.readByte(); + }; + + ForwardOutputStream outputStream(rawData,0,rawData.size()); + + // This follows quite closely Choloks pascal reference + uint32_t ar[999]; + + auto resum=[&]() + { + for (uint32_t i=498;i;i--) + ar[i]=ar[i*2]+ar[i*2+1]; + }; + + auto init=[&]() + { + for (uint32_t i=0;i<499;i++) ar[i]=0; + for (uint32_t i=0;i<256;i++) ar[i+499]=(i<32||i>126)?1:3; + for (uint32_t i=256+499;i<999;i++) ar[i]=0; + resum(); + }; + + auto update=[&](uint32_t updateIndex,uint32_t increment) + { + if (updateIndex>=499) return; + updateIndex+=499; + while (updateIndex) + { + ar[updateIndex]+=increment; + updateIndex>>=1; + } + if (ar[1]>=0x2000) + { + for (uint32_t i=499;i<998;i++) + if (ar[i]) ar[i]=(ar[i]>>1)+1; + resum(); + } + }; + + auto scale=[&](uint32_t a,uint32_t b,uint32_t mult)->uint32_t + { + if (!b) throw Decompressor::DecompressionError(); + uint32_t tmp=(a<<16)/b; + uint32_t tmp2=(((a<<16)%b)<<16)/b; + return ((mult&0xffffU)*tmp>>16)+((mult>>16)*tmp2>>16)+(mult>>16)*tmp; + }; + + uint32_t vlen=0,vnext=0; + + auto upgrade=[&]() + { + if (vnext>=65532) + { + vnext=~0U; + } else if (!vlen) { + vnext=1; + } else { + uint32_t vvalue=vnext-1; + if (vvalue<48) update(vvalue+256,1); + uint32_t bits=0,compare=4; + while (vvalue>=compare) + { + vvalue-=compare; + compare<<=1; + bits++; + } + if (bits>=14) + { + vnext=~0U; + } else { + if (!vvalue) + { + if (bits<7) + { + for (uint32_t i=304;i<=307;i++) + update((bits<<2)+i,1); + } + if (bits<13) + { + for (uint32_t i=332;i<=333;i++) + update((bits<<1)+i,1); + } + static const uint32_t updates1[6]={358,359,386,387,414,415}; + static const uint32_t updates2[4]={442,456,470,484}; + for (auto it : updates1) + update((bits<<1)+it,1); + for (auto it : updates2) + update(bits+it,1); + } + if (vnext<49) + { + vnext++; + } else if (vnext==49) { + vnext=61; + } else { + vnext=(vnext<<1)+3; + } + } + } + }; + + uint32_t stream=0,shift=0; + + auto refillStream=[&]() + { + while (shift<0x100'0000) + { + stream=(stream<<8)|uint32_t(readByte()); + shift<<=8; + } + }; + + auto getSymbol=[&]()->uint32_t + { + if (!(shift>>16)) throw Decompressor::DecompressionError(); + uint32_t vvalue=(stream/(shift>>16))&0xffff; + uint32_t threshold=(ar[1]*vvalue)>>16; + uint32_t arIndex=1; + uint32_t result=0; + do { + arIndex<<=1; + uint32_t tmp=ar[arIndex]+result; + if (threshold>=tmp) + { + result=tmp; + arIndex++; + } + } while (arIndex<499); + uint32_t newValue=scale(result,ar[1],shift); + if (newValue>stream) + { + while (newValue>stream) + { + if (--arIndex<499) arIndex+=499; + result-=ar[arIndex]; + newValue=scale(result,ar[1],shift); + } + } else { + result+=ar[arIndex]; + while (result=998) arIndex-=499; + result+=ar[arIndex]; + newValue=compare; + } + } + stream-=newValue; + shift=scale(ar[arIndex],ar[1],shift); + uint32_t addition=(ar[1]>>10)+3; + arIndex-=499; + update(arIndex,addition); + refillStream(); + return arIndex; + }; + + auto getCode=[&](uint32_t size)->uint32_t + { + uint32_t ret=0; + while (size--) + { + ret<<=1; + shift>>=1; + if (stream>=shift) + { + ret++; + stream-=shift; + } + refillStream(); + } + return ret; + }; + + if (_ver==1) + { + init(); + update(498,1); + + shift=0x8000'0000U; + } else { + SHRIState *state=static_cast(_state.get()); + vlen=state->vlen; + vnext=state->vnext; + shift=state->shift; + for (uint32_t i=0;i<999;i++) ar[i]=state->ar[i]; + } + + { + const uint8_t *buf=inputStream.consume(4); + stream=(uint32_t(buf[0])<<24)|(uint32_t(buf[1])<<16)| + (uint32_t(buf[2])<<8)|uint32_t(buf[3]); + } + + while (!outputStream.eof()) + { + while (vlen>=vnext) upgrade(); + uint32_t code=getSymbol(); + if (code<256) + { + outputStream.writeByte(code); + vlen++; + } else { + auto distanceAddition=[](uint32_t i)->uint32_t + { + return ((1<<(i+2))-1)&~0x3U; + }; + + uint32_t count,distance; + if (code<304) + { + count=2; + distance=code-255; + } else if (code<332) { + uint32_t tmp=code-304; + uint32_t extra=getCode(tmp>>2); + distance=((extra<<2)|(tmp&3))+distanceAddition(tmp>>2)+1; + count=3; + } else if (code<358) { + uint32_t tmp=code-332; + uint32_t extra=getCode((tmp>>1)+1); + distance=((extra<<1)|(tmp&1))+distanceAddition(tmp>>1)+1; + count=4; + } else if (code<386) { + uint32_t tmp=code-358; + uint32_t extra=getCode((tmp>>1)+1); + distance=((extra<<1)|(tmp&1))+distanceAddition(tmp>>1)+1; + count=5; + } else if (code<414) { + uint32_t tmp=code-386; + uint32_t extra=getCode((tmp>>1)+1); + distance=((extra<<1)|(tmp&1))+distanceAddition(tmp>>1)+1; + count=6; + } else if (code<442) { + uint32_t tmp=code-414; + uint32_t extra=getCode((tmp>>1)+1); + distance=((extra<<1)|(tmp&1))+distanceAddition(tmp>>1)+1; + count=7; + } else if (code<498) { + uint32_t tmp=code-442; + uint32_t d=tmp/14; + uint32_t m=tmp%14; + count=getCode(d+2)+distanceAddition(d)+8; + distance=getCode(m+2)+distanceAddition(m)+1; + } else { + count=getCode(16); + distance=getCode(16); + } + vlen+=count; + if (!count) throw Decompressor::DecompressionError(); + outputStream.copy(distance,count,previousData); + } + } + + SHRIState *state=static_cast(_state.get()); + state->vlen=vlen; + state->vnext=vnext; + state->shift=shift; + for (uint32_t i=0;i<999;i++) state->ar[i]=ar[i]; +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/SHRIDecompressor.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/SHRIDecompressor.hpp new file mode 100644 index 00000000..549fa1e0 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/SHRIDecompressor.hpp @@ -0,0 +1,50 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef SHRIDECOMPRESSOR_HPP +#define SHRIDECOMPRESSOR_HPP + +#include "XPKDecompressor.hpp" + +namespace ancient::internal +{ + +class SHRIDecompressor : public XPKDecompressor +{ +private: + class SHRIState : public XPKDecompressor::State + { + public: + SHRIState() noexcept; + virtual ~SHRIState(); + + uint32_t vlen=0; + uint32_t vnext=0; + uint32_t shift=0; + uint32_t ar[999]; + }; + +public: + SHRIDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + + virtual ~SHRIDecompressor(); + + virtual const std::string &getSubName() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) override final; + + static bool detectHeaderXPK(uint32_t hdr) noexcept; + static std::shared_ptr create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + +private: + const Buffer &_packedData; + + uint32_t _ver=0; + size_t _startOffset=0; + size_t _rawSize=0; + + std::shared_ptr &_state; // reference!!! +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/SLZ3Decompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/SLZ3Decompressor.cpp new file mode 100644 index 00000000..199a8689 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/SLZ3Decompressor.cpp @@ -0,0 +1,71 @@ +/* Copyright (C) Teemu Suutari */ + +#include "SLZ3Decompressor.hpp" +#include "InputStream.hpp" +#include "OutputStream.hpp" +#include "common/Common.hpp" + + +namespace ancient::internal +{ + +bool SLZ3Decompressor::detectHeaderXPK(uint32_t hdr) noexcept +{ + return hdr==FourCC("SLZ3"); +} + +std::shared_ptr SLZ3Decompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) +{ + return std::make_shared(hdr,recursionLevel,packedData,state,verify); +} + +SLZ3Decompressor::SLZ3Decompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) : + XPKDecompressor(recursionLevel), + _packedData(packedData) +{ + if (!detectHeaderXPK(hdr)) throw Decompressor::InvalidFormatError(); +} + +SLZ3Decompressor::~SLZ3Decompressor() +{ + // nothing needed +} + +const std::string &SLZ3Decompressor::getSubName() const noexcept +{ + static std::string name="XPK-SLZ3: SLZ3 CyberYAFA compressor"; + return name; +} + +void SLZ3Decompressor::decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) +{ + ForwardInputStream inputStream(_packedData,0,_packedData.size()); + MSBBitReader bitReader(inputStream); + auto readBit=[&]()->uint32_t + { + return bitReader.readBits8(1); + }; + auto readByte=[&]()->uint8_t + { + return inputStream.readByte(); + }; + + ForwardOutputStream outputStream(rawData,0,rawData.size()); + + while (!outputStream.eof()) + { + if (!readBit()) + { + outputStream.writeByte(readByte()); + } else { + uint8_t tmp=readByte(); + if (!tmp) throw Decompressor::DecompressionError(); + uint32_t distance=uint32_t(tmp&0xf0)<<4; + distance|=uint32_t(readByte()); + uint32_t count=uint32_t(tmp&0xf)+2; + outputStream.copy(distance,count); + } + } +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/SLZ3Decompressor.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/SLZ3Decompressor.hpp new file mode 100644 index 00000000..56f62800 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/SLZ3Decompressor.hpp @@ -0,0 +1,31 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef SLZ3DECOMPRESSOR_HPP +#define SLZ3DECOMPRESSOR_HPP + +#include "XPKDecompressor.hpp" + +namespace ancient::internal +{ + +class SLZ3Decompressor : public XPKDecompressor +{ +public: + SLZ3Decompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + + virtual ~SLZ3Decompressor(); + + virtual const std::string &getSubName() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) override final; + + static bool detectHeaderXPK(uint32_t hdr) noexcept; + static std::shared_ptr create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + +private: + const Buffer &_packedData; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/SMPLDecompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/SMPLDecompressor.cpp new file mode 100644 index 00000000..95530147 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/SMPLDecompressor.cpp @@ -0,0 +1,78 @@ +/* Copyright (C) Teemu Suutari */ + +#include "SMPLDecompressor.hpp" +#include "InputStream.hpp" +#include "OutputStream.hpp" +#include "HuffmanDecoder.hpp" +#include "common/Common.hpp" + + +namespace ancient::internal +{ + +bool SMPLDecompressor::detectHeaderXPK(uint32_t hdr) noexcept +{ + return hdr==FourCC("SMPL"); +} + +std::shared_ptr SMPLDecompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) +{ + return std::make_shared(hdr,recursionLevel,packedData,state,verify); +} + +SMPLDecompressor::SMPLDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) : + XPKDecompressor(recursionLevel), + _packedData(packedData) +{ + if (!detectHeaderXPK(hdr) || packedData.size()<2) throw Decompressor::InvalidFormatError(); + + if (packedData.readBE16(0)!=1) throw Decompressor::InvalidFormatError(); +} + +SMPLDecompressor::~SMPLDecompressor() +{ + // nothing needed +} + +const std::string &SMPLDecompressor::getSubName() const noexcept +{ + static std::string name="XPK-SMPL: Huffman compressor with delta encoding"; + return name; +} + +void SMPLDecompressor::decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) +{ + ForwardInputStream inputStream(_packedData,2,_packedData.size()); + MSBBitReader bitReader(inputStream); + auto readBits=[&](uint32_t count)->uint32_t + { + return bitReader.readBits8(count); + }; + auto readBit=[&]()->uint32_t + { + return bitReader.readBits8(1); + }; + + ForwardOutputStream outputStream(rawData,0,rawData.size()); + + HuffmanDecoder decoder; + + for (uint32_t i=0;i<256;i++) + { + uint32_t codeLength=readBits(4); + if (!codeLength) continue; + if (codeLength==15) codeLength=readBits(4)+15; + uint32_t code=readBits(codeLength); + decoder.insert(HuffmanCode{codeLength,code,i}); + } + + uint8_t accum=0; + while (!outputStream.eof()) + { + uint32_t code=decoder.decode(readBit); + accum+=code; + outputStream.writeByte(accum); + } +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/SMPLDecompressor.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/SMPLDecompressor.hpp new file mode 100644 index 00000000..e2153ef9 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/SMPLDecompressor.hpp @@ -0,0 +1,31 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef SMPLDECOMPRESSOR_HPP +#define SMPLDECOMPRESSOR_HPP + +#include "XPKDecompressor.hpp" + +namespace ancient::internal +{ + +class SMPLDecompressor : public XPKDecompressor +{ +public: + SMPLDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + + virtual ~SMPLDecompressor(); + + virtual const std::string &getSubName() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) override final; + + static bool detectHeaderXPK(uint32_t hdr) noexcept; + static std::shared_ptr create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + +private: + const Buffer &_packedData; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/SQSHDecompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/SQSHDecompressor.cpp new file mode 100644 index 00000000..bcf6383f --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/SQSHDecompressor.cpp @@ -0,0 +1,218 @@ +/* Copyright (C) Teemu Suutari */ + +#include "SQSHDecompressor.hpp" +#include "InputStream.hpp" +#include "OutputStream.hpp" +#include "HuffmanDecoder.hpp" +#include "common/Common.hpp" + + +namespace ancient::internal +{ + +bool SQSHDecompressor::detectHeaderXPK(uint32_t hdr) noexcept +{ + return hdr==FourCC("SQSH"); +} + +std::shared_ptr SQSHDecompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) +{ + return std::make_shared(hdr,recursionLevel,packedData,state,verify); +} + +SQSHDecompressor::SQSHDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) : + XPKDecompressor(recursionLevel), + _packedData(packedData) +{ + if (!detectHeaderXPK(hdr) || packedData.size()<3) throw Decompressor::InvalidFormatError(); + _rawSize=packedData.readBE16(0); + if (!_rawSize) throw Decompressor::InvalidFormatError(); +} + +SQSHDecompressor::~SQSHDecompressor() +{ + // nothing needed +} + +const std::string &SQSHDecompressor::getSubName() const noexcept +{ + static std::string name="XPK-SQSH: Compressor for sampled sounds"; + return name; +} + +void SQSHDecompressor::decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) +{ + if (rawData.size()!=_rawSize) throw Decompressor::DecompressionError(); + + ForwardInputStream inputStream(_packedData,2,_packedData.size()); + MSBBitReader bitReader(inputStream); + auto readBits=[&](uint32_t count)->uint32_t + { + return bitReader.readBits8(count); + }; + auto readSignedBits=[&](uint8_t bits)->int32_t + { + int32_t ret=readBits(bits); + if (ret&(1<<(bits-1))) + ret|=~0U<uint32_t + { + return bitReader.readBits8(1); + }; + auto readByte=[&]()->uint8_t + { + return inputStream.readByte(); + }; + + ForwardOutputStream outputStream(rawData,0,_rawSize); + + HuffmanDecoder modDecoder + { + HuffmanCode{1,0b0001,0}, + HuffmanCode{2,0b0000,1}, + HuffmanCode{3,0b0010,2}, + HuffmanCode{4,0b0110,3}, + HuffmanCode{4,0b0111,4} + }; + + HuffmanDecoder lengthDecoder + { + HuffmanCode{1,0b0000,0}, + HuffmanCode{2,0b0010,1}, + HuffmanCode{3,0b0110,2}, + HuffmanCode{4,0b1110,3}, + HuffmanCode{4,0b1111,4} + }; + + HuffmanDecoder distanceDecoder + { + HuffmanCode{1,0b01,0}, + HuffmanCode{2,0b00,1}, + HuffmanCode{2,0b01,2} + }; + + // first byte is special + uint8_t currentSample=readByte(); + outputStream.writeByte(currentSample); + + uint32_t accum1=0,accum2=0,prevBits=0; + + while (!outputStream.eof()) + { + uint8_t bits=0; + uint32_t count=0; + bool doRepeat=false; + + if (accum1>=8) + { + static const uint8_t bitLengthTable[7][8]={ + {2,3,4,5,6,7,8,0}, + {3,2,4,5,6,7,8,0}, + {4,3,5,2,6,7,8,0}, + {5,4,6,2,3,7,8,0}, + {6,5,7,2,3,4,8,0}, + {7,6,8,2,3,4,5,0}, + {8,7,6,2,3,4,5,0}}; + + auto handleCondCase=[&]() + { + if (bits==8) { + if (accum2<20) + { + count=1; + } else { + count=2; + accum2+=8; + } + } else { + count=5; + accum2+=8; + } + }; + + auto handleTable=[&](uint32_t newBits) + { + if (prevBits<2 || !newBits) throw Decompressor::DecompressionError(); + bits=bitLengthTable[prevBits-2][newBits-1]; + if (!bits) throw Decompressor::DecompressionError(); + handleCondCase(); + }; + + uint32_t mod=modDecoder.decode(readBit); + switch (mod) + { + case 0: + if (prevBits==8) + { + bits=8; + handleCondCase(); + } else { + bits=prevBits; + count=5; + accum2+=8; + } + break; + + case 1: + doRepeat=true; + break; + + case 2: + handleTable(2); + break; + + case 3: + handleTable(3); + break; + + case 4: + handleTable(readBits(2)+4); + break; + + default: + throw Decompressor::DecompressionError(); + } + } else { + if (readBit()) + { + doRepeat=true; + } else { + count=1; + bits=8; + } + } + + if (doRepeat) { + uint32_t lengthIndex=lengthDecoder.decode(readBit); + static const uint8_t lengthBits[5]={1,1,1,3,5}; + static const uint32_t lengthAdditions[5]={2,4,6,8,16}; + count=readBits(lengthBits[lengthIndex])+lengthAdditions[lengthIndex]; + if (count>=3) + { + if (accum1) accum1--; + if (count>3 && accum1) accum1--; + } + uint32_t distanceIndex=distanceDecoder.decode(readBit); + static const uint8_t distanceBits[3]={12,8,14}; + static const uint32_t distanceAdditions[3]={0x101,1,0x1101}; + uint32_t distance=readBits(distanceBits[distanceIndex])+distanceAdditions[distanceIndex]; + count=std::min(count,uint32_t(_rawSize-outputStream.getOffset())); + currentSample=outputStream.copy(distance,count); + } else { + count=std::min(count,uint32_t(_rawSize-outputStream.getOffset())); + for (uint32_t i=0;i>3; + } +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/SQSHDecompressor.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/SQSHDecompressor.hpp new file mode 100644 index 00000000..066e0905 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/SQSHDecompressor.hpp @@ -0,0 +1,33 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef SQSHDECOMPRESSOR_HPP +#define SQSHDECOMPRESSOR_HPP + +#include "XPKDecompressor.hpp" + +namespace ancient::internal +{ + +class SQSHDecompressor : public XPKDecompressor +{ +public: + SQSHDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + + virtual ~SQSHDecompressor(); + + virtual const std::string &getSubName() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) override final; + + static bool detectHeaderXPK(uint32_t hdr) noexcept; + static std::shared_ptr create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + +private: + const Buffer &_packedData; + + uint32_t _rawSize=0; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/SXSCDecompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/SXSCDecompressor.cpp new file mode 100644 index 00000000..73967362 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/SXSCDecompressor.cpp @@ -0,0 +1,829 @@ +/* Copyright (C) Teemu Suutari */ + +#include "SXSCDecompressor.hpp" + +#include "InputStream.hpp" +#include "OutputStream.hpp" +#include "DLTADecode.hpp" +#include "common/MemoryBuffer.hpp" +#include "common/Common.hpp" + + +namespace ancient::internal +{ + +SXSCDecompressor::SXSCReader::SXSCReader(ForwardInputStream &stream) : + _reader(stream) +{ + // nothing needed +} + +SXSCDecompressor::SXSCReader::~SXSCReader() +{ + // nothing needed +} + +uint32_t SXSCDecompressor::SXSCReader::readBit() +{ + return _reader.readBits8(1); +} + + +bool SXSCDecompressor::detectHeaderXPK(uint32_t hdr) noexcept +{ + return hdr==FourCC("SASC")||hdr==FourCC("SHSC"); +} + +std::shared_ptr SXSCDecompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) +{ + return std::make_shared(hdr,recursionLevel,packedData,state,verify); +} + +SXSCDecompressor::SXSCDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) : + XPKDecompressor(recursionLevel), + _packedData(packedData), + _isHSC(hdr==FourCC("SHSC")) +{ + if (!detectHeaderXPK(hdr)) throw Decompressor::InvalidFormatError(); +} + +SXSCDecompressor::~SXSCDecompressor() +{ + // nothing needed +} + +const std::string &SXSCDecompressor::getSubName() const noexcept +{ + static std::string nameASC="XPK-SASC: LZ-compressor with arithmetic and delta encoding"; + static std::string nameHSC="XPK-SHSC: Context modeling compressor"; + return _isHSC?nameHSC:nameASC; +} + +void SXSCDecompressor::decompressASC(Buffer &rawData,ForwardInputStream &inputStream) +{ + ForwardOutputStream outputStream(rawData,0,rawData.size()); + + uint16_t bitReaderInitialValue; + bitReaderInitialValue=inputStream.readByte()<<8; + bitReaderInitialValue|=inputStream.readByte(); + SXSCReader bitReader(inputStream); + RangeDecoder arithDecoder(bitReader,bitReaderInitialValue); + + // decoder for literal, copy, end decision + // two thresholds -> 3 symbols, last symbol is break with size of 1 + uint16_t bitThreshold1[4]={40,40,40,40}; + uint16_t bitThreshold2[4]={40,40,40,40}; + uint32_t bitPos=0; + + // generics for the other decoder + + auto tableElements=[](auto &table)->uint16_t + { + return (sizeof(table)/sizeof(*table)+1)>>1; + }; + + auto initTable=[](auto &table,uint16_t initialValue) + { + constexpr uint32_t length=(sizeof(table)/sizeof(*table)+1)>>1; + for (uint32_t i=0;i>1; + for (uint32_t i=index;i>1)+length) + table[i]+=value; + if (table[length*2-2]>=max) + { + for (uint32_t i=0;i1) table[i]>>=1; + for (uint32_t j=0,i=length;iuint16_t + { + constexpr uint32_t length=(sizeof(table)/sizeof(*table)+1)>>1; + return table[length*2-2]; + }; + + auto decodeSymbol=[](auto &table,uint16_t &value)->uint16_t + { + constexpr uint32_t length=(sizeof(table)/sizeof(*table)+1)>>1; + uint32_t threshold=0; + uint32_t i=length*2-4; + while (i>=length) + { + uint32_t child=(i-length)<<1; + if (value-threshold>=table[i]) + { + threshold+=table[i]; + child+=2; + } + i=child; + } + if (value-threshold>=table[i]) + { + threshold+=table[i]; + i++; + } + value=threshold; + return i; + }; + + // literal decoder + uint16_t litInitial[256*2-1]; + uint16_t litDynamic[256*2-1]; + uint16_t litThreshold=1; + + initTable(litInitial,1); + initTable(litDynamic,0); + + // distance / length decoder + uint16_t distanceCodes[16*2-1]; + uint16_t countInitial[64*2-1]; + uint16_t countDynamic[64*2-1]; + uint16_t countThreshold=8; + + initTable(distanceCodes,0); + initTable(countInitial,1); + initTable(countDynamic,0); + + updateTable(distanceCodes,6000,0,24); + uint32_t distanceIndex=0; + + auto twoStepArithDecoder=[&](auto &initialTable,auto &dynamicTable,uint16_t &threshold,uint16_t max,uint16_t step,uint16_t updateRange)->uint16_t + { + uint16_t value=arithDecoder.decode(tableSize(dynamicTable)+threshold); + uint16_t ret; + if (valueupdateRange?ret-updateRange:0;istep?threshold-step:1; + return ret; + }; + + for (;;) + { + uint16_t bitSize=bitThreshold1[bitPos]+bitThreshold2[bitPos]; + uint16_t bitValue=arithDecoder.decode(bitSize+1); + if (bitValue==bitSize) break; + bool bit=bitValue=6000) + { + if (!(bitThreshold1[bitPos]>>=1)) bitThreshold1[bitPos]=1; + if (!(bitThreshold2[bitPos]>>=1)) bitThreshold2[bitPos]=1; + } + bitPos=(bitPos<<1&2)|(bit?0:1); + if (bit) + { + // literal + outputStream.writeByte(uint8_t(twoStepArithDecoder(litInitial,litDynamic,litThreshold,1000,1,8))); + } else { + // copy + while (outputStream.getOffset()>(1ULL<=2) + { + uint16_t minRange=1<<(distanceBits-1); + uint16_t range=distanceIndex==distanceBits?static_cast(std::min(outputStream.getOffset(),size_t(31200U)))-minRange:minRange; + distance=arithDecoder.decode(range); + arithDecoder.scale(distance,distance+1,range); + distance+=minRange; + } + distance++; + uint32_t count=twoStepArithDecoder(countInitial,countDynamic,countThreshold,6000,8,4); + if (count==15) + { + count=783; + } else if (count>=16) { + uint16_t value=arithDecoder.decode(16); + arithDecoder.scale(value,value+1,16); + count=((count-16)<<4)+value+15; + } + count+=3; + outputStream.copy(distance,count); + } + } + if (!outputStream.eof()) throw Decompressor::DecompressionError(); +} + +template +class CheckedArray +{ +public: + CheckedArray() : + _memory(length*sizeof(T)) + { + // nothing needed + } + + ~CheckedArray() + { + // nothing needed + } + + T &operator[](size_t i) + { + if (i>=length) throw Decompressor::DecompressionError(); + return _memory.cast()[i]; + } + + const T &operator[](size_t i) const + { + if (i>=length) throw Decompressor::DecompressionError(); + return _memory.cast()[i]; + } + +private: + MemoryBuffer _memory; +}; + +// The horror. It needs to follow exactly the original logic, even if that logic is not very good. +void SXSCDecompressor::decompressHSC(Buffer &rawData,ForwardInputStream &inputStream) +{ + struct Model + { + uint8_t context[4]; + + uint16_t hashPointer; + uint16_t expiryPrevious; + uint16_t expiryNext; + uint16_t frequencyTotal; + uint16_t escapeFrequency; + + uint8_t contextLength; + uint8_t characterCount; + uint8_t refreshCounter; + }; + + struct Frequency + { + uint16_t frequency; + uint16_t next; + uint8_t character; + }; + + struct HashItem + { + uint16_t data; + uint16_t random; + }; + + ForwardOutputStream outputStream(rawData,0,rawData.size()); + + uint16_t bitReaderInitialValue; + bitReaderInitialValue=inputStream.readByte()<<8; + bitReaderInitialValue|=inputStream.readByte(); + SXSCReader bitReader(inputStream); + RangeDecoder arithDecoder(bitReader,bitReaderInitialValue); + + uint8_t maxContextLength=4; + int16_t dropCount=2500; + int16_t contextSearchLength=0; + + CheckedArray models{}; + for (uint32_t i=0;i<10000;i++) + { + auto &m=models[i]; + + for (uint32_t j=0;j<4;j++) + m.context[j]=0; + + m.hashPointer=0; + m.expiryPrevious=i-1; + m.expiryNext=i+1; + m.frequencyTotal=0; + m.escapeFrequency=0; + + m.contextLength=0xffU; + m.characterCount=0; + m.refreshCounter=0; + } + + uint8_t currentContext[4]; + for (uint32_t i=0;i<4;i++) currentContext[i]=0; + uint16_t firstExpiry=0,lastExpiry=9999; + uint16_t freeBlockPointer=10000; + uint16_t releaseBlock=0; + + CheckedArray frequencies{}; + for (uint32_t i=0;i<32760;i++) + { + auto &f=frequencies[i]; + f.frequency=0; + f.next=(i>=10000&&i<32759)?i+1:0xffffU; + f.character=0; + } + + CheckedArray hashes{}; + for (uint32_t i=0,j=10;i<0x4000U;i++) + { + auto &h=hashes[i]; + h.data=0xffffU; + // constants used are 2147483647 % / 16807 + int32_t integerPart=j/127773U; + int32_t fractionalPart=j%127773U; + int32_t tmp=16807*fractionalPart-2836*integerPart; + j=tmp<0?tmp+0x7fff'ffff:tmp; + h.random=j&0x3fffU; + } + uint16_t hashStack[5]; + for (uint32_t i=0;i<5;i++) + hashStack[i]=0; + + bool characterMask[256]; + uint8_t characterMaskStack[256]; + for (uint32_t i=0;i<256;i++) + { + characterMask[i]=false; + characterMaskStack[i]=0; + } + int16_t characterMaskStackPointer=0; + + uint8_t initialEscapeChar[5]; + for (uint32_t i=0;i<5;i++) + initialEscapeChar[i]=i?15:16; + uint8_t escapeCharacterCounter=0; + + uint16_t stackPointer=0; + uint16_t contextPointer[5]; + uint16_t frequencyArrayIndex[5]; + for (uint32_t i=0;i<5;i++) + { + contextPointer[i]=0; + frequencyArrayIndex[i]=0; + } + + auto loopBreaker=[](uint16_t i) { + if (i>=0x8000U) throw Decompressor::DecompressionError(); + }; + + auto findNext=[&]()->uint16_t + { + for (int32_t i=contextSearchLength-1;i>=0;i--) + { + for (uint32_t lb=0,j=hashes[hashStack[i]].data;j!=0xffffU;j=models[j].hashPointer,loopBreaker(lb++)) + { + if (i==models[j].contextLength) + { + if ([&]()->bool + { + for (int32_t k=0;k=value) break; + i++; + } + arithDecoder.scale(i,i+1,size); + break; + } + + // madness!!! + auto getEscFrequency=[&](uint16_t value,uint16_t i)->uint16_t + { + auto &model=models[i]; + if (model.frequencyTotal==1) + return initialEscapeChar[model.contextLength]>=16?2:1; + if (model.characterCount==0xffU) return 1; + uint16_t tmp=uint16_t(model.characterCount)*2+2; + if (model.characterCount && tmp>=model.frequencyTotal) + { + value=int32_t(value)*tmp/model.frequencyTotal; + if (model.characterCount+1==model.frequencyTotal) value+=tmp>>2; + } + if (!value) value++; + return value; + }; + + int16_t freq=0,escapeFreq=0; + int16_t currentFrequency=0,frequencyTotal=0; + auto decodeCf=[&](uint16_t shift,bool cmCondition)->uint16_t + { + freq<<=shift; + uint16_t i,value=arithDecoder.decode(freq+escapeFreq)>>shift; + uint32_t lb=0; + for (i=index;i!=0xffffU;i=frequencies[i].next,loopBreaker(lb++)) + { + auto &frequency=frequencies[i]; + if (cmCondition||!characterMask[frequency.character]) + { + if (frequencyTotal+frequency.frequency<=value) + { + frequencyTotal+=frequency.frequency; + } else { + currentFrequency=frequency.frequency<bool + { + if (chPos==0xffffU) + { + arithDecoder.scale(freq,freq+escapeFreq,freq+escapeFreq); + if (models[index].frequencyTotal==1 && initialEscapeChar[models[index].contextLength]<32) + initialEscapeChar[models[index].contextLength]++; + uint16_t prevI=0; + for (uint16_t lb=0,i=index;i!=0xffffU;prevI=i,i=frequencies[i].next,loopBreaker(lb++)) + { + auto &frequency=frequencies[i]; + if (cmCondition||!characterMask[frequency.character]) + { + if (characterMaskStackPointer==256) throw Decompressor::DecompressionError(); + characterMaskStack[characterMaskStackPointer++]=frequency.character; + characterMask[frequency.character]=true; + } + } + contextPointer[insertPos]=index|0x8000U; + frequencyArrayIndex[insertPos]=prevI; + ch=256; + return true; + } else { + arithDecoder.scale(frequencyTotal,frequencyTotal+currentFrequency,freq+escapeFreq); + if (models[index].frequencyTotal==1 && initialEscapeChar[models[index].contextLength]) + initialEscapeChar[models[index].contextLength]--; + contextPointer[insertPos]=index; + frequencyArrayIndex[insertPos]=chPos; + ch=frequencies[chPos].character; + return false; + } + }; + + if (characterMaskStackPointer) + { + for (uint16_t lb=0,i=index;i!=0xffffU;i=frequencies[i].next,loopBreaker(lb++)) + { + auto &frequency=frequencies[i]; + if (!characterMask[frequency.character]) + { + freq+=frequency.frequency; + if (frequency.frequency<3) escapeFreq++; + } + } + escapeFreq=getEscFrequency(escapeFreq,index); + + uint16_t chPos=decodeCf(0,false); + if (stackPointer==5) throw Decompressor::DecompressionError(); + if (!decodeCh(chPos,stackPointer,false)) + { + if (escapeCharacterCounter==10) throw Decompressor::DecompressionError(); + escapeCharacterCounter++; + } + stackPointer++; + + } else { + freq=models[index].frequencyTotal; + escapeFreq=getEscFrequency(models[index].escapeFrequency,index); + + uint16_t chPos=decodeCf((escapeCharacterCounter>=5)?(freq<5 && escapeCharacterCounter==10)?2:1:0,true); + + stackPointer=1; + if (decodeCh(chPos,0,true)) + { + escapeCharacterCounter=0; + } else { + if (escapeCharacterCounter<10) escapeCharacterCounter++; + } + } + + if (ch!=256) + { + if (index!=firstExpiry) + { + auto &model=models[index]; + if (index==lastExpiry) + { + lastExpiry=model.expiryPrevious; + } else { + models[model.expiryNext].expiryPrevious=model.expiryPrevious; + models[model.expiryPrevious].expiryNext=model.expiryNext; + } + models[firstExpiry].expiryPrevious=index; + model.expiryNext=firstExpiry; + firstExpiry=index; + } + break; + } + } + + if (ch==256) break; + + while (stackPointer) + { + uint16_t freqIndex=frequencyArrayIndex[--stackPointer]; + uint16_t pointer=contextPointer[stackPointer]; + auto &model=models[pointer&0x7fffU]; + if (pointer&0x8000U) + { + if (freeBlockPointer==0xffffU) + { + for (uint16_t i=0;i<=stackPointer;) + { + // yuck + uint32_t lb=0; + do + { + releaseBlock=(releaseBlock!=9999U)?releaseBlock+1:0; + loopBreaker(lb++); + } while (frequencies[releaseBlock].next==0xffffU); + for (i=0;i<=stackPointer;i++) + if ((contextPointer[i]&0x7fffU)==releaseBlock) break; + } + auto &frequencyRB=frequencies[releaseBlock]; + auto &modelRB=models[releaseBlock]; + uint16_t f=frequencyRB.frequency; + for (uint16_t lb=0,i=frequencyRB.next;i!=0xffffU;i=frequencies[i].next,loopBreaker(lb++)) + if (frequencies[i].frequencyfrequencies[freqIndex].frequency*2) + { + model.refreshCounter--; + } else if (model.refreshCounter<4) { + model.refreshCounter++; + } + // one ugly scaler + if (!model.refreshCounter||model.frequencyTotal>=8000) + { + model.refreshCounter++; + model.escapeFrequency=0; + model.frequencyTotal=0; + for (uint16_t lb=0,i=pointer&0x7fffU;i!=0xffffU;i=frequencies[i].next,loopBreaker(lb++)) + { + if (frequencies[i].frequency>1) + { + uint16_t tmp=frequencies[i].frequency>>=1; + model.frequencyTotal+=tmp; + if (tmp<3) model.escapeFrequency++; + } else { + model.escapeFrequency++; + model.frequencyTotal++; + } + } + } + } + + uint8_t maxLength=maxContextLength+1; + while (maxLength-->minLength) + { + auto hash=[&](const uint8_t *block,uint32_t length)->uint16_t + { + uint16_t ret=0; + for (uint32_t i=0;i=2); + std::unique_ptr tmpBuffer; + if (needsTmpBuffer) tmpBuffer=std::make_unique(rawData.size()); + if (_isHSC) decompressHSC(needsTmpBuffer?*tmpBuffer:rawData,inputStream); + else decompressASC(needsTmpBuffer?*tmpBuffer:rawData,inputStream); + + // Mono, High byte only + // also includes de-interleaving + auto deltaDecode16BE=[&]() + { + size_t length=rawData.size(); + const uint8_t *src=tmpBuffer->data(); + const uint8_t *midSrc=&src[length>>1]; + uint8_t *dest=rawData.data(); + + uint8_t ctr=0; + for (size_t i=0,j=0;jdata(); + const uint8_t *midSrc=&src[length>>1]; + uint8_t *dest=rawData.data(); + + uint8_t ctr=0; + for (size_t i=0,j=0;j + +#include "XPKDecompressor.hpp" +#include "InputStream.hpp" +#include "RangeDecoder.hpp" + +namespace ancient::internal +{ + +class SXSCDecompressor : public XPKDecompressor +{ +public: + SXSCDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + + virtual ~SXSCDecompressor(); + + virtual const std::string &getSubName() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) override final; + + static bool detectHeaderXPK(uint32_t hdr) noexcept; + static std::shared_ptr create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + +private: + class SXSCReader : public RangeDecoder::BitReader + { + public: + SXSCReader(ForwardInputStream &stream); + virtual ~SXSCReader(); + + virtual uint32_t readBit() override final; + + private: + MSBBitReader _reader; + }; + + void decompressASC(Buffer &rawData,ForwardInputStream &inputStream); + void decompressHSC(Buffer &rawData,ForwardInputStream &inputStream); + + const Buffer &_packedData; + bool _isHSC; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/StoneCrackerDecompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/StoneCrackerDecompressor.cpp new file mode 100644 index 00000000..2410f105 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/StoneCrackerDecompressor.cpp @@ -0,0 +1,695 @@ +/* Copyright (C) Teemu Suutari */ + +#include "StoneCrackerDecompressor.hpp" +#include "InputStream.hpp" +#include "OutputStream.hpp" +#include "HuffmanDecoder.hpp" +#include "common/Common.hpp" + + +namespace ancient::internal +{ + +bool StoneCrackerDecompressor::detectHeaderAndGeneration(uint32_t hdr,uint32_t &generation) noexcept +{ + // Stonecracker 2.71 (and others from 2.69 - 2.8 series) do not have any sensible identification value + // first 3 bytes are constants for RLE-encoder (byte values for RLE-encoder, at least they are unique) + // last byte is bit length. + // + // 2.92 and 2.99 do not have either any proper identification word either, however its + // bit lengts for decompressor are stored in the first 4 bytes, which forms identifiable + // value. + // + // Thus for detecting 2.71 and friends, we are creating lots of false positives here. + // At least we can rule those out later when detecting the actual header content + // Final complication is that values for 2.71/2.9X overlap, this we need to handle + // later as well + if (hdr>=0x08090a08U&&hdr<=0x08090a0eU&&hdr!=0x08090a09U) + { + // can be generation 1 as well. needs to be determined later + generation=2; + return true; + } + if ((hdr&0xffU)>=0x08U&&(hdr&0xffU)<=0x0eU) + { + uint8_t byte0=hdr>>24U; + uint8_t byte1=hdr>>16U; + uint8_t byte2=hdr>>8U; + // only limiter I can think of apart from the last byte is that the rle-bytes are unique + if (byte0!=byte1 && byte0!=byte2 && byte1!=byte2) + { + generation=1; + return true; + } + } + // From 3.00 and onwards we can be certain of the format + switch (hdr) + { + case FourCC("S300"): + generation=3; + return true; + + case FourCC("S310"): + generation=4; + return true; + + case FourCC("S400"): + generation=5; + return true; + + case FourCC("S401"): + generation=6; + return true; + + case FourCC("S403"): + generation=7; + return true; + + case FourCC("S404"): + generation=8; + return true; + + default: + return false; + } +} + +bool StoneCrackerDecompressor::detectHeader(uint32_t hdr) noexcept +{ + uint32_t dummy; + return detectHeaderAndGeneration(hdr,dummy); +} + +std::shared_ptr StoneCrackerDecompressor::create(const Buffer &packedData,bool exactSizeKnown,bool verify) +{ + return std::make_shared(packedData,exactSizeKnown,verify); +} + +void StoneCrackerDecompressor::initialize(const Buffer &packedData,uint32_t hdr) +{ + auto readModes=[&](uint32_t value) + { + for (uint32_t i=0;i<4U;i++) + { + _modes[i]=value>>24U; + if (_modes[i]<8U || _modes[i]>14U) + throw InvalidFormatError(); + value<<=8U; + } + }; + + switch (_generation) + { + case 1: + _dataOffset=18U; + _rle[0]=hdr>>24U; + _rle[1]=hdr>>16U; + _rle[2]=hdr>>8U; + _modes[0]=hdr; + if (packedData.size()<_dataOffset) throw InvalidFormatError(); + for (uint32_t i=1;i<3U;i++) + { + _modes[i]=packedData.read8(i+15U); + if (_modes[i]<4U || _modes[i]>7U) + throw InvalidFormatError(); + } + _rleSize=packedData.readBE32(4U); + _rawSize=packedData.readBE32(8U); + _packedSize=packedData.readBE32(12U); + break; + + case 2: + readModes(hdr); + case 4: + case 5: + case 6: + _dataOffset=12U; + if (packedData.size()<_dataOffset) throw InvalidFormatError(); + _rawSize=packedData.readBE32(4U); + _packedSize=packedData.readBE32(8U); + break; + + case 3: + _dataOffset=16U; + if (packedData.size()<_dataOffset) throw InvalidFormatError(); + readModes(packedData.readBE32(4)); + _rawSize=packedData.readBE32(8U); + _packedSize=packedData.readBE32(12U); + break; + + case 7: + case 8: + _dataOffset=16U; + if (packedData.size()<_dataOffset+2U) throw InvalidFormatError(); + _rawSize=packedData.readBE32(8U); + _packedSize=packedData.readBE32(12U)+2U; + break; + + default: + throw InvalidFormatError(); + break; + } + + if (_packedSize>getMaxPackedSize() || _rawSize>getMaxRawSize()) + throw InvalidFormatError(); + + // Final sanity checks on old formats, especially on 2.71 which can still be false positive + // For a sanity check we assume the compressor is actually compressing, which is not a exactly wrong thing to do + // (of course there could be expanding files, but it is doubtful someone would actually used them) + // Also, the compressor seem to crash on large files. Lets cap the filesize to 1M + if (_generation==1 && (_rleSize>_rawSize || _packedSize>_rleSize || _rawSize>1048'576U)) + throw InvalidFormatError(); + _packedSize+=_dataOffset; + if (_packedSize>packedData.size()) + throw InvalidFormatError(); +} + +StoneCrackerDecompressor::StoneCrackerDecompressor(const Buffer &packedData,bool exactSizeKnown,bool verify) : + _packedData(packedData) +{ + uint32_t hdr=packedData.readBE32(0); + if (!detectHeaderAndGeneration(hdr,_generation)) throw InvalidFormatError(); + + bool initialized=false; + // this is the fallback if we have accidentally identified the wrong version + if (_generation==2) + { + try + { + initialize(packedData,hdr); + initialized=true; + } catch (const Error &) { + _generation=1; + } + } + if (!initialized) initialize(packedData,hdr); +} + +StoneCrackerDecompressor::~StoneCrackerDecompressor() +{ + // nothing needed +} + +const std::string &StoneCrackerDecompressor::getName() const noexcept +{ + switch (_generation) + { + case 1: + { + static std::string name="SC: StoneCracker v2.69 - v2.81"; + return name; + } + + case 2: + { + static std::string name="SC: StoneCracker v2.92, v2.99"; + return name; + } + + case 3: + { + static std::string name="S300: StoneCracker v3.00"; + return name; + } + + case 4: + { + static std::string name="S310: StoneCracker v3.10, v3.11b"; + return name; + } + + case 5: + { + static std::string name="S400: StoneCracker pre v4.00"; + return name; + } + + case 6: + { + static std::string name="S401: StoneCracker v4.01"; + return name; + } + + case 7: + { + static std::string name="S403: StoneCracker v4.02a"; + return name; + } + + case 8: + { + static std::string name="S404: StoneCracker v4.10"; + return name; + } + } + static std::string dummy=""; + return dummy; +} + +size_t StoneCrackerDecompressor::getPackedSize() const noexcept +{ + return _packedSize; +} + +size_t StoneCrackerDecompressor::getRawSize() const noexcept +{ + return _rawSize; +} + +// v2.71 +void StoneCrackerDecompressor::decompressGen1(Buffer &rawData) +{ + BackwardInputStream inputStream(_packedData,_dataOffset,_packedSize); + MSBBitReader bitReader(inputStream); + + MemoryBuffer tmpBuffer(_rleSize); + BackwardOutputStream outputStream(tmpBuffer,0,_rleSize); + + auto readBits=[&](uint32_t count)->uint32_t + { + return bitReader.readBitsBE32(count); + }; + auto readBit=[&]()->uint32_t + { + return bitReader.readBitsBE32(1); + }; + + + // anchor-bit handling + { + uint32_t value=0; + for (uint32_t i=0;i<4U;i++) + { + value>>=8U; + value|=uint32_t(inputStream.readByte())<<24U; + } + uint32_t tmp=value; + uint32_t count=0; + while (tmp) + { + tmp<<=1; + count++; + } + if (count) count--; + if (count) + bitReader.reset(value>>(32U-count),count); + } + + struct SCItem + { + uint32_t distanceBits; + uint32_t countBits; + uint32_t addition; + bool isLiteral; + }; + + // logic is very hard to un-convolute... + HuffmanDecoder scDecoder + { + HuffmanCode{2,0b000,SCItem{0,3U,0,true}}, + HuffmanCode{3,0b010,SCItem{0,_modes[2]+1U,8U,true}}, + HuffmanCode{3,0b011,SCItem{_modes[0]+1U,_modes[1]+1U,5U,false}}, + HuffmanCode{2,0b010,SCItem{8U,0,2U,false}}, + HuffmanCode{3,0b110,SCItem{9U,0,3U,false}}, + HuffmanCode{3,0b111,SCItem{10U,0,4U,false}} + }; + + while (!outputStream.eof()) + { + const auto &item=scDecoder.decode(readBit); + if (item.isLiteral) + { + uint32_t count=readBits(item.countBits); + if (!item.addition) count=!count?8U:count; // why?!? + else count+=item.addition; + for (uint32_t i=0;i bitReader(inputStream); + + BackwardOutputStream outputStream(rawData,0,_rawSize); + + // anchor-bit handling + { + uint32_t value=0; + for (uint32_t i=0;i<4U;i++) + { + value>>=8U; + value|=uint32_t(inputStream.readByte())<<24U; + } + if (value) for (uint32_t i=31U;i>0;i--) + { + if (value&(1U<uint32_t + { + return bitReader.readBitsBE32(count); + }; + auto readBit=[&]()->uint32_t + { + return bitReader.readBitsBE32(1); + }; + + auto readCount=[&](uint32_t threshold,uint32_t bits)->uint32_t + { + uint32_t ret=0; + uint32_t tmp; + do + { + tmp=rotateBits(readBits(bits),bits); + ret+=tmp; + } while (tmp==threshold); + return ret; + }; + + bool gen3=_generation>=3; + while (!outputStream.eof()) + { + if (readBit()) + { + uint32_t count=readCount(7U,3U); + if (gen3) count++; + // for 2.92 zero count could meant count of 65536 + // for 2.99 it would be 4G + // nevertheless it is an error + // 3.00 fixes this by +1 + if (!count) + throw DecompressionError(); + for (uint32_t i=0;i bitReader(inputStream); + + ForwardOutputStream outputStream(rawData,0,_rawSize); + + auto readBits=[&](uint32_t count)->uint32_t + { + if (_generation==4) return bitReader.readBitsBE32(count); + else return bitReader.readBitsBE16(count); + }; + auto readBit=[&]()->uint32_t + { + return readBits(1); + }; + + auto readCount=[&](uint32_t threshold,uint32_t bits)->uint32_t + { + uint32_t ret=0; + uint32_t tmp; + do + { + tmp=readBits(bits); + ret+=tmp; + } while (tmp==threshold); + return ret; + }; + + static const uint8_t modes[4]={10U,11U,12U,8U}; + + while (!outputStream.eof()) + { + if (readBit()) + { + uint32_t mode=readBits(2U); + uint32_t distance=readBits(modes[mode]); + // will obviously throw if distance is 0 + uint32_t count; + if (mode>=2U) + { + if (_generation==4) count=readCount(15U,4U)+3U; + else count=readCount(7U,3U)+3U; + } else { + count=mode+3U; + } + // yet another bug + if (count>_rawSize-uint32_t(outputStream.getOffset())) + count=_rawSize-uint32_t(outputStream.getOffset()); + outputStream.copy(distance,count); + } else { + uint32_t count=readCount(7U,3U); + // A regression in 3.10 that is not fixed until 4.01 + if (_generation==6) count++; + if (!count) + throw DecompressionError(); + for (uint32_t i=0;i bitReader(inputStream); + + BackwardOutputStream outputStream(rawData,0,_rawSize); + + // incomplete value at start + { + uint16_t bitCount=_packedData.readBE16(_packedSize-2U); + if (bitCount>16U) + throw DecompressionError(); + uint16_t value=inputStream.readByte(); + value|=uint16_t(inputStream.readByte())<<8U; + bitReader.reset(value,bitCount&0xff); + } + + auto readBits=[&](uint32_t count)->uint32_t + { + return bitReader.readBitsBE16(count); + }; + auto readBit=[&]()->uint32_t + { + return bitReader.readBitsBE16(1); + }; + + while (!outputStream.eof()) + { + if (readBit()) + { + static const uint8_t distanceBits[4]={5U,8U,10U,12U}; + static const uint32_t distanceAdditions[4]={1U,0x21,0x121U,0x521U}; + uint32_t mode=readBits(2U); + uint32_t distance=readBits(distanceBits[mode])+distanceAdditions[mode]; + // christmas tree! + uint32_t count=2U; + if (!readBit()) + { + count++; + if (!readBit()) + { + count++; + if (!readBit()) + { + count++; + uint32_t tmp; + do + { + tmp=readBits(3U); + count+=tmp; + } while (tmp==7U); + } + } + } + outputStream.copy(distance,count); + } else { + outputStream.writeByte(readBits(8)); + } + } +} + +// v4.10 +void StoneCrackerDecompressor::decompressGen8(Buffer &rawData) +{ + BackwardInputStream inputStream(_packedData,_dataOffset,_packedSize-2U); + MSBBitReader bitReader(inputStream); + + BackwardOutputStream outputStream(rawData,0,_rawSize); + + // incomplete value at start + uint16_t modeBits=0; + { + uint16_t bitCount=_packedData.readBE16(_packedSize-2U)&15U; + uint16_t value=inputStream.readByte(); + value|=uint16_t(inputStream.readByte())<<8U; + bitReader.reset(value>>(16U-bitCount),bitCount&0xff); + + modeBits=inputStream.readByte(); + modeBits|=uint16_t(inputStream.readByte())<<8U; + if (modeBits<10U || modeBits>14U) + throw DecompressionError(); + } + + auto readBits=[&](uint32_t count)->uint32_t + { + return bitReader.readBitsBE16(count); + }; + auto readBit=[&]()->uint32_t + { + return bitReader.readBitsBE16(1); + }; + + struct CountItem + { + uint32_t bits; + uint32_t addition; + bool isLiteral; + }; + + struct DistanceItem + { + uint32_t bits; + uint32_t addition; + }; + + HuffmanDecoder countDecoder + { + HuffmanCode{1,0b00000000,CountItem{0,1U,true}}, + HuffmanCode{2,0b00000011,CountItem{1U,2U,false}}, + HuffmanCode{3,0b00000101,CountItem{2U,4U,false}}, + HuffmanCode{4,0b00001000,CountItem{8U,23U,false}}, + HuffmanCode{5,0b00010010,CountItem{3U,8U,false}}, + HuffmanCode{6,0b00100110,CountItem{2U,16U,false}}, + HuffmanCode{7,0b01001110,CountItem{1U,20U,false}}, + HuffmanCode{8,0b10011110,CountItem{0,22U,false}}, + HuffmanCode{8,0b10011111,CountItem{5U,14U,true}} + }; + + HuffmanDecoder distanceDecoder + { + HuffmanCode{1,0b01,DistanceItem{modeBits,0x221U}}, + HuffmanCode{2,0b00,DistanceItem{9U,0x21U}}, + HuffmanCode{2,0b01,DistanceItem{5U,0x1U}} + }; + + while (!outputStream.eof()) + { + const auto &countItem=countDecoder.decode(readBit); + uint32_t count=countItem.addition; + uint32_t tmp; + do + { + tmp=readBits(countItem.bits); + count+=tmp; + } while (tmp==0xffU); + if (countItem.isLiteral) + { + for (uint32_t i=0;i create(const Buffer &packedData,bool exactSizeKnown,bool verify); + +private: + static bool detectHeaderAndGeneration(uint32_t hdr,uint32_t &generation) noexcept; + + void initialize(const Buffer &packedData,uint32_t hdr); + void decompressGen1(Buffer &rawData); + void decompressGen23(Buffer &rawData); + void decompressGen456(Buffer &rawData); + void decompressGen7(Buffer &rawData); + void decompressGen8(Buffer &rawData); + + const Buffer &_packedData; + + uint32_t _rawSize=0; + uint32_t _packedSize=0; + uint32_t _rleSize=0; + uint8_t _modes[4]; + uint8_t _rle[3]; + uint32_t _generation; + uint32_t _dataOffset; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/TDCSDecompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/TDCSDecompressor.cpp new file mode 100644 index 00000000..cae05c0e --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/TDCSDecompressor.cpp @@ -0,0 +1,96 @@ +/* Copyright (C) Teemu Suutari */ + +#include "TDCSDecompressor.hpp" +#include "InputStream.hpp" +#include "OutputStream.hpp" +#include "common/Common.hpp" + + +namespace ancient::internal +{ + +bool TDCSDecompressor::detectHeaderXPK(uint32_t hdr) noexcept +{ + return hdr==FourCC("TDCS"); +} + +std::shared_ptr TDCSDecompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) +{ + return std::make_shared(hdr,recursionLevel,packedData,state,verify); +} + +TDCSDecompressor::TDCSDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) : + XPKDecompressor(recursionLevel), + _packedData(packedData) +{ + if (!detectHeaderXPK(hdr)) throw Decompressor::InvalidFormatError(); +} + +TDCSDecompressor::~TDCSDecompressor() +{ + // nothing needed +} + +const std::string &TDCSDecompressor::getSubName() const noexcept +{ + static std::string name="XPK-TDCS: LZ77-compressor"; + return name; +} + +void TDCSDecompressor::decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) +{ + ForwardInputStream inputStream(_packedData,0,_packedData.size()); + MSBBitReader bitReader(inputStream); + auto read2Bits=[&]()->uint32_t + { + return bitReader.readBitsBE32(2); + }; + auto readByte=[&]()->uint8_t + { + return inputStream.readByte(); + }; + + ForwardOutputStream outputStream(rawData,0,rawData.size()); + + while (!outputStream.eof()) + { + uint32_t distance=0; + uint32_t count=0; + uint32_t tmp; + switch (read2Bits()) + { + case 0: + outputStream.writeByte(readByte()); + break; + + case 1: + tmp=uint32_t(readByte())<<8; + tmp|=uint32_t(readByte()); + count=(tmp&3)+3; + distance=((tmp>>2)^0x3fff)+1; + break; + + case 2: + tmp=uint32_t(readByte())<<8; + tmp|=uint32_t(readByte()); + count=(tmp&0xf)+3; + distance=((tmp>>4)^0xfff)+1; + break; + + case 3: + distance=uint32_t(readByte())<<8; + distance|=uint32_t(readByte()); + count=uint32_t(readByte())+3; + if (!distance) throw Decompressor::DecompressionError(); + distance=(distance^0xffff)+1; + break; + + default: + throw Decompressor::DecompressionError(); + } + if (count && distance) + outputStream.copy(distance,count); + } +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/TDCSDecompressor.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/TDCSDecompressor.hpp new file mode 100644 index 00000000..edbd22f4 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/TDCSDecompressor.hpp @@ -0,0 +1,31 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef TDCSDECOMPRESSOR_HPP +#define TDCSDECOMPRESSOR_HPP + +#include "XPKDecompressor.hpp" + +namespace ancient::internal +{ + +class TDCSDecompressor : public XPKDecompressor +{ +public: + TDCSDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + + virtual ~TDCSDecompressor(); + + virtual const std::string &getSubName() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) override final; + + static bool detectHeaderXPK(uint32_t hdr) noexcept; + static std::shared_ptr create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + +private: + const Buffer &_packedData; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/TPWMDecompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/TPWMDecompressor.cpp new file mode 100644 index 00000000..c078e465 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/TPWMDecompressor.cpp @@ -0,0 +1,92 @@ +/* Copyright (C) Teemu Suutari */ + +#include "TPWMDecompressor.hpp" +#include "InputStream.hpp" +#include "OutputStream.hpp" +#include "common/Common.hpp" + + +namespace ancient::internal +{ + +bool TPWMDecompressor::detectHeader(uint32_t hdr) noexcept +{ + return hdr==FourCC("TPWM"); +} + +std::shared_ptr TPWMDecompressor::create(const Buffer &packedData,bool exactSizeKnown,bool verify) +{ + return std::make_shared(packedData,verify); +} + +TPWMDecompressor::TPWMDecompressor(const Buffer &packedData,bool verify) : + _packedData(packedData) +{ + uint32_t hdr=packedData.readBE32(0); + if (!detectHeader(hdr) || packedData.size()<12) throw InvalidFormatError(); + + _rawSize=packedData.readBE32(4); + if (!_rawSize || _rawSize>getMaxRawSize()) + throw InvalidFormatError(); +} + +TPWMDecompressor::~TPWMDecompressor() +{ + // nothing needed +} + +const std::string &TPWMDecompressor::getName() const noexcept +{ + static std::string name="TPWM: Turbo Packer"; + return name; +} + +size_t TPWMDecompressor::getPackedSize() const noexcept +{ + // No packed size in the stream :( + // After decompression, we can tell how many bytes were actually used + return _decompressedPackedSize; +} + +size_t TPWMDecompressor::getRawSize() const noexcept +{ + return _rawSize; +} + +void TPWMDecompressor::decompressImpl(Buffer &rawData,bool verify) +{ + if (rawData.size()<_rawSize) throw DecompressionError(); + + ForwardInputStream inputStream(_packedData,8,_packedData.size()); + MSBBitReader bitReader(inputStream); + auto readBit=[&]()->uint32_t + { + return bitReader.readBits8(1); + }; + auto readByte=[&]()->uint8_t + { + return inputStream.readByte(); + }; + + ForwardOutputStream outputStream(rawData,0,_rawSize); + + while (!outputStream.eof()) + { + if (readBit()) + { + uint8_t byte1=readByte(); + uint8_t byte2=readByte(); + uint32_t distance=(uint32_t(byte1&0xf0)<<4)|byte2; + uint32_t count=uint32_t(byte1&0xf)+3; + + count=std::min(count,uint32_t(_rawSize-outputStream.getOffset())); + outputStream.copy(distance,count); + } else { + outputStream.writeByte(readByte()); + } + } + + _decompressedPackedSize=inputStream.getOffset(); +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/TPWMDecompressor.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/TPWMDecompressor.hpp new file mode 100644 index 00000000..5fd74a95 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/TPWMDecompressor.hpp @@ -0,0 +1,36 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef TPWMDECOMPRESSOR_HPP +#define TPWMDECOMPRESSOR_HPP + +#include "Decompressor.hpp" + +namespace ancient::internal +{ + +class TPWMDecompressor : public Decompressor +{ +public: + TPWMDecompressor(const Buffer &packedData,bool verify); + + virtual ~TPWMDecompressor(); + + virtual const std::string &getName() const noexcept override final; + virtual size_t getPackedSize() const noexcept override final; + virtual size_t getRawSize() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,bool verify) override final; + + static bool detectHeader(uint32_t hdr) noexcept; + static std::shared_ptr create(const Buffer &packedData,bool exactSizeKnown,bool verify); + +private: + const Buffer &_packedData; + + uint32_t _rawSize=0; + size_t _decompressedPackedSize=0; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/XPKDecompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/XPKDecompressor.cpp new file mode 100644 index 00000000..be40d5f9 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/XPKDecompressor.cpp @@ -0,0 +1,25 @@ +/* Copyright (C) Teemu Suutari */ + +#include "XPKDecompressor.hpp" +#include "XPKMain.hpp" + +namespace ancient::internal +{ + +XPKDecompressor::State::~State() +{ + // nothing needed +} + +XPKDecompressor::XPKDecompressor(uint32_t recursionLevel) : + _recursionLevel(recursionLevel) +{ + // nothing needed +} + +XPKDecompressor::~XPKDecompressor() +{ + // nothing needed +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/XPKDecompressor.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/XPKDecompressor.hpp new file mode 100644 index 00000000..26e1d920 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/XPKDecompressor.hpp @@ -0,0 +1,48 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef XPKDECOMPRESSOR_HPP +#define XPKDECOMPRESSOR_HPP + +#include +#include + +#include + +#include "Decompressor.hpp" + +namespace ancient::internal +{ + +class XPKDecompressor +{ +public: + class State + { + public: + State(const State&)=delete; + State& operator=(const State&)=delete; + + State()=default; + virtual ~State(); + + uint32_t getRecursionLevel() const; + }; + + XPKDecompressor(const XPKDecompressor&)=delete; + XPKDecompressor& operator=(const XPKDecompressor&)=delete; + + XPKDecompressor(uint32_t recursionLevel=0); + virtual ~XPKDecompressor(); + + virtual const std::string &getSubName() const noexcept=0; + + // Actual decompression + virtual void decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify)=0; + +protected: + uint32_t _recursionLevel; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/XPKMain.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/XPKMain.cpp new file mode 100644 index 00000000..7b3089f0 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/XPKMain.cpp @@ -0,0 +1,342 @@ +/* Copyright (C) Teemu Suutari */ + +#include +#include +#include + +#include "common/SubBuffer.hpp" +#include "common/OverflowCheck.hpp" +#include "common/Common.hpp" +#include "common/Common.hpp" +#include "XPKMain.hpp" +#include "XPKDecompressor.hpp" + +#include "ACCADecompressor.hpp" +#include "ARTMDecompressor.hpp" +#include "BLZWDecompressor.hpp" +#include "BZIP2Decompressor.hpp" +#include "CBR0Decompressor.hpp" +#include "CRMDecompressor.hpp" +#include "CYB2Decoder.hpp" +#include "DEFLATEDecompressor.hpp" +#include "DLTADecode.hpp" +#include "FASTDecompressor.hpp" +#include "FBR2Decompressor.hpp" +#include "FRLEDecompressor.hpp" +#include "HFMNDecompressor.hpp" +#include "HUFFDecompressor.hpp" +#include "ILZRDecompressor.hpp" +#include "IMPDecompressor.hpp" +#include "LHLBDecompressor.hpp" +#include "LIN1Decompressor.hpp" +#include "LIN2Decompressor.hpp" +#include "LZBSDecompressor.hpp" +#include "LZCBDecompressor.hpp" +#include "LZW2Decompressor.hpp" +#include "LZW4Decompressor.hpp" +#include "LZW5Decompressor.hpp" +#include "LZXDecompressor.hpp" +#include "MASHDecompressor.hpp" +#include "NONEDecompressor.hpp" +#include "NUKEDecompressor.hpp" +#include "PPDecompressor.hpp" +#include "RAKEDecompressor.hpp" +#include "RDCNDecompressor.hpp" +#include "RLENDecompressor.hpp" +#include "SDHCDecompressor.hpp" +#include "SHR3Decompressor.hpp" +#include "SHRIDecompressor.hpp" +#include "SLZ3Decompressor.hpp" +#include "SMPLDecompressor.hpp" +#include "SQSHDecompressor.hpp" +#include "SXSCDecompressor.hpp" +#include "TDCSDecompressor.hpp" +#include "ZENODecompressor.hpp" + +namespace ancient::internal +{ + +bool XPKMain::detectHeader(uint32_t hdr) noexcept +{ + return hdr==FourCC("XPKF"); +} + +std::shared_ptr XPKMain::create(const Buffer &packedData,bool verify,bool exactSizeKnown) +{ + return std::make_shared(packedData,verify,0); +} + +static std::vector(*)(uint32_t,uint32_t,const Buffer&,std::shared_ptr&,bool)>> XPKDecompressors={ + {ACCADecompressor::detectHeaderXPK,ACCADecompressor::create}, + {ARTMDecompressor::detectHeaderXPK,ARTMDecompressor::create}, + {BLZWDecompressor::detectHeaderXPK,BLZWDecompressor::create}, + {BZIP2Decompressor::detectHeaderXPK,BZIP2Decompressor::create}, + {CBR0Decompressor::detectHeaderXPK,CBR0Decompressor::create}, + {CRMDecompressor::detectHeaderXPK,CRMDecompressor::create}, + {CYB2Decoder::detectHeaderXPK,CYB2Decoder::create}, + {DEFLATEDecompressor::detectHeaderXPK,DEFLATEDecompressor::create}, + {DLTADecode::detectHeaderXPK,DLTADecode::create}, + {FASTDecompressor::detectHeaderXPK,FASTDecompressor::create}, + {FBR2Decompressor::detectHeaderXPK,FBR2Decompressor::create}, + {FRLEDecompressor::detectHeaderXPK,FRLEDecompressor::create}, + {HFMNDecompressor::detectHeaderXPK,HFMNDecompressor::create}, + {HUFFDecompressor::detectHeaderXPK,HUFFDecompressor::create}, + {ILZRDecompressor::detectHeaderXPK,ILZRDecompressor::create}, + {IMPDecompressor::detectHeaderXPK,IMPDecompressor::create}, + {LHLBDecompressor::detectHeaderXPK,LHLBDecompressor::create}, + {LIN1Decompressor::detectHeaderXPK,LIN1Decompressor::create}, + {LIN2Decompressor::detectHeaderXPK,LIN2Decompressor::create}, + {LZBSDecompressor::detectHeaderXPK,LZBSDecompressor::create}, + {LZCBDecompressor::detectHeaderXPK,LZCBDecompressor::create}, + {LZW2Decompressor::detectHeaderXPK,LZW2Decompressor::create}, + {LZW4Decompressor::detectHeaderXPK,LZW4Decompressor::create}, + {LZW5Decompressor::detectHeaderXPK,LZW5Decompressor::create}, + {LZXDecompressor::detectHeaderXPK,LZXDecompressor::create}, + {MASHDecompressor::detectHeaderXPK,MASHDecompressor::create}, + {NONEDecompressor::detectHeaderXPK,NONEDecompressor::create}, + {NUKEDecompressor::detectHeaderXPK,NUKEDecompressor::create}, + {PPDecompressor::detectHeaderXPK,PPDecompressor::create}, + {RAKEDecompressor::detectHeaderXPK,RAKEDecompressor::create}, + {RDCNDecompressor::detectHeaderXPK,RDCNDecompressor::create}, + {RLENDecompressor::detectHeaderXPK,RLENDecompressor::create}, + {SDHCDecompressor::detectHeaderXPK,SDHCDecompressor::create}, + {SHR3Decompressor::detectHeaderXPK,SHR3Decompressor::create}, + {SHRIDecompressor::detectHeaderXPK,SHRIDecompressor::create}, + {SLZ3Decompressor::detectHeaderXPK,SLZ3Decompressor::create}, + {SMPLDecompressor::detectHeaderXPK,SMPLDecompressor::create}, + {SQSHDecompressor::detectHeaderXPK,SQSHDecompressor::create}, + {SXSCDecompressor::detectHeaderXPK,SXSCDecompressor::create}, + {TDCSDecompressor::detectHeaderXPK,TDCSDecompressor::create}, + {ZENODecompressor::detectHeaderXPK,ZENODecompressor::create}}; + +XPKMain::XPKMain(const Buffer &packedData,bool verify,uint32_t recursionLevel) : + _packedData(packedData) +{ + if (packedData.size()<44) throw InvalidFormatError(); + uint32_t hdr=packedData.readBE32(0); + if (!detectHeader(hdr)) throw InvalidFormatError(); + + _packedSize=packedData.readBE32(4); + _type=packedData.readBE32(8); + _rawSize=packedData.readBE32(12); + + if (!_rawSize || !_packedSize) throw InvalidFormatError(); + if (_rawSize>getMaxRawSize() || _packedSize>getMaxPackedSize()) throw InvalidFormatError(); + + uint8_t flags=packedData.read8(32); + _longHeaders=(flags&1)?true:false; + if (flags&2) throw InvalidFormatError(); // needs password. we do not support that + if (flags&4) // extra header + { + _headerSize=38+uint32_t(packedData.readBE16(36)); + } else { + _headerSize=36; + } + + if (OverflowCheck::sum(_packedSize,8U)>packedData.size()) throw InvalidFormatError(); + + bool found=false; + for (auto &it : XPKDecompressors) + { + if (it.first(_type)) + { + if (recursionLevel>=getMaxRecursionLevel()) throw InvalidFormatError(); + else { + found=true; + break; + } + } + } + if (!found) throw InvalidFormatError(); + + auto headerChecksum=[](const Buffer &buffer,size_t offset,size_t len)->bool + { + if (!len || OverflowCheck::sum(offset,len)>buffer.size()) return false; + const uint8_t *ptr=buffer.data()+offset; + uint8_t tmp=0; + for (size_t i=0;ibool + { + if (!len || OverflowCheck::sum(offset,len)>buffer.size()) return false; + const uint8_t *ptr=buffer.data()+offset; + uint8_t tmp[2]={0,0}; + for (size_t i=0;i>8) && tmp[1]==(checkValue&0xff); + }; + + + if (verify) + { + if (!headerChecksum(_packedData,0,36)) throw VerificationError(); + + std::shared_ptr state; + forEachChunk([&](const Buffer &header,const Buffer &chunk,uint32_t rawChunkSize,uint8_t chunkType)->bool + { + if (!headerChecksum(header,0,header.size())) throw VerificationError(); + + uint16_t hdrCheck=header.readBE16(2); + if (chunk.size() && !chunkChecksum(chunk,0,chunk.size(),hdrCheck)) throw VerificationError(); + + if (chunkType==1) + { + auto sub=createDecompressor(_type,_recursionLevel,chunk,state,true); + } else if (chunkType!=0 && chunkType!=15) throw InvalidFormatError(); + return true; + }); + } +} + +XPKMain::~XPKMain() +{ + // nothing needed +} + +const std::string &XPKMain::getName() const noexcept +{ + std::shared_ptr sub; + std::shared_ptr state; + try + { + forEachChunk([&](const Buffer &header,const Buffer &chunk,uint32_t rawChunkSize,uint8_t chunkType)->bool + { + try + { + sub=createDecompressor(_type,_recursionLevel,chunk,state,false); + } catch (const Error&) { + // should not happen since the code is already tried out, + // however, lets handle the case gracefully + } + return false; + }); + } catch (const Buffer::Error&) { + // ditto + } + static std::string invName=""; + return (sub)?sub->getSubName():invName; +} + +size_t XPKMain::getPackedSize() const noexcept +{ + return _packedSize+8; +} + +size_t XPKMain::getRawSize() const noexcept +{ + return _rawSize; +} + +void XPKMain::decompressImpl(Buffer &rawData,bool verify) +{ + if (rawData.size()<_rawSize) throw DecompressionError(); + + uint32_t destOffset=0; + std::shared_ptr state; + forEachChunk([&](const Buffer &header,const Buffer &chunk,uint32_t rawChunkSize,uint8_t chunkType)->bool + { + if (OverflowCheck::sum(destOffset,rawChunkSize)>rawData.size()) throw DecompressionError(); + if (!rawChunkSize) return true; + + ConstSubBuffer previousBuffer(rawData,0,destOffset); + SubBuffer DestBuffer(rawData,destOffset,rawChunkSize); + switch (chunkType) + { + case 0: + if (rawChunkSize!=chunk.size()) throw DecompressionError();; + std::memcpy(DestBuffer.data(),chunk.data(),rawChunkSize); + break; + + case 1: + { + try + { + auto sub=createDecompressor(_type,_recursionLevel,chunk,state,false); + sub->decompressImpl(DestBuffer,previousBuffer,verify); + } catch (const InvalidFormatError&) { + // we should throw a correct error + throw DecompressionError(); + } + } + break; + + case 15: + break; + + default: + return false; + } + + destOffset+=rawChunkSize; + return true; + }); + + if (destOffset!=_rawSize) throw DecompressionError(); + + if (verify) + { + if (std::memcmp(_packedData.data()+16,rawData.data(),std::min(_rawSize,16U))) throw DecompressionError(); + } +} + +std::shared_ptr XPKMain::createDecompressor(uint32_t type,uint32_t recursionLevel,const Buffer &buffer,std::shared_ptr &state,bool verify) +{ + // since this method is used externally, better check recursion level + if (recursionLevel>=getMaxRecursionLevel()) throw InvalidFormatError(); + for (auto &it : XPKDecompressors) + { + if (it.first(type)) return it.second(type,recursionLevel,buffer,state,verify); + } + throw InvalidFormatError(); +} + +template +void XPKMain::forEachChunk(F func) const +{ + uint32_t currentOffset=0,rawSize,packedSize; + bool isLast=false; + + while (currentOffset<_packedSize+8 && !isLast) + { + auto readDualValue=[&](uint32_t offsetShort,uint32_t offsetLong,uint32_t &value) + { + if (_longHeaders) + { + value=_packedData.readBE32(currentOffset+offsetLong); + } else { + value=uint32_t(_packedData.readBE16(currentOffset+offsetShort)); + } + }; + + uint32_t chunkHeaderLen=_longHeaders?12:8; + if (!currentOffset) + { + // return first; + currentOffset=_headerSize; + } else { + uint32_t tmp; + readDualValue(4,4,tmp); + tmp=((tmp+3U)&~3U); + if (OverflowCheck::sum(tmp,currentOffset,chunkHeaderLen)>_packedSize) + throw InvalidFormatError(); + currentOffset+=chunkHeaderLen+tmp; + } + readDualValue(4,4,packedSize); + readDualValue(6,8,rawSize); + + ConstSubBuffer hdr(_packedData,currentOffset,chunkHeaderLen); + ConstSubBuffer chunk(_packedData,currentOffset+chunkHeaderLen,packedSize); + + uint8_t type=_packedData.read8(currentOffset); + if (!func(hdr,chunk,rawSize,type)) return; + + if (type==15) isLast=true; + } + if (!isLast) throw InvalidFormatError(); +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/XPKMain.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/XPKMain.hpp new file mode 100644 index 00000000..5ad6c08f --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/XPKMain.hpp @@ -0,0 +1,54 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef XPKMAIN_HPP +#define XPKMAIN_HPP + +#include "Decompressor.hpp" +#include "XPKDecompressor.hpp" + +#include + +namespace ancient::internal +{ + +class XPKMain : public Decompressor +{ +friend class XPKDecompressor; +public: + XPKMain(const Buffer &packedData,bool verify,uint32_t recursionLevel); + + virtual ~XPKMain(); + + virtual const std::string &getName() const noexcept override final; + virtual size_t getPackedSize() const noexcept override final; + virtual size_t getRawSize() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,bool verify) override final; + + static bool detectHeader(uint32_t hdr) noexcept; + + static std::shared_ptr create(const Buffer &packedData,bool exactSizeKnown,bool verify); + + // Can be used to create directly decoder for chunk (needed by CYB2) + static std::shared_ptr createDecompressor(uint32_t type,uint32_t recursionLevel,const Buffer &buffer,std::shared_ptr &state,bool verify); + +private: + static void registerDecompressor(bool(*detect)(uint32_t),std::shared_ptr(*create)(uint32_t,uint32_t,const Buffer&,std::shared_ptr&,bool)); + static constexpr uint32_t getMaxRecursionLevel() noexcept { return 4; } + + template + void forEachChunk(F func) const; + + const Buffer &_packedData; + + uint32_t _packedSize=0; + uint32_t _rawSize=0; + uint32_t _headerSize=0; + uint32_t _type=0; + bool _longHeaders=false; + uint32_t _recursionLevel=0; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/ZENODecompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/ZENODecompressor.cpp new file mode 100644 index 00000000..8b2b4e0a --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/ZENODecompressor.cpp @@ -0,0 +1,130 @@ +/* Copyright (C) Teemu Suutari */ + +#include "ZENODecompressor.hpp" +#include "InputStream.hpp" +#include "OutputStream.hpp" +#include "common/Common.hpp" + + +namespace ancient::internal +{ + +bool ZENODecompressor::detectHeaderXPK(uint32_t hdr) noexcept +{ + return hdr==FourCC("ZENO"); +} + +std::shared_ptr ZENODecompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) +{ + return std::make_shared(hdr,recursionLevel,packedData,state,verify); +} + +ZENODecompressor::ZENODecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify) : + XPKDecompressor(recursionLevel), + _packedData(packedData) +{ + if (!detectHeaderXPK(hdr) || _packedData.size()<6) + throw Decompressor::InvalidFormatError(); + // first 4 bytes is checksum for password. It needs to be zero + if (_packedData.readBE32(0)) throw Decompressor::InvalidFormatError(); + _maxBits=_packedData.read8(4); + if (_maxBits<9 || _maxBits>20) throw Decompressor::InvalidFormatError(); + _startOffset=uint32_t(_packedData.read8(5))+6; + if (_startOffset>=_packedData.size()) throw Decompressor::InvalidFormatError(); +} + +ZENODecompressor::~ZENODecompressor() +{ + // nothing needed +} + +const std::string &ZENODecompressor::getSubName() const noexcept +{ + static std::string name="XPK-ZENO: LZW-compressor"; + return name; +} + +void ZENODecompressor::decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) +{ + ForwardInputStream inputStream(_packedData,_startOffset,_packedData.size()); + MSBBitReader bitReader(inputStream); + auto readBits=[&](uint32_t count)->uint32_t + { + return bitReader.readBits8(count); + }; + + ForwardOutputStream outputStream(rawData,0,rawData.size()); + + uint32_t maxCode=1<<_maxBits; + uint32_t stackLength=5000; // magic constant + auto prefix=std::make_unique(maxCode-258); + auto suffix=std::make_unique(maxCode-258); + auto stack=std::make_unique(stackLength); + + uint32_t freeIndex,codeBits,prevCode,newCode; + + auto init=[&]() + { + codeBits=9; + freeIndex=258; + }; + + init(); + prevCode=readBits(9); + newCode=prevCode; + suffix[freeIndex-258]=0; + prefix[freeIndex-258]=0; + freeIndex++; + outputStream.writeByte(newCode); + + while (!outputStream.eof()) + { + if (freeIndex+3>=(1U<=258) + { + do { + if (stackPos+1>=stackLength || tmp>=freeIndex) throw Decompressor::DecompressionError(); + stack[stackPos++]=suffix[tmp-258]; + tmp=prefix[tmp-258]; + } while (tmp>=258); + stack[stackPos++]=newCode=tmp; + while (stackPos) outputStream.writeByte(stack[--stackPos]); + } else { + newCode=tmp; + outputStream.writeByte(tmp); + if (stackPos) outputStream.writeByte(stack[0]); + } + } + if (freeIndex &state,bool verify); + + virtual ~ZENODecompressor(); + + virtual const std::string &getSubName() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) override final; + + static bool detectHeaderXPK(uint32_t hdr) noexcept; + static std::shared_ptr create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr &state,bool verify); + +private: + const Buffer &_packedData; + + uint32_t _maxBits=0; + size_t _startOffset=0; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/Zip/ImplodeDecompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/Zip/ImplodeDecompressor.cpp new file mode 100644 index 00000000..717f01f9 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/Zip/ImplodeDecompressor.cpp @@ -0,0 +1,130 @@ +/* Copyright (C) Teemu Suutari */ + +#include +#include + +#include "ImplodeDecompressor.hpp" +#include "../InputStream.hpp" +#include "../OutputStream.hpp" +#include "../HuffmanDecoder.hpp" + + +namespace ancient::internal +{ + +ImplodeDecompressor::ImplodeDecompressor(const Buffer &packedData,uint32_t flags) : + _packedData(packedData), + _flags(flags) +{ + +} + +ImplodeDecompressor::~ImplodeDecompressor() +{ + // nothing needed +} + +size_t ImplodeDecompressor::getRawSize() const noexcept +{ + // N/A + return 0; +} + +size_t ImplodeDecompressor::getPackedSize() const noexcept +{ + // N/A + return 0; +} + +const std::string &ImplodeDecompressor::getName() const noexcept +{ + static std::string name="Zip: Implode"; + return name; +} + +void ImplodeDecompressor::decompressImpl(Buffer &rawData,bool verify) +{ + ForwardInputStream inputStream(_packedData,0,_packedData.size()); + LSBBitReader bitReader(inputStream); + auto readBits=[&](uint32_t count)->uint32_t + { + return bitReader.readBits8(count); + }; + auto readBit=[&]()->uint32_t + { + return bitReader.readBits8(1); + }; + + ForwardOutputStream outputStream(rawData,0,rawData.size()); + + // Although Implode uses Fannon-Shano, Huffman decoder can be used + typedef HuffmanDecoder ImplodeHuffmanDecoder; + + auto createDecoder=[&](ImplodeHuffmanDecoder &dec,uint32_t maxValue) + { + uint32_t length=readBits(8)+1; + uint8_t bitLengths[257]; + uint8_t counts[257]; + uint8_t offsets[257]; + uint8_t minDepth=32,maxDepth=0; + + for (uint32_t i=0;imaxDepth) maxDepth=bitLengths[i]; + } + if (static_cast(offsets[length-1]+counts[length-1])>maxValue) throw DecompressionError(); + + uint32_t code=0; + for (uint32_t depth=maxDepth;depth>=minDepth;depth--) + { + for (int32_t i=length-1;i>=0;i--) + { + if (depth!=bitLengths[i]) continue; + for (uint32_t j=counts[i];j>0;j--) + { + dec.insert(HuffmanCode{depth,code>>(maxDepth-depth),uint8_t(offsets[i]+j-1)}); + code+=1<<(maxDepth-depth); + } + } + } + }; + + ImplodeHuffmanDecoder lengthDecoder,distanceDecoder,litDecoder; + + uint32_t extraDistanceBits=(_flags&2)?7:6; + bool literalDecPresent=_flags&4; + uint32_t lengthAddition=2; + + if (literalDecPresent) + { + createDecoder(litDecoder,256); + lengthAddition++; + } + createDecoder(lengthDecoder,64); + createDecoder(distanceDecoder,64); + + while (!outputStream.eof()) + { + if (readBit()) + { + if (literalDecPresent) outputStream.writeByte(litDecoder.decode(readBit)); + else outputStream.writeByte(readBits(8)); + } else { + uint32_t distance=readBits(extraDistanceBits); + distance|=uint32_t(distanceDecoder.decode(readBit))< +#include + +#include "ReduceDecompressor.hpp" +#include "../InputStream.hpp" +#include "../OutputStream.hpp" + + +namespace ancient::internal +{ + +ReduceDecompressor::ReduceDecompressor(const Buffer &packedData,uint32_t mode) : + _packedData(packedData), + _mode(mode) +{ + if (mode<2 || mode>5) throw InvalidFormatError(); +} + +ReduceDecompressor::~ReduceDecompressor() +{ + // nothing needed +} + +size_t ReduceDecompressor::getRawSize() const noexcept +{ + // N/A + return 0; +} + +size_t ReduceDecompressor::getPackedSize() const noexcept +{ + // N/A + return 0; +} + +const std::string &ReduceDecompressor::getName() const noexcept +{ + static std::string name="Zip: Reduce"; + return name; +} + +void ReduceDecompressor::decompressImpl(Buffer &rawData,bool verify) +{ + ForwardInputStream inputStream(_packedData,0,_packedData.size()); + LSBBitReader bitReader(inputStream); + auto readBits=[&](uint32_t count)->uint32_t + { + return bitReader.readBits8(count); + }; + + ForwardOutputStream outputStream(rawData,0,rawData.size()); + + uint8_t SLengths[256]; + auto SBuf=std::make_unique(256*64); + uint8_t (&S)[256][64]=*reinterpret_cast(SBuf.get()); + + static const uint8_t bitLengths[64]={ + 8,1,1,2,2,3,3,3, 3,4,4,4,4,4,4,4, + 4,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5, + 5,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6, + 6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6}; + + for (int32_t i=255;i>=0;i--) + { + uint32_t length=SLengths[i]=readBits(6); + for (uint32_t j=0;juint8_t + { + uint8_t ret; + if (!SLengths[lastChar] || readBits(1)) + { + ret=readBits(8); + } else { + uint8_t tmp=readBits(bitLengths[SLengths[lastChar]]); + if (tmp>=SLengths[lastChar]) throw DecompressionError(); + ret=S[lastChar][tmp]; + } + lastChar=ret; + return ret; + }; + + uint8_t ch=readByte(); + if (ch!=0x90U) + { + outputStream.writeByte(ch); + } else { + ch=readByte(); + if (!ch) + { + outputStream.writeByte(0x90U); + } else { + uint8_t lengthMask=0xffU>>(8U-lengthBits); + uint32_t count=ch&lengthMask; + if (count==lengthMask) + count+=uint32_t(readByte()); + count+=3; + uint32_t distance=(uint32_t(ch>>lengthBits)<<8)|uint32_t(readByte()); + distance++; + + outputStream.copy(distance,count,0); + } + } + } +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/Zip/ReduceDecompressor.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/Zip/ReduceDecompressor.hpp new file mode 100644 index 00000000..3612e7eb --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/Zip/ReduceDecompressor.hpp @@ -0,0 +1,32 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef REDUCEDECOMPRESSOR_HPP +#define REDUCEDECOMPRESSOR_HPP + +#include "Decompressor.hpp" + +namespace ancient::internal +{ + +class ReduceDecompressor : public Decompressor +{ +public: + ReduceDecompressor(const Buffer &packedData,uint32_t mode); + virtual ~ReduceDecompressor(); + + virtual size_t getRawSize() const noexcept override final; + virtual size_t getPackedSize() const noexcept override final; + + virtual const std::string &getName() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,bool verify) override final; + +private: + const Buffer &_packedData; + + uint32_t _mode; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/Zip/ShrinkDecompressor.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/Zip/ShrinkDecompressor.cpp new file mode 100644 index 00000000..8668e0f6 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/Zip/ShrinkDecompressor.cpp @@ -0,0 +1,137 @@ +/* Copyright (C) Teemu Suutari */ + +#include +#include +#include + +#include "ShrinkDecompressor.hpp" +#include "../InputStream.hpp" +#include "../OutputStream.hpp" + + +namespace ancient::internal +{ + +ShrinkDecompressor::ShrinkDecompressor(const Buffer &packedData) : + _packedData(packedData) +{ + +} + +ShrinkDecompressor::~ShrinkDecompressor() +{ + // nothing needed +} + +size_t ShrinkDecompressor::getRawSize() const noexcept +{ + // N/A + return 0; +} + +size_t ShrinkDecompressor::getPackedSize() const noexcept +{ + // N/A + return 0; +} + +const std::string &ShrinkDecompressor::getName() const noexcept +{ + static std::string name="Zip: Shrink"; + return name; +} + +void ShrinkDecompressor::decompressImpl(Buffer &rawData,bool verify) +{ + ForwardInputStream inputStream(_packedData,0,_packedData.size()); + LSBBitReader bitReader(inputStream); + auto readBits=[&](uint32_t count)->uint32_t + { + return bitReader.readBits8(count); + }; + + ForwardOutputStream outputStream(rawData,0,rawData.size()); + + const uint32_t maxCode=0x2000U; + auto prefix=std::make_unique(maxCode-257); + auto suffix=std::make_unique(maxCode-257); + auto stack=std::make_unique(maxCode-257); + + uint32_t freeIndex,codeBits,prevCode,newCode; + + auto suffixLookup=[&](uint32_t code)->uint32_t + { + // main protection against negative values + if (code>=maxCode) throw DecompressionError(); + return (code<257)?code:suffix[code-257]; + }; + + auto insert=[&](uint32_t code) + { + uint32_t stackPos=0; + newCode=suffixLookup(code); + while (code>=257) + { + if (stackPos+1>=maxCode-257) throw DecompressionError(); + stack[stackPos++]=newCode; + code=prefix[code-257]; + newCode=suffixLookup(code); + } + stack[stackPos++]=newCode; + while (stackPos) outputStream.writeByte(stack[--stackPos]); + }; + + for (uint32_t i=0;i usageMap(freeIndex-257,false); + for (uint32_t i=257;i=257) usageMap[tmp-257]=true; + } + uint32_t firstEmpty=freeIndex; + for (uint32_t i=257;i=257 && (prefix[code-257]&0x8000'0000U)) + { + uint32_t tmp=newCode; + insert(prevCode); + outputStream.writeByte(tmp); + } else insert(code); + while (!(prefix[freeIndex-257]&0x8000'0000U) && freeIndex +#include + +#include "ZIPDecompressor.hpp" + +#include "../BZIP2Decompressor.hpp" +#include "../DEFLATEDecompressor.hpp" +#include "ImplodeDecompressor.hpp" +#include "ReduceDecompressor.hpp" +#include "ShrinkDecompressor.hpp" + + +namespace ancient::internal +{ + +ZIPDecompressor::ZIPDecompressor(const Buffer &packedData,uint32_t method,uint32_t flags) : + _packedData(packedData), + _method(method), + _flags(flags) +{ + +} + +ZIPDecompressor::~ZIPDecompressor() +{ + // nothing needed +} + +size_t ZIPDecompressor::getRawSize() const noexcept +{ + // N/A + return 0; +} + +size_t ZIPDecompressor::getPackedSize() const noexcept +{ + // N/A + return 0; +} + +const std::string &ZIPDecompressor::getName() const noexcept +{ + static std::string name="Zip"; + return name; +} + +void ZIPDecompressor::decompressImpl(Buffer &rawData,bool verify) +{ + switch (_method) + { + case 0: + if (rawData.size()!=_packedData.size()) throw DecompressionError(); + std::memcpy(rawData.data(),_packedData.data(),rawData.size()); + break; + + case 1: + { + ShrinkDecompressor dec(_packedData); + dec.decompress(rawData,verify); + } + break; + + case 2: + case 3: + case 4: + case 5: + { + ReduceDecompressor dec(_packedData,_method); + dec.decompress(rawData,verify); + } + break; + + case 6: + { + ImplodeDecompressor dec(_packedData,_flags); + dec.decompress(rawData,verify); + } + break; + + case 8: + case 9: + { + DEFLATEDecompressor dec(_packedData,_packedData.size(),rawData.size(),false,verify,_method==9); + dec.decompress(rawData,verify); + } + break; + + case 12: + { + BZIP2Decompressor dec(_packedData,true,verify); + dec.decompress(rawData,verify); + } + break; + + case 14: + // LZMA + throw DecompressionError(); + break; + + case 97: + // WavPack + throw DecompressionError(); + break; + + case 98: + // PPMd + throw DecompressionError(); + break; + + default: + throw DecompressionError(); + } +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/Zip/ZIPDecompressor.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/Zip/ZIPDecompressor.hpp new file mode 100644 index 00000000..77ecd6fe --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/Zip/ZIPDecompressor.hpp @@ -0,0 +1,33 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef ZIPDECOMPRESSOR_HPP +#define ZIPDECOMPRESSOR_HPP + +#include "Decompressor.hpp" + +namespace ancient::internal +{ + +class ZIPDecompressor : public Decompressor +{ +public: + ZIPDecompressor(const Buffer &packedData,uint32_t method,uint32_t flags); + virtual ~ZIPDecompressor(); + + virtual size_t getRawSize() const noexcept override final; + virtual size_t getPackedSize() const noexcept override final; + + virtual const std::string &getName() const noexcept override final; + + virtual void decompressImpl(Buffer &rawData,bool verify) override final; + +private: + const Buffer &_packedData; + + uint32_t _method; + uint32_t _flags; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/Buffer.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/Buffer.cpp new file mode 100644 index 00000000..0d534a24 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/Buffer.cpp @@ -0,0 +1,112 @@ +/* Copyright (C) Teemu Suutari */ + +#include "Buffer.hpp" +#include "OverflowCheck.hpp" + + +namespace ancient::internal +{ + +Buffer::Error::Error() noexcept +{ + // nothing needed +} + +Buffer::Error::~Error() +{ + // nothing needed +} + +Buffer::OutOfBoundsError::OutOfBoundsError() noexcept +{ + // nothing needed +} + +Buffer::OutOfBoundsError::~OutOfBoundsError() +{ + // nothing needed +} + +Buffer::InvalidOperationError::InvalidOperationError() noexcept +{ + // nothing needed +} + +Buffer::InvalidOperationError::~InvalidOperationError() +{ + // nothing needed +} + +// --- + +Buffer::Buffer() noexcept +{ + // nothing needed +} + +Buffer::~Buffer() +{ + // nothing needed +} + +void Buffer::resize(size_t newSize) +{ + throw InvalidOperationError(); +} + +uint8_t &Buffer::operator[](size_t i) +{ + if (i>=size()) throw OutOfBoundsError(); + return data()[i]; +} + +const uint8_t &Buffer::operator[](size_t i) const +{ + if (i>=size()) throw OutOfBoundsError(); + return data()[i]; +} + +uint32_t Buffer::readBE32(size_t offset) const +{ + if (OverflowCheck::sum(offset,4U)>size()) throw OutOfBoundsError(); + const uint8_t *ptr=data()+offset; + return (uint32_t(ptr[0])<<24)|(uint32_t(ptr[1])<<16)|(uint32_t(ptr[2])<<8)|uint32_t(ptr[3]); +} + +uint16_t Buffer::readBE16(size_t offset) const +{ + if (OverflowCheck::sum(offset,2U)>size()) throw OutOfBoundsError(); + const uint8_t *ptr=data()+offset; + return (uint16_t(ptr[0])<<8)|uint16_t(ptr[1]); +} + +uint64_t Buffer::readLE64(size_t offset) const +{ + if (OverflowCheck::sum(offset,8U)>size()) throw OutOfBoundsError(); + const uint8_t *ptr=data()+offset; + return (uint64_t(ptr[7])<<56)|(uint64_t(ptr[6])<<48)|(uint64_t(ptr[5])<<40)|(uint64_t(ptr[4])<<32)| + (uint64_t(ptr[3])<<24)|(uint64_t(ptr[2])<<16)|(uint64_t(ptr[1])<<8)|uint64_t(ptr[0]); +} + +uint32_t Buffer::readLE32(size_t offset) const +{ + if (OverflowCheck::sum(offset,4U)>size()) throw OutOfBoundsError(); + const uint8_t *ptr=data()+offset; + return (uint32_t(ptr[3])<<24)|(uint32_t(ptr[2])<<16)|(uint32_t(ptr[1])<<8)|uint32_t(ptr[0]); +} + +uint16_t Buffer::readLE16(size_t offset) const +{ + if (OverflowCheck::sum(offset,2U)>size()) throw OutOfBoundsError(); + const uint8_t *ptr=data()+offset; + return (uint16_t(ptr[1])<<8)|uint16_t(ptr[0]); +} + +uint8_t Buffer::read8(size_t offset) const +{ + if (offset>=size()) throw OutOfBoundsError(); + const uint8_t *ptr=reinterpret_cast(data())+offset; + return ptr[0]; +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/Buffer.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/Buffer.hpp new file mode 100644 index 00000000..1ce5890e --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/Buffer.hpp @@ -0,0 +1,80 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef BUFFER_HPP +#define BUFFER_HPP + +#include +#include + +#include + +namespace ancient::internal +{ + +class Buffer +{ +protected: + Buffer() noexcept; + +public: + class Error : public std::exception + { + public: + Error() noexcept; + virtual ~Error(); + }; + + class OutOfBoundsError : public Error + { + public: + OutOfBoundsError() noexcept; + virtual ~OutOfBoundsError(); + }; + + class InvalidOperationError : public Error + { + public: + InvalidOperationError() noexcept; + virtual ~InvalidOperationError(); + }; + + Buffer(const Buffer&)=delete; + Buffer& operator=(const Buffer&)=delete; + + virtual ~Buffer(); + + virtual const uint8_t *data() const noexcept=0; + virtual uint8_t *data()=0; + virtual size_t size() const noexcept=0; + + template + const T *cast() const noexcept + { + return reinterpret_cast(data()); + } + + template + T *cast() + { + return reinterpret_cast(data()); + } + + virtual bool isResizable() const noexcept=0; + virtual void resize(size_t newSize); + + uint8_t &operator[](size_t i); + const uint8_t &operator[](size_t i) const; + + uint32_t readBE32(size_t offset) const; + uint16_t readBE16(size_t offset) const; + + uint64_t readLE64(size_t offset) const; + uint32_t readLE32(size_t offset) const; + uint16_t readLE16(size_t offset) const; + + uint8_t read8(size_t offset) const; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/CRC16.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/CRC16.cpp new file mode 100644 index 00000000..1be46221 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/CRC16.cpp @@ -0,0 +1,44 @@ +/* Copyright (C) Teemu Suutari */ + +#include + +#include "Buffer.hpp" +#include "OverflowCheck.hpp" + + +namespace ancient::internal +{ + +static const uint16_t CRC16Table[256]={ + 0x0000,0xc0c1,0xc181,0x0140,0xc301,0x03c0,0x0280,0xc241,0xc601,0x06c0,0x0780,0xc741,0x0500,0xc5c1,0xc481,0x0440, + 0xcc01,0x0cc0,0x0d80,0xcd41,0x0f00,0xcfc1,0xce81,0x0e40,0x0a00,0xcac1,0xcb81,0x0b40,0xc901,0x09c0,0x0880,0xc841, + 0xd801,0x18c0,0x1980,0xd941,0x1b00,0xdbc1,0xda81,0x1a40,0x1e00,0xdec1,0xdf81,0x1f40,0xdd01,0x1dc0,0x1c80,0xdc41, + 0x1400,0xd4c1,0xd581,0x1540,0xd701,0x17c0,0x1680,0xd641,0xd201,0x12c0,0x1380,0xd341,0x1100,0xd1c1,0xd081,0x1040, + 0xf001,0x30c0,0x3180,0xf141,0x3300,0xf3c1,0xf281,0x3240,0x3600,0xf6c1,0xf781,0x3740,0xf501,0x35c0,0x3480,0xf441, + 0x3c00,0xfcc1,0xfd81,0x3d40,0xff01,0x3fc0,0x3e80,0xfe41,0xfa01,0x3ac0,0x3b80,0xfb41,0x3900,0xf9c1,0xf881,0x3840, + 0x2800,0xe8c1,0xe981,0x2940,0xeb01,0x2bc0,0x2a80,0xea41,0xee01,0x2ec0,0x2f80,0xef41,0x2d00,0xedc1,0xec81,0x2c40, + 0xe401,0x24c0,0x2580,0xe541,0x2700,0xe7c1,0xe681,0x2640,0x2200,0xe2c1,0xe381,0x2340,0xe101,0x21c0,0x2080,0xe041, + 0xa001,0x60c0,0x6180,0xa141,0x6300,0xa3c1,0xa281,0x6240,0x6600,0xa6c1,0xa781,0x6740,0xa501,0x65c0,0x6480,0xa441, + 0x6c00,0xacc1,0xad81,0x6d40,0xaf01,0x6fc0,0x6e80,0xae41,0xaa01,0x6ac0,0x6b80,0xab41,0x6900,0xa9c1,0xa881,0x6840, + 0x7800,0xb8c1,0xb981,0x7940,0xbb01,0x7bc0,0x7a80,0xba41,0xbe01,0x7ec0,0x7f80,0xbf41,0x7d00,0xbdc1,0xbc81,0x7c40, + 0xb401,0x74c0,0x7580,0xb541,0x7700,0xb7c1,0xb681,0x7640,0x7200,0xb2c1,0xb381,0x7340,0xb101,0x71c0,0x7080,0xb041, + 0x5000,0x90c1,0x9181,0x5140,0x9301,0x53c0,0x5280,0x9241,0x9601,0x56c0,0x5780,0x9741,0x5500,0x95c1,0x9481,0x5440, + 0x9c01,0x5cc0,0x5d80,0x9d41,0x5f00,0x9fc1,0x9e81,0x5e40,0x5a00,0x9ac1,0x9b81,0x5b40,0x9901,0x59c0,0x5880,0x9841, + 0x8801,0x48c0,0x4980,0x8941,0x4b00,0x8bc1,0x8a81,0x4a40,0x4e00,0x8ec1,0x8f81,0x4f40,0x8d01,0x4dc0,0x4c80,0x8c41, + 0x4400,0x84c1,0x8581,0x4540,0x8701,0x47c0,0x4680,0x8641,0x8201,0x42c0,0x4380,0x8341,0x4100,0x81c1,0x8081,0x4040}; + +uint16_t CRC16(const Buffer &buffer,size_t offset,size_t len,uint16_t accumulator) +{ + if (!len || OverflowCheck::sum(offset,len)>buffer.size()) throw Buffer::OutOfBoundsError(); + const uint8_t *ptr=buffer.data()+offset; + for (size_t i=0;i>8)^CRC16Table[(accumulator&0xff)^ptr[i]]; + return accumulator; +} + +uint16_t CRC16Byte(uint8_t ch,uint16_t accumulator) noexcept +{ + return (accumulator>>8)^CRC16Table[(accumulator&0xff)^ch]; +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/CRC16.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/CRC16.hpp new file mode 100644 index 00000000..8889aad2 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/CRC16.hpp @@ -0,0 +1,21 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef CRC16_HPP +#define CRC16_HPP + +#include + +#include "Buffer.hpp" + +namespace ancient::internal +{ + +// The most common CRC16 + +uint16_t CRC16(const Buffer &buffer,size_t offset,size_t len,uint16_t accumulator); + +uint16_t CRC16Byte(uint8_t ch,uint16_t accumulator) noexcept; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/CRC32.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/CRC32.cpp new file mode 100644 index 00000000..b5fd3ba2 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/CRC32.cpp @@ -0,0 +1,115 @@ +/* Copyright (C) Teemu Suutari */ + +#include + +#include "Buffer.hpp" +#include "OverflowCheck.hpp" + + +namespace ancient::internal +{ + +static const uint32_t CRC32Table[256]={ + 0x00000000U,0x77073096U,0xee0e612cU,0x990951baU,0x076dc419U,0x706af48fU,0xe963a535U,0x9e6495a3U, + 0x0edb8832U,0x79dcb8a4U,0xe0d5e91eU,0x97d2d988U,0x09b64c2bU,0x7eb17cbdU,0xe7b82d07U,0x90bf1d91U, + 0x1db71064U,0x6ab020f2U,0xf3b97148U,0x84be41deU,0x1adad47dU,0x6ddde4ebU,0xf4d4b551U,0x83d385c7U, + 0x136c9856U,0x646ba8c0U,0xfd62f97aU,0x8a65c9ecU,0x14015c4fU,0x63066cd9U,0xfa0f3d63U,0x8d080df5U, + 0x3b6e20c8U,0x4c69105eU,0xd56041e4U,0xa2677172U,0x3c03e4d1U,0x4b04d447U,0xd20d85fdU,0xa50ab56bU, + 0x35b5a8faU,0x42b2986cU,0xdbbbc9d6U,0xacbcf940U,0x32d86ce3U,0x45df5c75U,0xdcd60dcfU,0xabd13d59U, + 0x26d930acU,0x51de003aU,0xc8d75180U,0xbfd06116U,0x21b4f4b5U,0x56b3c423U,0xcfba9599U,0xb8bda50fU, + 0x2802b89eU,0x5f058808U,0xc60cd9b2U,0xb10be924U,0x2f6f7c87U,0x58684c11U,0xc1611dabU,0xb6662d3dU, + 0x76dc4190U,0x01db7106U,0x98d220bcU,0xefd5102aU,0x71b18589U,0x06b6b51fU,0x9fbfe4a5U,0xe8b8d433U, + 0x7807c9a2U,0x0f00f934U,0x9609a88eU,0xe10e9818U,0x7f6a0dbbU,0x086d3d2dU,0x91646c97U,0xe6635c01U, + 0x6b6b51f4U,0x1c6c6162U,0x856530d8U,0xf262004eU,0x6c0695edU,0x1b01a57bU,0x8208f4c1U,0xf50fc457U, + 0x65b0d9c6U,0x12b7e950U,0x8bbeb8eaU,0xfcb9887cU,0x62dd1ddfU,0x15da2d49U,0x8cd37cf3U,0xfbd44c65U, + 0x4db26158U,0x3ab551ceU,0xa3bc0074U,0xd4bb30e2U,0x4adfa541U,0x3dd895d7U,0xa4d1c46dU,0xd3d6f4fbU, + 0x4369e96aU,0x346ed9fcU,0xad678846U,0xda60b8d0U,0x44042d73U,0x33031de5U,0xaa0a4c5fU,0xdd0d7cc9U, + 0x5005713cU,0x270241aaU,0xbe0b1010U,0xc90c2086U,0x5768b525U,0x206f85b3U,0xb966d409U,0xce61e49fU, + 0x5edef90eU,0x29d9c998U,0xb0d09822U,0xc7d7a8b4U,0x59b33d17U,0x2eb40d81U,0xb7bd5c3bU,0xc0ba6cadU, + 0xedb88320U,0x9abfb3b6U,0x03b6e20cU,0x74b1d29aU,0xead54739U,0x9dd277afU,0x04db2615U,0x73dc1683U, + 0xe3630b12U,0x94643b84U,0x0d6d6a3eU,0x7a6a5aa8U,0xe40ecf0bU,0x9309ff9dU,0x0a00ae27U,0x7d079eb1U, + 0xf00f9344U,0x8708a3d2U,0x1e01f268U,0x6906c2feU,0xf762575dU,0x806567cbU,0x196c3671U,0x6e6b06e7U, + 0xfed41b76U,0x89d32be0U,0x10da7a5aU,0x67dd4accU,0xf9b9df6fU,0x8ebeeff9U,0x17b7be43U,0x60b08ed5U, + 0xd6d6a3e8U,0xa1d1937eU,0x38d8c2c4U,0x4fdff252U,0xd1bb67f1U,0xa6bc5767U,0x3fb506ddU,0x48b2364bU, + 0xd80d2bdaU,0xaf0a1b4cU,0x36034af6U,0x41047a60U,0xdf60efc3U,0xa867df55U,0x316e8eefU,0x4669be79U, + 0xcb61b38cU,0xbc66831aU,0x256fd2a0U,0x5268e236U,0xcc0c7795U,0xbb0b4703U,0x220216b9U,0x5505262fU, + 0xc5ba3bbeU,0xb2bd0b28U,0x2bb45a92U,0x5cb36a04U,0xc2d7ffa7U,0xb5d0cf31U,0x2cd99e8bU,0x5bdeae1dU, + 0x9b64c2b0U,0xec63f226U,0x756aa39cU,0x026d930aU,0x9c0906a9U,0xeb0e363fU,0x72076785U,0x05005713U, + 0x95bf4a82U,0xe2b87a14U,0x7bb12baeU,0x0cb61b38U,0x92d28e9bU,0xe5d5be0dU,0x7cdcefb7U,0x0bdbdf21U, + 0x86d3d2d4U,0xf1d4e242U,0x68ddb3f8U,0x1fda836eU,0x81be16cdU,0xf6b9265bU,0x6fb077e1U,0x18b74777U, + 0x88085ae6U,0xff0f6a70U,0x66063bcaU,0x11010b5cU,0x8f659effU,0xf862ae69U,0x616bffd3U,0x166ccf45U, + 0xa00ae278U,0xd70dd2eeU,0x4e048354U,0x3903b3c2U,0xa7672661U,0xd06016f7U,0x4969474dU,0x3e6e77dbU, + 0xaed16a4aU,0xd9d65adcU,0x40df0b66U,0x37d83bf0U,0xa9bcae53U,0xdebb9ec5U,0x47b2cf7fU,0x30b5ffe9U, + 0xbdbdf21cU,0xcabac28aU,0x53b39330U,0x24b4a3a6U,0xbad03605U,0xcdd70693U,0x54de5729U,0x23d967bfU, + 0xb3667a2eU,0xc4614ab8U,0x5d681b02U,0x2a6f2b94U,0xb40bbe37U,0xc30c8ea1U,0x5a05df1bU,0x2d02ef8dU}; + +uint32_t CRC32(const Buffer &buffer,size_t offset,size_t len,uint32_t accumulator) +{ + + if (!len || OverflowCheck::sum(offset,len)>buffer.size()) throw Buffer::OutOfBoundsError(); + const uint8_t *ptr=buffer.data()+offset; + accumulator=~accumulator; + for (size_t i=0;i>8)^CRC32Table[(accumulator&0xff)^ptr[i]]; + return ~accumulator; +} + +uint32_t CRC32Byte(uint8_t ch,uint32_t accumulator) noexcept +{ + return ~((~accumulator>>8)^CRC32Table[(~accumulator&0xff)^ch]); +} + +// instead of bit-twiddling lets have a separate implementation for reverse + +// same table as the previous one, but reflected +static const uint32_t CRC32RevTable[256]={ + 0x00000000U,0x04c11db7U,0x09823b6eU,0x0d4326d9U,0x130476dcU,0x17c56b6bU,0x1a864db2U,0x1e475005U, + 0x2608edb8U,0x22c9f00fU,0x2f8ad6d6U,0x2b4bcb61U,0x350c9b64U,0x31cd86d3U,0x3c8ea00aU,0x384fbdbdU, + 0x4c11db70U,0x48d0c6c7U,0x4593e01eU,0x4152fda9U,0x5f15adacU,0x5bd4b01bU,0x569796c2U,0x52568b75U, + 0x6a1936c8U,0x6ed82b7fU,0x639b0da6U,0x675a1011U,0x791d4014U,0x7ddc5da3U,0x709f7b7aU,0x745e66cdU, + 0x9823b6e0U,0x9ce2ab57U,0x91a18d8eU,0x95609039U,0x8b27c03cU,0x8fe6dd8bU,0x82a5fb52U,0x8664e6e5U, + 0xbe2b5b58U,0xbaea46efU,0xb7a96036U,0xb3687d81U,0xad2f2d84U,0xa9ee3033U,0xa4ad16eaU,0xa06c0b5dU, + 0xd4326d90U,0xd0f37027U,0xddb056feU,0xd9714b49U,0xc7361b4cU,0xc3f706fbU,0xceb42022U,0xca753d95U, + 0xf23a8028U,0xf6fb9d9fU,0xfbb8bb46U,0xff79a6f1U,0xe13ef6f4U,0xe5ffeb43U,0xe8bccd9aU,0xec7dd02dU, + 0x34867077U,0x30476dc0U,0x3d044b19U,0x39c556aeU,0x278206abU,0x23431b1cU,0x2e003dc5U,0x2ac12072U, + 0x128e9dcfU,0x164f8078U,0x1b0ca6a1U,0x1fcdbb16U,0x018aeb13U,0x054bf6a4U,0x0808d07dU,0x0cc9cdcaU, + 0x7897ab07U,0x7c56b6b0U,0x71159069U,0x75d48ddeU,0x6b93dddbU,0x6f52c06cU,0x6211e6b5U,0x66d0fb02U, + 0x5e9f46bfU,0x5a5e5b08U,0x571d7dd1U,0x53dc6066U,0x4d9b3063U,0x495a2dd4U,0x44190b0dU,0x40d816baU, + 0xaca5c697U,0xa864db20U,0xa527fdf9U,0xa1e6e04eU,0xbfa1b04bU,0xbb60adfcU,0xb6238b25U,0xb2e29692U, + 0x8aad2b2fU,0x8e6c3698U,0x832f1041U,0x87ee0df6U,0x99a95df3U,0x9d684044U,0x902b669dU,0x94ea7b2aU, + 0xe0b41de7U,0xe4750050U,0xe9362689U,0xedf73b3eU,0xf3b06b3bU,0xf771768cU,0xfa325055U,0xfef34de2U, + 0xc6bcf05fU,0xc27dede8U,0xcf3ecb31U,0xcbffd686U,0xd5b88683U,0xd1799b34U,0xdc3abdedU,0xd8fba05aU, + 0x690ce0eeU,0x6dcdfd59U,0x608edb80U,0x644fc637U,0x7a089632U,0x7ec98b85U,0x738aad5cU,0x774bb0ebU, + 0x4f040d56U,0x4bc510e1U,0x46863638U,0x42472b8fU,0x5c007b8aU,0x58c1663dU,0x558240e4U,0x51435d53U, + 0x251d3b9eU,0x21dc2629U,0x2c9f00f0U,0x285e1d47U,0x36194d42U,0x32d850f5U,0x3f9b762cU,0x3b5a6b9bU, + 0x0315d626U,0x07d4cb91U,0x0a97ed48U,0x0e56f0ffU,0x1011a0faU,0x14d0bd4dU,0x19939b94U,0x1d528623U, + 0xf12f560eU,0xf5ee4bb9U,0xf8ad6d60U,0xfc6c70d7U,0xe22b20d2U,0xe6ea3d65U,0xeba91bbcU,0xef68060bU, + 0xd727bbb6U,0xd3e6a601U,0xdea580d8U,0xda649d6fU,0xc423cd6aU,0xc0e2d0ddU,0xcda1f604U,0xc960ebb3U, + 0xbd3e8d7eU,0xb9ff90c9U,0xb4bcb610U,0xb07daba7U,0xae3afba2U,0xaafbe615U,0xa7b8c0ccU,0xa379dd7bU, + 0x9b3660c6U,0x9ff77d71U,0x92b45ba8U,0x9675461fU,0x8832161aU,0x8cf30badU,0x81b02d74U,0x857130c3U, + 0x5d8a9099U,0x594b8d2eU,0x5408abf7U,0x50c9b640U,0x4e8ee645U,0x4a4ffbf2U,0x470cdd2bU,0x43cdc09cU, + 0x7b827d21U,0x7f436096U,0x7200464fU,0x76c15bf8U,0x68860bfdU,0x6c47164aU,0x61043093U,0x65c52d24U, + 0x119b4be9U,0x155a565eU,0x18197087U,0x1cd86d30U,0x029f3d35U,0x065e2082U,0x0b1d065bU,0x0fdc1becU, + 0x3793a651U,0x3352bbe6U,0x3e119d3fU,0x3ad08088U,0x2497d08dU,0x2056cd3aU,0x2d15ebe3U,0x29d4f654U, + 0xc5a92679U,0xc1683bceU,0xcc2b1d17U,0xc8ea00a0U,0xd6ad50a5U,0xd26c4d12U,0xdf2f6bcbU,0xdbee767cU, + 0xe3a1cbc1U,0xe760d676U,0xea23f0afU,0xeee2ed18U,0xf0a5bd1dU,0xf464a0aaU,0xf9278673U,0xfde69bc4U, + 0x89b8fd09U,0x8d79e0beU,0x803ac667U,0x84fbdbd0U,0x9abc8bd5U,0x9e7d9662U,0x933eb0bbU,0x97ffad0cU, + 0xafb010b1U,0xab710d06U,0xa6322bdfU,0xa2f33668U,0xbcb4666dU,0xb8757bdaU,0xb5365d03U,0xb1f740b4U}; + +uint32_t CRC32Rev(const Buffer &buffer,size_t offset,size_t len,uint32_t accumulator) +{ + + if (!len || OverflowCheck::sum(offset,len)>buffer.size()) throw Buffer::OutOfBoundsError(); + const uint8_t *ptr=buffer.data()+offset; + accumulator=~accumulator; + for (size_t i=0;i>24)^ptr[i]]; + return ~accumulator; +} + +uint32_t CRC32RevByte(uint8_t ch,uint32_t &accumulator) noexcept +{ + return ~((~accumulator<<8)^CRC32RevTable[(~accumulator>>24)^ch]); +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/CRC32.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/CRC32.hpp new file mode 100644 index 00000000..540de2d4 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/CRC32.hpp @@ -0,0 +1,27 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef CRC32_HPP +#define CRC32_HPP + +#include + +#include "Buffer.hpp" + +namespace ancient::internal +{ + +// The most common CRC32 + +uint32_t CRC32(const Buffer &buffer,size_t offset,size_t len,uint32_t accumulator); + +uint32_t CRC32Byte(uint8_t ch,uint32_t accumulator) noexcept; + +// Same polynomial, but in reverse... + +uint32_t CRC32Rev(const Buffer &buffer,size_t offset,size_t len,uint32_t accumulator); + +uint32_t CRC32RevByte(uint8_t ch,uint32_t accumulator) noexcept; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/Common.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/Common.cpp new file mode 100644 index 00000000..380abc3a --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/Common.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) Teemu Suutari */ + +#include "Common.hpp" + + +namespace ancient::internal +{ + +uint32_t rotateBits(uint32_t value,uint32_t count) +{ + static const uint8_t rotateNibble[16]={ + 0x0,0x8,0x4,0xc, + 0x2,0xa,0x6,0xe, + 0x1,0x9,0x5,0xd, + 0x3,0xb,0x7,0xf + }; + + uint32_t ret=0; + for (uint32_t i=0;i>=4; + } + ret>>=(4-count)&3; + return ret; +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/Common.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/Common.hpp new file mode 100644 index 00000000..5dab2696 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/Common.hpp @@ -0,0 +1,46 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef COMMON_HPP +#define COMMON_HPP + +#include + +#include +#include + +namespace ancient::internal +{ + +constexpr uint16_t MultiChar2(const char (&cc)[3]) noexcept +{ + return static_cast((static_cast(cc[0]) << 8) | static_cast(cc[1])); +} + +constexpr uint32_t FourCC(const char (&cc)[5]) noexcept +{ + return static_cast((static_cast(cc[0]) << 24) | (static_cast(cc[1]) << 16) | (static_cast(cc[2]) << 8) | static_cast(cc[3])); +} + +constexpr bool isValidSize(uint64_t &value) noexcept +{ +#if INTPTR_MAX == INT32_MAX + return value<0x1'0000'0000ULL; +#else + return true; +#endif +} + +constexpr bool isValidSize(off_t &value) noexcept +{ +#if INTPTR_MAX == INT32_MAX + return value<0x1'0000'0000ULL; +#else + return true; +#endif +} + +uint32_t rotateBits(uint32_t value,uint32_t count); + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/MemoryBuffer.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/MemoryBuffer.cpp new file mode 100644 index 00000000..fa0dcef8 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/MemoryBuffer.cpp @@ -0,0 +1,70 @@ +/* Copyright (C) Teemu Suutari */ + +#include +#include + +#include +#include + +#include "MemoryBuffer.hpp" +#include "OverflowCheck.hpp" + + +namespace ancient::internal +{ + +MemoryBuffer::MemoryBuffer(size_t size) : + _data(reinterpret_cast(std::malloc(size))), + _size(size) +{ + if (!_data) throw std::bad_alloc(); +} + +MemoryBuffer::MemoryBuffer(const Buffer &src,size_t offset,size_t size) : + MemoryBuffer(size) +{ + if(OverflowCheck::sum(offset,size)>src.size()) throw InvalidOperationError(); + std::memcpy(_data,src.data()+offset,size); +} + + +MemoryBuffer::~MemoryBuffer() +{ + std::free(_data); +} + +const uint8_t *MemoryBuffer::data() const noexcept +{ + return _data; +} + +uint8_t *MemoryBuffer::data() +{ + return _data; +} + +size_t MemoryBuffer::size() const noexcept +{ + return _size; +} + +bool MemoryBuffer::isResizable() const noexcept +{ + return true; +} + +void MemoryBuffer::resize(size_t newSize) +{ + uint8_t *newData=reinterpret_cast(std::realloc(_data,newSize)); + if (!newData) + { + std::free(_data); + _data=nullptr; + _size=0; + throw std::bad_alloc(); + } + _data=newData; + _size=newSize; +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/MemoryBuffer.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/MemoryBuffer.hpp new file mode 100644 index 00000000..d19215a6 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/MemoryBuffer.hpp @@ -0,0 +1,34 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef MEMORYBUFFER_HPP +#define MEMORYBUFFER_HPP + +#include + +#include "Buffer.hpp" + +namespace ancient::internal +{ + +class MemoryBuffer : public Buffer +{ +public: + MemoryBuffer(size_t size); + MemoryBuffer(const Buffer &src,size_t offset,size_t size); + virtual ~MemoryBuffer() override final; + + virtual const uint8_t *data() const noexcept override final; + virtual uint8_t *data() override final; + virtual size_t size() const noexcept override final; + + virtual bool isResizable() const noexcept override final; + virtual void resize(size_t newSize) override final; + +private: + uint8_t* _data; + size_t _size; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/OverflowCheck.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/OverflowCheck.hpp new file mode 100644 index 00000000..524dd2f4 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/OverflowCheck.hpp @@ -0,0 +1,32 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef OVERFLOW_CHECK_HPP +#define OVERFLOW_CHECK_HPP + +#include "Buffer.hpp" + +namespace ancient::internal +{ + +class OverflowCheck +{ +public: + template + static T sum(T a,U b) + { + // TODO: Add type traits to handle signed integers + T ret=a+b; + if (ret + static T sum(T a,U b,Args... args) + { + return sum(sum(a,b),args...); + } +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/StaticBuffer.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/StaticBuffer.cpp new file mode 100644 index 00000000..16590752 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/StaticBuffer.cpp @@ -0,0 +1,41 @@ +/* Copyright (C) Teemu Suutari */ + +#include "StaticBuffer.hpp" + + +namespace ancient::internal +{ + +ConstStaticBuffer::ConstStaticBuffer(const uint8_t *data,size_t length) : + _data(data), + _length(length) +{ + // nothing needed +} + +ConstStaticBuffer::~ConstStaticBuffer() +{ + // nothing needed +} + +const uint8_t *ConstStaticBuffer::data() const noexcept +{ + return _data; +} + +uint8_t *ConstStaticBuffer::data() +{ + throw InvalidOperationError(); +} + +size_t ConstStaticBuffer::size() const noexcept +{ + return _length; +} + +bool ConstStaticBuffer::isResizable() const noexcept +{ + return false; +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/StaticBuffer.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/StaticBuffer.hpp new file mode 100644 index 00000000..2fcff561 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/StaticBuffer.hpp @@ -0,0 +1,72 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef STATICBUFFER_HPP +#define STATICBUFFER_HPP + +#include +#include + +#include "Buffer.hpp" + +namespace ancient::internal +{ + +template +class StaticBuffer : public Buffer +{ +public: + StaticBuffer(const StaticBuffer&)=delete; + StaticBuffer& operator=(const StaticBuffer&)=delete; + + StaticBuffer() { } + + virtual ~StaticBuffer() { } + + virtual const uint8_t *data() const noexcept override + { + return _data; + } + + virtual uint8_t *data() override + { + return _data; + } + + virtual size_t size() const noexcept override + { + return N; + } + + virtual bool isResizable() const noexcept override + { + return false; + } + +private: + uint8_t _data[N]; +}; + + +class ConstStaticBuffer : public Buffer +{ +public: + ConstStaticBuffer(const ConstStaticBuffer&)=delete; + ConstStaticBuffer& operator=(const ConstStaticBuffer&)=delete; + + ConstStaticBuffer(const uint8_t *data,size_t length); + virtual ~ConstStaticBuffer(); + + virtual const uint8_t *data() const noexcept override; + virtual uint8_t *data() override; + + virtual size_t size() const noexcept override; + virtual bool isResizable() const noexcept override; + +private: + const uint8_t *_data; + size_t _length; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/SubBuffer.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/SubBuffer.cpp new file mode 100644 index 00000000..8864667a --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/SubBuffer.cpp @@ -0,0 +1,21 @@ +/* Copyright (C) Teemu Suutari */ + +#include "SubBuffer.hpp" + + +namespace ancient::internal +{ + +template <> +uint8_t *GenericSubBuffer::data() +{ + return _base.data()+_start; +} + +template <> +uint8_t *GenericSubBuffer::data() +{ + throw InvalidOperationError(); +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/SubBuffer.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/SubBuffer.hpp new file mode 100644 index 00000000..3c76a8cd --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/SubBuffer.hpp @@ -0,0 +1,75 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef SUBBUFFER_HPP +#define SUBBUFFER_HPP + +#include +#include + +#include "Buffer.hpp" +#include "OverflowCheck.hpp" + +namespace ancient::internal +{ + +// helpers to splice Buffer + +template +class GenericSubBuffer : public Buffer +{ +public: + GenericSubBuffer(const GenericSubBuffer&)=delete; + GenericSubBuffer& operator=(const GenericSubBuffer&)=delete; + + GenericSubBuffer(T &base,size_t start,size_t length) : + _base(base), + _start(start), + _length(length) + { + // if the sub-buffer is invalid, we set both _start and _length to 0 + if (OverflowCheck::sum(start,length)>_base.size()) + { + _start=0; + _length=0; + } + } + + virtual ~GenericSubBuffer() { } + + virtual const uint8_t *data() const noexcept override + { + return _base.data()+_start; + } + + virtual uint8_t *data() override; + + virtual size_t size() const noexcept override + { + return _length; + } + + virtual bool isResizable() const noexcept override + { + return false; + } + + // can only make the buffer smaller, can't run away from the current bounds + void adjust(size_t start,size_t length) + { + if (start<_start || OverflowCheck::sum(start,length)>_start+_length) throw OutOfBoundsError(); + _start=start; + _length=length; + } + +private: + T &_base; + size_t _start; + size_t _length; +}; + +typedef GenericSubBuffer SubBuffer; +typedef GenericSubBuffer ConstSubBuffer; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/WrappedVectorBuffer.cpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/WrappedVectorBuffer.cpp new file mode 100644 index 00000000..aaf7579e --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/WrappedVectorBuffer.cpp @@ -0,0 +1,45 @@ +/* Copyright (C) Teemu Suutari */ + +#include "WrappedVectorBuffer.hpp" + + +namespace ancient::internal +{ + +WrappedVectorBuffer::WrappedVectorBuffer(std::vector &refdata) : + _refdata(refdata) +{ + return; +} + +WrappedVectorBuffer::~WrappedVectorBuffer() +{ + return; +} + +const uint8_t *WrappedVectorBuffer::data() const noexcept +{ + return _refdata.data(); +} + +uint8_t *WrappedVectorBuffer::data() +{ + return _refdata.data(); +} + +size_t WrappedVectorBuffer::size() const noexcept +{ + return _refdata.size(); +} + +bool WrappedVectorBuffer::isResizable() const noexcept +{ + return true; +} + +void WrappedVectorBuffer::resize(size_t newSize) +{ + _refdata.resize(newSize); +} + +} diff --git a/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/WrappedVectorBuffer.hpp b/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/WrappedVectorBuffer.hpp new file mode 100644 index 00000000..c3a4a921 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/ancient/src/common/WrappedVectorBuffer.hpp @@ -0,0 +1,35 @@ +/* Copyright (C) Teemu Suutari */ + +#ifndef WRAPPEDVECTORBUFFER_HPP +#define WRAPPEDVECTORBUFFER_HPP + +#include + +#include +#include + +#include "Buffer.hpp" + +namespace ancient::internal +{ + +class WrappedVectorBuffer : public Buffer +{ +public: + WrappedVectorBuffer(std::vector &refdata); + virtual ~WrappedVectorBuffer() override final; + + virtual const uint8_t *data() const noexcept override final; + virtual uint8_t *data() override final; + virtual size_t size() const noexcept override final; + + virtual bool isResizable() const noexcept override final; + virtual void resize(size_t newSize) override final; + +private: + std::vector & _refdata; +}; + +} + +#endif -- cgit