123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123 |
- /* Copyright (C) Teemu Suutari */
- #include "LIN1Decompressor.hpp"
- #include "InputStream.hpp"
- #include "OutputStream.hpp"
- #include "common/Common.hpp"
- namespace ancient::internal
- {
- bool LIN1Decompressor::detectHeaderXPK(uint32_t hdr) noexcept
- {
- return hdr==FourCC("LIN1") || hdr==FourCC("LIN3");
- }
- std::shared_ptr<XPKDecompressor> LIN1Decompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr<XPKDecompressor::State> &state,bool verify)
- {
- return std::make_shared<LIN1Decompressor>(hdr,recursionLevel,packedData,state,verify);
- }
- LIN1Decompressor::LIN1Decompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr<XPKDecompressor::State> &state,bool verify) :
- XPKDecompressor(recursionLevel),
- _packedData(packedData)
- {
- if (!detectHeaderXPK(hdr)) throw Decompressor::InvalidFormatError();
- _ver=(hdr==FourCC("LIN1"))?1:3;
- if (packedData.size()<5) throw Decompressor::InvalidFormatError();
- uint32_t tmp=packedData.readBE32(0);
- if (tmp) throw Decompressor::InvalidFormatError(); // password set
- }
- LIN1Decompressor::~LIN1Decompressor()
- {
- // nothing needed
- }
- const std::string &LIN1Decompressor::getSubName() const noexcept
- {
- static std::string name1="XPK-LIN1: LIN1 LINO packer";
- static std::string name3="XPK-LIN3: LIN3 LINO packer";
- return (_ver==1)?name1:name3;
- }
- void LIN1Decompressor::decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify)
- {
- ForwardInputStream inputStream(_packedData,5,_packedData.size());
- MSBBitReader<ForwardInputStream> bitReader(inputStream);
- auto readBits=[&](uint32_t count)->uint32_t
- {
- return bitReader.readBits8(count);
- };
- auto readByte=[&]()->uint8_t
- {
- return inputStream.readByte();
- };
- size_t rawSize=rawData.size();
- ForwardOutputStream outputStream(rawData,0,rawSize);
- while (!outputStream.eof())
- {
- if (!readBits(1))
- {
- outputStream.writeByte(readByte()^0x55);
- } else {
- uint32_t count=3;
- if (readBits(1))
- {
- count=readBits(2);
- if (count==3)
- {
- count=readBits(3);
- if (count==7)
- {
- count=readBits(4);
- if (count==15)
- {
- count=readByte();
- if (count==0xff) throw Decompressor::DecompressionError();
- count+=3;
- } else count+=14;
- } else count+=7;
- } else count+=4;
- }
- uint32_t distance = 0;
- switch (readBits(2))
- {
- case 0:
- distance=readByte()+1;
- break;
- case 1:
- distance=uint32_t(readBits(2))<<8;
- distance|=readByte();
- distance+=0x101;
- break;
- case 2:
- distance=uint32_t(readBits(4))<<8;
- distance|=readByte();
- distance+=0x501;
- break;
- case 3:
- distance=uint32_t(readBits(6))<<8;
- distance|=readByte();
- distance+=0x1501;
- break;
- }
- // buggy compressors
- count=std::min(count,uint32_t(rawSize-outputStream.getOffset()));
- if (!count) throw Decompressor::DecompressionError();
- outputStream.copy(distance,count);
- }
- }
- }
- }
|