128 lines
3.6 KiB
Lua
128 lines
3.6 KiB
Lua
|
|
-- Import
|
|
|
|
local ffi = require 'ffi'
|
|
local bit = require 'bit'
|
|
|
|
-- Constants
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- Util
|
|
|
|
local HEX_TO_BIN = {
|
|
['0'] = '0000', ['1'] = '0001', ['2'] = '0010', ['3'] = '0011',
|
|
['4'] = '0100', ['5'] = '0101', ['6'] = '0110', ['7'] = '0111',
|
|
['8'] = '1000', ['9'] = '1001', ['A'] = '1010', ['B'] = '1011',
|
|
['C'] = '1100', ['D'] = '1101', ['E'] = '1110', ['F'] = '1111',
|
|
}
|
|
|
|
local function to_hex (val, nr_elements, element_size)
|
|
local l = {}
|
|
for i = 0, nr_elements - 1 do
|
|
local v = val[i]
|
|
l[#l+1] = bit.tohex(v, -2*element_size)
|
|
l[#l+1] = ' '
|
|
end
|
|
l[#l] = nil
|
|
return table.concat(l, '')
|
|
end
|
|
|
|
local function to_bin (val, nr_elements, element_size)
|
|
return to_hex(val, nr_elements, element_size):gsub('[0-9A-F]', HEX_TO_BIN)
|
|
end
|
|
|
|
local function is_nice_unicode_string (str)
|
|
-- TODO... Maybe also look into a purely binary oriented representation.
|
|
return false
|
|
end
|
|
|
|
local function is_nice_ascii_string (str)
|
|
for i = 1, #str do
|
|
local byte = str:byte(i)
|
|
if not (32 <= byte and byte <= 126) then return false end
|
|
end
|
|
return true
|
|
end
|
|
|
|
local function get_type_and_size_of_singular ( ctype )
|
|
local nr_elements, layers = 1, 0
|
|
while true do
|
|
local etype, elements = ctype:match('(.+)%[(%d*)%]$')
|
|
if not elements then break end
|
|
ctype, nr_elements = etype, nr_elements * elements
|
|
layers = layers + 1
|
|
end
|
|
return ctype, nr_elements, layers
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
local CDATA_REPR_MATCHER = 'cdata<(.+)>: (0x%w+)'
|
|
|
|
|
|
local function format_cdata (value, display, l, format_value)
|
|
|
|
-- Error check
|
|
assert(type(value) == 'cdata' )
|
|
assert(type(display) == 'number' )
|
|
assert(type(l) == 'table' )
|
|
assert(type(format_value) == 'function')
|
|
|
|
-- Do stuff
|
|
local native_repr = tostring(value)
|
|
local data_length = ffi.sizeof(value)
|
|
local ctype, addr = native_repr:match(CDATA_REPR_MATCHER)
|
|
|
|
-- Is void pointer?
|
|
if ctype == 'void *' then
|
|
local address_pointing_at = tonumber(ffi.cast('int', value))
|
|
l[#l+1] = 'void pointer to ' .. addr
|
|
return ;
|
|
end
|
|
|
|
-- Is normal pointer?
|
|
if ctype:match('%*$') then
|
|
if type(value[0]) ~= 'cdata' then
|
|
-- Data presentable in Lua, refered to by pointers?
|
|
l[#l+1] = 'pointer to '
|
|
return format_value(value[0], display, l.options, l)
|
|
else
|
|
l[#l+1] = '* '
|
|
return format_cdata(value[0], display, l.options, l, format_value)
|
|
end
|
|
end
|
|
|
|
l[#l+1] = 'cdata {'
|
|
--l[#l+1] = '\n\tnative = \'' .. native_repr .. '\','
|
|
l[#l+1] = '\n\ttype = ' .. ctype .. ','
|
|
l[#l+1] = '\n\taddr = ' .. addr .. ','
|
|
if data_length then
|
|
-- Size
|
|
local str = ffi.string(value, data_length)
|
|
l[#l+1] = '\n\tsize = ' .. data_length .. ','
|
|
|
|
-- Element size and type
|
|
local element_type, nr_elements, nr_layers = get_type_and_size_of_singular(ctype)
|
|
local element_size = data_length / nr_elements
|
|
l[#l+1] = '\n\tnr_e = ' .. nr_elements .. ','
|
|
l[#l+1] = '\n\ttype_e = ' .. element_type .. ','
|
|
l[#l+1] = '\n\tsize_e = ' .. element_size .. ','
|
|
|
|
-- If can be expressed as string, express it as string.
|
|
if is_nice_ascii_string(str) or is_nice_unicode_string(str) then
|
|
local string_or_unicode = is_nice_ascii_string(str) and 'ascii' or 'utf8 '
|
|
l[#l+1] = '\n\t'..string_or_unicode..' = ' .. str .. ','
|
|
end
|
|
--
|
|
if nr_layers == 1 then
|
|
-- Only a single level of arrays
|
|
l[#l+1] = '\n\thex = ' .. to_hex(value, nr_elements, element_size) .. ','
|
|
l[#l+1] = '\n\tbin = ' .. to_bin(value, nr_elements, element_size) .. ','
|
|
end
|
|
|
|
end
|
|
l[#l+1] = '\n}'
|
|
end
|
|
|
|
return format_cdata
|