mame/plugins/data/load_dat.lua
2016-11-27 09:56:49 +11:00

166 lines
4.2 KiB
Lua

local sql = require("lsqlite3")
local datfile = {}
local db = sql.open(lfs.env_replace(mame_manager:ui():options().entries.historypath:value():match("([^;]+)")) .. "/history.db")
if db then
local found = false
db:exec("select * from sqllite_master where name = version", function() found = true return 0 end)
if not found then
db:exec([[
CREATE TABLE version (
version VARCHAR NOT NULL,
datfile VARCHAR UNIQUE NOT NULL)]])
end
end
function datfile.open(file, vertag, fixupcb)
if not db then
return nil
end
local function read(tag1, tag2, set)
local data
local stmt = db:prepare("SELECT f.data FROM \"" .. file .. "_idx\" AS fi, \"" .. file .. [["
AS f WHERE fi.type = ? AND fi.val = ? AND fi.romset = ? AND f.rowid = fi.data]])
stmt:bind_values(tag1, tag2, set)
if stmt:step() == sql.ROW then
data = stmt:get_value(0)
end
stmt:finalize()
return data
end
local ver, dbver
local filepath
local fh
for path in mame_manager:ui():options().entries.historypath:value():gmatch("([^;]+)") do
filepath = lfs.env_replace(path) .. "/" .. file
fh = io.open(filepath, "r")
if fh then
break
end
return
end
-- remove unsafe chars from file for use in sql statement
file = file:gsub("[^%w%._]", "")
local stmt = db:prepare("SELECT version FROM version WHERE datfile = ?")
stmt:bind_values(file)
if stmt:step() == sql.ROW then
dbver = stmt:get_value(0)
end
stmt:finalize()
if not dbver then
db:exec("CREATE TABLE \"" .. file .. [[_idx" (
type VARCHAR NOT NULL,
val VARCHAR NOT NULL,
romset VARCHAR NOT NULL,
data INTEGER NOT NULL)]])
db:exec("CREATE TABLE \"" .. file .. "\" (data CLOB NOT NULL)")
db:exec("CREATE INDEX \"typeval_" .. file .. "\" ON \"" .. file .. "_idx\"(type, val)")
elseif not fh then
-- data in database but missing file, just use what we have
return read, dbver
elseif not fh and not dbver then
return nil
end
if vertag then
for line in fh:lines() do
local match = line:match(vertag .. "%s*([^%s]+)")
if match then
ver = match
break
end
end
else
-- use file ctime for version
ver = tostring(lfs.attributes(filepath, "change"))
end
if ver == dbver then
return read, dbver
end
if dbver then
db:exec("DELETE FROM \"" .. file .. "\"")
db:exec("DELETE FROM \"" .. file .. "_idx\"")
stmt = db:prepare("UPDATE version SET version = ? WHERE datfile = ?")
else
stmt = db:prepare("INSERT INTO version VALUES (?, ?)")
end
stmt:bind_values(ver, file)
stmt:step()
stmt:finalize()
do
local inblock = false
fh:seek("set")
local buffer = fh:read("a")
db:exec("BEGIN TRANSACTION")
local function gmatchpos()
local pos = 1
local function iter()
local tag1, tag2, data, start, inblock = false
while not data do
local spos, epos, match = buffer:find("\n($[^\n]*)", pos)
if not spos then
return nil
end
if match ~= "$end" and not inblock then
if not tag1 then
tag1 = match
else
tag2 = match
start = epos + 1
inblock = true
end
elseif inblock == true then
data = buffer:sub(start, spos)
inblock = false
end
pos = epos
end
return tag1, tag2, data
end
return iter
end
for info1, info2, data in gmatchpos() do
local tag, set = info1:match("^%$([^%s=]+)=?([^%s]*)")
if set and set ~= "" then
local tags = {}
local sets = {}
tag:gsub("([^,]+)", function(s) tags[#tags + 1] = s end)
set:gsub("([^,]+)", function(s) sets[#sets + 1] = s end)
if #tags > 0 and #sets > 0 then
local tag1 = info2:match("^$([^%s]*)")
if fixupcb then
data = fixupcb(data)
end
stmt = db:prepare("INSERT INTO \"" .. file .. "\" VALUES (?)")
stmt:bind_values(data)
stmt:step()
local row = stmt:last_insert_rowid()
stmt:finalize()
for num1, tag2 in pairs(tags) do
for num2, set in pairs(sets) do
if fixupcb then
fixupcb(data)
end
stmt = db:prepare("INSERT INTO \"" .. file .. "_idx\" VALUES (?, ?, ?, ?)")
stmt:bind_values(tag1, tag2, set, row)
stmt:step()
stmt:finalize()
end
end
end
end
end
db:exec("END TRANSACTION")
end
fh:close()
return read, ver
end
return datfile