From b7bedc94cdf8f2cfba7727f2ce50545d03c44cab Mon Sep 17 00:00:00 2001 From: Ziver Koc Date: Sun, 31 Jan 2016 15:13:07 +0100 Subject: [PATCH] Basic implementation of Binary struct parsing --- src/zutil/ByteUtil.java | 33 ++++++++++++++ src/zutil/converters/Converter.java | 19 ++++++++ .../parser/binary/BinaryStructParser.java | 43 ++++++++++++++++--- test/zutil/test/ByteUtilTest.java | 24 +++++++++++ test/zutil/test/ConverterTest.java | 10 +++++ 5 files changed, 123 insertions(+), 6 deletions(-) create mode 100755 src/zutil/ByteUtil.java create mode 100755 test/zutil/test/ByteUtilTest.java mode change 100644 => 100755 test/zutil/test/ConverterTest.java diff --git a/src/zutil/ByteUtil.java b/src/zutil/ByteUtil.java new file mode 100755 index 0000000..5b44ac4 --- /dev/null +++ b/src/zutil/ByteUtil.java @@ -0,0 +1,33 @@ +package zutil; + +/** + * Utility functions for byte primitive type + * + * Created by Ziver on 2016-01-30. + */ +public class ByteUtil { + + private static final int[][] BYTE_MASK = new int[][]{ + {0b0000_0001}, + {0b0000_0010, 0b0000_0011}, + {0b0000_0100, 0b0000_0110, 0b0000_0111}, + {0b0000_1000, 0b0000_1100, 0b0000_1110, 0b0000_1111}, + {0b0001_0000, 0b0001_1000, 0b0001_1100, 0b0001_1110, 0b0001_1111}, + {0b0010_0000, 0b0011_0000, 0b0011_1000, 0b0011_1100, 0b0011_1110, 0b0011_1111}, + {0b0100_0000, 0b0110_0000, 0b0111_0000, 0b0111_1000, 0b0111_1100, 0b0111_1110, 0b0111_1111}, + {0b1000_0000, 0b1100_0000, 0b1110_0000, 0b1111_0000, 0b1111_1000, 0b1111_1100, 0b1111_1110, 0b1111_1111} + }; + + public static byte getBits(byte data, int index, int length){ + length--; + if(0 > index || index > 7) + throw new IllegalArgumentException("Invalid index argument, allowed value is 0-7"); + if(length < 0 && index-length < 0) + throw new IllegalArgumentException("Invalid length argument: "+length+", allowed values 1-8 depending on index"); + + int ret = data & BYTE_MASK[index][length]; + ret = ret >>> index-length; + return (byte) ret; + } + +} diff --git a/src/zutil/converters/Converter.java b/src/zutil/converters/Converter.java index ea147c7..f01f42c 100755 --- a/src/zutil/converters/Converter.java +++ b/src/zutil/converters/Converter.java @@ -307,6 +307,25 @@ public class Converter { return (int)(b & 0xff); } + /** + * Converts a dynamic sized byte array to a integer + * + * @param b is the byte array of size 1-4 + * @return the int value of the byte array + */ + public static int toInt(byte[] b){ + int i = 0; + switch (b.length){ + default: + case 4: i |= 0xFF000000 & (b[3] << 24); + case 3: i |= 0x00FF0000 & (b[2] << 16); + case 2: i |= 0x0000FF00 & (b[1] << 8); + case 1: i |= 0x000000FF & b[0]; break; + case 0: break; + } + return i; + } + /** * Converts a Integer to a BitSet * diff --git a/src/zutil/parser/binary/BinaryStructParser.java b/src/zutil/parser/binary/BinaryStructParser.java index e43f0ea..8c963ae 100755 --- a/src/zutil/parser/binary/BinaryStructParser.java +++ b/src/zutil/parser/binary/BinaryStructParser.java @@ -5,18 +5,20 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import zutil.ByteUtil; +import zutil.converters.Converter; import zutil.parser.binary.BinaryStruct.*; /** - * Created by ezivkoc on 2016-01-28. + * Created by Ziver on 2016-01-28. */ public class BinaryStructParser { - public static void parse(BinaryStruct struct, byte[] bytes) { + public static void parse(BinaryStruct struct, byte[] data) { List structDataList = getStructDataList(struct.getClass()); - int bitIndex; - for(BinaryFieldData field : structDataList){ - + int bitOffset = 0; + for (BinaryFieldData field : structDataList){ + bitOffset += field.setValue(struct, data, bitOffset); } } @@ -42,9 +44,38 @@ public class BinaryStructParser { field = f; BinaryField fieldData = field.getAnnotation(BinaryField.class); index = fieldData.index(); - length = fieldData.index(); + length = fieldData.length(); } + protected int setValue(Object obj, byte[] data, int bitOffset){ + try { + int byteIndex = bitOffset / 8; + int bitIndex = 7 - bitOffset % 8; + int bitLength = Math.min(bitIndex+1, length); + + int readLength = 0; + byte[] valueData = new byte[(int) Math.ceil(length / 8.0)]; + for (int index = valueData.length - 1; index >= 0; --index) { + valueData[index] = ByteUtil.getBits(data[byteIndex], bitIndex, bitLength); + readLength += bitLength; + byteIndex++; + bitIndex = 7; + bitLength = Math.min(bitIndex+1, length - readLength); + } + + field.setAccessible(true); + if (field.getType() == Boolean.class || field.getType() == boolean.class) + field.set(obj, valueData[0] != 0); + else if (field.getType() == Integer.class || field.getType() == int.class) + field.set(obj, Converter.toInt(valueData)); + else if (field.getType() == String.class) + field.set(obj, new String(valueData)); + return readLength; + } catch (IllegalAccessException e){ + e.printStackTrace(); + } + return length; // we return the configured length to not shift the data + } @Override public int compareTo(BinaryFieldData o) { diff --git a/test/zutil/test/ByteUtilTest.java b/test/zutil/test/ByteUtilTest.java new file mode 100755 index 0000000..228b999 --- /dev/null +++ b/test/zutil/test/ByteUtilTest.java @@ -0,0 +1,24 @@ +package zutil.test; + +import org.junit.Test; +import zutil.ByteUtil; + +import static org.junit.Assert.assertEquals; + +/** + * Created by Ziver on 2016-01-31. + */ +public class ByteUtilTest { + + + @Test + public void getBits(){ + assertEquals(1, ByteUtil.getBits((byte)0b1000_0000, 7, 1)); + assertEquals(1, ByteUtil.getBits((byte)0b0001_0000, 4, 1)); + assertEquals(1, ByteUtil.getBits((byte)0b0000_0001, 0, 1)); + + assertEquals(3, ByteUtil.getBits((byte)0b0110_0000, 6, 2)); + + assertEquals((byte)0xFF, ByteUtil.getBits((byte)0b1111_1111, 7, 8)); + } +} diff --git a/test/zutil/test/ConverterTest.java b/test/zutil/test/ConverterTest.java old mode 100644 new mode 100755 index 7fa2b9a..7a07811 --- a/test/zutil/test/ConverterTest.java +++ b/test/zutil/test/ConverterTest.java @@ -77,4 +77,14 @@ public class ConverterTest { Converter.urlDecode("9i34%202y9252%25%2623%20463765(%2f%26(") ); } + + @Test + public void byteArrayToInt(){ + assertEquals(0, Converter.toInt(new byte[]{})); + assertEquals(1, Converter.toInt(new byte[]{0b0000_0001})); + assertEquals(1, Converter.toInt(new byte[]{0x01,0x00})); + assertEquals(256, Converter.toInt(new byte[]{0x00,0x01,0x00})); + assertEquals(Integer.MAX_VALUE, Converter.toInt(new byte[]{(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0x7F})); + assertEquals(Integer.MAX_VALUE, Converter.toInt(new byte[]{(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0x7F,(byte)0xFF,(byte)0xFF})); + } }