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.BufferedInputStream; 19 import java.io.BufferedOutputStream; 20 import java.io.BufferedReader; 21 import java.io.Closeable; 22 import java.io.File; 23 import java.io.FileInputStream; 24 import java.io.FileOutputStream; 25 import java.io.FileNotFoundException; 26 import java.io.InputStream; 27 import java.io.InputStreamReader; 28 import java.io.IOException; 29 import java.io.OutputStream; 30 import java.security.NoSuchAlgorithmException; 31 import java.util.ArrayList; 32 import java.util.Enumeration; 33 import java.util.HashMap; 34 import java.util.Optional; 35 import java.util.regex.Pattern; 36 import java.util.zip.ZipEntry; 37 import java.util.zip.ZipFile; 38 import java.util.zip.ZipInputStream; 39 import java.security.MessageDigest; 40 41 /** 42 * file tools 43 * 44 */ 45 class FileUtils { 46 private static final int BUFFER_SIZE = 1024; 47 private static final int SHA256_BUFFER_SIZE = 10240; 48 private static final Log LOG = new Log(FileUtils.class.toString()); 49 private static final String RESOURCE_PATH = "resources/base/profile/"; 50 private static final String SHA256 = "SHA-256"; 51 private static final String PATTERN = "[0-9A-Za-z/].{0,4095}"; 52 53 /** 54 * generate fileData byte stream 55 * 56 * @param filePath file path 57 * @return byte array 58 */ getFileData(final String filePath)59 public static byte[] getFileData(final String filePath) { 60 File file = new File(filePath); 61 long fileSize = file.length(); 62 byte[] buffer = new byte[(int) fileSize]; 63 if (fileSize > Integer.MAX_VALUE) { 64 LOG.error("file too big."); 65 return buffer; 66 } 67 FileInputStream fi = null; 68 try { 69 fi = new FileInputStream(file); 70 int offset = 0; 71 int numRead = 0; 72 while (offset < buffer.length && (numRead = fi.read(buffer, offset, buffer.length - offset)) >= 0) { 73 offset += numRead; 74 } 75 } catch (IOException exception) { 76 LOG.error("getFileData IOException error: " + exception.getMessage()); 77 return new byte[(int) fileSize]; 78 } finally { 79 closeStream(fi); 80 } 81 return buffer; 82 } 83 84 /** 85 * search filePath for special fileName 86 * 87 * @param fileName file name 88 * @param directory dir path 89 * @return filePath 90 */ searchFile(final String fileName, final String directory)91 public static Optional<String> searchFile(final String fileName, final String directory) { 92 ArrayList<String> fileList = new ArrayList<>(); 93 getFileList(directory, fileList); 94 for (String fileItem : fileList) { 95 if (fileItem.endsWith(fileName)) { 96 return Optional.ofNullable(fileItem); 97 } 98 } 99 return Optional.empty(); 100 } 101 102 /** 103 * get file list in filePath 104 * 105 * @param filePath file path 106 * @param fileList file path in arrayList 107 */ getFileList(final String filePath, ArrayList<String> fileList)108 public static void getFileList(final String filePath, ArrayList<String> fileList) { 109 File file = new File(filePath); 110 if (!file.exists()) { 111 LOG.error("getFileList: file is not exists."); 112 return; 113 } 114 File[] files = file.listFiles(); 115 if (files == null) { 116 LOG.error("getFileList: no file in this file path."); 117 return; 118 } 119 for (File f : files) { 120 try { 121 if (f.isFile()) { 122 fileList.add(f.getCanonicalPath()); 123 } else if (f.isDirectory()) { 124 getFileList(f.getCanonicalPath(), fileList); 125 } else { 126 LOG.error("It's not file or directory."); 127 } 128 } catch (IOException msg) { 129 LOG.error("IOException error: " + msg.getMessage()); 130 return; 131 } 132 } 133 } 134 135 /** 136 * get string from file 137 * 138 * @param filePath file path 139 * @return String for file 140 */ getFileContent(final String filePath)141 public static Optional<String> getFileContent(final String filePath) { 142 if (filePath.isEmpty()) { 143 return Optional.empty(); 144 } 145 BufferedReader reader = null; 146 FileInputStream fileInputStream = null; 147 InputStreamReader inputStreamReader = null; 148 StringBuilder content = new StringBuilder(); 149 try { 150 fileInputStream = new FileInputStream(filePath); 151 inputStreamReader = new InputStreamReader(fileInputStream, "UTF-8"); 152 reader = new BufferedReader(inputStreamReader); 153 String tempString; 154 while ((tempString = reader.readLine()) != null) { 155 content.append(tempString); 156 } 157 } catch (IOException msg) { 158 LOG.error("get file content fail, msg is " + msg.getMessage()); 159 return Optional.empty(); 160 } finally { 161 closeStream(reader); 162 closeStream(inputStreamReader); 163 closeStream(fileInputStream); 164 } 165 return Optional.ofNullable(content.toString()); 166 } 167 168 /** 169 * close file stream 170 * 171 * @param fileStream file stream 172 */ closeStream(Closeable fileStream)173 public static void closeStream(Closeable fileStream) { 174 try { 175 if (fileStream != null) { 176 fileStream.close(); 177 } 178 } catch (IOException msg) { 179 LOG.error("stream close Error, msg is " + msg.getMessage()); 180 } 181 } 182 183 /** 184 * delete file 185 * 186 * @param path file path which will be deleted 187 */ deleteFile(final String path)188 public static void deleteFile(final String path) { 189 File file = new File(path); 190 if (file.exists()) { 191 file.delete(); 192 } 193 } 194 195 /** 196 * unzip hap package to path 197 * 198 * @param hapPath zip file 199 * @param destDir path after unzip file 200 */ unzip(final String hapPath, final String destDir)201 public static void unzip(final String hapPath, final String destDir) { 202 File file = new File(destDir); 203 if (!file.exists()) { 204 file.mkdirs(); 205 } 206 207 ZipFile zipFile = null; 208 BufferedInputStream bis = null; 209 BufferedOutputStream bos = null; 210 FileOutputStream fos = null; 211 try { 212 zipFile = new ZipFile(hapPath); 213 Enumeration<? extends ZipEntry> entries = zipFile.entries(); 214 int entriesNum = 0; 215 while (entries.hasMoreElements()) { 216 entriesNum++; 217 ZipEntry entry = entries.nextElement(); 218 if (entry == null) { 219 continue; 220 } 221 String filePath = destDir + File.separator + entry.getName(); 222 if (!matchPattern(filePath)) { 223 LOG.error("Input invalid file: " + filePath); 224 throw new BundleException("Input invalid file " + filePath); 225 } 226 if (entry.isDirectory()) { 227 new File(filePath).mkdirs(); 228 continue; 229 } 230 231 bis = new BufferedInputStream(zipFile.getInputStream(entry)); 232 File newFile = new File(filePath); 233 File parent = newFile.getParentFile(); 234 if (parent != null && (!parent.exists())) { 235 parent.mkdirs(); 236 } 237 238 fos = new FileOutputStream(newFile); 239 bos = new BufferedOutputStream(fos, BUFFER_SIZE); 240 241 int count; 242 int total = 0; 243 byte[] data = new byte[BUFFER_SIZE]; 244 while ((count = bis.read(data, 0, BUFFER_SIZE)) != -1) { 245 bos.write(data, 0, count); 246 total += count; 247 } 248 249 bos.flush(); 250 bos.close(); 251 fos.close(); 252 bis.close(); 253 } 254 } catch (IOException | BundleException exception) { 255 LOG.error("unzip file failed " + exception.getMessage()); 256 } finally { 257 closeStream(bos); 258 closeStream(fos); 259 closeStream(bis); 260 closeStream(zipFile); 261 } 262 } 263 264 /** 265 * delete directory 266 * 267 * @param directory dir path which will be deleted 268 */ deleteDirectory(final String directory)269 public static void deleteDirectory(final String directory) { 270 File dir = new File(directory); 271 if (!dir.exists()) { 272 return; 273 } 274 275 File[] fileList = dir.listFiles(); 276 if (fileList == null) { 277 return; 278 } 279 for (File file : fileList) { 280 try { 281 if (file.isFile()) { 282 file.delete(); 283 } else if (file.isDirectory()) { 284 deleteDirectory(file.getCanonicalPath()); 285 } else { 286 LOG.error("It's not file or directory."); 287 } 288 } catch (IOException msg) { 289 LOG.error("deleteDirectory IOException : " + msg.getMessage()); 290 } 291 } 292 dir.delete(); 293 } 294 295 /** 296 * format filepath 297 * 298 * @param filePath file path which is need to format 299 * @return canonicalPath for filePath 300 */ getFormatedPath(final String filePath)301 public static Optional<String> getFormatedPath(final String filePath) { 302 String absPath; 303 try { 304 File file = new File(filePath); 305 absPath = file.getCanonicalPath(); 306 } catch (IOException msg) { 307 LOG.error("format path IOException : " + msg.getMessage()); 308 return Optional.empty(); 309 } 310 return Optional.of(absPath); 311 } 312 313 /** 314 * check file whether is exist or not 315 * 316 * @param filePath bin file path 317 * @return true: file is exist, false: file is not exist 318 */ checkFileIsExists(final String filePath)319 public static boolean checkFileIsExists(final String filePath) { 320 if (filePath.isEmpty()) { 321 return false; 322 } 323 324 Optional<String> absFilePath = getFormatedPath(filePath); 325 if (!absFilePath.isPresent()) { 326 return false; 327 } 328 329 File file = new File(absFilePath.get()); 330 if (!file.exists()) { 331 return false; 332 } 333 return true; 334 } 335 336 /** 337 * copy a file to another place. 338 * 339 * @param sourceFile is the source file 340 * @param destFile is the destination file 341 * @throws IOException FileNotFoundException|IOException. 342 */ copyFile(File sourceFile, File destFile)343 public static void copyFile(File sourceFile, File destFile) throws IOException, BundleException { 344 if (sourceFile == null || destFile == null) { 345 String errMsg = "CompressorFileUtil::copyFile input file is null."; 346 LOG.error(errMsg); 347 throw new BundleException(errMsg); 348 } 349 InputStream inputStream = null; 350 OutputStream outputStream = null; 351 try { 352 inputStream = new FileInputStream(sourceFile); 353 outputStream = new FileOutputStream(destFile); 354 byte[] buffer = new byte[BUFFER_SIZE]; 355 int length; 356 while ((length = inputStream.read(buffer)) > 0) { 357 outputStream.write(buffer, 0, length); 358 } 359 } finally { 360 Utility.closeStream(inputStream); 361 Utility.closeStream(outputStream); 362 } 363 } 364 365 /** 366 * make a directory if not exist. 367 * 368 * @param dirFile is the directory file 369 * @throws IOException FileNotFoundException|IOException. 370 */ makeDir(File dirFile)371 public static void makeDir(File dirFile) throws IOException, BundleException { 372 if (dirFile == null) { 373 String errMsg = "CompressorFileUtil::makeDir input file is null."; 374 LOG.error(errMsg); 375 throw new BundleException(errMsg); 376 } 377 dirFile.mkdirs(); 378 } 379 380 /** 381 * check json type code in haps. 382 * 383 * @param srcFile source file to zip 384 * @return true is for successful and false is for failed 385 * @throws BundleException FileNotFoundException|IOException. 386 */ getJsonInZips(File srcFile, String jsonName)387 public static String getJsonInZips(File srcFile, String jsonName) throws BundleException { 388 String fileStr = srcFile.getPath(); 389 ZipFile zipFile = null; 390 FileInputStream zipInput = null; 391 ZipInputStream zin = null; 392 InputStream inputStream = null; 393 InputStreamReader reader = null; 394 BufferedReader br = null; 395 ZipEntry entry = null; 396 StringBuilder jsonStr = new StringBuilder(); 397 try { 398 zipFile = new ZipFile(srcFile); 399 zipInput = new FileInputStream(fileStr); 400 zin = new ZipInputStream(zipInput); 401 while ((entry = zin.getNextEntry()) != null) { 402 if (entry.getName().toLowerCase().equals(jsonName)) { 403 inputStream = zipFile.getInputStream(entry); 404 reader = new InputStreamReader(inputStream); 405 br = new BufferedReader(reader); 406 String line; 407 while ((line = br.readLine()) != null) { 408 jsonStr.append(line); 409 } 410 inputStream.close(); 411 } 412 } 413 jsonStr = new StringBuilder(jsonStr.toString().replaceAll("\r|\n|\t", "")); 414 } catch (IOException exception) { 415 LOG.error("Compressor::checkModuleTypeInHaps io exception: " + exception.getMessage()); 416 throw new BundleException("Compressor::checkModuleTypeInHaps failed."); 417 } finally { 418 Utility.closeStream(zipFile); 419 Utility.closeStream(zipInput); 420 Utility.closeStream(zin); 421 Utility.closeStream(inputStream); 422 Utility.closeStream(reader); 423 Utility.closeStream(br); 424 } 425 return jsonStr.toString(); 426 } 427 428 /** 429 * get all resource file in profile. 430 * 431 * @param zipFile is the hap file 432 * @throws BundleException when get profile json file failed 433 */ getProfileJson(ZipFile zipFile)434 static HashMap<String, String> getProfileJson(ZipFile zipFile) throws BundleException { 435 HashMap<String, String> resourceMap = new HashMap<>(); 436 try { 437 final Enumeration<? extends ZipEntry> entries = zipFile.entries(); 438 while (entries.hasMoreElements()) { 439 final ZipEntry entry = entries.nextElement(); 440 if (entry.getName().contains(RESOURCE_PATH)) { 441 String filePath = entry.getName(); 442 String fileName = filePath.replaceAll(RESOURCE_PATH, ""); 443 String fileContent = getFileStringFromZip(filePath, zipFile); 444 resourceMap.put(fileName, fileContent); 445 } 446 } 447 } catch (IOException e) { 448 LOG.error("FileUtil::getProfileJson IOException: " + e.getMessage()); 449 throw new BundleException("FileUtil::getProfileJson failed."); 450 } 451 return resourceMap; 452 } 453 454 /** 455 * get file content in string from zip 456 * 457 * @param fileName is the file name we want to read 458 * @param zipFile is the zip file 459 */ getFileStringFromZip(String fileName, ZipFile zipFile)460 public static String getFileStringFromZip(String fileName, ZipFile zipFile) 461 throws IOException { 462 ZipEntry entry = zipFile.getEntry(fileName); 463 if (entry == null) { 464 LOG.debug("Uncompress::readStringFromFile " + fileName + " not found exception."); 465 return ""; 466 } 467 InputStream fileInputStream = null; 468 BufferedReader bufferedReader = null; 469 try { 470 fileInputStream = zipFile.getInputStream(entry); 471 bufferedReader = new BufferedReader(new InputStreamReader(fileInputStream, "UTF-8")); 472 String line; 473 StringBuilder sb = new StringBuilder(); 474 while ((line = bufferedReader.readLine()) != null) { 475 sb.append(line); 476 } 477 return sb.toString(); 478 } finally { 479 Utility.closeStream(bufferedReader); 480 Utility.closeStream(fileInputStream); 481 } 482 } 483 484 /** 485 * get sha-256 for file 486 * 487 * @param hapPath is the input path of file 488 */ getSha256(String hapPath)489 public static String getSha256(String hapPath) { 490 String sha256 = ""; 491 BufferedInputStream inputStream = null; 492 try { 493 File file = new File(hapPath); 494 inputStream = new BufferedInputStream(new FileInputStream(file)); 495 byte[] buffer = new byte[SHA256_BUFFER_SIZE]; 496 MessageDigest md5 = MessageDigest.getInstance(SHA256); 497 int size = -1; 498 while ((size = inputStream.read(buffer)) != -1) { 499 md5.update(buffer, 0, size); 500 } 501 sha256 = toHex(md5.digest()); 502 } catch (FileNotFoundException e) { 503 LOG.error("input hap file is not found: " + e.getMessage()); 504 } catch (NoSuchAlgorithmException e) { 505 LOG.error("can not provide sha-256 algorithm: " + e.getMessage()); 506 } catch (IOException e) { 507 LOG.error("input hap IO exception: " + e.getMessage()); 508 } finally { 509 Utility.closeStream(inputStream); 510 } 511 return sha256; 512 } 513 toHex(byte[] data)514 private static String toHex(byte[] data) { 515 StringBuilder hexString = new StringBuilder(); 516 for (byte item : data) { 517 hexString.append(Integer.toHexString(item & 0xFF)); 518 } 519 return hexString.toString(); 520 } 521 522 /** 523 * unzip file 524 * 525 * @param zipFilePath is the zipFilePath 526 * @param destDirPath is the output dest path 527 */ unzipFile(String zipFilePath, String destDirPath)528 public static boolean unzipFile(String zipFilePath, String destDirPath) { 529 boolean success = false; 530 File destDir = new File(destDirPath); 531 if (!destDir.exists()) { 532 destDir.mkdirs(); 533 } 534 ZipInputStream zipInputStream = null; 535 try { 536 zipInputStream = new ZipInputStream(new FileInputStream(zipFilePath)); 537 ZipEntry entry = zipInputStream.getNextEntry(); 538 while (entry != null) { 539 String filePath = destDirPath + File.separator + entry.getName(); 540 if (!matchPattern(filePath)) { 541 LOG.error("Input invalid file " + filePath + "."); 542 return false; 543 } 544 if (!entry.isDirectory()) { 545 extractFile(zipInputStream, filePath); 546 } else { 547 File dir = new File(filePath); 548 dir.mkdirs(); 549 } 550 zipInputStream.closeEntry(); 551 entry = zipInputStream.getNextEntry(); 552 } 553 success = true; 554 } catch (IOException e) { 555 LOG.error("FileUtil::unzipFile failed, IOException is " + e.getMessage()); 556 } finally { 557 Utility.closeStream(zipInputStream); 558 } 559 return success; 560 } 561 extractFile(ZipInputStream zipInputStream, String filePath)562 private static void extractFile(ZipInputStream zipInputStream, String filePath) { 563 BufferedOutputStream bufferedOutputStream = null; 564 try { 565 if (!matchPattern(filePath)) { 566 LOG.error("input invalid file: " + filePath); 567 throw new BundleException("input invalid file " + filePath + "."); 568 } 569 bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(filePath)); 570 byte[] bytes = new byte[BUFFER_SIZE]; 571 int readLength = 0; 572 while ((readLength = zipInputStream.read(bytes)) != -1) { 573 bufferedOutputStream.write(bytes, 0, readLength); 574 } 575 } catch (IOException | BundleException e) { 576 LOG.error("FileUtil::extractFile failed, Exception is " + e.getMessage()); 577 } finally { 578 Utility.closeStream(bufferedOutputStream); 579 } 580 } 581 matchPattern(String path)582 static boolean matchPattern(String path) { 583 if (!Pattern.matches(PATTERN, path)) { 584 LOG.error("input invalid file of " + path + "."); 585 return false; 586 } 587 return true; 588 } 589 590 /** 591 * getFileSize 592 * 593 * @param filePath is the input file path 594 * @return file length 595 */ getFileSize(String filePath)596 public static long getFileSize(String filePath) { 597 File file = new File(filePath); 598 if (file.exists() && file.isFile()) { 599 return file.length(); 600 } 601 LOG.error("input " + filePath + " is not a valid file."); 602 return 0; 603 } 604 } 605