| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 |
- import { gzip, ungzip } from "pako";
- /*
- MIT License
- Copyright (c) 2020 Egor Nepomnyaschih
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
- const base64abc = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split("");
- const l = 256;
- const base64codes = new Uint8Array(l);
- for (let i = 0; i < l; ++i) {
- base64codes[i] = 255; // invalid character
- }
- base64abc.forEach((char, index) => {
- base64codes[char.charCodeAt(0)] = index;
- });
- base64codes["=".charCodeAt(0)] = 0; // ignored anyway, so we just need to prevent an error
- function getBase64Code(charCode: number): number {
- if (charCode >= base64codes.length) {
- throw new Error("Unable to parse base64 string.");
- }
- const code = base64codes[charCode];
- if (code === 255) {
- throw new Error("Unable to parse base64 string.");
- }
- return code;
- }
- export function bytesToBase64(bytes: Uint8Array) {
- let result = "",
- i: number;
- const l = bytes.length;
- for (i = 2; i < l; i += 3) {
- result += base64abc[bytes[i - 2] >> 2];
- result += base64abc[((bytes[i - 2] & 0x03) << 4) | (bytes[i - 1] >> 4)];
- result += base64abc[((bytes[i - 1] & 0x0f) << 2) | (bytes[i] >> 6)];
- result += base64abc[bytes[i] & 0x3f];
- }
- if (i === l + 1) {
- // 1 octet yet to write
- result += base64abc[bytes[i - 2] >> 2];
- result += base64abc[(bytes[i - 2] & 0x03) << 4];
- result += "==";
- }
- if (i === l) {
- // 2 octets yet to write
- result += base64abc[bytes[i - 2] >> 2];
- result += base64abc[((bytes[i - 2] & 0x03) << 4) | (bytes[i - 1] >> 4)];
- result += base64abc[(bytes[i - 1] & 0x0f) << 2];
- result += "=";
- }
- return result;
- }
- export function base64ToBytes(str: string) {
- if (str.length % 4 !== 0) {
- throw new Error("Unable to parse base64 string.");
- }
- const index = str.indexOf("=");
- if (index !== -1 && index < str.length - 2) {
- throw new Error("Unable to parse base64 string.");
- }
- const missingOctets = str.endsWith("==") ? 2 : str.endsWith("=") ? 1 : 0;
- const n = str.length;
- const result = new Uint8Array(3 * (n / 4));
- let buffer: number;
- for (let i = 0, j = 0; i < n; i += 4, j += 3) {
- buffer =
- (getBase64Code(str.charCodeAt(i)) << 18) |
- (getBase64Code(str.charCodeAt(i + 1)) << 12) |
- (getBase64Code(str.charCodeAt(i + 2)) << 6) |
- getBase64Code(str.charCodeAt(i + 3));
- result[j] = buffer >> 16;
- result[j + 1] = (buffer >> 8) & 0xff;
- result[j + 2] = buffer & 0xff;
- }
- return result.subarray(0, result.length - missingOctets);
- }
- export function base64encode(str: string, encoder = new TextEncoder()): string {
- return bytesToBase64(encoder.encode(str));
- }
- export function base64decode(str: string, decoder = new TextDecoder()): string {
- return decoder.decode(base64ToBytes(str));
- }
- export function zipEncode(str: string): string {
- return bytesToBase64(gzip(str));
- }
- export function decodeUnzip(str: string): string {
- return ungzip(base64ToBytes(str), { to: "string" });
- }
- export type CompressedArray<T> = {
- k: Array<keyof T>;
- v: Array<Array<T[keyof T]>>;
- };
- export function compressArray<T>(arr: Array<T>): CompressedArray<T> {
- if (arr.length == 0) {
- return { k: [], v: [] };
- }
- const elt = arr[0];
- const keys = Object.keys(elt) as Array<keyof T>;
- return { k: keys, v: arr.map((o) => keys.map((k) => o[k])) };
- }
- export function restoreArray<T>(obj: CompressedArray<T>): Array<T> {
- return obj.v.map((a) => {
- const o: Partial<T> = {};
- obj.k.forEach((k, i) => (o[k] = a[i]));
- return o as T;
- });
- }
- export function compressArrayZipEncode<T>(obj: T): string {
- const temp: Partial<T> = {};
- Object.entries(obj).forEach((kv) => {
- const v = kv[1];
- temp[kv[0] as keyof T] = Array.isArray(v) ? compressArray(v) : v;
- });
- return zipEncode(JSON.stringify(temp));
- }
- export function decodeUnzipRestoreArray<T>(str: string): T {
- const obj = JSON.parse(decodeUnzip(str));
- Object.keys(obj).forEach((k) => {
- const v = obj[k];
- if (typeof v == "object" && v && "k" in v && "v" in v) {
- obj[k] = restoreArray(v);
- }
- });
- return obj as T;
- }
|