I've no coding experience in PHP at all. But while looking for a solution for my Java project, i found an example of the problem in PHP, which incidentally is alien to me.
Can anyone please explain the working and the result of the unpack('N*',"string") function of PHP and how to implement it in Java?
An example would help me a lot!
Thanks!
In PHP (and in Perl, where PHP copied it from), unpack("N*", ...) takes a string (actually representing a sequence of bytes) and parses each 4-byte segment of it as a signed 32-bit big-endian ("Network byte order") integer, returning them in an array.
There are several ways to do the same in Java, but one way would be to wrap the input byte array in a java.nio.ByteBuffer, convert it to an IntBuffer and then read the integers from that:
public static int[] unpackNStar ( byte[] bytes ) {
// first, wrap the input array in a ByteBuffer:
ByteBuffer byteBuf = ByteBuffer.wrap( bytes );
// then turn it into an IntBuffer, using big-endian ("Network") byte order:
byteBuf.order( ByteOrder.BIG_ENDIAN );
IntBuffer intBuf = byteBuf.asIntBuffer();
// finally, dump the contents of the IntBuffer into an array
int[] integers = new int[ intBuf.remaining() ];
intBuf.get( integers );
return integers;
}
Of course, if you just want to iterate over the integers, you don't really need the IntBuffer or the array:
ByteBuffer buf = ButeBuffer.wrap( bytes );
buf.order( ByteOrder.BIG_ENDIAN );
while ( buf.hasRemaining() ) {
int num = buf.getInt();
// do something with num...
}
In fact, iterating over a ByteBuffer like this is a convenient way to emulate the behavior of even more complicated examples of unpack() in Perl or PHP.
(Disclaimer: I have not tested this code. I believe it should work, but it's always possible that I may have mistyped or misunderstood something. Please test before using.)
Ps. If you're reading the bytes from an input stream, you could also wrap it in a DataInputStream and use its readInt() method. Of course, it's also possible to use a ByteArrayInputStream to read the input from a byte array, achieving the same results as the ByteBuffer examples above.
Related
I am trying to write a byte array that I know the size of to the array however I am not able to parse the resultant data.
I am using the following code:
okAppender.writeBytes(b -> b.write(byteData));
and
byte[] byteData = new byte[500];
okTailer.readBytes(b -> b.read(byteData));
I expect there is padding but I do not know how much. Any insight would be appreciated.
I suggest you use the chronicle Bytes class ( which can wrap a bytebufffer ) as reading into a byte[] creates and object each time.
I have an Android app that uses ByteBuffer to send an array of ints (converted to a string) to my server, which is written in Ruby. The server takes the string and unpacks it. My code to build the ByteBuffer looks like this:
ByteBuffer bytes = ByteBuffer.allocate(16);
bytes.order(ByteOrder.LITTLE_ENDIAN);
bytes.putInt(int1);
bytes.putInt(int2);
bytes.putInt(int3);
bytes.putInt(int4);
String byteString = new String(bytes.array());
This works great when the ints are all positive values. When it has a negative int, things go awry. For example, in iOS when I submit an array of ints like [1,1,-1,0], the byte string on the server is:
"\x01\x00\x00\x00\x01\x00\x00\x00\xFF\xFF\xFF\xFF\x00\x00\x00\x00"
That gets correctly unpacked to [1,1,-1,0].
In Android, however, when I try to submit the same array of [1,1,-1,0], my string is:
"\x01\x00\x00\x00\x01\x00\x00\x00\xEF\xBF\xBD\xEF\xBF\xBD\xEF\xBF\xBD\xEF\xBF\xBD\x00\x00\x00\x00"
Which gets unpacked to [1, 1, -272777233, -1074807361].
If I convert the negative int to an unsigned int:
byte intByte = (byte) -1;
int unsignedInt = intByte & 0xff;
I get the following:
"\x01\x00\x00\x00\x01\x00\x00\x00\xEF\xBF\xBD\x00\x00\x00\x00\x00\x00\x00"
Which gets unpacked to [1, 1, 12435439, 0]. I'm hoping someone can help me figure out how to properly handle this so I can send negative values properly.
Your problem is here:
String byteString = new String(bytes.array());
Why do you do that? You want to send a stream of bytes, so why convert it to a stream of chars?
If you want to send bytes, send bytes. Use an OutputStream, not a Writer; use an InputStream, not a Reader. The fact that integers are "negative" or "positive" does not matter.
What´s the difference between
"hello world".getBytes("UTF-8");
and
Charset.forName("UTF-8").encode("hello world").array();
?
The second code produces a byte array with 0-bytes at the end in most cases.
Your second snippet uses ByteBuffer.array(), which just returns the array backing the ByteBuffer. That may well be longer than the content written to the ByteBuffer.
Basically, I would use the first approach if you want a byte[] from a String :) You could use other ways of dealing with the ByteBuffer to convert it to a byte[], but given that String.getBytes(Charset) is available and convenient, I'd just use that...
Sample code to retrieve the bytes from a ByteBuffer:
ByteBuffer buffer = Charset.forName("UTF-8").encode("hello world");
byte[] array = new byte[buffer.limit()];
buffer.get(array);
System.out.println(array.length); // 11
System.out.println(array[0]); // 104 (encoded 'h')
I need to parse a binary file created by C++ and overwrite a 4 char long char array in that file, for example change the original char array of ABCD to WXYZ.
I know exactly the position in terms of bytes of the that char array. I tried RandomAccessFile which let me go to the position easily. But I cannot make the rest work for me right now.
Is the RandomAccessFile a right way to go?
I know I have to do some conversion from 2 bytes char to one byte char.
Anybody has a good way to do this?
Fine: always try the JavaDoc RandomAccessFile.
long position = ...;
byte[] bytes = new byte[] { (byte)'W', ... };
raf.seek(position);
raf.write(bytes);
RandomAccessFile is fine. As you have already figured out, in C++ char is a single byte, whereas Java uses UTF-16.
The easiest option might be to use byte[4] in your code to represent the 4-character ASCII string.
I am porting some C++ code over to java, and in my particular instance, i am writing data to a byte[] to be written to a file. The first portion, as defined in C++ is a structure consisting of a uint, and 3 ushorts. The second portion is the main part of the data, which i will just append on the end of the byte[] before i send it to the outputstream.
My question is this: What is the simplest way to write the header values to the byte[]? I know i can put 1 value in there, then offset the specific number of bytes, and repeat as necessary, but is this the best way to do it?
Also, how do i manage byte alignment? The C++ code appears to use the default values (4-byte?) for alignment.
Thanks,
Jason
You might find it easier to use ByteBuffer, which is probably the nicest way in Java to organize byte-by-byte output.
ByteBuffer doesn't directly care about alignment, though, and I don't know how C++ is aligning its output -- but in a pinch, you can just advance it manually.
Use a DataOutputStream that wraps a ByteArrayOutputStream
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()
DataOutputStream stream = new DataOutputStream(byteArrayOutputStream);
try {
stream.writeInt(i);
stream.writeShort(s0);
stream.writeShort(s1);
stream.writeShort(s2);
stream.flush();
} catch (IOException e) {
// this can't happen, but you still require a try catch block
}
byte[] array = byteArrayOutputStream.toByteArray();
If your code might be parsing a similar byte array with unsigned integers then you're going to have a bit of headache. That is, you will have to check for negative numbers and deal with them appropriately.
eg.
int unsignedIntAsSignedInt = inStream.readInt();
long realData;
if (unsignedIntAsSignedInt < 0) {
realData = ((long) unsignedIntAsSignedInt) - (((long)Integer.MIN_VALUE) * 2);
} else {
realData = unsignedIntAsSignedInt;
}