1

I need to convert a number to byte array and then back to number. The problem is that the byte array is of variable size, so I need to convert a number given his byte length, the methods that I came up with are those: (Java)

private static byte[] toArray(long value, int bytes) {
    byte[] res = new byte[bytes];

    final int max = bytes*8;
    for(int i = 1; i <= bytes; i++)
        res[i - 1] = (byte) (value >> (max - 8 * i));

    return res;
}

private static long toLong(byte[] value) {
    long res = 0;

    for (byte b : value)
        res = (res << 8) | (b & 0xff);

    return res;
}

Here I use a long because 8 is the max bytes we can use. This method works perfectly with positive numbers but I can't seem to make the decoding work with negatives.

EDIT: to test this I've tried with processing the value Integer.MIN_VALUE + 1 (-2147483647) and 4 bytes

SnowyCoder
  • 213
  • 7
  • 18
  • Dunno if your issue is solved now but... See if my Answer helps you with handling large negative values. – VC.One Jan 13 '17 at 16:26

2 Answers2

1

Take a look at Apache Common Conversion.intToByteArray util method.

JavaDoc:

Converts a int into an array of byte using the default (little endian, Lsb0) byte and bit ordering

Andrii Abramov
  • 10,019
  • 9
  • 74
  • 96
1

After accepting this as working solution, the Asker made some further optimizations.
I have included their own
linked code below for reference :

private static long toLong(byte[] value) {
    ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);
    final byte val = (byte) (value[0] < 0 ? 0xFF : 0);

    for(int i = value.length; i < Long.BYTES; i++)
        buffer.put(val);

    buffer.put(value);
    return buffer.getLong(0);
}

OLDER ANSWER

edit : Based on comments (understanding Question better)

To make your toLong function handle both negative & positive numbers try this:

private static long toLong(byte[] value) 
{
    long res = 0;
    int tempInt = 0;
    String tempStr = ""; //holds temp string Hex values

    tempStr = bytesToHex(value);

    if (value[0] < 0 ) 
    { 
        tempInt = value.length;
        for (int i=tempInt; i<8; i++) { tempStr = ("FF" + tempStr); }

        res = Long.parseUnsignedLong(tempStr, 16); 
    }
    else { res = Long.parseLong(tempStr, 16); }

    return res;

}

Below is related bytesToHex function (re-factored to work out-of-box with any byte[] input...)

public static String bytesToHex(byte[] bytes)
{ String tempStr = ""; tempStr = DatatypeConverter.printHexBinary(bytes); return tempStr; }


VC.One
  • 14,790
  • 4
  • 25
  • 57
  • 1
    This is not variable, I cannot say "put this number in 5 bytes" or "get my number from those 5 bytes" – SnowyCoder Jan 13 '17 at 18:59
  • You aren't supposed to put in just 5 bytes only. All languages / OS read as 1, 2, 4 or 8 bytes at once. If your number needs 5 bytes only then you're already in a situation where you actually must read as 8 bytes. Use [**bit-shifting**](http://stackoverflow.com/a/141873/2057709) to keep your 40 bits (5 bytes) at one side of Array and fill remaining 3 byte slots with zero bits. – VC.One Jan 13 '17 at 19:29
  • I did already do something like it (see my question) but the problem is that I don't know how to deal with negative values – SnowyCoder Jan 13 '17 at 19:43
  • What is the problem exactly? I tried `myByteArray = toArray(-2147483647, 8);` and I got result `FFFFFFFF80000001` which is correct. The **toArray** is your own function and result is checked via my function **bytesToHex**. – VC.One Jan 13 '17 at 21:06
  • 1
    I made my tests using my methods and yout bytesToHex: byte[] toArr = toArray(Integer.MIN_VALUE + 1, 4); System.out.println(bytesToHex(toArr)); System.out.println(toLong(toArr)); Result: "80000001" and "2147483649", negativity lost :/ – SnowyCoder Jan 13 '17 at 21:32
  • I get your point now... check the new edit. I've tested the output and it works fine. **Note** : when you do `someNum = toArray( amount, length)` if _length_ does not fit the required _amount_ then answer returned is always _1_. Maybe you could have some safety check (ie: a `While` loop) where if result is an unexpected "1" then keep trying again with a continual _length+1_ increment (until a not-1 result). – VC.One Jan 14 '17 at 15:10
  • 1
    Thank you for the answer, I wrote a slightly optimized version of it (the string operations aren't really fast) here's the new version using java's ByteBuffer http://pastebin.com/JKy8s5A6 – SnowyCoder Jan 14 '17 at 16:50