1 /* 2 * Copyright (c) 2021 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 package ohos; 17 18 import java.io.File; 19 import java.util.ArrayList; 20 import java.util.List; 21 import java.util.Locale; 22 23 /** 24 * compress commend parser. 25 * 26 */ 27 public class CompressVerify { 28 private static final String COMMA_SPLIT = ","; 29 private static final String JSON_PROFILE = "config.json"; 30 private static final String MODULE_PROFILE = "module.json"; 31 private static final String PROFILE_NAME = "CAPABILITY.profile"; 32 private static final String INDEX_PROFILE = "resources.index"; 33 private static final String RPCID_PROFILE = "rpcid.sc"; 34 private static final String PACK_INFO = "pack.info"; 35 private static final String PACK_RES = "pack.res"; 36 private static final String HAP_SUFFIX = ".hap"; 37 private static final String HAR_SUFFIX = ".har"; 38 private static final String APP_SUFFIX = ".app"; 39 private static final String APK_SUFFIX = ".apk"; 40 private static final String DEX_SUFFIX = ".dex"; 41 private static final String ABC_SUFFIX = ".abc"; 42 private static final String SO_SUFFIX = ".so"; 43 private static final String JAR_SUFFIX = ".jar"; 44 private static final String TXT_SUFFIX = ".txt"; 45 private static final String PNG_SUFFIX = ".png"; 46 private static final String RES_SUFFIX = ".res"; 47 private static final String ENTRY_CARD_DIRECTORY_NAME = "EntryCard"; 48 49 private static final Log LOG = new Log(CompressVerify.class.toString()); 50 51 private static final boolean TYPE_FILE = true; 52 private static final boolean TYPE_DIR = false; 53 54 /** 55 * if args valid. 56 * 57 * @param utility common data 58 * @return commandVerify if command valid. 59 */ commandVerify(Utility utility)60 public static boolean commandVerify(Utility utility) { 61 if (utility == null) { 62 LOG.error("CompressVerify::commandVerify utility is null!"); 63 return false; 64 } 65 66 if (!utility.getForceRewrite().isEmpty() && !"true".equals(utility.getForceRewrite()) 67 && !"false".equals(utility.getForceRewrite())) { 68 LOG.error("CompressVerify::commandVerify forceRewrite is invalid!"); 69 return false; 70 } 71 return commandPathVerify(utility); 72 } 73 74 /** 75 * verify path. 76 * 77 * @param utility common data 78 * @return commandPathVerify if command valid. 79 */ commandPathVerify(Utility utility)80 private static boolean commandPathVerify(Utility utility) { 81 if (Utility.MODE_HAP.equals(utility.getMode())) { 82 if (!utility.getJsonPath().isEmpty()) { 83 File file = new File(utility.getJsonPath()); 84 if (!file.isFile()) { 85 LOG.error("CompressVerify::isArgsValidInHapMode json-path is not a file!"); 86 return false; 87 } 88 if (!file.getName().equals(JSON_PROFILE) && !file.getName().equals(MODULE_PROFILE)) { 89 LOG.error("CompressVerify::isArgsValidInHapMode json-path must be config.json or module.json file!"); 90 return false; 91 } 92 } 93 94 if (!utility.getRpcidPath().isEmpty()) { 95 File file = new File(utility.getRpcidPath()); 96 if (!file.isFile()) { 97 LOG.error("CompressVerify::isArgsValidInHapMode rpcid-path is not a file!"); 98 return false; 99 } 100 if (!file.getName().equals(RPCID_PROFILE)) { 101 LOG.error("CompressVerify::isArgsValidInHapMode rpcid-path must be rpcid.sc file!"); 102 return false; 103 } 104 } 105 106 if (!utility.getApkPath().isEmpty() && !compatibleProcess(utility, utility.getApkPath(), 107 utility.getFormattedApkPathList(), APK_SUFFIX)) { 108 LOG.error("CompressVerify::isArgsValidInHapMode shell-apk-path is invalid!"); 109 return false; 110 } 111 112 if (!utility.getProfilePath().isEmpty()) { 113 File file = new File(utility.getProfilePath()); 114 if (!file.isFile() || !file.getName().equals(PROFILE_NAME)) { 115 LOG.error("CompressVerify::isArgsValidInHapMode profile-path must be CAPABILITY.profile file!"); 116 return false; 117 } 118 } 119 120 if (!utility.getDexPath().isEmpty() && !compatibleProcess(utility, utility.getDexPath(), 121 utility.getFormattedDexPathList(), DEX_SUFFIX)) { 122 LOG.error("CompressVerify::isArgsValidInHapMode dex-path is invalid!"); 123 return false; 124 } 125 126 if (!utility.getAbcPath().isEmpty() && !compatibleProcess(utility, utility.getAbcPath(), 127 utility.getFormattedAbcPathList(), ABC_SUFFIX)) { 128 LOG.error("CompressVerify::isArgsValidInHapMode abc-path is invalid!"); 129 return false; 130 } 131 132 return isVerifyValidInHapMode(utility); 133 } else if (Utility.MODE_HAR.equals(utility.getMode())) { 134 return isVerifyValidInHarMode(utility); 135 } else if (Utility.MODE_APP.equals(utility.getMode())) { 136 return isVerifyValidInAppMode(utility); 137 } else if (Utility.MODE_RES.equals(utility.getMode())) { 138 return isVerifyValidInResMode(utility); 139 } else { 140 LOG.error("CompressVerify::commandVerify mode is invalid!"); 141 return false; 142 } 143 } 144 145 /** 146 * parse and check args if valid in hap mode. 147 * 148 * @param utility common data 149 * @return isVerifyValidInHapMode if verify valid in hap mode. 150 */ isVerifyValidInHapMode(Utility utility)151 private static boolean isVerifyValidInHapMode(Utility utility) { 152 File file = new File(utility.getIndexPath()); 153 if (!utility.getIndexPath().isEmpty() && !file.isFile() && file.getName().equals(INDEX_PROFILE)) { 154 LOG.error("CompressVerify::isArgsValidInHapMode index-path must be resources.index file!"); 155 return false; 156 } 157 158 if (!utility.getSoPath().isEmpty() && 159 !compatibleProcess(utility, utility.getSoPath(), utility.getFormattedSoPathList(), SO_SUFFIX)) { 160 LOG.error("CompressVerify::isArgsValidInHapMode maple-so-path is invalid!"); 161 return false; 162 } 163 164 if (!utility.getAbilitySoPath().isEmpty() && !compatibleProcess(utility, utility.getAbilitySoPath(), 165 utility.getFormattedAbilitySoPathList(), SO_SUFFIX)) { 166 LOG.error("CompressVerify::isArgsValidInHapMode ability-so-path is invalid!"); 167 return false; 168 } 169 170 if (isHapPathValid(utility.getSoDir())) { 171 LOG.error("CompressVerify::isArgsValidInHapMode maple-so-dir is invalid!"); 172 return false; 173 } 174 175 if (isHapPathValid(utility.getLibPath())) { 176 LOG.error("CompressVerify::isArgsValidInHapMode lib-path is invalid!"); 177 return false; 178 } 179 180 if (isHapPathValid(utility.getResPath())) { 181 LOG.error("CompressVerify::isArgsValidInHapMode res-path is invalid!"); 182 return false; 183 } 184 185 if (isHapPathValid(utility.getResourcesPath())) { 186 LOG.error("CompressVerify::isArgsValidInHapMode resources-path is invalid!"); 187 return false; 188 } 189 190 if (isHapPathValid(utility.getAssetsPath())) { 191 LOG.error("CompressVerify::isArgsValidInHapMode assets-path is invalid!"); 192 return false; 193 } 194 195 if (isHapPathValid(utility.getSharedLibsPath())) { 196 LOG.error("CompressVerify::isArgsValidInHapMode shared-libs-path is invalid!"); 197 return false; 198 } 199 200 if (!utility.getJarPath().isEmpty() 201 && !compatibleProcess(utility, utility.getJarPath(), utility.getFormattedJarPathList(), JAR_SUFFIX)) { 202 LOG.error("CompressVerify::isArgsValidInHapMode jar-path is invalid!"); 203 return false; 204 } 205 206 if (!utility.getTxtPath().isEmpty() 207 && !compatibleProcess(utility, utility.getTxtPath(), utility.getFormattedTxtPathList(), TXT_SUFFIX)) { 208 LOG.error("CompressVerify::isArgsValidInHapMode txt-path is invalid!"); 209 return false; 210 } 211 212 213 if (!utility.getPackInfoPath().isEmpty() && !isPathValid(utility.getPackInfoPath(), TYPE_FILE, PACK_INFO)) { 214 LOG.error("CompressVerify::isArgsValidInHapMode pack-info-path is invalid!"); 215 return false; 216 } 217 218 return isOutPathValid(utility, HAP_SUFFIX); 219 } 220 221 /** 222 * check hap path if valid 223 * 224 * @param path path input 225 * @return isPathValid if path verify 226 */ isHapPathValid(String path)227 private static boolean isHapPathValid(String path) { 228 return (!path.isEmpty() && !isPathValid(path, TYPE_DIR, null)); 229 } 230 231 /** 232 * parse and check args if valid in har mode. 233 * 234 * @param utility common data 235 * @return isVerifyValidInHarMode if verify valid in har mode. 236 */ isVerifyValidInHarMode(Utility utility)237 private static boolean isVerifyValidInHarMode(Utility utility) { 238 if (utility.getJsonPath().isEmpty()) { 239 LOG.error("CompressVerify::isArgsValidInHarMode json-path is empty!"); 240 return false; 241 } 242 243 if (!isPathValid(utility.getJsonPath(), TYPE_FILE, JSON_PROFILE) 244 && !isPathValid(utility.getJsonPath(), TYPE_FILE, MODULE_PROFILE)) { 245 LOG.error("CompressVerify::isArgsValidInHarMode json-path must be config.json file!"); 246 return false; 247 } 248 249 if (!utility.getJarPath().isEmpty() 250 && !compatibleProcess(utility, utility.getJarPath(), utility.getFormattedJarPathList(), JAR_SUFFIX)) { 251 LOG.error("CompressVerify::isArgsValidInHarMode jar-path is invalid!"); 252 return false; 253 } 254 255 if (!utility.getTxtPath().isEmpty() 256 && !compatibleProcess(utility, utility.getTxtPath(), utility.getFormattedTxtPathList(), TXT_SUFFIX)) { 257 LOG.error("CompressVerify::isArgsValidInHarMode txt-path is invalid!"); 258 return false; 259 } 260 261 if (!utility.getLibPath().isEmpty() && !isPathValid(utility.getLibPath(), TYPE_DIR, null)) { 262 LOG.error("CompressVerify::isArgsValidInHarMode lib-path is invalid!"); 263 return false; 264 } 265 266 if (!utility.getResPath().isEmpty() && !isPathValid(utility.getResPath(), TYPE_DIR, null)) { 267 LOG.error("CompressVerify::isArgsValidInHarMode res-path is invalid!"); 268 return false; 269 } 270 271 if (utility.getResourcesPath().isEmpty() || !isPathValid(utility.getResourcesPath(), TYPE_DIR, null)) { 272 LOG.error("CompressVerify::isArgsValidInHarMode resources-path is invalid!"); 273 return false; 274 } 275 276 if (!utility.getAssetsPath().isEmpty() && !isPathValid(utility.getAssetsPath(), TYPE_DIR, null)) { 277 LOG.error("CompressVerify::isArgsValidInHarMode assets-path is invalid!"); 278 return false; 279 } 280 281 return isOutPathValid(utility, HAR_SUFFIX); 282 } 283 284 /** 285 * parse and check args if valid in app mode. 286 * 287 * @param utility common data 288 * @return isVerifyValidInAppMode if verify valid in app mode. 289 */ isVerifyValidInAppMode(Utility utility)290 private static boolean isVerifyValidInAppMode(Utility utility) { 291 if (utility.getHapPath().isEmpty()) { 292 LOG.error("CompressVerify::isArgsValidInAppMode hap-path is empty!"); 293 return false; 294 } 295 296 if (!compatibleProcess(utility, utility.getHapPath(), utility.getFormattedHapPathList(), HAP_SUFFIX)) { 297 LOG.error("CompressVerify::isArgsValidInAppMode hap-path is invalid!"); 298 return false; 299 } 300 301 if (utility.getPackInfoPath().isEmpty()) { 302 LOG.error("CompressVerify::isArgsValidInAppMode pack-info-path is empty!"); 303 return false; 304 } 305 306 File file = new File(utility.getPackInfoPath()); 307 if (!file.isFile() || !file.getName().equals(PACK_INFO)) { 308 LOG.error("CompressVerify::isArgsValidInAppMode pack-info-path is invalid!"); 309 return false; 310 } 311 312 if (!utility.getSignaturePath().isEmpty() && !(new File(utility.getSignaturePath())).isFile()) { 313 LOG.error("CompressVerify::isArgsValidInAppMode signature-path is invalid!"); 314 return false; 315 } 316 317 if (!utility.getCertificatePath().isEmpty() && !(new File(utility.getCertificatePath())).isFile()) { 318 LOG.error("CompressVerify::isArgsValidInAppMode certificate-path is invalid!"); 319 return false; 320 } 321 322 if (!utility.getEntryCardPath().isEmpty() && 323 !compatibleProcess(utility, utility.getEntryCardPath(), 324 utility.getformattedEntryCardPathList(), PNG_SUFFIX)) { 325 LOG.error("CompressVerify::isArgsValidInAppMode entrycard-path is invalid!"); 326 return false; 327 } 328 if (!utility.getPackResPath().isEmpty() && !isPathValid(utility.getPackResPath(), TYPE_FILE, PACK_RES)) { 329 LOG.error("CompressVerify::isArgsValidInAppMode pack-res-path is invalid!:" ); 330 return false; 331 } 332 333 return isOutPathValid(utility, APP_SUFFIX); 334 } 335 336 337 /** 338 * parse and check args if valid in res mode. 339 * 340 * @param utility common data 341 * @return isVerifyValidInAppMode if verify valid in app mode. 342 */ isVerifyValidInResMode(Utility utility)343 private static boolean isVerifyValidInResMode(Utility utility) { 344 if (!isPathValid(utility.getPackInfoPath(), TYPE_FILE, PACK_INFO)) { 345 LOG.error("CompressVerify::isArgsValidInResMode pack-info-path is invalid!"); 346 return false; 347 } 348 349 if (!isDirectoryValidStrictCase(utility.getEntryCardPath(), ENTRY_CARD_DIRECTORY_NAME)) { 350 LOG.error("CompressVerify::isArgsValidInResMode the level-1 directory name must is EntryCard" + 351 ", current is " + utility.getEntryCardPath()); 352 return false; 353 } 354 if (!compatibleProcess(utility, utility.getEntryCardPath(), 355 utility.getformattedEntryCardPathList(), PNG_SUFFIX)) { 356 LOG.error("CompressVerify::isArgsValidInResMode entrycard-path is invalid!"); 357 return false; 358 } 359 return isOutPathValid(utility, RES_SUFFIX); 360 } 361 362 363 /** 364 * Compatible file input and directory input 365 * 366 * @param utility common data 367 * @param inputPath input path 368 * @param fileList save files' path with list 369 * @param suffix process type 370 * @return Returns {@code true} if the compatible is successful; returns {@code false} otherwise. 371 */ compatibleProcess(Utility utility, String inputPath, List<String> fileList, String suffix)372 private static boolean compatibleProcess(Utility utility, String inputPath, 373 List<String> fileList, String suffix) { 374 if (isPathValid(inputPath, TYPE_DIR, null)) { 375 File inputFile = new File(inputPath); 376 File[] files = inputFile.listFiles(); 377 if (files == null) { 378 return true; 379 } 380 for (File fileItem : files) { 381 if (fileItem.getName().toLowerCase(Locale.ENGLISH).endsWith(suffix)) { 382 fileList.add(fileItem.toString()); 383 } 384 } 385 return true; 386 } else { 387 String formattedPathItem = ""; 388 List<String> pathList = removeDuplicatePath(inputPath); 389 for (String pathItem : pathList) { 390 formattedPathItem = utility.getFormattedPath(pathItem); 391 if (!isPathValid(formattedPathItem, TYPE_FILE, suffix)) { 392 return false; 393 } 394 fileList.add(formattedPathItem); 395 } 396 return true; 397 } 398 } 399 400 /** 401 * turn input path block to formatted path list 402 * 403 * @param utility common data 404 * @param suffix used to determine type 405 * @return isVerifyValidInAppMode if verify valid in app mode. 406 */ isOutPathValid(Utility utility, String suffix)407 private static boolean isOutPathValid(Utility utility, String suffix) { 408 File outFile = new File(utility.getOutPath()); 409 410 if (("false".equals(utility.getForceRewrite())) && (outFile.exists())) { 411 LOG.error("CompressVerify::isOutPathValid out file already existed!"); 412 return false; 413 } 414 415 if (HAP_SUFFIX.equals(suffix)) { 416 if (!outFile.getName().toLowerCase(Locale.ENGLISH).endsWith(HAP_SUFFIX)) { 417 LOG.error("CompressVerify::isOutPathValid out-path must end with .hap!"); 418 return false; 419 } else { 420 return true; 421 } 422 } 423 424 if (HAR_SUFFIX.equals(suffix)) { 425 if (!outFile.getName().toLowerCase(Locale.ENGLISH).endsWith(HAR_SUFFIX)) { 426 LOG.error("CompressVerify::isOutPathValid out-path must end with .har!"); 427 return false; 428 } else { 429 return true; 430 } 431 } 432 433 if (APP_SUFFIX.equals(suffix)) { 434 if (!outFile.getName().toLowerCase(Locale.ENGLISH).endsWith(APP_SUFFIX)) { 435 LOG.error("CompressVerify::isOutPathValid out-path must end with .app!"); 436 return false; 437 } else { 438 return true; 439 } 440 } 441 442 if (RES_SUFFIX.equals(suffix)) { 443 if (!outFile.getName().toLowerCase(Locale.ENGLISH).endsWith(RES_SUFFIX)) { 444 LOG.error("CompressVerify::isOutPathValid out-path must end with .res!"); 445 return false; 446 } else { 447 return true; 448 } 449 } 450 451 return false; 452 } 453 454 /** 455 * check path if valid 456 * 457 * @param path path input 458 * @param isFile type input 459 * @param flag flag input 460 * @return isPathValid if path verify 461 */ isPathValid(String path, boolean isFile, String flag)462 private static boolean isPathValid(String path, boolean isFile, String flag) { 463 File file = new File(path); 464 if (isFile && (file.isFile()) && file.getName().toLowerCase(Locale.ENGLISH).endsWith(flag)) { 465 return true; 466 } 467 return (!isFile) && file.isDirectory(); 468 } 469 isDirectoryValidStrictCase(String path, String directoryName)470 private static boolean isDirectoryValidStrictCase(String path, String directoryName) { 471 File file = new File(path); 472 if (!file.exists()) { 473 LOG.error("CompressVerify::isDirectoryValidStrictCase directory is not exist, directoryPath: " 474 + path); 475 return false; 476 } 477 if (file.isDirectory()) { 478 return directoryName.equals(file.getName()); 479 } 480 return false; 481 } 482 483 /** 484 * remove duplicate in path. 485 * 486 * @param path input path, use comma separate. 487 * @return result list 488 */ removeDuplicatePath(String path)489 private static List<String> removeDuplicatePath(String path) { 490 String[] array = path.split(COMMA_SPLIT); 491 List<String> list = new ArrayList<>(); 492 493 for (String item : array) { 494 if (!list.contains(item)) { 495 list.add(item); 496 } 497 } 498 return list; 499 } 500 } 501