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