Obtain low and high order nybbles from byte within Java ByteBuffer - java

I need to extract two integer values from a byte stored within a ByteBuffer (little endian order)
ByteBuffer bb = ByteBuffer.wrap(inputBuffer);
bb.order(ByteOrder.LITTLE_ENDIAN);
The values I need to obtain from any byte within the ByteBuffer are:
length = integer value of low order nibble
frequency = integer value of high order nibble
At the moment I'm extracting the low order nybble with this code:
length = bb.getInt(index) & 0xf;
Which seems to work perfectly well. It is however the high order nybble that I seem to be having trouble interpreting correctly.
I get a bit confused with bit shifting or masking, which I think I need to perform, and any advice would be super helpful.
Thanks muchly!!

I need to extract two integer values from a byte
So you need to get a byte not an int, and the byte order doesn't matter.
int lowNibble = bb.get(index) & 0x0f; // the lowest 4 bits
int hiNibble = (bb.get(index) >> 4) & 0x0f; // the highest 4 bits.

To get the high order nibble, all you need to do is bit shift; the low order bits will simply fall off.
int val = 0xAB;
int lo = val & 0xF;
int hi = val >> 4;
System.out.println("hi is " + Integer.toString(hi, 16));
System.out.println("lo is " + Integer.toString(lo, 16));

Related

Don't understand how these bitwise operators operate on bytes and integers

I am working with some code that takes in a binary file as input. However, I am having trouble understanding the for loop in the code, as I don't understand what the bitwise operators do to IFD_Address, such as the |=, <<, and & 0xff. I think IFD_Address refers to a pointer in the binary file, but I am not sure. What is this piece of code trying to achieve?
byte[] IFD_Address_tmp = Arrays.copyOfRange(bytes, 4, 8);
int IFD_Address = 0;
int i = 0;
int shiftBy = 0;
for (shiftBy = 0; shiftBy < 32; shiftBy += 8) {
IFD_Address |= ((long) (IFD_Address_tmp[i] & 0xff)) << shiftBy;
i++;
}
This behavior is best understood in terms of moving bits around, not numbers. Bytes comprise eight bits, integers, 32 bits. The loop basically takes each byte in the array and places the corresponding bits in the integer IFD_Address in 8-bit chunks, from right (least significant) to left (most significant), like this:
About the bitwise operations:
& 0xff is required to capture the 8 bits into an integer;
<< shifts the bits to the left to select the appropriate place in IFD_Address;
|= sets the bits in IFD_Address.
See this tutorial for details.

How can I concatenate two bytes in java?

I have an integer called writePos that takes a value between [0,1023]. I need to store it in the last two bytes of a byte array called bucket. So, I figure I need to represent it as a concatenation of the array's last two bytes.
How would I go about breaking down writePos into two bytes that, when concatenated and cast into an int, produces writePos again?
How would I go about concatenating once I get it broken down into the bytes?
This would be covered high-level by a ByteBuffer.
short loc = (short) writeLocation;
byte[] bucket = ...
int idex = bucket.length - 2;
ByteBuffer buf = ByteBuffer.wrap(bucket);
buf.order(ByteOrder.LITTLE__ENDIAN); // Optional
buf.putShort(index, loc);
writeLocation = buf.getShort(index);
The order can be specified, or left to the default (BIG_ENDIAN).
The ByteBuffer wraps the original byte array, and changes to ByteBuffer effect on the byte array too.
One can use sequential writing and reading an positioning (seek), but here I use overloaded methods for immediate positioning with index.
putShort writes to the byte array, modifying two bytes, a short.
getShort reads a short from the byte array, which can be put in an int.
Explanation
A short in java is a two-byte (signed) integral number. And that is what is meant. The order is whether LITTLE_ENDIAN: least significant byte first (n % 256, n / 256) or big endian.
Bitwise operations.
To byte:
byte[] bytes = new byte[2];
// This uses a bitwise and (&) to take only the last 8 bits of i
byte[0] = (byte)(i & 0xff);
// This uses a bitwise and (&) to take the 9th to 16th bits of i
// It then uses a right shift (>>) then move them right 8 bits
byte[1] = (byte)((i & 0xff00) >> 8);from byte:
To go back the other way
// This just reverses the shift, no need for masking.
// The & here is used to handle complications coming from the sign bit that
// will otherwise be moved as the bytes are combined together and converted
// into an int
i = (byte[0] & 0xFF)+(byte[1] & 0xFF)<<8;
There is a working example here of some of the conversions that you can play around with:
http://ideone.com/eRzsun
You need to split the integer into two bytes. The high and the low byte. Following your description it's stored as bug endian in the array.
int writeLocation = 511;
byte[] bucket = new byte[10];
// range checks must be done before
// bitwise right rotation by 8 bits
bucket[8] = (byte) (writeLocation >> 8); // the high byte
bucket[9] = (byte) (writeLocation & 0xFF); // the low byte
System.out.println("bytes = " + Arrays.toString(bucket));
// convert back the integer value 511 from the two bytes
bucket[8] = 1;
bucket[9] = (byte) (0xFF);
// the high byte will bit bitwise left rotated
// the low byte will be converted into an int
// and only the last 8 bits will be added
writeLocation = (bucket[8] << 8) + (((int) bucket[9]) & 0xFF);
System.out.println("writeLocation = " + writeLocation);

Byte to "Bit"array

A byte is the smallest numeric datatype java offers but yesterday I came in contact with bytestreams for the first time and at the beginning of every package a marker byte is send which gives further instructions on how to handle the package. Every bit of the byte has a specific meaning so I am in need to entangle the byte into it's 8 bits.
You probably could convert the byte to a boolean array or create a switch for every case but that can't certainly be the best practice.
How is this possible in java why are there no bit datatypes in java?
Because there is no bit data type that exists on the physical computer. The smallest allotment you can allocate on most modern computers is a byte which is also known as an octet or 8 bits. When you display a single bit you are really just pulling that first bit out of the byte with arithmetic and adding it to a new byte which still is using an 8 bit space. If you want to put bit data inside of a byte you can but it will be stored as a at least a single byte no matter what programming language you use.
You could load the byte into a BitSet. This abstraction hides the gory details of manipulating single bits.
import java.util.BitSet;
public class Bits {
public static void main(String[] args) {
byte[] b = new byte[]{10};
BitSet bitset = BitSet.valueOf(b);
System.out.println("Length of bitset = " + bitset.length());
for (int i=0; i<bitset.length(); ++i) {
System.out.println("bit " + i + ": " + bitset.get(i));
}
}
}
$ java Bits
Length of bitset = 4
bit 0: false
bit 1: true
bit 2: false
bit 3: true
You can ask for any bit, but the length tells you that all the bits past length() - 1 are set to 0 (false):
System.out.println("bit 75: " + bitset.get(75));
bit 75: false
Have a look at java.util.BitSet.
You might use it to interpret the byte read and can use the get method to check whether a specific bit is set like this:
byte b = stream.read();
final BitSet bitSet = BitSet.valueOf(new byte[]{b});
if (bitSet.get(2)) {
state.activateComponentA();
} else {
state.deactivateComponentA();
}
state.setFeatureBTo(bitSet.get(1));
On the other hand, you can create your own bitmask easily and convert it to a byte array (or just byte) afterwards:
final BitSet output = BitSet.valueOf(ByteBuffer.allocate(1));
output.set(3, state.isComponentXActivated());
if (state.isY){
output.set(4);
}
final byte w = output.toByteArray()[0];
How is this possible in java why are there no bit datatypes in java?
There are no bit data types in most languages. And most CPU instruction sets have few (if any) instructions dedicated to adressing single bits. You can think of the lack of these as a trade-off between (language or CPU) complexity and need.
Manipulating a single bit can be though of as a special case of manipulating multiple bits; and languages as well as CPU's are equipped for the latter.
Very common operations like testing, setting, clearing, inverting as well as exclusive or are all supported on the integer primitive types (byte, short/char, int, long), operating on all bits of the type at once. By chosing the parameters appropiately you can select which bits to operate on.
If you think about it, a byte array is a bit array where the bits are grouped in packages of 8. Adressing a single bit in the array is relatively simple using logical operators (AND &, OR |, XOR ^ and NOT ~).
For example, testing if bit N is set in a byte can be done using a logical AND with a mask where only the bit to be tested is set:
public boolean testBit(byte b, int n) {
int mask = 1 << n; // equivalent of 2 to the nth power
return (b & mask) != 0;
}
Extending this to a byte array is no magic either, each byte consists of 8 bits, so the byte index is simply the bit number divided by 8, and the bit number inside that byte is the remainder (modulo 8):
public boolean testBit(byte[] array, int n) {
int index = n >>> 3; // divide by 8
int mask = 1 << (n & 7); // n modulo 8
return (array[index] & mask) != 0;
}
Here is a sample, I hope useful for you!
DatagramSocket socket = new DatagramSocket(6160, InetAddress.getByName("0.0.0.0"));
socket.setBroadcast(true);
while (true) {
byte[] recvBuf = new byte[26];
DatagramPacket packet = new DatagramPacket(recvBuf, recvBuf.length);
socket.receive(packet);
String bitArray = toBitArray(recvBuf);
System.out.println(Integer.parseInt(bitArray.substring(0, 8), 2)); // convert first byte binary to decimal
System.out.println(Integer.parseInt(bitArray.substring(8, 16), 2)); // convert second byte binary to decimal
}
public static String toBitArray(byte[] byteArray) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < byteArray.length; i++) {
sb.append(String.format("%8s", Integer.toBinaryString(byteArray[i] & 0xFF)).replace(' ', '0'));
}
return sb.toString();
}

Convert long to "unsigned, 4 byte integer in network byte order" with ByteBuffer

The protocol I'm using requires sending back the current position in a file as a "unsigned, 4 byte integer in network byte order". There are several questions on this, but they are assuming I'm using Integers, not Longs
I am attempting to port this to NIO's ByteBuffer so it can be sent in the socket channel:
long bytesTransfered = ... some number of bytes transfered...
//TODO: What does this actually do?
outBuffer[0] = (byte) ((bytesTransfered >> 24) & 0xff);
outBuffer[1] = (byte) ((bytesTransfered >> 16) & 0xff);
outBuffer[2] = (byte) ((bytesTransfered >> 8) & 0xff);
//TODO: Why does netbeans say this does nothing?
outBuffer[3] = (byte) ((bytesTransfered >> 0) & 0xff);
Are their any methods in ByteBuffer that accomplish this? Hopefully in a more obvious, self-descriptive way then the bit-shifting magic above?
Whether signed or unsigned, the bits are the same.
If you cast a long to an int, the JVM discards the high-order bits. The issue comes when promoting an int to a long: Java will sign-extend the value, filling in the high-order bits of the long with the most-significant bit of the int.
To resolve this problem, simply apply a mask to the long. The following should make this clear:
long value = Integer.MAX_VALUE + 1234L;
System.out.println("original value = " + value);
int iValue = (int)value;
System.out.println("value as int = " + iValue);
byte[] array = new byte[4];
ByteBuffer buf = ByteBuffer.wrap(array);
buf.putInt(0, iValue);
int iRetrieved = buf.getInt(0);
System.out.println("int from buf = " + iRetrieved);
long retrieved = iRetrieved;
System.out.println("converted to long = " + retrieved);
retrieved = retrieved & 0xFFFFFFFFL;
System.out.println("high bytes masked = " + retrieved);
However, be aware that you still have only 32 bits. If the filesizes is greater than 4Gb you won't be able to fit it into 4 bytes (and if you have to worry about files > 2G, then you should worry about files > 4G).
That's exactly what ByteBuffer.putInt() is for. You say you're using long but you also only want to write four bytes, so you'll have to cast your long to int. Or else use putLong() and get 8 bytes.

Is there a way to represent int value in byte over 127 without doing bitwise operations?

I am really short on time for doing the learning of bitwise operations.
I want to convert large integer(>127) values without doing '<<' or anything similar.
I need byte representation of integer values used to identify sequence numbers of packets in header sent across UDP. If there is no solution I will introduce two bytes..
Something like: 1, 1 ; 1,2 ; 1,3 ; packet lost ; 1,4 ; packet lost; 2,1 ,2,2
and then reset it upon reaching 127; 127
I can introduce third, but this is rather ugly.
It would be really useful to have black box that is part of java api doing all that byte conversion for me. Is there?
Thanks,
To pack an unsigned 8-bit value into a byte:
static byte toByte(int i) {
if ((i < 0) || (i > 255))
throw new IllegalArgumentException(String.valueOf(i));
return (byte) i;
}
To convert back:
static int toInt(byte b) {
return (b < 0) ? (b + 256) : b;
}
After reading your comments on other answers, it sounds like you might want something like this:
byte[] b = BigInteger.valueOf(counter).toByteArray();
and
long counter = new BigInteger(b).longValue();
Since the length of the array would vary as the counter grows, you'd need some way to indicate its length or delimit it. But this technique will convert any integer value to an array of bytes.
Is the problem that you want unsigned bytes, as in, numbers between 128 and 255 inclusive?
That's...tricky. The Java language won't let you directly treat bytes as unsigned...but with library support it gets a little easier. Guava provides an UnsignedBytes utility class for some of these needs. Addition, multiplication, and subtraction are all exactly the same on signed and unsigned bytes.
EDIT: Judging from your additional comments, you might be interested in Ints.toByteArray(int) and the like, which work on types between byte and BigInteger.
According to my understanding, you want to separate an int into 4 bytes. If so, then just copy paste this code:
int i = /* your int */
int[] b = { (i >> 24) & 0xff, (i >> 16) & 0xff, (i >> 8) & 0xff, i & 0xff };
Indices 0-3 are each of the 4 bytes in the int.

Categories