├── .editorconfig ├── .gitattributes ├── .gitignore ├── .travis.yml ├── Gruntfile.js ├── LICENSE-MIT.txt ├── README.md ├── base64.js ├── package.json ├── scripts └── export-data.js ├── src └── base64.js └── tests └── tests.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = tab 6 | end_of_line = lf 7 | insert_final_newline = true 8 | trim_trailing_whitespace = true 9 | 10 | [{README.md,*.yml}] 11 | indent_style = space 12 | indent_size = 2 13 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Automatically normalize line endings for all text-based files 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Coverage report 2 | coverage 3 | 4 | # Installed npm modules 5 | node_modules 6 | 7 | # Folder view configuration files 8 | .DS_Store 9 | Desktop.ini 10 | 11 | # Thumbnail cache files 12 | ._* 13 | Thumbs.db 14 | 15 | # Files that might appear on external disks 16 | .Spotlight-V100 17 | .Trashes 18 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "10" 4 | - "12" 5 | before_script: 6 | - "npm install -g grunt-cli" 7 | script: 8 | - "grunt ci" 9 | after_script: 10 | - "grunt shell:cover-coveralls" 11 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | grunt.initConfig({ 4 | 'shell': { 5 | 'options': { 6 | 'stdout': true, 7 | 'stderr': true, 8 | 'failOnError': true 9 | }, 10 | 'cover-html': { 11 | 'command': 'istanbul cover --report "html" --verbose --dir "coverage" "tests/tests.js"' 12 | }, 13 | 'cover-coveralls': { 14 | 'command': 'istanbul cover --verbose --dir "coverage" "tests/tests.js" && coveralls < coverage/lcov.info; rm -rf coverage/lcov*' 15 | }, 16 | 'test-node': { 17 | 'command': 'echo "Testing in Node..."; npm test' 18 | }, 19 | 'test-browser': { 20 | 'command': 'echo "Testing in a browser..."; open "tests/index.html"; open "tests/index.html?norequire=true"' 21 | } 22 | }, 23 | 'template': { 24 | 'build': { 25 | 'options': { 26 | 'data': function() { 27 | return require('./scripts/export-data.js'); 28 | } 29 | }, 30 | 'files': { 31 | 'base64.js': ['src/base64.js'] 32 | } 33 | } 34 | } 35 | }); 36 | 37 | grunt.loadNpmTasks('grunt-shell'); 38 | grunt.loadNpmTasks('grunt-template'); 39 | 40 | grunt.registerTask('cover', 'shell:cover-html'); 41 | grunt.registerTask('ci', [ 42 | 'template', 43 | 'shell:test-node' 44 | ]); 45 | grunt.registerTask('test', [ 46 | 'ci', 47 | 'shell:test-browser' 48 | ]); 49 | 50 | grunt.registerTask('fetch', [ 51 | 'shell:fetch', 52 | 'build' 53 | ]); 54 | 55 | grunt.registerTask('build', [ 56 | 'default' 57 | ]); 58 | 59 | grunt.registerTask('default', [ 60 | 'template', 61 | 'shell:test-node' 62 | ]); 63 | 64 | }; 65 | -------------------------------------------------------------------------------- /LICENSE-MIT.txt: -------------------------------------------------------------------------------- 1 | Copyright Mathias Bynens 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # base64 [![Build status](https://travis-ci.org/mathiasbynens/base64.svg?branch=master)](https://travis-ci.org/mathiasbynens/base64) [![Code coverage status](http://img.shields.io/coveralls/mathiasbynens/base64/master.svg)](https://coveralls.io/r/mathiasbynens/base64) 2 | 3 | _base64_ is a robust base64 encoder/decoder that is fully compatible with [`atob()` and `btoa()`](https://html.spec.whatwg.org/multipage/webappapis.html#atob), written in JavaScript. The base64-encoding and -decoding algorithms it uses are fully [RFC 4648](https://tools.ietf.org/html/rfc4648#section-4) compliant. 4 | 5 | ## Installation 6 | 7 | Via [npm](https://www.npmjs.com/): 8 | 9 | ```bash 10 | npm install base-64 11 | ``` 12 | 13 | In a browser: 14 | 15 | ```html 16 | 17 | ``` 18 | 19 | In [Narwhal](http://narwhaljs.org/), [Node.js](https://nodejs.org/), and [RingoJS](http://ringojs.org/): 20 | 21 | ```js 22 | var base64 = require('base-64'); 23 | ``` 24 | 25 | In [Rhino](http://www.mozilla.org/rhino/): 26 | 27 | ```js 28 | load('base64.js'); 29 | ``` 30 | 31 | Using an AMD loader like [RequireJS](http://requirejs.org/): 32 | 33 | ```js 34 | require( 35 | { 36 | 'paths': { 37 | 'base64': 'path/to/base64' 38 | } 39 | }, 40 | ['base64'], 41 | function(base64) { 42 | console.log(base64); 43 | } 44 | ); 45 | ``` 46 | 47 | ## API 48 | 49 | ### `base64.version` 50 | 51 | A string representing the semantic version number. 52 | 53 | ### `base64.encode(input)` 54 | 55 | This function takes a byte string (the `input` parameter) and encodes it according to base64. The input data must be in the form of a string containing only characters in the range from U+0000 to U+00FF, each representing a binary byte with values `0x00` to `0xFF`. The `base64.encode()` function is designed to be fully compatible with [`btoa()` as described in the HTML Standard](https://html.spec.whatwg.org/multipage/webappapis.html#dom-windowbase64-btoa). 56 | 57 | ```js 58 | var encodedData = base64.encode(input); 59 | ``` 60 | 61 | To base64-encode any Unicode string, [encode it as UTF-8 first](https://github.com/mathiasbynens/utf8.js#utf8encodestring): 62 | 63 | ```js 64 | var base64 = require('base-64'); 65 | var utf8 = require('utf8'); 66 | 67 | var text = 'foo © bar 𝌆 baz'; 68 | var bytes = utf8.encode(text); 69 | var encoded = base64.encode(bytes); 70 | console.log(encoded); 71 | // → 'Zm9vIMKpIGJhciDwnYyGIGJheg==' 72 | ``` 73 | 74 | ### `base64.decode(input)` 75 | 76 | This function takes a base64-encoded string (the `input` parameter) and decodes it. The return value is in the form of a string containing only characters in the range from U+0000 to U+00FF, each representing a binary byte with values `0x00` to `0xFF`. The `base64.decode()` function is designed to be fully compatible with [`atob()` as described in the HTML Standard](https://html.spec.whatwg.org/multipage/webappapis.html#dom-windowbase64-atob). 77 | 78 | ```js 79 | var decodedData = base64.decode(encodedData); 80 | ``` 81 | 82 | To base64-decode UTF-8-encoded data back into a Unicode string, [UTF-8-decode it](https://github.com/mathiasbynens/utf8.js#utf8decodebytestring) after base64-decoding it: 83 | 84 | ```js 85 | var encoded = 'Zm9vIMKpIGJhciDwnYyGIGJheg=='; 86 | var bytes = base64.decode(encoded); 87 | var text = utf8.decode(bytes); 88 | console.log(text); 89 | // → 'foo © bar 𝌆 baz' 90 | ``` 91 | 92 | ## Support 93 | 94 | _base64_ is designed to work in at least Node.js v0.10.0, Narwhal 0.3.2, RingoJS 0.8-0.9, PhantomJS 1.9.0, Rhino 1.7RC4, as well as old and modern versions of Chrome, Firefox, Safari, Opera, and Internet Explorer. 95 | 96 | ## Unit tests & code coverage 97 | 98 | After cloning this repository, run `npm install` to install the dependencies needed for development and testing. You may want to install Istanbul _globally_ using `npm install istanbul -g`. 99 | 100 | Once that’s done, you can run the unit tests in Node using `npm test` or `node tests/tests.js`. To run the tests in Rhino, Ringo, Narwhal, and web browsers as well, use `grunt test`. 101 | 102 | To generate the code coverage report, use `grunt cover`. 103 | 104 | ## Author 105 | 106 | | [![twitter/mathias](https://gravatar.com/avatar/24e08a9ea84deb17ae121074d0f17125?s=70)](https://twitter.com/mathias "Follow @mathias on Twitter") | 107 | |---| 108 | | [Mathias Bynens](https://mathiasbynens.be/) | 109 | 110 | ## License 111 | 112 | _base64_ is available under the [MIT](https://mths.be/mit) license. 113 | -------------------------------------------------------------------------------- /base64.js: -------------------------------------------------------------------------------- 1 | /*! https://mths.be/base64 v1.0.0 by @mathias | MIT license */ 2 | ;(function(root) { 3 | 4 | // Detect free variables `exports`. 5 | var freeExports = typeof exports == 'object' && exports; 6 | 7 | // Detect free variable `module`. 8 | var freeModule = typeof module == 'object' && module && 9 | module.exports == freeExports && module; 10 | 11 | // Detect free variable `global`, from Node.js or Browserified code, and use 12 | // it as `root`. 13 | var freeGlobal = typeof global == 'object' && global; 14 | if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) { 15 | root = freeGlobal; 16 | } 17 | 18 | /*--------------------------------------------------------------------------*/ 19 | 20 | var InvalidCharacterError = function(message) { 21 | this.message = message; 22 | }; 23 | InvalidCharacterError.prototype = new Error; 24 | InvalidCharacterError.prototype.name = 'InvalidCharacterError'; 25 | 26 | var error = function(message) { 27 | // Note: the error messages used throughout this file match those used by 28 | // the native `atob`/`btoa` implementation in Chromium. 29 | throw new InvalidCharacterError(message); 30 | }; 31 | 32 | var TABLE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; 33 | // http://whatwg.org/html/common-microsyntaxes.html#space-character 34 | var REGEX_SPACE_CHARACTERS = /[\t\n\f\r ]/g; 35 | 36 | // `decode` is designed to be fully compatible with `atob` as described in the 37 | // HTML Standard. http://whatwg.org/html/webappapis.html#dom-windowbase64-atob 38 | // The optimized base64-decoding algorithm used is based on @atk’s excellent 39 | // implementation. https://gist.github.com/atk/1020396 40 | var decode = function(input) { 41 | input = String(input) 42 | .replace(REGEX_SPACE_CHARACTERS, ''); 43 | var length = input.length; 44 | if (length % 4 == 0) { 45 | input = input.replace(/==?$/, ''); 46 | length = input.length; 47 | } 48 | if ( 49 | length % 4 == 1 || 50 | // http://whatwg.org/C#alphanumeric-ascii-characters 51 | /[^+a-zA-Z0-9/]/.test(input) 52 | ) { 53 | error( 54 | 'Invalid character: the string to be decoded is not correctly encoded.' 55 | ); 56 | } 57 | var bitCounter = 0; 58 | var bitStorage; 59 | var buffer; 60 | var output = ''; 61 | var position = -1; 62 | while (++position < length) { 63 | buffer = TABLE.indexOf(input.charAt(position)); 64 | bitStorage = bitCounter % 4 ? bitStorage * 64 + buffer : buffer; 65 | // Unless this is the first of a group of 4 characters… 66 | if (bitCounter++ % 4) { 67 | // …convert the first 8 bits to a single ASCII character. 68 | output += String.fromCharCode( 69 | 0xFF & bitStorage >> (-2 * bitCounter & 6) 70 | ); 71 | } 72 | } 73 | return output; 74 | }; 75 | 76 | // `encode` is designed to be fully compatible with `btoa` as described in the 77 | // HTML Standard: http://whatwg.org/html/webappapis.html#dom-windowbase64-btoa 78 | var encode = function(input) { 79 | input = String(input); 80 | if (/[^\0-\xFF]/.test(input)) { 81 | // Note: no need to special-case astral symbols here, as surrogates are 82 | // matched, and the input is supposed to only contain ASCII anyway. 83 | error( 84 | 'The string to be encoded contains characters outside of the ' + 85 | 'Latin1 range.' 86 | ); 87 | } 88 | var padding = input.length % 3; 89 | var output = ''; 90 | var position = -1; 91 | var a; 92 | var b; 93 | var c; 94 | var buffer; 95 | // Make sure any padding is handled outside of the loop. 96 | var length = input.length - padding; 97 | 98 | while (++position < length) { 99 | // Read three bytes, i.e. 24 bits. 100 | a = input.charCodeAt(position) << 16; 101 | b = input.charCodeAt(++position) << 8; 102 | c = input.charCodeAt(++position); 103 | buffer = a + b + c; 104 | // Turn the 24 bits into four chunks of 6 bits each, and append the 105 | // matching character for each of them to the output. 106 | output += ( 107 | TABLE.charAt(buffer >> 18 & 0x3F) + 108 | TABLE.charAt(buffer >> 12 & 0x3F) + 109 | TABLE.charAt(buffer >> 6 & 0x3F) + 110 | TABLE.charAt(buffer & 0x3F) 111 | ); 112 | } 113 | 114 | if (padding == 2) { 115 | a = input.charCodeAt(position) << 8; 116 | b = input.charCodeAt(++position); 117 | buffer = a + b; 118 | output += ( 119 | TABLE.charAt(buffer >> 10) + 120 | TABLE.charAt((buffer >> 4) & 0x3F) + 121 | TABLE.charAt((buffer << 2) & 0x3F) + 122 | '=' 123 | ); 124 | } else if (padding == 1) { 125 | buffer = input.charCodeAt(position); 126 | output += ( 127 | TABLE.charAt(buffer >> 2) + 128 | TABLE.charAt((buffer << 4) & 0x3F) + 129 | '==' 130 | ); 131 | } 132 | 133 | return output; 134 | }; 135 | 136 | var base64 = { 137 | 'encode': encode, 138 | 'decode': decode, 139 | 'version': '1.0.0' 140 | }; 141 | 142 | // Some AMD build optimizers, like r.js, check for specific condition patterns 143 | // like the following: 144 | if ( 145 | typeof define == 'function' && 146 | typeof define.amd == 'object' && 147 | define.amd 148 | ) { 149 | define(function() { 150 | return base64; 151 | }); 152 | } else if (freeExports && !freeExports.nodeType) { 153 | if (freeModule) { // in Node.js or RingoJS v0.8.0+ 154 | freeModule.exports = base64; 155 | } else { // in Narwhal or RingoJS v0.7.0- 156 | for (var key in base64) { 157 | base64.hasOwnProperty(key) && (freeExports[key] = base64[key]); 158 | } 159 | } 160 | } else { // in Rhino or a web browser 161 | root.base64 = base64; 162 | } 163 | 164 | }(this)); 165 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "base-64", 3 | "version": "1.0.0", 4 | "description": "A robust base64 encoder/decoder that is fully compatible with `atob()` and `btoa()`, written in JavaScript.", 5 | "homepage": "https://mths.be/base64", 6 | "main": "base64.js", 7 | "keywords": [ 8 | "codec", 9 | "decoder", 10 | "encoder", 11 | "base64", 12 | "atob", 13 | "btoa" 14 | ], 15 | "license": "MIT", 16 | "author": { 17 | "name": "Mathias Bynens", 18 | "url": "https://mathiasbynens.be/" 19 | }, 20 | "repository": { 21 | "type": "git", 22 | "url": "https://github.com/mathiasbynens/base64.git" 23 | }, 24 | "bugs": "https://github.com/mathiasbynens/base64/issues", 25 | "files": [ 26 | "LICENSE-MIT.txt", 27 | "base64.js" 28 | ], 29 | "scripts": { 30 | "test": "mocha tests/tests.js", 31 | "build": "grunt build" 32 | }, 33 | "devDependencies": { 34 | "coveralls": "^2.11.4", 35 | "grunt": "^0.4.5", 36 | "grunt-cli": "^1.3.2", 37 | "grunt-shell": "^1.1.2", 38 | "grunt-template": "^0.2.3", 39 | "istanbul": "^0.4.0", 40 | "mocha": "^6.2.0", 41 | "regenerate": "^1.2.1" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /scripts/export-data.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var regenerate = require('regenerate'); 3 | 4 | // http://whatwg.org/html/common-microsyntaxes.html#space-character 5 | var spaceCharacters = regenerate( 6 | 0x0020, // U+0020 SPACE 7 | 0x0009, // U+0009 CHARACTER TABULATION (tab) 8 | 0x000A, // U+000A LINE FEED (LF) 9 | 0x000C, // U+000C FORM FEED (FF) 10 | 0x000D // U+000D CARRIAGE RETURN (CR) 11 | ); 12 | 13 | module.exports = { 14 | 'spaceCharacters': spaceCharacters.toString(), 15 | 'version': JSON.parse(fs.readFileSync('package.json', 'utf-8')).version 16 | }; 17 | -------------------------------------------------------------------------------- /src/base64.js: -------------------------------------------------------------------------------- 1 | /*! https://mths.be/base64 v<%= version %> by @mathias | MIT license */ 2 | ;(function(root) { 3 | 4 | // Detect free variables `exports`. 5 | var freeExports = typeof exports == 'object' && exports; 6 | 7 | // Detect free variable `module`. 8 | var freeModule = typeof module == 'object' && module && 9 | module.exports == freeExports && module; 10 | 11 | // Detect free variable `global`, from Node.js or Browserified code, and use 12 | // it as `root`. 13 | var freeGlobal = typeof global == 'object' && global; 14 | if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) { 15 | root = freeGlobal; 16 | } 17 | 18 | /*--------------------------------------------------------------------------*/ 19 | 20 | var InvalidCharacterError = function(message) { 21 | this.message = message; 22 | }; 23 | InvalidCharacterError.prototype = new Error; 24 | InvalidCharacterError.prototype.name = 'InvalidCharacterError'; 25 | 26 | var error = function(message) { 27 | // Note: the error messages used throughout this file match those used by 28 | // the native `atob`/`btoa` implementation in Chromium. 29 | throw new InvalidCharacterError(message); 30 | }; 31 | 32 | var TABLE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; 33 | // http://whatwg.org/html/common-microsyntaxes.html#space-character 34 | var REGEX_SPACE_CHARACTERS = /<%= spaceCharacters %>/g; 35 | 36 | // `decode` is designed to be fully compatible with `atob` as described in the 37 | // HTML Standard. http://whatwg.org/html/webappapis.html#dom-windowbase64-atob 38 | // The optimized base64-decoding algorithm used is based on @atk’s excellent 39 | // implementation. https://gist.github.com/atk/1020396 40 | var decode = function(input) { 41 | input = String(input) 42 | .replace(REGEX_SPACE_CHARACTERS, ''); 43 | var length = input.length; 44 | if (length % 4 == 0) { 45 | input = input.replace(/==?$/, ''); 46 | length = input.length; 47 | } 48 | if ( 49 | length % 4 == 1 || 50 | // http://whatwg.org/C#alphanumeric-ascii-characters 51 | /[^+a-zA-Z0-9/]/.test(input) 52 | ) { 53 | error( 54 | 'Invalid character: the string to be decoded is not correctly encoded.' 55 | ); 56 | } 57 | var bitCounter = 0; 58 | var bitStorage; 59 | var buffer; 60 | var output = ''; 61 | var position = -1; 62 | while (++position < length) { 63 | buffer = TABLE.indexOf(input.charAt(position)); 64 | bitStorage = bitCounter % 4 ? bitStorage * 64 + buffer : buffer; 65 | // Unless this is the first of a group of 4 characters… 66 | if (bitCounter++ % 4) { 67 | // …convert the first 8 bits to a single ASCII character. 68 | output += String.fromCharCode( 69 | 0xFF & bitStorage >> (-2 * bitCounter & 6) 70 | ); 71 | } 72 | } 73 | return output; 74 | }; 75 | 76 | // `encode` is designed to be fully compatible with `btoa` as described in the 77 | // HTML Standard: http://whatwg.org/html/webappapis.html#dom-windowbase64-btoa 78 | var encode = function(input) { 79 | input = String(input); 80 | if (/[^\0-\xFF]/.test(input)) { 81 | // Note: no need to special-case astral symbols here, as surrogates are 82 | // matched, and the input is supposed to only contain ASCII anyway. 83 | error( 84 | 'The string to be encoded contains characters outside of the ' + 85 | 'Latin1 range.' 86 | ); 87 | } 88 | var padding = input.length % 3; 89 | var output = ''; 90 | var position = -1; 91 | var a; 92 | var b; 93 | var c; 94 | var buffer; 95 | // Make sure any padding is handled outside of the loop. 96 | var length = input.length - padding; 97 | 98 | while (++position < length) { 99 | // Read three bytes, i.e. 24 bits. 100 | a = input.charCodeAt(position) << 16; 101 | b = input.charCodeAt(++position) << 8; 102 | c = input.charCodeAt(++position); 103 | buffer = a + b + c; 104 | // Turn the 24 bits into four chunks of 6 bits each, and append the 105 | // matching character for each of them to the output. 106 | output += ( 107 | TABLE.charAt(buffer >> 18 & 0x3F) + 108 | TABLE.charAt(buffer >> 12 & 0x3F) + 109 | TABLE.charAt(buffer >> 6 & 0x3F) + 110 | TABLE.charAt(buffer & 0x3F) 111 | ); 112 | } 113 | 114 | if (padding == 2) { 115 | a = input.charCodeAt(position) << 8; 116 | b = input.charCodeAt(++position); 117 | buffer = a + b; 118 | output += ( 119 | TABLE.charAt(buffer >> 10) + 120 | TABLE.charAt((buffer >> 4) & 0x3F) + 121 | TABLE.charAt((buffer << 2) & 0x3F) + 122 | '=' 123 | ); 124 | } else if (padding == 1) { 125 | buffer = input.charCodeAt(position); 126 | output += ( 127 | TABLE.charAt(buffer >> 2) + 128 | TABLE.charAt((buffer << 4) & 0x3F) + 129 | '==' 130 | ); 131 | } 132 | 133 | return output; 134 | }; 135 | 136 | var base64 = { 137 | 'encode': encode, 138 | 'decode': decode, 139 | 'version': '<%= version %>' 140 | }; 141 | 142 | // Some AMD build optimizers, like r.js, check for specific condition patterns 143 | // like the following: 144 | if ( 145 | typeof define == 'function' && 146 | typeof define.amd == 'object' && 147 | define.amd 148 | ) { 149 | define(function() { 150 | return base64; 151 | }); 152 | } else if (freeExports && !freeExports.nodeType) { 153 | if (freeModule) { // in Node.js or RingoJS v0.8.0+ 154 | freeModule.exports = base64; 155 | } else { // in Narwhal or RingoJS v0.7.0- 156 | for (var key in base64) { 157 | base64.hasOwnProperty(key) && (freeExports[key] = base64[key]); 158 | } 159 | } 160 | } else { // in Rhino or a web browser 161 | root.base64 = base64; 162 | } 163 | 164 | }(this)); 165 | -------------------------------------------------------------------------------- /tests/tests.js: -------------------------------------------------------------------------------- 1 | const base64 = require('../base64.js'); 2 | 3 | const assert = require('assert'); 4 | 5 | describe('base64.encode', function() { 6 | it('should work', function() { 7 | assert.equal( 8 | base64.encode('\0\x01\x02\x03\x04\x05\x06\x07\b\t\n\x0B\f\r\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7F'), 9 | 'AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn8=', 10 | 'All possible octets' 11 | ); 12 | assert.equal( 13 | base64.encode('a'), 14 | 'YQ==', 15 | 'Two padding characters' 16 | ); 17 | assert.equal( 18 | base64.encode('aa'), 19 | 'YWE=', 20 | 'One padding character' 21 | ); 22 | assert.equal( 23 | base64.encode('aaa'), 24 | 'YWFh', 25 | 'No padding characters' 26 | ); 27 | assert.equal( 28 | base64.encode('foo\0'), 29 | 'Zm9vAA==', 30 | 'U+0000' 31 | ); 32 | assert.equal( 33 | base64.encode('foo\0\0'), 34 | 'Zm9vAAA=', 35 | 'U+0000' 36 | ); 37 | // Tests from https://tools.ietf.org/html/rfc4648#section-10 38 | assert.equal( 39 | base64.encode(''), 40 | '', 41 | 'empty string' 42 | ); 43 | assert.equal( 44 | base64.encode('f'), 45 | 'Zg==' 46 | ); 47 | assert.equal( 48 | base64.encode('fo'), 49 | 'Zm8=' 50 | ); 51 | assert.equal( 52 | base64.encode('foo'), 53 | 'Zm9v' 54 | ); 55 | assert.equal( 56 | base64.encode('foob'), 57 | 'Zm9vYg==' 58 | ); 59 | assert.equal( 60 | base64.encode('fooba'), 61 | 'Zm9vYmE=' 62 | ); 63 | assert.equal( 64 | base64.encode('foobar'), 65 | 'Zm9vYmFy' 66 | ); 67 | // Tests from https://github.com/w3c/web-platform-tests/blob/master/html/webappapis/atob/base64.html 68 | assert.throws( 69 | function() { 70 | base64.encode('\u05E2\u05D1\u05E8\u05D9\u05EA'); 71 | } 72 | ); 73 | assert.equal( 74 | (function() { 75 | try { 76 | base64.encode('\u05E2\u05D1\u05E8\u05D9\u05EA'); 77 | } catch (exception) { 78 | return exception.name; 79 | } 80 | }()), 81 | 'InvalidCharacterError' 82 | ); 83 | assert.equal( 84 | base64.encode('\xFF\xFF\xC0'), 85 | '///A' 86 | ); 87 | assert.equal( 88 | base64.encode('\0'), 89 | 'AA==' 90 | ); 91 | assert.equal( 92 | base64.encode('\0a'), 93 | 'AGE=' 94 | ); 95 | assert.equal( 96 | base64.encode(undefined), 97 | 'dW5kZWZpbmVk' 98 | ); 99 | assert.equal( 100 | base64.encode(null), 101 | 'bnVsbA==' 102 | ); 103 | assert.equal( 104 | base64.encode(7), 105 | 'Nw==' 106 | ); 107 | assert.equal( 108 | base64.encode(1.5), 109 | 'MS41' 110 | ); 111 | assert.equal( 112 | base64.encode(true), 113 | 'dHJ1ZQ==' 114 | ); 115 | assert.equal( 116 | base64.encode(false), 117 | 'ZmFsc2U=' 118 | ); 119 | assert.equal( 120 | base64.encode(NaN), 121 | 'TmFO' 122 | ); 123 | assert.equal( 124 | base64.encode(-Infinity), 125 | 'LUluZmluaXR5' 126 | ); 127 | assert.equal( 128 | base64.encode(+Infinity), 129 | 'SW5maW5pdHk=' 130 | ); 131 | assert.equal( 132 | base64.encode(-0), 133 | 'MA==' 134 | ); 135 | assert.equal( 136 | base64.encode(+0), 137 | 'MA==' 138 | ); 139 | assert.equal( 140 | base64.encode({ 'toString': function() { return 'foo'; } }), 141 | 'Zm9v' 142 | ); 143 | assert.throws( 144 | function() { 145 | base64.encode({ 'toString': function() { throw new RangeError(); } }); 146 | }, 147 | RangeError 148 | ); 149 | assert.throws( 150 | function() { 151 | base64.encode('\uD800\uDC00'); 152 | } 153 | ); 154 | assert.equal( 155 | (function() { 156 | try { 157 | base64.encode('\uD800\uDC00'); 158 | } catch (exception) { 159 | return exception.name; 160 | } 161 | }()), 162 | 'InvalidCharacterError' 163 | ); 164 | }); 165 | }); 166 | 167 | describe('base64.decode', function() { 168 | it('should work', function() { 169 | assert.equal( 170 | base64.decode('AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn8='), 171 | '\0\x01\x02\x03\x04\x05\x06\x07\b\t\n\x0B\f\r\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7F', 172 | 'All possible octets' 173 | ); 174 | assert.equal( 175 | base64.decode('AAECA\t\n\f\r wQFBgcICQoLDA0ODx\t\n\f\r AREhMUFRYXGBkaGxwdHh8gIS\t\n\f\r IjJCUmJygpKissLS4vMDEyMzQ1Njc4OT\t\n\f\r o7PD0+P0BBQkNERUZHSElKS0xNT\t\n\f\r k9QUVJTVFVWV1hZWltcXV5fY\t\n\f\r GFiY2RlZmdoaWprbG\t\n\f\r 1ub3BxcnN0dXZ3eH\t\n\f\r l6e3x9fn8='), 176 | '\0\x01\x02\x03\x04\x05\x06\x07\b\t\n\x0B\f\r\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7F', 177 | 'HTML space characters must be stripped before decoding' 178 | ); 179 | assert.throws( 180 | function() { 181 | base64.decode('YQ==='); 182 | }, 183 | /Invalid character/, 184 | 'Invalid character' 185 | ); 186 | assert.equal( 187 | (function() { 188 | try { 189 | base64.decode('YQ==='); 190 | } catch (exception) { 191 | return exception.name; 192 | } 193 | }()), 194 | 'InvalidCharacterError', 195 | 'The string to be decoded is not correctly encoded.' 196 | ); 197 | assert.equal( 198 | base64.decode('YQ=='), 199 | 'a', 200 | 'Two padding characters' 201 | ); 202 | assert.equal( 203 | base64.decode('YWE='), 204 | 'aa', 205 | 'One padding character' 206 | ); 207 | assert.equal( 208 | base64.decode('YWFh'), 209 | 'aaa', 210 | 'No padding characters' 211 | ); 212 | assert.equal( 213 | base64.decode('YQ'), 214 | 'a', 215 | 'Discarded bits' 216 | ); 217 | assert.equal( 218 | base64.decode('YR'), 219 | 'a', 220 | 'Discarded bits' 221 | ); 222 | assert.equal( 223 | base64.decode('Zm9vIGJhciBiYXo='), 224 | 'foo bar baz', 225 | 'One-character padding `=`' 226 | ); 227 | assert.equal( 228 | base64.decode('Zm9vIGJhcg=='), 229 | 'foo bar', 230 | 'Two-character padding `==`' 231 | ); 232 | assert.equal( 233 | base64.decode('Zm9v'), 234 | 'foo', 235 | 'No padding' 236 | ); 237 | assert.equal( 238 | base64.decode('Zm9vAA=='), 239 | 'foo\0', 240 | 'U+0000' 241 | ); 242 | assert.equal( 243 | base64.decode('Zm9vAAA='), 244 | 'foo\0\0', 245 | 'U+0000' 246 | ); 247 | // Tests from https://github.com/w3c/web-platform-tests/blob/master/html/webappapis/atob/base64.html 248 | assert.equal( 249 | base64.decode(''), 250 | '' 251 | ); 252 | assert.equal( 253 | base64.decode('abcd'), 254 | 'i\xB7\x1D' 255 | ); 256 | assert.equal( 257 | base64.decode(' abcd'), 258 | 'i\xB7\x1D' 259 | ); 260 | assert.equal( 261 | base64.decode('abcd '), 262 | 'i\xB7\x1D' 263 | ); 264 | assert.throws( 265 | function() { 266 | base64.decode('abcd==='); 267 | } 268 | ); 269 | assert.equal( 270 | (function() { 271 | try { 272 | base64.decode('abcd==='); 273 | } catch (exception) { 274 | return exception.name; 275 | } 276 | }()), 277 | 'InvalidCharacterError', 278 | ); 279 | assert.throws( 280 | function() { 281 | base64.decode(' abcd==='); 282 | } 283 | ); 284 | assert.equal( 285 | (function() { 286 | try { 287 | base64.decode(' abcd==='); 288 | } catch (exception) { 289 | return exception.name; 290 | } 291 | }()), 292 | 'InvalidCharacterError' 293 | ); 294 | assert.throws( 295 | function() { 296 | base64.decode('abcd=== '); 297 | } 298 | ); 299 | assert.equal( 300 | (function() { 301 | try { 302 | base64.decode('abcd=== '); 303 | } catch (exception) { 304 | return exception.name; 305 | } 306 | }()), 307 | 'InvalidCharacterError' 308 | ); 309 | assert.throws( 310 | function() { 311 | base64.decode('abcd ==='); 312 | } 313 | ); 314 | assert.equal( 315 | (function() { 316 | try { 317 | base64.decode('abcd ==='); 318 | } catch (exception) { 319 | return exception.name; 320 | } 321 | }()), 322 | 'InvalidCharacterError' 323 | ); 324 | assert.throws( 325 | function() { 326 | base64.decode('a'); 327 | } 328 | ); 329 | assert.equal( 330 | (function() { 331 | try { 332 | base64.decode('a'); 333 | } catch (exception) { 334 | return exception.name; 335 | } 336 | }()), 337 | 'InvalidCharacterError' 338 | ); 339 | assert.equal( 340 | base64.decode('ab'), 341 | 'i' 342 | ); 343 | assert.equal( 344 | base64.decode('abc'), 345 | 'i\xB7' 346 | ); 347 | assert.throws( 348 | function() { 349 | base64.decode('abcde'); 350 | } 351 | ); 352 | assert.equal( 353 | (function() { 354 | try { 355 | base64.decode('abcde'); 356 | } catch (exception) { 357 | return exception.name; 358 | } 359 | }()), 360 | 'InvalidCharacterError' 361 | ); 362 | assert.throws( 363 | function() { 364 | base64.decode('\uD800\uDC00'); 365 | } 366 | ); 367 | assert.equal( 368 | (function() { 369 | try { 370 | base64.decode('\uD800\uDC00'); 371 | } catch (exception) { 372 | return exception.name; 373 | } 374 | }()), 375 | 'InvalidCharacterError' 376 | ); 377 | assert.throws( 378 | function() { 379 | base64.decode('='); 380 | } 381 | ); 382 | assert.equal( 383 | (function() { 384 | try { 385 | base64.decode('='); 386 | } catch (exception) { 387 | return exception.name; 388 | } 389 | }()), 390 | 'InvalidCharacterError' 391 | ); 392 | assert.throws( 393 | function() { 394 | base64.decode('=='); 395 | } 396 | ); 397 | assert.equal( 398 | (function() { 399 | try { 400 | base64.decode('=='); 401 | } catch (exception) { 402 | return exception.name; 403 | } 404 | }()), 405 | 'InvalidCharacterError' 406 | ); 407 | assert.throws( 408 | function() { 409 | base64.decode('==='); 410 | } 411 | ); 412 | assert.equal( 413 | (function() { 414 | try { 415 | base64.decode('==='); 416 | } catch (exception) { 417 | return exception.name; 418 | } 419 | }()), 420 | 'InvalidCharacterError' 421 | ); 422 | assert.throws( 423 | function() { 424 | base64.decode('===='); 425 | }, 426 | ); 427 | assert.equal( 428 | (function() { 429 | try { 430 | base64.decode('===='); 431 | } catch (exception) { 432 | return exception.name; 433 | } 434 | }()), 435 | 'InvalidCharacterError' 436 | ); 437 | assert.throws( 438 | function() { 439 | base64.decode('====='); 440 | } 441 | ); 442 | assert.equal( 443 | (function() { 444 | try { 445 | base64.decode('====='); 446 | } catch (exception) { 447 | return exception.name; 448 | } 449 | }()), 450 | 'InvalidCharacterError' 451 | ); 452 | assert.throws( 453 | function() { 454 | base64.decode('a='); 455 | } 456 | ); 457 | assert.equal( 458 | (function() { 459 | try { 460 | base64.decode('a='); 461 | } catch (exception) { 462 | return exception.name; 463 | } 464 | }()), 465 | 'InvalidCharacterError' 466 | ); 467 | assert.throws( 468 | function() { 469 | base64.decode('a=='); 470 | } 471 | ); 472 | assert.equal( 473 | (function() { 474 | try { 475 | base64.decode('a=='); 476 | } catch (exception) { 477 | return exception.name; 478 | } 479 | }()), 480 | 'InvalidCharacterError' 481 | ); 482 | assert.throws( 483 | function() { 484 | base64.decode('a==='); 485 | } 486 | ); 487 | assert.equal( 488 | (function() { 489 | try { 490 | base64.decode('a==='); 491 | } catch (exception) { 492 | return exception.name; 493 | } 494 | }()), 495 | 'InvalidCharacterError' 496 | ); 497 | assert.throws( 498 | function() { 499 | base64.decode('a===='); 500 | } 501 | ); 502 | assert.equal( 503 | (function() { 504 | try { 505 | base64.decode('a===='); 506 | } catch (exception) { 507 | return exception.name; 508 | } 509 | }()), 510 | 'InvalidCharacterError' 511 | ); 512 | assert.throws( 513 | function() { 514 | base64.decode('a====='); 515 | } 516 | ); 517 | assert.equal( 518 | (function() { 519 | try { 520 | base64.decode('a====='); 521 | } catch (exception) { 522 | return exception.name; 523 | } 524 | }()), 525 | 'InvalidCharacterError' 526 | ); 527 | assert.throws( 528 | function() { 529 | base64.decode('ab='); 530 | } 531 | ); 532 | assert.equal( 533 | (function() { 534 | try { 535 | base64.decode('ab='); 536 | } catch (exception) { 537 | return exception.name; 538 | } 539 | }()), 540 | 'InvalidCharacterError' 541 | ); 542 | assert.equal( 543 | base64.decode('ab=='), 544 | 'i' 545 | ); 546 | assert.throws( 547 | function() { 548 | base64.decode('ab==='); 549 | } 550 | ); 551 | assert.equal( 552 | (function() { 553 | try { 554 | base64.decode('ab==='); 555 | } catch (exception) { 556 | return exception.name; 557 | } 558 | }()), 559 | 'InvalidCharacterError' 560 | ); 561 | assert.throws( 562 | function() { 563 | base64.decode('ab===='); 564 | } 565 | ); 566 | assert.equal( 567 | (function() { 568 | try { 569 | base64.decode('ab===='); 570 | } catch (exception) { 571 | return exception.name; 572 | } 573 | }()), 574 | 'InvalidCharacterError' 575 | ); 576 | assert.throws( 577 | function() { 578 | base64.decode('ab====='); 579 | } 580 | ); 581 | assert.equal( 582 | (function() { 583 | try { 584 | base64.decode('ab====='); 585 | } catch (exception) { 586 | return exception.name; 587 | } 588 | }()), 589 | 'InvalidCharacterError' 590 | ); 591 | assert.equal( 592 | base64.decode('abc='), 593 | 'i\xB7' 594 | ); 595 | assert.throws( 596 | function() { 597 | base64.decode('abc=='); 598 | } 599 | ); 600 | assert.equal( 601 | (function() { 602 | try { 603 | base64.decode('abc=='); 604 | } catch (exception) { 605 | return exception.name; 606 | } 607 | }()), 608 | 'InvalidCharacterError', 609 | ); 610 | assert.throws( 611 | function() { 612 | base64.decode('abc==='); 613 | } 614 | ); 615 | assert.equal( 616 | (function() { 617 | try { 618 | base64.decode('abc==='); 619 | } catch (exception) { 620 | return exception.name; 621 | } 622 | }()), 623 | 'InvalidCharacterError' 624 | ); 625 | assert.throws( 626 | function() { 627 | base64.decode('abc===='); 628 | } 629 | ); 630 | assert.equal( 631 | (function() { 632 | try { 633 | base64.decode('abc===='); 634 | } catch (exception) { 635 | return exception.name; 636 | } 637 | }()), 638 | 'InvalidCharacterError' 639 | ); 640 | assert.throws( 641 | function() { 642 | base64.decode('abc====='); 643 | } 644 | ); 645 | assert.equal( 646 | (function() { 647 | try { 648 | base64.decode('abc====='); 649 | } catch (exception) { 650 | return exception.name; 651 | } 652 | }()), 653 | 'InvalidCharacterError' 654 | ); 655 | assert.throws( 656 | function() { 657 | base64.decode('abcd='); 658 | } 659 | ); 660 | assert.equal( 661 | (function() { 662 | try { 663 | base64.decode('abcd='); 664 | } catch (exception) { 665 | return exception.name; 666 | } 667 | }()), 668 | 'InvalidCharacterError' 669 | ); 670 | assert.throws( 671 | function() { 672 | base64.decode('abcd=='); 673 | } 674 | ); 675 | assert.equal( 676 | (function() { 677 | try { 678 | base64.decode('abcd=='); 679 | } catch (exception) { 680 | return exception.name; 681 | } 682 | }()), 683 | 'InvalidCharacterError' 684 | ); 685 | assert.throws( 686 | function() { 687 | base64.decode('abcd==='); 688 | } 689 | ); 690 | assert.equal( 691 | (function() { 692 | try { 693 | base64.decode('abcd==='); 694 | } catch (exception) { 695 | return exception.name; 696 | } 697 | }()), 698 | 'InvalidCharacterError' 699 | ); 700 | assert.throws( 701 | function() { 702 | base64.decode('abcd===='); 703 | } 704 | ); 705 | assert.equal( 706 | (function() { 707 | try { 708 | base64.decode('abcd===='); 709 | } catch (exception) { 710 | return exception.name; 711 | } 712 | }()), 713 | 'InvalidCharacterError' 714 | ); 715 | assert.throws( 716 | function() { 717 | base64.decode('abcd====='); 718 | } 719 | ); 720 | assert.equal( 721 | (function() { 722 | try { 723 | base64.decode('abcd====='); 724 | } catch (exception) { 725 | return exception.name; 726 | } 727 | }()), 728 | 'InvalidCharacterError' 729 | ); 730 | assert.throws( 731 | function() { 732 | base64.decode('abcde='); 733 | } 734 | ); 735 | assert.equal( 736 | (function() { 737 | try { 738 | base64.decode('abcde='); 739 | } catch (exception) { 740 | return exception.name; 741 | } 742 | }()), 743 | 'InvalidCharacterError' 744 | ); 745 | assert.throws( 746 | function() { 747 | base64.decode('abcde=='); 748 | } 749 | ); 750 | assert.equal( 751 | (function() { 752 | try { 753 | base64.decode('abcde=='); 754 | } catch (exception) { 755 | return exception.name; 756 | } 757 | }()), 758 | 'InvalidCharacterError' 759 | ); 760 | assert.throws( 761 | function() { 762 | base64.decode('abcde==='); 763 | } 764 | ); 765 | assert.equal( 766 | (function() { 767 | try { 768 | base64.decode('abcde==='); 769 | } catch (exception) { 770 | return exception.name; 771 | } 772 | }()), 773 | 'InvalidCharacterError' 774 | ); 775 | assert.throws( 776 | function() { 777 | base64.decode('abcde===='); 778 | } 779 | ); 780 | assert.equal( 781 | (function() { 782 | try { 783 | base64.decode('abcde===='); 784 | } catch (exception) { 785 | return exception.name; 786 | } 787 | }()), 788 | 'InvalidCharacterError' 789 | ); 790 | assert.throws( 791 | function() { 792 | base64.decode('abcde====='); 793 | } 794 | ); 795 | assert.equal( 796 | (function() { 797 | try { 798 | base64.decode('abcde====='); 799 | } catch (exception) { 800 | return exception.name; 801 | } 802 | }()), 803 | 'InvalidCharacterError' 804 | ); 805 | assert.throws( 806 | function() { 807 | base64.decode('=a'); 808 | } 809 | ); 810 | assert.equal( 811 | (function() { 812 | try { 813 | base64.decode('=a'); 814 | } catch (exception) { 815 | return exception.name; 816 | } 817 | }()), 818 | 'InvalidCharacterError' 819 | ); 820 | assert.throws( 821 | function() { 822 | base64.decode('=a='); 823 | } 824 | ); 825 | assert.equal( 826 | (function() { 827 | try { 828 | base64.decode('=a='); 829 | } catch (exception) { 830 | return exception.name; 831 | } 832 | }()), 833 | 'InvalidCharacterError' 834 | ); 835 | assert.throws( 836 | function() { 837 | base64.decode('a=b'); 838 | } 839 | ); 840 | assert.equal( 841 | (function() { 842 | try { 843 | base64.decode('a=b'); 844 | } catch (exception) { 845 | return exception.name; 846 | } 847 | }()), 848 | 'InvalidCharacterError' 849 | ); 850 | assert.throws( 851 | function() { 852 | base64.decode('a=b='); 853 | } 854 | ); 855 | assert.equal( 856 | (function() { 857 | try { 858 | base64.decode('a=b='); 859 | } catch (exception) { 860 | return exception.name; 861 | } 862 | }()), 863 | 'InvalidCharacterError' 864 | ); 865 | assert.throws( 866 | function() { 867 | base64.decode('ab=c'); 868 | } 869 | ); 870 | assert.equal( 871 | (function() { 872 | try { 873 | base64.decode('ab=c'); 874 | } catch (exception) { 875 | return exception.name; 876 | } 877 | }()), 878 | 'InvalidCharacterError' 879 | ); 880 | assert.throws( 881 | function() { 882 | base64.decode('ab=c='); 883 | } 884 | ); 885 | assert.equal( 886 | (function() { 887 | try { 888 | base64.decode('ab=c='); 889 | } catch (exception) { 890 | return exception.name; 891 | } 892 | }()), 893 | 'InvalidCharacterError' 894 | ); 895 | assert.throws( 896 | function() { 897 | base64.decode('abc=d'); 898 | } 899 | ); 900 | assert.equal( 901 | (function() { 902 | try { 903 | base64.decode('abc=d'); 904 | } catch (exception) { 905 | return exception.name; 906 | } 907 | }()), 908 | 'InvalidCharacterError' 909 | ); 910 | assert.throws( 911 | function() { 912 | base64.decode('abc=d='); 913 | } 914 | ); 915 | assert.equal( 916 | (function() { 917 | try { 918 | base64.decode('abc=d='); 919 | } catch (exception) { 920 | return exception.name; 921 | } 922 | }()), 923 | 'InvalidCharacterError' 924 | ); 925 | assert.equal( 926 | base64.decode('ab\tcd'), 927 | 'i\xB7\x1D' 928 | ); 929 | assert.equal( 930 | base64.decode('ab\ncd'), 931 | 'i\xB7\x1D' 932 | ); 933 | assert.equal( 934 | base64.decode('ab\fcd'), 935 | 'i\xB7\x1D' 936 | ); 937 | assert.equal( 938 | base64.decode('ab\rcd'), 939 | 'i\xB7\x1D' 940 | ); 941 | assert.equal( 942 | base64.decode('ab cd'), 943 | 'i\xB7\x1D' 944 | ); 945 | assert.throws( 946 | function() { 947 | base64.decode('ab\xA0cd'); 948 | } 949 | ); 950 | assert.equal( 951 | (function() { 952 | try { 953 | base64.decode('ab\xA0cd'); 954 | } catch (exception) { 955 | return exception.name; 956 | } 957 | }()), 958 | 'InvalidCharacterError' 959 | ); 960 | assert.equal( 961 | base64.decode('ab\t\n\f\r cd'), 962 | 'i\xB7\x1D' 963 | ); 964 | assert.equal( 965 | base64.decode(' \t\n\f\r ab\t\n\f\r cd\t\n\f\r '), 966 | 'i\xB7\x1D' 967 | ); 968 | assert.equal( 969 | base64.decode('ab\t\n\f\r =\t\n\f\r =\t\n\f\r '), 970 | 'i' 971 | ); 972 | assert.throws( 973 | function() { 974 | base64.decode('A'); 975 | } 976 | ); 977 | assert.equal( 978 | (function() { 979 | try { 980 | base64.decode('A'); 981 | } catch (exception) { 982 | return exception.name; 983 | } 984 | }()), 985 | 'InvalidCharacterError' 986 | ); 987 | assert.equal( 988 | base64.decode('/A'), 989 | '\xFC' 990 | ); 991 | assert.equal( 992 | base64.decode('//A'), 993 | '\xFF\xF0' 994 | ); 995 | assert.equal( 996 | base64.decode('///A'), 997 | '\xFF\xFF\xC0' 998 | ); 999 | assert.throws( 1000 | function() { 1001 | base64.decode('////A'); 1002 | } 1003 | ); 1004 | assert.equal( 1005 | (function() { 1006 | try { 1007 | base64.decode('////A'); 1008 | } catch (exception) { 1009 | return exception.name; 1010 | } 1011 | }()), 1012 | 'InvalidCharacterError' 1013 | ); 1014 | assert.throws( 1015 | function() { 1016 | base64.decode('/'); 1017 | } 1018 | ); 1019 | assert.equal( 1020 | (function() { 1021 | try { 1022 | base64.decode('/'); 1023 | } catch (exception) { 1024 | return exception.name; 1025 | } 1026 | }()), 1027 | 'InvalidCharacterError' 1028 | ); 1029 | assert.equal( 1030 | base64.decode('A/'), 1031 | '\x03' 1032 | ); 1033 | assert.equal( 1034 | base64.decode('AA/'), 1035 | '\0\x0F' 1036 | ); 1037 | assert.throws( 1038 | function() { 1039 | base64.decode('AAAA/'); 1040 | } 1041 | ); 1042 | assert.equal( 1043 | (function() { 1044 | try { 1045 | base64.decode('AAAA/'); 1046 | } catch (exception) { 1047 | return exception.name; 1048 | } 1049 | }()), 1050 | 'InvalidCharacterError' 1051 | ); 1052 | assert.equal( 1053 | base64.decode('AAA/'), 1054 | '\0\0?' 1055 | ); 1056 | assert.throws( 1057 | function() { 1058 | base64.decode('\0'); 1059 | } 1060 | ); 1061 | assert.equal( 1062 | (function() { 1063 | try { 1064 | base64.decode('\0'); 1065 | } catch (exception) { 1066 | return exception.name; 1067 | } 1068 | }()), 1069 | 'InvalidCharacterError' 1070 | ); 1071 | assert.throws( 1072 | function() { 1073 | base64.decode('\0nonsense'); 1074 | } 1075 | ); 1076 | assert.equal( 1077 | (function() { 1078 | try { 1079 | base64.decode('\0nonsense'); 1080 | } catch (exception) { 1081 | return exception.name; 1082 | } 1083 | }()), 1084 | 'InvalidCharacterError' 1085 | ); 1086 | assert.throws( 1087 | function() { 1088 | base64.decode('abcd\0nonsense'); 1089 | } 1090 | ); 1091 | assert.equal( 1092 | (function() { 1093 | try { 1094 | base64.decode('abcd\0nonsense'); 1095 | } catch (exception) { 1096 | return exception.name; 1097 | } 1098 | }()), 1099 | 'InvalidCharacterError' 1100 | ); 1101 | assert.throws( 1102 | function() { 1103 | base64.decode(undefined); 1104 | } 1105 | ); 1106 | assert.equal( 1107 | (function() { 1108 | try { 1109 | base64.decode(undefined); 1110 | } catch (exception) { 1111 | return exception.name; 1112 | } 1113 | }()), 1114 | 'InvalidCharacterError' 1115 | ); 1116 | assert.equal( 1117 | base64.decode(null), 1118 | '\x9E\xE9e' 1119 | ); 1120 | assert.throws( 1121 | function() { 1122 | base64.decode(7); 1123 | } 1124 | ); 1125 | assert.equal( 1126 | (function() { 1127 | try { 1128 | base64.decode(7); 1129 | } catch (exception) { 1130 | return exception.name; 1131 | } 1132 | }()), 1133 | 'InvalidCharacterError' 1134 | ); 1135 | assert.equal( 1136 | base64.decode(12), 1137 | '\xD7' 1138 | ); 1139 | assert.throws( 1140 | function() { 1141 | base64.decode(1.5); 1142 | } 1143 | ); 1144 | assert.equal( 1145 | (function() { 1146 | try { 1147 | base64.decode(1.5); 1148 | } catch (exception) { 1149 | return exception.name; 1150 | } 1151 | }()), 1152 | 'InvalidCharacterError' 1153 | ); 1154 | assert.equal( 1155 | base64.decode(true), 1156 | '\xB6\xBB\x9E' 1157 | ); 1158 | assert.throws( 1159 | function() { 1160 | base64.decode(false); 1161 | } 1162 | ); 1163 | assert.equal( 1164 | (function() { 1165 | try { 1166 | base64.decode(false); 1167 | } catch (exception) { 1168 | return exception.name; 1169 | } 1170 | }()), 1171 | 'InvalidCharacterError' 1172 | ); 1173 | assert.equal( 1174 | base64.decode(NaN), 1175 | '5\xA3' 1176 | ); 1177 | assert.equal( 1178 | base64.decode(+Infinity), 1179 | '"w\xE2\x9E+r' 1180 | ); 1181 | assert.throws( 1182 | function() { 1183 | base64.decode(-Infinity); 1184 | } 1185 | ); 1186 | assert.equal( 1187 | (function() { 1188 | try { 1189 | base64.decode(-Infinity); 1190 | } catch (exception) { 1191 | return exception.name; 1192 | } 1193 | }()), 1194 | 'InvalidCharacterError' 1195 | ); 1196 | assert.throws( 1197 | function() { 1198 | base64.decode(+0); 1199 | } 1200 | ); 1201 | assert.equal( 1202 | (function() { 1203 | try { 1204 | base64.decode(+0); 1205 | } catch (exception) { 1206 | return exception.name; 1207 | } 1208 | }()), 1209 | 'InvalidCharacterError' 1210 | ); 1211 | assert.throws( 1212 | function() { 1213 | base64.decode(-0); 1214 | } 1215 | ); 1216 | assert.equal( 1217 | (function() { 1218 | try { 1219 | base64.decode(-0); 1220 | } catch (exception) { 1221 | return exception.name; 1222 | } 1223 | }()), 1224 | 'InvalidCharacterError' 1225 | ); 1226 | assert.equal( 1227 | base64.decode({ 'toString': function() { return 'foo'; }}), 1228 | '~\x8A' 1229 | ); 1230 | assert.equal( 1231 | base64.decode({ 'toString': function() { return 'abcd'; }}), 1232 | 'i\xB7\x1D' 1233 | ); 1234 | }); 1235 | }); 1236 | --------------------------------------------------------------------------------