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