1 /* 2 * Copyright (c) 2023 Huawei Device Co., Ltd. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package ohos; 18 19 import java.io.BufferedInputStream; 20 import java.io.BufferedReader; 21 import java.io.File; 22 import java.io.FileInputStream; 23 import java.io.FileNotFoundException; 24 import java.io.FileOutputStream; 25 import java.io.FileWriter; 26 import java.io.IOException; 27 import java.io.InputStreamReader; 28 import java.net.URL; 29 import java.nio.charset.StandardCharsets; 30 import java.security.NoSuchAlgorithmException; 31 import java.util.ArrayList; 32 import java.util.List; 33 import java.util.zip.ZipEntry; 34 import java.util.zip.ZipInputStream; 35 36 /** 37 * scan info 38 * 39 * @since 2023/11/23 40 */ 41 42 public class Scan { 43 private static final String LINUX_FILE_SEPARATOR = "/"; 44 private static final String EMPTY_STRING = ""; 45 private static final String HTML_START = "<!DOCTYPE html><html lang=\"en\">"; 46 private static final String HTML_END = "</html>"; 47 private static final String STAT_JSON = "stat.json"; 48 private static final String STAT_HTML = "stat.html"; 49 private static final String STAT_CSS = "stat.css"; 50 private static final String HTML_HEAD = "<head><meta charset=\"UTF-8\" name=\"stat\">" 51 + "<title>stat</title><link rel=\"stylesheet\" href=\"./stat.css\"></head>"; 52 private static final String UNPACK_NAME = "unpack"; 53 private static final String BACKUPS = "backups"; 54 private static final String HAP = ".hap"; 55 private static final String HSP = ".hsp"; 56 private static final String TEMPLATE_HTML = "ohos/scan_template.html"; 57 private static final String TEMPLATE_CSS = "ohos/scan_template.css"; 58 private static final String DIV_BOX = "<div id=\"box\">"; 59 private static final String HTML_BODY = "<body>"; 60 private static final String HTML_DIV_END = "</div>"; 61 private static final String HTML_BODY_END = "</body>"; 62 private static final String USER_DIR = "user.dir"; 63 private static final String HTML_BR = "<br/>"; 64 private static final int BUFFER_SIZE = 10 * 1024; 65 private static final Log LOG = new Log(Scan.class.toString()); 66 67 68 /** 69 * start scan. 70 * 71 * @param utility common data 72 * @return scanProcess if scan succeed 73 */ scanProcess(Utility utility)74 public boolean scanProcess(Utility utility) { 75 File destFile = new File(utility.getOutPath()); 76 File outParentFile = destFile.getParentFile(); 77 if ((outParentFile != null) && (!outParentFile.exists())) { 78 if (!outParentFile.mkdirs()) { 79 LOG.error(ScanErrorEnum.SCAN_MKDIRS_ERROR.toString()); 80 return false; 81 } 82 } 83 boolean scanResult = true; 84 try { 85 scanExecute(utility); 86 } catch (FileNotFoundException exception) { 87 scanResult = false; 88 LOG.error(ScanErrorEnum.SCAN_NOT_FOUND_ERROR + exception.getMessage()); 89 } catch (BundleException | NoSuchAlgorithmException | IOException exception) { 90 scanResult = false; 91 LOG.error(ScanErrorEnum.SCAN_REMIND_ERROR + exception.getMessage()); 92 } finally { 93 if (!scanResult) { 94 LOG.error(ScanErrorEnum.SCAN_COMPRESS_ERROR.toString()); 95 if (!destFile.delete()) { 96 LOG.error(ScanErrorEnum.SCAN_DELETE_ERROR.toString()); 97 } 98 } 99 } 100 return scanResult; 101 } 102 scanExecute(Utility utility)103 private void scanExecute(Utility utility) throws BundleException, IOException, NoSuchAlgorithmException { 104 List<String> jsonList = new ArrayList<>(); 105 String templateHtml = getJsTemplate(TEMPLATE_HTML); 106 templateHtml = templateHtml.replace(HTML_BR, System.lineSeparator()); 107 String htmlStr = HTML_START + HTML_HEAD + DIV_BOX + HTML_BODY + templateHtml; 108 String currentDir = System.getProperty(USER_DIR); 109 String targetPath = currentDir + LINUX_FILE_SEPARATOR + UNPACK_NAME; 110 List<String> fileList = getAllInputFileList(utility, targetPath); 111 if (utility.getStatDuplicate()) { 112 ScanStatDuplicate scanStatDuplicate = new ScanStatDuplicate(); 113 String duplicateHtml = scanStatDuplicate.statDuplicate(utility, jsonList, fileList); 114 htmlStr = htmlStr + duplicateHtml; 115 } 116 if (null != utility.getStatFileSize() && !utility.getStatFileSize().isEmpty()) { 117 ScanStatFileSize scanStatFileSize = new ScanStatFileSize(); 118 String fileSizeHtml = scanStatFileSize.statFileSize(utility, jsonList, fileList); 119 htmlStr = htmlStr + fileSizeHtml; 120 } 121 if (utility.getStatSuffix()) { 122 ScanStatSuffix scanStatSuffix = new ScanStatSuffix(); 123 String suffixHtml = scanStatSuffix.statSuffix(utility, jsonList, fileList); 124 htmlStr = htmlStr + suffixHtml; 125 } 126 if (!((!utility.getStatDuplicate()) && !utility.getStatSuffix() 127 && EMPTY_STRING.equals(utility.getStatFileSize()))) { 128 htmlStr = htmlStr + HTML_DIV_END + HTML_BODY_END + HTML_END; 129 String jsonPath = utility.getOutPath() + LINUX_FILE_SEPARATOR + STAT_JSON; 130 String htmlPath = utility.getOutPath() + LINUX_FILE_SEPARATOR + STAT_HTML; 131 String cssPath = utility.getOutPath() + LINUX_FILE_SEPARATOR + STAT_CSS; 132 writeFile(jsonPath, jsonList.toString()); 133 writeFile(htmlPath, htmlStr); 134 String templateCss = getJsTemplate(TEMPLATE_CSS); 135 writeFile(cssPath, templateCss); 136 } 137 File deleteFile = new File(targetPath); 138 deleteFile(deleteFile); 139 } 140 getAllInputFileList(Utility utility, String path)141 private List<String> getAllInputFileList(Utility utility, String path) throws BundleException, IOException { 142 ArrayList<String> fileList = new ArrayList<>(); 143 unpackHap(utility.getInput(), path); 144 File file = new File(path); 145 File[] files = file.listFiles(); 146 if (files == null) { 147 LOG.error(ScanErrorEnum.SCAN_NO_FILE_ERROR.toString()); 148 return fileList; 149 } 150 String copyPath = path + LINUX_FILE_SEPARATOR + BACKUPS; 151 for (File f : files) { 152 String fileName = f.getName(); 153 if (fileName.endsWith(HSP) || fileName.endsWith(HAP)) { 154 String absolutePath = f.getCanonicalPath(); 155 File destDir = new File(copyPath); 156 if (!destDir.exists()) { 157 destDir.mkdirs(); 158 } 159 String targetPath = copyPath + LINUX_FILE_SEPARATOR + fileName; 160 File targetFile = new File(targetPath); 161 File sourceFile = new File(absolutePath); 162 FileUtils.copyFile(sourceFile, targetFile); 163 File deleteFile = new File(absolutePath); 164 deleteFile(deleteFile); 165 String outPath = path + LINUX_FILE_SEPARATOR + fileName; 166 File outDir = new File(outPath); 167 if (!outDir.exists()) { 168 outDir.mkdirs(); 169 } 170 unpackHap(targetPath, outPath); 171 } 172 } 173 File deleteFile = new File(copyPath); 174 deleteFile(deleteFile); 175 FileUtils.getFileList(path, fileList); 176 return fileList; 177 } 178 unpackHap(String srcPath, String outPath)179 private static void unpackHap(String srcPath, String outPath) throws BundleException { 180 try (FileInputStream fis = new FileInputStream(srcPath); 181 ZipInputStream zipInputStream = new ZipInputStream(new BufferedInputStream(fis))) { 182 File destDir = new File(outPath); 183 if (!destDir.exists()) { 184 destDir.mkdirs(); 185 } 186 unpackEntryToFile(zipInputStream, outPath); 187 } catch (IOException e) { 188 LOG.error(ScanErrorEnum.SCAN_UNPACK_ERROR + e.getMessage()); 189 throw new BundleException(ScanErrorEnum.SCAN_UNPACK_ERROR.msg + e.getMessage()); 190 } 191 } 192 unpackEntryToFile(ZipInputStream zipInputStream, String outPath)193 private static void unpackEntryToFile(ZipInputStream zipInputStream, String outPath) 194 throws BundleException, IOException { 195 ZipEntry entry; 196 while ((entry = zipInputStream.getNextEntry()) != null) { 197 String entryName = entry.getName(); 198 File entryFile = new File(outPath, entryName); 199 200 if (entry.isDirectory()) { 201 entryFile.mkdirs(); 202 zipInputStream.closeEntry(); 203 continue; 204 } 205 File parent = entryFile.getParentFile(); 206 if (!parent.exists()) { 207 parent.mkdirs(); 208 } 209 try (FileOutputStream fos = new FileOutputStream(entryFile)) { 210 byte[] buffer = new byte[BUFFER_SIZE]; 211 int bytesRead; 212 while ((bytesRead = zipInputStream.read(buffer)) != -1) { 213 fos.write(buffer, 0, bytesRead); 214 } 215 } catch (IOException e) { 216 LOG.error(ScanErrorEnum.SCAN_UNPACK_ERROR + e.getMessage()); 217 throw new BundleException(ScanErrorEnum.SCAN_UNPACK_ERROR.msg + e.getMessage()); 218 } 219 zipInputStream.closeEntry(); 220 } 221 } 222 deleteFile(File file)223 private static void deleteFile(File file) { 224 if (file == null || !file.exists()) { 225 return; 226 } 227 if (file.isDirectory()) { 228 File[] files = file.listFiles(); 229 for (File fileTmp : files) { 230 deleteFile(fileTmp); 231 } 232 } 233 file.delete(); 234 } 235 getJsTemplate(String fileName)236 private static String getJsTemplate(String fileName) throws IOException { 237 ClassLoader classLoader = Scan.class.getClassLoader(); 238 URL resource = classLoader.getResource(fileName); 239 try (BufferedReader bufferedReader = new BufferedReader( 240 new InputStreamReader(resource.openStream(), StandardCharsets.UTF_8))) { 241 StringBuilder template = new StringBuilder(); 242 String line; 243 while ((line = bufferedReader.readLine()) != null) { 244 template.append(line); 245 } 246 return template.toString(); 247 } catch (IOException e) { 248 LOG.error(ScanErrorEnum.SCAN_GET_JS_TEMPLATE_ERROR + e.getMessage()); 249 throw new IOException(ScanErrorEnum.SCAN_GET_JS_TEMPLATE_ERROR.msg + e.getMessage()); 250 } 251 } 252 writeFile(String targetPath, String data)253 private static void writeFile(String targetPath, String data) throws IOException { 254 try (FileWriter fileWriter = new FileWriter(targetPath)) { 255 fileWriter.write(data); 256 fileWriter.flush(); 257 } catch (IOException e) { 258 LOG.error(ScanErrorEnum.SCAN_WRITEFILE_ERROR + e.getMessage()); 259 throw new IOException(ScanErrorEnum.SCAN_WRITEFILE_ERROR.msg + e.getMessage()); 260 } 261 } 262 } 263