/*
* Copyright (C) 2012 Sony Mobile Communications AB
*
* This file is part of ApkAnalyser.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package mereflect.io;
import java.io.DataInputStream;
import java.io.IOException;
import mereflect.MEClass;
import mereflect.MEField;
import mereflect.MEMethod;
import mereflect.info.AbstractClassInfo;
import mereflect.info.AttributeInfo;
import mereflect.info.CiUtf8;
import mereflect.info.ClassInfo;
public class DebugClassReader extends DefaultClassReader
{
boolean DBG = true;
IndexedInputStream iis;
@Override
public MEClass readClassFile(DataInputStream dis) throws IOException
{
iis = new IndexedInputStream(dis);
dis = new DataInputStream(iis);
MEClass c = new MEClass();
int magic = dis.readInt();
if (magic != 0xcafebabe) {
throw new IOException("Not a class file");
}
// Version
int majMin = dis.readInt();
c.setMajorVersion((majMin & 0xff00) >> 8);
c.setMinorVersion(majMin & 0xff);
// Constant pool
boolean corruptPool = false;
int prereadByte = 0;
int cpLen = dis.readUnsignedShort();
if (DBG) {
System.out.println("\tconstant pool " + cpLen);
}
ClassInfo[] infos = new ClassInfo[cpLen];
for (int i = 1; i < cpLen; i++)
{
try
{
int pre = iis.getIndex();
infos[i] = readClassInfo(c, dis);
int post = iis.getIndex() - 1;
if (DBG) {
System.out.print("\t" + i + ": " +
AbstractClassInfo.ciTagToString(infos[i].getTag()) +
"\t[" + infos[i].getTag() + "] \t" +
Integer.toHexString(pre) + " - " +
Integer.toHexString(post) + " : " + (post - pre + 1));
}
if (DBG)
{
if (infos[i].getTag() == ClassInfo.CONSTANT_Utf8)
{
int strlen = ((CiUtf8) infos[i]).getUtf8().length();
System.out.println(" strlen:" + strlen +
(((strlen + 3) != (post - pre + 1)) ? " MISMATCH" : ""));
} else {
System.out.println();
}
}
if (infos[i].getTag() == ClassInfo.CONSTANT_Long ||
infos[i].getTag() == ClassInfo.CONSTANT_Double)
{
i++;
}
} catch (MissingClassInfoException mcie)
{
if (DBG) {
System.out.println(">>>\t" + c.getMajorVersion() + "/" + c.getMinorVersion() +
" Got corrupt pool, tag " + mcie.getTag() + " on " + i);
}
corruptPool = true;
prereadByte = mcie.getTag();
break;
}
}
c.setConstantPool(infos);
// Class data
int accessFlags = 0;
if (corruptPool) {
accessFlags = (prereadByte << 8) | dis.readUnsignedByte(); // Pool corrupt, we've already read a zero byte
} else {
accessFlags = dis.readUnsignedShort();
}
int thisClass = dis.readUnsignedShort();
int superClass = dis.readUnsignedShort();
c.setAccessFlags(accessFlags);
c.setThisClassIndex(thisClass);
c.setSuperClassIndex(superClass);
// Interfaces
int pre = iis.getIndex();
int ifcLen = dis.readUnsignedShort();
int[] ifcs = new int[ifcLen];
for (int i = 0; i < ifcLen; i++)
{
ifcs[i] = dis.readUnsignedShort();
}
int post = iis.getIndex() - 1;
c.setInterfaceIndices(ifcs);
if (DBG) {
System.out.println("\tInterfaces \t" +
ifcLen + "\t" +
Integer.toHexString(pre) + " - " +
Integer.toHexString(post) + " : " + (post - pre + 1));
}
// Fields
pre = iis.getIndex();
int fLen = dis.readUnsignedShort();
MEField[] fields = new MEField[fLen];
for (int i = 0; i < fLen; i++)
{
int pre2 = iis.getIndex();
fields[i] = readFieldInfo(c, dis);
int post2 = iis.getIndex() - 1;
if (DBG) {
System.out.println("\tField \t\t" + i + "\t" +
Integer.toHexString(pre2) + " - " +
Integer.toHexString(post2) + " : " + (post2 - pre2 + 1));
}
}
post = iis.getIndex() - 1;
c.setFields(fields);
if (DBG) {
System.out.println("\tFields \t\t" +
fLen + "\t" +
Integer.toHexString(pre) + " - " +
Integer.toHexString(post) + " : " + (post - pre + 1));
}
// Methods
pre = iis.getIndex();
int mLen = dis.readUnsignedShort();
MEMethod[] methods = new MEMethod[mLen];
for (int i = 0; i < mLen; i++)
{
int pre2 = iis.getIndex();
methods[i] = readMethodInfo(c, dis);
int post2 = iis.getIndex() - 1;
if (DBG) {
System.out.println("\tMethod \t\t" + i + "\t" +
Integer.toHexString(pre2) + " - " +
Integer.toHexString(post2) + " : " + (post2 - pre2 + 1));
}
}
post = iis.getIndex() - 1;
c.setMethods(methods);
if (DBG) {
System.out.println("\tMethods \t\t" +
mLen + "\t" +
Integer.toHexString(pre) + " - " +
Integer.toHexString(post) + " : " + (post - pre + 1));
}
// Attributes
AttributeInfo[] attrs = readAttributeInfos(c, dis);
c.setAttributes(attrs);
return c;
}
@Override
protected AttributeInfo[] readAttributeInfos(MEClass c, DataInputStream dis) throws IOException
{
int attrLen = dis.readUnsignedShort();
AttributeInfo[] attrs = new AttributeInfo[attrLen];
int pre = iis.getIndex();
for (int i = 0; i < attrLen; i++)
{
int pre2 = iis.getIndex();
attrs[i] = readAttributeInfo(c, dis);
int post2 = iis.getIndex() - 1;
if (DBG) {
System.out.println("\t\tAttr" + attrs[i].getNameIndex() + "\t" +
i + "\t" +
Integer.toHexString(pre2) + " - " +
Integer.toHexString(post2) + " : " + (post2 - pre2 + 1));
}
}
int post = iis.getIndex() - 1;
if (attrLen > 0) {
if (DBG) {
System.out.println("\t\tAttrs \t" +
attrLen + "\t" +
Integer.toHexString(pre) + " - " +
Integer.toHexString(post) + " : " + (post - pre + 1));
}
}
return attrs;
}
}