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 LOG.error("Compressor::compressProcess compress pack.res failed, moduleName " 1219 + moduleName + " is error, please check it in config.json."); 1220 throw new BundleException("Compress pack.res failed, moduleName Error."); 1221 } 1222 String fileLanguageCountryName = temp[temp.length - 3]; 1223 if (!isThirdLevelDirectoryNameValid(fileLanguageCountryName)) { 1224 LOG.error("Compressor::compressProcess compress failed third level directory name: " 1225 + fileLanguageCountryName + " is invalid, please check it with reference to this example: " 1226 + "zh_Hani_CN-vertical-car-mdpi-dark or zh_Hani_CN-vertical-car-mdpi."); 1227 throw new BundleException("Compress failed third level directory name Error."); 1228 } 1229 String filePicturingName = temp[temp.length - 1]; 1230 if (!isPicturing(filePicturingName, utility)) { 1231 LOG.error("Compressor::compressProcess Compress pack.res failed, Invalid resource file" + 1232 " name: " + filePicturingName + ", correct format example is formName-2x2.png."); 1233 throw new BundleException("Compress pack.res failed, Invalid resource file name: " 1234 + filePicturingName + ", correct format example is formName-2x2.png."); 1235 } 1236 1237 } else { 1238 LOG.error("Compressor::compressProcess compress failed No image in PNG format is found."); 1239 throw new BundleException("Compress pack.res failed, compress failed No image in" 1240 + " PNG format is found."); 1241 } 1242 } 1243 pathToFile(utility, utility.getEntryCardPath(), ENTRYCARD_NAME, false); 1244 } 1245 } 1246 1247 /** 1248 * Check whether modelname meets specifications. 1249 * 1250 * @param name modelName 1251 * @return false and true 1252 */ isModelName(String name)1253 private boolean isModelName(String name) { 1254 for (String listName : list) { 1255 if (name.equals(listName)) { 1256 return true; 1257 } 1258 } 1259 return false; 1260 } 1261 isThirdLevelDirectoryNameValid(String thirdLevelDirectoryName)1262 private boolean isThirdLevelDirectoryNameValid(String thirdLevelDirectoryName) { 1263 if (thirdLevelDirectoryName == null || thirdLevelDirectoryName.isEmpty()) { 1264 return false; 1265 } 1266 if (ENTRYCARD_BASE_NAME.equals(thirdLevelDirectoryName)) { 1267 return true; 1268 } 1269 // example: zh_Hani_CN-vertical-car-mdpi-dark or zh_Hani_CN-vertical-car-mdpi 1270 int firstDelimiterIndex = thirdLevelDirectoryName.indexOf("_"); 1271 if (firstDelimiterIndex < 0) { 1272 return false; 1273 } 1274 String language = thirdLevelDirectoryName.substring(0, firstDelimiterIndex); 1275 int secondDelimiterIndex = thirdLevelDirectoryName.indexOf("_", firstDelimiterIndex + 1); 1276 if (secondDelimiterIndex < 0) { 1277 return false; 1278 } 1279 String script = thirdLevelDirectoryName.substring(firstDelimiterIndex + 1, secondDelimiterIndex); 1280 int thirdDelimiterIndex = thirdLevelDirectoryName.indexOf("-", secondDelimiterIndex + 1); 1281 if (thirdDelimiterIndex < 0) { 1282 return false; 1283 } 1284 String country = thirdLevelDirectoryName.substring(secondDelimiterIndex + 1, thirdDelimiterIndex); 1285 if (!checkLanguage(language) || !checkScript(script) || !checkCountry(country)) { 1286 return false; 1287 } 1288 int forthDelimiterIndex = thirdLevelDirectoryName.indexOf("-", thirdDelimiterIndex + 1); 1289 if (forthDelimiterIndex < 0) { 1290 return false; 1291 } 1292 String orientation = thirdLevelDirectoryName.substring(thirdDelimiterIndex + 1, forthDelimiterIndex); 1293 int fifthDelimiterIndex = thirdLevelDirectoryName.indexOf("-", forthDelimiterIndex + 1); 1294 if (fifthDelimiterIndex < 0) { 1295 return false; 1296 } 1297 String deviceType = thirdLevelDirectoryName.substring(forthDelimiterIndex + 1, fifthDelimiterIndex); 1298 if (!checkOrientation(orientation) || !checkDeviceType(deviceType)) { 1299 return false; 1300 } 1301 int sixthDelimiterIndex = thirdLevelDirectoryName.indexOf("-", fifthDelimiterIndex + 1); 1302 if (sixthDelimiterIndex < 0) { 1303 String screenDensity = thirdLevelDirectoryName.substring(fifthDelimiterIndex + 1, 1304 thirdLevelDirectoryName.length()); 1305 return checkScreenDensity(screenDensity); 1306 } else { 1307 String screenDensity = thirdLevelDirectoryName.substring(fifthDelimiterIndex + 1, sixthDelimiterIndex); 1308 if (!checkScreenDensity(screenDensity)) { 1309 return false; 1310 } 1311 } 1312 int seventhDelimiterIndex = thirdLevelDirectoryName.indexOf("-", sixthDelimiterIndex + 1); 1313 if (seventhDelimiterIndex < 0) { 1314 String tmp = thirdLevelDirectoryName.substring(sixthDelimiterIndex + 1, thirdLevelDirectoryName.length()); 1315 return checkColorModeOrShape(tmp); 1316 } 1317 if (!checkColorMode(thirdLevelDirectoryName.substring(sixthDelimiterIndex + 1, seventhDelimiterIndex))) { 1318 return false; 1319 } 1320 String shape = thirdLevelDirectoryName.substring(seventhDelimiterIndex + 1, thirdLevelDirectoryName.length()); 1321 return checkShape(shape); 1322 } 1323 checkLanguage(String language)1324 private boolean checkLanguage(String language) { 1325 if (!Pattern.compile(REGEX_LANGUAGE).matcher(language).matches()) { 1326 LOG.error("Compressor::compressProcess language " + language + " is not in ISO 639-1 list."); 1327 return false; 1328 } 1329 return true; 1330 } 1331 checkScript(String script)1332 private boolean checkScript(String script) { 1333 if (!Pattern.compile(REGEX_SCRIPT).matcher(script).matches()) { 1334 LOG.error("Compressor::compressProcess script " + script + " is not in ISO 15924 list."); 1335 return false; 1336 } 1337 return true; 1338 } 1339 checkCountry(String country)1340 private boolean checkCountry(String country) { 1341 if (!Pattern.compile(REGEX_COUNTRY).matcher(country).matches()) { 1342 LOG.error("Compressor::compressProcess country " + country + " is not in ISO 3166-1 list."); 1343 return false; 1344 } 1345 return true; 1346 } 1347 checkOrientation(String orientation)1348 private boolean checkOrientation(String orientation) { 1349 if (!Pattern.compile(REGEX_ORIENTATION).matcher(orientation).matches()) { 1350 LOG.error("Compressor::compressProcess orientation " + orientation + 1351 " is not in {vertical, horizontal} list."); 1352 return false; 1353 } 1354 return true; 1355 } 1356 checkDeviceType(String deviceType)1357 private boolean checkDeviceType(String deviceType) { 1358 if (!Pattern.compile(REGEX_DEVICE_TYPE).matcher(deviceType).matches()) { 1359 LOG.error("Compressor::compressProcess deviceType " + deviceType + 1360 " is not in {phone, tablet, car, tv, wearable, liteWearable} list."); 1361 return false; 1362 } 1363 return true; 1364 } 1365 checkScreenDensity(String screenDensity)1366 private boolean checkScreenDensity(String screenDensity) { 1367 if (!Pattern.compile(REGEX_SCREEN_DENSITY).matcher(screenDensity).matches()) { 1368 LOG.error("Compressor::compressProcess screenDensity " + screenDensity + 1369 " is not in {sdpi, mdpi, ldpi, xldpi, xxldpi} list."); 1370 return false; 1371 } 1372 return true; 1373 } 1374 checkColorMode(String colorMode)1375 private boolean checkColorMode(String colorMode) { 1376 if (!Pattern.compile(REGEX_COLOR_MODE).matcher(colorMode).matches()) { 1377 LOG.error("Compressor::compressProcess colorMode " + colorMode + 1378 " is not in {light, dark} list."); 1379 return false; 1380 } 1381 return true; 1382 } 1383 checkColorModeOrShape(String tmp)1384 private boolean checkColorModeOrShape(String tmp) { 1385 if (Pattern.compile(REGEX_COLOR_MODE).matcher(tmp).matches() || 1386 Pattern.compile(REGEX_SHAPE).matcher(tmp).matches()) { 1387 return true; 1388 } 1389 LOG.error("Compressor::compressProcess " + tmp + 1390 " is neither in colorMode list {light, dark} nor in shape list {circle}."); 1391 return false; 1392 } 1393 checkShape(String shape)1394 private boolean checkShape(String shape) { 1395 if (Pattern.compile(REGEX_SHAPE).matcher(shape).matches()) { 1396 return true; 1397 } 1398 LOG.error("Compressor::compressProcess shape" + shape + " is not in {circle} list."); 1399 return false; 1400 } 1401 1402 /** 1403 * Check whether languageCountryName meets specifications. 1404 * 1405 * @param name languageCountryName 1406 * @return false and true 1407 */ isLanguageCountry(String name)1408 private boolean isLanguageCountry(String name) { 1409 if (!ENTRYCARD_BASE_NAME.equals(name)) { 1410 boolean isLanguage = false; 1411 String[] str = name.split("-"); 1412 if (str.length > 1) { 1413 Locale[] ls = Locale.getAvailableLocales(); 1414 for (int i = 0; i < ls.length; i++) { 1415 if (ls[i].toString().equals(str[0])) { 1416 isLanguage = true; 1417 } 1418 } 1419 if (VERTICAL.equals(str[1]) || HORIZONTAL.equals(str[1])) { 1420 isLanguage = true; 1421 } 1422 if (CAR.equals(str[2]) || TV.equals(str[2]) || WEARABLE.equals(str[2])) { 1423 isLanguage = true; 1424 } 1425 if (SDIP.equals(str[3]) || MDIP.equals(str[3])) { 1426 isLanguage = true; 1427 } 1428 return isLanguage; 1429 } else { 1430 return false; 1431 } 1432 } else { 1433 return true; 1434 } 1435 } 1436 1437 /** 1438 * Check whether picturingName meets specifications. 1439 * 1440 * @param name picturingName 1441 * @param utility common data 1442 * @return false and true 1443 */ isPicturing(String name, Utility utility)1444 private boolean isPicturing(String name, Utility utility) { 1445 boolean isSpecifications = false; 1446 if (name == null || name.isEmpty()) { 1447 return isSpecifications; 1448 } 1449 if (!name.endsWith(PNG_SUFFIX) && !name.endsWith(UPPERCASE_PNG_SUFFIX)) { 1450 LOG.error("isPicturing: the suffix is not .png or .PNG."); 1451 return false; 1452 } 1453 int delimiterIndex = name.lastIndexOf("-"); 1454 if (delimiterIndex < 0) { 1455 LOG.error("isPicturing: the entry card naming format is invalid and should be separated by '-'."); 1456 return false; 1457 } 1458 String formName = name.substring(0, delimiterIndex); 1459 if (!utility.getFormNameList().contains(formName)) { 1460 LOG.error("isPicturing: the name is not same as formName, name: " + formName + " is not in " + 1461 utility.getFormNameList().toString()); 1462 return false; 1463 } 1464 String dimension = name.substring(delimiterIndex + 1, name.lastIndexOf(".")); 1465 if (!supportDimensionsList.contains(dimension)) { 1466 LOG.error("isPicturing: the dimension: " + dimension + " is invalid, is not in the following list: " 1467 + "{1X2, 2X2, 2X4, 4X4}."); 1468 return false; 1469 } 1470 return true; 1471 } 1472 getFileList(final String filePath)1473 private void getFileList(final String filePath) throws BundleException { 1474 File file = new File(filePath); 1475 if (!file.exists()) { 1476 LOG.error("getFileList: file is not exists."); 1477 return; 1478 } 1479 File[] files = file.listFiles(); 1480 if (files == null) { 1481 LOG.error("getFileList: no file in this file path."); 1482 return; 1483 } 1484 for (File f : files) { 1485 try { 1486 if (f.isFile()) { 1487 if (f.getName().endsWith(".DS_Store")) { 1488 deleteFile(f.getCanonicalPath()); 1489 continue; 1490 } 1491 String snapshotDirectoryName = f.getParentFile().getName(); 1492 if (!ENTRYCARD_SNAPSHOT_NAME.equals(snapshotDirectoryName)) { 1493 LOG.error("The level-4 directory of EntryCard must be named as snapshot" + 1494 ", but current is: " + snapshotDirectoryName + "."); 1495 throw new BundleException("The level-4 directory of EntryCard must be named as snapshot" + 1496 ", but current is: " + snapshotDirectoryName + "."); 1497 } 1498 checkContain2x2EntryCard(f.getParentFile()); 1499 fileNameList.add(f.getCanonicalPath()); 1500 } else if (f.isDirectory()) { 1501 getFileList(f.getCanonicalPath()); 1502 } else { 1503 LOG.error("It's not file or directory."); 1504 } 1505 } catch (IOException msg) { 1506 LOG.error("IOException error: " + msg.getMessage()); 1507 return; 1508 } 1509 } 1510 } 1511 checkContain2x2EntryCard(final File snapshotDirectory)1512 private void checkContain2x2EntryCard(final File snapshotDirectory) throws IOException, BundleException { 1513 if (!snapshotDirectory.exists()) { 1514 LOG.error("checkContain2x2EntryCard: file is not exist: " + snapshotDirectory.getName()); 1515 throw new BundleException("checkContain2x2EntryCard: file is not exist."); 1516 } 1517 File[] files = snapshotDirectory.listFiles(); 1518 if (files == null) { 1519 LOG.error("checkContain2x2EntryCard: no file in this file path."); 1520 throw new BundleException("checkContain2x2EntryCard: no file in this file path."); 1521 } 1522 1523 for (File entryCardFile : files) { 1524 if (entryCardFile.isFile() && entryCardFile.getName().contains(PIC_2X2)) { 1525 return; 1526 } 1527 } 1528 mIsContain2x2EntryCard = false; 1529 LOG.error("checkContain2x2EntryCard: must contain 2x2 entryCard, please check it in " 1530 + snapshotDirectory.getCanonicalPath() + "."); 1531 throw new BundleException("checkContain2x2EntryCard: must contain 2x2 entryCard, please check it in " 1532 + snapshotDirectory.getCanonicalPath() + "."); 1533 } 1534 1535 /** 1536 * compress file or directory. 1537 * 1538 * @param utility common data 1539 * @param path create new file by path 1540 * @param baseDir base path for file 1541 * @param isCompression if need compression 1542 * @throws BundleException FileNotFoundException|IOException. 1543 */ pathToFile(Utility utility, String path, String baseDir, boolean isCompression)1544 private void pathToFile(Utility utility, String path, String baseDir, boolean isCompression) 1545 throws BundleException { 1546 if (path.isEmpty()) { 1547 return; 1548 } 1549 File fileItem = new File(path); 1550 if (fileItem.isDirectory()) { 1551 File[] files = fileItem.listFiles(); 1552 if (files == null) { 1553 return; 1554 } 1555 for (File file : files) { 1556 if (file.isDirectory()) { 1557 compressDirectory(utility, file, baseDir, isCompression); 1558 } else if (isCompression) { 1559 compressFile(utility, file, baseDir, isCompression); 1560 } else { 1561 compressFile(utility, file, baseDir, isCompression); 1562 } 1563 } 1564 } else { 1565 compressFile(utility, fileItem, baseDir, isCompression); 1566 } 1567 } 1568 1569 /** 1570 * compress file directory. 1571 * 1572 * @param utility common data 1573 * @param dir file directory 1574 * @param baseDir current directory name 1575 * @param isCompression if need compression 1576 * @throws BundleException FileNotFoundException|IOException. 1577 */ compressDirectory(Utility utility, File dir, String baseDir, boolean isCompression)1578 private void compressDirectory(Utility utility, File dir, String baseDir, boolean isCompression) 1579 throws BundleException { 1580 File[] files = dir.listFiles(); 1581 if (files == null) { 1582 return; 1583 } 1584 for (File file : files) { 1585 if (file.isDirectory()) { 1586 compressDirectory(utility, file, baseDir + dir.getName() + File.separator, isCompression); 1587 } else { 1588 compressFile(utility, file, baseDir + dir.getName() + File.separator, isCompression); 1589 } 1590 } 1591 } 1592 1593 /** 1594 * compress pack.info 1595 * 1596 * @param sourceFile source 1597 * @param zipOutputStream ZipOutputStream 1598 * @param name filename 1599 * @param KeepDirStructure Empty File 1600 */ compress(File sourceFile, ZipOutputStream zipOutputStream, String name, boolean KeepDirStructure)1601 private void compress(File sourceFile, ZipOutputStream zipOutputStream, String name, 1602 boolean KeepDirStructure) { 1603 FileInputStream in = null; 1604 try { 1605 byte[] buf = new byte[BUFFER_SIZE]; 1606 if (sourceFile.isFile()) { 1607 ZipEntry zipEntry = getStoredZipEntry(sourceFile, name); 1608 zipOutputStream.putNextEntry(zipEntry); 1609 in = new FileInputStream(sourceFile); 1610 int len; 1611 while ((len = in.read(buf)) != -1) { 1612 zipOutputStream.write(buf, 0, len); 1613 } 1614 zipOutputStream.closeEntry(); 1615 } else { 1616 File[] listFiles = sourceFile.listFiles(); 1617 if (listFiles == null || listFiles.length == 0) { 1618 if (KeepDirStructure) { 1619 if (!name.isEmpty()) { 1620 ZipEntry zipEntry = getStoredZipEntry(sourceFile, name + "/"); 1621 zipOutputStream.putNextEntry(zipEntry); 1622 } else { 1623 ZipEntry zipEntry = getStoredZipEntry(sourceFile, name); 1624 zipOutputStream.putNextEntry(zipEntry); 1625 } 1626 zipOutputStream.closeEntry(); 1627 } 1628 } else { 1629 for (File file : listFiles) { 1630 if (KeepDirStructure) { 1631 isNameEmpty(zipOutputStream, name, KeepDirStructure, file); 1632 } else { 1633 compress(file, zipOutputStream, file.getName(), KeepDirStructure); 1634 } 1635 } 1636 } 1637 } 1638 } catch (FileNotFoundException ignored) { 1639 LOG.error("Compressor::compressFile file not found exception."); 1640 } catch (IOException exception) { 1641 LOG.error("Compressor::compressFile io exception: " + exception.getMessage()); 1642 } catch (BundleException bundleException) { 1643 LOG.error("Compressor::compressFile bundle exception" + bundleException.getMessage()); 1644 } finally { 1645 Utility.closeStream(in); 1646 } 1647 } 1648 getStoredZipEntry(File sourceFile, String name)1649 private ZipEntry getStoredZipEntry(File sourceFile, String name) throws BundleException { 1650 ZipEntry zipEntry = new ZipEntry(name); 1651 zipEntry.setMethod(ZipEntry.STORED); 1652 zipEntry.setCompressedSize(sourceFile.length()); 1653 zipEntry.setSize(sourceFile.length()); 1654 CRC32 crc = getCrcFromFile(sourceFile); 1655 zipEntry.setCrc(crc.getValue()); 1656 FileTime fileTime = FileTime.fromMillis(FILE_TIME); 1657 zipEntry.setLastAccessTime(fileTime); 1658 zipEntry.setLastModifiedTime(fileTime); 1659 return zipEntry; 1660 } 1661 getCrcFromFile(File file)1662 private CRC32 getCrcFromFile(File file) throws BundleException { 1663 FileInputStream fileInputStream = null; 1664 CRC32 crc = new CRC32(); 1665 try { 1666 fileInputStream = new FileInputStream(file); 1667 byte[] buffer = new byte[BUFFER_SIZE]; 1668 1669 int count = fileInputStream.read(buffer); 1670 while (count > 0) { 1671 crc.update(buffer, 0, count); 1672 count = fileInputStream.read(buffer); 1673 } 1674 } catch (FileNotFoundException ignored) { 1675 LOG.error("Uncompressor::getCrcFromFile file not found exception."); 1676 throw new BundleException("Get Crc from file failed."); 1677 } catch (IOException exception) { 1678 LOG.error("Uncompressor::getCrcFromFile io exception: " + exception.getMessage()); 1679 throw new BundleException("Get Crc from file failed."); 1680 } finally { 1681 Utility.closeStream(fileInputStream); 1682 } 1683 return crc; 1684 } 1685 1686 /** 1687 * isNameEmpty 1688 * 1689 * @param zipOutputStream ZipOutputStream 1690 * @param name filename 1691 * @param KeepDirStructure KeepDirStructure 1692 * @param file file 1693 */ isNameEmpty(ZipOutputStream zipOutputStream, String name, boolean KeepDirStructure, File file)1694 private void isNameEmpty(ZipOutputStream zipOutputStream, String name, boolean KeepDirStructure, File file) { 1695 if (!name.isEmpty()) { 1696 compress(file, zipOutputStream, name + "/" + file.getName(), KeepDirStructure); 1697 } else { 1698 compress(file, zipOutputStream, file.getName(), KeepDirStructure); 1699 } 1700 } 1701 1702 /** 1703 * compress process. 1704 * 1705 * @param utility common data 1706 * @param srcFile source file to zip 1707 * @param baseDir current directory name of file 1708 * @param isCompression if need compression 1709 * @throws BundleException FileNotFoundException|IOException. 1710 */ compressFile(Utility utility, File srcFile, String baseDir, boolean isCompression)1711 private void compressFile(Utility utility, File srcFile, String baseDir, boolean isCompression) 1712 throws BundleException { 1713 BufferedInputStream bufferedInputStream = null; 1714 FileInputStream fileInputStream = null; 1715 try { 1716 String entryName = (baseDir + srcFile.getName()).replace(File.separator, LINUX_FILE_SEPARATOR); 1717 ZipEntry zipEntry = new ZipEntry(entryName); 1718 if (srcFile.getName().toLowerCase(Locale.ENGLISH).endsWith(JSON_SUFFIX)) { 1719 zipEntry.setMethod(ZipEntry.STORED); 1720 jsonSpecialProcess(utility, srcFile, zipEntry); 1721 return; 1722 } 1723 1724 if (isCompression) { 1725 zipEntry.setMethod(ZipEntry.DEFLATED); 1726 } else { 1727 zipEntry.setMethod(ZipEntry.STORED); 1728 1729 // update size 1730 zipEntry.setCompressedSize(srcFile.length()); 1731 zipEntry.setSize(srcFile.length()); 1732 1733 // update crc 1734 CRC32 crc = getCrcFromFile(utility, srcFile); 1735 zipEntry.setCrc(crc.getValue()); 1736 } 1737 1738 // update fileTime 1739 FileTime fileTime = FileTime.fromMillis(FILE_TIME); 1740 zipEntry.setLastAccessTime(fileTime); 1741 zipEntry.setLastModifiedTime(fileTime); 1742 1743 zipOut.putNextEntry(zipEntry); 1744 byte[] data = new byte[BUFFER_SIZE]; 1745 fileInputStream = new FileInputStream(srcFile); 1746 bufferedInputStream = new BufferedInputStream(fileInputStream); 1747 1748 int count = bufferedInputStream.read(data); 1749 while (count > 0) { 1750 zipOut.write(data, 0, count); 1751 count = bufferedInputStream.read(data); 1752 } 1753 } catch (FileNotFoundException ignored) { 1754 throw new BundleException("CoompressFile failed."); 1755 } catch (IOException exception) { 1756 LOG.error("Compressor::compressFile io exception: " + exception.getMessage()); 1757 throw new BundleException("CoompressFile failed."); 1758 } finally { 1759 Utility.closeStream(bufferedInputStream); 1760 Utility.closeStream(fileInputStream); 1761 } 1762 } 1763 1764 /** 1765 * check hap type for pack app. 1766 * 1767 * @param hapPath source file to zip 1768 * @return true is for is stage type and false is for FA type 1769 * @throws BundleException FileNotFoundException|IOException. 1770 */ isModuleHap(String hapPath)1771 public static boolean isModuleHap(String hapPath) throws BundleException { 1772 if (!hapPath.toLowerCase(Locale.ENGLISH).endsWith(HAP_SUFFIX)) { 1773 return true; 1774 } 1775 1776 FileInputStream zipInput = null; 1777 ZipInputStream zin = null; 1778 ZipEntry entry = null; 1779 try { 1780 zipInput = new FileInputStream(hapPath); 1781 zin = new ZipInputStream(zipInput); 1782 while ((entry = zin.getNextEntry()) != null) { 1783 if (MODULE_JSON.equals(entry.getName().toLowerCase())) { 1784 return true; 1785 } 1786 } 1787 } catch (IOException exception) { 1788 LOG.error("Compressor::isModuleHap io exception: " + exception.getMessage()); 1789 throw new BundleException("Compressor::isModuleHap failed."); 1790 } finally { 1791 Utility.closeStream(zipInput); 1792 Utility.closeStream(zin); 1793 } 1794 return false; 1795 } 1796 1797 /** 1798 * get CRC32 from file. 1799 * 1800 * @param utility common data 1801 * @param file source file 1802 * @return CRC32 1803 * @throws BundleException FileNotFoundException|IOException. 1804 */ getCrcFromFile(Utility utility, File file)1805 private CRC32 getCrcFromFile(Utility utility, File file) throws BundleException { 1806 FileInputStream fileInputStream = null; 1807 CRC32 crc = new CRC32(); 1808 try { 1809 fileInputStream = new FileInputStream(file); 1810 byte[] buffer = new byte[BUFFER_SIZE]; 1811 1812 int count = fileInputStream.read(buffer); 1813 while (count > 0) { 1814 crc.update(buffer, 0, count); 1815 count = fileInputStream.read(buffer); 1816 } 1817 } catch (FileNotFoundException ignored) { 1818 throw new BundleException("Get Crc from file failed."); 1819 } catch (IOException exception) { 1820 LOG.error("Compressor::getCrcFromFile io exception: " + exception.getMessage()); 1821 throw new BundleException("Get Crc from file failed."); 1822 } finally { 1823 Utility.closeStream(fileInputStream); 1824 } 1825 return crc; 1826 } 1827 infoSpecialProcess(Utility utility, File srcFile)1828 private void infoSpecialProcess(Utility utility, File srcFile) 1829 throws BundleException { 1830 FileInputStream fileInputStream = null; 1831 BufferedReader bufferedReader = null; 1832 InputStreamReader inputStreamReader = null; 1833 1834 try { 1835 fileInputStream = new FileInputStream(srcFile); 1836 inputStreamReader = new InputStreamReader(fileInputStream, StandardCharsets.UTF_8); 1837 bufferedReader = new BufferedReader(inputStreamReader); 1838 bufferedReader.mark((int) srcFile.length() + 1); 1839 // parse moduleName from pack.info 1840 parsePackModuleName(bufferedReader, utility); 1841 bufferedReader.reset(); 1842 parsePackFormName(bufferedReader, utility); 1843 bufferedReader.reset(); 1844 parseDeviceType(bufferedReader, utility); 1845 bufferedReader.reset(); 1846 1847 Pattern pattern = Pattern.compile(System.lineSeparator()); 1848 String str = bufferedReader.readLine(); 1849 StringBuilder builder = new StringBuilder(); 1850 while (str != null) { 1851 Matcher matcher = pattern.matcher(str.trim()); 1852 String dest = matcher.replaceAll(""); 1853 builder.append(dest); 1854 str = bufferedReader.readLine(); 1855 } 1856 } catch (IOException exception) { 1857 LOG.error("Compressor::jsonSpecialProcess io exception: " + exception.getMessage()); 1858 throw new BundleException("Json special process failed."); 1859 } finally { 1860 Utility.closeStream(bufferedReader); 1861 Utility.closeStream(inputStreamReader); 1862 Utility.closeStream(fileInputStream); 1863 } 1864 } 1865 1866 /** 1867 * trim and remove "\r\n" in *.json file. 1868 * 1869 * @param utility common data 1870 * @param srcFile file input 1871 * @param entry zip file entry 1872 * @throws BundleException FileNotFoundException|IOException. 1873 */ jsonSpecialProcess(Utility utility, File srcFile, ZipEntry entry)1874 private void jsonSpecialProcess(Utility utility, File srcFile, ZipEntry entry) 1875 throws BundleException { 1876 FileInputStream fileInputStream = null; 1877 BufferedReader bufferedReader = null; 1878 InputStreamReader inputStreamReader = null; 1879 1880 try { 1881 fileInputStream = new FileInputStream(srcFile); 1882 inputStreamReader = new InputStreamReader(fileInputStream, StandardCharsets.UTF_8); 1883 bufferedReader = new BufferedReader(inputStreamReader); 1884 bufferedReader.mark((int) srcFile.length() + 1); 1885 // parse moduleName from config.json 1886 parseModuleName(bufferedReader, utility); 1887 bufferedReader.reset(); 1888 parseCompressNativeLibs(bufferedReader, utility); 1889 bufferedReader.reset(); 1890 parseDeviceType(bufferedReader, utility); 1891 bufferedReader.reset(); 1892 1893 Pattern pattern = Pattern.compile(System.lineSeparator()); 1894 String str = bufferedReader.readLine(); 1895 StringBuilder builder = new StringBuilder(); 1896 while (str != null) { 1897 Matcher matcher = pattern.matcher(str.trim()); 1898 String dest = matcher.replaceAll(""); 1899 builder.append(dest); 1900 str = bufferedReader.readLine(); 1901 } 1902 byte[] trimJson = builder.toString().getBytes(StandardCharsets.UTF_8); 1903 1904 // update crc 1905 CRC32 crc = new CRC32(); 1906 crc.update(trimJson); 1907 entry.setCrc(crc.getValue()); 1908 1909 // update size 1910 entry.setSize(trimJson.length); 1911 entry.setCompressedSize(trimJson.length); 1912 1913 // update fileTime 1914 FileTime fileTime = FileTime.fromMillis(FILE_TIME); 1915 entry.setLastAccessTime(fileTime); 1916 entry.setLastModifiedTime(fileTime); 1917 1918 // compress data 1919 zipOut.putNextEntry(entry); 1920 zipOut.write(trimJson); 1921 } catch (IOException exception) { 1922 LOG.error("Compressor::jsonSpecialProcess io exception: " + exception.getMessage()); 1923 throw new BundleException("Json special process failed."); 1924 } finally { 1925 Utility.closeStream(bufferedReader); 1926 Utility.closeStream(inputStreamReader); 1927 Utility.closeStream(fileInputStream); 1928 } 1929 } 1930 1931 /** 1932 * Parse module name from config.json 1933 * 1934 * @param bufferedReader config.json buffered Reader 1935 * @param utility common data 1936 * @throws BundleException IOException 1937 */ parseModuleName(BufferedReader bufferedReader, Utility utility)1938 private void parseModuleName(BufferedReader bufferedReader, Utility utility) throws BundleException { 1939 String lineStr = null; 1940 boolean isDistroStart = false; 1941 try { 1942 while ((lineStr = bufferedReader.readLine()) != null) { 1943 if (!isDistroStart) { 1944 if (lineStr.contains(DISTRO)) { 1945 isDistroStart = true; 1946 } 1947 continue; 1948 } 1949 if (lineStr.contains(JSON_END)) { 1950 continue; 1951 } 1952 if (lineStr.contains(MODULE_NAME_NEW) || lineStr.contains(MODULE_NAME)) { 1953 getModuleNameFromString(lineStr, utility); 1954 break; 1955 } 1956 } 1957 } catch (IOException exception) { 1958 LOG.error("Compressor::parseModuleName io exception: " + exception.getMessage()); 1959 throw new BundleException("Parse module name failed."); 1960 } 1961 } 1962 1963 /** 1964 * Parse module name from pack.info 1965 * 1966 * @param bufferedReader pack.info buffered Reader 1967 * @param utility common data 1968 * @throws BundleException IOException 1969 */ parsePackModuleName(BufferedReader bufferedReader, Utility utility)1970 private void parsePackModuleName(BufferedReader bufferedReader, Utility utility) throws BundleException { 1971 String lineStr = null; 1972 boolean isDistroStart = false; 1973 try { 1974 while ((lineStr = bufferedReader.readLine()) != null) { 1975 if (lineStr.contains(DISTRO)) { 1976 continue; 1977 } 1978 if (lineStr.contains(JSON_END)) { 1979 continue; 1980 } 1981 if (lineStr.contains(MODULE_NAME_NEW) || lineStr.contains(MODULE_NAME)) { 1982 getModuleNameFromString(lineStr, utility); 1983 } 1984 } 1985 } catch (IOException exception) { 1986 LOG.error("Compressor::parseModuleName io exception: " + exception.getMessage()); 1987 throw new BundleException("Parse module name failed."); 1988 } 1989 } 1990 1991 /** 1992 * Parse Forms name from pack.info 1993 * 1994 * @param bufferedReader pack.info buffered Reader 1995 * @param utility common data 1996 * @throws BundleException IOException 1997 */ parsePackFormName(BufferedReader bufferedReader, Utility utility)1998 private void parsePackFormName(BufferedReader bufferedReader, Utility utility) throws BundleException { 1999 String lineStr = null; 2000 try { 2001 while ((lineStr = bufferedReader.readLine()) != null) { 2002 if (lineStr.contains("abilities")) { 2003 continue; 2004 } 2005 if (lineStr.contains(FORMS)) { 2006 continue; 2007 } 2008 if (lineStr.contains(JSON_END)) { 2009 continue; 2010 } 2011 if (lineStr.contains(NAME)) { 2012 getNameFromString(lineStr, utility); 2013 } 2014 } 2015 } catch (IOException exception) { 2016 LOG.error("Compressor::parseModuleName io exception: " + exception.getMessage()); 2017 throw new BundleException("Parse module name failed."); 2018 } 2019 } 2020 2021 2022 /** 2023 * Get name from line string 2024 * 2025 * @param lineStr line string 2026 * @param utility common data 2027 * @throws BundleException StringIndexOutOfBoundsException 2028 */ getNameFromString(String lineStr, Utility utility)2029 private void getNameFromString(String lineStr, Utility utility) throws BundleException { 2030 try { 2031 int endIndex = lineStr.lastIndexOf(SEMICOLON); 2032 if (endIndex <= 0) { 2033 LOG.error("Compressor::getModuleNameFromString field the json is not standard."); 2034 throw new BundleException("Parse module name failed, module-name is invalid."); 2035 } 2036 int startIndex = lineStr.lastIndexOf(SEMICOLON, endIndex - 1) + 1; 2037 String formName = lineStr.substring(startIndex, endIndex); 2038 if (formName == null || formName.isEmpty()) { 2039 LOG.error("Compressor::getModuleNameFromString field module-name is empty."); 2040 throw new BundleException("Parse module name failed, module-name is empty."); 2041 } 2042 String[] nameList = formName.split("\\."); 2043 if (nameList.length <= 1) { 2044 formNamesList.add(formName); 2045 utility.addFormNameList(formName); 2046 } 2047 } catch (StringIndexOutOfBoundsException exception) { 2048 LOG.error("Compressor::parseModuleName field module-name is fault: " + exception.getMessage()); 2049 throw new BundleException("Parse module name failed, module-name is invalid."); 2050 } 2051 } 2052 2053 /** 2054 * Get module name from line string 2055 * 2056 * @param lineStr line string 2057 * @param utility common data 2058 * @throws BundleException StringIndexOutOfBoundsException 2059 */ getModuleNameFromString(String lineStr, Utility utility)2060 private void getModuleNameFromString(String lineStr, Utility utility) throws BundleException { 2061 try { 2062 int endIndex = lineStr.lastIndexOf(SEMICOLON); 2063 if (endIndex <= 0) { 2064 LOG.error("Compressor::getModuleNameFromString field the json is not standard."); 2065 throw new BundleException("Parse module name failed, module-name is invalid."); 2066 } 2067 int startIndex = lineStr.lastIndexOf(SEMICOLON, endIndex - 1) + 1; 2068 String moduleName = lineStr.substring(startIndex, endIndex); 2069 list.add(moduleName); 2070 if (moduleName == null || moduleName.isEmpty()) { 2071 LOG.error("Compressor::getModuleNameFromString field module-name is empty."); 2072 throw new BundleException("Parse module name failed, module-name is empty."); 2073 } 2074 utility.setModuleName(moduleName); 2075 } catch (StringIndexOutOfBoundsException exception) { 2076 LOG.error("Compressor::parseModuleName field module-name is fault: " + exception.getMessage()); 2077 throw new BundleException("Parse module name failed, module-name is invalid."); 2078 } 2079 } 2080 parseCompressNativeLibs(BufferedReader bufferedReader, Utility utility)2081 private void parseCompressNativeLibs(BufferedReader bufferedReader, Utility utility) throws BundleException { 2082 String lineStr = null; 2083 try { 2084 while ((lineStr = bufferedReader.readLine()) != null) { 2085 if (lineStr.contains(COMPRESS_NATIVE_LIBS)) { 2086 if (lineStr.contains(Utility.FALSE_STRING)) { 2087 utility.setIsCompressNativeLibs(false); 2088 break; 2089 } 2090 } 2091 } 2092 } catch (IOException exception) { 2093 LOG.error("Compressor::parseCompressNativeLibs io exception: " + exception.getMessage()); 2094 throw new BundleException("Parse compress native libs failed."); 2095 } 2096 } 2097 2098 /** 2099 * ZipOutputStream flush, closeEntry and finish. 2100 */ closeZipOutputStream()2101 private void closeZipOutputStream() { 2102 try { 2103 if (zipOut != null) { 2104 zipOut.flush(); 2105 } 2106 } catch (IOException exception) { 2107 LOG.error("Compressor::closeZipOutputStream flush exception " + exception.getMessage()); 2108 } 2109 try { 2110 if (zipOut != null) { 2111 zipOut.closeEntry(); 2112 } 2113 } catch (IOException exception) { 2114 LOG.error("Compressor::closeZipOutputStream close entry io exception " + exception.getMessage()); 2115 } 2116 try { 2117 if (zipOut != null) { 2118 zipOut.finish(); 2119 } 2120 } catch (IOException exception) { 2121 LOG.error("Compressor::closeZipOutputStream finish exception " + exception.getMessage()); 2122 } 2123 } 2124 2125 /** 2126 * Parse device type from config.json 2127 * 2128 * @param bufferedReader config.json buffered Reader 2129 * @param utility common data 2130 * @throws BundleException IOException 2131 */ parseDeviceType(BufferedReader bufferedReader, Utility utility)2132 private void parseDeviceType(BufferedReader bufferedReader, Utility utility) throws BundleException { 2133 String lineStr = null; 2134 boolean isDeviceTypeStart = false; 2135 try { 2136 while ((lineStr = bufferedReader.readLine()) != null) { 2137 if (!isDeviceTypeStart) { 2138 if (lineStr.contains(DEVICE_TYPE)) { 2139 isDeviceTypeStart = true; 2140 } 2141 continue; 2142 } 2143 if (lineStr.contains(JSON_END)) { 2144 break; 2145 } 2146 utility.setDeviceType(lineStr); 2147 break; 2148 } 2149 } catch (IOException exception) { 2150 LOG.error("Compressor::parseDeviceType io exception: " + exception.getMessage()); 2151 throw new BundleException("Parse device type failed"); 2152 } 2153 } 2154 2155 /** 2156 * check hap is valid in haps when pack app, check type has bundleName, 2157 * vendor, version, apiVersion moduleName, packageName. 2158 * 2159 * @param fileLists is the list of hapPath. 2160 * @return true is for successful and false is for failed 2161 * @throws BundleException FileNotFoundException|IOException. 2162 */ checkHapIsValid(List<String> fileLists)2163 private boolean checkHapIsValid(List<String> fileLists) throws BundleException { 2164 List<HapVerifyInfo> hapVerifyInfos = new ArrayList<>(); 2165 for (String hapPath : fileLists) { 2166 if (hapPath.isEmpty()) { 2167 LOG.error("Compressor::checkHapIsValid input wrong hap file."); 2168 throw new BundleException("Compressor::checkHapIsValid input wrong hap file."); 2169 } 2170 File srcFile = new File(hapPath); 2171 String fileStr = srcFile.getName(); 2172 if (fileStr.isEmpty()) { 2173 LOG.error("Compressor::checkHapIsValid get file name failed."); 2174 throw new BundleException("Compressor::checkHapIsValid get file name failed."); 2175 } 2176 if (!fileStr.toLowerCase(Locale.ENGLISH).endsWith(HAP_SUFFIX) 2177 && !fileStr.toLowerCase(Locale.ENGLISH).endsWith(HSP_SUFFIX)) { 2178 LOG.error("Compressor::checkHapIsValid input wrong hap file."); 2179 throw new BundleException("Compressor::checkHapIsValid input wrong hap file."); 2180 } 2181 if (isModuleHap(hapPath)) { 2182 hapVerifyInfos.add(parseStageHapVerifyInfo(hapPath)); 2183 } else { 2184 hapVerifyInfos.add(parseFAHapVerifyInfo(hapPath)); 2185 } 2186 } 2187 setAtomicServiceFileSizeLimit(hapVerifyInfos); 2188 if (!HapVerify.checkHapIsValid(hapVerifyInfos)) { 2189 return false; 2190 } 2191 return true; 2192 } 2193 2194 /** 2195 * parse stage file to hap verify info from hap path. 2196 * 2197 * @param filePath is the hap path 2198 * @return hapVerifyInfo 2199 */ parseStageHapVerifyInfo(String filePath)2200 public static HapVerifyInfo parseStageHapVerifyInfo(String filePath) throws BundleException { 2201 HapVerifyInfo hapVerifyInfo = readStageHapVerifyInfo(filePath); 2202 hapVerifyInfo.setStageModule(true); 2203 ModuleJsonUtil.parseStageHapVerifyInfo(hapVerifyInfo); 2204 hapVerifyInfo.setFileLength(FileUtils.getFileSize(filePath)); 2205 return hapVerifyInfo; 2206 } 2207 2208 /** 2209 * set file size limit for each HapVerifyInfo. 2210 * 2211 * @param hapVerifyInfos Indicates hapVerifyInfo list. 2212 */ setAtomicServiceFileSizeLimit(List<HapVerifyInfo>hapVerifyInfos)2213 public static void setAtomicServiceFileSizeLimit(List<HapVerifyInfo>hapVerifyInfos) { 2214 for (HapVerifyInfo hapVerifyInfo : hapVerifyInfos) { 2215 if (!hapVerifyInfo.getBundleType().equals(ATOMIC_SERVICE)) { 2216 continue; 2217 } 2218 hapVerifyInfo.setEntrySizeLimit(getEntryModuleSizeLimit()); 2219 hapVerifyInfo.setNotEntrySizeLimit(getNotEntryModuleSizeLimit()); 2220 hapVerifyInfo.setSumSizeLimit(getSumModuleSizeLimit()); 2221 } 2222 } 2223 2224 /** 2225 * parse fa file to hap verify info from hap path. 2226 * 2227 * @param filePath is the hap path 2228 * @return hapVerifyInfo 2229 */ parseFAHapVerifyInfo(String filePath)2230 public static HapVerifyInfo parseFAHapVerifyInfo(String filePath) throws BundleException { 2231 HapVerifyInfo hapVerifyInfo = readFAHapVerifyInfo(filePath); 2232 hapVerifyInfo.setStageModule(false); 2233 hapVerifyInfo.setFileLength(FileUtils.getFileSize(filePath)); 2234 ModuleJsonUtil.parseFAHapVerifyInfo(hapVerifyInfo); 2235 return hapVerifyInfo; 2236 } 2237 2238 /** 2239 * read stage hap verify info from hap file. 2240 * 2241 * @param srcPath source file to zip 2242 * @return HapVerifyInfo of parse result 2243 * @throws BundleException FileNotFoundException|IOException. 2244 */ readStageHapVerifyInfo(String srcPath)2245 public static HapVerifyInfo readStageHapVerifyInfo(String srcPath) throws BundleException { 2246 HapVerifyInfo hapVerifyInfo = new HapVerifyInfo(); 2247 ZipFile zipFile = null; 2248 try { 2249 File srcFile = new File(srcPath); 2250 zipFile = new ZipFile(srcFile); 2251 hapVerifyInfo.setResourceMap(FileUtils.getProfileJson(zipFile)); 2252 hapVerifyInfo.setProfileStr(FileUtils.getFileStringFromZip(MODULE_JSON, zipFile)); 2253 } catch (IOException e) { 2254 LOG.error("FileUtil::parseStageHapVerifyInfo file not available."); 2255 throw new BundleException("FileUtil::parseStageHapVerifyInfo file not available."); 2256 } finally { 2257 Utility.closeStream(zipFile); 2258 } 2259 return hapVerifyInfo; 2260 } 2261 2262 /** 2263 * read fa hap verify info from hap file. 2264 * 2265 * @param srcPath source file to zip 2266 * @return HapVerifyInfo of parse result 2267 * @throws BundleException FileNotFoundException|IOException. 2268 */ readFAHapVerifyInfo(String srcPath)2269 public static HapVerifyInfo readFAHapVerifyInfo(String srcPath) throws BundleException { 2270 HapVerifyInfo hapVerifyInfo = new HapVerifyInfo(); 2271 ZipFile zipFile = null; 2272 try { 2273 File srcFile = new File(srcPath); 2274 zipFile = new ZipFile(srcFile); 2275 hapVerifyInfo.setProfileStr(FileUtils.getFileStringFromZip(CONFIG_JSON, zipFile)); 2276 } catch (IOException e) { 2277 LOG.error("FileUtil::parseStageHapVerifyInfo file not available."); 2278 throw new BundleException("FileUtil::parseStageHapVerifyInfo file not available."); 2279 } finally { 2280 Utility.closeStream(zipFile); 2281 } 2282 return hapVerifyInfo; 2283 } 2284 2285 /** 2286 * compress in hqf mode. 2287 * 2288 * @param utility common data 2289 * @throws BundleException FileNotFoundException|IOException. 2290 */ compressHQFMode(Utility utility)2291 private void compressHQFMode(Utility utility) throws BundleException { 2292 pathToFile(utility, utility.getJsonPath(), NULL_DIR_NAME, false); 2293 2294 if (!utility.getEtsPath().isEmpty()) { 2295 pathToFile(utility, utility.getEtsPath(), ETS_PATH, false); 2296 } 2297 if (!utility.getLibPath().isEmpty()) { 2298 pathToFile(utility, utility.getLibPath(), LIBS_DIR_NAME, false); 2299 } 2300 } 2301 2302 /** 2303 * compress in appqf mode. 2304 * 2305 * @param utility common data 2306 * @throws BundleException FileNotFoundException|IOException. 2307 */ compressAPPQFMode(Utility utility)2308 private void compressAPPQFMode(Utility utility) throws BundleException { 2309 List<String> fileList = utility.getFormatedHQFList(); 2310 if (!checkHQFIsValid(fileList)) { 2311 LOG.error("Error: checkHQFIsValid failed when pack appqf file."); 2312 throw new BundleException("Error: checkHQFIsValid failed when pack appqf file."); 2313 } 2314 for (String hapPath : fileList) { 2315 pathToFile(utility, hapPath, NULL_DIR_NAME, false); 2316 } 2317 } 2318 2319 /** 2320 * check input hqf is valid. 2321 * 2322 * @param fileList is input path of hqf files 2323 * @throws BundleException FileNotFoundException|IOException. 2324 */ checkHQFIsValid(List<String> fileList)2325 private boolean checkHQFIsValid(List<String> fileList) throws BundleException { 2326 List<HQFInfo> hqfVerifyInfos = new ArrayList<>(); 2327 for (String file : fileList) { 2328 hqfVerifyInfos.add(ModuleJsonUtil.parseHQFInfo(file)); 2329 } 2330 if (!HQFVerify.checkHQFIsValid(hqfVerifyInfos)) { 2331 LOG.error("Error: input hqf is invalid."); 2332 return false; 2333 } 2334 return true; 2335 } 2336 compressHSPMode(Utility utility)2337 private void compressHSPMode(Utility utility) throws BundleException { 2338 pathToFile(utility, utility.getJsonPath(), NULL_DIR_NAME, false); 2339 2340 pathToFile(utility, utility.getProfilePath(), NULL_DIR_NAME, false); 2341 2342 if (!utility.getIndexPath().isEmpty() && isModuleJSON(utility.getJsonPath())) { 2343 String assetsPath = NULL_DIR_NAME; 2344 pathToFile(utility, utility.getIndexPath(), assetsPath, false); 2345 } 2346 2347 if (!utility.getLibPath().isEmpty()) { 2348 pathToFile(utility, utility.getLibPath(), LIBS_DIR_NAME, utility.isCompressNativeLibs()); 2349 } 2350 2351 if (!utility.getANPath().isEmpty()) { 2352 pathToFile(utility, utility.getANPath(), AN_DIR_NAME, false); 2353 } 2354 2355 if (!utility.getFilePath().isEmpty()) { 2356 pathToFile(utility, utility.getFilePath(), NULL_DIR_NAME, false); 2357 } 2358 2359 if (!utility.getResPath().isEmpty() && !utility.getModuleName().isEmpty()) { 2360 String resPath = ASSETS_DIR_NAME + utility.getModuleName() + LINUX_FILE_SEPARATOR 2361 + RESOURCES_DIR_NAME; 2362 if (DEVICE_TYPE_FITNESSWATCH.equals(utility.getDeviceType().replace(SEMICOLON, EMPTY_STRING).trim()) || 2363 DEVICE_TYPE_FITNESSWATCH_NEW.equals( 2364 utility.getDeviceType().replace(SEMICOLON, EMPTY_STRING).trim())) { 2365 resPath = RES_DIR_NAME; 2366 } 2367 pathToFile(utility, utility.getResPath(), resPath, false); 2368 } 2369 2370 if (!utility.getResourcesPath().isEmpty() && isModuleJSON(utility.getJsonPath())) { 2371 String resourcesPath = RESOURCES_DIR_NAME; 2372 pathToFile(utility, utility.getResourcesPath(), resourcesPath, false); 2373 } 2374 if (!utility.getJsPath().isEmpty() && isModuleJSON(utility.getJsonPath())) { 2375 String jsPath = JS_PATH; 2376 pathToFile(utility, utility.getJsPath(), jsPath, false); 2377 } 2378 2379 if (!utility.getEtsPath().isEmpty() && isModuleJSON(utility.getJsonPath())) { 2380 String etsPath = ETS_PATH; 2381 pathToFile(utility, utility.getEtsPath(), etsPath, false); 2382 } 2383 2384 if (!utility.getRpcidPath().isEmpty()) { 2385 String rpcidPath = NULL_DIR_NAME; 2386 pathToFile(utility, utility.getRpcidPath(), rpcidPath, false); 2387 } 2388 2389 if (!utility.getAssetsPath().isEmpty()) { 2390 pathToFile(utility, utility.getAssetsPath(), ASSETS_DIR_NAME, false); 2391 } 2392 2393 if (!utility.getBinPath().isEmpty()) { 2394 pathToFile(utility, utility.getBinPath(), NULL_DIR_NAME, false); 2395 } 2396 2397 if (!utility.getPackInfoPath().isEmpty()) { 2398 pathToFile(utility, utility.getPackInfoPath(), NULL_DIR_NAME, false); 2399 } 2400 2401 compressHapModeMultiple(utility); 2402 } 2403 } 2404