mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2025-01-15 11:26:31 +01:00
260dd0ca24
Adds support for the OnAcceleratedPaint callback. Verified to work on macOS and Windows. Linux support is present but not implemented for cefclient, so it is not verified to work. To test: Run `cefclient --off-screen-rendering-enabled --shared-texture-enabled`
2154 lines
66 KiB
Python
2154 lines
66 KiB
Python
# Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights
|
|
# reserved. Use of this source code is governed by a BSD-style license that
|
|
# can be found in the LICENSE file.
|
|
|
|
from __future__ import absolute_import
|
|
from date_util import *
|
|
from file_util import *
|
|
import os
|
|
import re
|
|
import shutil
|
|
import string
|
|
import sys
|
|
import textwrap
|
|
import time
|
|
|
|
|
|
def notify(msg):
|
|
""" Display a message. """
|
|
sys.stdout.write(' NOTE: ' + msg + '\n')
|
|
|
|
|
|
def wrap_text(text, indent='', maxchars=80, listitem=False):
|
|
""" Wrap the text to the specified number of characters. If
|
|
necessary a line will be broken and wrapped after a word.
|
|
"""
|
|
if listitem:
|
|
initial_indent = indent + '- '
|
|
subsequent_indent = indent + ' '
|
|
else:
|
|
initial_indent = indent
|
|
subsequent_indent = indent
|
|
lines = textwrap.wrap(
|
|
text,
|
|
maxchars,
|
|
initial_indent=initial_indent,
|
|
subsequent_indent=subsequent_indent)
|
|
return '\n'.join(lines) + '\n'
|
|
|
|
|
|
def is_base_class(clsname):
|
|
""" Returns true if |clsname| is a known base (root) class in the object
|
|
hierarchy.
|
|
"""
|
|
return clsname == 'CefBaseRefCounted' or clsname == 'CefBaseScoped'
|
|
|
|
|
|
def get_capi_file_name(cppname):
|
|
""" Convert a C++ header file name to a C API header file name. """
|
|
return cppname[:-2] + '_capi.h'
|
|
|
|
|
|
def get_capi_name(cppname, isclassname, prefix=None):
|
|
""" Convert a C++ CamelCaps name to a C API underscore name. """
|
|
result = ''
|
|
lastchr = ''
|
|
for chr in cppname:
|
|
# add an underscore if the current character is an upper case letter
|
|
# and the last character was a lower case letter
|
|
if len(result) > 0 and not chr.isdigit() \
|
|
and chr.upper() == chr \
|
|
and not lastchr.upper() == lastchr:
|
|
result += '_'
|
|
result += chr.lower()
|
|
lastchr = chr
|
|
|
|
if isclassname:
|
|
result += '_t'
|
|
|
|
if not prefix is None:
|
|
if prefix[0:3] == 'cef':
|
|
# if the prefix name is duplicated in the function name
|
|
# remove that portion of the function name
|
|
subprefix = prefix[3:]
|
|
pos = result.find(subprefix)
|
|
if pos >= 0:
|
|
result = result[0:pos] + result[pos + len(subprefix):]
|
|
result = prefix + '_' + result
|
|
|
|
return result
|
|
|
|
|
|
def get_wrapper_type_enum(cppname):
|
|
""" Returns the wrapper type enumeration value for the specified C++ class
|
|
name. """
|
|
return 'WT_' + get_capi_name(cppname, False)[4:].upper()
|
|
|
|
|
|
def get_prev_line(body, pos):
|
|
""" Retrieve the start and end positions and value for the line immediately
|
|
before the line containing the specified position.
|
|
"""
|
|
end = body.rfind('\n', 0, pos)
|
|
start = body.rfind('\n', 0, end) + 1
|
|
line = body[start:end]
|
|
return {'start': start, 'end': end, 'line': line}
|
|
|
|
|
|
def get_comment(body, name):
|
|
""" Retrieve the comment for a class or function. """
|
|
result = []
|
|
|
|
pos = body.find(name)
|
|
in_block_comment = False
|
|
while pos > 0:
|
|
data = get_prev_line(body, pos)
|
|
line = data['line'].strip()
|
|
pos = data['start']
|
|
if len(line) == 0:
|
|
break
|
|
# single line /*--cef()--*/
|
|
elif line[0:2] == '/*' and line[-2:] == '*/':
|
|
continue
|
|
# start of multi line /*--cef()--*/
|
|
elif in_block_comment and line[0:2] == '/*':
|
|
in_block_comment = False
|
|
continue
|
|
# end of multi line /*--cef()--*/
|
|
elif not in_block_comment and line[-2:] == '*/':
|
|
in_block_comment = True
|
|
continue
|
|
elif in_block_comment:
|
|
continue
|
|
elif line[0:3] == '///':
|
|
# keep the comment line including any leading spaces
|
|
result.append(line[3:])
|
|
else:
|
|
break
|
|
|
|
result.reverse()
|
|
return result
|
|
|
|
|
|
def validate_comment(file, name, comment):
|
|
""" Validate the comment array returned by get_comment(). """
|
|
# Verify that the comment contains beginning and ending '///' as required by
|
|
# Doxygen (the leading '///' from each line will already have been removed by
|
|
# the get_comment() logic).
|
|
if len(comment) < 3 or len(comment[0]) != 0 or len(comment[-1]) != 0:
|
|
raise Exception('Missing or incorrect comment in %s for: %s' % \
|
|
(file, name))
|
|
|
|
|
|
def format_comment(comment, indent, translate_map=None, maxchars=80):
|
|
""" Return the comments array as a formatted string. """
|
|
if not translate_map is None:
|
|
# Replace longest keys first in translation.
|
|
translate_keys = sorted(
|
|
translate_map.keys(), key=lambda item: (-len(item), item))
|
|
|
|
result = ''
|
|
wrapme = ''
|
|
hasemptyline = False
|
|
listitem = False
|
|
for line in comment:
|
|
# if the line starts with a leading space, remove that space
|
|
if not line is None and len(line) > 0 and line[0] == ' ':
|
|
line = line[1:]
|
|
didremovespace = True
|
|
else:
|
|
didremovespace = False
|
|
|
|
if line is None or len(line) == 0 or (line[0] == ' ' and not listitem) \
|
|
or line[0] == '-':
|
|
# the previous paragraph or list item, if any, has ended
|
|
if len(wrapme) > 0:
|
|
if not translate_map is None:
|
|
# apply the translation
|
|
for key in translate_keys:
|
|
wrapme = wrapme.replace(key, translate_map[key])
|
|
# output the previous paragraph
|
|
result += wrap_text(wrapme, indent + '/// ', maxchars, listitem)
|
|
wrapme = ''
|
|
listitem = False
|
|
|
|
if not line is None:
|
|
if len(line) > 0 and line[0] == '-':
|
|
# list item
|
|
listitem = True
|
|
wrapme = line[1:].strip()
|
|
if len(line) > 0 and line[0] == ' ' and listitem:
|
|
# list item continues
|
|
wrapme += line[1:]
|
|
if len(line) == 0 or (line[0] == ' ' and not listitem):
|
|
# blank lines or anything that's further indented should be
|
|
# output as-is
|
|
result += indent + '///'
|
|
if len(line) > 0:
|
|
if didremovespace:
|
|
result += ' ' + line
|
|
else:
|
|
result += line
|
|
result += '\n'
|
|
listitem = False
|
|
else:
|
|
if not listitem:
|
|
# add to the current paragraph
|
|
wrapme += line + ' '
|
|
else:
|
|
# output an empty line
|
|
hasemptyline = True
|
|
result += '\n'
|
|
|
|
if len(wrapme) > 0:
|
|
if not translate_map is None:
|
|
# apply the translation
|
|
for key in translate_map.keys():
|
|
wrapme = wrapme.replace(key, translate_map[key])
|
|
# output the previous paragraph
|
|
result += wrap_text(wrapme, indent + '/// ', maxchars, listitem)
|
|
|
|
if hasemptyline:
|
|
# an empty line means a break between comments, so the comment is
|
|
# probably a section heading and should have an extra line before it
|
|
result = '\n' + result
|
|
return result
|
|
|
|
|
|
def format_translation_changes(old, new):
|
|
""" Return a comment stating what is different between the old and new
|
|
function prototype parts.
|
|
"""
|
|
changed = False
|
|
result = ''
|
|
|
|
# normalize C API attributes
|
|
oldargs = [x.replace('struct _', '') for x in old['args']]
|
|
oldretval = old['retval'].replace('struct _', '')
|
|
newargs = [x.replace('struct _', '') for x in new['args']]
|
|
newretval = new['retval'].replace('struct _', '')
|
|
|
|
# check if the prototype has changed
|
|
oldset = set(oldargs)
|
|
newset = set(newargs)
|
|
if len(oldset.symmetric_difference(newset)) > 0:
|
|
changed = True
|
|
result += '\n // WARNING - CHANGED ATTRIBUTES'
|
|
|
|
# in the implementation set only
|
|
oldonly = oldset.difference(newset)
|
|
for arg in oldonly:
|
|
result += '\n // REMOVED: ' + arg
|
|
|
|
# in the current set only
|
|
newonly = newset.difference(oldset)
|
|
for arg in newonly:
|
|
result += '\n // ADDED: ' + arg
|
|
|
|
# check if the return value has changed
|
|
if oldretval != newretval:
|
|
changed = True
|
|
result += '\n // WARNING - CHANGED RETURN VALUE'+ \
|
|
'\n // WAS: '+old['retval']+ \
|
|
'\n // NOW: '+new['retval']
|
|
|
|
if changed:
|
|
result += '\n #pragma message("Warning: " __FILE__ ": '+new['name']+ \
|
|
' prototype has changed")\n'
|
|
|
|
return result
|
|
|
|
|
|
def format_translation_includes(header, body):
|
|
""" Return the necessary list of includes based on the contents of the
|
|
body.
|
|
"""
|
|
result = ''
|
|
|
|
# <algorithm> required for VS2013.
|
|
if body.find('std::min') > 0 or body.find('std::max') > 0:
|
|
result += '#include <algorithm>\n'
|
|
|
|
if body.find('cef_api_hash(') > 0:
|
|
result += '#include "include/cef_api_hash.h"\n'
|
|
|
|
if body.find('template_util::has_valid_size(') > 0:
|
|
result += '#include "libcef_dll/template_util.h"\n'
|
|
|
|
# identify what CppToC classes are being used
|
|
p = re.compile(r'([A-Za-z0-9_]{1,})CppToC')
|
|
list = sorted(set(p.findall(body)))
|
|
for item in list:
|
|
directory = ''
|
|
if not is_base_class(item):
|
|
cls = header.get_class(item)
|
|
dir = cls.get_file_directory()
|
|
if not dir is None:
|
|
directory = dir + '/'
|
|
result += '#include "libcef_dll/cpptoc/'+directory+ \
|
|
get_capi_name(item[3:], False)+'_cpptoc.h"\n'
|
|
|
|
# identify what CToCpp classes are being used
|
|
p = re.compile(r'([A-Za-z0-9_]{1,})CToCpp')
|
|
list = sorted(set(p.findall(body)))
|
|
for item in list:
|
|
directory = ''
|
|
if not is_base_class(item):
|
|
cls = header.get_class(item)
|
|
dir = cls.get_file_directory()
|
|
if not dir is None:
|
|
directory = dir + '/'
|
|
result += '#include "libcef_dll/ctocpp/'+directory+ \
|
|
get_capi_name(item[3:], False)+'_ctocpp.h"\n'
|
|
|
|
if body.find('shutdown_checker') > 0:
|
|
result += '#include "libcef_dll/shutdown_checker.h"\n'
|
|
|
|
if body.find('transfer_') > 0:
|
|
result += '#include "libcef_dll/transfer_util.h"\n'
|
|
|
|
return result
|
|
|
|
|
|
def str_to_dict(str):
|
|
""" Convert a string to a dictionary. If the same key has multiple values
|
|
the values will be stored in a list. """
|
|
dict = {}
|
|
parts = str.split(',')
|
|
for part in parts:
|
|
part = part.strip()
|
|
if len(part) == 0:
|
|
continue
|
|
sparts = part.split('=')
|
|
if len(sparts) > 2:
|
|
raise Exception('Invalid dictionary pair format: ' + part)
|
|
name = sparts[0].strip()
|
|
if len(sparts) == 2:
|
|
val = sparts[1].strip()
|
|
else:
|
|
val = True
|
|
if name in dict:
|
|
# a value with this name already exists
|
|
curval = dict[name]
|
|
if not isinstance(curval, list):
|
|
# convert the string value to a list
|
|
dict[name] = [curval]
|
|
dict[name].append(val)
|
|
else:
|
|
dict[name] = val
|
|
return dict
|
|
|
|
|
|
def dict_to_str(dict):
|
|
""" Convert a dictionary to a string. """
|
|
str = []
|
|
for name in dict.keys():
|
|
if not isinstance(dict[name], list):
|
|
if dict[name] is True:
|
|
# currently a bool value
|
|
str.append(name)
|
|
else:
|
|
# currently a string value
|
|
str.append(name + '=' + dict[name])
|
|
else:
|
|
# currently a list value
|
|
for val in dict[name]:
|
|
str.append(name + '=' + val)
|
|
return ','.join(str)
|
|
|
|
|
|
# regex for matching comment-formatted attributes
|
|
_cre_attrib = r'/\*--cef\(([A-Za-z0-9_ ,=:\n]{0,})\)--\*/'
|
|
# regex for matching class and function names
|
|
_cre_cfname = r'([A-Za-z0-9_]{1,})'
|
|
# regex for matching class and function names including path separators
|
|
_cre_cfnameorpath = r'([A-Za-z0-9_\/]{1,})'
|
|
# regex for matching typedef value and name combination
|
|
_cre_typedef = r'([A-Za-z0-9_<>:,\*\&\s]{1,})'
|
|
# regex for matching function return value and name combination
|
|
_cre_func = r'([A-Za-z][A-Za-z0-9_<>:,\*\&\s]{1,})'
|
|
# regex for matching virtual function modifiers + arbitrary whitespace
|
|
_cre_vfmod = r'([\sA-Za-z0-9_]{0,})'
|
|
# regex for matching arbitrary whitespace
|
|
_cre_space = r'[\s]{1,}'
|
|
# regex for matching optional virtual keyword
|
|
_cre_virtual = r'(?:[\s]{1,}virtual){0,1}'
|
|
|
|
# Simple translation types. Format is:
|
|
# 'cpp_type' : ['capi_type', 'capi_default_value']
|
|
_simpletypes = {
|
|
'void': ['void', ''],
|
|
'void*': ['void*', 'NULL'],
|
|
'int': ['int', '0'],
|
|
'int16_t': ['int16_t', '0'],
|
|
'uint16_t': ['uint16_t', '0'],
|
|
'int32_t': ['int32_t', '0'],
|
|
'uint32_t': ['uint32_t', '0'],
|
|
'int64_t': ['int64_t', '0'],
|
|
'uint64_t': ['uint64_t', '0'],
|
|
'double': ['double', '0'],
|
|
'float': ['float', '0'],
|
|
'float*': ['float*', 'NULL'],
|
|
'long': ['long', '0'],
|
|
'unsigned long': ['unsigned long', '0'],
|
|
'long long': ['long long', '0'],
|
|
'size_t': ['size_t', '0'],
|
|
'bool': ['int', '0'],
|
|
'char': ['char', '0'],
|
|
'char* const': ['char* const', 'NULL'],
|
|
'cef_color_t': ['cef_color_t', '0'],
|
|
'cef_json_parser_error_t': ['cef_json_parser_error_t', 'JSON_NO_ERROR'],
|
|
'CefAcceleratedPaintInfo': [
|
|
'cef_accelerated_paint_info_t', 'CefAcceleratedPaintInfo()'
|
|
],
|
|
'CefAudioParameters': ['cef_audio_parameters_t', 'CefAudioParameters()'],
|
|
'CefBaseTime': ['cef_basetime_t', 'CefBaseTime()'],
|
|
'CefBoxLayoutSettings': [
|
|
'cef_box_layout_settings_t', 'CefBoxLayoutSettings()'
|
|
],
|
|
'CefCompositionUnderline': [
|
|
'cef_composition_underline_t', 'CefCompositionUnderline()'
|
|
],
|
|
'CefCursorHandle': ['cef_cursor_handle_t', 'kNullCursorHandle'],
|
|
'CefCursorInfo': ['cef_cursor_info_t', 'CefCursorInfo()'],
|
|
'CefDraggableRegion': ['cef_draggable_region_t', 'CefDraggableRegion()'],
|
|
'CefEventHandle': ['cef_event_handle_t', 'kNullEventHandle'],
|
|
'CefInsets': ['cef_insets_t', 'CefInsets()'],
|
|
'CefKeyEvent': ['cef_key_event_t', 'CefKeyEvent()'],
|
|
'CefMainArgs': ['cef_main_args_t', 'CefMainArgs()'],
|
|
'CefMouseEvent': ['cef_mouse_event_t', 'CefMouseEvent()'],
|
|
'CefPoint': ['cef_point_t', 'CefPoint()'],
|
|
'CefPopupFeatures': ['cef_popup_features_t', 'CefPopupFeatures()'],
|
|
'CefRange': ['cef_range_t', 'CefRange()'],
|
|
'CefRect': ['cef_rect_t', 'CefRect()'],
|
|
'CefScreenInfo': ['cef_screen_info_t', 'CefScreenInfo()'],
|
|
'CefSize': ['cef_size_t', 'CefSize()'],
|
|
'CefTouchEvent': ['cef_touch_event_t', 'CefTouchEvent()'],
|
|
'CefTouchHandleState': [
|
|
'cef_touch_handle_state_t', 'CefTouchHandleState()'
|
|
],
|
|
'CefThreadId': ['cef_thread_id_t', 'TID_UI'],
|
|
'CefTime': ['cef_time_t', 'CefTime()'],
|
|
'CefWindowHandle': ['cef_window_handle_t', 'kNullWindowHandle'],
|
|
}
|
|
|
|
|
|
def get_function_impls(content, ident, has_impl=True):
|
|
""" Retrieve the function parts from the specified contents as a set of
|
|
return value, name, arguments and body. Ident must occur somewhere in
|
|
the value.
|
|
"""
|
|
# Remove prefix from methods in CToCpp files.
|
|
content = content.replace('NO_SANITIZE("cfi-icall") ', '')
|
|
content = content.replace('NO_SANITIZE("cfi-icall")\n', '')
|
|
|
|
# extract the functions
|
|
find_regex = r'\n' + _cre_func + r'\((.*?)\)([A-Za-z0-9_\s]{0,})'
|
|
if has_impl:
|
|
find_regex += r'\{(.*?)\n\}'
|
|
else:
|
|
find_regex += r'(;)'
|
|
p = re.compile(find_regex, re.MULTILINE | re.DOTALL)
|
|
list = p.findall(content)
|
|
|
|
# build the function map with the function name as the key
|
|
result = []
|
|
for retval, argval, vfmod, body in list:
|
|
if retval.find(ident) < 0:
|
|
# the identifier was not found
|
|
continue
|
|
|
|
# remove the identifier
|
|
retval = retval.replace(ident, '')
|
|
retval = retval.strip()
|
|
|
|
# Normalize the delimiter.
|
|
retval = retval.replace('\n', ' ')
|
|
|
|
# retrieve the function name
|
|
parts = retval.split(' ')
|
|
name = parts[-1]
|
|
del parts[-1]
|
|
retval = ' '.join(parts)
|
|
|
|
# parse the arguments
|
|
args = []
|
|
if argval != 'void':
|
|
for v in argval.split(','):
|
|
v = v.strip()
|
|
if len(v) > 0:
|
|
args.append(v)
|
|
|
|
result.append({
|
|
'retval': retval.strip(),
|
|
'name': name,
|
|
'args': args,
|
|
'vfmod': vfmod.strip(),
|
|
'body': body if has_impl else '',
|
|
})
|
|
|
|
return result
|
|
|
|
|
|
def get_next_function_impl(existing, name):
|
|
result = None
|
|
for item in existing:
|
|
if item['name'] == name:
|
|
result = item
|
|
existing.remove(item)
|
|
break
|
|
return result
|
|
|
|
|
|
def get_copyright(full=False, translator=True):
|
|
if full:
|
|
result = \
|
|
"""// Copyright (c) $YEAR$ Marshall A. Greenblatt. All rights reserved.
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions are
|
|
// met:
|
|
//
|
|
// * Redistributions of source code must retain the above copyright
|
|
// notice, this list of conditions and the following disclaimer.
|
|
// * Redistributions in binary form must reproduce the above
|
|
// copyright notice, this list of conditions and the following disclaimer
|
|
// in the documentation and/or other materials provided with the
|
|
// distribution.
|
|
// * Neither the name of Google Inc. nor the name Chromium Embedded
|
|
// Framework nor the names of its contributors may be used to endorse
|
|
// or promote products derived from this software without specific prior
|
|
// written permission.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
"""
|
|
else:
|
|
result = \
|
|
"""// Copyright (c) $YEAR$ The Chromium Embedded Framework Authors. All rights
|
|
// reserved. Use of this source code is governed by a BSD-style license that
|
|
// can be found in the LICENSE file.
|
|
"""
|
|
|
|
if translator:
|
|
result += \
|
|
"""//
|
|
// ---------------------------------------------------------------------------
|
|
//
|
|
// This file was generated by the CEF translator tool. If making changes by
|
|
// hand only do so within the body of existing method and function
|
|
// implementations. See the translator.README.txt file in the tools directory
|
|
// for more information.
|
|
//
|
|
// $hash=$$HASH$$$
|
|
//
|
|
|
|
"""
|
|
|
|
# add the copyright year
|
|
return result.replace('$YEAR$', get_year())
|
|
|
|
|
|
class obj_header:
|
|
""" Class representing a C++ header file. """
|
|
|
|
def __init__(self):
|
|
self.filenames = []
|
|
self.typedefs = []
|
|
self.funcs = []
|
|
self.classes = []
|
|
self.root_directory = None
|
|
|
|
def set_root_directory(self, root_directory):
|
|
""" Set the root directory. """
|
|
self.root_directory = root_directory
|
|
|
|
def get_root_directory(self):
|
|
""" Get the root directory. """
|
|
return self.root_directory
|
|
|
|
def add_directory(self, directory, excluded_files=[]):
|
|
""" Add all header files from the specified directory. """
|
|
files = get_files(os.path.join(directory, '*.h'))
|
|
for file in files:
|
|
if len(excluded_files) == 0 or \
|
|
not os.path.split(file)[1] in excluded_files:
|
|
self.add_file(file)
|
|
|
|
def add_file(self, filepath):
|
|
""" Add a header file. """
|
|
|
|
if self.root_directory is None:
|
|
filename = os.path.split(filepath)[1]
|
|
else:
|
|
filename = os.path.relpath(filepath, self.root_directory)
|
|
filename = filename.replace('\\', '/')
|
|
|
|
try:
|
|
# read the input file into memory
|
|
self.add_data(filename, read_file(filepath))
|
|
except Exception:
|
|
print('Exception while parsing %s' % filepath)
|
|
raise
|
|
|
|
def add_data(self, filename, data):
|
|
""" Add header file contents. """
|
|
|
|
added = False
|
|
|
|
# remove space from between template definition end brackets
|
|
data = data.replace("> >", ">>")
|
|
|
|
# extract global typedefs
|
|
p = re.compile(r'\ntypedef' + _cre_space + _cre_typedef + r';',
|
|
re.MULTILINE | re.DOTALL)
|
|
list = p.findall(data)
|
|
if len(list) > 0:
|
|
# build the global typedef objects
|
|
for value in list:
|
|
pos = value.rfind(' ')
|
|
if pos < 0:
|
|
raise Exception('Invalid typedef: ' + value)
|
|
alias = value[pos + 1:].strip()
|
|
value = value[:pos].strip()
|
|
self.typedefs.append(obj_typedef(self, filename, value, alias))
|
|
|
|
# extract global functions
|
|
p = re.compile(r'\n' + _cre_attrib + r'\n' + _cre_func + r'\((.*?)\)',
|
|
re.MULTILINE | re.DOTALL)
|
|
list = p.findall(data)
|
|
if len(list) > 0:
|
|
added = True
|
|
|
|
# build the global function objects
|
|
for attrib, retval, argval in list:
|
|
comment = get_comment(data, retval + '(' + argval + ');')
|
|
validate_comment(filename, retval, comment)
|
|
self.funcs.append(
|
|
obj_function(self, filename, attrib, retval, argval, comment))
|
|
|
|
# extract includes
|
|
p = re.compile(r'\n#include \"include/' + _cre_cfnameorpath + r'.h')
|
|
includes = p.findall(data)
|
|
|
|
# extract forward declarations
|
|
p = re.compile(r'\nclass' + _cre_space + _cre_cfname + r';')
|
|
forward_declares = p.findall(data)
|
|
|
|
# extract empty classes
|
|
p = re.compile(r'\n' + _cre_attrib + r'\nclass' + _cre_space + _cre_cfname +
|
|
_cre_space + r':' + _cre_space + r'public' + _cre_virtual +
|
|
_cre_space + _cre_cfname + _cre_space + r'{};',
|
|
re.MULTILINE | re.DOTALL)
|
|
list = p.findall(data)
|
|
if len(list) > 0:
|
|
added = True
|
|
|
|
# build the class objects
|
|
for attrib, name, parent_name in list:
|
|
# Style may place the ':' on the next line.
|
|
comment = get_comment(data, name + ' :')
|
|
if len(comment) == 0:
|
|
comment = get_comment(data, name + "\n")
|
|
validate_comment(filename, name, comment)
|
|
self.classes.append(
|
|
obj_class(self, filename, attrib, name, parent_name, "", comment,
|
|
includes, forward_declares))
|
|
|
|
# Remove empty classes from |data| so we don't mess up the non-empty
|
|
# class search that follows.
|
|
data = p.sub('', data)
|
|
|
|
# extract classes
|
|
p = re.compile(r'\n' + _cre_attrib + r'\nclass' + _cre_space + _cre_cfname +
|
|
_cre_space + r':' + _cre_space + r'public' + _cre_virtual +
|
|
_cre_space + _cre_cfname + _cre_space + r'{(.*?)\n};',
|
|
re.MULTILINE | re.DOTALL)
|
|
list = p.findall(data)
|
|
if len(list) > 0:
|
|
added = True
|
|
|
|
# build the class objects
|
|
for attrib, name, parent_name, body in list:
|
|
# Style may place the ':' on the next line.
|
|
comment = get_comment(data, name + ' :')
|
|
if len(comment) == 0:
|
|
comment = get_comment(data, name + "\n")
|
|
validate_comment(filename, name, comment)
|
|
self.classes.append(
|
|
obj_class(self, filename, attrib, name, parent_name, body, comment,
|
|
includes, forward_declares))
|
|
|
|
if added:
|
|
# a global function or class was read from the header file
|
|
self.filenames.append(filename)
|
|
|
|
def __repr__(self):
|
|
result = ''
|
|
|
|
if len(self.typedefs) > 0:
|
|
strlist = []
|
|
for cls in self.typedefs:
|
|
strlist.append(str(cls))
|
|
result += "\n".join(strlist) + "\n\n"
|
|
|
|
if len(self.funcs) > 0:
|
|
strlist = []
|
|
for cls in self.funcs:
|
|
strlist.append(str(cls))
|
|
result += "\n".join(strlist) + "\n\n"
|
|
|
|
if len(self.classes) > 0:
|
|
strlist = []
|
|
for cls in self.classes:
|
|
strlist.append(str(cls))
|
|
result += "\n".join(strlist)
|
|
|
|
return result
|
|
|
|
def get_file_names(self):
|
|
""" Return the array of header file names. """
|
|
return self.filenames
|
|
|
|
def get_typedefs(self):
|
|
""" Return the array of typedef objects. """
|
|
return self.typedefs
|
|
|
|
def get_funcs(self, filename=None):
|
|
""" Return the array of function objects. """
|
|
if filename is None:
|
|
return self.funcs
|
|
else:
|
|
# only return the functions in the specified file
|
|
res = []
|
|
for func in self.funcs:
|
|
if func.get_file_name() == filename:
|
|
res.append(func)
|
|
return res
|
|
|
|
def get_classes(self, filename=None):
|
|
""" Return the array of class objects. """
|
|
if filename is None:
|
|
return self.classes
|
|
else:
|
|
# only return the classes in the specified file
|
|
res = []
|
|
for cls in self.classes:
|
|
if cls.get_file_name() == filename:
|
|
res.append(cls)
|
|
return res
|
|
|
|
def get_class(self, classname, defined_structs=None):
|
|
""" Return the specified class or None if not found. """
|
|
for cls in self.classes:
|
|
if cls.get_name() == classname:
|
|
return cls
|
|
elif not defined_structs is None:
|
|
defined_structs.append(cls.get_capi_name())
|
|
return None
|
|
|
|
def get_class_names(self):
|
|
""" Returns the names of all classes in this object. """
|
|
result = []
|
|
for cls in self.classes:
|
|
result.append(cls.get_name())
|
|
return result
|
|
|
|
def get_base_class_name(self, classname):
|
|
""" Returns the base (root) class name for |classname|. """
|
|
cur_cls = self.get_class(classname)
|
|
while True:
|
|
parent_name = cur_cls.get_parent_name()
|
|
if is_base_class(parent_name):
|
|
return parent_name
|
|
else:
|
|
parent_cls = self.get_class(parent_name)
|
|
if parent_cls is None:
|
|
break
|
|
cur_cls = self.get_class(parent_name)
|
|
return None
|
|
|
|
def get_types(self, list):
|
|
""" Return a dictionary mapping data types to analyzed values. """
|
|
for cls in self.typedefs:
|
|
cls.get_types(list)
|
|
|
|
for cls in self.classes:
|
|
cls.get_types(list)
|
|
|
|
def get_alias_translation(self, alias):
|
|
""" Return a translation of alias to value based on typedef
|
|
statements. """
|
|
for cls in self.typedefs:
|
|
if cls.alias == alias:
|
|
return cls.value
|
|
return None
|
|
|
|
def get_analysis(self, value, named=True):
|
|
""" Return an analysis of the value based the header file context. """
|
|
return obj_analysis([self], value, named)
|
|
|
|
def get_defined_structs(self):
|
|
""" Return a list of already defined structure names. """
|
|
return [
|
|
'cef_print_info_t', 'cef_window_info_t', 'cef_base_ref_counted_t',
|
|
'cef_base_scoped_t'
|
|
]
|
|
|
|
def get_capi_translations(self):
|
|
""" Return a dictionary that maps C++ terminology to C API terminology.
|
|
"""
|
|
# strings that will be changed in C++ comments
|
|
map = {
|
|
'class': 'structure',
|
|
'Class': 'Structure',
|
|
'interface': 'structure',
|
|
'Interface': 'Structure',
|
|
'true': 'true (1)',
|
|
'false': 'false (0)',
|
|
'empty': 'NULL',
|
|
'method': 'function'
|
|
}
|
|
|
|
# add mappings for all classes and functions
|
|
funcs = self.get_funcs()
|
|
for func in funcs:
|
|
map[func.get_name() + '()'] = func.get_capi_name() + '()'
|
|
|
|
classes = self.get_classes()
|
|
for cls in classes:
|
|
map[cls.get_name()] = cls.get_capi_name()
|
|
|
|
funcs = cls.get_virtual_funcs()
|
|
for func in funcs:
|
|
map[func.get_name() + '()'] = func.get_capi_name() + '()'
|
|
|
|
funcs = cls.get_static_funcs()
|
|
for func in funcs:
|
|
map[func.get_name() + '()'] = func.get_capi_name() + '()'
|
|
|
|
return map
|
|
|
|
|
|
class obj_class:
|
|
""" Class representing a C++ class. """
|
|
|
|
def __init__(self, parent, filename, attrib, name, parent_name, body, comment,
|
|
includes, forward_declares):
|
|
if not isinstance(parent, obj_header):
|
|
raise Exception('Invalid parent object type')
|
|
|
|
self.parent = parent
|
|
self.filename = filename
|
|
self.attribs = str_to_dict(attrib)
|
|
self.name = name
|
|
self.parent_name = parent_name
|
|
self.comment = comment
|
|
self.includes = includes
|
|
self.forward_declares = forward_declares
|
|
|
|
# extract typedefs
|
|
p = re.compile(
|
|
r'\n' + _cre_space + r'typedef' + _cre_space + _cre_typedef + r';',
|
|
re.MULTILINE | re.DOTALL)
|
|
list = p.findall(body)
|
|
|
|
# build the typedef objects
|
|
self.typedefs = []
|
|
for value in list:
|
|
pos = value.rfind(' ')
|
|
if pos < 0:
|
|
raise Exception('Invalid typedef: ' + value)
|
|
alias = value[pos + 1:].strip()
|
|
value = value[:pos].strip()
|
|
self.typedefs.append(obj_typedef(self, filename, value, alias))
|
|
|
|
# extract static functions
|
|
p = re.compile(r'\n' + _cre_space + _cre_attrib + r'\n' + _cre_space +
|
|
r'static' + _cre_space + _cre_func + r'\((.*?)\)',
|
|
re.MULTILINE | re.DOTALL)
|
|
list = p.findall(body)
|
|
|
|
# build the static function objects
|
|
self.staticfuncs = []
|
|
for attrib, retval, argval in list:
|
|
comment = get_comment(body, retval + '(' + argval + ')')
|
|
validate_comment(filename, retval, comment)
|
|
self.staticfuncs.append(
|
|
obj_function_static(self, attrib, retval, argval, comment))
|
|
|
|
# extract virtual functions
|
|
p = re.compile(
|
|
r'\n' + _cre_space + _cre_attrib + r'\n' + _cre_space + r'virtual' +
|
|
_cre_space + _cre_func + r'\((.*?)\)' + _cre_vfmod,
|
|
re.MULTILINE | re.DOTALL)
|
|
list = p.findall(body)
|
|
|
|
# build the virtual function objects
|
|
self.virtualfuncs = []
|
|
for attrib, retval, argval, vfmod in list:
|
|
comment = get_comment(body, retval + '(' + argval + ')')
|
|
validate_comment(filename, retval, comment)
|
|
self.virtualfuncs.append(
|
|
obj_function_virtual(self, attrib, retval, argval, comment,
|
|
vfmod.strip()))
|
|
|
|
def __repr__(self):
|
|
result = '/* ' + dict_to_str(
|
|
self.attribs) + ' */ class ' + self.name + "\n{"
|
|
|
|
if len(self.typedefs) > 0:
|
|
result += "\n\t"
|
|
strlist = []
|
|
for cls in self.typedefs:
|
|
strlist.append(str(cls))
|
|
result += "\n\t".join(strlist)
|
|
|
|
if len(self.staticfuncs) > 0:
|
|
result += "\n\t"
|
|
strlist = []
|
|
for cls in self.staticfuncs:
|
|
strlist.append(str(cls))
|
|
result += "\n\t".join(strlist)
|
|
|
|
if len(self.virtualfuncs) > 0:
|
|
result += "\n\t"
|
|
strlist = []
|
|
for cls in self.virtualfuncs:
|
|
strlist.append(str(cls))
|
|
result += "\n\t".join(strlist)
|
|
|
|
result += "\n};\n"
|
|
return result
|
|
|
|
def get_file_name(self):
|
|
""" Return the C++ header file name. Includes the directory component,
|
|
if any. """
|
|
return self.filename
|
|
|
|
def get_capi_file_name(self):
|
|
""" Return the CAPI header file name. Includes the directory component,
|
|
if any. """
|
|
return get_capi_file_name(self.filename)
|
|
|
|
def get_file_directory(self):
|
|
""" Return the file directory component, if any. """
|
|
pos = self.filename.rfind('/')
|
|
if pos >= 0:
|
|
return self.filename[:pos]
|
|
return None
|
|
|
|
def get_name(self):
|
|
""" Return the class name. """
|
|
return self.name
|
|
|
|
def get_capi_name(self):
|
|
""" Return the CAPI structure name for this class. """
|
|
return get_capi_name(self.name, True)
|
|
|
|
def get_parent_name(self):
|
|
""" Return the parent class name. """
|
|
return self.parent_name
|
|
|
|
def get_parent_capi_name(self):
|
|
""" Return the CAPI structure name for the parent class. """
|
|
return get_capi_name(self.parent_name, True)
|
|
|
|
def has_parent(self, parent_name):
|
|
""" Returns true if this class has the specified class anywhere in its
|
|
inheritance hierarchy. """
|
|
# Every class has a known base class as the top-most parent.
|
|
if is_base_class(parent_name) or parent_name == self.parent_name:
|
|
return True
|
|
if is_base_class(self.parent_name):
|
|
return False
|
|
|
|
cur_cls = self.parent.get_class(self.parent_name)
|
|
while True:
|
|
cur_parent_name = cur_cls.get_parent_name()
|
|
if is_base_class(cur_parent_name):
|
|
break
|
|
elif cur_parent_name == parent_name:
|
|
return True
|
|
cur_cls = self.parent.get_class(cur_parent_name)
|
|
|
|
return False
|
|
|
|
def get_comment(self):
|
|
""" Return the class comment as an array of lines. """
|
|
return self.comment
|
|
|
|
def get_includes(self):
|
|
""" Return the list of classes that are included from this class'
|
|
header file. """
|
|
return self.includes
|
|
|
|
def get_forward_declares(self):
|
|
""" Return the list of classes that are forward declared for this
|
|
class. """
|
|
return self.forward_declares
|
|
|
|
def get_attribs(self):
|
|
""" Return all attributes as a dictionary. """
|
|
return self.attribs
|
|
|
|
def has_attrib(self, name):
|
|
""" Return true if the specified attribute exists. """
|
|
return name in self.attribs
|
|
|
|
def get_attrib(self, name):
|
|
""" Return the first or only value for specified attribute. """
|
|
if name in self.attribs:
|
|
if isinstance(self.attribs[name], list):
|
|
# the value is a list
|
|
return self.attribs[name][0]
|
|
else:
|
|
# the value is a string
|
|
return self.attribs[name]
|
|
return None
|
|
|
|
def get_attrib_list(self, name):
|
|
""" Return all values for specified attribute as a list. """
|
|
if name in self.attribs:
|
|
if isinstance(self.attribs[name], list):
|
|
# the value is already a list
|
|
return self.attribs[name]
|
|
else:
|
|
# convert the value to a list
|
|
return [self.attribs[name]]
|
|
return None
|
|
|
|
def get_typedefs(self):
|
|
""" Return the array of typedef objects. """
|
|
return self.typedefs
|
|
|
|
def has_typedef_alias(self, alias):
|
|
""" Returns true if the specified typedef alias is defined in the scope
|
|
of this class declaration. """
|
|
for typedef in self.typedefs:
|
|
if typedef.get_alias() == alias:
|
|
return True
|
|
return False
|
|
|
|
def get_static_funcs(self):
|
|
""" Return the array of static function objects. """
|
|
return self.staticfuncs
|
|
|
|
def get_virtual_funcs(self):
|
|
""" Return the array of virtual function objects. """
|
|
return self.virtualfuncs
|
|
|
|
def get_types(self, list):
|
|
""" Return a dictionary mapping data types to analyzed values. """
|
|
for cls in self.typedefs:
|
|
cls.get_types(list)
|
|
|
|
for cls in self.staticfuncs:
|
|
cls.get_types(list)
|
|
|
|
for cls in self.virtualfuncs:
|
|
cls.get_types(list)
|
|
|
|
def get_alias_translation(self, alias):
|
|
for cls in self.typedefs:
|
|
if cls.alias == alias:
|
|
return cls.value
|
|
return None
|
|
|
|
def get_analysis(self, value, named=True):
|
|
""" Return an analysis of the value based on the class definition
|
|
context.
|
|
"""
|
|
return obj_analysis([self, self.parent], value, named)
|
|
|
|
def is_library_side(self):
|
|
""" Returns true if the class is implemented by the library. """
|
|
return self.attribs['source'] == 'library'
|
|
|
|
def is_client_side(self):
|
|
""" Returns true if the class is implemented by the client. """
|
|
return self.attribs['source'] == 'client'
|
|
|
|
|
|
class obj_typedef:
|
|
""" Class representing a typedef statement. """
|
|
|
|
def __init__(self, parent, filename, value, alias):
|
|
if not isinstance(parent, obj_header) \
|
|
and not isinstance(parent, obj_class):
|
|
raise Exception('Invalid parent object type')
|
|
|
|
self.parent = parent
|
|
self.filename = filename
|
|
self.alias = alias
|
|
self.value = self.parent.get_analysis(value, False)
|
|
|
|
def __repr__(self):
|
|
return 'typedef ' + self.value.get_type() + ' ' + self.alias + ';'
|
|
|
|
def get_file_name(self):
|
|
""" Return the C++ header file name. """
|
|
return self.filename
|
|
|
|
def get_capi_file_name(self):
|
|
""" Return the CAPI header file name. """
|
|
return get_capi_file_name(self.filename)
|
|
|
|
def get_alias(self):
|
|
""" Return the alias. """
|
|
return self.alias
|
|
|
|
def get_value(self):
|
|
""" Return an analysis of the value based on the class or header file
|
|
definition context.
|
|
"""
|
|
return self.value
|
|
|
|
def get_types(self, list):
|
|
""" Return a dictionary mapping data types to analyzed values. """
|
|
name = self.value.get_type()
|
|
if not name in list:
|
|
list[name] = self.value
|
|
|
|
|
|
class obj_function:
|
|
""" Class representing a function. """
|
|
|
|
def __init__(self, parent, filename, attrib, retval, argval, comment):
|
|
self.parent = parent
|
|
self.filename = filename
|
|
self.attribs = str_to_dict(attrib)
|
|
self.retval = obj_argument(self, retval)
|
|
self.name = self.retval.remove_name()
|
|
self.comment = comment
|
|
|
|
# build the argument objects
|
|
self.arguments = []
|
|
arglist = argval.split(',')
|
|
argindex = 0
|
|
while argindex < len(arglist):
|
|
arg = arglist[argindex]
|
|
if arg.find('<') >= 0 and arg.find('>') == -1:
|
|
# We've split inside of a template type declaration. Join the
|
|
# next argument with this argument.
|
|
argindex += 1
|
|
arg += ',' + arglist[argindex]
|
|
|
|
arg = arg.strip()
|
|
if len(arg) > 0:
|
|
argument = obj_argument(self, arg)
|
|
if argument.needs_attrib_count_func() and \
|
|
argument.get_attrib_count_func() is None:
|
|
raise Exception("A 'count_func' attribute is required "+ \
|
|
"for the '"+argument.get_name()+ \
|
|
"' parameter to "+self.get_qualified_name())
|
|
self.arguments.append(argument)
|
|
|
|
argindex += 1
|
|
|
|
if self.retval.needs_attrib_default_retval() and \
|
|
self.retval.get_attrib_default_retval() is None:
|
|
raise Exception("A 'default_retval' attribute is required for "+ \
|
|
self.get_qualified_name())
|
|
|
|
def __repr__(self):
|
|
return '/* ' + dict_to_str(self.attribs) + ' */ ' + self.get_cpp_proto()
|
|
|
|
def get_file_name(self):
|
|
""" Return the C++ header file name. """
|
|
return self.filename
|
|
|
|
def get_capi_file_name(self):
|
|
""" Return the CAPI header file name. """
|
|
return get_capi_file_name(self.filename)
|
|
|
|
def get_name(self):
|
|
""" Return the function name. """
|
|
return self.name
|
|
|
|
def get_qualified_name(self):
|
|
""" Return the fully qualified function name. """
|
|
if isinstance(self.parent, obj_header):
|
|
# global function
|
|
return self.name
|
|
else:
|
|
# member function
|
|
return self.parent.get_name() + '::' + self.name
|
|
|
|
def get_capi_name(self, prefix=None):
|
|
""" Return the CAPI function name. """
|
|
if 'capi_name' in self.attribs:
|
|
return self.attribs['capi_name']
|
|
return get_capi_name(self.name, False, prefix)
|
|
|
|
def get_comment(self):
|
|
""" Return the function comment as an array of lines. """
|
|
return self.comment
|
|
|
|
def get_attribs(self):
|
|
""" Return all attributes as a dictionary. """
|
|
return self.attribs
|
|
|
|
def has_attrib(self, name):
|
|
""" Return true if the specified attribute exists. """
|
|
return name in self.attribs
|
|
|
|
def get_attrib(self, name):
|
|
""" Return the first or only value for specified attribute. """
|
|
if name in self.attribs:
|
|
if isinstance(self.attribs[name], list):
|
|
# the value is a list
|
|
return self.attribs[name][0]
|
|
else:
|
|
# the value is a string
|
|
return self.attribs[name]
|
|
return None
|
|
|
|
def get_attrib_list(self, name):
|
|
""" Return all values for specified attribute as a list. """
|
|
if name in self.attribs:
|
|
if isinstance(self.attribs[name], list):
|
|
# the value is already a list
|
|
return self.attribs[name]
|
|
else:
|
|
# convert the value to a list
|
|
return [self.attribs[name]]
|
|
return None
|
|
|
|
def get_retval(self):
|
|
""" Return the return value object. """
|
|
return self.retval
|
|
|
|
def get_arguments(self):
|
|
""" Return the argument array. """
|
|
return self.arguments
|
|
|
|
def get_types(self, list):
|
|
""" Return a dictionary mapping data types to analyzed values. """
|
|
for cls in self.arguments:
|
|
cls.get_types(list)
|
|
|
|
def get_capi_parts(self, defined_structs=[], isimpl=False, prefix=None):
|
|
""" Return the parts of the C API function definition. """
|
|
retval = ''
|
|
dict = self.retval.get_type().get_capi(defined_structs)
|
|
if dict['format'] == 'single':
|
|
retval = dict['value']
|
|
|
|
name = self.get_capi_name(prefix)
|
|
args = []
|
|
|
|
if isinstance(self, obj_function_virtual):
|
|
# virtual functions get themselves as the first argument
|
|
str = 'struct _' + self.parent.get_capi_name() + '* self'
|
|
if isinstance(self, obj_function_virtual) and self.is_const():
|
|
# const virtual functions get const self pointers
|
|
str = 'const ' + str
|
|
args.append(str)
|
|
elif not isimpl and len(self.arguments) == 0:
|
|
args.append('void')
|
|
|
|
if len(self.arguments) > 0:
|
|
for cls in self.arguments:
|
|
type = cls.get_type()
|
|
dict = type.get_capi(defined_structs)
|
|
if dict['format'] == 'single':
|
|
args.append(dict['value'])
|
|
elif dict['format'] == 'multi-arg':
|
|
# add an additional argument for the size of the array
|
|
type_name = type.get_name()
|
|
if type.is_const():
|
|
# for const arrays pass the size argument by value
|
|
args.append('size_t ' + type_name + 'Count')
|
|
else:
|
|
# for non-const arrays pass the size argument by address
|
|
args.append('size_t* ' + type_name + 'Count')
|
|
args.append(dict['value'])
|
|
|
|
return {'retval': retval, 'name': name, 'args': args}
|
|
|
|
def get_capi_proto(self, defined_structs=[], isimpl=False, prefix=None):
|
|
""" Return the prototype of the C API function. """
|
|
parts = self.get_capi_parts(defined_structs, isimpl, prefix)
|
|
result = parts['retval']+' '+parts['name']+ \
|
|
'('+', '.join(parts['args'])+')'
|
|
return result
|
|
|
|
def get_cpp_parts(self, isimpl=False):
|
|
""" Return the parts of the C++ function definition. """
|
|
retval = str(self.retval)
|
|
name = self.name
|
|
|
|
args = []
|
|
if len(self.arguments) > 0:
|
|
for cls in self.arguments:
|
|
args.append(str(cls))
|
|
|
|
if isimpl and isinstance(self, obj_function_virtual):
|
|
# enumeration return values must be qualified with the class name
|
|
# if the type is defined in the class declaration scope.
|
|
type = self.get_retval().get_type()
|
|
if type.is_result_struct() and type.is_result_struct_enum() and \
|
|
self.parent.has_typedef_alias(retval):
|
|
retval = self.parent.get_name() + '::' + retval
|
|
|
|
return {'retval': retval, 'name': name, 'args': args}
|
|
|
|
def get_cpp_proto(self, classname=None):
|
|
""" Return the prototype of the C++ function. """
|
|
parts = self.get_cpp_parts()
|
|
result = parts['retval'] + ' '
|
|
if not classname is None:
|
|
result += classname + '::'
|
|
result += parts['name'] + '(' + ', '.join(parts['args']) + ')'
|
|
if isinstance(self, obj_function_virtual) and self.is_const():
|
|
result += ' const'
|
|
return result
|
|
|
|
def is_same_side(self, other_class_name):
|
|
""" Returns true if this function is on the same side (library or
|
|
client) and the specified class. """
|
|
if isinstance(self.parent, obj_class):
|
|
# this function is part of a class
|
|
this_is_library_side = self.parent.is_library_side()
|
|
header = self.parent.parent
|
|
else:
|
|
# this function is global
|
|
this_is_library_side = True
|
|
header = self.parent
|
|
|
|
if is_base_class(other_class_name):
|
|
other_is_library_side = False
|
|
else:
|
|
other_class = header.get_class(other_class_name)
|
|
if other_class is None:
|
|
raise Exception('Unknown class: ' + other_class_name)
|
|
other_is_library_side = other_class.is_library_side()
|
|
|
|
return other_is_library_side == this_is_library_side
|
|
|
|
|
|
class obj_function_static(obj_function):
|
|
""" Class representing a static function. """
|
|
|
|
def __init__(self, parent, attrib, retval, argval, comment):
|
|
if not isinstance(parent, obj_class):
|
|
raise Exception('Invalid parent object type')
|
|
obj_function.__init__(self, parent, parent.filename, attrib, retval, argval,
|
|
comment)
|
|
|
|
def __repr__(self):
|
|
return 'static ' + obj_function.__repr__(self) + ';'
|
|
|
|
def get_capi_name(self, prefix=None):
|
|
""" Return the CAPI function name. """
|
|
if prefix is None:
|
|
# by default static functions are prefixed with the class name
|
|
prefix = get_capi_name(self.parent.get_name(), False)
|
|
return obj_function.get_capi_name(self, prefix)
|
|
|
|
|
|
class obj_function_virtual(obj_function):
|
|
""" Class representing a virtual function. """
|
|
|
|
def __init__(self, parent, attrib, retval, argval, comment, vfmod):
|
|
if not isinstance(parent, obj_class):
|
|
raise Exception('Invalid parent object type')
|
|
obj_function.__init__(self, parent, parent.filename, attrib, retval, argval,
|
|
comment)
|
|
if vfmod == 'const':
|
|
self.isconst = True
|
|
else:
|
|
self.isconst = False
|
|
|
|
def __repr__(self):
|
|
return 'virtual ' + obj_function.__repr__(self) + ';'
|
|
|
|
def is_const(self):
|
|
""" Returns true if the method declaration is const. """
|
|
return self.isconst
|
|
|
|
|
|
class obj_argument:
|
|
""" Class representing a function argument. """
|
|
|
|
def __init__(self, parent, argval):
|
|
if not isinstance(parent, obj_function):
|
|
raise Exception('Invalid parent object type')
|
|
|
|
self.parent = parent
|
|
self.type = self.parent.parent.get_analysis(argval)
|
|
|
|
def __repr__(self):
|
|
result = ''
|
|
if self.type.is_const():
|
|
result += 'const '
|
|
result += self.type.get_type()
|
|
if self.type.is_byref():
|
|
result += '&'
|
|
elif self.type.is_byaddr():
|
|
result += '*'
|
|
if self.type.has_name():
|
|
result += ' ' + self.type.get_name()
|
|
return result
|
|
|
|
def get_name(self):
|
|
""" Return the name for this argument. """
|
|
return self.type.get_name()
|
|
|
|
def remove_name(self):
|
|
""" Remove and return the name value. """
|
|
name = self.type.get_name()
|
|
self.type.name = None
|
|
return name
|
|
|
|
def get_type(self):
|
|
""" Return an analysis of the argument type based on the class
|
|
definition context.
|
|
"""
|
|
return self.type
|
|
|
|
def get_types(self, list):
|
|
""" Return a dictionary mapping data types to analyzed values. """
|
|
name = self.type.get_type()
|
|
if not name in list:
|
|
list[name] = self.type
|
|
|
|
def needs_attrib_count_func(self):
|
|
""" Returns true if this argument requires a 'count_func' attribute. """
|
|
# A 'count_func' attribute is required for non-const non-string vector
|
|
# attribute types
|
|
return self.type.has_name() and \
|
|
self.type.is_result_vector() and \
|
|
not self.type.is_result_vector_string() and \
|
|
not self.type.is_const()
|
|
|
|
def get_attrib_count_func(self):
|
|
""" Returns the count function for this argument. """
|
|
# The 'count_func' attribute value format is name:function
|
|
if not self.parent.has_attrib('count_func'):
|
|
return None
|
|
name = self.type.get_name()
|
|
vals = self.parent.get_attrib_list('count_func')
|
|
for val in vals:
|
|
parts = val.split(':')
|
|
if len(parts) != 2:
|
|
raise Exception("Invalid 'count_func' attribute value for "+ \
|
|
self.parent.get_qualified_name()+': '+val)
|
|
if parts[0].strip() == name:
|
|
return parts[1].strip()
|
|
return None
|
|
|
|
def needs_attrib_default_retval(self):
|
|
""" Returns true if this argument requires a 'default_retval' attribute.
|
|
"""
|
|
# A 'default_retval' attribute is required for enumeration return value
|
|
# types.
|
|
return not self.type.has_name() and \
|
|
self.type.is_result_struct() and \
|
|
self.type.is_result_struct_enum()
|
|
|
|
def get_attrib_default_retval(self):
|
|
""" Returns the defualt return value for this argument. """
|
|
return self.parent.get_attrib('default_retval')
|
|
|
|
def get_arg_type(self):
|
|
""" Returns the argument type as defined in translator.README.txt. """
|
|
if not self.type.has_name():
|
|
raise Exception('Cannot be called for retval types')
|
|
|
|
# simple or enumeration type
|
|
if (self.type.is_result_simple() and \
|
|
self.type.get_type() != 'bool') or \
|
|
(self.type.is_result_struct() and \
|
|
self.type.is_result_struct_enum()):
|
|
if self.type.is_byref():
|
|
if self.type.is_const():
|
|
return 'simple_byref_const'
|
|
return 'simple_byref'
|
|
elif self.type.is_byaddr():
|
|
return 'simple_byaddr'
|
|
return 'simple_byval'
|
|
|
|
# boolean type
|
|
if self.type.get_type() == 'bool':
|
|
if self.type.is_byref():
|
|
return 'bool_byref'
|
|
elif self.type.is_byaddr():
|
|
return 'bool_byaddr'
|
|
return 'bool_byval'
|
|
|
|
# structure type
|
|
if self.type.is_result_struct() and self.type.is_byref():
|
|
if self.type.is_const():
|
|
return 'struct_byref_const'
|
|
return 'struct_byref'
|
|
|
|
# string type
|
|
if self.type.is_result_string() and self.type.is_byref():
|
|
if self.type.is_const():
|
|
return 'string_byref_const'
|
|
return 'string_byref'
|
|
|
|
# *ptr type
|
|
if self.type.is_result_ptr():
|
|
prefix = self.type.get_result_ptr_type_prefix()
|
|
same_side = self.parent.is_same_side(self.type.get_ptr_type())
|
|
if self.type.is_byref():
|
|
if same_side:
|
|
return prefix + 'ptr_same_byref'
|
|
return prefix + 'ptr_diff_byref'
|
|
if same_side:
|
|
return prefix + 'ptr_same'
|
|
return prefix + 'ptr_diff'
|
|
|
|
if self.type.is_result_vector():
|
|
# all vector types must be passed by reference
|
|
if not self.type.is_byref():
|
|
return 'invalid'
|
|
|
|
if self.type.is_result_vector_string():
|
|
# string vector type
|
|
if self.type.is_const():
|
|
return 'string_vec_byref_const'
|
|
return 'string_vec_byref'
|
|
|
|
if self.type.is_result_vector_simple():
|
|
if self.type.get_vector_type() != 'bool':
|
|
# simple/enumeration vector types
|
|
if self.type.is_const():
|
|
return 'simple_vec_byref_const'
|
|
return 'simple_vec_byref'
|
|
|
|
# boolean vector types
|
|
if self.type.is_const():
|
|
return 'bool_vec_byref_const'
|
|
return 'bool_vec_byref'
|
|
|
|
if self.type.is_result_vector_ptr():
|
|
# *ptr vector types
|
|
prefix = self.type.get_result_vector_ptr_type_prefix()
|
|
same_side = self.parent.is_same_side(self.type.get_ptr_type())
|
|
if self.type.is_const():
|
|
if same_side:
|
|
return prefix + 'ptr_vec_same_byref_const'
|
|
return prefix + 'ptr_vec_diff_byref_const'
|
|
if same_side:
|
|
return prefix + 'ptr_vec_same_byref'
|
|
return prefix + 'ptr_vec_diff_byref'
|
|
|
|
# string single map type
|
|
if self.type.is_result_map_single():
|
|
if not self.type.is_byref():
|
|
return 'invalid'
|
|
if self.type.is_const():
|
|
return 'string_map_single_byref_const'
|
|
return 'string_map_single_byref'
|
|
|
|
# string multi map type
|
|
if self.type.is_result_map_multi():
|
|
if not self.type.is_byref():
|
|
return 'invalid'
|
|
if self.type.is_const():
|
|
return 'string_map_multi_byref_const'
|
|
return 'string_map_multi_byref'
|
|
|
|
return 'invalid'
|
|
|
|
def get_retval_type(self):
|
|
""" Returns the retval type as defined in translator.README.txt. """
|
|
if self.type.has_name():
|
|
raise Exception('Cannot be called for argument types')
|
|
|
|
# unsupported modifiers
|
|
if self.type.is_const() or self.type.is_byref() or \
|
|
self.type.is_byaddr():
|
|
return 'invalid'
|
|
|
|
# void types don't have a return value
|
|
if self.type.get_type() == 'void':
|
|
return 'none'
|
|
|
|
if (self.type.is_result_simple() and \
|
|
self.type.get_type() != 'bool') or \
|
|
(self.type.is_result_struct() and self.type.is_result_struct_enum()):
|
|
return 'simple'
|
|
|
|
if self.type.get_type() == 'bool':
|
|
return 'bool'
|
|
|
|
if self.type.is_result_string():
|
|
return 'string'
|
|
|
|
if self.type.is_result_ptr():
|
|
prefix = self.type.get_result_ptr_type_prefix()
|
|
if self.parent.is_same_side(self.type.get_ptr_type()):
|
|
return prefix + 'ptr_same'
|
|
else:
|
|
return prefix + 'ptr_diff'
|
|
|
|
return 'invalid'
|
|
|
|
def get_retval_default(self, for_capi):
|
|
""" Returns the default return value based on the retval type. """
|
|
# start with the default retval attribute, if any.
|
|
retval = self.get_attrib_default_retval()
|
|
if not retval is None:
|
|
if for_capi:
|
|
# apply any appropriate C API translations.
|
|
if retval == 'true':
|
|
return '1'
|
|
if retval == 'false':
|
|
return '0'
|
|
return retval
|
|
|
|
# next look at the retval type value.
|
|
type = self.get_retval_type()
|
|
if type == 'simple':
|
|
return self.get_type().get_result_simple_default()
|
|
elif type == 'bool':
|
|
if for_capi:
|
|
return '0'
|
|
return 'false'
|
|
elif type == 'string':
|
|
if for_capi:
|
|
return 'NULL'
|
|
return 'CefString()'
|
|
elif type == 'refptr_same' or type == 'refptr_diff' or \
|
|
type == 'rawptr_same' or type == 'rawptr_diff':
|
|
if for_capi:
|
|
return 'NULL'
|
|
return 'nullptr'
|
|
elif type == 'ownptr_same' or type == 'ownptr_diff':
|
|
if for_capi:
|
|
return 'NULL'
|
|
return 'CefOwnPtr<' + self.type.get_ptr_type() + '>()'
|
|
|
|
return ''
|
|
|
|
|
|
class obj_analysis:
|
|
""" Class representing an analysis of a data type value. """
|
|
|
|
def __init__(self, scopelist, value, named):
|
|
self.value = value
|
|
self.result_type = 'unknown'
|
|
self.result_value = None
|
|
self.result_default = None
|
|
self.ptr_type = None
|
|
|
|
# parse the argument string
|
|
partlist = value.strip().split()
|
|
|
|
if named == True:
|
|
# extract the name value
|
|
self.name = partlist[-1]
|
|
del partlist[-1]
|
|
else:
|
|
self.name = None
|
|
|
|
if len(partlist) == 0:
|
|
raise Exception('Invalid argument value: ' + value)
|
|
|
|
# check const status
|
|
if partlist[0] == 'const':
|
|
self.isconst = True
|
|
del partlist[0]
|
|
else:
|
|
self.isconst = False
|
|
|
|
if len(partlist) == 0:
|
|
raise Exception('Invalid argument value: ' + value)
|
|
|
|
# combine the data type
|
|
self.type = ' '.join(partlist)
|
|
|
|
# extract the last character of the data type
|
|
endchar = self.type[-1]
|
|
|
|
# check if the value is passed by reference
|
|
if endchar == '&':
|
|
self.isbyref = True
|
|
self.type = self.type[:-1]
|
|
else:
|
|
self.isbyref = False
|
|
|
|
# check if the value is passed by address
|
|
if endchar == '*':
|
|
self.isbyaddr = True
|
|
self.type = self.type[:-1]
|
|
else:
|
|
self.isbyaddr = False
|
|
|
|
# see if the value is directly identifiable
|
|
if self._check_advanced(self.type) == True:
|
|
return
|
|
|
|
# not identifiable, so look it up
|
|
translation = None
|
|
for scope in scopelist:
|
|
if not isinstance(scope, obj_header) \
|
|
and not isinstance(scope, obj_class):
|
|
raise Exception('Invalid scope object type')
|
|
translation = scope.get_alias_translation(self.type)
|
|
if not translation is None:
|
|
break
|
|
|
|
if translation is None:
|
|
raise Exception('Failed to translate type: ' + self.type)
|
|
|
|
# the translation succeeded so keep the result
|
|
self.result_type = translation.result_type
|
|
self.result_value = translation.result_value
|
|
|
|
def _check_advanced(self, value):
|
|
# check for vectors
|
|
if value.find('std::vector') == 0:
|
|
self.result_type = 'vector'
|
|
val = value[12:-1].strip()
|
|
self.result_value = [self._get_basic(val)]
|
|
self.result_value[0]['vector_type'] = val
|
|
return True
|
|
|
|
# check for maps
|
|
if value.find('std::map') == 0:
|
|
self.result_type = 'map'
|
|
vals = value[9:-1].split(',')
|
|
if len(vals) == 2:
|
|
self.result_value = [
|
|
self._get_basic(vals[0].strip()),
|
|
self._get_basic(vals[1].strip())
|
|
]
|
|
return True
|
|
|
|
# check for multimaps
|
|
if value.find('std::multimap') == 0:
|
|
self.result_type = 'multimap'
|
|
vals = value[14:-1].split(',')
|
|
if len(vals) == 2:
|
|
self.result_value = [
|
|
self._get_basic(vals[0].strip()),
|
|
self._get_basic(vals[1].strip())
|
|
]
|
|
return True
|
|
|
|
# check for basic types
|
|
basic = self._get_basic(value)
|
|
if not basic is None:
|
|
self.result_type = basic['result_type']
|
|
self.result_value = basic['result_value']
|
|
if 'ptr_type' in basic:
|
|
self.ptr_type = basic['ptr_type']
|
|
if 'result_default' in basic:
|
|
self.result_default = basic['result_default']
|
|
return True
|
|
|
|
return False
|
|
|
|
def _get_basic(self, value):
|
|
# check for string values
|
|
if value == "CefString":
|
|
return {'result_type': 'string', 'result_value': None}
|
|
|
|
# check for simple direct translations
|
|
if value in _simpletypes.keys():
|
|
return {
|
|
'result_type': 'simple',
|
|
'result_value': _simpletypes[value][0],
|
|
'result_default': _simpletypes[value][1],
|
|
}
|
|
|
|
# check if already a C API structure
|
|
if value[-2:] == '_t':
|
|
return {'result_type': 'structure', 'result_value': value}
|
|
|
|
# check for CEF reference pointers
|
|
p = re.compile(r'^CefRefPtr<(.*?)>$', re.DOTALL)
|
|
list = p.findall(value)
|
|
if len(list) == 1:
|
|
return {
|
|
'result_type': 'refptr',
|
|
'result_value': get_capi_name(list[0], True) + '*',
|
|
'ptr_type': list[0]
|
|
}
|
|
|
|
# check for CEF owned pointers
|
|
p = re.compile(r'^CefOwnPtr<(.*?)>$', re.DOTALL)
|
|
list = p.findall(value)
|
|
if len(list) == 1:
|
|
return {
|
|
'result_type': 'ownptr',
|
|
'result_value': get_capi_name(list[0], True) + '*',
|
|
'ptr_type': list[0]
|
|
}
|
|
|
|
# check for CEF raw pointers
|
|
p = re.compile(r'^CefRawPtr<(.*?)>$', re.DOTALL)
|
|
list = p.findall(value)
|
|
if len(list) == 1:
|
|
return {
|
|
'result_type': 'rawptr',
|
|
'result_value': get_capi_name(list[0], True) + '*',
|
|
'ptr_type': list[0]
|
|
}
|
|
|
|
# check for CEF structure types
|
|
if value[0:3] == 'Cef' and value[-4:] != 'List':
|
|
return {
|
|
'result_type': 'structure',
|
|
'result_value': get_capi_name(value, True)
|
|
}
|
|
|
|
return None
|
|
|
|
def __repr__(self):
|
|
return '(' + self.result_type + ') ' + str(self.result_value)
|
|
|
|
def has_name(self):
|
|
""" Returns true if a name value exists. """
|
|
return (not self.name is None)
|
|
|
|
def get_name(self):
|
|
""" Return the name. """
|
|
return self.name
|
|
|
|
def get_value(self):
|
|
""" Return the C++ value (type + name). """
|
|
return self.value
|
|
|
|
def get_type(self):
|
|
""" Return the C++ type. """
|
|
return self.type
|
|
|
|
def get_ptr_type(self):
|
|
""" Return the C++ class type referenced by a CefRefPtr. """
|
|
if self.is_result_vector() and self.is_result_vector_ptr():
|
|
# return the vector RefPtr type
|
|
return self.result_value[0]['ptr_type']
|
|
# return the basic RefPtr type
|
|
return self.ptr_type
|
|
|
|
def get_vector_type(self):
|
|
""" Return the C++ class type referenced by a std::vector. """
|
|
if self.is_result_vector():
|
|
return self.result_value[0]['vector_type']
|
|
return None
|
|
|
|
def is_const(self):
|
|
""" Returns true if the argument value is constant. """
|
|
return self.isconst
|
|
|
|
def is_byref(self):
|
|
""" Returns true if the argument is passed by reference. """
|
|
return self.isbyref
|
|
|
|
def is_byaddr(self):
|
|
""" Returns true if the argument is passed by address. """
|
|
return self.isbyaddr
|
|
|
|
def is_result_simple(self):
|
|
""" Returns true if this is a simple argument type. """
|
|
return (self.result_type == 'simple')
|
|
|
|
def get_result_simple_type_root(self):
|
|
""" Return the simple structure or basic type name. """
|
|
return self.result_value
|
|
|
|
def get_result_simple_type(self):
|
|
""" Return the simple type. """
|
|
result = ''
|
|
if self.is_const():
|
|
result += 'const '
|
|
result += self.result_value
|
|
if self.is_byaddr() or self.is_byref():
|
|
result += '*'
|
|
return result
|
|
|
|
def get_result_simple_default(self):
|
|
""" Return the default value fo the basic type. """
|
|
return self.result_default
|
|
|
|
def is_result_ptr(self):
|
|
""" Returns true if this is a *Ptr type. """
|
|
return self.is_result_refptr() or self.is_result_ownptr() or \
|
|
self.is_result_rawptr()
|
|
|
|
def get_result_ptr_type_root(self):
|
|
""" Return the *Ptr type structure name. """
|
|
return self.result_value[:-1]
|
|
|
|
def get_result_ptr_type(self, defined_structs=[]):
|
|
""" Return the *Ptr type. """
|
|
result = ''
|
|
if not self.result_value[:-1] in defined_structs:
|
|
result += 'struct _'
|
|
result += self.result_value
|
|
if self.is_byref() or self.is_byaddr():
|
|
result += '*'
|
|
return result
|
|
|
|
def get_result_ptr_type_prefix(self):
|
|
""" Returns the *Ptr type prefix. """
|
|
if self.is_result_refptr():
|
|
return 'ref'
|
|
if self.is_result_ownptr():
|
|
return 'own'
|
|
if self.is_result_rawptr():
|
|
return 'raw'
|
|
raise Exception('Not a pointer type')
|
|
|
|
def is_result_refptr(self):
|
|
""" Returns true if this is a RefPtr type. """
|
|
return (self.result_type == 'refptr')
|
|
|
|
def is_result_ownptr(self):
|
|
""" Returns true if this is a OwnPtr type. """
|
|
return (self.result_type == 'ownptr')
|
|
|
|
def is_result_rawptr(self):
|
|
""" Returns true if this is a RawPtr type. """
|
|
return (self.result_type == 'rawptr')
|
|
|
|
def is_result_struct(self):
|
|
""" Returns true if this is a structure type. """
|
|
return (self.result_type == 'structure')
|
|
|
|
def is_result_struct_enum(self):
|
|
""" Returns true if this struct type is likely an enumeration. """
|
|
# structure values that are passed by reference or address must be
|
|
# structures and not enumerations
|
|
if not self.is_byref() and not self.is_byaddr():
|
|
return True
|
|
return False
|
|
|
|
def get_result_struct_type(self, defined_structs=[]):
|
|
""" Return the structure or enumeration type. """
|
|
result = ''
|
|
is_enum = self.is_result_struct_enum()
|
|
if not is_enum:
|
|
if self.is_const():
|
|
result += 'const '
|
|
if not self.result_value in defined_structs:
|
|
result += 'struct _'
|
|
result += self.result_value
|
|
if not is_enum:
|
|
result += '*'
|
|
return result
|
|
|
|
def is_result_string(self):
|
|
""" Returns true if this is a string type. """
|
|
return (self.result_type == 'string')
|
|
|
|
def get_result_string_type(self):
|
|
""" Return the string type. """
|
|
if not self.has_name():
|
|
# Return values are string structs that the user must free. Use
|
|
# the name of the structure as a hint.
|
|
return 'cef_string_userfree_t'
|
|
elif not self.is_const() and (self.is_byref() or self.is_byaddr()):
|
|
# Parameters passed by reference or address. Use the normal
|
|
# non-const string struct.
|
|
return 'cef_string_t*'
|
|
# Const parameters use the const string struct.
|
|
return 'const cef_string_t*'
|
|
|
|
def is_result_vector(self):
|
|
""" Returns true if this is a vector type. """
|
|
return (self.result_type == 'vector')
|
|
|
|
def is_result_vector_string(self):
|
|
""" Returns true if this is a string vector. """
|
|
return self.result_value[0]['result_type'] == 'string'
|
|
|
|
def is_result_vector_simple(self):
|
|
""" Returns true if this is a string vector. """
|
|
return self.result_value[0]['result_type'] == 'simple'
|
|
|
|
def is_result_vector_ptr(self):
|
|
""" Returns true if this is a *Ptr vector. """
|
|
return self.is_result_vector_refptr() or \
|
|
self.is_result_vector_ownptr() or \
|
|
self.is_result_vector_rawptr()
|
|
|
|
def get_result_vector_ptr_type_prefix(self):
|
|
""" Returns the *Ptr type prefix. """
|
|
if self.is_result_vector_refptr():
|
|
return 'ref'
|
|
if self.is_result_vector_ownptr():
|
|
return 'own'
|
|
if self.is_result_vector_rawptr():
|
|
return 'raw'
|
|
raise Exception('Not a pointer type')
|
|
|
|
def is_result_vector_refptr(self):
|
|
""" Returns true if this is a RefPtr vector. """
|
|
return self.result_value[0]['result_type'] == 'refptr'
|
|
|
|
def is_result_vector_ownptr(self):
|
|
""" Returns true if this is a OwnPtr vector. """
|
|
return self.result_value[0]['result_type'] == 'ownptr'
|
|
|
|
def is_result_vector_rawptr(self):
|
|
""" Returns true if this is a RawPtr vector. """
|
|
return self.result_value[0]['result_type'] == 'rawptr'
|
|
|
|
def get_result_vector_type_root(self):
|
|
""" Return the vector structure or basic type name. """
|
|
return self.result_value[0]['result_value']
|
|
|
|
def get_result_vector_type(self, defined_structs=[]):
|
|
""" Return the vector type. """
|
|
if not self.has_name():
|
|
raise Exception('Cannot use vector as a return type')
|
|
|
|
type = self.result_value[0]['result_type']
|
|
value = self.result_value[0]['result_value']
|
|
|
|
result = {}
|
|
if type == 'string':
|
|
result['value'] = 'cef_string_list_t'
|
|
result['format'] = 'single'
|
|
return result
|
|
|
|
if type == 'simple':
|
|
str = value
|
|
if self.is_const():
|
|
str += ' const'
|
|
str += '*'
|
|
result['value'] = str
|
|
elif type == 'refptr' or type == 'ownptr' or type == 'rawptr':
|
|
str = ''
|
|
if not value[:-1] in defined_structs:
|
|
str += 'struct _'
|
|
str += value
|
|
if self.is_const():
|
|
str += ' const'
|
|
str += '*'
|
|
result['value'] = str
|
|
else:
|
|
raise Exception('Unsupported vector type: ' + type)
|
|
|
|
# vector values must be passed as a value array parameter
|
|
# and a size parameter
|
|
result['format'] = 'multi-arg'
|
|
return result
|
|
|
|
def is_result_map(self):
|
|
""" Returns true if this is a map type. """
|
|
return (self.result_type == 'map' or self.result_type == 'multimap')
|
|
|
|
def is_result_map_single(self):
|
|
""" Returns true if this is a single map type. """
|
|
return (self.result_type == 'map')
|
|
|
|
def is_result_map_multi(self):
|
|
""" Returns true if this is a multi map type. """
|
|
return (self.result_type == 'multimap')
|
|
|
|
def get_result_map_type(self, defined_structs=[]):
|
|
""" Return the map type. """
|
|
if not self.has_name():
|
|
raise Exception('Cannot use map as a return type')
|
|
if self.result_value[0]['result_type'] == 'string' \
|
|
and self.result_value[1]['result_type'] == 'string':
|
|
if self.result_type == 'map':
|
|
return {'value': 'cef_string_map_t', 'format': 'single'}
|
|
elif self.result_type == 'multimap':
|
|
return {'value': 'cef_string_multimap_t', 'format': 'multi'}
|
|
raise Exception('Only mappings of strings to strings are supported')
|
|
|
|
def get_capi(self, defined_structs=[]):
|
|
""" Format the value for the C API. """
|
|
result = ''
|
|
format = 'single'
|
|
if self.is_result_simple():
|
|
result += self.get_result_simple_type()
|
|
elif self.is_result_ptr():
|
|
result += self.get_result_ptr_type(defined_structs)
|
|
elif self.is_result_struct():
|
|
result += self.get_result_struct_type(defined_structs)
|
|
elif self.is_result_string():
|
|
result += self.get_result_string_type()
|
|
elif self.is_result_map():
|
|
resdict = self.get_result_map_type(defined_structs)
|
|
if resdict['format'] == 'single' or resdict['format'] == 'multi':
|
|
result += resdict['value']
|
|
else:
|
|
raise Exception('Unsupported map type')
|
|
elif self.is_result_vector():
|
|
resdict = self.get_result_vector_type(defined_structs)
|
|
if resdict['format'] != 'single':
|
|
format = resdict['format']
|
|
result += resdict['value']
|
|
|
|
if self.has_name():
|
|
result += ' ' + self.get_name()
|
|
|
|
return {'format': format, 'value': result}
|
|
|
|
|
|
# test the module
|
|
if __name__ == "__main__":
|
|
import pprint
|
|
import sys
|
|
|
|
# verify that the correct number of command-line arguments are provided
|
|
if len(sys.argv) != 2:
|
|
sys.stderr.write('Usage: ' + sys.argv[0] + ' <directory>')
|
|
sys.exit()
|
|
|
|
pp = pprint.PrettyPrinter(indent=4)
|
|
|
|
# create the header object
|
|
header = obj_header()
|
|
header.add_directory(sys.argv[1])
|
|
|
|
# output the type mapping
|
|
types = {}
|
|
header.get_types(types)
|
|
pp.pprint(types)
|
|
sys.stdout.write('\n')
|
|
|
|
# output the parsed C++ data
|
|
sys.stdout.write(str(header))
|
|
|
|
# output the C API formatted data
|
|
defined_names = header.get_defined_structs()
|
|
result = ''
|
|
|
|
# global functions
|
|
funcs = header.get_funcs()
|
|
if len(funcs) > 0:
|
|
for func in funcs:
|
|
result += func.get_capi_proto(defined_names, True) + ';\n'
|
|
result += '\n'
|
|
|
|
classes = header.get_classes()
|
|
for cls in classes:
|
|
# virtual functions are inside a structure
|
|
result += 'struct ' + cls.get_capi_name() + '\n{\n'
|
|
funcs = cls.get_virtual_funcs()
|
|
if len(funcs) > 0:
|
|
for func in funcs:
|
|
result += '\t' + func.get_capi_proto(defined_names, True) + ';\n'
|
|
result += '}\n\n'
|
|
|
|
defined_names.append(cls.get_capi_name())
|
|
|
|
# static functions become global
|
|
funcs = cls.get_static_funcs()
|
|
if len(funcs) > 0:
|
|
for func in funcs:
|
|
result += func.get_capi_proto(defined_names, True) + ';\n'
|
|
result += '\n'
|
|
sys.stdout.write(result)
|