load "VP-map.lua"
--[[
restrict = {
[3610] = true,
}
dump_font = true
]]--
function startup(file_in)
if loadmodule then
loadmodule "lualibs"
loadmodule "luahandle"
loadmodule "luacd"
loadmodule "luaslz"
loadmodule "luahttp"
loadmodule "luaxml"
iso_in = cdabstract(file_in or "VP-SQUISH.bin")
cdutil = cdutils(iso_in)
else
error("This can only be used with lua-interface now...")
end
end
num_entries = 5120
fkey_size = 256
skey_size = 16
log_file = nil
function log(str)
print(str)
log_file:write(str .. "\n")
end
function load_index()
local vp_sec, cfat, csiz, fat, siz, fkey, skey, fkey_pos, skey_pos
vp_sec = 150
cfat = cdutil:cdfile(vp_sec, num_entries * 4)
csiz = cdutil:cdfile(vp_sec + num_entries * 4 / 2048, num_entries)
fat = Buffer(true)
siz = Buffer(true)
fkey = Buffer(true)
skey = Buffer(true)
cfat:seek(num_entries * 4 - fkey_size)
csiz:seek(num_entries - skey_size)
fkey:copyfrom(cfat, fkey_size)
skey:copyfrom(csiz, skey_size)
cfat:seek(0)
csiz:seek(0)
fkey_pos = 0
skey_pos = 0
print "Decrypting index..."
for i = 0, (num_entries * 4 - 1) do
fat:writeU8(xorB(cfat:readU8(), fkey:readU8()))
fkey_pos = fkey_pos + 1
if fkey_pos == fkey_size then
fkey_pos = 0
fkey:seek(0)
end
end
for i = 0, (num_entries - 1) do
siz:writeU8(xorB(csiz:readU8(), skey:readU8()))
skey_pos = skey_pos + 1
if skey_pos == skey_size then
skey_pos = 0
skey:seek(0)
end
end
cfat:destroy()
csiz:destroy()
fkey:destroy()
skey:destroy()
print "Done."
local o, m, s, f, size_high, size
for k, v in pairs(VP_maintypes) do
mkdir("DUMP/" .. v)
end
fat:seek(4)
siz:seek(1)
index = {}
for i = 1, (num_entries - 1) do
m = fat:readU8()
s = fat:readU8()
f = fat:readU8()
size_high = fat:readU8()
sector = from_MSF(m, s, f)
size = siz:readU8() + size_high * 256
if (sector ~= 4294967146) then
log("Entry " .. i .. ", sector " .. sector .. ", nsectors = " .. size)
index[i] = { sector = sector, size = size }
end
end
fat:destroy()
siz:destroy()
return index
end
function dump_single_file(fname, h, size, ext, handler)
local sig = h:readU32()
h:seek(-4, SEEK_CUR)
local is_slz = sig == 0x05a4c53 or sig == 0x15a4c53 or sig == 0x25a4c53 or sig == 0x35a4c53
local is_tim = sig == 0x00000010
local eof = false
if is_slz then
log("Dumping " .. fname .. "." .. ext .. ".slz")
o = Output(fname .. "." .. ext .. ".slz")
o:copyfrom(h, size)
o:destroy()
h:seek(-size, SEEK_CUR)
local num, esiz, stype = 1
log("Extracting " .. fname .. ".slz")
while not eof do
local snum
snum = string.format("-%02i", num)
if num ~= 1 then
log("... file " .. num .. " to " .. fname .. snum .. "." .. ext)
end
o = Buffer(true)
local tell = h:tell()
esiz, stype = slz_decomp(h, o)
h:seek(tell + esiz)
dump_single_file(fname .. snum, o, o:getsize(), ext, handler)
o:destroy()
eof = esiz == 0
num = num + 1
end
else
if is_tim and ext ~= "tim" and not handler then
ext = ext .. ".magic.tim"
end
log("Dumping " .. fname .. "." .. ext)
o = Output(fname .. "." .. ext)
local tell = h:tell()
o:copyfrom(h, size)
h:seek(tell)
o:destroy()
if handler then
handler(fname, h, size, ext)
end
end
end
function extract_arcgfx(fname, h, size, ext)
log("Dumping " .. fname .. "." .. ext)
o = Output(fname .. "." .. ext)
o:copyfrom(h, size)
o:destroy()
h:seek(-size, SEEK_CUR)
log("Extracting " .. fname .. " - format 'arcgfx'")
mkdir(fname)
local nfiles = h:readU32()
local extra = h:readU32()
o = Output(fname .. "/--extra.bin")
o:writeU32(extra)
o:destroy()
o = Output(fname .. string.format("/0000-%08X", extra))
o:writeU32(extra)
o:destroy()
index = {}
for i = 1, nfiles do
index[i] = {}
index[i].extra = h:readU32()
index[i].size = h:readU32()
end
local tell
for i = 1, nfiles do
tell = h:tell()
dump_single_file(fname .. string.format("/%04i-%08X", i, index[i].extra), h, index[i].size, ext)
h:seek(tell + index[i].size)
end
end
function resolve_font(font)
local r = {}
for k, v in pairs(font) do
local g = glyphes[v]
if not g then error("Glyphe " .. v .. " not found!") end
r[k] = g.attr.Text
end
return r
end
function extract_font(fname, h)
local n_glyphes = h:readU32()
local height = h:readU32()
local widths = {}
for i = 1, n_glyphes do
widths[i] = h:readU8()
end
local o
local r = {}
if dump_glyph then
mkdir(fname)
end
for i = 1, n_glyphes do
if dump_glyph then
o = Output(fname .. string.format("/%03i.glyph", i))
o:copyfrom(h, height * 2)
o:destroy()
h:seek(-height * 2, SEEK_CUR)
o = Output(fname .. string.format("/%03i.raw", i))
local bits
for j = 1, height do
bits = h:readU16()
for k = 1, height do -- should be widths[i]
bits = shl(bits, 1)
local bit = andB(bits, 65536) ~= 0
o:writeU8(bit and 0xff or 0)
end
end
o:destroy()
h:seek(-height * 2, SEEK_CUR)
end
local b = Buffer(true)
b:copyfrom(h, height * 2)
r[i] = Base64Encode(b)
b:destroy()
end
return r
end
function dump_special(out, script, code)
if code == 0 then
out:write("\n")
elseif code == 1 then
out:write("\n\n")
elseif code == 3 then
local speed = script:readU8()
if speed == 255 then
out:write('')
else
out:write('')
end
elseif code == 5 then
out:write('')
elseif code == 14 then
out:write('')
elseif code == 4 then
out:write('')
else
local a1, a2
if code == 3 or code == 4 or code == 7 or code == 8 or code == 14 then
a1 = script:readU8()
out:write('')
elseif code == 6 or code == 12 or code == 17 or code == 19 then
a1 = script:readU8()
a2 = script:readU8()
out:write('')
else
out:write('')
end
end
end
function extract_char(out, script, lookup)
local
c = script:readU8()
if c == 0 then return false end
if c >= 0x80 then c = (c - 0x80) + (script:readU8() * 128) end
if c >= 0x4000 then
dump_special(out, script, c - 0x4000)
else
local l = lookup[c]
if not l and not sloppy_extract then error("Lookup failed for character " .. c) end
if not l then
out:write('')
else
out:write(xml_escape(l))
end
end
return true
end
function extract_script(fname, script, font)
log("Dumping script " .. fname)
mkdir(fname)
mkdir(fname .. "/EXTRA")
local font = extract_font(fname .. "/FONT", font)
local lookup = resolve_font(font)
local size_1 = script:readU32()
local u1 = script:readU32()
local u2 = script:readU32()
local n_ptrs = script:readU32()
local u3 = script:readU32()
local u4 = script:readU32()
local u5 = script:readU32()
local o
o = Output(fname .. "/EXTRA/00-head1-" .. string.format("%08X-%08X", u1, u2) .. ".bin")
o:writeU32(u1)
o:writeU32(u2)
o:destroy()
o = Output(fname .. "/EXTRA/00-head2-" .. string.format("%08X-%08X-%08X", u3, u4, u5) .. ".bin")
o:writeU32(u3)
o:writeU32(u4)
o:writeU32(u5)
o:destroy()
o = Output(fname .. "/EXTRA/01-head1.bin")
o:writeU32(u1)
o:writeU32(u2)
o:destroy()
o = Output(fname .. "/EXTRA/01-head2.bin")
o:writeU32(u3)
o:writeU32(u4)
o:writeU32(u5)
o:destroy()
o = Output(fname .. "/EXTRA/02-part1.bin")
o:copyfrom(script, size_1)
o:destroy()
local ptrs = {}
for i = 1, n_ptrs do
ptrs = script:readU16()
end
o = Output(fname .. "-script.xml")
o:write('\n')
o:destroy()
end
function extract_archive(fname, h, size, ext)
log("Dumping " .. fname .. "." .. ext)
local o = Output(fname .. "." .. ext)
o:copyfrom(h, size)
o:destroy()
h:seek(-size, SEEK_CUR)
log("Extracting " .. fname .. " - format 'archive'")
mkdir(fname)
local nfiles = h:readU32()
local offset = h:readU32()
if nfiles * 8 + 8 ~= offset then
error("Bad archive format.")
end
index = {}
for i = 1, nfiles do
index[i] = {}
index[i].ftype = h:readU32()
index[i].size = h:readU32()
end
local tell
for i = 1, nfiles do
tell = h:tell()
local handler = nil
local script = nil
local font = nil
local counter = 1
if index[i].ftype == 4 then
log("Preparing to dump script...")
script = Buffer(true)
font = Buffer(true)
handler = function(fname, h, size, ext)
if counter == 1 then
log("Taking script...")
script:copyfrom(h)
elseif counter == 2 then
log("Taking font...")
font:copyfrom(h)
else
error("Too many files.")
end
counter = counter + 1
end
end
dump_single_file(fname .. string.format("/%04i-%08X", i, index[i].ftype), h, index[i].size, ext, handler)
if handler then
extract_script(fname .. string.format("/%04i", i), script, font)
script:destroy()
font:destroy()
end
h:seek(tell + index[i].size)
end
end
function do_dump(i)
if not restrict then return true end
return restrict[i]
end
function dump_files(index, map)
print("Dumping files...")
local file_in, sig, is_slz, o, mode, dir, ftype
for i = 1, (num_entries - 1) do
if index[i] and do_dump(i) then
if map[i] then
mode = map[i].mode
dir = map[i].dir
ext = map[i].ext
ftype = map[i].ftype
else
mode = MODE2_FORM1
dir = "UNKNOWN"
ext = "out"
ftype = nil
end
if not mode then mode = MODE2_FORM1 end
if not ext then ext = "out" end
if not dir then dir = "UNKNOWN" end
file_in = cdutil:cdfile(index[i].sector, index[i].size * sec_sizes[mode])
mkdir("DUMP/" .. dir)
if not ftype then
dump_single_file("DUMP/" .. dir .. string.format("/%04i", i), file_in, file_in:getsize(), ext)
elseif ftype == "arcgfx" then
extract_arcgfx("DUMP/" .. dir .. string.format("/%04i", i), file_in, file_in:getsize(), ext)
elseif ftype == "archive" then
extract_archive("DUMP/" .. dir .. string.format("/%04i", i), file_in, file_in:getsize(), ext)
else
error("Unknow ftype: " .. ftype)
end
file_in:destroy()
end
end
end
function main(...)
startup(...)
local tglyphes = xml.LoadHandle(Input "VP-database.xml")[1]
glyphes = {}
for k, v in ipairs(tglyphes) do
glyphes[v.attr.Data] = v
end
mkdir "DUMP"
log_file = Output "DUMP/log.txt"
local index = load_index()
dump_files(index, VP_map)
log_file:destroy()
end