Fields Summary |
---|
private static final int | CLASS_FILE_MAGICthe expected value of the ClassFile.magic field |
private static final int | CLASS_FILE_MIN_MAJOR_VERSIONminimum .class file major version
The class file definition (vmspec/2nd-edition) says:
"Implementations of version 1.2 of the
Java 2 platform can support class file
formats of versions in the range 45.0
through 46.0 inclusive."
The class files generated by the build are currently
(as of 11/2006) reporting version 49.0 (0x31.0x00),
however, so we use that as our upper bound.
Valid ranges are typically of the form
"A.0 through B.C inclusive" where A <= B and C >= 0,
which is why we don't have a CLASS_FILE_MIN_MINOR_VERSION. |
private static final int | CLASS_FILE_MAX_MAJOR_VERSIONmaximum .class file major version |
private static final int | CLASS_FILE_MAX_MINOR_VERSIONmaximum .class file minor version |
private final String | filePathnon-null; the file path for the class, excluding any base directory
specification |
private final com.android.dx.util.ByteArray | bytesnon-null; the bytes of the file |
private final boolean | strictParsewhether to be strict about parsing; if
false , this avoids doing checks that only exist
for purposes of verification (such as magic number matching and
path-package consistency checking) |
private com.android.dx.rop.cst.StdConstantPool | poolnull-ok; the constant pool; only ever null
before the constant pool is successfully parsed |
private int | accessFlagsthe class file field access_flags ; will be -1
before the file is successfully parsed |
private com.android.dx.rop.cst.CstType | thisClassnull-ok; the class file field this_class ,
interpreted as a type constant; only ever null
before the file is successfully parsed |
private com.android.dx.rop.cst.CstType | superClassnull-ok; the class file field super_class , interpreted
as a type constant if non-zero |
private com.android.dx.rop.type.TypeList | interfacesnull-ok; the class file field interfaces ; only
ever null before the file is successfully
parsed |
private com.android.dx.cf.iface.FieldList | fieldsnull-ok; the class file field fields ; only ever
null before the file is successfully parsed |
private com.android.dx.cf.iface.MethodList | methodsnull-ok; the class file field methods ; only ever
null before the file is successfully parsed |
private com.android.dx.cf.iface.StdAttributeList | attributesnull-ok; the class file field attributes ; only
ever null before the file is successfully
parsed |
private AttributeFactory | attributeFactorynull-ok; attribute factory, if any |
private com.android.dx.cf.iface.ParseObserver | observernull-ok; parse observer, if any |
Methods Summary |
---|
public int | getAccessFlags(){@inheritDoc}
parseToInterfacesIfNecessary();
return accessFlags;
|
public com.android.dx.cf.iface.AttributeList | getAttributes(){@inheritDoc}
parseToEndIfNecessary();
return attributes;
|
public com.android.dx.util.ByteArray | getBytes()Gets the {@link ByteArray} that this instance's data comes from.
return bytes;
|
public com.android.dx.rop.cst.ConstantPool | getConstantPool(){@inheritDoc}
parseToInterfacesIfNecessary();
return pool;
|
public com.android.dx.cf.iface.FieldList | getFields(){@inheritDoc}
parseToEndIfNecessary();
return fields;
|
public com.android.dx.rop.type.TypeList | getInterfaces(){@inheritDoc}
parseToInterfacesIfNecessary();
return interfaces;
|
public int | getMagic(){@inheritDoc}
parseToInterfacesIfNecessary();
return getMagic0();
|
public int | getMagic0()Gets the class file field magic , but without doing any
checks or parsing first.
return bytes.getInt(0);
|
public int | getMajorVersion(){@inheritDoc}
parseToInterfacesIfNecessary();
return getMajorVersion0();
|
public int | getMajorVersion0()Gets the class file field major_version , but
without doing any checks or parsing first.
return bytes.getUnsignedShort(6);
|
public com.android.dx.cf.iface.MethodList | getMethods(){@inheritDoc}
parseToEndIfNecessary();
return methods;
|
public int | getMinorVersion(){@inheritDoc}
parseToInterfacesIfNecessary();
return getMinorVersion0();
|
public int | getMinorVersion0()Gets the class file field minor_version , but
without doing any checks or parsing first.
return bytes.getUnsignedShort(4);
|
public com.android.dx.rop.cst.CstUtf8 | getSourceFile(){@inheritDoc}
AttributeList attribs = getAttributes();
Attribute attSf = attribs.findFirst(AttSourceFile.ATTRIBUTE_NAME);
if (attSf instanceof AttSourceFile) {
return ((AttSourceFile) attSf).getSourceFile();
}
return null;
|
public com.android.dx.rop.cst.CstType | getSuperclass(){@inheritDoc}
parseToInterfacesIfNecessary();
return superClass;
|
public com.android.dx.rop.cst.CstType | getThisClass(){@inheritDoc}
parseToInterfacesIfNecessary();
return thisClass;
|
private boolean | isGoodVersion(int magic, int minorVersion, int majorVersion)Sees if the .class file header magic/version are within
range.
/* Valid version ranges are typically of the form
* "A.0 through B.C inclusive" where A <= B and C >= 0,
* which is why we don't have a CLASS_FILE_MIN_MINOR_VERSION.
*/
if (magic == CLASS_FILE_MAGIC && minorVersion >= 0) {
/* Check against max first to handle the case where
* MIN_MAJOR == MAX_MAJOR.
*/
if (majorVersion == CLASS_FILE_MAX_MAJOR_VERSION) {
if (minorVersion <= CLASS_FILE_MAX_MINOR_VERSION) {
return true;
}
} else if (majorVersion < CLASS_FILE_MAX_MAJOR_VERSION &&
majorVersion >= CLASS_FILE_MIN_MAJOR_VERSION) {
return true;
}
}
return false;
|
public com.android.dx.rop.type.TypeList | makeTypeList(int offset, int size)Constructs and returns an instance of {@link TypeList} whose
data comes from the bytes of this instance, interpreted as a
list of constant pool indices for classes, which are in turn
translated to type constants. Instance construction will fail
if any of the (alleged) indices turn out not to refer to
constant pool entries of type Class .
if (size == 0) {
return StdTypeList.EMPTY;
}
if (pool == null) {
throw new IllegalStateException("pool not yet initialized");
}
return new DcfTypeList(bytes, offset, size, pool, observer);
|
private void | parse()Does the parsing, handing exceptions.
try {
parse0();
} catch (ParseException ex) {
ex.addContext("...while parsing " + filePath);
throw ex;
} catch (RuntimeException ex) {
ParseException pe = new ParseException(ex);
pe.addContext("...while parsing " + filePath);
throw pe;
}
|
private void | parse0()Does the actual parsing.
if (bytes.size() < 10) {
throw new ParseException("severely truncated class file");
}
if (observer != null) {
observer.parsed(bytes, 0, 0, "begin classfile");
observer.parsed(bytes, 0, 4, "magic: " + Hex.u4(getMagic0()));
observer.parsed(bytes, 4, 2,
"minor_version: " + Hex.u2(getMinorVersion0()));
observer.parsed(bytes, 6, 2,
"major_version: " + Hex.u2(getMajorVersion0()));
}
if (strictParse) {
/* Make sure that this looks like a valid class file with a
* version that we can handle.
*/
if (!isGoodVersion(getMagic0(), getMinorVersion0(),
getMajorVersion0())) {
throw new ParseException("bad class file magic (" +
Hex.u4(getMagic0()) +
") or version (" +
Hex.u2(getMajorVersion0()) + "." +
Hex.u2(getMinorVersion0()) + ")");
}
}
ConstantPoolParser cpParser = new ConstantPoolParser(bytes);
cpParser.setObserver(observer);
pool = cpParser.getPool();
pool.setImmutable();
int at = cpParser.getEndOffset();
int accessFlags = bytes.getUnsignedShort(at); // u2 access_flags;
int cpi = bytes.getUnsignedShort(at + 2); // u2 this_class;
thisClass = (CstType) pool.get(cpi);
cpi = bytes.getUnsignedShort(at + 4); // u2 super_class;
superClass = (CstType) pool.get0Ok(cpi);
int count = bytes.getUnsignedShort(at + 6); // u2 interfaces_count
if (observer != null) {
observer.parsed(bytes, at, 2,
"access_flags: " +
AccessFlags.classString(accessFlags));
observer.parsed(bytes, at + 2, 2, "this_class: " + thisClass);
observer.parsed(bytes, at + 4, 2, "super_class: " +
stringOrNone(superClass));
observer.parsed(bytes, at + 6, 2,
"interfaces_count: " + Hex.u2(count));
if (count != 0) {
observer.parsed(bytes, at + 8, 0, "interfaces:");
}
}
at += 8;
interfaces = makeTypeList(at, count);
at += count * 2;
if (strictParse) {
/*
* Make sure that the file/jar path matches the declared
* package/class name.
*/
String thisClassName = thisClass.getClassType().getClassName();
if (!(filePath.endsWith(".class") &&
filePath.startsWith(thisClassName) &&
(filePath.length() == (thisClassName.length() + 6)))) {
throw new ParseException("class name (" + thisClassName +
") does not match path (" +
filePath + ")");
}
}
/*
* Only set the instance variable accessFlags here, since
* that's what signals a successful parse of the first part of
* the file (through the interfaces list).
*/
this.accessFlags = accessFlags;
FieldListParser flParser =
new FieldListParser(this, thisClass, at, attributeFactory);
flParser.setObserver(observer);
fields = flParser.getList();
at = flParser.getEndOffset();
MethodListParser mlParser =
new MethodListParser(this, thisClass, at, attributeFactory);
mlParser.setObserver(observer);
methods = mlParser.getList();
at = mlParser.getEndOffset();
AttributeListParser alParser =
new AttributeListParser(this, AttributeFactory.CTX_CLASS, at,
attributeFactory);
alParser.setObserver(observer);
attributes = alParser.getList();
attributes.setImmutable();
at = alParser.getEndOffset();
if (at != bytes.size()) {
throw new ParseException("extra bytes at end of class file, " +
"at offset " + Hex.u4(at));
}
if (observer != null) {
observer.parsed(bytes, at, 0, "end classfile");
}
|
private void | parseToEndIfNecessary()Runs {@link #parse} if it has not yet been run successfully.
if (attributes == null) {
parse();
}
|
private void | parseToInterfacesIfNecessary()Runs {@link #parse} if it has not yet been run to cover up to
the interfaces list.
if (accessFlags == -1) {
parse();
}
|
public void | setAttributeFactory(AttributeFactory attributeFactory)Sets the attribute factory to use.
if (attributeFactory == null) {
throw new NullPointerException("attributeFactory == null");
}
this.attributeFactory = attributeFactory;
|
public void | setObserver(com.android.dx.cf.iface.ParseObserver observer)Sets the parse observer for this instance.
this.observer = observer;
|
public static java.lang.String | stringOrNone(java.lang.Object obj)Returns the string form of an object or "(none)"
(rather than "null" ) for null .
if (obj == null) {
return "(none)";
}
return obj.toString();
|