@hugoalh/adler32
Version:
A module to get the checksum of the data with algorithm Adler32.
98 lines (97 loc) • 2.83 kB
JavaScript
/**
* Get the checksum of the data with algorithm Adler32.
*/
export class Adler32 {
get [Symbol.toStringTag]() {
return "Adler32";
}
#freezed = false;
#hashHex = null;
#hashUint8Array = null;
#a = 1n;
#b = 0n;
/**
* Initialize.
* @param {Adler32AcceptDataType} [data] Data. Can append later via the method {@linkcode Adler32.update} and {@linkcode Adler32.updateFromStream}.
*/
constructor(data) {
if (typeof data !== "undefined") {
this.update(data);
}
}
/**
* 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 Uint8Array.
* @returns {Uint8Array}
*/
hash() {
if (this.#hashUint8Array === null) {
const hex = this.hashHex();
const bytes = [];
for (let index = 0; index < hex.length; index += 2) {
bytes.push(hex.slice(index, index + 2));
}
this.#hashUint8Array = Uint8Array.from(bytes.map((byte) => {
return Number.parseInt(byte, 16);
}));
}
return Uint8Array.from(this.#hashUint8Array);
}
/**
* Get the checksum of the data, in hexadecimal with padding.
* @returns {string}
*/
hashHex() {
if (this.#hashHex === null) {
this.#hashHex = (this.#b * 65536n + this.#a).toString(16).toUpperCase().padStart(8, "0");
if (this.#hashHex.length !== 8) {
throw new Error(`Unexpected hash hex result \`${this.#hashHex}\`! Please submit a bug report.`);
}
}
return this.#hashHex;
}
/**
* Append data.
* @param {Adler32AcceptDataType} data Data.
* @returns {this}
*/
update(data) {
if (this.#freezed) {
throw new Error(`Instance is freezed!`);
}
this.#hashHex = null;
this.#hashUint8Array = null;
const dataFmt = (typeof data === "string") ? new TextEncoder().encode(data) : data;
for (const byte of dataFmt) {
this.#a = (this.#a + BigInt(byte)) % 65521n;
this.#b = (this.#b + this.#a) % 65521n;
}
return this;
}
/**
* Append data from the readable stream.
* @param {ReadableStream<Adler32AcceptDataType>} stream Data from the readable stream.
* @returns {Promise<this>}
*/
async updateFromStream(stream) {
for await (const chunk of stream) {
this.update(chunk);
}
return this;
}
}
export default Adler32;