diff --git a/build.lua b/build.lua index 9fabb5c..475040e 100644 --- a/build.lua +++ b/build.lua @@ -147,9 +147,9 @@ end local velx_spec = struct { endian = "<", {magic="c5"}, + {fver="B"}, {compression="B"}, {lver="B"}, - {fver="B"}, {os="B"}, {psize="I3"}, {lsize="I3"}, diff --git a/tkrnl.velx b/tkrnl.velx index 42f087e..6392f31 100644 Binary files a/tkrnl.velx and b/tkrnl.velx differ diff --git a/utils/velxdump.lua b/utils/velxdump.lua new file mode 100644 index 0000000..49d10ee --- /dev/null +++ b/utils/velxdump.lua @@ -0,0 +1,195 @@ +--[[---------------------------------------------------------------------------- + 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 + + +local function struct(tbl) + local pat = tbl.endian or "=" + local args = {} + for i=1, #tbl do + local a, b = pairs(tbl[i]) + local k, v = a(b) + args[i] = k + pat = pat .. v + end + return setmetatable({}, {__call=function(_, arg) + --checkArg(1, arg, "string", "table") + if (type(arg) == "string") then + local sval = {string.unpack(pat, arg)} + local rtn = {} + for i=1, #args do + rtn[args[i]] = sval[i] + end + return rtn, sval[#sval] + elseif (type(arg) == "table") then + local sval = {} + for i=1, #args do + sval[i] = arg[args[i]] + end + return string.pack(pat, unpack(sval)) + end + end, __len=function() + return string.packsize(pat) + end}) +end + +local velx_spec = struct { + endian = "<", + {magic="c5"}, + {fver="B"}, + {compression="B"}, + {lver="B"}, + {os="B"}, + {psize="I3"}, + {lsize="I3"}, + {ssize="I3"}, + {rsize="I4"} +} + +local compression = { + [0] = "None", + [1] = "LZSS" +} + +local os = { + [0] = "Tsuki", + [0x7F] = "BIOS", +} + +local f = io.open(arg[1], "rb") +local header = velx_spec(f:read(#velx_spec)) +local program = f:read(header.psize) +local linker = f:read(header.lsize) +local sigs = f:read(header.ssize) +local archive = f:read(header.rsize) +local lver = string.format("%x", header.lver) +lver = lver:sub(1,1).."."..lver:sub(2,2) +io.stdout:write(string.format([[File Version: %d +Compression: %s +Type: %s +OS: %s +Lua Version: %s]], +header.fver, +compression[header.compression] or "Unknown", +(((header.os & 0x80) > 0) and "Library") or "Executable", +os[header.os & 0x7F] or "Unknown", +lver),"\n") +local h = io.popen("tsar -t", "w") +h:write(archive) +h:close() +if (header.compression == 1) then + io.stderr:write(M.decompress(program)) +elseif (header.compression == 0) then + io.stderr:write(program) +end \ No newline at end of file