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 java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.nio.charset.StandardCharsets;
import java.util.*;
@ -49,7 +50,7 @@ public class BinaryFieldData {
private BinaryFieldData lengthField;
private int lengthMultiplier;
/* @CustomBinaryField */
private BinaryFieldSerializer serializer;
private Class<? extends BinaryFieldSerializer> serializerClass;
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;
this.length = -1;
this.lengthField = null;
this.lengthMultiplier = 1;
this.serializer = null;
this.serializerClass = null;
if (field.isAnnotationPresent(CustomBinaryField.class)) {
CustomBinaryField fieldData = field.getAnnotation(CustomBinaryField.class);
this.index = fieldData.index();
this.serializer = fieldData.serializer().newInstance();
this.serializerClass = fieldData.serializer();
}
else if (field.isAnnotationPresent(VariableLengthBinaryField.class)) {
VariableLengthBinaryField fieldData = field.getAnnotation(VariableLengthBinaryField.class);
@ -185,8 +187,21 @@ public class BinaryFieldData {
return length;
}
public boolean hasSerializer() {
return serializerClass != null;
}
public Class<? extends BinaryFieldSerializer> getSerializerClass() {
return serializerClass;
}
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: " + lengthField + ", LengthMultiplier: " + lengthMultiplier :
length + " bits") +
(serializer != null ?
", Serializer: " + serializer.getClass().getName() : "") +
(serializerClass != null ?
", 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.
* <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.
*
* Created by Ziver on 2016-04-11.

View file

@ -42,7 +42,7 @@ public interface BinaryStruct {
*/
@Retention(RetentionPolicy.RUNTIME)
@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. */
int index();
/** @return the bit length of the data */
@ -56,7 +56,7 @@ public interface BinaryStruct {
*/
@Retention(RetentionPolicy.RUNTIME)
@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. */
int index();
/** @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)
@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. */
int index();
/** @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.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* A stream class that parses a byte stream into
* binary struct objects.
* A stream class that parses a byte stream into binary struct objects.
* <p><p/>
* Limitations:<br>
* - Does not support sub binary objects.<br>
*
* @author Ziver
*/
@ -74,14 +78,20 @@ public class BinaryStructInputStream {
*/
public int read(BinaryStruct struct) throws IOException {
List<BinaryFieldData> structDataList = BinaryFieldData.getStructFieldList(struct.getClass());
Map<Class, BinaryFieldSerializer> serializerCache = new HashMap<>();
int totalReadLength = 0;
for (BinaryFieldData field : structDataList) {
if (field.getSerializer() != null) {
Object value = field.getSerializer().read(in, field);
if (field.hasSerializer()) {
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);
}
else {
} else {
byte[] valueData = new byte[(int) Math.ceil(field.getBitLength(struct) / 8.0)];
int fieldReadLength = 0; // How much we have read so far
int shiftBy = shiftLeftBy(dataBitIndex, field.getBitLength(struct));

View file

@ -29,12 +29,16 @@ import zutil.ByteUtil;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* A stream class that generates a byte stream from
* binary struct objects.
* A stream class that generates a byte stream from a binary struct objects.
* <p><p/>
* Limitations:<br>
* - Does not support sub binary objects.<br>
*
* @author Ziver
*/
@ -84,13 +88,19 @@ public class BinaryStructOutputStream {
*/
public void write(BinaryStruct struct) throws IOException {
List<BinaryFieldData> structDataList = BinaryFieldData.getStructFieldList(struct.getClass());
Map<Class, BinaryFieldSerializer> serializerCache = new HashMap<>();
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();
field.getSerializer().write(out, field.getValue(struct), field);
}
else {
serializer.write(out, field.getValue(struct), field);
} else {
int fieldBitLength = field.getBitLength(struct);
byte[] data = field.getByteValue(struct);
data = ByteUtil.shiftRight(data, ((8 - fieldBitLength % 8) % 8));
@ -100,7 +110,7 @@ public class BinaryStructOutputStream {
if (restBitLength == 0 && fieldBitLength >= 8)
out.write(0xFF & b);
else {
b = (byte)((b&0xFF) >> restBitLength);
b = (byte) ((b & 0xFF) >> restBitLength);
b &= ByteUtil.getBitMask(7 - restBitLength, fieldBitLength);
rest |= b;
restBitLength += fieldBitLength;