1#!/usr/bin/env python3 2# -*- coding: utf-8 -*- 3 4# Copyright (c) 2024 Huawei Device Co., Ltd. 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17from __future__ import absolute_import 18import system_util 19from io import BytesIO 20import os 21import re 22import shutil 23import string 24import sys 25import textwrap 26import time 27 28# pylint:disable=dangerous-default-value 29# pylint:disable=huawei-redefined-outer-name 30 31def notify(msg): 32 """ Display a message. """ 33 sys.stdout.write(' NOTE: ' + msg + '\n') 34 35 36def wrap_text(text, indent='', maxchars=120): 37 """ Wrap the text to the specified number of characters. If 38 necessary a line will be broken and wrapped after a word. 39 """ 40 result = '' 41 lines = textwrap.wrap(text, maxchars - len(indent)) 42 for line in lines: 43 result += indent + line + '\n' 44 return result 45 46 47def is_base_class(clsname): 48 """ Returns true if |clsname| is a known base (root) class in the object 49 hierarchy. 50 """ 51 return clsname == 'ArkWebBaseRefCounted' or clsname == 'ArkWebBaseScoped' 52 53 54def get_capi_file_name(cppname): 55 """ Convert a C++ header file name to a C API header file name. """ 56 return cppname[:-2] + '_capi.h' 57 58 59def get_capi_name(cppname, isclassname, prefix=None): 60 """ Convert a C++ CamelCaps name to a C API underscore name. """ 61 result = '' 62 lastchr = '' 63 for chr in cppname: 64 # add an underscore if the current character is an upper case letter 65 # and the last character was a lower case letter 66 if len(result) > 0 and not chr.isdigit() \ 67 and chr.upper() == chr \ 68 and not lastchr.upper() == lastchr: 69 result += '_' 70 result += chr.lower() 71 lastchr = chr 72 73 if isclassname: 74 result += '_t' 75 76 if not prefix is None: 77 if prefix[0:3] == 'cef': 78 # if the prefix name is duplicated in the function name 79 # remove that portion of the function name 80 subprefix = prefix[3:] 81 pos = result.find(subprefix) 82 if pos >= 0: 83 result = result[0:pos] + result[pos + len(subprefix):] 84 result = prefix + '_' + result 85 86 return result 87 88 89def get_wrapper_type_enum(cppname): 90 """ Returns the wrapper type enumeration value for the specified C++ class 91 name. """ 92 return get_capi_name(cppname, False).upper() 93 94 95def get_prev_line(body, pos): 96 """ Retrieve the start and end positions and value for the line immediately 97 before the line containing the specified position. 98 """ 99 end = body.rfind('\n', 0, pos) 100 start = body.rfind('\n', 0, end) + 1 101 line = body[start:end] 102 return {'start': start, 'end': end, 'line': line} 103 104 105def get_comment(body, name): 106 """ Retrieve the comment for a class or function. """ 107 result = [] 108 109 pos = body.find(name) 110 in_block_comment = False 111 while pos > 0: 112 data = get_prev_line(body, pos) 113 line = data['line'].strip() 114 pos = data['start'] 115 if len(line) == 0: 116 break 117 # single line /*--cef()--*/ 118 elif line[0:2] == '/*' and line[-2:] == '*/': 119 continue 120 # start of multi line /*--cef()--*/ 121 elif in_block_comment and line[0:2] == '/*': 122 in_block_comment = False 123 continue 124 # end of multi line /*--cef()--*/ 125 elif not in_block_comment and line[-2:] == '*/': 126 in_block_comment = True 127 continue 128 elif in_block_comment: 129 continue 130 elif line[0:3] == '///': 131 # keep the comment line including any leading spaces 132 result.append(line[3:]) 133 else: 134 break 135 136 result.reverse() 137 return result 138 139 140def validate_comment(file, name, comment): 141 """ Validate the comment array returned by get_comment(). """ 142 143def format_translation_changes(old, new): 144 """ Return a comment stating what is different between the old and new 145 function prototype parts. 146 """ 147 changed = False 148 result = '' 149 150 # normalize C API attributes 151 oldargs = [x.replace('struct _', '') for x in old['args']] 152 oldretval = old['retval'].replace('struct _', '') 153 newargs = [x.replace('struct _', '') for x in new['args']] 154 newretval = new['retval'].replace('struct _', '') 155 156 # check if the prototype has changed 157 oldset = set(oldargs) 158 newset = set(newargs) 159 if len(oldset.symmetric_difference(newset)) > 0: 160 changed = True 161 result += '\n // WARNING - CHANGED ATTRIBUTES' 162 163 # in the implementation set only 164 oldonly = oldset.difference(newset) 165 for arg in oldonly: 166 result += '\n // REMOVED: ' + arg 167 168 # in the current set only 169 newonly = newset.difference(oldset) 170 for arg in newonly: 171 result += '\n // ADDED: ' + arg 172 173 # check if the return value has changed 174 if oldretval != newretval: 175 changed = True 176 result += '\n // WARNING - CHANGED RETURN VALUE'+ \ 177 '\n // WAS: '+old['retval']+ \ 178 '\n // NOW: '+new['retval'] 179 180 if changed: 181 result += '\n #pragma message("Warning: " __FILE__ ": '+new['name']+ \ 182 ' prototype has changed")\n' 183 184 return result 185 186 187def format_translation_includes(header, dir_name, body): 188 """ Return the necessary list of includes based on the contents of the 189 body. 190 """ 191 result = '' 192 193 # <algorithm> required for VS2013. 194 if body.find('std::min') > 0 or body.find('std::max') > 0: 195 result += '#include <algorithm>\n' 196 197 if body.find('cef_api_hash(') > 0: 198 result += '#include "include/cef_api_hash.h"\n' 199 200 if body.find('template_util::has_valid_size(') > 0: 201 result += '#include "libcef_dll/template_util.h"\n' 202 203 # identify what CppToC classes are being used 204 p = re.compile('([A-Za-z0-9_]{1,})CppToC') 205 list = sorted(set(p.findall(body))) 206 for item in list: 207 directory = '' 208 if not is_base_class(item): 209 cls = header.get_class(item) 210 dir = cls.get_file_directory() 211 if not dir is None: 212 directory = dir + '/' 213 result += '#include "'+dir_name+'/cpptoc/'+directory+ \ 214 get_capi_name(item, False)+'_cpptoc.h"\n' 215 216 # identify what CToCpp classes are being used 217 p = re.compile('([A-Za-z0-9_]{1,})CToCpp') 218 list = sorted(set(p.findall(body))) 219 for item in list: 220 directory = '' 221 if not is_base_class(item): 222 cls = header.get_class(item) 223 dir = cls.get_file_directory() 224 if not dir is None: 225 directory = dir + '/' 226 result += '#include "'+dir_name+'/ctocpp/'+directory+ \ 227 get_capi_name(item, False)+'_ctocpp.h"\n' 228 229 if body.find('shutdown_checker') > 0: 230 result += '#include "libcef_dll/shutdown_checker.h"\n' 231 232 if body.find('transfer_') > 0: 233 result += '#include "libcef_dll/transfer_util.h"\n' 234 235 return result 236 237 238def str_to_dict(str): 239 """ Convert a string to a dictionary. If the same key has multiple values 240 the values will be stored in a list. """ 241 dict = {} 242 parts = str.split(',') 243 for part in parts: 244 part = part.strip() 245 if len(part) == 0: 246 continue 247 sparts = part.split('=') 248 if len(sparts) > 2: 249 raise Exception('Invalid dictionary pair format: ' + part) 250 name = sparts[0].strip() 251 if len(sparts) == 2: 252 val = sparts[1].strip() 253 else: 254 val = True 255 if name in dict: 256 # a value with this name already exists 257 curval = dict[name] 258 if not isinstance(curval, list): 259 # convert the string value to a list 260 dict[name] = [curval] 261 dict[name].append(val) 262 else: 263 dict[name] = val 264 return dict 265 266 267def dict_to_str(dict): 268 """ Convert a dictionary to a string. """ 269 str = [] 270 for name in dict.keys(): 271 if not isinstance(dict[name], list): 272 if dict[name] is True: 273 # currently a bool value 274 str.append(name) 275 else: 276 # currently a string value 277 str.append(name + '=' + dict[name]) 278 else: 279 # currently a list value 280 for val in dict[name]: 281 str.append(name + '=' + val) 282 return ','.join(str) 283 284 285# regex for matching comment-formatted attributes 286_cre_attrib = '/\*--ark web\(([A-Za-z0-9_ ,=:\n]{0,})\)--\*/' 287# regex for matching class and function names 288_cre_cfname = '([A-Za-z0-9_]{1,})' 289# regex for matching class and function names including path separators 290_cre_cfnameorpath = '([A-Za-z0-9_\/]{2,})' 291# regex for matching typedef value and name combination 292_cre_typedef = '([A-Za-z0-9_<>:,\*\&\s]{1,})' 293# regex for matching function return value and name combination 294_cre_func = '([A-Za-z][A-Za-z0-9_<>:,\*\&\s]{1,})' 295# regex for matching virtual function modifiers + arbitrary whitespace 296_cre_vfmod = '([\sA-Za-z0-9_]{0,})' 297# regex for matching arbitrary whitespace 298_cre_space = '[\s]{1,}' 299# regex for matching optional virtual keyword 300_cre_virtual = '(?:[\s]{1,}virtual){0,1}' 301 302# Simple translation types. Format is: 303# 'cpp_type' : ['capi_type', 'capi_default_value'] 304_simpletypes = { 305 'void': ['void', ''], 306 'void*': ['void*', 'NULL'], 307 'char*': ['char*', 'NULL'], 308 'int': ['int', '0'], 309 'OnVsyncCallback': ['OnVsyncCallback', 'NULL'], 310 'ArkWebRunInitedCallback*': ['ArkWebRunInitedCallback*', 'NULL'], 311 'ArkAudioAdapterDeviceDesc': ['ArkAudioAdapterDeviceDesc', '{0}'], 312 'ArkAudioAdapterDeviceDescVector': ['ArkAudioAdapterDeviceDescVector', '{0}'], 313 'ArkAudioAdapterInterrupt': ['ArkAudioAdapterInterrupt', '{0}'], 314 'ArkAudioAdapterRendererOptions': ['ArkAudioAdapterRendererOptions', '{0}'], 315 'WebRunInitedCallback*': ['WebRunInitedCallback*', 'NULL'], 316 'ArkWriteResultCallback': ['ArkWriteResultCallback', 'NULL'], 317 'ArkPasteCustomData': ['ArkPasteCustomData', '{0}'], 318 'ArkClipBoardImageData': ['ArkClipBoardImageData', '{0}'], 319 'ArkPasteRecordVector': ['ArkPasteRecordVector', '{0}'], 320 'ArkAudioDeviceDescAdapterVector': ['ArkAudioDeviceDescAdapterVector', '{0}'], 321 'ArkPrintAttributesAdapter': ['ArkPrintAttributesAdapter', '{0}'], 322 'ArkTimeZoneEventCallback': ['ArkTimeZoneEventCallback', 'NULL'], 323 'ArkIConsumerSurfaceAdapter*': ['ArkIConsumerSurfaceAdapter*', 'NULL'], 324 'ArkOhosAdapterHelper*': ['ark_ohos_adapter_helper_t*', 'NULL'], 325 'ArkOhosAdapterHelper': ['ark_ohos_adapter_helper_t', 'ArkOhosAdapterHelper()'], 326 'ArkDatashareAdapter*': ['ark_datashare_adapter_t*', 'NULL'], 327 'ArkFormatAdapterVector': ['ArkFormatAdapterVector', '{0}'], 328 'ArkFrameRateSettingAdapterVector': [ 329 'ArkFrameRateSettingAdapterVector', 'ark_frame_rate_setting_adapter_vector_default' 330 ], 331 'ArkVideoDeviceDescriptorAdapterVector': ['ArkVideoDeviceDescriptorAdapterVector', '{0}'], 332 'uint8_t': ['uint8_t', '0'], 333 'uint8_t*': ['uint8_t*', 'NULL'], 334 'time_t': ['time_t', '0'], 335 'pid_t': ['pid_t', '0'], 336 'int16_t': ['int16_t', '0'], 337 'uint16_t': ['uint16_t', '0'], 338 'int32_t': ['int32_t', '0'], 339 'uint32_t': ['uint32_t', '0'], 340 'uint32_t*': ['uint32_t*', 'NULL'], 341 'int64_t': ['int64_t', '0'], 342 'uint64_t': ['uint64_t', '0'], 343 'uint64_t*': ['uint64_t*', 'NULL'], 344 'double_t': ['double_t', '0'], 345 'double': ['double', '0'], 346 'float': ['float', '0'], 347 'long': ['long', '0'], 348 'unsigned int':['unsigned int', '0'], 349 'unsigned long': ['unsigned long', '0'], 350 'long long': ['long long', '0'], 351 'size_t': ['size_t', '0'], 352 'bool': ['bool', 'false'], 353 'char': ['char', '0'], 354 'Type':['Type', 'NONE'], 355 'unsigned char':['unsigned char', '0'], 356 'ArkWebDateTime':['ArkWebDateTime', 'ark_web_date_time_default'], 357 'AccessMode':['AccessMode', 'NEVER_ALLOW'], 358 'TextDirection':['TextDirection', 'SP_UNKNOWN'], 359 'CacheModeFlag':['CacheModeFlag', 'USE_NO_CACHE'], 360 'ImageColorType':['ImageColorType', 'COLOR_TYPE_UNKNOWN'], 361 'ImageAlphaType':['ImageAlphaType', 'ALPHA_TYPE_UNKNOWN'], 362 'TouchHandleType':['TouchHandleType', 'INVALID_HANDLE'], 363 'FileSelectorMode':['FileSelectorMode', 'FILE_OPEN_MODE'], 364 'ContextMenuMediaType':['ContextMenuMediaType', 'CM_MT_NONE'], 365 'NWebResponseDataType':['NWebResponseDataType', 'NWEB_STRING_TYPE'], 366 'ContextMenuSourceType':['ContextMenuSourceType', 'CM_ST_NONE'], 367 'SelectPopupMenuItemType':['SelectPopupMenuItemType', 'SP_OPTION'], 368 'ContextMenuInputFieldType':['ContextMenuInputFieldType', 'CM_IT_NONE'], 369 'MenuEventFlags':['MenuEventFlags', 'EF_NONE'], 370 'NWebConsoleLogLevel':['NWebConsoleLogLevel', 'ERROR'], 371 'ArkWebCursorInfo':['ArkWebCursorInfo', 'ark_web_cursor_info_default'], 372 'AccessibilityIdGenerateFunc':['AccessibilityIdGenerateFunc', 'NULL'], 373 'NativeArkWebOnValidCallback':['NativeArkWebOnValidCallback', 'NULL'], 374 'NativeArkWebOnDestroyCallback':['NativeArkWebOnDestroyCallback', 'NULL'], 375 'NativeArkWebOnJavaScriptProxyCallback':['NativeArkWebOnJavaScriptProxyCallback', 'NULL'], 376 'ArkWebCharVector':['ArkWebCharVector', 'ark_web_char_vector_default'], 377 'ArkWebUint8Vector':['ArkWebUint8Vector', 'ark_web_uint8_vector_default'], 378 'ArkWebUint16Vector':['ArkWebUint16Vector', 'ark_web_uint16_vector_default'], 379 'ArkWebInt32Vector':['ArkWebInt32Vector', 'ark_web_int32_vector_default'], 380 'ArkWebInt64Vector':['ArkWebInt64Vector', 'ark_web_int64_vector_default'], 381 'ArkWebUint32Vector':['ArkWebUint32Vector', 'ark_web_uint32_vector_default'], 382 'ArkWebDoubleVector':['ArkWebDoubleVector', 'ark_web_double_vector_default'], 383 'ArkWebBooleanVector':['ArkWebBooleanVector', 'ark_web_boolean_vector_default'], 384 'ArkWebInt32List':['ArkWebInt32List', 'ark_web_int32_list_default'], 385 'ArkWebValue':['ArkWebValue', 'ark_web_value_default'], 386 'ArkWebMessage':['ArkWebMessage', 'ark_web_message_default'], 387 'ArkWebString':['ArkWebString', 'ark_web_string_default'], 388 'ArkWebU16String':['ArkWebU16String', 'ark_web_u16string_default'], 389 'ArkWebStringList':['ArkWebStringList', 'ark_web_string_list_default'], 390 'ArkWebStringMap':['ArkWebStringMap', 'ark_web_string_map_default'], 391 'ArkWebStringVector':['ArkWebStringVector', 'ark_web_string_vector_default'], 392 'ArkWebStringVectorMap':['ArkWebStringVectorMap', 'ark_web_string_vector_map_default'], 393 'ArkWebValueVector':['ArkWebValueVector', 'ark_web_value_vector_default'], 394 'ArkWebTouchPointInfoVector':['ArkWebTouchPointInfoVector', 'ak_web_touch_point_info_vector_default'], 395 'ArkWebMediaSourceInfoVector':['ArkWebMediaSourceInfoVector', 'ark_web_media_source_info_vector_default'], 396 'ArkWebJsProxyCallbackVector':['ArkWebJsProxyCallbackVector', 'ark_web_js_proxy_callback_vector_default'], 397 'ArkWebWebStorageOriginVector':['ArkWebWebStorageOriginVector', 'ark_web_web_storage_origin_vector_default'], 398 'ArkWebDateTimeSuggestionVector':['ArkWebDateTimeSuggestionVector', 'ark_web_date_time_suggestion_vector_default'], 399 'ArkWebSelectPopupMenuItemVector':[ 400 'ArkWebSelectPopupMenuItemVector', 'ark_web_select_popup_menu_item_vector_default' 401 ], 402 'char* const': ['char* const', 'NULL'], 403 'cef_color_t': ['cef_color_t', '0'], 404 'cef_json_parser_error_t': ['cef_json_parser_error_t', 'JSON_NO_ERROR'], 405 'CefAudioParameters': ['cef_audio_parameters_t', 'CefAudioParameters()'], 406 'CefBaseTime': ['cef_basetime_t', 'CefBaseTime()'], 407 'CefBoxLayoutSettings': [ 408 'cef_box_layout_settings_t', 'CefBoxLayoutSettings()' 409 ], 410 'CefCompositionUnderline': [ 411 'cef_composition_underline_t', 'CefCompositionUnderline()' 412 ], 413 'CefCursorHandle': ['cef_cursor_handle_t', 'kNullCursorHandle'], 414 'CefCursorInfo': ['cef_cursor_info_t', 'CefCursorInfo()'], 415 'CefDraggableRegion': ['cef_draggable_region_t', 'CefDraggableRegion()'], 416 'CefEventHandle': ['cef_event_handle_t', 'kNullEventHandle'], 417 'CefInsets': ['cef_insets_t', 'CefInsets()'], 418 'CefKeyEvent': ['cef_key_event_t', 'CefKeyEvent()'], 419 'CefMainArgs': ['cef_main_args_t', 'CefMainArgs()'], 420 'CefMouseEvent': ['cef_mouse_event_t', 'CefMouseEvent()'], 421 'CefPoint': ['cef_point_t', 'CefPoint()'], 422 'CefPopupFeatures': ['cef_popup_features_t', 'CefPopupFeatures()'], 423 'CefRange': ['cef_range_t', 'CefRange()'], 424 'CefRect': ['cef_rect_t', 'CefRect()'], 425 'CefScreenInfo': ['cef_screen_info_t', 'CefScreenInfo()'], 426 'CefSize': ['cef_size_t', 'CefSize()'], 427 'CefTouchEvent': ['cef_touch_event_t', 'CefTouchEvent()'], 428 'CefTouchHandleState': [ 429 'cef_touch_handle_state_t', 'CefTouchHandleState()' 430 ], 431 'CefThreadId': ['cef_thread_id_t', 'TID_UI'], 432 'CefTime': ['cef_time_t', 'CefTime()'], 433 'CefWindowHandle': ['cef_window_handle_t', 'kNullWindowHandle'], 434 'WebSnapshotCallback':['WebSnapshotCallback', 'NULL'], 435 'ArkDisplayAdapterVector': ['ArkDisplayAdapterVector', '{0}'], 436} 437 438 439def get_function_impls(content, ident, has_impl=True): 440 """ Retrieve the function parts from the specified contents as a set of 441 return value, name, arguments and body. Ident must occur somewhere in 442 the value. 443 """ 444 # Remove prefix from methods in CToCpp files. 445 content = content.replace('ARK_WEB_NO_SANITIZE("cfi-icall") ', '') 446 content = content.replace('ARK_WEB_NO_SANITIZE("cfi-icall")\n', '') 447 448 # extract the functions 449 find_regex = '\n' + _cre_func + '\((.*?)\)([A-Za-z0-9_\s]{0,})' 450 if has_impl: 451 find_regex += '\{(.*?)\n\}' 452 else: 453 find_regex += '(;)' 454 p = re.compile(find_regex, re.MULTILINE | re.DOTALL) 455 list = p.findall(content) 456 457 # build the function map with the function name as the key 458 result = [] 459 for retval, argval, vfmod, body in list: 460 if retval.find(ident) < 0: 461 # the identifier was not found 462 continue 463 464 # remove the identifier 465 retval = retval.replace(ident, '') 466 retval = retval.strip() 467 468 # Normalize the delimiter. 469 retval = retval.replace('\n', ' ') 470 471 # retrieve the function name 472 parts = retval.split(' ') 473 name = parts[-1] 474 del parts[-1] 475 retval = ' '.join(parts) 476 477 # parse the arguments 478 args = [] 479 if argval != 'void': 480 for v in argval.split(','): 481 v = v.strip() 482 if len(v) > 0: 483 args.append(v) 484 485 result.append({ 486 'retval': retval.strip(), 487 'name': name, 488 'args': args, 489 'vfmod': vfmod.strip(), 490 'body': body if has_impl else '', 491 }) 492 493 return result 494 495 496def get_next_function_impl(existing, name): 497 result = None 498 for item in existing: 499 if item['name'] == name: 500 result = item 501 existing.remove(item) 502 break 503 return result 504 505def check_arg_type_is_struct(arg_type): 506 if arg_type == 'ArkWebString' or arg_type == 'ArkWebUint8Vector' or arg_type == 'ArkWebInt64Vector' or \ 507 arg_type == 'ArkWebDoubleVector' or arg_type == 'ArkWebBooleanVector' or arg_type == 'ArkWebStringMap' or \ 508 arg_type == 'ArkWebStringVector': 509 return True 510 else: 511 return False 512 513 514def check_func_name_is_key_work(func_name): 515 if func_name == 'continue': 516 return True 517 else: 518 return False 519 520 521class obj_header: 522 """ Class representing a C++ header file. """ 523 524 def __init__(self): 525 self.filenames = [] 526 self.typedefs = [] 527 self.funcs = [] 528 self.classes = [] 529 self.root_directory = None 530 531 def set_root_directory(self, root_directory): 532 """ Set the root directory. """ 533 self.root_directory = root_directory 534 535 def get_root_directory(self): 536 """ Get the root directory. """ 537 return self.root_directory 538 539 def add_directory(self, directory, excluded_files=[]): 540 """ Add all header files from the specified directory. """ 541 files = system_util.get_files(os.path.join(directory, '*.h')) 542 for file in files: 543 if len(excluded_files) == 0 or not os.path.split(file)[1] in excluded_files: 544 self.add_file(file) 545 546 def add_file(self, filepath): 547 """ Add a header file. """ 548 549 if self.root_directory is None: 550 filename = os.path.split(filepath)[1] 551 else: 552 filename = os.path.relpath(filepath, self.root_directory) 553 filename = filename.replace('\\', '/') 554 555 try: 556 # read the input file into memory 557 self.add_data(filename, system_util.read_file(filepath)) 558 except Exception: 559 print('Exception while parsing %s' % filepath) 560 raise 561 562 def add_data(self, filename, data): 563 """ Add header file contents. """ 564 565 added = False 566 567 # remove space from between template definition end brackets 568 data = data.replace("> >", ">>") 569 570 # extract global typedefs 571 p = re.compile('\ntypedef' + _cre_space + _cre_typedef + ';', 572 re.MULTILINE | re.DOTALL) 573 list = p.findall(data) 574 if len(list) > 0: 575 # build the global typedef objects 576 for value in list: 577 pos = value.rfind(' ') 578 if pos < 0: 579 raise Exception('Invalid typedef: ' + value) 580 alias = value[pos + 1:].strip() 581 value = value[:pos].strip() 582 self.typedefs.append(obj_typedef(self, filename, value, alias)) 583 584 # extract global functions 585 p = re.compile('\n' + _cre_attrib + '\n' + _cre_func + '\((.*?)\)', 586 re.MULTILINE | re.DOTALL) 587 list = p.findall(data) 588 if len(list) > 0: 589 added = True 590 591 # build the global function objects 592 for attrib, retval, argval in list: 593 comment = get_comment(data, retval + '(' + argval + ');') 594 validate_comment(filename, retval, comment) 595 self.funcs.append( 596 obj_function(self, filename, attrib, retval, argval, comment)) 597 598 # extract includes 599 p = re.compile('\n#include \"' + _cre_cfnameorpath + '.h') 600 includes = p.findall(data) 601 602 # extract forward declarations 603 p = re.compile('\nclass' + _cre_space + _cre_cfname + ';') 604 forward_declares = p.findall(data) 605 606 # extract empty classes 607 p = re.compile('\n' + _cre_attrib + '\nclass' + _cre_space + _cre_cfname + 608 _cre_space + ':' + _cre_space + 'public' + _cre_virtual + 609 _cre_space + _cre_cfname + _cre_space + '{};', 610 re.MULTILINE | re.DOTALL) 611 list = p.findall(data) 612 if len(list) > 0: 613 added = True 614 615 # build the class objects 616 for attrib, name, parent_name in list: 617 # Style may place the ':' on the next line. 618 comment = get_comment(data, name + ' :') 619 if len(comment) == 0: 620 comment = get_comment(data, name + "\n") 621 validate_comment(filename, name, comment) 622 self.classes.append( 623 obj_class(self, filename, attrib, name, parent_name, "", comment, 624 includes, forward_declares)) 625 626 # Remove empty classes from |data| so we don't mess up the non-empty 627 # class search that follows. 628 data = p.sub('', data) 629 630 # extract classes 631 p = re.compile('\n' + _cre_attrib + '\nclass' + _cre_space + _cre_cfname + 632 _cre_space + ':' + _cre_space + 'public' + _cre_virtual + 633 _cre_space + _cre_cfname + _cre_space + '{(.*?)\n};', 634 re.MULTILINE | re.DOTALL) 635 list = p.findall(data) 636 if len(list) > 0: 637 added = True 638 639 # build the class objects 640 for attrib, name, parent_name, body in list: 641 # Style may place the ':' on the next line. 642 comment = get_comment(data, name + ' :') 643 if len(comment) == 0: 644 comment = get_comment(data, name + "\n") 645 validate_comment(filename, name, comment) 646 self.classes.append( 647 obj_class(self, filename, attrib, name, parent_name, body, comment, 648 includes, forward_declares)) 649 650 if added: 651 # a global function or class was read from the header file 652 self.filenames.append(filename) 653 654 def __repr__(self): 655 result = '' 656 657 if len(self.typedefs) > 0: 658 strlist = [] 659 for cls in self.typedefs: 660 strlist.append(str(cls)) 661 result += "\n".join(strlist) + "\n\n" 662 663 if len(self.funcs) > 0: 664 strlist = [] 665 for cls in self.funcs: 666 strlist.append(str(cls)) 667 result += "\n".join(strlist) + "\n\n" 668 669 if len(self.classes) > 0: 670 strlist = [] 671 for cls in self.classes: 672 strlist.append(str(cls)) 673 result += "\n".join(strlist) 674 675 return result 676 677 def get_file_names(self): 678 """ Return the array of header file names. """ 679 return self.filenames 680 681 def get_typedefs(self): 682 """ Return the array of typedef objects. """ 683 return self.typedefs 684 685 def get_funcs(self, filename=None): 686 """ Return the array of function objects. """ 687 if filename is None: 688 return self.funcs 689 else: 690 # only return the functions in the specified file 691 res = [] 692 for func in self.funcs: 693 if func.get_file_name() == filename: 694 res.append(func) 695 return res 696 697 def get_classes(self, filename=None): 698 """ Return the array of class objects. """ 699 if filename is None: 700 return self.classes 701 else: 702 # only return the classes in the specified file 703 res = [] 704 for cls in self.classes: 705 if cls.get_file_name() == filename: 706 res.append(cls) 707 return res 708 709 def get_class(self, classname, defined_structs=None): 710 """ Return the specified class or None if not found. """ 711 for cls in self.classes: 712 if cls.get_name() == classname: 713 return cls 714 elif not defined_structs is None: 715 defined_structs.append(cls.get_capi_name()) 716 return None 717 718 def get_class_names(self): 719 """ Returns the names of all classes in this object. """ 720 result = [] 721 for cls in self.classes: 722 result.append(cls.get_name()) 723 return result 724 725 def get_base_class_name(self, classname): 726 """ Returns the base (root) class name for |classname|. """ 727 cur_cls = self.get_class(classname) 728 while True: 729 parent_name = cur_cls.get_parent_name() 730 if is_base_class(parent_name): 731 return parent_name 732 else: 733 parent_cls = self.get_class(parent_name) 734 if parent_cls is None: 735 break 736 cur_cls = self.get_class(parent_name) 737 return None 738 739 def get_types(self, list): 740 """ Return a dictionary mapping data types to analyzed values. """ 741 for cls in self.typedefs: 742 cls.get_types(list) 743 744 for cls in self.classes: 745 cls.get_types(list) 746 747 def get_alias_translation(self, alias): 748 """ Return a translation of alias to value based on typedef 749 statements. """ 750 for cls in self.typedefs: 751 if cls.alias == alias: 752 return cls.value 753 return None 754 755 def get_analysis(self, value, named=True): 756 """ Return an analysis of the value based the header file context. """ 757 return obj_analysis([self], value, named) 758 759 def get_defined_structs(self): 760 """ Return a list of already defined structure names. """ 761 return [ 762 'cef_print_info_t', 'cef_window_info_t', 'cef_base_ref_counted_t', 763 'cef_base_scoped_t' 764 ] 765 766 def get_capi_translations(self): 767 """ Return a dictionary that maps C++ terminology to C API terminology. 768 """ 769 # strings that will be changed in C++ comments 770 map = { 771 'class': 'structure', 772 'Class': 'Structure', 773 'interface': 'structure', 774 'Interface': 'Structure', 775 'true': 'true (1)', 776 'false': 'false (0)', 777 'empty': 'NULL', 778 'method': 'function' 779 } 780 781 # add mappings for all classes and functions 782 funcs = self.get_funcs() 783 for func in funcs: 784 map[func.get_name() + '()'] = func.get_capi_name() + '()' 785 786 classes = self.get_classes() 787 for cls in classes: 788 map[cls.get_name()] = cls.get_capi_name() 789 790 funcs = cls.get_virtual_funcs() 791 for func in funcs: 792 map[func.get_name() + '()'] = func.get_capi_name() + '()' 793 794 funcs = cls.get_static_funcs() 795 for func in funcs: 796 map[func.get_name() + '()'] = func.get_capi_name() + '()' 797 798 return map 799 800 801class obj_class: 802 """ Class representing a C++ class. """ 803 804 def __init__(self, parent, filename, attrib, name, parent_name, body, comment, 805 includes, forward_declares): 806 if not isinstance(parent, obj_header): 807 raise Exception('Invalid parent object type') 808 809 self.parent = parent 810 self.filename = filename 811 self.attribs = str_to_dict(attrib) 812 self.name = name 813 self.parent_name = parent_name 814 self.comment = comment 815 self.includes = includes 816 self.forward_declares = forward_declares 817 818 # extract typedefs 819 p = re.compile( 820 '\n' + _cre_space + 'typedef' + _cre_space + _cre_typedef + ';', 821 re.MULTILINE | re.DOTALL) 822 list = p.findall(body) 823 824 # build the typedef objects 825 self.typedefs = [] 826 for value in list: 827 pos = value.rfind(' ') 828 if pos < 0: 829 raise Exception('Invalid typedef: ' + value) 830 alias = value[pos + 1:].strip() 831 value = value[:pos].strip() 832 self.typedefs.append(obj_typedef(self, filename, value, alias)) 833 834 # extract static functions 835 p = re.compile('\n' + _cre_space + _cre_attrib + '\n' + _cre_space + 836 'static' + _cre_space + _cre_func + '\((.*?)\)', 837 re.MULTILINE | re.DOTALL) 838 list = p.findall(body) 839 840 # build the static function objects 841 self.staticfuncs = [] 842 for attrib, retval, argval in list: 843 comment = get_comment(body, retval + '(' + argval + ')') 844 validate_comment(filename, retval, comment) 845 self.staticfuncs.append( 846 obj_function_static(self, attrib, retval, argval, comment)) 847 848 # extract virtual functions 849 p = re.compile( 850 '\n' + _cre_space + _cre_attrib + '\n' + _cre_space + 'virtual' + 851 _cre_space + _cre_func + '\((.*?)\)' + _cre_vfmod, 852 re.MULTILINE | re.DOTALL) 853 list = p.findall(body) 854 855 # build the virtual function objects 856 self.virtualfuncs = [] 857 for attrib, retval, argval, vfmod in list: 858 comment = get_comment(body, retval + '(' + argval + ')') 859 validate_comment(filename, retval, comment) 860 self.virtualfuncs.append( 861 obj_function_virtual(self, attrib, retval, argval, comment, 862 vfmod.strip())) 863 864 def __repr__(self): 865 result = '/* ' + dict_to_str( 866 self.attribs) + ' */ class ' + self.name + "\n{" 867 868 if len(self.typedefs) > 0: 869 result += "\n\t" 870 strlist = [] 871 for cls in self.typedefs: 872 strlist.append(str(cls)) 873 result += "\n\t".join(strlist) 874 875 if len(self.staticfuncs) > 0: 876 result += "\n\t" 877 strlist = [] 878 for cls in self.staticfuncs: 879 strlist.append(str(cls)) 880 result += "\n\t".join(strlist) 881 882 if len(self.virtualfuncs) > 0: 883 result += "\n\t" 884 strlist = [] 885 for cls in self.virtualfuncs: 886 strlist.append(str(cls)) 887 result += "\n\t".join(strlist) 888 889 result += "\n};\n" 890 return result 891 892 def get_file_name(self): 893 """ Return the C++ header file name. Includes the directory component, 894 if any. """ 895 return self.filename 896 897 def get_capi_file_name(self): 898 """ Return the CAPI header file name. Includes the directory component, 899 if any. """ 900 return get_capi_file_name(self.filename) 901 902 def get_file_directory(self): 903 """ Return the file directory component, if any. """ 904 pos = self.filename.rfind('/') 905 if pos >= 0: 906 return self.filename[:pos] 907 return None 908 909 def get_name(self): 910 """ Return the class name. """ 911 return self.name 912 913 def get_capi_name(self): 914 """ Return the CAPI structure name for this class. """ 915 return get_capi_name(self.name, True) 916 917 def get_parent_name(self): 918 """ Return the parent class name. """ 919 return self.parent_name 920 921 def get_parent_capi_name(self): 922 """ Return the CAPI structure name for the parent class. """ 923 return get_capi_name(self.parent_name, True) 924 925 def has_parent(self, parent_name): 926 """ Returns true if this class has the specified class anywhere in its 927 inheritance hierarchy. """ 928 # Every class has a known base class as the top-most parent. 929 if is_base_class(parent_name) or parent_name == self.parent_name: 930 return True 931 if is_base_class(self.parent_name): 932 return False 933 934 cur_cls = self.parent.get_class(self.parent_name) 935 while True: 936 cur_parent_name = cur_cls.get_parent_name() 937 if is_base_class(cur_parent_name): 938 break 939 elif cur_parent_name == parent_name: 940 return True 941 cur_cls = self.parent.get_class(cur_parent_name) 942 943 return False 944 945 def get_comment(self): 946 """ Return the class comment as an array of lines. """ 947 return self.comment 948 949 def get_includes(self): 950 """ Return the list of classes that are included from this class' 951 header file. """ 952 return self.includes 953 954 def get_forward_declares(self): 955 """ Return the list of classes that are forward declared for this 956 class. """ 957 return self.forward_declares 958 959 def get_attribs(self): 960 """ Return all attributes as a dictionary. """ 961 return self.attribs 962 963 def has_attrib(self, name): 964 """ Return true if the specified attribute exists. """ 965 return name in self.attribs 966 967 def get_attrib(self, name): 968 """ Return the first or only value for specified attribute. """ 969 if name in self.attribs: 970 if isinstance(self.attribs[name], list): 971 # the value is a list 972 return self.attribs[name][0] 973 else: 974 # the value is a string 975 return self.attribs[name] 976 return None 977 978 def get_attrib_list(self, name): 979 """ Return all values for specified attribute as a list. """ 980 if name in self.attribs: 981 if isinstance(self.attribs[name], list): 982 # the value is already a list 983 return self.attribs[name] 984 else: 985 # convert the value to a list 986 return [self.attribs[name]] 987 return None 988 989 def get_typedefs(self): 990 """ Return the array of typedef objects. """ 991 return self.typedefs 992 993 def has_typedef_alias(self, alias): 994 """ Returns true if the specified typedef alias is defined in the scope 995 of this class declaration. """ 996 for typedef in self.typedefs: 997 if typedef.get_alias() == alias: 998 return True 999 return False 1000 1001 def get_static_funcs(self): 1002 """ Return the array of static function objects. """ 1003 return self.staticfuncs 1004 1005 def get_virtual_funcs(self): 1006 """ Return the array of virtual function objects. """ 1007 return self.virtualfuncs 1008 1009 def get_types(self, list): 1010 """ Return a dictionary mapping data types to analyzed values. """ 1011 for cls in self.typedefs: 1012 cls.get_types(list) 1013 1014 for cls in self.staticfuncs: 1015 cls.get_types(list) 1016 1017 for cls in self.virtualfuncs: 1018 cls.get_types(list) 1019 1020 def get_alias_translation(self, alias): 1021 for cls in self.typedefs: 1022 if cls.alias == alias: 1023 return cls.value 1024 return None 1025 1026 def get_analysis(self, value, named=True): 1027 """ Return an analysis of the value based on the class definition 1028 context. 1029 """ 1030 return obj_analysis([self, self.parent], value, named) 1031 1032 def is_webview_side(self): 1033 """ Returns true if the class is implemented by the library. """ 1034 return self.attribs['source'] == 'webview' 1035 1036 def is_webcore_side(self): 1037 """ Returns true if the class is implemented by the client. """ 1038 return self.attribs['source'] == 'webcore' 1039 1040 1041class obj_typedef: 1042 """ Class representing a typedef statement. """ 1043 1044 def __init__(self, parent, filename, value, alias): 1045 if not isinstance(parent, obj_header) \ 1046 and not isinstance(parent, obj_class): 1047 raise Exception('Invalid parent object type') 1048 1049 self.parent = parent 1050 self.filename = filename 1051 self.alias = alias 1052 self.value = self.parent.get_analysis(value, False) 1053 1054 def __repr__(self): 1055 return 'typedef ' + self.value.get_type() + ' ' + self.alias + ';' 1056 1057 def get_file_name(self): 1058 """ Return the C++ header file name. """ 1059 return self.filename 1060 1061 def get_capi_file_name(self): 1062 """ Return the CAPI header file name. """ 1063 return get_capi_file_name(self.filename) 1064 1065 def get_alias(self): 1066 """ Return the alias. """ 1067 return self.alias 1068 1069 def get_value(self): 1070 """ Return an analysis of the value based on the class or header file 1071 definition context. 1072 """ 1073 return self.value 1074 1075 def get_types(self, list): 1076 """ Return a dictionary mapping data types to analyzed values. """ 1077 name = self.value.get_type() 1078 if not name in list: 1079 list[name] = self.value 1080 1081 1082class obj_function: 1083 """ Class representing a function. """ 1084 1085 def __init__(self, parent, filename, attrib, retval, argval, comment): 1086 self.parent = parent 1087 self.filename = filename 1088 self.attribs = str_to_dict(attrib) 1089 self.retval = obj_argument(self, retval) 1090 self.name = self.retval.remove_name() 1091 self.comment = comment 1092 1093 # build the argument objects 1094 self.arguments = [] 1095 arglist = argval.split(',') 1096 argindex = 0 1097 while argindex < len(arglist): 1098 arg = arglist[argindex] 1099 if arg.find('<') >= 0 and arg.find('>') == -1: 1100 # We've split inside of a template type declaration. Join the 1101 # next argument with this argument. 1102 argindex += 1 1103 arg += ',' + arglist[argindex] 1104 1105 arg = arg.strip() 1106 if len(arg) > 0: 1107 argument = obj_argument(self, arg) 1108 if argument.needs_attrib_count_func() and \ 1109 argument.get_attrib_count_func() is None: 1110 raise Exception("A 'count_func' attribute is required "+ \ 1111 "for the '"+argument.get_name()+ \ 1112 "' parameter to "+self.get_qualified_name()) 1113 self.arguments.append(argument) 1114 1115 argindex += 1 1116 1117 if self.retval.needs_attrib_default_retval() and \ 1118 self.retval.get_attrib_default_retval() is None: 1119 raise Exception("A 'default_retval' attribute is required for "+ \ 1120 self.get_qualified_name()) 1121 1122 def __repr__(self): 1123 return '/* ' + dict_to_str(self.attribs) + ' */ ' + self.get_cpp_proto() 1124 1125 def get_file_name(self): 1126 """ Return the C++ header file name. """ 1127 return self.filename 1128 1129 def get_capi_file_name(self): 1130 """ Return the CAPI header file name. """ 1131 return get_capi_file_name(self.filename) 1132 1133 def get_name(self): 1134 """ Return the function name. """ 1135 return self.name 1136 1137 def get_qualified_name(self): 1138 """ Return the fully qualified function name. """ 1139 if isinstance(self.parent, obj_header): 1140 # global function 1141 return self.name 1142 else: 1143 # member function 1144 return self.parent.get_name() + '::' + self.name 1145 1146 def get_capi_name(self, prefix=None): 1147 """ Return the CAPI function name. """ 1148 if 'capi_name' in self.attribs: 1149 return self.attribs['capi_name'] 1150 return get_capi_name(self.name, False, prefix) 1151 1152 def get_comment(self): 1153 """ Return the function comment as an array of lines. """ 1154 return self.comment 1155 1156 def get_attribs(self): 1157 """ Return all attributes as a dictionary. """ 1158 return self.attribs 1159 1160 def has_attrib(self, name): 1161 """ Return true if the specified attribute exists. """ 1162 return name in self.attribs 1163 1164 def get_attrib(self, name): 1165 """ Return the first or only value for specified attribute. """ 1166 if name in self.attribs: 1167 if isinstance(self.attribs[name], list): 1168 # the value is a list 1169 return self.attribs[name][0] 1170 else: 1171 # the value is a string 1172 return self.attribs[name] 1173 return None 1174 1175 def get_attrib_list(self, name): 1176 """ Return all values for specified attribute as a list. """ 1177 if name in self.attribs: 1178 if isinstance(self.attribs[name], list): 1179 # the value is already a list 1180 return self.attribs[name] 1181 else: 1182 # convert the value to a list 1183 return [self.attribs[name]] 1184 return None 1185 1186 def get_retval(self): 1187 """ Return the return value object. """ 1188 return self.retval 1189 1190 def get_arguments(self): 1191 """ Return the argument array. """ 1192 return self.arguments 1193 1194 def get_types(self, list): 1195 """ Return a dictionary mapping data types to analyzed values. """ 1196 for cls in self.arguments: 1197 cls.get_types(list) 1198 1199 def get_capi_parts(self, defined_structs=[], isimpl=False, prefix=None): 1200 """ Return the parts of the C API function definition. """ 1201 retval = '' 1202 dict = self.retval.get_type().get_capi(defined_structs) 1203 if dict['format'] == 'single': 1204 retval = dict['value'] 1205 1206 name = self.get_capi_name(prefix) 1207 args = [] 1208 1209 if isinstance(self, obj_function_virtual): 1210 # virtual functions get themselves as the first argument 1211 str = 'struct _' + self.parent.get_capi_name() + '* self' 1212 if isinstance(self, obj_function_virtual) and self.is_const(): 1213 # const virtual functions get const self pointers 1214 str = 'const ' + str 1215 args.append(str) 1216 elif not isimpl and len(self.arguments) == 0: 1217 args.append('void') 1218 1219 if len(self.arguments) > 0: 1220 for cls in self.arguments: 1221 type = cls.get_type() 1222 dict = type.get_capi(defined_structs) 1223 if dict['format'] == 'single': 1224 args.append(dict['value']) 1225 elif dict['format'] == 'multi-arg': 1226 # add an additional argument for the size of the array 1227 type_name = type.get_name() 1228 if type.is_const(): 1229 # for const arrays pass the size argument by value 1230 args.append('size_t ' + type_name + 'Count') 1231 else: 1232 # for non-const arrays pass the size argument by address 1233 args.append('size_t* ' + type_name + 'Count') 1234 args.append(dict['value']) 1235 1236 return {'retval': retval, 'name': name, 'args': args} 1237 1238 def get_capi_proto(self, defined_structs=[], suffix="", isimpl=False, prefix=None): 1239 """ Return the prototype of the C API function. """ 1240 parts = self.get_capi_parts(defined_structs, isimpl, prefix) 1241 result = parts['retval']+' '+parts['name'] + suffix + \ 1242 '('+', '.join(parts['args'])+')' 1243 return result 1244 1245 def get_cpp_parts(self, isimpl=False): 1246 """ Return the parts of the C++ function definition. """ 1247 retval = str(self.retval) 1248 name = self.name 1249 1250 args = [] 1251 if len(self.arguments) > 0: 1252 for cls in self.arguments: 1253 args.append(str(cls)) 1254 1255 if isimpl and isinstance(self, obj_function_virtual): 1256 # enumeration return values must be qualified with the class name 1257 # if the type is defined in the class declaration scope. 1258 type = self.get_retval().get_type() 1259 if type.is_result_struct() and type.is_result_struct_enum() and \ 1260 self.parent.has_typedef_alias(retval): 1261 retval = self.parent.get_name() + '::' + retval 1262 1263 return {'retval': retval, 'name': name, 'args': args} 1264 1265 def get_cpp_proto(self, classname=None): 1266 """ Return the prototype of the C++ function. """ 1267 parts = self.get_cpp_parts() 1268 result = parts['retval'] + ' ' 1269 if not classname is None: 1270 result += classname + '::' 1271 result += parts['name'] + '(' + ', '.join(parts['args']) + ')' 1272 if isinstance(self, obj_function_virtual) and self.is_const(): 1273 result += ' const' 1274 return result 1275 1276 def is_same_side(self, other_class_name): 1277 """ Returns true if this function is on the same side (library or 1278 client) and the specified class. """ 1279 if isinstance(self.parent, obj_class): 1280 # this function is part of a class 1281 this_is_webview_side = self.parent.is_webview_side() 1282 header = self.parent.parent 1283 else: 1284 # this function is global 1285 this_is_webview_side = True 1286 header = self.parent 1287 1288 if is_base_class(other_class_name): 1289 other_is_webview_side = False 1290 else: 1291 other_class = header.get_class(other_class_name) 1292 if other_class is None: 1293 raise Exception('Unknown class: ' + other_class_name) 1294 other_is_webview_side = other_class.is_webview_side() 1295 1296 return other_is_webview_side == this_is_webview_side 1297 1298 1299class obj_function_static(obj_function): 1300 """ Class representing a static function. """ 1301 1302 def __init__(self, parent, attrib, retval, argval, comment): 1303 if not isinstance(parent, obj_class): 1304 raise Exception('Invalid parent object type') 1305 obj_function.__init__(self, parent, parent.filename, attrib, retval, argval, 1306 comment) 1307 1308 def __repr__(self): 1309 return 'static ' + obj_function.__repr__(self) + ';' 1310 1311 def get_capi_name(self, prefix=None): 1312 """ Return the CAPI function name. """ 1313 if prefix is None: 1314 # by default static functions are prefixed with the class name 1315 prefix = get_capi_name(self.parent.get_name(), False) 1316 return obj_function.get_capi_name(self, prefix) 1317 1318 1319class obj_function_virtual(obj_function): 1320 """ Class representing a virtual function. """ 1321 1322 def __init__(self, parent, attrib, retval, argval, comment, vfmod): 1323 if not isinstance(parent, obj_class): 1324 raise Exception('Invalid parent object type') 1325 obj_function.__init__(self, parent, parent.filename, attrib, retval, argval, 1326 comment) 1327 if vfmod == 'const': 1328 self.isconst = True 1329 else: 1330 self.isconst = False 1331 1332 def __repr__(self): 1333 return 'virtual ' + obj_function.__repr__(self) + ';' 1334 1335 def is_const(self): 1336 """ Returns true if the method declaration is const. """ 1337 return self.isconst 1338 1339 1340class obj_argument: 1341 """ Class representing a function argument. """ 1342 1343 def __init__(self, parent, argval): 1344 if not isinstance(parent, obj_function): 1345 raise Exception('Invalid parent object type') 1346 1347 self.parent = parent 1348 self.type = self.parent.parent.get_analysis(argval) 1349 1350 def __repr__(self): 1351 result = '' 1352 if self.type.is_const(): 1353 result += 'const ' 1354 result += self.type.get_type() 1355 if self.type.is_byref(): 1356 result += '&' 1357 elif self.type.is_byaddr(): 1358 result += '*' 1359 if self.type.has_name(): 1360 result += ' ' + self.type.get_name() 1361 return result 1362 1363 def get_name(self): 1364 """ Return the name for this argument. """ 1365 return self.type.get_name() 1366 1367 def remove_name(self): 1368 """ Remove and return the name value. """ 1369 name = self.type.get_name() 1370 self.type.name = None 1371 return name 1372 1373 def get_type(self): 1374 """ Return an analysis of the argument type based on the class 1375 definition context. 1376 """ 1377 return self.type 1378 1379 def get_types(self, list): 1380 """ Return a dictionary mapping data types to analyzed values. """ 1381 name = self.type.get_type() 1382 if not name in list: 1383 list[name] = self.type 1384 1385 def get_raw_type(self): 1386 result = '' 1387 if self.type.is_const(): 1388 result += 'const ' 1389 result += self.type.get_type() 1390 if self.type.is_byref(): 1391 result += '&' 1392 elif self.type.is_byaddr(): 1393 result += '*' 1394 return result 1395 1396 def needs_attrib_count_func(self): 1397 """ Returns true if this argument requires a 'count_func' attribute. """ 1398 # A 'count_func' attribute is required for non-const non-string vector 1399 # attribute types 1400 return self.type.has_name() and \ 1401 self.type.is_result_vector() and \ 1402 not self.type.is_result_vector_string() and \ 1403 not self.type.is_const() 1404 1405 def get_attrib_count_func(self): 1406 """ Returns the count function for this argument. """ 1407 # The 'count_func' attribute value format is name:function 1408 if not self.parent.has_attrib('count_func'): 1409 return None 1410 name = self.type.get_name() 1411 vals = self.parent.get_attrib_list('count_func') 1412 for val in vals: 1413 parts = val.split(':') 1414 if len(parts) != 2: 1415 raise Exception("Invalid 'count_func' attribute value for "+ \ 1416 self.parent.get_qualified_name()+': '+val) 1417 if parts[0].strip() == name: 1418 return parts[1].strip() 1419 return None 1420 1421 def needs_attrib_default_retval(self): 1422 """ Returns true if this argument requires a 'default_retval' attribute. 1423 """ 1424 # A 'default_retval' attribute is required for enumeration return value 1425 # types. 1426 return not self.type.has_name() and \ 1427 self.type.is_result_struct() and \ 1428 self.type.is_result_struct_enum() 1429 1430 def get_attrib_default_retval(self): 1431 """ Returns the defualt return value for this argument. """ 1432 return self.parent.get_attrib('default_retval') 1433 1434 def get_arg_type(self): 1435 """ Returns the argument type as defined in translator.README.txt. """ 1436 if not self.type.has_name(): 1437 raise Exception('Cannot be called for retval types') 1438 1439 # simple or enumeration type 1440 if (self.type.is_result_simple() and \ 1441 self.type.get_type() != 'bool') or \ 1442 (self.type.is_result_struct() and \ 1443 self.type.is_result_struct_enum()): 1444 if self.type.is_byref(): 1445 if self.type.is_const(): 1446 return 'simple_byref_const' 1447 return 'simple_byref' 1448 elif self.type.is_byaddr(): 1449 return 'simple_byaddr' 1450 return 'simple_byval' 1451 1452 # boolean type 1453 if self.type.get_type() == 'bool': 1454 if self.type.is_byref(): 1455 return 'bool_byref' 1456 elif self.type.is_byaddr(): 1457 return 'bool_byaddr' 1458 return 'bool_byval' 1459 1460 # structure type 1461 if self.type.is_result_struct() and self.type.is_byref(): 1462 if self.type.is_const(): 1463 return 'struct_byref_const' 1464 return 'struct_byref' 1465 1466 # string type 1467 if self.type.is_result_string() and self.type.is_byref(): 1468 if self.type.is_const(): 1469 return 'string_byref_const' 1470 return 'string_byref' 1471 1472 # *ptr type 1473 if self.type.is_result_ptr(): 1474 prefix = self.type.get_result_ptr_type_prefix() 1475 same_side = self.parent.is_same_side(self.type.get_ptr_type()) 1476 if self.type.is_byref(): 1477 if same_side: 1478 return prefix + 'ptr_same_byref' 1479 return prefix + 'ptr_diff_byref' 1480 if same_side: 1481 return prefix + 'ptr_same' 1482 return prefix + 'ptr_diff' 1483 1484 if self.type.is_result_vector(): 1485 # all vector types must be passed by reference 1486 if not self.type.is_byref(): 1487 return 'invalid' 1488 1489 if self.type.is_result_vector_string(): 1490 # string vector type 1491 if self.type.is_const(): 1492 return 'string_vec_byref_const' 1493 return 'string_vec_byref' 1494 1495 if self.type.is_result_vector_simple(): 1496 if self.type.get_vector_type() != 'bool': 1497 # simple/enumeration vector types 1498 if self.type.is_const(): 1499 return 'simple_vec_byref_const' 1500 return 'simple_vec_byref' 1501 1502 # boolean vector types 1503 if self.type.is_const(): 1504 return 'bool_vec_byref_const' 1505 return 'bool_vec_byref' 1506 1507 if self.type.is_result_vector_ptr(): 1508 # *ptr vector types 1509 prefix = self.type.get_result_vector_ptr_type_prefix() 1510 same_side = self.parent.is_same_side(self.type.get_ptr_type()) 1511 if self.type.is_const(): 1512 if same_side: 1513 return prefix + 'ptr_vec_same_byref_const' 1514 return prefix + 'ptr_vec_diff_byref_const' 1515 if same_side: 1516 return prefix + 'ptr_vec_same_byref' 1517 return prefix + 'ptr_vec_diff_byref' 1518 1519 # string single map type 1520 if self.type.is_result_map_single(): 1521 if not self.type.is_byref(): 1522 return 'invalid' 1523 if self.type.is_const(): 1524 return 'string_map_single_byref_const' 1525 return 'string_map_single_byref' 1526 1527 # string multi map type 1528 if self.type.is_result_map_multi(): 1529 if not self.type.is_byref(): 1530 return 'invalid' 1531 if self.type.is_const(): 1532 return 'string_map_multi_byref_const' 1533 return 'string_map_multi_byref' 1534 1535 return 'invalid' 1536 1537 def get_retval_type(self): 1538 """ Returns the retval type as defined in translator.README.txt. """ 1539 if self.type.has_name(): 1540 raise Exception('Cannot be called for argument types') 1541 1542 if check_arg_type_is_struct(self.type.get_type()): 1543 return self.type.get_type() 1544 1545 if self.type.get_type() == 'void' and self.type.is_byaddr(): 1546 return "void*" 1547 1548 if self.type.get_type() == 'uint8_t' and self.type.is_byaddr(): 1549 return "uint8_t*" 1550 1551 if self.type.get_type() == 'uint32_t' and self.type.is_byaddr(): 1552 return "uint32_t*" 1553 1554 if self.type.get_type() == 'char' and self.type.is_byaddr(): 1555 return "char*" 1556 1557 # unsupported modifiers 1558 if self.type.is_const() or self.type.is_byref() or \ 1559 self.type.is_byaddr(): 1560 return 'invalid' 1561 1562 # void types don't have a return value 1563 if self.type.get_type() == 'void': 1564 return 'none' 1565 1566 if (self.type.is_result_simple() and \ 1567 self.type.get_type() != 'bool') or \ 1568 (self.type.is_result_struct() and self.type.is_result_struct_enum()): 1569 return 'simple' 1570 1571 if self.type.get_type() == 'bool': 1572 return 'bool' 1573 1574 if self.type.is_result_string(): 1575 return 'string' 1576 1577 if self.type.is_result_ptr(): 1578 prefix = self.type.get_result_ptr_type_prefix() 1579 if self.parent.is_same_side(self.type.get_ptr_type()): 1580 return prefix + 'ptr_same' 1581 else: 1582 return prefix + 'ptr_diff' 1583 1584 return 'invalid' 1585 1586 def get_retval_default(self, for_capi): 1587 """ Returns the default return value based on the retval type. """ 1588 # start with the default retval attribute, if any. 1589 retval = self.get_attrib_default_retval() 1590 if not retval is None: 1591 if for_capi: 1592 # apply any appropriate C API translations. 1593 if retval == 'true': 1594 return '1' 1595 if retval == 'false': 1596 return '0' 1597 return retval 1598 1599 # next look at the retval type value. 1600 type = self.get_retval_type() 1601 if type == 'simple' or check_arg_type_is_struct(type): 1602 return self.get_type().get_result_simple_default() 1603 elif type == 'bool': 1604 return 'false' 1605 elif type == 'string': 1606 if for_capi: 1607 return 'NULL' 1608 return 'CefString()' 1609 elif type == 'refptr_same' or type == 'refptr_diff' or \ 1610 type == 'rawptr_same' or type == 'rawptr_diff' or type == 'void*' or \ 1611 type == 'uint8_t*' or type == 'uint32_t*' or type == 'char*': 1612 if for_capi: 1613 return 'NULL' 1614 return 'nullptr' 1615 elif type == 'ownptr_same' or type == 'ownptr_diff': 1616 if for_capi: 1617 return 'NULL' 1618 return 'CefOwnPtr<' + self.type.get_ptr_type() + '>()' 1619 1620 return '' 1621 1622 1623class obj_analysis: 1624 """ Class representing an analysis of a data type value. """ 1625 1626 def __init__(self, scopelist, value, named): 1627 self.value = value 1628 self.result_type = 'unknown' 1629 self.result_value = None 1630 self.result_default = None 1631 self.ptr_type = None 1632 1633 # parse the argument string 1634 partlist = value.strip().split() 1635 1636 if named: 1637 # extract the name value 1638 self.name = partlist[-1] 1639 del partlist[-1] 1640 else: 1641 self.name = None 1642 1643 if len(partlist) == 0: 1644 raise Exception('Invalid argument value: ' + value) 1645 1646 # check const status 1647 if partlist[0] == 'const': 1648 self.isconst = True 1649 del partlist[0] 1650 else: 1651 self.isconst = False 1652 1653 if len(partlist) == 0: 1654 raise Exception('Invalid argument value: ' + value) 1655 1656 # combine the data type 1657 self.type = ' '.join(partlist) 1658 1659 # extract the last character of the data type 1660 endchar = self.name[0] 1661 1662 # check if the value is passed by reference 1663 if endchar == '&': 1664 self.isbyref = True 1665 self.name = self.name[1:] 1666 else: 1667 self.isbyref = False 1668 1669 # check if the value is passed by address 1670 if endchar == '*': 1671 self.isbyaddr = True 1672 self.name = self.name[1:] 1673 else: 1674 self.isbyaddr = False 1675 1676 # see if the value is directly identifiable 1677 if self._check_advanced(self.type): 1678 return 1679 1680 # not identifiable, so look it up 1681 translation = None 1682 for scope in scopelist: 1683 if not isinstance(scope, obj_header) \ 1684 and not isinstance(scope, obj_class): 1685 raise Exception('Invalid scope object type') 1686 translation = scope.get_alias_translation(self.type) 1687 if not translation is None: 1688 break 1689 1690 if translation is None: 1691 raise Exception('Failed to translate type: ' + self.type) 1692 1693 # the translation succeeded so keep the result 1694 self.result_type = translation.result_type 1695 self.result_value = translation.result_value 1696 1697 def _check_advanced(self, value): 1698 # check for vectors 1699 if value.find('std::vector') == 0: 1700 self.result_type = 'vector' 1701 val = value[12:-1].strip() 1702 self.result_value = [self._get_basic(val)] 1703 self.result_value[0]['vector_type'] = val 1704 return True 1705 1706 # check for maps 1707 if value.find('std::map') == 0: 1708 self.result_type = 'map' 1709 vals = value[9:-1].split(',') 1710 if len(vals) == 2: 1711 self.result_value = [ 1712 self._get_basic(vals[0].strip()), 1713 self._get_basic(vals[1].strip()) 1714 ] 1715 return True 1716 1717 # check for multimaps 1718 if value.find('std::multimap') == 0: 1719 self.result_type = 'multimap' 1720 vals = value[14:-1].split(',') 1721 if len(vals) == 2: 1722 self.result_value = [ 1723 self._get_basic(vals[0].strip()), 1724 self._get_basic(vals[1].strip()) 1725 ] 1726 return True 1727 1728 # check for basic types 1729 basic = self._get_basic(value) 1730 if not basic is None: 1731 self.result_type = basic['result_type'] 1732 self.result_value = basic['result_value'] 1733 if 'ptr_type' in basic: 1734 self.ptr_type = basic['ptr_type'] 1735 if 'result_default' in basic: 1736 self.result_default = basic['result_default'] 1737 return True 1738 1739 return False 1740 1741 def _get_basic(self, value): 1742 # check for string values 1743 if value == "CefString": 1744 return {'result_type': 'string', 'result_value': None} 1745 1746 # check for simple direct translations 1747 if value in _simpletypes.keys(): 1748 return { 1749 'result_type': 'simple', 1750 'result_value': _simpletypes[value][0], 1751 'result_default': _simpletypes[value][1], 1752 } 1753 1754 # check if already a C API structure 1755 if value[-2:] == '_t': 1756 return {'result_type': 'structure', 'result_value': value} 1757 1758 # check for CEF reference pointers 1759 p = re.compile('^ArkWebRefPtr<(.*?)>$', re.DOTALL) 1760 list = p.findall(value) 1761 if len(list) == 1: 1762 return { 1763 'result_type': 'refptr', 1764 'result_value': get_capi_name(list[0], True) + '*', 1765 'ptr_type': list[0] 1766 } 1767 1768 # check for CEF owned pointers 1769 p = re.compile('^CefOwnPtr<(.*?)>$', re.DOTALL) 1770 list = p.findall(value) 1771 if len(list) == 1: 1772 return { 1773 'result_type': 'ownptr', 1774 'result_value': get_capi_name(list[0], True) + '*', 1775 'ptr_type': list[0] 1776 } 1777 1778 # check for CEF raw pointers 1779 p = re.compile('^CefRawPtr<(.*?)>$', re.DOTALL) 1780 list = p.findall(value) 1781 if len(list) == 1: 1782 return { 1783 'result_type': 'rawptr', 1784 'result_value': get_capi_name(list[0], True) + '*', 1785 'ptr_type': list[0] 1786 } 1787 1788 # check for CEF structure types 1789 if value[0:3] == 'Cef' and value[-4:] != 'List': 1790 return { 1791 'result_type': 'structure', 1792 'result_value': get_capi_name(value, True) 1793 } 1794 1795 return None 1796 1797 def __repr__(self): 1798 return '(' + self.result_type + ') ' + str(self.result_value) 1799 1800 def has_name(self): 1801 """ Returns true if a name value exists. """ 1802 return (not self.name is None) 1803 1804 def get_name(self): 1805 """ Return the name. """ 1806 return self.name 1807 1808 def get_value(self): 1809 """ Return the C++ value (type + name). """ 1810 return self.value 1811 1812 def get_type(self): 1813 """ Return the C++ type. """ 1814 return self.type 1815 1816 def get_ptr_type(self): 1817 """ Return the C++ class type referenced by a ArkWebRefPtr. """ 1818 if self.is_result_vector() and self.is_result_vector_ptr(): 1819 # return the vector RefPtr type 1820 return self.result_value[0]['ptr_type'] 1821 # return the basic RefPtr type 1822 return self.ptr_type 1823 1824 def get_vector_type(self): 1825 """ Return the C++ class type referenced by a std::vector. """ 1826 if self.is_result_vector(): 1827 return self.result_value[0]['vector_type'] 1828 return None 1829 1830 def is_const(self): 1831 """ Returns true if the argument value is constant. """ 1832 return self.isconst 1833 1834 def is_byref(self): 1835 """ Returns true if the argument is passed by reference. """ 1836 return self.isbyref 1837 1838 def is_byaddr(self): 1839 """ Returns true if the argument is passed by address. """ 1840 return self.isbyaddr 1841 1842 def is_result_simple(self): 1843 """ Returns true if this is a simple argument type. """ 1844 return (self.result_type == 'simple') 1845 1846 def get_result_simple_type_root(self): 1847 """ Return the simple structure or basic type name. """ 1848 return self.result_value 1849 1850 def get_result_simple_type(self): 1851 """ Return the simple type. """ 1852 result = '' 1853 if self.is_const(): 1854 result += 'const ' 1855 result += self.result_value 1856 if self.is_byaddr() or self.is_byref(): 1857 result += '*' 1858 return result 1859 1860 def get_result_simple_default(self): 1861 """ Return the default value fo the basic type. """ 1862 return self.result_default 1863 1864 def is_result_ptr(self): 1865 """ Returns true if this is a *Ptr type. """ 1866 return self.is_result_refptr() or self.is_result_ownptr() or \ 1867 self.is_result_rawptr() 1868 1869 def get_result_ptr_type_root(self): 1870 """ Return the *Ptr type structure name. """ 1871 return self.result_value[:-1] 1872 1873 def get_result_ptr_type(self, defined_structs=[]): 1874 """ Return the *Ptr type. """ 1875 result = self.result_value 1876 if self.is_byref() or self.is_byaddr(): 1877 result += '*' 1878 return result 1879 1880 def get_result_ptr_type_prefix(self): 1881 """ Returns the *Ptr type prefix. """ 1882 if self.is_result_refptr(): 1883 return 'ref' 1884 if self.is_result_ownptr(): 1885 return 'own' 1886 if self.is_result_rawptr(): 1887 return 'raw' 1888 raise Exception('Not a pointer type') 1889 1890 def is_result_refptr(self): 1891 """ Returns true if this is a RefPtr type. """ 1892 return (self.result_type == 'refptr') 1893 1894 def is_result_ownptr(self): 1895 """ Returns true if this is a OwnPtr type. """ 1896 return (self.result_type == 'ownptr') 1897 1898 def is_result_rawptr(self): 1899 """ Returns true if this is a RawPtr type. """ 1900 return (self.result_type == 'rawptr') 1901 1902 def is_result_struct(self): 1903 """ Returns true if this is a structure type. """ 1904 return (self.result_type == 'structure') 1905 1906 def is_result_struct_enum(self): 1907 """ Returns true if this struct type is likely an enumeration. """ 1908 # structure values that are passed by reference or address must be 1909 # structures and not enumerations 1910 if not self.is_byref() and not self.is_byaddr(): 1911 return True 1912 return False 1913 1914 def get_result_struct_type(self, defined_structs=[]): 1915 """ Return the structure or enumeration type. """ 1916 result = '' 1917 is_enum = self.is_result_struct_enum() 1918 if not is_enum: 1919 if self.is_const(): 1920 result += 'const ' 1921 result += self.result_value 1922 if not is_enum: 1923 result += '*' 1924 return result 1925 1926 def is_result_string(self): 1927 """ Returns true if this is a string type. """ 1928 return (self.result_type == 'string') 1929 1930 def get_result_string_type(self): 1931 """ Return the string type. """ 1932 if not self.has_name(): 1933 # Return values are string structs that the user must free. Use 1934 # the name of the structure as a hint. 1935 return 'cef_string_userfree_t' 1936 elif not self.is_const() and (self.is_byref() or self.is_byaddr()): 1937 # Parameters passed by reference or address. Use the normal 1938 # non-const string struct. 1939 return 'cef_string_t*' 1940 # Const parameters use the const string struct. 1941 return 'const cef_string_t*' 1942 1943 def is_result_vector(self): 1944 """ Returns true if this is a vector type. """ 1945 return (self.result_type == 'vector') 1946 1947 def is_result_vector_string(self): 1948 """ Returns true if this is a string vector. """ 1949 return self.result_value[0]['result_type'] == 'string' 1950 1951 def is_result_vector_simple(self): 1952 """ Returns true if this is a string vector. """ 1953 return self.result_value[0]['result_type'] == 'simple' 1954 1955 def is_result_vector_ptr(self): 1956 """ Returns true if this is a *Ptr vector. """ 1957 return self.is_result_vector_refptr() or \ 1958 self.is_result_vector_ownptr() or \ 1959 self.is_result_vector_rawptr() 1960 1961 def get_result_vector_ptr_type_prefix(self): 1962 """ Returns the *Ptr type prefix. """ 1963 if self.is_result_vector_refptr(): 1964 return 'ref' 1965 if self.is_result_vector_ownptr(): 1966 return 'own' 1967 if self.is_result_vector_rawptr(): 1968 return 'raw' 1969 raise Exception('Not a pointer type') 1970 1971 def is_result_vector_refptr(self): 1972 """ Returns true if this is a RefPtr vector. """ 1973 return self.result_value[0]['result_type'] == 'refptr' 1974 1975 def is_result_vector_ownptr(self): 1976 """ Returns true if this is a OwnPtr vector. """ 1977 return self.result_value[0]['result_type'] == 'ownptr' 1978 1979 def is_result_vector_rawptr(self): 1980 """ Returns true if this is a RawPtr vector. """ 1981 return self.result_value[0]['result_type'] == 'rawptr' 1982 1983 def get_result_vector_type_root(self): 1984 """ Return the vector structure or basic type name. """ 1985 return self.result_value[0]['result_value'] 1986 1987 def get_result_vector_type(self, defined_structs=[]): 1988 """ Return the vector type. """ 1989 if not self.has_name(): 1990 raise Exception('Cannot use vector as a return type') 1991 1992 type = self.result_value[0]['result_type'] 1993 value = self.result_value[0]['result_value'] 1994 1995 result = {} 1996 if type == 'string': 1997 result['value'] = 'cef_string_list_t' 1998 result['format'] = 'single' 1999 return result 2000 2001 if type == 'simple': 2002 str = value 2003 if self.is_const(): 2004 str += ' const' 2005 str += '*' 2006 result['value'] = str 2007 elif type == 'refptr' or type == 'ownptr' or type == 'rawptr': 2008 str = value 2009 if self.is_const(): 2010 str += ' const' 2011 str += '*' 2012 result['value'] = str 2013 else: 2014 raise Exception('Unsupported vector type: ' + type) 2015 2016 # vector values must be passed as a value array parameter 2017 # and a size parameter 2018 result['format'] = 'multi-arg' 2019 return result 2020 2021 def is_result_map(self): 2022 """ Returns true if this is a map type. """ 2023 return (self.result_type == 'map' or self.result_type == 'multimap') 2024 2025 def is_result_map_single(self): 2026 """ Returns true if this is a single map type. """ 2027 return (self.result_type == 'map') 2028 2029 def is_result_map_multi(self): 2030 """ Returns true if this is a multi map type. """ 2031 return (self.result_type == 'multimap') 2032 2033 def get_result_map_type(self, defined_structs=[]): 2034 """ Return the map type. """ 2035 if not self.has_name(): 2036 raise Exception('Cannot use map as a return type') 2037 if self.result_value[0]['result_type'] == 'string' \ 2038 and self.result_value[1]['result_type'] == 'string': 2039 if self.result_type == 'map': 2040 return {'value': 'cef_string_map_t', 'format': 'single'} 2041 elif self.result_type == 'multimap': 2042 return {'value': 'cef_string_multimap_t', 'format': 'multi'} 2043 raise Exception('Only mappings of strings to strings are supported') 2044 2045 def get_capi(self, defined_structs=[]): 2046 """ Format the value for the C API. """ 2047 result = '' 2048 format = 'single' 2049 if self.is_result_simple(): 2050 result += self.get_result_simple_type() 2051 elif self.is_result_ptr(): 2052 result += self.get_result_ptr_type(defined_structs) 2053 elif self.is_result_struct(): 2054 result += self.get_result_struct_type(defined_structs) 2055 elif self.is_result_string(): 2056 result += self.get_result_string_type() 2057 elif self.is_result_map(): 2058 resdict = self.get_result_map_type(defined_structs) 2059 if resdict['format'] == 'single' or resdict['format'] == 'multi': 2060 result += resdict['value'] 2061 else: 2062 raise Exception('Unsupported map type') 2063 elif self.is_result_vector(): 2064 resdict = self.get_result_vector_type(defined_structs) 2065 if resdict['format'] != 'single': 2066 format = resdict['format'] 2067 result += resdict['value'] 2068 2069 if self.has_name(): 2070 result += ' ' + self.get_name() 2071 2072 return {'format': format, 'value': result} 2073 2074 2075# test the module 2076if __name__ == "__main__": 2077 import pprint 2078 import sys 2079 2080 # verify that the correct number of command-line arguments are provided 2081 if len(sys.argv) != 2: 2082 sys.stderr.write('Usage: ' + sys.argv[0] + ' <directory>') 2083 sys.exit() 2084 2085 pp = pprint.PrettyPrinter(indent=4) 2086 2087 # create the header object 2088 header = obj_header() 2089 header.add_directory(sys.argv[1]) 2090 2091 # output the type mapping 2092 types = {} 2093 header.get_types(types) 2094 pp.pprint(types) 2095 sys.stdout.write('\n') 2096 2097 # output the parsed C++ data 2098 sys.stdout.write(str(header)) 2099 2100 # output the C API formatted data 2101 defined_names = header.get_defined_structs() 2102 result = '' 2103 2104 # global functions 2105 funcs = header.get_funcs() 2106 if len(funcs) > 0: 2107 for func in funcs: 2108 result += func.get_capi_proto(defined_names, "", True) + ';\n' 2109 result += '\n' 2110 2111 classes = header.get_classes() 2112 for cls in classes: 2113 # virtual functions are inside a structure 2114 result += 'struct ' + cls.get_capi_name() + '\n{\n' 2115 funcs = cls.get_virtual_funcs() 2116 if len(funcs) > 0: 2117 for func in funcs: 2118 result += '\t' + func.get_capi_proto(defined_names, "", True) + ';\n' 2119 result += '}\n\n' 2120 2121 defined_names.append(cls.get_capi_name()) 2122 2123 # static functions become global 2124 funcs = cls.get_static_funcs() 2125 if len(funcs) > 0: 2126 for func in funcs: 2127 result += func.get_capi_proto(defined_names, "", True) + ';\n' 2128 result += '\n' 2129 sys.stdout.write(result) 2130