I'm currently writing a Java program that communicates with a Chrome extension. I need to implement the Chrome native messaging protocol in order to communicate. The Google Chrome docs say:
... each message is serialized using JSON, UTF-8 encoded and is preceded with 32-bit message length in native byte order. (Source)
I tried to implement this in Java, but I have problems when my messages have a certain length, even though my implementation should be correct. Here is my current implementation, based on earlier SO-answers & questions(here for example):
// read the message size from Chrome. This part works correctly.
public static int getInt(char[] bytes) {
return (bytes[3]<<24) & 0xff000000|
(bytes[2]<<16) & 0x00ff0000|
(bytes[1]<< 8) & 0x0000ff00|
(bytes[0]<< 0) & 0x000000ff;
}
// transform the length into the 32-bit message length.
// This part works for small numbers, but does not work for length 2269 for example.
public static String getBytes(int length) {
return String.format("%c%c%c%c",
(char) ( length & 0xFF),
(char) ((length>>8) & 0xFF),
(char) ((length>>16) & 0xFF),
(char) ((length>>24) & 0xFF));
}
It seems the problem lies in the way java implements chars. I'd expect normal chars, like in C. In practice, it seems Java sometimes transforms these chars into unicode-chars (or at least, that's my suspicion so far). This is reflected in the following output (piped to xxd to show the actual bytes) from the java-program for length 2269:
0000000: c39d 0800 00 .....
The expected output however (with python):
import struct
struct.pack('I', 2269)
# outputs in interactive mode: '\xdd\x08\x00\x00'
What exactly is happening here? Why does Java convert my "0xDD" to "0xC39D" and how can I get my getBytes
function to represent the expected input for Chrome Native Messaging? Using another language is not an option.
Chars in Java are automatically transformed into unicode. The correct type for this use case is byte
, which doesn't automatically transform and keeps the correct value. A correct implementation of the Chrome Native Messaging protocol is thus as follows:
public static byte[] getBytes(int length) {
byte[] bytes = new byte[4];
bytes[0] = (byte) ( length & 0xFF);
bytes[1] = (byte) ((length>>8) & 0xFF);
bytes[2] = (byte) ((length>>16) & 0xFF);
bytes[3] = (byte) ((length>>24) & 0xFF);
return bytes;
}
Besides this method, care needs to be used not to use a String anywhere between the calculation of the length-bytes and the output. Output to System.out
can be done as following:
try {
System.out.write(getBytes(message.length()));
} catch (IOException ex) {
ex.printStackTrace();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With