int constantPoolCount;
int[] constantPoolOffsets;
try {
this.magicNumber = (int) u4At(classFileBytes, 0, 0);
if (this.magicNumber != 0xCAFEBABE) {
throw new ClassFormatException(ClassFormatException.INVALID_MAGIC_NUMBER);
}
int readOffset = 10;
this.minorVersion = this.u2At(classFileBytes, 4, 0);
this.majorVersion = this.u2At(classFileBytes, 6, 0);
if ((decodingFlags & IClassFileReader.CONSTANT_POOL) == 0) {
// no need to go further
return;
}
constantPoolCount = this.u2At(classFileBytes, 8, 0);
// Pass #1 - Fill in all primitive constants
constantPoolOffsets = new int[constantPoolCount];
for (int i = 1; i < constantPoolCount; i++) {
int tag = this.u1At(classFileBytes, readOffset, 0);
switch (tag) {
case IConstantPoolConstant.CONSTANT_Utf8 :
constantPoolOffsets[i] = readOffset;
readOffset += u2At(classFileBytes, readOffset + 1, 0);
readOffset += IConstantPoolConstant.CONSTANT_Utf8_SIZE;
break;
case IConstantPoolConstant.CONSTANT_Integer :
constantPoolOffsets[i] = readOffset;
readOffset += IConstantPoolConstant.CONSTANT_Integer_SIZE;
break;
case IConstantPoolConstant.CONSTANT_Float :
constantPoolOffsets[i] = readOffset;
readOffset += IConstantPoolConstant.CONSTANT_Float_SIZE;
break;
case IConstantPoolConstant.CONSTANT_Long :
constantPoolOffsets[i] = readOffset;
readOffset += IConstantPoolConstant.CONSTANT_Long_SIZE;
i++;
break;
case IConstantPoolConstant.CONSTANT_Double :
constantPoolOffsets[i] = readOffset;
readOffset += IConstantPoolConstant.CONSTANT_Double_SIZE;
i++;
break;
case IConstantPoolConstant.CONSTANT_Class :
constantPoolOffsets[i] = readOffset;
readOffset += IConstantPoolConstant.CONSTANT_Class_SIZE;
break;
case IConstantPoolConstant.CONSTANT_String :
constantPoolOffsets[i] = readOffset;
readOffset += IConstantPoolConstant.CONSTANT_String_SIZE;
break;
case IConstantPoolConstant.CONSTANT_Fieldref :
constantPoolOffsets[i] = readOffset;
readOffset += IConstantPoolConstant.CONSTANT_Fieldref_SIZE;
break;
case IConstantPoolConstant.CONSTANT_Methodref :
constantPoolOffsets[i] = readOffset;
readOffset += IConstantPoolConstant.CONSTANT_Methodref_SIZE;
break;
case IConstantPoolConstant.CONSTANT_InterfaceMethodref :
constantPoolOffsets[i] = readOffset;
readOffset += IConstantPoolConstant.CONSTANT_InterfaceMethodref_SIZE;
break;
case IConstantPoolConstant.CONSTANT_NameAndType :
constantPoolOffsets[i] = readOffset;
readOffset += IConstantPoolConstant.CONSTANT_NameAndType_SIZE;
break;
default:
throw new ClassFormatException(ClassFormatException.INVALID_TAG_CONSTANT);
}
}
this.constantPool = new ConstantPool(classFileBytes, constantPoolOffsets);
// Read and validate access flags
this.accessFlags = u2At(classFileBytes, readOffset, 0);
readOffset += 2;
// Read the classname, use exception handlers to catch bad format
this.classNameIndex = u2At(classFileBytes, readOffset, 0);
this.className = getConstantClassNameAt(classFileBytes, constantPoolOffsets, this.classNameIndex);
readOffset += 2;
// Read the superclass name, can be zero for java.lang.Object
this.superclassNameIndex = u2At(classFileBytes, readOffset, 0);
readOffset += 2;
// if superclassNameIndex is equals to 0 there is no need to set a value for the
// field this.superclassName. null is fine.
if (superclassNameIndex != 0) {
this.superclassName = getConstantClassNameAt(classFileBytes, constantPoolOffsets, this.superclassNameIndex);
}
// Read the interfaces, use exception handlers to catch bad format
this.interfacesCount = u2At(classFileBytes, readOffset, 0);
readOffset += 2;
this.interfaceNames = NO_INTERFACES_NAMES;
this.interfaceIndexes = Util.EMPTY_INT_ARRAY;
if (this.interfacesCount != 0) {
if ((decodingFlags & IClassFileReader.SUPER_INTERFACES) != IClassFileReader.CONSTANT_POOL) {
this.interfaceNames = new char[this.interfacesCount][];
this.interfaceIndexes = new int[this.interfacesCount];
for (int i = 0; i < this.interfacesCount; i++) {
this.interfaceIndexes[i] = u2At(classFileBytes, readOffset, 0);
this.interfaceNames[i] = getConstantClassNameAt(classFileBytes, constantPoolOffsets, this.interfaceIndexes[i]);
readOffset += 2;
}
} else {
readOffset += (2 * this.interfacesCount);
}
}
// Read the this.fields, use exception handlers to catch bad format
this.fieldsCount = u2At(classFileBytes, readOffset, 0);
readOffset += 2;
this.fields = NO_FIELD_INFOS;
if (this.fieldsCount != 0) {
if ((decodingFlags & IClassFileReader.FIELD_INFOS) != IClassFileReader.CONSTANT_POOL) {
FieldInfo field;
this.fields = new FieldInfo[this.fieldsCount];
for (int i = 0; i < this.fieldsCount; i++) {
field = new FieldInfo(classFileBytes, this.constantPool, readOffset);
this.fields[i] = field;
readOffset += field.sizeInBytes();
}
} else {
for (int i = 0; i < this.fieldsCount; i++) {
int attributeCountForField = u2At(classFileBytes, 6, readOffset);
readOffset += 8;
if (attributeCountForField != 0) {
for (int j = 0; j < attributeCountForField; j++) {
int attributeLength = (int) u4At(classFileBytes, 2, readOffset);
readOffset += (6 + attributeLength);
}
}
}
}
}
// Read the this.methods
this.methodsCount = u2At(classFileBytes, readOffset, 0);
readOffset += 2;
this.methods = NO_METHOD_INFOS;
if (this.methodsCount != 0) {
if ((decodingFlags & IClassFileReader.METHOD_INFOS) != IClassFileReader.CONSTANT_POOL) {
this.methods = new MethodInfo[this.methodsCount];
MethodInfo method;
for (int i = 0; i < this.methodsCount; i++) {
method = new MethodInfo(classFileBytes, this.constantPool, readOffset, decodingFlags);
this.methods[i] = method;
readOffset += method.sizeInBytes();
}
} else {
for (int i = 0; i < this.methodsCount; i++) {
int attributeCountForMethod = u2At(classFileBytes, 6, readOffset);
readOffset += 8;
if (attributeCountForMethod != 0) {
for (int j = 0; j < attributeCountForMethod; j++) {
int attributeLength = (int) u4At(classFileBytes, 2, readOffset);
readOffset += (6 + attributeLength);
}
}
}
}
}
// Read the attributes
this.attributesCount = u2At(classFileBytes, readOffset, 0);
readOffset += 2;
int attributesIndex = 0;
this.attributes = ClassFileAttribute.NO_ATTRIBUTES;
if (this.attributesCount != 0) {
if ((decodingFlags & IClassFileReader.CLASSFILE_ATTRIBUTES) != IClassFileReader.CONSTANT_POOL) {
this.attributes = new IClassFileAttribute[this.attributesCount];
for (int i = 0; i < attributesCount; i++) {
int utf8Offset = constantPoolOffsets[u2At(classFileBytes, readOffset, 0)];
char[] attributeName = utf8At(classFileBytes, utf8Offset + 3, 0, u2At(classFileBytes, utf8Offset + 1, 0));
if (equals(attributeName, IAttributeNamesConstants.INNER_CLASSES)) {
this.innerClassesAttribute = new InnerClassesAttribute(classFileBytes, this.constantPool, readOffset);
this.attributes[attributesIndex++] = this.innerClassesAttribute;
} else if (equals(attributeName, IAttributeNamesConstants.SOURCE)) {
this.sourceFileAttribute = new SourceFileAttribute(classFileBytes, this.constantPool, readOffset);
this.attributes[attributesIndex++] = this.sourceFileAttribute;
} else if (equals(attributeName, IAttributeNamesConstants.ENCLOSING_METHOD)) {
this.attributes[attributesIndex++] = new EnclosingMethodAttribute(classFileBytes, this.constantPool, readOffset);
} else if (equals(attributeName, IAttributeNamesConstants.SIGNATURE)) {
this.attributes[attributesIndex++] = new SignatureAttribute(classFileBytes, this.constantPool, readOffset);
} else if (equals(attributeName, IAttributeNamesConstants.RUNTIME_VISIBLE_ANNOTATIONS)) {
this.attributes[attributesIndex++] = new RuntimeVisibleAnnotationsAttribute(classFileBytes, this.constantPool, readOffset);
} else if (equals(attributeName, IAttributeNamesConstants.RUNTIME_INVISIBLE_ANNOTATIONS)) {
this.attributes[attributesIndex++] = new RuntimeInvisibleAnnotationsAttribute(classFileBytes, this.constantPool, readOffset);
} else {
this.attributes[attributesIndex++] = new ClassFileAttribute(classFileBytes, this.constantPool, readOffset);
}
readOffset += (6 + u4At(classFileBytes, readOffset + 2, 0));
}
} else {
for (int i = 0; i < attributesCount; i++) {
readOffset += (6 + u4At(classFileBytes, readOffset + 2, 0));
}
}
}
if (readOffset != classFileBytes.length) {
throw new ClassFormatException(ClassFormatException.TOO_MANY_BYTES);
}
} catch(ClassFormatException e) {
throw e;
} catch (Exception e) {
e.printStackTrace();
throw new ClassFormatException(ClassFormatException.ERROR_TRUNCATED_INPUT);
}
}