summaryrefslogtreecommitdiffstatshomepage
path: root/plugins/data/data_history.lua
blob: 2671d5a065df44e1ba9c5a4fafd57b82f50dd09b (plain) (blame)
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
local dat = {}
local db = require("data/database")
local ver, info
local file = "history.xml"

local function init()
	local filepath
	local dbver
	local fh

	for path in mame_manager.ui.options.entries.historypath:value():gmatch("([^;]+)") do
		filepath = emu.subst_env(path) .. "/" .. file
		fh = io.open(filepath, "r")
		if fh then
			break
		end
	end

	-- check for old history table
	local stmt = db.prepare("SELECT version FROM version WHERE datfile = ?")
	stmt:bind_values("history.dat")
	if stmt:step() == db.ROW then
		stmt:finalize()
		db.exec("DROP TABLE \"history.dat\"")
		db.exec("DROP TABLE \"history.dat_idx\"")
		stmt = db.prepare("DELETE FROM version WHERE datfile = ?")
		stmt:bind_values("history.dat")
		stmt:step()
	end
	stmt:finalize()


	local stmt = db.prepare("SELECT version FROM version WHERE datfile = ?")
	db.check("reading history version")
	stmt:bind_values(file)
	if stmt:step() == db.ROW then
		dbver = stmt:get_value(0)
	end
	stmt:finalize()

	if not fh and dbver then
		-- data in database but missing file, just use what we have
		ver = dbver
		return
	elseif not fh then
		return
	elseif not dbver then
		db.exec("CREATE TABLE \"" .. file .. [[_idx" (
				name VARCHAR NOT NULL,
				list VARCHAR,
				data INTEGER NOT NULL)]])
		db.check("creating index")
		db.exec("CREATE TABLE \"" .. file .. "\" (data CLOB NOT NULL)")
		db.check("creating table")
		db.exec("CREATE INDEX \"name_" .. file .. "\" ON \"" .. file .. "_idx\"(name)")
		db.check("creating system index")
	end

	for line in fh:lines() do
		local match = line:match("<history([^>]*)>")
		if match then
			match = match:match("version=\"([^\"]*)\"")
			if match then
				ver = match
				break
			end
		end
	end

	if not ver then
		fh:close()
		return
	end

	if ver == dbver then
		fh:close()
		return
	end

	if dbver then
		db.exec("DELETE FROM \"" .. file .. "\"")
		db.check("deleting history")
		db.exec("DELETE FROM \"" .. file .. "_idx\"")
		db.check("deleting index")
		stmt = db.prepare("UPDATE version SET version = ? WHERE datfile = ?")
		db.check("updating history version")
	else
		stmt = db.prepare("INSERT INTO version VALUES (?, ?)")
		db.check("inserting history version")
	end
	stmt:bind_values(ver, file)
	stmt:step()
	stmt:finalize()

	fh:seek("set")
	local buffer = fh:read("a")
	db.exec("BEGIN TRANSACTION")
	db.check("beginning history transation")

	local lasttag
	local entry = {}
	local rowid
	local slaxml = require("xml")

	local parser = slaxml:parser{
		startElement = function(name)
			lasttag = name
			if name == "entry" then
				entry = {}
				rowid = nil
			elseif (name == "system") or (name == "item") then
				entry[#entry + 1] = {}
			end
		end,
		attribute = function(name, value)
			if (name == "name") or (name == "list") then
				entry[#entry][name] = value
			end
		end,
		text = function(text, cdata)
			if lasttag == "text" then
				text = text:gsub("\r", "") -- strip crs
				stmt = db.prepare("INSERT INTO \"" .. file .. "\" VALUES (?)")
				db.check("inserting values")
				stmt:bind_values(text)
				stmt:step()
				rowid = stmt:last_insert_rowid()
				stmt:finalize()
			end
		end,
		closeElement = function(name)
			if name == "entry" then
				for num, entry in pairs(entry) do
					stmt = db.prepare("INSERT INTO \"" .. file .. "_idx\" VALUES (?, ?, ?)")
					db.check("inserting into index")
					stmt:bind_values(entry.name, entry.list, rowid)
					stmt:step()
					stmt:finalize()
				end
			end
		end
	}
	parser:parse(buffer, {stripWhitespace=true})
	fh:close()
	db.exec("END TRANSACTION")
	db.check("ending history transation")
end

if db then
	init()
end

function dat.check(set, softlist)
	if not ver or not db then
		return nil
	end
	info = nil
	local stmt
	if softlist then
		stmt = db.prepare("SELECT f.data FROM \"" .. file .. "_idx\" AS fi, \"" .. file .. [["
			AS f WHERE fi.name = ? AND fi.list = ? AND f.rowid = fi.data]])
		stmt:bind_values(set, softlist)
	else
		stmt = db.prepare("SELECT f.data FROM \"" .. file .. "_idx\" AS fi, \"" .. file .. [["
			AS f WHERE fi.name = ? AND fi.list ISNULL AND f.rowid = fi.data]])
		stmt:bind_values(set)
	end
	if stmt:step() == db.ROW then
		info = stmt:get_value(0)
	end
	stmt:finalize()
	return info and _("History") or nil
end

function dat.get()
	return info
end

function dat.ver()
	return ver
end

return dat