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.util.List; 21 22 import static ohos.Uncompress.getResourceFromHap; 23 24 25 /** 26 * bundle uncompress. 27 * step1: parse arguments 28 * step2: verity arguments 29 * step3: uncompress arguments 30 * 31 */ 32 public class UncompressEntrance { 33 /** 34 * Parses and returns the hap list that supports the device type. 35 */ 36 public static final String PARSE_MODE_HAPLIST = "hap-list"; 37 38 /** 39 * Parses and returns the information about the hap. 40 */ 41 public static final String PARSE_MODE_HAPINFO = "hap-info"; 42 43 /** 44 * Parses and returns the informations about the hap list that supports the device type and the haps in the app. 45 */ 46 public static final String PARSE_MODE_ALL = "all"; 47 48 /** 49 * Device type of default. 50 */ 51 public static final String DEVICE_TYPE_DEFAULT = "default"; 52 53 /** 54 * Device type of phone. 55 */ 56 public static final String DEVICE_TYPE_PHONE = "phone"; 57 58 /** 59 * Device type of tablet. 60 */ 61 public static final String DEVICE_TYPE_TABLET = "tablet"; 62 63 /** 64 * Device type of tv. 65 */ 66 public static final String DEVICE_TYPE_TV = "tv"; 67 68 /** 69 * Device type of car. 70 */ 71 public static final String DEVICE_TYPE_CAR = "car"; 72 73 /** 74 * Device type of smartWatch. 75 */ 76 public static final String DEVICE_TYPE_SMARTWATCH = "smartWatch"; 77 78 /** 79 * Device type of fitnessWatch. 80 */ 81 public static final String DEVICE_TYPE_FITNESSWATCH = "fitnessWatch"; 82 83 /** 84 * Device type of fitnessBand. 85 */ 86 public static final String DEVICE_TYPE_FITNESSBAND = "fitnessBand"; 87 88 private static final String APPQF_SUFFIX = ".appqf"; 89 private static final String APP_SUFFIX = ".app"; 90 private static final String HAP_SUFFIX = ".hap"; 91 private static final String HSP_SUFFIX = ".hsp"; 92 93 private static final int EXIT_STATUS_NORMAL = 0; 94 private static final int EXIT_STATUS_EXCEPTION = 1; 95 private static final Log LOG = new Log(UncompressEntrance.class.toString()); 96 97 /** 98 * Indicates the parseMode for parseApp interface. 99 */ 100 public enum ParseAppMode { 101 ALL(0, "all"), 102 HAP_LIST(1, "hap-list"), 103 HAP_INFO(2, "hap-info"); 104 ParseAppMode(int index, String type)105 ParseAppMode(int index, String type) { 106 this.index = index; 107 this.type = type; 108 } 109 getType(int index)110 public static String getType(int index) { 111 for (UncompressEntrance.ParseAppMode resType : UncompressEntrance.ParseAppMode.values()) { 112 if (resType.getIndex() == index) { 113 return resType.type; 114 } 115 } 116 return ""; 117 } 118 getIndex()119 public int getIndex() { 120 return index; 121 } getType()122 public String getType() { 123 return type; 124 } 125 private final int index; 126 private final String type; 127 } 128 129 /** 130 * Unpack the app. 131 * 132 * @param appPath Indicates the app path. 133 * @param outPath Indicates the out path. 134 * @param deviceType Indicates the device type supported by the haps.If this parameter is null, all the haps will 135 * be unpacked. 136 * @param unpackApk Indicates whether to decompress the apk file in the hap.The default value is {@code false}, 137 * not unpack the apk file. 138 * @return Return the unpack result. 139 */ unpack(String appPath, String outPath, String deviceType, boolean unpackApk)140 public static boolean unpack(String appPath, String outPath, String deviceType, boolean unpackApk) { 141 if (appPath == null || appPath.isEmpty()) { 142 LOG.error("UncompressEntrance::unpack appPath is invalid!"); 143 return false; 144 } 145 146 if (outPath == null || outPath.isEmpty()) { 147 LOG.error("UncompressEntrance::unpack outPath is invalid!"); 148 return false; 149 } 150 151 Utility utility = new Utility(); 152 utility.setMode(Utility.MODE_APP); 153 utility.setAppPath(appPath); 154 utility.setDeviceType(deviceType == null ? "" : deviceType); 155 utility.setOutPath(outPath); 156 utility.setUnpackApk(String.valueOf(unpackApk)); 157 utility.setForceRewrite("true"); 158 159 if (!UncompressVerify.commandVerify(utility)) { 160 LOG.error("CompressEntrance::unpack verity failed"); 161 return false; 162 } 163 164 if (!Uncompress.unpackageProcess(utility)) { 165 LOG.error("UncompressEntrance::unpackageProcess failed"); 166 return false; 167 } 168 169 return true; 170 } 171 172 /** 173 * Unpack the hap. 174 * 175 * @param hapPath Indicates the hap path. 176 * @param outPath Indicates the out path. 177 * @param unpackApk Indicates whether to decompress the apk file in the hap.The default value is {@code false}, 178 * not unpack the apk file. 179 * @return Return the unpack result. 180 */ unpackHap(String hapPath, String outPath, boolean unpackApk)181 public static boolean unpackHap(String hapPath, String outPath, boolean unpackApk) { 182 if (hapPath == null || hapPath.isEmpty()) { 183 LOG.error("UncompressEntrance::unpackHap hapPath is invalid!"); 184 return false; 185 } 186 187 if (outPath == null || outPath.isEmpty()) { 188 LOG.error("UncompressEntrance::unpackHap outPath is invalid!"); 189 return false; 190 } 191 192 Utility utility = new Utility(); 193 utility.setMode(Utility.MODE_HAP); 194 utility.setHapPath(hapPath); 195 utility.setDeviceType(""); 196 utility.setOutPath(outPath); 197 utility.setUnpackApk(String.valueOf(unpackApk)); 198 utility.setForceRewrite("true"); 199 200 if (!UncompressVerify.commandVerify(utility)) { 201 LOG.error("CompressEntrance::unpackHap verity failed"); 202 return false; 203 } 204 205 if (!Uncompress.unpackageProcess(utility)) { 206 LOG.error("UncompressEntrance::unpackageProcess failed"); 207 return false; 208 } 209 210 return true; 211 } 212 213 214 /** 215 * Parse the app. 216 * 217 * @param appPath Indicates the app path. 218 * @param parseMode Indicates the parse mode, which can be {@link #PARSE_MODE_HAPLIST}, {@link #PARSE_MODE_HAPINFO}, 219 * {@link #PARSE_MODE_ALL}. 220 * @param deviceType Indicates the device type supported by the haps, This parameter is required 221 * when {@code #parseMode} is {@link #PARSE_MODE_HAPLIST}. 222 * @param hapName Indicates the hap name, This parameter is required when {@code #parseMode} 223 * is {@link #PARSE_MODE_HAPINFO}. 224 * @param outPath Indicates the out path to unpack the files. 225 * @return Return the uncomperss result of parseApp 226 * @deprecated 227 */ parseApp(String appPath, String parseMode, String deviceType, String hapName, String outPath)228 public static UncompressResult parseApp(String appPath, String parseMode, String deviceType, String hapName, 229 String outPath) { 230 UncompressResult compressResult = new UncompressResult(); 231 232 Utility utility = new Utility(); 233 utility.setAppPath(appPath); 234 utility.setParseMode(parseMode); 235 utility.setDeviceType(deviceType == null ? "" : deviceType); 236 utility.setHapName(hapName == null ? "" : hapName); 237 238 if (!UncompressVerify.isPathValid(utility.getAppPath(), true, APP_SUFFIX)) { 239 LOG.error("UncompressEntrance::parseApp must input a app file!"); 240 compressResult.setResult(false); 241 compressResult.setMessage("ParseApp verify failed"); 242 return compressResult; 243 } 244 if (!UncompressVerify.isParseAppModeValid(utility.getParseMode(), utility.getHapName())) { 245 compressResult.setResult(false); 246 compressResult.setMessage("ParseApp verify failed"); 247 return compressResult; 248 } 249 250 compressResult = Uncompress.uncompressAppByPath(utility); 251 252 return compressResult; 253 } 254 255 /** 256 * Parse the app. 257 * 258 * @param input Indicates the InputStream about the app package. 259 * @param parseMode Indicates the parse mode, which can be {@link #PARSE_MODE_HAPLIST}, {@link #PARSE_MODE_HAPINFO}, 260 * {@link #PARSE_MODE_ALL}. 261 * @param deviceType Indicates the device type supported by the haps, This parameter is required 262 * when {@code #parseMode} is {@link #PARSE_MODE_HAPLIST}. 263 * @param hapName Indicates the hap name, This parameter is required when {@code #parseMode} 264 * is {@link #PARSE_MODE_HAPINFO}. 265 * @param outPath Indicates the out path to unzip temp files. 266 * @return Return the uncomperss result of parseApp 267 * @deprecated 268 */ parseApp(InputStream input, String parseMode, String deviceType, String hapName, String outPath)269 public static UncompressResult parseApp(InputStream input, String parseMode, String deviceType, String hapName, 270 String outPath) { 271 UncompressResult compressResult = new UncompressResult(); 272 273 if (input == null) { 274 LOG.error("UncompressEntrance::parseApp input is null!"); 275 compressResult.setResult(false); 276 compressResult.setMessage("ParseApp input is null"); 277 return compressResult; 278 } 279 280 Utility utility = new Utility(); 281 utility.setMode(Utility.MODE_APP); 282 utility.setParseMode(parseMode); 283 utility.setDeviceType(deviceType == null ? "" : deviceType); 284 utility.setHapName(hapName == null ? "" : hapName); 285 286 if (!UncompressVerify.isParseAppModeValid(utility.getParseMode(), utility.getHapName())) { 287 compressResult.setResult(false); 288 compressResult.setMessage("ParseApp verify failed"); 289 return compressResult; 290 } 291 292 compressResult = Uncompress.uncompressAppByInput(utility, input); 293 294 return compressResult; 295 } 296 297 /** 298 * Parse the app. 299 * 300 * @param appPath Indicates the path about the app package. 301 * @param parseAppMode Indicates the parse mode. 302 * @param hapName Indicates the hap name, This parameter is required when {@code #parseMode} 303 * is {@link #PARSE_MODE_HAPINFO}. 304 * @return Return the uncomperss result of parseApp 305 */ parseApp(String appPath, ParseAppMode parseAppMode, String hapName)306 public static UncompressResult parseApp(String appPath, ParseAppMode parseAppMode, String hapName) { 307 UncompressResult compressResult = new UncompressResult(); 308 Utility utility = new Utility(); 309 utility.setAppPath(appPath); 310 utility.setParseMode(parseAppMode.getType()); 311 utility.setDeviceType(""); 312 utility.setHapName(hapName); 313 if (!UncompressVerify.isPathValid(utility.getAppPath(), true, APP_SUFFIX)) { 314 LOG.error("UncompressEntrance::parseApp must input a app file!"); 315 compressResult.setResult(false); 316 compressResult.setMessage("ParseApp verify failed"); 317 return compressResult; 318 } 319 if (!UncompressVerify.isParseAppModeValid(utility.getParseMode(), utility.getHapName())) { 320 compressResult.setResult(false); 321 compressResult.setMessage("ParseApp verify failed"); 322 return compressResult; 323 } 324 compressResult = Uncompress.uncompressAppByPath(utility); 325 326 return compressResult; 327 } 328 329 /** 330 * Parse the app. 331 * 332 * @param input Indicates the input stream about the app package. 333 * @param parseAppMode Indicates the parse mode. 334 * @param hapName Indicates the hap name, This parameter is required when {@code #parseMode} 335 * is {@link #PARSE_MODE_HAPINFO}. 336 * @return Return the uncomperss result of parseApp 337 */ parseApp(InputStream input, ParseAppMode parseAppMode, String hapName)338 public static UncompressResult parseApp(InputStream input, ParseAppMode parseAppMode, String hapName) { 339 UncompressResult compressResult = new UncompressResult(); 340 if (input == null) { 341 LOG.error("UncompressEntrance::parseApp input is null!"); 342 compressResult.setResult(false); 343 compressResult.setMessage("ParseApp input is null"); 344 return compressResult; 345 } 346 Utility utility = new Utility(); 347 utility.setParseMode(parseAppMode.getType()); 348 utility.setDeviceType(""); 349 utility.setHapName(hapName); 350 if (!UncompressVerify.isParseAppModeValid(utility.getParseMode(), utility.getHapName())) { 351 compressResult.setResult(false); 352 compressResult.setMessage("ParseApp verify failed"); 353 return compressResult; 354 } 355 compressResult = Uncompress.uncompressAppByInput(utility, input); 356 return compressResult; 357 } 358 359 /** 360 * Parse the hap. 361 * 362 * @param hapPath Indicates the hap path. 363 * @return Return the uncomperss result of parseHap 364 */ parseHap(String hapPath)365 public static UncompressResult parseHap(String hapPath) { 366 UncompressResult compressResult = new UncompressResult(); 367 368 Utility utility = new Utility(); 369 utility.setHapPath(hapPath); 370 if (!UncompressVerify.isPathValid(utility.getHapPath(), true, HAP_SUFFIX) && 371 !UncompressVerify.isPathValid(utility.getHapPath(), true, HSP_SUFFIX)) { 372 LOG.error("UncompressEntrance::parseHap must input a hap file!"); 373 compressResult.setResult(false); 374 compressResult.setMessage("ParseHap hapPath is invalid"); 375 } 376 377 compressResult = Uncompress.uncompressHap(utility); 378 379 return compressResult; 380 } 381 382 /** 383 * Parse the hap. 384 * 385 * @param input Indicates the InputStream about the app package. 386 * @return Return the uncomperss result of parseHap 387 */ parseHap(InputStream input)388 public static UncompressResult parseHap(InputStream input) { 389 UncompressResult compressResult = new UncompressResult(); 390 391 if (input == null) { 392 LOG.error("UncompressEntrance::parseHap input is null!"); 393 compressResult.setResult(false); 394 compressResult.setMessage("ParseHap input is null"); 395 return compressResult; 396 } 397 398 Utility utility = new Utility(); 399 compressResult = Uncompress.uncompressHapByInput(utility, input); 400 return compressResult; 401 } 402 403 /** 404 * Parse the hap resource. 405 * 406 * @param hapPath Indicates the hap path. 407 * @return Return the List<ResourceIndexResult> result of parseHap 408 */ parseResource(String hapPath)409 public static List<ResourceIndexResult> parseResource(String hapPath) throws BundleException, IOException { 410 return getResourceFromHap(hapPath); 411 } 412 413 /** 414 * Parse the appqf file. 415 * 416 * @param appqfPath Indicates the hap path. 417 * @return Return the List<ResourceIndexResult> result of parseHap 418 */ parseAPPQF(String appqfPath)419 public static APPQFResult parseAPPQF(String appqfPath) { 420 APPQFResult result = new APPQFResult(); 421 if (!appqfPath.endsWith(APPQF_SUFFIX)) { 422 LOG.error("UncompressEntrance::parseAPPQF Error, input wrong type APPQF file!"); 423 result.setSuccess(false); 424 } 425 try { 426 result.setHqfInfoList(Uncompress.parseAPPQFFile(appqfPath)); 427 result.setSuccess(true); 428 } catch (BundleException e) { 429 LOG.error("UncompressEntrance::parseAPPQF failed, read patch.json in APPQF file failed!"); 430 result.setSuccess(false); 431 } 432 return result; 433 } 434 435 /** 436 * uncompress tool main function. 437 * 438 * @param args command line 439 */ main(String[] args)440 public static void main(String[] args) { 441 Utility utility = new Utility(); 442 443 if (!CommandParser.commandParser(utility, args)) { 444 LOG.error("UncompressEntrance::main exit, parser failed"); 445 ShowHelp.uncompressHelp(); 446 System.exit(EXIT_STATUS_EXCEPTION); 447 } 448 449 if (!UncompressVerify.commandVerify(utility)) { 450 LOG.error("UncompressEntrance::main exit, verify failed"); 451 ShowHelp.uncompressHelp(); 452 System.exit(EXIT_STATUS_EXCEPTION); 453 } 454 455 if (!Uncompress.unpackageProcess(utility)) { 456 LOG.error("UncompressEntrance::main exit, uncompress failed"); 457 ShowHelp.uncompressHelp(); 458 System.exit(EXIT_STATUS_EXCEPTION); 459 } 460 461 System.exit(EXIT_STATUS_NORMAL); 462 } 463 }