ArrayDataPseudoInstruction.java revision fda2e631ac0b1ca092973b7fff4b2f38d2c23437
1/* 2 * [The "BSD licence"] 3 * Copyright (c) 2009 Ben Gruver 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29package org.jf.dexlib.Code.Format; 30 31import org.jf.dexlib.Code.Instruction; 32import org.jf.dexlib.Code.Opcode; 33import org.jf.dexlib.Util.NumberUtils; 34import org.jf.dexlib.Util.AnnotatedOutput; 35import org.jf.dexlib.DexFile; 36import java.util.Iterator; 37 38public class ArrayDataPseudoInstruction extends Instruction { 39 public static final Instruction.InstructionFactory Factory = new Factory(); 40 private int elementWidth; 41 private byte[] encodedValues; 42 43 @Override 44 public int getSize(int offset) { 45 assert offset % 2 == 0; 46 int size = getElementWidth() * getElementCount(); 47 return size + (size & 0x01) + 8 + (offset % 4); 48 } 49 50 public ArrayDataPseudoInstruction(int elementWidth, byte[] encodedValues) { 51 super(Opcode.NOP); 52 53 if (encodedValues.length % elementWidth != 0) { 54 throw new RuntimeException("There are not a whole number of " + elementWidth + " byte elements"); 55 } 56 57 this.elementWidth = elementWidth; 58 this.encodedValues = encodedValues; 59 } 60 61 public ArrayDataPseudoInstruction(byte[] buffer, int bufferIndex) { 62 super(Opcode.NOP); 63 64 byte opcodeByte = buffer[bufferIndex]; 65 if (opcodeByte != 0x00) { 66 throw new RuntimeException("Invalid opcode byte for an ArrayData pseudo-instruction"); 67 } 68 69 byte subopcodeByte = buffer[bufferIndex+1]; 70 if (subopcodeByte != 0x03) { 71 throw new RuntimeException("Invalid sub-opcode byte for an ArrayData pseudo-instruction"); 72 } 73 74 this.elementWidth = NumberUtils.decodeUnsignedShort(buffer, bufferIndex+2); 75 int elementCount = NumberUtils.decodeInt(buffer, bufferIndex+4); 76 this.encodedValues = new byte[elementCount * elementWidth]; 77 System.arraycopy(buffer, bufferIndex+8, encodedValues, 0, elementCount * elementWidth); 78 } 79 80 protected void writeInstruction(AnnotatedOutput out, int currentCodeOffset) { 81 //write out padding, if necessary 82 if (out.getCursor() % 4 != 0) { 83 out.writeShort(0); 84 } 85 86 int elementCount = encodedValues.length / elementWidth; 87 88 out.writeByte(0x00); 89 out.writeByte(0x03); 90 out.writeShort(elementWidth); 91 out.writeInt(elementCount); 92 out.write(encodedValues); 93 if ((encodedValues.length % 2) != 0) { 94 //must write out an even number of bytes 95 out.writeByte(0); 96 } 97 } 98 99 protected void annotateInstruction(AnnotatedOutput out, int currentCodeOffset) { 100 out.annotate(getSize(currentCodeOffset), "[0x" + Integer.toHexString(currentCodeOffset/2) + "] " + 101 "fill-array-data instruction"); 102 } 103 104 public Format getFormat() { 105 return Format.ArrayData; 106 } 107 108 public int getElementWidth() { 109 return elementWidth; 110 } 111 112 public int getElementCount() { 113 return encodedValues.length / elementWidth; 114 } 115 116 public static class ArrayElement { 117 public final byte[] buffer; 118 public int bufferIndex; 119 public final int elementWidth; 120 public ArrayElement(byte[] buffer, int elementWidth) { 121 this.buffer = buffer; 122 this.elementWidth = elementWidth; 123 } 124 } 125 126 public Iterator<ArrayElement> getElements() { 127 return new Iterator<ArrayElement>() { 128 final int elementCount = getElementCount(); 129 int i=0; 130 int position=0; 131 final ArrayElement arrayElement = new ArrayElement(encodedValues, getElementWidth()); 132 133 public boolean hasNext() { 134 return i<elementCount; 135 } 136 137 public ArrayElement next() { 138 arrayElement.bufferIndex = position; 139 position += arrayElement.elementWidth; 140 i++; 141 return arrayElement; 142 } 143 144 public void remove() { 145 } 146 }; 147 } 148 149 private static class Factory implements Instruction.InstructionFactory { 150 public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { 151 if (opcode != Opcode.NOP) { 152 throw new RuntimeException("The opcode for an ArrayDataPseudoInstruction must by NOP"); 153 } 154 return new ArrayDataPseudoInstruction(buffer, bufferIndex); 155 } 156 } 157} 158