1/* 2 * [The "BSD licence"] 3 * Copyright (c) 2010 Ben Gruver (JesusFreke) 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.DexFile; 34import org.jf.dexlib.Util.AnnotatedOutput; 35import org.jf.dexlib.Util.NumberUtils; 36 37import java.util.Iterator; 38 39public class ArrayDataPseudoInstruction extends Instruction { 40 public static final Instruction.InstructionFactory Factory = new Factory(); 41 private int elementWidth; 42 private byte[] encodedValues; 43 44 @Override 45 public int getSize(int codeAddress) { 46 return ((encodedValues.length + 1)/2) + 4 + (codeAddress % 2); 47 } 48 49 public ArrayDataPseudoInstruction(int elementWidth, byte[] encodedValues) { 50 super(Opcode.NOP); 51 52 if (encodedValues.length % elementWidth != 0) { 53 throw new RuntimeException("There are not a whole number of " + elementWidth + " byte elements"); 54 } 55 56 this.elementWidth = elementWidth; 57 this.encodedValues = encodedValues; 58 } 59 60 public ArrayDataPseudoInstruction(byte[] buffer, int bufferIndex) { 61 super(Opcode.NOP); 62 63 byte opcodeByte = buffer[bufferIndex]; 64 if (opcodeByte != 0x00) { 65 throw new RuntimeException("Invalid opcode byte for an ArrayData pseudo-instruction"); 66 } 67 68 byte subopcodeByte = buffer[bufferIndex+1]; 69 if (subopcodeByte != 0x03) { 70 throw new RuntimeException("Invalid sub-opcode byte for an ArrayData pseudo-instruction"); 71 } 72 73 this.elementWidth = NumberUtils.decodeUnsignedShort(buffer, bufferIndex+2); 74 int elementCount = NumberUtils.decodeInt(buffer, bufferIndex+4); 75 this.encodedValues = new byte[elementCount * elementWidth]; 76 System.arraycopy(buffer, bufferIndex+8, encodedValues, 0, elementCount * elementWidth); 77 } 78 79 protected void writeInstruction(AnnotatedOutput out, int currentCodeAddress) { 80 out.alignTo(4); 81 82 int elementCount = encodedValues.length / elementWidth; 83 84 out.writeByte(0x00); 85 out.writeByte(0x03); 86 out.writeShort(elementWidth); 87 out.writeInt(elementCount); 88 out.write(encodedValues); 89 90 //make sure we're written out an even number of bytes 91 out.alignTo(2); 92 } 93 94 protected void annotateInstruction(AnnotatedOutput out, int currentCodeAddress) { 95 out.annotate(getSize(currentCodeAddress)*2, "[0x" + Integer.toHexString(currentCodeAddress) + "] " + 96 "fill-array-data instruction"); 97 } 98 99 public Format getFormat() { 100 return Format.ArrayData; 101 } 102 103 public int getElementWidth() { 104 return elementWidth; 105 } 106 107 public int getElementCount() { 108 return encodedValues.length / elementWidth; 109 } 110 111 public static class ArrayElement { 112 public final byte[] buffer; 113 public int bufferIndex; 114 public final int elementWidth; 115 public ArrayElement(byte[] buffer, int elementWidth) { 116 this.buffer = buffer; 117 this.elementWidth = elementWidth; 118 } 119 } 120 121 public Iterator<ArrayElement> getElements() { 122 return new Iterator<ArrayElement>() { 123 final int elementCount = getElementCount(); 124 int i=0; 125 int position=0; 126 final ArrayElement arrayElement = new ArrayElement(encodedValues, getElementWidth()); 127 128 public boolean hasNext() { 129 return i<elementCount; 130 } 131 132 public ArrayElement next() { 133 arrayElement.bufferIndex = position; 134 position += arrayElement.elementWidth; 135 i++; 136 return arrayElement; 137 } 138 139 public void remove() { 140 } 141 }; 142 } 143 144 private static class Factory implements Instruction.InstructionFactory { 145 public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { 146 if (opcode != Opcode.NOP) { 147 throw new RuntimeException("The opcode for an ArrayDataPseudoInstruction must be NOP"); 148 } 149 return new ArrayDataPseudoInstruction(buffer, bufferIndex); 150 } 151 } 152} 153