summaryrefslogtreecommitdiff
path: root/dalos-struct.lua
diff options
context:
space:
mode:
Diffstat (limited to 'dalos-struct.lua')
-rw-r--r--dalos-struct.lua601
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)