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