├── .gitignore ├── .travis.yml ├── scripts └── prepublish ├── bower.json ├── LICENSE ├── package.json ├── base64.min.js ├── Makefile ├── README.md ├── base64.js └── test └── base64.coffee /.gitignore: -------------------------------------------------------------------------------- 1 | /coverage/ 2 | /node_modules/ 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.8" 4 | - "0.10" 5 | - "0.11" 6 | install: make setup 7 | script: make test 8 | -------------------------------------------------------------------------------- /scripts/prepublish: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | rm -f base64.min.js 5 | make base64.min.js 6 | git add base64.min.js 7 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "base64", 3 | "version": "0.3.0", 4 | "description": "Base64 encoding and decoding", 5 | "main": "./base64.js", 6 | "license": "WTFPL", 7 | "repository": { 8 | "type": "git", 9 | "url": "git://github.com/davidchambers/Base64.js.git" 10 | }, 11 | "ignore": [ 12 | "**/.*", 13 | "Makefile", 14 | "coverage/", 15 | "scripts/", 16 | "test/" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 3 | Version 2, December 2004 4 | 5 | Copyright (c) 2011..2012 David Chambers 6 | 7 | Everyone is permitted to copy and distribute verbatim or modified 8 | copies of this license document, and changing it is allowed as long 9 | as the name is changed. 10 | 11 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 12 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 13 | 14 | 0. You just DO WHAT THE FUCK YOU WANT TO. 15 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Base64", 3 | "version": "0.3.0", 4 | "description": "Base64 encoding and decoding", 5 | "author": "David Chambers ", 6 | "main": "./base64.js", 7 | "licenses": [ 8 | { 9 | "type": "WTFPL", 10 | "url": "https://raw.github.com/davidchambers/Base64.js/master/LICENSE" 11 | } 12 | ], 13 | "repository": { 14 | "type": "git", 15 | "url": "git://github.com/davidchambers/Base64.js.git" 16 | }, 17 | "devDependencies": { 18 | "coffee-script": "1.8.x", 19 | "istanbul": "0.2.x", 20 | "mocha": "1.18.x", 21 | "uglify-js": "2.4.x", 22 | "xyz": "0.5.x" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /base64.min.js: -------------------------------------------------------------------------------- 1 | !function(){function t(t){this.message=t}var r="undefined"!=typeof exports?exports:this,e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";t.prototype=new Error,t.prototype.name="InvalidCharacterError",r.btoa||(r.btoa=function(r){for(var o,n,a=String(r),i=0,c=e,d="";a.charAt(0|i)||(c="=",i%1);d+=c.charAt(63&o>>8-i%1*8)){if(n=a.charCodeAt(i+=.75),n>255)throw new t("'btoa' failed: The string to be encoded contains characters outside of the Latin1 range.");o=o<<8|n}return d}),r.atob||(r.atob=function(r){var o=String(r).replace(/=+$/,"");if(o.length%4==1)throw new t("'atob' failed: The string to be decoded is not correctly encoded.");for(var n,a,i=0,c=0,d="";a=o.charAt(c++);~a&&(n=i%4?64*n+a:a,i++%4)?d+=String.fromCharCode(255&n>>(-2*i&6)):0)a=e.indexOf(a);return d})}(); -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ISTANBUL = node_modules/.bin/istanbul 2 | UGLIFYJS = node_modules/.bin/uglifyjs 3 | XYZ = node_modules/.bin/xyz --message X.Y.Z --tag X.Y.Z --repo git@github.com:davidchambers/Base64.js.git --script scripts/prepublish 4 | 5 | SRC = base64.js 6 | MIN = $(patsubst %.js,%.min.js,$(SRC)) 7 | 8 | 9 | .PHONY: all 10 | all: $(MIN) 11 | 12 | %.min.js: %.js 13 | $(UGLIFYJS) $< --compress --mangle > $@ 14 | 15 | 16 | .PHONY: bytes 17 | bytes: base64.min.js 18 | gzip --best --stdout $< | wc -c | tr -d ' ' 19 | 20 | 21 | .PHONY: clean 22 | clean: 23 | rm -f -- $(MIN) 24 | 25 | 26 | .PHONY: release-major release-minor release-patch 27 | release-major release-minor release-patch: 28 | @$(XYZ) --increment $(@:release-%=%) 29 | 30 | 31 | .PHONY: setup 32 | setup: 33 | npm install 34 | 35 | 36 | .PHONY: test 37 | test: 38 | $(ISTANBUL) cover node_modules/.bin/_mocha -- --compilers coffee:coffee-script/register 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Base64.js 2 | 3 | ≈ 500 byte* polyfill for browsers which don't provide [`window.btoa`][1] and 4 | [`window.atob`][2]. 5 | 6 | Although the script does no harm in browsers which do provide these functions, 7 | a conditional script loader such as [yepnope][3] can prevent unnecessary HTTP 8 | requests. 9 | 10 | ```javascript 11 | yepnope({ 12 | test: window.btoa && window.atob, 13 | nope: 'base64.js', 14 | callback: function () { 15 | // `btoa` and `atob` are now safe to use 16 | } 17 | }) 18 | ``` 19 | 20 | Base64.js stems from a [gist][4] by [yahiko][5]. 21 | 22 | ### Running the test suite 23 | 24 | make setup 25 | make test 26 | 27 | \* Minified and gzipped. Run `make bytes` to verify. 28 | 29 | 30 | [1]: https://developer.mozilla.org/en/DOM/window.btoa 31 | [2]: https://developer.mozilla.org/en/DOM/window.atob 32 | [3]: http://yepnopejs.com/ 33 | [4]: https://gist.github.com/229984 34 | [5]: https://github.com/yahiko 35 | -------------------------------------------------------------------------------- /base64.js: -------------------------------------------------------------------------------- 1 | ;(function () { 2 | 3 | var object = typeof exports != 'undefined' ? exports : this; // #8: web workers 4 | var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; 5 | 6 | function InvalidCharacterError(message) { 7 | this.message = message; 8 | } 9 | InvalidCharacterError.prototype = new Error; 10 | InvalidCharacterError.prototype.name = 'InvalidCharacterError'; 11 | 12 | // encoder 13 | // [https://gist.github.com/999166] by [https://github.com/nignag] 14 | object.btoa || ( 15 | object.btoa = function (input) { 16 | var str = String(input); 17 | for ( 18 | // initialize result and counter 19 | var block, charCode, idx = 0, map = chars, output = ''; 20 | // if the next str index does not exist: 21 | // change the mapping table to "=" 22 | // check if d has no fractional digits 23 | str.charAt(idx | 0) || (map = '=', idx % 1); 24 | // "8 - idx % 1 * 8" generates the sequence 2, 4, 6, 8 25 | output += map.charAt(63 & block >> 8 - idx % 1 * 8) 26 | ) { 27 | charCode = str.charCodeAt(idx += 3/4); 28 | if (charCode > 0xFF) { 29 | throw new InvalidCharacterError("'btoa' failed: The string to be encoded contains characters outside of the Latin1 range."); 30 | } 31 | block = block << 8 | charCode; 32 | } 33 | return output; 34 | }); 35 | 36 | // decoder 37 | // [https://gist.github.com/1020396] by [https://github.com/atk] 38 | object.atob || ( 39 | object.atob = function (input) { 40 | var str = String(input).replace(/=+$/, ''); 41 | if (str.length % 4 == 1) { 42 | throw new InvalidCharacterError("'atob' failed: The string to be decoded is not correctly encoded."); 43 | } 44 | for ( 45 | // initialize result and counters 46 | var bc = 0, bs, buffer, idx = 0, output = ''; 47 | // get next character 48 | buffer = str.charAt(idx++); 49 | // character found in table? initialize bit storage and add its ascii value; 50 | ~buffer && (bs = bc % 4 ? bs * 64 + buffer : buffer, 51 | // and if not first of each 4 characters, 52 | // convert the first 8 bits to one ascii character 53 | bc++ % 4) ? output += String.fromCharCode(255 & bs >> (-2 * bc & 6)) : 0 54 | ) { 55 | // try to find character in table (0-63, not found => -1) 56 | buffer = chars.indexOf(buffer); 57 | } 58 | return output; 59 | }); 60 | 61 | }()); 62 | -------------------------------------------------------------------------------- /test/base64.coffee: -------------------------------------------------------------------------------- 1 | assert = require 'assert' 2 | 3 | {btoa, atob} = require '..' 4 | 5 | 6 | describe 'Base64.js', -> 7 | 8 | it 'can encode ASCII input', -> 9 | assert.strictEqual btoa(''), '' 10 | assert.strictEqual btoa('f'), 'Zg==' 11 | assert.strictEqual btoa('fo'), 'Zm8=' 12 | assert.strictEqual btoa('foo'), 'Zm9v' 13 | assert.strictEqual btoa('quux'), 'cXV1eA==' 14 | assert.strictEqual btoa('!"#$%'), 'ISIjJCU=' 15 | assert.strictEqual btoa("&'()*+"), 'JicoKSor' 16 | assert.strictEqual btoa(',-./012'), 'LC0uLzAxMg==' 17 | assert.strictEqual btoa('3456789:'), 'MzQ1Njc4OTo=' 18 | assert.strictEqual btoa(';<=>?@ABC'), 'Ozw9Pj9AQUJD' 19 | assert.strictEqual btoa('DEFGHIJKLM'), 'REVGR0hJSktMTQ==' 20 | assert.strictEqual btoa('NOPQRSTUVWX'), 'Tk9QUVJTVFVWV1g=' 21 | assert.strictEqual btoa('YZ[\\]^_`abc'), 'WVpbXF1eX2BhYmM=' 22 | assert.strictEqual btoa('defghijklmnop'), 'ZGVmZ2hpamtsbW5vcA==' 23 | assert.strictEqual btoa('qrstuvwxyz{|}~'), 'cXJzdHV2d3h5ent8fX4=' 24 | 25 | it 'cannot encode non-ASCII input', -> 26 | assert.throws (-> btoa '✈'), (err) -> 27 | err instanceof Error and 28 | err.name is 'InvalidCharacterError' and 29 | err.message is "'btoa' failed: The string to be encoded contains characters outside of the Latin1 range." 30 | 31 | it 'coerces input', -> 32 | assert.strictEqual btoa(42), btoa('42') 33 | assert.strictEqual btoa(null), btoa('null') 34 | assert.strictEqual btoa({x: 1}), btoa('[object Object]') 35 | 36 | it 'can decode Base64-encoded input', -> 37 | assert.strictEqual atob(''), '' 38 | assert.strictEqual atob('Zg=='), 'f' 39 | assert.strictEqual atob('Zm8='), 'fo' 40 | assert.strictEqual atob('Zm9v'), 'foo' 41 | assert.strictEqual atob('cXV1eA=='), 'quux' 42 | assert.strictEqual atob('ISIjJCU='), '!"#$%' 43 | assert.strictEqual atob('JicoKSor'), "&'()*+" 44 | assert.strictEqual atob('LC0uLzAxMg=='), ',-./012' 45 | assert.strictEqual atob('MzQ1Njc4OTo='), '3456789:' 46 | assert.strictEqual atob('Ozw9Pj9AQUJD'), ';<=>?@ABC' 47 | assert.strictEqual atob('REVGR0hJSktMTQ=='), 'DEFGHIJKLM' 48 | assert.strictEqual atob('Tk9QUVJTVFVWV1g='), 'NOPQRSTUVWX' 49 | assert.strictEqual atob('WVpbXF1eX2BhYmM='), 'YZ[\\]^_`abc' 50 | assert.strictEqual atob('ZGVmZ2hpamtsbW5vcA=='), 'defghijklmnop' 51 | assert.strictEqual atob('cXJzdHV2d3h5ent8fX4='), 'qrstuvwxyz{|}~' 52 | 53 | it 'cannot decode invalid input', -> 54 | assert.throws (-> atob 'a'), (err) -> 55 | err instanceof Error and 56 | err.name is 'InvalidCharacterError' and 57 | err.message is "'atob' failed: The string to be decoded is not correctly encoded." 58 | 59 | it 'coerces input', -> 60 | assert.strictEqual atob(42), atob('42') 61 | assert.strictEqual atob(null), atob('null') 62 | --------------------------------------------------------------------------------