1 /*
2  * Copyright (C) 2009 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 dex.reader;
18 
19 import dex.structure.DexAnnotation;
20 import dex.structure.DexClass;
21 import dex.structure.DexField;
22 import dex.structure.DexFile;
23 import dex.structure.DexMethod;
24 
25 import java.util.ArrayList;
26 import java.util.List;
27 import java.util.Set;
28 
29 /**
30  * <pre>
31  * TypeDescriptor := 'V' | FieldTypeDescriptor
32  * FieldTypeDescriptor := NonArrayFieldTypeDescriptor | ('[' * 1...255) NonArrayFieldTypeDescriptor
33  * NonArrayFieldTypeDescriptor := 'Z' | 'B' | 'S' | 'C' | 'I' | 'J' | 'F' | 'D' | 'L' FullClassName ';'
34  * </pre>
35  */
36 public final class TypeFormatter {
37 
38     /**
39      * V void; only valid for return types Z boolean B byte S short C char I int
40      * J long F float D double Lfully/qualified/Name; the class
41      * fully.qualified.Name [descriptor array of descriptor, usable recursively
42      * for arrays-of-arrays, though it is invalid to have more than 255
43      * dimensions.
44      */
format(String typeName)45     public String format(String typeName) {
46         if (typeName.length() == 1) {
47             switch (typeName.charAt(0)) {
48             case 'V':
49                 return "void";
50             case 'Z':
51                 return "boolean";
52             case 'B':
53                 return "byte";
54             case 'S':
55                 return "short";
56             case 'C':
57                 return "char";
58             case 'I':
59                 return "int";
60             case 'J':
61                 return "long";
62             case 'F':
63                 return "float";
64             case 'D':
65                 return "double";
66             }
67         } else {
68             if (typeName.startsWith("L")) {
69                 return typeName.substring(1, typeName.length() - 1).replace(
70                         "/", "."); // remove 'L' and ';', replace '/' with '.'
71             } else if (typeName.startsWith("[")) {
72                 return format(typeName.substring(1)) + "[]";
73             }
74         }
75         System.err.println("Strange type in formatter: " + typeName);
76         return typeName;
77     }
78 
format(List<String> typeNames)79     public String format(List<String> typeNames) {
80         List<String> types = new ArrayList<String>(typeNames.size());
81         for (String type : typeNames) {
82             types.add(format(type));
83         }
84         return format(types, ", ");
85     }
86 
formatAnnotations(Set<DexAnnotation> annotations)87     public String formatAnnotations(Set<DexAnnotation> annotations) {
88         return format(new ArrayList<DexAnnotation>(annotations), "\n") + "\n";
89     }
90 
format(List<?> elements, String separator)91     private String format(List<?> elements, String separator) {
92         StringBuilder builder = new StringBuilder();
93         boolean first = true;
94         for (Object element : elements) {
95             if (!first) {
96                 builder.append(separator);
97             }
98             builder.append(element.toString());
99             first = false;
100         }
101         return builder.toString();
102     }
103 
104 
formatDexFile(DexFile file)105     public String formatDexFile(DexFile file) {
106         StringBuilder builder = new StringBuilder();
107         builder.append("----------------DEX_FILE--------------\n\n");
108         builder.append("Filename: ").append(file.getName());
109         builder.append("\n-----------DEFINED_CLASSES------------\n\n");
110         for (DexClass dexClass : file.getDefinedClasses()) {
111             builder.append("\n________________CLASS________________\n\n");
112             builder.append(dexClass);
113             builder.append("\n\n----------------FIELDS----------------\n");
114             for (DexField field : dexClass.getFields()) {
115                 builder.append(field).append("\n");
116             }
117             builder.append("----------------METHODS----------------\n");
118             for (DexMethod method : dexClass.getMethods()) {
119                 builder.append(method).append("\n");
120             }
121         }
122         return builder.toString();
123     }
124 }
125