@hugoalh/adler32
Version:
A module to get the checksum of the data with algorithm Adler32.
168 lines (167 loc) • 4.41 kB
JavaScript
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;