How do I initialize and increment a byte array in Java? - java

I need to increment a 32 bit value each time I enter a certain loop. However, eventually it must be in a byte array (byte[]) form. What is the best way to go about it?
Option 1:
byte[] count = new byte[4];
//some way to initialize and increment byte[]
Option 2:
int count=0;
count++;
//some way to convert int to byte
Option 3: ??

You would convert your int to byte[] as follows:
ByteBuffer b = ByteBuffer.allocate(4);
//b.order(ByteOrder.BIG_ENDIAN); // optional, the initial order of a byte buffer is always BIG_ENDIAN.
b.putInt(0xAABBCCDD);
byte[] result = b.array();
source: Convert integer into byte array (Java)
Now comes the increment part. You can increment your integer the same way you would do. using ++ or whatever the need be. Then, clear the ByteBuffer, put in the number again, flip() the buffer and get the array

Another convenient way is the following method which works also with arbitrary length byte arrays:
byte[] counter = new byte[4]; // all zeroes
byte[] incrementedCounter = new BigInteger(1, counter).add(BigInteger.ONE).toByteArray();
if (incrementedCounter.length > 4) {
incrementedCounter = ArrayUtils.subarray(incrementedCounter, 1, incrementedCounter.length);
}
else if (incrementedCounter.length < 5) {
incrementedCounter = ArrayUtils.addAll(new byte[5-incrementedCounter.length], incrementedCounter);
}
// do something with the counter
...
counter = incrementedCounter ;
The counter will overflow after 2^32 bits. Because also a sign bit is used by BigInteger it might be necessary to cut off an additional leading byte (done in the code). The overflow is handled here by this cut and starting with 0 again.
ArrayUtils is coming from the org.apache.commons library.

Related

Cast long from smaller byte array (Java)

I am trying to convert a byte array to long, but receive BufferUnderflowException
ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);
byte[] arg1 = new byte[] {0x04, (byte)0xB0};
buffer.put(arg1, 0, arg1.length);
buffer.flip();
long val = buffer.getLong();
In debug mode, I looked inside buffer. It has an internal byte array, and it fills the unspecified bytes with "0". So why does the exception occur? How can I fix it?
The spec of getLong() specifically says that it throws BufferUnderflowException if there are fewer than eight bytes remaining in this buffer. Your buffer has only two bytes.
It seems like you should use Long.BYTES to fill your buffer. If your byte[] is exhausted you could switch to 0. Like,
ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);
byte[] arg1 = new byte[] { 0x04, (byte) 0xB0 };
for (int i = 0; i < Long.BYTES; i++) {
int pos = Long.BYTES - i - 1;
byte val = (pos < arg1.length) ? arg1[pos] : 0;
buffer.put(val);
}
buffer.flip();
long val = buffer.getLong();
System.out.println(val);
Output is
45060
Going the other way
System.out.println(Integer.toHexString(45060));
b004
An ArrayList may have an Object[16], but that still doesn't mean that its logical size is bigger than the number of elements you've added. You need eight bytes in the buffer to read a long out of it.
If you are trying to use that byte array as an unsigned short, just write leading zero bytes to the buffer. Not sure why you want a long over an int if it's just two bytes, though.
The problem here is with -:
buffer.flip();
flip is used to flip the buffer from read to write mode or write to read mode by resetting the limit as the current position.
If you comment out the line, it will work fine.

int array to byte array with one integer per byte

All related questions I've found here on SO describe the conversion between a byte array and an int array where 4 bytes are converted to a single integer and vice versa.
What I am looking for instead is converting each integer to a single byte and vice versa, knowing that none of the values of the integer array exceeds the range of an unsigned byte.
Is there a library that does that (preferably Guava or Apache commons)? Essentially, I am looking for something like this:
int[] -> byte[]
for (int i = 0; i < intArray.length; i++){
byteArray[i] = (byte) intArray[i];
}
byte[] -> int[]
for (int i = 0; i < byteArray.length; i++){
intArray[i] = 0xff & byteArray[i];
}
You cannot cast arrays in Java in that way. AFAIK, the VM just does not let you reinterpret the bytes in an array as a different type. I assume that you could use some platform-dependent JNI magic to make it so, but that would be extremely hacky.
Edit (removed sample code; added following)
If you are going to reinterpret the same bytes as different primitive types, use a ByteBuffer.
Once declared, you get direct access operations to reinterpreted bytes, such as
myByteBuffer.getInt(1); // reads bytes 4, 5, 6, 7 as an int
myByteBuffer.getByte(5); // reads byte 5 as a byte
You can also extract primitive arrays from there, but there will be extra allocations involved.
Try:
int number = 54353, divisor = 256;
byte[] byteArray = new byte[4];
byteArray[3] = number%divisor;
number = number/divisor
byteArray[2] = number%divisor;
number = number/divisor
byteArray[1] = number%divisor;
number = number/divisor
byteArray[0] = number;

Java ByteBuffer - relative repositioning in a chain of put calls?

Here's what I want to do, except there are two problems with it: position() does an absolute positioning, not relative (and an argument of -1 is thus illegal), and you apparently can't chain another method call following a position() call - the compiler complains that it doesn't recognize putShort().
// Method to create a packet header for sending a packet. The placement of the two numbers is
// done according to little-endian encoding.
private byte[] createPacketHeader(EPacketType packetType, int fourBits,
int totalMessageLength, int segmentSize) {
return ByteBuffer.allocate(CPacketHeaderSize).order(ByteOrder.LITTLE_ENDIAN).
put((byte) ((byte) (packetType.getValue() << 4) | (byte) fourBits)).
putInt(totalMessageLength). // Bottom 3 bytes of total length (+ 1 byte discarded)
position(-1). // Reposition to discard last byte from above call !!DOESN'T WORK!!
putShort((short) segmentSize). // Segment length
put(_connectIdUtf8). // Connection ID in UTF-8, should be <= 10 bytes
array(); // This assumes zero initialization so final bytes are zero
}
So here's what I'm currently doing. It does work, but seems rather inelegant compared to what I was hoping I could do.
ByteBuffer byteBuffer =
ByteBuffer.allocate(CPacketHeaderSize).order(ByteOrder.LITTLE_ENDIAN);
byteBuffer.put((byte) ((byte) (packetType.getValue() << 4) | (byte) fourBits)).
putInt(totalMessageLength). // Bottom 3 bytes of total length (+ 1 byte discarded)
position(byteBuffer.position() -1); // Discard last byte from above call
byteBuffer.putShort((short) segmentSize). // Segment length
put(_connectIdUtf8); // Connection ID in UTF-8, should be <= 10 bytes
return byteBuffer.array(); // This assumes zero initialization so final bytes are zero
Any suggestions as to how I can get back to something closer to my first attempt?
EDIT:
Thanks for the answers, they were all helpful. If anyone is curious, here's what I ended up doing:
// Method to create a packet header for sending a packet. The placement of the two numbers is
// done according to little-endian encoding.
private byte[] createPacketHeader(EPacketType packetType, int fourBits,
int totalMessageLength, int segmentSize) {
return ByteBuffer.allocate(CPacketHeaderSize).order(ByteOrder.LITTLE_ENDIAN).
put((byte) ((byte) (packetType.getValue() << 4) | (byte) fourBits)).
put(intToThreeBytes(totalMessageLength)). // Bottom 3 bytes of total length
putShort((short) segmentSize). // Segment length
put(_connectIdUtf8). // Connection ID in UTF-8, should be <= 10 bytes
array(); // This assumes zero initialization so final bytes are zero
}
// Method to convert an int into a three-byte byte array, using little-endian encoding
private byte[] intToThreeBytes(int aNumber) {
byte[] byteArray = new byte[3];
for (int i = 0; i < 3; i++)
byteArray[i] = (byte)(aNumber >> i * 8);
return byteArray;
}
Missing in elegance too:
byte[] bytes = ByteBuffer.allocate(4).putInt(totalMessageLength).array();
byteBuffer.put(bytes, 0, 3);
I don't think you can. ByteBuffer just doesn't have the functionality to decrement the write cursor in a relative way. The write cursor only increases relatively.
I was thinking you could use mark, but as you are adding 4 bytes in one operation, you can't mark the third for an easy reset.
position method is not defined in ByteBuffer. But in its super class Buffer. So you will have to explicitly typecast to ByteBuffer after calling position method and before calling putShort method. Change the code as below:
return ((ByteBuffer)(ByteBuffer.allocate(CPacketHeaderSize).order(ByteOrder.LITTLE_ENDIAN).
put((byte) ((byte) (packetType.getValue() << 4) | (byte) fourBits)).
putInt(totalMessageLength). // Bottom 3 bytes of total length (+ 1 byte discarded)
position(-1))). // Reposition to discard last byte from above call !!DOESN'T WORK!!
putShort((short) segmentSize). // Segment length
put(_connectIdUtf8). // Connection ID in UTF-8, should be <= 10 bytes
array();

Get single bytes from multi-byte variable in java

How can I split a variable into single bytes in java? I have for example following snippet in C++:
unsigned long someVar;
byte *p = (byte*)(void*) someVar; // byte being typedef unsigned char (from 0 to 255)
byte *bytes = new byte[sizeof(someVar)];
for(byte i = 0;i<sizeof(someVar);i++)
{
bytes[i] = *p++;
}
.... //do something with bytes
I want to accomplish the same under java, but I can't seem to find an obvious workaround.
There are two ways to do it with the ByteBuffer class. One is to create a new byte array dynamically.
long value = 123;
byte[] bytes = ByteBuffer.allocate(8).putLong(value).array();
Another is to write to an existing array.
long value = 123;
byte[] bytes = new byte[8];
ByteBuffer.wrap(bytes).putLong(value);
// bytes now contains the byte representation of 123.
If you use Guava, there is a convenience Longs.toByteArray. It is simply a wrapper for John's ByteBuffer answer above, but if you already use Guava, it's slightly "nicer" to read.

Convert Bytes to bits

I'm working with java.
I have a byte array (8 bits in each position of the array) and what I need to do is to put together 2 of the values of the array and get a value.
I'll try to explain myself better; I'm extracting audio data from a audio file. This data is stored in a byte array. Each audio sample has a size of 16 bits. If the array is:
byte[] audioData;
What I need is to get 1 value from samples audioData[0] and audioData[1] in order to get 1 audio sample.
Can anyone explain me how to do this?
Thanks in advance.
I'm not a Java developer so this could be completely off-base, but have you considered using a ByteBuffer?
Assume the LSB is at data[0]
int val;
val = (((int)data[0]) & 0x00FF) | ((int)data[1]<<8);
As suggested before, Java has classes to help you with this. You can wrap your array with a ByteBuffer and then get an IntBuffer view of it.
ByteBuffer bb = ByteBuffer.wrap(audioData);
// optional: bb.order(ByteOrder.BIG_ENDIAN) or bb.order(ByteOrder.LITTLE_ENDIAN)
IntBuffer ib = bb.asIntBuffer();
int firstInt = ib.get(0);
ByteInputStream b = new ByteInputStream(audioData);
DataInputStream data = new DataInputStream(b);
short value = data.readShort();
The advantage of the above code is that you can keep reading the rest of 'data' in the same way.
A simpler solution for just two values might be:
short value = (short) ((audioData[0]<<8) | (audioData[1] & 0xff));
This simple solution extracts two bytes, and pieces them together with the first byte being the higher order bits and the second byte the lower order bits (this is known as Big-Endian; if your byte array contained Little-Endian data, you would shift the second byte over instead for 16-bit numbers; for Little-Endian 32-bit numbers, you would have to reverse the order of all 4 bytes, because Java's integers follow Big-Endian ordering).
easier way in Java to parse an array of bytes to bits is JBBP usage
class Parsed { #Bin(type = BinType.BIT_ARRAY) byte [] bits;}
final Parsed parsed = JBBPParser.prepare("bit:1 [_] bits;").parse(theByteArray).mapTo(Parsed.class);
the code will place parsed bits of each byte as 8 bytes in the bits array of the Parsed class instance
You can convert to a short (2 bytes) by logical or-ing the two bytes together:
short value = ((short) audioData[0]) | ((short) audioData[1] << 8);
I suggest you take a look at Preon. In Preon, you would be able to say something like this:
class Sample {
#BoundNumber(size="16") // Size of the sample in bits
int value;
}
class AudioFile {
#BoundList(size="...") // Number of samples
Sample[] samples;
}
byte[] buffer = ...;
Codec<AudioFile> codec = Codecs.create(AudioFile.class);
AudioFile audioFile = codec.decode(buffer);
You can do it like this, no libraries or external classes.
byte myByte = (byte) -128;
for(int i = 0 ; i < 8 ; i++) {
boolean val = (myByte & 256) > 0;
myByte = (byte) (myByte << 1);
System.out.print(val ? 1 : 0);
}
System.out.println();
byte myByte = 0x5B;
boolean bits = new boolean[8];
for(int i = 0 ; i < 8 ; i++)
bit[i] = (myByte%2 == 1);
The results is an array of zeros and ones where 1=TRUE and 0=FALSE :)

Categories

Resources