/* 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