Home | History | Annotate | Download | only in dexbacked
      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 
     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 
     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
    103     public String getName() {
    104         return dexFile.getString(dexFile.readSmallUint(getFieldIdItemOffset() + FieldIdItem.NAME_OFFSET));
    105     }
    106 
    107     @Nonnull
    108     @Override
    109     public String getType() {
    110         return dexFile.getType(dexFile.readUshort(getFieldIdItemOffset() + FieldIdItem.TYPE_OFFSET));
    111     }
    112 
    113     @Nonnull @Override public String getDefiningClass() { return classDef.getType(); }
    114     @Override public int getAccessFlags() { return accessFlags; }
    115     @Nullable @Override public EncodedValue getInitialValue() { return initialValue; }
    116 
    117     @Nonnull
    118     @Override
    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      */
    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 
    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      */
    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