From 17353a26a293eba02c01f12b6201679b9b5d51ee Mon Sep 17 00:00:00 2001 From: Matthew Dean Date: Tue, 30 Jan 2024 13:34:43 -0800 Subject: [PATCH 1/3] Add Lua port Port started by Defaultio and finished by me. Based on the Python port. Table indices incremented by 1 to account for Lua's 1-based indexing. --- lua/LibDeflate.lua | 3605 ++++++++++++++++++++++++++++++++++++++++ lua/README.md | 58 + lua/base64.lua | 201 +++ lua/examples/hello.lua | 9 + lua/mixbox.lua | 332 ++++ 5 files changed, 4205 insertions(+) create mode 100644 lua/LibDeflate.lua create mode 100644 lua/README.md create mode 100644 lua/base64.lua create mode 100644 lua/examples/hello.lua create mode 100644 lua/mixbox.lua diff --git a/lua/LibDeflate.lua b/lua/LibDeflate.lua new file mode 100644 index 0000000..02b36ab --- /dev/null +++ b/lua/LibDeflate.lua @@ -0,0 +1,3605 @@ +--[[-- +LibDeflate 1.0.2-release
+Pure Lua compressor and decompressor with high compression ratio using +DEFLATE/zlib format. + +@file LibDeflate.lua +@author Haoqian He (Github: SafeteeWoW; World of Warcraft: Safetyy-Illidan(US)) +@copyright LibDeflate <2018-2021> Haoqian He +@license zlib License + +This library is implemented according to the following specifications.
+Report a bug if LibDeflate is not fully compliant with those specs.
+Both compressors and decompressors have been implemented in the library.
+1. RFC1950: DEFLATE Compressed Data Format Specification version 1.3
+https://tools.ietf.org/html/rfc1951
+2. RFC1951: ZLIB Compressed Data Format Specification version 3.3
+https://tools.ietf.org/html/rfc1950
+ +This library requires Lua 5.1/5.2/5.3/5.4 interpreter or LuaJIT v2.0+.
+This library does not have any dependencies.
+
+This file "LibDeflate.lua" is the only source file of +the library.
+Submit suggestions or report bugs to +https://github.com/safeteeWow/LibDeflate/issues +]] --[[ +zlib License + +(C) 2018-2021 Haoqian He + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +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: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. + +License History: +1. GNU General Public License Version 3 in v1.0.0 and earlier versions. +2. GNU Lesser General Public License Version 3 in v1.0.1 +3. the zlib License since v1.0.2 + +Credits and Disclaimer: +This library rewrites the code from the algorithm +and the ideas of the following projects, +and uses their code to help to test the correctness of this library, +but their code is not included directly in the library itself. +Their original licenses shall be comply when used. + +1. zlib, by Jean-loup Gailly (compression) and Mark Adler (decompression). + http://www.zlib.net/ + Licensed under zlib License. http://www.zlib.net/zlib_license.html + For the compression algorithm. +2. puff, by Mark Adler. https://github.com/madler/zlib/tree/master/contrib/puff + Licensed under zlib License. http://www.zlib.net/zlib_license.html + For the decompression algorithm. +3. LibCompress, by jjsheets and Galmok of European Stormrage (Horde) + https://www.wowace.com/projects/libcompress + Licensed under GPLv2. + https://www.gnu.org/licenses/old-licenses/gpl-2.0.html + For the code to create customized codec. +4. WeakAuras2, + https://github.com/WeakAuras/WeakAuras2 + Licensed under GPLv2. + For the 6bit encoding and decoding. +]] --[[ + Curseforge auto-packaging replacements: + + Project Date: @project-date-iso@ + Project Hash: @project-hash@ + Project Version: @project-version@ +--]] local LibDeflate + +do + -- Semantic version. all lowercase. + -- Suffix can be alpha1, alpha2, beta1, beta2, rc1, rc2, etc. + -- NOTE: Two version numbers needs to modify. + -- 1. On the top of LibDeflate.lua + -- 2. _VERSION + -- 3. _MINOR + + -- version to store the official version of LibDeflate + local _VERSION = "1.0.2-release" + + -- When MAJOR is changed, I should name it as LibDeflate2 + local _MAJOR = "LibDeflate" + + -- Update this whenever a new version, for LibStub version registration. + -- 0 : v0.x + -- 1 : v1.0.0 + -- 2 : v1.0.1 + -- 3 : v1.0.2 + local _MINOR = 3 + + local _COPYRIGHT = "LibDeflate " .. _VERSION .. + " Copyright (C) 2018-2021 Haoqian He." .. + " Licensed under the zlib License" + + -- Register in the World of Warcraft library "LibStub" if detected. + if LibStub then + local lib, minor = LibStub:GetLibrary(_MAJOR, true) + if lib and minor and minor >= _MINOR then -- No need to update. + return lib + else -- Update or first time register + LibDeflate = LibStub:NewLibrary(_MAJOR, _MINOR) + -- NOTE: It is important that new version has implemented + -- all exported APIs and tables in the old version, + -- so the old library is fully garbage collected, + -- and we 100% ensure the backward compatibility. + end + else -- "LibStub" is not detected. + LibDeflate = {} + end + + LibDeflate._VERSION = _VERSION + LibDeflate._MAJOR = _MAJOR + LibDeflate._MINOR = _MINOR + LibDeflate._COPYRIGHT = _COPYRIGHT +end + +-- localize Lua api for faster access. +local assert = assert +local error = error +local pairs = pairs +local string_byte = string.byte +local string_char = string.char +local string_find = string.find +local string_gsub = string.gsub +local string_sub = string.sub +local table_concat = table.concat +local table_sort = table.sort +local tostring = tostring +local type = type + +-- Converts i to 2^i, (0<=i<=32) +-- This is used to implement bit left shift and bit right shift. +-- "x >> y" in C: "(x-x%_pow2[y])/_pow2[y]" in Lua +-- "x << y" in C: "x*_pow2[y]" in Lua +local _pow2 = {} + +-- Converts any byte to a character, (0<=byte<=255) +local _byte_to_char = {} + +-- _reverseBitsTbl[len][val] stores the bit reverse of +-- the number with bit length "len" and value "val" +-- For example, decimal number 6 with bits length 5 is binary 00110 +-- It's reverse is binary 01100, +-- which is decimal 12 and 12 == _reverseBitsTbl[5][6] +-- 1<=len<=9, 0<=val<=2^len-1 +-- The reason for 1<=len<=9 is that the max of min bitlen of huffman code +-- of a huffman alphabet is 9? +local _reverse_bits_tbl = {} + +-- Convert a LZ77 length (3<=len<=258) to +-- a deflate literal/LZ77_length code (257<=code<=285) +local _length_to_deflate_code = {} + +-- convert a LZ77 length (3<=len<=258) to +-- a deflate literal/LZ77_length code extra bits. +local _length_to_deflate_extra_bits = {} + +-- Convert a LZ77 length (3<=len<=258) to +-- a deflate literal/LZ77_length code extra bit length. +local _length_to_deflate_extra_bitlen = {} + +-- Convert a small LZ77 distance (1<=dist<=256) to a deflate code. +local _dist256_to_deflate_code = {} + +-- Convert a small LZ77 distance (1<=dist<=256) to +-- a deflate distance code extra bits. +local _dist256_to_deflate_extra_bits = {} + +-- Convert a small LZ77 distance (1<=dist<=256) to +-- a deflate distance code extra bit length. +local _dist256_to_deflate_extra_bitlen = {} + +-- Convert a literal/LZ77_length deflate code to LZ77 base length +-- The key of the table is (code - 256), 257<=code<=285 +local _literal_deflate_code_to_base_len = + { + 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 + } + +-- Convert a literal/LZ77_length deflate code to base LZ77 length extra bits +-- The key of the table is (code - 256), 257<=code<=285 +local _literal_deflate_code_to_extra_bitlen = + { + 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 + } + +-- Convert a distance deflate code to base LZ77 distance. (0<=code<=29) +local _dist_deflate_code_to_base_dist = { + [0] = 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 +} + +-- Convert a distance deflate code to LZ77 bits length. (0<=code<=29) +local _dist_deflate_code_to_extra_bitlen = + { + [0] = 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 + } + +-- The code order of the first huffman header in the dynamic deflate block. +-- See the page 12 of RFC1951 +local _rle_codes_huffman_bitlen_order = { + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 +} + +-- The following tables are used by fixed deflate block. +-- The value of these tables are assigned at the bottom of the source. + +-- The huffman code of the literal/LZ77_length deflate codes, +-- in fixed deflate block. +local _fix_block_literal_huffman_code + +-- Convert huffman code of the literal/LZ77_length to deflate codes, +-- in fixed deflate block. +local _fix_block_literal_huffman_to_deflate_code + +-- The bit length of the huffman code of literal/LZ77_length deflate codes, +-- in fixed deflate block. +local _fix_block_literal_huffman_bitlen + +-- The count of each bit length of the literal/LZ77_length deflate codes, +-- in fixed deflate block. +local _fix_block_literal_huffman_bitlen_count + +-- The huffman code of the distance deflate codes, +-- in fixed deflate block. +local _fix_block_dist_huffman_code + +-- Convert huffman code of the distance to deflate codes, +-- in fixed deflate block. +local _fix_block_dist_huffman_to_deflate_code + +-- The bit length of the huffman code of the distance deflate codes, +-- in fixed deflate block. +local _fix_block_dist_huffman_bitlen + +-- The count of each bit length of the huffman code of +-- the distance deflate codes, +-- in fixed deflate block. +local _fix_block_dist_huffman_bitlen_count + +for i = 0, 255 do _byte_to_char[i] = string_char(i) end + +do + local pow = 1 + for i = 0, 32 do + _pow2[i] = pow + pow = pow * 2 + end +end + +for i = 1, 9 do + _reverse_bits_tbl[i] = {} + for j = 0, _pow2[i + 1] - 1 do + local reverse = 0 + local value = j + for _ = 1, i do + -- The following line is equivalent to "res | (code %2)" in C. + reverse = reverse - reverse % 2 + + (((reverse % 2 == 1) or (value % 2) == 1) and 1 or 0) + value = (value - value % 2) / 2 + reverse = reverse * 2 + end + _reverse_bits_tbl[i][j] = (reverse - reverse % 2) / 2 + end +end + +-- The source code is written according to the pattern in the numbers +-- in RFC1951 Page10. +do + local a = 18 + local b = 16 + local c = 265 + local bitlen = 1 + for len = 3, 258 do + if len <= 10 then + _length_to_deflate_code[len] = len + 254 + _length_to_deflate_extra_bitlen[len] = 0 + elseif len == 258 then + _length_to_deflate_code[len] = 285 + _length_to_deflate_extra_bitlen[len] = 0 + else + if len > a then + a = a + b + b = b * 2 + c = c + 4 + bitlen = bitlen + 1 + end + local t = len - a - 1 + b / 2 + _length_to_deflate_code[len] = (t - (t % (b / 8))) / (b / 8) + c + _length_to_deflate_extra_bitlen[len] = bitlen + _length_to_deflate_extra_bits[len] = t % (b / 8) + end + end +end + +-- The source code is written according to the pattern in the numbers +-- in RFC1951 Page11. +do + _dist256_to_deflate_code[1] = 0 + _dist256_to_deflate_code[2] = 1 + _dist256_to_deflate_extra_bitlen[1] = 0 + _dist256_to_deflate_extra_bitlen[2] = 0 + + local a = 3 + local b = 4 + local code = 2 + local bitlen = 0 + for dist = 3, 256 do + if dist > b then + a = a * 2 + b = b * 2 + code = code + 2 + bitlen = bitlen + 1 + end + _dist256_to_deflate_code[dist] = (dist <= a) and code or (code + 1) + _dist256_to_deflate_extra_bitlen[dist] = (bitlen < 0) and 0 or bitlen + if b >= 8 then + _dist256_to_deflate_extra_bits[dist] = (dist - b / 2 - 1) % (b / 4) + end + end +end + +--- Calculate the Adler-32 checksum of the string.
+-- See RFC1950 Page 9 https://tools.ietf.org/html/rfc1950 for the +-- definition of Adler-32 checksum. +-- @param str [string] the input string to calcuate its Adler-32 checksum. +-- @return [integer] The Adler-32 checksum, which is greater or equal to 0, +-- and less than 2^32 (4294967296). +function LibDeflate:Adler32(str) + -- This function is loop unrolled by better performance. + -- + -- Here is the minimum code: + -- + -- local a = 1 + -- local b = 0 + -- for i=1, #str do + -- local s = string.byte(str, i, i) + -- a = (a+s)%65521 + -- b = (b+a)%65521 + -- end + -- return b*65536+a + if type(str) ~= "string" then + error(("Usage: LibDeflate:Adler32(str):" .. + " 'str' - string expected got '%s'."):format(type(str)), 2) + end + local strlen = #str + + local i = 1 + local a = 1 + local b = 0 + while i <= strlen - 15 do + local x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16 = + string_byte(str, i, i + 15) + b = + (b + 16 * a + 16 * x1 + 15 * x2 + 14 * x3 + 13 * x4 + 12 * x5 + 11 * x6 + + 10 * x7 + 9 * x8 + 8 * x9 + 7 * x10 + 6 * x11 + 5 * x12 + 4 * x13 + 3 * + x14 + 2 * x15 + x16) % 65521 + a = + (a + x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + x12 + x13 + + x14 + x15 + x16) % 65521 + i = i + 16 + end + while (i <= strlen) do + local x = string_byte(str, i, i) + a = (a + x) % 65521 + b = (b + a) % 65521 + i = i + 1 + end + return (b * 65536 + a) % 4294967296 +end + +-- Compare adler32 checksum. +-- adler32 should be compared with a mod to avoid sign problem +-- 4072834167 (unsigned) is the same adler32 as -222133129 +local function IsEqualAdler32(actual, expected) + return (actual % 4294967296) == (expected % 4294967296) +end + +--- Create a preset dictionary. +-- +-- This function is not fast, and the memory consumption of the produced +-- dictionary is about 50 times of the input string. Therefore, it is suggestted +-- to run this function only once in your program. +-- +-- It is very important to know that if you do use a preset dictionary, +-- compressors and decompressors MUST USE THE SAME dictionary. That is, +-- dictionary must be created using the same string. If you update your program +-- with a new dictionary, people with the old version won't be able to transmit +-- data with people with the new version. Therefore, changing the dictionary +-- must be very careful. +-- +-- The parameters "strlen" and "adler32" add a layer of verification to ensure +-- the parameter "str" is not modified unintentionally during the program +-- development. +-- +-- @usage local dict_str = "1234567890" +-- +-- -- print(dict_str:len(), LibDeflate:Adler32(dict_str)) +-- -- Hardcode the print result below to verify it to avoid acciently +-- -- modification of 'str' during the program development. +-- -- string length: 10, Adler-32: 187433486, +-- -- Don't calculate string length and its Adler-32 at run-time. +-- +-- local dict = LibDeflate:CreateDictionary(dict_str, 10, 187433486) +-- +-- @param str [string] The string used as the preset dictionary.
+-- You should put stuffs that frequently appears in the dictionary +-- string and preferablely put more frequently appeared stuffs toward the end +-- of the string.
+-- Empty string and string longer than 32768 bytes are not allowed. +-- @param strlen [integer] The length of 'str'. Please pass in this parameter +-- as a hardcoded constant, in order to verify the content of 'str'. The value +-- of this parameter should be known before your program runs. +-- @param adler32 [integer] The Adler-32 checksum of 'str'. Please pass in this +-- parameter as a hardcoded constant, in order to verify the content of 'str'. +-- The value of this parameter should be known before your program runs. +-- @return [table] The dictionary used for preset dictionary compression and +-- decompression. +-- @raise error if 'strlen' does not match the length of 'str', +-- or if 'adler32' does not match the Adler-32 checksum of 'str'. +function LibDeflate:CreateDictionary(str, strlen, adler32) + if type(str) ~= "string" then + error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):" .. + " 'str' - string expected got '%s'."):format(type(str)), 2) + end + if type(strlen) ~= "number" then + error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):" .. + " 'strlen' - number expected got '%s'."):format(type(strlen)), 2) + end + if type(adler32) ~= "number" then + error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):" .. + " 'adler32' - number expected got '%s'."):format(type(adler32)), 2) + end + if strlen ~= #str then + error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):" .. + " 'strlen' does not match the actual length of 'str'." .. + " 'strlen': %u, '#str': %u ." .. + " Please check if 'str' is modified unintentionally."):format( + strlen, #str)) + end + if strlen == 0 then + error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):" .. + " 'str' - Empty string is not allowed."), 2) + end + if strlen > 32768 then + error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):" .. + " 'str' - string longer than 32768 bytes is not allowed." .. + " Got %d bytes."):format(strlen), 2) + end + local actual_adler32 = self:Adler32(str) + if not IsEqualAdler32(adler32, actual_adler32) then + error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):" .. + " 'adler32' does not match the actual adler32 of 'str'." .. + " 'adler32': %u, 'Adler32(str)': %u ." .. + " Please check if 'str' is modified unintentionally."):format( + adler32, actual_adler32)) + end + + local dictionary = {} + dictionary.adler32 = adler32 + dictionary.hash_tables = {} + dictionary.string_table = {} + dictionary.strlen = strlen + local string_table = dictionary.string_table + local hash_tables = dictionary.hash_tables + string_table[1] = string_byte(str, 1, 1) + string_table[2] = string_byte(str, 2, 2) + if strlen >= 3 then + local i = 1 + local hash = string_table[1] * 256 + string_table[2] + while i <= strlen - 2 - 3 do + local x1, x2, x3, x4 = string_byte(str, i + 2, i + 5) + string_table[i + 2] = x1 + string_table[i + 3] = x2 + string_table[i + 4] = x3 + string_table[i + 5] = x4 + hash = (hash * 256 + x1) % 16777216 + local t = hash_tables[hash] + if not t then + t = {}; + hash_tables[hash] = t + end + t[#t + 1] = i - strlen + i = i + 1 + hash = (hash * 256 + x2) % 16777216 + t = hash_tables[hash] + if not t then + t = {}; + hash_tables[hash] = t + end + t[#t + 1] = i - strlen + i = i + 1 + hash = (hash * 256 + x3) % 16777216 + t = hash_tables[hash] + if not t then + t = {}; + hash_tables[hash] = t + end + t[#t + 1] = i - strlen + i = i + 1 + hash = (hash * 256 + x4) % 16777216 + t = hash_tables[hash] + if not t then + t = {}; + hash_tables[hash] = t + end + t[#t + 1] = i - strlen + i = i + 1 + end + while i <= strlen - 2 do + local x = string_byte(str, i + 2) + string_table[i + 2] = x + hash = (hash * 256 + x) % 16777216 + local t = hash_tables[hash] + if not t then + t = {}; + hash_tables[hash] = t + end + t[#t + 1] = i - strlen + i = i + 1 + end + end + return dictionary +end + +-- Check if the dictionary is valid. +-- @param dictionary The preset dictionary for compression and decompression. +-- @return true if valid, false if not valid. +-- @return if not valid, the error message. +local function IsValidDictionary(dictionary) + if type(dictionary) ~= "table" then + return false, + ("'dictionary' - table expected got '%s'."):format(type(dictionary)) + end + if type(dictionary.adler32) ~= "number" or type(dictionary.string_table) ~= + "table" or type(dictionary.strlen) ~= "number" or dictionary.strlen <= 0 or + dictionary.strlen > 32768 or dictionary.strlen ~= #dictionary.string_table or + type(dictionary.hash_tables) ~= "table" then + return false, + ("'dictionary' - corrupted dictionary."):format(type(dictionary)) + end + return true, "" +end + +--[[ + key of the configuration table is the compression level, + and its value stores the compression setting. + These numbers come from zlib source code. + + Higher compression level usually means better compression. + (Because LibDeflate uses a simplified version of zlib algorithm, + there is no guarantee that higher compression level does not create + bigger file than lower level, but I can say it's 99% likely) + + Be careful with the high compression level. This is a pure lua + implementation compressor/decompressor, which is significant slower than + a C/C++ equivalant compressor/decompressor. Very high compression level + costs significant more CPU time, and usually compression size won't be + significant smaller when you increase compression level by 1, when the + level is already very high. Benchmark yourself if you can afford it. + + See also https://github.com/madler/zlib/blob/master/doc/algorithm.txt, + https://github.com/madler/zlib/blob/master/deflate.c for more information. + + The meaning of each field: + @field 1 use_lazy_evaluation: + true/false. Whether the program uses lazy evaluation. + See what is "lazy evaluation" in the link above. + lazy_evaluation improves ratio, but relatively slow. + @field 2 good_prev_length: + Only effective if lazy is set, Only use 1/4 of max_chain, + if prev length of lazy match is above this. + @field 3 max_insert_length/max_lazy_match: + If not using lazy evaluation, + insert new strings in the hash table only if the match length is not + greater than this length. + If using lazy evaluation, only continue lazy evaluation, + if previous match length is strictly smaller than this value. + @field 4 nice_length: + Number. Don't continue to go down the hash chain, + if match length is above this. + @field 5 max_chain: + Number. The maximum number of hash chains we look. +--]] +local _compression_level_configs = { + [0] = {false, nil, 0, 0, 0}, -- level 0, no compression + [1] = {false, nil, 4, 8, 4}, -- level 1, similar to zlib level 1 + [2] = {false, nil, 5, 18, 8}, -- level 2, similar to zlib level 2 + [3] = {false, nil, 6, 32, 32}, -- level 3, similar to zlib level 3 + [4] = {true, 4, 4, 16, 16}, -- level 4, similar to zlib level 4 + [5] = {true, 8, 16, 32, 32}, -- level 5, similar to zlib level 5 + [6] = {true, 8, 16, 128, 128}, -- level 6, similar to zlib level 6 + [7] = {true, 8, 32, 128, 256}, -- (SLOW) level 7, similar to zlib level 7 + [8] = {true, 32, 128, 258, 1024}, -- (SLOW) level 8,similar to zlib level 8 + [9] = {true, 32, 258, 258, 4096} + -- (VERY SLOW) level 9, similar to zlib level 9 +} + +-- Check if the compression/decompression arguments is valid +-- @param str The input string. +-- @param check_dictionary if true, check if dictionary is valid. +-- @param dictionary The preset dictionary for compression and decompression. +-- @param check_configs if true, check if config is valid. +-- @param configs The compression configuration table +-- @return true if valid, false if not valid. +-- @return if not valid, the error message. +local function IsValidArguments(str, check_dictionary, dictionary, + check_configs, configs) + + if type(str) ~= "string" then + return false, ("'str' - string expected got '%s'."):format(type(str)) + end + if check_dictionary then + local dict_valid, dict_err = IsValidDictionary(dictionary) + if not dict_valid then return false, dict_err end + end + if check_configs then + local type_configs = type(configs) + if type_configs ~= "nil" and type_configs ~= "table" then + return false, ("'configs' - nil or table expected got '%s'."):format( + type(configs)) + end + if type_configs == "table" then + for k, v in pairs(configs) do + if k ~= "level" and k ~= "strategy" then + return false, + ("'configs' - unsupported table key in the configs: '%s'."):format( + k) + elseif k == "level" and not _compression_level_configs[v] then + return false, + ("'configs' - unsupported 'level': %s."):format(tostring(v)) + elseif k == "strategy" and v ~= "fixed" and v ~= "huffman_only" and v ~= + "dynamic" then + -- random_block_type is for testing purpose + return false, ("'configs' - unsupported 'strategy': '%s'."):format( + tostring(v)) + end + end + end + end + return true, "" +end + +--[[ -------------------------------------------------------------------------- + Compress code +--]] -------------------------------------------------------------------------- + +-- partial flush to save memory +local _FLUSH_MODE_MEMORY_CLEANUP = 0 +-- full flush with partial bytes +local _FLUSH_MODE_OUTPUT = 1 +-- write bytes to get to byte boundary +local _FLUSH_MODE_BYTE_BOUNDARY = 2 +-- no flush, just get num of bits written so far +local _FLUSH_MODE_NO_FLUSH = 3 + +--[[ + Create an empty writer to easily write stuffs as the unit of bits. + Return values: + 1. WriteBits(code, bitlen): + 2. WriteString(str): + 3. Flush(mode): +--]] +local function CreateWriter() + local buffer_size = 0 + local cache = 0 + local cache_bitlen = 0 + local total_bitlen = 0 + local buffer = {} + -- When buffer is big enough, flush into result_buffer to save memory. + local result_buffer = {} + + -- Write bits with value "value" and bit length of "bitlen" into writer. + -- @param value: The value being written + -- @param bitlen: The bit length of "value" + -- @return nil + local function WriteBits(value, bitlen) + cache = cache + value * _pow2[cache_bitlen] + cache_bitlen = cache_bitlen + bitlen + total_bitlen = total_bitlen + bitlen + -- Only bulk to buffer every 4 bytes. This is quicker. + if cache_bitlen >= 32 then + buffer_size = buffer_size + 1 + buffer[buffer_size] = _byte_to_char[cache % 256] .. + _byte_to_char[((cache - cache % 256) / 256 % 256)] .. + _byte_to_char[((cache - cache % 65536) / 65536 % + 256)] .. + _byte_to_char[((cache - cache % 16777216) / + 16777216 % 256)] + local rshift_mask = _pow2[32 - cache_bitlen + bitlen] + cache = (value - value % rshift_mask) / rshift_mask + cache_bitlen = cache_bitlen - 32 + end + end + + -- Write the entire string into the writer. + -- @param str The string being written + -- @return nil + local function WriteString(str) + for _ = 1, cache_bitlen, 8 do + buffer_size = buffer_size + 1 + buffer[buffer_size] = string_char(cache % 256) + cache = (cache - cache % 256) / 256 + end + cache_bitlen = 0 + buffer_size = buffer_size + 1 + buffer[buffer_size] = str + total_bitlen = total_bitlen + #str * 8 + end + + -- Flush current stuffs in the writer and return it. + -- This operation will free most of the memory. + -- @param mode See the descrtion of the constant and the source code. + -- @return The total number of bits stored in the writer right now. + -- for byte boundary mode, it includes the padding bits. + -- for output mode, it does not include padding bits. + -- @return Return the outputs if mode is output. + local function FlushWriter(mode) + if mode == _FLUSH_MODE_NO_FLUSH then return total_bitlen end + + if mode == _FLUSH_MODE_OUTPUT or mode == _FLUSH_MODE_BYTE_BOUNDARY then + -- Full flush, also output cache. + -- Need to pad some bits if cache_bitlen is not multiple of 8. + local padding_bitlen = (8 - cache_bitlen % 8) % 8 + + if cache_bitlen > 0 then + -- padding with all 1 bits, mainly because "\000" is not + -- good to be tranmitted. I do this so "\000" is a little bit + -- less frequent. + cache = cache - _pow2[cache_bitlen] + + _pow2[cache_bitlen + padding_bitlen] + for _ = 1, cache_bitlen, 8 do + buffer_size = buffer_size + 1 + buffer[buffer_size] = _byte_to_char[cache % 256] + cache = (cache - cache % 256) / 256 + end + + cache = 0 + cache_bitlen = 0 + end + if mode == _FLUSH_MODE_BYTE_BOUNDARY then + total_bitlen = total_bitlen + padding_bitlen + return total_bitlen + end + end + + local flushed = table_concat(buffer) + buffer = {} + buffer_size = 0 + result_buffer[#result_buffer + 1] = flushed + + if mode == _FLUSH_MODE_MEMORY_CLEANUP then + return total_bitlen + else + return total_bitlen, table_concat(result_buffer) + end + end + + return WriteBits, WriteString, FlushWriter +end + +-- Push an element into a max heap +-- @param heap A max heap whose max element is at index 1. +-- @param e The element to be pushed. Assume element "e" is a table +-- and comparison is done via its first entry e[1] +-- @param heap_size current number of elements in the heap. +-- NOTE: There may be some garbage stored in +-- heap[heap_size+1], heap[heap_size+2], etc.. +-- @return nil +local function MinHeapPush(heap, e, heap_size) + heap_size = heap_size + 1 + heap[heap_size] = e + local value = e[1] + local pos = heap_size + local parent_pos = (pos - pos % 2) / 2 + + while (parent_pos >= 1 and heap[parent_pos][1] > value) do + local t = heap[parent_pos] + heap[parent_pos] = e + heap[pos] = t + pos = parent_pos + parent_pos = (parent_pos - parent_pos % 2) / 2 + end +end + +-- Pop an element from a max heap +-- @param heap A max heap whose max element is at index 1. +-- @param heap_size current number of elements in the heap. +-- @return the poped element +-- Note: This function does not change table size of "heap" to save CPU time. +local function MinHeapPop(heap, heap_size) + local top = heap[1] + local e = heap[heap_size] + local value = e[1] + heap[1] = e + heap[heap_size] = top + heap_size = heap_size - 1 + + local pos = 1 + local left_child_pos = pos * 2 + local right_child_pos = left_child_pos + 1 + + while (left_child_pos <= heap_size) do + local left_child = heap[left_child_pos] + if (right_child_pos <= heap_size and heap[right_child_pos][1] < + left_child[1]) then + local right_child = heap[right_child_pos] + if right_child[1] < value then + heap[right_child_pos] = e + heap[pos] = right_child + pos = right_child_pos + left_child_pos = pos * 2 + right_child_pos = left_child_pos + 1 + else + break + end + else + if left_child[1] < value then + heap[left_child_pos] = e + heap[pos] = left_child + pos = left_child_pos + left_child_pos = pos * 2 + right_child_pos = left_child_pos + 1 + else + break + end + end + end + + return top +end + +-- Deflate defines a special huffman tree, which is unique once the bit length +-- of huffman code of all symbols are known. +-- @param bitlen_count Number of symbols with a specific bitlen +-- @param symbol_bitlen The bit length of a symbol +-- @param max_symbol The max symbol among all symbols, +-- which is (number of symbols - 1) +-- @param max_bitlen The max huffman bit length among all symbols. +-- @return The huffman code of all symbols. +local function GetHuffmanCodeFromBitlen(bitlen_counts, symbol_bitlens, + max_symbol, max_bitlen) + local huffman_code = 0 + local next_codes = {} + local symbol_huffman_codes = {} + for bitlen = 1, max_bitlen do + huffman_code = (huffman_code + (bitlen_counts[bitlen - 1] or 0)) * 2 + next_codes[bitlen] = huffman_code + end + for symbol = 0, max_symbol do + local bitlen = symbol_bitlens[symbol] + if bitlen then + huffman_code = next_codes[bitlen] + next_codes[bitlen] = huffman_code + 1 + + -- Reverse the bits of huffman code, + -- because most signifant bits of huffman code + -- is stored first into the compressed data. + -- @see RFC1951 Page5 Section 3.1.1 + if bitlen <= 9 then -- Have cached reverse for small bitlen. + symbol_huffman_codes[symbol] = _reverse_bits_tbl[bitlen][huffman_code] + else + local reverse = 0 + for _ = 1, bitlen do + reverse = reverse - reverse % 2 + + (((reverse % 2 == 1) or (huffman_code % 2) == 1) and 1 or + 0) + huffman_code = (huffman_code - huffman_code % 2) / 2 + reverse = reverse * 2 + end + symbol_huffman_codes[symbol] = (reverse - reverse % 2) / 2 + end + end + end + return symbol_huffman_codes +end + +-- A helper function to sort heap elements +-- a[1], b[1] is the huffman frequency +-- a[2], b[2] is the symbol value. +local function SortByFirstThenSecond(a, b) + return a[1] < b[1] or (a[1] == b[1] and a[2] < b[2]) +end + +-- Calculate the huffman bit length and huffman code. +-- @param symbol_count: A table whose table key is the symbol, and table value +-- is the symbol frenquency (nil means 0 frequency). +-- @param max_bitlen: See description of return value. +-- @param max_symbol: The maximum symbol +-- @return a table whose key is the symbol, and the value is the huffman bit +-- bit length. We guarantee that all bit length <= max_bitlen. +-- For 0<=symbol<=max_symbol, table value could be nil if the frequency +-- of the symbol is 0 or nil. +-- @return a table whose key is the symbol, and the value is the huffman code. +-- @return a number indicating the maximum symbol whose bitlen is not 0. +local function GetHuffmanBitlenAndCode(symbol_counts, max_bitlen, max_symbol) + local heap_size + local max_non_zero_bitlen_symbol = -1 + local leafs = {} + local heap = {} + local symbol_bitlens = {} + local symbol_codes = {} + local bitlen_counts = {} + + --[[ + tree[1]: weight, temporarily used as parent and bitLengths + tree[2]: symbol + tree[3]: left child + tree[4]: right child + --]] + local number_unique_symbols = 0 + for symbol, count in pairs(symbol_counts) do + number_unique_symbols = number_unique_symbols + 1 + leafs[number_unique_symbols] = {count, symbol} + end + + if (number_unique_symbols == 0) then + -- no code. + return {}, {}, -1 + elseif (number_unique_symbols == 1) then + -- Only one code. In this case, its huffman code + -- needs to be assigned as 0, and bit length is 1. + -- This is the only case that the return result + -- represents an imcomplete huffman tree. + local symbol = leafs[1][2] + symbol_bitlens[symbol] = 1 + symbol_codes[symbol] = 0 + return symbol_bitlens, symbol_codes, symbol + else + table_sort(leafs, SortByFirstThenSecond) + heap_size = number_unique_symbols + for i = 1, heap_size do heap[i] = leafs[i] end + + while (heap_size > 1) do + -- Note: pop does not change table size of heap + local leftChild = MinHeapPop(heap, heap_size) + heap_size = heap_size - 1 + local rightChild = MinHeapPop(heap, heap_size) + heap_size = heap_size - 1 + local newNode = {leftChild[1] + rightChild[1], -1, leftChild, rightChild} + MinHeapPush(heap, newNode, heap_size) + heap_size = heap_size + 1 + end + + -- Number of leafs whose bit length is greater than max_len. + local number_bitlen_overflow = 0 + + -- Calculate bit length of all nodes + local fifo = {heap[1], 0, 0, 0} -- preallocate some spaces. + local fifo_size = 1 + local index = 1 + heap[1][1] = 0 + while (index <= fifo_size) do -- Breath first search + local e = fifo[index] + local bitlen = e[1] + local symbol = e[2] + local left_child = e[3] + local right_child = e[4] + if left_child then + fifo_size = fifo_size + 1 + fifo[fifo_size] = left_child + left_child[1] = bitlen + 1 + end + if right_child then + fifo_size = fifo_size + 1 + fifo[fifo_size] = right_child + right_child[1] = bitlen + 1 + end + index = index + 1 + + if (bitlen > max_bitlen) then + number_bitlen_overflow = number_bitlen_overflow + 1 + bitlen = max_bitlen + end + if symbol >= 0 then + symbol_bitlens[symbol] = bitlen + max_non_zero_bitlen_symbol = (symbol > max_non_zero_bitlen_symbol) and + symbol or max_non_zero_bitlen_symbol + bitlen_counts[bitlen] = (bitlen_counts[bitlen] or 0) + 1 + end + end + + -- Resolve bit length overflow + -- @see ZLib/trees.c:gen_bitlen(s, desc), for reference + if (number_bitlen_overflow > 0) then + repeat + local bitlen = max_bitlen - 1 + while ((bitlen_counts[bitlen] or 0) == 0) do bitlen = bitlen - 1 end + -- move one leaf down the tree + bitlen_counts[bitlen] = bitlen_counts[bitlen] - 1 + -- move one overflow item as its brother + bitlen_counts[bitlen + 1] = (bitlen_counts[bitlen + 1] or 0) + 2 + bitlen_counts[max_bitlen] = bitlen_counts[max_bitlen] - 1 + number_bitlen_overflow = number_bitlen_overflow - 2 + until (number_bitlen_overflow <= 0) + + index = 1 + for bitlen = max_bitlen, 1, -1 do + local n = bitlen_counts[bitlen] or 0 + while (n > 0) do + local symbol = leafs[index][2] + symbol_bitlens[symbol] = bitlen + n = n - 1 + index = index + 1 + end + end + end + + symbol_codes = GetHuffmanCodeFromBitlen(bitlen_counts, symbol_bitlens, + max_symbol, max_bitlen) + return symbol_bitlens, symbol_codes, max_non_zero_bitlen_symbol + end +end + +-- Calculate the first huffman header in the dynamic huffman block +-- @see RFC1951 Page 12 +-- @param lcode_bitlen: The huffman bit length of literal/LZ77_length. +-- @param max_non_zero_bitlen_lcode: The maximum literal/LZ77_length symbol +-- whose huffman bit length is not zero. +-- @param dcode_bitlen: The huffman bit length of LZ77 distance. +-- @param max_non_zero_bitlen_dcode: The maximum LZ77 distance symbol +-- whose huffman bit length is not zero. +-- @return The run length encoded codes. +-- @return The extra bits. One entry for each rle code that needs extra bits. +-- (code == 16 or 17 or 18). +-- @return The count of appearance of each rle codes. +local function RunLengthEncodeHuffmanBitlen(lcode_bitlens, + max_non_zero_bitlen_lcode, + dcode_bitlens, + max_non_zero_bitlen_dcode) + local rle_code_tblsize = 0 + local rle_codes = {} + local rle_code_counts = {} + local rle_extra_bits_tblsize = 0 + local rle_extra_bits = {} + local prev = nil + local count = 0 + + -- If there is no distance code, assume one distance code of bit length 0. + -- RFC1951: One distance code of zero bits means that + -- there are no distance codes used at all (the data is all literals). + max_non_zero_bitlen_dcode = (max_non_zero_bitlen_dcode < 0) and 0 or + max_non_zero_bitlen_dcode + local max_code = max_non_zero_bitlen_lcode + max_non_zero_bitlen_dcode + 1 + + for code = 0, max_code + 1 do + local len = (code <= max_non_zero_bitlen_lcode) and + (lcode_bitlens[code] or 0) or ((code <= max_code) and + (dcode_bitlens[code - max_non_zero_bitlen_lcode - 1] or 0) or + nil) + if len == prev then + count = count + 1 + if len ~= 0 and count == 6 then + rle_code_tblsize = rle_code_tblsize + 1 + rle_codes[rle_code_tblsize] = 16 + rle_extra_bits_tblsize = rle_extra_bits_tblsize + 1 + rle_extra_bits[rle_extra_bits_tblsize] = 3 + rle_code_counts[16] = (rle_code_counts[16] or 0) + 1 + count = 0 + elseif len == 0 and count == 138 then + rle_code_tblsize = rle_code_tblsize + 1 + rle_codes[rle_code_tblsize] = 18 + rle_extra_bits_tblsize = rle_extra_bits_tblsize + 1 + rle_extra_bits[rle_extra_bits_tblsize] = 127 + rle_code_counts[18] = (rle_code_counts[18] or 0) + 1 + count = 0 + end + else + if count == 1 then + rle_code_tblsize = rle_code_tblsize + 1 + rle_codes[rle_code_tblsize] = prev + rle_code_counts[prev] = (rle_code_counts[prev] or 0) + 1 + elseif count == 2 then + rle_code_tblsize = rle_code_tblsize + 1 + rle_codes[rle_code_tblsize] = prev + rle_code_tblsize = rle_code_tblsize + 1 + rle_codes[rle_code_tblsize] = prev + rle_code_counts[prev] = (rle_code_counts[prev] or 0) + 2 + elseif count >= 3 then + rle_code_tblsize = rle_code_tblsize + 1 + local rleCode = (prev ~= 0) and 16 or (count <= 10 and 17 or 18) + rle_codes[rle_code_tblsize] = rleCode + rle_code_counts[rleCode] = (rle_code_counts[rleCode] or 0) + 1 + rle_extra_bits_tblsize = rle_extra_bits_tblsize + 1 + rle_extra_bits[rle_extra_bits_tblsize] = + (count <= 10) and (count - 3) or (count - 11) + end + + prev = len + if len and len ~= 0 then + rle_code_tblsize = rle_code_tblsize + 1 + rle_codes[rle_code_tblsize] = len + rle_code_counts[len] = (rle_code_counts[len] or 0) + 1 + count = 0 + else + count = 1 + end + end + end + + return rle_codes, rle_extra_bits, rle_code_counts +end + +-- Load the string into a table, in order to speed up LZ77. +-- Loop unrolled 16 times to speed this function up. +-- @param str The string to be loaded. +-- @param t The load destination +-- @param start str[index] will be the first character to be loaded. +-- @param end str[index] will be the last character to be loaded +-- @param offset str[index] will be loaded into t[index-offset] +-- @return t +local function LoadStringToTable(str, t, start, stop, offset) + local i = start - offset + while i <= stop - 15 - offset do + t[i], t[i + 1], t[i + 2], t[i + 3], t[i + 4], t[i + 5], t[i + 6], t[i + 7], t[i + + 8], t[i + 9], t[i + 10], t[i + 11], t[i + 12], t[i + 13], t[i + 14], t[i + + 15] = string_byte(str, i + offset, i + 15 + offset) + i = i + 16 + end + while (i <= stop - offset) do + t[i] = string_byte(str, i + offset, i + offset) + i = i + 1 + end + return t +end + +-- Do LZ77 process. This function uses the majority of the CPU time. +-- @see zlib/deflate.c:deflate_fast(), zlib/deflate.c:deflate_slow() +-- @see https://github.com/madler/zlib/blob/master/doc/algorithm.txt +-- This function uses the algorithms used above. You should read the +-- algorithm.txt above to understand what is the hash function and the +-- lazy evaluation. +-- +-- The special optimization used here is hash functions used here. +-- The hash function is just the multiplication of the three consective +-- characters. So if the hash matches, it guarantees 3 characters are matched. +-- This optimization can be implemented because Lua table is a hash table. +-- +-- @param level integer that describes compression level. +-- @param string_table table that stores the value of string to be compressed. +-- The index of this table starts from 1. +-- The caller needs to make sure all values needed by this function +-- are loaded. +-- Assume "str" is the origin input string into the compressor +-- str[block_start]..str[block_end+3] needs to be loaded into +-- string_table[block_start-offset]..string_table[block_end-offset] +-- If dictionary is presented, the last 258 bytes of the dictionary +-- needs to be loaded into sing_table[-257..0] +-- (See more in the description of offset.) +-- @param hash_tables. The table key is the hash value (0<=hash<=16777216=256^3) +-- The table value is an array0 that stores the indexes of the +-- input data string to be compressed, such that +-- hash == str[index]*str[index+1]*str[index+2] +-- Indexes are ordered in this array. +-- @param block_start The indexes of the input data string to be compressed. +-- that starts the LZ77 block. +-- @param block_end The indexes of the input data string to be compressed. +-- that stores the LZ77 block. +-- @param offset str[index] is stored in string_table[index-offset], +-- This offset is mainly an optimization to limit the index +-- of string_table, so lua can access this table quicker. +-- @param dictionary See LibDeflate:CreateDictionary +-- @return literal/LZ77_length deflate codes. +-- @return the extra bits of literal/LZ77_length deflate codes. +-- @return the count of each literal/LZ77 deflate code. +-- @return LZ77 distance deflate codes. +-- @return the extra bits of LZ77 distance deflate codes. +-- @return the count of each LZ77 distance deflate code. +local function GetBlockLZ77Result(level, string_table, hash_tables, block_start, + block_end, offset, dictionary) + local config = _compression_level_configs[level] + local config_use_lazy, config_good_prev_length, config_max_lazy_match, + config_nice_length, config_max_hash_chain = config[1], config[2], + config[3], config[4], + config[5] + + local config_max_insert_length = (not config_use_lazy) and + config_max_lazy_match or 2147483646 + local config_good_hash_chain = + (config_max_hash_chain - config_max_hash_chain % 4 / 4) + + local hash + + local dict_hash_tables + local dict_string_table + local dict_string_len = 0 + + if dictionary then + dict_hash_tables = dictionary.hash_tables + dict_string_table = dictionary.string_table + dict_string_len = dictionary.strlen + assert(block_start == 1) + if block_end >= block_start and dict_string_len >= 2 then + hash = dict_string_table[dict_string_len - 1] * 65536 + + dict_string_table[dict_string_len] * 256 + string_table[1] + local t = hash_tables[hash] + if not t then + t = {}; + hash_tables[hash] = t + end + t[#t + 1] = -1 + end + if block_end >= block_start + 1 and dict_string_len >= 1 then + hash = + dict_string_table[dict_string_len] * 65536 + string_table[1] * 256 + + string_table[2] + local t = hash_tables[hash] + if not t then + t = {}; + hash_tables[hash] = t + end + t[#t + 1] = 0 + end + end + + local dict_string_len_plus3 = dict_string_len + 3 + + hash = (string_table[block_start - offset] or 0) * 256 + + (string_table[block_start + 1 - offset] or 0) + + local lcodes = {} + local lcode_tblsize = 0 + local lcodes_counts = {} + local dcodes = {} + local dcodes_tblsize = 0 + local dcodes_counts = {} + + local lextra_bits = {} + local lextra_bits_tblsize = 0 + local dextra_bits = {} + local dextra_bits_tblsize = 0 + + local match_available = false + local prev_len + local prev_dist + local cur_len = 0 + local cur_dist = 0 + + local index = block_start + local index_end = block_end + (config_use_lazy and 1 or 0) + + -- the zlib source code writes separate code for lazy evaluation and + -- not lazy evaluation, which is easier to understand. + -- I put them together, so it is a bit harder to understand. + -- because I think this is easier for me to maintain it. + while (index <= index_end) do + local string_table_index = index - offset + local offset_minus_three = offset - 3 + prev_len = cur_len + prev_dist = cur_dist + cur_len = 0 + + hash = (hash * 256 + (string_table[string_table_index + 2] or 0)) % 16777216 + + local chain_index + local cur_chain + local hash_chain = hash_tables[hash] + local chain_old_size + if not hash_chain then + chain_old_size = 0 + hash_chain = {} + hash_tables[hash] = hash_chain + if dict_hash_tables then + cur_chain = dict_hash_tables[hash] + chain_index = cur_chain and #cur_chain or 0 + else + chain_index = 0 + end + else + chain_old_size = #hash_chain + cur_chain = hash_chain + chain_index = chain_old_size + end + + if index <= block_end then hash_chain[chain_old_size + 1] = index end + + if (chain_index > 0 and index + 2 <= block_end and + (not config_use_lazy or prev_len < config_max_lazy_match)) then + + local depth = + (config_use_lazy and prev_len >= config_good_prev_length) and + config_good_hash_chain or config_max_hash_chain + + local max_len_minus_one = block_end - index + max_len_minus_one = (max_len_minus_one >= 257) and 257 or + max_len_minus_one + max_len_minus_one = max_len_minus_one + string_table_index + local string_table_index_plus_three = string_table_index + 3 + + while chain_index >= 1 and depth > 0 do + local prev = cur_chain[chain_index] + + if index - prev > 32768 then break end + if prev < index then + local sj = string_table_index_plus_three + + if prev >= -257 then + local pj = prev - offset_minus_three + while (sj <= max_len_minus_one and string_table[pj] == + string_table[sj]) do + sj = sj + 1 + pj = pj + 1 + end + else + local pj = dict_string_len_plus3 + prev + while (sj <= max_len_minus_one and dict_string_table[pj] == + string_table[sj]) do + sj = sj + 1 + pj = pj + 1 + end + end + local j = sj - string_table_index + if j > cur_len then + cur_len = j + cur_dist = index - prev + end + if cur_len >= config_nice_length then break end + end + + chain_index = chain_index - 1 + depth = depth - 1 + if chain_index == 0 and prev > 0 and dict_hash_tables then + cur_chain = dict_hash_tables[hash] + chain_index = cur_chain and #cur_chain or 0 + end + end + end + + if not config_use_lazy then prev_len, prev_dist = cur_len, cur_dist end + if ((not config_use_lazy or match_available) and + (prev_len > 3 or (prev_len == 3 and prev_dist < 4096)) and cur_len <= + prev_len) then + local code = _length_to_deflate_code[prev_len] + local length_extra_bits_bitlen = _length_to_deflate_extra_bitlen[prev_len] + local dist_code, dist_extra_bits_bitlen, dist_extra_bits + if prev_dist <= 256 then -- have cached code for small distance. + dist_code = _dist256_to_deflate_code[prev_dist] + dist_extra_bits = _dist256_to_deflate_extra_bits[prev_dist] + dist_extra_bits_bitlen = _dist256_to_deflate_extra_bitlen[prev_dist] + else + dist_code = 16 + dist_extra_bits_bitlen = 7 + local a = 384 + local b = 512 + + while true do + if prev_dist <= a then + dist_extra_bits = (prev_dist - (b / 2) - 1) % (b / 4) + break + elseif prev_dist <= b then + dist_extra_bits = (prev_dist - (b / 2) - 1) % (b / 4) + dist_code = dist_code + 1 + break + else + dist_code = dist_code + 2 + dist_extra_bits_bitlen = dist_extra_bits_bitlen + 1 + a = a * 2 + b = b * 2 + end + end + end + lcode_tblsize = lcode_tblsize + 1 + lcodes[lcode_tblsize] = code + lcodes_counts[code] = (lcodes_counts[code] or 0) + 1 + + dcodes_tblsize = dcodes_tblsize + 1 + dcodes[dcodes_tblsize] = dist_code + dcodes_counts[dist_code] = (dcodes_counts[dist_code] or 0) + 1 + + if length_extra_bits_bitlen > 0 then + local lenExtraBits = _length_to_deflate_extra_bits[prev_len] + lextra_bits_tblsize = lextra_bits_tblsize + 1 + lextra_bits[lextra_bits_tblsize] = lenExtraBits + end + if dist_extra_bits_bitlen > 0 then + dextra_bits_tblsize = dextra_bits_tblsize + 1 + dextra_bits[dextra_bits_tblsize] = dist_extra_bits + end + + for i = index + 1, index + prev_len - (config_use_lazy and 2 or 1) do + hash = (hash * 256 + (string_table[i - offset + 2] or 0)) % 16777216 + if prev_len <= config_max_insert_length then + hash_chain = hash_tables[hash] + if not hash_chain then + hash_chain = {} + hash_tables[hash] = hash_chain + end + hash_chain[#hash_chain + 1] = i + end + end + index = index + prev_len - (config_use_lazy and 1 or 0) + match_available = false + elseif (not config_use_lazy) or match_available then + local code = string_table[config_use_lazy and (string_table_index - 1) or + string_table_index] + lcode_tblsize = lcode_tblsize + 1 + lcodes[lcode_tblsize] = code + lcodes_counts[code] = (lcodes_counts[code] or 0) + 1 + index = index + 1 + else + match_available = true + index = index + 1 + end + end + + -- Write "end of block" symbol + lcode_tblsize = lcode_tblsize + 1 + lcodes[lcode_tblsize] = 256 + lcodes_counts[256] = (lcodes_counts[256] or 0) + 1 + + return lcodes, lextra_bits, lcodes_counts, dcodes, dextra_bits, dcodes_counts +end + +-- Get the header data of dynamic block. +-- @param lcodes_count The count of each literal/LZ77_length codes. +-- @param dcodes_count The count of each Lz77 distance codes. +-- @return a lots of stuffs. +-- @see RFC1951 Page 12 +local function GetBlockDynamicHuffmanHeader(lcodes_counts, dcodes_counts) + local lcodes_huffman_bitlens, lcodes_huffman_codes, max_non_zero_bitlen_lcode = + GetHuffmanBitlenAndCode(lcodes_counts, 15, 285) + local dcodes_huffman_bitlens, dcodes_huffman_codes, max_non_zero_bitlen_dcode = + GetHuffmanBitlenAndCode(dcodes_counts, 15, 29) + + local rle_deflate_codes, rle_extra_bits, rle_codes_counts = + RunLengthEncodeHuffmanBitlen(lcodes_huffman_bitlens, + max_non_zero_bitlen_lcode, + dcodes_huffman_bitlens, + max_non_zero_bitlen_dcode) + + local rle_codes_huffman_bitlens, rle_codes_huffman_codes = + GetHuffmanBitlenAndCode(rle_codes_counts, 7, 18) + + local HCLEN = 0 + for i = 1, 19 do + local symbol = _rle_codes_huffman_bitlen_order[i] + local length = rle_codes_huffman_bitlens[symbol] or 0 + if length ~= 0 then HCLEN = i end + end + + HCLEN = HCLEN - 4 + local HLIT = max_non_zero_bitlen_lcode + 1 - 257 + local HDIST = max_non_zero_bitlen_dcode + 1 - 1 + if HDIST < 0 then HDIST = 0 end + + return HLIT, HDIST, HCLEN, rle_codes_huffman_bitlens, rle_codes_huffman_codes, + rle_deflate_codes, rle_extra_bits, lcodes_huffman_bitlens, + lcodes_huffman_codes, dcodes_huffman_bitlens, dcodes_huffman_codes +end + +-- Get the size of dynamic block without writing any bits into the writer. +-- @param ... Read the source code of GetBlockDynamicHuffmanHeader() +-- @return the bit length of the dynamic block +local function GetDynamicHuffmanBlockSize(lcodes, dcodes, HCLEN, + rle_codes_huffman_bitlens, + rle_deflate_codes, + lcodes_huffman_bitlens, + dcodes_huffman_bitlens) + + local block_bitlen = 17 -- 1+2+5+5+4 + block_bitlen = block_bitlen + (HCLEN + 4) * 3 + + for i = 1, #rle_deflate_codes do + local code = rle_deflate_codes[i] + block_bitlen = block_bitlen + rle_codes_huffman_bitlens[code] + if code >= 16 then + block_bitlen = block_bitlen + + ((code == 16) and 2 or (code == 17 and 3 or 7)) + end + end + + local length_code_count = 0 + for i = 1, #lcodes do + local code = lcodes[i] + local huffman_bitlen = lcodes_huffman_bitlens[code] + block_bitlen = block_bitlen + huffman_bitlen + if code > 256 then -- Length code + length_code_count = length_code_count + 1 + if code > 264 and code < 285 then -- Length code with extra bits + local extra_bits_bitlen = _literal_deflate_code_to_extra_bitlen[code - + 256] + block_bitlen = block_bitlen + extra_bits_bitlen + end + local dist_code = dcodes[length_code_count] + local dist_huffman_bitlen = dcodes_huffman_bitlens[dist_code] + block_bitlen = block_bitlen + dist_huffman_bitlen + + if dist_code > 3 then -- dist code with extra bits + local dist_extra_bits_bitlen = (dist_code - dist_code % 2) / 2 - 1 + block_bitlen = block_bitlen + dist_extra_bits_bitlen + end + end + end + return block_bitlen +end + +-- Write dynamic block. +-- @param ... Read the source code of GetBlockDynamicHuffmanHeader() +local function CompressDynamicHuffmanBlock(WriteBits, is_last_block, lcodes, + lextra_bits, dcodes, dextra_bits, + HLIT, HDIST, HCLEN, + rle_codes_huffman_bitlens, + rle_codes_huffman_codes, + rle_deflate_codes, rle_extra_bits, + lcodes_huffman_bitlens, + lcodes_huffman_codes, + dcodes_huffman_bitlens, + dcodes_huffman_codes) + + WriteBits(is_last_block and 1 or 0, 1) -- Last block identifier + WriteBits(2, 2) -- Dynamic Huffman block identifier + + WriteBits(HLIT, 5) + WriteBits(HDIST, 5) + WriteBits(HCLEN, 4) + + for i = 1, HCLEN + 4 do + local symbol = _rle_codes_huffman_bitlen_order[i] + local length = rle_codes_huffman_bitlens[symbol] or 0 + WriteBits(length, 3) + end + + local rleExtraBitsIndex = 1 + for i = 1, #rle_deflate_codes do + local code = rle_deflate_codes[i] + WriteBits(rle_codes_huffman_codes[code], rle_codes_huffman_bitlens[code]) + if code >= 16 then + local extraBits = rle_extra_bits[rleExtraBitsIndex] + WriteBits(extraBits, (code == 16) and 2 or (code == 17 and 3 or 7)) + rleExtraBitsIndex = rleExtraBitsIndex + 1 + end + end + + local length_code_count = 0 + local length_code_with_extra_count = 0 + local dist_code_with_extra_count = 0 + + for i = 1, #lcodes do + local deflate_codee = lcodes[i] + local huffman_code = lcodes_huffman_codes[deflate_codee] + local huffman_bitlen = lcodes_huffman_bitlens[deflate_codee] + WriteBits(huffman_code, huffman_bitlen) + if deflate_codee > 256 then -- Length code + length_code_count = length_code_count + 1 + if deflate_codee > 264 and deflate_codee < 285 then + -- Length code with extra bits + length_code_with_extra_count = length_code_with_extra_count + 1 + local extra_bits = lextra_bits[length_code_with_extra_count] + local extra_bits_bitlen = + _literal_deflate_code_to_extra_bitlen[deflate_codee - 256] + WriteBits(extra_bits, extra_bits_bitlen) + end + -- Write distance code + local dist_deflate_code = dcodes[length_code_count] + local dist_huffman_code = dcodes_huffman_codes[dist_deflate_code] + local dist_huffman_bitlen = dcodes_huffman_bitlens[dist_deflate_code] + WriteBits(dist_huffman_code, dist_huffman_bitlen) + + if dist_deflate_code > 3 then -- dist code with extra bits + dist_code_with_extra_count = dist_code_with_extra_count + 1 + local dist_extra_bits = dextra_bits[dist_code_with_extra_count] + local dist_extra_bits_bitlen = (dist_deflate_code - dist_deflate_code % + 2) / 2 - 1 + WriteBits(dist_extra_bits, dist_extra_bits_bitlen) + end + end + end +end + +-- Get the size of fixed block without writing any bits into the writer. +-- @param lcodes literal/LZ77_length deflate codes +-- @param decodes LZ77 distance deflate codes +-- @return the bit length of the fixed block +local function GetFixedHuffmanBlockSize(lcodes, dcodes) + local block_bitlen = 3 + local length_code_count = 0 + for i = 1, #lcodes do + local code = lcodes[i] + local huffman_bitlen = _fix_block_literal_huffman_bitlen[code] + block_bitlen = block_bitlen + huffman_bitlen + if code > 256 then -- Length code + length_code_count = length_code_count + 1 + if code > 264 and code < 285 then -- Length code with extra bits + local extra_bits_bitlen = _literal_deflate_code_to_extra_bitlen[code - + 256] + block_bitlen = block_bitlen + extra_bits_bitlen + end + local dist_code = dcodes[length_code_count] + block_bitlen = block_bitlen + 5 + + if dist_code > 3 then -- dist code with extra bits + local dist_extra_bits_bitlen = (dist_code - dist_code % 2) / 2 - 1 + block_bitlen = block_bitlen + dist_extra_bits_bitlen + end + end + end + return block_bitlen +end + +-- Write fixed block. +-- @param lcodes literal/LZ77_length deflate codes +-- @param decodes LZ77 distance deflate codes +local function CompressFixedHuffmanBlock(WriteBits, is_last_block, lcodes, + lextra_bits, dcodes, dextra_bits) + WriteBits(is_last_block and 1 or 0, 1) -- Last block identifier + WriteBits(1, 2) -- Fixed Huffman block identifier + local length_code_count = 0 + local length_code_with_extra_count = 0 + local dist_code_with_extra_count = 0 + for i = 1, #lcodes do + local deflate_code = lcodes[i] + local huffman_code = _fix_block_literal_huffman_code[deflate_code] + local huffman_bitlen = _fix_block_literal_huffman_bitlen[deflate_code] + WriteBits(huffman_code, huffman_bitlen) + if deflate_code > 256 then -- Length code + length_code_count = length_code_count + 1 + if deflate_code > 264 and deflate_code < 285 then + -- Length code with extra bits + length_code_with_extra_count = length_code_with_extra_count + 1 + local extra_bits = lextra_bits[length_code_with_extra_count] + local extra_bits_bitlen = + _literal_deflate_code_to_extra_bitlen[deflate_code - 256] + WriteBits(extra_bits, extra_bits_bitlen) + end + -- Write distance code + local dist_code = dcodes[length_code_count] + local dist_huffman_code = _fix_block_dist_huffman_code[dist_code] + WriteBits(dist_huffman_code, 5) + + if dist_code > 3 then -- dist code with extra bits + dist_code_with_extra_count = dist_code_with_extra_count + 1 + local dist_extra_bits = dextra_bits[dist_code_with_extra_count] + local dist_extra_bits_bitlen = (dist_code - dist_code % 2) / 2 - 1 + WriteBits(dist_extra_bits, dist_extra_bits_bitlen) + end + end + end +end + +-- Get the size of store block without writing any bits into the writer. +-- @param block_start The start index of the origin input string +-- @param block_end The end index of the origin input string +-- @param Total bit lens had been written into the compressed result before, +-- because store block needs to shift to byte boundary. +-- @return the bit length of the fixed block +local function GetStoreBlockSize(block_start, block_end, total_bitlen) + assert(block_end - block_start + 1 <= 65535) + local block_bitlen = 3 + total_bitlen = total_bitlen + 3 + local padding_bitlen = (8 - total_bitlen % 8) % 8 + block_bitlen = block_bitlen + padding_bitlen + block_bitlen = block_bitlen + 32 + block_bitlen = block_bitlen + (block_end - block_start + 1) * 8 + return block_bitlen +end + +-- Write the store block. +-- @param ... lots of stuffs +-- @return nil +local function CompressStoreBlock(WriteBits, WriteString, is_last_block, str, + block_start, block_end, total_bitlen) + assert(block_end - block_start + 1 <= 65535) + WriteBits(is_last_block and 1 or 0, 1) -- Last block identifer. + WriteBits(0, 2) -- Store block identifier. + total_bitlen = total_bitlen + 3 + local padding_bitlen = (8 - total_bitlen % 8) % 8 + if padding_bitlen > 0 then + WriteBits(_pow2[padding_bitlen] - 1, padding_bitlen) + end + local size = block_end - block_start + 1 + WriteBits(size, 16) + + -- Write size's one's complement + local comp = (255 - size % 256) + (255 - (size - size % 256) / 256) * 256 + WriteBits(comp, 16) + + WriteString(str:sub(block_start, block_end)) +end + +-- Do the deflate +-- Currently using a simple way to determine the block size +-- (This is why the compression ratio is little bit worse than zlib when +-- the input size is very large +-- The first block is 64KB, the following block is 32KB. +-- After each block, there is a memory cleanup operation. +-- This is not a fast operation, but it is needed to save memory usage, so +-- the memory usage does not grow unboundly. If the data size is less than +-- 64KB, then memory cleanup won't happen. +-- This function determines whether to use store/fixed/dynamic blocks by +-- calculating the block size of each block type and chooses the smallest one. +local function Deflate(configs, WriteBits, WriteString, FlushWriter, str, + dictionary) + local string_table = {} + local hash_tables = {} + local is_last_block = nil + local block_start + local block_end + local bitlen_written + local total_bitlen = FlushWriter(_FLUSH_MODE_NO_FLUSH) + local strlen = #str + local offset + + local level + local strategy + if configs then + if configs.level then level = configs.level end + if configs.strategy then strategy = configs.strategy end + end + + if not level then + if strlen < 2048 then + level = 7 + elseif strlen > 65536 then + level = 3 + else + level = 5 + end + end + + while not is_last_block do + if not block_start then + block_start = 1 + block_end = 64 * 1024 - 1 + offset = 0 + else + block_start = block_end + 1 + block_end = block_end + 32 * 1024 + offset = block_start - 32 * 1024 - 1 + end + + if block_end >= strlen then + block_end = strlen + is_last_block = true + else + is_last_block = false + end + + local lcodes, lextra_bits, lcodes_counts, dcodes, dextra_bits, dcodes_counts + + local HLIT, HDIST, HCLEN, rle_codes_huffman_bitlens, + rle_codes_huffman_codes, rle_deflate_codes, rle_extra_bits, + lcodes_huffman_bitlens, lcodes_huffman_codes, dcodes_huffman_bitlens, + dcodes_huffman_codes + + local dynamic_block_bitlen + local fixed_block_bitlen + local store_block_bitlen + + if level ~= 0 then + + -- GetBlockLZ77 needs block_start to block_end+3 to be loaded. + LoadStringToTable(str, string_table, block_start, block_end + 3, offset) + if block_start == 1 and dictionary then + local dict_string_table = dictionary.string_table + local dict_strlen = dictionary.strlen + for i = 0, (-dict_strlen + 1) < -257 and -257 or (-dict_strlen + 1), -1 do + string_table[i] = dict_string_table[dict_strlen + i] + end + end + + if strategy == "huffman_only" then + lcodes = {} + LoadStringToTable(str, lcodes, block_start, block_end, block_start - 1) + lextra_bits = {} + lcodes_counts = {} + lcodes[block_end - block_start + 2] = 256 -- end of block + for i = 1, block_end - block_start + 2 do + local code = lcodes[i] + lcodes_counts[code] = (lcodes_counts[code] or 0) + 1 + end + dcodes = {} + dextra_bits = {} + dcodes_counts = {} + else + lcodes, lextra_bits, lcodes_counts, dcodes, dextra_bits, dcodes_counts = + GetBlockLZ77Result(level, string_table, hash_tables, block_start, + block_end, offset, dictionary) + end + + -- LuaFormatter off + HLIT, HDIST, HCLEN, rle_codes_huffman_bitlens, rle_codes_huffman_codes, rle_deflate_codes, + rle_extra_bits, lcodes_huffman_bitlens, lcodes_huffman_codes, dcodes_huffman_bitlens, dcodes_huffman_codes = + -- LuaFormatter on + GetBlockDynamicHuffmanHeader(lcodes_counts, dcodes_counts) + dynamic_block_bitlen = GetDynamicHuffmanBlockSize(lcodes, dcodes, HCLEN, + rle_codes_huffman_bitlens, + rle_deflate_codes, + lcodes_huffman_bitlens, + dcodes_huffman_bitlens) + fixed_block_bitlen = GetFixedHuffmanBlockSize(lcodes, dcodes) + end + + store_block_bitlen = GetStoreBlockSize(block_start, block_end, total_bitlen) + + local min_bitlen = store_block_bitlen + min_bitlen = (fixed_block_bitlen and fixed_block_bitlen < min_bitlen) and + fixed_block_bitlen or min_bitlen + min_bitlen = + (dynamic_block_bitlen and dynamic_block_bitlen < min_bitlen) and + dynamic_block_bitlen or min_bitlen + + if level == 0 or + (strategy ~= "fixed" and strategy ~= "dynamic" and store_block_bitlen == + min_bitlen) then + CompressStoreBlock(WriteBits, WriteString, is_last_block, str, + block_start, block_end, total_bitlen) + total_bitlen = total_bitlen + store_block_bitlen + elseif strategy ~= "dynamic" and + (strategy == "fixed" or fixed_block_bitlen == min_bitlen) then + CompressFixedHuffmanBlock(WriteBits, is_last_block, lcodes, lextra_bits, + dcodes, dextra_bits) + total_bitlen = total_bitlen + fixed_block_bitlen + elseif strategy == "dynamic" or dynamic_block_bitlen == min_bitlen then + CompressDynamicHuffmanBlock(WriteBits, is_last_block, lcodes, lextra_bits, + dcodes, dextra_bits, HLIT, HDIST, HCLEN, + rle_codes_huffman_bitlens, + rle_codes_huffman_codes, rle_deflate_codes, + rle_extra_bits, lcodes_huffman_bitlens, + lcodes_huffman_codes, dcodes_huffman_bitlens, + dcodes_huffman_codes) + total_bitlen = total_bitlen + dynamic_block_bitlen + end + + if is_last_block then + bitlen_written = FlushWriter(_FLUSH_MODE_NO_FLUSH) + else + bitlen_written = FlushWriter(_FLUSH_MODE_MEMORY_CLEANUP) + end + + assert(bitlen_written == total_bitlen) + + -- Memory clean up, so memory consumption does not always grow linearly + -- , even if input string is > 64K. + -- Not a very efficient operation, but this operation won't happen + -- when the input data size is less than 64K. + if not is_last_block then + local j + if dictionary and block_start == 1 then + j = 0 + while (string_table[j]) do + string_table[j] = nil + j = j - 1 + end + end + dictionary = nil + j = 1 + for i = block_end - 32767, block_end do + string_table[j] = string_table[i - offset] + j = j + 1 + end + + for k, t in pairs(hash_tables) do + local tSize = #t + if tSize > 0 and block_end + 1 - t[1] > 32768 then + if tSize == 1 then + hash_tables[k] = nil + else + local new = {} + local newSize = 0 + for i = 2, tSize do + j = t[i] + if block_end + 1 - j <= 32768 then + newSize = newSize + 1 + new[newSize] = j + end + end + hash_tables[k] = new + end + end + end + end + end +end + +--- The description to compression configuration table.
+-- Any field can be nil to use its default.
+-- Table with keys other than those below is an invalid table. +-- @class table +-- @name compression_configs +-- @field level The compression level ranged from 0 to 9. 0 is no compression. +-- 9 is the slowest but best compression. Use nil for default level. +-- @field strategy The compression strategy. "fixed" to only use fixed deflate +-- compression block. "dynamic" to only use dynamic block. "huffman_only" to +-- do no LZ77 compression. Only do huffman compression. + +-- @see LibDeflate:CompressDeflate(str, configs) +-- @see LibDeflate:CompressDeflateWithDict(str, dictionary, configs) +local function CompressDeflateInternal(str, dictionary, configs) + local WriteBits, WriteString, FlushWriter = CreateWriter() + Deflate(configs, WriteBits, WriteString, FlushWriter, str, dictionary) + local total_bitlen, result = FlushWriter(_FLUSH_MODE_OUTPUT) + local padding_bitlen = (8 - total_bitlen % 8) % 8 + return result, padding_bitlen +end + +-- @see LibDeflate:CompressZlib +-- @see LibDeflate:CompressZlibWithDict +local function CompressZlibInternal(str, dictionary, configs) + local WriteBits, WriteString, FlushWriter = CreateWriter() + + local CM = 8 -- Compression method + local CINFO = 7 -- Window Size = 32K + local CMF = CINFO * 16 + CM + WriteBits(CMF, 8) + + local FDIST = dictionary and 1 or 0 + local FLEVEL = 2 -- Default compression + local FLG = FLEVEL * 64 + FDIST * 32 + local FCHECK = (31 - (CMF * 256 + FLG) % 31) + -- The FCHECK value must be such that CMF and FLG, + -- when viewed as a 16-bit unsigned integer stored + -- in MSB order (CMF*256 + FLG), is a multiple of 31. + FLG = FLG + FCHECK + WriteBits(FLG, 8) + + if FDIST == 1 then + local adler32 = dictionary.adler32 + local byte0 = adler32 % 256 + adler32 = (adler32 - byte0) / 256 + local byte1 = adler32 % 256 + adler32 = (adler32 - byte1) / 256 + local byte2 = adler32 % 256 + adler32 = (adler32 - byte2) / 256 + local byte3 = adler32 % 256 + WriteBits(byte3, 8) + WriteBits(byte2, 8) + WriteBits(byte1, 8) + WriteBits(byte0, 8) + end + + Deflate(configs, WriteBits, WriteString, FlushWriter, str, dictionary) + FlushWriter(_FLUSH_MODE_BYTE_BOUNDARY) + + local adler32 = LibDeflate:Adler32(str) + + -- Most significant byte first + local byte3 = adler32 % 256 + adler32 = (adler32 - byte3) / 256 + local byte2 = adler32 % 256 + adler32 = (adler32 - byte2) / 256 + local byte1 = adler32 % 256 + adler32 = (adler32 - byte1) / 256 + local byte0 = adler32 % 256 + + WriteBits(byte0, 8) + WriteBits(byte1, 8) + WriteBits(byte2, 8) + WriteBits(byte3, 8) + local total_bitlen, result = FlushWriter(_FLUSH_MODE_OUTPUT) + local padding_bitlen = (8 - total_bitlen % 8) % 8 + return result, padding_bitlen +end + +--- Compress using the raw deflate format. +-- @param str [string] The data to be compressed. +-- @param configs [table/nil] The configuration table to control the compression +-- . If nil, use the default configuration. +-- @return [string] The compressed data. +-- @return [integer] The number of bits padded at the end of output. +-- 0 <= bits < 8
+-- This means the most significant "bits" of the last byte of the returned +-- compressed data are padding bits and they don't affect decompression. +-- You don't need to use this value unless you want to do some postprocessing +-- to the compressed data. +-- @see compression_configs +-- @see LibDeflate:DecompressDeflate +function LibDeflate:CompressDeflate(str, configs) + local arg_valid, arg_err = IsValidArguments(str, false, nil, true, configs) + if not arg_valid then + error(("Usage: LibDeflate:CompressDeflate(str, configs): " .. arg_err), 2) + end + return CompressDeflateInternal(str, nil, configs) +end + +--- Compress using the raw deflate format with a preset dictionary. +-- @param str [string] The data to be compressed. +-- @param dictionary [table] The preset dictionary produced by +-- LibDeflate:CreateDictionary +-- @param configs [table/nil] The configuration table to control the compression +-- . If nil, use the default configuration. +-- @return [string] The compressed data. +-- @return [integer] The number of bits padded at the end of output. +-- 0 <= bits < 8
+-- This means the most significant "bits" of the last byte of the returned +-- compressed data are padding bits and they don't affect decompression. +-- You don't need to use this value unless you want to do some postprocessing +-- to the compressed data. +-- @see compression_configs +-- @see LibDeflate:CreateDictionary +-- @see LibDeflate:DecompressDeflateWithDict +function LibDeflate:CompressDeflateWithDict(str, dictionary, configs) + local arg_valid, arg_err = IsValidArguments(str, true, dictionary, true, + configs) + if not arg_valid then + error(("Usage: LibDeflate:CompressDeflateWithDict" .. + "(str, dictionary, configs): " .. arg_err), 2) + end + return CompressDeflateInternal(str, dictionary, configs) +end + +--- Compress using the zlib format. +-- @param str [string] the data to be compressed. +-- @param configs [table/nil] The configuration table to control the compression +-- . If nil, use the default configuration. +-- @return [string] The compressed data. +-- @return [integer] The number of bits padded at the end of output. +-- Should always be 0. +-- Zlib formatted compressed data never has padding bits at the end. +-- @see compression_configs +-- @see LibDeflate:DecompressZlib +function LibDeflate:CompressZlib(str, configs) + local arg_valid, arg_err = IsValidArguments(str, false, nil, true, configs) + if not arg_valid then + error(("Usage: LibDeflate:CompressZlib(str, configs): " .. arg_err), 2) + end + return CompressZlibInternal(str, nil, configs) +end + +--- Compress using the zlib format with a preset dictionary. +-- @param str [string] the data to be compressed. +-- @param dictionary [table] A preset dictionary produced +-- by LibDeflate:CreateDictionary() +-- @param configs [table/nil] The configuration table to control the compression +-- . If nil, use the default configuration. +-- @return [string] The compressed data. +-- @return [integer] The number of bits padded at the end of output. +-- Should always be 0. +-- Zlib formatted compressed data never has padding bits at the end. +-- @see compression_configs +-- @see LibDeflate:CreateDictionary +-- @see LibDeflate:DecompressZlibWithDict +function LibDeflate:CompressZlibWithDict(str, dictionary, configs) + local arg_valid, arg_err = IsValidArguments(str, true, dictionary, true, + configs) + if not arg_valid then + error(("Usage: LibDeflate:CompressZlibWithDict" .. + "(str, dictionary, configs): " .. arg_err), 2) + end + return CompressZlibInternal(str, dictionary, configs) +end + +--[[ -------------------------------------------------------------------------- + Decompress code +--]] -------------------------------------------------------------------------- + +--[[ + Create a reader to easily reader stuffs as the unit of bits. + Return values: + 1. ReadBits(bitlen) + 2. ReadBytes(bytelen, buffer, buffer_size) + 3. Decode(huffman_bitlen_count, huffman_symbol, min_bitlen) + 4. ReaderBitlenLeft() + 5. SkipToByteBoundary() +--]] +local function CreateReader(input_string) + local input = input_string + local input_strlen = #input_string + local input_next_byte_pos = 1 + local cache_bitlen = 0 + local cache = 0 + + -- Read some bits. + -- To improve speed, this function does not + -- check if the input has been exhausted. + -- Use ReaderBitlenLeft() < 0 to check it. + -- @param bitlen the number of bits to read + -- @return the data is read. + local function ReadBits(bitlen) + local rshift_mask = _pow2[bitlen] + local code + if bitlen <= cache_bitlen then + code = cache % rshift_mask + cache = (cache - code) / rshift_mask + cache_bitlen = cache_bitlen - bitlen + else -- Whether input has been exhausted is not checked. + local lshift_mask = _pow2[cache_bitlen] + local byte1, byte2, byte3, byte4 = + string_byte(input, input_next_byte_pos, input_next_byte_pos + 3) + -- This requires lua number to be at least double () + cache = cache + + ((byte1 or 0) + (byte2 or 0) * 256 + (byte3 or 0) * 65536 + + (byte4 or 0) * 16777216) * lshift_mask + input_next_byte_pos = input_next_byte_pos + 4 + cache_bitlen = cache_bitlen + 32 - bitlen + code = cache % rshift_mask + cache = (cache - code) / rshift_mask + end + return code + end + + -- Read some bytes from the reader. + -- Assume reader is on the byte boundary. + -- @param bytelen The number of bytes to be read. + -- @param buffer The byte read will be stored into this buffer. + -- @param buffer_size The buffer will be modified starting from + -- buffer[buffer_size+1], ending at buffer[buffer_size+bytelen-1] + -- @return the new buffer_size + local function ReadBytes(bytelen, buffer, buffer_size) + assert(cache_bitlen % 8 == 0) + + local byte_from_cache = + (cache_bitlen / 8 < bytelen) and (cache_bitlen / 8) or bytelen + for _ = 1, byte_from_cache do + local byte = cache % 256 + buffer_size = buffer_size + 1 + buffer[buffer_size] = string_char(byte) + cache = (cache - byte) / 256 + end + cache_bitlen = cache_bitlen - byte_from_cache * 8 + bytelen = bytelen - byte_from_cache + if (input_strlen - input_next_byte_pos - bytelen + 1) * 8 + cache_bitlen < 0 then + return -1 -- out of input + end + for i = input_next_byte_pos, input_next_byte_pos + bytelen - 1 do + buffer_size = buffer_size + 1 + buffer[buffer_size] = string_sub(input, i, i) + end + + input_next_byte_pos = input_next_byte_pos + bytelen + return buffer_size + end + + -- Decode huffman code + -- To improve speed, this function does not check + -- if the input has been exhausted. + -- Use ReaderBitlenLeft() < 0 to check it. + -- Credits for Mark Adler. This code is from puff:Decode() + -- @see puff:Decode(...) + -- @param huffman_bitlen_count + -- @param huffman_symbol + -- @param min_bitlen The minimum huffman bit length of all symbols + -- @return The decoded deflate code. + -- Negative value is returned if decoding fails. + local function Decode(huffman_bitlen_counts, huffman_symbols, min_bitlen) + local code = 0 + local first = 0 + local index = 0 + local count + if min_bitlen > 0 then + if cache_bitlen < 15 and input then + local lshift_mask = _pow2[cache_bitlen] + local byte1, byte2, byte3, byte4 = + string_byte(input, input_next_byte_pos, input_next_byte_pos + 3) + -- This requires lua number to be at least double () + cache = cache + + ((byte1 or 0) + (byte2 or 0) * 256 + (byte3 or 0) * 65536 + + (byte4 or 0) * 16777216) * lshift_mask + input_next_byte_pos = input_next_byte_pos + 4 + cache_bitlen = cache_bitlen + 32 + end + + local rshift_mask = _pow2[min_bitlen] + cache_bitlen = cache_bitlen - min_bitlen + code = cache % rshift_mask + cache = (cache - code) / rshift_mask + -- Reverse the bits + code = _reverse_bits_tbl[min_bitlen][code] + + count = huffman_bitlen_counts[min_bitlen] + if code < count then return huffman_symbols[code] end + index = count + first = count * 2 + code = code * 2 + end + + for bitlen = min_bitlen + 1, 15 do + local bit + bit = cache % 2 + cache = (cache - bit) / 2 + cache_bitlen = cache_bitlen - 1 + + code = (bit == 1) and (code + 1 - code % 2) or code + count = huffman_bitlen_counts[bitlen] or 0 + local diff = code - first + if diff < count then return huffman_symbols[index + diff] end + index = index + count + first = first + count + first = first * 2 + code = code * 2 + end + -- invalid literal/length or distance code + -- in fixed or dynamic block (run out of code) + return -10 + end + + local function ReaderBitlenLeft() + return (input_strlen - input_next_byte_pos + 1) * 8 + cache_bitlen + end + + local function SkipToByteBoundary() + local skipped_bitlen = cache_bitlen % 8 + local rshift_mask = _pow2[skipped_bitlen] + cache_bitlen = cache_bitlen - skipped_bitlen + cache = (cache - cache % rshift_mask) / rshift_mask + end + + return ReadBits, ReadBytes, Decode, ReaderBitlenLeft, SkipToByteBoundary +end + +-- Create a deflate state, so I can pass in less arguments to functions. +-- @param str the whole string to be decompressed. +-- @param dictionary The preset dictionary. nil if not provided. +-- This dictionary should be produced by LibDeflate:CreateDictionary(str) +-- @return The decomrpess state. +local function CreateDecompressState(str, dictionary) + local ReadBits, ReadBytes, Decode, ReaderBitlenLeft, SkipToByteBoundary = + CreateReader(str) + local state = { + ReadBits = ReadBits, + ReadBytes = ReadBytes, + Decode = Decode, + ReaderBitlenLeft = ReaderBitlenLeft, + SkipToByteBoundary = SkipToByteBoundary, + buffer_size = 0, + buffer = {}, + result_buffer = {}, + dictionary = dictionary + } + return state +end + +-- Get the stuffs needed to decode huffman codes +-- @see puff.c:construct(...) +-- @param huffman_bitlen The huffman bit length of the huffman codes. +-- @param max_symbol The maximum symbol +-- @param max_bitlen The min huffman bit length of all codes +-- @return zero or positive for success, negative for failure. +-- @return The count of each huffman bit length. +-- @return A table to convert huffman codes to deflate codes. +-- @return The minimum huffman bit length. +local function GetHuffmanForDecode(huffman_bitlens, max_symbol, max_bitlen) + local huffman_bitlen_counts = {} + local min_bitlen = max_bitlen + for symbol = 0, max_symbol do + local bitlen = huffman_bitlens[symbol] or 0 + min_bitlen = (bitlen > 0 and bitlen < min_bitlen) and bitlen or min_bitlen + huffman_bitlen_counts[bitlen] = (huffman_bitlen_counts[bitlen] or 0) + 1 + end + + if huffman_bitlen_counts[0] == max_symbol + 1 then -- No Codes + return 0, huffman_bitlen_counts, {}, 0 -- Complete, but decode will fail + end + + local left = 1 + for len = 1, max_bitlen do + left = left * 2 + left = left - (huffman_bitlen_counts[len] or 0) + if left < 0 then + return left -- Over-subscribed, return negative + end + end + + -- Generate offsets info symbol table for each length for sorting + local offsets = {} + offsets[1] = 0 + for len = 1, max_bitlen - 1 do + offsets[len + 1] = offsets[len] + (huffman_bitlen_counts[len] or 0) + end + + local huffman_symbols = {} + for symbol = 0, max_symbol do + local bitlen = huffman_bitlens[symbol] or 0 + if bitlen ~= 0 then + local offset = offsets[bitlen] + huffman_symbols[offset] = symbol + offsets[bitlen] = offsets[bitlen] + 1 + end + end + + -- Return zero for complete set, positive for incomplete set. + return left, huffman_bitlen_counts, huffman_symbols, min_bitlen +end + +-- Decode a fixed or dynamic huffman blocks, excluding last block identifier +-- and block type identifer. +-- @see puff.c:codes() +-- @param state decompression state that will be modified by this function. +-- @see CreateDecompressState +-- @param ... Read the source code +-- @return 0 on success, other value on failure. +local function DecodeUntilEndOfBlock(state, lcodes_huffman_bitlens, + lcodes_huffman_symbols, + lcodes_huffman_min_bitlen, + dcodes_huffman_bitlens, + dcodes_huffman_symbols, + dcodes_huffman_min_bitlen) + local buffer, buffer_size, ReadBits, Decode, ReaderBitlenLeft, result_buffer = + state.buffer, state.buffer_size, state.ReadBits, state.Decode, + state.ReaderBitlenLeft, state.result_buffer + local dictionary = state.dictionary + local dict_string_table + local dict_strlen + + local buffer_end = 1 + if dictionary and not buffer[0] then + -- If there is a dictionary, copy the last 258 bytes into + -- the string_table to make the copy in the main loop quicker. + -- This is done only once per decompression. + dict_string_table = dictionary.string_table + dict_strlen = dictionary.strlen + buffer_end = -dict_strlen + 1 + for i = 0, (-dict_strlen + 1) < -257 and -257 or (-dict_strlen + 1), -1 do + buffer[i] = _byte_to_char[dict_string_table[dict_strlen + i]] + end + end + + repeat + local symbol = Decode(lcodes_huffman_bitlens, lcodes_huffman_symbols, + lcodes_huffman_min_bitlen) + if symbol < 0 or symbol > 285 then + -- invalid literal/length or distance code in fixed or dynamic block + return -10 + elseif symbol < 256 then -- Literal + buffer_size = buffer_size + 1 + buffer[buffer_size] = _byte_to_char[symbol] + elseif symbol > 256 then -- Length code + symbol = symbol - 256 + local bitlen = _literal_deflate_code_to_base_len[symbol] + bitlen = (symbol >= 8) and + (bitlen + + ReadBits(_literal_deflate_code_to_extra_bitlen[symbol])) or + bitlen + symbol = Decode(dcodes_huffman_bitlens, dcodes_huffman_symbols, + dcodes_huffman_min_bitlen) + if symbol < 0 or symbol > 29 then + -- invalid literal/length or distance code in fixed or dynamic block + return -10 + end + local dist = _dist_deflate_code_to_base_dist[symbol] + dist = (dist > 4) and + (dist + ReadBits(_dist_deflate_code_to_extra_bitlen[symbol])) or + dist + + local char_buffer_index = buffer_size - dist + 1 + if char_buffer_index < buffer_end then + -- distance is too far back in fixed or dynamic block + return -11 + end + if char_buffer_index >= -257 then + for _ = 1, bitlen do + buffer_size = buffer_size + 1 + buffer[buffer_size] = buffer[char_buffer_index] + char_buffer_index = char_buffer_index + 1 + end + else + char_buffer_index = dict_strlen + char_buffer_index + for _ = 1, bitlen do + buffer_size = buffer_size + 1 + buffer[buffer_size] = + _byte_to_char[dict_string_table[char_buffer_index]] + char_buffer_index = char_buffer_index + 1 + end + end + end + + if ReaderBitlenLeft() < 0 then + return 2 -- available inflate data did not terminate + end + + if buffer_size >= 65536 then + result_buffer[#result_buffer + 1] = table_concat(buffer, "", 1, 32768) + for i = 32769, buffer_size do buffer[i - 32768] = buffer[i] end + buffer_size = buffer_size - 32768 + buffer[buffer_size + 1] = nil + -- NOTE: buffer[32769..end] and buffer[-257..0] are not cleared. + -- This is why "buffer_size" variable is needed. + end + until symbol == 256 + + state.buffer_size = buffer_size + + return 0 +end + +-- Decompress a store block +-- @param state decompression state that will be modified by this function. +-- @return 0 if succeeds, other value if fails. +local function DecompressStoreBlock(state) + local buffer, buffer_size, ReadBits, ReadBytes, ReaderBitlenLeft, + SkipToByteBoundary, result_buffer = state.buffer, state.buffer_size, + state.ReadBits, state.ReadBytes, + state.ReaderBitlenLeft, + state.SkipToByteBoundary, + state.result_buffer + + SkipToByteBoundary() + local bytelen = ReadBits(16) + if ReaderBitlenLeft() < 0 then + return 2 -- available inflate data did not terminate + end + local bytelenComp = ReadBits(16) + if ReaderBitlenLeft() < 0 then + return 2 -- available inflate data did not terminate + end + + if bytelen % 256 + bytelenComp % 256 ~= 255 then + return -2 -- Not one's complement + end + if (bytelen - bytelen % 256) / 256 + (bytelenComp - bytelenComp % 256) / 256 ~= + 255 then + return -2 -- Not one's complement + end + + -- Note that ReadBytes will skip to the next byte boundary first. + buffer_size = ReadBytes(bytelen, buffer, buffer_size) + if buffer_size < 0 then + return 2 -- available inflate data did not terminate + end + + -- memory clean up when there are enough bytes in the buffer. + if buffer_size >= 65536 then + result_buffer[#result_buffer + 1] = table_concat(buffer, "", 1, 32768) + for i = 32769, buffer_size do buffer[i - 32768] = buffer[i] end + buffer_size = buffer_size - 32768 + buffer[buffer_size + 1] = nil + end + state.buffer_size = buffer_size + return 0 +end + +-- Decompress a fixed block +-- @param state decompression state that will be modified by this function. +-- @return 0 if succeeds other value if fails. +local function DecompressFixBlock(state) + return DecodeUntilEndOfBlock(state, _fix_block_literal_huffman_bitlen_count, + _fix_block_literal_huffman_to_deflate_code, 7, + _fix_block_dist_huffman_bitlen_count, + _fix_block_dist_huffman_to_deflate_code, 5) +end + +-- Decompress a dynamic block +-- @param state decompression state that will be modified by this function. +-- @return 0 if success, other value if fails. +local function DecompressDynamicBlock(state) + local ReadBits, Decode = state.ReadBits, state.Decode + local nlen = ReadBits(5) + 257 + local ndist = ReadBits(5) + 1 + local ncode = ReadBits(4) + 4 + if nlen > 286 or ndist > 30 then + -- dynamic block code description: too many length or distance codes + return -3 + end + + local rle_codes_huffman_bitlens = {} + + for i = 1, ncode do + rle_codes_huffman_bitlens[_rle_codes_huffman_bitlen_order[i]] = ReadBits(3) + end + + local rle_codes_err, rle_codes_huffman_bitlen_counts, + rle_codes_huffman_symbols, rle_codes_huffman_min_bitlen = + GetHuffmanForDecode(rle_codes_huffman_bitlens, 18, 7) + if rle_codes_err ~= 0 then -- Require complete code set here + -- dynamic block code description: code lengths codes incomplete + return -4 + end + + local lcodes_huffman_bitlens = {} + local dcodes_huffman_bitlens = {} + -- Read length/literal and distance code length tables + local index = 0 + while index < nlen + ndist do + local symbol -- Decoded value + local bitlen -- Last length to repeat + + symbol = Decode(rle_codes_huffman_bitlen_counts, rle_codes_huffman_symbols, + rle_codes_huffman_min_bitlen) + + if symbol < 0 then + return symbol -- Invalid symbol + elseif symbol < 16 then + if index < nlen then + lcodes_huffman_bitlens[index] = symbol + else + dcodes_huffman_bitlens[index - nlen] = symbol + end + index = index + 1 + else + bitlen = 0 + if symbol == 16 then + if index == 0 then + -- dynamic block code description: repeat lengths + -- with no first length + return -5 + end + if index - 1 < nlen then + bitlen = lcodes_huffman_bitlens[index - 1] + else + bitlen = dcodes_huffman_bitlens[index - nlen - 1] + end + symbol = 3 + ReadBits(2) + elseif symbol == 17 then -- Repeat zero 3..10 times + symbol = 3 + ReadBits(3) + else -- == 18, repeat zero 11.138 times + symbol = 11 + ReadBits(7) + end + if index + symbol > nlen + ndist then + -- dynamic block code description: + -- repeat more than specified lengths + return -6 + end + while symbol > 0 do -- Repeat last or zero symbol times + symbol = symbol - 1 + if index < nlen then + lcodes_huffman_bitlens[index] = bitlen + else + dcodes_huffman_bitlens[index - nlen] = bitlen + end + index = index + 1 + end + end + end + + if (lcodes_huffman_bitlens[256] or 0) == 0 then + -- dynamic block code description: missing end-of-block code + return -9 + end + + local lcodes_err, lcodes_huffman_bitlen_counts, lcodes_huffman_symbols, + lcodes_huffman_min_bitlen = GetHuffmanForDecode(lcodes_huffman_bitlens, + nlen - 1, 15) + -- dynamic block code description: invalid literal/length code lengths, + -- Incomplete code ok only for single length 1 code + if (lcodes_err ~= 0 and + (lcodes_err < 0 or nlen ~= (lcodes_huffman_bitlen_counts[0] or 0) + + (lcodes_huffman_bitlen_counts[1] or 0))) then return -7 end + + local dcodes_err, dcodes_huffman_bitlen_counts, dcodes_huffman_symbols, + dcodes_huffman_min_bitlen = GetHuffmanForDecode(dcodes_huffman_bitlens, + ndist - 1, 15) + -- dynamic block code description: invalid distance code lengths, + -- Incomplete code ok only for single length 1 code + if (dcodes_err ~= 0 and + (dcodes_err < 0 or ndist ~= (dcodes_huffman_bitlen_counts[0] or 0) + + (dcodes_huffman_bitlen_counts[1] or 0))) then return -8 end + + -- Build buffman table for literal/length codes + return DecodeUntilEndOfBlock(state, lcodes_huffman_bitlen_counts, + lcodes_huffman_symbols, + lcodes_huffman_min_bitlen, + dcodes_huffman_bitlen_counts, + dcodes_huffman_symbols, dcodes_huffman_min_bitlen) +end + +-- Decompress a deflate stream +-- @param state: a decompression state +-- @return the decompressed string if succeeds. nil if fails. +local function Inflate(state) + local ReadBits = state.ReadBits + + local is_last_block + while not is_last_block do + is_last_block = (ReadBits(1) == 1) + local block_type = ReadBits(2) + local status + if block_type == 0 then + status = DecompressStoreBlock(state) + elseif block_type == 1 then + status = DecompressFixBlock(state) + elseif block_type == 2 then + status = DecompressDynamicBlock(state) + else + return nil, -1 -- invalid block type (type == 3) + end + if status ~= 0 then return nil, status end + end + + state.result_buffer[#state.result_buffer + 1] = + table_concat(state.buffer, "", 1, state.buffer_size) + local result = table_concat(state.result_buffer) + return result +end + +-- @see LibDeflate:DecompressDeflate(str) +-- @see LibDeflate:DecompressDeflateWithDict(str, dictionary) +local function DecompressDeflateInternal(str, dictionary) + local state = CreateDecompressState(str, dictionary) + local result, status = Inflate(state) + if not result then return nil, status end + + local bitlen_left = state.ReaderBitlenLeft() + local bytelen_left = (bitlen_left - bitlen_left % 8) / 8 + return result, bytelen_left +end + +-- @see LibDeflate:DecompressZlib(str) +-- @see LibDeflate:DecompressZlibWithDict(str) +local function DecompressZlibInternal(str, dictionary) + local state = CreateDecompressState(str, dictionary) + local ReadBits = state.ReadBits + + local CMF = ReadBits(8) + if state.ReaderBitlenLeft() < 0 then + return nil, 2 -- available inflate data did not terminate + end + local CM = CMF % 16 + local CINFO = (CMF - CM) / 16 + if CM ~= 8 then + return nil, -12 -- invalid compression method + end + if CINFO > 7 then + return nil, -13 -- invalid window size + end + + local FLG = ReadBits(8) + if state.ReaderBitlenLeft() < 0 then + return nil, 2 -- available inflate data did not terminate + end + if (CMF * 256 + FLG) % 31 ~= 0 then + return nil, -14 -- invalid header checksum + end + + local FDIST = ((FLG - FLG % 32) / 32 % 2) + local FLEVEL = ((FLG - FLG % 64) / 64 % 4) -- luacheck: ignore FLEVEL + + if FDIST == 1 then + if not dictionary then + return nil, -16 -- need dictonary, but dictionary is not provided. + end + local byte3 = ReadBits(8) + local byte2 = ReadBits(8) + local byte1 = ReadBits(8) + local byte0 = ReadBits(8) + local actual_adler32 = byte3 * 16777216 + byte2 * 65536 + byte1 * 256 + + byte0 + if state.ReaderBitlenLeft() < 0 then + return nil, 2 -- available inflate data did not terminate + end + if not IsEqualAdler32(actual_adler32, dictionary.adler32) then + return nil, -17 -- dictionary adler32 does not match + end + end + local result, status = Inflate(state) + if not result then return nil, status end + state.SkipToByteBoundary() + + local adler_byte0 = ReadBits(8) + local adler_byte1 = ReadBits(8) + local adler_byte2 = ReadBits(8) + local adler_byte3 = ReadBits(8) + if state.ReaderBitlenLeft() < 0 then + return nil, 2 -- available inflate data did not terminate + end + + local adler32_expected = adler_byte0 * 16777216 + adler_byte1 * 65536 + + adler_byte2 * 256 + adler_byte3 + local adler32_actual = LibDeflate:Adler32(result) + if not IsEqualAdler32(adler32_expected, adler32_actual) then + return nil, -15 -- Adler32 checksum does not match + end + + local bitlen_left = state.ReaderBitlenLeft() + local bytelen_left = (bitlen_left - bitlen_left % 8) / 8 + return result, bytelen_left +end + +--- Decompress a raw deflate compressed data. +-- @param str [string] The data to be decompressed. +-- @return [string/nil] If the decompression succeeds, return the decompressed +-- data. If the decompression fails, return nil. You should check if this return +-- value is non-nil to know if the decompression succeeds. +-- @return [integer] If the decompression succeeds, return the number of +-- unprocessed bytes in the input compressed data. This return value is a +-- positive integer if the input data is a valid compressed data appended by an +-- arbitary non-empty string. This return value is 0 if the input data does not +-- contain any extra bytes.
+-- If the decompression fails (The first return value of this function is nil), +-- this return value is undefined. +-- @see LibDeflate:CompressDeflate +function LibDeflate:DecompressDeflate(str) + local arg_valid, arg_err = IsValidArguments(str) + if not arg_valid then + error(("Usage: LibDeflate:DecompressDeflate(str): " .. arg_err), 2) + end + return DecompressDeflateInternal(str) +end + +--- Decompress a raw deflate compressed data with a preset dictionary. +-- @param str [string] The data to be decompressed. +-- @param dictionary [table] The preset dictionary used by +-- LibDeflate:CompressDeflateWithDict when the compressed data is produced. +-- Decompression and compression must use the same dictionary. +-- Otherwise wrong decompressed data could be produced without generating any +-- error. +-- @return [string/nil] If the decompression succeeds, return the decompressed +-- data. If the decompression fails, return nil. You should check if this return +-- value is non-nil to know if the decompression succeeds. +-- @return [integer] If the decompression succeeds, return the number of +-- unprocessed bytes in the input compressed data. This return value is a +-- positive integer if the input data is a valid compressed data appended by an +-- arbitary non-empty string. This return value is 0 if the input data does not +-- contain any extra bytes.
+-- If the decompression fails (The first return value of this function is nil), +-- this return value is undefined. +-- @see LibDeflate:CompressDeflateWithDict +function LibDeflate:DecompressDeflateWithDict(str, dictionary) + local arg_valid, arg_err = IsValidArguments(str, true, dictionary) + if not arg_valid then + error(("Usage: LibDeflate:DecompressDeflateWithDict(str, dictionary): " .. + arg_err), 2) + end + return DecompressDeflateInternal(str, dictionary) +end + +--- Decompress a zlib compressed data. +-- @param str [string] The data to be decompressed +-- @return [string/nil] If the decompression succeeds, return the decompressed +-- data. If the decompression fails, return nil. You should check if this return +-- value is non-nil to know if the decompression succeeds. +-- @return [integer] If the decompression succeeds, return the number of +-- unprocessed bytes in the input compressed data. This return value is a +-- positive integer if the input data is a valid compressed data appended by an +-- arbitary non-empty string. This return value is 0 if the input data does not +-- contain any extra bytes.
+-- If the decompression fails (The first return value of this function is nil), +-- this return value is undefined. +-- @see LibDeflate:CompressZlib +function LibDeflate:DecompressZlib(str) + local arg_valid, arg_err = IsValidArguments(str) + if not arg_valid then + error(("Usage: LibDeflate:DecompressZlib(str): " .. arg_err), 2) + end + return DecompressZlibInternal(str) +end + +--- Decompress a zlib compressed data with a preset dictionary. +-- @param str [string] The data to be decompressed +-- @param dictionary [table] The preset dictionary used by +-- LibDeflate:CompressDeflateWithDict when the compressed data is produced. +-- Decompression and compression must use the same dictionary. +-- Otherwise wrong decompressed data could be produced without generating any +-- error. +-- @return [string/nil] If the decompression succeeds, return the decompressed +-- data. If the decompression fails, return nil. You should check if this return +-- value is non-nil to know if the decompression succeeds. +-- @return [integer] If the decompression succeeds, return the number of +-- unprocessed bytes in the input compressed data. This return value is a +-- positive integer if the input data is a valid compressed data appended by an +-- arbitary non-empty string. This return value is 0 if the input data does not +-- contain any extra bytes.
+-- If the decompression fails (The first return value of this function is nil), +-- this return value is undefined. +-- @see LibDeflate:CompressZlibWithDict +function LibDeflate:DecompressZlibWithDict(str, dictionary) + local arg_valid, arg_err = IsValidArguments(str, true, dictionary) + if not arg_valid then + error(("Usage: LibDeflate:DecompressZlibWithDict(str, dictionary): " .. + arg_err), 2) + end + return DecompressZlibInternal(str, dictionary) +end + +-- Calculate the huffman code of fixed block +do + _fix_block_literal_huffman_bitlen = {} + for sym = 0, 143 do _fix_block_literal_huffman_bitlen[sym] = 8 end + for sym = 144, 255 do _fix_block_literal_huffman_bitlen[sym] = 9 end + for sym = 256, 279 do _fix_block_literal_huffman_bitlen[sym] = 7 end + for sym = 280, 287 do _fix_block_literal_huffman_bitlen[sym] = 8 end + + _fix_block_dist_huffman_bitlen = {} + for dist = 0, 31 do _fix_block_dist_huffman_bitlen[dist] = 5 end + local status + status, _fix_block_literal_huffman_bitlen_count, _fix_block_literal_huffman_to_deflate_code = + GetHuffmanForDecode(_fix_block_literal_huffman_bitlen, 287, 9) + assert(status == 0) + status, _fix_block_dist_huffman_bitlen_count, _fix_block_dist_huffman_to_deflate_code = + GetHuffmanForDecode(_fix_block_dist_huffman_bitlen, 31, 5) + assert(status == 0) + + _fix_block_literal_huffman_code = GetHuffmanCodeFromBitlen( + _fix_block_literal_huffman_bitlen_count, + _fix_block_literal_huffman_bitlen, 287, 9) + _fix_block_dist_huffman_code = GetHuffmanCodeFromBitlen( + _fix_block_dist_huffman_bitlen_count, + _fix_block_dist_huffman_bitlen, 31, 5) +end + +-- Prefix encoding algorithm +-- Credits to LibCompress. +-- The code has been rewritten by the author of LibDeflate. +------------------------------------------------------------------------------ + +-- to be able to match any requested byte value, the search +-- string must be preprocessed characters to escape with %: +-- ( ) . % + - * ? [ ] ^ $ +-- "illegal" byte values: +-- 0 is replaces %z +local _gsub_escape_table = { + ["\000"] = "%z", + ["("] = "%(", + [")"] = "%)", + ["."] = "%.", + ["%"] = "%%", + ["+"] = "%+", + ["-"] = "%-", + ["*"] = "%*", + ["?"] = "%?", + ["["] = "%[", + ["]"] = "%]", + ["^"] = "%^", + ["$"] = "%$" +} + +local function escape_for_gsub(str) + return str:gsub("([%z%(%)%.%%%+%-%*%?%[%]%^%$])", _gsub_escape_table) +end + +--- Create a custom codec with encoder and decoder.
+-- This codec is used to convert an input string to make it not contain +-- some specific bytes. +-- This created codec and the parameters of this function do NOT take +-- localization into account. One byte (0-255) in the string is exactly one +-- character (0-255). +-- Credits to LibCompress. +-- The code has been rewritten by the author of LibDeflate.
+-- @param reserved_chars [string] The created encoder will ensure encoded +-- data does not contain any single character in reserved_chars. This parameter +-- should be non-empty. +-- @param escape_chars [string] The escape character(s) used in the created +-- codec. The codec converts any character included in reserved\_chars / +-- escape\_chars / map\_chars to (one escape char + one character not in +-- reserved\_chars / escape\_chars / map\_chars). +-- You usually only need to provide a length-1 string for this parameter. +-- Length-2 string is only needed when +-- reserved\_chars + escape\_chars + map\_chars is longer than 127. +-- This parameter should be non-empty. +-- @param map_chars [string] The created encoder will map every +-- reserved\_chars:sub(i, i) (1 <= i <= #map\_chars) to map\_chars:sub(i, i). +-- This parameter CAN be empty string. +-- @return [table/nil] If the codec cannot be created, return nil.
+-- If the codec can be created according to the given +-- parameters, return the codec, which is a encode/decode table. +-- The table contains two functions:
+-- t:Encode(str) returns the encoded string.
+-- t:Decode(str) returns the decoded string if succeeds. nil if fails. +-- @return [nil/string] If the codec is successfully created, return nil. +-- If not, return a string that describes the reason why the codec cannot be +-- created. +-- @usage +-- -- Create an encoder/decoder that maps all "\000" to "\003", +-- -- and escape "\001" (and "\002" and "\003") properly +-- local codec = LibDeflate:CreateCodec("\000\001", "\002", "\003") +-- +-- local encoded = codec:Encode(SOME_STRING) +-- -- "encoded" does not contain "\000" or "\001" +-- local decoded = codec:Decode(encoded) +-- -- assert(decoded == SOME_STRING) +function LibDeflate:CreateCodec(reserved_chars, escape_chars, map_chars) + if type(reserved_chars) ~= "string" or type(escape_chars) ~= "string" or + type(map_chars) ~= "string" then + error("Usage: LibDeflate:CreateCodec(reserved_chars," .. + " escape_chars, map_chars):" .. " All arguments must be string.", 2) + end + + if escape_chars == "" then return nil, "No escape characters supplied." end + if #reserved_chars < #map_chars then + return nil, "The number of reserved characters must be" .. + " at least as many as the number of mapped chars." + end + if reserved_chars == "" then return nil, "No characters to encode." end + + local encode_bytes = reserved_chars .. escape_chars .. map_chars + -- build list of bytes not available as a suffix to a prefix byte + local taken = {} + for i = 1, #encode_bytes do + local byte = string_byte(encode_bytes, i, i) + if taken[byte] then + return nil, "There must be no duplicate characters in the" .. + " concatenation of reserved_chars, escape_chars and" .. + " map_chars." + end + taken[byte] = true + end + + local decode_patterns = {} + local decode_repls = {} + + -- the encoding can be a single gsub + -- , but the decoding can require multiple gsubs + local encode_search = {} + local encode_translate = {} + + -- map single byte to single byte + if #map_chars > 0 then + local decode_search = {} + local decode_translate = {} + for i = 1, #map_chars do + local from = string_sub(reserved_chars, i, i) + local to = string_sub(map_chars, i, i) + encode_translate[from] = to + encode_search[#encode_search + 1] = from + decode_translate[to] = from + decode_search[#decode_search + 1] = to + end + decode_patterns[#decode_patterns + 1] = + "([" .. escape_for_gsub(table_concat(decode_search)) .. "])" + decode_repls[#decode_repls + 1] = decode_translate + end + + local escape_char_index = 1 + local escape_char = string_sub(escape_chars, escape_char_index, + escape_char_index) + -- map single byte to double-byte + local r = 0 -- suffix char value to the escapeChar + + local decode_search = {} + local decode_translate = {} + for i = 1, #encode_bytes do + local c = string_sub(encode_bytes, i, i) + if not encode_translate[c] then + while r >= 256 or taken[r] do + r = r + 1 + if r > 255 then -- switch to next escapeChar + decode_patterns[#decode_patterns + 1] = + escape_for_gsub(escape_char) .. "([" .. + escape_for_gsub(table_concat(decode_search)) .. "])" + decode_repls[#decode_repls + 1] = decode_translate + + escape_char_index = escape_char_index + 1 + escape_char = string_sub(escape_chars, escape_char_index, + escape_char_index) + r = 0 + decode_search = {} + decode_translate = {} + + if not escape_char or escape_char == "" then + -- actually I don't need to check + -- "not ecape_char", but what if Lua changes + -- the behavior of string.sub() in the future? + -- we are out of escape chars and we need more! + return nil, "Out of escape characters." + end + end + end + + local char_r = _byte_to_char[r] + encode_translate[c] = escape_char .. char_r + encode_search[#encode_search + 1] = c + decode_translate[char_r] = c + decode_search[#decode_search + 1] = char_r + r = r + 1 + end + if i == #encode_bytes then + decode_patterns[#decode_patterns + 1] = + escape_for_gsub(escape_char) .. "([" .. + escape_for_gsub(table_concat(decode_search)) .. "])" + decode_repls[#decode_repls + 1] = decode_translate + end + end + + local codec = {} + + local encode_pattern = "([" .. escape_for_gsub(table_concat(encode_search)) .. + "])" + local encode_repl = encode_translate + + function codec:Encode(str) + if type(str) ~= "string" then + error( + ("Usage: codec:Encode(str):" .. " 'str' - string expected got '%s'."):format( + type(str)), 2) + end + return string_gsub(str, encode_pattern, encode_repl) + end + + local decode_tblsize = #decode_patterns + local decode_fail_pattern = "([" .. escape_for_gsub(reserved_chars) .. "])" + + function codec:Decode(str) + if type(str) ~= "string" then + error( + ("Usage: codec:Decode(str):" .. " 'str' - string expected got '%s'."):format( + type(str)), 2) + end + if string_find(str, decode_fail_pattern) then return nil end + for i = 1, decode_tblsize do + str = string_gsub(str, decode_patterns[i], decode_repls[i]) + end + return str + end + + return codec +end + +local _addon_channel_codec + +local function GenerateWoWAddonChannelCodec() + return LibDeflate:CreateCodec("\000", "\001", "") +end + +--- Encode the string to make it ready to be transmitted in World of +-- Warcraft addon channel.
+-- The encoded string is guaranteed to contain no NULL ("\000") character. +-- @param str [string] The string to be encoded. +-- @return The encoded string. +-- @see LibDeflate:DecodeForWoWAddonChannel +function LibDeflate:EncodeForWoWAddonChannel(str) + if type(str) ~= "string" then + error(("Usage: LibDeflate:EncodeForWoWAddonChannel(str):" .. + " 'str' - string expected got '%s'."):format(type(str)), 2) + end + if not _addon_channel_codec then + _addon_channel_codec = GenerateWoWAddonChannelCodec() + end + return _addon_channel_codec:Encode(str) +end + +--- Decode the string produced by LibDeflate:EncodeForWoWAddonChannel +-- @param str [string] The string to be decoded. +-- @return [string/nil] The decoded string if succeeds. nil if fails. +-- @see LibDeflate:EncodeForWoWAddonChannel +function LibDeflate:DecodeForWoWAddonChannel(str) + if type(str) ~= "string" then + error(("Usage: LibDeflate:DecodeForWoWAddonChannel(str):" .. + " 'str' - string expected got '%s'."):format(type(str)), 2) + end + if not _addon_channel_codec then + _addon_channel_codec = GenerateWoWAddonChannelCodec() + end + return _addon_channel_codec:Decode(str) +end + +-- For World of Warcraft Chat Channel Encoding +-- Credits to LibCompress. +-- The code has been rewritten by the author of LibDeflate.
+-- Following byte values are not allowed: +-- \000, s, S, \010, \013, \124, % +-- Because SendChatMessage will error +-- if an UTF8 multibyte character is incomplete, +-- all character values above 127 have to be encoded to avoid this. +-- This costs quite a bit of bandwidth (about 13-14%) +-- Also, because drunken status is unknown for the received +-- , strings used with SendChatMessage should be terminated with +-- an identifying byte value, after which the server MAY add "...hic!" +-- or as much as it can fit(!). +-- Pass the identifying byte as a reserved character to this function +-- to ensure the encoding doesn't contain that value. +-- or use this: local message, match = arg1:gsub("^(.*)\029.-$", "%1") +-- arg1 is message from channel, \029 is the string terminator +-- , but may be used in the encoded datastream as well. :-) +-- This encoding will expand data anywhere from: +-- 0% (average with pure ascii text) +-- 53.5% (average with random data valued zero to 255) +-- 100% (only encoding data that encodes to two bytes) +local function GenerateWoWChatChannelCodec() + local r = {} + for i = 128, 255 do r[#r + 1] = _byte_to_char[i] end + + local reserved_chars = "sS\000\010\013\124%" .. table_concat(r) + return LibDeflate:CreateCodec(reserved_chars, "\029\031", "\015\020") +end + +local _chat_channel_codec + +--- Encode the string to make it ready to be transmitted in World of +-- Warcraft chat channel.
+-- See also https://wow.gamepedia.com/ValidChatMessageCharacters +-- @param str [string] The string to be encoded. +-- @return [string] The encoded string. +-- @see LibDeflate:DecodeForWoWChatChannel +function LibDeflate:EncodeForWoWChatChannel(str) + if type(str) ~= "string" then + error(("Usage: LibDeflate:EncodeForWoWChatChannel(str):" .. + " 'str' - string expected got '%s'."):format(type(str)), 2) + end + if not _chat_channel_codec then + _chat_channel_codec = GenerateWoWChatChannelCodec() + end + return _chat_channel_codec:Encode(str) +end + +--- Decode the string produced by LibDeflate:EncodeForWoWChatChannel. +-- @param str [string] The string to be decoded. +-- @return [string/nil] The decoded string if succeeds. nil if fails. +-- @see LibDeflate:EncodeForWoWChatChannel +function LibDeflate:DecodeForWoWChatChannel(str) + if type(str) ~= "string" then + error(("Usage: LibDeflate:DecodeForWoWChatChannel(str):" .. + " 'str' - string expected got '%s'."):format(type(str)), 2) + end + if not _chat_channel_codec then + _chat_channel_codec = GenerateWoWChatChannelCodec() + end + return _chat_channel_codec:Decode(str) +end + +-- Credits to WeakAuras2 and Galmok for the 6 bit encoding algorithm. +-- The code has been rewritten by the author of LibDeflate. +-- The result of encoding will be 25% larger than the +-- origin string, but every single byte of the encoding result will be +-- printable characters as the following. +local _byte_to_6bit_char = { + [0] = "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + "Z", + "0", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "(", + ")" +} + +local _6bit_to_byte = { + [97] = 0, + [98] = 1, + [99] = 2, + [100] = 3, + [101] = 4, + [102] = 5, + [103] = 6, + [104] = 7, + [105] = 8, + [106] = 9, + [107] = 10, + [108] = 11, + [109] = 12, + [110] = 13, + [111] = 14, + [112] = 15, + [113] = 16, + [114] = 17, + [115] = 18, + [116] = 19, + [117] = 20, + [118] = 21, + [119] = 22, + [120] = 23, + [121] = 24, + [122] = 25, + [65] = 26, + [66] = 27, + [67] = 28, + [68] = 29, + [69] = 30, + [70] = 31, + [71] = 32, + [72] = 33, + [73] = 34, + [74] = 35, + [75] = 36, + [76] = 37, + [77] = 38, + [78] = 39, + [79] = 40, + [80] = 41, + [81] = 42, + [82] = 43, + [83] = 44, + [84] = 45, + [85] = 46, + [86] = 47, + [87] = 48, + [88] = 49, + [89] = 50, + [90] = 51, + [48] = 52, + [49] = 53, + [50] = 54, + [51] = 55, + [52] = 56, + [53] = 57, + [54] = 58, + [55] = 59, + [56] = 60, + [57] = 61, + [40] = 62, + [41] = 63 +} + +--- Encode the string to make it printable.
+-- +-- Credit to WeakAuras2, this function is equivalant to the implementation +-- it is using right now.
+-- The code has been rewritten by the author of LibDeflate.
+-- The encoded string will be 25% larger than the origin string. However, every +-- single byte of the encoded string will be one of 64 printable ASCII +-- characters, which are can be easier copied, pasted and displayed. +-- (26 lowercase letters, 26 uppercase letters, 10 numbers digits, +-- left parenthese, or right parenthese) +-- @param str [string] The string to be encoded. +-- @return [string] The encoded string. +function LibDeflate:EncodeForPrint(str) + if type(str) ~= "string" then + error(("Usage: LibDeflate:EncodeForPrint(str):" .. + " 'str' - string expected got '%s'."):format(type(str)), 2) + end + local strlen = #str + local strlenMinus2 = strlen - 2 + local i = 1 + local buffer = {} + local buffer_size = 0 + while i <= strlenMinus2 do + local x1, x2, x3 = string_byte(str, i, i + 2) + i = i + 3 + local cache = x1 + x2 * 256 + x3 * 65536 + local b1 = cache % 64 + cache = (cache - b1) / 64 + local b2 = cache % 64 + cache = (cache - b2) / 64 + local b3 = cache % 64 + local b4 = (cache - b3) / 64 + buffer_size = buffer_size + 1 + buffer[buffer_size] = _byte_to_6bit_char[b1] .. _byte_to_6bit_char[b2] .. + _byte_to_6bit_char[b3] .. _byte_to_6bit_char[b4] + end + + local cache = 0 + local cache_bitlen = 0 + while i <= strlen do + local x = string_byte(str, i, i) + cache = cache + x * _pow2[cache_bitlen] + cache_bitlen = cache_bitlen + 8 + i = i + 1 + end + while cache_bitlen > 0 do + local bit6 = cache % 64 + buffer_size = buffer_size + 1 + buffer[buffer_size] = _byte_to_6bit_char[bit6] + cache = (cache - bit6) / 64 + cache_bitlen = cache_bitlen - 6 + end + + return table_concat(buffer) +end + +--- Decode the printable string produced by LibDeflate:EncodeForPrint. +-- "str" will have its prefixed and trailing control characters or space +-- removed before it is decoded, so it is easier to use if "str" comes form +-- user copy and paste with some prefixed or trailing spaces. +-- Then decode fails if the string contains any characters cant be produced by +-- LibDeflate:EncodeForPrint. That means, decode fails if the string contains a +-- characters NOT one of 26 lowercase letters, 26 uppercase letters, +-- 10 numbers digits, left parenthese, or right parenthese. +-- @param str [string] The string to be decoded +-- @return [string/nil] The decoded string if succeeds. nil if fails. +function LibDeflate:DecodeForPrint(str) + if type(str) ~= "string" then + error(("Usage: LibDeflate:DecodeForPrint(str):" .. + " 'str' - string expected got '%s'."):format(type(str)), 2) + end + str = str:gsub("^[%c ]+", "") + str = str:gsub("[%c ]+$", "") + + local strlen = #str + if strlen == 1 then return nil end + local strlenMinus3 = strlen - 3 + local i = 1 + local buffer = {} + local buffer_size = 0 + while i <= strlenMinus3 do + local x1, x2, x3, x4 = string_byte(str, i, i + 3) + x1 = _6bit_to_byte[x1] + x2 = _6bit_to_byte[x2] + x3 = _6bit_to_byte[x3] + x4 = _6bit_to_byte[x4] + if not (x1 and x2 and x3 and x4) then return nil end + i = i + 4 + local cache = x1 + x2 * 64 + x3 * 4096 + x4 * 262144 + local b1 = cache % 256 + cache = (cache - b1) / 256 + local b2 = cache % 256 + local b3 = (cache - b2) / 256 + buffer_size = buffer_size + 1 + buffer[buffer_size] = _byte_to_char[b1] .. _byte_to_char[b2] .. + _byte_to_char[b3] + end + + local cache = 0 + local cache_bitlen = 0 + while i <= strlen do + local x = string_byte(str, i, i) + x = _6bit_to_byte[x] + if not x then return nil end + cache = cache + x * _pow2[cache_bitlen] + cache_bitlen = cache_bitlen + 6 + i = i + 1 + end + + while cache_bitlen >= 8 do + local byte = cache % 256 + buffer_size = buffer_size + 1 + buffer[buffer_size] = _byte_to_char[byte] + cache = (cache - byte) / 256 + cache_bitlen = cache_bitlen - 8 + end + + return table_concat(buffer) +end + +local function InternalClearCache() + _chat_channel_codec = nil + _addon_channel_codec = nil +end + +-- For test. Don't use the functions in this table for real application. +-- Stuffs in this table is subject to change. +LibDeflate.internals = { + LoadStringToTable = LoadStringToTable, + IsValidDictionary = IsValidDictionary, + IsEqualAdler32 = IsEqualAdler32, + _byte_to_6bit_char = _byte_to_6bit_char, + _6bit_to_byte = _6bit_to_byte, + InternalClearCache = InternalClearCache +} + +--[[-- Commandline options +@class table +@name CommandlineOptions +@usage lua LibDeflate.lua [OPTION] [INPUT] [OUTPUT] +\-0 store only. no compression. +\-1 fastest compression. +\-9 slowest and best compression. +\-d do decompression instead of compression. +\--dict specify the file that contains +the entire preset dictionary. +\-h give this help. +\--strategy specify a special compression strategy. +\-v print the version and copyright info. +\--zlib use zlib format instead of raw deflate. +]] + +-- currently no plan to support stdin and stdout. +-- Because Lua in Windows does not set stdout with binary mode. +if io and os and debug and _G.arg then + local io = io + local os = os + local debug = debug + local arg = _G.arg + local debug_info = debug.getinfo(1) + if debug_info.source == arg[0] or debug_info.short_src == arg[0] then + -- We are indeed runnning THIS file from the commandline. + local input + local output + local i = 1 + local status + local is_zlib = false + local is_decompress = false + local level + local strategy + local dictionary + while (arg[i]) do + local a = arg[i] + if a == "-h" then + print(LibDeflate._COPYRIGHT .. + "\nUsage: lua LibDeflate.lua [OPTION] [INPUT] [OUTPUT]\n" .. + " -0 store only. no compression.\n" .. + " -1 fastest compression.\n" .. + " -9 slowest and best compression.\n" .. + " -d do decompression instead of compression.\n" .. + " --dict specify the file that contains" .. + " the entire preset dictionary.\n" .. + " -h give this help.\n" .. + " --strategy " .. + " specify a special compression strategy.\n" .. + " -v print the version and copyright info.\n" .. + " --zlib use zlib format instead of raw deflate.\n") + os.exit(0) + elseif a == "-v" then + print(LibDeflate._COPYRIGHT) + os.exit(0) + elseif a:find("^%-[0-9]$") then + level = tonumber(a:sub(2, 2)) + elseif a == "-d" then + is_decompress = true + elseif a == "--dict" then + i = i + 1 + local dict_filename = arg[i] + if not dict_filename then + io.stderr:write("You must speicify the dict filename") + os.exit(1) + end + local dict_file, dict_status = io.open(dict_filename, "rb") + if not dict_file then + io.stderr:write( + ("LibDeflate: Cannot read the dictionary file '%s': %s"):format( + dict_filename, dict_status)) + os.exit(1) + end + local dict_str = dict_file:read("*all") + dict_file:close() + -- In your lua program, you should pass in adler32 as a CONSTANT + -- , so it actually prevent you from modifying dictionary + -- unintentionally during the program development. I do this + -- here just because no convenient way to verify in commandline. + dictionary = LibDeflate:CreateDictionary(dict_str, #dict_str, + LibDeflate:Adler32(dict_str)) + elseif a == "--strategy" then + -- Not sure if I should check error here + -- If I do, redudant code. + i = i + 1 + strategy = arg[i] + elseif a == "--zlib" then + is_zlib = true + elseif a:find("^%-") then + io.stderr:write(("LibDeflate: Invalid argument: %s"):format(a)) + os.exit(1) + else + if not input then + input, status = io.open(a, "rb") + if not input then + io.stderr:write( + ("LibDeflate: Cannot read the file '%s': %s"):format(a, tostring( + status))) + os.exit(1) + end + elseif not output then + output, status = io.open(a, "wb") + if not output then + io.stderr:write( + ("LibDeflate: Cannot write the file '%s': %s"):format(a, tostring( + status))) + os.exit(1) + end + end + end + i = i + 1 + end -- while (arg[i]) + + if not input or not output then + io.stderr:write("LibDeflate:" .. + " You must specify both input and output files.") + os.exit(1) + end + + local input_data = input:read("*all") + local configs = {level = level, strategy = strategy} + local output_data + if not is_decompress then + if not is_zlib then + if not dictionary then + output_data = LibDeflate:CompressDeflate(input_data, configs) + else + output_data = LibDeflate:CompressDeflateWithDict(input_data, + dictionary, configs) + end + else + if not dictionary then + output_data = LibDeflate:CompressZlib(input_data, configs) + else + output_data = LibDeflate:CompressZlibWithDict(input_data, dictionary, + configs) + end + end + else + if not is_zlib then + if not dictionary then + output_data = LibDeflate:DecompressDeflate(input_data) + else + output_data = LibDeflate:DecompressDeflateWithDict(input_data, + dictionary) + end + else + if not dictionary then + output_data = LibDeflate:DecompressZlib(input_data) + else + output_data = + LibDeflate:DecompressZlibWithDict(input_data, dictionary) + end + end + end + + if not output_data then + io.stderr:write("LibDeflate: Decompress fails.") + os.exit(1) + end + + output:write(output_data) + if input and input ~= io.stdin then input:close() end + if output and output ~= io.stdout then output:close() end + + io.stderr:write(("Successfully writes %d bytes"):format(output_data:len())) + os.exit(0) + end +end + +return LibDeflate diff --git a/lua/README.md b/lua/README.md new file mode 100644 index 0000000..1646ab6 --- /dev/null +++ b/lua/README.md @@ -0,0 +1,58 @@ +# Mixbox for Lua + +Compatible with Lua 5.1+ + +## Usage + +```lua +local mixbox = require("mixbox") + +local rgb1 = {0, 33, 133} -- blue +local rgb2 = {252, 211, 0} -- yellow +t = 0.5 -- mixing ratio + +local rgb = mixbox.lerp(rgb1, rgb2, t) + +print(table.unpack(rgb)) +``` + +## Mixing Multiple Colors + +```lua +local z1 = mixbox.rgb_to_latent(rgb1) +local z2 = mixbox.rgb_to_latent(rgb2) +local z3 = mixbox.rgb_to_latent(rgb3) + +local z_mix = {} + +for i = 1, mixbox.LATENT_SIZE do -- mix together: + z_mix[i] = (0.3*z1[i] + -- 30% of rgb1 + 0.6*z2[i] + -- 60% of rgb2 + 0.1*z3[i]) -- 10% of rgb3 + +rgb_mix = mixbox.latent_to_rgb(z_mix) +``` + +## Pigment Colors + +| Pigment | | RGB | Float RGB | Linear RGB | +| -------------------- | -------------------------------------------------------------------------- | :---------: | :-----------------: | :-----------------: | +| Cadmium Yellow | | 254, 236, 0 | 0.996, 0.925, 0.0 | 0.991, 0.839, 0.0 | +| Hansa Yellow | | 252, 211, 0 | 0.988, 0.827, 0.0 | 0.973, 0.651, 0.0 | +| Cadmium Orange | | 255, 105, 0 | 1.0, 0.412, 0.0 | 1.0, 0.141, 0.0 | +| Cadmium Red | | 255, 39, 2 | 1.0, 0.153, 0.008 | 1.0, 0.02, 0.001 | +| Quinacridone Magenta | | 128, 2, 46 | 0.502, 0.008, 0.18 | 0.216, 0.001, 0.027 | +| Cobalt Violet | | 78, 0, 66 | 0.306, 0.0, 0.259 | 0.076, 0.0, 0.054 | +| Ultramarine Blue | | 25, 0, 89 | 0.098, 0.0, 0.349 | 0.01, 0.0, 0.1 | +| Cobalt Blue | | 0, 33, 133 | 0.0, 0.129, 0.522 | 0.0, 0.015, 0.235 | +| Phthalo Blue | | 13, 27, 68 | 0.051, 0.106, 0.267 | 0.004, 0.011, 0.058 | +| Phthalo Green | | 0, 60, 50 | 0.0, 0.235, 0.196 | 0.0, 0.045, 0.032 | +| Permanent Green | | 7, 109, 22 | 0.027, 0.427, 0.086 | 0.002, 0.153, 0.008 | +| Sap Green | | 107, 148, 4 | 0.42, 0.58, 0.016 | 0.147, 0.296, 0.001 | +| Burnt Sienna | | 123, 72, 0 | 0.482, 0.282, 0.0 | 0.198, 0.065, 0.0 | + +## License + +Copyright (c) 2022, Secret Weapons. All rights reserved.
+Mixbox is provided under the CC BY-NC 4.0 license for non-commercial use only.
+If you want to obtain commercial license, please contact: mixbox@scrtwpns.com diff --git a/lua/base64.lua b/lua/base64.lua new file mode 100644 index 0000000..32de332 --- /dev/null +++ b/lua/base64.lua @@ -0,0 +1,201 @@ +--[[ + + base64 -- v1.5.3 public domain Lua base64 encoder/decoder + no warranty implied; use at your own risk + + Needs bit32.extract function. If not present it's implemented using BitOp + or Lua 5.3 native bit operators. For Lua 5.1 fallbacks to pure Lua + implementation inspired by Rici Lake's post: + http://ricilake.blogspot.co.uk/2007/10/iterating-bits-in-lua.html + + author: Ilya Kolbin (iskolbin@gmail.com) + url: github.com/iskolbin/lbase64 + + COMPATIBILITY + + Lua 5.1+, LuaJIT + + LICENSE + + See end of file for license information. + +--]] + + +local base64 = {} + +local extract = _G.bit32 and _G.bit32.extract -- Lua 5.2/Lua 5.3 in compatibility mode +if not extract then + if _G.bit then -- LuaJIT + local shl, shr, band = _G.bit.lshift, _G.bit.rshift, _G.bit.band + extract = function( v, from, width ) + return band( shr( v, from ), shl( 1, width ) - 1 ) + end + elseif _G._VERSION == "Lua 5.1" then + extract = function( v, from, width ) + local w = 0 + local flag = 2^from + for i = 0, width-1 do + local flag2 = flag + flag + if v % flag2 >= flag then + w = w + 2^i + end + flag = flag2 + end + return w + end + else -- Lua 5.3+ + extract = load[[return function( v, from, width ) + return ( v >> from ) & ((1 << width) - 1) + end]]() + end +end + + +function base64.makeencoder( s62, s63, spad ) + local encoder = {} + for b64code, char in pairs{[0]='A','B','C','D','E','F','G','H','I','J', + 'K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y', + 'Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n', + 'o','p','q','r','s','t','u','v','w','x','y','z','0','1','2', + '3','4','5','6','7','8','9',s62 or '+',s63 or'/',spad or'='} do + encoder[b64code] = char:byte() + end + return encoder +end + +function base64.makedecoder( s62, s63, spad ) + local decoder = {} + for b64code, charcode in pairs( base64.makeencoder( s62, s63, spad )) do + decoder[charcode] = b64code + end + return decoder +end + +local DEFAULT_ENCODER = base64.makeencoder() +local DEFAULT_DECODER = base64.makedecoder() + +local char, concat = string.char, table.concat + +function base64.encode( str, encoder, usecaching ) + encoder = encoder or DEFAULT_ENCODER + local t, k, n = {}, 1, #str + local lastn = n % 3 + local cache = {} + for i = 1, n-lastn, 3 do + local a, b, c = str:byte( i, i+2 ) + local v = a*0x10000 + b*0x100 + c + local s + if usecaching then + s = cache[v] + if not s then + s = char(encoder[extract(v,18,6)], encoder[extract(v,12,6)], encoder[extract(v,6,6)], encoder[extract(v,0,6)]) + cache[v] = s + end + else + s = char(encoder[extract(v,18,6)], encoder[extract(v,12,6)], encoder[extract(v,6,6)], encoder[extract(v,0,6)]) + end + t[k] = s + k = k + 1 + end + if lastn == 2 then + local a, b = str:byte( n-1, n ) + local v = a*0x10000 + b*0x100 + t[k] = char(encoder[extract(v,18,6)], encoder[extract(v,12,6)], encoder[extract(v,6,6)], encoder[64]) + elseif lastn == 1 then + local v = str:byte( n )*0x10000 + t[k] = char(encoder[extract(v,18,6)], encoder[extract(v,12,6)], encoder[64], encoder[64]) + end + return concat( t ) +end + +function base64.decode( b64, decoder, usecaching ) + decoder = decoder or DEFAULT_DECODER + local pattern = '[^%w%+%/%=]' + if decoder then + local s62, s63 + for charcode, b64code in pairs( decoder ) do + if b64code == 62 then s62 = charcode + elseif b64code == 63 then s63 = charcode + end + end + pattern = ('[^%%w%%%s%%%s%%=]'):format( char(s62), char(s63) ) + end + b64 = b64:gsub( pattern, '' ) + local cache = usecaching and {} + local t, k = {}, 1 + local n = #b64 + local padding = b64:sub(-2) == '==' and 2 or b64:sub(-1) == '=' and 1 or 0 + for i = 1, padding > 0 and n-4 or n, 4 do + local a, b, c, d = b64:byte( i, i+3 ) + local s + if usecaching then + local v0 = a*0x1000000 + b*0x10000 + c*0x100 + d + s = cache[v0] + if not s then + local v = decoder[a]*0x40000 + decoder[b]*0x1000 + decoder[c]*0x40 + decoder[d] + s = char( extract(v,16,8), extract(v,8,8), extract(v,0,8)) + cache[v0] = s + end + else + local v = decoder[a]*0x40000 + decoder[b]*0x1000 + decoder[c]*0x40 + decoder[d] + s = char( extract(v,16,8), extract(v,8,8), extract(v,0,8)) + end + t[k] = s + k = k + 1 + end + if padding == 1 then + local a, b, c = b64:byte( n-3, n-1 ) + local v = decoder[a]*0x40000 + decoder[b]*0x1000 + decoder[c]*0x40 + t[k] = char( extract(v,16,8), extract(v,8,8)) + elseif padding == 2 then + local a, b = b64:byte( n-3, n-2 ) + local v = decoder[a]*0x40000 + decoder[b]*0x1000 + t[k] = char( extract(v,16,8)) + end + return concat( t ) +end + +return base64 + +--[[ +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2018 Ilya Kolbin +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +--]] diff --git a/lua/examples/hello.lua b/lua/examples/hello.lua new file mode 100644 index 0000000..33d651a --- /dev/null +++ b/lua/examples/hello.lua @@ -0,0 +1,9 @@ +local mixbox = require("mixbox") + +local rgb1 = {0, 33, 133} -- blue +local rgb2 = {252, 211, 0} -- yellow +t = 0.5 -- mixing ratio + +local rgb = mixbox.lerp(rgb1, rgb2, t) + +print(table.unpack(rgb)) \ No newline at end of file diff --git a/lua/mixbox.lua b/lua/mixbox.lua new file mode 100644 index 0000000..7ab104c --- /dev/null +++ b/lua/mixbox.lua @@ -0,0 +1,332 @@ +--[[ +========================================================== + MIXBOX 2.0 (c) 2022 Secret Weapons. All rights reserved. + License: Creative Commons Attribution-NonCommercial 4.0 + Authors: Sarka Sochorova and Ondrej Jamriska +========================================================== + +Natural color mixing based on real pigments. + +BASIC USAGE + + local Mixbox = require("mixbox") + + local rgb = Mixbox.lerp(rgb1, rgb2, t) + +MULTI-COLOR MIXING + + local z1 = Mixbox.rgb_to_latent(rgb1) + local z2 = Mixbox.rgb_to_latent(rgb2) + local z3 = Mixbox.rgb_to_latent(rgb3) + + local z_mix = {} + + for i = 1, Mixbox.LATENT_SIZE do -- mix together: + z_mix[i] = (0.3*z1[i] + -- 30% of rgb1 + 0.6*z2[i] + -- 60% of rgb2 + 0.1*z3[i]) -- 10% of rgb3 + + rgb_mix = Mixbox.latent_to_rgb(z_mix) + +PIGMENT COLORS + + Cadmium Yellow 254, 236, 0 + Hansa Yellow 252, 211, 0 + Cadmium Orange 255, 105, 0 + Cadmium Red 255, 39, 2 + Quinacridone Magenta 128, 2, 46 + Cobalt Violet 78, 0, 66 + Ultramarine Blue 25, 0, 89 + Cobalt Blue 0, 33, 133 + Phthalo Blue 13, 27, 68 + Phthalo Green 0, 60, 50 + Permanent Green 7, 109, 22 + Sap Green 107, 148, 4 + Burnt Sienna 123, 72, 0 + +LICENSING + + If you want to obtain commercial license, please + contact us at: mixbox@scrtwpns.com + +]] + +local base64 = require("base64") +local bit32 = bit32 or require("bit32") +local LibDeflate = require("LibDeflate") + +local LATENT_SIZE = 7 + +local min = math.min +local max = math.max +local pow = math.pow +local int = math.floor +local round = math.round +local lut + +function lerp(color1, color2, t) + local len1 = #color1 + local len2 = #color2 + + local latent1 = rgb_to_latent(color1) + local latent2 = rgb_to_latent(color2) + + local rgb = latent_to_rgb(lerp_latent(latent1, latent2, t)) + + if len1 == 3 and len2 == 3 then + return rgb + end + + local a1 = len1 > 3 and color1[3] or 255 + local a2 = len2 > 3 and color2[3] or 255 + local a = round((1.0-t)*a1 + t*a2) + + return {rgb[0], rgb[1], rgb[2], a} +end + +function lerp_float(color1, color2, t) + local len1 = #color1 + local len2 = #color2 + + local latent1 = float_rgb_to_latent(color1) + local latent2 = float_rgb_to_latent(color2) + + local rgb = latent_to_float_rgb(_lerp_latent(latent1, latent2, t)) + + if len1 == 3 and len2 == 3 then + return rgb + end + + local a1 = len1 > 3 and color1[4] or 255 + local a2 = len2 > 3 and color2[4] or 255 + local a = (1.0-t)*a1 + t*a2 + + return {rgb[1], rgb[2], rgb[3], a} +end + +function lerp_linear_float(color1, color2, t) + local len1 = #color1 + local len2 = #color2 + + local latent1 = linear_float_rgb_to_latent(color1) + local latent2 = linear_float_rgb_to_latent(color2) + + local rgb = latent_to_linear_float_rgb(_lerp_latent(latent1, latent2, t)) + + if len1 == 3 and len2 == 3 then + return rgb + end + + local a1 = len1 > 3 and color1[4] or 255 + local a2 = len2 > 3 and color2[4] or 255 + local a = (1.0-t)*a1 + t*a2 + + return {rgb[1], rgb[2], rgb[3], a} +end + +function rgb_to_latent(rgb) + return float_rgb_to_latent({rgb[1] / 255.0, rgb[2] / 255.0, rgb[3] / 255.0}) +end + +function latent_to_rgb(latent) + local rgb = eval_polynomial(latent[1], latent[2], latent[3], latent[4]) + return { + int(round(clamp01(rgb[1] + latent[5]) * 255.0)), + int(round(clamp01(rgb[2] + latent[6]) * 255.0)), + int(round(clamp01(rgb[3] + latent[7]) * 255.0)) + } +end + +function float_rgb_to_latent(rgb) + local r = clamp01(rgb[1]) + local g = clamp01(rgb[2]) + local b = clamp01(rgb[3]) + + local x = r * 63.0 + local y = g * 63.0 + local z = b * 63.0 + + local ix = int(x) + local iy = int(y) + local iz = int(z) + + local tx = x - ix + local ty = y - iy + local tz = z - iz + + local xyz = bit32.band(ix + iy*64 + iz*64*64, 0x3FFFF) + 1 + + local c0 = 0.0 + local c1 = 0.0 + local c2 = 0.0 + local w + + w = (1.0-tx)*(1.0-ty)*(1.0-tz) c0 = c0 + w*lut[xyz+ 192] c1 = c1 + w*lut[xyz+262336] c2 = c2 + w*lut[xyz+524480] + w = ( tx)*(1.0-ty)*(1.0-tz) c0 = c0 + w*lut[xyz+ 193] c1 = c1 + w*lut[xyz+262337] c2 = c2 + w*lut[xyz+524481] + w = (1.0-tx)*( ty)*(1.0-tz) c0 = c0 + w*lut[xyz+ 256] c1 = c1 + w*lut[xyz+262400] c2 = c2 + w*lut[xyz+524544] + w = ( tx)*( ty)*(1.0-tz) c0 = c0 + w*lut[xyz+ 257] c1 = c1 + w*lut[xyz+262401] c2 = c2 + w*lut[xyz+524545] + w = (1.0-tx)*(1.0-ty)*( tz) c0 = c0 + w*lut[xyz+4288] c1 = c1 + w*lut[xyz+266432] c2 = c2 + w*lut[xyz+528576] + w = ( tx)*(1.0-ty)*( tz) c0 = c0 + w*lut[xyz+4289] c1 = c1 + w*lut[xyz+266433] c2 = c2 + w*lut[xyz+528577] + w = (1.0-tx)*( ty)*( tz) c0 = c0 + w*lut[xyz+4352] c1 = c1 + w*lut[xyz+266496] c2 = c2 + w*lut[xyz+528640] + w = ( tx)*( ty)*( tz) c0 = c0 + w*lut[xyz+4353] c1 = c1 + w*lut[xyz+266497] c2 = c2 + w*lut[xyz+528641] + + c0 = c0 / 255.0 + c1 = c1 / 255.0 + c2 = c2 / 255.0 + + local c3 = 1.0 - (c0 + c1 + c2) + + local mixrgb = eval_polynomial(c0, c1, c2, c3) + + return { + c0, + c1, + c2, + c3, + r - mixrgb[1], + g - mixrgb[2], + b - mixrgb[3], + } +end + +function latent_to_float_rgb(latent) + local rgb = eval_polynomial(latent[1], latent[2], latent[3], latent[4]) + return { + clamp01(rgb[1] + latent[5]), + clamp01(rgb[2] + latent[6]), + clamp01(rgb[3] + latent[7]) + } +end + +function linear_float_rgb_to_latent(rgb) + return float_rgb_to_latent({ + linear_to_srgb(rgb[1]), + linear_to_srgb(rgb[2]), + linear_to_srgb(rgb[3]) + }) +end + +function latent_to_linear_float_rgb(latent) + local rgb = latent_to_float_rgb(latent) + + return { + srgb_to_linear(rgb[1]), + srgb_to_linear(rgb[2]), + srgb_to_linear(rgb[3]) + } +end + +function round(num) + local fractional_part = num % 1 + if fractional_part == 0.5 or fractional_part == -0.5 then + local integer_part = num - fractional_part + if integer_part % 2 == 0 then + return integer_part + else + return integer_part + math.sign(num) + end + else + return math.floor(num + 0.5) + end +end + +function lerp_latent(latent1, latent2, t) + local result = {} + for i = 1, LATENT_SIZE do + table.insert(result, (1.0-t)*latent1[i] + t*latent2[i]) + end + return result +end + +function clamp01(x) + return min(max(x, 0.0), 1.0) +end + +function srgb_to_linear(x) + return x >= 0.04045 and pow((x+0.055)/1.055, 2.4) or x/12.92 +end + +function linear_to_srgb(x) + return x >= 0.0031308 and 1.055*pow(x, 1.0/2.4)-0.055 or 12.92*x +end + +function eval_polynomial(c0, c1, c2, c3) + local r = 0.0 + local g = 0.0 + local b = 0.0 + + local c00 = c0 * c0 + local c11 = c1 * c1 + local c22 = c2 * c2 + local c33 = c3 * c3 + local c01 = c0 * c1 + local c02 = c0 * c2 + local c12 = c1 * c2 + local w + + w = c0*c00 r = r + 00.07717053*w g = g + 00.02826978*w b = b + 00.24832992*w + w = c1*c11 r = r + 00.95912302*w g = g + 00.80256528*w b = b + 00.03561839*w + w = c2*c22 r = r + 00.74683774*w g = g + 00.04868586*w b = b + 00.00000000*w + w = c3*c33 r = r + 00.99518138*w g = g + 00.99978149*w b = b + 00.99704802*w + w = c00*c1 r = r + 00.04819146*w g = g + 00.83363781*w b = b + 00.32515377*w + w = c01*c1 r = r + -0.68146950*w g = g + 01.46107803*w b = b + 01.06980936*w + w = c00*c2 r = r + 00.27058419*w g = g + -0.15324870*w b = b + 01.98735057*w + w = c02*c2 r = r + 00.80478189*w g = g + 00.67093710*w b = b + 00.18424500*w + w = c00*c3 r = r + -0.35031003*w g = g + 01.37855826*w b = b + 03.68865000*w + w = c0*c33 r = r + 01.05128046*w g = g + 01.97815239*w b = b + 02.82989073*w + w = c11*c2 r = r + 03.21607125*w g = g + 00.81270228*w b = b + 01.03384539*w + w = c1*c22 r = r + 02.78893374*w g = g + 00.41565549*w b = b + -0.04487295*w + w = c11*c3 r = r + 03.02162577*w g = g + 02.55374103*w b = b + 00.32766114*w + w = c1*c33 r = r + 02.95124691*w g = g + 02.81201112*w b = b + 01.17578442*w + w = c22*c3 r = r + 02.82677043*w g = g + 00.79933038*w b = b + 01.81715262*w + w = c2*c33 r = r + 02.99691099*w g = g + 01.22593053*w b = b + 01.80653661*w + w = c01*c2 r = r + 01.87394106*w g = g + 02.05027182*w b = b + -0.29835996*w + w = c01*c3 r = r + 02.56609566*w g = g + 07.03428198*w b = b + 00.62575374*w + w = c02*c3 r = r + 04.08329484*w g = g + -1.40408358*w b = b + 02.14995522*w + w = c12*c3 r = r + 06.00078678*w g = g + 02.55552042*w b = b + 01.90739502*w + + return {r, g, b} +end + +function decompress(input) + local decoded = base64.decode(input) + + --local stream = zlib.inflate(-15) -- raw deflate stream + --local deflated = stream(decoded) + local deflated = LibDeflate:DecompressDeflate(decoded) + + local output = {} + for i = 1, #deflated do + output[i] = string.byte(deflated, i) + end + + for i = 1, #output do + output[i] = ((bit32.band((i-1), 63)) ~= 0 and output[i - 1] or 127) + (output[i] - 127) + end + + for i = 1, 4161 do + table.insert(output, 0) + end + return output +end + +lut = decompress("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") + +local module = {} + +module.LATENT_SIZE = LATENT_SIZE + +module.lerp = lerp +module.lerp_float = lerp_float +module.lerp_linear_float = lerp_linear_float + +module.rgb_to_latent = rgb_to_latent +module.latent_to_rgb = latent_to_rgb + +module.float_rgb_to_latent = float_rgb_to_latent +module.latent_to_float_rgb = latent_to_float_rgb + +module.linear_float_rgb_to_latent = linear_float_rgb_to_latent +module.latent_to_linear_float_rgb = latent_to_linear_float_rgb + +return module \ No newline at end of file From 20e3a0291c10ec2f0e1f3e3ca3d73933c335ae7f Mon Sep 17 00:00:00 2001 From: Matthew Dean Date: Tue, 30 Jan 2024 13:53:35 -0800 Subject: [PATCH 2/3] Add Lua instructions and example to README --- README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/README.md b/README.md index 0f1acc5..ed77a93 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ Mixbox is shipping in Rebelle 5 Pro as the [Rebelle Pigments](https://www.escape - [Unity](unity): add package from git url `git://github.com/scrtwpns/mixbox.git#upm` - [Godot](godot): copy `godot\addons` to the root of your project - [Shaders](shaders): load `mixbox_lut.png` as texture and include `mixbox.glsl`/`.hlsl`/`.metal` code into your shader +- [Lua](lua): add the `.lua` files from `lua` to the root of your project ## Pigment Colors | Pigment | | RGB | Float RGB | Linear RGB | @@ -346,6 +347,20 @@ gl.bindTexture(gl.TEXTURE_2D, mixbox.lutTexture(gl)); gl.uniform1i(gl.getUniformLocation(shaderProgram, "mixbox_lut"), 0); ``` +## Lua + +```lua +local mixbox = require("mixbox") + +local rgb1 = {0, 33, 133} -- blue +local rgb2 = {252, 211, 0} -- yellow +t = 0.5 -- mixing ratio + +local rgb = mixbox.lerp(rgb1, rgb2, t) + +print(table.unpack(rgb)) +``` + ## Examples | Gradients | Mountains | Palette Snakes | From a9e0fcba30e13741d6088e64a2a1bd4f07f0a349 Mon Sep 17 00:00:00 2001 From: Matthew Dean Date: Tue, 30 Jan 2024 14:05:54 -0800 Subject: [PATCH 3/3] Remove unused local variable --- lua/mixbox.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/lua/mixbox.lua b/lua/mixbox.lua index 7ab104c..d8523de 100644 --- a/lua/mixbox.lua +++ b/lua/mixbox.lua @@ -61,7 +61,6 @@ local min = math.min local max = math.max local pow = math.pow local int = math.floor -local round = math.round local lut function lerp(color1, color2, t)