UNPKG

node-pkware

Version:

nodejs implementation of StormLib's pkware compressor/de-compressor

220 lines 5.45 kB
import { EMPTY_BUFFER } from './constants.js'; /** * Creates a copy of `value` `repetitions` times into an array: * * @example * ```js * repeat(4, 10) -> [4, 4, 4, 4, 4, 4, 4, 4, 4, 4] * ``` * * Watch out! For reference types (arrays and objects) the repetitions will * all point to the same object: * * ```js * const data = { x: 10, y: 20 } * const reps = repeat(data, 3) // -> [data, data, data] * reps[2].x = 20 * console.log(data) // -> { x: 20, y: 20 } * ``` */ export function repeat(value, repetitions) { const values = []; for (let i = 0; i < repetitions; i++) { values.push(value); } return values; } /** * Makes sure `n` is no smaller than `min` and no greater than `max`: * * @example * ```js * clamp(3, 7, 8) === 7 * clamp(3, 7, 2) === 3 * clamp(3, 7, 5) === 5 * ``` */ export function clamp(min, max, n) { if (n < min) { return min; } if (n > max) { return max; } return n; } /** * @see https://github.com/ramda/ramda/blob/master/source/internal/_isFunction.js */ export function isFunction(x) { return Object.prototype.toString.call(x) === '[object Function]'; } /** * Creates `numberOfBits` number of 1s: * * @example * ```js * nBitsOfOnes(3) === 0b111 * nBitsOfOnes(7) === 0b111_1111 * ``` */ export function nBitsOfOnes(numberOfBits) { if (!Number.isInteger(numberOfBits) || numberOfBits < 0) { return 0; } return (1 << numberOfBits) - 1; } /** * Keeps the `numberOfBits` lower bits of `number` as is and discards higher bits: * * ``` * getLowestNBitsOf(0bXXXX_XXXX, 3) === 0b0000_0XXX * ``` * * @example * ```js * getLowestNBitsOf(0b1101_1011, 4) === 0b0000_1011 * getLowestNBitsOf(0b1101_1011, 3) === 0b0000_0011 * ``` */ export function getLowestNBitsOf(number, numberOfBits) { return number & nBitsOfOnes(numberOfBits); } /** * Converts a decimal integer into a hexadecimal number in a string with or without prefix and padding zeros * * @example * ```js * toHex(17) === "0x11" * toHex(17, 5) === "0x00011" * toHex(17, 5, false) === "00011" * toHex(17, 0, false) === "11" * * // invalid case: 1st parameter is not an integer * toHex(14.632) === "" * * // invalid case: 2nd parameter is not an integer * toHex(50, 3.2) === "" * * // invalid case: 2nd parameter is negative * toHex(24, -5) === "" * ``` */ export function toHex(num, digits = 0, withoutPrefix = false) { if (!Number.isInteger(num) || !Number.isInteger(digits) || digits < 0) { return ''; } let prefix = '0x'; if (withoutPrefix) { prefix = ''; } return `${prefix}${num.toString(16).padStart(digits, '0')}`; } /** * A sparse array is an array with holes in it: * * @example * ```js * const sparseArray = [1,, 3,, 5] * * // same as: * const sparseArray = [] * sparseArray[0] = 1 * sparseArray[2] = 3 * sparseArray[4] = 5 * ``` * * This function fills in holes in the 1st parameter array from the 2nd parameter array: * * @example * ```js * const a = [1,, 2,, 3] * const b = [,, 12, 13, 14] * mergeSparseArrays(a, b) // -> [1, undefined, 2, 13, 3] * ``` */ export function mergeSparseArrays(a, b) { let result; if (b.length < a.length) { result = [...b, ...repeat(undefined, a.length - b.length)]; } else { result = [...b]; } for (let i = 0; i < a.length; i++) { if (a[i] !== undefined) { result[i] = a[i]; } } return result; } /** * Builds a list from a seed value. Accepts an iterator function, which returns * either false to stop iteration or an array of length 2 containing the value * to add to the resulting list and the seed to be used in the next call to the * iterator function. * * @example * ```js * // while n is < 50: * // - turn current value to negative * // - add 10 to the next value * function fn(n) { * if (n > 50) { * return false * } * * return [-n, n + 10] * } * * unfold(fn, 10) // -> [-10, -20, -30, -40, -50] * ``` * * @see https://github.com/ramda/ramda/blob/master/source/unfold.js */ export function unfold(fn, seed) { let pair = fn(seed); const result = []; while (pair && pair.length > 0) { result[result.length] = pair[0]; pair = fn(pair[1]); } return result; } /** * @example * ```js * quotientAndRemainder(20, 3) // -> [6, 2] * ``` */ export function quotientAndRemainder(dividend, divisor) { return [Math.floor(dividend / divisor), dividend % divisor]; } /** * @see https://stackoverflow.com/a/49129872/1806628 */ export function concatArrayBuffers(buffers) { const nonEmptyBuffers = buffers.filter((buffer) => { return buffer.byteLength > 0; }); if (nonEmptyBuffers.length === 0) { return EMPTY_BUFFER; } const totalLength = nonEmptyBuffers.reduce((sum, buffer) => { return sum + buffer.byteLength; }, 0); const combinedBuffer = new Uint8Array(totalLength); let offset = 0; nonEmptyBuffers.forEach((buffer) => { combinedBuffer.set(new Uint8Array(buffer), offset); offset = offset + buffer.byteLength; }); return combinedBuffer.buffer; } export function sliceArrayBufferAt(buffer, at) { const view = new Uint8Array(buffer); const left = view.slice(0, at).buffer; const right = view.slice(at).buffer; return [left, right]; } //# sourceMappingURL=functions.js.map