1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
|
local dat_obj = {}
local match_key = nil
local function dat_lexer(f, fname)
local line, err = f:read("*l")
local location = {line_no = 1, column = 1, fname = fname}
return function()
local tok = nil
while not tok do
if not line then
return nil
end
pre_space, tok, line = string.match(line, "^(%s*)(..-)([()]*%s.*)")
if tok and string.match(tok, "^\"") then
tok, line = string.match(tok..line, "^\"([^\"]-)\"(.*)")
elseif tok and string.match(tok, "^[()]") then
line = tok:sub(2) .. line
tok = tok:sub(1,1)
end
location.column = location.column + #(pre_space or "")
tok_loc = {
line_no = location.line_no,
column = location.column,
fname = location.fname
}
if not line then
line = f:read("*l")
location.line_no = location.line_no + 1
location.column = 1
else
location.column = location.column + #tok
end
end
-- print(tok)
return tok, tok_loc
end
end
local function dat_parse_table(lexer, start_loc)
local res = {}
local state = "key"
local key = nil
for tok, loc in lexer do
if state == "key" then
if tok == ")" then
return res
elseif tok == "(" then
error(string.format(
"%s:%d:%d: fatal error: Unexpected '(' instead of key",
loc.fname,
loc.line_no,
loc.column
))
else
key = tok
state = "value"
end
else
if tok == "(" then
res[key] = dat_parse_table(lexer, loc)
elseif tok == ")" then
error(string.format(
"%s:%d:%d: fatal error: Unexpected ')' instead of value",
loc.fname,
loc.line_no,
loc.column
))
else
res[key] = tok
end
state = "key"
end
end
error(string.format(
"%s:%d:%d: fatal error: Missing ')' for '('",
start_loc.fname,
start_loc.line_no,
start_loc.column
))
end
local function dat_parser(lexer)
local res = {}
local state = "key"
local key = nil
local skip = true
for tok, loc in lexer do
if state == "key" then
if tok == "game" then
skip = false
end
state = "value"
else
if tok == "(" then
local v = dat_parse_table(lexer, loc)
if not skip then
table.insert(res, v)
skip = true
end
else
error(string.format(
"%s:%d:%d: fatal error: Expected '(' found '%s'",
loc.fname,
loc.line_no,
loc.column,
tok
))
end
state = "key"
end
end
return res
end
local function unhex(s)
if not s then return nil end
return (s:gsub('..', function (c)
return string.char(tonumber(c, 16))
end))
end
local function get_match_key(mk, t)
for p in string.gmatch(mk, "(%w+)[.]?") do
if p == nil or t == nil then
error("Invalid match key '"..mk.."'")
end
t = t[p]
end
return t
end
table.update = function(a, b)
for k,v in pairs(b) do
a[k] = v
end
end
function init(...)
local args = {...}
table.remove(args, 1)
if #args == 0 then
assert(dat_path, "dat file argument is missing")
end
if #args > 1 then
match_key = table.remove(args, 1)
end
local dat_hash = {}
for _, dat_path in ipairs(args) do
local dat_file, err = io.open(dat_path, "r")
if err then
error("could not open dat file '" .. dat_path .. "':" .. err)
end
print("Parsing dat file '" .. dat_path .. "'...")
local objs = dat_parser(dat_lexer(dat_file, dat_path))
dat_file:close()
for _, obj in pairs(objs) do
if match_key then
local mk = get_match_key(match_key, obj)
if mk == nil then
error("missing match key '" .. match_key .. "' in one of the entries")
end
if dat_hash[mk] == nil then
dat_hash[mk] = {}
table.insert(dat_obj, dat_hash[mk])
end
table.update(dat_hash[mk], obj)
else
table.insert(dat_obj, obj)
end
end
end
end
function get_value()
local t = table.remove(dat_obj)
if not t then
return
else
return {
name = t.name,
description = t.description,
rom_name = t.rom.name,
size = uint(tonumber(t.rom.size)),
users = uint(tonumber(t.users)),
releasemonth = uint(tonumber(t.releasemonth)),
releaseyear = uint(tonumber(t.releaseyear)),
rumble = uint(tonumber(t.rumble)),
analog = uint(tonumber(t.analog)),
famitsu_rating = uint(tonumber(t.famitsu_rating)),
edge_rating = uint(tonumber(t.edge_rating)),
edge_issue = uint(tonumber(t.edge_issue)),
edge_review = t.edge_review,
enhancement_hw = t.enhancement_hw,
barcode = t.barcode,
esrb_rating = t.esrb_rating,
elspa_rating = t.elspa_rating,
pegi_rating = t.pegi_rating,
cero_rating = t.cero_rating,
franchise = t.franchise,
developer = t.developer,
publisher = t.publisher,
origin = t.origin,
crc = binary(unhex(t.rom.crc)),
md5 = binary(unhex(t.rom.md5)),
sha1 = binary(unhex(t.rom.sha1)),
serial = binary(t.serial or t.rom.serial),
}
end
end
|