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