1be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver/*
2be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * Copyright 2012, Google Inc.
3be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * All rights reserved.
4be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver *
5be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * Redistribution and use in source and binary forms, with or without
6be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * modification, are permitted provided that the following conditions are
7be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * met:
8be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver *
9be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver *     * Redistributions of source code must retain the above copyright
10be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * notice, this list of conditions and the following disclaimer.
11be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver *     * Redistributions in binary form must reproduce the above
12be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * copyright notice, this list of conditions and the following disclaimer
13be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * in the documentation and/or other materials provided with the
14be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * distribution.
15be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver *     * Neither the name of Google Inc. nor the names of its
16be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * contributors may be used to endorse or promote products derived from
17be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * this software without specific prior written permission.
18be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver *
19be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver */
31be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver
32be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruverpackage org.jf.dexlib2.dexbacked;
33be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver
34f81150ad43efac4d590f6b7ea1425896b7ffb011Ben Gruverimport org.jf.dexlib2.base.reference.BaseFieldReference;
35e8158c86efe5494fb5b369e096c7a857623a1b11Ben Gruverimport org.jf.dexlib2.dexbacked.raw.FieldIdItem;
36b65e942e7e53fab70e177681989eb8eaeb4c89deWojtek Kalicińskiimport org.jf.dexlib2.dexbacked.reference.DexBackedFieldReference;
37be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruverimport org.jf.dexlib2.dexbacked.util.AnnotationsDirectory;
38be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruverimport org.jf.dexlib2.dexbacked.util.StaticInitialValueIterator;
39b65e942e7e53fab70e177681989eb8eaeb4c89deWojtek Kalicińskiimport org.jf.dexlib2.dexbacked.value.DexBackedEncodedValue;
40a8e05220c14778d93c97911044ff5124aadbd77cBen Gruverimport org.jf.dexlib2.iface.ClassDef;
41be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruverimport org.jf.dexlib2.iface.Field;
427c71ad420dbdfe2e36f205d335a261435181a25bBen Gruverimport org.jf.dexlib2.iface.value.EncodedValue;
43be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver
44be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruverimport javax.annotation.Nonnull;
45be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruverimport javax.annotation.Nullable;
4622c3185bb7c8618437eabe6c597549e0989ec4e6Ben Gruverimport java.util.Set;
47be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver
48f81150ad43efac4d590f6b7ea1425896b7ffb011Ben Gruverpublic class DexBackedField extends BaseFieldReference implements Field {
4984c1762a62d7fc6638432c6c56e0422aa8cc6939Ben Gruver    @Nonnull public final DexBackedDexFile dexFile;
50a8e05220c14778d93c97911044ff5124aadbd77cBen Gruver    @Nonnull public final ClassDef classDef;
51be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver
52be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver    public final int accessFlags;
537c71ad420dbdfe2e36f205d335a261435181a25bBen Gruver    @Nullable public final EncodedValue initialValue;
54be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver    public final int annotationSetOffset;
55be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver
56be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver    public final int fieldIndex;
57b65e942e7e53fab70e177681989eb8eaeb4c89deWojtek Kaliciński    private final int startOffset;
58b65e942e7e53fab70e177681989eb8eaeb4c89deWojtek Kaliciński    private final int initialValueOffset;
59be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver
60d1662b67fecaf835227aff3a136949a2358ccd4eBen Gruver    private int fieldIdItemOffset;
61d1662b67fecaf835227aff3a136949a2358ccd4eBen Gruver
6236e2ee200517b36652a6e8fe1c5aa24ce249765eBen Gruver    public DexBackedField(@Nonnull DexReader reader,
63a8e05220c14778d93c97911044ff5124aadbd77cBen Gruver                          @Nonnull DexBackedClassDef classDef,
64be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver                          int previousFieldIndex,
65be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver                          @Nonnull StaticInitialValueIterator staticInitialValueIterator,
66be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver                          @Nonnull AnnotationsDirectory.AnnotationIterator annotationIterator) {
6784c1762a62d7fc6638432c6c56e0422aa8cc6939Ben Gruver        this.dexFile = reader.dexBuf;
68a8e05220c14778d93c97911044ff5124aadbd77cBen Gruver        this.classDef = classDef;
69be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver
7045b8a4dae8176ad7a8cfb0ee0bc79354ac8c60b6Ben Gruver        // large values may be used for the index delta, which cause the cumulative index to overflow upon
7145b8a4dae8176ad7a8cfb0ee0bc79354ac8c60b6Ben Gruver        // addition, effectively allowing out of order entries.
72b65e942e7e53fab70e177681989eb8eaeb4c89deWojtek Kaliciński        startOffset = reader.getOffset();
7345b8a4dae8176ad7a8cfb0ee0bc79354ac8c60b6Ben Gruver        int fieldIndexDiff = reader.readLargeUleb128();
74be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver        this.fieldIndex = fieldIndexDiff + previousFieldIndex;
7536e2ee200517b36652a6e8fe1c5aa24ce249765eBen Gruver        this.accessFlags = reader.readSmallUleb128();
76be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver
77be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver        this.annotationSetOffset = annotationIterator.seekTo(fieldIndex);
78b65e942e7e53fab70e177681989eb8eaeb4c89deWojtek Kaliciński        initialValueOffset = staticInitialValueIterator.getReaderOffset();
79be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver        this.initialValue = staticInitialValueIterator.getNextOrNull();
80d1662b67fecaf835227aff3a136949a2358ccd4eBen Gruver    }
81be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver
820a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver    public DexBackedField(@Nonnull DexReader reader,
830a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver                          @Nonnull DexBackedClassDef classDef,
840a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver                          int previousFieldIndex,
850a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver                          @Nonnull AnnotationsDirectory.AnnotationIterator annotationIterator) {
860a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver        this.dexFile = reader.dexBuf;
870a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver        this.classDef = classDef;
880a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver
8945b8a4dae8176ad7a8cfb0ee0bc79354ac8c60b6Ben Gruver        // large values may be used for the index delta, which cause the cumulative index to overflow upon
9045b8a4dae8176ad7a8cfb0ee0bc79354ac8c60b6Ben Gruver        // addition, effectively allowing out of order entries.
91b65e942e7e53fab70e177681989eb8eaeb4c89deWojtek Kaliciński        startOffset = reader.getOffset();
9245b8a4dae8176ad7a8cfb0ee0bc79354ac8c60b6Ben Gruver        int fieldIndexDiff = reader.readLargeUleb128();
930a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver        this.fieldIndex = fieldIndexDiff + previousFieldIndex;
940a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver        this.accessFlags = reader.readSmallUleb128();
950a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver
960a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver        this.annotationSetOffset = annotationIterator.seekTo(fieldIndex);
97b65e942e7e53fab70e177681989eb8eaeb4c89deWojtek Kaliciński        initialValueOffset = 0;
980a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver        this.initialValue = null;
990a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver    }
1000a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver
101d1662b67fecaf835227aff3a136949a2358ccd4eBen Gruver    @Nonnull
102d1662b67fecaf835227aff3a136949a2358ccd4eBen Gruver    @Override
103d1662b67fecaf835227aff3a136949a2358ccd4eBen Gruver    public String getName() {
104e8158c86efe5494fb5b369e096c7a857623a1b11Ben Gruver        return dexFile.getString(dexFile.readSmallUint(getFieldIdItemOffset() + FieldIdItem.NAME_OFFSET));
105d1662b67fecaf835227aff3a136949a2358ccd4eBen Gruver    }
106d1662b67fecaf835227aff3a136949a2358ccd4eBen Gruver
107d1662b67fecaf835227aff3a136949a2358ccd4eBen Gruver    @Nonnull
108d1662b67fecaf835227aff3a136949a2358ccd4eBen Gruver    @Override
109d1662b67fecaf835227aff3a136949a2358ccd4eBen Gruver    public String getType() {
110e8158c86efe5494fb5b369e096c7a857623a1b11Ben Gruver        return dexFile.getType(dexFile.readUshort(getFieldIdItemOffset() + FieldIdItem.TYPE_OFFSET));
111be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver    }
112be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver
11322c3185bb7c8618437eabe6c597549e0989ec4e6Ben Gruver    @Nonnull @Override public String getDefiningClass() { return classDef.getType(); }
114be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver    @Override public int getAccessFlags() { return accessFlags; }
1157c71ad420dbdfe2e36f205d335a261435181a25bBen Gruver    @Nullable @Override public EncodedValue getInitialValue() { return initialValue; }
116be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver
117be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver    @Nonnull
118be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver    @Override
11922c3185bb7c8618437eabe6c597549e0989ec4e6Ben Gruver    public Set<? extends DexBackedAnnotation> getAnnotations() {
12084c1762a62d7fc6638432c6c56e0422aa8cc6939Ben Gruver        return AnnotationsDirectory.getAnnotations(dexFile, annotationSetOffset);
121be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver    }
122be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver
123be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver    /**
124be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver     * Skips the reader over the specified number of encoded_field structures
125be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver     *
12636e2ee200517b36652a6e8fe1c5aa24ce249765eBen Gruver     * @param reader The reader to skip
127be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver     * @param count The number of encoded_field structures to skip over
128be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver     */
129f939e912b53bccab66013c694442fa2f40d970e1Ben Gruver    public static void skipFields(@Nonnull DexReader reader, int count) {
130be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver        for (int i=0; i<count; i++) {
13136e2ee200517b36652a6e8fe1c5aa24ce249765eBen Gruver            reader.skipUleb128();
13236e2ee200517b36652a6e8fe1c5aa24ce249765eBen Gruver            reader.skipUleb128();
133be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver        }
134be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver    }
135d1662b67fecaf835227aff3a136949a2358ccd4eBen Gruver
136d1662b67fecaf835227aff3a136949a2358ccd4eBen Gruver    private int getFieldIdItemOffset() {
137d1662b67fecaf835227aff3a136949a2358ccd4eBen Gruver        if (fieldIdItemOffset == 0) {
13884c1762a62d7fc6638432c6c56e0422aa8cc6939Ben Gruver            fieldIdItemOffset = dexFile.getFieldIdItemOffset(fieldIndex);
139d1662b67fecaf835227aff3a136949a2358ccd4eBen Gruver        }
140d1662b67fecaf835227aff3a136949a2358ccd4eBen Gruver        return fieldIdItemOffset;
141d1662b67fecaf835227aff3a136949a2358ccd4eBen Gruver    }
142b65e942e7e53fab70e177681989eb8eaeb4c89deWojtek Kaliciński
143b65e942e7e53fab70e177681989eb8eaeb4c89deWojtek Kaliciński    /**
144b65e942e7e53fab70e177681989eb8eaeb4c89deWojtek Kaliciński     * Calculate and return the private size of a field definition.
145b65e942e7e53fab70e177681989eb8eaeb4c89deWojtek Kaliciński     *
146b65e942e7e53fab70e177681989eb8eaeb4c89deWojtek Kaliciński     * Calculated as: field_idx_diff + access_flags + annotations overhead +
147b65e942e7e53fab70e177681989eb8eaeb4c89deWojtek Kaliciński     * initial value size + field reference size
148b65e942e7e53fab70e177681989eb8eaeb4c89deWojtek Kaliciński     *
149b65e942e7e53fab70e177681989eb8eaeb4c89deWojtek Kaliciński     * @return size in bytes
150b65e942e7e53fab70e177681989eb8eaeb4c89deWojtek Kaliciński     */
151b65e942e7e53fab70e177681989eb8eaeb4c89deWojtek Kaliciński    public int getSize() {
152b65e942e7e53fab70e177681989eb8eaeb4c89deWojtek Kaliciński        int size = 0;
153b65e942e7e53fab70e177681989eb8eaeb4c89deWojtek Kaliciński        DexReader reader = dexFile.readerAt(startOffset);
154b65e942e7e53fab70e177681989eb8eaeb4c89deWojtek Kaliciński        reader.readLargeUleb128(); //field_idx_diff
155b65e942e7e53fab70e177681989eb8eaeb4c89deWojtek Kaliciński        reader.readSmallUleb128(); //access_flags
156b65e942e7e53fab70e177681989eb8eaeb4c89deWojtek Kaliciński        size += reader.getOffset() - startOffset;
157b65e942e7e53fab70e177681989eb8eaeb4c89deWojtek Kaliciński
158b65e942e7e53fab70e177681989eb8eaeb4c89deWojtek Kaliciński        Set<? extends DexBackedAnnotation> annotations = getAnnotations();
159b65e942e7e53fab70e177681989eb8eaeb4c89deWojtek Kaliciński        if (!annotations.isEmpty()) {
160b65e942e7e53fab70e177681989eb8eaeb4c89deWojtek Kaliciński            size += 2 * 4; //2 * uint overhead from field_annotation
161b65e942e7e53fab70e177681989eb8eaeb4c89deWojtek Kaliciński        }
162b65e942e7e53fab70e177681989eb8eaeb4c89deWojtek Kaliciński
163b65e942e7e53fab70e177681989eb8eaeb4c89deWojtek Kaliciński        if (initialValueOffset > 0) {
164b65e942e7e53fab70e177681989eb8eaeb4c89deWojtek Kaliciński            reader.setOffset(initialValueOffset);
165b65e942e7e53fab70e177681989eb8eaeb4c89deWojtek Kaliciński            if (initialValue != null) {
166b65e942e7e53fab70e177681989eb8eaeb4c89deWojtek Kaliciński                DexBackedEncodedValue.skipFrom(reader);
167b65e942e7e53fab70e177681989eb8eaeb4c89deWojtek Kaliciński                size += reader.getOffset() - initialValueOffset;
168b65e942e7e53fab70e177681989eb8eaeb4c89deWojtek Kaliciński            }
169b65e942e7e53fab70e177681989eb8eaeb4c89deWojtek Kaliciński        }
170b65e942e7e53fab70e177681989eb8eaeb4c89deWojtek Kaliciński
171b65e942e7e53fab70e177681989eb8eaeb4c89deWojtek Kaliciński        DexBackedFieldReference fieldRef = new DexBackedFieldReference(dexFile, fieldIndex);
172b65e942e7e53fab70e177681989eb8eaeb4c89deWojtek Kaliciński        size += fieldRef.getSize();
173b65e942e7e53fab70e177681989eb8eaeb4c89deWojtek Kaliciński
174b65e942e7e53fab70e177681989eb8eaeb4c89deWojtek Kaliciński        return size;
175b65e942e7e53fab70e177681989eb8eaeb4c89deWojtek Kaliciński    }
176be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver}
177