diff --git a/dexlib2/src/main/java/org/jf/dexlib2/Format.java b/dexlib2/src/main/java/org/jf/dexlib2/Format.java index 198d24d3..a1d22ae1 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/Format.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/Format.java @@ -63,20 +63,20 @@ public enum Format { Format3rmi(6), Format3rms(6), Format51l(10), - ArrayData(-1, true), - PackedSwitchData(-1, true), - SparseSwitchData(-1, true), - UnresolvedOdexInstruction(-1, false); + ArrayPayload(-1, true), + PackedSwitchPayload(-1, true), + SparseSwitchPayload(-1, true), + UnresolvedOdexInstruction(-1); public final int size; - public final boolean variableSizeFormat; + public final boolean payloadFormat; private Format(int size) { this(size, false); } - private Format(int size, boolean variableSizeFormat) { + private Format(int size, boolean payloadFormat) { this.size = size; - this.variableSizeFormat = variableSizeFormat; + this.payloadFormat = payloadFormat; } } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/Opcode.java b/dexlib2/src/main/java/org/jf/dexlib2/Opcode.java index ab21eb3d..e9635f83 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/Opcode.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/Opcode.java @@ -283,7 +283,11 @@ public enum Opcode IPUT_OBJECT_VOLATILE((short)0xfc, "iput-object-volatile", ReferenceType.FIELD, Format.Format22c, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE), SGET_OBJECT_VOLATILE((short)0xfd, "sget-object-volatile", ReferenceType.FIELD, Format.Format21c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), - SPUT_OBJECT_VOLATILE((short)0xfe, "sput-object-volatile", ReferenceType.FIELD, Format.Format21c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE); + SPUT_OBJECT_VOLATILE((short)0xfe, "sput-object-volatile", ReferenceType.FIELD, Format.Format21c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE), + + PACKED_SWITCH_PAYLOAD((short)0x100, "packed-switch-payload", ReferenceType.NONE, Format.PackedSwitchPayload, 0), + SPARSE_SWITCH_PAYLOAD((short)0x200, "sparse-switch-payload", ReferenceType.NONE, Format.SparseSwitchPayload, 0), + ARRAY_PAYLOAD((short)0x300, "array-payload", ReferenceType.NONE, Format.ArrayPayload, 0); private static final Opcode[] opcodesByValue; private static final HashMap opcodesByName; @@ -316,10 +320,12 @@ public enum Opcode opcodesByName = new HashMap(); for (Opcode opcode: Opcode.values()) { - //INVOKE_DIRECT_EMPTY was changed to INVOKE_OBJECT_INIT_RANGE in ICS - if (opcode != INVOKE_DIRECT_EMPTY) { - opcodesByValue[opcode.value] = opcode; - opcodesByName.put(opcode.name.hashCode(), opcode); + if (!opcode.format.payloadFormat) { + //INVOKE_DIRECT_EMPTY was changed to INVOKE_OBJECT_INIT_RANGE in ICS + if (opcode != INVOKE_DIRECT_EMPTY) { + opcodesByValue[opcode.value] = opcode; + opcodesByName.put(opcode.name.hashCode(), opcode); + } } } } @@ -329,7 +335,16 @@ public enum Opcode } public static Opcode getOpcodeByValue(int opcodeValue) { - return opcodesByValue[opcodeValue]; + switch (opcodeValue) { + case 0x100: + return SPARSE_SWITCH_PAYLOAD; + case 0x200: + return PACKED_SWITCH_PAYLOAD; + case 0x300: + return ARRAY_PAYLOAD; + default: + return opcodesByValue[opcodeValue]; + } } private static void removeOpcodes(Opcode... toRemove) { diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/instruction/DexBackedArrayPayload.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/instruction/DexBackedArrayPayload.java new file mode 100644 index 00000000..dee427de --- /dev/null +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/instruction/DexBackedArrayPayload.java @@ -0,0 +1,120 @@ +/* + * Copyright 2012, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.dexlib2.dexbacked.instruction; + +import org.jf.dexlib2.Opcode; +import org.jf.dexlib2.dexbacked.DexBuffer; +import org.jf.dexlib2.dexbacked.util.FixedSizeList; +import org.jf.dexlib2.iface.instruction.formats.ArrayPayload; +import org.jf.util.ExceptionWithContext; + +import javax.annotation.Nonnull; +import java.util.List; + +public class DexBackedArrayPayload implements ArrayPayload { + public static final Opcode OPCODE = Opcode.ARRAY_PAYLOAD; + + @Nonnull public final DexBuffer dexBuf; + private final int instructionOffset; + + public final int elementWidth; + public final int elementCount; + + private static final int ELEMENT_WIDTH_OFFSET = 2; + private static final int ELEMENT_COUNT_OFFSET = 4; + private static final int ELEMENTS_OFFSET = 8; + + public DexBackedArrayPayload(DexBuffer dexBuf, + int instructionOffset) { + this.dexBuf = dexBuf; + this.instructionOffset = instructionOffset; + + this.elementWidth = dexBuf.readUshort(instructionOffset + ELEMENT_WIDTH_OFFSET); + this.elementCount = dexBuf.readSmallUint(instructionOffset + ELEMENT_COUNT_OFFSET); + } + + @Override public int getElementWidth() { return elementWidth; } + + @Nonnull + @Override + public List getArrayElements() { + final int elementsStart = instructionOffset + ELEMENTS_OFFSET; + + abstract class ReturnedList extends FixedSizeList { + @Override public int size() { return elementCount; } + } + + switch (elementWidth) { + case 1: + return new ReturnedList() { + @Nonnull + @Override + public Number readItem(int index) { + return dexBuf.readByte(elementsStart + index); + } + }; + case 2: + return new ReturnedList() { + @Nonnull + @Override + public Number readItem(int index) { + return dexBuf.readShort(elementsStart + index*2); + } + }; + case 4: + return new ReturnedList() { + @Nonnull + @Override + public Number readItem(int index) { + return dexBuf.readInt(elementsStart + index*4); + } + }; + case 8: + return new ReturnedList() { + @Nonnull + @Override + public Number readItem(int index) { + return dexBuf.readLong(elementsStart + index*8); + } + }; + default: + throw new ExceptionWithContext("Invalid element width: %d", elementWidth); + } + } + + @Override + public int getCodeUnits() { + return 4 + (elementWidth*elementCount + 1) / 2; + } + + @Override public Opcode getOpcode() { return OPCODE; } +} diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/instruction/DexBackedInstruction.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/instruction/DexBackedInstruction.java index ff49fd8e..95f82a09 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/instruction/DexBackedInstruction.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/instruction/DexBackedInstruction.java @@ -45,6 +45,10 @@ public abstract class DexBackedInstruction { @Nonnull public static Instruction readFrom(@Nonnull DexReader reader) { int opcodeValue = reader.readUbyte(); + if (opcodeValue == 0) { + reader.moveRelative(-1); + opcodeValue = reader.readUshort(); + } Opcode opcode = Opcode.getOpcodeByValue(opcodeValue); @@ -101,6 +105,13 @@ public abstract class DexBackedInstruction { return instruction3rc(opcode, reader); case Format51l: return instruction51l(opcode, reader); + case PackedSwitchPayload: + return packedSwitchPayload(reader); + case SparseSwitchPayload: + return sparseSwitchPayload(reader); + case ArrayPayload: + return arrayPayload(reader); + //TODO: temporary, until we get all instructions implemented default: throw new ExceptionWithContext("Unexpected opcode format: %s", opcode.format.toString()); } @@ -308,4 +319,33 @@ public abstract class DexBackedInstruction { long literal = reader.readLong(); return new ImmutableInstruction51l(opcode, registerA, literal); } + + @Nonnull + private static DexBackedPackedSwitchPayload packedSwitchPayload(@Nonnull DexReader reader) { + // the reader is currently positioned after the 2-byte "opcode" + int instructionStartOffset = reader.getOffset() - 2; + DexBackedPackedSwitchPayload instruction = + new DexBackedPackedSwitchPayload(reader.getDexBuffer(), instructionStartOffset); + reader.moveRelative(instruction.getCodeUnits() * 2); + return instruction; + } + + @Nonnull + private static DexBackedSparseSwitchPayload sparseSwitchPayload(@Nonnull DexReader reader) { + // the reader is currently positioned after the 2-byte "opcode" + int instructionStartOffset = reader.getOffset() - 2; + DexBackedSparseSwitchPayload instruction = + new DexBackedSparseSwitchPayload(reader.getDexBuffer(), instructionStartOffset); + reader.moveRelative(instruction.getCodeUnits() * 2); + return instruction; + } + + @Nonnull + private static DexBackedArrayPayload arrayPayload(@Nonnull DexReader reader) { + // the reader is currently positioned after the 2-byte "opcode" + int instructionStartOffset = reader.getOffset() - 2; + DexBackedArrayPayload instruction = new DexBackedArrayPayload(reader.getDexBuffer(), instructionStartOffset); + reader.moveRelative(instruction.getCodeUnits() * 2); + return instruction; + } } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/instruction/DexBackedPackedSwitchPayload.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/instruction/DexBackedPackedSwitchPayload.java new file mode 100644 index 00000000..5e592c04 --- /dev/null +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/instruction/DexBackedPackedSwitchPayload.java @@ -0,0 +1,90 @@ +/* + * Copyright 2012, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.dexlib2.dexbacked.instruction; + +import org.jf.dexlib2.Opcode; +import org.jf.dexlib2.dexbacked.DexBuffer; +import org.jf.dexlib2.dexbacked.util.FixedSizeList; +import org.jf.dexlib2.iface.instruction.SwitchElement; +import org.jf.dexlib2.iface.instruction.formats.PackedSwitchPayload; + +import javax.annotation.Nonnull; +import java.util.List; + +public class DexBackedPackedSwitchPayload implements PackedSwitchPayload { + public static final Opcode OPCODE = Opcode.PACKED_SWITCH_PAYLOAD; + + @Nonnull public final DexBuffer dexBuf; + private final int instructionOffset; + + public final int elementCount; + + private static final int ELEMENT_COUNT_OFFSET = 2; + private static final int FIRST_KEY_OFFSET = 4; + private static final int TARGETS_OFFSET = 8; + + public DexBackedPackedSwitchPayload(@Nonnull DexBuffer dexBuf, + int instructionOffset) { + this.dexBuf = dexBuf; + this.instructionOffset = instructionOffset; + + this.elementCount = dexBuf.readByte(instructionOffset + ELEMENT_COUNT_OFFSET); + } + + @Nonnull + @Override + public List getSwitchElements() { + final int firstKey = dexBuf.readInt(instructionOffset + FIRST_KEY_OFFSET); + return new FixedSizeList() { + @Nonnull + @Override + public SwitchElement readItem(final int index) { + return new SwitchElement() { + @Override + public int getKey() { + return firstKey + index; + } + + @Override + public int getOffset() { + return dexBuf.readInt(instructionOffset + TARGETS_OFFSET + index*4); + } + }; + } + + @Override public int size() { return elementCount; } + }; + } + + @Override public int getCodeUnits() { return 4 + elementCount*2; } + @Override public Opcode getOpcode() { return OPCODE; } +} diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/instruction/DexBackedSparseSwitchPayload.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/instruction/DexBackedSparseSwitchPayload.java new file mode 100644 index 00000000..4fff5e1d --- /dev/null +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/instruction/DexBackedSparseSwitchPayload.java @@ -0,0 +1,88 @@ +/* + * Copyright 2012, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.dexlib2.dexbacked.instruction; + +import org.jf.dexlib2.Opcode; +import org.jf.dexlib2.dexbacked.DexBuffer; +import org.jf.dexlib2.dexbacked.util.FixedSizeList; +import org.jf.dexlib2.iface.instruction.SwitchElement; +import org.jf.dexlib2.iface.instruction.formats.SparseSwitchPayload; + +import javax.annotation.Nonnull; +import java.util.List; + +public class DexBackedSparseSwitchPayload implements SparseSwitchPayload { + public static final Opcode OPCODE = Opcode.SPARSE_SWITCH_PAYLOAD; + + @Nonnull public final DexBuffer dexBuf; + private final int instructionOffset; + + public final int elementCount; + + private static final int ELEMENT_COUNT_OFFSET = 2; + private static final int KEYS_OFFSET = 4; + + public DexBackedSparseSwitchPayload(@Nonnull DexBuffer dexBuf, + int instructionOffset) { + this.dexBuf = dexBuf; + this.instructionOffset = instructionOffset; + + this.elementCount = dexBuf.readUshort(instructionOffset + ELEMENT_COUNT_OFFSET); + } + + @Nonnull + @Override + public List getSwitchElements() { + return new FixedSizeList() { + @Nonnull + @Override + public SwitchElement readItem(final int index) { + return new SwitchElement() { + @Override + public int getKey() { + return dexBuf.readInt(instructionOffset + KEYS_OFFSET + index*4); + } + + @Override + public int getOffset() { + return dexBuf.readInt(instructionOffset + KEYS_OFFSET + elementCount*4 + index*4); + } + }; + } + + @Override public int size() { return elementCount; } + }; + } + + @Override public int getCodeUnits() { return 2 + elementCount*4; } + @Override public Opcode getOpcode() { return OPCODE; } +} diff --git a/dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/Instruction.java b/dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/Instruction.java index f0273c21..c06b073c 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/Instruction.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/Instruction.java @@ -35,4 +35,5 @@ import org.jf.dexlib2.Opcode; public interface Instruction { Opcode getOpcode(); + int getCodeUnits(); } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/PayloadInstruction.java b/dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/PayloadInstruction.java new file mode 100644 index 00000000..361b08b0 --- /dev/null +++ b/dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/PayloadInstruction.java @@ -0,0 +1,38 @@ +/* + * Copyright 2012, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.dexlib2.iface.instruction; + +/** + * Empty marker interface for the switch/array payload instructions + */ +public interface PayloadInstruction extends Instruction { +} diff --git a/dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/SwitchElement.java b/dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/SwitchElement.java new file mode 100644 index 00000000..b24f6ad1 --- /dev/null +++ b/dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/SwitchElement.java @@ -0,0 +1,37 @@ +/* + * Copyright 2012, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.dexlib2.iface.instruction; + +public interface SwitchElement { + public int getKey(); + public int getOffset(); +} diff --git a/dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/SwitchPayload.java b/dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/SwitchPayload.java new file mode 100644 index 00000000..3d882cf1 --- /dev/null +++ b/dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/SwitchPayload.java @@ -0,0 +1,39 @@ +/* + * Copyright 2012, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.dexlib2.iface.instruction; + +import javax.annotation.Nonnull; +import java.util.List; + +public interface SwitchPayload extends PayloadInstruction { + @Nonnull List getSwitchElements(); +} diff --git a/dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/formats/ArrayPayload.java b/dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/formats/ArrayPayload.java new file mode 100644 index 00000000..0a698543 --- /dev/null +++ b/dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/formats/ArrayPayload.java @@ -0,0 +1,42 @@ +/* + * Copyright 2012, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.dexlib2.iface.instruction.formats; + +import org.jf.dexlib2.iface.instruction.PayloadInstruction; + +import javax.annotation.Nonnull; +import java.util.List; + +public interface ArrayPayload extends PayloadInstruction { + public int getElementWidth(); + @Nonnull public List getArrayElements(); +} diff --git a/dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/formats/PackedSwitchPayload.java b/dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/formats/PackedSwitchPayload.java new file mode 100644 index 00000000..3872ece1 --- /dev/null +++ b/dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/formats/PackedSwitchPayload.java @@ -0,0 +1,37 @@ +/* + * Copyright 2012, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.dexlib2.iface.instruction.formats; + +import org.jf.dexlib2.iface.instruction.SwitchPayload; + +public interface PackedSwitchPayload extends SwitchPayload { +} diff --git a/dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/formats/SparseSwitchPayload.java b/dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/formats/SparseSwitchPayload.java new file mode 100644 index 00000000..29cc9c45 --- /dev/null +++ b/dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/formats/SparseSwitchPayload.java @@ -0,0 +1,37 @@ +/* + * Copyright 2012, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.dexlib2.iface.instruction.formats; + +import org.jf.dexlib2.iface.instruction.SwitchPayload; + +public interface SparseSwitchPayload extends SwitchPayload { +} diff --git a/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableArrayPayload.java b/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableArrayPayload.java new file mode 100644 index 00000000..ed1cd9b7 --- /dev/null +++ b/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableArrayPayload.java @@ -0,0 +1,81 @@ +/* + * Copyright 2012, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.dexlib2.immutable.instruction; + +import com.google.common.base.Objects; +import com.google.common.collect.ImmutableList; +import org.jf.dexlib2.Format; +import org.jf.dexlib2.Opcode; +import org.jf.dexlib2.iface.instruction.formats.ArrayPayload; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.List; + +public class ImmutableArrayPayload extends ImmutableInstruction implements ArrayPayload { + public static final Opcode OPCODE = Opcode.ARRAY_PAYLOAD; + + public final int elementWidth; + @Nonnull public final ImmutableList arrayElements; + + public ImmutableArrayPayload(int elementWidth, + @Nullable List arrayElements) { + super(OPCODE); + this.elementWidth = elementWidth; + this.arrayElements = arrayElements==null ? ImmutableList.of() : ImmutableList.copyOf(arrayElements); + } + + public ImmutableArrayPayload(int elementWidth, + @Nullable ImmutableList arrayElements) { + super(OPCODE); + //TODO: need to ensure this is a valid width (1, 2, 4, 8) + this.elementWidth = elementWidth; + //TODO: need to validate the elements fit within the width + this.arrayElements = Objects.firstNonNull(arrayElements, ImmutableList.of()); + } + + @Nonnull + public static ImmutableArrayPayload of(ArrayPayload instruction) { + if (instruction instanceof ImmutableArrayPayload) { + return (ImmutableArrayPayload)instruction; + } + return new ImmutableArrayPayload( + instruction.getElementWidth(), + instruction.getArrayElements()); + } + + @Override public int getElementWidth() { return elementWidth; } + @Nonnull @Override public List getArrayElements() { return arrayElements; } + + @Override public int getCodeUnits() { return 4 + (elementWidth * arrayElements.size() + 1) / 2; } + @Override public Format getFormat() { return OPCODE.format; } +} diff --git a/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction.java b/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction.java index d6a06847..2f7dbe6d 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction.java @@ -43,7 +43,7 @@ import javax.annotation.Nonnull; import java.util.List; public abstract class ImmutableInstruction implements Instruction { - public final Opcode opcode; + @Nonnull public final Opcode opcode; protected ImmutableInstruction(@Nonnull Opcode opcode) { this.opcode = opcode; @@ -51,6 +51,7 @@ public abstract class ImmutableInstruction implements Instruction { Preconditions.checkFormat(opcode, getFormat()); } + @Nonnull public static ImmutableInstruction of(Instruction instruction) { if (instruction instanceof ImmutableInstruction) { return (ImmutableInstruction)instruction; @@ -107,9 +108,16 @@ public abstract class ImmutableInstruction implements Instruction { return ImmutableInstruction3rc.of((Instruction3rc)instruction); case Format51l: return ImmutableInstruction51l.of((Instruction51l)instruction); + case PackedSwitchPayload: + return ImmutablePackedSwitchPayload.of((PackedSwitchPayload) instruction); + case SparseSwitchPayload: + return ImmutableSparseSwitchPayload.of((SparseSwitchPayload) instruction); + case ArrayPayload: + return ImmutableArrayPayload.of((ArrayPayload) instruction); + //TODO: temporary, until we get all instructions implemented + default: + throw new RuntimeException("Unexpected instruction type"); } - //TODO: temporary, until we get all instructions implemented - throw new RuntimeException("Unexpected instruction type"); } public Opcode getOpcode() { @@ -118,6 +126,10 @@ public abstract class ImmutableInstruction implements Instruction { public abstract Format getFormat(); + public int getCodeUnits() { + return getFormat().size * 2; + } + @Nonnull public static ImmutableList immutableListOf(List list) { return CONVERTER.convert(list); @@ -130,6 +142,7 @@ public abstract class ImmutableInstruction implements Instruction { return item instanceof ImmutableInstruction; } + @Nonnull @Override protected ImmutableInstruction makeImmutable(Instruction item) { return ImmutableInstruction.of(item); diff --git a/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutablePackedSwitchPayload.java b/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutablePackedSwitchPayload.java new file mode 100644 index 00000000..abb020a4 --- /dev/null +++ b/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutablePackedSwitchPayload.java @@ -0,0 +1,75 @@ +/* + * Copyright 2012, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.dexlib2.immutable.instruction; + +import com.google.common.base.Objects; +import com.google.common.collect.ImmutableList; +import org.jf.dexlib2.Format; +import org.jf.dexlib2.Opcode; +import org.jf.dexlib2.iface.instruction.SwitchElement; +import org.jf.dexlib2.iface.instruction.formats.PackedSwitchPayload; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.List; + +public class ImmutablePackedSwitchPayload extends ImmutableInstruction implements PackedSwitchPayload { + public static final Opcode OPCODE = Opcode.PACKED_SWITCH_PAYLOAD; + + @Nonnull public final ImmutableList switchElements; + + public ImmutablePackedSwitchPayload(@Nullable List switchElements) { + super(OPCODE); + //TODO: need to validate that the keys are sequential + this.switchElements = ImmutableSwitchElement.immutableListOf(switchElements); + } + + public ImmutablePackedSwitchPayload( + @Nullable ImmutableList switchElements) { + super(OPCODE); + this.switchElements = Objects.firstNonNull(switchElements, ImmutableList.of()); + } + + @Nonnull + public static ImmutablePackedSwitchPayload of(PackedSwitchPayload instruction) { + if (instruction instanceof ImmutablePackedSwitchPayload) { + return (ImmutablePackedSwitchPayload)instruction; + } + return new ImmutablePackedSwitchPayload( + instruction.getSwitchElements()); + } + + @Nonnull @Override public List getSwitchElements() { return switchElements; } + + @Override public int getCodeUnits() { return 4 + switchElements.size() * 2; } + @Override public Format getFormat() { return OPCODE.format; } +} diff --git a/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableSparseSwitchPayload.java b/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableSparseSwitchPayload.java new file mode 100644 index 00000000..64e94483 --- /dev/null +++ b/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableSparseSwitchPayload.java @@ -0,0 +1,75 @@ +/* + * Copyright 2012, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.dexlib2.immutable.instruction; + +import com.google.common.base.Objects; +import com.google.common.collect.ImmutableList; +import org.jf.dexlib2.Format; +import org.jf.dexlib2.Opcode; +import org.jf.dexlib2.iface.instruction.SwitchElement; +import org.jf.dexlib2.iface.instruction.formats.SparseSwitchPayload; +import org.jf.dexlib2.iface.instruction.formats.SparseSwitchPayload; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.List; + +public class ImmutableSparseSwitchPayload extends ImmutableInstruction implements SparseSwitchPayload { + public static final Opcode OPCODE = Opcode.SPARSE_SWITCH_PAYLOAD; + + @Nonnull public final ImmutableList switchElements; + + public ImmutableSparseSwitchPayload(@Nullable List switchElements) { + super(OPCODE); + this.switchElements = ImmutableSwitchElement.immutableListOf(switchElements); + } + + public ImmutableSparseSwitchPayload( + @Nullable ImmutableList switchElements) { + super(OPCODE); + this.switchElements = Objects.firstNonNull(switchElements, ImmutableList.of()); + } + + @Nonnull + public static ImmutableSparseSwitchPayload of(SparseSwitchPayload instruction) { + if (instruction instanceof ImmutableSparseSwitchPayload) { + return (ImmutableSparseSwitchPayload)instruction; + } + return new ImmutableSparseSwitchPayload( + instruction.getSwitchElements()); + } + + @Nonnull @Override public List getSwitchElements() { return switchElements; } + + @Override public int getCodeUnits() { return 2 + switchElements.size() * 4; } + @Override public Format getFormat() { return OPCODE.format; } +} diff --git a/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableSwitchElement.java b/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableSwitchElement.java new file mode 100644 index 00000000..0373efac --- /dev/null +++ b/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableSwitchElement.java @@ -0,0 +1,82 @@ +/* + * Copyright 2012, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.dexlib2.immutable.instruction; + +import com.google.common.collect.ImmutableList; +import org.jf.dexlib2.iface.instruction.SwitchElement; +import org.jf.util.ImmutableListConverter; + +import javax.annotation.Nonnull; +import java.util.List; + +public class ImmutableSwitchElement implements SwitchElement { + public final int key; + public final int offset; + + public ImmutableSwitchElement(int key, + int offset) { + this.key = key; + this.offset = offset; + } + + @Nonnull + public static ImmutableSwitchElement of(SwitchElement switchElement) { + if (switchElement instanceof ImmutableSwitchElement) { + return (ImmutableSwitchElement)switchElement; + } + return new ImmutableSwitchElement( + switchElement.getKey(), + switchElement.getOffset()); + } + + @Override public int getKey() { return key; } + @Override public int getOffset() { return offset; } + + @Nonnull + public static ImmutableList immutableListOf(List list) { + return CONVERTER.convert(list); + } + + private static final ImmutableListConverter CONVERTER = + new ImmutableListConverter() { + @Override + protected boolean isImmutable(SwitchElement item) { + return item instanceof ImmutableSwitchElement; + } + + @Nonnull + @Override + protected ImmutableSwitchElement makeImmutable(SwitchElement item) { + return ImmutableSwitchElement.of(item); + } + }; +}