# 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 cef_parser import * import copy import functools def make_cpptoc_impl_proto(name, func, parts): if isinstance(func, obj_function_virtual): proto = parts['retval'] + ' CEF_CALLBACK' else: proto = 'CEF_EXPORT ' + parts['retval'] proto += ' ' + name + '(' + ', '.join(parts['args']) + ')' return proto def make_cpptoc_function_impl_existing(cls, name, func, impl, defined_names, version, version_finder): notify(name + ' has manual edits') # retrieve the C API prototype parts parts = func.get_capi_parts( defined_names, True, version=version, version_finder=version_finder) changes = format_translation_changes(impl, parts) if len(changes) > 0: notify(name + ' prototype changed') return make_cpptoc_impl_proto(name, func, parts) + '{' + changes + impl['body'] + '\n}\n' def make_cpptoc_function_impl_new(cls, name, func, defined_names, base_scoped, version, version_finder): if not version is None and isinstance(func, obj_function_virtual) and \ not func.exists_at_version(version): raise Exception( 'Attempting to generate non-existing function %s at version %d' % (name, version)) # Special handling for the cef_shutdown global function. is_cef_shutdown = name == 'cef_shutdown' and isinstance( func.parent, obj_header) # retrieve the C API prototype parts parts = func.get_capi_parts( defined_names, True, version=version, version_finder=version_finder) result = make_cpptoc_impl_proto(name, func, parts) + ' {' if isinstance(func.parent, obj_class) and \ not func.parent.has_attrib('no_debugct_check') and \ not base_scoped: result += '\n shutdown_checker::AssertNotShutdown();\n' invalid = [] # retrieve the function arguments args = func.get_arguments() # determine the argument types for arg in args: if arg.get_arg_type() == 'invalid': invalid.append(arg.get_name()) # retrieve the function return value retval = func.get_retval() retval_type = retval.get_retval_type() if retval_type == 'invalid': invalid.append('(return value)') retval_default = '' else: retval_default = retval.get_retval_default(True) if len(retval_default) > 0: retval_default = ' ' + retval_default if len(invalid) > 0: notify(name + ' could not be autogenerated') # code could not be auto-generated result += '\n // BEGIN DELETE BEFORE MODIFYING' result += '\n // AUTO-GENERATED CONTENT' result += '\n // COULD NOT IMPLEMENT DUE TO: ' + ', '.join(invalid) result += '\n #pragma message("Warning: " __FILE__ ": ' + name + ' is not implemented")' result += '\n // END DELETE BEFORE MODIFYING' result += '\n}\n\n' return result result += '\n // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING\n' result_len = len(result) optional = [] # parameter verification if isinstance(func, obj_function_virtual): result += '\n DCHECK(self);'\ '\n if (!self) {'\ '\n return'+retval_default+';'\ '\n }' for arg in args: arg_type = arg.get_arg_type() arg_name = arg.get_type().get_name() # skip optional params optional_params = arg.parent.get_attrib_list('optional_param') if not optional_params is None and arg_name in optional_params: optional.append(arg_name) continue comment = '\n // Verify param: ' + arg_name + '; type: ' + arg_type if arg_type == 'simple_byref' or arg_type == 'simple_byref_const' or \ arg_type == 'simple_byaddr' or arg_type == 'bool_byref' or arg_type == 'bool_byaddr' or \ arg_type == 'struct_byref_const' or arg_type == 'struct_byref' or \ arg_type == 'string_byref_const' or arg_type == 'string_byref' or \ arg_type == 'refptr_same' or arg_type == 'refptr_same_byref' or \ arg_type == 'refptr_diff' or arg_type == 'refptr_diff_byref' or \ arg_type == 'ownptr_same' or arg_type == 'ownptr_same_byref' or \ arg_type == 'ownptr_diff' or arg_type == 'ownptr_diff_byref' or \ arg_type == 'rawptr_same' or arg_type == 'rawptr_same_byref' or \ arg_type == 'rawptr_diff' or arg_type == 'rawptr_diff_byref' or \ arg_type == 'string_vec_byref' or arg_type == 'string_vec_byref_const' or \ arg_type == 'string_map_single_byref' or arg_type == 'string_map_single_byref_const' or \ arg_type == 'string_map_multi_byref' or arg_type == 'string_map_multi_byref_const': result += comment+\ '\n DCHECK('+arg_name+');'\ '\n if (!'+arg_name+') {'\ '\n return'+retval_default+';'\ '\n }' if arg_type == 'struct_byref_const' or arg_type == 'struct_byref': result +=\ '\n if (!template_util::has_valid_size('+arg_name+')) {'\ '\n DCHECK(false) << "invalid '+arg_name+'->[base.]size";'\ '\n return'+retval_default+';'\ '\n }' elif arg_type == 'simple_vec_byref' or arg_type == 'bool_vec_byref' or \ arg_type == 'refptr_vec_same_byref' or arg_type == 'refptr_vec_diff_byref' or \ arg_type == 'ownptr_vec_same_byref' or arg_type == 'ownptr_vec_diff_byref' or \ arg_type == 'rawptr_vec_same_byref' or arg_type == 'rawptr_vec_diff_byref': result += comment+\ '\n DCHECK('+arg_name+'Count && (*'+arg_name+'Count == 0 || '+arg_name+'));'\ '\n if (!'+arg_name+'Count || (*'+arg_name+'Count > 0 && !'+arg_name+')) {'\ '\n return'+retval_default+';'\ '\n }' elif arg_type == 'simple_vec_byref_const' or arg_type == 'bool_vec_byref_const' or \ arg_type == 'refptr_vec_same_byref_const' or arg_type == 'refptr_vec_diff_byref_const' or \ arg_type == 'ownptr_vec_same_byref_const' or arg_type == 'ownptr_vec_diff_byref_const' or \ arg_type == 'rawptr_vec_same_byref_const' or arg_type == 'rawptr_vec_diff_byref_const': result += comment+\ '\n DCHECK('+arg_name+'Count == 0 || '+arg_name+');'\ '\n if ('+arg_name+'Count > 0 && !'+arg_name+') {'\ '\n return'+retval_default+';'\ '\n }' # check index params index_params = arg.parent.get_attrib_list('index_param') if not index_params is None and arg_name in index_params: result += comment+\ '\n DCHECK_GE('+arg_name+', 0);'\ '\n if ('+arg_name+' < 0) {'\ '\n return'+retval_default+';'\ '\n }' if len(optional) > 0: # Wrap the comment at 80 characters. str = '\n // Unverified params: ' + optional[0] for name in optional[1:]: str += ',' if len(str) + len(name) + 1 > 80: result += str str = '\n //' str += ' ' + name result += str if len(result) != result_len: result += '\n' result_len = len(result) # parameter translation params = [] for arg in args: arg_type = arg.get_arg_type() arg_name = arg.get_type().get_name() comment = '\n // Translate param: ' + arg_name + '; type: ' + arg_type if arg_type == 'simple_byval' or arg_type == 'simple_byaddr': params.append(arg_name) elif arg_type == 'simple_byref' or arg_type == 'simple_byref_const': data_type = arg.get_type().get_type() default = arg.get_type().get_result_simple_default() result += comment+\ '\n '+data_type+' '+arg_name+'Val = '+arg_name+'?*'+arg_name+':'+default+';' params.append(arg_name + 'Val') elif arg_type == 'bool_byval': params.append(arg_name + '?true:false') elif arg_type == 'bool_byref' or arg_type == 'bool_byaddr': result += comment+\ '\n bool '+arg_name+'Bool = ('+arg_name+' && *'+arg_name+')?true:false;' if arg_type == 'bool_byref': params.append(arg_name + 'Bool') else: params.append('&' + arg_name + 'Bool') elif arg_type == 'struct_byref_const': struct_type = arg.get_type().get_type() result += comment+\ '\n '+struct_type+' '+arg_name+'Obj;'\ '\n if ('+arg_name+') {'\ '\n '+arg_name+'Obj.Set(*'+arg_name+', false);'\ '\n }' params.append(arg_name + 'Obj') elif arg_type == 'struct_byref': struct_type = arg.get_type().get_type() result += comment+\ '\n '+struct_type+' '+arg_name+'Obj;'\ '\n if ('+arg_name+') {'\ '\n '+arg_name+'Obj.AttachTo(*'+arg_name+');'\ '\n }' params.append(arg_name + 'Obj') elif arg_type == 'string_byref_const': params.append('CefString(' + arg_name + ')') elif arg_type == 'string_byref': result += comment+\ '\n CefString '+arg_name+'Str('+arg_name+');' params.append(arg_name + 'Str') elif arg_type == 'refptr_same' or arg_type == 'refptr_diff': ptr_class = arg.get_type().get_ptr_type() if arg_type == 'refptr_same': params.append(ptr_class + 'CppToC_Unwrap(' + arg_name + ')') else: params.append(ptr_class + 'CToCpp_Wrap(' + arg_name + ')') elif arg_type == 'ownptr_same' or arg_type == 'rawptr_same': ptr_class = arg.get_type().get_ptr_type() if arg_type == 'ownptr_same': params.append(ptr_class + 'CppToC_UnwrapOwn(' + arg_name + ')') else: params.append(ptr_class + 'CppToC_UnwrapRaw(' + arg_name + ')') elif arg_type == 'ownptr_diff' or arg_type == 'rawptr_diff': ptr_class = arg.get_type().get_ptr_type() result += comment+\ '\n CefOwnPtr<'+ptr_class+'> '+arg_name+'Ptr('+ptr_class+'CToCpp_Wrap('+arg_name+'));' if arg_type == 'ownptr_diff': params.append('std::move(' + arg_name + 'Ptr)') else: params.append(arg_name + 'Ptr.get()') elif arg_type == 'refptr_same_byref' or arg_type == 'refptr_diff_byref': ptr_class = ptr_class_u = arg.get_type().get_ptr_type() if arg_type == 'refptr_same_byref': assign = ptr_class + 'CppToC_Unwrap(*' + arg_name + ')' else: assign = ptr_class + 'CToCpp_Wrap(*' + arg_name + ')' result += comment+\ '\n CefRefPtr<'+ptr_class_u+'> '+arg_name+'Ptr;'\ '\n if ('+arg_name+' && *'+arg_name+') {'\ '\n '+arg_name+'Ptr = '+assign+';'\ '\n }'\ '\n '+ptr_class+'* '+arg_name+'Orig = '+arg_name+'Ptr.get();' params.append(arg_name + 'Ptr') elif arg_type == 'string_vec_byref' or arg_type == 'string_vec_byref_const': result += comment+\ '\n std::vector '+arg_name+'List;'\ '\n transfer_string_list_contents('+arg_name+', '+arg_name+'List);' params.append(arg_name + 'List') elif arg_type == 'string_map_single_byref' or arg_type == 'string_map_single_byref_const': result += comment+\ '\n std::map '+arg_name+'Map;'\ '\n transfer_string_map_contents('+arg_name+', '+arg_name+'Map);' params.append(arg_name + 'Map') elif arg_type == 'string_map_multi_byref' or arg_type == 'string_map_multi_byref_const': result += comment+\ '\n std::multimap '+arg_name+'Multimap;'\ '\n transfer_string_multimap_contents('+arg_name+', '+arg_name+'Multimap);' params.append(arg_name + 'Multimap') elif arg_type == 'simple_vec_byref' or arg_type == 'bool_vec_byref' or \ arg_type == 'refptr_vec_same_byref' or arg_type == 'refptr_vec_diff_byref': vec_type = arg.get_type().get_vector_type() if arg_type == 'simple_vec_byref': assign = arg_name + '[i]' elif arg_type == 'bool_vec_byref': assign = arg_name + '[i]?true:false' elif arg_type == 'refptr_vec_same_byref': ptr_class = arg.get_type().get_ptr_type() assign = ptr_class + 'CppToC_Unwrap(' + arg_name + '[i])' elif arg_type == 'refptr_vec_diff_byref': ptr_class = arg.get_type().get_ptr_type() assign = ptr_class + 'CToCpp_Wrap(' + arg_name + '[i])' result += comment+\ '\n std::vector<'+vec_type+' > '+arg_name+'List;'\ '\n if ('+arg_name+'Count && *'+arg_name+'Count > 0 && '+arg_name+') {'\ '\n for (size_t i = 0; i < *'+arg_name+'Count; ++i) {'\ '\n '+arg_name+'List.push_back('+assign+');'\ '\n }'\ '\n }' params.append(arg_name + 'List') elif arg_type == 'simple_vec_byref_const' or arg_type == 'bool_vec_byref_const' or \ arg_type == 'refptr_vec_same_byref_const' or arg_type == 'refptr_vec_diff_byref_const' or \ arg_type == 'rawptr_vec_same_byref_const' or arg_type == 'rawptr_vec_diff_byref_const': vec_type = arg.get_type().get_vector_type() if arg_type == 'simple_vec_byref_const': assign = arg_name + '[i]' elif arg_type == 'bool_vec_byref_const': assign = arg_name + '[i]?true:false' else: ptr_class = arg.get_type().get_ptr_type() if arg_type == 'refptr_vec_same_byref_const': assign = ptr_class + 'CppToC_Unwrap(' + arg_name + '[i])' elif arg_type == 'refptr_vec_diff_byref_const': assign = ptr_class + 'CToCpp_Wrap(' + arg_name + '[i])' elif arg_type == 'rawptr_vec_same_byref_const': assign = ptr_class + 'CppToC_UnwrapRaw(' + arg_name + '[i])' elif arg_type == 'rawptr_vec_diff_byref_const': assign = ptr_class + 'CToCpp_Wrap(' + arg_name + '[i]).release()' result += comment+\ '\n std::vector<'+vec_type+' > '+arg_name+'List;'\ '\n if ('+arg_name+'Count > 0) {'\ '\n for (size_t i = 0; i < '+arg_name+'Count; ++i) {'\ '\n '+vec_type+' '+arg_name+'Val = '+assign+';'\ '\n '+arg_name+'List.push_back('+arg_name+'Val);'\ '\n }'\ '\n }' params.append(arg_name + 'List') else: raise Exception('Unsupported argument type %s for parameter %s in %s' % (arg_type, arg_name, name)) if len(result) != result_len: result += '\n' result_len = len(result) # execution result += '\n // Execute\n ' if retval_type != 'none': # has a return value if retval_type == 'simple' or retval_type == 'simple_byaddr': result += retval.get_type().get_result_simple_type() else: result += retval.get_type().get_type() result += ' _retval = ' if isinstance(func.parent, obj_class): # virtual and static class methods if isinstance(func, obj_function_virtual): ptr_class = cls.get_name() if not version_finder is None: ptr_class = version_finder(ptr_class, as_cpp=True) if cls.get_name() == func.parent.get_name(): # virtual method called for the current class result += ptr_class + 'CppToC::Get(self)->' else: # virtual method called for a parent class result += ptr_class + 'CppToC::Get(reinterpret_cast<' + cls.get_capi_name( version) + '*>(self))->' else: result += func.parent.get_name() + '::' result += func.get_name() + '(' if len(params) > 0: result += '\n ' + ',\n '.join(params) result += ');\n' if is_cef_shutdown: result += '\n\n#if DCHECK_IS_ON()'\ '\n shutdown_checker::SetIsShutdown();'\ '\n#endif\n' result_len = len(result) # parameter restoration for arg in args: arg_type = arg.get_arg_type() arg_name = arg.get_type().get_name() comment = '\n // Restore param: ' + arg_name + '; type: ' + arg_type if arg_type == 'simple_byref': result += comment+\ '\n if ('+arg_name+') {'\ '\n *'+arg_name+' = '+arg_name+'Val;'\ '\n }' elif arg_type == 'bool_byref' or arg_type == 'bool_byaddr': result += comment+\ '\n if ('+arg_name+') {'\ '\n *'+arg_name+' = '+arg_name+'Bool?true:false;'\ '\n }' elif arg_type == 'struct_byref': result += comment+\ '\n if ('+arg_name+') {'\ '\n '+arg_name+'Obj.DetachTo(*'+arg_name+');'\ '\n }' elif arg_type == 'refptr_same_byref' or arg_type == 'refptr_diff_byref': ptr_class = arg.get_type().get_ptr_type() if arg_type == 'refptr_same_byref': assign = ptr_class + 'CppToC_Wrap(' + arg_name + 'Ptr)' else: assign = ptr_class + 'CToCpp_Unwrap(' + arg_name + 'Ptr)' result += comment+\ '\n if ('+arg_name+') {'\ '\n if ('+arg_name+'Ptr.get()) {'\ '\n if ('+arg_name+'Ptr.get() != '+arg_name+'Orig) {'\ '\n *'+arg_name+' = '+assign+';'\ '\n }'\ '\n } else {'\ '\n *'+arg_name+' = nullptr;'\ '\n }'\ '\n }' elif arg_type == 'string_vec_byref': result += comment+\ '\n cef_string_list_clear('+arg_name+');'\ '\n transfer_string_list_contents('+arg_name+'List, '+arg_name+');' elif arg_type == 'string_map_single_byref': result += comment+\ '\n cef_string_map_clear('+arg_name+');'\ '\n transfer_string_map_contents('+arg_name+'Map, '+arg_name+');' elif arg_type == 'string_map_multi_byref': result += comment+\ '\n cef_string_multimap_clear('+arg_name+');'\ '\n transfer_string_multimap_contents('+arg_name+'Multimap, '+arg_name+');' elif arg_type == 'simple_vec_byref' or arg_type == 'bool_vec_byref' or \ arg_type == 'refptr_vec_same_byref' or arg_type == 'refptr_vec_diff_byref': if arg_type == 'simple_vec_byref' or arg_type == 'bool_vec_byref': assign = arg_name + 'List[i]' elif arg_type == 'refptr_vec_same_byref': ptr_class = arg.get_type().get_ptr_type() assign = ptr_class + 'CppToC_Wrap(' + arg_name + 'List[i])' elif arg_type == 'refptr_vec_diff_byref': ptr_class = arg.get_type().get_ptr_type() assign = ptr_class + 'CToCpp_Unwrap(' + arg_name + 'List[i])' result += comment+\ '\n if ('+arg_name+'Count && '+arg_name+') {'\ '\n *'+arg_name+'Count = std::min('+arg_name+'List.size(), *'+arg_name+'Count);'\ '\n if (*'+arg_name+'Count > 0) {'\ '\n for (size_t i = 0; i < *'+arg_name+'Count; ++i) {'\ '\n '+arg_name+'[i] = '+assign+';'\ '\n }'\ '\n }'\ '\n }' elif arg_type == 'rawptr_vec_diff_byref_const': result += comment+\ '\n if ('+arg_name+'Count > 0) {'\ '\n for (size_t i = 0; i < '+arg_name+'Count; ++i) {'\ '\n delete '+arg_name+'List[i];'\ '\n }'\ '\n }' if len(result) != result_len: result += '\n' result_len = len(result) if len(result) != result_len: result += '\n' result_len = len(result) # return translation if retval_type != 'none': # has a return value result += '\n // Return type: ' + retval_type if retval_type == 'simple' or retval_type == 'simple_byaddr' or retval_type == 'bool': result += '\n return _retval;' elif retval_type == 'string': result += '\n return _retval.DetachToUserFree();' elif retval_type == 'refptr_same': ptr_class = retval.get_type().get_ptr_type() result += '\n return ' + ptr_class + 'CppToC_Wrap(_retval);' elif retval_type == 'refptr_diff': ptr_class = retval.get_type().get_ptr_type() result += '\n return ' + ptr_class + 'CToCpp_Unwrap(_retval);' elif retval_type == 'ownptr_same': ptr_class = retval.get_type().get_ptr_type() result += '\n return ' + ptr_class + 'CppToC_WrapOwn(std::move(_retval));' elif retval_type == 'ownptr_diff': ptr_class = retval.get_type().get_ptr_type() result += '\n return ' + ptr_class + 'CToCpp_UnwrapOwn(std::move(_retval));' else: raise Exception('Unsupported return type %s in %s' % (retval_type, name)) if len(result) != result_len: result += '\n' result += '}\n' return result def make_cpptoc_function_impl(cls, funcs, existing, prefixname, suffixname, defined_names, base_scoped, version, version_finder): impl = '' customized = False for func in funcs: if not version is None and isinstance(func, obj_function_virtual) and \ not func.exists_at_version(version): continue name = func.get_capi_name() if not prefixname is None: name = prefixname + '_' + name if not suffixname is None: name += '_' + suffixname if version is None: pre, post = get_version_surround(func, long=True) else: pre = post = '' value = get_next_function_impl(existing, name) if not value is None \ and value['body'].find('// AUTO-GENERATED CONTENT') < 0: # an implementation exists that was not auto-generated customized = True impl += pre + make_cpptoc_function_impl_existing( cls, name, func, value, defined_names, version, version_finder) + post + '\n' else: impl += pre + make_cpptoc_function_impl_new( cls, name, func, defined_names, base_scoped, version, version_finder) + post + '\n' if not customized and impl.find('// COULD NOT IMPLEMENT') >= 0: customized = True return (impl, customized) def make_cpptoc_virtual_function_impl(header, cls, existing, prefixname, suffixname, defined_names, base_scoped, version, version_finder): # don't modify the original list funcs = copy.copy(cls.get_virtual_funcs(version=version)) cur_cls = cls while True: parent_name = cur_cls.get_parent_name() if is_base_class(parent_name): break else: parent_cls = header.get_class(parent_name) if parent_cls is None: raise Exception('Class does not exist: ' + parent_name) defined_names.append(parent_cls.get_capi_name(version)) funcs.extend(parent_cls.get_virtual_funcs(version=version)) cur_cls = header.get_class(parent_name) defined_names.append(cur_cls.get_capi_name(version)) return make_cpptoc_function_impl(cls, funcs, existing, prefixname, suffixname, defined_names, base_scoped, version, version_finder) def make_cpptoc_virtual_function_assignment_block(cls, offset, prefixname, suffixname, version): impl = '' funcs = cls.get_virtual_funcs(version_order=True, version=version) for func in funcs: # should only include methods directly declared in the current class assert func.parent.get_name() == cls.get_name(), func.get_name() if version is None: pre, post = get_version_surround(func) else: if func.removed_at_version(version): continue pre = post = '' name = oname = func.get_capi_name() if not prefixname is None: name = prefixname + '_' + name if not suffixname is None: name += '_' + suffixname impl += pre + ' GetStruct()->' + offset + oname + ' = ' + name + ';\n' + post return impl def make_cpptoc_virtual_function_assignment(header, cls, prefixname, suffixname, defined_names, version, version_finder): impl = make_cpptoc_virtual_function_assignment_block(cls, '', prefixname, suffixname, version) cur_cls = cls offset = '' while True: parent_name = cur_cls.get_parent_name() offset += 'base.' if is_base_class(parent_name): break else: parent_cls = header.get_class(parent_name) if parent_cls is None: raise Exception('Class does not exist: ' + parent_name) defined_names.append(parent_cls.get_capi_name(version)) impl += make_cpptoc_virtual_function_assignment_block( parent_cls, offset, prefixname, suffixname, version) cur_cls = header.get_class(parent_name) defined_names.append(cur_cls.get_capi_name(version)) return impl def make_cpptoc_unwrap_derived(header, cls, base_scoped, version): # identify all classes that derive from cls derived_classes = [] cur_clsname = cls.get_name() allclasses = header.get_classes() for cur_cls in allclasses: if cur_cls.get_name() == cur_clsname: continue if cur_cls.has_parent(cur_clsname): derived_classes.append(cur_cls.get_name()) derived_classes = sorted(derived_classes) if base_scoped: impl = ['', ''] for clsname in derived_classes: derived_cls = header.get_class(clsname) if version is None: capiname = derived_cls.get_capi_name() pre, post = get_version_surround(derived_cls) else: if not derived_cls.exists_at_version(version): continue capiname = derived_cls.get_capi_name(first_version=True) pre = post = '' impl[0] += pre + ' if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\ ' return '+clsname+'CppToC_UnwrapOwn(reinterpret_cast<'+capiname+'*>(s));\n'+\ ' }\n' + post impl[1] += pre + ' if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\ ' return '+clsname+'CppToC_UnwrapRaw(reinterpret_cast<'+capiname+'*>(s));\n'+\ ' }\n' + post else: impl = '' for clsname in derived_classes: derived_cls = header.get_class(clsname) if version is None: capiname = derived_cls.get_capi_name() pre, post = get_version_surround(derived_cls) else: if not derived_cls.exists_at_version(version): continue capiname = derived_cls.get_capi_name(first_version=True) pre = post = '' impl += pre + ' if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\ ' return '+clsname+'CppToC_Unwrap(reinterpret_cast<'+capiname+'*>(s));\n'+\ ' }\n' + post return impl def make_cpptoc_version_wrappers(header, cls, base_scoped, versions): assert len(versions) > 0 clsname = cls.get_name() typename = clsname + 'CppToC' structname = cls.get_capi_name(version=versions[0]) rversions = sorted(versions, reverse=True) notreached = format_notreached( True, '" called with invalid version " << version', default_retval='nullptr') impl = '' if base_scoped: impl += structname + '* ' + typename + '_WrapOwn(CefOwnPtr<' + clsname + '> c) {\n' + \ ' const int version = cef_api_version();\n' for version in rversions: vstr = str(version) impl += ' if (version >= ' + vstr + ') {\n' if versions[0] == version: impl += ' return ' + clsname + '_' + vstr + '_CppToC::WrapOwn(std::move(c));\n' else: impl += ' return reinterpret_cast<' + structname + '*>(' + clsname + '_' + vstr + '_CppToC::WrapOwn(std::move(c)));\n' impl += ' }\n' impl += ' ' + notreached + '\n'+ \ '}\n\n' + \ 'std::pair, '+ structname + '*> ' + typename + '_WrapRaw(CefRawPtr<' + clsname + '> c) {\n' + \ ' const int version = cef_api_version();\n' for version in rversions: vstr = str(version) impl += ' if (version >= ' + vstr + ') {\n' if versions[0] == version: impl += ' return ' + clsname + '_' + vstr + '_CppToC::WrapRaw(std::move(c));\n' else: impl += ' auto [ownPtr, structPtr] = ' + clsname + '_' + vstr + '_CppToC::WrapRaw(std::move(c));\n' + \ ' return std::make_pair(std::move(ownPtr), reinterpret_cast<' + structname + '*>(structPtr));\n' impl += ' }\n' impl += ' ' + notreached + '\n'+ \ '}\n\n' + \ 'CefOwnPtr<' + clsname + '> ' + typename + '_UnwrapOwn('+ structname + '* s) {\n' + \ ' const int version = cef_api_version();\n' for version in rversions: vstr = str(version) impl += ' if (version >= ' + vstr + ') {\n' if versions[0] == version: impl += ' return ' + clsname + '_' + vstr + '_CppToC::UnwrapOwn(s);\n' else: impl += ' return ' + clsname + '_' + vstr + '_CppToC::UnwrapOwn(reinterpret_cast<' + cls.get_capi_name( version) + '*>(s));\n' impl += ' }\n' impl += ' ' + notreached + '\n'+ \ '}\n\n' + \ 'CefRawPtr<' + clsname + '> ' + typename + '_UnwrapRaw('+ structname + '* s) {\n' + \ ' const int version = cef_api_version();\n' for version in rversions: vstr = str(version) impl += ' if (version >= ' + vstr + ') {\n' if versions[0] == version: impl += ' return ' + clsname + '_' + vstr + '_CppToC::UnwrapRaw(s);\n' else: impl += ' return ' + clsname + '_' + vstr + '_CppToC::UnwrapRaw(reinterpret_cast<' + cls.get_capi_name( version) + '*>(s));\n' impl += ' }\n' impl += ' ' + notreached + '\n'+ \ '}\n\n' + \ 'CefBaseScoped* ' + typename + '_GetWrapper('+ structname + '* s) {\n' + \ ' const int version = cef_api_version();\n' for version in rversions: vstr = str(version) impl += ' if (version >= ' + vstr + ') {\n' if versions[0] == version: impl += ' return ' + clsname + '_' + vstr + '_CppToC::GetWrapper(s);\n' else: impl += ' return ' + clsname + '_' + vstr + '_CppToC::GetWrapper(reinterpret_cast<' + cls.get_capi_name( version) + '*>(s));\n' impl += ' }\n' impl += ' ' + notreached + '\n'+ \ '}\n' else: impl += structname + '* ' + typename + '_Wrap(CefRefPtr<' + clsname + '> c) {\n' + \ ' const int version = cef_api_version();\n' for version in rversions: vstr = str(version) impl += ' if (version >= ' + vstr + ') {\n' if versions[0] == version: impl += ' return ' + clsname + '_' + vstr + '_CppToC::Wrap(c);\n' else: impl += ' return reinterpret_cast<' + structname + '*>(' + clsname + '_' + vstr + '_CppToC::Wrap(c));\n' impl += ' }\n' impl += ' ' + notreached + '\n'+ \ '}\n\n' + \ 'CefRefPtr<' + clsname + '> ' + typename + '_Unwrap('+ structname + '* s) {\n' + \ ' const int version = cef_api_version();\n' for version in rversions: vstr = str(version) impl += ' if (version >= ' + vstr + ') {\n' if versions[0] == version: impl += ' return ' + clsname + '_' + vstr + '_CppToC::Unwrap(s);\n' else: impl += ' return ' + clsname + '_' + vstr + '_CppToC::Unwrap(reinterpret_cast<' + cls.get_capi_name( version) + '*>(s));\n' impl += ' }\n' impl += ' ' + notreached + '\n'+ \ '}\n' return impl + '\n' def _version_finder(header, version, name, as_cpp=False): assert version is None or isinstance(version, int), version assert name[-1] != '*', name if as_cpp: cls = header.get_class(name) if cls is None: return name return cls.get_name(version=version) cls = header.get_capi_class(name) if not cls is None: return cls.get_capi_name(first_version=True) return name def make_cpptoc_class_impl(header, clsname, impl): # structure names that have already been defined defined_names = header.get_defined_structs() # retrieve the class and populate the defined names cls = header.get_class(clsname) if cls is None: raise Exception('Class does not exist: ' + clsname) prefixname = get_capi_name(clsname[3:], False) base_class_name = header.get_base_class_name(clsname) base_scoped = True if base_class_name == 'CefBaseScoped' else False if base_scoped: template_class = 'CefCppToCScoped' else: template_class = 'CefCppToCRefCounted' with_versions = cls.is_library_side() versions = list(cls.get_all_versions()) if with_versions else (None,) # retrieve the existing static function implementations existing_static = get_function_impls(impl, 'CEF_EXPORT') # retrieve the existing virtual function implementations existing_virtual = get_function_impls(impl, 'CEF_CALLBACK') staticout = virtualout = '' customized = False first = True idx = 0 for version in versions: version_finder = functools.partial(_version_finder, header, version) if with_versions else None defined_names.append(cls.get_capi_name(version=version)) if first: first = False # generate static functions staticimpl, scustomized = make_cpptoc_function_impl( cls, cls.get_static_funcs(), existing_static, None, None, defined_names, base_scoped, version, version_finder) if len(staticimpl) > 0: staticout += '// GLOBAL FUNCTIONS - Body may be edited by hand.\n\n' + staticimpl if scustomized: customized = True if len(versions) > 1: staticout += '// HELPER FUNCTIONS - Do not edit by hand.\n\n' staticout += make_cpptoc_version_wrappers(header, cls, base_scoped, versions) comment = '' if version is None else (' FOR VERSION %d' % version) suffixname = str(version) if (len(versions) > 1 and version > 0) else None # generate virtual functions virtualimpl, vcustomized = make_cpptoc_virtual_function_impl( header, cls, existing_virtual, prefixname, suffixname, defined_names, base_scoped, version, version_finder) if len(virtualimpl) > 0: virtualout += 'namespace {\n\n// MEMBER FUNCTIONS' + comment + ' - Body may be edited by hand.\n\n' + \ virtualimpl + '} // namespace\n\n' if vcustomized: customized = True # any derived classes can be unwrapped unwrapderived = make_cpptoc_unwrap_derived(header, cls, base_scoped, version) capiname = cls.get_capi_name(version=version) typename = cls.get_name(version=version) + 'CppToC' const = '// CONSTRUCTOR' + comment + ' - Do not edit by hand.\n\n'+ \ typename+'::'+typename+'() {\n' if not version is None: if idx < len(versions) - 1: condition = 'version < %d || version >= %d' % (version, versions[idx + 1]) else: condition = 'version < %d' % version const += ' const int version = cef_api_version();\n' + \ ' LOG_IF(FATAL, ' + condition + ') << __func__ << " called with invalid version " << version;\n\n' const += make_cpptoc_virtual_function_assignment(header, cls, prefixname, suffixname, defined_names, version, version_finder) const += '}\n\n'+ \ '// DESTRUCTOR' + comment + ' - Do not edit by hand.\n\n'+ \ typename+'::~'+typename+'() {\n' if not cls.has_attrib('no_debugct_check') and not base_scoped: const += ' shutdown_checker::AssertNotShutdown();\n' const += '}\n\n' parent_sig = template_class + '<' + typename + ', ' + clsname + ', ' + capiname + '>' notreached = format_notreached( with_versions, '" called with unexpected class type " << type', default_retval='nullptr') if base_scoped: const += 'template<> CefOwnPtr<'+clsname+'> '+parent_sig+'::UnwrapDerivedOwn(CefWrapperType type, '+capiname+'* s) {\n' + \ unwrapderived[0] + \ ' ' + notreached + '\n'+ \ '}\n\n' + \ 'template<> CefRawPtr<'+clsname+'> '+parent_sig+'::UnwrapDerivedRaw(CefWrapperType type, '+capiname+'* s) {\n' + \ unwrapderived[1] + \ ' ' + notreached + '\n'+ \ '}\n\n' else: const += 'template<> CefRefPtr<'+clsname+'> '+parent_sig+'::UnwrapDerived(CefWrapperType type, '+capiname+'* s) {\n' + \ unwrapderived + \ ' ' + notreached + '\n'+ \ '}\n\n' const += 'template<> CefWrapperType ' + parent_sig + '::kWrapperType = ' + get_wrapper_type_enum( clsname) + ';\n\n' virtualout += const idx += 1 out = staticout + virtualout # determine what includes are required by identifying what translation # classes are being used includes = format_translation_includes( header, out + (unwrapderived[0] if base_scoped else unwrapderived), with_versions=with_versions) # build the final output result = get_copyright() result += includes + '\n' if with_versions: pre = post = '' else: pre, post = get_version_surround(cls, long=True) if len(pre) > 0: result += pre + '\n' result += out + '\n' if len(post) > 0: result += post + '\n' return (result, customized) def make_cpptoc_global_impl(header, impl): # structure names that have already been defined defined_names = header.get_defined_structs() # retrieve the existing global function implementations existing = get_function_impls(impl, 'CEF_EXPORT') version_finder = functools.partial(_version_finder, header, None) # generate global functions impl, customized = make_cpptoc_function_impl(None, header.get_funcs(), existing, None, None, defined_names, False, None, version_finder) if len(impl) > 0: impl = '\n// GLOBAL FUNCTIONS - Body may be edited by hand.\n\n' + impl includes = '' # include required headers for global functions paths = set() for func in header.get_funcs(): filename = func.get_file_name() paths.add('include/' + func.get_file_name()) paths.add('include/capi/' + func.get_capi_file_name(versions=True)) # determine what includes are required by identifying what translation # classes are being used includes += format_translation_includes( header, impl, with_versions=True, other_includes=paths) # build the final output result = get_copyright() result += includes + '\n' + impl return (result, customized) def write_cpptoc_impl(header, clsname, dir): if clsname is None: # global file file = dir else: # class file # give the output file the same directory offset as the input file cls = header.get_class(clsname) dir = os.path.dirname(os.path.join(dir, cls.get_file_name())) file = os.path.join(dir, get_capi_name(clsname[3:], False) + '_cpptoc.cc') set_notify_context(file) if path_exists(file): oldcontents = read_file(file) else: oldcontents = '' if clsname is None: newcontents, customized = make_cpptoc_global_impl(header, oldcontents) else: newcontents, customized = make_cpptoc_class_impl(header, clsname, oldcontents) set_notify_context(None) return (file, newcontents, customized) # test the module if __name__ == "__main__": import sys # verify that the correct number of command-line arguments are provided if len(sys.argv) < 4: sys.stderr.write('Usage: ' + sys.argv[0] + ' ') sys.exit() # create the header object header = obj_header() header.add_file(sys.argv[1]) # read the existing implementation file into memory try: with open(sys.argv[3], 'r') as f: data = f.read() except IOError as e: (errno, strerror) = e.args raise Exception('Failed to read file ' + sys.argv[3] + ': ' + strerror) else: f.close() # dump the result to stdout sys.stdout.write(make_cpptoc_class_impl(header, sys.argv[2], data))