1local xml = {} 2 3function xml.filename(name) 4 return name .. ".xml" 5end 6 7-- basic xml parser for mamecheat only 8local function xml_parse(data) 9 local function fix_gt(str) 10 str = str:gsub(">=", " ge ") 11 str = str:gsub(">", " gt ") 12 return str 13 end 14 data = data:gsub("(condition=%b\"\")", fix_gt) 15 local cheat_str = data:match("<mamecheat.->(.*)</ *mamecheat>") 16 17 local function get_tags(str) 18 local arr = {} 19 while str ~= "" do 20 local tag, attr, stop 21 tag, attr, stop, str = str:match("<([%w!%-]+) ?(.-)(/?)[ %-]->(.*)") 22 23 if not tag then 24 return arr 25 end 26 if tag:sub(0, 3) ~= "!--" then 27 local block = {} 28 if stop ~= "/" then 29 local nest 30 nest, str = str:match("(.-)</ *" .. tag .. " *>(.*)") 31 local children = get_tags(nest) 32 if not next(children) then 33 nest = nest:gsub("<!--.-%-%->", "") 34 nest = nest:gsub("^%s*(.-)%s*$", "%1") 35 block["text"] = nest 36 else 37 block = children 38 end 39 end 40 if attr then 41 for name, value in attr:gmatch("(%w-)=\"(.-)\"") do 42 block[name] = value:gsub("^%s*(.-)%s*$", "%1") 43 end 44 end 45 if not arr[tag] then 46 arr[tag] = {} 47 end 48 arr[tag][#arr[tag] + 1] = block 49 end 50 end 51 return arr 52 end 53 local xml_table = get_tags(cheat_str) 54 return xml_table 55end 56 57function xml.conv_cheat(data) 58 local spaces, regions, output 59 data = xml_parse(data) 60 local cpu_spaces = {} 61 62 for tag, device in pairs(manager:machine().devices) do 63 local sp 64 for name, space in pairs(device.spaces) do 65 if not sp then 66 sp = {} 67 cpu_spaces[tag] = sp 68 end 69 sp[space.index] = space.name 70 end 71 end 72 73 local function convert_expr(data) 74 local write = false 75 76 local function convert_memref(cpu, phys, space, width, addr, rw) 77 -- debug expressions address spaces by index not by name 78 local function get_space_name(index) 79 local prefix = cpu:sub(1,1) 80 if prefix == ":" then 81 return cpu_spaces[cpu][index] 82 else 83 return cpu_spaces[":" .. cpu][index] 84 end 85 end 86 87 local mod = "" 88 local count 89 if space == "p" then 90 fullspace = get_space_name(0) 91 elseif space == "d" then 92 fullspace = get_space_name(1) 93 elseif space == "i" then 94 fullspace = get_space_name(2) 95 elseif space == "r" then 96 fullspace = get_space_name(0) 97 mod = "direct_" 98 space = "p" 99 elseif space == "o" then 100 fullspace = get_space_name(3) 101 mod = "direct_" 102 space = "o" 103 end 104 if width == "b" then 105 width = "u8" 106 elseif width == "w" then 107 width = "u16" 108 elseif width == "d" then 109 width = "u32" 110 elseif width == "q" then 111 width = "u64" 112 end 113 114 local prefix = cpu:sub(1,1) 115 if prefix == ":" then 116 cpu = cpu:sub(2,cpu:len()) 117 end 118 119 local cpuname = cpu:gsub(":", "_") 120 if space == "m" then 121 regions[cpuname .. space] = ":" .. cpu 122 else 123 spaces[cpuname .. space] = { tag = ":" .. cpu, type = fullspace } 124 if phys ~= "p" and mod == "" then 125 mod = "log_" 126 end 127 end 128 if rw == "=" then 129 write = true 130 ret = cpuname .. space .. ":" .. "write_" .. mod .. width .. "(" .. addr .. "," 131 else 132 ret = cpuname .. space .. ":" .. "read_" .. mod .. width .. "(" .. addr .. ")" 133 end 134 if rw == "==" then 135 ret = ret .. "==" 136 end 137 return ret 138 end 139 140 local function frame() 141 output = true 142 return "screen:frame_number()" 143 end 144 145 data = data:lower() 146 data = data:gsub("^[(](.-)[)]$", "%1") 147 data = data:gsub("%f[%w]lt%f[%W]", "<") 148 data = data:gsub("%f[%w]ge%f[%W]", ">=") 149 data = data:gsub("%f[%w]gt%f[%W]", ">") 150 data = data:gsub("%f[%w]le%f[%W]", "<=") 151 data = data:gsub("%f[%w]eq%f[%W]", "==") 152 data = data:gsub("%f[%w]ne%f[%W]", "~=") 153 data = data:gsub("!=", "~=") 154 data = data:gsub("||", " or ") 155 data = data:gsub("%f[%w]frame%f[%W]", frame) 156 data = data:gsub("%f[%w]band%f[%W]", "&") 157 data = data:gsub("%f[%w]bor%f[%W]", "|") 158 data = data:gsub("%f[%w]rshift%f[%W]", ">>") 159 data = data:gsub("%f[%w]lshift%f[%W]", "<<") 160 data = data:gsub("(%w-)%+%+", "%1 = %1 + 1") 161 data = data:gsub("%f[%w](%x+)%f[%W]", "0x%1") 162 -- 0?x? avoids an issue where db (data region byte) is interepeted as a hex number 163 data = data:gsub("([%w_:]-)%.(p?)0?x?([pmrodi3])([bwdq])@(%w+) *(=*)", convert_memref) 164 repeat 165 data, count = data:gsub("([%w_:]-)%.(p?)0?x?([pmrodi3])([bwdq])@(%b()) *(=*)", convert_memref) 166 until count == 0 167 if write then 168 data = data .. ")" 169 end 170 return data 171 end 172 173 local function convert_output(data) 174 local str = "draw_text(screen," 175 if data["align"] then 176 str = str .. data["align"] 177 else 178 str = str .. "\"left\"" 179 end 180 if data["line"] then 181 str = str .. ",\"" .. data["line"] .. "\"" 182 else 183 str = str .. ", \"auto\"" 184 end 185 str = str .. ", nil,\"" .. data["format"] .. "\"" 186 if data["argument"] then 187 for count, block in pairs(data["argument"]) do 188 local expr = convert_expr(block["text"]) 189 if block["count"] then 190 for i = 0, block["count"] - 1 do 191 str = str .. "," .. expr:gsub("argindex", i) 192 end 193 else 194 str = str .. "," .. expr 195 end 196 end 197 end 198 return str .. ")" 199 end 200 201 local function convert_script(data) 202 local str = "" 203 local state = "run" 204 for tag, block in pairs(data) do 205 if tag == "state" then 206 state = block 207 elseif tag == "action" then 208 for count, action in pairs(block) do 209 if action["condition"] then 210 str = str .. " if (" .. convert_expr(action["condition"]) .. ") then " 211 for expr in action["text"]:gmatch("([^,]+)") do 212 str = str .. convert_expr(expr) .. " " 213 end 214 str = str .. "end" 215 else 216 for expr in action["text"]:gmatch("([^,]+)") do 217 str = str .. " " .. convert_expr(expr) .. " " 218 end 219 end 220 end 221 elseif tag == "output" then 222 output = true 223 for count, output in pairs(block) do 224 if output["condition"] then 225 str = str .. " if " .. convert_expr(output["condition"]) .. " then " 226 str = str .. convert_output(output) .. " end " 227 else 228 str = str .. " " .. convert_output(output) .. " " 229 end 230 end 231 end 232 end 233 return state, str 234 end 235 236 for count, cheat in pairs(data["cheat"]) do 237 spaces = {} 238 regions = {} 239 output = false 240 for tag, block in pairs(cheat) do 241 if tag == "comment" then 242 data["cheat"][count]["comment"] = block[1]["text"] 243 elseif tag == "script" then 244 local scripts = {} 245 for count2, script in pairs(block) do 246 local state, str = convert_script(script) 247 scripts[state] = str 248 end 249 data["cheat"][count]["script"] = scripts 250 elseif tag == "parameter" then 251 if block[1]["min"] then 252 block[1]["min"] = block[1]["min"]:gsub("%$","0x") 253 end 254 if block[1]["max"] then 255 block[1]["max"] = block[1]["max"]:gsub("%$","0x") 256 end 257 if block[1]["step"] then 258 block[1]["step"] = block[1]["step"]:gsub("%$","0x") 259 end 260 data["cheat"][count]["parameter"] = block[1] 261 end 262 end 263 if next(spaces) then 264 data["cheat"][count]["space"] = {} 265 for name, space in pairs(spaces) do 266 data["cheat"][count]["space"] = {} 267 data["cheat"][count]["space"][name] = { type = space["type"], tag = space["tag"] } 268 end 269 end 270 if next(regions) then 271 data["cheat"][count]["region"] = {} 272 for name, region in pairs(regions) do 273 data["cheat"][count]["region"] = {} 274 data["cheat"][count]["region"][name] = region 275 end 276 end 277 if output then 278 data["cheat"][count]["screen"] = {} 279 data["cheat"][count]["screen"]["screen"] = ":screen" 280 end 281 end 282 return data["cheat"] 283end 284 285return xml 286