+++ /dev/null
-// ♓🌟 Piscēs ∷ base64.js
-// ====================================================================
-//
-// Copyright © 2020–2022 Lady [@ Lady’s Computer].
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
-
-import { fill, map, reduce } from "./collection.js";
-import { bind, call } from "./function.js";
-import { ceil, floor } from "./numeric.js";
-import { hasOwnProperty, objectCreate } from "./object.js";
-import {
- getCodeUnit,
- rawString,
- stringFromCodeUnits,
- stringReplace,
-} from "./string.js";
-
-const Buffer = ArrayBuffer;
-const View = DataView;
-const TypedArray = Object.getPrototypeOf(Uint8Array);
-const { prototype: arrayPrototype } = Array;
-const { prototype: bufferPrototype } = Buffer;
-const { iterator: iteratorSymbol } = Symbol;
-const { prototype: rePrototype } = RegExp;
-const { prototype: typedArrayPrototype } = TypedArray;
-const { prototype: viewPrototype } = View;
-
-const { [iteratorSymbol]: arrayIterator } = arrayPrototype;
-const {
- next: arrayIteratorNext,
-} = Object.getPrototypeOf([][iteratorSymbol]());
-const getBufferByteLength =
- Object.getOwnPropertyDescriptor(bufferPrototype, "byteLength").get;
-const getTypedArrayBuffer =
- Object.getOwnPropertyDescriptor(typedArrayPrototype, "buffer").get;
-const getViewBuffer =
- Object.getOwnPropertyDescriptor(viewPrototype, "buffer").get;
-const { exec: reExec } = rePrototype;
-const {
- getUint8: viewGetUint8,
- setUint8: viewSetUint8,
- setUint16: viewSetUint16,
-} = viewPrototype;
-
-const base64CodeUnitIterablePrototype = {
- [iteratorSymbol]() {
- return {
- next: bind(
- arrayIteratorNext,
- call(arrayIterator, this, []),
- [],
- ),
- };
- },
-};
-
-/**
- * Returns an ArrayBuffer generated from the provided Base64.
- *
- * This function can also be used as a tag for a template literal. The
- * literal will be interpreted akin to `String.raw`.
- */
-export const a2b = ($, ...$s) => {
- const source = stringReplace(
- typeof $ == "string"
- ? $
- : hasOwnProperty($, "raw")
- ? rawString($, ...$s)
- : `${$}`,
- /[\t\n\f\r ]+/gu,
- "",
- );
- const u6s = map(
- source.length % 4 == 0
- ? stringReplace(source, /={1,2}$/u, "")
- : source,
- (ucsCharacter) => {
- const code = getCodeUnit(ucsCharacter, 0);
- const result = code >= 0x41 && code <= 0x5A
- ? code - 65
- : code >= 0x61 && code <= 0x7A
- ? code - 71
- : code >= 0x30 && code <= 0x39
- ? code + 4
- : code == 0x2B
- ? 62
- : code == 0x2F
- ? 63
- : -1;
- if (result < 0) {
- throw new RangeError(
- `Piscēs: Invalid character in Base64: ${character}.`,
- );
- } else {
- return result;
- }
- },
- );
- const { length } = u6s;
- const dataView = new View(new Buffer(floor(length * 3 / 4)));
- for (let index = 0; index < length - 1;) {
- const dataIndex = ceil(index * 3 / 4);
- const remainder = index % 3;
- if (remainder == 0) {
- call(viewSetUint8, dataView, [
- dataIndex,
- (u6s[index] << 2) + (u6s[++index] >> 4),
- ]);
- } else if (remainder == 1) {
- call(viewSetUint8, dataView, [
- dataIndex,
- ((u6s[index] & 0xF) << 4) + (u6s[++index] >> 2),
- ]);
- } else {
- call(viewSetUint8, dataView, [
- dataIndex,
- ((u6s[index] & 0x3) << 6) + u6s[++index],
- ]);
- }
- }
- return call(getViewBuffer, dataView, []);
-};
-
-/**
- * Returns a (big‐endian) base64 string created from a typed array,
- * buffer, or string.
- *
- * This function can also be used as a tag for a template literal. The
- * literal will be interpreted akin to `String.raw`.
- */
-export const b2a = ($, ...$s) => {
- const buffer = $ instanceof Buffer
- ? $
- : $ instanceof View
- ? call(getViewBuffer, $, [])
- : $ instanceof TypedArray
- ? call(getTypedArrayBuffer, $, [])
- : ((string) =>
- call(
- getViewBuffer,
- reduce(
- string,
- (result, ucsCharacter, index) => (
- call(viewSetUint16, result, [
- index * 2,
- getCodeUnit(ucsCharacter, 0),
- ]), result
- ),
- new View(new Buffer(string.length * 2)),
- ),
- [],
- ))(
- typeof $ == "string"
- ? $
- : hasOwnProperty($, "raw")
- ? rawString($, ...$s)
- : `${$}`,
- );
- const dataView = new View(buffer);
- const byteLength = call(getBufferByteLength, buffer, []);
- const minimumLengthOfResults = ceil(byteLength * 4 / 3);
- const resultingCodeUnits = fill(
- objectCreate(
- base64CodeUnitIterablePrototype,
- {
- length: {
- value: minimumLengthOfResults +
- (4 - (minimumLengthOfResults % 4)) % 4,
- },
- },
- ),
- 0x3D,
- );
- for (let index = 0; index < byteLength;) {
- const codeUnitIndex = ceil(index * 4 / 3);
- const currentIndex = codeUnitIndex + +(
- index % 3 == 0 && resultingCodeUnits[codeUnitIndex] != 0x3D
- );
- const remainder = currentIndex % 4;
- const u6 = remainder == 0
- ? call(viewGetUint8, dataView, [index]) >> 2
- : remainder == 1
- ? ((call(viewGetUint8, dataView, [index++]) & 0x3) << 4) +
- (index < byteLength
- ? call(viewGetUint8, dataView, [index]) >> 4
- : 0)
- : remainder == 2
- ? ((call(viewGetUint8, dataView, [index++]) & 0xF) << 2) +
- (index < byteLength
- ? call(viewGetUint8, dataView, [index]) >> 6
- : 0)
- : call(viewGetUint8, dataView, [index++]) & 0x3F;
- const result = u6 < 26
- ? u6 + 65
- : u6 < 52
- ? u6 + 71
- : u6 < 62
- ? u6 - 4
- : u6 < 63
- ? 43
- : u6 < 64
- ? 47
- : -1;
- if (result < 0) {
- throw new RangeError(`Piscēs: Unexpected Base64 value: ${u6}.`);
- } else {
- resultingCodeUnits[currentIndex] = result;
- }
- }
- return stringFromCodeUnits(...resultingCodeUnits);
-};
-
-/**
- * Returns whether the provided value is a Base64 string.
- *
- * Returns false if the provided value is not a string primitive.
- */
-export const isBase64 = ($) => {
- if (typeof $ !== "string") {
- return false;
- } else {
- const source = stringReplace($, /[\t\n\f\r ]+/gu, "");
- const trimmed = source.length % 4 == 0
- ? stringReplace(source, /={1,2}$/u, "")
- : source;
- return trimmed.length % 4 != 1 &&
- call(reExec, /[^0-9A-Za-z+\/]/u, [trimmed]) == null;
- }
-};