/* Software Name : AsmDex * Version : 1.0 * * Copyright © 2012 France Télécom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.ow2.asmdex.structureWriter; import org.ow2.asmdex.Opcodes; import org.ow2.asmdex.encodedValue.EncodedValue; import org.ow2.asmdex.encodedValue.EncodedValueFactory; import org.ow2.asmdex.encodedValue.EncodedValueString; import org.ow2.asmdex.encodedValue.EncodedValueUtil; /** * Class representing a Field. A Field, as described by the field_id_item format, consists in its name, * the name of the class owning it, and its type. However, contrary to the field_id_item, it also own * its access flags, and its value. * * The value is only used for Final Static fields, else it's Null. * * Having two fields equals does NOT mean their value is equal. Just that the name, owner and type are the * same. * * Implements Comparable in order to easily sort the Fields. Like requested by the Dex documentation, * two Fields are sorted according to the class owning type, the field name and then their own type. * * @author Julien Névo */ public class Field implements Comparable<Field>, IAnnotationsHolder { /** * Name of the Class, owner of the Field. */ final private String className; /** * Type of the Field, described in the TypeDescriptor format. */ final private String typeName; /** * Name of the Field. */ final private String fieldName; /** * Access flags of the Field. */ private int access; /** * The Signature of the Field. May be Null. */ private String[] signature; /** * Value of the Field. Null for non-final static fields. */ private EncodedValue value = null; /** * Annotation_set_item, representing all the annotation_items for this Field. */ private AnnotationSetItem annotationSetItem = new AnnotationSetItem(); /** * The hashcode of the Field, calculated in the Constructor. */ final private int hashcode; /** * Constructor of the Field. * @param fieldName name of the Field. * @param desc type of the Field, described in the TypeDescriptor format. * @param classOwningName name of the Class, owner of the Field. */ public Field(String fieldName, String desc, String classOwningName) { this.fieldName = fieldName; typeName = desc; className = classOwningName; hashcode = calculateHashCode(fieldName, className, typeName); } /** * Init if this is the one kept. * @param access the access flags of the Field. * @param signature the Signature of the field. May be Null. * @param value the value of the Field, or Null for non-static Fields. * @param constantPool the Constant Pool. */ public void init( int access, String[] signature, Object value, ConstantPool constantPool) { this.access = access; this.signature = signature; setEncodedValueFromObject(value, typeName, constantPool); } // ---------------------------------------------- // Private methods. // ---------------------------------------------- /** * Sets the value field from the given Object. * @param value the Object. * @param desc the descriptor of the Field, described in the TypeDescriptor format. It is useful to know * if the Object contains a reference of not. * @param constantPool the Constant Pool of the Application. */ private void setEncodedValueFromObject(Object value, String desc, ConstantPool constantPool) { if ((access & (Opcodes.ACC_STATIC)) > 0) { if (value != null) { // Reference values are always encoded as Null, even if the value is given. // Exception for the Strings, which are encoded. boolean isRef = EncodedValueUtil.isTypeAReference(desc); if (isRef) { if (EncodedValueUtil.isString(desc)) { String str = (String)value; this.value = new EncodedValueString(str); constantPool.addStringToConstantPool(str); } else { setNoValue(); } } else { this.value = EncodedValueFactory.getEncodedValue(value, desc); } } } } // ---------------------------------------------- // Public methods. // ---------------------------------------------- /** * Calculates the hashcode of a Field according to some of its attributes. * @param fieldName the name of the Field. * @param classOwningName the Class owning the Field. * @param desc type of the Field, described in the TypeDescriptor format. * @return the hashcode of a Field. */ public static int calculateHashCode(String fieldName, String classOwningName, String desc) { return classOwningName.hashCode() + desc.hashCode() + fieldName.hashCode(); } /** * Adds information to the current Field. This is useful <i>only</i> if this Field has the ACC_UNKNOWN * flag, which means Instructions referred to it while it has not yet been visited, * declaring it but not giving all the information it should have. */ public void completeInformation(int access, String[] signature, Object value, ConstantPool constantPool) { this.access = access; this.signature = signature; setEncodedValueFromObject(value, typeName, constantPool); } /** * Indicates whether the Field is Static. */ public boolean isStatic() { return (access & Opcodes.ACC_STATIC) > 0; } /** * Indicates whether the Field is Final and Static. */ public boolean isFinalStatic() { return ((access & Opcodes.ACC_STATIC) > 0) && ((access & Opcodes.ACC_FINAL) > 0); } /** * Indicates whether the Field is unknown (referred to, but not yet parsed). * @return true if the Field is unknown. */ public boolean isUnknown() { return (access & Opcodes.ACC_UNKNOWN) != 0; } /** * Adds an annotation_item to the annotations_set_items. * @param annotationItem the Annotation Item to add. */ public void addAnnotationItem(AnnotationItem annotationItem) { annotationSetItem.addAnnotationItem(annotationItem); } // ---------------------------------------------- // Getters. // ---------------------------------------------- /** * Returns the Class owning the Field. * @return the Class owning the Field. */ public String getClassName() { return className; } /** * Returns the Type of the Field, described in the TypeDescriptor format. * @return the Type of the Field, described in the TypeDescriptor format. */ public String getTypeName() { return typeName; } /** * Returns the Name of the Field. * @return the Name of the Field. */ public String getFieldName() { return fieldName; } /** * Returns the access flags of the Field. * @return the access flags of the Field. */ public int getAccess() { return access; } /** * Returns the Signature of the Field. May be Null. * @return the Signature of the Field. May be Null. */ public String[] getSignature() { return signature; } /** * Returns the encoded value of the field. Null for non-static fields. * @return the encoded value of the field, or Null. */ public EncodedValue getValue() { return value; } /** * Encode the value into an array of Bytes. * @return an array of bytes. */ public byte[] encodeValue(ConstantPool constantPool) { return (value == null) ? null : value.encode(constantPool); } /** * Sets the value to 0 or Null according to its type. */ public void setNoValue() { value = EncodedValueFactory.getEncodedEmptyValue(typeName); } /** * Returns the annotation_set_item this structure currently contains. * @return the annotation_set_item this structure currently contains. */ @Override public AnnotationSetItem getAnnotationSetItem() { return annotationSetItem; } /** * Returns the number of annotation_items this structure currently contains. * @return the number of annotation_items this structure currently contains. */ @Override public int getNbAnnotations() { return annotationSetItem.getNbAnnotationItems(); } // ---------------------------------------------- // Overridden methods. // ---------------------------------------------- @Override public int hashCode() { return hashcode; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj instanceof Field) { Field field = (Field)obj; return fieldName.equals(field.fieldName) && (className.equals(field.className) && (typeName.equals(field.typeName))); } return false; } @Override public int compareTo(Field field) { if (this == field) { return 0; } // Tests class owning name first. int compare = className.compareTo(field.className); if (compare != 0) { return compare; } // Tests the names. compare = fieldName.compareTo(field.fieldName); if (compare != 0) { return compare; } // Tests the type. return typeName.compareTo(field.typeName); } }