[v2.0.0]Struct——auto calc struct and init a struct

Post your working scripts, libraries and tools.
User avatar
Mono919
Posts: 71
Joined: 05 May 2022, 02:36

[v2.0.0]Struct——auto calc struct and init a struct

Post by Mono919 » 04 Feb 2023, 04:58

2023.03.27
1.Fix __delete() error

2023.03.14
1.Fix nest struct bugs.
2.Change Buffer to malloc for easily ptr create & free.(Need msvcrt.dll)

2023.02.26
1.Fix Union Eval Error.

Renew some setting like your struct now init all member as 0.

Automatic parsing of structure text cannot directly parse nested structures, but it can be solved step by step. It also cannot resolve the structure of single line and multiple statements.
advantage:
Union is support: it also does not support direct parsing of nested text, but supports named union and anonymous union
Plus: you can make a type_map to support more types.(This part please read the source code. Easily example in Usage 5.)
Usage1:

Code: Select all

#include <struct\struct>
struct_script := "
(
int a;
int b;
)"
my_struct := struct(struct_script) ; => equal to struct([["int", "a"], ["int", "b"]])
my_struct["a"] := 1
msgbox my_struct["a"]
my_struct["b"] := 4
my_struct.exportself() ; => ["int",1,"int",4]
Usage2:

Code: Select all

#include <struct\struct>
struct_script := "
(
int a;
int b;
struct c;
)"
my_struct := struct.eval(struct_script)
substruct_script := "
(
unsingned int a;
int b;
)"
my_struct[1][3].push(struct.eval(substruct_script)[1])
my_struct := struct(my_struct)
msgbox my_struct["c", "addr"]
; msgbox my_struct["c", "type"] => "ptr" a bug for read struct or union to ptr
msgbox my_struct["c"]["a", "addr"]
msgbox my_struct["c"]["a", "type"] ; => "uint"
; not support my_struct["c", "a"]
Usage3:

Code: Select all

#include <struct\struct>
struct_script := "
(
int a;
int b;
union d;
)"
union_script := "
(
char a;
int b;
struct d;
)"
substruct_script := "
(
char a;
int b;
)"
my_union := union.eval(union_script)[1]
my_union[3].push(struct.eval(substruct_script)[1])
my_struct := struct.eval(struct_script)
my_struct[1][3].push(my_union)
msgbox struct(my_struct)["d", "addr"]
Usage4:

Code: Select all

; size usage => not support union
#include <struct\struct>
struct_script := "
(
unsigned short a[100];
int b;
)"
my_struct := struct(struct_script) ; => equal to struct([["unsigned short", "a", {size: 100}], ["int", "b"]])
msgbox my_struct["a", "addr", 50] ; => 100
Usage5:

Code: Select all

#include <struct\struct>
type_map := map("hello", ["int", 4]) ; old use {}, but newest use map()
struct_script := "
(
hello a[100];
int b;
)"
my_struct := struct(struct_script, type_map) ; => equal to struct([["hello", "a", {size: 100}], ["int", "b"]], type_map)
debug my_struct["a", "addr", 50]
Latest Source Code(2023.03.27) ->
1.Fix __delete() error

Code: Select all

class struct
{
    static encoding := "utf-8"
    static warningFlag := false
    
    static type_map := map(
        "__int8", ["char", 1],
        "__int16", ["short", 2],
        "__int32", ["int", 4],
        "__int64", ["int64", 8],
        "bool", ["char", 1],
        "byte", ["char", 1],
        "char", ["char", 1],
        "double", ["double", 8],
        "error_status_t", ["uint", 4],
        "float", ["float", 4],
        "int", ["int", 4],
        "int8_t", ["char", 1],
        "int16_t", ["short", 2],
        "int32_t", ["int", 4],
        "int64_t", ["int64", 8],
        "long", ["int", 4],
        "long long", ["int64", 8],
        "short", ["short", 2],
        "signed char", ["char", 1],
        "signed int", ["int", 4],
        "signed short", ["short", 2],
        "signed long", ["int", 4],
        "signed __int64", ["int64", 8],
        "ptr", ["ptr", a_ptrsize],
        "size_t", ["uptr", a_ptrsize],
        "uint8_t", ["uchar", 1],
        "uint16_t", ["ushort", 2],
        "uint32_t", ["uint", 4],
        "uint64_t", ["uint64", 8],
        "unsigned", ["uint", 4],
        "unsigned __int64", ["uint64", 8],
        "unsigned char", ["uchar", 1],
        "unsigned int", ["uint", 4],
        "unsigned long", ["uint", 4],
        "unsigned short", ["ushort", 2],
        "wchar_t", ["ushort", 2],
        "BOOL", ["int", 4],
        "BOOLEAN", ["uchar", 1],
        "BSTR", ["ptr", a_ptrsize],
        "BYTE", ["uchar", 1],
        "CHAR", ["char", 1],
        "FLOAT", ["float", 4],
        "DOUBLE", ["double", 8],
        "DWORD", ["uint", 4],
        "DWORD_PTR", ["ptr", a_ptrsize],
        "DWORD32", ["uint", 4],
        "DWORD64", ["uint64", 8],
        "DWORDLONG", ["uint64", 8],
        "HANDLE", ["ptr", a_ptrsize],
        "HCALL", ["uint", 4],
        "HRESULT", ["int", 4],
        "INT", ["int", 4],
        "INT8", ["char", 1],
        "INT16", ["short", 2],
        "INT32", ["int", 4],
        "LDAP_UDP_HANDLE", ["ptr", a_ptrsize],
        "LMCSTR", ["ushort", 2],
        "LONG", ["int", 4],
        "LONG_PTR", ["ptr", a_ptrsize],
        "LONG32", ["int", 4],
        "LONG64", ["int64", 8],
        "LONGLONG", ["int64", 8],
        "LPCSTR", ["ptr", a_ptrsize],
        "LPCVOID", ["ptr", a_ptrsize],
        "LPCWSTR", ["ushort", 2],
        "LPSTR", ["ptr", a_ptrsize],
        "LPTSTR", ["ptr", a_ptrsize],
        "LPCTSTR", ["ptr", a_ptrsize],
        "NET_API_STATUS", ["uint", 4],
        "NTSTATUS", ["int", 4],
        "QWORD", ["uint64", 8],
        "RPC_BINDING_HANDLE", ["ptr", a_ptrsize],
        "SHORT", ["short", 2],
        "SIZE_T", ["uptr", a_ptrsize],
        "STRING", ["ptr", a_ptrsize],
        "UCHAR", ["uchar", 1],
        "UINT", ["uint", 4],
        "UINT8", ["uchar", 1],
        "UINT16", ["ushort", 2],
        "UINT32", ["uint", 4],
        "UINT64", ["uint64", 8],
        "ULONG", ["uint", 4],
        "ULONG_PTR", ["uptr", a_ptrsize],
        "ULONG32", ["uint", 4],
        "ULONG64", ["uint64", 8],
        "ULONGLONG", ["uint64", 8],
        "USHORT", ["ushort", 2],
        "UNICODE", ["ushort", 2],
        "VOID", ["ptr", a_ptrsize],
        "WCHAR", ["ushort", 2],
        "WORD", ["ushort", 2])
    
    static strBuffer(str, encoding := struct.encoding)
    {
        buf := buffer(strput(str, encoding))
        strput(str, buf, encoding)
        return buf
    }
    
    __new(ptr := 0, member_array := [], type_map := map(), default_value := map())
    {
        this.warning := ""
        this.mallocflag := false
        if ptr is array
        {
            this.ptr := 0
            this.members := ptr
            this.type_map := (member_array is map) ? member_array : type_map
        }
        else if ptr is string
        {
            this.ptr := 0
            tmp := struct.eval(ptr)
            this.members := tmp[1]
            default_value := tmp[2]
            this.type_map := (member_array is map) ? member_array : type_map
        }
        else
        {
            this.ptr := ptr
            this.members := member_array is string ? struct.eval(member_array) : member_array
            this.type_map := type_map
        }
        this.exports := [[],[]]
        for member in this.members
        {
            if member[1] = "struct" || member[1] = "union"
                get_type := member[1]
            else
                get_type := this.type_map.has(member[1]) ? this.type_map[member[1]][1] : struct.type_map.has(member[1]) ? struct.type_map[member[1]][1] : "ptr"
            this.exports[1].push(get_type)
            this.exports[2].push(member[2])
        }
        this.addr := this.align()
        this.members := this.rebuild()
        this.size := this.addr.pop()
        if !this.ptr
        {
            this.mallocflag := true
            this.ptr := dllcall("msvcrt\malloc", "uint", this.size)
            dllcall("msvcrt\memset", "ptr", this.ptr, "int", 0, "uint", this.size)
        }
        for key, value in default_value
            this[key] := value
    }
    
    __delete()
    {
        if this.ptr && this.mallocflag
            dllcall("msvcrt\free", "ptr", this.ptr)
    }
    
    __item[name, param*]
    {
        get
        {
            if !(name is array) && instr(name, ".")
                name := strsplit(name, ".")
            if name is array && param.length && param[1] = "addr"
            {
                total_addr := 0
                tmp := this
                loop name.length - 1
                {
                    total_addr += tmp[name[a_index], "addr"]
                    tmp := tmp[name[a_index]]
                }
                return total_addr + tmp[name[-1], param*]
            }
            else if name is array
            {
                tmp := this
                loop name.length - 1
                    tmp := tmp[name[a_index]]
                return tmp[name[-1], param*]
            }
            if this.members.has(name)
            {
                member := this.members[name]
                size := 1
                get_type := this.type_map.has(member[1]) ? this.type_map[member[1]] : struct.type_map.has(member[1]) ? struct.type_map[member[1]] : ["ptr", 8]
                if param.length
                {
                    if param[1] = "type"
                        return get_type[1]
                    if param[-1] is integer
                        size := member[2].hasprop("size") ? param[-1] + 1 : 1
                    if param[1] = "addr"
                        return (size = 1 || !member[2].hasprop("size")) ? member[-1] : member[-1] + (size - 1) * get_type[2]
                }
                if member[1] = "struct" || member[1] = "union"
                    return (size = 1 && !member[2].hasprop("size")) ? (member[2].%member[1]%) : (member[2].%member[1]%)[size]
                return numget(this.ptr, member[-1] + (size - 1) * get_type[2], get_type[1])
            }
            else if this.members.has("")
            {
                member := this.members[""]
                if member[1] = "union"
                {
                    if param.length && param[1] = "addr"
                    {
                        ret := member[2].union[name, param*]
                        if !(ret = "")
                            return ret + member[-1]
                    }
                    return member[2].union[name, param*]
                }
            }
        }
        
        set
        {
            if !(name is array) && instr(name, ".")
                name := strsplit(name, ".")
            if name is array
            {
                tmp := this
                loop name.length - 1
                    tmp := tmp[name[a_index]]
                tmp[name[-1], param*] := value
                return
            }
            if !isnumber(value) && value is string
                value := struct.strBuffer(value).ptr
            if this.members.has(name)
            {
                member := this.members[name]
                size := 1
                if param.length && param[-1] is integer
                    size := member[2].hasprop("size") ? param[-1] + 1 : 1
                if member[1] = "struct" || member[1] = "union"
                    return
                get_type := this.type_map.has(member[1]) ? this.type_map[member[1]] : struct.type_map.has(member[1]) ? struct.type_map[member[1]] : ["ptr", 8]
                return numput(get_type[1], value, member[-1] + (size - 1) * get_type[2], this.ptr)
            }
            else if this.members.has("")
            {
                member := this.members[""]
                if member[1] = "union"
                    return member[2].union[name, param] := value
            }
        }
    }
    
    align()
    {
        this.max_align := 0
        old_addr := addr := 0
        addr_array := []
        for member in this.members
        {
            type_map := this.type_map.has(member[1]) ? this.type_map : struct.type_map.has(member[1]) ? struct.type_map : ""
            if type_map
            {
                old_addr := addr
                type_size := type_map[member[1]][2]
                addr := struct.find_nearmul(addr, type_size)
                addr_array.push(addr)
                tmp_size := (member.length >= 3 && member[3].hasprop("size")) ? member[3].size : 1
                addr += type_size * tmp_size
                this.max_align := max(this.max_align, type_size)
            }
            else if instr(member[1], "*")
            {
                old_addr := addr
                type_size := a_ptrsize
                addr := struct.find_nearmul(addr, type_size)
                addr_array.push(addr)
                tmp_size := (member.length >= 3 && member[3].hasprop("size")) ? member[3].size : 1
                addr += type_size * tmp_size
                this.max_align := max(this.max_align, type_size)
            }
            else if member[1] = "struct"
            {
                struct_flag := member[3] is struct
                tmp_struct := !struct_flag ? struct(0, member[3], this.type_map) : member[3]
                old_addr := addr
                type_size := tmp_struct.max_align
                addr := struct.find_nearmul(addr, type_size)
                addr_array.push(addr)
                if (member.length >= 4 && member[4].hasprop("size"))
                {
                    tmp_array := [tmp_struct]
                    tmp_size := member[4].size
                    loop tmp_size - 1
                        tmp_array.push(!struct_flag ? struct(0, member[3], this.type_map) : (ptr := dllcall("msvcrt\malloc", "uint", member[3].size), dllcall("msvcrt\memset", "ptr", ptr, "int", 0, "uint", member[3].size), tmp := member[3].clone(), tmp.ptr := ptr, tmp))
                    member[3] := tmp_array
                    addr += tmp_struct.size * tmp_size
                }
                else
                {
                    member[3] := tmp_struct
                    addr += tmp_struct.size
                }
            }
            else if member[1] = "union"
            {
                if !(member[2] is string)
                    member.insertat(2, "")
                union_flag := member[3] is union
                tmp_union := !union_flag ? union(member[3], this.type_map) : member[3]
                old_addr := addr
                type_size := tmp_union.max_align
                addr := struct.find_nearmul(addr, type_size)
                addr_array.push(addr)
                if false ; (member.length >= 4 && member[4].hasprop("size"))
                {
                    tmp_array := [tmp_union]
                    tmp_size := member[4].size
                    loop tmp_size - 1
                        tmp_array.push(!union_flag ? union(member[3], this.type_map) : (ptr := dllcall("msvcrt\malloc", "uint", member[3].size), dllcall("msvcrt\memset", "ptr", ptr, "int", 0, "uint", member[3].size), tmp := member[3].clone(), tmp.ptr := ptr, tmp))
                    member[3] := tmp_array
                    addr += tmp_union.size * tmp_size
                }
                else
                {
                    member[3] := tmp_union
                    addr += tmp_union.size
                }
            }
            else
            {
                old_addr := addr
                type_size := a_ptrsize
                addr := struct.find_nearmul(addr, type_size)
                addr_array.push(addr)
                tmp_size := (member.length >= 3 && member[3].hasprop("size")) ? member[3].size : 1
                addr += type_size * tmp_size
                this.max_align := max(this.max_align, type_size)
                this.warning .= "type " member[1] " auto analysis as ptr.`n"
            }
        }
        addr_array.push(struct.find_nearmul(addr, this.max_align))
        return addr_array
    }
    
    export(values*)
    {
        export_array := []
        for value in this.exports[1]
        {
            try
                get_value := values[a_index]
            catch
                get_value := "nullptr"
            if get_value is array
            {
                if get_value[1] is struct
                {
                    tmp := get_value.clone()
                    tmp_struct := tmp.removeat(1)
                    export_array.push(tmp_struct.export(tmp*)*)
                }
                else
                    export_array.push(get_value*)
            }
            else if !(get_value = "nullptr")
                export_array.push(value, get_value)
        }
        return export_array
    }
    
    exportname()
    {
        warning := ""
        export_array := []
        index := 1
        for value in this.exports[1]
        {
            if value = "struct"
            {
                struct_name := this.exports[2][index++]
                tmp_array := this[struct_name].exportname()
                loop tmp_array.length
                    tmp_array[a_index] := struct_name "." tmp_array[a_index]
                export_array.push(tmp_array*)
            }
            else if value = "union"
                warning .= "union " this.exports[2][index++] " has been passed.`n"
            else
                export_array.push(this.exports[2][index++])
        }
        if warning && struct.warningFlag
            msgbox warning
        return export_array
    }
    
    exportself()
    {
        warning := ""
        export_array := []
        for value in this.exports[1]
        {
            if value = "struct"
                export_array.push(this[this.exports[2][a_index]].exportself()*)
            else if value = "union"
                warning .= "union " this.exports[2][a_index] " has been passed.`n"
            else
                export_array.push(value, this[this.exports[2][a_index]])
        }
        if warning && struct.warningFlag
            msgbox warning
        return export_array
    }
    
    rebuild()
    {
        members := map()
        for member in this.members
        {
            if member[1] = "struct" || member[1] = "union"
            {
                members[member[2]] := [member[1], {%strlower(member[1])%: member[3]}, this.addr[a_index]]
                if (member.length >= 4 && member[4].hasprop("size")) && member[1] != "union"
                    members[member[2]][2].size := member[4].size
            }
            else
            {
                members[member[2]] := [member[1], {}, this.addr[a_index]]
                if (member.length >= 3 && member[3].hasprop("size"))
                    members[member[2]][2].size := member[3].size
            }
        }
        return members
    }
    
    static eval(_string, mode := "struct")
    {
        _string := strreplace(_string, ",", ";,")
        blank_flag := " "
        dot_flag := ","
        tab_flag := "`t"
        end_flag := ";"
        equal_flag := "="
        star_flag := "*"
        lbracket1_flag := "["
        rbracket1_flag := "]"
        lbracket2_flag := "{"
        rbracket2_flag := "}"
        last_type := ""
        tmp_type := ""
        tmp_name := ""
        tmp_size := ""
        tmp_blank_flag := false
        tmp_struct_flag := false
        tmp_union_flag := false
        tmp_size_flag := false
        tmp_pass_flag := false
        tmp_default_value_flag := false
        bracket_num := 0
        _string := trim(strreplace(_string, "`n"))
        eval_array := []
        tmp_default_value := ""
        tmp_struct_array := []
        tmp_union_array := []
        tmp_pass_string := ""
        default_value := map()
        if (substr(_string, 1, strlen(mode)) = mode || substr(_string, 1, 1) = "{")
        {
            pop_length := 0
            if substr(_string, -1) = "}"
            {
                _string := substr(_string, instr(_string, "{") + 1)
                pop_length := 1
            }
            else if substr(_string, -2) = "};"
            {
                _string := substr(_string, instr(_string, "{") + 1)
                pop_length := 2
            }
            if pop_length
                _string := substr(_string, 1, strlen(_string) - pop_length)
        }
        loop parse _string
        {
            if tmp_pass_flag
            {
                tmp_pass_string .= a_loopfield
                switch a_loopfield
                {
                    case lbracket2_flag:
                        bracket_num++
                    case rbracket2_flag:
                        bracket_num--
                }
                if !bracket_num
                {
                    if tmp_struct_flag
                    {
                        tmp := struct.eval(tmp_pass_string)
                        tmp_struct_array := tmp[1]
                        for key, value in tmp[2]
                        {
                            if key is array
                                default_value[[tmp_name, key*]] := value
                            else
                                default_value[[tmp_name, key]] := value
                        }
                    }
                    else if tmp_union_flag
                        tmp_union_array := union.eval(tmp_pass_string)[1]
                    tmp_pass_flag := false
                }
                continue
            }
            switch a_loopfield
            {
                case dot_flag:
                {
                    tmp_type := last_type
                }
                case equal_flag:
                {
                    tmp_name := strsplit(tmp_type, " ")[-1]
                    tmp_type := trim(substr(tmp_type, 1, strlen(tmp_type) - strlen(tmp_name)))
                    tmp_default_value_flag := true
                }
                case lbracket1_flag:
                {
                    tmp_size_flag := true
                }
                case rbracket1_flag:
                {
                    tmp_size_flag := false
                }
                case lbracket2_flag:
                {
                    tmp := strsplit(trim(tmp_type), " ", , 2)
                    tmp_type := tmp[1]
                    if tmp_type = "struct"
                        tmp_struct_flag := true
                    else if tmp_type = "union"
                        tmp_union_flag := true
                    tmp_name := tmp.length = 2 ? tmp[2] : ""
                    tmp_pass_flag := true
                    tmp_pass_string .= "{"
                    bracket_num++
                }
                case blank_flag, tab_flag:
                {
                    if tmp_blank_flag || !tmp_type
                        continue
                    tmp_blank_flag := true
                    tmp_type .= " "
                }
                case end_flag:
                {
                    if tmp_struct_flag
                    {
                        push_array := [tmp_type, tmp_name, tmp_struct_array]
                        try
                        {
                            tmp_size := integer(tmp_size)
                            if tmp_size
                                push_array.push({size: tmp_size})
                        }
                        eval_array.push(push_array)
                        tmp_struct_flag := false
                        tmp_struct_array := []
                    }
                    else if tmp_union_flag
                    {
                        push_array := [tmp_type, tmp_name, tmp_union_array]
                        try
                        {
                            tmp_size := integer(tmp_size)
                            if tmp_size
                                push_array.push({size: tmp_size})
                        }
                        eval_array.push(push_array)
                        tmp_union_flag := false
                        tmp_union_array := []
                    }
                    else
                    {
                        tmp_type := trim(tmp_type)
                        if !tmp_name
                        {
                            if instr(tmp_type, "*")
                                tmp_type := strreplace(strreplace(tmp_type, "* ", "*"), "*", "* ")
                            tmp_name := strsplit(tmp_type, " ")[-1]
                            tmp_type := trim(substr(tmp_type, 1, strlen(tmp_type) - strlen(tmp_name)))
                        }
                        push_array := [tmp_type, tmp_name]
                        try
                        {
                            tmp_size := integer(tmp_size)
                            if tmp_size
                                push_array.push({size: tmp_size})
                        }
                        eval_array.push(push_array)
                    }
                    if tmp_default_value_flag && !tmp_struct_flag && !tmp_union_flag
                    {
                        if instr(tmp_default_value, ".")
                        {
                            try
                            {
                                tmp_default_value := float(tmp_default_value)
                                default_value[tmp_name] := tmp_default_value
                            }
                        }
                        else
                        {
                            try
                            {
                                tmp_default_value := integer(tmp_default_value)
                                default_value[tmp_name] := tmp_default_value
                            }
                        }
                        tmp_default_value := ""
                        tmp_default_value_flag := false
                    }
                    last_type := tmp_type
                    tmp_type := ""
                    tmp_name := ""
                    tmp_size := ""
                    tmp_blank_flag := false
                    tmp_pass_string := ""
                }
                default:
                {
                    if tmp_size_flag
                        tmp_size .= a_loopfield
                    else if tmp_default_value_flag
                        tmp_default_value .= a_loopfield
                    else
                    {
                        if tmp_blank_flag
                        {
                            if a_loopfield = "*"
                                tmp_type := trim(tmp_type)
                            tmp_blank_flag := false
                        }
                        else if tmp_struct_flag || tmp_union_flag
                            continue
                        tmp_type .= a_loopfield
                    }
                }
            }
        }
        return [eval_array, default_value]
    }
    
    static find_nearmul(a, b)
    {
        while true
        {
            if mod(a, b) = 0
                return a
            a++
        }
    }
    
    ; Gui Part
    static add_typemap(struct_gui)
    {
        path := fileselect(, , "please select a standard type_map file")
        if !path
            return
        loop read path
        {
            tmp := trim(a_loopreadline)
            if (flag := strsplit(tmp, " "), flag.length) >= 3
            {
                tmp_type := flag[-2]
                tmp_value := flag[-1]
                tmp := trim(substr(tmp, 1, strlen(tmp) - strlen(tmp_value)))
                tmp := trim(substr(tmp, 1, strlen(tmp) - strlen(tmp_type)))
                struct_gui.type_map[tmp] := [tmp_type, integer(tmp_value)]
            }
        }
    }
    
    static get_struct(struct_gui)
    {
        if !struct_gui["EditBox"].Text
            struct_gui["ResultBox"].Text := ""
        else
        {
            try
            {
                _struct := struct(struct_gui["EditBox"].Value, struct_gui.type_map)
                _retv1 := format("; v1`nvarsetcapacity(tmp_struct, {}, 0)`n`n", _struct.size)
                _retv2 := format("; v2`ntmp_struct := buffer({}, 0)`n`n", _struct.size)
                output_array := _struct.exportself()
                numget_check := struct_gui["NumGetCheck"].Value
                numput_check := struct_gui["NumPutCheck"].Value
                version := struct_gui["Version"].Text
                for name in _struct.exportname()
                {
                    addr := instr(name, ".") ? _struct[strsplit(name, "."), "addr"] : _struct[name, "addr"]
                    if numget_check
                    {
                        if version = "v1"
                            _retv1 .= format("; numget(tmp_struct, {}, `"{}`") `; {}`n", addr, output_array[a_index * 2 - 1], name)
                        else
                            _retv2 .= format("; numget(tmp_struct, {}, `"{}`") `; {}`n", addr, output_array[a_index * 2 - 1], name)
                    }
                    if numput_check
                    {
                        if version = "v1"
                            _retv1 .= format("; numput({}, tmp_struct, {}, `"{}`") `; {}`n", output_array[a_index * 2], addr, output_array[a_index * 2 - 1], name)
                        else
                            _retv2 .= format("; numput(`"{}`", {}, tmp_struct, {}) `; {}`n", output_array[a_index * 2 - 1], output_array[a_index * 2], addr, name)
                    }
                }
                struct_gui["ResultBox"].Value := version = "v1" ? _retv1 : _retv2
            }
            catch
            {
                struct_gui["ResultBox"].Text := "invalid struct"
                throw
            }
        }
    }
    
    static gui()
    {
        struct_gui := gui()
        struct_gui.type_map := map()
        struct_gui.setfont("s11","MicroSoft YaHei")
        struct_gui.add("button", "vClearButton x5 y5", "Clear All").OnEvent("Click", (*) => (struct_gui["EditBox"].Text := "", struct_gui["ResultBox"].Text := ""))
        struct_gui.add("button", "vAddButton yp x+2", "Add TypeMap").OnEvent("Click", (*) => this.add_typemap(struct_gui))
        struct_gui.add("button", "vClearTypeMapButton yp x+3", "Clear TypeMap").OnEvent("Click", (*) => struct_gui.type_map := map())
        struct_gui.add("text", "xs", "please input struct here")
        struct_gui.add("edit", "vEditBox xs w600 h300")
        struct_gui.add("checkbox", "vNumGetCheck xp y+1 h25", "numget")
        struct_gui.add("checkbox", "vNumPutCheck yp x+1 h25", "numput")
        struct_gui.add("dropdownlist", "vVersion yp x+1 w100 Choose1", ["v1", "v2"])
        struct_gui.add("button", "vGetButton yp x+2 h25", "Get Result").OnEvent("Click", (*) => this.get_struct(struct_gui))
        struct_gui.add("text", "xs", "copy result here")
        struct_gui.add("edit", "vResultBox xs w600 h300 ReadOnly")
        struct_gui.show()
        return struct_gui
    }
}

class union
{
    static encoding := "utf-8"
    
    __new(member_array := [], type_map := map())
    {
        this.warning := ""
        this.members := member_array is string ? union.eval(member_array)[1] : member_array
        this.type_map := type_map
        this.align()
        this.members := this.rebuild()
        this.size := this.max_align
        this.ptr := dllcall("msvcrt\malloc", "uint", this.size)
        dllcall("msvcrt\memset", "ptr", this.ptr, "int", 0, "uint", this.size)
    }
    
    __delete()
    {
        if this.ptr
            dllcall("msvcrt\free", "ptr", this.ptr)
    }
    
    __item[name, param*]
    {
        get
        {
            if !(name is array) && instr(name, ".")
                name := strsplit(name, ".")
            if name is array && param.length && param[1] = "addr"
            {
                total_addr := 0
                tmp := this
                loop name.length - 1
                {
                    total_addr += tmp[name[a_index], "addr"]
                    tmp := tmp[name[a_index]]
                }
                return total_addr + tmp[name[-1], param*]
            }
            else if name is array
            {
                tmp := this
                loop name.length - 1
                    tmp := tmp[name[a_index]]
                return tmp[name[-1], param*]
            }
            if this.members.has(name)
            {
                member := this.members[name]
                size := 1
                get_type := this.type_map.has(member[1]) ? this.type_map[member[1]] : struct.type_map.has(member[1]) ? struct.type_map[member[1]] : ["ptr", 8]
                if param.length
                {
                    if param[1] = "type"
                        return get_type[1]
                    if param[-1] is integer
                        size := member[2].hasprop("size") ? param[-1] + 1 : 1
                    if param[1] = "addr"
                        return (size = 1 || !member[2].hasprop("size")) ? member[-1] : member[-1] + (size - 1) * get_type[2]
                }
                if member[1] = "struct" || member[1] = "union"
                    return (size = 1 && !member[2].hasprop("size")) ? (member[2].%member[1]%) : (member[2].%member[1]%)[size]
                return numget(this.ptr, member[-1] + (size - 1) * get_type[2], get_type[1])
            }
        }
        
        set
        {
            if !(name is array) && instr(name, ".")
                name := strsplit(name, ".")
            if name is array
            {
                tmp := this
                loop name.length - 1
                    tmp := tmp[name[a_index]]
                tmp[name[-1], param*] := value
                return
            }
            if !isnumber(value) && value is string
                value := struct.strBuffer(value, union.encoding).ptr
            if this.members.has(name)
            {
                member := this.members[name]
                size := 1
                if param.length && param[-1] is integer
                    size := member[2].hasprop("size") ? param[-1] + 1 : 1
                if member[1] = "struct" || member[1] = "union"
                    return
                get_type := this.type_map.has(member[1]) ? this.type_map[member[1]] : struct.type_map.has(member[1]) ? struct.type_map[member[1]] : ["ptr", 8]
                return numput(get_type[1], value, member[-1] + (size - 1) * get_type[2], this.ptr)
            }
        }
    }
    
    align()
    {
        max_size := 0
        this.max_align := 0
        for member in this.members
        {
            type_map := this.type_map.has(member[1]) ? this.type_map : struct.type_map.has(member[1]) ? struct.type_map : ""
            if type_map
            {
                type_size := type_map[member[1]][2]
                this.max_align := max(this.max_align, type_size)
                tmp_size := (member.length >= 3 && member[3].hasprop("size")) ? member[3].size : 1
                max_size := max(max_size, type_size * tmp_size)
            }
            else if instr(member[1], "*")
            {
                type_size := a_ptrsize
                this.max_align := max(this.max_align, type_size)
                tmp_size := (member.length >= 3 && member[3].hasprop("size")) ? member[3].size : 1
                max_size := max(max_size, type_size * tmp_size)
            }
            else if member[1] = "struct"
            {
                struct_flag := member[3] is struct
                tmp_struct := !struct_flag ? struct(0, member[3], this.type_map) : member[3]
                type_size := tmp_struct.max_align
                this.max_align := max(this.max_align, type_size)
                if (member.length >= 4 && member[4].hasprop("size"))
                {
                    tmp_array := [tmp_struct]
                    tmp_size := member[4].size
                    loop tmp_size - 1
                        tmp_array.push(!struct_flag ? struct(0, member[3], this.type_map) : (buf := buffer(member[3].size, 0), tmp := member[3].clone(), tmp.ptr := buf.ptr, tmp))
                    member[3] := tmp_array
                    max_size := max(max_size, tmp_struct.size * tmp_size)
                }
                else
                {
                    member[3] := tmp_struct
                    max_size := max(max_size, tmp_struct.size)
                }
            }
            else if member[1] = "union"
            {
                if !(member[2] is string)
                    member.insertat(2, "")
                union_flag := member[3] is union
                tmp_union := !union_flag ? union(member[3], this.type_map) : member[3]
                type_size := tmp_union.max_align
                this.max_align := max(this.max_align, type_size)
                if false ; (member.length >= 4 && member[4].hasprop("size"))
                {
                    tmp_array := [tmp_union]
                    tmp_size := member[4].size
                    loop tmp_size - 1
                        tmp_array.push(!union_flag ? union(member[3], this.type_map) : (buf := buffer(member[3].size, 0), tmp := member[3].clone(), tmp.ptr := buf.ptr, tmp))
                    member[3] := tmp_array
                    max_size := max(max_size, tmp_union.size * tmp_size)
                }
                else
                {
                    member[3] := tmp_union
                    max_size := max(max_size, tmp_union.size)
                }
            }
            else
            {
                type_size := a_ptrsize
                this.max_align := max(this.max_align, type_size)
                tmp_size := (member.length >= 3 && member[3].hasprop("size")) ? member[3].size : 1
                max_size := max(max_size, type_size * tmp_size)
                this.warning .= "type " member[1] " auto analysis as ptr.`n"
            }
        }
        this.max_align := struct.find_nearmul(max_size, this.max_align)
    }
    
    rebuild()
    {
        members := map()
        for member in this.members
        {
            if member[1] = "struct" || member[1] = "union"
            {
                members[member[2]] := [member[1], {%strlower(member[1])%: member[3]}, 0]
                if (member.length >= 4 && member[4].hasprop("size")) && member[1] != "union"
                    members[member[2]][2].size := member[4].size
            }
            else
            {
                members[member[2]] := [member[1], {}, 0]
                if (member.length >= 3 && member[3].hasprop("size"))
                    members[member[2]][2].size := member[3].size
            }
        }
        return members
    }
    
    static eval(_string, mode := "union")
    {
        return struct.eval(_string, mode)
    }
}
Last edited by Mono919 on 27 Mar 2023, 07:55, edited 17 times in total.

User avatar
Relayer
Posts: 160
Joined: 30 Sep 2013, 13:09
Location: Delaware, USA

Re: [v2.0.0]Struct——auto calc struct and init a struct

Post by Relayer » 07 Feb 2023, 10:57

Hi,

I tried using this and on the first example: the variable 'tmp_size' in align() errors out saying it contains the string 'a' when it expected a number.

I'm still learning v2 so I'm not as adept in troubleshooting yet.

Relayer

User avatar
Mono919
Posts: 71
Joined: 05 May 2022, 02:36

Re: [v2.0.0]Struct——auto calc struct and init a struct

Post by Mono919 » 08 Feb 2023, 01:08

Relayer wrote:
07 Feb 2023, 10:57
Hi,

I tried using this and on the first example: the variable 'tmp_size' in align() errors out saying it contains the string 'a' when it expected a number.

I'm still learning v2 so I'm not as adept in troubleshooting yet.

Relayer
can you put your example here? I can't really know what you mean.

User avatar
Relayer
Posts: 160
Joined: 30 Sep 2013, 13:09
Location: Delaware, USA

Re: [v2.0.0]Struct——auto calc struct and init a struct

Post by Relayer » 13 Feb 2023, 10:21

I was simply running your first example in your opening post and got:
image.png
image.png (15.52 KiB) Viewed 2967 times

User avatar
Mono919
Posts: 71
Joined: 05 May 2022, 02:36

Re: [v2.0.0]Struct——auto calc struct and init a struct

Post by Mono919 » 15 Feb 2023, 07:21

Relayer wrote:
13 Feb 2023, 10:21
I was simply running your first example in your opening post and got:

image.png
I think you do not use my example? your just show so little that I cannot get any message.

User avatar
Mono919
Posts: 71
Joined: 05 May 2022, 02:36

Re: [v2.0.0]Struct——auto calc struct and init a struct

Post by Mono919 » 16 Feb 2023, 12:00

Now I Refresh the eval code, then it may be more useful for everyone.
Support most nesting and default values.
but the ";" after "}" is neccessary. it means a para end.

New Usage:

Code: Select all

struct_script := "
(
struct hello {
    unsigned int*a;
    int b = 2;
    union m {
    int v [ 10 ];
    };
    struct k {
    int c = 5;
    };
}
)"
new_struct := struct(struct_script)
msgbox(new_struct[["m", "v"], "addr", 0]) ; => equal to 44. it means union m addr + v[0] addr in union m;
Source Code:

Code: Select all

class struct
{
    static encoding := "utf-8"
    static warningFlag := false
    
    static type_map :=
    {
        bool: ["char", 1],
        char: ["char", 1],
        %"signed char"%: ["char", 1],
        uchar: ["uchar", 1],
        %"unsigned char"%: ["uchar", 1],
        short: ["short", 2],
        %"signed short"%: ["short", 2],
        ushort: ["ushort", 2],
        %"unsigned short"%: ["ushort", 2],
        int: ["int", 4],
        %"signed int"%: ["int", 4],
        uint: ["uint", 4],
        %"unsigned int"%: ["uint", 4],
        long: ["int", 4],
        %"signed long"%: ["int", 4],
        %"unsigned long"%: ["uint", 4],
        size_t: ["uint", 4],
        float: ["float", 4],
        double: ["double", 8],
        ptr: ["ptr", 8],
        DWORD: ["uint", 4]
    }
    
    static strBuffer(str, encoding := "utf-8")
    {
        buf := buffer(strput(str, encoding))
        strput(str, buf, encoding)
        return buf
    }
    
    __new(ptr := 0, member_array := [], type_map := {}, default_value := map())
    {
        this.warning := ""
        if ptr is array
        {
            this.ptr := 0
            this.members := ptr
            this.type_map := (member_array is object) ? member_array : type_map
        }
        else if ptr is string
        {
            this.ptr := 0
            tmp := struct.eval(ptr)
            this.members := tmp[1]
            default_value := tmp[2]
            this.type_map := (member_array is object) ? member_array : type_map
        }
        else
        {
            this.ptr := ptr
            this.members := member_array is string ? struct.eval(member_array) : member_array
            this.type_map := type_map
        }
        this.exports := [[],[]]
        for member in this.members
        {
            if member[1] = "struct" || member[1] = "union"
                get_type := member[1]
            else
                get_type := this.type_map.hasprop(member[1]) ? this.type_map.%member[1]%[1] : struct.type_map.hasprop(member[1]) ? struct.type_map.%member[1]%[1] : "ptr"
            this.exports[1].push(get_type)
            this.exports[2].push(member[2])
        }
        this.addr := this.align()
        this.members := this.rebuild()
        this.size := this.addr.pop()
        if !this.ptr
        {
            this.buf := buffer(this.size, 0)
            this.ptr := this.buf.ptr
        }
        for key, value in default_value
            this[key] := value
    }
    
    __item[name, param*]
    {
        get
        {
            if name is array && param.length && param[1] = "addr"
            {
                total_addr := 0
                tmp := this
                loop name.length - 1
                {
                    total_addr += tmp[name[a_index], "addr"]
                    tmp := tmp[name[a_index]]
                }
                return total_addr + tmp[name[-1], param*]
            }
            else if name is array
            {
                tmp := this
                loop name.length - 1
                    tmp := tmp[name[a_index]]
                return tmp[name[-1], param*]
            }
            if this.members.has(name)
            {
                member := this.members[name]
                size := 1
                get_type := this.type_map.hasprop(member[1]) ? this.type_map.%member[1]% : struct.type_map.hasprop(member[1]) ? struct.type_map.%member[1]% : ["ptr", 8]
                if param.length
                {
                    if param[1] = "type"
                        return get_type[1]
                    if param[-1] is integer
                        size := member[2].hasprop("size") ? param[-1] + 1 : 1
                    if param[1] = "addr"
                        return (size = 1 || !member[2].hasprop("size")) ? member[-1] : member[-1] + (size - 1) * get_type[2]
                }
                if member[1] = "struct" || member[1] = "union"
                    return (size = 1 && !member[2].hasprop("size")) ? (member[2].%member[1]%) : (member[2].%member[1]%)[size]
                return numget(this.ptr, member[-1] + (size - 1) * get_type[2], get_type[1])
            }
            else if this.members.has("")
            {
                member := this.members[""]
                if member[1] = "union"
                {
                    if param.length && param[1] = "addr"
                    {
                        ret := member[2].union[name, param*]
                        if !(ret = "")
                            return ret + member[-1]
                    }
                    return member[2].union[name, param*]
                }
            }
        }
        
        set
        {
            if name is array
            {
                tmp := this
                loop name.length - 1
                    tmp := tmp[name[a_index]]
                tmp[name[-1], param*] := value
                return
            }
            if !isnumber(value) && value is string
                value := struct.strBuffer(value).ptr
            if this.members.has(name)
            {
                member := this.members[name]
                size := 1
                if param.length && param[-1] is integer
                    size := member[2].hasprop("size") ? param[-1] + 1 : 1
                if member[1] = "struct" || member[1] = "union"
                    return
                get_type := this.type_map.hasprop(member[1]) ? this.type_map.%member[1]% : struct.type_map.hasprop(member[1]) ? struct.type_map.%member[1]% : ["ptr", 8]
                return numput(get_type[1], value, member[-1] + (size - 1) * get_type[2], this.ptr)
            }
            else if this.members.has("")
            {
                member := this.members[""]
                if member[1] = "union"
                    return member[2].union[name, param] := value
            }
        }
    }
    
    align()
    {
        this.max_align := 0
        old_addr := addr := 0
        addr_array := []
        for member in this.members
        {
            type_map := this.type_map.hasprop(member[1]) ? this.type_map : struct.type_map.hasprop(member[1]) ? struct.type_map : ""
            if type_map
            {
                old_addr := addr
                type_size := type_map.%member[1]%[2]
                addr := struct.find_nearmul(addr, type_size)
                addr_array.push(addr)
                tmp_size := (member.length >= 3 && member[3].hasprop("size")) ? member[3].size : 1
                addr += type_size * tmp_size
                this.max_align := max(this.max_align, type_size)
            }
            else if instr(member[1], "*")
            {
                old_addr := addr
                type_size := a_ptrsize
                addr := struct.find_nearmul(addr, type_size)
                addr_array.push(addr)
                tmp_size := (member.length >= 3 && member[3].hasprop("size")) ? member[3].size : 1
                addr += type_size * tmp_size
                this.max_align := max(this.max_align, type_size)
            }
            else if member[1] = "struct"
            {
                struct_flag := member[3] is struct
                tmp_struct := !struct_flag ? struct(0, member[3], this.type_map) : member[3]
                old_addr := addr
                type_size := tmp_struct.max_align
                addr := struct.find_nearmul(addr, type_size)
                addr_array.push(addr)
                if (member.length >= 4 && member[4].hasprop("size"))
                {
                    tmp_array := [tmp_struct]
                    tmp_size := member[4].size
                    loop tmp_size - 1
                        tmp_array.push(!struct_flag ? struct(0, member[3], this.type_map) : (buf := buffer(member[3].size, 0), tmp := member[3].clone(), tmp.buf := buf, tmp.ptr := buf.ptr, tmp))
                    member[3] := tmp_array
                    addr += tmp_struct.size * tmp_size
                }
                else
                {
                    member[3] := tmp_struct
                    addr += tmp_struct.size
                }
            }
            else if member[1] = "union"
            {
                if !(member[2] is string)
                    member.insertat(2, "")
                union_flag := member[3] is union
                tmp_union := !union_flag ? union(member[3], this.type_map) : member[3]
                old_addr := addr
                type_size := tmp_union.max_align
                addr := struct.find_nearmul(addr, type_size)
                addr_array.push(addr)
                if false ; (member.length >= 4 && member[4].hasprop("size"))
                {
                    tmp_array := [tmp_union]
                    tmp_size := member[4].size
                    loop tmp_size - 1
                        tmp_array.push(!union_flag ? union(member[3], this.type_map) : (buf := buffer(member[3].size, 0), tmp := member[3].clone(), tmp.buf := buf, tmp.ptr := buf.ptr, tmp))
                    member[3] := tmp_array
                    addr += tmp_union.size * tmp_size
                }
                else
                {
                    member[3] := tmp_union
                    addr += tmp_union.size
                }
            }
            else
            {
                old_addr := addr
                type_size := a_ptrsize
                addr := struct.find_nearmul(addr, type_size)
                addr_array.push(addr)
                tmp_size := (member.length >= 3 && member[3].hasprop("size")) ? member[3].size : 1
                addr += type_size * tmp_size
                this.max_align := max(this.max_align, type_size)
                this.warning .= "type " member[1] " auto analysis as ptr.`n"
            }
        }
        addr_array.push(struct.find_nearmul(addr, this.max_align))
        return addr_array
    }
    
    export(values*)
    {
        export_array := []
        for value in this.exports[1]
        {
            try
                get_value := values[a_index]
            catch
                get_value := "nullptr"
            if get_value is array
            {
                if get_value[1] is struct
                {
                    tmp := get_value.clone()
                    tmp_struct := tmp.removeat(1)
                    export_array.push(tmp_struct.export(tmp*)*)
                }
                else
                    export_array.push(get_value*)
            }
            else if !(get_value = "nullptr")
                export_array.push(value, get_value)
        }
        return export_array
    }
    
    exportname()
    {
        warning := ""
        export_array := []
        index := 1
        for value in this.exports[1]
        {
            if value = "struct"
            {
                struct_name := this.exports[2][index++]
                tmp_array := this[struct_name].exportname()
                loop tmp_array.length
                    tmp_array[a_index] := struct_name "." tmp_array[a_index]
                export_array.push(tmp_array*)
            }
            else if value = "union"
                warning .= "union " this.exports[2][index++] " has been passed.`n"
            else
                export_array.push(this.exports[2][index++])
        }
        if warning && struct.warningFlag
            msgbox warning
        return export_array
    }
    
    exportself()
    {
        warning := ""
        export_array := []
        for value in this.exports[1]
        {
            if value = "struct"
                export_array.push(this[this.exports[2][a_index]].exportself()*)
            else if value = "union"
                warning .= "union " this.exports[2][a_index] " has been passed.`n"
            else
                export_array.push(value, this[this.exports[2][a_index]])
        }
        if warning && struct.warningFlag
            msgbox warning
        return export_array
    }
    
    rebuild()
    {
        members := map()
        for member in this.members
        {
            if member[1] = "struct" || member[1] = "union"
            {
                members[member[2]] := [member[1], {%strlower(member[1])%: member[3]}, this.addr[a_index]]
                if (member.length >= 4 && member[4].hasprop("size")) && member[1] != "union"
                    members[member[2]][2].size := member[4].size
            }
            else
            {
                members[member[2]] := [member[1], {}, this.addr[a_index]]
                if (member.length >= 3 && member[3].hasprop("size"))
                    members[member[2]][2].size := member[3].size
            }
        }
        return members
    }
    
    static eval(_string, mode := "struct")
    {
        blank_flag := " "
        tab_flag := "`t"
        end_flag := ";"
        equal_flag := "="
        star_flag := "*"
        lbracket1_flag := "["
        rbracket1_flag := "]"
        lbracket2_flag := "{"
        rbracket2_flag := "}"
        tmp_type := ""
        tmp_name := ""
        tmp_size := ""
        tmp_blank_flag := false
        tmp_struct_flag := false
        tmp_union_flag := false
        tmp_size_flag := false
        tmp_pass_flag := false
        tmp_default_value_flag := false
        bracket_num := 0
        _string := trim(strreplace(_string, "`n"))
        eval_array := []
        tmp_default_value := ""
        tmp_struct_array := []
        tmp_union_array := []
        tmp_pass_string := ""
        default_value := map()
        if (substr(_string, 1, strlen(mode)) = mode || substr(_string, 1, 1) = "{") && substr(_string, -1) = "}"
            _string := substr(_string, instr(_string, "{") + 1, strlen(_string) - 1)
        loop parse _string
        {
            if tmp_pass_flag
            {
                tmp_pass_string .= a_loopfield
                switch a_loopfield
                {
                    case lbracket2_flag:
                        bracket_num++
                    case rbracket2_flag:
                        bracket_num--
                }
                if !bracket_num
                {
                    if tmp_struct_flag
                    {
                        tmp := struct.eval(tmp_pass_string)
                        tmp_struct_array := tmp[1]
                        for key, value in tmp[2]
                        {
                            if key is array
                                default_value[[tmp_name, key*]] := value
                            else
                                default_value[[tmp_name, key]] := value
                        }
                    }
                    else if tmp_union_flag
                        tmp_union_array := union.eval(tmp_pass_string)[1]
                    tmp_pass_flag := false
                }
                continue
            }
            switch a_loopfield
            {
                case equal_flag:
                {
                    tmp_name := strsplit(tmp_type, " ")[-1]
                    tmp_type := trim(substr(tmp_type, 1, strlen(tmp_type) - strlen(tmp_name)))
                    tmp_default_value_flag := true
                }
                case lbracket1_flag:
                {
                    tmp_size_flag := true
                }
                case rbracket1_flag:
                {
                    tmp_size_flag := false
                }
                case lbracket2_flag:
                {
                    tmp := strsplit(trim(tmp_type), " ", , 2)
                    tmp_type := tmp[1]
                    if tmp_type = "struct"
                        tmp_struct_flag := true
                    else if tmp_type = "union"
                        tmp_union_flag := true
                    tmp_name := tmp.length = 2 ? tmp[2] : ""
                    tmp_pass_flag := true
                    tmp_pass_string .= "{"
                    bracket_num++
                }
                case blank_flag, tab_flag:
                {
                    if tmp_blank_flag || !tmp_type
                        continue
                    tmp_blank_flag := true
                    tmp_type .= " "
                }
                case end_flag:
                {
                    if tmp_struct_flag
                    {
                        push_array := [tmp_type, tmp_name, tmp_struct_array]
                        try
                        {
                            tmp_size := integer(tmp_size)
                            if tmp_size
                                push_array.push({size: tmp_size})
                        }
                        eval_array.push(push_array)
                        tmp_struct_flag := false
                        tmp_struct_array := []
                    }
                    else if tmp_union_flag
                    {
                        push_array := [tmp_type, tmp_name, tmp_union_array]
                        try
                        {
                            tmp_size := integer(tmp_size)
                            if tmp_size
                                push_array.push({size: tmp_size})
                        }
                        eval_array.push(push_array)
                        tmp_union_flag := false
                        tmp_union_array := []
                    }
                    else
                    {
                        tmp_type := trim(tmp_type)
                        if !tmp_name
                        {
                            if instr(tmp_type, "*")
                                tmp_type := strreplace(strreplace(tmp_type, "* ", "*"), "*", "* ")
                            tmp_name := strsplit(tmp_type, " ")[-1]
                            tmp_type := trim(substr(tmp_type, 1, strlen(tmp_type) - strlen(tmp_name)))
                        }
                        push_array := [tmp_type, tmp_name]
                        try
                        {
                            tmp_size := integer(tmp_size)
                            if tmp_size
                                push_array.push({size: tmp_size})
                        }
                        eval_array.push(push_array)
                    }
                    if tmp_default_value_flag && !tmp_struct_flag && !tmp_union_flag
                    {
                        if instr(tmp_default_value, ".")
                        {
                            try
                            {
                                tmp_default_value := float(tmp_default_value)
                                default_value[tmp_name] := tmp_default_value
                            }
                        }
                        else
                        {
                            try
                            {
                                tmp_default_value := integer(tmp_default_value)
                                default_value[tmp_name] := tmp_default_value
                            }
                        }
                        tmp_default_value := ""
                        tmp_default_value_flag := false
                    }
                    tmp_type := ""
                    tmp_name := ""
                    tmp_size := ""
                    tmp_blank_flag := false
                    tmp_pass_string := ""
                }
                default:
                {
                    if tmp_size_flag
                        tmp_size .= a_loopfield
                    else if tmp_default_value_flag
                        tmp_default_value .= a_loopfield
                    else
                    {
                        if tmp_blank_flag
                        {
                            if a_loopfield = "*"
                                tmp_type := trim(tmp_type)
                            tmp_blank_flag := false
                        }
                        else if tmp_struct_flag || tmp_union_flag
                            continue
                        tmp_type .= a_loopfield
                    }
                }
            }
        }
        return [eval_array, default_value]
    }
    
    static find_nearmul(a, b)
    {
        while true
        {
            if mod(a, b) = 0
                return a
            a++
        }
    }
    
    ; Gui Part
    static add_typemap(struct_gui)
    {
        path := fileselect(, , "please select a standard type_map file")
        if path = "cancel"
            return
        loop read path
        {
            tmp := trim(a_loopreadline)
            if flag := strsplit(tmp, " ") >= 3
            {
                tmp_type := flag[-2]
                tmp_value := flag[-1]
                tmp := trim(substr(tmp, 1, strlen(tmp) - strlen(tmp_value)))
                tmp := trim(substr(tmp, 1, strlen(tmp) - strlen(tmp_type)))
                struct_gui.type_map.%tmp% := [tmp_type, integer(tmp_value)]
            }
        }
    }
    
    static get_struct(struct_gui)
    {
        if !struct_gui["EditBox"].Text
            struct_gui["ResultBox"].Text := ""
        else
        {
            try
            {
                _struct := struct(struct_gui["ResultBox"].Text, struct_gui.type_map)
                _retv1 := format("; v1`nvarsetcapacity(tmp_struct, {}, 0)`n`n", _struct.size)
                _retv2 := format("; v2`ntmp_struct := buffer({}, 0)`n`n", _struct.size)
                output_array := _struct.exportself()
                for name in _struct.exportname()
                {
                    addr := instr(name, ".") ? _struct[strsplit(name, "."), "addr"] : _struct[name, "addr"]
                    _retv1 .= format("; numget(tmp_struct, {}, {}) `; {}`n", addr, output_array[a_index * 2 - 1], name)
                    _retv1 .= format("; numput({}, tmp_struct, {}, {}) `; {}`n", addr, output_array[a_index * 2], output_array[a_index * 2 - 1], name)
                    _retv2 .= format("numget(tmp_struct, {}, {}) `; {}`n", addr, output_array[a_index * 2 - 1], name)
                    _retv2 .= format("; numput({}, {}, tmp_struct, {}) `; {}`n", output_array[a_index * 2 - 1], output_array[a_index * 2], addr, name)
                }
                struct_gui["ResultBox"].Text := _retv1 " `n`n"
                struct_gui["ResultBox"].Text .= _retv2
            }
            catch
                struct_gui["ResultBox"].Text := "invalid struct"
        }
    }
    
    static gui()
    {
        struct_gui := gui()
        struct_gui.type_map := {}
        struct_gui.setfont("s14","MicroSoft YaHei")
        struct_gui.add("button", "vClearButton yp x+5", "Clear All").OnEvent("Click", (*) => (struct_gui["EditBox"].Text := "", struct_gui["ResultBox"].Text := ""))
        struct_gui.add("text", , "please input struct here")
        struct_gui.add("edit", "vEditBox xs y+0 w600 h300")
        struct_gui.add("button", "vGetButton Center", "Get Result").OnEvent("Click", this.get_struct.bind(this, struct_gui))
        struct_gui.add("button", "vAddButton Center", "Add TypeMap").OnEvent("Click", this.add_typemap.bind(this, struct_gui))
        struct_gui.add("button", "vClearTypeMapButton Center", "Add TypeMap").OnEvent("Click", (*) => struct_gui.type_map := {})
        struct_gui.add("text", , "copy result here")
        struct_gui.add("edit", "vResultBox xs y+2 w600 h300 ReadOnly")
        struct_gui.show()
        return struct_gui
    }
}

class union
{
    static encoding := "utf-8"
    
    __new(member_array := [], type_map := {})
    {
        this.warning := ""
        this.members := member_array is string ? union.eval(member_array) : member_array
        this.type_map := type_map
        this.align()
        this.members := this.rebuild()
        this.size := this.max_align
        this.buf := buffer(this.size, 0)
        this.ptr := this.buf.ptr
    }
    
    __item[name, param*]
    {
        get
        {
            if name is array && param.length && param[1] = "addr"
            {
                total_addr := 0
                tmp := this
                loop name.length - 1
                {
                    total_addr += tmp[name[a_index], "addr"]
                    tmp := tmp[name[a_index]]
                }
                return total_addr + tmp[name[-1], param*]
            }
            else if name is array
            {
                tmp := this
                loop name.length - 1
                    tmp := tmp[name[a_index]]
                return tmp[name[-1], param*]
            }
            if this.members.has(name)
            {
                member := this.members[name]
                size := 1
                get_type := this.type_map.hasprop(member[1]) ? this.type_map.%member[1]% : struct.type_map.hasprop(member[1]) ? struct.type_map.%member[1]% : ["ptr", 8]
                if param.length
                {
                    if param[1] = "type"
                        return get_type[1]
                    if param[-1] is integer
                        size := member[2].hasprop("size") ? param[-1] + 1 : 1
                    if param[1] = "addr"
                        return (size = 1 || !member[2].hasprop("size")) ? member[-1] : member[-1] + (size - 1) * get_type[2]
                }
                if member[1] = "struct" || member[1] = "union"
                    return (size = 1 && !member[2].hasprop("size")) ? (member[2].%member[1]%) : (member[2].%member[1]%)[size]
                return numget(this.ptr, member[-1] + (size - 1) * get_type[2], get_type[1])
            }
        }
        
        set
        {
            if name is array
            {
                tmp := this
                loop name.length - 1
                    tmp := tmp[name[a_index]]
                tmp[name[-1], param*] := value
                return
            }
            if !isnumber(value) && value is string
                value := struct.strBuffer(value, union.encoding).ptr
            if this.members.has(name)
            {
                member := this.members[name]
                size := 1
                if param.length && param[-1] is integer
                    size := member[2].hasprop("size") ? param[-1] + 1 : 1
                if member[1] = "struct" || member[1] = "union"
                    return
                get_type := this.type_map.hasprop(member[1]) ? this.type_map.%member[1]% : struct.type_map.hasprop(member[1]) ? struct.type_map.%member[1]% : ["ptr", 8]
                return numput(get_type[1], value, member[-1] + (size - 1) * get_type[2], this.ptr)
            }
        }
    }
    
    align()
    {
        max_size := 0
        this.max_align := 0
        for member in this.members
        {
            type_map := this.type_map.hasprop(member[1]) ? this.type_map : struct.type_map.hasprop(member[1]) ? struct.type_map : ""
            if type_map
            {
                type_size := type_map.%member[1]%[2]
                this.max_align := max(this.max_align, type_size)
                tmp_size := (member.length >= 3 && member[3].hasprop("size")) ? member[3].size : 1
                max_size := max(max_size, type_size * tmp_size)
            }
            else if instr(member[1], "*")
            {
                type_size := a_ptrsize
                this.max_align := max(this.max_align, type_size)
                tmp_size := (member.length >= 3 && member[3].hasprop("size")) ? member[3].size : 1
                max_size := max(max_size, type_size * tmp_size)
            }
            else if member[1] = "struct"
            {
                struct_flag := member[3] is struct
                tmp_struct := !struct_flag ? struct(0, member[3], this.type_map) : member[3]
                type_size := tmp_struct.max_align
                this.max_align := max(this.max_align, type_size)
                if (member.length >= 4 && member[4].hasprop("size"))
                {
                    tmp_array := [tmp_struct]
                    tmp_size := member[4].size
                    loop tmp_size - 1
                        tmp_array.push(!struct_flag ? struct(0, member[3], this.type_map) : (buf := buffer(member[3].size, 0), tmp := member[3].clone(), tmp.ptr := buf.ptr, tmp))
                    member[3] := tmp_array
                    max_size := max(max_size, tmp_struct.size * tmp_size)
                }
                else
                {
                    member[3] := tmp_struct
                    max_size := max(max_size, tmp_struct.size)
                }
            }
            else if member[1] = "union"
            {
                if !(member[2] is string)
                    member.insertat(2, "")
                union_flag := member[3] is union
                tmp_union := !union_flag ? union(member[3], this.type_map) : member[3]
                type_size := tmp_union.max_align
                this.max_align := max(this.max_align, type_size)
                if false ; (member.length >= 4 && member[4].hasprop("size"))
                {
                    tmp_array := [tmp_union]
                    tmp_size := member[4].size
                    loop tmp_size - 1
                        tmp_array.push(!union_flag ? union(member[3], this.type_map) : (buf := buffer(member[3].size, 0), tmp := member[3].clone(), tmp.ptr := buf.ptr, tmp))
                    member[3] := tmp_array
                    max_size := max(max_size, tmp_union.size * tmp_size)
                }
                else
                {
                    member[3] := tmp_union
                    max_size := max(max_size, tmp_union.size)
                }
            }
            else
            {
                type_size := a_ptrsize
                this.max_align := max(this.max_align, type_size)
                tmp_size := (member.length >= 3 && member[3].hasprop("size")) ? member[3].size : 1
                max_size := max(max_size, type_size * tmp_size)
                this.warning .= "type " member[1] " auto analysis as ptr.`n"
            }
        }
        this.max_align := struct.find_nearmul(max_size, this.max_align)
    }
    
    rebuild()
    {
        members := map()
        for member in this.members
        {
            if member[1] = "struct" || member[1] = "union"
            {
                members[member[2]] := [member[1], {%strlower(member[1])%: member[3]}, 0]
                if (member.length >= 4 && member[4].hasprop("size")) && member[1] != "union"
                    members[member[2]][2].size := member[4].size
            }
            else
            {
                members[member[2]] := [member[1], {}, 0]
                if (member.length >= 3 && member[3].hasprop("size"))
                    members[member[2]][2].size := member[3].size
            }
        }
        return members
    }
    
    static eval(_string, mode := "union")
    {
        return struct.eval(_string, mode)
    }
    
    static gui()
    {
        return struct.gui()
    }
}

User avatar
Mono919
Posts: 71
Joined: 05 May 2022, 02:36

Re: [v2.0.0]Struct——auto calc struct and init a struct

Post by Mono919 » 17 Feb 2023, 00:10

now you can use gui about struct get
and can add file typemap,like
//file
DWORD uint 4
DINT int 4

the command is struct.gui()

Source Code:

Code: Select all

class struct
{
    static encoding := "utf-8"
    static warningFlag := false
    
    static type_map :=
    {
        bool: ["char", 1],
        char: ["char", 1],
        %"signed char"%: ["char", 1],
        uchar: ["uchar", 1],
        %"unsigned char"%: ["uchar", 1],
        short: ["short", 2],
        %"signed short"%: ["short", 2],
        ushort: ["ushort", 2],
        %"unsigned short"%: ["ushort", 2],
        int: ["int", 4],
        %"signed int"%: ["int", 4],
        uint: ["uint", 4],
        %"unsigned int"%: ["uint", 4],
        long: ["int", 4],
        %"signed long"%: ["int", 4],
        %"unsigned long"%: ["uint", 4],
        size_t: ["uint", 4],
        float: ["float", 4],
        double: ["double", 8],
        ptr: ["ptr", 8],
        DWORD: ["uint", 4]
    }
    
    static strBuffer(str, encoding := "utf-8")
    {
        buf := buffer(strput(str, encoding))
        strput(str, buf, encoding)
        return buf
    }
    
    __new(ptr := 0, member_array := [], type_map := {}, default_value := map())
    {
        this.warning := ""
        if ptr is array
        {
            this.ptr := 0
            this.members := ptr
            this.type_map := (member_array is object) ? member_array : type_map
        }
        else if ptr is string
        {
            this.ptr := 0
            tmp := struct.eval(ptr)
            this.members := tmp[1]
            default_value := tmp[2]
            this.type_map := (member_array is object) ? member_array : type_map
        }
        else
        {
            this.ptr := ptr
            this.members := member_array is string ? struct.eval(member_array) : member_array
            this.type_map := type_map
        }
        this.exports := [[],[]]
        for member in this.members
        {
            if member[1] = "struct" || member[1] = "union"
                get_type := member[1]
            else
                get_type := this.type_map.hasprop(member[1]) ? this.type_map.%member[1]%[1] : struct.type_map.hasprop(member[1]) ? struct.type_map.%member[1]%[1] : "ptr"
            this.exports[1].push(get_type)
            this.exports[2].push(member[2])
        }
        this.addr := this.align()
        this.members := this.rebuild()
        this.size := this.addr.pop()
        if !this.ptr
        {
            this.buf := buffer(this.size, 0)
            this.ptr := this.buf.ptr
        }
        for key, value in default_value
            this[key] := value
    }
    
    __item[name, param*]
    {
        get
        {
            if name is array && param.length && param[1] = "addr"
            {
                total_addr := 0
                tmp := this
                loop name.length - 1
                {
                    total_addr += tmp[name[a_index], "addr"]
                    tmp := tmp[name[a_index]]
                }
                return total_addr + tmp[name[-1], param*]
            }
            else if name is array
            {
                tmp := this
                loop name.length - 1
                    tmp := tmp[name[a_index]]
                return tmp[name[-1], param*]
            }
            if this.members.has(name)
            {
                member := this.members[name]
                size := 1
                get_type := this.type_map.hasprop(member[1]) ? this.type_map.%member[1]% : struct.type_map.hasprop(member[1]) ? struct.type_map.%member[1]% : ["ptr", 8]
                if param.length
                {
                    if param[1] = "type"
                        return get_type[1]
                    if param[-1] is integer
                        size := member[2].hasprop("size") ? param[-1] + 1 : 1
                    if param[1] = "addr"
                        return (size = 1 || !member[2].hasprop("size")) ? member[-1] : member[-1] + (size - 1) * get_type[2]
                }
                if member[1] = "struct" || member[1] = "union"
                    return (size = 1 && !member[2].hasprop("size")) ? (member[2].%member[1]%) : (member[2].%member[1]%)[size]
                return numget(this.ptr, member[-1] + (size - 1) * get_type[2], get_type[1])
            }
            else if this.members.has("")
            {
                member := this.members[""]
                if member[1] = "union"
                {
                    if param.length && param[1] = "addr"
                    {
                        ret := member[2].union[name, param*]
                        if !(ret = "")
                            return ret + member[-1]
                    }
                    return member[2].union[name, param*]
                }
            }
        }
        
        set
        {
            if name is array
            {
                tmp := this
                loop name.length - 1
                    tmp := tmp[name[a_index]]
                tmp[name[-1], param*] := value
                return
            }
            if !isnumber(value) && value is string
                value := struct.strBuffer(value).ptr
            if this.members.has(name)
            {
                member := this.members[name]
                size := 1
                if param.length && param[-1] is integer
                    size := member[2].hasprop("size") ? param[-1] + 1 : 1
                if member[1] = "struct" || member[1] = "union"
                    return
                get_type := this.type_map.hasprop(member[1]) ? this.type_map.%member[1]% : struct.type_map.hasprop(member[1]) ? struct.type_map.%member[1]% : ["ptr", 8]
                return numput(get_type[1], value, member[-1] + (size - 1) * get_type[2], this.ptr)
            }
            else if this.members.has("")
            {
                member := this.members[""]
                if member[1] = "union"
                    return member[2].union[name, param] := value
            }
        }
    }
    
    align()
    {
        this.max_align := 0
        old_addr := addr := 0
        addr_array := []
        for member in this.members
        {
            type_map := this.type_map.hasprop(member[1]) ? this.type_map : struct.type_map.hasprop(member[1]) ? struct.type_map : ""
            if type_map
            {
                old_addr := addr
                type_size := type_map.%member[1]%[2]
                addr := struct.find_nearmul(addr, type_size)
                addr_array.push(addr)
                tmp_size := (member.length >= 3 && member[3].hasprop("size")) ? member[3].size : 1
                addr += type_size * tmp_size
                this.max_align := max(this.max_align, type_size)
            }
            else if instr(member[1], "*")
            {
                old_addr := addr
                type_size := a_ptrsize
                addr := struct.find_nearmul(addr, type_size)
                addr_array.push(addr)
                tmp_size := (member.length >= 3 && member[3].hasprop("size")) ? member[3].size : 1
                addr += type_size * tmp_size
                this.max_align := max(this.max_align, type_size)
            }
            else if member[1] = "struct"
            {
                struct_flag := member[3] is struct
                tmp_struct := !struct_flag ? struct(0, member[3], this.type_map) : member[3]
                old_addr := addr
                type_size := tmp_struct.max_align
                addr := struct.find_nearmul(addr, type_size)
                addr_array.push(addr)
                if (member.length >= 4 && member[4].hasprop("size"))
                {
                    tmp_array := [tmp_struct]
                    tmp_size := member[4].size
                    loop tmp_size - 1
                        tmp_array.push(!struct_flag ? struct(0, member[3], this.type_map) : (buf := buffer(member[3].size, 0), tmp := member[3].clone(), tmp.buf := buf, tmp.ptr := buf.ptr, tmp))
                    member[3] := tmp_array
                    addr += tmp_struct.size * tmp_size
                }
                else
                {
                    member[3] := tmp_struct
                    addr += tmp_struct.size
                }
            }
            else if member[1] = "union"
            {
                if !(member[2] is string)
                    member.insertat(2, "")
                union_flag := member[3] is union
                tmp_union := !union_flag ? union(member[3], this.type_map) : member[3]
                old_addr := addr
                type_size := tmp_union.max_align
                addr := struct.find_nearmul(addr, type_size)
                addr_array.push(addr)
                if false ; (member.length >= 4 && member[4].hasprop("size"))
                {
                    tmp_array := [tmp_union]
                    tmp_size := member[4].size
                    loop tmp_size - 1
                        tmp_array.push(!union_flag ? union(member[3], this.type_map) : (buf := buffer(member[3].size, 0), tmp := member[3].clone(), tmp.buf := buf, tmp.ptr := buf.ptr, tmp))
                    member[3] := tmp_array
                    addr += tmp_union.size * tmp_size
                }
                else
                {
                    member[3] := tmp_union
                    addr += tmp_union.size
                }
            }
            else
            {
                old_addr := addr
                type_size := a_ptrsize
                addr := struct.find_nearmul(addr, type_size)
                addr_array.push(addr)
                tmp_size := (member.length >= 3 && member[3].hasprop("size")) ? member[3].size : 1
                addr += type_size * tmp_size
                this.max_align := max(this.max_align, type_size)
                this.warning .= "type " member[1] " auto analysis as ptr.`n"
            }
        }
        addr_array.push(struct.find_nearmul(addr, this.max_align))
        return addr_array
    }
    
    export(values*)
    {
        export_array := []
        for value in this.exports[1]
        {
            try
                get_value := values[a_index]
            catch
                get_value := "nullptr"
            if get_value is array
            {
                if get_value[1] is struct
                {
                    tmp := get_value.clone()
                    tmp_struct := tmp.removeat(1)
                    export_array.push(tmp_struct.export(tmp*)*)
                }
                else
                    export_array.push(get_value*)
            }
            else if !(get_value = "nullptr")
                export_array.push(value, get_value)
        }
        return export_array
    }
    
    exportname()
    {
        warning := ""
        export_array := []
        index := 1
        for value in this.exports[1]
        {
            if value = "struct"
            {
                struct_name := this.exports[2][index++]
                tmp_array := this[struct_name].exportname()
                loop tmp_array.length
                    tmp_array[a_index] := struct_name "." tmp_array[a_index]
                export_array.push(tmp_array*)
            }
            else if value = "union"
                warning .= "union " this.exports[2][index++] " has been passed.`n"
            else
                export_array.push(this.exports[2][index++])
        }
        if warning && struct.warningFlag
            msgbox warning
        return export_array
    }
    
    exportself()
    {
        warning := ""
        export_array := []
        for value in this.exports[1]
        {
            if value = "struct"
                export_array.push(this[this.exports[2][a_index]].exportself()*)
            else if value = "union"
                warning .= "union " this.exports[2][a_index] " has been passed.`n"
            else
                export_array.push(value, this[this.exports[2][a_index]])
        }
        if warning && struct.warningFlag
            msgbox warning
        return export_array
    }
    
    rebuild()
    {
        members := map()
        for member in this.members
        {
            if member[1] = "struct" || member[1] = "union"
            {
                members[member[2]] := [member[1], {%strlower(member[1])%: member[3]}, this.addr[a_index]]
                if (member.length >= 4 && member[4].hasprop("size")) && member[1] != "union"
                    members[member[2]][2].size := member[4].size
            }
            else
            {
                members[member[2]] := [member[1], {}, this.addr[a_index]]
                if (member.length >= 3 && member[3].hasprop("size"))
                    members[member[2]][2].size := member[3].size
            }
        }
        return members
    }
    
    static eval(_string, mode := "struct")
    {
        blank_flag := " "
        tab_flag := "`t"
        end_flag := ";"
        equal_flag := "="
        star_flag := "*"
        lbracket1_flag := "["
        rbracket1_flag := "]"
        lbracket2_flag := "{"
        rbracket2_flag := "}"
        tmp_type := ""
        tmp_name := ""
        tmp_size := ""
        tmp_blank_flag := false
        tmp_struct_flag := false
        tmp_union_flag := false
        tmp_size_flag := false
        tmp_pass_flag := false
        tmp_default_value_flag := false
        bracket_num := 0
        _string := trim(strreplace(_string, "`n"))
        eval_array := []
        tmp_default_value := ""
        tmp_struct_array := []
        tmp_union_array := []
        tmp_pass_string := ""
        default_value := map()
        if (substr(_string, 1, strlen(mode)) = mode || substr(_string, 1, 1) = "{") && substr(_string, -1) = "}"
            _string := substr(_string, instr(_string, "{") + 1, strlen(_string) - 1)
        loop parse _string
        {
            if tmp_pass_flag
            {
                tmp_pass_string .= a_loopfield
                switch a_loopfield
                {
                    case lbracket2_flag:
                        bracket_num++
                    case rbracket2_flag:
                        bracket_num--
                }
                if !bracket_num
                {
                    if tmp_struct_flag
                    {
                        tmp := struct.eval(tmp_pass_string)
                        tmp_struct_array := tmp[1]
                        for key, value in tmp[2]
                        {
                            if key is array
                                default_value[[tmp_name, key*]] := value
                            else
                                default_value[[tmp_name, key]] := value
                        }
                    }
                    else if tmp_union_flag
                        tmp_union_array := union.eval(tmp_pass_string)[1]
                    tmp_pass_flag := false
                }
                continue
            }
            switch a_loopfield
            {
                case equal_flag:
                {
                    tmp_name := strsplit(tmp_type, " ")[-1]
                    tmp_type := trim(substr(tmp_type, 1, strlen(tmp_type) - strlen(tmp_name)))
                    tmp_default_value_flag := true
                }
                case lbracket1_flag:
                {
                    tmp_size_flag := true
                }
                case rbracket1_flag:
                {
                    tmp_size_flag := false
                }
                case lbracket2_flag:
                {
                    tmp := strsplit(trim(tmp_type), " ", , 2)
                    tmp_type := tmp[1]
                    if tmp_type = "struct"
                        tmp_struct_flag := true
                    else if tmp_type = "union"
                        tmp_union_flag := true
                    tmp_name := tmp.length = 2 ? tmp[2] : ""
                    tmp_pass_flag := true
                    tmp_pass_string .= "{"
                    bracket_num++
                }
                case blank_flag, tab_flag:
                {
                    if tmp_blank_flag || !tmp_type
                        continue
                    tmp_blank_flag := true
                    tmp_type .= " "
                }
                case end_flag:
                {
                    if tmp_struct_flag
                    {
                        push_array := [tmp_type, tmp_name, tmp_struct_array]
                        try
                        {
                            tmp_size := integer(tmp_size)
                            if tmp_size
                                push_array.push({size: tmp_size})
                        }
                        eval_array.push(push_array)
                        tmp_struct_flag := false
                        tmp_struct_array := []
                    }
                    else if tmp_union_flag
                    {
                        push_array := [tmp_type, tmp_name, tmp_union_array]
                        try
                        {
                            tmp_size := integer(tmp_size)
                            if tmp_size
                                push_array.push({size: tmp_size})
                        }
                        eval_array.push(push_array)
                        tmp_union_flag := false
                        tmp_union_array := []
                    }
                    else
                    {
                        tmp_type := trim(tmp_type)
                        if !tmp_name
                        {
                            if instr(tmp_type, "*")
                                tmp_type := strreplace(strreplace(tmp_type, "* ", "*"), "*", "* ")
                            tmp_name := strsplit(tmp_type, " ")[-1]
                            tmp_type := trim(substr(tmp_type, 1, strlen(tmp_type) - strlen(tmp_name)))
                        }
                        push_array := [tmp_type, tmp_name]
                        try
                        {
                            tmp_size := integer(tmp_size)
                            if tmp_size
                                push_array.push({size: tmp_size})
                        }
                        eval_array.push(push_array)
                    }
                    if tmp_default_value_flag && !tmp_struct_flag && !tmp_union_flag
                    {
                        if instr(tmp_default_value, ".")
                        {
                            try
                            {
                                tmp_default_value := float(tmp_default_value)
                                default_value[tmp_name] := tmp_default_value
                            }
                        }
                        else
                        {
                            try
                            {
                                tmp_default_value := integer(tmp_default_value)
                                default_value[tmp_name] := tmp_default_value
                            }
                        }
                        tmp_default_value := ""
                        tmp_default_value_flag := false
                    }
                    tmp_type := ""
                    tmp_name := ""
                    tmp_size := ""
                    tmp_blank_flag := false
                    tmp_pass_string := ""
                }
                default:
                {
                    if tmp_size_flag
                        tmp_size .= a_loopfield
                    else if tmp_default_value_flag
                        tmp_default_value .= a_loopfield
                    else
                    {
                        if tmp_blank_flag
                        {
                            if a_loopfield = "*"
                                tmp_type := trim(tmp_type)
                            tmp_blank_flag := false
                        }
                        else if tmp_struct_flag || tmp_union_flag
                            continue
                        tmp_type .= a_loopfield
                    }
                }
            }
        }
        return [eval_array, default_value]
    }
    
    static find_nearmul(a, b)
    {
        while true
        {
            if mod(a, b) = 0
                return a
            a++
        }
    }
    
    ; Gui Part
    static add_typemap(struct_gui)
    {
        path := fileselect(, , "please select a standard type_map file")
        if !path
            return
        loop read path
        {
            tmp := trim(a_loopreadline)
            if (flag := strsplit(tmp, " "), flag.length) >= 3
            {
                tmp_type := flag[-2]
                tmp_value := flag[-1]
                tmp := trim(substr(tmp, 1, strlen(tmp) - strlen(tmp_value)))
                tmp := trim(substr(tmp, 1, strlen(tmp) - strlen(tmp_type)))
                struct_gui.type_map.%tmp% := [tmp_type, integer(tmp_value)]
            }
        }
    }
    
    static get_struct(struct_gui)
    {
        if !struct_gui["EditBox"].Text
            struct_gui["ResultBox"].Text := ""
        else
        {
            try
            {
                _struct := struct(struct_gui["EditBox"].Value, struct_gui.type_map)
                _retv1 := format("; v1`nvarsetcapacity(tmp_struct, {}, 0)`n`n", _struct.size)
                _retv2 := format("; v2`ntmp_struct := buffer({}, 0)`n`n", _struct.size)
                output_array := _struct.exportself()
                for name in _struct.exportname()
                {
                    addr := instr(name, ".") ? _struct[strsplit(name, "."), "addr"] : _struct[name, "addr"]
                    _retv1 .= format("; numget(tmp_struct, {}, `"{}`") `; {}`n", addr, output_array[a_index * 2 - 1], name)
                    _retv1 .= format("; numput({}, tmp_struct, {}, `"{}`") `; {}`n", addr, output_array[a_index * 2], output_array[a_index * 2 - 1], name)
                    _retv2 .= format("numget(tmp_struct, {}, `"{}`") `; {}`n", addr, output_array[a_index * 2 - 1], name)
                    _retv2 .= format("; numput(`"{}`", {}, tmp_struct, {}) `; {}`n", output_array[a_index * 2 - 1], output_array[a_index * 2], addr, name)
                }
                struct_gui["ResultBox"].Value := _retv1 "`n`n"
                struct_gui["ResultBox"].Value .= _retv2
            }
            catch
                struct_gui["ResultBox"].Text := "invalid struct"
        }
    }
    
    static gui()
    {
        struct_gui := gui()
        struct_gui.type_map := {}
        struct_gui.setfont("s11","MicroSoft YaHei")
        struct_gui.add("button", "vClearButton x5 y5", "Clear All").OnEvent("Click", (*) => (struct_gui["EditBox"].Text := "", struct_gui["ResultBox"].Text := ""))
        struct_gui.add("button", "vGetButton yp x+1", "Get Result").OnEvent("Click", (*) => this.get_struct(struct_gui))
        struct_gui.add("button", "vAddButton yp x+2", "Add TypeMap").OnEvent("Click", (*) => this.add_typemap(struct_gui))
        struct_gui.add("button", "vClearTypeMapButton yp x+3", "Clear TypeMap").OnEvent("Click", (*) => struct_gui.type_map := {})
        struct_gui.add("text", "xs", "please input struct here")
        struct_gui.add("edit", "vEditBox xs w600 h300")
        struct_gui.add("text", "xs", "copy result here")
        struct_gui.add("edit", "vResultBox xs w600 h300 ReadOnly")
        struct_gui.show()
        return struct_gui
    }
}

class union
{
    static encoding := "utf-8"
    
    __new(member_array := [], type_map := {})
    {
        this.warning := ""
        this.members := member_array is string ? union.eval(member_array) : member_array
        this.type_map := type_map
        this.align()
        this.members := this.rebuild()
        this.size := this.max_align
        this.buf := buffer(this.size, 0)
        this.ptr := this.buf.ptr
    }
    
    __item[name, param*]
    {
        get
        {
            if name is array && param.length && param[1] = "addr"
            {
                total_addr := 0
                tmp := this
                loop name.length - 1
                {
                    total_addr += tmp[name[a_index], "addr"]
                    tmp := tmp[name[a_index]]
                }
                return total_addr + tmp[name[-1], param*]
            }
            else if name is array
            {
                tmp := this
                loop name.length - 1
                    tmp := tmp[name[a_index]]
                return tmp[name[-1], param*]
            }
            if this.members.has(name)
            {
                member := this.members[name]
                size := 1
                get_type := this.type_map.hasprop(member[1]) ? this.type_map.%member[1]% : struct.type_map.hasprop(member[1]) ? struct.type_map.%member[1]% : ["ptr", 8]
                if param.length
                {
                    if param[1] = "type"
                        return get_type[1]
                    if param[-1] is integer
                        size := member[2].hasprop("size") ? param[-1] + 1 : 1
                    if param[1] = "addr"
                        return (size = 1 || !member[2].hasprop("size")) ? member[-1] : member[-1] + (size - 1) * get_type[2]
                }
                if member[1] = "struct" || member[1] = "union"
                    return (size = 1 && !member[2].hasprop("size")) ? (member[2].%member[1]%) : (member[2].%member[1]%)[size]
                return numget(this.ptr, member[-1] + (size - 1) * get_type[2], get_type[1])
            }
        }
        
        set
        {
            if name is array
            {
                tmp := this
                loop name.length - 1
                    tmp := tmp[name[a_index]]
                tmp[name[-1], param*] := value
                return
            }
            if !isnumber(value) && value is string
                value := struct.strBuffer(value, union.encoding).ptr
            if this.members.has(name)
            {
                member := this.members[name]
                size := 1
                if param.length && param[-1] is integer
                    size := member[2].hasprop("size") ? param[-1] + 1 : 1
                if member[1] = "struct" || member[1] = "union"
                    return
                get_type := this.type_map.hasprop(member[1]) ? this.type_map.%member[1]% : struct.type_map.hasprop(member[1]) ? struct.type_map.%member[1]% : ["ptr", 8]
                return numput(get_type[1], value, member[-1] + (size - 1) * get_type[2], this.ptr)
            }
        }
    }
    
    align()
    {
        max_size := 0
        this.max_align := 0
        for member in this.members
        {
            type_map := this.type_map.hasprop(member[1]) ? this.type_map : struct.type_map.hasprop(member[1]) ? struct.type_map : ""
            if type_map
            {
                type_size := type_map.%member[1]%[2]
                this.max_align := max(this.max_align, type_size)
                tmp_size := (member.length >= 3 && member[3].hasprop("size")) ? member[3].size : 1
                max_size := max(max_size, type_size * tmp_size)
            }
            else if instr(member[1], "*")
            {
                type_size := a_ptrsize
                this.max_align := max(this.max_align, type_size)
                tmp_size := (member.length >= 3 && member[3].hasprop("size")) ? member[3].size : 1
                max_size := max(max_size, type_size * tmp_size)
            }
            else if member[1] = "struct"
            {
                struct_flag := member[3] is struct
                tmp_struct := !struct_flag ? struct(0, member[3], this.type_map) : member[3]
                type_size := tmp_struct.max_align
                this.max_align := max(this.max_align, type_size)
                if (member.length >= 4 && member[4].hasprop("size"))
                {
                    tmp_array := [tmp_struct]
                    tmp_size := member[4].size
                    loop tmp_size - 1
                        tmp_array.push(!struct_flag ? struct(0, member[3], this.type_map) : (buf := buffer(member[3].size, 0), tmp := member[3].clone(), tmp.ptr := buf.ptr, tmp))
                    member[3] := tmp_array
                    max_size := max(max_size, tmp_struct.size * tmp_size)
                }
                else
                {
                    member[3] := tmp_struct
                    max_size := max(max_size, tmp_struct.size)
                }
            }
            else if member[1] = "union"
            {
                if !(member[2] is string)
                    member.insertat(2, "")
                union_flag := member[3] is union
                tmp_union := !union_flag ? union(member[3], this.type_map) : member[3]
                type_size := tmp_union.max_align
                this.max_align := max(this.max_align, type_size)
                if false ; (member.length >= 4 && member[4].hasprop("size"))
                {
                    tmp_array := [tmp_union]
                    tmp_size := member[4].size
                    loop tmp_size - 1
                        tmp_array.push(!union_flag ? union(member[3], this.type_map) : (buf := buffer(member[3].size, 0), tmp := member[3].clone(), tmp.ptr := buf.ptr, tmp))
                    member[3] := tmp_array
                    max_size := max(max_size, tmp_union.size * tmp_size)
                }
                else
                {
                    member[3] := tmp_union
                    max_size := max(max_size, tmp_union.size)
                }
            }
            else
            {
                type_size := a_ptrsize
                this.max_align := max(this.max_align, type_size)
                tmp_size := (member.length >= 3 && member[3].hasprop("size")) ? member[3].size : 1
                max_size := max(max_size, type_size * tmp_size)
                this.warning .= "type " member[1] " auto analysis as ptr.`n"
            }
        }
        this.max_align := struct.find_nearmul(max_size, this.max_align)
    }
    
    rebuild()
    {
        members := map()
        for member in this.members
        {
            if member[1] = "struct" || member[1] = "union"
            {
                members[member[2]] := [member[1], {%strlower(member[1])%: member[3]}, 0]
                if (member.length >= 4 && member[4].hasprop("size")) && member[1] != "union"
                    members[member[2]][2].size := member[4].size
            }
            else
            {
                members[member[2]] := [member[1], {}, 0]
                if (member.length >= 3 && member[3].hasprop("size"))
                    members[member[2]][2].size := member[3].size
            }
        }
        return members
    }
    
    static eval(_string, mode := "union")
    {
        return struct.eval(_string, mode)
    }
    
    static gui()
    {
        return struct.gui()
    }
}
Attachments
pic20230217131925.png
pic20230217131925.png (53.37 KiB) Viewed 2681 times
pic20230217131609.png
pic20230217131609.png (38.47 KiB) Viewed 2684 times
pic20230217131525.png
pic20230217131525.png (59.02 KiB) Viewed 2684 times

User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Re: [v2.0.0]Struct——auto calc struct and init a struct

Post by jNizM » 17 Feb 2023, 02:57

A few suggestions for the GUI:
- Checkbox to choose between v1 and v2 on output. You don't need both at the same time.
- Checkbox to choose between NumGet and NumPut on output. Again, most of the time you don't need both at the same time.

Make it maybe possible to pull the struct info directly from the header (possibly with path to the folder of the header files, specifying struct name and header name), since some data types specify that somewhere in the header file and not directly in the struct itself.
e.g. https://learn.microsoft.com/en-us/windows/win32/api/windns/ns-windns-dns_recorda
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile

just me
Posts: 9424
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: [v2.0.0]Struct——auto calc struct and init a struct

Post by just me » 17 Feb 2023, 04:24

Line 24:

Code: Select all

        size_t: ["uint", 4],
SIZE_T is of type ULONG_PTR -> pointer size!

just me
Posts: 9424
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: [v2.0.0]Struct——auto calc struct and init a struct

Post by just me » 17 Feb 2023, 04:37

Line 5:

Code: Select all

        bool: ["char", 1],
BOOL is of type INT -> 4 bytes!

Line 27:

Code: Select all

        ptr: ["ptr", 8],
PTR is 4 bytes for 32-bit environments!

just me
Posts: 9424
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: [v2.0.0]Struct——auto calc struct and init a struct

Post by just me » 17 Feb 2023, 04:39

It would be nice to have an option to set the bitness of the result struct.

User avatar
Mono919
Posts: 71
Joined: 05 May 2022, 02:36

Re: [v2.0.0]Struct——auto calc struct and init a struct

Post by Mono919 » 17 Feb 2023, 04:47

just me wrote:
17 Feb 2023, 04:37
Line 5:

Code: Select all

        bool: ["char", 1],
BOOL is of type INT -> 4 bytes!

Line 27:

Code: Select all

        ptr: ["ptr", 8],
PTR is 4 bytes for 32-bit environments!
thanks for all suggestions, these problems I will solve later.

User avatar
Mono919
Posts: 71
Joined: 05 May 2022, 02:36

Re: [v2.0.0]Struct——auto calc struct and init a struct

Post by Mono919 » 17 Feb 2023, 04:48

jNizM wrote:
17 Feb 2023, 02:57
A few suggestions for the GUI:
- Checkbox to choose between v1 and v2 on output. You don't need both at the same time.
- Checkbox to choose between NumGet and NumPut on output. Again, most of the time you don't need both at the same time.

Make it maybe possible to pull the struct info directly from the header (possibly with path to the folder of the header files, specifying struct name and header name), since some data types specify that somewhere in the header file and not directly in the struct itself.
e.g. https://learn.microsoft.com/en-us/windows/win32/api/windns/ns-windns-dns_recorda
ok, thanks. all of your suggestions is on the way.

User avatar
Mono919
Posts: 71
Joined: 05 May 2022, 02:36

Re: [v2.0.0]Struct——auto calc struct and init a struct

Post by Mono919 » 14 Mar 2023, 08:16

2023.03.14 update
1.Fix nest struct bugs.
2.Change Buffer to malloc for easily ptr create & free.(Need msvcrt.dll)

crocodile
Posts: 98
Joined: 28 Dec 2020, 13:41

Re: [v2.0.0]Struct——auto calc struct and init a struct

Post by crocodile » 24 Mar 2023, 11:50

Does it support creating structures from h files?
I need to use the AVFormatContext structure when calling ffmpeg.dll, and I found its definition method in the avformat.h file, but it references a lot of other structures, which makes it hard to extract its definition method.
If I could create the AVFormatContext structure from avformat.h, this would solve a lot of insurmountable problems.

User avatar
Mono919
Posts: 71
Joined: 05 May 2022, 02:36

Re: [v2.0.0]Struct——auto calc struct and init a struct

Post by Mono919 » 24 Mar 2023, 21:33

crocodile wrote:
24 Mar 2023, 11:50
Does it support creating structures from h files?
I need to use the AVFormatContext structure when calling ffmpeg.dll, and I found its definition method in the avformat.h file, but it references a lot of other structures, which makes it hard to extract its definition method.
If I could create the AVFormatContext structure from avformat.h, this would solve a lot of insurmountable problems.
h files now is still not supported, because it may related to macro parsing, enum parsing, and so on. if you want to got sizeof, you may use `tcc` to do that.

viv
Posts: 217
Joined: 09 Dec 2020, 17:48

Re: [v2.0.0]Struct——auto calc struct and init a struct

Post by viv » 27 Mar 2023, 01:20

Please ask a question
I'm getting a ptr that points to a struct via dllcall
Can I define a struct or something like that and restore it to an ahk object?

If so, can give an example of dllcall interaction?
Similar to restore struct from ptr
or passing ahk objects as structs

User avatar
Mono919
Posts: 71
Joined: 05 May 2022, 02:36

Re: [v2.0.0]Struct——auto calc struct and init a struct

Post by Mono919 » 27 Mar 2023, 07:46

viv wrote:
27 Mar 2023, 01:20
Please ask a question
I'm getting a ptr that points to a struct via dllcall
Can I define a struct or something like that and restore it to an ahk object?

If so, can give an example of dllcall interaction?
Similar to restore struct from ptr
or passing ahk objects as structs
dll code

Code: Select all

#include "pch.h"
#include "framework.h"
#include "Struct.h"
#include <malloc.h>

struct test
{
    int a;
    double b;
    WORD c;
};

// This is an example of an exported function.
extern "C" STRUCT_API test* fnStruct(void)
{
    test* m = (struct test*)malloc(sizeof(struct test));
    m->a = 10;
    m->b = 5.0;
    m->c = 20;
    return m;
}
use example:

Code: Select all

#Include <data\debug>
#Include <struct\struct>

debug.ProgramPause := false
struct_script := "
(
struct test
{
    int a;
    double b;
    WORD c;
}
)"
ptr := dllcall("Struct.dll\fnStruct")
a := struct(ptr, struct.eval(struct_script)[1])
debug a.exportself() ; => ["int", 10, "double", 5.0, "ushort", 20] => dllcall("(func)", a.exportself()*)
dllcall("(func)", a) ; => for pass struct structname*

crocodile
Posts: 98
Joined: 28 Dec 2020, 13:41

Re: [v2.0.0]Struct——auto calc struct and init a struct

Post by crocodile » 01 Apr 2023, 19:43

Mono919 wrote:
24 Mar 2023, 21:33
crocodile wrote:
24 Mar 2023, 11:50
Does it support creating structures from h files?
I need to use the AVFormatContext structure when calling ffmpeg.dll, and I found its definition method in the avformat.h file, but it references a lot of other structures, which makes it hard to extract its definition method.
If I could create the AVFormatContext structure from avformat.h, this would solve a lot of insurmountable problems.
h files now is still not supported, because it may related to macro parsing, enum parsing, and so on. if you want to got sizeof, you may use `tcc` to do that.
Can we compile a C++ tool that literally loads these h files and then outputs the code available to AutoHotkey? (Sorry, I don't know c++ at all)

User avatar
Mono919
Posts: 71
Joined: 05 May 2022, 02:36

Re: [v2.0.0]Struct——auto calc struct and init a struct

Post by Mono919 » 02 Apr 2023, 06:41

crocodile wrote:
01 Apr 2023, 19:43
Mono919 wrote:
24 Mar 2023, 21:33
crocodile wrote:
24 Mar 2023, 11:50
Does it support creating structures from h files?
I need to use the AVFormatContext structure when calling ffmpeg.dll, and I found its definition method in the avformat.h file, but it references a lot of other structures, which makes it hard to extract its definition method.
If I could create the AVFormatContext structure from avformat.h, this would solve a lot of insurmountable problems.
h files now is still not supported, because it may related to macro parsing, enum parsing, and so on. if you want to got sizeof, you may use `tcc` to do that.
Can we compile a C++ tool that literally loads these h files and then outputs the code available to AutoHotkey? (Sorry, I don't know c++ at all)
In my impression, it can also be obtained using gcc. There is a tool called "Structor" in "Adventure" IDE, but it's a v1 library.

Post Reply

Return to “Scripts and Functions (v2)”