diff --git a/src/java.base/share/classes/java/util/zip/ZipUtils.java b/src/java.base/share/classes/java/util/zip/ZipUtils.java index 0cbc2e28795d8..227d8272cd426 100644 --- a/src/java.base/share/classes/java/util/zip/ZipUtils.java +++ b/src/java.base/share/classes/java/util/zip/ZipUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,6 +39,7 @@ import jdk.internal.access.JavaNioAccess; import jdk.internal.access.SharedSecrets; import jdk.internal.misc.Unsafe; +import jdk.internal.util.ByteArrayLittleEndian; class ZipUtils { @@ -170,7 +171,7 @@ static LocalDateTime javaEpochToLocalDateTime(long time) { * The bytes are assumed to be in Intel (little-endian) byte order. */ public static final int get16(byte[] b, int off) { - return (b[off] & 0xff) | ((b[off + 1] & 0xff) << 8); + return ByteArrayLittleEndian.getUnsignedShort(b, off); } /** @@ -178,7 +179,7 @@ public static final int get16(byte[] b, int off) { * The bytes are assumed to be in Intel (little-endian) byte order. */ public static final long get32(byte[] b, int off) { - return (get16(b, off) | ((long)get16(b, off+2) << 16)) & 0xffffffffL; + return ByteArrayLittleEndian.getUnsignedInt(b, off); } /** @@ -186,7 +187,7 @@ public static final long get32(byte[] b, int off) { * The bytes are assumed to be in Intel (little-endian) byte order. */ public static final long get64(byte[] b, int off) { - return get32(b, off) | (get32(b, off+4) << 32); + return ByteArrayLittleEndian.getLong(b, off); } /** @@ -195,7 +196,7 @@ public static final long get64(byte[] b, int off) { * */ public static final int get32S(byte[] b, int off) { - return (get16(b, off) | (get16(b, off+2) << 16)); + return ByteArrayLittleEndian.getInt(b, off); } // fields access methods @@ -204,15 +205,15 @@ static final int CH(byte[] b, int n) { } static final int SH(byte[] b, int n) { - return (b[n] & 0xff) | ((b[n + 1] & 0xff) << 8); + return ByteArrayLittleEndian.getUnsignedShort(b, n); } static final long LG(byte[] b, int n) { - return ((SH(b, n)) | (SH(b, n + 2) << 16)) & 0xffffffffL; + return ByteArrayLittleEndian.getUnsignedInt(b, n); } static final long LL(byte[] b, int n) { - return (LG(b, n)) | (LG(b, n + 4) << 32); + return ByteArrayLittleEndian.getLong(b, n); } static final long GETSIG(byte[] b) { diff --git a/src/java.base/share/classes/jdk/internal/util/ByteArray.java b/src/java.base/share/classes/jdk/internal/util/ByteArray.java index 94395df2c344b..78d10cf4ae2db 100644 --- a/src/java.base/share/classes/jdk/internal/util/ByteArray.java +++ b/src/java.base/share/classes/jdk/internal/util/ByteArray.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -132,6 +132,23 @@ public static int getInt(byte[] array, int offset) { return (int) INT.get(array, offset); } + /** + * {@return an {@code unsigned int} from the provided {@code array} at the given {@code offset} + * using big endian order}. + *
+ * There are no access alignment requirements. + * + * @param array to get a value from. + * @param offset where extraction in the array should begin + * @return an {@code long} representing an unsigned int from the array + * @throws IndexOutOfBoundsException if the provided {@code offset} is outside + * the range [0, array.length - 2] + * @see #setUnsignedShort(byte[], int, int) + */ + public static long getUnsignedInt(byte[] array, int offset) { + return Integer.toUnsignedLong((int) INT.get(array, offset)); + } + /** * {@return a {@code float} from the provided {@code array} at the given {@code offset} * using big endian order}. @@ -316,6 +333,23 @@ public static void setInt(byte[] array, int offset, int value) { INT.set(array, offset, value); } + /** + * Sets (writes) the provided {@code value} using big endian order into + * the provided {@code array} beginning at the given {@code offset}. + *
+ * There are no access alignment requirements. + * + * @param array to set (write) a value into + * @param offset where setting (writing) in the array should begin + * @param value value to set in the array + * @throws IndexOutOfBoundsException if the provided {@code offset} is outside + * the range [0, array.length - 4] + * @see #getUnsignedInt(byte[], int) + */ + public static void setUnsignedInt(byte[] array, int offset, long value) { + INT.set(array, offset, (int) value); + } + /** * Sets (writes) the provided {@code value} using big endian order into * the provided {@code array} beginning at the given {@code offset}. diff --git a/src/java.base/share/classes/jdk/internal/util/ByteArrayLittleEndian.java b/src/java.base/share/classes/jdk/internal/util/ByteArrayLittleEndian.java index fcd7ca2b9bfa9..2332cf5875c65 100644 --- a/src/java.base/share/classes/jdk/internal/util/ByteArrayLittleEndian.java +++ b/src/java.base/share/classes/jdk/internal/util/ByteArrayLittleEndian.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -132,6 +132,23 @@ public static int getInt(byte[] array, int offset) { return (int) INT.get(array, offset); } + /** + * {@return an {@code unsigned int} from the provided {@code array} at the given {@code offset} + * using little endian order}. + *
+ * There are no access alignment requirements. + * + * @param array to get a value from. + * @param offset where extraction in the array should begin + * @return an {@code int} representing an unsigned short from the array + * @throws IndexOutOfBoundsException if the provided {@code offset} is outside + * the range [0, array.length - 4] + * @see #setUnsignedInt(byte[], int, long) + */ + public static long getUnsignedInt(byte[] array, int offset) { + return Integer.toUnsignedLong((int) INT.get(array, offset)); + } + /** * {@return a {@code float} from the provided {@code array} at the given {@code offset} * using little endian order}. @@ -316,6 +333,23 @@ public static void setInt(byte[] array, int offset, int value) { INT.set(array, offset, value); } + /** + * Sets (writes) the provided {@code value} using little endian order into + * the provided {@code array} beginning at the given {@code offset}. + *
+ * There are no access alignment requirements.
+ *
+ * @param array to set (write) a value into
+ * @param offset where setting (writing) in the array should begin
+ * @param value value to set in the array
+ * @throws IndexOutOfBoundsException if the provided {@code offset} is outside
+ * the range [0, array.length - 4]
+ * @see #getUnsignedInt(byte[], int)
+ */
+ public static void setUnsignedInt(byte[] array, int offset, long value) {
+ INT.set(array, offset, (int) value);
+ }
+
/**
* Sets (writes) the provided {@code value} using little endian order into
* the provided {@code array} beginning at the given {@code offset}.
diff --git a/test/jdk/jdk/internal/util/ByteArray/ReadWriteValues.java b/test/jdk/jdk/internal/util/ByteArray/ReadWriteValues.java
index 273aaf4fc8c70..744ed159345f5 100644
--- a/test/jdk/jdk/internal/util/ByteArray/ReadWriteValues.java
+++ b/test/jdk/jdk/internal/util/ByteArray/ReadWriteValues.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,13 +23,14 @@
/*
* @test
- * @bug 8299576
+ * @bug 8299576 8310837
* @modules java.base/jdk.internal.util
* @summary Verify that reads and writes of primitives are correct
* @run junit ReadWriteValues
*/
import jdk.internal.util.ByteArray;
+import jdk.internal.util.ByteArrayLittleEndian;
import org.junit.jupiter.api.*;
import java.util.concurrent.ThreadLocalRandom;
@@ -37,6 +38,9 @@
import java.util.stream.LongStream;
import java.util.stream.Stream;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.junit.jupiter.params.ParameterizedTest;
import static org.junit.jupiter.api.Assertions.*;
final class ReadWriteValues {
@@ -48,148 +52,197 @@ final class ReadWriteValues {
private static final int ITERATIONS = 1 << 10;
- @Test
- void testGetShort() {
+ @ParameterizedTest
+ @MethodSource("byteArrayImplWithRef")
+ void testGetShort(ByteArrayImpl ref, ByteArrayImpl ba) {
longs().forEach(l -> {
short expected = (short) l;
- RefImpl.putShort(BUFF, OFFSET, expected);
- short actual = ByteArray.getShort(BUFF, OFFSET);
+ ref.setShort(BUFF, OFFSET, expected);
+ short actual = ba.getShort(BUFF, OFFSET);
assertEquals(expected, actual);
});
}
- @Test
- void testPutShort() {
+ @ParameterizedTest
+ @MethodSource("byteArrayImplWithRef")
+ void testSetShort(ByteArrayImpl ref, ByteArrayImpl ba) {
longs().forEach(l -> {
short expected = (short) l;
- ByteArray.setShort(BUFF, OFFSET, expected);
- short actual = RefImpl.getShort(BUFF, OFFSET);
+ ba.setShort(BUFF, OFFSET, expected);
+ short actual = ref.getShort(BUFF, OFFSET);
assertEquals(expected, actual);
});
}
- @Test
- void testGetChar() {
+ @ParameterizedTest
+ @MethodSource("byteArrayImplWithRef")
+ void testGetChar(ByteArrayImpl ref, ByteArrayImpl ba) {
longs().forEach(l -> {
char expected = (char) l;
- RefImpl.putChar(BUFF, OFFSET, expected);
- char actual = ByteArray.getChar(BUFF, OFFSET);
+ ref.setChar(BUFF, OFFSET, expected);
+ char actual = ba.getChar(BUFF, OFFSET);
assertEquals(expected, actual);
});
}
- @Test
- void testPutChar() {
+ @ParameterizedTest
+ @MethodSource("byteArrayImplWithRef")
+ void testSetChar(ByteArrayImpl ref, ByteArrayImpl ba) {
longs().forEach(l -> {
char expected = (char) l;
- ByteArray.setChar(BUFF, OFFSET, expected);
- char actual = RefImpl.getChar(BUFF, OFFSET);
+ ba.setChar(BUFF, OFFSET, expected);
+ char actual = ref.getChar(BUFF, OFFSET);
assertEquals(expected, actual);
});
}
- @Test
- void testGetInt() {
+ @ParameterizedTest
+ @MethodSource("byteArrayImplWithRef")
+ void testGetInt(ByteArrayImpl ref, ByteArrayImpl ba) {
longs().forEach(l -> {
int expected = (int) l;
- RefImpl.putInt(BUFF, OFFSET, expected);
- int actual = ByteArray.getInt(BUFF, OFFSET);
+ ref.setInt(BUFF, OFFSET, expected);
+ int actual = ba.getInt(BUFF, OFFSET);
assertEquals(expected, actual);
});
}
- @Test
- void testPutInt() {
+ @ParameterizedTest
+ @MethodSource("byteArrayImplWithRef")
+ void testSetInt(ByteArrayImpl ref, ByteArrayImpl ba) {
longs().forEach(l -> {
int expected = (int) l;
- ByteArray.setInt(BUFF, OFFSET, expected);
- int actual = RefImpl.getInt(BUFF, OFFSET);
+ ba.setInt(BUFF, OFFSET, expected);
+ int actual = ref.getInt(BUFF, OFFSET);
assertEquals(expected, actual);
});
}
- @Test
- void testGetLong() {
+ @ParameterizedTest
+ @MethodSource("byteArrayImplWithRef")
+ void testGetLong(ByteArrayImpl ref, ByteArrayImpl ba) {
longs().forEach(expected -> {
- RefImpl.putLong(BUFF, OFFSET, expected);
- long actual = ByteArray.getLong(BUFF, OFFSET);
+ ref.setLong(BUFF, OFFSET, expected);
+ long actual = ba.getLong(BUFF, OFFSET);
assertEquals(expected, actual);
});
}
- @Test
- void testPutLong() {
+ @ParameterizedTest
+ @MethodSource("byteArrayImplWithRef")
+ void testSetLong(ByteArrayImpl ref, ByteArrayImpl ba) {
longs().forEach(expected -> {
- ByteArray.setLong(BUFF, OFFSET, expected);
- long actual = RefImpl.getLong(BUFF, OFFSET);
+ ba.setLong(BUFF, OFFSET, expected);
+ long actual = ref.getLong(BUFF, OFFSET);
assertEquals(expected, actual);
});
}
- @Test
- void testGetFloat() {
+ @ParameterizedTest
+ @MethodSource("byteArrayImplWithRef")
+ void testGetFloat(ByteArrayImpl ref, ByteArrayImpl ba) {
floats().forEach(expected -> {
- RefImpl.putFloat(BUFF, OFFSET, expected);
- float actual = ByteArray.getFloat(BUFF, OFFSET);
+ ref.setFloat(BUFF, OFFSET, expected);
+ float actual = ba.getFloat(BUFF, OFFSET);
assertEquals(expected, actual);
});
}
- @Test
- void testPutFloat() {
+ @ParameterizedTest
+ @MethodSource("byteArrayImplWithRef")
+ void testSetFloat(ByteArrayImpl ref, ByteArrayImpl ba) {
floats().forEach(expected -> {
- ByteArray.setFloat(BUFF, OFFSET, expected);
- float actual = RefImpl.getFloat(BUFF, OFFSET);
+ ba.setFloat(BUFF, OFFSET, expected);
+ float actual = ref.getFloat(BUFF, OFFSET);
assertEquals(expected, actual);
});
}
- @Test
- void testGetDouble() {
+ @ParameterizedTest
+ @MethodSource("byteArrayImplWithRef")
+ void testGetDouble(ByteArrayImpl ref, ByteArrayImpl ba) {
doubles().forEach(expected -> {
- RefImpl.putDouble(BUFF, OFFSET, expected);
- double actual = ByteArray.getDouble(BUFF, OFFSET);
+ ref.setDouble(BUFF, OFFSET, expected);
+ double actual = ba.getDouble(BUFF, OFFSET);
assertEquals(expected, actual);
});
}
- @Test
- void testPutDouble() {
+ @ParameterizedTest
+ @MethodSource("byteArrayImplWithRef")
+ void testSetDouble(ByteArrayImpl ref, ByteArrayImpl ba) {
doubles().forEach(expected -> {
- ByteArray.setDouble(BUFF, OFFSET, expected);
- double actual = RefImpl.getDouble(BUFF, OFFSET);
+ ba.setDouble(BUFF, OFFSET, expected);
+ double actual = ref.getDouble(BUFF, OFFSET);
assertEquals(expected, actual);
});
}
- @Test
- void testPutUnsignedShort() {
+ @ParameterizedTest
+ @MethodSource("byteArrayImplWithRef")
+ void testGetUnsignedShort(ByteArrayImpl ref, ByteArrayImpl ba) {
longs().forEach(l -> {
int expected = Short.toUnsignedInt((short) l);
- ByteArray.setUnsignedShort(BUFF, OFFSET, expected);
- int actual = Short.toUnsignedInt(RefImpl.getShort(BUFF, OFFSET));
+ ref.setUnsignedShort(BUFF, OFFSET, expected);
+ int actual = ba.getUnsignedShort(BUFF, OFFSET);
+ assertEquals(expected, actual);
+ });
+ }
+
+ @ParameterizedTest
+ @MethodSource("byteArrayImplWithRef")
+ void testSetUnsignedShort(ByteArrayImpl ref, ByteArrayImpl ba) {
+ longs().forEach(l -> {
+ int expected = Short.toUnsignedInt((short) l);
+ ba.setUnsignedShort(BUFF, OFFSET, expected);
+ int actual = ref.getUnsignedShort(BUFF, OFFSET);
+ assertEquals(expected, actual);
+ });
+ }
+
+ @ParameterizedTest
+ @MethodSource("byteArrayImplWithRef")
+ void testGetUnsignedInt(ByteArrayImpl ref, ByteArrayImpl ba) {
+ longs().forEach(l -> {
+ long expected = Integer.toUnsignedLong((int) l);
+ ref.setUnsignedInt(BUFF, OFFSET, expected);
+ long actual = ba.getUnsignedInt(BUFF, OFFSET);
+ assertEquals(expected, actual);
+ });
+ }
+
+ @ParameterizedTest
+ @MethodSource("byteArrayImplWithRef")
+ void testSetUnsignedInt(ByteArrayImpl ref, ByteArrayImpl ba) {
+ longs().forEach(l -> {
+ long expected = Integer.toUnsignedLong((int) l);
+ ba.setUnsignedInt(BUFF, OFFSET, expected);
+ long actual = ref.getUnsignedInt(BUFF, OFFSET);
assertEquals(expected, actual);
});
}
// Unusual cases
- @Test
- void testNullArray() {
- assertThrowsOriginal(NullPointerException.class, () -> ByteArray.getInt(null, OFFSET));
- assertThrowsOriginal(NullPointerException.class, () -> ByteArray.setInt(null, OFFSET, 1));
+ @ParameterizedTest
+ @MethodSource("byteArrayImpl")
+ void testNullArray(ByteArrayImpl ba) {
+ assertThrowsOriginal(NullPointerException.class, () -> ba.getInt(null, OFFSET));
+ assertThrowsOriginal(NullPointerException.class, () -> ba.setInt(null, OFFSET, 1));
}
- @Test
- void testNegArg() {
- assertThrowsOriginal(IndexOutOfBoundsException.class, () -> ByteArray.getInt(BUFF, -1));
- assertThrowsOriginal(IndexOutOfBoundsException.class, () -> ByteArray.setInt(BUFF, -1, 1));
+ @ParameterizedTest
+ @MethodSource("byteArrayImpl")
+ void testNegArg(ByteArrayImpl ba) {
+ assertThrowsOriginal(IndexOutOfBoundsException.class, () -> ba.getInt(BUFF, -1));
+ assertThrowsOriginal(IndexOutOfBoundsException.class, () -> ba.setInt(BUFF, -1, 1));
}
- @Test
- void testOutOfBounds() {
- assertThrowsOriginal(IndexOutOfBoundsException.class, () -> ByteArray.getInt(BUFF, BUFF.length));
- assertThrowsOriginal(IndexOutOfBoundsException.class, () -> ByteArray.setInt(BUFF, BUFF.length, 1));
+ @ParameterizedTest
+ @MethodSource("byteArrayImpl")
+ void testOutOfBounds(ByteArrayImpl ba) {
+ assertThrowsOriginal(IndexOutOfBoundsException.class, () -> ba.getInt(BUFF, BUFF.length));
+ assertThrowsOriginal(IndexOutOfBoundsException.class, () -> ba.setInt(BUFF, BUFF.length, 1));
}
static LongStream longs() {
@@ -208,6 +261,7 @@ static DoubleStream doubles() {
+0.0d)
);
}
+
static Stream