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 floats() { return Stream.concat( ThreadLocalRandom.current().doubles(ITERATIONS).mapToObj(d -> (float)d), @@ -221,6 +275,16 @@ static Stream floats() { ); } + static Stream byteArrayImpl() { + return Stream.of(UNSAFE, UNSAFE_LE); + } + + static Stream byteArrayImplWithRef() { + return Stream.of( + Arguments.of(REF, UNSAFE), + Arguments.of(REF_LE, UNSAFE_LE)); + } + @FunctionalInterface interface ThrowingRunnable { void run() throws Exception; @@ -242,34 +306,83 @@ void assertThrowsOriginal(Class type, } + private interface ByteArrayImpl { + char getChar(byte[] b, int off); + + short getShort(byte[] b, int off); + + default int getUnsignedShort(byte[] b, int off) { + return Short.toUnsignedInt(getShort(b, off)); + } + + int getInt(byte[] b, int off); + + default long getUnsignedInt(byte[] b, int off) { + return Integer.toUnsignedLong(getInt(b, off)); + } + + long getLong(byte[] b, int off); + + default float getFloat(byte[] b, int off) { + return Float.intBitsToFloat(getInt(b, off)); + } + + default double getDouble(byte[] b, int off) { + return Double.longBitsToDouble(getLong(b, off)); + } + + /* + * Methods for packing primitive values into byte arrays starting at given + * offsets. + */ + + void setChar(byte[] b, int off, char val); + + void setShort(byte[] b, int off, short val); + + default void setUnsignedShort(byte[] b, int off, int val) { + setShort(b, off, (short) val); + } + + void setInt(byte[] b, int off, int val); + + default void setUnsignedInt(byte[] b, int off, long val) { + setInt(b, off, (int) val); + } + + void setLong(byte[] b, int off, long val); + + default void setFloat(byte[] b, int off, float val) { + setInt(b, off, Float.floatToIntBits(val)); + } + + default void setDouble(byte[] b, int off, double val) { + setLong(b, off, Double.doubleToLongBits(val)); + } + } + /** * Reference implementation from the old java.io.Bits implementation */ - private static final class RefImpl { - private RefImpl() {} - - static char getChar(byte[] b, int off) { + private static final ByteArrayImpl REF = new ByteArrayImpl() { + public char getChar(byte[] b, int off) { return (char) ((b[off + 1] & 0xFF) + (b[off] << 8)); } - static short getShort(byte[] b, int off) { + public short getShort(byte[] b, int off) { return (short) ((b[off + 1] & 0xFF) + (b[off] << 8)); } - static int getInt(byte[] b, int off) { + public int getInt(byte[] b, int off) { return ((b[off + 3] & 0xFF)) + ((b[off + 2] & 0xFF) << 8) + ((b[off + 1] & 0xFF) << 16) + ((b[off]) << 24); } - static float getFloat(byte[] b, int off) { - return Float.intBitsToFloat(getInt(b, off)); - } - - static long getLong(byte[] b, int off) { + public long getLong(byte[] b, int off) { return ((b[off + 7] & 0xFFL)) + ((b[off + 6] & 0xFFL) << 8) + ((b[off + 5] & 0xFFL) << 16) + @@ -280,37 +393,24 @@ static long getLong(byte[] b, int off) { (((long) b[off]) << 56); } - static double getDouble(byte[] b, int off) { - return Double.longBitsToDouble(getLong(b, off)); - } - - /* - * Methods for packing primitive values into byte arrays starting at given - * offsets. - */ - - static void putChar(byte[] b, int off, char val) { + public void setChar(byte[] b, int off, char val) { b[off + 1] = (byte) (val); b[off] = (byte) (val >>> 8); } - static void putShort(byte[] b, int off, short val) { + public void setShort(byte[] b, int off, short val) { b[off + 1] = (byte) (val); b[off] = (byte) (val >>> 8); } - static void putInt(byte[] b, int off, int val) { + public void setInt(byte[] b, int off, int val) { b[off + 3] = (byte) (val); b[off + 2] = (byte) (val >>> 8); b[off + 1] = (byte) (val >>> 16); b[off] = (byte) (val >>> 24); } - static void putFloat(byte[] b, int off, float val) { - putInt(b, off, Float.floatToIntBits(val)); - } - - static void putLong(byte[] b, int off, long val) { + public void setLong(byte[] b, int off, long val) { b[off + 7] = (byte) (val); b[off + 6] = (byte) (val >>> 8); b[off + 5] = (byte) (val >>> 16); @@ -320,9 +420,195 @@ static void putLong(byte[] b, int off, long val) { b[off + 1] = (byte) (val >>> 48); b[off] = (byte) (val >>> 56); } + }; - static void putDouble(byte[] b, int off, double val) { - putLong(b, off, Double.doubleToLongBits(val)); + private static final ByteArrayImpl REF_LE = new ByteArrayImpl() { + public char getChar(byte[] b, int off) { + return (char) ((b[off] & 0xFF) + + (b[off + 1] << 8)); } - } -} + + public short getShort(byte[] b, int off) { + return (short) ((b[off] & 0xFF) + + (b[off + 1] << 8)); + } + + public int getInt(byte[] b, int off) { + return ((b[off] & 0xFF)) + + ((b[off + 1] & 0xFF) << 8) + + ((b[off + 2] & 0xFF) << 16) + + ((b[off + 3]) << 24); + } + + public long getLong(byte[] b, int off) { + return ((b[off] & 0xFFL)) + + ((b[off + 1] & 0xFFL) << 8) + + ((b[off + 2] & 0xFFL) << 16) + + ((b[off + 3] & 0xFFL) << 24) + + ((b[off + 4] & 0xFFL) << 32) + + ((b[off + 5] & 0xFFL) << 40) + + ((b[off + 6] & 0xFFL) << 48) + + (((long) b[off + 7]) << 56); + } + + public void setChar(byte[] b, int off, char val) { + b[off] = (byte) (val); + b[off + 1] = (byte) (val >>> 8); + } + + public void setShort(byte[] b, int off, short val) { + b[off] = (byte) (val); + b[off + 1] = (byte) (val >>> 8); + } + + public void setInt(byte[] b, int off, int val) { + b[off] = (byte) (val); + b[off + 1] = (byte) (val >>> 8); + b[off + 2] = (byte) (val >>> 16); + b[off + 3] = (byte) (val >>> 24); + } + + public void setLong(byte[] b, int off, long val) { + b[off] = (byte) (val); + b[off + 1] = (byte) (val >>> 8); + b[off + 2] = (byte) (val >>> 16); + b[off + 3] = (byte) (val >>> 24); + b[off + 4] = (byte) (val >>> 32); + b[off + 5] = (byte) (val >>> 40); + b[off + 6] = (byte) (val >>> 48); + b[off + 7] = (byte) (val >>> 56); + } + }; + + private static final ByteArrayImpl UNSAFE = new ByteArrayImpl() { + public char getChar(byte[] b, int off) { + return ByteArray.getChar(b, off); + } + + public short getShort(byte[] b, int off) { + return ByteArray.getShort(b, off); + } + + public int getUnsignedShort(byte[] b, int off) { + return ByteArray.getUnsignedShort(b, off); + } + + public int getInt(byte[] b, int off) { + return ByteArray.getInt(b, off); + } + + public long getUnsignedInt(byte[] b, int off) { + return ByteArray.getUnsignedInt(b, off); + } + + public long getLong(byte[] b, int off) { + return ByteArray.getLong(b, off); + } + + public float getFloat(byte[] b, int off) { + return ByteArray.getFloat(b, off); + } + + public double getDouble(byte[] b, int off) { + return ByteArray.getDouble(b, off); + } + + public void setChar(byte[] b, int off, char val) { + ByteArray.setChar(b, off, val); + } + + public void setShort(byte[] b, int off, short val) { + ByteArray.setShort(b, off, val); + } + + public void setUnsignedShort(byte[] b, int off, int val) { + ByteArray.setUnsignedShort(b, off, val); + } + + public void setInt(byte[] b, int off, int val) { + ByteArray.setInt(b, off, val); + } + + public void setUnsignedInt(byte[] b, int off, long val) { + ByteArray.setUnsignedInt(b, off, val); + } + + public void setLong(byte[] b, int off, long val) { + ByteArray.setLong(b, off, val); + } + + public void setFloat(byte[] b, int off, float val) { + ByteArray.setFloat(b, off, val); + } + + public void setDouble(byte[] b, int off, double val) { + ByteArray.setDouble(b, off, val); + } + }; + + private static final ByteArrayImpl UNSAFE_LE = new ByteArrayImpl() { + public char getChar(byte[] b, int off) { + return ByteArrayLittleEndian.getChar(b, off); + } + + public short getShort(byte[] b, int off) { + return ByteArrayLittleEndian.getShort(b, off); + } + + public int getUnsignedShort(byte[] b, int off) { + return ByteArrayLittleEndian.getUnsignedShort(b, off); + } + + public int getInt(byte[] b, int off) { + return ByteArrayLittleEndian.getInt(b, off); + } + + public long getUnsignedInt(byte[] b, int off) { + return ByteArrayLittleEndian.getUnsignedInt(b, off); + } + + public long getLong(byte[] b, int off) { + return ByteArrayLittleEndian.getLong(b, off); + } + + public float getFloat(byte[] b, int off) { + return ByteArrayLittleEndian.getFloat(b, off); + } + + public double getDouble(byte[] b, int off) { + return ByteArrayLittleEndian.getDouble(b, off); + } + + public void setChar(byte[] b, int off, char val) { + ByteArrayLittleEndian.setChar(b, off, val); + } + + public void setShort(byte[] b, int off, short val) { + ByteArrayLittleEndian.setShort(b, off, val); + } + + public void setUnsignedShort(byte[] b, int off, int val) { + ByteArrayLittleEndian.setUnsignedShort(b, off, val); + } + + public void setInt(byte[] b, int off, int val) { + ByteArrayLittleEndian.setInt(b, off, val); + } + + public void setUnsignedInt(byte[] b, int off, long val) { + ByteArrayLittleEndian.setUnsignedInt(b, off, val); + } + + public void setLong(byte[] b, int off, long val) { + ByteArrayLittleEndian.setLong(b, off, val); + } + + public void setFloat(byte[] b, int off, float val) { + ByteArrayLittleEndian.setFloat(b, off, val); + } + + public void setDouble(byte[] b, int off, double val) { + ByteArrayLittleEndian.setDouble(b, off, val); + } + }; +} \ No newline at end of file