From 72fac36a5c6742eb2e6769a1f51b90ee89907c27 Mon Sep 17 00:00:00 2001 From: amosshi Date: Fri, 27 Aug 2021 00:55:50 -0700 Subject: [PATCH] #11 DEX format - parse items - encoded_value in progress --- .../commonlib/core/PosDataInputStream.java | 38 +-- .../freeinternals/commonlib/ui/UITool.java | 2 +- .../org/freeinternals/format/dex/DexFile.java | 32 ++- .../format/dex/JTreeDexFile.java | 10 +- .../format/dex/PosDataInputStreamDex.java | 254 +++++++++++++++++- .../format/dex/annotation_set_ref_list.java | 8 +- .../format/dex/encoded_annotation.java | 3 +- .../format/dex/encoded_array.java | 33 ++- .../format/dex/encoded_value.java | 63 ++--- .../freeinternals/format/dex/header_item.java | 2 +- 10 files changed, 350 insertions(+), 95 deletions(-) diff --git a/CommonLib/src/main/java/org/freeinternals/commonlib/core/PosDataInputStream.java b/CommonLib/src/main/java/org/freeinternals/commonlib/core/PosDataInputStream.java index 6408580..42d6477 100644 --- a/CommonLib/src/main/java/org/freeinternals/commonlib/core/PosDataInputStream.java +++ b/CommonLib/src/main/java/org/freeinternals/commonlib/core/PosDataInputStream.java @@ -18,7 +18,7 @@ public class PosDataInputStream extends DataInputStream implements DataInputEx { public static final byte[] EMPTY_BYTE_ARRAY = {}; - + /** * Number in bytes for Java byte type. */ @@ -39,60 +39,60 @@ public class PosDataInputStream extends DataInputStream implements DataInputEx { /** * Shift Operators, offset with 8. */ - private static final int SHIFT_8 = 8; + protected static final int SHIFT_8 = 8; /** * Shift Operators, offset with 16. */ - private static final int SHIFT_16 = 16; + protected static final int SHIFT_16 = 16; /** * Shift Operators, offset with 24. */ - private static final int SHIFT_24 = 24; + protected static final int SHIFT_24 = 24; /** * Shift Operators, offset with 32. */ - private static final int SHIFT_32 = 32; + protected static final int SHIFT_32 = 32; /** * Shift Operators, offset with 40. */ - private static final int SHIFT_40 = 40; + protected static final int SHIFT_40 = 40; /** * Shift Operators, offset with 48. */ - private static final int SHIFT_48 = 48; + protected static final int SHIFT_48 = 48; /** * Shift Operators, offset with 56. */ - private static final int SHIFT_56 = 56; + protected static final int SHIFT_56 = 56; /** * Half Byte length: 4. */ - private static final int BYTE_LENGTH_4 = 4; + protected static final int BYTE_LENGTH_4 = 4; /** * Full Byte length: 8. */ - private static final int BYTE_LENGTH_8 = 8; + protected static final int BYTE_LENGTH_8 = 8; /** Byte offset 0. */ - private static final int BYTE_OFFSET_0 = 0; + protected static final int BYTE_OFFSET_0 = 0; /** Byte offset 1. */ - private static final int BYTE_OFFSET_1 = 1; + protected static final int BYTE_OFFSET_1 = 1; /** Byte offset 2. */ - private static final int BYTE_OFFSET_2 = 2; + protected static final int BYTE_OFFSET_2 = 2; /** Byte offset 3. */ - private static final int BYTE_OFFSET_3 = 3; + protected static final int BYTE_OFFSET_3 = 3; /** Byte offset 4. */ - private static final int BYTE_OFFSET_4 = 4; + protected static final int BYTE_OFFSET_4 = 4; /** Byte offset 5. */ - private static final int BYTE_OFFSET_5 = 5; + protected static final int BYTE_OFFSET_5 = 5; /** Byte offset 6. */ - private static final int BYTE_OFFSET_6 = 6; + protected static final int BYTE_OFFSET_6 = 6; /** Byte offset 7. */ - private static final int BYTE_OFFSET_7 = 7; + protected static final int BYTE_OFFSET_7 = 7; /** * Byte max value: 255. */ - private static final int BYTE_MAX_255 = 255; + protected static final int BYTE_MAX_255 = 255; /** * New line character: LINE FEED (LF). diff --git a/CommonLib/src/main/java/org/freeinternals/commonlib/ui/UITool.java b/CommonLib/src/main/java/org/freeinternals/commonlib/ui/UITool.java index cb3d300..fefc241 100644 --- a/CommonLib/src/main/java/org/freeinternals/commonlib/ui/UITool.java +++ b/CommonLib/src/main/java/org/freeinternals/commonlib/ui/UITool.java @@ -33,7 +33,7 @@ public final class UITool { * * @see #left(String) */ - public static final int TREENODE_STRING_MAXLEN = 30; + public static final int TREENODE_STRING_MAXLEN = 64; private UITool() { } diff --git a/FormatDEX/src/main/java/org/freeinternals/format/dex/DexFile.java b/FormatDEX/src/main/java/org/freeinternals/format/dex/DexFile.java index 2bb6c8e..344ab84 100644 --- a/FormatDEX/src/main/java/org/freeinternals/format/dex/DexFile.java +++ b/FormatDEX/src/main/java/org/freeinternals/format/dex/DexFile.java @@ -10,9 +10,6 @@ import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; @@ -65,8 +62,10 @@ public final class DexFile extends FileFormat { * monotonically over time as the format evolves. *

*/ - public static final List DEX_FILE_MAGIC1 = Collections.unmodifiableList(Arrays.asList(new Byte[]{'d', 'e', 'x', '\n'})); - public static final List DEX_FILE_MAGIC2 = Collections.unmodifiableList(Arrays.asList(new Byte[]{'0', '3', '5', '\0'})); + @SuppressWarnings("java:S2386") + static final byte[] DEX_FILE_MAGIC1 = new byte[]{'d', 'e', 'x', '\n'}; + @SuppressWarnings("java:S2386") + static final byte[] DEX_FILE_MAGIC2 = new byte[]{'0', '3', '5', '\0'}; /** * Magic value part 1. @@ -110,22 +109,21 @@ public DexFile(File file) throws IOException, FileFormatException { super(file); // Check the file signature - this.magic1 = new byte[DEX_FILE_MAGIC1.size()]; - this.magic2 = new byte[DEX_FILE_MAGIC2.size()]; - System.arraycopy(super.fileByteArray, 0, magic1, 0, DEX_FILE_MAGIC1.size()); - System.arraycopy(super.fileByteArray, 4, magic2, 0, DEX_FILE_MAGIC2.size()); - - byte[] magic1Const = new byte[]{DEX_FILE_MAGIC1.get(0), DEX_FILE_MAGIC1.get(1), DEX_FILE_MAGIC1.get(2), DEX_FILE_MAGIC1.get(3)}; - if (!BytesTool.isByteArraySame(magic1Const, magic1) - || magic2[DEX_FILE_MAGIC2.size() - 1] != DEX_FILE_MAGIC2.get(DEX_FILE_MAGIC2.size() - 1)) { + this.magic1 = new byte[DEX_FILE_MAGIC1.length]; + this.magic2 = new byte[DEX_FILE_MAGIC2.length]; + System.arraycopy(super.fileByteArray, 0, magic1, 0, DEX_FILE_MAGIC1.length); + System.arraycopy(super.fileByteArray, 4, magic2, 0, DEX_FILE_MAGIC2.length); + + if (!BytesTool.isByteArraySame(DEX_FILE_MAGIC1, magic1) + || magic2[DEX_FILE_MAGIC2.length - 1] != DEX_FILE_MAGIC2[DEX_FILE_MAGIC2.length - 1]) { throw new FileFormatException("This is not a valid DEX file, because the DEX file signature does not exist at the beginning of this file."); } // Parse section by section PosDataInputStream parseEndian = new PosDataInputStream(new PosByteArrayInputStream(super.fileByteArray)); - BytesTool.skip(parseEndian, DEX_FILE_MAGIC1.size()); - BytesTool.skip(parseEndian, DEX_FILE_MAGIC2.size()); + BytesTool.skip(parseEndian, DEX_FILE_MAGIC1.length); + BytesTool.skip(parseEndian, DEX_FILE_MAGIC2.length); BytesTool.skip(parseEndian, Type_uint.LENGTH); // checksum BytesTool.skip(parseEndian, 20); // signature BytesTool.skip(parseEndian, Type_uint.LENGTH); // file_size @@ -153,8 +151,8 @@ public DexFile(File file) throws IOException, FileFormatException { SortedMap> todoData = new TreeMap<>(); // Header - BytesTool.skip(stream, DEX_FILE_MAGIC1.size()); - BytesTool.skip(stream, DEX_FILE_MAGIC2.size()); + BytesTool.skip(stream, DEX_FILE_MAGIC1.length); + BytesTool.skip(stream, DEX_FILE_MAGIC2.length); this.header = new header_item(stream); // string_ids diff --git a/FormatDEX/src/main/java/org/freeinternals/format/dex/JTreeDexFile.java b/FormatDEX/src/main/java/org/freeinternals/format/dex/JTreeDexFile.java index 9c68e2a..de06f5a 100644 --- a/FormatDEX/src/main/java/org/freeinternals/format/dex/JTreeDexFile.java +++ b/FormatDEX/src/main/java/org/freeinternals/format/dex/JTreeDexFile.java @@ -7,11 +7,9 @@ package org.freeinternals.format.dex; import java.nio.charset.StandardCharsets; -import java.util.Map; import java.util.logging.Logger; import javax.swing.Icon; import javax.swing.tree.DefaultMutableTreeNode; -import org.freeinternals.commonlib.core.FileComponent; import org.freeinternals.commonlib.ui.GenerateTreeNode; import org.freeinternals.commonlib.ui.JTreeNodeFileComponent; import org.freeinternals.commonlib.ui.UITool; @@ -78,22 +76,22 @@ private void generate_magic(DefaultMutableTreeNode parentNode, DexFile dexFile) DefaultMutableTreeNode magicNode = new DefaultMutableTreeNode(new JTreeNodeFileComponent( startPos, - DexFile.DEX_FILE_MAGIC1.size() + DexFile.DEX_FILE_MAGIC2.size(), + DexFile.DEX_FILE_MAGIC1.length + DexFile.DEX_FILE_MAGIC2.length, "magic")); parentNode.add(magicNode); magicNode.add(new DefaultMutableTreeNode(new JTreeNodeFileComponent( startPos, - DexFile.DEX_FILE_MAGIC1.size(), + DexFile.DEX_FILE_MAGIC1.length, "magic 1: " + new String(dexFile.magic1, StandardCharsets.UTF_8), UITool.icon4Magic(), GenerateTreeNodeDexFile.MESSAGES.getString("msg_dex_file_magic1") ))); - startPos += DexFile.DEX_FILE_MAGIC1.size(); + startPos += DexFile.DEX_FILE_MAGIC1.length; magicNode.add(new DefaultMutableTreeNode(new JTreeNodeFileComponent( startPos, - DexFile.DEX_FILE_MAGIC2.size(), + DexFile.DEX_FILE_MAGIC2.length, "magic 2: " + new String(dexFile.magic2, StandardCharsets.UTF_8), UITool.icon4Magic(), GenerateTreeNodeDexFile.MESSAGES.getString("msg_dex_file_magic2") diff --git a/FormatDEX/src/main/java/org/freeinternals/format/dex/PosDataInputStreamDex.java b/FormatDEX/src/main/java/org/freeinternals/format/dex/PosDataInputStreamDex.java index 74eb2fb..45e3068 100644 --- a/FormatDEX/src/main/java/org/freeinternals/format/dex/PosDataInputStreamDex.java +++ b/FormatDEX/src/main/java/org/freeinternals/format/dex/PosDataInputStreamDex.java @@ -6,6 +6,7 @@ */ package org.freeinternals.format.dex; +import java.io.EOFException; import java.io.IOException; import org.freeinternals.commonlib.core.PosByteArrayInputStream; import org.freeinternals.commonlib.core.PosDataInputStream; @@ -15,14 +16,28 @@ /** * * @author Amos Shi - * + * *
  * java:S100 - Method names should comply with a naming convention --- We use different naming convention for better readablity
+ * java:S1110 - Redundant parenthesis --- Redundant parenthesis is needed for readability
  * 
*/ -@SuppressWarnings("java:S100") +@SuppressWarnings({"java:S100", "java:S1110"}) public class PosDataInputStreamDex extends PosDataInputStream { + /** + * Full Byte length: 3. + */ + private static final int BYTE_LENGTH_3 = 3; + private static final int BYTE_LENGTH_5 = 5; + private static final int BYTE_LENGTH_6 = 6; + private static final int BYTE_LENGTH_7 = 7; + + /** + * Byte position: 6. + */ + private static final int BYTE_POSITION_5 = 5; + /** * Endian of the {@link DexFile}. The default value is little-endian * {@link header_item.Endian#ENDIAN_CONSTANT}, as the DEX format @@ -102,6 +117,20 @@ public Type_int Dex_int() throws IOException { } } + /** + * Read a 3-byte {@link Type_int} from the input stream. + * + * @return a {@link Type_int} + * @throws IOException I/O Error + */ + public Type_int Dex_int3() throws IOException { + if (this.endian == header_item.Endian.ENDIAN_CONSTANT) { + return new Type_int(this.readInt3()); + } else { + return new Type_int(this.readInt3InLittleEndian()); + } + } + /** * Read a {@link Type_uint} from the input stream. * @@ -116,6 +145,20 @@ public Type_uint Dex_uint() throws IOException { } } + /** + * Read a {@link Type_uint} from the input stream for only 3 bytes. + * + * @return a {@link Type_uint} + * @throws IOException I/O Error + */ + public Type_uint Dex_uint3() throws IOException { + if (this.endian.value == header_item.Endian.ENDIAN_CONSTANT.value) { + return new Type_uint(this.readUnsignedInt3()); + } else { + return new Type_uint(this.readUnsignedInt3InLittleEndian()); + } + } + /** * Read a {@link Type_long} from the input stream. * @@ -130,6 +173,39 @@ public Type_long Dex_long() throws IOException { } } + /** + * Read a 5/6/7-byte {@link Type_long} from the input stream. + * + * @param length Dynamic long length value: 5, 6, or 7 + * @return a {@link Type_long} + * @throws IOException I/O Error + */ + public Type_long Dex_long(int length) throws IOException { + if (this.endian == header_item.Endian.ENDIAN_CONSTANT) { + switch (length) { + case 5: + return new Type_long(this.readLong5()); + case 6: + return new Type_long(this.readLong6()); + case 7: + return new Type_long(this.readLong7()); + default: + } + } else { + switch (length) { + case 5: + return new Type_long(this.readLong5InLittleEndian()); + case 6: + return new Type_long(this.readLong6InLittleEndian()); + case 7: + return new Type_long(this.readLong7InLittleEndian()); + default: + } + } + + throw new IllegalArgumentException(String.format("Unexpected long value length: %d", length)); + } + /** * Read a {@link Type_ulong} from the input stream. * @@ -213,4 +289,178 @@ public Type_uleb128p1 Dex_uleb128p1() throws IOException, FileFormatException { Type_uleb128 uleb128 = this.Dex_uleb128(); return new Type_uleb128p1(uleb128.value - 1, uleb128.length); } + + /** + * Read 3-byte int. + */ + private int readInt3() throws IOException { + int ch1 = this.in.read(); + int ch2 = this.in.read(); + int ch3 = this.in.read(); + if ((ch1 | ch2 | ch3) < 0) { + throw new EOFException(); + } + + if ((ch3 & 0x80) > 0) { + System.out.println("TODO verify - 3-byte int test case at 0x" + Integer.toHexString(this.getPos()) + " ----------------------- readInt3 ----"); + return 0xFF000000 | (ch1 << SHIFT_16) | (ch2 << SHIFT_8) | (ch3); + } else { + return (ch1 << SHIFT_16) | (ch2 << SHIFT_8) | (ch3); + } + } + + /** + * Read 3-byte int in little-endian. + */ + private int readInt3InLittleEndian() throws IOException { + int ch1 = this.in.read(); + int ch2 = this.in.read(); + int ch3 = this.in.read(); + if ((ch1 | ch2 | ch3) < 0) { + throw new EOFException(); + } + + if ((ch3 & 0x80) > 0) { + // System.out.println("TODO verify via Java source code via minus value - 3-byte int test case at 0x" + Integer.toHexString(this.getPos()) + " ----------------------- readIntInLittleEndian3 ----"); + return 0xFF000000 | (ch3 << SHIFT_16) | (ch2 << SHIFT_8) | (ch1); + } else { + return (ch3 << SHIFT_16) | (ch2 << SHIFT_8) | (ch1); + } + } + + private long readLong5() throws IOException { + final byte[] readBuffer = new byte[BYTE_LENGTH_8]; + super.readFully(readBuffer, 3, BYTE_LENGTH_5); + + // TODO + return (((long) readBuffer[BYTE_OFFSET_7] << SHIFT_56) + | ((long) (readBuffer[BYTE_OFFSET_6] & BYTE_MAX_255) << SHIFT_48) + | ((long) (readBuffer[BYTE_OFFSET_5] & BYTE_MAX_255) << SHIFT_40) + | ((long) (readBuffer[BYTE_OFFSET_4] & BYTE_MAX_255) << SHIFT_32) + | ((long) (readBuffer[BYTE_OFFSET_3] & BYTE_MAX_255) << SHIFT_24) + | ((readBuffer[BYTE_OFFSET_2] & BYTE_MAX_255) << SHIFT_16) + | ((readBuffer[BYTE_OFFSET_1] & BYTE_MAX_255) << SHIFT_8) + | ((readBuffer[BYTE_OFFSET_0] & BYTE_MAX_255))); + } + private long readLong5InLittleEndian() throws IOException { + final byte[] readBuffer = new byte[BYTE_LENGTH_8]; + super.readFully(readBuffer, 3, BYTE_LENGTH_5); + + // TODO + return (((long) readBuffer[BYTE_OFFSET_7] << SHIFT_56) + | ((long) (readBuffer[BYTE_OFFSET_6] & BYTE_MAX_255) << SHIFT_48) + | ((long) (readBuffer[BYTE_OFFSET_5] & BYTE_MAX_255) << SHIFT_40) + | ((long) (readBuffer[BYTE_OFFSET_4] & BYTE_MAX_255) << SHIFT_32) + | ((long) (readBuffer[BYTE_OFFSET_3] & BYTE_MAX_255) << SHIFT_24) + | ((readBuffer[BYTE_OFFSET_2] & BYTE_MAX_255) << SHIFT_16) + | ((readBuffer[BYTE_OFFSET_1] & BYTE_MAX_255) << SHIFT_8) + | ((readBuffer[BYTE_OFFSET_0] & BYTE_MAX_255))); + } + + private long readLong6() throws IOException { + final byte[] readBuffer = new byte[BYTE_LENGTH_8]; + super.readFully(readBuffer, 2, BYTE_LENGTH_6); + + // TODO + return (((long) readBuffer[BYTE_OFFSET_7] << SHIFT_56) + | ((long) (readBuffer[BYTE_OFFSET_6] & BYTE_MAX_255) << SHIFT_48) + | ((long) (readBuffer[BYTE_OFFSET_5] & BYTE_MAX_255) << SHIFT_40) + | ((long) (readBuffer[BYTE_OFFSET_4] & BYTE_MAX_255) << SHIFT_32) + | ((long) (readBuffer[BYTE_OFFSET_3] & BYTE_MAX_255) << SHIFT_24) + | ((readBuffer[BYTE_OFFSET_2] & BYTE_MAX_255) << SHIFT_16) + | ((readBuffer[BYTE_OFFSET_1] & BYTE_MAX_255) << SHIFT_8) + | ((readBuffer[BYTE_OFFSET_0] & BYTE_MAX_255))); + } + private long readLong6InLittleEndian() throws IOException { + final byte[] readBuffer = new byte[BYTE_LENGTH_8]; + super.readFully(readBuffer, 2, BYTE_LENGTH_6); + + // TODO + return (((long) readBuffer[BYTE_OFFSET_7] << SHIFT_56) + | ((long) (readBuffer[BYTE_OFFSET_6] & BYTE_MAX_255) << SHIFT_48) + | ((long) (readBuffer[BYTE_OFFSET_5] & BYTE_MAX_255) << SHIFT_40) + | ((long) (readBuffer[BYTE_OFFSET_4] & BYTE_MAX_255) << SHIFT_32) + | ((long) (readBuffer[BYTE_OFFSET_3] & BYTE_MAX_255) << SHIFT_24) + | ((readBuffer[BYTE_OFFSET_2] & BYTE_MAX_255) << SHIFT_16) + | ((readBuffer[BYTE_OFFSET_1] & BYTE_MAX_255) << SHIFT_8) + | ((readBuffer[BYTE_OFFSET_0] & BYTE_MAX_255))); + } + + private long readLong7() throws IOException { + final byte[] readBuffer = new byte[BYTE_LENGTH_8]; + super.readFully(readBuffer, 1, BYTE_LENGTH_7); + + // TODO + return (((long) readBuffer[BYTE_OFFSET_7] << SHIFT_56) + | ((long) (readBuffer[BYTE_OFFSET_6] & BYTE_MAX_255) << SHIFT_48) + | ((long) (readBuffer[BYTE_OFFSET_5] & BYTE_MAX_255) << SHIFT_40) + | ((long) (readBuffer[BYTE_OFFSET_4] & BYTE_MAX_255) << SHIFT_32) + | ((long) (readBuffer[BYTE_OFFSET_3] & BYTE_MAX_255) << SHIFT_24) + | ((readBuffer[BYTE_OFFSET_2] & BYTE_MAX_255) << SHIFT_16) + | ((readBuffer[BYTE_OFFSET_1] & BYTE_MAX_255) << SHIFT_8) + | ((readBuffer[BYTE_OFFSET_0] & BYTE_MAX_255))); + } + private long readLong7InLittleEndian() throws IOException { + final byte[] readBuffer = new byte[BYTE_LENGTH_8]; + super.readFully(readBuffer, 1, BYTE_LENGTH_7); + + // TODO + return (((long) readBuffer[BYTE_OFFSET_7] << SHIFT_56) + | ((long) (readBuffer[BYTE_OFFSET_6] & BYTE_MAX_255) << SHIFT_48) + | ((long) (readBuffer[BYTE_OFFSET_5] & BYTE_MAX_255) << SHIFT_40) + | ((long) (readBuffer[BYTE_OFFSET_4] & BYTE_MAX_255) << SHIFT_32) + | ((long) (readBuffer[BYTE_OFFSET_3] & BYTE_MAX_255) << SHIFT_24) + | ((readBuffer[BYTE_OFFSET_2] & BYTE_MAX_255) << SHIFT_16) + | ((readBuffer[BYTE_OFFSET_1] & BYTE_MAX_255) << SHIFT_8) + | ((readBuffer[BYTE_OFFSET_0] & BYTE_MAX_255))); + } + + /** + * Read 3-byte unsigned int. + */ + private long readUnsignedInt3() throws IOException { + final byte[] readBuffer = new byte[BYTE_LENGTH_8]; + + super.readFully(readBuffer, BYTE_POSITION_5, BYTE_LENGTH_3); + readBuffer[BYTE_OFFSET_0] = 0; + readBuffer[BYTE_OFFSET_1] = 0; + readBuffer[BYTE_OFFSET_2] = 0; + readBuffer[BYTE_OFFSET_3] = 0; + readBuffer[BYTE_OFFSET_4] = 0; + + return (((long) readBuffer[BYTE_OFFSET_0] << SHIFT_56) + + ((long) (readBuffer[BYTE_OFFSET_1] & BYTE_MAX_255) << SHIFT_48) + + ((long) (readBuffer[BYTE_OFFSET_2] & BYTE_MAX_255) << SHIFT_40) + + ((long) (readBuffer[BYTE_OFFSET_3] & BYTE_MAX_255) << SHIFT_32) + + ((long) (readBuffer[BYTE_OFFSET_4] & BYTE_MAX_255) << SHIFT_24) + + ((readBuffer[BYTE_OFFSET_5] & BYTE_MAX_255) << SHIFT_16) + + ((readBuffer[BYTE_OFFSET_6] & BYTE_MAX_255) << SHIFT_8) + + ((readBuffer[BYTE_OFFSET_7] & BYTE_MAX_255))); + } + + /** + * Read 3-byte unsigned int in little-endian. + */ + private long readUnsignedInt3InLittleEndian() throws IOException { + final byte[] readBuffer = new byte[BYTE_LENGTH_8]; + + super.readFully(readBuffer, 0, BYTE_LENGTH_3); + readBuffer[BYTE_OFFSET_7] = readBuffer[BYTE_OFFSET_0]; + readBuffer[BYTE_OFFSET_6] = readBuffer[BYTE_OFFSET_1]; + readBuffer[BYTE_OFFSET_5] = readBuffer[BYTE_OFFSET_2]; + readBuffer[BYTE_OFFSET_4] = 0; + readBuffer[BYTE_OFFSET_3] = 0; + readBuffer[BYTE_OFFSET_2] = 0; + readBuffer[BYTE_OFFSET_1] = 0; + readBuffer[BYTE_OFFSET_0] = 0; + + return (((long) readBuffer[BYTE_OFFSET_0] << SHIFT_56) + + ((long) (readBuffer[BYTE_OFFSET_1] & BYTE_MAX_255) << SHIFT_48) + + ((long) (readBuffer[BYTE_OFFSET_2] & BYTE_MAX_255) << SHIFT_40) + + ((long) (readBuffer[BYTE_OFFSET_3] & BYTE_MAX_255) << SHIFT_32) + + ((long) (readBuffer[BYTE_OFFSET_4] & BYTE_MAX_255) << SHIFT_24) + + ((readBuffer[BYTE_OFFSET_5] & BYTE_MAX_255) << SHIFT_16) + + ((readBuffer[BYTE_OFFSET_6] & BYTE_MAX_255) << SHIFT_8) + + ((readBuffer[BYTE_OFFSET_7] & BYTE_MAX_255))); + } } diff --git a/FormatDEX/src/main/java/org/freeinternals/format/dex/annotation_set_ref_list.java b/FormatDEX/src/main/java/org/freeinternals/format/dex/annotation_set_ref_list.java index df3fa83..0f47533 100644 --- a/FormatDEX/src/main/java/org/freeinternals/format/dex/annotation_set_ref_list.java +++ b/FormatDEX/src/main/java/org/freeinternals/format/dex/annotation_set_ref_list.java @@ -89,8 +89,12 @@ public void generateTreeNode(DefaultMutableTreeNode parentNode, DexFile dexFile) UITool.icon4Offset() ); + if (refItem.annotations_off.value == 0) { + continue; + } + FileComponent fc = dexFile.data.get(refItem.annotations_off.value); - //annotation_set_item item = (annotation_set_item) + //annotation_set_item item = (annotation_set_item) DefaultMutableTreeNode itemNode = new DefaultMutableTreeNode(new JTreeNodeFileComponent( fc.getStartPos(), fc.getLength(), @@ -100,7 +104,7 @@ public void generateTreeNode(DefaultMutableTreeNode parentNode, DexFile dexFile) )); refItemNode.add(itemNode); if (fc instanceof GenerateTreeNodeDexFile) { - ((GenerateTreeNodeDexFile)fc).generateTreeNode(itemNode, dexFile); + ((GenerateTreeNodeDexFile) fc).generateTreeNode(itemNode, dexFile); } } } diff --git a/FormatDEX/src/main/java/org/freeinternals/format/dex/encoded_annotation.java b/FormatDEX/src/main/java/org/freeinternals/format/dex/encoded_annotation.java index ada48c2..f21358f 100644 --- a/FormatDEX/src/main/java/org/freeinternals/format/dex/encoded_annotation.java +++ b/FormatDEX/src/main/java/org/freeinternals/format/dex/encoded_annotation.java @@ -139,9 +139,10 @@ public static class annotation_element extends FileComponent implements Generate super.startPos = stream.getPos(); this.name_idx = stream.Dex_uleb128(); - try { // Dev phase only + try { // TODO Dev phase only this.value = new encoded_value(stream); } catch (FileFormatException e) { + // This should never happen LOGGER.log(Level.SEVERE, e.getMessage(), e); } diff --git a/FormatDEX/src/main/java/org/freeinternals/format/dex/encoded_array.java b/FormatDEX/src/main/java/org/freeinternals/format/dex/encoded_array.java index 62a0a28..f22af3c 100644 --- a/FormatDEX/src/main/java/org/freeinternals/format/dex/encoded_array.java +++ b/FormatDEX/src/main/java/org/freeinternals/format/dex/encoded_array.java @@ -7,6 +7,8 @@ package org.freeinternals.format.dex; import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; import javax.swing.tree.DefaultMutableTreeNode; import org.freeinternals.commonlib.core.FileComponent; import org.freeinternals.commonlib.core.FileFormatException; @@ -27,6 +29,7 @@ @SuppressWarnings({"java:S101", "java:S116", "java:S1104"}) public class encoded_array extends FileComponent implements GenerateTreeNodeDexFile { + private static final Logger LOGGER = Logger.getLogger(encoded_array.class.getName()); public final Type_uleb128 size; public final encoded_value[] values; @@ -36,7 +39,12 @@ public class encoded_array extends FileComponent implements GenerateTreeNodeDexF if (this.size.value > 0) { this.values = new encoded_value[this.size.value]; for (int i = 0; i < this.size.value; i++) { - this.values[i] = new encoded_value(stream); + try { + this.values[i] = new encoded_value(stream); + } catch (FileFormatException e) { + // This should never happen + LOGGER.log(Level.SEVERE, e.getMessage(), e); + } } } else { this.values = null; @@ -74,16 +82,21 @@ public void generateTreeNode(DefaultMutableTreeNode parentNode, DexFile dexFile) for (int i = 0; i < this.values.length; i++) { encoded_value value = this.values[i]; - DefaultMutableTreeNode valueNode = new DefaultMutableTreeNode(new JTreeNodeFileComponent( - value.getStartPos(), - value.getLength(), - String.format("%s[%d] %s", value.getClass().getSimpleName(), i, value.toString()), - UITool.icon4Data(), - MESSAGES.getString("msg_encoded_value") - )); + if (value != null) { + DefaultMutableTreeNode valueNode = new DefaultMutableTreeNode(new JTreeNodeFileComponent( + value.getStartPos(), + value.getLength(), + String.format("%s[%d] %s", value.getClass().getSimpleName(), i, value.toString()), + UITool.icon4Data(), + MESSAGES.getString("msg_encoded_value") + )); - valuesNode.add(valueNode); - value.generateTreeNode(valueNode, dexFile); + valuesNode.add(valueNode); + value.generateTreeNode(valueNode, dexFile); + } else { + // This should never happen + LOGGER.log(Level.SEVERE, "{0} at 0x{1} : value[{2}] is null", new Object[]{this.getClass().getSimpleName(), Integer.toHexString(this.getStartPos()), i}); + } } } } diff --git a/FormatDEX/src/main/java/org/freeinternals/format/dex/encoded_value.java b/FormatDEX/src/main/java/org/freeinternals/format/dex/encoded_value.java index 4fd1ebd..5cf3e9b 100644 --- a/FormatDEX/src/main/java/org/freeinternals/format/dex/encoded_value.java +++ b/FormatDEX/src/main/java/org/freeinternals/format/dex/encoded_value.java @@ -56,6 +56,12 @@ public class encoded_value extends FileComponent implements GenerateTreeNodeDexF private encoded_annotation union_value_annotation; private Boolean union_value_bollean; + /** + *
+     * java:S3776 - Cognitive Complexity of methods should not be too high --- No, it is not high
+     * 
+ */ + @SuppressWarnings({"java:S127", "java:S3776"}) encoded_value(final PosDataInputStreamDex stream) throws IOException, FileFormatException { super.startPos = stream.getPos(); value_arg_and_type = stream.Dex_ubyte(); @@ -84,21 +90,12 @@ public class encoded_value extends FileComponent implements GenerateTreeNodeDexF this.union_value_int = this.read_int(stream, this.value_arg); break; case VALUE_LONG: - if (this.value_arg != 7) { - System.out.println(this.getClass().getSimpleName() + " VALUE_LONG value_arg is not 7 but " + this.value_arg + " - to test"); - } - this.union_value_long = this.read_long(stream, length); + this.union_value_long = this.read_long(stream, this.value_arg); break; case VALUE_FLOAT: - if (this.value_arg != 3) { - System.out.println(this.getClass().getSimpleName() + " VALUE_FLOAT value_arg is not 3 but " + this.value_arg + " - to test"); - } this.union_value_float = this.read_float(stream, this.value_arg); break; case VALUE_DOUBLE: - if (this.value_arg != 7) { - System.out.println(this.getClass().getSimpleName() + " VALUE_DOUBLE value_arg is not 7 but " + this.value_arg + " - to test"); - } this.union_value_double = this.read_double(stream, this.value_arg); break; case VALUE_METHOD_TYPE: @@ -220,22 +217,22 @@ private Type_long read_long(final PosDataInputStreamDex stream, final int arg) t result = new Type_long(stream.Dex_short().value); break; + case 2: + result = new Type_long(stream.Dex_int3().value); + if (result.value < 0) { + System.out.println(this.getClass().getSimpleName() + String.format(" : read_long for triple bytes (minus value) at 0x%X ======= to verify =======", stream.getPos()) ); + } + break; + case 3: result = new Type_long(stream.Dex_int().value); break; - case 2: case 4: case 5: case 6: - // TODO - byte[] raw = new byte[arg + 1]; - int rb = stream.read(raw); - System.out.println(this.getClass().getSimpleName() + " Unhandled case encountered for long - TODO implement logic - readbytes=" + rb); - if (rb != arg + 1) { - throw new IOException(String.format("Cannot read enough bytes for long. expected=%d readbytes=%d", arg + 1, rb)); - } - result = new Type_long(5); + System.out.println(this.getClass().getSimpleName() + " : read_long for bytes 5/6/7 at 0x" + Integer.toHexString(stream.getPos()).toUpperCase() + " ======= to verify ======="); + result = stream.Dex_long(arg + 1); break; case 7: @@ -256,6 +253,10 @@ private Type_long read_long(final PosDataInputStreamDex stream, final int arg) t private Float read_float(final PosDataInputStreamDex stream, final int arg) throws IOException{ Float result = Float.MIN_VALUE; // TODO convert the bytes to float + if (arg != 3) { + System.out.println(this.getClass().getSimpleName() + " VALUE_FLOAT value_arg is not 3 but " + this.value_arg + " at 0x" + Integer.toHexString(stream.getPos()) + " - to implment"); + } + byte[] raw = new byte[arg + 1]; int rb = stream.read(raw); if (rb != arg + 1) { @@ -264,10 +265,14 @@ private Float read_float(final PosDataInputStreamDex stream, final int arg) thro return result; } - + private Double read_double(final PosDataInputStreamDex stream, final int arg) throws IOException{ Double result = Double.MAX_VALUE; // TODO convert the bytes to double + if (arg != 7) { + System.out.println(this.getClass().getSimpleName() + " VALUE_DOUBLE value_arg is not 7 but " + this.value_arg + " at 0x" + Integer.toHexString(stream.getPos()) + " - to implment"); + } + byte[] raw = new byte[arg + 1]; int rb = stream.read(raw); if (rb != arg + 1) { @@ -328,14 +333,7 @@ private Type_int read_int(final PosDataInputStreamDex stream, final int arg) thr result = new Type_int(stream.Dex_short().value); break; case 2: - // TODO - byte[] raw = new byte[arg + 1]; - int rb = stream.read(raw); - System.out.println(this.getClass().getSimpleName() + " Unhandled case encountered: triple bytes int - TODO implement logic - readbytes=" + rb); - if (rb != arg + 1) { - throw new IOException(String.format("Cannot read enough bytes for float. expected=%d readbytes=%d", arg + 1, rb)); - } - result = new Type_int(3); + result = stream.Dex_int3(); break; case 3: result = stream.Dex_int(); @@ -361,14 +359,7 @@ private Type_uint read_uint(final PosDataInputStreamDex stream, final int arg) t result = new Type_uint(stream.Dex_ushort().value); break; case 2: - // todo - byte[] raw = new byte[arg + 1]; - int rb = stream.read(raw); - System.out.println(this.getClass().getSimpleName() + " Unhandled case encountered: triple bytes uint - TODO implement logic - readbytes=" + rb); - if (rb != arg + 1) { - throw new IOException(String.format("Cannot read enough bytes for float. expected=%d readbytes=%d", arg + 1, rb)); - } - result = new Type_uint(2); + result = stream.Dex_uint3(); break; case 3: result = stream.Dex_uint(); diff --git a/FormatDEX/src/main/java/org/freeinternals/format/dex/header_item.java b/FormatDEX/src/main/java/org/freeinternals/format/dex/header_item.java index 64eff11..5ae1e11 100644 --- a/FormatDEX/src/main/java/org/freeinternals/format/dex/header_item.java +++ b/FormatDEX/src/main/java/org/freeinternals/format/dex/header_item.java @@ -119,7 +119,7 @@ public class header_item extends FileComponent implements GenerateTreeNode { this.data_size = stream.Dex_uint(); this.data_off = stream.Dex_uint(); - super.length = this.header_size.intValue() - DexFile.DEX_FILE_MAGIC1.size() - DexFile.DEX_FILE_MAGIC2.size(); + super.length = this.header_size.intValue() - DexFile.DEX_FILE_MAGIC1.length - DexFile.DEX_FILE_MAGIC2.length; } @Override