Skip to content

Instantly share code, notes, and snippets.

@MikuAuahDark
Created October 3, 2016 11:38
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 MikuAuahDark/ca9bd2b98d6e50c4a76c1ada4be1fcee to your computer and use it in GitHub Desktop.
Save MikuAuahDark/ca9bd2b98d6e50c4a76c1ada4be1fcee to your computer and use it in GitHub Desktop.
Playground Flash file dumper
-- Playground FLSH asset dumper.
-- It does not allow you to make new FLSH file!!!
local arg = {...}
local target_input = arg[1]
if target_input == nil then
print("Usage: lua flsh_dumper.lua <flsh path>")
print("It does not allow you to make new FLSH file!!!")
return 1
end
local input = assert(io.open(target_input, "rb"))
if input:read(4) ~= "FLSH" then
error("Invalid FLSH file")
end
input:read(4) -- Skip size
local function read32_be(file)
local x = {file:read(4):byte(1,4)}
return x[1] * 16777216 + x[2] * 65536 + x[3] * 256 + x[4]
end
local function read16_be(file)
local x = {file:read(2):byte(1,2)}
return x[1] * 256 + x[2]
end
local function read_float(file)
return read32_be(file) / 65536.0
end
local function read_byte(file)
return file:read(1):byte()
end
local function read_string(file)
local size = read16_be(file)
return ({file:read(size):gsub("%z", "")})[1]
end
-- Start!!!
print("Name", read_string(input))
do
local msf = read16_be(input)
print("MS/Frame", msf, math.floor(1000/msf).." FPS")
end
local strings_list = {}
local string_count = read16_be(input)
do
read16_be(input) -- Skip total string size
if string_count == 65535 then
error("Sound extension is not supported yet")
end
print()
print("Contains "..string_count.." string(s) constant")
for i = 1, string_count do
local x = read_string(input)
i = i - 1
strings_list[i] = x
print("["..i.."] = "..x)
end
end
local matrix_count = read32_be(input)
local float_count = read32_be(input)
local matrix_data = {}
local float_data = {}
print()
print("Contains "..float_count.." float constants")
for i = 1, float_count do
local x = read_float(input)
i = i - 1
float_data[i] = x
print("["..i.."] = "..x)
end
print()
print("Contains "..matrix_count.." matrix data")
for i = 1, matrix_count do
local x = read_byte(input)
local y = read32_be(input)
table.insert(matrix_data, {x, y})
print("Type", x, "Data Index", y)
end
local instr_count = read32_be(input)
local instr_data = {}
print()
print("Contains "..instr_count.." instructions")
for i = 1, instr_count do
local x = read32_be(input)
local instr_name = ""
table.insert(instr_data, x)
end
local movie_count = read16_be(input)
local movie_data = {}
print()
print("Contains "..movie_count.." movie(s)")
for i = 1, movie_count do
local x = {
name_idx = read32_be(input),
framecount = read32_be(input),
startindex = read32_be(input),
endindex = read32_be(input)
}
table.insert(movie_data, x)
if x.name_idx == 65535 then
print("Movie #"..i.." null/unknown movie")
else
local name = strings_list[x.name_idx]
if x.framecount == 65535 then
print(string.format("Movie #"..i.." image %s ; offsetx = %d ; offsety = %d", name, x.startindex, x.endindex))
elseif x.framecount == 36862 then
print(string.format("Movie #"..i.." shape %s ; offsetx = %d ; offsety = %d", name, x.startindex, x.endindex))
else
print(string.format("Movie #3 name = %s ; %d frames ; start instr idx = %d ; end instr idx = %d", name, x.framecount, x.startindex, x.endindex))
end
end
end
local max_instr_len = #string.format("%x", instr_count * 4)
local instr_idx_format = string.format("[%%%02dX]", max_instr_len)
for n, v in pairs(movie_data) do
local movie_name = strings_list[v.name_idx]
if v.name_idx ~= 65535 and movie_name:byte() == 70 then
print()
print("Decoded instructions for movie #"..n.." ("..movie_name..")")
local instr_counter = v.startindex + 4
local function get_next_instruction()
local x = instr_data[instr_counter]
instr_counter = instr_counter + 1
return x
end
while instr_counter <= v.endindex do
local instr_pos = instr_counter
local instr = get_next_instruction()
local instr_name = ""
local instr_info = {}
do
if instr == 0 then
instr_name = "SHOW_FRAME"
local label = get_next_instruction()
local type = get_next_instruction()
table.insert(instr_info, string.format("LABEL %08X", label))
table.insert(instr_info, string.format("TYPE %08X", type))
if type == 0 then
table.insert(instr_info, "STOP_INSTRUCTION")
elseif type == 1 or type == 2 then
if type == 1 then
table.insert(instr_info, "GOTO_AND_PLAY")
else
table.insert(instr_info, "GOTO_AND_STOP")
end
local frame_target = get_next_instruction() + 2
table.insert(instr_info, string.format("FRAMETARGET %08X", frame_target))
else
get_next_instruction()
end
elseif instr == 1 or instr == 4 then
if instr == 1 then
instr_name = "PLACE_OBJECT"
else
instr_name = "PLACE_OBJECT_CLIP"
end
local movieid = get_next_instruction()
local matrixidx = get_next_instruction()
local matrixcolidx = get_next_instruction()
local layer = get_next_instruction()
table.insert(instr_info, string.format("MOVIEID %d MATRIXIDX %d MATRIXCOLIDX %d LAYER %d", movieid, matrixidx, matrixcolidx, layer))
if instr == 4 then
local clip = get_next_instruction()
table.insert(instr_info, string.format("CLIP %d", clip))
end
elseif instr == 2 then
instr_name = "REMOVE_OBJECT"
local layer = get_next_instruction()
table.insert(instr_info, string.format("LAYER %d", layer))
elseif instr == 3 then
instr_name = "PLAY_SOUND"
local sndid = get_next_instruction()
table.insert(instr_info, string.format("SNDID %d", sndid))
else
instr_name = "INVALID"
end
end
print(string.format(instr_idx_format, instr_pos * 4), string.format("%08X\t%s\t%s", instr, instr_name, table.concat(instr_info, " ")))
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment