diff options
Diffstat (limited to 'fbreader/src/formats/chm/LZXDecompressor.cpp')
-rw-r--r-- | fbreader/src/formats/chm/LZXDecompressor.cpp | 287 |
1 files changed, 0 insertions, 287 deletions
diff --git a/fbreader/src/formats/chm/LZXDecompressor.cpp b/fbreader/src/formats/chm/LZXDecompressor.cpp deleted file mode 100644 index 38b4311..0000000 --- a/fbreader/src/formats/chm/LZXDecompressor.cpp +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Copyright (C) 2004-2012 Geometer Plus <[email protected]> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#include <cstring> - -#include "LZXDecompressor.h" - -static unsigned int slotNumber(int windowSizeIndex) { - if (windowSizeIndex == 20) { - return 42; - } else if (windowSizeIndex == 21) { - return 50; - } else { - return 2 * windowSizeIndex; - } -} - -LZXDecompressor::LZXDecompressor(int windowSizeIndex) : myWindow(1 << windowSizeIndex, 0), mySlotNumber(slotNumber(windowSizeIndex)) { - reset(); -} - -void LZXDecompressor::reset() { - myCurrentBlockType = UNKNOWNN; - myReadHeader = true; - - myState.WindowIterator = myWindow.begin(); - myState.R0 = 1; - myState.R1 = 1; - myState.R2 = 1; - - myMainTree.reset(); - myLengthTree.reset(); - - myBlockBytesLeft = 0; - - myE8Decoder.reset(0); -} - -static bool fill(std::vector<unsigned char> &data, std::vector<unsigned char>::iterator &it, int num, unsigned char value) { - if (data.end() - it < num) { - return false; - } - std::vector<unsigned char>::iterator end = it + num; - while (it != end) { - *it++ = value; - } - return true; -} - -bool LZXDecompressor::readLengths(HuffmanDecoder &decoder, std::size_t from, std::size_t size) { - HuffmanDecoder preTree; - preTree.CodeLengths.reserve(20); - for (int i = 0; i < 20; i++) { - preTree.CodeLengths.push_back(myBitStream.get(4)); - } - if (!preTree.buildTable()) { - return false; - } - - std::vector<unsigned char> &lengths = decoder.CodeLengths; - if (lengths.size() < from + size) { - lengths.insert(lengths.end(), from + size - lengths.size(), 0); - } - std::vector<unsigned char>::iterator start = lengths.begin() + from; - std::vector<unsigned char>::iterator end = start + size; - for (std::vector<unsigned char>::iterator it = start; it != end; ) { - int z = preTree.getSymbol(myBitStream); - if (z == 17) { - if (!fill(lengths, it, myBitStream.get(4) + 4, 0)) { - return false; - } - } else if (z == 18) { - if (!fill(lengths, it, myBitStream.get(5) + 20, 0)) { - return false; - } - } else if (z == 19) { - unsigned int num = myBitStream.get(1) + 4; - z = *it - preTree.getSymbol(myBitStream); - if (!fill(lengths, it, num, (z < 0) ? z + 17 : z)) { - return false; - } - } else { - z = *it - z; - *it++ = (z < 0) ? z + 17 : z; - } - } - - return true; -} - -static const unsigned int basePosition[51] = { - 0, 1, 2, 3, 4, 6, 8, 12, - 16, 24, 32, 48, 64, 96, 128, 192, - 256, 384, 512, 768, 1024, 1536, 2048, 3072, - 4096, 6144, 8192, 12288, 16384, 24576, 32768, 49152, - 65536, 98304, 131072, 196608, 262144, 393216, 524288, 655360, - 786432, 917504, 1048576, 1179648, 1310720, 1441792, 1572864, 1703936, - 1835008, 1966080, 2097152 -}; - -bool LZXDecompressor::decodeBytes(DecodingState &state, std::size_t bytesToDecode) { - if (myCurrentBlockType == UNCOMPRESSED) { - if (!myBitStream.getBytesDirect(&*state.WindowIterator, bytesToDecode)) { - return false; - } - state.WindowIterator += bytesToDecode; - return true; - } - - while (bytesToDecode > 0) { - int symbol = myMainTree.getSymbol(myBitStream); - if (symbol < 256) { - *state.WindowIterator++ = symbol; - --bytesToDecode; - continue; - } - - std::size_t length = symbol % 8; - if (length == 7) { - length += myLengthTree.getSymbol(myBitStream); - } - length += 2; - if (length > bytesToDecode) { - return false; - } - - std::size_t offset = (symbol - 256) / 8; - switch (offset) { - case 0: - offset = state.R0; - break; - case 1: - offset = state.R1; - state.R1 = state.R0; - state.R0 = offset; - break; - case 2: - offset = state.R2; - state.R2 = state.R0; - state.R0 = offset; - break; - default: - if ((myCurrentBlockType == VERBATIM) && (offset == 3)) { - offset = 1; - } else { - if (offset > 50) { - return false; - } - const int positionFooterBits = std::max(0, std::min((int)offset / 2 - 1, 17)); - offset = basePosition[offset] - 2; - if ((myCurrentBlockType == VERBATIM) || (positionFooterBits == 1) || (positionFooterBits == 2)) { - offset += myBitStream.get(positionFooterBits); - } else if (positionFooterBits == 3) { - offset += myAlignedOffsetTree.getSymbol(myBitStream); - } else if (positionFooterBits > 3) { - offset += 8 * myBitStream.get(positionFooterBits - 3); - offset += myAlignedOffsetTree.getSymbol(myBitStream); - } else { - offset = 1; - } - } - state.R2 = state.R1; - state.R1 = state.R0; - state.R0 = offset; - break; - } - - if ((state.WindowIterator - myWindow.begin()) + myWindow.size() < offset) { - return false; - } - if (myWindow.size() >= offset + (myWindow.end() - state.WindowIterator)) { - offset += myWindow.size(); - if (myWindow.size() >= offset + (myWindow.end() - state.WindowIterator)) { - return false; - } - } - std::vector<unsigned char>::iterator srcIt = state.WindowIterator + (myWindow.size() - offset); - for (std::size_t i = 0; i < length; ++i) { - if (srcIt == myWindow.end()) { - srcIt -= myWindow.size(); - } - *state.WindowIterator++ = *srcIt++; - } - bytesToDecode -= length; - } - return true; -} - -bool LZXDecompressor::decompress(const std::string &data, unsigned char *outBuffer, const std::size_t outSize) { - myBitStream.setData(data); - - if (myReadHeader) { - if (myBitStream.get(1) == 1) { - myE8Decoder.reset(myBitStream.get(32)); - } - myReadHeader = false; - } - - DecodingState state = myState; - - for (std::size_t bytesToWrite = outSize; bytesToWrite > 0; ) { - if (myBlockBytesLeft == 0) { - if (myCurrentBlockType == UNCOMPRESSED) { - if (myBlockSize & 1) { - myBitStream.remove(8); - } - myBitStream.reset(); - } - - myCurrentBlockType = (BlockType)myBitStream.get(3); - myBlockSize = myBitStream.get(24); - myBlockBytesLeft = myBlockSize; - - switch (myCurrentBlockType) { - case UNCOMPRESSED: - myBitStream.reset(); - state.R0 = myBitStream.get4BytesDirect(); - state.R1 = myBitStream.get4BytesDirect(); - state.R2 = myBitStream.get4BytesDirect(); - break; - - case ALIGNED: - myAlignedOffsetTree.CodeLengths.clear(); - for (int i = 0; i < 8; i++) { - myAlignedOffsetTree.CodeLengths.push_back(myBitStream.get(3)); - } - if (!myAlignedOffsetTree.buildTable()) { - return false; - } - // no break; it's not a mistake - - case VERBATIM: - if (!readLengths(myMainTree, 0, 256) || - !readLengths(myMainTree, 256, 8 * mySlotNumber) || - !readLengths(myLengthTree, 0, 249) || - !myMainTree.buildTable() || - !myLengthTree.buildTable()) { - return false; - } - break; - - default: - return false; - } - } - - while ((myBlockBytesLeft > 0) && (bytesToWrite > 0)) { - std::size_t bytesToDecode = std::min(myBlockBytesLeft, bytesToWrite); - if (state.WindowIterator + bytesToDecode > myWindow.end()) { - return false; - } - - if (!decodeBytes(state, bytesToDecode)) { - return false; - } - - bytesToWrite -= bytesToDecode; - myBlockBytesLeft -= bytesToDecode; - } - } - - std::vector<unsigned char>::iterator jt = - (state.WindowIterator != myWindow.begin()) ? state.WindowIterator : myWindow.end(); - std::memcpy(outBuffer, &*(jt - outSize), outSize); - - myState = state; - - myE8Decoder.decode(outBuffer, outSize); - - return true; -} |