Basic implementation of Binary struct parsing
This commit is contained in:
parent
da54bc8db5
commit
b7bedc94cd
5 changed files with 123 additions and 6 deletions
33
src/zutil/ByteUtil.java
Executable file
33
src/zutil/ByteUtil.java
Executable file
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -307,6 +307,25 @@ public class Converter {
|
||||||
return (int)(b & 0xff);
|
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
|
* Converts a Integer to a BitSet
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -5,18 +5,20 @@ import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import zutil.ByteUtil;
|
||||||
|
import zutil.converters.Converter;
|
||||||
import zutil.parser.binary.BinaryStruct.*;
|
import zutil.parser.binary.BinaryStruct.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by ezivkoc on 2016-01-28.
|
* Created by Ziver on 2016-01-28.
|
||||||
*/
|
*/
|
||||||
public class BinaryStructParser {
|
public class BinaryStructParser {
|
||||||
|
|
||||||
public static void parse(BinaryStruct struct, byte[] bytes) {
|
public static void parse(BinaryStruct struct, byte[] data) {
|
||||||
List<BinaryFieldData> structDataList = getStructDataList(struct.getClass());
|
List<BinaryFieldData> structDataList = getStructDataList(struct.getClass());
|
||||||
int bitIndex;
|
int bitOffset = 0;
|
||||||
for(BinaryFieldData field : structDataList){
|
for (BinaryFieldData field : structDataList){
|
||||||
|
bitOffset += field.setValue(struct, data, bitOffset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -42,9 +44,38 @@ public class BinaryStructParser {
|
||||||
field = f;
|
field = f;
|
||||||
BinaryField fieldData = field.getAnnotation(BinaryField.class);
|
BinaryField fieldData = field.getAnnotation(BinaryField.class);
|
||||||
index = fieldData.index();
|
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
|
@Override
|
||||||
public int compareTo(BinaryFieldData o) {
|
public int compareTo(BinaryFieldData o) {
|
||||||
|
|
|
||||||
24
test/zutil/test/ByteUtilTest.java
Executable file
24
test/zutil/test/ByteUtilTest.java
Executable file
|
|
@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
10
test/zutil/test/ConverterTest.java
Normal file → Executable file
10
test/zutil/test/ConverterTest.java
Normal file → Executable file
|
|
@ -77,4 +77,14 @@ public class ConverterTest {
|
||||||
Converter.urlDecode("9i34%202y9252%25%2623%20463765(%2f%26(") );
|
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}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue