#!/usr/bin/python3
# _*_ coding=utf-8 _*_
import argparse
import code
import fileinput
import json
import readline
from shutil import copy
import signal
import sys
from text import text
import datetime
import xml.etree.ElementTree
from misc import *
import datetime
# TODO-doesnt support non-byte-sized reads
def type_resolver(elem, elem_list):
type_str = elem.attrib["type"]
type_name = elem.attrib["name"]
if type_str == "int8":
return "int8_t"
elif type_str == "uint8":
return "uint8_t"
elif type_str == "int16":
return "int16_t"
elif type_str == "uint16":
return "uint16_t"
elif type_str == "int32":
return "int32_t"
elif type_str == "uint32":
return "uint32_t"
elif type_str == "int64":
return "int64_t"
elif type_str == "uint64":
return "uint64_t"
elif type_str == "int128":
return "int128_t"
elif type_str == "uint128":
return "uint128_t"
elif type_str == "float":
return "float"
elif type_str == "double":
return "double"
elif type_str == "bool":
return "uint8_t"
elif type_str == "uchar":
return "int8_t"
elif type_str == "schar":
return "schar_t"
elif type_str == "string":
return "char*"
elif type_str == "FT::conditional":
return "void*"
elif type_str.find("self::") == 0:
for node in elem_list:
if elem.attrib["type"][6:] == node.tag:
return node.attrib["name"]
else: return type_str
def get_def_node(type_str, elem_list):
for node in elem_list:
if type_str == node.attrib["name"]:
return node
def pointer_remover(name:str):
if name[-1] == '*': return name[0:-1] + '_p'
else: return name
def reader_generator(elem, elem_list):
pass
def SigHandler_SIGINT(signum, frame):
print()
sys.exit(0)
def get_full_path(path, name):
if path[-1] == "/": return path + name
else: return path + "/" + name
def get_elem_count(elem, elems):
if "count" in elem.attrib:
try:
if str(int(elem.attrib["count"])) == elem.attrib["count"]:
return int(elem.attrib["count"])
except ValueError:
return -1
else:
return 1
def get_elem_size(elem, elems):
if "size" in elem.attrib:
try:
if str(int(elem.attrib["size"])) == elem.attrib["size"]:
return int(elem.attrib["size"])
except ValueError:
return -1
else:
return 0
class Argparser(object):
def __init__(self):
parser = argparse.ArgumentParser()
parser.add_argument("--targetname", type=str, help="main target name")
parser.add_argument("--outdir", type=str, help="path to output dir")
parser.add_argument("--structs", type=str, help="the structs json file")
parser.add_argument("--structsinclude", type=str, help="the path to the header that's going to be included by structs.h before structure declarations.")
parser.add_argument("--xml", type=str, help="paht to the xml file")
parser.add_argument("--dbg", action="store_true", help="debug", default=False)
parser.add_argument("--datetime", action="store_true", help="print date and time in autogen files", default=False)
parser.add_argument("--inline", action="store_true", help="inlines reader funcs", default=False)
parser.add_argument("--static", action="store_true", help="statics reader funcs", default=False)
parser.add_argument("--verbose", action="store_true", help="verbose", default=False)
self.args = parser.parse_args()
def dupemake(path, main_name):
copy("./resources/makefile", path)
makefile_path = get_full_path(path, "makefile")
for line in fileinput.input(makefile_path, inplace=True):
if "XXX" in line:
line = line.replace("XXX", main_name)
sys.stdout.write(line)
class CodeGen(object):
def __init__(self, argparser):
self.argparser = argparser
self.struct_json = json.load(open(self.argparser.args.structs))
self.dnt = datetime.datetime.now().isoformat()
self.elems = []
self.def_elems = []
self.read_elems = []
self.read_iter = []
self.def_iter = []
def init_hook(self):
pass
def init(self):
dupemake(self.argparser.args.outdir, self.argparser.args.targetname)
def dump_elems(self):
for elem in self.elems:
print("XXXX " + elem.tag)
print(elem.attrib)
def dump_def_elems(self):
for elem in self.def_elems:
print("XXXX " + elem.tag)
print(elem.attrib)
def dump_read_elems(self):
for elem in self.read_elems:
print("XXXX " + elem.tag)
print(elem.attrib)
def gen_reader_funcs(self):
read_source = open(self.argparser.args.outdir + "/read.c", "w")
read_source.write("\n// automatically generated by faultrieber\n")
read_source.write("// " + self.dnt + "\n")
read_source.write(text.header_list)
read_source.write('#include "./structs.h"\n')
inline = "inline " if self.argparser.args.inline else ""
static = "static " if self.argparser.args.static else ""
for elem in self.def_elems+ self.read_elems:
dummy_list = []
pointer = str()
access = "."
if "isaggregate" in elem.attrib:
pointer = "*"
access = "->"
read_source.write(static + inline + text.c_read_elem_sig.replace("YYY", elem.attrib["name"]).replace("XXX", elem.attrib["name"]+pointer))
read_source.write(text.c_function_dummy_dec.replace("XXX", elem.attrib["name"] + pointer))
if "isaggregate" in elem.attrib:
count = get_elem_count(elem, self.read_elems+self.def_elems)
if count == 1:
for child in elem:
child_count = get_elem_count(child, self.def_elems + self.read_elems)
ref_node_name = type_resolver(child, self.def_elems)
ref_node = get_def_node(ref_node_name, self.def_elems)
size = get_elem_size(child, self.def_elems + self.read_elems)
read_size_replacement = str()
if size > 0:
read_size_replacement = str(size)
if size == -1:
ref_size = child.attrib["size"][6:]
for child2 in elem:
if child2.tag == ref_size : read_size_replacement = "dummy" + access + child2.attrib["name"]
if ref_node:
ref_node_name = pointer_remover(ref_node.attrib["name"])
for_dummy_declare = ref_node.attrib["name"] + "* " + ref_node_name + "_ins" + "="
for_read = text.c_read_elem_sig_1.replace("XXX", ref_node_name) + ";\n"
if child_count == 1:
for_dummy_assign = "dummy" + access + child.attrib["name"] + "=" +ref_node_name+"_ins" + ";\n"
read_source.write(for_dummy_declare+for_read+for_dummy_assign)
else:
if child_count > 1:
for_dummy_assign = "dummy" + access + child.attrib["name"] + "[i]" + "=" +ref_node_name+"_ins" + ";\n"
read_source.write(text.simple_loop.replace("YYY", for_dummy_declare+for_read+for_dummy_assign))
if child_count == -1:
replacement = str()
count_name_str = child.attrib["count"][6:]
for child2 in elem:
if child2.tag == count_name_str: replacement = "dummy" + access + child2.attrib["name"]
for_dummy_assign = "dummy" + access + child.attrib["name"] + "[i]" + "=" +ref_node_name+"_ins" + ";\n"
read_source.write(text.simple_loop.replace("YYY", for_dummy_declare+for_read+for_dummy_assign).replace("XXX", replacement))
else:
for_dummy_declare = ref_node_name + " " + pointer_remover(ref_node_name)+"_ins" + ";\n"
for item in dummy_list:
if item == for_dummy_declare:
for_dummy_declare = ""
if for_dummy_declare: dummy_list.append(for_dummy_declare)
for_read = str()
if "size" in child.attrib:
for_read = text.c_read_gen_2.replace("XXX", pointer_remover(ref_node_name)+"_ins").replace("YYY", read_size_replacement)
else:
for_read = text.c_read_gen.replace("XXX", pointer_remover(ref_node_name)+"_ins").replace("YYY", pointer_remover(ref_node_name))
if child_count == 1:
for_dummy_assign = "dummy" + access + child.attrib["name"] + "=" +pointer_remover(ref_node_name)+"_ins" + ";\n"
read_source.write(for_dummy_declare+for_read+for_dummy_assign)
else:
if child_count > 1:
for_dummy_assign = "dummy" + access + child.attrib["name"] + "[i]" + "=" +pointer_remover(ref_node_name)+"_ins" + ";\n"
read_source.write(text.simple_loop.replace("YYY", for_dummy_declare+for_read+for_dummy_assign))
if child_count == -1:
replacement = str()
count_name_str = child.attrib["count"][6:]
for child2 in elem:
if child2.tag == count_name_str: replacement = "dummy" + access + child2.attrib["name"]
for_dummy_assign = "dummy" + access + child.attrib["name"] + "[i]" + "=" +pointer_remover(ref_node_name)+"_ins" + ";\n"
read_source.write(text.simple_loop.replace("YYY", for_dummy_declare+for_read+for_dummy_assign).replace("XXX", replacement))
else:
pass
else:
read_source.write(type_resolver(elem, self.elems) + " " + elem.attrib["name"] + ";\n")
read_source.write(text.c_function_return_type)
read_source.write(text.c_function_close + "\n")
def read_xml(self):
if self.argparser.args.xml:
def_header = open(self.argparser.args.outdir + "/defines.h", "w")
def_header.write("\n// automatically generated by faultreiber\n")
def_header.write("// " + self.dnt + "\n")
def_header.write(text.header_inttype + "\n")
tree = xml.etree.ElementTree.parse(self.argparser.args.xml)
root = tree.getroot()
read_tree = xml.etree.ElementTree.Element("read")
def_tree = xml.etree.ElementTree.Element("def")
for child in root:
if child.tag == "Read":
read_tree = child
if child.tag == "Definition":
def_tree = child
for child in read_tree:
self.read_elems.append(child)
for child in def_tree:
self.def_elems.append(child)
read_iter = read_tree.iter(tag=None)
def_iter = def_tree.iter(tag=None)
self.read_iter = read_iter
self.def_iter = def_iter
for child in def_iter:
self.elems.append(child)
if "isaggregate" in child.attrib:
def_header.write("typedef struct {\n")
for childerer in child:
c_type = type_resolver(childerer, self.elems)
def_header.write("\t" + c_type + " " + childerer.attrib["name"] + ";\n")
def_header.write("}" + child.attrib["name"] + ";\n\n")
for child in read_iter:
self.elems.append(child)
if "isaggregate" in child.attrib:
def_header.write("typedef struct {\n")
for childerer in child:
c_type = type_resolver(childerer, self.elems)
def_header.write("\t" + c_type + " " + childerer.attrib["name"] + ";\n")
def_header.write("}" + child.attrib["name"] + ";\n\n")
def gen_struct_header_xml(self):
struct_source = open(get_full_path(self.argparser.args.outdir, "structs.h"), "w")
struct_source_c = open(get_full_path(self.argparser.args.outdir, "structs.c"), "w")
struct_source_c.write('#include "structs.h"')
struct_source.write(text.pre_header_guard)
struct_source.write(text.autogen_warning)
if self.argparser.args.datetime: struct_source.write("// " + self.dnt + "\n")
struct_source.write(text.header_guard_begin.replace("XXX", "structs".upper()))
struct_source.write(text.header_inttype)
struct_source.write(text.c_read_leb_u_def + "\n")
struct_source.write(text.c_read_leb_s_def + "\n")
struct_source.write(text.c_read_leb_macro_defs + "\n")
if self.argparser.args.structsinclude:
copy(self.argparser.args.structsinclude, self.argparser.args.outdir)
pos = self.argparser.args.structsinclude.rfind("/")
sub = self.argparser.args.structsinclude[pos+1:]
struct_source.write('#include "' + sub + '"\n\n')
for child in self.def_elems + self.read_elems:
struct_source.write("typedef struct {\n")
for childer in child:
ref_type = type_resolver(childer, self.def_elems + self.read_elems)
def_node = get_def_node(ref_type, self.def_elems + self.read_elems)
pointer = str()
if "count" in childer.attrib:
if childer.attrib["count"] != "1":
pointer = "*"
if def_node:
struct_source.write(ref_type + pointer + "* " + childer.attrib["name"] + ";\n")
else:
struct_source.write(ref_type + pointer + " " + childer.attrib["name"] + ";\n")
struct_source.write("}" + child.attrib["name"] + ";\n\n")
struct_source.write(text.pragma_endif)
struct_source.write(text.last_comment)
def gen_struct_header(self):
struct_source = open(get_full_path(self.argparser.args.outdir, "structs.h"), "w")
struct_source_c = open(get_full_path(self.argparser.args.outdir, "structs.c"), "w")
struct_source_c.write('#include "structs.h"')
struct_source.write(text.pre_header_guard)
struct_source.write(text.autogen_warning)
if self.argparser.args.datetime: struct_source.write("// " + self.dnt + "\n")
struct_source.write(text.header_guard_begin.replace("XXX", "structs".upper()))
struct_source.write(text.header_inttype)
if self.argparser.args.structsinclude:
copy(self.argparser.args.structsinclude, self.argparser.args.outdir)
pos = self.argparser.args.structsinclude.rfind("/")
sub = self.argparser.args.structsinclude[pos+1:]
struct_source.write('#include "' + sub + '"\n')
for k,v in self.struct_json.items():
struct_name = k
field_names = v["field_name"]
field_typess = v["field_type"]
struct_source.write("typedef struct {\n")
for i, j in zip(field_names, field_typess):
struct_source.write("\t" + j + " " + i + ";\n")
struct_source.write("}" + struct_name + ";\n\n")
struct_source.write(text.pragma_endif)
struct_source.write(text.last_comment)
def run(self):
self.init()
self.init_hook()
#self.gen_struct_header()
self.read_xml()
self.gen_reader_funcs()
self.gen_struct_header_xml()
#self.dump_def_elems()
#print("")
#self.dump_read_elems()
# write code here
def premain(argparser):
signal.signal(signal.SIGINT, SigHandler_SIGINT)
#here
codegen = CodeGen(argparser)
codegen.run()
def main():
argparser = Argparser()
if argparser.args.dbg:
try:
premain(argparser)
except Exception as e:
print(e.__doc__)
if e.message: print(e.message)
variables = globals().copy()
variables.update(locals())
shell = code.InteractiveConsole(variables)
shell.interact(banner="DEBUG REPL")
else:
premain(argparser)
if __name__ == "__main__":
main()