1

I have my below layout in which I need to represent my data and then finally I need to make one byte array out of that. I need to represent my data in the below format from Java code and then send the byte array to my C++ program which in turns c++ program unpacks the byte array and extract the relevant stuff from it -

// below is my data layout -
//
// key type - 1 byte
// key len - 1 byte
// key (variable size = key_len)
// timestamp (sizeof uint64_t)
// data size (sizeof uint16_t), this is unsigned 16-bit integer.
// data (variable size = data size)

So I started like this in Java which works fine on a simple use case which makes a single byte array out of this but I am thinking my dataSize calculation is wrong since I am using Short for the dataSize which can take maximum value as 32767 but dataSize specification is uint16_t as shown above which is unsigned 16-bit integer which can take maximum value more than 32767.

byte keyType = 101;
byte keyLength = 3;
byte[] key = {27, 55, 111};
long timestamp = System.currentTimeMillis();

byte[] data = "string data".getBytes("UTF-8");

// this is looking wrong to me since dataSize is uint16_t in my C++ specifications as shown above
short dataSize = (short) data.length;

int totalSize = (1 + 1 + keyLength + 8 + 2 + dataSize);
ByteBuffer bytes = ByteBuffer.allocate(totalSize);

bytes.put(keyType);
bytes.put(keyLength);
bytes.put(key);
bytes.putLong(timestamp);

// so this is also wrong
// what is the right way to send the dataSize?
bytes.putShort(dataSize);
bytes.put(data);

// write everthing as a single byte array:
byte[] byteArray = bytes.array();

Let's say if the length of data is 37714 (data.length), then dataSize will come as negative -27822.

So my question is - Is there any way I can have unsigned 16 bit Integer in java which I can use in my above code or some way to cast it?

Does my above code looks right with the above specifications or is there anything wrong which might cause problem if we have some big strings coming up.

4
  • The only unsigned 16-bit integer in Java is a char, but you can convert from short to char by simply casting. But you're probably better off using an int. Commented Feb 24, 2015 at 22:11
  • Why does dataSize need to be a signed short in the first place? Just declare it an int, and check that it's less than 65536 before you call putShort(). Commented Feb 24, 2015 at 22:13
  • @LeeDanielCrocker Can you provide an example how would I do that? Or do you mean to say what dasblinkenlight suggested below? Commented Feb 25, 2015 at 1:10
  • His version is a bit riskier because if data.length is > 65536 (and you don't show us where that comes from, so we have no idea), his code would silently ignore that error, and probably truncate data. I suggest checking for that case explicitly and handling the error if needed. Commented Feb 25, 2015 at 1:17

1 Answer 1

3

Java's only unsigned type is char, and it happens to be 16-bit wide. However, this is not the right choice to represent length: you should use int internally, and convert to/from 16-bit short only during serialization and deserialization.

int dataSize = data.length;
...
bytes.putShort((short)(dataSize & 0xFFFF));

and

short tmp = getShort(...);
int dataSize = ((int)tmp) & 0xFFFF;

0xFFFF is a 16-bit "mask" that cuts off the undesired bits of an int. Note that if tmp happens to be negative during deserialization, masking will make it positive again, producing the value that has been sent to you.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for suggestion. In our case, C++ program is reading the dataSize as uint16_t. Basically we need to write the data from Java program and read it from C++. So C++ program is reading the dataSize as uint16_t. And If I do it like this int size = 37714; System.out.println((short) (size & 0xFFFF)); it prints out negative number and that's what it stores in the bytes.putShort right? But will C++ will be able to decode this correctly? So far the C++ application we have is not able to decode it correctly.
It is reading it like this in the C++ program - val = ntohs(*reinterpret_cast<const uint16_t*>(buffer));
@david C++ should re-interpret that negative number as a large positive number composed of the same 16 bits. Does your code interpret some numbers correctly? ntohs may reorder the bytes, so Java may need to do some re-ordering too.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.