void Inflator::OutputPast(unsigned int length, unsigned int distance) { size_t start; if (distance <= m_current) start = m_current - distance; else if (m_wrappedAround && distance <= m_window.size()) start = m_current + m_window.size() - distance; else throw BadBlockErr(); if (start + length > m_window.size()) { for (; start < m_window.size(); start++, length--) OutputByte(m_window[start]); start = 0; } if (start + length > m_current || m_current + length >= m_window.size()) { while (length--) OutputByte(m_window[start++]); } else { memcpy(m_window + m_current, m_window + start, length); m_current += length; } }
void Inflator::OutputPast(unsigned int length, unsigned int distance) { if (distance > m_maxDistance) throw BadBlockErr(); unsigned int start; if (m_current > distance) start = m_current - distance; else start = m_current + m_window.size - distance; if (start + length > m_window.size) { for (; start < m_window.size; start++, length--) OutputByte(m_window[start]); start = 0; } if (start + length > m_current || m_current + length >= m_window.size) { while (length--) OutputByte(m_window[start++]); } else { memcpy(m_window + m_current, m_window + start, length); m_current += length; m_maxDistance = STDMIN(m_window.size, m_maxDistance + length); } }
bool Inflator::DecodeBody() { bool blockEnd = false; switch (m_blockType) { case 0: // stored assert(m_reader.BitsBuffered() == 0); while (!m_inQueue.IsEmpty() && !blockEnd) { size_t size; const byte *block = m_inQueue.Spy(size); size = UnsignedMin(m_storedLen, size); OutputString(block, size); m_inQueue.Skip(size); m_storedLen -= (word16)size; if (m_storedLen == 0) blockEnd = true; } break; case 1: // fixed codes case 2: // dynamic codes static const unsigned int lengthStarts[] = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258 }; static const unsigned int lengthExtraBits[] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 }; static const unsigned int distanceStarts[] = { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 }; static const unsigned int distanceExtraBits[] = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 }; const HuffmanDecoder& literalDecoder = GetLiteralDecoder(); const HuffmanDecoder& distanceDecoder = GetDistanceDecoder(); switch (m_nextDecode) { case LITERAL: while (true) { if (!literalDecoder.Decode(m_reader, m_literal)) { m_nextDecode = LITERAL; break; } if (m_literal < 256) OutputByte((byte)m_literal); else if (m_literal == 256) // end of block { blockEnd = true; break; } else { if (m_literal > 285) throw BadBlockErr(); unsigned int bits; case LENGTH_BITS: bits = lengthExtraBits[m_literal-257]; if (!m_reader.FillBuffer(bits)) { m_nextDecode = LENGTH_BITS; break; } m_literal = m_reader.GetBits(bits) + lengthStarts[m_literal-257]; case DISTANCE: if (!distanceDecoder.Decode(m_reader, m_distance)) { m_nextDecode = DISTANCE; break; } case DISTANCE_BITS: bits = distanceExtraBits[m_distance]; if (!m_reader.FillBuffer(bits)) { m_nextDecode = DISTANCE_BITS; break; } m_distance = m_reader.GetBits(bits) + distanceStarts[m_distance]; OutputPast(m_literal, m_distance); } } } } if (blockEnd) { if (m_eof) { FlushOutput(); m_reader.SkipBits(m_reader.BitsBuffered()%8); if (m_reader.BitsBuffered()) { // undo too much lookahead SecBlockWithHint<byte, 4> buffer(m_reader.BitsBuffered() / 8); for (unsigned int i=0; i<buffer.size(); i++) buffer[i] = (byte)m_reader.GetBits(8); m_inQueue.Unget(buffer, buffer.size()); } m_state = POST_STREAM; } else m_state = WAIT_HEADER; } return blockEnd; }
void Inflator::DecodeHeader() { if (!m_reader.FillBuffer(3)) throw UnexpectedEndErr(); m_eof = m_reader.GetBits(1) != 0; m_blockType = (byte)m_reader.GetBits(2); switch (m_blockType) { case 0: // stored { m_reader.SkipBits(m_reader.BitsBuffered() % 8); if (!m_reader.FillBuffer(32)) throw UnexpectedEndErr(); m_storedLen = (word16)m_reader.GetBits(16); word16 nlen = (word16)m_reader.GetBits(16); if (nlen != (word16)~m_storedLen) throw BadBlockErr(); break; } case 1: // fixed codes m_nextDecode = LITERAL; break; case 2: // dynamic codes { if (!m_reader.FillBuffer(5+5+4)) throw UnexpectedEndErr(); unsigned int hlit = m_reader.GetBits(5); unsigned int hdist = m_reader.GetBits(5); unsigned int hclen = m_reader.GetBits(4); FixedSizeSecBlock<unsigned int, 286+32> codeLengths; unsigned int i; static const unsigned int border[] = { // Order of the bit length code lengths 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; std::fill(codeLengths.begin(), codeLengths+19, 0); for (i=0; i<hclen+4; i++) codeLengths[border[i]] = m_reader.GetBits(3); try { HuffmanDecoder codeLengthDecoder(codeLengths, 19); for (i = 0; i < hlit+257+hdist+1; ) { unsigned int k, count, repeater; bool result = codeLengthDecoder.Decode(m_reader, k); if (!result) throw UnexpectedEndErr(); if (k <= 15) { count = 1; repeater = k; } else switch (k) { case 16: if (!m_reader.FillBuffer(2)) throw UnexpectedEndErr(); count = 3 + m_reader.GetBits(2); if (i == 0) throw BadBlockErr(); repeater = codeLengths[i-1]; break; case 17: if (!m_reader.FillBuffer(3)) throw UnexpectedEndErr(); count = 3 + m_reader.GetBits(3); repeater = 0; break; case 18: if (!m_reader.FillBuffer(7)) throw UnexpectedEndErr(); count = 11 + m_reader.GetBits(7); repeater = 0; break; } if (i + count > hlit+257+hdist+1) throw BadBlockErr(); std::fill(codeLengths + i, codeLengths + i + count, repeater); i += count; } m_dynamicLiteralDecoder.Initialize(codeLengths, hlit+257); if (hdist == 0 && codeLengths[hlit+257] == 0) { if (hlit != 0) // a single zero distance code length means all literals throw BadBlockErr(); } else m_dynamicDistanceDecoder.Initialize(codeLengths+hlit+257, hdist+1); m_nextDecode = LITERAL; } catch (HuffmanDecoder::Err &) { throw BadBlockErr(); } break; } default: throw BadBlockErr(); // reserved block type } m_state = DECODING_BODY; }