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

327 lines
7.1 KiB
C++
Raw Normal View History

2024-09-24 12:54:57 +00:00
/* Copyright (C) Teemu Suutari */
#include <array>
#include "LZCBDecompressor.hpp"
#include "RangeDecoder.hpp"
#include "InputStream.hpp"
#include "OutputStream.hpp"
#include "common/Common.hpp"
namespace ancient::internal
{
template<size_t T>
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<T;i++)
_tree[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<length;j++)
_tree[_levelOffsets[i+1]+(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<level;i++)
{
ret=(ret+1)>>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<levels();i++)
ret+=levelSize(i);
return ret;
}
static constexpr uint32_t levelOffset(uint32_t level)
{
uint32_t ret=0;
for (uint32_t i=0;i<level;i++)
ret+=levelSize(i);
return ret;
}
template<uint32_t... I>
static constexpr auto makeLevelOffsetSequence(std::integer_sequence<uint32_t,I...>)
{
return std::integer_sequence<uint32_t,levelOffset(I)...>{};
}
template<uint32_t... I>
static constexpr auto makeLevelSizeSequence(std::integer_sequence<uint32_t,I...>)
{
return std::integer_sequence<uint32_t,levelSize(I)...>{};
}
template<uint32_t... I>
static constexpr std::array<uint32_t,sizeof...(I)> makeArray(std::integer_sequence<uint32_t,I...>)
{
return std::array<uint32_t,sizeof...(I)>{{I...}};
}
static constexpr uint32_t _size=size();
static constexpr uint32_t _levels=levels();
static constexpr std::array<uint32_t,_levels> _levelOffsets=makeArray(makeLevelOffsetSequence(std::make_integer_sequence<uint32_t,levels()>{}));
static constexpr std::array<uint32_t,_levels> _levelSizes=makeArray(makeLevelSizeSequence(std::make_integer_sequence<uint32_t,levels()>{}));
uint16_t _tree[size()];
};
template<size_t T>
class FrequencyDecoder
{
public:
FrequencyDecoder(RangeDecoder &decoder) :
_decoder(decoder)
{
// nothing needed
}
~FrequencyDecoder()
{
// nothing needed
}
template<typename F>
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<T+1> _tree;
uint16_t _threshold=1;
};
bool LZCBDecompressor::detectHeaderXPK(uint32_t hdr) noexcept
{
return hdr==FourCC("LZCB");
}
std::shared_ptr<XPKDecompressor> LZCBDecompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr<XPKDecompressor::State> &state,bool verify)
{
return std::make_shared<LZCBDecompressor>(hdr,recursionLevel,packedData,state,verify);
}
LZCBDecompressor::LZCBDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr<XPKDecompressor::State> &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<ForwardInputStream> _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<FrequencyDecoder<256>> 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<literalCount;i++)
{
auto &literalDecoder=literalDecoders[ch];
if (!literalDecoder) literalDecoder=std::make_unique<FrequencyDecoder<256>>(rangeDecoder);
ch=uint8_t(literalDecoder->decode([&]()
{
return baseLiteralDecoder.decode(readByte);
}));
outputStream.writeByte(ch);
}
} while (literalCount==0x100U);
lastIsLiteral=true;
}
}
}
}