Getting the base-36 representation of a byte[8]

Hello all.

I am in the process of writing a _J2ME_ client for a properitary protocol transmitting stock data.

Simply put my problem is that I need to get the base-36 (0-9AZ) representation of a 64 bit _unsigned_ number (stored in a byte[8]).

To be more elaborate, I am encrypting a string using the Blowfish algorithm (from www.bouncycastle.org), and the resulting blocks are to be sent to the server as a base36 string representing the block.

Since I am on J2ME I do not have access to Sun's BigInteger, but Bouncycastle provides a lightweight one, however I think it is a bit buggy. Nor do I have access to the J2SE formatter classes.

Ideally I would want to do something like this:

Long.toString( (long)bytearray, 36 );

This of course do not work since

1) Jave does not support casting byte[] to long, this could however be fixed by bitshifting.

2) Long is always signed and I am really at a loss on how to do this.

Any ideas?

--

Regards Johan Seland

[1037 byte] By [Johan_Selanda] at [2007-9-29 6:14:03]
# 1
why not take all bytes and transform them into String Object, then concatenate each of them to make the whole thing?
evanzsa at 2007-7-14 20:21:43 > top of Java-index,Other Topics,Algorithms...
# 2

//low bytes first

byte[] bytes = new byte[] {1, 1, 0, 0, 0, 0, 0, 0};

long l = 0;

for (int i = 0; i < 8; i++) {

l |= (bytes[i] << (i * 8));

}

System.out.println(l);

The unsigned part is tricky. I can't easily comment on that.

Dimitris

ounosa at 2007-7-14 20:21:43 > top of Java-index,Other Topics,Algorithms...
# 3
A possibility would be to copy and modify the implementation of Long.toString(long, radix). It's not easy (if at all possible-due to the signum problem), as it uses package-private parts of Integer too.Wouldn't it be easier to copy BigInteger?
ounosa at 2007-7-14 20:21:43 > top of Java-index,Other Topics,Algorithms...
# 4

Is your byte array big endian or little endian? I'll assume little endian.

package base36;

import java.util.*;

/**

*

Single Sentence Description.

*

Long Description.

*

Copyright: © 2003

*

* @author Paul Murray

* @version 1.0

*/

public class Main

{

public static void main(String[] args) {

Main main1 = new Main();

main1.go();

}

void go() {

for (int i = 0; i < 13; i++) {

System.out.print("36 ^ " + i + " = ");

for (int j = 0; j < 8; j++) {

System.out.print(Integer.toHexString((((int)powers[i][j])>>4)&15));

System.out.print(Integer.toHexString(((int)powers[i][j])&15));

System.out.print(' ');

}

System.out.println(' ');

}

byte[] amt;

amt = new byte[] {0, 0, 0, 0, 0, 0, 0, 0};

dump(amt); System.out.println(" = " + cvt(amt));

amt = new byte[] {1, 0, 0, 0, 0, 0, 0, 0};

dump(amt); System.out.println(" = " + cvt(amt));

amt = new byte[] {0, 1, 0, 0, 0, 0, 0, 0};

dump(amt); System.out.println(" = " + cvt(amt));

amt = new byte[] { -1, -1, 0, 0, 0, 0, 0, 0};

dump(amt); System.out.println(" = " + cvt(amt));

amt = new byte[] { 0, 0, 1, 0, 0, 0, 0, 0};

dump(amt); System.out.println(" = " + cvt(amt));

amt = new byte[] { -1, -1, -1, -1, -1, -1, -1, -1};

dump(amt); System.out.println(" = " + cvt(amt));

amt = new byte[] { -2, -1, -1, -1, -1, -1, -1, -1};

dump(amt); System.out.println(" = " + cvt(amt));

}

void dump(byte[] d) {

for(int i=0;i<8;i++) {

System.out.print(Integer.toHexString((((int)d[i])>>4)&15));

System.out.print(Integer.toHexString(((int)d[i])&15));

System.out.print(' ');

}

}

/////////////////////////////////////////////////////////////////////////////

/**

* powers of 36. we use an array of short to nix sign extension. I happen to know that

* there are 13 powers of 36: n < 2^64

**/

static short[][] powers = new short[13][];

static {

// initialise the array of powers of 36

short[] p = new short[] {

1, 0, 0, 0, 0, 0, 0, 0};

int index = 0;

for (; ; ) {

powers[index] = new short[8];

System.arraycopy(p, 0, powers[index], 0, 8);

index++;

int carry = 0;

for (int i = 0; i < 8; i++) {

int mul = p[i] * 36 + carry;

p[i] = (short) (mul & 0xFF);

carry = mul >> 8;

}

if (carry != 0)

break;

}

assert index == 13:"there are exactly 13 64-bit powers of 36";

}

// use a single instance - not thread safe

short working[] = new short[8];

StringBuffer amt = new StringBuffer();

String cvt(byte[] n) {

if (n.length != 8)

throw new IllegalArgumentException("length of 8, please");

amt.setLength(0);

for (int i = 0; i < 8; i++)

working[i] = (short) ( ( (int) n[i]) & 0xFF);

for (int currentPower = 12; currentPower >= 0; currentPower--) {

int digit = 0;

while (lessThanOrEqualToWorking(powers[currentPower])) {

digit++;

subtractFromWorking(powers[currentPower]);

}

if (digit < 10) {

amt.append((char)('0' + digit));

}

else {

amt.append((char)('A' + digit - 10));

}

}

return amt.toString();

}

boolean lessThanOrEqualToWorking(short[] p) {

assert p.length == 8;

for (int i = 7; i >= 0; i--) {

if (p[i] > working[i])

return false;

if (p[i] < working[i])

return true;

}

return true;

}

void subtractFromWorking(short[] p) {

assert p.length == 8;

boolean carry = false;

for (int i = 0; i < 8; i++) {

if (carry)

working[i]--;

working[i] -= p[i];

if (working[i] < 0) {

working[i] += 256;

carry = true;

}

else {

carry = false;

}

}

assert!carry:"param must be < working";

}

}

pmuurray@bigpond.coma at 2007-7-14 20:21:43 > top of Java-index,Other Topics,Algorithms...
# 5

Hey Johan,

how about this one?

class Test {

public static void main(String[] args) {

char c;

byte[] bytes = new byte[] { 1, 3, 7, 15, 31, 63, 127, 85, 1, 3, 7, 15, 31, 63, 127, 85};

System.out.println(toBase36(bytes));

}

public static String toBase36(byte[] bytes) {

//can provide a (byte[], offset, length) method too

StringBuffer sb = new StringBuffer();

int bitsUsed = 0; //will point how many bits from the int are to be encoded

int temp = 0;

int tempBits = 0;

long swap;

int position = 0;

while ((position < bytes.length) || (bitsUsed != 0)) {

swap = 0;

if (tempBits > 0) {

//there are bits left over from previous iteration

swap = temp;

bitsUsed = tempBits;

tempBits = 0;

}

//fill some bytes

while ((position < bytes.length) && (bitsUsed < 36)) {

swap <<= 8;

swap |= bytes[position++];

bitsUsed += 8;

}

if (bitsUsed > 36) {

tempBits = bitsUsed - 36; //this is always 4

temp = (int)(swap & ((1 << tempBits) - 1)); //get low bits

swap >>= tempBits; //remove low bits

bitsUsed = 36;

}

sb.append(Long.toString(swap, 36));

bitsUsed = 0;

}

return sb.toString();

}

}

It translates 36 bits a time. They do fit into a long :-)

ounosa at 2007-7-14 20:21:43 > top of Java-index,Other Topics,Algorithms...