From f10d1a3598f5ba4476805bebfed64b664299edac Mon Sep 17 00:00:00 2001 From: "JesusFreke@JesusFreke.com" Date: Thu, 16 Apr 2009 06:14:38 +0000 Subject: [PATCH] Initial commit git-svn-id: https://smali.googlecode.com/svn/trunk@2 55b6fa8a-2a1e-11de-a435-ffa8d773f76a --- pom.xml | 56 ++ src/main/antlr3/org/JesusFreke/smali/smali.g | 594 ++++++++++++++++++ .../org/JesusFreke/smali/smaliTreeWalker.g | 437 +++++++++++++ .../dexlib/AnnotationDirectoryItem.java | 133 ++++ .../org/JesusFreke/dexlib/AnnotationItem.java | 81 +++ .../JesusFreke/dexlib/AnnotationSetItem.java | 68 ++ .../dexlib/AnnotationSetRefList.java | 68 ++ .../java/org/JesusFreke/dexlib/ByteField.java | 63 ++ .../dexlib/CachedIntegerValueField.java | 52 ++ .../org/JesusFreke/dexlib/ClassDataItem.java | 351 +++++++++++ .../org/JesusFreke/dexlib/ClassDefItem.java | 229 +++++++ .../java/org/JesusFreke/dexlib/CodeItem.java | 384 +++++++++++ .../org/JesusFreke/dexlib/CompositeField.java | 102 +++ .../org/JesusFreke/dexlib/DebugInfoItem.java | 116 ++++ .../java/org/JesusFreke/dexlib/DexFile.java | 390 ++++++++++++ .../JesusFreke/dexlib/EncodedArrayItem.java | 91 +++ .../EncodedValue/AnnotationElement.java | 49 ++ .../AnnotationEncodedValueSubField.java | 72 +++ .../ArrayEncodedValueSubField.java | 86 +++ .../BoolEncodedValueSubField.java | 62 ++ .../ByteEncodedValueSubField.java | 63 ++ .../CharEncodedValueSubField.java | 65 ++ .../DoubleEncodedValueSubField.java | 68 ++ .../EncodedIndexedItemReference.java | 100 +++ .../dexlib/EncodedValue/EncodedValue.java | 188 ++++++ .../EncodedValue/EncodedValueSubField.java | 38 ++ .../EncodedValueSubFieldFactory.java | 74 +++ .../FloatEncodedValueSubField.java | 67 ++ .../EncodedValue/IntEncodedValueSubField.java | 64 ++ .../LongEncodedValueSubField.java | 64 ++ .../NullEncodedValueSubField.java | 58 ++ .../ShortEncodedValueSubField.java | 64 ++ .../SimpleEncodedValueSubField.java | 68 ++ .../dexlib/EncodedValue/ValueType.java | 87 +++ .../java/org/JesusFreke/dexlib/Field.java | 39 ++ .../org/JesusFreke/dexlib/FieldIdItem.java | 96 +++ .../org/JesusFreke/dexlib/FieldListField.java | 105 ++++ .../dexlib/FixedByteArrayField.java | 66 ++ .../org/JesusFreke/dexlib/HeaderItem.java | 169 +++++ .../org/JesusFreke/dexlib/IndexedItem.java | 46 ++ .../dexlib/IndexedItemReference.java | 79 +++ .../org/JesusFreke/dexlib/IndexedSection.java | 88 +++ .../org/JesusFreke/dexlib/IntegerField.java | 70 +++ src/main/java/org/JesusFreke/dexlib/Item.java | 142 +++++ .../org/JesusFreke/dexlib/ItemReference.java | 87 +++ .../java/org/JesusFreke/dexlib/ItemType.java | 106 ++++ .../org/JesusFreke/dexlib/Leb128Field.java | 64 ++ .../org/JesusFreke/dexlib/Leb128p1Field.java | 64 ++ .../org/JesusFreke/dexlib/ListSizeField.java | 90 +++ .../java/org/JesusFreke/dexlib/MapField.java | 88 +++ .../java/org/JesusFreke/dexlib/MapItem.java | 135 ++++ .../org/JesusFreke/dexlib/MethodIdItem.java | 106 ++++ .../dexlib/NullTerminatedByteArrayField.java | 99 +++ .../org/JesusFreke/dexlib/OffsettedItem.java | 36 ++ .../dexlib/OffsettedItemReference.java | 86 +++ .../JesusFreke/dexlib/OffsettedSection.java | 83 +++ .../org/JesusFreke/dexlib/ProtoIdItem.java | 112 ++++ .../java/org/JesusFreke/dexlib/Section.java | 133 ++++ .../JesusFreke/dexlib/SectionHeaderInfo.java | 83 +++ .../JesusFreke/dexlib/ShortIntegerField.java | 70 +++ .../JesusFreke/dexlib/SignedLeb128Field.java | 64 ++ .../org/JesusFreke/dexlib/StringDataItem.java | 85 +++ .../org/JesusFreke/dexlib/StringIdItem.java | 75 +++ .../org/JesusFreke/dexlib/TypeIdItem.java | 100 +++ .../org/JesusFreke/dexlib/TypeListItem.java | 114 ++++ .../JesusFreke/dexlib/code/Format/Format.java | 43 ++ .../dexlib/code/Format/Format10x.java | 59 ++ .../dexlib/code/Format/Format11x.java | 63 ++ .../dexlib/code/Format/Format21c.java | 67 ++ .../dexlib/code/Format/Format22c.java | 69 ++ .../dexlib/code/Format/Format35c.java | 114 ++++ .../dexlib/code/Format/Format3rc.java | 118 ++++ .../JesusFreke/dexlib/code/Instruction.java | 194 ++++++ .../org/JesusFreke/dexlib/code/Opcode.java | 300 +++++++++ .../JesusFreke/dexlib/code/ReferenceType.java | 56 ++ .../JesusFreke/dexlib/debug/AdvanceLine.java | 53 ++ .../JesusFreke/dexlib/debug/AdvancePC.java | 50 ++ .../dexlib/debug/DebugInstruction.java | 35 ++ .../dexlib/debug/DebugInstructionFactory.java | 72 +++ .../org/JesusFreke/dexlib/debug/EndLocal.java | 50 ++ .../JesusFreke/dexlib/debug/EndSequence.java | 51 ++ .../JesusFreke/dexlib/debug/RestartLocal.java | 50 ++ .../dexlib/debug/SetEpilogueBegin.java | 51 ++ .../org/JesusFreke/dexlib/debug/SetFile.java | 50 ++ .../dexlib/debug/SetPrologueEnd.java | 51 ++ .../dexlib/debug/SpecialOpcode.java | 54 ++ .../JesusFreke/dexlib/debug/StartLocal.java | 52 ++ .../dexlib/debug/StartLocalExtended.java | 53 ++ .../JesusFreke/dexlib/util/AccessFlags.java | 59 ++ .../org/JesusFreke/dexlib/util/ByteArray.java | 379 +++++++++++ .../dexlib/util/ByteArrayInput.java | 312 +++++++++ .../dexlib/util/ByteArrayOutput.java | 582 +++++++++++++++++ .../dexlib/util/EncodedValueUtils.java | 143 +++++ .../dexlib/util/ExceptionWithContext.java | 149 +++++ .../org/JesusFreke/dexlib/util/FileUtils.java | 92 +++ .../java/org/JesusFreke/dexlib/util/Hex.java | 303 +++++++++ .../org/JesusFreke/dexlib/util/Input.java | 149 +++++ .../JesusFreke/dexlib/util/Leb128Utils.java | 78 +++ .../org/JesusFreke/dexlib/util/Output.java | 129 ++++ .../org/JesusFreke/dexlib/util/TypeUtils.java | 63 ++ .../org/JesusFreke/dexlib/util/Utf8Utils.java | 164 +++++ src/main/java/org/JesusFreke/smali/smali.java | 91 +++ src/test/resources/examples/Constants.smali | 97 +++ src/test/resources/examples/HelloWorld.smali | 21 + src/test/resources/examples/HelloWorld2.smali | 54 ++ src/test/resources/examples/Identifiers.smali | 39 ++ src/test/resources/examples/NoFields.smali | 28 + 107 files changed, 12019 insertions(+) create mode 100644 pom.xml create mode 100644 src/main/antlr3/org/JesusFreke/smali/smali.g create mode 100644 src/main/antlr3/org/JesusFreke/smali/smaliTreeWalker.g create mode 100644 src/main/java/org/JesusFreke/dexlib/AnnotationDirectoryItem.java create mode 100644 src/main/java/org/JesusFreke/dexlib/AnnotationItem.java create mode 100644 src/main/java/org/JesusFreke/dexlib/AnnotationSetItem.java create mode 100644 src/main/java/org/JesusFreke/dexlib/AnnotationSetRefList.java create mode 100644 src/main/java/org/JesusFreke/dexlib/ByteField.java create mode 100644 src/main/java/org/JesusFreke/dexlib/CachedIntegerValueField.java create mode 100644 src/main/java/org/JesusFreke/dexlib/ClassDataItem.java create mode 100644 src/main/java/org/JesusFreke/dexlib/ClassDefItem.java create mode 100644 src/main/java/org/JesusFreke/dexlib/CodeItem.java create mode 100644 src/main/java/org/JesusFreke/dexlib/CompositeField.java create mode 100644 src/main/java/org/JesusFreke/dexlib/DebugInfoItem.java create mode 100644 src/main/java/org/JesusFreke/dexlib/DexFile.java create mode 100644 src/main/java/org/JesusFreke/dexlib/EncodedArrayItem.java create mode 100644 src/main/java/org/JesusFreke/dexlib/EncodedValue/AnnotationElement.java create mode 100644 src/main/java/org/JesusFreke/dexlib/EncodedValue/AnnotationEncodedValueSubField.java create mode 100644 src/main/java/org/JesusFreke/dexlib/EncodedValue/ArrayEncodedValueSubField.java create mode 100644 src/main/java/org/JesusFreke/dexlib/EncodedValue/BoolEncodedValueSubField.java create mode 100644 src/main/java/org/JesusFreke/dexlib/EncodedValue/ByteEncodedValueSubField.java create mode 100644 src/main/java/org/JesusFreke/dexlib/EncodedValue/CharEncodedValueSubField.java create mode 100644 src/main/java/org/JesusFreke/dexlib/EncodedValue/DoubleEncodedValueSubField.java create mode 100644 src/main/java/org/JesusFreke/dexlib/EncodedValue/EncodedIndexedItemReference.java create mode 100644 src/main/java/org/JesusFreke/dexlib/EncodedValue/EncodedValue.java create mode 100644 src/main/java/org/JesusFreke/dexlib/EncodedValue/EncodedValueSubField.java create mode 100644 src/main/java/org/JesusFreke/dexlib/EncodedValue/EncodedValueSubFieldFactory.java create mode 100644 src/main/java/org/JesusFreke/dexlib/EncodedValue/FloatEncodedValueSubField.java create mode 100644 src/main/java/org/JesusFreke/dexlib/EncodedValue/IntEncodedValueSubField.java create mode 100644 src/main/java/org/JesusFreke/dexlib/EncodedValue/LongEncodedValueSubField.java create mode 100644 src/main/java/org/JesusFreke/dexlib/EncodedValue/NullEncodedValueSubField.java create mode 100644 src/main/java/org/JesusFreke/dexlib/EncodedValue/ShortEncodedValueSubField.java create mode 100644 src/main/java/org/JesusFreke/dexlib/EncodedValue/SimpleEncodedValueSubField.java create mode 100644 src/main/java/org/JesusFreke/dexlib/EncodedValue/ValueType.java create mode 100644 src/main/java/org/JesusFreke/dexlib/Field.java create mode 100644 src/main/java/org/JesusFreke/dexlib/FieldIdItem.java create mode 100644 src/main/java/org/JesusFreke/dexlib/FieldListField.java create mode 100644 src/main/java/org/JesusFreke/dexlib/FixedByteArrayField.java create mode 100644 src/main/java/org/JesusFreke/dexlib/HeaderItem.java create mode 100644 src/main/java/org/JesusFreke/dexlib/IndexedItem.java create mode 100644 src/main/java/org/JesusFreke/dexlib/IndexedItemReference.java create mode 100644 src/main/java/org/JesusFreke/dexlib/IndexedSection.java create mode 100644 src/main/java/org/JesusFreke/dexlib/IntegerField.java create mode 100644 src/main/java/org/JesusFreke/dexlib/Item.java create mode 100644 src/main/java/org/JesusFreke/dexlib/ItemReference.java create mode 100644 src/main/java/org/JesusFreke/dexlib/ItemType.java create mode 100644 src/main/java/org/JesusFreke/dexlib/Leb128Field.java create mode 100644 src/main/java/org/JesusFreke/dexlib/Leb128p1Field.java create mode 100644 src/main/java/org/JesusFreke/dexlib/ListSizeField.java create mode 100644 src/main/java/org/JesusFreke/dexlib/MapField.java create mode 100644 src/main/java/org/JesusFreke/dexlib/MapItem.java create mode 100644 src/main/java/org/JesusFreke/dexlib/MethodIdItem.java create mode 100644 src/main/java/org/JesusFreke/dexlib/NullTerminatedByteArrayField.java create mode 100644 src/main/java/org/JesusFreke/dexlib/OffsettedItem.java create mode 100644 src/main/java/org/JesusFreke/dexlib/OffsettedItemReference.java create mode 100644 src/main/java/org/JesusFreke/dexlib/OffsettedSection.java create mode 100644 src/main/java/org/JesusFreke/dexlib/ProtoIdItem.java create mode 100644 src/main/java/org/JesusFreke/dexlib/Section.java create mode 100644 src/main/java/org/JesusFreke/dexlib/SectionHeaderInfo.java create mode 100644 src/main/java/org/JesusFreke/dexlib/ShortIntegerField.java create mode 100644 src/main/java/org/JesusFreke/dexlib/SignedLeb128Field.java create mode 100644 src/main/java/org/JesusFreke/dexlib/StringDataItem.java create mode 100644 src/main/java/org/JesusFreke/dexlib/StringIdItem.java create mode 100644 src/main/java/org/JesusFreke/dexlib/TypeIdItem.java create mode 100644 src/main/java/org/JesusFreke/dexlib/TypeListItem.java create mode 100644 src/main/java/org/JesusFreke/dexlib/code/Format/Format.java create mode 100644 src/main/java/org/JesusFreke/dexlib/code/Format/Format10x.java create mode 100644 src/main/java/org/JesusFreke/dexlib/code/Format/Format11x.java create mode 100644 src/main/java/org/JesusFreke/dexlib/code/Format/Format21c.java create mode 100644 src/main/java/org/JesusFreke/dexlib/code/Format/Format22c.java create mode 100644 src/main/java/org/JesusFreke/dexlib/code/Format/Format35c.java create mode 100644 src/main/java/org/JesusFreke/dexlib/code/Format/Format3rc.java create mode 100644 src/main/java/org/JesusFreke/dexlib/code/Instruction.java create mode 100644 src/main/java/org/JesusFreke/dexlib/code/Opcode.java create mode 100644 src/main/java/org/JesusFreke/dexlib/code/ReferenceType.java create mode 100644 src/main/java/org/JesusFreke/dexlib/debug/AdvanceLine.java create mode 100644 src/main/java/org/JesusFreke/dexlib/debug/AdvancePC.java create mode 100644 src/main/java/org/JesusFreke/dexlib/debug/DebugInstruction.java create mode 100644 src/main/java/org/JesusFreke/dexlib/debug/DebugInstructionFactory.java create mode 100644 src/main/java/org/JesusFreke/dexlib/debug/EndLocal.java create mode 100644 src/main/java/org/JesusFreke/dexlib/debug/EndSequence.java create mode 100644 src/main/java/org/JesusFreke/dexlib/debug/RestartLocal.java create mode 100644 src/main/java/org/JesusFreke/dexlib/debug/SetEpilogueBegin.java create mode 100644 src/main/java/org/JesusFreke/dexlib/debug/SetFile.java create mode 100644 src/main/java/org/JesusFreke/dexlib/debug/SetPrologueEnd.java create mode 100644 src/main/java/org/JesusFreke/dexlib/debug/SpecialOpcode.java create mode 100644 src/main/java/org/JesusFreke/dexlib/debug/StartLocal.java create mode 100644 src/main/java/org/JesusFreke/dexlib/debug/StartLocalExtended.java create mode 100644 src/main/java/org/JesusFreke/dexlib/util/AccessFlags.java create mode 100644 src/main/java/org/JesusFreke/dexlib/util/ByteArray.java create mode 100644 src/main/java/org/JesusFreke/dexlib/util/ByteArrayInput.java create mode 100644 src/main/java/org/JesusFreke/dexlib/util/ByteArrayOutput.java create mode 100644 src/main/java/org/JesusFreke/dexlib/util/EncodedValueUtils.java create mode 100644 src/main/java/org/JesusFreke/dexlib/util/ExceptionWithContext.java create mode 100644 src/main/java/org/JesusFreke/dexlib/util/FileUtils.java create mode 100644 src/main/java/org/JesusFreke/dexlib/util/Hex.java create mode 100644 src/main/java/org/JesusFreke/dexlib/util/Input.java create mode 100644 src/main/java/org/JesusFreke/dexlib/util/Leb128Utils.java create mode 100644 src/main/java/org/JesusFreke/dexlib/util/Output.java create mode 100644 src/main/java/org/JesusFreke/dexlib/util/TypeUtils.java create mode 100644 src/main/java/org/JesusFreke/dexlib/util/Utf8Utils.java create mode 100644 src/main/java/org/JesusFreke/smali/smali.java create mode 100644 src/test/resources/examples/Constants.smali create mode 100644 src/test/resources/examples/HelloWorld.smali create mode 100644 src/test/resources/examples/HelloWorld2.smali create mode 100644 src/test/resources/examples/Identifiers.smali create mode 100644 src/test/resources/examples/NoFields.smali diff --git a/pom.xml b/pom.xml new file mode 100644 index 00000000..b125bd7b --- /dev/null +++ b/pom.xml @@ -0,0 +1,56 @@ + + + 4.0.0 + smali + smali + 1.0 + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.5 + 1.5 + + + + + org.antlr + antlr3-maven-plugin + 3.1.3-1 + + + smali + + antlr + + + org/JesusFreke/smali/smaliTreeWalker.g + + + + smaliTreeWalker + + antlr + + + org/JesusFreke/smali/smali.g + + + + + + + + + + + org.antlr + antlr-runtime + 3.1.3 + + + \ No newline at end of file diff --git a/src/main/antlr3/org/JesusFreke/smali/smali.g b/src/main/antlr3/org/JesusFreke/smali/smali.g new file mode 100644 index 00000000..3f3937a2 --- /dev/null +++ b/src/main/antlr3/org/JesusFreke/smali/smali.g @@ -0,0 +1,594 @@ +/* + * The comment lexical rule, and the number, string and character constant + * lexical rules are derived from rules from the Java 1.6 grammar which can be + * found here: http://openjdk.java.net/projects/compiler-grammar/antlrworks/Java.g + * + * Specifically, these rules: + * + * COMMENT, LONG_LITERAL, INT_LITERAL, Integer_number, Hex_prefix, Hex_digit, + * Long_suffix, Non_integer_number_SIMPLE_NAME, Non_integer_number, + * Decimal_exponent, Hex_exponent, Float_suffix, Double_suffix, + * FLOAT_LITERAL_SIMPLE_NAME, FLOAT_LITERAL, DOUBLE_LITERAL_SIMPLE_NAME, + * DOUBLE_LITERAL, CHAR_LITERAL, STRING_LITERAL, EscapeSequence + * + * These rules were originally copyrighted by Terence Parr, and are used here in + * accordance with the following license + * + * [The "BSD licence"] + * Copyright (c) 2007-2008 Terence Parr + * 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. + * + * + * The remainder of this grammar is released by me (Ben Gruver) under the + * following license: + * + * [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. + */ + +grammar smali; + +options { + output=AST; + ASTLabelType=CommonTree; +} + +tokens { + //I_* tokens are imaginary tokens used as parent AST nodes + I_CLASS_DEF; + I_SUPER; + I_ACCESS_LIST; + I_METHODS; + I_FIELDS; + I_FIELD; + I_FIELD_TYPE; + I_FIELD_INITIAL_VALUE; + I_METHOD; + I_METHOD_PROTOTYPE; + I_METHOD_RETURN_TYPE; + I_REGISTERS; + I_STATEMENTS; + I_INVOKE_STATEMENT; + I_INVOKE_RANGE_STATEMENT; + I_BARE_STATEMENT; + I_STATIC_FIELD_STATEMENT; + I_INSTANCE_FIELD_STATEMENT; + I_CONST_STRING_STATEMENT; + I_NEW_INSTANCE_STATEMENT; + I_SINGLE_REGISTER_STATEMENT; + I_REGISTER_RANGE; + I_REGISTER_LIST; +} + +@parser::header { +package org.JesusFreke.smali; +} + +@lexer::header { +package org.JesusFreke.smali; + +import java.util.ArrayDeque; +} + +@lexer::init { + state.token = Token.INVALID_TOKEN; +} + +@lexer::members { + protected ArrayDeque tokens = new ArrayDeque(); + + public void reset() { + super.reset(); + state.token = Token.INVALID_TOKEN; + tokens.clear(); + } + + public Token nextToken() { + while (true) { + if (tokens.size() > 0) { + Token token = tokens.poll(); + if (token == Token.SKIP_TOKEN) { + continue; + } + + return token; + } + + state.channel = Token.DEFAULT_CHANNEL; + state.tokenStartCharIndex = input.index(); + state.tokenStartCharPositionInLine = input.getCharPositionInLine(); + state.tokenStartLine = input.getLine(); + state.text = null; + if ( input.LA(1)==CharStream.EOF ) { + return Token.EOF_TOKEN; + } + try { + mTokens(); + + if (tokens.size() == 0) { + emit(); + } + } + catch (NoViableAltException nva) { + reportError(nva); + recover(nva); // throw out current char and try again + } + catch (RecognitionException re) { + reportError(re); + // match() routine has already called recover() + } + } + } + + public void skip() { + tokens.add(Token.SKIP_TOKEN); + } + + public void emit(Token token) { + tokens.add(token); + } +} + + +smali_file: header methods_and_fields -> ^(I_CLASS_DEF header methods_and_fields); + +header : class_spec super_spec; + +class_spec + : '.class' access_list class_name -> class_name access_list; + +super_spec + : first_token='.super' class_name -> ^(I_SUPER[$first_token, "I_SUPER"] class_name); + +access_list + : first_token=ACCESS_SPEC ACCESS_SPEC* -> ^(I_ACCESS_LIST[$first_token,"I_ACCESS_LIST"] ACCESS_SPEC+); + +methods_and_fields + : (method | field)* -> ^(I_METHODS method*) ^(I_FIELDS field*); + +field : first_token='.field' access_list member_name field_type_descriptor ('=' literal)? + -> ^(I_FIELD[$first_token, "I_FIELD"] member_name access_list ^(I_FIELD_TYPE field_type_descriptor) ^(I_FIELD_INITIAL_VALUE literal)?); + +method : first_token='.method' access_list method_name_and_prototype locals_directive statements '.end method' + -> ^(I_METHOD[$first_token, "I_METHOD"] method_name_and_prototype access_list locals_directive statements); + +method_prototype + : first_token='(' field_type_list ')' type_descriptor + -> ^(I_METHOD_PROTOTYPE[$first_token, "I_METHOD_PROTOTYPE"] ^(I_METHOD_RETURN_TYPE type_descriptor) field_type_list?); + +method_name_and_prototype + : member_name method_prototype; + +field_type_list + : field_type_descriptor*; + +locals_directive + : first_token='.registers' INT_LITERAL + -> ^(I_REGISTERS[$first_token, "I_REGISTERS"] INT_LITERAL); + + +full_method_name_and_prototype + : QUALIFIED_MEMBER__CLASS_NAME QUALIFIED_MEMBER__MEMBER_NAME method_prototype; + +full_field_name_and_type + : QUALIFIED_MEMBER__CLASS_NAME QUALIFIED_MEMBER__MEMBER_NAME field_type_descriptor; + +statements + : statement* -> ^(I_STATEMENTS statement*); + +statement + : instruction; + +instruction + //e.g. return + : BARE_INSTRUCTION_NAME + -> ^(I_BARE_STATEMENT[$start, "I_BARE_STATEMENT"] BARE_INSTRUCTION_NAME) + | //e.g. invoke-virtual {v0,v1} java/io/PrintStream/print(Ljava/lang/Stream;)V + INVOKE_INSTRUCTION_NAME '{' register_list '}' full_method_name_and_prototype + -> ^(I_INVOKE_STATEMENT[$start, "I_INVOKE_STATEMENT"] INVOKE_INSTRUCTION_NAME register_list full_method_name_and_prototype) + | //e.g. invoke-virtual/range {v25..v26} java/lang/StringBuilder/append(Ljava/lang/String;)Ljava/lang/StringBuilder; + INVOKE_RANGE_INSTRUCTION_NAME '{' register_range '}' full_method_name_and_prototype + -> ^(I_INVOKE_RANGE_STATEMENT[$start, "I_INVOKE_RANGE_STATEMENT"] INVOKE_RANGE_INSTRUCTION_NAME register_range full_method_name_and_prototype) + | //e.g. sget_object v0 java/lang/System/out LJava/io/PrintStream; + STATIC_FIELD_INSTRUCTION_NAME REGISTER full_field_name_and_type + -> ^(I_STATIC_FIELD_STATEMENT[$start, "I_STATIC_FIELD_STATEMENT"] STATIC_FIELD_INSTRUCTION_NAME REGISTER full_field_name_and_type) + | //e.g. iput-object v1 v0 org/JesusFreke/HelloWorld2/HelloWorld2.helloWorld Ljava/lang/String; + INSTANCE_FIELD_INSTRUCTION_NAME REGISTER REGISTER full_field_name_and_type + -> ^(I_INSTANCE_FIELD_STATEMENT[$start, "I_INSTANCE_FIELD_STATEMENT"] INSTANCE_FIELD_INSTRUCTION_NAME REGISTER REGISTER full_field_name_and_type) + | //e.g. const-string v1 "Hello World!" + CONST_STRING_INSTRUCTION_NAME REGISTER STRING_LITERAL + -> ^(I_CONST_STRING_STATEMENT[$start, "I_CONST_STRING_STATMENT"] CONST_STRING_INSTRUCTION_NAME REGISTER STRING_LITERAL) + | //e.g. new-instance v1 android/widget/TextView + NEW_INSTANCE_INSTRUCTION_NAME REGISTER class_name + -> ^(I_NEW_INSTANCE_STATEMENT[$start, "I_NEW_INSTANCE_STATEMENT"] NEW_INSTANCE_INSTRUCTION_NAME REGISTER class_name) + | //e.g. move-result-object v1 + SINGLE_REGISTER_INSTRUCTION_NAME REGISTER + -> ^(I_SINGLE_REGISTER_STATEMENT[$start, "I_SINGLE_REGISTER_STATEMENT"] SINGLE_REGISTER_INSTRUCTION_NAME REGISTER) + ; + + +register_list + : first_token=REGISTER? (',' REGISTER)* -> ^(I_REGISTER_LIST[$first_token, "I_REGISTER_LIST"] REGISTER*); + +register_range + : first_token=REGISTER ('..' REGISTER)? -> ^(I_REGISTER_RANGE[$first_token, "I_REGISTER_RANGE"] REGISTER REGISTER?); + +/*since there are no reserved words in the dex specification, there are a +number of tokens that can be a valid simple_name, in addition to just +SIMPLE_NAME. We need to match any token that could also be considered a valid +SIMPLE_NAME. In the case of floating point literals, some could be considered +a valid SIMPLE_NAME while others couldn't. The lexer will generate a separate +FLOAT_LITERAL_SIMPLE_NAME OR DOUBLE_LITERAL_SIMPLE_NAME token for literals +that can be considered a valid SIMPLE_NAME*/ +simple_name + : SIMPLE_NAME + | ACCESS_SPEC + | instruction_name + | INT_LITERAL + | LONG_LITERAL + | FLOAT_LITERAL_SIMPLE_NAME + | DOUBLE_LITERAL_SIMPLE_NAME + | BOOL_LITERAL + | PRIMITIVE_TYPE + ; + +instruction_name + : INVOKE_INSTRUCTION_NAME + | INVOKE_RANGE_INSTRUCTION_NAME + | STATIC_FIELD_INSTRUCTION_NAME + | INSTANCE_FIELD_INSTRUCTION_NAME + | BARE_INSTRUCTION_NAME + | CONST_STRING_INSTRUCTION_NAME + | NEW_INSTANCE_INSTRUCTION_NAME + | SINGLE_REGISTER_INSTRUCTION_NAME + ; + +member_name + : simple_name + | MEMBER_NAME + ; + +class_name + : SIMPLE_NAME | CLASS_WITH_PACKAGE_NAME; + +field_type_descriptor + : PRIMITIVE_TYPE + | CLASS_DESCRIPTOR + | ARRAY_TYPE + ; + +type_descriptor + : VOID_TYPE + | field_type_descriptor + ; + +literal : INT_LITERAL + | LONG_LITERAL + | float_literal + | double_literal + | CHAR_LITERAL + | STRING_LITERAL + | BOOL_LITERAL; + +float_literal + : FLOAT_LITERAL -> FLOAT_LITERAL + | FLOAT_LITERAL_SIMPLE_NAME -> FLOAT_LITERAL[$FLOAT_LITERAL_SIMPLE_NAME, $FLOAT_LITERAL_SIMPLE_NAME.text]; + +double_literal + : DOUBLE_LITERAL -> DOUBLE_LITERAL + | DOUBLE_LITERAL_SIMPLE_NAME -> DOUBLE_LITERAL[$DOUBLE_LITERAL_SIMPLE_NAME, $DOUBLE_LITERAL_SIMPLE_NAME.text]; + +ACCESS_SPEC + : 'public' | 'private' | 'static' | 'constructor' | 'final'; + +INVOKE_INSTRUCTION_NAME + : 'invoke-virtual' + | 'invoke-super' + | 'invoke-direct' + | 'invoke-static' + | 'invoke-interface' + ; + +INVOKE_RANGE_INSTRUCTION_NAME + : 'invoke-virtual/range' + | 'invoke-super/range' + | 'invoke-direct/range' + | 'invoke-static/range' + | 'invoke-interface/range' + ; + +STATIC_FIELD_INSTRUCTION_NAME + : 'sget' + | 'sget-wide' + | 'sget-object' + | 'sget-boolean' + | 'sget-byte' + | 'sget-char' + | 'sget-short' + | 'sput' + | 'sput-wide' + | 'sput-object' + | 'sput-boolean' + | 'sput-byte' + | 'sput-char' + | 'sput-short' + ; + +INSTANCE_FIELD_INSTRUCTION_NAME + : 'iget' + | 'iget-wide' + | 'iget-object' + | 'iget-boolean' + | 'iget-byte' + | 'iget-char' + | 'iget-short' + | 'iput' + | 'iput-wide' + | 'iput-object' + | 'iput-boolean' + | 'iput-byte' + | 'iput-char' + | 'iput-short' + ; + +BARE_INSTRUCTION_NAME + : 'return-void' + | 'nop'; + + +CONST_STRING_INSTRUCTION_NAME + : 'const-string'; + +NEW_INSTANCE_INSTRUCTION_NAME + : 'new-instance'; + +SINGLE_REGISTER_INSTRUCTION_NAME + : 'move-result' + | 'move-result-wide' + | 'move-result-object' + | 'move-exception' + | 'return' + | 'return-wide' + | 'return-object' + | 'monitor-enter' + | 'monitor-exit' + | 'throw'; + + +/*since SIMPLE_NAME is so all-encompassing, it includes all integer literals +and a subset of the possible floating point literals. For floating point +literals, we need to generate a separate token depending on whether the token +could also be considered a SIMPLE_NAME or not. + +The floating point related tokens with a _SIMPLE_NAME suffix could also be +considered valid SIMPLE_NAME tokens, while the plain version of the token +(without the suffix) could not be considered a valid SIMPLE_NAME token*/ + +LONG_LITERAL + : Integer_number Long_suffix; + +INT_LITERAL + : Integer_number; + +fragment Integer_number + : '-'? '0' + | '-'? ('1'..'9') ('0'..'9')* + | '0' ('0'..'7')+ + | Hex_prefix Hex_digit+ + ; + +fragment Hex_prefix + : '0x'|'0X'; + +fragment Hex_digit + : ('0'..'9'|'a'..'f'|'A'..'F'); + +fragment Long_suffix + : 'l'|'L'; + +fragment Non_integer_number_SIMPLE_NAME + : ('0'..'9')+ Decimal_exponent + | ('0'..'9')+ + | Hex_prefix (Hex_digit)* Hex_exponent + ; + + +fragment Non_integer_number + : ('0'..'9')+ '.' ('0'..'9')* Decimal_exponent? + | '.' ('0'..'9')+ Decimal_exponent? + | Hex_prefix (Hex_digit)* '.' (Hex_digit)* Hex_exponent + ; + +fragment Decimal_exponent + : ('e'|'E') '-'? ('0'..'9')+; + +fragment Hex_exponent + : ('p'|'P') '-'? ('0'..'9')+; + +fragment Float_suffix + : 'f'|'F'; + +fragment Double_suffix + : 'd'|'D'; + +FLOAT_LITERAL_SIMPLE_NAME + : Non_integer_number_SIMPLE_NAME Float_suffix; + +FLOAT_LITERAL + : Non_integer_number Float_suffix; + +DOUBLE_LITERAL_SIMPLE_NAME + : Non_integer_number_SIMPLE_NAME Double_suffix?; + +DOUBLE_LITERAL + : Non_integer_number Double_suffix?; + +CHAR_LITERAL + + : '\'' {StringBuilder sb = new StringBuilder();} + ( Escape_sequence[sb] {setText(sb.toString());} + | ~( '\'' | '\\' | '\r' | '\n' ) + ) + '\'' + ; + +STRING_LITERAL + : '"' {StringBuilder sb = new StringBuilder();} + ( Escape_sequence[sb] + | ~( '\\' | '"' | '\r' | '\n' ) {sb.append((char)input.LA(-1));} + )* + '"' {setText(sb.toString());} + ; + + +Hex_digits + : Hex_digit Hex_digit Hex_digit Hex_digit; + +fragment +Escape_sequence[StringBuilder sb] + : '\\' + ( + 'b' {sb.append("\b");} + | 't' {sb.append("\t");} + | 'n' {sb.append("\n");} + | 'f' {sb.append("\f");} + | 'r' {sb.append("\r");} + | '\"' {sb.append("\"");} + | '\'' {sb.append("'");} + | '\\' {sb.append("\\");} + | 'u' Hex_digits {sb.append((char)Integer.parseInt($Hex_digits.text, 16));} +/* | octdigits=(('0'..'3') ('0'..'7') ('0'..'7')) {$value = (char)Integer.parseInt("0" + $octdigits.text);} + | octdigits=(('0'..'7') ('0'..'7')) {$value = (char)Integer.parseInt("0" + $octdigits.text);} + | octdigits=(('0'..'7')) {$value = (char)Integer.parseInt("0" + $octdigits.text);}*/ + ); + +BOOL_LITERAL + : 'true'|'false'; + + + +WHITESPACE + : (' '|'\t'|'\n'|'\r')+ {$channel = HIDDEN;}; + +REGISTER: 'v' ('0'..'9')+; + + +/*a token of type QUALIFIED_MEMBER is never generated. This rule emits 2 sub-tokens +that represent the class name and the member name, so that they don't have to be +parsed out later*/ +QUALIFIED_MEMBER + : class_name=QUALIFIED_MEMBER__CLASS_NAME '.' member_name=QUALIFIED_MEMBER__MEMBER_NAME + { + $class_name.setType(QUALIFIED_MEMBER__CLASS_NAME); + $member_name.setType(QUALIFIED_MEMBER__MEMBER_NAME); + emit($class_name); + emit($member_name); + }; + +fragment QUALIFIED_MEMBER__CLASS_NAME + : (SIMPLE_NAME '/')* SIMPLE_NAME; + +fragment QUALIFIED_MEMBER__MEMBER_NAME + : MEMBER_NAME | SIMPLE_NAME; + + +ARRAY_TYPE + : + ARRAY_CHAR_LIST[255] (PRIMITIVE_TYPE | CLASS_DESCRIPTOR); + + +//match from 1 to maxCount '[' characters +fragment +ARRAY_CHAR_LIST[int maxCount] + : {$maxCount > 1}?=> '[' ARRAY_CHAR_LIST[$maxCount - 1] + | '[' + ; + +MEMBER_NAME + : '<' SIMPLE_NAME '>'; + +VOID_TYPE + : 'V'; + +PRIMITIVE_TYPE + : 'Z' + | 'B' + | 'S' + | 'C' + | 'I' + | 'J' + | 'F' + | 'D' + ; + +CLASS_WITH_PACKAGE_NAME + : (SIMPLE_NAME '/')+ SIMPLE_NAME; + +CLASS_DESCRIPTOR + : 'L' (SIMPLE_NAME | CLASS_WITH_PACKAGE_NAME) ';'; + +SIMPLE_NAME: + ( 'A'..'Z' + | 'a'..'z' + | '0'..'9' + | '$' + | '-' + | '_' + | '\u00a1'..'\u1fff' + | '\u2010'..'\u2027' + | '\u2030'..'\ud7ff' + | '\ue000'..'\uffef' + )+; + +COMMENT + : (';' ~('\n'|'\r')* ('\r\n' | '\r' | '\n') + | ';' ~('\n'|'\r')*) + { + $channel = HIDDEN; + } + ; diff --git a/src/main/antlr3/org/JesusFreke/smali/smaliTreeWalker.g b/src/main/antlr3/org/JesusFreke/smali/smaliTreeWalker.g new file mode 100644 index 00000000..c4806298 --- /dev/null +++ b/src/main/antlr3/org/JesusFreke/smali/smaliTreeWalker.g @@ -0,0 +1,437 @@ +/* + * [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. + */ + +tree grammar smaliTreeWalker; + +options { + tokenVocab=smali; + ASTLabelType=CommonTree; +} + +@header { +package org.JesusFreke.smali; + +import org.JesusFreke.dexlib.*; +import org.JesusFreke.dexlib.EncodedValue.*; +import org.JesusFreke.dexlib.util.*; +import org.JesusFreke.dexlib.code.*; +import org.JesusFreke.dexlib.code.Format.*; +} + +@members { + public DexFile dexFile; + public ClassDefItem classDefItem; + public ClassDataItem classDataItem; + + + private static byte parseRegister_nibble(String register) { + //register should be in the format "v12" + byte val = Byte.parseByte(register.substring(1)); + if (val >= 2<<4) { + //TODO: throw correct exception type + throw new RuntimeException("The maximum allowed register in this context is list of registers is v15"); + } + //the parser wouldn't accept a negative register, i.e. v-1, so we don't have to check for val<0; + return val; + } + + //return a short, because java's byte is signed + private static short parseRegister_byte(String register) { + //register should be in the format "v123" + short val = Short.parseShort(register.substring(1)); + if (val >= 2<<8) { + //TODO: throw correct exception type + throw new RuntimeException("The maximum allowed register in this context is v255"); + } + return val; + } + + //return an int because java's short is signed + private static int parseRegister_short(String register) { + //register should be in the format "v12345" + int val = Integer.parseInt(register.substring(1)); + if (val >= 2<<16) { + //TODO: throw correct exception type + throw new RuntimeException("The maximum allowed register in this context is v65535"); + } + //the parser wouldn't accept a negative register, i.e. v-1, so we don't have to check for val<0; + return val; + } +} + + + +smali_file returns[ClassDefItem classDefItem] + : ^(I_CLASS_DEF header methods fields); + +header : class_spec super_spec + { + classDataItem = new ClassDataItem(dexFile, 0); + classDefItem = new ClassDefItem(dexFile, $class_spec.type, $class_spec.accessFlags, $super_spec.type, classDataItem); + }; + +class_spec returns[TypeIdItem type, int accessFlags] + : class_name access_list + { + $type = $class_name.type; + $accessFlags = $access_list.value; + }; + +super_spec returns[TypeIdItem type] + : ^(I_SUPER class_name) + { + $type = $class_name.type; + }; + +access_list returns [int value] + @init + { + $value = 0; + } + : ^(I_ACCESS_LIST + ( + ACCESS_SPEC + { + $value |= AccessFlags.getValueForAccessFlag($ACCESS_SPEC.getText()); + } + )+); + +fields : ^(I_FIELDS + (field + { + classDefItem.addField($field.encodedField, $field.encodedValue); + })*); + +methods : ^(I_METHODS + (method + { + classDataItem.addMethod($method.encodedMethod); + })*); + +field returns[ClassDataItem.EncodedField encodedField, EncodedValue encodedValue] + :^(I_FIELD member_name access_list ^(I_FIELD_TYPE field_type_descriptor) field_initial_value) + { + TypeIdItem classType = classDefItem.getClassType(); + StringIdItem memberName = new StringIdItem(dexFile, $member_name.memberName); + TypeIdItem fieldType = $field_type_descriptor.type; + + FieldIdItem fieldIdItem = new FieldIdItem(dexFile, classType, memberName, fieldType); + $encodedField = new ClassDataItem.EncodedField(dexFile, fieldIdItem, $access_list.value); + + if ($field_initial_value.encodedValue != null) { + if (($access_list.value & AccessFlags.STATIC) == 0) { + //TODO: change to an appropriate exception type? + throw new RuntimeException("Initial field values can only be specified for static fields."); + } + + $encodedValue = $field_initial_value.encodedValue; + } else { + $encodedValue = null; + } + }; + +field_initial_value returns[EncodedValue encodedValue] + : ^(I_FIELD_INITIAL_VALUE + ( int_literal { $encodedValue = new EncodedValue(dexFile, new IntEncodedValueSubField($int_literal.value)); } + | long_literal { $encodedValue = new EncodedValue(dexFile, new LongEncodedValueSubField($long_literal.value)); } + | float_literal { $encodedValue = new EncodedValue(dexFile, new FloatEncodedValueSubField($float_literal.value)); } + | double_literal { $encodedValue = new EncodedValue(dexFile, new DoubleEncodedValueSubField($double_literal.value)); } + | char_literal { $encodedValue = new EncodedValue(dexFile, new CharEncodedValueSubField($char_literal.value)); } + | string_literal { $encodedValue = new EncodedValue(dexFile, new EncodedIndexedItemReference(dexFile, new StringIdItem(dexFile, $string_literal.value))); } + | bool_literal { $encodedValue = new EncodedValue(dexFile, new BoolEncodedValueSubField($bool_literal.value)); } + )) + | ; + + +method returns[ClassDataItem.EncodedMethod encodedMethod] + : ^(I_METHOD method_name_and_prototype access_list locals_directive statements) + { + MethodIdItem methodIdItem = $method_name_and_prototype.methodIdItem; + int registers = $locals_directive.registers; + int access = $access_list.value; + boolean isStatic = (access & AccessFlags.STATIC) != 0; + ArrayList instructions = $statements.instructions; + + CodeItem codeItem = new CodeItem(dexFile, registers, methodIdItem.getParameterWordCount(isStatic), instructions); + + $encodedMethod = new ClassDataItem.EncodedMethod(dexFile, methodIdItem, access, codeItem); + }; + +method_prototype returns[ProtoIdItem protoIdItem] + : ^(I_METHOD_PROTOTYPE ^(I_METHOD_RETURN_TYPE type_descriptor) field_type_list) + { + TypeIdItem returnType = $type_descriptor.type; + ArrayList parameterTypes = $field_type_list.types; + + $protoIdItem = new ProtoIdItem(dexFile, returnType, parameterTypes); + }; + +method_name_and_prototype returns[MethodIdItem methodIdItem] + : member_name method_prototype + { + TypeIdItem classType = classDefItem.getClassType(); + String methodNameString = $member_name.memberName; + StringIdItem methodName = new StringIdItem(dexFile, methodNameString); + ProtoIdItem protoIdItem = $method_prototype.protoIdItem; + + $methodIdItem = new MethodIdItem(dexFile, classType, methodName, protoIdItem); + }; + +field_type_list returns[ArrayList types] + @init + { + $types = new ArrayList(); + } + : ( + field_type_descriptor + { + $types.add($field_type_descriptor.type); + } + )*; + +locals_directive returns[int registers] + : ^(I_REGISTERS INT_LITERAL) {$registers = Integer.parseInt($INT_LITERAL.text);}; + +full_method_name_and_prototype returns[MethodIdItem methodIdItem] + : QUALIFIED_MEMBER__CLASS_NAME QUALIFIED_MEMBER__MEMBER_NAME method_prototype + { + TypeIdItem classType = new TypeIdItem(dexFile, "L" + $QUALIFIED_MEMBER__CLASS_NAME.text + ";"); + StringIdItem methodName = new StringIdItem(dexFile, $QUALIFIED_MEMBER__MEMBER_NAME.text); + ProtoIdItem prototype = $method_prototype.protoIdItem; + $methodIdItem = new MethodIdItem(dexFile, classType, methodName, prototype); + }; + +full_field_name_and_type returns[FieldIdItem fieldIdItem] + : QUALIFIED_MEMBER__CLASS_NAME QUALIFIED_MEMBER__MEMBER_NAME field_type_descriptor + { + TypeIdItem classType = new TypeIdItem(dexFile, "L" + $QUALIFIED_MEMBER__CLASS_NAME.text + ";"); + StringIdItem fieldName = new StringIdItem(dexFile, $QUALIFIED_MEMBER__MEMBER_NAME.text); + TypeIdItem fieldType = $field_type_descriptor.type; + $fieldIdItem = new FieldIdItem(dexFile, classType, fieldName, fieldType); + }; + +statements returns[ArrayList instructions] + @init + { + $instructions = new ArrayList(); + } + : ^(I_STATEMENTS + (instruction + { + $instructions.add($instruction.instruction); + })*); + + +instruction returns[Instruction instruction] + //e.g. return + : ^(I_BARE_STATEMENT BARE_INSTRUCTION_NAME) + { + Opcode opcode = Opcode.getOpcodeByName($BARE_INSTRUCTION_NAME.text); + $instruction = Format10x.Format.make(dexFile, opcode.value); + } + | //e.g. invoke-virtual {v0,v1} java/io/PrintStream/print(Ljava/lang/Stream;)V + ^(I_INVOKE_STATEMENT INVOKE_INSTRUCTION_NAME register_list full_method_name_and_prototype) + { + Opcode opcode = Opcode.getOpcodeByName($INVOKE_INSTRUCTION_NAME.text); + + //this depends on the fact that register_list returns a byte[5] + byte[] registers = $register_list.registers; + byte registerCount = $register_list.registerCount; + + MethodIdItem methodIdItem = $full_method_name_and_prototype.methodIdItem; + + $instruction = Format35c.Format.make(dexFile, opcode.value, registerCount, registers[0], registers[1], registers[2], registers[3], registers[4], methodIdItem); + } + | //e.g. invoke-virtual/range {v25..v26} java/lang/StringBuilder/append(Ljava/lang/String;)Ljava/lang/StringBuilder; + ^(I_INVOKE_RANGE_STATEMENT INVOKE_RANGE_INSTRUCTION_NAME register_range full_method_name_and_prototype) + { + Opcode opcode = Opcode.getOpcodeByName($INVOKE_RANGE_INSTRUCTION_NAME.text); + int startRegister = $register_range.startRegister; + int endRegister = $register_range.endRegister; + + int registerCount = endRegister-startRegister+1; + if (registerCount > 256) { + //TODO: throw appropriate exception type + throw new RuntimeException("A register range can span a maximum of 256 registers"); + } + if (registerCount < 1) { + //TODO: throw appropriate exception type + throw new RuntimeException("A register range must have the lower register listed first"); + } + + MethodIdItem methodIdItem = $full_method_name_and_prototype.methodIdItem; + + //not supported yet + $instruction = Format3rc.Format.make(dexFile, opcode.value, (short)registerCount, startRegister, methodIdItem); + } + | //e.g. sget_object v0 java/lang/System/out LJava/io/PrintStream; + ^(I_STATIC_FIELD_STATEMENT STATIC_FIELD_INSTRUCTION_NAME REGISTER full_field_name_and_type) + { + Opcode opcode = Opcode.getOpcodeByName($STATIC_FIELD_INSTRUCTION_NAME.text); + short regA = parseRegister_byte($REGISTER.text); + + FieldIdItem fieldIdItem = $full_field_name_and_type.fieldIdItem; + + $instruction = Format21c.Format.make(dexFile, opcode.value, regA, fieldIdItem); + } + | //e.g. iput-object v1 v0 org/JesusFreke/HelloWorld2/HelloWorld2.helloWorld Ljava/lang/String; + ^(I_INSTANCE_FIELD_STATEMENT INSTANCE_FIELD_INSTRUCTION_NAME registerA=REGISTER registerB=REGISTER full_field_name_and_type) + { + Opcode opcode = Opcode.getOpcodeByName($INSTANCE_FIELD_INSTRUCTION_NAME.text); + byte regA = parseRegister_nibble($registerA.text); + byte regB = parseRegister_nibble($registerB.text); + + FieldIdItem fieldIdItem = $full_field_name_and_type.fieldIdItem; + + $instruction = Format22c.Format.make(dexFile, opcode.value, regA, regB, fieldIdItem); + } + | //e.g. const-string v1 "Hello World!" + ^(I_CONST_STRING_STATEMENT CONST_STRING_INSTRUCTION_NAME REGISTER string_literal) + { + Opcode opcode = Opcode.getOpcodeByName($CONST_STRING_INSTRUCTION_NAME.text); + short regA = parseRegister_byte($REGISTER.text); + + StringIdItem stringIdItem = new StringIdItem(dexFile, $string_literal.value); + + $instruction = Format21c.Format.make(dexFile, opcode.value, regA, stringIdItem); + } + | //e.g. new-instance v1 android/widget/TextView + ^(I_NEW_INSTANCE_STATEMENT NEW_INSTANCE_INSTRUCTION_NAME REGISTER class_name) + { + Opcode opcode = Opcode.getOpcodeByName($NEW_INSTANCE_INSTRUCTION_NAME.text); + short regA = parseRegister_byte($REGISTER.text); + + TypeIdItem typeIdItem = $class_name.type; + + $instruction = Format21c.Format.make(dexFile, opcode.value, regA, typeIdItem); + } + | //e.g. move-result-object v1 + ^(I_SINGLE_REGISTER_STATEMENT SINGLE_REGISTER_INSTRUCTION_NAME REGISTER) + { + Opcode opcode = Opcode.getOpcodeByName($SINGLE_REGISTER_INSTRUCTION_NAME.text); + short regA = parseRegister_byte($REGISTER.text); + + $instruction = Format11x.Format.make(dexFile, opcode.value, regA); + } + ; + + +register_list returns[byte[\] registers, byte registerCount] + @init + { + $registers = new byte[5]; + $registerCount = 0; + } + : ^(I_REGISTER_LIST + (REGISTER + { + if ($registerCount == 5) { + //TODO: throw the correct type of exception + throw new RuntimeException("A list of registers can only have a maximum of 5 registers. Use the /range alternate opcode instead."); + } + $registers[$registerCount++] = parseRegister_nibble($REGISTER.text); + })*); + +register_range returns[int startRegister, int endRegister] + : ^(I_REGISTER_RANGE startReg=REGISTER endReg=REGISTER?) + { + $startRegister = parseRegister_short($startReg.text); + if ($endReg == null) { + $endRegister = $startRegister; + } else { + $endRegister = parseRegister_short($endReg.text); + } + } + ; + +simple_name + : SIMPLE_NAME + | ACCESS_SPEC + | INT_LITERAL + | LONG_LITERAL + | FLOAT_LITERAL_SIMPLE_NAME + | DOUBLE_LITERAL_SIMPLE_NAME + | BOOL_LITERAL + | PRIMITIVE_TYPE + | instruction_name + ; + +instruction_name returns[String value] + : INVOKE_INSTRUCTION_NAME + | INVOKE_RANGE_INSTRUCTION_NAME + | STATIC_FIELD_INSTRUCTION_NAME + | INSTANCE_FIELD_INSTRUCTION_NAME + | BARE_INSTRUCTION_NAME + | CONST_STRING_INSTRUCTION_NAME + | NEW_INSTANCE_INSTRUCTION_NAME + ; + +member_name returns[String memberName] + : (simple_name + | MEMBER_NAME) {$memberName = $start.getText();} + ; + +class_name returns [TypeIdItem type] + : token=(SIMPLE_NAME | CLASS_WITH_PACKAGE_NAME) + { + $type = new TypeIdItem(dexFile, 'L'+$token.text+';'); + }; + +field_type_descriptor returns [TypeIdItem type] + : token=(PRIMITIVE_TYPE + | CLASS_DESCRIPTOR + | ARRAY_TYPE) + { + $type = new TypeIdItem(dexFile, $token.text); + }; + +type_descriptor returns [TypeIdItem type] + : VOID_TYPE {$type = new TypeIdItem(dexFile, "V");} + | field_type_descriptor {$type = $field_type_descriptor.type;} + ; + +int_literal returns[int value] + : INT_LITERAL { $value = Integer.parseInt($INT_LITERAL.text); }; + +long_literal returns[long value] + : LONG_LITERAL { $value = Long.parseLong($LONG_LITERAL.text); }; + +float_literal returns[float value] + : FLOAT_LITERAL { $value = Float.parseFloat($FLOAT_LITERAL.text); }; + +double_literal returns[double value] + : DOUBLE_LITERAL { $value = Double.parseDouble($DOUBLE_LITERAL.text); }; + +char_literal returns[char value] + : CHAR_LITERAL { $value = $CHAR_LITERAL.text.charAt(0); }; + +string_literal returns[String value] + : STRING_LITERAL { $value = $STRING_LITERAL.text; }; + +bool_literal returns[boolean value] + : BOOL_LITERAL { $value = Boolean.parseBoolean($BOOL_LITERAL.text); }; diff --git a/src/main/java/org/JesusFreke/dexlib/AnnotationDirectoryItem.java b/src/main/java/org/JesusFreke/dexlib/AnnotationDirectoryItem.java new file mode 100644 index 00000000..02145036 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/AnnotationDirectoryItem.java @@ -0,0 +1,133 @@ +/* + * [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.JesusFreke.dexlib; + +import org.JesusFreke.dexlib.ItemType; + +import java.util.ArrayList; + +//TODO: fix field names in dex-format.html and submit +public class AnnotationDirectoryItem extends OffsettedItem { + private final Field[] fields; + + private final ArrayList fieldAnnotationList = new ArrayList(); + private final ArrayList methodAnnotationList = new ArrayList(); + private final ArrayList parameterAnnotationList = new ArrayList(); + + private final OffsettedItemReference classAnnotations; + private final ListSizeField annotatedFieldsCount; + private final ListSizeField annotatedMethodsCount; + private final ListSizeField annotatedParametersCount; + private final FieldListField fieldAnnotations; + private final FieldListField methodAnnotations; + private final FieldListField parameterAnnotations; + + public AnnotationDirectoryItem(final DexFile dexFile, int offset) { + super(offset); + + fields = new Field[] { + classAnnotations = new OffsettedItemReference(dexFile.AnnotationSetsSection, new IntegerField()), + annotatedFieldsCount = new ListSizeField(fieldAnnotationList, new IntegerField()), + annotatedMethodsCount = new ListSizeField(methodAnnotationList, new IntegerField()), + annotatedParametersCount = new ListSizeField(parameterAnnotationList, new IntegerField()), + fieldAnnotations = new FieldListField(fieldAnnotationList) { + protected FieldAnnotation make() { + return new FieldAnnotation(dexFile); + } + }, + methodAnnotations = new FieldListField(methodAnnotationList) { + protected MethodAnnotation make() { + return new MethodAnnotation(dexFile); + } + }, + parameterAnnotations = new FieldListField(parameterAnnotationList) { + protected ParameterAnnotation make() { + return new ParameterAnnotation(dexFile); + } + } + }; + } + + protected int getAlignment() { + return 4; + } + + protected Field[] getFields() { + return fields; + } + + public ItemType getItemType() { + return ItemType.TYPE_ANNOTATIONS_DIRECTORY_ITEM; + } + + public class FieldAnnotation extends CompositeField { + private final Field[] fields; + + public FieldAnnotation(DexFile dexFile) { + fields = new Field[] { + new IndexedItemReference(dexFile.FieldIdsSection, new IntegerField()), + new OffsettedItemReference(dexFile.AnnotationSetsSection, new IntegerField()) + }; + } + + protected Field[] getFields() { + return fields; + } + } + + public class MethodAnnotation extends CompositeField { + private final Field[] fields; + + public MethodAnnotation(DexFile dexFile) { + fields = new Field[] { + new IndexedItemReference(dexFile.MethodIdsSection, new IntegerField()), + new OffsettedItemReference(dexFile.AnnotationSetsSection, new IntegerField()) + }; + } + + protected Field[] getFields() { + return fields; + } + } + + public class ParameterAnnotation extends CompositeField { + private final Field[] fields; + + public ParameterAnnotation(DexFile dexFile) { + fields = new Field[] { + new IndexedItemReference(dexFile.MethodIdsSection, new IntegerField()), + new OffsettedItemReference(dexFile.AnnotationSetsSection, new IntegerField()) + }; + } + + protected Field[] getFields() { + return fields; + } + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/AnnotationItem.java b/src/main/java/org/JesusFreke/dexlib/AnnotationItem.java new file mode 100644 index 00000000..dc1a077d --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/AnnotationItem.java @@ -0,0 +1,81 @@ +/* + * [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.JesusFreke.dexlib; + +import org.JesusFreke.dexlib.EncodedValue.AnnotationEncodedValueSubField; +import org.JesusFreke.dexlib.ItemType; + +public class AnnotationItem extends OffsettedItem { + private final Field[] fields; + + private final ByteField visibility; + private final AnnotationEncodedValueSubField annotation; + + public AnnotationItem(DexFile dexFile, int offset) { + super(offset); + + fields = new Field[] { + visibility = new ByteField(), + annotation = new AnnotationEncodedValueSubField(dexFile) + }; + } + + protected int getAlignment() { + return 1; + } + + protected Field[] getFields() { + return fields; + } + + public ItemType getItemType() { + return ItemType.TYPE_ANNOTATION_ITEM; + } + + public void copyTo(DexFile dexFile, AnnotationItem copy) { + visibility.copyTo(dexFile, copy.visibility); + annotation.copyTo(dexFile, copy.annotation); + } + + public int hashCode() { + return visibility.hashCode() * 31 + annotation.hashCode(); + } + + public boolean equals(Object o) { + if (!(o instanceof AnnotationItem)) { + return false; + } + + AnnotationItem other = (AnnotationItem)o; + + if (!visibility.equals(other.visibility)) + return false; + return annotation.equals(other.annotation); + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/AnnotationSetItem.java b/src/main/java/org/JesusFreke/dexlib/AnnotationSetItem.java new file mode 100644 index 00000000..5e528dbb --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/AnnotationSetItem.java @@ -0,0 +1,68 @@ +/* + * [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.JesusFreke.dexlib; + +import org.JesusFreke.dexlib.ItemType; + +import java.util.ArrayList; + +public class AnnotationSetItem extends OffsettedItem { + private final Field[] fields; + + private final ArrayList> annotationReferences = + new ArrayList>(); + + private final ListSizeField annotationCount; + private final FieldListField> annotations; + + public AnnotationSetItem(final DexFile dexFile, int offset) { + super(offset); + + fields = new Field[] { + annotationCount = new ListSizeField(annotationReferences, new IntegerField()), + annotations = new FieldListField>(annotationReferences) { + protected OffsettedItemReference make() { + return new OffsettedItemReference(dexFile.AnnotationsSection, new IntegerField()); + } + } + }; + } + + protected int getAlignment() { + return 4; + } + + protected Field[] getFields() { + return fields; + } + + public ItemType getItemType() { + return ItemType.TYPE_ANNOTATION_SET_ITEM; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/AnnotationSetRefList.java b/src/main/java/org/JesusFreke/dexlib/AnnotationSetRefList.java new file mode 100644 index 00000000..0bf905e6 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/AnnotationSetRefList.java @@ -0,0 +1,68 @@ +/* + * [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.JesusFreke.dexlib; + +import org.JesusFreke.dexlib.ItemType; + +import java.util.ArrayList; + +public class AnnotationSetRefList extends OffsettedItem { + private final Field[] fields; + + private final ArrayList> annotationSetReferences = + new ArrayList>(); + + private final ListSizeField annotationSetCount; + private final FieldListField> annotationSets; + + public AnnotationSetRefList(final DexFile dexFile, int offset) { + super(offset); + + fields = new Field[] { + annotationSetCount = new ListSizeField(annotationSetReferences, new IntegerField()), + annotationSets = new FieldListField>(annotationSetReferences) { + protected OffsettedItemReference make() { + return new OffsettedItemReference(dexFile.AnnotationSetsSection, new IntegerField()); + } + } + }; + } + + protected int getAlignment() { + return 4; + } + + protected Field[] getFields() { + return fields; + } + + public ItemType getItemType() { + return ItemType.TYPE_ANNOTATION_SET_REF_LIST; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/ByteField.java b/src/main/java/org/JesusFreke/dexlib/ByteField.java new file mode 100644 index 00000000..12e06874 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/ByteField.java @@ -0,0 +1,63 @@ +/* + * [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.JesusFreke.dexlib; + +import org.JesusFreke.dexlib.util.Output; +import org.JesusFreke.dexlib.util.Input; + +public class ByteField extends CachedIntegerValueField { + protected byte value; + + public ByteField() { + } + + public ByteField(byte value) { + this.value = value; + } + + public void writeTo(Output out) { + out.writeByte(value); + } + + public void readFrom(Input in) { + value = in.readByte(); + } + + public int place(int offset) { + return offset + 1; + } + + public int getCachedValue() { + return value; + } + + public void cacheValue(int value) { + this.value = (byte)value; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/CachedIntegerValueField.java b/src/main/java/org/JesusFreke/dexlib/CachedIntegerValueField.java new file mode 100644 index 00000000..bcb75acb --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/CachedIntegerValueField.java @@ -0,0 +1,52 @@ +/* + * [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.JesusFreke.dexlib; + +public abstract class CachedIntegerValueField implements Field { + public abstract int getCachedValue(); + public abstract void cacheValue(int value); + + public void copyTo(DexFile dexFile, CachedIntegerValueField copy) { + copy.cacheValue(getCachedValue()); + } + + public int hashCode() { + return ((Integer)getCachedValue()).hashCode(); + } + + public boolean equals(Object o) { + if (getClass() != o.getClass()) { + return false; + } + + CachedIntegerValueField other = (CachedIntegerValueField)o; + + return getCachedValue() == other.getCachedValue(); + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/ClassDataItem.java b/src/main/java/org/JesusFreke/dexlib/ClassDataItem.java new file mode 100644 index 00000000..688fcc35 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/ClassDataItem.java @@ -0,0 +1,351 @@ +/* + * [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.JesusFreke.dexlib; + +import org.JesusFreke.dexlib.ItemType; +import org.JesusFreke.dexlib.util.Output; +import org.JesusFreke.dexlib.util.Input; +import org.JesusFreke.dexlib.util.AccessFlags; + +import java.util.ArrayList; +import java.util.Collections; + +public class ClassDataItem extends OffsettedItem { + private final Field[] fields; + + private final ArrayList staticFieldList = new ArrayList(); + private final ArrayList instanceFieldList = new ArrayList(); + private final ArrayList directMethodList = new ArrayList(); + private final ArrayList virtualMethodList = new ArrayList(); + + private final ListSizeField staticFieldsCount; + private final ListSizeField instanceFieldsCount; + private final ListSizeField directMethodsCount; + private final ListSizeField virtualMethodsCount; + private final EncodedMemberList staticFields; + private final EncodedMemberList instanceFields; + private final EncodedMemberList directMethods; + private final EncodedMemberList virtualMethods; + + + public ClassDataItem(final DexFile dexFile, int offset) { + super(offset); + + fields = new Field[] { + staticFieldsCount = new ListSizeField(staticFieldList, new Leb128Field()), + instanceFieldsCount = new ListSizeField(instanceFieldList, new Leb128Field()), + directMethodsCount = new ListSizeField(directMethodList, new Leb128Field()), + virtualMethodsCount = new ListSizeField(virtualMethodList, new Leb128Field()), + staticFields = new EncodedMemberList(staticFieldList) { + protected EncodedField make(EncodedField previousField) { + return new EncodedField(dexFile, previousField); + } + }, + instanceFields = new EncodedMemberList(instanceFieldList) { + protected EncodedField make(EncodedField previousField) { + return new EncodedField(dexFile, previousField); + } + }, + directMethods = new EncodedMemberList(directMethodList) { + protected EncodedMethod make(EncodedMethod previousMethod) { + return new EncodedMethod(dexFile, previousMethod); + } + }, + virtualMethods = new EncodedMemberList(virtualMethodList) { + protected EncodedMethod make(EncodedMethod previousMethod) { + return new EncodedMethod(dexFile, previousMethod); + } + } + }; + } + + public void addMethod(EncodedMethod encodedMethod) { + if (encodedMethod.isDirect()) { + directMethodList.add(encodedMethod); + } else { + virtualMethodList.add(encodedMethod); + } + } + + public int addField(EncodedField encodedField) { + if (encodedField.isStatic()) { + staticFieldList.add(encodedField); + Collections.sort(staticFieldList); + return Collections.binarySearch(staticFieldList, encodedField); + } else { + instanceFieldList.add(encodedField); + Collections.sort(instanceFieldList); + return Collections.binarySearch(instanceFieldList, encodedField); + } + } + + public EncodedField getStaticFieldAtIndex(int i) + { + return staticFieldList.get(i); + } + + private static abstract class EncodedMember> extends CompositeField implements Field, Comparable + { + protected abstract void setPreviousMember(T previousMember); + } + + private static abstract class EncodedMemberList> implements Field> { + private final ArrayList list; + + public EncodedMemberList(ArrayList list) { + this.list = list; + } + + public void writeTo(Output out) { + for (T field: list) { + field.writeTo(out); + } + } + + protected abstract T make(T previousField); + + public void readFrom(Input in) { + for (int i = 0; i < list.size(); i++) { + T previousField = null; + if (i > 0) { + previousField = list.get(i-1); + } + T field = make(previousField); + list.set(i, field); + field.readFrom(in); + } + } + + public int place(int offset) { + Collections.sort(list); + + T previousMember = null; + for (T encodedMember: list) { + encodedMember.setPreviousMember(previousMember); + offset = encodedMember.place(offset); + previousMember = encodedMember; + } + return offset; + } + + public void copyTo(DexFile dexFile, EncodedMemberList copy) { + copy.list.clear(); + copy.list.ensureCapacity(list.size()); + for (int i = 0; i < list.size(); i++) { + T previousField = null; + if (i > 0) { + previousField = copy.list.get(i-1); + } + T fieldCopy = copy.make(previousField); + list.get(i).copyTo(dexFile, fieldCopy); + copy.list.add(fieldCopy); + } + } + + public int hashCode() { + int h = 1; + for (int i = 0; i < list.size(); i++) { + h = h * 31 + list.get(i).hashCode(); + } + return h; + } + + public boolean equals(Object o) { + if (!(o instanceof EncodedMemberList)) { + return false; + } + + EncodedMemberList other = (EncodedMemberList)o; + if (list.size() != other.list.size()) { + return false; + } + + for (int i = 0; i < list.size(); i++) { + if (!list.get(i).equals(other.list.get(i))) { + return false; + } + } + return true; + } + } + + public static class EncodedField extends EncodedMember { + private final Field[] fields; + + private final IndexedItemReference field; + private final Leb128DeltaField fieldIndexField; + private final Leb128Field accessFlags; + + public EncodedField(DexFile dexFile, final EncodedField previousField) { + Leb128DeltaField previousIndexField = null; + if (previousField != null) { + previousIndexField = previousField.fieldIndexField; + } + + + fields = new Field[] { + field = new IndexedItemReference(dexFile.FieldIdsSection, + fieldIndexField = new Leb128DeltaField(previousIndexField)), + accessFlags = new Leb128Field() + }; + } + + public EncodedField(DexFile dexFile, FieldIdItem field, int accessFlags) { + fields = new Field[] { + this.field = new IndexedItemReference(dexFile, field, + fieldIndexField = new Leb128DeltaField(null)), + this.accessFlags = new Leb128Field(accessFlags) + }; + } + + protected void setPreviousMember(EncodedField previousField) { + if (previousField != null) { + fieldIndexField.setPreviousField(previousField.fieldIndexField); + } else { + fieldIndexField.setPreviousField(null); + } + } + + protected Field[] getFields() { + return fields; + } + + public int compareTo(EncodedField other) + { + return field.getReference().compareTo(other.field.getReference()); + } + + public boolean isStatic() { + return (accessFlags.getCachedValue() & AccessFlags.STATIC) != 0; + } + + public FieldIdItem getField() { + return field.getReference(); + } + } + + public static class EncodedMethod extends EncodedMember { + private final Field[] fields; + + private final IndexedItemReference method; + private final Leb128DeltaField methodIndexField; + private final Leb128Field accessFlags; + private final OffsettedItemReference codeItem; + + public EncodedMethod(DexFile dexFile, final EncodedMethod previousMethod) { + Leb128DeltaField previousIndexField = null; + if (previousMethod != null) { + previousIndexField = previousMethod.methodIndexField; + } + + fields = new Field[] { + method = new IndexedItemReference(dexFile.MethodIdsSection, + methodIndexField = new Leb128DeltaField(previousIndexField)), + accessFlags = new Leb128Field(), + codeItem = new OffsettedItemReference(dexFile.CodeItemsSection, new Leb128Field()) + }; + } + + public EncodedMethod(DexFile dexFile, MethodIdItem methodIdItem, int accessFlags, CodeItem codeItem) { + fields = new Field[] { + this.method = new IndexedItemReference(dexFile, methodIdItem, + methodIndexField = new Leb128DeltaField(null)), + this.accessFlags = new Leb128Field(accessFlags), + this.codeItem = new OffsettedItemReference(dexFile, codeItem, new Leb128Field()) + }; + } + + protected void setPreviousMember(EncodedMethod previousMethod) { + if (previousMethod != null) { + methodIndexField.setPreviousField(previousMethod.methodIndexField); + } else { + methodIndexField.setPreviousField(null); + } + } + + protected Field[] getFields() { + return fields; + } + + public int compareTo(EncodedMethod other) + { + return method.getReference().compareTo(other.method.getReference()); + } + + public boolean isDirect() { + return ((accessFlags.getCachedValue() & (AccessFlags.STATIC | AccessFlags.PRIVATE | AccessFlags.CONSTRUCTOR)) != 0); + } + } + + + /** + * An Leb128 integer that encodes its value as the difference between + * itself and the previous Leb128DeltaField in the list. The first + * item encodes the value as per normal + */ + protected static class Leb128DeltaField extends Leb128Field { + private Leb128DeltaField previousField; + + public Leb128DeltaField(Leb128DeltaField previousField) { + this.previousField = previousField; + } + + public void setPreviousField(Leb128DeltaField previousField) { + this.previousField = previousField; + } + + public int getCachedValue() { + if (previousField != null) { + return previousField.getCachedValue() + super.getCachedValue(); + } else { + return super.getCachedValue(); + } + } + + public void cacheValue(int value) { + if (previousField != null) { + super.cacheValue(value - previousField.getCachedValue()); + } else { + super.cacheValue(value); + } + } + } + + protected int getAlignment() { + return 1; + } + + protected Field[] getFields() { + return fields; + } + + public ItemType getItemType() { + return ItemType.TYPE_CLASS_DATA_ITEM; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/ClassDefItem.java b/src/main/java/org/JesusFreke/dexlib/ClassDefItem.java new file mode 100644 index 00000000..7bb5b2ec --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/ClassDefItem.java @@ -0,0 +1,229 @@ +/* + * [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.JesusFreke.dexlib; + +import org.JesusFreke.dexlib.ItemType; +import org.JesusFreke.dexlib.EncodedValue.EncodedValue; +import org.JesusFreke.dexlib.EncodedValue.EncodedValueSubField; +import org.JesusFreke.dexlib.util.TypeUtils; + +import java.util.HashMap; +import java.util.ArrayList; + +public class ClassDefItem extends IndexedItem { + private final Field[] fields; + + private final IndexedItemReference classType; + private final IntegerField accessFlags; + private final IndexedItemReference superclassType; + private final OffsettedItemReference classInterfacesList; + private final IndexedItemReference sourceFile; + private final OffsettedItemReference classAnnotations; + private final OffsettedItemReference classData; + private final OffsettedItemReference staticFieldInitialValues; + + private ArrayList staticFieldInitialValuesList; + + private final DexFile dexFile; + + public ClassDefItem(DexFile dexFile, int index) { + super(index); + + this.dexFile = dexFile; + + fields = new Field[] { + classType = new IndexedItemReference(dexFile.TypeIdsSection, new IntegerField()), + accessFlags = new IntegerField(), + superclassType = new IndexedItemReference(dexFile.TypeIdsSection, new IntegerField()), + classInterfacesList = new OffsettedItemReference(dexFile.TypeListsSection, new IntegerField()), + sourceFile = new IndexedItemReference(dexFile.StringIdsSection, new IntegerField()), + classAnnotations = new OffsettedItemReference(dexFile.AnnotationDirectoriesSection, new IntegerField()), + classData = new OffsettedItemReference(dexFile.ClassDataSection, new IntegerField()), + staticFieldInitialValues = new OffsettedItemReference(dexFile.EncodedArraysSection, new IntegerField()) + }; + } + + public ClassDefItem(DexFile dexFile, TypeIdItem classType, int accessFlags, TypeIdItem superType, ClassDataItem classDataItem) { + super(-1); + + this.dexFile = dexFile; + + fields = new Field[] { + this.classType = new IndexedItemReference(dexFile, classType, new IntegerField()), + this.accessFlags = new IntegerField(accessFlags), + superclassType = new IndexedItemReference(dexFile, superType, new IntegerField()), + classInterfacesList = new OffsettedItemReference(dexFile.TypeListsSection, new IntegerField()), + sourceFile = new IndexedItemReference(dexFile.StringIdsSection, new IntegerField()), + classAnnotations = new OffsettedItemReference(dexFile.AnnotationDirectoriesSection, new IntegerField()), + classData = new OffsettedItemReference(dexFile, classDataItem, new IntegerField()), + staticFieldInitialValues = new OffsettedItemReference(dexFile.EncodedArraysSection, new IntegerField()) + }; + } + + public TypeIdItem getSuperclass() { + return superclassType.getReference(); + } + + public TypeIdItem getClassType() { + return classType.getReference(); + } + + protected int getAlignment() { + return 4; + } + + protected Field[] getFields() { + return fields; + } + + public ItemType getItemType() { + return ItemType.TYPE_CLASS_DEF_ITEM; + } + + public String getClassName() { + return classType.getReference().toString(); + } + + public String toString() { + return getClassName(); + } + + public int hashCode() { + return classType.getReference().hashCode(); + } + + public boolean equals(Object o) { + if (!(o instanceof ClassDefItem)) { + return false; + } + ClassDefItem other = (ClassDefItem)o; + return classType.equals(other.classType); + } + + public int compareTo(ClassDefItem o) { + //sorting is implemented in SortClassDefItemSection, so this class doesn't + //need an implementation of compareTo + return 0; + } + + public void addMethod(ClassDataItem.EncodedMethod encodedMethod) { + } + + public void addField(ClassDataItem.EncodedField encodedField, EncodedValue initialValue) { + if (!encodedField.isStatic() && initialValue != null) { + throw new RuntimeException("Initial values are only allowed for static fields."); + } + + ClassDataItem classDataItem = this.classData.getReference(); + + int fieldIndex = classDataItem.addField(encodedField); + if (initialValue != null) { + if (staticFieldInitialValuesList == null) { + staticFieldInitialValuesList = new ArrayList(); + + EncodedArrayItem encodedArrayItem = new EncodedArrayItem(dexFile, staticFieldInitialValuesList); + staticFieldInitialValues.setReference(encodedArrayItem); + } + + //All static fields before this one must have an initial value. Add any default values as needed + for (int i=staticFieldInitialValuesList.size(); i < fieldIndex; i++) { + ClassDataItem.EncodedField staticField = classDataItem.getStaticFieldAtIndex(i); + EncodedValueSubField subField = TypeUtils.makeDefaultValueForType(dexFile, staticField.getField().getFieldType().toString()); + EncodedValue encodedValue = new EncodedValue(dexFile, subField); + staticFieldInitialValuesList.add(i, encodedValue); + } + + staticFieldInitialValuesList.add(fieldIndex, initialValue); + } + } + + 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 classDefsByType = 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.getReference(); + classDefsByType.put(typeIdItem, classDefItem); + } + } + + public int placeSection(int offset) { + currentOffset = offset; + for (ClassDefItem classDefItem: section.items) { + placeClass(classDefItem); + } + + for (ClassDefItem classDefItem: classDefsByType.values()) { + section.items.set(classDefItem.getIndex(), classDefItem); + } + + return currentOffset; + } + + private void placeClass(ClassDefItem classDefItem) { + if (!classDefItem.isPlaced()) { + TypeIdItem superType = classDefItem.superclassType.getReference(); + ClassDefItem superClassDefItem = classDefsByType.get(superType); + + if (superClassDefItem != null) { + placeClass(superClassDefItem); + } + + TypeListItem interfaces = classDefItem.classInterfacesList.getReference(); + + if (interfaces != null) { + for (TypeIdItem interfaceType: interfaces.getTypes()) { + ClassDefItem interfaceClass = classDefsByType.get(interfaceType); + if (interfaceClass != null) { + placeClass(interfaceClass); + } + } + } + + currentOffset = classDefItem.place(currentIndex++, currentOffset); + } + } + + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/CodeItem.java b/src/main/java/org/JesusFreke/dexlib/CodeItem.java new file mode 100644 index 00000000..07c39b53 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/CodeItem.java @@ -0,0 +1,384 @@ +/* + * [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.JesusFreke.dexlib; + +import org.JesusFreke.dexlib.code.Instruction; +import org.JesusFreke.dexlib.code.Opcode; +import org.JesusFreke.dexlib.ItemType; +import org.JesusFreke.dexlib.util.Input; +import org.JesusFreke.dexlib.util.Output; + +import java.util.ArrayList; + +public class CodeItem extends OffsettedItem { + private final Field[] fields; + private final ArrayList instructionList; + private final ArrayList tryItems = new ArrayList(); + private final ArrayList catchHandlerList = new ArrayList(); + + private final ShortIntegerField registersCount; + private final ShortIntegerField inArgumentCount; + private final ShortIntegerField outArgumentCount; + private final ListSizeField triesCount; + private final OffsettedItemReference debugInfo; + private final IntegerField instructionsSize; + private final InstructionListField instructionListField; + private final PaddingField padding; + private final FieldListField tries; + private final EncodedCatchHandlerList catchHandlers; + + public CodeItem(final DexFile dexFile, int offset) { + super(offset); + + instructionList = new ArrayList(); + + fields = new Field[] { + registersCount = new ShortIntegerField(), + inArgumentCount = new ShortIntegerField(), + outArgumentCount = new ShortIntegerField(), + triesCount = new ListSizeField(tryItems, new ShortIntegerField()), + debugInfo = new OffsettedItemReference(dexFile.DebugInfoItemsSection, new IntegerField()), + instructionsSize = new IntegerField(), + instructionListField = new InstructionListField(dexFile), + padding = new PaddingField(), + tries = new FieldListField(tryItems) { + protected TryItem make() { + return new TryItem(); + } + }, + + catchHandlers = new EncodedCatchHandlerList(dexFile) + }; + } + + + + public CodeItem(final DexFile dexFile, int registersCount, int inArguments, ArrayList instructions) { + super(-1); + + this.instructionList = new ArrayList(instructions); + this.instructionListField = new InstructionListField(dexFile); + + fields = new Field[] { + this.registersCount = new ShortIntegerField(registersCount), + this.inArgumentCount = new ShortIntegerField(inArguments), + this.outArgumentCount = new ShortIntegerField(instructionListField.getOutArguments()), + this.triesCount = new ListSizeField(tryItems, new ShortIntegerField(0)), + this.debugInfo = new OffsettedItemReference(dexFile, null, new IntegerField()), + this.instructionsSize = new IntegerField(instructionListField.getInstructionWordCount()), + instructionListField, + this.padding = new PaddingField(), + this.tries = new FieldListField(tryItems) { + protected TryItem make() { + return new TryItem(); + } + }, + this.catchHandlers = new EncodedCatchHandlerList(dexFile) + }; + } + + //TODO: take out + public void writeTo(Output out) { + super.writeTo(out); + } + + protected int getAlignment() { + return 4; + } + + public ItemType getItemType() { + return ItemType.TYPE_CODE_ITEM; + } + + public Field[] getFields() { + return fields; + } + + public class TryItem extends CompositeField { + private final Field[] fields; + + public TryItem() { + fields = new Field[] { + new IntegerField(), + new ShortIntegerField(), + new ShortIntegerField() + }; + } + + + protected Field[] getFields() { + return fields; + } + } + + class EncodedCatchHandlerList extends CompositeField { + private boolean fieldPresent = false; + + private final DexFile dexFile; + + public EncodedCatchHandlerList(DexFile dexFile) { + this.dexFile = dexFile; + } + + private final Field[] fields = new Field[] { + new ListSizeField(catchHandlerList, new Leb128Field()), + new FieldListField(catchHandlerList) { + protected EncodedCatchHandler make() { + return new EncodedCatchHandler(dexFile); + } + } + }; + + public void readFrom(Input in) { + if (tryItems.size() > 0) { + fieldPresent = true; + super.readFrom(in); + } + } + + public void writeTo(Output out) { + if (fieldPresent) { + super.writeTo(out); + } + } + + public int place(int offset) { + if (tryItems.size() > 0) { + fieldPresent = true; + return super.place(offset); + } else { + return offset; + } + } + + protected Field[] getFields() { + return fields; + } + + public void copyTo(DexFile dexFile, EncodedCatchHandlerList copy) { + super.copyTo(dexFile, copy); + copy.fieldPresent = fieldPresent; + } + } + + public class EncodedCatchHandler extends CompositeField { + public final Field[] fields; + private ArrayList list = new ArrayList(); + private boolean hasCatchAll = false; + + public EncodedCatchHandler(final DexFile dexFile) { + fields = new Field[] { + new ListSizeField(list, new SignedLeb128Field() { + public void readFrom(Input in) { + super.readFrom(in); + hasCatchAll = (getCachedValue() <= 0); + } + + public void cacheValue(int value) { + super.cacheValue(value * (hasCatchAll?-1:1)); + }}) + , + new FieldListField(list) { + protected EncodedTypeAddrPair make() { + return new EncodedTypeAddrPair(dexFile); + } + }, + new Leb128Field() { + public void readFrom(Input in) { + if (hasCatchAll) { + super.readFrom(in); + } + } + + public void writeTo(Output out) { + if (hasCatchAll) { + super.writeTo(out); + } + } + + public int place(int offset) { + if (hasCatchAll) { + return super.place(offset); + } + return offset; + } + } + }; + } + + protected Field[] getFields() { + return fields; + } + + public void copyTo(DexFile dexFile, EncodedCatchHandler copy) { + super.copyTo(dexFile, copy); + copy.hasCatchAll = hasCatchAll; + } + } + + public class EncodedTypeAddrPair extends CompositeField { + public final Field[] fields; + + public EncodedTypeAddrPair(DexFile dexFile) { + fields = new Field[] { + new IndexedItemReference(dexFile.TypeIdsSection, new Leb128Field()), + new Leb128Field() + }; + } + + protected Field[] getFields() { + return fields; + } + } + + private class InstructionListField implements Field { + private final DexFile dexFile; + + public InstructionListField(DexFile dexFile) { + this.dexFile = dexFile; + } + + public void writeTo(Output out) { + int startPosition = out.getCursor(); + for (Instruction instruction: instructionList) { + instruction.writeTo(out); + } + if ((out.getCursor() - startPosition) != (instructionsSize.getCachedValue() * 2)) { + throw new RuntimeException("Did not write the expected amount of bytes"); + } + } + + public void readFrom(Input in) { + int numBytes = instructionsSize.getCachedValue() * 2; + int startPosition = in.getCursor(); + + do { + Instruction instruction = new Instruction(dexFile); + instruction.readFrom(in); + instructionList.add(instruction); + } while (in.getCursor() - startPosition < numBytes); + + if (in.getCursor() - startPosition != numBytes) { + throw new RuntimeException("Read past the end of the code section"); + } + } + + public int place(int offset) { + return offset + (instructionsSize.getCachedValue() * 2); + } + + public void copyTo(DexFile dexFile, InstructionListField copy) { + ArrayList copyInstructionList = copy.getInstructionList(); + copyInstructionList.clear(); + for (Instruction instruction: instructionList) { + Instruction instructionCopy = new Instruction(dexFile); + instruction.copyTo(dexFile, instructionCopy); + copyInstructionList.add(instructionCopy); + } + } + + private ArrayList getInstructionList() { + return instructionList; + } + + //return the word size of the instruction list + public int getInstructionWordCount() { + int bytes = 0; + //TODO: what about option padding before the special opcodes? + for (Instruction instruction: instructionList) { + bytes += instruction.getBytes().length; + } + return bytes/2; + } + + //return the highest parameter word count of any method invokation + public int getOutArguments() { + int maxParamWordCount = 0; + for (Instruction instruction: instructionList) { + IndexedItem item = instruction.getReference(); + if (item instanceof MethodIdItem) { + MethodIdItem methodIdItem = (MethodIdItem)item; + Opcode opcode = instruction.getOpcode(); + + boolean isStatic = false; + if (opcode == Opcode.INVOKE_STATIC || opcode == Opcode.INVOKE_STATIC_RANGE) { + isStatic = true; + } + int paramWordCount = methodIdItem.getParameterWordCount(isStatic); + + if (maxParamWordCount < paramWordCount) { + maxParamWordCount = paramWordCount; + } + } + } + return maxParamWordCount; + } + } + + private class PaddingField implements Field { + + public PaddingField() { + } + + private boolean needsAlign() { + return (triesCount.getCachedValue() > 0) && (instructionsSize.getCachedValue() % 2 == 1); + } + + public void writeTo(Output out) { + if (needsAlign()) { + out.writeShort(0); + } + } + + public void readFrom(Input in) { + if (needsAlign()) { + in.skipBytes(2); + } + } + + public int place(int offset) { + if (needsAlign()) { + return offset + 2; + } else { + return offset; + } + } + + public int hashCode() { + return 0; + } + + public boolean equals(Object o) { + return getClass() == o.getClass(); + } + + public void copyTo(DexFile dexFile, Field field) { + } + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/CompositeField.java b/src/main/java/org/JesusFreke/dexlib/CompositeField.java new file mode 100644 index 00000000..e933ec2a --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/CompositeField.java @@ -0,0 +1,102 @@ +/* + * [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.JesusFreke.dexlib; + +import org.JesusFreke.dexlib.util.Output; +import org.JesusFreke.dexlib.util.Input; + + +public abstract class CompositeField> implements Field { + /** + * Every instance of a specific subclass should return an array with the same structure, + * in other words have the same size, and the same type of field at each position. + * @return An array of fields that represents the sub-fields that make up this CompositeField + */ + protected abstract Field[] getFields(); + + public void writeTo(Output out) { + for (Field field: getFields()) { + field.writeTo(out); + } + } + + public void readFrom(Input in) { + for (Field field: getFields()) { + field.readFrom(in); + } + } + + public int place(int offset) { + for (Field field: getFields()) { + offset = field.place(offset); + } + return offset; + } + + public void copyTo(DexFile dexFile, T copy) { + Field[] fields = getFields(); + Field[] copyFields = copy.getFields(); + for (int i = 0; i < fields.length; i++) { + /** + * This assumes that the fields will be the same for every instance + * of a specific concrete subclass. By making this assumption, every subclass is + * prevented from having to implement copyTo + */ + fields[i].copyTo(dexFile, copyFields[i]); + } + } + + public int hashCode() { + int h = 1; + for (Field field: getFields()) { + h = h * 31 + field.hashCode(); + } + return h; + } + + public boolean equals(Object o) { + if (!(o instanceof CompositeField)) { + return false; + } + + CompositeField other = (CompositeField)o; + Field[] fields = getFields(); + Field[] otherFields = other.getFields(); + if (fields.length != otherFields.length) { + return false; + } + for (int i = 0; i < fields.length; i++) { + if (!fields[i].equals(otherFields[i])) { + return false; + } + } + + return true; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/DebugInfoItem.java b/src/main/java/org/JesusFreke/dexlib/DebugInfoItem.java new file mode 100644 index 00000000..e15c33f7 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/DebugInfoItem.java @@ -0,0 +1,116 @@ +/* + * [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.JesusFreke.dexlib; + +import org.JesusFreke.dexlib.ItemType; +import org.JesusFreke.dexlib.debug.DebugInstructionFactory; +import org.JesusFreke.dexlib.debug.EndSequence; +import org.JesusFreke.dexlib.debug.DebugInstruction; +import org.JesusFreke.dexlib.util.Output; +import org.JesusFreke.dexlib.util.Input; + +import java.util.ArrayList; + +public class DebugInfoItem extends OffsettedItem { + private final Field[] fields; + + private final ArrayList> parameterNames = + new ArrayList>(); + + private ArrayList instructionFields = new ArrayList(); + + public DebugInfoItem(final DexFile dexFile, int offset) { + super(offset); + + fields = new Field[] { + new Leb128Field(), + new ListSizeField(parameterNames, new Leb128Field()), + new FieldListField>(parameterNames) { + protected IndexedItemReference make() { + return new IndexedItemReference(dexFile.StringIdsSection, new Leb128p1Field()); + } + }, + new DebugInstructionList(dexFile) + }; + } + + protected int getAlignment() { + return 1; + } + + protected Field[] getFields() { + return fields; + } + + public ItemType getItemType() { + return ItemType.TYPE_DEBUG_INFO_ITEM; + } + + private class DebugInstructionList implements Field { + private final DexFile dexFile; + private final ArrayList list; + + public DebugInstructionList(DexFile dexFile) { + this.dexFile = dexFile; + list = instructionFields; + } + + public void writeTo(Output out) { + for (DebugInstruction debugInstruction: list) { + debugInstruction.writeTo(out); + } + } + + public void readFrom(Input in) { + DebugInstruction debugInstruction; + do { + debugInstruction = DebugInstructionFactory.readDebugInstruction(dexFile, in); + list.add(debugInstruction); + } while (!(debugInstruction instanceof EndSequence)); + } + + public int place(int offset) { + for (Field field: list) { + offset = field.place(offset); + } + return offset; + } + + public void copyTo(DexFile dexFile, DebugInstructionList copy) { + copy.list.clear(); + copy.list.ensureCapacity(list.size()); + for (int i = 0; i < list.size(); i++) { + DebugInstruction debugInstruction = list.get(i); + DebugInstruction debugInstructionCopy = DebugInstructionFactory.makeDebugInstruction(dexFile, debugInstruction.getOpcode()); + debugInstruction.copyTo(dexFile, debugInstructionCopy); + copy.list.add(debugInstructionCopy); + } + } + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/DexFile.java b/src/main/java/org/JesusFreke/dexlib/DexFile.java new file mode 100644 index 00000000..7a77d4ad --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/DexFile.java @@ -0,0 +1,390 @@ +/* + * [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.JesusFreke.dexlib; + +import org.JesusFreke.dexlib.util.Input; +import org.JesusFreke.dexlib.util.ByteArrayInput; +import org.JesusFreke.dexlib.util.Output; +import org.JesusFreke.dexlib.util.FileUtils; + +import java.util.HashMap; +import java.util.ArrayList; +import java.util.zip.Adler32; +import java.io.File; +import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.DigestException; + +public class DexFile +{ + private final HashMap sectionsByType; + private final IndexedSection[] indexedSections; + private final OffsettedSection[] offsettedSections; + private int fileSize; + private int dataOffset; + private int dataSize; + + private final DexFile dexFile = this; + + private DexFile() { + sectionsByType = new HashMap(18); + + sectionsByType.put(ItemType.TYPE_ANNOTATION_ITEM, AnnotationsSection); + sectionsByType.put(ItemType.TYPE_ANNOTATION_SET_ITEM, AnnotationSetsSection); + sectionsByType.put(ItemType.TYPE_ANNOTATION_SET_REF_LIST, AnnotationSetRefListsSection); + sectionsByType.put(ItemType.TYPE_ANNOTATIONS_DIRECTORY_ITEM, AnnotationDirectoriesSection); + sectionsByType.put(ItemType.TYPE_CLASS_DATA_ITEM, ClassDataSection); + sectionsByType.put(ItemType.TYPE_CLASS_DEF_ITEM, ClassDefsSection); + sectionsByType.put(ItemType.TYPE_CODE_ITEM, CodeItemsSection); + sectionsByType.put(ItemType.TYPE_DEBUG_INFO_ITEM, DebugInfoItemsSection); + sectionsByType.put(ItemType.TYPE_ENCODED_ARRAY_ITEM, EncodedArraysSection); + sectionsByType.put(ItemType.TYPE_FIELD_ID_ITEM, FieldIdsSection); + sectionsByType.put(ItemType.TYPE_HEADER_ITEM, HeaderItemSection); + sectionsByType.put(ItemType.TYPE_MAP_LIST, MapSection); + sectionsByType.put(ItemType.TYPE_METHOD_ID_ITEM, MethodIdsSection); + sectionsByType.put(ItemType.TYPE_PROTO_ID_ITEM, ProtoIdsSection); + sectionsByType.put(ItemType.TYPE_STRING_DATA_ITEM, StringDataSection); + sectionsByType.put(ItemType.TYPE_STRING_ID_ITEM, StringIdsSection); + sectionsByType.put(ItemType.TYPE_TYPE_ID_ITEM, TypeIdsSection); + sectionsByType.put(ItemType.TYPE_TYPE_LIST, TypeListsSection); + + indexedSections = new IndexedSection[] { + StringIdsSection, + TypeIdsSection, + ProtoIdsSection, + FieldIdsSection, + MethodIdsSection, + ClassDefsSection + }; + + offsettedSections = new OffsettedSection[] { + AnnotationSetsSection, + CodeItemsSection, + AnnotationDirectoriesSection, + TypeListsSection, + StringDataSection, + DebugInfoItemsSection, + AnnotationsSection, + EncodedArraysSection, + ClassDataSection, + + AnnotationSetRefListsSection + }; + } + + public DexFile(File file) { + this(); + Input in = new ByteArrayInput(FileUtils.readFile(file)); + + HeaderItemSection.readFrom(1, in); + HeaderItem headerItem = HeaderItemSection.items.get(0); + + in.setCursor(headerItem.getMapOffset()); + + MapSection.readFrom(1, in); + + for (MapField mapField: MapSection.items.get(0).getMapEntries()) { + Section section = sectionsByType.get(mapField.getSectionItemType()); + if (section != null) { + in.setCursor(mapField.getSectionOffset()); + section.readFrom(mapField.getSectionSize(), in); + } + } + } + + public static DexFile makeBlankDexFile() { + DexFile dexFile = new DexFile(); + try + { + dexFile.HeaderItemSection.intern(dexFile, new HeaderItem(dexFile, 0)); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + + dexFile.MapSection.intern(dexFile, MapItem.makeBlankMapItem(dexFile)); + return dexFile; + } + + + public Section getSectionForItem(T item) { + return sectionsByType.get(item.getItemType()); + } + + public Section getSectionForType(ItemType itemType) { + return sectionsByType.get(itemType); + } + + public int getFileSize() { + return fileSize; + } + + public int getDataOffset() { + return dataOffset; + } + + public int getDataSize() { + return dataSize; + } + + public void place() { + int offset = 0; + + offset = HeaderItemSection.place(offset); + for (IndexedSection indexedSection: indexedSections) { + indexedSection.unplace(); + offset = indexedSection.place(offset); + } + + dataOffset = offset; + + for (OffsettedSection offsettedSection: offsettedSections) { + offsettedSection.unplace(); + + offset = offsettedSection.place(offset); + } + + offset = MapSection.place(offset); + + dataSize = offset - dataOffset; + fileSize = offset; + } + + public void writeTo(Output out) { + HeaderItemSection.writeTo(out); + for (IndexedSection indexedSection: indexedSections) { + indexedSection.writeTo(out); + } + + for (OffsettedSection offsettedSection: offsettedSections) { + offsettedSection.writeTo(out); + } + + MapSection.writeTo(out); + } + + public ClassDefItem getClassByName(String className) { + for (ClassDefItem classDefItem: ClassDefsSection.items) { + if (classDefItem.getClassName().equals(className)) { + return classDefItem; + } + } + throw new RuntimeException("class not found"); + } + + public MethodIdItem[] getMethodsByClass(TypeIdItem classType) { + ArrayList methods = new ArrayList(); + + for (MethodIdItem methodIdItem: MethodIdsSection.items) { + if (methodIdItem.getClassType() == classType) { + methods.add(methodIdItem); + } + } + + return methods.toArray(new MethodIdItem[0]); + } + + + + public final IndexedSection HeaderItemSection = new IndexedSection() { + protected HeaderItem make(int index) { + try { + return new HeaderItem(dexFile, index); + } catch (UnsupportedEncodingException ex) { + //TODO: handle this + throw new RuntimeException(ex); + } + } + }; + + public final IndexedSection StringIdsSection = new IndexedSection() { + protected StringIdItem make(int index) { + return new StringIdItem(dexFile, index); + } + }; + + public final IndexedSection TypeIdsSection = new IndexedSection() { + protected TypeIdItem make(int index) { + return new TypeIdItem(dexFile, index); + } + }; + + public final IndexedSection ProtoIdsSection = new IndexedSection() { + protected ProtoIdItem make(int index) { + return new ProtoIdItem(dexFile, index); + } + }; + + public final IndexedSection FieldIdsSection = new IndexedSection() { + protected FieldIdItem make(int index) { + return new FieldIdItem(dexFile, index); + } + }; + + public final IndexedSection MethodIdsSection = new IndexedSection() { + protected MethodIdItem make(int index) { + return new MethodIdItem(dexFile, index); + } + }; + + public final IndexedSection ClassDefsSection = new IndexedSection() { + protected ClassDefItem make(int index) { + return new ClassDefItem(dexFile, index); + } + + public int place(int offset) { + int ret = ClassDefItem.placeClassDefItems(this, offset); + + this.offset = items.get(0).getOffset(); + return ret; + } + }; + + public final IndexedSection MapSection = new IndexedSection() { + protected MapItem make(int index) { + return new MapItem(dexFile, index); + } + + public MapItem intern(DexFile dexFile, MapItem item) { + this.items.add(item); + return item; + } + }; + + public final OffsettedSection TypeListsSection = new OffsettedSection() { + protected TypeListItem make(int offset) { + return new TypeListItem(dexFile, offset); + } + }; + + public final OffsettedSection AnnotationSetRefListsSection = + new OffsettedSection() { + protected AnnotationSetRefList make(int offset) { + return new AnnotationSetRefList(dexFile, offset); + } + }; + + public final OffsettedSection AnnotationSetsSection = + new OffsettedSection() { + protected AnnotationSetItem make(int offset) { + return new AnnotationSetItem(dexFile, offset); + } + }; + + public final OffsettedSection ClassDataSection = new OffsettedSection() { + protected ClassDataItem make(int offset) { + return new ClassDataItem(dexFile, offset); + } + }; + + public final OffsettedSection CodeItemsSection = new OffsettedSection() { + protected CodeItem make(int offset) { + return new CodeItem(dexFile, offset); + } + }; + + public final OffsettedSection StringDataSection = new OffsettedSection() { + protected StringDataItem make(int offset) { + return new StringDataItem(offset); + } + }; + + public final OffsettedSection DebugInfoItemsSection = new OffsettedSection() { + protected DebugInfoItem make(int offset) { + return new DebugInfoItem(dexFile, offset); + } + }; + + public final OffsettedSection AnnotationsSection = new OffsettedSection() { + protected AnnotationItem make(int offset) { + return new AnnotationItem(dexFile, offset); + } + }; + + public final OffsettedSection EncodedArraysSection = new OffsettedSection() { + protected EncodedArrayItem make(int offset) { + return new EncodedArrayItem(dexFile, offset); + } + }; + + public final OffsettedSection AnnotationDirectoriesSection = + new OffsettedSection() { + protected AnnotationDirectoryItem make(int offset) { + return new AnnotationDirectoryItem(dexFile, offset); + } + }; + + + /** + * Calculates the signature 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 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); + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/EncodedArrayItem.java b/src/main/java/org/JesusFreke/dexlib/EncodedArrayItem.java new file mode 100644 index 00000000..032f2b9b --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/EncodedArrayItem.java @@ -0,0 +1,91 @@ +/* + * [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.JesusFreke.dexlib; + +import org.JesusFreke.dexlib.ItemType; +import org.JesusFreke.dexlib.EncodedValue.ArrayEncodedValueSubField; +import org.JesusFreke.dexlib.EncodedValue.EncodedValue; +import org.JesusFreke.dexlib.util.Input; +import org.JesusFreke.dexlib.util.Output; + +import java.util.ArrayList; + +public class EncodedArrayItem extends OffsettedItem { + private final Field[] fields; + + private final ArrayEncodedValueSubField encodedArray; + + public EncodedArrayItem(DexFile dexFile, int offset) { + super(offset); + + fields = new Field[] { + encodedArray = new ArrayEncodedValueSubField(dexFile) + }; + } + + public EncodedArrayItem(DexFile dexFile, ArrayList encodedValues) { + super(-1); + + fields = new Field[] { + encodedArray = new ArrayEncodedValueSubField(dexFile, encodedValues) + }; + } + + public void readFrom(Input in) { + super.readFrom(in); + } + + public int place(int index, int offset) { + return super.place(index, offset); + } + + public void writeTo(Output out) { + super.writeTo(out); + } + + protected int getAlignment() { + return 1; + } + + protected Field[] getFields() { + return fields; + } + + public int getOffset() { + return super.getOffset(); + } + + public void add(int index, EncodedValue value) { + encodedArray.add(index, value); + } + + public ItemType getItemType() { + return ItemType.TYPE_ENCODED_ARRAY_ITEM; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/EncodedValue/AnnotationElement.java b/src/main/java/org/JesusFreke/dexlib/EncodedValue/AnnotationElement.java new file mode 100644 index 00000000..2bbbbc9d --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/EncodedValue/AnnotationElement.java @@ -0,0 +1,49 @@ +/* + * [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.JesusFreke.dexlib.EncodedValue; + +import org.JesusFreke.dexlib.*; + +public class AnnotationElement extends CompositeField { + private Field[] fields; + + private final IndexedItemReference elementName; + private final EncodedValue encodedValue; + + public AnnotationElement(final DexFile dexFile) { + fields = new Field[] { + elementName = new IndexedItemReference(dexFile.StringIdsSection, new Leb128Field()), + encodedValue = new EncodedValue(dexFile) + }; + } + + protected Field[] getFields() { + return fields; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/EncodedValue/AnnotationEncodedValueSubField.java b/src/main/java/org/JesusFreke/dexlib/EncodedValue/AnnotationEncodedValueSubField.java new file mode 100644 index 00000000..91477717 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/EncodedValue/AnnotationEncodedValueSubField.java @@ -0,0 +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.JesusFreke.dexlib.EncodedValue; + +import org.JesusFreke.dexlib.*; + +import java.util.ArrayList; + +public class AnnotationEncodedValueSubField extends CompositeField + implements EncodedValueSubField { + + private final Field[] fields; + private final ArrayList annotationElementList = new ArrayList(); + + private final IndexedItemReference annotationType; + private final ListSizeField annotationCount; + private final FieldListField annotationElements; + + public AnnotationEncodedValueSubField(final DexFile dexFile) { + fields = new Field[] { + annotationType = new IndexedItemReference(dexFile.TypeIdsSection, new Leb128Field()), + annotationCount = new ListSizeField(annotationElementList, new Leb128Field()), + annotationElements = new FieldListField(annotationElementList) { + protected AnnotationElement make() { + return new AnnotationElement(dexFile); + } + } + }; + } + + protected Field[] getFields() { + return fields; + } + + public void setInitialValueArg(byte valueArg) { + //valueArg is ignored for annotations + } + + public byte getValueArg() { + return 0; + } + + public ValueType getValueType() { + return ValueType.VALUE_ANNOTATION; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/EncodedValue/ArrayEncodedValueSubField.java b/src/main/java/org/JesusFreke/dexlib/EncodedValue/ArrayEncodedValueSubField.java new file mode 100644 index 00000000..67218955 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/EncodedValue/ArrayEncodedValueSubField.java @@ -0,0 +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.JesusFreke.dexlib.EncodedValue; + +import org.JesusFreke.dexlib.*; + +import java.util.ArrayList; + +public class ArrayEncodedValueSubField extends CompositeField + implements EncodedValueSubField +{ + + private final Field[] fields; + private final ArrayList encodedValues; + + public ArrayEncodedValueSubField(final DexFile dexFile) { + encodedValues = new ArrayList(); + fields = new Field[] { + new ListSizeField(encodedValues, new Leb128Field()), + new FieldListField(encodedValues) { + protected EncodedValue make() { + return new EncodedValue(dexFile); + } + } + }; + } + + public ArrayEncodedValueSubField(final DexFile dexFile, ArrayList encodedValues) { + this.encodedValues = encodedValues; + + fields = new Field[] { + new ListSizeField(this.encodedValues, new Leb128Field()), + new FieldListField(encodedValues) { + protected EncodedValue make() { + return new EncodedValue(dexFile); + } + } + }; + } + + protected Field[] getFields() { + return fields; + } + + public void setInitialValueArg(byte valueArg) { + //valueArg is ignored for arrays + } + + public byte getValueArg() { + return 0; + } + + public ValueType getValueType() { + return ValueType.VALUE_ARRAY; + } + + public void add(int index, EncodedValue encodedValue) { + encodedValues.add(index, encodedValue); + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/EncodedValue/BoolEncodedValueSubField.java b/src/main/java/org/JesusFreke/dexlib/EncodedValue/BoolEncodedValueSubField.java new file mode 100644 index 00000000..f6078e4e --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/EncodedValue/BoolEncodedValueSubField.java @@ -0,0 +1,62 @@ +/* + * [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.JesusFreke.dexlib.EncodedValue; + +import org.JesusFreke.dexlib.util.Output; +import org.JesusFreke.dexlib.util.Input; + +public class BoolEncodedValueSubField + extends SimpleEncodedValueSubField +{ + public BoolEncodedValueSubField() { + } + + public BoolEncodedValueSubField(boolean value) { + this.value = value; + } + + public void writeTo(Output out) { + } + + public void readFrom(Input in) { + value = (valueArg != 0); + } + + public int place(int offset) { + return offset; + } + + public byte getValueArg() { + return (byte)(value?1:0); + } + + public ValueType getValueType() { + return ValueType.VALUE_BOOLEAN; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/EncodedValue/ByteEncodedValueSubField.java b/src/main/java/org/JesusFreke/dexlib/EncodedValue/ByteEncodedValueSubField.java new file mode 100644 index 00000000..a59e9441 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/EncodedValue/ByteEncodedValueSubField.java @@ -0,0 +1,63 @@ +/* + * [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.JesusFreke.dexlib.EncodedValue; + +import org.JesusFreke.dexlib.util.Output; +import org.JesusFreke.dexlib.util.Input; + +public class ByteEncodedValueSubField + extends SimpleEncodedValueSubField +{ + public ByteEncodedValueSubField() { + } + + public ByteEncodedValueSubField(byte value) { + this.value = value; + } + + public void writeTo(Output out) { + out.writeByte(value); + } + + public void readFrom(Input in) { + value = in.readByte(); + } + + public int place(int offset) { + return offset + 1; + } + + public byte getValueArg() { + return 0; + } + + public ValueType getValueType() { + return ValueType.VALUE_BYTE; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/EncodedValue/CharEncodedValueSubField.java b/src/main/java/org/JesusFreke/dexlib/EncodedValue/CharEncodedValueSubField.java new file mode 100644 index 00000000..ae70b879 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/EncodedValue/CharEncodedValueSubField.java @@ -0,0 +1,65 @@ +/* + * [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.JesusFreke.dexlib.EncodedValue; + +import org.JesusFreke.dexlib.util.Output; +import org.JesusFreke.dexlib.util.EncodedValueUtils; +import org.JesusFreke.dexlib.util.Input; + +public class CharEncodedValueSubField + extends SimpleEncodedValueSubField +{ + public CharEncodedValueSubField() { + } + + public CharEncodedValueSubField(char value) { + this.value = value; + } + + public void writeTo(Output out) { + out.write(EncodedValueUtils.encodeUnsignedIntegralValue(value)); + } + + public void readFrom(Input in) { + value = (char)EncodedValueUtils.decodeUnsignedIntegralValue( + in.readBytes(valueArg + 1)); + } + + public int place(int offset) { + return offset + EncodedValueUtils.getRequiredBytesForUnsignedIntegralValue(value); + } + + public byte getValueArg() { + return EncodedValueUtils.getRequiredBytesForUnsignedIntegralValue(value); + } + + public ValueType getValueType() { + return ValueType.VALUE_CHAR; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/EncodedValue/DoubleEncodedValueSubField.java b/src/main/java/org/JesusFreke/dexlib/EncodedValue/DoubleEncodedValueSubField.java new file mode 100644 index 00000000..49e26db3 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/EncodedValue/DoubleEncodedValueSubField.java @@ -0,0 +1,68 @@ +/* + * [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.JesusFreke.dexlib.EncodedValue; + +import org.JesusFreke.dexlib.util.Output; +import org.JesusFreke.dexlib.util.EncodedValueUtils; +import org.JesusFreke.dexlib.util.Input; + +public class DoubleEncodedValueSubField + extends SimpleEncodedValueSubField +{ + public DoubleEncodedValueSubField() { + } + + public DoubleEncodedValueSubField(double value) { + this.value = value; + } + + public void writeTo(Output out) { + out.write(EncodedValueUtils.encodeRightZeroExtendedValue( + Double.doubleToLongBits(value))); + } + + public void readFrom(Input in) { + value = Double.longBitsToDouble(EncodedValueUtils.decodeRightZeroExtendedValue( + in.readBytes(valueArg + 1))); + } + + public int place(int offset) { + return offset + EncodedValueUtils.getRequiredBytesForRightZeroExtendedValue( + Double.doubleToLongBits(value)); + } + + public byte getValueArg() { + return (byte)(EncodedValueUtils.getRequiredBytesForRightZeroExtendedValue( + Double.doubleToLongBits(value)) - 1); + } + + public ValueType getValueType() { + return ValueType.VALUE_DOUBLE; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/EncodedValue/EncodedIndexedItemReference.java b/src/main/java/org/JesusFreke/dexlib/EncodedValue/EncodedIndexedItemReference.java new file mode 100644 index 00000000..c3a32a52 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/EncodedValue/EncodedIndexedItemReference.java @@ -0,0 +1,100 @@ +/* + * [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.JesusFreke.dexlib.EncodedValue; + +import org.JesusFreke.dexlib.*; +import org.JesusFreke.dexlib.util.Output; +import org.JesusFreke.dexlib.util.Input; +import org.JesusFreke.dexlib.util.EncodedValueUtils; + +/** TODO: it should be possible to somehow use the IndexedItemReference class */ +public class EncodedIndexedItemReference> + extends ItemReference> + implements EncodedValueSubField> { + private int initialValueArg; + private ValueType valueType; + + public EncodedIndexedItemReference(IndexedSection section, ValueType valueType) { + super(section); + this.valueType = valueType; + } + + //TODO: implement support for enum values + public EncodedIndexedItemReference(DexFile dexFile, T item) { + super(dexFile, item); + if (item.getClass() == StringIdItem.class) { + valueType = ValueType.VALUE_STRING; + } else if (item.getClass() == TypeIdItem.class) { + valueType = ValueType.VALUE_TYPE; + } else if (item.getClass() == FieldIdItem.class) { + valueType = ValueType.VALUE_FIELD; + } else if (item.getClass() == MethodIdItem.class) { + valueType = ValueType.VALUE_METHOD; + } + } + + public void writeTo(Output out) { + T item = getReference(); + if (!item.isPlaced()) { + throw new RuntimeException("Trying to write a reference to an item that hasn't been placed."); + } + out.write(EncodedValueUtils.encodeUnsignedIntegralValue(item.getIndex())); + } + + public void readFrom(Input in) { + setReference(((IndexedSection)getSection()).getByIndex( + (int)EncodedValueUtils.decodeUnsignedIntegralValue(in.readBytes(initialValueArg)))); + } + + public int place(int offset) { + T item = getReference(); + if (!item.isPlaced()) { + throw new RuntimeException("Trying to place a reference to an item that hasn't been placed."); + } + return offset + EncodedValueUtils.getRequiredBytesForUnsignedIntegralValue(item.getIndex()); + } + + public T getValue() { + return getReference(); + } + + public void setInitialValueArg(byte valueArg) + { + initialValueArg = valueArg; + } + + public byte getValueArg() { + return EncodedValueUtils.getRequiredBytesForUnsignedIntegralValue(getReference().getIndex()); + } + + public ValueType getValueType() { + return valueType; + } + +} diff --git a/src/main/java/org/JesusFreke/dexlib/EncodedValue/EncodedValue.java b/src/main/java/org/JesusFreke/dexlib/EncodedValue/EncodedValue.java new file mode 100644 index 00000000..14d1e773 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/EncodedValue/EncodedValue.java @@ -0,0 +1,188 @@ +/* + * [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.JesusFreke.dexlib.EncodedValue; + +import org.JesusFreke.dexlib.util.Output; +import org.JesusFreke.dexlib.util.Input; +import org.JesusFreke.dexlib.*; + +public class EncodedValue extends CompositeField { + private final Field[] fields; + + private class ValueTypeArgField implements Field { + private ValueType valueType; + private byte valueArg; + + public ValueTypeArgField() { + } + + public ValueTypeArgField(ValueType valueType) { + this.valueType = valueType; + } + + public void writeTo(Output out) { + + byte value = (byte)(valueType.getMapValue() | (valueArg << 5)); + out.writeByte(value); + } + + public void readFrom(Input in) { + byte value = in.readByte(); + valueType = ValueType.fromByte((byte)(value & 0x1F)); + valueArg = (byte)((value & 0xFF) >>> 5); + } + + public int place(int offset) { + return offset + 1; + } + + public ValueType getValueType() { + return valueType; + } + + public byte getValueArg() { + return valueArg; + } + + public void copyTo(DexFile dexFile, ValueTypeArgField copy) { + copy.valueType = valueType; + copy.valueArg = valueArg; + } + + public int hashCode() { + return valueType.hashCode() * 31 + ((Byte)valueArg).hashCode(); + } + + public boolean equals(Object o) { + if (!(o instanceof ValueTypeArgField)) { + return false; + } + + ValueTypeArgField other = (ValueTypeArgField)o; + return valueType.equals(other.valueType) && (valueArg == other.valueArg); + } + } + + private class EncodedValueSubFieldWrapper implements Field { + private final DexFile dexFile; + private EncodedValueSubField subField; + + public EncodedValueSubFieldWrapper(DexFile dexFile) { + this.dexFile = dexFile; + } + + public EncodedValueSubFieldWrapper(DexFile dexFile, EncodedValueSubField subField) { + this.dexFile = dexFile; + this.subField = subField; + } + + public void writeTo(Output out) { + subField.writeTo(out); + } + + public void readFrom(Input in) { + subField = EncodedValueSubFieldFactory.makeEncodedValueField(dexFile, getValueType()); + subField.readFrom(in); + } + + public int place(int offset) { + return subField.place(offset); + } + + public EncodedValueSubField getEncodedValueSubField() { + return subField; + } + + public void copyTo(DexFile dexFile, EncodedValueSubFieldWrapper copy) { + EncodedValueSubField fieldCopy = EncodedValueSubFieldFactory.makeEncodedValueField(dexFile, getValueType()); + copy.subField = fieldCopy; + + //both fields should be the same type because they were both made with the a call to + //EncodedValueSubFieldFactory.makeEncodedValueField using the same value type. + subField.copyTo(dexFile, fieldCopy); + } + + public int hashCode() { + return subField.hashCode(); + } + + public boolean equals(Object o) { + if (!(o instanceof EncodedValueSubFieldWrapper)) { + return false; + } + + EncodedValueSubFieldWrapper other = (EncodedValueSubFieldWrapper)o; + return subField.equals(other.subField); + } + } + + private final ValueTypeArgField valueTypeArg; + private final EncodedValueSubFieldWrapper encodedValue; + + public EncodedValue(final DexFile dexFile) { + fields = new Field[] { + valueTypeArg = new ValueTypeArgField(), + encodedValue = new EncodedValueSubFieldWrapper(dexFile) + }; + } + + public EncodedValue(final DexFile dexFile, EncodedValueSubField subField) { + fields = new Field[] { + valueTypeArg = new ValueTypeArgField(subField.getValueType()), + encodedValue = new EncodedValueSubFieldWrapper(dexFile, subField) + }; + } + + public int place(int offset) { + offset = valueTypeArg.place(offset); + int encodedValueStartOffset = offset; + int ret = encodedValue.place(offset); + + int encodedValueLength = ret - encodedValueStartOffset; + if (encodedValueLength < 2 || valueTypeArg.valueType == ValueType.VALUE_ARRAY || + valueTypeArg.valueType == ValueType.VALUE_ANNOTATION) { + valueTypeArg.valueArg = 0; + } else { + valueTypeArg.valueArg = (byte)(encodedValueLength - 1); + } + return ret; + } + + public ValueType getValueType() { + return valueTypeArg.getValueType(); + } + + public byte getValueArg() { + return valueTypeArg.getValueArg(); + } + + protected Field[] getFields() { + return fields; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/EncodedValue/EncodedValueSubField.java b/src/main/java/org/JesusFreke/dexlib/EncodedValue/EncodedValueSubField.java new file mode 100644 index 00000000..9ab1b126 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/EncodedValue/EncodedValueSubField.java @@ -0,0 +1,38 @@ +/* + * [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.JesusFreke.dexlib.EncodedValue; + +import org.JesusFreke.dexlib.Field; + +public interface EncodedValueSubField extends Field +{ + public void setInitialValueArg(byte valueArg); + public byte getValueArg(); + public ValueType getValueType(); +} diff --git a/src/main/java/org/JesusFreke/dexlib/EncodedValue/EncodedValueSubFieldFactory.java b/src/main/java/org/JesusFreke/dexlib/EncodedValue/EncodedValueSubFieldFactory.java new file mode 100644 index 00000000..9ae0f401 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/EncodedValue/EncodedValueSubFieldFactory.java @@ -0,0 +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.JesusFreke.dexlib.EncodedValue; + +import org.JesusFreke.dexlib.*; + + +public abstract class EncodedValueSubFieldFactory +{ + public static EncodedValueSubField makeEncodedValueField(DexFile dexFile, ValueType valueType) { + switch (valueType) { + case VALUE_NULL: + return new NullEncodedValueSubField(); + case VALUE_BOOLEAN: + return new BoolEncodedValueSubField(); + case VALUE_BYTE: + return new ByteEncodedValueSubField(); + case VALUE_CHAR: + return new CharEncodedValueSubField(); + case VALUE_SHORT: + return new ShortEncodedValueSubField(); + case VALUE_INT: + return new IntEncodedValueSubField(); + case VALUE_LONG: + return new LongEncodedValueSubField(); + case VALUE_FLOAT: + return new FloatEncodedValueSubField(); + case VALUE_DOUBLE: + return new DoubleEncodedValueSubField(); + case VALUE_STRING: + return new EncodedIndexedItemReference(dexFile.StringIdsSection, valueType); + case VALUE_TYPE: + return new EncodedIndexedItemReference(dexFile.TypeIdsSection, valueType); + case VALUE_FIELD: + return new EncodedIndexedItemReference(dexFile.FieldIdsSection, valueType); + case VALUE_ENUM: + return new EncodedIndexedItemReference(dexFile.FieldIdsSection, valueType); + case VALUE_METHOD: + return new EncodedIndexedItemReference(dexFile.MethodIdsSection, valueType); + case VALUE_ARRAY: + return new ArrayEncodedValueSubField(dexFile); + case VALUE_ANNOTATION: + return new AnnotationEncodedValueSubField(dexFile); + default: + throw new RuntimeException("Invalid ValueType"); + } + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/EncodedValue/FloatEncodedValueSubField.java b/src/main/java/org/JesusFreke/dexlib/EncodedValue/FloatEncodedValueSubField.java new file mode 100644 index 00000000..f58d2624 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/EncodedValue/FloatEncodedValueSubField.java @@ -0,0 +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.JesusFreke.dexlib.EncodedValue; + +import org.JesusFreke.dexlib.util.Output; +import org.JesusFreke.dexlib.util.EncodedValueUtils; +import org.JesusFreke.dexlib.util.Input; + +public class FloatEncodedValueSubField + extends SimpleEncodedValueSubField +{ + public FloatEncodedValueSubField() { + } + + public FloatEncodedValueSubField(float value) { + this.value = value; + } + public void writeTo(Output out) { + out.write(EncodedValueUtils.encodeRightZeroExtendedValue( + ((long)Float.floatToIntBits(value)) << 32)); + } + + public void readFrom(Input in) { + long longValue = EncodedValueUtils.decodeRightZeroExtendedValue(in.readBytes(valueArg + 1)); + value = Float.intBitsToFloat((int)((longValue >> 32) & 0xFFFFFFFF)); + } + + public int place(int offset) { + return offset + EncodedValueUtils.getRequiredBytesForRightZeroExtendedValue( + ((long)Float.floatToRawIntBits(value)) << 32); + } + + public byte getValueArg() { + return (byte)(EncodedValueUtils.getRequiredBytesForRightZeroExtendedValue( + Float.floatToIntBits(value)) - 1); + } + + public ValueType getValueType() { + return ValueType.VALUE_LONG; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/EncodedValue/IntEncodedValueSubField.java b/src/main/java/org/JesusFreke/dexlib/EncodedValue/IntEncodedValueSubField.java new file mode 100644 index 00000000..418fa492 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/EncodedValue/IntEncodedValueSubField.java @@ -0,0 +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.JesusFreke.dexlib.EncodedValue; + +import org.JesusFreke.dexlib.util.Output; +import org.JesusFreke.dexlib.util.EncodedValueUtils; +import org.JesusFreke.dexlib.util.Input; + +public class IntEncodedValueSubField + extends SimpleEncodedValueSubField +{ + public IntEncodedValueSubField() { + } + + public IntEncodedValueSubField(int value) { + this.value = value; + } + + public void writeTo(Output out) { + out.write(EncodedValueUtils.encodeSignedIntegralValue(value)); + } + + public void readFrom(Input in) { + value = (int)EncodedValueUtils.decodeSignedIntegralValue(in.readBytes(valueArg+1)); + } + + public int place(int offset) { + return offset + EncodedValueUtils.getRequiredBytesForSignedIntegralValue(value); + } + + public byte getValueArg() { + return (byte)(EncodedValueUtils.getRequiredBytesForSignedIntegralValue(value) - 1); + } + + public ValueType getValueType() { + return ValueType.VALUE_INT; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/EncodedValue/LongEncodedValueSubField.java b/src/main/java/org/JesusFreke/dexlib/EncodedValue/LongEncodedValueSubField.java new file mode 100644 index 00000000..9f4f95ac --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/EncodedValue/LongEncodedValueSubField.java @@ -0,0 +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.JesusFreke.dexlib.EncodedValue; + +import org.JesusFreke.dexlib.util.Output; +import org.JesusFreke.dexlib.util.EncodedValueUtils; +import org.JesusFreke.dexlib.util.Input; + +public class LongEncodedValueSubField + extends SimpleEncodedValueSubField +{ + public LongEncodedValueSubField() { + } + + public LongEncodedValueSubField(long value) { + this.value = value; + } + + public void writeTo(Output out) { + out.write(EncodedValueUtils.encodeSignedIntegralValue(value)); + } + + public void readFrom(Input in) { + value = EncodedValueUtils.decodeSignedIntegralValue(in.readBytes(valueArg+1)); + } + + public int place(int offset) { + return offset + EncodedValueUtils.getRequiredBytesForSignedIntegralValue(value); + } + + public byte getValueArg() { + return (byte)(EncodedValueUtils.getRequiredBytesForSignedIntegralValue(value) - 1); + } + + public ValueType getValueType() { + return ValueType.VALUE_LONG; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/EncodedValue/NullEncodedValueSubField.java b/src/main/java/org/JesusFreke/dexlib/EncodedValue/NullEncodedValueSubField.java new file mode 100644 index 00000000..0b899835 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/EncodedValue/NullEncodedValueSubField.java @@ -0,0 +1,58 @@ +/* + * [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.JesusFreke.dexlib.EncodedValue; + +import org.JesusFreke.dexlib.util.Output; +import org.JesusFreke.dexlib.util.Input; + +public class NullEncodedValueSubField + extends SimpleEncodedValueSubField +{ + public NullEncodedValueSubField() { + } + + public void writeTo(Output out) { + } + + public void readFrom(Input in) { + value = null; + } + + public int place(int offset) { + return offset; + } + + public byte getValueArg() { + return 0; + } + + public ValueType getValueType() { + return ValueType.VALUE_NULL; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/EncodedValue/ShortEncodedValueSubField.java b/src/main/java/org/JesusFreke/dexlib/EncodedValue/ShortEncodedValueSubField.java new file mode 100644 index 00000000..2f098ac8 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/EncodedValue/ShortEncodedValueSubField.java @@ -0,0 +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.JesusFreke.dexlib.EncodedValue; + +import org.JesusFreke.dexlib.util.Output; +import org.JesusFreke.dexlib.util.EncodedValueUtils; +import org.JesusFreke.dexlib.util.Input; + +public class ShortEncodedValueSubField + extends SimpleEncodedValueSubField +{ + public ShortEncodedValueSubField() { + } + + public ShortEncodedValueSubField(short value) { + this.value = value; + } + + public void writeTo(Output out) { + out.write(EncodedValueUtils.encodeSignedIntegralValue(value)); + } + + public void readFrom(Input in) { + value = (short)EncodedValueUtils.decodeSignedIntegralValue(in.readBytes(valueArg+1)); + } + + public int place(int offset) { + return offset + EncodedValueUtils.getRequiredBytesForSignedIntegralValue(value); + } + + public byte getValueArg() { + return (byte)(EncodedValueUtils.getRequiredBytesForSignedIntegralValue(value) - 1); + } + + public ValueType getValueType() { + return ValueType.VALUE_SHORT; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/EncodedValue/SimpleEncodedValueSubField.java b/src/main/java/org/JesusFreke/dexlib/EncodedValue/SimpleEncodedValueSubField.java new file mode 100644 index 00000000..613a4181 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/EncodedValue/SimpleEncodedValueSubField.java @@ -0,0 +1,68 @@ +/* + * [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.JesusFreke.dexlib.EncodedValue; + +import org.JesusFreke.dexlib.DexFile; + +public abstract class SimpleEncodedValueSubField> implements EncodedValueSubField +{ + protected V value; + protected byte valueArg = 0; + + public V getValue() { + return value; + } + + public void setInitialValueArg(byte valueArg) { + this.valueArg = valueArg; + } + + public void copyTo(DexFile dexFile, T copy) { + copy.value = value; + } + + public int hashCode() { + if (value == null) { + return 0; + } + return value.hashCode(); + } + + public boolean equals(Object o) { + if (!(o instanceof SimpleEncodedValueSubField)) { + return false; + } + + SimpleEncodedValueSubField other = (SimpleEncodedValueSubField)o; + if (value == null) { + return other.value == null; + } + return value.equals(other.value); + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/EncodedValue/ValueType.java b/src/main/java/org/JesusFreke/dexlib/EncodedValue/ValueType.java new file mode 100644 index 00000000..f75e4c76 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/EncodedValue/ValueType.java @@ -0,0 +1,87 @@ +/* + * [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.JesusFreke.dexlib.EncodedValue; + +import java.util.TreeMap; + +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 an ItemType by ordinal + */ + private final static TreeMap valueTypeIntegerMap; + + /** builds the itemTypeIntegerMap object */ + static { + valueTypeIntegerMap = new TreeMap(); + + for (ValueType valueType : ValueType.values()) { + valueTypeIntegerMap.put(valueType.getMapValue(), valueType); + } + } + + private final byte mapValue; + + private ValueType(byte mapValue) { + this.mapValue = mapValue; + } + + public byte getMapValue() { + return mapValue; + } + + /** + * Converts a byte value to the corresponding ValueType enum value, + * or null if the value isn't a valid ValueType value + * + * @param valueType the int 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/src/main/java/org/JesusFreke/dexlib/Field.java b/src/main/java/org/JesusFreke/dexlib/Field.java new file mode 100644 index 00000000..b53c31a5 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/Field.java @@ -0,0 +1,39 @@ +/* + * [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.JesusFreke.dexlib; + +import org.JesusFreke.dexlib.util.Output; +import org.JesusFreke.dexlib.util.Input; + +public interface Field { + public void writeTo(Output out); + public void readFrom(Input in); + public int place(int offset); + public void copyTo(DexFile dexFile, T copy); +} diff --git a/src/main/java/org/JesusFreke/dexlib/FieldIdItem.java b/src/main/java/org/JesusFreke/dexlib/FieldIdItem.java new file mode 100644 index 00000000..f628c95a --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/FieldIdItem.java @@ -0,0 +1,96 @@ +/* + * [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.JesusFreke.dexlib; + +import org.JesusFreke.dexlib.ItemType; + +public class FieldIdItem extends IndexedItem { + private final Field[] fields; + + private final IndexedItemReference classType; + private final IndexedItemReference fieldType; + private final IndexedItemReference fieldName; + + public FieldIdItem(DexFile dexFile, int index) { + super(index); + fields = new Field[] { + classType = new IndexedItemReference(dexFile.TypeIdsSection, new ShortIntegerField()), + fieldType = new IndexedItemReference(dexFile.TypeIdsSection, new ShortIntegerField()), + fieldName = new IndexedItemReference(dexFile.StringIdsSection, new IntegerField()) + }; + } + + public FieldIdItem(DexFile dexFile, TypeIdItem classType, StringIdItem fieldName, TypeIdItem fieldType) { + super(-1); + fields = new Field[] { + this.classType = new IndexedItemReference(dexFile, classType, new ShortIntegerField()), + this.fieldType = new IndexedItemReference(dexFile, fieldType, new ShortIntegerField()), + this.fieldName = new IndexedItemReference(dexFile, fieldName, new IntegerField()) + }; + } + + public FieldIdItem(DexFile dexFile, TypeIdItem classType, String fieldName, TypeIdItem fieldType) { + this(dexFile, classType, new StringIdItem(dexFile, fieldName), fieldType); + } + + protected int getAlignment() { + return 4; + } + + protected Field[] getFields() { + return fields; + } + + public ItemType getItemType() { + return ItemType.TYPE_FIELD_ID_ITEM; + } + + public String toString() { + return classType.toString() + " - " + fieldName.toString(); + } + + 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); + + } + + public TypeIdItem getFieldType() { + return fieldType.getReference(); + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/FieldListField.java b/src/main/java/org/JesusFreke/dexlib/FieldListField.java new file mode 100644 index 00000000..fc95a962 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/FieldListField.java @@ -0,0 +1,105 @@ +/* + * [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.JesusFreke.dexlib; + +import org.JesusFreke.dexlib.util.Output; +import org.JesusFreke.dexlib.util.Input; + +import java.util.ArrayList; + +public abstract class FieldListField implements Field> { + private final ArrayList list; + + public FieldListField(ArrayList list) { + this.list = list; + } + + public void writeTo(Output out) { + for (Field field: list) { + field.writeTo(out); + } + } + + public void readFrom(Input in) { + for (int i = 0; i < list.size(); i++) { + T field = list.get(i); + + if (field == null) { + field = make(); + list.set(i, field); + } + field.readFrom(in); + } + } + + protected abstract T make(); + + public int place(int offset) { + for (Field field: list) { + offset = field.place(offset); + } + return offset; + } + + public void copyTo(DexFile dexFile, FieldListField copy) { + copy.list.clear(); + copy.list.ensureCapacity(list.size()); + for (int i = 0; i < list.size(); i++) { + T fieldCopy = copy.make(); + list.get(i).copyTo(dexFile, fieldCopy); + copy.list.add(fieldCopy); + } + } + + public int hashCode() { + int h = 1; + for (int i = 0; i < list.size(); i++) { + h = h * 31 + list.get(i).hashCode(); + } + return h; + } + + public boolean equals(Object o) { + if (!(o instanceof FieldListField)) { + return false; + } + + FieldListField other = (FieldListField)o; + if (list.size() != other.list.size()) { + return false; + } + + for (int i = 0; i < list.size(); i++) { + if (!list.get(i).equals(other.list.get(i))) { + return false; + } + } + return true; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/FixedByteArrayField.java b/src/main/java/org/JesusFreke/dexlib/FixedByteArrayField.java new file mode 100644 index 00000000..54cb7019 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/FixedByteArrayField.java @@ -0,0 +1,66 @@ +/* + * [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.JesusFreke.dexlib; + +import org.JesusFreke.dexlib.util.Output; +import org.JesusFreke.dexlib.util.Input; +import org.JesusFreke.dexlib.util.ByteArray; + +public class FixedByteArrayField implements Field { + protected byte[] value; + + public FixedByteArrayField(int size) { + value = new byte[size]; + } + + public FixedByteArrayField(byte[] bytes) { + this.value = bytes.clone(); + } + + public FixedByteArrayField(ByteArray byteArray) { + value = new byte[byteArray.size()]; + byteArray.getBytes(value, 0); + } + + public void writeTo(Output out) { + out.write(value); + } + + public void readFrom(Input in) { + in.read(value); + } + + public int place(int offset) { + return offset + value.length; + } + + public void copyTo(DexFile dexFile, FixedByteArrayField copy) { + copy.value = value.clone(); + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/HeaderItem.java b/src/main/java/org/JesusFreke/dexlib/HeaderItem.java new file mode 100644 index 00000000..e23252f0 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/HeaderItem.java @@ -0,0 +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.JesusFreke.dexlib; + +import org.JesusFreke.dexlib.ItemType; +import org.JesusFreke.dexlib.util.Output; + +import java.io.UnsupportedEncodingException; + +public class HeaderItem extends IndexedItem { + /** + * non-null; the file format magic number, represented as the + * low-order bytes of a string + */ + private static final String MAGIC = "dex\n035" + '\0'; + + /** size of this section, in bytes */ + private static final int HEADER_SIZE = 0x70; + + /** the endianness tag */ + private static final int ENDIAN_TAG = 0x12345678; + + private final Field[] fields; + + protected Field[] getFields() { + return fields; + } + + private final FixedByteArrayField magic; + private final IntegerField checksum; + private final FixedByteArrayField signature; + private final IntegerField fileSize; + private final IntegerField headerSize; + private final IntegerField endianTag; + private final IntegerField linkSize; + private final IntegerField linkOff; + private final IntegerField mapOff; + private final SectionHeaderInfo StringIdsInfo; + private final SectionHeaderInfo TypeIdsInfo; + private final SectionHeaderInfo ProtoIdsInfo; + private final SectionHeaderInfo FieldIdsInfo; + private final SectionHeaderInfo MethodIdsInfo; + private final SectionHeaderInfo ClassDefsInfo; + private final IntegerField dataSize; + private final IntegerField dataOff; + + public HeaderItem(final DexFile file, int index) throws UnsupportedEncodingException { + super(index); + + fields = new Field[] { + magic = new FixedByteArrayField(MAGIC.getBytes("US-ASCII")), + checksum = new IntegerField() { + public void writeTo(Output out) { + cacheValue(0); + super.writeTo(out); + } + }, + signature = new FixedByteArrayField(20) { + public void writeTo(Output out) { + for (int i = 0; i < value.length; i++) { + value[i] = 0; + } + super.writeTo(out); + } + }, + fileSize = new IntegerField() { + public void writeTo(Output out) { + cacheValue(file.getFileSize()); + super.writeTo(out); + } + }, + headerSize = new IntegerField(HEADER_SIZE), + endianTag = new IntegerField(ENDIAN_TAG), + linkSize = new IntegerField(0), + linkOff = new IntegerField(0), + mapOff = new IntegerField() { + public void writeTo(Output out) { + cacheValue(file.MapSection.getOffset()); + super.writeTo(out); + } + }, + StringIdsInfo = new SectionHeaderInfo() { + protected Section getSection() { + return file.StringIdsSection; + } + }, + TypeIdsInfo = new SectionHeaderInfo() { + protected Section getSection() { + return file.TypeIdsSection; + } + }, + ProtoIdsInfo = new SectionHeaderInfo() { + protected Section getSection() { + return file.ProtoIdsSection; + } + }, + FieldIdsInfo = new SectionHeaderInfo() { + protected Section getSection() { + return file.FieldIdsSection; + } + }, + MethodIdsInfo = new SectionHeaderInfo() { + protected Section getSection() { + return file.MethodIdsSection; + } + }, + ClassDefsInfo = new SectionHeaderInfo() { + protected Section getSection() { + return file.ClassDefsSection; + } + }, + dataSize = new IntegerField() { + public void writeTo(Output out) { + cacheValue(file.getDataSize()); + super.writeTo(out); + } + }, + dataOff = new IntegerField() { + public void writeTo(Output out) { + cacheValue(file.getDataOffset()); + super.writeTo(out); + } + } + }; + } + + public int getMapOffset() { + return mapOff.getCachedValue(); + } + + protected int getAlignment() { + return 4; + } + + public ItemType getItemType() { + return ItemType.TYPE_HEADER_ITEM; + } + + public int compareTo(HeaderItem o) { + //there is only 1 header item + return 0; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/IndexedItem.java b/src/main/java/org/JesusFreke/dexlib/IndexedItem.java new file mode 100644 index 00000000..895d948d --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/IndexedItem.java @@ -0,0 +1,46 @@ +/* + * [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.JesusFreke.dexlib; + +public abstract class IndexedItem extends Item implements Comparable { + private int index; + + protected IndexedItem(int index) { + this.index = index; + } + + public int place(int index, int offset) { + this.index = index; + return super.place(index, offset); + } + + public int getIndex() { + return index; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/IndexedItemReference.java b/src/main/java/org/JesusFreke/dexlib/IndexedItemReference.java new file mode 100644 index 00000000..85a2e254 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/IndexedItemReference.java @@ -0,0 +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.JesusFreke.dexlib; + +import org.JesusFreke.dexlib.util.Output; +import org.JesusFreke.dexlib.util.Input; + +public class IndexedItemReference> extends + ItemReference> implements Comparable> { + private final CachedIntegerValueField underlyingField; + + public IndexedItemReference(IndexedSection section, CachedIntegerValueField underlyingField) { + super(section); + this.underlyingField = underlyingField; + } + + public IndexedItemReference(DexFile dexFile, T item, CachedIntegerValueField underlyingField) { + super(dexFile, item); + this.underlyingField = underlyingField; + } + + public void writeTo(Output out) { + T item = getReference(); + if (item != null && !item.isPlaced()) { + throw new RuntimeException("Trying to write a reference to an item that hasn't been placed."); + } + underlyingField.writeTo(out); + } + + public void readFrom(Input in) { + underlyingField.readFrom(in); + if (underlyingField.getCachedValue() != -1) { + setReference(getSection().getByIndex(underlyingField.getCachedValue())); + } + } + + public IndexedSection getSection() { + return (IndexedSection)super.getSection(); + } + + public int place(int offset) { + if (getReference() != null) { + underlyingField.cacheValue(getReference().getIndex()); + } else { + underlyingField.cacheValue(-1); + } + return underlyingField.place(offset); + } + + public int compareTo(IndexedItemReference o) { + return getReference().compareTo(o.getReference()); + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/IndexedSection.java b/src/main/java/org/JesusFreke/dexlib/IndexedSection.java new file mode 100644 index 00000000..cc0579e2 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/IndexedSection.java @@ -0,0 +1,88 @@ +/* + * [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.JesusFreke.dexlib; + +import org.JesusFreke.dexlib.util.Input; + +import java.util.Collections; + +public abstract class IndexedSection> extends Section { + public IndexedSection() { + } + + public T getByIndex(int index) { + for (int i = items.size(); i <= index; i++) { + items.add(null); + } + T item = items.get(index); + if (item == null) { + item = make(index); + items.set(index, item); + } + return item; + } + + public void readFrom(int size, Input in) { + super.setSize(size); + + for (int i = 0; i < size(); i++) { + T item = getByIndex(i); + item.readFrom(in); + in.alignTo(item.getAlignment()); + } + } + + protected abstract T make(int index); + + public T intern(DexFile dexFile, T item) { + T itemToReturn = getInternedItem(item); + + if (itemToReturn == null) { + /** + * Make a new item at the end of this section, and copy the fields + * to the new item + */ + itemToReturn = getByIndex(size()); + item.copyTo(dexFile, itemToReturn); + uniqueItems.put(itemToReturn, itemToReturn); + } + + return itemToReturn; + } + + protected void sortSection() { + Collections.sort(items); + } + + public int place(int offset) { + sortSection(); + + return super.place(offset); + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/IntegerField.java b/src/main/java/org/JesusFreke/dexlib/IntegerField.java new file mode 100644 index 00000000..d04cf694 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/IntegerField.java @@ -0,0 +1,70 @@ +/* + * [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.JesusFreke.dexlib; + +import org.JesusFreke.dexlib.util.Output; +import org.JesusFreke.dexlib.util.Input; + +public class IntegerField extends CachedIntegerValueField { + protected int value = 0; + + public IntegerField() { + } + + public IntegerField(int value) { + this.value = value; + } + + public void writeTo(Output out) { + out.writeInt(value); + } + + public void readFrom(Input in) { + value = in.readInt(); + } + + public int place(int offset) { + return offset + 4; + } + + /** + * This method returns the integer value that has been cached. This + * value is either the value that the field was constructed with, the + * value that was read via readFrom, or the value that was + * cached when place was called + * @return the cached value + */ + public int getCachedValue() { + return value; + } + + public void cacheValue(int value) { + this.value = value; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/Item.java b/src/main/java/org/JesusFreke/dexlib/Item.java new file mode 100644 index 00000000..f80a1ff7 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/Item.java @@ -0,0 +1,142 @@ +/* + * [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.JesusFreke.dexlib; + +import org.JesusFreke.dexlib.util.Input; +import org.JesusFreke.dexlib.util.Output; +import org.JesusFreke.dexlib.ItemType; + +public abstract class Item { + private int offset = -1; + + protected Item() { + } + + protected Item(int offset) { + this.offset = offset; + } + + public boolean isPlaced() { + return offset > -1; + } + + public void unplace() { + offset = -1; + } + + public int place(int index, int offset) { + offset = alignOffset(offset); + + //TODO: take out + System.out.println("Placing item type " + getItemType().getTypeName() + " at offset " + ((Integer)offset).toString()); + + this.offset = offset; + + Field[] fields = getFields(); + + for (Field field: fields) { + offset = field.place(offset); + } + return offset; + } + + public void readFrom(Input in) { + for (Field field: getFields()) { + field.readFrom(in); + } + } + + public void writeTo(Output out) { + out.alignTo(getAlignment()); + + //TODO: take out + System.out.println("Writing item type " + getItemType().getTypeName() + " at offset " + ((Integer)out.getCursor()).toString()); + + if (out.getCursor() != offset) { + throw new RuntimeException("Item is being written somewhere other than where it was placed"); + } + for (Field field: getFields()) { + field.writeTo(out); + } + } + + protected abstract int getAlignment(); + + protected int alignOffset(int offset) { + int mask = getAlignment() - 1; + + return (offset + mask) & ~mask; + } + + protected int getOffset() { + return offset; + } + + protected abstract Field[] getFields(); + + public abstract ItemType getItemType(); + + public void copyTo(DexFile dexFile, T copy) { + Field[] fields = getFields(); + Field[] fieldsCopy = copy.getFields(); + for (int i = 0; i < fields.length; i++) { + fields[i].copyTo(dexFile, fieldsCopy[i]); + } + } + + public int hashCode() { + int h = 1; + for (Field field: getFields()) { + h = h*31 + field.hashCode(); + } + return h; + } + + public boolean equals(Object o) { + if (!(o instanceof Item)) { + return false; + } + + Item other = (Item)o; + Field[] fields = getFields(); + Field[] otherFields = other.getFields(); + + if (fields.length != otherFields.length) { + return false; + } + + for (int i = 0; i < fields.length; i++) { + if (!fields[i].equals(otherFields[i])) { + return false; + } + } + + return true; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/ItemReference.java b/src/main/java/org/JesusFreke/dexlib/ItemReference.java new file mode 100644 index 00000000..8638fd08 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/ItemReference.java @@ -0,0 +1,87 @@ +/* + * [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.JesusFreke.dexlib; + +public abstract class ItemReference, S extends ItemReference> implements Field { + private T item = null; + private Section section; + + public ItemReference(Section section) { + this.section = section; + } + + public ItemReference(DexFile dexFile, T item) { + if (item != null) { + section = dexFile.getSectionForItem(item); + this.item = item; + } + } + + public T getReference() { + return item; + } + + protected void setReference(T item) { + this.item = item; + } + + public Section getSection() { + return section; + } + + public void copyTo(DexFile dexFile, S copy) { + T referencedItem = getReference(); + if (referencedItem == null) { + return; + } + Section section = copy.getSection(); + T copiedItem = section.intern(dexFile, referencedItem); + copy.setReference(copiedItem); + } + + public int hashCode() { + if (item == null) { + return 0; + } + return item.hashCode(); + } + + public boolean equals(Object o) { + if (!(o instanceof ItemReference)) { + return false; + } + + ItemReference other = (ItemReference)o; + if (item != null) { + return item.equals(other.item); + } else { + return other.item == null; + } + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/ItemType.java b/src/main/java/org/JesusFreke/dexlib/ItemType.java new file mode 100644 index 00000000..33d4a0de --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/ItemType.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.JesusFreke.dexlib; + +import java.util.TreeMap; + +/** + * Enumeration of all the top-level item types. + */ +public enum ItemType { + TYPE_HEADER_ITEM( 0x0000, "header_item"), + TYPE_STRING_ID_ITEM( 0x0001, "string_id_item"), + TYPE_TYPE_ID_ITEM( 0x0002, "type_id_item"), + TYPE_PROTO_ID_ITEM( 0x0003, "proto_id_item"), + TYPE_FIELD_ID_ITEM( 0x0004, "field_id_item"), + TYPE_METHOD_ID_ITEM( 0x0005, "method_id_item"), + TYPE_CLASS_DEF_ITEM( 0x0006, "class_def_item"), + TYPE_MAP_LIST( 0x1000, "map_list"), + TYPE_TYPE_LIST( 0x1001, "type_list"), + TYPE_ANNOTATION_SET_REF_LIST( 0x1002, "annotation_set_ref_list"), + TYPE_ANNOTATION_SET_ITEM( 0x1003, "annotation_set_item"), + TYPE_CLASS_DATA_ITEM( 0x2000, "class_data_item"), + TYPE_CODE_ITEM( 0x2001, "code_item"), + TYPE_STRING_DATA_ITEM( 0x2002, "string_data_item"), + TYPE_DEBUG_INFO_ITEM( 0x2003, "debug_info_item"), + TYPE_ANNOTATION_ITEM( 0x2004, "annotation_item"), + TYPE_ENCODED_ARRAY_ITEM( 0x2005, "encoded_array_item"), + TYPE_ANNOTATIONS_DIRECTORY_ITEM(0x2006, "annotations_directory_item"), + TYPE_MAP_ITEM( -1, "map_item"), + TYPE_TYPE_ITEM( -1, "type_item"), + TYPE_EXCEPTION_HANDLER_ITEM( -1, "exception_handler_item"), + TYPE_ANNOTATION_SET_REF_ITEM( -1, "annotation_set_ref_item"); + + /** A map to facilitate looking up an ItemType by ordinal */ + private final static TreeMap itemTypeIntegerMap; + + /** builds the itemTypeIntegerMap object */ + static { + itemTypeIntegerMap = new TreeMap(); + + for (ItemType itemType: ItemType.values()) { + itemTypeIntegerMap.put(itemType.getMapValue(), itemType); + } + } + + /** value when represented in a MapItem */ + private final int mapValue; + + /** non-null; name of the type */ + private final String typeName; + + /** + * Constructs an instance. + * + * @param mapValue value when represented in a MapItem + * @param typeName non-null; name of the type + */ + private ItemType(int mapValue, String typeName) { + this.mapValue = mapValue; + this.typeName = typeName; + } + + /** + * Gets the map value. + * + * @return the map value + */ + public int getMapValue() { + return mapValue; + } + + /** + * Gets the type name. + * + * @return non-null; the type name + */ + public String getTypeName() { + return typeName; + } + + /** + * Converts an int value to the corresponding ItemType enum value, + * or null if the value isn't a valid ItemType value + * + * @param itemType the int value to convert to an ItemType + * @return the ItemType enum value corresponding to itemType, or null + * if not a valid ItemType value + */ + public static ItemType fromInt(int itemType) { + return itemTypeIntegerMap.get(itemType); + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/Leb128Field.java b/src/main/java/org/JesusFreke/dexlib/Leb128Field.java new file mode 100644 index 00000000..5993771e --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/Leb128Field.java @@ -0,0 +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.JesusFreke.dexlib; + +import org.JesusFreke.dexlib.util.Output; +import org.JesusFreke.dexlib.util.Input; +import org.JesusFreke.dexlib.util.Leb128Utils; + +public class Leb128Field extends CachedIntegerValueField { + protected int value; + + public Leb128Field() { + } + + public Leb128Field(int value) { + this.value = value; + } + + public void writeTo(Output out) { + out.writeUnsignedLeb128(value); + } + + public void readFrom(Input in) { + value = in.readUnsignedLeb128(); + } + + public int place(int offset) { + return offset + Leb128Utils.unsignedLeb128Size(value); + } + + public int getCachedValue() { + return value; + } + + public void cacheValue(int value) { + this.value = value; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/Leb128p1Field.java b/src/main/java/org/JesusFreke/dexlib/Leb128p1Field.java new file mode 100644 index 00000000..214d64e3 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/Leb128p1Field.java @@ -0,0 +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.JesusFreke.dexlib; + +import org.JesusFreke.dexlib.util.Output; +import org.JesusFreke.dexlib.util.Input; +import org.JesusFreke.dexlib.util.Leb128Utils; + +public class Leb128p1Field extends CachedIntegerValueField { + protected int value; + + public Leb128p1Field() { + } + + public Leb128p1Field(int value) { + this.value = value; + } + + public void writeTo(Output out) { + out.writeUnsignedLeb128(value + 1); + } + + public void readFrom(Input in) { + value = in.readUnsignedLeb128() - 1; + } + + public int place(int offset) { + return offset + Leb128Utils.unsignedLeb128Size(value + 1); + } + + public int getCachedValue() { + return value; + } + + public void cacheValue(int value) { + this.value = value; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/ListSizeField.java b/src/main/java/org/JesusFreke/dexlib/ListSizeField.java new file mode 100644 index 00000000..ce84d5ee --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/ListSizeField.java @@ -0,0 +1,90 @@ +/* + * [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.JesusFreke.dexlib; + +import org.JesusFreke.dexlib.util.Input; +import org.JesusFreke.dexlib.util.Output; + +import java.util.ArrayList; + +public class ListSizeField extends CachedIntegerValueField { + private final ArrayList list; + private final CachedIntegerValueField underlyingField; + + public ListSizeField(ArrayList list, CachedIntegerValueField underlyingField) { + this.list = list; + this.underlyingField = underlyingField; + } + + public void writeTo(Output out) { + underlyingField.writeTo(out); + } + + public void readFrom(Input in) { + underlyingField.readFrom(in); + /** the absolute value operation is needed for the case when a list sized is + * encoded as the absolute value of a signed integer + */ + int listSize = Math.abs(underlyingField.getCachedValue()); + + list.clear(); + list.ensureCapacity(listSize); + for (int i = 0; i < listSize; i++) { + list.add(null); + } + } + + public int place(int offset) { + underlyingField.cacheValue(list.size()); + return underlyingField.place(offset); + } + + public int getCachedValue() { + return underlyingField.getCachedValue(); + } + + public void cacheValue(int value) { + underlyingField.cacheValue(value); + } + + public int hashCode() { + //don't affect hash code calculations + return 0; + } + + public boolean equals(Object o) { + if (!(o instanceof ListSizeField)) { + return false; + } + + ListSizeField other = (ListSizeField)o; + + return list.size() == other.list.size(); + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/MapField.java b/src/main/java/org/JesusFreke/dexlib/MapField.java new file mode 100644 index 00000000..54fe5d9a --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/MapField.java @@ -0,0 +1,88 @@ +/* + * [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.JesusFreke.dexlib; + +import org.JesusFreke.dexlib.ItemType; +import org.JesusFreke.dexlib.util.Output; + +public class MapField extends CompositeField { + private final Field[] fields; + + public ItemType getSectionItemType() { + return ItemType.fromInt(sectionType.getCachedValue()); + } + + public int getSectionSize() { + return sectionInfo.getSectionSize(); + } + + public int getSectionOffset() { + return sectionInfo.getSectionOffset(); + } + + private final ShortIntegerField sectionType; + private final ShortIntegerField unused; + private final SectionHeaderInfo sectionInfo; + + public MapField(final DexFile dexFile) { + fields = new Field[] { + sectionType = new ShortIntegerField(), + unused = new ShortIntegerField((short)0), + sectionInfo = new SectionHeaderInfo() { + protected Section getSection() { + return dexFile.getSectionForType(getSectionItemType()); + } + } + }; + } + + public MapField(final DexFile dexFile, short sectionType) { + fields = new Field[] { + this.sectionType = new ShortIntegerField(sectionType), + this.unused = new ShortIntegerField((short)0), + this.sectionInfo = new SectionHeaderInfo() { + protected Section getSection() { + return dexFile.getSectionForType(getSectionItemType()); + } + } + }; + } + + public int place(int offset) { + return super.place(offset); + } + + public void writeTo(Output out) { + super.writeTo(out); + } + + protected Field[] getFields() { + return fields; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/MapItem.java b/src/main/java/org/JesusFreke/dexlib/MapItem.java new file mode 100644 index 00000000..53461adb --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/MapItem.java @@ -0,0 +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.JesusFreke.dexlib; + +import org.JesusFreke.dexlib.ItemType; +import org.JesusFreke.dexlib.util.Output; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; + +public class MapItem extends IndexedItem { + private final Field[] fields; + private ArrayList mapEntries = new ArrayList(); + + public MapItem(final DexFile dexFile, int index) { + super(index); + + fields = new Field[] { + new ListSizeField(mapEntries, new IntegerField()), + new FieldListField(mapEntries) { + protected MapField make() { + return new MapField(dexFile); + } + } + }; + } + + public int place(int index, int offset) { + for (int i=0; i 0x06*/) { + mapEntries.remove(i--); + } + } + + return super.place(index, offset); + } + + public void writeTo(Output out) { + Collections.sort(mapEntries, new Comparator() { + + public int compare(MapField o1, MapField o2) { + return ((Integer)o1.getSectionOffset()).compareTo(o2.getSectionOffset()); + } + }); + + super.writeTo(out); + } + + public static MapItem makeBlankMapItem(DexFile dexFile) { + MapItem mapItem = new MapItem(dexFile, 0); + + mapItem.mapEntries.add(new MapField(dexFile, (short)0x0000)); + mapItem.mapEntries.add(new MapField(dexFile, (short)0x0001)); + mapItem.mapEntries.add(new MapField(dexFile, (short)0x0002)); + mapItem.mapEntries.add(new MapField(dexFile, (short)0x0003)); + mapItem.mapEntries.add(new MapField(dexFile, (short)0x0004)); + mapItem.mapEntries.add(new MapField(dexFile, (short)0x0005)); + mapItem.mapEntries.add(new MapField(dexFile, (short)0x0006)); + mapItem.mapEntries.add(new MapField(dexFile, (short)0x1003)); + mapItem.mapEntries.add(new MapField(dexFile, (short)0x2001)); + mapItem.mapEntries.add(new MapField(dexFile, (short)0x2006)); + mapItem.mapEntries.add(new MapField(dexFile, (short)0x1001)); + mapItem.mapEntries.add(new MapField(dexFile, (short)0x2002)); + mapItem.mapEntries.add(new MapField(dexFile, (short)0x2003)); + mapItem.mapEntries.add(new MapField(dexFile, (short)0x2004)); + mapItem.mapEntries.add(new MapField(dexFile, (short)0x2005)); + mapItem.mapEntries.add(new MapField(dexFile, (short)0x2000)); + mapItem.mapEntries.add(new MapField(dexFile, (short)0x1000)); + + + return mapItem; + } + + public MapField[] getMapEntries() { + return mapEntries.toArray(new MapField[1]); + } + + protected int getAlignment() { + return 4; + } + + protected Field[] getFields() { + return fields; + } + + public ItemType getItemType() { + return ItemType.TYPE_MAP_LIST; + } + + public void copyTo(DexFile dexFile, MapItem copy) { + //nothing to do + } + + public int hashCode() { + return 1; + } + + public boolean equals(Object o) { + return getClass() == o.getClass(); + } + + public int compareTo(MapItem o) { + //there is only 1 map item + return 1; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/MethodIdItem.java b/src/main/java/org/JesusFreke/dexlib/MethodIdItem.java new file mode 100644 index 00000000..38e28522 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/MethodIdItem.java @@ -0,0 +1,106 @@ +/* + * [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.JesusFreke.dexlib; + +public class MethodIdItem extends IndexedItem { + private final Field[] fields; + + private final IndexedItemReference classType; + private final IndexedItemReference prototype; + private final IndexedItemReference methodName; + + public MethodIdItem(DexFile dexFile, int index) { + super(index); + fields = new Field[] { + classType = new IndexedItemReference(dexFile.TypeIdsSection, new ShortIntegerField()), + prototype = new IndexedItemReference(dexFile.ProtoIdsSection, new ShortIntegerField()), + methodName = new IndexedItemReference(dexFile.StringIdsSection, new IntegerField()) + }; + } + + public MethodIdItem(DexFile dexFile, TypeIdItem classType, StringIdItem methodName, ProtoIdItem prototype) { + super(-1); + fields = new Field[] { + this.classType = new IndexedItemReference(dexFile, classType, new ShortIntegerField()), + this.prototype = new IndexedItemReference(dexFile, prototype, new ShortIntegerField()), + this.methodName = new IndexedItemReference(dexFile, methodName, new IntegerField()) + }; + } + + public MethodIdItem(DexFile dexFile, TypeIdItem classType, String methodName, ProtoIdItem prototype) { + this(dexFile, classType, new StringIdItem(dexFile, methodName), prototype); + } + + + protected int getAlignment() { + return 4; + } + + protected Field[] getFields() { + return fields; + } + + public ItemType getItemType() { + return ItemType.TYPE_METHOD_ID_ITEM; + } + + public TypeIdItem getClassType() { + return classType.getReference(); + } + + public String getMethodName() { + return methodName.getReference().toString(); + } + + public void setClassType(TypeIdItem newClassType) { + classType.setReference(newClassType); + } + + public String toString() { + return classType.getReference().toString() + " - " + methodName.getReference().toString(); + } + + public int getParameterWordCount(boolean isStatic) { + return prototype.getReference().getParameterWordCount() + (isStatic?0:1); + } + + 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 prototype.compareTo(o.prototype); + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/NullTerminatedByteArrayField.java b/src/main/java/org/JesusFreke/dexlib/NullTerminatedByteArrayField.java new file mode 100644 index 00000000..c70980a8 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/NullTerminatedByteArrayField.java @@ -0,0 +1,99 @@ +/* + * [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.JesusFreke.dexlib; + +import org.JesusFreke.dexlib.util.Output; +import org.JesusFreke.dexlib.util.Input; +import org.JesusFreke.dexlib.util.ByteArray; + +public class NullTerminatedByteArrayField implements Field { + protected byte[] value; + + public NullTerminatedByteArrayField() { + } + + public NullTerminatedByteArrayField(byte[] value) { + this.value = value.clone(); + } + + public NullTerminatedByteArrayField(ByteArray byteArray) { + value = new byte[byteArray.size()]; + byteArray.getBytes(value, 0); + } + + public void writeTo(Output out) { + out.write(value); + out.writeByte(0); + } + + public void readFrom(Input in) { + int startPosition = in.getCursor(); + while (in.readByte() != 0); + int size = in.getCursor() - startPosition - 1; + + in.setCursor(startPosition); + value = in.readBytes(size); + in.skipBytes(1); + } + + public int place(int offset) { + return offset + value.length + 1; + } + + public void copyTo(DexFile dexFile, NullTerminatedByteArrayField copy) { + copy.value = value; + } + + public int hashCode() { + int h=1; + for (int i = 0; i < value.length; i++) { + h = h*7 + value[i]; + } + return h; + } + + public boolean equals(Object o) { + if (!(o instanceof NullTerminatedByteArrayField)) { + return false; + } + + NullTerminatedByteArrayField other = (NullTerminatedByteArrayField)o; + if (value.length != other.value.length) { + return false; + } + + for (int i = 0; i < value.length; i++) { + if (value[i] != other.value[i]) { + return false; + } + } + + return true; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/OffsettedItem.java b/src/main/java/org/JesusFreke/dexlib/OffsettedItem.java new file mode 100644 index 00000000..71485ab5 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/OffsettedItem.java @@ -0,0 +1,36 @@ +/* + * [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.JesusFreke.dexlib; + +public abstract class OffsettedItem> extends Item { + + public OffsettedItem(int offset) { + super(offset); + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/OffsettedItemReference.java b/src/main/java/org/JesusFreke/dexlib/OffsettedItemReference.java new file mode 100644 index 00000000..605a1096 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/OffsettedItemReference.java @@ -0,0 +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.JesusFreke.dexlib; + +import org.JesusFreke.dexlib.util.Output; +import org.JesusFreke.dexlib.util.Input; + +public class OffsettedItemReference> extends + ItemReference> { + private final CachedIntegerValueField underlyingField; + + public OffsettedItemReference(OffsettedSection section, CachedIntegerValueField underlyingField) { + super(section); + this.underlyingField = underlyingField; + } + + public OffsettedItemReference(DexFile dexFile, T item, CachedIntegerValueField underlyingField) { + super(dexFile, item); + this.underlyingField = underlyingField; + } + + public OffsettedSection getSection() { + return (OffsettedSection)super.getSection(); + } + + public void writeTo(Output out) { + T item = getReference(); + if (item != null && !item.isPlaced()) { + throw new RuntimeException("Trying to write reference to an item that hasn't been placed."); + } + + /*if (out.getCursor() != underlyingField.getCachedValue()) { + throw new RuntimeException("Trying to write a reference in a difference location from where it was placed"); + }*/ + //TODO: this is a hack to force it to reload the correct offset value + if (item == null) { + underlyingField.cacheValue(0); + } else { + underlyingField.cacheValue(item.getOffset()); + } + + underlyingField.writeTo(out); + } + + public void readFrom(Input in) { + underlyingField.readFrom(in); + if (underlyingField.getCachedValue() != 0) { + setReference(getSection().getByOffset(underlyingField.getCachedValue())); + } + } + + public int place(int offset) { + if (getReference() != null) { + underlyingField.cacheValue(getReference().getOffset()); + } else { + underlyingField.cacheValue(0); + } + return underlyingField.place(offset); + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/OffsettedSection.java b/src/main/java/org/JesusFreke/dexlib/OffsettedSection.java new file mode 100644 index 00000000..e3634dde --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/OffsettedSection.java @@ -0,0 +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.JesusFreke.dexlib; + +import org.JesusFreke.dexlib.util.Input; + +import java.util.HashMap; + +public abstract class OffsettedSection> extends Section { + protected HashMap itemsByOffset; + + public OffsettedSection() { + itemsByOffset = new HashMap(); + } + + /** + * Retrieves the item that starts at the given offset, or null if + * there are none found. This method is intended to only be used + * while reading in a dex file. + * TODO: find a better way to abstract this + * @param offset the offset of the item to get + * @return the item that starts at the given offset, or null if there + * are none found + */ + public T getByOffset(int offset) { + T item = itemsByOffset.get(offset); + if (item == null) { + item = make(offset); + items.add(item); + itemsByOffset.put(offset, item); + } + return item; + } + + public void readFrom(int size, Input in) { + for (int i = 0; i < size; i++) { + T item = getByOffset(in.getCursor()); + item.readFrom(in); + in.alignTo(item.getAlignment()); + } + } + + protected abstract T make(int offset); + + public T intern(DexFile dexFile, T item) { + T itemToReturn = getInternedItem(item); + + if (itemToReturn == null) { + itemToReturn = make(-1); + items.add(itemToReturn); + item.copyTo(dexFile, itemToReturn); + uniqueItems.put(itemToReturn, itemToReturn); + } + + return itemToReturn; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/ProtoIdItem.java b/src/main/java/org/JesusFreke/dexlib/ProtoIdItem.java new file mode 100644 index 00000000..737e90ca --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/ProtoIdItem.java @@ -0,0 +1,112 @@ +/* + * [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.JesusFreke.dexlib; + +import org.JesusFreke.dexlib.ItemType; + +import java.util.ArrayList; + +public class ProtoIdItem extends IndexedItem { + private final Field[] fields; + + private final IndexedItemReference shortyDescriptor; + private final IndexedItemReference returnType; + private final OffsettedItemReference parameters; + + public ProtoIdItem(DexFile dexFile, int index) { + super(index); + fields = new Field[] { + shortyDescriptor = new IndexedItemReference(dexFile.StringIdsSection, new IntegerField()), + returnType = new IndexedItemReference(dexFile.TypeIdsSection, new IntegerField()), + parameters = new OffsettedItemReference(dexFile.TypeListsSection, new IntegerField()) + }; + } + + public ProtoIdItem(DexFile dexFile, TypeIdItem returnType, ArrayList parameters) + { + super(-1); + StringIdItem stringIdItem = new StringIdItem(dexFile, createShortyDescriptor(returnType, parameters)); + TypeListItem typeListItem = new TypeListItem(dexFile, parameters); + + fields = new Field[] { + this.shortyDescriptor = new IndexedItemReference(dexFile, stringIdItem, new IntegerField()), + this.returnType = new IndexedItemReference(dexFile, returnType, new IntegerField()), + this.parameters = new OffsettedItemReference(dexFile, typeListItem, new IntegerField()) + }; + } + + private String createShortyDescriptor(TypeIdItem returnType, ArrayList parameters) { + StringBuilder sb = new StringBuilder(); + sb.append(returnType.toShorty()); + + for (TypeIdItem typeIdItem: parameters) { + sb.append(typeIdItem.toShorty()); + } + return sb.toString(); + } + + protected int getAlignment() { + return 4; + } + + public int getParameterWordCount() { + TypeListItem typeList = parameters.getReference(); + if (typeList == null) { + return 0; + } else { + return typeList.getWordCount(); + } + } + + protected Field[] getFields() { + return fields; + } + + public ItemType getItemType() { + return ItemType.TYPE_PROTO_ID_ITEM; + } + + public int compareTo(ProtoIdItem o) { + int result = returnType.compareTo(o.returnType); + if (result != 0) { + return result; + } + + TypeListItem thisParameters = parameters.getReference(); + if (thisParameters == null) { + return -1; + } + + return thisParameters.compareTo(o.parameters.getReference()); + } + + public String toString() { + return shortyDescriptor.toString(); + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/Section.java b/src/main/java/org/JesusFreke/dexlib/Section.java new file mode 100644 index 00000000..e59998e7 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/Section.java @@ -0,0 +1,133 @@ +/* + * [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.JesusFreke.dexlib; + +import org.JesusFreke.dexlib.util.Output; +import org.JesusFreke.dexlib.util.Input; + +import java.util.ArrayList; +import java.util.HashMap; + +public abstract class Section { + protected ArrayList items; + protected HashMap uniqueItems = null; + + /** + * When offset > -1, this section is "placed" at the specified offset. All + * items should have sequential indexes, and be placed appropriately. + * + * To unplace the section, set offset to -1, and set the offset of all + * items to -1 + */ + protected int offset = -1; + + public Section() { + items = new ArrayList(); + } + + public int place(int offset) { + this.offset = offset; + for (int i=0; i < items.size(); i++) { + T item = items.get(i); + if (item == null) { + items.remove(i--); + continue; + } + offset = item.place(i, offset); + if (i == 0) { + /** if this item type has an alignment requirement, + * then item.getOffset() may be different than the + * offset before item.place was called, so we have + * to initialize the section offset to the actual + * (post-alignment) offset of the first item + */ + this.offset = item.getOffset(); + } + } + + return offset; + } + + public void unplace() { + for (Item item: items) { + item.unplace(); + } + } + + public void writeTo(Output out) { + for (int i = 0; i < size(); i++) { + T item = items.get(i); + if (item == null) { + throw new RuntimeException("Cannot write section because all items haven't been initialized"); + } + item.writeTo(out); + } + } + + public abstract void readFrom(int size, Input in); + + protected void setSize(int size) { + if (items.size() > size) { + throw new RuntimeException("This section contains references to items beyond the size of the section"); + } + + items.ensureCapacity(size); + for (int i = items.size(); i < size; i++) { + items.add(null); + } + } + + public int size() { + return items.size(); + } + + public boolean isPlaced() { + return offset > -1; + } + + public int getOffset() { + return offset; + } + + protected T getInternedItem(T item) { + if (uniqueItems == null) { + buildInternedItemMap(); + } + return uniqueItems.get(item); + } + + protected void buildInternedItemMap() { + uniqueItems = new HashMap(); + for (T item: items) { + uniqueItems.put(item, item); + } + } + + public abstract T intern(DexFile dexFile, T item); +} diff --git a/src/main/java/org/JesusFreke/dexlib/SectionHeaderInfo.java b/src/main/java/org/JesusFreke/dexlib/SectionHeaderInfo.java new file mode 100644 index 00000000..48a11d4c --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/SectionHeaderInfo.java @@ -0,0 +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.JesusFreke.dexlib; + +import org.JesusFreke.dexlib.util.Output; +import org.JesusFreke.dexlib.util.Input; + +public abstract class SectionHeaderInfo implements Field { + private int sectionSize; + private int sectionOffset; + + public SectionHeaderInfo() { + } + + protected abstract Section getSection(); + + public void writeTo(Output out) { + Section section = getSection(); + + if (!section.isPlaced()) { + throw new RuntimeException("Trying to write a reference to a section that hasn't been placed."); + } + sectionSize = section.size(); + sectionOffset = section.getOffset(); + + out.writeInt(sectionSize); + out.writeInt(sectionOffset); + } + + public void readFrom(Input in) { + sectionSize = in.readInt(); + sectionOffset = in.readInt(); + } + + public int getSectionSize() { + return sectionSize; + } + + public int getSectionOffset() { + return sectionOffset; + } + + public int place(int offset) { + Section section = getSection(); + sectionSize = section.size(); + sectionOffset = section.getOffset(); + + return offset+8; + } + + public void copyTo(DexFile dexFile, SectionHeaderInfo copy) { + /** + * do nothing. the section size and offset are dynamically generated + * when the copy is written + */ + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/ShortIntegerField.java b/src/main/java/org/JesusFreke/dexlib/ShortIntegerField.java new file mode 100644 index 00000000..99a607c8 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/ShortIntegerField.java @@ -0,0 +1,70 @@ +/* + * [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.JesusFreke.dexlib; + +import org.JesusFreke.dexlib.util.Output; +import org.JesusFreke.dexlib.util.Input; + +public class ShortIntegerField extends CachedIntegerValueField { + protected int value = 0; + + public ShortIntegerField() { + } + + public ShortIntegerField(int value) { + this.value = value; + } + + public void writeTo(Output out) { + out.writeShort(value); + } + + public void readFrom(Input in) { + value = in.readShort(); + } + + public int place(int offset) { + return offset + 2; + } + + /** + * This method returns the short integer value that has been cached. This + * value is either the value that the field was constructed with, the + * value that was read via readFrom, or the value that was + * cached when place was called + * @return the cached value + */ + public int getCachedValue() { + return value; + } + + public void cacheValue(int value) { + this.value = (short)value; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/SignedLeb128Field.java b/src/main/java/org/JesusFreke/dexlib/SignedLeb128Field.java new file mode 100644 index 00000000..9047af0f --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/SignedLeb128Field.java @@ -0,0 +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.JesusFreke.dexlib; + +import org.JesusFreke.dexlib.util.Output; +import org.JesusFreke.dexlib.util.Input; +import org.JesusFreke.dexlib.util.Leb128Utils; + +public class SignedLeb128Field extends CachedIntegerValueField { + protected int value; + + public SignedLeb128Field() { + } + + public SignedLeb128Field(int value) { + this.value = value; + } + + public void writeTo(Output out) { + out.writeSignedLeb128(value); + } + + public void readFrom(Input in) { + value = in.readSignedLeb128(); + } + + public int place(int offset) { + return offset + Leb128Utils.signedLeb128Size(value); + } + + public int getCachedValue() { + return value; + } + + public void cacheValue(int value) { + this.value = value; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/StringDataItem.java b/src/main/java/org/JesusFreke/dexlib/StringDataItem.java new file mode 100644 index 00000000..720f6191 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/StringDataItem.java @@ -0,0 +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.JesusFreke.dexlib; + +import org.JesusFreke.dexlib.util.ByteArray; +import org.JesusFreke.dexlib.util.Utf8Utils; + +public class StringDataItem extends OffsettedItem implements Comparable { + private final Field[] fields; + + private String value = null; + + private final Leb128Field stringSize; + private final NullTerminatedByteArrayField stringByteArray; + + public StringDataItem(int offset) { + super(offset); + + fields = new Field[] { + stringSize = new Leb128Field(), + stringByteArray = new NullTerminatedByteArrayField() + }; + } + + public StringDataItem(String value) { + super(-1); + + this.value = value; + + fields = new Field[] { + stringSize = new Leb128Field(value.length()), + stringByteArray = new NullTerminatedByteArrayField(Utf8Utils.stringToUtf8Bytes(value)) + }; + } + + public Field[] getFields() { + return fields; + } + + public int getAlignment() { + return 1; + } + + public ItemType getItemType() { + return ItemType.TYPE_STRING_DATA_ITEM; + } + + public String toString() { + if (value == null) { + value = Utf8Utils.utf8BytesToString(new ByteArray(((NullTerminatedByteArrayField)fields[1]).value)); + } + + return value; + } + + public int compareTo(StringDataItem o) { + return toString().compareTo(o.toString()); + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/StringIdItem.java b/src/main/java/org/JesusFreke/dexlib/StringIdItem.java new file mode 100644 index 00000000..40f01fb9 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/StringIdItem.java @@ -0,0 +1,75 @@ +/* + * [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.JesusFreke.dexlib; + +public class StringIdItem extends IndexedItem { + private final Field[] fields; + + private final OffsettedItemReference stringData; + + public StringIdItem(DexFile dexFile, int index) { + super(index); + fields = new Field[] { + stringData = new OffsettedItemReference(dexFile.StringDataSection, new IntegerField()) + }; + } + + public StringIdItem(DexFile dexFile, StringDataItem stringDataItem) { + super(-1); + + fields = new Field[] { + stringData = new OffsettedItemReference(dexFile, stringDataItem, new IntegerField()) + }; + } + + public StringIdItem(DexFile dexFile, String value) { + this(dexFile, new StringDataItem(value)); + } + + protected int getAlignment() { + return 4; + } + + protected Field[] getFields() { + return fields; + } + + public ItemType getItemType() { + return ItemType.TYPE_STRING_ID_ITEM; + } + + public String toString() { + return stringData.getReference().toString(); + } + + public int compareTo(StringIdItem o) { + //sort by the string value + return toString().compareTo(o.toString()); + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/TypeIdItem.java b/src/main/java/org/JesusFreke/dexlib/TypeIdItem.java new file mode 100644 index 00000000..794f0698 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/TypeIdItem.java @@ -0,0 +1,100 @@ +/* + * [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.JesusFreke.dexlib; + +public class TypeIdItem extends IndexedItem { + private final Field[] fields; + + private final IndexedItemReference type; + + public TypeIdItem(DexFile dexFile, int index) { + super(index); + fields = new Field[] { + type = new IndexedItemReference(dexFile.StringIdsSection, new IntegerField()) + }; + } + + public TypeIdItem(DexFile dexFile, StringIdItem stringIdItem) { + super(-1); + fields = new Field[] { + type = new IndexedItemReference(dexFile, stringIdItem, new IntegerField()) + }; + } + + public TypeIdItem(DexFile dexFile, String value) { + super(-1); + StringDataItem stringDataItem = new StringDataItem(value); + StringIdItem stringIdItem = new StringIdItem(dexFile, stringDataItem); + fields = new Field[] { + type = new IndexedItemReference(dexFile, stringIdItem, new IntegerField()) + }; + } + + protected int getAlignment() { + return 4; + } + + protected Field[] getFields() { + return fields; + } + + public int getWordCount() { + String type = this.toString(); + /** 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; + } + } + + public ItemType getItemType() { + return ItemType.TYPE_TYPE_ID_ITEM; + } + + public String toString() { + return type.getReference().toString(); + } + + public int compareTo(TypeIdItem o) { + //sort by the index of the StringIdItem + return type.compareTo(o.type); + } + + public String toShorty() { + String type = toString(); + if (type.length() > 1) { + return "L"; + } else { + return type; + } + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/TypeListItem.java b/src/main/java/org/JesusFreke/dexlib/TypeListItem.java new file mode 100644 index 00000000..a1d4b5ee --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/TypeListItem.java @@ -0,0 +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.JesusFreke.dexlib; + +import java.util.ArrayList; +import java.util.List; + +public class TypeListItem extends OffsettedItem implements Comparable { + private final Field[] fields; + private final ArrayList> typeList = new ArrayList>(); + + public TypeListItem(final DexFile dexFile, int offset) { + super(offset); + + fields = new Field[] { + new ListSizeField(typeList, new IntegerField()), + new FieldListField>(typeList) { + protected IndexedItemReference make() { + return new IndexedItemReference(dexFile.TypeIdsSection, new ShortIntegerField()); + } + } + }; + } + + public TypeListItem(final DexFile dexFile, List types) { + this(dexFile, 0); + + for (TypeIdItem typeIdItem: types) { + typeList.add(new IndexedItemReference(dexFile, typeIdItem, new ShortIntegerField())); + } + } + + public List getTypes() { + ArrayList list = new ArrayList(typeList.size()); + + for (IndexedItemReference typeIdItemReference: typeList) { + list.add(typeIdItemReference.getReference()); + } + + return list; + } + + public Field[] getFields() { + return fields; + } + + public int getWordCount() { + int wordCount = 0; + for (IndexedItemReference typeRef: typeList) { + TypeIdItem item = typeRef.getReference(); + wordCount += item.getWordCount(); + } + return wordCount; + } + + public int getAlignment() { + return 4; + } + + public ItemType getItemType() { + return ItemType.TYPE_TYPE_LIST; + } + + public int compareTo(TypeListItem o) { + if (o == null) { + return 1; + } + + int thisSize = typeList.size(); + int otherSize = o.typeList.size(); + int size = Math.min(thisSize, otherSize); + + for (int i = 0; i < size; i++) { + int result = typeList.get(i).compareTo(o.typeList.get(i)); + if (result != 0) { + return result; + } + } + + if (thisSize < otherSize) { + return -1; + } else if (thisSize > otherSize) { + return 1; + } else { + return 0; + } + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/code/Format/Format.java b/src/main/java/org/JesusFreke/dexlib/code/Format/Format.java new file mode 100644 index 00000000..6ce7eb69 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/code/Format/Format.java @@ -0,0 +1,43 @@ +/* + * [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.JesusFreke.dexlib.code.Format; + +import org.JesusFreke.dexlib.code.Opcode; + +public abstract class Format +{ + public abstract int getByteCount(); + public abstract String getFormatName(); + + protected void checkOpcodeFormat(Opcode opcode) { + if (!opcode.format.equals(getFormatName())) { + throw new RuntimeException("Opcode " + opcode.name + " does not use format " + getFormatName()); + } + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/code/Format/Format10x.java b/src/main/java/org/JesusFreke/dexlib/code/Format/Format10x.java new file mode 100644 index 00000000..2cae9f6d --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/code/Format/Format10x.java @@ -0,0 +1,59 @@ +/* + * [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.JesusFreke.dexlib.code.Format; + +import org.JesusFreke.dexlib.code.Instruction; +import org.JesusFreke.dexlib.code.Opcode; +import org.JesusFreke.dexlib.DexFile; + +public class Format10x extends Format +{ + public static final Format10x Format = new Format10x(); + + private Format10x() { + } + + public Instruction make(DexFile dexFile, byte opcode) { + Opcode op = Opcode.getOpcodeByValue(opcode); + + checkOpcodeFormat(op); + + return new Instruction(dexFile, new byte[]{opcode,0x00}, null); + } + + public int getByteCount() + { + return 2; + } + + public String getFormatName() + { + return "10x"; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/code/Format/Format11x.java b/src/main/java/org/JesusFreke/dexlib/code/Format/Format11x.java new file mode 100644 index 00000000..d8cf37c7 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/code/Format/Format11x.java @@ -0,0 +1,63 @@ +/* + * [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.JesusFreke.dexlib.code.Format; + +import org.JesusFreke.dexlib.code.Instruction; +import org.JesusFreke.dexlib.code.Opcode; +import org.JesusFreke.dexlib.DexFile; + +public class Format11x extends Format +{ + public static final Format11x Format = new Format11x(); + + private Format11x() { + } + + public Instruction make(DexFile dexFile, byte opcode, short regA) { + Opcode op = Opcode.getOpcodeByValue(opcode); + + checkOpcodeFormat(op); + + if (regA >= 2<<8) { + throw new RuntimeException("The register number must be less than v256"); + } + + return new Instruction(dexFile, new byte[]{opcode,(byte)regA}, null); + } + + public int getByteCount() + { + return 2; + } + + public String getFormatName() + { + return "11x"; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/code/Format/Format21c.java b/src/main/java/org/JesusFreke/dexlib/code/Format/Format21c.java new file mode 100644 index 00000000..c6df8123 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/code/Format/Format21c.java @@ -0,0 +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.JesusFreke.dexlib.code.Format; + +import org.JesusFreke.dexlib.code.Instruction; +import org.JesusFreke.dexlib.code.Opcode; +import org.JesusFreke.dexlib.DexFile; +import org.JesusFreke.dexlib.IndexedItem; + +public class Format21c extends Format +{ + public static final Format21c Format = new Format21c(); + + private Format21c() { + } + + public Instruction make(DexFile dexFile, byte opcode, short regA, IndexedItem item) { + byte[] bytes = new byte[4]; + + Opcode op = Opcode.getOpcodeByValue(opcode); + + checkOpcodeFormat(op); + + if (regA >= 2<<8) { + throw new RuntimeException("The register number must be less than v256"); + } + + bytes[0] = opcode; + bytes[1] = (byte)regA; + + return new Instruction(dexFile, bytes, item); + } + + public int getByteCount() { + return 4; + } + + public String getFormatName() { + return "21c"; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/code/Format/Format22c.java b/src/main/java/org/JesusFreke/dexlib/code/Format/Format22c.java new file mode 100644 index 00000000..ab09a6dc --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/code/Format/Format22c.java @@ -0,0 +1,69 @@ +/* + * [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.JesusFreke.dexlib.code.Format; + +import org.JesusFreke.dexlib.code.Instruction; +import org.JesusFreke.dexlib.code.Opcode; +import org.JesusFreke.dexlib.DexFile; +import org.JesusFreke.dexlib.IndexedItem; + +public class Format22c extends Format +{ + public static final Format22c Format = new Format22c(); + + private Format22c() { + } + + public Instruction make(DexFile dexFile, byte opcode, byte regA, byte regB, IndexedItem item) { + byte[] bytes = new byte[4]; + + Opcode op = Opcode.getOpcodeByValue(opcode); + + checkOpcodeFormat(op); + + if (regA >= 16 || + regB >= 16) { + throw new RuntimeException("The register number must be less than v16"); + } + + + bytes[0] = opcode; + bytes[1] = (byte)((regB << 4) | regA); + + return new Instruction(dexFile, bytes, item); + } + + public int getByteCount() { + return 4; + } + + public String getFormatName() { + return "22c"; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/code/Format/Format35c.java b/src/main/java/org/JesusFreke/dexlib/code/Format/Format35c.java new file mode 100644 index 00000000..483f5205 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/code/Format/Format35c.java @@ -0,0 +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.JesusFreke.dexlib.code.Format; + +import org.JesusFreke.dexlib.*; +import org.JesusFreke.dexlib.code.Instruction; +import org.JesusFreke.dexlib.code.Opcode; +import static org.JesusFreke.dexlib.code.Opcode.*; + +public class Format35c extends Format +{ + public static final Format35c Format = new Format35c(); + + private Format35c() { + } + + public Instruction make(DexFile dexFile, byte opcode, byte regCount, byte regD, byte regE, byte regF, byte regG, byte regA, IndexedItem item) { + byte[] bytes = new byte[6]; + + Opcode op = Opcode.getOpcodeByValue(opcode); + + checkOpcodeFormat(op); + + if (regCount > 5) { + throw new RuntimeException("regCount cannot be greater than 5"); + } + if (regD >= 16 || + regE >= 16 || + regF >= 16 || + regG >= 16 || + regA >= 16) { + throw new RuntimeException("All register args must fit in 4 bits"); + } + + bytes[0] = opcode; + bytes[1] = (byte)((regCount << 4) | regA); + bytes[4] = (byte)((regE << 4) | regD); + bytes[5] = (byte)((regG << 4) | regF); + + //go ahead and make the instruction, to verify that item is the correct type. If it isn't, + //the construction will throw an exception + Instruction instruction = new Instruction(dexFile, bytes, item); + + if (opcode == FILLED_NEW_ARRAY.value) { + //check data for filled-new-array opcode + String type = ((TypeIdItem)item).toString(); + 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 >= INVOKE_VIRTUAL.value && opcode <= INVOKE_INTERFACE.value) { + //check data for invoke-* opcodes + MethodIdItem methodIdItem = (MethodIdItem)item; + if (methodIdItem.getParameterWordCount(opcode == INVOKE_STATIC.value) != regCount) { + throw new RuntimeException("regCount does not match the number of arguments of the method"); + } + } else { + throw new RuntimeException("Opcode " + Integer.toHexString(opcode) + " does not use the 35c format"); + } + + return instruction; + } + + public int getByteCount() { + return 6; + } + + public String getFormatName() { + return "35c"; + } + + /*@Test + public void testInvoke() { + DexFile dexFile = new DexFile(); + ArrayList types = new ArrayList(); + types.add(new TypeIdItem(dexFile, "I")); + types.add(new TypeIdItem(dexFile, "I")); + types.add(new TypeIdItem(dexFile, "I")); + types.add(new TypeIdItem(dexFile, "I")); + types.add(new TypeIdItem(dexFile, "I")); + MethodIdItem method = new MethodIdItem(dexFile, new TypeIdItem(dexFile, "test"), "test", new ProtoIdItem(dexFile, new TypeIdItem(dexFile, "V"), types)); + + Instruction ins = make(dexFile, (byte)INVOKE_VIRTUAL.value, (byte)5, (byte)0, (byte)1, (byte)2, (byte)3, (byte)4, method); + assertTrue("Is everything put in the right place?", java.util.Arrays.equals(ins.getBytes(), new byte[] {0x6e, 0x54, 0x00, 0x00, 0x10, 0x32})); + }*/ +} diff --git a/src/main/java/org/JesusFreke/dexlib/code/Format/Format3rc.java b/src/main/java/org/JesusFreke/dexlib/code/Format/Format3rc.java new file mode 100644 index 00000000..b4f64d63 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/code/Format/Format3rc.java @@ -0,0 +1,118 @@ +/* + * [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.JesusFreke.dexlib.code.Format; + +import org.JesusFreke.dexlib.*; +import org.JesusFreke.dexlib.code.Instruction; +import org.JesusFreke.dexlib.code.Opcode; +import static org.JesusFreke.dexlib.code.Opcode.*; + +public class Format3rc extends Format +{ + public static final Format3rc Format = new Format3rc(); + + public Format3rc() { + } + + public Instruction make(DexFile dexFile, byte opcode, short regCount, int startReg, IndexedItem item) { + byte[] bytes = new byte[6]; + + Opcode op = Opcode.getOpcodeByValue(opcode); + + checkOpcodeFormat(op); + + if (regCount >= 2<<8) { + throw new RuntimeException("regCount must be less than 256"); + } + if (regCount < 0) { + throw new RuntimeException("regCount cannot be negative"); + } + + if (startReg >= 2<<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"); + } + + bytes[0] = opcode; + bytes[1] = (byte)regCount; + bytes[4] = (byte)startReg; + bytes[5] = (byte)(startReg >> 8); + + //go ahead and make the instruction now, which will verify that item is the correct type. If it isn't, + //the construction will throw an exception + Instruction instruction = new Instruction(dexFile, bytes, item); + + if (opcode == FILLED_NEW_ARRAY_RANGE.value) { + //check data for filled-new-array/range opcode + String type = ((TypeIdItem)item).toString(); + 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 >= INVOKE_VIRTUAL_RANGE.value && opcode <= INVOKE_INTERFACE_RANGE.value) { + //check data for invoke-*/range opcodes + MethodIdItem methodIdItem = (MethodIdItem)item; + if (methodIdItem.getParameterWordCount(opcode == INVOKE_STATIC.value) != regCount) { + throw new RuntimeException("regCount does not match the number of arguments of the method"); + } + } else { + throw new RuntimeException("Opcode " + Integer.toHexString(opcode) + " does not use the 35c format"); + } + + return instruction; + } + + public int getByteCount() { + return 6; + } + + public String getFormatName() { + return "3rc"; + } + + /*@Test + public void testInvoke() { + DexFile dexFile = DexFile.makeBlankDexFile(); + ArrayList types = new ArrayList(); + types.add(new TypeIdItem(dexFile, "I")); + types.add(new TypeIdItem(dexFile, "I")); + types.add(new TypeIdItem(dexFile, "I")); + types.add(new TypeIdItem(dexFile, "I")); + types.add(new TypeIdItem(dexFile, "I")); + MethodIdItem method = new MethodIdItem(dexFile, new TypeIdItem(dexFile, "test"), "test", new ProtoIdItem(dexFile, new TypeIdItem(dexFile, "V"), types)); + + Instruction ins = Format.make(dexFile, (byte)INVOKE_VIRTUAL_RANGE.value, (short)6, 65500, method); + byte[] bytes = new byte[] {0x74, 0x06, 0x00, 0x00, (byte)0xDC, (byte)0xFF}; + assertTrue("Is everything put in the right place?", java.util.Arrays.equals(ins.getBytes(), bytes)); + }*/ +} diff --git a/src/main/java/org/JesusFreke/dexlib/code/Instruction.java b/src/main/java/org/JesusFreke/dexlib/code/Instruction.java new file mode 100644 index 00000000..18d9de4e --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/code/Instruction.java @@ -0,0 +1,194 @@ +/* + * [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.JesusFreke.dexlib.code; + +import org.JesusFreke.dexlib.*; +import org.JesusFreke.dexlib.util.Input; +import org.JesusFreke.dexlib.util.Output; + +//TODO: need to implement the "special" bytecode types, for switches etc. + +public final class Instruction implements Field { + private DexFile dexFile; + private byte[] bytes; + private Opcode opcode; + + private IndexedItem reference; + + public byte[] getBytes() { + return bytes; + } + + public Opcode getOpcode() { + return opcode; + } + + public IndexedItem getReference() { + return reference; + } + + public Instruction(DexFile dexFile) { + this.dexFile = dexFile; + } + + public Instruction(DexFile dexFile, byte[] bytes, IndexedItem item) { + this.dexFile = dexFile; + this.bytes = bytes; + this.reference = item; + this.opcode = Opcode.getOpcodeByValue(bytes[0]); + if (!this.opcode.referenceType.checkItem(item)) { + throw new RuntimeException("item is not the correct type for this opcode (got " + item.getClass().toString() + ", expecting " + opcode.referenceType.toString() + ")"); + } + } + + public void readFrom(Input in) { + int startPos = in.getCursor(); + + byte opByte = in.readByte(); + + if (opByte == 0x00) { + reference = null; + byte secondByte = in.readByte(); + + int count; + + + switch (secondByte) { + case 0x00: + /** nop */ + bytes = new byte[] { 0x00, 0x00 }; + return; + case 0x01: + /** packed switch */ + count = in.readShort(); + in.setCursor(startPos); + bytes = in.readBytes((count * 4) + 8); + return; + case 0x02: + /** sparse switch */ + count = in.readShort(); + in.setCursor(startPos); + bytes = in.readBytes((count * 8) + 4); + return; + case 0x03: + /** fill array data */ + int elementWidth = in.readShort(); + count = in.readInt(); + in.setCursor(startPos); + bytes = in.readBytes(((elementWidth * count + 1)/2 + 4) * 2); + return; + default: + throw new RuntimeException("Invalid 2nd byte for opcode 0x00"); + } + } + + this.opcode = Opcode.getOpcodeByValue(opByte); + + if (opcode.referenceType != ReferenceType.none) { + in.skipBytes(1); + int referenceIndex = in.readShort(); + + //handle const string/jumbo as a special case + if (opByte == 0x1b) { + int hiWord = in.readShort(); + if (hiWord != 0) { + throw new RuntimeException("32bit string indexes are not supported yet."); + } + } + + switch (opcode.referenceType) { + case string: + reference = dexFile.StringIdsSection.getByIndex(referenceIndex); + break; + case type: + reference = dexFile.TypeIdsSection.getByIndex(referenceIndex); + break; + case field: + reference = dexFile.FieldIdsSection.getByIndex(referenceIndex); + break; + case method: + reference = dexFile.MethodIdsSection.getByIndex(referenceIndex); + break; + } + } else { + reference = null; + } + + in.setCursor(startPos); + bytes = in.readBytes(opcode.numBytes); + } + + public void writeTo(Output out) { + if (bytes[0] == 0 && bytes[1] > 0) { + //the "special instructions" must be 4 byte aligned + out.alignTo(4); + out.write(bytes); + } else if (reference == null) { + out.write(bytes); + } else { + out.write(bytes,0,2); + if (bytes[0] == 0x1b) { + out.writeInt(reference.getIndex()); + } else { + int index = reference.getIndex(); + if (index > 0xFFFF) { + throw new RuntimeException("String index doesn't fit."); + } + out.writeShort(reference.getIndex()); + out.write(bytes, 4, bytes.length - 4); + } + } + } + + public void copyTo(DexFile dexFile, Instruction copy) { + copy.bytes = bytes; + copy.opcode = opcode; + + switch (opcode.referenceType) { + case string: + copy.reference = dexFile.StringIdsSection.intern(dexFile, (StringIdItem)reference); + break; + case type: + copy.reference = dexFile.TypeIdsSection.intern(dexFile, (TypeIdItem)reference); + break; + case field: + copy.reference = dexFile.FieldIdsSection.intern(dexFile, (FieldIdItem)reference); + break; + case method: + copy.reference = dexFile.MethodIdsSection.intern(dexFile, (MethodIdItem)reference); + break; + case none: + break; + } + } + + public int place(int offset) { + return offset + bytes.length; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/code/Opcode.java b/src/main/java/org/JesusFreke/dexlib/code/Opcode.java new file mode 100644 index 00000000..2a494db5 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/code/Opcode.java @@ -0,0 +1,300 @@ +/* + * [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.JesusFreke.dexlib.code; + +import java.util.ArrayList; +import java.util.HashMap; + +public enum Opcode +{ + NOP((byte)0x00, "NOP", (byte)2, ReferenceType.none, "10x"), + MOVE((byte)0x01, "MOVE", (byte)2, ReferenceType.none, "12x"), + MOVE_FROM16((byte)0x02, "MOVE/FROM16", (byte)4, ReferenceType.none, "22x"), + MOVE_16((byte)0x03, "MOVE/16", (byte)6, ReferenceType.none, "32x"), + MOVE_WIDE((byte)0x04, "MOVE-WIDE", (byte)2, ReferenceType.none, "12x"), + MOVE_WIDE_FROM16((byte)0x05, "MOVE-WIDE/FROM16", (byte)4, ReferenceType.none, "22x"), + MOVE_WIDE_16((byte)0x06, "MOVE-WIDE/16", (byte)6, ReferenceType.none, "32x"), + MOVE_OBJECT((byte)0x07, "MOVE-OBJECT", (byte)2, ReferenceType.none, "12x"), + MOVE_OBJECT_FROM16((byte)0x08, "MOVE-OBJECT/FROM16", (byte)4, ReferenceType.none, "22x"), + MOVE_OBJECT_16((byte)0x09, "MOVE-OBJECT/16", (byte)6, ReferenceType.none, "32x"), + MOVE_RESULT((byte)0x0a, "MOVE-RESULT", (byte)2, ReferenceType.none, "11x"), + MOVE_RESULT_WIDE((byte)0x0b, "MOVE-RESULT-WIDE", (byte)2, ReferenceType.none, "11x"), + MOVE_RESULT_OBJECT((byte)0x0c, "MOVE-RESULT-OBJECT", (byte)2, ReferenceType.none, "11x"), + MOVE_EXCEPTION((byte)0x0d, "MOVE-EXCEPTION", (byte)2, ReferenceType.none, "11x"), + RETURN_VOID((byte)0x0e, "RETURN-VOID", (byte)2, ReferenceType.none, "10x"), + RETURN((byte)0x0f, "RETURN", (byte)2, ReferenceType.none, "11x"), + RETURN_WIDE((byte)0x10, "RETURN-WIDE", (byte)2, ReferenceType.none, "11x"), + RETURN_OBJECT((byte)0x11, "RETURN-OBJECT", (byte)2, ReferenceType.none, "11x"), + CONST_4((byte)0x12, "CONST-4", (byte)2, ReferenceType.none, "11n"), + CONST_16((byte)0x13, "CONST/16", (byte)4, ReferenceType.none, "21s"), + CONST((byte)0x14, "CONST", (byte)6, ReferenceType.none, "31i"), + CONST_HIGH16((byte)0x15, "CONST/HIGH16", (byte)4, ReferenceType.none, "21h"), + CONST_WIDE_16((byte)0x16, "CONST-WIDE/16", (byte)4, ReferenceType.none, "21s"), + CONST_WIDE_32((byte)0x17, "CONST-WIDE/32", (byte)6, ReferenceType.none, "31i"), + CONST_WIDE((byte)0x18, "CONST-WIDE", (byte)10, ReferenceType.none, "51l"), + CONST_WIDE_HIGH16((byte)0x19, "CONST-WIDE/HIGH16", (byte)4, ReferenceType.none, "21h"), + CONST_STRING((byte)0x1a, "CONST-STRING", (byte)4, ReferenceType.string, "21c"), + CONST_STRING_JUMBO((byte)0x1b, "CONST-STRING/JUMBO", (byte)6, ReferenceType.string, "31c"), + CONST_CLASS((byte)0x1c, "CONST-CLASS", (byte)4, ReferenceType.type, "21c"), + MONITOR_ENTER((byte)0x1d, "MONITOR-ENTER", (byte)2, ReferenceType.none, "11x"), + MONITOR_EXIT((byte)0x1e, "MONITOR-EXIT", (byte)2, ReferenceType.none, "11x"), + CHECK_CAST((byte)0x1f, "CHECK-CAST", (byte)4, ReferenceType.type, "21c"), + INSTANCE_OF((byte)0x20, "INSTANCE-OF", (byte)4, ReferenceType.type, "22c"), + ARRAY_LENGTH((byte)0x21, "ARRAY-LENGTH", (byte)2, ReferenceType.none, "12x"), + NEW_INSTANCE((byte)0x22, "NEW-INSTANCE", (byte)4, ReferenceType.type, "21c"), + NEW_ARRAY((byte)0x23, "NEW-ARRAY", (byte)4, ReferenceType.type, "22c"), + FILLED_NEW_ARRAY((byte)0x24, "FILLED-NEW-ARRAY", (byte)6, ReferenceType.type, "35c"), + FILLED_NEW_ARRAY_RANGE((byte)0x25, "FILLED-NEW-ARRAY-RANGE", (byte)6, ReferenceType.type, "3rc"), + FILL_ARRAY_DATA((byte)0x26, "FILL-ARRAY-DATA", (byte)6, ReferenceType.none, "31t"), + THROW((byte)0x27, "THROW", (byte)2, ReferenceType.none, "11x"), + GOTO((byte)0x28, "GOTO", (byte)2, ReferenceType.none, "10t"), + GOTO_16((byte)0x29, "GOTO/16", (byte)4, ReferenceType.none, "20t"), + GOTO_32((byte)0x2a, "GOTO/32", (byte)6, ReferenceType.none, "30t"), + PACKED_SWITCH((byte)0x2b, "PACKED-SWITCH", (byte)6, ReferenceType.none, "31t"), + SPARSE_SWITCH((byte)0x2c, "SPARSE-SWITCH", (byte)6, ReferenceType.none, "31t"), + CMPL_FLOAT((byte)0x2d, "CMPL-FLOAT", (byte)4, ReferenceType.none, "23x"), + CMPG_FLOAT((byte)0x2e, "CMPG-FLOAT", (byte)4, ReferenceType.none, "23x"), + CMPL_DOUBLE((byte)0x2f, "CMPL-DOUBLE", (byte)4, ReferenceType.none, "23x"), + CMPG_DOUBLE((byte)0x30, "CMPG-DOUBLE", (byte)4, ReferenceType.none, "23x"), + CMP_LONG((byte)0x31, "CMP-LONG", (byte)4, ReferenceType.none, "23x"), + IF_EQ((byte)0x32, "IF-EQ", (byte)4, ReferenceType.none, "22t"), + IF_NE((byte)0x33, "IF-NE", (byte)4, ReferenceType.none, "22t"), + IF_LT((byte)0x34, "IF-LT", (byte)4, ReferenceType.none, "22t"), + IF_GE((byte)0x35, "IF-GE", (byte)4, ReferenceType.none, "22t"), + IF_GT((byte)0x36, "IF-GT", (byte)4, ReferenceType.none, "22t"), + IF_LE((byte)0x37, "IF-LE", (byte)4, ReferenceType.none, "22t"), + IF_EQZ((byte)0x38, "IF-EQZ", (byte)4, ReferenceType.none, "21t"), + IF_NEZ((byte)0x39, "IF-NEZ", (byte)4, ReferenceType.none, "21t"), + IF_LTZ((byte)0x3a, "IF-LTZ", (byte)4, ReferenceType.none, "21t"), + IF_GEZ((byte)0x3b, "IF-GEZ", (byte)4, ReferenceType.none, "21t"), + IF_GTZ((byte)0x3c, "IF-GTZ", (byte)4, ReferenceType.none, "21t"), + IF_LEZ((byte)0x3d, "IF-LEZ", (byte)4, ReferenceType.none, "21t"), + AGET((byte)0x44, "AGET", (byte)4, ReferenceType.none, "23x"), + AGET_WIDE((byte)0x45, "AGET-WIDE", (byte)4, ReferenceType.none, "23x"), + AGET_OBJECT((byte)0x46, "AGET-OBJECT", (byte)4, ReferenceType.none, "23x"), + AGET_BOOLEAN((byte)0x47, "AGET-BOOLEAN", (byte)4, ReferenceType.none, "23x"), + AGET_BYTE((byte)0x48, "AGET-BYTE", (byte)4, ReferenceType.none, "23x"), + AGET_CHAR((byte)0x49, "AGET-CHAR", (byte)4, ReferenceType.none, "23x"), + AGET_SHORT((byte)0x4a, "AGET-SHORT", (byte)4, ReferenceType.none, "23x"), + APUT((byte)0x4b, "APUT", (byte)4, ReferenceType.none, "23x"), + APUT_WIDE((byte)0x4c, "APUT-WIDE", (byte)4, ReferenceType.none, "23x"), + APUT_OBJECT((byte)0x4d, "APUT-OBJECT", (byte)4, ReferenceType.none, "23x"), + APUT_BOOLEAN((byte)0x4e, "APUT-BOOLEAN", (byte)4, ReferenceType.none, "23x"), + APUT_BYTE((byte)0x4f, "APUT-BYTE", (byte)4, ReferenceType.none, "23x"), + APUT_CHAR((byte)0x50, "APUT-CHAR", (byte)4, ReferenceType.none, "23x"), + APUT_SHORT((byte)0x51, "APUT-SHORT", (byte)4, ReferenceType.none, "23x"), + IGET((byte)0x52, "IGET", (byte)4, ReferenceType.field, "22c"), + IGET_WIDE((byte)0x53, "IGET-WIDE", (byte)4, ReferenceType.field, "22c"), + IGET_OBJECT((byte)0x54, "IGET-OBJECT", (byte)4, ReferenceType.field, "22c"), + IGET_BOOLEAN((byte)0x55, "IGET-BOOLEAN", (byte)4, ReferenceType.field, "22c"), + IGET_BYTE((byte)0x56, "IGET-BYTE", (byte)4, ReferenceType.field, "22c"), + IGET_CHAR((byte)0x57, "IGET-CHAR", (byte)4, ReferenceType.field, "22c"), + IGET_SHORT((byte)0x58, "IGET-SHORT", (byte)4, ReferenceType.field, "22c"), + IPUT((byte)0x59, "IPUT", (byte)4, ReferenceType.field, "22c"), + IPUT_WIDE((byte)0x5a, "IPUT-WIDE", (byte)4, ReferenceType.field, "22c"), + IPUT_OBJECT((byte)0x5b, "IPUT-OBJECT", (byte)4, ReferenceType.field, "22c"), + IPUT_BOOLEAN((byte)0x5c, "IPUT-BOOLEAN", (byte)4, ReferenceType.field, "22c"), + IPUT_BYTE((byte)0x5d, "IPUT-BYTE", (byte)4, ReferenceType.field, "22c"), + IPUT_CHAR((byte)0x5e, "IPUT-CHAR", (byte)4, ReferenceType.field, "22c"), + IPUT_SHORT((byte)0x5f, "IPUT-SHORT", (byte)4, ReferenceType.field, "22c"), + SGET((byte)0x60, "SGET", (byte)4, ReferenceType.field, "21c"), + SGET_WIDE((byte)0x61, "SGET-WIDE", (byte)4, ReferenceType.field, "21c"), + SGET_OBJECT((byte)0x62, "SGET-OBJECT", (byte)4, ReferenceType.field, "21c"), + SGET_BOOLEAN((byte)0x63, "SGET-BOOLEAN", (byte)4, ReferenceType.field, "21c"), + SGET_BYTE((byte)0x64, "SGET-BYTE", (byte)4, ReferenceType.field, "21c"), + SGET_CHAR((byte)0x65, "SGET-CHAR", (byte)4, ReferenceType.field, "21c"), + SGET_SHORT((byte)0x66, "SGET-SHORT", (byte)4, ReferenceType.field, "21c"), + SPUT((byte)0x67, "SPUT", (byte)4, ReferenceType.field, "21c"), + SPUT_WIDE((byte)0x68, "SPUT-WIDE", (byte)4, ReferenceType.field, "21c"), + SPUT_OBJECT((byte)0x69, "SPUT-OBJECT", (byte)4, ReferenceType.field, "21c"), + SPUT_BOOLEAN((byte)0x6a, "SPUT-BOOLEAN", (byte)4, ReferenceType.field, "21c"), + SPUT_BYTE((byte)0x6b, "SPUT-BYTE", (byte)4, ReferenceType.field, "21c"), + SPUT_CHAR((byte)0x6c, "SPUT-CHAR", (byte)4, ReferenceType.field, "21c"), + SPUT_SHORT((byte)0x6d, "SPUT-SHORT", (byte)4, ReferenceType.field, "21c"), + INVOKE_VIRTUAL((byte)0x6e, "INVOKE-VIRTUAL", (byte)6, ReferenceType.method, "35c"), + INVOKE_SUPER((byte)0x6f, "INVOKE-SUPER", (byte)6, ReferenceType.method, "35c"), + INVOKE_DIRECT((byte)0x70, "INVOKE-DIRECT", (byte)6, ReferenceType.method, "35c"), + INVOKE_STATIC((byte)0x71, "INVOKE-STATIC", (byte)6, ReferenceType.method, "35c"), + INVOKE_INTERFACE((byte)0x72, "INVOKE-INTERFACE", (byte)6, ReferenceType.method, "35c"), + INVOKE_VIRTUAL_RANGE((byte)0x74, "INVOKE-VIRTUAL/RANGE", (byte)6, ReferenceType.method, "3rc"), + INVOKE_SUPER_RANGE((byte)0x75, "INVOKE-SUPER/RANGE", (byte)6, ReferenceType.method, "3rc"), + INVOKE_DIRECT_RANGE((byte)0x76, "INVOKE-DIRECT/RANGE", (byte)6, ReferenceType.method, "3rc"), + INVOKE_STATIC_RANGE((byte)0x77, "INVOKE-STATIC/RANGE", (byte)6, ReferenceType.method, "3rc"), + INVOKE_INTERFACE_RANGE((byte)0x78, "INVOKE-INTERFACE/RANGE", (byte)6, ReferenceType.method, "3rc"), + NEG_INT((byte)0x7b, "NEG-INT", (byte)2, ReferenceType.none, "12x"), + NOT_INT((byte)0x7c, "NOT-INT", (byte)2, ReferenceType.none, "12x"), + NEG_LONG((byte)0x7d, "NEG-LONG", (byte)2, ReferenceType.none, "12x"), + NOT_LONG((byte)0x7e, "NOT-LONG", (byte)2, ReferenceType.none, "12x"), + NEG_FLOAT((byte)0x7f, "NEG-FLOAT", (byte)2, ReferenceType.none, "12x"), + NEG_DOUBLE((byte)0x80, "NEG-DOUBLE", (byte)2, ReferenceType.none, "12x"), + INT_TO_LONG((byte)0x81, "INT-TO-LONG", (byte)2, ReferenceType.none, "12x"), + INT_TO_FLOAT((byte)0x82, "INT-TO-FLOAT", (byte)2, ReferenceType.none, "12x"), + INT_TO_DOUBLE((byte)0x83, "INT-TO-DOUBLE", (byte)2, ReferenceType.none, "12x"), + LONG_TO_INT((byte)0x84, "LONG-TO-INT", (byte)2, ReferenceType.none, "12x"), + LONG_TO_FLOAT((byte)0x85, "LONG-TO-FLOAT", (byte)2, ReferenceType.none, "12x"), + LONG_TO_DOUBLE((byte)0x86, "LONG-TO-DOUBLE", (byte)2, ReferenceType.none, "12x"), + FLOAT_TO_INT((byte)0x87, "FLOAT-TO-INT", (byte)2, ReferenceType.none, "12x"), + FLOAT_TO_LONG((byte)0x88, "FLOAT-TO-LONG", (byte)2, ReferenceType.none, "12x"), + FLOAT_TO_DOUBLE((byte)0x89, "FLOAT-TO-DOUBLE", (byte)2, ReferenceType.none, "12x"), + DOUBLE_TO_INT((byte)0x8a, "DOUBLE-TO-INT", (byte)2, ReferenceType.none, "12x"), + DOUBLE_TO_LONG((byte)0x8b, "DOUBLE-TO-LONG", (byte)2, ReferenceType.none, "12x"), + DOUBLE_TO_FLOAT((byte)0x8c, "DOUBLE-TO-FLOAT", (byte)2, ReferenceType.none, "12x"), + INT_TO_BYTE((byte)0x8d, "INT-TO-BYTE", (byte)2, ReferenceType.none, "12x"), + INT_TO_CHAR((byte)0x8e, "INT-TO-CHAR", (byte)2, ReferenceType.none, "12x"), + INT_TO_SHORT((byte)0x8f, "INT-TO-SHORT", (byte)2, ReferenceType.none, "12x"), + ADD_INT((byte)0x90, "ADD-INT", (byte)4, ReferenceType.none, "23x"), + SUB_INT((byte)0x91, "SUB-INT", (byte)4, ReferenceType.none, "23x"), + MUL_INT((byte)0x92, "MUL-INT", (byte)4, ReferenceType.none, "23x"), + DIV_INT((byte)0x93, "DIV-INT", (byte)4, ReferenceType.none, "23x"), + REM_INT((byte)0x94, "REM-INT", (byte)4, ReferenceType.none, "23x"), + AND_INT((byte)0x95, "AND-INT", (byte)4, ReferenceType.none, "23x"), + OR_INT((byte)0x96, "OR-INT", (byte)4, ReferenceType.none, "23x"), + XOR_INT((byte)0x97, "XOR-INT", (byte)4, ReferenceType.none, "23x"), + SHL_INT((byte)0x98, "SHL-INT", (byte)4, ReferenceType.none, "23x"), + SHR_INT((byte)0x99, "SHR-INT", (byte)4, ReferenceType.none, "23x"), + USHR_INT((byte)0x9a, "USHR-INT", (byte)4, ReferenceType.none, "23x"), + ADD_LONG((byte)0x9b, "ADD-LONG", (byte)4, ReferenceType.none, "23x"), + SUB_LONG((byte)0x9c, "SUB-LONG", (byte)4, ReferenceType.none, "23x"), + MUL_LONG((byte)0x9d, "MUL-LONG", (byte)4, ReferenceType.none, "23x"), + DIV_LONG((byte)0x9e, "DIV-LONG", (byte)4, ReferenceType.none, "23x"), + REM_LONG((byte)0x9f, "REM-LONG", (byte)4, ReferenceType.none, "23x"), + AND_LONG((byte)0xa0, "AND-LONG", (byte)4, ReferenceType.none, "23x"), + OR_LONG((byte)0xa1, "OR-LONG", (byte)4, ReferenceType.none, "23x"), + XOR_LONG((byte)0xa2, "XOR-LONG", (byte)4, ReferenceType.none, "23x"), + SHL_LONG((byte)0xa3, "SHL-LONG", (byte)4, ReferenceType.none, "23x"), + SHR_LONG((byte)0xa4, "SHR-LONG", (byte)4, ReferenceType.none, "23x"), + USHR_LONG((byte)0xa5, "USHR-LONG", (byte)4, ReferenceType.none, "23x"), + ADD_FLOAT((byte)0xa6, "ADD-FLOAT", (byte)4, ReferenceType.none, "23x"), + SUB_FLOAT((byte)0xa7, "SUB-FLOAT", (byte)4, ReferenceType.none, "23x"), + MUL_FLOAT((byte)0xa8, "MUL-FLOAT", (byte)4, ReferenceType.none, "23x"), + DIV_FLOAT((byte)0xa9, "DIV-FLOAT", (byte)4, ReferenceType.none, "23x"), + REM_FLOAT((byte)0xaa, "REM-FLOAT", (byte)4, ReferenceType.none, "23x"), + ADD_DOUBLE((byte)0xab, "ADD-DOUBLE", (byte)4, ReferenceType.none, "23x"), + SUB_DOUBLE((byte)0xac, "SUB-DOUBLE", (byte)4, ReferenceType.none, "23x"), + MUL_DOUBLE((byte)0xad, "MUL-DOUBLE", (byte)4, ReferenceType.none, "23x"), + DIV_DOUBLE((byte)0xae, "DIV-DOUBLE", (byte)4, ReferenceType.none, "23x"), + REM_DOUBLE((byte)0xaf, "REM-DOUBLE", (byte)4, ReferenceType.none, "23x"), + ADD_INT_2ADDR((byte)0xb0, "ADD-INT/2ADDR", (byte)2, ReferenceType.none, "12x"), + SUB_INT_2ADDR((byte)0xb1, "SUB-INT/2ADDR", (byte)2, ReferenceType.none, "12x"), + MUL_INT_2ADDR((byte)0xb2, "MUL-INT/2ADDR", (byte)2, ReferenceType.none, "12x"), + DIV_INT_2ADDR((byte)0xb3, "DIV-INT/2ADDR", (byte)2, ReferenceType.none, "12x"), + REM_INT_2ADDR((byte)0xb4, "REM-INT/2ADDR", (byte)2, ReferenceType.none, "12x"), + AND_INT_2ADDR((byte)0xb5, "AND-INT/2ADDR", (byte)2, ReferenceType.none, "12x"), + OR_INT_2ADDR((byte)0xb6, "OR-INT/2ADDR", (byte)2, ReferenceType.none, "12x"), + XOR_INT_2ADDR((byte)0xb7, "XOR-INT/2ADDR", (byte)2, ReferenceType.none, "12x"), + SHL_INT_2ADDR((byte)0xb8, "SHL-INT/2ADDR", (byte)2, ReferenceType.none, "12x"), + SHR_INT_2ADDR((byte)0xb9, "SHR-INT/2ADDR", (byte)2, ReferenceType.none, "12x"), + USHR_INT_2ADDR((byte)0xba, "USHR-INT/2ADDR", (byte)2, ReferenceType.none, "12x"), + ADD_LONG_2ADDR((byte)0xbb, "ADD-LONG/2ADDR", (byte)2, ReferenceType.none, "12x"), + SUB_LONG_2ADDR((byte)0xbc, "SUB-LONG/2ADDR", (byte)2, ReferenceType.none, "12x"), + MUL_LONG_2ADDR((byte)0xbd, "MUL-LONG/2ADDR", (byte)2, ReferenceType.none, "12x"), + DIV_LONG_2ADDR((byte)0xbe, "DIV-LONG/2ADDR", (byte)2, ReferenceType.none, "12x"), + REM_LONG_2ADDR((byte)0xbf, "REM-LONG/2ADDR", (byte)2, ReferenceType.none, "12x"), + AND_LONG_2ADDR((byte)0xc0, "AND-LONG/2ADDR", (byte)2, ReferenceType.none, "12x"), + OR_LONG_2ADDR((byte)0xc1, "OR-LONG/2ADDR", (byte)2, ReferenceType.none, "12x"), + XOR_LONG_2ADDR((byte)0xc2, "XOR-LONG/2ADDR", (byte)2, ReferenceType.none, "12x"), + SHL_LONG_2ADDR((byte)0xc3, "SHL-LONG/2ADDR", (byte)2, ReferenceType.none, "12x"), + SHR_LONG_2ADDR((byte)0xc4, "SHR-LONG/2ADDR", (byte)2, ReferenceType.none, "12x"), + USHR_LONG_2ADDR((byte)0xc5, "USHR-LONG/2ADDR", (byte)2, ReferenceType.none, "12x"), + ADD_FLOAT_2ADDR((byte)0xc6, "ADD-FLOAT/2ADDR", (byte)2, ReferenceType.none, "12x"), + SUB_FLOAT_2ADDR((byte)0xc7, "SUB-FLOAT/2ADDR", (byte)2, ReferenceType.none, "12x"), + MUL_FLOAT_2ADDR((byte)0xc8, "MUL-FLOAT/2ADDR", (byte)2, ReferenceType.none, "12x"), + DIV_FLOAT_2ADDR((byte)0xc9, "DIV-FLOAT/2ADDR", (byte)2, ReferenceType.none, "12x"), + REM_FLOAT_2ADDR((byte)0xca, "REM-FLOAT/2ADDR", (byte)2, ReferenceType.none, "12x"), + ADD_DOUBLE_2ADDR((byte)0xcb, "ADD-DOUBLE/2ADDR", (byte)2, ReferenceType.none, "12x"), + SUB_DOUBLE_2ADDR((byte)0xcc, "SUB-DOUBLE/2ADDR", (byte)2, ReferenceType.none, "12x"), + MUL_DOUBLE_2ADDR((byte)0xcd, "MUL-DOUBLE/2ADDR", (byte)2, ReferenceType.none, "12x"), + DIV_DOUBLE_2ADDR((byte)0xce, "DIV-DOUBLE/2ADDR", (byte)2, ReferenceType.none, "12x"), + REM_DOUBLE_2ADDR((byte)0xcf, "REM-DOUBLE/2ADDR", (byte)2, ReferenceType.none, "12x"), + ADD_INT_LIT16((byte)0xd0, "ADD-INT/LIT16", (byte)4, ReferenceType.none, "22s"), + RSUB_INT_LIT16((byte)0xd1, "RSUB-INT/LIT16", (byte)4, ReferenceType.none, "22s"), + MUL_INT_LIT16((byte)0xd2, "MUL-INT/LIT16", (byte)4, ReferenceType.none, "22s"), + DIV_INT_LIT16((byte)0xd3, "DIV-INT/LIT16", (byte)4, ReferenceType.none, "22s"), + REM_INT_LIT16((byte)0xd4, "REM-INT/LIT16", (byte)4, ReferenceType.none, "22s"), + AND_INT_LIT16((byte)0xd5, "AND-INT/LIT16", (byte)4, ReferenceType.none, "22s"), + OR_INT_LIT16((byte)0xd6, "OR-INT/LIT16", (byte)4, ReferenceType.none, "22s"), + XOR_INT_LIT16((byte)0xd7, "XOR-INT/LIT16", (byte)4, ReferenceType.none, "22s"), + ADD_INT_LIT8((byte)0xd8, "ADD-INT/LIT8", (byte)4, ReferenceType.none, "22b"), + RSUB_INT_LIT8((byte)0xd9, "RSUB-INT/LIT8", (byte)4, ReferenceType.none, "22b"), + MUL_INT_LIT8((byte)0xda, "MUL-INT/LIT8", (byte)4, ReferenceType.none, "22b"), + DIV_INT_LIT8((byte)0xdb, "DIV-INT/LIT8", (byte)4, ReferenceType.none, "22b"), + REM_INT_LIT8((byte)0xdc, "REM-INT/LIT8", (byte)4, ReferenceType.none, "22b"), + AND_INT_LIT8((byte)0xdd, "AND-INT/LIT8", (byte)4, ReferenceType.none, "22b"), + OR_INT_LIT8((byte)0xde, "OR-INT/LIT8", (byte)4, ReferenceType.none, "22b"), + XOR_INT_LIT8((byte)0xdf, "XOR-INT/LIT8", (byte)4, ReferenceType.none, "22b"), + SHL_INT_LIT8((byte)0xe0, "SHL-INT/LIT8", (byte)4, ReferenceType.none, "22b"), + SHR_INT_LIT8((byte)0xe1, "SHR-INT/LIT8", (byte)4, ReferenceType.none, "22b"), + USHR_INT_LIT8((byte)0xe2, "USHR-INT/LIT8", (byte)4, ReferenceType.none, "22b"); + + + + private static ArrayList opcodesByValue; + private static HashMap opcodesByName; + + static { + try + { + opcodesByValue = new ArrayList(); + opcodesByName = new HashMap(); + + for (int i=0; i<0x100; i++) { + opcodesByValue.add(null); + } + + for (Opcode opcode: Opcode.values()) { + opcodesByValue.set((opcode.value & 0xFF), opcode); + opcodesByName.put(opcode.name.toLowerCase().hashCode(), opcode); + } + }catch (Exception ex) { + System.out.println(ex.toString()); + } + } + + public static Opcode getOpcodeByName(String opcodeName) { + return opcodesByName.get(opcodeName.toLowerCase().hashCode()); + } + + public static Opcode getOpcodeByValue(byte opcodeValue) { + return opcodesByValue.get(opcodeValue); + } + + public final byte value; + public final String name; + public final byte numBytes; + public final ReferenceType referenceType; + public final String format; + + Opcode(byte opcodeValue, String opcodeName, byte numBytes, ReferenceType referenceType, String format) { + this.value = opcodeValue; + this.name = opcodeName; + this.numBytes = numBytes; + this.referenceType = referenceType; + this.format = format; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/code/ReferenceType.java b/src/main/java/org/JesusFreke/dexlib/code/ReferenceType.java new file mode 100644 index 00000000..21024834 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/code/ReferenceType.java @@ -0,0 +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.JesusFreke.dexlib.code; + +import org.JesusFreke.dexlib.*; + +public enum ReferenceType +{ + string, + type, + field, + method, + none; + + public boolean checkItem(IndexedItem 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/src/main/java/org/JesusFreke/dexlib/debug/AdvanceLine.java b/src/main/java/org/JesusFreke/dexlib/debug/AdvanceLine.java new file mode 100644 index 00000000..01b984dc --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/debug/AdvanceLine.java @@ -0,0 +1,53 @@ +/* + * [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.JesusFreke.dexlib.debug; + +import org.JesusFreke.dexlib.CompositeField; +import org.JesusFreke.dexlib.Field; +import org.JesusFreke.dexlib.ByteField; +import org.JesusFreke.dexlib.SignedLeb128Field; + +public class AdvanceLine extends CompositeField implements DebugInstruction { + private final Field[] fields; + + public AdvanceLine() { + fields = new Field[] { + new ByteField((byte)0x02), + new SignedLeb128Field() + }; + } + + protected Field[] getFields() { + return fields; + } + + public byte getOpcode() { + return 0x02; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/debug/AdvancePC.java b/src/main/java/org/JesusFreke/dexlib/debug/AdvancePC.java new file mode 100644 index 00000000..887bdf16 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/debug/AdvancePC.java @@ -0,0 +1,50 @@ +/* + * [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.JesusFreke.dexlib.debug; + +import org.JesusFreke.dexlib.*; + +public class AdvancePC extends CompositeField implements DebugInstruction { + private final Field[] fields; + + public AdvancePC() { + fields = new Field[] { + new ByteField((byte)0x01), + new Leb128Field() + }; + } + + protected Field[] getFields() { + return fields; + } + + public byte getOpcode() { + return 0x01; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/debug/DebugInstruction.java b/src/main/java/org/JesusFreke/dexlib/debug/DebugInstruction.java new file mode 100644 index 00000000..847b7201 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/debug/DebugInstruction.java @@ -0,0 +1,35 @@ +/* + * [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.JesusFreke.dexlib.debug; + +import org.JesusFreke.dexlib.Field; + +public interface DebugInstruction extends Field { + public byte getOpcode(); +} diff --git a/src/main/java/org/JesusFreke/dexlib/debug/DebugInstructionFactory.java b/src/main/java/org/JesusFreke/dexlib/debug/DebugInstructionFactory.java new file mode 100644 index 00000000..c5587a02 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/debug/DebugInstructionFactory.java @@ -0,0 +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.JesusFreke.dexlib.debug; + +import org.JesusFreke.dexlib.DexFile; +import org.JesusFreke.dexlib.util.Input; + +public abstract class DebugInstructionFactory { + public static DebugInstruction readDebugInstruction(DexFile dexFile, Input in) { + int startCursor = in.getCursor(); + byte opcode = in.readByte(); + in.setCursor(startCursor); + + DebugInstruction debugInstruction = makeDebugInstruction(dexFile, opcode); + debugInstruction.readFrom(in); + return debugInstruction; + } + + public static DebugInstruction makeDebugInstruction(DexFile dexFile, byte opcode) { + switch (opcode) { + case 0x00: + return new EndSequence(); + case 0x01: + return new AdvancePC(); + case 0x02: + return new AdvanceLine(); + case 0x03: + return new StartLocal(dexFile); + case 0x04: + return new StartLocalExtended(dexFile); + case 0x05: + return new EndLocal(); + case 0x06: + return new RestartLocal(); + case 0x07: + return new SetPrologueEnd(); + case 0x08: + return new SetEpilogueBegin(); + case 0x09: + return new SetFile(dexFile); + default: + return new SpecialOpcode(opcode); + } + + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/debug/EndLocal.java b/src/main/java/org/JesusFreke/dexlib/debug/EndLocal.java new file mode 100644 index 00000000..22594dba --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/debug/EndLocal.java @@ -0,0 +1,50 @@ +/* + * [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.JesusFreke.dexlib.debug; + +import org.JesusFreke.dexlib.*; + +public class EndLocal extends CompositeField implements DebugInstruction { + private final Field[] fields; + + public EndLocal() { + fields = new Field[] { + new ByteField((byte)0x05), + new Leb128Field() + }; + } + + protected Field[] getFields() { + return fields; + } + + public byte getOpcode() { + return 0x05; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/debug/EndSequence.java b/src/main/java/org/JesusFreke/dexlib/debug/EndSequence.java new file mode 100644 index 00000000..c5cd6c3a --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/debug/EndSequence.java @@ -0,0 +1,51 @@ +/* + * [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.JesusFreke.dexlib.debug; + +import org.JesusFreke.dexlib.CompositeField; +import org.JesusFreke.dexlib.Field; +import org.JesusFreke.dexlib.ByteField; + +public class EndSequence extends CompositeField implements DebugInstruction { + private final Field[] fields; + + public EndSequence() { + fields = new Field[] { + new ByteField((byte)0x00) + }; + } + + protected Field[] getFields() { + return fields; + } + + public byte getOpcode() { + return 0x00; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/debug/RestartLocal.java b/src/main/java/org/JesusFreke/dexlib/debug/RestartLocal.java new file mode 100644 index 00000000..0d1e4c02 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/debug/RestartLocal.java @@ -0,0 +1,50 @@ +/* + * [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.JesusFreke.dexlib.debug; + +import org.JesusFreke.dexlib.*; + +public class RestartLocal extends CompositeField implements DebugInstruction { + private final Field[] fields; + + public RestartLocal() { + fields = new Field[] { + new ByteField((byte)0x06), + new SignedLeb128Field() + }; + } + + protected Field[] getFields() { + return fields; + } + + public byte getOpcode() { + return 0x06; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/debug/SetEpilogueBegin.java b/src/main/java/org/JesusFreke/dexlib/debug/SetEpilogueBegin.java new file mode 100644 index 00000000..b7524647 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/debug/SetEpilogueBegin.java @@ -0,0 +1,51 @@ +/* + * [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.JesusFreke.dexlib.debug; + +import org.JesusFreke.dexlib.CompositeField; +import org.JesusFreke.dexlib.Field; +import org.JesusFreke.dexlib.ByteField; + +public class SetEpilogueBegin extends CompositeField implements DebugInstruction { + private final Field[] fields; + + public SetEpilogueBegin() { + fields = new Field[] { + new ByteField((byte)0x08) + }; + } + + protected Field[] getFields() { + return fields; + } + + public byte getOpcode() { + return 0x08; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/debug/SetFile.java b/src/main/java/org/JesusFreke/dexlib/debug/SetFile.java new file mode 100644 index 00000000..0371cc71 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/debug/SetFile.java @@ -0,0 +1,50 @@ +/* + * [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.JesusFreke.dexlib.debug; + +import org.JesusFreke.dexlib.*; + +public class SetFile extends CompositeField implements DebugInstruction { + private final Field[] fields; + + public SetFile(DexFile dexFile) { + fields = new Field[] { + new ByteField((byte)0x09), + new IndexedItemReference(dexFile.StringIdsSection, new Leb128p1Field()) + }; + } + + protected Field[] getFields() { + return fields; + } + + public byte getOpcode() { + return 0x09; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/debug/SetPrologueEnd.java b/src/main/java/org/JesusFreke/dexlib/debug/SetPrologueEnd.java new file mode 100644 index 00000000..c111029a --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/debug/SetPrologueEnd.java @@ -0,0 +1,51 @@ +/* + * [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.JesusFreke.dexlib.debug; + +import org.JesusFreke.dexlib.CompositeField; +import org.JesusFreke.dexlib.Field; +import org.JesusFreke.dexlib.ByteField; + +public class SetPrologueEnd extends CompositeField implements DebugInstruction { + private final Field[] fields; + + public SetPrologueEnd() { + fields = new Field[] { + new ByteField((byte)0x07) + }; + } + + protected Field[] getFields() { + return fields; + } + + public byte getOpcode() { + return 0x07; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/debug/SpecialOpcode.java b/src/main/java/org/JesusFreke/dexlib/debug/SpecialOpcode.java new file mode 100644 index 00000000..e5dc2079 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/debug/SpecialOpcode.java @@ -0,0 +1,54 @@ +/* + * [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.JesusFreke.dexlib.debug; + +import org.JesusFreke.dexlib.CompositeField; +import org.JesusFreke.dexlib.Field; +import org.JesusFreke.dexlib.ByteField; + +public class SpecialOpcode extends CompositeField implements DebugInstruction { + private final Field[] fields; + + private final byte opcode; + + public SpecialOpcode(byte opcode) { + this.opcode = opcode; + fields = new Field[] { + new ByteField(opcode) + }; + } + + protected Field[] getFields() { + return fields; + } + + public byte getOpcode() { + return opcode; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/debug/StartLocal.java b/src/main/java/org/JesusFreke/dexlib/debug/StartLocal.java new file mode 100644 index 00000000..c0373308 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/debug/StartLocal.java @@ -0,0 +1,52 @@ +/* + * [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.JesusFreke.dexlib.debug; + +import org.JesusFreke.dexlib.*; + +public class StartLocal extends CompositeField implements DebugInstruction { + private final Field[] fields; + + public StartLocal(DexFile dexFile) { + fields = new Field[] { + new ByteField((byte)0x03), + new SignedLeb128Field(), + new IndexedItemReference(dexFile.StringIdsSection, new Leb128p1Field()), + new IndexedItemReference(dexFile.TypeIdsSection, new Leb128p1Field()), + }; + } + + protected Field[] getFields() { + return fields; + } + + public byte getOpcode() { + return 0x03; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/debug/StartLocalExtended.java b/src/main/java/org/JesusFreke/dexlib/debug/StartLocalExtended.java new file mode 100644 index 00000000..19537e8e --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/debug/StartLocalExtended.java @@ -0,0 +1,53 @@ +/* + * [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.JesusFreke.dexlib.debug; + +import org.JesusFreke.dexlib.*; + +public class StartLocalExtended extends CompositeField implements DebugInstruction { + private final Field[] fields; + + public StartLocalExtended(DexFile dexFile) { + fields = new Field[] { + new ByteField((byte)0x04), + new SignedLeb128Field(), + new IndexedItemReference(dexFile.StringIdsSection, new Leb128p1Field()), + new IndexedItemReference(dexFile.TypeIdsSection, new Leb128p1Field()), + new IndexedItemReference(dexFile.StringIdsSection, new Leb128p1Field()) + }; + } + + protected Field[] getFields() { + return fields; + } + + public byte getOpcode() { + return 0x04; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/util/AccessFlags.java b/src/main/java/org/JesusFreke/dexlib/util/AccessFlags.java new file mode 100644 index 00000000..e7b17166 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/util/AccessFlags.java @@ -0,0 +1,59 @@ +/* + * [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.JesusFreke.dexlib.util; + +import java.util.HashMap; + +public class AccessFlags +{ + public static final int PUBLIC = 0x01; + public static final int PRIVATE = 0x02; + public static final int STATIC = 0x08; + public static final int CONSTRUCTOR = 0x10000; + + private static HashMap accessFlagValues; + + static { + accessFlagValues = new HashMap(); + accessFlagValues.put("public", PUBLIC); + accessFlagValues.put("private", PRIVATE); + accessFlagValues.put("static", STATIC); + accessFlagValues.put("constructor", CONSTRUCTOR); + } + + public static int getValueForAccessFlag(String accessFlag) { + Integer retVal; + retVal = accessFlagValues.get(accessFlag); + if (retVal == null) { + return 0; + } + + return retVal.intValue(); + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/util/ByteArray.java b/src/main/java/org/JesusFreke/dexlib/util/ByteArray.java new file mode 100644 index 00000000..278e91b3 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/util/ByteArray.java @@ -0,0 +1,379 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.JesusFreke.dexlib.util; + +import java.io.DataInputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * Wrapper for a byte[], which provides read-only access and + * can "reveal" a partial slice of the underlying array. + * + * Note: Multibyte accessors all use big-endian order. + */ +public final class ByteArray { + /** non-null; underlying array */ + private final byte[] bytes; + + /** >= 0; start index of the slice (inclusive) */ + private final int start; + + /** >= 0, <= bytes.length; size computed as + * end - start (in the constructor) */ + private final int size; + + /** + * Constructs an instance. + * + * @param bytes non-null; the underlying array + * @param start >= 0; start index of the slice (inclusive) + * @param end >= start, <= bytes.length; end index of + * the slice (exclusive) + */ + public ByteArray(byte[] bytes, int start, int end) { + if (bytes == null) { + throw new NullPointerException("bytes == null"); + } + + if (start < 0) { + throw new IllegalArgumentException("start < 0"); + } + + if (end < start) { + throw new IllegalArgumentException("end < start"); + } + + if (end > bytes.length) { + throw new IllegalArgumentException("end > bytes.length"); + } + + this.bytes = bytes; + this.start = start; + this.size = end - start; + } + + /** + * Constructs an instance from an entire byte[]. + * + * @param bytes non-null; the underlying array + */ + public ByteArray(byte[] bytes) { + this(bytes, 0, bytes.length); + } + + /** + * Gets the size of the array, in bytes. + * + * @return >= 0; the size + */ + public int size() { + return size; + } + + /** + * Returns a slice (that is, a sub-array) of this instance. + * + * @param start >= 0; start index of the slice (inclusive) + * @param end >= start, <= size(); end index of + * the slice (exclusive) + * @return non-null; the slice + */ + public ByteArray slice(int start, int end) { + checkOffsets(start, end); + return new ByteArray(bytes, start + this.start, end + this.start); + } + + /** + * Returns the offset into the given array represented by the given + * offset into this instance. + * + * @param offset offset into this instance + * @param bytes non-null; (alleged) underlying array + * @return corresponding offset into bytes + * @throws IllegalArgumentException thrown if bytes is + * not the underlying array of this instance + */ + public int underlyingOffset(int offset, byte[] bytes) { + if (bytes != this.bytes) { + throw new IllegalArgumentException("wrong bytes"); + } + + return start + offset; + } + + /** + * Gets the signed byte value at a particular offset. + * + * @param off >= 0, < size(); offset to fetch + * @return signed byte at that offset + */ + public int getByte(int off) { + checkOffsets(off, off + 1); + return getByte0(off); + } + + /** + * Gets the signed short value at a particular offset. + * + * @param off >= 0, < (size() - 1); offset to fetch + * @return signed short at that offset + */ + public int getShort(int off) { + checkOffsets(off, off + 2); + return (getByte0(off) << 8) | getUnsignedByte0(off + 1); + } + + /** + * Gets the signed int value at a particular offset. + * + * @param off >= 0, < (size() - 3); offset to fetch + * @return signed int at that offset + */ + public int getInt(int off) { + checkOffsets(off, off + 4); + return (getByte0(off) << 24) | + (getUnsignedByte0(off + 1) << 16) | + (getUnsignedByte0(off + 2) << 8) | + getUnsignedByte0(off + 3); + } + + /** + * Gets the signed long value at a particular offset. + * + * @param off >= 0, < (size() - 7); offset to fetch + * @return signed int at that offset + */ + public long getLong(int off) { + checkOffsets(off, off + 8); + int part1 = (getByte0(off) << 24) | + (getUnsignedByte0(off + 1) << 16) | + (getUnsignedByte0(off + 2) << 8) | + getUnsignedByte0(off + 3); + int part2 = (getByte0(off + 4) << 24) | + (getUnsignedByte0(off + 5) << 16) | + (getUnsignedByte0(off + 6) << 8) | + getUnsignedByte0(off + 7); + + return (part2 & 0xffffffffL) | ((long) part1) << 32; + } + + /** + * Gets the unsigned byte value at a particular offset. + * + * @param off >= 0, < size(); offset to fetch + * @return unsigned byte at that offset + */ + public int getUnsignedByte(int off) { + checkOffsets(off, off + 1); + return getUnsignedByte0(off); + } + + /** + * Gets the unsigned short value at a particular offset. + * + * @param off >= 0, < (size() - 1); offset to fetch + * @return unsigned short at that offset + */ + public int getUnsignedShort(int off) { + checkOffsets(off, off + 2); + return (getUnsignedByte0(off) << 8) | getUnsignedByte0(off + 1); + } + + /** + * Copies the contents of this instance into the given raw + * byte[] at the given offset. The given array must be + * large enough. + * + * @param out non-null; array to hold the output + * @param offset non-null; index into out for the first + * byte of output + */ + public void getBytes(byte[] out, int offset) { + if ((out.length - offset) < size) { + throw new IndexOutOfBoundsException("(out.length - offset) < " + + "size()"); + } + + System.arraycopy(bytes, start, out, offset, size); + } + + /** + * Checks a range of offsets for validity, throwing if invalid. + * + * @param s start offset (inclusive) + * @param e end offset (exclusive) + */ + private void checkOffsets(int s, int e) { + if ((s < 0) || (e < s) || (e > size)) { + throw new IllegalArgumentException("bad range: " + s + ".." + e + + "; actual size " + size); + } + } + + /** + * Gets the signed byte value at the given offset, + * without doing any argument checking. + * + * @param off offset to fetch + * @return byte at that offset + */ + private int getByte0(int off) { + return bytes[start + off]; + } + + /** + * Gets the unsigned byte value at the given offset, + * without doing any argument checking. + * + * @param off offset to fetch + * @return byte at that offset + */ + private int getUnsignedByte0(int off) { + return bytes[start + off] & 0xff; + } + + /** + * Gets a DataInputStream that reads from this instance, + * with the cursor starting at the beginning of this instance's data. + * Note: The returned instance may be cast to {@link #GetCursor} + * if needed. + * + * @return non-null; an appropriately-constructed + * DataInputStream instance + */ + public MyDataInputStream makeDataInputStream() { + return new MyDataInputStream(makeInputStream()); + } + + /** + * Gets a InputStream that reads from this instance, + * with the cursor starting at the beginning of this instance's data. + * Note: The returned instance may be cast to {@link #GetCursor} + * if needed. + * + * @return non-null; an appropriately-constructed + * InputStream instancex + */ + public MyInputStream makeInputStream() { + return new MyInputStream(); + } + + /** + * Helper interface that allows one to get the cursor (of a stream). + */ + public interface GetCursor { + /** + * Gets the current cursor. + * + * @return 0..size(); the cursor + */ + public int getCursor(); + } + + /** + * Helper class for {@link #makeInputStream}, which implements the + * stream functionality. + */ + public class MyInputStream extends InputStream { + /** 0..size; the cursor */ + private int cursor; + + /** 0..size; the mark */ + private int mark; + + public MyInputStream() { + cursor = 0; + mark = 0; + } + + public int read() throws IOException { + if (cursor >= size) { + return -1; + } + + int result = getUnsignedByte0(cursor); + cursor++; + return result; + } + + public int read(byte[] arr, int offset, int length) { + if ((offset + length) > arr.length) { + length = arr.length - offset; + } + + int maxLength = size - cursor; + if (length > maxLength) { + length = maxLength; + } + + System.arraycopy(bytes, cursor, arr, offset, length); + cursor += length; + return length; + } + + public int available() { + return size - cursor; + } + + public void mark(int reserve) { + mark = cursor; + } + + public void reset() { + cursor = mark; + } + + public boolean markSupported() { + return true; + } + + /** + * Gets the current cursor. + * + * @return 0..size(); the cursor + */ + public int getCursor() { + return cursor; + } + } + + /** + * Helper class for {@link #makeDataInputStream}. This is used + * simply so that the cursor of a wrapped {@link #MyInputStream} + * instance may be easily determined. + */ + public class MyDataInputStream extends DataInputStream { + /** non-null; the underlying {@link #MyInputStream} */ + private final MyInputStream wrapped; + + public MyDataInputStream(MyInputStream wrapped) { + super(wrapped); + + this.wrapped = wrapped; + } + + /** + * Gets the current cursor. + * + * @return 0..size(); the cursor + */ + public int getCursor() { + return wrapped.getCursor(); + } + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/util/ByteArrayInput.java b/src/main/java/org/JesusFreke/dexlib/util/ByteArrayInput.java new file mode 100644 index 00000000..c354a74a --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/util/ByteArrayInput.java @@ -0,0 +1,312 @@ +/* + * [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.JesusFreke.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; + + /** + * TODO: is there a faster/better way to do this? + */ + return (long)((data[readAt] & 0xff) + + ((data[readAt + 1] & 0xff) << 8) + + ((data[readAt + 2] & 0xff) << 16) + + ((data[readAt + 3] & 0xff) << 24)) + + + + + ((long)((data[readAt + 4] & 0xff)+ + ((data[readAt + 5] & 0xff) << 8) + + ((data[readAt + 6] & 0xff) << 16) + + ((data[readAt + 7] & 0xff) << 24)) << 32); + } + + /** {@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 void skipBytes(int count) { + int end = cursor + count; + + if (end > data.length) { + throwBounds(); + } + + cursor = end; + } + + /** {@inheritDoc} */ + public void alignTo(int alignment) { + int mask = alignment - 1; + + if ((alignment < 0) || ((mask & alignment) != 0)) { + throw new IllegalArgumentException("bogus alignment"); + } + + int end = (cursor + mask) & ~mask; + + 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/src/main/java/org/JesusFreke/dexlib/util/ByteArrayOutput.java b/src/main/java/org/JesusFreke/dexlib/util/ByteArrayOutput.java new file mode 100644 index 00000000..2e3484d1 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/util/ByteArrayOutput.java @@ -0,0 +1,582 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.JesusFreke.dexlib.util; + +import java.util.ArrayList; + +/** + * Implementation of {@link AnnotatedOutput} which stores the written data + * into a byte[]. + * + *

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

+ */ +public final class ByteArrayOutput implements Output +{ + /** default size for stretchy instances */ + private static final int DEFAULT_SIZE = 1000; + + /** + * whether the instance is stretchy, that is, whether its array + * may be resized to increase capacity + */ + private final boolean stretchy; + + /** non-null; the data itself */ + private byte[] data; + + /** >= 0; current output cursor */ + private int cursor; + + /** whether annotations are to be verbose */ + private boolean verbose; + + /** + * null-ok; list of annotations, or null if this instance + * isn't keeping them + */ + private ArrayList annotations; + + /** >= 40 (if used); the desired maximum annotation width */ + private int annotationWidth; + + /** + * >= 8 (if used); the number of bytes of hex output to use + * in annotations + */ + private int hexCols; + + /** + * Constructs an instance with a fixed maximum size. Note that the + * given array is the only one that will be used to store data. In + * particular, no reallocation will occur in order to expand the + * capacity of the resulting instance. Also, the constructed + * instance does not keep annotations by default. + * + * @param data non-null; data array to use for output + */ + public ByteArrayOutput(byte[] data) { + this(data, false); + } + + /** + * Constructs a "stretchy" instance. The underlying array may be + * reallocated. The constructed instance does not keep annotations + * by default. + */ + public ByteArrayOutput() { + this(new byte[DEFAULT_SIZE], true); + } + + /** + * Internal constructor. + * + * @param data non-null; data array to use for output + * @param stretchy whether the instance is to be stretchy + */ + private ByteArrayOutput(byte[] data, boolean stretchy) { + if (data == null) { + throw new NullPointerException("data == null"); + } + + this.stretchy = stretchy; + this.data = data; + this.cursor = 0; + this.verbose = false; + this.annotations = null; + this.annotationWidth = 0; + this.hexCols = 0; + } + + /** + * Gets the underlying byte[] of this instance, which + * may be larger than the number of bytes written + * + * @see #toByteArray + * + * @return non-null; the byte[] + */ + public byte[] getArray() { + return data; + } + + /** + * Constructs and returns a new byte[] that contains + * the written contents exactly (that is, with no extra unwritten + * bytes at the end). + * + * @see #getArray + * + * @return non-null; an appropriately-constructed array + */ + public byte[] toByteArray() { + byte[] result = new byte[cursor]; + System.arraycopy(data, 0, result, 0, cursor); + return result; + } + + /** {@inheritDoc} */ + public int getCursor() { + return cursor; + } + + /** {@inheritDoc} */ + public void assertCursor(int expectedCursor) { + if (cursor != expectedCursor) { + throw new ExceptionWithContext("expected cursor " + + expectedCursor + "; actual value: " + cursor); + } + } + + /** {@inheritDoc} */ + public void writeByte(int value) { + int writeAt = cursor; + int end = writeAt + 1; + + if (stretchy) { + ensureCapacity(end); + } else if (end > data.length) { + throwBounds(); + return; + } + + data[writeAt] = (byte) value; + cursor = end; + } + + /** {@inheritDoc} */ + public void writeShort(int value) { + int writeAt = cursor; + int end = writeAt + 2; + + if (stretchy) { + ensureCapacity(end); + } else if (end > data.length) { + throwBounds(); + return; + } + + data[writeAt] = (byte) value; + data[writeAt + 1] = (byte) (value >> 8); + cursor = end; + } + + /** {@inheritDoc} */ + public void writeInt(int value) { + int writeAt = cursor; + int end = writeAt + 4; + + if (stretchy) { + ensureCapacity(end); + } else if (end > data.length) { + throwBounds(); + return; + } + + data[writeAt] = (byte) value; + data[writeAt + 1] = (byte) (value >> 8); + data[writeAt + 2] = (byte) (value >> 16); + data[writeAt + 3] = (byte) (value >> 24); + cursor = end; + } + + /** {@inheritDoc} */ + public void writeLong(long value) { + int writeAt = cursor; + int end = writeAt + 8; + + if (stretchy) { + ensureCapacity(end); + } else if (end > data.length) { + throwBounds(); + return; + } + + int half = (int) value; + data[writeAt] = (byte) half; + data[writeAt + 1] = (byte) (half >> 8); + data[writeAt + 2] = (byte) (half >> 16); + data[writeAt + 3] = (byte) (half >> 24); + + half = (int) (value >> 32); + data[writeAt + 4] = (byte) half; + data[writeAt + 5] = (byte) (half >> 8); + data[writeAt + 6] = (byte) (half >> 16); + data[writeAt + 7] = (byte) (half >> 24); + + cursor = end; + } + + /** {@inheritDoc} */ + public int writeUnsignedLeb128(int value) { + int remaining = value >> 7; + int count = 0; + + while (remaining != 0) { + writeByte((value & 0x7f) | 0x80); + value = remaining; + remaining >>= 7; + count++; + } + + writeByte(value & 0x7f); + return count + 1; + } + + /** {@inheritDoc} */ + public int writeSignedLeb128(int value) { + int remaining = value >> 7; + int count = 0; + boolean hasMore = true; + int end = ((value & Integer.MIN_VALUE) == 0) ? 0 : -1; + + while (hasMore) { + hasMore = (remaining != end) + || ((remaining & 1) != ((value >> 6) & 1)); + + writeByte((value & 0x7f) | (hasMore ? 0x80 : 0)); + value = remaining; + remaining >>= 7; + count++; + } + + return count; + } + + /** {@inheritDoc} */ + public void write(ByteArray bytes) { + int blen = bytes.size(); + int writeAt = cursor; + int end = writeAt + blen; + + if (stretchy) { + ensureCapacity(end); + } else if (end > data.length) { + throwBounds(); + return; + } + + bytes.getBytes(data, writeAt); + cursor = end; + } + + /** {@inheritDoc} */ + public void write(byte[] bytes, int offset, int length) { + int writeAt = cursor; + int end = writeAt + length; + int bytesEnd = offset + length; + + // twos-complement math trick: ((x < 0) || (y < 0)) <=> ((x|y) < 0) + if (((offset | length | end) < 0) || (bytesEnd > bytes.length)) { + throw new IndexOutOfBoundsException("bytes.length " + + bytes.length + "; " + + offset + "..!" + end); + } + + if (stretchy) { + ensureCapacity(end); + } else if (end > data.length) { + throwBounds(); + return; + } + + System.arraycopy(bytes, offset, data, writeAt, length); + cursor = end; + } + + /** {@inheritDoc} */ + public void write(byte[] bytes) { + write(bytes, 0, bytes.length); + } + + /** {@inheritDoc} */ + public void writeZeroes(int count) { + if (count < 0) { + throw new IllegalArgumentException("count < 0"); + } + + int end = cursor + count; + + if (stretchy) { + ensureCapacity(end); + } else if (end > data.length) { + throwBounds(); + return; + } + + /* + * There is no need to actually write zeroes, since the array is + * already preinitialized with zeroes. + */ + + cursor = end; + } + + /** {@inheritDoc} */ + public void alignTo(int alignment) { + int mask = alignment - 1; + + if ((alignment < 0) || ((mask & alignment) != 0)) { + throw new IllegalArgumentException("bogus alignment"); + } + + int end = (cursor + mask) & ~mask; + + if (stretchy) { + ensureCapacity(end); + } else if (end > data.length) { + throwBounds(); + return; + } + + /* + * There is no need to actually write zeroes, since the array is + * already preinitialized with zeroes. + */ + + cursor = end; + } + + /** {@inheritDoc} */ + public boolean annotates() { + return (annotations != null); + } + + /** {@inheritDoc} */ + public boolean isVerbose() { + return verbose; + } + + /** {@inheritDoc} */ + public void annotate(String msg) { + if (annotations == null) { + return; + } + + endAnnotation(); + annotations.add(new Annotation(cursor, msg)); + } + + /** {@inheritDoc} */ + public void annotate(int amt, String msg) { + if (annotations == null) { + return; + } + + endAnnotation(); + + int asz = annotations.size(); + int lastEnd = (asz == 0) ? 0 : annotations.get(asz - 1).getEnd(); + int startAt; + + if (lastEnd <= cursor) { + startAt = cursor; + } else { + startAt = lastEnd; + } + + annotations.add(new Annotation(startAt, startAt + amt, msg)); + } + + /** {@inheritDoc} */ + public void endAnnotation() { + if (annotations == null) { + return; + } + + int sz = annotations.size(); + + if (sz != 0) { + annotations.get(sz - 1).setEndIfUnset(cursor); + } + } + + /** {@inheritDoc} */ + public int getAnnotationWidth() { + int leftWidth = 8 + (hexCols * 2) + (hexCols / 2); + + return annotationWidth - leftWidth; + } + + /** + * Indicates that this instance should keep annotations. This method may + * be called only once per instance, and only before any data has been + * written to the it. + * + * @param annotationWidth >= 40; the desired maximum annotation width + * @param verbose whether or not to indicate verbose annotations + */ + public void enableAnnotations(int annotationWidth, boolean verbose) { + if ((annotations != null) || (cursor != 0)) { + throw new RuntimeException("cannot enable annotations"); + } + + if (annotationWidth < 40) { + throw new IllegalArgumentException("annotationWidth < 40"); + } + + int hexCols = (((annotationWidth - 7) / 15) + 1) & ~1; + if (hexCols < 6) { + hexCols = 6; + } else if (hexCols > 10) { + hexCols = 10; + } + + this.annotations = new ArrayList(1000); + this.annotationWidth = annotationWidth; + this.hexCols = hexCols; + this.verbose = verbose; + } + + /** + * Finishes up annotation processing. This closes off any open + * annotations and removes annotations that don't refer to written + * data. + */ + public void finishAnnotating() { + // Close off the final annotation, if any. + endAnnotation(); + + // Remove annotations that refer to unwritten data. + if (annotations != null) { + int asz = annotations.size(); + while (asz > 0) { + Annotation last = annotations.get(asz - 1); + if (last.getStart() > cursor) { + annotations.remove(asz - 1); + asz--; + } else if (last.getEnd() > cursor) { + last.setEnd(cursor); + break; + } else { + break; + } + } + } + } + + /** + * Throws the excpetion for when an attempt is made to write past the + * end of the instance. + */ + private static void throwBounds() { + throw new IndexOutOfBoundsException("attempt to write past the end"); + } + + /** + * Reallocates the underlying array if necessary. Calls to this method + * should be guarded by a test of {@link #stretchy}. + * + * @param desiredSize >= 0; the desired minimum total size of the array + */ + private void ensureCapacity(int desiredSize) { + if (data.length < desiredSize) { + byte[] newData = new byte[desiredSize * 2 + 1000]; + System.arraycopy(data, 0, newData, 0, cursor); + data = newData; + } + } + + /** + * Annotation on output. + */ + private static class Annotation { + /** >= 0; start of annotated range (inclusive) */ + private final int start; + + /** + * >= 0; end of annotated range (exclusive); + * Integer.MAX_VALUE if unclosed + */ + private int end; + + /** non-null; annotation text */ + private final String text; + + /** + * Constructs an instance. + * + * @param start >= 0; start of annotated range + * @param end >= start; end of annotated range (exclusive) or + * Integer.MAX_VALUE if unclosed + * @param text non-null; annotation text + */ + public Annotation(int start, int end, String text) { + this.start = start; + this.end = end; + this.text = text; + } + + /** + * Constructs an instance. It is initally unclosed. + * + * @param start >= 0; start of annotated range + * @param text non-null; annotation text + */ + public Annotation(int start, String text) { + this(start, Integer.MAX_VALUE, text); + } + + /** + * Sets the end as given, but only if the instance is unclosed; + * otherwise, do nothing. + * + * @param end >= start; the end + */ + public void setEndIfUnset(int end) { + if (this.end == Integer.MAX_VALUE) { + this.end = end; + } + } + + /** + * Sets the end as given. + * + * @param end >= start; the end + */ + public void setEnd(int end) { + this.end = end; + } + + /** + * Gets the start. + * + * @return the start + */ + public int getStart() { + return start; + } + + /** + * Gets the end. + * + * @return the end + */ + public int getEnd() { + return end; + } + + /** + * Gets the text. + * + * @return non-null; the text + */ + public String getText() { + return text; + } + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/util/EncodedValueUtils.java b/src/main/java/org/JesusFreke/dexlib/util/EncodedValueUtils.java new file mode 100644 index 00000000..68eb0f0d --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/util/EncodedValueUtils.java @@ -0,0 +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.JesusFreke.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/src/main/java/org/JesusFreke/dexlib/util/ExceptionWithContext.java b/src/main/java/org/JesusFreke/dexlib/util/ExceptionWithContext.java new file mode 100644 index 00000000..31960476 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/util/ExceptionWithContext.java @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.JesusFreke.dexlib.util; + +import java.io.PrintStream; +import java.io.PrintWriter; + +/** + * Exception which carries around structured context. + */ +public class ExceptionWithContext + extends RuntimeException { + /** non-null; human-oriented context of the exception */ + private StringBuffer context; + + /** + * Augments the given exception with the given context, and return the + * result. The result is either the given exception if it was an + * {@link ExceptionWithContext}, or a newly-constructed exception if it + * was not. + * + * @param ex non-null; the exception to augment + * @param str non-null; context to add + * @return non-null; an appropriate instance + */ + public static ExceptionWithContext withContext(Throwable ex, String str) { + ExceptionWithContext ewc; + + if (ex instanceof ExceptionWithContext) { + ewc = (ExceptionWithContext) ex; + } else { + ewc = new ExceptionWithContext(ex); + } + + ewc.addContext(str); + return ewc; + } + + /** + * Constructs an instance. + * + * @param message human-oriented message + */ + public ExceptionWithContext(String message) { + this(message, null); + } + + /** + * Constructs an instance. + * + * @param cause null-ok; exception that caused this one + */ + public ExceptionWithContext(Throwable cause) { + this(null, cause); + } + + /** + * Constructs an instance. + * + * @param message human-oriented message + * @param cause null-ok; exception that caused this one + */ + public ExceptionWithContext(String message, Throwable cause) { + super((message != null) ? message : + (cause != null) ? cause.getMessage() : null, + cause); + + if (cause instanceof ExceptionWithContext) { + String ctx = ((ExceptionWithContext) cause).context.toString(); + context = new StringBuffer(ctx.length() + 200); + context.append(ctx); + } else { + context = new StringBuffer(200); + } + } + + /** {@inheritDoc} */ + @Override + public void printStackTrace(PrintStream out) { + super.printStackTrace(out); + out.println(context); + } + + /** {@inheritDoc} */ + @Override + public void printStackTrace(PrintWriter out) { + super.printStackTrace(out); + out.println(context); + } + + /** + * Adds a line of context to this instance. + * + * @param str non-null; new context + */ + public void addContext(String str) { + if (str == null) { + throw new NullPointerException("str == null"); + } + + context.append(str); + if (!str.endsWith("\n")) { + context.append('\n'); + } + } + + /** + * Gets the context. + * + * @return non-null; the context + */ + public String getContext() { + return context.toString(); + } + + /** + * Prints the message and context. + * + * @param out non-null; where to print to + */ + public void printContext(PrintStream out) { + out.println(getMessage()); + out.print(context); + } + + /** + * Prints the message and context. + * + * @param out non-null; where to print to + */ + public void printContext(PrintWriter out) { + out.println(getMessage()); + out.print(context); + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/util/FileUtils.java b/src/main/java/org/JesusFreke/dexlib/util/FileUtils.java new file mode 100644 index 00000000..86bccea1 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/util/FileUtils.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.JesusFreke.dexlib.util; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; + +/** + * File I/O utilities. + */ +public final class FileUtils { + /** + * This class is uninstantiable. + */ + private FileUtils() { + // This space intentionally left blank. + } + + /** + * Reads the named file, translating {@link IOException} to a + * {@link RuntimeException} of some sort. + * + * @param fileName non-null; name of the file to read + * @return non-null; contents of the file + */ + public static byte[] readFile(String fileName) { + File file = new File(fileName); + return readFile(file); + } + + /** + * Reads the given file, translating {@link IOException} to a + * {@link RuntimeException} of some sort. + * + * @param file non-null; the file to read + * @return non-null; contents of the file + */ + public static byte[] readFile(File file) { + if (!file.exists()) { + throw new RuntimeException(file + ": file not found"); + } + + if (!file.isFile()) { + throw new RuntimeException(file + ": not a file"); + } + + if (!file.canRead()) { + throw new RuntimeException(file + ": file not readable"); + } + + long longLength = file.length(); + int length = (int) longLength; + if (length != longLength) { + throw new RuntimeException(file + ": file too long"); + } + + byte[] result = new byte[length]; + + try { + FileInputStream in = new FileInputStream(file); + int at = 0; + while (length > 0) { + int amt = in.read(result, at, length); + if (amt == -1) { + throw new RuntimeException(file + ": unexpected EOF"); + } + at += amt; + length -= amt; + } + in.close(); + } catch (IOException ex) { + throw new RuntimeException(file + ": trouble reading", ex); + } + + return result; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/util/Hex.java b/src/main/java/org/JesusFreke/dexlib/util/Hex.java new file mode 100644 index 00000000..e9174fa8 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/util/Hex.java @@ -0,0 +1,303 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.JesusFreke.dexlib.util; + +/** + * Utilities for formatting numbers as hexadecimal. + */ +public final class Hex { + /** + * This class is uninstantiable. + */ + private Hex() { + // This space intentionally left blank. + } + + /** + * Formats a long as an 8-byte unsigned hex value. + * + * @param v value to format + * @return non-null; formatted form + */ + public static String u8(long v) { + char[] result = new char[16]; + for (int i = 0; i < 16; i++) { + result[15 - i] = Character.forDigit((int) v & 0x0f, 16); + v >>= 4; + } + + return new String(result); + } + + /** + * Formats an int as a 4-byte unsigned hex value. + * + * @param v value to format + * @return non-null; formatted form + */ + public static String u4(int v) { + char[] result = new char[8]; + for (int i = 0; i < 8; i++) { + result[7 - i] = Character.forDigit(v & 0x0f, 16); + v >>= 4; + } + + return new String(result); + } + + /** + * Formats an int as a 3-byte unsigned hex value. + * + * @param v value to format + * @return non-null; formatted form + */ + public static String u3(int v) { + char[] result = new char[6]; + for (int i = 0; i < 6; i++) { + result[5 - i] = Character.forDigit(v & 0x0f, 16); + v >>= 4; + } + + return new String(result); + } + + /** + * Formats an int as a 2-byte unsigned hex value. + * + * @param v value to format + * @return non-null; formatted form + */ + public static String u2(int v) { + char[] result = new char[4]; + for (int i = 0; i < 4; i++) { + result[3 - i] = Character.forDigit(v & 0x0f, 16); + v >>= 4; + } + + return new String(result); + } + + /** + * Formats an int as either a 2-byte unsigned hex value + * (if the value is small enough) or a 4-byte unsigned hex value (if + * not). + * + * @param v value to format + * @return non-null; formatted form + */ + public static String u2or4(int v) { + if (v == (char) v) { + return u2(v); + } else { + return u4(v); + } + } + + /** + * Formats an int as a 1-byte unsigned hex value. + * + * @param v value to format + * @return non-null; formatted form + */ + public static String u1(int v) { + char[] result = new char[2]; + for (int i = 0; i < 2; i++) { + result[1 - i] = Character.forDigit(v & 0x0f, 16); + v >>= 4; + } + + return new String(result); + } + + /** + * Formats an int as a 4-bit unsigned hex nibble. + * + * @param v value to format + * @return non-null; formatted form + */ + public static String uNibble(int v) { + char[] result = new char[1]; + + result[0] = Character.forDigit(v & 0x0f, 16); + return new String(result); + } + + /** + * Formats a long as an 8-byte signed hex value. + * + * @param v value to format + * @return non-null; formatted form + */ + public static String s8(long v) { + char[] result = new char[17]; + + if (v < 0) { + result[0] = '-'; + v = -v; + } else { + result[0] = '+'; + } + + for (int i = 0; i < 16; i++) { + result[16 - i] = Character.forDigit((int) v & 0x0f, 16); + v >>= 4; + } + + return new String(result); + } + + /** + * Formats an int as a 4-byte signed hex value. + * + * @param v value to format + * @return non-null; formatted form + */ + public static String s4(int v) { + char[] result = new char[9]; + + if (v < 0) { + result[0] = '-'; + v = -v; + } else { + result[0] = '+'; + } + + for (int i = 0; i < 8; i++) { + result[8 - i] = Character.forDigit(v & 0x0f, 16); + v >>= 4; + } + + return new String(result); + } + + /** + * Formats an int as a 2-byte signed hex value. + * + * @param v value to format + * @return non-null; formatted form + */ + public static String s2(int v) { + char[] result = new char[5]; + + if (v < 0) { + result[0] = '-'; + v = -v; + } else { + result[0] = '+'; + } + + for (int i = 0; i < 4; i++) { + result[4 - i] = Character.forDigit(v & 0x0f, 16); + v >>= 4; + } + + return new String(result); + } + + /** + * Formats an int as a 1-byte signed hex value. + * + * @param v value to format + * @return non-null; formatted form + */ + public static String s1(int v) { + char[] result = new char[3]; + + if (v < 0) { + result[0] = '-'; + v = -v; + } else { + result[0] = '+'; + } + + for (int i = 0; i < 2; i++) { + result[2 - i] = Character.forDigit(v & 0x0f, 16); + v >>= 4; + } + + return new String(result); + } + + /** + * Formats a hex dump of a portion of a byte[]. The result + * is always newline-terminated, unless the passed-in length was zero, + * in which case the result is always the empty string (""). + * + * @param arr non-null; array to format + * @param offset >= 0; offset to the part to dump + * @param length >= 0; number of bytes to dump + * @param outOffset >= 0; first output offset to print + * @param bpl >= 0; number of bytes of output per line + * @param addressLength {2,4,6,8}; number of characters for each address + * header + * @return non-null; a string of the dump + */ + public static String dump(byte[] arr, int offset, int length, + int outOffset, int bpl, int addressLength) { + int end = offset + length; + + // twos-complement math trick: ((x < 0) || (y < 0)) <=> ((x|y) < 0) + if (((offset | length | end) < 0) || (end > arr.length)) { + throw new IndexOutOfBoundsException("arr.length " + + arr.length + "; " + + offset + "..!" + end); + } + + if (outOffset < 0) { + throw new IllegalArgumentException("outOffset < 0"); + } + + if (length == 0) { + return ""; + } + + StringBuffer sb = new StringBuffer(length * 4 + 6); + boolean bol = true; + int col = 0; + + while (length > 0) { + if (col == 0) { + String astr; + switch (addressLength) { + case 2: astr = Hex.u1(outOffset); break; + case 4: astr = Hex.u2(outOffset); break; + case 6: astr = Hex.u3(outOffset); break; + default: astr = Hex.u4(outOffset); break; + } + sb.append(astr); + sb.append(": "); + } else if ((col & 1) == 0) { + sb.append(' '); + } + sb.append(Hex.u1(arr[offset])); + outOffset++; + offset++; + col++; + if (col == bpl) { + sb.append('\n'); + col = 0; + } + length--; + } + + if (col != 0) { + sb.append('\n'); + } + + return sb.toString(); + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/util/Input.java b/src/main/java/org/JesusFreke/dexlib/util/Input.java new file mode 100644 index 00000000..b581a4e0 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/util/Input.java @@ -0,0 +1,149 @@ +/* + * [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.JesusFreke.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 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); + + /** + * 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/src/main/java/org/JesusFreke/dexlib/util/Leb128Utils.java b/src/main/java/org/JesusFreke/dexlib/util/Leb128Utils.java new file mode 100644 index 00000000..e40ebdef --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/util/Leb128Utils.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.JesusFreke.dexlib.util; + +/** + * LEB128 (little-endian base 128) utilities. + */ +public final class Leb128Utils { + /** + * This class is uninstantiable. + */ + private Leb128Utils() { + // This space intentionally left blank. + } + + /** + * Gets the number of bytes in the unsigned LEB128 encoding of the + * given value. + * + * @param value the value in question + * @return its write size, in bytes + */ + public static int unsignedLeb128Size(int value) { + // TODO: This could be much cleverer. + + int remaining = value >> 7; + int count = 0; + + while (remaining != 0) { + value = remaining; + remaining >>= 7; + count++; + } + + return count + 1; + } + + /** + * Gets the number of bytes in the signed LEB128 encoding of the + * given value. + * + * @param value the value in question + * @return its write size, in bytes + */ + public static int signedLeb128Size(int value) { + // TODO: This could be much cleverer. + + int remaining = value >> 7; + int count = 0; + boolean hasMore = true; + int end = ((value & Integer.MIN_VALUE) == 0) ? 0 : -1; + + while (hasMore) { + hasMore = (remaining != end) + || ((remaining & 1) != ((value >> 6) & 1)); + + value = remaining; + remaining >>= 7; + count++; + } + + return count; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/util/Output.java b/src/main/java/org/JesusFreke/dexlib/util/Output.java new file mode 100644 index 00000000..dbb76df0 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/util/Output.java @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.JesusFreke.dexlib.util; + +/** + * Interface for a sink for binary output. This is similar to + * java.util.DataOutput, but no IOExceptions + * are declared, and multibyte output is defined to be little-endian. + */ +public interface Output { + /** + * Gets the current cursor position. This is the same as the number of + * bytes written to this instance. + * + * @return >= 0; the cursor position + */ + public int getCursor(); + + /** + * 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); + + /** + * Writes a byte to this instance. + * + * @param value the value to write; all but the low 8 bits are ignored + */ + public void writeByte(int value); + + /** + * Writes a short to this instance. + * + * @param value the value to write; all but the low 16 bits are ignored + */ + public void writeShort(int value); + + /** + * Writes an int to this instance. + * + * @param value the value to write + */ + public void writeInt(int value); + + /** + * Writes a long to this instance. + * + * @param value the value to write + */ + public void writeLong(long value); + + /** + * Writes a DWARFv3-style unsigned LEB128 integer. For details, + * see the "Dalvik Executable Format" document or DWARF v3 section + * 7.6. + * + * @param value value to write, treated as an unsigned value + * @return 1..5; the number of bytes actually written + */ + public int writeUnsignedLeb128(int value); + + /** + * Writes a DWARFv3-style unsigned LEB128 integer. For details, + * see the "Dalvik Executable Format" document or DWARF v3 section + * 7.6. + * + * @param value value to write + * @return 1..5; the number of bytes actually written + */ + public int writeSignedLeb128(int value); + + /** + * Writes a {@link ByteArray} to this instance. + * + * @param bytes non-null; the array to write + */ + public void write(ByteArray bytes); + + /** + * Writes a portion of a byte[] to this instance. + * + * @param bytes non-null; the array to write + * @param offset >= 0; offset into bytes for the first + * byte to write + * @param length >= 0; number of bytes to write + */ + public void write(byte[] bytes, int offset, int length); + + /** + * Writes a byte[] to this instance. This is just + * a convenient shorthand for write(bytes, 0, bytes.length). + * + * @param bytes non-null; the array to write + */ + public void write(byte[] bytes); + + /** + * Writes the given number of 0 bytes. + * + * @param count >= 0; the number of zeroes to write + */ + public void writeZeroes(int count); + + /** + * Adds extra bytes if necessary (with value 0) 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/src/main/java/org/JesusFreke/dexlib/util/TypeUtils.java b/src/main/java/org/JesusFreke/dexlib/util/TypeUtils.java new file mode 100644 index 00000000..1361fcb4 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/util/TypeUtils.java @@ -0,0 +1,63 @@ +/* + * [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.JesusFreke.dexlib.util; + +import org.JesusFreke.dexlib.EncodedValue.EncodedValueSubFieldFactory; +import org.JesusFreke.dexlib.EncodedValue.ValueType; +import org.JesusFreke.dexlib.EncodedValue.EncodedValueSubField; +import org.JesusFreke.dexlib.DexFile; + +public class TypeUtils +{ + public static EncodedValueSubField makeDefaultValueForType(DexFile dexFile, String type) { + switch (type.charAt(0)) { + case 'Z': + return EncodedValueSubFieldFactory.makeEncodedValueField(dexFile, ValueType.VALUE_BOOLEAN); + case 'B': + return EncodedValueSubFieldFactory.makeEncodedValueField(dexFile, ValueType.VALUE_BYTE); + case 'S': + return EncodedValueSubFieldFactory.makeEncodedValueField(dexFile, ValueType.VALUE_SHORT); + case 'C': + return EncodedValueSubFieldFactory.makeEncodedValueField(dexFile, ValueType.VALUE_CHAR); + case 'I': + return EncodedValueSubFieldFactory.makeEncodedValueField(dexFile, ValueType.VALUE_INT); + case 'J': + return EncodedValueSubFieldFactory.makeEncodedValueField(dexFile, ValueType.VALUE_LONG); + case 'F': + return EncodedValueSubFieldFactory.makeEncodedValueField(dexFile, ValueType.VALUE_FLOAT); + case 'D': + return EncodedValueSubFieldFactory.makeEncodedValueField(dexFile, ValueType.VALUE_DOUBLE); + case 'L': + case '[': + //TODO: is the default value for array types null or an empty array? + return EncodedValueSubFieldFactory.makeEncodedValueField(dexFile, ValueType.VALUE_NULL); + } + return null; + } +} diff --git a/src/main/java/org/JesusFreke/dexlib/util/Utf8Utils.java b/src/main/java/org/JesusFreke/dexlib/util/Utf8Utils.java new file mode 100644 index 00000000..0d26a371 --- /dev/null +++ b/src/main/java/org/JesusFreke/dexlib/util/Utf8Utils.java @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.JesusFreke.dexlib.util; + +import org.JesusFreke.dexlib.util.ByteArray; +import org.JesusFreke.dexlib.util.Hex; + +/** + * Constants of type CONSTANT_Utf8_info. + */ +public final class Utf8Utils { + + + /** + * Converts a string into its Java-style UTF-8 form. Java-style UTF-8 + * differs from normal UTF-8 in the handling of character '\0' and + * surrogate pairs. + * + * @param string non-null; the string to convert + * @return non-null; the UTF-8 bytes for it + */ + public static byte[] stringToUtf8Bytes(String string) { + int len = string.length(); + byte[] bytes = new byte[len * 3]; // Avoid having to reallocate. + int outAt = 0; + + for (int i = 0; i < len; i++) { + char c = string.charAt(i); + if ((c != 0) && (c < 0x80)) { + bytes[outAt] = (byte) c; + outAt++; + } else if (c < 0x800) { + bytes[outAt] = (byte) (((c >> 6) & 0x1f) | 0xc0); + bytes[outAt + 1] = (byte) ((c & 0x3f) | 0x80); + outAt += 2; + } else { + bytes[outAt] = (byte) (((c >> 12) & 0x0f) | 0xe0); + bytes[outAt + 1] = (byte) (((c >> 6) & 0x3f) | 0x80); + bytes[outAt + 2] = (byte) ((c & 0x3f) | 0x80); + outAt += 3; + } + } + + byte[] result = new byte[outAt]; + System.arraycopy(bytes, 0, result, 0, outAt); + return result; + } + + /** + * Converts an array of UTF-8 bytes into a string. + * + * @param bytes non-null; the bytes to convert + * @return non-null; the converted string + */ + public static String utf8BytesToString(ByteArray bytes) { + int length = bytes.size(); + char[] chars = new char[length]; // This is sized to avoid a realloc. + int outAt = 0; + + for (int at = 0; length > 0; /*at*/) { + int v0 = bytes.getUnsignedByte(at); + char out; + switch (v0 >> 4) { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: { + // 0XXXXXXX -- single-byte encoding + length--; + if (v0 == 0) { + // A single zero byte is illegal. + return throwBadUtf8(v0, at); + } + out = (char) v0; + at++; + break; + } + case 0x0c: case 0x0d: { + // 110XXXXX -- two-byte encoding + length -= 2; + if (length < 0) { + return throwBadUtf8(v0, at); + } + int v1 = bytes.getUnsignedByte(at + 1); + if ((v1 & 0xc0) != 0x80) { + return throwBadUtf8(v1, at + 1); + } + int value = ((v0 & 0x1f) << 6) | (v1 & 0x3f); + if ((value != 0) && (value < 0x80)) { + /* + * This should have been represented with + * one-byte encoding. + */ + return throwBadUtf8(v1, at + 1); + } + out = (char) value; + at += 2; + break; + } + case 0x0e: { + // 1110XXXX -- three-byte encoding + length -= 3; + if (length < 0) { + return throwBadUtf8(v0, at); + } + int v1 = bytes.getUnsignedByte(at + 1); + if ((v1 & 0xc0) != 0x80) { + return throwBadUtf8(v1, at + 1); + } + int v2 = bytes.getUnsignedByte(at + 2); + if ((v1 & 0xc0) != 0x80) { + return throwBadUtf8(v2, at + 2); + } + int value = ((v0 & 0x0f) << 12) | ((v1 & 0x3f) << 6) | + (v2 & 0x3f); + if (value < 0x800) { + /* + * This should have been represented with one- or + * two-byte encoding. + */ + return throwBadUtf8(v2, at + 2); + } + out = (char) value; + at += 3; + break; + } + default: { + // 10XXXXXX, 1111XXXX -- illegal + return throwBadUtf8(v0, at); + } + } + chars[outAt] = out; + outAt++; + } + + return new String(chars, 0, outAt); + } + + /** + * Helper for {@link #utf8BytesToString}, which throws the right + * exception for a bogus utf-8 byte. + * + * @param value the byte value + * @param offset the file offset + * @return never + * @throws IllegalArgumentException always thrown + */ + private static String throwBadUtf8(int value, int offset) { + throw new IllegalArgumentException("bad utf-8 byte " + Hex.u1(value) + + " at offset " + Hex.u4(offset)); + } +} diff --git a/src/main/java/org/JesusFreke/smali/smali.java b/src/main/java/org/JesusFreke/smali/smali.java new file mode 100644 index 00000000..ddc57cc4 --- /dev/null +++ b/src/main/java/org/JesusFreke/smali/smali.java @@ -0,0 +1,91 @@ +/* + * [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.JesusFreke.smali; + +import org.JesusFreke.dexlib.DexFile; +import org.JesusFreke.dexlib.util.ByteArrayOutput; +import org.antlr.runtime.ANTLRInputStream; +import org.antlr.runtime.CommonTokenStream; +import org.antlr.runtime.tree.CommonTree; +import org.antlr.runtime.tree.CommonTreeNodeStream; + +import java.io.FileInputStream; +import java.io.FileOutputStream; + +public class smali +{ + public static void main(String[] args) throws Exception + { + /*ANTLRStringStream input = new ANTLRStringStream("atest1btest2"); + testLexer lexer = new testLexer(input); + CommonTokenStream tokens = new CommonTokenStream(lexer); + + List l = tokens.getTokens();*/ + + + ANTLRInputStream input = new ANTLRInputStream(new FileInputStream(args[0])); + smaliLexer lexer = new smaliLexer(input); + CommonTokenStream tokens = new CommonTokenStream(lexer); + smaliParser parser = new smaliParser(tokens); + smaliParser.smali_file_return result = parser.smali_file(); + CommonTree t = (CommonTree) result.getTree(); + + CommonTreeNodeStream treeStream = new CommonTreeNodeStream(t); + + smaliTreeWalker dexGen = new smaliTreeWalker(treeStream); + + DexFile dexFile = DexFile.makeBlankDexFile(); + dexGen.dexFile = dexFile; + dexGen.smali_file(); + + dexFile.ClassDefsSection.intern(dexFile, dexGen.classDefItem); + dexFile.place(); + try + { + ByteArrayOutput out = new ByteArrayOutput(); + dexFile.writeTo(out); + + byte[] bytes = out.toByteArray(); + + DexFile.calcSignature(bytes); + DexFile.calcChecksum(bytes); + + FileOutputStream fileOutputStream = new FileOutputStream("classes.dex"); + + fileOutputStream.write(bytes); + fileOutputStream.close(); + } catch (Exception ex) + { + System.out.println(ex.toString()); + } + + + System.out.println("here"); + } +} \ No newline at end of file diff --git a/src/test/resources/examples/Constants.smali b/src/test/resources/examples/Constants.smali new file mode 100644 index 00000000..5d9a779b --- /dev/null +++ b/src/test/resources/examples/Constants.smali @@ -0,0 +1,97 @@ +.class public org/JesusFreke/HelloWorld2/HelloWorld2 +.super android/app/Activity + +.field private static final stringConstant1 Ljava/lang/String; = "Hello World!" +.field private static final stringConstant2 Ljava/lang/String; = "" +.field private static final stringConstant3 Ljava/lang/String; = "a\b\n\f\r\"\'\\\u1234\u0000\u000a\u000d" + +.field private static final charConstant1 C = 'a' +.field private static final charConstant2 C = '\b' ;backspace +.field private static final charConstant3 C = '\n' +.field private static final charConstant4 C = '\f' ;formfeed +.field private static final charConstant5 C = '\r' +.field private static final charConstant6 C = '\"' +.field private static final charConstant7 C = '\'' +.field private static final charConstant8 C = '\\' +.field private static final charConstant9 C = '\0' +.field private static final charConstant10 C = '\7' +.field private static final charConstant11 C = '\77' +.field private static final charConstant12 C = '\377' + +.field private static final intDecConstant1 I = 0 +.field private static final intDecConstant2 I = 1 +.field private static final intDecConstant3 I = 1000 +.field private static final intDecConstant4 I = 1024 +.field private static final intDecConstant5 I = 2147483647 +.field private static final intDecConstant6 I = -0 +.field private static final intDecConstant7 I = -1 +.field private static final intDecConstant8 I = -1000 +.field private static final intDecConstant9 I = -1024 +.field private static final intDecConstant10 I = -2147483648 + +.field private static final intHexConstant1 I = 0x0 +.field private static final intHexConstant2 I = 0x00 +.field private static final intHexConstant3 I = 0x1 +.field private static final intHexConstant4 I = 0x01 +.field private static final intHexConstant5 I = 0x3E8 ;1000 +.field private static final intHexConstant6 I = 0x400 ;1024 +.field private static final intHexConstant7 I = 0x7fffffff ;2147483647 +.field private static final intHexConstant8 I = 0xFFFFFFFF ;-1 +.field private static final intHexConstant9 I = 0xFFFFFC18 ;-1000 +.field private static final intHexConstant10 I = 0xFFFFFC00 ;-1024 +.field private static final intHexConstant11 I = 0x80000000 ;-2147483648 + +.field private static final longDecConstant1 J = 0L +.field private static final longDecConstant2 J = 1L +.field private static final longDecConstant3 J = 1000L +.field private static final longDecConstant4 J = 1024L +.field private static final longDecConstant5 J = 2147483647L +.field private static final longDecConstant5 J = 2147483648L +.field private static final longDecConstant5 J = 9223372036854775807L +.field private static final longDecConstant6 J = -0L +.field private static final longDecConstant7 J = -1L +.field private static final longDecConstant8 J = -1000L +.field private static final longDecConstant9 J = -1024L +.field private static final longDecConstant10 J = -2147483648L +.field private static final longDecConstant10 J = -2147483649L +.field private static final longDecConstant10 J = -9223372036854775808L + +.field private static final longHexConstant1 J = 0x0L +.field private static final longHexConstant2 J = 0x00L +.field private static final longHexConstant3 J = 0x1L +.field private static final longHexConstant4 J = 0x01L +.field private static final longHexConstant5 J = 0x3E8L ;1000 +.field private static final longHexConstant6 J = 0x400L ;1024 +.field private static final longHexConstant7 J = 0x7fffffffL ;2147483647 +.field private static final longHexConstant7 J = 0x80000000L ;2147483648 +.field private static final longHexConstant7 J = 0x7fffffffffffffffL ;9223372036854775807 +.field private static final longHexConstant8 J = 0xFFFFFFFFFFFFFFFFL ;-1 +.field private static final longHexConstant9 J = 0xFFFFFFFFFFFFFC18L ;-1000 +.field private static final longHexConstant10 J = 0xFFFFFFFFFFFFFC00L ;-1024 +.field private static final longHexConstant11 J = 0xFFFFFFFF80000000L ;-2147483648 +.field private static final longHexConstant11 J = 0xFFFFFFFF7FFFFFFFL ;-2147483649 +.field private static final longHexConstant12 J = 0x8000000000000000L ;-9223372036854775808 + +.method public constructor ()V + .registers 1 + invoke-direct {v0} android/app/Activity.()V + return-void +.end method + +.method public onCreate(Landroid/os/Bundle;)V + .registers 4 + + sget-object v0 java/lang/System.out Ljava/io/PrintStream; + + invoke-super {v2,v3} android/app/Activity.onCreate(Landroid/os/Bundle;)V + + new-instance v0 android/widget/TextView + invoke-direct {v0,v2} android/widget/TextView.(Landroid/content/Context;)V + const-string v1 "Hello World!" + invoke-virtual {v0,v1} android/widget/TextView.setText(Ljava/lang/CharSequence;)V + invoke-virtual {v2,v0} org/JesusFreke/HelloWorld2/HelloWorld2.setContentView(Landroid/view/View;)V + + return-void +.end method + + diff --git a/src/test/resources/examples/HelloWorld.smali b/src/test/resources/examples/HelloWorld.smali new file mode 100644 index 00000000..4bdac992 --- /dev/null +++ b/src/test/resources/examples/HelloWorld.smali @@ -0,0 +1,21 @@ +.class public HelloWorld +.super java/lang/Object + +.method public ()V + .registers 1 + + invoke-direct {v0} java/lang/Object.()V + + return-void +.end method + +.method public static main([Ljava/lang/String;)V + .registers 4 + + sget-object v0 java/lang/System.out Ljava/io/PrintStream; + const-string v1 "Hello World!" + + invoke-virtual {v0, v1} java/io/PrintStream.print(Ljava/Lang/Stream;)V + + return-void +.end method diff --git a/src/test/resources/examples/HelloWorld2.smali b/src/test/resources/examples/HelloWorld2.smali new file mode 100644 index 00000000..85f6c11e --- /dev/null +++ b/src/test/resources/examples/HelloWorld2.smali @@ -0,0 +1,54 @@ +.class public org/JesusFreke/HelloWorld2/HelloWorld2 +.super android/app/Activity + +.field private helloWorld Ljava/lang/String; +.field private static helloWorldStatic Ljava/lang/String; + +.field private static helloWorldStatic2 Ljava/lang/String; = "Static Initializer Hello World!" + +.method static constructor ()V + .registers 1 + + const-string v0 "Static Hello World!" + sput-object v0 org/JesusFreke/HelloWorld2/HelloWorld2.helloWorldStatic Ljava/lang/String; + + return-void +.end method + +.method public constructor ()V + .registers 2 + invoke-direct {v1} android/app/Activity.()V + + const-string v0 "Hello World!" + iput-object v0 v1 org/JesusFreke/HelloWorld2/HelloWorld2.helloWorld Ljava/lang/String; + + return-void +.end method + +.method public onCreate(Landroid/os/Bundle;)V + .registers 5 + + invoke-super {v3,v4} android/app/Activity.onCreate(Landroid/os/Bundle;)V + + new-instance v0 android/widget/TextView + invoke-direct {v0,v3} android/widget/TextView.(Landroid/content/Context;)V + + iget-object v1 v3 org/JesusFreke/HelloWorld2/HelloWorld2.helloWorld Ljava/lang/String; + + sget-object v2 org/JesusFreke/HelloWorld2/HelloWorld2.helloWorldStatic Ljava/lang/String; + invoke-virtual {v1, v2} java/lang/String.concat(Ljava/lang/String;)Ljava/lang/String; + + move-result-object v1 + + sget-object v2 org/JesusFreke/HelloWorld2/HelloWorld2.helloWorldStatic2 Ljava/lang/String; + invoke-virtual/range {v1 .. v2} java/lang/String.concat(Ljava/lang/String;)Ljava/lang/String; + + move-result-object v1 + + invoke-virtual {v0,v1} android/widget/TextView.setText(Ljava/lang/CharSequence;)V + invoke-virtual {v3,v0} org/JesusFreke/HelloWorld2/HelloWorld2.setContentView(Landroid/view/View;)V + + return-void +.end method + + diff --git a/src/test/resources/examples/Identifiers.smali b/src/test/resources/examples/Identifiers.smali new file mode 100644 index 00000000..b3a36cac --- /dev/null +++ b/src/test/resources/examples/Identifiers.smali @@ -0,0 +1,39 @@ +.class public org/JesusFreke/HelloWorld2/HelloWorld2 +.super android/app/Activity + +.field private static final final Ljava/lang/String; +.field private static final static I +.field private static final 1234 I +.field private static final 1234-5678 I +.field private static final 1E1000 I +.field private static final 1E-1000 I +.field private static final return I +.field private static final new-instance I +.field private static final I +.field private static final I +.field private static final test$abcd I + + +.method public constructor ()V + .registers 1 + invoke-direct {v0} android/app/Activity.()V + return-void +.end method + +.method public 1E-2000(Landroid/os/Bundle;)V + .registers 4 + + sget-object v0 java/lang/System.out Ljava/io/PrintStream; + + invoke-super {v2,v3} android/app/Activity.onCreate(Landroid/os/Bundle;)V + + new-instance v0 android/widget/TextView + invoke-direct {v0,v2} android/widget/TextView.(Landroid/content/Context;)V + const-string v1 "Hello World!" + invoke-virtual {v0,v1} android/widget/TextView.setText(Ljava/lang/CharSequence;)V + invoke-virtual {v2,v0} org/JesusFreke/HelloWorld2/HelloWorld2.setContentView(Landroid/view/View;)V + + return-void +.end method + + diff --git a/src/test/resources/examples/NoFields.smali b/src/test/resources/examples/NoFields.smali new file mode 100644 index 00000000..4d045cb9 --- /dev/null +++ b/src/test/resources/examples/NoFields.smali @@ -0,0 +1,28 @@ +.class public org/JesusFreke/HelloWorld2/HelloWorld2 +.super android/app/Activity + +.method public constructor ()V + .registers 1 + invoke-direct {v1} android/app/Activity.()V + + return-void +.end method + +.method public onCreate(Landroid/os/Bundle;)V + .registers 5 + + invoke-super {v3,v4} android/app/Activity.onCreate(Landroid/os/Bundle;)V + + const-string v1 "Hello World!" + + new-instance v0 android/widget/TextView + invoke-direct {v0,v3} android/widget/TextView.(Landroid/content/Context;)V + + + invoke-virtual {v0,v1} android/widget/TextView.setText(Ljava/lang/CharSequence;)V + invoke-virtual {v3,v0} org/JesusFreke/HelloWorld2/HelloWorld2.setContentView(Landroid/view/View;)V + + return-void +.end method + +