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.BufferedInputStream; 19 import java.io.BufferedReader; 20 import java.io.ByteArrayOutputStream; 21 import java.io.File; 22 import java.io.FileInputStream; 23 import java.io.FileNotFoundException; 24 import java.io.FileOutputStream; 25 import java.io.IOException; 26 import java.io.InputStream; 27 import java.io.InputStreamReader; 28 29 import java.nio.charset.StandardCharsets; 30 import java.nio.file.attribute.FileTime; 31 32 import java.util.ArrayList; 33 import java.util.Enumeration; 34 import java.util.HashMap; 35 import java.util.List; 36 import java.util.Locale; 37 import java.util.stream.Collectors; 38 import java.util.zip.CRC32; 39 import java.util.zip.CheckedOutputStream; 40 import java.util.zip.ZipEntry; 41 import java.util.zip.ZipFile; 42 import java.util.zip.ZipInputStream; 43 import java.util.zip.ZipOutputStream; 44 45 46 /** 47 * bundle uncompress. 48 * 49 */ 50 public class Uncompress { 51 private static final String HAP_SUFFIX = ".hap"; 52 private static final String APK_SUFFIX = ".apk"; 53 private static final String JSON_SUFFIX = ".json"; 54 private static final String HSP_SUFFIX = ".hsp"; 55 56 private static final String PACK_INFO = "pack.info"; 57 private static final String HARMONY_PROFILE = "config.json"; 58 private static final String MODULE_JSON = "module.json"; 59 private static final String RESOURCE_INDEX = "resources.index"; 60 private static final String RPCID_SC = "rpcid.sc"; 61 private static final String LINUX_FILE_SEPARATOR = "/"; 62 private static final String TEMP_PATH = "temp"; 63 private static final String HAP_SUFFIXI = ".hap"; 64 private static final String ENTRY_TYPE = "entry"; 65 private static final String SYSTEM_ACTION = "action.system.home"; 66 private static final String SYSTEM_WANT_HOME = "ohos.want.action.home"; 67 private static final String SYSTEM_ENTITY = "entity.system.home"; 68 private static final int READ_BUFFER_SIZE = 1024; 69 private static final int BUFFER_SIZE = 10 * 1024; 70 private static final long FILE_TIME = 1546272000000L; 71 private static final String LIBS_DIR_NAME = "libs"; 72 private static final String CUT_ENTRY_FILENAME = "cut_entry.apk"; 73 private static final String SO_SUFFIX = ".so"; 74 private static final String RESOURCE_PATH = "resources/base/profile/"; 75 private static final String TRUE = "true"; 76 private static final String HQF_SUFFIX = ".hqf"; 77 private static final String PATCH_JSON = "patch.json"; 78 private static final String HAP_PREFIX = "HAP"; 79 private static final String TEMP = "temp"; 80 private static final Log LOG = new Log(Uncompress.class.toString()); 81 82 /** 83 * unpackage entrance. 84 * 85 * @param utility common data 86 * @return unpackageProcess if unpackage succeed 87 */ unpackageProcess(Utility utility)88 static boolean unpackageProcess(Utility utility) { 89 if (utility == null) { 90 LOG.error("Uncompress::unpackageProcess utility is null."); 91 return false; 92 } 93 boolean unpackageResult = true; 94 File destFile = new File(utility.getOutPath()); 95 96 if (!destFile.exists()) { 97 if (!destFile.mkdirs()) { 98 LOG.error("Uncompress::unpackageProcess create out file directory failed!"); 99 return false; 100 } 101 } 102 try { 103 if (!Utility.MODE_HAP.equals(utility.getMode()) || !TRUE.equals(utility.getRpcid())) { 104 if (!utility.getForceRewrite().isEmpty() && "true".equals(utility.getForceRewrite())) { 105 File outPath = new File(utility.getOutPath()); 106 deleteFile(outPath); 107 outPath.mkdirs(); 108 } 109 } 110 switch (utility.getMode()) { 111 case Utility.MODE_HAP: 112 unpackageHapMode(utility); 113 break; 114 case Utility.MODE_HAR: 115 dataTransferAllFiles(utility.getHarPath(), utility.getOutPath()); 116 break; 117 case Utility.MODE_APP: 118 dataTransferFilesByApp(utility, utility.getAppPath(), utility.getOutPath()); 119 break; 120 case Utility.MODE_APPQF: 121 uncompressAPPQFFile(utility); 122 break; 123 case Utility.MODE_HSP: 124 dataTransferAllFiles(utility.getHspPath(), utility.getOutPath()); 125 break; 126 default: 127 LOG.error("Uncompress::unpackageProcess input wrong type!"); 128 throw new BundleException("Uncompress::unpackageProcess input wrong type!"); 129 } 130 } catch (BundleException ignored) { 131 unpackageResult = false; 132 LOG.error("Uncompress::unpackageProcess Bundle exception"); 133 } 134 // return uncompress information. 135 if (!unpackageResult) { 136 LOG.error("Uncompress::unpackageProcess unpackage failed!"); 137 } 138 return unpackageResult; 139 } 140 141 /** 142 * unpack hap. 143 * 144 * @param utility common data 145 */ unpackageHapMode(Utility utility)146 static void unpackageHapMode(Utility utility) throws BundleException { 147 if (!Utility.MODE_HAP.equals(utility.getMode())) { 148 throw new BundleException("Uncompress::unpackageHapMode input wrong unpack mode"); 149 } 150 try { 151 if (TRUE.equals(utility.getRpcid())) { 152 getRpcidFromHap(utility.getHapPath(), utility.getOutPath()); 153 return; 154 } 155 if (TRUE.equals(utility.getUnpackApk())) { 156 unzip(utility, utility.getHapPath(), utility.getOutPath(), APK_SUFFIX); 157 String[] temp = utility.getHapPath().replace("\\", "/").split("/"); 158 String hapName = temp[temp.length - 1]; 159 repackHap(utility.getHapPath(), utility.getOutPath(), hapName, utility.getUnpackApk()); 160 } else { 161 dataTransferAllFiles(utility.getHapPath(), utility.getOutPath()); 162 } 163 } catch (BundleException e) { 164 LOG.error("Uncompress::unpackageHapMode failed"); 165 throw new BundleException("Uncompress::unpackageHapMode failed"); 166 } 167 } 168 169 /** 170 * uncompress app. 171 * 172 * @param utility common data 173 * @return the uncompress result 174 */ uncompressAppByPath(Utility utility)175 static UncompressResult uncompressAppByPath(Utility utility) { 176 UncompressResult compressResult = new UncompressResult(); 177 InputStream input = null; 178 String srcPath = utility.getAppPath(); 179 String parseMode = utility.getParseMode(); 180 181 try { 182 if (UncompressEntrance.PARSE_MODE_HAPLIST.equals(parseMode)) { 183 compressResult = uncompress(utility.getDeviceType(), srcPath, PACK_INFO); 184 } else if (UncompressEntrance.PARSE_MODE_HAPINFO.equals(parseMode)) { 185 compressResult = uncompressHapFromAppPath(srcPath, utility); 186 } else if (UncompressEntrance.PARSE_MODE_ALL.equals(parseMode)) { 187 compressResult = uncompressAllAppByPath(srcPath); 188 } else { 189 LOG.error("Uncompress::uncompressApp parseMode is invalid!"); 190 compressResult.setResult(false); 191 compressResult.setMessage("ParseApp parseMode is invalid"); 192 } 193 } catch (BundleException e) { 194 LOG.error("Uncompress::uncompressApp Bundle exception"); 195 compressResult.setResult(false); 196 compressResult.setMessage("ParseApp Bundle exception"); 197 } finally { 198 Utility.closeStream(input); 199 } 200 return compressResult; 201 } 202 uncompressHapFromAppPath(String srcPath, Utility utility)203 private static UncompressResult uncompressHapFromAppPath(String srcPath, Utility utility) throws BundleException { 204 UncompressResult result = new UncompressResult(); 205 String hapName = utility.getHapName(); 206 if (!hapName.toLowerCase(Locale.ENGLISH).endsWith(HAP_SUFFIX)) { 207 hapName += HAP_SUFFIX; 208 } 209 ZipFile appFile = null; 210 ZipEntry entry = null; 211 InputStream stream = null; 212 try { 213 appFile = new ZipFile(srcPath); 214 Enumeration<? extends ZipEntry> entries = appFile.entries(); 215 while (entries.hasMoreElements()) { 216 entry = entries.nextElement(); 217 stream = appFile.getInputStream(entry); 218 if (!hapName.equals(entry.getName().toLowerCase(Locale.ENGLISH))) { 219 continue; 220 } 221 UncompressResult hapInfo = uncompressHapByStream("", stream, hapName); 222 if (hapInfo.getProfileInfos() != null && hapInfo.getProfileInfos().size() > 0) { 223 result.addProfileInfo(hapInfo.getProfileInfos().get(0)); 224 result.addProfileInfoStr(hapInfo.getProfileInfosStr().get(0)); 225 } 226 break; 227 } 228 } catch (IOException | BundleException e) { 229 LOG.error("uncompressHapFromAppPath failed!"); 230 throw new BundleException("uncompressHapFromAppPath failed!"); 231 } finally { 232 Utility.closeStream(appFile); 233 Utility.closeStream(stream); 234 } 235 return result; 236 } 237 uncompressAllAppByPath(String srcPath)238 private static UncompressResult uncompressAllAppByPath(String srcPath) throws BundleException { 239 UncompressResult result = new UncompressResult(); 240 ZipFile appFile = null; 241 ZipEntry entry = null; 242 InputStream stream = null; 243 try { 244 appFile = new ZipFile(srcPath); 245 Enumeration<? extends ZipEntry> entries = appFile.entries(); 246 while (entries.hasMoreElements()) { 247 entry = entries.nextElement(); 248 stream = appFile.getInputStream(entry); 249 if (PACK_INFO.equals(entry.getName().toLowerCase(Locale.ENGLISH))) { 250 String packInfo = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8)) 251 .lines().parallel().collect(Collectors.joining(System.lineSeparator())); 252 List<PackInfo> packInfos = JsonUtil.parseHapList("", packInfo); 253 result.setPackInfoStr(packInfo); 254 result.setPackInfos(packInfos); 255 } 256 if (entry.getName().toLowerCase(Locale.ENGLISH).endsWith(HAP_SUFFIX)) { 257 UncompressResult hapInfo = uncompressHapByStream("", stream, entry.getName()); 258 if (hapInfo.getProfileInfos() != null && hapInfo.getProfileInfos().size() > 0) { 259 result.addProfileInfo(hapInfo.getProfileInfos().get(0)); 260 result.addProfileInfoStr(hapInfo.getProfileInfosStr().get(0)); 261 } 262 } 263 } 264 result = checkParseAllResult(result); 265 result = obtainLabelAndIcon(result); 266 } catch (IOException | BundleException e) { 267 LOG.error("uncompressAllAppByPath failed!"); 268 throw new BundleException("uncompressAllAppByPath failed!"); 269 } finally { 270 Utility.closeStream(appFile); 271 Utility.closeStream(stream); 272 } 273 return result; 274 } 275 276 277 /** 278 * uncompress app. 279 * 280 * @param utility common data 281 * @param input the InputStream about the app package. 282 * @return the uncompress result 283 */ uncompressAppByInput(Utility utility, InputStream input)284 static UncompressResult uncompressAppByInput(Utility utility, InputStream input) { 285 UncompressResult compressResult = new UncompressResult(); 286 String parseMode = utility.getParseMode(); 287 try { 288 if (!parseMode.isEmpty() && UncompressEntrance.PARSE_MODE_HAPLIST.equals(parseMode)) { 289 compressResult = uncompressByInput(utility.getDeviceType(), input, PACK_INFO, ""); 290 } else if (!parseMode.isEmpty() && UncompressEntrance.PARSE_MODE_HAPINFO.equals(parseMode)) { 291 compressResult = uncompressHapFromAppStream(utility.getDeviceType(), input, utility.getHapName()); 292 } else if (!parseMode.isEmpty() && UncompressEntrance.PARSE_MODE_ALL.equals(parseMode)) { 293 compressResult = uncompressAllFromAppStream(input); 294 } else { 295 LOG.error("Uncompress::uncompressAppByInput parseMode is invalid!"); 296 compressResult.setResult(false); 297 compressResult.setMessage("ParseApp parseMode is invalid"); 298 } 299 } catch (BundleException exception) { 300 LOG.error("Uncompress::uncompressAppByInput Bundle exception"); 301 compressResult.setResult(false); 302 compressResult.setMessage("ParseApp Bundle exception"); 303 } 304 return compressResult; 305 } 306 uncompressHapFromAppStream(String deviceType, InputStream stream, String fileName)307 private static UncompressResult uncompressHapFromAppStream(String deviceType, InputStream stream, String fileName) 308 throws BundleException { 309 String hapFile = fileName; 310 if (!fileName.toLowerCase(Locale.ENGLISH).endsWith(HAP_SUFFIX)) { 311 hapFile += HAP_SUFFIX; 312 } 313 UncompressResult result = new UncompressResult(); 314 ZipInputStream zipInputStream = null; 315 try { 316 zipInputStream = new ZipInputStream(stream); 317 ZipEntry appEntry; 318 while ((appEntry = zipInputStream.getNextEntry()) != null) { 319 if (appEntry.getName().toLowerCase(Locale.ENGLISH).equals(hapFile)) { 320 result = uncompressHapByStream("", zipInputStream, appEntry.getName()); 321 } 322 } 323 } catch (IOException e) { 324 LOG.error("uncompressHapFromAppStream failed!"); 325 throw new BundleException("uncompressHapFromAppStream failed!"); 326 } finally { 327 Utility.closeStream(zipInputStream); 328 } 329 return result; 330 } 331 uncompressAllFromAppStream(InputStream stream)332 private static UncompressResult uncompressAllFromAppStream(InputStream stream) throws BundleException { 333 UncompressResult result = new UncompressResult(); 334 ZipInputStream zipInputStream = null; 335 ByteArrayOutputStream outputStream = null; 336 try { 337 zipInputStream = new ZipInputStream(stream); 338 ZipEntry entry; 339 while ((entry = zipInputStream.getNextEntry()) != null) { 340 if (PACK_INFO.equals(entry.getName().toLowerCase(Locale.ENGLISH))) { 341 String packInfo = new BufferedReader(new InputStreamReader(zipInputStream, 342 StandardCharsets.UTF_8)).lines().parallel() 343 .collect(Collectors.joining(System.lineSeparator())); 344 List<PackInfo> packInfos = JsonUtil.parseHapList("", packInfo); 345 result.setPackInfoStr(packInfo); 346 result.setPackInfos(packInfos); 347 } 348 if (entry.getName().toLowerCase(Locale.ENGLISH).endsWith(HAP_SUFFIX)) { 349 UncompressResult hapResult = uncompressHapByStream("", zipInputStream, entry.getName()); 350 if (hapResult.getProfileInfos() != null && hapResult.getProfileInfos().size() > 0) { 351 result.addProfileInfo(hapResult.getProfileInfos().get(0)); 352 result.addProfileInfoStr(hapResult.getProfileInfosStr().get(0)); 353 } 354 } 355 } 356 result = checkParseAllResult(result); 357 result = obtainLabelAndIcon(result); 358 } catch (IOException | BundleException e) { 359 LOG.error("uncompressAllFromAppStream failed!"); 360 throw new BundleException("uncompressAllFromAppStream failed!"); 361 } finally { 362 Utility.closeStream(zipInputStream); 363 Utility.closeStream(outputStream); 364 } 365 return result; 366 } 367 368 /** 369 * uncompress hap. 370 * 371 * @param utility common data 372 * @return the uncompress result 373 */ uncompressHap(Utility utility)374 static UncompressResult uncompressHap(Utility utility) { 375 UncompressResult compressResult = new UncompressResult(); 376 try { 377 compressResult = uncompressHapByPath(utility.getDeviceType(), utility.getHapPath()); 378 } catch (BundleException ignored) { 379 LOG.error("Uncompress::uncompressHap Bundle exception"); 380 compressResult.setResult(false); 381 compressResult.setMessage("uncompressHap Bundle exception"); 382 } 383 return compressResult; 384 } 385 386 /** 387 * uncompress hap by path, it can adapt stage module and fa module. 388 * 389 * @param deviceType indicates the device type of parse type. 390 * @param hapPath indicates the hap path of hap. 391 * @return the uncompress result 392 */ uncompressHapByPath(String deviceType, String hapPath)393 static UncompressResult uncompressHapByPath(String deviceType, String hapPath) throws BundleException { 394 UncompressResult compressResult = new UncompressResult(); 395 try { 396 if (isModuleHap(hapPath, compressResult)) { 397 compressResult = unCompressModuleHap(deviceType, hapPath, MODULE_JSON); 398 } else { 399 compressResult = uncompress(deviceType, hapPath, HARMONY_PROFILE); 400 compressResult = obtainLabelAndIcon(compressResult); 401 } 402 } catch (BundleException e) { 403 LOG.error("Uncompress::uncompressHapByPath Bundle exception"); 404 throw new BundleException("Uncompress::uncompressHapByPath failed"); 405 } 406 return compressResult; 407 } 408 409 /** 410 * uncompress hap. 411 * 412 * @param utility common data 413 * @param input the InputStream about the app package. 414 * @return the uncompress result 415 */ uncompressHapByInput(Utility utility, InputStream input)416 static UncompressResult uncompressHapByInput(Utility utility, InputStream input) { 417 UncompressResult compressResult = new UncompressResult(); 418 try { 419 compressResult = uncompressHapByStream(utility.getDeviceType(), input, ""); 420 } catch (BundleException ignored) { 421 LOG.error("Uncompress::uncompressHapByInput Bundle exception"); 422 compressResult.setResult(false); 423 compressResult.setMessage("uncompressHapByInput Bundle exception"); 424 } 425 return compressResult; 426 } 427 428 /** 429 * uncompress hap by InputStream, it can adapt stage module and fa module. 430 * 431 * @param deviceType indicates the device type of parse type. 432 * @param stream indicates the input stream of hap. 433 * @return the uncompress result 434 */ uncompressHapByStream(String deviceType, InputStream stream, String hapName)435 static UncompressResult uncompressHapByStream(String deviceType, InputStream stream, 436 String hapName) throws BundleException { 437 UncompressResult compressResult = new UncompressResult(); 438 compressResult = uncompressHapByBigStream(deviceType, stream, hapName); 439 return compressResult; 440 } 441 uncompressHapByBigStream(String deviceType, InputStream stream, String hapName)442 static UncompressResult uncompressHapByBigStream(String deviceType, InputStream stream, String hapName) 443 throws BundleException { 444 UncompressResult compressResult = new UncompressResult(); 445 InputStream fileStream = null; 446 InputStream parseStream = null; 447 File file = null; 448 try { 449 String releativePath = System.getProperty("user.dir"); 450 File directory = new File(releativePath); 451 file = File.createTempFile(HAP_PREFIX, HAP_SUFFIX, directory); 452 writeToTempFile(stream, file); 453 fileStream = new FileInputStream(file); 454 boolean isModule = false; 455 if (isModuleInput(fileStream)) { 456 isModule = true; 457 } 458 parseStream = new FileInputStream(file); 459 if (isModule) { 460 compressResult = uncompressModuleHapByInput(deviceType, parseStream, MODULE_JSON, hapName); 461 } else { 462 compressResult = uncompressByInput(deviceType, parseStream, HARMONY_PROFILE, hapName); 463 compressResult = obtainLabelAndIcon(compressResult); 464 } 465 } catch (IOException e) { 466 LOG.error("uncompressHapByBigStream failed for IO exception!"); 467 throw new BundleException("uncompressHapByBigStream failed for IO exception!"); 468 } finally { 469 Utility.closeStream(fileStream); 470 Utility.closeStream(parseStream); 471 if (file != null) { 472 FileUtils.deleteFile(file.getPath()); 473 } 474 } 475 return compressResult; 476 } 477 478 /** 479 * unzip process 480 * 481 * @param utility common data 482 * @param srcPath source file path 483 * @param destDirPath destination file path 484 * @param suffix suffix for judgment 485 * @throws BundleException FileNotFoundException|IOException. 486 */ unzip(Utility utility, String srcPath, String destDirPath, String suffix)487 private static void unzip(Utility utility, String srcPath, String destDirPath, String suffix) 488 throws BundleException { 489 if (utility == null) { 490 LOG.error("Uncompress::unzip utility is null!"); 491 throw new BundleException("Unzip failed, utility is null"); 492 } 493 494 if (srcPath.isEmpty() || !UncompressVerify.isPathValid(srcPath, true, "")) { 495 LOG.error("Uncompress::unzip srcPath is invalid!"); 496 throw new BundleException("Unzip failed, srcPath is invalid"); 497 } 498 499 if (destDirPath.isEmpty() || !UncompressVerify.isPathValid(destDirPath, false, null)) { 500 LOG.error("Uncompress::unzip destDirPath is invalid!"); 501 throw new BundleException("Unzip failed, destDirPath is invalid"); 502 } 503 unzipFromFile(utility, srcPath, destDirPath, suffix); 504 } 505 506 /** 507 * unzip process from the file 508 * 509 * @param utility common data 510 * @param srcPath source file path 511 * @param destDirPath destination file path 512 * @param suffix suffix for judgment 513 * @throws BundleException FileNotFoundException|IOException. 514 */ unzipFromFile(Utility utility, String srcPath, String destDirPath, String suffix)515 private static void unzipFromFile(Utility utility, String srcPath, String destDirPath, String suffix) 516 throws BundleException { 517 ZipFile zipFile = null; 518 String hapNames = ""; 519 try { 520 zipFile = new ZipFile(new File(srcPath)); 521 if (utility != null && !utility.getDeviceType().isEmpty() && HAP_SUFFIX.equals(suffix)) { 522 List<PackInfo> packInfos = uncompress(utility.getDeviceType(), srcPath, PACK_INFO).getPackInfos(); 523 for (PackInfo packinfo : packInfos) { 524 hapNames += packinfo.name + ","; 525 } 526 } 527 528 int entriesNum = 0; 529 for (Enumeration<? extends ZipEntry> entries = zipFile.entries(); entries.hasMoreElements();) { 530 entriesNum++; 531 ZipEntry entry = entries.nextElement(); 532 String entryName = ""; 533 if (entry == null || entry.getName().isEmpty()) { 534 continue; 535 } 536 if (entry.getName().toLowerCase().endsWith(CUT_ENTRY_FILENAME) && 537 "false".equals(utility.getUnpackCutEntryApk())) { 538 continue; 539 } 540 entryName = entry.getName(); 541 if (!entryName.toLowerCase(Locale.ENGLISH).endsWith(suffix) || 542 (!hapNames.isEmpty() && !hapNames.contains(entryName.replace(suffix, "")))) { 543 continue; 544 } 545 String tempDir = destDirPath.replace(File.separator, LINUX_FILE_SEPARATOR); 546 if (HAP_SUFFIX.equals(suffix) && "true".equals(utility.getUnpackApk())) { 547 tempDir = tempDir + LINUX_FILE_SEPARATOR + entryName.replace(suffix, ""); 548 File destFileDir = new File(tempDir); 549 if (!destFileDir.exists()) { 550 destFileDir.mkdir(); 551 } 552 } 553 if (APK_SUFFIX.equals(suffix) && "true".equals(utility.getUnpackApk()) 554 && entryName.contains(LINUX_FILE_SEPARATOR)) { 555 // only unpack shell apk which in the root directory 556 continue; 557 } 558 String tempPath = tempDir + LINUX_FILE_SEPARATOR + entryName; 559 if (!FileUtils.matchPattern(tempPath)) { 560 throw new BundleException("Input invalid file " + tempPath); 561 } 562 File destFile = new File(tempPath); 563 dataTransfer(zipFile, entry, destFile); 564 if (JSON_SUFFIX.equals(suffix)) { 565 break; 566 } else if (HAP_SUFFIX.equals(suffix) && "true".equals(utility.getUnpackApk())) { 567 unzip(utility, tempPath, tempDir, APK_SUFFIX); 568 repackHap(tempPath, tempDir, entryName, utility.getUnpackApk()); 569 } 570 } 571 } catch (IOException | BundleException exception) { 572 LOG.error("Uncompress::unzipInHapMode failed: " + exception.getMessage()); 573 throw new BundleException("Unzip in hap mode failed"); 574 } finally { 575 Utility.closeStream(zipFile); 576 } 577 } 578 579 /** 580 * uncompress dataTransfer 581 * 582 * @param zipFile input zip file 583 * @param entry input file in zip 584 * @param destFile output file path 585 * @throws BundleException FileNotFoundException|IOException. 586 */ dataTransfer(ZipFile zipFile, ZipEntry entry, File destFile)587 private static void dataTransfer(ZipFile zipFile, ZipEntry entry, File destFile) throws BundleException { 588 InputStream fileInputStream = null; 589 FileOutputStream fileOutStream = null; 590 try { 591 if (!FileUtils.matchPattern(destFile.getCanonicalPath())) { 592 LOG.error("Input invalid file " + destFile); 593 throw new BundleException("Input invalid file" + destFile.getCanonicalPath()); 594 } 595 fileInputStream = zipFile.getInputStream(entry); 596 fileOutStream = new FileOutputStream(destFile); 597 byte[] data = new byte[BUFFER_SIZE]; 598 int count = fileInputStream.read(data); 599 int total = 0; 600 while (count > 0) { 601 fileOutStream.write(data, 0, count); 602 total += count; 603 count = fileInputStream.read(data); 604 } 605 } catch (IOException | BundleException exception) { 606 LOG.error("Uncompress::dataTransfer file " + exception.getMessage()); 607 throw new BundleException("DataTransfer failed"); 608 } finally { 609 Utility.closeStream(fileOutStream); 610 Utility.closeStream(fileInputStream); 611 } 612 } 613 614 /** 615 * uncompress dataTransfer all files. 616 * 617 * @param srcPath source file path 618 * @param destDirPath destination file path 619 * @throws BundleException FileNotFoundException|IOException. 620 */ dataTransferAllFiles(String srcPath, String destDirPath)621 private static void dataTransferAllFiles(String srcPath, String destDirPath) throws BundleException { 622 ZipFile zipFile = null; 623 try { 624 if (!FileUtils.matchPattern(srcPath)) { 625 throw new BundleException("Input invalid file " + srcPath); 626 } 627 zipFile = new ZipFile(new File(srcPath)); 628 int entriesNum = 0; 629 for (Enumeration<? extends ZipEntry> entries = zipFile.entries(); entries.hasMoreElements();) { 630 entriesNum++; 631 ZipEntry entry = entries.nextElement(); 632 if (entry == null) { 633 continue; 634 } 635 String tempPath = destDirPath + LINUX_FILE_SEPARATOR + entry.getName(); 636 File destFile = new File(tempPath); 637 if (destFile != null && destFile.getParentFile() != null && !destFile.getParentFile().exists()) { 638 destFile.getParentFile().mkdirs(); 639 } 640 dataTransfer(zipFile, entry, destFile); 641 } 642 } catch (FileNotFoundException ignored) { 643 LOG.error("Uncompress::unzipApk file not found exception"); 644 throw new BundleException("Unzip Apk failed"); 645 } catch (IOException exception) { 646 LOG.error("Uncompress::unzipApk io exception: " + exception.getMessage()); 647 throw new BundleException("Unzip Apk failed"); 648 } finally { 649 Utility.closeStream(zipFile); 650 } 651 } 652 dataTransferFilesByApp(Utility utility, String srcPath, String destDirPath)653 private static void dataTransferFilesByApp(Utility utility, String srcPath, String destDirPath) 654 throws BundleException { 655 ZipFile zipFile = null; 656 try { 657 zipFile = new ZipFile(new File(srcPath)); 658 int entriesNum = 0; 659 for (Enumeration<? extends ZipEntry> entries = zipFile.entries(); entries.hasMoreElements();) { 660 entriesNum++; 661 ZipEntry entry = entries.nextElement(); 662 if (entry == null) { 663 continue; 664 } 665 String filePath = destDirPath + LINUX_FILE_SEPARATOR + entry.getName(); 666 if (!FileUtils.matchPattern(filePath)) { 667 throw new BundleException("Input invalid path " + filePath); 668 } 669 File destFile = new File(filePath); 670 if (destFile != null && destFile.getParentFile() != null && !destFile.getParentFile().exists()) { 671 destFile.getParentFile().mkdirs(); 672 } 673 boolean isUnpackApk = "true".equals(utility.getUnpackApk()); 674 if (isUnpackApk && filePath.toLowerCase().endsWith(HAP_SUFFIX)) { 675 dataTransfer(zipFile, entry, destFile); 676 unzip(utility, filePath, destDirPath, APK_SUFFIX); 677 String[] temp = filePath.replace("\\", "/").split("/"); 678 String hapName = ""; 679 if (temp.length > 0) { 680 hapName = temp[temp.length - 1]; 681 } 682 repackHap(filePath, destDirPath, hapName, utility.getUnpackApk()); 683 } else { 684 dataTransfer(zipFile, entry, destFile); 685 } 686 } 687 } catch (IOException | BundleException exception) { 688 LOG.error("Uncompress::unzipApk file failed " + exception.getMessage()); 689 throw new BundleException("Unzip Apk failed"); 690 } finally { 691 Utility.closeStream(zipFile); 692 } 693 } 694 getResourceDataFromHap(ZipFile zipFile)695 private static byte[] getResourceDataFromHap(ZipFile zipFile) throws BundleException, IOException { 696 int entriesNum = 0; 697 InputStream indexInputStream = null; 698 try { 699 for (Enumeration<? extends ZipEntry> entries = zipFile.entries(); entries.hasMoreElements();) { 700 entriesNum++; 701 ZipEntry indexEntry = entries.nextElement(); 702 if (indexEntry == null) { 703 continue; 704 } 705 if (indexEntry != null && !"".equals(indexEntry.getName()) && 706 indexEntry.getName().toLowerCase().endsWith(RESOURCE_INDEX)) { 707 indexInputStream = zipFile.getInputStream(indexEntry); 708 return getByte(indexInputStream); 709 } 710 } 711 } finally { 712 Utility.closeStream(indexInputStream); 713 } 714 return null; 715 } 716 unZipHapFileFromHapFile(String srcPath)717 private static HapZipInfo unZipHapFileFromHapFile(String srcPath) 718 throws BundleException, IOException { 719 HapZipInfo hapZipInfo = new HapZipInfo(); 720 ZipFile zipFile = null; 721 if (!FileUtils.matchPattern(srcPath)) { 722 LOG.error("Input invalid path " + srcPath); 723 throw new BundleException("Input invalid path " + srcPath); 724 } 725 try { 726 File srcFile = new File(srcPath); 727 zipFile = new ZipFile(srcFile); 728 hapZipInfo.setHarmonyProfileJsonStr(FileUtils.getFileStringFromZip(HARMONY_PROFILE, zipFile)); 729 hapZipInfo.setResDataBytes(getResourceDataFromHap(zipFile)); 730 hapZipInfo.setPackInfoJsonStr(FileUtils.getFileStringFromZip(PACK_INFO, zipFile)); 731 hapZipInfo.setHapFileName(getHapNameWithoutSuffix(srcFile.getName())); 732 } finally { 733 Utility.closeStream(zipFile); 734 } 735 return hapZipInfo; 736 } 737 738 /** 739 * uncompress from specified file name 740 * 741 * @param deviceType device type 742 * @param srcPath source file path 743 * @param fileName uncompress file name 744 * @return the uncompress result 745 * @throws BundleException FileNotFoundException|IOException. 746 */ uncompress(String deviceType, String srcPath, String fileName)747 private static UncompressResult uncompress(String deviceType, String srcPath, String fileName) 748 throws BundleException { 749 if (srcPath.isEmpty() || fileName.isEmpty()) { 750 LOG.error("Uncompress::uncompress srcPath, fileName is empty!"); 751 throw new BundleException("Uncompress failed, srcPath or fileName is empty"); 752 } 753 754 UncompressResult result = new UncompressResult(); 755 try { 756 HapZipInfo hapZipInfo = unZipHapFileFromHapFile(srcPath); 757 if (isPackInfo(fileName)) { 758 uncompressPackInfo(deviceType, hapZipInfo, result); 759 } else { 760 uncompressProfileInfo(hapZipInfo, result); 761 } 762 } catch (IOException exception) { 763 LOG.error("Uncompress::uncompress io exception: " + exception.getMessage()); 764 throw new BundleException("Uncompress failed"); 765 } 766 return result; 767 } 768 uncompressPackInfo(String deviceType, HapZipInfo hapZipInfo, UncompressResult uncomperssResult)769 private static void uncompressPackInfo(String deviceType, HapZipInfo hapZipInfo, UncompressResult uncomperssResult) 770 throws BundleException { 771 List<PackInfo> packInfos = JsonUtil.parseHapList(deviceType, hapZipInfo.getPackInfoJsonStr()); 772 uncomperssResult.setPackInfoStr(hapZipInfo.getPackInfoJsonStr()); 773 uncomperssResult.setPackInfos(packInfos); 774 } 775 uncompressProfileInfo(HapZipInfo hapZipInfo, UncompressResult uncomperssResult)776 private static void uncompressProfileInfo(HapZipInfo hapZipInfo, UncompressResult uncomperssResult) 777 throws BundleException { 778 ProfileInfo profileInfo = JsonUtil.parseProfileInfo(hapZipInfo.getHarmonyProfileJsonStr(), 779 hapZipInfo.getResDataBytes(), hapZipInfo.getPackInfoJsonStr(), hapZipInfo.getHapFileName()); 780 profileInfo.hapName = hapZipInfo.getHapFileName(); 781 profileInfo.appInfo.setBundleType(getFABundleType(profileInfo)); 782 uncomperssResult.addProfileInfoStr(hapZipInfo.getHarmonyProfileJsonStr()); 783 uncomperssResult.addProfileInfo(profileInfo); 784 } 785 getFABundleType(ProfileInfo profileInfo)786 private static String getFABundleType(ProfileInfo profileInfo) { 787 String bundleType = "app"; 788 if (profileInfo.hapInfo.distro.installationFree == 1) { 789 bundleType = "atomicService"; 790 } 791 return bundleType; 792 } 793 unZipHapFileFromInputStream(InputStream input)794 private static HapZipInfo unZipHapFileFromInputStream(InputStream input) throws BundleException, IOException { 795 BufferedInputStream bufIn = null; 796 ZipInputStream zipIn = null; 797 BufferedReader bufferedReader = null; 798 HapZipInfo hapZipInfo = new HapZipInfo(); 799 try { 800 ZipEntry entry = null; 801 bufIn = new BufferedInputStream(input); 802 zipIn = new ZipInputStream(bufIn); 803 int entriesNum = 0; 804 while ((entry = zipIn.getNextEntry()) != null) { 805 entriesNum++; 806 if (entry.getName().toLowerCase().endsWith(RESOURCE_INDEX)) { 807 hapZipInfo.setResDataBytes(getByte(zipIn)); 808 continue; 809 } 810 if (isPackInfo(entry.getName())) { 811 bufferedReader = new BufferedReader(new InputStreamReader(zipIn)); 812 hapZipInfo.setPackInfoJsonStr(readStringFromInputStream(zipIn, bufferedReader)); 813 continue; 814 } 815 if (isHarmonyProfile(entry.getName())) { 816 bufferedReader = new BufferedReader(new InputStreamReader(zipIn)); 817 hapZipInfo.setHarmonyProfileJsonStr(readStringFromInputStream(zipIn, bufferedReader)); 818 } 819 } 820 } finally { 821 Utility.closeStream(bufferedReader); 822 Utility.closeStream(bufIn); 823 Utility.closeStream(zipIn); 824 } 825 return hapZipInfo; 826 } 827 readStringFromInputStream(ZipInputStream zipIn, BufferedReader bufferedReader)828 private static String readStringFromInputStream(ZipInputStream zipIn, BufferedReader bufferedReader) 829 throws IOException { 830 String line; 831 StringBuilder sb = new StringBuilder(); 832 while ((line = bufferedReader.readLine()) != null) { 833 sb.append(line); 834 } 835 return sb.toString(); 836 } 837 838 /** 839 * uncompress process by InputStream 840 * 841 * @param deviceType device type 842 * @param input the InputStream about the package. 843 * @param fileName uncompress file name 844 * @return the uncompress result 845 * @throws BundleException FileNotFoundException|IOException. 846 */ uncompressByInput(String deviceType, InputStream input, String fileName, String hapName)847 private static UncompressResult uncompressByInput(String deviceType, InputStream input, 848 String fileName, String hapName) throws BundleException { 849 UncompressResult result = new UncompressResult(); 850 try { 851 HapZipInfo hapZipInfo = unZipHapFileFromInputStream(input); 852 hapZipInfo.setHapFileName(hapName); 853 if (isPackInfo(fileName)) { 854 uncompressPackInfo(deviceType, hapZipInfo, result); 855 } else { 856 uncompressProfileInfo(hapZipInfo, result); 857 } 858 } catch (IOException exception) { 859 LOG.error("Uncompress::uncompressByInput io exception: " + exception.getMessage()); 860 throw new BundleException("Uncompress by input failed"); 861 } 862 return result; 863 } 864 865 /** 866 * uncompress process by InputStream 867 * 868 * @param deviceType device type 869 * @param input the InputStream about the package. 870 * @param fileName uncompress file name 871 * @return the module uncompress result 872 * @throws BundleException FileNotFoundException|IOException. 873 */ uncompressModuleByInput(String deviceType, InputStream input, String fileName, String hapName)874 private static ModuleResult uncompressModuleByInput(String deviceType, InputStream input, 875 String fileName, String hapName) throws BundleException { 876 ModuleResult result = new ModuleResult(); 877 try { 878 HapZipInfo hapZipInfo = unZipModuleHapFileFromInputStream(input); 879 hapZipInfo.setHapFileName(hapName); 880 if (isPackInfo(fileName)) { 881 // for parse app 882 } else { 883 uncompressModuleJsonInfo(hapZipInfo, result); 884 } 885 } catch (BundleException exception) { 886 LOG.error("Uncompress::uncompressByInput io exception: " + exception.getMessage()); 887 throw new BundleException("Uncompress by input failed"); 888 } 889 return result; 890 } 891 892 /** 893 * Get entry byte array. 894 * 895 * @param zis the InputStream about the entry. 896 * @return Return the entry byte array. 897 * @throws BundleException FileNotFoundException|IOException. 898 */ getByte(InputStream zis)899 private static byte[] getByte(InputStream zis) throws BundleException { 900 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 901 byte[] buf = null; 902 try { 903 byte[] temp = new byte[READ_BUFFER_SIZE]; 904 int length = 0; 905 906 while ((length = zis.read(temp, 0, READ_BUFFER_SIZE)) != -1) { 907 bos.write(temp, 0, length); 908 } 909 910 buf = bos.toByteArray(); 911 } catch (IOException e) { 912 LOG.error("Uncompress::getByte io exception: " + e.getMessage()); 913 throw new BundleException("Get byte failed"); 914 } finally { 915 Utility.closeStream(bos); 916 } 917 return buf; 918 } 919 920 /** 921 * repack hap 922 * 923 * @param srcPath source file path 924 * @param destDirPath destination file path 925 * @param fileName target file name 926 * @param unpackApk unpackApk flag 927 * @throws BundleException FileNotFoundException|IOException. 928 */ repackHap(String srcPath, String destDirPath, String fileName, String unpackApk)929 private static void repackHap(String srcPath, String destDirPath, String fileName, String unpackApk) 930 throws BundleException { 931 if (srcPath.isEmpty() || destDirPath.isEmpty() || fileName.isEmpty()) { 932 LOG.error("Uncompress::repackHap srcPath, destDirPath or fileName is empty!"); 933 throw new BundleException("Repack hap failed, srcPath, destDirPath or fileName is empty"); 934 } 935 936 if (!UncompressVerify.isPathValid(srcPath, true, "")) { 937 LOG.error("Uncompress::repackHap srcPath is invalid!"); 938 throw new BundleException("Repack hap failed, srcPath is invalid"); 939 } 940 941 if (!UncompressVerify.isPathValid(destDirPath, false, null)) { 942 LOG.error("Uncompress::repackHap destDirPath is invalid!"); 943 throw new BundleException("Repack hap failed, destDirPath is invalid"); 944 } 945 946 String tempDir = destDirPath.replace(File.separator, LINUX_FILE_SEPARATOR) + LINUX_FILE_SEPARATOR + 947 TEMP_PATH; 948 dataTransferAllFiles(srcPath, tempDir); 949 packFilesByPath(tempDir, destDirPath, fileName, unpackApk); 950 File deleteFile = new File(tempDir); 951 deleteFile(deleteFile); 952 } 953 954 /** 955 * compress file directory. 956 * 957 * @param srcPath source file path 958 * @param destDirPath destination file path 959 * @param fileName target file name 960 * @param unpackApk unpackApk flag 961 * @throws BundleException FileNotFoundException|IOException. 962 */ packFilesByPath(String srcPath, String destDirPath, String fileName, String unpackApk)963 private static void packFilesByPath(String srcPath, String destDirPath, String fileName, String unpackApk) 964 throws BundleException { 965 if (srcPath.isEmpty() || destDirPath.isEmpty() || fileName.isEmpty()) { 966 LOG.error("Uncompress::packFilesByPath srcPath, destDirPath or fileName is empty!"); 967 throw new BundleException("Pack files by path failed, srcPath, destDirPath or fileName is empty"); 968 } 969 970 if (!UncompressVerify.isPathValid(srcPath, false, null) || 971 !UncompressVerify.isPathValid(destDirPath, false, null)) { 972 LOG.error("Uncompress::packFilesByPath srcPath or destDirPath is invalid!"); 973 throw new BundleException("Pack files by path failed, srcPath or destDirPath is invalid"); 974 } 975 976 File srcDir = new File(srcPath); 977 File[] srcFiles = srcDir.listFiles(); 978 if (srcFiles == null) { 979 return; 980 } 981 FileOutputStream fileOut = null; 982 CheckedOutputStream checkedOut = null; 983 ZipOutputStream zipOut = null; 984 985 try { 986 String zipPath = destDirPath + LINUX_FILE_SEPARATOR + fileName; 987 if (!FileUtils.matchPattern(zipPath)) { 988 throw new BundleException("Input invalid file" + zipPath); 989 } 990 File zipFile = new File(zipPath); 991 fileOut = new FileOutputStream(zipFile); 992 checkedOut = new CheckedOutputStream(fileOut, new CRC32()); 993 zipOut = new ZipOutputStream(checkedOut); 994 for (int i = 0; i < srcFiles.length; i++) { 995 File srcFile = srcFiles[i]; 996 if (srcFile.isDirectory()) { 997 if (srcFile.getPath().toLowerCase(Locale.ENGLISH).endsWith(LIBS_DIR_NAME)) { 998 compressDirectory(srcFile, "", zipOut, true); 999 } else { 1000 compressDirectory(srcFile, "", zipOut, false); 1001 } 1002 } else { 1003 if (srcFile.getPath().toLowerCase(Locale.ENGLISH).endsWith(APK_SUFFIX) && 1004 "true".equals(unpackApk)) { 1005 continue; 1006 } 1007 compressFile(srcFile, "", zipOut, false); 1008 } 1009 } 1010 } catch (FileNotFoundException | BundleException exception) { 1011 LOG.error("Uncompress::packFilesByPath " + exception.getMessage()); 1012 throw new BundleException("Pack files by path failed"); 1013 } finally { 1014 Utility.closeStream(zipOut); 1015 Utility.closeStream(checkedOut); 1016 Utility.closeStream(fileOut); 1017 } 1018 } 1019 1020 /** 1021 * compress file directory. 1022 * 1023 * @param dir file directory 1024 * @param baseDir base path for file 1025 * @param zipOut zip outPutStream 1026 * @param isCompression if need compression 1027 * @throws BundleException FileNotFoundException|IOException. 1028 */ compressDirectory(File dir, String baseDir, ZipOutputStream zipOut, boolean isCompression)1029 private static void compressDirectory(File dir, String baseDir, ZipOutputStream zipOut, boolean isCompression) 1030 throws BundleException { 1031 File[] files = dir.listFiles(); 1032 if (files == null) { 1033 return; 1034 } 1035 for (File file : files) { 1036 if (file.isDirectory()) { 1037 compressDirectory(file, baseDir + dir.getName() + File.separator, zipOut, isCompression); 1038 } else { 1039 compressFile(file, baseDir + dir.getName() + File.separator, zipOut, isCompression); 1040 } 1041 } 1042 } 1043 1044 /** 1045 * compress process. 1046 * 1047 * @param srcFile source file to zip 1048 * @param baseDir base path for file 1049 * @param zipOut zip outPutStream 1050 * @param isCompression if need compression 1051 * @throws BundleException FileNotFoundException|IOException. 1052 */ compressFile(File srcFile, String baseDir, ZipOutputStream zipOut, boolean isCompression)1053 private static void compressFile(File srcFile, String baseDir, ZipOutputStream zipOut, boolean isCompression) 1054 throws BundleException { 1055 FileInputStream fileInputStream = null; 1056 BufferedInputStream bufferedInputStream = null; 1057 1058 try { 1059 String entryName = (baseDir + srcFile.getName()).replace(File.separator, LINUX_FILE_SEPARATOR); 1060 ZipEntry zipEntry = new ZipEntry(entryName); 1061 boolean isNeedCompress = isCompression; 1062 if (srcFile.isFile() && srcFile.getName().toLowerCase(Locale.ENGLISH).endsWith(SO_SUFFIX)) { 1063 isNeedCompress = false; 1064 } 1065 if (isNeedCompress) { 1066 zipEntry.setMethod(ZipEntry.DEFLATED); 1067 } else { 1068 zipEntry.setMethod(ZipEntry.STORED); 1069 zipEntry.setCompressedSize(srcFile.length()); 1070 zipEntry.setSize(srcFile.length()); 1071 CRC32 crc = getCrcFromFile(srcFile); 1072 zipEntry.setCrc(crc.getValue()); 1073 } 1074 FileTime fileTime = FileTime.fromMillis(FILE_TIME); 1075 zipEntry.setLastAccessTime(fileTime); 1076 zipEntry.setLastModifiedTime(fileTime); 1077 zipOut.putNextEntry(zipEntry); 1078 byte[] data = new byte[BUFFER_SIZE]; 1079 fileInputStream = new FileInputStream(srcFile); 1080 bufferedInputStream = new BufferedInputStream(fileInputStream); 1081 int count = bufferedInputStream.read(data); 1082 while (count > 0) { 1083 zipOut.write(data, 0, count); 1084 count = bufferedInputStream.read(data); 1085 } 1086 } catch (FileNotFoundException ignored) { 1087 LOG.error("Uncompress::compressFile file not found exception"); 1088 throw new BundleException("Compress file failed"); 1089 } catch (IOException exception) { 1090 LOG.error("Uncompress::compressFile io exception: " + exception.getMessage()); 1091 throw new BundleException("Compress file failed"); 1092 } finally { 1093 Utility.closeStream(fileInputStream); 1094 Utility.closeStream(bufferedInputStream); 1095 } 1096 } 1097 1098 /** 1099 * get CRC32 from file. 1100 * 1101 * @param file source file 1102 * @return CRC32 1103 * @throws BundleException FileNotFoundException|IOException. 1104 */ getCrcFromFile(File file)1105 private static CRC32 getCrcFromFile(File file) throws BundleException { 1106 FileInputStream fileInputStream = null; 1107 CRC32 crc = new CRC32(); 1108 try { 1109 fileInputStream = new FileInputStream(file); 1110 byte[] buffer = new byte[BUFFER_SIZE]; 1111 1112 int count = fileInputStream.read(buffer); 1113 while (count > 0) { 1114 crc.update(buffer, 0, count); 1115 count = fileInputStream.read(buffer); 1116 } 1117 } catch (FileNotFoundException ignored) { 1118 LOG.error("Uncompressor::getCrcFromFile file not found exception"); 1119 throw new BundleException("Get Crc from file failed"); 1120 } catch (IOException exception) { 1121 LOG.error("Uncompressor::getCrcFromFile io exception: " + exception.getMessage()); 1122 throw new BundleException("Get Crc from file failed"); 1123 } finally { 1124 Utility.closeStream(fileInputStream); 1125 } 1126 return crc; 1127 } 1128 1129 /** 1130 * delete file 1131 * 1132 * @param file the file to be deleted 1133 */ deleteFile(File file)1134 private static void deleteFile(File file) { 1135 if (file.exists()) { 1136 if (file.isDirectory()) { 1137 File[] files = file.listFiles(); 1138 for (int i = 0; i < files.length; i++) { 1139 deleteFile(files[i]); 1140 } 1141 } 1142 file.delete(); 1143 } 1144 } 1145 1146 /** 1147 * check 1148 * 1149 * @param result the result of parse app all mode 1150 * @return return the result of checkParseAllResult. 1151 */ checkParseAllResult(UncompressResult result)1152 private static UncompressResult checkParseAllResult(UncompressResult result) { 1153 UncompressResult errorResult = new UncompressResult(); 1154 errorResult.setResult(false); 1155 errorResult.setMessage("App package is invalid."); 1156 if (result == null || result.getPackInfos() == null || result.getProfileInfos() == null) { 1157 return errorResult; 1158 } 1159 1160 List<PackInfo> packInfos = result.getPackInfos(); 1161 List<ProfileInfo> profileInfos = result.getProfileInfos(); 1162 int packInfoSize = packInfos.size(); 1163 int profileInfoSize = profileInfos.size(); 1164 if (packInfoSize == 0 || profileInfoSize == 0 || packInfoSize != profileInfoSize) { 1165 LOG.error("Uncompress::checkParseAllResult error, hapNum is invalid in app"); 1166 return errorResult; 1167 } 1168 1169 for (int i = 0; i < packInfoSize; i++) { 1170 if (packInfos.get(i) == null || packInfos.get(i).name.isEmpty()) { 1171 return errorResult; 1172 } 1173 boolean isHave = false; 1174 for (int j = 0; j < profileInfoSize; j++) { 1175 if (profileInfos.get(j) == null || profileInfos.get(j).hapName.isEmpty()) { 1176 return errorResult; 1177 } 1178 if (profileInfos.get(j).hapName.replace(HAP_SUFFIXI, "") 1179 .equals(packInfos.get(i).name.replace(HAP_SUFFIXI, ""))) { 1180 isHave = true; 1181 break; 1182 } 1183 } 1184 if (!isHave) { 1185 return errorResult; 1186 } 1187 } 1188 1189 return result; 1190 } 1191 1192 /** 1193 * get label and icon for application 1194 * 1195 * @param result the result of parse app all mode 1196 * @return return the result which contains icon and label 1197 */ obtainLabelAndIcon(UncompressResult result)1198 private static UncompressResult obtainLabelAndIcon(UncompressResult result) { 1199 List<ProfileInfo> profileInfos = result.getProfileInfos(); 1200 if (profileInfos.isEmpty()) { 1201 return result; 1202 } 1203 for (ProfileInfo profileInfo : profileInfos) { 1204 if (profileInfo == null) { 1205 continue; 1206 } 1207 HapInfo hapInfo = profileInfo.hapInfo; 1208 if (hapInfo == null) { 1209 continue; 1210 } 1211 Distro distro = hapInfo.distro; 1212 if (distro == null) { 1213 continue; 1214 } 1215 String moduleType = distro.moduleType; 1216 if (ENTRY_TYPE.equals(moduleType.toLowerCase(Locale.ENGLISH))) { 1217 return obtainInnerLabelAndIcon(result, hapInfo, distro); 1218 } 1219 } 1220 return result; 1221 } 1222 1223 /** 1224 * get label and icon for application 1225 * 1226 * @param result the result of parse app all mode 1227 * @param hapInfo hap info of entry hap 1228 * @return return the result which contains icon and label 1229 */ obtainInnerLabelAndIcon(UncompressResult result, HapInfo hapInfo, Distro distro)1230 private static UncompressResult obtainInnerLabelAndIcon(UncompressResult result, HapInfo hapInfo, Distro distro) { 1231 List<AbilityInfo> abilities = hapInfo.abilities; 1232 if ((abilities == null) || (abilities.isEmpty())) { 1233 result.setLabel(distro.moduleName); 1234 return result; 1235 } 1236 int size = 0; 1237 for (AbilityInfo info : abilities) { 1238 if (info == null) { 1239 size++; 1240 continue; 1241 } 1242 if ((info.skills == null) || (info.skills.isEmpty())) { 1243 continue; 1244 } 1245 for (SkillInfo skill : info.skills) { 1246 if (skill == null) { 1247 continue; 1248 } 1249 List<String> actions = skill.actions; 1250 List<String> entities = skill.entities; 1251 if ((!actions.isEmpty()) && (actions.contains(SYSTEM_ACTION) || actions.contains(SYSTEM_WANT_HOME)) 1252 && (!entities.isEmpty()) && (entities.contains(SYSTEM_ENTITY))) { 1253 result.setLabel(info.label); 1254 result.setIcon(info.icon); 1255 return result; 1256 } 1257 } 1258 } 1259 if (size == abilities.size()) { 1260 result.setLabel(distro.moduleName); 1261 return result; 1262 } 1263 for (AbilityInfo info : abilities) { 1264 if (info != null) { 1265 result.setLabel(info.label); 1266 result.setIcon(info.icon); 1267 break; 1268 } 1269 } 1270 return result; 1271 } 1272 1273 isHarmonyProfile(String fileName)1274 private static boolean isHarmonyProfile(String fileName) { 1275 return HARMONY_PROFILE.equals(fileName); 1276 } 1277 isPackInfo(String fileName)1278 private static boolean isPackInfo(String fileName) { 1279 return PACK_INFO.equals(fileName); 1280 } 1281 getHapNameWithoutSuffix(String hapFileName)1282 private static String getHapNameWithoutSuffix(String hapFileName) { 1283 if (hapFileName == null || hapFileName.isEmpty() || hapFileName.lastIndexOf(".") == -1) { 1284 return ""; 1285 } 1286 return hapFileName.substring(0, hapFileName.lastIndexOf(".")); 1287 } 1288 unZipModuleHapFile(String srcPath)1289 private static HapZipInfo unZipModuleHapFile(String srcPath) 1290 throws BundleException, IOException { 1291 HapZipInfo hapZipInfo = new HapZipInfo(); 1292 ZipFile zipFile = null; 1293 try { 1294 File srcFile = new File(srcPath); 1295 zipFile = new ZipFile(srcFile); 1296 getProfileJson(zipFile, hapZipInfo.resourcemMap); 1297 hapZipInfo.setHarmonyProfileJsonStr(FileUtils.getFileStringFromZip(MODULE_JSON, zipFile)); 1298 hapZipInfo.setPackInfoJsonStr(FileUtils.getFileStringFromZip(PACK_INFO, zipFile)); 1299 hapZipInfo.setResDataBytes(getResourceDataFromHap(zipFile)); 1300 hapZipInfo.setHapFileName(getHapNameWithoutSuffix(srcFile.getName())); 1301 } finally { 1302 Utility.closeStream(zipFile); 1303 } 1304 return hapZipInfo; 1305 } 1306 1307 /** 1308 * uncompress from HapZipInfo 1309 * 1310 * @param hapZipInfo hap zip info 1311 * @return the parse moduleResult 1312 * @throws BundleException FileNotFoundException|IOException. 1313 */ uncompressModuleJsonInfo(HapZipInfo hapZipInfo, ModuleResult moduleResult)1314 private static void uncompressModuleJsonInfo(HapZipInfo hapZipInfo, ModuleResult moduleResult) 1315 throws BundleException { 1316 ModuleProfileInfo moduleProfileInfo = JsonUtil.parseModuleProfileInfo(hapZipInfo.getHarmonyProfileJsonStr(), 1317 hapZipInfo.getResDataBytes(), hapZipInfo.getPackInfoJsonStr(), hapZipInfo.getHapFileName(), 1318 hapZipInfo.resourcemMap); 1319 moduleProfileInfo.hapName = hapZipInfo.getHapFileName(); 1320 moduleResult.addModuleProfileInfo(moduleProfileInfo); 1321 moduleResult.moduleProfileStr.add(hapZipInfo.getHarmonyProfileJsonStr()); 1322 } 1323 1324 /** 1325 * uncompress from specified file name 1326 * 1327 * @param deviceType device type 1328 * @param srcPath source file path 1329 * @param fileName uncompress file name 1330 * @return the uncompress result 1331 * @throws BundleException FileNotFoundException|IOException. 1332 */ uncompressModule(String deviceType, String srcPath, String fileName)1333 private static ModuleResult uncompressModule(String deviceType, String srcPath, String fileName) 1334 throws BundleException { 1335 if (srcPath.isEmpty() || fileName.isEmpty()) { 1336 LOG.error("Uncompress::uncompressModule srcPath, fileName is empty!"); 1337 throw new BundleException("uncompressModule failed, srcPath or fileName is empty"); 1338 } 1339 ModuleResult moduleResult = new ModuleResult(); 1340 try { 1341 HapZipInfo hapZipInfo = unZipModuleHapFile(srcPath); 1342 uncompressModuleJsonInfo(hapZipInfo, moduleResult); 1343 if (moduleResult.packInfos.isEmpty() && !hapZipInfo.getPackInfoJsonStr().isEmpty()) { 1344 moduleResult.packInfos = JsonUtil.parsePackInfos(hapZipInfo.getPackInfoJsonStr()); 1345 } 1346 } catch (IOException exception) { 1347 moduleResult.setResult(false); 1348 LOG.error("Uncompress::uncompressModule parseMode is invalid!"); 1349 } 1350 return moduleResult; 1351 } 1352 1353 /** 1354 * uncompress module hap. 1355 * 1356 * @param deviceType indicates the device type of uncompress mode. 1357 * @param srcPath indicates the path type of hap. 1358 * @param fileName indicates json file name. 1359 * @return the uncompress result 1360 */ unCompressModuleHap(String deviceType, String srcPath, String fileName)1361 static UncompressResult unCompressModuleHap(String deviceType, String srcPath, String fileName) 1362 throws BundleException{ 1363 if (srcPath.isEmpty() || fileName.isEmpty()) { 1364 LOG.error("Uncompress::uncompress srcPath, fileName is empty!"); 1365 throw new BundleException("Uncompress failed, srcPath or fileName is empty"); 1366 } 1367 UncompressResult uncomperssResult = new UncompressResult(); 1368 ModuleResult moduleResult = new ModuleResult(); 1369 try { 1370 moduleResult = uncompressModule(deviceType, srcPath, fileName); 1371 ModuleAdaption moduleAdaption = new ModuleAdaption(); 1372 uncomperssResult = moduleAdaption.convertToUncompressResult(moduleResult); 1373 } catch (BundleException ignored) { 1374 LOG.error("Uncompress::uncompressHap Bundle exception"); 1375 uncomperssResult.setResult(false); 1376 uncomperssResult.setMessage("uncompressHap Bundle exception"); 1377 } 1378 return uncomperssResult; 1379 } 1380 /** 1381 * get all resource in profile. 1382 * 1383 * @param zipFile is the hap file 1384 * @return the parse resource result 1385 */ getProfileJson(ZipFile zipFile, HashMap<String, String> resourceMap)1386 static void getProfileJson(ZipFile zipFile, HashMap<String, String> resourceMap) throws BundleException { 1387 try { 1388 final Enumeration<? extends ZipEntry> entries = zipFile.entries(); 1389 while (entries.hasMoreElements()) { 1390 final ZipEntry entry = entries.nextElement(); 1391 if (entry.getName().contains(RESOURCE_PATH)) { 1392 String filePath = entry.getName(); 1393 String fileName = filePath.replaceAll(RESOURCE_PATH, ""); 1394 String fileContent = FileUtils.getFileStringFromZip(filePath, zipFile); 1395 resourceMap.put(fileName, fileContent); 1396 } 1397 } 1398 } catch (IOException e) { 1399 LOG.error("Uncompress::getProfileJson IOException"); 1400 throw new BundleException("Uncompress::getProfileJson failed"); 1401 } 1402 } 1403 1404 /** 1405 * uncompress module hap. 1406 * 1407 * @param deviceType indicates the deviceType of parse hap. 1408 * @param input the InputStream about the app package. 1409 * @param fileName the file name of json file. 1410 * @return the uncompress result 1411 */ uncompressModuleHapByInput(String deviceType, InputStream input, String fileName, String hapName)1412 static UncompressResult uncompressModuleHapByInput(String deviceType, 1413 InputStream input, String fileName, String hapName) { 1414 UncompressResult uncompressResult = new UncompressResult(); 1415 ModuleResult moduleResult = new ModuleResult(); 1416 try { 1417 moduleResult = uncompressModuleByInput(deviceType, input, MODULE_JSON, hapName); 1418 ModuleAdaption moduleAdaption = new ModuleAdaption(); 1419 uncompressResult = moduleAdaption.convertToUncompressResult(moduleResult); 1420 } catch (BundleException ignored) { 1421 LOG.error("Uncompress::uncompressHapByInput Bundle exception"); 1422 uncompressResult.setResult(false); 1423 uncompressResult.setMessage("uncompressHapByInput Bundle exception"); 1424 } 1425 return uncompressResult; 1426 } 1427 1428 /** 1429 * unzip module hap from zip file. 1430 * 1431 * @param input Indicates the InputStream about the package. 1432 * @return Return the uncomperss result of parseHap 1433 */ unZipModuleHapFileFromInputStream(InputStream input)1434 private static HapZipInfo unZipModuleHapFileFromInputStream(InputStream input) throws BundleException { 1435 BufferedInputStream bufIn = null; 1436 ZipInputStream zipIn = null; 1437 BufferedReader bufferedReader = null; 1438 HapZipInfo hapZipInfo = new HapZipInfo(); 1439 try { 1440 ZipEntry entry = null; 1441 bufIn = new BufferedInputStream(input); 1442 zipIn = new ZipInputStream(bufIn); 1443 while ((entry = zipIn.getNextEntry()) != null) { 1444 if (entry.getName().toLowerCase().endsWith(RESOURCE_INDEX)) { 1445 hapZipInfo.setResDataBytes(getByte(zipIn)); 1446 continue; 1447 } 1448 if (isPackInfo(entry.getName())) { 1449 bufferedReader = new BufferedReader(new InputStreamReader(zipIn)); 1450 hapZipInfo.setPackInfoJsonStr(readStringFromInputStream(zipIn, bufferedReader)); 1451 continue; 1452 } 1453 if (MODULE_JSON.equals(entry.getName())) { 1454 bufferedReader = new BufferedReader(new InputStreamReader(zipIn)); 1455 hapZipInfo.setHarmonyProfileJsonStr(readStringFromInputStream(zipIn, bufferedReader)); 1456 } 1457 if (entry.getName().contains(RESOURCE_PATH)) { 1458 bufferedReader = new BufferedReader(new InputStreamReader(zipIn)); 1459 String filePath = entry.getName(); 1460 String fileName = filePath.replaceAll(RESOURCE_PATH, ""); 1461 String fileContent = readStringFromInputStream(zipIn, bufferedReader); 1462 hapZipInfo.pushResourceMap(fileName, fileContent); 1463 } 1464 } 1465 } catch (BundleException | IOException e) { 1466 LOG.error("unZipModuleHapFileFromInputStream failed!"); 1467 throw new BundleException("unZipModuleHapFileFromInputStream failed!"); 1468 } finally { 1469 Utility.closeStream(bufferedReader); 1470 Utility.closeStream(bufIn); 1471 Utility.closeStream(zipIn); 1472 } 1473 return hapZipInfo; 1474 } 1475 1476 /** 1477 * Parse the hap type. 1478 * 1479 * @param hapPath Indicates the hap path. 1480 * @param compressResult Indicates the result of parse hap. 1481 * @return Return the type result of isModuleHap 1482 */ isModuleHap(String hapPath, UncompressResult compressResult)1483 public static boolean isModuleHap(String hapPath, UncompressResult compressResult) { 1484 ZipFile zipFile = null; 1485 try { 1486 zipFile = new ZipFile(new File(hapPath)); 1487 final Enumeration<? extends ZipEntry> entries = zipFile.entries(); 1488 while (entries.hasMoreElements()) { 1489 final ZipEntry entry = entries.nextElement(); 1490 if (MODULE_JSON.equals(entry.getName())) { 1491 return true; 1492 } 1493 } 1494 } catch (FileNotFoundException ignored) { 1495 LOG.error("Uncompress::isModuleHap file not found exception"); 1496 compressResult.setResult(false); 1497 compressResult.setMessage("judge is module failed"); 1498 } catch (IOException exception) { 1499 LOG.error("Uncompress::isModuleHap io exception: " + exception.getMessage()); 1500 compressResult.setResult(false); 1501 compressResult.setMessage("judge is module failed"); 1502 } finally { 1503 Utility.closeStream(zipFile); 1504 } 1505 return false; 1506 } 1507 1508 /** 1509 * Parse the hap type. 1510 * 1511 * @param input Indicates the hap FileInputStream. 1512 * @return Return the type result of isModuleHap. 1513 */ isModuleInput(InputStream input)1514 public static boolean isModuleInput(InputStream input) throws BundleException { 1515 BufferedInputStream bufIn = null; 1516 ZipInputStream zipIn = null; 1517 BufferedReader bufferedReader = null; 1518 try { 1519 ZipEntry entry = null; 1520 bufIn = new BufferedInputStream(input); 1521 zipIn = new ZipInputStream(bufIn); 1522 while((entry = zipIn.getNextEntry()) != null) { 1523 if (entry.getName().toLowerCase().endsWith(MODULE_JSON)) { 1524 return true; 1525 } 1526 } 1527 } catch (IOException ignored) { 1528 LOG.error("Uncompress::isModuleHap judge failed!"); 1529 throw new BundleException("Uncompress::isModuleHap judge failed!"); 1530 } finally { 1531 Utility.closeStream(bufferedReader); 1532 Utility.closeStream(bufIn); 1533 Utility.closeStream(zipIn); 1534 } 1535 return false; 1536 } 1537 1538 /** 1539 * create file output stream from InputStream . 1540 * 1541 * @param stream Indicates the input stream of hap. 1542 * @param file Indicates the temp file to save input stream. 1543 */ writeToTempFile(InputStream stream, File file)1544 static void writeToTempFile(InputStream stream, File file) throws BundleException { 1545 FileOutputStream fileOutputStream = null; 1546 try { 1547 if (file == null) { 1548 LOG.error("file not exist!"); 1549 } 1550 fileOutputStream = new FileOutputStream(file); 1551 int bytesRead = 0; 1552 byte[] buffer = new byte[1024]; 1553 while ((bytesRead = stream.read(buffer)) != -1) { 1554 fileOutputStream.write(buffer, 0, bytesRead); 1555 } 1556 } catch (IOException e) { 1557 LOG.error("writeToTempFile failed!"); 1558 throw new BundleException("writeToTempFile failed!"); 1559 } finally { 1560 Utility.closeStream(fileOutputStream); 1561 } 1562 } 1563 1564 /** 1565 * copy rpcid.sc file. 1566 * 1567 * @param srcFile Indicates the path of hap. 1568 * @param rpcidPath Indicates the output path of rpcid.sc file. 1569 */ getRpcidFromHap(String srcFile, String rpcidPath)1570 static void getRpcidFromHap(String srcFile, String rpcidPath) throws BundleException { 1571 ZipFile zipFile = null; 1572 InputStream inputStream = null; 1573 FileOutputStream outputStream = null; 1574 try { 1575 zipFile = new ZipFile(srcFile); 1576 String filePath = null; 1577 final Enumeration<? extends ZipEntry> entries = zipFile.entries(); 1578 while (entries.hasMoreElements()) { 1579 final ZipEntry entry = entries.nextElement(); 1580 if (RPCID_SC.equals(entry.getName())) { 1581 filePath = entry.getName(); 1582 break; 1583 } 1584 } 1585 if (filePath != null) { 1586 File rpcidFile = new File(rpcidPath, RPCID_SC); 1587 if (rpcidFile.getParentFile() != null && !rpcidFile.getParentFile().exists()) { 1588 rpcidFile.getParentFile().mkdirs(); 1589 } 1590 ZipEntry rpcidEntry = zipFile.getEntry(filePath); 1591 inputStream = zipFile.getInputStream(rpcidEntry); 1592 byte[] buffer = new byte[1024]; 1593 int noBytes = 0; 1594 outputStream = new FileOutputStream(rpcidFile); 1595 while((noBytes = inputStream.read(buffer)) != -1) { 1596 outputStream.write(buffer, 0, noBytes); 1597 } 1598 } else { 1599 LOG.error("Uncompress::getRpcidFromHap hap has no rpcid.sc file"); 1600 throw new BundleException("Uncompress::getRpcidFromHap hap has no rpcid.sc file"); 1601 } 1602 } catch (IOException e) { 1603 LOG.error("Uncompress::getRpcidFromHap IOException " + e.getMessage()); 1604 throw new BundleException("Uncompress::getRpcidFromHap failed"); 1605 } finally { 1606 Utility.closeStream(zipFile); 1607 Utility.closeStream(inputStream); 1608 Utility.closeStream(outputStream); 1609 } 1610 } 1611 1612 /** 1613 * parse resource.index file. 1614 * 1615 * @param srcPath Indicates the path of hap. 1616 */ getResourceFromHap(String srcPath)1617 static List<ResourceIndexResult> getResourceFromHap(String srcPath) throws BundleException, IOException { 1618 ZipFile zipFile = null; 1619 try { 1620 File srcFile = new File(srcPath); 1621 zipFile = new ZipFile(srcFile); 1622 byte[] data = getResourceDataFromHap(zipFile); 1623 return ResourcesParser.getAllDataItem(data); 1624 } finally { 1625 Utility.closeStream(zipFile); 1626 } 1627 } 1628 1629 /** 1630 * uncompress appqf file. 1631 * 1632 * @param utility is the common args for input. 1633 * @throws BundleException if uncompress failed. 1634 */ uncompressAPPQFFile(Utility utility)1635 private static void uncompressAPPQFFile(Utility utility) throws BundleException { 1636 ZipFile zipFile = null; 1637 try { 1638 zipFile = new ZipFile(new File(utility.getAPPQFPath())); 1639 int entriesNum = 0; 1640 for (Enumeration<? extends ZipEntry> entries = zipFile.entries(); entries.hasMoreElements();) { 1641 entriesNum++; 1642 ZipEntry entry = entries.nextElement(); 1643 if (entry == null) { 1644 continue; 1645 } 1646 String filePath = utility.getOutPath() + File.separator + entry.getName(); 1647 if (!FileUtils.matchPattern(filePath)) { 1648 LOG.error("uncompressAPPQFFile: Input invalid file" + filePath); 1649 throw new BundleException("uncompressAPPQFFile: Input invalid file" + filePath); 1650 } 1651 File destFile = new File(filePath); 1652 if (destFile != null && destFile.getParentFile() != null && !destFile.getParentFile().exists()) { 1653 destFile.getParentFile().mkdirs(); 1654 } 1655 dataTransfer(zipFile, entry, destFile); 1656 } 1657 } catch (FileNotFoundException ignored) { 1658 LOG.error("Uncompress::uncompressAPPQFFile file not found exception"); 1659 throw new BundleException("Uncompress::uncompressAPPQFFile file not found"); 1660 } catch (IOException exception) { 1661 LOG.error("Uncompress::uncompressAPPQFFile io exception"); 1662 throw new BundleException("Uncompress::uncompressAPPQFFile io exception"); 1663 } finally { 1664 Utility.closeStream(zipFile); 1665 } 1666 } 1667 1668 /** 1669 * parse appqf file, . 1670 * 1671 * @param appqfPath is the path of appqf file. 1672 * @throws BundleException if uncompress failed. 1673 * @throws IOException if IOException happened. 1674 */ parseAPPQFFile(String appqfPath)1675 public static List<HQFInfo> parseAPPQFFile(String appqfPath) throws BundleException { 1676 List<String> patchList = new ArrayList<>(); 1677 ZipFile zipFile = null; 1678 InputStream stream = null; 1679 ZipInputStream zipInputStream = null; 1680 try { 1681 zipFile = new ZipFile(appqfPath); 1682 Enumeration<? extends ZipEntry> entries = zipFile.entries(); 1683 while (entries.hasMoreElements()) { 1684 ZipEntry appqfEntry = entries.nextElement(); 1685 stream = zipFile.getInputStream(appqfEntry); 1686 if (!appqfEntry.getName().endsWith(HQF_SUFFIX)) { 1687 continue; 1688 } 1689 zipInputStream = new ZipInputStream(stream); 1690 String patchJson = readPatchJson(zipInputStream); 1691 if (patchJson == null) { 1692 continue; 1693 } 1694 patchList.add(patchJson); 1695 } 1696 } catch (IOException e) { 1697 LOG.error("parseAPPQFFile failed!"); 1698 throw new BundleException("parseAPPQFFile failed!"); 1699 } finally { 1700 Utility.closeStream(zipFile); 1701 Utility.closeStream(stream); 1702 Utility.closeStream(zipInputStream); 1703 } 1704 return parsePatchJson(patchList); 1705 } 1706 readPatchJson(ZipInputStream zipInputStream)1707 private static String readPatchJson(ZipInputStream zipInputStream) throws BundleException { 1708 String patchJson = null; 1709 ZipEntry hqfEntry; 1710 try { 1711 while ((hqfEntry = zipInputStream.getNextEntry()) != null) { 1712 if (!PATCH_JSON.equals(hqfEntry.getName())) { 1713 continue; 1714 } 1715 patchJson = new BufferedReader(new InputStreamReader(zipInputStream, 1716 StandardCharsets.UTF_8)).lines().parallel() 1717 .collect(Collectors.joining(System.lineSeparator())); 1718 } 1719 } catch (IOException e) { 1720 LOG.error("readPatchJson failed!"); 1721 throw new BundleException("readPatchJson failed!"); 1722 } 1723 return patchJson; 1724 } 1725 parsePatchJson(List<String> patchList)1726 private static List<HQFInfo> parsePatchJson(List<String> patchList) throws BundleException { 1727 List<HQFInfo> hqfInfoList = new ArrayList<>(); 1728 for (String patchJson : patchList) { 1729 hqfInfoList.add(JsonUtil.parsePatch(patchJson)); 1730 } 1731 return hqfInfoList; 1732 } 1733 } 1734