ArrayDataPseudoInstruction.java revision 3c48a886bd0175660de04f3cb77d6308742d7bad
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.Output; 35import org.jf.dexlib.DexFile; 36 37import java.util.Iterator; 38 39public class ArrayDataPseudoInstruction extends Instruction { 40 public static final Instruction.InstructionFactory Factory = new Factory(); 41 42 @Override 43 public int getSize() { 44 int size = getElementWidth() * getElementCount(); 45 return size + (size & 0x01) + 8; 46 } 47 48 public static void emit(Output out, int elementWidth, byte[] encodedValues) { 49 if (encodedValues.length % elementWidth != 0) { 50 throw new RuntimeException("There are not a whole number of " + elementWidth + " byte elements"); 51 } 52 53 //write out padding, if necessary 54 if (out.getCursor() % 4 != 0) { 55 out.writeShort(0); 56 } 57 58 int elementCount = encodedValues.length / elementWidth; 59 60 out.writeByte(0x00); 61 out.writeByte(0x03); 62 out.writeShort(elementWidth); 63 out.writeInt(elementCount); 64 out.write(encodedValues); 65 } 66 67 public ArrayDataPseudoInstruction(byte[] buffer, int bufferIndex) { 68 super(Opcode.NOP, buffer, bufferIndex); 69 70 byte opcodeByte = buffer[bufferIndex++]; 71 if (opcodeByte != 0x00) { 72 throw new RuntimeException("Invalid opcode byte for an ArrayData pseudo-instruction"); 73 } 74 75 byte subopcodeByte = buffer[bufferIndex]; 76 if (subopcodeByte != 0x03) { 77 throw new RuntimeException("Invalid sub-opcode byte for an ArrayData pseudo-instruction"); 78 } 79 } 80 81 public Format getFormat() { 82 return Format.ArrayData; 83 } 84 85 public int getElementWidth() { 86 return NumberUtils.decodeUnsignedShort(buffer[bufferIndex+2], buffer[bufferIndex+3]); 87 } 88 89 public int getElementCount() { 90 return NumberUtils.decodeInt(buffer, bufferIndex+4); 91 } 92 93 public static class ArrayElement { 94 public final byte[] buffer; 95 public int bufferIndex; 96 public final int elementWidth; 97 public ArrayElement(byte[] buffer, int elementWidth) { 98 this.buffer = buffer; 99 this.elementWidth = elementWidth; 100 } 101 } 102 103 public Iterator<ArrayElement> getElements() { 104 return new Iterator<ArrayElement>() { 105 final int elementCount = getElementCount(); 106 int i=0; 107 int position = bufferIndex + 8; 108 final ArrayElement arrayElement = new ArrayElement(buffer, getElementWidth()); 109 110 public boolean hasNext() { 111 return i<elementCount; 112 } 113 114 public ArrayElement next() { 115 arrayElement.bufferIndex = position; 116 position += arrayElement.elementWidth; 117 i++; 118 return arrayElement; 119 } 120 121 public void remove() { 122 } 123 }; 124 } 125 126 private static class Factory implements Instruction.InstructionFactory { 127 public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { 128 if (opcode != Opcode.NOP) { 129 throw new RuntimeException("The opcode for an ArrayDataPseudoInstruction must by NOP"); 130 } 131 return new ArrayDataPseudoInstruction(buffer, bufferIndex); 132 } 133 } 134} 135