• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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