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