3

I need to convert some strings using Base64 encoding, and was delighted to see that I didn't have to roll my own converter--Java provides one with javax.xml.bind.DataConverter. However, it has some problems. Here's the output of my time with a Jython REPL:

>>> import javax.xml.bind.DatatypeConverter as DC
>>> import java.lang.String as String
>>> def foo(text):
...   return DC.printBase64Binary(DC.parseBase64Binary(String(text)))
... 
>>> foo("hello")
'hell'
>>> foo("This, it's a punctuated sentence.")
'Thisitsapunctuatedsenten'
>>> foo("\"foo\" \"bar\"")
'foob'
>>> foo("\"foo\" \"bar\"12")
'foobar12'
>>> foo("\"foo\" \"bar\"1")
'foob'

As you can see, it doesn't handle non-alphanumeric characters at all, and also frequently--but not always--truncates the string by two characters.

I guess it might be time to just write my own class, but now I'm bothered that either a) I'm failing at reading the javadoc or something b) The class doesn't work as expected.

So any help is much appreciated; thanks in advance.

tsm
  • 3,598
  • 2
  • 21
  • 35
  • possible duplicate of [Decode Base64 data in java](http://stackoverflow.com/questions/469695/decode-base64-data-in-java) – NPE Jun 07 '11 at 13:32
  • @aix: I don't think so... that doesn't talk about the situation in this question at all. – Jon Skeet Jun 07 '11 at 13:32
  • @aix I've already looked at that post several times :) The problem is I can't use third-party libraries. It is where I got the idea to try `javax.xml.bind` though. – tsm Jun 07 '11 at 13:42

6 Answers6

12

hello is not a base64 String, so the parsing fails. You must convert the string into a byte array (try String(text).getBytes('UTF-8')) and then call DC.printBase64Binary() on the byte array to get the data in Base64.

DC.parseBase64Binary() will then convert this Base64 encoded data back into the byte array (which you can then convert back into a string).

Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
  • Thanks! I got thrown off by `parseBase64Binary()` accepting a String--I failed to realize it had to be an encoded String. Doing it your way has passed all my test cases--great! – tsm Jun 07 '11 at 13:51
7

A few findings after spending time resolving a similar problem on a GAE platform (Base64 decoder eats last (two) characters when decoding a base64-string from facebook)

If the encoded string is not of a 4*n length then the method DatatypeConverter.parseBase64Binary might drop some trailing characters (rendering the JSON payload syntactically wrong). My solution was to add the following code:

while (payload.length() % 4 != 0) payload += "=";

With regards to the code example in the question, I would suggest a change where the test string gets first encoded and then decoded, ie:

return DC.parseBase64Binary(DC.printBase64Binary(String(text).getBytes()))
Draško Kokić
  • 1,280
  • 1
  • 19
  • 34
1

You're not giving it complete base64 (including final padding) etc to start with. If you give it a complete base64 string, it should be fine.

You should only try to interpret data as if it's base64 if it really is base64 to start with. Doing it with arbitrary character sequences is a bad idea.

It's unclear what you're really trying to do, if you're not actually starting with base64 data. You talk about "converting some strings" - are they base64 or not?

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
0
import javax.xml.bind.DatatypeConverter;
import java.io.UnsupportedEncodingException;
import java.lang.String ;
public class HttpBasicAuthenticationHeader {

 public static void main(String[] args) {
 DatatypeConverter dc;

 String str="ENCODE";

String s="";

try {
s=javax.xml.bind.DatatypeConverter.printBase64Binary(str.getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}
System.out.println(s);
 }
Prasun
  • 1
0

I'm receiving the data in Deflater zip technique. So, a little function to be decompressed is:

public byte[] descomprimir() throws IOException, DataFormatException {
    final String wsData = "eNqzsa/IzVEoSy0qzszPs1Uy1DNQUkjNS85PycxLt1XyDPbXtbAwtdQ1VLK347JJTixJzMlPzy/Wt+MCAAU6ETY=";
    byte[] data = DatatypeConverter.parseBase64Binary(wsData);

    Inflater inflater = new Inflater();
    inflater.setInput(data);
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream(data.length);
    byte[] buffer = new byte[1024];
    while (!inflater.finished()) {
        int count = inflater.inflate(buffer);
        outputStream.write(buffer, 0, count);
    }
    outputStream.close();
    byte[] output = outputStream.toByteArray();
    return output;
}

Then you can convert the byte to a new String or anything else.

0

I think that the javax.xml.bind.DatatypeConverter class may expect to work with XML data or XSD types, as the JavaDoc method states for the parameter:

A string containing lexical representation of xsd:base64Binary

Personally I wouldn't feel comfortable using a class/library oriented towards XML transformations for something like this.

Take a look at the commons-codec library, which has an easy-to-use Base64 class.

matt b
  • 138,234
  • 66
  • 282
  • 345
  • I can't use third-party libraries, so commons-codec is out, unfortunately. I guess you're right about `DatatypeConverter` being inappropriate...time to write my own, I suppose. ¶ All I really want is the equivalent of Python's `("foo".encode("base64")).decode("base64")`. – tsm Jun 07 '11 at 13:46