KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > proguard > retrace > StackTraceItem


1 /*
2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
3  * of Java bytecode.
4  *
5  * Copyright (c) 2002-2007 Eric Lafortune (eric@graphics.cornell.edu)
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the Free
9  * Software Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15  * more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  */

21 package proguard.retrace;
22
23 import java.io.*;
24 import java.util.*;
25
26 import proguard.obfuscate.MappingProcessor;
27
28
29 /**
30  * This class represents an obfuscated stack trace item. It can read, de-obfuscate,
31  * and then write its contents.
32  *
33  * @author Eric Lafortune
34  */

35 class StackTraceItem implements MappingProcessor
36 {
37     // The stack trace settings.
38
private boolean verbose;
39
40     public String JavaDoc prefix;
41     public String JavaDoc obfuscatedClassName;
42     public String JavaDoc obfuscatedMethodName;
43     public String JavaDoc sourceFile;
44     public int lineNumber;
45     public String JavaDoc suffix;
46
47     public String JavaDoc originalClassName;
48     public List originalMethodNames;
49
50     /**
51      * Creates a new StackTraceItem.
52      * @param verbose specifies whether the de-obfuscated stack trace should
53      * be verbose.
54      */

55     public StackTraceItem(boolean verbose)
56     {
57         this.verbose = verbose;
58     }
59
60
61     /**
62      * Parses the stack trace
63      */

64     public void parse(String JavaDoc line) throws IOException
65     {
66         if (!parseAtLine(line) &&
67             !parseExceptionInThreadLine(line))
68         {
69             parseAnyLine(line);
70         }
71     }
72
73
74     /**
75      * Tries to parse "at ___.___(___:___)", containing the class name,
76      * the method name, the source file, and the optional line number.
77      */

78     private boolean parseAtLine(String JavaDoc line)
79     {
80         if (!line.startsWith("at "))
81         {
82             return false;
83         }
84
85         int openParenthesisIndex = line.indexOf('(', 3);
86         if (openParenthesisIndex < 0)
87         {
88             return false;
89         }
90
91         int colonIndex = line.indexOf(':', openParenthesisIndex + 1);
92
93         int closeParenthesisIndex = line.indexOf(')', Math.max(openParenthesisIndex, colonIndex) + 1);
94         if (closeParenthesisIndex < 0)
95         {
96             return false;
97         }
98
99         int periodIndex = line.lastIndexOf('.', openParenthesisIndex - 1);
100         if (periodIndex < 0)
101         {
102             return false;
103         }
104
105         prefix = " at ";
106         obfuscatedClassName = line.substring(3, periodIndex).trim();
107         obfuscatedMethodName = line.substring(periodIndex + 1, openParenthesisIndex).trim();
108         sourceFile = line.substring(openParenthesisIndex + 1, colonIndex < 0 ? closeParenthesisIndex : colonIndex).trim();
109         lineNumber = colonIndex < 0 ? 0 : Integer.parseInt(line.substring(colonIndex + 1, closeParenthesisIndex).trim());
110
111         return true;
112     }
113
114
115     /**
116      * Tries to parse "Exception in thread "___" ___:___" or just "___:___",
117      * containing the optional thread name, the exception class name and the
118      * exception message.
119      */

120     private boolean parseExceptionInThreadLine(String JavaDoc line)
121     {
122         // Trim away the thread message part, if any.
123
if (line.startsWith("Exception in thread \""))
124         {
125             int quote_index = line.indexOf('"', 21);
126             if (quote_index < 0)
127             {
128                 return false;
129             }
130
131             prefix = line.substring(0, quote_index+1) + " ";
132             line = line.substring(quote_index+1).trim();
133         }
134
135         int colonIndex = line.indexOf(':');
136         if (colonIndex < 0)
137         {
138             return false;
139         }
140
141         int spaceIndex = line.lastIndexOf(' ', colonIndex);
142
143         prefix = line.substring(0, spaceIndex+1);
144         obfuscatedClassName = line.substring(spaceIndex+1, colonIndex).trim();
145         suffix = line.substring(colonIndex);
146
147         return true;
148     }
149
150
151     /**
152      * Parses any line.
153      */

154     private void parseAnyLine(String JavaDoc line)
155     {
156         prefix = line;
157     }
158
159
160     /**
161      * Prints out the de-obfuscated stack trace.
162      */

163     public void print()
164     {
165         // Get the original class name, if we found it.
166
String JavaDoc className = originalClassName != null ?
167             originalClassName :
168             obfuscatedClassName;
169
170         // Get the first original method name, if we found it.
171
String JavaDoc methodName = originalMethodNames != null ?
172             (String JavaDoc)originalMethodNames.get(0) :
173             obfuscatedMethodName;
174
175         // Compose the source file with the line number, if any.
176
String JavaDoc source = lineNumber != 0 ?
177             sourceFile + ":" + lineNumber :
178             sourceFile;
179
180         // Print out the resolved stack trace
181
if (prefix != null)
182         {
183             System.out.print(prefix);
184         }
185
186         if (className != null)
187         {
188             System.out.print(className);
189         }
190
191         if (methodName != null)
192         {
193             System.out.print("." + methodName + "(" + source + ")");
194
195             // Print out alternatives, if any.
196
if (originalMethodNames != null)
197             {
198                 for (int otherMethodNameIndex = 1; otherMethodNameIndex < originalMethodNames.size(); otherMethodNameIndex++) {
199                     String JavaDoc otherMethodName = (String JavaDoc)originalMethodNames.get(otherMethodNameIndex);
200                     System.out.println();
201                     printSpaces(className.length()+12);
202                     System.out.print(otherMethodName);
203                 }
204             }
205         }
206
207         if (suffix != null)
208         {
209             System.out.print(suffix);
210         }
211
212         System.out.println();
213     }
214
215
216     /**
217      * Prints the given number of spaces.
218      */

219     private void printSpaces(int aCount)
220     {
221         for (int counter = 0; counter < aCount; counter++)
222           System.out.print(' ');
223     }
224
225
226     // Implementations for MappingProcessor.
227

228     public boolean processClassMapping(String JavaDoc className,
229                                        String JavaDoc newClassName)
230     {
231         boolean present = false;
232
233         if (newClassName.equals(obfuscatedClassName))
234         {
235             originalClassName = className;
236             present = true;
237         }
238
239         return present;
240     }
241
242
243     public void processFieldMapping(String JavaDoc className,
244                                     String JavaDoc fieldType,
245                                     String JavaDoc fieldName,
246                                     String JavaDoc newFieldName)
247     {
248         // A stack trace item never contains any fields.
249
}
250
251
252     public void processMethodMapping(String JavaDoc className,
253                                      int firstLineNumber,
254                                      int lastLineNumber,
255                                      String JavaDoc methodReturnType,
256                                      String JavaDoc methodNameAndArguments,
257                                      String JavaDoc newMethodName)
258     {
259         if (className.equals(originalClassName) &&
260             newMethodName.equals(obfuscatedMethodName) &&
261             (lineNumber == 0 ||
262              firstLineNumber == 0 ||
263              lastLineNumber == 0 ||
264              (firstLineNumber <= lineNumber &&
265               lastLineNumber >= lineNumber)))
266         {
267             // Create a List for storing solutions for this
268
// method name.
269
if (originalMethodNames == null)
270             {
271                 originalMethodNames = new ArrayList();
272             }
273
274             // Does the method have line numbers?
275
if (firstLineNumber != 0 &&
276                 lastLineNumber != 0 &&
277                 lineNumber != 0)
278             {
279                 // Then it will be the one and only solution.
280
obfuscatedMethodName = null;
281                 originalMethodNames.clear();
282             }
283
284             // Include return type and arguments in the method name if
285
// we're in verbose mode, otherwise strip the arguments.
286
String JavaDoc originalMethodName = verbose ?
287                 (methodReturnType + " " + methodNameAndArguments) :
288                 methodNameAndArguments.substring(0, methodNameAndArguments.indexOf('('));
289
290             // Add this method name solution to the list.
291
originalMethodNames.add(originalMethodName);
292         }
293     }
294 }
295
Popular Tags