Main Page   Packages   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members  

ClassFile.java

00001 package ca.mcgill.sable.soot.coffi;
00002 
00003 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
00004  * Jimple, a 3-address code Java(TM) bytecode representation.        *
00005  * Copyright (C) 1997, 1998 Raja Vallee-Rai (kor@sable.mcgill.ca)    *
00006  * All rights reserved.                                              *
00007  *                                                                   *
00008  * Modifications by Etienne Gagnon (gagnon@sable.mcgill.ca) are      *
00009  * Copyright (C) 1998 Etienne Gagnon (gagnon@sable.mcgill.ca).  All  *
00010  * rights reserved.                                                  *
00011  *                                                                   *
00012  * This work was done as a project of the Sable Research Group,      *
00013  * School of Computer Science, McGill University, Canada             *
00014  * (http://www.sable.mcgill.ca/).  It is understood that any         *
00015  * modification not identified as such is not covered by the         *
00016  * preceding statement.                                              *
00017  *                                                                   *
00018  * This work is free software; you can redistribute it and/or        *
00019  * modify it under the terms of the GNU Library General Public       *
00020  * License as published by the Free Software Foundation; either      *
00021  * version 2 of the License, or (at your option) any later version.  *
00022  *                                                                   *
00023  * This work is distributed in the hope that it will be useful,      *
00024  * but WITHOUT ANY WARRANTY; without even the implied warranty of    *
00025  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU *
00026  * Library General Public License for more details.                  *
00027  *                                                                   *
00028  * You should have received a copy of the GNU Library General Public *
00029  * License along with this library; if not, write to the             *
00030  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,      *
00031  * Boston, MA  02111-1307, USA.                                      *
00032  *                                                                   *
00033  * Java is a trademark of Sun Microsystems, Inc.                     *
00034  *                                                                   *
00035  * To submit a bug report, send a comment, or get the latest news on *
00036  * this project and other Sable Research Group projects, please      *
00037  * visit the web site: http://www.sable.mcgill.ca/                   *
00038  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00039 
00040 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
00041  * Coffi, a bytecode parser for the Java(TM) language.               *
00042  * Copyright (C) 1996, 1997 Clark Verbrugge (clump@sable.mcgill.ca). *
00043  * All rights reserved.                                              *
00044  *                                                                   *
00045  * This work was done as a project of the Sable Research Group,      *
00046  * School of Computer Science, McGill University, Canada             *
00047  * (http://www.sable.mcgill.ca/).  It is understood that any         *
00048  * modification not identified as such is not covered by the         *
00049  * preceding statement.                                              *
00050  *                                                                   *
00051  * This work is free software; you can redistribute it and/or        *
00052  * modify it under the terms of the GNU Library General Public       *
00053  * License as published by the Free Software Foundation; either      *
00054  * version 2 of the License, or (at your option) any later version.  *
00055  *                                                                   *
00056  * This work is distributed in the hope that it will be useful,      *
00057  * but WITHOUT ANY WARRANTY; without even the implied warranty of    *
00058  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU *
00059  * Library General Public License for more details.                  *
00060  *                                                                   *
00061  * You should have received a copy of the GNU Library General Public *
00062  * License along with this library; if not, write to the             *
00063  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,      *
00064  * Boston, MA  02111-1307, USA.                                      *
00065  *                                                                   *
00066  * Java is a trademark of Sun Microsystems, Inc.                     *
00067  *                                                                   *
00068  * To submit a bug report, send a comment, or get the latest news on *
00069  * this project and other Sable Research Group projects, please      *
00070  * visit the web site: http://www.sable.mcgill.ca/                   *
00071  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00072 
00073 /*
00074  Reference Version
00075  -----------------
00076  This is the latest official version on which this file is based.
00077  The reference version is: $CoffiVersion: 1.1 $
00078                            $SootVersion: 1.beta.4 $
00079 
00080  Change History
00081  --------------
00082  A) Notes:
00083 
00084  Please use the following template.  Most recent changes should
00085  appear at the top of the list.
00086 
00087  - Modified on [date (March 1, 1900)] by [name]. [(*) if appropriate]
00088    [description of modification].
00089 
00090  Any Modification flagged with "(*)" was done as a project of the
00091  Sable Research Group, School of Computer Science,
00092  McGill University, Canada (http://www.sable.mcgill.ca/).
00093 
00094  You should add your copyright, using the following template, at
00095  the top of this file, along with other copyrights.
00096 
00097  *                                                                   *
00098  * Modifications by [name] are                                       *
00099  * Copyright (C) [year(s)] [your name (or company)].  All rights     *
00100  * reserved.                                                         *
00101  *                                                                   *
00102 
00103  B) Changes:
00104 
00105  - Modified on November 13, 1998 by Raja Vallee-Rai (kor@sable.mcgill.ca) (*)
00106    Changed some short's to int's to properly contain unsigned
00107    short values.
00108 
00109  - Modified on November 2, 1998 by Raja Vallee-Rai (kor@sable.mcgill.ca) (*)
00110    Repackaged all source files and performed extensive modifications.
00111    First initial release of Soot.
00112 
00113  - Modified on September 3, 1998 by Raja Vallee-Rai (kor@sable.mcgill.ca). (*)
00114    Changed (short) readUnsignedShort() to (int) readUnsignedShort()
00115    to avoid truncation.
00116 
00117  - Modified on July 5, 1998 by Etienne Gagnon (gagnon@sable.mcgill.ca). (*)
00118    Added special handling for jimpleClassPath.
00119 
00120  - Modified on 15-Jun-1998 by Raja Vallee-Rai (kor@sable.mcgill.ca). (*)
00121    First internal release (Version 0.1).
00122 */
00123 
00124 import java.io.*;
00125 import java.util.Enumeration;
00126 import java.util.Vector;
00127 import ca.mcgill.sable.util.ClassLocator;
00128 import ca.mcgill.sable.soot.jimple.Main;
00129 
00130 /**
00131  * A ClassFile object represents the contents of a <tt>.class</tt> file.
00132  * <p>
00133  * A ClassFile contains code for manipulation of its constituents.
00134  * @author Clark Verbrugge
00135  */
00136 public class ClassFile {
00137 
00138    /** Magic number. */
00139     static final long MAGIC = 0xCAFEBABEL;
00140 
00141    /** Access bit flag. */
00142     static final short ACC_PUBLIC =    0x0001;
00143    /** Access bit flag. */
00144     static final short ACC_PRIVATE =   0x0002;
00145    /** Access bit flag. */
00146     static final short ACC_PROTECTED = 0x0004;
00147    /** Access bit flag. */
00148     static final short ACC_STATIC =    0x0008;
00149    /** Access bit flag. */
00150     static final short ACC_FINAL =     0x0010;
00151    /** Access bit flag. */
00152     static final short ACC_SUPER =     0x0020;
00153    /** Access bit flag. */
00154     static final short ACC_VOLATILE =  0x0040;
00155    /** Access bit flag. */
00156     static final short ACC_TRANSIENT = 0x0080;
00157    /** Access bit flag. */
00158     static final short ACC_INTERFACE = 0x0200;
00159    /** Access bit flag. */
00160     static final short ACC_ABSTRACT =  0x0400;
00161    /** Remaining bits in the access bit flag. */
00162     static final short ACC_UNKNOWN =   0x7800;
00163 
00164    /** Descriptor code string. */
00165     static final String DESC_BYTE =    "B";
00166    /** Descriptor code string. */
00167     static final String DESC_CHAR =    "C";
00168    /** Descriptor code string. */
00169     static final String DESC_DOUBLE =  "D";
00170    /** Descriptor code string. */
00171     static final String DESC_FLOAT=    "F";
00172    /** Descriptor code string. */
00173     static final String DESC_INT =     "I";
00174    /** Descriptor code string. */
00175     static final String DESC_LONG =    "J";
00176    /** Descriptor code string. */
00177     static final String DESC_OBJECT =  "L";
00178    /** Descriptor code string. */
00179     static final String DESC_SHORT =   "S";
00180    /** Descriptor code string. */
00181     static final String DESC_BOOLEAN = "Z";
00182    /** Descriptor code string. */
00183     static final String DESC_VOID =    "V";
00184    /** Descriptor code string. */
00185     static final String DESC_ARRAY =   "[";
00186 
00187    /** Debugging flag. */
00188     boolean debug;
00189 
00190    /** File name of the <tt>.class</tt> this represents. */
00191     String fn;
00192 
00193    /* For chaining ClassFiles into a list.
00194       ClassFile next;*/
00195 
00196    /** Magic number read in.
00197     * @see ClassFile#MAGIC
00198     */
00199     long magic;
00200    /** Minor version. */
00201     int minor_version;
00202    /** Major version. */
00203     int major_version;
00204    /** Number of items in the constant pool. */
00205     int constant_pool_count;
00206    /** Array of constant pool items.
00207     * @see cp_info
00208     */
00209     public cp_info constant_pool[];
00210    /** Access flags for this Class.
00211     */
00212     int access_flags;
00213    /** Constant pool index of the Class constant describing <i>this</i>.
00214     * @see CONSTANT_Class_info
00215     */
00216     public int this_class;
00217    /** Constant pool index of the Class constant describing <i>super</i>.
00218     * @see CONSTANT_Class_info
00219     */
00220     int super_class;
00221    /** Count of interfaces implemented. */
00222     int interfaces_count;
00223    /** Array of constant pool indices of Class constants describing each
00224     * interace implemented by this class, as given in the source for this
00225     * class.
00226     * @see CONSTANT_Class_info
00227     */
00228     int interfaces[];
00229    /** Count of fields this Class contains. */
00230     int fields_count;
00231    /** Array of field_info objects describing each field.
00232     * @see field_info
00233     */
00234     field_info fields[];
00235    /** Count of methods this Class contains. */
00236     int methods_count;
00237    /** Array of method_info objects describing each field.
00238     * @see method_info
00239     */
00240     method_info methods[];
00241    /** Count of attributes this class contains. */
00242     int attributes_count;
00243    /** Array of attribute_info objects for this class.
00244     * @see attribute_info
00245     */
00246     attribute_info attributes[];
00247 
00248    /* DEPRECATED
00249    // Locates the given classfile, and extracts it from the list.
00250    // It cannot be the first one in the list, and this returns null
00251    // or the classfile.
00252     static ClassFile removeClassFile(ClassFile cfhead,String cfn) {
00253       ClassFile cf,cfprev;
00254       cf = cfhead;
00255       cfprev = null;
00256       while (cf!=null) {
00257          if (cf.sameClass(cfn)) {
00258             if (cfprev==null) return null; // this shouldn't happen
00259             cfprev.next = cf.next;
00260             cf.next = null;
00261             return cf;
00262          }
00263          cfprev = cf;
00264          cf = cf.next;
00265       }
00266       return null;
00267    }
00268 
00269    // returns true if this class contains any references to the given
00270    // cuClass.cuName, which is of type cuDesc.  Searches for methods if
00271    // ismethod is true, fields otherwise.
00272    boolean refersTo(boolean ismethod,CONSTANT_Utf8_info cuClass,
00273                     CONSTANT_Utf8_info cuName,CONSTANT_Utf8_info cuDesc) {
00274       int i;
00275       CONSTANT_Utf8_info cu;
00276       // note that we start at 1 in the constant pool
00277       if (ismethod) {
00278          for (i=1;i<constant_pool_count;i++) {
00279             if ((constant_pool[i]).tag==cp_info.CONSTANT_Methodref) {
00280                CONSTANT_Methodref_info cf = (CONSTANT_Methodref_info)(constant_pool[i]);
00281                CONSTANT_Class_info cc = (CONSTANT_Class_info)
00282                   (constant_pool[cf.class_index]);
00283                if (cuClass.equals((CONSTANT_Utf8_info)
00284                                   (constant_pool[cc.name_index]))) {
00285                   CONSTANT_NameAndType_info cn = (CONSTANT_NameAndType_info)
00286                      (constant_pool[cf.name_and_type_index]);
00287                   if (cuName.equals((CONSTANT_Utf8_info)
00288                                     (constant_pool[cn.name_index])) &&
00289                       cuDesc.equals((CONSTANT_Utf8_info)
00290                                     (constant_pool[cn.descriptor_index])))
00291                      return true;
00292                }
00293             } else if ((constant_pool[i]).tag==
00294                        cp_info.CONSTANT_InterfaceMethodref) {
00295                CONSTANT_InterfaceMethodref_info cf =
00296                   (CONSTANT_InterfaceMethodref_info)(constant_pool[i]);
00297                CONSTANT_Class_info cc = (CONSTANT_Class_info)
00298                   (constant_pool[cf.class_index]);
00299                if (cuClass.equals((CONSTANT_Utf8_info)
00300                                   (constant_pool[cc.name_index]))) {
00301                   CONSTANT_NameAndType_info cn = (CONSTANT_NameAndType_info)
00302                      (constant_pool[cf.name_and_type_index]);
00303                   if (cuName.equals((CONSTANT_Utf8_info)
00304                                     (constant_pool[cn.name_index])) &&
00305                       cuDesc.equals((CONSTANT_Utf8_info)
00306                                     (constant_pool[cn.descriptor_index])))
00307                      return true;
00308                }
00309             } else if ((constant_pool[i]).tag==cp_info.CONSTANT_Long ||
00310                        (constant_pool[i]).tag==cp_info.CONSTANT_Double) {
00311                // must skip an entry after a long or double constant
00312                i++;
00313             }
00314          }
00315       } else {
00316          for (i=1;i<constant_pool_count;i++) {
00317             if ((constant_pool[i]).tag==cp_info.CONSTANT_Fieldref) {
00318                CONSTANT_Fieldref_info cf = (CONSTANT_Fieldref_info)(constant_pool[i]);
00319                CONSTANT_Class_info cc = (CONSTANT_Class_info)
00320                   (constant_pool[cf.class_index]);
00321                if (cuClass.equals((CONSTANT_Utf8_info)
00322                                   (constant_pool[cc.name_index]))) {
00323                   CONSTANT_NameAndType_info cn = (CONSTANT_NameAndType_info)
00324                      (constant_pool[cf.name_and_type_index]);
00325                   if (cuName.equals((CONSTANT_Utf8_info)
00326                                     (constant_pool[cn.name_index])) &&
00327                       cuDesc.equals((CONSTANT_Utf8_info)
00328                                     (constant_pool[cn.descriptor_index])))
00329                      return true;
00330                }
00331             } else if ((constant_pool[i]).tag==cp_info.CONSTANT_Long ||
00332                        (constant_pool[i]).tag==cp_info.CONSTANT_Double) {
00333                // must skip an entry after a long or double constant
00334                i++;
00335             }
00336          }
00337       }
00338       return false;
00339    }
00340 
00341    // produces a sorted array of constant pool indices, one for each Utf8 entry used
00342    // by any field
00343    short[] forbiddenFields() {
00344       short fFields[] = new short[fields_count];
00345       for (int i=0;i<fields_count;i++) {
00346          fFields[i] = fields[i].name_index;
00347       }
00348       // now to sort the array
00349       return sortShorts(fFields);
00350    }
00351 
00352    // sorts an array of shorts using selection sort.  It's assumed no valid
00353    // entry is 0.
00354    static short[] sortShorts(short a[]) {
00355       int i,largest;
00356       short s;
00357       for(largest = a.length-1;largest>=1;largest--) {
00358          for (i=0;i<largest;i++) {
00359             if (a[i]>a[largest]) {
00360                s = a[i];
00361                a[i] = a[largest];
00362                a[largest] = s;
00363             }
00364          }
00365       }
00366       return a;
00367    }
00368 
00369    // Given a new constant pool, and a list of redirections
00370    // (new index = redirect[old index]), this changes all constant
00371    // pool entries, and installs the new constant pool of size size
00372    void changeConstantPool(short redirect[],cp_info newCP[],short size) {
00373       Debig d = new Debig(this);
00374       d.redirectCPRefs(redirect);
00375       constant_pool = newCP;
00376       constant_pool_count = size;
00377    }
00378 
00379    // the constant pool is typically a few hundred entries in size, and so
00380    // is just a bit too big to make use of insertion/selection sort.
00381    // However, the variable size of the entries makes using a heapsort
00382    // or quicksort rather cumbersome, so since it is quite close to the
00383    // limits of efficient insertion/selection sort, we'll use that anyway.
00384     void sortConstantPool() {
00385       cp_info newcp[] = new cp_info[constant_pool_count];
00386       short redirect[] = new short[constant_pool_count];
00387       newcp[0] = constant_pool[0];  // the 0-entry stays put
00388       redirect[0] = (short)0;
00389       int smallest,j;
00390       for (int i=1;i<constant_pool_count;i++) redirect[i] = (short)0;
00391       for (int i=1;i<constant_pool_count;i++) {
00392          for (smallest = 1;smallest<constant_pool_count;smallest++)
00393             if (redirect[smallest]==(short)0) break;
00394          //System.out.println(" smallest = " + smallest);
00395          j = (constant_pool[smallest].tag==cp_info.CONSTANT_Double ||
00396               constant_pool[smallest].tag==cp_info.CONSTANT_Long) ? smallest+2 : smallest+1;
00397          for (;j<constant_pool_count;j++) {
00398             if ((redirect[j]==(short)0) && constant_pool[j].
00399                 compareTo(constant_pool,constant_pool[smallest],constant_pool)<0) {
00400                smallest = j;
00401             }
00402             if (constant_pool[j].tag==cp_info.CONSTANT_Double ||
00403                 constant_pool[j].tag==cp_info.CONSTANT_Long) j++;
00404          }
00405          redirect[smallest] = (short)i;
00406          newcp[i] = constant_pool[smallest];
00407          //System.out.println(" Smallest cp entry is [" + smallest + "] = " + constant_pool[smallest]
00408          //                 + " -> " + i);
00409 
00410          if (constant_pool[smallest].tag==cp_info.CONSTANT_Double ||
00411              constant_pool[smallest].tag==cp_info.CONSTANT_Long) {
00412             redirect[++smallest] = (short)(++i);
00413             newcp[i] = constant_pool[smallest];
00414          }
00415       }
00416       // constant pool is now sorted into newcp
00417       changeConstantPool(redirect,newcp,constant_pool_count);
00418       System.out.println("Finished sorting constant pool");
00419    }
00420 
00421    // just a wrapper for the debigulation, so we can elegantly allocate
00422    // a new debigulator, debigualte and then produce some output
00423     void debigulate(boolean attribs,boolean privates) {
00424       Debig debigulator = new Debig(this);
00425       debigulator.debigulate(attribs,privates);
00426       debigulator.setCF(null);
00427 
00428       inf.verboseReport(System.out);
00429    }*/
00430 
00431 
00432    /** Creates a new ClassFile object given the name of the file.
00433     * @param nfn file name which this ClassFile will represent.
00434     */
00435     ClassFile(String nfn) { fn = nfn; }
00436    /** Returns a String constructed by parsing the bits in the given
00437     * access code (as defined by the ACC_* constants).
00438     * @param af access code.
00439     * @param separator String used to separate words used for access bits.
00440     * @see ClassFile#access_flags
00441     * @see method_info#access_flags
00442     * @see field_info#access_flags
00443     */
00444     static String access_string(int af,String separator) {
00445       boolean hasone = false;
00446       String s = "";
00447       if ((af & ACC_PUBLIC) != 0) {
00448          s = "public";
00449          hasone = true;
00450       }
00451       if ((af & ACC_PRIVATE) != 0) {
00452          if (hasone) s = s + separator;
00453          else hasone = true;
00454          s = s + "private";
00455       }
00456       if ((af & ACC_PROTECTED) != 0) {
00457          if (hasone) s = s + separator;
00458          else hasone = true;
00459          s = s + "protected";
00460       }
00461       if ((af & ACC_STATIC) != 0) {
00462          if (hasone) s = s + separator;
00463          else hasone = true;
00464          s = s + "static";
00465       }
00466       if ((af & ACC_FINAL) != 0) {
00467          if (hasone) s = s + separator;
00468          else hasone = true;
00469          s = s + "final";
00470       }
00471       if ((af & ACC_SUPER) != 0) {
00472          if (hasone) s = s + separator;
00473          else hasone = true;
00474          s = s + "super";
00475       }
00476       if ((af & ACC_VOLATILE) != 0) {
00477          if (hasone) s = s + separator;
00478          else hasone = true;
00479          s = s + "volatile";
00480       }
00481       if ((af & ACC_TRANSIENT) != 0) {
00482          if (hasone) s = s + separator;
00483          else hasone = true;
00484          s = s + "transient";
00485       }
00486       if ((af & ACC_INTERFACE) != 0) {
00487          if (hasone) s = s + separator;
00488          else hasone = true;
00489          s = s + "interface";
00490       }
00491       if ((af & ACC_ABSTRACT) != 0) {
00492          if (hasone) s = s + separator;
00493          else hasone = true;
00494          s = s + "abstract";
00495       }
00496       if ((af & ACC_UNKNOWN) != 0) {
00497          if (hasone) s = s + separator;
00498          else hasone = true;
00499          s = s + "unknown";
00500       }
00501       return s;
00502    }   
00503    /** Answers whether this class is an immediate descendant (as subclass or
00504     * as an implementation of an interface) of the given class.
00505     * @param cf ClassFile of supposed parent.
00506     * @return <i>true</i> if it is a parent, <i>false</i> otherwise.
00507     * @see ClassFile#descendsFrom(String)
00508     */
00509     boolean descendsFrom(ClassFile cf) { return descendsFrom(cf.toString()); }
00510    /** Answers whether this class is an immediate descendant (as subclass or
00511     * as an implementation of an interface) of the given class.
00512     * @param cname name of supposed parent.
00513     * @return <i>true</i> if it is a parent, <i>false</i> otherwise.
00514     * @see ClassFile#descendsFrom(ClassFile)
00515     */
00516     boolean descendsFrom(String cname) {
00517       cp_info cf;
00518       int i;
00519       cf = constant_pool[super_class];
00520       if (cf.toString(constant_pool).compareTo(cname)==0) return true;
00521       for (i=0;i<interfaces_count;i++) {
00522          cf = constant_pool[interfaces[i]];
00523          if (cf.toString(constant_pool).compareTo(cname)==0) return true;
00524       }
00525       return false;
00526    }   
00527    /** Returns the name of a specific field in the field array.
00528     * @param i index of field in field array.
00529     * @return name of field.
00530     */
00531     String fieldName(int i) {
00532       return fields[i].toName(constant_pool);
00533    }   
00534    /** Locates a method by name.
00535     * @param s name of method.
00536     * @return method_info object representing method, or <i>null</i> if not found.
00537     * @see method_info#toName
00538     */
00539     method_info findMethod(String s) {
00540       method_info m;
00541       int i;
00542 
00543       for (i=0;i<methods_count;i++) {
00544          m = methods[i];
00545          if (s.equals(m.toName(constant_pool))) {
00546             return m;
00547          }
00548       }
00549       return null;
00550    }   
00551    /** Answers whether this class can have subclasses outside its package.
00552     * @return <i>true</i> if it cannot, <i>false</i> if it might.
00553     */
00554     boolean isSterile() {
00555       if ((access_flags&ACC_PUBLIC)!=0 && (access_flags&ACC_FINAL)==0) return false;
00556       return true;
00557    }   
00558    /** Displays the entire constant pool.
00559     * @see ClassFile#constant_pool
00560     * @see ClassFile#constant_pool_count
00561     * @see cp_info#toString
00562     */
00563     void listConstantPool() {
00564       cp_info c;
00565       int i;
00566 
00567       // note that we start at 1 in the constant pool
00568       for (i=1;i<constant_pool_count;i++) {
00569          c = constant_pool[i];
00570          System.out.println("[" + i + "] " + c.typeName() +
00571                             "=" + c.toString(constant_pool));
00572          if ((constant_pool[i]).tag==cp_info.CONSTANT_Long ||
00573              (constant_pool[i]).tag==cp_info.CONSTANT_Double) {
00574             // must skip an entry after a long or double constant
00575             i++;
00576          }
00577       }
00578    }   
00579    /** Displays the list of fields defined in this ClassFile, including
00580     * any static initializers (constants).
00581     * @see ClassFile#fields
00582     * @see ClassFile#fields_count
00583     * @see field_info#prototype
00584     * @see ConstantValue_attribute
00585     */
00586     void listFields() {
00587       field_info fi;
00588       ConstantValue_attribute cva;
00589       CONSTANT_Utf8_info cm;
00590       int i,j;
00591 
00592       for (i=0;i<fields_count;i++) {
00593          fi = fields[i];
00594          System.out.print(fi.prototype(constant_pool));
00595          // see if has a constant value attribute
00596          for (j=0;j<fi.attributes_count;j++) {
00597             cm = (CONSTANT_Utf8_info)(constant_pool[fi.attributes[j].attribute_name]);
00598             if (cm.convert().compareTo(attribute_info.ConstantValue)==0) {
00599                cva = (ConstantValue_attribute)(fi.attributes[j]);
00600                //dm = (CONSTANT_Utf8_info)(constant_pool[cva.constantvalue_index]);
00601                System.out.print(" = " +
00602                                 constant_pool[cva.constantvalue_index].
00603                                 toString(constant_pool));
00604                break;
00605             }
00606          }
00607          System.out.println(";");
00608       }
00609    }   
00610    /** Displays a the prototypes for all the methods defined in this ClassFile.
00611     * @see ClassFile#methods
00612     * @see ClassFile#methods_count
00613     * @see method_info#prototype
00614     */
00615     void listMethods() {
00616       int i;
00617 
00618       for (i=0;i<methods_count;i++) {
00619          System.out.println(methods[i].prototype(constant_pool));
00620       }
00621    }   
00622    /** Main entry point for reading in a class file.
00623     * The file name is given in the constructor; this opens the
00624     * file and reads in the contents, building the representation.
00625     * @return <i>true</i> on success.
00626     */
00627     boolean loadClassFile() {
00628       InputStream f;
00629       DataInputStream d;
00630       boolean b;
00631 
00632       try
00633       {   if(Main.jimpleClassPath != null)
00634           {   f = ClassLocator.getInputStreamOf(Main.jimpleClassPath, fn);
00635           }
00636           else
00637           {   f = ClassLocator.getInputStreamOf(fn);
00638           }
00639           
00640       }
00641       catch(ClassNotFoundException e)
00642       {   throw new RuntimeException("Could not locate class " + fn);
00643       }
00644 
00645       d = new DataInputStream(f);
00646       b = readClass(d);
00647       
00648       try {
00649         d.close(); 
00650         f.close();
00651       } catch(IOException e) {
00652          System.out.println("IOException with " + fn + ": " + e.getMessage());
00653          return false;
00654       }
00655       
00656       if (!b) return false;
00657       parse();        // parse all methods & builds CFGs
00658       //System.out.println("-- Read " + cf + " --");
00659       return true;
00660    }   
00661    /** Moves a method to a different index in the methods array.
00662     * @param m name of method to move.
00663     * @param pos desired index.
00664     * @see ClassFile#methods
00665     */
00666     void moveMethod(String m,int pos) {
00667       int i,j;
00668       method_info mthd;
00669       System.out.println("Moving " + m + " to position " + pos +
00670                          " of " + methods_count);
00671 
00672       for (i=0;i<methods_count;i++) {
00673          if (m.compareTo(methods[i].toName(constant_pool))==0) {
00674             mthd = methods[i];
00675             if (i>pos) {
00676                for (j=i;j>pos && j>0;j--)
00677                   methods[j] = methods[j-1];
00678                methods[pos] = mthd;
00679             } else if (i<pos) {
00680                for (j=i;j<pos && j<methods_count-1;j++)
00681                   methods[j] = methods[j+1];
00682                methods[pos] = mthd;
00683             }
00684             return;
00685          }
00686       }
00687    }   
00688    /** For every method, this calls parseMethod, storing the list of Instructions
00689     * in the method_info object, and also constructs the corresponding CFG.
00690     * @see ClassFile#parseMethod
00691     * @see CFG
00692     */
00693     void parse() {
00694       method_info mi;
00695       int i;
00696 
00697       for (i=0;i<methods_count;i++) {
00698          mi = methods[i];
00699          mi.instructions = parseMethod(mi);
00700          //new CFG(mi);
00701          // don't build it right away for now
00702       }
00703    }   
00704    /** Static utility method to parse the given method descriptor string.
00705     * @param desc descriptor string.
00706     * @param sep String to use as a separator between types.
00707     * @return String of types parsed.
00708     * @see ClassFile#parseDesc
00709     * @see ClassFile#parseMethodDesc_return
00710     */
00711     static String parseDesc(String desc,String sep) {
00712       String params = "",param;
00713       char c;
00714       int i,len,arraylevel=0;
00715       boolean didone = false;
00716 
00717       len = desc.length();
00718       for (i=0;i<len;i++) {
00719          c = desc.charAt(i);
00720          if (c==DESC_BYTE.charAt(0)) {
00721             param = "byte";
00722          } else if (c==DESC_CHAR.charAt(0)) {
00723             param = "char";
00724          } else if (c==DESC_DOUBLE.charAt(0)) {
00725             param = "double";
00726          } else if (c==DESC_FLOAT.charAt(0)) {
00727             param = "float";
00728          } else if (c==DESC_INT.charAt(0)) {
00729             param = "int";
00730          } else if (c==DESC_LONG.charAt(0)) {
00731             param = "long";
00732          } else if (c==DESC_SHORT.charAt(0)) {
00733             param = "short";
00734          } else if (c==DESC_BOOLEAN.charAt(0)) {
00735             param = "boolean";
00736          } else if (c==DESC_VOID.charAt(0)) {
00737             param = "void";
00738          } else if (c==DESC_ARRAY.charAt(0)) {
00739             arraylevel++;
00740             continue;
00741          } else if (c==DESC_OBJECT.charAt(0)) {
00742             int j;
00743             j = desc.indexOf(';',i+1);
00744             if (j<0) {
00745                System.out.println("Warning: Parse error -- can't find a ; in " +
00746                                   desc.substring(i+1));
00747                param = "<error>";
00748             } else {
00749                if (j-i>10 && desc.substring(i+1,i+11).compareTo("java/lang/")==0)
00750                   i = i+10;
00751                param = desc.substring(i+1,j);
00752                // replace '/'s with '.'s
00753                param = param.replace('/','.');
00754                i = j;
00755             }
00756          } else    {
00757             param = "???";
00758          }
00759          if (didone) params = params + sep;
00760          params = params + param;
00761          while (arraylevel>0) {
00762             params = params + "[]";
00763             arraylevel--;
00764          }
00765          didone = true;
00766       }
00767       return params;
00768    }   
00769    /** Parses the given method, converting its bytecode array into a list
00770     * of Instruction objects.
00771     * @param m method to parse.
00772     * @return head of a list of Instructions.
00773     * @see Instruction
00774     * @see ByteCode
00775     * @see ByteCode#disassemble_bytecode
00776     */
00777     Instruction parseMethod(method_info m) {
00778       // first task, look through attributes for a code attribute
00779       int j;
00780       Code_attribute ca;
00781       ByteCode bc;
00782       Instruction inst,head,tail;
00783       exception_table_entry e;
00784 
00785       head = null;
00786       tail = null;
00787       bc = new ByteCode();
00788 
00789       ca = m.locate_code_attribute();
00790       if (ca==null) return null;
00791 
00792       j = 0;
00793       while(j<ca.code_length) {
00794          inst = bc.disassemble_bytecode(ca.code,j);
00795          inst.originalIndex = j;
00796          // System.out.println(inst + ": " + (((int)(inst.code))&0xff));
00797          // System.out.println(j + " : " + inst);
00798 
00799          if (inst instanceof Instruction_Unknown) {
00800             System.out.println("Unknown instruction in \"" + m.toName(constant_pool) +
00801                                "\" at offset " + j);
00802             System.out.println(" bytecode = " + (((int)(inst.code))&0xff));
00803          }
00804          // System.out.println("before: " + j);
00805          j = inst.nextOffset(j);
00806          // System.out.println("after: " + j);
00807 
00808          if (head==null) head = inst;
00809          else tail.next = inst;
00810          tail = inst;
00811       }
00812 
00813       // bytecode converted into instructions, now build pointers
00814       bc.build(head);
00815 
00816       // also change exception table to use pointers instead of absolute addresses
00817       for (j=0;j<ca.exception_table_length;j++) {
00818          e = ca.exception_table[j];
00819          e.start_inst = bc.locateInst(e.start_pc);
00820          if (e.end_pc == ca.code_length)
00821             e.end_inst = null;
00822          else
00823             e.end_inst = bc.locateInst(e.end_pc);
00824          e.handler_inst = bc.locateInst(e.handler_pc);
00825          if (e.handler_inst!=null)
00826             e.handler_inst.labelled = true;
00827       }
00828 
00829       return head;
00830    }   
00831    /** Static utility method to parse the given method descriptor string.
00832     * @param s descriptor string.
00833     * @return comma-separated ordered list of parameter types
00834     * @see ClassFile#parseDesc
00835     * @see ClassFile#parseMethodDesc_return
00836     */
00837     static String parseMethodDesc_params(String s) {
00838       int i,j;
00839       i = s.indexOf('(');
00840       if (i>=0) {
00841          j = s.indexOf(')',i+1);
00842          if (j>=0) {
00843             return parseDesc(s.substring(i+1,j),",");
00844          }
00845       }
00846       return "<parse error>";
00847    }   
00848    /** Static utility method to parse the given method descriptor string.
00849     * @param s descriptor string.
00850     * @return return type of method.
00851     * @see ClassFile#parseDesc
00852     * @see ClassFile#parseMethodDesc_params
00853     */
00854     static String parseMethodDesc_return(String s) {
00855       int j;
00856       j = s.lastIndexOf(')');
00857       if (j>=0) {
00858          return parseDesc(s.substring(j+1),",");
00859       }
00860       return parseDesc(s,",");
00861    }   
00862    /** Reads in the given number of attributes from the given stream.
00863     * @param d Stream forming the <tt>.class</tt> file.
00864     * @param attributes_count number of attributes to read in.
00865     * @param ai pre-allocated array of attributes to be filled in.
00866     * @return <i>true</i> if read was successful, <i>false</i> on some error.
00867     * @exception java.io.IOException on error.
00868     */
00869    protected boolean readAttributes(DataInputStream d,int attributes_count,
00870                                     attribute_info[] ai) throws IOException {
00871       attribute_info a=null;
00872       int i;
00873       int j;
00874       long len;
00875       String s;
00876 
00877       for (i=0;i<attributes_count;i++) {
00878          j = d.readUnsignedShort();  // read attribute name before allocating
00879          len = d.readInt() & 0xFFFFFFFFL;
00880          s = ((CONSTANT_Utf8_info)(constant_pool[j])).convert();
00881 
00882          if (s.compareTo(attribute_info.SourceFile)==0) {
00883             SourceFile_attribute sa = new SourceFile_attribute();
00884             sa.sourcefile_index = d.readUnsignedShort();
00885             a = (attribute_info)sa;
00886          } else if(s.compareTo(attribute_info.ConstantValue)==0) {
00887             ConstantValue_attribute ca = new ConstantValue_attribute();
00888             ca.constantvalue_index = d.readUnsignedShort();
00889             a = (attribute_info)ca;
00890          } else if(s.compareTo(attribute_info.Code)==0) {
00891             Code_attribute ca = new Code_attribute();
00892             ca.max_stack = d.readUnsignedShort();
00893             ca.max_locals = d.readUnsignedShort();
00894             ca.code_length = d.readInt() & 0xFFFFFFFFL;
00895             ca.code = new byte[(int) ca.code_length];
00896             d.read(ca.code);
00897             ca.exception_table_length = d.readUnsignedShort();
00898             ca.exception_table = new exception_table_entry[ca.exception_table_length];
00899             int k;
00900             exception_table_entry e;
00901             for (k=0; k<ca.exception_table_length; k++) {
00902                e = new exception_table_entry();
00903                e.start_pc = d.readUnsignedShort();
00904                e.end_pc = d.readUnsignedShort();
00905                e.handler_pc = d.readUnsignedShort();
00906                e.catch_type = d.readUnsignedShort();
00907                ca.exception_table[k] = e;
00908             }
00909             ca.attributes_count = d.readUnsignedShort();
00910             ca.attributes = new attribute_info[ca.attributes_count];
00911             readAttributes(d,ca.attributes_count,ca.attributes);
00912             a = (attribute_info)ca;
00913          } else if(s.compareTo(attribute_info.Exceptions)==0) {
00914             Exception_attribute ea = new Exception_attribute();
00915             ea.number_of_exceptions = d.readUnsignedShort();
00916             if (ea.number_of_exceptions>0) {
00917                int k;
00918                ea.exception_index_table = new int[ea.number_of_exceptions];
00919                for (k=0; k<ea.number_of_exceptions; k++)
00920                   ea.exception_index_table[k]  = d.readUnsignedShort();
00921             }
00922             a = (attribute_info)ea;
00923          } else if(s.compareTo(attribute_info.LineNumberTable)==0) {
00924             LineNumberTable_attribute la = new LineNumberTable_attribute();
00925             la.line_number_table_length = d.readUnsignedShort();
00926             int k;
00927             line_number_table_entry e;
00928             la.line_number_table = new
00929                line_number_table_entry[la.line_number_table_length];
00930             for (k=0; k<la.line_number_table_length; k++) {
00931                e = new line_number_table_entry();
00932                e.start_pc = d.readUnsignedShort();
00933                e.line_number = d.readUnsignedShort();
00934                la.line_number_table[k] = e;
00935             }
00936             a = (attribute_info)la;
00937          } else if(s.compareTo(attribute_info.LocalVariableTable)==0) {
00938             LocalVariableTable_attribute la = new LocalVariableTable_attribute();
00939             la.local_variable_table_length = d.readUnsignedShort();
00940             int k;
00941             local_variable_table_entry e;
00942             la.local_variable_table =
00943                new local_variable_table_entry[la.local_variable_table_length];
00944             for (k=0; k<la.local_variable_table_length; k++) {
00945                e = new local_variable_table_entry();
00946                e.start_pc = d.readUnsignedShort();
00947                e.length = d.readUnsignedShort();
00948                e.name_index = d.readUnsignedShort();
00949                e.descriptor_index = d.readUnsignedShort();
00950                e.index = d.readUnsignedShort();
00951                la.local_variable_table[k] = e;
00952             }
00953             a = (attribute_info)la;
00954          } else {
00955             // unknown attribute
00956             // System.out.println("Generic/Unknown Attribute: " + s);
00957             Generic_attribute ga = new Generic_attribute();
00958             if (len>0) {
00959                ga.info = new byte[(int) len];
00960                d.read(ga.info);
00961             }
00962             a = (attribute_info)ga;
00963          }
00964          a.attribute_name = j;
00965          a.attribute_length = len;
00966          ai[i] = a;
00967       }
00968       return true;
00969    }   
00970    /** Builds the internal representation of this Class by reading in the
00971     * given class file.
00972     * @param d Stream forming the <tt>.class</tt> file.
00973     * @return <i>true</i> if read was successful, <i>false</i> on some error.
00974     */
00975    public boolean readClass(DataInputStream d) {
00976       try {
00977          // first read in magic number
00978          magic = d.readInt() & 0xFFFFFFFFL;
00979          if (magic != MAGIC) {
00980             System.out.println("Wrong magic number in " + fn + ": " + magic);
00981             return false;
00982          }
00983          //System.out.println("Magic number ok");
00984          minor_version = d.readUnsignedShort();
00985          major_version = d.readUnsignedShort();
00986          //System.out.println("Version: " + major_version + "." + minor_version);
00987          constant_pool_count = d.readUnsignedShort();
00988          //System.out.println("Constant pool count: " + constant_pool_count);
00989 
00990          if (!readConstantPool(d))
00991             return false;
00992 
00993          access_flags = d.readUnsignedShort();
00994          //if (access_flags!=0)
00995          //    System.out.println("Access flags: " + access_flags + " = " +
00996          //                   access_string(access_flags,", "));
00997 
00998          this_class = d.readUnsignedShort();
00999          super_class = d.readUnsignedShort();
01000          interfaces_count = d.readUnsignedShort();
01001          if (interfaces_count>0) {
01002             interfaces = new int[interfaces_count];
01003             int j;
01004             for (j=0; j<interfaces_count; j++)
01005                interfaces[j] = d.readUnsignedShort();
01006          }
01007          //System.out.println("Implements " + interfaces_count + " interface(s)");
01008 
01009          fields_count = d.readUnsignedShort();
01010          //System.out.println("Has " + fields_count + " field(s)");
01011          readFields(d);
01012 
01013          methods_count = d.readUnsignedShort();
01014          //System.out.println("Has " + methods_count + " method(s)");
01015          readMethods(d);
01016 
01017          attributes_count = d.readUnsignedShort();
01018          //System.out.println("Has " + attributes_count + " attribute(s)");
01019          if (attributes_count>0) {
01020             attributes =  new attribute_info[attributes_count];
01021             readAttributes(d,attributes_count,attributes);
01022          }
01023       } catch(IOException e) {
01024          throw new RuntimeException("IOException with " + fn + ": " + e.getMessage());
01025       }
01026 
01027       /*inf.fields = fields_count;
01028         inf.methods = methods_count;
01029         inf.cp = constant_pool_count;*/
01030 
01031       return true;
01032    }   
01033    /** Reads in the constant pool from the given stream.
01034     * @param d Stream forming the <tt>.class</tt> file.
01035     * @return <i>true</i> if read was successful, <i>false</i> on some error.
01036     * @exception java.io.IOException on error.
01037     */
01038    protected boolean readConstantPool(DataInputStream d) throws IOException {
01039       byte tag;
01040       cp_info cp;
01041       int i;
01042       boolean skipone;   // set if next cp entry is to be skipped
01043 
01044       constant_pool = new cp_info[constant_pool_count];
01045       //Instruction.constant_pool = constant_pool;
01046       skipone = false;
01047 
01048       for (i=1;i<constant_pool_count;i++) {
01049          if (skipone) {
01050             skipone = false;
01051             continue;
01052          }
01053          tag = (byte)d.readUnsignedByte();
01054          switch(tag) {
01055          case cp_info.CONSTANT_Class:
01056             cp = new CONSTANT_Class_info();
01057             ((CONSTANT_Class_info)cp).name_index = d.readUnsignedShort();
01058             if (debug) System.out.println("Constant pool[" + i + "]: Class");
01059             break;
01060          case cp_info.CONSTANT_Fieldref:
01061             cp = new CONSTANT_Fieldref_info();
01062             ((CONSTANT_Fieldref_info)cp).class_index = d.readUnsignedShort();
01063             ((CONSTANT_Fieldref_info)cp).name_and_type_index =
01064                 d.readUnsignedShort();
01065             if (debug) System.out.println("Constant pool[" + i + "]: Fieldref");
01066             break;
01067          case cp_info.CONSTANT_Methodref:
01068             cp = new CONSTANT_Methodref_info();
01069             ((CONSTANT_Methodref_info)cp).class_index = d.readUnsignedShort();
01070             ((CONSTANT_Methodref_info)cp).name_and_type_index =
01071                d.readUnsignedShort();
01072             if (debug) System.out.println("Constant pool[" + i + "]: Methodref");
01073             break;
01074          case cp_info.CONSTANT_InterfaceMethodref:
01075             cp = new CONSTANT_InterfaceMethodref_info();
01076             ((CONSTANT_InterfaceMethodref_info)cp).class_index =
01077                d.readUnsignedShort();
01078             ((CONSTANT_InterfaceMethodref_info)cp).name_and_type_index =
01079                d.readUnsignedShort();
01080             if (debug)
01081                System.out.println("Constant pool[" + i + "]: InterfaceMethodref");
01082             break;
01083          case cp_info.CONSTANT_String:
01084             cp = new CONSTANT_String_info();
01085             ((CONSTANT_String_info)cp).string_index =
01086                 d.readUnsignedShort();
01087             if (debug) System.out.println("Constant pool[" + i + "]: String");
01088             break;
01089          case cp_info.CONSTANT_Integer:
01090             cp = new CONSTANT_Integer_info();
01091             ((CONSTANT_Integer_info)cp).bytes = d.readInt();
01092             if (debug) System.out.println("Constant pool[" + i + "]: Integer = " +
01093                                           ((CONSTANT_Integer_info)cp).bytes);
01094             break;
01095          case cp_info.CONSTANT_Float:
01096             cp = new CONSTANT_Float_info();
01097             ((CONSTANT_Float_info)cp).bytes = d.readInt();
01098             if (debug) System.out.println("Constant pool[" + i + "]: Float = " +
01099                                           ((CONSTANT_Float_info)cp).convert());
01100             break;
01101          case cp_info.CONSTANT_Long:
01102             cp = new CONSTANT_Long_info();
01103             ((CONSTANT_Long_info)cp).high = d.readInt() & 0xFFFFFFFFL;
01104             ((CONSTANT_Long_info)cp).low = d.readInt() & 0xFFFFFFFFL;
01105             
01106             if (debug) {
01107                String temp = cp.toString(constant_pool);
01108                System.out.println("Constant pool[" + i + "]: Long = " + temp);
01109                /*System.out.println("Constant pool[" + i + "]: that's " +
01110                  cp.printBits(((CONSTANT_Long_info)cp).high) + " <<32 + " +
01111                  cp.printBits(((CONSTANT_Long_info)cp).low) + " = " +
01112                  cp.printBits(((CONSTANT_Long_info)cp).convert()));*/
01113             }
01114             skipone = true;  // next entry needs to be skipped
01115             break;
01116          case cp_info.CONSTANT_Double:
01117             cp = new CONSTANT_Double_info();
01118             ((CONSTANT_Double_info)cp).high = d.readInt() & 0xFFFFFFFFL;
01119             ((CONSTANT_Double_info)cp).low = d.readInt() & 0xFFFFFFFFL;
01120             if (debug) System.out.println("Constant pool[" + i + "]: Double = " +
01121                                           ((CONSTANT_Double_info)cp).convert());
01122             skipone = true;  // next entry needs to be skipped
01123             break;
01124          case cp_info.CONSTANT_NameAndType:
01125             cp = new CONSTANT_NameAndType_info();
01126             ((CONSTANT_NameAndType_info)cp).name_index =
01127                d.readUnsignedShort();
01128             ((CONSTANT_NameAndType_info)cp).descriptor_index =
01129                d.readUnsignedShort();
01130             if (debug) System.out.println("Constant pool[" + i + "]: Name and Type");
01131             break;
01132          case cp_info.CONSTANT_Utf8:
01133             int len;
01134             CONSTANT_Utf8_info cputf8 = new CONSTANT_Utf8_info();
01135             len = d.readUnsignedShort();
01136             cputf8.bytes = new byte[len+2];
01137             cputf8.bytes[0] = (byte)(len>>8);
01138             cputf8.bytes[1] = (byte)(len & 0xff);
01139             if (len>0) {
01140                int j;
01141                for (j=0; j<len;j++)
01142                   cputf8.bytes[j+2] = (byte)d.readUnsignedByte();
01143             }
01144             cp = (cp_info)cputf8;
01145             if (debug)
01146                System.out.println("Constant pool[" + i + "]: Utf8 = \"" +
01147                                   cputf8.convert() + "\"");
01148             break;
01149          default:
01150             System.out.println("Unknown tag in constant pool: " +
01151                                tag + " at entry " + i);
01152             return false;
01153          }
01154          cp.tag = tag;
01155          constant_pool[i] = cp;
01156       }
01157       return true;
01158    }   
01159    /** Reads in the fields from the given stream.
01160     * @param d Stream forming the <tt>.class</tt> file.
01161     * @return <i>true</i> if read was successful, <i>false</i> on some error.
01162     * @exception java.io.IOException on error.
01163     */
01164    protected boolean readFields(DataInputStream d) throws IOException {
01165       field_info fi;
01166       int i;
01167 
01168       fields = new field_info[fields_count];
01169 
01170       for (i=0;i<fields_count;i++) {
01171          fi = new field_info();
01172          fi.access_flags = d.readUnsignedShort();
01173          fi.name_index = d.readUnsignedShort();
01174          fi.descriptor_index = d.readUnsignedShort();
01175          fi.attributes_count = d.readUnsignedShort();
01176          if (fi.attributes_count>0) {
01177             fi.attributes = new attribute_info[fi.attributes_count];
01178             readAttributes(d,fi.attributes_count,fi.attributes);
01179          }
01180          /*CONSTANT_Utf8_info ci;
01181            ci = (CONSTANT_Utf8_info)(constant_pool[fi.name_index]);
01182            System.out.println("Field: " + ci.convert());*/
01183          fields[i] = fi;
01184       }
01185 
01186       return true;
01187    }   
01188    /** Reads in the methods from the given stream.
01189     * @param d Stream forming the <tt>.class</tt> file.
01190     * @return <i>true</i> if read was successful, <i>false</i> on some error.
01191     * @exception java.io.IOException on error.
01192     */
01193    protected boolean readMethods(DataInputStream d) throws IOException {
01194       method_info mi;
01195       int i;
01196 
01197       methods = new method_info[methods_count];
01198 
01199       for (i=0;i<methods_count;i++) {
01200          mi = new method_info();
01201          mi.access_flags = d.readUnsignedShort();
01202          mi.name_index = d.readUnsignedShort();
01203          mi.descriptor_index = d.readUnsignedShort();
01204          mi.attributes_count = d.readUnsignedShort();
01205 
01206          /*CONSTANT_Utf8_info ci;
01207            ci = (CONSTANT_Utf8_info)(constant_pool[mi.name_index]);
01208            System.out.println(" " + access_string(mi.access_flags," ").toLowerCase() +
01209            " " + ci.convert());*/
01210 
01211          if (mi.attributes_count>0) {
01212             mi.attributes = new attribute_info[mi.attributes_count];
01213             readAttributes(d,mi.attributes_count,mi.attributes);
01214          }
01215 
01216          /*if ("main".compareTo(ci.convert())==0) {
01217            decompile(mi);
01218            }*/
01219 
01220          methods[i] = mi;
01221       }
01222 
01223       return true;
01224    }   
01225    /** Recomputes the offset of each Instruction starting from 0;
01226     * used when converting references back to offsets.
01227     * @param i list of Instructions to process.
01228     * @return length of corresponding bytecode.
01229     * @see Instruction#nextOffset
01230     */
01231     int relabel(Instruction i) {
01232       int index = 0;
01233       while (i!=null) {
01234          i.label = index;
01235          index = i.nextOffset(index);
01236          i = i.next;
01237       }
01238       return index;
01239    }   
01240    /** Given the name of a class --- possibly with <tt>.class</tt> after it,
01241     * this answers whether the class might refer to this ClassFile object.
01242     * @return <i>true</i> if it does, <i>false</i> if it doesn't.
01243     */
01244     boolean sameClass(String cfn) {
01245       String s = cfn;
01246       int i = s.lastIndexOf(".class");
01247       if (i>0) {  // has .class after it
01248          s = s.substring(0,i);  // cut off the .class
01249       }
01250       if (s.compareTo(toString())==0)
01251          return true;
01252       return false;
01253    }   
01254    /** Main entry point for writing a class file.
01255     * The file name is given in the constructor; this opens the
01256     * file and writes the internal representation.
01257     * @return <i>true</i> on success.
01258     */
01259     boolean saveClassFile() {
01260       FileOutputStream f;
01261       DataOutputStream d;
01262       boolean b;
01263       try {
01264          f = new FileOutputStream(fn);
01265       } catch(FileNotFoundException e) {
01266          if (fn.indexOf(".class")>=0) {
01267             System.out.println("Can't find " + fn);
01268             return false;
01269          }
01270          fn = fn + ".class";
01271          try {
01272             f = new FileOutputStream(fn);
01273          } catch(FileNotFoundException ee) {
01274             System.out.println("Can't find " + fn);
01275             return false;
01276          } catch(IOException ee) {
01277             System.out.println("IOException with " + fn + ": " + ee.getMessage());
01278             return false;
01279          }
01280       } catch(IOException e) {
01281          System.out.println("IOException with " + fn + ": " + e.getMessage());
01282          return false;
01283       }
01284       d = new DataOutputStream(f);
01285       if (d==null) {
01286          try {
01287             f.close();
01288          } catch(IOException e) { }
01289          return false;
01290       }
01291       b = writeClass(d);
01292       try {
01293          d.close();
01294          f.close();
01295       } catch(IOException e) {
01296          System.out.println("IOException with " + fn + ": " + e.getMessage());
01297          return false;
01298       }
01299       return b;
01300    }   
01301    /** Returns the name of this Class. */
01302    public String toString() {
01303       return (constant_pool[this_class].toString(constant_pool));
01304    }   
01305    /** Inversive to parse, this method calls unparseMethod for each
01306     * method, storing the resulting bytecode in the method's code
01307     * attribute, and recomputing offsets for exception handlers.
01308     * @see ClassFile#unparseMethod
01309     */
01310     void unparse() {
01311       int i,j;
01312       Code_attribute ca;
01313       byte bc[];
01314       method_info mi;
01315       exception_table_entry e;
01316 
01317       for (i=0;i<methods_count;i++) {
01318          mi = methods[i];
01319          // locate code attribute
01320          ca = mi.locate_code_attribute();
01321          if (ca==null) continue;
01322          bc = unparseMethod(mi);
01323          if (bc==null) {
01324             System.out.println("Recompile of " + mi.toName(constant_pool) + " failed!");
01325          } else {
01326             ca.code_length = bc.length;
01327             ca.code = bc;
01328             // also recompile exception table
01329             for (j=0;j<ca.exception_table_length;j++) {
01330                e = ca.exception_table[j];
01331                e.start_pc = (e.start_inst.label);
01332                if (e.end_inst!=null)
01333                   e.end_pc = (e.end_inst.label);
01334                else
01335                   e.end_pc = (int) (ca.code_length);
01336                e.handler_pc = (e.handler_inst.label);
01337             }
01338          }
01339       }
01340    }   
01341    /** Inversive to parseMethod, this converts the list of
01342     * Instructions stored in a method_info object back to an
01343     * array of bytecode.
01344     * @param m method to unparse.
01345     * @return array of bytecode, or <i>null</i> on error.
01346     * @see CFG#reconstructInstructions
01347     * @see ClassFile#parseMethod
01348     * @see ClassFile#relabel
01349     * @see Instruction#compile
01350     */
01351     byte[] unparseMethod(method_info m) {
01352       int codesize;
01353       byte bc[];
01354       Instruction i;
01355 
01356       // Rebuild instruction sequence
01357       m.cfg.reconstructInstructions();
01358 
01359       // relabel instructions and get size of code array
01360       codesize = relabel(m.instructions);
01361 
01362       // construct a new array for the byte-code
01363       bc = new byte[codesize];
01364       if (bc==null) {
01365          System.out.println("Warning: can't allocate memory for recompile");
01366          return null;
01367       }
01368 
01369       // then recompile the instructions into byte-code
01370       i = m.instructions;
01371       codesize = 0;
01372       while (i!=null) {
01373          codesize = i.compile(bc,codesize);
01374          i = i.next;
01375       }
01376       if (codesize != bc.length)
01377          System.out.println("Warning: code size doesn't match array length!");
01378 
01379       return bc;
01380    }   
01381    /** Writes the given array of attributes to the given stream.
01382     * @param dd output stream.
01383     * @param attributes_count number of attributes to write.
01384     * @param ai array of attributes to write.
01385     * @return <i>true</i> if write was successful, <i>false</i> on some error.
01386     * @exception java.io.IOException on error.
01387     */
01388    protected boolean writeAttributes(DataOutputStream dd, int attributes_count,
01389                                      attribute_info[] ai) throws IOException {
01390       attribute_info a=null;
01391       int i,len;
01392       short j;
01393       String s;
01394 
01395       for (i=0;i<attributes_count;i++) {
01396          a = ai[i];
01397          dd.writeShort(a.attribute_name);
01398          dd.writeInt((int) a.attribute_length);
01399          if (a instanceof SourceFile_attribute) {
01400             SourceFile_attribute sa = (SourceFile_attribute)a;
01401             dd.writeShort(sa.sourcefile_index);
01402          } else if(a instanceof ConstantValue_attribute) {
01403             ConstantValue_attribute ca = (ConstantValue_attribute)a;
01404             dd.writeShort(ca.constantvalue_index);
01405          } else if(a instanceof Code_attribute) {
01406             Code_attribute ca = (Code_attribute)a;
01407             dd.writeShort(ca.max_stack);
01408             dd.writeShort(ca.max_locals);
01409             dd.writeInt((int) ca.code_length);
01410             dd.write(ca.code,0, (int) ca.code_length);
01411             dd.writeShort(ca.exception_table_length);
01412             int k;
01413             exception_table_entry e;
01414             for (k=0; k<ca.exception_table_length; k++) {
01415                e = ca.exception_table[k];
01416                dd.writeShort(e.start_pc);
01417                dd.writeShort(e.end_pc);
01418                dd.writeShort(e.handler_pc);
01419                dd.writeShort(e.catch_type);
01420             }
01421             dd.writeShort(ca.attributes_count);
01422             if (ca.attributes_count>0)
01423                writeAttributes(dd,ca.attributes_count,ca.attributes);
01424          } else if(a instanceof Exception_attribute) {
01425             Exception_attribute ea = (Exception_attribute)a;
01426             dd.writeShort(ea.number_of_exceptions);
01427             if (ea.number_of_exceptions>0) {
01428                int k;
01429                for (k=0; k<ea.number_of_exceptions; k++)
01430                   dd.writeShort(ea.exception_index_table[k]);
01431             }
01432          } else if(a instanceof LineNumberTable_attribute) {
01433             LineNumberTable_attribute la = (LineNumberTable_attribute)a;
01434             dd.writeShort(la.line_number_table_length);
01435             int k;
01436             line_number_table_entry e;
01437             for (k=0; k<la.line_number_table_length; k++) {
01438                e = la.line_number_table[k];
01439                dd.writeShort(e.start_pc);
01440                dd.writeShort(e.line_number);
01441             }
01442          } else if(a instanceof LocalVariableTable_attribute) {
01443             LocalVariableTable_attribute la = (LocalVariableTable_attribute)a;
01444             dd.writeShort(la.local_variable_table_length);
01445             int k;
01446             local_variable_table_entry e;
01447             for (k=0; k<la.local_variable_table_length; k++) {
01448                e = la.local_variable_table[k];
01449                dd.writeShort(e.start_pc);
01450                dd.writeShort(e.length);
01451                dd.writeShort(e.name_index);
01452                dd.writeShort(e.descriptor_index);
01453                dd.writeShort(e.index);
01454             }
01455          } else {
01456             // unknown attribute
01457             System.out.println("Generic/Unknown Attribute in output");
01458             Generic_attribute ga = (Generic_attribute)a;
01459             if (ga.attribute_length>0) {
01460                dd.write(ga.info,0,(int) ga.attribute_length);
01461             }
01462          }
01463       }
01464       return true;
01465    }   
01466    /** Writes this entire ClassFile object to the given stream.
01467     * @param dd output stream.
01468     * @return <i>true</i> if write was successful, <i>false</i> on some error.
01469     */
01470     boolean writeClass(DataOutputStream dd) {
01471       // outputs the .class file from the loaded one
01472       try {
01473          // first write magic number
01474          dd.writeInt((int) magic);
01475 
01476          dd.writeShort(minor_version);
01477          dd.writeShort(major_version);
01478          dd.writeShort(constant_pool_count);
01479 
01480          if (!writeConstantPool(dd))
01481             return false;
01482 
01483          dd.writeShort(access_flags);
01484          dd.writeShort(this_class);
01485          dd.writeShort(super_class);
01486          dd.writeShort(interfaces_count);
01487          if (interfaces_count>0) {
01488             int j;
01489             for (j=0; j<interfaces_count; j++)
01490                dd.writeShort(interfaces[j]);
01491          }
01492 
01493          dd.writeShort(fields_count);
01494          writeFields(dd);
01495 
01496          dd.writeShort(methods_count);
01497          writeMethods(dd);
01498 
01499          dd.writeShort(attributes_count);
01500          if (attributes_count>0) {
01501             writeAttributes(dd,attributes_count,attributes);
01502          }
01503       } catch(IOException e) {
01504          System.out.println("IOException with " + fn + ": " + e.getMessage());
01505          return false;
01506       }
01507       return true;
01508    }   
01509    /* DEPRECATED
01510       public void showByteCode(Code_attribute ca) {
01511       int i=0,j;
01512 
01513       System.out.println("Code bytes follow...");
01514       while(i<ca.code_length) {
01515       j = (int)(ca.code[i]);
01516       j &= 0xff;
01517       System.out.print(Integer.toString(j) + " ");
01518       i++;
01519       }
01520       System.out.println("");
01521       }*/
01522 
01523    /** Writes the current constant pool to the given stream.
01524     * @param dd output stream.
01525     * @return <i>true</i> if write was successful, <i>false</i> on some error.
01526     * @exception java.io.IOException on error.
01527     */
01528    protected boolean writeConstantPool(DataOutputStream dd) throws IOException {
01529       byte tag;
01530       cp_info cp;
01531       int i;
01532       boolean skipone = false;
01533 
01534       for (i=1;i<constant_pool_count;i++) {
01535          if (skipone) {
01536             skipone = false;
01537             continue;
01538          }
01539          cp = constant_pool[i];
01540          dd.writeByte(cp.tag);
01541          switch(cp.tag) {
01542          case cp_info.CONSTANT_Class:
01543             dd.writeShort(((CONSTANT_Class_info)cp).name_index);
01544             break;
01545          case cp_info.CONSTANT_Fieldref:
01546             dd.writeShort(((CONSTANT_Fieldref_info)cp).class_index);
01547             dd.writeShort(((CONSTANT_Fieldref_info)cp).name_and_type_index);
01548             break;
01549          case cp_info.CONSTANT_Methodref:
01550             dd.writeShort(((CONSTANT_Methodref_info)cp).class_index);
01551             dd.writeShort(((CONSTANT_Methodref_info)cp).name_and_type_index);
01552             break;
01553          case cp_info.CONSTANT_InterfaceMethodref:
01554             dd.writeShort(((CONSTANT_InterfaceMethodref_info)cp).class_index);
01555             dd.writeShort(((CONSTANT_InterfaceMethodref_info)cp).name_and_type_index);
01556             break;
01557          case cp_info.CONSTANT_String:
01558             dd.writeShort(((CONSTANT_String_info)cp).string_index);
01559             break;
01560          case cp_info.CONSTANT_Integer:
01561             dd.writeInt((int) ((CONSTANT_Integer_info)cp).bytes);
01562             break;
01563          case cp_info.CONSTANT_Float:
01564             dd.writeInt((int) ((CONSTANT_Float_info)cp).bytes);
01565             break;
01566          case cp_info.CONSTANT_Long:
01567             dd.writeInt((int) ((CONSTANT_Long_info)cp).high);
01568             dd.writeInt((int) ((CONSTANT_Long_info)cp).low);
01569             skipone = true;
01570             break;
01571          case cp_info.CONSTANT_Double:
01572             dd.writeInt((int) ((CONSTANT_Double_info)cp).high);
01573             dd.writeInt((int) ((CONSTANT_Double_info)cp).low);
01574             skipone = true;
01575             break;
01576          case cp_info.CONSTANT_NameAndType:
01577             dd.writeShort(((CONSTANT_NameAndType_info)cp).name_index);
01578             dd.writeShort(((CONSTANT_NameAndType_info)cp).descriptor_index);
01579             break;
01580          case cp_info.CONSTANT_Utf8:
01581             int len;
01582             len = ((CONSTANT_Utf8_info)cp).bytes.length;
01583             dd.writeShort(len-2);
01584             dd.write(((CONSTANT_Utf8_info)cp).bytes,2,len-2);
01585             break;
01586          default:
01587             System.out.println("Unknown tag in constant pool: " + cp.tag);
01588             return false;
01589          }
01590       }
01591       return true;
01592    }   
01593    /** Writes the fields to the given stream.
01594     * @param dd output stream.
01595     * @return <i>true</i> if write was successful, <i>false</i> on some error.
01596     * @exception java.io.IOException on error.
01597     */
01598    protected boolean writeFields(DataOutputStream dd) throws IOException {
01599       field_info fi;
01600       int i;
01601 
01602       for (i=0;i<fields_count;i++) {
01603          fi = fields[i];
01604          dd.writeShort(fi.access_flags);
01605          dd.writeShort(fi.name_index);
01606          dd.writeShort(fi.descriptor_index);
01607          dd.writeShort(fi.attributes_count);
01608          if (fi.attributes_count>0) {
01609             writeAttributes(dd,fi.attributes_count,fi.attributes);
01610          }
01611       }
01612       return true;
01613    }   
01614    /** Writes the methods to the given stream.
01615     * @param dd output stream.
01616     * @return <i>true</i> if write was successful, <i>false</i> on some error.
01617     * @exception java.io.IOException on error.
01618     */
01619    protected boolean writeMethods(DataOutputStream dd) throws IOException {
01620       method_info mi;
01621       int i;
01622 
01623       for (i=0;i<methods_count;i++) {
01624          mi = methods[i];
01625          dd.writeShort(mi.access_flags);
01626          dd.writeShort(mi.name_index);
01627          dd.writeShort(mi.descriptor_index);
01628          dd.writeShort(mi.attributes_count);
01629          if (mi.attributes_count>0) {
01630             writeAttributes(dd,mi.attributes_count,mi.attributes);
01631          }
01632       }
01633       return true;
01634    }   
01635 }

Generated at Thu Feb 7 06:42:15 2002 for Bandera by doxygen1.2.10 written by Dimitri van Heesch, © 1997-2001