From ea4eb9692074b53b323cbfcc861ddf80c70d39f1 Mon Sep 17 00:00:00 2001 From: streamich Date: Tue, 9 Apr 2024 16:10:51 +0200 Subject: [PATCH 1/3] =?UTF-8?q?chore:=20=F0=9F=A4=96=20remove=20base64=20u?= =?UTF-8?q?tils?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/util/base64/README.md | 91 ----------------- src/util/base64/__bench__/decode.js | 77 --------------- src/util/base64/__bench__/encode.js | 98 ------------------- .../base64/__tests__/decode-base64url.spec.ts | 20 ---- src/util/base64/__tests__/decode-bin.spec.ts | 31 ------ src/util/base64/__tests__/decode.spec.ts | 33 ------- .../base64/__tests__/encode-base64url.spec.ts | 23 ----- src/util/base64/__tests__/encode-bin.spec.ts | 38 ------- src/util/base64/__tests__/encode.spec.ts | 24 ----- src/util/base64/constants.ts | 2 - src/util/base64/createFromBase64.ts | 66 ------------- src/util/base64/createFromBase64Bin.ts | 73 -------------- src/util/base64/createToBase64.ts | 45 --------- src/util/base64/createToBase64Bin.ts | 58 ----------- src/util/base64/createToBase64BinUint8.ts | 56 ----------- src/util/base64/fromBase64.ts | 10 -- src/util/base64/fromBase64Bin.ts | 3 - src/util/base64/fromBase64Url.ts | 3 - src/util/base64/index.ts | 7 -- src/util/base64/toBase64.ts | 12 --- src/util/base64/toBase64Bin.ts | 3 - src/util/base64/toBase64Url.ts | 3 - 22 files changed, 776 deletions(-) delete mode 100644 src/util/base64/README.md delete mode 100644 src/util/base64/__bench__/decode.js delete mode 100644 src/util/base64/__bench__/encode.js delete mode 100644 src/util/base64/__tests__/decode-base64url.spec.ts delete mode 100644 src/util/base64/__tests__/decode-bin.spec.ts delete mode 100644 src/util/base64/__tests__/decode.spec.ts delete mode 100644 src/util/base64/__tests__/encode-base64url.spec.ts delete mode 100644 src/util/base64/__tests__/encode-bin.spec.ts delete mode 100644 src/util/base64/__tests__/encode.spec.ts delete mode 100644 src/util/base64/constants.ts delete mode 100644 src/util/base64/createFromBase64.ts delete mode 100644 src/util/base64/createFromBase64Bin.ts delete mode 100644 src/util/base64/createToBase64.ts delete mode 100644 src/util/base64/createToBase64Bin.ts delete mode 100644 src/util/base64/createToBase64BinUint8.ts delete mode 100644 src/util/base64/fromBase64.ts delete mode 100644 src/util/base64/fromBase64Bin.ts delete mode 100644 src/util/base64/fromBase64Url.ts delete mode 100644 src/util/base64/index.ts delete mode 100644 src/util/base64/toBase64.ts delete mode 100644 src/util/base64/toBase64Bin.ts delete mode 100644 src/util/base64/toBase64Url.ts diff --git a/src/util/base64/README.md b/src/util/base64/README.md deleted file mode 100644 index fadf8a9..0000000 --- a/src/util/base64/README.md +++ /dev/null @@ -1,91 +0,0 @@ -# Base64 - - -## Encoder - -- Implements Base64 encoding algorithm compatible with Node's Buffer. -- Isomorphic—it can be used in, both, Node and the browser. -- Faster than the Node's implementation for short blobs, smaller than 40 bytes. -- Uses Node's implementation for long blobs, if available. Hence, it also works - in browser, but in Node environment will perform faster for short strings. - - -### Usage - -Use encoder compatible with Node's Buffer: - -```ts -import {toBase64} from 'json-pack/lib/util/base64'; - -toBase64(new Uint8Array([1, 2, 3])); -``` - -Create your custom encoder: - -```ts -import {createToBase64} from 'json-pack/lib/util/base64'; - -const encode = createToBase64('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_'); - -encode(new Uint8Array([1, 2, 3])); -``` - - -### Benchmark - -Below benchmark encodes random binary blobs of sizes 8, 16, 32, 64, 128, 256, 512, and 1024 byes. -`json-pack/util/base64` is faster, because for short strings (less than 40 chars) it uses a -native JavaScript implementation, which is faster and also works in browsers. For blobs larger -than 40 chars, it falls back to Node `Buffer` implementation, if available. - -Encoding: - -``` -node benchmarks/util/base64/encode.js -json-pack/util/base64 toBase64(uint8) x 1,257,419 ops/sec ±1.19% (93 runs sampled), 795 ns/op -json-pack/util/base64 createToBase64()(uint8) x 868,953 ops/sec ±0.96% (96 runs sampled), 1151 ns/op -js-base64 x 974,991 ops/sec ±0.73% (94 runs sampled), 1026 ns/op -fast-base64-encode x 428,545 ops/sec ±1.67% (96 runs sampled), 2333 ns/op -base64-js x 295,165 ops/sec ±1.59% (98 runs sampled), 3388 ns/op -Buffer.from(uint8).toString('base64'); x 973,173 ops/sec ±0.65% (95 runs sampled), 1028 ns/op -Fastest is json-pack/util/base64 toBase64(uint8) -``` - -Decoding: - -``` -node benchmarks/util/base64/decode.js -json-pack/util/base64 fromBase64(str) x 602,268 ops/sec ±1.09% (88 runs sampled), 1660 ns/op -json-pack/util/base64 createFromBase64()(str) x 392,345 ops/sec ±0.96% (91 runs sampled), 2549 ns/op -Buffer.from(str, 'base64') x 498,609 ops/sec ±1.66% (93 runs sampled), 2006 ns/op -base64-js x 439,246 ops/sec ±0.94% (89 runs sampled), 2277 ns/op -js-base64 x 151,694 ops/sec ±0.51% (99 runs sampled), 6592 ns/op -Fastest is json-pack/util/base64 fromBase64(str) -``` - - -## Decoder - -- Uses Node.js built-in `Buffer`, if available. -- When `Buffer` is not available, uses JavaScript implementation. - - -### Usage - -Use decoder compatible with Node's Buffer: - -```ts -import {toBase64, fromBase64} from 'json-pack/{lib,es2020}/util/base64'; - -fromBase64(toBase64(new Uint8Array([1, 2, 3]))); -``` - -Create your custom encoder: - -```ts -import {createFromBase64} from 'json-pack/{lib,es2020}/util/base64'; - -const decoder = createFromBase64('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_'); - -decoder(toBase64(new Uint8Array([1, 2, 3]))); -``` diff --git a/src/util/base64/__bench__/decode.js b/src/util/base64/__bench__/decode.js deleted file mode 100644 index 76ea7c2..0000000 --- a/src/util/base64/__bench__/decode.js +++ /dev/null @@ -1,77 +0,0 @@ -const Benchmark = require('benchmark'); -const toBase64 = require('../../../../es2020/util/base64').toBase64; -const {bufferToUint8Array} = require('../../../../es2020/util/buffers/bufferToUint8Array'); -const {fromBase64, createFromBase64} = require('../../../../es2020/util/base64'); -const {toByteArray} = require('base64-js'); -const {decode: decodeJsBase64} = require('js-base64'); - -const fromBase642 = createFromBase64(); - -const generateBlob = (length) => { - const uint8 = new Uint8Array(length); - for (let i = 0; i < length; i++) { - uint8[i] = Math.floor(Math.random() * 256); - } - return uint8; -}; - -const str4 = toBase64(generateBlob(4)); -const str8 = toBase64(generateBlob(8)); -const str16 = toBase64(generateBlob(16)); -const str24 = toBase64(generateBlob(24)); -const str32 = toBase64(generateBlob(32)); -const str64 = toBase64(generateBlob(64)); -const str128 = toBase64(generateBlob(128)); -const str256 = toBase64(generateBlob(256)); - -const suite = new Benchmark.Suite(); - -const encoders = [ - { - name: `util/base64 fromBase64(str)`, - decode: (str) => fromBase64(str), - }, - { - name: `util/base64 createFromBase64()(str)`, - decode: (str) => fromBase642(str), - }, - { - name: `Buffer.from(str, 'base64')`, - decode: (str) => bufferToUint8Array(Buffer.from(str, 'base64')), - }, - { - name: `base64-js`, - decode: (str) => toByteArray(str), - }, - { - name: `js-base64`, - decode: (str) => decodeJsBase64(str), - }, -]; - -for (const encoder of encoders) { - // Warm up - for (let i = 0; i < 100000; i++) { - encoder.decode(str8); - encoder.decode(str256); - } - suite.add(encoder.name, () => { - encoder.decode(str4); - encoder.decode(str8); - encoder.decode(str16); - encoder.decode(str24); - encoder.decode(str32); - encoder.decode(str64); - encoder.decode(str128); - encoder.decode(str256); - }); -} - -suite - .on('cycle', function (event) { - console.log(String(event.target) + `, ${Math.round(1000000000 / event.target.hz)} ns/op`); - }) - .on('complete', function () { - console.log('Fastest is ' + this.filter('fastest').map('name')); - }) - .run(); diff --git a/src/util/base64/__bench__/encode.js b/src/util/base64/__bench__/encode.js deleted file mode 100644 index 12e2fae..0000000 --- a/src/util/base64/__bench__/encode.js +++ /dev/null @@ -1,98 +0,0 @@ -const Benchmark = require('benchmark'); -const {toBase64, createToBase64} = require('../../../../es2020/util/base64'); -const {fromByteArray} = require('base64-js'); -const {encode: encodeJsBase64} = require('js-base64'); - -const toBase64Native = createToBase64(); - -const generateBlob = (length) => { - const uint8 = new Uint8Array(length); - for (let i = 0; i < length; i++) { - uint8[i] = Math.floor(Math.random() * 256); - } - return uint8; -}; - -const arr8 = generateBlob(9); -const arr16 = generateBlob(17); -const arr32 = generateBlob(33); -const arr64 = generateBlob(65); -const arr128 = generateBlob(127); -const arr256 = generateBlob(257); -const arr512 = generateBlob(513); -const arr1024 = generateBlob(1025); - -// fast-base64-encode -const table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split(''); -const fastBase64Encode = (source) => { - let out = ''; - let tmp; - const length = source.byteLength; - const extraLength = length % 3; - const baseLength = length - extraLength; - for (let i = 0; i < baseLength; i += 3) { - tmp = ((source[i] & 0xff) << 16) | ((source[i + 1] & 0xff) << 8) | (source[i + 2] & 0xff); - out += table[(tmp >> 18) & 0x3f] + table[(tmp >> 12) & 0x3f] + table[(tmp >> 6) & 0x3f] + table[tmp & 0x3f]; - } - if (extraLength) { - if (extraLength === 1) { - tmp = source[baseLength] & 0xff; - out += table[tmp >> 2] + table[(tmp << 4) & 0x3f] + '=='; - } else { - tmp = ((source[baseLength] & 0xff) << 8) | (source[baseLength + 1] & 0xff); - out += table[tmp >> 10] + table[(tmp >> 4) & 0x3f] + table[(tmp << 2) & 0x3f] + '='; - } - } - return out; -}; - -const suite = new Benchmark.Suite(); - -const encoders = [ - { - name: `util/base64 toBase64(uint8)`, - encode: (uint8) => toBase64(uint8), - }, - { - name: `util/base64 createToBase64()(uint8)`, - encode: (uint8) => toBase64Native(uint8, uint8.length), - }, - { - name: `js-base64`, - encode: (uint8) => encodeJsBase64(uint8), - }, - { - name: `fast-base64-encode`, - encode: (uint8) => fastBase64Encode(uint8), - }, - { - name: `base64-js`, - encode: (uint8) => fromByteArray(uint8), - }, - { - name: `Buffer.from(uint8).toString('base64');`, - encode: (uint8) => Buffer.from(uint8).toString('base64'), - }, -]; - -for (const encoder of encoders) { - suite.add(encoder.name, () => { - encoder.encode(arr8); - encoder.encode(arr16); - encoder.encode(arr32); - encoder.encode(arr64); - encoder.encode(arr128); - // encoder.encode(arr256); - // encoder.encode(arr512); - // encoder.encode(arr1024); - }); -} - -suite - .on('cycle', function (event) { - console.log(String(event.target) + `, ${Math.round(1000000000 / event.target.hz)} ns/op`); - }) - .on('complete', function () { - console.log('Fastest is ' + this.filter('fastest').map('name')); - }) - .run(); diff --git a/src/util/base64/__tests__/decode-base64url.spec.ts b/src/util/base64/__tests__/decode-base64url.spec.ts deleted file mode 100644 index 3344250..0000000 --- a/src/util/base64/__tests__/decode-base64url.spec.ts +++ /dev/null @@ -1,20 +0,0 @@ -import {toBase64} from '../toBase64'; -import {fromBase64Url} from '../fromBase64Url'; - -const generateBlob = (): Uint8Array => { - const length = Math.floor(Math.random() * 100); - const uint8 = new Uint8Array(length); - for (let i = 0; i < length; i++) { - uint8[i] = Math.floor(Math.random() * 256); - } - return uint8; -}; - -test('works', () => { - for (let i = 0; i < 100; i++) { - const blob = generateBlob(); - const encoded = toBase64(blob).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, ''); - const decoded2 = fromBase64Url(encoded); - expect(decoded2).toEqual(blob); - } -}); diff --git a/src/util/base64/__tests__/decode-bin.spec.ts b/src/util/base64/__tests__/decode-bin.spec.ts deleted file mode 100644 index ba0c5ff..0000000 --- a/src/util/base64/__tests__/decode-bin.spec.ts +++ /dev/null @@ -1,31 +0,0 @@ -import {toBase64Bin} from '../toBase64Bin'; -import {fromBase64Bin} from '../fromBase64Bin'; - -const generateBlob = (): Uint8Array => { - const length = Math.floor(Math.random() * 100); - const uint8 = new Uint8Array(length); - for (let i = 0; i < length; i++) { - uint8[i] = Math.floor(Math.random() * 256); - } - return uint8; -}; - -test('works', () => { - for (let i = 0; i < 100; i++) { - const blob = generateBlob(); - const dest = new Uint8Array(blob.length * 4); - const length = toBase64Bin(blob, 0, blob.length, new DataView(dest.buffer), 0); - const encoded = dest.subarray(0, length); - const view = new DataView(encoded.buffer); - const decoded = fromBase64Bin(view, 0, encoded.length); - let padding = 0; - if (encoded.length > 0 && view.getUint8(encoded.length - 1) === 0x3d) padding++; - if (encoded.length > 1 && view.getUint8(encoded.length - 2) === 0x3d) padding++; - const decoded2 = fromBase64Bin(view, 0, encoded.length - padding); - // console.log('blob', blob); - // console.log('encoded', encoded); - // console.log('decoded', decoded); - expect(decoded).toEqual(blob); - expect(decoded2).toEqual(blob); - } -}); diff --git a/src/util/base64/__tests__/decode.spec.ts b/src/util/base64/__tests__/decode.spec.ts deleted file mode 100644 index 273857a..0000000 --- a/src/util/base64/__tests__/decode.spec.ts +++ /dev/null @@ -1,33 +0,0 @@ -import {toBase64} from '../toBase64'; -import {fromBase64} from '../fromBase64'; -import {createFromBase64} from '../createFromBase64'; - -const fromBase64_2 = createFromBase64(); - -const generateBlob = (): Uint8Array => { - const length = Math.floor(Math.random() * 100); - const uint8 = new Uint8Array(length); - for (let i = 0; i < length; i++) { - uint8[i] = Math.floor(Math.random() * 256); - } - return uint8; -}; - -test('works', () => { - for (let i = 0; i < 100; i++) { - const blob = generateBlob(); - const encoded = toBase64(blob); - const decoded1 = fromBase64_2(encoded); - const decoded2 = fromBase64(encoded); - expect(decoded1).toEqual(blob); - expect(decoded2).toEqual(blob); - } -}); - -test('handles invalid values', () => { - for (let i = 0; i < 100; i++) { - const blob = generateBlob(); - const encoded = toBase64(blob); - expect(() => fromBase64_2(encoded + '!!!!')).toThrowError(new Error('INVALID_BASE64_STRING')); - } -}); diff --git a/src/util/base64/__tests__/encode-base64url.spec.ts b/src/util/base64/__tests__/encode-base64url.spec.ts deleted file mode 100644 index 1d2880f..0000000 --- a/src/util/base64/__tests__/encode-base64url.spec.ts +++ /dev/null @@ -1,23 +0,0 @@ -import {toBase64Url} from '../toBase64Url'; - -const generateBlob = (): Uint8Array => { - const length = Math.floor(Math.random() * 100) + 1; - const uint8 = new Uint8Array(length); - for (let i = 0; i < length; i++) { - uint8[i] = Math.floor(Math.random() * 256); - } - return uint8; -}; - -test('works', () => { - for (let i = 0; i < 100; i++) { - const blob = generateBlob(); - const expected = Buffer.from(blob).toString('base64'); - const base64url = toBase64Url(blob, blob.length); - let encoded = base64url.replace(/-/g, '+').replace(/_/g, '/'); - const mod = encoded.length % 4; - if (mod === 2) encoded += '=='; - else if (mod === 3) encoded += '='; - expect(encoded).toEqual(expected); - } -}); diff --git a/src/util/base64/__tests__/encode-bin.spec.ts b/src/util/base64/__tests__/encode-bin.spec.ts deleted file mode 100644 index 6ce22c6..0000000 --- a/src/util/base64/__tests__/encode-bin.spec.ts +++ /dev/null @@ -1,38 +0,0 @@ -import {toBase64} from '../toBase64'; -import {createToBase64Bin} from '../createToBase64Bin'; -import {createToBase64BinUint8} from '../createToBase64BinUint8'; -import {bufferToUint8Array} from '../../buffers/bufferToUint8Array'; -import {copy} from '../../buffers/copy'; - -const encode = createToBase64Bin('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/', '='); -const encodeUint8 = createToBase64BinUint8('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/', '='); -const encodeNoPadding = createToBase64Bin('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'); - -const generateBlob = (): Uint8Array => { - const length = Math.floor(Math.random() * 100) + 1; - const uint8 = new Uint8Array(length); - for (let i = 0; i < length; i++) { - uint8[i] = Math.floor(Math.random() * 256); - } - return uint8; -}; - -test('works', () => { - for (let i = 0; i < 100; i++) { - const blob = generateBlob(); - const result = bufferToUint8Array(Buffer.from(toBase64(blob))); - const binWithBuffer = new Uint8Array(result.length + 3); - encode(blob, 0, blob.length, new DataView(binWithBuffer.buffer), 3); - const dupe = copy(blob); - encodeNoPadding(blob, 0, blob.length, new DataView(binWithBuffer.buffer), 3); - expect(dupe).toEqual(blob); - const dupe2 = copy(blob); - encodeUint8(blob, 0, blob.length, binWithBuffer, 3); - expect(dupe2).toEqual(blob); - const encoded = binWithBuffer.subarray(3); - // console.log(result); - // console.log(binWithBuffer); - // console.log(encoded); - expect(result).toEqual(encoded); - } -}); diff --git a/src/util/base64/__tests__/encode.spec.ts b/src/util/base64/__tests__/encode.spec.ts deleted file mode 100644 index 74a4c62..0000000 --- a/src/util/base64/__tests__/encode.spec.ts +++ /dev/null @@ -1,24 +0,0 @@ -import {toBase64} from '../toBase64'; -import {createToBase64} from '../createToBase64'; - -const encode2 = createToBase64(); - -const generateBlob = (): Uint8Array => { - const length = Math.floor(Math.random() * 100) + 1; - const uint8 = new Uint8Array(length); - for (let i = 0; i < length; i++) { - uint8[i] = Math.floor(Math.random() * 256); - } - return uint8; -}; - -test('works', () => { - for (let i = 0; i < 100; i++) { - const blob = generateBlob(); - const result = toBase64(blob); - const result2 = encode2(blob, blob.byteLength); - const expected = Buffer.from(blob).toString('base64'); - expect(result).toBe(expected); - expect(result2).toBe(expected); - } -}); diff --git a/src/util/base64/constants.ts b/src/util/base64/constants.ts deleted file mode 100644 index 46b1926..0000000 --- a/src/util/base64/constants.ts +++ /dev/null @@ -1,2 +0,0 @@ -export const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; -export const hasBuffer = typeof Buffer === 'function' && typeof Buffer.from === 'function'; diff --git a/src/util/base64/createFromBase64.ts b/src/util/base64/createFromBase64.ts deleted file mode 100644 index 5f4922f..0000000 --- a/src/util/base64/createFromBase64.ts +++ /dev/null @@ -1,66 +0,0 @@ -import {alphabet} from './constants'; - -const E = '='; - -export const createFromBase64 = (chars: string = alphabet, noPadding: boolean = false) => { - if (chars.length !== 64) throw new Error('chars must be 64 characters long'); - let max = 0; - for (let i = 0; i < chars.length; i++) max = Math.max(max, chars.charCodeAt(i)); - const table: number[] = []; - for (let i = 0; i <= max; i += 1) table[i] = -1; - for (let i = 0; i < chars.length; i++) table[chars.charCodeAt(i)] = i; - - return (encoded: string): Uint8Array => { - if (!encoded) return new Uint8Array(0); - let length = encoded.length; - if (noPadding) { - const mod = length % 4; - if (mod === 2) { - encoded += '=='; - length += 2; - } else if (mod === 3) { - encoded += '='; - length += 1; - } - } - if (length % 4 !== 0) throw new Error('Base64 string length must be a multiple of 4'); - const mainLength = encoded[length - 1] !== E ? length : length - 4; - let bufferLength = (length >> 2) * 3; - let padding = 0; - if (encoded[length - 2] === E) { - padding = 2; - bufferLength -= 2; - } else if (encoded[length - 1] === E) { - padding = 1; - bufferLength -= 1; - } - const buf = new Uint8Array(bufferLength); - let j = 0; - let i = 0; - for (; i < mainLength; i += 4) { - const sextet0 = table[encoded.charCodeAt(i)]; - const sextet1 = table[encoded.charCodeAt(i + 1)]; - const sextet2 = table[encoded.charCodeAt(i + 2)]; - const sextet3 = table[encoded.charCodeAt(i + 3)]; - if (sextet0 < 0 || sextet1 < 0 || sextet2 < 0 || sextet3 < 0) throw new Error('INVALID_BASE64_STRING'); - buf[j] = (sextet0 << 2) | (sextet1 >> 4); - buf[j + 1] = (sextet1 << 4) | (sextet2 >> 2); - buf[j + 2] = (sextet2 << 6) | sextet3; - j += 3; - } - if (padding === 2) { - const sextet0 = table[encoded.charCodeAt(mainLength)]; - const sextet1 = table[encoded.charCodeAt(mainLength + 1)]; - if (sextet0 < 0 || sextet1 < 0) throw new Error('INVALID_BASE64_STRING'); - buf[j] = (sextet0 << 2) | (sextet1 >> 4); - } else if (padding === 1) { - const sextet0 = table[encoded.charCodeAt(mainLength)]; - const sextet1 = table[encoded.charCodeAt(mainLength + 1)]; - const sextet2 = table[encoded.charCodeAt(mainLength + 2)]; - if (sextet0 < 0 || sextet1 < 0 || sextet2 < 0) throw new Error('INVALID_BASE64_STRING'); - buf[j] = (sextet0 << 2) | (sextet1 >> 4); - buf[j + 1] = (sextet1 << 4) | (sextet2 >> 2); - } - return buf; - }; -}; diff --git a/src/util/base64/createFromBase64Bin.ts b/src/util/base64/createFromBase64Bin.ts deleted file mode 100644 index ed9b018..0000000 --- a/src/util/base64/createFromBase64Bin.ts +++ /dev/null @@ -1,73 +0,0 @@ -import {alphabet} from './constants'; - -export const createFromBase64Bin = (chars: string = alphabet, pad: string = '=') => { - if (chars.length !== 64) throw new Error('chars must be 64 characters long'); - let max = 0; - for (let i = 0; i < chars.length; i++) max = Math.max(max, chars.charCodeAt(i)); - const table: number[] = []; - for (let i = 0; i <= max; i += 1) table[i] = -1; - for (let i = 0; i < chars.length; i++) table[chars.charCodeAt(i)] = i; - - const doExpectPadding = pad.length === 1; - const PAD = doExpectPadding ? pad.charCodeAt(0) : 0; - - return (view: DataView, offset: number, length: number): Uint8Array => { - if (!length) return new Uint8Array(0); - let padding = 0; - if (length % 4 !== 0) { - padding = 4 - (length % 4); - length += padding; - } else { - const end = offset + length; - const last = end - 1; - if (view.getUint8(last) === PAD) { - padding = 1; - if (length > 1 && view.getUint8(last - 1) === PAD) padding = 2; - } - } - if (length % 4 !== 0) throw new Error('Base64 string length must be a multiple of 4'); - const mainEnd = offset + length - (padding ? 4 : 0); - const bufferLength = (length >> 2) * 3 - padding; - const buf = new Uint8Array(bufferLength); - let j = 0; - let i = offset; - for (; i < mainEnd; i += 4) { - const word = view.getUint32(i); - const octet0 = word >>> 24; - const octet1 = (word >>> 16) & 0xff; - const octet2 = (word >>> 8) & 0xff; - const octet3 = word & 0xff; - const sextet0 = table[octet0]; - const sextet1 = table[octet1]; - const sextet2 = table[octet2]; - const sextet3 = table[octet3]; - if (sextet0 < 0 || sextet1 < 0 || sextet2 < 0 || sextet3 < 0) throw new Error('INVALID_BASE64_SEQ'); - buf[j] = (sextet0 << 2) | (sextet1 >> 4); - buf[j + 1] = (sextet1 << 4) | (sextet2 >> 2); - buf[j + 2] = (sextet2 << 6) | sextet3; - j += 3; - } - if (!padding) return buf; - if (padding === 1) { - const word = view.getUint16(mainEnd); - const octet0 = word >> 8; - const octet1 = word & 0xff; - const octet2 = view.getUint8(mainEnd + 2); - const sextet0 = table[octet0]; - const sextet1 = table[octet1]; - const sextet2 = table[octet2]; - if (sextet0 < 0 || sextet1 < 0 || sextet2 < 0) throw new Error('INVALID_BASE64_SEQ'); - buf[j] = (sextet0 << 2) | (sextet1 >> 4); - buf[j + 1] = (sextet1 << 4) | (sextet2 >> 2); - return buf; - } - const word = view.getUint16(mainEnd); - const octet0 = word >> 8; - const octet1 = word & 0xff; - const sextet0 = table[octet0]; - const sextet1 = table[octet1]; - if (sextet0 < 0 || sextet1 < 0) throw new Error('INVALID_BASE64_SEQ'); - buf[j] = (sextet0 << 2) | (sextet1 >> 4); - return buf; - }; -}; diff --git a/src/util/base64/createToBase64.ts b/src/util/base64/createToBase64.ts deleted file mode 100644 index 8368152..0000000 --- a/src/util/base64/createToBase64.ts +++ /dev/null @@ -1,45 +0,0 @@ -import {flatstr} from '../strings/flatstr'; -import {alphabet} from './constants'; - -export const createToBase64 = (chars: string = alphabet, pad: string = '=') => { - if (chars.length !== 64) throw new Error('chars must be 64 characters long'); - - const table = chars.split(''); - const table2: string[] = []; - - for (const c1 of table) { - for (const c2 of table) { - const two = flatstr(c1 + c2); - table2.push(two); - } - } - - const E: string = pad; - const EE: string = flatstr(pad + pad); - - return (uint8: Uint8Array, length: number): string => { - let out = ''; - const extraLength = length % 3; - const baseLength = length - extraLength; - for (let i = 0; i < baseLength; i += 3) { - const o1 = uint8[i]; - const o2 = uint8[i + 1]; - const o3 = uint8[i + 2]; - const v1 = (o1 << 4) | (o2 >> 4); - const v2 = ((o2 & 0b1111) << 8) | o3; - out += table2[v1] + table2[v2]; - } - if (!extraLength) return out; - if (extraLength === 1) { - const o1 = uint8[baseLength]; - out += table2[o1 << 4] + EE; - } else { - const o1 = uint8[baseLength]; - const o2 = uint8[baseLength + 1]; - const v1 = (o1 << 4) | (o2 >> 4); - const v2 = (o2 & 0b1111) << 2; - out += table2[v1] + table[v2] + E; - } - return out; - }; -}; diff --git a/src/util/base64/createToBase64Bin.ts b/src/util/base64/createToBase64Bin.ts deleted file mode 100644 index 95e3a92..0000000 --- a/src/util/base64/createToBase64Bin.ts +++ /dev/null @@ -1,58 +0,0 @@ -import {alphabet} from './constants'; - -export const createToBase64Bin = (chars: string = alphabet, pad: string = '=') => { - if (chars.length !== 64) throw new Error('chars must be 64 characters long'); - - const table = chars.split('').map((c) => c.charCodeAt(0)); - const table2: number[] = []; - - for (const c1 of table) { - for (const c2 of table) { - const two = (c1 << 8) + c2; - table2.push(two); - } - } - - const doAddPadding = pad.length === 1; - const E: number = doAddPadding ? pad.charCodeAt(0) : 0; - const EE: number = doAddPadding ? (E << 8) | E : 0; - - return (uint8: Uint8Array, start: number, length: number, dest: DataView, offset: number): number => { - const extraLength = length % 3; - const baseLength = length - extraLength; - for (; start < baseLength; start += 3) { - const o1 = uint8[start]; - const o2 = uint8[start + 1]; - const o3 = uint8[start + 2]; - const v1 = (o1 << 4) | (o2 >> 4); - const v2 = ((o2 & 0b1111) << 8) | o3; - dest.setInt32(offset, (table2[v1] << 16) + table2[v2]); - offset += 4; - } - if (extraLength === 1) { - const o1 = uint8[baseLength]; - if (doAddPadding) { - dest.setInt32(offset, (table2[o1 << 4] << 16) + EE); - offset += 4; - } else { - dest.setInt16(offset, table2[o1 << 4]); - offset += 2; - } - } else if (extraLength) { - const o1 = uint8[baseLength]; - const o2 = uint8[baseLength + 1]; - const v1 = (o1 << 4) | (o2 >> 4); - const v2 = (o2 & 0b1111) << 2; - if (doAddPadding) { - dest.setInt32(offset, (table2[v1] << 16) + (table[v2] << 8) + E); - offset += 4; - } else { - dest.setInt16(offset, table2[v1]); - offset += 2; - dest.setInt8(offset, table[v2]); - offset += 1; - } - } - return offset; - }; -}; diff --git a/src/util/base64/createToBase64BinUint8.ts b/src/util/base64/createToBase64BinUint8.ts deleted file mode 100644 index efa7761..0000000 --- a/src/util/base64/createToBase64BinUint8.ts +++ /dev/null @@ -1,56 +0,0 @@ -import {alphabet} from './constants'; - -export const createToBase64BinUint8 = (chars: string = alphabet, pad: string = '=') => { - if (chars.length !== 64) throw new Error('chars must be 64 characters long'); - - const table = chars.split('').map((c) => c.charCodeAt(0)); - const table2: number[] = []; - - for (const c1 of table) { - for (const c2 of table) { - const two = (c1 << 8) + c2; - table2.push(two); - } - } - - const PAD: number = pad.length === 1 ? pad.charCodeAt(0) : 0; - - return (uint8: Uint8Array, start: number, length: number, dest: Uint8Array, offset: number): number => { - const extraLength = length % 3; - const baseLength = length - extraLength; - for (; start < baseLength; start += 3) { - const o1 = uint8[start]; - const o2 = uint8[start + 1]; - const o3 = uint8[start + 2]; - const v1 = (o1 << 4) | (o2 >> 4); - const v2 = ((o2 & 0b1111) << 8) | o3; - let u16 = table2[v1]; - dest[offset++] = u16 >> 8; - dest[offset++] = u16; - u16 = table2[v2]; - dest[offset++] = u16 >> 8; - dest[offset++] = u16; - } - if (extraLength === 1) { - const o1 = uint8[baseLength]; - const u16 = table2[o1 << 4]; - dest[offset++] = u16 >> 8; - dest[offset++] = u16; - if (PAD) { - dest[offset++] = PAD; - dest[offset++] = PAD; - } - } else if (extraLength) { - const o1 = uint8[baseLength]; - const o2 = uint8[baseLength + 1]; - const v1 = (o1 << 4) | (o2 >> 4); - const v2 = (o2 & 0b1111) << 2; - const u16 = table2[v1]; - dest[offset++] = u16 >> 8; - dest[offset++] = u16; - dest[offset++] = table[v2]; - if (PAD) dest[offset++] = PAD; - } - return offset; - }; -}; diff --git a/src/util/base64/fromBase64.ts b/src/util/base64/fromBase64.ts deleted file mode 100644 index f9a6bb8..0000000 --- a/src/util/base64/fromBase64.ts +++ /dev/null @@ -1,10 +0,0 @@ -import {bufferToUint8Array} from '../buffers/bufferToUint8Array'; -import {hasBuffer} from './constants'; -import {createFromBase64} from './createFromBase64'; - -const fromBase64Cpp = hasBuffer ? (encoded: string) => bufferToUint8Array(Buffer.from(encoded, 'base64')) : null; -const fromBase64Native = createFromBase64(); - -export const fromBase64 = !fromBase64Cpp - ? fromBase64Native - : (encoded: string): Uint8Array => (encoded.length > 48 ? fromBase64Cpp(encoded) : fromBase64Native(encoded)); diff --git a/src/util/base64/fromBase64Bin.ts b/src/util/base64/fromBase64Bin.ts deleted file mode 100644 index 678898d..0000000 --- a/src/util/base64/fromBase64Bin.ts +++ /dev/null @@ -1,3 +0,0 @@ -import {createFromBase64Bin} from './createFromBase64Bin'; - -export const fromBase64Bin = createFromBase64Bin(); diff --git a/src/util/base64/fromBase64Url.ts b/src/util/base64/fromBase64Url.ts deleted file mode 100644 index 12be59f..0000000 --- a/src/util/base64/fromBase64Url.ts +++ /dev/null @@ -1,3 +0,0 @@ -import {createFromBase64} from './createFromBase64'; - -export const fromBase64Url = createFromBase64('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_', true); diff --git a/src/util/base64/index.ts b/src/util/base64/index.ts deleted file mode 100644 index 0c865ce..0000000 --- a/src/util/base64/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -export * from './createToBase64'; -export * from './createToBase64Bin'; -export * from './createFromBase64'; -export * from './toBase64'; -export * from './toBase64Bin'; -export * from './fromBase64'; -export * from './fromBase64Bin'; diff --git a/src/util/base64/toBase64.ts b/src/util/base64/toBase64.ts deleted file mode 100644 index be2688b..0000000 --- a/src/util/base64/toBase64.ts +++ /dev/null @@ -1,12 +0,0 @@ -import {hasBuffer} from './constants'; -import {createToBase64} from './createToBase64'; - -const encodeSmall = createToBase64(); - -export const toBase64 = !hasBuffer - ? (uint8: Uint8Array) => encodeSmall(uint8, uint8.length) - : (uint8: Uint8Array): string => { - const length = uint8.length; - if (length <= 48) return encodeSmall(uint8, length); - return Buffer.from(uint8).toString('base64'); - }; diff --git a/src/util/base64/toBase64Bin.ts b/src/util/base64/toBase64Bin.ts deleted file mode 100644 index 012f2c2..0000000 --- a/src/util/base64/toBase64Bin.ts +++ /dev/null @@ -1,3 +0,0 @@ -import {createToBase64Bin} from './createToBase64Bin'; - -export const toBase64Bin = createToBase64Bin(); diff --git a/src/util/base64/toBase64Url.ts b/src/util/base64/toBase64Url.ts deleted file mode 100644 index 4188ca4..0000000 --- a/src/util/base64/toBase64Url.ts +++ /dev/null @@ -1,3 +0,0 @@ -import {createToBase64} from './createToBase64'; - -export const toBase64Url = createToBase64('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_', ''); From b345e600dd80e7b8733cf7bb9f09215530c96abe Mon Sep 17 00:00:00 2001 From: streamich Date: Tue, 9 Apr 2024 16:11:09 +0200 Subject: [PATCH 2/3] =?UTF-8?q?chore:=20=F0=9F=A4=96=20install=20jsonjoy.c?= =?UTF-8?q?om/base64=20package?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + yarn.lock | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/package.json b/package.json index f2a32bb..9e2a9b1 100644 --- a/package.json +++ b/package.json @@ -62,6 +62,7 @@ "tslib": "2" }, "dependencies": { + "@jsonjoy.com/base64": "^1.1.1", "hyperdyperid": "^1.2.0", "thingies": "^1.20.0" }, diff --git a/yarn.lock b/yarn.lock index f0c8671..9d38adb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -595,6 +595,11 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" +"@jsonjoy.com/base64@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@jsonjoy.com/base64/-/base64-1.1.1.tgz#a717fd8840f7bad49c7fe66cc65db8bcfc4c4dc5" + integrity sha512-LnFjVChaGY8cZVMwAIMjvA1XwQjZ/zIXHyh28IyJkyNkzof4Dkm1+KN9UIm3lHhREH4vs7XwZ0NpkZKnwOtEfg== + "@msgpack/msgpack@^3.0.0-beta2": version "3.0.0-beta2" resolved "https://registry.yarnpkg.com/@msgpack/msgpack/-/msgpack-3.0.0-beta2.tgz#5bccee30f84df220b33905e3d8249ba96deca0b7" From 078580f28039cec8f660a4affd2d87d04a22a83a Mon Sep 17 00:00:00 2001 From: streamich Date: Tue, 9 Apr 2024 16:11:23 +0200 Subject: [PATCH 3/3] =?UTF-8?q?refactor:=20=F0=9F=92=A1=20start=20using=20?= =?UTF-8?q?jsonjoy.com/base64=20package?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/json-binary/codec.ts | 3 ++- src/json/JsonDecoder.ts | 2 +- src/json/JsonDecoderDag.ts | 2 +- src/json/JsonEncoder.ts | 2 +- src/json/JsonEncoderDag.ts | 2 +- src/util/buffers/toDataUri.ts | 2 +- 6 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/json-binary/codec.ts b/src/json-binary/codec.ts index ac6779f..d766ad5 100644 --- a/src/json-binary/codec.ts +++ b/src/json-binary/codec.ts @@ -1,5 +1,6 @@ import {JsonPackExtension, JsonPackValue} from '../msgpack'; -import {fromBase64, toBase64} from '../util/base64'; +import {fromBase64} from '@jsonjoy.com/base64/lib/fromBase64'; +import {toBase64} from '@jsonjoy.com/base64/lib/toBase64'; import {isUint8Array} from '../util/buffers/isUint8Array'; import {binUriStart, msgPackExtStart, msgPackUriStart} from './constants'; import {binary_string} from './types'; diff --git a/src/json/JsonDecoder.ts b/src/json/JsonDecoder.ts index 380806a..8f9805e 100644 --- a/src/json/JsonDecoder.ts +++ b/src/json/JsonDecoder.ts @@ -1,6 +1,6 @@ import {decodeUtf8} from '../util/buffers/utf8/decodeUtf8'; import {Reader} from '../util/buffers/Reader'; -import {fromBase64Bin} from '../util/base64/fromBase64Bin'; +import {fromBase64Bin} from '@jsonjoy.com/base64/lib/fromBase64Bin'; import {findEndingQuote} from './util'; import type {BinaryJsonDecoder, PackValue} from '../types'; diff --git a/src/json/JsonDecoderDag.ts b/src/json/JsonDecoderDag.ts index ac3883b..e3f5747 100644 --- a/src/json/JsonDecoderDag.ts +++ b/src/json/JsonDecoderDag.ts @@ -1,7 +1,7 @@ import {JsonDecoder} from './JsonDecoder'; import {findEndingQuote} from './util'; import type {PackValue} from '../types'; -import {createFromBase64Bin} from '../util/base64/createFromBase64Bin'; +import {createFromBase64Bin} from '@jsonjoy.com/base64/lib/createFromBase64Bin'; export const fromBase64Bin = createFromBase64Bin(undefined, ''); diff --git a/src/json/JsonEncoder.ts b/src/json/JsonEncoder.ts index f2db12b..a360c6d 100644 --- a/src/json/JsonEncoder.ts +++ b/src/json/JsonEncoder.ts @@ -1,4 +1,4 @@ -import {toBase64Bin} from '../util/base64/toBase64Bin'; +import {toBase64Bin} from '@jsonjoy.com/base64/lib/toBase64Bin'; import type {IWriter, IWriterGrowable} from '../util/buffers'; import type {BinaryJsonEncoder, StreamingBinaryJsonEncoder} from '../types'; diff --git a/src/json/JsonEncoderDag.ts b/src/json/JsonEncoderDag.ts index 0e05f6f..bd0a043 100644 --- a/src/json/JsonEncoderDag.ts +++ b/src/json/JsonEncoderDag.ts @@ -1,5 +1,5 @@ import {JsonEncoderStable} from './JsonEncoderStable'; -import {createToBase64Bin} from '../util/base64/createToBase64Bin'; +import {createToBase64Bin} from '@jsonjoy.com/base64/lib/createToBase64Bin'; const objBaseLength = '{"/":{"bytes":""}}'.length; const cidBaseLength = '{"/":""}'.length; diff --git a/src/util/buffers/toDataUri.ts b/src/util/buffers/toDataUri.ts index b5f26da..42a9178 100644 --- a/src/util/buffers/toDataUri.ts +++ b/src/util/buffers/toDataUri.ts @@ -1,4 +1,4 @@ -import {toBase64} from '../base64'; +import {toBase64} from '@jsonjoy.com/base64/lib/toBase64'; export const toDataUri = (buf: Uint8Array, params?: Record): string => { let uri = 'data:application/octet-stream;base64';