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