Changed BinaryFieldSerializer instance to be between read sessions
This commit is contained in:
parent
decf114f49
commit
e42d25fa99
5 changed files with 63 additions and 23 deletions
|
|
@ -33,6 +33,7 @@ import zutil.parser.binary.BinaryStruct.CustomBinaryField;
|
||||||
import zutil.parser.binary.BinaryStruct.VariableLengthBinaryField;
|
import zutil.parser.binary.BinaryStruct.VariableLengthBinaryField;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
|
@ -49,7 +50,7 @@ public class BinaryFieldData {
|
||||||
private BinaryFieldData lengthField;
|
private BinaryFieldData lengthField;
|
||||||
private int lengthMultiplier;
|
private int lengthMultiplier;
|
||||||
/* @CustomBinaryField */
|
/* @CustomBinaryField */
|
||||||
private BinaryFieldSerializer serializer;
|
private Class<? extends BinaryFieldSerializer> serializerClass;
|
||||||
|
|
||||||
|
|
||||||
protected static List<BinaryFieldData> getStructFieldList(Class<? extends BinaryStruct> clazz) {
|
protected static List<BinaryFieldData> getStructFieldList(Class<? extends BinaryStruct> clazz) {
|
||||||
|
|
@ -80,16 +81,17 @@ public class BinaryFieldData {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private BinaryFieldData(Field f) throws IllegalAccessException, InstantiationException, NoSuchFieldException {
|
private BinaryFieldData(Field f) throws NoSuchFieldException {
|
||||||
field = f;
|
field = f;
|
||||||
this.length = -1;
|
this.length = -1;
|
||||||
this.lengthField = null;
|
this.lengthField = null;
|
||||||
this.lengthMultiplier = 1;
|
this.lengthMultiplier = 1;
|
||||||
this.serializer = null;
|
this.serializerClass = null;
|
||||||
|
|
||||||
if (field.isAnnotationPresent(CustomBinaryField.class)) {
|
if (field.isAnnotationPresent(CustomBinaryField.class)) {
|
||||||
CustomBinaryField fieldData = field.getAnnotation(CustomBinaryField.class);
|
CustomBinaryField fieldData = field.getAnnotation(CustomBinaryField.class);
|
||||||
this.index = fieldData.index();
|
this.index = fieldData.index();
|
||||||
this.serializer = fieldData.serializer().newInstance();
|
this.serializerClass = fieldData.serializer();
|
||||||
}
|
}
|
||||||
else if (field.isAnnotationPresent(VariableLengthBinaryField.class)) {
|
else if (field.isAnnotationPresent(VariableLengthBinaryField.class)) {
|
||||||
VariableLengthBinaryField fieldData = field.getAnnotation(VariableLengthBinaryField.class);
|
VariableLengthBinaryField fieldData = field.getAnnotation(VariableLengthBinaryField.class);
|
||||||
|
|
@ -185,8 +187,21 @@ public class BinaryFieldData {
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public boolean hasSerializer() {
|
||||||
|
return serializerClass != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class<? extends BinaryFieldSerializer> getSerializerClass() {
|
||||||
|
return serializerClass;
|
||||||
|
}
|
||||||
|
|
||||||
public BinaryFieldSerializer getSerializer() {
|
public BinaryFieldSerializer getSerializer() {
|
||||||
return serializer;
|
try {
|
||||||
|
return serializerClass.getDeclaredConstructor().newInstance();
|
||||||
|
} catch (ReflectiveOperationException e) {
|
||||||
|
throw new RuntimeException("Unable to instantiate class: " + serializerClass, e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -197,8 +212,8 @@ public class BinaryFieldData {
|
||||||
(lengthField != null ?
|
(lengthField != null ?
|
||||||
"LengthField: " + lengthField + ", LengthMultiplier: " + lengthMultiplier :
|
"LengthField: " + lengthField + ", LengthMultiplier: " + lengthMultiplier :
|
||||||
length + " bits") +
|
length + " bits") +
|
||||||
(serializer != null ?
|
(serializerClass != null ?
|
||||||
", Serializer: " + serializer.getClass().getName() : "") +
|
", Serializer: " + serializerClass.getClass().getName() : "") +
|
||||||
")";
|
")";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,11 @@ import java.io.OutputStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An Interface where custom field parser and writer can be implemented.
|
* An Interface where custom field parser and writer can be implemented.
|
||||||
|
* <p></p>
|
||||||
|
* One instance of the serializer and will have the scope of the methods
|
||||||
|
* {@link BinaryStructInputStream#read(BinaryStruct)} and {@link BinaryStructOutputStream#write(BinaryStruct)}
|
||||||
|
* where as it will be deallocated after the methods have returned.
|
||||||
|
* <p></p>
|
||||||
* NOTE: Partial octet serializing not supported.
|
* NOTE: Partial octet serializing not supported.
|
||||||
*
|
*
|
||||||
* Created by Ziver on 2016-04-11.
|
* Created by Ziver on 2016-04-11.
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ public interface BinaryStruct {
|
||||||
*/
|
*/
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target(ElementType.FIELD)
|
@Target(ElementType.FIELD)
|
||||||
@interface BinaryField{
|
@interface BinaryField {
|
||||||
/** @return a number indicating the order the fields are read. Lowest index number field will be read first. */
|
/** @return a number indicating the order the fields are read. Lowest index number field will be read first. */
|
||||||
int index();
|
int index();
|
||||||
/** @return the bit length of the data */
|
/** @return the bit length of the data */
|
||||||
|
|
@ -56,7 +56,7 @@ public interface BinaryStruct {
|
||||||
*/
|
*/
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target(ElementType.FIELD)
|
@Target(ElementType.FIELD)
|
||||||
@interface VariableLengthBinaryField{
|
@interface VariableLengthBinaryField {
|
||||||
/** @return a number indicating the order the fields are read. Lowest index number field will be read first. */
|
/** @return a number indicating the order the fields are read. Lowest index number field will be read first. */
|
||||||
int index();
|
int index();
|
||||||
/** @return a String name of the field that contains the length of the data to be read. */
|
/** @return a String name of the field that contains the length of the data to be read. */
|
||||||
|
|
@ -71,7 +71,7 @@ public interface BinaryStruct {
|
||||||
*/
|
*/
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target(ElementType.FIELD)
|
@Target(ElementType.FIELD)
|
||||||
@interface CustomBinaryField{
|
@interface CustomBinaryField {
|
||||||
/** @return a number indicating the order the fields are read. Lowest index number field will be read first. */
|
/** @return a number indicating the order the fields are read. Lowest index number field will be read first. */
|
||||||
int index();
|
int index();
|
||||||
/** @return the serializer class name that will be used. Class needs to be publicly visible. */
|
/** @return the serializer class name that will be used. Class needs to be publicly visible. */
|
||||||
|
|
|
||||||
|
|
@ -29,11 +29,15 @@ import zutil.ByteUtil;
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A stream class that parses a byte stream into
|
* A stream class that parses a byte stream into binary struct objects.
|
||||||
* binary struct objects.
|
* <p><p/>
|
||||||
|
* Limitations:<br>
|
||||||
|
* - Does not support sub binary objects.<br>
|
||||||
*
|
*
|
||||||
* @author Ziver
|
* @author Ziver
|
||||||
*/
|
*/
|
||||||
|
|
@ -74,14 +78,20 @@ public class BinaryStructInputStream {
|
||||||
*/
|
*/
|
||||||
public int read(BinaryStruct struct) throws IOException {
|
public int read(BinaryStruct struct) throws IOException {
|
||||||
List<BinaryFieldData> structDataList = BinaryFieldData.getStructFieldList(struct.getClass());
|
List<BinaryFieldData> structDataList = BinaryFieldData.getStructFieldList(struct.getClass());
|
||||||
|
Map<Class, BinaryFieldSerializer> serializerCache = new HashMap<>();
|
||||||
|
|
||||||
int totalReadLength = 0;
|
int totalReadLength = 0;
|
||||||
for (BinaryFieldData field : structDataList) {
|
for (BinaryFieldData field : structDataList) {
|
||||||
if (field.getSerializer() != null) {
|
if (field.hasSerializer()) {
|
||||||
Object value = field.getSerializer().read(in, field);
|
BinaryFieldSerializer serializer = serializerCache.get(field.getSerializerClass());
|
||||||
|
if (serializer == null) {
|
||||||
|
serializer = field.getSerializer();
|
||||||
|
serializerCache.put(serializer.getClass(), serializer);
|
||||||
|
}
|
||||||
|
|
||||||
|
Object value = serializer.read(in, field);
|
||||||
field.setValue(struct, value);
|
field.setValue(struct, value);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
byte[] valueData = new byte[(int) Math.ceil(field.getBitLength(struct) / 8.0)];
|
byte[] valueData = new byte[(int) Math.ceil(field.getBitLength(struct) / 8.0)];
|
||||||
int fieldReadLength = 0; // How much we have read so far
|
int fieldReadLength = 0; // How much we have read so far
|
||||||
int shiftBy = shiftLeftBy(dataBitIndex, field.getBitLength(struct));
|
int shiftBy = shiftLeftBy(dataBitIndex, field.getBitLength(struct));
|
||||||
|
|
|
||||||
|
|
@ -29,12 +29,16 @@ import zutil.ByteUtil;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A stream class that generates a byte stream from
|
* A stream class that generates a byte stream from a binary struct objects.
|
||||||
* binary struct objects.
|
* <p><p/>
|
||||||
|
* Limitations:<br>
|
||||||
|
* - Does not support sub binary objects.<br>
|
||||||
*
|
*
|
||||||
* @author Ziver
|
* @author Ziver
|
||||||
*/
|
*/
|
||||||
|
|
@ -84,13 +88,19 @@ public class BinaryStructOutputStream {
|
||||||
*/
|
*/
|
||||||
public void write(BinaryStruct struct) throws IOException {
|
public void write(BinaryStruct struct) throws IOException {
|
||||||
List<BinaryFieldData> structDataList = BinaryFieldData.getStructFieldList(struct.getClass());
|
List<BinaryFieldData> structDataList = BinaryFieldData.getStructFieldList(struct.getClass());
|
||||||
|
Map<Class, BinaryFieldSerializer> serializerCache = new HashMap<>();
|
||||||
|
|
||||||
for (BinaryFieldData field : structDataList) {
|
for (BinaryFieldData field : structDataList) {
|
||||||
if (field.getSerializer() != null) {
|
if (field.hasSerializer()) {
|
||||||
|
BinaryFieldSerializer serializer = serializerCache.get(field.getSerializerClass());
|
||||||
|
if (serializer == null) {
|
||||||
|
serializer = field.getSerializer();
|
||||||
|
serializerCache.put(serializer.getClass(), serializer);
|
||||||
|
}
|
||||||
|
|
||||||
localFlush();
|
localFlush();
|
||||||
field.getSerializer().write(out, field.getValue(struct), field);
|
serializer.write(out, field.getValue(struct), field);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
int fieldBitLength = field.getBitLength(struct);
|
int fieldBitLength = field.getBitLength(struct);
|
||||||
byte[] data = field.getByteValue(struct);
|
byte[] data = field.getByteValue(struct);
|
||||||
data = ByteUtil.shiftRight(data, ((8 - fieldBitLength % 8) % 8));
|
data = ByteUtil.shiftRight(data, ((8 - fieldBitLength % 8) % 8));
|
||||||
|
|
@ -100,7 +110,7 @@ public class BinaryStructOutputStream {
|
||||||
if (restBitLength == 0 && fieldBitLength >= 8)
|
if (restBitLength == 0 && fieldBitLength >= 8)
|
||||||
out.write(0xFF & b);
|
out.write(0xFF & b);
|
||||||
else {
|
else {
|
||||||
b = (byte)((b&0xFF) >> restBitLength);
|
b = (byte) ((b & 0xFF) >> restBitLength);
|
||||||
b &= ByteUtil.getBitMask(7 - restBitLength, fieldBitLength);
|
b &= ByteUtil.getBitMask(7 - restBitLength, fieldBitLength);
|
||||||
rest |= b;
|
rest |= b;
|
||||||
restBitLength += fieldBitLength;
|
restBitLength += fieldBitLength;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue