winamp/Src/external_dependencies/openmpt-trunk/include/ancient/src/SDHCDecompressor.cpp

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