How to use Wrap Method of ByteBuffer in Java - java

Okay, so I was looking up what the best way to convert from a byte array to it's numeric value in java was and I came across this link. And the second answer mentions the use of the ByteBuffer class. For those that do not wish to click on the link, originally the question asks if I have:
byte[] by = new byte[8];
How does one convert that to int? Well the answer goes...
ByteBuffer bb = ByteBuffer.wrap(new byte[] {0, 0, 0, 0, 0, 0, 0, 4});
long l = bb.getLong();
System.out.println(l);
Result
4
And that is awesome to learn, but I just want to confirm something before going that route.
Say I have a previously read in byte array that is 8 bytes long.
byte[] oldByte = new byte[8];
then I do...
ByteBuffer bb = ByteBuffer.wrap(new byte[] {oldByte[2], oldByte[3]});
int intValue = bb.getInt();
Will that work/be read in the same manner as the previous example?

The documentation for the ByteBuffer class specifies that the getInt() method reads the next four bytes, so if you are only passing two bytes to the call to wrap, you will get a BufferUnderflowException:
Throws: BufferUnderflowException - If there are fewer than four bytes remaining in this buffer

Related

Convert array of doubles to byte array: What is the Java way of C# Buffer.BlockCopy?

I need to serialize an array of doubles to base64 in Java. I have following method from C#
public static string DoubleArrayToBase64( double[] dValues ) {
byte[] bytes = new byte[dValues.Length * sizeof( double )];
Buffer.BlockCopy( dValues, 0, bytes, 0, bytes.Length );
return Convert.ToBase64String( bytes );
}
How do I do that in Java? I tried
Byte[] bytes = new Byte[abundaceArray.length * Double.SIZE];
System.arraycopy(abundaceArray, 0, bytes, 0, bytes.length);
abundanceValues = Base64.encodeBase64String(bytes);
however this leads to an IndexOutofBoundsException.
How can I achieve this in Java?
EDIT:
Buffer.BlockCopy copies on byte level, the last paramter is number of bytes. System.arraycopy last parameter is number of elements to copy. So yes it should be abundaceArray.length but then a ArrayStoreException is thrown.
EDIT2:
The base64 string must be the same as the ine created with the c# code!
You get an ArrayStoreException when the array types on the method are not the same primitive, so double to byte will not work. Here is a workaround i patched up that seems to work. I do not know of any method in the java core that does automatic conversion from primitive to byte block :
public class CUSTOM {
public static void main(String[] args) {
double[] arr = new double[]{1.1,1.3};
byte[] barr = toByteArray(arr);
for(byte b: barr){
System.out.println(b);
}
}
public static byte[] toByteArray(double[] from) {
byte[] output = new byte[from.length*Double.SIZE/8]; //this is reprezented in bits
int step = Double.SIZE/8;
int index = 0;
for(double d : from){
for(int i=0 ; i<step ; i++){
long bits = Double.doubleToLongBits(d); // first transform to a primitive that allows bit shifting
byte b = (byte)((bits>>>(i*8)) & 0xFF); // bit shift and keep adding
int currentIndex = i+(index*8);
output[currentIndex] = b;
}
index++;
}
return output;
}
}
The Double.SIZE get 64 which is number of bits I suggest to initialize the array like this
Byte[] bytes = new Byte[abundaceArray.length * 8];
Not sure what this C# function does, but I suspect you should replace this line
System.arraycopy(abundaceArray, 0, bytes, 0, bytes.length);
with this
System.arraycopy(abundaceArray, 0, bytes, 0, abundaceArray.length);
I'm guessing you're using the apache commons Base64 class. That only has methods accepting an array of bytes (the primitive type), not Bytes (object wrapper around primitive type).
It's not clear what type your 'abundaceArray' is - whether it's doubles or Doubles.
Either way, you can't use System.arraycopy to copy between arrays of difference primitive types.
I think your best bet is to serialise your array object to a byte array, then base64 encode that.
eg:
ByteArrayOutputStream b = new ByteArrayOutputStream(); // to store output from serialization in a byte array
ObjectOutputStream o = new ObjectOutputStream(b); // to do the serialization
o.writeObject(abundaceArray); // arrays of primitive types are serializable
String abundanceValues = Base64.encodeBase64String(b.toByteArray());
There is of course an ObjectInputStream for going in the other direction at the other end.

Parse a DatagramPacket after converting it to a byte array in Java

I am trying to parse a DatagramPacket that I will receive at a socket. I know the format of the packet I will receive, which is a DHCPREQUEST packet, but I don't think that really matters. For simplicity's sake, let's just consider the first six fields:
First field is the "opcode", which is 1 byte.
Second field is the "hardware type" which is 1 byte.
Third, "hardware address length", 1 byte.
Fourth, "hops", 1 byte.
Fifth, "transaction identifier xid", 4 bytes.
Sixth, "seconds", 2 bytes.
After I receive the packet, my approach is to convert it to a byte array.
DatagramPacket request = new DatagramPacket(new byte[1024], 1024);
socket.receive(request);
byte[] buf = request.getData();
At this point, the packet is stored in the byte array buf as a series of bytes. Since I know what the structure of this byte sequence is, how can I parse it? The one-byte fields are simple enough, but how about the multiple-bit fields? For example, how can I extract bytes 4 to 7, and store them in a variable named xid?
I could manually put each byte into an array:
byte[] xid = new byte[4];
xid[0] = buf[4];
xid[1] = buf[5];
xid[2] = buf[6];
xid[3] = buf[7];
But that's just tedious, and impractical for fields that are hundreds of bytes in length. The String class can parse substrings given an offset and length; is there a similar method for byte arrays in Java?
Or am I somehow making things difficult for myself?
Wrap the byte array in a ByteArrayOutputStream; wrap a DataInputStream around that; then use the methods of DataInputStream.
The cleanest way to do something like this is probably to use the utility method Arrays.copyOfRange.
What you do is write yourself some helper methods to extract 2 byte, 4 byte, etc values from the packet, reading the bytes and assembling them into Java short, int or whatever values.
For example
public short getShort(byte[] buffer, int offset) {
return (short) ((buffer[offset] << 8) | buffer[offset + 1]);
}
Then you use these helper methods as often as you need to. (If you want to be fancy, you could have the methods update an attribute that holds the current position, so that you don't have to pass an offset argument.)
Alternatively, if you were not worried by the overheads, you could wrap the byte array in ByteArrayInputStream and a DataInputStream, and use the latter's API to read bytes, shorts, ints, and so on. IIRC, DataInputStream assumes that numbers are represented in the stream in "network byte order" ... which is almost certainly what the DHCP spec mandates.
I'm a bit late to this, but there's a ByteBuffer class:
ByteBuffer b = ByteBuffer.wrap(request.getData());
byte opcode = b.get();
byte hwtype = b.get();
byte hw_addr_len = b.get();
byte hops = b.get();
int xid = b.getInt();
short seconds = b.getShort();
Or, if you only need a single field:
ByteBuffer b = ByteBuffer.wrap(request.getData());
int xid = b.getInt(4);

Convert byte[] to Buffer type

I am working in Android. I need to convert byte[] to Buffer type. In Android, I have seen a type Buffered that I needed to use in particular functions. But, I my data source is type byte[].
Take a look at ByteBuffer.wrap:
byte[] bytes = ...;
Buffer buf = ByteBuffer.wrap(bytes);
There's also a ByteBuffer.wrap(byte[] array, int start, int byteCount) if you only want to wrap part of an array.

ByteBuffer api giving wrong integer values

I am using ByteBuffer APIs to convert an object into bytes. The object's class is as follows
public class Obj{
int a; // size 1 byte
int b; // size 4 bytes
int c; // size 4 bytes
}
Using ByteBuffer API, I have allocated an object
ByteBuffer bbf = ByteBuffer.allocate(9);
bbf.put((byte) this.getA());
bbf.putInt(this.getB());
bbf.putInt(this.getC());
byte[] msg = bbf.array();
I set the value of B as 100 but when I convert the byte array from offset 1 till length 4, I get a different integer value.
Any idea where is the problem?
thanks!
The code works as it should, and if you indeed select bytes with index 1,2,3,4 they will yield the value 100:
ByteBuffer bbf = ByteBuffer.allocate(9);
bbf.put((byte) 10);
bbf.putInt(100);
bbf.putInt(55);
byte[] msg = bbf.array();
byte[] from4to8 = Arrays.copyOfRange(msg, 1, 5);
ByteBuffer buf2 = ByteBuffer.wrap(from4to8);
System.out.println(buf2.getInt()); // Prints 100
Some notes:
Keep in mind that the endian may differ from system to system (so check the endian on both hosts if this is part of a protocol)
The array you get from the bbf.array() call is a backing array, i.e.:
Modifications to this buffer's content will cause the returned array's content to be modified, and vice versa.
As far as I can see, B is at offset 1

Addup differently byte-sized fields in Java?

I am coding some sort of packet which has different fields with different length in bytes.
So field1 is 2 byte long field2 is 3 bytes long field3 is 6 bytes long and when I addup these fields, I should be getting 11 bytes in length.
But I have no idea how I can declare something with this byte long.
Use an array:
byte[] byteArray = new byte[11];
How's about:
byte[] arr = new byte[11];
You could use a class to represent your packet:
public class Packet
{
public byte[] Field1, Field2, Field3;
public Packet(byte[] packetBytes)
{
ByteBuffer packet = ByteBuffer.wrap(packetBytes);
Field1 = new byte[2];
Field2 = new byte[3];
Field3 = new byte[6];
packet.get(Field1, 0, 2);
packet.get(Field2, 2, 3);
packet.get(Field3, 5, 6);
}
}
ByteBuffer is good for byte-manipulation.
I have found that java.nio.ByteBuffer is typically better for this sort of thing. It has nice methods for dealing with interpreting the bytes in the buffer. The docs are here.
import java.nio.ByteBuffer;
ByteBuffer buffer = ByteBuffer.allocate(11);
Check out the docs and look at the nice methods such as getInt() and getChar().
Java has a limited collection of primitive types, which all have a fixed size. You can see a list of them here. That means you can't decide how many bytes your variable will consist of.
Of course, as others have already mentioned, you can always create a new byte[11]. Note that Java's byte is signed, however. It goes from -128 to 127, not from 0 to 255.
I recommend the utility classes in Javolution for dealing with binary protocol streams such as this. They've come in handy for me several times when dealing with low-level binary streams.
You should probably design your code to separate the message you want to manipulate in java from the wire level format you need to read/write.
e.g. If you have a ScreenResolution concept, you could represent it in java with a ScreenResolution class:
public class ScreenResolution {
public int height;
public int width;
}
This class is easy to work with in Java. Transforming this to a packet that can be transmitted over a network/saved to a file, etc. according to some file format or protocol is another concern.
Say the height and width is to be laid out in 3 bytes each, with some ID and length for the "wire format", you make something like
public byte[] marshalScreenResolution(ScreenResolution obj) {
byte[] buf = new byte[9];
//length of this packet, 2 bytes
buf[0] = 0;
buf[1] = 9;
buf[2] = SCREENRESOLUTION_OPCODE;
//marshal the height/width , 3 least significant bytes.
buf[3] = (obj.height&0xff0000) >> 16;
buf[4] = (obj.height&0x00ff00) >> 8;
buf[5] = (obj.height&0x0000ff) ;
buf[6] = (obj.width&0xff0000) >> 16;
buf[7] = (obj.width&0x00ff00) >> 8;
buf[8] = (obj.width&0x0000ff) ;
return buf;
}
And you make a demarshalScreenResolution function for going from a packet to a ScreenResolution object. The point is you decouple the representation in java from the external representation, and you assemble the fields in the external representation using bytes + some basic bit fiddling.

Categories