• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2023 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 
22 import org.apache.logging.log4j.LogManager;
23 import org.apache.logging.log4j.Logger;
24 
25 import java.io.BufferedWriter;
26 import java.io.ByteArrayOutputStream;
27 import java.io.Closeable;
28 import java.io.DataOutputStream;
29 import java.io.File;
30 import java.io.FileInputStream;
31 import java.io.FileNotFoundException;
32 import java.io.FileOutputStream;
33 import java.io.IOException;
34 import java.io.InputStream;
35 import java.io.OutputStream;
36 import java.io.OutputStreamWriter;
37 import java.nio.charset.Charset;
38 import java.nio.file.Files;
39 
40 /**
41  * Common file operation.
42  *
43  * @since 2021/12/28
44  */
45 public final class FileUtils {
46     /**
47      * LOGGER.
48      */
49     private static final Logger LOGGER = LogManager.getLogger(FileUtils.class);
50 
51     /**
52      * add GSON static.
53      */
54     public static final Gson GSON = (new GsonBuilder()).disableHtmlEscaping().create();
55 
56     /**
57      * add GSON_PRETTY_PRINT static.
58      */
59     public static final Gson GSON_PRETTY_PRINT = (new GsonBuilder()).disableHtmlEscaping().setPrettyPrinting().create();
60 
61     /**
62      * File reader block size
63      */
64     public static final int FILE_BUFFER_BLOCK = 1024 * 1024;
65 
66     /**
67      * File end
68      */
69     public static final int FILE_END = -1;
70 
71     /**
72      * Expected split string length
73      */
74     public static final int SPLIT_LENGTH = 2;
75 
76     /**
77      * libs dir path
78      */
79     public static final String LIBS_PATH_PREFIX = "libs/";
80 
81     private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
82 
FileUtils()83     private FileUtils() {
84     }
85 
86     /**
87      * Close closeable quietly.
88      *
89      * @param closeable closeable
90      */
close(Closeable closeable)91     public static void close(Closeable closeable) {
92         if (closeable != null) {
93             try {
94                 closeable.close();
95             } catch (IOException exception) {
96                 LOGGER.debug(exception.getMessage(), exception);
97             }
98         }
99     }
100 
101     /**
102      * Read byte from input file.
103      *
104      * @param file Which file to read
105      * @return byte content
106      * @throws IOException Read failed
107      */
readFile(File file)108     public static byte[] readFile(File file) throws IOException {
109         return read(Files.newInputStream(file.toPath()));
110     }
111 
112     /**
113      * Read byte from input stream.
114      *
115      * @param input Input stream
116      * @return File content
117      * @throws IOException Read failed
118      */
read(InputStream input)119     public static byte[] read(InputStream input) throws IOException {
120         try (ByteArrayOutputStream output = new ByteArrayOutputStream()) {
121             byte[] buffer = new byte[FILE_BUFFER_BLOCK];
122             int read;
123             while ((read = input.read(buffer)) != FILE_END) {
124                 output.write(buffer, 0, read);
125             }
126             return output.toByteArray();
127         } finally {
128             close(input);
129         }
130     }
131 
132     /**
133      * Read byte from input file.
134      *
135      * @param file input file
136      * @param offset offset
137      * @param length length
138      * @return data bytes
139      */
readFileByOffsetAndLength(File file, long offset, long length)140     public static byte[] readFileByOffsetAndLength(File file, long offset, long length) throws IOException {
141         try (FileInputStream input = new FileInputStream(file)) {
142             return readInputByOffsetAndLength(input, offset, length);
143         }
144     }
145 
146     /**
147      * Read byte from input stream.
148      *
149      * @param input input stream
150      * @param offset offset
151      * @param length length
152      * @return data bytes
153      * @throws IOException read exception
154      */
readInputByOffsetAndLength(InputStream input, long offset, long length)155     public static byte[] readInputByOffsetAndLength(InputStream input, long offset, long length) throws IOException {
156         input.skip(offset);
157         return readInputByLength(input, length);
158     }
159 
160     /**
161      * Read byte from input stream.
162      *
163      * @param input InputStream
164      * @param length length
165      * @return data bytes
166      */
readInputByLength(InputStream input, long length)167     public static byte[] readInputByLength(InputStream input, long length) throws IOException {
168         try (ByteArrayOutputStream output = new ByteArrayOutputStream()) {
169             if (length > Integer.MAX_VALUE) {
170                 throw new IOException("Size cannot be greater than Integer max value: " + length);
171             }
172             writeInputToOutPut(input, output, length);
173             return output.toByteArray();
174         }
175     }
176 
177     /**
178      * write input to output by length
179      */
writeInputToOutPut(InputStream input, OutputStream output, long length)180     private static void writeInputToOutPut(InputStream input, OutputStream output, long length) throws IOException {
181         byte[] buffer = new byte[FILE_BUFFER_BLOCK];
182         long hasReadLen = 0L;
183         while (hasReadLen < length) {
184             int readLen = (int) Math.min(length - hasReadLen, FILE_BUFFER_BLOCK);
185             int len = input.read(buffer, 0, readLen);
186             if (len != readLen) {
187                 throw new IOException("read" + hasReadLen + "bytes data less than " + length);
188             }
189             output.write(buffer, 0, len);
190             hasReadLen += len;
191         }
192     }
193 
194     /**
195      * Out put content to file.
196      *
197      * @param content Which content to out put
198      * @param output  File to write
199      * @throws IOException Write failed
200      */
write(byte[] content, File output)201     public static void write(byte[] content, File output) throws IOException {
202         try (FileOutputStream out = new FileOutputStream(output)) {
203             for (byte con : content) {
204                 out.write(con);
205             }
206         }
207     }
208 
209     /**
210      * Write data in file to output stream
211      *
212      * @param inFile input file path.
213      * @param out output file path.
214      * @param offset file read offset
215      * @param size file read size
216      * @return true, if write successfully.
217      */
appendWriteFileByOffsetToFile(String inFile, FileOutputStream out, long offset, long size)218     public static boolean appendWriteFileByOffsetToFile(String inFile, FileOutputStream out, long offset, long size) {
219         File inputFile = new File(inFile);
220         try (FileInputStream fis = new FileInputStream(inputFile)) {
221             fis.skip(offset);
222             writeInputToOutPut(fis, out, size);
223             return true;
224         } catch (FileNotFoundException e) {
225             LOGGER.error("Failed to get input stream object.");
226         } catch (IOException e) {
227             LOGGER.error("Failed to read or write data.");
228         }
229         return false;
230     }
231 
232     /**
233      * Check file exist or not.
234      *
235      * @param filePath File path
236      * @return Is file exist
237      */
isFileExist(String filePath)238     public static boolean isFileExist(String filePath) {
239         return new File(filePath).exists();
240     }
241 
242     /**
243      * Throw runtime exception if not allowed file type.
244      *
245      * @param filePath file path
246      * @param types    Such as "txt" "json" "mp3"
247      */
validFileType(String filePath, String... types)248     public static void validFileType(String filePath, String... types) {
249         String suffix = getSuffix(filePath);
250         ValidateUtils.throwIfNotMatches(!StringUtils.isEmpty(suffix),
251                 ERROR.NOT_SUPPORT_ERROR, "Not support file: " + filePath);
252         boolean isMatches = false;
253         for (String type : types) {
254             if (StringUtils.isEmpty(type)) {
255                 continue;
256             }
257             if (type.equalsIgnoreCase(suffix)) {
258                 isMatches = true;
259                 break;
260             }
261         }
262         ValidateUtils.throwIfNotMatches(isMatches, ERROR.NOT_SUPPORT_ERROR, "Not support file: " + filePath);
263     }
264 
265     /**
266      * Get suffix of file.
267      *
268      * @param filePath file path
269      * @return file suffix. Such as "txt" "json" "p12"
270      */
getSuffix(String filePath)271     public static String getSuffix(String filePath) {
272         if (StringUtils.isEmpty(filePath)) {
273             return "";
274         }
275         File file = new File(filePath);
276         String fileName = file.getName();
277         String[] temps = fileName.split("\\.");
278         if (temps.length < SPLIT_LENGTH) {
279             return "";
280         }
281         return temps[temps.length - 1];
282     }
283 
284     /**
285      * Write data in file to output stream
286      *
287      * @param file input file path.
288      * @param dos output stream.
289      * @return true, if write successfully.
290      */
writeFileToDos(String file, DataOutputStream dos)291     public static boolean writeFileToDos(String file, DataOutputStream dos) {
292         if (dos == null) {
293             return false;
294         }
295         File src = new File(file);
296         try (FileInputStream fileStream = new FileInputStream(src)) {
297             int temp;
298             byte[] buf = new byte[FILE_BUFFER_BLOCK];
299             while ((temp = fileStream.read(buf)) > 0) {
300                 dos.write(buf, 0, temp);
301             }
302             return true;
303         } catch (FileNotFoundException e) {
304             LOGGER.error("Failed to get input stream object.");
305         } catch (IOException e) {
306             LOGGER.error("Failed to read or write data.");
307         }
308         return false;
309     }
310 
311     /**
312      * Write byte array to output stream
313      *
314      * @param data byte array
315      * @param dos output stream
316      * @return true, if write successfully.
317      */
writeByteToDos(byte[] data, DataOutputStream dos)318     public static boolean writeByteToDos(byte[] data, DataOutputStream dos) {
319         if (data == null) {
320             return true;
321         }
322         try {
323             dos.write(data);
324         } catch (IOException e) {
325             LOGGER.error("Failed to write data to output stream.");
326             return false;
327         }
328         return true;
329     }
330 
331     /**
332      * Get length of file.
333      *
334      * @param filePath input file path.
335      * @return long value of file length.
336      */
getFileLen(String filePath)337     public static long getFileLen(String filePath) {
338         File file = new File(filePath);
339         if (file.exists() && file.isFile()) {
340             return file.length();
341         }
342         return -1;
343     }
344 
345     /**
346      * Write byte array data to output file.
347      *
348      * @param bytes byte array data.
349      * @param outFile output file path.
350      * @return true, if write successfully.
351      */
writeByteToOutFile(byte[] bytes, String outFile)352     public static boolean writeByteToOutFile(byte[] bytes, String outFile) {
353         try (OutputStream ops = new FileOutputStream(outFile, true)) {
354             return writeByteToOutFile(bytes, ops);
355         } catch (FileNotFoundException e) {
356             LOGGER.error("Failed to get output stream object, outfile: " + outFile);
357         } catch (IOException e) {
358             LOGGER.error("Failed to write data to ops, outfile: " + outFile);
359         }
360         return false;
361     }
362 
363     /**
364      * Write byte array data to output file.
365      *
366      * @param bytes byte array data.
367      * @param outFile output file path.
368      * @return true, if write successfully.
369      */
writeByteToOutFile(byte[] bytes, OutputStream outFile)370     public static boolean writeByteToOutFile(byte[] bytes, OutputStream outFile) {
371         try {
372             outFile.write(bytes, 0, bytes.length);
373             outFile.flush();
374             return true;
375         } catch (FileNotFoundException e) {
376             LOGGER.error("Failed to get output stream object, outfile: " + outFile);
377         } catch (IOException e) {
378             LOGGER.error("Failed to write data to ops, outfile: " + outFile);
379         }
380         return false;
381     }
382 
383     /**
384      * Check input file is valid.
385      *
386      * @param file input file.
387      * @throws IOException file is a directory or can't be read.
388      */
isValidFile(File file)389     public static void isValidFile(File file) throws IOException {
390         if (!file.exists()) {
391             throw new FileNotFoundException("File '" + file + "' does not exist");
392         }
393 
394         if (file.isDirectory()) {
395             throw new IOException("File '" + file + "' exists but is a directory");
396         }
397 
398         if (!file.canRead()) {
399             throw new IOException("File '" + file + "' cannot be read");
400         }
401     }
402 
403     /**
404      * Open an input stream of input file safely.
405      *
406      * @param file input file.
407      * @return an input stream of input file
408      * @throws IOException file is a directory or can't be read.
409      */
openInputStream(File file)410     public static FileInputStream openInputStream(File file) throws IOException {
411         isValidFile(file);
412         return new FileInputStream(file);
413     }
414 
toByteArray(final InputStream input, final int size)415     private static byte[] toByteArray(final InputStream input, final int size) throws IOException {
416         if (size < 0) {
417             throw new IllegalArgumentException("Size must be equal or greater than zero: " + size);
418         }
419 
420         if (size == 0) {
421             return EMPTY_BYTE_ARRAY;
422         }
423 
424         final byte[] data = new byte[size];
425         int offset = 0;
426         int read;
427 
428         while (offset < size && (read = input.read(data, offset, size - offset)) != FILE_END) {
429             offset += read;
430         }
431 
432         if (offset != size) {
433             throw new IOException("Unexpected read size. current: " + offset + ", expected: " + size);
434         }
435 
436         return data;
437     }
438 
439     /**
440      * Read file to byte array.
441      *
442      * @param file input file.
443      * @return byte array of file-content.
444      * @throws IOException fill exception
445      */
readFileToByteArray(File file)446     public static byte[] readFileToByteArray(File file) throws IOException {
447         try (InputStream in = openInputStream(file)) {
448             final long fileLength = file.length();
449             if (fileLength > Integer.MAX_VALUE) {
450                 throw new IllegalArgumentException("Size cannot be greater than Integer max value: " + fileLength);
451             }
452             return toByteArray(in, (int) fileLength);
453         }
454     }
455 
456     /**
457      * Write a string to file
458      *
459      * @param source String will be written.
460      * @param filePath path to write file.
461      * @param charset a charset
462      * @throws IOException write error.
463      */
writeStringToFile(String source, String filePath, Charset charset)464     public static void writeStringToFile(String source, String filePath, Charset charset) throws IOException {
465         try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
466                 new FileOutputStream(filePath), charset))) {
467             writer.write(source);
468             writer.flush();
469         }
470     }
471 
472     /**
473      * Delete a file quietly
474      *
475      * @param file the file to delete
476      */
deleteFile(File file)477     public static void deleteFile(File file) {
478         if (file != null && file.isFile()) {
479             try {
480                 Files.delete(file.toPath());
481             } catch (IOException e) {
482                 LOGGER.warn("delete file '{}' error, error message: {}", file, e.getMessage());
483             }
484         }
485     }
486 
487     /**
488      * regex filename
489      *
490      * @param name filename
491      * @return boolean
492      */
isRunnableFile(String name)493     public static boolean isRunnableFile(String name) {
494         if (StringUtils.isEmpty(name)) {
495             return false;
496         }
497         if (name.endsWith(".an") || name.endsWith(".abc")) {
498             return true;
499         }
500         if (name.startsWith(LIBS_PATH_PREFIX)) {
501             return true;
502         }
503         return false;
504     }
505 }
506