LZXDecompressor.cpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. /* Copyright (C) Teemu Suutari */
  2. #include <cstdint>
  3. #include <cstring>
  4. #include "LZXDecompressor.hpp"
  5. #include "HuffmanDecoder.hpp"
  6. #include "DLTADecode.hpp"
  7. #include "InputStream.hpp"
  8. #include "OutputStream.hpp"
  9. #include "common/CRC32.hpp"
  10. #include "common/Common.hpp"
  11. #include "common/OverflowCheck.hpp"
  12. namespace ancient::internal
  13. {
  14. bool LZXDecompressor::detectHeaderXPK(uint32_t hdr) noexcept
  15. {
  16. return hdr==FourCC("ELZX") || hdr==FourCC("SLZX");
  17. }
  18. std::shared_ptr<XPKDecompressor> LZXDecompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr<XPKDecompressor::State> &state,bool verify)
  19. {
  20. return std::make_shared<LZXDecompressor>(hdr,recursionLevel,packedData,state,verify);
  21. }
  22. LZXDecompressor::LZXDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr<XPKDecompressor::State> &state,bool verify) :
  23. XPKDecompressor(recursionLevel),
  24. _packedData(packedData)
  25. {
  26. if (!detectHeaderXPK(hdr)) throw Decompressor::InvalidFormatError();
  27. if (hdr==FourCC("SLZX")) _isSampled=true;
  28. // There is no good spec on the LZX header content -> lots of unknowns here
  29. if (_packedData.size()<41) throw Decompressor::InvalidFormatError();
  30. // XPK LZX compression is embedded single file of LZX -> read first file. Ignore rest
  31. // this will include flags, which need to be zero anyway
  32. uint32_t streamHdr=_packedData.readBE32(0);
  33. if (streamHdr!=FourCC("LZX\0")) throw Decompressor::InvalidFormatError();
  34. _rawSize=_packedData.readLE32(12);
  35. _packedSize=_packedData.readLE32(16);
  36. _rawCRC=_packedData.readLE32(32);
  37. uint32_t headerCRC=_packedData.readLE32(36);
  38. uint8_t tmp=_packedData.read8(21);
  39. if (tmp && tmp!=2) throw Decompressor::InvalidFormatError();
  40. if (tmp==2) _isCompressed=true;
  41. _packedOffset=41U+_packedData.read8(40U);
  42. _packedOffset+=_packedData.read8(24U);
  43. _packedSize+=_packedOffset;
  44. if (_packedSize>_packedData.size()) throw Decompressor::InvalidFormatError();
  45. if (verify)
  46. {
  47. uint32_t crc=CRC32(_packedData,10,26,0);
  48. for (uint32_t i=0;i<4;i++) crc=CRC32Byte(0,crc);
  49. crc=CRC32(_packedData,40,_packedOffset-40,crc);
  50. if (crc!=headerCRC) throw Decompressor::VerificationError();
  51. }
  52. }
  53. LZXDecompressor::~LZXDecompressor()
  54. {
  55. // nothing needed
  56. }
  57. const std::string &LZXDecompressor::getSubName() const noexcept
  58. {
  59. static std::string nameE="XPK-ELZX: LZX-compressor";
  60. static std::string nameS="XPK-SLZX: LZX-compressor with delta encoding";
  61. return (_isSampled)?nameS:nameE;
  62. }
  63. void LZXDecompressor::decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify)
  64. {
  65. if (rawData.size()!=_rawSize) throw Decompressor::DecompressionError();
  66. if (!_isCompressed)
  67. {
  68. if (_packedSize!=_rawSize) throw Decompressor::DecompressionError();
  69. std::memcpy(rawData.data(),_packedData.data()+_packedOffset,_rawSize);
  70. return;
  71. }
  72. ForwardInputStream inputStream(_packedData,_packedOffset,_packedSize);
  73. LSBBitReader<ForwardInputStream> bitReader(inputStream);
  74. auto readBits=[&](uint32_t count)->uint32_t
  75. {
  76. return bitReader.readBitsBE16(count);
  77. };
  78. auto readBit=[&]()->uint32_t
  79. {
  80. return bitReader.readBitsBE16(1);
  81. };
  82. ForwardOutputStream outputStream(rawData,0,rawData.size());
  83. typedef HuffmanDecoder<uint32_t> LZXDecoder;
  84. // possibly padded/reused later if multiple blocks
  85. uint8_t literalTable[768];
  86. for (uint32_t i=0;i<768;i++) literalTable[i]=0;
  87. LZXDecoder literalDecoder;
  88. uint32_t previousDistance=1;
  89. while (!outputStream.eof())
  90. {
  91. auto createHuffmanTable=[&](LZXDecoder &dec,const uint8_t *bitLengths,uint32_t bitTableLength)
  92. {
  93. uint8_t minDepth=16,maxDepth=0;
  94. for (uint32_t i=0;i<bitTableLength;i++)
  95. {
  96. if (bitLengths[i] && bitLengths[i]<minDepth) minDepth=bitLengths[i];
  97. if (bitLengths[i]>maxDepth) maxDepth=bitLengths[i];
  98. }
  99. if (!maxDepth) return;
  100. dec.createOrderlyHuffmanTable(bitLengths,bitTableLength);
  101. };
  102. uint32_t method=readBits(3);
  103. if (method<1 || method>3) throw Decompressor::DecompressionError();
  104. LZXDecoder distanceDecoder;
  105. if (method==3)
  106. {
  107. uint8_t bitLengths[8];
  108. for (uint32_t i=0;i<8;i++) bitLengths[i]=readBits(3);
  109. createHuffmanTable(distanceDecoder,bitLengths,8);
  110. }
  111. size_t blockLength=readBits(8)<<16;
  112. blockLength|=readBits(8)<<8;
  113. blockLength|=readBits(8);
  114. if (OverflowCheck::sum(blockLength,outputStream.getOffset())>_rawSize) throw Decompressor::DecompressionError();
  115. if (method!=1)
  116. {
  117. literalDecoder.reset();
  118. for (uint32_t pos=0,block=0;block<2;block++)
  119. {
  120. uint32_t adjust=(block)?0:1;
  121. uint32_t maxPos=(block)?768:256;
  122. LZXDecoder bitLengthDecoder;
  123. {
  124. uint8_t lengthTable[20];
  125. for (uint32_t i=0;i<20;i++) lengthTable[i]=readBits(4);
  126. createHuffmanTable(bitLengthDecoder,lengthTable,20);
  127. }
  128. while (pos<maxPos)
  129. {
  130. uint32_t symbol=bitLengthDecoder.decode(readBit);
  131. auto doRepeat=[&](uint32_t count,uint8_t value)
  132. {
  133. if (count>maxPos-pos) count=maxPos-pos;
  134. while (count--) literalTable[pos++]=value;
  135. };
  136. auto symDecode=[&](uint32_t value)->uint32_t
  137. {
  138. return (literalTable[pos]+17-value)%17;
  139. };
  140. switch (symbol)
  141. {
  142. case 17:
  143. doRepeat(readBits(4)+3+adjust,0);
  144. break;
  145. case 18:
  146. doRepeat(readBits(6-adjust)+19+adjust,0);
  147. break;
  148. case 19:
  149. {
  150. uint32_t count=readBit()+3+adjust;
  151. doRepeat(count,symDecode(bitLengthDecoder.decode(readBit)));
  152. }
  153. break;
  154. default:
  155. literalTable[pos++]=symDecode(symbol);
  156. break;
  157. }
  158. }
  159. }
  160. createHuffmanTable(literalDecoder,literalTable,768);
  161. }
  162. while (blockLength)
  163. {
  164. uint32_t symbol=literalDecoder.decode(readBit);
  165. if (symbol<256) {
  166. outputStream.writeByte(symbol);
  167. blockLength--;
  168. } else {
  169. // both of these tables are almost too regular to be tables...
  170. static const uint8_t ldBits[32]={
  171. 0,0,0,0,1,1,2,2,
  172. 3,3,4,4,5,5,6,6,
  173. 7,7,8,8,9,9,10,10,
  174. 11,11,12,12,13,13,14,14};
  175. static const uint32_t ldAdditions[32]={
  176. 0x0,
  177. 0x1, 0x2, 0x3, 0x4, 0x6, 0x8, 0xc, 0x10,
  178. 0x18, 0x20, 0x30, 0x40, 0x60, 0x80, 0xc0, 0x100,
  179. 0x180, 0x200, 0x300, 0x400, 0x600, 0x800, 0xc00,0x1000,
  180. 0x1800,0x2000,0x3000,0x4000,0x6000,0x8000,0xc000};
  181. symbol-=256;
  182. uint32_t bits=ldBits[symbol&0x1f];
  183. uint32_t distance=ldAdditions[symbol&0x1f];
  184. if (bits>=3 && method==3)
  185. {
  186. distance+=readBits(bits-3)<<3;
  187. uint32_t tmp=distanceDecoder.decode(readBit);
  188. distance+=tmp;
  189. } else {
  190. distance+=readBits(bits);
  191. if (!distance) distance=previousDistance;
  192. }
  193. previousDistance=distance;
  194. uint32_t count=ldAdditions[symbol>>5]+readBits(ldBits[symbol>>5])+3;
  195. if (count>blockLength) throw Decompressor::DecompressionError();
  196. outputStream.copy(distance,count);
  197. blockLength-=count;
  198. }
  199. }
  200. }
  201. if (verify)
  202. {
  203. uint32_t crc=CRC32(rawData,0,_rawSize,0);
  204. if (crc!=_rawCRC) throw Decompressor::VerificationError();
  205. }
  206. if (_isSampled)
  207. DLTADecode::decode(rawData,rawData,0,_rawSize);
  208. }
  209. }