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