• 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                         LOG.error("Compressor::compressProcess compress pack.res failed, moduleName "
1219                             + moduleName + " is error, please check it in config.json.");
1220                         throw new BundleException("Compress pack.res failed, moduleName Error.");
1221                     }
1222                     String fileLanguageCountryName = temp[temp.length - 3];
1223                     if (!isThirdLevelDirectoryNameValid(fileLanguageCountryName)) {
1224                         LOG.error("Compressor::compressProcess compress failed third level directory name: "
1225                             + fileLanguageCountryName + " is invalid, please check it with reference to this example: "
1226                             + "zh_Hani_CN-vertical-car-mdpi-dark or zh_Hani_CN-vertical-car-mdpi.");
1227                         throw new BundleException("Compress failed third level directory name Error.");
1228                     }
1229                     String filePicturingName = temp[temp.length - 1];
1230                     if (!isPicturing(filePicturingName, utility)) {
1231                         LOG.error("Compressor::compressProcess Compress pack.res failed, Invalid resource file" +
1232                             " name: " + filePicturingName + ", correct format example is formName-2x2.png.");
1233                         throw new BundleException("Compress pack.res failed, Invalid resource file name: "
1234                             + filePicturingName + ", correct format example is formName-2x2.png.");
1235                     }
1236 
1237                 } else {
1238                     LOG.error("Compressor::compressProcess compress failed No image in PNG format is found.");
1239                     throw new BundleException("Compress pack.res failed, compress failed No image in"
1240                         + " PNG format is found.");
1241                 }
1242             }
1243             pathToFile(utility, utility.getEntryCardPath(), ENTRYCARD_NAME, false);
1244         }
1245     }
1246 
1247     /**
1248      * Check whether modelname meets specifications.
1249      *
1250      * @param name modelName
1251      * @return false and true
1252      */
isModelName(String name)1253     private boolean isModelName(String name) {
1254         for (String listName : list) {
1255             if (name.equals(listName)) {
1256                 return true;
1257             }
1258         }
1259         return false;
1260     }
1261 
isThirdLevelDirectoryNameValid(String thirdLevelDirectoryName)1262     private boolean isThirdLevelDirectoryNameValid(String thirdLevelDirectoryName) {
1263         if (thirdLevelDirectoryName == null || thirdLevelDirectoryName.isEmpty()) {
1264             return false;
1265         }
1266         if (ENTRYCARD_BASE_NAME.equals(thirdLevelDirectoryName)) {
1267             return true;
1268         }
1269         // example: zh_Hani_CN-vertical-car-mdpi-dark or zh_Hani_CN-vertical-car-mdpi
1270         int firstDelimiterIndex = thirdLevelDirectoryName.indexOf("_");
1271         if (firstDelimiterIndex < 0) {
1272             return false;
1273         }
1274         String language = thirdLevelDirectoryName.substring(0, firstDelimiterIndex);
1275         int secondDelimiterIndex = thirdLevelDirectoryName.indexOf("_", firstDelimiterIndex + 1);
1276         if (secondDelimiterIndex < 0) {
1277             return false;
1278         }
1279         String script = thirdLevelDirectoryName.substring(firstDelimiterIndex + 1, secondDelimiterIndex);
1280         int thirdDelimiterIndex = thirdLevelDirectoryName.indexOf("-", secondDelimiterIndex + 1);
1281         if (thirdDelimiterIndex < 0) {
1282             return false;
1283         }
1284         String country = thirdLevelDirectoryName.substring(secondDelimiterIndex + 1, thirdDelimiterIndex);
1285         if (!checkLanguage(language) || !checkScript(script) || !checkCountry(country)) {
1286             return false;
1287         }
1288         int forthDelimiterIndex = thirdLevelDirectoryName.indexOf("-", thirdDelimiterIndex + 1);
1289         if (forthDelimiterIndex < 0) {
1290             return false;
1291         }
1292         String orientation = thirdLevelDirectoryName.substring(thirdDelimiterIndex + 1, forthDelimiterIndex);
1293         int fifthDelimiterIndex = thirdLevelDirectoryName.indexOf("-", forthDelimiterIndex + 1);
1294         if (fifthDelimiterIndex < 0) {
1295             return false;
1296         }
1297         String deviceType = thirdLevelDirectoryName.substring(forthDelimiterIndex + 1, fifthDelimiterIndex);
1298         if (!checkOrientation(orientation) || !checkDeviceType(deviceType)) {
1299             return false;
1300         }
1301         int sixthDelimiterIndex = thirdLevelDirectoryName.indexOf("-", fifthDelimiterIndex + 1);
1302         if (sixthDelimiterIndex < 0) {
1303             String screenDensity = thirdLevelDirectoryName.substring(fifthDelimiterIndex + 1,
1304                     thirdLevelDirectoryName.length());
1305             return checkScreenDensity(screenDensity);
1306         } else {
1307             String screenDensity = thirdLevelDirectoryName.substring(fifthDelimiterIndex + 1, sixthDelimiterIndex);
1308             if (!checkScreenDensity(screenDensity)) {
1309                 return false;
1310             }
1311         }
1312         int seventhDelimiterIndex = thirdLevelDirectoryName.indexOf("-", sixthDelimiterIndex + 1);
1313         if (seventhDelimiterIndex < 0) {
1314             String tmp = thirdLevelDirectoryName.substring(sixthDelimiterIndex + 1, thirdLevelDirectoryName.length());
1315             return checkColorModeOrShape(tmp);
1316         }
1317         if (!checkColorMode(thirdLevelDirectoryName.substring(sixthDelimiterIndex + 1, seventhDelimiterIndex))) {
1318             return false;
1319         }
1320         String shape = thirdLevelDirectoryName.substring(seventhDelimiterIndex + 1, thirdLevelDirectoryName.length());
1321         return checkShape(shape);
1322     }
1323 
checkLanguage(String language)1324     private boolean checkLanguage(String language) {
1325         if (!Pattern.compile(REGEX_LANGUAGE).matcher(language).matches()) {
1326             LOG.error("Compressor::compressProcess language " + language + " is not in ISO 639-1 list.");
1327             return false;
1328         }
1329         return true;
1330     }
1331 
checkScript(String script)1332     private boolean checkScript(String script) {
1333         if (!Pattern.compile(REGEX_SCRIPT).matcher(script).matches()) {
1334             LOG.error("Compressor::compressProcess script " + script + " is not in ISO 15924 list.");
1335             return false;
1336         }
1337         return true;
1338     }
1339 
checkCountry(String country)1340     private boolean checkCountry(String country) {
1341         if (!Pattern.compile(REGEX_COUNTRY).matcher(country).matches()) {
1342             LOG.error("Compressor::compressProcess country " + country + " is not in ISO 3166-1 list.");
1343             return false;
1344         }
1345         return true;
1346     }
1347 
checkOrientation(String orientation)1348     private boolean checkOrientation(String orientation) {
1349         if (!Pattern.compile(REGEX_ORIENTATION).matcher(orientation).matches()) {
1350             LOG.error("Compressor::compressProcess orientation " + orientation +
1351                 " is not in {vertical, horizontal} list.");
1352             return false;
1353         }
1354         return true;
1355     }
1356 
checkDeviceType(String deviceType)1357     private boolean checkDeviceType(String deviceType) {
1358         if (!Pattern.compile(REGEX_DEVICE_TYPE).matcher(deviceType).matches()) {
1359             LOG.error("Compressor::compressProcess deviceType " + deviceType +
1360                     " is not in {phone, tablet, car, tv, wearable, liteWearable} list.");
1361             return false;
1362         }
1363         return true;
1364     }
1365 
checkScreenDensity(String screenDensity)1366     private boolean checkScreenDensity(String screenDensity) {
1367         if (!Pattern.compile(REGEX_SCREEN_DENSITY).matcher(screenDensity).matches()) {
1368             LOG.error("Compressor::compressProcess screenDensity " + screenDensity +
1369                     " is not in {sdpi, mdpi, ldpi, xldpi, xxldpi} list.");
1370             return false;
1371         }
1372         return true;
1373     }
1374 
checkColorMode(String colorMode)1375     private boolean checkColorMode(String colorMode) {
1376         if (!Pattern.compile(REGEX_COLOR_MODE).matcher(colorMode).matches()) {
1377             LOG.error("Compressor::compressProcess colorMode " + colorMode +
1378                     " is not in {light, dark} list.");
1379             return false;
1380         }
1381         return true;
1382     }
1383 
checkColorModeOrShape(String tmp)1384     private boolean checkColorModeOrShape(String tmp) {
1385         if (Pattern.compile(REGEX_COLOR_MODE).matcher(tmp).matches() ||
1386             Pattern.compile(REGEX_SHAPE).matcher(tmp).matches()) {
1387             return true;
1388         }
1389         LOG.error("Compressor::compressProcess " + tmp +
1390                 " is neither in colorMode list {light, dark} nor in shape list {circle}.");
1391         return false;
1392     }
1393 
checkShape(String shape)1394     private boolean checkShape(String shape) {
1395         if (Pattern.compile(REGEX_SHAPE).matcher(shape).matches()) {
1396             return true;
1397         }
1398         LOG.error("Compressor::compressProcess shape" + shape + " is not in {circle} list.");
1399         return false;
1400     }
1401 
1402     /**
1403      * Check whether languageCountryName meets specifications.
1404      *
1405      * @param name languageCountryName
1406      * @return false and true
1407      */
isLanguageCountry(String name)1408     private boolean isLanguageCountry(String name) {
1409         if (!ENTRYCARD_BASE_NAME.equals(name)) {
1410             boolean isLanguage = false;
1411             String[] str = name.split("-");
1412             if (str.length > 1) {
1413                 Locale[] ls = Locale.getAvailableLocales();
1414                 for (int i = 0; i < ls.length; i++) {
1415                     if (ls[i].toString().equals(str[0])) {
1416                         isLanguage = true;
1417                     }
1418                 }
1419                 if (VERTICAL.equals(str[1]) || HORIZONTAL.equals(str[1])) {
1420                     isLanguage = true;
1421                 }
1422                 if (CAR.equals(str[2]) || TV.equals(str[2]) || WEARABLE.equals(str[2])) {
1423                     isLanguage = true;
1424                 }
1425                 if (SDIP.equals(str[3]) || MDIP.equals(str[3])) {
1426                     isLanguage = true;
1427                 }
1428                 return isLanguage;
1429             } else {
1430                 return false;
1431             }
1432         } else {
1433             return true;
1434         }
1435     }
1436 
1437     /**
1438      * Check whether picturingName meets specifications.
1439      *
1440      * @param name picturingName
1441      * @param utility common data
1442      * @return false and true
1443      */
isPicturing(String name, Utility utility)1444     private boolean isPicturing(String name, Utility utility) {
1445         boolean isSpecifications = false;
1446         if (name == null || name.isEmpty()) {
1447             return isSpecifications;
1448         }
1449         if (!name.endsWith(PNG_SUFFIX) && !name.endsWith(UPPERCASE_PNG_SUFFIX)) {
1450             LOG.error("isPicturing: the suffix is not .png or .PNG.");
1451             return false;
1452         }
1453         int delimiterIndex = name.lastIndexOf("-");
1454         if (delimiterIndex < 0) {
1455             LOG.error("isPicturing: the entry card naming format is invalid and should be separated by '-'.");
1456             return false;
1457         }
1458         String formName = name.substring(0, delimiterIndex);
1459         if (!utility.getFormNameList().contains(formName)) {
1460             LOG.error("isPicturing: the name is not same as formName, name: " + formName + " is not in " +
1461                 utility.getFormNameList().toString());
1462             return false;
1463         }
1464         String dimension = name.substring(delimiterIndex + 1, name.lastIndexOf("."));
1465         if (!supportDimensionsList.contains(dimension)) {
1466             LOG.error("isPicturing: the dimension: " + dimension + " is invalid, is not in the following list: "
1467                 + "{1X2, 2X2, 2X4, 4X4}.");
1468             return false;
1469         }
1470         return true;
1471     }
1472 
getFileList(final String filePath)1473     private void getFileList(final String filePath) throws BundleException {
1474         File file = new File(filePath);
1475         if (!file.exists()) {
1476             LOG.error("getFileList: file is not exists.");
1477             return;
1478         }
1479         File[] files = file.listFiles();
1480         if (files == null) {
1481             LOG.error("getFileList: no file in this file path.");
1482             return;
1483         }
1484         for (File f : files) {
1485             try {
1486                 if (f.isFile()) {
1487                     if (f.getName().endsWith(".DS_Store")) {
1488                         deleteFile(f.getCanonicalPath());
1489                         continue;
1490                     }
1491                     String snapshotDirectoryName = f.getParentFile().getName();
1492                     if (!ENTRYCARD_SNAPSHOT_NAME.equals(snapshotDirectoryName)) {
1493                         LOG.error("The level-4 directory of EntryCard must be named as snapshot" +
1494                             ", but current is: " + snapshotDirectoryName + ".");
1495                         throw new BundleException("The level-4 directory of EntryCard must be named as snapshot" +
1496                             ", but current is: " + snapshotDirectoryName + ".");
1497                     }
1498                     checkContain2x2EntryCard(f.getParentFile());
1499                     fileNameList.add(f.getCanonicalPath());
1500                 } else if (f.isDirectory()) {
1501                     getFileList(f.getCanonicalPath());
1502                 } else {
1503                     LOG.error("It's not file or directory.");
1504                 }
1505             } catch (IOException msg) {
1506                 LOG.error("IOException error: " + msg.getMessage());
1507                 return;
1508             }
1509         }
1510     }
1511 
checkContain2x2EntryCard(final File snapshotDirectory)1512     private void checkContain2x2EntryCard(final File snapshotDirectory) throws IOException, BundleException {
1513         if (!snapshotDirectory.exists()) {
1514             LOG.error("checkContain2x2EntryCard: file is not exist: " + snapshotDirectory.getName());
1515             throw new BundleException("checkContain2x2EntryCard: file is not exist.");
1516         }
1517         File[] files = snapshotDirectory.listFiles();
1518         if (files == null) {
1519             LOG.error("checkContain2x2EntryCard: no file in this file path.");
1520             throw new BundleException("checkContain2x2EntryCard: no file in this file path.");
1521         }
1522 
1523         for (File entryCardFile : files) {
1524             if (entryCardFile.isFile() && entryCardFile.getName().contains(PIC_2X2)) {
1525                 return;
1526             }
1527         }
1528         mIsContain2x2EntryCard = false;
1529         LOG.error("checkContain2x2EntryCard: must contain 2x2 entryCard, please check it in "
1530             + snapshotDirectory.getCanonicalPath() + ".");
1531         throw new BundleException("checkContain2x2EntryCard: must contain 2x2 entryCard, please check it in "
1532             + snapshotDirectory.getCanonicalPath() + ".");
1533     }
1534 
1535     /**
1536      * compress file or directory.
1537      *
1538      * @param utility       common data
1539      * @param path          create new file by path
1540      * @param baseDir       base path for file
1541      * @param isCompression if need compression
1542      * @throws BundleException FileNotFoundException|IOException.
1543      */
pathToFile(Utility utility, String path, String baseDir, boolean isCompression)1544     private void pathToFile(Utility utility, String path, String baseDir, boolean isCompression)
1545             throws BundleException {
1546         if (path.isEmpty()) {
1547             return;
1548         }
1549         File fileItem = new File(path);
1550         if (fileItem.isDirectory()) {
1551             File[] files = fileItem.listFiles();
1552             if (files == null) {
1553                 return;
1554             }
1555             for (File file : files) {
1556                 if (file.isDirectory()) {
1557                     compressDirectory(utility, file, baseDir, isCompression);
1558                 } else if (isCompression) {
1559                     compressFile(utility, file, baseDir, isCompression);
1560                 } else {
1561                     compressFile(utility, file, baseDir, isCompression);
1562                 }
1563             }
1564         } else {
1565             compressFile(utility, fileItem, baseDir, isCompression);
1566         }
1567     }
1568 
1569     /**
1570      * compress file directory.
1571      *
1572      * @param utility       common data
1573      * @param dir           file directory
1574      * @param baseDir       current directory name
1575      * @param isCompression if need compression
1576      * @throws BundleException FileNotFoundException|IOException.
1577      */
compressDirectory(Utility utility, File dir, String baseDir, boolean isCompression)1578     private void compressDirectory(Utility utility, File dir, String baseDir, boolean isCompression)
1579             throws BundleException {
1580         File[] files = dir.listFiles();
1581         if (files == null) {
1582             return;
1583         }
1584         for (File file : files) {
1585             if (file.isDirectory()) {
1586                 compressDirectory(utility, file, baseDir + dir.getName() + File.separator, isCompression);
1587             } else {
1588                 compressFile(utility, file, baseDir + dir.getName() + File.separator, isCompression);
1589             }
1590         }
1591     }
1592 
1593     /**
1594      * compress pack.info
1595      *
1596      * @param sourceFile source
1597      * @param zipOutputStream ZipOutputStream
1598      * @param name filename
1599      * @param KeepDirStructure Empty File
1600      */
compress(File sourceFile, ZipOutputStream zipOutputStream, String name, boolean KeepDirStructure)1601     private void compress(File sourceFile, ZipOutputStream zipOutputStream, String name,
1602                                 boolean KeepDirStructure) {
1603         FileInputStream in = null;
1604         try {
1605             byte[] buf = new byte[BUFFER_SIZE];
1606             if (sourceFile.isFile()) {
1607                 ZipEntry zipEntry = getStoredZipEntry(sourceFile, name);
1608                 zipOutputStream.putNextEntry(zipEntry);
1609                 in = new FileInputStream(sourceFile);
1610                 int len;
1611                 while ((len = in.read(buf)) != -1) {
1612                     zipOutputStream.write(buf, 0, len);
1613                 }
1614                 zipOutputStream.closeEntry();
1615             } else {
1616                 File[] listFiles = sourceFile.listFiles();
1617                 if (listFiles == null || listFiles.length == 0) {
1618                     if (KeepDirStructure) {
1619                         if (!name.isEmpty()) {
1620                             ZipEntry zipEntry = getStoredZipEntry(sourceFile, name + "/");
1621                             zipOutputStream.putNextEntry(zipEntry);
1622                         } else {
1623                             ZipEntry zipEntry = getStoredZipEntry(sourceFile, name);
1624                             zipOutputStream.putNextEntry(zipEntry);
1625                         }
1626                         zipOutputStream.closeEntry();
1627                     }
1628                 } else {
1629                     for (File file : listFiles) {
1630                         if (KeepDirStructure) {
1631                             isNameEmpty(zipOutputStream, name, KeepDirStructure, file);
1632                         } else {
1633                             compress(file, zipOutputStream, file.getName(), KeepDirStructure);
1634                         }
1635                     }
1636                 }
1637             }
1638         } catch (FileNotFoundException ignored) {
1639             LOG.error("Compressor::compressFile file not found exception.");
1640         } catch (IOException exception) {
1641             LOG.error("Compressor::compressFile io exception: " + exception.getMessage());
1642         } catch (BundleException bundleException) {
1643             LOG.error("Compressor::compressFile bundle exception" + bundleException.getMessage());
1644         } finally {
1645             Utility.closeStream(in);
1646         }
1647     }
1648 
getStoredZipEntry(File sourceFile, String name)1649     private ZipEntry getStoredZipEntry(File sourceFile, String name) throws BundleException {
1650         ZipEntry zipEntry = new ZipEntry(name);
1651         zipEntry.setMethod(ZipEntry.STORED);
1652         zipEntry.setCompressedSize(sourceFile.length());
1653         zipEntry.setSize(sourceFile.length());
1654         CRC32 crc = getCrcFromFile(sourceFile);
1655         zipEntry.setCrc(crc.getValue());
1656         FileTime fileTime = FileTime.fromMillis(FILE_TIME);
1657         zipEntry.setLastAccessTime(fileTime);
1658         zipEntry.setLastModifiedTime(fileTime);
1659         return zipEntry;
1660     }
1661 
getCrcFromFile(File file)1662     private CRC32 getCrcFromFile(File file) throws BundleException {
1663         FileInputStream fileInputStream = null;
1664         CRC32 crc = new CRC32();
1665         try {
1666             fileInputStream = new FileInputStream(file);
1667             byte[] buffer = new byte[BUFFER_SIZE];
1668 
1669             int count = fileInputStream.read(buffer);
1670             while (count > 0) {
1671                 crc.update(buffer, 0, count);
1672                 count = fileInputStream.read(buffer);
1673             }
1674         } catch (FileNotFoundException ignored) {
1675             LOG.error("Uncompressor::getCrcFromFile file not found exception.");
1676             throw new BundleException("Get Crc from file failed.");
1677         } catch (IOException exception) {
1678             LOG.error("Uncompressor::getCrcFromFile io exception: " + exception.getMessage());
1679             throw new BundleException("Get Crc from file failed.");
1680         } finally {
1681             Utility.closeStream(fileInputStream);
1682         }
1683         return crc;
1684     }
1685 
1686     /**
1687      * isNameEmpty
1688      *
1689      * @param zipOutputStream ZipOutputStream
1690      * @param name filename
1691      * @param KeepDirStructure KeepDirStructure
1692      * @param file file
1693      */
isNameEmpty(ZipOutputStream zipOutputStream, String name, boolean KeepDirStructure, File file)1694     private void isNameEmpty(ZipOutputStream zipOutputStream, String name, boolean KeepDirStructure, File file) {
1695         if (!name.isEmpty()) {
1696             compress(file, zipOutputStream, name + "/" + file.getName(), KeepDirStructure);
1697         } else {
1698             compress(file, zipOutputStream, file.getName(), KeepDirStructure);
1699         }
1700     }
1701 
1702     /**
1703      * compress process.
1704      *
1705      * @param utility       common data
1706      * @param srcFile       source file to zip
1707      * @param baseDir       current directory name of file
1708      * @param isCompression if need compression
1709      * @throws BundleException FileNotFoundException|IOException.
1710      */
compressFile(Utility utility, File srcFile, String baseDir, boolean isCompression)1711     private void compressFile(Utility utility, File srcFile, String baseDir, boolean isCompression)
1712             throws BundleException {
1713         BufferedInputStream bufferedInputStream = null;
1714         FileInputStream fileInputStream = null;
1715         try {
1716             String entryName = (baseDir + srcFile.getName()).replace(File.separator, LINUX_FILE_SEPARATOR);
1717             ZipEntry zipEntry = new ZipEntry(entryName);
1718             if (srcFile.getName().toLowerCase(Locale.ENGLISH).endsWith(JSON_SUFFIX)) {
1719                 zipEntry.setMethod(ZipEntry.STORED);
1720                 jsonSpecialProcess(utility, srcFile, zipEntry);
1721                 return;
1722             }
1723 
1724             if (isCompression) {
1725                 zipEntry.setMethod(ZipEntry.DEFLATED);
1726             } else {
1727                 zipEntry.setMethod(ZipEntry.STORED);
1728 
1729                 // update size
1730                 zipEntry.setCompressedSize(srcFile.length());
1731                 zipEntry.setSize(srcFile.length());
1732 
1733                 // update crc
1734                 CRC32 crc = getCrcFromFile(utility, srcFile);
1735                 zipEntry.setCrc(crc.getValue());
1736             }
1737 
1738             // update fileTime
1739             FileTime fileTime = FileTime.fromMillis(FILE_TIME);
1740             zipEntry.setLastAccessTime(fileTime);
1741             zipEntry.setLastModifiedTime(fileTime);
1742 
1743             zipOut.putNextEntry(zipEntry);
1744             byte[] data = new byte[BUFFER_SIZE];
1745             fileInputStream = new FileInputStream(srcFile);
1746             bufferedInputStream = new BufferedInputStream(fileInputStream);
1747 
1748             int count = bufferedInputStream.read(data);
1749             while (count > 0) {
1750                 zipOut.write(data, 0, count);
1751                 count = bufferedInputStream.read(data);
1752             }
1753         } catch (FileNotFoundException ignored) {
1754             throw new BundleException("CoompressFile failed.");
1755         } catch (IOException exception) {
1756             LOG.error("Compressor::compressFile io exception: " + exception.getMessage());
1757             throw new BundleException("CoompressFile failed.");
1758         } finally {
1759             Utility.closeStream(bufferedInputStream);
1760             Utility.closeStream(fileInputStream);
1761         }
1762     }
1763 
1764     /**
1765      * check hap type for pack app.
1766      *
1767      * @param hapPath source file to zip
1768      * @return true is for is stage type and false is for FA type
1769      * @throws BundleException FileNotFoundException|IOException.
1770      */
isModuleHap(String hapPath)1771     public static boolean isModuleHap(String hapPath) throws BundleException {
1772         if (!hapPath.toLowerCase(Locale.ENGLISH).endsWith(HAP_SUFFIX)) {
1773             return true;
1774         }
1775 
1776         FileInputStream zipInput = null;
1777         ZipInputStream zin = null;
1778         ZipEntry entry = null;
1779         try {
1780             zipInput = new FileInputStream(hapPath);
1781             zin = new ZipInputStream(zipInput);
1782             while ((entry = zin.getNextEntry()) != null) {
1783                 if (MODULE_JSON.equals(entry.getName().toLowerCase())) {
1784                     return true;
1785                 }
1786             }
1787         } catch (IOException exception) {
1788             LOG.error("Compressor::isModuleHap io exception: " + exception.getMessage());
1789             throw new BundleException("Compressor::isModuleHap failed.");
1790         } finally {
1791             Utility.closeStream(zipInput);
1792             Utility.closeStream(zin);
1793         }
1794         return false;
1795     }
1796 
1797     /**
1798      * get CRC32 from file.
1799      *
1800      * @param utility common data
1801      * @param file    source file
1802      * @return CRC32
1803      * @throws BundleException FileNotFoundException|IOException.
1804      */
getCrcFromFile(Utility utility, File file)1805     private CRC32 getCrcFromFile(Utility utility, File file) throws BundleException {
1806         FileInputStream fileInputStream = null;
1807         CRC32 crc = new CRC32();
1808         try {
1809             fileInputStream = new FileInputStream(file);
1810             byte[] buffer = new byte[BUFFER_SIZE];
1811 
1812             int count = fileInputStream.read(buffer);
1813             while (count > 0) {
1814                 crc.update(buffer, 0, count);
1815                 count = fileInputStream.read(buffer);
1816             }
1817         } catch (FileNotFoundException ignored) {
1818             throw new BundleException("Get Crc from file failed.");
1819         } catch (IOException exception) {
1820             LOG.error("Compressor::getCrcFromFile io exception: " + exception.getMessage());
1821             throw new BundleException("Get Crc from file failed.");
1822         } finally {
1823             Utility.closeStream(fileInputStream);
1824         }
1825         return crc;
1826     }
1827 
infoSpecialProcess(Utility utility, File srcFile)1828     private void infoSpecialProcess(Utility utility, File srcFile)
1829             throws BundleException {
1830         FileInputStream fileInputStream = null;
1831         BufferedReader bufferedReader = null;
1832         InputStreamReader inputStreamReader = null;
1833 
1834         try {
1835             fileInputStream = new FileInputStream(srcFile);
1836             inputStreamReader = new InputStreamReader(fileInputStream, StandardCharsets.UTF_8);
1837             bufferedReader = new BufferedReader(inputStreamReader);
1838             bufferedReader.mark((int) srcFile.length() + 1);
1839             // parse moduleName from pack.info
1840             parsePackModuleName(bufferedReader, utility);
1841             bufferedReader.reset();
1842             parsePackFormName(bufferedReader, utility);
1843             bufferedReader.reset();
1844             parseDeviceType(bufferedReader, utility);
1845             bufferedReader.reset();
1846 
1847             Pattern pattern = Pattern.compile(System.lineSeparator());
1848             String str = bufferedReader.readLine();
1849             StringBuilder builder = new StringBuilder();
1850             while (str != null) {
1851                 Matcher matcher = pattern.matcher(str.trim());
1852                 String dest = matcher.replaceAll("");
1853                 builder.append(dest);
1854                 str = bufferedReader.readLine();
1855             }
1856         } catch (IOException exception) {
1857             LOG.error("Compressor::jsonSpecialProcess io exception: " + exception.getMessage());
1858             throw new BundleException("Json special process failed.");
1859         } finally {
1860             Utility.closeStream(bufferedReader);
1861             Utility.closeStream(inputStreamReader);
1862             Utility.closeStream(fileInputStream);
1863         }
1864     }
1865 
1866     /**
1867      * trim and remove "\r\n" in *.json file.
1868      *
1869      * @param utility common data
1870      * @param srcFile file input
1871      * @param entry   zip file entry
1872      * @throws BundleException FileNotFoundException|IOException.
1873      */
jsonSpecialProcess(Utility utility, File srcFile, ZipEntry entry)1874     private void jsonSpecialProcess(Utility utility, File srcFile, ZipEntry entry)
1875             throws BundleException {
1876         FileInputStream fileInputStream = null;
1877         BufferedReader bufferedReader = null;
1878         InputStreamReader inputStreamReader = null;
1879 
1880         try {
1881             fileInputStream = new FileInputStream(srcFile);
1882             inputStreamReader = new InputStreamReader(fileInputStream, StandardCharsets.UTF_8);
1883             bufferedReader = new BufferedReader(inputStreamReader);
1884             bufferedReader.mark((int) srcFile.length() + 1);
1885             // parse moduleName from config.json
1886             parseModuleName(bufferedReader, utility);
1887             bufferedReader.reset();
1888             parseCompressNativeLibs(bufferedReader, utility);
1889             bufferedReader.reset();
1890             parseDeviceType(bufferedReader, utility);
1891             bufferedReader.reset();
1892 
1893             Pattern pattern = Pattern.compile(System.lineSeparator());
1894             String str = bufferedReader.readLine();
1895             StringBuilder builder = new StringBuilder();
1896             while (str != null) {
1897                 Matcher matcher = pattern.matcher(str.trim());
1898                 String dest = matcher.replaceAll("");
1899                 builder.append(dest);
1900                 str = bufferedReader.readLine();
1901             }
1902             byte[] trimJson = builder.toString().getBytes(StandardCharsets.UTF_8);
1903 
1904             // update crc
1905             CRC32 crc = new CRC32();
1906             crc.update(trimJson);
1907             entry.setCrc(crc.getValue());
1908 
1909             // update size
1910             entry.setSize(trimJson.length);
1911             entry.setCompressedSize(trimJson.length);
1912 
1913             // update fileTime
1914             FileTime fileTime = FileTime.fromMillis(FILE_TIME);
1915             entry.setLastAccessTime(fileTime);
1916             entry.setLastModifiedTime(fileTime);
1917 
1918             // compress data
1919             zipOut.putNextEntry(entry);
1920             zipOut.write(trimJson);
1921         } catch (IOException exception) {
1922             LOG.error("Compressor::jsonSpecialProcess io exception: " + exception.getMessage());
1923             throw new BundleException("Json special process failed.");
1924         } finally {
1925             Utility.closeStream(bufferedReader);
1926             Utility.closeStream(inputStreamReader);
1927             Utility.closeStream(fileInputStream);
1928         }
1929     }
1930 
1931     /**
1932      * Parse module name from config.json
1933      *
1934      * @param bufferedReader config.json buffered Reader
1935      * @param utility        common data
1936      * @throws BundleException IOException
1937      */
parseModuleName(BufferedReader bufferedReader, Utility utility)1938     private void parseModuleName(BufferedReader bufferedReader, Utility utility) throws BundleException {
1939         String lineStr = null;
1940         boolean isDistroStart = false;
1941         try {
1942             while ((lineStr = bufferedReader.readLine()) != null) {
1943                 if (!isDistroStart) {
1944                     if (lineStr.contains(DISTRO)) {
1945                         isDistroStart = true;
1946                     }
1947                     continue;
1948                 }
1949                 if (lineStr.contains(JSON_END)) {
1950                     continue;
1951                 }
1952                 if (lineStr.contains(MODULE_NAME_NEW) || lineStr.contains(MODULE_NAME)) {
1953                     getModuleNameFromString(lineStr, utility);
1954                     break;
1955                 }
1956             }
1957         } catch (IOException exception) {
1958             LOG.error("Compressor::parseModuleName io exception: " + exception.getMessage());
1959             throw new BundleException("Parse module name failed.");
1960         }
1961     }
1962 
1963     /**
1964      * Parse module name from pack.info
1965      *
1966      * @param bufferedReader pack.info buffered Reader
1967      * @param utility        common data
1968      * @throws BundleException IOException
1969      */
parsePackModuleName(BufferedReader bufferedReader, Utility utility)1970     private void parsePackModuleName(BufferedReader bufferedReader, Utility utility) throws BundleException {
1971         String lineStr = null;
1972         boolean isDistroStart = false;
1973         try {
1974             while ((lineStr = bufferedReader.readLine()) != null) {
1975                 if (lineStr.contains(DISTRO)) {
1976                     continue;
1977                 }
1978                 if (lineStr.contains(JSON_END)) {
1979                     continue;
1980                 }
1981                 if (lineStr.contains(MODULE_NAME_NEW) || lineStr.contains(MODULE_NAME)) {
1982                     getModuleNameFromString(lineStr, utility);
1983                 }
1984             }
1985         } catch (IOException exception) {
1986             LOG.error("Compressor::parseModuleName io exception: " + exception.getMessage());
1987             throw new BundleException("Parse module name failed.");
1988         }
1989     }
1990 
1991     /**
1992      * Parse Forms name from pack.info
1993      *
1994      * @param bufferedReader pack.info buffered Reader
1995      * @param utility        common data
1996      * @throws BundleException IOException
1997      */
parsePackFormName(BufferedReader bufferedReader, Utility utility)1998     private void parsePackFormName(BufferedReader bufferedReader, Utility utility) throws BundleException {
1999         String lineStr = null;
2000         try {
2001             while ((lineStr = bufferedReader.readLine()) != null) {
2002                 if (lineStr.contains("abilities")) {
2003                     continue;
2004                 }
2005                 if (lineStr.contains(FORMS)) {
2006                     continue;
2007                 }
2008                 if (lineStr.contains(JSON_END)) {
2009                     continue;
2010                 }
2011                 if (lineStr.contains(NAME)) {
2012                     getNameFromString(lineStr, utility);
2013                 }
2014             }
2015         } catch (IOException exception) {
2016             LOG.error("Compressor::parseModuleName io exception: " + exception.getMessage());
2017             throw new BundleException("Parse module name failed.");
2018         }
2019     }
2020 
2021 
2022     /**
2023      * Get name from line string
2024      *
2025      * @param lineStr line string
2026      * @param utility common data
2027      * @throws BundleException StringIndexOutOfBoundsException
2028      */
getNameFromString(String lineStr, Utility utility)2029     private void getNameFromString(String lineStr, Utility utility) throws BundleException {
2030         try {
2031             int endIndex = lineStr.lastIndexOf(SEMICOLON);
2032             if (endIndex <= 0) {
2033                 LOG.error("Compressor::getModuleNameFromString field the json is not standard.");
2034                 throw new BundleException("Parse module name failed, module-name is invalid.");
2035             }
2036             int startIndex = lineStr.lastIndexOf(SEMICOLON, endIndex - 1) + 1;
2037             String formName = lineStr.substring(startIndex, endIndex);
2038             if (formName == null || formName.isEmpty()) {
2039                 LOG.error("Compressor::getModuleNameFromString field module-name is empty.");
2040                 throw new BundleException("Parse module name failed, module-name is empty.");
2041             }
2042             String[] nameList = formName.split("\\.");
2043             if (nameList.length <= 1) {
2044                 formNamesList.add(formName);
2045                 utility.addFormNameList(formName);
2046             }
2047         } catch (StringIndexOutOfBoundsException exception) {
2048             LOG.error("Compressor::parseModuleName field module-name is fault: " + exception.getMessage());
2049             throw new BundleException("Parse module name failed, module-name is invalid.");
2050         }
2051     }
2052 
2053     /**
2054      * Get module name from line string
2055      *
2056      * @param lineStr line string
2057      * @param utility common data
2058      * @throws BundleException StringIndexOutOfBoundsException
2059      */
getModuleNameFromString(String lineStr, Utility utility)2060     private void getModuleNameFromString(String lineStr, Utility utility) throws BundleException {
2061         try {
2062             int endIndex = lineStr.lastIndexOf(SEMICOLON);
2063             if (endIndex <= 0) {
2064                 LOG.error("Compressor::getModuleNameFromString field the json is not standard.");
2065                 throw new BundleException("Parse module name failed, module-name is invalid.");
2066             }
2067             int startIndex = lineStr.lastIndexOf(SEMICOLON, endIndex - 1) + 1;
2068             String moduleName = lineStr.substring(startIndex, endIndex);
2069             list.add(moduleName);
2070             if (moduleName == null || moduleName.isEmpty()) {
2071                 LOG.error("Compressor::getModuleNameFromString field module-name is empty.");
2072                 throw new BundleException("Parse module name failed, module-name is empty.");
2073             }
2074             utility.setModuleName(moduleName);
2075         } catch (StringIndexOutOfBoundsException exception) {
2076             LOG.error("Compressor::parseModuleName field module-name is fault: " + exception.getMessage());
2077             throw new BundleException("Parse module name failed, module-name is invalid.");
2078         }
2079     }
2080 
parseCompressNativeLibs(BufferedReader bufferedReader, Utility utility)2081     private void parseCompressNativeLibs(BufferedReader bufferedReader, Utility utility) throws BundleException {
2082         String lineStr = null;
2083         try {
2084             while ((lineStr = bufferedReader.readLine()) != null) {
2085                 if (lineStr.contains(COMPRESS_NATIVE_LIBS)) {
2086                     if (lineStr.contains(Utility.FALSE_STRING)) {
2087                         utility.setIsCompressNativeLibs(false);
2088                         break;
2089                     }
2090                 }
2091             }
2092         } catch (IOException exception) {
2093             LOG.error("Compressor::parseCompressNativeLibs io exception: " + exception.getMessage());
2094             throw new BundleException("Parse compress native libs failed.");
2095         }
2096     }
2097 
2098     /**
2099      * ZipOutputStream flush, closeEntry and finish.
2100      */
closeZipOutputStream()2101     private void closeZipOutputStream() {
2102         try {
2103             if (zipOut != null) {
2104                 zipOut.flush();
2105             }
2106         } catch (IOException exception) {
2107             LOG.error("Compressor::closeZipOutputStream flush exception " + exception.getMessage());
2108         }
2109         try {
2110             if (zipOut != null) {
2111                 zipOut.closeEntry();
2112             }
2113         } catch (IOException exception) {
2114             LOG.error("Compressor::closeZipOutputStream close entry io exception " + exception.getMessage());
2115         }
2116         try {
2117             if (zipOut != null) {
2118                 zipOut.finish();
2119             }
2120         } catch (IOException exception) {
2121             LOG.error("Compressor::closeZipOutputStream finish exception " + exception.getMessage());
2122         }
2123     }
2124 
2125     /**
2126      * Parse device type from config.json
2127      *
2128      * @param bufferedReader config.json buffered Reader
2129      * @param utility        common data
2130      * @throws BundleException IOException
2131      */
parseDeviceType(BufferedReader bufferedReader, Utility utility)2132     private void parseDeviceType(BufferedReader bufferedReader, Utility utility) throws BundleException {
2133         String lineStr = null;
2134         boolean isDeviceTypeStart = false;
2135         try {
2136             while ((lineStr = bufferedReader.readLine()) != null) {
2137                 if (!isDeviceTypeStart) {
2138                     if (lineStr.contains(DEVICE_TYPE)) {
2139                         isDeviceTypeStart = true;
2140                     }
2141                     continue;
2142                 }
2143                 if (lineStr.contains(JSON_END)) {
2144                     break;
2145                 }
2146                 utility.setDeviceType(lineStr);
2147                 break;
2148             }
2149         } catch (IOException exception) {
2150             LOG.error("Compressor::parseDeviceType io exception: " + exception.getMessage());
2151             throw new BundleException("Parse device type failed");
2152         }
2153     }
2154 
2155     /**
2156      * check hap is valid in haps when pack app, check type has bundleName,
2157      * vendor, version, apiVersion moduleName, packageName.
2158      *
2159      * @param fileLists is the list of hapPath.
2160      * @return true is for successful and false is for failed
2161      * @throws BundleException FileNotFoundException|IOException.
2162      */
checkHapIsValid(List<String> fileLists)2163     private boolean checkHapIsValid(List<String> fileLists) throws BundleException {
2164         List<HapVerifyInfo> hapVerifyInfos = new ArrayList<>();
2165         for (String hapPath : fileLists) {
2166             if (hapPath.isEmpty()) {
2167                 LOG.error("Compressor::checkHapIsValid input wrong hap file.");
2168                 throw new BundleException("Compressor::checkHapIsValid input wrong hap file.");
2169             }
2170             File srcFile = new File(hapPath);
2171             String fileStr = srcFile.getName();
2172             if (fileStr.isEmpty()) {
2173                 LOG.error("Compressor::checkHapIsValid get file name failed.");
2174                 throw new BundleException("Compressor::checkHapIsValid get file name failed.");
2175             }
2176             if (!fileStr.toLowerCase(Locale.ENGLISH).endsWith(HAP_SUFFIX)
2177                     && !fileStr.toLowerCase(Locale.ENGLISH).endsWith(HSP_SUFFIX)) {
2178                 LOG.error("Compressor::checkHapIsValid input wrong hap file.");
2179                 throw new BundleException("Compressor::checkHapIsValid input wrong hap file.");
2180             }
2181             if (isModuleHap(hapPath)) {
2182                 hapVerifyInfos.add(parseStageHapVerifyInfo(hapPath));
2183             } else {
2184                 hapVerifyInfos.add(parseFAHapVerifyInfo(hapPath));
2185             }
2186         }
2187         setAtomicServiceFileSizeLimit(hapVerifyInfos);
2188         if (!HapVerify.checkHapIsValid(hapVerifyInfos)) {
2189             return false;
2190         }
2191         return true;
2192     }
2193 
2194     /**
2195      * parse stage file to hap verify info from hap path.
2196      *
2197      * @param filePath is the hap path
2198      * @return hapVerifyInfo
2199      */
parseStageHapVerifyInfo(String filePath)2200     public static HapVerifyInfo parseStageHapVerifyInfo(String filePath) throws BundleException {
2201         HapVerifyInfo hapVerifyInfo = readStageHapVerifyInfo(filePath);
2202         hapVerifyInfo.setStageModule(true);
2203         ModuleJsonUtil.parseStageHapVerifyInfo(hapVerifyInfo);
2204         hapVerifyInfo.setFileLength(FileUtils.getFileSize(filePath));
2205         return hapVerifyInfo;
2206     }
2207 
2208     /**
2209      * set file size limit for each HapVerifyInfo.
2210      *
2211      * @param hapVerifyInfos Indicates hapVerifyInfo list.
2212      */
setAtomicServiceFileSizeLimit(List<HapVerifyInfo>hapVerifyInfos)2213     public static void setAtomicServiceFileSizeLimit(List<HapVerifyInfo>hapVerifyInfos) {
2214         for (HapVerifyInfo hapVerifyInfo : hapVerifyInfos) {
2215             if (!hapVerifyInfo.getBundleType().equals(ATOMIC_SERVICE)) {
2216                 continue;
2217             }
2218             hapVerifyInfo.setEntrySizeLimit(getEntryModuleSizeLimit());
2219             hapVerifyInfo.setNotEntrySizeLimit(getNotEntryModuleSizeLimit());
2220             hapVerifyInfo.setSumSizeLimit(getSumModuleSizeLimit());
2221         }
2222     }
2223 
2224     /**
2225      * parse fa file to hap verify info from hap path.
2226      *
2227      * @param filePath is the hap path
2228      * @return hapVerifyInfo
2229      */
parseFAHapVerifyInfo(String filePath)2230     public static HapVerifyInfo parseFAHapVerifyInfo(String filePath) throws BundleException {
2231         HapVerifyInfo hapVerifyInfo = readFAHapVerifyInfo(filePath);
2232         hapVerifyInfo.setStageModule(false);
2233         hapVerifyInfo.setFileLength(FileUtils.getFileSize(filePath));
2234         ModuleJsonUtil.parseFAHapVerifyInfo(hapVerifyInfo);
2235         return hapVerifyInfo;
2236     }
2237 
2238     /**
2239      * read stage hap verify info from hap file.
2240      *
2241      * @param srcPath source file to zip
2242      * @return HapVerifyInfo of parse result
2243      * @throws BundleException FileNotFoundException|IOException.
2244      */
readStageHapVerifyInfo(String srcPath)2245     public static HapVerifyInfo readStageHapVerifyInfo(String srcPath) throws BundleException {
2246         HapVerifyInfo hapVerifyInfo = new HapVerifyInfo();
2247         ZipFile zipFile = null;
2248         try {
2249             File srcFile = new File(srcPath);
2250             zipFile = new ZipFile(srcFile);
2251             hapVerifyInfo.setResourceMap(FileUtils.getProfileJson(zipFile));
2252             hapVerifyInfo.setProfileStr(FileUtils.getFileStringFromZip(MODULE_JSON, zipFile));
2253         } catch (IOException e) {
2254             LOG.error("FileUtil::parseStageHapVerifyInfo file not available.");
2255             throw new BundleException("FileUtil::parseStageHapVerifyInfo file not available.");
2256         } finally {
2257             Utility.closeStream(zipFile);
2258         }
2259         return hapVerifyInfo;
2260     }
2261 
2262     /**
2263      * read fa hap verify info from hap file.
2264      *
2265      * @param srcPath source file to zip
2266      * @return HapVerifyInfo of parse result
2267      * @throws BundleException FileNotFoundException|IOException.
2268      */
readFAHapVerifyInfo(String srcPath)2269     public static HapVerifyInfo readFAHapVerifyInfo(String srcPath) throws BundleException {
2270         HapVerifyInfo hapVerifyInfo = new HapVerifyInfo();
2271         ZipFile zipFile = null;
2272         try {
2273             File srcFile = new File(srcPath);
2274             zipFile = new ZipFile(srcFile);
2275             hapVerifyInfo.setProfileStr(FileUtils.getFileStringFromZip(CONFIG_JSON, zipFile));
2276         } catch (IOException e) {
2277             LOG.error("FileUtil::parseStageHapVerifyInfo file not available.");
2278             throw new BundleException("FileUtil::parseStageHapVerifyInfo file not available.");
2279         } finally {
2280             Utility.closeStream(zipFile);
2281         }
2282         return hapVerifyInfo;
2283     }
2284 
2285     /**
2286      * compress in hqf mode.
2287      *
2288      * @param utility common data
2289      * @throws BundleException FileNotFoundException|IOException.
2290      */
compressHQFMode(Utility utility)2291     private void compressHQFMode(Utility utility) throws BundleException {
2292         pathToFile(utility, utility.getJsonPath(), NULL_DIR_NAME, false);
2293 
2294         if (!utility.getEtsPath().isEmpty()) {
2295             pathToFile(utility, utility.getEtsPath(), ETS_PATH, false);
2296         }
2297         if (!utility.getLibPath().isEmpty()) {
2298             pathToFile(utility, utility.getLibPath(), LIBS_DIR_NAME, false);
2299         }
2300     }
2301 
2302     /**
2303      * compress in appqf mode.
2304      *
2305      * @param utility common data
2306      * @throws BundleException FileNotFoundException|IOException.
2307      */
compressAPPQFMode(Utility utility)2308     private void compressAPPQFMode(Utility utility) throws BundleException {
2309         List<String> fileList = utility.getFormatedHQFList();
2310         if (!checkHQFIsValid(fileList)) {
2311             LOG.error("Error: checkHQFIsValid failed when pack appqf file.");
2312             throw new BundleException("Error: checkHQFIsValid failed when pack appqf file.");
2313         }
2314         for (String hapPath : fileList) {
2315             pathToFile(utility, hapPath, NULL_DIR_NAME, false);
2316         }
2317     }
2318 
2319     /**
2320      * check input hqf is valid.
2321      *
2322      * @param fileList is input path of hqf files
2323      * @throws BundleException FileNotFoundException|IOException.
2324      */
checkHQFIsValid(List<String> fileList)2325     private boolean checkHQFIsValid(List<String> fileList) throws BundleException {
2326         List<HQFInfo> hqfVerifyInfos = new ArrayList<>();
2327         for (String file : fileList) {
2328             hqfVerifyInfos.add(ModuleJsonUtil.parseHQFInfo(file));
2329         }
2330         if (!HQFVerify.checkHQFIsValid(hqfVerifyInfos)) {
2331             LOG.error("Error: input hqf is invalid.");
2332             return false;
2333         }
2334         return true;
2335     }
2336 
compressHSPMode(Utility utility)2337     private void compressHSPMode(Utility utility) throws BundleException {
2338         pathToFile(utility, utility.getJsonPath(), NULL_DIR_NAME, false);
2339 
2340         pathToFile(utility, utility.getProfilePath(), NULL_DIR_NAME, false);
2341 
2342         if (!utility.getIndexPath().isEmpty() && isModuleJSON(utility.getJsonPath())) {
2343             String assetsPath = NULL_DIR_NAME;
2344             pathToFile(utility, utility.getIndexPath(), assetsPath, false);
2345         }
2346 
2347         if (!utility.getLibPath().isEmpty()) {
2348             pathToFile(utility, utility.getLibPath(), LIBS_DIR_NAME, utility.isCompressNativeLibs());
2349         }
2350 
2351         if (!utility.getANPath().isEmpty()) {
2352             pathToFile(utility, utility.getANPath(), AN_DIR_NAME, false);
2353         }
2354 
2355         if (!utility.getFilePath().isEmpty()) {
2356             pathToFile(utility, utility.getFilePath(), NULL_DIR_NAME, false);
2357         }
2358 
2359         if (!utility.getResPath().isEmpty() && !utility.getModuleName().isEmpty()) {
2360             String resPath = ASSETS_DIR_NAME + utility.getModuleName() + LINUX_FILE_SEPARATOR
2361                     + RESOURCES_DIR_NAME;
2362             if (DEVICE_TYPE_FITNESSWATCH.equals(utility.getDeviceType().replace(SEMICOLON, EMPTY_STRING).trim()) ||
2363                     DEVICE_TYPE_FITNESSWATCH_NEW.equals(
2364                         utility.getDeviceType().replace(SEMICOLON, EMPTY_STRING).trim())) {
2365                 resPath = RES_DIR_NAME;
2366             }
2367             pathToFile(utility, utility.getResPath(), resPath, false);
2368         }
2369 
2370         if (!utility.getResourcesPath().isEmpty() && isModuleJSON(utility.getJsonPath())) {
2371             String resourcesPath = RESOURCES_DIR_NAME;
2372             pathToFile(utility, utility.getResourcesPath(), resourcesPath, false);
2373         }
2374         if (!utility.getJsPath().isEmpty() && isModuleJSON(utility.getJsonPath())) {
2375             String jsPath = JS_PATH;
2376             pathToFile(utility, utility.getJsPath(), jsPath, false);
2377         }
2378 
2379         if (!utility.getEtsPath().isEmpty() && isModuleJSON(utility.getJsonPath())) {
2380             String etsPath = ETS_PATH;
2381             pathToFile(utility, utility.getEtsPath(), etsPath, false);
2382         }
2383 
2384         if (!utility.getRpcidPath().isEmpty()) {
2385             String rpcidPath = NULL_DIR_NAME;
2386             pathToFile(utility, utility.getRpcidPath(), rpcidPath, false);
2387         }
2388 
2389         if (!utility.getAssetsPath().isEmpty()) {
2390             pathToFile(utility, utility.getAssetsPath(), ASSETS_DIR_NAME, false);
2391         }
2392 
2393         if (!utility.getBinPath().isEmpty()) {
2394             pathToFile(utility, utility.getBinPath(), NULL_DIR_NAME, false);
2395         }
2396 
2397         if (!utility.getPackInfoPath().isEmpty()) {
2398             pathToFile(utility, utility.getPackInfoPath(), NULL_DIR_NAME, false);
2399         }
2400 
2401         compressHapModeMultiple(utility);
2402     }
2403 }
2404