diff --git a/src/zutil/ByteUtil.java b/src/zutil/ByteUtil.java index a16503f..47a7842 100755 --- a/src/zutil/ByteUtil.java +++ b/src/zutil/ByteUtil.java @@ -44,16 +44,6 @@ public class ByteUtil { {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 @@ -82,6 +72,17 @@ public class ByteUtil { 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. * @@ -97,6 +98,17 @@ public class ByteUtil { 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 * (LittleEndian -> BigEndian, BigEndian -> LittleEndian) @@ -144,7 +156,7 @@ public class ByteUtil { byte rest = 0; for (int i=0; i> shiftBy); + data[i] = (byte)((data[i]&0xFF) >>> shiftBy); if(i != 0) data[i-1] |= rest; } @@ -152,6 +164,31 @@ public class ByteUtil { 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>>= 1; + } + return str.reverse().toString(); + } + /** 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'}; /** diff --git a/src/zutil/parser/binary/BinaryStructInputStream.java b/src/zutil/parser/binary/BinaryStructInputStream.java index 23b5b75..997b035 100755 --- a/src/zutil/parser/binary/BinaryStructInputStream.java +++ b/src/zutil/parser/binary/BinaryStructInputStream.java @@ -78,7 +78,7 @@ public class BinaryStructInputStream { 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 = shiftBy(dataBitIndex, field.getBitLength(struct)); + int shiftBy = shiftLeftBy(dataBitIndex, field.getBitLength(struct)); // Parse value for (int valueDataIndex=valueData.length-1; valueDataIndex >= 0 ; --valueDataIndex) { @@ -101,7 +101,7 @@ public class BinaryStructInputStream { 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; return shiftBy; } diff --git a/src/zutil/parser/binary/BinaryStructOutputStream.java b/src/zutil/parser/binary/BinaryStructOutputStream.java index 0bb2d2a..8d83d5f 100755 --- a/src/zutil/parser/binary/BinaryStructOutputStream.java +++ b/src/zutil/parser/binary/BinaryStructOutputStream.java @@ -78,15 +78,16 @@ public class BinaryStructOutputStream { field.getSerializer().write(out, field.getValue(struct), field); } else{ - byte[] data = field.getByteValue(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) { byte b = data[i]; if (restBitLength == 0 && fieldBitLength >= 8) out.write(0xFF & b); else { - b <<= 8 - restBitLength - fieldBitLength; + b = (byte)((b&0xFF) >> restBitLength); b &= ByteUtil.getBitMask(7 - restBitLength, fieldBitLength); rest |= b; restBitLength += fieldBitLength; diff --git a/test/zutil/ByteUtilTest.java b/test/zutil/ByteUtilTest.java index d2413ae..b25944f 100755 --- a/test/zutil/ByteUtilTest.java +++ b/test/zutil/ByteUtilTest.java @@ -50,10 +50,18 @@ public class ByteUtilTest { @Test public void getBits(){ - assertEquals(0x01, ByteUtil.getBits((byte)0xFF, 1)); - assertEquals(0x0F, ByteUtil.getBits((byte)0xFF, 4)); - assertEquals((byte)0xFF, ByteUtil.getBits((byte)0xFF, 8)); + assertEquals(0x01, ByteUtil.getBits((byte)0x11, 1)); + assertEquals(0x03, ByteUtil.getBits((byte)0x13, 4)); + 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 @@ -77,7 +85,7 @@ public class ByteUtilTest { @Test - public void toFormattedStringTest(){ + public void toFormattedString(){ byte[] data = new byte[1]; assertEquals("000 00 '. '", ByteUtil.toFormattedString(data)); @@ -118,4 +126,24 @@ public class ByteUtilTest { assertArrayEquals( new byte[]{0b0000_0001,0b0000_0001,0b0000_0001,0b0000_0001}, 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)); + } } diff --git a/test/zutil/parser/binary/BinaryStructInputStreamTest.java b/test/zutil/parser/binary/BinaryStructInputStreamTest.java index 3d76372..c0fe759 100755 --- a/test/zutil/parser/binary/BinaryStructInputStreamTest.java +++ b/test/zutil/parser/binary/BinaryStructInputStreamTest.java @@ -204,48 +204,48 @@ public class BinaryStructInputStreamTest { @Test - public void shiftBy(){ - assertEquals(0, BinaryStructInputStream.shiftBy(0, 1)); - assertEquals(1, BinaryStructInputStream.shiftBy(1, 1)); - assertEquals(3, BinaryStructInputStream.shiftBy(3, 1)); - assertEquals(4, BinaryStructInputStream.shiftBy(4, 1)); - assertEquals(5, BinaryStructInputStream.shiftBy(5, 1)); - assertEquals(6, BinaryStructInputStream.shiftBy(6, 1)); - assertEquals(7, BinaryStructInputStream.shiftBy(7, 1)); + public void shiftLeftBy(){ + assertEquals(0, BinaryStructInputStream.shiftLeftBy(0, 1)); + assertEquals(1, BinaryStructInputStream.shiftLeftBy(1, 1)); + assertEquals(3, BinaryStructInputStream.shiftLeftBy(3, 1)); + assertEquals(4, BinaryStructInputStream.shiftLeftBy(4, 1)); + assertEquals(5, BinaryStructInputStream.shiftLeftBy(5, 1)); + assertEquals(6, BinaryStructInputStream.shiftLeftBy(6, 1)); + assertEquals(7, BinaryStructInputStream.shiftLeftBy(7, 1)); - assertEquals(0, BinaryStructInputStream.shiftBy(1, 2)); - assertEquals(2, BinaryStructInputStream.shiftBy(3, 2)); - assertEquals(6, BinaryStructInputStream.shiftBy(7, 2)); + assertEquals(0, BinaryStructInputStream.shiftLeftBy(1, 2)); + assertEquals(2, BinaryStructInputStream.shiftLeftBy(3, 2)); + assertEquals(6, BinaryStructInputStream.shiftLeftBy(7, 2)); - assertEquals(0, BinaryStructInputStream.shiftBy(7, 8)); - assertEquals(2, BinaryStructInputStream.shiftBy(7, 6)); - assertEquals(3, BinaryStructInputStream.shiftBy(7, 5)); - assertEquals(6, BinaryStructInputStream.shiftBy(7, 2)); + assertEquals(0, BinaryStructInputStream.shiftLeftBy(7, 8)); + assertEquals(2, BinaryStructInputStream.shiftLeftBy(7, 6)); + assertEquals(3, BinaryStructInputStream.shiftLeftBy(7, 5)); + assertEquals(6, BinaryStructInputStream.shiftLeftBy(7, 2)); // Cross 1 byte border - assertEquals(7, BinaryStructInputStream.shiftBy(0, 2)); - assertEquals(6, BinaryStructInputStream.shiftBy(1, 4)); - assertEquals(4, BinaryStructInputStream.shiftBy(3, 8)); - assertEquals(0, BinaryStructInputStream.shiftBy(3, 12)); - assertEquals(0, BinaryStructInputStream.shiftBy(7, 16)); + assertEquals(7, BinaryStructInputStream.shiftLeftBy(0, 2)); + assertEquals(6, BinaryStructInputStream.shiftLeftBy(1, 4)); + assertEquals(4, BinaryStructInputStream.shiftLeftBy(3, 8)); + assertEquals(0, BinaryStructInputStream.shiftLeftBy(3, 12)); + assertEquals(0, BinaryStructInputStream.shiftLeftBy(7, 16)); // Cross 2 byte borders - assertEquals(0, BinaryStructInputStream.shiftBy(7, 32)); - assertEquals(7, BinaryStructInputStream.shiftBy(7, 33)); - assertEquals(6, BinaryStructInputStream.shiftBy(7, 34)); - assertEquals(5, BinaryStructInputStream.shiftBy(7, 35)); - assertEquals(4, BinaryStructInputStream.shiftBy(7, 36)); - assertEquals(3, BinaryStructInputStream.shiftBy(7, 37)); - assertEquals(2, BinaryStructInputStream.shiftBy(7, 38)); - assertEquals(1, BinaryStructInputStream.shiftBy(7, 39)); - assertEquals(0, BinaryStructInputStream.shiftBy(7, 40)); - assertEquals(7, BinaryStructInputStream.shiftBy(7, 41)); - assertEquals(6, BinaryStructInputStream.shiftBy(6, 41)); - assertEquals(5, BinaryStructInputStream.shiftBy(5, 41)); - assertEquals(4, BinaryStructInputStream.shiftBy(4, 41)); - assertEquals(3, BinaryStructInputStream.shiftBy(3, 41)); - assertEquals(2, BinaryStructInputStream.shiftBy(2, 41)); - assertEquals(1, BinaryStructInputStream.shiftBy(1, 41)); - assertEquals(0, BinaryStructInputStream.shiftBy(7, 64)); + assertEquals(0, BinaryStructInputStream.shiftLeftBy(7, 32)); + assertEquals(7, BinaryStructInputStream.shiftLeftBy(7, 33)); + assertEquals(6, BinaryStructInputStream.shiftLeftBy(7, 34)); + assertEquals(5, BinaryStructInputStream.shiftLeftBy(7, 35)); + assertEquals(4, BinaryStructInputStream.shiftLeftBy(7, 36)); + assertEquals(3, BinaryStructInputStream.shiftLeftBy(7, 37)); + assertEquals(2, BinaryStructInputStream.shiftLeftBy(7, 38)); + assertEquals(1, BinaryStructInputStream.shiftLeftBy(7, 39)); + assertEquals(0, BinaryStructInputStream.shiftLeftBy(7, 40)); + assertEquals(7, BinaryStructInputStream.shiftLeftBy(7, 41)); + assertEquals(6, BinaryStructInputStream.shiftLeftBy(6, 41)); + assertEquals(5, BinaryStructInputStream.shiftLeftBy(5, 41)); + assertEquals(4, BinaryStructInputStream.shiftLeftBy(4, 41)); + assertEquals(3, BinaryStructInputStream.shiftLeftBy(3, 41)); + assertEquals(2, BinaryStructInputStream.shiftLeftBy(2, 41)); + assertEquals(1, BinaryStructInputStream.shiftLeftBy(1, 41)); + assertEquals(0, BinaryStructInputStream.shiftLeftBy(7, 64)); } } diff --git a/test/zutil/parser/binary/BinaryStructOutputStreamTest.java b/test/zutil/parser/binary/BinaryStructOutputStreamTest.java index 9530ada..97c53f2 100755 --- a/test/zutil/parser/binary/BinaryStructOutputStreamTest.java +++ b/test/zutil/parser/binary/BinaryStructOutputStreamTest.java @@ -25,11 +25,14 @@ package zutil.parser.binary; import org.junit.Test; +import zutil.converter.Converter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.nio.charset.StandardCharsets; +import static junit.framework.TestCase.assertEquals; import static org.junit.Assert.assertArrayEquals; @@ -93,6 +96,27 @@ public class BinaryStructOutputStreamTest { 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 public void customBinaryFieldTest() throws IOException { @@ -129,4 +153,5 @@ public class BinaryStructOutputStreamTest { byte[] data = BinaryStructOutputStream.serialize(struct); assertArrayEquals(expected, data); } + }