1#!/usr/bin/env python
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
17import os
18import struct
19import sys
20
21
22def int_to_str(int_n):
23    buf = ""
24    i = 0
25    while i < 4:
26        a = ((int_n >> (3 - i) * 8) & 0xff)
27        if a != 0:
28            buf = buf + chr(a)
29        i = i + 1
30    return buf
31
32
33resolutions = {-2: "nodpi", -1: "anydpi", 120: "sdpi", 160: "mdpi", 213: "tvdpi", 240: "ldpi", 320: "xldpi",
34               480: "xxldpi", 640: "xxxldpi"}
35
36orientations = {0: "vertical", 1: "horizontal"}
37
38devices = {0: "phone", 1: "tablet", 2: "car", 3: "pc", 4: "tv", 5: "speaker", 6: "wearable", 7: "glasses", 8: "headset"}
39
40night_modes = {0: "dark", 1: "light"}
41
42
43def parse_limit_key(limit_key):
44    key_str = ""
45    key_ = limit_key
46    if key_ == "":
47        key_ = "base"
48        key_str = "base"
49
50    key_sets = key_.split("-")
51    last_key_type = -1
52    for key_item in key_sets:
53        if key_item == "base":
54            continue
55        key_s = key_item.split(":")
56        if int(key_s[0]) == 0 or int(key_s[0]) == 1 or int(key_s[0]) == 5:
57            i = int(key_s[1])
58            if key_str == "":
59                key_str = key_str + int_to_str(i)
60            elif last_key_type == 0 or last_key_type == 1 or last_key_type == 5:
61                key_str = "{}_{}".format(key_str, int_to_str(i))
62            else:
63                key_str = "{}-{}".format(key_str, int_to_str(i))
64            last_key_type = int(key_s[0])
65        elif int(key_s[0]) == 2:
66            k = int(key_s[1])
67            if (k & 0x80000000) != 0:
68                a = (0xffffffff ^ k) + 1
69                k = -1 * a
70            if key_str == "":
71                key_str = key_str + resolutions.get(k)
72            else:
73                key_str = "{}-{}".format(key_str, resolutions.get(k))
74        elif int(key_s[0]) == 3:
75            if key_str == "":
76                key_str = key_str + orientations.get(int(key_s[1]))
77            else:
78                key_str = "{}-{}".format(key_str, orientations.get(int(key_s[1])))
79        elif int(key_s[0]) == 4:
80            if key_str == "":
81                key_str = key_str + devices.get(int(key_s[1]))
82            else:
83                key_str = "{}-{}".format(key_str, devices.get(int(key_s[1])))
84        elif int(key_s[0]) == 6:
85            if key_str == "":
86                key_str = key_str + night_modes.get(int(key_s[1]))
87            else:
88                key_str = "{}-{}".format(key_str, night_modes.get(int(key_s[1])))
89        elif int(key_s[0]) == 7:
90            i = int(key_s[1])
91            if key_str == "":
92                key_str = "{}mcc{}".format(key_str, str(i))
93            else:
94                key_str = "{}_mcc{}".format(key_str, str(i))
95        elif int(key_s[0]) == 8:
96            i = int(key_s[1])
97            if key_str == "":
98                key_str = "{}mnc{:0>2d}".format(key_str, i)
99            else:
100                key_str = "{}_mnc{:0>2d}".format(key_str, i)
101        else:
102            raise Exception("invalid key={}".format(str(int(key_s[0]))))
103    return key_str
104
105
106def open_new_resource_index(file_path):
107    if not os.path.exists(file_path):
108        raise Exception("not found:" + file_path)
109
110    with open(file_path, "rb") as fp_resource_index:
111        header = fp_resource_index.read(128)
112        length = fp_resource_index.read(4)
113        key_count = fp_resource_index.read(4)
114        pri_key_count = struct.unpack("i", key_count)[0]
115
116        index_one = 0
117
118        # keys
119        private_index = {}
120        while index_one < pri_key_count:
121            buf = fp_resource_index.read(4)
122            p_key_tag = struct.unpack("4s", buf)[0]
123
124            buf = fp_resource_index.read(4)
125            p_data_offset = struct.unpack("I", buf)[0]
126
127            buf = fp_resource_index.read(4)
128            p_key_count = struct.unpack("I", buf)[0]
129
130            i = 0
131            key_str = ""
132            while i < p_key_count:
133                buf = fp_resource_index.read(8)
134                p_key_type = struct.unpack("I", buf[0:4])[0]
135                p_value = struct.unpack("I", buf[4:8])[0]
136                if key_str == "":
137                    key_str = "{}:{}".format(str(p_key_type), str(p_value))
138                else:
139                    key_str = "{}-{}:{}".format(key_str, str(p_key_type), str(p_value))
140                i = i + 1
141            private_index[key_str] = p_data_offset
142            index_one = index_one + 1
143
144        # idss
145        c = 0
146        idss_cache = {}
147        while c < pri_key_count:
148            pos = fp_resource_index.tell()
149            idss_buf = fp_resource_index.read(4)
150            idss_tag = struct.unpack("4s", idss_buf)[0]
151            idss_buf = fp_resource_index.read(4)
152            idss_count = struct.unpack("I", idss_buf)[0]
153            i = 0
154            idss_index = {}
155            while i < idss_count:
156                buf = fp_resource_index.read(4)
157                p_id = struct.unpack("I", buf)[0]
158                buf = fp_resource_index.read(4)
159                p_offset = struct.unpack("I", buf)[0]
160                idss_index[p_id] = p_offset
161                i = i + 1
162            idss_cache[pos] = idss_index
163            c = c + 1
164
165        third_data = {}
166        d_data = {}
167        d_pos = fp_resource_index.tell()
168        d_buf = fp_resource_index.read(4)
169        while len(d_buf) > 0:
170            d_size = struct.unpack("I", d_buf)[0]
171            d_buf = fp_resource_index.read(d_size)
172            d_res_type = struct.unpack("I", d_buf[0:4])[0]
173
174            d_value_len_l = struct.unpack("B", d_buf[8:9])[0]
175            d_value_len_h = struct.unpack("B", d_buf[9:10])[0]
176            d_value_len = d_value_len_l + d_value_len_h * 256
177            d_value = ""
178            if d_res_type == 10 or d_res_type == 11 or d_res_type == 16 or d_res_type == 17 or d_res_type == 22:
179                tmp = d_buf[10:10 + d_value_len]
180                d_d_pos = 0
181                while d_d_pos < d_value_len - 1:
182                    d_d_value_len_l = struct.unpack("B", tmp[0 + d_d_pos:1 + d_d_pos])[0]
183                    d_d_value_len_h = struct.unpack("B", tmp[1 + d_d_pos:2 + d_d_pos])[0]
184                    d_d_value_len = d_d_value_len_l + d_d_value_len_h * 256
185                    d_value = "{}<{}>".format(d_value, str(tmp[2 + d_d_pos:2 + d_d_value_len + d_d_pos]))
186                    d_d_pos = d_d_pos + 2 + d_d_value_len + 1
187            else:
188                d_value = d_buf[10:10 + d_value_len - 1].decode("utf-8")
189
190            d_name_len_l = struct.unpack("B", d_buf[10 + d_value_len:11 + d_value_len])[0]
191            d_name_len_h = struct.unpack("B", d_buf[11 + d_value_len:12 + d_value_len])[0]
192            d_name_len = d_name_len_l + d_name_len_h * 256
193            d_name = str(d_buf[12 + d_value_len:12 + d_value_len + d_name_len - 1].decode("utf-8"))
194            d_data[d_pos] = [d_value, d_name]
195
196            d_pos = fp_resource_index.tell()
197            d_buf = fp_resource_index.read(4)
198
199    for key_, key_offset in private_index.items():
200        third_data[key_] = {}
201        idss_sets = idss_cache.get(key_offset)
202        for id_, offset in idss_sets.items():
203            id_sets = d_data.get(offset)
204            third_data[key_][id_] = id_sets
205    return third_data
206
207
208def dump(file_path, out_path):
209    out_file = os.open(out_path, os.O_WRONLY | os.O_CREAT, 0o664)
210    third_data = open_new_resource_index(file_path)
211    for key_, ids_ in third_data.items():
212        key_str = parse_limit_key(key_)
213        if "zh_CN" == key_str:
214            continue
215        os.write(out_file, str.encode("keyconfig:{}\n".format(key_)))
216        os.write(out_file, str.encode("{}\n".format(key_str)))
217        for id_, idsets in ids_.items():
218            os.write(out_file, str.encode("id:{}, '{}' '{}'\n".format(str(id_), idsets[0], str(idsets[1]))))
219    os.close(out_file)
220