diff --git a/byteops-milo/pom.xml b/byteops-milo/pom.xml
new file mode 100644
index 0000000..9498729
--- /dev/null
+++ b/byteops-milo/pom.xml
@@ -0,0 +1,40 @@
+
+
+ 4.0.0
+
+ com.digitalpetri.util
+ byteops-parent
+ 0.1.4-SNAPSHOT
+
+
+ byteops-milo
+
+
+
+ com.digitalpetri.util
+ byteops
+ ${project.version}
+
+
+ org.eclipse.milo
+ milo-stack-core
+ ${milo.version}
+
+
+ org.jspecify
+ jspecify
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ test
+
+
+
diff --git a/byteops-milo/src/main/java/com/digitalpetri/util/byteops/milo/MiloByteOps.java b/byteops-milo/src/main/java/com/digitalpetri/util/byteops/milo/MiloByteOps.java
new file mode 100644
index 0000000..d5a4f7d
--- /dev/null
+++ b/byteops-milo/src/main/java/com/digitalpetri/util/byteops/milo/MiloByteOps.java
@@ -0,0 +1,462 @@
+package com.digitalpetri.util.byteops.milo;
+
+import com.digitalpetri.util.byteops.ByteOps;
+import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UByte;
+import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger;
+import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.ULong;
+import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UShort;
+
+/**
+ * Additional operations for working with Milo unsigned numbers.
+ *
+ * @param the type of bytes.
+ */
+public final class MiloByteOps implements ByteOps {
+
+ /**
+ * Create a new {@link MiloByteOps} derived from the given {@link ByteOps}.
+ *
+ * @param ops the {@link ByteOps} to derive from.
+ * @param the type of bytes.
+ * @return a new {@link MiloByteOps}.
+ */
+ public static MiloByteOps of(ByteOps ops) {
+ return new MiloByteOps<>(ops);
+ }
+
+ private final ByteOps delegate;
+
+ public MiloByteOps(ByteOps delegate) {
+ this.delegate = delegate;
+ }
+
+ /**
+ * Get the {@link UByte} value at the given {@code index} in {@code bytes}.
+ *
+ * @param bytes the bytes to get the value from.
+ * @param index the index into {@code bytes} to get the value at.
+ * @return the {@link UByte} value at the given {@code index}.
+ */
+ public UByte getUByte(T bytes, int index) {
+ return UByte.valueOf(getByte(bytes, index));
+ }
+
+ /**
+ * Get the {@link UShort} value at the given {@code index} in {@code bytes}.
+ *
+ * @param bytes the bytes to get the value from.
+ * @param index the index into {@code bytes} to get the value at.
+ * @return the {@link UShort} value at the given {@code index}.
+ */
+ public UShort getUShort(T bytes, int index) {
+ return UShort.valueOf(getShort(bytes, index));
+ }
+
+ /**
+ * Get the {@link UInteger} value at the given {@code index} in {@code bytes}.
+ *
+ * @param bytes the bytes to get the value from.
+ * @param index the index into {@code bytes} to get the value at.
+ * @return the {@link UInteger} value at the given {@code index}.
+ */
+ public UInteger getUInt(T bytes, int index) {
+ return UInteger.valueOf(getInt(bytes, index));
+ }
+
+ /**
+ * Get the {@link ULong} value at the given {@code index} in {@code bytes}.
+ *
+ * @param bytes the bytes to get the value from.
+ * @param index the index into {@code bytes} to get the value at.
+ * @return the {@link ULong} value at the given {@code index}.
+ */
+ public ULong getULong(T bytes, int index) {
+ return ULong.valueOf(getLong(bytes, index));
+ }
+
+ /**
+ * Get the {@link UByte} array at the given {@code index} in {@code bytes}.
+ *
+ * @param bytes the bytes to get the value from.
+ * @param index the index into {@code bytes} to get the value at.
+ * @param length the length of the array.
+ * @return the UByte array at the given {@code index}.
+ */
+ public UByte[] getUByteArray(T bytes, int index, int length) {
+ byte[] byteArray = delegate.getByteArray(bytes, index, length);
+ UByte[] uByteArray = new UByte[byteArray.length];
+ for (int i = 0; i < byteArray.length; i++) {
+ uByteArray[i] = UByte.valueOf(byteArray[i]);
+ }
+ return uByteArray;
+ }
+
+ /**
+ * Get the {@link UShort} array at the given {@code index} in {@code bytes}.
+ *
+ * @param bytes the bytes to get the value from.
+ * @param index the index into {@code bytes} to get the value at.
+ * @param length the length of the array.
+ * @return the UShort array at the given {@code index}.
+ */
+ public UShort[] getUShortArray(T bytes, int index, int length) {
+ short[] shortArray = delegate.getShortArray(bytes, index, length);
+ UShort[] uShortArray = new UShort[shortArray.length];
+ for (int i = 0; i < shortArray.length; i++) {
+ uShortArray[i] = UShort.valueOf(shortArray[i]);
+ }
+ return uShortArray;
+ }
+
+ /**
+ * Get the {@link UInteger} array at the given {@code index} in {@code bytes}.
+ *
+ * @param bytes the bytes to get the value from.
+ * @param index the index into {@code bytes} to get the value at.
+ * @param length the length of the array.
+ * @return the UInteger array at the given {@code index}.
+ */
+ public UInteger[] getUIntArray(T bytes, int index, int length) {
+ int[] intArray = delegate.getIntArray(bytes, index, length);
+ UInteger[] uIntArray = new UInteger[intArray.length];
+ for (int i = 0; i < intArray.length; i++) {
+ uIntArray[i] = UInteger.valueOf(intArray[i]);
+ }
+ return uIntArray;
+ }
+
+ /**
+ * Get the {@link ULong} array at the given {@code index} in {@code bytes}.
+ *
+ * @param bytes the bytes to get the value from.
+ * @param index the index into {@code bytes} to get the value at.
+ * @param length the length of the array.
+ * @return the ULong array at the given {@code index}.
+ */
+ public ULong[] getULongArray(T bytes, int index, int length) {
+ long[] longArray = delegate.getLongArray(bytes, index, length);
+ ULong[] uLongArray = new ULong[longArray.length];
+ for (int i = 0; i < longArray.length; i++) {
+ uLongArray[i] = ULong.valueOf(longArray[i]);
+ }
+ return uLongArray;
+ }
+
+ /**
+ * Set the {@link UByte} value at the given {@code index} in {@code bytes}.
+ *
+ * @param bytes the bytes to set the value in.
+ * @param index the index into {@code bytes} to set the value at.
+ * @param value the {@link UByte} value to set.
+ */
+ public void setUByte(T bytes, int index, UByte value) {
+ setByte(bytes, index, (byte) value.intValue());
+ }
+
+ /**
+ * Set the {@link UShort} value at the given {@code index} in {@code bytes}.
+ *
+ * @param bytes the bytes to set the value in.
+ * @param index the index into {@code bytes} to set the value at.
+ * @param value the {@link UShort} value to set.
+ */
+ public void setUShort(T bytes, int index, UShort value) {
+ setShort(bytes, index, (short) value.intValue());
+ }
+
+ /**
+ * Set the {@link UInteger} value at the given {@code index} in {@code bytes}.
+ *
+ * @param bytes the bytes to set the value in.
+ * @param index the index into {@code bytes} to set the value at.
+ * @param value the {@link UInteger} value to set.
+ */
+ public void setUInt(T bytes, int index, UInteger value) {
+ setInt(bytes, index, value.intValue());
+ }
+
+ /**
+ * Set the {@link ULong} value at the given {@code index} in {@code bytes}.
+ *
+ * @param bytes the bytes to set the value in.
+ * @param index the index into {@code bytes} to set the value at.
+ * @param value the {@link ULong} value to set.
+ */
+ public void setULong(T bytes, int index, ULong value) {
+ setLong(bytes, index, value.longValue());
+ }
+
+ /**
+ * Set the {@link UByte} array at the given {@code index} in {@code bytes}.
+ *
+ * @param bytes the bytes to set the values in.
+ * @param index the index into {@code bytes} to set the values at.
+ * @param values the UByte array to set.
+ */
+ public void setUByteArray(T bytes, int index, UByte[] values) {
+ byte[] byteArray = new byte[values.length];
+ for (int i = 0; i < values.length; i++) {
+ byteArray[i] = (byte) values[i].intValue();
+ }
+ delegate.setByteArray(bytes, index, byteArray);
+ }
+
+ /**
+ * Set the {@link UShort} array at the given {@code index} in {@code bytes}.
+ *
+ * @param bytes the bytes to set the values in.
+ * @param index the index into {@code bytes} to set the values at.
+ * @param values the UShort array to set.
+ */
+ public void setUShortArray(T bytes, int index, UShort[] values) {
+ short[] shortArray = new short[values.length];
+ for (int i = 0; i < values.length; i++) {
+ shortArray[i] = (short) values[i].intValue();
+ }
+ delegate.setShortArray(bytes, index, shortArray);
+ }
+
+ /**
+ * Set the {@link UInteger} array at the given {@code index} in {@code bytes}.
+ *
+ * @param bytes the bytes to set the values in.
+ * @param index the index into {@code bytes} to set the values at.
+ * @param values the UInteger array to set.
+ */
+ public void setUIntArray(T bytes, int index, UInteger[] values) {
+ int[] intArray = new int[values.length];
+ for (int i = 0; i < values.length; i++) {
+ intArray[i] = values[i].intValue();
+ }
+ delegate.setIntArray(bytes, index, intArray);
+ }
+
+ /**
+ * Set the {@link ULong} array at the given {@code index} in {@code bytes}.
+ *
+ * @param bytes the bytes to set the values in.
+ * @param index the index into {@code bytes} to set the values at.
+ * @param values the ULong array to set.
+ */
+ public void setULongArray(T bytes, int index, ULong[] values) {
+ long[] longArray = new long[values.length];
+ for (int i = 0; i < values.length; i++) {
+ longArray[i] = values[i].longValue();
+ }
+ delegate.setLongArray(bytes, index, longArray);
+ }
+
+ // region ByteOps delegated methods
+
+ @Override
+ public boolean getBoolean(T bytes, int index) {
+ return delegate.getBoolean(bytes, index);
+ }
+
+ @Override
+ public byte getByte(T bytes, int index) {
+ return delegate.getByte(bytes, index);
+ }
+
+ @Override
+ public short getShort(T bytes, int index) {
+ return delegate.getShort(bytes, index);
+ }
+
+ @Override
+ public int getInt(T bytes, int index) {
+ return delegate.getInt(bytes, index);
+ }
+
+ @Override
+ public long getLong(T bytes, int index) {
+ return delegate.getLong(bytes, index);
+ }
+
+ @Override
+ public float getFloat(T bytes, int index) {
+ return delegate.getFloat(bytes, index);
+ }
+
+ @Override
+ public double getDouble(T bytes, int index) {
+ return delegate.getDouble(bytes, index);
+ }
+
+ @Override
+ public boolean[] getBooleanArray(T bytes, int index, int length) {
+ return delegate.getBooleanArray(bytes, index, length);
+ }
+
+ @Override
+ public byte[] getByteArray(T bytes, int index, int length) {
+ return delegate.getByteArray(bytes, index, length);
+ }
+
+ @Override
+ public short[] getShortArray(T bytes, int index, int length) {
+ return delegate.getShortArray(bytes, index, length);
+ }
+
+ @Override
+ public int[] getIntArray(T bytes, int index, int length) {
+ return delegate.getIntArray(bytes, index, length);
+ }
+
+ @Override
+ public long[] getLongArray(T bytes, int index, int length) {
+ return delegate.getLongArray(bytes, index, length);
+ }
+
+ @Override
+ public float[] getFloatArray(T bytes, int index, int length) {
+ return delegate.getFloatArray(bytes, index, length);
+ }
+
+ @Override
+ public double[] getDoubleArray(T bytes, int index, int length) {
+ return delegate.getDoubleArray(bytes, index, length);
+ }
+
+ @Override
+ public void setBoolean(T bytes, int index, boolean value) {
+ delegate.setBoolean(bytes, index, value);
+ }
+
+ @Override
+ public void setByte(T bytes, int index, byte value) {
+ delegate.setByte(bytes, index, value);
+ }
+
+ @Override
+ public void setShort(T bytes, int index, short value) {
+ delegate.setShort(bytes, index, value);
+ }
+
+ @Override
+ public void setInt(T bytes, int index, int value) {
+ delegate.setInt(bytes, index, value);
+ }
+
+ @Override
+ public void setLong(T bytes, int index, long value) {
+ delegate.setLong(bytes, index, value);
+ }
+
+ @Override
+ public void setFloat(T bytes, int index, float value) {
+ delegate.setFloat(bytes, index, value);
+ }
+
+ @Override
+ public void setDouble(T bytes, int index, double value) {
+ delegate.setDouble(bytes, index, value);
+ }
+
+ @Override
+ public void setBooleanArray(T bytes, int index, boolean[] values) {
+ delegate.setBooleanArray(bytes, index, values);
+ }
+
+ @Override
+ public void setByteArray(T bytes, int index, byte[] values) {
+ delegate.setByteArray(bytes, index, values);
+ }
+
+ @Override
+ public void setShortArray(T bytes, int index, short[] values) {
+ delegate.setShortArray(bytes, index, values);
+ }
+
+ @Override
+ public void setIntArray(T bytes, int index, int[] values) {
+ delegate.setIntArray(bytes, index, values);
+ }
+
+ @Override
+ public void setLongArray(T bytes, int index, long[] values) {
+ delegate.setLongArray(bytes, index, values);
+ }
+
+ @Override
+ public void setFloatArray(T bytes, int index, float[] values) {
+ delegate.setFloatArray(bytes, index, values);
+ }
+
+ @Override
+ public void setDoubleArray(T bytes, int index, double[] values) {
+ delegate.setDoubleArray(bytes, index, values);
+ }
+
+ @Override
+ public Boolean[] getBoxedBooleanArray(T bytes, int index, int length) {
+ return delegate.getBoxedBooleanArray(bytes, index, length);
+ }
+
+ @Override
+ public void setBoxedBooleanArray(T bytes, int index, Boolean[] values) {
+ delegate.setBoxedBooleanArray(bytes, index, values);
+ }
+
+ @Override
+ public Byte[] getBoxedByteArray(T bytes, int index, int length) {
+ return delegate.getBoxedByteArray(bytes, index, length);
+ }
+
+ @Override
+ public void setBoxedByteArray(T bytes, int index, Byte[] values) {
+ delegate.setBoxedByteArray(bytes, index, values);
+ }
+
+ @Override
+ public Short[] getBoxedShortArray(T bytes, int index, int length) {
+ return delegate.getBoxedShortArray(bytes, index, length);
+ }
+
+ @Override
+ public void setBoxedShortArray(T bytes, int index, Short[] values) {
+ delegate.setBoxedShortArray(bytes, index, values);
+ }
+
+ @Override
+ public Integer[] getBoxedIntArray(T bytes, int index, int length) {
+ return delegate.getBoxedIntArray(bytes, index, length);
+ }
+
+ @Override
+ public void setBoxedIntArray(T bytes, int index, Integer[] values) {
+ delegate.setBoxedIntArray(bytes, index, values);
+ }
+
+ @Override
+ public Long[] getBoxedLongArray(T bytes, int index, int length) {
+ return delegate.getBoxedLongArray(bytes, index, length);
+ }
+
+ @Override
+ public void setBoxedLongArray(T bytes, int index, Long[] values) {
+ delegate.setBoxedLongArray(bytes, index, values);
+ }
+
+ @Override
+ public Float[] getBoxedFloatArray(T bytes, int index, int length) {
+ return delegate.getBoxedFloatArray(bytes, index, length);
+ }
+
+ @Override
+ public void setBoxedFloatArray(T bytes, int index, Float[] values) {
+ delegate.setBoxedFloatArray(bytes, index, values);
+ }
+
+ @Override
+ public Double[] getBoxedDoubleArray(T bytes, int index, int length) {
+ return delegate.getBoxedDoubleArray(bytes, index, length);
+ }
+
+ @Override
+ public void setBoxedDoubleArray(T bytes, int index, Double[] values) {
+ delegate.setBoxedDoubleArray(bytes, index, values);
+ }
+
+ // endregion
+}
diff --git a/byteops-milo/src/main/java/com/digitalpetri/util/byteops/milo/package-info.java b/byteops-milo/src/main/java/com/digitalpetri/util/byteops/milo/package-info.java
new file mode 100644
index 0000000..8bce94d
--- /dev/null
+++ b/byteops-milo/src/main/java/com/digitalpetri/util/byteops/milo/package-info.java
@@ -0,0 +1,4 @@
+@NullMarked
+package com.digitalpetri.util.byteops.milo;
+
+import org.jspecify.annotations.NullMarked;
diff --git a/byteops-milo/src/test/java/com/digitalpetri/util/byteops/milo/MiloByteOpsTest.java b/byteops-milo/src/test/java/com/digitalpetri/util/byteops/milo/MiloByteOpsTest.java
new file mode 100644
index 0000000..fb2f5a3
--- /dev/null
+++ b/byteops-milo/src/test/java/com/digitalpetri/util/byteops/milo/MiloByteOpsTest.java
@@ -0,0 +1,279 @@
+package com.digitalpetri.util.byteops.milo;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import com.digitalpetri.util.byteops.ByteArrayByteOps;
+import com.digitalpetri.util.byteops.ByteOps;
+import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UByte;
+import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger;
+import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.ULong;
+import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UShort;
+import org.junit.jupiter.api.Test;
+
+class MiloByteOpsTest {
+
+ @Test
+ void getUByte() {
+ ByteOps ops = ByteArrayByteOps.BIG_ENDIAN;
+ MiloByteOps miloOps = MiloByteOps.of(ops);
+
+ byte[] bytes = new byte[] {(byte) 0xff};
+ UByte uByte = miloOps.getUByte(bytes, 0);
+
+ assertEquals(UByte.valueOf((byte) 0xff), uByte);
+ }
+
+ @Test
+ void getUByteArray() {
+ ByteOps ops = ByteArrayByteOps.BIG_ENDIAN;
+ MiloByteOps miloOps = MiloByteOps.of(ops);
+
+ byte[] bytes = new byte[] {(byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04};
+ UByte[] uBytes = miloOps.getUByteArray(bytes, 0, 4);
+
+ assertEquals(UByte.valueOf((byte) 0x01), uBytes[0]);
+ assertEquals(UByte.valueOf((byte) 0x02), uBytes[1]);
+ assertEquals(UByte.valueOf((byte) 0x03), uBytes[2]);
+ assertEquals(UByte.valueOf((byte) 0x04), uBytes[3]);
+ }
+
+ @Test
+ void setUByte() {
+ ByteOps ops = ByteArrayByteOps.BIG_ENDIAN;
+ MiloByteOps miloOps = MiloByteOps.of(ops);
+
+ byte[] bytes = new byte[1];
+ miloOps.setUByte(bytes, 0, UByte.valueOf((byte) 0xff));
+
+ assertEquals((byte) 0xff, bytes[0]);
+ assertEquals(0xff, miloOps.getUByte(bytes, 0).intValue());
+ }
+
+ @Test
+ void setUByteArray() {
+ ByteOps ops = ByteArrayByteOps.BIG_ENDIAN;
+ MiloByteOps miloOps = MiloByteOps.of(ops);
+
+ byte[] bytes = new byte[4];
+ miloOps.setUByteArray(
+ bytes,
+ 0,
+ new UByte[] {
+ UByte.valueOf((byte) 0x01),
+ UByte.valueOf((byte) 0x02),
+ UByte.valueOf((byte) 0x03),
+ UByte.valueOf((byte) 0x04)
+ });
+
+ assertEquals((byte) 0x01, bytes[0]);
+ assertEquals((byte) 0x02, bytes[1]);
+ assertEquals((byte) 0x03, bytes[2]);
+ assertEquals((byte) 0x04, bytes[3]);
+ assertEquals(0x01, miloOps.getUByte(bytes, 0).intValue());
+ assertEquals(0x02, miloOps.getUByte(bytes, 1).intValue());
+ assertEquals(0x03, miloOps.getUByte(bytes, 2).intValue());
+ assertEquals(0x04, miloOps.getUByte(bytes, 3).intValue());
+ }
+
+ @Test
+ void getUShort() {
+ ByteOps ops = ByteArrayByteOps.BIG_ENDIAN;
+ MiloByteOps miloOps = MiloByteOps.of(ops);
+
+ byte[] bytes = new byte[] {(byte) 0xff, (byte) 0xff};
+ UShort uShort = miloOps.getUShort(bytes, 0);
+
+ assertEquals(UShort.valueOf((short) 0xffff), uShort);
+ }
+
+ @Test
+ void getUShortArray() {
+ ByteOps ops = ByteArrayByteOps.BIG_ENDIAN;
+ MiloByteOps miloOps = MiloByteOps.of(ops);
+
+ byte[] bytes = new byte[] {(byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04};
+ UShort[] uShorts = miloOps.getUShortArray(bytes, 0, 2);
+
+ assertEquals(UShort.valueOf((short) 0x0102), uShorts[0]);
+ assertEquals(UShort.valueOf((short) 0x0304), uShorts[1]);
+ }
+
+ @Test
+ void setUShort() {
+ ByteOps ops = ByteArrayByteOps.BIG_ENDIAN;
+ MiloByteOps miloOps = MiloByteOps.of(ops);
+
+ byte[] bytes = new byte[2];
+ miloOps.setUShort(bytes, 0, UShort.valueOf((short) 0xffff));
+
+ assertEquals((byte) 0xff, bytes[0]);
+ assertEquals((byte) 0xff, bytes[1]);
+ assertEquals(0xffff, miloOps.getUShort(bytes, 0).intValue());
+ }
+
+ @Test
+ void setUShortArray() {
+ ByteOps ops = ByteArrayByteOps.BIG_ENDIAN;
+ MiloByteOps miloOps = MiloByteOps.of(ops);
+
+ byte[] bytes = new byte[4];
+ miloOps.setUShortArray(
+ bytes, 0, new UShort[] {UShort.valueOf((short) 0x0102), UShort.valueOf((short) 0x0304)});
+
+ assertEquals((byte) 0x01, bytes[0]);
+ assertEquals((byte) 0x02, bytes[1]);
+ assertEquals((byte) 0x03, bytes[2]);
+ assertEquals((byte) 0x04, bytes[3]);
+ assertEquals(0x0102, miloOps.getUShort(bytes, 0).intValue());
+ assertEquals(0x0304, miloOps.getUShort(bytes, 2).intValue());
+ }
+
+ @Test
+ void getUInt() {
+ ByteOps ops = ByteArrayByteOps.BIG_ENDIAN;
+ MiloByteOps miloOps = MiloByteOps.of(ops);
+
+ byte[] bytes = new byte[] {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff};
+ UInteger uInteger = miloOps.getUInt(bytes, 0);
+
+ assertEquals(UInteger.valueOf(0xffffffffL), uInteger);
+ }
+
+ @Test
+ void getUIntArray() {
+ ByteOps ops = ByteArrayByteOps.BIG_ENDIAN;
+ MiloByteOps miloOps = MiloByteOps.of(ops);
+
+ byte[] bytes =
+ new byte[] {
+ (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04,
+ (byte) 0x05, (byte) 0x06, (byte) 0x07, (byte) 0x08
+ };
+
+ UInteger[] uInts = miloOps.getUIntArray(bytes, 0, 2);
+
+ assertEquals(UInteger.valueOf(0x01020304), uInts[0]);
+ assertEquals(UInteger.valueOf(0x05060708), uInts[1]);
+ }
+
+ @Test
+ void setUInt() {
+ ByteOps ops = ByteArrayByteOps.BIG_ENDIAN;
+ MiloByteOps miloOps = MiloByteOps.of(ops);
+
+ byte[] bytes = new byte[4];
+ miloOps.setUInt(bytes, 0, UInteger.valueOf(0xffffffffL));
+
+ assertEquals((byte) 0xff, bytes[0]);
+ assertEquals((byte) 0xff, bytes[1]);
+ assertEquals((byte) 0xff, bytes[2]);
+ assertEquals((byte) 0xff, bytes[3]);
+ assertEquals(0xffffffffL, miloOps.getUInt(bytes, 0).longValue());
+ }
+
+ @Test
+ void setUIntArray() {
+ ByteOps ops = ByteArrayByteOps.BIG_ENDIAN;
+ MiloByteOps miloOps = MiloByteOps.of(ops);
+
+ byte[] bytes = new byte[8];
+ miloOps.setUIntArray(
+ bytes, 0, new UInteger[] {UInteger.valueOf(0x01020304), UInteger.valueOf(0x05060708)});
+
+ assertEquals((byte) 0x01, bytes[0]);
+ assertEquals((byte) 0x02, bytes[1]);
+ assertEquals((byte) 0x03, bytes[2]);
+ assertEquals((byte) 0x04, bytes[3]);
+ assertEquals((byte) 0x05, bytes[4]);
+ assertEquals((byte) 0x06, bytes[5]);
+ assertEquals((byte) 0x07, bytes[6]);
+ assertEquals((byte) 0x08, bytes[7]);
+ assertEquals(0x01020304, miloOps.getUInt(bytes, 0).intValue());
+ assertEquals(0x05060708, miloOps.getUInt(bytes, 4).intValue());
+ }
+
+ @Test
+ void getULong() {
+ ByteOps ops = ByteArrayByteOps.BIG_ENDIAN;
+ MiloByteOps miloOps = MiloByteOps.of(ops);
+
+ byte[] bytes =
+ new byte[] {
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff
+ };
+
+ ULong uLong = miloOps.getULong(bytes, 0);
+
+ assertEquals(ULong.valueOf(0xffffffffffffffffL), uLong);
+ }
+
+ @Test
+ void getULongArray() {
+ ByteOps ops = ByteArrayByteOps.BIG_ENDIAN;
+ MiloByteOps miloOps = MiloByteOps.of(ops);
+
+ byte[] bytes =
+ new byte[] {
+ (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04,
+ (byte) 0x05, (byte) 0x06, (byte) 0x07, (byte) 0x08,
+ (byte) 0x09, (byte) 0x0a, (byte) 0x0b, (byte) 0x0c,
+ (byte) 0x0d, (byte) 0x0e, (byte) 0x0f, (byte) 0x10
+ };
+
+ ULong[] uLongs = miloOps.getULongArray(bytes, 0, 2);
+
+ assertEquals(ULong.valueOf(0x0102030405060708L), uLongs[0]);
+ assertEquals(ULong.valueOf(0x090a0b0c0d0e0f10L), uLongs[1]);
+ }
+
+ @Test
+ void setULong() {
+ ByteOps ops = ByteArrayByteOps.BIG_ENDIAN;
+ MiloByteOps miloOps = MiloByteOps.of(ops);
+
+ byte[] bytes = new byte[8];
+ miloOps.setULong(bytes, 0, ULong.valueOf(0xffffffffffffffffL));
+
+ assertEquals((byte) 0xff, bytes[0]);
+ assertEquals((byte) 0xff, bytes[1]);
+ assertEquals((byte) 0xff, bytes[2]);
+ assertEquals((byte) 0xff, bytes[3]);
+ assertEquals((byte) 0xff, bytes[4]);
+ assertEquals((byte) 0xff, bytes[5]);
+ assertEquals((byte) 0xff, bytes[6]);
+ assertEquals((byte) 0xff, bytes[7]);
+ assertEquals(0xffffffffffffffffL, miloOps.getULong(bytes, 0).longValue());
+ }
+
+ @Test
+ void setULongArray() {
+ ByteOps ops = ByteArrayByteOps.BIG_ENDIAN;
+ MiloByteOps miloOps = MiloByteOps.of(ops);
+
+ byte[] bytes = new byte[16];
+ miloOps.setULongArray(
+ bytes,
+ 0,
+ new ULong[] {ULong.valueOf(0x0102030405060708L), ULong.valueOf(0x090a0b0c0d0e0f10L)});
+
+ assertEquals((byte) 0x01, bytes[0]);
+ assertEquals((byte) 0x02, bytes[1]);
+ assertEquals((byte) 0x03, bytes[2]);
+ assertEquals((byte) 0x04, bytes[3]);
+ assertEquals((byte) 0x05, bytes[4]);
+ assertEquals((byte) 0x06, bytes[5]);
+ assertEquals((byte) 0x07, bytes[6]);
+ assertEquals((byte) 0x08, bytes[7]);
+ assertEquals((byte) 0x09, bytes[8]);
+ assertEquals((byte) 0x0a, bytes[9]);
+ assertEquals((byte) 0x0b, bytes[10]);
+ assertEquals((byte) 0x0c, bytes[11]);
+ assertEquals((byte) 0x0d, bytes[12]);
+ assertEquals((byte) 0x0e, bytes[13]);
+ assertEquals((byte) 0x0f, bytes[14]);
+ assertEquals((byte) 0x10, bytes[15]);
+ assertEquals(0x0102030405060708L, miloOps.getULong(bytes, 0).longValue());
+ assertEquals(0x090a0b0c0d0e0f10L, miloOps.getULong(bytes, 8).longValue());
+ }
+}
diff --git a/pom.xml b/pom.xml
index 14fe763..cd49ba7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -50,6 +50,7 @@
0.9.4
1.0.0
+ 1.0.8
4.1.112.Final
@@ -62,6 +63,7 @@
byteops
+ byteops-milo
byteops-netty
byteops-unsigned