|
- --[[----------------------------------------------------------------------------
-
- LZSS - encoder / decoder
-
- 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.
-
- For more information, please refer to <http://unlicense.org/>
-
- --]]----------------------------------------------------------------------------
- --------------------------------------------------------------------------------
- local M = {}
- local string, table = string, table
-
- --------------------------------------------------------------------------------
- local POS_BITS = 12
- local LEN_BITS = 16 - POS_BITS
- local POS_SIZE = 1 << POS_BITS
- local LEN_SIZE = 1 << LEN_BITS
- local LEN_MIN = 3
-
- --------------------------------------------------------------------------------
- function M.compress(input)
- local offset, output = 1, {}
- local window = ''
-
- local function search()
- for i = LEN_SIZE + LEN_MIN - 1, LEN_MIN, -1 do
- local str = string.sub(input, offset, offset + i - 1)
- local pos = string.find(window, str, 1, true)
- if pos then
- return pos, str
- end
- end
- end
-
- while offset <= #input do
- local flags, buffer = 0, {}
-
- for i = 0, 7 do
- if offset <= #input then
- local pos, str = search()
- if pos and #str >= LEN_MIN then
- local tmp = ((pos - 1) << LEN_BITS) | (#str - LEN_MIN)
- buffer[#buffer + 1] = string.pack('>I2', tmp)
- else
- flags = flags | (1 << i)
- str = string.sub(input, offset, offset)
- buffer[#buffer + 1] = str
- end
- window = string.sub(window .. str, -POS_SIZE)
- offset = offset + #str
- else
- break
- end
- end
-
- if #buffer > 0 then
- output[#output + 1] = string.char(flags)
- output[#output + 1] = table.concat(buffer)
- end
- end
-
- return table.concat(output)
- end
-
- --------------------------------------------------------------------------------
- function M.decompress(input)
- local offset, output = 1, {}
- local window = ''
-
- while offset <= #input do
- local flags = string.byte(input, offset)
- offset = offset + 1
-
- for i = 1, 8 do
- local str = nil
- if (flags & 1) ~= 0 then
- if offset <= #input then
- str = string.sub(input, offset, offset)
- offset = offset + 1
- end
- else
- if offset + 1 <= #input then
- local tmp = string.unpack('>I2', input, offset)
- offset = offset + 2
- local pos = (tmp >> LEN_BITS) + 1
- local len = (tmp & (LEN_SIZE - 1)) + LEN_MIN
- str = string.sub(window, pos, pos + len - 1)
- end
- end
- flags = flags >> 1
- if str then
- output[#output + 1] = str
- window = string.sub(window .. str, -POS_SIZE)
- end
- end
- end
-
- return table.concat(output)
- end
-
- return M
|