Dark Byte Site Admin
Reputation: 470
Joined: 09 May 2003 Posts: 25796 Location: The netherlands
|
Posted: Mon Aug 18, 2025 4:25 am Post subject: Convert structure to C header file (AI generated) |
|
|
Here's a script that will convert a structure to a C header file
(100% ai written with only 15 prompts)
Code: |
-- Lua script for Cheat Engine: Generate C header from a Structure object,
-- handling gaps, overlaps, recursion, nested structs, all value types, signed/unsigned integer display,
-- unnamed fields, and cleans up invalid C identifier characters in element names.
-- Assumes vtByte .. vtWideString are already defined in CE. (Do not redeclare them!)
local function mapVartypeToC(elem, child_struct_typename)
local vt = elem.Vartype
local display = elem.DisplayMethod
local signed = (display == 'dtSignedInteger')
if vt == vtByte then
return signed and "signed char" or "unsigned char", elem.Bytesize
elseif vt == vtWord then
return signed and "short" or "unsigned short", elem.Bytesize
elseif vt == vtDword then
return signed and "int" or "unsigned int", elem.Bytesize
elseif vt == vtQword then
return signed and "long long" or "unsigned long long", elem.Bytesize
elseif vt == vtSingle then
return "float", elem.Bytesize
elseif vt == vtDouble then
return "double", elem.Bytesize
elseif vt == vtPointer then
if child_struct_typename then
if elem.NestedStructure then
return child_struct_typename, elem.Bytesize
else
return child_struct_typename .. "*", elem.Bytesize
end
else
return "void*", elem.Bytesize
end
elseif vt == vtString then
return "char", elem.Bytesize
elseif vt == vtWideString then
return "wchar_t", elem.Bytesize // 2
else
return "int", elem.Bytesize
end
end
local function getStructTypeName(structure)
-- Only allow valid C identifier characters for struct names
return tostring(structure.Name):gsub("[^%w_]", "_")
end
local function getElementName(elem)
local rawname = elem.Name or ""
local name
if rawname == "" then
name = string.format("unnamed%X", elem.Offset or 0)
else
-- Replace invalid C identifier characters with '_'
name = tostring(rawname):gsub("[^%w_]", "_")
-- C identifiers can't start with a digit
if name:match("^[0-9]") then
name = "_" .. name
end
end
return name
end
local function generate_c_header(structure, defined_structs)
defined_structs = defined_structs or {}
local struct_name = getStructTypeName(structure)
if defined_structs[struct_name] then
return "" -- already defined, skip
end
defined_structs[struct_name] = true
local guard = ("_%s_H_"):format(struct_name):upper():gsub("%W","_")
local out = {}
table.insert(out, "#ifndef "..guard)
table.insert(out, "#define "..guard)
table.insert(out, "")
table.insert(out, "#include <stdint.h>")
table.insert(out, "#include <wchar.h>")
table.insert(out, "")
table.insert(out, ("typedef struct %s {"):format(struct_name))
local used_bytes = {}
local current_offset = 0
local reserved_count = 0
local child_struct_defs = {}
for i=0, structure.Count-1 do
local elem = structure.Element[i]
if elem then
local elem_offset = elem.Offset
local elem_end = elem_offset + elem.Bytesize
local child_struct_typename = nil
local name = getElementName(elem)
if elem.Vartype == vtPointer and elem.ChildStruct then
child_struct_typename = getStructTypeName(elem.ChildStruct)
if not defined_structs[child_struct_typename] then
table.insert(child_struct_defs, generate_c_header(elem.ChildStruct, defined_structs))
end
end
local ctype, size = mapVartypeToC(elem, child_struct_typename)
local overlap = false
for b = elem_offset, elem_end - 1 do
if used_bytes[b] then
overlap = true
break
end
end
if overlap then
table.insert(out, (" // Field '%s' REMOVED due to overlap with a previous field"):format(name))
else
if elem_offset > current_offset then
local gap = elem_offset - current_offset
reserved_count = reserved_count + 1
table.insert(out, (" unsigned char reserved_%d[%d]; // gap"):format(reserved_count, gap))
current_offset = current_offset + gap
end
if elem.Vartype == vtString or elem.Vartype == vtWideString then
table.insert(out, (" %s %s[%d];"):format(ctype, name, size))
if elem.Vartype == vtWideString then
current_offset = current_offset + size * 2
else
current_offset = current_offset + size
end
elseif elem.Vartype == vtPointer and elem.ChildStruct and elem.NestedStructure then
table.insert(out, (" %s %s;"):format(ctype, name))
current_offset = current_offset + elem.Bytesize
else
local use_array = false
local type_size = size
if elem.Vartype == vtByte then type_size = 1
elseif elem.Vartype == vtWord then type_size = 2
elseif elem.Vartype == vtDword then type_size = 4
elseif elem.Vartype == vtQword then type_size = 8
elseif elem.Vartype == vtSingle then type_size = 4
elseif elem.Vartype == vtDouble then type_size = 8
elseif elem.Vartype == vtPointer then type_size = elem.Bytesize
end
if elem.Bytesize > type_size then
use_array = true
end
if use_array then
table.insert(out, (" %s %s[%d];"):format(ctype, name, elem.Bytesize // type_size))
else
table.insert(out, (" %s %s;"):format(ctype, name))
end
current_offset = current_offset + elem.Bytesize
end
for b = elem_offset, elem_end - 1 do
used_bytes[b] = true
end
end
end
end
table.insert(out, ("} %s;"):format(struct_name))
table.insert(out, "")
table.insert(out, "#endif // "..guard)
if #child_struct_defs > 0 then
table.insert(out, table.concat(child_struct_defs, "\n"))
end
return table.concat(out, "\n")
end
-- Usage in Cheat Engine:
-- local header = generate_c_header(structure)
-- print(header)
|
_________________
Do not ask me about online cheats. I don't know any and wont help finding them.
Like my help? Join me on Patreon so i can keep helping |
|