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      */
DexEncodedValueImpl(DexBuffer buffer, DexAnnotation annotation, int[] typeIds, String[] stringPool, FieldIdItem[] fieldIdItems)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 
parseValue()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      */
getBooleanValue(int valueArg)120     private Boolean getBooleanValue(int valueArg) {
121         return valueArg == 1;
122     }
123 
124     /** VALUE_NULL 0x1e (none; must be 0) (none) null reference value */
getNullValue(int valueArg)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      */
getAnnotationValue(int valueArg)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      */
getArrayValue(int valueArg)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      */
getEnumValue(int valueArg)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      */
getMethodValue(int valueArg)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      */
getFieldValue(int valueArg)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      */
getTypeValue(int valueArg)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      */
getStringValue(int valueArg)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      */
getDoubleValue(int valueArg)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      */
getFloatValue(int valueArg)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      */
getLongValue(int valueArg)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      */
getIntValue(int valueArg)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      */
getCharValue(int valueArg)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      */
getShortValue(int valueArg)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      */
getByteValue(int valueArg)268     private Byte getByteValue(int valueArg) {
269         assert valueArg == 0 : "Illegal valueArg for VALUE_BYTE: " + valueArg;
270         return null;
271     }
272 
getType()273     public DexEncodedValueType getType() {
274         return type;
275     }
276 
getValue()277     public Object getValue() {
278         return value;
279     }
280 
281     @Override
toString()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