Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: jreversepro/reflect/JClassInfo.java


1   /*
2    * @(#)JClassInfo.java
3    *
4    * JReversePro - Java Decompiler / Disassembler.
5    * Copyright (C) 2000 Karthik Kumar.
6    * EMail: akkumar@users.sourceforge.net
7    *
8    * This program is free software; you can redistribute it and/or modify
9    * it , under the terms of the GNU General Public License as published
10   * by the Free Software Foundation; either version 2 of the License,
11   * or (at your option) any later version.
12   *
13   * This program is distributed in the hope that it will be useful,
14   * but WITHOUT ANY WARRANTY; without even the implied warranty of
15   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16   * See the GNU General Public License for more details.
17   * You should have received a copy of the GNU General Public License
18   * along with this program.If not, write to
19   *  The Free Software Foundation, Inc.,
20   *  59 Temple Place - Suite 330,
21   *  Boston, MA 02111-1307, USA.
22   */
23  package jreversepro.reflect;
24  
25  
26  
27  import java.util.List;
28  import java.util.ArrayList;
29  
30  import jreversepro.common.KeyWords;
31  import jreversepro.common.Helper;
32  import jreversepro.common.AppConstants;
33  
34  import jreversepro.parser.ClassParserException;
35  
36  import jreversepro.revengine.JReverseEngineer;
37  import jreversepro.revengine.JDecompiler;
38  import jreversepro.revengine.JDisAssembler;
39  import jreversepro.revengine.RevEngineException;
40  
41  /**
42   * <b>JClassInfo</b> is the abstract representation of the Class File.
43   * The names of the methods are self explanatory.
44   *
45   * @author      Karthik Kumar
46   */
47  public class JClassInfo implements KeyWords {
48  
49      /**
50       * ACC_SUPER bit required to be set on all
51       * modern classes.
52       **/
53      public static final int ACC_SUPER   = 0x0020;
54  
55      /**
56       * ACC_INTERFACE bit required to be set if it is an
57       * interface and not a class.
58       **/
59      public static final int ACC_INTERFACE   = 0x0200;
60  
61      //Generic Info about a class File.
62      /**
63       * Absolute path where the class' source file was located.
64       **/
65      private String absPath;
66  
67      /**
68       * Major number of the JVM version that this class file
69       * is compiled for.
70       **/
71      private short majorNumber;
72  
73      /**
74       * Minor number of the JVM version that this class file
75       * is compiled for.
76       **/
77      private short minorNumber;
78  
79  
80      /**
81       * Name of the current class in the JVM format.
82       * That is, if the class is String then the name would be
83       * java/lang/String.
84       **/
85      private String thisClass;
86  
87  
88      /**
89       * Name of the current class' superclass in the JVM format.
90       * That is, if the class is String then the name would be
91       * java/lang/String.
92       **/
93      private String superClass;
94  
95      /**
96       * Name of the package of the current class in the JVM format.
97       * That is the fully qualified name of the class is
98       * java.lang.String. then the package name would contain
99       * java/lang.
100      **/
101     private String packageName;
102 
103     /**
104      * Name of the source file in which this class files' code
105      * is present.
106      **/
107     private String srcFile;
108 
109     /**
110      * ConstantPool information contained in the class.
111      **/
112     private JConstantPool cpInfo;
113 
114     /**
115      * TRUE if the class was decompiled.
116      * False if disasembled.
117      **/
118     private boolean decompiled;
119 
120     /**
121      * List of fields present in the class.
122      * All the members in the list are JField.
123      **/
124     private List memFields;
125 
126     /**
127      * List of methods present in the class.
128      * All the members in the list are JMethod.
129      **/
130     private List memMethods;
131 
132     /**
133      * List of interfaces present in the class.
134      * All the members in the list are String.
135      * For example if the class implements
136      * java.awt.event.ActionListener then the list would
137      * contain java/awt/event/ActionListener as its member.
138      * The class file name would be in the JVM format as mentioned
139      * above.
140      **/
141     private List interfaces;
142 
143     /**
144      * An integer referring to the access permission of the
145      * class.
146      * Like if a class is public static void main ()
147      * then the accessflag would have appropriate bits
148      * set to say if it public static.
149      **/
150     private int accessFlag;
151 
152     /**
153      * Empty constructor
154      **/
155     public JClassInfo() {
156         memFields =  new ArrayList();
157         memMethods =  new ArrayList();
158         interfaces = new ArrayList();
159         cpInfo =  new JConstantPool(2);
160 
161         decompiled = false;
162     }
163 
164     /**
165      * Adds a new interface that is implemented by this class.
166      * @param interfaceName Name of the interface.
167      **/
168     public void addInterface(String interfaceName) {
169         interfaces.add(interfaceName);
170     }
171 
172     /**
173      * Adds a new field present in the class.
174      * @param rhsField contains the field-related information.
175      **/
176     public void addField(JField rhsField) {
177         memFields.add(rhsField);
178     }
179 
180     /**
181      * Adds a new method present in the class.
182      * @param rhsMethod contains the method-related information.
183      **/
184     public void addMethod(JMethod rhsMethod) {
185         memMethods.add(rhsMethod);
186     }
187 
188     /**
189      * Sets the pathname of this class.
190      * @param classPath Path to this class.
191      **/
192     public void setPathName(String classPath) {
193         absPath  = classPath;
194     }
195 
196     /**
197      * Sets the ConstantPool information of this class.
198      * @param cpInfo contains the constant pool information
199      * of this class.
200      **/
201     public void setConstantPool(JConstantPool cpInfo) {
202         this.cpInfo = cpInfo;
203     }
204 
205     /**
206      * Returns the constantpool reference
207      * @return Returns the ConstantPool reference.
208      **/
209     public JConstantPool getConstantPool() {
210         return this.cpInfo;
211     }
212 
213     /**
214      * Sets the major and minor number of the JVM
215      * for which this class file is compiled for.
216      * @param rhsMajor Major number
217      * @param rhsMinor Minor number
218      **/
219     public void setMajorMinor(short rhsMajor, short rhsMinor) {
220         majorNumber = rhsMajor;
221         minorNumber = rhsMinor;
222     }
223 
224     /**
225      * Sets the access flag of the class.
226      * @param rhsAccess Access flag of the class.
227      **/
228     public void setAccess(int rhsAccess) {
229         accessFlag = rhsAccess;
230     }
231 
232     /**
233      * Sets the name of the current class.
234      * @param rhsName Name of this class.
235      **/
236     public void setThisClass(String rhsName) {
237         thisClass = rhsName;
238     }
239 
240     /**
241      * Sets the name of the current class' superclass.
242      * @param rhsName Name of this class; superclass.
243      **/
244     public void setSuperClass(String rhsName) {
245         superClass = rhsName;
246     }
247 
248     /**
249      * Sets the package to which this class belongs to.
250      * @param packageName name of the package to be set.
251      **/
252     public void setPackageName(String packageName) {
253         this.packageName = packageName;
254     }
255 
256     /**
257      * Sets the name of the source file to which this
258      * was contained in.
259      * @param rhsSrcFile Name of the source file.
260      **/
261     public void setSourceFile(String rhsSrcFile) {
262         srcFile = rhsSrcFile;
263     }
264 
265 
266     /**
267      * Returns the path name of this class.
268      * @return Absolute path of this class.
269      **/
270     public String getPathName() {
271         return absPath;
272     }
273 
274     /**
275      * Returns the major number of the JVM.
276      * @return JVM
277      **/
278     public int getMajor() {
279         return majorNumber;
280     }
281 
282     /**
283      * Returns the minor number of the JVM.
284      * @return JVM minor version
285      **/
286     public int getMinor() {
287         return minorNumber;
288     }
289 
290     /**
291      * @param fullyQualified Parameter to indicate if to return 
292      * the fully qualified name. 
293      * Yes - Fully qualified name along with the package name.
294      * No - Just the class name only.
295      * @return Returns Thisclass name only.
296      **/
297     public String getThisClass(boolean fullyQualified) {
298         if (fullyQualified) {
299             return thisClass;               
300         } else {
301             int lastIndex = thisClass.lastIndexOf('/');
302             if (lastIndex != -1) {
303                 return thisClass.substring(lastIndex + 1);
304             } else {
305                 return thisClass;
306             }
307         }   
308     }
309     
310     /**
311      * Returns the class name of this class.
312      * @return name of the current class.
313      **/
314     public String getThisClass() {
315         return thisClass;
316     }
317 
318     /**
319      * Returns the class name of this class' super class.
320      * @return name of the current class' super-class.
321      **/
322     public String getSuperClass() {
323         return superClass;
324     }
325 
326     /**
327      * Returns the source file of the current class.
328      * @return source file of the current class.
329      **/
330     public String getSourceFile() {
331         return srcFile;
332     }
333 
334     /**
335      * Returns the List of interfaces of the current class.
336      * @return interfaces of the current class.
337      **/
338     public List getInterfaces() {
339         return interfaces;
340     }
341 
342     /**
343      * Returns the fields present in the class.
344      * @return Returns a List of JField
345      **/
346     public List getFields() {
347         return memFields;
348     }
349 
350     /**
351      * Returns the methods of this class.
352      * @return Returns a list of JMethods
353      **/
354     public List getMethods() {
355         return memMethods;
356     }
357 
358     /**
359      * Returns the access string of this class.
360      * @return Returns the access string of this class.
361      **/
362     public String getAccessString() {
363         StringBuffer  accString = new StringBuffer();
364         accString.append(JMember.getStringRep(accessFlag, false));
365 
366         if (isClass())  {
367             accString.append(CLASS);
368         } else {
369             accString.append(INTERFACE);
370         }
371         return accString.toString();
372     }
373 
374     /**
375      * Returns if this is a class or an interface
376      * @return Returns true if this is a class,
377      *      false, if this is an interface.
378      **/
379     public boolean isClass() {
380         return ((accessFlag & ACC_INTERFACE) == 0);
381    }
382 
383    /**
384     * Process the methods.
385     * @param getBytecode TRUE - disassemble.
386     * FALSE - disassemble.
387     **/
388     public void processMethods(boolean getBytecode) {
389 
390         for (int i = 0 ; i < this.getMethods().size(); i++) {
391 
392             JMethod method = (JMethod) this.getMethods().get(i);
393             JReverseEngineer jre;
394 
395             jre = getBytecode 
396                         ?
397                     (JReverseEngineer)
398                     new JDisAssembler(method,
399                             this.getConstantPool()) 
400                             :
401                     (JReverseEngineer)
402                     new JDecompiler(
403                            method,
404                            this.getConstantPool());
405             try {
406                 jre.genCode();
407             } catch (Exception ex) {
408               ex.printStackTrace();
409             }
410         }
411     }
412 
413     /**
414      * Returns the stringified disassembled/decompiled class.
415      * @param getBytecode If TRUE, returns the disassembled code
416      *          IF the class has already been disassembled. If FALSE,
417      *          returns the decompiled code IF the class has been 
418      *          decompiled. Otherwise, returns null;
419      * @return  Stringified class
420      **/
421     public String getStringifiedClass(boolean getBytecode) {
422         return getStringifiedClass(getBytecode, false);
423     }
424     
425     /**
426      * Returns the stringified disassembled/decompiled class, optionally with
427      *      metadata.
428      * @param getBytecode If TRUE, returns the disassembled code
429      *          IF the class has already been disassembled. If FALSE,
430      *          returns the decompiled code IF the class has been 
431      *          decompiled. Otherwise, returns null;
432      * @param includeMetadata - TRUE if method stack & exception data should be
433      * output.
434      * @return  Stringified class
435      **/
436     public String getStringifiedClass(boolean getBytecode, 
437                                     boolean includeMetadata) {
438 
439         StringBuffer sb = new StringBuffer();
440         
441         sb.append(getHeaders());
442         sb.append(getPackageImports());
443         sb.append(getThisSuperClasses());
444 
445         sb.append(getStringifiedInterfaces()  + "{");
446         sb.append(getStringifiedFields());
447         sb.append(getStringifiedMethods(getBytecode, includeMetadata));
448         
449         sb.append("\n}");
450         return sb.toString();
451     }        
452 
453     /**
454      * Returns the stringified disassembled/decompiled method.
455      * @param getBytecode If TRUE, returns the disassembled code
456      *          IF the method has already been disassembled. If FALSE,
457      *          returns the decompiled code IF the method has been 
458      *          decompiled. Otherwise, returns null;
459      * @param includeMetadata - TRUE if method stack & exception data should be
460      * output
461      * @return  Stringified methods in this class
462      **/
463     public String getStringifiedMethods(boolean getBytecode,
464                                             boolean includeMetadata) {
465 
466         StringBuffer sb = new StringBuffer();
467         
468         for (int i = 0 ; i < this.getMethods().size() ; i++) {
469             JMethod method = (JMethod) this.getMethods().get(i);
470             sb.append(method.getMethodAsString(getBytecode, includeMetadata));
471         }
472         return sb.toString();
473     }
474     
475     
476     /**
477      * @return Returns a StringBuffer containing the headers for the reverse
478      * engineered code.
479      **/
480     private StringBuffer getHeaders() {
481         StringBuffer init =  new StringBuffer();
482         init.append("// Decompiled by JReversePro " + AppConstants.VERSION);
483         init.append("\n// Home : http://jrevpro.sourceforge.net ");
484         init.append("\n// JVM VERSiON: " 
485                         + majorNumber + "." 
486                         + minorNumber);
487         init.append("\n// SOURCEFILE: " 
488                         + srcFile);
489         return init;
490     }
491 
492     /**
493      * @return Returns a StringBuffer containing the package and import 
494      * information of the .class file.
495      **/
496     private StringBuffer getPackageImports() {
497         StringBuffer result =  new StringBuffer();
498         String packageName = Helper.getPackageName(thisClass);
499         
500         if (packageName.length() != 0) {
501             result.append("\npackage " 
502                             + packageName +  ";");
503         }
504 
505         result.append("\n\n" 
506                 +  cpInfo.getImportedClasses().getImportClasses(packageName));
507         return result;
508     }
509 
510     /**
511      * @return Returns a StringBuffer containing the current class name
512      * and the super class name.
513      **/
514     private StringBuffer getThisSuperClasses() {
515         StringBuffer sb =  new StringBuffer();
516         sb.append("\n\n" + getAccessString() + " ");
517 
518         sb.append(cpInfo.getImportedClasses().
519                             getClassName(
520                                     thisClass));
521 
522         
523         if (!superClass.equals(LANG_OBJECT)) {
524             sb.append(" extends ");
525             sb.append(
526                 cpInfo.getImportedClasses().
527                                         getClassName(superClass) + "   ");
528         }
529         return sb;
530     }
531 
532     /**
533      * @return Returns a StringBuffer containing the information
534      * of the interfaces implemented by the class.
535      **/
536     private StringBuffer getStringifiedInterfaces() {
537         StringBuffer sb = new StringBuffer();
538         if (interfaces.size() != 0) {
539             sb.append("\n\t\timplements ");
540             for (int i = 0; i < interfaces.size(); i++) {
541                 if (i != 0) {
542                     sb.append(" ,");
543                 }
544                 sb.append(
545                     cpInfo.getImportedClasses().
546                         getClassName(
547                                 (String) interfaces.get(i)));
548             }
549         }
550         return sb;
551     }
552     
553     /**
554      * @return Returns a StringBuffer containing the information
555      * of fields present in this class.
556      **/
557     private StringBuffer getStringifiedFields() {
558         StringBuffer sb = new StringBuffer("\n");
559         for (int i = 0; i < memFields.size(); i++) {
560             JField field = (JField) memFields.get(i);
561             String datatype =
562                 cpInfo.getImportedClasses().
563                     getClassName(
564                         Helper.getJavaDataType(
565                             field.getDatatype(), false));
566 
567             String access = field.getQualifierName();
568 
569             sb.append("\n\t" + access);
570             sb.append(datatype);
571             sb.append(" " + field.getName());
572             String val = field.getValue();
573             if (field.isFinal() && val.length() != 0) {
574                 sb.append(" = " + val);
575             }
576             sb.append(";");
577         }
578         return sb;
579     }
580     
581     /**
582      * Reverse Engineer the Class file.
583      * @param getBytecode True disassembler, false - decompile.
584      * @throws ClassParserException Thrown if class file not in proper format.
585      * @throws RevEngineException Thrown if error occured in reverse
586      * engineering file.
587      **/
588     public void reverseEngineer(boolean getBytecode)
589                         throws ClassParserException,
590                                 RevEngineException {
591         //Reverse Engineer here
592         processMethods(getBytecode);
593     }
594 }