DexBackedEncodedValue.java revision 22c3185bb7c8618437eabe6c597549e0989ec4e6
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
32package org.jf.dexlib2.dexbacked.value;
33
34import org.jf.dexlib2.ValueType;
35import org.jf.dexlib2.dexbacked.DexReader;
36import org.jf.dexlib2.iface.value.EncodedValue;
37import org.jf.dexlib2.immutable.value.*;
38import org.jf.dexlib2.util.Preconditions;
39import org.jf.util.ExceptionWithContext;
40
41import javax.annotation.Nonnull;
42
43public abstract class DexBackedEncodedValue {
44    @Nonnull
45    public static EncodedValue readFrom(@Nonnull DexReader reader) {
46        int startOffset = reader.getOffset();
47
48        try {
49            int b = reader.readUbyte();
50            int valueType = b & 0x1f;
51            int valueArg = b >>> 5;
52
53            switch (valueType) {
54                case ValueType.BYTE:
55                    Preconditions.checkValueArg(valueArg, 0);
56                    return new ImmutableByteEncodedValue((byte)reader.readByte());
57                case ValueType.SHORT:
58                    Preconditions.checkValueArg(valueArg, 1);
59                    return new ImmutableShortEncodedValue((short)reader.readSizedInt(valueArg + 1));
60                case ValueType.CHAR:
61                    Preconditions.checkValueArg(valueArg, 1);
62                    return new ImmutableCharEncodedValue((char)reader.readSizedSmallUint(valueArg + 1));
63                case ValueType.INT:
64                    Preconditions.checkValueArg(valueArg, 3);
65                    return new ImmutableIntEncodedValue(reader.readSizedInt(valueArg + 1));
66                case ValueType.LONG:
67                    Preconditions.checkValueArg(valueArg, 7);
68                    return new ImmutableLongEncodedValue(reader.readSizedLong(valueArg + 1));
69                case ValueType.FLOAT:
70                    Preconditions.checkValueArg(valueArg, 3);
71                    return new ImmutableFloatEncodedValue(Float.intBitsToFloat(
72                            reader.readSizedRightExtendedInt(valueArg + 1)));
73                case ValueType.DOUBLE:
74                    Preconditions.checkValueArg(valueArg, 7);
75                    return new ImmutableDoubleEncodedValue(Double.longBitsToDouble(
76                            reader.readSizedRightExtendedLong(valueArg + 1)));
77                case ValueType.STRING:
78                    Preconditions.checkValueArg(valueArg, 3);
79                    return new DexBackedStringEncodedValue(reader, valueArg);
80                case ValueType.TYPE:
81                    Preconditions.checkValueArg(valueArg, 3);
82                    return new ImmutableTypeEncodedValue(reader.getType(reader.readSizedSmallUint(valueArg + 1)));
83                case ValueType.FIELD:
84                    Preconditions.checkValueArg(valueArg, 3);
85                    return new DexBackedFieldEncodedValue(reader, valueArg);
86                case ValueType.METHOD:
87                    Preconditions.checkValueArg(valueArg, 3);
88                    return new DexBackedMethodEncodedValue(reader, valueArg);
89                case ValueType.ENUM:
90                    Preconditions.checkValueArg(valueArg, 3);
91                    return new DexBackedEnumEncodedValue(reader, valueArg);
92                case ValueType.ARRAY:
93                    Preconditions.checkValueArg(valueArg, 0);
94                    return new DexBackedArrayEncodedValue(reader);
95                case ValueType.ANNOTATION:
96                    Preconditions.checkValueArg(valueArg, 0);
97                    return new DexBackedAnnotationEncodedValue(reader);
98                case ValueType.NULL:
99                    Preconditions.checkValueArg(valueArg, 0);
100                    return ImmutableNullEncodedValue.INSTANCE;
101                case ValueType.BOOLEAN:
102                    Preconditions.checkValueArg(valueArg, 1);
103                    return new ImmutableBooleanEncodedValue(valueArg == 1);
104                default:
105                    throw new ExceptionWithContext("Invalid encoded_value type: 0x%x", valueType);
106            }
107        } catch (Exception ex) {
108            throw ExceptionWithContext.withContext(ex, "Error while reading encoded value at offset 0x%x", startOffset);
109        }
110    }
111
112    public static void skipFrom(@Nonnull DexReader reader) {
113        int startOffset = reader.getOffset();
114
115        try {
116            int b = reader.readUbyte();
117            int valueType = b & 0x1f;
118
119            switch (valueType) {
120                case ValueType.BYTE:
121                    reader.skipByte();
122                    break;
123                case ValueType.SHORT:
124                case ValueType.CHAR:
125                case ValueType.INT:
126                case ValueType.LONG:
127                case ValueType.FLOAT:
128                case ValueType.DOUBLE:
129                case ValueType.STRING:
130                case ValueType.TYPE:
131                case ValueType.FIELD:
132                case ValueType.METHOD:
133                case ValueType.ENUM:
134                    int valueArg = b >>> 5;
135                    reader.moveRelative(valueArg+1);
136                    break;
137                case ValueType.ARRAY:
138                    DexBackedArrayEncodedValue.skipFrom(reader);
139                    break;
140                case ValueType.ANNOTATION:
141                    DexBackedAnnotationEncodedValue.skipFrom(reader);
142                    break;
143                case ValueType.NULL:
144                case ValueType.BOOLEAN:
145                    break;
146                default:
147                    throw new ExceptionWithContext("Invalid encoded_value type: 0x%x", valueType);
148            }
149        } catch (Exception ex) {
150            throw ExceptionWithContext.withContext(ex, "Error while skipping encoded value at offset 0x%x",
151                    startOffset);
152        }
153    }
154}
155