UNPKG

@hugoalh/adler32

Version:

A module to get the checksum of the data with algorithm Adler32.

168 lines (167 loc) 4.41 kB
import { Buffer } from "node:buffer"; /** * Get the checksum of the data with algorithm Adler32. */ export class Adler32 { get [Symbol.toStringTag]() { return "Adler32"; } #freezed = false; #hash = null; #hashBase16 = null; #hashBase32Hex = null; #hashBase36 = null; #hashBase64 = null; #hashBase64URL = null; #a = 1n; #b = 0n; /** * Initialize. * @param {Adler32AcceptDataType} [data] Data. Can append later via the method {@linkcode Adler32.update}. */ constructor(data) { if (typeof data !== "undefined") { this.update(data); } } #clearStorage() { if (this.#freezed) { throw new Error(`Instance is freezed!`); } this.#hash = null; this.#hashBase16 = null; this.#hashBase32Hex = null; this.#hashBase36 = null; this.#hashBase64 = null; this.#hashBase64URL = null; } /** * Whether the instance is freezed. * @returns {boolean} */ get freezed() { return this.#freezed; } /** * Freeze the instance to prevent any further update. * @returns {this} */ freeze() { this.#freezed = true; return this; } /** * Get the checksum of the data, in original format. * @returns {bigint} */ hash() { this.#hash ??= this.#b * 65536n + this.#a; return this.#hash; } /** * Get the checksum of the data, in Base16. * @returns {string} */ hashBase16() { this.#hashBase16 ??= this.hashBigInt().toString(16).toUpperCase(); return this.#hashBase16; } /** * Get the checksum of the data, in Base32Hex ({@link https://datatracker.ietf.org/doc/html/rfc4648#section-7 RFC 4648 §7}). * @returns {string} */ hashBase32Hex() { this.#hashBase32Hex ??= this.hashBigInt().toString(32).toUpperCase(); return this.#hashBase32Hex; } /** * Get the checksum of the data, in Base36. * @returns {string} */ hashBase36() { this.#hashBase36 ??= this.hashBigInt().toString(36).toUpperCase(); return this.#hashBase36; } /** * Get the checksum of the data, in Base64. * @returns {string} */ hashBase64() { this.#hashBase64 ??= this.hashBuffer().toString("base64"); return this.#hashBase64; } /** * Get the checksum of the data, in Base64URL. * @returns {string} */ hashBase64URL() { this.#hashBase64URL ??= this.hashBuffer().toString("base64url"); return this.#hashBase64URL; } /** * Get the checksum of the data, in big integer. * @returns {bigint} */ hashBigInt() { return this.hash(); } /** * Get the checksum of the data, in big integer. * @returns {bigint} */ hashBigInteger = this.hashBigInt; /** * Get the checksum of the data, in Buffer. * @returns {Buffer} */ hashBuffer() { return Buffer.from(this.hashBase16(), "hex"); } /** * Get the checksum of the data, in hex/hexadecimal without padding. * @returns {string} */ hashHex() { return this.hashBase16(); } /** * Get the checksum of the data, in hex/hexadecimal with padding. * @returns {string} */ hashHexPadding() { return this.hashHex().padStart(8, "0"); } /** * Get the checksum of the data, in number. * @returns {number} */ hashNumber() { return Number(this.hash()); } /** * Append data. * @param {Adler32AcceptDataType} data Data. * @returns {this} */ update(data) { this.#clearStorage(); for (const byte of ((typeof data === "string") ? new TextEncoder().encode(data) : data)) { this.#a = (this.#a + BigInt(byte)) % 65521n; this.#b = (this.#b + this.#a) % 65521n; } return this; } /** * Initialize from the readable stream. * @param {ReadableStream<Adler32AcceptDataType>} stream Readable stream. * @returns {Promise<Adler32>} */ static async fromStream(stream) { const instance = new this(); for await (const chunk of stream) { instance.update(chunk); } return instance; } } export default Adler32;