Skip to content

Instantly share code, notes, and snippets.

@uyjulian
Last active May 18, 2021 22:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save uyjulian/c026f3ba0234de3dbfde16607c5a4b38 to your computer and use it in GitHub Desktop.
Save uyjulian/c026f3ba0234de3dbfde16607c5a4b38 to your computer and use it in GitHub Desktop.
-- You are probably going to have a much, much better time using my Python implementation…
-- https://gist.github.com/uyjulian/55475c98c631632ddfd5453469726439
file_util = require"file_util"
ffi = require"ffi"
bit = require"bit"
S = require"syscall"
struct = require"struct"
dir = arg[1] .. "_"
S.mkdir(dir, "RWXU")
f = io.open(arg[1], "rb")
indat = f\read("*a")
f\close()
___1, total, bl = struct.unpack("<I4I4", indat)
--the first uint32 is all zeros...
--print("filecount: " .. total)
trim = (s) ->
return s\match'^%z*(.*%Z)' or ''
--get entries
filez = {}
num = total
ffi.cdef[[void * memmove(void *dst, const void *src, size_t len);]]
decompress = (v) ->
des, bl = struct.unpack("<I4", indat, bl)
if des ~= v.decsize
des = (des > v.decsize) and des or v.decsize
cms, bl = struct.unpack("<I4", indat, bl)
if (cms ~= v.cmpsize) and ((v.cmpsize - cms) ~= 4)
error("compression size in header and stream don't match")
num3, bl = struct.unpack("<I4", indat, bl)
fin = bl + cms - 13
cd = ffi.new("unsigned char[?]", des)
i = 0
num4 = 0
while bl <= fin
i += 1
b, bl = struct.unpack("<I1", indat, bl)
if b == num3
i += 1
b2, bl = struct.unpack("<I1", indat, bl)
if b2 ~= num3
i += 1
if b2 >= num3
b2 -= 1
b3, bl = struct.unpack("<I1", indat, bl)
ffi.C.memmove(cd + (num4), cd + (num4 - b2), b3)
num4 += b3
else
cd[num4] = b2
num4 += 1
else
cd[num4] = b
num4 += 1
return ffi.string(cd, des)
while num ~= 0
num -= 1
filename, bl = struct.unpack("<c64", indat, bl)
filename = trim(filename)
decsize, cmpsize, offset, flags, bl = struct.unpack("<I4I4I4I4", indat, bl)
compressed = bit.band(flags, 1) ~= 0
skip4bytes = bit.band(flags, 2) ~= 0
filez[total - num] = {:filename, :cmpsize, :decsize, :offset, :flags, :compressed, :skip4bytes}
--extract entries
for i, v in ipairs(filez)
-- print("filename: " .. v.filename)
-- print("compressed size: " .. v.cmpsize)
-- print("decompressed size: " .. v.decsize)
-- print("offset: " .. v.offset)
-- print("extra flags: 0x" .. bit.tohex(v.flags))
-- print("compressed: " .. (v.compressed and "true" or "false"))
-- print("skip 4 bytes: " .. (v.skip4bytes and "true" or "false"))
-- print("file number: " .. i)
bl = v.offset + 1
data = ""
if v.skip4bytes
bl += 4
if v.compressed
data = decompress(v)
else
if v.cmpsize ~= v.decsize
error("compress size is not equal to decompress size")
data = string.sub(indat, bl, bl + v.decsize)
file_util.writefile(dir .. "/" .. v.filename, data)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment