Skip to content

Commit b7d82d0

Browse files
committed
Add toIntArray converter
Supports little and big endian order. fixes #28
1 parent c7dde7b commit b7d82d0

File tree

4 files changed

+102
-3
lines changed

4 files changed

+102
-3
lines changed

CHANGELOG

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
* add `append()` method supporting multiple byte arrays #26
66
* add `toCharArray()` method which decodes internal byte array to char[] #27
77
* add `encodeBase64()` supporting padding-less encoding
8+
* add `toIntArray()` converter #28
89

910
### Breaking
1011

src/main/java/at/favre/lib/bytes/Bytes.java

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1625,7 +1625,7 @@ public String encodeBase36() {
16251625

16261626
/**
16271627
* Base64 representation with padding. This is *NOT* the url safe variation. This encoding has a space efficiency of 75%.
1628-
*
1628+
* <p>
16291629
* This encoding is <a href="https://tools.ietf.org/html/rfc4648">RFC 4648</a> compatible.
16301630
* <p>
16311631
* Example: <code>SpT9/x6v7Q==</code>
@@ -1640,7 +1640,7 @@ public String encodeBase64() {
16401640
/**
16411641
* Base64 representation with padding. This is the url safe variation substitution '+' and '/' with '-' and '_'
16421642
* respectively. This encoding has a space efficiency of 75%.
1643-
*
1643+
* <p>
16441644
* This encoding is <a href="https://tools.ietf.org/html/rfc4648">RFC 4648</a> compatible.
16451645
* <p>
16461646
* Example: <code>SpT9_x6v7Q==</code>
@@ -1736,7 +1736,7 @@ public List<Byte> toList() {
17361736
/**
17371737
* Returns a copy of the internal byte-array as boxed primitive array.
17381738
* This requires a time and space complexity of O(n).
1739-
*
1739+
* <p>
17401740
* Note: this method was previously called <code>toObjectArray()</code>
17411741
*
17421742
* @return copy of internal array as object array
@@ -1861,6 +1861,25 @@ public int toInt() {
18611861
return intAt(0);
18621862
}
18631863

1864+
/**
1865+
* Converts the internal byte array to an int array, that is, every 4 bytes will be packed into a single int.
1866+
* <p>
1867+
* E.g. 4 bytes will be packed to a length 1 int array:
1868+
* <pre>
1869+
* [b1, b2, b3, b4] = [int1]
1870+
* </pre>
1871+
* <p>
1872+
* This conversion respects the internal byte order. Will only work if all bytes can be directly mapped to int,
1873+
* which means the byte array length must be dividable by 4 without rest.
1874+
*
1875+
* @return new int[] instance representing this byte array
1876+
* @throws IllegalArgumentException if internal byte length mod 4 != 0
1877+
*/
1878+
public int[] toIntArray() {
1879+
Util.checkModLength(length(), 4, "creating an int array");
1880+
return Util.toIntArray(internalArray(), byteOrder);
1881+
}
1882+
18641883
/**
18651884
* If the underlying byte array is exactly 8 byte / 64 bit long, return signed two-complement
18661885
* representation for a Java signed long integer value. The output is dependent on the set {@link #byteOrder()}.

src/main/java/at/favre/lib/bytes/Util.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import java.nio.ByteBuffer;
2626
import java.nio.ByteOrder;
2727
import java.nio.CharBuffer;
28+
import java.nio.IntBuffer;
2829
import java.nio.charset.CharacterCodingException;
2930
import java.nio.charset.Charset;
3031
import java.nio.file.Files;
@@ -456,6 +457,28 @@ static char[] byteToCharArray(byte[] bytes, Charset charset) {
456457
}
457458
}
458459

460+
/**
461+
* Converts the byte array to an int array. This will spread 4 bytes into a single int:
462+
*
463+
* <pre>
464+
* [b1, b2, b3, b4] = int1
465+
* </pre>
466+
*
467+
* @param bytes to convert to int array
468+
* @param byteOrder of the byte array
469+
* @return int array
470+
*/
471+
static int[] toIntArray(byte[] bytes, ByteOrder byteOrder) {
472+
IntBuffer buffer = ByteBuffer.wrap(bytes).order(byteOrder).asIntBuffer();
473+
if (buffer.hasArray()) {
474+
return buffer.array();
475+
} else {
476+
int[] array = new int[buffer.remaining()];
477+
buffer.get(array);
478+
return array;
479+
}
480+
}
481+
459482
/**
460483
* Shows the length and a preview of max 8 bytes of the given byte
461484
*
@@ -590,6 +613,21 @@ static int hashCode(byte[] byteArray, ByteOrder byteOrder) {
590613
return result;
591614
}
592615

616+
/**
617+
* Checks if given length is divisable by mod factor (with zero rest).
618+
* This can be used to check of a byte array can be convertet to an e.g. int array which is
619+
* multiples of 4.
620+
*
621+
* @param length of the byte array
622+
* @param modFactor to divide the length
623+
* @param errorSubject human readable message of the exact error subject
624+
*/
625+
static void checkModLength(int length, int modFactor, String errorSubject) {
626+
if (length % modFactor != 0) {
627+
throw new IllegalArgumentException("Illegal length for " + errorSubject + ". Byte array length must be multiple of " + modFactor + ", length was " + length);
628+
}
629+
}
630+
593631
/*
594632
=================================================================================================
595633
Copyright 2011 Twitter, Inc.

src/test/java/at/favre/lib/bytes/BytesToConvertOtherTypesTest.java

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
import org.junit.Test;
2525

26+
import java.nio.ByteOrder;
2627
import java.util.List;
2728

2829
import static org.junit.Assert.*;
@@ -235,4 +236,44 @@ public void testToUUIDToShort() {
235236
public void testToUUIDEmpty() {
236237
Bytes.allocate(0).toUUID();
237238
}
239+
240+
@Test
241+
public void testToIntArray() {
242+
assertArrayEquals(new int[]{1}, Bytes.wrap(new byte[]{0, 0, 0, 1}).toIntArray());
243+
assertArrayEquals(new int[]{257}, Bytes.wrap(new byte[]{0, 0, 1, 1}).toIntArray());
244+
assertArrayEquals(new int[]{65_793}, Bytes.wrap(new byte[]{0, 1, 1, 1}).toIntArray());
245+
assertArrayEquals(new int[]{16_843_009}, Bytes.wrap(new byte[]{1, 1, 1, 1}).toIntArray());
246+
assertArrayEquals(new int[]{571_211_845}, Bytes.wrap(new byte[]{34, 12, 0, 69}).toIntArray());
247+
assertArrayEquals(new int[]{1_290_429_439}, Bytes.wrap(new byte[]{76, (byte) 234, 99, (byte) 255}).toIntArray());
248+
249+
assertArrayEquals(new int[]{1, 1}, Bytes.wrap(new byte[]{0, 0, 0, 1, 0, 0, 0, 1}).toIntArray());
250+
assertArrayEquals(new int[]{257, 1}, Bytes.wrap(new byte[]{0, 0, 1, 1, 0, 0, 0, 1}).toIntArray());
251+
assertArrayEquals(new int[]{257, 65_793, 1}, Bytes.wrap(new byte[]{0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1}).toIntArray());
252+
}
253+
254+
@Test(expected = IllegalArgumentException.class)
255+
public void testToIntArrayNotMod4Was5Byte() {
256+
Bytes.wrap(new byte[]{1, 0, 0, 0, 1}).toIntArray();
257+
}
258+
259+
@Test(expected = IllegalArgumentException.class)
260+
public void testToIntArrayNotMod4Only3Byte() {
261+
Bytes.wrap(new byte[]{0, 0, 1}).toIntArray();
262+
}
263+
264+
@Test
265+
public void testToIntEmptyArray() {
266+
assertArrayEquals(new int[0], Bytes.empty().toIntArray());
267+
}
268+
269+
@Test
270+
public void testToIntArrayLittleEndian() {
271+
assertArrayEquals(new int[]{1}, Bytes.wrap(new byte[]{1, 0, 0, 0}, ByteOrder.LITTLE_ENDIAN).toIntArray());
272+
assertArrayEquals(new int[]{257}, Bytes.wrap(new byte[]{1, 1, 0, 0}, ByteOrder.LITTLE_ENDIAN).toIntArray());
273+
assertArrayEquals(new int[]{1_290_429_439}, Bytes.wrap(new byte[]{(byte) 255, 99, (byte) 234, 76}, ByteOrder.LITTLE_ENDIAN).toIntArray());
274+
275+
assertArrayEquals(new int[]{1, 1}, Bytes.wrap(new byte[]{1, 0, 0, 0, 1, 0, 0, 0}, ByteOrder.LITTLE_ENDIAN).toIntArray());
276+
assertArrayEquals(new int[]{257, 1}, Bytes.wrap(new byte[]{1, 1, 0, 0, 1, 0, 0, 0}, ByteOrder.LITTLE_ENDIAN).toIntArray());
277+
assertArrayEquals(new int[]{257, 65_793, 1}, Bytes.wrap(new byte[]{1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0}, ByteOrder.LITTLE_ENDIAN).toIntArray());
278+
}
238279
}

0 commit comments

Comments
 (0)