1/*
2 * Copyright (C) 2011 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
17package com.android.dex;
18
19import com.android.dex.util.ByteInput;
20
21/**
22 * Pull parser for encoded values.
23 */
24public final class EncodedValueReader {
25    public static final int ENCODED_BYTE = 0x00;
26    public static final int ENCODED_SHORT = 0x02;
27    public static final int ENCODED_CHAR = 0x03;
28    public static final int ENCODED_INT = 0x04;
29    public static final int ENCODED_LONG = 0x06;
30    public static final int ENCODED_FLOAT = 0x10;
31    public static final int ENCODED_DOUBLE = 0x11;
32    public static final int ENCODED_METHOD_TYPE = 0x15;
33    public static final int ENCODED_METHOD_HANDLE = 0x16;
34    public static final int ENCODED_STRING = 0x17;
35    public static final int ENCODED_TYPE = 0x18;
36    public static final int ENCODED_FIELD = 0x19;
37    public static final int ENCODED_ENUM = 0x1b;
38    public static final int ENCODED_METHOD = 0x1a;
39    public static final int ENCODED_ARRAY = 0x1c;
40    public static final int ENCODED_ANNOTATION = 0x1d;
41    public static final int ENCODED_NULL = 0x1e;
42    public static final int ENCODED_BOOLEAN = 0x1f;
43
44    /** placeholder type if the type is not yet known */
45    private static final int MUST_READ = -1;
46
47    protected final ByteInput in;
48    private int type = MUST_READ;
49    private int annotationType;
50    private int arg;
51
52    public EncodedValueReader(ByteInput in) {
53        this.in = in;
54    }
55
56    public EncodedValueReader(EncodedValue in) {
57        this(in.asByteInput());
58    }
59
60    /**
61     * Creates a new encoded value reader whose only value is the specified
62     * known type. This is useful for encoded values without a type prefix,
63     * such as class_def_item's encoded_array or annotation_item's
64     * encoded_annotation.
65     */
66    public EncodedValueReader(ByteInput in, int knownType) {
67        this.in = in;
68        this.type = knownType;
69    }
70
71    public EncodedValueReader(EncodedValue in, int knownType) {
72        this(in.asByteInput(), knownType);
73    }
74
75    /**
76     * Returns the type of the next value to read.
77     */
78    public int peek() {
79        if (type == MUST_READ) {
80            int argAndType = in.readByte() & 0xff;
81            type = argAndType & 0x1f;
82            arg = (argAndType & 0xe0) >> 5;
83        }
84        return type;
85    }
86
87    /**
88     * Begins reading the elements of an array, returning the array's size. The
89     * caller must follow up by calling a read method for each element in the
90     * array. For example, this reads a byte array: <pre>   {@code
91     *   int arraySize = readArray();
92     *   for (int i = 0, i < arraySize; i++) {
93     *     readByte();
94     *   }
95     * }</pre>
96     */
97    public int readArray() {
98        checkType(ENCODED_ARRAY);
99        type = MUST_READ;
100        return Leb128.readUnsignedLeb128(in);
101    }
102
103    /**
104     * Begins reading the fields of an annotation, returning the number of
105     * fields. The caller must follow up by making alternating calls to {@link
106     * #readAnnotationName()} and another read method. For example, this reads
107     * an annotation whose fields are all bytes: <pre>   {@code
108     *   int fieldCount = readAnnotation();
109     *   int annotationType = getAnnotationType();
110     *   for (int i = 0; i < fieldCount; i++) {
111     *       readAnnotationName();
112     *       readByte();
113     *   }
114     * }</pre>
115     */
116    public int readAnnotation() {
117        checkType(ENCODED_ANNOTATION);
118        type = MUST_READ;
119        annotationType = Leb128.readUnsignedLeb128(in);
120        return Leb128.readUnsignedLeb128(in);
121    }
122
123    /**
124     * Returns the type of the annotation just returned by {@link
125     * #readAnnotation()}. This method's value is undefined unless the most
126     * recent call was to {@link #readAnnotation()}.
127     */
128    public int getAnnotationType() {
129        return annotationType;
130    }
131
132    public int readAnnotationName() {
133        return Leb128.readUnsignedLeb128(in);
134    }
135
136    public byte readByte() {
137        checkType(ENCODED_BYTE);
138        type = MUST_READ;
139        return (byte) EncodedValueCodec.readSignedInt(in, arg);
140    }
141
142    public short readShort() {
143        checkType(ENCODED_SHORT);
144        type = MUST_READ;
145        return (short) EncodedValueCodec.readSignedInt(in, arg);
146    }
147
148    public char readChar() {
149        checkType(ENCODED_CHAR);
150        type = MUST_READ;
151        return (char) EncodedValueCodec.readUnsignedInt(in, arg, false);
152    }
153
154    public int readInt() {
155        checkType(ENCODED_INT);
156        type = MUST_READ;
157        return EncodedValueCodec.readSignedInt(in, arg);
158    }
159
160    public long readLong() {
161        checkType(ENCODED_LONG);
162        type = MUST_READ;
163        return EncodedValueCodec.readSignedLong(in, arg);
164    }
165
166    public float readFloat() {
167        checkType(ENCODED_FLOAT);
168        type = MUST_READ;
169        return Float.intBitsToFloat(EncodedValueCodec.readUnsignedInt(in, arg, true));
170    }
171
172    public double readDouble() {
173        checkType(ENCODED_DOUBLE);
174        type = MUST_READ;
175        return Double.longBitsToDouble(EncodedValueCodec.readUnsignedLong(in, arg, true));
176    }
177
178    public int readMethodType() {
179        checkType(ENCODED_METHOD_TYPE);
180        type = MUST_READ;
181        return EncodedValueCodec.readUnsignedInt(in, arg, false);
182    }
183
184    public int readMethodHandle() {
185        checkType(ENCODED_METHOD_HANDLE);
186        type = MUST_READ;
187        return EncodedValueCodec.readUnsignedInt(in, arg, false);
188    }
189
190    public int readString() {
191        checkType(ENCODED_STRING);
192        type = MUST_READ;
193        return EncodedValueCodec.readUnsignedInt(in, arg, false);
194    }
195
196    public int readType() {
197        checkType(ENCODED_TYPE);
198        type = MUST_READ;
199        return EncodedValueCodec.readUnsignedInt(in, arg, false);
200    }
201
202    public int readField() {
203        checkType(ENCODED_FIELD);
204        type = MUST_READ;
205        return EncodedValueCodec.readUnsignedInt(in, arg, false);
206    }
207
208    public int readEnum() {
209        checkType(ENCODED_ENUM);
210        type = MUST_READ;
211        return EncodedValueCodec.readUnsignedInt(in, arg, false);
212    }
213
214    public int readMethod() {
215        checkType(ENCODED_METHOD);
216        type = MUST_READ;
217        return EncodedValueCodec.readUnsignedInt(in, arg, false);
218    }
219
220    public void readNull() {
221        checkType(ENCODED_NULL);
222        type = MUST_READ;
223    }
224
225    public boolean readBoolean() {
226        checkType(ENCODED_BOOLEAN);
227        type = MUST_READ;
228        return arg != 0;
229    }
230
231    /**
232     * Skips a single value, including its nested values if it is an array or
233     * annotation.
234     */
235    public void skipValue() {
236        switch (peek()) {
237        case ENCODED_BYTE:
238            readByte();
239            break;
240        case ENCODED_SHORT:
241            readShort();
242            break;
243        case ENCODED_CHAR:
244            readChar();
245            break;
246        case ENCODED_INT:
247            readInt();
248            break;
249        case ENCODED_LONG:
250            readLong();
251            break;
252        case ENCODED_FLOAT:
253            readFloat();
254            break;
255        case ENCODED_DOUBLE:
256            readDouble();
257            break;
258        case ENCODED_METHOD_TYPE:
259            readMethodType();
260            break;
261        case ENCODED_METHOD_HANDLE:
262            readMethodHandle();
263            break;
264        case ENCODED_STRING:
265            readString();
266            break;
267        case ENCODED_TYPE:
268            readType();
269            break;
270        case ENCODED_FIELD:
271            readField();
272            break;
273        case ENCODED_ENUM:
274            readEnum();
275            break;
276        case ENCODED_METHOD:
277            readMethod();
278            break;
279        case ENCODED_ARRAY:
280            for (int i = 0, size = readArray(); i < size; i++) {
281                skipValue();
282            }
283            break;
284        case ENCODED_ANNOTATION:
285            for (int i = 0, size = readAnnotation(); i < size; i++) {
286                readAnnotationName();
287                skipValue();
288            }
289            break;
290        case ENCODED_NULL:
291            readNull();
292            break;
293        case ENCODED_BOOLEAN:
294            readBoolean();
295            break;
296        default:
297            throw new DexException("Unexpected type: " + Integer.toHexString(type));
298        }
299    }
300
301    private void checkType(int expected) {
302        if (peek() != expected) {
303            throw new IllegalStateException(
304                    String.format("Expected %x but was %x", expected, peek()));
305        }
306    }
307}
308