diff --git a/com/huawei/ohos/CompressVerify.java b/com/huawei/ohos/CompressVerify.java index 06f1ba7be029b8562c65707e7f7c8665df263403..94715aa4b2b5ba4e83534a84ba4f35be9a4a429a 100755 --- a/com/huawei/ohos/CompressVerify.java +++ b/com/huawei/ohos/CompressVerify.java @@ -44,7 +44,7 @@ public class CompressVerify { private static final String TXT_SUFFIX = ".txt"; private static final String PNG_SUFFIX = ".png"; private static final String RES_SUFFIX = ".res"; - private static final String ENTRYCARD = "EntryCard"; + private static final String ENTRY_CARD_DIRECTORY_NAME = "EntryCard"; private static final Log LOG = new Log(CompressVerify.class.toString()); @@ -323,8 +323,13 @@ public class CompressVerify { return false; } + if (!isDirectoryValidStrictCase(utility.getEntryCardPath(), ENTRY_CARD_DIRECTORY_NAME)) { + LOG.error("CompressVerify::isArgsValidInResMode the level-1 directory name must is EntryCard" + + ", current is " + utility.getEntryCardPath()); + return false; + } if (!compatibleProcess(utility, utility.getEntryCardPath(), - utility.getformattedEntryCardPathList(), ENTRYCARD)) { + utility.getformattedEntryCardPathList(), PNG_SUFFIX)) { LOG.error("CompressVerify::isArgsValidInResMode entrycard-path is invalid!"); return false; } @@ -439,6 +444,19 @@ public class CompressVerify { return (!isFile) && file.isDirectory(); } + private static boolean isDirectoryValidStrictCase(String path, String directoryName) { + File file = new File(path); + if (!file.exists()) { + LOG.error("CompressVerify::isDirectoryValidStrictCase directory is not exist, directoryPath: " + + path); + return false; + } + if (file.isDirectory()) { + return directoryName.equals(file.getName()); + } + return false; + } + /** * remove duplicate in path. * @@ -456,4 +474,4 @@ public class CompressVerify { } return list; } -} \ No newline at end of file +} diff --git a/com/huawei/ohos/Compressor.java b/com/huawei/ohos/Compressor.java index 1dda71ceddda908d191bceb69e197fd12ecf53a2..1020310c5d0b7115f5062e26a07e46b77b74641f 100755 --- a/com/huawei/ohos/Compressor.java +++ b/com/huawei/ohos/Compressor.java @@ -25,10 +25,8 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; -import java.io.OutputStream; import java.nio.charset.StandardCharsets; import java.nio.file.attribute.FileTime; -import java.nio.file.Files; import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -95,6 +93,13 @@ public class Compressor { private static final String PIC_2X2 = "2x2"; private static final String PIC_2X4 = "2x4"; private static final String PIC_4X4 = "4x4"; + private static final String REGEX_LANGUAGE = "^[a-z]{2}$"; + private static final String REGEX_SCRIPT = "^[A-Z][a-z]{3}$"; + private static final String REGEX_COUNTRY = "^[A-Z]{2,3}|[0-9]{3}$"; + private static final String REGEX_ORIENTATION = "^vertical|horizontal$"; + private static final String REGEX_DEVICE_TYPE = "^phone|tablet|car|tv|wearable|liteWearable$"; + private static final String REGEX_SCREEN_DENSITY = "^sdpi|mdpi|ldpi|xldpi|xxldpi$"; + private static final String REGEX_COLOR_MODE = "^light|dark$"; // set timestamp to get fixed MD5 @@ -109,11 +114,12 @@ public class Compressor { private static String versionName = ""; private ZipOutputStream zipOut = null; + private boolean mIsContain2x2EntryCard = true; private List list = new ArrayList(); private List formNamesList = new ArrayList(); private List fileNameList = new ArrayList(); - private List supportDimensionsList = Arrays.asList(PIC_1X2, PIC_2X4, PIC_4X4); + private List supportDimensionsList = Arrays.asList(PIC_1X2, PIC_2X2, PIC_2X4, PIC_4X4); /** * start compress. @@ -549,7 +555,10 @@ public class Compressor { } if (!utility.getEntryCardPath().isEmpty()) { getFileList(utility.getEntryCardPath()); - boolean isSatisfies = true; + if (!mIsContain2x2EntryCard) { + LOG.error("Compressor::compressPackResMode No 2x2 resource file exists"); + throw new BundleException("No 2x2 resource file exists"); + } for (String fileName : fileNameList) { if (fileName.endsWith(PNG_SUFFIX) || fileName.endsWith(UPPERCASE_PNG_SUFFIX)) { String fName = fileName.trim(); @@ -559,33 +568,34 @@ public class Compressor { + temp.length); continue; } - String fileModelName = temp[temp.length - 4]; - if (!isModelName(fileModelName)) { - LOG.error("Compressor::compressProcess compress failed ModelName Error!"); - isSatisfies = false; - break; + String moduleName = temp[temp.length - 4]; + if (!isModelName(moduleName)) { + LOG.error("Compressor::compressProcess compress pack.res failed, moduleName " + + moduleName + " is error, please check it in config.json"); + throw new BundleException("Compress pack.res failed, moduleName Error"); } String fileLanguageCountryName = temp[temp.length - 3]; - if (!isLanguageCountry(fileLanguageCountryName)) { - LOG.error("Compressor::compressProcess compress failed LanguageCountryName Error!"); - isSatisfies = false; - break; + if (!isThirdLevelDirectoryNameValid(fileLanguageCountryName)) { + LOG.error("Compressor::compressProcess compress failed third level directory name: " + + fileLanguageCountryName + " is invalid, please check it with reference to this example: " + + "zh_Hani_CN-vertical-car-mdpi-dark or zh_Hani_CN-vertical-car-mdpi"); + throw new BundleException("Compress failed third level directory name Error!"); } String filePicturingName = temp[temp.length - 1]; - if (!filePicturingName.contains(PIC_2X2) && !isPicturing(filePicturingName)) { - LOG.error("Compressor::compressProcess compress failed PicturingName Error!"); - isSatisfies = false; - break; + if (!isPicturing(filePicturingName, utility)) { + LOG.error("Compressor::compressProcess Compress pack.res failed, Invalid resource file" + + " name: " + filePicturingName + ", correct format example is formName-2x2.png"); + throw new BundleException("Compress pack.res failed, Invalid resource file name: " + + filePicturingName + ", correct format example is formName-2x2.png"); } } else { - isSatisfies = false; LOG.error("Compressor::compressProcess compress failed No image in PNG format is found!"); + throw new BundleException("Compress pack.res failed, compress failed No image in" + + " PNG format is found"); } } - if (isSatisfies) { - pathToFile(utility, utility.getEntryCardPath(), ENTRYCARD_NAME, false); - } + pathToFile(utility, utility.getEntryCardPath(), ENTRYCARD_NAME, false); } } @@ -604,6 +614,120 @@ public class Compressor { return false; } + private boolean isThirdLevelDirectoryNameValid(String thirdLevelDirectoryName) { + if (thirdLevelDirectoryName == null || thirdLevelDirectoryName.isEmpty()) { + return false; + } + if (ENTRYCARD_BASE_NAME.equals(thirdLevelDirectoryName)) { + return true; + } + // example: zh_Hani_CN-vertical-car-mdpi-dark or zh_Hani_CN-vertical-car-mdpi + int firstDelimiterIndex = thirdLevelDirectoryName.indexOf("_"); + if (firstDelimiterIndex < 0) { + return false; + } + String language = thirdLevelDirectoryName.substring(0, firstDelimiterIndex); + int secondDelimiterIndex = thirdLevelDirectoryName.indexOf("_", firstDelimiterIndex + 1); + if (secondDelimiterIndex < 0) { + return false; + } + String script = thirdLevelDirectoryName.substring(firstDelimiterIndex + 1, secondDelimiterIndex); + int thirdDelimiterIndex = thirdLevelDirectoryName.indexOf("-", secondDelimiterIndex + 1); + if (thirdDelimiterIndex < 0) { + return false; + } + String country = thirdLevelDirectoryName.substring(secondDelimiterIndex + 1, thirdDelimiterIndex); + if (!checkLanguage(language) || !checkScript(script) || !checkCountry(country)) { + return false; + } + int forthDelimiterIndex = thirdLevelDirectoryName.indexOf("-", thirdDelimiterIndex + 1); + if (forthDelimiterIndex < 0) { + return false; + } + String orientation = thirdLevelDirectoryName.substring(thirdDelimiterIndex + 1, forthDelimiterIndex); + int fifthDelimiterIndex = thirdLevelDirectoryName.indexOf("-", forthDelimiterIndex + 1); + if (fifthDelimiterIndex < 0) { + return false; + } + String deviceType = thirdLevelDirectoryName.substring(forthDelimiterIndex + 1, fifthDelimiterIndex); + if (!checkOrientation(orientation) || !checkDeviceType(deviceType)) { + return false; + } + int sixthDelimiterIndex = thirdLevelDirectoryName.indexOf("-", fifthDelimiterIndex + 1); + if (sixthDelimiterIndex < 0) { + String screenDensity = thirdLevelDirectoryName.substring(fifthDelimiterIndex + 1, + thirdLevelDirectoryName.length()); + return checkScreenDensity(screenDensity); + } else { + String screenDensity = thirdLevelDirectoryName.substring(fifthDelimiterIndex + 1, sixthDelimiterIndex); + if (!checkScreenDensity(screenDensity)) { + return false; + } + } + String colorMode = thirdLevelDirectoryName.substring(sixthDelimiterIndex + 1, thirdLevelDirectoryName.length()); + return checkColorMode(colorMode); + } + + private boolean checkLanguage(String language) { + if (!Pattern.compile(REGEX_LANGUAGE).matcher(language).matches()) { + LOG.error("Compressor::compressProcess language " + language + " is not in ISO 639-1 list"); + return false; + } + return true; + } + + private boolean checkScript(String script) { + if (!Pattern.compile(REGEX_SCRIPT).matcher(script).matches()) { + LOG.error("Compressor::compressProcess script " + script + " is not in ISO 15924 list"); + return false; + } + return true; + } + + private boolean checkCountry(String country) { + if (!Pattern.compile(REGEX_COUNTRY).matcher(country).matches()) { + LOG.error("Compressor::compressProcess country " + country + " is not in ISO 3166-1 list"); + return false; + } + return true; + } + + private boolean checkOrientation(String orientation) { + if (!Pattern.compile(REGEX_ORIENTATION).matcher(orientation).matches()) { + LOG.error("Compressor::compressProcess orientation " + orientation + + " is not in {vertical, horizontal} list"); + return false; + } + return true; + } + + private boolean checkDeviceType(String deviceType) { + if (!Pattern.compile(REGEX_DEVICE_TYPE).matcher(deviceType).matches()) { + LOG.error("Compressor::compressProcess deviceType " + deviceType + + " is not in {phone, tablet, car, tv, wearable, liteWearable} list"); + return false; + } + return true; + } + + private boolean checkScreenDensity(String screenDensity) { + if (!Pattern.compile(REGEX_SCREEN_DENSITY).matcher(screenDensity).matches()) { + LOG.error("Compressor::compressProcess screenDensity " + screenDensity + + " is not in {sdpi, mdpi, ldpi, xldpi, xxldpi} list"); + return false; + } + return true; + } + + private boolean checkColorMode(String colorMode) { + if (!Pattern.compile(REGEX_COLOR_MODE).matcher(colorMode).matches()) { + LOG.error("Compressor::compressProcess colorMode " + colorMode + + " is not in {light, dark} list"); + return false; + } + return true; + } + /** * Check whether languageCountryName meets specifications. * @@ -643,9 +767,10 @@ public class Compressor { * Check whether picturingName meets specifications. * * @param name picturingName + * @param utility common data * @return false and true */ - private boolean isPicturing(String name) { + private boolean isPicturing(String name, Utility utility) { boolean isSpecifications = false; if (name == null || name.isEmpty()) { return isSpecifications; @@ -660,21 +785,21 @@ public class Compressor { return false; } String formName = name.substring(0, delimiterIndex); - if (!formNamesList.contains(formName)) { - LOG.error("isPicturing: the name is not same as formName, name: " + formName); + if (!utility.getFormNameList().contains(formName)) { + LOG.error("isPicturing: the name is not same as formName, name: " + formName + " is not in " + + utility.getFormNameList().toString()); return false; } String dimension = name.substring(delimiterIndex + 1, name.lastIndexOf(".")); - return supportDimensionsList.contains(dimension); + if (!supportDimensionsList.contains(dimension)) { + LOG.error("isPicturing: the dimension: " + dimension + " is invalid, is not in the following list: " + + "{1X2, 2X2, 2X4, 4X4}"); + return false; + } + return true; } - /** - * get file list in filePath - * - * @param filePath file path - * @param fileList file path in arrayList - */ - private void getFileList(final String filePath) { + private void getFileList(final String filePath) throws BundleException { File file = new File(filePath); if (!file.exists()) { LOG.error("getFileList: file is not exists"); @@ -692,6 +817,14 @@ public class Compressor { deleteFile(f.getCanonicalPath()); continue; } + String snapshotDirectoryName = f.getParentFile().getName(); + if (!ENTRYCARD_SNAPSHOT_NAME.equals(snapshotDirectoryName)) { + LOG.error("The level-4 directory of EntryCard must be named as snapshot" + + ", but current is: " + snapshotDirectoryName); + throw new BundleException("The level-4 directory of EntryCard must be named as snapshot" + + ", but current is: " + snapshotDirectoryName); + } + checkContain2x2EntryCard(f.getParentFile()); fileNameList.add(f.getCanonicalPath()); } else if (f.isDirectory()) { getFileList(f.getCanonicalPath()); @@ -705,6 +838,29 @@ public class Compressor { } } + private void checkContain2x2EntryCard(final File snapshotDirectory) throws IOException, BundleException { + if (!snapshotDirectory.exists()) { + LOG.error("checkContain2x2EntryCard: file is not exist: " + snapshotDirectory.getName()); + throw new BundleException("checkContain2x2EntryCard: file is not exist"); + } + File[] files = snapshotDirectory.listFiles(); + if (files == null) { + LOG.error("checkContain2x2EntryCard: no file in this file path"); + throw new BundleException("checkContain2x2EntryCard: no file in this file path"); + } + + for (File entryCardFile : files) { + if (entryCardFile.isFile() && entryCardFile.getName().contains(PIC_2X2)) { + return; + } + } + mIsContain2x2EntryCard = false; + LOG.error("checkContain2x2EntryCard: must contain 2x2 entryCard, please check it in " + + snapshotDirectory.getCanonicalPath()); + throw new BundleException("checkContain2x2EntryCard: must contain 2x2 entryCard, please check it in " + + snapshotDirectory.getCanonicalPath()); + } + /** * compress file or directory. * @@ -1034,7 +1190,7 @@ public class Compressor { inputStreamReader = new InputStreamReader(fileInputStream, StandardCharsets.UTF_8); bufferedReader = new BufferedReader(inputStreamReader); bufferedReader.mark((int) srcFile.length() + 1); - // parse moduleName from config.json + // parse moduleName from pack.info parsePackModuleName(bufferedReader, utility); bufferedReader.reset(); parsePackFormName(bufferedReader, utility); @@ -1322,20 +1478,22 @@ public class Compressor { */ private void parsePackFormName(BufferedReader bufferedReader, Utility utility) throws BundleException { String lineStr = null; - boolean isDistroStart = false; try { + boolean isFormsStart = false; while ((lineStr = bufferedReader.readLine()) != null) { if (lineStr.contains("abilities")) { continue; } if (lineStr.contains(FORMS)) { + isFormsStart = true; continue; } if (lineStr.contains(JSON_END)) { continue; } - if (lineStr.contains(NAME)) { + if (isFormsStart && lineStr.contains(NAME)) { getNameFromString(lineStr, utility); + isFormsStart = false; } } } catch (IOException exception) { @@ -1360,14 +1518,15 @@ public class Compressor { throw new BundleException("Parse module name failed, module-name is invalid"); } int startIndex = lineStr.lastIndexOf(SEMICOLON, endIndex - 1) + 1; - String fromsName = lineStr.substring(startIndex, endIndex); - if (fromsName == null || fromsName.isEmpty()) { + String formName = lineStr.substring(startIndex, endIndex); + if (formName == null || formName.isEmpty()) { LOG.error("Compressor::getModuleNameFromString field module-name is empty"); throw new BundleException("Parse module name failed, module-name is empty"); } - String[] nameList = fromsName.split("\\."); + String[] nameList = formName.split("\\."); if (nameList.length <= 1) { - formNamesList.add(fromsName); + formNamesList.add(formName); + utility.addFormNameList(formName); } } catch (StringIndexOutOfBoundsException exception) { LOG.error("Compressor::parseModuleName field module-name is fault: " + exception.getMessage()); diff --git a/com/huawei/ohos/Utility.java b/com/huawei/ohos/Utility.java index 4b9976438d2d87f59f5cb06c01337ddfc481c6a9..ebf86e526f89eea1f4a9f7b35417c7e75d9ffa19 100755 --- a/com/huawei/ohos/Utility.java +++ b/com/huawei/ohos/Utility.java @@ -84,6 +84,7 @@ public class Utility { private List formattedJarPathList = new ArrayList<>(); private List formattedTxtPathList = new ArrayList<>(); private List formattedEntryCardPathList = new ArrayList<>(); + private List formNameList = new ArrayList<>(); public String getMode() { return mode; @@ -513,4 +514,22 @@ public class Utility { } } } + + /** + * Add form name. + * + * @param formName the name of form + */ + public void addFormNameList(String formName) { + this.formNameList.add(formName); + } + + /** + * Get all form names + * + * @return all form names + */ + public List getFormNameList() { + return formNameList; + } }