Brought to you by EarthWeb
ITKnowledge Logo Login Graphic Click to go to the Oscars.
Click to go to the Oscars.
ITKnowledge
Find:
 
EXPERT SEARCH ----- nav

EarthWeb Direct

EarthWeb sites: other sites

Previous Table of Contents Next


The 2-byte unsigned short immediately following the access flags is the name index—that is, an index into the constant pool that provides the field name’s location.

Next comes the descriptor index, another 2-byte unsigned short index into the constant pool. This points to a UTF8 structure, which represents a field descriptor.

Next comes the attributes table for this field. You read this by passing the DataInputStream into the AttributeTable constructor. Listing 4-22 is the full FieldInfo class.

Listing 4-22 The FieldInfo class

   import java.io.*;

   public class FieldInfo {

    int accessflags;
    int nameIndex;
    int descriptorIndex;
    AttributeInfo[] attributes;

    public final static int cPublic = 0x0001;
    public final static int cPrivate = 0x0002;
    public final static int cProtected = 0x0004;
    public final static int cStatic = 0x0008;
    public final static int cFinal = 0x0010;
    public final static int cVolatile = 0x0040;
    public final static int cTransient = 0x0080;

    public FieldInfo( DataInputStream dis) throws IOException {
     accessflags = dis.readUnsignedShort();
     nameIndex = dis.readUnsignedShort();
     descriptorIndex = dis.readUnsignedShort();
     attributes = new AttributeInfo[dis.readUnsignedShort()];
     for (int i = 0; i < attributes.length; i++) {
      attributes[i] = new AttributeInfo(dis);
     }

    }

    public int nameIndex() {
     return nameIndex;
    }

    public int descriptorIndex() {
     return descriptorIndex;
    }

    public boolean isPublic() {
     return (accessflags & cPublic) != 0;
    }

    public boolean isPrivate() {
     return (accessflags & cPrivate) != 0;
    }

    public boolean isProtected() {
     return (accessflags & cProtected) != 0;
    }

    public boolean isStatic() {
     return (accessflags & cStatic) != 0;
    }

    public boolean isVolatile() {
     return (accessflags & cVolatile) != 0;
    }

    public boolean isTransient() {
     return (accessflags & cTransient) != 0;
    }

    public boolean isFinal() {
     return (accessflags & cFinal) != 0;
    }

   }

Here’s the fleshed-out readFields() method for the Disassembler class. It’s quite simple, because all the work goes on inside the FieldInfo class.

   FieldInfo[] fields;

    void readFields() throws IOException {
     fields = new FieldInfo[theInput.readUnsignedShort()];
     for (int i = 0; i < fields.length; i++) {
      fields[i] = new FieldInfo[dis];
     }
    }

Methods

The methods table is similar to the fields table. First, there’s an unsigned short to tell you how many methods there are. Then there’s an array of method_info structures. As with the FieldInfo structure, this program keeps all the intelligence inside the MethodInfo constructor. Listing 4-23 is the fleshed-out readMethods() method for the Disassembler class.

Listing 4-23 readMethods()

   MethodInfo[] methods;

   void readMethods() throws IOException {
    methods = new MethodInfo[theInput.readUnsignedShort()];
    for (int i = 0; i < methods.length; i++) {
     methods[i] = new MethodInfo[dis];
    }
   }

The MethodInfo structure is almost identical to a FieldInfo structure. In fact, the only difference is in the permitted values for the access flags and the meaning of the attributes. Listing 4-24 is the MethodInfo class.

Listing 4-24 The MethodInfo class

   import java.io.*;

   public class MethodInfo {
    int accessflags;
    int nameIndex;
    int descriptorIndex;
    AttributeInfo[] attributes;

    public final static int cPublic = 0x0001;
    public final static int cPrivate = 0x0002;
    public final static int cProtected = 0x0004;
    public final static int cStatic = 0x0008;
    public final static int cFinal = 0x0010;
    public final static int cSynchronized = 0x0020;
    public final static int cNative = 0x0100;
    public final static int cAbstract = 0x0400;

    public MethodInfo (DataInputStream dis) throws IOException {
     accessflags = dis.readUnsignedShort();
     nameIndex = dis.readUnsignedShort();
     descriptorIndex = dis.readUnsignedShort();
     attributes = new AttributeInfo[dis.readUnsignedShort()];
     for (int i = 0; i < attributes.length; i++) {
      attributes[i] = new AttributeInfo(dis);
     }

    }

    public int nameIndex() {
     return nameIndex;
    }

    public int descriptorIndex() {
     return descriptorIndex;
    }

    public boolean isPublic() {
     return (accessflags & cPublic) != 0;
    }

    public boolean isPrivate() {
     return (accessflags & cPrivate) != 0;
    }

    public boolean isProtected() {
     return (accessflags & cProtected) != 0;
    }

    public boolean isStatic() {
     return (accessflags & cStatic) != 0;
    }

    public boolean isSynchronized() {
     return (accessflags & cSynchronized) != 0;
    }

    public boolean isNative() {
     return (accessflags & cNative) != 0;
    }

    public boolean isAbstract() {
     return (accessflags & cAbstract) != 0;
    }

    public AttributeInfo[] getAttributes() {
     return attributes;
    }

    public String toString() {
     return “NameIndex: “ + nameIndex + “;\tDescriptorIndex: “ + descriptorIndex;
    }

   }

Putting It All Together

Now that the entire .class file has been read into memory and parsed, it can be output as more-or-less-legible source code. You do not need to output items in the order in which they appeared in the .class file. For example, the first thing outputted will be any import statements in the file. Then you’ll produce the access specifiers for the class and then the class name itself, followed by any interfaces that the class implements. Next come the fields, and then the methods. Along the way, you’ll add in necessary syntax — such as semicolons and keywords — that is normally present in source code but is not included in byte code.

To do this, the Disassembler class needs for eight more methods to be filled out:

   writeImports();
   writeAccess();
   writeClassName();
   writeInterfaces();
   writeFields();
   writeMethods();

Each of these methods will parse the data structures read in the first part of this chapter to collect the needed information.


Previous Table of Contents Next
HomeAbout UsSearchSubscribeAdvertising InfoContact UsFAQs
Use of this site is subject to certain Terms & Conditions.
Copyright (c) 1996-1999 EarthWeb Inc. All rights reserved. Reproduction in whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.