Convert java string with odd length to hex byte array - java

I need to convert string to hexademical byte array,my code is:
public static byte[] stringToHex(final String buf)
{
return DatatypeConverter.parseHexBinary(buf);
}
According to java doc to convert string to Hex DatatypeConverteruse the following implementation
public byte[] parseHexBinary(String s) {
final int len = s.length();
// "111" is not a valid hex encoding.
if (len % 2 != 0) {
throw new IllegalArgumentException("hexBinary needs to be even-length: " + s);
}
byte[] out = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
int h = hexToBin(s.charAt(i));
int l = hexToBin(s.charAt(i + 1));
if (h == -1 || l == -1) {
throw new IllegalArgumentException("contains illegal character for hexBinary: " + s);
}
out[i / 2] = (byte) (h * 16 + l);
}
return out;
}
It means that only strings with the even length is legal to be converted.But in php there is no such constraint
For example code in php:
echo pack("H*", "250922f67dcbc2b97184464a91e7f8f");
And in java
String hex = "250922f67dcbc2b97184464a91e7f8f";
System.out.println(stringToHex(hex));//my method that was described earlier
Why the following string is legal in php?

PHP just adds a final 0 in case the number of characters is odd.
Both of these
echo pack("H*", "48454C50");
echo pack("H*", "48454C5");
yield
HELP

Related

Convert Binary to Hexadecimal in Java without methods

I am currently a beginner in programming and I am trying to write a program in java to convert binary in hexadecimal numbers.
I know that the program will have to divide the number in groups of 4 and convert them to hexadecimal.
Ex: 11101111 (b2) --> E + F --- EF
However, since I used ints to do the conversion of the numbers, I'm stuck when I need to print a letter because it is a String.
Can someone point me to the right way? What am I doing wrong? I've also tried another version with an auxiliary array to store each group of 4 digits but I can't manage to insert a proper dimension to the array.
Unfortunately I am not allowed to use any function other than Scanner and Math, the method lenght and charAt and the basic stuff. I can't modify the public static line either.
EDIT: So after your inputs and so many tries, I managed to get this code. However it gives me an error if I insert too many numbers, eg: 0111011010101111. I've tried to change int to double but that didn't fix the problem.
import java.util.Scanner;
public class Bin2HexString {
public static void main(String[] args) {
Scanner keyb = new Scanner(System.in);
System.out.println("Valor?");
int vlr = keyb.nextInt();
String num = "";
int aux = vlr;
// Hexadecimal numbers
String arr[] = {"0","1","2","3","4","5","6","7","8","9","A", "B", "C", "D", "E", "F"};
String bits[] = {"0000","0001","0010","0011","0100","0101","0110","0111","1000","1001","1010","1011","1100","1101","1110","1111"};
String letters = "";
//Divide in groups of 4
int r;
for (; aux > 0; ) {
r = aux % 10000;
aux = aux / 10000;
num = "" + r;
for (;num.length() < 4;) { //add missing zeros
String zero = "0";
num = zero + num;
}
int charint = 0,bitint = 0;
for (int i = 0; i < arr.length;i++) {
String aux2 = bits[i];
String aux3 = arr[i];
for (int j = 0; j < num.length();j++) { // compare each group with arr[i]
char charvl = num.charAt(j);
char bitsvl = aux2.charAt(j);
charint = ((int) (charvl)-'0');
bitint = ((int) (bitsvl) - '0');
if (bitint != charint)
break;
}
if (bitint == charint)
letters = aux3 + "" + letters;
}
}
System.out.println(letters);
}
}
Having thought about this for a while to determine the most effective and useful way to do this is to write methods which convert a string from any base between 2 and 16 to an int and back to a string again.
This way you have useful methods for other things. And note that they methods can be easily changed and names to simply hard code the desired radix into the method to limit it to binary and hex methods.
The indexOf utility method was written to avoid using the builtin String method.
final static String hex = "0123456789ABCDEF";
static int stringToInt(String str, int radix) {
if (radix < 2 || radix > 16) {
System.out.println("Base must be between 2 and 16 inclusive");
return -1;
}
int v = 0;
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
int idx = indexOf(hex, c);
if (idx < 0 || idx > radix) {
System.out.println("Illegal character in string (" + c + ")");
}
v = v * radix + idx;
}
return v;
}
static String intToBase(int v, int radix) {
if (radix < 2 || radix > 16) {
System.out.println("Base must be between 2 and 16 inclusive");
return null;
}
String s = "";
while (v > 0) {
int idx = v % radix;
s = hex.charAt(idx) + s;
v /= radix;
}
return s;
}
static int indexOf(String str, char c) {
for (int i = 0; i < str.length(); i++) {
if (str.charAt(i) == c) {
return i;
}
}
return -1;
}
And here is an example of their use.
// generate some test data
Random r = new Random(23);
String[] bitStrings =
r.ints(20, 20, 4000).mapToObj(Integer::toBinaryString).toArray(
String[]::new);
for (String bitstr : bitStrings) {
int v = baseToInt(bitstr, 2);
String hex = intToBase(v, 16);
System.out.printf("%12s = %s%n", bitstr, hex);
}
Which prints the following:
101110000011 = B83
111001111100 = E7C
10001110111 = 477
100110001111 = 98F
111001010 = 1CA
111001001111 = E4F
111000011010 = E1A
100001010010 = 852
11011001101 = 6CD
111010010111 = E97
Just some quick notes:
First this is wrong:
//Divide in groups of 4
for (; aux > 0; ) {
r = aux % 10000;
aux = aux / 10000;
Not at all what you want to do. Try it by hand and see what happens. Take a simple number that you know the answer to, and try it. You won't get the right answer. A good test is 17, which is 11 hex.
Try this instead: convert directly to the base you want. Hex is base 16 (its radix is 16), so you use 16 instead.
//Divide in groups of 4
for (; aux > 0; ) {
r = aux % 16;
aux = aux / 16;
Try those numbers with the test case, which is 17, and see what you get. That will get you much closer.
I'm assuming by "without methods" in the title, you are attempting to write your own integer parsing method instead of using Scanner.nextInt(int radix). In that case, my first advice would be work with a string instead of an integer - you'll be able to handle larger numbers and you can simply make an array of substrings (length 4) to convert to letters.
So, if you use the string approach - first scan in a string, not an int. Then I'd recommend a hash table with the 4-bit strings as keys and the hexadecimal equivalents as values. That should make calculation quite fast.
e.g.
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class HashMapBin2Hex
{
public static void main(String[] args)
{
//Read the string in
Scanner sc = new Scanner(System.in);
System.out.println("Binary number?");
String bin = sc.nextLine();
//Pad the bitstring with leading zeros to make a multiple of four
String zeros = "";
int i;
if (bin.length() % 4 != 0)
{
for (i = 0; i < 4 - (bin.length() % 4); i++)
{
zeros += "0";
}
}
bin = zeros + bin;
//Split the padded string into 4-bit chunks
String[] chunks = new String[bin.length() / 4];
for (i = 0; (i * 4) < bin.length() - 1; i++)
{
chunks[i] = bin.substring(i * 4, (i * 4) + 4);
}
//Convert the chunks to hexadecimal
String hex = "";
Map<String, String> bin2hex = new HashMap<>();
bin2hex.put("0000", "0");
bin2hex.put("0001", "1");
bin2hex.put("0010", "2");
bin2hex.put("0011", "3");
bin2hex.put("0100", "4");
bin2hex.put("0101", "5");
bin2hex.put("0110", "6");
bin2hex.put("0111", "7");
bin2hex.put("1000", "8");
bin2hex.put("1001", "9");
bin2hex.put("1010", "A");
bin2hex.put("1011", "B");
bin2hex.put("1100", "C");
bin2hex.put("1101", "D");
bin2hex.put("1110", "E");
bin2hex.put("1111", "F");
for (String s : chunks)
{
hex += bin2hex.get(s);
}
System.out.println("Hexadecimal: " + hex);
sc.close();
}
}
Further iterations could have some error checking to prevent catastrophic failure in the case of characters other than 0 or 1.
And of course, if you're fine with the other way (builtins), the following is far easier and more robust (ie will throw an exception if the string contains anything other than 0s and 1s):
import java.util.Scanner;
public class BuiltinBin2Hex
{
public static void main(String[] args)
{
//Read the binary number in
Scanner sc = new Scanner(System.in);
System.out.println("Binary number?");
int bin = sc.nextInt(2);
//And print as hexadecimal
System.out.println("Hexadecimal: " + Integer.toString(bin, 16));
sc.close();
}
}

Java Byte Operation - Converting 3 Byte To Integer Data

I have some byte-int operations. But I cant figure out the problem.
First of all I have a hex data and I am holding it as an integer
public static final int hexData = 0xDFC10A;
And I am converting it to byte array with this function:
public static byte[] hexToByteArray(int hexNum)
{
ArrayList<Byte> byteBuffer = new ArrayList<>();
while (true)
{
byteBuffer.add(0, (byte) (hexNum % 256));
hexNum = hexNum / 256;
if (hexNum == 0) break;
}
byte[] data = new byte[byteBuffer.size()];
for (int i=0;i<byteBuffer.size();i++){
data[i] = byteBuffer.get(i).byteValue();
}
return data;
}
And I want to convert 3 byte array to integer back again how can I do that?
Or you can also suggest other converting functions like hex-to-3-bytes-array and 3-bytes-to-int thank you again.
UPDATE
In c# someone use below function but not working in java
public static int byte3ToInt(byte[] byte3){
int res = 0;
for (int i = 0; i < 3; i++)
{
res += res * 0xFF + byte3[i];
if (byte3[i] < 0x7F)
{
break;
}
}
return res;
}
This will give you the value:
(byte3[0] & 0xff) << 16 | (byte3[1] & 0xff) << 8 | (byte3[2] & 0xff)
This assumes, the byte array is 3 bytes long. If you need to convert also shorter arrays you can use a loop.
The conversion in the other direction (int to bytes) can be written with logical operations like this:
byte3[0] = (byte)(hexData >> 16);
byte3[1] = (byte)(hexData >> 8);
byte3[2] = (byte)(hexData);
You could use Java NIO's ByteBuffer:
byte[] bytes = ByteBuffer.allocate(4).putInt(hexNum).array();
And the other way round is possible too. Have a look at this.
As an example:
final byte[] array = new byte[] { 0x00, (byte) 0xdf, (byte) 0xc1, 0x0a };//you need 4 bytes to get an integer (padding with a 0 byte)
final int x = ByteBuffer.wrap(array).getInt();
// x contains the int 0x00dfc10a
If you want to do it similar to the C# code:
public static int byte3ToInt(final byte[] byte3) {
int res = 0;
for (int i = 0; i < 3; i++)
{
res *= 256;
if (byte3[i] < 0)
{
res += 256 + byte3[i]; //signed to unsigned conversion
} else
{
res += byte3[i];
}
}
return res;
}
to convert Integer to hex: integer.toHexString()
to convert hexString to Integer: Integer.parseInt("FF", 16);

Java - Convert Big-Endian to Little-Endian

I have the following hex string:
00000000000008a3a41b85b8b29ad444def299fee21793cd8b9e567eab02cd81
but I want it to look like this:
81cd02ab7e569e8bcd9317e2fe99f2de44d49ab2b8851ba4a308000000000000 (Big
endian)
I think I have to reverse and swap the string, but something like this doesn't give me right result:
String hex = "00000000000008a3a41b85b8b29ad444def299fee21793cd8b9e567eab02cd81";
hex = new StringBuilder(hex).reverse().toString();
Result:
81dc20bae765e9b8dc39712eef992fed444da92b8b58b14a3a80000000000000
(wrong)
81cd02ab7e569e8bcd9317e2fe99f2de44d49ab2b8851ba4a308000000000000
(should be)
The swapping:
public static String hexSwap(String origHex) {
// make a number from the hex
BigInteger orig = new BigInteger(origHex,16);
// get the bytes to swap
byte[] origBytes = orig.toByteArray();
int i = 0;
while(origBytes[i] == 0) i++;
// swap the bytes
byte[] swapBytes = new byte[origBytes.length];
for(/**/; i < origBytes.length; i++) {
swapBytes[i] = origBytes[origBytes.length - i - 1];
}
BigInteger swap = new BigInteger(swapBytes);
return swap.toString(10);
}
hex = hexSwap(hex);
Result:
026053973026883595670517176393898043396144045912271014791797784
(wrong)
81cd02ab7e569e8bcd9317e2fe99f2de44d49ab2b8851ba4a308000000000000
(should be)
Can anyone give me a example of how to accomplish this?
Thank you a lot :)
You need to swap each pair of characters, as you're reversing the order of the bytes, not the nybbles. So something like:
public static String reverseHex(String originalHex) {
// TODO: Validation that the length is even
int lengthInBytes = originalHex.length() / 2;
char[] chars = new char[lengthInBytes * 2];
for (int index = 0; index < lengthInBytes; index++) {
int reversedIndex = lengthInBytes - 1 - index;
chars[reversedIndex * 2] = originalHex.charAt(index * 2);
chars[reversedIndex * 2 + 1] = originalHex.charAt(index * 2 + 1);
}
return new String(chars);
}

convert hex string to base64

Please help me on converting a hexstring to base64
here is the cede where I'm getting the exception
String hexString = "bf940165bcc3bca12321a5cc4c753220129337b48ad129d880f718d147a2cd1bfa79de92239ef1bc06c2f05886b0cd5d";
private static String ConvertHexStringToBase64(String hexString) {
System.out.println(hexString);
if ((hexString.length()) % 2 > 0)
throw new NumberFormatException("Input string was not in a correct format.");
byte[] buffer = new byte[hexString.length() / 2];
int i = 0;
while (i < hexString.length())
{
buffer[i / 2] = Byte.parseByte(hexString.substring(i, 2));
i += 2;
}
System.out.println("hexSring"+hexString+"afterconverttobase64"+Base64.encodeBase64String(buffer));
return Base64.encodeBase64String(buffer);
}
I'm getting an exception here::bf940165bcc3bca12321a5cc4c753220129337b48ad129d880f718d147a2cd1bfa79de92239ef1bc06c2f05886b0cd5d
Exception in thread "main" java.lang.NumberFormatException: For input string: "bf"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
at java.lang.Integer.parseInt(Integer.java:449)
at java.lang.Byte.parseByte(Byte.java:151)
at java.lang.Byte.parseByte(Byte.java:108)
at com.motorola.gst.DecryptTest3.ConvertHexStringToBase64(DecryptTest3.java:38)
at com.motorola.gst.DecryptTest3.main(DecryptTest3.java:16)
First of all you have to specify the specify the radix(16 in your case) in the parseByte method to avoid the numberFormat exception :
buffer[i / 2] = Byte.parseByte(hexString.substring(i, 2),16);
However your code seems broken, take a look at the corrected one :
if ((hexString.length()) % 2 > 0)
throw new NumberFormatException("Input string was not in a correct format.");
int[] buffer = new int[hexString.length() / 2];
int i = 2;
while (i < hexString.length())
{
buffer[i / 2] = Integer.parseInt(hexString.substring(i, i + 2),16);
i += 2;
}
Your loop was wrong and you have to parse as Integer because you have some values inside your input string that overflow the byte capability ...
If you need byte you could cast the parsed int to byte in this way :
byte[] buffer = new byte[hexString.length() / 2];
int i = 2;
while (i < hexString.length())
{
buffer[i / 2] = (byte)Integer.parseInt(hexString.substring(i, i + 2),16);
i += 2;
}
Found a similar solution, thought it might be good to share:
public static string convertHexToBase64String(String hexString)
{
string base64 = "";
//--Important: remove "0x" groups from hexidecimal string--
hexString = hexString.Replace("0x", "");
byte[] buffer = new byte[hexString.Length / 2];
for (int i = 0; i < hexString.Length; i++)
{
try
{
buffer[i / 2] = Convert.ToByte(Convert.ToInt32(hexString.Substring(i, 2), 16));
}
catch (Exception ex) { }
i += 1;
}
base64 = Convert.ToBase64String(buffer);
return base64;
}
Hope it helps someone else.

Store binary sequence in byte array?

I need to store a couple binary sequences that are 16 bits in length into a byte array (of length 2). The one or two binary numbers don't change, so a function that does conversion might be overkill. Say for example the 16 bit binary sequence is 1111000011110001. How do I store that in a byte array of length two?
String val = "1111000011110001";
byte[] bval = new BigInteger(val, 2).toByteArray();
There are other options, but I found it best to use BigInteger class, that has conversion to byte array, for this kind of problems. I prefer if, because I can instantiate class from String, that can represent various bases like 8, 16, etc. and also output it as such.
Edit: Mondays ... :P
public static byte[] getRoger(String val) throws NumberFormatException,
NullPointerException {
byte[] result = new byte[2];
byte[] holder = new BigInteger(val, 2).toByteArray();
if (holder.length == 1) result[0] = holder[0];
else if (holder.length > 1) {
result[1] = holder[holder.length - 2];
result[0] = holder[holder.length - 1];
}
return result;
}
Example:
int bitarray = 12321;
String val = Integer.toString(bitarray, 2);
System.out.println(new StringBuilder().append(bitarray).append(':').append(val)
.append(':').append(Arrays.toString(getRoger(val))).append('\n'));
I have been disappointed with all of the solutions I have found to converting strings of bits to byte arrays and vice versa -- all have been buggy (even the BigInteger solution above), and very few are as efficient as they should be.
I realize the OP was only concerned with a bit string to an array of two bytes, which the BitInteger approach seems to work fine for. However, since this post is currently the first search result when searching "bit string to byte array java" in Google, I am going to post my general solution here for people dealing with huge strings and/or huge byte arrays.
Note that my solution below is the only solution I have ran that passes all of my test cases -- many online solutions to this relatively simple problem simply do not work.
Code
/**
* Zips (compresses) bit strings to byte arrays and unzips (decompresses)
* byte arrays to bit strings.
*
* #author ryan
*
*/
public class BitZip {
private static final byte[] BIT_MASKS = new byte[] {1, 2, 4, 8, 16, 32, 64, -128};
private static final int BITS_PER_BYTE = 8;
private static final int MAX_BIT_INDEX_IN_BYTE = BITS_PER_BYTE - 1;
/**
* Decompress the specified byte array to a string.
* <p>
* This function does not pad with zeros for any bit-string result
* with a length indivisible by 8.
*
* #param bytes The bytes to convert into a string of bits, with byte[0]
* consisting of the least significant bits in the byte array.
* #return The string of bits representing the byte array.
*/
public static final String unzip(final byte[] bytes) {
int byteCount = bytes.length;
int bitCount = byteCount * BITS_PER_BYTE;
char[] bits = new char[bitCount];
{
int bytesIndex = 0;
int iLeft = Math.max(bitCount - BITS_PER_BYTE, 0);
while (bytesIndex < byteCount) {
byte value = bytes[bytesIndex];
for (int b = MAX_BIT_INDEX_IN_BYTE; b >= 0; --b) {
bits[iLeft + b] = ((value % 2) == 0 ? '0' : '1');
value >>= 1;
}
iLeft = Math.max(iLeft - BITS_PER_BYTE, 0);
++bytesIndex;
}
}
return new String(bits).replaceFirst("^0+(?!$)", "");
}
/**
* Compresses the specified bit string to a byte array, ignoring trailing
* zeros past the most significant set bit.
*
* #param bits The string of bits (composed strictly of '0' and '1' characters)
* to convert into an array of bytes.
* #return The bits, as a byte array with byte[0] containing the least
* significant bits.
*/
public static final byte[] zip(final String bits) {
if ((bits == null) || bits.isEmpty()) {
// No observations -- return nothing.
return new byte[0];
}
char[] bitChars = bits.toCharArray();
int bitCount = bitChars.length;
int left;
for (left = 0; left < bitCount; ++left) {
// Ignore leading zeros.
if (bitChars[left] == '1') {
break;
}
}
if (bitCount == left) {
// Only '0's in the string.
return new byte[] {0};
}
int cBits = bitCount - left;
byte[] bytes = new byte[((cBits) / BITS_PER_BYTE) + (((cBits % BITS_PER_BYTE) > 0) ? 1 : 0)];
{
int iRight = bitCount - 1;
int iLeft = Math.max(bitCount - BITS_PER_BYTE, left);
int bytesIndex = 0;
byte _byte = 0;
while (bytesIndex < bytes.length) {
while (iLeft <= iRight) {
if (bitChars[iLeft] == '1') {
_byte |= BIT_MASKS[iRight - iLeft];
}
++iLeft;
}
bytes[bytesIndex++] = _byte;
iRight = Math.max(iRight - BITS_PER_BYTE, left);
iLeft = Math.max((1 + iRight) - BITS_PER_BYTE, left);
_byte = 0;
}
}
return bytes;
}
}
Performance
I was bored at work so I did some performance testing comparing against the accepted answer here for when N is large. (Pretending to ignore the fact that the BigInteger approach posted above doesn't even work properly as a general approach.)
This is running with a random bit string of size 5M and a random byte array of size 1M:
String -> byte[] -- BigInteger result: 39098ms
String -> byte[] -- BitZip result: 29ms
byte[] -> String -- Integer result: 138ms
byte[] -> String -- BitZip result: 71ms
And the code:
public static void main(String[] argv) {
int testByteLength = 1000000;
int testStringLength = 5000000;
// Independently random.
final byte[] randomBytes = new byte[testByteLength];
final String randomBitString;
{
StringBuilder sb = new StringBuilder();
Random rand = new Random();
for (int i = 0; i < testStringLength; ++i) {
int value = rand.nextInt(1 + i);
sb.append((value % 2) == 0 ? '0' : '1');
randomBytes[i % testByteLength] = (byte) value;
}
randomBitString = sb.toString();
}
byte[] resultCompress;
String resultDecompress;
{
Stopwatch s = new Stopwatch();
TimeUnit ms = TimeUnit.MILLISECONDS;
{
s.start();
{
resultCompress = compressFromBigIntegerToByteArray(randomBitString);
}
s.stop();
{
System.out.println("String -> byte[] -- BigInteger result: " + s.elapsed(ms) + "ms");
}
s.reset();
}
{
s.start();
{
resultCompress = zip(randomBitString);
}
s.stop();
{
System.out.println("String -> byte[] -- BitZip result: " + s.elapsed(ms) + "ms");
}
s.reset();
}
{
s.start();
{
resultDecompress = decompressFromIntegerParseInt(randomBytes);
}
s.stop();
{
System.out.println("byte[] -> String -- Integer result: " + s.elapsed(ms) + "ms");
}
s.reset();
}
{
s.start();
{
resultDecompress = unzip(randomBytes);
}
s.stop();
{
System.out.println("byte[] -> String -- BitZip result: " + s.elapsed(ms) + "ms");
}
s.reset();
}
}
}

Categories

Resources