You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2025/01/05 14:14:44 UTC
(commons-lang) branch master updated: Add ArrayUtils.startsWith()
This is an automated email from the ASF dual-hosted git repository.
ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-lang.git
The following commit(s) were added to refs/heads/master by this push:
new ef3d5d93a Add ArrayUtils.startsWith()
ef3d5d93a is described below
commit ef3d5d93a30ba3934b8f02b88c048451aad8e87a
Author: Gary D. Gregory <ga...@gmail.com>
AuthorDate: Sun Jan 5 09:14:36 2025 -0500
Add ArrayUtils.startsWith()
---
src/changes/changes.xml | 1 +
.../java/org/apache/commons/lang3/ArrayUtils.java | 35 ++++++++++++++++++++++
.../org/apache/commons/lang3/ArrayUtilsTest.java | 29 ++++++++++++++++++
3 files changed, 65 insertions(+)
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index d268afaa4..463246456 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -87,6 +87,7 @@ The <action> type attribute can be add,update,fix,remove.
<action type="add" dev="ggregory" due-to="Gary Gregory">Add SystemUtils.IS_OS_MAC_OSX_SEQUOIA.</action>
<action type="add" dev="ggregory" due-to="Gary Gregory">Add BasicThreadFactory.builder() and deprecate BasicThreadFactory.Builder().</action>
<action type="add" dev="ggregory" due-to="Gary Gregory">Add BasicThreadFactory.daemon().</action>
+ <action type="add" dev="ggregory" due-to="Gary Gregory">Add ArrayUtils.startsWith.</action>
<!-- UPDATE -->
<action type="update" dev="ggregory" due-to="Gary Gregory, Dependabot">Bump org.apache.commons:commons-parent from 73 to 78 #1267, #1277, #1283, #1288, #1302.</action>
<action type="update" dev="ggregory" due-to="Gary Gregory, Dependabot">[site] Bump org.codehaus.mojo:taglist-maven-plugin from 3.1.0 to 3.2.1 #1300.</action>
diff --git a/src/main/java/org/apache/commons/lang3/ArrayUtils.java b/src/main/java/org/apache/commons/lang3/ArrayUtils.java
index 4545b18d7..76b856035 100644
--- a/src/main/java/org/apache/commons/lang3/ArrayUtils.java
+++ b/src/main/java/org/apache/commons/lang3/ArrayUtils.java
@@ -7842,6 +7842,41 @@ public class ArrayUtils {
}
}
+ /**
+ * Tests whether the given data array starts with an expected array, for example, signature bytes.
+ * <p>
+ * If both arrays are null, the method returns true. The method return false when one array is null and the other not.
+ * </p>
+ *
+ * @param data The data to search, maybe larger than the expected data.
+ * @param expected The expected data to find.
+ * @return whether a match was found.
+ * @since 3.18.0
+ */
+ public static boolean startsWith(final byte[] data, final byte[] expected) {
+ if (data == expected) {
+ return true;
+ }
+ if (data == null || expected == null) {
+ return false;
+ }
+ final int dataLen = data.length;
+ if (expected.length > dataLen) {
+ return false;
+ }
+ if (expected.length == dataLen) {
+ // delegate to Arrays.equals() which has optimizations on Java > 8
+ return Arrays.equals(data, expected);
+ }
+ // Once we are on Java 9+ we can delegate to Arrays here as well (or not).
+ for (int i = 0; i < expected.length; i++) {
+ if (data[i] != expected[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
/**
* Produces a new {@code boolean} array containing the elements
* between the start and end indices.
diff --git a/src/test/java/org/apache/commons/lang3/ArrayUtilsTest.java b/src/test/java/org/apache/commons/lang3/ArrayUtilsTest.java
index aad63f3aa..7256865e7 100644
--- a/src/test/java/org/apache/commons/lang3/ArrayUtilsTest.java
+++ b/src/test/java/org/apache/commons/lang3/ArrayUtilsTest.java
@@ -31,6 +31,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
import java.lang.annotation.ElementType;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
+import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Collections;
@@ -5176,6 +5177,34 @@ public class ArrayUtilsTest extends AbstractLangTest {
}
}
+ @Test
+ public void testStartsWith() {
+ // edge cases
+ assertTrue(ArrayUtils.startsWith(null, null));
+ assertFalse(ArrayUtils.startsWith(ArrayUtils.EMPTY_BYTE_ARRAY, null));
+ assertFalse(ArrayUtils.startsWith(null, ArrayUtils.EMPTY_BYTE_ARRAY));
+ assertTrue(ArrayUtils.startsWith(ArrayUtils.EMPTY_BYTE_ARRAY, ArrayUtils.EMPTY_BYTE_ARRAY));
+ assertTrue(ArrayUtils.startsWith(new byte[0], new byte[0]));
+ // normal cases
+ assertTrue(ArrayUtils.startsWith(new byte[10], new byte[10]));
+ assertTrue(ArrayUtils.startsWith(new byte[10], new byte[9]));
+ assertTrue(ArrayUtils.startsWith(new byte[10], new byte[1]));
+ final byte[] sig = "Signature".getBytes(StandardCharsets.US_ASCII);
+ final byte[] data = new byte[1024];
+ // data is 0
+ assertFalse(ArrayUtils.startsWith(data, sig));
+ // data is 1 short for expected at the end
+ System.arraycopy(sig, 0, data, 0, sig.length - 1);
+ assertFalse(ArrayUtils.startsWith(data, sig));
+ // data is mimatched at the start
+ System.arraycopy(sig, 0, data, 0, sig.length);
+ data[0] = 0;
+ assertFalse(ArrayUtils.startsWith(data, sig));
+ // data is as expected
+ System.arraycopy(sig, 0, data, 0, sig.length);
+ assertTrue(ArrayUtils.startsWith(data, sig));
+ }
+
@Test
public void testSubarrayBoolean() {
final boolean[] nullArray = null;