127 lines
2.7 KiB
C++
127 lines
2.7 KiB
C++
/* Copyright (C) Teemu Suutari */
|
|
|
|
#include <cstring>
|
|
|
|
#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<XPKDecompressor> SDHCDecompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr<XPKDecompressor::State> &state,bool verify)
|
|
{
|
|
return std::make_shared<SDHCDecompressor>(hdr,recursionLevel,packedData,state,verify);
|
|
}
|
|
|
|
SDHCDecompressor::SDHCDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr<XPKDecompressor::State> &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<length;i+=2)
|
|
{
|
|
uint16_t tmp;
|
|
tmp=(uint16_t(buf[i])<<8)|uint16_t(buf[i+1]);
|
|
ctr+=tmp;
|
|
buf[i]=ctr>>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<length;i+=4)
|
|
{
|
|
uint16_t tmp;
|
|
tmp=(uint16_t(buf[i])<<8)|uint16_t(buf[i+1]);
|
|
ctr1+=tmp;
|
|
tmp=(uint16_t(buf[i+2])<<8)|uint16_t(buf[i+3]);
|
|
ctr2+=tmp;
|
|
buf[i]=ctr1>>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();
|
|
}
|
|
}
|
|
|
|
}
|