You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by sr...@apache.org on 2019/12/12 12:08:44 UTC
[plc4x] 01/01: first draft of big integer support on driver base
java
This is an automated email from the ASF dual-hosted git repository.
sruehl pushed a commit to branch feature/big_integer_support_on_driver_base
in repository https://gitbox.apache.org/repos/asf/plc4x.git
commit cf9a33fc5c6e982a920bc45efb256dc31e566adb
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Thu Dec 12 13:08:28 2019 +0100
first draft of big integer support on driver base java
---
plc4j/utils/driver-base-java/pom.xml | 6 +
.../org/apache/plc4x/java/utils/WriteBuffer.java | 106 ++++++++++----
.../apache/plc4x/java/utils/WriteBufferTest.java | 153 +++++++++++++++++++++
3 files changed, 239 insertions(+), 26 deletions(-)
diff --git a/plc4j/utils/driver-base-java/pom.xml b/plc4j/utils/driver-base-java/pom.xml
index 2adef47..01f6afc 100644
--- a/plc4j/utils/driver-base-java/pom.xml
+++ b/plc4j/utils/driver-base-java/pom.xml
@@ -37,6 +37,12 @@
<groupId>com.github.jinahya</groupId>
<artifactId>bit-io</artifactId>
</dependency>
+
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</project>
\ No newline at end of file
diff --git a/plc4j/utils/driver-base-java/src/main/java/org/apache/plc4x/java/utils/WriteBuffer.java b/plc4j/utils/driver-base-java/src/main/java/org/apache/plc4x/java/utils/WriteBuffer.java
index 8c14102..a0fd385 100644
--- a/plc4j/utils/driver-base-java/src/main/java/org/apache/plc4x/java/utils/WriteBuffer.java
+++ b/plc4j/utils/driver-base-java/src/main/java/org/apache/plc4x/java/utils/WriteBuffer.java
@@ -59,10 +59,10 @@ public class WriteBuffer {
}
public void writeUnsignedByte(int bitLength, byte value) throws ParseException {
- if(bitLength <= 0) {
+ if (bitLength <= 0) {
throw new ParseException("unsigned byte must contain at least 1 bit");
}
- if(bitLength > 4) {
+ if (bitLength > 4) {
throw new ParseException("unsigned byte can only contain max 4 bits");
}
try {
@@ -73,10 +73,10 @@ public class WriteBuffer {
}
public void writeUnsignedShort(int bitLength, short value) throws ParseException {
- if(bitLength <= 0) {
+ if (bitLength <= 0) {
throw new ParseException("unsigned short must contain at least 1 bit");
}
- if(bitLength > 8) {
+ if (bitLength > 8) {
throw new ParseException("unsigned short can only contain max 8 bits");
}
try {
@@ -87,14 +87,14 @@ public class WriteBuffer {
}
public void writeUnsignedInt(int bitLength, int value) throws ParseException {
- if(bitLength <= 0) {
+ if (bitLength <= 0) {
throw new ParseException("unsigned int must contain at least 1 bit");
}
- if(bitLength > 16) {
+ if (bitLength > 16) {
throw new ParseException("unsigned int can only contain max 16 bits");
}
try {
- if(!littleEndian) {
+ if (!littleEndian) {
value = Integer.reverseBytes(value) >> 16;
}
bo.writeInt(true, bitLength, value);
@@ -104,14 +104,14 @@ public class WriteBuffer {
}
public void writeUnsignedLong(int bitLength, long value) throws ParseException {
- if(bitLength <= 0) {
+ if (bitLength <= 0) {
throw new ParseException("unsigned long must contain at least 1 bit");
}
- if(bitLength > 32) {
+ if (bitLength > 32) {
throw new ParseException("unsigned long can only contain max 32 bits");
}
try {
- if(!littleEndian) {
+ if (!littleEndian) {
value = Long.reverseBytes(value) >> 32;
}
bo.writeLong(true, bitLength, value);
@@ -120,15 +120,11 @@ public class WriteBuffer {
}
}
- public void writeUnsignedBigInteger(int bitLength, BigInteger value) throws ParseException {
- throw new UnsupportedOperationException("not implemented yet");
- }
-
public void writeByte(int bitLength, byte value) throws ParseException {
- if(bitLength <= 0) {
+ if (bitLength <= 0) {
throw new ParseException("byte must contain at least 1 bit");
}
- if(bitLength > 8) {
+ if (bitLength > 8) {
throw new ParseException("byte can only contain max 8 bits");
}
try {
@@ -139,14 +135,14 @@ public class WriteBuffer {
}
public void writeShort(int bitLength, short value) throws ParseException {
- if(bitLength <= 0) {
+ if (bitLength <= 0) {
throw new ParseException("short must contain at least 1 bit");
}
- if(bitLength > 16) {
+ if (bitLength > 16) {
throw new ParseException("short can only contain max 16 bits");
}
try {
- if(!littleEndian) {
+ if (!littleEndian) {
value = Short.reverseBytes(value);
}
bo.writeShort(false, bitLength, value);
@@ -156,14 +152,14 @@ public class WriteBuffer {
}
public void writeInt(int bitLength, int value) throws ParseException {
- if(bitLength <= 0) {
+ if (bitLength <= 0) {
throw new ParseException("int must contain at least 1 bit");
}
- if(bitLength > 32) {
+ if (bitLength > 32) {
throw new ParseException("int can only contain max 32 bits");
}
try {
- if(!littleEndian) {
+ if (!littleEndian) {
value = Integer.reverseBytes(value);
}
bo.writeInt(false, bitLength, value);
@@ -173,14 +169,14 @@ public class WriteBuffer {
}
public void writeLong(int bitLength, long value) throws ParseException {
- if(bitLength <= 0) {
+ if (bitLength <= 0) {
throw new ParseException("long must contain at least 1 bit");
}
- if(bitLength > 64) {
+ if (bitLength > 64) {
throw new ParseException("long can only contain max 64 bits");
}
try {
- if(!littleEndian) {
+ if (!littleEndian) {
value = Long.reverseBytes(value);
}
bo.writeLong(false, bitLength, value);
@@ -190,9 +186,67 @@ public class WriteBuffer {
}
public void writeBigInteger(int bitLength, BigInteger value) throws ParseException {
- throw new UnsupportedOperationException("not implemented yet");
+ int actualBitLength = value.bitLength();
+ boolean negative = value.compareTo(BigInteger.ZERO) < 0;
+ int bitLengthIncludingPossibleSign = actualBitLength + (negative ? 1 : 0);
+ if (bitLength < bitLengthIncludingPossibleSign) {
+ throw new ParseException("bit length including possible sign " + bitLengthIncludingPossibleSign + " exceeds supplied bit length " + bitLength);
+ }
+ byte[] bytes = value.toByteArray();
+ int remainingBitLength = bitLengthIncludingPossibleSign;
+ try {
+ if (!littleEndian) {
+ // MSB in 0
+ for (int i = 0; i < bytes.length; i++) {
+ int bitsToWrite = Math.max(Math.min(remainingBitLength, 8), 1);
+ bo.writeByte(false, bitsToWrite, bytes[i]);
+ remainingBitLength -= bitsToWrite;
+ }
+ } else {
+ // MSB in bytes.length
+ for (int i = bytes.length - 1; i >= 0; i--) {
+ int bitsToWrite = Math.max(Math.min(remainingBitLength, 8), 1);
+ bo.writeByte(false, bitsToWrite, bytes[i]);
+ remainingBitLength -= bitsToWrite;
+ }
+ }
+ } catch (IOException e) {
+ throw new ParseException("Error reading", e);
+ }
}
+ public void writeUnsignedBigInteger(int bitLength, BigInteger value) throws ParseException {
+ if (value.compareTo(BigInteger.ZERO) < 0) {
+ throw new ParseException("value " + value + " is below 0");
+ }
+ int actualBitLength = value.bitLength();
+ if (bitLength < actualBitLength) {
+ throw new ParseException("bit length" + actualBitLength + " exceeds supplied bit length " + bitLength);
+ }
+ byte[] bytes = value.toByteArray();
+ int remainingBitLength = actualBitLength;
+ try {
+ if (!littleEndian) {
+ // MSB in 0
+ for (int i = 0; i < bytes.length; i++) {
+ int bitsToWrite = Math.max(Math.min(remainingBitLength, 8), 1);
+ bo.writeByte(false, bitsToWrite, bytes[i]);
+ remainingBitLength -= bitsToWrite;
+ }
+ } else {
+ // MSB in bytes.length
+ for (int i = bytes.length - 1; i >= 0; i--) {
+ int bitsToWrite = Math.max(Math.min(remainingBitLength, 8), 1);
+ bo.writeByte(false, bitsToWrite, bytes[i]);
+ remainingBitLength -= bitsToWrite;
+ }
+ }
+ } catch (IOException e) {
+ throw new ParseException("Error reading", e);
+ }
+ }
+
+
public void writeFloat(int bitLength, float value) throws ParseException {
throw new UnsupportedOperationException("not implemented yet");
}
diff --git a/plc4j/utils/driver-base-java/src/test/java/org/apache/plc4x/java/utils/WriteBufferTest.java b/plc4j/utils/driver-base-java/src/test/java/org/apache/plc4x/java/utils/WriteBufferTest.java
new file mode 100644
index 0000000..08ecd77
--- /dev/null
+++ b/plc4j/utils/driver-base-java/src/test/java/org/apache/plc4x/java/utils/WriteBufferTest.java
@@ -0,0 +1,153 @@
+package org.apache.plc4x.java.utils;
+
+import org.apache.commons.io.HexDump;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class WriteBufferTest {
+
+ @Test
+ void getData() {
+ // TODO: implement me
+ }
+
+ @Test
+ void writeBit() {
+ // TODO: implement me
+ }
+
+ @Test
+ void writeUnsignedByte() {
+ // TODO: implement me
+ }
+
+ @Test
+ void writeUnsignedShort() {
+ // TODO: implement me
+ }
+
+ @Test
+ void writeUnsignedInt() {
+ // TODO: implement me
+ }
+
+ @Test
+ void writeUnsignedLong() {
+ // TODO: implement me
+ }
+
+ @Test
+ void writeUnsignedBigInteger() {
+ // TODO: implement me
+ }
+
+ @Test
+ void writeByte() {
+ // TODO: implement me
+ }
+
+ @Test
+ void writeShort() {
+ // TODO: implement me
+ }
+
+ @Test
+ void writeInt() {
+ // TODO: implement me
+ }
+
+ @Test
+ void writeLong() {
+ // TODO: implement me
+ }
+
+ @Nested
+ class WriteBigInteger {
+ @Nested
+ class BigEndian {
+
+ @Test
+ void zero() throws Exception {
+ WriteBuffer SUT = new WriteBuffer(1, false);
+ SUT.writeBigInteger(8, BigInteger.ZERO);
+ byte[] data = SUT.getData();
+ System.out.println(toHex(data));
+ // TODO: check right representation
+ assertArrayEquals(new byte[]{0b0000_0000}, data);
+ assertEquals(BigInteger.ZERO, new BigInteger(data));
+ }
+
+ @Test
+ void one() throws Exception {
+ WriteBuffer SUT = new WriteBuffer(1, false);
+ SUT.writeBigInteger(8, BigInteger.ONE);
+ byte[] data = SUT.getData();
+ System.out.println(toHex(data));
+ // TODO: check right representation
+ assertArrayEquals(new byte[]{0b0000_0001}, data);
+ assertEquals(BigInteger.ZERO, new BigInteger(data));
+ }
+
+ @Test
+ void minusOne() throws Exception {
+ WriteBuffer SUT = new WriteBuffer(1, false);
+ SUT.writeBigInteger(8, BigInteger.ZERO.subtract(BigInteger.ONE));
+ byte[] data = SUT.getData();
+ System.out.println(toHex(data));
+ // TODO: check right representation
+ assertArrayEquals(new byte[]{0b0000_0001}, data);
+ assertEquals(BigInteger.ZERO, new BigInteger(data));
+ }
+
+ @Test
+ void minus255() throws Exception {
+ WriteBuffer SUT = new WriteBuffer(1, false);
+ SUT.writeBigInteger(8, BigInteger.valueOf(-255L));
+ byte[] data = SUT.getData();
+ System.out.println(toHex(data));
+ // TODO: check right representation
+ assertArrayEquals(new byte[]{(byte) 0b1000_0000, 0b0000_0001}, data);
+ assertEquals(BigInteger.valueOf(-255L), new BigInteger(data));
+ }
+
+ }
+
+ @Nested
+ class LittleEndian {
+
+ @Test
+ void writeBigInteger_LE() throws Exception {
+ WriteBuffer SUT_LE = new WriteBuffer(8012, true);
+ SUT_LE.writeBigInteger(1, BigInteger.ZERO);
+ }
+ }
+ }
+
+ @Test
+ void writeFloat() {
+ // TODO: implement me
+ }
+
+ @Test
+ void writeDouble() {
+ // TODO: implement me
+ }
+
+ @Test
+ void writeBigDecimal() {
+ // TODO: implement me
+ }
+
+ public static String toHex(byte[] bytes) throws Exception {
+ try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
+ HexDump.dump(bytes, 0, byteArrayOutputStream, 0);
+ return byteArrayOutputStream.toString();
+ }
+ }
+}
\ No newline at end of file