1#!/usr/bin/env python3 2# -*- coding: utf-8 -*- 3 4# Copyright (c) 2024 Huawei Device Co., Ltd. 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17from __future__ import absolute_import 18 19import os 20import file_parser 21import make_file_base 22 23 24# pylint:disable=variable-type-changed 25# pylint:disable=huawei-redefined-outer-name 26 27def make_cpptoc_impl_proto(name, func, parts, flag): 28 if isinstance(func, file_parser.obj_function_virtual): 29 proto = parts['retval'] + ' ARK_WEB_CALLBACK' 30 elif flag: 31 proto = 'ARK_WEB_EXPORT ' + parts['retval'] 32 else: 33 proto = parts['retval'] 34 35 proto += ' ' + name + '(' + ', '.join(parts['args']) + ')' 36 return proto 37 38 39def verify_cpptoc_func_args(func, retval_default, macro_retval_default): 40 result = '' 41 if isinstance(func, file_parser.obj_function_virtual): 42 result += '\n ARK_WEB_CPPTOC_DV_LOG(\"capi struct is %{public}ld\", (long)self);\n' + \ 43 '\n ARK_WEB_CPPTOC_CHECK_PARAM(self, ' + macro_retval_default + ');' 44 45 args = func.get_arguments() 46 for arg in args: 47 arg_type = arg.get_arg_type() 48 arg_name = arg.get_type().get_name() 49 comment = '\n // Verify param: ' + arg_name + '; type: ' + arg_type 50 51 if arg_type == 'bool_byref' or arg_type == 'bool_byref_const' or arg_type == 'simple_byref' or \ 52 arg_type == 'simple_byref_const' or arg_type == 'struct_byref' or arg_type == 'struct_byref_const' or \ 53 arg_type == 'refptr_diff_byref': 54 result += '\n ARK_WEB_CPPTOC_CHECK_PARAM(' + arg_name + ', ' + macro_retval_default + ');' 55 if arg_type == 'struct_byref_const' or arg_type == 'struct_byref': 56 result += '\n if (!template_util::has_valid_size(' + arg_name + ')) {' + \ 57 '\n return' + retval_default + ';' + \ 58 '\n }' 59 60 # check index params 61 index_params = arg.parent.get_attrib_list('index_param') 62 if not index_params is None and arg_name in index_params: 63 result += comment + \ 64 '\n if (' + arg_name + ' < 0) {' + \ 65 '\n return' + retval_default + ';' + \ 66 '\n }' 67 return result 68 69 70def restore_cpptoc_func_args(func): 71 result = '' 72 args = func.get_arguments() 73 for arg in args: 74 arg_type = arg.get_arg_type() 75 arg_name = arg.get_type().get_name() 76 comment = '\n // Restore param: ' + arg_name + '; type: ' + arg_type 77 78 if arg_type == 'struct_byref': 79 result += comment + \ 80 '\n if (' + arg_name + ') {' + \ 81 '\n ' + arg_name + 'Obj.DetachTo(*' + arg_name + ');' + \ 82 '\n }' 83 elif arg_type == 'refptr_same_byref' or arg_type == 'refptr_diff_byref': 84 ptr_class = arg.get_type().get_ptr_type() 85 if arg_type == 'refptr_same_byref': 86 assign = ptr_class + 'CppToC::Invert(' + arg_name + 'Ptr)' 87 else: 88 assign = ptr_class + 'CToCpp::Revert(' + arg_name + 'Ptr)' 89 result += comment + \ 90 '\n if (' + arg_name + ') {' + \ 91 '\n if (' + arg_name + 'Ptr.get()) {' + \ 92 '\n if (' + arg_name + 'Ptr.get() != ' + arg_name + 'Orig) {' + \ 93 '\n *' + arg_name + ' = ' + assign + ';' + \ 94 '\n }' + \ 95 '\n } else {' + \ 96 '\n *' + arg_name + ' = nullptr;' + \ 97 '\n }' + \ 98 '\n }' 99 return result; 100 101 102def translate_cpptoc_func_args(func): 103 result = '' 104 params = [] 105 args = func.get_arguments() 106 for arg in args: 107 arg_type = arg.get_arg_type() 108 arg_name = arg.get_type().get_name() 109 comment = ' // Translate param: ' + arg_name + '; type: ' + arg_type 110 111 if arg_type == 'simple_byval' or arg_type == 'simple_byaddr': 112 if arg_name[0] == '*': 113 params.append(arg_name[1:]) 114 else: 115 pos = arg_name.find('[') 116 if pos == -1: 117 params.append(arg_name) 118 else: 119 params.append(arg_name[0:pos]) 120 elif arg_type == 'simple_byref' or arg_type == 'simple_byref_const': 121 params.append('*' + arg_name) 122 elif arg_type == 'bool_byval': 123 params.append(arg_name) 124 elif arg_type == 'bool_byref' or arg_type == 'bool_byaddr': 125 params.append('*' + arg_name) 126 elif arg_type == 'struct_byref_const': 127 struct_type = arg.get_type().get_type() 128 result += comment + \ 129 '\n ' + struct_type + ' ' + arg_name + 'Obj;' + \ 130 '\n if (' + arg_name + ') {' + \ 131 '\n ' + arg_name + 'Obj.Set(*' + arg_name + ', false);' + \ 132 '\n }' 133 params.append(arg_name + 'Obj') 134 elif arg_type == 'struct_byref': 135 struct_type = arg.get_type().get_type() 136 result += comment + \ 137 '\n ' + struct_type + ' ' + arg_name + 'Obj;' + \ 138 '\n if (' + arg_name + ') {' + \ 139 '\n ' + arg_name + 'Obj.AttachTo(*' + arg_name + ');' + \ 140 '\n }' 141 params.append(arg_name + 'Obj') 142 elif arg_type == 'refptr_same' or arg_type == 'refptr_diff': 143 ptr_class = arg.get_type().get_ptr_type() 144 if arg_type == 'refptr_same': 145 params.append(ptr_class + 'CppToC::Revert(' + arg_name + ')') 146 else: 147 params.append(ptr_class + 'CToCpp::Invert(' + arg_name + ')') 148 elif arg_type == 'refptr_same_byref' or arg_type == 'refptr_diff_byref': 149 ptr_class = arg.get_type().get_ptr_type() 150 if arg_type == 'refptr_same_byref': 151 assign = ptr_class + 'CppToC::Revert(*' + arg_name + ')' 152 else: 153 assign = ptr_class + 'CToCpp::Invert(*' + arg_name + ')' 154 result += comment + \ 155 '\n ArkWebRefPtr<' + ptr_class + '> ' + arg_name + 'Ptr;' + \ 156 '\n if (' + arg_name + ' && *' + arg_name + ') {' + \ 157 '\n ' + arg_name + 'Ptr = ' + assign + ';' + \ 158 '\n }' + \ 159 '\n ' + ptr_class + '* ' + arg_name + 'Orig = ' + arg_name + 'Ptr.get();' 160 params.append(arg_name + 'Ptr') 161 else: 162 raise Exception('Unsupported argument type %s for parameter %s in %s' % 163 (arg_type, arg_name, name)) 164 return result, params 165 166 167def make_cpptoc_function_impl(cls, name, func, defined_names): 168 # retrieve the C API prototype parts 169 parts = func.get_capi_parts(defined_names, True) 170 result = make_cpptoc_impl_proto(name, func, parts, False) + ' {' 171 172 invalid = make_file_base.get_func_invalid_info(name, func) 173 if len(invalid) > 0: 174 return result + invalid 175 176 retval = func.get_retval() 177 retval_default = retval.get_retval_default(True) 178 if len(retval_default) > 0: 179 retval_default = ' ' + retval_default 180 macro_retval_default = retval_default 181 else: 182 macro_retval_default = 'ARK_WEB_RETURN_VOID' 183 result_len = len(result) 184 185 # parameter verification 186 result += verify_cpptoc_func_args(func, retval_default, macro_retval_default) 187 if len(result) != result_len: 188 result += '\n' 189 result_len = len(result) 190 191 # parameter translation 192 trans, params = translate_cpptoc_func_args(func) 193 if len(trans) != 0: 194 result += trans + '\n' 195 196 # execution 197 result += '\n // Execute\n ' 198 199 retval_type = retval.get_retval_type() 200 if retval_type != 'none': 201 # has a return value 202 if retval_type == 'simple' or retval_type == 'bool' or retval_type == 'void*' or \ 203 retval_type == 'uint8_t*' or retval_type == 'uint32_t*' or retval_type == 'char*' or \ 204 file_parser.check_arg_type_is_struct(retval_type): 205 result += 'return ' 206 else: 207 result += retval.get_type().get_type() + ' _retval = ' 208 209 if isinstance(func.parent, file_parser.obj_class): 210 parent_clsname = func.parent.get_name() 211 if isinstance(func, file_parser.obj_function_virtual): 212 if cls.get_name() == parent_clsname: 213 result += parent_clsname + 'CppToC::Get(self)->' 214 else: 215 result += cls.get_name() + 'CppToC::Get(reinterpret_cast<' + cls.get_capi_name() + '*>(self))->' 216 else: 217 result += parent_clsname + '::' 218 result += func.get_name() + '(' 219 220 if len(params) > 0: 221 result += '\n ' + ',\n '.join(params) 222 result += ');\n' 223 result_len = len(result) 224 225 # parameter restoration 226 result += restore_cpptoc_func_args(func) 227 if len(result) != result_len: 228 result += '\n' 229 result_len = len(result) 230 231 if retval_type == 'refptr_same': 232 result += '\n // Return type: ' + retval_type + \ 233 '\n return ' + retval.get_type().get_ptr_type() + 'CppToC::Invert(_retval);' 234 elif retval_type == 'refptr_diff': 235 result += '\n // Return type: ' + retval_type + \ 236 '\n return ' + retval.get_type().get_ptr_type() + 'CToCpp::Revert(_retval);' 237 238 if len(result) != result_len: 239 result += '\n' 240 241 result += '}\n\n' 242 return result 243 244 245def make_cpptoc_function_body(cls, funcs, prefix, defined_names): 246 new_list = [] 247 old_list = make_file_base.get_func_name_list(funcs) 248 249 impl = '' 250 for func in funcs: 251 suffix = '' 252 new_list = make_file_base.get_func_name_count(func.get_capi_name(), old_list, new_list) 253 if new_list.count(func.get_capi_name()) != 0: 254 suffix = str(new_list.count(func.get_capi_name())) 255 256 name, _ = make_file_base.get_func_pointer_name(cls, func, prefix, suffix) 257 impl += make_cpptoc_function_impl(cls, name, func, defined_names) 258 return impl 259 260 261def cpptoc_make_function_assign(cls, prefix, header): 262 funcs = make_file_base.get_class_func_list(cls, header); 263 new_list = [] 264 old_list = make_file_base.get_func_name_list(funcs) 265 266 insert = '' 267 assign = '' 268 for func in funcs: 269 suffix = '' 270 new_list = make_file_base.get_func_name_count(func.get_capi_name(), old_list, new_list) 271 if new_list.count(func.get_capi_name()) != 0: 272 suffix = str(new_list.count(func.get_capi_name())) 273 274 hash_name = make_file_base.get_func_hash_name(func, prefix) 275 var_name = make_file_base.get_func_variable_name(func, suffix) 276 func_name, _ = make_file_base.get_func_pointer_name(cls, func, prefix, suffix) 277 insert += ' funcMemberMap[\"' + hash_name + '\"] = reinterpret_cast<void*>(' + func_name + ');\n ' 278 assign += ' GetStruct()->' + var_name + ' = ' + func_name + ';\n' 279 return assign, insert 280 281 282def make_cpptoc_static_function_impl(cls, funcs, defined_names): 283 new_list = [] 284 old_list = make_file_base.get_func_name_list(funcs) 285 286 impl = '#ifdef __cplusplus\nextern "C" {\n#endif // __cplusplus\n\n' 287 for func in funcs: 288 suffix = '' 289 new_list = make_file_base.get_func_name_count(func.get_capi_name(), old_list, new_list) 290 if new_list.count(func.get_capi_name()) != 0: 291 suffix = str(new_list.count(func.get_capi_name())) 292 parts = func.get_capi_parts(defined_names, True) 293 func_name, _ = make_file_base.get_func_pointer_name(cls, func, '', suffix) 294 impl += make_cpptoc_impl_proto(func_name + '_static', func, parts, True) + ' {\n' + \ 295 ' ARK_WEB_CPPTOC_DV_LOG();\n\n' 296 297 retval = func.get_retval() 298 retval_type = retval.get_retval_type() 299 if retval_type != 'none': 300 impl += ' return ' 301 impl += 'OHOS::ArkWeb::' + func_name + '(' 302 303 params = [] 304 args = func.get_arguments() 305 for arg in args: 306 arg_name = arg.get_type().get_name() 307 params.append(arg_name) 308 309 if len(params) > 0: 310 impl += '\n ' + ',\n '.join(params) 311 impl += ');\n}\n\n' 312 313 impl += '#ifdef __cplusplus\n}\n#endif // __cplusplus' 314 return impl 315 316 317def cpptoc_make_unwrap_derived(cls, header, clsname): 318 impl = '' 319 derived_classes = make_file_base.get_derived_classes(cls, header) 320 for clsname in derived_classes: 321 impl += ' if (type == ' + file_parser.get_wrapper_type_enum(clsname) + ') {\n' + \ 322 ' return ' + clsname + 'CppToC::Revert(reinterpret_cast<' + \ 323 file_parser.get_capi_name(clsname, True) + '*>(s));\n' + \ 324 ' }\n' 325 return impl 326 327 328def cpptoc_make_include_file(cls, body, header, dir_name): 329 result = file_parser.format_translation_includes(header, dir_name, body) 330 result += '#include "base/cpptoc/ark_web_cpptoc_macros.h"\n' 331 if dir_name == 'ohos_nweb': 332 if cls.is_webview_side(): 333 result += '#include "ohos_nweb/bridge/ark_web_nweb_webview_bridge_helper.h"\n' 334 else: 335 result += '#include "ohos_nweb/bridge/ark_web_nweb_webcore_bridge_helper.h"\n' 336 else: 337 if cls.is_webview_side(): 338 result += '#include "ohos_adapter/bridge/ark_web_adapter_webview_bridge_helper.h"\n' 339 else: 340 result += '#include "ohos_adapter/bridge/ark_web_adapter_webcore_bridge_helper.h"\n' 341 return result 342 343 344def cpptoc_make_class_function(cls, prefix, header, dir_name): 345 assign, insert = cpptoc_make_function_assign(cls, prefix, header) 346 result = cls.get_name() + 'CppToC::' + cls.get_name() + 'CppToC() {' + \ 347 '\n' + assign + \ 348 '\n static std::once_flag flag;' + \ 349 '\n std::call_once(flag, [] {' + \ 350 '\n std::map<std::string, void*> funcMemberMap;' + \ 351 '\n ' + insert 352 if dir_name == 'ohos_nweb': 353 if cls.is_webview_side(): 354 result += ' ArkWebNWebWebviewBridgeHelper::GetInstance().RegisterFuncMember(' 355 else: 356 result += ' ArkWebNWebWebcoreBridgeHelper::GetInstance().RegisterFuncMember(' 357 else: 358 if cls.is_webview_side(): 359 result += ' ArkWebAdapterWebviewBridgeHelper::GetInstance().RegisterFuncMember(' 360 else: 361 result += ' ArkWebAdapterWebcoreBridgeHelper::GetInstance().RegisterFuncMember(' 362 result += file_parser.get_wrapper_type_enum(cls.get_name()) + ', funcMemberMap);\n });\n}\n' + \ 363 '\n' + cls.get_name() + 'CppToC::~' + cls.get_name() + 'CppToC() {\n}\n\n' 364 return result 365 366 367def cpptoc_make_c_function_body(cls, header, dir_name, defined_names): 368 funcs = make_file_base.get_class_func_list(cls, header) 369 prefix = file_parser.get_capi_name(cls.get_name(), False) 370 result = make_cpptoc_function_body(cls, funcs, prefix, defined_names) 371 if len(result) > 0: 372 result = make_cpptoc_function_body(cls, cls.get_static_funcs(), '', defined_names) + \ 373 'namespace {\n\n' + result + '} // namespace\n\n' + \ 374 cpptoc_make_class_function(cls, prefix, header, dir_name) 375 else: 376 result = make_cpptoc_function_body(cls, cls.get_static_funcs(), '', defined_names) + \ 377 cpptoc_make_class_function(cls, prefix, header, dir_name) 378 return result 379 380 381def make_cpptoc_impl_file(header, dir_path, dir_name, clsname): 382 defined_names = header.get_defined_structs() 383 cls = header.get_class(clsname, defined_names) 384 if cls is None: 385 raise Exception('Class does not exist: ' + clsname) 386 387 defined_names.append(cls.get_capi_name()) 388 function_body = cpptoc_make_c_function_body(cls, header, dir_name, defined_names) 389 390 unwrap_derived = cpptoc_make_unwrap_derived(cls, header, clsname) 391 include_file = cpptoc_make_include_file(cls, function_body + unwrap_derived, header, dir_name) 392 393 content = make_file_base.get_copyright() + '\n' + include_file + '\n' + \ 394 'namespace OHOS::ArkWeb {\n\n' + \ 395 function_body + '\n' + \ 396 '\n' + make_file_base.make_wrapper_type(cls, 'CppToC') + \ 397 '\n\n} // namespace OHOS::ArkWeb\n\n' 398 399 if len(cls.get_static_funcs()) > 0: 400 content += make_cpptoc_static_function_impl(cls, cls.get_static_funcs(), defined_names) 401 402 absolute_dir = os.path.join(os.path.join(dir_path, dir_name), 'cpptoc') 403 absolute_path = os.path.join(absolute_dir, file_parser.get_capi_name(clsname, False) + '_cpptoc.cpp') 404 return (content, absolute_path) 405