Get two raw bytes from a single char - java

Size of char in Java is two bytes. How can I get raw bytes from a char variable?
var ch = '文';
var b1 = // ?
var b2 = // ?

You can perform bitwise arithmetic on char to access the individual bytes:
var b1 = (byte) ch;
var b2 = (byte) (ch >> 8);
System.out.printf("%02x %02x\n", b1, b2);
// 87 65

This is probably just simple math.
byte b1 = (byte)(0xFF & ch);
byte b2 = (byte)(0xFF & (ch >> 8));
Let us know if this works for you. Be aware that byte is signed and this will yield negative numbers about half the time.

Related

java - convert bytes to integer - why AND each byte with 0xff?

What is the difference between:
int n = (b1 & 0xff) << 24 | (b2 & 0xff) << 16 | (b3 & 0xff) << 8 | b4 & 0xff
and
int n = b1 << 24 | b2 << 16 | b3 << 8 | b4
? Why should we AND each byte with 255?
First you need to understand that b1 <<< 24 expects the a operand to be of type int or long. So, if b1 is a byte, Java will convert it to an int before the shift takes place.
That conversion happens by mapping each byte value into the corresponding int value. The problem is that byte is a signed type, which means that the possible values are -128 through to +127. Therefore, when you convert a byte with a negative value, you will get an int with a negative value; e.g. the byte 11111111 (binary) which is -1 becomes 11111111111111111111111111111111 (binary) which is also -1.
Those leading ones are the result of sign extension, and we do NOT want them if we are about to shift them and combine them in a bitwise fashion.
Hence, you will often see a byte being masked with 0xff to remove the (unwanted) results of sign extension after the conversion. For example
11111111111111111111111111101110 &
00000000000000000000000011111111
gives
00000000000000000000000011101110
Let me assume types of b1, b2, b3 and b4 are byte.
In this case, their values will be sign extended and if they are negative, the result will be wrong if AND isn't used.
Demo:
class Test {
public static void main(String[] args) {
byte a = (byte)128;
int x1 = a << 8;
int x2 = (a & 0xff) << 8;
System.out.println(x1);
System.out.println(x2);
}
}
Output:
-32768
32768

Convert Integer to Hex String

i have an Integer value and i want to convert it on Hex.
i do this:
private short getCouleur(Integer couleur, HSSFWorkbook classeur) {
if (null == couleur) {
return WHITE.index;
} else {
HSSFPalette palette = classeur.getCustomPalette();
String hexa = Integer.toHexString(couleur);
byte r = Integer.valueOf(hexa.substring(0, 2), 16).byteValue();
byte g = Integer.valueOf(hexa.substring(2, 4), 16).byteValue();
byte b = Integer.valueOf(hexa.substring(4, 6), 16).byteValue();
palette.setColorAtIndex((short) 65, r, g, b);
return (short) 65;
}
}
In output i have this:
couleur: 65331
Hexa: FF33
hexa.substring(0, 2): FF
hexa.substring(2, 4): 33
hexa.substring(4, 6):
r: -1
g: 51
b: error message
error message: String index out of range: 6
Thx.
you can call the method in JDK.
String result = Integer.toHexString(131);
If I understand correctly you want to split an int into three bytes (R, G, B).
If so, then you can do this by simply shifting the bits in the integer:
byte r = (byte)((couleur >> 16) & 0x000000ff);
byte g = (byte)((couleur >> 8) & 0x000000ff);
byte b = (byte)(couleur & 0x000000ff);
That's much more efficient. You don't have to do it through conversion to String.
The problem is that you are assuming that the hex string will be six digits long.
try String.format ("%06d", Integer.toHexString(couleur));
to pad it with zeros if less than 6 digits longs

Reverse bytes order of long

I've got a long variable and I need to reverse its byte order. For example: B1, B2, ... , B8 I should return a long that consists of B8, B7, ..., B1. How can I do it by using bitwise operations?
you can use Long.reverseBytes(long)
Or for more methods which include bitwise operations, you can refer to this stack overflow question
Heres another method you may like, I'd still recommend the above but it's better than bitwise where you can easily make mistakes.
Bytebuffer
byte[] bytes = ByteBuffer.allocate(8).putLong(someLong).array();
for (int left = 0, right = bytes.length - 1; left < right; ++left, --right) {
byte temp = bytes[left];
bytes[left] = bytes[right];
bytes[right] = temp;
}
I am trying to steer you away from bitwise solutions because they are cumbersome and very easy to mess up if you do not know what you are doing... But bitwise would look like this:
byte[] bytes = new byte[8];
// set the byte array from smallest to largest byte
for(int i = 0; i < 8; ++i) {
byte[i] = (your_long >> i*8) & 0xFF;
}
// build the new long from largest to smallest byte (reversed)
long l = ((buf[0] & 0xFFL) << 56) |
((buf[1] & 0xFFL) << 48) |
((buf[2] & 0xFFL) << 40) |
((buf[3] & 0xFFL) << 32) |
((buf[4] & 0xFFL) << 24) |
((buf[5] & 0xFFL) << 16) |
((buf[6] & 0xFFL) << 8) |
((buf[7] & 0xFFL) << 0) ;
You might want to use Long.reverseBytes instead of using bitwise operations. See the Java Reference for details.
Otherwise, you could have a look at the JDK sources (src.zip in your JDK folder) in Long.java but mind the copyright by Oracle.
Here's an old trick that you can use to endian swap a register:
static long swapblock(long a, long mask, int shift) {
long b1 = a & mask; // extract block
long b2 = a ^ b1; // extract remaining bits
return (b1 << shift) |
((b2 >> shift) & mask); // mask again to clear sign extension
}
static long endianswap(long a) {
a = swapblock(a, 0x00000000ffffffffL, 32);
a = swapblock(a, 0x0000ffff0000ffffL, 16);
a = swapblock(a, 0x00ff00ff00ff00ffL, 8);
return a;
}
The idea is to progressively swap sub blocks until you reach the desired level you want to stop at. By adding swaps of sizes 4, 2, and 1, you can change this into a bit mirror function.
There is only one tricky bit due to lack of unsigned types in java. You need to mask out high order bits when shifting right, because the sign bit is replicated by the shift amount, filling the high order bits with ones (0x8000000000000000 >> 8 is 0xFF80000000000000).
long reverse(long x){
x = (x >> 32) | (x << 32); // step 1
x = ((x & 0xffff0000ffff0000 ) >> 16)
| ((x & 0x0000ffff0000ffff ) << 16); // step 2
x = ((x & 0xff00ff00ff00ff00 ) >> 8)
| ((x & 0x00ff00ff00ff00ff ) << 8); // step 3
return x;
}
If we assume that bitwise operator works in O(1) time, reverse function works in O(lg(number of bits) ) time.
Explanation
Step 0 : B1 B2 B3 B4 B5 B6 B7 B8
Step 1 : B5 B6 B7 B8 B1 B2 B3 B4
Step 2 : B7 B8 B5 B6 B3 B4 B1 B2
Step 3 : B8 B7 B6 B5 B4 B3 B2 B1
Plain answer with loops:
public static long byteReverse(long a) {
long result = 0;
for(int i = 0; i < 8; i++){
// grab the byte in the ith place
long x = (a >> (i*8)) & (0b11111111);
result <<= 8;
result |= x;
}
return result;
}
bitwise only:
public static long byteReverse(long a) {
a = (a << 32) | (a >>> 32);
a = ((a & 0xffff0000ffff0000L) >>> 16) | ((a & 0x0000ffff0000ffffL) << 16);
a = ((a & 0x00ff00ff00ff00ffL) << 8) | ((a & 0xff00ff00ff00ff00L) >>> 8);
return a;
}

Java stripping zeros from function

I'm trying to flip some bytes around in Java and the function I have is working correctly for some bytes and failing for others.
The function I am using is this:
public static int foldInByte(int m, int pos, byte b) {
int tempInt = (b << (pos * 8));
tempInt = tempInt & (0x000000ff << (pos * 8));
m = m | tempInt;
return m;
}
And the code that implements this is:
byte[] bitMaskArray = new byte[]{
byteBuffer.get(inputIndex),
byteBuffer.get(inputIndex + 1),
byteBuffer.get(inputIndex + 2),
byteBuffer.get(inputIndex + 3)};
int tempInt = 0;
tempInt = foldInByte(0, 3, bitMaskArray[3]);
tempInt = foldInByte(tempInt, 2, bitMaskArray[2]);
tempInt = foldInByte(tempInt, 1, bitMaskArray[1]);
tempInt = foldInByte(tempInt, 0, bitMaskArray[0]);
bitMask = tempInt;
The bytes are being read from a ByteBuffer with the byteOrder being Little Endian.
For example, the bytes 00 01 B6 02 set the bitMask to: 2B60100 - which works perfectly in my program.
However, if the bytes are A0 01 30 00, the bitMask is set to: 3001A0 - which has stipped the last zero from the bitmask.
Is there any way I can stop Java from stipping off trailing zeros?
I hope that makes sense.
Thanks
Tony
The zeros are not being stripped -- both examples cited are correct.
00 01 B6 02 is the 4-byte little-endian for 2B60100
A0 01 30 00 is the 4-byte little-endian for 3001A0
The zeros are there, but probably just not being printed. The System.out.print family of calls will not print leading zero digits.
I might mention that your method is needlessly complex. Here is a single method that computes the same value:
static int extractLittleEndian4(byte[] buf, int index)
{
int a = buf[index+0]&0xff, b = buf[index+1]&0xff, c = buf[index+2]&0xff, d = buf[index+3]&0xff;
return a | (b << 8) | (c << 16) | (d << 24);
}
It looks like you have a ByteBuffer filled with your bytes already. Why don't you let the ByteBuffer reverse the bytes for you? Just add the bytes to the buffer (BIG_ENDIAN is the default if you want to add an integer instead of bytes) and then change the order before reading the integer.
byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
int output = byteBuffer.getInt(0);
If all you're doing is reversing the byte order, let the library do the work for you. If you happened to start with an integer value, you can even just do this:
int input = ...;
int output = Integer.reverseBytes(input);

how to read bytes bigger than 127 in java?

alright, so my code to read bytes into a int is like so:
int offset = (byte << 16) | (byte2 << 8) | byte3;
And it's reading the bytes "00 00 be" as -66.
How do I read it as the 190 it's meant to be?
byte b = -66;
int i = b & 0xff;
byte b = -66;
int i = b < 0 ? b + 256 : b;
It might be useful declare helper function for this.

Categories