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,255}"; 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 throw new BundleException("Input invalid file " + filePath); 224 } 225 if (entry.isDirectory()) { 226 new File(filePath).mkdirs(); 227 continue; 228 } 229 230 bis = new BufferedInputStream(zipFile.getInputStream(entry)); 231 File newFile = new File(filePath); 232 File parent = newFile.getParentFile(); 233 if (parent != null && (!parent.exists())) { 234 parent.mkdirs(); 235 } 236 237 fos = new FileOutputStream(newFile); 238 bos = new BufferedOutputStream(fos, BUFFER_SIZE); 239 240 int count; 241 int total = 0; 242 byte[] data = new byte[BUFFER_SIZE]; 243 while ((count = bis.read(data, 0, BUFFER_SIZE)) != -1) { 244 bos.write(data, 0, count); 245 total += count; 246 } 247 248 bos.flush(); 249 bos.close(); 250 fos.close(); 251 bis.close(); 252 } 253 } catch (IOException | BundleException exception) { 254 LOG.error("unzip file failed " + exception.getMessage()); 255 } finally { 256 closeStream(bos); 257 closeStream(fos); 258 closeStream(bis); 259 closeStream(zipFile); 260 } 261 } 262 263 /** 264 * delete directory 265 * 266 * @param directory dir path which will be deleted 267 */ deleteDirectory(final String directory)268 public static void deleteDirectory(final String directory) { 269 File dir = new File(directory); 270 if (!dir.exists()) { 271 return; 272 } 273 274 File[] fileList = dir.listFiles(); 275 if (fileList == null) { 276 return; 277 } 278 for (File file : fileList) { 279 try { 280 if (file.isFile()) { 281 file.delete(); 282 } else if (file.isDirectory()) { 283 deleteDirectory(file.getCanonicalPath()); 284 } else { 285 LOG.error("It's not file or directory."); 286 } 287 } catch (IOException msg) { 288 LOG.error("deleteDirectory IOException : " + msg.getMessage()); 289 } 290 } 291 dir.delete(); 292 } 293 294 /** 295 * format filepath 296 * 297 * @param filePath file path which is need to format 298 * @return canonicalPath for filePath 299 */ getFormatedPath(final String filePath)300 public static Optional<String> getFormatedPath(final String filePath) { 301 String absPath; 302 try { 303 File file = new File(filePath); 304 absPath = file.getCanonicalPath(); 305 } catch (IOException msg) { 306 LOG.error("format path IOException : " + msg.getMessage()); 307 return Optional.empty(); 308 } 309 return Optional.of(absPath); 310 } 311 312 /** 313 * check file whether is exist or not 314 * 315 * @param filePath bin file path 316 * @return true: file is exist, false: file is not exist 317 */ checkFileIsExists(final String filePath)318 public static boolean checkFileIsExists(final String filePath) { 319 if (filePath.isEmpty()) { 320 return false; 321 } 322 323 Optional<String> absFilePath = getFormatedPath(filePath); 324 if (!absFilePath.isPresent()) { 325 return false; 326 } 327 328 File file = new File(absFilePath.get()); 329 if (!file.exists()) { 330 return false; 331 } 332 return true; 333 } 334 335 /** 336 * copy a file to another place. 337 * 338 * @param sourceFile is the source file 339 * @param destFile is the destination file 340 * @throws IOException FileNotFoundException|IOException. 341 */ copyFile(File sourceFile, File destFile)342 public static void copyFile(File sourceFile, File destFile) throws IOException, BundleException { 343 if (sourceFile == null || destFile == null) { 344 String errMsg = "CompressorFileUtil::copyFile input file is null."; 345 LOG.error(errMsg); 346 throw new BundleException(errMsg); 347 } 348 InputStream inputStream = null; 349 OutputStream outputStream = null; 350 try { 351 inputStream = new FileInputStream(sourceFile); 352 outputStream = new FileOutputStream(destFile); 353 byte[] buffer = new byte[BUFFER_SIZE]; 354 int length; 355 while ((length = inputStream.read(buffer)) > 0) { 356 outputStream.write(buffer, 0, length); 357 } 358 } finally { 359 Utility.closeStream(inputStream); 360 Utility.closeStream(outputStream); 361 } 362 } 363 364 /** 365 * make a directory if not exist. 366 * 367 * @param dirFile is the directory file 368 * @throws IOException FileNotFoundException|IOException. 369 */ makeDir(File dirFile)370 public static void makeDir(File dirFile) throws IOException, BundleException { 371 if (dirFile == null) { 372 String errMsg = "CompressorFileUtil::makeDir input file is null."; 373 LOG.error(errMsg); 374 throw new BundleException(errMsg); 375 } 376 dirFile.mkdirs(); 377 } 378 379 /** 380 * check json type code in haps. 381 * 382 * @param srcFile source file to zip 383 * @return true is for successful and false is for failed 384 * @throws BundleException FileNotFoundException|IOException. 385 */ getJsonInZips(File srcFile, String jsonName)386 public static String getJsonInZips(File srcFile, String jsonName) throws BundleException { 387 String fileStr = srcFile.getPath(); 388 ZipFile zipFile = null; 389 FileInputStream zipInput = null; 390 ZipInputStream zin = null; 391 InputStream inputStream = null; 392 InputStreamReader reader = null; 393 BufferedReader br = null; 394 ZipEntry entry = null; 395 StringBuilder jsonStr = new StringBuilder(); 396 try { 397 zipFile = new ZipFile(srcFile); 398 zipInput = new FileInputStream(fileStr); 399 zin = new ZipInputStream(zipInput); 400 while ((entry = zin.getNextEntry()) != null) { 401 if (entry.getName().toLowerCase().equals(jsonName)) { 402 inputStream = zipFile.getInputStream(entry); 403 reader = new InputStreamReader(inputStream); 404 br = new BufferedReader(reader); 405 String line; 406 while ((line = br.readLine()) != null) { 407 jsonStr.append(line); 408 } 409 inputStream.close(); 410 } 411 } 412 jsonStr = new StringBuilder(jsonStr.toString().replaceAll("\r|\n|\t", "")); 413 } catch (IOException exception) { 414 LOG.error("Compressor::checkModuleTypeInHaps io exception: " + exception.getMessage()); 415 throw new BundleException("Compressor::checkModuleTypeInHaps failed."); 416 } finally { 417 Utility.closeStream(zipFile); 418 Utility.closeStream(zipInput); 419 Utility.closeStream(zin); 420 Utility.closeStream(inputStream); 421 Utility.closeStream(reader); 422 Utility.closeStream(br); 423 } 424 return jsonStr.toString(); 425 } 426 427 /** 428 * get all resource file in profile. 429 * 430 * @param zipFile is the hap file 431 * @throws BundleException when get profile json file failed 432 */ getProfileJson(ZipFile zipFile)433 static HashMap<String, String> getProfileJson(ZipFile zipFile) throws BundleException { 434 HashMap<String, String> resourceMap = new HashMap<>(); 435 try { 436 final Enumeration<? extends ZipEntry> entries = zipFile.entries(); 437 while (entries.hasMoreElements()) { 438 final ZipEntry entry = entries.nextElement(); 439 if (entry.getName().contains(RESOURCE_PATH)) { 440 String filePath = entry.getName(); 441 String fileName = filePath.replaceAll(RESOURCE_PATH, ""); 442 String fileContent = getFileStringFromZip(filePath, zipFile); 443 resourceMap.put(fileName, fileContent); 444 } 445 } 446 } catch (IOException e) { 447 LOG.error("FileUtil::getProfileJson IOException."); 448 throw new BundleException("FileUtil::getProfileJson failed."); 449 } 450 return resourceMap; 451 } 452 453 /** 454 * get file content in string from zip 455 * 456 * @param fileName is the file name we want to read 457 * @param zipFile is the zip file 458 */ getFileStringFromZip(String fileName, ZipFile zipFile)459 public static String getFileStringFromZip(String fileName, ZipFile zipFile) 460 throws IOException { 461 ZipEntry entry = zipFile.getEntry(fileName); 462 if (entry == null) { 463 LOG.debug("Uncompress::readStringFromFile " + fileName + " not found exception."); 464 return ""; 465 } 466 InputStream fileInputStream = null; 467 BufferedReader bufferedReader = null; 468 try { 469 fileInputStream = zipFile.getInputStream(entry); 470 bufferedReader = new BufferedReader(new InputStreamReader(fileInputStream, "UTF-8")); 471 String line; 472 StringBuilder sb = new StringBuilder(); 473 while ((line = bufferedReader.readLine()) != null) { 474 sb.append(line); 475 } 476 return sb.toString(); 477 } finally { 478 Utility.closeStream(bufferedReader); 479 Utility.closeStream(fileInputStream); 480 } 481 } 482 483 /** 484 * get sha-256 for file 485 * 486 * @param hapPath is the input path of file 487 */ getSha256(String hapPath)488 public static String getSha256(String hapPath) { 489 String sha256 = ""; 490 BufferedInputStream inputStream = null; 491 try { 492 File file = new File(hapPath); 493 inputStream = new BufferedInputStream(new FileInputStream(file)); 494 byte[] buffer = new byte[SHA256_BUFFER_SIZE]; 495 MessageDigest md5 = MessageDigest.getInstance(SHA256); 496 int size = -1; 497 while ((size = inputStream.read(buffer)) != -1) { 498 md5.update(buffer, 0, size); 499 } 500 sha256 = toHex(md5.digest()); 501 } catch (FileNotFoundException e) { 502 LOG.error("input hap file is not found."); 503 } catch (NoSuchAlgorithmException e) { 504 LOG.error("can not provide sha-256 algorithm."); 505 } catch (IOException e) { 506 LOG.error("input hap IO exception."); 507 } finally { 508 Utility.closeStream(inputStream); 509 } 510 return sha256; 511 } 512 toHex(byte[] data)513 private static String toHex(byte[] data) { 514 StringBuilder hexString = new StringBuilder(); 515 for (byte item : data) { 516 hexString.append(Integer.toHexString(item & 0xFF)); 517 } 518 return hexString.toString(); 519 } 520 521 /** 522 * unzip file 523 * 524 * @param zipFilePath is the zipFilePath 525 * @param destDirPath is the output dest path 526 */ unzipFile(String zipFilePath, String destDirPath)527 public static boolean unzipFile(String zipFilePath, String destDirPath) { 528 boolean success = false; 529 File destDir = new File(destDirPath); 530 if (!destDir.exists()) { 531 destDir.mkdirs(); 532 } 533 ZipInputStream zipInputStream = null; 534 try { 535 zipInputStream = new ZipInputStream(new FileInputStream(zipFilePath)); 536 ZipEntry entry = zipInputStream.getNextEntry(); 537 while (entry != null) { 538 String filePath = destDirPath + File.separator + entry.getName(); 539 if (!matchPattern(filePath)) { 540 LOG.error("Input invalid file " + filePath + "."); 541 return false; 542 } 543 if (!entry.isDirectory()) { 544 extractFile(zipInputStream, filePath); 545 } else { 546 File dir = new File(filePath); 547 dir.mkdirs(); 548 } 549 zipInputStream.closeEntry(); 550 entry = zipInputStream.getNextEntry(); 551 } 552 success = true; 553 } catch (IOException e) { 554 LOG.error("FileUtil::unzipFile failed, IOException is " + e.getMessage()); 555 } finally { 556 Utility.closeStream(zipInputStream); 557 } 558 return success; 559 } 560 extractFile(ZipInputStream zipInputStream, String filePath)561 private static void extractFile(ZipInputStream zipInputStream, String filePath) { 562 BufferedOutputStream bufferedOutputStream = null; 563 try { 564 if (!matchPattern(filePath)) { 565 throw new BundleException("input invalid file " + filePath + "."); 566 } 567 bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(filePath)); 568 byte[] bytes = new byte[BUFFER_SIZE]; 569 int readLength = 0; 570 while ((readLength = zipInputStream.read(bytes)) != -1) { 571 bufferedOutputStream.write(bytes, 0, readLength); 572 } 573 } catch (IOException | BundleException e) { 574 LOG.error("FileUtil::extractFile failed, Exception is " + e.getMessage()); 575 } finally { 576 Utility.closeStream(bufferedOutputStream); 577 } 578 } 579 matchPattern(String path)580 static boolean matchPattern(String path) { 581 if (!Pattern.matches(PATTERN, path)) { 582 LOG.error("input invalid file of " + path + "."); 583 return false; 584 } 585 return true; 586 } 587 588 /** 589 * getFileSize 590 * 591 * @param filePath is the input file path 592 * @return file length 593 */ getFileSize(String filePath)594 public static long getFileSize(String filePath) { 595 File file = new File(filePath); 596 if (file.exists() && file.isFile()) { 597 return file.length(); 598 } 599 LOG.error("input " + filePath + " is not a valid file."); 600 return 0; 601 } 602 } 603