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.dex.Leb128;
20import com.android.dx.rop.code.AccessFlags;
21import com.android.dx.rop.cst.CstFieldRef;
22import com.android.dx.rop.cst.CstString;
23import com.android.dx.util.AnnotatedOutput;
24import com.android.dx.util.Hex;
25import java.io.PrintWriter;
26
27/**
28 * Representation of a field of a class, of any sort.
29 */
30public final class EncodedField extends EncodedMember
31        implements Comparable<EncodedField> {
32    /** {@code non-null;} constant for the field */
33    private final CstFieldRef field;
34
35    /**
36     * Constructs an instance.
37     *
38     * @param field {@code non-null;} constant for the field
39     * @param accessFlags access flags
40     */
41    public EncodedField(CstFieldRef field, int accessFlags) {
42        super(accessFlags);
43
44        if (field == null) {
45            throw new NullPointerException("field == null");
46        }
47
48        /*
49         * TODO: Maybe check accessFlags, at least for
50         * easily-checked stuff?
51         */
52
53        this.field = field;
54    }
55
56    /** {@inheritDoc} */
57    public int hashCode() {
58        return field.hashCode();
59    }
60
61    /** {@inheritDoc} */
62    public boolean equals(Object other) {
63        if (! (other instanceof EncodedField)) {
64            return false;
65        }
66
67        return compareTo((EncodedField) other) == 0;
68    }
69
70    /**
71     * {@inheritDoc}
72     *
73     * <p><b>Note:</b> This compares the method constants only,
74     * ignoring any associated code, because it should never be the
75     * case that two different items with the same method constant
76     * ever appear in the same list (or same file, even).</p>
77     */
78    public int compareTo(EncodedField other) {
79        return field.compareTo(other.field);
80    }
81
82    /** {@inheritDoc} */
83    @Override
84    public String toString() {
85        StringBuffer sb = new StringBuffer(100);
86
87        sb.append(getClass().getName());
88        sb.append('{');
89        sb.append(Hex.u2(getAccessFlags()));
90        sb.append(' ');
91        sb.append(field);
92        sb.append('}');
93        return sb.toString();
94    }
95
96    /** {@inheritDoc} */
97    @Override
98    public void addContents(DexFile file) {
99        FieldIdsSection fieldIds = file.getFieldIds();
100        fieldIds.intern(field);
101    }
102
103    /** {@inheritDoc} */
104    @Override
105    public CstString getName() {
106        return field.getNat().getName();
107    }
108
109    /** {@inheritDoc} */
110    public String toHuman() {
111        return field.toHuman();
112    }
113
114    /** {@inheritDoc} */
115    @Override
116    public void debugPrint(PrintWriter out, boolean verbose) {
117        // TODO: Maybe put something better here?
118        out.println(toString());
119    }
120
121    /**
122     * Gets the constant for the field.
123     *
124     * @return {@code non-null;} the constant
125     */
126    public CstFieldRef getRef() {
127        return field;
128    }
129
130    /** {@inheritDoc} */
131    @Override
132    public int encode(DexFile file, AnnotatedOutput out,
133            int lastIndex, int dumpSeq) {
134        int fieldIdx = file.getFieldIds().indexOf(field);
135        int diff = fieldIdx - lastIndex;
136        int accessFlags = getAccessFlags();
137
138        if (out.annotates()) {
139            out.annotate(0, String.format("  [%x] %s", dumpSeq,
140                            field.toHuman()));
141            out.annotate(Leb128.unsignedLeb128Size(diff),
142                    "    field_idx:    " + Hex.u4(fieldIdx));
143            out.annotate(Leb128.unsignedLeb128Size(accessFlags),
144                    "    access_flags: " +
145                    AccessFlags.fieldString(accessFlags));
146        }
147
148        out.writeUleb128(diff);
149        out.writeUleb128(accessFlags);
150
151        return fieldIdx;
152    }
153}
154