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