Home | History | Annotate | Download | only in reader
      1 /*
      2  * Copyright (C) 2009 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 
     17 package dex.reader;
     18 
     19 import static dex.structure.DexEncodedValueType.*;
     20 import dex.reader.DexFileReader.FieldIdItem;
     21 import dex.structure.DexAnnotation;
     22 import dex.structure.DexEncodedValue;
     23 import dex.structure.DexEncodedValueType;
     24 
     25 import java.util.ArrayList;
     26 import java.util.List;
     27 
     28 /* package */final class DexEncodedValueImpl implements DexEncodedValue {
     29 
     30     private final DexBuffer buffer;
     31     private byte typeAndValueArg;
     32     private DexEncodedValueType type;
     33     private String[] stringPool;
     34     private Object value;
     35     private int[] typeIds;
     36     private final FieldIdItem[] fieldIdItems;
     37     private final DexAnnotation annotation;
     38 
     39     /**
     40      *
     41      * @param buffer
     42      *            the buffer with the correct position
     43      * @param annotation
     44      * @param stringPool
     45      * @param fieldIdItems
     46      */
     47     public DexEncodedValueImpl(DexBuffer buffer, DexAnnotation annotation,
     48             int[] typeIds, String[] stringPool, FieldIdItem[] fieldIdItems) {
     49         this.buffer = buffer;
     50         this.annotation = annotation;
     51         this.typeIds = typeIds;
     52         this.stringPool = stringPool;
     53         this.fieldIdItems = fieldIdItems;
     54         parseValue();
     55     }
     56 
     57     private void parseValue() {
     58         typeAndValueArg = buffer.readUByte();
     59         type = DexEncodedValueType.get(typeAndValueArg);
     60         int valueArg = DexEncodedValueType.valueArg(typeAndValueArg);
     61         switch (type) {
     62         case VALUE_BYTE:
     63             value = getByteValue(valueArg);
     64             break;
     65         case VALUE_SHORT:
     66             value = getShortValue(valueArg);
     67             break;
     68         case VALUE_CHAR:
     69             value = getCharValue(valueArg);
     70             break;
     71         case VALUE_INT:
     72             value = getIntValue(valueArg);
     73             break;
     74         case VALUE_LONG:
     75             value = getLongValue(valueArg);
     76             break;
     77         case VALUE_FLOAT:
     78             value = getFloatValue(valueArg);
     79             break;
     80         case VALUE_DOUBLE:
     81             value = getDoubleValue(valueArg);
     82             break;
     83         case VALUE_STRING:
     84             value = getStringValue(valueArg);
     85             break;
     86         case VALUE_TYPE:
     87             value = getTypeValue(valueArg);
     88             break;
     89         case VALUE_FIELD:
     90             value = getFieldValue(valueArg);
     91             break;
     92         case VALUE_METHOD:
     93             value = getMethodValue(valueArg);
     94             break;
     95         case VALUE_ENUM:
     96             value = getEnumValue(valueArg);
     97             break;
     98         case VALUE_ARRAY:
     99             value = getArrayValue(valueArg);
    100             break;
    101         case VALUE_ANNOTATION:
    102             value = getAnnotationValue(valueArg);
    103             break;
    104         case VALUE_NULL:
    105             value = getNullValue(valueArg);
    106             break;
    107         case VALUE_BOOLEAN:
    108             value = getBooleanValue(valueArg);
    109             break;
    110         default:
    111             throw new IllegalArgumentException("DexEncodedValueType " + type
    112                     + " not recognized");
    113         }
    114     }
    115 
    116     /**
    117      * VALUE_BOOLEAN 0x1f boolean (0...1) (none) one-bit value; 0 for false and
    118      * 1 for true. The bit is represented in the value_arg.
    119      */
    120     private Boolean getBooleanValue(int valueArg) {
    121         return valueArg == 1;
    122     }
    123 
    124     /** VALUE_NULL 0x1e (none; must be 0) (none) null reference value */
    125     private Object getNullValue(int valueArg) {
    126         return null; // must be like that!
    127     }
    128 
    129     /**
    130      * VALUE_ANNOTATION 0x1d (none; must be 0) encoded_annotation a
    131      * sub-annotation, in the format specified by "encoded_annotation Format"
    132      * below. The size of the value is implicit in the encoding.
    133      */
    134     private Object getAnnotationValue(int valueArg) {
    135         // use the buffer directly to get adjusted offset
    136         return new DexEncodedAnnotationImpl(buffer, annotation, typeIds,
    137                 stringPool, fieldIdItems);
    138     }
    139 
    140     /**
    141      * VALUE_ARRAY 0x1c (none; must be 0) encoded_array an array of values, in
    142      * the format specified by "encoded_array Format" below. The size of the
    143      * value is implicit in the encoding.
    144      */
    145     private List<DexEncodedValue> getArrayValue(int valueArg) {
    146         int size = buffer.readUleb128();
    147         List<DexEncodedValue> values = new ArrayList<DexEncodedValue>(size);
    148         for (int i = 0; i < size; i++) {
    149             values.add(new DexEncodedValueImpl(buffer, annotation, typeIds,
    150                     stringPool, fieldIdItems));
    151         }
    152         return values;
    153     }
    154 
    155     /**
    156      * VALUE_ENUM 0x1b size - 1 (0...3) ubyte[size] unsigned (zero-extended)
    157      * four-byte integer value, interpreted as an index into the field_ids
    158      * section and representing the value of an enumerated type constant
    159      */
    160     private Object getEnumValue(int valueArg) {
    161         int fieldOffset = buffer.readInt(valueArg + 1);
    162         FieldIdItem fieldIdItem = fieldIdItems[fieldOffset];
    163         // FORMAT La/b/E;!CONSTANT
    164         String constantName = stringPool[fieldIdItem.name_idx];
    165         String typeName = stringPool[typeIds[fieldIdItem.type_idx]];
    166         return typeName + "!" + constantName;
    167     }
    168 
    169     /**
    170      * VALUE_METHOD 0x1a size - 1 (0...3) ubyte[size] unsigned (zero-extended)
    171      * four-byte integer value, interpreted as an index into the method_ids
    172      * section and representing a reflective method value
    173      */
    174     private Object getMethodValue(int valueArg) {
    175         // FIXME lookup value
    176         buffer.skip(valueArg + 1);
    177         return null;
    178     }
    179 
    180     /**
    181      * VALUE_FIELD 0x19 size - 1 (0...3) ubyte[size] unsigned (zero-extended)
    182      * four-byte integer value, interpreted as an index into the field_ids
    183      * section and representing a reflective field value
    184      */
    185     private Object getFieldValue(int valueArg) {
    186         int fieldOffset = buffer.readInt(valueArg + 1);
    187         FieldIdItem fieldIdItem = fieldIdItems[fieldOffset];
    188         // FORMAT La/b/E;!CONSTANT
    189         String fieldName = stringPool[fieldIdItem.name_idx];
    190         String typeName = stringPool[typeIds[fieldIdItem.type_idx]];
    191         return typeName + "!" + fieldName;
    192     }
    193 
    194     /**
    195      * VALUE_TYPE 0x18 size - 1 (0...3) ubyte[size] unsigned (zero-extended)
    196      * four-byte integer value, interpreted as an index into the type_ids
    197      * section and representing a reflective type/class value
    198      */
    199     private Object getTypeValue(int valueArg) {
    200         valueArg++; // size - 1 (0...3)
    201         // FIXME SPEC!! states: unsigned (zero-extended) four-byte integer value
    202         return stringPool[typeIds[buffer.readInt(valueArg)]];
    203     }
    204 
    205     /**
    206      * VALUE_STRING 0x17 size - 1 (0...3) ubyte[size] unsigned (zero-extended)
    207      * four-byte integer value, interpreted as an index into the string_ids
    208      * section and representing a string value
    209      */
    210     private Object getStringValue(int valueArg) {
    211         valueArg++;
    212         return stringPool[buffer.readInt(valueArg)];
    213     }
    214 
    215     /**
    216      * VALUE_DOUBLE 0x11 size - 1 (0...7) ubyte[size] eight-byte bit pattern,
    217      * zero-extended to the right, and interpreted as an IEEE754 64-bit floating
    218      * point value
    219      */
    220     private Object getDoubleValue(int valueArg) {
    221         return buffer.readDouble(valueArg + 1);
    222     }
    223 
    224     /**
    225      * VALUE_FLOAT 0x10 size - 1 (0...3) ubyte[size] four-byte bit pattern,
    226      * zero-extended to the right, and interpreted as an IEEE754 32-bit floating
    227      * point value
    228      */
    229     private Float getFloatValue(int valueArg) {
    230         return buffer.readFloat(valueArg + 1);
    231     }
    232 
    233     /**
    234      * VALUE_LONG 0x06 size - 1 (0...7) ubyte[size] signed eight-byte integer
    235      * value, sign-extended
    236      */
    237     private Long getLongValue(int valueArg) {
    238         return buffer.readLong(valueArg + 1);
    239     }
    240 
    241     /**
    242      * VALUE_INT 0x04 size - 1 (0...3) ubyte[size] signed four-byte integer
    243      * value, sign-extended
    244      */
    245     private Integer getIntValue(int valueArg) {
    246         return buffer.readInt(valueArg + 1);
    247     }
    248 
    249     /**
    250      * VALUE_CHAR 0x03 size - 1 (0...1) ubyte[size] unsigned two-byte integer
    251      * value, zero-extended
    252      */
    253     private Character getCharValue(int valueArg) {
    254         return buffer.readChar(valueArg + 1);
    255     }
    256 
    257     /**
    258      * VALUE_SHORT 0x02 size - 1 (0...1) ubyte[size] signed two-byte integer
    259      * value, sign-extended
    260      */
    261     private Short getShortValue(int valueArg) {
    262         return buffer.readShort(valueArg + 1);
    263     }
    264 
    265     /**
    266      * VALUE_BYTE 0x00 (none; must be 0) ubyte[1] signed one-byte integer value
    267      */
    268     private Byte getByteValue(int valueArg) {
    269         assert valueArg == 0 : "Illegal valueArg for VALUE_BYTE: " + valueArg;
    270         return null;
    271     }
    272 
    273     public DexEncodedValueType getType() {
    274         return type;
    275     }
    276 
    277     public Object getValue() {
    278         return value;
    279     }
    280 
    281     @Override
    282     public String toString() {
    283         StringBuilder builder = new StringBuilder();
    284         builder.append("=");
    285         if (type == VALUE_ARRAY) {
    286             if (getValue() instanceof List<?>) {
    287                 List<?> values = (List<?>) getValue();
    288                 for (Object object : values) {
    289                     DexEncodedValue val = (DexEncodedValue) object;
    290                     builder.append(val.getValue());
    291                 }
    292             }
    293         } else {
    294             builder.append(getValue());
    295         }
    296         return builder.toString();
    297     }
    298 }
    299