Fixed BinaryOutputStream bug
This commit is contained in:
parent
50ea517cf3
commit
c894ba8a61
7 changed files with 164 additions and 57 deletions
|
|
@ -44,16 +44,6 @@ public class ByteUtil {
|
||||||
{0b1000_0000, 0b1100_0000, 0b1110_0000, 0b1111_0000, 0b1111_1000, 0b1111_1100, 0b1111_1110, 0b1111_1111}
|
{0b1000_0000, 0b1100_0000, 0b1110_0000, 0b1111_0000, 0b1111_1000, 0b1111_1100, 0b1111_1110, 0b1111_1111}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new sub byte from MSB to the given length
|
|
||||||
*
|
|
||||||
* @param data is the byte data
|
|
||||||
* @param length is the length of bits to return, valid values 1-8
|
|
||||||
* @return a new byte containing a sub byte defined by the index and length
|
|
||||||
*/
|
|
||||||
public static byte getBits(byte data, int length){
|
|
||||||
return getBits(data, length-1, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new sub byte from index and with the given length length
|
* Creates a new sub byte from index and with the given length length
|
||||||
|
|
@ -82,6 +72,17 @@ public class ByteUtil {
|
||||||
return (byte) ret;
|
return (byte) ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new sub byte from LSB to the given length
|
||||||
|
*
|
||||||
|
* @param data is the byte data
|
||||||
|
* @param length is the length of bits to return, valid values 1-8
|
||||||
|
* @return a new byte containing a sub byte defined by the index and length
|
||||||
|
*/
|
||||||
|
public static byte getBits(byte data, int length){
|
||||||
|
return getBits(data, length-1, length);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new sub byte array with only the given length of bits from the LSB.
|
* Creates a new sub byte array with only the given length of bits from the LSB.
|
||||||
*
|
*
|
||||||
|
|
@ -97,6 +98,17 @@ public class ByteUtil {
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new sub byte from MSB to the given length
|
||||||
|
*
|
||||||
|
* @param data is the byte data
|
||||||
|
* @param length is the length of bits to return, valid values 1-8
|
||||||
|
* @return a new byte containing a sub byte defined by the index and length
|
||||||
|
*/
|
||||||
|
public static byte getBitsMSB(byte data, int length){
|
||||||
|
return getShiftedBits(data, 7, length);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new byte array with reversed byte ordering
|
* Creates a new byte array with reversed byte ordering
|
||||||
* (LittleEndian -> BigEndian, BigEndian -> LittleEndian)
|
* (LittleEndian -> BigEndian, BigEndian -> LittleEndian)
|
||||||
|
|
@ -144,7 +156,7 @@ public class ByteUtil {
|
||||||
byte rest = 0;
|
byte rest = 0;
|
||||||
for (int i=0; i<data.length; ++i){
|
for (int i=0; i<data.length; ++i){
|
||||||
rest = (byte)(getBits(data[i], shiftBy-1, shiftBy) << 8 - shiftBy);
|
rest = (byte)(getBits(data[i], shiftBy-1, shiftBy) << 8 - shiftBy);
|
||||||
data[i] = (byte)((int)(data[i]&0xFF) >> shiftBy);
|
data[i] = (byte)((data[i]&0xFF) >>> shiftBy);
|
||||||
if(i != 0)
|
if(i != 0)
|
||||||
data[i-1] |= rest;
|
data[i-1] |= rest;
|
||||||
}
|
}
|
||||||
|
|
@ -152,6 +164,31 @@ public class ByteUtil {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shifts a whole byte array to the right by the specified amount.
|
||||||
|
*
|
||||||
|
* @param data the array to be shifted
|
||||||
|
* @param shiftBy the amount to shift. Currently only supports maximum value of 8
|
||||||
|
* @return same data reference as the data input
|
||||||
|
*/
|
||||||
|
public static byte[] shiftRight(byte[] data, int shiftBy) {
|
||||||
|
if(0 > shiftBy || shiftBy > 8)
|
||||||
|
throw new IllegalArgumentException("Invalid shiftBy("+shiftBy+") argument, allowed values: 0-8");
|
||||||
|
if (shiftBy == 0)
|
||||||
|
return data;
|
||||||
|
|
||||||
|
byte rest = 0;
|
||||||
|
for (int i=0; i<data.length; ++i){
|
||||||
|
byte preRest = getBitsMSB(data[i], shiftBy);
|
||||||
|
data[i] = (byte)(data[i] << shiftBy);
|
||||||
|
if(i != 0)
|
||||||
|
data[i] |= rest;
|
||||||
|
rest = preRest;
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Presents a binary array in HEX and ASCII
|
* Presents a binary array in HEX and ASCII
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
package zutil.converter;
|
package zutil.converter;
|
||||||
|
|
||||||
|
import zutil.ByteUtil;
|
||||||
import zutil.io.DynamicByteArrayStream;
|
import zutil.io.DynamicByteArrayStream;
|
||||||
import zutil.parser.Base64Decoder;
|
import zutil.parser.Base64Decoder;
|
||||||
|
|
||||||
|
|
@ -186,6 +187,21 @@ public class Converter {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a byte to a Bit String (e.g 01100100)
|
||||||
|
*
|
||||||
|
* @param raw the byte array to convert
|
||||||
|
* @return a bit String
|
||||||
|
*/
|
||||||
|
public static String toBitString(byte raw){
|
||||||
|
StringBuilder str = new StringBuilder(8);
|
||||||
|
for (int i=0; i<8; ++i) {
|
||||||
|
str.append(raw & 0x01);
|
||||||
|
raw >>>= 1;
|
||||||
|
}
|
||||||
|
return str.reverse().toString();
|
||||||
|
}
|
||||||
|
|
||||||
/** array needed for byteToHex */
|
/** array needed for byteToHex */
|
||||||
private static char[] HEX_CHARS = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
|
private static char[] HEX_CHARS = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ public class BinaryStructInputStream {
|
||||||
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 = shiftBy(dataBitIndex, field.getBitLength(struct));
|
int shiftBy = shiftLeftBy(dataBitIndex, field.getBitLength(struct));
|
||||||
|
|
||||||
// Parse value
|
// Parse value
|
||||||
for (int valueDataIndex=valueData.length-1; valueDataIndex >= 0 ; --valueDataIndex) {
|
for (int valueDataIndex=valueData.length-1; valueDataIndex >= 0 ; --valueDataIndex) {
|
||||||
|
|
@ -101,7 +101,7 @@ public class BinaryStructInputStream {
|
||||||
return totalReadLength;
|
return totalReadLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static int shiftBy(int bitIndex, int bitLength){
|
protected static int shiftLeftBy(int bitIndex, int bitLength){
|
||||||
int shiftBy = (8 - ((7-bitIndex) + bitLength) % 8) % 8;
|
int shiftBy = (8 - ((7-bitIndex) + bitLength) % 8) % 8;
|
||||||
return shiftBy;
|
return shiftBy;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -78,15 +78,16 @@ public class BinaryStructOutputStream {
|
||||||
field.getSerializer().write(out, field.getValue(struct), field);
|
field.getSerializer().write(out, field.getValue(struct), field);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
byte[] data = field.getByteValue(struct);
|
|
||||||
|
|
||||||
int fieldBitLength = field.getBitLength(struct);
|
int fieldBitLength = field.getBitLength(struct);
|
||||||
|
byte[] data = field.getByteValue(struct);
|
||||||
|
data = ByteUtil.shiftRight(data, ((8 - fieldBitLength % 8) % 8));
|
||||||
|
|
||||||
for (int i=(int)Math.ceil(fieldBitLength/8.0)-1; fieldBitLength>0; fieldBitLength-=8, --i) {
|
for (int i=(int)Math.ceil(fieldBitLength/8.0)-1; fieldBitLength>0; fieldBitLength-=8, --i) {
|
||||||
byte b = data[i];
|
byte b = data[i];
|
||||||
if (restBitLength == 0 && fieldBitLength >= 8)
|
if (restBitLength == 0 && fieldBitLength >= 8)
|
||||||
out.write(0xFF & b);
|
out.write(0xFF & b);
|
||||||
else {
|
else {
|
||||||
b <<= 8 - restBitLength - fieldBitLength;
|
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;
|
||||||
|
|
|
||||||
|
|
@ -50,10 +50,18 @@ public class ByteUtilTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getBits(){
|
public void getBits(){
|
||||||
assertEquals(0x01, ByteUtil.getBits((byte)0xFF, 1));
|
assertEquals(0x01, ByteUtil.getBits((byte)0x11, 1));
|
||||||
assertEquals(0x0F, ByteUtil.getBits((byte)0xFF, 4));
|
assertEquals(0x03, ByteUtil.getBits((byte)0x13, 4));
|
||||||
assertEquals((byte)0xFF, ByteUtil.getBits((byte)0xFF, 8));
|
assertEquals((byte)0x55, ByteUtil.getBits((byte)0x55, 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getBitsMSB(){
|
||||||
|
assertEquals(0x01, ByteUtil.getBitsMSB((byte)0x80, 1));
|
||||||
|
assertEquals(0x05, ByteUtil.getBitsMSB((byte)0x52, 4));
|
||||||
|
assertEquals((byte)0x55, ByteUtil.getBitsMSB((byte)0x55, 8));
|
||||||
|
assertEquals((byte)0x03, ByteUtil.getBitsMSB((byte)0xFF, 2));
|
||||||
|
assertEquals((byte)0x0F, ByteUtil.getBitsMSB((byte)0xFF, 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -77,7 +85,7 @@ public class ByteUtilTest {
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void toFormattedStringTest(){
|
public void toFormattedString(){
|
||||||
byte[] data = new byte[1];
|
byte[] data = new byte[1];
|
||||||
assertEquals("000 00 '. '",
|
assertEquals("000 00 '. '",
|
||||||
ByteUtil.toFormattedString(data));
|
ByteUtil.toFormattedString(data));
|
||||||
|
|
@ -118,4 +126,24 @@ public class ByteUtilTest {
|
||||||
assertArrayEquals( new byte[]{0b0000_0001,0b0000_0001,0b0000_0001,0b0000_0001},
|
assertArrayEquals( new byte[]{0b0000_0001,0b0000_0001,0b0000_0001,0b0000_0001},
|
||||||
ByteUtil.shiftLeft(new byte[]{0b0001_0000,0b0001_0000,0b0001_0000,0b0001_0000}, 4));
|
ByteUtil.shiftLeft(new byte[]{0b0001_0000,0b0001_0000,0b0001_0000,0b0001_0000}, 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shiftRight(){
|
||||||
|
assertArrayEquals( new byte[]{},
|
||||||
|
ByteUtil.shiftRight(new byte[]{}, 4));
|
||||||
|
assertArrayEquals( new byte[]{0b0000_0001},
|
||||||
|
ByteUtil.shiftRight(new byte[]{0b0000_0001}, 0));
|
||||||
|
assertArrayEquals( new byte[]{(byte)0b0001_0000},
|
||||||
|
ByteUtil.shiftRight(new byte[]{0b0000_0001}, 4));
|
||||||
|
assertArrayEquals( new byte[]{(byte)0b1000_0000},
|
||||||
|
ByteUtil.shiftRight(new byte[]{0b0000_1000}, 4));
|
||||||
|
assertArrayEquals( new byte[]{0b0000_0000},
|
||||||
|
ByteUtil.shiftRight(new byte[]{(byte)0b0001_0000}, 4));
|
||||||
|
assertArrayEquals( new byte[]{0b0001_0000, 0b0001_0000},
|
||||||
|
ByteUtil.shiftRight(new byte[]{0b0000_0001, 0b0000_0001}, 4));
|
||||||
|
assertArrayEquals( new byte[]{(byte)0b1100_0000, (byte)0b1001_1111},
|
||||||
|
ByteUtil.shiftRight(new byte[]{0b0111_1111, 0b0101_0010}, 6));
|
||||||
|
assertArrayEquals( new byte[]{0b0000_0000,0b0000_0001,0b0000_0001,0b0000_0001},
|
||||||
|
ByteUtil.shiftRight(new byte[]{0b0001_0000,0b0001_0000,0b0001_0000,0b0001_0000}, 4));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -204,48 +204,48 @@ public class BinaryStructInputStreamTest {
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shiftBy(){
|
public void shiftLeftBy(){
|
||||||
assertEquals(0, BinaryStructInputStream.shiftBy(0, 1));
|
assertEquals(0, BinaryStructInputStream.shiftLeftBy(0, 1));
|
||||||
assertEquals(1, BinaryStructInputStream.shiftBy(1, 1));
|
assertEquals(1, BinaryStructInputStream.shiftLeftBy(1, 1));
|
||||||
assertEquals(3, BinaryStructInputStream.shiftBy(3, 1));
|
assertEquals(3, BinaryStructInputStream.shiftLeftBy(3, 1));
|
||||||
assertEquals(4, BinaryStructInputStream.shiftBy(4, 1));
|
assertEquals(4, BinaryStructInputStream.shiftLeftBy(4, 1));
|
||||||
assertEquals(5, BinaryStructInputStream.shiftBy(5, 1));
|
assertEquals(5, BinaryStructInputStream.shiftLeftBy(5, 1));
|
||||||
assertEquals(6, BinaryStructInputStream.shiftBy(6, 1));
|
assertEquals(6, BinaryStructInputStream.shiftLeftBy(6, 1));
|
||||||
assertEquals(7, BinaryStructInputStream.shiftBy(7, 1));
|
assertEquals(7, BinaryStructInputStream.shiftLeftBy(7, 1));
|
||||||
|
|
||||||
assertEquals(0, BinaryStructInputStream.shiftBy(1, 2));
|
assertEquals(0, BinaryStructInputStream.shiftLeftBy(1, 2));
|
||||||
assertEquals(2, BinaryStructInputStream.shiftBy(3, 2));
|
assertEquals(2, BinaryStructInputStream.shiftLeftBy(3, 2));
|
||||||
assertEquals(6, BinaryStructInputStream.shiftBy(7, 2));
|
assertEquals(6, BinaryStructInputStream.shiftLeftBy(7, 2));
|
||||||
|
|
||||||
assertEquals(0, BinaryStructInputStream.shiftBy(7, 8));
|
assertEquals(0, BinaryStructInputStream.shiftLeftBy(7, 8));
|
||||||
assertEquals(2, BinaryStructInputStream.shiftBy(7, 6));
|
assertEquals(2, BinaryStructInputStream.shiftLeftBy(7, 6));
|
||||||
assertEquals(3, BinaryStructInputStream.shiftBy(7, 5));
|
assertEquals(3, BinaryStructInputStream.shiftLeftBy(7, 5));
|
||||||
assertEquals(6, BinaryStructInputStream.shiftBy(7, 2));
|
assertEquals(6, BinaryStructInputStream.shiftLeftBy(7, 2));
|
||||||
|
|
||||||
// Cross 1 byte border
|
// Cross 1 byte border
|
||||||
assertEquals(7, BinaryStructInputStream.shiftBy(0, 2));
|
assertEquals(7, BinaryStructInputStream.shiftLeftBy(0, 2));
|
||||||
assertEquals(6, BinaryStructInputStream.shiftBy(1, 4));
|
assertEquals(6, BinaryStructInputStream.shiftLeftBy(1, 4));
|
||||||
assertEquals(4, BinaryStructInputStream.shiftBy(3, 8));
|
assertEquals(4, BinaryStructInputStream.shiftLeftBy(3, 8));
|
||||||
assertEquals(0, BinaryStructInputStream.shiftBy(3, 12));
|
assertEquals(0, BinaryStructInputStream.shiftLeftBy(3, 12));
|
||||||
assertEquals(0, BinaryStructInputStream.shiftBy(7, 16));
|
assertEquals(0, BinaryStructInputStream.shiftLeftBy(7, 16));
|
||||||
|
|
||||||
// Cross 2 byte borders
|
// Cross 2 byte borders
|
||||||
assertEquals(0, BinaryStructInputStream.shiftBy(7, 32));
|
assertEquals(0, BinaryStructInputStream.shiftLeftBy(7, 32));
|
||||||
assertEquals(7, BinaryStructInputStream.shiftBy(7, 33));
|
assertEquals(7, BinaryStructInputStream.shiftLeftBy(7, 33));
|
||||||
assertEquals(6, BinaryStructInputStream.shiftBy(7, 34));
|
assertEquals(6, BinaryStructInputStream.shiftLeftBy(7, 34));
|
||||||
assertEquals(5, BinaryStructInputStream.shiftBy(7, 35));
|
assertEquals(5, BinaryStructInputStream.shiftLeftBy(7, 35));
|
||||||
assertEquals(4, BinaryStructInputStream.shiftBy(7, 36));
|
assertEquals(4, BinaryStructInputStream.shiftLeftBy(7, 36));
|
||||||
assertEquals(3, BinaryStructInputStream.shiftBy(7, 37));
|
assertEquals(3, BinaryStructInputStream.shiftLeftBy(7, 37));
|
||||||
assertEquals(2, BinaryStructInputStream.shiftBy(7, 38));
|
assertEquals(2, BinaryStructInputStream.shiftLeftBy(7, 38));
|
||||||
assertEquals(1, BinaryStructInputStream.shiftBy(7, 39));
|
assertEquals(1, BinaryStructInputStream.shiftLeftBy(7, 39));
|
||||||
assertEquals(0, BinaryStructInputStream.shiftBy(7, 40));
|
assertEquals(0, BinaryStructInputStream.shiftLeftBy(7, 40));
|
||||||
assertEquals(7, BinaryStructInputStream.shiftBy(7, 41));
|
assertEquals(7, BinaryStructInputStream.shiftLeftBy(7, 41));
|
||||||
assertEquals(6, BinaryStructInputStream.shiftBy(6, 41));
|
assertEquals(6, BinaryStructInputStream.shiftLeftBy(6, 41));
|
||||||
assertEquals(5, BinaryStructInputStream.shiftBy(5, 41));
|
assertEquals(5, BinaryStructInputStream.shiftLeftBy(5, 41));
|
||||||
assertEquals(4, BinaryStructInputStream.shiftBy(4, 41));
|
assertEquals(4, BinaryStructInputStream.shiftLeftBy(4, 41));
|
||||||
assertEquals(3, BinaryStructInputStream.shiftBy(3, 41));
|
assertEquals(3, BinaryStructInputStream.shiftLeftBy(3, 41));
|
||||||
assertEquals(2, BinaryStructInputStream.shiftBy(2, 41));
|
assertEquals(2, BinaryStructInputStream.shiftLeftBy(2, 41));
|
||||||
assertEquals(1, BinaryStructInputStream.shiftBy(1, 41));
|
assertEquals(1, BinaryStructInputStream.shiftLeftBy(1, 41));
|
||||||
assertEquals(0, BinaryStructInputStream.shiftBy(7, 64));
|
assertEquals(0, BinaryStructInputStream.shiftLeftBy(7, 64));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,11 +25,14 @@
|
||||||
package zutil.parser.binary;
|
package zutil.parser.binary;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import zutil.converter.Converter;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
import static junit.framework.TestCase.assertEquals;
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -93,6 +96,27 @@ public class BinaryStructOutputStreamTest {
|
||||||
assertArrayEquals(expected, data);
|
assertArrayEquals(expected, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void mixedTypeTest() throws IOException {
|
||||||
|
BinaryStruct struct = new BinaryStruct() {
|
||||||
|
@BinaryField(index=1, length=26)
|
||||||
|
private int house = 11_772_006;
|
||||||
|
@BinaryField(index=2, length=1)
|
||||||
|
private boolean group = false;
|
||||||
|
@BinaryField(index=3, length=1)
|
||||||
|
private boolean enable = true;
|
||||||
|
@BinaryField(index=4, length=4)
|
||||||
|
private int unit = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
byte[] expected = new byte[]{
|
||||||
|
(byte) 0b0010_1100,
|
||||||
|
(byte) 0b1110_1000,
|
||||||
|
(byte) 0b0001_1001,
|
||||||
|
(byte) 0b10_0_1_0000};
|
||||||
|
byte[] actual = BinaryStructOutputStream.serialize(struct);
|
||||||
|
assertArrayEquals(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void customBinaryFieldTest() throws IOException {
|
public void customBinaryFieldTest() throws IOException {
|
||||||
|
|
@ -129,4 +153,5 @@ public class BinaryStructOutputStreamTest {
|
||||||
byte[] data = BinaryStructOutputStream.serialize(struct);
|
byte[] data = BinaryStructOutputStream.serialize(struct);
|
||||||
assertArrayEquals(expected, data);
|
assertArrayEquals(expected, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue