Buffer to String - java

I send/receive data between Android and other device through the usb.
The code that I use for receive data:
StringBuilder stringBuilder = new StringBuilder();
int i = 0;
int s = buffer[0];
for (; i < s; i++) {
stringBuilder.append(String.valueOf((char)buffer[i]));
}
byte[] b = String.valueOf(stringBuilder).getBytes();
I receive fine all of bytes, except when the byte is bigger than 127. How to do?
I try to use:
stringBuilder2.append(String.valueOf((int)buffer[i] & 0xFF));
And work fine if I read String.valueOf(stringBuilder), but not when I create byte[]

If all the bytes you're receiving are in format ASCII, in your stringBuilder you already have the text of the String you need.
On the other side assuming that buffer[0] is the size of your buffer you could try something like this:
byte[] tmp = new byte[buffer[0]];
System.arraycopy(buffer, 1, tmp, 0, buffer[0]);
String result = new String(tmp);

Related

What is CharsetDecoder.decode(ByteBuffer, CharBuffer, endOfInput)

I have a problem with CharsetDecoder class.
First example of code (which works):
final CharsetDecoder dec = Charset.forName("UTF-8").newDecoder();
final ByteBuffer b = ByteBuffer.allocate(3);
final byte[] tab = new byte[]{(byte)-30, (byte)-126, (byte)-84}; //char €
for (int i=0; i<tab.length; i++){
b.put(tab, i, 1);
}
try {
b.flip();
System.out.println("a" + dec.decode(b).toString() + "a");
} catch (CharacterCodingException e1) {
e1.printStackTrace();
}
The result is a€a
But when i execute this code:
final CharsetDecoder dec = Charset.forName("UTF-8").newDecoder();
final CharBuffer chars = CharBuffer.allocate(3);
final byte[] tab = new byte[]{(byte)-30, (byte)-126, (byte)-84}; //char €
for (int i=0; i<tab.length; i++){
ByteBuffer buffer = ByteBuffer.wrap(tab, i, 1);
dec.decode(buffer, chars, i == 2);
}
dec.flush(chars);
System.out.println("a" + chars.toString() + "a");
The result is a
Why is not the same result?
How to use the method decode(ByteBuffer, CharBuffer, endOfInput) of class CharsetDecoder in order to retrieve the result a€a ?
-- EDIT --
So with code of Jesper I do that. It's no perfect but works with a step = 1, 2 and 3
final CharsetDecoder dec = Charset.forName("UTF-8").newDecoder();
final CharBuffer chars = CharBuffer.allocate(6);
final byte[] tab = new byte[]{(byte)97, (byte)-30, (byte)-126, (byte)-84, (byte)97, (byte)97}; //char €
final ByteBuffer buffer = ByteBuffer.allocate(10);
final int step = 3;
for (int i = 0; i < tab.length; i++) {
// Add the next byte to the buffer
buffer.put(tab, i, step);
i+=step-1;
// Remember the current position
final int pos = buffer.position();
int l=chars.position();
// Try to decode
buffer.flip();
final CoderResult result = dec.decode(buffer, chars, i >= tab.length -1);
System.out.println(result);
if (result.isUnderflow() && chars.position() == l) {
// Underflow, prepare the buffer for more writing
buffer.position(pos);
}else{
if (buffer.position() == buffer.limit()){
//ByteBuffer decoded
buffer.clear();
buffer.position(0);
}else{
//a part of ByteBuffer is decoded. We keep only bytes which are not decoded
final byte[] b = buffer.array();
final int f = buffer.position();
final int g = buffer.limit() - buffer.position();
buffer.clear();
buffer.position(0);
buffer.put(b, f, g);
}
}
buffer.limit(buffer.capacity());
}
dec.flush(chars);
chars.flip();
System.out.println(chars.toString());
The method decode(ByteBuffer, CharBuffer, boolean) returns a result, but you are ignoring the result. If print the result in your second code fragment:
for (int i = 0; i < tab.length; i++) {
ByteBuffer buffer = ByteBuffer.wrap(tab, i, 1);
System.out.println(dec.decode(buffer, chars, i == 2));
}
you'll see this output:
UNDERFLOW
MALFORMED[1]
MALFORMED[1]
a a
Apparently it does not work correctly if you start decoding in the middle of a character. The decoder expects that the first thing it reads is the start of a valid UTF-8 sequence.
edit - When the decoder reports UNDERFLOW, it expects you to add more data to the input buffer and then try to call decode() again, but you must re-offer it the data from the start of the UTF-8 sequence that you are trying to decode. You can't continue in the middle of an UTF-8 sequence.
Here is a version that works, adding one byte from tab in every iteration of the loop:
final CharsetDecoder dec = Charset.forName("UTF-8").newDecoder();
final CharBuffer chars = CharBuffer.allocate(3);
final byte[] tab = new byte[]{(byte) -30, (byte) -126, (byte) -84}; //char €
final ByteBuffer buffer = ByteBuffer.allocate(10);
for (int i = 0; i < tab.length; i++) {
// Add the next byte to the buffer
buffer.put(tab[i]);
// Remember the current position
final int pos = buffer.position();
// Try to decode
buffer.flip();
final CoderResult result = dec.decode(buffer, chars, i == 2);
System.out.println(result);
if (result.isUnderflow()) {
// Underflow, prepare the buffer for more writing
buffer.limit(buffer.capacity());
buffer.position(pos);
}
}
dec.flush(chars);
chars.flip();
System.out.println("a" + chars.toString() + "a");
The decoder does not internally cache the data from partial characters, but this does not mean that you have to do complicated things to figure out what data to re-feed the decoder. You gave it a clear way to represent what data it actually consumed, i.e. the input ByteBuffer and its position. In the second example, by giving it a new ByteBuffer every time, the OP failed to pass the decoder back what it reported it had not yet consumed.
The standard pattern for using NIO Buffers is input, flip, output, compact, loop. Short of optimization (which may be premature), there is no reason to re-implement compact yourself. You might just get it wrong, like #Jesper and #lecogiteur did (if more than a single character was ever presented). You should NOT be resetting to the position from before the decode call.
The second example should have read something like:
final CharsetDecoder dec = Charset.forName("UTF-8").newDecoder();
final CharBuffer chars = CharBuffer.allocate(3);
final byte[] tab = new byte[]{(byte)-30, (byte)-126, (byte)-84}; //char €
final ByteBuffer buffer = ByteBuffer.wrap(new byte[3]);
for (int i=0; i<tab.length; i++){
b.put(tab, i, 1); // In actual usage some type of IO read/transfer would occur here
b.flip();
dec.decode(buffer, chars, i == 2);
b.compact();
}
dec.flush(chars);
System.out.println("a" + chars.toString() + "a");
NOTE: The above does not check the return value to detect malformed input or other error handling for running safely on arbitrary input/IO conditions.

convert byte array to string, string can't convert back after transfer

Code for the same:
public byte[] stringToBytesUTFCustom(String str) {
char[] buffer1 = str.toCharArray();
byte[] b = new byte[buffer1.length << 1];
for(int i = 0; i < buffer1.length; i++) {
int bpos = i << 1;
b[bpos] = (byte) ((buffer1[i]&0xFF00)>>8);
b[bpos + 1] = (byte) (buffer1[i]&0x00FF);
}
return b;
}
public String bytesToStringUTFCustom(byte[] bytes) {
char[] buffer = new char[bytes.length >> 1];
for(int i = 0; i < buffer.length; i++) {
int bpos = i << 1;
char c = (char)(((bytes[bpos]&0x00FF)<<8) + (bytes[bpos+1]&0x00FF));
buffer[i] = c;
}
String txt = String.valueOf(buffer);
//return new String(buffer);
return txt;
}
First, I implement a SMS encryption app (Client to Client) and then want to encode cipher(format "Byte[]") to string, Base64 it's work but can't send because more than 160 character.
I'm want to convert byte array to string ,when use function above it's work for same function, but when I use bytesToStringUTFCustom and then send this text(SMS) can't work.
Receiver cannot read a text to decode from.
Cipher is a result of bytesToStringUTFCustom function, so anyone can help me?
Thanks.
Did you know these:
String.getBytes(Charset encoding)
new String(byte[] byteArray, Charset encoding)
You can use Charset.forName(String) to get the Charset.
Charset UTF8 = Charset.forName("UTF-8");
byte[] bytes = str.getBytes(UTF8);
String reverted = new String(bytes, UTF8);

Encoding String to "modified UTF-8" for the DataInput

I would like to encode String value to the modified UTF-8 format bytes. Something like
byte[] bytes = MagicEncoder.encode(str, "modified UTF-8");
DataInput input = new DataInputStream(new ByteArrayInputStream(bytes));
Each read*() method of the DataInput has to be able to properly read the underlaying bytes.
Use DataOutputStream
ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
DataOutputStream dataOutputStream = new DataOutputStream(byteOutputStream);
dataOutputStream.writeUTF("some string to write");
dataOutputStream.close();
result is available in byteOutputStream.toByteArray()
As info:
The modified UTF-8 encoding simply replaces the nul character U+0000, normally encoded as byte 0, as the byte sequence C0 80, the normal multi-byte encoding, used for codes > 0x7F.
(Hence normal UTF-8 decoding suffices.)
byte[] originalBytes;
int nulCount = 0;
for (int i = 0; i < originalBytes.length; ++i) {
if (originalBytes[i] == 0) {
++nulCount;
}
}
byte[] convertedBytes = new byte[originalCount + nulCount];
for (int i = 0, j = 0; i < originalBytes.length; ++i, ++j) {
convertedBytes[j] = originalBytes[i];
if (originalBytes[i] == 0) {
convertedBytes[j] = 0xC0;
++j;
convertedBytes[j] = 0x80;
}
}
Better to use System.arrayCopy, and check whether nulCount == 0.

Java CipherInputStream behavior on decryption

I am using the following code to decrypt files encrypted from android device.
private void mDecrypt_File(FileInputStream fin, String outFile) throws Exception {
FileOutputStream fout = new FileOutputStream(outFile);
byte[] iv = new byte[16];
byte[] salt = new byte[16];
byte[] len = new byte[8];
byte[] FC_TAGBuffer = new byte[8];
Cipher cipher = Cipher.getInstance(CIPHER_INSTANCE);
DataInputStream dis = new DataInputStream(fin);
dis.read(iv, 0, 16);
dis.read(salt, 0, 16);
Rfc2898DeriveBytes rfc = new Rfc2898DeriveBytes(DEFAULT_PASSWORD, salt, F_ITERATIONS);
SecretKey key = new SecretKeySpec(rfc.getBytes(32), "AES");
//decryption code
cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
CipherInputStream cIn = new CipherInputStream(dis, cipher);
cIn.read(len, 0, 8);
long lSize = getLong(len, 0);
cIn.read(FC_TAGBuffer, 0, 8);
byte[] tempFC_TAGBuffer = changeByteArray(FC_TAGBuffer, 0);//new byte[8];
BigInteger ulong = new BigInteger(1, tempFC_TAGBuffer);
if (!ulong.equals(FC_TAG)) {
Exception ex = new Exception("Tags are not equal");
throw ex;
}
byte[] bytes = new byte[BUFFER_SIZE];
//determine number of reads to process on the file
long numReads = lSize / BUFFER_SIZE;
// determine what is left of the file, after numReads
long slack = (long) lSize % BUFFER_SIZE;
int read = -1;
int value = 0;
int outValue = 0;
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.reset();
// read the buffer_sized chunks
for (int i = 0; i < numReads; ++i) {
read = cIn.read(bytes, 0, bytes.length);
fout.write(bytes, 0, read);
md.update(bytes, 0, read);
value += read;
outValue += read;
}
// now read the slack
if (slack > 0) {
read = cIn.read(bytes, 0, (int) slack);
fout.write(bytes, 0, read);
md.update(bytes, 0, read);
value += read;
outValue += read;
}
fout.flush();
fout.close();
byte[] curHash = md.digest();
byte[] oldHash = new byte[md.getDigestLength()];
read = cIn.read(oldHash, 0, oldHash.length);
if (oldHash.length != read || (!CheckByteArrays(oldHash, curHash))) {
Exception ex = new Exception("File Corrupted!");
throw ex;
}
if (outValue != lSize) {
Exception ex = new Exception("File Sizes don't match!");
throw ex;
}
}
This code is working fine on android but behaving strange on Java desktop application.
What I have observed is, on reading old hash from CipherInputStream cIn returns correct hash value only if the size of data to be decrypted is multiples of 32. For example, if I encrypt a text file which have a text of length 32 chars(or 64/128/...), then the following code
byte[] oldHash = new byte[md.getDigestLength()];
read = cIn.read(oldHash, 0, oldHash.length);
if (oldHash.length != read || (!CheckByteArrays(oldHash, curHash))) {
Exception ex = new Exception("File Corrupted!");
throw ex;
}
calculates oldHash correctly, but if I change the text of any other length(not multiple of 32) then the oldHash's last few values becomes zeros.
My Observations :
Text Size 6 char - Trailing zeros in oldHash - 6
Text Size 13 char - Trailing zeros in oldHash - 13
Text Size 20 char - Trailing zeros in oldHash - 4
Text Size 32 char - Trailing zeros in oldHash - 0 // Correct Result
Text Size 31 char - Trailing zeros in oldHash - 1
Text Size 64 char - Trailing zeros in oldHash - 0 // Correct Result
Please help me understanding this behavior.
Agree with DuncanJones, your loop is a mess. Although you properly check the return value of the read() method your loop iterations assume that every read() will return BUFFER_SIZE bytes or 'slack' bytes for the last read.
You code would be hugely better if you make proper use of DataInputStream. For example, you wrap the FileInputStream fin in a DataInputStream but then use the wrong methods in these two lines:
dis.read(iv, 0, 16);
dis.read(salt, 0, 16);
instead, you should use the readFully method, as in:
dis.readFully(iv);
dis.readFully(salt);
Similarly, you would benefit from wrapping your CipherInputStream cIn with another DataInputStream, something like:
CipherInputStream cIn = new CipherInputStream(dis, cipher);
DataInputStream dcIn = new DataInputStream(cIn);
DataInputStream already has a getLong method, so you could just replace these lines:
cIn.read(len, 0, 8);
long lSize = getLong(len, 0);
cIn.read(FC_TAGBuffer, 0, 8);
with
long lSize = dcIn.getLong()
dcIn.readFully(FC_TAGBuffer);
and you get to throw out your homegrown getLong method. Now you can go on and read the next lSize bytes in exactly BUFFER_SIZE chunks using dcIn.readFully(bytes) and make your code, cleaner, shorter, easier to read, and correct.

Write Hex string in Socket Communication in android

I am working on Socket connection. I am working on the client side.
I have gone through this discussion Socket pass value as Hex. I need to send the String e.g(0x01 is a hex value and a String "Ravi") at the server they are expecting hexa value like 1 72 61 76 69. I tried of converting String Ravi to hexa value as String and appending "1" and try to convert to byte array. I am getting an exception that StringIndexOutOfBound exception.
update:
`public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 2)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
public String toHex(String arg) {
return String.format("%x", new BigInteger(arg.getBytes()));
}`
I used these two methods to convert the 1Ravi string to byte array but i am getting exception hexstringtobytearray method.
try this
Socket sock = new Socket("host", port);
OutputStream out = sock.getOutputStream();
out.write(0);
String s = "ravi";
byte[] bytes = s.getBytes("UTF-8");
out.write(bytes);

Categories