diff options
Diffstat (limited to 'dalos-struct.lua')
-rw-r--r-- | dalos-struct.lua | 601 |
1 files changed, 601 insertions, 0 deletions
diff --git a/dalos-struct.lua b/dalos-struct.lua new file mode 100644 index 0000000..5f157ef --- /dev/null +++ b/dalos-struct.lua @@ -0,0 +1,601 @@ +local function imLoadImage(fname) + local f = im.FileOpen(fname) + local r = f:LoadImage() + f:Close() + return r +end + +dalosp.struct = { + templates = {}, + + images = { + up = imLoadImage "12-em-up.tga", + down = imLoadImage "12-em-down.tga", + cross = imLoadImage "12-em-cross.tga", + plus = imLoadImage "12-em-plus.tga", + }, + + types = { + "int8", + "uint8", + "int16", + "uint16", + "int32", + "uint32", + "int64", + "uint64", + "float", + "double", + "nascii", + "asciiz", + }, + + rtypes = { + int8 = 1, + uint8 = 2, + int16 = 3, + uint16 = 4, + int32 = 5, + uint32 = 6, + int64 = 7, + uint64 = 8, + float = 9, + double = 10, + nascii = 11, + asciiz = 12, + }, + + typessizes = { + 1, 1, 2, 2, 4, 4, 8, 8, 4, 8, 1, -1, + }, + + get_settings = function (self) + return { entries = self.extra.entries } + end, + + configure = function (self) + self.cfg_dlg:show() + end, + + activate = function (self) + self.act_dlg:show() + end, + + input_change = function (self, ind) + if ind == 1 then self:update_values() end + if ind == 2 then + local h = self:get_linked_input(2) + self:auto_template(dalosp.struct.templates, h:readstring()) + end + end, + + offset = function (self, lin) + local cache = self.extra.cache + return cache[lin] + end, + + read_value = function (self, h, t, flags, size) + local v + + if t == "int8" then + return h:read8() + elseif t == "uint8" then + return h:readU8() + elseif t == "int16" then + return h:read16() + elseif t == "uint16" then + return h:readU16() + elseif t == "int32" then + return h:read32() + elseif t == "uint32" then + return h:readU32() + elseif t == "int64" then + return h:read64() + elseif t == "uint64" then + return h:readU64() + elseif t == "float" then + return h:readFloat() + elseif t == "double" then + return h:readDouble() + elseif t == "asciiz" then + v = "" + local b + repeat + b = h:readU8() + if b ~= 0 then v = v .. string.char(b) end + until b == 0 + return v + elseif t == "nascii" then + return h:readstring(size) + end + + return 0 + end, + + update_values = function (self) + local h = self:get_linked_input(1) + self.extra.values = {} + self.extra.values_by_name = {} + if h and h:getsize() >= self.extra.size then + h:seek(0) + local v, s, t + for e, f in ipairs(self.extra.entries) do + s = f.size + if not tonumber(s) then + s = self.extra.values_by_name[s] + end + t = dalosp.struct.types[f.type] + if t == "asciiz" or t == "nascii" or s == 1 then + v = self:read_value(h, t, f.flags, s) + else + v = {} + for i = 1, f.size do + v[i] = self:read_value(h, t, f.flags, s) + end + end + self.extra.values[e] = v + self.extra.values_by_name[f.name] = v + end + self:output_selected() + self:output_struct() + else + self:set_houtput(nil, 1) + self:set_houtput(nil, 2) + end + end, + + output_selected = function (self) + local selected = self.extra.selected + local cache = self.extra.cache + local cursor = selected and cache[selected] or -1 + local h = self:get_linked_input(1) + if h and selected and selected > 0 and cursor >= 0 then + local field = self.extra.entries[selected].name + local maxsize = (cache[selected + 1] or self.extra.size) - cursor + h:seek(cursor) + local obj = { + h = h, + str = self, + origin = cursor, + field = field, + size = maxsize - cursor, + getname = function (self) return self.str.name .. ":" .. self.field end, + getmodif = function (self) return self.h:getmodif() end, + do_seek = function (self) + self.h:seek(self.offset + self.origin) + end, + do_read = function (self, count, userdata) + return self.h:read(count, userdata) + end, + } + self:set_houtput(dalos.luahandle(obj), 1) + local b = Buffer(true) + b:write(field .. "\n") + self:set_houtput(b, 3) + else + self:set_houtput(nil, 1) + self:set_houtput(nil, 3) + end + end, + + output_struct = function (self) + local b = Buffer(true) + dumpvars(b, self.extra.values_by_name, "data") + self:set_houtput(b, 2) + end, + + cacheoffset = function (self) + local entries = self.extra.entries + self.extra.cache = {} + local cache = self.extra.cache + local offset = 0 + local got_var = false + local ssize + local vsize + + for i, v in ipairs(entries) do + ssize = dalosp.struct.typessizes[v.type] + vsize = ssize == -1 or type(v.size) ~= "number" + if vsize then got_var = true end + if got_var then + cache[i] = -1 + else + cache[i] = offset + end + if not vsize then offset = offset + ssize * v.size end + end + self.extra.size = offset + if self.cfg_dlg then + self.cfg_dlg.mx.redraw = "C10" + self.cfg_dlg.lsize.title = offset + self:update_values() + self.act_dlg.mx.numlin = #entries + self.act_dlg.mx.numlin_visible = #entries + self.act_dlg.mx.redraw = "All" + end + end, + + isunique = function (self, name) + for _, v in ipairs(self.extra.entries) do + if name == v.name then return false end + end + return true + end, + + getunique = function (self, lin) + local newname = "Field" .. lin + local base_newname = newname + local i = 1 + while not self:isunique(newname) do + newname = base_newname .. "." .. i + i = i + 1 + end + return newname + end, + + insert_line = function (self, lin) + if not lin then lin = (#self.extra.entries + 1) end + local name = self:getunique(lin) + table.insert(self.extra.entries, lin, { name = name, type = 1, size = 1 }) + self:cacheoffset() + local mx = self.cfg_dlg.mx + mx.numlin = mx.numlin + 1 + mx.numlin_visible = mx.numlin_visible + 1 + end, + + remove_line = function (self, lin) + table.remove(self.extra.entries, lin) + self:cacheoffset() + local mx = self.cfg_dlg.mx + mx.numlin = mx.numlin - 1 + mx.numlin_visible = mx.numlin_visible - 1 + end, + + line_up = function (self, lin) + if lin == 1 then return iup.DEFAULT end + local entries = self.extra.entries + local old_lin = entries[lin] + table.remove(entries, lin) + table.insert(entries, lin - 1, old_lin) + self:cacheoffset() + local mx = self.cfg_dlg.mx + mx.redraw = "L" .. (lin - 1) + mx.redraw = "L" .. lin + end, + + line_down = function (self, lin) + local entries = self.extra.entries + if lin == #entries then return iup.DEFAULT end + local old_lin = entries[lin] + table.remove(entries, lin) + table.insert(entries, lin + 1, old_lin) + self:cacheoffset() + local mx = self.cfg_dlg.mx + mx.redraw = "L" .. lin + mx.redraw = "L" .. (lin + 1) + end, + + gen_template = function (self) + return self:get_settings() + end, + + apply_template = function (self, data) + self.extra.entries = data.entries + self:cacheoffset() + end, + + get_field_value = function (self, lin) + local v = self.extra.values[lin] + if type(v) == "table" then + local r = nil + for k, sv in ipairs(v) do + if not r then + r = sv + else + r = r .. ", " .. sv + end + end + + return "[" .. (r or " ") .."]" + else + return v or "" + end + end, + + cfg_draw_cb = function (self, lin, col, x1, x2, y1, y2, cv) + if col == 1 then + dalosp.struct.images.plus:cdCanvasPutImageRect(cv, x1 + 3, y2 + 5, 12, 12, 0, 12, 0, 12) + return iup.DEFAULT + elseif col == 2 and lin ~= 0 then + dalosp.struct.images.cross:cdCanvasPutImageRect(cv, x1 + 3, y2 + 5, 12, 12, 0, 12, 0, 12) + return iup.DEFAULT + elseif col == 3 and lin ~= 0 and lin ~= 1 then + dalosp.struct.images.up:cdCanvasPutImageRect(cv, x1 + 3, y2 + 5, 12, 12, 0, 12, 0, 12) + return iup.DEFAULT + elseif col == 4 and lin ~= 0 and lin ~= #self.struct.extra.entries then + dalosp.struct.images.down:cdCanvasPutImageRect(cv, x1 + 3, y2 + 5, 12, 12, 0, 12, 0, 12) + return iup.DEFAULT + end + + return iup.IGNORE + end, + + cfg_click_cb = function (self, lin, col, status) + if col == 1 and lin == 0 then return self.struct:insert_line() end + if lin == 0 then return iup.DEFAULT end + + if col == 1 then + self.struct:insert_line(lin) + elseif col == 2 then + self.struct:remove_line(lin) + elseif col == 3 then + self.struct:line_up(lin) + elseif col == 4 then + self.struct:line_down(lin) + elseif col == 11 then + -- edit flags + end + end, + + cfg_value_cb = function (self, lin, col) + if lin == 0 then + if col == 5 then + return "Name" + elseif col == 6 then + return "Type" + elseif col == 7 then + return "Size" + elseif col == 8 then + return "Enum" + elseif col == 9 then + return "Value Check" + elseif col == 10 then + return "Offset" + elseif col == 11 then + return "Flags" + end + return "" + end + + local entries = self.struct.extra.entries + + if col == 5 then + return entries[lin].name + elseif col == 6 then + return dalosp.struct.types[entries[lin].type] + elseif col == 7 then + return entries[lin].size + elseif col == 10 then + local off = self.struct:offset(lin) + if off == -1 then return "" end + return off + elseif col == 11 then + -- flags + end + + return "" + end, + + cfg_value_edit_cb = function (self, lin, col, newval) + local entries = self.struct.extra.entries + + if col == 5 then + entries[lin].name = newval + self.struct:output_selected() + self.struct:output_struct() + elseif col == 6 then + entries[lin].type = dalosp.struct.rtypes[newval] + self.struct:cacheoffset() + elseif col == 7 then + local nnewval = tonumber(newval) + if nnewval then newval = nnewval end + entries[lin].size = newval + self.struct:cacheoffset() + elseif col == 8 then + -- enum + elseif col == 9 then + -- value check + end + self.struct.act_dlg.mx.redraw = "All" + end, + + cfg_dropcheck_cb = function (self, lin, col) + return col == 6 and iup.DEFAULT or iup.IGNORE + end, + + cfg_edition_cb = function (self, lin, col, mode, update) + if mode == 1 then + return (col >= 5 and col <= 7) and iup.DEFAULT or iup.IGNORE + else + local newval = self.value + if update == 0 then return iup.DEFAULT end + if col == 5 then + if not self.struct:isunique(newval) then return iup.IGNORE end + elseif col == 6 then + -- do a check on the dropdown ? I don't think so + elseif col == 7 then + if not tonumber(newval) and self.struct:isunique(newval) then return iup.IGNORE end + elseif col == 8 then + -- enum + elseif col == 9 then + -- value check + end + return iup.DEFAULT + end + end, + + cfg_drop_cb = function (self, drop, lin, col) + if col ~= 6 then return iup.IGNORE end + + for i, v in ipairs(dalosp.struct.types) do + drop[i] = v + end + drop.value = self.previousvalue + drop.visible_items = 15 + + return iup.DEFAULT + end, + + act_value_cb = function (self, lin, col) + if lin == 0 then if col == 1 then return "Field" elseif col == 2 then return "Value" end end + if col == 0 then return nil end + + local entry = self.struct.extra.entries[lin] + + if col == 1 then + return entry.name + else + return self.struct:get_field_value(lin) + end + end, + + act_click_cb = function (self, lin, col, status) + self.struct.extra.selected = lin + self.struct:output_selected() + end, + + create = function (d, tab, settings) + tab.ninputs = 2 + tab.noutputs = 3 + tab.otype = dalos.objtype.LUA_VIEWER + tab.configure = dalosp.struct.configure + tab.activate = dalosp.struct.activate + tab.input_change = dalosp.struct.input_change + tab.get_settings = dalosp.struct.get_settings + tab.gen_template = dalosp.struct.gen_template + tab.apply_template = dalosp.struct.apply_template + tab.draw = function (self, cv, x, y, w, h) + dalosp.object.default_draw(self, cv, x, y, w, h) + end + tab.default_name = "Struct" + tab.ntype = "Struct" + + local extra = { } + if not settings then settings = {} end + local entries = settings.entries or {} + extra.entries = entries + + local obj = dalos.object(d, tab, extra) + + obj.insert_line = dalosp.struct.insert_line + obj.remove_line = dalosp.struct.remove_line + obj.line_up = dalosp.struct.line_up + obj.line_down = dalosp.struct.line_down + obj.offset = dalosp.struct.offset + obj.cacheoffset = dalosp.struct.cacheoffset + obj.isunique = dalosp.struct.isunique + obj.getunique = dalosp.struct.getunique + obj.get_field_value = dalosp.struct.get_field_value + obj.update_values = dalosp.struct.update_values + obj.read_value = dalosp.struct.read_value + obj.output_selected = dalosp.struct.output_selected + obj.output_struct = dalosp.struct.output_struct + + local cmx = iup.matrix { + numcol = 11, + numcol_visible = 11, + usetitlesize = "Yes", + rasterwidth1 = 12, + rasterwidth2 = 12, + rasterwidth3 = 12, + rasterwidth4 = 12, + rasterwidth5 = 120, + rasterwidth6 = 80, + rasterwidth7 = 80, + rasterwidth8 = 80, + rasterwidth9 = 120, + rasterwidth10 = 40, + rasterwidth11 = 60, + resizematrix = "Yes", + readonly = "No", + struct = obj, + draw_cb = dalosp.struct.cfg_draw_cb, + value_cb = dalosp.struct.cfg_value_cb, + value_edit_cb = dalosp.struct.cfg_value_edit_cb, + dropcheck_cb = dalosp.struct.cfg_dropcheck_cb, + drop_cb = dalosp.struct.cfg_drop_cb, + edition_cb = dalosp.struct.cfg_edition_cb, + click_cb = dalosp.struct.cfg_click_cb, + } + local amx = iup.matrix { + numcol = 2, + numcol_visible = 2, + usetitlesize = "Yes", + rasterwidth1 = 120, + rasterwidth2 = 120, + readonly = "Yes", + resizematrix = "Yes", + struct = obj, + value_cb = dalosp.struct.act_value_cb, + click_cb = dalosp.struct.act_click_cb, + } + local lsize = iup.label { title = "0", expand = "Horizontal", } + + obj.cfg_dlg = iup.dialog { + iup.vbox { + iup.hbox { + iup.label { title = "Struct size: " }, + lsize, + }, + cmx, + iup.hbox { + iup.fill {}, + iup.button { + title = "Ok", + action = function (self) return iup.CLOSE end, + }, + iup.button { + title = "Import", + action = function() obj:load_template() return iup.CLOSE end, + }, + iup.button { + title = "Export", + action = function() obj:save_template(self:gen_template()) end, + }, + iup.button { + title = "Use Template", + action = function() obj:use_template(dalsop.struct.templates) end, + }, + iup.button { + title = "Change name", + action = function() local s, n = iup.GetParam("Change name", nil, "Name: %s\n", obj.name) if s then obj.name = n end end + }, + iup.fill {}, + iup.button { + title = "Close", + action = function() return iup.CLOSE end, + }, + }, + }, + + size = "500x220", + mx = cmx, + lsize = lsize, + title = obj.name .. " configuration", + } + + obj.act_dlg = iup.dialog { + amx, + size = "250x120", + mx = amx, + title = obj.name, + } + + if entries then + obj.cfg_dlg.mx.numlin = #entries + obj.cfg_dlg.mx.numlin_visible = #entries + obj.act_dlg.mx.numlin = #entries + obj.act_dlg.mx.numlin_visible = #entries + end + obj:cacheoffset() + + return obj + end, + + register_template = function (data, tname) + dalosp.struct.templates[tname] = data + end, +} + +dalos.struct = dalosp.struct.create +dalos:register_obj("Struct", dalos.struct, "Programmable", dalosp.struct.register_template) |