Skip to content

Instantly share code, notes, and snippets.

@uupaa
Created July 18, 2013 21:19
Show Gist options
  • Select an option

  • Save uupaa/6033187 to your computer and use it in GitHub Desktop.

Select an option

Save uupaa/6033187 to your computer and use it in GitHub Desktop.
Base64.jsx
// JSX

var base64 = Base64.btoa(xhr.responseText, true);
// JSX
import "js.jsx";
import "js/web.jsx";

class Base64 {
    static var _indexToChar =
                "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split("");
    static var _charToIndex = {
                A:  0, B:  1, C:  2, D:  3, E:  4, F:  5, G:  6, H:  7, I:  8, J:  9,
                K: 10, L: 11, M: 12, N: 13, O: 14, P: 15, Q: 16, R: 17, S: 18, T: 19,
                U: 20, V: 21, W: 22, X: 23, Y: 24, Z: 25,
                a: 26, b: 27, c: 28, d: 29, e: 30, f: 31, g: 32, h: 33, i: 34, j: 35,
                k: 36, l: 37, m: 38, n: 39, o: 40, p: 41, q: 42, r: 43, s: 44, t: 45,
                u: 46, v: 47, w: 48, x: 49, y: 50, z: 51,
                0: 52, 1: 53, 2: 54, 3: 55, 4: 56, 5: 57, 6: 58, 7: 59, 8: 60, 9: 61,
                "+": 62, "-": 62, // URLSafe64 chars
                "/": 63, "_": 63, // URLSafe64 chars
                "=": 0            // padding
            }:Map.<int>;

    static function btoa(binary:string,
                         normalize:boolean = false):string {
        var window = js.global["window"] as __noconvert__ Window;

        if (window.btoa) {
            if (!normalize) {
                try {
                    return window.btoa(binary); // BinaryString to Base64String
                } catch (o_o:Error) {
                    // maybe. xhr response data has non ascii values.
                }
            }
            return window.btoa( BinaryString.normalize(binary, 0xff) );
        }
        return Base64.encode( BinaryString.toArray(binary, 0xff) );
    }
    static function atob(base64:string):string {
        var window = js.global["window"] as __noconvert__ Window;

        if (window.atob) {
            try {
                return window.atob(base64);
            } catch (o_o:Error) {
                // maybe. broken base64 data
            }
        }
        return BinaryString.fromArray( Base64.decode(base64) );
    }
    static function encode(ary:Array.<int>,
                           safe:boolean = false):string {
        var rv = []:Array.<string>;
        var c = 0;
        var i = -1;
        var iz = ary.length;
        var pad = [0, 2, 1][iz % 3];
        var chars = Base64._indexToChar;

        // 24bit binary string -> 32bit base64 binary string
        --iz;
        while (i < iz) {
            c =  ((ary[++i] & 0xff) << 16) |
                 ((ary[++i] & 0xff) <<  8) |
                  (ary[++i] & 0xff); // 24bit

            rv.push(chars[(c >> 18) & 0x3f],
                    chars[(c >> 12) & 0x3f],
                    chars[(c >>  6) & 0x3f],
                    chars[ c        & 0x3f]);
        }
        pad > 1 && (rv[rv.length - 2] = "=");
        pad > 0 && (rv[rv.length - 1] = "=");
        if (safe) {
            return rv.join("").replace(/\=+$/g, "").replace(/\+/g, "-").
                                                    replace(/\//g, "_");
        }
        return rv.join("");
    }
    static function decode(str:string):Array.<int> {
        var rv = []:Array.<int>;
        var c = 0;
        var i = 0;
        var ary = str.split("");
        var iz = str.length - 1;
        var codes = Base64._charToIndex;

        // 32bit base64 binary string -> 24bit binary string
        while (i < iz) {                // 00000000|00000000|00000000 (24bit)
            c = (codes[ary[i++]] << 18) // 111111  |        |
              | (codes[ary[i++]] << 12) //       11|1111    |
              | (codes[ary[i++]] <<  6) //         |    1111|11
              |  codes[ary[i++]];       //         |        |  111111
                                        //    v        v        v
            rv.push((c >> 16) & 0xff,   // --------
                    (c >>  8) & 0xff,   //          --------
                     c        & 0xff);  //                   --------
        }
        rv.length -= [0, 0, 2, 1][str.replace(/\=+$/, "").length % 4]; // cut tail

        return rv;
    }
}

class BinaryString {
    static function toArray(binary:string,
                            filter:int = 0xffff):Array.<int> {
        var i = 0, iz = binary.length, rv = new Array.<int>(iz);

        for (; i < iz; ++i) {
            rv[i] = binary.charCodeAt(i) & filter;
        }
        return rv;
    }
    static function fromArray(ary:Array.<int>):string {
        var rv = []:Array.<string>, i = 0, iz = ary.length, bulkSize = 32000;

        // Avoid String.fromCharCode.apply(null, BigArray) exception
        if (iz < bulkSize) {
          //return String.fromCharCode.apply(null, ary);
            return js.invoke(String, "fromCharCode", ary as __noconvert__ Array.<variant>) as string;
        }
        for (; i < iz; i += bulkSize) {
          //rv.push( String.fromCharCode.apply(null, ary.slice(i, i + bulkSize)) );
            rv.push(
                     js.invoke(String, "fromCharCode",
                               ary.slice(i, i + bulkSize) as __noconvert__ Array.<variant>) as string );

        }
        return rv.join("");
    }
    static function normalize(binary:string,
                              filter:int = 0xffff):string {
        return BinaryString.fromArray( BinaryString.toArray(binary, filter) );
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment