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