MASHDecompressor.cpp 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. /* Copyright (C) Teemu Suutari */
  2. #include "MASHDecompressor.hpp"
  3. #include "HuffmanDecoder.hpp"
  4. #include "InputStream.hpp"
  5. #include "OutputStream.hpp"
  6. #include "common/Common.hpp"
  7. namespace ancient::internal
  8. {
  9. bool MASHDecompressor::detectHeaderXPK(uint32_t hdr) noexcept
  10. {
  11. return hdr==FourCC("MASH");
  12. }
  13. std::shared_ptr<XPKDecompressor> MASHDecompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr<XPKDecompressor::State> &state,bool verify)
  14. {
  15. return std::make_shared<MASHDecompressor>(hdr,recursionLevel,packedData,state,verify);
  16. }
  17. MASHDecompressor::MASHDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr<XPKDecompressor::State> &state,bool verify) :
  18. XPKDecompressor(recursionLevel),
  19. _packedData(packedData)
  20. {
  21. if (!detectHeaderXPK(hdr)) throw Decompressor::InvalidFormatError();
  22. }
  23. MASHDecompressor::~MASHDecompressor()
  24. {
  25. // nothing needed
  26. }
  27. const std::string &MASHDecompressor::getSubName() const noexcept
  28. {
  29. static std::string name="XPK-MASH: LZRW-compressor";
  30. return name;
  31. }
  32. void MASHDecompressor::decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify)
  33. {
  34. ForwardInputStream inputStream(_packedData,0,_packedData.size());
  35. MSBBitReader<ForwardInputStream> bitReader(inputStream);
  36. auto readBits=[&](uint32_t count)->uint32_t
  37. {
  38. return bitReader.readBits8(count);
  39. };
  40. auto readBit=[&]()->uint32_t
  41. {
  42. return bitReader.readBits8(1);
  43. };
  44. auto readByte=[&]()->uint8_t
  45. {
  46. return inputStream.readByte();
  47. };
  48. size_t rawSize=rawData.size();
  49. ForwardOutputStream outputStream(rawData,0,rawSize);
  50. HuffmanDecoder<uint32_t> litDecoder
  51. {
  52. HuffmanCode<uint32_t>{1,0b000000,0},
  53. HuffmanCode<uint32_t>{2,0b000010,1},
  54. HuffmanCode<uint32_t>{3,0b000110,2},
  55. HuffmanCode<uint32_t>{4,0b001110,3},
  56. HuffmanCode<uint32_t>{5,0b011110,4},
  57. HuffmanCode<uint32_t>{6,0b111110,5},
  58. HuffmanCode<uint32_t>{6,0b111111,6}
  59. };
  60. while (!outputStream.eof())
  61. {
  62. uint32_t litLength=litDecoder.decode(readBit);
  63. if (litLength==6)
  64. {
  65. uint32_t litBits;
  66. for (litBits=1;litBits<=17;litBits++) if (!readBit()) break;
  67. if (litBits==17) throw Decompressor::DecompressionError();
  68. litLength=readBits(litBits)+(1<<litBits)+4;
  69. }
  70. for (uint32_t i=0;i<litLength;i++) outputStream.writeByte(readByte());
  71. uint32_t count,distance;
  72. auto readDistance=[&]()
  73. {
  74. uint32_t tableIndex=readBits(3);
  75. static const uint8_t distanceBits[8]={5,7,9,10,11,12,13,14};
  76. static const uint32_t distanceAdditions[8]={0,0x20,0xa0,0x2a0,0x6a0,0xea0,0x1ea0,0x3ea0};
  77. distance=readBits(distanceBits[tableIndex])+distanceAdditions[tableIndex];
  78. };
  79. if (readBit())
  80. {
  81. uint32_t countBits;
  82. for (countBits=1;countBits<=16;countBits++) if (!readBit()) break;
  83. if (countBits==16) throw Decompressor::DecompressionError();
  84. count=readBits(countBits)+(1<<countBits)+2;
  85. readDistance();
  86. } else {
  87. if (readBit())
  88. {
  89. readDistance();
  90. count=3;
  91. } else {
  92. distance=readBits(9);
  93. count=2;
  94. }
  95. }
  96. // hacks to make it work
  97. if (!distance && outputStream.eof()) break;
  98. // zero distance when we are at the end of the stream...
  99. // there seems to be almost systematic extra one byte at the end of the stream...
  100. count=std::min(count,uint32_t(rawSize-outputStream.getOffset()));
  101. outputStream.copy(distance,count);
  102. }
  103. }
  104. }