From c2ef5bdba6e0eb9fd9eb6ed4fdae75727cc36783 Mon Sep 17 00:00:00 2001
From: pfavre
Date: Sun, 29 Nov 2020 19:55:00 +0100
Subject: [PATCH 01/39] Update Links to Travis CI (using .com now as required
by Travis migration)
---
README.md | 2 +-
pom.xml | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 389643f..fb4a105 100644
--- a/README.md
+++ b/README.md
@@ -28,7 +28,7 @@ to blindly paste code snippets from
[m](https://stackoverflow.com/questions/1519736/random-shuffling-of-an-array)
[](https://bintray.com/patrickfav/maven/bytes-java/_latestVersion)
-[](https://travis-ci.org/patrickfav/bytes-java)
+[](https://travis-ci.com/patrickfav/bytes-java)
[](https://www.javadoc.io/doc/at.favre.lib/bytes)
[](https://coveralls.io/github/patrickfav/bytes-java?branch=master)
[](https://codeclimate.com/github/patrickfav/bytes-java/maintainability)
diff --git a/pom.xml b/pom.xml
index 8d70d20..0a27b42 100644
--- a/pom.xml
+++ b/pom.xml
@@ -138,6 +138,6 @@
Travis
- https://travis-ci.org/patrickfav/bytes-java
+ https://travis-ci.com/patrickfav/bytes-java
From 2208aade7db2f116543940f0ef13f80dc302b02f Mon Sep 17 00:00:00 2001
From: Grant Peltier
Date: Sun, 21 Feb 2021 11:40:48 -0600
Subject: [PATCH 02/39] Fix Bytes.bitAt to respect byte order
Closes #39. bitAt now checks byte order before locating the desired
bit.
---
src/main/java/at/favre/lib/bytes/Bytes.java | 6 +++++-
src/test/java/at/favre/lib/bytes/BytesMiscTest.java | 6 ++++++
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/src/main/java/at/favre/lib/bytes/Bytes.java b/src/main/java/at/favre/lib/bytes/Bytes.java
index b033e41..a04e319 100644
--- a/src/main/java/at/favre/lib/bytes/Bytes.java
+++ b/src/main/java/at/favre/lib/bytes/Bytes.java
@@ -1338,7 +1338,11 @@ public boolean endsWith(byte[] subArray) {
*/
public boolean bitAt(int bitIndex) {
Util.Validation.checkIndexBounds(lengthBit(), bitIndex, 1, "bit");
- return ((byteAt(length() - 1 - (bitIndex / 8)) >>> bitIndex % 8) & 1) != 0;
+ if (byteOrder == ByteOrder.BIG_ENDIAN) {
+ return ((byteAt(length() - 1 - (bitIndex / 8)) >>> bitIndex % 8) & 1) != 0;
+ } else {
+ return ((byteAt(bitIndex / 8) >>> bitIndex % 8) & 1) != 0;
+ }
}
/**
diff --git a/src/test/java/at/favre/lib/bytes/BytesMiscTest.java b/src/test/java/at/favre/lib/bytes/BytesMiscTest.java
index 95303f7..ed832bb 100644
--- a/src/test/java/at/favre/lib/bytes/BytesMiscTest.java
+++ b/src/test/java/at/favre/lib/bytes/BytesMiscTest.java
@@ -272,6 +272,12 @@ public void bitAt() {
fail();
} catch (IndexOutOfBoundsException ignored) {
}
+
+ Bytes bytes = Bytes.wrap(new byte[]{1, 0, 2, 0}).byteOrder(ByteOrder.LITTLE_ENDIAN);
+ assertTrue(bytes.bitAt(0));
+ assertTrue(bytes.bitAt(17));
+ assertFalse(bytes.bitAt(8));
+ assertFalse(bytes.bitAt(31));
}
@Test
From e997250f181cf60d3dbfb729a4c755e06fdf14d3 Mon Sep 17 00:00:00 2001
From: Grant Peltier
Date: Mon, 22 Feb 2021 16:56:27 -0600
Subject: [PATCH 03/39] Fix bit shift methods to respect byte order
Closes #41. Bytes.leftShift and Bytes.rightShift now behave as expected
based on the set byte order.
---
src/main/java/at/favre/lib/bytes/Bytes.java | 12 ++-
.../at/favre/lib/bytes/BytesTransformer.java | 9 ++-
src/main/java/at/favre/lib/bytes/Util.java | 78 +++++++++++++------
.../favre/lib/bytes/BytesTransformTest.java | 3 +-
.../java/at/favre/lib/bytes/UtilByteTest.java | 73 ++++++++++-------
5 files changed, 120 insertions(+), 55 deletions(-)
diff --git a/src/main/java/at/favre/lib/bytes/Bytes.java b/src/main/java/at/favre/lib/bytes/Bytes.java
index a04e319..f1ab738 100644
--- a/src/main/java/at/favre/lib/bytes/Bytes.java
+++ b/src/main/java/at/favre/lib/bytes/Bytes.java
@@ -967,7 +967,11 @@ public Bytes not() {
* @see Bit shifts
*/
public Bytes leftShift(int shiftCount) {
- return transform(new BytesTransformer.ShiftTransformer(shiftCount, BytesTransformer.ShiftTransformer.Type.LEFT_SHIFT));
+ return transform(new BytesTransformer.ShiftTransformer(
+ shiftCount,
+ BytesTransformer.ShiftTransformer.Type.LEFT_SHIFT,
+ byteOrder
+ ));
}
/**
@@ -982,7 +986,11 @@ public Bytes leftShift(int shiftCount) {
* @see Bit shifts
*/
public Bytes rightShift(int shiftCount) {
- return transform(new BytesTransformer.ShiftTransformer(shiftCount, BytesTransformer.ShiftTransformer.Type.RIGHT_SHIFT));
+ return transform(new BytesTransformer.ShiftTransformer(
+ shiftCount,
+ BytesTransformer.ShiftTransformer.Type.RIGHT_SHIFT,
+ byteOrder
+ ));
}
/**
diff --git a/src/main/java/at/favre/lib/bytes/BytesTransformer.java b/src/main/java/at/favre/lib/bytes/BytesTransformer.java
index 3612505..22367d8 100644
--- a/src/main/java/at/favre/lib/bytes/BytesTransformer.java
+++ b/src/main/java/at/favre/lib/bytes/BytesTransformer.java
@@ -21,6 +21,7 @@
package at.favre.lib.bytes;
+import java.nio.ByteOrder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Objects;
@@ -131,10 +132,12 @@ public enum Type {
private final int shiftCount;
private final Type type;
+ private final ByteOrder byteOrder;
- ShiftTransformer(int shiftCount, Type type) {
+ ShiftTransformer(int shiftCount, Type type, ByteOrder byteOrder) {
this.shiftCount = shiftCount;
this.type = Objects.requireNonNull(type, "passed shift type must not be null");
+ this.byteOrder = Objects.requireNonNull(byteOrder, "passed byteOrder type must not be null");
}
@Override
@@ -143,10 +146,10 @@ public byte[] transform(byte[] currentArray, boolean inPlace) {
switch (type) {
case RIGHT_SHIFT:
- return Util.Byte.shiftRight(out, shiftCount);
+ return Util.Byte.shiftRight(out, shiftCount, byteOrder);
default:
case LEFT_SHIFT:
- return Util.Byte.shiftLeft(out, shiftCount);
+ return Util.Byte.shiftLeft(out, shiftCount, byteOrder);
}
}
diff --git a/src/main/java/at/favre/lib/bytes/Util.java b/src/main/java/at/favre/lib/bytes/Util.java
index 2588223..ee494fc 100644
--- a/src/main/java/at/favre/lib/bytes/Util.java
+++ b/src/main/java/at/favre/lib/bytes/Util.java
@@ -291,25 +291,42 @@ static void reverse(byte[] array, int fromIndex, int toIndex) {
*
* @param byteArray to shift
* @param shiftBitCount how many bits to shift
+ * @param byteOrder endianness of given byte array
* @return shifted byte array
*/
- static byte[] shiftLeft(byte[] byteArray, int shiftBitCount) {
+ static byte[] shiftLeft(byte[] byteArray, int shiftBitCount, ByteOrder byteOrder) {
final int shiftMod = shiftBitCount % 8;
final byte carryMask = (byte) ((1 << shiftMod) - 1);
final int offsetBytes = (shiftBitCount / 8);
int sourceIndex;
- for (int i = 0; i < byteArray.length; i++) {
- sourceIndex = i + offsetBytes;
- if (sourceIndex >= byteArray.length) {
- byteArray[i] = 0;
- } else {
- byte src = byteArray[sourceIndex];
- byte dst = (byte) (src << shiftMod);
- if (sourceIndex + 1 < byteArray.length) {
- dst |= byteArray[sourceIndex + 1] >>> (8 - shiftMod) & carryMask;
+ if (byteOrder == ByteOrder.BIG_ENDIAN) {
+ for (int i = 0; i < byteArray.length; i++) {
+ sourceIndex = i + offsetBytes;
+ if (sourceIndex >= byteArray.length) {
+ byteArray[i] = 0;
+ } else {
+ byte src = byteArray[sourceIndex];
+ byte dst = (byte) (src << shiftMod);
+ if (sourceIndex + 1 < byteArray.length) {
+ dst |= byteArray[sourceIndex + 1] >>> (8 - shiftMod) & carryMask;
+ }
+ byteArray[i] = dst;
+ }
+ }
+ } else {
+ for (int i = byteArray.length - 1; i >= 0; i--) {
+ sourceIndex = i - offsetBytes;
+ if (sourceIndex < 0) {
+ byteArray[i] = 0;
+ } else {
+ byte src = byteArray[sourceIndex];
+ byte dst = (byte) (src << shiftMod);
+ if (sourceIndex - 1 >= 0) {
+ dst |= byteArray[sourceIndex - 1] >>> (8 - shiftMod) & carryMask;
+ }
+ byteArray[i] = dst;
}
- byteArray[i] = dst;
}
}
return byteArray;
@@ -330,25 +347,42 @@ static byte[] shiftLeft(byte[] byteArray, int shiftBitCount) {
*
* @param byteArray to shift
* @param shiftBitCount how many bits to shift
+ * @param byteOrder endianness of given byte array
* @return shifted byte array
*/
- static byte[] shiftRight(byte[] byteArray, int shiftBitCount) {
+ static byte[] shiftRight(byte[] byteArray, int shiftBitCount, ByteOrder byteOrder) {
final int shiftMod = shiftBitCount % 8;
final byte carryMask = (byte) (0xFF << (8 - shiftMod));
final int offsetBytes = (shiftBitCount / 8);
int sourceIndex;
- for (int i = byteArray.length - 1; i >= 0; i--) {
- sourceIndex = i - offsetBytes;
- if (sourceIndex < 0) {
- byteArray[i] = 0;
- } else {
- byte src = byteArray[sourceIndex];
- byte dst = (byte) ((0xff & src) >>> shiftMod);
- if (sourceIndex - 1 >= 0) {
- dst |= byteArray[sourceIndex - 1] << (8 - shiftMod) & carryMask;
+ if (byteOrder == ByteOrder.BIG_ENDIAN) {
+ for (int i = byteArray.length - 1; i >= 0; i--) {
+ sourceIndex = i - offsetBytes;
+ if (sourceIndex < 0) {
+ byteArray[i] = 0;
+ } else {
+ byte src = byteArray[sourceIndex];
+ byte dst = (byte) ((0xff & src) >>> shiftMod);
+ if (sourceIndex - 1 >= 0) {
+ dst |= byteArray[sourceIndex - 1] << (8 - shiftMod) & carryMask;
+ }
+ byteArray[i] = dst;
+ }
+ }
+ } else {
+ for (int i = 0; i < byteArray.length; i++) {
+ sourceIndex = i + offsetBytes;
+ if (sourceIndex >= byteArray.length) {
+ byteArray[i] = 0;
+ } else {
+ byte src = byteArray[sourceIndex];
+ byte dst = (byte) ((0xff & src) >>> shiftMod);
+ if (sourceIndex + 1 < byteArray.length) {
+ dst |= byteArray[sourceIndex + 1] << (8 - shiftMod) & carryMask;
+ }
+ byteArray[i] = dst;
}
- byteArray[i] = dst;
}
}
return byteArray;
diff --git a/src/test/java/at/favre/lib/bytes/BytesTransformTest.java b/src/test/java/at/favre/lib/bytes/BytesTransformTest.java
index dd6feaf..8041380 100644
--- a/src/test/java/at/favre/lib/bytes/BytesTransformTest.java
+++ b/src/test/java/at/favre/lib/bytes/BytesTransformTest.java
@@ -25,6 +25,7 @@
import java.math.BigInteger;
import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Comparator;
@@ -446,7 +447,7 @@ public void transformerInPlaceTest() {
assertTrue(new BytesTransformer.BitSwitchTransformer(0, true).supportInPlaceTransformation());
assertTrue(new BytesTransformer.BitWiseOperatorTransformer(new byte[]{}, BytesTransformer.BitWiseOperatorTransformer.Mode.XOR).supportInPlaceTransformation());
assertTrue(new BytesTransformer.NegateTransformer().supportInPlaceTransformation());
- assertTrue(new BytesTransformer.ShiftTransformer(0, BytesTransformer.ShiftTransformer.Type.LEFT_SHIFT).supportInPlaceTransformation());
+ assertTrue(new BytesTransformer.ShiftTransformer(0, BytesTransformer.ShiftTransformer.Type.LEFT_SHIFT, ByteOrder.BIG_ENDIAN).supportInPlaceTransformation());
assertTrue(new BytesTransformer.ReverseTransformer().supportInPlaceTransformation());
assertFalse(new BytesTransformer.MessageDigestTransformer("SHA1").supportInPlaceTransformation());
diff --git a/src/test/java/at/favre/lib/bytes/UtilByteTest.java b/src/test/java/at/favre/lib/bytes/UtilByteTest.java
index 26180ea..95b55fb 100644
--- a/src/test/java/at/favre/lib/bytes/UtilByteTest.java
+++ b/src/test/java/at/favre/lib/bytes/UtilByteTest.java
@@ -25,6 +25,7 @@
import org.junit.Test;
import java.math.BigInteger;
+import java.nio.ByteOrder;
import java.util.Arrays;
import java.util.Random;
@@ -162,21 +163,34 @@ private static void testReverse(byte[] input, int fromIndex, int toIndex, byte[]
@Test
public void testLeftShift() {
byte[] test = new byte[]{0, 0, 1, 0};
- assertArrayEquals(new byte[]{0, 1, 0, 0}, Util.Byte.shiftLeft(new byte[]{0, 0, -128, 0}, 1));
- assertArrayEquals(new byte[]{0, 1, 0, 0}, Util.Byte.shiftLeft(new byte[]{0, 0, 64, 0}, 2));
- assertArrayEquals(new byte[]{1, 1, 1, 0}, Util.Byte.shiftLeft(new byte[]{-128, -128, -128, -128}, 1));
- assertArrayEquals(new byte[]{0, 0, 2, 0}, Util.Byte.shiftLeft(Bytes.from(test).array(), 1));
- assertArrayEquals(new byte[]{0, 0, 4, 0}, Util.Byte.shiftLeft(Bytes.from(test).array(), 2));
- assertArrayEquals(new byte[]{0, 0, 8, 0}, Util.Byte.shiftLeft(Bytes.from(test).array(), 3));
- assertArrayEquals(new byte[]{0, 1, 0, 0}, Util.Byte.shiftLeft(Bytes.from(test).array(), 8));
- assertArrayEquals(new byte[]{0, 2, 0, 0}, Util.Byte.shiftLeft(Bytes.from(test).array(), 9));
- assertArrayEquals(new byte[]{1, 0, 0, 0}, Util.Byte.shiftLeft(Bytes.from(test).array(), 16));
- assertArrayEquals(new byte[]{2, 0, 0, 0}, Util.Byte.shiftLeft(Bytes.from(test).array(), 17));
- assertArrayEquals(new byte[]{-128, 0, 0, 0}, Util.Byte.shiftLeft(Bytes.from(test).array(), 23));
- assertArrayEquals(new byte[]{0, 0, 0, 0}, Util.Byte.shiftLeft(Bytes.from(test).array(), 24));
- assertArrayEquals(new byte[]{0, 0, 0, 0}, Util.Byte.shiftLeft(Bytes.from(test).array(), 24));
-
- assertSame(test, Util.Byte.shiftLeft(test, 1));
+ assertArrayEquals(new byte[]{0, 1, 0, 0}, Util.Byte.shiftLeft(new byte[]{0, 0, -128, 0}, 1, ByteOrder.BIG_ENDIAN));
+ assertArrayEquals(new byte[]{0, 1, 0, 0}, Util.Byte.shiftLeft(new byte[]{0, 0, 64, 0}, 2, ByteOrder.BIG_ENDIAN));
+ assertArrayEquals(new byte[]{1, 1, 1, 0}, Util.Byte.shiftLeft(new byte[]{-128, -128, -128, -128}, 1, ByteOrder.BIG_ENDIAN));
+ assertArrayEquals(new byte[]{0, 0, 2, 0}, Util.Byte.shiftLeft(Bytes.from(test).array(), 1, ByteOrder.BIG_ENDIAN));
+ assertArrayEquals(new byte[]{0, 0, 4, 0}, Util.Byte.shiftLeft(Bytes.from(test).array(), 2, ByteOrder.BIG_ENDIAN));
+ assertArrayEquals(new byte[]{0, 0, 8, 0}, Util.Byte.shiftLeft(Bytes.from(test).array(), 3, ByteOrder.BIG_ENDIAN));
+ assertArrayEquals(new byte[]{0, 1, 0, 0}, Util.Byte.shiftLeft(Bytes.from(test).array(), 8, ByteOrder.BIG_ENDIAN));
+ assertArrayEquals(new byte[]{0, 2, 0, 0}, Util.Byte.shiftLeft(Bytes.from(test).array(), 9, ByteOrder.BIG_ENDIAN));
+ assertArrayEquals(new byte[]{1, 0, 0, 0}, Util.Byte.shiftLeft(Bytes.from(test).array(), 16, ByteOrder.BIG_ENDIAN));
+ assertArrayEquals(new byte[]{2, 0, 0, 0}, Util.Byte.shiftLeft(Bytes.from(test).array(), 17, ByteOrder.BIG_ENDIAN));
+ assertArrayEquals(new byte[]{-128, 0, 0, 0}, Util.Byte.shiftLeft(Bytes.from(test).array(), 23, ByteOrder.BIG_ENDIAN));
+ assertArrayEquals(new byte[]{0, 0, 0, 0}, Util.Byte.shiftLeft(Bytes.from(test).array(), 24, ByteOrder.BIG_ENDIAN));
+ assertArrayEquals(new byte[]{0, 0, 0, 0}, Util.Byte.shiftLeft(Bytes.from(test).array(), 24, ByteOrder.BIG_ENDIAN));
+
+ assertSame(test, Util.Byte.shiftLeft(test, 1, ByteOrder.BIG_ENDIAN));
+
+ assertArrayEquals(new byte[]{0, 0, 1, 0}, Util.Byte.shiftLeft(new byte[]{0, 1, 0, 0}, 8, ByteOrder.LITTLE_ENDIAN));
+ assertArrayEquals(new byte[]{(byte) 0, 0, 1, 0}, Util.Byte.shiftLeft(new byte[]{(byte) 0, 1, 0, 1}, 8, ByteOrder.LITTLE_ENDIAN));
+ assertArrayEquals(new byte[]{(byte) 0x54, 0x1}, Util.Byte.shiftLeft(new byte[]{(byte) 0xAA, 0}, 1, ByteOrder.LITTLE_ENDIAN));
+ assertArrayEquals(new byte[]{(byte) 0xA8, 0x2}, Util.Byte.shiftLeft(new byte[]{(byte) 0xAA, 0}, 2, ByteOrder.LITTLE_ENDIAN));
+ assertArrayEquals(new byte[]{(byte) 0x50, 0x5}, Util.Byte.shiftLeft(new byte[]{(byte) 0xAA, 0}, 3, ByteOrder.LITTLE_ENDIAN));
+ assertArrayEquals(new byte[]{(byte) 0xA0, 0xA}, Util.Byte.shiftLeft(new byte[]{(byte) 0xAA, 0}, 4, ByteOrder.LITTLE_ENDIAN));
+ assertArrayEquals(new byte[]{(byte) 0x40, 0x15}, Util.Byte.shiftLeft(new byte[]{(byte) 0xAA, 0}, 5, ByteOrder.LITTLE_ENDIAN));
+ assertArrayEquals(new byte[]{(byte) 0x80, 0x2A}, Util.Byte.shiftLeft(new byte[]{(byte) 0xAA, 0}, 6, ByteOrder.LITTLE_ENDIAN));
+ assertArrayEquals(new byte[]{(byte) 0x00, 0x55}, Util.Byte.shiftLeft(new byte[]{(byte) 0xAA, 0}, 7, ByteOrder.LITTLE_ENDIAN));
+ assertArrayEquals(new byte[]{(byte) 0, (byte) 0xAA}, Util.Byte.shiftLeft(new byte[]{(byte) 0xAA, 0}, 8, ByteOrder.LITTLE_ENDIAN));
+ assertArrayEquals(new byte[]{0, 0, 0, 0x40}, Util.Byte.shiftLeft(new byte[]{1, 0, 0, 0}, 30, ByteOrder.LITTLE_ENDIAN));
+
}
@Test
@@ -187,7 +201,7 @@ public void testLeftShiftAgainstRefImpl() {
Bytes rnd = Bytes.random(4 + new Random().nextInt(14));
byte[] expected = Bytes.from(new BigInteger(rnd.array()).shiftLeft(shift).toByteArray()).resize(rnd.length(), BytesTransformer.ResizeTransformer.Mode.RESIZE_KEEP_FROM_MAX_LENGTH).array();
- byte[] actual = Bytes.from(Util.Byte.shiftLeft(rnd.copy().array(), shift)).resize(rnd.length(), BytesTransformer.ResizeTransformer.Mode.RESIZE_KEEP_FROM_MAX_LENGTH).array();
+ byte[] actual = Bytes.from(Util.Byte.shiftLeft(rnd.copy().array(), shift, ByteOrder.BIG_ENDIAN)).resize(rnd.length(), BytesTransformer.ResizeTransformer.Mode.RESIZE_KEEP_FROM_MAX_LENGTH).array();
System.out.println("Original \t" + rnd.encodeBinary() + " << " + shift);
System.out.println("Expected \t" + Bytes.wrap(expected).encodeBinary());
@@ -202,18 +216,23 @@ public void testLeftShiftAgainstRefImpl() {
public void testRightShift() {
byte[] test = new byte[]{0, 0, 16, 0};
assertEquals(0b01111110, 0b11111101 >>> 1);
- assertArrayEquals(new byte[]{0b00101101, (byte) 0b01111110}, Util.Byte.shiftRight(new byte[]{0b01011010, (byte) 0b11111101}, 1));
- assertArrayEquals(new byte[]{0, -128, -128, -128}, Util.Byte.shiftRight(new byte[]{1, 1, 1, 1}, 1));
- assertArrayEquals(new byte[]{0, -128, 66, 0}, Util.Byte.shiftRight(new byte[]{2, 1, 8, 2}, 2));
+ assertArrayEquals(new byte[]{0b00101101, (byte) 0b01111110}, Util.Byte.shiftRight(new byte[]{0b01011010, (byte) 0b11111101}, 1, ByteOrder.BIG_ENDIAN));
+ assertArrayEquals(new byte[]{0, -128, -128, -128}, Util.Byte.shiftRight(new byte[]{1, 1, 1, 1}, 1, ByteOrder.BIG_ENDIAN));
+ assertArrayEquals(new byte[]{0, -128, 66, 0}, Util.Byte.shiftRight(new byte[]{2, 1, 8, 2}, 2, ByteOrder.BIG_ENDIAN));
assertArrayEquals(new byte[]{0, -128, 66, 0}, new BigInteger(new byte[]{2, 1, 8, 2}).shiftRight(2).toByteArray());
- assertArrayEquals(new byte[]{0, 0, 0, -128}, Util.Byte.shiftRight(Bytes.from(test).array(), 5));
- assertArrayEquals(new byte[]{0, 0, 0, -128}, Util.Byte.shiftRight(new byte[]{0, 0, 1, 0}, 1));
- assertArrayEquals(new byte[]{0, 0, 8, 0}, Util.Byte.shiftRight(Bytes.from(test).array(), 1));
- assertArrayEquals(new byte[]{0, 0, 4, 0}, Util.Byte.shiftRight(Bytes.from(test).array(), 2));
- assertArrayEquals(new byte[]{0, 0, 2, 0}, Util.Byte.shiftRight(Bytes.from(test).array(), 3));
- assertArrayEquals(new byte[]{0, 0, 1, 0}, Util.Byte.shiftRight(Bytes.from(test).array(), 4));
+ assertArrayEquals(new byte[]{0, 0, 0, -128}, Util.Byte.shiftRight(Bytes.from(test).array(), 5, ByteOrder.BIG_ENDIAN));
+ assertArrayEquals(new byte[]{0, 0, 0, -128}, Util.Byte.shiftRight(new byte[]{0, 0, 1, 0}, 1, ByteOrder.BIG_ENDIAN));
+ assertArrayEquals(new byte[]{0, 0, 8, 0}, Util.Byte.shiftRight(Bytes.from(test).array(), 1, ByteOrder.BIG_ENDIAN));
+ assertArrayEquals(new byte[]{0, 0, 4, 0}, Util.Byte.shiftRight(Bytes.from(test).array(), 2, ByteOrder.BIG_ENDIAN));
+ assertArrayEquals(new byte[]{0, 0, 2, 0}, Util.Byte.shiftRight(Bytes.from(test).array(), 3, ByteOrder.BIG_ENDIAN));
+ assertArrayEquals(new byte[]{0, 0, 1, 0}, Util.Byte.shiftRight(Bytes.from(test).array(), 4, ByteOrder.BIG_ENDIAN));
+
+ assertSame(test, Util.Byte.shiftRight(test, 1, ByteOrder.BIG_ENDIAN));
- assertSame(test, Util.Byte.shiftRight(test, 1));
+ assertArrayEquals(new byte[]{0, 0}, Util.Byte.shiftRight(new byte[]{1, 0}, 1, ByteOrder.LITTLE_ENDIAN));
+ assertArrayEquals(new byte[]{(byte) 0x80, 0}, Util.Byte.shiftRight(new byte[]{0, 0x02}, 2, ByteOrder.LITTLE_ENDIAN));
+ assertArrayEquals(new byte[]{(byte) 0x80, 0, 0, 0}, Util.Byte.shiftRight(new byte[]{0, 0, 0, 1}, 17, ByteOrder.LITTLE_ENDIAN));
+ assertArrayEquals(new byte[]{(byte) 1, 0, 0, 0}, Util.Byte.shiftRight(new byte[]{0, 0, 0, (byte) 0x80}, 31, ByteOrder.LITTLE_ENDIAN));
}
@Test
@@ -223,7 +242,7 @@ public void testRightShiftAgainstRefImpl() {
Bytes rnd = Bytes.random(4 + new Random().nextInt(12));
if (!rnd.bitAt(rnd.lengthBit() - 1)) { //only unsigned
byte[] expected = Bytes.from(new BigInteger(rnd.array()).shiftRight(shift).toByteArray()).resize(rnd.length(), BytesTransformer.ResizeTransformer.Mode.RESIZE_KEEP_FROM_MAX_LENGTH).array();
- byte[] actual = Bytes.from(Util.Byte.shiftRight(rnd.copy().array(), shift)).resize(rnd.length(), BytesTransformer.ResizeTransformer.Mode.RESIZE_KEEP_FROM_MAX_LENGTH).array();
+ byte[] actual = Bytes.from(Util.Byte.shiftRight(rnd.copy().array(), shift, ByteOrder.BIG_ENDIAN)).resize(rnd.length(), BytesTransformer.ResizeTransformer.Mode.RESIZE_KEEP_FROM_MAX_LENGTH).array();
// System.out.println("Original \t" + rnd.encodeBinary() + " >> " + shift);
// System.out.println("Expected \t" + Bytes.wrap(expected).encodeBinary());
From e8eb89e252cd68bc982ffe5d4efd221eab556443 Mon Sep 17 00:00:00 2001
From: pfavre
Date: Sat, 27 Feb 2021 23:04:11 +0100
Subject: [PATCH 04/39] Update CHANGELOG
---
CHANGELOG | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/CHANGELOG b/CHANGELOG
index 10b2ffc..d211c99 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,5 +1,10 @@
# Releases
+## v1.5.0
+
+* fix `leftShift()` and `rightShift()` to respect byte order (thx @gfpeltier)
+* fix `bitAt()` to respect byte order (thx @gfpeltier)
+
## v1.4.0
* add `from()` constructor from `float[]`
From 8a74c6b87f987ac11daf59de54ce2ecb336c3427 Mon Sep 17 00:00:00 2001
From: pfavre
Date: Sat, 27 Feb 2021 23:23:44 +0100
Subject: [PATCH 05/39] Bump version
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index 0a27b42..f2de9ac 100644
--- a/pom.xml
+++ b/pom.xml
@@ -11,7 +11,7 @@
bytes
- 1.4.0
+ 1.5.0
bundle
Bytes Utility Library
From 000e37c553a4b788854c1f19032a220d688ef6b3 Mon Sep 17 00:00:00 2001
From: michielj-webiq <80327153+michielj-webiq@users.noreply.github.com>
Date: Tue, 9 Mar 2021 12:43:12 +0100
Subject: [PATCH 06/39] use buffer instead of byteBuffer in README
The method to turn Bytes into a ByteBuffer is called `buffer`, not `byteBuffer`
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index fb4a105..b7ac77f 100644
--- a/README.md
+++ b/README.md
@@ -498,7 +498,7 @@ Conversion to [`InputStream`](https://docs.oracle.com/javase/7/docs/api/java/io/
```java
Bytes.wrap(array).inputStream();
-Bytes.wrap(array).byteBuffer();
+Bytes.wrap(array).buffer();
```
If you just want a duplicated instance, sharing the same array:
From f3a0c68459c4b84a36ef72810e38a9f2a6dd5d74 Mon Sep 17 00:00:00 2001
From: Herman Lyakhovich <53296879+hlyakhovich@users.noreply.github.com>
Date: Thu, 11 Mar 2021 16:54:56 +0100
Subject: [PATCH 07/39] Add toShortArray
---
src/main/java/at/favre/lib/bytes/Bytes.java | 19 +++++++++++
src/main/java/at/favre/lib/bytes/Util.java | 28 +++++++++++++++
.../bytes/BytesToConvertOtherTypesTest.java | 34 +++++++++++++++++++
.../at/favre/lib/bytes/UtilConverterTest.java | 16 +++++++++
4 files changed, 97 insertions(+)
diff --git a/src/main/java/at/favre/lib/bytes/Bytes.java b/src/main/java/at/favre/lib/bytes/Bytes.java
index f1ab738..42541e6 100644
--- a/src/main/java/at/favre/lib/bytes/Bytes.java
+++ b/src/main/java/at/favre/lib/bytes/Bytes.java
@@ -2044,6 +2044,25 @@ public double[] toDoubleArray() {
return Util.Converter.toDoubleArray(internalArray(), byteOrder);
}
+ /**
+ * Converts the internal byte array to a short array, that is, every 2 bytes will be packed into a single short.
+ *
+ * E.g. 2 bytes will be packed to a length 1 short array:
+ *
+ * [b1, b2] = [short1]
+ *
+ *
+ * This conversion respects the internal byte order. Will only work if all bytes can be directly mapped to short,
+ * which means the byte array length must be dividable by 2 without rest.
+ *
+ * @return new short[] instance representing this byte array
+ * @throws IllegalArgumentException if internal byte length mod 2 != 0
+ */
+ public short[] toShortArray() {
+ Util.Validation.checkModLength(length(), 2, "creating a short array");
+ return Util.Converter.toShortArray(internalArray(), byteOrder);
+ }
+
/**
* Decodes the internal byte array to UTF-8 char array.
* This implementation will not internally create a {@link String}.
diff --git a/src/main/java/at/favre/lib/bytes/Util.java b/src/main/java/at/favre/lib/bytes/Util.java
index ee494fc..da50ff0 100644
--- a/src/main/java/at/favre/lib/bytes/Util.java
+++ b/src/main/java/at/favre/lib/bytes/Util.java
@@ -860,6 +860,34 @@ static double[] toDoubleArray(byte[] bytes, ByteOrder byteOrder) {
return array;
}
+
+ /**
+ * Converts the byte array to a short array. This will spread 2 bytes into a single short:
+ *
+ *
+ * [b1, b2] = [short1]
+ *
+ *
+ *
+ * Analysis
+ *
+ * - Time Complexity:
O(n)
+ * - Space Complexity:
O(n)
+ * - Alters Parameters:
false
+ *
+ *
+ *
+ * @param bytes to convert to short array, must be % 2 == 0 to work correctly
+ * @param byteOrder of the byte array
+ * @return short array
+ */
+ static short[] toShortArray(byte[] bytes, ByteOrder byteOrder) {
+ ShortBuffer buffer = ByteBuffer.wrap(bytes).order(byteOrder).asShortBuffer();
+ short[] array = new short[buffer.remaining()];
+ buffer.get(array);
+ return array;
+ }
+
/**
* Convert UUID to a newly generated 16 byte long array representation. Puts the 8 byte most significant bits and
* 8 byte least significant bits into an byte array.
diff --git a/src/test/java/at/favre/lib/bytes/BytesToConvertOtherTypesTest.java b/src/test/java/at/favre/lib/bytes/BytesToConvertOtherTypesTest.java
index 4c1ff0f..efa1559 100644
--- a/src/test/java/at/favre/lib/bytes/BytesToConvertOtherTypesTest.java
+++ b/src/test/java/at/favre/lib/bytes/BytesToConvertOtherTypesTest.java
@@ -406,4 +406,38 @@ public void testToDoubleArrayLittleEndian() {
1, 1, 1, 0, 0, 0, 1, 0,
1, 0, 0, 0, 0, 0, 0, 0}, ByteOrder.LITTLE_ENDIAN).toDoubleArray(), 0.01);
}
+
+ @Test
+ public void testToShortArrayEmpty() {
+ assertArrayEquals(new short[0], Bytes.empty().toShortArray());
+ }
+
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testToShortArrayNotMod2Was5Byte() {
+ Bytes.wrap(new byte[]{0, 0, 0, 0, 1}).toShortArray();
+ }
+
+ @Test
+ public void testToShortArray() {
+ assertArrayEquals(new short[]{1}, Bytes.wrap(new byte[]{0, 1}).toShortArray());
+ assertArrayEquals(new short[]{257}, Bytes.wrap(new byte[]{1, 1}).toShortArray());
+ assertArrayEquals(new short[]{32_767}, Bytes.wrap(new byte[]{127, -1}).toShortArray());
+
+ assertArrayEquals(new short[]{1, 1}, Bytes.wrap(new byte[]{0, 1, 0, 1}).toShortArray());
+ assertArrayEquals(new short[]{257, 1}, Bytes.wrap(new byte[]{1, 1, 0, 1}).toShortArray());
+ assertArrayEquals(new short[]{257, 32_767, 1}, Bytes.wrap(new byte[]{1, 1, 127, -1, 0, 1}).toShortArray());
+ }
+
+ @Test
+ public void testToShortArrayLittleEndian() {
+ assertArrayEquals(new short[]{1}, Bytes.wrap(new byte[]{1, 0}, ByteOrder.LITTLE_ENDIAN).toShortArray());
+ assertArrayEquals(new short[]{257}, Bytes.wrap(new byte[]{1, 1}, ByteOrder.LITTLE_ENDIAN).toShortArray());
+ assertArrayEquals(new short[]{32_767}, Bytes.wrap(new byte[]{-1, 127}, ByteOrder.LITTLE_ENDIAN).toShortArray());
+
+ assertArrayEquals(new short[]{1, 1}, Bytes.wrap(new byte[]{1, 0, 1, 0}, ByteOrder.LITTLE_ENDIAN).toShortArray());
+ assertArrayEquals(new short[]{257, 1}, Bytes.wrap(new byte[]{1, 1, 1, 0}, ByteOrder.LITTLE_ENDIAN).toShortArray());
+ assertArrayEquals(new short[]{257, 32_767, 1}, Bytes.wrap(new byte[]{1, 1, -1, 127, 1, 0}, ByteOrder.LITTLE_ENDIAN).toShortArray());
+ }
+
}
diff --git a/src/test/java/at/favre/lib/bytes/UtilConverterTest.java b/src/test/java/at/favre/lib/bytes/UtilConverterTest.java
index 8aa717f..3ac6f7b 100644
--- a/src/test/java/at/favre/lib/bytes/UtilConverterTest.java
+++ b/src/test/java/at/favre/lib/bytes/UtilConverterTest.java
@@ -193,4 +193,20 @@ public void testToDoubleArray() {
assertArrayEquals(new double[0], Util.Converter.toDoubleArray(new byte[0], ByteOrder.LITTLE_ENDIAN), 0.01);
assertArrayEquals(new double[0], Util.Converter.toDoubleArray(new byte[0], ByteOrder.BIG_ENDIAN), 0.01);
}
+
+ @Test
+ public void testToShortArray() {
+ assertArrayEquals(new short[]{1}, Util.Converter.toShortArray(new byte[]{0, 1}, ByteOrder.BIG_ENDIAN));
+ assertArrayEquals(new short[]{257}, Util.Converter.toShortArray(new byte[]{1, 1}, ByteOrder.BIG_ENDIAN));
+ assertArrayEquals(new short[]{32_767}, Util.Converter.toShortArray(new byte[]{127, -1}, ByteOrder.BIG_ENDIAN));
+ assertArrayEquals(new short[]{257, 32_767, 1}, Util.Converter.toShortArray(new byte[]{1, 1, 127, -1, 0, 1}, ByteOrder.BIG_ENDIAN));
+
+ assertArrayEquals(new short[]{1}, Util.Converter.toShortArray(new byte[]{1, 0}, ByteOrder.LITTLE_ENDIAN));
+ assertArrayEquals(new short[]{257}, Util.Converter.toShortArray(new byte[]{1, 1}, ByteOrder.LITTLE_ENDIAN));
+ assertArrayEquals(new short[]{32_767}, Util.Converter.toShortArray(new byte[]{-1, 127}, ByteOrder.LITTLE_ENDIAN));
+ assertArrayEquals(new short[]{257, 32_767, 1}, Util.Converter.toShortArray(new byte[]{1, 1, -1, 127, 1, 0}, ByteOrder.LITTLE_ENDIAN));
+
+ assertArrayEquals(new short[0], Util.Converter.toShortArray(new byte[0], ByteOrder.LITTLE_ENDIAN));
+ assertArrayEquals(new short[0], Util.Converter.toShortArray(new byte[0], ByteOrder.BIG_ENDIAN));
+ }
}
From c0f45adc2ca696c0317edab2cf3eed89adaf17bc Mon Sep 17 00:00:00 2001
From: Herman Lyakhovich <53296879+hlyakhovich@users.noreply.github.com>
Date: Wed, 17 Mar 2021 19:29:22 +0100
Subject: [PATCH 08/39] Overload from() with short array
---
src/main/java/at/favre/lib/bytes/Bytes.java | 12 +++++++-
src/main/java/at/favre/lib/bytes/Util.java | 28 ++++++++++++++++++-
.../lib/bytes/BytesConstructorTests.java | 13 +++++++++
3 files changed, 51 insertions(+), 2 deletions(-)
diff --git a/src/main/java/at/favre/lib/bytes/Bytes.java b/src/main/java/at/favre/lib/bytes/Bytes.java
index 42541e6..3797292 100644
--- a/src/main/java/at/favre/lib/bytes/Bytes.java
+++ b/src/main/java/at/favre/lib/bytes/Bytes.java
@@ -296,6 +296,16 @@ public static Bytes from(short short2Byte) {
return wrap(ByteBuffer.allocate(2).putShort(short2Byte).array());
}
+ /**
+ * Creates a new instance from given 2 byte short array.
+ *
+ * @param shortArray to create from
+ * @return new instance
+ */
+ public static Bytes from(short... shortArray) {
+ return wrap(Util.Converter.toByteArray(Objects.requireNonNull(shortArray, "must provide at least a single short")));
+ }
+
/**
* Creates a new instance from given 4 byte integer.
*
@@ -1492,7 +1502,7 @@ public Bytes duplicate() {
/**
* Set the byte order or endianness of this instance. Default in Java is {@link ByteOrder#BIG_ENDIAN}.
*
- * This option is important for all encoding and conversation methods.
+ * This option is important for all encoding and conversion methods.
*
* @param byteOrder new byteOrder
* @return a new instance with the same underlying array and new order, or "this" if order is the same
diff --git a/src/main/java/at/favre/lib/bytes/Util.java b/src/main/java/at/favre/lib/bytes/Util.java
index da50ff0..710c4d3 100644
--- a/src/main/java/at/favre/lib/bytes/Util.java
+++ b/src/main/java/at/favre/lib/bytes/Util.java
@@ -567,6 +567,33 @@ static byte[] toPrimitiveArray(java.lang.Byte[] objectArray) {
return primitivesArray;
}
+ /**
+ * Creates a byte array from given short array.
+ * The resulting byte array will have length shortArray * 2.
+ *
+ *
+ * Analysis
+ *
+ * - Time Complexity:
O(n)
+ * - Space Complexity:
O(n)
+ * - Alters Parameters:
false
+ *
+ *
+ *
+ * @param shortArray to convert
+ * @return resulting byte array
+ */
+ static byte[] toByteArray(short[] shortArray) {
+ byte[] primitivesArray = new byte[shortArray.length * 2];
+ ByteBuffer buffer = ByteBuffer.allocate(2);
+ for (int i = 0; i < shortArray.length; i++) {
+ buffer.clear();
+ byte[] shortBytes = buffer.putShort(shortArray[i]).array();
+ System.arraycopy(shortBytes, 0, primitivesArray, (i * 2), shortBytes.length);
+ }
+ return primitivesArray;
+ }
+
/**
* Creates a byte array from given int array.
* The resulting byte array will have length intArray * 4.
@@ -860,7 +887,6 @@ static double[] toDoubleArray(byte[] bytes, ByteOrder byteOrder) {
return array;
}
-
/**
* Converts the byte array to a short array. This will spread 2 bytes into a single short:
*
diff --git a/src/test/java/at/favre/lib/bytes/BytesConstructorTests.java b/src/test/java/at/favre/lib/bytes/BytesConstructorTests.java
index 612dba3..5cf5058 100644
--- a/src/test/java/at/favre/lib/bytes/BytesConstructorTests.java
+++ b/src/test/java/at/favre/lib/bytes/BytesConstructorTests.java
@@ -179,6 +179,19 @@ public void fromShort() {
assertEquals(test, Bytes.from(test).toShort());
}
+ @Test(expected = NullPointerException.class)
+ public void fromShortArray_empty_shouldThrow() {
+ Bytes.from((short[]) null);
+ }
+
+ @Test
+ public void fromShortArray() {
+ assertArrayEquals(new byte[]{0, 1, 0, 2}, Bytes.from((short) 1, (short) 2).array());
+ assertArrayEquals(Bytes.from(Bytes.from((short) 32767), Bytes.from((short) 6761), Bytes.from((short) -8517)).array(), Bytes.from((short) 32767, (short) 6761, (short) -8517).array());
+ assertArrayEquals(Bytes.from(Bytes.from((short) 1678), Bytes.from((short) -223), Bytes.from((short) 11114)).array(), Bytes.from((short) 1678, (short) -223, (short) 11114).array());
+ assertArrayEquals(new byte[]{114, -123, 35, 53, 0, 0, 56, -70}, Bytes.from((short) 29317, (short) 9013, (short) 0, (short) 14522).array());
+ }
+
@Test
public void fromInt() {
int test = 722837193;
From c4b411acaebc747ed3e6ea1adc9e92404633223c Mon Sep 17 00:00:00 2001
From: Herman Lyakhovich <53296879+hlyakhovich@users.noreply.github.com>
Date: Wed, 17 Mar 2021 19:42:29 +0100
Subject: [PATCH 09/39] Correct Checkstyle clause in docs
---
CONTRIBUTING.md | 4 ++--
README.md | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 4a0c2d5..7404d32 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -2,13 +2,13 @@
We ❤ pull requests from everyone.
-If possible proof features and bug fixes with unit tests.
+If possible to proof features and bug fixes with unit tests.
This repo validates against checkstyle (import the xml found in the root to your IDE if possible)
To run the tests (and checkstyle):
```shell
-mvn test
+mvn verify
```
Tests are automatically run against branches and pull requests
diff --git a/README.md b/README.md
index b7ac77f..96e0a0b 100644
--- a/README.md
+++ b/README.md
@@ -694,7 +694,7 @@ Use the Maven wrapper to create a jar including all dependencies
### Checkstyle Config File
This project uses my [`common-parent`](https://github.com/patrickfav/mvn-common-parent) which centralized a lot of
-the plugin versions aswell as providing the checkstyle config rules. Specifically they are maintained in [`checkstyle-config`](https://github.com/patrickfav/checkstyle-config). Locally the files will be copied after you `mvnw install` into your `target` folder and is called
+the plugin versions as well as providing the checkstyle config rules. Specifically they are maintained in [`checkstyle-config`](https://github.com/patrickfav/checkstyle-config). Locally the files will be copied after you `mvnw install` into your `target` folder and is called
`target/checkstyle-checker.xml`. So if you use a plugin for your IDE, use this file as your local configuration.
## Tech Stack
From 8796a66e3ab1e163f7d660fddfd558f147013bc4 Mon Sep 17 00:00:00 2001
From: airsquared <36649395+airsquared@users.noreply.github.com>
Date: Mon, 29 Mar 2021 22:38:40 -0700
Subject: [PATCH 10/39] Add an automatic module name to support the JPMS
---
pom.xml | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/pom.xml b/pom.xml
index f2de9ac..fe145e2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -92,6 +92,16 @@
net.nicoulaj.maven.plugins
checksum-maven-plugin
+
+ maven-jar-plugin
+
+
+
+ at.favre.lib.bytes
+
+
+
+
From 966feae09b0b5d0b02467e6824c5d037ca18ea39 Mon Sep 17 00:00:00 2001
From: Herman Lyakhovich <53296879+hlyakhovich@users.noreply.github.com>
Date: Sat, 3 Sep 2022 15:21:34 +0200
Subject: [PATCH 11/39] Add toIndex versions for indexOf()
---
src/main/java/at/favre/lib/bytes/Bytes.java | 33 +++++++++++++++++++
.../at/favre/lib/bytes/BytesMiscTest.java | 19 +++++++++++
2 files changed, 52 insertions(+)
diff --git a/src/main/java/at/favre/lib/bytes/Bytes.java b/src/main/java/at/favre/lib/bytes/Bytes.java
index 3797292..c2b5b20 100644
--- a/src/main/java/at/favre/lib/bytes/Bytes.java
+++ b/src/main/java/at/favre/lib/bytes/Bytes.java
@@ -1277,6 +1277,20 @@ public int indexOf(byte target, int fromIndex) {
return indexOf(new byte[]{target}, fromIndex);
}
+ /**
+ * Returns the index of the first appearance of the value {@code target} in
+ * {@code array} from given start index 'fromIndex' to given end index 'toIndex'.
+ *
+ * @param target a primitive {@code byte} value
+ * @param fromIndex search from this index
+ * @param toIndex search to this index
+ * @return the least index {@code i} for which {@code array[i] == target}, or
+ * {@code -1} if no such index exists or fromIndex is gt target length.
+ */
+ public int indexOf(byte target, int fromIndex, int toIndex) {
+ return indexOf(new byte[]{target}, fromIndex, toIndex);
+ }
+
/**
* Returns the start position of the first occurrence of the specified {@code
* target} within {@code array}, or {@code -1} if there is no such occurrence.
@@ -1311,6 +1325,25 @@ public int indexOf(byte[] subArray, int fromIndex) {
return Util.Byte.indexOf(internalArray(), subArray, fromIndex, length());
}
+ /**
+ * Returns the start position of the first occurrence of the specified {@code
+ * target} within {@code array} from given start index 'fromIndex' to given end
+ * index 'toIndex', or {@code -1} if there is no such occurrence.
+ *
+ * More formally, returns the lowest index {@code i} such that {@code
+ * java.util.Arrays.copyOfRange(array, i, i + target.length)} contains exactly
+ * the same elements as {@code target}.
+ *
+ * @param subArray the array to search for as a sub-sequence of {@code array}
+ * @param fromIndex search from this index
+ * @param toIndex search to this index
+ * @return the least index {@code i} for which {@code array[i] == target}, or
+ * {@code -1} if no such index exists.
+ */
+ public int indexOf(byte[] subArray, int fromIndex, int toIndex) {
+ return Util.Byte.indexOf(internalArray(), subArray, fromIndex, toIndex);
+ }
+
/**
* Checks if the given sub array is equal to the start of given array. That is, sub array must be gt or eq
* to the length of the internal array and internal[i] == subArray[i] for i=0..subArray.length-1
diff --git a/src/test/java/at/favre/lib/bytes/BytesMiscTest.java b/src/test/java/at/favre/lib/bytes/BytesMiscTest.java
index ed832bb..a57398d 100644
--- a/src/test/java/at/favre/lib/bytes/BytesMiscTest.java
+++ b/src/test/java/at/favre/lib/bytes/BytesMiscTest.java
@@ -188,6 +188,15 @@ public void indexOfByteFromIndex() {
assertEquals(10, Bytes.from(example_bytes_sixteen).indexOf((byte) 0xFD, 5));
}
+ @Test
+ public void indexOfByteFromIndexToIndex() {
+ assertEquals(4, Bytes.from(example_bytes_seven).indexOf((byte) 0x1E, 0, 7));
+ assertEquals(4, Bytes.from(example_bytes_seven).indexOf((byte) 0x1E, 3, 5));
+ assertEquals(-1, Bytes.from(example_bytes_seven).indexOf((byte) 0x1E, 0, 3));
+ assertEquals(-1, Bytes.from(example_bytes_seven).indexOf((byte) 0x1E, 6, 7));
+ assertEquals(-1, Bytes.from(example_bytes_seven).indexOf((byte) 0xCA, 0, 7));
+ }
+
@Test
public void indexOfArray() {
assertEquals(-1, Bytes.allocate(0).indexOf(new byte[]{(byte) 0xFD}));
@@ -204,6 +213,16 @@ public void indexOfArrayFromIndex() {
assertEquals(2, Bytes.from(new byte[]{(byte) 0x8E, (byte) 0xD1, (byte) 0x8E, (byte) 0xD1, 0x12, (byte) 0xAF, (byte) 0x78, 0x09, 0x1E, (byte) 0xD1, (byte) 0xFD, (byte) 0xAA, 0x12}).indexOf(new byte[]{(byte) 0x8E, (byte) 0xD1}, 1));
}
+ @Test
+ public void indexOfArrayFromIndexToIndex() {
+ assertEquals(4, Bytes.from(example_bytes_seven).indexOf(new byte[] { (byte) 0x1E, (byte) 0xAF }, 0, 7));
+ assertEquals(4, Bytes.from(example_bytes_seven).indexOf(new byte[] { (byte) 0x1E, (byte) 0xAF }, 3, 5));
+ assertEquals(4, Bytes.from(example_bytes_seven).indexOf(new byte[] { (byte) 0x1E, (byte) 0xAF, (byte) 0xED }, 4, 5));
+ assertEquals(-1, Bytes.from(example_bytes_seven).indexOf(new byte[] { (byte) 0x1E, (byte) 0xAF }, 0, 3));
+ assertEquals(-1, Bytes.from(example_bytes_seven).indexOf(new byte[] { (byte) 0x1E, (byte) 0xAF }, 6, 7));
+ assertEquals(-1, Bytes.from(example_bytes_seven).indexOf(new byte[] { (byte) 0xCA, (byte) 0xFE }, 0, 7));
+ }
+
@Test
public void startsWidth() {
assertFalse(Bytes.allocate(0).startsWith(new byte[1]));
From 0b6dd028c9fa90a0623580a2766bde0585f060a0 Mon Sep 17 00:00:00 2001
From: Patrick Favre-Bulle
Date: Sat, 11 Feb 2023 18:46:31 +0100
Subject: [PATCH 12/39] Migrate to Github Actions, CodeCov and Maven Central
and update maven wrapper and deps
---
.github/workflows/build_deploy.yml | 64 +++++++++++++
.mvn/wrapper/MavenWrapperDownloader.java | 117 -----------------------
.mvn/wrapper/maven-wrapper.jar | Bin 50710 -> 59925 bytes
.mvn/wrapper/maven-wrapper.properties | 20 +++-
.travis.yml | 51 ----------
README.md | 4 +-
mvnw | 99 ++++++++-----------
mvnw.cmd | 39 ++++----
pom.xml | 32 ++++---
secrets.tar.enc | Bin 6672 -> 0 bytes
10 files changed, 163 insertions(+), 263 deletions(-)
create mode 100644 .github/workflows/build_deploy.yml
delete mode 100644 .mvn/wrapper/MavenWrapperDownloader.java
delete mode 100644 .travis.yml
delete mode 100644 secrets.tar.enc
diff --git a/.github/workflows/build_deploy.yml b/.github/workflows/build_deploy.yml
new file mode 100644
index 0000000..3fd75e4
--- /dev/null
+++ b/.github/workflows/build_deploy.yml
@@ -0,0 +1,64 @@
+name: Build and Deploy with Maven
+
+on:
+ push:
+ branches:
+ - main
+ tags:
+ - '*' # Trigger on all tags
+ pull_request: { }
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout Code
+ uses: actions/checkout@v3
+ - name: Set up JDK 8
+ uses: actions/setup-java@v3
+ with:
+ java-version: '8'
+ distribution: 'adopt'
+ cache: 'maven'
+ - name: Build with Maven
+ run: ./mvnw -B clean package checkstyle:checkstyle jacoco:report -DcommonConfig.jarSign.skip=true
+ - name: Upload coverage reports to CodeCov
+ uses: codecov/codecov-action@v3
+
+ deploy:
+ needs: build
+ if: startsWith(github.ref, 'refs/tags/')
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v3
+ - name: Retrieve Keystore from secrets
+ env:
+ KEYSTORE_BASE64: ${{ secrets.KEYSTORE_BASE64 }}
+ run: |
+ echo $KEYSTORE_BASE64 | base64 --decode > keystore.jks
+ - name: Set up Maven Central Repository
+ uses: actions/setup-java@v3
+ with:
+ java-version: '8'
+ distribution: 'adopt'
+ cache: 'maven'
+ server-id: ossrh
+ server-username: MAVEN_USERNAME
+ server-password: MAVEN_PASSWORD
+ - name: Publish package
+ run: mvn -B deploy -DskipTests
+ env:
+ OPENSOURCE_PROJECTS_KS_PW: ${{ secrets.KEYSTORE_PASSWORD }}
+ OPENSOURCE_PROJECTS_KEY_PW: ${{ secrets.KEYSTORE_KEY_PASSWORD }}
+ MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }}
+ MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }}
+ - name: Create and upload Github Release
+ uses: xresloader/upload-to-github-release@v1
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ file: "target/*.jar;target/*.sha256;target/checksum-sha256.txt"
+ tags: true
+ draft: false
diff --git a/.mvn/wrapper/MavenWrapperDownloader.java b/.mvn/wrapper/MavenWrapperDownloader.java
deleted file mode 100644
index b901097..0000000
--- a/.mvn/wrapper/MavenWrapperDownloader.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright 2007-present the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import java.net.*;
-import java.io.*;
-import java.nio.channels.*;
-import java.util.Properties;
-
-public class MavenWrapperDownloader {
-
- private static final String WRAPPER_VERSION = "0.5.6";
- /**
- * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
- */
- private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
- + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
-
- /**
- * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
- * use instead of the default one.
- */
- private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
- ".mvn/wrapper/maven-wrapper.properties";
-
- /**
- * Path where the maven-wrapper.jar will be saved to.
- */
- private static final String MAVEN_WRAPPER_JAR_PATH =
- ".mvn/wrapper/maven-wrapper.jar";
-
- /**
- * Name of the property which should be used to override the default download url for the wrapper.
- */
- private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
-
- public static void main(String args[]) {
- System.out.println("- Downloader started");
- File baseDirectory = new File(args[0]);
- System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
-
- // If the maven-wrapper.properties exists, read it and check if it contains a custom
- // wrapperUrl parameter.
- File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
- String url = DEFAULT_DOWNLOAD_URL;
- if(mavenWrapperPropertyFile.exists()) {
- FileInputStream mavenWrapperPropertyFileInputStream = null;
- try {
- mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
- Properties mavenWrapperProperties = new Properties();
- mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
- url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
- } catch (IOException e) {
- System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
- } finally {
- try {
- if(mavenWrapperPropertyFileInputStream != null) {
- mavenWrapperPropertyFileInputStream.close();
- }
- } catch (IOException e) {
- // Ignore ...
- }
- }
- }
- System.out.println("- Downloading from: " + url);
-
- File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
- if(!outputFile.getParentFile().exists()) {
- if(!outputFile.getParentFile().mkdirs()) {
- System.out.println(
- "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
- }
- }
- System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
- try {
- downloadFileFromURL(url, outputFile);
- System.out.println("Done");
- System.exit(0);
- } catch (Throwable e) {
- System.out.println("- Error downloading");
- e.printStackTrace();
- System.exit(1);
- }
- }
-
- private static void downloadFileFromURL(String urlString, File destination) throws Exception {
- if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
- String username = System.getenv("MVNW_USERNAME");
- char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
- Authenticator.setDefault(new Authenticator() {
- @Override
- protected PasswordAuthentication getPasswordAuthentication() {
- return new PasswordAuthentication(username, password);
- }
- });
- }
- URL website = new URL(urlString);
- ReadableByteChannel rbc;
- rbc = Channels.newChannel(website.openStream());
- FileOutputStream fos = new FileOutputStream(destination);
- fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
- fos.close();
- rbc.close();
- }
-
-}
diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar
index 2cc7d4a55c0cd0092912bf49ae38b3a9e3fd0054..bf82ff01c6cdae4a1bb754a6e062954d77ac5c11 100644
GIT binary patch
literal 59925
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