/* * 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; import java.io.IOException; import mereflect.info.AiConstantValue; import mereflect.info.AttributeInfo; import mereflect.info.CiDouble; import mereflect.info.CiFloat; import mereflect.info.CiInteger; import mereflect.info.CiLong; import mereflect.info.CiString; import mereflect.info.CiUtf8; import mereflect.info.ClassInfo; import mereflect.io.DescriptorParser; public class MEField { public static final int ACC_PUBLIC = 0x0001; public static final int ACC_PRIVATE = 0x0002; public static final int ACC_PROTECTED = 0x0004; public static final int ACC_STATIC = 0x0008; public static final int ACC_FINAL = 0x0010; public static final int ACC_VOLATILE = 0x0040; public static final int ACC_TRANSIENT = 0x0080; protected int m_accFlags; protected int m_nameIndex; protected int m_descIndex; protected AttributeInfo[] m_attributes; protected MEClass m_class; protected Type m_type = null; public MEField(MEClass clazz) { m_class = clazz; } public MEClass getMEClass() { return m_class; } /** * Returns the name of this field * @return field name */ public String getName() { return ((CiUtf8) m_class.getConstantPool()[getNameIndex()]).getUtf8(); } /** * Returns constant pool descriptor of this field * @return constant pool descriptor */ public String getDescriptor() { return ((CiUtf8) m_class.getConstantPool()[getDescriptorIndex()]).getUtf8(); } /** * Returns the type that this field is declared as * @return the field type */ public Type getType() { if (m_type == null) { try { m_type = DescriptorParser.processTypeDescriptor(m_class, new StringBuffer(getDescriptor())); } catch (IOException e) { throw new RuntimeException(e); } } return m_type; } /** * Returns true if this field is declared public * @return if field is public */ public boolean isPublic() { return (m_accFlags & ACC_PUBLIC) > 0; } /** * Returns true if this field is declared protected * @return if field is protected */ public boolean isProtected() { return (m_accFlags & ACC_PROTECTED) > 0; } /** * Returns true if this field is declared private * @return if field is private */ public boolean isPrivate() { return (m_accFlags & ACC_PRIVATE) > 0; } /** * Returns true if this field is declared static * @return if field is static */ public boolean isStatic() { return (m_accFlags & ACC_STATIC) > 0; } /** * Returns true if this field is declared final * @return if field is final */ public boolean isFinal() { return (m_accFlags & ACC_FINAL) > 0; } /** * Returns true if this field is declared volatile * @return if field is volatile */ public boolean isVolatile() { return (m_accFlags & ACC_VOLATILE) > 0; } /** * Returns true if this field is declared transient * @return if field is transient */ public boolean isTransient() { return (m_accFlags & ACC_TRANSIENT) > 0; } /** * Returns the constant value declared by this field. Constant values * are only declared by final primitives and strings. * @return constant value or null if no constant value is declared */ public Object getConstantValue() { Object res = null; AiConstantValue cval = null; AttributeInfo[] attrs = getAttributes(); for (int i = 0; cval == null && i < attrs.length; i++) { if (attrs[i] instanceof AiConstantValue) { cval = (AiConstantValue) attrs[i]; } } if (cval != null) { ClassInfo valInfo = m_class.getConstantPool()[cval.getConstantValueIndex()]; Type t = getType(); if (t.equals(Type.BOOLEAN)) { res = new Boolean(((CiInteger) valInfo).getInteger() > 0); } else if (t.equals(Type.BYTE)) { res = new Long((byte) ((CiInteger) valInfo).getInteger()); } else if (t.equals(Type.CHAR)) { res = new Character((char) ((CiInteger) valInfo).getInteger()); } else if (t.equals(Type.DOUBLE)) { res = new Double(((CiDouble) valInfo).getDouble()); } else if (t.equals(Type.FLOAT)) { res = new Float(((CiFloat) valInfo).getFloat()); } else if (t.equals(Type.INT)) { res = new Long(((CiInteger) valInfo).getInteger()); } else if (t.equals(Type.LONG)) { res = new Long(((CiLong) valInfo).getLong()); } else if (t.equals(Type.SHORT)) { res = new Long((short) ((CiInteger) valInfo).getInteger()); } else if (t.getName().equals(Type.STR_STRING)) { res = ((CiUtf8) m_class.getConstantPool()[(((CiString) valInfo).getStringIndex())]).getUtf8(); } } return res; } /** * Returns a string representation of the constantvalue declared by this field. * @return String representation of constant value or null * if no constant value is declared */ public String getConstantValueString() { Object cval = getConstantValue(); if (cval != null) { StringBuffer sb = new StringBuffer(); Type t = getType(); boolean tFloat = t.equals(Type.FLOAT); boolean tLong = t.equals(Type.LONG); boolean tChar = t.equals(Type.CHAR) && Character.isLetterOrDigit(((Character) cval).charValue()); boolean tCharSpec = t.equals(Type.CHAR) && !Character.isLetterOrDigit(((Character) cval).charValue()); boolean tString = t.getName().equals(Type.STR_STRING); boolean tNumeric = t.equals(Type.INT) || t.equals(Type.LONG) || t.equals(Type.SHORT); if (tChar) { sb.append('\''); } if (tString) { sb.append('\"'); } if (tNumeric && (((Long) cval).longValue() > 255)) { sb.append("0x"); sb.append(Long.toHexString(((Long) cval).longValue())); } else if (tCharSpec) { sb.append(Integer.toString(((Character) cval).charValue())); } else { sb.append(cval); } if (tFloat) { sb.append('f'); } if (tLong) { sb.append('l'); } if (tChar) { sb.append('\''); } if (tString) { sb.append('\"'); } return sb.toString(); } else { return null; } } // Getters /** * Returns accessflags as declared in constant pool * @return constant pool access flags */ public int getAccessFlags() { return m_accFlags; } /** * Returns nameindex as declared in constant pool * @return constant pool nameindex */ public int getNameIndex() { return m_nameIndex; } /** * Returns descriptor index as declared in constant pool * @return constant pool descriptor index */ public int getDescriptorIndex() { return m_descIndex; } /** * Returns constant pool attributes belonging to this field * @return constant pool attributes */ public AttributeInfo[] getAttributes() { return m_attributes; } // Setters public void setAccessFlags(int accFlags) { m_accFlags = accFlags; } public void setAttributes(AttributeInfo[] attributes) { m_attributes = attributes; } public void setDescriptorIndex(int descIndex) { m_descIndex = descIndex; } public void setNameIndex(int nameIndex) { m_nameIndex = nameIndex; } @Override public String toString() { StringBuffer sb = new StringBuffer(); if (isPrivate()) { sb.append("private "); } else if (isProtected()) { sb.append("protected "); } else if (isPublic()) { sb.append("public "); } if (isStatic()) { sb.append("static "); } if (isFinal()) { sb.append("final "); } if (isVolatile()) { sb.append("volatile "); } if (isTransient()) { sb.append("transient "); } sb.append(getType()); sb.append(' '); sb.append(getName()); String cval = getConstantValueString(); if (cval != null) { sb.append(" = "); sb.append(cval); } sb.append(';'); return sb.toString(); } @Override public int hashCode() { //return getName().hashCode(); int hashCode = m_class.getName().hashCode(); hashCode = 31 * hashCode + getName().hashCode(); hashCode = 31 * hashCode + getDescriptor().hashCode(); return hashCode; } @Override public boolean equals(Object o) { if (o != null && o instanceof MEField) { MEField m = (MEField) o; boolean match = m.getMEClass().equals(getMEClass()) && m.getName().equals(getName()) && m.getDescriptor().equals(getDescriptor()); return match; } else { return false; } } }