1 /* 2 * Copyright (c) 2021-2022 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 com.ohos.hapsigntool.utils; 17 18 import com.google.gson.Gson; 19 import com.google.gson.GsonBuilder; 20 import com.ohos.hapsigntool.error.ERROR; 21 import org.apache.logging.log4j.LogManager; 22 import org.apache.logging.log4j.Logger; 23 24 import java.io.BufferedWriter; 25 import java.io.ByteArrayOutputStream; 26 import java.io.Closeable; 27 import java.io.DataOutputStream; 28 import java.io.File; 29 import java.io.FileInputStream; 30 import java.io.FileNotFoundException; 31 import java.io.FileOutputStream; 32 import java.io.IOException; 33 import java.io.InputStream; 34 import java.io.OutputStream; 35 import java.io.OutputStreamWriter; 36 import java.nio.charset.Charset; 37 import java.nio.file.Files; 38 39 /** 40 * Common file operation. 41 * 42 * @since 2021/12/28 43 */ 44 public final class FileUtils { 45 46 /** 47 * LOGGER. 48 */ 49 private static final Logger LOGGER = LogManager.getLogger(FileUtils.class); 50 /** 51 * add GSON static. 52 */ 53 public static final Gson GSON = (new GsonBuilder()).disableHtmlEscaping().create(); 54 /** 55 * add GSON_PRETTY_PRINT static. 56 */ 57 public static final Gson GSON_PRETTY_PRINT = (new GsonBuilder()).disableHtmlEscaping().setPrettyPrinting().create(); 58 /** 59 * File reader block size 60 */ 61 public static final int FILE_BUFFER_BLOCK = 4096; 62 /** 63 * File end 64 */ 65 public static final int FILE_END = -1; 66 /** 67 * Expected split string length 68 */ 69 public static final int SPLIT_LENGTH = 2; 70 71 private static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; 72 FileUtils()73 private FileUtils() { 74 } 75 76 /** 77 * Close closeable quietly. 78 * 79 * @param closeable closeable 80 */ close(Closeable closeable)81 public static void close(Closeable closeable) { 82 if (closeable != null) { 83 try { 84 closeable.close(); 85 } catch (IOException exception) { 86 LOGGER.debug(exception.getMessage(), exception); 87 } 88 } 89 } 90 91 /** 92 * Read byte from input file. 93 * 94 * @param file Which file to read 95 * @return byte content 96 * @throws IOException Read failed 97 */ readFile(File file)98 public static byte[] readFile(File file) throws IOException { 99 return read(new FileInputStream(file)); 100 } 101 102 /** 103 * Read byte from input stream. 104 * 105 * @param input Input stream 106 * @return File content 107 * @throws IOException Read failed 108 */ read(InputStream input)109 public static byte[] read(InputStream input) throws IOException { 110 try (ByteArrayOutputStream output = new ByteArrayOutputStream()) { 111 byte[] buffer = new byte[FILE_BUFFER_BLOCK]; 112 int read; 113 while ((read = input.read(buffer)) != FILE_END) { 114 output.write(buffer, 0, read); 115 } 116 return output.toByteArray(); 117 } finally { 118 close(input); 119 } 120 } 121 122 /** 123 * Out put content to file. 124 * 125 * @param content Which content to out put 126 * @param output File to write 127 * @throws IOException Write failed 128 */ write(byte[] content, File output)129 public static void write(byte[] content, File output) throws IOException { 130 try (FileOutputStream out = new FileOutputStream(output)) { 131 for (byte con : content) { 132 out.write(con); 133 } 134 } 135 } 136 137 /** 138 * Check file exist or not. 139 * 140 * @param filePath File path 141 * @return Is file exist 142 */ isFileExist(String filePath)143 public static boolean isFileExist(String filePath) { 144 return new File(filePath).exists(); 145 } 146 147 /** 148 * Throw runtime exception if not allowed file type. 149 * 150 * @param filePath file path 151 * @param types Such as "txt" "json" "mp3" 152 */ validFileType(String filePath, String... types)153 public static void validFileType(String filePath, String... types) { 154 String suffix = getSuffix(filePath); 155 ValidateUtils.throwIfNotMatches(!StringUtils.isEmpty(suffix), 156 ERROR.NOT_SUPPORT_ERROR, "Not support file: " + filePath); 157 boolean isMatches = false; 158 for (String type : types) { 159 if (StringUtils.isEmpty(type)) { 160 continue; 161 } 162 if (type.equalsIgnoreCase(suffix)) { 163 isMatches = true; 164 break; 165 } 166 } 167 ValidateUtils.throwIfNotMatches(isMatches, ERROR.NOT_SUPPORT_ERROR, "Not support file: " + filePath); 168 } 169 170 /** 171 * Get suffix of file. 172 * 173 * @param filePath file path 174 * @return file suffix. Such as "txt" "json" "p12" 175 */ getSuffix(String filePath)176 public static String getSuffix(String filePath) { 177 if (StringUtils.isEmpty(filePath)) { 178 return ""; 179 } 180 File file = new File(filePath); 181 String fileName = file.getName(); 182 String[] temps = fileName.split("\\."); 183 if (temps.length < SPLIT_LENGTH) { 184 return ""; 185 } 186 return temps[temps.length - 1]; 187 } 188 189 /** 190 * Write data in file to output stream 191 * 192 * @param file input file path. 193 * @param dos output stream. 194 * @return true, if write successfully. 195 */ writeFileToDos(String file, DataOutputStream dos)196 public static boolean writeFileToDos(String file, DataOutputStream dos) { 197 if (dos == null) { 198 return false; 199 } 200 File src = new File(file); 201 try (FileInputStream fileStream = new FileInputStream(src)) { 202 int temp; 203 byte[] buf = new byte[FILE_BUFFER_BLOCK]; 204 while ((temp = fileStream.read(buf)) > 0) { 205 dos.write(buf, 0, temp); 206 } 207 return true; 208 } catch (FileNotFoundException e) { 209 LOGGER.error("Failed to get input stream object."); 210 } catch (IOException e) { 211 LOGGER.error("Failed to read or write data."); 212 } 213 return false; 214 } 215 216 /** 217 * Write byte array to output stream 218 * 219 * @param data byte array 220 * @param dos output stream 221 * @return true, if write successfully. 222 */ writeByteToDos(byte[] data, DataOutputStream dos)223 public static boolean writeByteToDos(byte[] data, DataOutputStream dos) { 224 try { 225 dos.write(data); 226 } catch (IOException e) { 227 LOGGER.error("Faile to write data to output stream."); 228 return false; 229 } 230 return true; 231 } 232 233 /** 234 * Get length of file. 235 * 236 * @param filePath input file path. 237 * @return long value of file length. 238 */ getFileLen(String filePath)239 public static long getFileLen(String filePath) { 240 File file = new File(filePath); 241 if (file.exists() && file.isFile()) { 242 return file.length(); 243 } 244 return -1; 245 } 246 247 /** 248 * Write byte array data to output file. 249 * 250 * @param signHeadByte byte array data. 251 * @param outFile output file path. 252 * @return true, if write successfully. 253 */ writeByteToOutFile(byte[] signHeadByte, String outFile)254 public static boolean writeByteToOutFile(byte[] signHeadByte, String outFile) { 255 try (OutputStream ops = new FileOutputStream(outFile, true)) { 256 ops.write(signHeadByte, 0, signHeadByte.length); 257 ops.flush(); 258 return true; 259 } catch (FileNotFoundException e) { 260 LOGGER.error("Failed to get output stream object, outfile: " + outFile); 261 } catch (IOException e) { 262 LOGGER.error("Failed to write data to ops, outfile: " + outFile); 263 } 264 return false; 265 } 266 267 /** 268 * Check input file is valid. 269 * 270 * @param file input file. 271 * @throws IOException file is a directory or can't be read. 272 */ isValidFile(File file)273 public static void isValidFile(File file) throws IOException { 274 if (!file.exists()) { 275 throw new FileNotFoundException("File '" + file + "' does not exist"); 276 } 277 278 if (file.isDirectory()) { 279 throw new IOException("File '" + file + "' exists but is a directory"); 280 } 281 282 if (!file.canRead()) { 283 throw new IOException("File '" + file + "' cannot be read"); 284 } 285 } 286 287 /** 288 * Open an input stream of input file safely. 289 * @param file input file. 290 * @return an input stream of input file 291 * @throws IOException file is a directory or can't be read. 292 */ openInputStream(File file)293 public static FileInputStream openInputStream(File file) throws IOException { 294 isValidFile(file); 295 return new FileInputStream(file); 296 } 297 toByteArray(final InputStream input, final int size)298 private static byte[] toByteArray(final InputStream input, final int size) throws IOException { 299 if (size < 0) { 300 throw new IllegalArgumentException("Size must be equal or greater than zero: " + size); 301 } 302 303 if (size == 0) { 304 return EMPTY_BYTE_ARRAY; 305 } 306 307 final byte[] data = new byte[size]; 308 int offset = 0; 309 int read; 310 311 while (offset < size && (read = input.read(data, offset, size - offset)) != FILE_END) { 312 offset += read; 313 } 314 315 if (offset != size) { 316 throw new IOException("Unexpected read size. current: " + offset + ", expected: " + size); 317 } 318 319 return data; 320 } 321 322 /** 323 * Read file to byte array. 324 * 325 * @param file input file. 326 * @return byte array of file-content. 327 * @throws IOException fill exception 328 */ readFileToByteArray(File file)329 public static byte[] readFileToByteArray(File file) throws IOException { 330 try (InputStream in = openInputStream(file)) { 331 final long fileLength = file.length(); 332 if (fileLength > Integer.MAX_VALUE) { 333 throw new IllegalArgumentException("Size cannot be greater than Integer max value: " + fileLength); 334 } 335 return toByteArray(in, (int) fileLength); 336 } 337 } 338 339 /** 340 * Write a string to file 341 * 342 * @param source String will be written. 343 * @param filePath path to write file. 344 * @param charset a charset 345 * @throws IOException write error. 346 */ writeStringToFile(String source, String filePath, Charset charset)347 public static void writeStringToFile(String source, String filePath, Charset charset) throws IOException { 348 try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter( 349 new FileOutputStream(filePath), charset))) { 350 writer.write(source); 351 writer.flush(); 352 } 353 } 354 355 /** 356 * Delete a file quietly 357 * 358 * @param file the file to delete 359 */ deleteFile(File file)360 public static void deleteFile(File file) { 361 if (file != null && file.isFile()) { 362 try { 363 Files.delete(file.toPath()); 364 } catch (IOException e) { 365 LOGGER.warn("delete file '{}' error, error message: {}", file, e.getMessage()); 366 } 367 } 368 } 369 } 370