/* 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(); } } }