From 5867263eb588f4671400895d1e6b01c01535061b Mon Sep 17 00:00:00 2001 From: "JesusFreke@JesusFreke.com" Date: Wed, 23 Dec 2009 05:25:59 +0000 Subject: [PATCH] line ending and trailing whitespace cleanup git-svn-id: https://smali.googlecode.com/svn/trunk@500 55b6fa8a-2a1e-11de-a435-ffa8d773f76a --- .../AnnotationEncodedValueAdaptor.java | 2 +- .../EncodedValue/EncodedValueAdaptor.java | 2 +- .../jf/baksmali/Adaptors/FieldDefinition.java | 6 +- .../baksmali/Adaptors/MethodDefinition.java | 8 +- .../baksmali/Adaptors/RegisterFormatter.java | 2 +- .../jf/baksmali/Renderers/ByteRenderer.java | 2 +- .../main/java/org/jf/baksmali/baksmali.java | 4 +- .../src/main/java/org/jf/baksmali/dump.java | 2 +- .../src/test/smali/baksmali_test_class.smali | 4 +- .../src/test/smali/deodex_test1/main.smali | 8 +- .../smali/deodex_test2/app_classes/main.smali | 6 +- deodexerant/Main.c | 88 +- .../jf/dexlib/AnnotationDirectoryItem.java | 946 ++++----- .../java/org/jf/dexlib/AnnotationItem.java | 324 ++-- .../java/org/jf/dexlib/AnnotationSetItem.java | 338 ++-- .../org/jf/dexlib/AnnotationSetRefList.java | 340 ++-- .../java/org/jf/dexlib/ClassDataItem.java | 1062 +++++------ .../main/java/org/jf/dexlib/ClassDefItem.java | 754 ++++---- .../Format/ArrayDataPseudoInstruction.java | 276 +-- .../org/jf/dexlib/Code/Format/Format.java | 172 +- .../jf/dexlib/Code/Format/Instruction10t.java | 140 +- .../jf/dexlib/Code/Format/Instruction10x.java | 120 +- .../jf/dexlib/Code/Format/Instruction11n.java | 152 +- .../jf/dexlib/Code/Format/Instruction11x.java | 134 +- .../jf/dexlib/Code/Format/Instruction12x.java | 144 +- .../jf/dexlib/Code/Format/Instruction20t.java | 144 +- .../jf/dexlib/Code/Format/Instruction21c.java | 164 +- .../jf/dexlib/Code/Format/Instruction21h.java | 146 +- .../jf/dexlib/Code/Format/Instruction21s.java | 146 +- .../jf/dexlib/Code/Format/Instruction21t.java | 160 +- .../jf/dexlib/Code/Format/Instruction22b.java | 156 +- .../jf/dexlib/Code/Format/Instruction22c.java | 148 +- .../jf/dexlib/Code/Format/Instruction22s.java | 154 +- .../jf/dexlib/Code/Format/Instruction22t.java | 170 +- .../jf/dexlib/Code/Format/Instruction22x.java | 152 +- .../jf/dexlib/Code/Format/Instruction23x.java | 158 +- .../jf/dexlib/Code/Format/Instruction30t.java | 128 +- .../jf/dexlib/Code/Format/Instruction31c.java | 148 +- .../jf/dexlib/Code/Format/Instruction31i.java | 146 +- .../jf/dexlib/Code/Format/Instruction31t.java | 144 +- .../jf/dexlib/Code/Format/Instruction32x.java | 148 +- .../jf/dexlib/Code/Format/Instruction35c.java | 268 +-- .../jf/dexlib/Code/Format/Instruction3rc.java | 228 +-- .../jf/dexlib/Code/Format/Instruction51l.java | 146 +- .../PackedSwitchDataPseudoInstruction.java | 272 +-- .../SparseSwitchDataPseudoInstruction.java | 303 ++- .../java/org/jf/dexlib/Code/Instruction.java | 146 +- .../main/java/org/jf/dexlib/Code/Opcode.java | 620 +++--- .../org/jf/dexlib/Code/ReferenceType.java | 110 +- .../src/main/java/org/jf/dexlib/CodeItem.java | 1424 +++++++------- .../java/org/jf/dexlib/DebugInfoItem.java | 1224 ++++++------ .../src/main/java/org/jf/dexlib/DexFile.java | 1689 ++++++++--------- .../java/org/jf/dexlib/EncodedArrayItem.java | 270 +-- .../org/jf/dexlib/EncodedValue/ValueType.java | 170 +- .../main/java/org/jf/dexlib/FieldIdItem.java | 432 ++--- .../main/java/org/jf/dexlib/HeaderItem.java | 468 ++--- .../java/org/jf/dexlib/IndexedSection.java | 132 +- dexlib/src/main/java/org/jf/dexlib/Item.java | 364 ++-- .../src/main/java/org/jf/dexlib/MapItem.java | 276 +-- .../main/java/org/jf/dexlib/MethodIdItem.java | 414 ++-- .../java/org/jf/dexlib/OffsettedSection.java | 166 +- .../main/java/org/jf/dexlib/ProtoIdItem.java | 434 ++--- .../src/main/java/org/jf/dexlib/Section.java | 434 ++--- .../java/org/jf/dexlib/StringDataItem.java | 306 +-- .../main/java/org/jf/dexlib/StringIdItem.java | 296 +-- .../main/java/org/jf/dexlib/TypeIdItem.java | 364 ++-- .../main/java/org/jf/dexlib/TypeListItem.java | 516 ++--- .../java/org/jf/dexlib/Util/AccessFlags.java | 350 ++-- .../org/jf/dexlib/Util/ByteArrayInput.java | 728 +++---- .../org/jf/dexlib/Util/DebugInfoBuilder.java | 902 ++++----- .../org/jf/dexlib/Util/EncodedValueUtils.java | 286 +-- .../main/java/org/jf/dexlib/Util/Input.java | 334 ++-- .../main/java/org/jf/dexlib/Util/Pair.java | 80 +- .../org/jf/dexlib/Util/TryListBuilder.java | 694 +++---- .../java/org/jf/dexlib/Util/TypeUtils.java | 122 +- .../main/java/org/jf/smali/literalTools.java | 756 ++++---- smali/src/main/java/org/jf/smali/main.java | 6 +- smali/src/test/java/ByteLiteralTest.java | 278 +-- smali/src/test/java/IntLiteralTest.java | 288 +-- smali/src/test/java/LongLiteralTest.java | 278 +-- smali/src/test/java/ShortLiteralTest.java | 278 +-- 81 files changed, 12149 insertions(+), 12151 deletions(-) diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/EncodedValue/AnnotationEncodedValueAdaptor.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/EncodedValue/AnnotationEncodedValueAdaptor.java index 756407b9..a0155e71 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/EncodedValue/AnnotationEncodedValueAdaptor.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/EncodedValue/AnnotationEncodedValueAdaptor.java @@ -39,7 +39,7 @@ import java.util.List; import java.util.ArrayList; public abstract class AnnotationEncodedValueAdaptor { - + public static StringTemplate makeTemplate(StringTemplateGroup stg, AnnotationEncodedSubValue encodedAnnotation) { StringTemplate template = stg.getInstanceOf("AnnotationEncodedValue"); template.setAttribute("AnnotationType", TypeReference.makeTemplate(stg, encodedAnnotation.annotationType)); diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/EncodedValue/EncodedValueAdaptor.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/EncodedValue/EncodedValueAdaptor.java index a54a9bc7..73f0dc56 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/EncodedValue/EncodedValueAdaptor.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/EncodedValue/EncodedValueAdaptor.java @@ -58,7 +58,7 @@ public abstract class EncodedValueAdaptor { return SimpleEncodedValueAdaptor.makeTemplate(stg, ((FloatEncodedValue)encodedValue).value); case VALUE_INT: return SimpleEncodedValueAdaptor.makeTemplate(stg, ((IntEncodedValue)encodedValue).value); - case VALUE_LONG: + case VALUE_LONG: return SimpleEncodedValueAdaptor.makeTemplate(stg, ((LongEncodedValue)encodedValue).value); case VALUE_METHOD: return EncodedIndexedItemAdaptor.makeTemplate(stg, MethodReference.makeTemplate(stg, diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/FieldDefinition.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/FieldDefinition.java index 6e4e6d90..4f2b94bc 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/FieldDefinition.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/FieldDefinition.java @@ -63,13 +63,13 @@ public class FieldDefinition { fieldTypeDescriptor.length() == 1 || initialValue != NullEncodedValue.NullValue )) { - + template.setAttribute("Comments", new String[]{"the value of this static final field might be set in the static constructor"}); } else { template.setAttribute("Comments", null); } - + if (initialValue != null) { template.setAttribute("InitialValue", EncodedValueAdaptor.make(stg, initialValue)); } @@ -96,7 +96,7 @@ public class FieldDefinition { if (annotationSet == null) { return null; } - + List annotationAdaptors = new ArrayList(); for (AnnotationItem annotationItem: annotationSet.getAnnotations()) { diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/MethodDefinition.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/MethodDefinition.java index 43f6a6b2..daec8f3c 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/MethodDefinition.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/MethodDefinition.java @@ -61,7 +61,7 @@ public class MethodDefinition { template.setAttribute("Annotations", getAnnotations(stg, annotationSet)); template.setAttribute("MethodItems", getMethodItems(encodedMethod.method.getDexFile(), stg, codeItem)); - return template; + return template; } private static int getRegisterCount(ClassDataItem.EncodedMethod encodedMethod) @@ -83,7 +83,7 @@ public class MethodDefinition { for (AccessFlags accessFlag: AccessFlags.getAccessFlagsForMethod(encodedMethod.accessFlags)) { accessFlags.add(accessFlag.toString()); } - + return accessFlags; } @@ -281,7 +281,7 @@ public class MethodDefinition { } }); } - + blanks.remove(blanks.size()-1); addTries(); @@ -334,7 +334,7 @@ public class MethodDefinition { addInstructionMethodItem( new Instruction11xMethodItem(codeItem, offset, stg, (Instruction11x)instruction), commentedOut); - return; + return; case Format12x: addInstructionMethodItem( new Instruction12xMethodItem(codeItem, offset, stg, (Instruction12x)instruction), diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/RegisterFormatter.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/RegisterFormatter.java index 9ab0eded..632bef6a 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/RegisterFormatter.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/RegisterFormatter.java @@ -53,7 +53,7 @@ public class RegisterFormatter { int registerCount = codeItem.getRegisterCount(); assert startRegister <= lastRegister; - + if (startRegister >= registerCount - parameterRegisterCount) { return new String[] {"p" + (startRegister - (registerCount - parameterRegisterCount)), "p" + (lastRegister - (registerCount - parameterRegisterCount))}; diff --git a/baksmali/src/main/java/org/jf/baksmali/Renderers/ByteRenderer.java b/baksmali/src/main/java/org/jf/baksmali/Renderers/ByteRenderer.java index 0ae16d9a..9b077f64 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Renderers/ByteRenderer.java +++ b/baksmali/src/main/java/org/jf/baksmali/Renderers/ByteRenderer.java @@ -42,7 +42,7 @@ public class ByteRenderer implements AttributeRenderer { public String toString(Object o, String s) { if (s.equals("unsigned")) { Byte b = (Byte)o; - return "0x" + Integer.toHexString(b & 0xFF) + "t"; + return "0x" + Integer.toHexString(b & 0xFF) + "t"; } return toString(o); } diff --git a/baksmali/src/main/java/org/jf/baksmali/baksmali.java b/baksmali/src/main/java/org/jf/baksmali/baksmali.java index d70eb9c5..b52e9ba0 100644 --- a/baksmali/src/main/java/org/jf/baksmali/baksmali.java +++ b/baksmali/src/main/java/org/jf/baksmali/baksmali.java @@ -57,7 +57,7 @@ public class baksmali { if (deodexerant != null) { baksmali.deodexUtil = new DeodexUtil(deodexerant); } - + File outputDirectoryFile = new File(outputDirectory); if (!outputDirectoryFile.exists()) { if (!outputDirectoryFile.mkdirs()) { @@ -76,7 +76,7 @@ public class baksmali { templates.registerRenderer(Float.class, new FloatRenderer()); templates.registerRenderer(Character.class, new CharRenderer()); templates.registerRenderer(StringIdItem.class, new StringIdItemRenderer()); - + for (ClassDefItem classDefItem: dexFile.ClassDefsSection.getItems()) { /** diff --git a/baksmali/src/main/java/org/jf/baksmali/dump.java b/baksmali/src/main/java/org/jf/baksmali/dump.java index e5158134..ad8d63e3 100644 --- a/baksmali/src/main/java/org/jf/baksmali/dump.java +++ b/baksmali/src/main/java/org/jf/baksmali/dump.java @@ -40,7 +40,7 @@ public class dump { if (sort) { //sort all items, to guarantee a unique ordering - dexFile.setSortAllItems(true); + dexFile.setSortAllItems(true); } else { //don't change the order dexFile.setInplace(true); diff --git a/baksmali/src/test/smali/baksmali_test_class.smali b/baksmali/src/test/smali/baksmali_test_class.smali index 6ae17270..903baf48 100644 --- a/baksmali/src/test/smali/baksmali_test_class.smali +++ b/baksmali/src/test/smali/baksmali_test_class.smali @@ -97,7 +97,7 @@ const-string v0, "testing\n123" goto switch: - + sget v0, Lbaksmali/test/class;->staticField:I switch: @@ -194,7 +194,7 @@ .source "somefile.java" .line 101 - + nop diff --git a/baksmali/src/test/smali/deodex_test1/main.smali b/baksmali/src/test/smali/deodex_test1/main.smali index 99ffecad..bc6ca320 100644 --- a/baksmali/src/test/smali/deodex_test1/main.smali +++ b/baksmali/src/test/smali/deodex_test1/main.smali @@ -28,13 +28,13 @@ invoke-virtual {v0}, Lrandomclass;->getSuperclass()Lsuperclass; move-result-object v1 - + #a branch to outside the dead code. The branch label should not #be commented out, because there is a non-dead instruction #that branches to it if-eqz v0, :here2 - + #a branch to inside the dead code. the branch label should be #commented out if-eqz v0, :here @@ -61,14 +61,14 @@ #but still commented out invoke-virtual {v2}, Lsuperclass;->somemethod()V - + :here2 #and we're back to the non-dead code invoke-virtual {v2}, Lsuperclass;->somemethod()V if-nez v0, :here3 - + return-void .end method diff --git a/baksmali/src/test/smali/deodex_test2/app_classes/main.smali b/baksmali/src/test/smali/deodex_test2/app_classes/main.smali index 970d4ba0..505312c6 100644 --- a/baksmali/src/test/smali/deodex_test2/app_classes/main.smali +++ b/baksmali/src/test/smali/deodex_test2/app_classes/main.smali @@ -6,11 +6,11 @@ .registers 6 const v2, 0 - - + + const v3, 1 const v4, 0 - new-array v1, v3, [Lsubclass1; + new-array v1, v3, [Lsubclass1; new-instance v0, Lsubclass1; invoke-direct {v0}, Lsubclass1;->()V aput-object v0, v1, v4 diff --git a/deodexerant/Main.c b/deodexerant/Main.c index 4a03bdfc..28aa3547 100644 --- a/deodexerant/Main.c +++ b/deodexerant/Main.c @@ -297,17 +297,17 @@ int dumpFields(char *classType, FILE *clientOut) clazz = dvmFindArrayClass(classType, NULL); else clazz = dvmFindSystemClassNoInit(classType); - + if (clazz == NULL) return 0; - + int i; do { InstField *pField = clazz->ifields; for (i=0; iifieldCount; i++, pField++) fprintf(clientOut, "field: %d %s:%s\n", pField->byteOffset, pField->field.name, pField->field.signature); - + clazz = clazz->super; } while (clazz != NULL); @@ -318,15 +318,15 @@ int dumpInlineMethods(FILE *clientOut) { const InlineOperation *inlineTable = dvmGetInlineOpsTable(); int count = dvmGetInlineOpsTableLength(); - + int i; for (i=0; iclassDescriptor); if (clazz == NULL) return 0; - + char *methodType; Method *method = dvmFindDirectMethodByDescriptor(clazz, inlineOp->methodName, inlineOp->methodSignature); if (method == NULL) @@ -339,13 +339,13 @@ int dumpInlineMethods(FILE *clientOut) else methodType = "direct"; } - + if (method == NULL) return 0; - + fprintf(clientOut, "inline: %s %s->%s%s\n", methodType, method->clazz->descriptor, method->name, dexProtoGetMethodDescriptor(&method->prototype, &stringCache)); } - + return 1; } @@ -356,14 +356,14 @@ int dumpVirtualMethods(char *classType, FILE *clientOut) clazz = dvmFindArrayClass(classType, NULL); else clazz = dvmFindSystemClassNoInit(classType); - - + + if (clazz == NULL) { fprintf(clientOut, "err: could not find class %s\n", classType); return 0; } - + //interface classes don't have virtual methods, by definition. But it's possible //to call virtual methods defined on the Object class via an interface type if (dvmIsInterfaceClass(clazz)) @@ -389,10 +389,10 @@ int dumpVirtualMethods(char *classType, FILE *clientOut) ClassObject *lookupSuperclass(char *classType) { ClassObject *clazz = dvmFindSystemClassNoInit(classType); - + if (clazz == NULL) return NULL; - + return clazz->super; } @@ -428,7 +428,7 @@ int main(int argc, char* const argv[]) fprintf(stderr, "Unable to open '%s': %s\n", inputFileName, strerror(errno)); return 1; } - + int port = atoi(argv[2]); int socketFd = socket(AF_INET, SOCK_STREAM, 0); if (socketFd < 0) @@ -436,7 +436,7 @@ int main(int argc, char* const argv[]) fprintf(stderr, "Unable to open socket\n"); return 1; } - + struct sockaddr_in serverAddress, clientAddress; bzero((char *)&serverAddress, sizeof(serverAddress)); serverAddress.sin_family = AF_INET; @@ -446,14 +446,14 @@ int main(int argc, char* const argv[]) { fprintf(stderr, "Unable to bind socket\n"); return 1; - } + } const char* bcp = getenv("BOOTCLASSPATH"); if (bcp == NULL) { fprintf(stderr, "BOOTCLASSPATH not set\n"); return 1; } - + DexClassVerifyMode verifyMode = VERIFY_MODE_ALL; DexOptimizerMode dexOptMode = OPTIMIZE_MODE_VERIFIED; @@ -498,12 +498,12 @@ int main(int argc, char* const argv[]) fprintf(stderr, "error while loading classes\n"); return 1; } - - - - + + + + listen(socketFd, 1); - + int clientSocketLength = sizeof(clientAddress); int clientFd = accept(socketFd, (struct sockaddr *) &clientAddress, &clientSocketLength); if (clientFd < 0) @@ -511,14 +511,14 @@ int main(int argc, char* const argv[]) fprintf(stderr, "Unable to accept incomming connection\n"); return 1; } - + FILE *clientIn = fdopen(clientFd, "r"); if (clientIn == 0) { fprintf(stderr, "Unable to fdopen socket to get input stream\n"); return 1; } - + FILE *clientOut = fdopen(dup(clientFd), "w"); if (clientOut == 0) { @@ -536,7 +536,7 @@ int main(int argc, char* const argv[]) char *buf = malloc(len+1); memcpy(buf, command, len); buf[len] = 0; - + //printf("%s\n", buf); char *cmd = strtok(buf, " "); @@ -557,14 +557,14 @@ int main(int argc, char* const argv[]) fflush(clientOut); break; } - + if (!dumpFields(classType, clientOut)) { fprintf(clientOut, "err: error while dumping fields\n"); fflush(clientOut); break; } - + fprintf(clientOut, "done\n"); fflush(clientOut); break; @@ -577,7 +577,7 @@ int main(int argc, char* const argv[]) fflush(clientOut); break; } - + fprintf(clientOut, "done\n"); fflush(clientOut); break; @@ -591,13 +591,13 @@ int main(int argc, char* const argv[]) fflush(clientOut); break; } - + if (!dumpVirtualMethods(classType, clientOut)) { fprintf(clientOut, "err: error encountered while dumping virtual methods\n"); fflush(clientOut); break; } - + fprintf(clientOut, "done\n"); fflush(clientOut); break; @@ -611,7 +611,7 @@ int main(int argc, char* const argv[]) fflush(clientOut); break; } - + ClassObject *clazz = lookupSuperclass(classType); if (clazz == NULL) { @@ -633,20 +633,20 @@ int main(int argc, char* const argv[]) fflush(clientOut); break; } - + ClassObject *clazz1; if (classType1[0] == '[') clazz1 = dvmFindArrayClass(classType1, NULL); else clazz1 = dvmFindSystemClassNoInit(classType1); - + if (clazz1 == NULL) { fprintf(clientOut, "err: class %s could not be found for common superclass lookup. This can be caused if a library the odex depends on is not in the BOOTCLASSPATH environment variable\n", classType1); fflush(clientOut); break; - } - + } + char *classType2 = strtok(NULL, " "); if (classType2 == NULL) { @@ -654,20 +654,20 @@ int main(int argc, char* const argv[]) fflush(clientOut); break; } - + ClassObject *clazz2; if (classType2[0] == '[') clazz2 = dvmFindArrayClass(classType2, NULL); else clazz2 = dvmFindSystemClassNoInit(classType2); - + if (clazz2 == NULL) { fprintf(clientOut, "err: class %s could not be found for common superclass lookup\n", classType2); fflush(clientOut); break; - } - + } + ClassObject *clazz = findCommonSuperclass(clazz1, clazz2); fprintf(clientOut, "class: %s\n", clazz->descriptor); fflush(clientOut); @@ -677,12 +677,12 @@ int main(int argc, char* const argv[]) fprintf(clientOut, "err: not a valid command\n"); fflush(clientOut); } - - /*gettimeofday(&tv, NULL); - + + /*gettimeofday(&tv, NULL); + printf("end %07d\n", tv.tv_usec);*/ - + } return 0; diff --git a/dexlib/src/main/java/org/jf/dexlib/AnnotationDirectoryItem.java b/dexlib/src/main/java/org/jf/dexlib/AnnotationDirectoryItem.java index c03652aa..38fdbe69 100644 --- a/dexlib/src/main/java/org/jf/dexlib/AnnotationDirectoryItem.java +++ b/dexlib/src/main/java/org/jf/dexlib/AnnotationDirectoryItem.java @@ -1,473 +1,473 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib; - -import org.jf.dexlib.Util.Input; -import org.jf.dexlib.Util.AnnotatedOutput; - -import java.util.Collections; -import java.util.List; - -public class AnnotationDirectoryItem extends Item { - private AnnotationSetItem classAnnotations; - - private FieldIdItem[] fieldAnnotationFields; - private AnnotationSetItem[] fieldAnnotations; - - private MethodIdItem[] methodAnnotationMethods; - private AnnotationSetItem[] methodAnnotations; - - private MethodIdItem[] parameterAnnotationMethods; - private AnnotationSetRefList[] parameterAnnotations; - - /** - * typically each AnnotationDirectoryItem will have a distinct parent. The only case that isn't true is when - * the AnnotationDirectoryItem *only* contains class annotations, with no other type of annotation. In that - * case, the same AnnotationDirectoryItem could be referenced from multiple classes. - * This isn't a problem though, because this field is only used in compareTo to determine the sort order, - * which handles it as a special case - */ - private ClassDefItem parent = null; - - /** - * Creates a new uninitialized AnnotationDirectoryItem - * @param dexFile The DexFile that this item belongs to - */ - protected AnnotationDirectoryItem(DexFile dexFile) { - super(dexFile); - } - - /** - * Creates a new AnnotationDirectoryItem with the given values - * @param dexFile The DexFile that this item belongs to - * @param classAnnotations The annotations associated with the overall class - * @param fieldAnnotationFields An array of FieldIdItem objects that the annotations in - * fieldAnnotations are associated with - * @param fieldAnnotations An array of AnnotationSetItem objects that contain the annotations for the - * fields in fieldAnnotationFields - * @param methodAnnotationMethods An array of MethodIdItem objects that the annotations in - * methodAnnotations are associated with - * @param methodAnnotations An array of AnnotationSetItem objects that contain the annotations for the - * methods in methodAnnotationMethods - * @param parameterAnnotationMethods An array of MethodIdItem objects that the annotations in - * parameterAnnotations are associated with - * @param parameterAnnotations An array of AnnotationSetRefList objects that contain the parameter - * annotations for the methods in parameterAnnotationMethods - */ - private AnnotationDirectoryItem(DexFile dexFile, AnnotationSetItem classAnnotations, - FieldIdItem[] fieldAnnotationFields, AnnotationSetItem[] fieldAnnotations, - MethodIdItem[] methodAnnotationMethods, AnnotationSetItem[] methodAnnotations, - MethodIdItem[] parameterAnnotationMethods, - AnnotationSetRefList[] parameterAnnotations) { - super(dexFile); - this.classAnnotations = classAnnotations; - this.fieldAnnotationFields = fieldAnnotationFields; - this.fieldAnnotations = fieldAnnotations; - this.methodAnnotationMethods = methodAnnotationMethods; - this.methodAnnotations = methodAnnotations; - this.parameterAnnotationMethods = parameterAnnotationMethods; - this.parameterAnnotations = parameterAnnotations; - } - - /** - * Returns an AnnotationDirectoryItem for the given values, and that has been interned into the given - * DexFile - * @param dexFile The DexFile that this item belongs to - * @param classAnnotations The annotations associated with the class - * @param fieldAnnotations A list of FieldAnnotation objects containing the field annotations - * @param methodAnnotations A list of MethodAnnotation objects containing the method annotations - * @param parameterAnnotations A list of ParameterAnnotation objects containin the parameter - * annotations - * @return an AnnotationItem for the given values, and that has been interned into the given - * DexFile - */ - public static AnnotationDirectoryItem getInternedAnnotationDirectoryItem(DexFile dexFile, - AnnotationSetItem classAnnotations, - List fieldAnnotations, - List methodAnnotations, - List parameterAnnotations) { - FieldIdItem[] fieldAnnotationFields = null; - AnnotationSetItem[] fieldAnnotationsArray = null; - MethodIdItem[] methodAnnotationMethods = null; - AnnotationSetItem[] methodAnnotationsArray = null; - MethodIdItem[] parameterAnnotationMethods = null; - AnnotationSetRefList[] parameterAnnotationsArray = null; - - if (fieldAnnotations != null && fieldAnnotations.size() > 0) { - fieldAnnotationFields = new FieldIdItem[fieldAnnotations.size()]; - fieldAnnotationsArray = new AnnotationSetItem[fieldAnnotations.size()]; - - Collections.sort(fieldAnnotations); - - int index = 0; - for (FieldAnnotation fieldAnnotation: fieldAnnotations) { - fieldAnnotationFields[index] = fieldAnnotation.field; - fieldAnnotationsArray[index++] = fieldAnnotation.annotationSet; - } - } - - if (methodAnnotations != null && methodAnnotations.size() > 0) { - methodAnnotationMethods = new MethodIdItem[methodAnnotations.size()]; - methodAnnotationsArray = new AnnotationSetItem[methodAnnotations.size()]; - - Collections.sort(methodAnnotations); - - int index = 0; - for (MethodAnnotation methodAnnotation: methodAnnotations) { - methodAnnotationMethods[index] = methodAnnotation.method; - methodAnnotationsArray[index++] = methodAnnotation.annotationSet; - } - } - - if (parameterAnnotations != null && parameterAnnotations.size() > 0) { - parameterAnnotationMethods = new MethodIdItem[parameterAnnotations.size()]; - parameterAnnotationsArray = new AnnotationSetRefList[parameterAnnotations.size()]; - - Collections.sort(parameterAnnotations); - - int index = 0; - for (ParameterAnnotation parameterAnnotation: parameterAnnotations) { - parameterAnnotationMethods[index] = parameterAnnotation.method; - parameterAnnotationsArray[index++] = parameterAnnotation.annotationSet; - } - } - - AnnotationDirectoryItem annotationDirectoryItem = new AnnotationDirectoryItem(dexFile, classAnnotations, - fieldAnnotationFields, fieldAnnotationsArray, methodAnnotationMethods, methodAnnotationsArray, - parameterAnnotationMethods, parameterAnnotationsArray); - return dexFile.AnnotationDirectoriesSection.intern(annotationDirectoryItem); - } - - /** {@inheritDoc} */ - protected void readItem(Input in, ReadContext readContext) { - classAnnotations = (AnnotationSetItem)readContext.getOffsettedItemByOffset(ItemType.TYPE_ANNOTATION_SET_ITEM, - in.readInt()); - fieldAnnotationFields = new FieldIdItem[in.readInt()]; - fieldAnnotations = new AnnotationSetItem[fieldAnnotationFields.length]; - - methodAnnotationMethods = new MethodIdItem[in.readInt()]; - methodAnnotations = new AnnotationSetItem[methodAnnotationMethods.length]; - - parameterAnnotationMethods = new MethodIdItem[in.readInt()]; - parameterAnnotations = new AnnotationSetRefList[parameterAnnotationMethods.length]; - - for (int i=0; iAnnotationDirectoryItem - */ - public int getFieldAnnotationCount() { - return fieldAnnotationFields.length; - } - - /** - * Iterates over the method annotations, calling delegate.processMethodAnnotations for each - * @param delegate the delegate to call - */ - public void iterateMethodAnnotations(MethodAnnotationIteratorDelegate delegate) { - for (int i=0; iAnnotationDirectoryItem - */ - public int getMethodAnnotationCount() { - return methodAnnotationMethods.length; - } - - /** - * Iterates over the parameter annotations, calling delegate.processParameterAnnotations for each - * @param delegate the delegate to call - */ - public void iterateParameterAnnotations(ParameterAnnotationIteratorDelegate delegate) { - for (int i=0; iAnnotationDirectoryItem - */ - public int getParameterAnnotationCount() { - return parameterAnnotationMethods.length; - } - - /** - * @return true if this AnnotationDirectoryItem is internable. It is only internable if it has - * only class annotations, but no field, method or parameter annotations - */ - private boolean isInternable() { - return classAnnotations != null && - (fieldAnnotations == null || fieldAnnotations.length == 0) && - (methodAnnotations == null || methodAnnotations.length == 0) && - (parameterAnnotations == null || parameterAnnotations.length == 0); - } - - /** - * Sets the ClassDefItem that this AnnotationDirectoryItem is associated with. - * This is only applicable if this AnnotationDirectoryItem contains only class annotations, and no field, method - * or parameter annotations. - * @param classDefItem the ClassDefItem that this AnnotationDirectoryItem is associated - * with - */ - protected void setParent(ClassDefItem classDefItem) { - this.parent = classDefItem; - } - - @Override - public int hashCode() { - //an instance is only internable if it has only class annotations, but - //no other type of annotation - if (!isInternable()) { - return super.hashCode(); - } - return classAnnotations.hashCode(); - } - - @Override - public boolean equals(Object o) { - if (this==o) { - return true; - } - if (o==null || !this.getClass().equals(o.getClass())) { - return false; - } - - AnnotationDirectoryItem other = (AnnotationDirectoryItem)o; - return (this.compareTo(other) == 0); - } - - public static class FieldAnnotation implements Comparable { - public final FieldIdItem field; - public final AnnotationSetItem annotationSet; - - public FieldAnnotation(FieldIdItem field, AnnotationSetItem annotationSet) { - this.field = field; - this.annotationSet = annotationSet; - } - - public int compareTo(FieldAnnotation other) { - return field.compareTo(other.field); - } - } - - public static class MethodAnnotation implements Comparable { - public final MethodIdItem method; - public final AnnotationSetItem annotationSet; - - public MethodAnnotation(MethodIdItem method, AnnotationSetItem annotationSet) { - this.method = method; - this.annotationSet = annotationSet; - } - - public int compareTo(MethodAnnotation other) { - return method.compareTo(other.method); - } - } - - public static class ParameterAnnotation implements Comparable { - public final MethodIdItem method; - public final AnnotationSetRefList annotationSet; - - public ParameterAnnotation(MethodIdItem method, AnnotationSetRefList annotationSet) { - this.method = method; - this.annotationSet = annotationSet; - } - - public int compareTo(ParameterAnnotation other) { - return method.compareTo(other.method); - } - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib; + +import org.jf.dexlib.Util.Input; +import org.jf.dexlib.Util.AnnotatedOutput; + +import java.util.Collections; +import java.util.List; + +public class AnnotationDirectoryItem extends Item { + private AnnotationSetItem classAnnotations; + + private FieldIdItem[] fieldAnnotationFields; + private AnnotationSetItem[] fieldAnnotations; + + private MethodIdItem[] methodAnnotationMethods; + private AnnotationSetItem[] methodAnnotations; + + private MethodIdItem[] parameterAnnotationMethods; + private AnnotationSetRefList[] parameterAnnotations; + + /** + * typically each AnnotationDirectoryItem will have a distinct parent. The only case that isn't true is when + * the AnnotationDirectoryItem *only* contains class annotations, with no other type of annotation. In that + * case, the same AnnotationDirectoryItem could be referenced from multiple classes. + * This isn't a problem though, because this field is only used in compareTo to determine the sort order, + * which handles it as a special case + */ + private ClassDefItem parent = null; + + /** + * Creates a new uninitialized AnnotationDirectoryItem + * @param dexFile The DexFile that this item belongs to + */ + protected AnnotationDirectoryItem(DexFile dexFile) { + super(dexFile); + } + + /** + * Creates a new AnnotationDirectoryItem with the given values + * @param dexFile The DexFile that this item belongs to + * @param classAnnotations The annotations associated with the overall class + * @param fieldAnnotationFields An array of FieldIdItem objects that the annotations in + * fieldAnnotations are associated with + * @param fieldAnnotations An array of AnnotationSetItem objects that contain the annotations for the + * fields in fieldAnnotationFields + * @param methodAnnotationMethods An array of MethodIdItem objects that the annotations in + * methodAnnotations are associated with + * @param methodAnnotations An array of AnnotationSetItem objects that contain the annotations for the + * methods in methodAnnotationMethods + * @param parameterAnnotationMethods An array of MethodIdItem objects that the annotations in + * parameterAnnotations are associated with + * @param parameterAnnotations An array of AnnotationSetRefList objects that contain the parameter + * annotations for the methods in parameterAnnotationMethods + */ + private AnnotationDirectoryItem(DexFile dexFile, AnnotationSetItem classAnnotations, + FieldIdItem[] fieldAnnotationFields, AnnotationSetItem[] fieldAnnotations, + MethodIdItem[] methodAnnotationMethods, AnnotationSetItem[] methodAnnotations, + MethodIdItem[] parameterAnnotationMethods, + AnnotationSetRefList[] parameterAnnotations) { + super(dexFile); + this.classAnnotations = classAnnotations; + this.fieldAnnotationFields = fieldAnnotationFields; + this.fieldAnnotations = fieldAnnotations; + this.methodAnnotationMethods = methodAnnotationMethods; + this.methodAnnotations = methodAnnotations; + this.parameterAnnotationMethods = parameterAnnotationMethods; + this.parameterAnnotations = parameterAnnotations; + } + + /** + * Returns an AnnotationDirectoryItem for the given values, and that has been interned into the given + * DexFile + * @param dexFile The DexFile that this item belongs to + * @param classAnnotations The annotations associated with the class + * @param fieldAnnotations A list of FieldAnnotation objects containing the field annotations + * @param methodAnnotations A list of MethodAnnotation objects containing the method annotations + * @param parameterAnnotations A list of ParameterAnnotation objects containin the parameter + * annotations + * @return an AnnotationItem for the given values, and that has been interned into the given + * DexFile + */ + public static AnnotationDirectoryItem getInternedAnnotationDirectoryItem(DexFile dexFile, + AnnotationSetItem classAnnotations, + List fieldAnnotations, + List methodAnnotations, + List parameterAnnotations) { + FieldIdItem[] fieldAnnotationFields = null; + AnnotationSetItem[] fieldAnnotationsArray = null; + MethodIdItem[] methodAnnotationMethods = null; + AnnotationSetItem[] methodAnnotationsArray = null; + MethodIdItem[] parameterAnnotationMethods = null; + AnnotationSetRefList[] parameterAnnotationsArray = null; + + if (fieldAnnotations != null && fieldAnnotations.size() > 0) { + fieldAnnotationFields = new FieldIdItem[fieldAnnotations.size()]; + fieldAnnotationsArray = new AnnotationSetItem[fieldAnnotations.size()]; + + Collections.sort(fieldAnnotations); + + int index = 0; + for (FieldAnnotation fieldAnnotation: fieldAnnotations) { + fieldAnnotationFields[index] = fieldAnnotation.field; + fieldAnnotationsArray[index++] = fieldAnnotation.annotationSet; + } + } + + if (methodAnnotations != null && methodAnnotations.size() > 0) { + methodAnnotationMethods = new MethodIdItem[methodAnnotations.size()]; + methodAnnotationsArray = new AnnotationSetItem[methodAnnotations.size()]; + + Collections.sort(methodAnnotations); + + int index = 0; + for (MethodAnnotation methodAnnotation: methodAnnotations) { + methodAnnotationMethods[index] = methodAnnotation.method; + methodAnnotationsArray[index++] = methodAnnotation.annotationSet; + } + } + + if (parameterAnnotations != null && parameterAnnotations.size() > 0) { + parameterAnnotationMethods = new MethodIdItem[parameterAnnotations.size()]; + parameterAnnotationsArray = new AnnotationSetRefList[parameterAnnotations.size()]; + + Collections.sort(parameterAnnotations); + + int index = 0; + for (ParameterAnnotation parameterAnnotation: parameterAnnotations) { + parameterAnnotationMethods[index] = parameterAnnotation.method; + parameterAnnotationsArray[index++] = parameterAnnotation.annotationSet; + } + } + + AnnotationDirectoryItem annotationDirectoryItem = new AnnotationDirectoryItem(dexFile, classAnnotations, + fieldAnnotationFields, fieldAnnotationsArray, methodAnnotationMethods, methodAnnotationsArray, + parameterAnnotationMethods, parameterAnnotationsArray); + return dexFile.AnnotationDirectoriesSection.intern(annotationDirectoryItem); + } + + /** {@inheritDoc} */ + protected void readItem(Input in, ReadContext readContext) { + classAnnotations = (AnnotationSetItem)readContext.getOffsettedItemByOffset(ItemType.TYPE_ANNOTATION_SET_ITEM, + in.readInt()); + fieldAnnotationFields = new FieldIdItem[in.readInt()]; + fieldAnnotations = new AnnotationSetItem[fieldAnnotationFields.length]; + + methodAnnotationMethods = new MethodIdItem[in.readInt()]; + methodAnnotations = new AnnotationSetItem[methodAnnotationMethods.length]; + + parameterAnnotationMethods = new MethodIdItem[in.readInt()]; + parameterAnnotations = new AnnotationSetRefList[parameterAnnotationMethods.length]; + + for (int i=0; iAnnotationDirectoryItem + */ + public int getFieldAnnotationCount() { + return fieldAnnotationFields.length; + } + + /** + * Iterates over the method annotations, calling delegate.processMethodAnnotations for each + * @param delegate the delegate to call + */ + public void iterateMethodAnnotations(MethodAnnotationIteratorDelegate delegate) { + for (int i=0; iAnnotationDirectoryItem + */ + public int getMethodAnnotationCount() { + return methodAnnotationMethods.length; + } + + /** + * Iterates over the parameter annotations, calling delegate.processParameterAnnotations for each + * @param delegate the delegate to call + */ + public void iterateParameterAnnotations(ParameterAnnotationIteratorDelegate delegate) { + for (int i=0; iAnnotationDirectoryItem + */ + public int getParameterAnnotationCount() { + return parameterAnnotationMethods.length; + } + + /** + * @return true if this AnnotationDirectoryItem is internable. It is only internable if it has + * only class annotations, but no field, method or parameter annotations + */ + private boolean isInternable() { + return classAnnotations != null && + (fieldAnnotations == null || fieldAnnotations.length == 0) && + (methodAnnotations == null || methodAnnotations.length == 0) && + (parameterAnnotations == null || parameterAnnotations.length == 0); + } + + /** + * Sets the ClassDefItem that this AnnotationDirectoryItem is associated with. + * This is only applicable if this AnnotationDirectoryItem contains only class annotations, and no field, method + * or parameter annotations. + * @param classDefItem the ClassDefItem that this AnnotationDirectoryItem is associated + * with + */ + protected void setParent(ClassDefItem classDefItem) { + this.parent = classDefItem; + } + + @Override + public int hashCode() { + //an instance is only internable if it has only class annotations, but + //no other type of annotation + if (!isInternable()) { + return super.hashCode(); + } + return classAnnotations.hashCode(); + } + + @Override + public boolean equals(Object o) { + if (this==o) { + return true; + } + if (o==null || !this.getClass().equals(o.getClass())) { + return false; + } + + AnnotationDirectoryItem other = (AnnotationDirectoryItem)o; + return (this.compareTo(other) == 0); + } + + public static class FieldAnnotation implements Comparable { + public final FieldIdItem field; + public final AnnotationSetItem annotationSet; + + public FieldAnnotation(FieldIdItem field, AnnotationSetItem annotationSet) { + this.field = field; + this.annotationSet = annotationSet; + } + + public int compareTo(FieldAnnotation other) { + return field.compareTo(other.field); + } + } + + public static class MethodAnnotation implements Comparable { + public final MethodIdItem method; + public final AnnotationSetItem annotationSet; + + public MethodAnnotation(MethodIdItem method, AnnotationSetItem annotationSet) { + this.method = method; + this.annotationSet = annotationSet; + } + + public int compareTo(MethodAnnotation other) { + return method.compareTo(other.method); + } + } + + public static class ParameterAnnotation implements Comparable { + public final MethodIdItem method; + public final AnnotationSetRefList annotationSet; + + public ParameterAnnotation(MethodIdItem method, AnnotationSetRefList annotationSet) { + this.method = method; + this.annotationSet = annotationSet; + } + + public int compareTo(ParameterAnnotation other) { + return method.compareTo(other.method); + } + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/AnnotationItem.java b/dexlib/src/main/java/org/jf/dexlib/AnnotationItem.java index c2b51c89..ec02004e 100644 --- a/dexlib/src/main/java/org/jf/dexlib/AnnotationItem.java +++ b/dexlib/src/main/java/org/jf/dexlib/AnnotationItem.java @@ -1,162 +1,162 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib; - -import org.jf.dexlib.EncodedValue.AnnotationEncodedSubValue; -import org.jf.dexlib.Util.Input; -import org.jf.dexlib.Util.AnnotatedOutput; - -public class AnnotationItem extends Item { - private int hashCode = 0; - - private AnnotationVisibility visibility; - private AnnotationEncodedSubValue annotationValue; - - /** - * Creates a new uninitialized AnnotationItem - * @param dexFile The DexFile that this item belongs to - */ - protected AnnotationItem(DexFile dexFile) { - super(dexFile); - } - - /** - * Creates a new AnnotationItem with the given values - * @param dexFile The DexFile that this item belongs to - * @param visibility The visibility of this annotation - * @param annotationValue The value of this annotation - */ - private AnnotationItem(DexFile dexFile, AnnotationVisibility visibility, - AnnotationEncodedSubValue annotationValue) { - super(dexFile); - this.visibility = visibility; - this.annotationValue = annotationValue; - } - - /** - * Returns an AnnotationItem for the given values, and that has been interned into the given - * DexFile - * @param dexFile The DexFile that this item belongs to - * @param visibility The visibility of this annotation - * @param annotationValue The value of this annotation - * @return an AnnotationItem for the given values, and that has been interned into the given - * DexFile - */ - public static AnnotationItem getInternedAnnotationItem(DexFile dexFile, AnnotationVisibility visibility, - AnnotationEncodedSubValue annotationValue) { - AnnotationItem annotationItem = new AnnotationItem(dexFile, visibility, annotationValue); - return dexFile.AnnotationsSection.intern(annotationItem); - } - - /** {@inheritDoc} */ - protected void readItem(Input in, ReadContext readContext) { - visibility = AnnotationVisibility.fromByte(in.readByte()); - annotationValue = new AnnotationEncodedSubValue(dexFile, in); - } - - /** {@inheritDoc} */ - protected int placeItem(int offset) { - return annotationValue.placeValue(offset + 1); - } - - /** {@inheritDoc} */ - protected void writeItem(AnnotatedOutput out) { - if (out.annotates()) { - out.annotate("visibility: " + visibility.name()); - out.writeByte(visibility.value); - annotationValue.writeValue(out); - }else { - out.writeByte(visibility.value); - annotationValue.writeValue(out); - } - } - - /** {@inheritDoc} */ - public ItemType getItemType() { - return ItemType.TYPE_ANNOTATION_ITEM; - } - - /** {@inheritDoc} */ - public String getConciseIdentity() { - return "annotation_item @0x" + Integer.toHexString(getOffset()); - } - - /** {@inheritDoc} */ - public int compareTo(AnnotationItem o) { - int comp = visibility.value - o.visibility.value; - if (comp == 0) { - comp = annotationValue.compareTo(o.annotationValue); - } - return comp; - } - - /** - * @return The visibility of this annotation - */ - public AnnotationVisibility getVisibility() { - return visibility; - } - - /** - * @return The encoded annotation value of this annotation - */ - public AnnotationEncodedSubValue getEncodedAnnotation() { - return annotationValue; - } - - /** - * calculate and cache the hashcode - */ - private void calcHashCode() { - hashCode = visibility.value; - hashCode = hashCode * 31 + annotationValue.hashCode(); - } - - @Override - public int hashCode() { - //there's a small possibility that the actual hash code will be 0. If so, we'll - //just end up recalculating it each time - if (hashCode == 0) - calcHashCode(); - return hashCode; - } - - @Override - public boolean equals(Object o) { - if (this==o) { - return true; - } - if (o==null || !this.getClass().equals(o.getClass())) { - return false; - } - - AnnotationItem other = (AnnotationItem)o; - return visibility == other.visibility && annotationValue.equals(other.annotationValue); - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib; + +import org.jf.dexlib.EncodedValue.AnnotationEncodedSubValue; +import org.jf.dexlib.Util.Input; +import org.jf.dexlib.Util.AnnotatedOutput; + +public class AnnotationItem extends Item { + private int hashCode = 0; + + private AnnotationVisibility visibility; + private AnnotationEncodedSubValue annotationValue; + + /** + * Creates a new uninitialized AnnotationItem + * @param dexFile The DexFile that this item belongs to + */ + protected AnnotationItem(DexFile dexFile) { + super(dexFile); + } + + /** + * Creates a new AnnotationItem with the given values + * @param dexFile The DexFile that this item belongs to + * @param visibility The visibility of this annotation + * @param annotationValue The value of this annotation + */ + private AnnotationItem(DexFile dexFile, AnnotationVisibility visibility, + AnnotationEncodedSubValue annotationValue) { + super(dexFile); + this.visibility = visibility; + this.annotationValue = annotationValue; + } + + /** + * Returns an AnnotationItem for the given values, and that has been interned into the given + * DexFile + * @param dexFile The DexFile that this item belongs to + * @param visibility The visibility of this annotation + * @param annotationValue The value of this annotation + * @return an AnnotationItem for the given values, and that has been interned into the given + * DexFile + */ + public static AnnotationItem getInternedAnnotationItem(DexFile dexFile, AnnotationVisibility visibility, + AnnotationEncodedSubValue annotationValue) { + AnnotationItem annotationItem = new AnnotationItem(dexFile, visibility, annotationValue); + return dexFile.AnnotationsSection.intern(annotationItem); + } + + /** {@inheritDoc} */ + protected void readItem(Input in, ReadContext readContext) { + visibility = AnnotationVisibility.fromByte(in.readByte()); + annotationValue = new AnnotationEncodedSubValue(dexFile, in); + } + + /** {@inheritDoc} */ + protected int placeItem(int offset) { + return annotationValue.placeValue(offset + 1); + } + + /** {@inheritDoc} */ + protected void writeItem(AnnotatedOutput out) { + if (out.annotates()) { + out.annotate("visibility: " + visibility.name()); + out.writeByte(visibility.value); + annotationValue.writeValue(out); + }else { + out.writeByte(visibility.value); + annotationValue.writeValue(out); + } + } + + /** {@inheritDoc} */ + public ItemType getItemType() { + return ItemType.TYPE_ANNOTATION_ITEM; + } + + /** {@inheritDoc} */ + public String getConciseIdentity() { + return "annotation_item @0x" + Integer.toHexString(getOffset()); + } + + /** {@inheritDoc} */ + public int compareTo(AnnotationItem o) { + int comp = visibility.value - o.visibility.value; + if (comp == 0) { + comp = annotationValue.compareTo(o.annotationValue); + } + return comp; + } + + /** + * @return The visibility of this annotation + */ + public AnnotationVisibility getVisibility() { + return visibility; + } + + /** + * @return The encoded annotation value of this annotation + */ + public AnnotationEncodedSubValue getEncodedAnnotation() { + return annotationValue; + } + + /** + * calculate and cache the hashcode + */ + private void calcHashCode() { + hashCode = visibility.value; + hashCode = hashCode * 31 + annotationValue.hashCode(); + } + + @Override + public int hashCode() { + //there's a small possibility that the actual hash code will be 0. If so, we'll + //just end up recalculating it each time + if (hashCode == 0) + calcHashCode(); + return hashCode; + } + + @Override + public boolean equals(Object o) { + if (this==o) { + return true; + } + if (o==null || !this.getClass().equals(o.getClass())) { + return false; + } + + AnnotationItem other = (AnnotationItem)o; + return visibility == other.visibility && annotationValue.equals(other.annotationValue); + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/AnnotationSetItem.java b/dexlib/src/main/java/org/jf/dexlib/AnnotationSetItem.java index 9aabf8be..945bd0cd 100644 --- a/dexlib/src/main/java/org/jf/dexlib/AnnotationSetItem.java +++ b/dexlib/src/main/java/org/jf/dexlib/AnnotationSetItem.java @@ -1,169 +1,169 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib; - -import org.jf.dexlib.Util.Input; -import org.jf.dexlib.Util.AnnotatedOutput; - -import java.util.List; - -public class AnnotationSetItem extends Item { - private int hashCode = 0; - - private AnnotationItem[] annotations; - - /** - * Creates a new uninitialized AnnotationSetItem - * @param dexFile The DexFile that this item belongs to - */ - protected AnnotationSetItem(DexFile dexFile) { - super(dexFile); - } - - /** - * Creates a new AnnotationSetItem for the given annotations - * @param dexFile The DexFile that this item belongs to - * @param annotations The annotations for this AnnotationSetItem - */ - private AnnotationSetItem(DexFile dexFile, AnnotationItem[] annotations) { - super(dexFile); - this.annotations = annotations; - } - - /** - * Returns an AnnotationSetItem for the given annotations, and that has been interned into the given - * DexFile - * @param dexFile The DexFile that this item belongs to - * @param annotations The annotations for this AnnotationSetItem - * @return an AnnotationSetItem for the given annotations - */ - public static AnnotationSetItem getInternedAnnotationSetItem(DexFile dexFile, List annotations) { - AnnotationItem[] annotationsArray = new AnnotationItem[annotations.size()]; - annotations.toArray(annotationsArray); - AnnotationSetItem annotationSetItem = new AnnotationSetItem(dexFile, annotationsArray); - return dexFile.AnnotationSetsSection.intern(annotationSetItem); - } - - /** {@inheritDoc} */ - protected void readItem(Input in, ReadContext readContext) { - annotations = new AnnotationItem[in.readInt()]; - - for (int i=0; iAnnotationItem objects in this AnnotationSetItem - */ - public AnnotationItem[] getAnnotations() { - return annotations; - } - - /** - * calculate and cache the hashcode - */ - private void calcHashCode() { - hashCode = 0; - for (AnnotationItem annotationItem: annotations) { - hashCode = hashCode * 31 + annotationItem.hashCode(); - } - } - - @Override - public int hashCode() { - //there's a small possibility that the actual hash code will be 0. If so, we'll - //just end up recalculating it each time - if (hashCode == 0) - calcHashCode(); - return hashCode; - } - - @Override - public boolean equals(Object o) { - if (this==o) { - return true; - } - if (o==null || !this.getClass().equals(o.getClass())) { - return false; - } - - AnnotationSetItem other = (AnnotationSetItem)o; - return (this.compareTo(other) == 0); - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib; + +import org.jf.dexlib.Util.Input; +import org.jf.dexlib.Util.AnnotatedOutput; + +import java.util.List; + +public class AnnotationSetItem extends Item { + private int hashCode = 0; + + private AnnotationItem[] annotations; + + /** + * Creates a new uninitialized AnnotationSetItem + * @param dexFile The DexFile that this item belongs to + */ + protected AnnotationSetItem(DexFile dexFile) { + super(dexFile); + } + + /** + * Creates a new AnnotationSetItem for the given annotations + * @param dexFile The DexFile that this item belongs to + * @param annotations The annotations for this AnnotationSetItem + */ + private AnnotationSetItem(DexFile dexFile, AnnotationItem[] annotations) { + super(dexFile); + this.annotations = annotations; + } + + /** + * Returns an AnnotationSetItem for the given annotations, and that has been interned into the given + * DexFile + * @param dexFile The DexFile that this item belongs to + * @param annotations The annotations for this AnnotationSetItem + * @return an AnnotationSetItem for the given annotations + */ + public static AnnotationSetItem getInternedAnnotationSetItem(DexFile dexFile, List annotations) { + AnnotationItem[] annotationsArray = new AnnotationItem[annotations.size()]; + annotations.toArray(annotationsArray); + AnnotationSetItem annotationSetItem = new AnnotationSetItem(dexFile, annotationsArray); + return dexFile.AnnotationSetsSection.intern(annotationSetItem); + } + + /** {@inheritDoc} */ + protected void readItem(Input in, ReadContext readContext) { + annotations = new AnnotationItem[in.readInt()]; + + for (int i=0; iAnnotationItem objects in this AnnotationSetItem + */ + public AnnotationItem[] getAnnotations() { + return annotations; + } + + /** + * calculate and cache the hashcode + */ + private void calcHashCode() { + hashCode = 0; + for (AnnotationItem annotationItem: annotations) { + hashCode = hashCode * 31 + annotationItem.hashCode(); + } + } + + @Override + public int hashCode() { + //there's a small possibility that the actual hash code will be 0. If so, we'll + //just end up recalculating it each time + if (hashCode == 0) + calcHashCode(); + return hashCode; + } + + @Override + public boolean equals(Object o) { + if (this==o) { + return true; + } + if (o==null || !this.getClass().equals(o.getClass())) { + return false; + } + + AnnotationSetItem other = (AnnotationSetItem)o; + return (this.compareTo(other) == 0); + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/AnnotationSetRefList.java b/dexlib/src/main/java/org/jf/dexlib/AnnotationSetRefList.java index 27a0b1f7..f280d637 100644 --- a/dexlib/src/main/java/org/jf/dexlib/AnnotationSetRefList.java +++ b/dexlib/src/main/java/org/jf/dexlib/AnnotationSetRefList.java @@ -1,170 +1,170 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib; - -import org.jf.dexlib.Util.Input; -import org.jf.dexlib.Util.AnnotatedOutput; - -import java.util.List; - -public class AnnotationSetRefList extends Item { - private int hashCode = 0; - - private AnnotationSetItem[] annotationSets; - - /** - * Creates a new uninitialized AnnotationSetRefList - * @param dexFile The DexFile that this item belongs to - */ - protected AnnotationSetRefList(DexFile dexFile) { - super(dexFile); - } - - /** - * Creates a new AnnotationSetRefList for the given annotation sets - * @param dexFile The DexFile that this item belongs to - * @param annotationSets The annotationSets for this AnnotationSetRefList - */ - private AnnotationSetRefList(DexFile dexFile, AnnotationSetItem[] annotationSets) { - super(dexFile); - this.annotationSets = annotationSets; - } - - /** - * Returns an AnnotationSetRefList for the given annotation sets, and that has been interned into the - * given DexFile - * @param dexFile The DexFile that this item belongs to - * @param annotationSets The annotation sets for this AnnotationSetRefList - * @return an AnnotationSetItem for the given annotations - */ - public static AnnotationSetRefList getInternedAnnotationSetRefList(DexFile dexFile, - List annotationSets) { - AnnotationSetItem[] annotationSetsArray = new AnnotationSetItem[annotationSets.size()]; - annotationSets.toArray(annotationSetsArray); - AnnotationSetRefList annotationSetRefList = new AnnotationSetRefList(dexFile, annotationSetsArray); - return dexFile.AnnotationSetRefListsSection.intern(annotationSetRefList); - } - - /** {@inheritDoc} */ - protected void readItem(Input in, ReadContext readContext) { - annotationSets = new AnnotationSetItem[in.readInt()]; - - for (int i=0; iAnnotationSetItem objects that make up this - * AnnotationSetRefList - */ - public AnnotationSetItem[] getAnnotationSets() { - return annotationSets; - } - - /** - * calculate and cache the hashcode - */ - private void calcHashCode() { - hashCode = 0; - for (AnnotationSetItem annotationSetItem: annotationSets) { - hashCode = hashCode * 31 + annotationSetItem.hashCode(); - } - } - - @Override - public int hashCode() { - //there's a small possibility that the actual hash code will be 0. If so, we'll - //just end up recalculating it each time - if (hashCode == 0) - calcHashCode(); - return hashCode; - } - - @Override - public boolean equals(Object o) { - if (this==o) { - return true; - } - if (o==null || !this.getClass().equals(o.getClass())) { - return false; - } - - AnnotationSetRefList other = (AnnotationSetRefList)o; - return (this.compareTo(other) == 0); - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib; + +import org.jf.dexlib.Util.Input; +import org.jf.dexlib.Util.AnnotatedOutput; + +import java.util.List; + +public class AnnotationSetRefList extends Item { + private int hashCode = 0; + + private AnnotationSetItem[] annotationSets; + + /** + * Creates a new uninitialized AnnotationSetRefList + * @param dexFile The DexFile that this item belongs to + */ + protected AnnotationSetRefList(DexFile dexFile) { + super(dexFile); + } + + /** + * Creates a new AnnotationSetRefList for the given annotation sets + * @param dexFile The DexFile that this item belongs to + * @param annotationSets The annotationSets for this AnnotationSetRefList + */ + private AnnotationSetRefList(DexFile dexFile, AnnotationSetItem[] annotationSets) { + super(dexFile); + this.annotationSets = annotationSets; + } + + /** + * Returns an AnnotationSetRefList for the given annotation sets, and that has been interned into the + * given DexFile + * @param dexFile The DexFile that this item belongs to + * @param annotationSets The annotation sets for this AnnotationSetRefList + * @return an AnnotationSetItem for the given annotations + */ + public static AnnotationSetRefList getInternedAnnotationSetRefList(DexFile dexFile, + List annotationSets) { + AnnotationSetItem[] annotationSetsArray = new AnnotationSetItem[annotationSets.size()]; + annotationSets.toArray(annotationSetsArray); + AnnotationSetRefList annotationSetRefList = new AnnotationSetRefList(dexFile, annotationSetsArray); + return dexFile.AnnotationSetRefListsSection.intern(annotationSetRefList); + } + + /** {@inheritDoc} */ + protected void readItem(Input in, ReadContext readContext) { + annotationSets = new AnnotationSetItem[in.readInt()]; + + for (int i=0; iAnnotationSetItem objects that make up this + * AnnotationSetRefList + */ + public AnnotationSetItem[] getAnnotationSets() { + return annotationSets; + } + + /** + * calculate and cache the hashcode + */ + private void calcHashCode() { + hashCode = 0; + for (AnnotationSetItem annotationSetItem: annotationSets) { + hashCode = hashCode * 31 + annotationSetItem.hashCode(); + } + } + + @Override + public int hashCode() { + //there's a small possibility that the actual hash code will be 0. If so, we'll + //just end up recalculating it each time + if (hashCode == 0) + calcHashCode(); + return hashCode; + } + + @Override + public boolean equals(Object o) { + if (this==o) { + return true; + } + if (o==null || !this.getClass().equals(o.getClass())) { + return false; + } + + AnnotationSetRefList other = (AnnotationSetRefList)o; + return (this.compareTo(other) == 0); + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/ClassDataItem.java b/dexlib/src/main/java/org/jf/dexlib/ClassDataItem.java index 11beb268..1ab6b282 100644 --- a/dexlib/src/main/java/org/jf/dexlib/ClassDataItem.java +++ b/dexlib/src/main/java/org/jf/dexlib/ClassDataItem.java @@ -1,531 +1,531 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib; - -import org.jf.dexlib.Util.*; - -import java.util.List; -import java.util.Collections; - -public class ClassDataItem extends Item { - private EncodedField[] staticFields; - private EncodedField[] instanceFields; - private EncodedMethod[] directMethods; - private EncodedMethod[] virtualMethods; - - private ClassDefItem parent = null; - - /** - * Creates a new uninitialized ClassDataItem - * @param dexFile The DexFile that this item belongs to - */ - public ClassDataItem(final DexFile dexFile) { - super(dexFile); - } - - /** - * Creates a new ClassDataItem with the given values - * @param dexFile The DexFile that this item belongs to - * @param staticFields The static fields for this class - * @param instanceFields The instance fields for this class - * @param directMethods The direct methods for this class - * @param virtualMethods The virtual methods for this class - */ - private ClassDataItem(DexFile dexFile, EncodedField[] staticFields, EncodedField[] instanceFields, - EncodedMethod[] directMethods, EncodedMethod[] virtualMethods) { - super(dexFile); - this.staticFields = staticFields==null?new EncodedField[0]:staticFields; - this.instanceFields = instanceFields==null?new EncodedField[0]:instanceFields; - this.directMethods = directMethods==null?new EncodedMethod[0]:directMethods; - this.virtualMethods = virtualMethods==null?new EncodedMethod[0]:virtualMethods; - } - - /** - * Creates a new ClassDataItem with the given values - * @param dexFile The DexFile that this item belongs to - * @param staticFields The static fields for this class - * @param instanceFields The instance fields for this class - * @param directMethods The direct methods for this class - * @param virtualMethods The virtual methods for this class - * @return a new ClassDataItem with the given values - */ - public static ClassDataItem getInternedClassDataItem(DexFile dexFile, List staticFields, - List instanceFields, - List directMethods, - List virtualMethods) { - EncodedField[] staticFieldsArray = null; - EncodedField[] instanceFieldsArray = null; - EncodedMethod[] directMethodsArray = null; - EncodedMethod[] virtualMethodsArray = null; - - if (staticFields != null && staticFields.size() > 0) { - Collections.sort(staticFields); - staticFieldsArray = new EncodedField[staticFields.size()]; - staticFields.toArray(staticFieldsArray); - } - - if (instanceFields != null && instanceFields.size() > 0) { - Collections.sort(instanceFields); - instanceFieldsArray = new EncodedField[instanceFields.size()]; - instanceFields.toArray(instanceFieldsArray); - } - - if (directMethods != null && directMethods.size() > 0) { - Collections.sort(directMethods); - directMethodsArray = new EncodedMethod[directMethods.size()]; - directMethods.toArray(directMethodsArray); - } - - if (virtualMethods != null && virtualMethods.size() > 0) { - Collections.sort(virtualMethods); - virtualMethodsArray = new EncodedMethod[virtualMethods.size()]; - virtualMethods.toArray(virtualMethodsArray); - } - - ClassDataItem classDataItem = new ClassDataItem(dexFile, staticFieldsArray, instanceFieldsArray, - directMethodsArray, virtualMethodsArray); - return dexFile.ClassDataSection.intern(classDataItem); - } - - /** {@inheritDoc} */ - protected void readItem(Input in, ReadContext readContext) { - staticFields = new EncodedField[in.readUnsignedLeb128()]; - instanceFields = new EncodedField[in.readUnsignedLeb128()]; - directMethods = new EncodedMethod[in.readUnsignedLeb128()]; - virtualMethods = new EncodedMethod[in.readUnsignedLeb128()]; - - EncodedField previousEncodedField = null; - for (int i=0; iClassDefItem that this ClassDataItem is associated with - * @param classDefItem the ClassDefItem that this ClassDataItem is associated with - */ - protected void setParent(ClassDefItem classDefItem) { - this.parent = classDefItem; - } - - /** - * @return the static fields for this class - */ - public EncodedField[] getStaticFields() { - return staticFields; - } - - /** - * @return the instance fields for this class - */ - public EncodedField[] getInstanceFields() { - return instanceFields; - } - - /** - * @return the direct methods for this class - */ - public EncodedMethod[] getDirectMethods() { - return directMethods; - } - - /** - * @return the virtual methods for this class - */ - public EncodedMethod[] getVirtualMethods() { - return virtualMethods; - } - - public static class EncodedField implements Comparable { - /** - * The FieldIdItem that this EncodedField is associated with - */ - public final FieldIdItem field; - - /** - * The access flags for this field - */ - public final int accessFlags; - - /** - * Constructs a new EncodedField with the given values - * @param field The FieldIdItem that this EncodedField is associated with - * @param accessFlags The access flags for this field - */ - public EncodedField(FieldIdItem field, int accessFlags) { - this.field = field; - this.accessFlags = accessFlags; - } - - /** - * This is used internally to construct a new EncodedField while reading in a DexFile - * @param dexFile The DexFile that is being read in - * @param in the Input object to read the EncodedField from - * @param previousEncodedField The previous EncodedField in the list containing this - * EncodedField. - */ - private EncodedField(DexFile dexFile, Input in, EncodedField previousEncodedField) { - int previousIndex = previousEncodedField==null?0:previousEncodedField.field.getIndex(); - field = dexFile.FieldIdsSection.getItemByIndex(in.readUnsignedLeb128() + previousIndex); - accessFlags = in.readUnsignedLeb128(); - } - - /** - * Writes the EncodedField to the given AnnotatedOutput object - * @param out the AnnotatedOutput object to write to - * @param previousEncodedField The previous EncodedField in the list containing this - * EncodedField. - */ - private void writeTo(AnnotatedOutput out, EncodedField previousEncodedField) { - int previousIndex = previousEncodedField==null?0:previousEncodedField.field.getIndex(); - - if (out.annotates()) { - out.annotate("field: " + field.getFieldString()); - out.writeUnsignedLeb128(field.getIndex() - previousIndex); - out.annotate("access_flags: " + AccessFlags.formatAccessFlagsForField(accessFlags)); - out.writeUnsignedLeb128(accessFlags); - }else { - out.writeUnsignedLeb128(field.getIndex() - previousIndex); - out.writeUnsignedLeb128(accessFlags); - } - } - - /** - * Calculates the size of this EncodedField and returns the offset - * immediately following it - * @param offset the offset of this EncodedField in the DexFile - * @param previousEncodedField The previous EncodedField in the list containing this - * EncodedField. - * @return the offset immediately following this EncodedField - */ - private int place(int offset, EncodedField previousEncodedField) { - int previousIndex = previousEncodedField==null?0:previousEncodedField.field.getIndex(); - - offset += Leb128Utils.unsignedLeb128Size(field.getIndex() - previousIndex); - offset += Leb128Utils.unsignedLeb128Size(accessFlags); - return offset; - } - - /** - * Compares this EncodedField to another, based on the comparison of the associated - * FieldIdItem - * @param other The EncodedField to compare against - * @return a standard integer comparison value indicating the relationship - */ - public int compareTo(EncodedField other) - { - return field.compareTo(other.field); - } - - /** - * @return true if this is a static field - */ - public boolean isStatic() { - return (accessFlags & AccessFlags.STATIC.getValue()) != 0; - } - } - - public static class EncodedMethod implements Comparable { - /** - * The MethodIdItem that this EncodedMethod is associated with - */ - public final MethodIdItem method; - - /** - * The access flags for this method - */ - public final int accessFlags; - - /** - * The CodeItem containing the code for this method, or null if there is no code for this method - * (i.e. an abstract method) - */ - public final CodeItem codeItem; - - /** - * Constructs a new EncodedMethod with the given values - * @param method The MethodIdItem that this EncodedMethod is associated with - * @param accessFlags The access flags for this method - * @param codeItem The CodeItem containing the code for this method, or null if there is no code - * for this method (i.e. an abstract method) - */ - public EncodedMethod(MethodIdItem method, int accessFlags, CodeItem codeItem) { - this.method = method; - this.accessFlags = accessFlags; - this.codeItem = codeItem; - if (codeItem != null) { - codeItem.setParent(this); - } - } - - /** - * This is used internally to construct a new EncodedMethod while reading in a DexFile - * @param dexFile The DexFile that is being read in - * @param readContext a ReadContext object to hold information that is only needed while reading - * in a file - * @param in the Input object to read the EncodedMethod from - * @param previousEncodedMethod The previous EncodedMethod in the list containing this - * EncodedMethod. - */ - public EncodedMethod(DexFile dexFile, ReadContext readContext, Input in, EncodedMethod previousEncodedMethod) { - int previousIndex = previousEncodedMethod==null?0:previousEncodedMethod.method.getIndex(); - method = dexFile.MethodIdsSection.getItemByIndex(in.readUnsignedLeb128() + previousIndex); - accessFlags = in.readUnsignedLeb128(); - codeItem = (CodeItem)readContext.getOffsettedItemByOffset(ItemType.TYPE_CODE_ITEM, in.readUnsignedLeb128()); - if (codeItem != null) { - codeItem.setParent(this); - } - } - - /** - * Writes the EncodedMethod to the given AnnotatedOutput object - * @param out the AnnotatedOutput object to write to - * @param previousEncodedMethod The previous EncodedMethod in the list containing this - * EncodedMethod. - */ - private void writeTo(AnnotatedOutput out, EncodedMethod previousEncodedMethod) { - int previousIndex = previousEncodedMethod==null?0:previousEncodedMethod.method.getIndex(); - - if (out.annotates()) { - out.annotate("method: " + method.getMethodString()); - out.writeUnsignedLeb128(method.getIndex() - previousIndex); - out.annotate("access_flags: " + AccessFlags.formatAccessFlagsForMethod(accessFlags)); - out.writeUnsignedLeb128(accessFlags); - if (codeItem != null) { - out.annotate("code_off: 0x" + codeItem.getOffset()); - out.writeUnsignedLeb128(codeItem.getOffset()); - } else { - out.annotate("code_off: 0x0"); - out.writeUnsignedLeb128(0); - } - }else { - out.writeUnsignedLeb128(method.getIndex() - previousIndex); - out.writeUnsignedLeb128(accessFlags); - out.writeUnsignedLeb128(codeItem==null?0:codeItem.getOffset()); - } - } - - /** - * Calculates the size of this EncodedMethod and returns the offset - * immediately following it - * @param offset the offset of this EncodedMethod in the DexFile - * @param previousEncodedMethod The previous EncodedMethod in the list containing this - * EncodedMethod. - * @return the offset immediately following this EncodedField - */ - private int place(int offset, EncodedMethod previousEncodedMethod) { - int previousIndex = previousEncodedMethod==null?0:previousEncodedMethod.method.getIndex(); - - offset += Leb128Utils.unsignedLeb128Size(method.getIndex() - previousIndex); - offset += Leb128Utils.unsignedLeb128Size(accessFlags); - offset += codeItem==null?1:Leb128Utils.unsignedLeb128Size(codeItem.getOffset()); - return offset; - } - - /** - * Compares this EncodedMethod to another, based on the comparison of the associated - * MethodIdItem - * @param other The EncodedMethod to compare against - * @return a standard integer comparison value indicating the relationship - */ - public int compareTo(EncodedMethod other) { - return method.compareTo(other.method); - } - - /** - * @return true if this is a direct method - */ - public boolean isDirect() { - return ((accessFlags & (AccessFlags.STATIC.getValue() | AccessFlags.PRIVATE.getValue() | - AccessFlags.CONSTRUCTOR.getValue())) != 0); - } - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib; + +import org.jf.dexlib.Util.*; + +import java.util.List; +import java.util.Collections; + +public class ClassDataItem extends Item { + private EncodedField[] staticFields; + private EncodedField[] instanceFields; + private EncodedMethod[] directMethods; + private EncodedMethod[] virtualMethods; + + private ClassDefItem parent = null; + + /** + * Creates a new uninitialized ClassDataItem + * @param dexFile The DexFile that this item belongs to + */ + public ClassDataItem(final DexFile dexFile) { + super(dexFile); + } + + /** + * Creates a new ClassDataItem with the given values + * @param dexFile The DexFile that this item belongs to + * @param staticFields The static fields for this class + * @param instanceFields The instance fields for this class + * @param directMethods The direct methods for this class + * @param virtualMethods The virtual methods for this class + */ + private ClassDataItem(DexFile dexFile, EncodedField[] staticFields, EncodedField[] instanceFields, + EncodedMethod[] directMethods, EncodedMethod[] virtualMethods) { + super(dexFile); + this.staticFields = staticFields==null?new EncodedField[0]:staticFields; + this.instanceFields = instanceFields==null?new EncodedField[0]:instanceFields; + this.directMethods = directMethods==null?new EncodedMethod[0]:directMethods; + this.virtualMethods = virtualMethods==null?new EncodedMethod[0]:virtualMethods; + } + + /** + * Creates a new ClassDataItem with the given values + * @param dexFile The DexFile that this item belongs to + * @param staticFields The static fields for this class + * @param instanceFields The instance fields for this class + * @param directMethods The direct methods for this class + * @param virtualMethods The virtual methods for this class + * @return a new ClassDataItem with the given values + */ + public static ClassDataItem getInternedClassDataItem(DexFile dexFile, List staticFields, + List instanceFields, + List directMethods, + List virtualMethods) { + EncodedField[] staticFieldsArray = null; + EncodedField[] instanceFieldsArray = null; + EncodedMethod[] directMethodsArray = null; + EncodedMethod[] virtualMethodsArray = null; + + if (staticFields != null && staticFields.size() > 0) { + Collections.sort(staticFields); + staticFieldsArray = new EncodedField[staticFields.size()]; + staticFields.toArray(staticFieldsArray); + } + + if (instanceFields != null && instanceFields.size() > 0) { + Collections.sort(instanceFields); + instanceFieldsArray = new EncodedField[instanceFields.size()]; + instanceFields.toArray(instanceFieldsArray); + } + + if (directMethods != null && directMethods.size() > 0) { + Collections.sort(directMethods); + directMethodsArray = new EncodedMethod[directMethods.size()]; + directMethods.toArray(directMethodsArray); + } + + if (virtualMethods != null && virtualMethods.size() > 0) { + Collections.sort(virtualMethods); + virtualMethodsArray = new EncodedMethod[virtualMethods.size()]; + virtualMethods.toArray(virtualMethodsArray); + } + + ClassDataItem classDataItem = new ClassDataItem(dexFile, staticFieldsArray, instanceFieldsArray, + directMethodsArray, virtualMethodsArray); + return dexFile.ClassDataSection.intern(classDataItem); + } + + /** {@inheritDoc} */ + protected void readItem(Input in, ReadContext readContext) { + staticFields = new EncodedField[in.readUnsignedLeb128()]; + instanceFields = new EncodedField[in.readUnsignedLeb128()]; + directMethods = new EncodedMethod[in.readUnsignedLeb128()]; + virtualMethods = new EncodedMethod[in.readUnsignedLeb128()]; + + EncodedField previousEncodedField = null; + for (int i=0; iClassDefItem that this ClassDataItem is associated with + * @param classDefItem the ClassDefItem that this ClassDataItem is associated with + */ + protected void setParent(ClassDefItem classDefItem) { + this.parent = classDefItem; + } + + /** + * @return the static fields for this class + */ + public EncodedField[] getStaticFields() { + return staticFields; + } + + /** + * @return the instance fields for this class + */ + public EncodedField[] getInstanceFields() { + return instanceFields; + } + + /** + * @return the direct methods for this class + */ + public EncodedMethod[] getDirectMethods() { + return directMethods; + } + + /** + * @return the virtual methods for this class + */ + public EncodedMethod[] getVirtualMethods() { + return virtualMethods; + } + + public static class EncodedField implements Comparable { + /** + * The FieldIdItem that this EncodedField is associated with + */ + public final FieldIdItem field; + + /** + * The access flags for this field + */ + public final int accessFlags; + + /** + * Constructs a new EncodedField with the given values + * @param field The FieldIdItem that this EncodedField is associated with + * @param accessFlags The access flags for this field + */ + public EncodedField(FieldIdItem field, int accessFlags) { + this.field = field; + this.accessFlags = accessFlags; + } + + /** + * This is used internally to construct a new EncodedField while reading in a DexFile + * @param dexFile The DexFile that is being read in + * @param in the Input object to read the EncodedField from + * @param previousEncodedField The previous EncodedField in the list containing this + * EncodedField. + */ + private EncodedField(DexFile dexFile, Input in, EncodedField previousEncodedField) { + int previousIndex = previousEncodedField==null?0:previousEncodedField.field.getIndex(); + field = dexFile.FieldIdsSection.getItemByIndex(in.readUnsignedLeb128() + previousIndex); + accessFlags = in.readUnsignedLeb128(); + } + + /** + * Writes the EncodedField to the given AnnotatedOutput object + * @param out the AnnotatedOutput object to write to + * @param previousEncodedField The previous EncodedField in the list containing this + * EncodedField. + */ + private void writeTo(AnnotatedOutput out, EncodedField previousEncodedField) { + int previousIndex = previousEncodedField==null?0:previousEncodedField.field.getIndex(); + + if (out.annotates()) { + out.annotate("field: " + field.getFieldString()); + out.writeUnsignedLeb128(field.getIndex() - previousIndex); + out.annotate("access_flags: " + AccessFlags.formatAccessFlagsForField(accessFlags)); + out.writeUnsignedLeb128(accessFlags); + }else { + out.writeUnsignedLeb128(field.getIndex() - previousIndex); + out.writeUnsignedLeb128(accessFlags); + } + } + + /** + * Calculates the size of this EncodedField and returns the offset + * immediately following it + * @param offset the offset of this EncodedField in the DexFile + * @param previousEncodedField The previous EncodedField in the list containing this + * EncodedField. + * @return the offset immediately following this EncodedField + */ + private int place(int offset, EncodedField previousEncodedField) { + int previousIndex = previousEncodedField==null?0:previousEncodedField.field.getIndex(); + + offset += Leb128Utils.unsignedLeb128Size(field.getIndex() - previousIndex); + offset += Leb128Utils.unsignedLeb128Size(accessFlags); + return offset; + } + + /** + * Compares this EncodedField to another, based on the comparison of the associated + * FieldIdItem + * @param other The EncodedField to compare against + * @return a standard integer comparison value indicating the relationship + */ + public int compareTo(EncodedField other) + { + return field.compareTo(other.field); + } + + /** + * @return true if this is a static field + */ + public boolean isStatic() { + return (accessFlags & AccessFlags.STATIC.getValue()) != 0; + } + } + + public static class EncodedMethod implements Comparable { + /** + * The MethodIdItem that this EncodedMethod is associated with + */ + public final MethodIdItem method; + + /** + * The access flags for this method + */ + public final int accessFlags; + + /** + * The CodeItem containing the code for this method, or null if there is no code for this method + * (i.e. an abstract method) + */ + public final CodeItem codeItem; + + /** + * Constructs a new EncodedMethod with the given values + * @param method The MethodIdItem that this EncodedMethod is associated with + * @param accessFlags The access flags for this method + * @param codeItem The CodeItem containing the code for this method, or null if there is no code + * for this method (i.e. an abstract method) + */ + public EncodedMethod(MethodIdItem method, int accessFlags, CodeItem codeItem) { + this.method = method; + this.accessFlags = accessFlags; + this.codeItem = codeItem; + if (codeItem != null) { + codeItem.setParent(this); + } + } + + /** + * This is used internally to construct a new EncodedMethod while reading in a DexFile + * @param dexFile The DexFile that is being read in + * @param readContext a ReadContext object to hold information that is only needed while reading + * in a file + * @param in the Input object to read the EncodedMethod from + * @param previousEncodedMethod The previous EncodedMethod in the list containing this + * EncodedMethod. + */ + public EncodedMethod(DexFile dexFile, ReadContext readContext, Input in, EncodedMethod previousEncodedMethod) { + int previousIndex = previousEncodedMethod==null?0:previousEncodedMethod.method.getIndex(); + method = dexFile.MethodIdsSection.getItemByIndex(in.readUnsignedLeb128() + previousIndex); + accessFlags = in.readUnsignedLeb128(); + codeItem = (CodeItem)readContext.getOffsettedItemByOffset(ItemType.TYPE_CODE_ITEM, in.readUnsignedLeb128()); + if (codeItem != null) { + codeItem.setParent(this); + } + } + + /** + * Writes the EncodedMethod to the given AnnotatedOutput object + * @param out the AnnotatedOutput object to write to + * @param previousEncodedMethod The previous EncodedMethod in the list containing this + * EncodedMethod. + */ + private void writeTo(AnnotatedOutput out, EncodedMethod previousEncodedMethod) { + int previousIndex = previousEncodedMethod==null?0:previousEncodedMethod.method.getIndex(); + + if (out.annotates()) { + out.annotate("method: " + method.getMethodString()); + out.writeUnsignedLeb128(method.getIndex() - previousIndex); + out.annotate("access_flags: " + AccessFlags.formatAccessFlagsForMethod(accessFlags)); + out.writeUnsignedLeb128(accessFlags); + if (codeItem != null) { + out.annotate("code_off: 0x" + codeItem.getOffset()); + out.writeUnsignedLeb128(codeItem.getOffset()); + } else { + out.annotate("code_off: 0x0"); + out.writeUnsignedLeb128(0); + } + }else { + out.writeUnsignedLeb128(method.getIndex() - previousIndex); + out.writeUnsignedLeb128(accessFlags); + out.writeUnsignedLeb128(codeItem==null?0:codeItem.getOffset()); + } + } + + /** + * Calculates the size of this EncodedMethod and returns the offset + * immediately following it + * @param offset the offset of this EncodedMethod in the DexFile + * @param previousEncodedMethod The previous EncodedMethod in the list containing this + * EncodedMethod. + * @return the offset immediately following this EncodedField + */ + private int place(int offset, EncodedMethod previousEncodedMethod) { + int previousIndex = previousEncodedMethod==null?0:previousEncodedMethod.method.getIndex(); + + offset += Leb128Utils.unsignedLeb128Size(method.getIndex() - previousIndex); + offset += Leb128Utils.unsignedLeb128Size(accessFlags); + offset += codeItem==null?1:Leb128Utils.unsignedLeb128Size(codeItem.getOffset()); + return offset; + } + + /** + * Compares this EncodedMethod to another, based on the comparison of the associated + * MethodIdItem + * @param other The EncodedMethod to compare against + * @return a standard integer comparison value indicating the relationship + */ + public int compareTo(EncodedMethod other) { + return method.compareTo(other.method); + } + + /** + * @return true if this is a direct method + */ + public boolean isDirect() { + return ((accessFlags & (AccessFlags.STATIC.getValue() | AccessFlags.PRIVATE.getValue() | + AccessFlags.CONSTRUCTOR.getValue())) != 0); + } + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/ClassDefItem.java b/dexlib/src/main/java/org/jf/dexlib/ClassDefItem.java index b15b6663..34e27b37 100644 --- a/dexlib/src/main/java/org/jf/dexlib/ClassDefItem.java +++ b/dexlib/src/main/java/org/jf/dexlib/ClassDefItem.java @@ -1,377 +1,377 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib; - -import org.jf.dexlib.Util.Input; -import org.jf.dexlib.Util.AnnotatedOutput; -import org.jf.dexlib.Util.AccessFlags; -import org.jf.dexlib.Util.TypeUtils; -import org.jf.dexlib.EncodedValue.EncodedValue; -import org.jf.dexlib.EncodedValue.ArrayEncodedSubValue; - -import java.util.*; - -public class ClassDefItem extends Item { - private TypeIdItem classType; - private int accessFlags; - private TypeIdItem superType; - private TypeListItem implementedInterfaces; - private StringIdItem sourceFile; - private AnnotationDirectoryItem annotations; - private ClassDataItem classData; - private EncodedArrayItem staticFieldInitializers; - - /** - * Creates a new uninitialized ClassDefItem - * @param dexFile The DexFile that this item belongs to - */ - protected ClassDefItem(DexFile dexFile) { - super(dexFile); - } - - /** - * Creates a new ClassDefItem with the given values - * @param dexFile The DexFile that this item belongs to - * @param classType The type of this class - * @param accessFlags The access flags of this class - * @param superType The superclass of this class, or null if none (only valid for java.lang.Object) - * @param implementedInterfaces A list of the interfaces that this class implements, or null if none - * @param sourceFile The main source file that this class is defined in, or null if not available - * @param annotations The annotations for this class and its fields, methods and method parameters, or null if none - * @param classData The ClassDataItem containing the method and field definitions for this class - * @param staticFieldInitializers The initial values for this class's static fields, or null if none. The initial - * values should be in the same order as the static fields in the ClassDataItem. It can contain - * fewer items than static fields, in which case the remaining static fields will be initialized with a default - * value of null/0. The initial value for any fields that don't specifically have a value can be either the - * type-appropriate null/0 encoded value, or null. - */ - private ClassDefItem(DexFile dexFile, TypeIdItem classType, int accessFlags, TypeIdItem superType, - TypeListItem implementedInterfaces, StringIdItem sourceFile, - AnnotationDirectoryItem annotations, ClassDataItem classData, - EncodedArrayItem staticFieldInitializers) { - super(dexFile); - this.classType = classType; - this.accessFlags = accessFlags; - this.superType = superType; - this.implementedInterfaces = implementedInterfaces; - this.sourceFile = sourceFile; - this.annotations = annotations; - this.classData = classData; - this.staticFieldInitializers = staticFieldInitializers; - - if (classData != null) { - classData.setParent(this); - } - if (annotations != null) { - annotations.setParent(this); - } - } - - /** - * Returns a ClassDefItem for the given values, and that has been interned into the given - * DexFile - * @param dexFile The DexFile that this item belongs to - * @param classType The type of this class - * @param accessFlags The access flags of this class - * @param superType The superclass of this class, or null if none (only valid for java.lang.Object) - * @param implementedInterfaces A list of the interfaces that this class implements, or null if none - * @param sourceFile The main source file that this class is defined in, or null if not available - * @param annotations The annotations for this class and its fields, methods and method parameters, or null if none - * @param classData The ClassDataItem containing the method and field definitions for this class - * @param staticFieldInitializers The initial values for this class's static fields, or null if none. If it is not - * null, it must contain the same number of items as the number of static fields in this class. The value in the - * StaticFieldInitializer for any field that doesn't have an explicit initial value can either be null - * or be the type-appropriate null/0 value. - * @return a ClassDefItem for the given values, and that has been interned into the given - * DexFile - */ - public static ClassDefItem getInternedClassDefItem(DexFile dexFile, TypeIdItem classType, int accessFlags, - TypeIdItem superType, TypeListItem implementedInterfaces, StringIdItem sourceFile, - AnnotationDirectoryItem annotations, ClassDataItem classData, - List staticFieldInitializers) { - EncodedArrayItem encodedArrayItem = null; - if(!dexFile.getInplace() && staticFieldInitializers != null && staticFieldInitializers.size() > 0) { - assert classData != null; - assert staticFieldInitializers.size() == classData.getStaticFields().length; - encodedArrayItem = makeStaticFieldInitializersItem(dexFile, staticFieldInitializers); - } - - ClassDefItem classDefItem = new ClassDefItem(dexFile, classType, accessFlags, superType, implementedInterfaces, - sourceFile, annotations, classData, encodedArrayItem); - return dexFile.ClassDefsSection.intern(classDefItem); - } - - /** {@inheritDoc} */ - protected void readItem(Input in, ReadContext readContext) { - classType = dexFile.TypeIdsSection.getItemByIndex(in.readInt()); - accessFlags = in.readInt(); - superType = dexFile.TypeIdsSection.getItemByIndex(in.readInt()); - implementedInterfaces = (TypeListItem)readContext.getOffsettedItemByOffset(ItemType.TYPE_TYPE_LIST, - in.readInt()); - sourceFile = dexFile.StringIdsSection.getItemByIndex(in.readInt()); - annotations = (AnnotationDirectoryItem)readContext.getOffsettedItemByOffset( - ItemType.TYPE_ANNOTATIONS_DIRECTORY_ITEM, in.readInt()); - classData = (ClassDataItem)readContext.getOffsettedItemByOffset(ItemType.TYPE_CLASS_DATA_ITEM, in.readInt()); - staticFieldInitializers = (EncodedArrayItem)readContext.getOffsettedItemByOffset( - ItemType.TYPE_ENCODED_ARRAY_ITEM, in.readInt()); - - if (classData != null) { - classData.setParent(this); - } - if (annotations != null) { - annotations.setParent(this); - } - } - - /** {@inheritDoc} */ - protected int placeItem(int offset) { - return offset + 32; - } - - /** {@inheritDoc} */ - protected void writeItem(AnnotatedOutput out) { - if (out.annotates()) { - out.annotate(4, "class_type: " + classType.getTypeDescriptor()); - out.annotate(4, "access_flags: " + AccessFlags.formatAccessFlagsForClass(accessFlags)); - out.annotate(4, "superclass_type: " + (superType==null?"":superType.getTypeDescriptor())); - out.annotate(4, "interfaces: " + - (implementedInterfaces==null?"":implementedInterfaces.getTypeListString(" "))); - out.annotate(4, "source_file: " + (sourceFile==null?"":sourceFile.getStringValue())); - out.annotate(4, "annotations_off: " + - (annotations==null?"":"0x"+Integer.toHexString(annotations.getOffset()))); - out.annotate(4, "class_data_off:" + - (classData==null?"":"0x"+Integer.toHexString(classData.getOffset()))); - out.annotate(4, "static_values_off: " + - (staticFieldInitializers==null?"":"0x"+Integer.toHexString(staticFieldInitializers.getOffset()))); - } - out.writeInt(classType.getIndex()); - out.writeInt(accessFlags); - out.writeInt(superType==null?-1:superType.getIndex()); - out.writeInt(implementedInterfaces==null?0:implementedInterfaces.getOffset()); - out.writeInt(sourceFile==null?-1:sourceFile.getIndex()); - out.writeInt(annotations==null?0:annotations.getOffset()); - out.writeInt(classData==null?0:classData.getOffset()); - out.writeInt(staticFieldInitializers==null?0:staticFieldInitializers.getOffset()); - } - - /** {@inheritDoc} */ - public ItemType getItemType() { - return ItemType.TYPE_CLASS_DEF_ITEM; - } - - /** {@inheritDoc} */ - public String getConciseIdentity() { - return "class_def_item: " + classType.getTypeDescriptor(); - } - - /** {@inheritDoc} */ - public int compareTo(ClassDefItem o) { - //The actual sorting for this class is implemented in SortClassDefItemSection. - //This method is just used for sorting the associated ClassDataItem items, so - //we can just do the comparison based on the offsets of the items - return this.getOffset() - o.getOffset(); - } - - public TypeIdItem getClassType() { - return classType; - } - - public int getAccessFlags() { - return accessFlags; - } - - public TypeIdItem getSuperclass() { - return superType; - } - - public TypeListItem getInterfaces() { - return implementedInterfaces; - } - - public StringIdItem getSourceFile() { - return sourceFile; - } - - public AnnotationDirectoryItem getAnnotations() { - return annotations; - } - - public ClassDataItem getClassData() { - return classData; - } - - public EncodedArrayItem getStaticFieldInitializers() { - return staticFieldInitializers; - } - - public static int placeClassDefItems(IndexedSection section, int offset) { - ClassDefPlacer cdp = new ClassDefPlacer(section); - return cdp.placeSection(offset); - } - - /** - * This class places the items within a ClassDefItem section, such that superclasses and interfaces are - * placed before sub/implementing classes - */ - private static class ClassDefPlacer { - private final IndexedSection section; - private final HashMap unplacedClassDefsByType = - new HashMap(); - - private int currentIndex = 0; - private int currentOffset; - - public ClassDefPlacer(IndexedSection section) { - this.section = section; - - for (ClassDefItem classDefItem: section.items) { - TypeIdItem typeIdItem = classDefItem.classType; - unplacedClassDefsByType.put(typeIdItem, classDefItem); - } - } - - public int placeSection(int offset) { - currentOffset = offset; - - if (section.DexFile.getSortAllItems()) { - //presort the list, to guarantee a unique ordering - Collections.sort(section.items, new Comparator() { - public int compare(ClassDefItem a, ClassDefItem b) { - return a.getClassType().compareTo(b.getClassType()); - } - }); - } - - //we need to initialize the offset for all the classes to -1, so we can tell which ones - //have been placed - for (ClassDefItem classDefItem: section.items) { - classDefItem.offset = -1; - } - - for (ClassDefItem classDefItem: section.items) { - placeClass(classDefItem); - } - - for (ClassDefItem classDefItem: unplacedClassDefsByType.values()) { - section.items.set(classDefItem.getIndex(), classDefItem); - } - - return currentOffset; - } - - private void placeClass(ClassDefItem classDefItem) { - if (classDefItem.getOffset() == -1) { - TypeIdItem superType = classDefItem.superType; - ClassDefItem superClassDefItem = unplacedClassDefsByType.get(superType); - - if (superClassDefItem != null) { - placeClass(superClassDefItem); - } - - TypeListItem interfaces = classDefItem.implementedInterfaces; - - if (interfaces != null) { - for (TypeIdItem interfaceType: interfaces.getTypes()) { - ClassDefItem interfaceClass = unplacedClassDefsByType.get(interfaceType); - if (interfaceClass != null) { - placeClass(interfaceClass); - } - } - } - - currentOffset = classDefItem.placeAt(currentOffset, currentIndex++); - unplacedClassDefsByType.remove(classDefItem.classType); - } - } - } - - public static class StaticFieldInitializer implements Comparable { - public final EncodedValue value; - public final ClassDataItem.EncodedField field; - public StaticFieldInitializer(EncodedValue value, ClassDataItem.EncodedField field) { - this.value = value; - this.field = field; - } - - public int compareTo(StaticFieldInitializer other) { - return field.compareTo(other.field); - } - } - - - /** - * A helper method to sort the static field initializers and populate the default values as needed - * @param dexFile the DexFile - * @param staticFieldInitializers the initial values - * @return an interned EncodedArrayItem containing the static field initializers - */ - private static EncodedArrayItem makeStaticFieldInitializersItem(DexFile dexFile, - List staticFieldInitializers) { - if (staticFieldInitializers == null || staticFieldInitializers.size() == 0) { - return null; - } - - int len = staticFieldInitializers.size(); - - Collections.sort(staticFieldInitializers); - - int lastIndex = -1; - for (int i=len-1; i>=0; i--) { - StaticFieldInitializer staticFieldInitializer = staticFieldInitializers.get(i); - - if (staticFieldInitializer.value != null && - (staticFieldInitializer.value.compareTo(TypeUtils.makeDefaultValueForType(dexFile, - staticFieldInitializer.field.field.getFieldType().getTypeDescriptor())) != 0)) { - lastIndex = i; - break; - } - } - - //we don't have any non-null/non-default values, so we don't need to create an EncodedArrayItem - if (lastIndex == -1) { - return null; - } - - EncodedValue[] values = new EncodedValue[lastIndex+1]; - - for (int i=0; i<=lastIndex; i++) { - StaticFieldInitializer staticFieldInitializer = staticFieldInitializers.get(i); - EncodedValue encodedValue = staticFieldInitializer.value; - if (encodedValue == null) { - encodedValue = TypeUtils.makeDefaultValueForType(dexFile, - staticFieldInitializer.field.field.getFieldType().getTypeDescriptor()); - } - - values[i] = encodedValue; - } - - ArrayEncodedSubValue encodedArrayValue = new ArrayEncodedSubValue(values); - return EncodedArrayItem.getInternedEncodedArrayItem(dexFile, encodedArrayValue); - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib; + +import org.jf.dexlib.Util.Input; +import org.jf.dexlib.Util.AnnotatedOutput; +import org.jf.dexlib.Util.AccessFlags; +import org.jf.dexlib.Util.TypeUtils; +import org.jf.dexlib.EncodedValue.EncodedValue; +import org.jf.dexlib.EncodedValue.ArrayEncodedSubValue; + +import java.util.*; + +public class ClassDefItem extends Item { + private TypeIdItem classType; + private int accessFlags; + private TypeIdItem superType; + private TypeListItem implementedInterfaces; + private StringIdItem sourceFile; + private AnnotationDirectoryItem annotations; + private ClassDataItem classData; + private EncodedArrayItem staticFieldInitializers; + + /** + * Creates a new uninitialized ClassDefItem + * @param dexFile The DexFile that this item belongs to + */ + protected ClassDefItem(DexFile dexFile) { + super(dexFile); + } + + /** + * Creates a new ClassDefItem with the given values + * @param dexFile The DexFile that this item belongs to + * @param classType The type of this class + * @param accessFlags The access flags of this class + * @param superType The superclass of this class, or null if none (only valid for java.lang.Object) + * @param implementedInterfaces A list of the interfaces that this class implements, or null if none + * @param sourceFile The main source file that this class is defined in, or null if not available + * @param annotations The annotations for this class and its fields, methods and method parameters, or null if none + * @param classData The ClassDataItem containing the method and field definitions for this class + * @param staticFieldInitializers The initial values for this class's static fields, or null if none. The initial + * values should be in the same order as the static fields in the ClassDataItem. It can contain + * fewer items than static fields, in which case the remaining static fields will be initialized with a default + * value of null/0. The initial value for any fields that don't specifically have a value can be either the + * type-appropriate null/0 encoded value, or null. + */ + private ClassDefItem(DexFile dexFile, TypeIdItem classType, int accessFlags, TypeIdItem superType, + TypeListItem implementedInterfaces, StringIdItem sourceFile, + AnnotationDirectoryItem annotations, ClassDataItem classData, + EncodedArrayItem staticFieldInitializers) { + super(dexFile); + this.classType = classType; + this.accessFlags = accessFlags; + this.superType = superType; + this.implementedInterfaces = implementedInterfaces; + this.sourceFile = sourceFile; + this.annotations = annotations; + this.classData = classData; + this.staticFieldInitializers = staticFieldInitializers; + + if (classData != null) { + classData.setParent(this); + } + if (annotations != null) { + annotations.setParent(this); + } + } + + /** + * Returns a ClassDefItem for the given values, and that has been interned into the given + * DexFile + * @param dexFile The DexFile that this item belongs to + * @param classType The type of this class + * @param accessFlags The access flags of this class + * @param superType The superclass of this class, or null if none (only valid for java.lang.Object) + * @param implementedInterfaces A list of the interfaces that this class implements, or null if none + * @param sourceFile The main source file that this class is defined in, or null if not available + * @param annotations The annotations for this class and its fields, methods and method parameters, or null if none + * @param classData The ClassDataItem containing the method and field definitions for this class + * @param staticFieldInitializers The initial values for this class's static fields, or null if none. If it is not + * null, it must contain the same number of items as the number of static fields in this class. The value in the + * StaticFieldInitializer for any field that doesn't have an explicit initial value can either be null + * or be the type-appropriate null/0 value. + * @return a ClassDefItem for the given values, and that has been interned into the given + * DexFile + */ + public static ClassDefItem getInternedClassDefItem(DexFile dexFile, TypeIdItem classType, int accessFlags, + TypeIdItem superType, TypeListItem implementedInterfaces, StringIdItem sourceFile, + AnnotationDirectoryItem annotations, ClassDataItem classData, + List staticFieldInitializers) { + EncodedArrayItem encodedArrayItem = null; + if(!dexFile.getInplace() && staticFieldInitializers != null && staticFieldInitializers.size() > 0) { + assert classData != null; + assert staticFieldInitializers.size() == classData.getStaticFields().length; + encodedArrayItem = makeStaticFieldInitializersItem(dexFile, staticFieldInitializers); + } + + ClassDefItem classDefItem = new ClassDefItem(dexFile, classType, accessFlags, superType, implementedInterfaces, + sourceFile, annotations, classData, encodedArrayItem); + return dexFile.ClassDefsSection.intern(classDefItem); + } + + /** {@inheritDoc} */ + protected void readItem(Input in, ReadContext readContext) { + classType = dexFile.TypeIdsSection.getItemByIndex(in.readInt()); + accessFlags = in.readInt(); + superType = dexFile.TypeIdsSection.getItemByIndex(in.readInt()); + implementedInterfaces = (TypeListItem)readContext.getOffsettedItemByOffset(ItemType.TYPE_TYPE_LIST, + in.readInt()); + sourceFile = dexFile.StringIdsSection.getItemByIndex(in.readInt()); + annotations = (AnnotationDirectoryItem)readContext.getOffsettedItemByOffset( + ItemType.TYPE_ANNOTATIONS_DIRECTORY_ITEM, in.readInt()); + classData = (ClassDataItem)readContext.getOffsettedItemByOffset(ItemType.TYPE_CLASS_DATA_ITEM, in.readInt()); + staticFieldInitializers = (EncodedArrayItem)readContext.getOffsettedItemByOffset( + ItemType.TYPE_ENCODED_ARRAY_ITEM, in.readInt()); + + if (classData != null) { + classData.setParent(this); + } + if (annotations != null) { + annotations.setParent(this); + } + } + + /** {@inheritDoc} */ + protected int placeItem(int offset) { + return offset + 32; + } + + /** {@inheritDoc} */ + protected void writeItem(AnnotatedOutput out) { + if (out.annotates()) { + out.annotate(4, "class_type: " + classType.getTypeDescriptor()); + out.annotate(4, "access_flags: " + AccessFlags.formatAccessFlagsForClass(accessFlags)); + out.annotate(4, "superclass_type: " + (superType==null?"":superType.getTypeDescriptor())); + out.annotate(4, "interfaces: " + + (implementedInterfaces==null?"":implementedInterfaces.getTypeListString(" "))); + out.annotate(4, "source_file: " + (sourceFile==null?"":sourceFile.getStringValue())); + out.annotate(4, "annotations_off: " + + (annotations==null?"":"0x"+Integer.toHexString(annotations.getOffset()))); + out.annotate(4, "class_data_off:" + + (classData==null?"":"0x"+Integer.toHexString(classData.getOffset()))); + out.annotate(4, "static_values_off: " + + (staticFieldInitializers==null?"":"0x"+Integer.toHexString(staticFieldInitializers.getOffset()))); + } + out.writeInt(classType.getIndex()); + out.writeInt(accessFlags); + out.writeInt(superType==null?-1:superType.getIndex()); + out.writeInt(implementedInterfaces==null?0:implementedInterfaces.getOffset()); + out.writeInt(sourceFile==null?-1:sourceFile.getIndex()); + out.writeInt(annotations==null?0:annotations.getOffset()); + out.writeInt(classData==null?0:classData.getOffset()); + out.writeInt(staticFieldInitializers==null?0:staticFieldInitializers.getOffset()); + } + + /** {@inheritDoc} */ + public ItemType getItemType() { + return ItemType.TYPE_CLASS_DEF_ITEM; + } + + /** {@inheritDoc} */ + public String getConciseIdentity() { + return "class_def_item: " + classType.getTypeDescriptor(); + } + + /** {@inheritDoc} */ + public int compareTo(ClassDefItem o) { + //The actual sorting for this class is implemented in SortClassDefItemSection. + //This method is just used for sorting the associated ClassDataItem items, so + //we can just do the comparison based on the offsets of the items + return this.getOffset() - o.getOffset(); + } + + public TypeIdItem getClassType() { + return classType; + } + + public int getAccessFlags() { + return accessFlags; + } + + public TypeIdItem getSuperclass() { + return superType; + } + + public TypeListItem getInterfaces() { + return implementedInterfaces; + } + + public StringIdItem getSourceFile() { + return sourceFile; + } + + public AnnotationDirectoryItem getAnnotations() { + return annotations; + } + + public ClassDataItem getClassData() { + return classData; + } + + public EncodedArrayItem getStaticFieldInitializers() { + return staticFieldInitializers; + } + + public static int placeClassDefItems(IndexedSection section, int offset) { + ClassDefPlacer cdp = new ClassDefPlacer(section); + return cdp.placeSection(offset); + } + + /** + * This class places the items within a ClassDefItem section, such that superclasses and interfaces are + * placed before sub/implementing classes + */ + private static class ClassDefPlacer { + private final IndexedSection section; + private final HashMap unplacedClassDefsByType = + new HashMap(); + + private int currentIndex = 0; + private int currentOffset; + + public ClassDefPlacer(IndexedSection section) { + this.section = section; + + for (ClassDefItem classDefItem: section.items) { + TypeIdItem typeIdItem = classDefItem.classType; + unplacedClassDefsByType.put(typeIdItem, classDefItem); + } + } + + public int placeSection(int offset) { + currentOffset = offset; + + if (section.DexFile.getSortAllItems()) { + //presort the list, to guarantee a unique ordering + Collections.sort(section.items, new Comparator() { + public int compare(ClassDefItem a, ClassDefItem b) { + return a.getClassType().compareTo(b.getClassType()); + } + }); + } + + //we need to initialize the offset for all the classes to -1, so we can tell which ones + //have been placed + for (ClassDefItem classDefItem: section.items) { + classDefItem.offset = -1; + } + + for (ClassDefItem classDefItem: section.items) { + placeClass(classDefItem); + } + + for (ClassDefItem classDefItem: unplacedClassDefsByType.values()) { + section.items.set(classDefItem.getIndex(), classDefItem); + } + + return currentOffset; + } + + private void placeClass(ClassDefItem classDefItem) { + if (classDefItem.getOffset() == -1) { + TypeIdItem superType = classDefItem.superType; + ClassDefItem superClassDefItem = unplacedClassDefsByType.get(superType); + + if (superClassDefItem != null) { + placeClass(superClassDefItem); + } + + TypeListItem interfaces = classDefItem.implementedInterfaces; + + if (interfaces != null) { + for (TypeIdItem interfaceType: interfaces.getTypes()) { + ClassDefItem interfaceClass = unplacedClassDefsByType.get(interfaceType); + if (interfaceClass != null) { + placeClass(interfaceClass); + } + } + } + + currentOffset = classDefItem.placeAt(currentOffset, currentIndex++); + unplacedClassDefsByType.remove(classDefItem.classType); + } + } + } + + public static class StaticFieldInitializer implements Comparable { + public final EncodedValue value; + public final ClassDataItem.EncodedField field; + public StaticFieldInitializer(EncodedValue value, ClassDataItem.EncodedField field) { + this.value = value; + this.field = field; + } + + public int compareTo(StaticFieldInitializer other) { + return field.compareTo(other.field); + } + } + + + /** + * A helper method to sort the static field initializers and populate the default values as needed + * @param dexFile the DexFile + * @param staticFieldInitializers the initial values + * @return an interned EncodedArrayItem containing the static field initializers + */ + private static EncodedArrayItem makeStaticFieldInitializersItem(DexFile dexFile, + List staticFieldInitializers) { + if (staticFieldInitializers == null || staticFieldInitializers.size() == 0) { + return null; + } + + int len = staticFieldInitializers.size(); + + Collections.sort(staticFieldInitializers); + + int lastIndex = -1; + for (int i=len-1; i>=0; i--) { + StaticFieldInitializer staticFieldInitializer = staticFieldInitializers.get(i); + + if (staticFieldInitializer.value != null && + (staticFieldInitializer.value.compareTo(TypeUtils.makeDefaultValueForType(dexFile, + staticFieldInitializer.field.field.getFieldType().getTypeDescriptor())) != 0)) { + lastIndex = i; + break; + } + } + + //we don't have any non-null/non-default values, so we don't need to create an EncodedArrayItem + if (lastIndex == -1) { + return null; + } + + EncodedValue[] values = new EncodedValue[lastIndex+1]; + + for (int i=0; i<=lastIndex; i++) { + StaticFieldInitializer staticFieldInitializer = staticFieldInitializers.get(i); + EncodedValue encodedValue = staticFieldInitializer.value; + if (encodedValue == null) { + encodedValue = TypeUtils.makeDefaultValueForType(dexFile, + staticFieldInitializer.field.field.getFieldType().getTypeDescriptor()); + } + + values[i] = encodedValue; + } + + ArrayEncodedSubValue encodedArrayValue = new ArrayEncodedSubValue(values); + return EncodedArrayItem.getInternedEncodedArrayItem(dexFile, encodedArrayValue); + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/ArrayDataPseudoInstruction.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/ArrayDataPseudoInstruction.java index 84e45405..96847d76 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/ArrayDataPseudoInstruction.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/ArrayDataPseudoInstruction.java @@ -1,138 +1,138 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format; - -import org.jf.dexlib.Code.Instruction; -import org.jf.dexlib.Code.Opcode; -import org.jf.dexlib.Util.NumberUtils; -import org.jf.dexlib.Util.Output; -import org.jf.dexlib.DexFile; - -import java.util.Iterator; - -public class ArrayDataPseudoInstruction extends Instruction { - public static final Instruction.InstructionFactory Factory = new Factory(); - - @Override - public int getSize() { - int size = getElementWidth() * getElementCount(); - return size + (size & 0x01) + 8; - } - - public static void emit(Output out, int elementWidth, byte[] encodedValues) { - if (encodedValues.length % elementWidth != 0) { - throw new RuntimeException("There are not a whole number of " + elementWidth + " byte elements"); - } - - //write out padding, if necessary - if (out.getCursor() % 4 != 0) { - out.writeShort(0); - } - - int elementCount = encodedValues.length / elementWidth; - - out.writeByte(0x00); - out.writeByte(0x03); - out.writeShort(elementWidth); - out.writeInt(elementCount); - out.write(encodedValues); - if ((encodedValues.length % 2) != 0) { - //must write out an even number of bytes - out.writeByte(0); - } - } - - public ArrayDataPseudoInstruction(byte[] buffer, int bufferIndex) { - super(Opcode.NOP, buffer, bufferIndex); - - byte opcodeByte = buffer[bufferIndex++]; - if (opcodeByte != 0x00) { - throw new RuntimeException("Invalid opcode byte for an ArrayData pseudo-instruction"); - } - - byte subopcodeByte = buffer[bufferIndex]; - if (subopcodeByte != 0x03) { - throw new RuntimeException("Invalid sub-opcode byte for an ArrayData pseudo-instruction"); - } - } - - public Format getFormat() { - return Format.ArrayData; - } - - public int getElementWidth() { - return NumberUtils.decodeUnsignedShort(buffer[bufferIndex+2], buffer[bufferIndex+3]); - } - - public int getElementCount() { - return NumberUtils.decodeInt(buffer, bufferIndex+4); - } - - public static class ArrayElement { - public final byte[] buffer; - public int bufferIndex; - public final int elementWidth; - public ArrayElement(byte[] buffer, int elementWidth) { - this.buffer = buffer; - this.elementWidth = elementWidth; - } - } - - public Iterator getElements() { - return new Iterator() { - final int elementCount = getElementCount(); - int i=0; - int position = bufferIndex + 8; - final ArrayElement arrayElement = new ArrayElement(buffer, getElementWidth()); - - public boolean hasNext() { - return i getElements() { + return new Iterator() { + final int elementCount = getElementCount(); + int i=0; + int position = bufferIndex + 8; + final ArrayElement arrayElement = new ArrayElement(buffer, getElementWidth()); + + public boolean hasNext() { + return i= 1 << 4) { - throw new RuntimeException("The register number must be less than v16"); - } - - if (litB < -(1 << 3) || - litB >= 1 << 3) { - throw new RuntimeException("The literal value must be between -8 and 7 inclusive"); - } - - out.writeByte(opcode.value); - out.writeByte((litB << 4) | regA); - } - - private Instruction11n(Opcode opcode, byte[] buffer, int bufferIndex) { - super(opcode, buffer, bufferIndex); - } - - public Format getFormat() { - return Format.Format11n; - } - - public int getRegisterA() { - return NumberUtils.decodeLowUnsignedNibble(buffer[bufferIndex + 1]); - } - - public long getLiteral() { - return NumberUtils.decodeHighSignedNibble(buffer[bufferIndex + 1]); - } - - private static class Factory implements Instruction.InstructionFactory { - public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { - return new Instruction11n(opcode, buffer, bufferIndex); - } - } +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format; + +import org.jf.dexlib.Code.Instruction; +import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.SingleRegisterInstruction; +import org.jf.dexlib.Code.LiteralInstruction; +import org.jf.dexlib.DexFile; +import org.jf.dexlib.Util.NumberUtils; +import org.jf.dexlib.Util.Output; + +public class Instruction11n extends Instruction implements SingleRegisterInstruction, LiteralInstruction { + public static final InstructionFactory Factory = new Factory(); + + public static void emit(Output out, Opcode opcode, byte regA, byte litB) { + if (regA >= 1 << 4) { + throw new RuntimeException("The register number must be less than v16"); + } + + if (litB < -(1 << 3) || + litB >= 1 << 3) { + throw new RuntimeException("The literal value must be between -8 and 7 inclusive"); + } + + out.writeByte(opcode.value); + out.writeByte((litB << 4) | regA); + } + + private Instruction11n(Opcode opcode, byte[] buffer, int bufferIndex) { + super(opcode, buffer, bufferIndex); + } + + public Format getFormat() { + return Format.Format11n; + } + + public int getRegisterA() { + return NumberUtils.decodeLowUnsignedNibble(buffer[bufferIndex + 1]); + } + + public long getLiteral() { + return NumberUtils.decodeHighSignedNibble(buffer[bufferIndex + 1]); + } + + private static class Factory implements Instruction.InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { + return new Instruction11n(opcode, buffer, bufferIndex); + } + } } \ No newline at end of file diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction11x.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction11x.java index 37f62874..df874dba 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction11x.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction11x.java @@ -1,67 +1,67 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format; - -import org.jf.dexlib.Code.Instruction; -import org.jf.dexlib.Code.Opcode; -import org.jf.dexlib.Code.SingleRegisterInstruction; -import org.jf.dexlib.DexFile; -import org.jf.dexlib.Util.NumberUtils; -import org.jf.dexlib.Util.Output; - -public class Instruction11x extends Instruction implements SingleRegisterInstruction { - public static final Instruction.InstructionFactory Factory = new Factory(); - - public static void emit(Output out, Opcode opcode, short regA) { - if (regA >= 1 << 8) { - throw new RuntimeException("The register number must be less than v256"); - } - - out.writeByte(opcode.value); - out.writeByte(regA); - } - - private Instruction11x(Opcode opcode, byte[] buffer, int bufferIndex) { - super(opcode, buffer, bufferIndex); - } - - public Format getFormat() { - return Format.Format11x; - } - - public int getRegisterA() { - return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]); - } - - private static class Factory implements Instruction.InstructionFactory { - public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { - return new Instruction11x(opcode, buffer, bufferIndex); - } - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format; + +import org.jf.dexlib.Code.Instruction; +import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.SingleRegisterInstruction; +import org.jf.dexlib.DexFile; +import org.jf.dexlib.Util.NumberUtils; +import org.jf.dexlib.Util.Output; + +public class Instruction11x extends Instruction implements SingleRegisterInstruction { + public static final Instruction.InstructionFactory Factory = new Factory(); + + public static void emit(Output out, Opcode opcode, short regA) { + if (regA >= 1 << 8) { + throw new RuntimeException("The register number must be less than v256"); + } + + out.writeByte(opcode.value); + out.writeByte(regA); + } + + private Instruction11x(Opcode opcode, byte[] buffer, int bufferIndex) { + super(opcode, buffer, bufferIndex); + } + + public Format getFormat() { + return Format.Format11x; + } + + public int getRegisterA() { + return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]); + } + + private static class Factory implements Instruction.InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { + return new Instruction11x(opcode, buffer, bufferIndex); + } + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction12x.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction12x.java index 2c6443e1..299312d3 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction12x.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction12x.java @@ -1,72 +1,72 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format; - -import org.jf.dexlib.Code.Instruction; -import org.jf.dexlib.Code.Opcode; -import org.jf.dexlib.Code.TwoRegisterInstruction; -import org.jf.dexlib.DexFile; -import org.jf.dexlib.Util.NumberUtils; -import org.jf.dexlib.Util.Output; - -public class Instruction12x extends Instruction implements TwoRegisterInstruction { - public static final Instruction.InstructionFactory Factory = new Factory(); - - public static void emit(Output out, Opcode opcode, byte regA, byte regB) { - if (regA >= 1 << 4 || - regB >= 1 << 4) { - throw new RuntimeException("The register number must be less than v16"); - } - - out.writeByte(opcode.value); - out.writeByte((regB << 4) | regA); - } - - private Instruction12x(Opcode opcode, byte[] buffer, int bufferIndex) { - super(opcode, buffer, bufferIndex); - } - - public Format getFormat() { - return Format.Format12x; - } - - public int getRegisterA() { - return NumberUtils.decodeLowUnsignedNibble(buffer[bufferIndex + 1]); - } - - public int getRegisterB() { - return NumberUtils.decodeHighUnsignedNibble(buffer[bufferIndex + 1]); - } - - private static class Factory implements Instruction.InstructionFactory { - public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { - return new Instruction12x(opcode, buffer, bufferIndex); - } - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format; + +import org.jf.dexlib.Code.Instruction; +import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.TwoRegisterInstruction; +import org.jf.dexlib.DexFile; +import org.jf.dexlib.Util.NumberUtils; +import org.jf.dexlib.Util.Output; + +public class Instruction12x extends Instruction implements TwoRegisterInstruction { + public static final Instruction.InstructionFactory Factory = new Factory(); + + public static void emit(Output out, Opcode opcode, byte regA, byte regB) { + if (regA >= 1 << 4 || + regB >= 1 << 4) { + throw new RuntimeException("The register number must be less than v16"); + } + + out.writeByte(opcode.value); + out.writeByte((regB << 4) | regA); + } + + private Instruction12x(Opcode opcode, byte[] buffer, int bufferIndex) { + super(opcode, buffer, bufferIndex); + } + + public Format getFormat() { + return Format.Format12x; + } + + public int getRegisterA() { + return NumberUtils.decodeLowUnsignedNibble(buffer[bufferIndex + 1]); + } + + public int getRegisterB() { + return NumberUtils.decodeHighUnsignedNibble(buffer[bufferIndex + 1]); + } + + private static class Factory implements Instruction.InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { + return new Instruction12x(opcode, buffer, bufferIndex); + } + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction20t.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction20t.java index 6ea48a9d..6168bc19 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction20t.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction20t.java @@ -1,72 +1,72 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format; - -import org.jf.dexlib.Code.Instruction; -import org.jf.dexlib.Code.Opcode; -import org.jf.dexlib.Code.OffsetInstruction; -import org.jf.dexlib.DexFile; -import org.jf.dexlib.Util.NumberUtils; -import org.jf.dexlib.Util.Output; - -public class Instruction20t extends Instruction implements OffsetInstruction { - public static final Instruction.InstructionFactory Factory = new Factory(); - - public static void emit(Output out, Opcode opcode, short offA) { - if (offA == 0) { - throw new RuntimeException("The offset cannot be 0. Use goto/32 instead."); - } - - out.writeByte(opcode.value); - out.writeByte(0); - out.writeShort(offA); - } - - private Instruction20t(Opcode opcode, byte[] buffer, int bufferIndex) { - super(opcode, buffer, bufferIndex); - - if (getOffset() == 0) { - throw new RuntimeException("The offset cannot be 0. Use goto/32 instead."); - } - } - - public Format getFormat() { - return Format.Format20t; - } - - public int getOffset() { - return NumberUtils.decodeShort(buffer, bufferIndex + 2); - } - - private static class Factory implements Instruction.InstructionFactory { - public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { - return new Instruction20t(opcode, buffer, bufferIndex); - } - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format; + +import org.jf.dexlib.Code.Instruction; +import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.OffsetInstruction; +import org.jf.dexlib.DexFile; +import org.jf.dexlib.Util.NumberUtils; +import org.jf.dexlib.Util.Output; + +public class Instruction20t extends Instruction implements OffsetInstruction { + public static final Instruction.InstructionFactory Factory = new Factory(); + + public static void emit(Output out, Opcode opcode, short offA) { + if (offA == 0) { + throw new RuntimeException("The offset cannot be 0. Use goto/32 instead."); + } + + out.writeByte(opcode.value); + out.writeByte(0); + out.writeShort(offA); + } + + private Instruction20t(Opcode opcode, byte[] buffer, int bufferIndex) { + super(opcode, buffer, bufferIndex); + + if (getOffset() == 0) { + throw new RuntimeException("The offset cannot be 0. Use goto/32 instead."); + } + } + + public Format getFormat() { + return Format.Format20t; + } + + public int getOffset() { + return NumberUtils.decodeShort(buffer, bufferIndex + 2); + } + + private static class Factory implements Instruction.InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { + return new Instruction20t(opcode, buffer, bufferIndex); + } + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21c.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21c.java index 6b56e55e..e4bbcc30 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21c.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21c.java @@ -1,82 +1,82 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format; - -import org.jf.dexlib.Code.Instruction; -import org.jf.dexlib.Code.InstructionWithReference; -import org.jf.dexlib.Code.Opcode; -import org.jf.dexlib.Code.SingleRegisterInstruction; -import org.jf.dexlib.DexFile; -import org.jf.dexlib.Item; -import org.jf.dexlib.TypeIdItem; -import org.jf.dexlib.Util.NumberUtils; -import org.jf.dexlib.Util.Output; - -public class Instruction21c extends InstructionWithReference implements SingleRegisterInstruction { - public static final Instruction.InstructionFactory Factory = new Factory(); - - public static void emit(Output out, Opcode opcode, short regA, Item referencedItem) { - if (regA >= 1 << 8) { - throw new RuntimeException("The register number must be less than v256"); - } - - if (opcode == Opcode.NEW_INSTANCE) { - assert referencedItem instanceof TypeIdItem; - if (((TypeIdItem)referencedItem).getTypeDescriptor().charAt(0) != 'L') { - throw new RuntimeException("Only class references can be used with the new-instance opcode"); - } - } - - out.writeByte(opcode.value); - out.writeByte(regA); - out.writeShort(0); - } - - private Instruction21c(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { - super(dexFile, opcode, buffer, bufferIndex); - - if (opcode == Opcode.NEW_INSTANCE && ((TypeIdItem) this.getReferencedItem()).getTypeDescriptor().charAt(0) != 'L') { - throw new RuntimeException("Only class references can be used with the new-instance opcode"); - } - } - - public Format getFormat() { - return Format.Format21c; - } - - public int getRegisterA() { - return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]); - } - - private static class Factory implements Instruction.InstructionFactory { - public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { - return new Instruction21c(dexFile, opcode, buffer, bufferIndex); - } - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format; + +import org.jf.dexlib.Code.Instruction; +import org.jf.dexlib.Code.InstructionWithReference; +import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.SingleRegisterInstruction; +import org.jf.dexlib.DexFile; +import org.jf.dexlib.Item; +import org.jf.dexlib.TypeIdItem; +import org.jf.dexlib.Util.NumberUtils; +import org.jf.dexlib.Util.Output; + +public class Instruction21c extends InstructionWithReference implements SingleRegisterInstruction { + public static final Instruction.InstructionFactory Factory = new Factory(); + + public static void emit(Output out, Opcode opcode, short regA, Item referencedItem) { + if (regA >= 1 << 8) { + throw new RuntimeException("The register number must be less than v256"); + } + + if (opcode == Opcode.NEW_INSTANCE) { + assert referencedItem instanceof TypeIdItem; + if (((TypeIdItem)referencedItem).getTypeDescriptor().charAt(0) != 'L') { + throw new RuntimeException("Only class references can be used with the new-instance opcode"); + } + } + + out.writeByte(opcode.value); + out.writeByte(regA); + out.writeShort(0); + } + + private Instruction21c(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { + super(dexFile, opcode, buffer, bufferIndex); + + if (opcode == Opcode.NEW_INSTANCE && ((TypeIdItem) this.getReferencedItem()).getTypeDescriptor().charAt(0) != 'L') { + throw new RuntimeException("Only class references can be used with the new-instance opcode"); + } + } + + public Format getFormat() { + return Format.Format21c; + } + + public int getRegisterA() { + return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]); + } + + private static class Factory implements Instruction.InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { + return new Instruction21c(dexFile, opcode, buffer, bufferIndex); + } + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21h.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21h.java index 0fd20c90..1f87d878 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21h.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21h.java @@ -1,73 +1,73 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format; - -import org.jf.dexlib.Code.Instruction; -import org.jf.dexlib.Code.Opcode; -import org.jf.dexlib.Code.LiteralInstruction; -import org.jf.dexlib.Code.SingleRegisterInstruction; -import org.jf.dexlib.DexFile; -import org.jf.dexlib.Util.NumberUtils; -import org.jf.dexlib.Util.Output; - -public class Instruction21h extends Instruction implements SingleRegisterInstruction, LiteralInstruction { - public static final Instruction.InstructionFactory Factory = new Factory(); - - public static void emit(Output out, Opcode opcode, short regA, short litB) { - if (regA >= 1 << 8) { - throw new RuntimeException("The register number must be less than v256"); - } - - out.writeByte(opcode.value); - out.writeByte(regA); - out.writeShort(litB); - } - - private Instruction21h(Opcode opcode, byte[] buffer, int bufferIndex) { - super(opcode, buffer, bufferIndex); - } - - public Format getFormat() { - return Format.Format21h; - } - - public int getRegisterA() { - return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]); - } - - public long getLiteral() { - return NumberUtils.decodeShort(buffer, bufferIndex + 2); - } - - private static class Factory implements Instruction.InstructionFactory { - public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { - return new Instruction21h(opcode, buffer, bufferIndex); - } - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format; + +import org.jf.dexlib.Code.Instruction; +import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.LiteralInstruction; +import org.jf.dexlib.Code.SingleRegisterInstruction; +import org.jf.dexlib.DexFile; +import org.jf.dexlib.Util.NumberUtils; +import org.jf.dexlib.Util.Output; + +public class Instruction21h extends Instruction implements SingleRegisterInstruction, LiteralInstruction { + public static final Instruction.InstructionFactory Factory = new Factory(); + + public static void emit(Output out, Opcode opcode, short regA, short litB) { + if (regA >= 1 << 8) { + throw new RuntimeException("The register number must be less than v256"); + } + + out.writeByte(opcode.value); + out.writeByte(regA); + out.writeShort(litB); + } + + private Instruction21h(Opcode opcode, byte[] buffer, int bufferIndex) { + super(opcode, buffer, bufferIndex); + } + + public Format getFormat() { + return Format.Format21h; + } + + public int getRegisterA() { + return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]); + } + + public long getLiteral() { + return NumberUtils.decodeShort(buffer, bufferIndex + 2); + } + + private static class Factory implements Instruction.InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { + return new Instruction21h(opcode, buffer, bufferIndex); + } + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21s.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21s.java index 88462552..e37aefd9 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21s.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21s.java @@ -1,73 +1,73 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format; - -import org.jf.dexlib.Code.Instruction; -import org.jf.dexlib.Code.Opcode; -import org.jf.dexlib.Code.LiteralInstruction; -import org.jf.dexlib.Code.SingleRegisterInstruction; -import org.jf.dexlib.DexFile; -import org.jf.dexlib.Util.NumberUtils; -import org.jf.dexlib.Util.Output; - -public class Instruction21s extends Instruction implements SingleRegisterInstruction, LiteralInstruction { - public static final Instruction.InstructionFactory Factory = new Factory(); - - public static void emit(Output out, Opcode opcode, short regA, short litB) { - if (regA >= 1 << 8) { - throw new RuntimeException("The register number must be less than v256"); - } - - out.writeByte(opcode.value); - out.writeByte(regA); - out.writeShort(litB); - } - - private Instruction21s(Opcode opcode, byte[] buffer, int bufferIndex) { - super(opcode, buffer, bufferIndex); - } - - public Format getFormat() { - return Format.Format21s; - } - - public int getRegisterA() { - return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]); - } - - public long getLiteral() { - return NumberUtils.decodeShort(buffer, bufferIndex + 2); - } - - private static class Factory implements Instruction.InstructionFactory { - public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { - return new Instruction21s(opcode, buffer, bufferIndex); - } - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format; + +import org.jf.dexlib.Code.Instruction; +import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.LiteralInstruction; +import org.jf.dexlib.Code.SingleRegisterInstruction; +import org.jf.dexlib.DexFile; +import org.jf.dexlib.Util.NumberUtils; +import org.jf.dexlib.Util.Output; + +public class Instruction21s extends Instruction implements SingleRegisterInstruction, LiteralInstruction { + public static final Instruction.InstructionFactory Factory = new Factory(); + + public static void emit(Output out, Opcode opcode, short regA, short litB) { + if (regA >= 1 << 8) { + throw new RuntimeException("The register number must be less than v256"); + } + + out.writeByte(opcode.value); + out.writeByte(regA); + out.writeShort(litB); + } + + private Instruction21s(Opcode opcode, byte[] buffer, int bufferIndex) { + super(opcode, buffer, bufferIndex); + } + + public Format getFormat() { + return Format.Format21s; + } + + public int getRegisterA() { + return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]); + } + + public long getLiteral() { + return NumberUtils.decodeShort(buffer, bufferIndex + 2); + } + + private static class Factory implements Instruction.InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { + return new Instruction21s(opcode, buffer, bufferIndex); + } + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21t.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21t.java index 02980b4d..83288859 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21t.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21t.java @@ -1,80 +1,80 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format; - -import org.jf.dexlib.Code.Instruction; -import org.jf.dexlib.Code.Opcode; -import org.jf.dexlib.Code.OffsetInstruction; -import org.jf.dexlib.DexFile; -import org.jf.dexlib.Util.NumberUtils; -import org.jf.dexlib.Util.Output; - -public class Instruction21t extends Instruction implements OffsetInstruction { - public static final Instruction.InstructionFactory Factory = new Factory(); - - public static void emit(Output out, Opcode opcode, short regA, short offB) { - if (regA >= 1 << 8) { - throw new RuntimeException("The register number must be less than v256"); - } - - if (offB == 0) { - throw new RuntimeException("The offset cannot be 0."); - } - - out.writeByte(opcode.value); - out.writeByte(regA); - out.writeShort(offB); - } - - private Instruction21t(Opcode opcode, byte[] buffer, int bufferIndex) { - super(opcode, buffer, bufferIndex); - - if (getOffset() == 0) { - throw new RuntimeException("The offset cannot be 0."); - } - } - - public Format getFormat() { - return Format.Format21t; - } - - public short getRegister() { - return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]); - } - - public int getOffset() { - return NumberUtils.decodeShort(buffer, bufferIndex + 2); - } - - private static class Factory implements Instruction.InstructionFactory { - public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { - return new Instruction21t(opcode, buffer, bufferIndex); - } - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format; + +import org.jf.dexlib.Code.Instruction; +import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.OffsetInstruction; +import org.jf.dexlib.DexFile; +import org.jf.dexlib.Util.NumberUtils; +import org.jf.dexlib.Util.Output; + +public class Instruction21t extends Instruction implements OffsetInstruction { + public static final Instruction.InstructionFactory Factory = new Factory(); + + public static void emit(Output out, Opcode opcode, short regA, short offB) { + if (regA >= 1 << 8) { + throw new RuntimeException("The register number must be less than v256"); + } + + if (offB == 0) { + throw new RuntimeException("The offset cannot be 0."); + } + + out.writeByte(opcode.value); + out.writeByte(regA); + out.writeShort(offB); + } + + private Instruction21t(Opcode opcode, byte[] buffer, int bufferIndex) { + super(opcode, buffer, bufferIndex); + + if (getOffset() == 0) { + throw new RuntimeException("The offset cannot be 0."); + } + } + + public Format getFormat() { + return Format.Format21t; + } + + public short getRegister() { + return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]); + } + + public int getOffset() { + return NumberUtils.decodeShort(buffer, bufferIndex + 2); + } + + private static class Factory implements Instruction.InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { + return new Instruction21t(opcode, buffer, bufferIndex); + } + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22b.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22b.java index 7a7b6380..a7d19b07 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22b.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22b.java @@ -1,78 +1,78 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format; - -import org.jf.dexlib.Code.Instruction; -import org.jf.dexlib.Code.Opcode; -import org.jf.dexlib.Code.TwoRegisterInstruction; -import org.jf.dexlib.DexFile; -import org.jf.dexlib.Util.NumberUtils; -import org.jf.dexlib.Util.Output; - -public class Instruction22b extends Instruction implements TwoRegisterInstruction { - public static final Instruction.InstructionFactory Factory = new Factory(); - - public static void emit(Output out, Opcode opcode, short regA, short regB, byte litC) { - if (regA >= 1 << 8 || - regB >= 1 << 8) { - throw new RuntimeException("The register number must be less than v256"); - } - - out.writeByte(opcode.value); - out.writeByte(regA); - out.writeByte(regB); - out.writeByte(litC); - } - - private Instruction22b(Opcode opcode, byte[] buffer, int bufferIndex) { - super(opcode, buffer, bufferIndex); - } - - public Format getFormat() { - return Format.Format22b; - } - - public int getRegisterA() { - return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]); - } - - public int getRegisterB() { - return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 2]); - } - - public byte getLiteral() { - return buffer[bufferIndex + 3]; - } - - private static class Factory implements Instruction.InstructionFactory { - public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { - return new Instruction22b(opcode, buffer, bufferIndex); - } - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format; + +import org.jf.dexlib.Code.Instruction; +import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.TwoRegisterInstruction; +import org.jf.dexlib.DexFile; +import org.jf.dexlib.Util.NumberUtils; +import org.jf.dexlib.Util.Output; + +public class Instruction22b extends Instruction implements TwoRegisterInstruction { + public static final Instruction.InstructionFactory Factory = new Factory(); + + public static void emit(Output out, Opcode opcode, short regA, short regB, byte litC) { + if (regA >= 1 << 8 || + regB >= 1 << 8) { + throw new RuntimeException("The register number must be less than v256"); + } + + out.writeByte(opcode.value); + out.writeByte(regA); + out.writeByte(regB); + out.writeByte(litC); + } + + private Instruction22b(Opcode opcode, byte[] buffer, int bufferIndex) { + super(opcode, buffer, bufferIndex); + } + + public Format getFormat() { + return Format.Format22b; + } + + public int getRegisterA() { + return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]); + } + + public int getRegisterB() { + return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 2]); + } + + public byte getLiteral() { + return buffer[bufferIndex + 3]; + } + + private static class Factory implements Instruction.InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { + return new Instruction22b(opcode, buffer, bufferIndex); + } + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22c.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22c.java index 8040869b..37019c56 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22c.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22c.java @@ -1,74 +1,74 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format; - -import org.jf.dexlib.Code.Instruction; -import org.jf.dexlib.Code.InstructionWithReference; -import org.jf.dexlib.Code.Opcode; -import org.jf.dexlib.Code.TwoRegisterInstruction; -import org.jf.dexlib.DexFile; -import org.jf.dexlib.Util.NumberUtils; -import org.jf.dexlib.Util.Output; - -public class Instruction22c extends InstructionWithReference implements TwoRegisterInstruction { - public static final Instruction.InstructionFactory Factory = new Factory(); - - public static void emit(Output out, Opcode opcode, byte regA, byte regB) { - if (regA >= 1 << 4 || - regB >= 1 << 4) { - throw new RuntimeException("The register number must be less than v16"); - } - - out.writeByte(opcode.value); - out.writeByte((regB << 4) | regA); - out.writeShort(0); - } - - private Instruction22c(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { - super(dexFile, opcode, buffer, bufferIndex); - } - - public Format getFormat() { - return Format.Format22c; - } - - public int getRegisterA() { - return NumberUtils.decodeLowUnsignedNibble(buffer[bufferIndex + 1]); - } - - public int getRegisterB() { - return NumberUtils.decodeHighUnsignedNibble(buffer[bufferIndex + 1]); - } - - private static class Factory implements Instruction.InstructionFactory { - public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { - return new Instruction22c(dexFile, opcode, buffer, bufferIndex); - } - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format; + +import org.jf.dexlib.Code.Instruction; +import org.jf.dexlib.Code.InstructionWithReference; +import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.TwoRegisterInstruction; +import org.jf.dexlib.DexFile; +import org.jf.dexlib.Util.NumberUtils; +import org.jf.dexlib.Util.Output; + +public class Instruction22c extends InstructionWithReference implements TwoRegisterInstruction { + public static final Instruction.InstructionFactory Factory = new Factory(); + + public static void emit(Output out, Opcode opcode, byte regA, byte regB) { + if (regA >= 1 << 4 || + regB >= 1 << 4) { + throw new RuntimeException("The register number must be less than v16"); + } + + out.writeByte(opcode.value); + out.writeByte((regB << 4) | regA); + out.writeShort(0); + } + + private Instruction22c(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { + super(dexFile, opcode, buffer, bufferIndex); + } + + public Format getFormat() { + return Format.Format22c; + } + + public int getRegisterA() { + return NumberUtils.decodeLowUnsignedNibble(buffer[bufferIndex + 1]); + } + + public int getRegisterB() { + return NumberUtils.decodeHighUnsignedNibble(buffer[bufferIndex + 1]); + } + + private static class Factory implements Instruction.InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { + return new Instruction22c(dexFile, opcode, buffer, bufferIndex); + } + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22s.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22s.java index 2e2e09f0..8c7c8176 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22s.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22s.java @@ -1,77 +1,77 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format; - -import org.jf.dexlib.Code.Instruction; -import org.jf.dexlib.Code.Opcode; -import org.jf.dexlib.Code.TwoRegisterInstruction; -import org.jf.dexlib.DexFile; -import org.jf.dexlib.Util.NumberUtils; -import org.jf.dexlib.Util.Output; - -public class Instruction22s extends Instruction implements TwoRegisterInstruction { - public static final Instruction.InstructionFactory Factory = new Factory(); - - public static void emit(Output out, Opcode opcode, byte regA, byte regB, short litC) { - if (regA >= 1 << 4 || - regB >= 1 << 4) { - throw new RuntimeException("The register number must be less than v16"); - } - - out.writeByte(opcode.value); - out.writeByte((regB << 4) | regA); - out.writeShort(litC); - } - - private Instruction22s(Opcode opcode, byte[] buffer, int bufferIndex) { - super(opcode, buffer, bufferIndex); - } - - public Format getFormat() { - return Format.Format22s; - } - - public int getRegisterA() { - return NumberUtils.decodeLowUnsignedNibble(buffer[bufferIndex + 1]); - } - - public int getRegisterB() { - return NumberUtils.decodeHighUnsignedNibble(buffer[bufferIndex + 1]); - } - - public short getLiteral() { - return NumberUtils.decodeShort(buffer, bufferIndex + 2); - } - - private static class Factory implements Instruction.InstructionFactory { - public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { - return new Instruction22s(opcode, buffer, bufferIndex); - } - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format; + +import org.jf.dexlib.Code.Instruction; +import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.TwoRegisterInstruction; +import org.jf.dexlib.DexFile; +import org.jf.dexlib.Util.NumberUtils; +import org.jf.dexlib.Util.Output; + +public class Instruction22s extends Instruction implements TwoRegisterInstruction { + public static final Instruction.InstructionFactory Factory = new Factory(); + + public static void emit(Output out, Opcode opcode, byte regA, byte regB, short litC) { + if (regA >= 1 << 4 || + regB >= 1 << 4) { + throw new RuntimeException("The register number must be less than v16"); + } + + out.writeByte(opcode.value); + out.writeByte((regB << 4) | regA); + out.writeShort(litC); + } + + private Instruction22s(Opcode opcode, byte[] buffer, int bufferIndex) { + super(opcode, buffer, bufferIndex); + } + + public Format getFormat() { + return Format.Format22s; + } + + public int getRegisterA() { + return NumberUtils.decodeLowUnsignedNibble(buffer[bufferIndex + 1]); + } + + public int getRegisterB() { + return NumberUtils.decodeHighUnsignedNibble(buffer[bufferIndex + 1]); + } + + public short getLiteral() { + return NumberUtils.decodeShort(buffer, bufferIndex + 2); + } + + private static class Factory implements Instruction.InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { + return new Instruction22s(opcode, buffer, bufferIndex); + } + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22t.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22t.java index caacb1da..241039f0 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22t.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22t.java @@ -1,85 +1,85 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format; - -import org.jf.dexlib.Code.Instruction; -import org.jf.dexlib.Code.Opcode; -import org.jf.dexlib.Code.OffsetInstruction; -import org.jf.dexlib.DexFile; -import org.jf.dexlib.Util.NumberUtils; -import org.jf.dexlib.Util.Output; - -public class Instruction22t extends Instruction implements OffsetInstruction { - public static final Instruction.InstructionFactory Factory = new Factory(); - - public static void emit(Output out, Opcode opcode, byte regA, byte regB, short offC) { - if (regA >= 1 << 4 || - regB >= 1 << 4) { - throw new RuntimeException("The register number must be less than v16"); - } - - if (offC == 0) { - throw new RuntimeException("The offset cannot be 0."); - } - - out.writeByte(opcode.value); - out.writeByte((regB << 4) | regA); - out.writeShort(offC); - } - - private Instruction22t(Opcode opcode, byte[] buffer, int bufferIndex) { - super(opcode, buffer, bufferIndex); - - if (getOffset() == 0) { - throw new RuntimeException("The offset cannot be 0."); - } - } - - public Format getFormat() { - return Format.Format22t; - } - - public byte getRegisterA() { - return NumberUtils.decodeLowUnsignedNibble(buffer[bufferIndex + 1]); - } - - public byte getRegisterB() { - return NumberUtils.decodeHighUnsignedNibble(buffer[bufferIndex + 1]); - } - - public int getOffset() { - return NumberUtils.decodeShort(buffer, bufferIndex + 2); - } - - private static class Factory implements Instruction.InstructionFactory { - public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { - return new Instruction22t(opcode, buffer, bufferIndex); - } - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format; + +import org.jf.dexlib.Code.Instruction; +import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.OffsetInstruction; +import org.jf.dexlib.DexFile; +import org.jf.dexlib.Util.NumberUtils; +import org.jf.dexlib.Util.Output; + +public class Instruction22t extends Instruction implements OffsetInstruction { + public static final Instruction.InstructionFactory Factory = new Factory(); + + public static void emit(Output out, Opcode opcode, byte regA, byte regB, short offC) { + if (regA >= 1 << 4 || + regB >= 1 << 4) { + throw new RuntimeException("The register number must be less than v16"); + } + + if (offC == 0) { + throw new RuntimeException("The offset cannot be 0."); + } + + out.writeByte(opcode.value); + out.writeByte((regB << 4) | regA); + out.writeShort(offC); + } + + private Instruction22t(Opcode opcode, byte[] buffer, int bufferIndex) { + super(opcode, buffer, bufferIndex); + + if (getOffset() == 0) { + throw new RuntimeException("The offset cannot be 0."); + } + } + + public Format getFormat() { + return Format.Format22t; + } + + public byte getRegisterA() { + return NumberUtils.decodeLowUnsignedNibble(buffer[bufferIndex + 1]); + } + + public byte getRegisterB() { + return NumberUtils.decodeHighUnsignedNibble(buffer[bufferIndex + 1]); + } + + public int getOffset() { + return NumberUtils.decodeShort(buffer, bufferIndex + 2); + } + + private static class Factory implements Instruction.InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { + return new Instruction22t(opcode, buffer, bufferIndex); + } + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22x.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22x.java index c9081f0f..77bd4b20 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22x.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22x.java @@ -1,76 +1,76 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format; - -import org.jf.dexlib.Code.Instruction; -import org.jf.dexlib.Code.Opcode; -import org.jf.dexlib.Code.TwoRegisterInstruction; -import org.jf.dexlib.DexFile; -import org.jf.dexlib.Util.NumberUtils; -import org.jf.dexlib.Util.Output; - -public class Instruction22x extends Instruction implements TwoRegisterInstruction { - public static final Instruction.InstructionFactory Factory = new Factory(); - - public static void emit(Output out, Opcode opcode, short regA, int regB) { - if (regA >= 1 << 8) { - throw new RuntimeException("The register number must be less than v16"); - } - - if (regB >= 1 << 16) { - throw new RuntimeException("The register number must be less than v65536"); - } - - out.writeByte(opcode.value); - out.writeByte(regA); - out.writeShort(regB); - } - - private Instruction22x(Opcode opcode, byte[] buffer, int bufferIndex) { - super(opcode, buffer, bufferIndex); - } - - public Format getFormat() { - return Format.Format22x; - } - - public int getRegisterA() { - return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]); - } - - public int getRegisterB() { - return NumberUtils.decodeUnsignedShort(buffer, bufferIndex + 2); - } - - private static class Factory implements Instruction.InstructionFactory { - public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { - return new Instruction22x(opcode, buffer, bufferIndex); - } - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format; + +import org.jf.dexlib.Code.Instruction; +import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.TwoRegisterInstruction; +import org.jf.dexlib.DexFile; +import org.jf.dexlib.Util.NumberUtils; +import org.jf.dexlib.Util.Output; + +public class Instruction22x extends Instruction implements TwoRegisterInstruction { + public static final Instruction.InstructionFactory Factory = new Factory(); + + public static void emit(Output out, Opcode opcode, short regA, int regB) { + if (regA >= 1 << 8) { + throw new RuntimeException("The register number must be less than v16"); + } + + if (regB >= 1 << 16) { + throw new RuntimeException("The register number must be less than v65536"); + } + + out.writeByte(opcode.value); + out.writeByte(regA); + out.writeShort(regB); + } + + private Instruction22x(Opcode opcode, byte[] buffer, int bufferIndex) { + super(opcode, buffer, bufferIndex); + } + + public Format getFormat() { + return Format.Format22x; + } + + public int getRegisterA() { + return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]); + } + + public int getRegisterB() { + return NumberUtils.decodeUnsignedShort(buffer, bufferIndex + 2); + } + + private static class Factory implements Instruction.InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { + return new Instruction22x(opcode, buffer, bufferIndex); + } + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction23x.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction23x.java index 4a27cf59..addb9fad 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction23x.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction23x.java @@ -1,79 +1,79 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format; - -import org.jf.dexlib.Code.Instruction; -import org.jf.dexlib.Code.Opcode; -import org.jf.dexlib.Code.ThreeRegisterInstruction; -import org.jf.dexlib.DexFile; -import org.jf.dexlib.Util.NumberUtils; -import org.jf.dexlib.Util.Output; - -public class Instruction23x extends Instruction implements ThreeRegisterInstruction { - public static final Instruction.InstructionFactory Factory = new Factory(); - - public static void emit(Output out, Opcode opcode, short regA, short regB, short regC) { - if (regA >= 1 << 8 || - regB >= 1 << 8 || - regC >= 1 << 8) { - throw new RuntimeException("The register number must be less than v256"); - } - - out.writeByte(opcode.value); - out.writeByte(regA); - out.writeByte(regB); - out.writeByte(regC); - } - - private Instruction23x(Opcode opcode, byte[] buffer, int bufferIndex) { - super(opcode, buffer, bufferIndex); - } - - public Format getFormat() { - return Format.Format23x; - } - - public int getRegisterA() { - return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]); - } - - public int getRegisterB() { - return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 2]); - } - - public int getRegisterC() { - return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 3]); - } - - private static class Factory implements Instruction.InstructionFactory { - public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { - return new Instruction23x(opcode, buffer, bufferIndex); - } - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format; + +import org.jf.dexlib.Code.Instruction; +import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.ThreeRegisterInstruction; +import org.jf.dexlib.DexFile; +import org.jf.dexlib.Util.NumberUtils; +import org.jf.dexlib.Util.Output; + +public class Instruction23x extends Instruction implements ThreeRegisterInstruction { + public static final Instruction.InstructionFactory Factory = new Factory(); + + public static void emit(Output out, Opcode opcode, short regA, short regB, short regC) { + if (regA >= 1 << 8 || + regB >= 1 << 8 || + regC >= 1 << 8) { + throw new RuntimeException("The register number must be less than v256"); + } + + out.writeByte(opcode.value); + out.writeByte(regA); + out.writeByte(regB); + out.writeByte(regC); + } + + private Instruction23x(Opcode opcode, byte[] buffer, int bufferIndex) { + super(opcode, buffer, bufferIndex); + } + + public Format getFormat() { + return Format.Format23x; + } + + public int getRegisterA() { + return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]); + } + + public int getRegisterB() { + return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 2]); + } + + public int getRegisterC() { + return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 3]); + } + + private static class Factory implements Instruction.InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { + return new Instruction23x(opcode, buffer, bufferIndex); + } + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction30t.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction30t.java index 5c3f1b0d..d7ba1f27 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction30t.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction30t.java @@ -1,64 +1,64 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format; - -import org.jf.dexlib.DexFile; -import org.jf.dexlib.Code.Instruction; -import org.jf.dexlib.Code.Opcode; -import org.jf.dexlib.Code.OffsetInstruction; -import org.jf.dexlib.Util.NumberUtils; -import org.jf.dexlib.Util.Output; - -public class Instruction30t extends Instruction implements OffsetInstruction { - public static final Instruction.InstructionFactory Factory = new Factory(); - - public static void emit(Output out, Opcode opcode, int offA) { - out.writeByte(opcode.value); - out.writeByte(0); - out.writeInt(offA); - } - - private Instruction30t(Opcode opcode, byte[] buffer, int bufferIndex) { - super(opcode, buffer, bufferIndex); - } - - public Format getFormat() { - return Format.Format30t; - } - - public int getOffset() { - return NumberUtils.decodeInt(buffer, bufferIndex + 2); - } - - private static class Factory implements Instruction.InstructionFactory { - public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { - return new Instruction30t(opcode, buffer, bufferIndex); - } - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format; + +import org.jf.dexlib.DexFile; +import org.jf.dexlib.Code.Instruction; +import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.OffsetInstruction; +import org.jf.dexlib.Util.NumberUtils; +import org.jf.dexlib.Util.Output; + +public class Instruction30t extends Instruction implements OffsetInstruction { + public static final Instruction.InstructionFactory Factory = new Factory(); + + public static void emit(Output out, Opcode opcode, int offA) { + out.writeByte(opcode.value); + out.writeByte(0); + out.writeInt(offA); + } + + private Instruction30t(Opcode opcode, byte[] buffer, int bufferIndex) { + super(opcode, buffer, bufferIndex); + } + + public Format getFormat() { + return Format.Format30t; + } + + public int getOffset() { + return NumberUtils.decodeInt(buffer, bufferIndex + 2); + } + + private static class Factory implements Instruction.InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { + return new Instruction30t(opcode, buffer, bufferIndex); + } + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction31c.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction31c.java index 5eccff74..0f3a05d5 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction31c.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction31c.java @@ -1,74 +1,74 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format; - -import org.jf.dexlib.Code.Instruction; -import org.jf.dexlib.Code.InstructionWithReference; -import org.jf.dexlib.Code.Opcode; -import org.jf.dexlib.Code.SingleRegisterInstruction; -import org.jf.dexlib.DexFile; -import org.jf.dexlib.Item; -import org.jf.dexlib.Util.NumberUtils; -import org.jf.dexlib.Util.Output; - -public class Instruction31c extends InstructionWithReference implements SingleRegisterInstruction { - public static final Instruction.InstructionFactory Factory = new Factory(); - - public static void emit(Output out, Opcode opcode, short regA) { - if (regA >= 1 << 8) { - throw new RuntimeException("The register number must be less than v256"); - } - - out.writeByte(opcode.value); - out.writeByte(regA); - out.writeInt(0); - } - - private Instruction31c(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { - super(dexFile, opcode, buffer, bufferIndex); - } - - protected int getReferencedItemIndex() { - return NumberUtils.decodeInt(buffer, bufferIndex + 2); - } - - public Format getFormat() { - return Format.Format31c; - } - - public int getRegisterA() { - return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]); - } - - private static class Factory implements Instruction.InstructionFactory { - public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { - return new Instruction31c(dexFile, opcode, buffer, bufferIndex); - } - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format; + +import org.jf.dexlib.Code.Instruction; +import org.jf.dexlib.Code.InstructionWithReference; +import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.SingleRegisterInstruction; +import org.jf.dexlib.DexFile; +import org.jf.dexlib.Item; +import org.jf.dexlib.Util.NumberUtils; +import org.jf.dexlib.Util.Output; + +public class Instruction31c extends InstructionWithReference implements SingleRegisterInstruction { + public static final Instruction.InstructionFactory Factory = new Factory(); + + public static void emit(Output out, Opcode opcode, short regA) { + if (regA >= 1 << 8) { + throw new RuntimeException("The register number must be less than v256"); + } + + out.writeByte(opcode.value); + out.writeByte(regA); + out.writeInt(0); + } + + private Instruction31c(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { + super(dexFile, opcode, buffer, bufferIndex); + } + + protected int getReferencedItemIndex() { + return NumberUtils.decodeInt(buffer, bufferIndex + 2); + } + + public Format getFormat() { + return Format.Format31c; + } + + public int getRegisterA() { + return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]); + } + + private static class Factory implements Instruction.InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { + return new Instruction31c(dexFile, opcode, buffer, bufferIndex); + } + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction31i.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction31i.java index 43d0ae2b..c15695e5 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction31i.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction31i.java @@ -1,73 +1,73 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format; - -import org.jf.dexlib.Code.Instruction; -import org.jf.dexlib.Code.Opcode; -import org.jf.dexlib.Code.LiteralInstruction; -import org.jf.dexlib.Code.SingleRegisterInstruction; -import org.jf.dexlib.DexFile; -import org.jf.dexlib.Util.NumberUtils; -import org.jf.dexlib.Util.Output; - -public class Instruction31i extends Instruction implements SingleRegisterInstruction, LiteralInstruction { - public static final Instruction.InstructionFactory Factory = new Factory(); - - public static void emit(Output out, Opcode opcode, short regA, int litB) { - if (regA >= 1 << 8) { - throw new RuntimeException("The register number must be less than v256"); - } - - out.writeByte(opcode.value); - out.writeByte(regA); - out.writeInt(litB); - } - - private Instruction31i(Opcode opcode, byte[] buffer, int bufferIndex) { - super(opcode, buffer, bufferIndex); - } - - public Format getFormat() { - return Format.Format31i; - } - - public int getRegisterA() { - return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]); - } - - public long getLiteral() { - return NumberUtils.decodeInt(buffer, bufferIndex + 2); - } - - private static class Factory implements Instruction.InstructionFactory { - public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { - return new Instruction31i(opcode, buffer, bufferIndex); - } - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format; + +import org.jf.dexlib.Code.Instruction; +import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.LiteralInstruction; +import org.jf.dexlib.Code.SingleRegisterInstruction; +import org.jf.dexlib.DexFile; +import org.jf.dexlib.Util.NumberUtils; +import org.jf.dexlib.Util.Output; + +public class Instruction31i extends Instruction implements SingleRegisterInstruction, LiteralInstruction { + public static final Instruction.InstructionFactory Factory = new Factory(); + + public static void emit(Output out, Opcode opcode, short regA, int litB) { + if (regA >= 1 << 8) { + throw new RuntimeException("The register number must be less than v256"); + } + + out.writeByte(opcode.value); + out.writeByte(regA); + out.writeInt(litB); + } + + private Instruction31i(Opcode opcode, byte[] buffer, int bufferIndex) { + super(opcode, buffer, bufferIndex); + } + + public Format getFormat() { + return Format.Format31i; + } + + public int getRegisterA() { + return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]); + } + + public long getLiteral() { + return NumberUtils.decodeInt(buffer, bufferIndex + 2); + } + + private static class Factory implements Instruction.InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { + return new Instruction31i(opcode, buffer, bufferIndex); + } + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction31t.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction31t.java index 0cf455cf..f4c297a3 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction31t.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction31t.java @@ -1,72 +1,72 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format; - -import org.jf.dexlib.Code.Instruction; -import org.jf.dexlib.Code.Opcode; -import org.jf.dexlib.Code.OffsetInstruction; -import org.jf.dexlib.DexFile; -import org.jf.dexlib.Util.NumberUtils; -import org.jf.dexlib.Util.Output; - -public class Instruction31t extends Instruction implements OffsetInstruction { - public static final Instruction.InstructionFactory Factory = new Factory(); - - public static void emit(Output out, Opcode opcode, short regA, int offB) { - if (regA >= 1 << 8) { - throw new RuntimeException("The register number must be less than v256"); - } - - out.writeByte(opcode.value); - out.writeByte(regA); - out.writeInt(offB); - } - - private Instruction31t(Opcode opcode, byte[] buffer, int bufferIndex) { - super(opcode, buffer, bufferIndex); - } - - public Format getFormat() { - return Format.Format31t; - } - - public short getRegister() { - return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]); - } - - public int getOffset() { - return NumberUtils.decodeInt(buffer, bufferIndex + 2); - } - - private static class Factory implements Instruction.InstructionFactory { - public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { - return new Instruction31t(opcode, buffer, bufferIndex); - } - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format; + +import org.jf.dexlib.Code.Instruction; +import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.OffsetInstruction; +import org.jf.dexlib.DexFile; +import org.jf.dexlib.Util.NumberUtils; +import org.jf.dexlib.Util.Output; + +public class Instruction31t extends Instruction implements OffsetInstruction { + public static final Instruction.InstructionFactory Factory = new Factory(); + + public static void emit(Output out, Opcode opcode, short regA, int offB) { + if (regA >= 1 << 8) { + throw new RuntimeException("The register number must be less than v256"); + } + + out.writeByte(opcode.value); + out.writeByte(regA); + out.writeInt(offB); + } + + private Instruction31t(Opcode opcode, byte[] buffer, int bufferIndex) { + super(opcode, buffer, bufferIndex); + } + + public Format getFormat() { + return Format.Format31t; + } + + public short getRegister() { + return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]); + } + + public int getOffset() { + return NumberUtils.decodeInt(buffer, bufferIndex + 2); + } + + private static class Factory implements Instruction.InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { + return new Instruction31t(opcode, buffer, bufferIndex); + } + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction32x.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction32x.java index ad3097c0..e09ea642 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction32x.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction32x.java @@ -1,74 +1,74 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format; - -import org.jf.dexlib.DexFile; -import org.jf.dexlib.Code.Instruction; -import org.jf.dexlib.Code.Opcode; -import org.jf.dexlib.Code.TwoRegisterInstruction; -import org.jf.dexlib.Util.NumberUtils; -import org.jf.dexlib.Util.Output; - -public class Instruction32x extends Instruction implements TwoRegisterInstruction { - public static final Instruction.InstructionFactory Factory = new Factory(); - - public static void emit(Output out, Opcode opcode, int regA, int regB) { - if (regA >= 1<<16 || - regB >= 1<<16) { - throw new RuntimeException("The register number must be less than v65536"); - } - - out.writeByte(opcode.value); - out.writeByte(0); - out.writeShort(regA); - out.writeShort(regB); - } - - private Instruction32x(Opcode opcode, byte[] buffer, int bufferIndex) { - super(opcode, buffer, bufferIndex); - } - - public Format getFormat() { - return Format.Format32x; - } - - public int getRegisterA() { - return NumberUtils.decodeUnsignedShort(buffer, bufferIndex + 2); - } - - public int getRegisterB() { - return NumberUtils.decodeUnsignedShort(buffer, bufferIndex + 4); - } - - private static class Factory implements Instruction.InstructionFactory { - public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { - return new Instruction32x(opcode, buffer, bufferIndex); - } - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format; + +import org.jf.dexlib.DexFile; +import org.jf.dexlib.Code.Instruction; +import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.TwoRegisterInstruction; +import org.jf.dexlib.Util.NumberUtils; +import org.jf.dexlib.Util.Output; + +public class Instruction32x extends Instruction implements TwoRegisterInstruction { + public static final Instruction.InstructionFactory Factory = new Factory(); + + public static void emit(Output out, Opcode opcode, int regA, int regB) { + if (regA >= 1<<16 || + regB >= 1<<16) { + throw new RuntimeException("The register number must be less than v65536"); + } + + out.writeByte(opcode.value); + out.writeByte(0); + out.writeShort(regA); + out.writeShort(regB); + } + + private Instruction32x(Opcode opcode, byte[] buffer, int bufferIndex) { + super(opcode, buffer, bufferIndex); + } + + public Format getFormat() { + return Format.Format32x; + } + + public int getRegisterA() { + return NumberUtils.decodeUnsignedShort(buffer, bufferIndex + 2); + } + + public int getRegisterB() { + return NumberUtils.decodeUnsignedShort(buffer, bufferIndex + 4); + } + + private static class Factory implements Instruction.InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { + return new Instruction32x(opcode, buffer, bufferIndex); + } + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction35c.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction35c.java index dddf6741..b8dddbf6 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction35c.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction35c.java @@ -1,134 +1,134 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format; - -import org.jf.dexlib.Code.Instruction; -import org.jf.dexlib.Code.InstructionWithReference; -import org.jf.dexlib.Code.Opcode; -import static org.jf.dexlib.Code.Opcode.*; -import org.jf.dexlib.DexFile; -import org.jf.dexlib.Item; -import org.jf.dexlib.MethodIdItem; -import org.jf.dexlib.TypeIdItem; -import org.jf.dexlib.Util.NumberUtils; -import org.jf.dexlib.Util.Output; - -public class Instruction35c extends InstructionWithReference { - public static final Instruction.InstructionFactory Factory = new Factory(); - - public static void emit(Output out, Opcode opcode, int regCount, byte regD, byte regE, byte regF, byte regG, - byte regA, Item referencedItem) { - if (regCount > 5) { - throw new RuntimeException("regCount cannot be greater than 5"); - } - - if (regD >= 1 << 4 || - regE >= 1 << 4 || - regF >= 1 << 4 || - regG >= 1 << 4 || - regA >= 1 << 4) { - throw new RuntimeException("All register args must fit in 4 bits"); - } - - out.writeByte(opcode.value); - out.writeByte((regCount << 4) | regA); - out.writeShort(0); - out.writeByte((regE << 4) | regD); - out.writeByte((regG << 4) | regF); - - checkItem(opcode, referencedItem, regCount); - } - - protected Instruction35c(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { - super(dexFile, opcode, buffer, bufferIndex); - - if (getRegCount() > 5) { - throw new RuntimeException("regCount cannot be greater than 5"); - } - - checkItem(opcode, getReferencedItem(), getRegCount()); - } - - public Format getFormat() { - return Format.Format35c; - } - - public byte getRegisterA() { - return NumberUtils.decodeLowUnsignedNibble(buffer[bufferIndex + 1]); - } - - public byte getRegCount() { - return NumberUtils.decodeHighUnsignedNibble(buffer[bufferIndex + 1]); - } - - public byte getRegisterD() { - return NumberUtils.decodeLowUnsignedNibble(buffer[bufferIndex + 4]); - } - - public byte getRegisterE() { - return NumberUtils.decodeHighUnsignedNibble(buffer[bufferIndex + 4]); - } - - public byte getRegisterF() { - return NumberUtils.decodeLowUnsignedNibble(buffer[bufferIndex + 5]); - } - - public byte getRegisterG() { - return NumberUtils.decodeHighUnsignedNibble(buffer[bufferIndex + 5]); - } - - private static void checkItem(Opcode opcode, Item item, int regCount) { - if (opcode == FILLED_NEW_ARRAY) { - //check data for filled-new-array opcode - String type = ((TypeIdItem) item).getTypeDescriptor(); - if (type.charAt(0) != '[') { - throw new RuntimeException("The type must be an array type"); - } - if (type.charAt(1) == 'J' || type.charAt(1) == 'D') { - throw new RuntimeException("The type cannot be an array of longs or doubles"); - } - } else if (opcode.value >= INVOKE_VIRTUAL.value && opcode.value <= INVOKE_INTERFACE.value) { - //check data for invoke-* opcodes - MethodIdItem methodIdItem = (MethodIdItem) item; - int parameterRegisterCount = methodIdItem.getPrototype().getParameterRegisterCount(); - if (opcode != INVOKE_STATIC) { - parameterRegisterCount++; - } - if (parameterRegisterCount != regCount) { - throw new RuntimeException("regCount does not match the number of arguments of the method"); - } - } - } - - private static class Factory implements Instruction.InstructionFactory { - public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { - return new Instruction35c(dexFile, opcode, buffer, bufferIndex); - } - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format; + +import org.jf.dexlib.Code.Instruction; +import org.jf.dexlib.Code.InstructionWithReference; +import org.jf.dexlib.Code.Opcode; +import static org.jf.dexlib.Code.Opcode.*; +import org.jf.dexlib.DexFile; +import org.jf.dexlib.Item; +import org.jf.dexlib.MethodIdItem; +import org.jf.dexlib.TypeIdItem; +import org.jf.dexlib.Util.NumberUtils; +import org.jf.dexlib.Util.Output; + +public class Instruction35c extends InstructionWithReference { + public static final Instruction.InstructionFactory Factory = new Factory(); + + public static void emit(Output out, Opcode opcode, int regCount, byte regD, byte regE, byte regF, byte regG, + byte regA, Item referencedItem) { + if (regCount > 5) { + throw new RuntimeException("regCount cannot be greater than 5"); + } + + if (regD >= 1 << 4 || + regE >= 1 << 4 || + regF >= 1 << 4 || + regG >= 1 << 4 || + regA >= 1 << 4) { + throw new RuntimeException("All register args must fit in 4 bits"); + } + + out.writeByte(opcode.value); + out.writeByte((regCount << 4) | regA); + out.writeShort(0); + out.writeByte((regE << 4) | regD); + out.writeByte((regG << 4) | regF); + + checkItem(opcode, referencedItem, regCount); + } + + protected Instruction35c(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { + super(dexFile, opcode, buffer, bufferIndex); + + if (getRegCount() > 5) { + throw new RuntimeException("regCount cannot be greater than 5"); + } + + checkItem(opcode, getReferencedItem(), getRegCount()); + } + + public Format getFormat() { + return Format.Format35c; + } + + public byte getRegisterA() { + return NumberUtils.decodeLowUnsignedNibble(buffer[bufferIndex + 1]); + } + + public byte getRegCount() { + return NumberUtils.decodeHighUnsignedNibble(buffer[bufferIndex + 1]); + } + + public byte getRegisterD() { + return NumberUtils.decodeLowUnsignedNibble(buffer[bufferIndex + 4]); + } + + public byte getRegisterE() { + return NumberUtils.decodeHighUnsignedNibble(buffer[bufferIndex + 4]); + } + + public byte getRegisterF() { + return NumberUtils.decodeLowUnsignedNibble(buffer[bufferIndex + 5]); + } + + public byte getRegisterG() { + return NumberUtils.decodeHighUnsignedNibble(buffer[bufferIndex + 5]); + } + + private static void checkItem(Opcode opcode, Item item, int regCount) { + if (opcode == FILLED_NEW_ARRAY) { + //check data for filled-new-array opcode + String type = ((TypeIdItem) item).getTypeDescriptor(); + if (type.charAt(0) != '[') { + throw new RuntimeException("The type must be an array type"); + } + if (type.charAt(1) == 'J' || type.charAt(1) == 'D') { + throw new RuntimeException("The type cannot be an array of longs or doubles"); + } + } else if (opcode.value >= INVOKE_VIRTUAL.value && opcode.value <= INVOKE_INTERFACE.value) { + //check data for invoke-* opcodes + MethodIdItem methodIdItem = (MethodIdItem) item; + int parameterRegisterCount = methodIdItem.getPrototype().getParameterRegisterCount(); + if (opcode != INVOKE_STATIC) { + parameterRegisterCount++; + } + if (parameterRegisterCount != regCount) { + throw new RuntimeException("regCount does not match the number of arguments of the method"); + } + } + } + + private static class Factory implements Instruction.InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { + return new Instruction35c(dexFile, opcode, buffer, bufferIndex); + } + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction3rc.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction3rc.java index af26c1f5..5975bc49 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction3rc.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction3rc.java @@ -1,114 +1,114 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format; - -import org.jf.dexlib.Code.Instruction; -import org.jf.dexlib.Code.InstructionWithReference; -import org.jf.dexlib.Code.Opcode; -import static org.jf.dexlib.Code.Opcode.*; -import org.jf.dexlib.DexFile; -import org.jf.dexlib.Item; -import org.jf.dexlib.MethodIdItem; -import org.jf.dexlib.TypeIdItem; -import org.jf.dexlib.Util.NumberUtils; -import org.jf.dexlib.Util.Output; - -public class Instruction3rc extends InstructionWithReference { - public static final Instruction.InstructionFactory Factory = new Factory(); - - public static void emit(Output out, Opcode opcode, short regCount, int startReg, Item referencedItem) { - if (regCount >= 1 << 8) { - throw new RuntimeException("regCount must be less than 256"); - } - if (regCount < 0) { - throw new RuntimeException("regCount cannot be negative"); - } - - if (startReg >= 1 << 16) { - throw new RuntimeException("The beginning register of the range must be less than 65536"); - } - if (startReg < 0) { - throw new RuntimeException("The beginning register of the range cannot be negative"); - } - - out.writeByte(opcode.value); - out.writeByte(regCount); - out.writeShort(0); - out.writeShort(startReg); - - checkItem(opcode, referencedItem, regCount); - } - - private Instruction3rc(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { - super(dexFile, opcode, buffer, bufferIndex); - - checkItem(opcode, getReferencedItem(), getRegCount()); - } - - public Format getFormat() { - return Format.Format3rc; - } - - public short getRegCount() { - return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]); - } - - public int getStartRegister() { - return NumberUtils.decodeUnsignedShort(buffer, bufferIndex + 4); - } - - private static void checkItem(Opcode opcode, Item item, int regCount) { - if (opcode == FILLED_NEW_ARRAY_RANGE) { - //check data for filled-new-array/range opcode - String type = ((TypeIdItem) item).getTypeDescriptor(); - if (type.charAt(0) != '[') { - throw new RuntimeException("The type must be an array type"); - } - if (type.charAt(1) == 'J' || type.charAt(1) == 'D') { - throw new RuntimeException("The type cannot be an array of longs or doubles"); - } - } else if (opcode.value >= INVOKE_VIRTUAL_RANGE.value && opcode.value <= INVOKE_INTERFACE_RANGE.value) { - //check data for invoke-*/range opcodes - MethodIdItem methodIdItem = (MethodIdItem) item; - int parameterRegisterCount = methodIdItem.getPrototype().getParameterRegisterCount(); - if (opcode != INVOKE_STATIC_RANGE) { - parameterRegisterCount++; - } - if (parameterRegisterCount != regCount) { - throw new RuntimeException("regCount does not match the number of arguments of the method"); - } - } - } - - private static class Factory implements Instruction.InstructionFactory { - public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { - return new Instruction3rc(dexFile, opcode, buffer, bufferIndex); - } - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format; + +import org.jf.dexlib.Code.Instruction; +import org.jf.dexlib.Code.InstructionWithReference; +import org.jf.dexlib.Code.Opcode; +import static org.jf.dexlib.Code.Opcode.*; +import org.jf.dexlib.DexFile; +import org.jf.dexlib.Item; +import org.jf.dexlib.MethodIdItem; +import org.jf.dexlib.TypeIdItem; +import org.jf.dexlib.Util.NumberUtils; +import org.jf.dexlib.Util.Output; + +public class Instruction3rc extends InstructionWithReference { + public static final Instruction.InstructionFactory Factory = new Factory(); + + public static void emit(Output out, Opcode opcode, short regCount, int startReg, Item referencedItem) { + if (regCount >= 1 << 8) { + throw new RuntimeException("regCount must be less than 256"); + } + if (regCount < 0) { + throw new RuntimeException("regCount cannot be negative"); + } + + if (startReg >= 1 << 16) { + throw new RuntimeException("The beginning register of the range must be less than 65536"); + } + if (startReg < 0) { + throw new RuntimeException("The beginning register of the range cannot be negative"); + } + + out.writeByte(opcode.value); + out.writeByte(regCount); + out.writeShort(0); + out.writeShort(startReg); + + checkItem(opcode, referencedItem, regCount); + } + + private Instruction3rc(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { + super(dexFile, opcode, buffer, bufferIndex); + + checkItem(opcode, getReferencedItem(), getRegCount()); + } + + public Format getFormat() { + return Format.Format3rc; + } + + public short getRegCount() { + return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]); + } + + public int getStartRegister() { + return NumberUtils.decodeUnsignedShort(buffer, bufferIndex + 4); + } + + private static void checkItem(Opcode opcode, Item item, int regCount) { + if (opcode == FILLED_NEW_ARRAY_RANGE) { + //check data for filled-new-array/range opcode + String type = ((TypeIdItem) item).getTypeDescriptor(); + if (type.charAt(0) != '[') { + throw new RuntimeException("The type must be an array type"); + } + if (type.charAt(1) == 'J' || type.charAt(1) == 'D') { + throw new RuntimeException("The type cannot be an array of longs or doubles"); + } + } else if (opcode.value >= INVOKE_VIRTUAL_RANGE.value && opcode.value <= INVOKE_INTERFACE_RANGE.value) { + //check data for invoke-*/range opcodes + MethodIdItem methodIdItem = (MethodIdItem) item; + int parameterRegisterCount = methodIdItem.getPrototype().getParameterRegisterCount(); + if (opcode != INVOKE_STATIC_RANGE) { + parameterRegisterCount++; + } + if (parameterRegisterCount != regCount) { + throw new RuntimeException("regCount does not match the number of arguments of the method"); + } + } + } + + private static class Factory implements Instruction.InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { + return new Instruction3rc(dexFile, opcode, buffer, bufferIndex); + } + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction51l.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction51l.java index f0fe0334..a3f06ed5 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction51l.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction51l.java @@ -1,73 +1,73 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format; - -import org.jf.dexlib.Code.Instruction; -import org.jf.dexlib.Code.Opcode; -import org.jf.dexlib.Code.SingleRegisterInstruction; -import org.jf.dexlib.Code.LiteralInstruction; -import org.jf.dexlib.DexFile; -import org.jf.dexlib.Util.NumberUtils; -import org.jf.dexlib.Util.Output; - -public class Instruction51l extends Instruction implements SingleRegisterInstruction, LiteralInstruction { - public static final Instruction.InstructionFactory Factory = new Factory(); - - public static void emit(Output out, Opcode opcode, short regA, long litB) { - if (regA >= 1 << 8) { - throw new RuntimeException("The register number must be less than v256"); - } - - out.writeByte(opcode.value); - out.writeByte(regA); - out.writeLong(litB); - } - - private Instruction51l(Opcode opcode, byte[] buffer, int bufferIndex) { - super(opcode, buffer, bufferIndex); - } - - public Format getFormat() { - return Format.Format51l; - } - - public int getRegisterA() { - return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]); - } - - public long getLiteral() { - return NumberUtils.decodeLong(buffer, bufferIndex + 2); - } - - private static class Factory implements Instruction.InstructionFactory { - public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { - return new Instruction51l(opcode, buffer, bufferIndex); - } - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format; + +import org.jf.dexlib.Code.Instruction; +import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.SingleRegisterInstruction; +import org.jf.dexlib.Code.LiteralInstruction; +import org.jf.dexlib.DexFile; +import org.jf.dexlib.Util.NumberUtils; +import org.jf.dexlib.Util.Output; + +public class Instruction51l extends Instruction implements SingleRegisterInstruction, LiteralInstruction { + public static final Instruction.InstructionFactory Factory = new Factory(); + + public static void emit(Output out, Opcode opcode, short regA, long litB) { + if (regA >= 1 << 8) { + throw new RuntimeException("The register number must be less than v256"); + } + + out.writeByte(opcode.value); + out.writeByte(regA); + out.writeLong(litB); + } + + private Instruction51l(Opcode opcode, byte[] buffer, int bufferIndex) { + super(opcode, buffer, bufferIndex); + } + + public Format getFormat() { + return Format.Format51l; + } + + public int getRegisterA() { + return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]); + } + + public long getLiteral() { + return NumberUtils.decodeLong(buffer, bufferIndex + 2); + } + + private static class Factory implements Instruction.InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { + return new Instruction51l(opcode, buffer, bufferIndex); + } + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/PackedSwitchDataPseudoInstruction.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/PackedSwitchDataPseudoInstruction.java index 48283050..eabccf87 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/PackedSwitchDataPseudoInstruction.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/PackedSwitchDataPseudoInstruction.java @@ -1,136 +1,136 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format; - -import org.jf.dexlib.Code.Instruction; -import org.jf.dexlib.Code.Opcode; -import org.jf.dexlib.Util.NumberUtils; -import org.jf.dexlib.Util.Output; -import org.jf.dexlib.DexFile; - -import java.util.Iterator; - -public class PackedSwitchDataPseudoInstruction extends Instruction { - public static final Instruction.InstructionFactory Factory = new Factory(); - - @Override - public int getSize() { - return getTargetCount() * 4 + 8; - } - - public static void emit(Output out, int firstKey, int[] targets) { - if (targets.length > 0xFFFF) { - throw new RuntimeException("The packed-switch data contains too many elements. " + - "The maximum number of switch elements is 65535"); - } - - //write out padding, if necessary - if (out.getCursor() % 4 != 0) { - out.writeShort(0); - } - - out.writeByte(0x00); - out.writeByte(0x01); - out.writeShort(targets.length); - out.writeInt(firstKey); - - for (int target : targets) { - out.writeInt(target); - } - } - - public PackedSwitchDataPseudoInstruction(byte[] buffer, int bufferIndex) { - super(Opcode.NOP, buffer, bufferIndex); - - byte opcodeByte = buffer[bufferIndex++]; - if (opcodeByte != 0x00) { - throw new RuntimeException("Invalid opcode byte for a PackedSwitchData pseudo-instruction"); - } - byte subopcodeByte = buffer[bufferIndex]; - if (subopcodeByte != 0x01) { - throw new RuntimeException("Invalid sub-opcode byte for a PackedSwitchData pseudo-instruction"); - } - } - - public Format getFormat() { - return Format.PackedSwitchData; - } - - public int getTargetCount() { - return NumberUtils.decodeUnsignedShort(buffer, bufferIndex + 2); - } - - public int getFirstKey() { - return NumberUtils.decodeInt(buffer, bufferIndex + 4); - } - - public static class PackedSwitchTarget { - public int value; - public int target; - } - - public Iterator getTargets() { - return new Iterator() { - final int targetCount = getTargetCount(); - int i = 0; - int position = bufferIndex + 8; - int value = getFirstKey(); - - PackedSwitchTarget packedSwitchTarget = new PackedSwitchTarget(); - - public boolean hasNext() { - return i 0xFFFF) { + throw new RuntimeException("The packed-switch data contains too many elements. " + + "The maximum number of switch elements is 65535"); + } + + //write out padding, if necessary + if (out.getCursor() % 4 != 0) { + out.writeShort(0); + } + + out.writeByte(0x00); + out.writeByte(0x01); + out.writeShort(targets.length); + out.writeInt(firstKey); + + for (int target : targets) { + out.writeInt(target); + } + } + + public PackedSwitchDataPseudoInstruction(byte[] buffer, int bufferIndex) { + super(Opcode.NOP, buffer, bufferIndex); + + byte opcodeByte = buffer[bufferIndex++]; + if (opcodeByte != 0x00) { + throw new RuntimeException("Invalid opcode byte for a PackedSwitchData pseudo-instruction"); + } + byte subopcodeByte = buffer[bufferIndex]; + if (subopcodeByte != 0x01) { + throw new RuntimeException("Invalid sub-opcode byte for a PackedSwitchData pseudo-instruction"); + } + } + + public Format getFormat() { + return Format.PackedSwitchData; + } + + public int getTargetCount() { + return NumberUtils.decodeUnsignedShort(buffer, bufferIndex + 2); + } + + public int getFirstKey() { + return NumberUtils.decodeInt(buffer, bufferIndex + 4); + } + + public static class PackedSwitchTarget { + public int value; + public int target; + } + + public Iterator getTargets() { + return new Iterator() { + final int targetCount = getTargetCount(); + int i = 0; + int position = bufferIndex + 8; + int value = getFirstKey(); + + PackedSwitchTarget packedSwitchTarget = new PackedSwitchTarget(); + + public boolean hasNext() { + return i 0xFFFF) { - throw new RuntimeException("The sparse-switch data contains too many elements. " + - "The maximum number of switch elements is 65535"); - } - - //write out padding, if necessary - if (out.getCursor() % 4 != 0) { - out.writeShort(0); - } - - out.writeByte(0x00); - out.writeByte(0x02); - out.writeShort(targets.length); - - if (targets.length > 0) { - int key = keys[0]; - - out.writeInt(key); - - for (int i = 1; i < keys.length; i++) { - key = keys[i]; - if (key <= keys[i - 1]) { - throw new RuntimeException("The targets in a sparse switch block must be sorted in ascending" + - "order, by key"); - } - out.writeInt(key); - } - - for (int target : targets) { - out.writeInt(target); - } - } - } - - public SparseSwitchDataPseudoInstruction(byte[] buffer, int bufferIndex) { - super(Opcode.NOP, buffer, bufferIndex); - - byte opcodeByte = buffer[bufferIndex++]; - if (opcodeByte != 0x00) { - throw new RuntimeException("Invalid opcode byte for a SparseSwitchData pseudo-instruction"); - } - byte subopcodeByte = buffer[bufferIndex]; - if (subopcodeByte != 0x02) { - throw new RuntimeException("Invalid sub-opcode byte for a SparseSwitchData pseudo-instruction"); - } - } - - public Format getFormat() { - return Format.SparseSwitchData; - } - - public int getTargetCount() { - return NumberUtils.decodeUnsignedShort(buffer, bufferIndex + 2); - } - - public static class SparseSwitchTarget { - public int value; - public int target; - } - - public Iterator getTargets() { - return new Iterator() { - final int targetCount = getTargetCount(); - int i = 0; - int valuePosition = bufferIndex + 4; - int targetPosition = bufferIndex + 4 + targetCount * 4; - - SparseSwitchTarget sparseSwitchTarget = new SparseSwitchTarget(); - - public boolean hasNext() { - return i 0xFFFF) { + throw new RuntimeException("The sparse-switch data contains too many elements. " + + "The maximum number of switch elements is 65535"); + } + + //write out padding, if necessary + if (out.getCursor() % 4 != 0) { + out.writeShort(0); + } + + out.writeByte(0x00); + out.writeByte(0x02); + out.writeShort(targets.length); + + if (targets.length > 0) { + int key = keys[0]; + + out.writeInt(key); + + for (int i = 1; i < keys.length; i++) { + key = keys[i]; + if (key <= keys[i - 1]) { + throw new RuntimeException("The targets in a sparse switch block must be sorted in ascending" + + "order, by key"); + } + out.writeInt(key); + } + + for (int target : targets) { + out.writeInt(target); + } + } + } + + public SparseSwitchDataPseudoInstruction(byte[] buffer, int bufferIndex) { + super(Opcode.NOP, buffer, bufferIndex); + + byte opcodeByte = buffer[bufferIndex++]; + if (opcodeByte != 0x00) { + throw new RuntimeException("Invalid opcode byte for a SparseSwitchData pseudo-instruction"); + } + byte subopcodeByte = buffer[bufferIndex]; + if (subopcodeByte != 0x02) { + throw new RuntimeException("Invalid sub-opcode byte for a SparseSwitchData pseudo-instruction"); + } + } + + public Format getFormat() { + return Format.SparseSwitchData; + } + + public int getTargetCount() { + return NumberUtils.decodeUnsignedShort(buffer, bufferIndex + 2); + } + + public static class SparseSwitchTarget { + public int value; + public int target; + } + + public Iterator getTargets() { + return new Iterator() { + final int targetCount = getTargetCount(); + int i = 0; + int valuePosition = bufferIndex + 4; + int targetPosition = bufferIndex + 4 + targetCount * 4; + + SparseSwitchTarget sparseSwitchTarget = new SparseSwitchTarget(); + + public boolean hasNext() { + return i opcodesByName; - - static { - opcodesByValue = new Opcode[256]; - opcodesByName = new HashMap(); - - for (Opcode opcode: Opcode.values()) { - opcodesByValue[opcode.value & 0xFF] = opcode; - opcodesByName.put(opcode.name.hashCode(), opcode); - } - } - - public static Opcode getOpcodeByName(String opcodeName) { - return opcodesByName.get(opcodeName.toLowerCase().hashCode()); - } - - public static Opcode getOpcodeByValue(byte opcodeValue) { - return opcodesByValue[opcodeValue & 0xFF]; - } - - public final byte value; - public final String name; - public final ReferenceType referenceType; - public final Format format; - public final boolean odexOnly; - - Opcode(byte opcodeValue, String opcodeName, ReferenceType referenceType, Format format) { - this(opcodeValue, opcodeName, referenceType, format, false); - } - - Opcode(byte opcodeValue, String opcodeName, ReferenceType referenceType, Format format, boolean odexOnly) { - this.value = opcodeValue; - this.name = opcodeName; - this.referenceType = referenceType; - this.format = format; - this.odexOnly = odexOnly; - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code; + +import org.jf.dexlib.Code.Format.Format; + +import java.util.HashMap; + +public enum Opcode +{ + NOP((byte)0x00, "nop", ReferenceType.none, Format.Format10x), + MOVE((byte)0x01, "move", ReferenceType.none, Format.Format12x), + MOVE_FROM16((byte)0x02, "move/from16", ReferenceType.none, Format.Format22x), + MOVE_16((byte)0x03, "move/16", ReferenceType.none, Format.Format32x), + MOVE_WIDE((byte)0x04, "move-wide", ReferenceType.none, Format.Format12x), + MOVE_WIDE_FROM16((byte)0x05, "move-wide/from16", ReferenceType.none, Format.Format22x), + MOVE_WIDE_16((byte)0x06, "move-wide/16", ReferenceType.none, Format.Format32x), + MOVE_OBJECT((byte)0x07, "move-object", ReferenceType.none, Format.Format12x), + MOVE_OBJECT_FROM16((byte)0x08, "move-object/from16", ReferenceType.none, Format.Format22x), + MOVE_OBJECT_16((byte)0x09, "move-object/16", ReferenceType.none, Format.Format32x), + MOVE_RESULT((byte)0x0a, "move-result", ReferenceType.none, Format.Format11x), + MOVE_RESULT_WIDE((byte)0x0b, "move-result-wide", ReferenceType.none, Format.Format11x), + MOVE_RESULT_OBJECT((byte)0x0c, "move-result-object", ReferenceType.none, Format.Format11x), + MOVE_EXCEPTION((byte)0x0d, "move-exception", ReferenceType.none, Format.Format11x), + RETURN_VOID((byte)0x0e, "return-void", ReferenceType.none, Format.Format10x), + RETURN((byte)0x0f, "return", ReferenceType.none, Format.Format11x), + RETURN_WIDE((byte)0x10, "return-wide", ReferenceType.none, Format.Format11x), + RETURN_OBJECT((byte)0x11, "return-object", ReferenceType.none, Format.Format11x), + CONST_4((byte)0x12, "const/4", ReferenceType.none, Format.Format11n), + CONST_16((byte)0x13, "const/16", ReferenceType.none, Format.Format21s), + CONST((byte)0x14, "const", ReferenceType.none, Format.Format31i), + CONST_HIGH16((byte)0x15, "const/high16", ReferenceType.none, Format.Format21h), + CONST_WIDE_16((byte)0x16, "const-wide/16", ReferenceType.none, Format.Format21s), + CONST_WIDE_32((byte)0x17, "const-wide/32", ReferenceType.none, Format.Format31i), + CONST_WIDE((byte)0x18, "const-wide", ReferenceType.none, Format.Format51l), + CONST_WIDE_HIGH16((byte)0x19, "const-wide/high16", ReferenceType.none, Format.Format21h), + CONST_STRING((byte)0x1a, "const-string", ReferenceType.string, Format.Format21c), + CONST_STRING_JUMBO((byte)0x1b, "const-string/jumbo", ReferenceType.string, Format.Format31c), + CONST_CLASS((byte)0x1c, "const-class", ReferenceType.type, Format.Format21c), + MONITOR_ENTER((byte)0x1d, "monitor-enter", ReferenceType.none, Format.Format11x), + MONITOR_EXIT((byte)0x1e, "monitor-exit", ReferenceType.none, Format.Format11x), + CHECK_CAST((byte)0x1f, "check-cast", ReferenceType.type, Format.Format21c), + INSTANCE_OF((byte)0x20, "instance-of", ReferenceType.type, Format.Format22c), + ARRAY_LENGTH((byte)0x21, "array-length", ReferenceType.none, Format.Format12x), + NEW_INSTANCE((byte)0x22, "new-instance", ReferenceType.type, Format.Format21c), + NEW_ARRAY((byte)0x23, "new-array", ReferenceType.type, Format.Format22c), + FILLED_NEW_ARRAY((byte)0x24, "filled-new-array", ReferenceType.type, Format.Format35c), + FILLED_NEW_ARRAY_RANGE((byte)0x25, "filled-new-array/range", ReferenceType.type, Format.Format3rc), + FILL_ARRAY_DATA((byte)0x26, "fill-array-data", ReferenceType.none, Format.Format31t), + THROW((byte)0x27, "throw", ReferenceType.none, Format.Format11x), + GOTO((byte)0x28, "goto", ReferenceType.none, Format.Format10t), + GOTO_16((byte)0x29, "goto/16", ReferenceType.none, Format.Format20t), + GOTO_32((byte)0x2a, "goto/32", ReferenceType.none, Format.Format30t), + PACKED_SWITCH((byte)0x2b, "packed-switch", ReferenceType.none, Format.Format31t), + SPARSE_SWITCH((byte)0x2c, "sparse-switch", ReferenceType.none, Format.Format31t), + CMPL_FLOAT((byte)0x2d, "cmpl-float", ReferenceType.none, Format.Format23x), + CMPG_FLOAT((byte)0x2e, "cmpg-float", ReferenceType.none, Format.Format23x), + CMPL_DOUBLE((byte)0x2f, "cmpl-double", ReferenceType.none, Format.Format23x), + CMPG_DOUBLE((byte)0x30, "cmpg-double", ReferenceType.none, Format.Format23x), + CMP_LONG((byte)0x31, "cmp-long", ReferenceType.none, Format.Format23x), + IF_EQ((byte)0x32, "if-eq", ReferenceType.none, Format.Format22t), + IF_NE((byte)0x33, "if-ne", ReferenceType.none, Format.Format22t), + IF_LT((byte)0x34, "if-lt", ReferenceType.none, Format.Format22t), + IF_GE((byte)0x35, "if-ge", ReferenceType.none, Format.Format22t), + IF_GT((byte)0x36, "if-gt", ReferenceType.none, Format.Format22t), + IF_LE((byte)0x37, "if-le", ReferenceType.none, Format.Format22t), + IF_EQZ((byte)0x38, "if-eqz", ReferenceType.none, Format.Format21t), + IF_NEZ((byte)0x39, "if-nez", ReferenceType.none, Format.Format21t), + IF_LTZ((byte)0x3a, "if-ltz", ReferenceType.none, Format.Format21t), + IF_GEZ((byte)0x3b, "if-gez", ReferenceType.none, Format.Format21t), + IF_GTZ((byte)0x3c, "if-gtz", ReferenceType.none, Format.Format21t), + IF_LEZ((byte)0x3d, "if-lez", ReferenceType.none, Format.Format21t), + AGET((byte)0x44, "aget", ReferenceType.none, Format.Format23x), + AGET_WIDE((byte)0x45, "aget-wide", ReferenceType.none, Format.Format23x), + AGET_OBJECT((byte)0x46, "aget-object", ReferenceType.none, Format.Format23x), + AGET_BOOLEAN((byte)0x47, "aget-boolean", ReferenceType.none, Format.Format23x), + AGET_BYTE((byte)0x48, "aget-byte", ReferenceType.none, Format.Format23x), + AGET_CHAR((byte)0x49, "aget-char", ReferenceType.none, Format.Format23x), + AGET_SHORT((byte)0x4a, "aget-short", ReferenceType.none, Format.Format23x), + APUT((byte)0x4b, "aput", ReferenceType.none, Format.Format23x), + APUT_WIDE((byte)0x4c, "aput-wide", ReferenceType.none, Format.Format23x), + APUT_OBJECT((byte)0x4d, "aput-object", ReferenceType.none, Format.Format23x), + APUT_BOOLEAN((byte)0x4e, "aput-boolean", ReferenceType.none, Format.Format23x), + APUT_BYTE((byte)0x4f, "aput-byte", ReferenceType.none, Format.Format23x), + APUT_CHAR((byte)0x50, "aput-char", ReferenceType.none, Format.Format23x), + APUT_SHORT((byte)0x51, "aput-short", ReferenceType.none, Format.Format23x), + IGET((byte)0x52, "iget", ReferenceType.field, Format.Format22c), + IGET_WIDE((byte)0x53, "iget-wide", ReferenceType.field, Format.Format22c), + IGET_OBJECT((byte)0x54, "iget-object", ReferenceType.field, Format.Format22c), + IGET_BOOLEAN((byte)0x55, "iget-boolean", ReferenceType.field, Format.Format22c), + IGET_BYTE((byte)0x56, "iget-byte", ReferenceType.field, Format.Format22c), + IGET_CHAR((byte)0x57, "iget-char", ReferenceType.field, Format.Format22c), + IGET_SHORT((byte)0x58, "iget-short", ReferenceType.field, Format.Format22c), + IPUT((byte)0x59, "iput", ReferenceType.field, Format.Format22c), + IPUT_WIDE((byte)0x5a, "iput-wide", ReferenceType.field, Format.Format22c), + IPUT_OBJECT((byte)0x5b, "iput-object", ReferenceType.field, Format.Format22c), + IPUT_BOOLEAN((byte)0x5c, "iput-boolean", ReferenceType.field, Format.Format22c), + IPUT_BYTE((byte)0x5d, "iput-byte", ReferenceType.field, Format.Format22c), + IPUT_CHAR((byte)0x5e, "iput-char", ReferenceType.field, Format.Format22c), + IPUT_SHORT((byte)0x5f, "iput-short", ReferenceType.field, Format.Format22c), + SGET((byte)0x60, "sget", ReferenceType.field, Format.Format21c), + SGET_WIDE((byte)0x61, "sget-wide", ReferenceType.field, Format.Format21c), + SGET_OBJECT((byte)0x62, "sget-object", ReferenceType.field, Format.Format21c), + SGET_BOOLEAN((byte)0x63, "sget-boolean", ReferenceType.field, Format.Format21c), + SGET_BYTE((byte)0x64, "sget-byte", ReferenceType.field, Format.Format21c), + SGET_CHAR((byte)0x65, "sget-char", ReferenceType.field, Format.Format21c), + SGET_SHORT((byte)0x66, "sget-short", ReferenceType.field, Format.Format21c), + SPUT((byte)0x67, "sput", ReferenceType.field, Format.Format21c), + SPUT_WIDE((byte)0x68, "sput-wide", ReferenceType.field, Format.Format21c), + SPUT_OBJECT((byte)0x69, "sput-object", ReferenceType.field, Format.Format21c), + SPUT_BOOLEAN((byte)0x6a, "sput-boolean", ReferenceType.field, Format.Format21c), + SPUT_BYTE((byte)0x6b, "sput-byte", ReferenceType.field, Format.Format21c), + SPUT_CHAR((byte)0x6c, "sput-char", ReferenceType.field, Format.Format21c), + SPUT_SHORT((byte)0x6d, "sput-short", ReferenceType.field, Format.Format21c), + INVOKE_VIRTUAL((byte)0x6e, "invoke-virtual", ReferenceType.method, Format.Format35c), + INVOKE_SUPER((byte)0x6f, "invoke-super", ReferenceType.method, Format.Format35c), + INVOKE_DIRECT((byte)0x70, "invoke-direct", ReferenceType.method, Format.Format35c), + INVOKE_STATIC((byte)0x71, "invoke-static", ReferenceType.method, Format.Format35c), + INVOKE_INTERFACE((byte)0x72, "invoke-interface", ReferenceType.method, Format.Format35c), + INVOKE_VIRTUAL_RANGE((byte)0x74, "invoke-virtual/range", ReferenceType.method, Format.Format3rc), + INVOKE_SUPER_RANGE((byte)0x75, "invoke-super/range", ReferenceType.method, Format.Format3rc), + INVOKE_DIRECT_RANGE((byte)0x76, "invoke-direct/range", ReferenceType.method, Format.Format3rc), + INVOKE_STATIC_RANGE((byte)0x77, "invoke-static/range", ReferenceType.method, Format.Format3rc), + INVOKE_INTERFACE_RANGE((byte)0x78, "invoke-interface/range", ReferenceType.method, Format.Format3rc), + NEG_INT((byte)0x7b, "neg-int", ReferenceType.none, Format.Format12x), + NOT_INT((byte)0x7c, "not-int", ReferenceType.none, Format.Format12x), + NEG_LONG((byte)0x7d, "neg-long", ReferenceType.none, Format.Format12x), + NOT_LONG((byte)0x7e, "not-long", ReferenceType.none, Format.Format12x), + NEG_FLOAT((byte)0x7f, "neg-float", ReferenceType.none, Format.Format12x), + NEG_DOUBLE((byte)0x80, "neg-double", ReferenceType.none, Format.Format12x), + INT_TO_LONG((byte)0x81, "int-to-long", ReferenceType.none, Format.Format12x), + INT_TO_FLOAT((byte)0x82, "int-to-float", ReferenceType.none, Format.Format12x), + INT_TO_DOUBLE((byte)0x83, "int-to-double", ReferenceType.none, Format.Format12x), + LONG_TO_INT((byte)0x84, "long-to-int", ReferenceType.none, Format.Format12x), + LONG_TO_FLOAT((byte)0x85, "long-to-float", ReferenceType.none, Format.Format12x), + LONG_TO_DOUBLE((byte)0x86, "long-to-double", ReferenceType.none, Format.Format12x), + FLOAT_TO_INT((byte)0x87, "float-to-int", ReferenceType.none, Format.Format12x), + FLOAT_TO_LONG((byte)0x88, "float-to-long", ReferenceType.none, Format.Format12x), + FLOAT_TO_DOUBLE((byte)0x89, "float-to-double", ReferenceType.none, Format.Format12x), + DOUBLE_TO_INT((byte)0x8a, "double-to-int", ReferenceType.none, Format.Format12x), + DOUBLE_TO_LONG((byte)0x8b, "double-to-long", ReferenceType.none, Format.Format12x), + DOUBLE_TO_FLOAT((byte)0x8c, "double-to-float", ReferenceType.none, Format.Format12x), + INT_TO_BYTE((byte)0x8d, "int-to-byte", ReferenceType.none, Format.Format12x), + INT_TO_CHAR((byte)0x8e, "int-to-char", ReferenceType.none, Format.Format12x), + INT_TO_SHORT((byte)0x8f, "int-to-short", ReferenceType.none, Format.Format12x), + ADD_INT((byte)0x90, "add-int", ReferenceType.none, Format.Format23x), + SUB_INT((byte)0x91, "sub-int", ReferenceType.none, Format.Format23x), + MUL_INT((byte)0x92, "mul-int", ReferenceType.none, Format.Format23x), + DIV_INT((byte)0x93, "div-int", ReferenceType.none, Format.Format23x), + REM_INT((byte)0x94, "rem-int", ReferenceType.none, Format.Format23x), + AND_INT((byte)0x95, "and-int", ReferenceType.none, Format.Format23x), + OR_INT((byte)0x96, "or-int", ReferenceType.none, Format.Format23x), + XOR_INT((byte)0x97, "xor-int", ReferenceType.none, Format.Format23x), + SHL_INT((byte)0x98, "shl-int", ReferenceType.none, Format.Format23x), + SHR_INT((byte)0x99, "shr-int", ReferenceType.none, Format.Format23x), + USHR_INT((byte)0x9a, "ushr-int", ReferenceType.none, Format.Format23x), + ADD_LONG((byte)0x9b, "add-long", ReferenceType.none, Format.Format23x), + SUB_LONG((byte)0x9c, "sub-long", ReferenceType.none, Format.Format23x), + MUL_LONG((byte)0x9d, "mul-long", ReferenceType.none, Format.Format23x), + DIV_LONG((byte)0x9e, "div-long", ReferenceType.none, Format.Format23x), + REM_LONG((byte)0x9f, "rem-long", ReferenceType.none, Format.Format23x), + AND_LONG((byte)0xa0, "and-long", ReferenceType.none, Format.Format23x), + OR_LONG((byte)0xa1, "or-long", ReferenceType.none, Format.Format23x), + XOR_LONG((byte)0xa2, "xor-long", ReferenceType.none, Format.Format23x), + SHL_LONG((byte)0xa3, "shl-long", ReferenceType.none, Format.Format23x), + SHR_LONG((byte)0xa4, "shr-long", ReferenceType.none, Format.Format23x), + USHR_LONG((byte)0xa5, "ushr-long", ReferenceType.none, Format.Format23x), + ADD_FLOAT((byte)0xa6, "add-float", ReferenceType.none, Format.Format23x), + SUB_FLOAT((byte)0xa7, "sub-float", ReferenceType.none, Format.Format23x), + MUL_FLOAT((byte)0xa8, "mul-float", ReferenceType.none, Format.Format23x), + DIV_FLOAT((byte)0xa9, "div-float", ReferenceType.none, Format.Format23x), + REM_FLOAT((byte)0xaa, "rem-float", ReferenceType.none, Format.Format23x), + ADD_DOUBLE((byte)0xab, "add-double", ReferenceType.none, Format.Format23x), + SUB_DOUBLE((byte)0xac, "sub-double", ReferenceType.none, Format.Format23x), + MUL_DOUBLE((byte)0xad, "mul-double", ReferenceType.none, Format.Format23x), + DIV_DOUBLE((byte)0xae, "div-double", ReferenceType.none, Format.Format23x), + REM_DOUBLE((byte)0xaf, "rem-double", ReferenceType.none, Format.Format23x), + ADD_INT_2ADDR((byte)0xb0, "add-int/2addr", ReferenceType.none, Format.Format12x), + SUB_INT_2ADDR((byte)0xb1, "sub-int/2addr", ReferenceType.none, Format.Format12x), + MUL_INT_2ADDR((byte)0xb2, "mul-int/2addr", ReferenceType.none, Format.Format12x), + DIV_INT_2ADDR((byte)0xb3, "div-int/2addr", ReferenceType.none, Format.Format12x), + REM_INT_2ADDR((byte)0xb4, "rem-int/2addr", ReferenceType.none, Format.Format12x), + AND_INT_2ADDR((byte)0xb5, "and-int/2addr", ReferenceType.none, Format.Format12x), + OR_INT_2ADDR((byte)0xb6, "or-int/2addr", ReferenceType.none, Format.Format12x), + XOR_INT_2ADDR((byte)0xb7, "xor-int/2addr", ReferenceType.none, Format.Format12x), + SHL_INT_2ADDR((byte)0xb8, "shl-int/2addr", ReferenceType.none, Format.Format12x), + SHR_INT_2ADDR((byte)0xb9, "shr-int/2addr", ReferenceType.none, Format.Format12x), + USHR_INT_2ADDR((byte)0xba, "ushr-int/2addr", ReferenceType.none, Format.Format12x), + ADD_LONG_2ADDR((byte)0xbb, "add-long/2addr", ReferenceType.none, Format.Format12x), + SUB_LONG_2ADDR((byte)0xbc, "sub-long/2addr", ReferenceType.none, Format.Format12x), + MUL_LONG_2ADDR((byte)0xbd, "mul-long/2addr", ReferenceType.none, Format.Format12x), + DIV_LONG_2ADDR((byte)0xbe, "div-long/2addr", ReferenceType.none, Format.Format12x), + REM_LONG_2ADDR((byte)0xbf, "rem-long/2addr", ReferenceType.none, Format.Format12x), + AND_LONG_2ADDR((byte)0xc0, "and-long/2addr", ReferenceType.none, Format.Format12x), + OR_LONG_2ADDR((byte)0xc1, "or-long/2addr", ReferenceType.none, Format.Format12x), + XOR_LONG_2ADDR((byte)0xc2, "xor-long/2addr", ReferenceType.none, Format.Format12x), + SHL_LONG_2ADDR((byte)0xc3, "shl-long/2addr", ReferenceType.none, Format.Format12x), + SHR_LONG_2ADDR((byte)0xc4, "shr-long/2addr", ReferenceType.none, Format.Format12x), + USHR_LONG_2ADDR((byte)0xc5, "ushr-long/2addr", ReferenceType.none, Format.Format12x), + ADD_FLOAT_2ADDR((byte)0xc6, "add-float/2addr", ReferenceType.none, Format.Format12x), + SUB_FLOAT_2ADDR((byte)0xc7, "sub-float/2addr", ReferenceType.none, Format.Format12x), + MUL_FLOAT_2ADDR((byte)0xc8, "mul-float/2addr", ReferenceType.none, Format.Format12x), + DIV_FLOAT_2ADDR((byte)0xc9, "div-float/2addr", ReferenceType.none, Format.Format12x), + REM_FLOAT_2ADDR((byte)0xca, "rem-float/2addr", ReferenceType.none, Format.Format12x), + ADD_DOUBLE_2ADDR((byte)0xcb, "add-double/2addr", ReferenceType.none, Format.Format12x), + SUB_DOUBLE_2ADDR((byte)0xcc, "sub-double/2addr", ReferenceType.none, Format.Format12x), + MUL_DOUBLE_2ADDR((byte)0xcd, "mul-double/2addr", ReferenceType.none, Format.Format12x), + DIV_DOUBLE_2ADDR((byte)0xce, "div-double/2addr", ReferenceType.none, Format.Format12x), + REM_DOUBLE_2ADDR((byte)0xcf, "rem-double/2addr", ReferenceType.none, Format.Format12x), + ADD_INT_LIT16((byte)0xd0, "add-int/lit16", ReferenceType.none, Format.Format22s), + RSUB_INT((byte)0xd1, "rsub-int", ReferenceType.none, Format.Format22s), + MUL_INT_LIT16((byte)0xd2, "mul-int/lit16", ReferenceType.none, Format.Format22s), + DIV_INT_LIT16((byte)0xd3, "div-int/lit16", ReferenceType.none, Format.Format22s), + REM_INT_LIT16((byte)0xd4, "rem-int/lit16", ReferenceType.none, Format.Format22s), + AND_INT_LIT16((byte)0xd5, "and-int/lit16", ReferenceType.none, Format.Format22s), + OR_INT_LIT16((byte)0xd6, "or-int/lit16", ReferenceType.none, Format.Format22s), + XOR_INT_LIT16((byte)0xd7, "xor-int/lit16", ReferenceType.none, Format.Format22s), + ADD_INT_LIT8((byte)0xd8, "add-int/lit8", ReferenceType.none, Format.Format22b), + RSUB_INT_LIT8((byte)0xd9, "rsub-int/lit8", ReferenceType.none, Format.Format22b), + MUL_INT_LIT8((byte)0xda, "mul-int/lit8", ReferenceType.none, Format.Format22b), + DIV_INT_LIT8((byte)0xdb, "div-int/lit8", ReferenceType.none, Format.Format22b), + REM_INT_LIT8((byte)0xdc, "rem-int/lit8", ReferenceType.none, Format.Format22b), + AND_INT_LIT8((byte)0xdd, "and-int/lit8", ReferenceType.none, Format.Format22b), + OR_INT_LIT8((byte)0xde, "or-int/lit8", ReferenceType.none, Format.Format22b), + XOR_INT_LIT8((byte)0xdf, "xor-int/lit8", ReferenceType.none, Format.Format22b), + SHL_INT_LIT8((byte)0xe0, "shl-int/lit8", ReferenceType.none, Format.Format22b), + SHR_INT_LIT8((byte)0xe1, "shr-int/lit8", ReferenceType.none, Format.Format22b), + USHR_INT_LIT8((byte)0xe2, "ushr-int/lit8", ReferenceType.none, Format.Format22b), + + + INVOKE_EXECUTE_INLINE((byte)0xee, "execute_inline", ReferenceType.none, Format.Format35ms, true), + INVOKE_DIRECT_EMPTY((byte)0xf0, "invoke-direct-empty", ReferenceType.method, Format.Format35s, true), + IGET_QUICK((byte)0xf2, "iget-quick", ReferenceType.none, Format.Format22cs, true), + IGET_WIDE_QUICK((byte)0xf3, "iget-wide-quick", ReferenceType.none, Format.Format22cs, true), + IGET_OBJECT_QUICK((byte)0xf4, "iget-object-quick", ReferenceType.none, Format.Format22cs, true), + IPUT_QUICK((byte)0xf5, "iput-quick", ReferenceType.none, Format.Format22cs, true), + IPUT_WIDE_QUICK((byte)0xf6, "iput-wide-quick", ReferenceType.none, Format.Format22cs, true), + IPUT_OBJECT_QUICK((byte)0xf7, "iput-object-quick", ReferenceType.none, Format.Format22cs, true), + INVOKE_VIRTUAL_QUICK((byte)0xf8, "invoke-virtual-quick", ReferenceType.none, Format.Format35ms, true), + INVOKE_VIRTUAL_RANGE_QUICK((byte)0xf9, "invoke-virtual-range-quick", ReferenceType.none, Format.Format3rms, true), + INVOKE_SUPER_QUICK((byte)0xfa, "invoke-super-quick", ReferenceType.none, Format.Format35ms, true), + INVOKE_SUPER_RANGE_QUICK((byte)0xfb, "invoke-super-range-quick", ReferenceType.none, Format.Format3rms, true); + + + + private static Opcode[] opcodesByValue; + private static HashMap opcodesByName; + + static { + opcodesByValue = new Opcode[256]; + opcodesByName = new HashMap(); + + for (Opcode opcode: Opcode.values()) { + opcodesByValue[opcode.value & 0xFF] = opcode; + opcodesByName.put(opcode.name.hashCode(), opcode); + } + } + + public static Opcode getOpcodeByName(String opcodeName) { + return opcodesByName.get(opcodeName.toLowerCase().hashCode()); + } + + public static Opcode getOpcodeByValue(byte opcodeValue) { + return opcodesByValue[opcodeValue & 0xFF]; + } + + public final byte value; + public final String name; + public final ReferenceType referenceType; + public final Format format; + public final boolean odexOnly; + + Opcode(byte opcodeValue, String opcodeName, ReferenceType referenceType, Format format) { + this(opcodeValue, opcodeName, referenceType, format, false); + } + + Opcode(byte opcodeValue, String opcodeName, ReferenceType referenceType, Format format, boolean odexOnly) { + this.value = opcodeValue; + this.name = opcodeName; + this.referenceType = referenceType; + this.format = format; + this.odexOnly = odexOnly; + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/ReferenceType.java b/dexlib/src/main/java/org/jf/dexlib/Code/ReferenceType.java index 8590dae3..9ba9a50a 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/ReferenceType.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/ReferenceType.java @@ -1,56 +1,56 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code; - -import org.jf.dexlib.*; - -public enum ReferenceType -{ - string, - type, - field, - method, - none; - - public boolean checkItem(Item item) { - switch (this) { - case string: - return item instanceof StringIdItem; - case type: - return item instanceof TypeIdItem; - case field: - return item instanceof FieldIdItem; - case method: - return item instanceof MethodIdItem; - case none: - return item == null; - } - return false; - } +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code; + +import org.jf.dexlib.*; + +public enum ReferenceType +{ + string, + type, + field, + method, + none; + + public boolean checkItem(Item item) { + switch (this) { + case string: + return item instanceof StringIdItem; + case type: + return item instanceof TypeIdItem; + case field: + return item instanceof FieldIdItem; + case method: + return item instanceof MethodIdItem; + case none: + return item == null; + } + return false; + } } \ No newline at end of file diff --git a/dexlib/src/main/java/org/jf/dexlib/CodeItem.java b/dexlib/src/main/java/org/jf/dexlib/CodeItem.java index 8d2f7ba2..9e04d8ba 100644 --- a/dexlib/src/main/java/org/jf/dexlib/CodeItem.java +++ b/dexlib/src/main/java/org/jf/dexlib/CodeItem.java @@ -1,712 +1,712 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib; - -import org.jf.dexlib.Code.*; -import org.jf.dexlib.Util.AnnotatedOutput; -import org.jf.dexlib.Util.Input; -import org.jf.dexlib.Util.SparseArray; -import org.jf.dexlib.Util.Leb128Utils; - -import java.util.List; -import java.util.LinkedList; - -public class CodeItem extends Item { - private int registerCount; - private int inWords; - private int outWords; - private DebugInfoItem debugInfo; - private byte[] encodedInstructions; - private Item[] referencedItems; - private TryItem[] tries; - private EncodedCatchHandler[] encodedCatchHandlers; - - private ClassDataItem.EncodedMethod parent; - - /** - * Creates a new uninitialized CodeItem - * @param dexFile The DexFile that this item belongs to - */ - public CodeItem(DexFile dexFile) { - super(dexFile); - } - - /** - * Creates a new CodeItem with the given values. - * @param dexFile The DexFile that this item belongs to - * @param registerCount the number of registers that the method containing this code uses - * @param inWords the number of 2-byte words that the parameters to the method containing this code take - * @param outWords the maximum number of 2-byte words for the arguments of any method call in this code - * @param debugInfo the debug information for this code/method - * @param encodedInstructions the instructions, encoded as a byte array - * @param referencedItems an array of the items referenced by instructions, in order of occurance in the code - * @param tries an array of the tries defined for this code/method - * @param encodedCatchHandlers an array of the exception handlers defined for this code/method - */ - private CodeItem(DexFile dexFile, - int registerCount, - int inWords, - int outWords, - DebugInfoItem debugInfo, - byte[] encodedInstructions, - Item[] referencedItems, - TryItem[] tries, - EncodedCatchHandler[] encodedCatchHandlers) { - super(dexFile); - - this.registerCount = registerCount; - this.inWords = inWords; - this.outWords = outWords; - this.debugInfo = debugInfo; - if (debugInfo != null) { - debugInfo.setParent(this); - } - this.encodedInstructions = encodedInstructions; - this.referencedItems = referencedItems; - this.tries = tries; - this.encodedCatchHandlers = encodedCatchHandlers; - } - - /** - * Returns a new CodeItem with the given values. - * @param dexFile The DexFile that this item belongs to - * @param registerCount the number of registers that the method containing this code uses - * @param inWords the number of 2-byte words that the parameters to the method containing this code take - * @param outWords the maximum number of 2-byte words for the arguments of any method call in this code - * @param debugInfo the debug information for this code/method - * @param encodedInstructions the instructions, encoded as a byte array - * @param referencedItems a list of the items referenced by instructions, in order of occurance in the code, - * or null if none - * @param tries a list of the tries defined for this code/method or null if none - * @param encodedCatchHandlers a list of the exception handlers defined for this code/method or null if none - * @return a new CodeItem with the given values. - */ - public static CodeItem getInternedCodeItem(DexFile dexFile, - int registerCount, - int inWords, - int outWords, - DebugInfoItem debugInfo, - byte[] encodedInstructions, - List referencedItems, - List tries, - List encodedCatchHandlers) { - Item[] referencedItemsArray = null; - TryItem[] triesArray = null; - EncodedCatchHandler[] encodedCatchHandlersArray = null; - - if (referencedItems != null && referencedItems.size() > 0) { - referencedItemsArray = new Item[referencedItems.size()]; - referencedItems.toArray(referencedItemsArray); - } - - if (tries != null && tries.size() > 0) { - triesArray = new TryItem[tries.size()]; - tries.toArray(triesArray); - } - - if (encodedCatchHandlers != null && encodedCatchHandlers.size() > 0) { - encodedCatchHandlersArray = new EncodedCatchHandler[encodedCatchHandlers.size()]; - encodedCatchHandlers.toArray(encodedCatchHandlersArray); - } - - CodeItem codeItem = new CodeItem(dexFile, registerCount, inWords, outWords, debugInfo, encodedInstructions, - referencedItemsArray, triesArray, encodedCatchHandlersArray); - return dexFile.CodeItemsSection.intern(codeItem); - } - - /** {@inheritDoc} */ - protected void readItem(Input in, ReadContext readContext) { - this.registerCount = in.readShort(); - this.inWords = in.readShort(); - this.outWords = in.readShort(); - int triesCount = in.readShort(); - this.debugInfo = (DebugInfoItem)readContext.getOffsettedItemByOffset(ItemType.TYPE_DEBUG_INFO_ITEM, - in.readInt()); - if (this.debugInfo != null) { - this.debugInfo.setParent(this); - } - int instructionCount = in.readInt(); - this.encodedInstructions = in.readBytes(instructionCount * 2); - this.referencedItems = InstructionReader.getReferencedItems(encodedInstructions, dexFile); - if (triesCount > 0) { - in.alignTo(4); - - //we need to read in the catch handlers first, so save the offset to the try items for future reference - int triesOffset = in.getCursor(); - in.setCursor(triesOffset + 8 * triesCount); - - //read in the encoded catch handlers - int encodedHandlerStart = in.getCursor(); - int handlerCount = in.readUnsignedLeb128(); - SparseArray handlerMap = new SparseArray(handlerCount); - encodedCatchHandlers = new EncodedCatchHandler[handlerCount]; - for (int i=0; i 0) { - if (encodedInstructions.length % 4 != 0) { - offset+=2; - } - - offset += tries.length * 8; - int encodedCatchHandlerBaseOffset = offset; - offset += Leb128Utils.unsignedLeb128Size(encodedCatchHandlers.length); - for (EncodedCatchHandler encodedCatchHandler: encodedCatchHandlers) { - offset = encodedCatchHandler.place(offset, encodedCatchHandlerBaseOffset); - } - } - return offset; - } - - /** {@inheritDoc} */ - protected void writeItem(final AnnotatedOutput out) { - if (out.annotates()) { - out.annotate(0, parent.method.getMethodString()); - out.annotate(2, "registers_size: 0x" + Integer.toHexString(registerCount) + " (" + registerCount + ")"); - out.annotate(2, "ins_size: 0x" + Integer.toHexString(inWords) + " (" + inWords + ")"); - out.annotate(2, "outs_size: 0x" + Integer.toHexString(outWords) + " (" + outWords + ")"); - int triesLength = tries==null?0:tries.length; - out.annotate(2, "tries_size: 0x" + Integer.toHexString(triesLength) + " (" + triesLength + ")"); - if (debugInfo == null) { - out.annotate(4, "debug_info_off:"); - } else { - out.annotate(4, "debug_info_off: 0x" + debugInfo.getOffset()); - } - out.annotate(4, "insns_size: 0x" + Integer.toHexString(encodedInstructions.length / 2) + " (" + - (encodedInstructions.length / 2) + ")"); - InstructionIterator.IterateInstructions(encodedInstructions, - new InstructionIterator.ProcessRawInstructionDelegate() { - - public void ProcessNormalInstruction(Opcode opcode, int index) { - out.annotate(opcode.format.size, "[0x" + Integer.toHexString(index/2) + "] " + opcode.name + - " instruction"); - } - - public void ProcessReferenceInstruction(Opcode opcode, int index) { - out.annotate(opcode.format.size, "[0x" + Integer.toHexString(index/2) + "] " + opcode.name + - " instruction"); - } - - public void ProcessPackedSwitchInstruction(int index, int targetCount, int instructionLength) { - out.annotate(instructionLength, "[0x" + Integer.toHexString(index/2) + "] " + - "packed_switch instruction"); - } - - public void ProcessSparseSwitchInstruction(int index, int targetCount, int instructionLength) { - out.annotate(instructionLength, "[0x" + Integer.toHexString(index/2) + "] " + - "sparse_switch instruction"); - } - - public void ProcessFillArrayDataInstruction(int index, int elementWidth, int elementCount, - int instructionLength) { - out.annotate(instructionLength, "[0x" + Integer.toHexString(index/2) + "] " + - "fill_array_data instruction"); - } - }); - } - - out.writeShort(registerCount); - out.writeShort(inWords); - out.writeShort(outWords); - if (tries == null) { - out.writeShort(0); - } else { - out.writeShort(tries.length); - } - if (debugInfo == null) { - out.writeInt(0); - } else { - out.writeInt(debugInfo.getOffset()); - } - out.writeInt(encodedInstructions.length / 2); - InstructionWriter.writeInstructions(encodedInstructions, referencedItems, out); - - if (tries != null && tries.length > 0) { - if (out.annotates()) { - if ((encodedInstructions.length % 4) != 0) { - out.annotate("padding"); - out.writeShort(0); - } - - int index = 0; - for (TryItem tryItem: tries) { - out.annotate(0, "[0x" + Integer.toHexString(index++) + "] try_item"); - out.indent(); - tryItem.writeTo(out); - out.deindent(); - } - - out.annotate("handler_count: 0x" + Integer.toHexString(encodedCatchHandlers.length) + "(" + - encodedCatchHandlers.length + ")"); - out.writeUnsignedLeb128(encodedCatchHandlers.length); - - index = 0; - for (EncodedCatchHandler encodedCatchHandler: encodedCatchHandlers) { - out.annotate(0, "[" + Integer.toHexString(index++) + "] encoded_catch_handler"); - out.indent(); - encodedCatchHandler.writeTo(out); - out.deindent(); - } - } else { - if ((encodedInstructions.length % 4) != 0) { - out.writeShort(0); - } - - for (TryItem tryItem: tries) { - tryItem.writeTo(out); - } - - out.writeUnsignedLeb128(encodedCatchHandlers.length); - - for (EncodedCatchHandler encodedCatchHandler: encodedCatchHandlers) { - encodedCatchHandler.writeTo(out); - } - } - } - } - - /** {@inheritDoc} */ - public ItemType getItemType() { - return ItemType.TYPE_CODE_ITEM; - } - - /** {@inheritDoc} */ - public String getConciseIdentity() { - //TODO: should mention the method name here - return "code_item @0x" + Integer.toHexString(getOffset()); - } - - /** {@inheritDoc} */ - public int compareTo(CodeItem other) { - if (parent == null) { - if (other.parent == null) { - return 0; - } - return -1; - } - if (other.parent == null) { - return 1; - } - return parent.method.compareTo(other.parent.method); - } - - /** - * @return the register count - */ - public int getRegisterCount() { - return registerCount; - } - - /** - * @return a byte array containing the encoded instructions - */ - public byte[] getEncodedInstructions() { - return encodedInstructions; - } - - /** - * @return an array of the TryItem objects in this CodeItem - */ - public TryItem[] getTries() { - return tries; - } - - /** - * @return an array of the EncodedCatchHandler objects in this CodeItem - */ - public EncodedCatchHandler[] getHandlers() { - return encodedCatchHandlers; - } - - /** - * @return the DebugInfoItem associated with this CodeItem - */ - public DebugInfoItem getDebugInfo() { - return debugInfo; - } - - /** - * Sets the MethodIdItem of the method that this CodeItem is associated with - * @param encodedMethod the EncodedMethod of the method that this CodeItem is associated - * with - */ - protected void setParent(ClassDataItem.EncodedMethod encodedMethod) { - this.parent = encodedMethod; - } - - /** - * @return the MethodIdItem of the method that this CodeItem belongs to - */ - public ClassDataItem.EncodedMethod getParent() { - return parent; - } - - /** - * Used by OdexUtil to update this CodeItem with a deodexed version of the instructions - * @param newEncodedInstructions - */ - public void updateCode(byte[] newEncodedInstructions) { - final LinkedList referencedItemsList = new LinkedList(); - - - InstructionIterator.IterateInstructions(dexFile, newEncodedInstructions, - new InstructionIterator.ProcessInstructionDelegate() { - public void ProcessInstruction(int index, Instruction instruction) { - if (instruction.opcode.referenceType != ReferenceType.none) { - referencedItemsList.add(((InstructionWithReference)instruction).getReferencedItem()); - } - } - }); - - referencedItems = new Item[referencedItemsList.size()]; - referencedItemsList.toArray(referencedItems); - encodedInstructions = newEncodedInstructions; - } - - public static class TryItem { - /** - * The address (in 2-byte words) within the code where the try block starts - */ - public final int startAddress; - - /** - * The number of 2-byte words that the try block covers - */ - public final int instructionCount; - - /** - * The associated exception handler - */ - public final EncodedCatchHandler encodedCatchHandler; - - /** - * Construct a new TryItem with the given values - * @param startAddress the address (in 2-byte words) within the code where the try block starts - * @param instructionCount the number of 2-byte words that the try block covers - * @param encodedCatchHandler the associated exception handler - */ - public TryItem(int startAddress, int instructionCount, EncodedCatchHandler encodedCatchHandler) { - this.startAddress = startAddress; - this.instructionCount = instructionCount; - this.encodedCatchHandler = encodedCatchHandler; - } - - /** - * This is used internally to construct a new TryItem while reading in a DexFile - * @param in the Input object to read the TryItem from - * @param encodedCatchHandlers a SparseArray of the EncodedCatchHandlers for this CodeItem. The - * key should be the offset of the EncodedCatchHandler from the beginning of the encoded_catch_handler_list - * structure. - */ - private TryItem(Input in, SparseArray encodedCatchHandlers) { - startAddress = in.readInt(); - instructionCount = in.readShort(); - - encodedCatchHandler = encodedCatchHandlers.get(in.readShort()); - if (encodedCatchHandler == null) { - throw new RuntimeException("Could not find the EncodedCatchHandler referenced by this TryItem"); - } - } - - /** - * Writes the TryItem to the given AnnotatedOutput object - * @param out the AnnotatedOutput object to write to - */ - private void writeTo(AnnotatedOutput out) { - if (out.annotates()) { - out.annotate(4, "start_addr: 0x" + Integer.toHexString(startAddress)); - out.annotate(2, "insn_count: 0x" + Integer.toHexString(instructionCount) + " (" + instructionCount + - ")"); - out.annotate(2, "handler_off: 0x" + Integer.toHexString(encodedCatchHandler.getOffsetInList())); - } - - out.writeInt(startAddress); - out.writeShort(instructionCount); - out.writeShort(encodedCatchHandler.getOffsetInList()); - } - } - - public static class EncodedCatchHandler { - /** - * An array of the individual exception handlers - */ - public final EncodedTypeAddrPair[] handlers; - - /** - * The address within the code (in 2-byte words) for the catch all handler, or -1 if there is no catch all - * handler - */ - public final int catchAllHandlerAddress; - - //TODO: would it be possible to get away without having these? and generate/create these values while writing? - private int baseOffset; - private int offset; - - /** - * Constructs a new EncodedCatchHandler with the given values - * @param handlers an array of the individual exception handlers - * @param catchAllHandlerAddress The address within the code (in 2-byte words) for the catch all handler, or -1 - * if there is no catch all handler - */ - public EncodedCatchHandler(EncodedTypeAddrPair[] handlers, int catchAllHandlerAddress) { - this.handlers = handlers; - this.catchAllHandlerAddress = catchAllHandlerAddress; - } - - /** - * This is used internally to construct a new EncodedCatchHandler while reading in a - * DexFile - * @param dexFile the DexFile that is being read in - * @param in the Input object to read the EncodedCatchHandler from - */ - private EncodedCatchHandler(DexFile dexFile, Input in) { - int handlerCount = in.readSignedLeb128(); - - if (handlerCount < 0) { - handlers = new EncodedTypeAddrPair[-1 * handlerCount]; - } else { - handlers = new EncodedTypeAddrPair[handlerCount]; - } - - for (int i=0; iEncodedCatchHandler from the beginning of the - * encoded_catch_handler_list structure - */ - private int getOffsetInList() { - return offset-baseOffset; - } - - /** - * Places the EncodedCatchHandler, storing the offset and baseOffset, and returning the offset - * immediately following this EncodedCatchHandler - * @param offset the offset of this EncodedCatchHandler in the DexFile - * @param baseOffset the offset of the beginning of the encoded_catch_handler_list structure in the - * DexFile - * @return the offset immediately following this EncodedCatchHandler - */ - private int place(int offset, int baseOffset) { - this.offset = offset; - this.baseOffset = baseOffset; - - int size = handlers.length; - if (catchAllHandlerAddress > -1) { - size *= -1; - offset += Leb128Utils.unsignedLeb128Size(catchAllHandlerAddress); - } - offset += Leb128Utils.signedLeb128Size(size); - - for (EncodedTypeAddrPair handler: handlers) { - offset += handler.getSize(); - } - return offset; - } - - /** - * Writes the EncodedCatchHandler to the given AnnotatedOutput object - * @param out the AnnotatedOutput object to write to - */ - private void writeTo(AnnotatedOutput out) { - if (out.annotates()) { - out.annotate("size: 0x" + Integer.toHexString(handlers.length) + " (" + handlers.length + ")"); - - int size = handlers.length; - if (catchAllHandlerAddress > -1) { - size = size * -1; - } - out.writeSignedLeb128(size); - - int index = 0; - for (EncodedTypeAddrPair handler: handlers) { - out.annotate(0, "[" + index++ + "] encoded_type_addr_pair"); - out.indent(); - handler.writeTo(out); - out.deindent(); - } - - if (catchAllHandlerAddress > -1) { - out.annotate("catch_all_addr: 0x" + Integer.toHexString(catchAllHandlerAddress)); - out.writeUnsignedLeb128(catchAllHandlerAddress); - } - } else { - int size = handlers.length; - if (catchAllHandlerAddress > -1) { - size = size * -1; - } - out.writeSignedLeb128(size); - - for (EncodedTypeAddrPair handler: handlers) { - handler.writeTo(out); - } - - if (catchAllHandlerAddress > -1) { - out.writeUnsignedLeb128(catchAllHandlerAddress); - } - } - } - - @Override - public int hashCode() { - int hash = 0; - for (EncodedTypeAddrPair handler: handlers) { - hash = hash * 31 + handler.hashCode(); - } - hash = hash * 31 + catchAllHandlerAddress; - return hash; - } - - @Override - public boolean equals(Object o) { - if (this==o) { - return true; - } - if (o==null || !this.getClass().equals(o.getClass())) { - return false; - } - - EncodedCatchHandler other = (EncodedCatchHandler)o; - if (handlers.length != other.handlers.length || catchAllHandlerAddress != other.catchAllHandlerAddress) { - return false; - } - - for (int i=0; iException that this handler handles - */ - public final TypeIdItem exceptionType; - - /** - * The address (in 2-byte words) in the code of the handler - */ - public final int handlerAddress; - - /** - * Constructs a new EncodedTypeAddrPair with the given values - * @param exceptionType the type of the Exception that this handler handles - * @param handlerAddress the address (in 2-byte words) in the code of the handler - */ - public EncodedTypeAddrPair(TypeIdItem exceptionType, int handlerAddress) { - this.exceptionType = exceptionType; - this.handlerAddress = handlerAddress; - } - - /** - * This is used internally to construct a new EncodedTypeAddrPair while reading in a - * DexFile - * @param dexFile the DexFile that is being read in - * @param in the Input object to read the EncodedCatchHandler from - */ - private EncodedTypeAddrPair(DexFile dexFile, Input in) { - exceptionType = dexFile.TypeIdsSection.getItemByIndex(in.readUnsignedLeb128()); - handlerAddress = in.readUnsignedLeb128(); - } - - /** - * @return the size of this EncodedTypeAddrPair - */ - private int getSize() { - return Leb128Utils.unsignedLeb128Size(exceptionType.getIndex()) + - Leb128Utils.unsignedLeb128Size(handlerAddress); - } - - /** - * Writes the EncodedTypeAddrPair to the given AnnotatedOutput object - * @param out the AnnotatedOutput object to write to - */ - private void writeTo(AnnotatedOutput out) { - if (out.annotates()) { - out.annotate("exception_type: " + exceptionType.getTypeDescriptor()); - out.writeUnsignedLeb128(exceptionType.getIndex()); - - out.annotate("handler_addr: 0x" + Integer.toHexString(handlerAddress)); - out.writeUnsignedLeb128(handlerAddress); - } else { - out.writeUnsignedLeb128(exceptionType.getIndex()); - out.writeUnsignedLeb128(handlerAddress); - } - } - - @Override - public int hashCode() { - return exceptionType.hashCode() * 31 + handlerAddress; - } - - @Override - public boolean equals(Object o) { - if (this==o) { - return true; - } - if (o==null || !this.getClass().equals(o.getClass())) { - return false; - } - - EncodedTypeAddrPair other = (EncodedTypeAddrPair)o; - return exceptionType == other.exceptionType && handlerAddress == other.handlerAddress; - } - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib; + +import org.jf.dexlib.Code.*; +import org.jf.dexlib.Util.AnnotatedOutput; +import org.jf.dexlib.Util.Input; +import org.jf.dexlib.Util.SparseArray; +import org.jf.dexlib.Util.Leb128Utils; + +import java.util.List; +import java.util.LinkedList; + +public class CodeItem extends Item { + private int registerCount; + private int inWords; + private int outWords; + private DebugInfoItem debugInfo; + private byte[] encodedInstructions; + private Item[] referencedItems; + private TryItem[] tries; + private EncodedCatchHandler[] encodedCatchHandlers; + + private ClassDataItem.EncodedMethod parent; + + /** + * Creates a new uninitialized CodeItem + * @param dexFile The DexFile that this item belongs to + */ + public CodeItem(DexFile dexFile) { + super(dexFile); + } + + /** + * Creates a new CodeItem with the given values. + * @param dexFile The DexFile that this item belongs to + * @param registerCount the number of registers that the method containing this code uses + * @param inWords the number of 2-byte words that the parameters to the method containing this code take + * @param outWords the maximum number of 2-byte words for the arguments of any method call in this code + * @param debugInfo the debug information for this code/method + * @param encodedInstructions the instructions, encoded as a byte array + * @param referencedItems an array of the items referenced by instructions, in order of occurance in the code + * @param tries an array of the tries defined for this code/method + * @param encodedCatchHandlers an array of the exception handlers defined for this code/method + */ + private CodeItem(DexFile dexFile, + int registerCount, + int inWords, + int outWords, + DebugInfoItem debugInfo, + byte[] encodedInstructions, + Item[] referencedItems, + TryItem[] tries, + EncodedCatchHandler[] encodedCatchHandlers) { + super(dexFile); + + this.registerCount = registerCount; + this.inWords = inWords; + this.outWords = outWords; + this.debugInfo = debugInfo; + if (debugInfo != null) { + debugInfo.setParent(this); + } + this.encodedInstructions = encodedInstructions; + this.referencedItems = referencedItems; + this.tries = tries; + this.encodedCatchHandlers = encodedCatchHandlers; + } + + /** + * Returns a new CodeItem with the given values. + * @param dexFile The DexFile that this item belongs to + * @param registerCount the number of registers that the method containing this code uses + * @param inWords the number of 2-byte words that the parameters to the method containing this code take + * @param outWords the maximum number of 2-byte words for the arguments of any method call in this code + * @param debugInfo the debug information for this code/method + * @param encodedInstructions the instructions, encoded as a byte array + * @param referencedItems a list of the items referenced by instructions, in order of occurance in the code, + * or null if none + * @param tries a list of the tries defined for this code/method or null if none + * @param encodedCatchHandlers a list of the exception handlers defined for this code/method or null if none + * @return a new CodeItem with the given values. + */ + public static CodeItem getInternedCodeItem(DexFile dexFile, + int registerCount, + int inWords, + int outWords, + DebugInfoItem debugInfo, + byte[] encodedInstructions, + List referencedItems, + List tries, + List encodedCatchHandlers) { + Item[] referencedItemsArray = null; + TryItem[] triesArray = null; + EncodedCatchHandler[] encodedCatchHandlersArray = null; + + if (referencedItems != null && referencedItems.size() > 0) { + referencedItemsArray = new Item[referencedItems.size()]; + referencedItems.toArray(referencedItemsArray); + } + + if (tries != null && tries.size() > 0) { + triesArray = new TryItem[tries.size()]; + tries.toArray(triesArray); + } + + if (encodedCatchHandlers != null && encodedCatchHandlers.size() > 0) { + encodedCatchHandlersArray = new EncodedCatchHandler[encodedCatchHandlers.size()]; + encodedCatchHandlers.toArray(encodedCatchHandlersArray); + } + + CodeItem codeItem = new CodeItem(dexFile, registerCount, inWords, outWords, debugInfo, encodedInstructions, + referencedItemsArray, triesArray, encodedCatchHandlersArray); + return dexFile.CodeItemsSection.intern(codeItem); + } + + /** {@inheritDoc} */ + protected void readItem(Input in, ReadContext readContext) { + this.registerCount = in.readShort(); + this.inWords = in.readShort(); + this.outWords = in.readShort(); + int triesCount = in.readShort(); + this.debugInfo = (DebugInfoItem)readContext.getOffsettedItemByOffset(ItemType.TYPE_DEBUG_INFO_ITEM, + in.readInt()); + if (this.debugInfo != null) { + this.debugInfo.setParent(this); + } + int instructionCount = in.readInt(); + this.encodedInstructions = in.readBytes(instructionCount * 2); + this.referencedItems = InstructionReader.getReferencedItems(encodedInstructions, dexFile); + if (triesCount > 0) { + in.alignTo(4); + + //we need to read in the catch handlers first, so save the offset to the try items for future reference + int triesOffset = in.getCursor(); + in.setCursor(triesOffset + 8 * triesCount); + + //read in the encoded catch handlers + int encodedHandlerStart = in.getCursor(); + int handlerCount = in.readUnsignedLeb128(); + SparseArray handlerMap = new SparseArray(handlerCount); + encodedCatchHandlers = new EncodedCatchHandler[handlerCount]; + for (int i=0; i 0) { + if (encodedInstructions.length % 4 != 0) { + offset+=2; + } + + offset += tries.length * 8; + int encodedCatchHandlerBaseOffset = offset; + offset += Leb128Utils.unsignedLeb128Size(encodedCatchHandlers.length); + for (EncodedCatchHandler encodedCatchHandler: encodedCatchHandlers) { + offset = encodedCatchHandler.place(offset, encodedCatchHandlerBaseOffset); + } + } + return offset; + } + + /** {@inheritDoc} */ + protected void writeItem(final AnnotatedOutput out) { + if (out.annotates()) { + out.annotate(0, parent.method.getMethodString()); + out.annotate(2, "registers_size: 0x" + Integer.toHexString(registerCount) + " (" + registerCount + ")"); + out.annotate(2, "ins_size: 0x" + Integer.toHexString(inWords) + " (" + inWords + ")"); + out.annotate(2, "outs_size: 0x" + Integer.toHexString(outWords) + " (" + outWords + ")"); + int triesLength = tries==null?0:tries.length; + out.annotate(2, "tries_size: 0x" + Integer.toHexString(triesLength) + " (" + triesLength + ")"); + if (debugInfo == null) { + out.annotate(4, "debug_info_off:"); + } else { + out.annotate(4, "debug_info_off: 0x" + debugInfo.getOffset()); + } + out.annotate(4, "insns_size: 0x" + Integer.toHexString(encodedInstructions.length / 2) + " (" + + (encodedInstructions.length / 2) + ")"); + InstructionIterator.IterateInstructions(encodedInstructions, + new InstructionIterator.ProcessRawInstructionDelegate() { + + public void ProcessNormalInstruction(Opcode opcode, int index) { + out.annotate(opcode.format.size, "[0x" + Integer.toHexString(index/2) + "] " + opcode.name + + " instruction"); + } + + public void ProcessReferenceInstruction(Opcode opcode, int index) { + out.annotate(opcode.format.size, "[0x" + Integer.toHexString(index/2) + "] " + opcode.name + + " instruction"); + } + + public void ProcessPackedSwitchInstruction(int index, int targetCount, int instructionLength) { + out.annotate(instructionLength, "[0x" + Integer.toHexString(index/2) + "] " + + "packed_switch instruction"); + } + + public void ProcessSparseSwitchInstruction(int index, int targetCount, int instructionLength) { + out.annotate(instructionLength, "[0x" + Integer.toHexString(index/2) + "] " + + "sparse_switch instruction"); + } + + public void ProcessFillArrayDataInstruction(int index, int elementWidth, int elementCount, + int instructionLength) { + out.annotate(instructionLength, "[0x" + Integer.toHexString(index/2) + "] " + + "fill_array_data instruction"); + } + }); + } + + out.writeShort(registerCount); + out.writeShort(inWords); + out.writeShort(outWords); + if (tries == null) { + out.writeShort(0); + } else { + out.writeShort(tries.length); + } + if (debugInfo == null) { + out.writeInt(0); + } else { + out.writeInt(debugInfo.getOffset()); + } + out.writeInt(encodedInstructions.length / 2); + InstructionWriter.writeInstructions(encodedInstructions, referencedItems, out); + + if (tries != null && tries.length > 0) { + if (out.annotates()) { + if ((encodedInstructions.length % 4) != 0) { + out.annotate("padding"); + out.writeShort(0); + } + + int index = 0; + for (TryItem tryItem: tries) { + out.annotate(0, "[0x" + Integer.toHexString(index++) + "] try_item"); + out.indent(); + tryItem.writeTo(out); + out.deindent(); + } + + out.annotate("handler_count: 0x" + Integer.toHexString(encodedCatchHandlers.length) + "(" + + encodedCatchHandlers.length + ")"); + out.writeUnsignedLeb128(encodedCatchHandlers.length); + + index = 0; + for (EncodedCatchHandler encodedCatchHandler: encodedCatchHandlers) { + out.annotate(0, "[" + Integer.toHexString(index++) + "] encoded_catch_handler"); + out.indent(); + encodedCatchHandler.writeTo(out); + out.deindent(); + } + } else { + if ((encodedInstructions.length % 4) != 0) { + out.writeShort(0); + } + + for (TryItem tryItem: tries) { + tryItem.writeTo(out); + } + + out.writeUnsignedLeb128(encodedCatchHandlers.length); + + for (EncodedCatchHandler encodedCatchHandler: encodedCatchHandlers) { + encodedCatchHandler.writeTo(out); + } + } + } + } + + /** {@inheritDoc} */ + public ItemType getItemType() { + return ItemType.TYPE_CODE_ITEM; + } + + /** {@inheritDoc} */ + public String getConciseIdentity() { + //TODO: should mention the method name here + return "code_item @0x" + Integer.toHexString(getOffset()); + } + + /** {@inheritDoc} */ + public int compareTo(CodeItem other) { + if (parent == null) { + if (other.parent == null) { + return 0; + } + return -1; + } + if (other.parent == null) { + return 1; + } + return parent.method.compareTo(other.parent.method); + } + + /** + * @return the register count + */ + public int getRegisterCount() { + return registerCount; + } + + /** + * @return a byte array containing the encoded instructions + */ + public byte[] getEncodedInstructions() { + return encodedInstructions; + } + + /** + * @return an array of the TryItem objects in this CodeItem + */ + public TryItem[] getTries() { + return tries; + } + + /** + * @return an array of the EncodedCatchHandler objects in this CodeItem + */ + public EncodedCatchHandler[] getHandlers() { + return encodedCatchHandlers; + } + + /** + * @return the DebugInfoItem associated with this CodeItem + */ + public DebugInfoItem getDebugInfo() { + return debugInfo; + } + + /** + * Sets the MethodIdItem of the method that this CodeItem is associated with + * @param encodedMethod the EncodedMethod of the method that this CodeItem is associated + * with + */ + protected void setParent(ClassDataItem.EncodedMethod encodedMethod) { + this.parent = encodedMethod; + } + + /** + * @return the MethodIdItem of the method that this CodeItem belongs to + */ + public ClassDataItem.EncodedMethod getParent() { + return parent; + } + + /** + * Used by OdexUtil to update this CodeItem with a deodexed version of the instructions + * @param newEncodedInstructions + */ + public void updateCode(byte[] newEncodedInstructions) { + final LinkedList referencedItemsList = new LinkedList(); + + + InstructionIterator.IterateInstructions(dexFile, newEncodedInstructions, + new InstructionIterator.ProcessInstructionDelegate() { + public void ProcessInstruction(int index, Instruction instruction) { + if (instruction.opcode.referenceType != ReferenceType.none) { + referencedItemsList.add(((InstructionWithReference)instruction).getReferencedItem()); + } + } + }); + + referencedItems = new Item[referencedItemsList.size()]; + referencedItemsList.toArray(referencedItems); + encodedInstructions = newEncodedInstructions; + } + + public static class TryItem { + /** + * The address (in 2-byte words) within the code where the try block starts + */ + public final int startAddress; + + /** + * The number of 2-byte words that the try block covers + */ + public final int instructionCount; + + /** + * The associated exception handler + */ + public final EncodedCatchHandler encodedCatchHandler; + + /** + * Construct a new TryItem with the given values + * @param startAddress the address (in 2-byte words) within the code where the try block starts + * @param instructionCount the number of 2-byte words that the try block covers + * @param encodedCatchHandler the associated exception handler + */ + public TryItem(int startAddress, int instructionCount, EncodedCatchHandler encodedCatchHandler) { + this.startAddress = startAddress; + this.instructionCount = instructionCount; + this.encodedCatchHandler = encodedCatchHandler; + } + + /** + * This is used internally to construct a new TryItem while reading in a DexFile + * @param in the Input object to read the TryItem from + * @param encodedCatchHandlers a SparseArray of the EncodedCatchHandlers for this CodeItem. The + * key should be the offset of the EncodedCatchHandler from the beginning of the encoded_catch_handler_list + * structure. + */ + private TryItem(Input in, SparseArray encodedCatchHandlers) { + startAddress = in.readInt(); + instructionCount = in.readShort(); + + encodedCatchHandler = encodedCatchHandlers.get(in.readShort()); + if (encodedCatchHandler == null) { + throw new RuntimeException("Could not find the EncodedCatchHandler referenced by this TryItem"); + } + } + + /** + * Writes the TryItem to the given AnnotatedOutput object + * @param out the AnnotatedOutput object to write to + */ + private void writeTo(AnnotatedOutput out) { + if (out.annotates()) { + out.annotate(4, "start_addr: 0x" + Integer.toHexString(startAddress)); + out.annotate(2, "insn_count: 0x" + Integer.toHexString(instructionCount) + " (" + instructionCount + + ")"); + out.annotate(2, "handler_off: 0x" + Integer.toHexString(encodedCatchHandler.getOffsetInList())); + } + + out.writeInt(startAddress); + out.writeShort(instructionCount); + out.writeShort(encodedCatchHandler.getOffsetInList()); + } + } + + public static class EncodedCatchHandler { + /** + * An array of the individual exception handlers + */ + public final EncodedTypeAddrPair[] handlers; + + /** + * The address within the code (in 2-byte words) for the catch all handler, or -1 if there is no catch all + * handler + */ + public final int catchAllHandlerAddress; + + //TODO: would it be possible to get away without having these? and generate/create these values while writing? + private int baseOffset; + private int offset; + + /** + * Constructs a new EncodedCatchHandler with the given values + * @param handlers an array of the individual exception handlers + * @param catchAllHandlerAddress The address within the code (in 2-byte words) for the catch all handler, or -1 + * if there is no catch all handler + */ + public EncodedCatchHandler(EncodedTypeAddrPair[] handlers, int catchAllHandlerAddress) { + this.handlers = handlers; + this.catchAllHandlerAddress = catchAllHandlerAddress; + } + + /** + * This is used internally to construct a new EncodedCatchHandler while reading in a + * DexFile + * @param dexFile the DexFile that is being read in + * @param in the Input object to read the EncodedCatchHandler from + */ + private EncodedCatchHandler(DexFile dexFile, Input in) { + int handlerCount = in.readSignedLeb128(); + + if (handlerCount < 0) { + handlers = new EncodedTypeAddrPair[-1 * handlerCount]; + } else { + handlers = new EncodedTypeAddrPair[handlerCount]; + } + + for (int i=0; iEncodedCatchHandler from the beginning of the + * encoded_catch_handler_list structure + */ + private int getOffsetInList() { + return offset-baseOffset; + } + + /** + * Places the EncodedCatchHandler, storing the offset and baseOffset, and returning the offset + * immediately following this EncodedCatchHandler + * @param offset the offset of this EncodedCatchHandler in the DexFile + * @param baseOffset the offset of the beginning of the encoded_catch_handler_list structure in the + * DexFile + * @return the offset immediately following this EncodedCatchHandler + */ + private int place(int offset, int baseOffset) { + this.offset = offset; + this.baseOffset = baseOffset; + + int size = handlers.length; + if (catchAllHandlerAddress > -1) { + size *= -1; + offset += Leb128Utils.unsignedLeb128Size(catchAllHandlerAddress); + } + offset += Leb128Utils.signedLeb128Size(size); + + for (EncodedTypeAddrPair handler: handlers) { + offset += handler.getSize(); + } + return offset; + } + + /** + * Writes the EncodedCatchHandler to the given AnnotatedOutput object + * @param out the AnnotatedOutput object to write to + */ + private void writeTo(AnnotatedOutput out) { + if (out.annotates()) { + out.annotate("size: 0x" + Integer.toHexString(handlers.length) + " (" + handlers.length + ")"); + + int size = handlers.length; + if (catchAllHandlerAddress > -1) { + size = size * -1; + } + out.writeSignedLeb128(size); + + int index = 0; + for (EncodedTypeAddrPair handler: handlers) { + out.annotate(0, "[" + index++ + "] encoded_type_addr_pair"); + out.indent(); + handler.writeTo(out); + out.deindent(); + } + + if (catchAllHandlerAddress > -1) { + out.annotate("catch_all_addr: 0x" + Integer.toHexString(catchAllHandlerAddress)); + out.writeUnsignedLeb128(catchAllHandlerAddress); + } + } else { + int size = handlers.length; + if (catchAllHandlerAddress > -1) { + size = size * -1; + } + out.writeSignedLeb128(size); + + for (EncodedTypeAddrPair handler: handlers) { + handler.writeTo(out); + } + + if (catchAllHandlerAddress > -1) { + out.writeUnsignedLeb128(catchAllHandlerAddress); + } + } + } + + @Override + public int hashCode() { + int hash = 0; + for (EncodedTypeAddrPair handler: handlers) { + hash = hash * 31 + handler.hashCode(); + } + hash = hash * 31 + catchAllHandlerAddress; + return hash; + } + + @Override + public boolean equals(Object o) { + if (this==o) { + return true; + } + if (o==null || !this.getClass().equals(o.getClass())) { + return false; + } + + EncodedCatchHandler other = (EncodedCatchHandler)o; + if (handlers.length != other.handlers.length || catchAllHandlerAddress != other.catchAllHandlerAddress) { + return false; + } + + for (int i=0; iException that this handler handles + */ + public final TypeIdItem exceptionType; + + /** + * The address (in 2-byte words) in the code of the handler + */ + public final int handlerAddress; + + /** + * Constructs a new EncodedTypeAddrPair with the given values + * @param exceptionType the type of the Exception that this handler handles + * @param handlerAddress the address (in 2-byte words) in the code of the handler + */ + public EncodedTypeAddrPair(TypeIdItem exceptionType, int handlerAddress) { + this.exceptionType = exceptionType; + this.handlerAddress = handlerAddress; + } + + /** + * This is used internally to construct a new EncodedTypeAddrPair while reading in a + * DexFile + * @param dexFile the DexFile that is being read in + * @param in the Input object to read the EncodedCatchHandler from + */ + private EncodedTypeAddrPair(DexFile dexFile, Input in) { + exceptionType = dexFile.TypeIdsSection.getItemByIndex(in.readUnsignedLeb128()); + handlerAddress = in.readUnsignedLeb128(); + } + + /** + * @return the size of this EncodedTypeAddrPair + */ + private int getSize() { + return Leb128Utils.unsignedLeb128Size(exceptionType.getIndex()) + + Leb128Utils.unsignedLeb128Size(handlerAddress); + } + + /** + * Writes the EncodedTypeAddrPair to the given AnnotatedOutput object + * @param out the AnnotatedOutput object to write to + */ + private void writeTo(AnnotatedOutput out) { + if (out.annotates()) { + out.annotate("exception_type: " + exceptionType.getTypeDescriptor()); + out.writeUnsignedLeb128(exceptionType.getIndex()); + + out.annotate("handler_addr: 0x" + Integer.toHexString(handlerAddress)); + out.writeUnsignedLeb128(handlerAddress); + } else { + out.writeUnsignedLeb128(exceptionType.getIndex()); + out.writeUnsignedLeb128(handlerAddress); + } + } + + @Override + public int hashCode() { + return exceptionType.hashCode() * 31 + handlerAddress; + } + + @Override + public boolean equals(Object o) { + if (this==o) { + return true; + } + if (o==null || !this.getClass().equals(o.getClass())) { + return false; + } + + EncodedTypeAddrPair other = (EncodedTypeAddrPair)o; + return exceptionType == other.exceptionType && handlerAddress == other.handlerAddress; + } + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/DebugInfoItem.java b/dexlib/src/main/java/org/jf/dexlib/DebugInfoItem.java index 4e28277f..e4b55a46 100644 --- a/dexlib/src/main/java/org/jf/dexlib/DebugInfoItem.java +++ b/dexlib/src/main/java/org/jf/dexlib/DebugInfoItem.java @@ -1,612 +1,612 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib; - -import org.jf.dexlib.Debug.DebugInstructionIterator; -import org.jf.dexlib.Debug.DebugOpcode; -import org.jf.dexlib.Util.AnnotatedOutput; -import org.jf.dexlib.Util.Input; -import org.jf.dexlib.Util.Leb128Utils; -import org.jf.dexlib.Util.ByteArrayInput; - -import java.util.ArrayList; -import java.util.List; - -public class DebugInfoItem extends Item { - private int lineStart; - private StringIdItem[] parameterNames; - private byte[] encodedDebugInfo; - private Item[] referencedItems; - - private CodeItem parent = null; - - /** - * Creates a new uninitialized DebugInfoInfo - * @param dexFile The DexFile that this item belongs to - */ - public DebugInfoItem(DexFile dexFile) { - super(dexFile); - } - - /** - * Creates a new DebugInfoItem with the given values - * @param dexFile The DexFile that this item belongs to - * @param lineStart the initial value for the line number register for the debug info machine - * @param parameterNames an array of the names of the associated method's parameters. The entire parameter - * can be null if no parameter info is available, or any element can be null to indicate no info for that parameter - * @param encodedDebugInfo the debug info, encoded as a byte array - * @param referencedItems an array of the items referenced by instructions, in order of occurance in the encoded - * debug info - */ - private DebugInfoItem(DexFile dexFile, - int lineStart, - StringIdItem[] parameterNames, - byte[] encodedDebugInfo, - Item[] referencedItems) { - super(dexFile); - this.lineStart = lineStart; - this.parameterNames = parameterNames; - this.encodedDebugInfo = encodedDebugInfo; - this.referencedItems = referencedItems; - } - - /** - * Returns a new DebugInfoItem with the given values - * @param dexFile The DexFile that this item belongs to - * @param lineStart the initial value for the line number register for the debug info machine - * @param parameterNames an array of the names of the associated method's parameters. The entire parameter - * can be null if no parameter info is available, or any element can be null to indicate no info for that parameter - * @param encodedDebugInfo the debug info, encoded as a byte array - * @param referencedItems an array of the items referenced by instructions, in order of occurance in the encoded - * debug info - * @return a new DebugInfoItem with the given values - */ - public static DebugInfoItem getInternedDebugInfoItem(DexFile dexFile, - int lineStart, - StringIdItem[] parameterNames, - byte[] encodedDebugInfo, - Item[] referencedItems) { - DebugInfoItem debugInfoItem = new DebugInfoItem(dexFile, lineStart, parameterNames, encodedDebugInfo, - referencedItems); - return dexFile.DebugInfoItemsSection.intern(debugInfoItem); - } - - /** {@inheritDoc} */ - protected void readItem(Input in, ReadContext readContext) { - lineStart = in.readUnsignedLeb128(); - parameterNames = new StringIdItem[in.readUnsignedLeb128()]; - IndexedSection stringIdSection = dexFile.StringIdsSection; - for (int i=0; i referencedItemsList = new ArrayList(50); - DebugInstructionIterator.IterateInstructions(in, - new DebugInstructionIterator.ProcessRawDebugInstructionDelegate() { - @Override - public void ProcessStartLocal(int startOffset, int length, int registerNum, int nameIndex, - int typeIndex, boolean registerIsSigned) { - if (nameIndex != -1) { - referencedItemsList.add(dexFile.StringIdsSection.getItemByIndex(nameIndex)); - } - if (typeIndex != -1) { - referencedItemsList.add(dexFile.TypeIdsSection.getItemByIndex(typeIndex)); - } - } - - @Override - public void ProcessStartLocalExtended(int startOffset, int length, int registerNume, int nameIndex, - int typeIndex, int signatureIndex, - boolean registerIsSigned) { - if (nameIndex != -1) { - referencedItemsList.add(dexFile.StringIdsSection.getItemByIndex(nameIndex)); - } - if (typeIndex != -1) { - referencedItemsList.add(dexFile.TypeIdsSection.getItemByIndex(typeIndex)); - } - if (signatureIndex != -1) { - referencedItemsList.add(dexFile.StringIdsSection.getItemByIndex(signatureIndex)); - } - } - - @Override - public void ProcessSetFile(int startOffset, int length, int nameIndex) { - if (nameIndex != -1) { - referencedItemsList.add(dexFile.StringIdsSection.getItemByIndex(nameIndex)); - } - } - }); - - referencedItems = new Item[referencedItemsList.size()]; - referencedItemsList.toArray(referencedItems); - - int length = in.getCursor() - start; - in.setCursor(start); - encodedDebugInfo = in.readBytes(length); - } - - - - /** {@inheritDoc} */ - protected int placeItem(int offset) { - offset += Leb128Utils.unsignedLeb128Size(lineStart); - offset += Leb128Utils.unsignedLeb128Size(parameterNames.length); - for (StringIdItem parameterName: parameterNames) { - int indexp1; - if (parameterName == null) { - indexp1 = 0; - } else { - indexp1 = parameterName.getIndex() + 1; - } - offset += Leb128Utils.unsignedLeb128Size(indexp1); - } - - //make a subclass so we can keep track of and access the computed length - class ProcessDebugInstructionDelegateWithLength extends - DebugInstructionIterator.ProcessRawDebugInstructionDelegate { - public int length = 0; - } - ProcessDebugInstructionDelegateWithLength pdidwl; - - //final referencedItems = this.referencedItems; - - DebugInstructionIterator.IterateInstructions(new ByteArrayInput(encodedDebugInfo), - pdidwl = new ProcessDebugInstructionDelegateWithLength() { - private int referencedItemsPosition = 0; - - @Override - public void ProcessStaticOpcode(DebugOpcode opcode, int startOffset, int length) { - this.length+=length; - } - - @Override - public void ProcessStartLocal(int startOffset, int length, int registerNum, int nameIndex, - int typeIndex, boolean registerIsSigned) { - this.length++; - if (dexFile.getPreserveSignedRegisters() && registerIsSigned) { - this.length += Leb128Utils.signedLeb128Size(registerNum); - } else { - this.length+=Leb128Utils.unsignedLeb128Size(registerNum); - } - if (nameIndex != -1) { - this.length+= - Leb128Utils.unsignedLeb128Size(referencedItems[referencedItemsPosition++].getIndex()+1); - } else { - this.length++; - } - if (typeIndex != -1) { - this.length+= - Leb128Utils.unsignedLeb128Size(referencedItems[referencedItemsPosition++].getIndex()+1); - } else { - this.length++; - } - - } - - @Override - public void ProcessStartLocalExtended(int startOffset, int length, int registerNum, int nameIndex, - int typeIndex, int signatureIndex, - boolean registerIsSigned) { - this.length++; - if (dexFile.getPreserveSignedRegisters() && registerIsSigned) { - this.length += Leb128Utils.signedLeb128Size(registerNum); - } else { - this.length+=Leb128Utils.unsignedLeb128Size(registerNum); - } - if (nameIndex != -1) { - this.length+= - Leb128Utils.unsignedLeb128Size(referencedItems[referencedItemsPosition++].getIndex()+1); - } else { - this.length++; - } - if (typeIndex != -1) { - this.length+= - Leb128Utils.unsignedLeb128Size(referencedItems[referencedItemsPosition++].getIndex()+1); - } else { - this.length++; - } - if (signatureIndex != -1) { - this.length+= - Leb128Utils.unsignedLeb128Size(referencedItems[referencedItemsPosition++].getIndex()+1); - } else { - this.length++; - } - } - - @Override - public void ProcessSetFile(int startOffset, int length, int nameIndex) { - this.length++; - if (nameIndex != -1) { - this.length+= - Leb128Utils.unsignedLeb128Size(referencedItems[referencedItemsPosition++].getIndex()+1); - } else { - this.length++; - } - } - }); - return offset + pdidwl.length; - } - - /** {@inheritDoc} */ - protected void writeItem(final AnnotatedOutput out) { - - if (out.annotates()) { - writeItemWithAnnotations(out); - } else { - writeItemWithNoAnnotations(out); - } - } - - /** - * Helper method that writes the item, without writing annotations - * @param out the AnnotatedOutput object - */ - private void writeItemWithNoAnnotations(final AnnotatedOutput out) { - out.writeUnsignedLeb128(lineStart); - out.writeUnsignedLeb128(parameterNames.length); - for (StringIdItem parameterName: parameterNames) { - int indexp1; - if (parameterName == null) { - indexp1 = 0; - } else { - indexp1 = parameterName.getIndex() + 1; - } - out.writeUnsignedLeb128(indexp1); - } - - DebugInstructionIterator.IterateInstructions(new ByteArrayInput(encodedDebugInfo), - new DebugInstructionIterator.ProcessRawDebugInstructionDelegate() { - private int referencedItemsPosition = 0; - - @Override - public void ProcessStaticOpcode(DebugOpcode opcode, int startOffset, int length) { - out.write(encodedDebugInfo, startOffset, length); - } - - @Override - public void ProcessStartLocal(int startOffset, int length, int registerNum, int nameIndex, - int typeIndex, boolean registerIsSigned) { - out.writeByte(DebugOpcode.DBG_START_LOCAL.value); - if (dexFile.getPreserveSignedRegisters() && registerIsSigned) { - out.writeSignedLeb128(registerNum); - } else { - out.writeUnsignedLeb128(registerNum); - } - if (nameIndex != -1) { - out.writeUnsignedLeb128(referencedItems[referencedItemsPosition++].getIndex() + 1); - } else { - out.writeByte(0); - } - if (typeIndex != -1) { - out.writeUnsignedLeb128(referencedItems[referencedItemsPosition++].getIndex() + 1); - } else { - out.writeByte(0); - } - } - - @Override - public void ProcessStartLocalExtended(int startOffset, int length, int registerNum, int nameIndex, - int typeIndex, int signatureIndex, - boolean registerIsSigned) { - out.writeByte(DebugOpcode.DBG_START_LOCAL_EXTENDED.value); - if (dexFile.getPreserveSignedRegisters() && registerIsSigned) { - out.writeSignedLeb128(registerNum); - } else { - out.writeUnsignedLeb128(registerNum); - } - if (nameIndex != -1) { - out.writeUnsignedLeb128(referencedItems[referencedItemsPosition++].getIndex() + 1); - } else { - out.writeByte(0); - } - if (typeIndex != -1) { - out.writeUnsignedLeb128(referencedItems[referencedItemsPosition++].getIndex() + 1); - } else { - out.writeByte(0); - } - if (signatureIndex != -1) { - out.writeUnsignedLeb128(referencedItems[referencedItemsPosition++].getIndex() + 1); - } else { - out.writeByte(0); - } - } - - @Override - public void ProcessSetFile(int startOffset, int length, int nameIndex) { - out.writeByte(DebugOpcode.DBG_SET_FILE.value); - if (nameIndex != -1) { - out.writeUnsignedLeb128(referencedItems[referencedItemsPosition++].getIndex() + 1); - } else { - out.writeByte(0); - } - } - }); - } - - /** - * Helper method that writes and annotates the item - * @param out the AnnotatedOutput object - */ - private void writeItemWithAnnotations(final AnnotatedOutput out) { - out.annotate(0, parent.getParent().method.getMethodString()); - out.annotate("line_start: 0x" + Integer.toHexString(lineStart) + " (" + lineStart + ")"); - out.writeUnsignedLeb128(lineStart); - out.annotate("parameters_size: 0x" + Integer.toHexString(parameterNames.length) + " (" + parameterNames.length - + ")"); - out.writeUnsignedLeb128(parameterNames.length); - int index = 0; - for (StringIdItem parameterName: parameterNames) { - int indexp1; - if (parameterName == null) { - out.annotate("[" + index++ +"] parameterName: "); - indexp1 = 0; - } else { - out.annotate("[" + index++ +"] parameterName: " + parameterName.getStringValue()); - indexp1 = parameterName.getIndex() + 1; - } - out.writeUnsignedLeb128(indexp1); - } - - DebugInstructionIterator.IterateInstructions(new ByteArrayInput(encodedDebugInfo), - new DebugInstructionIterator.ProcessRawDebugInstructionDelegate() { - private int referencedItemsPosition = 0; - - @Override - public void ProcessEndSequence(int startOffset) { - out.annotate("DBG_END_SEQUENCE"); - out.writeByte(DebugOpcode.DBG_END_SEQUENCE.value); - } - - @Override - public void ProcessAdvancePC(int startOffset, int length, int addressDiff) { - out.annotate("DBG_ADVANCE_PC"); - out.writeByte(DebugOpcode.DBG_ADVANCE_PC.value); - out.indent(); - out.annotate("addr_diff: 0x" + Integer.toHexString(addressDiff) + " (" + addressDiff + ")"); - out.writeUnsignedLeb128(addressDiff); - out.deindent(); - } - - @Override - public void ProcessAdvanceLine(int startOffset, int length, int lineDiff) { - out.annotate("DBG_ADVANCE_LINE"); - out.writeByte(DebugOpcode.DBG_ADVANCE_LINE.value); - out.indent(); - out.annotate("line_diff: 0x" + Integer.toHexString(lineDiff) + " (" + lineDiff + ")"); - out.writeSignedLeb128(lineDiff); - out.deindent(); - } - - @Override - public void ProcessStartLocal(int startOffset, int length, int registerNum, int nameIndex, - int typeIndex, boolean registerIsSigned) { - out.annotate("DBG_START_LOCAL"); - out.writeByte(DebugOpcode.DBG_START_LOCAL.value); - out.indent(); - out.annotate("register_num: 0x" + Integer.toHexString(registerNum) + " (" + registerNum + ")"); - if (dexFile.getPreserveSignedRegisters() && registerIsSigned) { - out.writeSignedLeb128(registerNum); - } else { - out.writeUnsignedLeb128(registerNum); - } - if (nameIndex != -1) { - Item nameItem = referencedItems[referencedItemsPosition++]; - assert nameItem instanceof StringIdItem; - out.annotate("name: " + ((StringIdItem)nameItem).getStringValue()); - out.writeUnsignedLeb128(nameItem.getIndex() + 1); - } else { - out.annotate("name: "); - out.writeByte(0); - } - if (typeIndex != -1) { - Item typeItem = referencedItems[referencedItemsPosition++]; - assert typeItem instanceof TypeIdItem; - out.annotate("type: " + ((TypeIdItem)typeItem).getTypeDescriptor()); - out.writeUnsignedLeb128(typeItem.getIndex() + 1); - } else { - out.annotate("type: "); - out.writeByte(0); - } - out.deindent(); - } - - @Override - public void ProcessStartLocalExtended(int startOffset, int length, int registerNum, int nameIndex, - int typeIndex, int signatureIndex, - boolean registerIsSigned) { - out.annotate("DBG_START_LOCAL_EXTENDED"); - out.writeByte(DebugOpcode.DBG_START_LOCAL_EXTENDED.value); - out.indent(); - out.annotate("register_num: 0x" + Integer.toHexString(registerNum) + " (" + registerNum + ")"); - if (dexFile.getPreserveSignedRegisters() && registerIsSigned) { - out.writeSignedLeb128(registerNum); - } else { - out.writeUnsignedLeb128(registerNum); - } - if (nameIndex != -1) { - Item nameItem = referencedItems[referencedItemsPosition++]; - assert nameItem instanceof StringIdItem; - out.annotate("name: " + ((StringIdItem)nameItem).getStringValue()); - out.writeUnsignedLeb128(nameItem.getIndex() + 1); - } else { - out.annotate("name: "); - out.writeByte(0); - } - if (typeIndex != -1) { - Item typeItem = referencedItems[referencedItemsPosition++]; - assert typeItem instanceof TypeIdItem; - out.annotate("type: " + ((TypeIdItem)typeItem).getTypeDescriptor()); - out.writeUnsignedLeb128(typeItem.getIndex() + 1); - } else { - out.annotate("type: "); - out.writeByte(0); - } - if (signatureIndex != -1) { - Item signatureItem = referencedItems[referencedItemsPosition++]; - assert signatureItem instanceof StringIdItem; - out.annotate("signature: " + ((StringIdItem)signatureItem).getStringValue()); - out.writeUnsignedLeb128(signatureItem.getIndex() + 1); - } else { - out.annotate("signature: "); - out.writeByte(0); - } - out.deindent(); - } - - @Override - public void ProcessEndLocal(int startOffset, int length, int registerNum, boolean registerIsSigned) { - out.annotate("DBG_END_LOCAL"); - out.writeByte(DebugOpcode.DBG_END_LOCAL.value); - out.annotate("register_num: 0x" + Integer.toHexString(registerNum) + " (" + registerNum + ")"); - if (registerIsSigned) { - out.writeSignedLeb128(registerNum); - } else { - out.writeUnsignedLeb128(registerNum); - } - } - - @Override - public void ProcessRestartLocal(int startOffset, int length, int registerNum, boolean registerIsSigned) { - out.annotate("DBG_RESTART_LOCAL"); - out.writeByte(DebugOpcode.DBG_RESTART_LOCAL.value); - out.annotate("register_num: 0x" + Integer.toHexString(registerNum) + " (" + registerNum + ")"); - if (registerIsSigned) { - out.writeSignedLeb128(registerNum); - } else { - out.writeUnsignedLeb128(registerNum); - } - } - - @Override - public void ProcessSetPrologueEnd(int startOffset) { - out.annotate("DBG_SET_PROLOGUE_END"); - out.writeByte(DebugOpcode.DBG_SET_PROLOGUE_END.value); - } - - @Override - public void ProcessSetEpilogueBegin(int startOffset) { - out.annotate("DBG_SET_EPILOGUE_BEGIN"); - out.writeByte(DebugOpcode.DBG_SET_EPILOGUE_BEGIN.value); - } - - @Override - public void ProcessSetFile(int startOffset, int length, int nameIndex) { - out.annotate("DBG_SET_FILE"); - out.writeByte(DebugOpcode.DBG_SET_FILE.value); - if (nameIndex != -1) { - Item sourceItem = referencedItems[referencedItemsPosition++]; - assert sourceItem instanceof StringIdItem; - out.annotate("source_file: \"" + ((StringIdItem)sourceItem).getStringValue() + "\""); - out.writeUnsignedLeb128(sourceItem.getIndex() + 1); - } else { - out.annotate("source_file: "); - out.writeByte(0); - } - } - - @Override - public void ProcessSpecialOpcode(int startOffset, int debugOpcode, int lineDiff, int addressDiff) { - out.annotate("DBG_SPECIAL_OPCODE: line_diff=0x" + Integer.toHexString(lineDiff) + "(" + - lineDiff +"),addressDiff=0x" + Integer.toHexString(addressDiff) + "(" + addressDiff + - ")"); - out.writeByte(debugOpcode); - } - }); - } - - - - - /** {@inheritDoc} */ - public ItemType getItemType() { - return ItemType.TYPE_DEBUG_INFO_ITEM; - } - - /** {@inheritDoc} */ - public String getConciseIdentity() { - return "debug_info_item @0x" + Integer.toHexString(getOffset()); - } - - /** {@inheritDoc} */ - public int compareTo(DebugInfoItem other) { - if (parent == null) { - if (other.parent == null) { - return 0; - } - return -1; - } - if (other.parent == null) { - return 1; - } - return parent.compareTo(other.parent); - } - - /** - * Set the CodeItem that this DebugInfoItem is associated with - * @param codeItem the CodeItem that this DebugInfoItem is associated with - */ - protected void setParent(CodeItem codeItem) { - this.parent = codeItem; - } - - /** - * @return the initial value for the line number register for the debug info machine - */ - public int getLineStart() { - return lineStart; - } - - /** - * @return the debug info, encoded as a byte array - */ - public byte[] getEncodedDebugInfo() { - return encodedDebugInfo; - } - - /** - * @return an array of the items referenced by instructions, in order of occurance in the encoded debug info - */ - public Item[] getReferencedItems() { - return referencedItems; - } - - /** - * @return an array of the names of the associated method's parameters. The array can be null if no parameter info - * is available, or any element can be null to indicate no info for that parameter - */ - public StringIdItem[] getParameterNames() { - return parameterNames; - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib; + +import org.jf.dexlib.Debug.DebugInstructionIterator; +import org.jf.dexlib.Debug.DebugOpcode; +import org.jf.dexlib.Util.AnnotatedOutput; +import org.jf.dexlib.Util.Input; +import org.jf.dexlib.Util.Leb128Utils; +import org.jf.dexlib.Util.ByteArrayInput; + +import java.util.ArrayList; +import java.util.List; + +public class DebugInfoItem extends Item { + private int lineStart; + private StringIdItem[] parameterNames; + private byte[] encodedDebugInfo; + private Item[] referencedItems; + + private CodeItem parent = null; + + /** + * Creates a new uninitialized DebugInfoInfo + * @param dexFile The DexFile that this item belongs to + */ + public DebugInfoItem(DexFile dexFile) { + super(dexFile); + } + + /** + * Creates a new DebugInfoItem with the given values + * @param dexFile The DexFile that this item belongs to + * @param lineStart the initial value for the line number register for the debug info machine + * @param parameterNames an array of the names of the associated method's parameters. The entire parameter + * can be null if no parameter info is available, or any element can be null to indicate no info for that parameter + * @param encodedDebugInfo the debug info, encoded as a byte array + * @param referencedItems an array of the items referenced by instructions, in order of occurance in the encoded + * debug info + */ + private DebugInfoItem(DexFile dexFile, + int lineStart, + StringIdItem[] parameterNames, + byte[] encodedDebugInfo, + Item[] referencedItems) { + super(dexFile); + this.lineStart = lineStart; + this.parameterNames = parameterNames; + this.encodedDebugInfo = encodedDebugInfo; + this.referencedItems = referencedItems; + } + + /** + * Returns a new DebugInfoItem with the given values + * @param dexFile The DexFile that this item belongs to + * @param lineStart the initial value for the line number register for the debug info machine + * @param parameterNames an array of the names of the associated method's parameters. The entire parameter + * can be null if no parameter info is available, or any element can be null to indicate no info for that parameter + * @param encodedDebugInfo the debug info, encoded as a byte array + * @param referencedItems an array of the items referenced by instructions, in order of occurance in the encoded + * debug info + * @return a new DebugInfoItem with the given values + */ + public static DebugInfoItem getInternedDebugInfoItem(DexFile dexFile, + int lineStart, + StringIdItem[] parameterNames, + byte[] encodedDebugInfo, + Item[] referencedItems) { + DebugInfoItem debugInfoItem = new DebugInfoItem(dexFile, lineStart, parameterNames, encodedDebugInfo, + referencedItems); + return dexFile.DebugInfoItemsSection.intern(debugInfoItem); + } + + /** {@inheritDoc} */ + protected void readItem(Input in, ReadContext readContext) { + lineStart = in.readUnsignedLeb128(); + parameterNames = new StringIdItem[in.readUnsignedLeb128()]; + IndexedSection stringIdSection = dexFile.StringIdsSection; + for (int i=0; i referencedItemsList = new ArrayList(50); + DebugInstructionIterator.IterateInstructions(in, + new DebugInstructionIterator.ProcessRawDebugInstructionDelegate() { + @Override + public void ProcessStartLocal(int startOffset, int length, int registerNum, int nameIndex, + int typeIndex, boolean registerIsSigned) { + if (nameIndex != -1) { + referencedItemsList.add(dexFile.StringIdsSection.getItemByIndex(nameIndex)); + } + if (typeIndex != -1) { + referencedItemsList.add(dexFile.TypeIdsSection.getItemByIndex(typeIndex)); + } + } + + @Override + public void ProcessStartLocalExtended(int startOffset, int length, int registerNume, int nameIndex, + int typeIndex, int signatureIndex, + boolean registerIsSigned) { + if (nameIndex != -1) { + referencedItemsList.add(dexFile.StringIdsSection.getItemByIndex(nameIndex)); + } + if (typeIndex != -1) { + referencedItemsList.add(dexFile.TypeIdsSection.getItemByIndex(typeIndex)); + } + if (signatureIndex != -1) { + referencedItemsList.add(dexFile.StringIdsSection.getItemByIndex(signatureIndex)); + } + } + + @Override + public void ProcessSetFile(int startOffset, int length, int nameIndex) { + if (nameIndex != -1) { + referencedItemsList.add(dexFile.StringIdsSection.getItemByIndex(nameIndex)); + } + } + }); + + referencedItems = new Item[referencedItemsList.size()]; + referencedItemsList.toArray(referencedItems); + + int length = in.getCursor() - start; + in.setCursor(start); + encodedDebugInfo = in.readBytes(length); + } + + + + /** {@inheritDoc} */ + protected int placeItem(int offset) { + offset += Leb128Utils.unsignedLeb128Size(lineStart); + offset += Leb128Utils.unsignedLeb128Size(parameterNames.length); + for (StringIdItem parameterName: parameterNames) { + int indexp1; + if (parameterName == null) { + indexp1 = 0; + } else { + indexp1 = parameterName.getIndex() + 1; + } + offset += Leb128Utils.unsignedLeb128Size(indexp1); + } + + //make a subclass so we can keep track of and access the computed length + class ProcessDebugInstructionDelegateWithLength extends + DebugInstructionIterator.ProcessRawDebugInstructionDelegate { + public int length = 0; + } + ProcessDebugInstructionDelegateWithLength pdidwl; + + //final referencedItems = this.referencedItems; + + DebugInstructionIterator.IterateInstructions(new ByteArrayInput(encodedDebugInfo), + pdidwl = new ProcessDebugInstructionDelegateWithLength() { + private int referencedItemsPosition = 0; + + @Override + public void ProcessStaticOpcode(DebugOpcode opcode, int startOffset, int length) { + this.length+=length; + } + + @Override + public void ProcessStartLocal(int startOffset, int length, int registerNum, int nameIndex, + int typeIndex, boolean registerIsSigned) { + this.length++; + if (dexFile.getPreserveSignedRegisters() && registerIsSigned) { + this.length += Leb128Utils.signedLeb128Size(registerNum); + } else { + this.length+=Leb128Utils.unsignedLeb128Size(registerNum); + } + if (nameIndex != -1) { + this.length+= + Leb128Utils.unsignedLeb128Size(referencedItems[referencedItemsPosition++].getIndex()+1); + } else { + this.length++; + } + if (typeIndex != -1) { + this.length+= + Leb128Utils.unsignedLeb128Size(referencedItems[referencedItemsPosition++].getIndex()+1); + } else { + this.length++; + } + + } + + @Override + public void ProcessStartLocalExtended(int startOffset, int length, int registerNum, int nameIndex, + int typeIndex, int signatureIndex, + boolean registerIsSigned) { + this.length++; + if (dexFile.getPreserveSignedRegisters() && registerIsSigned) { + this.length += Leb128Utils.signedLeb128Size(registerNum); + } else { + this.length+=Leb128Utils.unsignedLeb128Size(registerNum); + } + if (nameIndex != -1) { + this.length+= + Leb128Utils.unsignedLeb128Size(referencedItems[referencedItemsPosition++].getIndex()+1); + } else { + this.length++; + } + if (typeIndex != -1) { + this.length+= + Leb128Utils.unsignedLeb128Size(referencedItems[referencedItemsPosition++].getIndex()+1); + } else { + this.length++; + } + if (signatureIndex != -1) { + this.length+= + Leb128Utils.unsignedLeb128Size(referencedItems[referencedItemsPosition++].getIndex()+1); + } else { + this.length++; + } + } + + @Override + public void ProcessSetFile(int startOffset, int length, int nameIndex) { + this.length++; + if (nameIndex != -1) { + this.length+= + Leb128Utils.unsignedLeb128Size(referencedItems[referencedItemsPosition++].getIndex()+1); + } else { + this.length++; + } + } + }); + return offset + pdidwl.length; + } + + /** {@inheritDoc} */ + protected void writeItem(final AnnotatedOutput out) { + + if (out.annotates()) { + writeItemWithAnnotations(out); + } else { + writeItemWithNoAnnotations(out); + } + } + + /** + * Helper method that writes the item, without writing annotations + * @param out the AnnotatedOutput object + */ + private void writeItemWithNoAnnotations(final AnnotatedOutput out) { + out.writeUnsignedLeb128(lineStart); + out.writeUnsignedLeb128(parameterNames.length); + for (StringIdItem parameterName: parameterNames) { + int indexp1; + if (parameterName == null) { + indexp1 = 0; + } else { + indexp1 = parameterName.getIndex() + 1; + } + out.writeUnsignedLeb128(indexp1); + } + + DebugInstructionIterator.IterateInstructions(new ByteArrayInput(encodedDebugInfo), + new DebugInstructionIterator.ProcessRawDebugInstructionDelegate() { + private int referencedItemsPosition = 0; + + @Override + public void ProcessStaticOpcode(DebugOpcode opcode, int startOffset, int length) { + out.write(encodedDebugInfo, startOffset, length); + } + + @Override + public void ProcessStartLocal(int startOffset, int length, int registerNum, int nameIndex, + int typeIndex, boolean registerIsSigned) { + out.writeByte(DebugOpcode.DBG_START_LOCAL.value); + if (dexFile.getPreserveSignedRegisters() && registerIsSigned) { + out.writeSignedLeb128(registerNum); + } else { + out.writeUnsignedLeb128(registerNum); + } + if (nameIndex != -1) { + out.writeUnsignedLeb128(referencedItems[referencedItemsPosition++].getIndex() + 1); + } else { + out.writeByte(0); + } + if (typeIndex != -1) { + out.writeUnsignedLeb128(referencedItems[referencedItemsPosition++].getIndex() + 1); + } else { + out.writeByte(0); + } + } + + @Override + public void ProcessStartLocalExtended(int startOffset, int length, int registerNum, int nameIndex, + int typeIndex, int signatureIndex, + boolean registerIsSigned) { + out.writeByte(DebugOpcode.DBG_START_LOCAL_EXTENDED.value); + if (dexFile.getPreserveSignedRegisters() && registerIsSigned) { + out.writeSignedLeb128(registerNum); + } else { + out.writeUnsignedLeb128(registerNum); + } + if (nameIndex != -1) { + out.writeUnsignedLeb128(referencedItems[referencedItemsPosition++].getIndex() + 1); + } else { + out.writeByte(0); + } + if (typeIndex != -1) { + out.writeUnsignedLeb128(referencedItems[referencedItemsPosition++].getIndex() + 1); + } else { + out.writeByte(0); + } + if (signatureIndex != -1) { + out.writeUnsignedLeb128(referencedItems[referencedItemsPosition++].getIndex() + 1); + } else { + out.writeByte(0); + } + } + + @Override + public void ProcessSetFile(int startOffset, int length, int nameIndex) { + out.writeByte(DebugOpcode.DBG_SET_FILE.value); + if (nameIndex != -1) { + out.writeUnsignedLeb128(referencedItems[referencedItemsPosition++].getIndex() + 1); + } else { + out.writeByte(0); + } + } + }); + } + + /** + * Helper method that writes and annotates the item + * @param out the AnnotatedOutput object + */ + private void writeItemWithAnnotations(final AnnotatedOutput out) { + out.annotate(0, parent.getParent().method.getMethodString()); + out.annotate("line_start: 0x" + Integer.toHexString(lineStart) + " (" + lineStart + ")"); + out.writeUnsignedLeb128(lineStart); + out.annotate("parameters_size: 0x" + Integer.toHexString(parameterNames.length) + " (" + parameterNames.length + + ")"); + out.writeUnsignedLeb128(parameterNames.length); + int index = 0; + for (StringIdItem parameterName: parameterNames) { + int indexp1; + if (parameterName == null) { + out.annotate("[" + index++ +"] parameterName: "); + indexp1 = 0; + } else { + out.annotate("[" + index++ +"] parameterName: " + parameterName.getStringValue()); + indexp1 = parameterName.getIndex() + 1; + } + out.writeUnsignedLeb128(indexp1); + } + + DebugInstructionIterator.IterateInstructions(new ByteArrayInput(encodedDebugInfo), + new DebugInstructionIterator.ProcessRawDebugInstructionDelegate() { + private int referencedItemsPosition = 0; + + @Override + public void ProcessEndSequence(int startOffset) { + out.annotate("DBG_END_SEQUENCE"); + out.writeByte(DebugOpcode.DBG_END_SEQUENCE.value); + } + + @Override + public void ProcessAdvancePC(int startOffset, int length, int addressDiff) { + out.annotate("DBG_ADVANCE_PC"); + out.writeByte(DebugOpcode.DBG_ADVANCE_PC.value); + out.indent(); + out.annotate("addr_diff: 0x" + Integer.toHexString(addressDiff) + " (" + addressDiff + ")"); + out.writeUnsignedLeb128(addressDiff); + out.deindent(); + } + + @Override + public void ProcessAdvanceLine(int startOffset, int length, int lineDiff) { + out.annotate("DBG_ADVANCE_LINE"); + out.writeByte(DebugOpcode.DBG_ADVANCE_LINE.value); + out.indent(); + out.annotate("line_diff: 0x" + Integer.toHexString(lineDiff) + " (" + lineDiff + ")"); + out.writeSignedLeb128(lineDiff); + out.deindent(); + } + + @Override + public void ProcessStartLocal(int startOffset, int length, int registerNum, int nameIndex, + int typeIndex, boolean registerIsSigned) { + out.annotate("DBG_START_LOCAL"); + out.writeByte(DebugOpcode.DBG_START_LOCAL.value); + out.indent(); + out.annotate("register_num: 0x" + Integer.toHexString(registerNum) + " (" + registerNum + ")"); + if (dexFile.getPreserveSignedRegisters() && registerIsSigned) { + out.writeSignedLeb128(registerNum); + } else { + out.writeUnsignedLeb128(registerNum); + } + if (nameIndex != -1) { + Item nameItem = referencedItems[referencedItemsPosition++]; + assert nameItem instanceof StringIdItem; + out.annotate("name: " + ((StringIdItem)nameItem).getStringValue()); + out.writeUnsignedLeb128(nameItem.getIndex() + 1); + } else { + out.annotate("name: "); + out.writeByte(0); + } + if (typeIndex != -1) { + Item typeItem = referencedItems[referencedItemsPosition++]; + assert typeItem instanceof TypeIdItem; + out.annotate("type: " + ((TypeIdItem)typeItem).getTypeDescriptor()); + out.writeUnsignedLeb128(typeItem.getIndex() + 1); + } else { + out.annotate("type: "); + out.writeByte(0); + } + out.deindent(); + } + + @Override + public void ProcessStartLocalExtended(int startOffset, int length, int registerNum, int nameIndex, + int typeIndex, int signatureIndex, + boolean registerIsSigned) { + out.annotate("DBG_START_LOCAL_EXTENDED"); + out.writeByte(DebugOpcode.DBG_START_LOCAL_EXTENDED.value); + out.indent(); + out.annotate("register_num: 0x" + Integer.toHexString(registerNum) + " (" + registerNum + ")"); + if (dexFile.getPreserveSignedRegisters() && registerIsSigned) { + out.writeSignedLeb128(registerNum); + } else { + out.writeUnsignedLeb128(registerNum); + } + if (nameIndex != -1) { + Item nameItem = referencedItems[referencedItemsPosition++]; + assert nameItem instanceof StringIdItem; + out.annotate("name: " + ((StringIdItem)nameItem).getStringValue()); + out.writeUnsignedLeb128(nameItem.getIndex() + 1); + } else { + out.annotate("name: "); + out.writeByte(0); + } + if (typeIndex != -1) { + Item typeItem = referencedItems[referencedItemsPosition++]; + assert typeItem instanceof TypeIdItem; + out.annotate("type: " + ((TypeIdItem)typeItem).getTypeDescriptor()); + out.writeUnsignedLeb128(typeItem.getIndex() + 1); + } else { + out.annotate("type: "); + out.writeByte(0); + } + if (signatureIndex != -1) { + Item signatureItem = referencedItems[referencedItemsPosition++]; + assert signatureItem instanceof StringIdItem; + out.annotate("signature: " + ((StringIdItem)signatureItem).getStringValue()); + out.writeUnsignedLeb128(signatureItem.getIndex() + 1); + } else { + out.annotate("signature: "); + out.writeByte(0); + } + out.deindent(); + } + + @Override + public void ProcessEndLocal(int startOffset, int length, int registerNum, boolean registerIsSigned) { + out.annotate("DBG_END_LOCAL"); + out.writeByte(DebugOpcode.DBG_END_LOCAL.value); + out.annotate("register_num: 0x" + Integer.toHexString(registerNum) + " (" + registerNum + ")"); + if (registerIsSigned) { + out.writeSignedLeb128(registerNum); + } else { + out.writeUnsignedLeb128(registerNum); + } + } + + @Override + public void ProcessRestartLocal(int startOffset, int length, int registerNum, boolean registerIsSigned) { + out.annotate("DBG_RESTART_LOCAL"); + out.writeByte(DebugOpcode.DBG_RESTART_LOCAL.value); + out.annotate("register_num: 0x" + Integer.toHexString(registerNum) + " (" + registerNum + ")"); + if (registerIsSigned) { + out.writeSignedLeb128(registerNum); + } else { + out.writeUnsignedLeb128(registerNum); + } + } + + @Override + public void ProcessSetPrologueEnd(int startOffset) { + out.annotate("DBG_SET_PROLOGUE_END"); + out.writeByte(DebugOpcode.DBG_SET_PROLOGUE_END.value); + } + + @Override + public void ProcessSetEpilogueBegin(int startOffset) { + out.annotate("DBG_SET_EPILOGUE_BEGIN"); + out.writeByte(DebugOpcode.DBG_SET_EPILOGUE_BEGIN.value); + } + + @Override + public void ProcessSetFile(int startOffset, int length, int nameIndex) { + out.annotate("DBG_SET_FILE"); + out.writeByte(DebugOpcode.DBG_SET_FILE.value); + if (nameIndex != -1) { + Item sourceItem = referencedItems[referencedItemsPosition++]; + assert sourceItem instanceof StringIdItem; + out.annotate("source_file: \"" + ((StringIdItem)sourceItem).getStringValue() + "\""); + out.writeUnsignedLeb128(sourceItem.getIndex() + 1); + } else { + out.annotate("source_file: "); + out.writeByte(0); + } + } + + @Override + public void ProcessSpecialOpcode(int startOffset, int debugOpcode, int lineDiff, int addressDiff) { + out.annotate("DBG_SPECIAL_OPCODE: line_diff=0x" + Integer.toHexString(lineDiff) + "(" + + lineDiff +"),addressDiff=0x" + Integer.toHexString(addressDiff) + "(" + addressDiff + + ")"); + out.writeByte(debugOpcode); + } + }); + } + + + + + /** {@inheritDoc} */ + public ItemType getItemType() { + return ItemType.TYPE_DEBUG_INFO_ITEM; + } + + /** {@inheritDoc} */ + public String getConciseIdentity() { + return "debug_info_item @0x" + Integer.toHexString(getOffset()); + } + + /** {@inheritDoc} */ + public int compareTo(DebugInfoItem other) { + if (parent == null) { + if (other.parent == null) { + return 0; + } + return -1; + } + if (other.parent == null) { + return 1; + } + return parent.compareTo(other.parent); + } + + /** + * Set the CodeItem that this DebugInfoItem is associated with + * @param codeItem the CodeItem that this DebugInfoItem is associated with + */ + protected void setParent(CodeItem codeItem) { + this.parent = codeItem; + } + + /** + * @return the initial value for the line number register for the debug info machine + */ + public int getLineStart() { + return lineStart; + } + + /** + * @return the debug info, encoded as a byte array + */ + public byte[] getEncodedDebugInfo() { + return encodedDebugInfo; + } + + /** + * @return an array of the items referenced by instructions, in order of occurance in the encoded debug info + */ + public Item[] getReferencedItems() { + return referencedItems; + } + + /** + * @return an array of the names of the associated method's parameters. The array can be null if no parameter info + * is available, or any element can be null to indicate no info for that parameter + */ + public StringIdItem[] getParameterNames() { + return parameterNames; + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/DexFile.java b/dexlib/src/main/java/org/jf/dexlib/DexFile.java index 77a3a547..d3860237 100644 --- a/dexlib/src/main/java/org/jf/dexlib/DexFile.java +++ b/dexlib/src/main/java/org/jf/dexlib/DexFile.java @@ -1,846 +1,845 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib; - -import org.jf.dexlib.Util.*; -import org.jf.dexlib.*; -import org.jf.dexlib.Item; -import org.jf.dexlib.StringDataItem; - -import java.io.*; -import java.security.DigestException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.HashMap; -import java.util.Arrays; -import java.util.Comparator; -import java.util.Collections; -import java.util.zip.Adler32; -import java.util.zip.ZipFile; -import java.util.zip.ZipException; -import java.util.zip.ZipEntry; - -/** - *

Main use cases

- * - *

These are the main use cases that drove the design of this library

- * - *
    - *
  1. Annotate an existing dex file - In this case, the intent is to document the structure of - * an existing dex file. We want to be able to read in the dex file, and then write out a dex file - * that is exactly the same (while adding annotation information to an AnnotatedOutput object)

  2. - * - *
  3. Canonicalize an existing dex file - In this case, the intent is to rewrite an existing dex file - * so that it is in a canonical form. There is a certain amount of leeway in how various types of - * tems in a dex file are ordered or represented. It is sometimes useful to be able to easily - * compare a disassebled and reassembled dex file with the original dex file. If both dex-files are - * written canonically, they "should" match exactly, barring any explicit changes to the reassembled - * file.

    - * - *

    Currently, there are a couple of pieces of information that probably won't match exactly - *

      - *
    • the order of exception handlers in the EncodedCatchHandlerList for a method
    • - *
    • the ordering of some of the debug info in the {@link org.jf.dexlib.DebugInfoItem} for a method
    • - *

    - * - * - *

    Note that the above discrepancies should typically only be "intra-item" differences. They - * shouldn't change the size of the item, or affect how anything else is placed or laid out

  4. - * - *
  5. Creating a dex file from scratch - In this case, a blank dex file is created and then classes - * are added to it incrementally by calling the {@link org.jf.dexlib.Section#intern intern} method of - * {@link DexFile#ClassDefsSection}, which will add all the information necessary to represent the given - * class. For example, when assembling a dex file from a set of assembly text files.

    - * - *

    In this case, we can choose to write the dex file in a canonical form or not. It is somewhat - * slower to write it in a canonical format, due to the extra sorting and calculations that are - * required.

  6. - * - * - *
  7. Reading in the dex file - In this case, the intent is to read in a dex file and expose all the - * data to the calling application. For example, when disassembling a dex file into a text based - * assembly format, or doing other misc processing of the dex file.

  8. - * - * - *

    Other use cases

    - * - *

    These are other use cases that are possible, but did not drive the design of the library. - * No effort was made to test these use cases or ensure that they work. Some of these could - * probably be better achieved with a disassemble - modify - reassemble type process, using - * smali/baksmali or another assembler/disassembler pair that are compatible with each other

    - * - *
      - *
    • deleting classes/methods/etc. from a dex file
    • - *
    • merging 2 dex files
    • - *
    • splitting a dex file
    • - *
    • moving classes from 1 dex file to another
    • - *
    • removing the debug information from a dex file
    • - *
    • obfustication of a dex file
    • - *
    - */ -public class DexFile -{ - /** - * A mapping from ItemType to the section that contains items of the given type - */ - private final Section[] sectionsByType; - - /** - * Ordered lists of the indexed and offsetted sections. The order of these lists specifies the order - * that the sections will be written in - */ - private final IndexedSection[] indexedSections; - private final OffsettedSection[] offsettedSections; - - /** - * dalvik had a bug where it wrote the registers for certain types of debug info in a signed leb - * format, instead of an unsigned leb format. There are no negative registers of course, but - * certain positive values have a different encoding depending on whether they are encoded as - * an unsigned leb128 or a signed leb128. Specifically, the signed leb128 is 1 byte longer in some cases. - * - * This determine whether we should keep any signed registers as signed, or force all register to - * unsigned. By default we don't keep track of whether they were signed or not, and write them back - * out as unsigned. This option only has an effect when reading an existing dex file. It has no - * effect when a dex file is created from scratch - * - * The 2 main use-cases in play are - * 1. Annotate an existing dex file - In this case, preserveSignedRegisters should be false, so that we keep - * track of any signed registers and write them back out as signed Leb128 values. - * - * 2. Canonicalize an existing dex file - In this case, fixRegisters should be true, so that all - * registers in the debug info are written as unsigned Leb128 values regardless of how they were - * originally encoded - */ - private final boolean preserveSignedRegisters; - - /** - * When true, this prevents any sorting of the items during placement of the dex file. This - * should *only* be set to true when this dex file was read in from an existing (valid) dex file, - * and no modifications were made (i.e. no items added or deleted). Otherwise it is likely that - * an invalid dex file will be generated. - * - * This is useful for the first use case (annotating an existing dex file). This ensures the items - * retain the same order as in the original dex file. - */ - private boolean inplace = false; - - /** - * When true, this imposes an full ordering on all the items, to force them into a (possibly - * arbitrary) canonical order. When false, only the items that the dex format specifies - * an order for are sorted. The rest of the items are not ordered. - * - * This is useful for the second use case (canonicalizing an existing dex file) or possibly for - * the third use case (creating a dex file from scratch), if there is a need to write the new - * dex file in a canonical form. - */ - private boolean sortAllItems = false; - - - /** - * this is used to access the dex file from within inner classes, when they declare fields or - * variable that hide fields on this object - */ - private final DexFile dexFile = this; - - /** - * Is this file an odex file? This is only set when reading in an odex file - */ - private boolean isOdex = false; - - - private int dataOffset; - private int dataSize; - private int fileSize; - - private boolean disableInterning = false; - - - /** - * A private constructor containing common code to initialize the section maps and lists - * @param preserveSignedRegisters If true, keep track of any registers in the debug information - * that are signed, so they will be written in the same format. See - * getPreserveSignedRegisters() - */ - private DexFile(boolean preserveSignedRegisters) { - this.preserveSignedRegisters = preserveSignedRegisters; - - sectionsByType = new Section[] { - StringIdsSection, - TypeIdsSection, - ProtoIdsSection, - FieldIdsSection, - MethodIdsSection, - ClassDefsSection, - TypeListsSection, - AnnotationSetRefListsSection, - AnnotationSetsSection, - ClassDataSection, - CodeItemsSection, - AnnotationDirectoriesSection, - StringDataSection, - DebugInfoItemsSection, - AnnotationsSection, - EncodedArraysSection, - null, - null - }; - - indexedSections = new IndexedSection[] { - StringIdsSection, - TypeIdsSection, - ProtoIdsSection, - FieldIdsSection, - MethodIdsSection, - ClassDefsSection - }; - - offsettedSections = new OffsettedSection[] { - AnnotationSetRefListsSection, - AnnotationSetsSection, - CodeItemsSection, - AnnotationDirectoriesSection, - TypeListsSection, - StringDataSection, - AnnotationsSection, - EncodedArraysSection, - ClassDataSection, - DebugInfoItemsSection - }; - } - - - /** - * Construct a new DexFile instance by reading in the given dex file. - * @param file The dex file to read in - * @throws IOException if an IOException occurs - */ - public DexFile(String file) - throws IOException { - this(new File(file), true); - } - - /** - * Construct a new DexFile instance by reading in the given dex file, - * and optionally keep track of any registers in the debug information that are signed, - * so they will be written in the same format. - * @param file The dex file to read in - * @param preserveSignedRegisters If true, keep track of any registers in the debug information - * that are signed, so they will be written in the same format. See - * getPreserveSignedRegisters() - * @throws IOException if an IOException occurs - */ - public DexFile(String file, boolean preserveSignedRegisters) - throws IOException { - this(new File(file), preserveSignedRegisters); - } - - /** - * Construct a new DexFile instance by reading in the given dex file. - * @param file The dex file to read in - * @throws IOException if an IOException occurs - */ - public DexFile(File file) - throws IOException { - this(file, true); - } - - /** - * Construct a new DexFile instance by reading in the given dex file, - * and optionally keep track of any registers in the debug information that are signed, - * so they will be written in the same format. - * @param file The dex file to read in - * @param preserveSignedRegisters If true, keep track of any registers in the debug information - * that are signed, so they will be written in the same format. - * @see #getPreserveSignedRegisters - * @throws IOException if an IOException occurs - */ - public DexFile(File file, boolean preserveSignedRegisters) - throws IOException { - this(preserveSignedRegisters); - - long fileLength; - byte[] magic = FileUtils.readFile(file, 0, 8); - - InputStream inputStream = null; - Input in = null; - ZipFile zipFile = null; - - try { - //do we have a zip file? - if (magic[0] == 0x50 && magic[1] == 0x4B) { - zipFile = new ZipFile(file); - ZipEntry zipEntry = zipFile.getEntry("classes.dex"); - if (zipEntry == null) { - throw new RuntimeException("zip file " + file.getName() + " does not contain a classes.dex file"); - } - fileLength = zipEntry.getSize(); - if (fileLength < 40) { - throw new RuntimeException("The classes.dex file in " + file.getName() + " is too small to be a" + - " valid dex file"); - } else if (fileLength > Integer.MAX_VALUE) { - throw new RuntimeException("The classes.dex file in " + file.getName() + " is too large to read in"); - } - inputStream = new BufferedInputStream(zipFile.getInputStream(zipEntry)); - - inputStream.mark(8); - for (int i=0; i<8; i++) { - magic[i] = (byte)inputStream.read(); - } - inputStream.reset(); - } else { - fileLength = file.length(); - if (fileLength < 40) { - throw new RuntimeException(file.getName() + " is too small to be a valid dex file"); - } - if (fileLength < 40) { - throw new RuntimeException(file.getName() + " is too small to be a valid dex file"); - } else if (fileLength > Integer.MAX_VALUE) { - throw new RuntimeException(file.getName() + " is too large to read in"); - } - inputStream = new FileInputStream(file); - } - - byte[] dexMagic, odexMagic; - - dexMagic = org.jf.dexlib.HeaderItem.MAGIC; - odexMagic = OdexHeaderItem.MAGIC; - - boolean isDex = true; - this.isOdex = true; - for (int i=0; i<8; i++) { - if (magic[i] != dexMagic[i]) { - isDex = false; - } - if (magic[i] != odexMagic[i]) { - isOdex = false; - } - } - - if (isOdex) { - byte[] odexHeaderBytes = FileUtils.readStream(inputStream, 40); - Input odexHeaderIn = new ByteArrayInput(odexHeaderBytes); - OdexHeaderItem odexHeader = new OdexHeaderItem(odexHeaderIn); - - in = new ByteArrayInput(FileUtils.readStream(inputStream, odexHeader.dexLength)); - } else if (isDex) { - in = new ByteArrayInput(FileUtils.readStream(inputStream, (int)fileLength)); - } else { - StringBuffer sb = new StringBuffer("bad magic value:"); - for (int i=0; i<8; i++) { - sb.append(" "); - sb.append(Hex.u1(magic[i])); - } - throw new RuntimeException(sb.toString()); - } - } finally { - if (inputStream != null) { - inputStream.close(); - } - if (zipFile != null) { - zipFile.close(); - } - } - - ReadContext readContext = new ReadContext(this); - - HeaderItem.readFrom(in, 0, readContext); - - //the map offset was set while reading in the header item - int mapOffset = readContext.getSectionOffset(ItemType.TYPE_MAP_LIST); - - in.setCursor(mapOffset); - MapItem.readFrom(in, 0, readContext); - - for (Section section: sectionsByType) { - if (section == null) { - continue; - } - - int sectionOffset = readContext.getSectionOffset(section.ItemType); - if (sectionOffset > 0) { - int sectionSize = readContext.getSectionSize(section.ItemType); - in.setCursor(sectionOffset); - section.readFrom(sectionSize, in, readContext); - } - } - } - - /** - * Constructs a new, blank dex file. Classes can be added to this dex file by calling - * the Section.intern() method of ClassDefsSection - */ - public DexFile() { - this(true); - } - - /** - * Get the Section containing items of the same type as the given item - * @param item Get the Section that contains items of this type - * @param The specific item subclass - inferred from the passed item - * @return the Section containing items of the same type as the given item - */ - public Section getSectionForItem(T item) { - return (Section)sectionsByType[item.getItemType().SectionIndex]; - } - - /** - * Get the Section containing items of the given type - * @param itemType the type of item - * @return the Section containing items of the given type - */ - public Section getSectionForType(ItemType itemType) { - return sectionsByType[itemType.SectionIndex]; - } - - /** - * Get a boolean value indicating whether this dex file preserved any signed - * registers in the debug info as it read the dex file in. By default, the dex file - * doesn't check whether the registers are encoded as unsigned or signed values. - * - * This does *not* affect the actual register value that is read in. The value is - * read correctly regardless - * - * This does affect whether any signed registers will retain the same encoding or be - * forced to the (correct) unsigned encoding when the dex file is written back out. - * - * See the discussion about signed register values in the documentation for - * DexFile - * @return a boolean indicating whether this dex file preserved any signed registers - * as it was read in - */ - public boolean getPreserveSignedRegisters() { - return preserveSignedRegisters; - } - - /** - * Get a boolean value indicating whether all items should be placed into a - * (possibly arbitrary) "canonical" ordering. If false, then only the items - * that must be ordered per the dex specification are sorted. - * - * When true, writing the dex file involves somewhat more overhead - * - * If both SortAllItems and Inplace are true, Inplace takes precedence - * @return a boolean value indicating whether all items should be sorted - */ - public boolean getSortAllItems() { - return this.sortAllItems; - } - - /** - * Set a boolean value indicating whether all items should be placed into a - * (possibly arbitrary) "canonical" ordering. If false, then only the items - * that must be ordered per the dex specification are sorted. - * - * When true, writing the dex file involves somewhat more overhead - * - * If both SortAllItems and Inplace are true, Inplace takes precedence - * @param value a boolean value indicating whether all items should be sorted - */ - public void setSortAllItems(boolean value) { - this.sortAllItems = value; - } - - /** - * Disables adding new items to this dex file. The various getInterned*() type - * methods on individual items will return null if there isn't an existing item - * that matches - */ - public void disableInterning() { - this.disableInterning = true; - } - - /** - * @return a boolean value indicating whether interning new items has been disabled - * for this dex file - */ - public boolean getInterningDisabled() { - return disableInterning; - } - - /** - * @return a boolean value indicating whether this dex file was created by reading in an odex file - */ - public boolean isOdex() { - return this.isOdex; - } - - /** - * Get a boolean value indicating whether items in this dex file should be - * written back out "in-place", or whether the normal layout logic should be - * applied. - * - * This should only be used for a dex file that has been read from an existing - * dex file, and no modifications have been made to the dex file. Otherwise, - * there is a good chance that the resulting dex file will be invalid due to - * items that aren't placed correctly - * - * If both SortAllItems and Inplace are true, Inplace takes precedence - * @return a boolean value indicating whether items in this dex file should be - * written back out in-place. - */ - public boolean getInplace() { - return this.inplace; - } - - /** - * @return the size of the file, in bytes - */ - public int getFileSize() { - return fileSize; - } - - /** - * @return the size of the data section, in bytes - */ - public int getDataSize() { - return dataSize; - } - - /** - * @return the offset where the data section begins - */ - public int getDataOffset() { - return dataOffset; - } - - /** - * Set a boolean value indicating whether items in this dex file should be - * written back out "in-place", or whether the normal layout logic should be - * applied. - * - * This should only be used for a dex file that has been read from an existing - * dex file, and no modifications have been made to the dex file. Otherwise, - * there is a good chance that the resulting dex file will be invalid due to - * items that aren't placed correctly - * - * If both SortAllItems and Inplace are true, Inplace takes precedence - * @param value a boolean value indicating whether items in this dex file should be - * written back out in-place. - */ - public void setInplace(boolean value) { - this.inplace = value; - } - - /** - * Get an array of Section objects that are sorted by offset. - * @return an array of Section objects that are sorted by offset. - */ - protected Section[] getOrderedSections() { - int sectionCount = 0; - - for (Section section: sectionsByType) { - if (section != null && section.getItems().size() > 0) { - sectionCount++; - } - } - - Section[] sections = new Section[sectionCount]; - sectionCount = 0; - for (Section section: sectionsByType) { - if (section != null && section.getItems().size() > 0) { - sections[sectionCount++] = section; - } - } - - Arrays.sort(sections, new Comparator
    () { - public int compare(Section a, Section b) { - return a.getOffset() - b.getOffset(); - } - }); - - return sections; - } - - /** - * This method should be called before writing a dex file. It sorts the sections - * as needed or as indicated by getSortAllItems() and getInplace(), - * and then performs a pass through all of the items, finalizing the position (i.e. - * index and/or offset) of each item in the dex file. - * - * This step is needed primarily so that the indexes and offsets of all indexed and - * offsetted items are available when writing references to those items elsewhere. - */ - public void place() { - int offset = HeaderItem.placeAt(0, 0); - - int sectionsPosition = 0; - Section[] sections; - if (this.inplace) { - sections = this.getOrderedSections(); - } else { - sections = new Section[indexedSections.length + offsettedSections.length]; - System.arraycopy(indexedSections, 0, sections, 0, indexedSections.length); - System.arraycopy(offsettedSections, 0, sections, indexedSections.length, offsettedSections.length); - } - - while (sectionsPosition < sections.length && sections[sectionsPosition].ItemType.isIndexedItem()) { - Section section = sections[sectionsPosition]; - if (!this.inplace) { - section.sortSection(); - } - - offset = section.placeAt(offset); - - sectionsPosition++; - } - - dataOffset = offset; - - while (sectionsPosition < sections.length) { - Section section = sections[sectionsPosition]; - if (this.sortAllItems && !this.inplace) { - section.sortSection(); - } - offset = section.placeAt(offset); - - sectionsPosition++; - } - - - offset = AlignmentUtils.alignOffset(offset, ItemType.TYPE_MAP_LIST.ItemAlignment); - offset = MapItem.placeAt(offset, 0); - - fileSize = offset; - dataSize = offset - dataOffset; - } - - /** - * Writes the dex file to the give AnnotatedOutput object. If - * out.Annotates() is true, then annotations that document the format - * of the dex file are written. - * - * You must call place() on this dex file, before calling this method - * @param out the AnnotatedOutput object to write the dex file and annotations to - * - * After calling this method, you should call calcSignature() and - * then calcChecksum() on the resulting byte array, to calculate the - * signature and checksum in the header - */ - public void writeTo(AnnotatedOutput out) { - - out.annotate(0, "-----------------------------"); - out.annotate(0, "header item"); - out.annotate(0, "-----------------------------"); - out.annotate(0, " "); - HeaderItem.writeTo(out); - - out.annotate(0, " "); - - int sectionsPosition = 0; - Section[] sections; - if (this.inplace) { - sections = this.getOrderedSections(); - } else { - sections = new Section[indexedSections.length + offsettedSections.length]; - System.arraycopy(indexedSections, 0, sections, 0, indexedSections.length); - System.arraycopy(offsettedSections, 0, sections, indexedSections.length, offsettedSections.length); - } - - while (sectionsPosition < sections.length) { - sections[sectionsPosition].writeTo(out); - sectionsPosition++; - } - - out.alignTo(MapItem.getItemType().ItemAlignment); - - out.annotate(0, " "); - out.annotate(0, "-----------------------------"); - out.annotate(0, "map item"); - out.annotate(0, "-----------------------------"); - out.annotate(0, " "); - MapItem.writeTo(out); - } - - public final HeaderItem HeaderItem = new HeaderItem(this); - public final MapItem MapItem = new MapItem(this); - - /** - * The IndexedSection containing StringIdItem items - */ - public final IndexedSection StringIdsSection = - new IndexedSection(this, ItemType.TYPE_STRING_ID_ITEM); - - /** - * The IndexedSection containing TypeIdItem items - */ - public final IndexedSection TypeIdsSection = - new IndexedSection(this, ItemType.TYPE_TYPE_ID_ITEM); - - /** - * The IndexedSection containing ProtoIdItem items - */ - public final IndexedSection ProtoIdsSection = - new IndexedSection(this, ItemType.TYPE_PROTO_ID_ITEM); - - /** - * The IndexedSection containing FieldIdItem items - */ - public final IndexedSection FieldIdsSection = - new IndexedSection(this, ItemType.TYPE_FIELD_ID_ITEM); - - /** - * The IndexedSection containing MethodIdItem items - */ - public final IndexedSection MethodIdsSection = - new IndexedSection(this, ItemType.TYPE_METHOD_ID_ITEM); - - /** - * The IndexedSection containing ClassDefItem items - */ - public final IndexedSection ClassDefsSection = - new IndexedSection(this, ItemType.TYPE_CLASS_DEF_ITEM) { - - public int placeAt(int offset) { - if (dexFile.getInplace()) { - return super.placeAt(offset); - } - - int ret = ClassDefItem.placeClassDefItems(this, offset); - - Collections.sort(this.items, new Comparator() { - - public int compare(ClassDefItem a, ClassDefItem b) { - return a.getOffset() - b.getOffset(); - } - }); - - this.offset = items.get(0).getOffset(); - return ret; - } - }; - - /** - * The OffsettedSection containing TypeListItem items - */ - public final OffsettedSection TypeListsSection = - new OffsettedSection(this, ItemType.TYPE_TYPE_LIST); - - /** - * The OffsettedSection containing AnnotationSetRefList items - */ - public final OffsettedSection AnnotationSetRefListsSection = - new OffsettedSection(this, ItemType.TYPE_ANNOTATION_SET_REF_LIST); - - /** - * The OffsettedSection containing AnnotationSetItem items - */ - public final OffsettedSection AnnotationSetsSection = - new OffsettedSection(this, ItemType.TYPE_ANNOTATION_SET_ITEM); - - /** - * The OffsettedSection containing ClassDataItem items - */ - public final OffsettedSection ClassDataSection = - new OffsettedSection(this, ItemType.TYPE_CLASS_DATA_ITEM); - - /** - * The OffsettedSection containing CodeItem items - */ - public final OffsettedSection CodeItemsSection = - new OffsettedSection(this, ItemType.TYPE_CODE_ITEM); - - /** - * The OffsettedSection containing StringDataItem items - */ - public final OffsettedSection StringDataSection = - new OffsettedSection(this, ItemType.TYPE_STRING_DATA_ITEM); - - /** - * The OffsettedSection containing DebugInfoItem items - */ - public final OffsettedSection DebugInfoItemsSection = - new OffsettedSection(this, ItemType.TYPE_DEBUG_INFO_ITEM); - - /** - * The OffsettedSection containing AnnotationItem items - */ - public final OffsettedSection AnnotationsSection = - new OffsettedSection(this, ItemType.TYPE_ANNOTATION_ITEM); - - /** - * The OffsettedSection containing EncodedArrayItem items - */ - public final OffsettedSection EncodedArraysSection = - new OffsettedSection(this, ItemType.TYPE_ENCODED_ARRAY_ITEM); - - /** - * The OffsettedSection containing AnnotationDirectoryItem items - */ - public final OffsettedSection AnnotationDirectoriesSection = - new OffsettedSection(this, ItemType.TYPE_ANNOTATIONS_DIRECTORY_ITEM); - - - /** - * Calculates the signature for the dex file in the given byte array, - * and then writes the signature to the appropriate location in the header - * containing in the array - * - * @param bytes non-null; the bytes of the file - */ - public static void calcSignature(byte[] bytes) { - MessageDigest md; - - try { - md = MessageDigest.getInstance("SHA-1"); - } catch (NoSuchAlgorithmException ex) { - throw new RuntimeException(ex); - } - - md.update(bytes, 32, bytes.length - 32); - - try { - int amt = md.digest(bytes, 12, 20); - if (amt != 20) { - throw new RuntimeException("unexpected digest write: " + amt + - " bytes"); - } - } catch (DigestException ex) { - throw new RuntimeException(ex); - } - } - - /** - * Calculates the checksum for the .dex file in the - * given array, and modify the array to contain it. - * - * @param bytes non-null; the bytes of the file - */ - public static void calcChecksum(byte[] bytes) { - Adler32 a32 = new Adler32(); - - a32.update(bytes, 12, bytes.length - 12); - - int sum = (int) a32.getValue(); - - bytes[8] = (byte) sum; - bytes[9] = (byte) (sum >> 8); - bytes[10] = (byte) (sum >> 16); - bytes[11] = (byte) (sum >> 24); - } +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib; + +import org.jf.dexlib.Util.*; +import org.jf.dexlib.*; +import org.jf.dexlib.Item; +import org.jf.dexlib.StringDataItem; + +import java.io.*; +import java.security.DigestException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.HashMap; +import java.util.Arrays; +import java.util.Comparator; +import java.util.Collections; +import java.util.zip.Adler32; +import java.util.zip.ZipFile; +import java.util.zip.ZipException; +import java.util.zip.ZipEntry; + +/** + *

    Main use cases

    + * + *

    These are the main use cases that drove the design of this library

    + * + *
      + *
    1. Annotate an existing dex file - In this case, the intent is to document the structure of + * an existing dex file. We want to be able to read in the dex file, and then write out a dex file + * that is exactly the same (while adding annotation information to an AnnotatedOutput object)

    2. + * + *
    3. Canonicalize an existing dex file - In this case, the intent is to rewrite an existing dex file + * so that it is in a canonical form. There is a certain amount of leeway in how various types of + * tems in a dex file are ordered or represented. It is sometimes useful to be able to easily + * compare a disassebled and reassembled dex file with the original dex file. If both dex-files are + * written canonically, they "should" match exactly, barring any explicit changes to the reassembled + * file.

      + * + *

      Currently, there are a couple of pieces of information that probably won't match exactly + *

        + *
      • the order of exception handlers in the EncodedCatchHandlerList for a method
      • + *
      • the ordering of some of the debug info in the {@link org.jf.dexlib.DebugInfoItem} for a method
      • + *

      + * + * + *

      Note that the above discrepancies should typically only be "intra-item" differences. They + * shouldn't change the size of the item, or affect how anything else is placed or laid out

    4. + * + *
    5. Creating a dex file from scratch - In this case, a blank dex file is created and then classes + * are added to it incrementally by calling the {@link org.jf.dexlib.Section#intern intern} method of + * {@link DexFile#ClassDefsSection}, which will add all the information necessary to represent the given + * class. For example, when assembling a dex file from a set of assembly text files.

      + * + *

      In this case, we can choose to write the dex file in a canonical form or not. It is somewhat + * slower to write it in a canonical format, due to the extra sorting and calculations that are + * required.

    6. + * + * + *
    7. Reading in the dex file - In this case, the intent is to read in a dex file and expose all the + * data to the calling application. For example, when disassembling a dex file into a text based + * assembly format, or doing other misc processing of the dex file.

    8. + * + * + *

      Other use cases

      + * + *

      These are other use cases that are possible, but did not drive the design of the library. + * No effort was made to test these use cases or ensure that they work. Some of these could + * probably be better achieved with a disassemble - modify - reassemble type process, using + * smali/baksmali or another assembler/disassembler pair that are compatible with each other

      + * + *
        + *
      • deleting classes/methods/etc. from a dex file
      • + *
      • merging 2 dex files
      • + *
      • splitting a dex file
      • + *
      • moving classes from 1 dex file to another
      • + *
      • removing the debug information from a dex file
      • + *
      • obfustication of a dex file
      • + *
      + */ +public class DexFile +{ + /** + * A mapping from ItemType to the section that contains items of the given type + */ + private final Section[] sectionsByType; + + /** + * Ordered lists of the indexed and offsetted sections. The order of these lists specifies the order + * that the sections will be written in + */ + private final IndexedSection[] indexedSections; + private final OffsettedSection[] offsettedSections; + + /** + * dalvik had a bug where it wrote the registers for certain types of debug info in a signed leb + * format, instead of an unsigned leb format. There are no negative registers of course, but + * certain positive values have a different encoding depending on whether they are encoded as + * an unsigned leb128 or a signed leb128. Specifically, the signed leb128 is 1 byte longer in some cases. + * + * This determine whether we should keep any signed registers as signed, or force all register to + * unsigned. By default we don't keep track of whether they were signed or not, and write them back + * out as unsigned. This option only has an effect when reading an existing dex file. It has no + * effect when a dex file is created from scratch + * + * The 2 main use-cases in play are + * 1. Annotate an existing dex file - In this case, preserveSignedRegisters should be false, so that we keep + * track of any signed registers and write them back out as signed Leb128 values. + * + * 2. Canonicalize an existing dex file - In this case, fixRegisters should be true, so that all + * registers in the debug info are written as unsigned Leb128 values regardless of how they were + * originally encoded + */ + private final boolean preserveSignedRegisters; + + /** + * When true, this prevents any sorting of the items during placement of the dex file. This + * should *only* be set to true when this dex file was read in from an existing (valid) dex file, + * and no modifications were made (i.e. no items added or deleted). Otherwise it is likely that + * an invalid dex file will be generated. + * + * This is useful for the first use case (annotating an existing dex file). This ensures the items + * retain the same order as in the original dex file. + */ + private boolean inplace = false; + + /** + * When true, this imposes an full ordering on all the items, to force them into a (possibly + * arbitrary) canonical order. When false, only the items that the dex format specifies + * an order for are sorted. The rest of the items are not ordered. + * + * This is useful for the second use case (canonicalizing an existing dex file) or possibly for + * the third use case (creating a dex file from scratch), if there is a need to write the new + * dex file in a canonical form. + */ + private boolean sortAllItems = false; + + + /** + * this is used to access the dex file from within inner classes, when they declare fields or + * variable that hide fields on this object + */ + private final DexFile dexFile = this; + + /** + * Is this file an odex file? This is only set when reading in an odex file + */ + private boolean isOdex = false; + + + private int dataOffset; + private int dataSize; + private int fileSize; + + private boolean disableInterning = false; + + + /** + * A private constructor containing common code to initialize the section maps and lists + * @param preserveSignedRegisters If true, keep track of any registers in the debug information + * that are signed, so they will be written in the same format. See + * getPreserveSignedRegisters() + */ + private DexFile(boolean preserveSignedRegisters) { + this.preserveSignedRegisters = preserveSignedRegisters; + + sectionsByType = new Section[] { + StringIdsSection, + TypeIdsSection, + ProtoIdsSection, + FieldIdsSection, + MethodIdsSection, + ClassDefsSection, + TypeListsSection, + AnnotationSetRefListsSection, + AnnotationSetsSection, + ClassDataSection, + CodeItemsSection, + AnnotationDirectoriesSection, + StringDataSection, + DebugInfoItemsSection, + AnnotationsSection, + EncodedArraysSection, + null, + null + }; + + indexedSections = new IndexedSection[] { + StringIdsSection, + TypeIdsSection, + ProtoIdsSection, + FieldIdsSection, + MethodIdsSection, + ClassDefsSection + }; + + offsettedSections = new OffsettedSection[] { + AnnotationSetRefListsSection, + AnnotationSetsSection, + CodeItemsSection, + AnnotationDirectoriesSection, + TypeListsSection, + StringDataSection, + AnnotationsSection, + EncodedArraysSection, + ClassDataSection, + DebugInfoItemsSection + }; + } + + + /** + * Construct a new DexFile instance by reading in the given dex file. + * @param file The dex file to read in + * @throws IOException if an IOException occurs + */ + public DexFile(String file) + throws IOException { + this(new File(file), true); + } + + /** + * Construct a new DexFile instance by reading in the given dex file, + * and optionally keep track of any registers in the debug information that are signed, + * so they will be written in the same format. + * @param file The dex file to read in + * @param preserveSignedRegisters If true, keep track of any registers in the debug information + * that are signed, so they will be written in the same format. See + * getPreserveSignedRegisters() + * @throws IOException if an IOException occurs + */ + public DexFile(String file, boolean preserveSignedRegisters) + throws IOException { + this(new File(file), preserveSignedRegisters); + } + + /** + * Construct a new DexFile instance by reading in the given dex file. + * @param file The dex file to read in + * @throws IOException if an IOException occurs + */ + public DexFile(File file) + throws IOException { + this(file, true); + } + + /** + * Construct a new DexFile instance by reading in the given dex file, + * and optionally keep track of any registers in the debug information that are signed, + * so they will be written in the same format. + * @param file The dex file to read in + * @param preserveSignedRegisters If true, keep track of any registers in the debug information + * that are signed, so they will be written in the same format. + * @see #getPreserveSignedRegisters + * @throws IOException if an IOException occurs + */ + public DexFile(File file, boolean preserveSignedRegisters) + throws IOException { + this(preserveSignedRegisters); + + long fileLength; + byte[] magic = FileUtils.readFile(file, 0, 8); + + InputStream inputStream = null; + Input in = null; + ZipFile zipFile = null; + + try { + //do we have a zip file? + if (magic[0] == 0x50 && magic[1] == 0x4B) { + zipFile = new ZipFile(file); + ZipEntry zipEntry = zipFile.getEntry("classes.dex"); + if (zipEntry == null) { + throw new RuntimeException("zip file " + file.getName() + " does not contain a classes.dex file"); + } + fileLength = zipEntry.getSize(); + if (fileLength < 40) { + throw new RuntimeException("The classes.dex file in " + file.getName() + " is too small to be a" + + " valid dex file"); + } else if (fileLength > Integer.MAX_VALUE) { + throw new RuntimeException("The classes.dex file in " + file.getName() + " is too large to read in"); + } + inputStream = new BufferedInputStream(zipFile.getInputStream(zipEntry)); + + inputStream.mark(8); + for (int i=0; i<8; i++) { + magic[i] = (byte)inputStream.read(); + } + inputStream.reset(); + } else { + fileLength = file.length(); + if (fileLength < 40) { + throw new RuntimeException(file.getName() + " is too small to be a valid dex file"); + } + if (fileLength < 40) { + throw new RuntimeException(file.getName() + " is too small to be a valid dex file"); + } else if (fileLength > Integer.MAX_VALUE) { + throw new RuntimeException(file.getName() + " is too large to read in"); + } + inputStream = new FileInputStream(file); + } + + byte[] dexMagic, odexMagic; + + dexMagic = org.jf.dexlib.HeaderItem.MAGIC; + odexMagic = OdexHeaderItem.MAGIC; + + boolean isDex = true; + this.isOdex = true; + for (int i=0; i<8; i++) { + if (magic[i] != dexMagic[i]) { + isDex = false; + } + if (magic[i] != odexMagic[i]) { + isOdex = false; + } + } + + if (isOdex) { + byte[] odexHeaderBytes = FileUtils.readStream(inputStream, 40); + Input odexHeaderIn = new ByteArrayInput(odexHeaderBytes); + OdexHeaderItem odexHeader = new OdexHeaderItem(odexHeaderIn); + + in = new ByteArrayInput(FileUtils.readStream(inputStream, odexHeader.dexLength)); + } else if (isDex) { + in = new ByteArrayInput(FileUtils.readStream(inputStream, (int)fileLength)); + } else { + StringBuffer sb = new StringBuffer("bad magic value:"); + for (int i=0; i<8; i++) { + sb.append(" "); + sb.append(Hex.u1(magic[i])); + } + throw new RuntimeException(sb.toString()); + } + } finally { + if (inputStream != null) { + inputStream.close(); + } + if (zipFile != null) { + zipFile.close(); + } + } + + ReadContext readContext = new ReadContext(this); + + HeaderItem.readFrom(in, 0, readContext); + + //the map offset was set while reading in the header item + int mapOffset = readContext.getSectionOffset(ItemType.TYPE_MAP_LIST); + + in.setCursor(mapOffset); + MapItem.readFrom(in, 0, readContext); + + for (Section section: sectionsByType) { + if (section == null) { + continue; + } + + int sectionOffset = readContext.getSectionOffset(section.ItemType); + if (sectionOffset > 0) { + int sectionSize = readContext.getSectionSize(section.ItemType); + in.setCursor(sectionOffset); + section.readFrom(sectionSize, in, readContext); + } + } + } + + /** + * Constructs a new, blank dex file. Classes can be added to this dex file by calling + * the Section.intern() method of ClassDefsSection + */ + public DexFile() { + this(true); + } + + /** + * Get the Section containing items of the same type as the given item + * @param item Get the Section that contains items of this type + * @param The specific item subclass - inferred from the passed item + * @return the Section containing items of the same type as the given item + */ + public Section getSectionForItem(T item) { + return (Section)sectionsByType[item.getItemType().SectionIndex]; + } + + /** + * Get the Section containing items of the given type + * @param itemType the type of item + * @return the Section containing items of the given type + */ + public Section getSectionForType(ItemType itemType) { + return sectionsByType[itemType.SectionIndex]; + } + + /** + * Get a boolean value indicating whether this dex file preserved any signed + * registers in the debug info as it read the dex file in. By default, the dex file + * doesn't check whether the registers are encoded as unsigned or signed values. + * + * This does *not* affect the actual register value that is read in. The value is + * read correctly regardless + * + * This does affect whether any signed registers will retain the same encoding or be + * forced to the (correct) unsigned encoding when the dex file is written back out. + * + * See the discussion about signed register values in the documentation for + * DexFile + * @return a boolean indicating whether this dex file preserved any signed registers + * as it was read in + */ + public boolean getPreserveSignedRegisters() { + return preserveSignedRegisters; + } + + /** + * Get a boolean value indicating whether all items should be placed into a + * (possibly arbitrary) "canonical" ordering. If false, then only the items + * that must be ordered per the dex specification are sorted. + * + * When true, writing the dex file involves somewhat more overhead + * + * If both SortAllItems and Inplace are true, Inplace takes precedence + * @return a boolean value indicating whether all items should be sorted + */ + public boolean getSortAllItems() { + return this.sortAllItems; + } + + /** + * Set a boolean value indicating whether all items should be placed into a + * (possibly arbitrary) "canonical" ordering. If false, then only the items + * that must be ordered per the dex specification are sorted. + * + * When true, writing the dex file involves somewhat more overhead + * + * If both SortAllItems and Inplace are true, Inplace takes precedence + * @param value a boolean value indicating whether all items should be sorted + */ + public void setSortAllItems(boolean value) { + this.sortAllItems = value; + } + + /** + * Disables adding new items to this dex file. The various getInterned*() type + * methods on individual items will return null if there isn't an existing item + * that matches + */ + public void disableInterning() { + this.disableInterning = true; + } + + /** + * @return a boolean value indicating whether interning new items has been disabled + * for this dex file + */ + public boolean getInterningDisabled() { + return disableInterning; + } + + /** + * @return a boolean value indicating whether this dex file was created by reading in an odex file + */ + public boolean isOdex() { + return this.isOdex; + } + + /** + * Get a boolean value indicating whether items in this dex file should be + * written back out "in-place", or whether the normal layout logic should be + * applied. + * + * This should only be used for a dex file that has been read from an existing + * dex file, and no modifications have been made to the dex file. Otherwise, + * there is a good chance that the resulting dex file will be invalid due to + * items that aren't placed correctly + * + * If both SortAllItems and Inplace are true, Inplace takes precedence + * @return a boolean value indicating whether items in this dex file should be + * written back out in-place. + */ + public boolean getInplace() { + return this.inplace; + } + + /** + * @return the size of the file, in bytes + */ + public int getFileSize() { + return fileSize; + } + + /** + * @return the size of the data section, in bytes + */ + public int getDataSize() { + return dataSize; + } + + /** + * @return the offset where the data section begins + */ + public int getDataOffset() { + return dataOffset; + } + + /** + * Set a boolean value indicating whether items in this dex file should be + * written back out "in-place", or whether the normal layout logic should be + * applied. + * + * This should only be used for a dex file that has been read from an existing + * dex file, and no modifications have been made to the dex file. Otherwise, + * there is a good chance that the resulting dex file will be invalid due to + * items that aren't placed correctly + * + * If both SortAllItems and Inplace are true, Inplace takes precedence + * @param value a boolean value indicating whether items in this dex file should be + * written back out in-place. + */ + public void setInplace(boolean value) { + this.inplace = value; + } + + /** + * Get an array of Section objects that are sorted by offset. + * @return an array of Section objects that are sorted by offset. + */ + protected Section[] getOrderedSections() { + int sectionCount = 0; + + for (Section section: sectionsByType) { + if (section != null && section.getItems().size() > 0) { + sectionCount++; + } + } + + Section[] sections = new Section[sectionCount]; + sectionCount = 0; + for (Section section: sectionsByType) { + if (section != null && section.getItems().size() > 0) { + sections[sectionCount++] = section; + } + } + + Arrays.sort(sections, new Comparator
      () { + public int compare(Section a, Section b) { + return a.getOffset() - b.getOffset(); + } + }); + + return sections; + } + + /** + * This method should be called before writing a dex file. It sorts the sections + * as needed or as indicated by getSortAllItems() and getInplace(), + * and then performs a pass through all of the items, finalizing the position (i.e. + * index and/or offset) of each item in the dex file. + * + * This step is needed primarily so that the indexes and offsets of all indexed and + * offsetted items are available when writing references to those items elsewhere. + */ + public void place() { + int offset = HeaderItem.placeAt(0, 0); + + int sectionsPosition = 0; + Section[] sections; + if (this.inplace) { + sections = this.getOrderedSections(); + } else { + sections = new Section[indexedSections.length + offsettedSections.length]; + System.arraycopy(indexedSections, 0, sections, 0, indexedSections.length); + System.arraycopy(offsettedSections, 0, sections, indexedSections.length, offsettedSections.length); + } + + while (sectionsPosition < sections.length && sections[sectionsPosition].ItemType.isIndexedItem()) { + Section section = sections[sectionsPosition]; + if (!this.inplace) { + section.sortSection(); + } + + offset = section.placeAt(offset); + + sectionsPosition++; + } + + dataOffset = offset; + + while (sectionsPosition < sections.length) { + Section section = sections[sectionsPosition]; + if (this.sortAllItems && !this.inplace) { + section.sortSection(); + } + offset = section.placeAt(offset); + + sectionsPosition++; + } + + offset = AlignmentUtils.alignOffset(offset, ItemType.TYPE_MAP_LIST.ItemAlignment); + offset = MapItem.placeAt(offset, 0); + + fileSize = offset; + dataSize = offset - dataOffset; + } + + /** + * Writes the dex file to the give AnnotatedOutput object. If + * out.Annotates() is true, then annotations that document the format + * of the dex file are written. + * + * You must call place() on this dex file, before calling this method + * @param out the AnnotatedOutput object to write the dex file and annotations to + * + * After calling this method, you should call calcSignature() and + * then calcChecksum() on the resulting byte array, to calculate the + * signature and checksum in the header + */ + public void writeTo(AnnotatedOutput out) { + + out.annotate(0, "-----------------------------"); + out.annotate(0, "header item"); + out.annotate(0, "-----------------------------"); + out.annotate(0, " "); + HeaderItem.writeTo(out); + + out.annotate(0, " "); + + int sectionsPosition = 0; + Section[] sections; + if (this.inplace) { + sections = this.getOrderedSections(); + } else { + sections = new Section[indexedSections.length + offsettedSections.length]; + System.arraycopy(indexedSections, 0, sections, 0, indexedSections.length); + System.arraycopy(offsettedSections, 0, sections, indexedSections.length, offsettedSections.length); + } + + while (sectionsPosition < sections.length) { + sections[sectionsPosition].writeTo(out); + sectionsPosition++; + } + + out.alignTo(MapItem.getItemType().ItemAlignment); + + out.annotate(0, " "); + out.annotate(0, "-----------------------------"); + out.annotate(0, "map item"); + out.annotate(0, "-----------------------------"); + out.annotate(0, " "); + MapItem.writeTo(out); + } + + public final HeaderItem HeaderItem = new HeaderItem(this); + public final MapItem MapItem = new MapItem(this); + + /** + * The IndexedSection containing StringIdItem items + */ + public final IndexedSection StringIdsSection = + new IndexedSection(this, ItemType.TYPE_STRING_ID_ITEM); + + /** + * The IndexedSection containing TypeIdItem items + */ + public final IndexedSection TypeIdsSection = + new IndexedSection(this, ItemType.TYPE_TYPE_ID_ITEM); + + /** + * The IndexedSection containing ProtoIdItem items + */ + public final IndexedSection ProtoIdsSection = + new IndexedSection(this, ItemType.TYPE_PROTO_ID_ITEM); + + /** + * The IndexedSection containing FieldIdItem items + */ + public final IndexedSection FieldIdsSection = + new IndexedSection(this, ItemType.TYPE_FIELD_ID_ITEM); + + /** + * The IndexedSection containing MethodIdItem items + */ + public final IndexedSection MethodIdsSection = + new IndexedSection(this, ItemType.TYPE_METHOD_ID_ITEM); + + /** + * The IndexedSection containing ClassDefItem items + */ + public final IndexedSection ClassDefsSection = + new IndexedSection(this, ItemType.TYPE_CLASS_DEF_ITEM) { + + public int placeAt(int offset) { + if (dexFile.getInplace()) { + return super.placeAt(offset); + } + + int ret = ClassDefItem.placeClassDefItems(this, offset); + + Collections.sort(this.items, new Comparator() { + + public int compare(ClassDefItem a, ClassDefItem b) { + return a.getOffset() - b.getOffset(); + } + }); + + this.offset = items.get(0).getOffset(); + return ret; + } + }; + + /** + * The OffsettedSection containing TypeListItem items + */ + public final OffsettedSection TypeListsSection = + new OffsettedSection(this, ItemType.TYPE_TYPE_LIST); + + /** + * The OffsettedSection containing AnnotationSetRefList items + */ + public final OffsettedSection AnnotationSetRefListsSection = + new OffsettedSection(this, ItemType.TYPE_ANNOTATION_SET_REF_LIST); + + /** + * The OffsettedSection containing AnnotationSetItem items + */ + public final OffsettedSection AnnotationSetsSection = + new OffsettedSection(this, ItemType.TYPE_ANNOTATION_SET_ITEM); + + /** + * The OffsettedSection containing ClassDataItem items + */ + public final OffsettedSection ClassDataSection = + new OffsettedSection(this, ItemType.TYPE_CLASS_DATA_ITEM); + + /** + * The OffsettedSection containing CodeItem items + */ + public final OffsettedSection CodeItemsSection = + new OffsettedSection(this, ItemType.TYPE_CODE_ITEM); + + /** + * The OffsettedSection containing StringDataItem items + */ + public final OffsettedSection StringDataSection = + new OffsettedSection(this, ItemType.TYPE_STRING_DATA_ITEM); + + /** + * The OffsettedSection containing DebugInfoItem items + */ + public final OffsettedSection DebugInfoItemsSection = + new OffsettedSection(this, ItemType.TYPE_DEBUG_INFO_ITEM); + + /** + * The OffsettedSection containing AnnotationItem items + */ + public final OffsettedSection AnnotationsSection = + new OffsettedSection(this, ItemType.TYPE_ANNOTATION_ITEM); + + /** + * The OffsettedSection containing EncodedArrayItem items + */ + public final OffsettedSection EncodedArraysSection = + new OffsettedSection(this, ItemType.TYPE_ENCODED_ARRAY_ITEM); + + /** + * The OffsettedSection containing AnnotationDirectoryItem items + */ + public final OffsettedSection AnnotationDirectoriesSection = + new OffsettedSection(this, ItemType.TYPE_ANNOTATIONS_DIRECTORY_ITEM); + + + /** + * Calculates the signature for the dex file in the given byte array, + * and then writes the signature to the appropriate location in the header + * containing in the array + * + * @param bytes non-null; the bytes of the file + */ + public static void calcSignature(byte[] bytes) { + MessageDigest md; + + try { + md = MessageDigest.getInstance("SHA-1"); + } catch (NoSuchAlgorithmException ex) { + throw new RuntimeException(ex); + } + + md.update(bytes, 32, bytes.length - 32); + + try { + int amt = md.digest(bytes, 12, 20); + if (amt != 20) { + throw new RuntimeException("unexpected digest write: " + amt + + " bytes"); + } + } catch (DigestException ex) { + throw new RuntimeException(ex); + } + } + + /** + * Calculates the checksum for the .dex file in the + * given array, and modify the array to contain it. + * + * @param bytes non-null; the bytes of the file + */ + public static void calcChecksum(byte[] bytes) { + Adler32 a32 = new Adler32(); + + a32.update(bytes, 12, bytes.length - 12); + + int sum = (int) a32.getValue(); + + bytes[8] = (byte) sum; + bytes[9] = (byte) (sum >> 8); + bytes[10] = (byte) (sum >> 16); + bytes[11] = (byte) (sum >> 24); + } } \ No newline at end of file diff --git a/dexlib/src/main/java/org/jf/dexlib/EncodedArrayItem.java b/dexlib/src/main/java/org/jf/dexlib/EncodedArrayItem.java index 845b2494..99ef6cc7 100644 --- a/dexlib/src/main/java/org/jf/dexlib/EncodedArrayItem.java +++ b/dexlib/src/main/java/org/jf/dexlib/EncodedArrayItem.java @@ -1,135 +1,135 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib; - -import org.jf.dexlib.EncodedValue.ArrayEncodedSubValue; -import org.jf.dexlib.Util.Input; -import org.jf.dexlib.Util.AnnotatedOutput; - -public class EncodedArrayItem extends Item { - private int hashCode = 0; - - private ArrayEncodedSubValue encodedArray; - - /** - * Creates a new uninitialized EncodedArrayItem - * @param dexFile The DexFile that this item belongs to - */ - protected EncodedArrayItem(DexFile dexFile) { - super(dexFile); - } - - /** - * Creates a new EncodedArrayItem with the given values - * @param dexFile The DexFile that this item belongs to - * @param encodedArray The encoded array value - */ - private EncodedArrayItem(DexFile dexFile, ArrayEncodedSubValue encodedArray) { - super(dexFile); - this.encodedArray = encodedArray; - } - - /** - * Returns an EncodedArrayItem for the given values, and that has been interned into the given - * DexFile - * @param dexFile The DexFile that this item belongs to - * @param encodedArray The encoded array value - * @return an EncodedArrayItem for the given values, and that has been interned into the given - */ - public static EncodedArrayItem getInternedEncodedArrayItem(DexFile dexFile, ArrayEncodedSubValue encodedArray) { - EncodedArrayItem encodedArrayItem = new EncodedArrayItem(dexFile, encodedArray); - return dexFile.EncodedArraysSection.intern(encodedArrayItem); - } - - /** {@inheritDoc} */ - protected void readItem(Input in, ReadContext readContext) { - encodedArray = new ArrayEncodedSubValue(dexFile, in); - } - - /** {@inheritDoc} */ - protected int placeItem(int offset) { - return encodedArray.placeValue(offset); - } - - /** {@inheritDoc} */ - protected void writeItem(AnnotatedOutput out) { - encodedArray.writeValue(out); - } - - /** {@inheritDoc} */ - public ItemType getItemType() { - return ItemType.TYPE_ENCODED_ARRAY_ITEM; - } - - /** {@inheritDoc} */ - public String getConciseIdentity() { - return "encoded_array @0x" + Integer.toHexString(getOffset()); - } - - /** {@inheritDoc} */ - public int compareTo(EncodedArrayItem encodedArrayItem) { - return encodedArray.compareTo(encodedArrayItem.encodedArray); - } - - /** - * @return The encoded array value - */ - public ArrayEncodedSubValue getEncodedArray() { - return encodedArray; - } - - /** - * calculate and cache the hashcode - */ - private void calcHashCode() { - hashCode = encodedArray.hashCode(); - } - - @Override - public int hashCode() { - //there's a small possibility that the actual hash code will be 0. If so, we'll - //just end up recalculating it each time - if (hashCode == 0) - calcHashCode(); - return hashCode; - } - - @Override - public boolean equals(Object o) { - if (this==o) { - return true; - } - if (o==null || !this.getClass().equals(o.getClass())) { - return false; - } - - EncodedArrayItem other = (EncodedArrayItem)o; - return (encodedArray.compareTo(other.encodedArray) == 0); - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib; + +import org.jf.dexlib.EncodedValue.ArrayEncodedSubValue; +import org.jf.dexlib.Util.Input; +import org.jf.dexlib.Util.AnnotatedOutput; + +public class EncodedArrayItem extends Item { + private int hashCode = 0; + + private ArrayEncodedSubValue encodedArray; + + /** + * Creates a new uninitialized EncodedArrayItem + * @param dexFile The DexFile that this item belongs to + */ + protected EncodedArrayItem(DexFile dexFile) { + super(dexFile); + } + + /** + * Creates a new EncodedArrayItem with the given values + * @param dexFile The DexFile that this item belongs to + * @param encodedArray The encoded array value + */ + private EncodedArrayItem(DexFile dexFile, ArrayEncodedSubValue encodedArray) { + super(dexFile); + this.encodedArray = encodedArray; + } + + /** + * Returns an EncodedArrayItem for the given values, and that has been interned into the given + * DexFile + * @param dexFile The DexFile that this item belongs to + * @param encodedArray The encoded array value + * @return an EncodedArrayItem for the given values, and that has been interned into the given + */ + public static EncodedArrayItem getInternedEncodedArrayItem(DexFile dexFile, ArrayEncodedSubValue encodedArray) { + EncodedArrayItem encodedArrayItem = new EncodedArrayItem(dexFile, encodedArray); + return dexFile.EncodedArraysSection.intern(encodedArrayItem); + } + + /** {@inheritDoc} */ + protected void readItem(Input in, ReadContext readContext) { + encodedArray = new ArrayEncodedSubValue(dexFile, in); + } + + /** {@inheritDoc} */ + protected int placeItem(int offset) { + return encodedArray.placeValue(offset); + } + + /** {@inheritDoc} */ + protected void writeItem(AnnotatedOutput out) { + encodedArray.writeValue(out); + } + + /** {@inheritDoc} */ + public ItemType getItemType() { + return ItemType.TYPE_ENCODED_ARRAY_ITEM; + } + + /** {@inheritDoc} */ + public String getConciseIdentity() { + return "encoded_array @0x" + Integer.toHexString(getOffset()); + } + + /** {@inheritDoc} */ + public int compareTo(EncodedArrayItem encodedArrayItem) { + return encodedArray.compareTo(encodedArrayItem.encodedArray); + } + + /** + * @return The encoded array value + */ + public ArrayEncodedSubValue getEncodedArray() { + return encodedArray; + } + + /** + * calculate and cache the hashcode + */ + private void calcHashCode() { + hashCode = encodedArray.hashCode(); + } + + @Override + public int hashCode() { + //there's a small possibility that the actual hash code will be 0. If so, we'll + //just end up recalculating it each time + if (hashCode == 0) + calcHashCode(); + return hashCode; + } + + @Override + public boolean equals(Object o) { + if (this==o) { + return true; + } + if (o==null || !this.getClass().equals(o.getClass())) { + return false; + } + + EncodedArrayItem other = (EncodedArrayItem)o; + return (encodedArray.compareTo(other.encodedArray) == 0); + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/EncodedValue/ValueType.java b/dexlib/src/main/java/org/jf/dexlib/EncodedValue/ValueType.java index a0729c2f..9c02b48d 100644 --- a/dexlib/src/main/java/org/jf/dexlib/EncodedValue/ValueType.java +++ b/dexlib/src/main/java/org/jf/dexlib/EncodedValue/ValueType.java @@ -1,86 +1,86 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.EncodedValue; - -import org.jf.dexlib.Util.SparseArray; - -public enum ValueType { - - VALUE_BYTE((byte) 0x00), - VALUE_SHORT((byte) 0x02), - VALUE_CHAR((byte) 0x03), - VALUE_INT((byte) 0x04), - VALUE_LONG((byte) 0x06), - VALUE_FLOAT((byte) 0x10), - VALUE_DOUBLE((byte) 0x11), - VALUE_STRING((byte) 0x17), - VALUE_TYPE((byte) 0x18), - VALUE_FIELD((byte) 0x19), - VALUE_METHOD((byte) 0x1a), - VALUE_ENUM((byte) 0x1b), - VALUE_ARRAY((byte) 0x1c), - VALUE_ANNOTATION((byte) 0x1d), - VALUE_NULL((byte) 0x1e), - VALUE_BOOLEAN((byte) 0x1f); - - /** - * A map to facilitate looking up a ValueType by byte value - */ - private final static SparseArray valueTypeIntegerMap; - - static { - /** build the valueTypeIntegerMap object */ - valueTypeIntegerMap = new SparseArray(16); - - for (ValueType valueType : ValueType.values()) { - valueTypeIntegerMap.put(valueType.value, valueType); - } - } - - /** - * The byte value for this ValueType - */ - public final byte value; - - private ValueType(byte value) { - this.value = value; - } - - /** - * Converts a byte value to the corresponding ValueType enum value, - * or null if the value isn't a valid ValueType value - * - * @param valueType the byte value to convert to a ValueType - * @return the ValueType enum value corresponding to valueType, or null - * if not a valid ValueType value - */ - public static ValueType fromByte(byte valueType) { - return valueTypeIntegerMap.get(valueType); - } +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.EncodedValue; + +import org.jf.dexlib.Util.SparseArray; + +public enum ValueType { + + VALUE_BYTE((byte) 0x00), + VALUE_SHORT((byte) 0x02), + VALUE_CHAR((byte) 0x03), + VALUE_INT((byte) 0x04), + VALUE_LONG((byte) 0x06), + VALUE_FLOAT((byte) 0x10), + VALUE_DOUBLE((byte) 0x11), + VALUE_STRING((byte) 0x17), + VALUE_TYPE((byte) 0x18), + VALUE_FIELD((byte) 0x19), + VALUE_METHOD((byte) 0x1a), + VALUE_ENUM((byte) 0x1b), + VALUE_ARRAY((byte) 0x1c), + VALUE_ANNOTATION((byte) 0x1d), + VALUE_NULL((byte) 0x1e), + VALUE_BOOLEAN((byte) 0x1f); + + /** + * A map to facilitate looking up a ValueType by byte value + */ + private final static SparseArray valueTypeIntegerMap; + + static { + /** build the valueTypeIntegerMap object */ + valueTypeIntegerMap = new SparseArray(16); + + for (ValueType valueType : ValueType.values()) { + valueTypeIntegerMap.put(valueType.value, valueType); + } + } + + /** + * The byte value for this ValueType + */ + public final byte value; + + private ValueType(byte value) { + this.value = value; + } + + /** + * Converts a byte value to the corresponding ValueType enum value, + * or null if the value isn't a valid ValueType value + * + * @param valueType the byte value to convert to a ValueType + * @return the ValueType enum value corresponding to valueType, or null + * if not a valid ValueType value + */ + public static ValueType fromByte(byte valueType) { + return valueTypeIntegerMap.get(valueType); + } } \ No newline at end of file diff --git a/dexlib/src/main/java/org/jf/dexlib/FieldIdItem.java b/dexlib/src/main/java/org/jf/dexlib/FieldIdItem.java index 7160fa00..8c9245ac 100644 --- a/dexlib/src/main/java/org/jf/dexlib/FieldIdItem.java +++ b/dexlib/src/main/java/org/jf/dexlib/FieldIdItem.java @@ -1,217 +1,217 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib; - -import org.jf.dexlib.Util.Input; -import org.jf.dexlib.Util.AnnotatedOutput; - -public class FieldIdItem extends Item { - private int hashCode = 0; - - private TypeIdItem classType; - private TypeIdItem fieldType; - private StringIdItem fieldName; - - /** - * Creates a new uninitialized FieldIdItem - * @param dexFile The DexFile that this item belongs to - */ - protected FieldIdItem(DexFile dexFile) { - super(dexFile); - } - - /** - * Creates a new FieldIdItem for the given class, type and name - * @param dexFile The DexFile that this item belongs to - * @param classType the class that the field is a member of - * @param fieldType the type of the field - * @param fieldName the name of the field - */ - private FieldIdItem(DexFile dexFile, TypeIdItem classType, TypeIdItem fieldType, StringIdItem fieldName) { - this(dexFile); - - assert classType.dexFile == dexFile; - assert fieldType.dexFile == dexFile; - assert fieldName.dexFile == dexFile; - - this.classType = classType; - this.fieldType = fieldType; - this.fieldName = fieldName; - } - - /** - * Returns a FieldIdItem for the given values, and that has been interned into - * the given DexFile - * @param dexFile The DexFile that this item belongs to - * @param classType the class that the field is a member of - * @param fieldType the type of the field - * @param fieldName the name of the field - * @return a FieldIdItem for the given values, and that has been interned into - * the given DexFile - */ - public static FieldIdItem getInternedFieldIdItem(DexFile dexFile, TypeIdItem classType, TypeIdItem fieldType, - StringIdItem fieldName) { - FieldIdItem fieldIdItem = new FieldIdItem(dexFile, classType, fieldType, fieldName); - return dexFile.FieldIdsSection.intern(fieldIdItem); - } - - /** {@inheritDoc} */ - protected void readItem(Input in, ReadContext readContext) { - classType = dexFile.TypeIdsSection.getItemByIndex(in.readShort()); - fieldType = dexFile.TypeIdsSection.getItemByIndex(in.readShort()); - fieldName = dexFile.StringIdsSection.getItemByIndex(in.readInt()); - } - - /** {@inheritDoc} */ - protected int placeItem(int offset) { - return offset + 8; - } - - /** {@inheritDoc} */ - protected void writeItem(AnnotatedOutput out) { - if (out.annotates()) { - out.annotate(2, "class_type: " + classType.getTypeDescriptor()); - out.annotate(2, "field_type: " + fieldType.getTypeDescriptor()); - out.annotate(4, "field_name: " + fieldName.getStringValue()); - } - - out.writeShort(classType.getIndex()); - out.writeShort(fieldType.getIndex()); - out.writeInt(fieldName.getIndex()); - } - - /** {@inheritDoc} */ - public ItemType getItemType() { - return ItemType.TYPE_FIELD_ID_ITEM; - } - - /** {@inheritDoc} */ - public String getConciseIdentity() { - String parentClass = classType.getTypeDescriptor(); - //strip off the leading L and trailing ; - parentClass = parentClass.substring(1, parentClass.length() - 1); - - return parentClass + "/" + fieldName.getStringValue() + - ":" + fieldType.getTypeDescriptor(); - } - - /** {@inheritDoc} */ - public int compareTo(FieldIdItem o) { - int result = classType.compareTo(o.classType); - if (result != 0) { - return result; - } - - result = fieldName.compareTo(o.fieldName); - if (result != 0) { - return result; - } - - return fieldType.compareTo(o.fieldType); - } - - /** - * @return the class that this field is a member of - */ - public TypeIdItem getContainingClass() { - return classType; - } - - /** - * @return the type of this field - */ - public TypeIdItem getFieldType() { - return fieldType; - } - - /** - * @return the field name - */ - public StringIdItem getFieldName() { - return fieldName; - } - - String cachedFieldString = null; - /** - * @return a string formatted like LclassName;->fieldName:fieldType - */ - public String getFieldString() { - if (cachedFieldString == null) { - String typeDescriptor = classType.getTypeDescriptor(); - String fieldName = this.fieldName.getStringValue(); - String fieldType = this.fieldType.getTypeDescriptor(); - - StringBuffer sb = new StringBuffer(typeDescriptor.length() + fieldName.length() + fieldType.length() + 3); - sb.append(typeDescriptor); - sb.append("->"); - sb.append(fieldName); - sb.append(":"); - sb.append(fieldType); - cachedFieldString = sb.toString(); - } - return cachedFieldString; - } - - /** - * calculate and cache the hashcode - */ - private void calcHashCode() { - hashCode = classType.hashCode(); - hashCode = 31 * hashCode + fieldType.hashCode(); - hashCode = 31 * hashCode + fieldName.hashCode(); - } - - @Override - public int hashCode() { - //there's a small possibility that the actual hash code will be 0. If so, we'll - //just end up recalculating it each time - if (hashCode == 0) - calcHashCode(); - return hashCode; - } - - @Override - public boolean equals(Object o) { - if (this==o) { - return true; - } - if (o==null || !this.getClass().equals(o.getClass())) { - return false; - } - - //This assumes that the referenced items have been interned in both objects. - //This is a valid assumption because all outside code must use the static - //"getInterned..." style methods to make new items, and any item created - //internally is guaranteed to be interned - FieldIdItem other = (FieldIdItem)o; - return (classType == other.classType && - fieldType == other.fieldType && - fieldName == other.fieldName); - } +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib; + +import org.jf.dexlib.Util.Input; +import org.jf.dexlib.Util.AnnotatedOutput; + +public class FieldIdItem extends Item { + private int hashCode = 0; + + private TypeIdItem classType; + private TypeIdItem fieldType; + private StringIdItem fieldName; + + /** + * Creates a new uninitialized FieldIdItem + * @param dexFile The DexFile that this item belongs to + */ + protected FieldIdItem(DexFile dexFile) { + super(dexFile); + } + + /** + * Creates a new FieldIdItem for the given class, type and name + * @param dexFile The DexFile that this item belongs to + * @param classType the class that the field is a member of + * @param fieldType the type of the field + * @param fieldName the name of the field + */ + private FieldIdItem(DexFile dexFile, TypeIdItem classType, TypeIdItem fieldType, StringIdItem fieldName) { + this(dexFile); + + assert classType.dexFile == dexFile; + assert fieldType.dexFile == dexFile; + assert fieldName.dexFile == dexFile; + + this.classType = classType; + this.fieldType = fieldType; + this.fieldName = fieldName; + } + + /** + * Returns a FieldIdItem for the given values, and that has been interned into + * the given DexFile + * @param dexFile The DexFile that this item belongs to + * @param classType the class that the field is a member of + * @param fieldType the type of the field + * @param fieldName the name of the field + * @return a FieldIdItem for the given values, and that has been interned into + * the given DexFile + */ + public static FieldIdItem getInternedFieldIdItem(DexFile dexFile, TypeIdItem classType, TypeIdItem fieldType, + StringIdItem fieldName) { + FieldIdItem fieldIdItem = new FieldIdItem(dexFile, classType, fieldType, fieldName); + return dexFile.FieldIdsSection.intern(fieldIdItem); + } + + /** {@inheritDoc} */ + protected void readItem(Input in, ReadContext readContext) { + classType = dexFile.TypeIdsSection.getItemByIndex(in.readShort()); + fieldType = dexFile.TypeIdsSection.getItemByIndex(in.readShort()); + fieldName = dexFile.StringIdsSection.getItemByIndex(in.readInt()); + } + + /** {@inheritDoc} */ + protected int placeItem(int offset) { + return offset + 8; + } + + /** {@inheritDoc} */ + protected void writeItem(AnnotatedOutput out) { + if (out.annotates()) { + out.annotate(2, "class_type: " + classType.getTypeDescriptor()); + out.annotate(2, "field_type: " + fieldType.getTypeDescriptor()); + out.annotate(4, "field_name: " + fieldName.getStringValue()); + } + + out.writeShort(classType.getIndex()); + out.writeShort(fieldType.getIndex()); + out.writeInt(fieldName.getIndex()); + } + + /** {@inheritDoc} */ + public ItemType getItemType() { + return ItemType.TYPE_FIELD_ID_ITEM; + } + + /** {@inheritDoc} */ + public String getConciseIdentity() { + String parentClass = classType.getTypeDescriptor(); + //strip off the leading L and trailing ; + parentClass = parentClass.substring(1, parentClass.length() - 1); + + return parentClass + "/" + fieldName.getStringValue() + + ":" + fieldType.getTypeDescriptor(); + } + + /** {@inheritDoc} */ + public int compareTo(FieldIdItem o) { + int result = classType.compareTo(o.classType); + if (result != 0) { + return result; + } + + result = fieldName.compareTo(o.fieldName); + if (result != 0) { + return result; + } + + return fieldType.compareTo(o.fieldType); + } + + /** + * @return the class that this field is a member of + */ + public TypeIdItem getContainingClass() { + return classType; + } + + /** + * @return the type of this field + */ + public TypeIdItem getFieldType() { + return fieldType; + } + + /** + * @return the field name + */ + public StringIdItem getFieldName() { + return fieldName; + } + + String cachedFieldString = null; + /** + * @return a string formatted like LclassName;->fieldName:fieldType + */ + public String getFieldString() { + if (cachedFieldString == null) { + String typeDescriptor = classType.getTypeDescriptor(); + String fieldName = this.fieldName.getStringValue(); + String fieldType = this.fieldType.getTypeDescriptor(); + + StringBuffer sb = new StringBuffer(typeDescriptor.length() + fieldName.length() + fieldType.length() + 3); + sb.append(typeDescriptor); + sb.append("->"); + sb.append(fieldName); + sb.append(":"); + sb.append(fieldType); + cachedFieldString = sb.toString(); + } + return cachedFieldString; + } + + /** + * calculate and cache the hashcode + */ + private void calcHashCode() { + hashCode = classType.hashCode(); + hashCode = 31 * hashCode + fieldType.hashCode(); + hashCode = 31 * hashCode + fieldName.hashCode(); + } + + @Override + public int hashCode() { + //there's a small possibility that the actual hash code will be 0. If so, we'll + //just end up recalculating it each time + if (hashCode == 0) + calcHashCode(); + return hashCode; + } + + @Override + public boolean equals(Object o) { + if (this==o) { + return true; + } + if (o==null || !this.getClass().equals(o.getClass())) { + return false; + } + + //This assumes that the referenced items have been interned in both objects. + //This is a valid assumption because all outside code must use the static + //"getInterned..." style methods to make new items, and any item created + //internally is guaranteed to be interned + FieldIdItem other = (FieldIdItem)o; + return (classType == other.classType && + fieldType == other.fieldType && + fieldName == other.fieldName); + } } \ No newline at end of file diff --git a/dexlib/src/main/java/org/jf/dexlib/HeaderItem.java b/dexlib/src/main/java/org/jf/dexlib/HeaderItem.java index 9d30f0ba..b7d57889 100644 --- a/dexlib/src/main/java/org/jf/dexlib/HeaderItem.java +++ b/dexlib/src/main/java/org/jf/dexlib/HeaderItem.java @@ -1,234 +1,234 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib; - -import org.jf.dexlib.Util.AnnotatedOutput; -import org.jf.dexlib.Util.Input; -import org.jf.dexlib.Util.Utf8Utils; - -import java.io.UnsupportedEncodingException; - -public class HeaderItem extends Item { - /** - * the file format magic number, represented as the - * low-order bytes of a string - */ - public static final byte[] MAGIC = new byte[] {0x64, 0x65, 0x78, 0x0A, 0x30, 0x33, 0x35, 0x00};//"dex\n035" + '\0'; - - - /** size of this section, in bytes */ - private static final int HEADER_SIZE = 0x70; - - /** the endianness constants */ - private static final int LITTLE_ENDIAN = 0x12345678; - private static final int BIG_ENDIAN = 0x78562312; - - /** - * Create a new uninitialized HeaderItem - * @param dexFile The DexFile containing this HeaderItem - */ - protected HeaderItem(final DexFile dexFile) { - super(dexFile); - } - - /** {@inheritDoc} */ - protected void readItem(Input in, ReadContext readContext) { - byte[] readMagic = in.readBytes(8); - - for (int i=0; i<8; i++) { - if (MAGIC[i] != readMagic[i]) { - throw new RuntimeException("The magic value is not the expected value"); - } - } - - in.readBytes(20); //checksum - in.readInt(); //signature - in.readInt(); //filesize - if (in.readInt() != HEADER_SIZE) { - throw new RuntimeException("The header size is not the expected value (0x70)"); - } - - int endianTag = in.readInt(); - if (endianTag == BIG_ENDIAN) { - throw new RuntimeException("This dex file is big endian. Only little endian is currently supported."); - } else if (endianTag != LITTLE_ENDIAN) { - throw new RuntimeException("The endian tag is not 0x12345678 or 0x78563412"); - } - - //link_size - if (in.readInt() != 0) { - throw new RuntimeException("This dex file has a link section, which is not supported"); - } - - //link_off - if (in.readInt() != 0) { - throw new RuntimeException("This dex file has a link section, which is not supported"); - } - - int sectionSize; - int sectionOffset; - - //map_offset - sectionOffset = in.readInt(); - readContext.addSection(ItemType.TYPE_MAP_LIST, 1, sectionOffset); - - //string_id_item - sectionSize = in.readInt(); - sectionOffset = in.readInt(); - readContext.addSection(ItemType.TYPE_STRING_ID_ITEM, sectionSize, sectionOffset); - - //type_id_item - sectionSize = in.readInt(); - sectionOffset = in.readInt(); - readContext.addSection(ItemType.TYPE_TYPE_ID_ITEM, sectionSize, sectionOffset); - - //proto_id_item - sectionSize = in.readInt(); - sectionOffset = in.readInt(); - readContext.addSection(ItemType.TYPE_PROTO_ID_ITEM, sectionSize, sectionOffset); - - //field_id_item - sectionSize = in.readInt(); - sectionOffset = in.readInt(); - readContext.addSection(ItemType.TYPE_FIELD_ID_ITEM, sectionSize, sectionOffset); - - //method_id_item - sectionSize = in.readInt(); - sectionOffset = in.readInt(); - readContext.addSection(ItemType.TYPE_METHOD_ID_ITEM, sectionSize, sectionOffset); - - //class_data_item - sectionSize = in.readInt(); - sectionOffset = in.readInt(); - readContext.addSection(ItemType.TYPE_CLASS_DEF_ITEM, sectionSize, sectionOffset); - - in.readInt(); //data_size - in.readInt(); //data_off - } - - /** {@inheritDoc} */ - protected int placeItem(int offset) { - return HEADER_SIZE; - } - - /** {@inheritDoc} */ - protected void writeItem(AnnotatedOutput out) { - StringBuilder magicBuilder = new StringBuilder(); - for (int i=0; i<8; i++) { - magicBuilder.append((char)MAGIC[i]); - } - - out.annotate("magic: " + Utf8Utils.escapeString(magicBuilder.toString())); - out.write(MAGIC); - - out.annotate("checksum"); - out.writeInt(0); - - out.annotate("signature"); - out.write(new byte[20]); - - out.annotate("file_size: 0x" + Integer.toHexString(dexFile.getFileSize()) + " (" + dexFile.getFileSize() + - " bytes)"); - out.writeInt(dexFile.getFileSize()); - - out.annotate("header_size: 0x" + Integer.toHexString(HEADER_SIZE)); - out.writeInt(HEADER_SIZE); - - out.annotate("endian_tag: 0x" + Integer.toHexString(LITTLE_ENDIAN)); - out.writeInt(LITTLE_ENDIAN); - - out.annotate("link_size: 0"); - out.writeInt(0); - - out.annotate("link_off: 0"); - out.writeInt(0); - - out.annotate("map_off: 0x" + Integer.toHexString(dexFile.MapItem.getOffset())); - out.writeInt(dexFile.MapItem.getOffset()); - - out.annotate("string_ids_size: " + dexFile.StringIdsSection.getItems().size()); - out.writeInt(dexFile.StringIdsSection.getItems().size()); - - out.annotate("string_ids_off: 0x" + Integer.toHexString(dexFile.StringIdsSection.getOffset())); - out.writeInt(dexFile.StringIdsSection.getOffset()); - - out.annotate("type_ids_size: " + dexFile.TypeIdsSection.getItems().size()); - out.writeInt(dexFile.TypeIdsSection.getItems().size()); - - out.annotate("type_ids_off: 0x" + Integer.toHexString(dexFile.TypeIdsSection.getOffset())); - out.writeInt(dexFile.TypeIdsSection.getOffset()); - - out.annotate("proto_ids_size: " + dexFile.ProtoIdsSection.getItems().size()); - out.writeInt(dexFile.ProtoIdsSection.getItems().size()); - - out.annotate("proto_ids_off: 0x" + Integer.toHexString(dexFile.ProtoIdsSection.getOffset())); - out.writeInt(dexFile.ProtoIdsSection.getOffset()); - - out.annotate("field_ids_size: " + dexFile.FieldIdsSection.getItems().size()); - out.writeInt(dexFile.FieldIdsSection.getItems().size()); - - out.annotate("field_ids_off: 0x" + Integer.toHexString(dexFile.FieldIdsSection.getOffset())); - out.writeInt(dexFile.FieldIdsSection.getOffset()); - - out.annotate("method_ids_size: " + dexFile.MethodIdsSection.getItems().size()); - out.writeInt(dexFile.MethodIdsSection.getItems().size()); - - out.annotate("method_ids_off: 0x" + Integer.toHexString(dexFile.MethodIdsSection.getOffset())); - out.writeInt(dexFile.MethodIdsSection.getOffset()); - - out.annotate("class_defs_size: " + dexFile.ClassDefsSection.getItems().size()); - out.writeInt(dexFile.ClassDefsSection.getItems().size()); - - out.annotate("class_defs_off: 0x" + Integer.toHexString(dexFile.ClassDefsSection.getOffset())); - out.writeInt(dexFile.ClassDefsSection.getOffset()); - - out.annotate("data_size: 0x" + Integer.toHexString(dexFile.getDataSize()) + " (" + dexFile.getDataSize() + - " bytes)"); - out.writeInt(dexFile.getDataSize()); - - out.annotate("data_off: 0x" + Integer.toHexString(dexFile.getDataOffset())); - out.writeInt(dexFile.getDataOffset()); - } - - /** {@inheritDoc} */ - public ItemType getItemType() { - return ItemType.TYPE_HEADER_ITEM; - } - - /** {@inheritDoc} */ - public String getConciseIdentity() { - return "header_item"; - } - - /** {@inheritDoc} */ - public int compareTo(HeaderItem o) { - //there is only 1 header item - return 0; - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib; + +import org.jf.dexlib.Util.AnnotatedOutput; +import org.jf.dexlib.Util.Input; +import org.jf.dexlib.Util.Utf8Utils; + +import java.io.UnsupportedEncodingException; + +public class HeaderItem extends Item { + /** + * the file format magic number, represented as the + * low-order bytes of a string + */ + public static final byte[] MAGIC = new byte[] {0x64, 0x65, 0x78, 0x0A, 0x30, 0x33, 0x35, 0x00};//"dex\n035" + '\0'; + + + /** size of this section, in bytes */ + private static final int HEADER_SIZE = 0x70; + + /** the endianness constants */ + private static final int LITTLE_ENDIAN = 0x12345678; + private static final int BIG_ENDIAN = 0x78562312; + + /** + * Create a new uninitialized HeaderItem + * @param dexFile The DexFile containing this HeaderItem + */ + protected HeaderItem(final DexFile dexFile) { + super(dexFile); + } + + /** {@inheritDoc} */ + protected void readItem(Input in, ReadContext readContext) { + byte[] readMagic = in.readBytes(8); + + for (int i=0; i<8; i++) { + if (MAGIC[i] != readMagic[i]) { + throw new RuntimeException("The magic value is not the expected value"); + } + } + + in.readBytes(20); //checksum + in.readInt(); //signature + in.readInt(); //filesize + if (in.readInt() != HEADER_SIZE) { + throw new RuntimeException("The header size is not the expected value (0x70)"); + } + + int endianTag = in.readInt(); + if (endianTag == BIG_ENDIAN) { + throw new RuntimeException("This dex file is big endian. Only little endian is currently supported."); + } else if (endianTag != LITTLE_ENDIAN) { + throw new RuntimeException("The endian tag is not 0x12345678 or 0x78563412"); + } + + //link_size + if (in.readInt() != 0) { + throw new RuntimeException("This dex file has a link section, which is not supported"); + } + + //link_off + if (in.readInt() != 0) { + throw new RuntimeException("This dex file has a link section, which is not supported"); + } + + int sectionSize; + int sectionOffset; + + //map_offset + sectionOffset = in.readInt(); + readContext.addSection(ItemType.TYPE_MAP_LIST, 1, sectionOffset); + + //string_id_item + sectionSize = in.readInt(); + sectionOffset = in.readInt(); + readContext.addSection(ItemType.TYPE_STRING_ID_ITEM, sectionSize, sectionOffset); + + //type_id_item + sectionSize = in.readInt(); + sectionOffset = in.readInt(); + readContext.addSection(ItemType.TYPE_TYPE_ID_ITEM, sectionSize, sectionOffset); + + //proto_id_item + sectionSize = in.readInt(); + sectionOffset = in.readInt(); + readContext.addSection(ItemType.TYPE_PROTO_ID_ITEM, sectionSize, sectionOffset); + + //field_id_item + sectionSize = in.readInt(); + sectionOffset = in.readInt(); + readContext.addSection(ItemType.TYPE_FIELD_ID_ITEM, sectionSize, sectionOffset); + + //method_id_item + sectionSize = in.readInt(); + sectionOffset = in.readInt(); + readContext.addSection(ItemType.TYPE_METHOD_ID_ITEM, sectionSize, sectionOffset); + + //class_data_item + sectionSize = in.readInt(); + sectionOffset = in.readInt(); + readContext.addSection(ItemType.TYPE_CLASS_DEF_ITEM, sectionSize, sectionOffset); + + in.readInt(); //data_size + in.readInt(); //data_off + } + + /** {@inheritDoc} */ + protected int placeItem(int offset) { + return HEADER_SIZE; + } + + /** {@inheritDoc} */ + protected void writeItem(AnnotatedOutput out) { + StringBuilder magicBuilder = new StringBuilder(); + for (int i=0; i<8; i++) { + magicBuilder.append((char)MAGIC[i]); + } + + out.annotate("magic: " + Utf8Utils.escapeString(magicBuilder.toString())); + out.write(MAGIC); + + out.annotate("checksum"); + out.writeInt(0); + + out.annotate("signature"); + out.write(new byte[20]); + + out.annotate("file_size: 0x" + Integer.toHexString(dexFile.getFileSize()) + " (" + dexFile.getFileSize() + + " bytes)"); + out.writeInt(dexFile.getFileSize()); + + out.annotate("header_size: 0x" + Integer.toHexString(HEADER_SIZE)); + out.writeInt(HEADER_SIZE); + + out.annotate("endian_tag: 0x" + Integer.toHexString(LITTLE_ENDIAN)); + out.writeInt(LITTLE_ENDIAN); + + out.annotate("link_size: 0"); + out.writeInt(0); + + out.annotate("link_off: 0"); + out.writeInt(0); + + out.annotate("map_off: 0x" + Integer.toHexString(dexFile.MapItem.getOffset())); + out.writeInt(dexFile.MapItem.getOffset()); + + out.annotate("string_ids_size: " + dexFile.StringIdsSection.getItems().size()); + out.writeInt(dexFile.StringIdsSection.getItems().size()); + + out.annotate("string_ids_off: 0x" + Integer.toHexString(dexFile.StringIdsSection.getOffset())); + out.writeInt(dexFile.StringIdsSection.getOffset()); + + out.annotate("type_ids_size: " + dexFile.TypeIdsSection.getItems().size()); + out.writeInt(dexFile.TypeIdsSection.getItems().size()); + + out.annotate("type_ids_off: 0x" + Integer.toHexString(dexFile.TypeIdsSection.getOffset())); + out.writeInt(dexFile.TypeIdsSection.getOffset()); + + out.annotate("proto_ids_size: " + dexFile.ProtoIdsSection.getItems().size()); + out.writeInt(dexFile.ProtoIdsSection.getItems().size()); + + out.annotate("proto_ids_off: 0x" + Integer.toHexString(dexFile.ProtoIdsSection.getOffset())); + out.writeInt(dexFile.ProtoIdsSection.getOffset()); + + out.annotate("field_ids_size: " + dexFile.FieldIdsSection.getItems().size()); + out.writeInt(dexFile.FieldIdsSection.getItems().size()); + + out.annotate("field_ids_off: 0x" + Integer.toHexString(dexFile.FieldIdsSection.getOffset())); + out.writeInt(dexFile.FieldIdsSection.getOffset()); + + out.annotate("method_ids_size: " + dexFile.MethodIdsSection.getItems().size()); + out.writeInt(dexFile.MethodIdsSection.getItems().size()); + + out.annotate("method_ids_off: 0x" + Integer.toHexString(dexFile.MethodIdsSection.getOffset())); + out.writeInt(dexFile.MethodIdsSection.getOffset()); + + out.annotate("class_defs_size: " + dexFile.ClassDefsSection.getItems().size()); + out.writeInt(dexFile.ClassDefsSection.getItems().size()); + + out.annotate("class_defs_off: 0x" + Integer.toHexString(dexFile.ClassDefsSection.getOffset())); + out.writeInt(dexFile.ClassDefsSection.getOffset()); + + out.annotate("data_size: 0x" + Integer.toHexString(dexFile.getDataSize()) + " (" + dexFile.getDataSize() + + " bytes)"); + out.writeInt(dexFile.getDataSize()); + + out.annotate("data_off: 0x" + Integer.toHexString(dexFile.getDataOffset())); + out.writeInt(dexFile.getDataOffset()); + } + + /** {@inheritDoc} */ + public ItemType getItemType() { + return ItemType.TYPE_HEADER_ITEM; + } + + /** {@inheritDoc} */ + public String getConciseIdentity() { + return "header_item"; + } + + /** {@inheritDoc} */ + public int compareTo(HeaderItem o) { + //there is only 1 header item + return 0; + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/IndexedSection.java b/dexlib/src/main/java/org/jf/dexlib/IndexedSection.java index 35f0d295..c11485b7 100644 --- a/dexlib/src/main/java/org/jf/dexlib/IndexedSection.java +++ b/dexlib/src/main/java/org/jf/dexlib/IndexedSection.java @@ -1,67 +1,67 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib; - -import org.jf.dexlib.Util.Input; - -public class IndexedSection extends Section { - - /** - * Create a new indexed section - * @param dexFile The DexFile that this section belongs to - * @param itemType The itemType that this section will hold - */ - public IndexedSection(DexFile dexFile, ItemType itemType) { - super(dexFile, itemType); - } - - /** {@inheritDoc} */ - protected void readItems(Input in, ReadContext readContext) { - for (int i = 0; i < items.size(); i++) { - T item = (T)ItemFactory.makeItem(ItemType, DexFile); - items.set(i, item); - item.readFrom(in, i, readContext); - } - } - - /** - * Gets the item at the specified index in this section - * @param index the index of the item to get - * @return the item at the specified index in this section - * @throws IndexOutOfBoundsException if index is outside the bounds of this section - */ - public T getItemByIndex(int index) { - if (index == -1) { - return null; - } - - //if index is out of bounds, just let it throw an exception - return items.get(index); - } +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib; + +import org.jf.dexlib.Util.Input; + +public class IndexedSection extends Section { + + /** + * Create a new indexed section + * @param dexFile The DexFile that this section belongs to + * @param itemType The itemType that this section will hold + */ + public IndexedSection(DexFile dexFile, ItemType itemType) { + super(dexFile, itemType); + } + + /** {@inheritDoc} */ + protected void readItems(Input in, ReadContext readContext) { + for (int i = 0; i < items.size(); i++) { + T item = (T)ItemFactory.makeItem(ItemType, DexFile); + items.set(i, item); + item.readFrom(in, i, readContext); + } + } + + /** + * Gets the item at the specified index in this section + * @param index the index of the item to get + * @return the item at the specified index in this section + * @throws IndexOutOfBoundsException if index is outside the bounds of this section + */ + public T getItemByIndex(int index) { + if (index == -1) { + return null; + } + + //if index is out of bounds, just let it throw an exception + return items.get(index); + } } \ No newline at end of file diff --git a/dexlib/src/main/java/org/jf/dexlib/Item.java b/dexlib/src/main/java/org/jf/dexlib/Item.java index abf312e9..21468528 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Item.java +++ b/dexlib/src/main/java/org/jf/dexlib/Item.java @@ -1,182 +1,182 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib; - -import org.jf.dexlib.Util.AnnotatedOutput; -import org.jf.dexlib.Util.Input; -import org.jf.dexlib.Util.AlignmentUtils; - -public abstract class Item implements Comparable { - /** - * The offset of this item in the dex file, or -1 if not known - */ - protected int offset = -1; - - /** - * The index of this item in the containing section, or -1 if not known - */ - protected int index = -1; - - /** - * The DexFile that this item is associatedr with - */ - protected final DexFile dexFile; - - /** - * The constructor that is used when reading in a DexFile - * @param dexFile the DexFile that this item is associated with - */ - protected Item(DexFile dexFile) { - this.dexFile = dexFile; - } - - /** - * Read in the item from the given input stream, and initialize the index - * @param in the Input object to read from - * @param index the index within the containing section of the item being read in - * @param readContext a ReadContext object to hold information that is - * only needed while reading in a file - */ - protected void readFrom(Input in, int index, ReadContext readContext) { - assert in.getCursor() % getItemType().ItemAlignment == 0; - - this.offset = in.getCursor(); - this.index = index; - this.readItem(in, readContext); - } - - /** - * Place the item at the given offset and index, and return the offset of the byte following this item - * @param offset The offset to place the item at - * @param index The index of the item within the containing section - * @return The offset of the byte following this item - */ - protected int placeAt(int offset, int index) { - assert offset % getItemType().ItemAlignment == 0; - assert !dexFile.getInplace() || (offset == this.offset && this.index == index); - - this.offset = offset; - this.index = index; - return this.placeItem(offset); - } - - /** - * Write and annotate this item to the output stream - * @param out The output stream to write and annotate to - */ - protected void writeTo(AnnotatedOutput out) { - assert out.getCursor() % getItemType().ItemAlignment == 0; - assert out.getCursor() == offset; - - if (out.annotates()) { - out.annotate(0, "[" + index + "] " + this.getItemType().TypeName); - } - - out.indent(); - writeItem(out); - out.deindent(); - } - - /** - * Returns a human readable form of this item - * @return a human readable form of this item - */ - public String toString() { - return getConciseIdentity(); - } - - /** - * The method in the concrete item subclass that actually reads in the data for the item - * - * The logic in this method can assume that the given Input object is valid and is - * aligned as neccessary. - * - * This method is for internal use only - * @param in the Input object to read from - * @param readContext a ReadContext object to hold information that is - * only needed while reading in a file - */ - protected abstract void readItem(Input in, ReadContext readContext); - - /** - * The method should finalize the layout of the item and return the offset of the byte - * immediately following the item. - * - * The implementation of this method can assume that the offset argument has already been - * aligned based on the item's alignment requirements - * - * This method is for internal use only - * @param offset the (pre-aligned) offset to place the item at - * @return the size of the item, in bytes - */ - protected abstract int placeItem(int offset); - - /** - * The method in the concrete item subclass that actually writes and annotates the data - * for the item. - * - * The logic in this method can assume that the given Output object is valid and is - * aligned as neccessary - * - * @param out The AnnotatedOutput object to write/annotate to - */ - protected abstract void writeItem(AnnotatedOutput out); - - /** - * @return An ItemType enum that represents the item type of this item - */ - public abstract ItemType getItemType(); - - /** - * @return A concise (human-readable) string value that conveys the identity of this item - */ - public abstract String getConciseIdentity(); - - - /** - * @return the offset in the dex file where this item is located - */ - public int getOffset() { - return offset; - } - - /** - * @return the index of this item within the item's containing section - */ - public int getIndex() { - return index; - } - - /** - * @return the DexFile that contains this item - */ - public DexFile getDexFile() { - return dexFile; - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib; + +import org.jf.dexlib.Util.AnnotatedOutput; +import org.jf.dexlib.Util.Input; +import org.jf.dexlib.Util.AlignmentUtils; + +public abstract class Item implements Comparable { + /** + * The offset of this item in the dex file, or -1 if not known + */ + protected int offset = -1; + + /** + * The index of this item in the containing section, or -1 if not known + */ + protected int index = -1; + + /** + * The DexFile that this item is associatedr with + */ + protected final DexFile dexFile; + + /** + * The constructor that is used when reading in a DexFile + * @param dexFile the DexFile that this item is associated with + */ + protected Item(DexFile dexFile) { + this.dexFile = dexFile; + } + + /** + * Read in the item from the given input stream, and initialize the index + * @param in the Input object to read from + * @param index the index within the containing section of the item being read in + * @param readContext a ReadContext object to hold information that is + * only needed while reading in a file + */ + protected void readFrom(Input in, int index, ReadContext readContext) { + assert in.getCursor() % getItemType().ItemAlignment == 0; + + this.offset = in.getCursor(); + this.index = index; + this.readItem(in, readContext); + } + + /** + * Place the item at the given offset and index, and return the offset of the byte following this item + * @param offset The offset to place the item at + * @param index The index of the item within the containing section + * @return The offset of the byte following this item + */ + protected int placeAt(int offset, int index) { + assert offset % getItemType().ItemAlignment == 0; + assert !dexFile.getInplace() || (offset == this.offset && this.index == index); + + this.offset = offset; + this.index = index; + return this.placeItem(offset); + } + + /** + * Write and annotate this item to the output stream + * @param out The output stream to write and annotate to + */ + protected void writeTo(AnnotatedOutput out) { + assert out.getCursor() % getItemType().ItemAlignment == 0; + assert out.getCursor() == offset; + + if (out.annotates()) { + out.annotate(0, "[" + index + "] " + this.getItemType().TypeName); + } + + out.indent(); + writeItem(out); + out.deindent(); + } + + /** + * Returns a human readable form of this item + * @return a human readable form of this item + */ + public String toString() { + return getConciseIdentity(); + } + + /** + * The method in the concrete item subclass that actually reads in the data for the item + * + * The logic in this method can assume that the given Input object is valid and is + * aligned as neccessary. + * + * This method is for internal use only + * @param in the Input object to read from + * @param readContext a ReadContext object to hold information that is + * only needed while reading in a file + */ + protected abstract void readItem(Input in, ReadContext readContext); + + /** + * The method should finalize the layout of the item and return the offset of the byte + * immediately following the item. + * + * The implementation of this method can assume that the offset argument has already been + * aligned based on the item's alignment requirements + * + * This method is for internal use only + * @param offset the (pre-aligned) offset to place the item at + * @return the size of the item, in bytes + */ + protected abstract int placeItem(int offset); + + /** + * The method in the concrete item subclass that actually writes and annotates the data + * for the item. + * + * The logic in this method can assume that the given Output object is valid and is + * aligned as neccessary + * + * @param out The AnnotatedOutput object to write/annotate to + */ + protected abstract void writeItem(AnnotatedOutput out); + + /** + * @return An ItemType enum that represents the item type of this item + */ + public abstract ItemType getItemType(); + + /** + * @return A concise (human-readable) string value that conveys the identity of this item + */ + public abstract String getConciseIdentity(); + + + /** + * @return the offset in the dex file where this item is located + */ + public int getOffset() { + return offset; + } + + /** + * @return the index of this item within the item's containing section + */ + public int getIndex() { + return index; + } + + /** + * @return the DexFile that contains this item + */ + public DexFile getDexFile() { + return dexFile; + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/MapItem.java b/dexlib/src/main/java/org/jf/dexlib/MapItem.java index 47c1f0dc..1fa1c8ba 100644 --- a/dexlib/src/main/java/org/jf/dexlib/MapItem.java +++ b/dexlib/src/main/java/org/jf/dexlib/MapItem.java @@ -1,138 +1,138 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib; - -import org.jf.dexlib.Util.Input; -import org.jf.dexlib.Util.AnnotatedOutput; - -/** - * This item represents a map_list item from the dex specification. It contains a - * SectionInfo instance for every section in the DexFile, with the number of items - * in and offset of that section. - */ -public class MapItem extends Item { - /** - * This item is read in immediately after the HeaderItem, and the section info contained - * by this item is added to the ReadContext object, which is used when reading in the other - * sections in the dex file. - * - * This item should be placed last. It depends on the fact that the other sections - * in the file have been placed. - */ - - /** - * Create a new uninitialized MapItem - * @param dexFile The DexFile that this item belongs to - */ - protected MapItem(final DexFile dexFile) { - super(dexFile); - } - - /** {@inheritDoc} */ - protected int placeItem(int offset) { - Section[] sections = dexFile.getOrderedSections(); - //the list returned by getOrderedSections doesn't contain the header - //or map section, so add 2 to the length - return offset + 4 + (sections.length + 2) * 12; - } - - /** {@inheritDoc} */ - protected void readItem(Input in, ReadContext readContext) { - int size = in.readInt(); - - for (int i=0; i 0; - Section[] sections = dexFile.getOrderedSections(); - - out.annotate("map_size: 0x" + Integer.toHexString(sections.length + 2) + " (" + - Integer.toString(sections.length + 2) + ")"); - out.writeInt(sections.length + 2); - - int index = 0; - out.annotate(0, "[" + index++ + "]"); - out.indent(); - writeSectionInfo(out, ItemType.TYPE_HEADER_ITEM, 1, 0); - out.deindent(); - - for (Section section: dexFile.getOrderedSections()) { - out.annotate(0, "[" + index++ + "]"); - out.indent(); - writeSectionInfo(out, section.ItemType, section.getItems().size(), section.getOffset()); - out.deindent(); - } - - out.annotate(0, "[" + index++ + "]"); - out.indent(); - writeSectionInfo(out, ItemType.TYPE_MAP_LIST, 1, dexFile.MapItem.getOffset()); - out.deindent(); - } - - private void writeSectionInfo(AnnotatedOutput out, ItemType itemType, int sectionSize, int sectionOffset) { - if (out.annotates()) { - out.annotate(2, "item_type: " + itemType); - out.annotate(2, "unused"); - out.annotate(4, "section_size: 0x" + Integer.toHexString(sectionSize) + " (" + sectionSize + ")"); - out.annotate(4, "section_off: 0x" + Integer.toHexString(sectionOffset)); - } - - out.writeShort(itemType.MapValue); - out.writeShort(0); - out.writeInt(sectionSize); - out.writeInt(sectionOffset); - } - - /** {@inheritDoc} */ - public ItemType getItemType() { - return ItemType.TYPE_MAP_LIST; - } - - /** {@inheritDoc} */ - public int compareTo(MapItem o) { - return 0; - } - - /** {@inheritDoc} */ - public String getConciseIdentity() { - return "map_item"; - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib; + +import org.jf.dexlib.Util.Input; +import org.jf.dexlib.Util.AnnotatedOutput; + +/** + * This item represents a map_list item from the dex specification. It contains a + * SectionInfo instance for every section in the DexFile, with the number of items + * in and offset of that section. + */ +public class MapItem extends Item { + /** + * This item is read in immediately after the HeaderItem, and the section info contained + * by this item is added to the ReadContext object, which is used when reading in the other + * sections in the dex file. + * + * This item should be placed last. It depends on the fact that the other sections + * in the file have been placed. + */ + + /** + * Create a new uninitialized MapItem + * @param dexFile The DexFile that this item belongs to + */ + protected MapItem(final DexFile dexFile) { + super(dexFile); + } + + /** {@inheritDoc} */ + protected int placeItem(int offset) { + Section[] sections = dexFile.getOrderedSections(); + //the list returned by getOrderedSections doesn't contain the header + //or map section, so add 2 to the length + return offset + 4 + (sections.length + 2) * 12; + } + + /** {@inheritDoc} */ + protected void readItem(Input in, ReadContext readContext) { + int size = in.readInt(); + + for (int i=0; i 0; + Section[] sections = dexFile.getOrderedSections(); + + out.annotate("map_size: 0x" + Integer.toHexString(sections.length + 2) + " (" + + Integer.toString(sections.length + 2) + ")"); + out.writeInt(sections.length + 2); + + int index = 0; + out.annotate(0, "[" + index++ + "]"); + out.indent(); + writeSectionInfo(out, ItemType.TYPE_HEADER_ITEM, 1, 0); + out.deindent(); + + for (Section section: dexFile.getOrderedSections()) { + out.annotate(0, "[" + index++ + "]"); + out.indent(); + writeSectionInfo(out, section.ItemType, section.getItems().size(), section.getOffset()); + out.deindent(); + } + + out.annotate(0, "[" + index++ + "]"); + out.indent(); + writeSectionInfo(out, ItemType.TYPE_MAP_LIST, 1, dexFile.MapItem.getOffset()); + out.deindent(); + } + + private void writeSectionInfo(AnnotatedOutput out, ItemType itemType, int sectionSize, int sectionOffset) { + if (out.annotates()) { + out.annotate(2, "item_type: " + itemType); + out.annotate(2, "unused"); + out.annotate(4, "section_size: 0x" + Integer.toHexString(sectionSize) + " (" + sectionSize + ")"); + out.annotate(4, "section_off: 0x" + Integer.toHexString(sectionOffset)); + } + + out.writeShort(itemType.MapValue); + out.writeShort(0); + out.writeInt(sectionSize); + out.writeInt(sectionOffset); + } + + /** {@inheritDoc} */ + public ItemType getItemType() { + return ItemType.TYPE_MAP_LIST; + } + + /** {@inheritDoc} */ + public int compareTo(MapItem o) { + return 0; + } + + /** {@inheritDoc} */ + public String getConciseIdentity() { + return "map_item"; + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/MethodIdItem.java b/dexlib/src/main/java/org/jf/dexlib/MethodIdItem.java index 8e934b5f..61882f0f 100644 --- a/dexlib/src/main/java/org/jf/dexlib/MethodIdItem.java +++ b/dexlib/src/main/java/org/jf/dexlib/MethodIdItem.java @@ -1,207 +1,207 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib; - -import org.jf.dexlib.Util.Input; -import org.jf.dexlib.Util.AnnotatedOutput; - -public class MethodIdItem extends Item { - private int hashCode = 0; - - private TypeIdItem classType; - private ProtoIdItem methodPrototype; - private StringIdItem methodName; - - /** - * Creates a new uninitialized MethodIdItem - * @param dexFile The DexFile that this item belongs to - */ - protected MethodIdItem(DexFile dexFile) { - super(dexFile); - } - - /** - * Creates a new MethodIdItem for the given class, type and name - * @param dexFile The DexFile that this item belongs to - * @param classType the class that the method is a member of - * @param methodPrototype the type of the method - * @param methodName the name of the method - */ - private MethodIdItem(DexFile dexFile, TypeIdItem classType, ProtoIdItem methodPrototype, StringIdItem methodName) { - this(dexFile); - this.classType = classType; - this.methodPrototype = methodPrototype; - this.methodName = methodName; - } - - /** - * Returns a MethodIdItem for the given values, and that has been interned into - * the given DexFile - * @param dexFile The DexFile that this item belongs to - * @param classType the class that the method is a member of - * @param methodPrototype the type of the method - * @param methodName the name of the method - * @return a MethodIdItem for the given values, and that has been interned into - * the given DexFile - */ - public static MethodIdItem getInternedMethodIdItem(DexFile dexFile, TypeIdItem classType, - ProtoIdItem methodPrototype, StringIdItem methodName) { - MethodIdItem methodIdItem = new MethodIdItem(dexFile, classType, methodPrototype, methodName); - return dexFile.MethodIdsSection.intern(methodIdItem); - } - - /** {@inheritDoc} */ - protected void readItem(Input in, ReadContext readContext) { - classType = dexFile.TypeIdsSection.getItemByIndex(in.readShort()); - methodPrototype = dexFile.ProtoIdsSection.getItemByIndex(in.readShort()); - methodName = dexFile.StringIdsSection.getItemByIndex(in.readInt()); - } - - /** {@inheritDoc} */ - protected int placeItem(int offset) { - return offset + 8; - } - - /** {@inheritDoc} */ - protected void writeItem(AnnotatedOutput out) { - if (out.annotates()) { - out.annotate(2, "class_type: " + classType.getTypeDescriptor()); - out.annotate(2, "method_prototype: " + methodPrototype.getPrototypeString()); - out.annotate(4, "method_name: " + methodName.getStringValue()); - } - - out.writeShort(classType.getIndex()); - out.writeShort(methodPrototype.getIndex()); - out.writeInt(methodName.getIndex()); - } - - /** {@inheritDoc} */ - public ItemType getItemType() { - return ItemType.TYPE_METHOD_ID_ITEM; - } - - /** {@inheritDoc} */ - public String getConciseIdentity() { - return "method_id_item: " + getMethodString(); - } - - /** {@inheritDoc} */ - public int compareTo(MethodIdItem o) { - int result = classType.compareTo(o.classType); - if (result != 0) { - return result; - } - - result = methodName.compareTo(o.methodName); - if (result != 0) { - return result; - } - - return methodPrototype.compareTo(o.methodPrototype); - } - - private String cachedMethodString = null; - /** - * @return a string formatted like LclassName;->methodName(TTTT..)R - */ - public String getMethodString() { - if (cachedMethodString == null) { - String classType = this.classType.getTypeDescriptor(); - String methodName = this.methodName.getStringValue(); - String prototypeString = methodPrototype.getPrototypeString(); - - StringBuilder sb = new StringBuilder(classType.length() + methodName.length() + prototypeString.length() + - 2); - sb.append(classType); - sb.append("->"); - sb.append(methodName); - sb.append(prototypeString); - cachedMethodString = sb.toString(); - } - return cachedMethodString; - } - - /** - * @return the method prototype - */ - public ProtoIdItem getPrototype() { - return methodPrototype; - } - - /** - * @return the name of the method - */ - public StringIdItem getMethodName() { - return methodName; - } - - /** - * @return the class this method is a member of - */ - public TypeIdItem getContainingClass() { - return classType; - } - - /** - * calculate and cache the hashcode - */ - private void calcHashCode() { - hashCode = classType.hashCode(); - hashCode = 31 * hashCode + methodPrototype.hashCode(); - hashCode = 31 * hashCode + methodName.hashCode(); - } - - @Override - public int hashCode() { - //there's a small possibility that the actual hash code will be 0. If so, we'll - //just end up recalculating it each time - if (hashCode == 0) - calcHashCode(); - return hashCode; - } - - @Override - public boolean equals(Object o) { - if (this==o) { - return true; - } - if (o==null || !this.getClass().equals(o.getClass())) { - return false; - } - - //This assumes that the referenced items have been interned in both objects. - //This is a valid assumption because all outside code must use the static - //"getInterned..." style methods to make new items, and any item created - //internally is guaranteed to be interned - MethodIdItem other = (MethodIdItem)o; - return (classType == other.classType && - methodPrototype == other.methodPrototype && - methodName == other.methodName); - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib; + +import org.jf.dexlib.Util.Input; +import org.jf.dexlib.Util.AnnotatedOutput; + +public class MethodIdItem extends Item { + private int hashCode = 0; + + private TypeIdItem classType; + private ProtoIdItem methodPrototype; + private StringIdItem methodName; + + /** + * Creates a new uninitialized MethodIdItem + * @param dexFile The DexFile that this item belongs to + */ + protected MethodIdItem(DexFile dexFile) { + super(dexFile); + } + + /** + * Creates a new MethodIdItem for the given class, type and name + * @param dexFile The DexFile that this item belongs to + * @param classType the class that the method is a member of + * @param methodPrototype the type of the method + * @param methodName the name of the method + */ + private MethodIdItem(DexFile dexFile, TypeIdItem classType, ProtoIdItem methodPrototype, StringIdItem methodName) { + this(dexFile); + this.classType = classType; + this.methodPrototype = methodPrototype; + this.methodName = methodName; + } + + /** + * Returns a MethodIdItem for the given values, and that has been interned into + * the given DexFile + * @param dexFile The DexFile that this item belongs to + * @param classType the class that the method is a member of + * @param methodPrototype the type of the method + * @param methodName the name of the method + * @return a MethodIdItem for the given values, and that has been interned into + * the given DexFile + */ + public static MethodIdItem getInternedMethodIdItem(DexFile dexFile, TypeIdItem classType, + ProtoIdItem methodPrototype, StringIdItem methodName) { + MethodIdItem methodIdItem = new MethodIdItem(dexFile, classType, methodPrototype, methodName); + return dexFile.MethodIdsSection.intern(methodIdItem); + } + + /** {@inheritDoc} */ + protected void readItem(Input in, ReadContext readContext) { + classType = dexFile.TypeIdsSection.getItemByIndex(in.readShort()); + methodPrototype = dexFile.ProtoIdsSection.getItemByIndex(in.readShort()); + methodName = dexFile.StringIdsSection.getItemByIndex(in.readInt()); + } + + /** {@inheritDoc} */ + protected int placeItem(int offset) { + return offset + 8; + } + + /** {@inheritDoc} */ + protected void writeItem(AnnotatedOutput out) { + if (out.annotates()) { + out.annotate(2, "class_type: " + classType.getTypeDescriptor()); + out.annotate(2, "method_prototype: " + methodPrototype.getPrototypeString()); + out.annotate(4, "method_name: " + methodName.getStringValue()); + } + + out.writeShort(classType.getIndex()); + out.writeShort(methodPrototype.getIndex()); + out.writeInt(methodName.getIndex()); + } + + /** {@inheritDoc} */ + public ItemType getItemType() { + return ItemType.TYPE_METHOD_ID_ITEM; + } + + /** {@inheritDoc} */ + public String getConciseIdentity() { + return "method_id_item: " + getMethodString(); + } + + /** {@inheritDoc} */ + public int compareTo(MethodIdItem o) { + int result = classType.compareTo(o.classType); + if (result != 0) { + return result; + } + + result = methodName.compareTo(o.methodName); + if (result != 0) { + return result; + } + + return methodPrototype.compareTo(o.methodPrototype); + } + + private String cachedMethodString = null; + /** + * @return a string formatted like LclassName;->methodName(TTTT..)R + */ + public String getMethodString() { + if (cachedMethodString == null) { + String classType = this.classType.getTypeDescriptor(); + String methodName = this.methodName.getStringValue(); + String prototypeString = methodPrototype.getPrototypeString(); + + StringBuilder sb = new StringBuilder(classType.length() + methodName.length() + prototypeString.length() + + 2); + sb.append(classType); + sb.append("->"); + sb.append(methodName); + sb.append(prototypeString); + cachedMethodString = sb.toString(); + } + return cachedMethodString; + } + + /** + * @return the method prototype + */ + public ProtoIdItem getPrototype() { + return methodPrototype; + } + + /** + * @return the name of the method + */ + public StringIdItem getMethodName() { + return methodName; + } + + /** + * @return the class this method is a member of + */ + public TypeIdItem getContainingClass() { + return classType; + } + + /** + * calculate and cache the hashcode + */ + private void calcHashCode() { + hashCode = classType.hashCode(); + hashCode = 31 * hashCode + methodPrototype.hashCode(); + hashCode = 31 * hashCode + methodName.hashCode(); + } + + @Override + public int hashCode() { + //there's a small possibility that the actual hash code will be 0. If so, we'll + //just end up recalculating it each time + if (hashCode == 0) + calcHashCode(); + return hashCode; + } + + @Override + public boolean equals(Object o) { + if (this==o) { + return true; + } + if (o==null || !this.getClass().equals(o.getClass())) { + return false; + } + + //This assumes that the referenced items have been interned in both objects. + //This is a valid assumption because all outside code must use the static + //"getInterned..." style methods to make new items, and any item created + //internally is guaranteed to be interned + MethodIdItem other = (MethodIdItem)o; + return (classType == other.classType && + methodPrototype == other.methodPrototype && + methodName == other.methodName); + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/OffsettedSection.java b/dexlib/src/main/java/org/jf/dexlib/OffsettedSection.java index c34137fe..fa8f4212 100644 --- a/dexlib/src/main/java/org/jf/dexlib/OffsettedSection.java +++ b/dexlib/src/main/java/org/jf/dexlib/OffsettedSection.java @@ -1,83 +1,83 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib; - -import org.jf.dexlib.Util.Input; -import org.jf.dexlib.Util.SparseArray; -import org.jf.dexlib.Util.Hex; - -import junit.framework.Assert; - -public class OffsettedSection extends Section { - public OffsettedSection(DexFile dexFile, ItemType itemType) { - super(dexFile, itemType); - } - - public void readItems(Input in, ReadContext readContext) { - SparseArray precreatedItems = (SparseArray)readContext.getItemsByType(ItemType); - - assert precreatedItems.size() <= items.size(): "Trying to read " + items.size() + " items, but this section " + - "already contains " + precreatedItems.size() + " items."; - - int precreatedIndex = 0; - int nextPrecreatedOffset = Integer.MAX_VALUE; - - if (precreatedItems.size() > 0) { - nextPrecreatedOffset = precreatedItems.keyAt(0); - } - - for (int i = 0; i < items.size(); i++) { - assert items.get(i) == null; - - T item = null; - in.alignTo(ItemType.ItemAlignment); - int currentOffset = in.getCursor(); - - if (currentOffset == nextPrecreatedOffset) { - item = precreatedItems.valueAt(precreatedIndex++); - if (precreatedIndex < precreatedItems.size()) { - nextPrecreatedOffset = precreatedItems.keyAt(precreatedIndex); - } else { - nextPrecreatedOffset = Integer.MAX_VALUE; - } - } else if (currentOffset > nextPrecreatedOffset) { - //we passed by the next precreated item, something is wrong - throw new RuntimeException("The pre-created item at offset 0x" + Hex.u4(nextPrecreatedOffset) - + " was not read"); - } else { - item = (T)ItemFactory.makeItem(ItemType, DexFile); - } - - items.set(i, item); - item.readFrom(in, i, readContext); - } - - readContext.setItemsForSection(ItemType, items); - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib; + +import org.jf.dexlib.Util.Input; +import org.jf.dexlib.Util.SparseArray; +import org.jf.dexlib.Util.Hex; + +import junit.framework.Assert; + +public class OffsettedSection extends Section { + public OffsettedSection(DexFile dexFile, ItemType itemType) { + super(dexFile, itemType); + } + + public void readItems(Input in, ReadContext readContext) { + SparseArray precreatedItems = (SparseArray)readContext.getItemsByType(ItemType); + + assert precreatedItems.size() <= items.size(): "Trying to read " + items.size() + " items, but this section " + + "already contains " + precreatedItems.size() + " items."; + + int precreatedIndex = 0; + int nextPrecreatedOffset = Integer.MAX_VALUE; + + if (precreatedItems.size() > 0) { + nextPrecreatedOffset = precreatedItems.keyAt(0); + } + + for (int i = 0; i < items.size(); i++) { + assert items.get(i) == null; + + T item = null; + in.alignTo(ItemType.ItemAlignment); + int currentOffset = in.getCursor(); + + if (currentOffset == nextPrecreatedOffset) { + item = precreatedItems.valueAt(precreatedIndex++); + if (precreatedIndex < precreatedItems.size()) { + nextPrecreatedOffset = precreatedItems.keyAt(precreatedIndex); + } else { + nextPrecreatedOffset = Integer.MAX_VALUE; + } + } else if (currentOffset > nextPrecreatedOffset) { + //we passed by the next precreated item, something is wrong + throw new RuntimeException("The pre-created item at offset 0x" + Hex.u4(nextPrecreatedOffset) + + " was not read"); + } else { + item = (T)ItemFactory.makeItem(ItemType, DexFile); + } + + items.set(i, item); + item.readFrom(in, i, readContext); + } + + readContext.setItemsForSection(ItemType, items); + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/ProtoIdItem.java b/dexlib/src/main/java/org/jf/dexlib/ProtoIdItem.java index eb19d8a5..b9744461 100644 --- a/dexlib/src/main/java/org/jf/dexlib/ProtoIdItem.java +++ b/dexlib/src/main/java/org/jf/dexlib/ProtoIdItem.java @@ -1,217 +1,217 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib; - -import org.jf.dexlib.Util.Input; -import org.jf.dexlib.Util.AnnotatedOutput; - -public class ProtoIdItem extends Item { - private int hashCode = 0; - - private StringIdItem shortyDescriptor; - private TypeIdItem returnType; - private TypeListItem parameters; - - /** - * Creates a new uninitialized ProtoIdItem - * @param dexFile The DexFile that this item belongs to - */ - protected ProtoIdItem(DexFile dexFile) { - super(dexFile); - } - - /** - * Creates a new ProtoIdItem with the given values - * @param dexFile The DexFile that this item belongs to - * @param returnType the return type - * @param parameters a TypeListItem containing a list of the parameter types - */ - private ProtoIdItem(DexFile dexFile, TypeIdItem returnType, TypeListItem parameters) { - this(dexFile); - - String shortyString = returnType.toShorty(); - if (parameters != null) { - shortyString += parameters.getShortyString(); - } - this.shortyDescriptor = StringIdItem.getInternedStringIdItem(dexFile, shortyString); - this.returnType = returnType; - this.parameters = parameters; - } - - /** - * Returns a ProtoIdItem for the given values, and that has been interned into - * the given DexFile - * @param dexFile The DexFile that this item belongs to - * @param returnType the return type - * @param parameters a TypeListItem containing a list of the parameter types - * @return a ProtoIdItem for the given values, and that has been interned into - * the given DexFile - */ - public static ProtoIdItem getInternedProtoIdItem(DexFile dexFile, TypeIdItem returnType, TypeListItem parameters) { - ProtoIdItem protoIdItem = new ProtoIdItem(dexFile, returnType, parameters); - return dexFile.ProtoIdsSection.intern(protoIdItem); - } - - /** {@inheritDoc} */ - protected void readItem(Input in, ReadContext readContext) { - shortyDescriptor = dexFile.StringIdsSection.getItemByIndex(in.readInt()); - returnType = dexFile.TypeIdsSection.getItemByIndex(in.readInt()); - parameters = (TypeListItem)readContext.getOffsettedItemByOffset(ItemType.TYPE_TYPE_LIST, in.readInt()); - } - - /** {@inheritDoc} */ - protected int placeItem(int offset) { - return offset + 12; - } - - /** {@inheritDoc} */ - protected void writeItem(AnnotatedOutput out) { - if (out.annotates()) { - out.annotate(4, "shorty_descriptor: " + shortyDescriptor.getStringValue()); - out.annotate(4, "return_type: " + returnType.getTypeDescriptor()); - - if (parameters == null) { - out.annotate(4, "parameters:"); - } else { - out.annotate(4, "parameters: " + parameters.getTypeListString("")); - } - } - - out.writeInt(shortyDescriptor.getIndex()); - out.writeInt(returnType.getIndex()); - out.writeInt(parameters == null?0:parameters.getOffset()); - } - - /** {@inheritDoc} */ - public ItemType getItemType() { - return ItemType.TYPE_PROTO_ID_ITEM; - } - - /** {@inheritDoc} */ - public int compareTo(ProtoIdItem o) { - int result = returnType.compareTo(o.returnType); - if (result != 0) { - return result; - } - - if (parameters == null) { - if (o.parameters == null) { - return 0; - } - return -1; - } else if (o.parameters == null) { - return 1; - } - - return parameters.compareTo(o.parameters); - } - - /** {@inheritDoc} */ - public String getConciseIdentity() { - return "proto_id_item: " + getPrototypeString(); - } - - private String cachedPrototypeString = null; - /** - * @return a string in the format (TTTT..)R where TTTT.. are the parameter types and R is the return type - */ - public String getPrototypeString() { - if (cachedPrototypeString == null) { - StringBuilder sb = new StringBuilder("("); - if (parameters != null) { - sb.append(parameters.getTypeListString("")); - } - sb.append(")"); - sb.append(returnType.getTypeDescriptor()); - - cachedPrototypeString = sb.toString(); - } - return cachedPrototypeString; - } - - /** - * @return the return type of the method - */ - public TypeIdItem getReturnType() { - return returnType; - } - - /** - * @return a TypeListItem containing the method parameter types - */ - public TypeListItem getParameters() { - return parameters; - } - - /** - * @return the number of registers required for the parameters of this ProtoIdItem - */ - public int getParameterRegisterCount() { - if (parameters == null) { - return 0; - } else { - return parameters.getRegisterCount(); - } - } - - /** - * calculate and cache the hashcode - */ - private void calcHashCode() { - hashCode = returnType.hashCode(); - hashCode = 31 * hashCode + (parameters==null?0:parameters.hashCode()); - } - - @Override - public int hashCode() { - //there's a small possibility that the actual hash code will be 0. If so, we'll - //just end up recalculating it each time - if (hashCode == 0) - calcHashCode(); - return hashCode; - } - - @Override - public boolean equals(Object o) { - if (this==o) { - return true; - } - if (o==null || !this.getClass().equals(o.getClass())) { - return false; - } - - //This assumes that the referenced items have been interned in both objects. - //This is a valid assumption because all outside code must use the static - //"getInterned..." style methods to make new items, and any item created - //internally is guaranteed to be interned - ProtoIdItem other = (ProtoIdItem)o; - return (returnType == other.returnType && - parameters == other.parameters); - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib; + +import org.jf.dexlib.Util.Input; +import org.jf.dexlib.Util.AnnotatedOutput; + +public class ProtoIdItem extends Item { + private int hashCode = 0; + + private StringIdItem shortyDescriptor; + private TypeIdItem returnType; + private TypeListItem parameters; + + /** + * Creates a new uninitialized ProtoIdItem + * @param dexFile The DexFile that this item belongs to + */ + protected ProtoIdItem(DexFile dexFile) { + super(dexFile); + } + + /** + * Creates a new ProtoIdItem with the given values + * @param dexFile The DexFile that this item belongs to + * @param returnType the return type + * @param parameters a TypeListItem containing a list of the parameter types + */ + private ProtoIdItem(DexFile dexFile, TypeIdItem returnType, TypeListItem parameters) { + this(dexFile); + + String shortyString = returnType.toShorty(); + if (parameters != null) { + shortyString += parameters.getShortyString(); + } + this.shortyDescriptor = StringIdItem.getInternedStringIdItem(dexFile, shortyString); + this.returnType = returnType; + this.parameters = parameters; + } + + /** + * Returns a ProtoIdItem for the given values, and that has been interned into + * the given DexFile + * @param dexFile The DexFile that this item belongs to + * @param returnType the return type + * @param parameters a TypeListItem containing a list of the parameter types + * @return a ProtoIdItem for the given values, and that has been interned into + * the given DexFile + */ + public static ProtoIdItem getInternedProtoIdItem(DexFile dexFile, TypeIdItem returnType, TypeListItem parameters) { + ProtoIdItem protoIdItem = new ProtoIdItem(dexFile, returnType, parameters); + return dexFile.ProtoIdsSection.intern(protoIdItem); + } + + /** {@inheritDoc} */ + protected void readItem(Input in, ReadContext readContext) { + shortyDescriptor = dexFile.StringIdsSection.getItemByIndex(in.readInt()); + returnType = dexFile.TypeIdsSection.getItemByIndex(in.readInt()); + parameters = (TypeListItem)readContext.getOffsettedItemByOffset(ItemType.TYPE_TYPE_LIST, in.readInt()); + } + + /** {@inheritDoc} */ + protected int placeItem(int offset) { + return offset + 12; + } + + /** {@inheritDoc} */ + protected void writeItem(AnnotatedOutput out) { + if (out.annotates()) { + out.annotate(4, "shorty_descriptor: " + shortyDescriptor.getStringValue()); + out.annotate(4, "return_type: " + returnType.getTypeDescriptor()); + + if (parameters == null) { + out.annotate(4, "parameters:"); + } else { + out.annotate(4, "parameters: " + parameters.getTypeListString("")); + } + } + + out.writeInt(shortyDescriptor.getIndex()); + out.writeInt(returnType.getIndex()); + out.writeInt(parameters == null?0:parameters.getOffset()); + } + + /** {@inheritDoc} */ + public ItemType getItemType() { + return ItemType.TYPE_PROTO_ID_ITEM; + } + + /** {@inheritDoc} */ + public int compareTo(ProtoIdItem o) { + int result = returnType.compareTo(o.returnType); + if (result != 0) { + return result; + } + + if (parameters == null) { + if (o.parameters == null) { + return 0; + } + return -1; + } else if (o.parameters == null) { + return 1; + } + + return parameters.compareTo(o.parameters); + } + + /** {@inheritDoc} */ + public String getConciseIdentity() { + return "proto_id_item: " + getPrototypeString(); + } + + private String cachedPrototypeString = null; + /** + * @return a string in the format (TTTT..)R where TTTT.. are the parameter types and R is the return type + */ + public String getPrototypeString() { + if (cachedPrototypeString == null) { + StringBuilder sb = new StringBuilder("("); + if (parameters != null) { + sb.append(parameters.getTypeListString("")); + } + sb.append(")"); + sb.append(returnType.getTypeDescriptor()); + + cachedPrototypeString = sb.toString(); + } + return cachedPrototypeString; + } + + /** + * @return the return type of the method + */ + public TypeIdItem getReturnType() { + return returnType; + } + + /** + * @return a TypeListItem containing the method parameter types + */ + public TypeListItem getParameters() { + return parameters; + } + + /** + * @return the number of registers required for the parameters of this ProtoIdItem + */ + public int getParameterRegisterCount() { + if (parameters == null) { + return 0; + } else { + return parameters.getRegisterCount(); + } + } + + /** + * calculate and cache the hashcode + */ + private void calcHashCode() { + hashCode = returnType.hashCode(); + hashCode = 31 * hashCode + (parameters==null?0:parameters.hashCode()); + } + + @Override + public int hashCode() { + //there's a small possibility that the actual hash code will be 0. If so, we'll + //just end up recalculating it each time + if (hashCode == 0) + calcHashCode(); + return hashCode; + } + + @Override + public boolean equals(Object o) { + if (this==o) { + return true; + } + if (o==null || !this.getClass().equals(o.getClass())) { + return false; + } + + //This assumes that the referenced items have been interned in both objects. + //This is a valid assumption because all outside code must use the static + //"getInterned..." style methods to make new items, and any item created + //internally is guaranteed to be interned + ProtoIdItem other = (ProtoIdItem)o; + return (returnType == other.returnType && + parameters == other.parameters); + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/Section.java b/dexlib/src/main/java/org/jf/dexlib/Section.java index 7d38381a..a9e1cc48 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Section.java +++ b/dexlib/src/main/java/org/jf/dexlib/Section.java @@ -1,218 +1,218 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib; - -import org.jf.dexlib.Util.AnnotatedOutput; -import org.jf.dexlib.Util.Input; -import org.jf.dexlib.Util.AlignmentUtils; - -import java.util.*; - -public abstract class Section { - /** - * A list of the items that this section contains. - * If the section has been placed, this list should be in the order that the items - * will written to the dex file - */ - protected final ArrayList items; - - /** - * A HashMap of the items in this section. This is used when interning items, to determine - * if this section already has an item equivalent to the one that is being interned. - * Both the key and the value should be the same object - */ - protected HashMap uniqueItems = null; - - /** - * The offset of this section within the DexFile - */ - protected int offset = 0; - - /** - * The type of item that this section holds - */ - public final ItemType ItemType; - - /** - * The DexFile that this section belongs to - */ - public final DexFile DexFile; - - /** - * Create a new section - * @param dexFile The DexFile that this section belongs to - * @param itemType The itemType that this section will hold - */ - protected Section(DexFile dexFile, ItemType itemType) { - this.DexFile = dexFile; - items = new ArrayList(); - this.ItemType = itemType; - } - - /** - * Finalize the location of all items, and place them starting at the given offset - * @param offset The offset where this section should be placed - * @return the offset of the byte immediate after the last item in this section - */ - protected int placeAt(int offset) { - if (items.size() > 0) { - offset = AlignmentUtils.alignOffset(offset, ItemType.ItemAlignment); - assert !DexFile.getInplace() || offset == this.offset; - this.offset = offset; - - for (int i=0; i < items.size(); i++) { - T item = items.get(i); - assert item != null; - offset = AlignmentUtils.alignOffset(offset, ItemType.ItemAlignment); - offset = item.placeAt(offset, i); - } - } else { - this.offset = 0; - } - - return offset; - } - - /** - * Write the items to the given AnnotatedOutput - * @param out the AnnotatedOutput object to write to - */ - protected void writeTo(AnnotatedOutput out) { - out.annotate(0, " "); - out.annotate(0, "-----------------------------"); - out.annotate(0, this.ItemType.TypeName + " section"); - out.annotate(0, "-----------------------------"); - out.annotate(0, " "); - - for (Item item: items) { - assert item!=null; - out.alignTo(ItemType.ItemAlignment); - item.writeTo(out); - out.annotate(0, " "); - } - } - - /** - * Read the specified number of items from the given Input object - * @param size The number of items to read - * @param in The Input object to read from - * @param readContext a ReadContext object to hold information that is - * only needed while reading in a file - */ - protected void readFrom(int size, Input in, ReadContext readContext) { - //readItems() expects that the list will already be the correct size, so add null items - //until we reach the specified size - items.ensureCapacity(size); - for (int i = items.size(); i < size; i++) { - items.add(null); - } - - in.alignTo(ItemType.ItemAlignment); - offset = in.getCursor(); - - //call the subclass's method that actually reads in the items - readItems(in, readContext); - } - - /** - * This method in the concrete item subclass should read in all the items from the given Input - * object, using any pre-created items as applicable (i.e. items that were created prior to reading in the - * section, by other items requesting items from this section that they reference by index/offset) - * @param in the Input - * @param readContext a ReadContext object to hold information that is - * only needed while reading in a file - */ - protected abstract void readItems(Input in, ReadContext readContext); - - /** - * Gets the offset where the first item in this section is placed - * @return the ofset where the first item in this section is placed - */ - public int getOffset() { - return offset; - } - - /** - * Gets a the items contained in this section as a read-only list - * @return A read-only List object containing the items in this section - */ - public List getItems() { - return Collections.unmodifiableList(items); - } - - /** - * This method checks if an item that is equivalent to the given item has already been added. If found, - * it returns that item. If not found, it adds the given item to this section and returns it. - * @param item the item to intern - * @return An item from this section that is equivalent to the given item. It may or may not be the same - * as the item passed to this method. - */ - protected T intern(T item) { - if (item == null) { - return null; - } - T internedItem = getInternedItem(item); - if (internedItem == null && !item.dexFile.getInterningDisabled()) { - uniqueItems.put(item, item); - items.add(item); - return item; - } - return internedItem; - } - - /** - * Returns the interned item that is equivalent to the given item, or null - * @param item the item to check - * @return the interned item that is equivalent to the given item, or null - */ - protected T getInternedItem(T item) { - if (uniqueItems == null) { - buildInternedItemMap(); - } - return uniqueItems.get(item); - } - - /** - * Builds the interned item map from the items that are in this section - */ - private void buildInternedItemMap() { - uniqueItems = new HashMap(); - for (T item: items) { - assert item != null; - uniqueItems.put(item, item); - } - } - - /** - * Sorts the items in the section - */ - protected void sortSection() { - Collections.sort(items); - } +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib; + +import org.jf.dexlib.Util.AnnotatedOutput; +import org.jf.dexlib.Util.Input; +import org.jf.dexlib.Util.AlignmentUtils; + +import java.util.*; + +public abstract class Section { + /** + * A list of the items that this section contains. + * If the section has been placed, this list should be in the order that the items + * will written to the dex file + */ + protected final ArrayList items; + + /** + * A HashMap of the items in this section. This is used when interning items, to determine + * if this section already has an item equivalent to the one that is being interned. + * Both the key and the value should be the same object + */ + protected HashMap uniqueItems = null; + + /** + * The offset of this section within the DexFile + */ + protected int offset = 0; + + /** + * The type of item that this section holds + */ + public final ItemType ItemType; + + /** + * The DexFile that this section belongs to + */ + public final DexFile DexFile; + + /** + * Create a new section + * @param dexFile The DexFile that this section belongs to + * @param itemType The itemType that this section will hold + */ + protected Section(DexFile dexFile, ItemType itemType) { + this.DexFile = dexFile; + items = new ArrayList(); + this.ItemType = itemType; + } + + /** + * Finalize the location of all items, and place them starting at the given offset + * @param offset The offset where this section should be placed + * @return the offset of the byte immediate after the last item in this section + */ + protected int placeAt(int offset) { + if (items.size() > 0) { + offset = AlignmentUtils.alignOffset(offset, ItemType.ItemAlignment); + assert !DexFile.getInplace() || offset == this.offset; + this.offset = offset; + + for (int i=0; i < items.size(); i++) { + T item = items.get(i); + assert item != null; + offset = AlignmentUtils.alignOffset(offset, ItemType.ItemAlignment); + offset = item.placeAt(offset, i); + } + } else { + this.offset = 0; + } + + return offset; + } + + /** + * Write the items to the given AnnotatedOutput + * @param out the AnnotatedOutput object to write to + */ + protected void writeTo(AnnotatedOutput out) { + out.annotate(0, " "); + out.annotate(0, "-----------------------------"); + out.annotate(0, this.ItemType.TypeName + " section"); + out.annotate(0, "-----------------------------"); + out.annotate(0, " "); + + for (Item item: items) { + assert item!=null; + out.alignTo(ItemType.ItemAlignment); + item.writeTo(out); + out.annotate(0, " "); + } + } + + /** + * Read the specified number of items from the given Input object + * @param size The number of items to read + * @param in The Input object to read from + * @param readContext a ReadContext object to hold information that is + * only needed while reading in a file + */ + protected void readFrom(int size, Input in, ReadContext readContext) { + //readItems() expects that the list will already be the correct size, so add null items + //until we reach the specified size + items.ensureCapacity(size); + for (int i = items.size(); i < size; i++) { + items.add(null); + } + + in.alignTo(ItemType.ItemAlignment); + offset = in.getCursor(); + + //call the subclass's method that actually reads in the items + readItems(in, readContext); + } + + /** + * This method in the concrete item subclass should read in all the items from the given Input + * object, using any pre-created items as applicable (i.e. items that were created prior to reading in the + * section, by other items requesting items from this section that they reference by index/offset) + * @param in the Input + * @param readContext a ReadContext object to hold information that is + * only needed while reading in a file + */ + protected abstract void readItems(Input in, ReadContext readContext); + + /** + * Gets the offset where the first item in this section is placed + * @return the ofset where the first item in this section is placed + */ + public int getOffset() { + return offset; + } + + /** + * Gets a the items contained in this section as a read-only list + * @return A read-only List object containing the items in this section + */ + public List getItems() { + return Collections.unmodifiableList(items); + } + + /** + * This method checks if an item that is equivalent to the given item has already been added. If found, + * it returns that item. If not found, it adds the given item to this section and returns it. + * @param item the item to intern + * @return An item from this section that is equivalent to the given item. It may or may not be the same + * as the item passed to this method. + */ + protected T intern(T item) { + if (item == null) { + return null; + } + T internedItem = getInternedItem(item); + if (internedItem == null && !item.dexFile.getInterningDisabled()) { + uniqueItems.put(item, item); + items.add(item); + return item; + } + return internedItem; + } + + /** + * Returns the interned item that is equivalent to the given item, or null + * @param item the item to check + * @return the interned item that is equivalent to the given item, or null + */ + protected T getInternedItem(T item) { + if (uniqueItems == null) { + buildInternedItemMap(); + } + return uniqueItems.get(item); + } + + /** + * Builds the interned item map from the items that are in this section + */ + private void buildInternedItemMap() { + uniqueItems = new HashMap(); + for (T item: items) { + assert item != null; + uniqueItems.put(item, item); + } + } + + /** + * Sorts the items in the section + */ + protected void sortSection() { + Collections.sort(items); + } } \ No newline at end of file diff --git a/dexlib/src/main/java/org/jf/dexlib/StringDataItem.java b/dexlib/src/main/java/org/jf/dexlib/StringDataItem.java index 5d794101..ff94c5ab 100644 --- a/dexlib/src/main/java/org/jf/dexlib/StringDataItem.java +++ b/dexlib/src/main/java/org/jf/dexlib/StringDataItem.java @@ -1,153 +1,153 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib; - -import org.jf.dexlib.Util.*; - -public class StringDataItem extends Item { - private int hashCode = 0; - - private String stringValue; - - /** - * Creates a new uninitialized StringDataItem - * @param dexFile The DexFile that this item belongs to - */ - protected StringDataItem(DexFile dexFile) { - super(dexFile); - } - - /** - * Creates a new StringDataItem for the given string - * @param dexFile The DexFile that this item belongs to - * @param stringValue The string value that this item represents - */ - private StringDataItem(DexFile dexFile, String stringValue) { - super(dexFile); - - this.stringValue = stringValue; - } - - /** - * Returns a StringDataItem for the given values, and that has been interned into - * the given DexFile - * @param dexFile The DexFile that this item belongs to - * @param value The string value that this item represents - * @return a StringDataItem for the given values, and that has been interned into - * the given DexFile - */ - public static StringDataItem getInternedStringDataItem(DexFile dexFile, String value) { - StringDataItem StringDataItem = new StringDataItem(dexFile, value); - return dexFile.StringDataSection.intern(StringDataItem); - } - - /** {@inheritDoc} */ - protected void readItem(Input in, ReadContext readContext) { - in.readUnsignedLeb128(); //string length - stringValue = Utf8Utils.utf8BytesToString(in.readNullTerminatedBytes()); - } - - /** {@inheritDoc} */ - protected int placeItem(int offset) { - return offset + Leb128Utils.unsignedLeb128Size(stringValue.length()) + - Utf8Utils.stringToUtf8Bytes(stringValue).length + 1; - } - - /** {@inheritDoc} */ - protected void writeItem(AnnotatedOutput out) { - byte[] encodedValue = Utf8Utils.stringToUtf8Bytes(stringValue); - if (out.annotates()) { - out.annotate("string_size: 0x" + Integer.toHexString(stringValue.length()) + " (" + stringValue.length() + - ")"); - out.writeUnsignedLeb128(stringValue.length()); - - out.annotate(encodedValue.length + 1, "string_data: \"" + Utf8Utils.escapeString(stringValue) + "\""); - } else { - out.writeUnsignedLeb128(stringValue.length()); - } - out.write(encodedValue); - out.writeByte(0); - } - - /** {@inheritDoc} */ - public ItemType getItemType() { - return ItemType.TYPE_STRING_DATA_ITEM; - } - - /** {@inheritDoc} */ - public String getConciseIdentity() { - return "string_data_item: \"" + Utf8Utils.escapeString(getStringValue()) + "\""; - } - - /** {@inheritDoc} */ - public int compareTo(StringDataItem o) { - return getStringValue().compareTo(o.getStringValue()); - } - - /** - * Get the string value of this item as a String - * @return the string value of this item as a String - */ - public String getStringValue() { - return stringValue; - } - - /** - * calculate and cache the hashcode - */ - private void calcHashCode() { - hashCode = getStringValue().hashCode(); - } - - @Override - public int hashCode() { - //there's a small possibility that the actual hash code will be 0. If so, we'll - //just end up recalculating it each time - if (hashCode == 0) - calcHashCode(); - return hashCode; - } - - @Override - public boolean equals(Object o) { - if (this==o) { - return true; - } - if (o==null || !this.getClass().equals(o.getClass())) { - return false; - } - - //This assumes that the referenced items have been interned in both objects. - //This is a valid assumption because all outside code must use the static - //"getInterned..." style methods to make new items, and any item created - //internally is guaranteed to be interned - StringDataItem other = (StringDataItem)o; - return getStringValue().equals(other.getStringValue()); - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib; + +import org.jf.dexlib.Util.*; + +public class StringDataItem extends Item { + private int hashCode = 0; + + private String stringValue; + + /** + * Creates a new uninitialized StringDataItem + * @param dexFile The DexFile that this item belongs to + */ + protected StringDataItem(DexFile dexFile) { + super(dexFile); + } + + /** + * Creates a new StringDataItem for the given string + * @param dexFile The DexFile that this item belongs to + * @param stringValue The string value that this item represents + */ + private StringDataItem(DexFile dexFile, String stringValue) { + super(dexFile); + + this.stringValue = stringValue; + } + + /** + * Returns a StringDataItem for the given values, and that has been interned into + * the given DexFile + * @param dexFile The DexFile that this item belongs to + * @param value The string value that this item represents + * @return a StringDataItem for the given values, and that has been interned into + * the given DexFile + */ + public static StringDataItem getInternedStringDataItem(DexFile dexFile, String value) { + StringDataItem StringDataItem = new StringDataItem(dexFile, value); + return dexFile.StringDataSection.intern(StringDataItem); + } + + /** {@inheritDoc} */ + protected void readItem(Input in, ReadContext readContext) { + in.readUnsignedLeb128(); //string length + stringValue = Utf8Utils.utf8BytesToString(in.readNullTerminatedBytes()); + } + + /** {@inheritDoc} */ + protected int placeItem(int offset) { + return offset + Leb128Utils.unsignedLeb128Size(stringValue.length()) + + Utf8Utils.stringToUtf8Bytes(stringValue).length + 1; + } + + /** {@inheritDoc} */ + protected void writeItem(AnnotatedOutput out) { + byte[] encodedValue = Utf8Utils.stringToUtf8Bytes(stringValue); + if (out.annotates()) { + out.annotate("string_size: 0x" + Integer.toHexString(stringValue.length()) + " (" + stringValue.length() + + ")"); + out.writeUnsignedLeb128(stringValue.length()); + + out.annotate(encodedValue.length + 1, "string_data: \"" + Utf8Utils.escapeString(stringValue) + "\""); + } else { + out.writeUnsignedLeb128(stringValue.length()); + } + out.write(encodedValue); + out.writeByte(0); + } + + /** {@inheritDoc} */ + public ItemType getItemType() { + return ItemType.TYPE_STRING_DATA_ITEM; + } + + /** {@inheritDoc} */ + public String getConciseIdentity() { + return "string_data_item: \"" + Utf8Utils.escapeString(getStringValue()) + "\""; + } + + /** {@inheritDoc} */ + public int compareTo(StringDataItem o) { + return getStringValue().compareTo(o.getStringValue()); + } + + /** + * Get the string value of this item as a String + * @return the string value of this item as a String + */ + public String getStringValue() { + return stringValue; + } + + /** + * calculate and cache the hashcode + */ + private void calcHashCode() { + hashCode = getStringValue().hashCode(); + } + + @Override + public int hashCode() { + //there's a small possibility that the actual hash code will be 0. If so, we'll + //just end up recalculating it each time + if (hashCode == 0) + calcHashCode(); + return hashCode; + } + + @Override + public boolean equals(Object o) { + if (this==o) { + return true; + } + if (o==null || !this.getClass().equals(o.getClass())) { + return false; + } + + //This assumes that the referenced items have been interned in both objects. + //This is a valid assumption because all outside code must use the static + //"getInterned..." style methods to make new items, and any item created + //internally is guaranteed to be interned + StringDataItem other = (StringDataItem)o; + return getStringValue().equals(other.getStringValue()); + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/StringIdItem.java b/dexlib/src/main/java/org/jf/dexlib/StringIdItem.java index 79195e95..95f3dbfa 100644 --- a/dexlib/src/main/java/org/jf/dexlib/StringIdItem.java +++ b/dexlib/src/main/java/org/jf/dexlib/StringIdItem.java @@ -1,148 +1,148 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib; - -import org.jf.dexlib.Util.Utf8Utils; -import org.jf.dexlib.Util.Input; -import org.jf.dexlib.Util.AnnotatedOutput; - -public class StringIdItem extends Item { - private StringDataItem stringDataItem; - - /** - * Creates a new uninitialized StringIdItem - * @param dexFile The DexFile that this item belongs to - */ - protected StringIdItem(DexFile dexFile) { - super(dexFile); - } - - /** - * Creates a new StringIdItem for the given StringDataItem - * @param dexFile The DexFile that this item belongs to - * @param stringDataItem The StringDataItem that this StringIdItem represents - */ - protected StringIdItem(DexFile dexFile, StringDataItem stringDataItem) { - super(dexFile); - this.stringDataItem = stringDataItem; - } - - /** - * Returns a StringIdItem for the given values, and that has been interned into - * the given DexFile - * @param dexFile The DexFile that this item will belong to - * @param stringValue The string value that this item represents - * @return a StringIdItem for the given values, and that has been interned into - * the given DexFile - */ - public static StringIdItem getInternedStringIdItem(DexFile dexFile, String stringValue) { - StringDataItem stringDataItem = StringDataItem.getInternedStringDataItem(dexFile, stringValue); - if (stringDataItem == null) { - return null; - } - StringIdItem stringIdItem = new StringIdItem(dexFile, stringDataItem); - return dexFile.StringIdsSection.intern(stringIdItem); - } - - /** {@inheritDoc} */ - protected void readItem(Input in, ReadContext readContext) { - int stringDataOffset = in.readInt(); - - stringDataItem = (StringDataItem)readContext.getOffsettedItemByOffset(ItemType.TYPE_STRING_DATA_ITEM, - stringDataOffset); - } - - /** {@inheritDoc} */ - protected int placeItem(int offset) { - return offset + 4; - } - - /** {@inheritDoc} */ - protected void writeItem(AnnotatedOutput out) { - if (out.annotates()) { - out.annotate(4, stringDataItem.getConciseIdentity()); - } - - out.writeInt(stringDataItem.getOffset()); - } - - /** {@inheritDoc} */ - public ItemType getItemType() { - return ItemType.TYPE_STRING_ID_ITEM; - } - - /** {@inheritDoc} */ - public String getConciseIdentity() { - return "string_id_item: " + Utf8Utils.escapeString(getStringValue()); - } - - /** {@inheritDoc} */ - public int compareTo(StringIdItem o) { - //sort by the string value - return getStringValue().compareTo(o.getStringValue()); - } - - /** - * Get the String value that this StringIdItem represents - * @return the String value that this StringIdItem represents - */ - public String getStringValue() { - return stringDataItem.getStringValue(); - } - - /** - * Get the StringDataItem that this StringIdItem references - * @return the StringDataItem that this StringIdItem references - */ - public StringDataItem getStringDataItem() { - return stringDataItem; - } - - @Override - public int hashCode() { - return stringDataItem.hashCode(); - } - - @Override - public boolean equals(Object o) { - if (this==o) { - return true; - } - if (o==null || !this.getClass().equals(o.getClass())) { - return false; - } - - //This assumes that the referenced items have been interned in both objects. - //This is a valid assumption because all outside code must use the static - //"getInterned..." style methods to make new items, and any item created - //internally is guaranteed to be interned - StringIdItem other = (StringIdItem)o; - return stringDataItem == other.stringDataItem; - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib; + +import org.jf.dexlib.Util.Utf8Utils; +import org.jf.dexlib.Util.Input; +import org.jf.dexlib.Util.AnnotatedOutput; + +public class StringIdItem extends Item { + private StringDataItem stringDataItem; + + /** + * Creates a new uninitialized StringIdItem + * @param dexFile The DexFile that this item belongs to + */ + protected StringIdItem(DexFile dexFile) { + super(dexFile); + } + + /** + * Creates a new StringIdItem for the given StringDataItem + * @param dexFile The DexFile that this item belongs to + * @param stringDataItem The StringDataItem that this StringIdItem represents + */ + protected StringIdItem(DexFile dexFile, StringDataItem stringDataItem) { + super(dexFile); + this.stringDataItem = stringDataItem; + } + + /** + * Returns a StringIdItem for the given values, and that has been interned into + * the given DexFile + * @param dexFile The DexFile that this item will belong to + * @param stringValue The string value that this item represents + * @return a StringIdItem for the given values, and that has been interned into + * the given DexFile + */ + public static StringIdItem getInternedStringIdItem(DexFile dexFile, String stringValue) { + StringDataItem stringDataItem = StringDataItem.getInternedStringDataItem(dexFile, stringValue); + if (stringDataItem == null) { + return null; + } + StringIdItem stringIdItem = new StringIdItem(dexFile, stringDataItem); + return dexFile.StringIdsSection.intern(stringIdItem); + } + + /** {@inheritDoc} */ + protected void readItem(Input in, ReadContext readContext) { + int stringDataOffset = in.readInt(); + + stringDataItem = (StringDataItem)readContext.getOffsettedItemByOffset(ItemType.TYPE_STRING_DATA_ITEM, + stringDataOffset); + } + + /** {@inheritDoc} */ + protected int placeItem(int offset) { + return offset + 4; + } + + /** {@inheritDoc} */ + protected void writeItem(AnnotatedOutput out) { + if (out.annotates()) { + out.annotate(4, stringDataItem.getConciseIdentity()); + } + + out.writeInt(stringDataItem.getOffset()); + } + + /** {@inheritDoc} */ + public ItemType getItemType() { + return ItemType.TYPE_STRING_ID_ITEM; + } + + /** {@inheritDoc} */ + public String getConciseIdentity() { + return "string_id_item: " + Utf8Utils.escapeString(getStringValue()); + } + + /** {@inheritDoc} */ + public int compareTo(StringIdItem o) { + //sort by the string value + return getStringValue().compareTo(o.getStringValue()); + } + + /** + * Get the String value that this StringIdItem represents + * @return the String value that this StringIdItem represents + */ + public String getStringValue() { + return stringDataItem.getStringValue(); + } + + /** + * Get the StringDataItem that this StringIdItem references + * @return the StringDataItem that this StringIdItem references + */ + public StringDataItem getStringDataItem() { + return stringDataItem; + } + + @Override + public int hashCode() { + return stringDataItem.hashCode(); + } + + @Override + public boolean equals(Object o) { + if (this==o) { + return true; + } + if (o==null || !this.getClass().equals(o.getClass())) { + return false; + } + + //This assumes that the referenced items have been interned in both objects. + //This is a valid assumption because all outside code must use the static + //"getInterned..." style methods to make new items, and any item created + //internally is guaranteed to be interned + StringIdItem other = (StringIdItem)o; + return stringDataItem == other.stringDataItem; + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/TypeIdItem.java b/dexlib/src/main/java/org/jf/dexlib/TypeIdItem.java index 7e137986..800f6c15 100644 --- a/dexlib/src/main/java/org/jf/dexlib/TypeIdItem.java +++ b/dexlib/src/main/java/org/jf/dexlib/TypeIdItem.java @@ -1,182 +1,182 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib; - -import org.jf.dexlib.Util.Input; -import org.jf.dexlib.Util.AnnotatedOutput; - -public class TypeIdItem extends Item { - private StringIdItem typeDescriptor; - - /** - * Creates a new uninitialized TypeIdItem - * @param dexFile The DexFile that this item belongs to - */ - protected TypeIdItem(DexFile dexFile) { - super(dexFile); - } - - /** - * Creates a new TypeIdItem for the given StringIdItem - * @param dexFile The DexFile that this item will belong to - * @param typeDescriptor The StringIdItem containing the type descriptor that - * this TypeIdItem represents - */ - private TypeIdItem(DexFile dexFile, StringIdItem typeDescriptor) { - super(dexFile); - this.typeDescriptor = typeDescriptor; - } - - /** - * Returns a TypeIdItem for the given values, and that has been interned into - * the given DexFile - * @param dexFile The DexFile that this item will belong to - * @param typeDescriptor The StringIdItem containing the type descriptor that - * this TypeIdItem represents - * @return a TypeIdItem for the given values, and that has been interned into - * the given DexFile - */ - public static TypeIdItem getInternedTypeIdItem(DexFile dexFile, StringIdItem typeDescriptor) { - TypeIdItem typeIdItem = new TypeIdItem(dexFile, typeDescriptor); - return dexFile.TypeIdsSection.intern(typeIdItem); - } - - /** - * Returns a TypeIdItem for the given values, and that has been interned into - * the given DexFile - * @param dexFile The DexFile that this item will belong to - * @param typeDescriptor The string containing the type descriptor that this - * TypeIdItem represents - * @return a TypeIdItem for the given values, and that has been interned into - * the given DexFile - */ - public static TypeIdItem getInternedTypeIdItem(DexFile dexFile, String typeDescriptor) { - StringIdItem stringIdItem = StringIdItem.getInternedStringIdItem(dexFile, typeDescriptor); - if (stringIdItem == null) { - return null; - } - TypeIdItem typeIdItem = new TypeIdItem(dexFile, stringIdItem); - return dexFile.TypeIdsSection.intern(typeIdItem); - } - - /** {@inheritDoc} */ - protected void readItem(Input in, ReadContext readContext) { - int stringIdIndex = in.readInt(); - this.typeDescriptor = dexFile.StringIdsSection.getItemByIndex(stringIdIndex); - } - - /** {@inheritDoc} */ - protected int placeItem(int offset) { - return offset + 4; - } - - /** {@inheritDoc} */ - protected void writeItem(AnnotatedOutput out) { - if (out.annotates()) { - out.annotate(4, typeDescriptor.getConciseIdentity()); - } - - out.writeInt(typeDescriptor.getIndex()); - } - - /** {@inheritDoc} */ - public ItemType getItemType() { - return ItemType.TYPE_TYPE_ID_ITEM; - } - - /** {@inheritDoc} */ - public String getConciseIdentity() { - return "type_id_item: " + getTypeDescriptor(); - } - - /** {@inheritDoc} */ - public int compareTo(TypeIdItem o) { - //sort by the index of the StringIdItem - return typeDescriptor.compareTo(o.typeDescriptor); - } - - /** - * Returns the type descriptor as a String for this type - * @return the type descriptor as a String for this type - */ - public String getTypeDescriptor() { - return typeDescriptor.getStringValue(); - } - - /** - * Returns the "shorty" representation of this type, used to create the shorty prototype string for a method - * @return the "shorty" representation of this type, used to create the shorty prototype string for a method - */ - public String toShorty() { - String type = getTypeDescriptor(); - if (type.length() > 1) { - return "L"; - } else { - return type; - } - } - - /** - * Calculates the number of 2-byte registers that an instance of this type requires - * @return The number of 2-byte registers that an instance of this type requires - */ - public int getRegisterCount() { - String type = this.getTypeDescriptor(); - /** Only the long and double primitive types are 2 words, - * everything else is a single word - */ - if (type.equals("J") || type.equals("D")) { - return 2; - } else { - return 1; - } - } - - @Override - public int hashCode() { - return typeDescriptor.hashCode(); - } - - @Override - public boolean equals(Object o) { - if (this==o) { - return true; - } - if (o==null || !this.getClass().equals(o.getClass())) { - return false; - } - - //This assumes that the referenced items have been interned in both objects. - //This is a valid assumption because all outside code must use the static - //"getInterned..." style methods to make new items, and any item created - //internally is guaranteed to be interned - TypeIdItem other = (TypeIdItem)o; - return typeDescriptor == other.typeDescriptor; - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib; + +import org.jf.dexlib.Util.Input; +import org.jf.dexlib.Util.AnnotatedOutput; + +public class TypeIdItem extends Item { + private StringIdItem typeDescriptor; + + /** + * Creates a new uninitialized TypeIdItem + * @param dexFile The DexFile that this item belongs to + */ + protected TypeIdItem(DexFile dexFile) { + super(dexFile); + } + + /** + * Creates a new TypeIdItem for the given StringIdItem + * @param dexFile The DexFile that this item will belong to + * @param typeDescriptor The StringIdItem containing the type descriptor that + * this TypeIdItem represents + */ + private TypeIdItem(DexFile dexFile, StringIdItem typeDescriptor) { + super(dexFile); + this.typeDescriptor = typeDescriptor; + } + + /** + * Returns a TypeIdItem for the given values, and that has been interned into + * the given DexFile + * @param dexFile The DexFile that this item will belong to + * @param typeDescriptor The StringIdItem containing the type descriptor that + * this TypeIdItem represents + * @return a TypeIdItem for the given values, and that has been interned into + * the given DexFile + */ + public static TypeIdItem getInternedTypeIdItem(DexFile dexFile, StringIdItem typeDescriptor) { + TypeIdItem typeIdItem = new TypeIdItem(dexFile, typeDescriptor); + return dexFile.TypeIdsSection.intern(typeIdItem); + } + + /** + * Returns a TypeIdItem for the given values, and that has been interned into + * the given DexFile + * @param dexFile The DexFile that this item will belong to + * @param typeDescriptor The string containing the type descriptor that this + * TypeIdItem represents + * @return a TypeIdItem for the given values, and that has been interned into + * the given DexFile + */ + public static TypeIdItem getInternedTypeIdItem(DexFile dexFile, String typeDescriptor) { + StringIdItem stringIdItem = StringIdItem.getInternedStringIdItem(dexFile, typeDescriptor); + if (stringIdItem == null) { + return null; + } + TypeIdItem typeIdItem = new TypeIdItem(dexFile, stringIdItem); + return dexFile.TypeIdsSection.intern(typeIdItem); + } + + /** {@inheritDoc} */ + protected void readItem(Input in, ReadContext readContext) { + int stringIdIndex = in.readInt(); + this.typeDescriptor = dexFile.StringIdsSection.getItemByIndex(stringIdIndex); + } + + /** {@inheritDoc} */ + protected int placeItem(int offset) { + return offset + 4; + } + + /** {@inheritDoc} */ + protected void writeItem(AnnotatedOutput out) { + if (out.annotates()) { + out.annotate(4, typeDescriptor.getConciseIdentity()); + } + + out.writeInt(typeDescriptor.getIndex()); + } + + /** {@inheritDoc} */ + public ItemType getItemType() { + return ItemType.TYPE_TYPE_ID_ITEM; + } + + /** {@inheritDoc} */ + public String getConciseIdentity() { + return "type_id_item: " + getTypeDescriptor(); + } + + /** {@inheritDoc} */ + public int compareTo(TypeIdItem o) { + //sort by the index of the StringIdItem + return typeDescriptor.compareTo(o.typeDescriptor); + } + + /** + * Returns the type descriptor as a String for this type + * @return the type descriptor as a String for this type + */ + public String getTypeDescriptor() { + return typeDescriptor.getStringValue(); + } + + /** + * Returns the "shorty" representation of this type, used to create the shorty prototype string for a method + * @return the "shorty" representation of this type, used to create the shorty prototype string for a method + */ + public String toShorty() { + String type = getTypeDescriptor(); + if (type.length() > 1) { + return "L"; + } else { + return type; + } + } + + /** + * Calculates the number of 2-byte registers that an instance of this type requires + * @return The number of 2-byte registers that an instance of this type requires + */ + public int getRegisterCount() { + String type = this.getTypeDescriptor(); + /** Only the long and double primitive types are 2 words, + * everything else is a single word + */ + if (type.equals("J") || type.equals("D")) { + return 2; + } else { + return 1; + } + } + + @Override + public int hashCode() { + return typeDescriptor.hashCode(); + } + + @Override + public boolean equals(Object o) { + if (this==o) { + return true; + } + if (o==null || !this.getClass().equals(o.getClass())) { + return false; + } + + //This assumes that the referenced items have been interned in both objects. + //This is a valid assumption because all outside code must use the static + //"getInterned..." style methods to make new items, and any item created + //internally is guaranteed to be interned + TypeIdItem other = (TypeIdItem)o; + return typeDescriptor == other.typeDescriptor; + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/TypeListItem.java b/dexlib/src/main/java/org/jf/dexlib/TypeListItem.java index ac7aed88..c601a081 100644 --- a/dexlib/src/main/java/org/jf/dexlib/TypeListItem.java +++ b/dexlib/src/main/java/org/jf/dexlib/TypeListItem.java @@ -1,258 +1,258 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib; - -import org.jf.dexlib.Util.Input; -import org.jf.dexlib.Util.AnnotatedOutput; -import org.jf.dexlib.Util.ReadOnlyArrayList; - -import java.util.List; - -public class TypeListItem extends Item { - private int hashCode = 0; - - private TypeIdItem[] typeList; - - /** - * Creates a new uninitialized TypeListItem - * @param dexFile The DexFile that this item belongs to - */ - protected TypeListItem(DexFile dexFile) { - super(dexFile); - } - - /** - * Creates a new TypeListItem for the given string - * @param dexFile The DexFile that this item belongs to - * @param typeList A list of the types that this TypeListItem represents - */ - private TypeListItem(DexFile dexFile, TypeIdItem[] typeList) { - super(dexFile); - - this.typeList = typeList; - } - - /** - * Returns a TypeListItem for the given values, and that has been interned into - * the given DexFile - * @param dexFile The DexFile that this item belongs to - * @param typeList A list of the types that this TypeListItem represents - * @return a TypeListItem for the given values, and that has been interned into - * the given DexFile - */ - public static TypeListItem getInternedTypeListItem(DexFile dexFile, List typeList) { - TypeIdItem[] typeArray = new TypeIdItem[typeList.size()]; - typeList.toArray(typeArray); - TypeListItem typeListItem = new TypeListItem(dexFile, typeArray); - return dexFile.TypeListsSection.intern(typeListItem); - } - - /** {@inheritDoc} */ - protected void readItem(Input in, ReadContext readContext) { - int size = in.readInt(); - typeList = new TypeIdItem[size]; - for (int i=0; i otherSize) { - return 1; - } else { - return 0; - } - } - - /** - * @return the number of registers required for this TypeListItem - */ - public int getRegisterCount() { - int wordCount = 0; - for (TypeIdItem typeIdItem: typeList) { - wordCount += typeIdItem.getRegisterCount(); - } - return wordCount; - } - - /** - * @return a string consisting of the type descriptors in this TypeListItem - * that are separated by the given separator - * @param separator the separator between each type - */ - public String getTypeListString(String separator) { - int size = 0; - for (TypeIdItem typeIdItem: typeList) { - size += typeIdItem.getTypeDescriptor().length(); - size += separator.length(); - } - - StringBuilder sb = new StringBuilder(size); - for (TypeIdItem typeIdItem: typeList) { - sb.append(typeIdItem.getTypeDescriptor()); - sb.append(separator); - } - if (typeList.length > 0) { - sb.delete(sb.length() - separator.length(), sb.length()); - } - return sb.toString(); - } - - /** - * @return a string consisting of the shorty form of the type descriptors in this - * TypeListItem that are directly concatenated together - */ - public String getShortyString() { - StringBuilder sb = new StringBuilder(); - for (TypeIdItem typeIdItem: typeList) { - sb.append(typeIdItem.toShorty()); - } - return sb.toString(); - } - - /** - * @param index the index of the TypeIdItem to get - * @return the TypeIdItem at the given index - */ - public TypeIdItem getTypeIdItem(int index) { - return typeList[index]; - } - - /** - * @return the number of types in this TypeListItem - */ - public int getTypeCount() { - return typeList.length; - } - - /** - * @return an array of the TypeIdItems in this TypeListItem - */ - public List getTypes() { - return new ReadOnlyArrayList(typeList); - } - - /** - * calculate and cache the hashcode - */ - private void calcHashCode() { - int hashCode = 1; - - for (TypeIdItem typeIdItem: typeList) { - hashCode = 31 * hashCode + typeIdItem.hashCode(); - } - this.hashCode = hashCode; - } - - @Override - public int hashCode() { - //there's a small possibility that the actual hash code will be 0. If so, we'll - //just end up recalculating it each time - if (hashCode == 0) - calcHashCode(); - return hashCode; - } - - @Override - public boolean equals(Object o) { - if (this==o) { - return true; - } - if (o==null || !this.getClass().equals(o.getClass())) { - return false; - } - - //This assumes that the referenced items have been interned in both objects. - //This is a valid assumption because all outside code must use the static - //"getInterned..." style methods to make new items, and any item created - //internally is guaranteed to be interned - TypeListItem other = (TypeListItem)o; - if (typeList.length != other.typeList.length) { - return false; - } - - for (int i=0; i { + private int hashCode = 0; + + private TypeIdItem[] typeList; + + /** + * Creates a new uninitialized TypeListItem + * @param dexFile The DexFile that this item belongs to + */ + protected TypeListItem(DexFile dexFile) { + super(dexFile); + } + + /** + * Creates a new TypeListItem for the given string + * @param dexFile The DexFile that this item belongs to + * @param typeList A list of the types that this TypeListItem represents + */ + private TypeListItem(DexFile dexFile, TypeIdItem[] typeList) { + super(dexFile); + + this.typeList = typeList; + } + + /** + * Returns a TypeListItem for the given values, and that has been interned into + * the given DexFile + * @param dexFile The DexFile that this item belongs to + * @param typeList A list of the types that this TypeListItem represents + * @return a TypeListItem for the given values, and that has been interned into + * the given DexFile + */ + public static TypeListItem getInternedTypeListItem(DexFile dexFile, List typeList) { + TypeIdItem[] typeArray = new TypeIdItem[typeList.size()]; + typeList.toArray(typeArray); + TypeListItem typeListItem = new TypeListItem(dexFile, typeArray); + return dexFile.TypeListsSection.intern(typeListItem); + } + + /** {@inheritDoc} */ + protected void readItem(Input in, ReadContext readContext) { + int size = in.readInt(); + typeList = new TypeIdItem[size]; + for (int i=0; i otherSize) { + return 1; + } else { + return 0; + } + } + + /** + * @return the number of registers required for this TypeListItem + */ + public int getRegisterCount() { + int wordCount = 0; + for (TypeIdItem typeIdItem: typeList) { + wordCount += typeIdItem.getRegisterCount(); + } + return wordCount; + } + + /** + * @return a string consisting of the type descriptors in this TypeListItem + * that are separated by the given separator + * @param separator the separator between each type + */ + public String getTypeListString(String separator) { + int size = 0; + for (TypeIdItem typeIdItem: typeList) { + size += typeIdItem.getTypeDescriptor().length(); + size += separator.length(); + } + + StringBuilder sb = new StringBuilder(size); + for (TypeIdItem typeIdItem: typeList) { + sb.append(typeIdItem.getTypeDescriptor()); + sb.append(separator); + } + if (typeList.length > 0) { + sb.delete(sb.length() - separator.length(), sb.length()); + } + return sb.toString(); + } + + /** + * @return a string consisting of the shorty form of the type descriptors in this + * TypeListItem that are directly concatenated together + */ + public String getShortyString() { + StringBuilder sb = new StringBuilder(); + for (TypeIdItem typeIdItem: typeList) { + sb.append(typeIdItem.toShorty()); + } + return sb.toString(); + } + + /** + * @param index the index of the TypeIdItem to get + * @return the TypeIdItem at the given index + */ + public TypeIdItem getTypeIdItem(int index) { + return typeList[index]; + } + + /** + * @return the number of types in this TypeListItem + */ + public int getTypeCount() { + return typeList.length; + } + + /** + * @return an array of the TypeIdItems in this TypeListItem + */ + public List getTypes() { + return new ReadOnlyArrayList(typeList); + } + + /** + * calculate and cache the hashcode + */ + private void calcHashCode() { + int hashCode = 1; + + for (TypeIdItem typeIdItem: typeList) { + hashCode = 31 * hashCode + typeIdItem.hashCode(); + } + this.hashCode = hashCode; + } + + @Override + public int hashCode() { + //there's a small possibility that the actual hash code will be 0. If so, we'll + //just end up recalculating it each time + if (hashCode == 0) + calcHashCode(); + return hashCode; + } + + @Override + public boolean equals(Object o) { + if (this==o) { + return true; + } + if (o==null || !this.getClass().equals(o.getClass())) { + return false; + } + + //This assumes that the referenced items have been interned in both objects. + //This is a valid assumption because all outside code must use the static + //"getInterned..." style methods to make new items, and any item created + //internally is guaranteed to be interned + TypeListItem other = (TypeListItem)o; + if (typeList.length != other.typeList.length) { + return false; + } + + for (int i=0; i accessFlagsByName; - - static { - accessFlagsByName = new HashMap(); - for (AccessFlags accessFlag: AccessFlags.values()) { - accessFlagsByName.put(accessFlag.accessFlagName, accessFlag); - } - } - - private AccessFlags(int value, String accessFlagName, boolean validForClass, boolean validForMethod, - boolean validForField) { - this.value = value; - this.accessFlagName = accessFlagName; - this.validForClass = validForClass; - this.validForMethod = validForMethod; - this.validForField = validForField; - } - - public static AccessFlags[] getAccessFlagsForClass(int accessFlagValue) { - int size = 0; - for (AccessFlags accessFlag: AccessFlags.values()) { - if (accessFlag.validForClass && (accessFlagValue & accessFlag.value) != 0) { - size++; - } - } - - AccessFlags[] accessFlags = new AccessFlags[size]; - int accessFlagsPosition = 0; - for (AccessFlags accessFlag: AccessFlags.values()) { - if (accessFlag.validForClass && (accessFlagValue & accessFlag.value) != 0) { - accessFlags[accessFlagsPosition++] = accessFlag; - } - } - return accessFlags; - } - - private static String formatAccessFlags(AccessFlags[] accessFlags) { - int size = 0; - for (AccessFlags accessFlag: accessFlags) { - size += accessFlag.toString().length() + 1; - } - - StringBuilder sb = new StringBuilder(size); - for (AccessFlags accessFlag: accessFlags) { - sb.append(accessFlag.toString()); - sb.append(" "); - } - if (accessFlags.length > 0) { - sb.delete(sb.length() - 1, sb.length()); - } - return sb.toString(); - } - - public static String formatAccessFlagsForClass(int accessFlagValue) { - return formatAccessFlags(getAccessFlagsForClass(accessFlagValue)); - } - - public static AccessFlags[] getAccessFlagsForMethod(int accessFlagValue) { - int size = 0; - for (AccessFlags accessFlag: AccessFlags.values()) { - if (accessFlag.validForMethod && (accessFlagValue & accessFlag.value) != 0) { - size++; - } - } - - AccessFlags[] accessFlags = new AccessFlags[size]; - int accessFlagsPosition = 0; - for (AccessFlags accessFlag: AccessFlags.values()) { - if (accessFlag.validForMethod && (accessFlagValue & accessFlag.value) != 0) { - accessFlags[accessFlagsPosition++] = accessFlag; - } - } - return accessFlags; - } - - public static String formatAccessFlagsForMethod(int accessFlagValue) { - return formatAccessFlags(getAccessFlagsForMethod(accessFlagValue)); - } - - public static AccessFlags[] getAccessFlagsForField(int accessFlagValue) { - int size = 0; - for (AccessFlags accessFlag: AccessFlags.values()) { - if (accessFlag.validForField && (accessFlagValue & accessFlag.value) != 0) { - size++; - } - } - - AccessFlags[] accessFlags = new AccessFlags[size]; - int accessFlagsPosition = 0; - for (AccessFlags accessFlag: AccessFlags.values()) { - if (accessFlag.validForField && (accessFlagValue & accessFlag.value) != 0) { - accessFlags[accessFlagsPosition++] = accessFlag; - } - } - return accessFlags; - } - - public static String formatAccessFlagsForField(int accessFlagValue) { - return formatAccessFlags(getAccessFlagsForField(accessFlagValue)); - } - - public static AccessFlags getAccessFlag(String accessFlag) { - return accessFlagsByName.get(accessFlag); - } - - public int getValue() { - return value; - } - - public String toString() { - return accessFlagName; - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Util; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public enum AccessFlags +{ + PUBLIC(0x1, "public", true, true, true), + PRIVATE(0x2, "private", true, true, true), + PROTECTED(0x4, "protected", true, true, true), + STATIC(0x8, "static", true, true, true), + FINAL(0x10, "final", true, true, true), + SYNCHRONIZED(0x20, "synchronized", false, true, false), + VOLATILE(0x40, "volatile", false, false, true), + BRIDGE(0x40, "bridge", false, true, false), + TRANSIENT(0x80, "transient", false, false, true), + VARARGS(0x80, "varargs", false, true, false), + NATIVE(0x100, "native", false, true, false), + INTERFACE(0x200, "interface", true, false, false), + ABSTRACT(0x400, "abstract", true, true, false), + STRICTFP(0x800, "strictfp", false, true, false), + SYNTHETIC(0x1000, "synthetic", true, true, true), + ANNOTATION(0x2000, "annotation", true, false, false), + ENUM(0x4000, "enum", true, false, true), + CONSTRUCTOR(0x10000, "constructor", false, true, false), + DECLARED_SYNCHRONIZED(0x20000, "declared-synchronized", false, true, false); + + private int value; + private String accessFlagName; + private boolean validForClass; + private boolean validForMethod; + private boolean validForField; + + private static HashMap accessFlagsByName; + + static { + accessFlagsByName = new HashMap(); + for (AccessFlags accessFlag: AccessFlags.values()) { + accessFlagsByName.put(accessFlag.accessFlagName, accessFlag); + } + } + + private AccessFlags(int value, String accessFlagName, boolean validForClass, boolean validForMethod, + boolean validForField) { + this.value = value; + this.accessFlagName = accessFlagName; + this.validForClass = validForClass; + this.validForMethod = validForMethod; + this.validForField = validForField; + } + + public static AccessFlags[] getAccessFlagsForClass(int accessFlagValue) { + int size = 0; + for (AccessFlags accessFlag: AccessFlags.values()) { + if (accessFlag.validForClass && (accessFlagValue & accessFlag.value) != 0) { + size++; + } + } + + AccessFlags[] accessFlags = new AccessFlags[size]; + int accessFlagsPosition = 0; + for (AccessFlags accessFlag: AccessFlags.values()) { + if (accessFlag.validForClass && (accessFlagValue & accessFlag.value) != 0) { + accessFlags[accessFlagsPosition++] = accessFlag; + } + } + return accessFlags; + } + + private static String formatAccessFlags(AccessFlags[] accessFlags) { + int size = 0; + for (AccessFlags accessFlag: accessFlags) { + size += accessFlag.toString().length() + 1; + } + + StringBuilder sb = new StringBuilder(size); + for (AccessFlags accessFlag: accessFlags) { + sb.append(accessFlag.toString()); + sb.append(" "); + } + if (accessFlags.length > 0) { + sb.delete(sb.length() - 1, sb.length()); + } + return sb.toString(); + } + + public static String formatAccessFlagsForClass(int accessFlagValue) { + return formatAccessFlags(getAccessFlagsForClass(accessFlagValue)); + } + + public static AccessFlags[] getAccessFlagsForMethod(int accessFlagValue) { + int size = 0; + for (AccessFlags accessFlag: AccessFlags.values()) { + if (accessFlag.validForMethod && (accessFlagValue & accessFlag.value) != 0) { + size++; + } + } + + AccessFlags[] accessFlags = new AccessFlags[size]; + int accessFlagsPosition = 0; + for (AccessFlags accessFlag: AccessFlags.values()) { + if (accessFlag.validForMethod && (accessFlagValue & accessFlag.value) != 0) { + accessFlags[accessFlagsPosition++] = accessFlag; + } + } + return accessFlags; + } + + public static String formatAccessFlagsForMethod(int accessFlagValue) { + return formatAccessFlags(getAccessFlagsForMethod(accessFlagValue)); + } + + public static AccessFlags[] getAccessFlagsForField(int accessFlagValue) { + int size = 0; + for (AccessFlags accessFlag: AccessFlags.values()) { + if (accessFlag.validForField && (accessFlagValue & accessFlag.value) != 0) { + size++; + } + } + + AccessFlags[] accessFlags = new AccessFlags[size]; + int accessFlagsPosition = 0; + for (AccessFlags accessFlag: AccessFlags.values()) { + if (accessFlag.validForField && (accessFlagValue & accessFlag.value) != 0) { + accessFlags[accessFlagsPosition++] = accessFlag; + } + } + return accessFlags; + } + + public static String formatAccessFlagsForField(int accessFlagValue) { + return formatAccessFlags(getAccessFlagsForField(accessFlagValue)); + } + + public static AccessFlags getAccessFlag(String accessFlag) { + return accessFlagsByName.get(accessFlag); + } + + public int getValue() { + return value; + } + + public String toString() { + return accessFlagName; + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/Util/ByteArrayInput.java b/dexlib/src/main/java/org/jf/dexlib/Util/ByteArrayInput.java index 63196198..8ebab80c 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Util/ByteArrayInput.java +++ b/dexlib/src/main/java/org/jf/dexlib/Util/ByteArrayInput.java @@ -1,364 +1,364 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Util; - -/** - * Implementation of {@link Input} which reads the data from a - * byte[] instance. - * - *

      Note: As per the {@link Input } interface, multi-byte - * reads all use little-endian order.

      - */ -public class ByteArrayInput - implements Input { - - /** non-null; the data itself */ - private byte[] data; - - /** >= 0; current read cursor */ - private int cursor; - - /** - * Constructs an instance with the given data - * - * @param data non-null; data array to use for input - */ - public ByteArrayInput(byte[] data) { - if (data == null) { - throw new NullPointerException("data == null"); - } - - this.data = data; - this.cursor = 0; - } - - /** - * Gets the underlying byte[] of this instance - * - * @return non-null; the byte[] - */ - public byte[] getArray() { - return data; - } - - /** {@inheritDoc} */ - public int getCursor() { - return cursor; - } - - /** {@inheritDoc} */ - public void setCursor(int cursor) { - if (cursor < 0 || cursor >= data.length) - throw new IndexOutOfBoundsException("The provided cursor value " + - "is not within the bounds of this instance's data array"); - this.cursor = cursor; - } - - /** {@inheritDoc} */ - public void assertCursor(int expectedCursor) { - if (cursor != expectedCursor) { - throw new ExceptionWithContext("expected cursor " + - expectedCursor + "; actual value: " + cursor); - } - } - - /** {@inheritDoc} */ - public byte readByte() { - int readAt = cursor; - int end = readAt + 1; - - if (end > data.length) { - throwBounds(); - } - - cursor = end; - return data[readAt]; - } - - /** {@inheritDoc} */ - public int readShort() { - int readAt = cursor; - int end = readAt + 2; - - if (end > data.length) { - throwBounds(); - } - - cursor = end; - return (int)((data[readAt] & 0xff) + - ((data[readAt + 1] & 0xff) << 8)); - } - - /** {@inheritDoc} */ - public int readInt() { - int readAt = cursor; - int end = readAt + 4; - - if (end > data.length) { - throwBounds(); - } - - cursor = end; - return (data[readAt] & 0xff) + - ((data[readAt + 1] & 0xff) << 8) + - ((data[readAt + 2] & 0xff) << 16) + - ((data[readAt + 3] & 0xff) << 24); - } - - /** {@inheritDoc} */ - public long readLong() { - int readAt = cursor; - int end = readAt + 8; - - if (end > data.length) { - throwBounds(); - } - - cursor = end; - - return (data[readAt] & 0xffL) | - ((data[readAt + 1] & 0xffL) << 8) | - ((data[readAt + 2] & 0xffL) << 16) | - ((data[readAt + 3] & 0xffL) << 24) | - ((data[readAt + 4] & 0xffL) << 32) | - ((data[readAt + 5] & 0xffL) << 40) | - ((data[readAt + 6] & 0xffL) << 48) | - ((data[readAt + 7] & 0xffL) << 58); - } - - - /** {@inheritDoc} */ - public int readUnsignedOrSignedLeb128() { - int end = cursor; - int currentByteValue; - int result; - - result = data[end++] & 0xff; - if (result > 0x7f) { - currentByteValue = data[end++] & 0xff; - result = (result & 0x7f) | ((currentByteValue & 0x7f) << 7); - if (currentByteValue > 0x7f) { - currentByteValue = data[end++] & 0xff; - result |= (currentByteValue & 0x7f) << 14; - if (currentByteValue > 0x7f) { - currentByteValue = data[end++] & 0xff; - result |= (currentByteValue & 0x7f) << 21; - if (currentByteValue > 0x7f) { - currentByteValue = data[end++] & 0xff; - if (currentByteValue > 0x0f) { - throwInvalidLeb(); - } - result |= currentByteValue << 28; - } - } - } - } else { - cursor = end; - return result; - } - - cursor = end; - - //If the last byte is 0, then this was an unsigned value (incorrectly) written in a signed format - //The caller wants to know if this is the case, so we'll return the negated value instead - //If there was only a single byte that had a value of 0, then we would have returned in the above - //"else" - if (data[end-1] == 0) { - return ~result; - } - return result; - } - - - - - /** {@inheritDoc} */ - public int readUnsignedLeb128() { - int end = cursor; - int currentByteValue; - int result; - - result = data[end++] & 0xff; - if (result > 0x7f) { - currentByteValue = data[end++] & 0xff; - result = (result & 0x7f) | ((currentByteValue & 0x7f) << 7); - if (currentByteValue > 0x7f) { - currentByteValue = data[end++] & 0xff; - result |= (currentByteValue & 0x7f) << 14; - if (currentByteValue > 0x7f) { - currentByteValue = data[end++] & 0xff; - result |= (currentByteValue & 0x7f) << 21; - if (currentByteValue > 0x7f) { - currentByteValue = data[end++] & 0xff; - if (currentByteValue > 0x0f) { - throwInvalidLeb(); - } - result |= currentByteValue << 28; - } - } - } - } - - cursor = end; - return result; - } - - /** {@inheritDoc} */ - public int readSignedLeb128() { - int end = cursor; - int currentByteValue; - int result; - - result = data[end++] & 0xff; - if (result <= 0x7f) { - result = (result << 25) >> 25; - } else { - currentByteValue = data[end++] & 0xff; - result = (result & 0x7f) | ((currentByteValue & 0x7f) << 7); - if (currentByteValue <= 0x7f) { - result = (result << 18) >> 18; - } else { - currentByteValue = data[end++] & 0xff; - result |= (currentByteValue & 0x7f) << 14; - if (currentByteValue <= 0x7f) { - result = (result << 11) >> 11; - } else { - currentByteValue = data[end++] & 0xff; - result |= (currentByteValue & 0x7f) << 21; - if (currentByteValue <= 0x7f) { - result = (result << 4) >> 4; - } else { - currentByteValue = data[end++] & 0xff; - if (currentByteValue > 0x0f) { - throwInvalidLeb(); - } - result |= currentByteValue << 28; - } - } - } - } - - cursor = end; - return result; - } - - /** {@inheritDoc} */ - public void read(byte[] bytes, int offset, int length) { - int end = cursor + length; - - if (end > data.length) { - throwBounds(); - } - - System.arraycopy(data, cursor, bytes, offset, length); - cursor = end; - } - - /** {@inheritDoc} */ - public void read(byte[] bytes) { - int length = bytes.length; - int end = cursor + length; - - if (end > data.length) { - throwBounds(); - } - - System.arraycopy(data, cursor, bytes, 0, length); - cursor = end; - } - - /** {@inheritDoc} */ - public byte[] readBytes(int length) { - int end = cursor + length; - - if (end > data.length) { - throwBounds(); - } - - byte[] result = new byte[length]; - System.arraycopy(data, cursor, result, 0, length); - cursor = end; - return result; - } - - /** {@inheritDoc} */ - public byte[] readNullTerminatedBytes() { - int startPosition = cursor; - while (data[cursor] != 0) { - cursor++; - if (cursor >= data.length) { - throwBounds(); - } - } - int byteCount = cursor - startPosition; - //skip the terminating null - cursor++; - - byte[] result = new byte[byteCount]; - System.arraycopy(data, startPosition, result, 0, byteCount); - return result; - } - - /** {@inheritDoc} */ - public void skipBytes(int count) { - int end = cursor + count; - - if (end > data.length) { - throwBounds(); - } - - cursor = end; - } - - /** {@inheritDoc} */ - public void alignTo(int alignment) { - int end = AlignmentUtils.alignOffset(cursor, alignment); - - if (end > data.length) { - throwBounds(); - } - - cursor = end; - } - - /** - * Throws the excpetion for when an attempt is made to read past the - * end of the instance. - */ - private static void throwBounds() { - throw new IndexOutOfBoundsException("attempt to read past the end"); - } - - /** - * Throws the exception for when an invalid LEB128 value is encountered - */ - private static void throwInvalidLeb() { - throw new RuntimeException("invalid LEB128 integer encountered"); - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Util; + +/** + * Implementation of {@link Input} which reads the data from a + * byte[] instance. + * + *

      Note: As per the {@link Input } interface, multi-byte + * reads all use little-endian order.

      + */ +public class ByteArrayInput + implements Input { + + /** non-null; the data itself */ + private byte[] data; + + /** >= 0; current read cursor */ + private int cursor; + + /** + * Constructs an instance with the given data + * + * @param data non-null; data array to use for input + */ + public ByteArrayInput(byte[] data) { + if (data == null) { + throw new NullPointerException("data == null"); + } + + this.data = data; + this.cursor = 0; + } + + /** + * Gets the underlying byte[] of this instance + * + * @return non-null; the byte[] + */ + public byte[] getArray() { + return data; + } + + /** {@inheritDoc} */ + public int getCursor() { + return cursor; + } + + /** {@inheritDoc} */ + public void setCursor(int cursor) { + if (cursor < 0 || cursor >= data.length) + throw new IndexOutOfBoundsException("The provided cursor value " + + "is not within the bounds of this instance's data array"); + this.cursor = cursor; + } + + /** {@inheritDoc} */ + public void assertCursor(int expectedCursor) { + if (cursor != expectedCursor) { + throw new ExceptionWithContext("expected cursor " + + expectedCursor + "; actual value: " + cursor); + } + } + + /** {@inheritDoc} */ + public byte readByte() { + int readAt = cursor; + int end = readAt + 1; + + if (end > data.length) { + throwBounds(); + } + + cursor = end; + return data[readAt]; + } + + /** {@inheritDoc} */ + public int readShort() { + int readAt = cursor; + int end = readAt + 2; + + if (end > data.length) { + throwBounds(); + } + + cursor = end; + return (int)((data[readAt] & 0xff) + + ((data[readAt + 1] & 0xff) << 8)); + } + + /** {@inheritDoc} */ + public int readInt() { + int readAt = cursor; + int end = readAt + 4; + + if (end > data.length) { + throwBounds(); + } + + cursor = end; + return (data[readAt] & 0xff) + + ((data[readAt + 1] & 0xff) << 8) + + ((data[readAt + 2] & 0xff) << 16) + + ((data[readAt + 3] & 0xff) << 24); + } + + /** {@inheritDoc} */ + public long readLong() { + int readAt = cursor; + int end = readAt + 8; + + if (end > data.length) { + throwBounds(); + } + + cursor = end; + + return (data[readAt] & 0xffL) | + ((data[readAt + 1] & 0xffL) << 8) | + ((data[readAt + 2] & 0xffL) << 16) | + ((data[readAt + 3] & 0xffL) << 24) | + ((data[readAt + 4] & 0xffL) << 32) | + ((data[readAt + 5] & 0xffL) << 40) | + ((data[readAt + 6] & 0xffL) << 48) | + ((data[readAt + 7] & 0xffL) << 58); + } + + + /** {@inheritDoc} */ + public int readUnsignedOrSignedLeb128() { + int end = cursor; + int currentByteValue; + int result; + + result = data[end++] & 0xff; + if (result > 0x7f) { + currentByteValue = data[end++] & 0xff; + result = (result & 0x7f) | ((currentByteValue & 0x7f) << 7); + if (currentByteValue > 0x7f) { + currentByteValue = data[end++] & 0xff; + result |= (currentByteValue & 0x7f) << 14; + if (currentByteValue > 0x7f) { + currentByteValue = data[end++] & 0xff; + result |= (currentByteValue & 0x7f) << 21; + if (currentByteValue > 0x7f) { + currentByteValue = data[end++] & 0xff; + if (currentByteValue > 0x0f) { + throwInvalidLeb(); + } + result |= currentByteValue << 28; + } + } + } + } else { + cursor = end; + return result; + } + + cursor = end; + + //If the last byte is 0, then this was an unsigned value (incorrectly) written in a signed format + //The caller wants to know if this is the case, so we'll return the negated value instead + //If there was only a single byte that had a value of 0, then we would have returned in the above + //"else" + if (data[end-1] == 0) { + return ~result; + } + return result; + } + + + + + /** {@inheritDoc} */ + public int readUnsignedLeb128() { + int end = cursor; + int currentByteValue; + int result; + + result = data[end++] & 0xff; + if (result > 0x7f) { + currentByteValue = data[end++] & 0xff; + result = (result & 0x7f) | ((currentByteValue & 0x7f) << 7); + if (currentByteValue > 0x7f) { + currentByteValue = data[end++] & 0xff; + result |= (currentByteValue & 0x7f) << 14; + if (currentByteValue > 0x7f) { + currentByteValue = data[end++] & 0xff; + result |= (currentByteValue & 0x7f) << 21; + if (currentByteValue > 0x7f) { + currentByteValue = data[end++] & 0xff; + if (currentByteValue > 0x0f) { + throwInvalidLeb(); + } + result |= currentByteValue << 28; + } + } + } + } + + cursor = end; + return result; + } + + /** {@inheritDoc} */ + public int readSignedLeb128() { + int end = cursor; + int currentByteValue; + int result; + + result = data[end++] & 0xff; + if (result <= 0x7f) { + result = (result << 25) >> 25; + } else { + currentByteValue = data[end++] & 0xff; + result = (result & 0x7f) | ((currentByteValue & 0x7f) << 7); + if (currentByteValue <= 0x7f) { + result = (result << 18) >> 18; + } else { + currentByteValue = data[end++] & 0xff; + result |= (currentByteValue & 0x7f) << 14; + if (currentByteValue <= 0x7f) { + result = (result << 11) >> 11; + } else { + currentByteValue = data[end++] & 0xff; + result |= (currentByteValue & 0x7f) << 21; + if (currentByteValue <= 0x7f) { + result = (result << 4) >> 4; + } else { + currentByteValue = data[end++] & 0xff; + if (currentByteValue > 0x0f) { + throwInvalidLeb(); + } + result |= currentByteValue << 28; + } + } + } + } + + cursor = end; + return result; + } + + /** {@inheritDoc} */ + public void read(byte[] bytes, int offset, int length) { + int end = cursor + length; + + if (end > data.length) { + throwBounds(); + } + + System.arraycopy(data, cursor, bytes, offset, length); + cursor = end; + } + + /** {@inheritDoc} */ + public void read(byte[] bytes) { + int length = bytes.length; + int end = cursor + length; + + if (end > data.length) { + throwBounds(); + } + + System.arraycopy(data, cursor, bytes, 0, length); + cursor = end; + } + + /** {@inheritDoc} */ + public byte[] readBytes(int length) { + int end = cursor + length; + + if (end > data.length) { + throwBounds(); + } + + byte[] result = new byte[length]; + System.arraycopy(data, cursor, result, 0, length); + cursor = end; + return result; + } + + /** {@inheritDoc} */ + public byte[] readNullTerminatedBytes() { + int startPosition = cursor; + while (data[cursor] != 0) { + cursor++; + if (cursor >= data.length) { + throwBounds(); + } + } + int byteCount = cursor - startPosition; + //skip the terminating null + cursor++; + + byte[] result = new byte[byteCount]; + System.arraycopy(data, startPosition, result, 0, byteCount); + return result; + } + + /** {@inheritDoc} */ + public void skipBytes(int count) { + int end = cursor + count; + + if (end > data.length) { + throwBounds(); + } + + cursor = end; + } + + /** {@inheritDoc} */ + public void alignTo(int alignment) { + int end = AlignmentUtils.alignOffset(cursor, alignment); + + if (end > data.length) { + throwBounds(); + } + + cursor = end; + } + + /** + * Throws the excpetion for when an attempt is made to read past the + * end of the instance. + */ + private static void throwBounds() { + throw new IndexOutOfBoundsException("attempt to read past the end"); + } + + /** + * Throws the exception for when an invalid LEB128 value is encountered + */ + private static void throwInvalidLeb() { + throw new RuntimeException("invalid LEB128 integer encountered"); + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/Util/DebugInfoBuilder.java b/dexlib/src/main/java/org/jf/dexlib/Util/DebugInfoBuilder.java index 8fcb93f3..b2176bb7 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Util/DebugInfoBuilder.java +++ b/dexlib/src/main/java/org/jf/dexlib/Util/DebugInfoBuilder.java @@ -1,451 +1,451 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Util; - -import org.jf.dexlib.*; - -import java.util.ArrayList; -import java.util.List; - -/** - * This class is intended to provide an easy to use container to build up a method's debug info. You can easily add - * an "event" at a specific address, where an event is something like a line number, start/end local, etc. - * The events must be added such that the code addresses increase monotonically. This matches how a parser would - * generally behave, and is intended to increase performance. - */ -public class DebugInfoBuilder -{ - private static final int LINE_BASE = -4; - private static final int LINE_RANGE = 15; - private static final int FIRST_SPECIAL = 0x0a; - - private int lineStart = 0; - private ArrayList parameterNames = new ArrayList(); - private ArrayList events = new ArrayList(); - private int lastAddress = 0; - - private boolean hasData; - - private int currentAddress; - private int currentLine; - - public DebugInfoBuilder() { - } - - private void checkAddress(int address) { - if (lastAddress > address) { - throw new RuntimeException("Cannot add an event with an address before the address of the prior event"); - } - } - - public void addParameterName(String parameterName) { - if (parameterName != null) { - hasData = true; - } - - parameterNames.add(parameterName); - } - - public void addLine(int address, int line) { - hasData = true; - - checkAddress(address); - - if (lineStart == 0) { - lineStart = line; - } - - events.add(new LineEvent(address, line)); - } - - public void addLocal(int address, int registerNumber, String localName, String localType) { - hasData = true; - - checkAddress(address); - - events.add(new StartLocalEvent(address, registerNumber, localName, localType)); - } - - public void addLocalExtended(int address, int registerNumber, String localName, String localType, - String signature) { - hasData = true; - - checkAddress(address); - - events.add(new StartLocalExtendedEvent(address, registerNumber, localName, localType, signature)); - } - - public void addEndLocal(int address, int registerNumber) { - hasData = true; - - checkAddress(address); - - events.add(new EndLocalEvent(address, registerNumber)); - } - - public void addRestartLocal(int address, int registerNumber) { - hasData = true; - - checkAddress(address); - - events.add(new RestartLocalEvent(address, registerNumber)); - } - - public void addPrologue(int address) { - hasData = true; - - checkAddress(address); - - events.add(new PrologueEvent(address)); - } - - public void addEpilogue(int address) { - hasData = true; - - checkAddress(address); - - events.add(new EpilogueEvent(address)); - } - - public void addSetFile(int address, String fileName) { - hasData = true; - - checkAddress(address); - - events.add(new SetFileEvent(address, fileName)); - } - - public int getParameterNameCount() { - return parameterNames.size(); - } - - public DebugInfoItem encodeDebugInfo(DexFile dexFile) { - if (!hasData) { - return null; - } - - ByteArrayOutput out = new ByteArrayOutput(); - StringIdItem[] parameterNamesArray = new StringIdItem[parameterNames.size()]; - ArrayList referencedItems = new ArrayList(); - - if (lineStart == 0) { - lineStart = 1; - } - - currentLine = lineStart; - - for (Event event: events) { - event.emit(dexFile, out, referencedItems); - } - emitEndSequence(out); - - int index = 0; - for (String parameterName: parameterNames) { - if (parameterName == null) { - parameterNamesArray[index++] = null; - } else { - parameterNamesArray[index++] = StringIdItem.getInternedStringIdItem(dexFile, parameterName); - } - } - - Item[] referencedItemsArray = new Item[referencedItems.size()]; - referencedItems.toArray(referencedItemsArray); - return DebugInfoItem.getInternedDebugInfoItem(dexFile, lineStart, parameterNamesArray, out.getArray(), - referencedItemsArray); - } - - private interface Event - { - int getAddress(); - void emit(DexFile dexFile, Output out, List referencedItems); - } - - private void emitEndSequence(Output out) { - out.writeByte(0); - } - - private void emitAdvancePC(Output out, int address) { - int addressDelta = address-currentAddress; - - if (addressDelta > 0) { - out.writeByte(1); - out.writeUnsignedLeb128(addressDelta); - currentAddress = address; - } - } - - private void emitAdvanceLine(Output out, int lineDelta) { - out.writeByte(2); - out.writeSignedLeb128(lineDelta); - } - - private void emitStartLocal(Output out, int registerNum) { - out.writeByte(3); - out.writeUnsignedLeb128(registerNum); - out.writeByte(1); - out.writeByte(1); - } - - private void emitStartLocalExtended(Output out, int registerNum) { - out.writeByte(4); - out.writeUnsignedLeb128(registerNum); - out.writeByte(1); - out.writeByte(1); - out.writeByte(1); - } - - private void emitEndLocal(Output out, int registerNum) { - out.writeByte(5); - out.writeUnsignedLeb128(registerNum); - } - - private void emitRestartLocal(Output out, int registerNum) { - out.writeByte(6); - out.writeUnsignedLeb128(registerNum); - } - - private void emitSetPrologueEnd(Output out) { - out.writeByte(7); - } - - private void emitSetEpilogueBegin(Output out) { - out.writeByte(8); - } - - private void emitSetFile(Output out) { - out.writeByte(9); - out.writeByte(1); - } - - private void emitSpecialOpcode(Output out, byte opcode) { - out.writeByte(opcode); - } - - private class LineEvent implements Event - { - private final int address; - private final int line; - - public LineEvent(int address, int line) { - this.address = address; - this.line = line; - } - - public int getAddress() { - return address; - } - - public void emit(DexFile dexFile, Output out, List referencedItems) { - int lineDelta = line - currentLine; - int addressDelta = address - currentAddress; - - if (lineDelta < -4 || lineDelta > 10) { - emitAdvanceLine(out, lineDelta); - lineDelta = 0; - } - if (lineDelta < 2 && addressDelta > 16 || lineDelta > 1 && addressDelta > 15) { - emitAdvancePC(out, address); - addressDelta = 0; - } - - //TODO: need to handle the case when the line delta is larger than a signed int - emitSpecialOpcode(out, calculateSpecialOpcode(lineDelta, addressDelta)); - - currentAddress = address; - currentLine = line; - } - - private byte calculateSpecialOpcode(int lineDelta, int addressDelta) { - return (byte)(FIRST_SPECIAL + (addressDelta * LINE_RANGE) + (lineDelta - LINE_BASE)); - } - } - - private class StartLocalEvent implements Event - { - private final int address; - private final int registerNum; - private final String localName; - private final String localType; - - public StartLocalEvent(int address, int registerNum, String localName, String localType) { - this.address = address; - this.registerNum = registerNum; - this.localName = localName; - this.localType = localType; - } - - public int getAddress() { - return address; - } - - public void emit(DexFile dexFile, Output out, List referencedItems) { - emitAdvancePC(out, address); - emitStartLocal(out, registerNum); - referencedItems.add(localName==null?null:StringIdItem.getInternedStringIdItem(dexFile, localName)); - referencedItems.add(localType==null?null:TypeIdItem.getInternedTypeIdItem(dexFile, - StringIdItem.getInternedStringIdItem(dexFile, localType))); - } - } - - private class StartLocalExtendedEvent implements Event - { - private final int address; - private final int registerNum; - private final String localName; - private final String localType; - private final String signature; - - public StartLocalExtendedEvent(int address, int registerNum, String localName, String localType, - String signature) { - this.address = address; - this.registerNum = registerNum; - this.localName = localName; - this.localType = localType; - this.signature = signature; - } - - public int getAddress() { - return address; - } - - public void emit(DexFile dexFile, Output out, List referencedItems) { - emitAdvancePC(out, address); - emitStartLocalExtended(out, registerNum); - if (localName != null) { - referencedItems.add(StringIdItem.getInternedStringIdItem(dexFile, localName)); - } - if (localType != null) { - referencedItems.add(TypeIdItem.getInternedTypeIdItem(dexFile, - StringIdItem.getInternedStringIdItem(dexFile, localType))); - } - if (signature != null) { - referencedItems.add(StringIdItem.getInternedStringIdItem(dexFile, signature)); - } - } - } - - private class EndLocalEvent implements Event - { - private final int address; - private final int registerNum; - - public EndLocalEvent(int address, int registerNum) { - this.address = address; - this.registerNum = registerNum; - } - - public int getAddress() { - return address; - } - - public void emit(DexFile dexFile, Output out, List referencedItems) { - emitAdvancePC(out, address); - emitEndLocal(out, registerNum); - } - } - - private class RestartLocalEvent implements Event - { - private final int address; - private final int registerNum; - - public RestartLocalEvent(int address, int registerNum) { - this.address = address; - this.registerNum = registerNum; - } - - public int getAddress() { - return address; - } - - public void emit(DexFile dexFile, Output out, List referencedItems) { - emitAdvancePC(out, address); - emitRestartLocal(out, registerNum); - } - } - - private class PrologueEvent implements Event - { - private final int address; - - public PrologueEvent(int address) { - this.address = address; - } - - public int getAddress() { - return address; - } - - public void emit(DexFile dexFile, Output out, List referencedItems) { - emitAdvancePC(out, address); - emitSetPrologueEnd(out); - } - } - - private class EpilogueEvent implements Event - { - private final int address; - - public EpilogueEvent(int address) { - this.address = address; - } - - public int getAddress() { - return address; - } - - public void emit(DexFile dexFile, Output out, List referencedItems) { - emitAdvancePC(out, address); - emitSetEpilogueBegin(out); - } - } - - private class SetFileEvent implements Event - { - private final int address; - private final String fileName; - - public SetFileEvent(int address, String fileName) { - this.address = address; - this.fileName = fileName; - } - - public int getAddress() { - return address; - } - - public void emit(DexFile dexFile, Output out, List referencedItems) { - emitAdvancePC(out, address); - emitSetFile(out); - if (fileName != null) { - referencedItems.add(StringIdItem.getInternedStringIdItem(dexFile, fileName)); - } - } - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Util; + +import org.jf.dexlib.*; + +import java.util.ArrayList; +import java.util.List; + +/** + * This class is intended to provide an easy to use container to build up a method's debug info. You can easily add + * an "event" at a specific address, where an event is something like a line number, start/end local, etc. + * The events must be added such that the code addresses increase monotonically. This matches how a parser would + * generally behave, and is intended to increase performance. + */ +public class DebugInfoBuilder +{ + private static final int LINE_BASE = -4; + private static final int LINE_RANGE = 15; + private static final int FIRST_SPECIAL = 0x0a; + + private int lineStart = 0; + private ArrayList parameterNames = new ArrayList(); + private ArrayList events = new ArrayList(); + private int lastAddress = 0; + + private boolean hasData; + + private int currentAddress; + private int currentLine; + + public DebugInfoBuilder() { + } + + private void checkAddress(int address) { + if (lastAddress > address) { + throw new RuntimeException("Cannot add an event with an address before the address of the prior event"); + } + } + + public void addParameterName(String parameterName) { + if (parameterName != null) { + hasData = true; + } + + parameterNames.add(parameterName); + } + + public void addLine(int address, int line) { + hasData = true; + + checkAddress(address); + + if (lineStart == 0) { + lineStart = line; + } + + events.add(new LineEvent(address, line)); + } + + public void addLocal(int address, int registerNumber, String localName, String localType) { + hasData = true; + + checkAddress(address); + + events.add(new StartLocalEvent(address, registerNumber, localName, localType)); + } + + public void addLocalExtended(int address, int registerNumber, String localName, String localType, + String signature) { + hasData = true; + + checkAddress(address); + + events.add(new StartLocalExtendedEvent(address, registerNumber, localName, localType, signature)); + } + + public void addEndLocal(int address, int registerNumber) { + hasData = true; + + checkAddress(address); + + events.add(new EndLocalEvent(address, registerNumber)); + } + + public void addRestartLocal(int address, int registerNumber) { + hasData = true; + + checkAddress(address); + + events.add(new RestartLocalEvent(address, registerNumber)); + } + + public void addPrologue(int address) { + hasData = true; + + checkAddress(address); + + events.add(new PrologueEvent(address)); + } + + public void addEpilogue(int address) { + hasData = true; + + checkAddress(address); + + events.add(new EpilogueEvent(address)); + } + + public void addSetFile(int address, String fileName) { + hasData = true; + + checkAddress(address); + + events.add(new SetFileEvent(address, fileName)); + } + + public int getParameterNameCount() { + return parameterNames.size(); + } + + public DebugInfoItem encodeDebugInfo(DexFile dexFile) { + if (!hasData) { + return null; + } + + ByteArrayOutput out = new ByteArrayOutput(); + StringIdItem[] parameterNamesArray = new StringIdItem[parameterNames.size()]; + ArrayList referencedItems = new ArrayList(); + + if (lineStart == 0) { + lineStart = 1; + } + + currentLine = lineStart; + + for (Event event: events) { + event.emit(dexFile, out, referencedItems); + } + emitEndSequence(out); + + int index = 0; + for (String parameterName: parameterNames) { + if (parameterName == null) { + parameterNamesArray[index++] = null; + } else { + parameterNamesArray[index++] = StringIdItem.getInternedStringIdItem(dexFile, parameterName); + } + } + + Item[] referencedItemsArray = new Item[referencedItems.size()]; + referencedItems.toArray(referencedItemsArray); + return DebugInfoItem.getInternedDebugInfoItem(dexFile, lineStart, parameterNamesArray, out.getArray(), + referencedItemsArray); + } + + private interface Event + { + int getAddress(); + void emit(DexFile dexFile, Output out, List referencedItems); + } + + private void emitEndSequence(Output out) { + out.writeByte(0); + } + + private void emitAdvancePC(Output out, int address) { + int addressDelta = address-currentAddress; + + if (addressDelta > 0) { + out.writeByte(1); + out.writeUnsignedLeb128(addressDelta); + currentAddress = address; + } + } + + private void emitAdvanceLine(Output out, int lineDelta) { + out.writeByte(2); + out.writeSignedLeb128(lineDelta); + } + + private void emitStartLocal(Output out, int registerNum) { + out.writeByte(3); + out.writeUnsignedLeb128(registerNum); + out.writeByte(1); + out.writeByte(1); + } + + private void emitStartLocalExtended(Output out, int registerNum) { + out.writeByte(4); + out.writeUnsignedLeb128(registerNum); + out.writeByte(1); + out.writeByte(1); + out.writeByte(1); + } + + private void emitEndLocal(Output out, int registerNum) { + out.writeByte(5); + out.writeUnsignedLeb128(registerNum); + } + + private void emitRestartLocal(Output out, int registerNum) { + out.writeByte(6); + out.writeUnsignedLeb128(registerNum); + } + + private void emitSetPrologueEnd(Output out) { + out.writeByte(7); + } + + private void emitSetEpilogueBegin(Output out) { + out.writeByte(8); + } + + private void emitSetFile(Output out) { + out.writeByte(9); + out.writeByte(1); + } + + private void emitSpecialOpcode(Output out, byte opcode) { + out.writeByte(opcode); + } + + private class LineEvent implements Event + { + private final int address; + private final int line; + + public LineEvent(int address, int line) { + this.address = address; + this.line = line; + } + + public int getAddress() { + return address; + } + + public void emit(DexFile dexFile, Output out, List referencedItems) { + int lineDelta = line - currentLine; + int addressDelta = address - currentAddress; + + if (lineDelta < -4 || lineDelta > 10) { + emitAdvanceLine(out, lineDelta); + lineDelta = 0; + } + if (lineDelta < 2 && addressDelta > 16 || lineDelta > 1 && addressDelta > 15) { + emitAdvancePC(out, address); + addressDelta = 0; + } + + //TODO: need to handle the case when the line delta is larger than a signed int + emitSpecialOpcode(out, calculateSpecialOpcode(lineDelta, addressDelta)); + + currentAddress = address; + currentLine = line; + } + + private byte calculateSpecialOpcode(int lineDelta, int addressDelta) { + return (byte)(FIRST_SPECIAL + (addressDelta * LINE_RANGE) + (lineDelta - LINE_BASE)); + } + } + + private class StartLocalEvent implements Event + { + private final int address; + private final int registerNum; + private final String localName; + private final String localType; + + public StartLocalEvent(int address, int registerNum, String localName, String localType) { + this.address = address; + this.registerNum = registerNum; + this.localName = localName; + this.localType = localType; + } + + public int getAddress() { + return address; + } + + public void emit(DexFile dexFile, Output out, List referencedItems) { + emitAdvancePC(out, address); + emitStartLocal(out, registerNum); + referencedItems.add(localName==null?null:StringIdItem.getInternedStringIdItem(dexFile, localName)); + referencedItems.add(localType==null?null:TypeIdItem.getInternedTypeIdItem(dexFile, + StringIdItem.getInternedStringIdItem(dexFile, localType))); + } + } + + private class StartLocalExtendedEvent implements Event + { + private final int address; + private final int registerNum; + private final String localName; + private final String localType; + private final String signature; + + public StartLocalExtendedEvent(int address, int registerNum, String localName, String localType, + String signature) { + this.address = address; + this.registerNum = registerNum; + this.localName = localName; + this.localType = localType; + this.signature = signature; + } + + public int getAddress() { + return address; + } + + public void emit(DexFile dexFile, Output out, List referencedItems) { + emitAdvancePC(out, address); + emitStartLocalExtended(out, registerNum); + if (localName != null) { + referencedItems.add(StringIdItem.getInternedStringIdItem(dexFile, localName)); + } + if (localType != null) { + referencedItems.add(TypeIdItem.getInternedTypeIdItem(dexFile, + StringIdItem.getInternedStringIdItem(dexFile, localType))); + } + if (signature != null) { + referencedItems.add(StringIdItem.getInternedStringIdItem(dexFile, signature)); + } + } + } + + private class EndLocalEvent implements Event + { + private final int address; + private final int registerNum; + + public EndLocalEvent(int address, int registerNum) { + this.address = address; + this.registerNum = registerNum; + } + + public int getAddress() { + return address; + } + + public void emit(DexFile dexFile, Output out, List referencedItems) { + emitAdvancePC(out, address); + emitEndLocal(out, registerNum); + } + } + + private class RestartLocalEvent implements Event + { + private final int address; + private final int registerNum; + + public RestartLocalEvent(int address, int registerNum) { + this.address = address; + this.registerNum = registerNum; + } + + public int getAddress() { + return address; + } + + public void emit(DexFile dexFile, Output out, List referencedItems) { + emitAdvancePC(out, address); + emitRestartLocal(out, registerNum); + } + } + + private class PrologueEvent implements Event + { + private final int address; + + public PrologueEvent(int address) { + this.address = address; + } + + public int getAddress() { + return address; + } + + public void emit(DexFile dexFile, Output out, List referencedItems) { + emitAdvancePC(out, address); + emitSetPrologueEnd(out); + } + } + + private class EpilogueEvent implements Event + { + private final int address; + + public EpilogueEvent(int address) { + this.address = address; + } + + public int getAddress() { + return address; + } + + public void emit(DexFile dexFile, Output out, List referencedItems) { + emitAdvancePC(out, address); + emitSetEpilogueBegin(out); + } + } + + private class SetFileEvent implements Event + { + private final int address; + private final String fileName; + + public SetFileEvent(int address, String fileName) { + this.address = address; + this.fileName = fileName; + } + + public int getAddress() { + return address; + } + + public void emit(DexFile dexFile, Output out, List referencedItems) { + emitAdvancePC(out, address); + emitSetFile(out); + if (fileName != null) { + referencedItems.add(StringIdItem.getInternedStringIdItem(dexFile, fileName)); + } + } + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/Util/EncodedValueUtils.java b/dexlib/src/main/java/org/jf/dexlib/Util/EncodedValueUtils.java index 5d0f3d2d..8b42fdbb 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Util/EncodedValueUtils.java +++ b/dexlib/src/main/java/org/jf/dexlib/Util/EncodedValueUtils.java @@ -1,143 +1,143 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Util; - -public class EncodedValueUtils { - public static byte getRequiredBytesForSignedIntegralValue(long value) { - /* - * Figure out how many bits are needed to represent the value, - * including a sign bit: The bit count is subtracted from 65 - * and not 64 to account for the sign bit. The xor operation - * has the effect of leaving non-negative values alone and - * unary complementing negative values (so that a leading zero - * count always returns a useful number for our present - * purpose). - */ - int requiredBits = - 65 - Long.numberOfLeadingZeros(value ^ (value >> 63)); - - // Round up the requiredBits to a number of bytes. - return (byte)((requiredBits + 0x07) >> 3); - } - - public static long decodeSignedIntegralValue(byte[] bytes) { - long value = 0; - for (int i = 0; i < bytes.length; i++) { - value |= (((long)(bytes[i] & 0xFF)) << (i * 8)); - } - - int shift = (8 - bytes.length) * 8; - return value << shift >> shift; - } - - public static byte[] encodeSignedIntegralValue(long value) { - int requiredBytes = getRequiredBytesForSignedIntegralValue(value); - - byte[] bytes = new byte[requiredBytes]; - - for (int i = 0; i < requiredBytes; i++) { - bytes[i] = (byte) value; - value >>= 8; - } - return bytes; - } - - - - - - public static byte getRequiredBytesForUnsignedIntegralValue(long value) { - // Figure out how many bits are needed to represent the value. - int requiredBits = 64 - Long.numberOfLeadingZeros(value); - if (requiredBits == 0) { - requiredBits = 1; - } - - // Round up the requiredBits to a number of bytes. - return (byte)((requiredBits + 0x07) >> 3); - } - - public static long decodeUnsignedIntegralValue(byte[] bytes) { - long value = 0; - for (int i = 0; i < bytes.length; i++) { - value |= (((long)(bytes[i] & 0xFF)) << i * 8); - } - return value; - } - - public static byte[] encodeUnsignedIntegralValue(long value) { - int requiredBytes = getRequiredBytesForUnsignedIntegralValue(value); - - byte[] bytes = new byte[requiredBytes]; - - for (int i = 0; i < requiredBytes; i++) { - bytes[i] = (byte) value; - value >>= 8; - } - return bytes; - } - - - - - - public static int getRequiredBytesForRightZeroExtendedValue(long value) { - // Figure out how many bits are needed to represent the value. - int requiredBits = 64 - Long.numberOfTrailingZeros(value); - if (requiredBits == 0) { - requiredBits = 1; - } - - // Round up the requiredBits to a number of bytes. - return (requiredBits + 0x07) >> 3; - } - - public static long decodeRightZeroExtendedValue(byte[] bytes) { - long value = 0; - for (int i = 0; i < bytes.length; i++) { - value |= (((long)(bytes[i] & 0xFF)) << (i * 8)); - } - return value << (8 - bytes.length) * 8; - } - - public static byte[] encodeRightZeroExtendedValue(long value) { - int requiredBytes = getRequiredBytesForRightZeroExtendedValue(value); - - // Scootch the first bits to be written down to the low-order bits. - value >>= 64 - (requiredBytes * 8); - - byte[] bytes = new byte[requiredBytes]; - - for(int i = 0; i < requiredBytes; i++) { - bytes[i] = (byte)value; - value >>= 8; - } - return bytes; - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Util; + +public class EncodedValueUtils { + public static byte getRequiredBytesForSignedIntegralValue(long value) { + /* + * Figure out how many bits are needed to represent the value, + * including a sign bit: The bit count is subtracted from 65 + * and not 64 to account for the sign bit. The xor operation + * has the effect of leaving non-negative values alone and + * unary complementing negative values (so that a leading zero + * count always returns a useful number for our present + * purpose). + */ + int requiredBits = + 65 - Long.numberOfLeadingZeros(value ^ (value >> 63)); + + // Round up the requiredBits to a number of bytes. + return (byte)((requiredBits + 0x07) >> 3); + } + + public static long decodeSignedIntegralValue(byte[] bytes) { + long value = 0; + for (int i = 0; i < bytes.length; i++) { + value |= (((long)(bytes[i] & 0xFF)) << (i * 8)); + } + + int shift = (8 - bytes.length) * 8; + return value << shift >> shift; + } + + public static byte[] encodeSignedIntegralValue(long value) { + int requiredBytes = getRequiredBytesForSignedIntegralValue(value); + + byte[] bytes = new byte[requiredBytes]; + + for (int i = 0; i < requiredBytes; i++) { + bytes[i] = (byte) value; + value >>= 8; + } + return bytes; + } + + + + + + public static byte getRequiredBytesForUnsignedIntegralValue(long value) { + // Figure out how many bits are needed to represent the value. + int requiredBits = 64 - Long.numberOfLeadingZeros(value); + if (requiredBits == 0) { + requiredBits = 1; + } + + // Round up the requiredBits to a number of bytes. + return (byte)((requiredBits + 0x07) >> 3); + } + + public static long decodeUnsignedIntegralValue(byte[] bytes) { + long value = 0; + for (int i = 0; i < bytes.length; i++) { + value |= (((long)(bytes[i] & 0xFF)) << i * 8); + } + return value; + } + + public static byte[] encodeUnsignedIntegralValue(long value) { + int requiredBytes = getRequiredBytesForUnsignedIntegralValue(value); + + byte[] bytes = new byte[requiredBytes]; + + for (int i = 0; i < requiredBytes; i++) { + bytes[i] = (byte) value; + value >>= 8; + } + return bytes; + } + + + + + + public static int getRequiredBytesForRightZeroExtendedValue(long value) { + // Figure out how many bits are needed to represent the value. + int requiredBits = 64 - Long.numberOfTrailingZeros(value); + if (requiredBits == 0) { + requiredBits = 1; + } + + // Round up the requiredBits to a number of bytes. + return (requiredBits + 0x07) >> 3; + } + + public static long decodeRightZeroExtendedValue(byte[] bytes) { + long value = 0; + for (int i = 0; i < bytes.length; i++) { + value |= (((long)(bytes[i] & 0xFF)) << (i * 8)); + } + return value << (8 - bytes.length) * 8; + } + + public static byte[] encodeRightZeroExtendedValue(long value) { + int requiredBytes = getRequiredBytesForRightZeroExtendedValue(value); + + // Scootch the first bits to be written down to the low-order bits. + value >>= 64 - (requiredBytes * 8); + + byte[] bytes = new byte[requiredBytes]; + + for(int i = 0; i < requiredBytes; i++) { + bytes[i] = (byte)value; + value >>= 8; + } + return bytes; + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/Util/Input.java b/dexlib/src/main/java/org/jf/dexlib/Util/Input.java index 463ed98b..37fd09ce 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Util/Input.java +++ b/dexlib/src/main/java/org/jf/dexlib/Util/Input.java @@ -1,167 +1,167 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Util; - -/** - * Interface for a source for binary input. This is similar to - * java.util.DataInput, but no IOExceptions - * are declared, and multibyte input is defined to be little-endian. - */ -public interface Input { - /** - * Gets the current cursor position. This is the same as the number of - * bytes read from this instance. - * - * @return >= 0; the cursor position - */ - public int getCursor(); - - /** - * Sets the current cursor position. - * - * @return >= 0; the cursor position - */ - public void setCursor(int cursor); - - /** - * Asserts that the cursor is the given value. - * - * @param expectedCursor the expected cursor value - * @throws RuntimeException thrown if getCursor() != - * expectedCursor - */ - public void assertCursor(int expectedCursor); - - /** - * Reads a byte from this instance. - * - * @return the byte value that was read - */ - public byte readByte(); - - /** - * Reads a short from this instance. - * - * @return the short value that was read, as an int - */ - public int readShort(); - - /** - * Reads an int from this instance. - * - * @return the unsigned int value that was read - */ - public int readInt(); - - /** - * Reads a long from this instance. - * - * @return the long value that was read - */ - public long readLong(); - - - /** - * Reads a DWARFv3-style signed LEB128 integer. For details, - * see the "Dalvik Executable Format" document or DWARF v3 section - * 7.6. - * - * @return the integer value that was read - */ - public int readSignedLeb128(); - - /** - * Reads a DWARFv3-style unsigned LEB128 integer. For details, - * see the "Dalvik Executable Format" document or DWARF v3 section - * 7.6. - * - * @return the integer value that was read - */ - public int readUnsignedLeb128(); - - - /** - * Reads a unsigned value as a DWARFv3-style LEB128 integer. It specifically - * checks for the case when the value was incorrectly formatted as a signed - * LEB128, and returns the appropriate unsigned value, but negated - * @return If the value was formatted as a ULEB128, it returns the actual unsigned - * value. Otherwise, if the value was formatted as a signed LEB128, it negates the - * "correct" unsigned value and returns that - */ - public int readUnsignedOrSignedLeb128(); - - /** - * reads a byte[] from this instance. - * - * @param bytes non-null; the buffer to read the data into - * @param offset >= 0; offset into bytes for the first - * byte to write - * @param length >= 0; number of bytes to read - */ - public void read(byte[] bytes, int offset, int length); - - /** - * reads a byte[] from this instance. This is just - * a convenient shorthand for read(bytes, 0, bytes.length). - * - * @param bytes non-null; the buffer to read the data into - */ - public void read(byte[] bytes); - - - /** - * reads a byte[] from this instance - * - * @param length >= 0; number of bytes to read - * @return a byte array containing length bytes - */ - public byte[] readBytes(int length); - - /** - * reads a byte[] from this instance, from the current cursor up to but not including - * the next null (0) byte. The terminating null byte is read and discarded, so that after the read, - * the cursor is positioned at the byte immediately after the terminating null - */ - public byte[] readNullTerminatedBytes(); - - /** - * Skips the given number of bytes. - * - * @param count >= 0; the number of bytes to skip - */ - public void skipBytes(int count); - - /** - * Skip extra bytes if necessary to force alignment of the output - * cursor as given. - * - * @param alignment > 0; the alignment; must be a power of two - */ - public void alignTo(int alignment); -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Util; + +/** + * Interface for a source for binary input. This is similar to + * java.util.DataInput, but no IOExceptions + * are declared, and multibyte input is defined to be little-endian. + */ +public interface Input { + /** + * Gets the current cursor position. This is the same as the number of + * bytes read from this instance. + * + * @return >= 0; the cursor position + */ + public int getCursor(); + + /** + * Sets the current cursor position. + * + * @return >= 0; the cursor position + */ + public void setCursor(int cursor); + + /** + * Asserts that the cursor is the given value. + * + * @param expectedCursor the expected cursor value + * @throws RuntimeException thrown if getCursor() != + * expectedCursor + */ + public void assertCursor(int expectedCursor); + + /** + * Reads a byte from this instance. + * + * @return the byte value that was read + */ + public byte readByte(); + + /** + * Reads a short from this instance. + * + * @return the short value that was read, as an int + */ + public int readShort(); + + /** + * Reads an int from this instance. + * + * @return the unsigned int value that was read + */ + public int readInt(); + + /** + * Reads a long from this instance. + * + * @return the long value that was read + */ + public long readLong(); + + + /** + * Reads a DWARFv3-style signed LEB128 integer. For details, + * see the "Dalvik Executable Format" document or DWARF v3 section + * 7.6. + * + * @return the integer value that was read + */ + public int readSignedLeb128(); + + /** + * Reads a DWARFv3-style unsigned LEB128 integer. For details, + * see the "Dalvik Executable Format" document or DWARF v3 section + * 7.6. + * + * @return the integer value that was read + */ + public int readUnsignedLeb128(); + + + /** + * Reads a unsigned value as a DWARFv3-style LEB128 integer. It specifically + * checks for the case when the value was incorrectly formatted as a signed + * LEB128, and returns the appropriate unsigned value, but negated + * @return If the value was formatted as a ULEB128, it returns the actual unsigned + * value. Otherwise, if the value was formatted as a signed LEB128, it negates the + * "correct" unsigned value and returns that + */ + public int readUnsignedOrSignedLeb128(); + + /** + * reads a byte[] from this instance. + * + * @param bytes non-null; the buffer to read the data into + * @param offset >= 0; offset into bytes for the first + * byte to write + * @param length >= 0; number of bytes to read + */ + public void read(byte[] bytes, int offset, int length); + + /** + * reads a byte[] from this instance. This is just + * a convenient shorthand for read(bytes, 0, bytes.length). + * + * @param bytes non-null; the buffer to read the data into + */ + public void read(byte[] bytes); + + + /** + * reads a byte[] from this instance + * + * @param length >= 0; number of bytes to read + * @return a byte array containing length bytes + */ + public byte[] readBytes(int length); + + /** + * reads a byte[] from this instance, from the current cursor up to but not including + * the next null (0) byte. The terminating null byte is read and discarded, so that after the read, + * the cursor is positioned at the byte immediately after the terminating null + */ + public byte[] readNullTerminatedBytes(); + + /** + * Skips the given number of bytes. + * + * @param count >= 0; the number of bytes to skip + */ + public void skipBytes(int count); + + /** + * Skip extra bytes if necessary to force alignment of the output + * cursor as given. + * + * @param alignment > 0; the alignment; must be a power of two + */ + public void alignTo(int alignment); +} diff --git a/dexlib/src/main/java/org/jf/dexlib/Util/Pair.java b/dexlib/src/main/java/org/jf/dexlib/Util/Pair.java index c0fb468a..490049cd 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Util/Pair.java +++ b/dexlib/src/main/java/org/jf/dexlib/Util/Pair.java @@ -1,40 +1,40 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Util; - -public class Pair { - public final A first; - public final B second; - - public Pair(A first, B second) { - this.first = first; - this.second = second; - } -} - +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Util; + +public class Pair { + public final A first; + public final B second; + + public Pair(A first, B second) { + this.first = first; + this.second = second; + } +} + diff --git a/dexlib/src/main/java/org/jf/dexlib/Util/TryListBuilder.java b/dexlib/src/main/java/org/jf/dexlib/Util/TryListBuilder.java index 65ea048c..8cb572ea 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Util/TryListBuilder.java +++ b/dexlib/src/main/java/org/jf/dexlib/Util/TryListBuilder.java @@ -1,347 +1,347 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Util; - -import org.jf.dexlib.CodeItem; -import org.jf.dexlib.TypeIdItem; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; - -public class TryListBuilder -{ - /*TODO: add logic to merge adjacent, identical try blocks, and remove superflous handlers - Also provide a "strict" mode, where the above isn't performed, which will be useful to be able to - exactly reproduce the original .dex file (for testing/verification purposes)*/ - - - private TryRange firstTryRange = new TryRange(0,0); - private TryRange lastTryRange = new TryRange(0,0); - - public TryListBuilder() { - firstTryRange.next = lastTryRange; - lastTryRange.previous = firstTryRange; - } - - private class TryRange - { - public TryRange previous = null; - public TryRange next = null; - - public int startAddress; - public int endAddress; - public LinkedList handlers; - - public int catchAllHandlerAddress; - - public TryRange(int startAddress, int endAddress) { - this.startAddress = startAddress; - this.endAddress = endAddress; - this.handlers = new LinkedList(); - this.previous = null; - this.next = null; - catchAllHandlerAddress = -1; - } - - public void append(TryRange tryRange) { - /*we use a dummy last item, so this.next will always - have a value*/ - this.next.previous = tryRange; - tryRange.next = this.next; - - this.next = tryRange; - tryRange.previous = this; - } - - public void prepend(TryRange tryRange){ - /*we use a dummy first item, so this.previous will always - have a value*/ - this.previous.next = tryRange; - tryRange.previous = this.previous; - - this.previous = tryRange; - tryRange.next = this; - } - - /** - * This splits the current range into two ranges at the given - * address. The existing range will be shortened to the first - * half, and a new range will be created and returned for the - * 2nd half. - * @param address The address to split at - * @return The 2nd half of the - */ - public TryRange split(int address) { - //this is a private class, so address is assumed - //to be valid - - TryRange tryRange = new TryRange(address, endAddress); - tryRange.catchAllHandlerAddress = this.catchAllHandlerAddress; - tryRange.handlers.addAll(this.handlers); - append(tryRange); - - this.endAddress = address; - - return tryRange; - } - - public void appendHandler(Handler handler) { - handlers.addLast(handler); - } - - public void prependHandler(Handler handler) { - handlers.addFirst(handler); - } - } - - private class Handler - { - public final TypeIdItem type; - public final int handlerAddress; - - public Handler(TypeIdItem type, int handlerAddress) { - this.type = type; - this.handlerAddress = handlerAddress; - } - } - - public Pair, List> encodeTries() { - if (firstTryRange.next == lastTryRange) { - return new Pair, List>(null, null); - } - - ArrayList tries = new ArrayList(); - ArrayList handlers = new ArrayList(); - - HashMap handlerDict = - new HashMap(); - - TryRange tryRange = firstTryRange.next; - - while (tryRange != lastTryRange) { - CodeItem.EncodedTypeAddrPair[] encodedTypeAddrPairs = - new CodeItem.EncodedTypeAddrPair[tryRange.handlers.size()]; - - int index = 0; - for (Handler handler: tryRange.handlers) { - CodeItem.EncodedTypeAddrPair encodedTypeAddrPair = new CodeItem.EncodedTypeAddrPair( - handler.type, - handler.handlerAddress); - encodedTypeAddrPairs[index++] = encodedTypeAddrPair; - } - - CodeItem.EncodedCatchHandler encodedCatchHandler = new CodeItem.EncodedCatchHandler( - encodedTypeAddrPairs, - tryRange.catchAllHandlerAddress); - CodeItem.EncodedCatchHandler internedEncodedCatchHandler = handlerDict.get(encodedCatchHandler); - if (internedEncodedCatchHandler == null) { - handlerDict.put(encodedCatchHandler, encodedCatchHandler); - handlers.add(encodedCatchHandler); - } else { - encodedCatchHandler = internedEncodedCatchHandler; - } - - CodeItem.TryItem tryItem = new CodeItem.TryItem( - tryRange.startAddress, - tryRange.endAddress - tryRange.startAddress, - encodedCatchHandler); - tries.add(tryItem); - - tryRange = tryRange.next; - } - - return new Pair, List>(tries, handlers); - } - - public void addCatchAllHandler(int startAddress, int endAddress, int handlerAddress) { - TryRange startRange; - TryRange endRange; - - Pair ranges = getBoundingRanges(startAddress, endAddress); - startRange = ranges.first; - endRange = ranges.second; - - int previousEnd = startAddress; - TryRange tryRange = startRange; - - /*Now we have the start and end ranges that exactly match the start and end - of the range being added. We need to iterate over all the ranges from the start - to end range inclusively, and append the handler to the end of each range's handler - list. We also need to create a new range for any "holes" in the existing ranges*/ - do - { - //is there a hole? If so, add a new range to fill the hole - if (tryRange.startAddress > previousEnd) { - TryRange newRange = new TryRange(previousEnd, tryRange.startAddress); - tryRange.prepend(newRange); - tryRange = newRange; - } - - if (tryRange.catchAllHandlerAddress == -1) { - tryRange.catchAllHandlerAddress = handlerAddress; - } - - previousEnd = tryRange.endAddress; - tryRange = tryRange.next; - } while (tryRange.previous != endRange); - } - - public Pair getBoundingRanges(int startAddress, int endAddress) { - TryRange startRange = null; - TryRange endRange = null; - - TryRange tryRange = firstTryRange.next; - while (tryRange != lastTryRange) { - if (startAddress == tryRange.startAddress) { - //|-----| - //^------ - /*Bam. We hit the start of the range right on the head*/ - startRange = tryRange; - break; - } else if (startAddress > tryRange.startAddress && startAddress < tryRange.endAddress) { - //|-----| - // ^---- - /*Almost. The start of the range being added is in the middle - of an existing try range. We need to split the existing range - at the start address of the range being added*/ - startRange = tryRange.split(startAddress); - break; - }else if (startAddress < tryRange.startAddress) { - if (endAddress <= tryRange.startAddress) { - // |-----| - //^--^ - /*Oops, totally too far! The new range doesn't overlap any existing - ones, so we just add it and return*/ - startRange = new TryRange(startAddress, endAddress); - tryRange.prepend(startRange); - return new Pair(startRange, startRange); - } else { - // |-----| - //^--------- - /*Oops, too far! We've passed the start of the range being added, but - the new range does overlap this one. We need to add a new range just - before this one*/ - startRange = new TryRange(startAddress, tryRange.startAddress); - tryRange.prepend(startRange); - break; - } - } - - tryRange = tryRange.next; - } - - //|-----| - // ^----- - /*Either the list of tries is blank, or all the tries in the list - end before the range being added starts. In either case, we just need - to add a new range at the end of the list*/ - if (startRange == null) { - startRange = new TryRange(startAddress, endAddress); - lastTryRange.prepend(startRange); - return new Pair(startRange, startRange); - } - - tryRange = startRange; - while (tryRange != lastTryRange) { - if (tryRange.endAddress == endAddress) { - //|-----| - //------^ - /*Bam! We hit the end right on the head.*/ - endRange = tryRange; - break; - } else if (tryRange.startAddress < endAddress && tryRange.endAddress > endAddress) { - //|-----| - //--^ - /*Almost. The range being added ends in the middle of an - existing range. We need to split the existing range - at the end of the range being added.*/ - tryRange.split(endAddress); - endRange = tryRange; - break; - } else if (tryRange.startAddress >= endAddress) { - //|-----| |-----| - //-----------^ - /*Oops, too far! The current range starts after the range being added - ends. We need to create a new range that starts at the end of the - previous range, and ends at the end of the range being added*/ - endRange = new TryRange(tryRange.previous.endAddress, endAddress); - tryRange.prepend(endRange); - break; - } - tryRange = tryRange.next; - } - - //|-----| - //--------^ - /*The last range in the list ended before the end of the range being added. - We need to add a new range that starts at the end of the last range in the - list, and ends at the end of the range being added.*/ - if (endRange == null) { - endRange = new TryRange(lastTryRange.previous.endAddress, endAddress); - lastTryRange.prepend(endRange); - } - - return new Pair(startRange, endRange); - } - - public void addHandler(TypeIdItem type, int startAddress, int endAddress, int handlerAddress) { - TryRange startRange; - TryRange endRange; - - //TODO: need to check for pre-existing exception types in the handler list? - - Pair ranges = getBoundingRanges(startAddress, endAddress); - startRange = ranges.first; - endRange = ranges.second; - Handler handler = new Handler(type, handlerAddress); - - int previousEnd = startAddress; - TryRange tryRange = startRange; - - /*Now we have the start and end ranges that exactly match the start and end - of the range being added. We need to iterate over all the ranges from the start - to end range inclusively, and append the handler to the end of each range's handler - list. We also need to create a new range for any "holes" in the existing ranges*/ - do - { - //is there a hole? If so, add a new range to fill the hole - if (tryRange.startAddress > previousEnd) { - TryRange newRange = new TryRange(previousEnd, tryRange.startAddress); - tryRange.prepend(newRange); - tryRange = newRange; - } - - tryRange.appendHandler(handler); - previousEnd = tryRange.endAddress; - tryRange = tryRange.next; - } while (tryRange.previous != endRange); - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Util; + +import org.jf.dexlib.CodeItem; +import org.jf.dexlib.TypeIdItem; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; + +public class TryListBuilder +{ + /*TODO: add logic to merge adjacent, identical try blocks, and remove superflous handlers + Also provide a "strict" mode, where the above isn't performed, which will be useful to be able to + exactly reproduce the original .dex file (for testing/verification purposes)*/ + + + private TryRange firstTryRange = new TryRange(0,0); + private TryRange lastTryRange = new TryRange(0,0); + + public TryListBuilder() { + firstTryRange.next = lastTryRange; + lastTryRange.previous = firstTryRange; + } + + private class TryRange + { + public TryRange previous = null; + public TryRange next = null; + + public int startAddress; + public int endAddress; + public LinkedList handlers; + + public int catchAllHandlerAddress; + + public TryRange(int startAddress, int endAddress) { + this.startAddress = startAddress; + this.endAddress = endAddress; + this.handlers = new LinkedList(); + this.previous = null; + this.next = null; + catchAllHandlerAddress = -1; + } + + public void append(TryRange tryRange) { + /*we use a dummy last item, so this.next will always + have a value*/ + this.next.previous = tryRange; + tryRange.next = this.next; + + this.next = tryRange; + tryRange.previous = this; + } + + public void prepend(TryRange tryRange){ + /*we use a dummy first item, so this.previous will always + have a value*/ + this.previous.next = tryRange; + tryRange.previous = this.previous; + + this.previous = tryRange; + tryRange.next = this; + } + + /** + * This splits the current range into two ranges at the given + * address. The existing range will be shortened to the first + * half, and a new range will be created and returned for the + * 2nd half. + * @param address The address to split at + * @return The 2nd half of the + */ + public TryRange split(int address) { + //this is a private class, so address is assumed + //to be valid + + TryRange tryRange = new TryRange(address, endAddress); + tryRange.catchAllHandlerAddress = this.catchAllHandlerAddress; + tryRange.handlers.addAll(this.handlers); + append(tryRange); + + this.endAddress = address; + + return tryRange; + } + + public void appendHandler(Handler handler) { + handlers.addLast(handler); + } + + public void prependHandler(Handler handler) { + handlers.addFirst(handler); + } + } + + private class Handler + { + public final TypeIdItem type; + public final int handlerAddress; + + public Handler(TypeIdItem type, int handlerAddress) { + this.type = type; + this.handlerAddress = handlerAddress; + } + } + + public Pair, List> encodeTries() { + if (firstTryRange.next == lastTryRange) { + return new Pair, List>(null, null); + } + + ArrayList tries = new ArrayList(); + ArrayList handlers = new ArrayList(); + + HashMap handlerDict = + new HashMap(); + + TryRange tryRange = firstTryRange.next; + + while (tryRange != lastTryRange) { + CodeItem.EncodedTypeAddrPair[] encodedTypeAddrPairs = + new CodeItem.EncodedTypeAddrPair[tryRange.handlers.size()]; + + int index = 0; + for (Handler handler: tryRange.handlers) { + CodeItem.EncodedTypeAddrPair encodedTypeAddrPair = new CodeItem.EncodedTypeAddrPair( + handler.type, + handler.handlerAddress); + encodedTypeAddrPairs[index++] = encodedTypeAddrPair; + } + + CodeItem.EncodedCatchHandler encodedCatchHandler = new CodeItem.EncodedCatchHandler( + encodedTypeAddrPairs, + tryRange.catchAllHandlerAddress); + CodeItem.EncodedCatchHandler internedEncodedCatchHandler = handlerDict.get(encodedCatchHandler); + if (internedEncodedCatchHandler == null) { + handlerDict.put(encodedCatchHandler, encodedCatchHandler); + handlers.add(encodedCatchHandler); + } else { + encodedCatchHandler = internedEncodedCatchHandler; + } + + CodeItem.TryItem tryItem = new CodeItem.TryItem( + tryRange.startAddress, + tryRange.endAddress - tryRange.startAddress, + encodedCatchHandler); + tries.add(tryItem); + + tryRange = tryRange.next; + } + + return new Pair, List>(tries, handlers); + } + + public void addCatchAllHandler(int startAddress, int endAddress, int handlerAddress) { + TryRange startRange; + TryRange endRange; + + Pair ranges = getBoundingRanges(startAddress, endAddress); + startRange = ranges.first; + endRange = ranges.second; + + int previousEnd = startAddress; + TryRange tryRange = startRange; + + /*Now we have the start and end ranges that exactly match the start and end + of the range being added. We need to iterate over all the ranges from the start + to end range inclusively, and append the handler to the end of each range's handler + list. We also need to create a new range for any "holes" in the existing ranges*/ + do + { + //is there a hole? If so, add a new range to fill the hole + if (tryRange.startAddress > previousEnd) { + TryRange newRange = new TryRange(previousEnd, tryRange.startAddress); + tryRange.prepend(newRange); + tryRange = newRange; + } + + if (tryRange.catchAllHandlerAddress == -1) { + tryRange.catchAllHandlerAddress = handlerAddress; + } + + previousEnd = tryRange.endAddress; + tryRange = tryRange.next; + } while (tryRange.previous != endRange); + } + + public Pair getBoundingRanges(int startAddress, int endAddress) { + TryRange startRange = null; + TryRange endRange = null; + + TryRange tryRange = firstTryRange.next; + while (tryRange != lastTryRange) { + if (startAddress == tryRange.startAddress) { + //|-----| + //^------ + /*Bam. We hit the start of the range right on the head*/ + startRange = tryRange; + break; + } else if (startAddress > tryRange.startAddress && startAddress < tryRange.endAddress) { + //|-----| + // ^---- + /*Almost. The start of the range being added is in the middle + of an existing try range. We need to split the existing range + at the start address of the range being added*/ + startRange = tryRange.split(startAddress); + break; + }else if (startAddress < tryRange.startAddress) { + if (endAddress <= tryRange.startAddress) { + // |-----| + //^--^ + /*Oops, totally too far! The new range doesn't overlap any existing + ones, so we just add it and return*/ + startRange = new TryRange(startAddress, endAddress); + tryRange.prepend(startRange); + return new Pair(startRange, startRange); + } else { + // |-----| + //^--------- + /*Oops, too far! We've passed the start of the range being added, but + the new range does overlap this one. We need to add a new range just + before this one*/ + startRange = new TryRange(startAddress, tryRange.startAddress); + tryRange.prepend(startRange); + break; + } + } + + tryRange = tryRange.next; + } + + //|-----| + // ^----- + /*Either the list of tries is blank, or all the tries in the list + end before the range being added starts. In either case, we just need + to add a new range at the end of the list*/ + if (startRange == null) { + startRange = new TryRange(startAddress, endAddress); + lastTryRange.prepend(startRange); + return new Pair(startRange, startRange); + } + + tryRange = startRange; + while (tryRange != lastTryRange) { + if (tryRange.endAddress == endAddress) { + //|-----| + //------^ + /*Bam! We hit the end right on the head.*/ + endRange = tryRange; + break; + } else if (tryRange.startAddress < endAddress && tryRange.endAddress > endAddress) { + //|-----| + //--^ + /*Almost. The range being added ends in the middle of an + existing range. We need to split the existing range + at the end of the range being added.*/ + tryRange.split(endAddress); + endRange = tryRange; + break; + } else if (tryRange.startAddress >= endAddress) { + //|-----| |-----| + //-----------^ + /*Oops, too far! The current range starts after the range being added + ends. We need to create a new range that starts at the end of the + previous range, and ends at the end of the range being added*/ + endRange = new TryRange(tryRange.previous.endAddress, endAddress); + tryRange.prepend(endRange); + break; + } + tryRange = tryRange.next; + } + + //|-----| + //--------^ + /*The last range in the list ended before the end of the range being added. + We need to add a new range that starts at the end of the last range in the + list, and ends at the end of the range being added.*/ + if (endRange == null) { + endRange = new TryRange(lastTryRange.previous.endAddress, endAddress); + lastTryRange.prepend(endRange); + } + + return new Pair(startRange, endRange); + } + + public void addHandler(TypeIdItem type, int startAddress, int endAddress, int handlerAddress) { + TryRange startRange; + TryRange endRange; + + //TODO: need to check for pre-existing exception types in the handler list? + + Pair ranges = getBoundingRanges(startAddress, endAddress); + startRange = ranges.first; + endRange = ranges.second; + Handler handler = new Handler(type, handlerAddress); + + int previousEnd = startAddress; + TryRange tryRange = startRange; + + /*Now we have the start and end ranges that exactly match the start and end + of the range being added. We need to iterate over all the ranges from the start + to end range inclusively, and append the handler to the end of each range's handler + list. We also need to create a new range for any "holes" in the existing ranges*/ + do + { + //is there a hole? If so, add a new range to fill the hole + if (tryRange.startAddress > previousEnd) { + TryRange newRange = new TryRange(previousEnd, tryRange.startAddress); + tryRange.prepend(newRange); + tryRange = newRange; + } + + tryRange.appendHandler(handler); + previousEnd = tryRange.endAddress; + tryRange = tryRange.next; + } while (tryRange.previous != endRange); + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/Util/TypeUtils.java b/dexlib/src/main/java/org/jf/dexlib/Util/TypeUtils.java index 68a9fd5b..26370a5a 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Util/TypeUtils.java +++ b/dexlib/src/main/java/org/jf/dexlib/Util/TypeUtils.java @@ -1,61 +1,61 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Util; - -import org.jf.dexlib.DexFile; -import org.jf.dexlib.EncodedValue.*; - -public class TypeUtils -{ - public static EncodedValue makeDefaultValueForType(DexFile dexFile, String type) { - EncodedValue subField; - switch (type.charAt(0)) { - case 'Z': - return BooleanEncodedValue.FalseValue; - case 'B': - return new ByteEncodedValue((byte)0); - case 'S': - return new ShortEncodedValue((short)0); - case 'C': - return new CharEncodedValue((char)0); - case 'I': - return new IntEncodedValue(0); - case 'J': - return new LongEncodedValue(0); - case 'F': - return new FloatEncodedValue(0); - case 'D': - return new DoubleEncodedValue(0); - case 'L': - case '[': - return NullEncodedValue.NullValue; - } - return null; - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Util; + +import org.jf.dexlib.DexFile; +import org.jf.dexlib.EncodedValue.*; + +public class TypeUtils +{ + public static EncodedValue makeDefaultValueForType(DexFile dexFile, String type) { + EncodedValue subField; + switch (type.charAt(0)) { + case 'Z': + return BooleanEncodedValue.FalseValue; + case 'B': + return new ByteEncodedValue((byte)0); + case 'S': + return new ShortEncodedValue((short)0); + case 'C': + return new CharEncodedValue((char)0); + case 'I': + return new IntEncodedValue(0); + case 'J': + return new LongEncodedValue(0); + case 'F': + return new FloatEncodedValue(0); + case 'D': + return new DoubleEncodedValue(0); + case 'L': + case '[': + return NullEncodedValue.NullValue; + } + return null; + } +} diff --git a/smali/src/main/java/org/jf/smali/literalTools.java b/smali/src/main/java/org/jf/smali/literalTools.java index 8c582722..14dc750a 100644 --- a/smali/src/main/java/org/jf/smali/literalTools.java +++ b/smali/src/main/java/org/jf/smali/literalTools.java @@ -1,378 +1,378 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.smali; - -public class literalTools -{ - public static byte parseByte(String byteLiteral) - throws NumberFormatException { - if (byteLiteral == null) { - throw new NumberFormatException("string is null"); - } - if (byteLiteral.length() == 0) { - throw new NumberFormatException("string is blank"); - } - - char[] byteChars; - if (byteLiteral.toUpperCase().endsWith("T")) { - byteChars = byteLiteral.substring(0, byteLiteral.length()-1).toCharArray(); - } else { - byteChars = byteLiteral.toCharArray(); - } - - int position = 0; - int radix = 10; - boolean negative = false; - if (byteChars[position] == '-') { - position++; - negative = true; - } - - if (byteChars[position] == '0') { - position++; - if (position == byteChars.length) { - return 0; - } else if (byteChars[position] == 'x' || byteChars[position] == 'X') { - radix = 16; - position++; - } else if (Character.digit(byteChars[position], 8) >= 0) { - radix = 8; - } - } - - byte result = 0; - byte shiftedResult; - int digit; - byte maxValue = (byte)(Byte.MAX_VALUE / (radix / 2)); - - while (position < byteChars.length) { - digit = Character.digit(byteChars[position], radix); - if (digit < 0) { - throw new NumberFormatException("The string contains invalid an digit - '" + byteChars[position] + "'"); - } - shiftedResult = (byte)(result * radix); - if (result > maxValue) { - throw new NumberFormatException(byteLiteral + " cannot fit into a byte"); - } - if (shiftedResult < 0 && shiftedResult >= -digit) { - throw new NumberFormatException(byteLiteral + " cannot fit into a byte"); - } - result = (byte)(shiftedResult + digit); - position++; - } - - if (negative) { - //allow -0x80, which is = 0x80 - if (result == Byte.MIN_VALUE) { - return result; - } else if (result < 0) { - throw new NumberFormatException(byteLiteral + " cannot fit into a byte"); - } - return (byte)(result * -1); - } else { - return result; - } - } - - public static short parseShort(String shortLiteral) - throws NumberFormatException { - if (shortLiteral == null) { - throw new NumberFormatException("string is null"); - } - if (shortLiteral.length() == 0) { - throw new NumberFormatException("string is blank"); - } - - char[] shortChars; - if (shortLiteral.toUpperCase().endsWith("S")) { - shortChars = shortLiteral.substring(0, shortLiteral.length()-1).toCharArray(); - } else { - shortChars = shortLiteral.toCharArray(); - } - - int position = 0; - int radix = 10; - boolean negative = false; - if (shortChars[position] == '-') { - position++; - negative = true; - } - - if (shortChars[position] == '0') { - position++; - if (position == shortChars.length) { - return 0; - } else if (shortChars[position] == 'x' || shortChars[position] == 'X') { - radix = 16; - position++; - } else if (Character.digit(shortChars[position], 8) >= 0) { - radix = 8; - } - } - - short result = 0; - short shiftedResult; - int digit; - short maxValue = (short)(Short.MAX_VALUE / (radix / 2)); - - while (position < shortChars.length) { - digit = Character.digit(shortChars[position], radix); - if (digit < 0) { - throw new NumberFormatException("The string contains invalid an digit - '" + shortChars[position] + "'"); - } - shiftedResult = (short)(result * radix); - if (result > maxValue) { - throw new NumberFormatException(shortLiteral + " cannot fit into a short"); - } - if (shiftedResult < 0 && shiftedResult >= -digit) { - throw new NumberFormatException(shortLiteral + " cannot fit into a short"); - } - result = (short)(shiftedResult + digit); - position++; - } - - if (negative) { - //allow -0x8000, which is = 0x8000 - if (result == Short.MIN_VALUE) { - return result; - } else if (result < 0) { - throw new NumberFormatException(shortLiteral + " cannot fit into a short"); - } - return (short)(result * -1); - } else { - return result; - } - } - - public static int parseInt(String intLiteral) - throws NumberFormatException { - if (intLiteral == null) { - throw new NumberFormatException("string is null"); - } - if (intLiteral.length() == 0) { - throw new NumberFormatException("string is blank"); - } - - char[] intChars = intLiteral.toCharArray(); - int position = 0; - int radix = 10; - boolean negative = false; - if (intChars[position] == '-') { - position++; - negative = true; - } - - if (intChars[position] == '0') { - position++; - if (position == intChars.length) { - return 0; - } else if (intChars[position] == 'x' || intChars[position] == 'X') { - radix = 16; - position++; - } else if (Character.digit(intChars[position], 8) >= 0) { - radix = 8; - } - } - - int result = 0; - int shiftedResult; - int digit; - int maxValue = Integer.MAX_VALUE / (radix / 2); - - while (position < intChars.length) { - digit = Character.digit(intChars[position], radix); - if (digit < 0) { - throw new NumberFormatException("The string contains an invalid digit - '" + intChars[position] + "'"); - } - shiftedResult = result * radix; - if (result > maxValue) { - throw new NumberFormatException(intLiteral + " cannot fit into an int"); - } - if (shiftedResult < 0 && shiftedResult >= -digit) { - throw new NumberFormatException(intLiteral + " cannot fit into an int"); - } - result = shiftedResult + digit; - position++; - } - - if (negative) { - //allow -0x80000000, which is = 0x80000000 - if (result == Integer.MIN_VALUE) { - return result; - } else if (result < 0) { - throw new NumberFormatException(intLiteral + " cannot fit into an int"); - } - return result * -1; - } else { - return result; - } - } - - public static long parseLong(String longLiteral) - throws NumberFormatException { - if (longLiteral == null) { - throw new NumberFormatException("string is null"); - } - if (longLiteral.length() == 0) { - throw new NumberFormatException("string is blank"); - } - - char[] longChars; - if (longLiteral.toUpperCase().endsWith("L")) { - longChars = longLiteral.substring(0, longLiteral.length()-1).toCharArray(); - } else { - longChars = longLiteral.toCharArray(); - } - - int position = 0; - int radix = 10; - boolean negative = false; - if (longChars[position] == '-') { - position++; - negative = true; - } - - if (longChars[position] == '0') { - position++; - if (position == longChars.length) { - return 0; - } else if (longChars[position] == 'x' || longChars[position] == 'X') { - radix = 16; - position++; - } else if (Character.digit(longChars[position], 8) >= 0) { - radix = 8; - } - } - - long result = 0; - long shiftedResult; - int digit; - long maxValue = Long.MAX_VALUE / (radix / 2); - - while (position < longChars.length) { - digit = Character.digit(longChars[position], radix); - if (digit < 0) { - throw new NumberFormatException("The string contains an invalid digit - '" + longChars[position] + "'"); - } - shiftedResult = result * radix; - if (result > maxValue) { - throw new NumberFormatException(longLiteral + " cannot fit into a long"); - } - if (shiftedResult < 0 && shiftedResult >= -digit) { - throw new NumberFormatException(longLiteral + " cannot fit into a long"); - } - result = shiftedResult + digit; - position++; - } - - if (negative) { - //allow -0x8000000000000000, which is = 0x8000000000000000 - if (result == Long.MIN_VALUE) { - return result; - } else if (result < 0) { - throw new NumberFormatException(longLiteral + " cannot fit into a long"); - } - return result * -1; - } else { - return result; - } - } - - public static byte[] longToBytes(long value) { - byte[] bytes = new byte[8]; - - for (int i=0; value != 0; i++) { - bytes[i] = (byte)value; - value = value >>> 8; - } - return bytes; - } - - public static byte[] intToBytes(int value) { - byte[] bytes = new byte[4]; - - for (int i=0; value != 0; i++) { - bytes[i] = (byte)value; - value = value >>> 8; - } - return bytes; - } - - public static byte[] shortToBytes(short value) { - byte[] bytes = new byte[2]; - - bytes[0] = (byte)value; - bytes[1] = (byte)(value >>> 8); - return bytes; - } - - public static byte[] floatToBytes(float value) { - return intToBytes(Float.floatToRawIntBits(value)); - } - - public static byte[] doubleToBytes(double value) { - return longToBytes(Double.doubleToRawLongBits(value)); - } - - public static byte[] charToBytes(char value) { - return shortToBytes((short)value); - } - - public static byte[] boolToBytes(boolean value) { - if (value) { - return new byte[] { 0x01 }; - } else { - return new byte[] { 0x00 }; - } - } - - public static void checkInt(long value) { - if (value > 0xFFFFFFFF || value < -0x80000000) { - throw new NumberFormatException(Long.toString(value) + " cannot fit into an int"); - } - } - - public static void checkShort(long value) { - if (value > 0xFFFF | value < -0x8000) { - throw new NumberFormatException(Long.toString(value) + " cannot fit into a short"); - } - } - - public static void checkByte(long value) { - if (value > 0xFF | value < -0x80) { - throw new NumberFormatException(Long.toString(value) + " cannot fit into a byte"); - } - } - - public static void checkNibble(long value) { - if (value > 0x0F | value < -0x08) { - throw new NumberFormatException(Long.toString(value) + " cannot fit into a nibble"); - } - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.smali; + +public class literalTools +{ + public static byte parseByte(String byteLiteral) + throws NumberFormatException { + if (byteLiteral == null) { + throw new NumberFormatException("string is null"); + } + if (byteLiteral.length() == 0) { + throw new NumberFormatException("string is blank"); + } + + char[] byteChars; + if (byteLiteral.toUpperCase().endsWith("T")) { + byteChars = byteLiteral.substring(0, byteLiteral.length()-1).toCharArray(); + } else { + byteChars = byteLiteral.toCharArray(); + } + + int position = 0; + int radix = 10; + boolean negative = false; + if (byteChars[position] == '-') { + position++; + negative = true; + } + + if (byteChars[position] == '0') { + position++; + if (position == byteChars.length) { + return 0; + } else if (byteChars[position] == 'x' || byteChars[position] == 'X') { + radix = 16; + position++; + } else if (Character.digit(byteChars[position], 8) >= 0) { + radix = 8; + } + } + + byte result = 0; + byte shiftedResult; + int digit; + byte maxValue = (byte)(Byte.MAX_VALUE / (radix / 2)); + + while (position < byteChars.length) { + digit = Character.digit(byteChars[position], radix); + if (digit < 0) { + throw new NumberFormatException("The string contains invalid an digit - '" + byteChars[position] + "'"); + } + shiftedResult = (byte)(result * radix); + if (result > maxValue) { + throw new NumberFormatException(byteLiteral + " cannot fit into a byte"); + } + if (shiftedResult < 0 && shiftedResult >= -digit) { + throw new NumberFormatException(byteLiteral + " cannot fit into a byte"); + } + result = (byte)(shiftedResult + digit); + position++; + } + + if (negative) { + //allow -0x80, which is = 0x80 + if (result == Byte.MIN_VALUE) { + return result; + } else if (result < 0) { + throw new NumberFormatException(byteLiteral + " cannot fit into a byte"); + } + return (byte)(result * -1); + } else { + return result; + } + } + + public static short parseShort(String shortLiteral) + throws NumberFormatException { + if (shortLiteral == null) { + throw new NumberFormatException("string is null"); + } + if (shortLiteral.length() == 0) { + throw new NumberFormatException("string is blank"); + } + + char[] shortChars; + if (shortLiteral.toUpperCase().endsWith("S")) { + shortChars = shortLiteral.substring(0, shortLiteral.length()-1).toCharArray(); + } else { + shortChars = shortLiteral.toCharArray(); + } + + int position = 0; + int radix = 10; + boolean negative = false; + if (shortChars[position] == '-') { + position++; + negative = true; + } + + if (shortChars[position] == '0') { + position++; + if (position == shortChars.length) { + return 0; + } else if (shortChars[position] == 'x' || shortChars[position] == 'X') { + radix = 16; + position++; + } else if (Character.digit(shortChars[position], 8) >= 0) { + radix = 8; + } + } + + short result = 0; + short shiftedResult; + int digit; + short maxValue = (short)(Short.MAX_VALUE / (radix / 2)); + + while (position < shortChars.length) { + digit = Character.digit(shortChars[position], radix); + if (digit < 0) { + throw new NumberFormatException("The string contains invalid an digit - '" + shortChars[position] + "'"); + } + shiftedResult = (short)(result * radix); + if (result > maxValue) { + throw new NumberFormatException(shortLiteral + " cannot fit into a short"); + } + if (shiftedResult < 0 && shiftedResult >= -digit) { + throw new NumberFormatException(shortLiteral + " cannot fit into a short"); + } + result = (short)(shiftedResult + digit); + position++; + } + + if (negative) { + //allow -0x8000, which is = 0x8000 + if (result == Short.MIN_VALUE) { + return result; + } else if (result < 0) { + throw new NumberFormatException(shortLiteral + " cannot fit into a short"); + } + return (short)(result * -1); + } else { + return result; + } + } + + public static int parseInt(String intLiteral) + throws NumberFormatException { + if (intLiteral == null) { + throw new NumberFormatException("string is null"); + } + if (intLiteral.length() == 0) { + throw new NumberFormatException("string is blank"); + } + + char[] intChars = intLiteral.toCharArray(); + int position = 0; + int radix = 10; + boolean negative = false; + if (intChars[position] == '-') { + position++; + negative = true; + } + + if (intChars[position] == '0') { + position++; + if (position == intChars.length) { + return 0; + } else if (intChars[position] == 'x' || intChars[position] == 'X') { + radix = 16; + position++; + } else if (Character.digit(intChars[position], 8) >= 0) { + radix = 8; + } + } + + int result = 0; + int shiftedResult; + int digit; + int maxValue = Integer.MAX_VALUE / (radix / 2); + + while (position < intChars.length) { + digit = Character.digit(intChars[position], radix); + if (digit < 0) { + throw new NumberFormatException("The string contains an invalid digit - '" + intChars[position] + "'"); + } + shiftedResult = result * radix; + if (result > maxValue) { + throw new NumberFormatException(intLiteral + " cannot fit into an int"); + } + if (shiftedResult < 0 && shiftedResult >= -digit) { + throw new NumberFormatException(intLiteral + " cannot fit into an int"); + } + result = shiftedResult + digit; + position++; + } + + if (negative) { + //allow -0x80000000, which is = 0x80000000 + if (result == Integer.MIN_VALUE) { + return result; + } else if (result < 0) { + throw new NumberFormatException(intLiteral + " cannot fit into an int"); + } + return result * -1; + } else { + return result; + } + } + + public static long parseLong(String longLiteral) + throws NumberFormatException { + if (longLiteral == null) { + throw new NumberFormatException("string is null"); + } + if (longLiteral.length() == 0) { + throw new NumberFormatException("string is blank"); + } + + char[] longChars; + if (longLiteral.toUpperCase().endsWith("L")) { + longChars = longLiteral.substring(0, longLiteral.length()-1).toCharArray(); + } else { + longChars = longLiteral.toCharArray(); + } + + int position = 0; + int radix = 10; + boolean negative = false; + if (longChars[position] == '-') { + position++; + negative = true; + } + + if (longChars[position] == '0') { + position++; + if (position == longChars.length) { + return 0; + } else if (longChars[position] == 'x' || longChars[position] == 'X') { + radix = 16; + position++; + } else if (Character.digit(longChars[position], 8) >= 0) { + radix = 8; + } + } + + long result = 0; + long shiftedResult; + int digit; + long maxValue = Long.MAX_VALUE / (radix / 2); + + while (position < longChars.length) { + digit = Character.digit(longChars[position], radix); + if (digit < 0) { + throw new NumberFormatException("The string contains an invalid digit - '" + longChars[position] + "'"); + } + shiftedResult = result * radix; + if (result > maxValue) { + throw new NumberFormatException(longLiteral + " cannot fit into a long"); + } + if (shiftedResult < 0 && shiftedResult >= -digit) { + throw new NumberFormatException(longLiteral + " cannot fit into a long"); + } + result = shiftedResult + digit; + position++; + } + + if (negative) { + //allow -0x8000000000000000, which is = 0x8000000000000000 + if (result == Long.MIN_VALUE) { + return result; + } else if (result < 0) { + throw new NumberFormatException(longLiteral + " cannot fit into a long"); + } + return result * -1; + } else { + return result; + } + } + + public static byte[] longToBytes(long value) { + byte[] bytes = new byte[8]; + + for (int i=0; value != 0; i++) { + bytes[i] = (byte)value; + value = value >>> 8; + } + return bytes; + } + + public static byte[] intToBytes(int value) { + byte[] bytes = new byte[4]; + + for (int i=0; value != 0; i++) { + bytes[i] = (byte)value; + value = value >>> 8; + } + return bytes; + } + + public static byte[] shortToBytes(short value) { + byte[] bytes = new byte[2]; + + bytes[0] = (byte)value; + bytes[1] = (byte)(value >>> 8); + return bytes; + } + + public static byte[] floatToBytes(float value) { + return intToBytes(Float.floatToRawIntBits(value)); + } + + public static byte[] doubleToBytes(double value) { + return longToBytes(Double.doubleToRawLongBits(value)); + } + + public static byte[] charToBytes(char value) { + return shortToBytes((short)value); + } + + public static byte[] boolToBytes(boolean value) { + if (value) { + return new byte[] { 0x01 }; + } else { + return new byte[] { 0x00 }; + } + } + + public static void checkInt(long value) { + if (value > 0xFFFFFFFF || value < -0x80000000) { + throw new NumberFormatException(Long.toString(value) + " cannot fit into an int"); + } + } + + public static void checkShort(long value) { + if (value > 0xFFFF | value < -0x8000) { + throw new NumberFormatException(Long.toString(value) + " cannot fit into a short"); + } + } + + public static void checkByte(long value) { + if (value > 0xFF | value < -0x80) { + throw new NumberFormatException(Long.toString(value) + " cannot fit into a byte"); + } + } + + public static void checkNibble(long value) { + if (value > 0x0F | value < -0x08) { + throw new NumberFormatException(Long.toString(value) + " cannot fit into a nibble"); + } + } +} diff --git a/smali/src/main/java/org/jf/smali/main.java b/smali/src/main/java/org/jf/smali/main.java index ff96b1ed..6a429115 100644 --- a/smali/src/main/java/org/jf/smali/main.java +++ b/smali/src/main/java/org/jf/smali/main.java @@ -57,7 +57,7 @@ public class main { VERSION = version; } - + /** * This class is uninstantiable. */ @@ -290,7 +290,7 @@ public class main { if (dexGen.getNumberOfSyntaxErrors() > 0) { return false; } - + return true; } @@ -314,7 +314,7 @@ public class main { System.exit(0); } - + private static void buildOptions() { Option versionOption = OptionBuilder.withLongOpt("version") diff --git a/smali/src/test/java/ByteLiteralTest.java b/smali/src/test/java/ByteLiteralTest.java index 42609e30..7a07d395 100644 --- a/smali/src/test/java/ByteLiteralTest.java +++ b/smali/src/test/java/ByteLiteralTest.java @@ -1,139 +1,139 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. - */ - -import org.jf.smali.literalTools; -import org.junit.Assert; -import org.junit.Test; - -public class ByteLiteralTest -{ - - @Test - public void SuccessHexTests() { - - Assert.assertTrue(literalTools.parseByte("0x0T") == 0x0); - Assert.assertTrue(literalTools.parseByte("0x00") == 0x0); - Assert.assertTrue(literalTools.parseByte("0x1T") == 0x1); - Assert.assertTrue(literalTools.parseByte("0x12") == 0x12); - Assert.assertTrue(literalTools.parseByte("0x7fT") == 0x7f); - Assert.assertTrue(literalTools.parseByte("0x80t") == Byte.MIN_VALUE); - Assert.assertTrue(literalTools.parseByte("0xFFt") == -1); - - Assert.assertTrue(literalTools.parseByte("-0x00") == 0); - Assert.assertTrue(literalTools.parseByte("-0x01") == -1); - Assert.assertTrue(literalTools.parseByte("-0x12") == -0x12); - Assert.assertTrue(literalTools.parseByte("-0x80") == Byte.MIN_VALUE); - } - - @Test(expected=NumberFormatException.class) - public void FaileHexTest1() { - literalTools.parseByte("-0x81"); - } - - @Test(expected=NumberFormatException.class) - public void FailHexTest2() { - literalTools.parseByte("-0xFF"); - } - - @Test(expected=NumberFormatException.class) - public void FailHexTest3() { - literalTools.parseByte("0x100"); - } - - - - @Test - public void SuccessDecTests() { - Assert.assertTrue(literalTools.parseByte("0") == 0); - Assert.assertTrue(literalTools.parseByte("1t") == 1); - Assert.assertTrue(literalTools.parseByte("123") == 123); - Assert.assertTrue(literalTools.parseByte("127T") == 127); - Assert.assertTrue(literalTools.parseByte("128") == Byte.MIN_VALUE); - Assert.assertTrue(literalTools.parseByte("255") == -1); - - - Assert.assertTrue(literalTools.parseByte("-0") == 0); - Assert.assertTrue(literalTools.parseByte("-1") == -1); - Assert.assertTrue(literalTools.parseByte("-123") == -123); - Assert.assertTrue(literalTools.parseByte("-127") == -127); - Assert.assertTrue(literalTools.parseByte("-128") == Byte.MIN_VALUE); - } - - @Test(expected=NumberFormatException.class) - public void FaileDecTest1() { - literalTools.parseByte("-129"); - } - - @Test(expected=NumberFormatException.class) - public void FailDecTest2() { - literalTools.parseByte("-255"); - } - - @Test(expected=NumberFormatException.class) - public void FailDecTest3() { - literalTools.parseByte("256"); - } - - @Test(expected=NumberFormatException.class) - public void FailDecTest4() { - literalTools.parseByte("260"); - } - - - @Test - public void SuccessOctTests() { - Assert.assertTrue(literalTools.parseByte("00") == 00); - Assert.assertTrue(literalTools.parseByte("01") == 01); - Assert.assertTrue(literalTools.parseByte("0123t") == 0123); - Assert.assertTrue(literalTools.parseByte("0177") == Byte.MAX_VALUE); - Assert.assertTrue(literalTools.parseByte("0200T") == Byte.MIN_VALUE); - Assert.assertTrue(literalTools.parseByte("0377") == -1); - - - Assert.assertTrue(literalTools.parseByte("-00") == 0); - Assert.assertTrue(literalTools.parseByte("-01") == -1); - Assert.assertTrue(literalTools.parseByte("-0123") == -0123); - Assert.assertTrue(literalTools.parseByte("-0177") == -0177); - Assert.assertTrue(literalTools.parseByte("-0200") == Byte.MIN_VALUE); - } - - @Test(expected=NumberFormatException.class) - public void FaileOctTest1() { - literalTools.parseByte("-0201"); - } - - @Test(expected=NumberFormatException.class) - public void FailOctTest2() { - literalTools.parseByte("-0377"); - } - - @Test(expected=NumberFormatException.class) - public void FailOctTest3() { - literalTools.parseByte("0400"); - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +import org.jf.smali.literalTools; +import org.junit.Assert; +import org.junit.Test; + +public class ByteLiteralTest +{ + + @Test + public void SuccessHexTests() { + + Assert.assertTrue(literalTools.parseByte("0x0T") == 0x0); + Assert.assertTrue(literalTools.parseByte("0x00") == 0x0); + Assert.assertTrue(literalTools.parseByte("0x1T") == 0x1); + Assert.assertTrue(literalTools.parseByte("0x12") == 0x12); + Assert.assertTrue(literalTools.parseByte("0x7fT") == 0x7f); + Assert.assertTrue(literalTools.parseByte("0x80t") == Byte.MIN_VALUE); + Assert.assertTrue(literalTools.parseByte("0xFFt") == -1); + + Assert.assertTrue(literalTools.parseByte("-0x00") == 0); + Assert.assertTrue(literalTools.parseByte("-0x01") == -1); + Assert.assertTrue(literalTools.parseByte("-0x12") == -0x12); + Assert.assertTrue(literalTools.parseByte("-0x80") == Byte.MIN_VALUE); + } + + @Test(expected=NumberFormatException.class) + public void FaileHexTest1() { + literalTools.parseByte("-0x81"); + } + + @Test(expected=NumberFormatException.class) + public void FailHexTest2() { + literalTools.parseByte("-0xFF"); + } + + @Test(expected=NumberFormatException.class) + public void FailHexTest3() { + literalTools.parseByte("0x100"); + } + + + + @Test + public void SuccessDecTests() { + Assert.assertTrue(literalTools.parseByte("0") == 0); + Assert.assertTrue(literalTools.parseByte("1t") == 1); + Assert.assertTrue(literalTools.parseByte("123") == 123); + Assert.assertTrue(literalTools.parseByte("127T") == 127); + Assert.assertTrue(literalTools.parseByte("128") == Byte.MIN_VALUE); + Assert.assertTrue(literalTools.parseByte("255") == -1); + + + Assert.assertTrue(literalTools.parseByte("-0") == 0); + Assert.assertTrue(literalTools.parseByte("-1") == -1); + Assert.assertTrue(literalTools.parseByte("-123") == -123); + Assert.assertTrue(literalTools.parseByte("-127") == -127); + Assert.assertTrue(literalTools.parseByte("-128") == Byte.MIN_VALUE); + } + + @Test(expected=NumberFormatException.class) + public void FaileDecTest1() { + literalTools.parseByte("-129"); + } + + @Test(expected=NumberFormatException.class) + public void FailDecTest2() { + literalTools.parseByte("-255"); + } + + @Test(expected=NumberFormatException.class) + public void FailDecTest3() { + literalTools.parseByte("256"); + } + + @Test(expected=NumberFormatException.class) + public void FailDecTest4() { + literalTools.parseByte("260"); + } + + + @Test + public void SuccessOctTests() { + Assert.assertTrue(literalTools.parseByte("00") == 00); + Assert.assertTrue(literalTools.parseByte("01") == 01); + Assert.assertTrue(literalTools.parseByte("0123t") == 0123); + Assert.assertTrue(literalTools.parseByte("0177") == Byte.MAX_VALUE); + Assert.assertTrue(literalTools.parseByte("0200T") == Byte.MIN_VALUE); + Assert.assertTrue(literalTools.parseByte("0377") == -1); + + + Assert.assertTrue(literalTools.parseByte("-00") == 0); + Assert.assertTrue(literalTools.parseByte("-01") == -1); + Assert.assertTrue(literalTools.parseByte("-0123") == -0123); + Assert.assertTrue(literalTools.parseByte("-0177") == -0177); + Assert.assertTrue(literalTools.parseByte("-0200") == Byte.MIN_VALUE); + } + + @Test(expected=NumberFormatException.class) + public void FaileOctTest1() { + literalTools.parseByte("-0201"); + } + + @Test(expected=NumberFormatException.class) + public void FailOctTest2() { + literalTools.parseByte("-0377"); + } + + @Test(expected=NumberFormatException.class) + public void FailOctTest3() { + literalTools.parseByte("0400"); + } +} diff --git a/smali/src/test/java/IntLiteralTest.java b/smali/src/test/java/IntLiteralTest.java index eb7dbc8d..15258252 100644 --- a/smali/src/test/java/IntLiteralTest.java +++ b/smali/src/test/java/IntLiteralTest.java @@ -1,144 +1,144 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. - */ - -import org.jf.smali.literalTools; -import org.junit.Assert; -import org.junit.Test; - -public class IntLiteralTest -{ - - @Test - public void SuccessHexTests() { - - Assert.assertTrue(literalTools.parseInt("0x0") == 0x0); - Assert.assertTrue(literalTools.parseInt("0x00") == 0x0); - Assert.assertTrue(literalTools.parseInt("0x1") == 0x1); - Assert.assertTrue(literalTools.parseInt("0x12345678") == 0x12345678); - Assert.assertTrue(literalTools.parseInt("0x7fffffff") == 0x7fffffff); - Assert.assertTrue(literalTools.parseInt("0x80000000") == Integer.MIN_VALUE); - Assert.assertTrue(literalTools.parseInt("0xFFFFFFFF") == -1); - - Assert.assertTrue(literalTools.parseInt("-0x00") == 0); - Assert.assertTrue(literalTools.parseInt("-0x01") == -1); - Assert.assertTrue(literalTools.parseInt("-0x12345678") == -0x12345678); - Assert.assertTrue(literalTools.parseInt("-0x80000000") == Integer.MIN_VALUE); - } - - @Test(expected=NumberFormatException.class) - public void FaileHexTest1() { - literalTools.parseInt("-0x80000001"); - } - - @Test(expected=NumberFormatException.class) - public void FailHexTest2() { - literalTools.parseInt("-0xFFFFFFFF"); - } - - @Test(expected=NumberFormatException.class) - public void FailHexTest3() { - literalTools.parseInt("0x100000000"); - } - - - - @Test - public void SuccessDecTests() { - Assert.assertTrue(literalTools.parseInt("0") == 0); - Assert.assertTrue(literalTools.parseInt("1") == 1); - Assert.assertTrue(literalTools.parseInt("1234567890") == 1234567890); - Assert.assertTrue(literalTools.parseInt("2147483647") == 2147483647); - Assert.assertTrue(literalTools.parseInt("2147483648") == Integer.MIN_VALUE); - Assert.assertTrue(literalTools.parseInt("4294967295") == -1); - - - Assert.assertTrue(literalTools.parseInt("-0") == 0); - Assert.assertTrue(literalTools.parseInt("-1") == -1); - Assert.assertTrue(literalTools.parseInt("-1234567890") == -1234567890); - Assert.assertTrue(literalTools.parseInt("-2147483647") == -2147483647); - Assert.assertTrue(literalTools.parseInt("-2147483648") == Integer.MIN_VALUE); - } - - @Test(expected=NumberFormatException.class) - public void FaileDecTest1() { - literalTools.parseInt("-2147483649"); - } - - @Test(expected=NumberFormatException.class) - public void FailDecTest2() { - literalTools.parseInt("-4294967295"); - } - - @Test(expected=NumberFormatException.class) - public void FailDecTest3() { - literalTools.parseInt("4294967296"); - } - - @Test(expected=NumberFormatException.class) - public void FailDecTest4() { - literalTools.parseInt("4294967300"); - } - - @Test(expected=NumberFormatException.class) - public void FailDecTest5() { - literalTools.parseInt("8589934592"); - } - - - @Test - public void SuccessOctTests() { - Assert.assertTrue(literalTools.parseInt("00") == 00); - Assert.assertTrue(literalTools.parseInt("01") == 01); - Assert.assertTrue(literalTools.parseInt("012345670123") == 012345670123); - Assert.assertTrue(literalTools.parseInt("017777777777") == Integer.MAX_VALUE); - Assert.assertTrue(literalTools.parseInt("020000000000") == Integer.MIN_VALUE); - Assert.assertTrue(literalTools.parseInt("037777777777") == -1); - - - Assert.assertTrue(literalTools.parseInt("-00") == 0); - Assert.assertTrue(literalTools.parseInt("-01") == -1); - Assert.assertTrue(literalTools.parseInt("-012345670123") == -012345670123); - Assert.assertTrue(literalTools.parseInt("-017777777777") == -017777777777); - Assert.assertTrue(literalTools.parseInt("-020000000000") == Integer.MIN_VALUE); - } - - @Test(expected=NumberFormatException.class) - public void FaileOctTest1() { - literalTools.parseInt("-020000000001"); - } - - @Test(expected=NumberFormatException.class) - public void FailOctTest2() { - literalTools.parseInt("-037777777777"); - } - - @Test(expected=NumberFormatException.class) - public void FailOctTest3() { - literalTools.parseInt("040000000000"); - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +import org.jf.smali.literalTools; +import org.junit.Assert; +import org.junit.Test; + +public class IntLiteralTest +{ + + @Test + public void SuccessHexTests() { + + Assert.assertTrue(literalTools.parseInt("0x0") == 0x0); + Assert.assertTrue(literalTools.parseInt("0x00") == 0x0); + Assert.assertTrue(literalTools.parseInt("0x1") == 0x1); + Assert.assertTrue(literalTools.parseInt("0x12345678") == 0x12345678); + Assert.assertTrue(literalTools.parseInt("0x7fffffff") == 0x7fffffff); + Assert.assertTrue(literalTools.parseInt("0x80000000") == Integer.MIN_VALUE); + Assert.assertTrue(literalTools.parseInt("0xFFFFFFFF") == -1); + + Assert.assertTrue(literalTools.parseInt("-0x00") == 0); + Assert.assertTrue(literalTools.parseInt("-0x01") == -1); + Assert.assertTrue(literalTools.parseInt("-0x12345678") == -0x12345678); + Assert.assertTrue(literalTools.parseInt("-0x80000000") == Integer.MIN_VALUE); + } + + @Test(expected=NumberFormatException.class) + public void FaileHexTest1() { + literalTools.parseInt("-0x80000001"); + } + + @Test(expected=NumberFormatException.class) + public void FailHexTest2() { + literalTools.parseInt("-0xFFFFFFFF"); + } + + @Test(expected=NumberFormatException.class) + public void FailHexTest3() { + literalTools.parseInt("0x100000000"); + } + + + + @Test + public void SuccessDecTests() { + Assert.assertTrue(literalTools.parseInt("0") == 0); + Assert.assertTrue(literalTools.parseInt("1") == 1); + Assert.assertTrue(literalTools.parseInt("1234567890") == 1234567890); + Assert.assertTrue(literalTools.parseInt("2147483647") == 2147483647); + Assert.assertTrue(literalTools.parseInt("2147483648") == Integer.MIN_VALUE); + Assert.assertTrue(literalTools.parseInt("4294967295") == -1); + + + Assert.assertTrue(literalTools.parseInt("-0") == 0); + Assert.assertTrue(literalTools.parseInt("-1") == -1); + Assert.assertTrue(literalTools.parseInt("-1234567890") == -1234567890); + Assert.assertTrue(literalTools.parseInt("-2147483647") == -2147483647); + Assert.assertTrue(literalTools.parseInt("-2147483648") == Integer.MIN_VALUE); + } + + @Test(expected=NumberFormatException.class) + public void FaileDecTest1() { + literalTools.parseInt("-2147483649"); + } + + @Test(expected=NumberFormatException.class) + public void FailDecTest2() { + literalTools.parseInt("-4294967295"); + } + + @Test(expected=NumberFormatException.class) + public void FailDecTest3() { + literalTools.parseInt("4294967296"); + } + + @Test(expected=NumberFormatException.class) + public void FailDecTest4() { + literalTools.parseInt("4294967300"); + } + + @Test(expected=NumberFormatException.class) + public void FailDecTest5() { + literalTools.parseInt("8589934592"); + } + + + @Test + public void SuccessOctTests() { + Assert.assertTrue(literalTools.parseInt("00") == 00); + Assert.assertTrue(literalTools.parseInt("01") == 01); + Assert.assertTrue(literalTools.parseInt("012345670123") == 012345670123); + Assert.assertTrue(literalTools.parseInt("017777777777") == Integer.MAX_VALUE); + Assert.assertTrue(literalTools.parseInt("020000000000") == Integer.MIN_VALUE); + Assert.assertTrue(literalTools.parseInt("037777777777") == -1); + + + Assert.assertTrue(literalTools.parseInt("-00") == 0); + Assert.assertTrue(literalTools.parseInt("-01") == -1); + Assert.assertTrue(literalTools.parseInt("-012345670123") == -012345670123); + Assert.assertTrue(literalTools.parseInt("-017777777777") == -017777777777); + Assert.assertTrue(literalTools.parseInt("-020000000000") == Integer.MIN_VALUE); + } + + @Test(expected=NumberFormatException.class) + public void FaileOctTest1() { + literalTools.parseInt("-020000000001"); + } + + @Test(expected=NumberFormatException.class) + public void FailOctTest2() { + literalTools.parseInt("-037777777777"); + } + + @Test(expected=NumberFormatException.class) + public void FailOctTest3() { + literalTools.parseInt("040000000000"); + } +} diff --git a/smali/src/test/java/LongLiteralTest.java b/smali/src/test/java/LongLiteralTest.java index cf749de7..f54ef8f6 100644 --- a/smali/src/test/java/LongLiteralTest.java +++ b/smali/src/test/java/LongLiteralTest.java @@ -1,139 +1,139 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. - */ - -import org.jf.smali.literalTools; -import org.junit.Assert; -import org.junit.Test; - -public class LongLiteralTest -{ - - @Test - public void SuccessHexTests() { - - Assert.assertTrue(literalTools.parseLong("0x0L") == 0x0); - Assert.assertTrue(literalTools.parseLong("0x00") == 0x0); - Assert.assertTrue(literalTools.parseLong("0x1L") == 0x1); - Assert.assertTrue(literalTools.parseLong("0x1234567890123456L") == 0x1234567890123456L); - Assert.assertTrue(literalTools.parseLong("0x7fffffffffffffffL") == 0x7fffffffffffffffL); - Assert.assertTrue(literalTools.parseLong("0x8000000000000000L") == Long.MIN_VALUE); - Assert.assertTrue(literalTools.parseLong("0xFFFFFFFFFFFFFFFFL") == -1); - - Assert.assertTrue(literalTools.parseLong("-0x00L") == 0); - Assert.assertTrue(literalTools.parseLong("-0x01L") == -1); - Assert.assertTrue(literalTools.parseLong("-0x1234567890123456L") == -0x1234567890123456L); - Assert.assertTrue(literalTools.parseLong("-0x8000000000000000") == Long.MIN_VALUE); - } - - @Test(expected=NumberFormatException.class) - public void FaileHexTest1() { - literalTools.parseLong("-0x8000000000000001"); - } - - @Test(expected=NumberFormatException.class) - public void FailHexTest2() { - literalTools.parseLong("-0xFFFFFFFFFFFFFFFF"); - } - - @Test(expected=NumberFormatException.class) - public void FailHexTest3() { - literalTools.parseLong("0x10000000000000000"); - } - - - - @Test - public void SuccessDecTests() { - Assert.assertTrue(literalTools.parseLong("0L") == 0); - Assert.assertTrue(literalTools.parseLong("1") == 1); - Assert.assertTrue(literalTools.parseLong("1234567890123456789") == 1234567890123456789L); - Assert.assertTrue(literalTools.parseLong("9223372036854775807") == 9223372036854775807L); - Assert.assertTrue(literalTools.parseLong("9223372036854775808") == Long.MIN_VALUE); - Assert.assertTrue(literalTools.parseLong("18446744073709551615L") == -1); - - - Assert.assertTrue(literalTools.parseLong("-0") == 0); - Assert.assertTrue(literalTools.parseLong("-1") == -1); - Assert.assertTrue(literalTools.parseLong("-1234567890123456789") == -1234567890123456789L); - Assert.assertTrue(literalTools.parseLong("-9223372036854775807") == -9223372036854775807L); - Assert.assertTrue(literalTools.parseLong("-9223372036854775808") == Long.MIN_VALUE); - } - - @Test(expected=NumberFormatException.class) - public void FaileDecTest1() { - literalTools.parseLong("-9223372036854775809"); - } - - @Test(expected=NumberFormatException.class) - public void FailDecTest2() { - literalTools.parseLong("-18446744073709551616"); - } - - @Test(expected=NumberFormatException.class) - public void FailDecTest3() { - literalTools.parseLong("18446744073709551617"); - } - - @Test(expected=NumberFormatException.class) - public void FailDecTest4() { - literalTools.parseLong("18446744073709551700"); - } - - - @Test - public void SuccessOctTests() { - Assert.assertTrue(literalTools.parseLong("00") == 00); - Assert.assertTrue(literalTools.parseLong("01") == 01); - Assert.assertTrue(literalTools.parseLong("0123456701234567012345") == 0123456701234567012345L); - Assert.assertTrue(literalTools.parseLong("0777777777777777777777") == Long.MAX_VALUE); - Assert.assertTrue(literalTools.parseLong("01000000000000000000000") == Long.MIN_VALUE); - Assert.assertTrue(literalTools.parseLong("01777777777777777777777") == -1); - - - Assert.assertTrue(literalTools.parseLong("-00") == 0); - Assert.assertTrue(literalTools.parseLong("-01") == -1); - Assert.assertTrue(literalTools.parseLong("-0123456701234567012345") == -0123456701234567012345L); - Assert.assertTrue(literalTools.parseLong("-0777777777777777777777") == -0777777777777777777777L); - Assert.assertTrue(literalTools.parseLong("-01000000000000000000000") == Long.MIN_VALUE); - } - - @Test(expected=NumberFormatException.class) - public void FaileOctTest1() { - literalTools.parseLong("-01000000000000000000001"); - } - - @Test(expected=NumberFormatException.class) - public void FailOctTest2() { - literalTools.parseLong("-01777777777777777777777"); - } - - @Test(expected=NumberFormatException.class) - public void FailOctTest3() { - literalTools.parseLong("02000000000000000000000"); - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +import org.jf.smali.literalTools; +import org.junit.Assert; +import org.junit.Test; + +public class LongLiteralTest +{ + + @Test + public void SuccessHexTests() { + + Assert.assertTrue(literalTools.parseLong("0x0L") == 0x0); + Assert.assertTrue(literalTools.parseLong("0x00") == 0x0); + Assert.assertTrue(literalTools.parseLong("0x1L") == 0x1); + Assert.assertTrue(literalTools.parseLong("0x1234567890123456L") == 0x1234567890123456L); + Assert.assertTrue(literalTools.parseLong("0x7fffffffffffffffL") == 0x7fffffffffffffffL); + Assert.assertTrue(literalTools.parseLong("0x8000000000000000L") == Long.MIN_VALUE); + Assert.assertTrue(literalTools.parseLong("0xFFFFFFFFFFFFFFFFL") == -1); + + Assert.assertTrue(literalTools.parseLong("-0x00L") == 0); + Assert.assertTrue(literalTools.parseLong("-0x01L") == -1); + Assert.assertTrue(literalTools.parseLong("-0x1234567890123456L") == -0x1234567890123456L); + Assert.assertTrue(literalTools.parseLong("-0x8000000000000000") == Long.MIN_VALUE); + } + + @Test(expected=NumberFormatException.class) + public void FaileHexTest1() { + literalTools.parseLong("-0x8000000000000001"); + } + + @Test(expected=NumberFormatException.class) + public void FailHexTest2() { + literalTools.parseLong("-0xFFFFFFFFFFFFFFFF"); + } + + @Test(expected=NumberFormatException.class) + public void FailHexTest3() { + literalTools.parseLong("0x10000000000000000"); + } + + + + @Test + public void SuccessDecTests() { + Assert.assertTrue(literalTools.parseLong("0L") == 0); + Assert.assertTrue(literalTools.parseLong("1") == 1); + Assert.assertTrue(literalTools.parseLong("1234567890123456789") == 1234567890123456789L); + Assert.assertTrue(literalTools.parseLong("9223372036854775807") == 9223372036854775807L); + Assert.assertTrue(literalTools.parseLong("9223372036854775808") == Long.MIN_VALUE); + Assert.assertTrue(literalTools.parseLong("18446744073709551615L") == -1); + + + Assert.assertTrue(literalTools.parseLong("-0") == 0); + Assert.assertTrue(literalTools.parseLong("-1") == -1); + Assert.assertTrue(literalTools.parseLong("-1234567890123456789") == -1234567890123456789L); + Assert.assertTrue(literalTools.parseLong("-9223372036854775807") == -9223372036854775807L); + Assert.assertTrue(literalTools.parseLong("-9223372036854775808") == Long.MIN_VALUE); + } + + @Test(expected=NumberFormatException.class) + public void FaileDecTest1() { + literalTools.parseLong("-9223372036854775809"); + } + + @Test(expected=NumberFormatException.class) + public void FailDecTest2() { + literalTools.parseLong("-18446744073709551616"); + } + + @Test(expected=NumberFormatException.class) + public void FailDecTest3() { + literalTools.parseLong("18446744073709551617"); + } + + @Test(expected=NumberFormatException.class) + public void FailDecTest4() { + literalTools.parseLong("18446744073709551700"); + } + + + @Test + public void SuccessOctTests() { + Assert.assertTrue(literalTools.parseLong("00") == 00); + Assert.assertTrue(literalTools.parseLong("01") == 01); + Assert.assertTrue(literalTools.parseLong("0123456701234567012345") == 0123456701234567012345L); + Assert.assertTrue(literalTools.parseLong("0777777777777777777777") == Long.MAX_VALUE); + Assert.assertTrue(literalTools.parseLong("01000000000000000000000") == Long.MIN_VALUE); + Assert.assertTrue(literalTools.parseLong("01777777777777777777777") == -1); + + + Assert.assertTrue(literalTools.parseLong("-00") == 0); + Assert.assertTrue(literalTools.parseLong("-01") == -1); + Assert.assertTrue(literalTools.parseLong("-0123456701234567012345") == -0123456701234567012345L); + Assert.assertTrue(literalTools.parseLong("-0777777777777777777777") == -0777777777777777777777L); + Assert.assertTrue(literalTools.parseLong("-01000000000000000000000") == Long.MIN_VALUE); + } + + @Test(expected=NumberFormatException.class) + public void FaileOctTest1() { + literalTools.parseLong("-01000000000000000000001"); + } + + @Test(expected=NumberFormatException.class) + public void FailOctTest2() { + literalTools.parseLong("-01777777777777777777777"); + } + + @Test(expected=NumberFormatException.class) + public void FailOctTest3() { + literalTools.parseLong("02000000000000000000000"); + } +} diff --git a/smali/src/test/java/ShortLiteralTest.java b/smali/src/test/java/ShortLiteralTest.java index 16d1553e..2b9824fb 100644 --- a/smali/src/test/java/ShortLiteralTest.java +++ b/smali/src/test/java/ShortLiteralTest.java @@ -1,139 +1,139 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. - */ - -import org.jf.smali.literalTools; -import org.junit.Assert; -import org.junit.Test; - -public class ShortLiteralTest -{ - - @Test - public void SuccessHexTests() { - - Assert.assertTrue(literalTools.parseShort("0x0") == 0x0); - Assert.assertTrue(literalTools.parseShort("0x00") == 0x0); - Assert.assertTrue(literalTools.parseShort("0x1") == 0x1); - Assert.assertTrue(literalTools.parseShort("0x1234") == 0x1234); - Assert.assertTrue(literalTools.parseShort("0x7fff") == 0x7fff); - Assert.assertTrue(literalTools.parseShort("0x8000") == Short.MIN_VALUE); - Assert.assertTrue(literalTools.parseShort("0xFFFF") == -1); - - Assert.assertTrue(literalTools.parseShort("-0x00") == 0); - Assert.assertTrue(literalTools.parseShort("-0x01") == -1); - Assert.assertTrue(literalTools.parseShort("-0x1234") == -0x1234); - Assert.assertTrue(literalTools.parseShort("-0x8000") == Short.MIN_VALUE); - } - - @Test(expected=NumberFormatException.class) - public void FaileHexTest1() { - literalTools.parseShort("-0x8001"); - } - - @Test(expected=NumberFormatException.class) - public void FailHexTest2() { - literalTools.parseShort("-0xFFFF"); - } - - @Test(expected=NumberFormatException.class) - public void FailHexTest3() { - literalTools.parseShort("0x100000"); - } - - - - @Test - public void SuccessDecTests() { - Assert.assertTrue(literalTools.parseShort("0") == 0); - Assert.assertTrue(literalTools.parseShort("1") == 1); - Assert.assertTrue(literalTools.parseShort("12345") == 12345); - Assert.assertTrue(literalTools.parseShort("32767") == 32767); - Assert.assertTrue(literalTools.parseShort("32768") == Short.MIN_VALUE); - Assert.assertTrue(literalTools.parseShort("65535") == -1); - - - Assert.assertTrue(literalTools.parseShort("-0") == 0); - Assert.assertTrue(literalTools.parseShort("-1") == -1); - Assert.assertTrue(literalTools.parseShort("-12345") == -12345); - Assert.assertTrue(literalTools.parseShort("-32767") == -32767); - Assert.assertTrue(literalTools.parseShort("-32768") == Short.MIN_VALUE); - } - - @Test(expected=NumberFormatException.class) - public void FaileDecTest1() { - literalTools.parseShort("-32769"); - } - - @Test(expected=NumberFormatException.class) - public void FailDecTest2() { - literalTools.parseShort("-65535"); - } - - @Test(expected=NumberFormatException.class) - public void FailDecTest3() { - literalTools.parseShort("65536"); - } - - @Test(expected=NumberFormatException.class) - public void FailDecTest4() { - literalTools.parseShort("65600"); - } - - - @Test - public void SuccessOctTests() { - Assert.assertTrue(literalTools.parseShort("00") == 00); - Assert.assertTrue(literalTools.parseShort("01") == 01); - Assert.assertTrue(literalTools.parseShort("012345") == 012345); - Assert.assertTrue(literalTools.parseShort("077777") == Short.MAX_VALUE); - Assert.assertTrue(literalTools.parseShort("0100000") == Short.MIN_VALUE); - Assert.assertTrue(literalTools.parseShort("0177777") == -1); - - - Assert.assertTrue(literalTools.parseShort("-00") == 0); - Assert.assertTrue(literalTools.parseShort("-01") == -1); - Assert.assertTrue(literalTools.parseShort("-012345") == -012345); - Assert.assertTrue(literalTools.parseShort("-077777") == -077777); - Assert.assertTrue(literalTools.parseShort("-0100000") == Short.MIN_VALUE); - } - - @Test(expected=NumberFormatException.class) - public void FaileOctTest1() { - literalTools.parseShort("-0100001"); - } - - @Test(expected=NumberFormatException.class) - public void FailOctTest2() { - literalTools.parseShort("-0177777"); - } - - @Test(expected=NumberFormatException.class) - public void FailOctTest3() { - literalTools.parseShort("0200000"); - } -} +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +import org.jf.smali.literalTools; +import org.junit.Assert; +import org.junit.Test; + +public class ShortLiteralTest +{ + + @Test + public void SuccessHexTests() { + + Assert.assertTrue(literalTools.parseShort("0x0") == 0x0); + Assert.assertTrue(literalTools.parseShort("0x00") == 0x0); + Assert.assertTrue(literalTools.parseShort("0x1") == 0x1); + Assert.assertTrue(literalTools.parseShort("0x1234") == 0x1234); + Assert.assertTrue(literalTools.parseShort("0x7fff") == 0x7fff); + Assert.assertTrue(literalTools.parseShort("0x8000") == Short.MIN_VALUE); + Assert.assertTrue(literalTools.parseShort("0xFFFF") == -1); + + Assert.assertTrue(literalTools.parseShort("-0x00") == 0); + Assert.assertTrue(literalTools.parseShort("-0x01") == -1); + Assert.assertTrue(literalTools.parseShort("-0x1234") == -0x1234); + Assert.assertTrue(literalTools.parseShort("-0x8000") == Short.MIN_VALUE); + } + + @Test(expected=NumberFormatException.class) + public void FaileHexTest1() { + literalTools.parseShort("-0x8001"); + } + + @Test(expected=NumberFormatException.class) + public void FailHexTest2() { + literalTools.parseShort("-0xFFFF"); + } + + @Test(expected=NumberFormatException.class) + public void FailHexTest3() { + literalTools.parseShort("0x100000"); + } + + + + @Test + public void SuccessDecTests() { + Assert.assertTrue(literalTools.parseShort("0") == 0); + Assert.assertTrue(literalTools.parseShort("1") == 1); + Assert.assertTrue(literalTools.parseShort("12345") == 12345); + Assert.assertTrue(literalTools.parseShort("32767") == 32767); + Assert.assertTrue(literalTools.parseShort("32768") == Short.MIN_VALUE); + Assert.assertTrue(literalTools.parseShort("65535") == -1); + + + Assert.assertTrue(literalTools.parseShort("-0") == 0); + Assert.assertTrue(literalTools.parseShort("-1") == -1); + Assert.assertTrue(literalTools.parseShort("-12345") == -12345); + Assert.assertTrue(literalTools.parseShort("-32767") == -32767); + Assert.assertTrue(literalTools.parseShort("-32768") == Short.MIN_VALUE); + } + + @Test(expected=NumberFormatException.class) + public void FaileDecTest1() { + literalTools.parseShort("-32769"); + } + + @Test(expected=NumberFormatException.class) + public void FailDecTest2() { + literalTools.parseShort("-65535"); + } + + @Test(expected=NumberFormatException.class) + public void FailDecTest3() { + literalTools.parseShort("65536"); + } + + @Test(expected=NumberFormatException.class) + public void FailDecTest4() { + literalTools.parseShort("65600"); + } + + + @Test + public void SuccessOctTests() { + Assert.assertTrue(literalTools.parseShort("00") == 00); + Assert.assertTrue(literalTools.parseShort("01") == 01); + Assert.assertTrue(literalTools.parseShort("012345") == 012345); + Assert.assertTrue(literalTools.parseShort("077777") == Short.MAX_VALUE); + Assert.assertTrue(literalTools.parseShort("0100000") == Short.MIN_VALUE); + Assert.assertTrue(literalTools.parseShort("0177777") == -1); + + + Assert.assertTrue(literalTools.parseShort("-00") == 0); + Assert.assertTrue(literalTools.parseShort("-01") == -1); + Assert.assertTrue(literalTools.parseShort("-012345") == -012345); + Assert.assertTrue(literalTools.parseShort("-077777") == -077777); + Assert.assertTrue(literalTools.parseShort("-0100000") == Short.MIN_VALUE); + } + + @Test(expected=NumberFormatException.class) + public void FaileOctTest1() { + literalTools.parseShort("-0100001"); + } + + @Test(expected=NumberFormatException.class) + public void FailOctTest2() { + literalTools.parseShort("-0177777"); + } + + @Test(expected=NumberFormatException.class) + public void FailOctTest3() { + literalTools.parseShort("0200000"); + } +}