1# !/usr/bin/env python3 2# coding=utf-8 3""" 4* Copyright (c) 2022 Shenzhen Kaihong Digital Industry Development Co., Ltd. 5* 6* HDF is dual licensed: you can use it either under the terms of 7* the GPL, or the BSD license, at your option. 8* See the LICENSE file in the root of this repository for complete details. 9""" 10 11import json 12import os 13import re 14from shutil import copyfile, move 15 16import CppHeaderParser 17 18 19class HeaderParser: 20 """ 21 Extract file path, file name, includes, enums, unions, structs, interfaces and callbacks 22 from CppHeaderParser 23 """ 24 25 def __init__(self): 26 self._header_dict = { 27 "name": "", 28 "path": "", 29 "import": [], 30 "enum": [], 31 "union": [], 32 "struct": [], 33 "typedef": [], 34 "interface": [], 35 "callback": [] 36 } 37 self._rand_name_count = 0 38 39 def parse(self, header_file): 40 try: 41 hjson = json.loads(CppHeaderParser.CppHeader(header_file).toJSON()) 42 except CppHeaderParser.CppParseError: 43 back_file = self._pre_handle(header_file) 44 hjson = json.loads(CppHeaderParser.CppHeader(header_file).toJSON()) 45 move(back_file, header_file) 46 47 try: 48 self._extract_path_and_file(header_file) 49 self._extract_include(hjson["includes"]) 50 self._extract_enum(hjson["enums"]) 51 for i in hjson["classes"]: 52 self._extract_union(hjson["classes"][i]) 53 self._extract_struct(hjson["classes"][i]) 54 self._extract_interface(hjson["classes"][i]) 55 self._extract_typedef(hjson["typedefs"]) 56 return self._header_dict 57 except KeyError: 58 pass 59 60 @staticmethod 61 def _pre_handle(header_file): 62 back_file = header_file + ".back" 63 copyfile(header_file, back_file) 64 f = open(header_file, 'r') 65 new_lines = "" 66 for line in f: 67 tt = re.match(r".*enum *((\w+) *\*) *\w* *;", line) 68 if tt: 69 new_line = line.replace(tt[1], tt[2] + "_ENUM_POINTER ") 70 new_lines += new_line 71 continue 72 tt = re.match(r".*(\[\w* *\(.*\) *]) *", line) 73 if tt: 74 new_line = line.replace(tt[1], "[]") 75 new_lines += new_line 76 continue 77 else: 78 new_lines += line 79 f.close() 80 f = open(header_file, 'w') 81 f.writelines(new_lines) 82 f.close() 83 return back_file 84 85 @staticmethod 86 def _has_function_pointer(jvs): 87 for jv in jvs: 88 if jv["function_pointer"] > 0: 89 return True 90 return False 91 92 def _checkout_function_pointer_param(self, params): 93 if params == '': 94 return [] 95 tt = re.match(r"(typedef )* *\w+ \( \* \) \(( .* )\)", params) 96 if tt: 97 params = tt[2].strip() + "," 98 else: 99 print("error cant analyze function pointer params: ", params) 100 return [] 101 ret = [] 102 while params: 103 tt = re.match(" *(const )*(struct |enum |union )* *", params) 104 if tt: # 去掉结构类型头 105 params = params[tt.regs[0][1]:] 106 tt = re.match(r"((unsigned )*[a-zA-Z0-9_:]+( *\** *\**)) *", params) 107 if tt: 108 param_type = params[tt.regs[1][0]:tt.regs[1][1]] # 参数类型 109 params = params[tt.regs[0][1]:] 110 tt = re.match("([a-zA-Z0-9_]+) *(,)", params) 111 if tt: 112 param_name = params[tt.regs[1][0]:tt.regs[1][1]] 113 params = params[tt.regs[0][1]:] 114 else: # 没有定义变量名的,设置一个默认变量名 115 param_name = "rand_name_%d" % self._rand_name_count 116 self._rand_name_count += 1 117 params = params[params.index(",") + 1:] 118 ret.append({"name": param_name, "type": param_type.strip()}) 119 else: 120 ret.append({"name": '', "type": params.strip(',').strip()}) 121 break 122 else: 123 print("error cant analyze param :[%s]" % params) 124 break 125 return ret 126 127 def _extract_path_and_file(self, path): 128 self._header_dict["path"], self._header_dict["name"] = os.path.split(path) 129 130 def _extract_include(self, includes): 131 """ 132 Extract imports from includes 133 """ 134 for include in includes: 135 if '<' not in include: # ignore system files 136 self._header_dict.get("import").append(include[1:-1]) 137 138 def _extract_enum(self, enums): 139 """ 140 Extract enums from enums 141 """ 142 for enm in enums: 143 if "name" in enm: 144 enum_dict = {"name": enm["name"], "members": []} 145 else: 146 enum_dict = {"name": "LostName_%d" % self._rand_name_count, "members": []} 147 self._rand_name_count += 1 148 for value in enm["values"]: 149 v_value = value["value"] 150 if not isinstance(v_value, int): 151 tt = re.match(r"0x|0X|\(|-", v_value) 152 if tt: 153 errmsg = "unexpected '%s'" % tt[0] 154 v_value = v_value + " // " + errmsg 155 print("[HeaderParser]: %s[line %d] " % (enm["filename"], enm["line_number"]), errmsg) 156 enum_dict["members"].append({"name": value["name"], "value": v_value}) 157 self._header_dict.get("enum").append(enum_dict) 158 159 def _extract_union(self, stack): 160 """ 161 Extract unions from classes 162 """ 163 union_dict = {} 164 if stack["declaration_method"] == "union": 165 union_dict["name"] = stack["name"].split(" ")[-1] 166 union_dict["type"] = "union" 167 union_dict["members"] = [] 168 file_name = self._header_dict.get("path") + "/" + self._header_dict.get("name") 169 for mb in stack["members"]: 170 union_dict.get("members").append({"file_name": file_name, 171 "line_number": mb["line_number"], 172 "name": mb["name"], "type": mb["type"]}) 173 self._header_dict.get("union").append(union_dict) 174 175 def _extract_struct(self, stack): 176 """ 177 Extract structs from structs or classes that have no methods 178 """ 179 struct_dict = {} 180 if stack["declaration_method"] in ["struct", "class"]: 181 if len(stack["methods"]["public"]) == 0: # 不带函数 182 if not self._has_function_pointer(stack["properties"]["public"]): # 变量中没有函数指针 183 struct_dict["name"] = stack["name"] 184 struct_dict["type"] = "struct" 185 struct_dict["members"] = [] 186 file_name = self._header_dict.get("path") + "/" + self._header_dict.get("name") 187 for mb in stack["properties"]["public"]: 188 if "enum_type" in mb: 189 struct_dict.get("members").append({"file_name": file_name, 190 "line_number": mb["line_number"], 191 "name": mb["name"], 192 "type": mb["enum_type"]["name"]}) 193 elif mb["array"] == 1: 194 struct_dict.get("members").append({"file_name": file_name, 195 "line_number": mb["line_number"], 196 "name": mb["name"], 197 "type": mb["type"] + " *"}) 198 else: 199 struct_dict.get("members").append({"file_name": file_name, 200 "line_number": mb["line_number"], 201 "name": mb["name"], 202 "type": mb["type"]}) 203 self._header_dict.get("struct").append(struct_dict) 204 205 def _extract_interface(self, stack): 206 """ 207 Extract interfaces from structs or classes which have some methods 208 """ 209 interface_dict = {} 210 if stack["declaration_method"] in ["struct", "class"]: 211 # 带函数,或变量中包含函数指针 212 if len(stack["methods"]["public"]) > 0 or self._has_function_pointer(stack["properties"]["public"]): 213 interface_dict["name"] = stack["name"] 214 interface_dict["members"] = [] 215 for mb in stack["methods"]["public"]: 216 if mb["name"] in (stack["name"], "DECLARE_INTERFACE_DESCRIPTOR"): 217 continue 218 params = [] 219 for param in mb["parameters"]: 220 para_name = param["name"] 221 if para_name == '': 222 para_name = "rand_name_%d" % self._rand_name_count 223 self._rand_name_count += 1 224 params.append({"name": para_name, "type": param["type"]}) 225 interface_dict.get("members").append( 226 {"name": mb["name"], 227 "params": params, 228 "file_name": 229 self._header_dict.get("path") + "/" + self._header_dict.get("name"), 230 "line_number": mb["line_number"]}) 231 for mb in stack["properties"]["public"]: 232 if mb["function_pointer"] > 0: 233 interface_dict.get("members").append( 234 {"name": mb["name"], 235 "params": self._checkout_function_pointer_param(mb["type"]), 236 "file_name": 237 self._header_dict.get("path") + "/" + self._header_dict.get("name"), 238 "line_number": mb["line_number"]}) 239 self._header_dict.get("interface").append(interface_dict) 240 241 def _extract_typedef(self, typedefs): 242 """ 243 Extract typedef from global typedefs 244 e.g. 245 "typedefs": { 246 "HotPlugCallback": "typedef void ( * ) ( uint32_t devId , bool connected , void * data )", 247 "AudioHandle": "void *" 248 } 249 """ 250 for td in typedefs: 251 if "typedef" in typedefs[td]: 252 self._header_dict.get("typedef").append({"name": td, 253 "type": "/* unsupported function pointer type: " + td + " */"}) 254 else: 255 self._header_dict.get("typedef").append({"name": td, "type": typedefs[td]}) 256