Convert byte[] to Buffer type - java

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.

Related

Why some Java functions requires bytes array length when byte arrays object was already provided in the argument?

While writing Java code, I really wonder why some functions require byte arrays length as an argument when the first argument was byte arrays object. Why they don't get the length from the object provided?
For example:
// E.g.: 1. Bitmap
byte[] bytes = task.getResult();
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
// E.g.: 2. Datagram
byte[] data = new byte[1024];
DatagramPacket request = new DatagramPacket(data, data.length);
If they want the length, why they don't use data.length?
The byte array is a buffer to which data, the length of which is less than the length of the buffer, is read. The length parameter defines the amount of bytes in the buffer that are relevant. You're not supposed to pass the length of the buffer in the parameter, that would be redundant. You're supposed to pass the number of bytes in the buffer that contain actual data.
The API documentation of DatagramPacket, for example, reveals this.
length - the number of bytes to read
The simple answer is: most read methods (in Java, and any other language) that operate on buffer arrays have to tell you the exact number of bytes that were actually read.
Keep in mind: that array is an buffer. The default behavior is that buffer.length or less bytes can be read. So, knowing how long the buffer is doesn't help you. You have to know how many bytes were actually put into the buffer.
Broadly a buffer is used as a temporary data in a data loading processing.
You fill the buffer until its size or less but never more than its capacity of course.
The DatagramPacket javadoc confirms that :
The length argument must be less than or equal to buf.length.
And a thing that you don't have to forget : conceptually you use a buffer because the data has to be progressively loaded or only a specific part of that.
In some cases you will read as much data as its maximal capacity but in some other cases you need to read only the X first bytes or the bytes from X to Y offset.
So the buffer class methods provide generally multiple way to read from the buffer.
Such as :
public DatagramPacket(byte buf[], int length);
public DatagramPacket(byte buf[], int offset, int length);
Now conceptually you are not wrong, sometimes you want to fill the whole buffer because you know that you will need to read exactly this size of data.
The java.net.DatagramSocket confirms that :
public synchronized void receive(DatagramPacket p) throws IOException {
...
tmp = new DatagramPacket(new byte[1024], 1024);
...
}
So an additional overloading such as :
public DatagramPacket(byte buf[]);
would make sense.
Because the data that you want to read can be less than or equal to byte[] buf's length.
Below is the API documentation :
public DatagramPacket(byte[] buf,
int length)
Constructs a DatagramPacket for receiving packets of length length.
The length argument must be less than or equal to buf.length.
Parameters:
buf - buffer for holding the incoming datagram.
length - the number of bytes to read.
https://docs.oracle.com/javase/7/docs/api/java/net/DatagramPacket.html

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.

How to use Wrap Method of ByteBuffer in 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

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);

Bitmap LockBits on Android?

My program on Android uses an algorithm that uses a lot of setPixel and getPixel, therefore, it's very slow. On .NET, I can use LockBits to make it faster. Is there LockBits or similar on Java or Android?
EDIT: After some searches, I found copyPixelToBuffer and copyPixelFromBuffer, wonder if it is what I need?
Yes, you should use the above two methods and make use of a ByteBuffer object where you will be first storing all the bitmap data. After doing so, copy all the buffer data into a byte array and then you can do all you argb manipulations within this array. After all done, wrap this byte array into a newly allocated ByteBuffer and then finally copy the pixels back from this buffer into the original bitmap.
Here's some sample:
"bmpData" is your Bitmap object holding image pixel data.
int size = bmpData.getRowBytes()*bmpData.getHeight()*4;
ByteBuffer buf = ByteBuffer.allocate(size);
bmpData.copyPixelsToBuffer(buf);
byte[] byt = buf.array();
for(int ctr=0;ctr<size;ctr+=4)
{
//access array in form of argb. for ex. byt[0] is 'r', byt[1] is 'g' and so on..
}
ByteBuffer retBuf = ByteBuffer.wrap(byt);
bmpData.copyPixelsFromBuffer(retBuf);

Categories