1#!/usr/bin/env python3 2#coding: utf-8 3 4""" 5Copyright (c) 2021 Huawei Device Co., Ltd. 6Licensed under the Apache License, Version 2.0 (the "License"); 7you may not use this file except in compliance with the License. 8You may obtain a copy of the License at 9 10 http://www.apache.org/licenses/LICENSE-2.0 11 12Unless required by applicable law or agreed to in writing, software 13distributed under the License is distributed on an "AS IS" BASIS, 14WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15See the License for the specific language governing permissions and 16limitations under the License. 17Description: Generate interface to get java plugin's js code and binary 18""" 19 20import os 21import subprocess 22import argparse 23import stat 24 25JAVA_FILE_SUFFIX = "JsCode" 26JS_BIN_EXT = ".abc" 27ARRAY_MAX = 8192 # size of 8K 28 29 30def parse_args(): 31 parser = argparse.ArgumentParser() 32 parser.add_argument("--node", 33 help="path to nodejs exetuable") 34 parser.add_argument("--frontend-tool-path", 35 help="path to frontend conversion tool") 36 parser.add_argument("--node-modules", 37 help='path to node-modules exetuable') 38 parser.add_argument("--plugin-path", 39 help="plugin js file path") 40 parser.add_argument("--plugin-name", 41 help="name of js file, ex: BatteryPlugin.js") 42 parser.add_argument("--generated-file", 43 help="name of generated file") 44 parser.add_argument("--package-name", 45 help="name of generated file's package") 46 47 arguments = parser.parse_args() 48 return arguments 49 50 51def split_array_by_n(array, max_len): 52 for i in range(0, len(array), max_len): 53 yield array[i: i + max_len] 54 55 56def gen_bin_info(input_arguments): 57 file_name = input_arguments.plugin_name 58 file_path = input_arguments.plugin_path 59 js_file = os.path.join(file_path, file_name) 60 file_name_pre = os.path.splitext(file_name)[0] 61 62 generate_js_bytecode = os.path.join( 63 os.path.dirname(__file__), "generate_js_bytecode.py") 64 65 (out_dir, _) = os.path.split(input_arguments.generated_file) 66 dst_file = os.path.join(out_dir, f'{file_name_pre}{JS_BIN_EXT}') 67 68 args = [ 69 '--src-js', 70 js_file, 71 '--dst-file', 72 dst_file, 73 '--node', 74 input_arguments.node, 75 '--frontend-tool-path', 76 input_arguments.frontend_tool_path, 77 '--node-modules', 78 input_arguments.node_modules, 79 ] 80 81 proc = subprocess.Popen(['python3', generate_js_bytecode] + args) 82 return_code = proc.wait() 83 return return_code 84 85 86def gen_java_method(input_arguments): 87 file_name = input_arguments.plugin_name 88 file_path = input_arguments.plugin_path 89 out_file = input_arguments.generated_file 90 91 if os.path.exists(out_file): 92 os.remove(out_file) 93 94 file_name_pre = os.path.splitext(file_name)[0] 95 js_src_file = os.path.join(file_path, file_name) 96 (out_dir, _) = os.path.split(input_arguments.generated_file) 97 js_bin_file = os.path.join(out_dir, file_name_pre + JS_BIN_EXT) 98 99 flags = os.O_WRONLY | os.O_CREAT 100 modes = stat.S_IWUSR | stat.S_IRUSR 101 102 with os.fdopen(os.open(out_file, flags, modes), "w") as output: 103 output.write("/*%s * Generated from Java and JavaScript plugins by ts2abc.%s */%s%s" 104 % (os.linesep, os.linesep, os.linesep, os.linesep)) 105 106 output.write("package %s;%s" 107 % (input_arguments.package_name, os.linesep)) 108 output.write("%s" % os.linesep) 109 output.write("public class %s%s {%s" 110 % (file_name_pre, JAVA_FILE_SUFFIX, os.linesep)) 111 112 # write method: getJsCode 113 with open(js_src_file, "r") as input_src: 114 lines = input_src.readlines() 115 # separate lines into blocks 116 single_block_len = 1024 117 total_len = len(lines) 118 for index, line in enumerate(lines): 119 block_index = index // single_block_len 120 line = line.strip(os.linesep) 121 line = line.replace("\"", "\\\"") 122 # generate getJsCode%s 123 if (index % single_block_len == 0): 124 output.write(" private static String getJsCode%s(){%s" 125 % (block_index, os.linesep)) 126 output.write(" return%s" % os.linesep) 127 if (index % single_block_len == single_block_len - 1 or index == total_len - 1): 128 output.write(" \"%s\";%s" % (line, os.linesep)) 129 output.write(" }%s" % os.linesep) 130 else: 131 output.write(" \"%s\\n\" +%s" % (line, os.linesep)) 132 block_num = (total_len // single_block_len) + 1 133 if total_len % single_block_len == 0: 134 block_num = total_len // single_block_len 135 # generate getJsCode 136 output.write(" public static String getJsCode(){%s" % os.linesep) 137 output.write(" return%s" % os.linesep) 138 # let getJsCode call getJsCode%s 139 for index in range(block_num): 140 if (index != block_num - 1): 141 output.write(" getJsCode%s() +%s" % (index, os.linesep)) 142 else: 143 output.write(" getJsCode%s() ;%s" % (index, os.linesep)) 144 output.write(" }%s" % os.linesep) 145 146 output.write("%s" % os.linesep) 147 148 # write method: getJsBytecode 149 with open(js_bin_file, "rb") as input_bin: 150 # separate bytecode list 151 buf = bytearray(os.path.getsize(js_bin_file)) 152 input_bin.readinto(buf) 153 hex_str = [hex(i) for i in buf] 154 byte_str = ["(byte){}".format(i) for i in hex_str] 155 separate_array = split_array_by_n(byte_str, ARRAY_MAX) 156 157 # generate separate methods for js bytecode with ARRAY_MAX 158 method_idx = 0 159 method_len_list = [] 160 for array in separate_array: 161 output.write(" private static byte[] getJsByteCode_%s() {%s" 162 % (method_idx, os.linesep)) 163 output.write(" return new byte[] {") 164 output.write(", ".join(array)) 165 output.write("};%s" % os.linesep) 166 output.write(" }%s" % os.linesep) 167 method_idx = method_idx + 1 168 method_len_list.append(len(array)) 169 170 # generate a method collect all separated arrays 171 cur_pos = 0 172 output.write(" public static byte[] getJsByteCode() {%s" 173 % os.linesep) 174 output.write(" byte[] allByteCode = new byte[%s];%s" 175 % (len(byte_str), os.linesep)) 176 for idx in range(0, len(method_len_list)): 177 output.write(" System.arraycopy(getJsByteCode_%s(), " 178 "0, allByteCode, %s, %s);%s" 179 % (idx, cur_pos, method_len_list[idx], os.linesep)) 180 cur_pos = cur_pos + method_len_list[idx] 181 output.write(" return allByteCode;%s" % os.linesep) 182 output.write(" }%s" % os.linesep) 183 184 output.write("}") 185 return 186 187 188def operate_file(input_arguments): 189 retcode = gen_bin_info(input_arguments) 190 if retcode != 0: 191 return 192 193 gen_java_method(input_arguments) 194 195 196if __name__ == "__main__": 197 operate_file(parse_args()) 198