86 lines
2.9 KiB
Java
Executable file
86 lines
2.9 KiB
Java
Executable file
package zutil.parser.binary;
|
|
|
|
import java.lang.reflect.Field;
|
|
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 Ziver on 2016-01-28.
|
|
*/
|
|
public class BinaryStructParser {
|
|
|
|
public static int parse(BinaryStruct struct, byte[] data) {
|
|
List<BinaryFieldData> structDataList = getStructDataList(struct.getClass());
|
|
int bitOffset = 0;
|
|
for (BinaryFieldData field : structDataList){
|
|
bitOffset += field.setValue(struct, data, bitOffset);
|
|
}
|
|
return bitOffset;
|
|
}
|
|
|
|
|
|
private static List<BinaryFieldData> getStructDataList(Class<? extends BinaryStruct> clazz){
|
|
ArrayList<BinaryFieldData> list = new ArrayList<>();
|
|
for (Field field : clazz.getFields()){
|
|
if (field.isAnnotationPresent(BinaryField.class))
|
|
list.add(new BinaryFieldData(field));
|
|
}
|
|
Collections.sort(list);
|
|
return list;
|
|
}
|
|
|
|
|
|
|
|
public static class BinaryFieldData implements Comparable<BinaryFieldData> {
|
|
private int index;
|
|
private int length;
|
|
private Field field;
|
|
|
|
protected BinaryFieldData(Field f){
|
|
field = f;
|
|
BinaryField fieldData = field.getAnnotation(BinaryField.class);
|
|
index = 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) {
|
|
return this.index - o.index;
|
|
}
|
|
}
|
|
}
|