Implemented possibility to read parent object while writing custom binary field
This commit is contained in:
parent
3514a58c40
commit
fcbb2ef227
8 changed files with 372 additions and 29 deletions
|
|
@ -25,6 +25,7 @@
|
||||||
package zutil;
|
package zutil;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A utility class containing Array specific utility methods
|
* A utility class containing Array specific utility methods
|
||||||
|
|
@ -45,15 +46,87 @@ public class ArrayUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Searches for a given object inside of an array.
|
* Searches for a given object inside an array.
|
||||||
* The method uses reference comparison or {@link #equals(Object)} to check for equality.
|
* The method uses reference comparison or {@link #equals(Object)} to check for equality.
|
||||||
*
|
*
|
||||||
* @return True if the given Object is found inside the array, false otherwise.
|
* @return True if the given Object is found inside the array, false otherwise.
|
||||||
*/
|
*/
|
||||||
public static <T> boolean contains(T[] array, T obj) {
|
public static <T> boolean contains(T[] array, T obj) {
|
||||||
for (final T element : array)
|
for (final T element : array)
|
||||||
if (element == obj || obj != null && obj.equals(element))
|
if (Objects.equals(obj, element))
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Combines multiple arras into one.
|
||||||
|
*
|
||||||
|
* @param arrays the arrays to be combined.
|
||||||
|
* @return one array containing all the elements of the provided arrays.
|
||||||
|
* @param <T>
|
||||||
|
*/
|
||||||
|
public static <T> T[] combine(T[]... arrays) {
|
||||||
|
int totalLength = 0;
|
||||||
|
for (T[] array : arrays) {
|
||||||
|
totalLength += array.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
int outputPos = 0;
|
||||||
|
Object[] output = new Object[totalLength];
|
||||||
|
|
||||||
|
for (T[] array : arrays) {
|
||||||
|
System.arraycopy(array, 0, output, outputPos, array.length);
|
||||||
|
outputPos += array.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (T[]) output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Combines multiple arras into one.
|
||||||
|
*
|
||||||
|
* @param arrays the arrays to be combined.
|
||||||
|
* @return one array containing all the elements of the provided arrays.
|
||||||
|
* @param <T>
|
||||||
|
*/
|
||||||
|
public static int[] combine(int[]... arrays) {
|
||||||
|
int totalLength = 0;
|
||||||
|
for (int[] array : arrays) {
|
||||||
|
totalLength += array.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
int outputPos = 0;
|
||||||
|
int[] output = new int[totalLength];
|
||||||
|
|
||||||
|
for (int[] array : arrays) {
|
||||||
|
System.arraycopy(array, 0, output, outputPos, array.length);
|
||||||
|
outputPos += array.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Combines multiple arras into one.
|
||||||
|
*
|
||||||
|
* @param arrays the arrays to be combined.
|
||||||
|
* @return one array containing all the elements of the provided arrays.
|
||||||
|
* @param <T>
|
||||||
|
*/
|
||||||
|
public static byte[] combine(byte[]... arrays) {
|
||||||
|
int totalLength = 0;
|
||||||
|
for (byte[] array : arrays) {
|
||||||
|
totalLength += array.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
int outputPos = 0;
|
||||||
|
byte[] output = new byte[totalLength];
|
||||||
|
|
||||||
|
for (byte[] array : arrays) {
|
||||||
|
System.arraycopy(array, 0, output, outputPos, array.length);
|
||||||
|
outputPos += array.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,8 +32,8 @@ import zutil.parser.binary.BinaryStruct.BinaryField;
|
||||||
import zutil.parser.binary.BinaryStruct.CustomBinaryField;
|
import zutil.parser.binary.BinaryStruct.CustomBinaryField;
|
||||||
import zutil.parser.binary.BinaryStruct.VariableLengthBinaryField;
|
import zutil.parser.binary.BinaryStruct.VariableLengthBinaryField;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
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.*;
|
||||||
|
|
||||||
|
|
@ -53,7 +53,7 @@ public class BinaryFieldData {
|
||||||
private Class<? extends BinaryFieldSerializer> serializerClass;
|
private Class<? extends BinaryFieldSerializer> serializerClass;
|
||||||
|
|
||||||
|
|
||||||
protected static List<BinaryFieldData> getStructFieldList(Class<? extends BinaryStruct> clazz) {
|
public static List<BinaryFieldData> getStructFieldList(Class<? extends BinaryStruct> clazz) {
|
||||||
if (!cache.containsKey(clazz)) {
|
if (!cache.containsKey(clazz)) {
|
||||||
try {
|
try {
|
||||||
ArrayList<BinaryFieldData> list = new ArrayList<>();
|
ArrayList<BinaryFieldData> list = new ArrayList<>();
|
||||||
|
|
@ -198,7 +198,9 @@ public class BinaryFieldData {
|
||||||
|
|
||||||
public BinaryFieldSerializer getSerializer() {
|
public BinaryFieldSerializer getSerializer() {
|
||||||
try {
|
try {
|
||||||
return serializerClass.getDeclaredConstructor().newInstance();
|
Constructor<? extends BinaryFieldSerializer> constructor = serializerClass.getDeclaredConstructor();
|
||||||
|
constructor.setAccessible(true);
|
||||||
|
return constructor.newInstance();
|
||||||
} catch (ReflectiveOperationException e) {
|
} catch (ReflectiveOperationException e) {
|
||||||
throw new RuntimeException("Unable to instantiate class: " + serializerClass, e);
|
throw new RuntimeException("Unable to instantiate class: " + serializerClass, e);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,17 +31,59 @@ import java.io.OutputStream;
|
||||||
/**
|
/**
|
||||||
* An Interface defining a custom field parser and writer.
|
* An Interface defining a custom field parser and writer.
|
||||||
* <p>
|
* <p>
|
||||||
* One singleton instance of the serializer will be instantiated for the lifetime of the
|
* A new instance of the serializer will be instantiated for every time serialization is required.
|
||||||
* {@link BinaryStructInputStream} and {@link BinaryStructOutputStream} objects.
|
* {@link BinaryStructInputStream} and {@link BinaryStructOutputStream} objects.
|
||||||
* <p>
|
* <p>
|
||||||
* NOTE: Partial octet serializing not supported.
|
* NOTE: Partial octet serializing not supported.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public interface BinaryFieldSerializer<T> {
|
public interface BinaryFieldSerializer<T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read the given field from the stream.
|
||||||
|
*
|
||||||
|
* @param in the stream where the data should be read from.
|
||||||
|
* @param field meta-data about the target field that will be assigned.
|
||||||
|
* @param parentObject the parent object that owns the field.
|
||||||
|
* @return the value that should be assigned to the field.
|
||||||
|
*/
|
||||||
|
default T read(InputStream in,
|
||||||
|
BinaryFieldData field,
|
||||||
|
Object parentObject) throws IOException {
|
||||||
|
return read(in, field);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read the given field from the stream.
|
||||||
|
*
|
||||||
|
* @param in the stream where the data should be read from.
|
||||||
|
* @param field meta-data about the target field that will be assigned.
|
||||||
|
* @return the value that should be assigned to the field.
|
||||||
|
*/
|
||||||
T read(InputStream in,
|
T read(InputStream in,
|
||||||
BinaryFieldData field) throws IOException;
|
BinaryFieldData field) throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write the given field to the output stream.
|
||||||
|
*
|
||||||
|
* @param out the stream where the field data should be written to.
|
||||||
|
* @param obj the object that should be serialized and written to the stream.
|
||||||
|
* @param field meta-data about the source field that will be serialized.
|
||||||
|
* @param parentObject the parent object that owns the field.
|
||||||
|
*/
|
||||||
|
default void write(OutputStream out,
|
||||||
|
T obj,
|
||||||
|
BinaryFieldData field,
|
||||||
|
Object parentObject) throws IOException {
|
||||||
|
write(out, obj, field);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write the given field to the output stream.
|
||||||
|
*
|
||||||
|
* @param out the stream where the field data should be written to.
|
||||||
|
* @param obj the object that should be serialized and written to the stream.
|
||||||
|
* @param field meta-data about the source field that will be serialized.
|
||||||
|
*/
|
||||||
void write(OutputStream out,
|
void write(OutputStream out,
|
||||||
T obj,
|
T obj,
|
||||||
BinaryFieldData field) throws IOException;
|
BinaryFieldData field) throws IOException;
|
||||||
|
|
|
||||||
|
|
@ -41,14 +41,12 @@ import java.util.Map;
|
||||||
*
|
*
|
||||||
* @author Ziver
|
* @author Ziver
|
||||||
*/
|
*/
|
||||||
public class BinaryStructInputStream {
|
public class BinaryStructInputStream extends InputStream{
|
||||||
|
|
||||||
private InputStream in;
|
private InputStream in;
|
||||||
private byte data;
|
private byte data;
|
||||||
private int dataBitIndex = -1;
|
private int dataBitIndex = -1;
|
||||||
|
|
||||||
private Map<Class, BinaryFieldSerializer> serializerCache = new HashMap<>();
|
|
||||||
|
|
||||||
|
|
||||||
public BinaryStructInputStream(InputStream in) {
|
public BinaryStructInputStream(InputStream in) {
|
||||||
this.in = in;
|
this.in = in;
|
||||||
|
|
@ -85,13 +83,9 @@ public class BinaryStructInputStream {
|
||||||
int totalReadLength = 0;
|
int totalReadLength = 0;
|
||||||
for (BinaryFieldData field : structDataList) {
|
for (BinaryFieldData field : structDataList) {
|
||||||
if (field.hasSerializer()) {
|
if (field.hasSerializer()) {
|
||||||
BinaryFieldSerializer serializer = serializerCache.get(field.getSerializerClass());
|
BinaryFieldSerializer<Object> serializer = field.getSerializer();
|
||||||
if (serializer == null) {
|
|
||||||
serializer = field.getSerializer();
|
|
||||||
serializerCache.put(serializer.getClass(), serializer);
|
|
||||||
}
|
|
||||||
|
|
||||||
Object value = serializer.read(in, field);
|
Object value = serializer.read(in, field, struct);
|
||||||
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)];
|
||||||
|
|
@ -119,21 +113,35 @@ public class BinaryStructInputStream {
|
||||||
return totalReadLength;
|
return totalReadLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read() throws IOException {
|
||||||
|
return in.read();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read(byte[] b, int off, int len) throws IOException {
|
||||||
|
return in.read(b, off, len);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see InputStream#markSupported()
|
* @see InputStream#markSupported()
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public boolean markSupported() {
|
public boolean markSupported() {
|
||||||
return in.markSupported();
|
return in.markSupported();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see InputStream#mark(int)
|
* @see InputStream#mark(int)
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void mark(int limit) {
|
public void mark(int limit) {
|
||||||
in.mark(limit);
|
in.mark(limit);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @see InputStream#reset()
|
* @see InputStream#reset()
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void reset() throws IOException {
|
public void reset() throws IOException {
|
||||||
in.reset();
|
in.reset();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,9 +29,7 @@ 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;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -42,14 +40,12 @@ import java.util.Map;
|
||||||
*
|
*
|
||||||
* @author Ziver
|
* @author Ziver
|
||||||
*/
|
*/
|
||||||
public class BinaryStructOutputStream {
|
public class BinaryStructOutputStream extends OutputStream {
|
||||||
|
|
||||||
private OutputStream out;
|
private OutputStream out;
|
||||||
private byte rest;
|
private byte rest;
|
||||||
private int restBitLength; // length from Most Significant Bit
|
private int restBitLength; // length from Most Significant Bit
|
||||||
|
|
||||||
private Map<Class, BinaryFieldSerializer> serializerCache = new HashMap<>();
|
|
||||||
|
|
||||||
|
|
||||||
public BinaryStructOutputStream(OutputStream out) {
|
public BinaryStructOutputStream(OutputStream out) {
|
||||||
this.out = out;
|
this.out = out;
|
||||||
|
|
@ -71,16 +67,23 @@ public class BinaryStructOutputStream {
|
||||||
return buffer.toByteArray();
|
return buffer.toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see OutputStream#write(int b)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void write(int b) throws IOException {
|
||||||
|
out.write(b);
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* @see OutputStream#write(byte[])
|
* @see OutputStream#write(byte[])
|
||||||
*/
|
*/
|
||||||
public void write(byte b[]) throws IOException {
|
public void write(byte[] b) throws IOException {
|
||||||
out.write(b);
|
out.write(b);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @see OutputStream#write(byte[], int, int)
|
* @see OutputStream#write(byte[], int, int)
|
||||||
*/
|
*/
|
||||||
public void write(byte b[], int off, int len) throws IOException {
|
public void write(byte[] b, int off, int len) throws IOException {
|
||||||
out.write(b, off, len);
|
out.write(b, off, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -93,14 +96,10 @@ public class BinaryStructOutputStream {
|
||||||
|
|
||||||
for (BinaryFieldData field : structDataList) {
|
for (BinaryFieldData field : structDataList) {
|
||||||
if (field.hasSerializer()) {
|
if (field.hasSerializer()) {
|
||||||
BinaryFieldSerializer serializer = serializerCache.get(field.getSerializerClass());
|
BinaryFieldSerializer<Object> serializer = field.getSerializer();
|
||||||
if (serializer == null) {
|
|
||||||
serializer = field.getSerializer();
|
|
||||||
serializerCache.put(serializer.getClass(), serializer);
|
|
||||||
}
|
|
||||||
|
|
||||||
localFlush();
|
localFlush();
|
||||||
serializer.write(out, field.getValue(struct), field);
|
serializer.write(out, field.getValue(struct), field, struct);
|
||||||
} else {
|
} else {
|
||||||
int fieldBitLength = field.getBitLength(struct);
|
int fieldBitLength = field.getBitLength(struct);
|
||||||
byte[] data = field.getByteValue(struct);
|
byte[] data = field.getByteValue(struct);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,84 @@
|
||||||
|
/*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Ziver Koc
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package zutil.parser.binary.serializer;
|
||||||
|
|
||||||
|
import zutil.parser.binary.BinaryFieldData;
|
||||||
|
import zutil.parser.binary.BinaryFieldSerializer;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.StreamCorruptedException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serializer handles data that is prefixed by two byte length.
|
||||||
|
* <p>
|
||||||
|
* Currently only these types are supported:
|
||||||
|
* <ul>
|
||||||
|
* <li>byte[]</li>
|
||||||
|
* <li>String</li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
public class TwoByteLengthPrefixedDataSerializer implements BinaryFieldSerializer<Object> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object read(InputStream in, BinaryFieldData field) throws IOException {
|
||||||
|
int b = in.read();
|
||||||
|
if (b < 0)
|
||||||
|
throw new StreamCorruptedException("Stream ended prematurely when reading first length byte.");
|
||||||
|
int length = (b & 0xFF) << 8;
|
||||||
|
|
||||||
|
b = in.read();
|
||||||
|
if (b < 0)
|
||||||
|
throw new StreamCorruptedException("Stream ended prematurely when reading second length byte.");
|
||||||
|
length |= b & 0xFF;
|
||||||
|
|
||||||
|
byte[] payload = new byte[length];
|
||||||
|
in.read(payload);
|
||||||
|
|
||||||
|
if (field.getType().isAssignableFrom(String.class))
|
||||||
|
return new String(payload, StandardCharsets.UTF_8);
|
||||||
|
return payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(OutputStream out, Object obj, BinaryFieldData field) throws IOException {
|
||||||
|
if (obj == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
byte[] payload;
|
||||||
|
if (obj instanceof String)
|
||||||
|
payload = ((String) obj).getBytes(StandardCharsets.UTF_8);
|
||||||
|
else
|
||||||
|
payload = (byte[]) obj;
|
||||||
|
|
||||||
|
int length = payload.length;
|
||||||
|
|
||||||
|
out.write((length & 0xFF00) >> 8);
|
||||||
|
out.write(length & 0xFF);
|
||||||
|
out.write(payload);
|
||||||
|
}
|
||||||
|
}
|
||||||
39
test/zutil/ArrayUtilTest.java
Normal file
39
test/zutil/ArrayUtilTest.java
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
package zutil;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
public class ArrayUtilTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void toIntArray() {
|
||||||
|
assertArrayEquals(new int[]{}, ArrayUtil.toIntArray(Collections.emptyList()));
|
||||||
|
assertArrayEquals(new int[]{1, 2, 3}, ArrayUtil.toIntArray(Arrays.asList(1, 2, 3)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void contains() {
|
||||||
|
assertFalse(ArrayUtil.contains(new Integer[]{}, 1));
|
||||||
|
assertTrue(ArrayUtil.contains(new Integer[]{1}, 1));
|
||||||
|
assertTrue(ArrayUtil.contains(new Integer[]{2, 1, 3}, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void combine() {
|
||||||
|
assertArrayEquals(new Integer[]{}, ArrayUtil.combine(new Integer[]{}, new Integer[]{}));
|
||||||
|
assertArrayEquals(new Integer[]{1, 2}, ArrayUtil.combine(new Integer[]{1, 2}, new Integer[]{}));
|
||||||
|
assertArrayEquals(new Integer[]{1, 2, 3, 4}, ArrayUtil.combine(new Integer[]{1, 2}, new Integer[]{3, 4}));
|
||||||
|
|
||||||
|
assertArrayEquals(new int[]{}, ArrayUtil.combine(new int[]{}, new int[]{}));
|
||||||
|
assertArrayEquals(new int[]{1, 2}, ArrayUtil.combine(new int[]{1, 2}, new int[]{}));
|
||||||
|
assertArrayEquals(new int[]{1, 2, 3, 4}, ArrayUtil.combine(new int[]{1, 2}, new int[]{3, 4}));
|
||||||
|
|
||||||
|
assertArrayEquals(new byte[]{}, ArrayUtil.combine(new byte[]{}, new byte[]{}));
|
||||||
|
assertArrayEquals(new byte[]{1, 2}, ArrayUtil.combine(new byte[]{1, 2}, new byte[]{}));
|
||||||
|
assertArrayEquals(new byte[]{1, 2, 3, 4}, ArrayUtil.combine(new byte[]{1, 2}, new byte[]{3, 4}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,96 @@
|
||||||
|
package zutil.parser.binary.serializer;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import zutil.ArrayUtil;
|
||||||
|
import zutil.ByteUtil;
|
||||||
|
import zutil.parser.binary.BinaryFieldData;
|
||||||
|
import zutil.parser.binary.BinaryStruct;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.StreamCorruptedException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
public class TwoByteLengthPrefixedDataSerializerTest implements BinaryStruct {
|
||||||
|
|
||||||
|
@BinaryField(index = 10, length = 1)
|
||||||
|
private String tmpStringField;
|
||||||
|
@BinaryField(index = 20, length = 1)
|
||||||
|
private byte[] tmpByteField;
|
||||||
|
|
||||||
|
@Test(expected = StreamCorruptedException.class)
|
||||||
|
public void readPrematureEnd0() throws IOException {
|
||||||
|
TwoByteLengthPrefixedDataSerializer serializer = new TwoByteLengthPrefixedDataSerializer();
|
||||||
|
|
||||||
|
// 0 length stream
|
||||||
|
ByteArrayInputStream inputStream = new ByteArrayInputStream(new byte[0]);
|
||||||
|
serializer.read(inputStream, null, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = StreamCorruptedException.class)
|
||||||
|
public void readPrematureEnd1() throws IOException {
|
||||||
|
TwoByteLengthPrefixedDataSerializer serializer = new TwoByteLengthPrefixedDataSerializer();
|
||||||
|
|
||||||
|
// 1 length stream
|
||||||
|
ByteArrayInputStream inputStream = new ByteArrayInputStream(new byte[]{0x00});
|
||||||
|
serializer.read(inputStream, null, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void read() throws IOException, NoSuchFieldException {
|
||||||
|
TwoByteLengthPrefixedDataSerializer serializer = new TwoByteLengthPrefixedDataSerializer();
|
||||||
|
List<BinaryFieldData> fieldDataList = BinaryFieldData.getStructFieldList(this.getClass());
|
||||||
|
BinaryFieldData stringFieldData = fieldDataList.get(0);
|
||||||
|
BinaryFieldData byteFieldData = fieldDataList.get(1);
|
||||||
|
|
||||||
|
// 0 Length
|
||||||
|
ByteArrayInputStream inputStream = new ByteArrayInputStream(new byte[]{0x00, 0x00});
|
||||||
|
assertEquals("", serializer.read(inputStream, stringFieldData, this));
|
||||||
|
inputStream.reset();
|
||||||
|
assertArrayEquals(new byte[0], (byte[])serializer.read(inputStream, byteFieldData, this));
|
||||||
|
|
||||||
|
// String "1234"
|
||||||
|
inputStream = new ByteArrayInputStream(ArrayUtil.combine(new byte[]{0x00, 0x04}, "1234".getBytes(StandardCharsets.UTF_8)));
|
||||||
|
assertEquals("1234", serializer.read(inputStream, stringFieldData, this));
|
||||||
|
inputStream.reset();
|
||||||
|
assertArrayEquals("1234".getBytes(StandardCharsets.UTF_8), (byte[])serializer.read(inputStream, byteFieldData, this));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void write() throws IOException {
|
||||||
|
TwoByteLengthPrefixedDataSerializer serializer = new TwoByteLengthPrefixedDataSerializer();
|
||||||
|
List<BinaryFieldData> fieldDataList = BinaryFieldData.getStructFieldList(this.getClass());
|
||||||
|
BinaryFieldData stringFieldData = fieldDataList.get(0);
|
||||||
|
BinaryFieldData byteFieldData = fieldDataList.get(1);
|
||||||
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
// 0 Length
|
||||||
|
outputStream.reset();outputStream.reset();
|
||||||
|
serializer.write(outputStream, null, stringFieldData, this);
|
||||||
|
assertArrayEquals(new byte[]{}, outputStream.toByteArray());
|
||||||
|
outputStream.reset();
|
||||||
|
serializer.write(outputStream, null, byteFieldData, this);
|
||||||
|
assertArrayEquals(new byte[]{}, outputStream.toByteArray());
|
||||||
|
|
||||||
|
// 0 Length
|
||||||
|
outputStream.reset();
|
||||||
|
serializer.write(outputStream, "", stringFieldData, this);
|
||||||
|
assertArrayEquals(new byte[]{0, 0}, outputStream.toByteArray());
|
||||||
|
outputStream.reset();
|
||||||
|
serializer.write(outputStream, new byte[0], byteFieldData, this);
|
||||||
|
assertArrayEquals(new byte[]{0, 0}, outputStream.toByteArray());
|
||||||
|
|
||||||
|
// String "1234"
|
||||||
|
outputStream.reset();
|
||||||
|
serializer.write(outputStream, "1234", stringFieldData, this);
|
||||||
|
assertArrayEquals(new byte[]{0, 4, 49, 50, 51, 52}, outputStream.toByteArray());
|
||||||
|
outputStream.reset();
|
||||||
|
serializer.write(outputStream, "1234".getBytes(StandardCharsets.UTF_8), byteFieldData, this);
|
||||||
|
assertArrayEquals(new byte[]{0, 4, 49, 50, 51, 52}, outputStream.toByteArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue