diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 128adda..ed92c64 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -56,6 +56,11 @@ jobs: with: node-version: ${{ matrix.node }} + # Older versions of NPM do not correctly install the dependencies. + - name: Install newer NPM on Node.js 6 + if: matrix.node == 6 + run: npm install -g npm@^5 + - name: Install dependencies run: npm install diff --git a/base64js.min.js b/base64js.min.js index 908ac83..caf18f8 100644 --- a/base64js.min.js +++ b/base64js.min.js @@ -1 +1 @@ -(function(a){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=a();else if("function"==typeof define&&define.amd)define([],a);else{var b;b="undefined"==typeof window?"undefined"==typeof global?"undefined"==typeof self?this:self:global:window,b.base64js=a()}})(function(){return function(){function b(d,e,g){function a(j,i){if(!e[j]){if(!d[j]){var f="function"==typeof require&&require;if(!i&&f)return f(j,!0);if(h)return h(j,!0);var c=new Error("Cannot find module '"+j+"'");throw c.code="MODULE_NOT_FOUND",c}var k=e[j]={exports:{}};d[j][0].call(k.exports,function(b){var c=d[j][1][b];return a(c||b)},k,k.exports,b,d,e,g)}return e[j].exports}for(var h="function"==typeof require&&require,c=0;c>16,j[k++]=255&b>>8,j[k++]=255&b;return 2===h&&(b=l[a.charCodeAt(c)]<<2|l[a.charCodeAt(c+1)]>>4,j[k++]=255&b),1===h&&(b=l[a.charCodeAt(c)]<<10|l[a.charCodeAt(c+1)]<<4|l[a.charCodeAt(c+2)]>>2,j[k++]=255&b>>8,j[k++]=255&b),j}function g(a){return k[63&a>>18]+k[63&a>>12]+k[63&a>>6]+k[63&a]}function h(a,b,c){for(var d,e=[],f=b;fj?j:g+f));return 1===d?(b=a[c-1],e.push(k[b>>2]+k[63&b<<4]+"==")):2===d&&(b=(a[c-2]<<8)+a[c-1],e.push(k[b>>10]+k[63&b>>4]+k[63&b<<2]+"=")),e.join("")}c.byteLength=function(a){var b=d(a),c=b[0],e=b[1];return 3*(c+e)/4-e},c.toByteArray=f,c.fromByteArray=j;for(var k=[],l=[],m="undefined"==typeof Uint8Array?Array:Uint8Array,n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",o=0,p=n.length;o0)throw new Error("Invalid string. Length must be a multiple of 4");var e=r.indexOf("=");return-1===e&&(e=t),[e,e===t?0:4-e%4]}function f(t,e,n){for(var o,a,f=[],i=e;i>18&63]+r[a>>12&63]+r[a>>6&63]+r[63&a]);return f.join("")}t["-".charCodeAt(0)]=62,t["_".charCodeAt(0)]=63,exports.byteLength=function(r){var t=a(r),e=t[0],n=t[1];return 3*(e+n)/4-n},exports.fromByteArray=function(t){for(var e,n=t.length,o=n%3,a=[],i=16383,u=0,c=n-o;uc?c:u+i));return 1===o?(e=t[n-1],a.push(r[e>>2]+r[e<<4&63]+"==")):2===o&&(e=(t[n-2]<<8)+t[n-1],a.push(r[e>>10]+r[e>>4&63]+r[e<<2&63]+"=")),a.join("")},exports.toByteArray=function(r){var n,o,f=a(r),i=f[0],u=f[1],c=new e(function(r,t,e){return 3*(t+e)/4-e}(0,i,u)),h=0,d=u>0?i-4:i;for(o=0;o>16&255,c[h++]=n>>8&255,c[h++]=255&n;return 2===u&&(n=t[r.charCodeAt(o)]<<2|t[r.charCodeAt(o+1)]>>4,c[h++]=255&n),1===u&&(n=t[r.charCodeAt(o)]<<10|t[r.charCodeAt(o+1)]<<4|t[r.charCodeAt(o+2)]>>2,c[h++]=n>>8&255,c[h++]=255&n),c}})); diff --git a/index.d.mts b/index.d.mts new file mode 100644 index 0000000..7d9fa1d --- /dev/null +++ b/index.d.mts @@ -0,0 +1,3 @@ +export function byteLength(b64: string): number; +export function toByteArray(b64: string): Uint8Array; +export function fromByteArray(uint8: Uint8Array): string; diff --git a/index.js b/index.js index 0599f3e..3f629c5 100644 --- a/index.js +++ b/index.js @@ -1,26 +1,22 @@ -'use strict' +'use strict'; -exports.byteLength = byteLength -exports.toByteArray = toByteArray -exports.fromByteArray = fromByteArray +var lookup = []; +var revLookup = []; +var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array; -var lookup = [] -var revLookup = [] -var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array - -var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' +var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; for (var i = 0, len = code.length; i < len; ++i) { - lookup[i] = code[i] - revLookup[code.charCodeAt(i)] = i + lookup[i] = code[i]; + revLookup[code.charCodeAt(i)] = i; } // Support decoding URL-safe base64 strings, as Node.js does. // See: https://en.wikipedia.org/wiki/Base64#URL_applications -revLookup['-'.charCodeAt(0)] = 62 -revLookup['_'.charCodeAt(0)] = 63 +revLookup['-'.charCodeAt(0)] = 62; +revLookup['_'.charCodeAt(0)] = 63; function getLens (b64) { - var len = b64.length + var len = b64.length; if (len % 4 > 0) { throw new Error('Invalid string. Length must be a multiple of 4') @@ -28,21 +24,21 @@ function getLens (b64) { // Trim off extra bytes after placeholder bytes are found // See: https://github.com/beatgammit/base64-js/issues/42 - var validLen = b64.indexOf('=') - if (validLen === -1) validLen = len + var validLen = b64.indexOf('='); + if (validLen === -1) validLen = len; var placeHoldersLen = validLen === len ? 0 - : 4 - (validLen % 4) + : 4 - (validLen % 4); return [validLen, placeHoldersLen] } // base64 is 4/3 + up to two characters of the original data function byteLength (b64) { - var lens = getLens(b64) - var validLen = lens[0] - var placeHoldersLen = lens[1] + var lens = getLens(b64); + var validLen = lens[0]; + var placeHoldersLen = lens[1]; return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen } @@ -51,46 +47,46 @@ function _byteLength (b64, validLen, placeHoldersLen) { } function toByteArray (b64) { - var tmp - var lens = getLens(b64) - var validLen = lens[0] - var placeHoldersLen = lens[1] + var tmp; + var lens = getLens(b64); + var validLen = lens[0]; + var placeHoldersLen = lens[1]; - var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen)) + var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen)); - var curByte = 0 + var curByte = 0; // if there are placeholders, only get up to the last complete 4 chars var len = placeHoldersLen > 0 ? validLen - 4 - : validLen + : validLen; - var i + var i; for (i = 0; i < len; i += 4) { tmp = (revLookup[b64.charCodeAt(i)] << 18) | (revLookup[b64.charCodeAt(i + 1)] << 12) | (revLookup[b64.charCodeAt(i + 2)] << 6) | - revLookup[b64.charCodeAt(i + 3)] - arr[curByte++] = (tmp >> 16) & 0xFF - arr[curByte++] = (tmp >> 8) & 0xFF - arr[curByte++] = tmp & 0xFF + revLookup[b64.charCodeAt(i + 3)]; + arr[curByte++] = (tmp >> 16) & 0xFF; + arr[curByte++] = (tmp >> 8) & 0xFF; + arr[curByte++] = tmp & 0xFF; } if (placeHoldersLen === 2) { tmp = (revLookup[b64.charCodeAt(i)] << 2) | - (revLookup[b64.charCodeAt(i + 1)] >> 4) - arr[curByte++] = tmp & 0xFF + (revLookup[b64.charCodeAt(i + 1)] >> 4); + arr[curByte++] = tmp & 0xFF; } if (placeHoldersLen === 1) { tmp = (revLookup[b64.charCodeAt(i)] << 10) | (revLookup[b64.charCodeAt(i + 1)] << 4) | - (revLookup[b64.charCodeAt(i + 2)] >> 2) - arr[curByte++] = (tmp >> 8) & 0xFF - arr[curByte++] = tmp & 0xFF + (revLookup[b64.charCodeAt(i + 2)] >> 2); + arr[curByte++] = (tmp >> 8) & 0xFF; + arr[curByte++] = tmp & 0xFF; } return arr @@ -104,47 +100,51 @@ function tripletToBase64 (num) { } function encodeChunk (uint8, start, end) { - var tmp - var output = [] + var tmp; + var output = []; for (var i = start; i < end; i += 3) { tmp = ((uint8[i] << 16) & 0xFF0000) + ((uint8[i + 1] << 8) & 0xFF00) + - (uint8[i + 2] & 0xFF) - output.push(tripletToBase64(tmp)) + (uint8[i + 2] & 0xFF); + output.push(tripletToBase64(tmp)); } return output.join('') } function fromByteArray (uint8) { - var tmp - var len = uint8.length - var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes - var parts = [] - var maxChunkLength = 16383 // must be multiple of 3 + var tmp; + var len = uint8.length; + var extraBytes = len % 3; // if we have 1 byte left, pad 2 bytes + var parts = []; + var maxChunkLength = 16383; // must be multiple of 3 // go through the array every three bytes, we'll deal with trailing stuff later for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) { - parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength))) + parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength))); } // pad the end with zeros, but make sure to not forget the extra bytes if (extraBytes === 1) { - tmp = uint8[len - 1] + tmp = uint8[len - 1]; parts.push( lookup[tmp >> 2] + lookup[(tmp << 4) & 0x3F] + '==' - ) + ); } else if (extraBytes === 2) { - tmp = (uint8[len - 2] << 8) + uint8[len - 1] + tmp = (uint8[len - 2] << 8) + uint8[len - 1]; parts.push( lookup[tmp >> 10] + lookup[(tmp >> 4) & 0x3F] + lookup[(tmp << 2) & 0x3F] + '=' - ) + ); } return parts.join('') } + +exports.byteLength = byteLength; +exports.fromByteArray = fromByteArray; +exports.toByteArray = toByteArray; diff --git a/index.mjs b/index.mjs new file mode 100644 index 0000000..12b4736 --- /dev/null +++ b/index.mjs @@ -0,0 +1,144 @@ +var lookup = [] +var revLookup = [] +var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array + +var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' +for (var i = 0, len = code.length; i < len; ++i) { + lookup[i] = code[i] + revLookup[code.charCodeAt(i)] = i +} + +// Support decoding URL-safe base64 strings, as Node.js does. +// See: https://en.wikipedia.org/wiki/Base64#URL_applications +revLookup['-'.charCodeAt(0)] = 62 +revLookup['_'.charCodeAt(0)] = 63 + +function getLens (b64) { + var len = b64.length + + if (len % 4 > 0) { + throw new Error('Invalid string. Length must be a multiple of 4') + } + + // Trim off extra bytes after placeholder bytes are found + // See: https://github.com/beatgammit/base64-js/issues/42 + var validLen = b64.indexOf('=') + if (validLen === -1) validLen = len + + var placeHoldersLen = validLen === len + ? 0 + : 4 - (validLen % 4) + + return [validLen, placeHoldersLen] +} + +// base64 is 4/3 + up to two characters of the original data +export function byteLength (b64) { + var lens = getLens(b64) + var validLen = lens[0] + var placeHoldersLen = lens[1] + return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen +} + +function _byteLength (b64, validLen, placeHoldersLen) { + return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen +} + +export function toByteArray (b64) { + var tmp + var lens = getLens(b64) + var validLen = lens[0] + var placeHoldersLen = lens[1] + + var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen)) + + var curByte = 0 + + // if there are placeholders, only get up to the last complete 4 chars + var len = placeHoldersLen > 0 + ? validLen - 4 + : validLen + + var i + for (i = 0; i < len; i += 4) { + tmp = + (revLookup[b64.charCodeAt(i)] << 18) | + (revLookup[b64.charCodeAt(i + 1)] << 12) | + (revLookup[b64.charCodeAt(i + 2)] << 6) | + revLookup[b64.charCodeAt(i + 3)] + arr[curByte++] = (tmp >> 16) & 0xFF + arr[curByte++] = (tmp >> 8) & 0xFF + arr[curByte++] = tmp & 0xFF + } + + if (placeHoldersLen === 2) { + tmp = + (revLookup[b64.charCodeAt(i)] << 2) | + (revLookup[b64.charCodeAt(i + 1)] >> 4) + arr[curByte++] = tmp & 0xFF + } + + if (placeHoldersLen === 1) { + tmp = + (revLookup[b64.charCodeAt(i)] << 10) | + (revLookup[b64.charCodeAt(i + 1)] << 4) | + (revLookup[b64.charCodeAt(i + 2)] >> 2) + arr[curByte++] = (tmp >> 8) & 0xFF + arr[curByte++] = tmp & 0xFF + } + + return arr +} + +function tripletToBase64 (num) { + return lookup[num >> 18 & 0x3F] + + lookup[num >> 12 & 0x3F] + + lookup[num >> 6 & 0x3F] + + lookup[num & 0x3F] +} + +function encodeChunk (uint8, start, end) { + var tmp + var output = [] + for (var i = start; i < end; i += 3) { + tmp = + ((uint8[i] << 16) & 0xFF0000) + + ((uint8[i + 1] << 8) & 0xFF00) + + (uint8[i + 2] & 0xFF) + output.push(tripletToBase64(tmp)) + } + return output.join('') +} + +export function fromByteArray (uint8) { + var tmp + var len = uint8.length + var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes + var parts = [] + var maxChunkLength = 16383 // must be multiple of 3 + + // go through the array every three bytes, we'll deal with trailing stuff later + for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) { + parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength))) + } + + // pad the end with zeros, but make sure to not forget the extra bytes + if (extraBytes === 1) { + tmp = uint8[len - 1] + parts.push( + lookup[tmp >> 2] + + lookup[(tmp << 4) & 0x3F] + + '==' + ) + } else if (extraBytes === 2) { + tmp = (uint8[len - 2] << 8) + uint8[len - 1] + parts.push( + lookup[tmp >> 10] + + lookup[(tmp >> 4) & 0x3F] + + lookup[(tmp << 2) & 0x3F] + + '=' + ) + } + + return parts.join('') +} diff --git a/package.json b/package.json index 4e58d16..f3904ed 100644 --- a/package.json +++ b/package.json @@ -33,24 +33,38 @@ "files": [ "base64js.min.js", "index.d.ts", - "index.js" + "index.d.mts", + "index.js", + "index.mjs" ], "main": "index.js", "typings": "index.d.ts", + "exports": { + ".": { + "import": { + "types": "./index.d.mts", + "default": "./index.mjs" + }, + "require": { + "types": "./index.d.ts", + "default": "./index.js" + } + } + }, "repository": { "type": "git", "url": "git+https://github.com/feross/base64-js.git" }, "scripts": { - "build": "browserify -s base64js -r ./ | minify > base64js.min.js", - "lint": "standard", + "build": "rollup index.mjs --file index.js --format cjs && rollup index.js --file base64js.min.js --format umd --name base64js --plugin terser", + "lint": "standard --ignore index.js --ignore base64js.min.js", "test": "npm run lint && npm run unit", "unit": "tape test/*.js" }, "devDependencies": { - "babel-minify": "^0.5.1", + "@rollup/plugin-terser": "^0.4.4", "benchmark": "^2.1.4", - "browserify": "^17.0.0", + "rollup": "^4.19.0", "standard": "*", "tape": "^5.4.0" }