├── LICENSE ├── Makefile ├── README.md ├── build.bat ├── example └── Application.cc └── source ├── adler32.cc ├── adler32.h ├── bit_reader.cc ├── bit_reader.h ├── crc32.cc ├── crc32.h ├── decompressor.cc ├── decompressor.h ├── huffman_decoder.cc └── huffman_decoder.h /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Artexety 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SOURCE_FILES := $(wildcard bin/*.cc) 2 | OBJECT_FILES := $(patsubst %.cc, %.o, $(SOURCE_FILES)) 3 | 4 | all: compile 5 | 6 | compile: $(OBJECT_FILES) 7 | g++ -o Inflatecpp.exe $^ 8 | 9 | %.o: %.cc 10 | g++ -c -o $@ $< -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Inflate++ 2 | [![Code Size](https://img.shields.io/github/languages/code-size/Artexety/inflatecpp?style=flat-square)](https://github.com/Artexety/inflatecpp) 3 | [![GitHub issues](https://img.shields.io/github/issues/Artexety/inflatecpp?style=flat-square)](https://github.com/Artexety/inflatecpp) 4 | [![GitHub license](https://img.shields.io/github/license/mashape/apistatus.svg?style=flat-square)](https://github.com/Artexety/inflatecpp) 5 | 6 | __Inflate++__ is a single function call (optional), memory-to-memory decompressor for the zlib and deflate bitstream formats: 7 | 8 | [RFC 1950: ZLIB specification](https://www.ietf.org/rfc/rfc1950.txt) 9 | 10 | [RFC 1951: DEFLATE specification](https://www.ietf.org/rfc/rfc1951.txt) 11 | 12 | [RFC 1952: GZIP specification](https://www.ietf.org/rfc/rfc1952.txt) 13 | 14 | __Inflate++__ is less than 1000 lines of C++ (excluding aproximatly 250 lines of the adler checksum implementation), and decompresses faster than the original zlib method. 15 | 16 | Decompressing large raw texture file (zlib bitstream, 60,132,846 bytes compressed to 25,614,357): 17 | 18 | Decompressor Time (microseconds) 19 | zlib inflate 1.2.11 134,245 (100%) 20 | Inflate++ (with checksum) 118,399 (91%) 21 | Inflate++ (without checksum) 110,238 (85%) 22 | 23 | Decompressing GZIP format archive (gzip bitstream, 147,120,395 bytes compressed to 53,625,384): 24 | 25 | Decompressor Time (microseconds) 26 | zlib inflate 1.2.11 465,567 (100%) 27 | Inflate++ (with checksum) 362,133 (87%) 28 | Inflate++ (without checksum) 265,462 (65%) 29 | 30 | --- 31 | ## Usage 32 | First, you need to include all source files given in this repository to your project. Then include "decompressor.h" in your code and you are ready to go. 33 | 34 | You can use the "decompressor.h" as follows: 35 | 36 | ```C++ 37 | 38 | #include 39 | #include 40 | 41 | #include "\decompressor.h" 42 | 43 | int main(int argc, const char *argv[]) 44 | { 45 | Decompressor example_decompressor = Decompressor(); 46 | 47 | unsigned int compressed_data_size = ... 48 | unsigned int max_decompressed_data_size = 200000000; // As an example 49 | unsigned char *compressed_data = new unsigned char[compressed_data_size]; 50 | unsigned char *decompressed_data = new unsigned char[max_decompressed_data_size]; 51 | 52 | // ... 53 | // assign values to "compressed_data" 54 | // ... 55 | 56 | unsigned int decompressed_data_size = example_decompressor.Feed(compressed_data, 57 | compressed_data_size, decompressed_data, max_decompressed_data_size, true); 58 | // Use "true" as fifth argument of "Feed()" if you want to use the checksum 59 | 60 | if(decompressed_data_size == -1) 61 | { 62 | std::cout << "decompression error!" << std::endl; 63 | delete [] compressed_data; 64 | delete [] decompressed_data; 65 | 66 | return 0; 67 | } 68 | 69 | std::cout << "decompressed " << decompressed_data_size << " bytes"; 70 | 71 | // ... 72 | // use the decompressed data stored in "decompressed_data" 73 | // ... 74 | 75 | return 0; 76 | } 77 | 78 | ``` 79 | [See example](https://github.com/Artexety/inflatecpp/blob/main/example/Application.cc) 80 | NOTE: To build the example just run __build.bat__ in the command prompt (windows). 81 | 82 | --- 83 | ## License 84 | __Inflate++__ is developed by Artexety inspired by Mark Adlers zlib decompression. The adler checksum compution by [Mark Adler](https://github.com/madler). The gzip crc32 checksum by [Stephen Brumme](https://github.com/stbrumme). All code is licensed under the [permissive free software license (MIT)](https://mit-license.org). All mentions are included in the source code aswell. 85 | 86 | -------------------------------------------------------------------------------- /build.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | md "bin" >nul 2>&1 3 | copy source bin >nul 2>&1 4 | copy example bin >nul >nul 2>&1 5 | 6 | make 7 | 8 | del "bin\*" /f /q /s >nul 2>&1 9 | rmdir "bin" >nul 2>&1 -------------------------------------------------------------------------------- /example/Application.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "decompressor.h" 6 | 7 | int main(int argc, const char *argv[]) 8 | { 9 | if (argc < 2) 10 | { 11 | std::cout << "usage: " << argv[0] << " [infile] [outfile]" << std::endl; 12 | return 0; 13 | } 14 | 15 | Decompressor example_decompressor = Decompressor(); 16 | std::ifstream input_file = std::ifstream(argv[1], std::ios::binary | std::ios::app | std::ios::in); 17 | std::ofstream output_file; 18 | 19 | if(!input_file.is_open()) 20 | { 21 | std::cout << "could not open the specified input file!" << std::endl; 22 | return 0; 23 | } 24 | 25 | input_file.seekg(0, std::ios::end); 26 | unsigned int compressed_data_size = input_file.tellg(); 27 | input_file.seekg(0, std::ios::beg); 28 | 29 | unsigned int max_decompressed_data_size = 200000000; // As an example (max buffer size) 30 | unsigned char *compressed_data = new unsigned char[compressed_data_size]; 31 | unsigned char *decompressed_data = new unsigned char[max_decompressed_data_size]; 32 | 33 | input_file.read(reinterpret_cast(&compressed_data[0]), compressed_data_size); 34 | input_file.close(); 35 | 36 | unsigned int decompressed_data_size = example_decompressor.Feed(compressed_data, 37 | compressed_data_size, decompressed_data, max_decompressed_data_size, false); 38 | 39 | if (decompressed_data_size == -1) 40 | { 41 | std::cout << "decompression error!" << std::endl; 42 | delete[] compressed_data; 43 | delete[] decompressed_data; 44 | 45 | return 0; 46 | } 47 | 48 | std::cout << "decompressed " << decompressed_data_size << " bytes" << std::endl; 49 | 50 | output_file.open(argv[2], std::ios::binary | std::ios::app | std::ios::out); 51 | 52 | if (!output_file.is_open()) 53 | { 54 | std::cout << "could not open the specified output file!" << std::endl; 55 | delete[] compressed_data; 56 | delete[] decompressed_data; 57 | 58 | return 0; 59 | } 60 | 61 | output_file.write(reinterpret_cast(&decompressed_data[0]), decompressed_data_size); 62 | output_file.close(); 63 | 64 | delete[] compressed_data; 65 | delete[] decompressed_data; 66 | 67 | return 0; 68 | } 69 | -------------------------------------------------------------------------------- /source/adler32.cc: -------------------------------------------------------------------------------- 1 | #include "adler32.h" 2 | 3 | unsigned int adler32_z(unsigned int adler, const unsigned char *buf, unsigned int len) 4 | { 5 | unsigned long sum2; 6 | unsigned n; 7 | 8 | /* split Adler-32 into component sums */ 9 | sum2 = (adler >> 16) & 0xffff; 10 | adler &= 0xffff; 11 | 12 | /* in case user likes doing a byte at a time, keep it fast */ 13 | if (len == 1) { 14 | adler += buf[0]; 15 | if (adler >= BASE) 16 | adler -= BASE; 17 | sum2 += adler; 18 | if (sum2 >= BASE) 19 | sum2 -= BASE; 20 | return adler | (sum2 << 16); 21 | } 22 | 23 | /* initial Adler-32 value (deferred check for len == 1 speed) */ 24 | if (buf == NULL) 25 | return 1L; 26 | 27 | /* in case short lengths are provided, keep it somewhat fast */ 28 | if (len < 16) { 29 | while (len--) { 30 | adler += *buf++; 31 | sum2 += adler; 32 | } 33 | if (adler >= BASE) 34 | adler -= BASE; 35 | MOD28(sum2); /* only added so many BASE's */ 36 | return adler | (sum2 << 16); 37 | } 38 | 39 | /* do length NMAX blocks -- requires just one modulo operation */ 40 | while (len >= NMAX) { 41 | len -= NMAX; 42 | n = NMAX / 16; /* NMAX is divisible by 16 */ 43 | do { 44 | DO16(buf); /* 16 sums unrolled */ 45 | buf += 16; 46 | } while (--n); 47 | MOD(adler); 48 | MOD(sum2); 49 | } 50 | 51 | /* do remaining bytes (less than NMAX, still just one modulo) */ 52 | if (len) { /* avoid modulos if none remaining */ 53 | while (len >= 16) { 54 | len -= 16; 55 | DO16(buf); 56 | buf += 16; 57 | } 58 | while (len--) { 59 | adler += *buf++; 60 | sum2 += adler; 61 | } 62 | MOD(adler); 63 | MOD(sum2); 64 | } 65 | 66 | /* return recombined sums */ 67 | return adler | (sum2 << 16); 68 | } 69 | -------------------------------------------------------------------------------- /source/adler32.h: -------------------------------------------------------------------------------- 1 | /* 2 | By Mark Adler - https://github.com/madler/zlib/blob/master/adler32.c 3 | 4 | Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler 5 | This software is provided 'as-is', without any express or implied 6 | warranty. In no event will the authors be held liable for any damages 7 | arising from the use of this software. 8 | Permission is granted to anyone to use this software for any purpose, 9 | including commercial applications, and to alter it and redistribute it 10 | freely, subject to the following restrictions: 11 | 1. The origin of this software must not be misrepresented; you must not 12 | claim that you wrote the original software. If you use this software 13 | in a product, an acknowledgment in the product documentation would be 14 | appreciated but is not required. 15 | 2. Altered source versions must be plainly marked as such, and must not be 16 | misrepresented as being the original software. 17 | 3. This notice may not be removed or altered from any source distribution. 18 | Jean-loup Gailly Mark Adler 19 | jloup@gzip.org madler@alumni.caltech.edu 20 | The data format used by the zlib library is described by RFCs (Request for 21 | Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 22 | (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). 23 | */ 24 | 25 | #ifndef _ADLER_32_H 26 | #define _ADLER_32_H 27 | 28 | #include 29 | #include 30 | 31 | #define BASE 65521U 32 | #define NMAX 5552 33 | 34 | #define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} 35 | #define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); 36 | #define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); 37 | #define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); 38 | #define DO16(buf) DO8(buf,0); DO8(buf,8); 39 | #define MOD(a) a %= BASE 40 | #define MOD28(a) a %= BASE 41 | #define MOD63(a) a %= BASE 42 | 43 | unsigned int adler32_z(unsigned int, const unsigned char *, unsigned int); 44 | 45 | #endif /* !_ADLER_32_H */ 46 | 47 | -------------------------------------------------------------------------------- /source/bit_reader.cc: -------------------------------------------------------------------------------- 1 | #include "bit_reader.h" 2 | 3 | BitReader::BitReader() 4 | { 5 | this->shifter_bit_count_ = 0; 6 | this->shifter_data_ = 0; 7 | this->in_block_ = nullptr; 8 | this->in_block_end_ = nullptr; 9 | this->in_block_start_ = nullptr; 10 | } 11 | 12 | /** 13 | * Initialize bit reader 14 | * 15 | * @param in_block pointer to the start of the compressed block 16 | * @param in_block_end pointer to the end of the compressed block + 1 17 | */ 18 | void BitReader::Init(unsigned char *in_block, unsigned char *in_block_end) 19 | { 20 | this->in_block_ = in_block; 21 | this->in_block_end_ = in_block_end; 22 | this->in_block_start_ = in_block; 23 | } 24 | 25 | /** Refill 32 bits at a time if the architecture allows it, otherwise do nothing. */ 26 | void BitReader::Refill32() 27 | { 28 | #ifdef X64BIT_SHIFTER 29 | if (this->shifter_bit_count_ <= 32 && (this->in_block_ + 4) <= this->in_block_end_) 30 | { 31 | #ifdef defined(_M_X64) || defined(__x86_64__) 32 | this->shifter_data_ |= (((shifter_t)(*((unsigned int*)this->in_block_))) << this->shifter_bit_count_); 33 | this->shifter_bit_count_ += 32; 34 | this->in_block_ += 4; 35 | #else 36 | this->shifter_data_ |= (((shifter_t)(*this->in_block_++)) << this->shifter_bit_count_); 37 | this->shifter_bit_count_ += 8; 38 | this->shifter_data_ |= (((shifter_t)(*this->in_block_++)) << this->shifter_bit_count_); 39 | this->shifter_bit_count_ += 8; 40 | this->shifter_data_ |= (((shifter_t)(*this->in_block_++)) << this->shifter_bit_count_); 41 | this->shifter_bit_count_ += 8; 42 | this->shifter_data_ |= (((shifter_t)(*this->in_block_++)) << this->shifter_bit_count_); 43 | this->shifter_bit_count_ += 8; 44 | #endif 45 | } 46 | #endif /* X64BIT_SHIFTER */ 47 | } 48 | 49 | /** 50 | * Consume variable bit-length value, after reading it with PeekBits() 51 | * 52 | * @param n size of value to consume, in bits 53 | */ 54 | void BitReader::ConsumeBits(const int n) 55 | { 56 | this->shifter_data_ >>= n; 57 | this->shifter_bit_count_ -= n; 58 | } 59 | 60 | /** 61 | * Read variable bit-length value 62 | * 63 | * @param n size of value in bits (number of bits to read), 0..16 64 | * 65 | * @return value, or -1 for failure 66 | */ 67 | unsigned int BitReader::GetBits(const int n) 68 | { 69 | if (this->shifter_bit_count_ < n) 70 | { 71 | if (this->in_block_ < this->in_block_end_) 72 | { 73 | this->shifter_data_ |= (((shifter_t)(*this->in_block_++)) << this->shifter_bit_count_); 74 | this->shifter_bit_count_ += 8; 75 | 76 | if (this->in_block_ < this->in_block_end_) 77 | { 78 | this->shifter_data_ |= (((shifter_t)(*this->in_block_++)) << this->shifter_bit_count_); 79 | this->shifter_bit_count_ += 8; 80 | } 81 | } 82 | else 83 | return -1; 84 | } 85 | 86 | unsigned int value = this->shifter_data_ & ((1 << n) - 1); 87 | this->shifter_data_ >>= n; 88 | this->shifter_bit_count_ -= n; 89 | return value; 90 | } 91 | 92 | /** 93 | * Peek at a 16-bit value in the bitstream (lookahead) 94 | * 95 | * @return value 96 | */ 97 | unsigned int BitReader::PeekBits() 98 | { 99 | if (this->shifter_bit_count_ < 16) 100 | { 101 | if (this->in_block_ < this->in_block_end_) 102 | { 103 | this->shifter_data_ |= (((shifter_t)(*this->in_block_++)) << this->shifter_bit_count_); 104 | if (this->in_block_ < this->in_block_end_) 105 | this->shifter_data_ |= (((shifter_t)(*this->in_block_++)) << (this->shifter_bit_count_ + 8)); 106 | this->shifter_bit_count_ += 16; 107 | } 108 | } 109 | 110 | return this->shifter_data_ & 0xffff; 111 | } 112 | 113 | /** Re-align bitstream on a byte */ 114 | int BitReader::ByteAllign() 115 | { 116 | while (this->shifter_bit_count_ >= 8) { 117 | this->shifter_bit_count_ -= 8; 118 | this->in_block_--; 119 | if (this->in_block_ < this->in_block_start_) return -1; 120 | } 121 | 122 | this->shifter_bit_count_ = 0; 123 | this->shifter_data_ = 0; 124 | return 0; 125 | } 126 | 127 | void BitReader::ModifyInBlock(const int v) 128 | { 129 | this->in_block_ += v; 130 | } 131 | -------------------------------------------------------------------------------- /source/bit_reader.h: -------------------------------------------------------------------------------- 1 | #ifndef _BIT_READER_H 2 | #define _BIT_READER_H 3 | 4 | #if defined(_M_X64) || defined(__x86_64__) || defined(__aarch64__) 5 | #define X64BIT_SHIFTER 6 | #endif /* defined(_M_X64) */ 7 | 8 | #ifdef X64BIT_SHIFTER 9 | typedef unsigned long long shifter_t; 10 | #else 11 | typedef unsigned int shifter_t; 12 | #endif /* X64BIT_SHIFTER */ 13 | 14 | class BitReader 15 | { 16 | public: 17 | BitReader(); 18 | ~BitReader() = default; 19 | 20 | void Init(unsigned char *, unsigned char *); 21 | void ConsumeBits(const int); 22 | void ModifyInBlock(const int); 23 | void Refill32(); 24 | 25 | unsigned int GetBits(const int); 26 | unsigned int PeekBits(); 27 | 28 | int ByteAllign(); 29 | 30 | unsigned char *GetInBlock() { return this->in_block_; }; 31 | unsigned char *GetInBlockEnd() { return this->in_block_end_; }; 32 | unsigned char *GetInBlockStart() { return this->in_block_start_; }; 33 | 34 | private: 35 | int shifter_bit_count_; 36 | shifter_t shifter_data_; 37 | unsigned char *in_block_; 38 | unsigned char *in_block_end_; 39 | unsigned char *in_block_start_; 40 | }; 41 | 42 | #endif /* !_BIT_READER_H */ -------------------------------------------------------------------------------- /source/crc32.cc: -------------------------------------------------------------------------------- 1 | #include "crc32.h" 2 | 3 | inline unsigned int crc32_swap(unsigned int x) { 4 | #if defined(__GNUC__) || defined(__clang__) 5 | return __builtin_bswap32(x); 6 | #else 7 | return (x >> 24) | ((x >> 8) & 0x0000FF00) | ((x << 8) & 0x00FF0000) | (x << 24); 8 | #endif 9 | } 10 | 11 | unsigned int crc32_4bytes(const void* data, unsigned int length, unsigned int previousCrc32) { 12 | unsigned int crc = ~previousCrc32; 13 | const unsigned int* current = (const unsigned int*)data; 14 | 15 | while (length >= 4) 16 | { 17 | unsigned int one = *current++ ^ crc; 18 | crc = kCrc32Lookup[0][(one >> 24) & 0xFF] ^ kCrc32Lookup[1][(one >> 16) & 0xFF] ^ 19 | kCrc32Lookup[2][(one >> 8) & 0xFF] ^ kCrc32Lookup[3][one & 0xFF]; 20 | 21 | length -= 4; 22 | } 23 | 24 | const unsigned char* currentChar = (const unsigned char*)current; 25 | 26 | while (length-- != 0) 27 | crc = (crc >> 8) ^ kCrc32Lookup[0][(crc & 0xFF) ^ *currentChar++]; 28 | 29 | return ~crc; 30 | } -------------------------------------------------------------------------------- /source/crc32.h: -------------------------------------------------------------------------------- 1 | /*-- gzip crc32 calculation --*/ 2 | 3 | /** 4 | By Stephen Brumme - https://create.stephan-brumme.com/crc32/ 5 | Unless otherwise noted in a file's first 5 lines, all source code published on http://create.stephan-brumme.com and its sub-pages is licensed similar to the zlib license: 6 | This software is provided 'as-is', without any express or implied warranty. In no event will the author be held liable for any damages arising from the use of this software. 7 | Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 8 | The origin of this software must not be misrepresented; you must not claim that you wrote the original software. 9 | If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 10 | Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 11 | */ 12 | 13 | #ifndef _CRC_32_H 14 | #define _CRC_32_H 15 | 16 | #include 17 | #include 18 | 19 | constexpr auto kLittleEdian = 1234; 20 | constexpr auto kBigEdian = 4321; 21 | constexpr unsigned int kCrc32Lookup[4][256] = { 22 | { 23 | 0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,0xE963A535,0x9E6495A3, 24 | 0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,0x09B64C2B,0x7EB17CBD,0xE7B82D07,0x90BF1D91, 25 | 0x1DB71064,0x6AB020F2,0xF3B97148,0x84BE41DE,0x1ADAD47D,0x6DDDE4EB,0xF4D4B551,0x83D385C7, 26 | 0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC,0x14015C4F,0x63066CD9,0xFA0F3D63,0x8D080DF5, 27 | 0x3B6E20C8,0x4C69105E,0xD56041E4,0xA2677172,0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B, 28 | 0x35B5A8FA,0x42B2986C,0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59, 29 | 0x26D930AC,0x51DE003A,0xC8D75180,0xBFD06116,0x21B4F4B5,0x56B3C423,0xCFBA9599,0xB8BDA50F, 30 | 0x2802B89E,0x5F058808,0xC60CD9B2,0xB10BE924,0x2F6F7C87,0x58684C11,0xC1611DAB,0xB6662D3D, 31 | 0x76DC4190,0x01DB7106,0x98D220BC,0xEFD5102A,0x71B18589,0x06B6B51F,0x9FBFE4A5,0xE8B8D433, 32 | 0x7807C9A2,0x0F00F934,0x9609A88E,0xE10E9818,0x7F6A0DBB,0x086D3D2D,0x91646C97,0xE6635C01, 33 | 0x6B6B51F4,0x1C6C6162,0x856530D8,0xF262004E,0x6C0695ED,0x1B01A57B,0x8208F4C1,0xF50FC457, 34 | 0x65B0D9C6,0x12B7E950,0x8BBEB8EA,0xFCB9887C,0x62DD1DDF,0x15DA2D49,0x8CD37CF3,0xFBD44C65, 35 | 0x4DB26158,0x3AB551CE,0xA3BC0074,0xD4BB30E2,0x4ADFA541,0x3DD895D7,0xA4D1C46D,0xD3D6F4FB, 36 | 0x4369E96A,0x346ED9FC,0xAD678846,0xDA60B8D0,0x44042D73,0x33031DE5,0xAA0A4C5F,0xDD0D7CC9, 37 | 0x5005713C,0x270241AA,0xBE0B1010,0xC90C2086,0x5768B525,0x206F85B3,0xB966D409,0xCE61E49F, 38 | 0x5EDEF90E,0x29D9C998,0xB0D09822,0xC7D7A8B4,0x59B33D17,0x2EB40D81,0xB7BD5C3B,0xC0BA6CAD, 39 | 0xEDB88320,0x9ABFB3B6,0x03B6E20C,0x74B1D29A,0xEAD54739,0x9DD277AF,0x04DB2615,0x73DC1683, 40 | 0xE3630B12,0x94643B84,0x0D6D6A3E,0x7A6A5AA8,0xE40ECF0B,0x9309FF9D,0x0A00AE27,0x7D079EB1, 41 | 0xF00F9344,0x8708A3D2,0x1E01F268,0x6906C2FE,0xF762575D,0x806567CB,0x196C3671,0x6E6B06E7, 42 | 0xFED41B76,0x89D32BE0,0x10DA7A5A,0x67DD4ACC,0xF9B9DF6F,0x8EBEEFF9,0x17B7BE43,0x60B08ED5, 43 | 0xD6D6A3E8,0xA1D1937E,0x38D8C2C4,0x4FDFF252,0xD1BB67F1,0xA6BC5767,0x3FB506DD,0x48B2364B, 44 | 0xD80D2BDA,0xAF0A1B4C,0x36034AF6,0x41047A60,0xDF60EFC3,0xA867DF55,0x316E8EEF,0x4669BE79, 45 | 0xCB61B38C,0xBC66831A,0x256FD2A0,0x5268E236,0xCC0C7795,0xBB0B4703,0x220216B9,0x5505262F, 46 | 0xC5BA3BBE,0xB2BD0B28,0x2BB45A92,0x5CB36A04,0xC2D7FFA7,0xB5D0CF31,0x2CD99E8B,0x5BDEAE1D, 47 | 0x9B64C2B0,0xEC63F226,0x756AA39C,0x026D930A,0x9C0906A9,0xEB0E363F,0x72076785,0x05005713, 48 | 0x95BF4A82,0xE2B87A14,0x7BB12BAE,0x0CB61B38,0x92D28E9B,0xE5D5BE0D,0x7CDCEFB7,0x0BDBDF21, 49 | 0x86D3D2D4,0xF1D4E242,0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777, 50 | 0x88085AE6,0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,0x616BFFD3,0x166CCF45, 51 | 0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,0xA7672661,0xD06016F7,0x4969474D,0x3E6E77DB, 52 | 0xAED16A4A,0xD9D65ADC,0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5,0x47B2CF7F,0x30B5FFE9, 53 | 0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,0xCDD70693,0x54DE5729,0x23D967BF, 54 | 0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D, 55 | }, 56 | 57 | { 58 | 0x00000000,0x191B3141,0x32366282,0x2B2D53C3,0x646CC504,0x7D77F445,0x565AA786,0x4F4196C7, 59 | 0xC8D98A08,0xD1C2BB49,0xFAEFE88A,0xE3F4D9CB,0xACB54F0C,0xB5AE7E4D,0x9E832D8E,0x87981CCF, 60 | 0x4AC21251,0x53D92310,0x78F470D3,0x61EF4192,0x2EAED755,0x37B5E614,0x1C98B5D7,0x05838496, 61 | 0x821B9859,0x9B00A918,0xB02DFADB,0xA936CB9A,0xE6775D5D,0xFF6C6C1C,0xD4413FDF,0xCD5A0E9E, 62 | 0x958424A2,0x8C9F15E3,0xA7B24620,0xBEA97761,0xF1E8E1A6,0xE8F3D0E7,0xC3DE8324,0xDAC5B265, 63 | 0x5D5DAEAA,0x44469FEB,0x6F6BCC28,0x7670FD69,0x39316BAE,0x202A5AEF,0x0B07092C,0x121C386D, 64 | 0xDF4636F3,0xC65D07B2,0xED705471,0xF46B6530,0xBB2AF3F7,0xA231C2B6,0x891C9175,0x9007A034, 65 | 0x179FBCFB,0x0E848DBA,0x25A9DE79,0x3CB2EF38,0x73F379FF,0x6AE848BE,0x41C51B7D,0x58DE2A3C, 66 | 0xF0794F05,0xE9627E44,0xC24F2D87,0xDB541CC6,0x94158A01,0x8D0EBB40,0xA623E883,0xBF38D9C2, 67 | 0x38A0C50D,0x21BBF44C,0x0A96A78F,0x138D96CE,0x5CCC0009,0x45D73148,0x6EFA628B,0x77E153CA, 68 | 0xBABB5D54,0xA3A06C15,0x888D3FD6,0x91960E97,0xDED79850,0xC7CCA911,0xECE1FAD2,0xF5FACB93, 69 | 0x7262D75C,0x6B79E61D,0x4054B5DE,0x594F849F,0x160E1258,0x0F152319,0x243870DA,0x3D23419B, 70 | 0x65FD6BA7,0x7CE65AE6,0x57CB0925,0x4ED03864,0x0191AEA3,0x188A9FE2,0x33A7CC21,0x2ABCFD60, 71 | 0xAD24E1AF,0xB43FD0EE,0x9F12832D,0x8609B26C,0xC94824AB,0xD05315EA,0xFB7E4629,0xE2657768, 72 | 0x2F3F79F6,0x362448B7,0x1D091B74,0x04122A35,0x4B53BCF2,0x52488DB3,0x7965DE70,0x607EEF31, 73 | 0xE7E6F3FE,0xFEFDC2BF,0xD5D0917C,0xCCCBA03D,0x838A36FA,0x9A9107BB,0xB1BC5478,0xA8A76539, 74 | 0x3B83984B,0x2298A90A,0x09B5FAC9,0x10AECB88,0x5FEF5D4F,0x46F46C0E,0x6DD93FCD,0x74C20E8C, 75 | 0xF35A1243,0xEA412302,0xC16C70C1,0xD8774180,0x9736D747,0x8E2DE606,0xA500B5C5,0xBC1B8484, 76 | 0x71418A1A,0x685ABB5B,0x4377E898,0x5A6CD9D9,0x152D4F1E,0x0C367E5F,0x271B2D9C,0x3E001CDD, 77 | 0xB9980012,0xA0833153,0x8BAE6290,0x92B553D1,0xDDF4C516,0xC4EFF457,0xEFC2A794,0xF6D996D5, 78 | 0xAE07BCE9,0xB71C8DA8,0x9C31DE6B,0x852AEF2A,0xCA6B79ED,0xD37048AC,0xF85D1B6F,0xE1462A2E, 79 | 0x66DE36E1,0x7FC507A0,0x54E85463,0x4DF36522,0x02B2F3E5,0x1BA9C2A4,0x30849167,0x299FA026, 80 | 0xE4C5AEB8,0xFDDE9FF9,0xD6F3CC3A,0xCFE8FD7B,0x80A96BBC,0x99B25AFD,0xB29F093E,0xAB84387F, 81 | 0x2C1C24B0,0x350715F1,0x1E2A4632,0x07317773,0x4870E1B4,0x516BD0F5,0x7A468336,0x635DB277, 82 | 0xCBFAD74E,0xD2E1E60F,0xF9CCB5CC,0xE0D7848D,0xAF96124A,0xB68D230B,0x9DA070C8,0x84BB4189, 83 | 0x03235D46,0x1A386C07,0x31153FC4,0x280E0E85,0x674F9842,0x7E54A903,0x5579FAC0,0x4C62CB81, 84 | 0x8138C51F,0x9823F45E,0xB30EA79D,0xAA1596DC,0xE554001B,0xFC4F315A,0xD7626299,0xCE7953D8, 85 | 0x49E14F17,0x50FA7E56,0x7BD72D95,0x62CC1CD4,0x2D8D8A13,0x3496BB52,0x1FBBE891,0x06A0D9D0, 86 | 0x5E7EF3EC,0x4765C2AD,0x6C48916E,0x7553A02F,0x3A1236E8,0x230907A9,0x0824546A,0x113F652B, 87 | 0x96A779E4,0x8FBC48A5,0xA4911B66,0xBD8A2A27,0xF2CBBCE0,0xEBD08DA1,0xC0FDDE62,0xD9E6EF23, 88 | 0x14BCE1BD,0x0DA7D0FC,0x268A833F,0x3F91B27E,0x70D024B9,0x69CB15F8,0x42E6463B,0x5BFD777A, 89 | 0xDC656BB5,0xC57E5AF4,0xEE530937,0xF7483876,0xB809AEB1,0xA1129FF0,0x8A3FCC33,0x9324FD72, 90 | }, 91 | 92 | { 93 | 0x00000000,0x01C26A37,0x0384D46E,0x0246BE59,0x0709A8DC,0x06CBC2EB,0x048D7CB2,0x054F1685, 94 | 0x0E1351B8,0x0FD13B8F,0x0D9785D6,0x0C55EFE1,0x091AF964,0x08D89353,0x0A9E2D0A,0x0B5C473D, 95 | 0x1C26A370,0x1DE4C947,0x1FA2771E,0x1E601D29,0x1B2F0BAC,0x1AED619B,0x18ABDFC2,0x1969B5F5, 96 | 0x1235F2C8,0x13F798FF,0x11B126A6,0x10734C91,0x153C5A14,0x14FE3023,0x16B88E7A,0x177AE44D, 97 | 0x384D46E0,0x398F2CD7,0x3BC9928E,0x3A0BF8B9,0x3F44EE3C,0x3E86840B,0x3CC03A52,0x3D025065, 98 | 0x365E1758,0x379C7D6F,0x35DAC336,0x3418A901,0x3157BF84,0x3095D5B3,0x32D36BEA,0x331101DD, 99 | 0x246BE590,0x25A98FA7,0x27EF31FE,0x262D5BC9,0x23624D4C,0x22A0277B,0x20E69922,0x2124F315, 100 | 0x2A78B428,0x2BBADE1F,0x29FC6046,0x283E0A71,0x2D711CF4,0x2CB376C3,0x2EF5C89A,0x2F37A2AD, 101 | 0x709A8DC0,0x7158E7F7,0x731E59AE,0x72DC3399,0x7793251C,0x76514F2B,0x7417F172,0x75D59B45, 102 | 0x7E89DC78,0x7F4BB64F,0x7D0D0816,0x7CCF6221,0x798074A4,0x78421E93,0x7A04A0CA,0x7BC6CAFD, 103 | 0x6CBC2EB0,0x6D7E4487,0x6F38FADE,0x6EFA90E9,0x6BB5866C,0x6A77EC5B,0x68315202,0x69F33835, 104 | 0x62AF7F08,0x636D153F,0x612BAB66,0x60E9C151,0x65A6D7D4,0x6464BDE3,0x662203BA,0x67E0698D, 105 | 0x48D7CB20,0x4915A117,0x4B531F4E,0x4A917579,0x4FDE63FC,0x4E1C09CB,0x4C5AB792,0x4D98DDA5, 106 | 0x46C49A98,0x4706F0AF,0x45404EF6,0x448224C1,0x41CD3244,0x400F5873,0x4249E62A,0x438B8C1D, 107 | 0x54F16850,0x55330267,0x5775BC3E,0x56B7D609,0x53F8C08C,0x523AAABB,0x507C14E2,0x51BE7ED5, 108 | 0x5AE239E8,0x5B2053DF,0x5966ED86,0x58A487B1,0x5DEB9134,0x5C29FB03,0x5E6F455A,0x5FAD2F6D, 109 | 0xE1351B80,0xE0F771B7,0xE2B1CFEE,0xE373A5D9,0xE63CB35C,0xE7FED96B,0xE5B86732,0xE47A0D05, 110 | 0xEF264A38,0xEEE4200F,0xECA29E56,0xED60F461,0xE82FE2E4,0xE9ED88D3,0xEBAB368A,0xEA695CBD, 111 | 0xFD13B8F0,0xFCD1D2C7,0xFE976C9E,0xFF5506A9,0xFA1A102C,0xFBD87A1B,0xF99EC442,0xF85CAE75, 112 | 0xF300E948,0xF2C2837F,0xF0843D26,0xF1465711,0xF4094194,0xF5CB2BA3,0xF78D95FA,0xF64FFFCD, 113 | 0xD9785D60,0xD8BA3757,0xDAFC890E,0xDB3EE339,0xDE71F5BC,0xDFB39F8B,0xDDF521D2,0xDC374BE5, 114 | 0xD76B0CD8,0xD6A966EF,0xD4EFD8B6,0xD52DB281,0xD062A404,0xD1A0CE33,0xD3E6706A,0xD2241A5D, 115 | 0xC55EFE10,0xC49C9427,0xC6DA2A7E,0xC7184049,0xC25756CC,0xC3953CFB,0xC1D382A2,0xC011E895, 116 | 0xCB4DAFA8,0xCA8FC59F,0xC8C97BC6,0xC90B11F1,0xCC440774,0xCD866D43,0xCFC0D31A,0xCE02B92D, 117 | 0x91AF9640,0x906DFC77,0x922B422E,0x93E92819,0x96A63E9C,0x976454AB,0x9522EAF2,0x94E080C5, 118 | 0x9FBCC7F8,0x9E7EADCF,0x9C381396,0x9DFA79A1,0x98B56F24,0x99770513,0x9B31BB4A,0x9AF3D17D, 119 | 0x8D893530,0x8C4B5F07,0x8E0DE15E,0x8FCF8B69,0x8A809DEC,0x8B42F7DB,0x89044982,0x88C623B5, 120 | 0x839A6488,0x82580EBF,0x801EB0E6,0x81DCDAD1,0x8493CC54,0x8551A663,0x8717183A,0x86D5720D, 121 | 0xA9E2D0A0,0xA820BA97,0xAA6604CE,0xABA46EF9,0xAEEB787C,0xAF29124B,0xAD6FAC12,0xACADC625, 122 | 0xA7F18118,0xA633EB2F,0xA4755576,0xA5B73F41,0xA0F829C4,0xA13A43F3,0xA37CFDAA,0xA2BE979D, 123 | 0xB5C473D0,0xB40619E7,0xB640A7BE,0xB782CD89,0xB2CDDB0C,0xB30FB13B,0xB1490F62,0xB08B6555, 124 | 0xBBD72268,0xBA15485F,0xB853F606,0xB9919C31,0xBCDE8AB4,0xBD1CE083,0xBF5A5EDA,0xBE9834ED, 125 | }, 126 | 127 | { 128 | 0x00000000,0xB8BC6765,0xAA09C88B,0x12B5AFEE,0x8F629757,0x37DEF032,0x256B5FDC,0x9DD738B9, 129 | 0xC5B428EF,0x7D084F8A,0x6FBDE064,0xD7018701,0x4AD6BFB8,0xF26AD8DD,0xE0DF7733,0x58631056, 130 | 0x5019579F,0xE8A530FA,0xFA109F14,0x42ACF871,0xDF7BC0C8,0x67C7A7AD,0x75720843,0xCDCE6F26, 131 | 0x95AD7F70,0x2D111815,0x3FA4B7FB,0x8718D09E,0x1ACFE827,0xA2738F42,0xB0C620AC,0x087A47C9, 132 | 0xA032AF3E,0x188EC85B,0x0A3B67B5,0xB28700D0,0x2F503869,0x97EC5F0C,0x8559F0E2,0x3DE59787, 133 | 0x658687D1,0xDD3AE0B4,0xCF8F4F5A,0x7733283F,0xEAE41086,0x525877E3,0x40EDD80D,0xF851BF68, 134 | 0xF02BF8A1,0x48979FC4,0x5A22302A,0xE29E574F,0x7F496FF6,0xC7F50893,0xD540A77D,0x6DFCC018, 135 | 0x359FD04E,0x8D23B72B,0x9F9618C5,0x272A7FA0,0xBAFD4719,0x0241207C,0x10F48F92,0xA848E8F7, 136 | 0x9B14583D,0x23A83F58,0x311D90B6,0x89A1F7D3,0x1476CF6A,0xACCAA80F,0xBE7F07E1,0x06C36084, 137 | 0x5EA070D2,0xE61C17B7,0xF4A9B859,0x4C15DF3C,0xD1C2E785,0x697E80E0,0x7BCB2F0E,0xC377486B, 138 | 0xCB0D0FA2,0x73B168C7,0x6104C729,0xD9B8A04C,0x446F98F5,0xFCD3FF90,0xEE66507E,0x56DA371B, 139 | 0x0EB9274D,0xB6054028,0xA4B0EFC6,0x1C0C88A3,0x81DBB01A,0x3967D77F,0x2BD27891,0x936E1FF4, 140 | 0x3B26F703,0x839A9066,0x912F3F88,0x299358ED,0xB4446054,0x0CF80731,0x1E4DA8DF,0xA6F1CFBA, 141 | 0xFE92DFEC,0x462EB889,0x549B1767,0xEC277002,0x71F048BB,0xC94C2FDE,0xDBF98030,0x6345E755, 142 | 0x6B3FA09C,0xD383C7F9,0xC1366817,0x798A0F72,0xE45D37CB,0x5CE150AE,0x4E54FF40,0xF6E89825, 143 | 0xAE8B8873,0x1637EF16,0x048240F8,0xBC3E279D,0x21E91F24,0x99557841,0x8BE0D7AF,0x335CB0CA, 144 | 0xED59B63B,0x55E5D15E,0x47507EB0,0xFFEC19D5,0x623B216C,0xDA874609,0xC832E9E7,0x708E8E82, 145 | 0x28ED9ED4,0x9051F9B1,0x82E4565F,0x3A58313A,0xA78F0983,0x1F336EE6,0x0D86C108,0xB53AA66D, 146 | 0xBD40E1A4,0x05FC86C1,0x1749292F,0xAFF54E4A,0x322276F3,0x8A9E1196,0x982BBE78,0x2097D91D, 147 | 0x78F4C94B,0xC048AE2E,0xD2FD01C0,0x6A4166A5,0xF7965E1C,0x4F2A3979,0x5D9F9697,0xE523F1F2, 148 | 0x4D6B1905,0xF5D77E60,0xE762D18E,0x5FDEB6EB,0xC2098E52,0x7AB5E937,0x680046D9,0xD0BC21BC, 149 | 0x88DF31EA,0x3063568F,0x22D6F961,0x9A6A9E04,0x07BDA6BD,0xBF01C1D8,0xADB46E36,0x15080953, 150 | 0x1D724E9A,0xA5CE29FF,0xB77B8611,0x0FC7E174,0x9210D9CD,0x2AACBEA8,0x38191146,0x80A57623, 151 | 0xD8C66675,0x607A0110,0x72CFAEFE,0xCA73C99B,0x57A4F122,0xEF189647,0xFDAD39A9,0x45115ECC, 152 | 0x764DEE06,0xCEF18963,0xDC44268D,0x64F841E8,0xF92F7951,0x41931E34,0x5326B1DA,0xEB9AD6BF, 153 | 0xB3F9C6E9,0x0B45A18C,0x19F00E62,0xA14C6907,0x3C9B51BE,0x842736DB,0x96929935,0x2E2EFE50, 154 | 0x2654B999,0x9EE8DEFC,0x8C5D7112,0x34E11677,0xA9362ECE,0x118A49AB,0x033FE645,0xBB838120, 155 | 0xE3E09176,0x5B5CF613,0x49E959FD,0xF1553E98,0x6C820621,0xD43E6144,0xC68BCEAA,0x7E37A9CF, 156 | 0xD67F4138,0x6EC3265D,0x7C7689B3,0xC4CAEED6,0x591DD66F,0xE1A1B10A,0xF3141EE4,0x4BA87981, 157 | 0x13CB69D7,0xAB770EB2,0xB9C2A15C,0x017EC639,0x9CA9FE80,0x241599E5,0x36A0360B,0x8E1C516E, 158 | 0x866616A7,0x3EDA71C2,0x2C6FDE2C,0x94D3B949,0x090481F0,0xB1B8E695,0xA30D497B,0x1BB12E1E, 159 | 0x43D23E48,0xFB6E592D,0xE9DBF6C3,0x516791A6,0xCCB0A91F,0x740CCE7A,0x66B96194,0xDE0506F1, 160 | } 161 | }; 162 | 163 | inline unsigned int crc32_swap(unsigned int); 164 | unsigned int crc32_4bytes(const void *, unsigned int, unsigned int); 165 | 166 | #endif /* !_CRC_32_H */ -------------------------------------------------------------------------------- /source/decompressor.cc: -------------------------------------------------------------------------------- 1 | #include "decompressor.h" 2 | 3 | unsigned int CopyStored(BitReader *bit_reader, unsigned char *out, unsigned int out_offset, unsigned int block_size_max) 4 | { 5 | if (bit_reader->ByteAllign() < 0) 6 | return -1; 7 | 8 | if ((bit_reader->GetInBlock() + 4) > bit_reader->GetInBlockEnd()) 9 | return -1; 10 | 11 | unsigned short stored_length = ((unsigned short)bit_reader->GetInBlock()[0]) | (((unsigned short)bit_reader->GetInBlock()[0]) << 8); 12 | bit_reader->ModifyInBlock(2); 13 | 14 | unsigned short neg_stored_length = ((unsigned short)bit_reader->GetInBlock()[0]) | (((unsigned short)bit_reader->GetInBlock()[1]) << 8); 15 | bit_reader->ModifyInBlock(2); 16 | 17 | if (stored_length != ((~neg_stored_length) & 0xffff)) 18 | return -1; 19 | 20 | if (stored_length > block_size_max) 21 | return -1; 22 | 23 | std::memcpy(out + out_offset, bit_reader->GetInBlock(), stored_length); 24 | bit_reader->ModifyInBlock(stored_length); 25 | 26 | return (unsigned int)stored_length; 27 | } 28 | 29 | unsigned int DecompressBlock(BitReader *bit_reader, int dynamic_block, unsigned char *out, unsigned int out_offset, unsigned int block_size_max) 30 | { 31 | HuffmanDecoder literals_decoder; 32 | HuffmanDecoder offset_decoder; 33 | unsigned int literals_rev_sym_table[kLiteralSyms * 2]; 34 | unsigned int offset_rev_sym_table[kLiteralSyms * 2]; 35 | int i; 36 | 37 | if (dynamic_block) 38 | { 39 | HuffmanDecoder tables_decoder; 40 | unsigned char code_length[kLiteralSyms + kOffsetSyms]; 41 | unsigned int tables_rev_sym_table[kCodeLenSyms * 2]; 42 | 43 | unsigned int literal_syms = bit_reader->GetBits(5); 44 | if (literal_syms == -1) 45 | return -1; 46 | literal_syms += 257; 47 | if (literal_syms > kLiteralSyms) 48 | return -1; 49 | 50 | unsigned int offset_syms = bit_reader->GetBits(5); 51 | if (offset_syms == -1) 52 | return -1; 53 | offset_syms += 1; 54 | if (offset_syms > kOffsetSyms) 55 | return -1; 56 | 57 | unsigned int code_len_syms = bit_reader->GetBits(4); 58 | if (code_len_syms == -1) 59 | return -1; 60 | code_len_syms += 4; 61 | if (code_len_syms > kCodeLenSyms) 62 | return -1; 63 | 64 | if (HuffmanDecoder::ReadRawLengths(kCodeLenBits, code_len_syms, kCodeLenSyms, code_length, bit_reader) < 0) 65 | return -1; 66 | if (tables_decoder.PrepareTable(tables_rev_sym_table, kCodeLenSyms, kCodeLenSyms, code_length) < 0) 67 | return -1; 68 | if (tables_decoder.FinalizeTable(tables_rev_sym_table) < 0) 69 | return -1; 70 | 71 | if (tables_decoder.ReadLength(tables_rev_sym_table, literal_syms + offset_syms, kLiteralSyms + kOffsetSyms, code_length, bit_reader) < 0) 72 | return -1; 73 | if (literals_decoder.PrepareTable(literals_rev_sym_table, literal_syms, kLiteralSyms, code_length) < 0) 74 | return -1; 75 | if (offset_decoder.PrepareTable(offset_rev_sym_table, offset_syms, kOffsetSyms, code_length + literal_syms) < 0) 76 | return -1; 77 | } 78 | else 79 | { 80 | unsigned char fixed_literal_code_len[kLiteralSyms]; 81 | unsigned char fixed_offset_code_len[kOffsetSyms]; 82 | 83 | for (i = 0; i < 144; i++) 84 | fixed_literal_code_len[i] = 8; 85 | for (; i < 256; i++) 86 | fixed_literal_code_len[i] = 9; 87 | for (; i < 280; i++) 88 | fixed_literal_code_len[i] = 7; 89 | for (; i < kLiteralSyms; i++) 90 | fixed_literal_code_len[i] = 8; 91 | 92 | for (i = 0; i < kOffsetSyms; i++) 93 | fixed_offset_code_len[i] = 5; 94 | 95 | if (literals_decoder.PrepareTable(literals_rev_sym_table, kLiteralSyms, kLiteralSyms, fixed_literal_code_len) < 0) 96 | return -1; 97 | if (offset_decoder.PrepareTable(offset_rev_sym_table, kOffsetSyms, kOffsetSyms, fixed_offset_code_len) < 0) 98 | return -1; 99 | } 100 | 101 | for (i = 0; i < kOffsetSyms; i++) 102 | { 103 | unsigned int n = offset_rev_sym_table[i]; 104 | if (n < kOffsetSyms) 105 | { 106 | offset_rev_sym_table[i] = kOffsetCode[n]; 107 | } 108 | } 109 | 110 | for (i = 0; i < kLiteralSyms; i++) 111 | { 112 | unsigned int n = literals_rev_sym_table[i]; 113 | if (n >= kMatchLenSymStart && n < kLiteralSyms) 114 | { 115 | literals_rev_sym_table[i] = kMatchLenCode[n - kMatchLenSymStart]; 116 | } 117 | } 118 | 119 | if (literals_decoder.FinalizeTable(literals_rev_sym_table) < 0) 120 | return -1; 121 | if (offset_decoder.FinalizeTable(offset_rev_sym_table) < 0) 122 | return -1; 123 | 124 | unsigned char *current_out = out + out_offset; 125 | const unsigned char *out_end = current_out + block_size_max; 126 | const unsigned char *out_fast_end = out_end - 15; 127 | 128 | while (1) 129 | { 130 | bit_reader->Refill32(); 131 | 132 | unsigned int literals_code_word = literals_decoder.ReadValue(literals_rev_sym_table, bit_reader); 133 | if (literals_code_word < 256) 134 | { 135 | 136 | if (current_out < out_end) 137 | *current_out++ = literals_code_word; 138 | else 139 | return -1; 140 | } 141 | else 142 | { 143 | if (literals_code_word == kEODMarkerSym) 144 | break; 145 | if (literals_code_word == -1) 146 | return -1; 147 | 148 | unsigned int match_length = bit_reader->GetBits((literals_code_word >> 16) & 15); 149 | if (match_length == -1) 150 | return -1; 151 | 152 | match_length += (literals_code_word & 0x7fff); 153 | 154 | unsigned int offset_code_word = offset_decoder.ReadValue(offset_rev_sym_table, bit_reader); 155 | if (offset_code_word == -1) 156 | return -1; 157 | 158 | unsigned int match_offset = bit_reader->GetBits((offset_code_word >> 16) & 15); 159 | if (match_offset == -1) 160 | return -1; 161 | 162 | match_offset += (offset_code_word & 0x7fff); 163 | 164 | const unsigned char *src = current_out - match_offset; 165 | if (src >= out) 166 | { 167 | if (match_offset >= 16 && (current_out + match_length) <= out_fast_end) 168 | { 169 | const unsigned char *copy_src = src; 170 | unsigned char *copy_dst = current_out; 171 | const unsigned char *copy_end_dst = current_out + match_length; 172 | 173 | do 174 | { 175 | std::memcpy(copy_dst, copy_src, 16); 176 | copy_src += 16; 177 | copy_dst += 16; 178 | } 179 | while (copy_dst < copy_end_dst); 180 | 181 | current_out += match_length; 182 | } 183 | else 184 | { 185 | if ((current_out + match_length) > out_end) 186 | return -1; 187 | 188 | while 189 | (match_length--) { 190 | *current_out++ = *src++; 191 | } 192 | } 193 | } 194 | else 195 | return -1; 196 | } 197 | } 198 | 199 | return (unsigned int)(current_out - (out + out_offset)); 200 | } 201 | 202 | enum ChecksumType { kNone = 0, kGZIP = 1, kZLIB = 2 }; 203 | 204 | /** 205 | * Inflate zlib data 206 | * 207 | * @param compressed_data pointer to start of zlib data 208 | * @param compressed_data_size size of zlib data, in bytes 209 | * @param out pointer to start of decompression buffer 210 | * @param out_size_max maximum size of decompression buffer, in bytes 211 | * @param checksum defines if the decompressor should use a specific checksum 212 | * 213 | * @return number of bytes decompressed, or -1 in case of an error 214 | */ 215 | unsigned int Decompressor::Feed(const void *compressed_data, unsigned int compressed_data_size, unsigned char *out, unsigned int out_size_max, bool checksum) 216 | { 217 | unsigned char *current_compressed_data = (unsigned char *)compressed_data; 218 | unsigned char *end_compressed_data = current_compressed_data + compressed_data_size; 219 | unsigned int final_block; 220 | unsigned int current_out_offset; 221 | unsigned long check_sum = 0; 222 | 223 | ChecksumType checksum_type = ChecksumType::kNone; 224 | BitReader bit_reader; 225 | 226 | if ((current_compressed_data + 2) > end_compressed_data) 227 | return -1; 228 | 229 | if(current_compressed_data[0] == 0x1f && current_compressed_data[1] == 0x8b) 230 | { 231 | current_compressed_data += 2; 232 | if ((current_compressed_data + 8) > end_compressed_data || current_compressed_data[0] != 0x08) 233 | return -1; 234 | 235 | current_compressed_data++; 236 | 237 | unsigned char flags = *current_compressed_data++; 238 | current_compressed_data += 6; 239 | 240 | if (flags & 0x02) 241 | { 242 | if ((current_compressed_data + 2) > end_compressed_data) 243 | return -1; 244 | 245 | current_compressed_data += 2; 246 | } 247 | 248 | if (flags & 0x04) 249 | { 250 | if ((current_compressed_data + 2) > end_compressed_data) 251 | return -1; 252 | 253 | unsigned short extra_field_len = ((unsigned short)current_compressed_data[0]) | (((unsigned short)current_compressed_data[1]) << 8); 254 | current_compressed_data += 2; 255 | 256 | if ((current_compressed_data + extra_field_len) > end_compressed_data) 257 | return -1; 258 | 259 | current_compressed_data += extra_field_len; 260 | } 261 | 262 | if (flags & 0x08) 263 | { 264 | do 265 | { 266 | if (current_compressed_data >= end_compressed_data) 267 | return -1; 268 | 269 | current_compressed_data++; 270 | } 271 | while (current_compressed_data[-1]); 272 | } 273 | 274 | if (flags & 0x10) 275 | { 276 | do 277 | { 278 | if (current_compressed_data >= end_compressed_data) 279 | return -1; 280 | 281 | current_compressed_data++; 282 | } 283 | while (current_compressed_data[-1]); 284 | } 285 | 286 | if (flags & 0x20) 287 | return -1; 288 | 289 | checksum_type = ChecksumType::kGZIP; 290 | } 291 | else if ((current_compressed_data[0] & 0x0f) == 0x08) 292 | { 293 | unsigned char CMF = current_compressed_data[0]; 294 | unsigned char FLG = current_compressed_data[1]; 295 | unsigned short check = FLG | (((unsigned short)CMF) << 8); 296 | 297 | if ((CMF >> 4) <= 7 && (check % 31) == 0) 298 | { 299 | current_compressed_data += 2; 300 | if (FLG & 0x20) 301 | { 302 | if ((current_compressed_data + 4) > end_compressed_data) 303 | return -1; 304 | current_compressed_data += 4; 305 | } 306 | } 307 | 308 | checksum_type = ChecksumType::kZLIB; 309 | } 310 | 311 | if (checksum && checksum_type == ChecksumType::kZLIB) 312 | check_sum = adler32_z(0, nullptr, 0); 313 | 314 | bit_reader.Init(current_compressed_data, end_compressed_data); 315 | current_out_offset = 0; 316 | 317 | do 318 | { 319 | unsigned int block_type; 320 | unsigned int block_result; 321 | 322 | final_block = bit_reader.GetBits(1); 323 | block_type = bit_reader.GetBits(2); 324 | 325 | switch (block_type) 326 | { 327 | case 0: 328 | block_result = CopyStored(&bit_reader, out, current_out_offset, out_size_max - current_out_offset); 329 | break; 330 | 331 | case 1: 332 | block_result = DecompressBlock(&bit_reader, 0, out, current_out_offset, out_size_max - current_out_offset); 333 | break; 334 | 335 | case 2: 336 | block_result = DecompressBlock(&bit_reader, 1, out, current_out_offset, out_size_max - current_out_offset); 337 | break; 338 | 339 | case 3: 340 | return -1; 341 | } 342 | 343 | if (block_result == -1) 344 | return -1; 345 | 346 | if(checksum) 347 | { 348 | switch (checksum_type) 349 | { 350 | case ChecksumType::kGZIP: 351 | check_sum = crc32_4bytes(out + current_out_offset, block_result, check_sum); 352 | break; 353 | 354 | case ChecksumType::kZLIB: 355 | check_sum = adler32_z(check_sum, out + current_out_offset, block_result); 356 | break; 357 | } 358 | } 359 | 360 | current_out_offset += block_result; 361 | } 362 | while (!final_block); 363 | 364 | bit_reader.ByteAllign(); 365 | current_compressed_data = bit_reader.GetInBlock(); 366 | 367 | if (checksum) 368 | { 369 | unsigned int stored_check_sum; 370 | 371 | switch (checksum_type) 372 | { 373 | case ChecksumType::kGZIP: 374 | if ((current_compressed_data + 4) > end_compressed_data) 375 | return -1; 376 | 377 | stored_check_sum = ((unsigned int)current_compressed_data[0]); 378 | stored_check_sum |= ((unsigned int)current_compressed_data[1]) << 8; 379 | stored_check_sum |= ((unsigned int)current_compressed_data[2]) << 16; 380 | stored_check_sum |= ((unsigned int)current_compressed_data[3]) << 24; 381 | 382 | if (stored_check_sum != check_sum) 383 | return -1; 384 | 385 | current_compressed_data += 4; 386 | break; 387 | 388 | case ChecksumType::kZLIB: 389 | if ((current_compressed_data + 4) > end_compressed_data) 390 | return -1; 391 | 392 | stored_check_sum = ((unsigned int)current_compressed_data[0]) << 24; 393 | stored_check_sum |= ((unsigned int)current_compressed_data[1]) << 16; 394 | stored_check_sum |= ((unsigned int)current_compressed_data[2]) << 8; 395 | stored_check_sum |= ((unsigned int)current_compressed_data[3]); 396 | 397 | if (stored_check_sum != check_sum) 398 | return -1; 399 | 400 | current_compressed_data += 4; 401 | break; 402 | } 403 | } 404 | 405 | return current_out_offset; 406 | } -------------------------------------------------------------------------------- /source/decompressor.h: -------------------------------------------------------------------------------- 1 | #ifndef _DECOMPRESSOR_H 2 | #define _DECOMPRESSOR_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "bit_reader.h" 9 | #include "huffman_decoder.h" 10 | #include "adler32.h" 11 | #include "crc32.h" 12 | 13 | #define MATCHLEN_PAIR(__base,__dispbits) ((__base) | ((__dispbits) << 16) | 0x8000) 14 | #define OFFSET_PAIR(__base,__dispbits) ((__base) | ((__dispbits) << 16)) 15 | 16 | /*-- zlib static and dynamic blocks inflater --*/ 17 | constexpr auto kCodeLenBits = 3; 18 | constexpr auto kLiteralSyms = 288; 19 | constexpr auto kEODMarkerSym = 256; 20 | constexpr auto kMatchLenSymStart = 257; 21 | constexpr auto kMatchLenSyms = 29; 22 | constexpr auto kOffsetSyms = 32; 23 | constexpr auto kMinMatchSize = 3; 24 | 25 | constexpr unsigned int kMatchLenCode[kMatchLenSyms] = { 26 | MATCHLEN_PAIR(kMinMatchSize + 0, 0), MATCHLEN_PAIR(kMinMatchSize + 1, 0), MATCHLEN_PAIR(kMinMatchSize + 2, 0), MATCHLEN_PAIR(kMinMatchSize + 3, 0), MATCHLEN_PAIR(kMinMatchSize + 4, 0), 27 | MATCHLEN_PAIR(kMinMatchSize + 5, 0), MATCHLEN_PAIR(kMinMatchSize + 6, 0), MATCHLEN_PAIR(kMinMatchSize + 7, 0), MATCHLEN_PAIR(kMinMatchSize + 8, 1), MATCHLEN_PAIR(kMinMatchSize + 10, 1), 28 | MATCHLEN_PAIR(kMinMatchSize + 12, 1), MATCHLEN_PAIR(kMinMatchSize + 14, 1), MATCHLEN_PAIR(kMinMatchSize + 16, 2), MATCHLEN_PAIR(kMinMatchSize + 20, 2), MATCHLEN_PAIR(kMinMatchSize + 24, 2), 29 | MATCHLEN_PAIR(kMinMatchSize + 28, 2), MATCHLEN_PAIR(kMinMatchSize + 32, 3), MATCHLEN_PAIR(kMinMatchSize + 40, 3), MATCHLEN_PAIR(kMinMatchSize + 48, 3), MATCHLEN_PAIR(kMinMatchSize + 56, 3), 30 | MATCHLEN_PAIR(kMinMatchSize + 64, 4), MATCHLEN_PAIR(kMinMatchSize + 80, 4), MATCHLEN_PAIR(kMinMatchSize + 96, 4), MATCHLEN_PAIR(kMinMatchSize + 112, 4), MATCHLEN_PAIR(kMinMatchSize + 128, 5), 31 | MATCHLEN_PAIR(kMinMatchSize + 160, 5), MATCHLEN_PAIR(kMinMatchSize + 192, 5), MATCHLEN_PAIR(kMinMatchSize + 224, 5), MATCHLEN_PAIR(kMinMatchSize + 255, 0), 32 | }; 33 | 34 | constexpr unsigned int kOffsetCode[kOffsetSyms] = { 35 | OFFSET_PAIR(1, 0), OFFSET_PAIR(2, 0), OFFSET_PAIR(3, 0), OFFSET_PAIR(4, 0), OFFSET_PAIR(5, 1), OFFSET_PAIR(7, 1), OFFSET_PAIR(9, 2), OFFSET_PAIR(13, 2), OFFSET_PAIR(17, 3), OFFSET_PAIR(25, 3), 36 | OFFSET_PAIR(33, 4), OFFSET_PAIR(49, 4), OFFSET_PAIR(65, 5), OFFSET_PAIR(97, 5), OFFSET_PAIR(129, 6), OFFSET_PAIR(193, 6), OFFSET_PAIR(257, 7), OFFSET_PAIR(385, 7), OFFSET_PAIR(513, 8), OFFSET_PAIR(769, 8), 37 | OFFSET_PAIR(1025, 9), OFFSET_PAIR(1537, 9), OFFSET_PAIR(2049, 10), OFFSET_PAIR(3073, 10), OFFSET_PAIR(4097, 11), OFFSET_PAIR(6145, 11), OFFSET_PAIR(8193, 12), OFFSET_PAIR(12289, 12), OFFSET_PAIR(16385, 13), OFFSET_PAIR(24577, 13), 38 | }; 39 | 40 | class Decompressor 41 | { 42 | public: 43 | Decompressor() {}; 44 | ~Decompressor() = default; 45 | 46 | unsigned int Feed(const void *, unsigned int, unsigned char *, unsigned int, bool); 47 | }; 48 | 49 | #endif /* !_DECOMPRESSOR_H */ 50 | -------------------------------------------------------------------------------- /source/huffman_decoder.cc: -------------------------------------------------------------------------------- 1 | #include "huffman_decoder.h" 2 | 3 | /** 4 | * Prepare huffman tables 5 | * 6 | * @param rev_symbol_table array of 2 * symbols entries for storing the reverse lookup table 7 | * @param code_length codeword lengths table 8 | * 9 | * @return 0 for success, -1 for failure 10 | */ 11 | int HuffmanDecoder::PrepareTable(unsigned int *rev_symbol_table, const int read_symbols, const int symbols, unsigned char *code_length) 12 | { 13 | int num_symbols_per_len[16]; 14 | int i; 15 | 16 | if (read_symbols < 0 || read_symbols > kMaxSymbols || symbols < 0 || symbols > kMaxSymbols || read_symbols > symbols) 17 | return -1; 18 | this->symbols_ = symbols; 19 | 20 | 21 | for (i = 0; i < 16; i++) 22 | num_symbols_per_len[i] = 0; 23 | 24 | for (i = 0; i < read_symbols; i++) 25 | { 26 | if (code_length[i] >= 16) return -1; 27 | num_symbols_per_len[code_length[i]]++; 28 | } 29 | 30 | this->starting_pos_[0] = 0; 31 | this->num_sorted_ = 0; 32 | for (i = 1; i < 16; i++) 33 | { 34 | this->starting_pos_[i] = this->num_sorted_; 35 | this->num_sorted_ += num_symbols_per_len[i]; 36 | } 37 | 38 | for (i = 0; i < symbols; i++) 39 | rev_symbol_table[i] = -1; 40 | 41 | for (i = 0; i < read_symbols; i++) 42 | { 43 | if (code_length[i]) 44 | rev_symbol_table[this->starting_pos_[code_length[i]]++] = i; 45 | } 46 | 47 | return 0; 48 | } 49 | 50 | /** 51 | * Finalize huffman codewords for decoding 52 | * 53 | * @param rev_symbol_table array of 2 * symbols entries that contains the reverse lookup table 54 | * 55 | * @return 0 for success, -1 for failure 56 | */ 57 | int HuffmanDecoder::FinalizeTable(unsigned int *rev_symbol_table) 58 | { 59 | const int symbols = this->symbols_; 60 | unsigned int canonical_code_word = 0; 61 | unsigned int *rev_code_length_table = rev_symbol_table + symbols; 62 | int canonical_length = 1; 63 | int i; 64 | 65 | for (i = 0; i < (1 << kFastSymbolBits); i++) 66 | this->fast_symbol_[i] = 0; 67 | for (i = 0; i < 16; i++) 68 | this->start_index_[i] = 0; 69 | 70 | i = 0; 71 | while (i < this->num_sorted_) 72 | { 73 | if (canonical_length >= 16) return -1; 74 | this->start_index_[canonical_length] = i - canonical_code_word; 75 | 76 | while (i < this->starting_pos_[canonical_length]) 77 | { 78 | 79 | if (i >= symbols) return -1; 80 | rev_code_length_table[i] = canonical_length; 81 | 82 | if (canonical_code_word >= (1U << canonical_length)) return -1; 83 | 84 | if (canonical_length <= kFastSymbolBits) 85 | { 86 | unsigned int rev_word; 87 | 88 | /* Get upside down codeword (branchless method by Eric Biggers) */ 89 | rev_word = ((canonical_code_word & 0x5555) << 1) | ((canonical_code_word & 0xaaaa) >> 1); 90 | rev_word = ((rev_word & 0x3333) << 2) | ((rev_word & 0xcccc) >> 2); 91 | rev_word = ((rev_word & 0x0f0f) << 4) | ((rev_word & 0xf0f0) >> 4); 92 | rev_word = ((rev_word & 0x00ff) << 8) | ((rev_word & 0xff00) >> 8); 93 | rev_word = rev_word >> (16 - canonical_length); 94 | 95 | int slots = 1 << (kFastSymbolBits - canonical_length); 96 | while (slots) 97 | { 98 | this->fast_symbol_[rev_word] = (rev_symbol_table[i] & 0xffffff) | (canonical_length << 24); 99 | rev_word += (1 << canonical_length); 100 | slots--; 101 | } 102 | } 103 | 104 | i++; 105 | canonical_code_word++; 106 | } 107 | canonical_length++; 108 | canonical_code_word <<= 1; 109 | } 110 | 111 | while (i < symbols) 112 | { 113 | rev_symbol_table[i] = -1; 114 | rev_code_length_table[i++] = 0; 115 | } 116 | 117 | return 0; 118 | } 119 | 120 | /** 121 | * Read fixed bit size code lengths 122 | * 123 | * @param len_bits number of bits per code length 124 | * @param read_symbols number of symbols actually read 125 | * @param symbols number of symbols to build codes for 126 | * @param code_length output code lengths table 127 | * @param bit_reader bit reader context 128 | * 129 | * @return 0 for success, -1 for failure 130 | */ 131 | int HuffmanDecoder::ReadRawLengths(const int len_bits, const int read_symbols, const int symbols, unsigned char *code_length, BitReader *bit_reader) 132 | { 133 | const unsigned char code_len_syms[kCodeLenSyms] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; 134 | int i; 135 | 136 | if (read_symbols < 0 || read_symbols > kMaxSymbols || symbols < 0 || symbols > kMaxSymbols || read_symbols > symbols) 137 | return -1; 138 | 139 | i = 0; 140 | while (i < read_symbols) 141 | { 142 | unsigned int length = bit_reader->GetBits(len_bits); 143 | if (length == -1) 144 | return -1; 145 | 146 | code_length[code_len_syms[i++]] = length; 147 | } 148 | 149 | while (i < symbols) 150 | { 151 | code_length[code_len_syms[i++]] = 0; 152 | } 153 | 154 | return 0; 155 | } 156 | 157 | /** 158 | * Read huffman-encoded code lengths 159 | * 160 | * @param tables_rev_symbol_table reverse lookup table for code lengths 161 | * @param read_symbols number of symbols actually read 162 | * @param symbols number of symbols to build codes for 163 | * @param code_length output code lengths table 164 | * @param bit_reader bit reader context 165 | * 166 | * @return 0 for success, -1 for failure 167 | */ 168 | int HuffmanDecoder::ReadLength(const unsigned int *tables_rev_symbol_table, const int read_symbols, const int symbols, unsigned char *code_length, BitReader *bit_reader) 169 | { 170 | int i; 171 | if (read_symbols < 0 || symbols < 0 || read_symbols > symbols) 172 | return -1; 173 | 174 | i = 0; 175 | unsigned int previous_length = 0; 176 | 177 | while (i < read_symbols) 178 | { 179 | unsigned int length = this->ReadValue(tables_rev_symbol_table, bit_reader); 180 | if (length == -1) 181 | return -1; 182 | 183 | if (length < 16) 184 | { 185 | previous_length = length; 186 | code_length[i++] = previous_length; 187 | } 188 | else 189 | { 190 | unsigned int run_length = 0; 191 | 192 | if (length == 16) 193 | { 194 | int extra_run_length = bit_reader->GetBits(2); 195 | if (extra_run_length == -1) 196 | return -1; 197 | run_length = 3 + extra_run_length; 198 | } 199 | else if (length == 17) 200 | { 201 | int extra_run_length = bit_reader->GetBits(3); 202 | if (extra_run_length == -1) 203 | return -1; 204 | previous_length = 0; 205 | run_length = 3 + extra_run_length; 206 | } 207 | else if (length == 18) 208 | { 209 | int extra_run_length = bit_reader->GetBits(7); 210 | if (extra_run_length == -1) 211 | return -1; 212 | previous_length = 0; 213 | run_length = 11 + extra_run_length; 214 | } 215 | 216 | while (run_length && i < read_symbols) 217 | { 218 | code_length[i++] = previous_length; 219 | run_length--; 220 | } 221 | } 222 | } 223 | 224 | while (i < symbols) 225 | code_length[i++] = 0; 226 | return 0; 227 | } 228 | 229 | /** 230 | * Decode next symbol 231 | * 232 | * @param rev_symbol_table reverse lookup table 233 | * @param bit_reader bit reader context 234 | * 235 | * @return symbol, or -1 for error 236 | */ 237 | unsigned int HuffmanDecoder::ReadValue(const unsigned int *rev_symbol_table, BitReader *bit_reader) 238 | { 239 | unsigned int stream = bit_reader->PeekBits(); 240 | unsigned int fast_sym_bits = this->fast_symbol_[stream & ((1 << kFastSymbolBits) - 1)]; 241 | if (fast_sym_bits) 242 | { 243 | bit_reader->ConsumeBits(fast_sym_bits >> 24); 244 | return fast_sym_bits & 0xffffff; 245 | } 246 | const unsigned int *rev_code_length_table = rev_symbol_table + this->symbols_; 247 | unsigned int code_word = 0; 248 | int bits = 1; 249 | 250 | do 251 | { 252 | code_word |= (stream & 1); 253 | 254 | unsigned int table_index = this->start_index_[bits] + code_word; 255 | if (table_index < this->symbols_) 256 | { 257 | if (bits == rev_code_length_table[table_index]) 258 | { 259 | bit_reader->ConsumeBits(bits); 260 | return rev_symbol_table[table_index]; 261 | } 262 | } 263 | code_word <<= 1; 264 | stream >>= 1; 265 | bits++; 266 | } while (bits < 16); 267 | 268 | return -1; 269 | } -------------------------------------------------------------------------------- /source/huffman_decoder.h: -------------------------------------------------------------------------------- 1 | #ifndef _HUFFMAN_DECODER_H 2 | #define _HUFFMAN_DECODER_H 3 | 4 | #include "bit_reader.h" 5 | 6 | constexpr auto kMaxSymbols = 288; 7 | constexpr auto kCodeLenSyms = 19; 8 | constexpr auto kFastSymbolBits = 10; 9 | 10 | class HuffmanDecoder 11 | { 12 | public: 13 | HuffmanDecoder() {}; 14 | ~HuffmanDecoder() = default; 15 | 16 | int PrepareTable(unsigned int *, const int, const int, unsigned char *); 17 | int FinalizeTable(unsigned int *); 18 | static int ReadRawLengths(const int, const int, const int, unsigned char *, BitReader *); 19 | int ReadLength(const unsigned int *, const int, const int, unsigned char *, BitReader *); 20 | 21 | unsigned int ReadValue(const unsigned int *, BitReader *); 22 | 23 | private: 24 | unsigned int fast_symbol_[1 << kFastSymbolBits]; 25 | unsigned int start_index_[16]; 26 | unsigned int symbols_; 27 | int num_sorted_; 28 | int starting_pos_[16]; 29 | }; 30 | 31 | #endif /* !_HUFFMAN_DECODER_H */ 32 | --------------------------------------------------------------------------------