• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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