Changed BinaryFieldSerializer instance to be between read sessions

This commit is contained in:
Ziver Koc 2021-08-25 22:43:03 +02:00
parent decf114f49
commit e42d25fa99
5 changed files with 63 additions and 23 deletions

View file

@ -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() : "") +
")"; ")";
} }

View file

@ -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.

View file

@ -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. */

View file

@ -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));

View file

@ -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;