1 /* 2 * Copyright (c) 2021-2023 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.BufferedOutputStream; 19 import java.io.BufferedInputStream; 20 import java.io.BufferedReader; 21 import java.io.File; 22 import java.io.FileInputStream; 23 import java.io.FileNotFoundException; 24 import java.io.FileOutputStream; 25 import java.io.FileWriter; 26 import java.io.IOException; 27 import java.io.InputStream; 28 import java.io.InputStreamReader; 29 import java.io.OutputStream; 30 import java.nio.charset.StandardCharsets; 31 import java.nio.file.attribute.FileTime; 32 33 import java.util.ArrayList; 34 import java.util.Arrays; 35 import java.util.Enumeration; 36 import java.util.HashMap; 37 import java.util.List; 38 import java.util.Locale; 39 import java.util.Optional; 40 import java.util.regex.Matcher; 41 import java.util.regex.Pattern; 42 import java.util.zip.CRC32; 43 import java.util.zip.CheckedOutputStream; 44 import java.util.zip.ZipInputStream; 45 import java.util.zip.ZipEntry; 46 import java.util.zip.ZipFile; 47 import java.util.zip.ZipOutputStream; 48 49 50 /** 51 * bundle compressor class, compress file and directory. 52 * 53 */ 54 public class Compressor { 55 private static final String JSON_SUFFIX = ".json"; 56 private static final String INFO_SUFFIX = ".info"; 57 private static final String HAP_SUFFIX = ".hap"; 58 private static final String HSP_SUFFIX = ".hsp"; 59 private static final String PNG_SUFFIX = ".png"; 60 private static final String APP_SUFFIX = ".app"; 61 private static final String UPPERCASE_PNG_SUFFIX = ".PNG"; 62 private static final String CONFIG_JSON = "config.json"; 63 private static final String MODULE_JSON = "module.json"; 64 private static final String CODE = "code"; 65 private static final String NAME = "name"; 66 private static final String VERSION = "\"version\""; 67 private static final String VERSION_CODE = "\"versionCode\""; 68 private static final String NULL_DIR_NAME = ""; 69 private static final String RES_DIR_NAME = "res/"; 70 private static final String RESOURCES_DIR_NAME = "resources/"; 71 private static final String LIBS_DIR_NAME = "libs/"; 72 private static final String AN_DIR_NAME = "an/"; 73 private static final String ASSETS_DIR_NAME = "assets/"; 74 private static final String SO_DIR_NAME = "maple/"; 75 private static final String SO_ARM64_DIR_NAME = "maple/arm64/"; 76 private static final String LINUX_FILE_SEPARATOR = "/"; 77 private static final String DISTRO = "distro"; 78 private static final String FORMS = "forms"; 79 private static final String MODULE_NAME = "module-name"; 80 private static final String MODULE_NAME_NEW = "moduleName"; 81 private static final String JSON_END = "}"; 82 private static final String SEMICOLON = "\""; 83 private static final String APPLICATION = "deviceConfig"; 84 private static final String COMPRESS_NATIVE_LIBS = "compressNativeLibs"; 85 private static final String SHARED_LIBS_DIR_NAME = "shared_libs/"; 86 private static final String DEVICE_TYPE = "deviceType"; 87 private static final String DEVICE_TYPE_FITNESSWATCH = "fitnessWatch"; 88 private static final String DEVICE_TYPE_FITNESSWATCH_NEW = "liteWearable"; 89 private static final String COLON = ":"; 90 private static final String COMMA = ","; 91 private static final String ENTRYCARD_NAME = "EntryCard/"; 92 private static final String PACKINFO_NAME = "pack.info"; 93 private static final String ENTRYCARD_BASE_NAME = "base"; 94 private static final String ENTRYCARD_SNAPSHOT_NAME = "snapshot"; 95 private static final String VERTICAL = "vertical"; 96 private static final String HORIZONTAL = "horizontal"; 97 private static final String CAR = "car"; 98 private static final String TV = "tv"; 99 private static final String SDIP = "sdip"; 100 private static final String MDIP = "mdip"; 101 private static final String WEARABLE = "wearable"; 102 private static final String PIC_1X2 = "1x2"; 103 private static final String PIC_2X2 = "2x2"; 104 private static final String PIC_2X4 = "2x4"; 105 private static final String PIC_4X4 = "4x4"; 106 private static final String REGEX_LANGUAGE = "^[a-z]{2}$"; 107 private static final String REGEX_SCRIPT = "^[A-Z][a-z]{3}$"; 108 private static final String REGEX_COUNTRY = "^[A-Z]{2,3}|[0-9]{3}$"; 109 private static final String REGEX_ORIENTATION = "^vertical|horizontal$"; 110 private static final String REGEX_DEVICE_TYPE = "^phone|tablet|car|tv|wearable|liteWearable$"; 111 private static final String REGEX_SCREEN_DENSITY = "^sdpi|mdpi|ldpi|xldpi|xxldpi$"; 112 private static final String REGEX_COLOR_MODE = "^light|dark$"; 113 private static final String REGEX_SHAPE = "^circle$"; 114 private static final String JS_PATH = "js/"; 115 private static final String ETS_PATH = "ets/"; 116 private static final String TEMP_HAP_DIR = "tempHapDir"; 117 private static final String TEMP_SELECTED_HAP_DIR = "tempSelectedHapDir"; 118 private static final String ABILITIES_DIR_NAME = "abilities"; 119 private static final String EMPTY_STRING = ""; 120 private static final String RELEASE = "Release"; 121 private static final String AP_PATH_NAME = "ap/"; 122 private static final String ATOMIC_SERVICE = "atomicService"; 123 private static final String TYPE_SHARED = "shared"; 124 125 126 // set timestamp to get fixed MD5 127 private static final long FILE_TIME = 1546272000000L; 128 129 // set buffer size of each read 130 private static final int BUFFER_SIZE = 10 * 1024; 131 private static final Log LOG = new Log(Compressor.class.toString()); 132 private static final int ENTRY_FILE_LIMIT_DEFAULT = 2; 133 private static final int NOT_ENTRY_FILE_LIMIT_DEFAULT = 2; 134 private static final int TOTAL_FILE_LIMIT_DEFAULT = 10; 135 private static final int FILE_LIMIT = 10; 136 private static String versionCode = ""; 137 private static String versionName = ""; 138 private static int entryModuleSizeLimit = 2; 139 private static int notEntryModuleSizeLimit = 2; 140 private static int sumModuleSizeLimit = 10; 141 142 private ZipOutputStream zipOut = null; 143 private boolean mIsContain2x2EntryCard = true; 144 private List<String> list = new ArrayList<String>(); 145 private List<String> formNamesList = new ArrayList<String>(); 146 private List<String> fileNameList = new ArrayList<String>(); 147 private List<String> supportDimensionsList = Arrays.asList(PIC_1X2, PIC_2X2, PIC_2X4, PIC_4X4); 148 getEntryModuleSizeLimit()149 public static int getEntryModuleSizeLimit() { 150 return entryModuleSizeLimit; 151 } 152 setEntryModuleSizeLimit(int entry)153 public static void setEntryModuleSizeLimit(int entry) { 154 entryModuleSizeLimit = entry; 155 } 156 getNotEntryModuleSizeLimit()157 public static int getNotEntryModuleSizeLimit() { 158 return notEntryModuleSizeLimit; 159 } 160 setNotEntryModuleSizeLimit(int notEntry)161 public static void setNotEntryModuleSizeLimit(int notEntry) { 162 notEntryModuleSizeLimit = notEntry; 163 } 164 getSumModuleSizeLimit()165 public static int getSumModuleSizeLimit() { 166 return sumModuleSizeLimit; 167 } 168 setSumModuleSizeLimit(int sumModule)169 public static void setSumModuleSizeLimit(int sumModule) { 170 sumModuleSizeLimit = sumModule; 171 } 172 173 /** 174 * parse file size limit from utility. 175 * 176 * @param utility Indicates the utility. 177 */ parseFileSizeLimit(Utility utility)178 public void parseFileSizeLimit(Utility utility) throws BundleException { 179 int sumLimit = TOTAL_FILE_LIMIT_DEFAULT; 180 String totalLimit = utility.getTotalLimit(); 181 if (!totalLimit.isEmpty()) { 182 sumLimit = Integer.parseInt(totalLimit); 183 if (sumLimit <= 0 || sumLimit > FILE_LIMIT) { 184 LOG.error("parseFileSizeLimit failed, input total-limit invalid."); 185 throw new BundleException("parseFileSizeLimit failed, input total-limit invalid."); 186 } 187 } 188 189 String normalLimit = utility.getNormalModuleLimit(); 190 int notEntry = NOT_ENTRY_FILE_LIMIT_DEFAULT; 191 if (!normalLimit.isEmpty()) { 192 notEntry = Integer.parseInt(normalLimit); 193 if (notEntry <= 0 || notEntry > sumLimit || notEntry > FILE_LIMIT) { 194 LOG.error("parseFileSizeLimit failed, input normal-module-limit invalid."); 195 throw new BundleException("parseFileSizeLimit failed, input normal-module-limit invalid."); 196 } 197 } 198 199 String mainLimit = utility.getMainModuleLimit(); 200 int entryLimit = ENTRY_FILE_LIMIT_DEFAULT; 201 if (!mainLimit.isEmpty()) { 202 entryLimit = Integer.parseInt(mainLimit); 203 if (entryLimit <= 0 || entryLimit > sumLimit || entryLimit > FILE_LIMIT) { 204 LOG.error("parseFileSizeLimit failed, input main-module-limit invalid."); 205 throw new BundleException("parseFileSizeLimit failed, input main-module-limit invalid."); 206 } 207 } 208 209 setEntryModuleSizeLimit(entryLimit); 210 setNotEntryModuleSizeLimit(notEntry); 211 setSumModuleSizeLimit(sumLimit); 212 } 213 214 /** 215 * check path if is a module.json file 216 * 217 * @param path path input 218 * @return true if path is a module file 219 */ isModuleJSON(String path)220 private static boolean isModuleJSON(String path) 221 { 222 File file = new File(path); 223 if ((file.isFile()) && MODULE_JSON.equals(file.getName())) { 224 return true; 225 } 226 return false; 227 } 228 229 /** 230 * start compress. 231 * file orders as follows: 232 * for hap: 1.config.json 2.lib 3.res 4.assets 5.*.so 6.*.dex 7.*.apk 8.resources.index 233 * for app: 1.certificate 2.signature 3.pack.info 4.hap (1 and 2 may not be used) 234 * 235 * @param utility common data 236 * @return compressProcess if compress succeed 237 */ compressProcess(Utility utility)238 public boolean compressProcess(Utility utility) { 239 boolean compressResult = true; 240 File destFile = new File(utility.getOutPath()); 241 242 // if out file directory not exist, mkdirs. 243 File outParentFile = destFile.getParentFile(); 244 if ((outParentFile != null) && (!outParentFile.exists())) { 245 if (!outParentFile.mkdirs()) { 246 LOG.error("Compressor::compressProcess create out file parent directory failed."); 247 return false; 248 } 249 } 250 251 FileOutputStream fileOut = null; 252 CheckedOutputStream checkedOut = null; 253 try { 254 fileOut = new FileOutputStream(destFile); 255 checkedOut = new CheckedOutputStream(fileOut, new CRC32()); 256 zipOut = new ZipOutputStream(checkedOut); 257 compressExcute(utility); 258 } catch (FileNotFoundException exception) { 259 compressResult = false; 260 LOG.error("Compressor::compressProcess file not found exception" + exception.getMessage()); 261 } catch (BundleException ignored) { 262 compressResult = false; 263 LOG.error("Compressor::compressProcess Bundle exception."); 264 } finally { 265 closeZipOutputStream(); 266 Utility.closeStream(zipOut); 267 Utility.closeStream(checkedOut); 268 Utility.closeStream(fileOut); 269 } 270 // if compress failed, delete out file. 271 if (!compressResult) { 272 LOG.error("Compressor::compressProcess compress failed."); 273 if (!destFile.delete()) { 274 LOG.error("Compressor::compressProcess delete dest file failed."); 275 } 276 } 277 return compressResult; 278 } 279 compressExcute(Utility utility)280 private void compressExcute(Utility utility) throws BundleException { 281 switch (utility.getMode()) { 282 case Utility.MODE_HAP: 283 compressHap(utility); 284 break; 285 case Utility.MODE_HAR: 286 compressHarMode(utility); 287 break; 288 case Utility.MODE_APP: 289 compressAppMode(utility); 290 break; 291 case Utility.MODE_MULTI_APP: 292 compressAppModeForMultiProject(utility); 293 break; 294 case Utility.MODE_HQF: 295 compressHQFMode(utility); 296 break; 297 case Utility.MODE_APPQF: 298 compressAPPQFMode(utility); 299 break; 300 case Utility.MODE_HSP: 301 compressHsp(utility); 302 break; 303 default: 304 compressPackResMode(utility); 305 } 306 } 307 compressHsp(Utility utility)308 private void compressHsp(Utility utility) throws BundleException { 309 if (isModuleJSON(utility.getJsonPath())) { 310 Optional<String> optional = FileUtils.getFileContent(utility.getJsonPath()); 311 String jsonString = optional.get(); 312 if (!checkStageAtomicService(jsonString)) { 313 LOG.error("Error: checkStageAtomicService failed!"); 314 throw new BundleException("Error: checkStageHap failed!"); 315 } 316 String moduleType = ModuleJsonUtil.parseStageIsEntry(jsonString); 317 if (!TYPE_SHARED.equals(moduleType)) { 318 LOG.error("module type must be shared."); 319 throw new BundleException("compressHsp failed."); 320 } 321 } 322 compressHSPMode(utility); 323 } 324 compressHap(Utility utility)325 private void compressHap(Utility utility) throws BundleException { 326 if (isModuleJSON(utility.getJsonPath())) { 327 if (!checkStageHap(utility)) { 328 LOG.error("Error: checkStageHap failed."); 329 throw new BundleException("Error: checkStageHap failed."); 330 } 331 compressHapModeForModule(utility); 332 } else { 333 if (!checkFAHap(utility)) { 334 LOG.error("Error: checkFAHap failed."); 335 throw new BundleException("Error: checkStageHap failed."); 336 } 337 compressHapMode(utility); 338 } 339 } 340 checkStageHap(Utility utility)341 private static boolean checkStageHap(Utility utility) throws BundleException { 342 Optional<String> optional = FileUtils.getFileContent(utility.getJsonPath()); 343 String jsonString = optional.get(); 344 if (!checkStageAsanEnabledValid(jsonString)) { 345 LOG.error("Error: checkStageAsanEnabledValid failed!"); 346 return false; 347 } 348 // check atomicService in module.json 349 if (!checkStageAtomicService(jsonString)) { 350 LOG.error("Error: checkStageAtomicService failed!"); 351 return false; 352 } 353 String moduleType = ModuleJsonUtil.parseStageIsEntry(jsonString); 354 if (TYPE_SHARED.equals(moduleType)) { 355 LOG.warning("Compress mode is hap, but module type is shared."); 356 } 357 return true; 358 } 359 checkStageAsanEnabledValid(String jsonString)360 private static boolean checkStageAsanEnabledValid(String jsonString) throws BundleException { 361 boolean asanEnabled = ModuleJsonUtil.getStageAsanEnabled(jsonString); 362 boolean debug = ModuleJsonUtil.getDebug(jsonString); 363 if (asanEnabled && !debug) { 364 LOG.error("asanEnabled is not supported for Release."); 365 return false; 366 } 367 return true; 368 } 369 checkStageAtomicService(String jsonString)370 private static boolean checkStageAtomicService(String jsonString) throws BundleException { 371 // check consistency of atomicService 372 if (!ModuleJsonUtil.isModuleAtomicServiceValid(jsonString)) { 373 LOG.error("Error: check module atomicService failed!"); 374 return false; 375 } 376 // check entry module must have ability 377 if (!ModuleJsonUtil.checkEntryInAtomicService(jsonString)) { 378 LOG.error("checkEntryInAtomicService failed."); 379 return false; 380 } 381 // check installationFree 382 if (!ModuleJsonUtil.checkAtomicServiceInstallationFree(jsonString)) { 383 LOG.error("Error: check atomic service installationFree failed!"); 384 return false; 385 } 386 387 return true; 388 } 389 checkFAHap(Utility utility)390 private static boolean checkFAHap(Utility utility) throws BundleException { 391 Optional<String> optional = FileUtils.getFileContent(utility.getJsonPath()); 392 String jsonString = optional.get(); 393 return checkFAAsanEnabledValid(jsonString); 394 } 395 checkFAAsanEnabledValid(String jsonString)396 private static boolean checkFAAsanEnabledValid(String jsonString) throws BundleException { 397 boolean asanEnabled = ModuleJsonUtil.getFAAsanEnabled(jsonString); 398 boolean debug = ModuleJsonUtil.getFADebug(jsonString); 399 if (asanEnabled && !debug) { 400 LOG.error("asanEnabled is not supported for Release."); 401 return false; 402 } 403 return true; 404 } 405 406 /** 407 * compress in hap mode. 408 * 409 * @param utility common data 410 * @throws BundleException FileNotFoundException|IOException. 411 */ compressHapMode(Utility utility)412 private void compressHapMode(Utility utility) throws BundleException { 413 pathToFile(utility, utility.getJsonPath(), NULL_DIR_NAME, false); 414 415 pathToFile(utility, utility.getProfilePath(), NULL_DIR_NAME, false); 416 417 if (!utility.getIndexPath().isEmpty() && !utility.getModuleName().isEmpty()) { 418 String assetsPath = ASSETS_DIR_NAME + utility.getModuleName() + LINUX_FILE_SEPARATOR; 419 pathToFile(utility, utility.getIndexPath(), assetsPath, false); 420 } 421 422 if (!utility.getLibPath().isEmpty()) { 423 pathToFile(utility, utility.getLibPath(), LIBS_DIR_NAME, utility.isCompressNativeLibs()); 424 } 425 426 if (!utility.getFilePath().isEmpty()) { 427 pathToFile(utility, utility.getFilePath(), NULL_DIR_NAME, false); 428 } 429 430 if (!utility.getResPath().isEmpty() && !utility.getModuleName().isEmpty()) { 431 String resPath = ASSETS_DIR_NAME + utility.getModuleName() + LINUX_FILE_SEPARATOR 432 + RESOURCES_DIR_NAME; 433 String deviceTypes = utility.getDeviceType().replace("\"", "").trim(); 434 if (DEVICE_TYPE_FITNESSWATCH.equals(deviceTypes) || 435 DEVICE_TYPE_FITNESSWATCH_NEW.equals(deviceTypes)) { 436 resPath = RES_DIR_NAME; 437 } 438 pathToFile(utility, utility.getResPath(), resPath, false); 439 } 440 441 if (!utility.getResourcesPath().isEmpty() && !utility.getModuleName().isEmpty()) { 442 String resourcesPath = ASSETS_DIR_NAME + utility.getModuleName() + LINUX_FILE_SEPARATOR 443 + RESOURCES_DIR_NAME; 444 pathToFile(utility, utility.getResourcesPath(), resourcesPath, false); 445 } 446 447 if (!utility.getRpcidPath().isEmpty()) { 448 String rpcidPath = NULL_DIR_NAME; 449 pathToFile(utility, utility.getRpcidPath(), rpcidPath, false); 450 } 451 452 if (!utility.getPackInfoPath().isEmpty()) { 453 String packInfoPath = NULL_DIR_NAME; 454 pathToFile(utility, utility.getPackInfoPath(), packInfoPath, false); 455 } 456 457 if (!utility.getAssetsPath().isEmpty()) { 458 pathToFile(utility, utility.getAssetsPath(), ASSETS_DIR_NAME, false); 459 } 460 461 if (!utility.getBinPath().isEmpty()) { 462 pathToFile(utility, utility.getBinPath(), NULL_DIR_NAME, false); 463 } 464 // pack --dir-list 465 if (!utility.getFormatedDirList().isEmpty()) { 466 for (int i = 0; i < utility.getFormatedDirList().size(); ++i) { 467 String baseDir = new File(utility.getFormatedDirList().get(i)).getName() + File.separator; 468 pathToFile(utility, utility.getFormatedDirList().get(i), baseDir, false); 469 } 470 } 471 472 compressHapModeMultiple(utility); 473 } 474 475 /** 476 * compress in hap mode for module.json. 477 * 478 * @param utility common data 479 * @throws BundleException FileNotFoundException|IOException. 480 */ compressHapModeForModule(Utility utility)481 private void compressHapModeForModule(Utility utility) throws BundleException { 482 pathToFile(utility, utility.getJsonPath(), NULL_DIR_NAME, false); 483 484 pathToFile(utility, utility.getProfilePath(), NULL_DIR_NAME, false); 485 486 if (!utility.getIndexPath().isEmpty() && isModuleJSON(utility.getJsonPath())) { 487 String assetsPath = NULL_DIR_NAME; 488 pathToFile(utility, utility.getIndexPath(), assetsPath, false); 489 } 490 491 if (!utility.getLibPath().isEmpty()) { 492 pathToFile(utility, utility.getLibPath(), LIBS_DIR_NAME, utility.isCompressNativeLibs()); 493 } 494 495 if (!utility.getANPath().isEmpty()) { 496 pathToFile(utility, utility.getANPath(), AN_DIR_NAME, false); 497 } 498 499 if (!utility.getAPPath().isEmpty()) { 500 pathToFile(utility, utility.getAPPath(), AP_PATH_NAME, false); 501 } 502 503 if (!utility.getFilePath().isEmpty()) { 504 pathToFile(utility, utility.getFilePath(), NULL_DIR_NAME, false); 505 } 506 507 if (!utility.getResPath().isEmpty() && !utility.getModuleName().isEmpty()) { 508 String resPath = ASSETS_DIR_NAME + utility.getModuleName() + LINUX_FILE_SEPARATOR 509 + RESOURCES_DIR_NAME; 510 String deviceTypes = utility.getDeviceType().replace("\"", "").trim(); 511 if (DEVICE_TYPE_FITNESSWATCH.equals(deviceTypes) || 512 DEVICE_TYPE_FITNESSWATCH_NEW.equals(deviceTypes)) { 513 resPath = RES_DIR_NAME; 514 } 515 pathToFile(utility, utility.getResPath(), resPath, false); 516 } 517 518 if (!utility.getResourcesPath().isEmpty() && isModuleJSON(utility.getJsonPath())) { 519 String resourcesPath = RESOURCES_DIR_NAME; 520 pathToFile(utility, utility.getResourcesPath(), resourcesPath, false); 521 } 522 if (!utility.getJsPath().isEmpty() && isModuleJSON(utility.getJsonPath())) { 523 String jsPath = JS_PATH; 524 pathToFile(utility, utility.getJsPath(), jsPath, false); 525 } 526 527 if (!utility.getEtsPath().isEmpty() && isModuleJSON(utility.getJsonPath())) { 528 String etsPath = ETS_PATH; 529 pathToFile(utility, utility.getEtsPath(), etsPath, false); 530 } 531 532 if (!utility.getRpcidPath().isEmpty()) { 533 String rpcidPath = NULL_DIR_NAME; 534 pathToFile(utility, utility.getRpcidPath(), rpcidPath, false); 535 } 536 537 if (!utility.getAssetsPath().isEmpty()) { 538 pathToFile(utility, utility.getAssetsPath(), ASSETS_DIR_NAME, false); 539 } 540 541 if (!utility.getBinPath().isEmpty()) { 542 pathToFile(utility, utility.getBinPath(), NULL_DIR_NAME, false); 543 } 544 545 if (!utility.getPackInfoPath().isEmpty()) { 546 pathToFile(utility, utility.getPackInfoPath(), NULL_DIR_NAME, false); 547 } 548 549 // pack --dir-list 550 if (!utility.getFormatedDirList().isEmpty()) { 551 for (int i = 0; i < utility.getFormatedDirList().size(); ++i) { 552 String baseDir = new File(utility.getFormatedDirList().get(i)).getName() + File.separator; 553 pathToFile(utility, utility.getFormatedDirList().get(i), baseDir, false); 554 } 555 } 556 557 compressHapModeMultiple(utility); 558 } 559 560 /** 561 * compress in hap mode multiple path. 562 * 563 * @param utility common data 564 * @throws BundleException FileNotFoundException|IOException. 565 */ compressHapModeMultiple(Utility utility)566 private void compressHapModeMultiple(Utility utility) throws BundleException { 567 for (String soPathItem : utility.getFormattedSoPathList()) { 568 pathToFile(utility, soPathItem, SO_ARM64_DIR_NAME, false); 569 } 570 571 if (utility.getFormattedSoPathList().size() == 0 && !utility.getSoDir().isEmpty()) { 572 pathToFile(utility, utility.getSoDir(), SO_DIR_NAME, false); 573 } 574 575 for (String soPathItem : utility.getFormattedAbilitySoPathList()) { 576 pathToFile(utility, soPathItem, NULL_DIR_NAME, false); 577 } 578 579 for (String dexPathItem : utility.getFormattedDexPathList()) { 580 pathToFile(utility, dexPathItem, NULL_DIR_NAME, false); 581 } 582 583 for (String abcPathItem : utility.getFormattedAbcPathList()) { 584 pathToFile(utility, abcPathItem, NULL_DIR_NAME, false); 585 } 586 587 for (String apkPathItem : utility.getFormattedApkPathList()) { 588 pathToFile(utility, apkPathItem, NULL_DIR_NAME, false); 589 } 590 591 for (String jarPathItem : utility.getFormattedJarPathList()) { 592 pathToFile(utility, jarPathItem, NULL_DIR_NAME, false); 593 } 594 595 for (String txtPathItem : utility.getFormattedTxtPathList()) { 596 pathToFile(utility, txtPathItem, NULL_DIR_NAME, false); 597 } 598 599 if (!utility.getSharedLibsPath().isEmpty()) { 600 pathToFile(utility, utility.getSharedLibsPath(), SHARED_LIBS_DIR_NAME, utility.isCompressNativeLibs()); 601 } 602 } 603 604 /** 605 * compress in har mode. 606 * 607 * @param utility common data 608 * @throws BundleException FileNotFoundException|IOException. 609 */ compressHarMode(Utility utility)610 private void compressHarMode(Utility utility) throws BundleException { 611 pathToFile(utility, utility.getJsonPath(), NULL_DIR_NAME, false); 612 613 if (!utility.getLibPath().isEmpty()) { 614 pathToFile(utility, utility.getLibPath(), LIBS_DIR_NAME, utility.isCompressNativeLibs()); 615 } 616 617 if (!utility.getResPath().isEmpty()) { 618 pathToFile(utility, utility.getResPath(), RESOURCES_DIR_NAME, false); 619 } 620 621 if (!utility.getResourcesPath().isEmpty()) { 622 pathToFile(utility, utility.getResourcesPath(), RESOURCES_DIR_NAME, false); 623 } 624 625 if (!utility.getAssetsPath().isEmpty()) { 626 pathToFile(utility, utility.getAssetsPath(), ASSETS_DIR_NAME, false); 627 } 628 629 for (String jarPathItem : utility.getFormattedJarPathList()) { 630 pathToFile(utility, jarPathItem, NULL_DIR_NAME, false); 631 } 632 633 for (String txtPathItem : utility.getFormattedTxtPathList()) { 634 pathToFile(utility, txtPathItem, NULL_DIR_NAME, false); 635 } 636 } 637 638 /** 639 * compress in app mode. 640 * 641 * @param utility common data 642 * @throws BundleException FileNotFoundException|IOException. 643 */ compressAppMode(Utility utility)644 private void compressAppMode(Utility utility) throws BundleException { 645 List<String> fileList = new ArrayList<>(); 646 File appOutputFile = new File(utility.getOutPath().trim()); 647 String tempPath = appOutputFile.getParentFile().getParent() + File.separator + TEMP_HAP_DIR; 648 try { 649 pathToFile(utility, utility.getJsonPath(), NULL_DIR_NAME, false); 650 651 if (!utility.getCertificatePath().isEmpty()) { 652 pathToFile(utility, utility.getCertificatePath(), NULL_DIR_NAME, false); 653 } 654 655 if (!utility.getSignaturePath().isEmpty()) { 656 pathToFile(utility, utility.getSignaturePath(), NULL_DIR_NAME, false); 657 } 658 659 File tempDir = new File(tempPath); 660 if (!tempDir.exists()) { 661 tempDir.mkdirs(); 662 } 663 664 for (String hapPathItem : utility.getFormattedHapPathList()) { 665 File hapFile = new File(hapPathItem.trim()); 666 String hapTempPath = tempDir + File.separator + hapFile.getName(); 667 fileList.add(hapTempPath); 668 try { 669 compressPackinfoIntoHap(hapPathItem, hapTempPath, utility.getPackInfoPath()); 670 } catch (IOException e) { 671 LOG.error("Compressor::compressAppMode compress pack.info into hap failed."); 672 throw new BundleException("Compressor::compressAppMode compress pack.info into hap failed."); 673 } 674 } 675 676 for (String hspPathItem : utility.getFormattedHspPathList()) { 677 File hspFile = new File(hspPathItem.trim()); 678 String hspTempPath = tempDir + File.separator + hspFile.getName(); 679 fileList.add(hspTempPath); 680 try { 681 compressPackinfoIntoHap(hspPathItem, hspTempPath, utility.getPackInfoPath()); 682 } catch (IOException e) { 683 LOG.error("Compressor::compressAppMode compress pack.info into hsp failed."); 684 throw new BundleException("Compressor::compressAppMode compress pack.info into hsp failed."); 685 } 686 } 687 parseFileSizeLimit(utility); 688 // check hap is valid 689 if (!checkHapIsValid(fileList)) { 690 throw new BundleException("Compressor::compressFile verify failed, check version, " + 691 "apiVersion,moduleName,packageName."); 692 } 693 for (String hapPath : fileList) { 694 pathToFile(utility, hapPath, NULL_DIR_NAME, false); 695 } 696 697 if (!utility.getEntryCardPath().isEmpty()) { 698 String entryCardPath = ENTRYCARD_NAME + utility.getModuleName() + LINUX_FILE_SEPARATOR 699 + ENTRYCARD_BASE_NAME + ENTRYCARD_SNAPSHOT_NAME; 700 for (String entryCardPathItem : utility.getformattedEntryCardPathList()) { 701 pathToFile(utility, entryCardPathItem, entryCardPath, true); 702 } 703 } 704 705 if (!utility.getPackResPath().isEmpty()) { 706 pathToFile(utility, utility.getPackResPath(), NULL_DIR_NAME, false); 707 } 708 File file = new File(utility.getPackInfoPath()); 709 compressFile(utility, file, NULL_DIR_NAME, false); 710 } catch (BundleException e) { 711 LOG.error("Compressor::compressAppMode compress failed."); 712 throw new BundleException("Compressor::compressAppMode compress failed."); 713 } finally { 714 // delete temp file 715 for (String path : fileList) { 716 deleteFile(path); 717 } 718 deleteFile(tempPath); 719 } 720 } 721 722 /** 723 * compress in app mode for multi project. 724 * 725 * @param utility common data 726 * @throws BundleException FileNotFoundException|IOException. 727 */ compressAppModeForMultiProject(Utility utility)728 private void compressAppModeForMultiProject(Utility utility) throws BundleException { 729 List<String> fileList = new ArrayList<>(); 730 File appOutputFile = new File(utility.getOutPath().trim()); 731 String tempPath = appOutputFile.getParentFile().getParent() + File.separator + TEMP_HAP_DIR; 732 String tempSelectedHapPath = appOutputFile.getParentFile().getParent() +File.separator + TEMP_SELECTED_HAP_DIR; 733 try { 734 File tempSelectedHapDir = new File(tempSelectedHapPath); 735 FileUtils.makeDir(tempSelectedHapDir); 736 File tempHapDir = new File(tempPath); 737 FileUtils.makeDir(tempHapDir); 738 // pack app and dispose conflict 739 // save hap name into list 740 List<String> seletedHaps = new ArrayList<>(); 741 String finalPackInfoStr = disposeApp(utility, seletedHaps, tempSelectedHapPath); 742 // pack hap and dispose conflict 743 finalPackInfoStr = disposeHap(utility, seletedHaps, tempSelectedHapPath, finalPackInfoStr); 744 745 // save final pack.info file 746 String finalPackInfoPath = tempSelectedHapDir.getPath() + File.separator + PACKINFO_NAME; 747 writePackInfo(finalPackInfoPath, finalPackInfoStr); 748 // pack haps 749 for (String selectedHapName : seletedHaps) { 750 String hapPathItem = tempSelectedHapDir.getPath() + File.separator + selectedHapName; 751 File hapFile = new File(hapPathItem.trim()); 752 String hapTempPath = tempHapDir.getPath() + File.separator + hapFile.getName(); 753 fileList.add(hapTempPath); 754 compressPackinfoIntoHap(hapPathItem, hapTempPath, finalPackInfoPath); 755 } 756 // check hap is valid 757 if (!checkHapIsValid(fileList)) { 758 String errMsg = "Compressor::compressAppModeForMultiProject There are some " + 759 "haps with different version code or duplicated moduleName or packageName."; 760 throw new BundleException(errMsg); 761 } 762 for (String hapPath : fileList) { 763 pathToFile(utility, hapPath, NULL_DIR_NAME, false); 764 } 765 File file = new File(finalPackInfoPath); 766 compressFile(utility, file, NULL_DIR_NAME, false); 767 } catch (BundleException | IOException exception) { 768 String errMsg = "Compressor::compressAppModeForMultiProject file failed."; 769 LOG.error(errMsg); 770 throw new BundleException(errMsg); 771 } finally { 772 deleteFile(tempPath); 773 deleteFile(tempSelectedHapPath); 774 } 775 } 776 777 /** 778 * pack hap in app to selectedHaps 779 * 780 * @param utility is common data 781 * @param seletedHaps is seleted haps should be pack into app 782 * @return the final pack.info string after dispose app 783 * @throws BundleException FileNotFoundException|IOException. 784 */ disposeApp(Utility utility, List<String> seletedHaps, String tempDir)785 private static String disposeApp(Utility utility, List<String> seletedHaps, 786 String tempDir) throws BundleException { 787 // dispose app conflict 788 if (utility.getFormattedAppList().isEmpty()) { 789 return ""; 790 } 791 String finalAppPackInfo = ""; 792 try { 793 for (String appPath : utility.getFormattedAppList()) { 794 // select hap in app 795 finalAppPackInfo = selectHapInApp(appPath, seletedHaps, tempDir, finalAppPackInfo); 796 } 797 } catch (BundleException | IOException e) { 798 String errMsg = "Compressor:disposeApp disposeApp failed."; 799 LOG.error(errMsg); 800 throw new BundleException(errMsg); 801 } 802 return finalAppPackInfo; 803 } 804 805 /** 806 * select hap from app file list 807 * 808 * @param appPath is common data 809 * @param selectedHaps is list of packInfos 810 * @throws BundleException FileNotFoundException|IOException. 811 */ selectHapInApp(String appPath, List<String> selectedHaps, String tempDir, String finalAppPackInfo)812 private static String selectHapInApp(String appPath, List<String> selectedHaps, String tempDir, 813 String finalAppPackInfo) throws BundleException, IOException { 814 List<String> selectedHapsInApp = new ArrayList<>(); 815 // classify hap in app 816 copyHapAndHspFromApp(appPath, selectedHapsInApp, selectedHaps, tempDir); 817 // rebuild pack.info 818 String packInfoStr = FileUtils.getJsonInZips(new File(appPath), PACKINFO_NAME); 819 if (packInfoStr.isEmpty()) { 820 String errorMsg = "Compressor:selectHapInApp failed, app has no pack.info."; 821 LOG.error(errorMsg); 822 throw new BundleException(errorMsg); 823 } 824 if (finalAppPackInfo.isEmpty()) { 825 finalAppPackInfo = packInfoStr; 826 return finalAppPackInfo; 827 } 828 // read selected module in temp hap 829 HashMap<String, String> packagePair = new HashMap<>(); 830 for (String hapName : selectedHapsInApp) { 831 packagePair.put(hapName, readModlueNameFromHap(tempDir + File.separator + hapName)); 832 } 833 return ModuleJsonUtil.mergeTwoPackInfoByPackagePair(finalAppPackInfo, packInfoStr, packagePair); 834 } 835 836 /** 837 * copy hap from app file 838 * 839 * @param appPath is common data 840 * @param selectedHapsInApp is list of haps and hsps selected in app file 841 * @param selectedHaps is the list of haps and hsps selected in input 842 * @throws BundleException FileNotFoundException|IOException. 843 */ copyHapAndHspFromApp(String appPath, List<String> selectedHapsInApp, List<String> selectedHaps, String tempDir)844 private static void copyHapAndHspFromApp(String appPath, List<String> selectedHapsInApp, List<String> selectedHaps, 845 String tempDir) throws BundleException, IOException { 846 ZipInputStream zipInput = null; 847 ZipFile zipFile = null; 848 OutputStream outputStream = null; 849 InputStream inputStream = null; 850 ZipEntry zipEntry = null; 851 try { 852 zipInput = new ZipInputStream(new FileInputStream(appPath)); 853 zipFile = new ZipFile(appPath); 854 while ((zipEntry = zipInput.getNextEntry()) != null) { 855 File file = null; 856 if (!zipEntry.getName().endsWith(HAP_SUFFIX) && !zipEntry.getName().endsWith(HSP_SUFFIX)) { 857 continue; 858 } 859 // copy duplicated hap to duplicated dir and get moduleName of duplicated hap 860 if (selectedHaps.contains(zipEntry.getName())) { 861 LOG.error("Compressor::copyHapFromApp file duplicated, file is " + zipEntry.getName() + "."); 862 throw new BundleException("Compressor::copyHapFromApp file duplicated, file is " 863 + zipEntry.getName()); 864 } else { 865 // copy selectedHap to tempDir 866 if (tempDir == null || EMPTY_STRING.equals(tempDir)) { 867 throw new BundleException("Compressor::copyHapFromApp tempDir is empty."); 868 } 869 file = new File(tempDir + File.separator + zipEntry.getName()); 870 selectedHaps.add(file.getName()); 871 selectedHapsInApp.add(file.getName()); 872 } 873 if (file == null || !file.exists()) { 874 throw new BundleException("Compressor::copyHapFromApp file is not exists."); 875 } 876 outputStream = new FileOutputStream(file); 877 inputStream = zipFile.getInputStream(zipEntry); 878 int len; 879 while ((len = inputStream.read()) != -1) { 880 outputStream.write(len); 881 } 882 outputStream.close(); 883 inputStream.close(); 884 } 885 } catch (IOException e) { 886 String errMsg = "Compressor:copyHapFromApp app path not found."; 887 LOG.error(errMsg); 888 throw new BundleException(errMsg); 889 } finally { 890 Utility.closeStream(zipInput); 891 Utility.closeStream(zipFile); 892 Utility.closeStream(outputStream); 893 Utility.closeStream(inputStream); 894 } 895 } 896 897 /** 898 * read moduleName in hap 899 * 900 * @param hapPath is path of hap file 901 * @throws BundleException FileNotFoundException|IOException. 902 */ readModlueNameFromHap(String hapPath)903 private static String readModlueNameFromHap(String hapPath) throws BundleException { 904 String moduleName = ""; 905 File hapFile = new File(hapPath); 906 if (isModuleHap(hapPath)) { 907 String jsonString = FileUtils.getJsonInZips(hapFile, MODULE_JSON); 908 moduleName = ModuleJsonUtil.parseStageModuleName(jsonString); 909 } else { 910 String jsonString = FileUtils.getJsonInZips(hapFile, CONFIG_JSON); 911 moduleName = ModuleJsonUtil.parseFaModuleName(jsonString); 912 } 913 return moduleName; 914 } 915 916 /** 917 * dispose input of hap 918 * 919 * @param utility is common data 920 * @param seletedHaps is the selected haps of all input 921 * @param tempDir is the path of temp directory 922 * @param finalPackInfoStr is the pack.info of the final app 923 * @throws BundleException FileNotFoundException|IOException. 924 */ disposeHap(Utility utility, List<String> seletedHaps, String tempDir, String finalPackInfoStr)925 private static String disposeHap(Utility utility, List<String> seletedHaps, String tempDir, 926 String finalPackInfoStr) throws BundleException, IOException { 927 // dispose hap conflict 928 if (utility.getFormattedHapList().isEmpty()) { 929 return finalPackInfoStr; 930 } 931 for (String hapPath : utility.getFormattedHapList()) { 932 if (seletedHaps.contains(new File(hapPath).getName())) { 933 LOG.error("Compressor::disposeHap file duplicated, file is " + new File(hapPath).getName()); 934 throw new BundleException("Compressor::disposeHap file duplicated, file is " 935 + new File(hapPath).getName() + "."); 936 } 937 File hapFile = new File(hapPath); 938 seletedHaps.add(hapFile.getName()); 939 // copy hap to tempDir 940 FileUtils.copyFile(hapFile, new File((tempDir +File.separator + hapFile.getName()))); 941 String packInfo = FileUtils.getJsonInZips(hapFile, PACKINFO_NAME); 942 943 if (packInfo.isEmpty()) { 944 String errMsg = "Compressor::disposeHap failed, hap has no pack.info."; 945 LOG.error(errMsg); 946 throw new BundleException(errMsg); 947 } 948 if (finalPackInfoStr.isEmpty()) { 949 finalPackInfoStr = packInfo; 950 } else { 951 finalPackInfoStr = ModuleJsonUtil.mergeTwoPackInfo(finalPackInfoStr, packInfo); 952 } 953 } 954 return finalPackInfoStr; 955 } 956 957 /** 958 * write string to pack.info 959 * 960 * @param filePath pack.info file path 961 * @param packInfoStr is the string of pack.info 962 * @throws BundleException FileNotFoundException|IOException. 963 */ writePackInfo(String filePath, String packInfoStr)964 private void writePackInfo(String filePath, String packInfoStr) throws BundleException, IOException { 965 FileWriter fwriter = null; 966 try { 967 fwriter = new FileWriter(filePath); 968 fwriter.write(packInfoStr); 969 } catch (IOException e) { 970 String errMsg = "Compressor:writePackInfo failed."; 971 LOG.error(errMsg); 972 throw new BundleException(errMsg); 973 } finally { 974 if (fwriter != null) { 975 fwriter.flush(); 976 fwriter.close(); 977 } 978 } 979 } 980 copy(InputStream input, OutputStream output)981 private void copy(InputStream input, OutputStream output) throws IOException { 982 int bytesRead; 983 byte[] data = new byte[BUFFER_SIZE]; 984 while ((bytesRead = input.read(data, 0, BUFFER_SIZE)) != -1) { 985 output.write(data, 0, bytesRead); 986 } 987 } 988 compressPackinfoIntoHap(String hapPathItem, String outPathString, String packInfo)989 private void compressPackinfoIntoHap(String hapPathItem, String outPathString, String packInfo) 990 throws FileNotFoundException, IOException, BundleException { 991 ZipFile sourceHapFile = new ZipFile(hapPathItem); 992 ZipOutputStream append = new ZipOutputStream(new FileOutputStream(outPathString)); 993 try { 994 Enumeration<? extends ZipEntry> entries = sourceHapFile.entries(); 995 while (entries.hasMoreElements()) { 996 ZipEntry zipEntry = entries.nextElement(); 997 if (zipEntry.getName() != null && PACKINFO_NAME.equals(zipEntry.getName())) { 998 continue; 999 } 1000 append.putNextEntry(zipEntry); 1001 if (!zipEntry.isDirectory()) { 1002 copy(sourceHapFile.getInputStream(zipEntry), append); 1003 } 1004 append.closeEntry(); 1005 } 1006 File packInfoFile = new File(packInfo); 1007 ZipEntry zipEntry = getStoredZipEntry(packInfoFile, PACKINFO_NAME); 1008 append.putNextEntry(zipEntry); 1009 FileInputStream in = new FileInputStream(packInfoFile); 1010 try { 1011 byte[] buf = new byte[BUFFER_SIZE]; 1012 int len; 1013 while ((len = in.read(buf)) != -1) { 1014 append.write(buf, 0, len); 1015 } 1016 } finally { 1017 in.close(); 1018 } 1019 append.closeEntry(); 1020 } catch (IOException exception) { 1021 LOG.error("Compressor::compressPackinfoIntoHap io exception."); 1022 throw new BundleException("Compressor::compressPackinfoIntoHap io exception."); 1023 } finally { 1024 sourceHapFile.close(); 1025 append.close(); 1026 } 1027 } 1028 1029 /** 1030 * zipFile 1031 * 1032 * @param path path 1033 */ zipFile(String path)1034 private void zipFile(String path) { 1035 FileOutputStream outputStream = null; 1036 ZipOutputStream out = null; 1037 try { 1038 File destFile = new File(path + HAP_SUFFIX); 1039 File outParentFile = destFile.getParentFile(); 1040 if ((outParentFile != null) && (!outParentFile.exists())) { 1041 if (!outParentFile.mkdirs()) { 1042 LOG.error("Compressor::compressProcess create out file parent directory failed."); 1043 } 1044 } 1045 outputStream = new FileOutputStream(destFile); 1046 out = new ZipOutputStream(new CheckedOutputStream(outputStream, new CRC32())); 1047 out.setMethod(ZipOutputStream.STORED); 1048 compress(new File(path), out, NULL_DIR_NAME, true); 1049 } catch (FileNotFoundException ignored) { 1050 LOG.error("zip file not found exception."); 1051 } finally { 1052 Utility.closeStream(out); 1053 Utility.closeStream(outputStream); 1054 deleteFile(path); 1055 } 1056 } 1057 1058 /** 1059 * copyFileUsingFileStreams pack.info 1060 * 1061 * @param source inputPath 1062 * @param dest outputPath 1063 * 1064 */ copyFileUsingFileStreams(String source, String dest)1065 private static void copyFileUsingFileStreams(String source, String dest) { 1066 FileInputStream input = null; 1067 FileOutputStream output = null; 1068 try { 1069 File inputFile = new File(source); 1070 File outputFile = new File(dest, PACKINFO_NAME); 1071 File outputFileParent = outputFile.getParentFile(); 1072 if (!outputFileParent.exists()) { 1073 outputFileParent.mkdirs(); 1074 } 1075 if (!outputFile.exists()) { 1076 outputFile.createNewFile(); 1077 } 1078 input = new FileInputStream(inputFile); 1079 output = new FileOutputStream(outputFile); 1080 byte[] buf = new byte[1024]; 1081 int bytesRead; 1082 while ((bytesRead = input.read(buf)) != -1) { 1083 output.write(buf, 0, bytesRead); 1084 } 1085 input.close(); 1086 output.close(); 1087 } catch (FileNotFoundException ignored) { 1088 LOG.error("copy file not found exception" + ignored.toString()); 1089 } catch (IOException msg) { 1090 LOG.error("IOException : " + msg.getMessage()); 1091 } finally { 1092 Utility.closeStream(input); 1093 Utility.closeStream(output); 1094 } 1095 } 1096 1097 1098 /** 1099 * unzip hap package to path 1100 * 1101 * @param hapPath zip file 1102 * @param destDir path after unzip file 1103 */ unzip(final String hapPath, final String destDir)1104 public static void unzip(final String hapPath, final String destDir) { 1105 File file = new File(destDir); 1106 if (!file.exists()) { 1107 file.mkdirs(); 1108 } 1109 ZipFile zipFile = null; 1110 BufferedInputStream bis = null; 1111 BufferedOutputStream bos = null; 1112 FileOutputStream fos = null; 1113 try { 1114 zipFile = new ZipFile(hapPath); 1115 Enumeration<? extends ZipEntry> entries = zipFile.entries(); 1116 int entriesNum = 0; 1117 while (entries.hasMoreElements()) { 1118 entriesNum++; 1119 ZipEntry entry = entries.nextElement(); 1120 if (entry == null) { 1121 continue; 1122 } 1123 if (entry.isDirectory()) { 1124 new File(destDir + File.separator + entry.getName()).mkdirs(); 1125 continue; 1126 } 1127 bis = new BufferedInputStream(zipFile.getInputStream(entry)); 1128 File newFile = new File(destDir + File.separator + entry.getName()); 1129 File parent = newFile.getParentFile(); 1130 if (parent != null && (!parent.exists())) { 1131 parent.mkdirs(); 1132 } 1133 fos = new FileOutputStream(newFile); 1134 bos = new BufferedOutputStream(fos, BUFFER_SIZE); 1135 writeFile(bis, bos, entry); 1136 bos.flush(); 1137 bos.close(); 1138 fos.close(); 1139 bis.close(); 1140 } 1141 } catch (FileNotFoundException ignored) { 1142 LOG.error("unzip file not found exception."); 1143 } catch (IOException msg) { 1144 LOG.error("unzip IOException : " + msg.getMessage()); 1145 } finally { 1146 Utility.closeStream(bos); 1147 Utility.closeStream(fos); 1148 Utility.closeStream(bis); 1149 Utility.closeStream(zipFile); 1150 } 1151 } 1152 1153 /** 1154 * unzipWriteFile 1155 * 1156 * @param bis BufferedInputStream 1157 * @param bos BufferedOutputStream 1158 * @param entry ZipEntry 1159 * @throws IOException IO 1160 */ writeFile(BufferedInputStream bis, BufferedOutputStream bos, ZipEntry entry)1161 private static void writeFile(BufferedInputStream bis, BufferedOutputStream bos, 1162 ZipEntry entry) throws IOException { 1163 int count; 1164 int total = 0; 1165 byte[] data = new byte[BUFFER_SIZE]; 1166 while ((count = bis.read(data, 0, BUFFER_SIZE)) != -1) { 1167 bos.write(data, 0, count); 1168 total += count; 1169 } 1170 } 1171 1172 /** 1173 * delete file 1174 * 1175 * @param path file path which will be deleted 1176 */ deleteFile(final String path)1177 private static void deleteFile(final String path) { 1178 File file = new File(path); 1179 if (file.exists()) { 1180 if (file.isDirectory()) { 1181 File[] files = file.listFiles(); 1182 for (int i = 0; i < files.length; i++) { 1183 deleteFile(files[i].toString()); 1184 } 1185 } 1186 file.delete(); 1187 } 1188 } 1189 1190 /** 1191 * compress in res mode. 1192 * 1193 * @param utility common data 1194 * @throws BundleException FileNotFoundException|IOException. 1195 */ compressPackResMode(Utility utility)1196 private void compressPackResMode(Utility utility) throws BundleException { 1197 if (!utility.getPackInfoPath().isEmpty()) { 1198 File file = new File(utility.getPackInfoPath()); 1199 infoSpecialProcess(utility, file); 1200 } 1201 if (!utility.getEntryCardPath().isEmpty()) { 1202 getFileList(utility.getEntryCardPath()); 1203 if (!mIsContain2x2EntryCard) { 1204 LOG.error("Compressor::compressPackResMode No 2x2 resource file exists."); 1205 throw new BundleException("No 2x2 resource file exists."); 1206 } 1207 for (String fileName : fileNameList) { 1208 if (fileName.endsWith(PNG_SUFFIX) || fileName.endsWith(UPPERCASE_PNG_SUFFIX)) { 1209 String fName = fileName.trim(); 1210 String[] temp = fName.replace("\\", "/").split("/"); 1211 if (temp.length < 4) { 1212 LOG.error("Compressor::compressPackResMode the hap file path is invalid, length: " 1213 + temp.length + "."); 1214 continue; 1215 } 1216 String moduleName = temp[temp.length - 4]; 1217 if (!isModelName(moduleName)) { 1218 String errMessage = "Compressor::compressProcess compress pack.res failed, " + 1219 "please check the related configurations in module " + moduleName + "."; 1220 LOG.error(errMessage); 1221 throw new BundleException(errMessage); 1222 } 1223 String fileLanguageCountryName = temp[temp.length - 3]; 1224 if (!isThirdLevelDirectoryNameValid(fileLanguageCountryName)) { 1225 LOG.error("Compressor::compressProcess compress failed third level directory name: " 1226 + fileLanguageCountryName + " is invalid, please check it with reference to this example: " 1227 + "zh_Hani_CN-vertical-car-mdpi-dark or zh_Hani_CN-vertical-car-mdpi."); 1228 throw new BundleException("Compress failed third level directory name Error."); 1229 } 1230 String filePicturingName = temp[temp.length - 1]; 1231 if (!isPicturing(filePicturingName, utility)) { 1232 LOG.error("Compressor::compressProcess Compress pack.res failed, Invalid resource file" + 1233 " name: " + filePicturingName + ", correct format example is formName-2x2.png."); 1234 throw new BundleException("Compress pack.res failed, Invalid resource file name: " 1235 + filePicturingName + ", correct format example is formName-2x2.png."); 1236 } 1237 1238 } else { 1239 LOG.error("Compressor::compressProcess compress failed No image in PNG format is found."); 1240 throw new BundleException("Compress pack.res failed, compress failed No image in" 1241 + " PNG format is found."); 1242 } 1243 } 1244 pathToFile(utility, utility.getEntryCardPath(), ENTRYCARD_NAME, false); 1245 } 1246 } 1247 1248 /** 1249 * Check whether modelname meets specifications. 1250 * 1251 * @param name modelName 1252 * @return false and true 1253 */ isModelName(String name)1254 private boolean isModelName(String name) { 1255 for (String listName : list) { 1256 if (name.equals(listName)) { 1257 return true; 1258 } 1259 } 1260 return false; 1261 } 1262 isThirdLevelDirectoryNameValid(String thirdLevelDirectoryName)1263 private boolean isThirdLevelDirectoryNameValid(String thirdLevelDirectoryName) { 1264 if (thirdLevelDirectoryName == null || thirdLevelDirectoryName.isEmpty()) { 1265 return false; 1266 } 1267 if (ENTRYCARD_BASE_NAME.equals(thirdLevelDirectoryName)) { 1268 return true; 1269 } 1270 // example: zh_Hani_CN-vertical-car-mdpi-dark or zh_Hani_CN-vertical-car-mdpi 1271 int firstDelimiterIndex = thirdLevelDirectoryName.indexOf("_"); 1272 if (firstDelimiterIndex < 0) { 1273 return false; 1274 } 1275 String language = thirdLevelDirectoryName.substring(0, firstDelimiterIndex); 1276 int secondDelimiterIndex = thirdLevelDirectoryName.indexOf("_", firstDelimiterIndex + 1); 1277 if (secondDelimiterIndex < 0) { 1278 return false; 1279 } 1280 String script = thirdLevelDirectoryName.substring(firstDelimiterIndex + 1, secondDelimiterIndex); 1281 int thirdDelimiterIndex = thirdLevelDirectoryName.indexOf("-", secondDelimiterIndex + 1); 1282 if (thirdDelimiterIndex < 0) { 1283 return false; 1284 } 1285 String country = thirdLevelDirectoryName.substring(secondDelimiterIndex + 1, thirdDelimiterIndex); 1286 if (!checkLanguage(language) || !checkScript(script) || !checkCountry(country)) { 1287 return false; 1288 } 1289 int forthDelimiterIndex = thirdLevelDirectoryName.indexOf("-", thirdDelimiterIndex + 1); 1290 if (forthDelimiterIndex < 0) { 1291 return false; 1292 } 1293 String orientation = thirdLevelDirectoryName.substring(thirdDelimiterIndex + 1, forthDelimiterIndex); 1294 int fifthDelimiterIndex = thirdLevelDirectoryName.indexOf("-", forthDelimiterIndex + 1); 1295 if (fifthDelimiterIndex < 0) { 1296 return false; 1297 } 1298 String deviceType = thirdLevelDirectoryName.substring(forthDelimiterIndex + 1, fifthDelimiterIndex); 1299 if (!checkOrientation(orientation) || !checkDeviceType(deviceType)) { 1300 return false; 1301 } 1302 int sixthDelimiterIndex = thirdLevelDirectoryName.indexOf("-", fifthDelimiterIndex + 1); 1303 if (sixthDelimiterIndex < 0) { 1304 String screenDensity = thirdLevelDirectoryName.substring(fifthDelimiterIndex + 1, 1305 thirdLevelDirectoryName.length()); 1306 return checkScreenDensity(screenDensity); 1307 } else { 1308 String screenDensity = thirdLevelDirectoryName.substring(fifthDelimiterIndex + 1, sixthDelimiterIndex); 1309 if (!checkScreenDensity(screenDensity)) { 1310 return false; 1311 } 1312 } 1313 int seventhDelimiterIndex = thirdLevelDirectoryName.indexOf("-", sixthDelimiterIndex + 1); 1314 if (seventhDelimiterIndex < 0) { 1315 String tmp = thirdLevelDirectoryName.substring(sixthDelimiterIndex + 1, thirdLevelDirectoryName.length()); 1316 return checkColorModeOrShape(tmp); 1317 } 1318 if (!checkColorMode(thirdLevelDirectoryName.substring(sixthDelimiterIndex + 1, seventhDelimiterIndex))) { 1319 return false; 1320 } 1321 String shape = thirdLevelDirectoryName.substring(seventhDelimiterIndex + 1, thirdLevelDirectoryName.length()); 1322 return checkShape(shape); 1323 } 1324 checkLanguage(String language)1325 private boolean checkLanguage(String language) { 1326 if (!Pattern.compile(REGEX_LANGUAGE).matcher(language).matches()) { 1327 LOG.error("Compressor::compressProcess language " + language + " is not in ISO 639-1 list."); 1328 return false; 1329 } 1330 return true; 1331 } 1332 checkScript(String script)1333 private boolean checkScript(String script) { 1334 if (!Pattern.compile(REGEX_SCRIPT).matcher(script).matches()) { 1335 LOG.error("Compressor::compressProcess script " + script + " is not in ISO 15924 list."); 1336 return false; 1337 } 1338 return true; 1339 } 1340 checkCountry(String country)1341 private boolean checkCountry(String country) { 1342 if (!Pattern.compile(REGEX_COUNTRY).matcher(country).matches()) { 1343 LOG.error("Compressor::compressProcess country " + country + " is not in ISO 3166-1 list."); 1344 return false; 1345 } 1346 return true; 1347 } 1348 checkOrientation(String orientation)1349 private boolean checkOrientation(String orientation) { 1350 if (!Pattern.compile(REGEX_ORIENTATION).matcher(orientation).matches()) { 1351 LOG.error("Compressor::compressProcess orientation " + orientation + 1352 " is not in {vertical, horizontal} list."); 1353 return false; 1354 } 1355 return true; 1356 } 1357 checkDeviceType(String deviceType)1358 private boolean checkDeviceType(String deviceType) { 1359 if (!Pattern.compile(REGEX_DEVICE_TYPE).matcher(deviceType).matches()) { 1360 LOG.error("Compressor::compressProcess deviceType " + deviceType + 1361 " is not in {phone, tablet, car, tv, wearable, liteWearable} list."); 1362 return false; 1363 } 1364 return true; 1365 } 1366 checkScreenDensity(String screenDensity)1367 private boolean checkScreenDensity(String screenDensity) { 1368 if (!Pattern.compile(REGEX_SCREEN_DENSITY).matcher(screenDensity).matches()) { 1369 LOG.error("Compressor::compressProcess screenDensity " + screenDensity + 1370 " is not in {sdpi, mdpi, ldpi, xldpi, xxldpi} list."); 1371 return false; 1372 } 1373 return true; 1374 } 1375 checkColorMode(String colorMode)1376 private boolean checkColorMode(String colorMode) { 1377 if (!Pattern.compile(REGEX_COLOR_MODE).matcher(colorMode).matches()) { 1378 LOG.error("Compressor::compressProcess colorMode " + colorMode + 1379 " is not in {light, dark} list."); 1380 return false; 1381 } 1382 return true; 1383 } 1384 checkColorModeOrShape(String tmp)1385 private boolean checkColorModeOrShape(String tmp) { 1386 if (Pattern.compile(REGEX_COLOR_MODE).matcher(tmp).matches() || 1387 Pattern.compile(REGEX_SHAPE).matcher(tmp).matches()) { 1388 return true; 1389 } 1390 LOG.error("Compressor::compressProcess " + tmp + 1391 " is neither in colorMode list {light, dark} nor in shape list {circle}."); 1392 return false; 1393 } 1394 checkShape(String shape)1395 private boolean checkShape(String shape) { 1396 if (Pattern.compile(REGEX_SHAPE).matcher(shape).matches()) { 1397 return true; 1398 } 1399 LOG.error("Compressor::compressProcess shape" + shape + " is not in {circle} list."); 1400 return false; 1401 } 1402 1403 /** 1404 * Check whether languageCountryName meets specifications. 1405 * 1406 * @param name languageCountryName 1407 * @return false and true 1408 */ isLanguageCountry(String name)1409 private boolean isLanguageCountry(String name) { 1410 if (!ENTRYCARD_BASE_NAME.equals(name)) { 1411 boolean isLanguage = false; 1412 String[] str = name.split("-"); 1413 if (str.length > 1) { 1414 Locale[] ls = Locale.getAvailableLocales(); 1415 for (int i = 0; i < ls.length; i++) { 1416 if (ls[i].toString().equals(str[0])) { 1417 isLanguage = true; 1418 } 1419 } 1420 if (VERTICAL.equals(str[1]) || HORIZONTAL.equals(str[1])) { 1421 isLanguage = true; 1422 } 1423 if (CAR.equals(str[2]) || TV.equals(str[2]) || WEARABLE.equals(str[2])) { 1424 isLanguage = true; 1425 } 1426 if (SDIP.equals(str[3]) || MDIP.equals(str[3])) { 1427 isLanguage = true; 1428 } 1429 return isLanguage; 1430 } else { 1431 return false; 1432 } 1433 } else { 1434 return true; 1435 } 1436 } 1437 1438 /** 1439 * Check whether picturingName meets specifications. 1440 * 1441 * @param name picturingName 1442 * @param utility common data 1443 * @return false and true 1444 */ isPicturing(String name, Utility utility)1445 private boolean isPicturing(String name, Utility utility) { 1446 boolean isSpecifications = false; 1447 if (name == null || name.isEmpty()) { 1448 return isSpecifications; 1449 } 1450 if (!name.endsWith(PNG_SUFFIX) && !name.endsWith(UPPERCASE_PNG_SUFFIX)) { 1451 LOG.error("isPicturing: the suffix is not .png or .PNG."); 1452 return false; 1453 } 1454 int delimiterIndex = name.lastIndexOf("-"); 1455 if (delimiterIndex < 0) { 1456 LOG.error("isPicturing: the entry card naming format is invalid and should be separated by '-'."); 1457 return false; 1458 } 1459 String formName = name.substring(0, delimiterIndex); 1460 if (!utility.getFormNameList().contains(formName)) { 1461 LOG.error("isPicturing: the name is not same as formName, name: " + formName + " is not in " + 1462 utility.getFormNameList().toString()); 1463 return false; 1464 } 1465 String dimension = name.substring(delimiterIndex + 1, name.lastIndexOf(".")); 1466 if (!supportDimensionsList.contains(dimension)) { 1467 LOG.error("isPicturing: the dimension: " + dimension + " is invalid, is not in the following list: " 1468 + "{1X2, 2X2, 2X4, 4X4}."); 1469 return false; 1470 } 1471 return true; 1472 } 1473 getFileList(final String filePath)1474 private void getFileList(final String filePath) throws BundleException { 1475 File file = new File(filePath); 1476 if (!file.exists()) { 1477 LOG.error("getFileList: file is not exists."); 1478 return; 1479 } 1480 File[] files = file.listFiles(); 1481 if (files == null) { 1482 LOG.error("getFileList: no file in this file path."); 1483 return; 1484 } 1485 for (File f : files) { 1486 try { 1487 if (f.isFile()) { 1488 if (f.getName().endsWith(".DS_Store")) { 1489 deleteFile(f.getCanonicalPath()); 1490 continue; 1491 } 1492 String snapshotDirectoryName = f.getParentFile().getName(); 1493 if (!ENTRYCARD_SNAPSHOT_NAME.equals(snapshotDirectoryName)) { 1494 LOG.error("The level-4 directory of EntryCard must be named as snapshot" + 1495 ", but current is: " + snapshotDirectoryName + "."); 1496 throw new BundleException("The level-4 directory of EntryCard must be named as snapshot" + 1497 ", but current is: " + snapshotDirectoryName + "."); 1498 } 1499 checkContain2x2EntryCard(f.getParentFile()); 1500 fileNameList.add(f.getCanonicalPath()); 1501 } else if (f.isDirectory()) { 1502 getFileList(f.getCanonicalPath()); 1503 } else { 1504 LOG.error("It's not file or directory."); 1505 } 1506 } catch (IOException msg) { 1507 LOG.error("IOException error: " + msg.getMessage()); 1508 return; 1509 } 1510 } 1511 } 1512 checkContain2x2EntryCard(final File snapshotDirectory)1513 private void checkContain2x2EntryCard(final File snapshotDirectory) throws IOException, BundleException { 1514 if (!snapshotDirectory.exists()) { 1515 LOG.error("checkContain2x2EntryCard: file is not exist: " + snapshotDirectory.getName()); 1516 throw new BundleException("checkContain2x2EntryCard: file is not exist."); 1517 } 1518 File[] files = snapshotDirectory.listFiles(); 1519 if (files == null) { 1520 LOG.error("checkContain2x2EntryCard: no file in this file path."); 1521 throw new BundleException("checkContain2x2EntryCard: no file in this file path."); 1522 } 1523 1524 for (File entryCardFile : files) { 1525 if (entryCardFile.isFile() && entryCardFile.getName().contains(PIC_2X2)) { 1526 return; 1527 } 1528 } 1529 mIsContain2x2EntryCard = false; 1530 LOG.error("checkContain2x2EntryCard: must contain 2x2 entryCard, please check it in " 1531 + snapshotDirectory.getCanonicalPath() + "."); 1532 throw new BundleException("checkContain2x2EntryCard: must contain 2x2 entryCard, please check it in " 1533 + snapshotDirectory.getCanonicalPath() + "."); 1534 } 1535 1536 /** 1537 * compress file or directory. 1538 * 1539 * @param utility common data 1540 * @param path create new file by path 1541 * @param baseDir base path for file 1542 * @param isCompression if need compression 1543 * @throws BundleException FileNotFoundException|IOException. 1544 */ pathToFile(Utility utility, String path, String baseDir, boolean isCompression)1545 private void pathToFile(Utility utility, String path, String baseDir, boolean isCompression) 1546 throws BundleException { 1547 if (path.isEmpty()) { 1548 return; 1549 } 1550 File fileItem = new File(path); 1551 if (fileItem.isDirectory()) { 1552 File[] files = fileItem.listFiles(); 1553 if (files == null) { 1554 return; 1555 } 1556 for (File file : files) { 1557 if (file.isDirectory()) { 1558 compressDirectory(utility, file, baseDir, isCompression); 1559 } else if (isCompression) { 1560 compressFile(utility, file, baseDir, isCompression); 1561 } else { 1562 compressFile(utility, file, baseDir, isCompression); 1563 } 1564 } 1565 } else { 1566 compressFile(utility, fileItem, baseDir, isCompression); 1567 } 1568 } 1569 1570 /** 1571 * compress file directory. 1572 * 1573 * @param utility common data 1574 * @param dir file directory 1575 * @param baseDir current directory name 1576 * @param isCompression if need compression 1577 * @throws BundleException FileNotFoundException|IOException. 1578 */ compressDirectory(Utility utility, File dir, String baseDir, boolean isCompression)1579 private void compressDirectory(Utility utility, File dir, String baseDir, boolean isCompression) 1580 throws BundleException { 1581 File[] files = dir.listFiles(); 1582 if (files == null) { 1583 return; 1584 } 1585 for (File file : files) { 1586 if (file.isDirectory()) { 1587 compressDirectory(utility, file, baseDir + dir.getName() + File.separator, isCompression); 1588 } else { 1589 compressFile(utility, file, baseDir + dir.getName() + File.separator, isCompression); 1590 } 1591 } 1592 } 1593 1594 /** 1595 * compress pack.info 1596 * 1597 * @param sourceFile source 1598 * @param zipOutputStream ZipOutputStream 1599 * @param name filename 1600 * @param KeepDirStructure Empty File 1601 */ compress(File sourceFile, ZipOutputStream zipOutputStream, String name, boolean KeepDirStructure)1602 private void compress(File sourceFile, ZipOutputStream zipOutputStream, String name, 1603 boolean KeepDirStructure) { 1604 FileInputStream in = null; 1605 try { 1606 byte[] buf = new byte[BUFFER_SIZE]; 1607 if (sourceFile.isFile()) { 1608 ZipEntry zipEntry = getStoredZipEntry(sourceFile, name); 1609 zipOutputStream.putNextEntry(zipEntry); 1610 in = new FileInputStream(sourceFile); 1611 int len; 1612 while ((len = in.read(buf)) != -1) { 1613 zipOutputStream.write(buf, 0, len); 1614 } 1615 zipOutputStream.closeEntry(); 1616 } else { 1617 File[] listFiles = sourceFile.listFiles(); 1618 if (listFiles == null || listFiles.length == 0) { 1619 if (KeepDirStructure) { 1620 if (!name.isEmpty()) { 1621 ZipEntry zipEntry = getStoredZipEntry(sourceFile, name + "/"); 1622 zipOutputStream.putNextEntry(zipEntry); 1623 } else { 1624 ZipEntry zipEntry = getStoredZipEntry(sourceFile, name); 1625 zipOutputStream.putNextEntry(zipEntry); 1626 } 1627 zipOutputStream.closeEntry(); 1628 } 1629 } else { 1630 for (File file : listFiles) { 1631 if (KeepDirStructure) { 1632 isNameEmpty(zipOutputStream, name, KeepDirStructure, file); 1633 } else { 1634 compress(file, zipOutputStream, file.getName(), KeepDirStructure); 1635 } 1636 } 1637 } 1638 } 1639 } catch (FileNotFoundException ignored) { 1640 LOG.error("Compressor::compressFile file not found exception."); 1641 } catch (IOException exception) { 1642 LOG.error("Compressor::compressFile io exception: " + exception.getMessage()); 1643 } catch (BundleException bundleException) { 1644 LOG.error("Compressor::compressFile bundle exception" + bundleException.getMessage()); 1645 } finally { 1646 Utility.closeStream(in); 1647 } 1648 } 1649 getStoredZipEntry(File sourceFile, String name)1650 private ZipEntry getStoredZipEntry(File sourceFile, String name) throws BundleException { 1651 ZipEntry zipEntry = new ZipEntry(name); 1652 zipEntry.setMethod(ZipEntry.STORED); 1653 zipEntry.setCompressedSize(sourceFile.length()); 1654 zipEntry.setSize(sourceFile.length()); 1655 CRC32 crc = getCrcFromFile(sourceFile); 1656 zipEntry.setCrc(crc.getValue()); 1657 FileTime fileTime = FileTime.fromMillis(FILE_TIME); 1658 zipEntry.setLastAccessTime(fileTime); 1659 zipEntry.setLastModifiedTime(fileTime); 1660 return zipEntry; 1661 } 1662 getCrcFromFile(File file)1663 private CRC32 getCrcFromFile(File file) throws BundleException { 1664 FileInputStream fileInputStream = null; 1665 CRC32 crc = new CRC32(); 1666 try { 1667 fileInputStream = new FileInputStream(file); 1668 byte[] buffer = new byte[BUFFER_SIZE]; 1669 1670 int count = fileInputStream.read(buffer); 1671 while (count > 0) { 1672 crc.update(buffer, 0, count); 1673 count = fileInputStream.read(buffer); 1674 } 1675 } catch (FileNotFoundException ignored) { 1676 LOG.error("Uncompressor::getCrcFromFile file not found exception."); 1677 throw new BundleException("Get Crc from file failed."); 1678 } catch (IOException exception) { 1679 LOG.error("Uncompressor::getCrcFromFile io exception: " + exception.getMessage()); 1680 throw new BundleException("Get Crc from file failed."); 1681 } finally { 1682 Utility.closeStream(fileInputStream); 1683 } 1684 return crc; 1685 } 1686 1687 /** 1688 * isNameEmpty 1689 * 1690 * @param zipOutputStream ZipOutputStream 1691 * @param name filename 1692 * @param KeepDirStructure KeepDirStructure 1693 * @param file file 1694 */ isNameEmpty(ZipOutputStream zipOutputStream, String name, boolean KeepDirStructure, File file)1695 private void isNameEmpty(ZipOutputStream zipOutputStream, String name, boolean KeepDirStructure, File file) { 1696 if (!name.isEmpty()) { 1697 compress(file, zipOutputStream, name + "/" + file.getName(), KeepDirStructure); 1698 } else { 1699 compress(file, zipOutputStream, file.getName(), KeepDirStructure); 1700 } 1701 } 1702 1703 /** 1704 * compress process. 1705 * 1706 * @param utility common data 1707 * @param srcFile source file to zip 1708 * @param baseDir current directory name of file 1709 * @param isCompression if need compression 1710 * @throws BundleException FileNotFoundException|IOException. 1711 */ compressFile(Utility utility, File srcFile, String baseDir, boolean isCompression)1712 private void compressFile(Utility utility, File srcFile, String baseDir, boolean isCompression) 1713 throws BundleException { 1714 BufferedInputStream bufferedInputStream = null; 1715 FileInputStream fileInputStream = null; 1716 try { 1717 String entryName = (baseDir + srcFile.getName()).replace(File.separator, LINUX_FILE_SEPARATOR); 1718 ZipEntry zipEntry = new ZipEntry(entryName); 1719 if (srcFile.getName().toLowerCase(Locale.ENGLISH).endsWith(JSON_SUFFIX)) { 1720 zipEntry.setMethod(ZipEntry.STORED); 1721 jsonSpecialProcess(utility, srcFile, zipEntry); 1722 return; 1723 } 1724 1725 if (isCompression) { 1726 zipEntry.setMethod(ZipEntry.DEFLATED); 1727 } else { 1728 zipEntry.setMethod(ZipEntry.STORED); 1729 1730 // update size 1731 zipEntry.setCompressedSize(srcFile.length()); 1732 zipEntry.setSize(srcFile.length()); 1733 1734 // update crc 1735 CRC32 crc = getCrcFromFile(utility, srcFile); 1736 zipEntry.setCrc(crc.getValue()); 1737 } 1738 1739 // update fileTime 1740 FileTime fileTime = FileTime.fromMillis(FILE_TIME); 1741 zipEntry.setLastAccessTime(fileTime); 1742 zipEntry.setLastModifiedTime(fileTime); 1743 1744 zipOut.putNextEntry(zipEntry); 1745 byte[] data = new byte[BUFFER_SIZE]; 1746 fileInputStream = new FileInputStream(srcFile); 1747 bufferedInputStream = new BufferedInputStream(fileInputStream); 1748 1749 int count = bufferedInputStream.read(data); 1750 while (count > 0) { 1751 zipOut.write(data, 0, count); 1752 count = bufferedInputStream.read(data); 1753 } 1754 } catch (FileNotFoundException ignored) { 1755 throw new BundleException("CoompressFile failed."); 1756 } catch (IOException exception) { 1757 LOG.error("Compressor::compressFile io exception: " + exception.getMessage()); 1758 throw new BundleException("CoompressFile failed."); 1759 } finally { 1760 Utility.closeStream(bufferedInputStream); 1761 Utility.closeStream(fileInputStream); 1762 } 1763 } 1764 1765 /** 1766 * check hap type for pack app. 1767 * 1768 * @param hapPath source file to zip 1769 * @return true is for is stage type and false is for FA type 1770 * @throws BundleException FileNotFoundException|IOException. 1771 */ isModuleHap(String hapPath)1772 public static boolean isModuleHap(String hapPath) throws BundleException { 1773 if (!hapPath.toLowerCase(Locale.ENGLISH).endsWith(HAP_SUFFIX)) { 1774 return true; 1775 } 1776 1777 FileInputStream zipInput = null; 1778 ZipInputStream zin = null; 1779 ZipEntry entry = null; 1780 try { 1781 zipInput = new FileInputStream(hapPath); 1782 zin = new ZipInputStream(zipInput); 1783 while ((entry = zin.getNextEntry()) != null) { 1784 if (MODULE_JSON.equals(entry.getName().toLowerCase())) { 1785 return true; 1786 } 1787 } 1788 } catch (IOException exception) { 1789 LOG.error("Compressor::isModuleHap io exception: " + exception.getMessage()); 1790 throw new BundleException("Compressor::isModuleHap failed."); 1791 } finally { 1792 Utility.closeStream(zipInput); 1793 Utility.closeStream(zin); 1794 } 1795 return false; 1796 } 1797 1798 /** 1799 * get CRC32 from file. 1800 * 1801 * @param utility common data 1802 * @param file source file 1803 * @return CRC32 1804 * @throws BundleException FileNotFoundException|IOException. 1805 */ getCrcFromFile(Utility utility, File file)1806 private CRC32 getCrcFromFile(Utility utility, File file) throws BundleException { 1807 FileInputStream fileInputStream = null; 1808 CRC32 crc = new CRC32(); 1809 try { 1810 fileInputStream = new FileInputStream(file); 1811 byte[] buffer = new byte[BUFFER_SIZE]; 1812 1813 int count = fileInputStream.read(buffer); 1814 while (count > 0) { 1815 crc.update(buffer, 0, count); 1816 count = fileInputStream.read(buffer); 1817 } 1818 } catch (FileNotFoundException ignored) { 1819 throw new BundleException("Get Crc from file failed."); 1820 } catch (IOException exception) { 1821 LOG.error("Compressor::getCrcFromFile io exception: " + exception.getMessage()); 1822 throw new BundleException("Get Crc from file failed."); 1823 } finally { 1824 Utility.closeStream(fileInputStream); 1825 } 1826 return crc; 1827 } 1828 infoSpecialProcess(Utility utility, File srcFile)1829 private void infoSpecialProcess(Utility utility, File srcFile) 1830 throws BundleException { 1831 FileInputStream fileInputStream = null; 1832 BufferedReader bufferedReader = null; 1833 InputStreamReader inputStreamReader = null; 1834 1835 try { 1836 fileInputStream = new FileInputStream(srcFile); 1837 inputStreamReader = new InputStreamReader(fileInputStream, StandardCharsets.UTF_8); 1838 bufferedReader = new BufferedReader(inputStreamReader); 1839 bufferedReader.mark((int) srcFile.length() + 1); 1840 // parse moduleName from pack.info 1841 parsePackModuleName(bufferedReader, utility); 1842 bufferedReader.reset(); 1843 parsePackFormName(bufferedReader, utility); 1844 bufferedReader.reset(); 1845 parseDeviceType(bufferedReader, utility); 1846 bufferedReader.reset(); 1847 1848 Pattern pattern = Pattern.compile(System.lineSeparator()); 1849 String str = bufferedReader.readLine(); 1850 StringBuilder builder = new StringBuilder(); 1851 while (str != null) { 1852 Matcher matcher = pattern.matcher(str.trim()); 1853 String dest = matcher.replaceAll(""); 1854 builder.append(dest); 1855 str = bufferedReader.readLine(); 1856 } 1857 } catch (IOException exception) { 1858 LOG.error("Compressor::jsonSpecialProcess io exception: " + exception.getMessage()); 1859 throw new BundleException("Json special process failed."); 1860 } finally { 1861 Utility.closeStream(bufferedReader); 1862 Utility.closeStream(inputStreamReader); 1863 Utility.closeStream(fileInputStream); 1864 } 1865 } 1866 1867 /** 1868 * trim and remove "\r\n" in *.json file. 1869 * 1870 * @param utility common data 1871 * @param srcFile file input 1872 * @param entry zip file entry 1873 * @throws BundleException FileNotFoundException|IOException. 1874 */ jsonSpecialProcess(Utility utility, File srcFile, ZipEntry entry)1875 private void jsonSpecialProcess(Utility utility, File srcFile, ZipEntry entry) 1876 throws BundleException { 1877 FileInputStream fileInputStream = null; 1878 BufferedReader bufferedReader = null; 1879 InputStreamReader inputStreamReader = null; 1880 1881 try { 1882 fileInputStream = new FileInputStream(srcFile); 1883 inputStreamReader = new InputStreamReader(fileInputStream, StandardCharsets.UTF_8); 1884 bufferedReader = new BufferedReader(inputStreamReader); 1885 bufferedReader.mark((int) srcFile.length() + 1); 1886 // parse moduleName from config.json 1887 parseModuleName(bufferedReader, utility); 1888 bufferedReader.reset(); 1889 parseCompressNativeLibs(bufferedReader, utility); 1890 bufferedReader.reset(); 1891 parseDeviceType(bufferedReader, utility); 1892 bufferedReader.reset(); 1893 1894 Pattern pattern = Pattern.compile(System.lineSeparator()); 1895 String str = bufferedReader.readLine(); 1896 StringBuilder builder = new StringBuilder(); 1897 while (str != null) { 1898 Matcher matcher = pattern.matcher(str.trim()); 1899 String dest = matcher.replaceAll(""); 1900 builder.append(dest); 1901 str = bufferedReader.readLine(); 1902 } 1903 byte[] trimJson = builder.toString().getBytes(StandardCharsets.UTF_8); 1904 1905 // update crc 1906 CRC32 crc = new CRC32(); 1907 crc.update(trimJson); 1908 entry.setCrc(crc.getValue()); 1909 1910 // update size 1911 entry.setSize(trimJson.length); 1912 entry.setCompressedSize(trimJson.length); 1913 1914 // update fileTime 1915 FileTime fileTime = FileTime.fromMillis(FILE_TIME); 1916 entry.setLastAccessTime(fileTime); 1917 entry.setLastModifiedTime(fileTime); 1918 1919 // compress data 1920 zipOut.putNextEntry(entry); 1921 zipOut.write(trimJson); 1922 } catch (IOException exception) { 1923 LOG.error("Compressor::jsonSpecialProcess io exception: " + exception.getMessage()); 1924 throw new BundleException("Json special process failed."); 1925 } finally { 1926 Utility.closeStream(bufferedReader); 1927 Utility.closeStream(inputStreamReader); 1928 Utility.closeStream(fileInputStream); 1929 } 1930 } 1931 1932 /** 1933 * Parse module name from config.json 1934 * 1935 * @param bufferedReader config.json buffered Reader 1936 * @param utility common data 1937 * @throws BundleException IOException 1938 */ parseModuleName(BufferedReader bufferedReader, Utility utility)1939 private void parseModuleName(BufferedReader bufferedReader, Utility utility) throws BundleException { 1940 String lineStr = null; 1941 boolean isDistroStart = false; 1942 try { 1943 while ((lineStr = bufferedReader.readLine()) != null) { 1944 if (!isDistroStart) { 1945 if (lineStr.contains(DISTRO)) { 1946 isDistroStart = true; 1947 } 1948 continue; 1949 } 1950 if (lineStr.contains(JSON_END)) { 1951 continue; 1952 } 1953 if (lineStr.contains(MODULE_NAME_NEW) || lineStr.contains(MODULE_NAME)) { 1954 getModuleNameFromString(lineStr, utility); 1955 break; 1956 } 1957 } 1958 } catch (IOException exception) { 1959 LOG.error("Compressor::parseModuleName io exception: " + exception.getMessage()); 1960 throw new BundleException("Parse module name failed."); 1961 } 1962 } 1963 1964 /** 1965 * Parse module name from pack.info 1966 * 1967 * @param bufferedReader pack.info buffered Reader 1968 * @param utility common data 1969 * @throws BundleException IOException 1970 */ parsePackModuleName(BufferedReader bufferedReader, Utility utility)1971 private void parsePackModuleName(BufferedReader bufferedReader, Utility utility) throws BundleException { 1972 String lineStr = null; 1973 boolean isDistroStart = false; 1974 try { 1975 while ((lineStr = bufferedReader.readLine()) != null) { 1976 if (lineStr.contains(DISTRO)) { 1977 continue; 1978 } 1979 if (lineStr.contains(JSON_END)) { 1980 continue; 1981 } 1982 if (lineStr.contains(MODULE_NAME_NEW) || lineStr.contains(MODULE_NAME)) { 1983 getModuleNameFromString(lineStr, utility); 1984 } 1985 } 1986 } catch (IOException exception) { 1987 LOG.error("Compressor::parseModuleName io exception: " + exception.getMessage()); 1988 throw new BundleException("Parse module name failed."); 1989 } 1990 } 1991 1992 /** 1993 * Parse Forms name from pack.info 1994 * 1995 * @param bufferedReader pack.info buffered Reader 1996 * @param utility common data 1997 * @throws BundleException IOException 1998 */ parsePackFormName(BufferedReader bufferedReader, Utility utility)1999 private void parsePackFormName(BufferedReader bufferedReader, Utility utility) throws BundleException { 2000 String lineStr = null; 2001 try { 2002 while ((lineStr = bufferedReader.readLine()) != null) { 2003 if (lineStr.contains("abilities")) { 2004 continue; 2005 } 2006 if (lineStr.contains(FORMS)) { 2007 continue; 2008 } 2009 if (lineStr.contains(JSON_END)) { 2010 continue; 2011 } 2012 if (lineStr.contains(NAME)) { 2013 getNameFromString(lineStr, utility); 2014 } 2015 } 2016 } catch (IOException exception) { 2017 LOG.error("Compressor::parseModuleName io exception: " + exception.getMessage()); 2018 throw new BundleException("Parse module name failed."); 2019 } 2020 } 2021 2022 2023 /** 2024 * Get name from line string 2025 * 2026 * @param lineStr line string 2027 * @param utility common data 2028 * @throws BundleException StringIndexOutOfBoundsException 2029 */ getNameFromString(String lineStr, Utility utility)2030 private void getNameFromString(String lineStr, Utility utility) throws BundleException { 2031 try { 2032 int endIndex = lineStr.lastIndexOf(SEMICOLON); 2033 if (endIndex <= 0) { 2034 LOG.error("Compressor::getModuleNameFromString field the json is not standard."); 2035 throw new BundleException("Parse module name failed, module-name is invalid."); 2036 } 2037 int startIndex = lineStr.lastIndexOf(SEMICOLON, endIndex - 1) + 1; 2038 String formName = lineStr.substring(startIndex, endIndex); 2039 if (formName == null || formName.isEmpty()) { 2040 LOG.error("Compressor::getModuleNameFromString field module-name is empty."); 2041 throw new BundleException("Parse module name failed, module-name is empty."); 2042 } 2043 String[] nameList = formName.split("\\."); 2044 if (nameList.length <= 1) { 2045 formNamesList.add(formName); 2046 utility.addFormNameList(formName); 2047 } 2048 } catch (StringIndexOutOfBoundsException exception) { 2049 LOG.error("Compressor::parseModuleName field module-name is fault: " + exception.getMessage()); 2050 throw new BundleException("Parse module name failed, module-name is invalid."); 2051 } 2052 } 2053 2054 /** 2055 * Get module name from line string 2056 * 2057 * @param lineStr line string 2058 * @param utility common data 2059 * @throws BundleException StringIndexOutOfBoundsException 2060 */ getModuleNameFromString(String lineStr, Utility utility)2061 private void getModuleNameFromString(String lineStr, Utility utility) throws BundleException { 2062 try { 2063 int endIndex = lineStr.lastIndexOf(SEMICOLON); 2064 if (endIndex <= 0) { 2065 LOG.error("Compressor::getModuleNameFromString field the json is not standard."); 2066 throw new BundleException("Parse module name failed, module-name is invalid."); 2067 } 2068 int startIndex = lineStr.lastIndexOf(SEMICOLON, endIndex - 1) + 1; 2069 String moduleName = lineStr.substring(startIndex, endIndex); 2070 list.add(moduleName); 2071 if (moduleName == null || moduleName.isEmpty()) { 2072 LOG.error("Compressor::getModuleNameFromString field module-name is empty."); 2073 throw new BundleException("Parse module name failed, module-name is empty."); 2074 } 2075 utility.setModuleName(moduleName); 2076 } catch (StringIndexOutOfBoundsException exception) { 2077 LOG.error("Compressor::parseModuleName field module-name is fault: " + exception.getMessage()); 2078 throw new BundleException("Parse module name failed, module-name is invalid."); 2079 } 2080 } 2081 parseCompressNativeLibs(BufferedReader bufferedReader, Utility utility)2082 private void parseCompressNativeLibs(BufferedReader bufferedReader, Utility utility) throws BundleException { 2083 String lineStr = null; 2084 try { 2085 while ((lineStr = bufferedReader.readLine()) != null) { 2086 if (lineStr.contains(COMPRESS_NATIVE_LIBS)) { 2087 if (lineStr.contains(Utility.FALSE_STRING)) { 2088 utility.setIsCompressNativeLibs(false); 2089 break; 2090 } 2091 } 2092 } 2093 } catch (IOException exception) { 2094 LOG.error("Compressor::parseCompressNativeLibs io exception: " + exception.getMessage()); 2095 throw new BundleException("Parse compress native libs failed."); 2096 } 2097 } 2098 2099 /** 2100 * ZipOutputStream flush, closeEntry and finish. 2101 */ closeZipOutputStream()2102 private void closeZipOutputStream() { 2103 try { 2104 if (zipOut != null) { 2105 zipOut.flush(); 2106 } 2107 } catch (IOException exception) { 2108 LOG.error("Compressor::closeZipOutputStream flush exception " + exception.getMessage()); 2109 } 2110 try { 2111 if (zipOut != null) { 2112 zipOut.closeEntry(); 2113 } 2114 } catch (IOException exception) { 2115 LOG.error("Compressor::closeZipOutputStream close entry io exception " + exception.getMessage()); 2116 } 2117 try { 2118 if (zipOut != null) { 2119 zipOut.finish(); 2120 } 2121 } catch (IOException exception) { 2122 LOG.error("Compressor::closeZipOutputStream finish exception " + exception.getMessage()); 2123 } 2124 } 2125 2126 /** 2127 * Parse device type from config.json 2128 * 2129 * @param bufferedReader config.json buffered Reader 2130 * @param utility common data 2131 * @throws BundleException IOException 2132 */ parseDeviceType(BufferedReader bufferedReader, Utility utility)2133 private void parseDeviceType(BufferedReader bufferedReader, Utility utility) throws BundleException { 2134 String lineStr = null; 2135 boolean isDeviceTypeStart = false; 2136 try { 2137 while ((lineStr = bufferedReader.readLine()) != null) { 2138 if (!isDeviceTypeStart) { 2139 if (lineStr.contains(DEVICE_TYPE)) { 2140 isDeviceTypeStart = true; 2141 } 2142 continue; 2143 } 2144 if (lineStr.contains(JSON_END)) { 2145 break; 2146 } 2147 utility.setDeviceType(lineStr); 2148 break; 2149 } 2150 } catch (IOException exception) { 2151 LOG.error("Compressor::parseDeviceType io exception: " + exception.getMessage()); 2152 throw new BundleException("Parse device type failed"); 2153 } 2154 } 2155 2156 /** 2157 * check hap is valid in haps when pack app, check type has bundleName, 2158 * vendor, version, apiVersion moduleName, packageName. 2159 * 2160 * @param fileLists is the list of hapPath. 2161 * @return true is for successful and false is for failed 2162 * @throws BundleException FileNotFoundException|IOException. 2163 */ checkHapIsValid(List<String> fileLists)2164 private boolean checkHapIsValid(List<String> fileLists) throws BundleException { 2165 List<HapVerifyInfo> hapVerifyInfos = new ArrayList<>(); 2166 for (String hapPath : fileLists) { 2167 if (hapPath.isEmpty()) { 2168 LOG.error("Compressor::checkHapIsValid input wrong hap file."); 2169 throw new BundleException("Compressor::checkHapIsValid input wrong hap file."); 2170 } 2171 File srcFile = new File(hapPath); 2172 String fileStr = srcFile.getName(); 2173 if (fileStr.isEmpty()) { 2174 LOG.error("Compressor::checkHapIsValid get file name failed."); 2175 throw new BundleException("Compressor::checkHapIsValid get file name failed."); 2176 } 2177 if (!fileStr.toLowerCase(Locale.ENGLISH).endsWith(HAP_SUFFIX) 2178 && !fileStr.toLowerCase(Locale.ENGLISH).endsWith(HSP_SUFFIX)) { 2179 LOG.error("Compressor::checkHapIsValid input wrong hap file."); 2180 throw new BundleException("Compressor::checkHapIsValid input wrong hap file."); 2181 } 2182 if (isModuleHap(hapPath)) { 2183 hapVerifyInfos.add(parseStageHapVerifyInfo(hapPath)); 2184 } else { 2185 hapVerifyInfos.add(parseFAHapVerifyInfo(hapPath)); 2186 } 2187 } 2188 setAtomicServiceFileSizeLimit(hapVerifyInfos); 2189 if (!HapVerify.checkHapIsValid(hapVerifyInfos)) { 2190 return false; 2191 } 2192 return true; 2193 } 2194 2195 /** 2196 * parse stage file to hap verify info from hap path. 2197 * 2198 * @param filePath is the hap path 2199 * @return hapVerifyInfo 2200 */ parseStageHapVerifyInfo(String filePath)2201 public static HapVerifyInfo parseStageHapVerifyInfo(String filePath) throws BundleException { 2202 HapVerifyInfo hapVerifyInfo = readStageHapVerifyInfo(filePath); 2203 hapVerifyInfo.setStageModule(true); 2204 ModuleJsonUtil.parseStageHapVerifyInfo(hapVerifyInfo); 2205 hapVerifyInfo.setFileLength(FileUtils.getFileSize(filePath)); 2206 return hapVerifyInfo; 2207 } 2208 2209 /** 2210 * set file size limit for each HapVerifyInfo. 2211 * 2212 * @param hapVerifyInfos Indicates hapVerifyInfo list. 2213 */ setAtomicServiceFileSizeLimit(List<HapVerifyInfo>hapVerifyInfos)2214 public static void setAtomicServiceFileSizeLimit(List<HapVerifyInfo>hapVerifyInfos) { 2215 for (HapVerifyInfo hapVerifyInfo : hapVerifyInfos) { 2216 if (!hapVerifyInfo.getBundleType().equals(ATOMIC_SERVICE)) { 2217 continue; 2218 } 2219 hapVerifyInfo.setEntrySizeLimit(getEntryModuleSizeLimit()); 2220 hapVerifyInfo.setNotEntrySizeLimit(getNotEntryModuleSizeLimit()); 2221 hapVerifyInfo.setSumSizeLimit(getSumModuleSizeLimit()); 2222 } 2223 } 2224 2225 /** 2226 * parse fa file to hap verify info from hap path. 2227 * 2228 * @param filePath is the hap path 2229 * @return hapVerifyInfo 2230 */ parseFAHapVerifyInfo(String filePath)2231 public static HapVerifyInfo parseFAHapVerifyInfo(String filePath) throws BundleException { 2232 HapVerifyInfo hapVerifyInfo = readFAHapVerifyInfo(filePath); 2233 hapVerifyInfo.setStageModule(false); 2234 hapVerifyInfo.setFileLength(FileUtils.getFileSize(filePath)); 2235 ModuleJsonUtil.parseFAHapVerifyInfo(hapVerifyInfo); 2236 return hapVerifyInfo; 2237 } 2238 2239 /** 2240 * read stage hap verify info from hap file. 2241 * 2242 * @param srcPath source file to zip 2243 * @return HapVerifyInfo of parse result 2244 * @throws BundleException FileNotFoundException|IOException. 2245 */ readStageHapVerifyInfo(String srcPath)2246 public static HapVerifyInfo readStageHapVerifyInfo(String srcPath) throws BundleException { 2247 HapVerifyInfo hapVerifyInfo = new HapVerifyInfo(); 2248 ZipFile zipFile = null; 2249 try { 2250 File srcFile = new File(srcPath); 2251 zipFile = new ZipFile(srcFile); 2252 hapVerifyInfo.setResourceMap(FileUtils.getProfileJson(zipFile)); 2253 hapVerifyInfo.setProfileStr(FileUtils.getFileStringFromZip(MODULE_JSON, zipFile)); 2254 } catch (IOException e) { 2255 LOG.error("FileUtil::parseStageHapVerifyInfo file not available."); 2256 throw new BundleException("FileUtil::parseStageHapVerifyInfo file not available."); 2257 } finally { 2258 Utility.closeStream(zipFile); 2259 } 2260 return hapVerifyInfo; 2261 } 2262 2263 /** 2264 * read fa hap verify info from hap file. 2265 * 2266 * @param srcPath source file to zip 2267 * @return HapVerifyInfo of parse result 2268 * @throws BundleException FileNotFoundException|IOException. 2269 */ readFAHapVerifyInfo(String srcPath)2270 public static HapVerifyInfo readFAHapVerifyInfo(String srcPath) throws BundleException { 2271 HapVerifyInfo hapVerifyInfo = new HapVerifyInfo(); 2272 ZipFile zipFile = null; 2273 try { 2274 File srcFile = new File(srcPath); 2275 zipFile = new ZipFile(srcFile); 2276 hapVerifyInfo.setProfileStr(FileUtils.getFileStringFromZip(CONFIG_JSON, zipFile)); 2277 } catch (IOException e) { 2278 LOG.error("FileUtil::parseStageHapVerifyInfo file not available."); 2279 throw new BundleException("FileUtil::parseStageHapVerifyInfo file not available."); 2280 } finally { 2281 Utility.closeStream(zipFile); 2282 } 2283 return hapVerifyInfo; 2284 } 2285 2286 /** 2287 * compress in hqf mode. 2288 * 2289 * @param utility common data 2290 * @throws BundleException FileNotFoundException|IOException. 2291 */ compressHQFMode(Utility utility)2292 private void compressHQFMode(Utility utility) throws BundleException { 2293 pathToFile(utility, utility.getJsonPath(), NULL_DIR_NAME, false); 2294 2295 if (!utility.getEtsPath().isEmpty()) { 2296 pathToFile(utility, utility.getEtsPath(), ETS_PATH, false); 2297 } 2298 if (!utility.getLibPath().isEmpty()) { 2299 pathToFile(utility, utility.getLibPath(), LIBS_DIR_NAME, false); 2300 } 2301 } 2302 2303 /** 2304 * compress in appqf mode. 2305 * 2306 * @param utility common data 2307 * @throws BundleException FileNotFoundException|IOException. 2308 */ compressAPPQFMode(Utility utility)2309 private void compressAPPQFMode(Utility utility) throws BundleException { 2310 List<String> fileList = utility.getFormatedHQFList(); 2311 if (!checkHQFIsValid(fileList)) { 2312 LOG.error("Error: checkHQFIsValid failed when pack appqf file."); 2313 throw new BundleException("Error: checkHQFIsValid failed when pack appqf file."); 2314 } 2315 for (String hapPath : fileList) { 2316 pathToFile(utility, hapPath, NULL_DIR_NAME, false); 2317 } 2318 } 2319 2320 /** 2321 * check input hqf is valid. 2322 * 2323 * @param fileList is input path of hqf files 2324 * @throws BundleException FileNotFoundException|IOException. 2325 */ checkHQFIsValid(List<String> fileList)2326 private boolean checkHQFIsValid(List<String> fileList) throws BundleException { 2327 List<HQFInfo> hqfVerifyInfos = new ArrayList<>(); 2328 for (String file : fileList) { 2329 hqfVerifyInfos.add(ModuleJsonUtil.parseHQFInfo(file)); 2330 } 2331 if (!HQFVerify.checkHQFIsValid(hqfVerifyInfos)) { 2332 LOG.error("Error: input hqf is invalid."); 2333 return false; 2334 } 2335 return true; 2336 } 2337 compressHSPMode(Utility utility)2338 private void compressHSPMode(Utility utility) throws BundleException { 2339 pathToFile(utility, utility.getJsonPath(), NULL_DIR_NAME, false); 2340 2341 pathToFile(utility, utility.getProfilePath(), NULL_DIR_NAME, false); 2342 2343 if (!utility.getIndexPath().isEmpty() && isModuleJSON(utility.getJsonPath())) { 2344 String assetsPath = NULL_DIR_NAME; 2345 pathToFile(utility, utility.getIndexPath(), assetsPath, false); 2346 } 2347 2348 if (!utility.getLibPath().isEmpty()) { 2349 pathToFile(utility, utility.getLibPath(), LIBS_DIR_NAME, utility.isCompressNativeLibs()); 2350 } 2351 2352 if (!utility.getANPath().isEmpty()) { 2353 pathToFile(utility, utility.getANPath(), AN_DIR_NAME, false); 2354 } 2355 2356 if (!utility.getFilePath().isEmpty()) { 2357 pathToFile(utility, utility.getFilePath(), NULL_DIR_NAME, false); 2358 } 2359 2360 if (!utility.getResPath().isEmpty() && !utility.getModuleName().isEmpty()) { 2361 String resPath = ASSETS_DIR_NAME + utility.getModuleName() + LINUX_FILE_SEPARATOR 2362 + RESOURCES_DIR_NAME; 2363 if (DEVICE_TYPE_FITNESSWATCH.equals(utility.getDeviceType().replace(SEMICOLON, EMPTY_STRING).trim()) || 2364 DEVICE_TYPE_FITNESSWATCH_NEW.equals( 2365 utility.getDeviceType().replace(SEMICOLON, EMPTY_STRING).trim())) { 2366 resPath = RES_DIR_NAME; 2367 } 2368 pathToFile(utility, utility.getResPath(), resPath, false); 2369 } 2370 2371 if (!utility.getResourcesPath().isEmpty() && isModuleJSON(utility.getJsonPath())) { 2372 String resourcesPath = RESOURCES_DIR_NAME; 2373 pathToFile(utility, utility.getResourcesPath(), resourcesPath, false); 2374 } 2375 if (!utility.getJsPath().isEmpty() && isModuleJSON(utility.getJsonPath())) { 2376 String jsPath = JS_PATH; 2377 pathToFile(utility, utility.getJsPath(), jsPath, false); 2378 } 2379 2380 if (!utility.getEtsPath().isEmpty() && isModuleJSON(utility.getJsonPath())) { 2381 String etsPath = ETS_PATH; 2382 pathToFile(utility, utility.getEtsPath(), etsPath, false); 2383 } 2384 2385 if (!utility.getRpcidPath().isEmpty()) { 2386 String rpcidPath = NULL_DIR_NAME; 2387 pathToFile(utility, utility.getRpcidPath(), rpcidPath, false); 2388 } 2389 2390 if (!utility.getAssetsPath().isEmpty()) { 2391 pathToFile(utility, utility.getAssetsPath(), ASSETS_DIR_NAME, false); 2392 } 2393 2394 if (!utility.getBinPath().isEmpty()) { 2395 pathToFile(utility, utility.getBinPath(), NULL_DIR_NAME, false); 2396 } 2397 2398 if (!utility.getPackInfoPath().isEmpty()) { 2399 pathToFile(utility, utility.getPackInfoPath(), NULL_DIR_NAME, false); 2400 } 2401 2402 compressHapModeMultiple(utility); 2403 } 2404 } 2405