Skip to content

Instantly share code, notes, and snippets.

@SonoSooS
Created December 22, 2016 09:53
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 SonoSooS/f09eeb52d7b33304706d211375056bf9 to your computer and use it in GitHub Desktop.
Save SonoSooS/f09eeb52d7b33304706d211375056bf9 to your computer and use it in GitHub Desktop.
FST parser Lua script
#!/bin/lua
-- ===================================
-- FST parser Lua script
--
-- created by MarcusD
-- Copyright $(date +"%Y")
--
-- :P
-- ===================================
local argv = {...}
local argc = #argv
local function read32(fileptr)
local n = {fileptr:read(4):byte(1, 4)}
return
(n[1] * 256 * 256 * 256) +
(n[2] * 256 * 256) +
(n[3] * 256) +
(n[4])
end
local function read24(fileptr)
local n = {fileptr:read(3):byte(1, 3)}
return
(n[1] * 256 * 256) +
(n[2] * 256) +
(n[3])
end
local function read16(fileptr)
local n = {fileptr:read(2):byte(1, 2)}
return
(n[1] * 256) +
(n[2])
end
local function ftell(ptr)
return ptr:seek("cur", 0)
end
local function readstring(ptr)
local buf = {}
local n = nil
while true do
n = ptr:read(1)
if not n then break end
if n == "\0" then break end
buf[#buf + 1] = n
end
return table.concat(buf)
end
local fprefix = "- "
local dirprefix = "* "
local function iterdir(ptr, is, cnt, baseoffs, nameoffs, depth, topdir)
if not depth then depth = 1 end
if not topdir then topdir = -1 end
if not is then is = 1 end
local i = is
while i < cnt do
local isdir = ptr:read(1):byte() ~= 0
local offs = read24(ptr) + nameoffs
local bakptr = ftell(ptr)
ptr:seek("set", offs)
local name = readstring(ptr)
ptr:seek("set", bakptr)
local foffs = read32(ptr)
local fsize = read32(ptr)
local flags = read16(ptr)
if not isdir and (flags % 8) < 4 then foffs = foffs * 0x20 end
local coffs = read16(ptr)
print(("%02i "):format(i) .. (" "):rep(depth - 1) .. (isdir and dirprefix or fprefix) .. name .. (isdir and "" or (" (Size: 0x" .. ("%X"):format(fsize)) .. ")") .. (coffs ~= 0 and (" (ContentID: " .. (coffs + 1) .. ")") or ""))
if isdir then
if foffs <= topdir then return i end
iterdir(ptr, i + 1, fsize, baseoffs, nameoffs, depth + 1, foffs)
i = fsize - 1
end
i = i + 1
end
end
if argc < 1 then
print("Usage: fstlist.lua <file...>")
return 1
end
for _, path in pairs(argv) do
local ptr, err = io.open(path, "rb")
if ptr then
local num = read32(ptr)
if num == 0x46535400 then
local exhsize = read32(ptr)
local exhcount = read32(ptr)
print("exheader size: 0x" .. ("%X"):format(exhsize))
print("exheader count: " .. exhcount)
if exhsize == 0x20 then
ptr:seek("cur", 0x14)
for i = 1, exhcount do
print(("#%02i:"):format(i))
print("- Unknown1: 0x" .. ("%08X"):format(read32(ptr)))
print("- Unknown2: 0x" .. ("%08X"):format(read32(ptr)))
print("- TitleID: 0x" .. ("%08X%08X"):format(read32(ptr), read32(ptr)))
print("- GroupID: 0x" .. ("%08X"):format(read32(ptr)))
print("- Flags?: 0x" .. ("%04X"):format(read16(ptr)))
print("")
ptr:seek("cur", 10)
end
local fsestart = ftell(ptr)
ptr:seek("cur", 8)
local rootcnt = read32(ptr)
ptr:seek("cur", 4)
local nameoffs = fsestart + (rootcnt * 0x10)
iterdir(ptr, 1, rootcnt - 1, fsestart + 0x10, nameoffs)
else
print("'" .. path .. "': invalid exheader size: 0x" .. ("%X"):format(exhsize))
end
else
print("'" .. path .. "': not an FST file (" .. ("%08X"):format(num) .. ")")
end
ptr:close()
else
print("Error opening '" .. path .. "': " .. err)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment