From 453793959c96a74722e559527bb727d8516ffaad Mon Sep 17 00:00:00 2001 From: autumn330 Date: Fri, 12 Mar 2021 19:15:56 +0800 Subject: [PATCH 1/3] Add readme for packing tool. --- README_zh.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 README_zh.md diff --git a/README_zh.md b/README_zh.md new file mode 100644 index 00000000..cac42fa5 --- /dev/null +++ b/README_zh.md @@ -0,0 +1,12 @@ +# 打包工具组件 + +- [简介][#section11660541593] + +## 简介 + +本组件包含打包、拆包和包解析三个功能模块: + +- 打包模块有将资源文件打包成hap包,和将多个hap包打包成app包两种模式。 +- 拆包模块有从app包中拆出所有hap包,和从hap包中拆出json文件两种模式。 + +- 包解析模块可以根据对应解析模式,解析出指定设备类型下的hap包列表、hap包信息、签名信息等。 \ No newline at end of file -- Gitee From 9504b252606f732e1c257cf2b0697db3def70469 Mon Sep 17 00:00:00 2001 From: autumn330 Date: Fri, 12 Mar 2021 19:24:01 +0800 Subject: [PATCH 2/3] Add readme. --- README_zh.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README_zh.md b/README_zh.md index cac42fa5..b91aea9a 100644 --- a/README_zh.md +++ b/README_zh.md @@ -1,6 +1,6 @@ # 打包工具组件 -- [简介][#section11660541593] +- [简介](#section11660541593) ## 简介 -- Gitee From db24b76ea4aa23b5f72a158efe7ef6eac09e84fa Mon Sep 17 00:00:00 2001 From: fenghao Date: Thu, 25 Mar 2021 23:01:24 +0800 Subject: [PATCH 3/3] Description:fix bugs that hap is compressed while repacking Team:OTHERS Feature or Bugfix:Bugfix Binary Source:No PrivateCode(Yes/No):No Change-Id: I5ba6c6e37e5cd36fbc58f92cb599934c8cb96534 ChangeID:13422861 --- .gitignore | 3 +- BUILD.gn | 1 + com/huawei/ohos/AppInfo.java | 67 ++++++++ com/huawei/ohos/CommandParser.java | 6 +- com/huawei/ohos/CompressVerify.java | 8 +- com/huawei/ohos/Compressor.java | 122 +++++++++++---- com/huawei/ohos/HapZipInfo.java | 101 ++++++++++++ com/huawei/ohos/JsonUtil.java | 67 +++++++- com/huawei/ohos/README | 4 +- com/huawei/ohos/Uncompress.java | 235 ++++++++++++++++++---------- com/huawei/ohos/Utility.java | 18 +-- 11 files changed, 486 insertions(+), 146 deletions(-) mode change 100644 => 100755 .gitignore create mode 100755 com/huawei/ohos/HapZipInfo.java diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 index 8b137891..c51f72ae --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ - +jar +.idea/ diff --git a/BUILD.gn b/BUILD.gn index 53804692..42c16221 100755 --- a/BUILD.gn +++ b/BUILD.gn @@ -60,6 +60,7 @@ java_library("hmos_app_unpacking_tool_java") { "com/huawei/ohos/ScreenDensity.java", "com/huawei/ohos/ScreenWindow.java", "com/huawei/ohos/CountryCode.java", + "com/huawei/ohos/HapZipInfo.java", ] deps = [ "//third_party/fastjson/repackaged:fastjson_utils_java" ] diff --git a/com/huawei/ohos/AppInfo.java b/com/huawei/ohos/AppInfo.java index 03c89c93..278877ab 100755 --- a/com/huawei/ohos/AppInfo.java +++ b/com/huawei/ohos/AppInfo.java @@ -74,4 +74,71 @@ public class AppInfo { * Indicates the releaseType of app AppInfo. */ public String releaseType = ""; + + + private String shellVersionCode = ""; + private String shellVersionName = ""; + private boolean multiFrameworkBundle; + + /** + * Get shell version code. + * + * @return shell version code + */ + public String getShellVersionCode() { + return shellVersionCode; + } + + /** + * Set shell version code. + * + * @param shellVersionCode Indicates the shell version name + */ + public void setShellVersionCode(String shellVersionCode) { + this.shellVersionCode = shellVersionCode; + } + + /** + * Get shell version name. + * + * @return shell version name + */ + public String getShellVersionName() { + return shellVersionName; + } + + /** + * Set shell version name. + * + * @param shellVersionName Indicates the shell version name + */ + public void setShellVersionName(String shellVersionName) { + this.shellVersionName = shellVersionName; + } + + /** + * Whether the app is multi framework bundle. + * + * @return true if the app is a multi framework bundle. + */ + public boolean isMultiFrameworkBundle() { + return multiFrameworkBundle; + } + + /** + * Set multi framework bundle. + * + * @param multiFrameworkBundle Indicates the app type + */ + public void setMultiFrameworkBundle(boolean multiFrameworkBundle) { + this.multiFrameworkBundle = multiFrameworkBundle; + } + + /** + * Set default shell version + */ + public void setDefaultShellVersion() { + this.shellVersionCode = versionCode; + this.shellVersionName = versionName; + } } diff --git a/com/huawei/ohos/CommandParser.java b/com/huawei/ohos/CommandParser.java index fc318199..7351061e 100755 --- a/com/huawei/ohos/CommandParser.java +++ b/com/huawei/ohos/CommandParser.java @@ -40,7 +40,7 @@ public class CommandParser { private static final String CMD_SO_DIR = "--maple-so-dir"; private static final String CMD_ABILITY_SO_PATH = "--ability-so-path"; private static final String CMD_DEX_PATH = "--dex-path"; - private static final String CMD_AEX_PATH = "--aex-path"; + private static final String CMD_ABC_PATH = "--abc-path"; private static final String CMD_LIB_PATH = "--lib-path"; private static final String CMD_RES_PATH = "--res-path"; private static final String CMD_RESOURCES_PATH = "--resources-path"; @@ -255,8 +255,8 @@ public class CommandParser { utility.setDexPath(value); return true; } - case CMD_AEX_PATH: { - utility.setAexPath(value); + case CMD_ABC_PATH: { + utility.setAbcPath(value); return true; } case CMD_LIB_PATH: { diff --git a/com/huawei/ohos/CompressVerify.java b/com/huawei/ohos/CompressVerify.java index 1e360282..06f1ba7b 100755 --- a/com/huawei/ohos/CompressVerify.java +++ b/com/huawei/ohos/CompressVerify.java @@ -38,7 +38,7 @@ public class CompressVerify { private static final String APP_SUFFIX = ".app"; private static final String APK_SUFFIX = ".apk"; private static final String DEX_SUFFIX = ".dex"; - private static final String AEX_SUFFIX = ".aex"; + private static final String ABC_SUFFIX = ".abc"; private static final String SO_SUFFIX = ".so"; private static final String JAR_SUFFIX = ".jar"; private static final String TXT_SUFFIX = ".txt"; @@ -107,9 +107,9 @@ public class CompressVerify { return false; } - if (!utility.getAexPath().isEmpty() && !compatibleProcess(utility, utility.getAexPath(), - utility.getFormattedAexPathList(), AEX_SUFFIX)) { - LOG.error("CompressVerify::isArgsValidInHapMode aex-path is invalid!"); + if (!utility.getAbcPath().isEmpty() && !compatibleProcess(utility, utility.getAbcPath(), + utility.getFormattedAbcPathList(), ABC_SUFFIX)) { + LOG.error("CompressVerify::isArgsValidInHapMode abc-path is invalid!"); return false; } diff --git a/com/huawei/ohos/Compressor.java b/com/huawei/ohos/Compressor.java index cc17acbc..cd5022ae 100755 --- a/com/huawei/ohos/Compressor.java +++ b/com/huawei/ohos/Compressor.java @@ -41,6 +41,7 @@ import java.util.zip.ZipOutputStream; import java.util.Enumeration; import java.util.ArrayList; import java.util.List; +import java.util.Arrays; /** * bundle compressor class, compress file and directory. @@ -110,8 +111,9 @@ public class Compressor { private ZipOutputStream zipOut = null; private List list = new ArrayList(); - private List fromsList = new ArrayList(); + private List formNamesList = new ArrayList(); private List fileNameList = new ArrayList(); + private List supportDimensionsList = Arrays.asList(PIC_1X2, PIC_2X4, PIC_4X4); /** * start compress. @@ -246,8 +248,8 @@ public class Compressor { pathToFile(utility, dexPathItem, NULL_DIR_NAME, false); } - for (String aexPathItem : utility.getFormattedAexPathList()) { - pathToFile(utility, aexPathItem, NULL_DIR_NAME, false); + for (String abcPathItem : utility.getFormattedAbcPathList()) { + pathToFile(utility, abcPathItem, NULL_DIR_NAME, false); } for (String apkPathItem : utility.getFormattedApkPathList()) { @@ -318,12 +320,20 @@ public class Compressor { pathToFile(utility, utility.getSignaturePath(), NULL_DIR_NAME, false); } - String[] outPath = utility.getOutPath().split("\\\\"); + String[] outPath = utility.getOutPath().replace("\\", "/").split("/"); + if (outPath.length < 2) { + LOG.error("Compressor::compressAppMode the outPath is invalid, length: " + outPath.length); + return; + } String[] path = utility.getOutPath().split(outPath[outPath.length - 2].toString()); List fileList = new ArrayList<>(); for (String hapPathItem : utility.getFormattedHapPathList()) { String fName = hapPathItem.trim(); - String[] temp = fName.split("\\\\"); + String[] temp = fName.replace("\\", "/").split("/"); + if (temp.length < 1) { + LOG.error("Compressor::compressAppMode the hap file path is invalid, length: " + temp.length); + continue; + } String[] str = temp[temp.length - 1].split("\\."); String outPathString = path[0] + str[0]; fileList.add(outPathString); @@ -376,6 +386,7 @@ public class Compressor { } outputStream = new FileOutputStream(destFile); out = new ZipOutputStream(new CheckedOutputStream(outputStream, new CRC32())); + out.setMethod(ZipOutputStream.STORED); compress(new File(path), out, NULL_DIR_NAME, true); } catch (FileNotFoundException ignored) { LOG.error("zip file not found exception"); @@ -542,7 +553,12 @@ public class Compressor { for (String fileName : fileNameList) { if (fileName.endsWith(PNG_SUFFIX) || fileName.endsWith(UPPERCASE_PNG_SUFFIX)) { String fName = fileName.trim(); - String[] temp = fName.split("\\\\"); + String[] temp = fName.replace("\\", "/").split("/"); + if (temp.length < 4) { + LOG.error("Compressor::compressPackResMode the hap file path is invalid, length: " + + temp.length); + continue; + } String fileModelName = temp[temp.length - 4]; if (!isModelName(fileModelName)) { LOG.error("Compressor::compressProcess compress failed ModelName Error!"); @@ -634,26 +650,22 @@ public class Compressor { if (name == null || name.isEmpty()) { return isSpecifications; } - if (name.endsWith(PNG_SUFFIX) || name.endsWith(UPPERCASE_PNG_SUFFIX)) { - String[] picName = name.split("-"); - if (picName.length > 1) { - for (String fromName : fromsList) { - if (fromName.equals(picName[0])) { - isSpecifications = false; - String[] normName = picName[1].split("\\."); - if (normName[0].equals( PIC_1X2 ) || normName[0].equals( PIC_2X2 ) - || normName[0].equals( PIC_2X4 ) || normName[0].equals( PIC_4X4 )) { - isSpecifications = true; - } - } - } - return isSpecifications; - } else { - return isSpecifications; - } - } else { - return isSpecifications; + if (!name.endsWith(PNG_SUFFIX) && !name.endsWith(UPPERCASE_PNG_SUFFIX)) { + LOG.error("isPicturing: the suffix is not .png or .PNG"); + return false; + } + int delimiterIndex = name.lastIndexOf("-"); + if (delimiterIndex < 0) { + LOG.error("isPicturing: the entry card naming format is invalid and should be separated by '-'!"); + return false; + } + String formName = name.substring(0, delimiterIndex); + if (!formNamesList.contains(formName)) { + LOG.error("isPicturing: the name is not same as formName, name: " + formName); + return false; } + String dimension = name.substring(delimiterIndex + 1, name.lastIndexOf(".")); + return supportDimensionsList.contains(dimension); } /** @@ -676,6 +688,10 @@ public class Compressor { for (File f : files) { try { if (f.isFile()) { + if (f.getName().endsWith(".DS_Store")) { + deleteFile(f.getCanonicalPath()); + continue; + } fileNameList.add(f.getCanonicalPath()); } else if (f.isDirectory()) { getFileList(f.getCanonicalPath()); @@ -755,13 +771,14 @@ public class Compressor { * @param name filename * @param KeepDirStructure Empty File */ - private static void compress(File sourceFile, ZipOutputStream zos, String name, + private void compress(File sourceFile, ZipOutputStream zos, String name, boolean KeepDirStructure) { FileInputStream in = null; try { byte[] buf = new byte[BUFFER_SIZE]; if (sourceFile.isFile()) { - zos.putNextEntry(new ZipEntry(name)); + ZipEntry zipEntry = getStoredZipEntry(sourceFile, name); + zos.putNextEntry(zipEntry); in = new FileInputStream(sourceFile); int len; while ((len = in.read(buf)) != -1) { @@ -773,9 +790,11 @@ public class Compressor { if (listFiles == null || listFiles.length == 0) { if (KeepDirStructure) { if (!name.isEmpty()) { - zos.putNextEntry(new ZipEntry(name + "/")); + ZipEntry zipEntry = getStoredZipEntry(sourceFile, name + "/"); + zos.putNextEntry(zipEntry); } else { - zos.putNextEntry(new ZipEntry(name)); + ZipEntry zipEntry = getStoredZipEntry(sourceFile, name); + zos.putNextEntry(zipEntry); } zos.closeEntry(); } @@ -793,11 +812,50 @@ public class Compressor { LOG.error("Compressor::compressFile file not found exception"); } catch (IOException exception) { LOG.error("Compressor::compressFile io exception: " + exception.getMessage()); - }finally { + } catch (BundleException bundleException) { + LOG.error("Compressor::compressFile bundle exception" + bundleException.getMessage()); + } finally { Utility.closeStream(in); } } + private ZipEntry getStoredZipEntry(File sourceFile, String name) throws BundleException { + ZipEntry zipEntry = new ZipEntry(name); + zipEntry.setMethod(ZipEntry.STORED); + zipEntry.setCompressedSize(sourceFile.length()); + zipEntry.setSize(sourceFile.length()); + CRC32 crc = getCrcFromFile(sourceFile); + zipEntry.setCrc(crc.getValue()); + FileTime fileTime = FileTime.fromMillis(FILE_TIME); + zipEntry.setLastAccessTime(fileTime); + zipEntry.setLastModifiedTime(fileTime); + return zipEntry; + } + + private CRC32 getCrcFromFile(File file) throws BundleException { + FileInputStream fileInputStream = null; + CRC32 crc = new CRC32(); + try { + fileInputStream = new FileInputStream(file); + byte[] buffer = new byte[BUFFER_SIZE]; + + int count = fileInputStream.read(buffer); + while (count > 0) { + crc.update(buffer, 0, count); + count = fileInputStream.read(buffer); + } + } catch (FileNotFoundException ignored) { + LOG.error("Uncompressor::getCrcFromFile file not found exception"); + throw new BundleException("Get Crc from file failed"); + } catch (IOException exception) { + LOG.error("Uncompressor::getCrcFromFile io exception: " + exception.getMessage()); + throw new BundleException("Get Crc from file failed"); + } finally { + Utility.closeStream(fileInputStream); + } + return crc; + } + /** * isNameEmpty * @@ -806,7 +864,7 @@ public class Compressor { * @param KeepDirStructure KeepDirStructure * @param file file */ - private static void isNameEmpty(ZipOutputStream zos, String name, boolean KeepDirStructure, File file) { + private void isNameEmpty(ZipOutputStream zos, String name, boolean KeepDirStructure, File file) { if (!name.isEmpty()) { compress(file, zos, name + "/" + file.getName(), KeepDirStructure); } else { @@ -1309,7 +1367,7 @@ public class Compressor { } String[] nameList = fromsName.split("\\."); if (nameList.length <= 1) { - fromsList.add(fromsName); + formNamesList.add(fromsName); } } catch (StringIndexOutOfBoundsException exception) { LOG.error("Compressor::parseModuleName field module-name is fault: " + exception.getMessage()); diff --git a/com/huawei/ohos/HapZipInfo.java b/com/huawei/ohos/HapZipInfo.java new file mode 100755 index 00000000..5e26f5c0 --- /dev/null +++ b/com/huawei/ohos/HapZipInfo.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.huawei.ohos; + +/** + * Hap zip info + * + * @author yaoyanbing + * @since 2021-03-16 + */ +class HapZipInfo { + private byte[] resDataBytes; + private String harmonyProfileJsonStr = ""; + private String packInfoJsonStr = ""; + private String hapFileName = ""; + + /** + * Get resource data bytes. + * + * @return resource data bytes. + */ + public byte[] getResDataBytes() { + return resDataBytes; + } + + /** + * Set resource data bytes. + * + * @param resDataBytes Indicates the resource data bytes. + */ + public void setResDataBytes(byte[] resDataBytes) { + this.resDataBytes = resDataBytes; + } + + /** + * Get harmony profile json string. + * + * @return harmony profile json string. + */ + public String getHarmonyProfileJsonStr() { + return harmonyProfileJsonStr; + } + + /** + * Set harmony profile json string. + * + * @param harmonyProfileJsonStr Indicates harmony profile json string. + */ + public void setHarmonyProfileJsonStr(String harmonyProfileJsonStr) { + this.harmonyProfileJsonStr = harmonyProfileJsonStr; + } + + /** + * Get pack.info json string. + * + * @return pack.info json string. + */ + public String getPackInfoJsonStr() { + return packInfoJsonStr; + } + + /** + * Set pack.info json string. + * + * @param packInfoJsonStr Indicates the pack.info json string. + */ + public void setPackInfoJsonStr(String packInfoJsonStr) { + this.packInfoJsonStr = packInfoJsonStr; + } + + /** + * Get hap file name. + * + * @return hap file name. + */ + public String getHapFileName() { + return hapFileName; + } + + /** + * Set hap file name. + * + * @param hapFileName Indicates the hap file name. + */ + public void setHapFileName(String hapFileName) { + this.hapFileName = hapFileName; + } +} diff --git a/com/huawei/ohos/JsonUtil.java b/com/huawei/ohos/JsonUtil.java index d8aa3a87..40ced598 100755 --- a/com/huawei/ohos/JsonUtil.java +++ b/com/huawei/ohos/JsonUtil.java @@ -42,6 +42,13 @@ public class JsonUtil { private static final String ASSETS_DIR_NAME = "assets/"; private static final Log LOG = new Log(JsonUtil.class.toString()); + private static final String SUMMARY = "summary"; + private static final String APP = "app"; + private static final String VERSION = "version"; + private static final String LEGACY_VERSION_CODE = "legacyVersionCode"; + private static final String LEGACY_VERSION_NAME = "legacyVersionName"; + private static final String MULTI_FRAMEWORK_BUNDLE = "multiFrameworkBundle"; + /** * parse hap list by device type * @@ -89,24 +96,64 @@ public class JsonUtil { return packInfos; } + private static boolean parseShellVersionInfoToAppInfo(String packInfoJsonStr, AppInfo appInfo) { + LOG.info("Uncompress::parseShellVersionInfoToAppInfo: begin"); + if (!appInfo.isMultiFrameworkBundle()) { + LOG.info("Uncompress::parseShellVersionInfoToAppInfo: is not a multi framewok bundle."); + return false; + } + + JSONObject jsonObject = JSONObject.parseObject(packInfoJsonStr); + if (jsonObject == null) { + LOG.error("Uncompress::parseShellVersionInfoToAppInfo error: summary is null"); + return false; + } + + JSONObject summaryJson = jsonObject.getJSONObject(SUMMARY); + if (summaryJson == null) { + LOG.error("Uncompress::parseShellVersionInfoToAppInfo error: summary is null"); + return false; + } + JSONObject appJson = summaryJson.getJSONObject(APP); + if (appJson == null) { + LOG.error("Uncompress::parseShellVersionInfoToAppInfo error: app is null"); + return false; + } + JSONObject versionJson = appJson.getJSONObject(VERSION); + if (versionJson == null) { + LOG.error("Uncompress::parseShellVersionInfoToAppInfo error: version is null"); + return false; + } + + if (!versionJson.containsKey(LEGACY_VERSION_CODE) || !versionJson.containsKey(LEGACY_VERSION_NAME)) { + LOG.error("Uncompress::parseShellVersionInfoToAppInfo no legacy version info."); + return false; + } + appInfo.setShellVersionCode(versionJson.getString(LEGACY_VERSION_CODE)); + appInfo.setShellVersionName(versionJson.getString(LEGACY_VERSION_NAME)); + return true; + } + /** * parse hap profile info * - * @param jsonString uncompress json String + * @param harmonyProfileJsonString uncompress json String * @param data resource index data + * @param paclInfoJsonString pack.info json String * @return the parseProfileInfo result * @throws BundleException Throws this exception if the json is not standard. */ - static ProfileInfo parseProfileInfo(String jsonString, byte[] data) throws BundleException { + static ProfileInfo parseProfileInfo(String harmonyProfileJsonString, byte[] data, String paclInfoJsonString) + throws BundleException { ProfileInfo profileInfo = new ProfileInfo(); - JSONObject jsonObject = JSONObject.parseObject(jsonString); - if (jsonObject == null || !jsonObject.containsKey("app") || !jsonObject.containsKey("deviceConfig") + JSONObject jsonObject = JSONObject.parseObject(harmonyProfileJsonString); + if (jsonObject == null || !jsonObject.containsKey(APP) || !jsonObject.containsKey("deviceConfig") || !jsonObject.containsKey("module")) { LOG.error("Uncompress::parseProfileInfo exception: app, deviceConfig or module is null"); throw new BundleException("Parse profile info failed, app, deviceConfig or module is null"); } - if (jsonObject.containsKey("app")) { - JSONObject appJson = jsonObject.getJSONObject("app"); + if (jsonObject.containsKey(APP)) { + JSONObject appJson = jsonObject.getJSONObject(APP); profileInfo.appInfo = parseAppInfo(appJson); } if (jsonObject.containsKey("module")) { @@ -138,6 +185,9 @@ public class JsonUtil { } } + if (!parseShellVersionInfoToAppInfo(paclInfoJsonString, profileInfo.appInfo)) { + profileInfo.appInfo.setDefaultShellVersion(); + } return profileInfo; } @@ -157,8 +207,8 @@ public class JsonUtil { appInfo.bundleName = getJsonString(appJson, "bundleName"); appInfo.vendor = getJsonString(appJson, "vendor"); appInfo.relatedBundleName = getJsonString(appJson, "relatedBundleName"); - if (appJson.containsKey("version")) { - JSONObject version = appJson.getJSONObject("version"); + if (appJson.containsKey(VERSION)) { + JSONObject version = appJson.getJSONObject(VERSION); appInfo.versionName = getJsonString(version, "name"); appInfo.versionCode = getJsonString(version, "code"); } @@ -168,6 +218,7 @@ public class JsonUtil { appInfo.targetApiVersion = apiVersion.getIntValue("target"); appInfo.releaseType = getJsonString(apiVersion, "releaseType"); } + appInfo.setMultiFrameworkBundle(appJson.getBooleanValue(MULTI_FRAMEWORK_BUNDLE)); return appInfo; } diff --git a/com/huawei/ohos/README b/com/huawei/ohos/README index 86d45bf1..3e30fa9a 100755 --- a/com/huawei/ohos/README +++ b/com/huawei/ohos/README @@ -42,9 +42,9 @@ HAP MODE OPTIONS: --dex-path 1.dex path must end with .dex, if has more than one dex, use comma(,) to separate. 2.dex path also can be directory path. - --aex-path 1.aex path must end with .aex, if has more than one aex, + --abc-path 1.abc path must end with .abc, if has more than one abc, use comma(,) to separate. - 2.aex path also can be directory path. + 2.abc path also can be directory path. --lib-path lib/ path. --assets-path assets/ path. --resources-path resources path. diff --git a/com/huawei/ohos/Uncompress.java b/com/huawei/ohos/Uncompress.java index 03e21bd2..80d430c3 100755 --- a/com/huawei/ohos/Uncompress.java +++ b/com/huawei/ohos/Uncompress.java @@ -542,59 +542,43 @@ public class Uncompress { } } - /** - * uncompress process - * - * @param deviceType device type - * @param srcPath source file path - * @param fileName uncompress file name - * @return the uncompress result - * @throws BundleException FileNotFoundException|IOException. - */ - private static UncomperssResult uncompress(String deviceType, String srcPath, String fileName) - throws BundleException { - if (srcPath.isEmpty() || fileName.isEmpty()) { - LOG.error("Uncompress::uncompress srcPath, fileName is empty!"); - throw new BundleException("Uncompress failed, srcPath or fileName is empty"); - } - - UncomperssResult result = new UncomperssResult(); - InputStream fileInputStream = null; + private static byte[] getResourceDataFromHap(ZipFile zipFile) throws BundleException, IOException { + int entriesNum = 0; InputStream indexInputStream = null; - ZipFile zipFile = null; - BufferedReader bufferedReader = null; - byte[] data = null; try { - File srcFile = new File(srcPath); - zipFile = new ZipFile(srcFile); - - if (HARMONY_PROFILE.equals(fileName)) { - int entriesNum = 0; - for (Enumeration entries = zipFile.entries(); entries.hasMoreElements(); ) { - entriesNum++; - if (entriesNum > TOO_MANY_SIZE) { - LOG.error("Uncompress::uncompress exception: the entry num is too many."); - throw new BundleException("uncompress failed entry num is too many"); - } + for (Enumeration entries = zipFile.entries(); entries.hasMoreElements(); ) { + entriesNum++; + if (entriesNum > TOO_MANY_SIZE) { + LOG.error("Uncompress::uncompress exception: the entry num is too many."); + throw new BundleException("uncompress failed entry num is too many"); + } - ZipEntry indexEntry = entries.nextElement(); - if (indexEntry == null) { - continue; - } - if (indexEntry != null && !"".equals(indexEntry.getName()) && - indexEntry.getName().toLowerCase().endsWith(RESOURCE_INDEX)) { - indexInputStream = zipFile.getInputStream(indexEntry); - data = getByte(indexInputStream); - break; - } + ZipEntry indexEntry = entries.nextElement(); + if (indexEntry == null) { + continue; + } + if (indexEntry != null && !"".equals(indexEntry.getName()) && + indexEntry.getName().toLowerCase().endsWith(RESOURCE_INDEX)) { + indexInputStream = zipFile.getInputStream(indexEntry); + return getByte(indexInputStream); } } + } finally { + Utility.closeStream(indexInputStream); + } + return null; + } - ZipEntry entry = zipFile.getEntry(fileName); - if (entry == null) { - LOG.error("Uncompress::uncompress " + fileName + " not found exception"); - throw new BundleException("Uncompress failed"); - } + private static String readStringFromFile(String fileName, ZipFile zipFile) + throws IOException { + ZipEntry entry = zipFile.getEntry(fileName); + if (entry == null) { + LOG.error("Uncompress::readStringFromFile " + fileName + " not found exception"); + return ""; + } + InputStream fileInputStream = null; + BufferedReader bufferedReader = null; + try { fileInputStream = zipFile.getInputStream(entry); bufferedReader = new BufferedReader(new InputStreamReader(fileInputStream)); String line; @@ -602,50 +586,86 @@ public class Uncompress { while ((line = bufferedReader.readLine()) != null) { sb.append(line); } - if (PACK_INFO.equals(fileName)) { - List packInfos = JsonUtil.parseHapList(deviceType, sb.toString()); - result.setPackInfoStr(sb.toString()); - result.setPackInfos(packInfos); - } else { - ProfileInfo profileInfo = JsonUtil.parseProfileInfo(sb.toString(), data); - profileInfo.hapName = srcFile.getName().replace(HAP_SUFFIX, ""); - result.addProfileInfoStr(sb.toString()); - result.addProfileInfo(profileInfo); - } - } catch (IOException exception) { - LOG.error("Uncompress::uncompress io exception: " + exception.getMessage()); - throw new BundleException("Uncompress failed"); + return sb.toString(); } finally { Utility.closeStream(bufferedReader); - Utility.closeStream(indexInputStream); Utility.closeStream(fileInputStream); + } + } + + private static HapZipInfo unZipHapFileFromHapFile(String srcPath) + throws BundleException, IOException { + HapZipInfo hapZipInfo = new HapZipInfo(); + ZipFile zipFile = null; + try { + File srcFile = new File(srcPath); + zipFile = new ZipFile(srcFile); + hapZipInfo.setHarmonyProfileJsonStr(readStringFromFile(HARMONY_PROFILE, zipFile)); + hapZipInfo.setResDataBytes(getResourceDataFromHap(zipFile)); + hapZipInfo.setPackInfoJsonStr(readStringFromFile(PACK_INFO, zipFile)); + hapZipInfo.setHapFileName(getHapNameWithoutSuffix(srcFile.getName())); + } finally { Utility.closeStream(zipFile); } - return result; + return hapZipInfo; } /** - * uncompress process by InputStream + * uncompress from specified file name * * @param deviceType device type - * @param input the InputStream about the package. + * @param srcPath source file path * @param fileName uncompress file name * @return the uncompress result * @throws BundleException FileNotFoundException|IOException. */ - private static UncomperssResult uncompressByInput(String deviceType, InputStream input, String fileName) + private static UncomperssResult uncompress(String deviceType, String srcPath, String fileName) throws BundleException { + if (srcPath.isEmpty() || fileName.isEmpty()) { + LOG.error("Uncompress::uncompress srcPath, fileName is empty!"); + throw new BundleException("Uncompress failed, srcPath or fileName is empty"); + } + UncomperssResult result = new UncomperssResult(); + try { + HapZipInfo hapZipInfo = unZipHapFileFromHapFile(srcPath); + if (isPackInfo(fileName)) { + uncompressPackInfo(deviceType, hapZipInfo, result); + } else { + uncompressProfileInfo(hapZipInfo, result); + } + } catch (IOException exception) { + LOG.error("Uncompress::uncompress io exception: " + exception.getMessage()); + throw new BundleException("Uncompress failed"); + } + return result; + } + + private static void uncompressPackInfo(String deviceType, HapZipInfo hapZipInfo, UncomperssResult uncomperssResult) + throws BundleException { + List packInfos = JsonUtil.parseHapList(deviceType, hapZipInfo.getPackInfoJsonStr()); + uncomperssResult.setPackInfoStr(hapZipInfo.getPackInfoJsonStr()); + uncomperssResult.setPackInfos(packInfos); + } + + private static void uncompressProfileInfo(HapZipInfo hapZipInfo, UncomperssResult uncomperssResult) + throws BundleException { + ProfileInfo profileInfo = JsonUtil.parseProfileInfo(hapZipInfo.getHarmonyProfileJsonStr(), + hapZipInfo.getResDataBytes(), hapZipInfo.getPackInfoJsonStr()); + profileInfo.hapName = hapZipInfo.getHapFileName(); + uncomperssResult.addProfileInfoStr(hapZipInfo.getHarmonyProfileJsonStr()); + uncomperssResult.addProfileInfo(profileInfo); + } + + private static HapZipInfo unZipHapFileFromInputStream(InputStream input) throws BundleException, IOException { BufferedInputStream bufIn = null; - InputStream indexInputStream = null; ZipInputStream zipIn = null; BufferedReader bufferedReader = null; + HapZipInfo hapZipInfo = new HapZipInfo(); try { ZipEntry entry = null; bufIn = new BufferedInputStream(input); zipIn = new ZipInputStream(bufIn); - String sbStr = ""; - byte[] dataRes = null; int entriesNum = 0; while ((entry = zipIn.getNextEntry()) != null) { entriesNum++; @@ -655,34 +675,59 @@ public class Uncompress { } if (entry.getName().toLowerCase().endsWith(RESOURCE_INDEX)) { - dataRes = getByte(zipIn); - } else if (fileName.equals(entry.getName())) { + hapZipInfo.setResDataBytes(getByte(zipIn)); + continue; + } + if (isPackInfo(entry.getName())) { bufferedReader = new BufferedReader(new InputStreamReader(zipIn)); - String line; - StringBuilder sb = new StringBuilder(); - while ((line = bufferedReader.readLine()) != null) { - sb.append(line); - } - sbStr = sb.toString(); + hapZipInfo.setPackInfoJsonStr(readStringFromInputStream(zipIn, bufferedReader)); + continue; + } + if (isHarmonyProfile(entry.getName())) { + bufferedReader = new BufferedReader(new InputStreamReader(zipIn)); + hapZipInfo.setHarmonyProfileJsonStr(readStringFromInputStream(zipIn, bufferedReader)); } } + } finally { + Utility.closeStream(bufferedReader); + Utility.closeStream(bufIn); + Utility.closeStream(zipIn); + } + return hapZipInfo; + } + + private static String readStringFromInputStream(ZipInputStream zipIn, BufferedReader bufferedReader) + throws IOException { + String line; + StringBuilder sb = new StringBuilder(); + while ((line = bufferedReader.readLine()) != null) { + sb.append(line); + } + return sb.toString(); + } - if (PACK_INFO.equals(fileName)) { - List packInfos = JsonUtil.parseHapList(deviceType, sbStr); - result.setPackInfoStr(sbStr); - result.setPackInfos(packInfos); + /** + * uncompress process by InputStream + * + * @param deviceType device type + * @param input the InputStream about the package. + * @param fileName uncompress file name + * @return the uncompress result + * @throws BundleException FileNotFoundException|IOException. + */ + private static UncomperssResult uncompressByInput(String deviceType, InputStream input, String fileName) + throws BundleException { + UncomperssResult result = new UncomperssResult(); + try { + HapZipInfo hapZipInfo = unZipHapFileFromInputStream(input); + if (isPackInfo(fileName)) { + uncompressPackInfo(deviceType, hapZipInfo, result); } else { - result.addProfileInfoStr(sbStr); - result.addProfileInfo(JsonUtil.parseProfileInfo(sbStr, dataRes)); + uncompressProfileInfo(hapZipInfo, result); } } catch (IOException exception) { LOG.error("Uncompress::uncompressByInput io exception: " + exception.getMessage()); throw new BundleException("Uncompress by input failed"); - } finally { - Utility.closeStream(bufferedReader); - Utility.closeStream(indexInputStream); - Utility.closeStream(bufIn); - Utility.closeStream(zipIn); } return result; } @@ -1201,4 +1246,20 @@ public class Uncompress { } return result; } + + + private static boolean isHarmonyProfile(String fileName) { + return HARMONY_PROFILE.equals(fileName); + } + + private static boolean isPackInfo(String fileName) { + return PACK_INFO.equals(fileName); + } + + private static String getHapNameWithoutSuffix(String hapFileName) { + if (hapFileName == null || hapFileName.isEmpty()) { + return ""; + } + return hapFileName.replace(HAP_SUFFIX, ""); + } } \ No newline at end of file diff --git a/com/huawei/ohos/Utility.java b/com/huawei/ohos/Utility.java index 4cad9ccd..b1f92589 100755 --- a/com/huawei/ohos/Utility.java +++ b/com/huawei/ohos/Utility.java @@ -45,7 +45,7 @@ public class Utility { private String soDir = ""; private String abilitySoPath = ""; private String dexPath = ""; - private String aexPath = ""; + private String abcPath = ""; private String indexPath = ""; private String hapPath = ""; private String appPath = ""; @@ -77,7 +77,7 @@ public class Utility { private List formattedSoPathList = new ArrayList<>(); private List formattedAbilitySoPathList = new ArrayList<>(); private List formattedDexPathList = new ArrayList<>(); - private List formattedAexPathList = new ArrayList<>(); + private List formattedAbcPathList = new ArrayList<>(); private List formattedHapPathList = new ArrayList<>(); private List formattedApkPathList = new ArrayList<>(); private List formattedJarPathList = new ArrayList<>(); @@ -154,13 +154,13 @@ public class Utility { } } - public String getAexPath() { - return aexPath; + public String getAbcPath() { + return abcPath; } - public void setAexPath(String aexPath) { - if (!aexPath.startsWith(CMD_PREFIX)) { - this.aexPath = aexPath; + public void setAbcPath(String abcPath) { + if (!abcPath.startsWith(CMD_PREFIX)) { + this.abcPath = abcPath; } } @@ -439,8 +439,8 @@ public class Utility { return formattedDexPathList; } - public List getFormattedAexPathList() { - return formattedAexPathList; + public List getFormattedAbcPathList() { + return formattedAbcPathList; } public List getFormattedHapPathList() { -- Gitee