1/* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.dx.dex.file; 18 19import com.android.dx.rop.code.AccessFlags; 20import com.android.dx.rop.cst.CstFieldRef; 21import com.android.dx.rop.cst.CstString; 22import com.android.dx.util.AnnotatedOutput; 23import com.android.dx.util.Hex; 24import com.android.dx.util.Leb128Utils; 25 26import java.io.PrintWriter; 27 28/** 29 * Representation of a field of a class, of any sort. 30 */ 31public final class EncodedField extends EncodedMember 32 implements Comparable<EncodedField> { 33 /** {@code non-null;} constant for the field */ 34 private final CstFieldRef field; 35 36 /** 37 * Constructs an instance. 38 * 39 * @param field {@code non-null;} constant for the field 40 * @param accessFlags access flags 41 */ 42 public EncodedField(CstFieldRef field, int accessFlags) { 43 super(accessFlags); 44 45 if (field == null) { 46 throw new NullPointerException("field == null"); 47 } 48 49 /* 50 * TODO: Maybe check accessFlags, at least for 51 * easily-checked stuff? 52 */ 53 54 this.field = field; 55 } 56 57 /** {@inheritDoc} */ 58 public int hashCode() { 59 return field.hashCode(); 60 } 61 62 /** {@inheritDoc} */ 63 public boolean equals(Object other) { 64 if (! (other instanceof EncodedField)) { 65 return false; 66 } 67 68 return compareTo((EncodedField) other) == 0; 69 } 70 71 /** 72 * {@inheritDoc} 73 * 74 * <p><b>Note:</b> This compares the method constants only, 75 * ignoring any associated code, because it should never be the 76 * case that two different items with the same method constant 77 * ever appear in the same list (or same file, even).</p> 78 */ 79 public int compareTo(EncodedField other) { 80 return field.compareTo(other.field); 81 } 82 83 /** {@inheritDoc} */ 84 @Override 85 public String toString() { 86 StringBuffer sb = new StringBuffer(100); 87 88 sb.append(getClass().getName()); 89 sb.append('{'); 90 sb.append(Hex.u2(getAccessFlags())); 91 sb.append(' '); 92 sb.append(field); 93 sb.append('}'); 94 return sb.toString(); 95 } 96 97 /** {@inheritDoc} */ 98 @Override 99 public void addContents(DexFile file) { 100 FieldIdsSection fieldIds = file.getFieldIds(); 101 fieldIds.intern(field); 102 } 103 104 /** {@inheritDoc} */ 105 @Override 106 public CstString getName() { 107 return field.getNat().getName(); 108 } 109 110 /** {@inheritDoc} */ 111 public String toHuman() { 112 return field.toHuman(); 113 } 114 115 /** {@inheritDoc} */ 116 @Override 117 public void debugPrint(PrintWriter out, boolean verbose) { 118 // TODO: Maybe put something better here? 119 out.println(toString()); 120 } 121 122 /** 123 * Gets the constant for the field. 124 * 125 * @return {@code non-null;} the constant 126 */ 127 public CstFieldRef getRef() { 128 return field; 129 } 130 131 /** {@inheritDoc} */ 132 @Override 133 public int encode(DexFile file, AnnotatedOutput out, 134 int lastIndex, int dumpSeq) { 135 int fieldIdx = file.getFieldIds().indexOf(field); 136 int diff = fieldIdx - lastIndex; 137 int accessFlags = getAccessFlags(); 138 139 if (out.annotates()) { 140 out.annotate(0, String.format(" [%x] %s", dumpSeq, 141 field.toHuman())); 142 out.annotate(Leb128Utils.unsignedLeb128Size(diff), 143 " field_idx: " + Hex.u4(fieldIdx)); 144 out.annotate(Leb128Utils.unsignedLeb128Size(accessFlags), 145 " access_flags: " + 146 AccessFlags.fieldString(accessFlags)); 147 } 148 149 out.writeUleb128(diff); 150 out.writeUleb128(accessFlags); 151 152 return fieldIdx; 153 } 154} 155