1b8a72a62Sopenharmony_ci/* 2b8a72a62Sopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd. 3b8a72a62Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4b8a72a62Sopenharmony_ci * you may not use this file except in compliance with the License. 5b8a72a62Sopenharmony_ci * You may obtain a copy of the License at 6b8a72a62Sopenharmony_ci * 7b8a72a62Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8b8a72a62Sopenharmony_ci * 9b8a72a62Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10b8a72a62Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11b8a72a62Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12b8a72a62Sopenharmony_ci * See the License for the specific language governing permissions and 13b8a72a62Sopenharmony_ci * limitations under the License. 14b8a72a62Sopenharmony_ci */ 15b8a72a62Sopenharmony_ci 16b8a72a62Sopenharmony_cipackage ohos; 17b8a72a62Sopenharmony_ci 18b8a72a62Sopenharmony_ciimport com.alibaba.fastjson.JSON; 19b8a72a62Sopenharmony_ciimport com.alibaba.fastjson.JSONArray; 20b8a72a62Sopenharmony_ciimport com.alibaba.fastjson.JSONException; 21b8a72a62Sopenharmony_ciimport com.alibaba.fastjson.JSONObject; 22b8a72a62Sopenharmony_ciimport com.alibaba.fastjson.serializer.SerializerFeature; 23b8a72a62Sopenharmony_ciimport org.apache.commons.compress.archivers.zip.DefaultBackingStoreSupplier; 24b8a72a62Sopenharmony_ciimport org.apache.commons.compress.archivers.zip.ParallelScatterZipCreator; 25b8a72a62Sopenharmony_ciimport org.apache.commons.compress.archivers.zip.ZipArchiveEntry; 26b8a72a62Sopenharmony_ciimport org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream; 27b8a72a62Sopenharmony_ciimport org.apache.commons.compress.archivers.zip.ZipFile; 28b8a72a62Sopenharmony_ciimport org.apache.commons.compress.parallel.InputStreamSupplier; 29b8a72a62Sopenharmony_ciimport org.apache.commons.compress.utils.IOUtils; 30b8a72a62Sopenharmony_ci 31b8a72a62Sopenharmony_ciimport java.io.ByteArrayInputStream; 32b8a72a62Sopenharmony_ciimport java.io.ByteArrayOutputStream; 33b8a72a62Sopenharmony_ciimport java.io.File; 34b8a72a62Sopenharmony_ciimport java.io.FileInputStream; 35b8a72a62Sopenharmony_ciimport java.io.IOException; 36b8a72a62Sopenharmony_ciimport java.io.InputStream; 37b8a72a62Sopenharmony_ciimport java.nio.file.FileVisitResult; 38b8a72a62Sopenharmony_ciimport java.nio.file.Files; 39b8a72a62Sopenharmony_ciimport java.nio.file.Path; 40b8a72a62Sopenharmony_ciimport java.nio.file.Paths; 41b8a72a62Sopenharmony_ciimport java.nio.file.SimpleFileVisitor; 42b8a72a62Sopenharmony_ciimport java.nio.file.attribute.BasicFileAttributes; 43b8a72a62Sopenharmony_ciimport java.security.MessageDigest; 44b8a72a62Sopenharmony_ciimport java.security.NoSuchAlgorithmException; 45b8a72a62Sopenharmony_ciimport java.util.ArrayList; 46b8a72a62Sopenharmony_ciimport java.util.Enumeration; 47b8a72a62Sopenharmony_ciimport java.util.HashSet; 48b8a72a62Sopenharmony_ciimport java.util.List; 49b8a72a62Sopenharmony_ciimport java.util.Locale; 50b8a72a62Sopenharmony_ciimport java.util.Set; 51b8a72a62Sopenharmony_ciimport java.util.concurrent.ExecutionException; 52b8a72a62Sopenharmony_ciimport java.util.concurrent.LinkedBlockingQueue; 53b8a72a62Sopenharmony_ciimport java.util.concurrent.ThreadPoolExecutor; 54b8a72a62Sopenharmony_ciimport java.util.concurrent.TimeUnit; 55b8a72a62Sopenharmony_ciimport java.util.stream.Stream; 56b8a72a62Sopenharmony_ciimport java.util.zip.CRC32; 57b8a72a62Sopenharmony_ciimport java.util.zip.CheckedOutputStream; 58b8a72a62Sopenharmony_ciimport java.util.zip.ZipEntry; 59b8a72a62Sopenharmony_ciimport java.util.zip.ZipOutputStream; 60b8a72a62Sopenharmony_ci 61b8a72a62Sopenharmony_ci/** 62b8a72a62Sopenharmony_ci * PackageUtil 63b8a72a62Sopenharmony_ci * 64b8a72a62Sopenharmony_ci * @since 2024-06-18 65b8a72a62Sopenharmony_ci */ 66b8a72a62Sopenharmony_cipublic class PackageUtil { 67b8a72a62Sopenharmony_ci private static final Log LOG = new Log(""); 68b8a72a62Sopenharmony_ci 69b8a72a62Sopenharmony_ci /** 70b8a72a62Sopenharmony_ci * get the package name list from pack.info 71b8a72a62Sopenharmony_ci * 72b8a72a62Sopenharmony_ci * @param path the path dir or hsp contains pack.info, or the path of pack.info 73b8a72a62Sopenharmony_ci * @return the list of package name 74b8a72a62Sopenharmony_ci */ 75b8a72a62Sopenharmony_ci public static List<String> getPackageNameFromPath(Path path) { 76b8a72a62Sopenharmony_ci List<String> list = new ArrayList<>(); 77b8a72a62Sopenharmony_ci if (!Files.exists(path)) { 78b8a72a62Sopenharmony_ci LOG.warning("getPackageNameFromPath path not exists: " + path); 79b8a72a62Sopenharmony_ci return list; 80b8a72a62Sopenharmony_ci } 81b8a72a62Sopenharmony_ci if (Files.isRegularFile(path)) { 82b8a72a62Sopenharmony_ci String filename = path.getFileName().toString(); 83b8a72a62Sopenharmony_ci if (filename.endsWith(Constants.HSP_SUFFIX)) { 84b8a72a62Sopenharmony_ci // .hsp: return filename 85b8a72a62Sopenharmony_ci list.add(filename.substring(0, filename.lastIndexOf(Constants.HSP_SUFFIX))); 86b8a72a62Sopenharmony_ci return list; 87b8a72a62Sopenharmony_ci } 88b8a72a62Sopenharmony_ci } 89b8a72a62Sopenharmony_ci String content = getPackInfoContentFromPath(path); 90b8a72a62Sopenharmony_ci if (content == null) { 91b8a72a62Sopenharmony_ci return list; 92b8a72a62Sopenharmony_ci } 93b8a72a62Sopenharmony_ci return getPackageNameFromPackInfo(content); 94b8a72a62Sopenharmony_ci } 95b8a72a62Sopenharmony_ci 96b8a72a62Sopenharmony_ci /** 97b8a72a62Sopenharmony_ci * get the package name list from module.json 98b8a72a62Sopenharmony_ci * 99b8a72a62Sopenharmony_ci * @param path the path dir or hsp contains module.json, or the path of module.json 100b8a72a62Sopenharmony_ci * @return the bundleType 101b8a72a62Sopenharmony_ci */ 102b8a72a62Sopenharmony_ci public static String getBundleTypeFromPath(Path path) { 103b8a72a62Sopenharmony_ci if (!Files.exists(path)) { 104b8a72a62Sopenharmony_ci LOG.warning("getBundleTypeFromPath path not exists: " + path); 105b8a72a62Sopenharmony_ci return ""; 106b8a72a62Sopenharmony_ci } 107b8a72a62Sopenharmony_ci String content = getModuleJsonContentFromPath(path); 108b8a72a62Sopenharmony_ci if (content == null) { 109b8a72a62Sopenharmony_ci return ""; 110b8a72a62Sopenharmony_ci } 111b8a72a62Sopenharmony_ci return getBundleTypeFromModuleJson(content); 112b8a72a62Sopenharmony_ci } 113b8a72a62Sopenharmony_ci 114b8a72a62Sopenharmony_ci /** 115b8a72a62Sopenharmony_ci * get the package name list from pack.info 116b8a72a62Sopenharmony_ci * 117b8a72a62Sopenharmony_ci * @param packInfoContent the content of pack.info 118b8a72a62Sopenharmony_ci * @return the list of package name 119b8a72a62Sopenharmony_ci */ 120b8a72a62Sopenharmony_ci public static List<String> getPackageNameFromPackInfo(String packInfoContent) { 121b8a72a62Sopenharmony_ci List<String> packages = new ArrayList<>(); 122b8a72a62Sopenharmony_ci try { 123b8a72a62Sopenharmony_ci JSONObject jsonObject = JSON.parseObject(packInfoContent, JSONObject.class); 124b8a72a62Sopenharmony_ci if (jsonObject == null) { 125b8a72a62Sopenharmony_ci LOG.warning("getPackagesFromPackInfo failed, json format invalid."); 126b8a72a62Sopenharmony_ci return packages; 127b8a72a62Sopenharmony_ci } 128b8a72a62Sopenharmony_ci JSONArray jsonArray = jsonObject.getJSONArray(Constants.PACKAGES); 129b8a72a62Sopenharmony_ci if (jsonArray == null) { 130b8a72a62Sopenharmony_ci LOG.warning("getPackagesFromPackInfo failed, json format invalid."); 131b8a72a62Sopenharmony_ci return packages; 132b8a72a62Sopenharmony_ci } 133b8a72a62Sopenharmony_ci for (int i = 0; i < jsonArray.size(); i++) { 134b8a72a62Sopenharmony_ci JSONObject object = jsonArray.getJSONObject(i); 135b8a72a62Sopenharmony_ci String packageName = object.getString(Constants.MODULE_NAME); 136b8a72a62Sopenharmony_ci if (packageName != null) { 137b8a72a62Sopenharmony_ci packages.add(packageName); 138b8a72a62Sopenharmony_ci } 139b8a72a62Sopenharmony_ci } 140b8a72a62Sopenharmony_ci return packages; 141b8a72a62Sopenharmony_ci } catch (JSONException ex) { 142b8a72a62Sopenharmony_ci LOG.warning("getPackagesFromPackInfo err: " + ex.getMessage()); 143b8a72a62Sopenharmony_ci return new ArrayList<>(); 144b8a72a62Sopenharmony_ci } 145b8a72a62Sopenharmony_ci } 146b8a72a62Sopenharmony_ci 147b8a72a62Sopenharmony_ci private static String getBundleTypeFromModuleJson(String moduleJsonContent) { 148b8a72a62Sopenharmony_ci try { 149b8a72a62Sopenharmony_ci JSONObject jsonObject = JSON.parseObject(moduleJsonContent, JSONObject.class); 150b8a72a62Sopenharmony_ci if (jsonObject == null) { 151b8a72a62Sopenharmony_ci LOG.warning("getBundleTypeFromModuleJson failed, parse json is null."); 152b8a72a62Sopenharmony_ci return ""; 153b8a72a62Sopenharmony_ci } 154b8a72a62Sopenharmony_ci JSONObject appObject = jsonObject.getJSONObject(Constants.APP); 155b8a72a62Sopenharmony_ci if (appObject == null) { 156b8a72a62Sopenharmony_ci LOG.warning("getBundleTypeFromModuleJson failed, [app] is null."); 157b8a72a62Sopenharmony_ci return ""; 158b8a72a62Sopenharmony_ci } 159b8a72a62Sopenharmony_ci String bundleType = appObject.getString(Constants.BUNDLE_TYPE); 160b8a72a62Sopenharmony_ci return bundleType != null ? bundleType : Constants.APP; 161b8a72a62Sopenharmony_ci } catch (JSONException ex) { 162b8a72a62Sopenharmony_ci LOG.warning("getBundleTypeFromModuleJson failed: " + ex.getMessage()); 163b8a72a62Sopenharmony_ci } 164b8a72a62Sopenharmony_ci return ""; 165b8a72a62Sopenharmony_ci } 166b8a72a62Sopenharmony_ci 167b8a72a62Sopenharmony_ci private static ModuleJsonInfo parseModuleJsonInfo(Path moduleJson) { 168b8a72a62Sopenharmony_ci ModuleJsonInfo moduleJsonInfo = new ModuleJsonInfo(); 169b8a72a62Sopenharmony_ci try (FileInputStream input = new FileInputStream(moduleJson.toFile())) { 170b8a72a62Sopenharmony_ci JSONObject jsonObject = JSON.parseObject(input, JSONObject.class); 171b8a72a62Sopenharmony_ci if (jsonObject == null) { 172b8a72a62Sopenharmony_ci LOG.warning("parseModuleJsonInfo failed, json format invalid."); 173b8a72a62Sopenharmony_ci return moduleJsonInfo; 174b8a72a62Sopenharmony_ci } 175b8a72a62Sopenharmony_ci JSONObject appObject = jsonObject.getJSONObject(Constants.APP); 176b8a72a62Sopenharmony_ci if (appObject == null) { 177b8a72a62Sopenharmony_ci LOG.warning("parseModuleJsonInfo failed, not found [app]"); 178b8a72a62Sopenharmony_ci return moduleJsonInfo; 179b8a72a62Sopenharmony_ci } 180b8a72a62Sopenharmony_ci JSONObject moduleObject = jsonObject.getJSONObject(Constants.MODULE); 181b8a72a62Sopenharmony_ci if (moduleObject == null) { 182b8a72a62Sopenharmony_ci LOG.warning("parseModuleJsonInfo failed, not found [module]"); 183b8a72a62Sopenharmony_ci return moduleJsonInfo; 184b8a72a62Sopenharmony_ci } 185b8a72a62Sopenharmony_ci moduleJsonInfo.setGenerateBuildHash( 186b8a72a62Sopenharmony_ci appObject.getBooleanValue(Constants.GENERATE_BUILD_HASH) || 187b8a72a62Sopenharmony_ci moduleObject.getBooleanValue(Constants.GENERATE_BUILD_HASH)); 188b8a72a62Sopenharmony_ci moduleJsonInfo.setCompressNativeLibs( 189b8a72a62Sopenharmony_ci moduleObject.getBooleanValue(Constants.COMPRESS_NATIVE_LIBS)); 190b8a72a62Sopenharmony_ci String moduleType = moduleObject.getString(Constants.MODULE_TYPE); 191b8a72a62Sopenharmony_ci moduleJsonInfo.setModuleType(moduleType != null ? moduleType : ""); 192b8a72a62Sopenharmony_ci String moduleName = moduleObject.getString(Constants.MODULE_NAME); 193b8a72a62Sopenharmony_ci moduleJsonInfo.setModuleName(moduleName != null ? moduleName : ""); 194b8a72a62Sopenharmony_ci return moduleJsonInfo; 195b8a72a62Sopenharmony_ci } catch (IOException ex) { 196b8a72a62Sopenharmony_ci LOG.warning("parseModuleJsonInfo err: " + ex.getMessage()); 197b8a72a62Sopenharmony_ci } 198b8a72a62Sopenharmony_ci return moduleJsonInfo; 199b8a72a62Sopenharmony_ci } 200b8a72a62Sopenharmony_ci 201b8a72a62Sopenharmony_ci private static String getPackInfoContentFromPath(Path path) { 202b8a72a62Sopenharmony_ci try { 203b8a72a62Sopenharmony_ci if (Files.isRegularFile(path)) { 204b8a72a62Sopenharmony_ci String filename = path.getFileName().toString(); 205b8a72a62Sopenharmony_ci if (filename.equals(Constants.FILE_PACK_INFO)) { 206b8a72a62Sopenharmony_ci return new String(Files.readAllBytes(path)); 207b8a72a62Sopenharmony_ci } else if (filename.endsWith(Constants.HSP_SUFFIX)) { 208b8a72a62Sopenharmony_ci return getZipEntryContent(path, Constants.FILE_PACK_INFO); 209b8a72a62Sopenharmony_ci } 210b8a72a62Sopenharmony_ci } else { 211b8a72a62Sopenharmony_ci return new String(Files.readAllBytes(path.resolve(Constants.FILE_PACK_INFO))); 212b8a72a62Sopenharmony_ci } 213b8a72a62Sopenharmony_ci } catch (IOException ex) { 214b8a72a62Sopenharmony_ci LOG.warning("getPackInfoContentFromPath err: " + ex.getMessage()); 215b8a72a62Sopenharmony_ci } 216b8a72a62Sopenharmony_ci return null; 217b8a72a62Sopenharmony_ci } 218b8a72a62Sopenharmony_ci 219b8a72a62Sopenharmony_ci private static String getModuleJsonContentFromPath(Path path) { 220b8a72a62Sopenharmony_ci try { 221b8a72a62Sopenharmony_ci if (Files.isRegularFile(path)) { 222b8a72a62Sopenharmony_ci String filename = path.getFileName().toString(); 223b8a72a62Sopenharmony_ci if (filename.equals(Constants.FILE_MODULE_JSON)) { 224b8a72a62Sopenharmony_ci return new String(Files.readAllBytes(path)); 225b8a72a62Sopenharmony_ci } else if (filename.endsWith(Constants.HSP_SUFFIX)) { 226b8a72a62Sopenharmony_ci return getZipEntryContent(path, Constants.FILE_MODULE_JSON); 227b8a72a62Sopenharmony_ci } 228b8a72a62Sopenharmony_ci } else { 229b8a72a62Sopenharmony_ci return new String(Files.readAllBytes(path.resolve(Constants.FILE_MODULE_JSON))); 230b8a72a62Sopenharmony_ci } 231b8a72a62Sopenharmony_ci } catch (IOException ex) { 232b8a72a62Sopenharmony_ci LOG.warning("getPackInfoContentFromPath err: " + ex.getMessage()); 233b8a72a62Sopenharmony_ci } 234b8a72a62Sopenharmony_ci return null; 235b8a72a62Sopenharmony_ci } 236b8a72a62Sopenharmony_ci 237b8a72a62Sopenharmony_ci private static String getZipEntryContent(Path zipPath, String entryName) { 238b8a72a62Sopenharmony_ci if (!Files.isRegularFile(zipPath)) { 239b8a72a62Sopenharmony_ci return null; 240b8a72a62Sopenharmony_ci } 241b8a72a62Sopenharmony_ci try (ZipFile zipFile = new ZipFile(zipPath.toFile()); 242b8a72a62Sopenharmony_ci ByteArrayOutputStream output = new ByteArrayOutputStream()) { 243b8a72a62Sopenharmony_ci ZipArchiveEntry zipEntry = zipFile.getEntry(entryName); 244b8a72a62Sopenharmony_ci if (zipEntry != null) { 245b8a72a62Sopenharmony_ci IOUtils.copy(zipFile.getInputStream(zipEntry), output); 246b8a72a62Sopenharmony_ci return output.toString(); 247b8a72a62Sopenharmony_ci } 248b8a72a62Sopenharmony_ci } catch (IOException ex) { 249b8a72a62Sopenharmony_ci LOG.warning("getZipEntryContent err: " + ex.getMessage()); 250b8a72a62Sopenharmony_ci } 251b8a72a62Sopenharmony_ci return null; 252b8a72a62Sopenharmony_ci } 253b8a72a62Sopenharmony_ci 254b8a72a62Sopenharmony_ci /** 255b8a72a62Sopenharmony_ci * pack hap or hsp 256b8a72a62Sopenharmony_ci * 257b8a72a62Sopenharmony_ci * @param inputPath input hap/hsp path 258b8a72a62Sopenharmony_ci * @param appPackInfo app scope pack.info 259b8a72a62Sopenharmony_ci * @param outPath output dir 260b8a72a62Sopenharmony_ci * @param compressLevel compress level 261b8a72a62Sopenharmony_ci * @return the hap/hsp path 262b8a72a62Sopenharmony_ci * @throws BundleException bundle exception 263b8a72a62Sopenharmony_ci * @throws IOException IO exception 264b8a72a62Sopenharmony_ci */ 265b8a72a62Sopenharmony_ci public static Path pack(Path inputPath, Path appPackInfo, Path outPath, int compressLevel) 266b8a72a62Sopenharmony_ci throws BundleException, IOException { 267b8a72a62Sopenharmony_ci if (!Files.exists(inputPath)) { 268b8a72a62Sopenharmony_ci throw new BundleException("pack err, input path not exists."); 269b8a72a62Sopenharmony_ci } 270b8a72a62Sopenharmony_ci if (!Files.exists(appPackInfo)) { 271b8a72a62Sopenharmony_ci throw new BundleException("pack err, app pack.info not exists."); 272b8a72a62Sopenharmony_ci } 273b8a72a62Sopenharmony_ci if (Files.isDirectory(inputPath)) { 274b8a72a62Sopenharmony_ci return packDir(inputPath, appPackInfo, outPath, compressLevel); 275b8a72a62Sopenharmony_ci } else if (Files.isRegularFile(inputPath) && 276b8a72a62Sopenharmony_ci inputPath.getFileName().toString().endsWith(Constants.HSP_SUFFIX)) { 277b8a72a62Sopenharmony_ci return repackHsp(inputPath, appPackInfo, outPath, compressLevel); 278b8a72a62Sopenharmony_ci } 279b8a72a62Sopenharmony_ci throw new BundleException("pack err, not support: " + inputPath); 280b8a72a62Sopenharmony_ci } 281b8a72a62Sopenharmony_ci 282b8a72a62Sopenharmony_ci /** 283b8a72a62Sopenharmony_ci * rm dir 284b8a72a62Sopenharmony_ci * 285b8a72a62Sopenharmony_ci * @param dir input path to rm 286b8a72a62Sopenharmony_ci * @return true if rm dir success 287b8a72a62Sopenharmony_ci */ 288b8a72a62Sopenharmony_ci public static boolean rmdir(Path dir) { 289b8a72a62Sopenharmony_ci try { 290b8a72a62Sopenharmony_ci Files.walkFileTree(dir, new SimpleFileVisitor<Path>() { 291b8a72a62Sopenharmony_ci @Override 292b8a72a62Sopenharmony_ci public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { 293b8a72a62Sopenharmony_ci Files.delete(file); 294b8a72a62Sopenharmony_ci return FileVisitResult.CONTINUE; 295b8a72a62Sopenharmony_ci } 296b8a72a62Sopenharmony_ci 297b8a72a62Sopenharmony_ci @Override 298b8a72a62Sopenharmony_ci public FileVisitResult postVisitDirectory(Path dir, IOException ex) throws IOException { 299b8a72a62Sopenharmony_ci Files.delete(dir); 300b8a72a62Sopenharmony_ci return FileVisitResult.CONTINUE; 301b8a72a62Sopenharmony_ci } 302b8a72a62Sopenharmony_ci }); 303b8a72a62Sopenharmony_ci return true; 304b8a72a62Sopenharmony_ci } catch (IOException ex) { 305b8a72a62Sopenharmony_ci LOG.warning("rmdir err: " + ex.getMessage()); 306b8a72a62Sopenharmony_ci } 307b8a72a62Sopenharmony_ci return false; 308b8a72a62Sopenharmony_ci } 309b8a72a62Sopenharmony_ci 310b8a72a62Sopenharmony_ci private static String hash(Path path) { 311b8a72a62Sopenharmony_ci try (Stream<Path> pathStream = Files.walk(path)) { 312b8a72a62Sopenharmony_ci MessageDigest md = MessageDigest.getInstance(Constants.SHA_256); 313b8a72a62Sopenharmony_ci pathStream.filter(Files::isRegularFile) 314b8a72a62Sopenharmony_ci .sorted() 315b8a72a62Sopenharmony_ci .forEach(file -> { 316b8a72a62Sopenharmony_ci try { 317b8a72a62Sopenharmony_ci byte[] fileBytes = Files.readAllBytes(file); 318b8a72a62Sopenharmony_ci md.update(fileBytes); 319b8a72a62Sopenharmony_ci } catch (IOException e) { 320b8a72a62Sopenharmony_ci LOG.warning("calc hash err: " + e.getMessage()); 321b8a72a62Sopenharmony_ci } 322b8a72a62Sopenharmony_ci }); 323b8a72a62Sopenharmony_ci byte[] hashBytes = md.digest(); 324b8a72a62Sopenharmony_ci StringBuilder sb = new StringBuilder(); 325b8a72a62Sopenharmony_ci for (byte b : hashBytes) { 326b8a72a62Sopenharmony_ci sb.append(String.format("%02x", b)); 327b8a72a62Sopenharmony_ci } 328b8a72a62Sopenharmony_ci return sb.toString(); 329b8a72a62Sopenharmony_ci } catch (NoSuchAlgorithmException | IOException e) { 330b8a72a62Sopenharmony_ci LOG.warning("calc hash err: " + e.getMessage()); 331b8a72a62Sopenharmony_ci } 332b8a72a62Sopenharmony_ci return ""; 333b8a72a62Sopenharmony_ci } 334b8a72a62Sopenharmony_ci 335b8a72a62Sopenharmony_ci private static Path repackHsp(Path inputPath, Path appPackInfo, Path outPath, int compressLevel) 336b8a72a62Sopenharmony_ci throws BundleException, IOException { 337b8a72a62Sopenharmony_ci Path outHsp = Files.createFile(outPath.resolve(inputPath.getFileName())); 338b8a72a62Sopenharmony_ci try (ZipFile hspFile = new ZipFile(inputPath.toFile()); 339b8a72a62Sopenharmony_ci ZipArchiveOutputStream zipOut = new ZipArchiveOutputStream( 340b8a72a62Sopenharmony_ci new CheckedOutputStream(Files.newOutputStream(outHsp), new CRC32()))) { 341b8a72a62Sopenharmony_ci int cores = Runtime.getRuntime().availableProcessors(); 342b8a72a62Sopenharmony_ci ThreadPoolExecutor executorService = new ThreadPoolExecutor(cores, cores, 60L, 343b8a72a62Sopenharmony_ci TimeUnit.SECONDS, new LinkedBlockingQueue<>()); 344b8a72a62Sopenharmony_ci ParallelScatterZipCreator zipCreator = new ParallelScatterZipCreator( 345b8a72a62Sopenharmony_ci executorService, new DefaultBackingStoreSupplier(null), compressLevel); 346b8a72a62Sopenharmony_ci // pack.info 347b8a72a62Sopenharmony_ci pathToZipEntry(appPackInfo, Constants.NULL_DIR, zipCreator, false); 348b8a72a62Sopenharmony_ci // others 349b8a72a62Sopenharmony_ci Enumeration<ZipArchiveEntry> entries = hspFile.getEntries(); 350b8a72a62Sopenharmony_ci while (entries.hasMoreElements()) { 351b8a72a62Sopenharmony_ci ZipArchiveEntry zipEntry = entries.nextElement(); 352b8a72a62Sopenharmony_ci if (Constants.FILE_PACK_INFO.equals(zipEntry.getName())) { 353b8a72a62Sopenharmony_ci continue; 354b8a72a62Sopenharmony_ci } 355b8a72a62Sopenharmony_ci InputStreamSupplier supplier = () -> { 356b8a72a62Sopenharmony_ci try { 357b8a72a62Sopenharmony_ci return hspFile.getInputStream(zipEntry); 358b8a72a62Sopenharmony_ci } catch (IOException e) { 359b8a72a62Sopenharmony_ci LOG.error("addArchiveEntry err: " + e.getMessage()); 360b8a72a62Sopenharmony_ci return null; 361b8a72a62Sopenharmony_ci } 362b8a72a62Sopenharmony_ci }; 363b8a72a62Sopenharmony_ci zipCreator.addArchiveEntry(zipEntry, supplier); 364b8a72a62Sopenharmony_ci } 365b8a72a62Sopenharmony_ci zipCreator.writeTo(zipOut); 366b8a72a62Sopenharmony_ci } catch (InterruptedException | ExecutionException e) { 367b8a72a62Sopenharmony_ci String errMsg = "repackHsp err: " + e.getMessage(); 368b8a72a62Sopenharmony_ci LOG.error(errMsg); 369b8a72a62Sopenharmony_ci throw new BundleException(errMsg); 370b8a72a62Sopenharmony_ci } 371b8a72a62Sopenharmony_ci return outHsp; 372b8a72a62Sopenharmony_ci } 373b8a72a62Sopenharmony_ci 374b8a72a62Sopenharmony_ci private static Path packDir(Path inputPath, Path appPackInfo, Path outPath, int compressLevel) 375b8a72a62Sopenharmony_ci throws BundleException, IOException { 376b8a72a62Sopenharmony_ci List<String> packageNames = getPackageNameFromPath(inputPath.resolve(Constants.FILE_PACK_INFO)); 377b8a72a62Sopenharmony_ci if (packageNames.size() != 1) { 378b8a72a62Sopenharmony_ci throw new BundleException("pack err, pack.info format err"); 379b8a72a62Sopenharmony_ci } 380b8a72a62Sopenharmony_ci ModuleJsonInfo moduleJsonInfo = parseModuleJsonInfo(inputPath.resolve(Constants.FILE_MODULE_JSON)); 381b8a72a62Sopenharmony_ci String pkgName = packageNames.get(0); 382b8a72a62Sopenharmony_ci String suffix = moduleJsonInfo.isShared() ? Constants.HSP_SUFFIX : Constants.HAP_SUFFIX; 383b8a72a62Sopenharmony_ci Path outHap = Files.createFile(outPath.resolve(pkgName + suffix)); 384b8a72a62Sopenharmony_ci 385b8a72a62Sopenharmony_ci if (moduleJsonInfo.isCompressNativeLibs()) { 386b8a72a62Sopenharmony_ci return packMultiThread(inputPath, appPackInfo, outHap, compressLevel, moduleJsonInfo); 387b8a72a62Sopenharmony_ci } else { 388b8a72a62Sopenharmony_ci return packSingleThread(inputPath, appPackInfo, outHap, moduleJsonInfo); 389b8a72a62Sopenharmony_ci } 390b8a72a62Sopenharmony_ci } 391b8a72a62Sopenharmony_ci 392b8a72a62Sopenharmony_ci private static Path packSingleThread(Path inputPath, Path appPackInfo, Path outHap, ModuleJsonInfo moduleJsonInfo) 393b8a72a62Sopenharmony_ci throws BundleException, IOException { 394b8a72a62Sopenharmony_ci File[] files = inputPath.toFile().listFiles(); 395b8a72a62Sopenharmony_ci if (files == null || files.length == 0) { 396b8a72a62Sopenharmony_ci throw new BundleException("pack err, dir is empty"); 397b8a72a62Sopenharmony_ci } 398b8a72a62Sopenharmony_ci try (ZipOutputStream zipOut = new ZipOutputStream( 399b8a72a62Sopenharmony_ci new CheckedOutputStream(Files.newOutputStream(outHap), new CRC32()))) { 400b8a72a62Sopenharmony_ci // pack.info 401b8a72a62Sopenharmony_ci pathToZipEntry(appPackInfo, Constants.NULL_DIR, zipOut, false); 402b8a72a62Sopenharmony_ci // module.json generateBuildHash 403b8a72a62Sopenharmony_ci if (moduleJsonInfo.isGenerateBuildHash()) { 404b8a72a62Sopenharmony_ci genBuildHash(inputPath, zipOut); 405b8a72a62Sopenharmony_ci } 406b8a72a62Sopenharmony_ci // others 407b8a72a62Sopenharmony_ci filesToZipEntry(files, zipOut, moduleJsonInfo.isGenerateBuildHash(), 408b8a72a62Sopenharmony_ci moduleJsonInfo.isCompressNativeLibs()); 409b8a72a62Sopenharmony_ci } 410b8a72a62Sopenharmony_ci return outHap; 411b8a72a62Sopenharmony_ci } 412b8a72a62Sopenharmony_ci 413b8a72a62Sopenharmony_ci private static Path packMultiThread(Path inputPath, Path appPackInfo, Path outHap, int compressLevel, 414b8a72a62Sopenharmony_ci ModuleJsonInfo moduleJsonInfo)throws BundleException, IOException { 415b8a72a62Sopenharmony_ci File[] files = inputPath.toFile().listFiles(); 416b8a72a62Sopenharmony_ci if (files == null || files.length == 0) { 417b8a72a62Sopenharmony_ci throw new BundleException("pack err, dir is empty"); 418b8a72a62Sopenharmony_ci } 419b8a72a62Sopenharmony_ci try (ZipArchiveOutputStream zipOut = new ZipArchiveOutputStream( 420b8a72a62Sopenharmony_ci new CheckedOutputStream(Files.newOutputStream(outHap), new CRC32()))) { 421b8a72a62Sopenharmony_ci int cores = Runtime.getRuntime().availableProcessors(); 422b8a72a62Sopenharmony_ci ThreadPoolExecutor executorService = new ThreadPoolExecutor(cores, cores, 60L, 423b8a72a62Sopenharmony_ci TimeUnit.SECONDS, new LinkedBlockingQueue<>()); 424b8a72a62Sopenharmony_ci ParallelScatterZipCreator zipCreator = new ParallelScatterZipCreator( 425b8a72a62Sopenharmony_ci executorService, new DefaultBackingStoreSupplier(null), compressLevel); 426b8a72a62Sopenharmony_ci // pack.info 427b8a72a62Sopenharmony_ci pathToZipEntry(appPackInfo, Constants.NULL_DIR, zipCreator, false); 428b8a72a62Sopenharmony_ci // module.json generateBuildHash 429b8a72a62Sopenharmony_ci if (moduleJsonInfo.isGenerateBuildHash()) { 430b8a72a62Sopenharmony_ci genBuildHash(inputPath, zipCreator); 431b8a72a62Sopenharmony_ci } 432b8a72a62Sopenharmony_ci // others 433b8a72a62Sopenharmony_ci filesToZipEntry(files, zipCreator, moduleJsonInfo.isGenerateBuildHash(), 434b8a72a62Sopenharmony_ci moduleJsonInfo.isCompressNativeLibs()); 435b8a72a62Sopenharmony_ci // write to zip 436b8a72a62Sopenharmony_ci zipCreator.writeTo(zipOut); 437b8a72a62Sopenharmony_ci } catch (InterruptedException | ExecutionException e) { 438b8a72a62Sopenharmony_ci String errMsg = "packDir err: " + e.getMessage(); 439b8a72a62Sopenharmony_ci LOG.error(errMsg); 440b8a72a62Sopenharmony_ci throw new BundleException(errMsg); 441b8a72a62Sopenharmony_ci } 442b8a72a62Sopenharmony_ci return outHap; 443b8a72a62Sopenharmony_ci } 444b8a72a62Sopenharmony_ci 445b8a72a62Sopenharmony_ci private static void filesToZipEntry(File[] files, ParallelScatterZipCreator zipCreator, 446b8a72a62Sopenharmony_ci boolean genHash, boolean compress) throws BundleException { 447b8a72a62Sopenharmony_ci for (File file : files) { 448b8a72a62Sopenharmony_ci if (file.isFile() && !file.getName().equals(Constants.FILE_PACK_INFO)) { 449b8a72a62Sopenharmony_ci if (genHash && file.getName().equals(Constants.FILE_MODULE_JSON)) { 450b8a72a62Sopenharmony_ci continue; 451b8a72a62Sopenharmony_ci } 452b8a72a62Sopenharmony_ci pathToZipEntry(file.toPath(), Constants.NULL_DIR, zipCreator, false); 453b8a72a62Sopenharmony_ci } else if (file.isDirectory()) { 454b8a72a62Sopenharmony_ci if (file.getName().equals(Constants.LIBS_DIR)) { 455b8a72a62Sopenharmony_ci pathToZipEntry(file.toPath(), Constants.LIBS_DIR + Constants.SLASH, zipCreator, compress); 456b8a72a62Sopenharmony_ci } else { 457b8a72a62Sopenharmony_ci pathToZipEntry(file.toPath(), file.getName() + Constants.SLASH, zipCreator, false); 458b8a72a62Sopenharmony_ci } 459b8a72a62Sopenharmony_ci } 460b8a72a62Sopenharmony_ci } 461b8a72a62Sopenharmony_ci } 462b8a72a62Sopenharmony_ci 463b8a72a62Sopenharmony_ci private static void genBuildHash(Path path, ParallelScatterZipCreator zipCreator) { 464b8a72a62Sopenharmony_ci String hash = hash(path); 465b8a72a62Sopenharmony_ci if (hash.isEmpty()) { 466b8a72a62Sopenharmony_ci return; 467b8a72a62Sopenharmony_ci } 468b8a72a62Sopenharmony_ci Path moduleJson = path.resolve(Constants.FILE_MODULE_JSON); 469b8a72a62Sopenharmony_ci if (!Files.exists(moduleJson)) { 470b8a72a62Sopenharmony_ci LOG.warning("module.json not found: " + path); 471b8a72a62Sopenharmony_ci return; 472b8a72a62Sopenharmony_ci } 473b8a72a62Sopenharmony_ci try (FileInputStream input = new FileInputStream(moduleJson.toFile())) { 474b8a72a62Sopenharmony_ci JSONObject jsonObject = JSON.parseObject(input, JSONObject.class); 475b8a72a62Sopenharmony_ci if (jsonObject == null) { 476b8a72a62Sopenharmony_ci LOG.warning("generateBuildHash: parse json is null."); 477b8a72a62Sopenharmony_ci return; 478b8a72a62Sopenharmony_ci } 479b8a72a62Sopenharmony_ci JSONObject moduleObject = jsonObject.getJSONObject(Constants.MODULE); 480b8a72a62Sopenharmony_ci if (moduleObject == null) { 481b8a72a62Sopenharmony_ci LOG.warning("generateBuildHash: parse json[module] is null."); 482b8a72a62Sopenharmony_ci return; 483b8a72a62Sopenharmony_ci } 484b8a72a62Sopenharmony_ci moduleObject.put(Constants.BUILD_HASH, hash); 485b8a72a62Sopenharmony_ci byte[] data = JSON.toJSONBytes(jsonObject, SerializerFeature.WriteMapNullValue, 486b8a72a62Sopenharmony_ci SerializerFeature.WriteDateUseDateFormat, SerializerFeature.SortField); 487b8a72a62Sopenharmony_ci ZipArchiveEntry zipEntry = new ZipArchiveEntry(Constants.FILE_MODULE_JSON); 488b8a72a62Sopenharmony_ci zipEntry.setMethod(ZipArchiveEntry.STORED); 489b8a72a62Sopenharmony_ci InputStreamSupplier supplier = () -> new ByteArrayInputStream(data); 490b8a72a62Sopenharmony_ci zipCreator.addArchiveEntry(zipEntry, supplier); 491b8a72a62Sopenharmony_ci } catch (IOException ex) { 492b8a72a62Sopenharmony_ci LOG.warning("genBuildHash err: " + ex.getMessage()); 493b8a72a62Sopenharmony_ci } 494b8a72a62Sopenharmony_ci } 495b8a72a62Sopenharmony_ci 496b8a72a62Sopenharmony_ci private static void pathToZipEntry(Path path, String baseDir, ParallelScatterZipCreator zipCreator, 497b8a72a62Sopenharmony_ci boolean compress) throws BundleException { 498b8a72a62Sopenharmony_ci try { 499b8a72a62Sopenharmony_ci File file = path.toFile(); 500b8a72a62Sopenharmony_ci if (file.isDirectory()) { 501b8a72a62Sopenharmony_ci File[] files = file.listFiles(); 502b8a72a62Sopenharmony_ci if (files == null) { 503b8a72a62Sopenharmony_ci return; 504b8a72a62Sopenharmony_ci } 505b8a72a62Sopenharmony_ci for (File f : files) { 506b8a72a62Sopenharmony_ci addArchiveEntry(f, baseDir, zipCreator, compress); 507b8a72a62Sopenharmony_ci } 508b8a72a62Sopenharmony_ci } else { 509b8a72a62Sopenharmony_ci addArchiveEntry(file, baseDir, zipCreator, compress); 510b8a72a62Sopenharmony_ci } 511b8a72a62Sopenharmony_ci } catch (IOException e) { 512b8a72a62Sopenharmony_ci String errMsg = "pathToZip err: " + e.getMessage(); 513b8a72a62Sopenharmony_ci LOG.error(errMsg); 514b8a72a62Sopenharmony_ci throw new BundleException(errMsg); 515b8a72a62Sopenharmony_ci } 516b8a72a62Sopenharmony_ci } 517b8a72a62Sopenharmony_ci 518b8a72a62Sopenharmony_ci private static void addArchiveEntry(File file, String baseDir, ParallelScatterZipCreator zipCreator, 519b8a72a62Sopenharmony_ci boolean compress) 520b8a72a62Sopenharmony_ci throws IOException { 521b8a72a62Sopenharmony_ci if (file.isDirectory()) { 522b8a72a62Sopenharmony_ci File[] files = file.listFiles(); 523b8a72a62Sopenharmony_ci if (files == null) { 524b8a72a62Sopenharmony_ci LOG.error("listFiles null: " + file.getName()); 525b8a72a62Sopenharmony_ci return; 526b8a72a62Sopenharmony_ci } 527b8a72a62Sopenharmony_ci if (files.length == 0) { 528b8a72a62Sopenharmony_ci String entryName = (baseDir + file.getName() + File.separator) 529b8a72a62Sopenharmony_ci .replace(File.separator, Constants.SLASH); 530b8a72a62Sopenharmony_ci ZipArchiveEntry zipEntry = new ZipArchiveEntry(entryName); 531b8a72a62Sopenharmony_ci zipEntry.setMethod(ZipArchiveEntry.STORED); 532b8a72a62Sopenharmony_ci zipEntry.setSize(0); 533b8a72a62Sopenharmony_ci zipEntry.setCrc(0); 534b8a72a62Sopenharmony_ci InputStreamSupplier supplier = () -> new ByteArrayInputStream(new byte[0]); 535b8a72a62Sopenharmony_ci zipCreator.addArchiveEntry(zipEntry, supplier); 536b8a72a62Sopenharmony_ci } 537b8a72a62Sopenharmony_ci for (File f : files) { 538b8a72a62Sopenharmony_ci addArchiveEntry(f, baseDir + file.getName() + File.separator, zipCreator, compress); 539b8a72a62Sopenharmony_ci } 540b8a72a62Sopenharmony_ci } else { 541b8a72a62Sopenharmony_ci String entryName = (baseDir + file.getName()).replace(File.separator, Constants.SLASH); 542b8a72a62Sopenharmony_ci ZipArchiveEntry zipEntry = new ZipArchiveEntry(entryName); 543b8a72a62Sopenharmony_ci if (compress) { 544b8a72a62Sopenharmony_ci zipEntry.setMethod(ZipArchiveEntry.DEFLATED); 545b8a72a62Sopenharmony_ci } else { 546b8a72a62Sopenharmony_ci zipEntry.setMethod(ZipArchiveEntry.STORED); 547b8a72a62Sopenharmony_ci } 548b8a72a62Sopenharmony_ci InputStreamSupplier supplier = () -> { 549b8a72a62Sopenharmony_ci try { 550b8a72a62Sopenharmony_ci return getInputStream(entryName, file); 551b8a72a62Sopenharmony_ci } catch (IOException e) { 552b8a72a62Sopenharmony_ci LOG.error("addArchiveEntry err: " + e.getMessage()); 553b8a72a62Sopenharmony_ci return null; 554b8a72a62Sopenharmony_ci } 555b8a72a62Sopenharmony_ci }; 556b8a72a62Sopenharmony_ci zipCreator.addArchiveEntry(zipEntry, supplier); 557b8a72a62Sopenharmony_ci } 558b8a72a62Sopenharmony_ci } 559b8a72a62Sopenharmony_ci 560b8a72a62Sopenharmony_ci private static InputStream getInputStream(String entryName, File file) throws IOException { 561b8a72a62Sopenharmony_ci if (!entryName.contains(Constants.RAW_FILE_PATH) && !entryName.contains(Constants.RES_FILE_PATH) && 562b8a72a62Sopenharmony_ci file.getName().toLowerCase(Locale.ENGLISH).endsWith(Constants.JSON_SUFFIX)) { 563b8a72a62Sopenharmony_ci try { 564b8a72a62Sopenharmony_ci Object jsonObject = JSON.parse(Files.readAllBytes(file.toPath())); 565b8a72a62Sopenharmony_ci byte[] data = JSON.toJSONBytes(jsonObject, 566b8a72a62Sopenharmony_ci SerializerFeature.WriteMapNullValue, SerializerFeature.WriteDateUseDateFormat); 567b8a72a62Sopenharmony_ci return new ByteArrayInputStream(data); 568b8a72a62Sopenharmony_ci } catch (JSONException ex) { 569b8a72a62Sopenharmony_ci LOG.warning("json format err: " + file.getName()); 570b8a72a62Sopenharmony_ci } 571b8a72a62Sopenharmony_ci } 572b8a72a62Sopenharmony_ci return Files.newInputStream(file.toPath()); 573b8a72a62Sopenharmony_ci } 574b8a72a62Sopenharmony_ci 575b8a72a62Sopenharmony_ci private static void filesToZipEntry(File[] files, ZipOutputStream zipOut, boolean genHash, boolean compress) 576b8a72a62Sopenharmony_ci throws BundleException { 577b8a72a62Sopenharmony_ci for (File file : files) { 578b8a72a62Sopenharmony_ci if (file.isFile() && !file.getName().equals(Constants.FILE_PACK_INFO)) { 579b8a72a62Sopenharmony_ci if (genHash && file.getName().equals(Constants.FILE_MODULE_JSON)) { 580b8a72a62Sopenharmony_ci continue; 581b8a72a62Sopenharmony_ci } 582b8a72a62Sopenharmony_ci pathToZipEntry(file.toPath(), Constants.NULL_DIR, zipOut, false); 583b8a72a62Sopenharmony_ci } else if (file.isDirectory()) { 584b8a72a62Sopenharmony_ci if (file.getName().equals(Constants.LIBS_DIR)) { 585b8a72a62Sopenharmony_ci pathToZipEntry(file.toPath(), Constants.LIBS_DIR + Constants.SLASH, zipOut, compress); 586b8a72a62Sopenharmony_ci } else { 587b8a72a62Sopenharmony_ci pathToZipEntry(file.toPath(), file.getName() + Constants.SLASH, zipOut, false); 588b8a72a62Sopenharmony_ci } 589b8a72a62Sopenharmony_ci } 590b8a72a62Sopenharmony_ci } 591b8a72a62Sopenharmony_ci } 592b8a72a62Sopenharmony_ci 593b8a72a62Sopenharmony_ci private static void genBuildHash(Path path, ZipOutputStream zipOut) { 594b8a72a62Sopenharmony_ci String hash = hash(path); 595b8a72a62Sopenharmony_ci if (hash.isEmpty()) { 596b8a72a62Sopenharmony_ci return; 597b8a72a62Sopenharmony_ci } 598b8a72a62Sopenharmony_ci Path moduleJson = path.resolve(Constants.FILE_MODULE_JSON); 599b8a72a62Sopenharmony_ci if (!Files.exists(moduleJson)) { 600b8a72a62Sopenharmony_ci LOG.warning("module.json not found: " + path); 601b8a72a62Sopenharmony_ci return; 602b8a72a62Sopenharmony_ci } 603b8a72a62Sopenharmony_ci try (FileInputStream input = new FileInputStream(moduleJson.toFile())) { 604b8a72a62Sopenharmony_ci JSONObject jsonObject = JSON.parseObject(input, JSONObject.class); 605b8a72a62Sopenharmony_ci if (jsonObject == null) { 606b8a72a62Sopenharmony_ci LOG.warning("generateBuildHash: parse json is null."); 607b8a72a62Sopenharmony_ci return; 608b8a72a62Sopenharmony_ci } 609b8a72a62Sopenharmony_ci JSONObject moduleObject = jsonObject.getJSONObject(Constants.MODULE); 610b8a72a62Sopenharmony_ci if (moduleObject == null) { 611b8a72a62Sopenharmony_ci LOG.warning("generateBuildHash: parse json[module] is null."); 612b8a72a62Sopenharmony_ci return; 613b8a72a62Sopenharmony_ci } 614b8a72a62Sopenharmony_ci moduleObject.put(Constants.BUILD_HASH, hash); 615b8a72a62Sopenharmony_ci byte[] data = JSON.toJSONBytes(jsonObject, SerializerFeature.WriteMapNullValue, 616b8a72a62Sopenharmony_ci SerializerFeature.WriteDateUseDateFormat, SerializerFeature.SortField); 617b8a72a62Sopenharmony_ci CRC32 crc32 = new CRC32(); 618b8a72a62Sopenharmony_ci crc32.update(data, 0, data.length); 619b8a72a62Sopenharmony_ci ZipEntry zipEntry = new ZipEntry(Constants.FILE_MODULE_JSON); 620b8a72a62Sopenharmony_ci zipEntry.setMethod(ZipEntry.STORED); 621b8a72a62Sopenharmony_ci zipEntry.setCompressedSize(data.length); 622b8a72a62Sopenharmony_ci zipEntry.setCrc(crc32.getValue()); 623b8a72a62Sopenharmony_ci zipOut.putNextEntry(zipEntry); 624b8a72a62Sopenharmony_ci try (InputStream inputStream = new ByteArrayInputStream(data)) { 625b8a72a62Sopenharmony_ci IOUtils.copy(inputStream, zipOut, Constants.BUFFER_SIZE); 626b8a72a62Sopenharmony_ci } 627b8a72a62Sopenharmony_ci zipOut.closeEntry(); 628b8a72a62Sopenharmony_ci } catch (IOException ex) { 629b8a72a62Sopenharmony_ci LOG.warning("genBuildHash err: " + ex.getMessage()); 630b8a72a62Sopenharmony_ci } 631b8a72a62Sopenharmony_ci } 632b8a72a62Sopenharmony_ci 633b8a72a62Sopenharmony_ci private static void pathToZipEntry(Path path, String baseDir, ZipOutputStream zipOut, 634b8a72a62Sopenharmony_ci boolean compress) throws BundleException { 635b8a72a62Sopenharmony_ci try { 636b8a72a62Sopenharmony_ci File file = path.toFile(); 637b8a72a62Sopenharmony_ci if (file.isDirectory()) { 638b8a72a62Sopenharmony_ci File[] files = file.listFiles(); 639b8a72a62Sopenharmony_ci if (files == null) { 640b8a72a62Sopenharmony_ci return; 641b8a72a62Sopenharmony_ci } 642b8a72a62Sopenharmony_ci for (File f : files) { 643b8a72a62Sopenharmony_ci addArchiveEntry(f, baseDir, zipOut, compress); 644b8a72a62Sopenharmony_ci } 645b8a72a62Sopenharmony_ci } else { 646b8a72a62Sopenharmony_ci addArchiveEntry(file, baseDir, zipOut, compress); 647b8a72a62Sopenharmony_ci } 648b8a72a62Sopenharmony_ci } catch (IOException e) { 649b8a72a62Sopenharmony_ci String errMsg = "pathToZip err: " + e.getMessage(); 650b8a72a62Sopenharmony_ci LOG.error(errMsg); 651b8a72a62Sopenharmony_ci throw new BundleException(errMsg); 652b8a72a62Sopenharmony_ci } 653b8a72a62Sopenharmony_ci } 654b8a72a62Sopenharmony_ci 655b8a72a62Sopenharmony_ci private static void addArchiveEntry(File file, String baseDir, ZipOutputStream zipOut, boolean compress) 656b8a72a62Sopenharmony_ci throws IOException, BundleException { 657b8a72a62Sopenharmony_ci if (file.isDirectory()) { 658b8a72a62Sopenharmony_ci File[] files = file.listFiles(); 659b8a72a62Sopenharmony_ci if (files == null) { 660b8a72a62Sopenharmony_ci LOG.error("listFiles null: " + file.getName()); 661b8a72a62Sopenharmony_ci return; 662b8a72a62Sopenharmony_ci } 663b8a72a62Sopenharmony_ci if (files.length == 0) { 664b8a72a62Sopenharmony_ci String entryName = (baseDir + file.getName() + File.separator) 665b8a72a62Sopenharmony_ci .replace(File.separator, Constants.SLASH); 666b8a72a62Sopenharmony_ci ZipEntry zipEntry = new ZipEntry(entryName); 667b8a72a62Sopenharmony_ci zipEntry.setMethod(ZipEntry.STORED); 668b8a72a62Sopenharmony_ci zipEntry.setSize(0); 669b8a72a62Sopenharmony_ci zipEntry.setCrc(0); 670b8a72a62Sopenharmony_ci zipOut.putNextEntry(zipEntry); 671b8a72a62Sopenharmony_ci zipOut.closeEntry(); 672b8a72a62Sopenharmony_ci } 673b8a72a62Sopenharmony_ci for (File f : files) { 674b8a72a62Sopenharmony_ci addArchiveEntry(f, baseDir + file.getName() + File.separator, zipOut, compress); 675b8a72a62Sopenharmony_ci } 676b8a72a62Sopenharmony_ci } else { 677b8a72a62Sopenharmony_ci String entryName = (baseDir + file.getName()).replace(File.separator, Constants.SLASH); 678b8a72a62Sopenharmony_ci ZipEntry zipEntry = new ZipEntry(entryName); 679b8a72a62Sopenharmony_ci if (compress) { 680b8a72a62Sopenharmony_ci zipEntry.setMethod(ZipEntry.DEFLATED); 681b8a72a62Sopenharmony_ci } else { 682b8a72a62Sopenharmony_ci zipEntry.setMethod(ZipEntry.STORED); 683b8a72a62Sopenharmony_ci CRC32 crc32 = PackageNormalize.getCrcFromFile(file); 684b8a72a62Sopenharmony_ci zipEntry.setCrc(crc32.getValue()); 685b8a72a62Sopenharmony_ci zipEntry.setCompressedSize(file.length()); 686b8a72a62Sopenharmony_ci } 687b8a72a62Sopenharmony_ci zipOut.putNextEntry(zipEntry); 688b8a72a62Sopenharmony_ci try (InputStream input = Files.newInputStream(file.toPath())) { 689b8a72a62Sopenharmony_ci IOUtils.copy(input, zipOut, Constants.BUFFER_SIZE); 690b8a72a62Sopenharmony_ci } 691b8a72a62Sopenharmony_ci zipOut.closeEntry(); 692b8a72a62Sopenharmony_ci } 693b8a72a62Sopenharmony_ci } 694b8a72a62Sopenharmony_ci 695b8a72a62Sopenharmony_ci private static boolean checkBundleTypeConsistency(List<String> hapPathList, List<String> hspPathList, 696b8a72a62Sopenharmony_ci Utility utility) { 697b8a72a62Sopenharmony_ci String bundleType = ""; 698b8a72a62Sopenharmony_ci if (!hapPathList.isEmpty()) { 699b8a72a62Sopenharmony_ci bundleType = getBundleTypeFromPath(Paths.get(hapPathList.get(0))); 700b8a72a62Sopenharmony_ci } else if (!hspPathList.isEmpty()) { 701b8a72a62Sopenharmony_ci bundleType = getBundleTypeFromPath(Paths.get(hspPathList.get(0))); 702b8a72a62Sopenharmony_ci } 703b8a72a62Sopenharmony_ci if (bundleType == null || bundleType.isEmpty()) { 704b8a72a62Sopenharmony_ci return false; 705b8a72a62Sopenharmony_ci } 706b8a72a62Sopenharmony_ci for (String hapPath : hapPathList) { 707b8a72a62Sopenharmony_ci if (!bundleType.equals(getBundleTypeFromPath(Paths.get(hapPath)))) { 708b8a72a62Sopenharmony_ci LOG.error("bundleType is not same"); 709b8a72a62Sopenharmony_ci return false; 710b8a72a62Sopenharmony_ci } 711b8a72a62Sopenharmony_ci } 712b8a72a62Sopenharmony_ci for (String hspPath : hspPathList) { 713b8a72a62Sopenharmony_ci if (!bundleType.equals(getBundleTypeFromPath(Paths.get(hspPath)))) { 714b8a72a62Sopenharmony_ci LOG.error("bundleType is not same"); 715b8a72a62Sopenharmony_ci return false; 716b8a72a62Sopenharmony_ci } 717b8a72a62Sopenharmony_ci } 718b8a72a62Sopenharmony_ci if (bundleType.equals(Constants.BUNDLE_TYPE_SHARED)) { 719b8a72a62Sopenharmony_ci utility.setIsSharedApp(true); 720b8a72a62Sopenharmony_ci } 721b8a72a62Sopenharmony_ci return true; 722b8a72a62Sopenharmony_ci } 723b8a72a62Sopenharmony_ci 724b8a72a62Sopenharmony_ci private static boolean moduleJsonAndPackInfoExists(List<String> hapPathList, List<String> hspPathList) { 725b8a72a62Sopenharmony_ci for (String hapPath : hapPathList) { 726b8a72a62Sopenharmony_ci Path path = Paths.get(hapPath); 727b8a72a62Sopenharmony_ci if (!Files.exists(path.resolve(Constants.FILE_MODULE_JSON))) { 728b8a72a62Sopenharmony_ci LOG.error("not found module.json in path: " + path); 729b8a72a62Sopenharmony_ci return false; 730b8a72a62Sopenharmony_ci } 731b8a72a62Sopenharmony_ci if (!Files.exists(path.resolve(Constants.FILE_PACK_INFO))) { 732b8a72a62Sopenharmony_ci LOG.error("not found pack.info in path: " + path); 733b8a72a62Sopenharmony_ci return false; 734b8a72a62Sopenharmony_ci } 735b8a72a62Sopenharmony_ci } 736b8a72a62Sopenharmony_ci for (String hspPath : hspPathList) { 737b8a72a62Sopenharmony_ci Path path = Paths.get(hspPath); 738b8a72a62Sopenharmony_ci if (Files.isDirectory(path)) { 739b8a72a62Sopenharmony_ci if (!Files.exists(path.resolve(Constants.FILE_MODULE_JSON))) { 740b8a72a62Sopenharmony_ci LOG.error("not found module.json in path: " + path); 741b8a72a62Sopenharmony_ci return false; 742b8a72a62Sopenharmony_ci } 743b8a72a62Sopenharmony_ci if (!Files.exists(path.resolve(Constants.FILE_PACK_INFO))) { 744b8a72a62Sopenharmony_ci LOG.error("not found pack.info in path: " + path); 745b8a72a62Sopenharmony_ci return false; 746b8a72a62Sopenharmony_ci } 747b8a72a62Sopenharmony_ci } 748b8a72a62Sopenharmony_ci } 749b8a72a62Sopenharmony_ci return true; 750b8a72a62Sopenharmony_ci } 751b8a72a62Sopenharmony_ci 752b8a72a62Sopenharmony_ci private static boolean isFileValid(String filePath, String suffix) { 753b8a72a62Sopenharmony_ci Path path = Paths.get(filePath); 754b8a72a62Sopenharmony_ci return Files.isRegularFile(path) && path.getFileName().toString().endsWith(suffix); 755b8a72a62Sopenharmony_ci } 756b8a72a62Sopenharmony_ci 757b8a72a62Sopenharmony_ci private static boolean isDirValid(String filePath) { 758b8a72a62Sopenharmony_ci return Files.isDirectory(Paths.get(filePath)); 759b8a72a62Sopenharmony_ci } 760b8a72a62Sopenharmony_ci 761b8a72a62Sopenharmony_ci /** 762b8a72a62Sopenharmony_ci * verify input param 763b8a72a62Sopenharmony_ci * 764b8a72a62Sopenharmony_ci * @param utility common data 765b8a72a62Sopenharmony_ci * @return true if verify ok 766b8a72a62Sopenharmony_ci */ 767b8a72a62Sopenharmony_ci public static boolean isVerifyValidInFastAppMode(Utility utility) { 768b8a72a62Sopenharmony_ci if (!isVerifyValid(utility)) { 769b8a72a62Sopenharmony_ci return false; 770b8a72a62Sopenharmony_ci } 771b8a72a62Sopenharmony_ci if (!utility.getHapPath().isEmpty() && 772b8a72a62Sopenharmony_ci (!isFormatPathValid(utility.getHapPath(), utility.getFormattedHapPathList()) || 773b8a72a62Sopenharmony_ci !isHapPathValid(utility.getFormattedHapPathList()))) { 774b8a72a62Sopenharmony_ci LOG.error("CompressVerify::isVerifyValidInFastAppMode hap-path is invalid."); 775b8a72a62Sopenharmony_ci return false; 776b8a72a62Sopenharmony_ci } 777b8a72a62Sopenharmony_ci if (!utility.getHspPath().isEmpty() && 778b8a72a62Sopenharmony_ci (!isFormatPathValid(utility.getHspPath(), utility.getFormattedHspPathList()) || 779b8a72a62Sopenharmony_ci !isHspPathValid(utility.getFormattedHspPathList()))) { 780b8a72a62Sopenharmony_ci LOG.error("CompressVerify::isVerifyValidInFastAppMode hsp-path is invalid."); 781b8a72a62Sopenharmony_ci return false; 782b8a72a62Sopenharmony_ci } 783b8a72a62Sopenharmony_ci if (utility.getHapPath().isEmpty() && utility.getHspPath().isEmpty()) { 784b8a72a62Sopenharmony_ci LOG.error("CompressVerify::isVerifyValidInFastAppMode hap-path and hsp-path is empty."); 785b8a72a62Sopenharmony_ci return false; 786b8a72a62Sopenharmony_ci } 787b8a72a62Sopenharmony_ci if (!moduleJsonAndPackInfoExists(utility.getFormattedHapPathList(), utility.getFormattedHspPathList())) { 788b8a72a62Sopenharmony_ci LOG.error("CompressVerify::isVerifyValidInFastAppMode hap-path or hsp-path is invalid."); 789b8a72a62Sopenharmony_ci return false; 790b8a72a62Sopenharmony_ci } 791b8a72a62Sopenharmony_ci if (!checkBundleTypeConsistency( 792b8a72a62Sopenharmony_ci utility.getFormattedHapPathList(), utility.getFormattedHspPathList(), utility)) { 793b8a72a62Sopenharmony_ci LOG.error("CompressVerify::isVerifyValidInFastAppMode bundleType is inconsistent."); 794b8a72a62Sopenharmony_ci return false; 795b8a72a62Sopenharmony_ci } 796b8a72a62Sopenharmony_ci if (!isPackInfoValid(Paths.get(utility.getPackInfoPath()), 797b8a72a62Sopenharmony_ci utility.getFormattedHapPathList(), utility.getFormattedHspPathList())) { 798b8a72a62Sopenharmony_ci LOG.error("CompressVerify::isVerifyValidInFastAppMode pack.info is invalid."); 799b8a72a62Sopenharmony_ci return false; 800b8a72a62Sopenharmony_ci } 801b8a72a62Sopenharmony_ci if (!utility.getEncryptPath().isEmpty() 802b8a72a62Sopenharmony_ci && !isFileValid(utility.getEncryptPath(), Constants.FILE_ENCRYPT_JSON)) { 803b8a72a62Sopenharmony_ci LOG.error("CompressVerify::isVerifyValidInFastAppMode encrypt-path is invalid."); 804b8a72a62Sopenharmony_ci return false; 805b8a72a62Sopenharmony_ci } 806b8a72a62Sopenharmony_ci Path outPath = Paths.get(utility.getOutPath()); 807b8a72a62Sopenharmony_ci if (utility.getForceRewrite().equals(Constants.FALSE) && Files.exists(outPath)) { 808b8a72a62Sopenharmony_ci LOG.error("CompressVerify::isVerifyValidInFastAppMode out file already existed."); 809b8a72a62Sopenharmony_ci return false; 810b8a72a62Sopenharmony_ci } 811b8a72a62Sopenharmony_ci if (!outPath.getFileName().toString().endsWith(Constants.APP_SUFFIX)) { 812b8a72a62Sopenharmony_ci LOG.error("CompressVerify::isVerifyValidInFastAppMode out-path must end with .app."); 813b8a72a62Sopenharmony_ci return false; 814b8a72a62Sopenharmony_ci } 815b8a72a62Sopenharmony_ci return true; 816b8a72a62Sopenharmony_ci } 817b8a72a62Sopenharmony_ci 818b8a72a62Sopenharmony_ci private static boolean isVerifyValid(Utility utility) { 819b8a72a62Sopenharmony_ci if (utility.getPackInfoPath().isEmpty()) { 820b8a72a62Sopenharmony_ci LOG.error("CompressVerify::isArgsValidInAppMode pack-info-path is empty."); 821b8a72a62Sopenharmony_ci return false; 822b8a72a62Sopenharmony_ci } 823b8a72a62Sopenharmony_ci if (!isFileValid(utility.getPackInfoPath(), Constants.FILE_PACK_INFO)) { 824b8a72a62Sopenharmony_ci LOG.error("CompressVerify::isVerifyValidInFastAppMode pack-info-path is invalid."); 825b8a72a62Sopenharmony_ci return false; 826b8a72a62Sopenharmony_ci } 827b8a72a62Sopenharmony_ci if (!utility.getSignaturePath().isEmpty() && !isFileValid(utility.getSignaturePath(), "")) { 828b8a72a62Sopenharmony_ci LOG.error("CompressVerify::isVerifyValidInFastAppMode signature-path is invalid."); 829b8a72a62Sopenharmony_ci return false; 830b8a72a62Sopenharmony_ci } 831b8a72a62Sopenharmony_ci if (!utility.getCertificatePath().isEmpty() && 832b8a72a62Sopenharmony_ci !isFileValid(utility.getCertificatePath(), "")) { 833b8a72a62Sopenharmony_ci LOG.error("CompressVerify::isVerifyValidInFastAppMode certificate-path is invalid."); 834b8a72a62Sopenharmony_ci return false; 835b8a72a62Sopenharmony_ci } 836b8a72a62Sopenharmony_ci if (!utility.getPackResPath().isEmpty() && !isFileValid(utility.getPackResPath(), Constants.FILE_PACK_RES)) { 837b8a72a62Sopenharmony_ci LOG.error("CompressVerify::isVerifyValidInFastAppMode pack-res-path is invalid."); 838b8a72a62Sopenharmony_ci return false; 839b8a72a62Sopenharmony_ci } 840b8a72a62Sopenharmony_ci if (!utility.getEntryCardPath().isEmpty() && 841b8a72a62Sopenharmony_ci !CompressVerify.compatibleProcess(utility, utility.getEntryCardPath(), 842b8a72a62Sopenharmony_ci utility.getformattedEntryCardPathList(), Constants.PNG_SUFFIX)) { 843b8a72a62Sopenharmony_ci LOG.error("CompressVerify::isVerifyValidInFastAppMode entrycard-path is invalid."); 844b8a72a62Sopenharmony_ci return false; 845b8a72a62Sopenharmony_ci } 846b8a72a62Sopenharmony_ci if (utility.getOutPath().isEmpty()) { 847b8a72a62Sopenharmony_ci LOG.error("CompressVerify::isVerifyValidInFastAppMode out-path is empty."); 848b8a72a62Sopenharmony_ci return false; 849b8a72a62Sopenharmony_ci } 850b8a72a62Sopenharmony_ci return true; 851b8a72a62Sopenharmony_ci } 852b8a72a62Sopenharmony_ci 853b8a72a62Sopenharmony_ci private static boolean isHapPathValid(List<String> formatPathList) { 854b8a72a62Sopenharmony_ci for (String path : formatPathList) { 855b8a72a62Sopenharmony_ci if (!isDirValid(path)) { 856b8a72a62Sopenharmony_ci return false; 857b8a72a62Sopenharmony_ci } 858b8a72a62Sopenharmony_ci } 859b8a72a62Sopenharmony_ci return true; 860b8a72a62Sopenharmony_ci } 861b8a72a62Sopenharmony_ci 862b8a72a62Sopenharmony_ci private static boolean isHspPathValid(List<String> formatPathList) { 863b8a72a62Sopenharmony_ci for (String path : formatPathList) { 864b8a72a62Sopenharmony_ci if (!isDirValid(path) && !isFileValid(path, Constants.HSP_SUFFIX)) { 865b8a72a62Sopenharmony_ci return false; 866b8a72a62Sopenharmony_ci } 867b8a72a62Sopenharmony_ci } 868b8a72a62Sopenharmony_ci return true; 869b8a72a62Sopenharmony_ci } 870b8a72a62Sopenharmony_ci 871b8a72a62Sopenharmony_ci private static boolean isFormatPathValid(String inputPath, List<String> formatPathList) { 872b8a72a62Sopenharmony_ci Set<String> formatPathSet = new HashSet<>(); 873b8a72a62Sopenharmony_ci for (String path : inputPath.split(Constants.COMMA)) { 874b8a72a62Sopenharmony_ci try { 875b8a72a62Sopenharmony_ci Path realpath = Paths.get(path).toRealPath(); 876b8a72a62Sopenharmony_ci if (Files.exists(realpath)) { 877b8a72a62Sopenharmony_ci formatPathSet.add(realpath.toString()); 878b8a72a62Sopenharmony_ci } else { 879b8a72a62Sopenharmony_ci LOG.error("PackageUtil::formatPath not exists: " + realpath); 880b8a72a62Sopenharmony_ci return false; 881b8a72a62Sopenharmony_ci } 882b8a72a62Sopenharmony_ci } catch (IOException ex) { 883b8a72a62Sopenharmony_ci LOG.error("PackageUtil::formatPath err: " + ex.getMessage()); 884b8a72a62Sopenharmony_ci return false; 885b8a72a62Sopenharmony_ci } 886b8a72a62Sopenharmony_ci } 887b8a72a62Sopenharmony_ci formatPathList.addAll(formatPathSet); 888b8a72a62Sopenharmony_ci return true; 889b8a72a62Sopenharmony_ci } 890b8a72a62Sopenharmony_ci 891b8a72a62Sopenharmony_ci private static boolean isPackInfoValid(Path packInfo, List<String> hapPathList, List<String> hspPathList) { 892b8a72a62Sopenharmony_ci List<String> allPackages = getPackageNameFromPath(packInfo); 893b8a72a62Sopenharmony_ci Set<String> allPackageSet = new HashSet<>(allPackages); 894b8a72a62Sopenharmony_ci if (allPackages.size() > allPackageSet.size()) { 895b8a72a62Sopenharmony_ci LOG.error("package name is redundant in app pack.info: " + packInfo); 896b8a72a62Sopenharmony_ci return false; 897b8a72a62Sopenharmony_ci } 898b8a72a62Sopenharmony_ci if (allPackages.isEmpty()) { 899b8a72a62Sopenharmony_ci LOG.error("app pack.info format err: " + packInfo); 900b8a72a62Sopenharmony_ci return false; 901b8a72a62Sopenharmony_ci } 902b8a72a62Sopenharmony_ci Set<String> packages = new HashSet<>(); 903b8a72a62Sopenharmony_ci for (String hapPath : hapPathList) { 904b8a72a62Sopenharmony_ci List<String> list = getPackageNameFromPath(Paths.get(hapPath)); 905b8a72a62Sopenharmony_ci if (list.size() != 1) { 906b8a72a62Sopenharmony_ci LOG.error("module pack.info format err: " + hapPath); 907b8a72a62Sopenharmony_ci return false; 908b8a72a62Sopenharmony_ci } 909b8a72a62Sopenharmony_ci String packageName = list.get(0); 910b8a72a62Sopenharmony_ci if (!allPackages.contains(packageName)) { 911b8a72a62Sopenharmony_ci LOG.error("module pack.info name not exist in app pack.info name list: " + hapPath); 912b8a72a62Sopenharmony_ci return false; 913b8a72a62Sopenharmony_ci } 914b8a72a62Sopenharmony_ci if (packages.contains(packageName)) { 915b8a72a62Sopenharmony_ci LOG.error("package name is redundant in " + hapPath); 916b8a72a62Sopenharmony_ci return false; 917b8a72a62Sopenharmony_ci } 918b8a72a62Sopenharmony_ci packages.add(packageName); 919b8a72a62Sopenharmony_ci } 920b8a72a62Sopenharmony_ci for (String hspPath : hspPathList) { 921b8a72a62Sopenharmony_ci List<String> list = getPackageNameFromPath(Paths.get(hspPath)); 922b8a72a62Sopenharmony_ci if (list.size() != 1) { 923b8a72a62Sopenharmony_ci LOG.error("module pack.info format err: " + hspPath); 924b8a72a62Sopenharmony_ci return false; 925b8a72a62Sopenharmony_ci } 926b8a72a62Sopenharmony_ci String packageName = list.get(0); 927b8a72a62Sopenharmony_ci if (!allPackages.contains(packageName)) { 928b8a72a62Sopenharmony_ci LOG.error("module pack.info name not exist in app pack.info name list: " + hspPath); 929b8a72a62Sopenharmony_ci return false; 930b8a72a62Sopenharmony_ci } 931b8a72a62Sopenharmony_ci if (packages.contains(packageName)) { 932b8a72a62Sopenharmony_ci LOG.error("package name is redundant in " + hspPath); 933b8a72a62Sopenharmony_ci return false; 934b8a72a62Sopenharmony_ci } 935b8a72a62Sopenharmony_ci packages.add(packageName); 936b8a72a62Sopenharmony_ci } 937b8a72a62Sopenharmony_ci if (!allPackageSet.equals(packages)) { 938b8a72a62Sopenharmony_ci LOG.error("package name not same between module and app pack.info."); 939b8a72a62Sopenharmony_ci return false; 940b8a72a62Sopenharmony_ci } 941b8a72a62Sopenharmony_ci return true; 942b8a72a62Sopenharmony_ci } 943b8a72a62Sopenharmony_ci 944b8a72a62Sopenharmony_ci} 945