DexBackedArrayPayload.java revision c307c1887d0c57e2213d5146cedec2307251e9fa
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.instruction;
33
34import org.jf.dexlib2.Opcode;
35import org.jf.dexlib2.dexbacked.DexBuffer;
36import org.jf.dexlib2.dexbacked.util.FixedSizeList;
37import org.jf.dexlib2.iface.instruction.formats.ArrayPayload;
38import org.jf.util.ExceptionWithContext;
39
40import javax.annotation.Nonnull;
41import java.util.List;
42
43public class DexBackedArrayPayload implements ArrayPayload {
44    public static final Opcode OPCODE = Opcode.ARRAY_PAYLOAD;
45
46    @Nonnull public final DexBuffer dexBuf;
47    private final int instructionOffset;
48
49    public final int elementWidth;
50    public final int elementCount;
51
52    private static final int ELEMENT_WIDTH_OFFSET = 2;
53    private static final int ELEMENT_COUNT_OFFSET = 4;
54    private static final int ELEMENTS_OFFSET = 8;
55
56    public DexBackedArrayPayload(DexBuffer dexBuf,
57                                 int instructionOffset) {
58        this.dexBuf = dexBuf;
59        this.instructionOffset = instructionOffset;
60
61        this.elementWidth = dexBuf.readUshort(instructionOffset + ELEMENT_WIDTH_OFFSET);
62        this.elementCount = dexBuf.readSmallUint(instructionOffset + ELEMENT_COUNT_OFFSET);
63    }
64
65    @Override public int getElementWidth() { return elementWidth; }
66
67    @Nonnull
68    @Override
69    public List<Number> getArrayElements() {
70        final int elementsStart = instructionOffset + ELEMENTS_OFFSET;
71
72        abstract class ReturnedList extends FixedSizeList<Number> {
73            @Override public int size() { return elementCount; }
74        }
75
76        switch (elementWidth) {
77            case 1:
78                return new ReturnedList() {
79                    @Nonnull
80                    @Override
81                    public Number readItem(int index) {
82                        return dexBuf.readByte(elementsStart + index);
83                    }
84                };
85            case 2:
86                return new ReturnedList() {
87                    @Nonnull
88                    @Override
89                    public Number readItem(int index) {
90                        return dexBuf.readShort(elementsStart + index*2);
91                    }
92                };
93            case 4:
94                return new ReturnedList() {
95                    @Nonnull
96                    @Override
97                    public Number readItem(int index) {
98                        return dexBuf.readInt(elementsStart + index*4);
99                    }
100                };
101            case 8:
102                return new ReturnedList() {
103                    @Nonnull
104                    @Override
105                    public Number readItem(int index) {
106                        return dexBuf.readLong(elementsStart + index*8);
107                    }
108                };
109            default:
110                throw new ExceptionWithContext("Invalid element width: %d", elementWidth);
111        }
112    }
113
114    @Override
115    public int getCodeUnits() {
116        return 4 + (elementWidth*elementCount + 1) / 2;
117    }
118
119    @Override public Opcode getOpcode() { return OPCODE; }
120}
121