From fb0c740b39b0a7b797f70590d0a06d49e15ee421 Mon Sep 17 00:00:00 2001 From: XeonSquared Date: Fri, 5 Jun 2020 22:54:51 +1000 Subject: [PATCH] add liblz16 and lzss for use with pkgfs, and eventually mtar probably --- lib/liblz16.lua | 71 ++++++++++++++++++++++++++++ lib/lzss.lua | 123 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 194 insertions(+) create mode 100644 lib/liblz16.lua create mode 100644 lib/lzss.lua diff --git a/lib/liblz16.lua b/lib/liblz16.lua new file mode 100644 index 0000000..a2faaa7 --- /dev/null +++ b/lib/liblz16.lua @@ -0,0 +1,71 @@ +local lz = require "lzss" +local buffer = require "buffer" + +lz16 = {} + +local function cint(n,l) + local t={} + for i = 0, 7 do + t[i+1] = (n >> (i * 8)) & 0xFF + end + return string.reverse(string.char(table.unpack(t)):sub(1,l)) +end +local function toint(s) + local n = 0 + local i = 1 + for p in s:gmatch(".") do + n = n << 8 + n = n | string.byte(p) + i=i+1 + end + return n +end + +local function readBuffer(fi) + local stream = {} + if fi:read(4) ~= "lz16" then + return false, "not an lz16 archive" + end + function stream.read() + local len = toint(fi:read(2) or "\0\0") + if len < 1 then + return nil + end + coroutine.yield() + return lz.decompress(fi:read(len)) + end + function stream.close() + fi:close() + end + return buffer.new("rb",stream) +end + +local function writeBuffer(fo) + local stream = {} + function stream:write(data) + local cblock = lz.compress(data) + fo:write(cint(cblock:len(),2)..cblock) + return cblock:len()+2 + end + function stream.close() + fo:close() + end + fo:write("lz16") -- write header + return buffer.new("wb",stream) +end + +function lz16.buffer(stream) + if stream.mode.w then + return writeBuffer(stream) + end + return readBuffer(stream) +end + +function lz16.open(fname, mode) + local f = io.open(fname, mode) + if not f then return false end + f.mode.b = true + return lz16.buffer(f) +end + +return lz16 diff --git a/lib/lzss.lua b/lib/lzss.lua new file mode 100644 index 0000000..501d0ec --- /dev/null +++ b/lib/lzss.lua @@ -0,0 +1,123 @@ +--[[---------------------------------------------------------------------------- + + 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 + +--]]---------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +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