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 ctocpp_make_impl_proto(cls, func): 28 proto = 'ARK_WEB_NO_SANITIZE\n' 29 parts = func.get_cpp_parts(True) 30 if cls.get_name() is None: 31 proto += 'ARK_WEB_GLOBAL ' + parts['retval'] + ' ' + func.get_name() + '(' + ', '.join(parts['args']) + ') {' 32 else: 33 const = '' 34 proto += parts['retval'] + ' ' + cls.get_name() 35 if isinstance(func, file_parser.obj_function_virtual): 36 proto += 'CToCpp' 37 if func.is_const(): 38 const = ' const' 39 proto += '::' + func.get_name() + '(' + ', '.join(parts['args']) + ')' + const + ' {' 40 return proto 41 42 43def verify_ctocpp_func_args(func, retval_default): 44 result = '' 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_byaddr': 52 result += comment + \ 53 '\n if (!' + arg_name + ') {' + \ 54 '\n return' + retval_default + ';' + \ 55 '\n }' 56 57 # check index params 58 index_params = arg.parent.get_attrib_list('index_param') 59 if not index_params is None and arg_name in index_params: 60 result += comment + \ 61 '\n if (' + arg_name + ' < 0) {' + \ 62 '\n return' + retval_default + ';' + \ 63 '\n }' 64 return result 65 66 67def restore_ctocpp_func_args(func): 68 result = '' 69 args = func.get_arguments() 70 for arg in args: 71 arg_type = arg.get_arg_type() 72 arg_name = arg.get_type().get_name() 73 comment = '\n // Restore param:' + arg_name + '; type: ' + arg_type 74 75 if arg_type == 'bool_byaddr': 76 result += comment + \ 77 '\n if (' + arg_name + ') {' + \ 78 '\n *' + arg_name + ' = ' + arg_name + 'Int ? true : false;' + \ 79 '\n }' 80 elif arg_type == 'refptr_same_byref' or arg_type == 'refptr_diff_byref': 81 ptr_class = arg.get_type().get_ptr_type() 82 if arg_type == 'refptr_same_byref': 83 assign = ptr_class + 'CToCpp::Invert(' + arg_name + 'Struct)' 84 else: 85 assign = ptr_class + 'CppToC::Revert(' + arg_name + 'Struct)' 86 result += comment + \ 87 '\n if (' + arg_name + 'Struct) {' + \ 88 '\n if (' + arg_name + 'Struct != ' + arg_name + 'Orig) {' + \ 89 '\n ' + arg_name + ' = ' + assign + ';' + \ 90 '\n }' + \ 91 '\n } else {' + \ 92 '\n ' + arg_name + ' = nullptr;' + \ 93 '\n }' 94 return result; 95 96 97def translate_ctocpp_func_args(func): 98 params = [] 99 if isinstance(func, file_parser.obj_function_virtual): 100 params.append('_struct') 101 102 result = '' 103 args = func.get_arguments() 104 for arg in args: 105 arg_type = arg.get_arg_type() 106 arg_name = arg.get_type().get_name() 107 comment = '\n // Translate param: ' + arg_name + '; type: ' + arg_type 108 109 if arg_type == 'simple_byval' or arg_type == 'simple_byaddr' or arg_type == 'bool_byval': 110 if arg_name[0] == '*': 111 params.append(arg_name[1:]) 112 else: 113 pos = arg_name.find('[') 114 if pos == -1: 115 params.append(arg_name) 116 else: 117 params.append(arg_name[0:pos]) 118 elif arg_type == 'simple_byref' or arg_type == 'simple_byref_const' or \ 119 arg_type == 'struct_byref_const' or arg_type == 'struct_byref': 120 params.append('&' + arg_name) 121 elif arg_type == 'bool_byref': 122 params.append('&' + arg_name) 123 elif arg_type == 'bool_byaddr': 124 result += comment + '\n int ' + arg_name + 'Int = ' + arg_name + '?*' + arg_name + ':0;' 125 params.append('&' + arg_name + 'Int') 126 elif arg_type == 'refptr_same': 127 ptr_class = arg.get_type().get_ptr_type() 128 params.append(ptr_class + 'CToCpp::Revert(' + arg_name + ')') 129 elif arg_type == 'refptr_diff': 130 ptr_class = arg.get_type().get_ptr_type() 131 params.append(ptr_class + 'CppToC::Invert(' + arg_name + ')') 132 elif arg_type == 'refptr_same_byref' or arg_type == 'refptr_diff_byref': 133 ptr_class = arg.get_type().get_ptr_type() 134 ptr_struct = arg.get_type().get_result_ptr_type_root() 135 if arg_type == 'refptr_same_byref': 136 assign = ptr_class + 'CToCpp::Revert(' + arg_name + ')' 137 else: 138 assign = ptr_class + 'CppToC::Invert(' + arg_name + ')' 139 result += comment + \ 140 '\n ' + ptr_struct + '* ' + arg_name + 'Struct = NULL;' + \ 141 '\n if (' + arg_name + '.get()) {' + \ 142 '\n ' + arg_name + 'Struct = ' + assign + ';' + \ 143 '\n }' + \ 144 '\n ' + ptr_struct + '* ' + arg_name + 'Orig = ' + arg_name + 'Struct;' 145 params.append('&' + arg_name + 'Struct') 146 else: 147 raise Exception('Unsupported argument type %s for parameter %s in %s' % 148 (arg_type, arg_name, name)) 149 return result, params 150 151 152def ctocpp_make_static_param(cls, funcs, prefix): 153 new_list = [] 154 old_list = make_file_base.get_func_name_list(funcs) 155 156 impl = '' 157 for func in funcs: 158 new_list = make_file_base.get_func_name_count(func.get_capi_name(), old_list, new_list) 159 160 suffix = '' 161 if new_list.count(func.get_capi_name()) > 0: 162 suffix = str(new_list.count(func.get_capi_name())) 163 164 parts = func.get_capi_parts() 165 func_name, func_type = make_file_base.get_func_pointer_name(cls, func, prefix, suffix) 166 impl += 'using ' + func_type + ' = ' + parts['retval'] + ' (*)(' + ', '.join(parts['args']) + ');\n' + \ 167 'static ' + func_type + ' ' + func_name + ' = reinterpret_cast<' + func_type + '>(ARK_WEB_INIT_ADDR);\n\n' 168 return impl 169 170 171def ctocpp_make_static_params(cls, header): 172 prefix = file_parser.get_capi_name(cls.get_name(), False) 173 result = ctocpp_make_static_param(cls, cls.get_static_funcs(), '') 174 result += ctocpp_make_static_param(cls, make_file_base.get_class_func_list(cls, header), prefix) 175 return result 176 177 178def ctocpp_get_static_funcion(cls, func, suffix, dir_name, retval_default): 179 func_name, func_type = make_file_base.get_func_pointer_name(cls, func, '', suffix) 180 result = '\n ARK_WEB_CTOCPP_DV_LOG();\n' + \ 181 '\n void* func_pointer = reinterpret_cast<void*>(' + func_name + ');' + \ 182 '\n if (func_pointer == ARK_WEB_INIT_ADDR) {' + \ 183 '\n static const char* funcName = \"' + func_name + '_static\";' + \ 184 '\n ' + func_name + ' = reinterpret_cast<' + func_type + '>(' 185 if dir_name == 'ohos_nweb': 186 if cls.is_webview_side(): 187 result += 'ArkWebNWebWebcoreBridgeHelper::GetInstance().LoadFuncSymbol(funcName));' 188 else: 189 result += 'ArkWebNWebWebviewBridgeHelper::GetInstance().LoadFuncSymbol(funcName));' 190 else: 191 if cls.is_webview_side(): 192 result += 'ArkWebAdapterWebcoreBridgeHelper::GetInstance().LoadFuncSymbol(funcName));' 193 else: 194 result += 'ArkWebAdapterWebviewBridgeHelper::GetInstance().LoadFuncSymbol(funcName));' 195 result += '\n }\n' + \ 196 '\n if (!' + func_name + ') {' + \ 197 '\n ARK_WEB_CTOCPP_WARN_LOG("failed to load func ' + func_name + '_static");' + \ 198 '\n return ' + retval_default + ';' + \ 199 '\n }\n' 200 return result, func_name 201 202 203def ctocpp_get_virtual_funcion(cls, func, suffix, dir_name, macro_retval_default): 204 result = '\n ARK_WEB_CTOCPP_DV_LOG(\"capi struct is %{public}ld\", (long)this);\n' 205 206 # determine how the struct should be referenced 207 if cls.get_name() == func.parent.get_name(): 208 result += '\n ' + file_parser.get_capi_name(cls.get_name(), True) + '* _struct = GetStruct();' 209 else: 210 result += '\n ' + func.parent.get_capi_name() + '* _struct = reinterpret_cast<' + \ 211 func.parent.get_capi_name() + '*>(GetStruct());' 212 213 prefix = file_parser.get_capi_name(cls.get_name(), False) 214 hash_name = make_file_base.get_func_hash_name(func, prefix) 215 var_name = make_file_base.get_func_variable_name(func, suffix) 216 func_name, func_type = make_file_base.get_func_pointer_name(cls, func, prefix, suffix) 217 if isinstance(func, file_parser.obj_function_virtual): 218 result += '\n ARK_WEB_CTOCPP_CHECK_PARAM(_struct, ' + macro_retval_default + ');\n' + \ 219 '\n void* func_pointer = reinterpret_cast<void*>(' + func_name + ');' + \ 220 '\n if (func_pointer == ARK_WEB_INIT_ADDR) {' + \ 221 '\n static const std::string funcName = \"' + hash_name + '\";' + \ 222 '\n func_pointer = ' 223 if dir_name == 'ohos_nweb': 224 if cls.is_webview_side(): 225 result += 'ArkWebNWebWebcoreBridgeHelper::GetInstance().CheckFuncMemberForCaller(' 226 else: 227 result += 'ArkWebNWebWebviewBridgeHelper::GetInstance().CheckFuncMemberForCaller(' 228 else: 229 if cls.is_webview_side(): 230 result += 'ArkWebAdapterWebcoreBridgeHelper::GetInstance().CheckFuncMemberForCaller(' 231 else: 232 result += 'ArkWebAdapterWebviewBridgeHelper::GetInstance().CheckFuncMemberForCaller(' 233 result += file_parser.get_wrapper_type_enum(cls.get_name()) + ', funcName);' 234 result += '\n if (func_pointer == ARK_WEB_INIT_ADDR) {' + \ 235 '\n ARK_WEB_CTOCPP_DV_LOG(\"failed to find func member ' + func_name + '\");' + \ 236 '\n if (ARK_WEB_FUNC_MEMBER_MISSING(_struct, ' + var_name + ')) {' + \ 237 '\n ' + func_name + ' = nullptr;' + \ 238 '\n } else {' + \ 239 '\n ' + func_name + ' = _struct->' + var_name + ';' + \ 240 '\n }' + \ 241 '\n } else {' + \ 242 '\n ' + func_name + ' = reinterpret_cast<' + func_type + '>(func_pointer);' + \ 243 '\n }' + \ 244 '\n }\n' + \ 245 '\n ARK_WEB_CTOCPP_CHECK_FUNC_POINTER(' + func_name + ',' + macro_retval_default + ');\n' 246 return result, func_name 247 248 249def ctocpp_make_function_impl(cls, func, suffix, dir_name): 250 # build the C++ prototype # build the C++ prototype 251 result = ctocpp_make_impl_proto(cls, func) 252 253 invalid = make_file_base.get_func_invalid_info(func.get_name(), func) 254 if len(invalid) > 0: 255 return result + invalid 256 257 retval = func.get_retval() 258 retval_default = retval.get_retval_default(False) 259 if len(retval_default) > 0: 260 macro_retval_default = retval_default 261 retval_default = ' ' + retval_default 262 else: 263 macro_retval_default = 'ARK_WEB_RETURN_VOID' 264 265 if isinstance(func, file_parser.obj_function_virtual): 266 func_body, func_name = ctocpp_get_virtual_funcion(cls, func, suffix, dir_name, macro_retval_default) 267 else: 268 func_body, func_name = ctocpp_get_static_funcion(cls, func, suffix, dir_name, retval_default) 269 270 result += func_body 271 result_len = len(result) 272 273 # parameter verification 274 result += verify_ctocpp_func_args(func, retval_default) 275 if len(result) != result_len: 276 result += '\n' 277 result_len = len(result) 278 279 # parameter translation 280 trans, params = translate_ctocpp_func_args(func) 281 if len(trans) != 0: 282 result += trans + '\n' 283 284 # execution 285 result += '\n // Execute\n ' 286 287 retval_type = retval.get_retval_type() 288 if retval_type != 'none': 289 # has a return value 290 if retval_type == 'simple' or retval_type == 'bool' or retval_type == 'void*' or retval_type == 'uint8_t*' or \ 291 retval_type == 'uint32_t*' or retval_type == 'char*' or file_parser.check_arg_type_is_struct( 292 retval_type): 293 result += 'return ' 294 elif retval_type == 'refptr_same' or retval_type == 'refptr_diff': 295 ptr_struct = retval.get_type().get_result_ptr_type_root() 296 result += ptr_struct + '* _retval = ' 297 else: 298 raise Exception('Unsupported return type %s in %s' % (retval_type, func.get_name())) 299 300 result += func_name + '(' 301 302 if len(params) > 0: 303 if not isinstance(func, file_parser.obj_function_virtual): 304 result += '\n ' 305 result += ',\n '.join(params) 306 307 result += ');\n' 308 result_len = len(result) 309 310 # parameter restoration 311 result += restore_ctocpp_func_args(func) 312 if len(result) != result_len: 313 result += '\n' 314 result_len = len(result) 315 316 if retval_type == 'refptr_same': 317 result += '\n // Return type: ' + retval_type + \ 318 '\n return ' + retval.get_type().get_ptr_type() + 'CToCpp::Invert(_retval);' 319 elif retval_type == 'refptr_diff': 320 result += '\n // Return type: ' + retval_type + \ 321 '\n return ' + retval.get_type().get_ptr_type() + 'CppToC::Revert(_retval);' 322 323 if len(result) != result_len: 324 result += '\n' 325 326 result += '}\n\n' 327 return result 328 329 330def ctocpp_make_function_body(cls, funcs, dir_name): 331 new_list = [] 332 old_list = make_file_base.get_func_name_list(funcs) 333 334 impl = '' 335 for func in funcs: 336 new_list = make_file_base.get_func_name_count(func.get_capi_name(), old_list, new_list) 337 338 suffix = '' 339 if new_list.count(func.get_capi_name()) > 0: 340 suffix = str(new_list.count(func.get_capi_name())) 341 342 impl += ctocpp_make_function_impl(cls, func, suffix, dir_name) 343 return impl 344 345 346def ctocpp_make_functions_body(cls, header, dir_name): 347 clsname = cls.get_name(); 348 result = ctocpp_make_function_body(cls, cls.get_static_funcs(), dir_name) 349 result += ctocpp_make_function_body(cls, make_file_base.get_class_func_list(cls, header), dir_name) 350 result += clsname + 'CToCpp::' + clsname + 'CToCpp() {\n}\n\n' + \ 351 clsname + 'CToCpp::~' + clsname + 'CToCpp() {\n}\n\n' 352 return result 353 354 355def ctocpp_make_include_files(cls, body, header, dir_name): 356 result = file_parser.format_translation_includes(header, dir_name, body) 357 result += '#include "base/ctocpp/ark_web_ctocpp_macros.h"\n' 358 if dir_name == 'ohos_nweb': 359 if cls.is_webview_side(): 360 result += '#include "ohos_nweb/bridge/ark_web_nweb_webcore_bridge_helper.h"\n' 361 else: 362 result += '#include "ohos_nweb/bridge/ark_web_nweb_webview_bridge_helper.h"\n' 363 else: 364 if cls.is_webview_side(): 365 result += '#include "ohos_adapter/bridge/ark_web_adapter_webcore_bridge_helper.h"\n' 366 else: 367 result += '#include "ohos_adapter/bridge/ark_web_adapter_webview_bridge_helper.h"\n' 368 return result 369 370 371def ctocpp_make_unwrap_derived(cls, header, clsname): 372 impl = '' 373 derived_classes = make_file_base.get_derived_classes(cls, header) 374 for clsname in derived_classes: 375 impl += ' if (type == ' + file_parser.get_wrapper_type_enum(clsname) + ') {\n' + \ 376 ' return reinterpret_cast<' + file_parser.get_capi_name(clsname, True) + '*>(' + \ 377 clsname + 'CToCpp::Revert(reinterpret_cast<' + clsname + '*>(c)));\n' + \ 378 ' }\n' 379 return impl 380 381 382def make_ctocpp_impl_file(header, dir_path, dir_name, clsname): 383 cls = header.get_class(clsname) 384 if cls is None: 385 raise Exception('Class does not exist: ' + clsname) 386 387 static_param = ctocpp_make_static_params(cls, header) 388 function_body = ctocpp_make_functions_body(cls, header, dir_name) 389 390 unwrapderived = ctocpp_make_unwrap_derived(cls, header, clsname) 391 includes = ctocpp_make_include_files(cls, function_body + unwrapderived, header, dir_name) 392 393 content = make_file_base.get_copyright() + '\n' + includes + '\n' + \ 394 'namespace OHOS::ArkWeb {\n\n' + \ 395 static_param + function_body + \ 396 make_file_base.make_wrapper_type(cls, 'CToCpp') + \ 397 '\n\n} // namespace OHOS::ArkWeb\n' 398 399 absolute_dir = os.path.join(os.path.join(dir_path, dir_name), 'ctocpp') 400 absolute_path = os.path.join(absolute_dir, file_parser.get_capi_name(clsname, False) + '_ctocpp.cpp') 401 return (content, absolute_path) 402