1 /* 2 * Copyright (C) 2018 The Android Open Source Project 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 com.android.cts.releaseparser; 18 19 import com.android.cts.releaseparser.ReleaseProto.*; 20 21 import java.io.BufferedReader; 22 import java.io.File; 23 import java.io.FileOutputStream; 24 import java.io.IOException; 25 import java.io.InputStream; 26 import java.io.InputStreamReader; 27 import java.io.OutputStream; 28 import java.nio.charset.Charset; 29 import java.util.HashMap; 30 import java.util.Map; 31 32 public class ClassUtils { 33 public static final char PACKAGE_SEPARATOR = '/'; 34 public static final char INNER_CLASS_SEPARATOR = '$'; 35 public static final char SPECIAL_CLASS_CHARACTER = '-'; 36 public static final char SPECIAL_MEMBER_SEPARATOR = '$'; 37 public static final char CLASS_MEMBER_SELECTOR = '.'; 38 39 public static final char TYPE_VOID = 'V'; 40 public static final char TYPE_BOOLEAN = 'Z'; 41 public static final char TYPE_BYTE = 'B'; 42 public static final char TYPE_CHAR = 'C'; 43 public static final char TYPE_SHORT = 'S'; 44 public static final char TYPE_INT = 'I'; 45 public static final char TYPE_LONG = 'J'; 46 public static final char TYPE_FLOAT = 'F'; 47 public static final char TYPE_DOUBLE = 'D'; 48 public static final char TYPE_CLASS_START = 'L'; 49 public static final char TYPE_CLASS_END = ';'; 50 public static final char TYPE_ARRAY = '['; 51 public static final String TYPE_ARRAY_ACCESS = "[]"; 52 53 private static Map<Character, String> primitiveTypes = new HashMap<>(); 54 55 static { primitiveTypes.put(TYPE_VOID, "void")56 primitiveTypes.put(TYPE_VOID, "void"); primitiveTypes.put(TYPE_BOOLEAN, "boolean")57 primitiveTypes.put(TYPE_BOOLEAN, "boolean"); primitiveTypes.put(TYPE_BYTE, "byte")58 primitiveTypes.put(TYPE_BYTE, "byte"); primitiveTypes.put(TYPE_CHAR, "char")59 primitiveTypes.put(TYPE_CHAR, "char"); primitiveTypes.put(TYPE_SHORT, "short")60 primitiveTypes.put(TYPE_SHORT, "short"); primitiveTypes.put(TYPE_INT, "int")61 primitiveTypes.put(TYPE_INT, "int"); primitiveTypes.put(TYPE_LONG, "long")62 primitiveTypes.put(TYPE_LONG, "long"); primitiveTypes.put(TYPE_FLOAT, "float")63 primitiveTypes.put(TYPE_FLOAT, "float"); primitiveTypes.put(TYPE_DOUBLE, "double")64 primitiveTypes.put(TYPE_DOUBLE, "double"); 65 } 66 67 /** 68 * Gets canonical name of a class 69 * 70 * @param name such as: [[Lcom/foo/bar/MyClass$Inner; 71 * @return canonical name as: com.foo.bar.MyClass.Inner[][] 72 */ getCanonicalName(String name)73 public static String getCanonicalName(String name) { 74 int arrDimension = 0; 75 for (int i = 0; i < name.length(); i++) { 76 if (name.charAt(i) == TYPE_ARRAY) { 77 arrDimension++; 78 } else { 79 break; 80 } 81 } 82 83 // test the first character. 84 final char firstChar = name.charAt(arrDimension); 85 if (primitiveTypes.containsKey(firstChar)) { 86 name = primitiveTypes.get(firstChar); 87 } else if (firstChar == TYPE_CLASS_START) { 88 // omit the leading 'L' and the trailing ';' 89 name = name.substring(arrDimension + 1, name.length() - 1); 90 91 // replace '/' and '$' to '.' 92 name = 93 name.replace(PACKAGE_SEPARATOR, CLASS_MEMBER_SELECTOR) 94 .replace(INNER_CLASS_SEPARATOR, CLASS_MEMBER_SELECTOR); 95 } 96 97 // add []'s, if any 98 for (int i = 0; i < arrDimension; i++) { 99 name += TYPE_ARRAY_ACCESS; 100 } 101 102 return name; 103 } 104 105 /** 106 * Reads a file from Resource and write to a tmp file 107 * 108 * @param clazz the Class contins resrouce files 109 * @param fileName of a resource file 110 * @return the File object of a tmp file 111 */ getResrouceFile(Class clazz, String fileName)112 public static File getResrouceFile(Class clazz, String fileName) throws IOException { 113 File tempFile = File.createTempFile(fileName, ""); 114 tempFile.deleteOnExit(); 115 try (InputStream input = openResourceAsStream(clazz, fileName); 116 OutputStream output = new FileOutputStream(tempFile)) { 117 byte[] buffer = new byte[4096]; 118 int length; 119 while ((length = input.read(buffer)) > 0) { 120 output.write(buffer, 0, length); 121 } 122 } 123 return tempFile; 124 } 125 126 /** 127 * Gets Resource file content as a String 128 * 129 * @param clazz the Class contins resrouce files 130 * @param fileName of a resource file 131 * @return a String of the resrouce file content 132 */ getResrouceContentString(Class clazz, String fileName)133 public static String getResrouceContentString(Class clazz, String fileName) throws IOException { 134 InputStream inStream = openResourceAsStream(clazz, fileName); 135 StringBuilder stringBuilder = new StringBuilder(); 136 String line = null; 137 138 try (BufferedReader bufferedReader = 139 new BufferedReader(new InputStreamReader(inStream, Charset.forName("UTF-8")))) { 140 while ((line = bufferedReader.readLine()) != null) { 141 stringBuilder.append(line); 142 } 143 } 144 145 return stringBuilder.toString(); 146 } 147 148 /** 149 * Gets an InputStrem of a file from Resource 150 * 151 * @param clazz the Class contins resrouce files 152 * @param fileName of a resource file 153 * @return the (@link InputStream} object of the file 154 */ openResourceAsStream(Class clazz, String fileName)155 public static InputStream openResourceAsStream(Class clazz, String fileName) { 156 InputStream input = clazz.getResourceAsStream("/" + fileName); 157 return input; 158 } 159 160 /** 161 * Gets an InputStremReader of a file from Resource 162 * 163 * @param clazz the Class contins resrouce files 164 * @param fileName of a resource file 165 * @return the (@link InputStream} object of the file 166 */ openResourceAsStreamReader(Class clazz, String fileName)167 public static InputStreamReader openResourceAsStreamReader(Class clazz, String fileName) { 168 return new InputStreamReader( 169 openResourceAsStream(clazz, fileName), Charset.forName("UTF-8")); 170 } 171 172 /** 173 * Gets/new ApiClass.Builder from a map by the class name 174 * 175 * @param HashMap<class name, ApiClass.Builder> 176 * @param Class name 177 * @return ApiClass.Builder 178 */ getApiClassBuilder( HashMap<String, ApiClass.Builder> apiClassBuilderMap, String name)179 public static ApiClass.Builder getApiClassBuilder( 180 HashMap<String, ApiClass.Builder> apiClassBuilderMap, String name) { 181 ApiClass.Builder builder = apiClassBuilderMap.get(name); 182 if (builder == null) { 183 builder = ApiClass.newBuilder().setName(ClassUtils.getCanonicalName(name)); 184 apiClassBuilderMap.put(name, builder); 185 } 186 return builder; 187 } 188 189 /** 190 * Adds all ApiClass in a map to ApiPackage.Builder 191 * 192 * @param HashMap<class name, ApiClass.Builder> 193 * @param ApiPackage.Builder 194 */ addAllApiClasses( HashMap<String, ApiClass.Builder> apiClassBuilderMap, ApiPackage.Builder apiPackageBuilder)195 public static void addAllApiClasses( 196 HashMap<String, ApiClass.Builder> apiClassBuilderMap, 197 ApiPackage.Builder apiPackageBuilder) { 198 apiClassBuilderMap 199 .values() 200 .forEach( 201 value -> { 202 apiPackageBuilder.addClasses(value.build()); 203 }); 204 } 205 } 206