1 /* 2 * Copyright (c) 2021 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 package ohos; 17 18 import java.io.IOException; 19 import java.io.InputStream; 20 import java.nio.ByteBuffer; 21 import java.nio.ByteOrder; 22 import java.nio.charset.StandardCharsets; 23 import java.util.ArrayList; 24 import java.util.List; 25 import java.util.Optional; 26 27 /** 28 * Resources Parser. 29 * 30 */ 31 public class ResourcesParser { 32 /** 33 * Parses resources default id. 34 */ 35 public static final int RESOURCE_DEFAULT_ID = -1; 36 37 private static final int VERSION_BYTE_LENGTH = 128; 38 private static final int TAG_BYTE_LENGTH = 4; 39 private static final Log LOG = new Log(ResourcesParser.class.toString()); 40 41 /** 42 * Key Param. 43 */ 44 static class KeyParam { 45 int keyType; 46 int value; 47 } 48 49 /** 50 * Config Index. 51 */ 52 static class ConfigIndex { 53 String tag; 54 int offset; 55 int keyCount; 56 KeyParam[] params; 57 } 58 59 /** 60 * Data Item. 61 */ 62 static class DataItem { 63 int size; 64 int type; 65 int id; 66 String value; 67 String name; 68 } 69 70 /** 71 * Get resource value by resource id. 72 * 73 * @param resourceId resource id 74 * @param data resource index data 75 * @return the resourceId value 76 * @throws BundleException IOException. 77 */ getResourceById(int resourceId, byte[] data)78 static String getResourceById(int resourceId, byte[] data) throws BundleException { 79 String resourceIdValue = ""; 80 if (data == null || data.length <= 0 || resourceId == RESOURCE_DEFAULT_ID) { 81 LOG.error("ResourcesParser::getIconPath data byte or ResourceId is null"); 82 return resourceIdValue; 83 } 84 85 List<String> result = getResource(resourceId, data); 86 if (result != null && result.size() > 0 && result.get(0) != null && !"".equals(result.get(0))) { 87 resourceIdValue = result.get(0).substring(0, result.get(0).length() - 1); 88 } 89 return resourceIdValue; 90 } 91 92 /** 93 * Get base resource value by resource id. 94 * 95 * @param resourceId resource id 96 * @param data resource index data 97 * @return the resource value 98 * @throws BundleException IOException. 99 */ getBaseResourceById(int resourceId, byte[] data)100 static String getBaseResourceById(int resourceId, byte[] data) throws BundleException { 101 String resourceIdValue = ""; 102 if (data == null || data.length <= 0 || resourceId == RESOURCE_DEFAULT_ID) { 103 LOG.error("ResourcesParser::getBaseResourceById data byte or ResourceId is null"); 104 return resourceIdValue; 105 } 106 resourceIdValue = getBaseResource(resourceId, data); 107 if (resourceIdValue != null && !"".equals(resourceIdValue)) { 108 resourceIdValue = resourceIdValue.substring(0, resourceIdValue.length() - 1); 109 } 110 return resourceIdValue; 111 } 112 113 /** 114 * Get base resource. 115 * 116 * @param resId resource id 117 * @param data resource index data array 118 * @return the resource value 119 * @throws BundleException IOException. 120 */ getBaseResource(int resId, byte[] data)121 static String getBaseResource(int resId, byte[] data) { 122 ByteBuffer byteBuf = ByteBuffer.wrap(data); 123 byteBuf.order(ByteOrder.LITTLE_ENDIAN); 124 byte[] version = new byte[VERSION_BYTE_LENGTH]; 125 byteBuf.get(version); 126 byteBuf.getInt(); 127 int configCount = byteBuf.getInt(); 128 Optional<ConfigIndex> optionalConfigIndex = loadBaseConfig(byteBuf, configCount); 129 if (!optionalConfigIndex.isPresent()) { 130 LOG.error("ResourcesParser::getBaseResource configIndex is null"); 131 return ""; 132 } 133 return readBaseItem(resId, optionalConfigIndex.get(), byteBuf); 134 } 135 136 /** 137 * Load index config. 138 * 139 * @param bufBuf config byte buffer 140 * @param count config count 141 * @return the base config index 142 * @throws BundleException IOException. 143 */ loadBaseConfig(ByteBuffer bufBuf, int count)144 static Optional<ConfigIndex> loadBaseConfig(ByteBuffer bufBuf, int count) { 145 for (int i = 0; i < count; i++) { 146 ConfigIndex cfg = new ConfigIndex(); 147 byte[] tag = new byte[TAG_BYTE_LENGTH]; 148 bufBuf.get(tag); 149 cfg.tag = new String(tag, StandardCharsets.UTF_8); 150 cfg.offset = bufBuf.getInt(); 151 cfg.keyCount = bufBuf.getInt(); 152 cfg.params = new KeyParam[cfg.keyCount]; 153 for (int j = 0; j < cfg.keyCount; j++) { 154 cfg.params[j] = new KeyParam(); 155 cfg.params[j].keyType = bufBuf.getInt(); 156 cfg.params[j].value = bufBuf.getInt(); 157 } 158 if (cfg.keyCount == 0) { 159 return Optional.of(cfg); 160 } 161 } 162 return Optional.empty(); 163 } 164 165 /** 166 * Read base config item. 167 * 168 * @param resId resource id 169 * @param configIndex the config index 170 * @param buf config byte buffer 171 * @return the base item 172 * @throws BundleException IOException. 173 */ readBaseItem(int resId, ConfigIndex configIndex, ByteBuffer buf)174 static String readBaseItem(int resId, ConfigIndex configIndex, ByteBuffer buf) { 175 buf.rewind(); 176 buf.position(configIndex.offset); 177 byte[] tag = new byte[TAG_BYTE_LENGTH]; 178 buf.get(tag); 179 int count = buf.getInt(); 180 for (int i = 0; i < count; i++) { 181 int id = buf.getInt(); 182 int offset = buf.getInt(); 183 if (id == resId) { 184 buf.rewind(); 185 buf.position(offset); 186 DataItem item = readItem(buf); 187 return item.value; 188 } 189 } 190 return ""; 191 } 192 193 /** 194 * Get Icon resource. 195 * 196 * @param resId resource id 197 * @param data resource index data array 198 * @return the result 199 * @throws BundleException IOException. 200 */ getResource(int resId, byte[] data)201 static List<String> getResource(int resId, byte[] data) { 202 ByteBuffer byteBuf = ByteBuffer.wrap(data); 203 byteBuf.order(ByteOrder.LITTLE_ENDIAN); 204 byte[] version = new byte[VERSION_BYTE_LENGTH]; 205 byteBuf.get(version); 206 byteBuf.getInt(); 207 int configCount = byteBuf.getInt(); 208 List<ConfigIndex> cfg = loadConfig(byteBuf, configCount); 209 return readAllItem(resId, cfg, byteBuf); 210 } 211 212 /** 213 * Load index config. 214 * 215 * @param bufBuf config byte buffer 216 * @param count config count 217 * @return the config list 218 * @throws BundleException IOException. 219 */ loadConfig(ByteBuffer bufBuf, int count)220 static List<ConfigIndex> loadConfig(ByteBuffer bufBuf, int count) { 221 List<ConfigIndex> configList = new ArrayList<>(count); 222 for (int i = 0; i < count; i++) { 223 ConfigIndex cfg = new ConfigIndex(); 224 byte[] tag = new byte[TAG_BYTE_LENGTH]; 225 bufBuf.get(tag); 226 cfg.tag = new String(tag, StandardCharsets.UTF_8); 227 cfg.offset = bufBuf.getInt(); 228 cfg.keyCount = bufBuf.getInt(); 229 cfg.params = new KeyParam[cfg.keyCount]; 230 for (int j = 0; j < cfg.keyCount; j++) { 231 cfg.params[j] = new KeyParam(); 232 cfg.params[j].keyType = bufBuf.getInt(); 233 cfg.params[j].value = bufBuf.getInt(); 234 } 235 236 configList.add(cfg); 237 } 238 return configList; 239 } 240 241 /** 242 * Read all config item. 243 * 244 * @param resId resource id 245 * @param configs the config list 246 * @param buf config byte buffer 247 * @return the item list 248 * @throws BundleException IOException. 249 */ readAllItem(int resId, List<ConfigIndex> configs, ByteBuffer buf)250 static List<String> readAllItem(int resId, List<ConfigIndex> configs, ByteBuffer buf) { 251 List<String> result = new ArrayList<>(); 252 for (ConfigIndex index : configs) { 253 buf.rewind(); 254 buf.position(index.offset); 255 byte[] tag = new byte[TAG_BYTE_LENGTH]; 256 buf.get(tag); 257 int count = buf.getInt(); 258 for (int i = 0; i < count; i++) { 259 int id = buf.getInt(); 260 int offset = buf.getInt(); 261 if (id == resId) { 262 buf.rewind(); 263 buf.position(offset); 264 DataItem item = readItem(buf); 265 result.add(item.value); 266 break; 267 } 268 } 269 } 270 return result; 271 } 272 273 /** 274 * Read the config item. 275 * 276 * @param buf config byte buffer 277 * @return the item info 278 * @throws BundleException IOException. 279 */ readItem(ByteBuffer buf)280 static DataItem readItem(ByteBuffer buf) { 281 DataItem item = new DataItem(); 282 item.size = buf.getInt(); 283 item.type = buf.getInt(); 284 item.id = buf.getInt(); 285 int len = buf.getShort(); 286 byte[] value = new byte[len]; 287 buf.get(value); 288 item.value = new String(value, StandardCharsets.UTF_8); 289 len = buf.getShort(); 290 byte[] name = new byte[len]; 291 buf.get(name); 292 item.name = new String(name, StandardCharsets.UTF_8); 293 return item; 294 } 295 } 296 297