1.12 Encoding and Decoding Base64 Strings

NN 2, IE 3

1.12.1 Problem

You want to convert a string to or from Base64 encoding.

1.12.2 Solution

Use the functions of the base64.js library shown in the Discussion. Syntax for invoking the two functions is straightforward. To encode a string, invoke:

var encodedString = base64Encode("stringToEncode");

To decode a string, invoke:

var plainString = base64Decode("encodedString");

1.12.3 Discussion

Example 1-2 shows the entire base64.js library.

Example 1-2. base64.js library
// Global lookup arrays for base64 conversions
var enc64List, dec64List;
   
// Load the lookup arrays once
function initBase64( ) {
    enc64List = new Array( );
    dec64List = new Array( );
    var i;
    for (i = 0; i < 26; i++) {
        enc64List[enc64List.length] = String.fromCharCode(65 + i);
    }
    for (i = 0; i < 26; i++) {
        enc64List[enc64List.length] = String.fromCharCode(97 + i);
    }
    for (i = 0; i < 10; i++) {
        enc64List[enc64List.length] = String.fromCharCode(48 + i);
    }
    enc64List[enc64List.length] = "+";
    enc64List[enc64List.length] = "/";
    for (i = 0; i < 128; i++) {
        dec64List[dec64List.length] = -1;
    }
    for (i = 0; i < 64; i++) {
        dec64List[enc64List[i].charCodeAt(0)] = i;
    }
}
   
// Encode a string
function base64Encode(str) {
    var c, d, e, end = 0;
    var u, v, w, x;
    var ptr = -1;
    var input = str.split("");
    var output = "";
    while(end =  = 0) {
        c = (typeof input[++ptr] != "undefined") ? input[ptr].charCodeAt(0) : 
            ((end = 1) ? 0 : 0);
        d = (typeof input[++ptr] != "undefined") ? input[ptr].charCodeAt(0) : 
            ((end += 1) ? 0 : 0);
        e = (typeof input[++ptr] != "undefined") ? input[ptr].charCodeAt(0) : 
            ((end += 1) ? 0 : 0);
        u = enc64List[c >> 2];
        v = enc64List[(0x00000003 & c) << 4 | d >> 4];
        w = enc64List[(0x0000000F & d) << 2 | e >> 6];
        x = enc64List[e & 0x0000003F];
        
        // handle padding to even out unevenly divisible string lengths
        if (end >= 1) {x = "=";}
        if (end =  = 2) {w = "=";}
        if (end < 3) {output += u + v + w + x;}
    }
    // format for 76-character line lengths per RFC
    var formattedOutput = "";
    var lineLength = 76;
    while (output.length > lineLength) {
        formattedOutput += output.substring(0, lineLength) + "\n";
        output = output.substring(lineLength);
    }
    formattedOutput += output;
    return formattedOutput;
}
   
// Decode a string
function base64Decode(str) {
    var c=0, d=0, e=0, f=0, i=0, n=0;
    var input = str.split("");
    var output = "";
    var ptr = 0;
    do {
        f = input[ptr++].charCodeAt(0);
        i = dec64List[f];
        if ( f >= 0 && f < 128 && i != -1 ) {
            if ( n % 4 =  = 0 ) {
                c = i << 2;
            } else if ( n % 4 =  = 1 ) {
                c = c | ( i >> 4 );
                d = ( i & 0x0000000F ) << 4;
            } else if ( n % 4 =  = 2 ) {
                d = d | ( i >> 2 );
                e = ( i & 0x00000003 ) << 6;
            } else {
                e = e | i;
            }
            n++;
            if ( n % 4 =  = 0 ) {
                output += String.fromCharCode(c) + 
                          String.fromCharCode(d) + 
                          String.fromCharCode(e);
            }
        }
    } while (typeof input[ptr] != "undefined");
    output += (n % 4 =  = 3) ? String.fromCharCode(c) + String.fromCharCode(d) : 
              ((n % 4 =  = 2) ? String.fromCharCode(c) : "");
    return output;
}
   
// Self-initialize the global variables
initBase64( );

The library begins with two global declarations and an initialization function that creates lookup tables for the character conversions. At the end of the library is a statement that invokes the initialization function.

Scripts may call the base64Encode( ) function directly to convert a standard string to a Base64-encoded string. The value of the original string is not changed, but the function returns an encoded copy. To convert an encoded string to a standard string, use the base64Decode( ) function, passing the encoded string as an argument.

Netscape 6 and later include global methods that perform the same conversions shown at length in the solution. The atob( ) method converts a Base64-encoded string to a plain string; the btoa( ) method converts a plain string to a Base64-encoded string. These methods are not part of the ECMAScript standard used as the foundation for these browser versions, so it's unclear when or if they will find their way into other browsers.

Frankly, there hasn't been a big need for Base64 encoding in most scripted web pages, but that's perhaps because the facilities weren't readily available. A Base64-encoded string contains a very small character set: a-z, A-Z, 0-9, +, /, and =. This low common denominator scheme allows data of any type to be conveyed by virtually any internet protocol. Binary attachments to your email are encoded as Base64 strings for their journey en route. Your email client decodes the simple string and generates the image, document, or executable file that arrives with the message. You may find additional ways to apply Base64-encoded data in your pages and scripts. To learn more about Base64 encoding, visit http://www.ietf.org/rfc/rfc2045.txt.

1.12.4 See Also

Recipe 1.11 for URL-encoding techniques.