@js-ak/excel-toolbox 1.2.6 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/build/cjs/lib/index.js +1 -0
- package/build/cjs/lib/template/index.js +17 -0
- package/build/cjs/lib/template/template-fs.js +465 -0
- package/build/cjs/lib/template/utils/check-row.js +23 -0
- package/build/cjs/lib/template/utils/check-rows.js +19 -0
- package/build/cjs/lib/template/utils/check-start-row.js +18 -0
- package/build/cjs/lib/template/utils/column-index-to-letter.js +17 -0
- package/build/cjs/lib/template/utils/escape-xml.js +24 -0
- package/build/cjs/lib/template/utils/get-max-row-number.js +20 -0
- package/build/cjs/lib/template/utils/get-rows-above.js +23 -0
- package/build/cjs/lib/template/utils/get-rows-below.js +23 -0
- package/build/cjs/lib/template/utils/index.js +27 -0
- package/build/cjs/lib/template/utils/parse-rows.js +30 -0
- package/build/cjs/lib/template/utils/to-excel-column-object.js +29 -0
- package/build/cjs/lib/template/utils/write-rows-to-stream.js +41 -0
- package/build/cjs/lib/xml/build-merged-sheet.js +1 -1
- package/build/cjs/lib/zip/constants.js +16 -1
- package/build/cjs/lib/zip/create-sync.js +32 -32
- package/build/cjs/lib/zip/create-with-stream.js +150 -0
- package/build/cjs/lib/zip/create.js +32 -32
- package/build/cjs/lib/zip/index.js +1 -0
- package/build/cjs/lib/zip/read-sync.js +60 -12
- package/build/cjs/lib/zip/read.js +60 -12
- package/build/cjs/lib/zip/utils/crc-32-stream.js +36 -0
- package/build/cjs/lib/zip/utils/crc-32.js +43 -0
- package/build/cjs/lib/zip/utils/dos-time.js +50 -0
- package/build/cjs/lib/zip/utils/find-data-descriptor.js +29 -0
- package/build/cjs/lib/zip/utils/index.js +21 -0
- package/build/cjs/lib/zip/utils/to-bytes.js +37 -0
- package/build/esm/lib/index.js +1 -0
- package/build/esm/lib/template/index.js +1 -0
- package/build/esm/lib/template/template-fs.js +428 -0
- package/build/esm/lib/template/utils/check-row.js +20 -0
- package/build/esm/lib/template/utils/check-rows.js +16 -0
- package/build/esm/lib/template/utils/check-start-row.js +15 -0
- package/build/esm/lib/template/utils/column-index-to-letter.js +14 -0
- package/build/esm/lib/template/utils/escape-xml.js +21 -0
- package/build/esm/lib/template/utils/get-max-row-number.js +17 -0
- package/build/esm/lib/template/utils/get-rows-above.js +20 -0
- package/build/esm/lib/template/utils/get-rows-below.js +20 -0
- package/build/esm/lib/template/utils/index.js +11 -0
- package/build/esm/lib/template/utils/parse-rows.js +27 -0
- package/build/esm/lib/template/utils/to-excel-column-object.js +26 -0
- package/build/esm/lib/template/utils/write-rows-to-stream.js +38 -0
- package/build/esm/lib/xml/build-merged-sheet.js +1 -1
- package/build/esm/lib/zip/constants.js +15 -0
- package/build/esm/lib/zip/create-sync.js +1 -1
- package/build/esm/lib/zip/create-with-stream.js +111 -0
- package/build/esm/lib/zip/create.js +1 -1
- package/build/esm/lib/zip/index.js +1 -0
- package/build/esm/lib/zip/read-sync.js +27 -12
- package/build/esm/lib/zip/read.js +27 -12
- package/build/esm/lib/zip/utils/crc-32-stream.js +33 -0
- package/build/esm/lib/zip/utils/crc-32.js +40 -0
- package/build/esm/lib/zip/utils/dos-time.js +47 -0
- package/build/esm/lib/zip/utils/find-data-descriptor.js +26 -0
- package/build/esm/lib/zip/utils/index.js +5 -0
- package/build/esm/lib/zip/utils/to-bytes.js +34 -0
- package/build/types/lib/index.d.ts +1 -0
- package/build/types/lib/template/index.d.ts +1 -0
- package/build/types/lib/template/template-fs.d.ts +122 -0
- package/build/types/lib/template/utils/check-row.d.ts +14 -0
- package/build/types/lib/template/utils/check-rows.d.ts +11 -0
- package/build/types/lib/template/utils/check-start-row.d.ts +8 -0
- package/build/types/lib/template/utils/column-index-to-letter.d.ts +7 -0
- package/build/types/lib/template/utils/escape-xml.d.ts +14 -0
- package/build/types/lib/template/utils/get-max-row-number.d.ts +7 -0
- package/build/types/lib/template/utils/get-rows-above.d.ts +12 -0
- package/build/types/lib/template/utils/get-rows-below.d.ts +12 -0
- package/build/types/lib/template/utils/index.d.ts +11 -0
- package/build/types/lib/template/utils/parse-rows.d.ts +1 -0
- package/build/types/lib/template/utils/to-excel-column-object.d.ts +10 -0
- package/build/types/lib/template/utils/write-rows-to-stream.d.ts +25 -0
- package/build/types/lib/zip/constants.d.ts +9 -0
- package/build/types/lib/zip/create-with-stream.d.ts +13 -0
- package/build/types/lib/zip/index.d.ts +1 -0
- package/build/types/lib/zip/utils/crc-32-stream.d.ts +11 -0
- package/build/types/lib/zip/utils/crc-32.d.ts +15 -0
- package/build/types/lib/zip/utils/dos-time.d.ts +25 -0
- package/build/types/lib/zip/utils/find-data-descriptor.d.ts +15 -0
- package/build/types/lib/zip/utils/index.d.ts +5 -0
- package/build/types/lib/zip/utils/to-bytes.d.ts +20 -0
- package/package.json +1 -1
- package/build/cjs/lib/zip/utils.js +0 -157
- package/build/esm/lib/zip/utils.js +0 -152
- package/build/types/lib/zip/utils.d.ts +0 -58
@@ -0,0 +1,14 @@
|
|
1
|
+
/**
|
2
|
+
* Validates that each key in the given row object is a valid cell reference.
|
3
|
+
*
|
4
|
+
* This function checks that all keys in the provided row object are composed
|
5
|
+
* only of column letters (A-Z, case insensitive). If a key is found that does
|
6
|
+
* not match this pattern, an error is thrown with a message indicating the
|
7
|
+
* invalid cell reference.
|
8
|
+
*
|
9
|
+
* @param row - An object representing a row of data, where keys are cell
|
10
|
+
* references and values are strings.
|
11
|
+
*
|
12
|
+
* @throws {Error} If any key in the row is not a valid column letter.
|
13
|
+
*/
|
14
|
+
export declare function checkRow(row: Record<string, string>): void;
|
@@ -0,0 +1,11 @@
|
|
1
|
+
/**
|
2
|
+
* Validates an array of row objects to ensure each cell reference is valid.
|
3
|
+
* Each row object is checked to ensure that its keys (cell references) are
|
4
|
+
* composed of valid column letters (e.g., "A", "B", "C").
|
5
|
+
*
|
6
|
+
* @param rows An array of row objects, where each object represents a row
|
7
|
+
* of data with cell references as keys and cell values as strings.
|
8
|
+
*
|
9
|
+
* @throws {Error} If any cell reference in the rows is invalid.
|
10
|
+
*/
|
11
|
+
export declare function checkRows(rows: Record<string, string>[]): void;
|
@@ -0,0 +1,7 @@
|
|
1
|
+
/**
|
2
|
+
* Converts a 0-based column index to an Excel-style letter (A, B, ..., Z, AA, AB, ...).
|
3
|
+
*
|
4
|
+
* @param index - The 0-based column index.
|
5
|
+
* @returns The Excel-style letter for the given column index.
|
6
|
+
*/
|
7
|
+
export declare function columnIndexToLetter(index: number): string;
|
@@ -0,0 +1,14 @@
|
|
1
|
+
/**
|
2
|
+
* Escapes special characters in a string for use in an XML document.
|
3
|
+
*
|
4
|
+
* Replaces:
|
5
|
+
* - `&` with `&`
|
6
|
+
* - `<` with `<`
|
7
|
+
* - `>` with `>`
|
8
|
+
* - `"` with `"`
|
9
|
+
* - `'` with `'`
|
10
|
+
*
|
11
|
+
* @param str - The string to escape.
|
12
|
+
* @returns The escaped string.
|
13
|
+
*/
|
14
|
+
export declare function escapeXml(str: string): string;
|
@@ -0,0 +1,7 @@
|
|
1
|
+
/**
|
2
|
+
* Finds the maximum row number in a list of <row> elements
|
3
|
+
* and returns the maximum row number + 1.
|
4
|
+
* @param {string} line - The line of XML to parse.
|
5
|
+
* @returns {number} - The maximum row number found + 1.
|
6
|
+
*/
|
7
|
+
export declare function getMaxRowNumber(line: string): number;
|
@@ -0,0 +1,12 @@
|
|
1
|
+
/**
|
2
|
+
* Filters out all rows in the given map that have a row number
|
3
|
+
* lower than or equal to the given minRow, and returns the
|
4
|
+
* filtered rows as a single string. Useful for removing rows
|
5
|
+
* from a template that are positioned above a certain row
|
6
|
+
* number.
|
7
|
+
*
|
8
|
+
* @param {Map<number, string>} map - The map of row numbers to row content
|
9
|
+
* @param {number} minRow - The minimum row number to include in the output
|
10
|
+
* @returns {string} The filtered rows, concatenated into a single string
|
11
|
+
*/
|
12
|
+
export declare function getRowsAbove(map: Map<number, string>, minRow: number): string;
|
@@ -0,0 +1,12 @@
|
|
1
|
+
/**
|
2
|
+
* Filters out all rows in the given map that have a row number
|
3
|
+
* greater than or equal to the given maxRow, and returns the
|
4
|
+
* filtered rows as a single string. Useful for removing rows
|
5
|
+
* from a template that are positioned below a certain row
|
6
|
+
* number.
|
7
|
+
*
|
8
|
+
* @param {Map<number, string>} map - The map of row numbers to row content
|
9
|
+
* @param {number} maxRow - The maximum row number to include in the output
|
10
|
+
* @returns {string} The filtered rows, concatenated into a single string
|
11
|
+
*/
|
12
|
+
export declare function getRowsBelow(map: Map<number, string>, maxRow: number): string;
|
@@ -0,0 +1,11 @@
|
|
1
|
+
export * from "./check-row.js";
|
2
|
+
export * from "./check-rows.js";
|
3
|
+
export * from "./check-start-row.js";
|
4
|
+
export * from "./column-index-to-letter.js";
|
5
|
+
export * from "./escape-xml.js";
|
6
|
+
export * from "./get-max-row-number.js";
|
7
|
+
export * from "./get-rows-above.js";
|
8
|
+
export * from "./get-rows-below.js";
|
9
|
+
export * from "./parse-rows.js";
|
10
|
+
export * from "./to-excel-column-object.js";
|
11
|
+
export * from "./write-rows-to-stream.js";
|
@@ -0,0 +1 @@
|
|
1
|
+
export declare function parseRows(innerRows: string): Map<number, string>;
|
@@ -0,0 +1,10 @@
|
|
1
|
+
/**
|
2
|
+
* Converts an array of values into a Record<string, string> with Excel column names as keys.
|
3
|
+
*
|
4
|
+
* The column names are generated in the standard Excel column naming convention (A, B, ..., Z, AA, AB, ...).
|
5
|
+
* The corresponding values are converted to strings using the String() function.
|
6
|
+
*
|
7
|
+
* @param values - The array of values to convert
|
8
|
+
* @returns The resulting Record<string, string>
|
9
|
+
*/
|
10
|
+
export declare function toExcelColumnObject(values: unknown[]): Record<string, string>;
|
@@ -0,0 +1,25 @@
|
|
1
|
+
import * as fs from "node:fs";
|
2
|
+
/**
|
3
|
+
* Writes an async iterable of rows to an Excel XML file.
|
4
|
+
*
|
5
|
+
* Each row is expected to be an array of values, where each value is
|
6
|
+
* converted to a string using the `String()` function. Empty values are
|
7
|
+
* replaced with an empty string.
|
8
|
+
*
|
9
|
+
* The `startRowNumber` parameter is used as the starting row number
|
10
|
+
* for the first row written to the file. Subsequent rows are written
|
11
|
+
* with incrementing row numbers.
|
12
|
+
*
|
13
|
+
* @param output - A file write stream to write the Excel XML to.
|
14
|
+
* @param rows - An async iterable of rows, where each row is an array
|
15
|
+
* of values.
|
16
|
+
* @param startRowNumber - The starting row number to use for the first
|
17
|
+
* row written to the file.
|
18
|
+
*
|
19
|
+
* @returns An object with a single property `rowNumber`, which is the
|
20
|
+
* last row number written to the file (i.e., the `startRowNumber`
|
21
|
+
* plus the number of rows written).
|
22
|
+
*/
|
23
|
+
export declare function writeRowsToStream(output: fs.WriteStream, rows: AsyncIterable<unknown[]>, startRowNumber: number): Promise<{
|
24
|
+
rowNumber: number;
|
25
|
+
}>;
|
@@ -12,6 +12,15 @@ import { Buffer } from "node:buffer";
|
|
12
12
|
* Found in the central directory that appears at the end of the ZIP file.
|
13
13
|
*/
|
14
14
|
export declare const CENTRAL_DIR_HEADER_SIG: Buffer<ArrayBuffer>;
|
15
|
+
/**
|
16
|
+
* Precomputed CRC-32 lookup table for optimized checksum calculation.
|
17
|
+
* The table is generated using the standard IEEE 802.3 (Ethernet) polynomial:
|
18
|
+
* 0xEDB88320 (reversed representation of 0x04C11DB7).
|
19
|
+
*
|
20
|
+
* The table is immediately invoked and cached as a constant for performance,
|
21
|
+
* following the common implementation pattern for CRC algorithms.
|
22
|
+
*/
|
23
|
+
export declare const CRC32_TABLE: Uint32Array<ArrayBuffer>;
|
15
24
|
/**
|
16
25
|
* End of Central Directory Record signature (0x504b0506).
|
17
26
|
* Marks the end of the central directory and contains global information
|
@@ -0,0 +1,13 @@
|
|
1
|
+
import { Writable } from "node:stream";
|
2
|
+
/**
|
3
|
+
* Creates a ZIP archive from a collection of files, streaming the output to a provided writable stream.
|
4
|
+
*
|
5
|
+
* @param fileKeys - An array of file paths (relative to the destination) that will be used to create a new workbook.
|
6
|
+
* @param destination - The path where the template files are located.
|
7
|
+
* @param output - A Writable stream that the ZIP archive will be written to.
|
8
|
+
*
|
9
|
+
* @throws {Error} - If a file does not exist in the destination.
|
10
|
+
* @throws {Error} - If a file is not readable.
|
11
|
+
* @throws {Error} - If the writable stream emits an error.
|
12
|
+
*/
|
13
|
+
export declare function createWithStream(fileKeys: string[], destination: string, output: Writable): Promise<void>;
|
@@ -0,0 +1,11 @@
|
|
1
|
+
import { Transform } from "node:stream";
|
2
|
+
/**
|
3
|
+
* Creates a Transform stream that computes the CRC-32 checksum of the input data.
|
4
|
+
*
|
5
|
+
* The `digest()` method can be called on the returned stream to get the final checksum value.
|
6
|
+
*
|
7
|
+
* @returns {Transform & { digest: () => number }} - The Transform stream.
|
8
|
+
*/
|
9
|
+
export declare function crc32Stream(): Transform & {
|
10
|
+
digest: () => number;
|
11
|
+
};
|
@@ -0,0 +1,15 @@
|
|
1
|
+
import { Buffer } from "node:buffer";
|
2
|
+
/**
|
3
|
+
* Computes a CRC-32 checksum for the given Buffer using the standard IEEE 802.3 polynomial.
|
4
|
+
* This implementation uses a precomputed lookup table for optimal performance.
|
5
|
+
*
|
6
|
+
* The algorithm follows these characteristics:
|
7
|
+
* - Polynomial: 0xEDB88320 (reversed representation of 0x04C11DB7)
|
8
|
+
* - Initial value: 0xFFFFFFFF (inverted by ~0)
|
9
|
+
* - Final XOR value: 0xFFFFFFFF (achieved by inverting the result)
|
10
|
+
* - Input and output reflection: Yes
|
11
|
+
*
|
12
|
+
* @param {Buffer} buf - The input buffer to calculate checksum for
|
13
|
+
* @returns {number} - The 32-bit unsigned CRC-32 checksum (0x00000000 to 0xFFFFFFFF)
|
14
|
+
*/
|
15
|
+
export declare function crc32(buf: Buffer): number;
|
@@ -0,0 +1,25 @@
|
|
1
|
+
import { Buffer } from "node:buffer";
|
2
|
+
/**
|
3
|
+
* Converts a JavaScript Date object to a 4-byte Buffer in MS-DOS date/time format
|
4
|
+
* as specified in the ZIP file format specification (PKZIP APPNOTE.TXT).
|
5
|
+
*
|
6
|
+
* The MS-DOS date/time format packs both date and time into 4 bytes (32 bits) with
|
7
|
+
* the following bit layout:
|
8
|
+
*
|
9
|
+
* Time portion (2 bytes/16 bits):
|
10
|
+
* - Bits 00-04: Seconds divided by 2 (0-29, representing 0-58 seconds)
|
11
|
+
* - Bits 05-10: Minutes (0-59)
|
12
|
+
* - Bits 11-15: Hours (0-23)
|
13
|
+
*
|
14
|
+
* Date portion (2 bytes/16 bits):
|
15
|
+
* - Bits 00-04: Day (1-31)
|
16
|
+
* - Bits 05-08: Month (1-12)
|
17
|
+
* - Bits 09-15: Year offset from 1980 (0-127, representing 1980-2107)
|
18
|
+
*
|
19
|
+
* @param {Date} date - The JavaScript Date object to convert
|
20
|
+
* @returns {Buffer} - 4-byte Buffer containing:
|
21
|
+
* - Bytes 0-1: DOS time (hours, minutes, seconds/2)
|
22
|
+
* - Bytes 2-3: DOS date (year-1980, month, day)
|
23
|
+
* @throws {RangeError} - If the date is before 1980 or after 2107
|
24
|
+
*/
|
25
|
+
export declare function dosTime(date: Date): Buffer;
|
@@ -0,0 +1,15 @@
|
|
1
|
+
/**
|
2
|
+
* Finds a Data Descriptor in a ZIP archive buffer.
|
3
|
+
*
|
4
|
+
* The Data Descriptor is an optional 16-byte structure that appears at the end of a file's compressed data.
|
5
|
+
* It contains the compressed size of the file, and must be used when the Local File Header does not contain this information.
|
6
|
+
*
|
7
|
+
* @param buffer - The buffer containing the ZIP archive data.
|
8
|
+
* @param start - The starting offset in the buffer to search for the Data Descriptor.
|
9
|
+
* @returns - An object with `offset` and `compressedSize` properties.
|
10
|
+
* @throws {Error} - If the Data Descriptor is not found.
|
11
|
+
*/
|
12
|
+
export declare function findDataDescriptor(buffer: Buffer, start: number): {
|
13
|
+
offset: number;
|
14
|
+
compressedSize: number;
|
15
|
+
};
|
@@ -0,0 +1,20 @@
|
|
1
|
+
import { Buffer } from "node:buffer";
|
2
|
+
/**
|
3
|
+
* Converts a numeric value into a fixed-length Buffer representation,
|
4
|
+
* storing the value in little-endian format with right-padding of zeros.
|
5
|
+
*
|
6
|
+
* This is particularly useful for binary protocols or file formats that
|
7
|
+
* require fixed-width numeric fields.
|
8
|
+
*
|
9
|
+
* @param {number} value - The numeric value to convert to bytes.
|
10
|
+
* Note: JavaScript numbers are IEEE 754 doubles, but only the
|
11
|
+
* integer portion will be used (up to 53-bit precision).
|
12
|
+
* @param {number} len - The desired length of the output Buffer in bytes.
|
13
|
+
* Must be a positive integer.
|
14
|
+
* @returns {Buffer} - A new Buffer of exactly `len` bytes containing:
|
15
|
+
* 1. The value's bytes in little-endian order (least significant byte first)
|
16
|
+
* 2. Zero padding in any remaining higher-order bytes
|
17
|
+
* @throws {RangeError} - If the value requires more bytes than `len` to represent
|
18
|
+
* (though this is currently not explicitly checked)
|
19
|
+
*/
|
20
|
+
export declare function toBytes(value: number, len: number): Buffer;
|
package/package.json
CHANGED
@@ -1,157 +0,0 @@
|
|
1
|
-
"use strict";
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.crc32 = crc32;
|
4
|
-
exports.dosTime = dosTime;
|
5
|
-
exports.toBytes = toBytes;
|
6
|
-
const node_buffer_1 = require("node:buffer");
|
7
|
-
/**
|
8
|
-
* Precomputed CRC-32 lookup table for optimized checksum calculation.
|
9
|
-
* The table is generated using the standard IEEE 802.3 (Ethernet) polynomial:
|
10
|
-
* 0xEDB88320 (reversed representation of 0x04C11DB7).
|
11
|
-
*
|
12
|
-
* The table is immediately invoked and cached as a constant for performance,
|
13
|
-
* following the common implementation pattern for CRC algorithms.
|
14
|
-
*/
|
15
|
-
const crcTable = (() => {
|
16
|
-
// Create a typed array for better performance with 256 32-bit unsigned integers
|
17
|
-
const table = new Uint32Array(256);
|
18
|
-
// Generate table entries for all possible byte values (0-255)
|
19
|
-
for (let i = 0; i < 256; i++) {
|
20
|
-
let crc = i; // Initialize with current byte value
|
21
|
-
// Process each bit (8 times)
|
22
|
-
for (let j = 0; j < 8; j++) {
|
23
|
-
/*
|
24
|
-
* CRC division algorithm:
|
25
|
-
* 1. If LSB is set (crc & 1), XOR with polynomial
|
26
|
-
* 2. Right-shift by 1 (unsigned)
|
27
|
-
*
|
28
|
-
* The polynomial 0xEDB88320 is:
|
29
|
-
* - Bit-reversed version of 0x04C11DB7
|
30
|
-
* - Uses reflected input/output algorithm
|
31
|
-
*/
|
32
|
-
crc = crc & 1
|
33
|
-
? 0xedb88320 ^ (crc >>> 1) // XOR with polynomial if LSB is set
|
34
|
-
: crc >>> 1; // Just shift right if LSB is not set
|
35
|
-
}
|
36
|
-
// Store final 32-bit value (>>> 0 ensures unsigned 32-bit representation)
|
37
|
-
table[i] = crc >>> 0;
|
38
|
-
}
|
39
|
-
return table;
|
40
|
-
})();
|
41
|
-
/**
|
42
|
-
* Computes a CRC-32 checksum for the given Buffer using the standard IEEE 802.3 polynomial.
|
43
|
-
* This implementation uses a precomputed lookup table for optimal performance.
|
44
|
-
*
|
45
|
-
* The algorithm follows these characteristics:
|
46
|
-
* - Polynomial: 0xEDB88320 (reversed representation of 0x04C11DB7)
|
47
|
-
* - Initial value: 0xFFFFFFFF (inverted by ~0)
|
48
|
-
* - Final XOR value: 0xFFFFFFFF (achieved by inverting the result)
|
49
|
-
* - Input and output reflection: Yes
|
50
|
-
*
|
51
|
-
* @param {Buffer} buf - The input buffer to calculate checksum for
|
52
|
-
* @returns {number} - The 32-bit unsigned CRC-32 checksum (0x00000000 to 0xFFFFFFFF)
|
53
|
-
*/
|
54
|
-
function crc32(buf) {
|
55
|
-
// Initialize CRC with all 1's (0xFFFFFFFF) using bitwise NOT
|
56
|
-
let crc = ~0;
|
57
|
-
// Process each byte in the buffer
|
58
|
-
for (let i = 0; i < buf.length; i++) {
|
59
|
-
/*
|
60
|
-
* CRC update algorithm steps:
|
61
|
-
* 1. XOR current CRC with next byte (lowest 8 bits)
|
62
|
-
* 2. Use result as index in precomputed table (0-255)
|
63
|
-
* 3. XOR the table value with right-shifted CRC (8 bits)
|
64
|
-
*
|
65
|
-
* The operation breakdown:
|
66
|
-
* - (crc ^ buf[i]) - XOR with next byte
|
67
|
-
* - & 0xff - Isolate lowest 8 bits
|
68
|
-
* - crc >>> 8 - Shift CRC right by 8 bits (unsigned)
|
69
|
-
* - ^ crcTable[...] - XOR with precomputed table value
|
70
|
-
*/
|
71
|
-
crc = (crc >>> 8) ^ crcTable[(crc ^ buf[i]) & 0xff];
|
72
|
-
}
|
73
|
-
/*
|
74
|
-
* Final processing:
|
75
|
-
* 1. Invert all bits (~crc) to match standard CRC-32 output
|
76
|
-
* 2. Convert to unsigned 32-bit integer (>>> 0)
|
77
|
-
*/
|
78
|
-
return ~crc >>> 0;
|
79
|
-
}
|
80
|
-
/**
|
81
|
-
* Converts a JavaScript Date object to a 4-byte Buffer in MS-DOS date/time format
|
82
|
-
* as specified in the ZIP file format specification (PKZIP APPNOTE.TXT).
|
83
|
-
*
|
84
|
-
* The MS-DOS date/time format packs both date and time into 4 bytes (32 bits) with
|
85
|
-
* the following bit layout:
|
86
|
-
*
|
87
|
-
* Time portion (2 bytes/16 bits):
|
88
|
-
* - Bits 00-04: Seconds divided by 2 (0-29, representing 0-58 seconds)
|
89
|
-
* - Bits 05-10: Minutes (0-59)
|
90
|
-
* - Bits 11-15: Hours (0-23)
|
91
|
-
*
|
92
|
-
* Date portion (2 bytes/16 bits):
|
93
|
-
* - Bits 00-04: Day (1-31)
|
94
|
-
* - Bits 05-08: Month (1-12)
|
95
|
-
* - Bits 09-15: Year offset from 1980 (0-127, representing 1980-2107)
|
96
|
-
*
|
97
|
-
* @param {Date} date - The JavaScript Date object to convert
|
98
|
-
* @returns {Buffer} - 4-byte Buffer containing:
|
99
|
-
* - Bytes 0-1: DOS time (hours, minutes, seconds/2)
|
100
|
-
* - Bytes 2-3: DOS date (year-1980, month, day)
|
101
|
-
* @throws {RangeError} - If the date is before 1980 or after 2107
|
102
|
-
*/
|
103
|
-
function dosTime(date) {
|
104
|
-
// Pack time components into 2 bytes (16 bits):
|
105
|
-
// - Hours (5 bits) shifted left 11 positions (bits 11-15)
|
106
|
-
// - Minutes (6 bits) shifted left 5 positions (bits 5-10)
|
107
|
-
// - Seconds/2 (5 bits) in least significant bits (bits 0-4)
|
108
|
-
const time = (date.getHours() << 11) | // Hours occupy bits 11-15
|
109
|
-
(date.getMinutes() << 5) | // Minutes occupy bits 5-10
|
110
|
-
(Math.floor(date.getSeconds() / 2)); // Seconds/2 occupy bits 0-4
|
111
|
-
// Pack date components into 2 bytes (16 bits):
|
112
|
-
// - (Year-1980) (7 bits) shifted left 9 positions (bits 9-15)
|
113
|
-
// - Month (4 bits) shifted left 5 positions (bits 5-8)
|
114
|
-
// - Day (5 bits) in least significant bits (bits 0-4)
|
115
|
-
const day = ((date.getFullYear() - 1980) << 9) | // Years since 1980 (bits 9-15)
|
116
|
-
((date.getMonth() + 1) << 5) | // Month 1-12 (bits 5-8)
|
117
|
-
date.getDate(); // Day 1-31 (bits 0-4)
|
118
|
-
// Combine both 2-byte values into a single 4-byte Buffer
|
119
|
-
// Note: Using little-endian byte order for each 2-byte segment
|
120
|
-
return node_buffer_1.Buffer.from([
|
121
|
-
...toBytes(time, 2), // Convert time to 2 bytes (LSB first)
|
122
|
-
...toBytes(day, 2), // Convert date to 2 bytes (LSB first)
|
123
|
-
]);
|
124
|
-
}
|
125
|
-
/**
|
126
|
-
* Converts a numeric value into a fixed-length Buffer representation,
|
127
|
-
* storing the value in little-endian format with right-padding of zeros.
|
128
|
-
*
|
129
|
-
* This is particularly useful for binary protocols or file formats that
|
130
|
-
* require fixed-width numeric fields.
|
131
|
-
*
|
132
|
-
* @param {number} value - The numeric value to convert to bytes.
|
133
|
-
* Note: JavaScript numbers are IEEE 754 doubles, but only the
|
134
|
-
* integer portion will be used (up to 53-bit precision).
|
135
|
-
* @param {number} len - The desired length of the output Buffer in bytes.
|
136
|
-
* Must be a positive integer.
|
137
|
-
* @returns {Buffer} - A new Buffer of exactly `len` bytes containing:
|
138
|
-
* 1. The value's bytes in little-endian order (least significant byte first)
|
139
|
-
* 2. Zero padding in any remaining higher-order bytes
|
140
|
-
* @throws {RangeError} - If the value requires more bytes than `len` to represent
|
141
|
-
* (though this is currently not explicitly checked)
|
142
|
-
*/
|
143
|
-
function toBytes(value, len) {
|
144
|
-
// Allocate a new Buffer of the requested length, automatically zero-filled
|
145
|
-
const buf = node_buffer_1.Buffer.alloc(len);
|
146
|
-
// Process each byte position from least significant to most significant
|
147
|
-
for (let i = 0; i < len; i++) {
|
148
|
-
// Store the least significant byte of the current value
|
149
|
-
buf[i] = value & 0xff; // Mask to get bottom 8 bits
|
150
|
-
// Right-shift the value by 8 bits to process the next byte
|
151
|
-
// Note: This uses unsigned right shift (>>> would be signed)
|
152
|
-
value >>= 8;
|
153
|
-
// If the loop completes with value != 0, we've overflowed the buffer length,
|
154
|
-
// but this isn't currently checked/handled
|
155
|
-
}
|
156
|
-
return buf;
|
157
|
-
}
|
@@ -1,152 +0,0 @@
|
|
1
|
-
import { Buffer } from "node:buffer";
|
2
|
-
/**
|
3
|
-
* Precomputed CRC-32 lookup table for optimized checksum calculation.
|
4
|
-
* The table is generated using the standard IEEE 802.3 (Ethernet) polynomial:
|
5
|
-
* 0xEDB88320 (reversed representation of 0x04C11DB7).
|
6
|
-
*
|
7
|
-
* The table is immediately invoked and cached as a constant for performance,
|
8
|
-
* following the common implementation pattern for CRC algorithms.
|
9
|
-
*/
|
10
|
-
const crcTable = (() => {
|
11
|
-
// Create a typed array for better performance with 256 32-bit unsigned integers
|
12
|
-
const table = new Uint32Array(256);
|
13
|
-
// Generate table entries for all possible byte values (0-255)
|
14
|
-
for (let i = 0; i < 256; i++) {
|
15
|
-
let crc = i; // Initialize with current byte value
|
16
|
-
// Process each bit (8 times)
|
17
|
-
for (let j = 0; j < 8; j++) {
|
18
|
-
/*
|
19
|
-
* CRC division algorithm:
|
20
|
-
* 1. If LSB is set (crc & 1), XOR with polynomial
|
21
|
-
* 2. Right-shift by 1 (unsigned)
|
22
|
-
*
|
23
|
-
* The polynomial 0xEDB88320 is:
|
24
|
-
* - Bit-reversed version of 0x04C11DB7
|
25
|
-
* - Uses reflected input/output algorithm
|
26
|
-
*/
|
27
|
-
crc = crc & 1
|
28
|
-
? 0xedb88320 ^ (crc >>> 1) // XOR with polynomial if LSB is set
|
29
|
-
: crc >>> 1; // Just shift right if LSB is not set
|
30
|
-
}
|
31
|
-
// Store final 32-bit value (>>> 0 ensures unsigned 32-bit representation)
|
32
|
-
table[i] = crc >>> 0;
|
33
|
-
}
|
34
|
-
return table;
|
35
|
-
})();
|
36
|
-
/**
|
37
|
-
* Computes a CRC-32 checksum for the given Buffer using the standard IEEE 802.3 polynomial.
|
38
|
-
* This implementation uses a precomputed lookup table for optimal performance.
|
39
|
-
*
|
40
|
-
* The algorithm follows these characteristics:
|
41
|
-
* - Polynomial: 0xEDB88320 (reversed representation of 0x04C11DB7)
|
42
|
-
* - Initial value: 0xFFFFFFFF (inverted by ~0)
|
43
|
-
* - Final XOR value: 0xFFFFFFFF (achieved by inverting the result)
|
44
|
-
* - Input and output reflection: Yes
|
45
|
-
*
|
46
|
-
* @param {Buffer} buf - The input buffer to calculate checksum for
|
47
|
-
* @returns {number} - The 32-bit unsigned CRC-32 checksum (0x00000000 to 0xFFFFFFFF)
|
48
|
-
*/
|
49
|
-
export function crc32(buf) {
|
50
|
-
// Initialize CRC with all 1's (0xFFFFFFFF) using bitwise NOT
|
51
|
-
let crc = ~0;
|
52
|
-
// Process each byte in the buffer
|
53
|
-
for (let i = 0; i < buf.length; i++) {
|
54
|
-
/*
|
55
|
-
* CRC update algorithm steps:
|
56
|
-
* 1. XOR current CRC with next byte (lowest 8 bits)
|
57
|
-
* 2. Use result as index in precomputed table (0-255)
|
58
|
-
* 3. XOR the table value with right-shifted CRC (8 bits)
|
59
|
-
*
|
60
|
-
* The operation breakdown:
|
61
|
-
* - (crc ^ buf[i]) - XOR with next byte
|
62
|
-
* - & 0xff - Isolate lowest 8 bits
|
63
|
-
* - crc >>> 8 - Shift CRC right by 8 bits (unsigned)
|
64
|
-
* - ^ crcTable[...] - XOR with precomputed table value
|
65
|
-
*/
|
66
|
-
crc = (crc >>> 8) ^ crcTable[(crc ^ buf[i]) & 0xff];
|
67
|
-
}
|
68
|
-
/*
|
69
|
-
* Final processing:
|
70
|
-
* 1. Invert all bits (~crc) to match standard CRC-32 output
|
71
|
-
* 2. Convert to unsigned 32-bit integer (>>> 0)
|
72
|
-
*/
|
73
|
-
return ~crc >>> 0;
|
74
|
-
}
|
75
|
-
/**
|
76
|
-
* Converts a JavaScript Date object to a 4-byte Buffer in MS-DOS date/time format
|
77
|
-
* as specified in the ZIP file format specification (PKZIP APPNOTE.TXT).
|
78
|
-
*
|
79
|
-
* The MS-DOS date/time format packs both date and time into 4 bytes (32 bits) with
|
80
|
-
* the following bit layout:
|
81
|
-
*
|
82
|
-
* Time portion (2 bytes/16 bits):
|
83
|
-
* - Bits 00-04: Seconds divided by 2 (0-29, representing 0-58 seconds)
|
84
|
-
* - Bits 05-10: Minutes (0-59)
|
85
|
-
* - Bits 11-15: Hours (0-23)
|
86
|
-
*
|
87
|
-
* Date portion (2 bytes/16 bits):
|
88
|
-
* - Bits 00-04: Day (1-31)
|
89
|
-
* - Bits 05-08: Month (1-12)
|
90
|
-
* - Bits 09-15: Year offset from 1980 (0-127, representing 1980-2107)
|
91
|
-
*
|
92
|
-
* @param {Date} date - The JavaScript Date object to convert
|
93
|
-
* @returns {Buffer} - 4-byte Buffer containing:
|
94
|
-
* - Bytes 0-1: DOS time (hours, minutes, seconds/2)
|
95
|
-
* - Bytes 2-3: DOS date (year-1980, month, day)
|
96
|
-
* @throws {RangeError} - If the date is before 1980 or after 2107
|
97
|
-
*/
|
98
|
-
export function dosTime(date) {
|
99
|
-
// Pack time components into 2 bytes (16 bits):
|
100
|
-
// - Hours (5 bits) shifted left 11 positions (bits 11-15)
|
101
|
-
// - Minutes (6 bits) shifted left 5 positions (bits 5-10)
|
102
|
-
// - Seconds/2 (5 bits) in least significant bits (bits 0-4)
|
103
|
-
const time = (date.getHours() << 11) | // Hours occupy bits 11-15
|
104
|
-
(date.getMinutes() << 5) | // Minutes occupy bits 5-10
|
105
|
-
(Math.floor(date.getSeconds() / 2)); // Seconds/2 occupy bits 0-4
|
106
|
-
// Pack date components into 2 bytes (16 bits):
|
107
|
-
// - (Year-1980) (7 bits) shifted left 9 positions (bits 9-15)
|
108
|
-
// - Month (4 bits) shifted left 5 positions (bits 5-8)
|
109
|
-
// - Day (5 bits) in least significant bits (bits 0-4)
|
110
|
-
const day = ((date.getFullYear() - 1980) << 9) | // Years since 1980 (bits 9-15)
|
111
|
-
((date.getMonth() + 1) << 5) | // Month 1-12 (bits 5-8)
|
112
|
-
date.getDate(); // Day 1-31 (bits 0-4)
|
113
|
-
// Combine both 2-byte values into a single 4-byte Buffer
|
114
|
-
// Note: Using little-endian byte order for each 2-byte segment
|
115
|
-
return Buffer.from([
|
116
|
-
...toBytes(time, 2), // Convert time to 2 bytes (LSB first)
|
117
|
-
...toBytes(day, 2), // Convert date to 2 bytes (LSB first)
|
118
|
-
]);
|
119
|
-
}
|
120
|
-
/**
|
121
|
-
* Converts a numeric value into a fixed-length Buffer representation,
|
122
|
-
* storing the value in little-endian format with right-padding of zeros.
|
123
|
-
*
|
124
|
-
* This is particularly useful for binary protocols or file formats that
|
125
|
-
* require fixed-width numeric fields.
|
126
|
-
*
|
127
|
-
* @param {number} value - The numeric value to convert to bytes.
|
128
|
-
* Note: JavaScript numbers are IEEE 754 doubles, but only the
|
129
|
-
* integer portion will be used (up to 53-bit precision).
|
130
|
-
* @param {number} len - The desired length of the output Buffer in bytes.
|
131
|
-
* Must be a positive integer.
|
132
|
-
* @returns {Buffer} - A new Buffer of exactly `len` bytes containing:
|
133
|
-
* 1. The value's bytes in little-endian order (least significant byte first)
|
134
|
-
* 2. Zero padding in any remaining higher-order bytes
|
135
|
-
* @throws {RangeError} - If the value requires more bytes than `len` to represent
|
136
|
-
* (though this is currently not explicitly checked)
|
137
|
-
*/
|
138
|
-
export function toBytes(value, len) {
|
139
|
-
// Allocate a new Buffer of the requested length, automatically zero-filled
|
140
|
-
const buf = Buffer.alloc(len);
|
141
|
-
// Process each byte position from least significant to most significant
|
142
|
-
for (let i = 0; i < len; i++) {
|
143
|
-
// Store the least significant byte of the current value
|
144
|
-
buf[i] = value & 0xff; // Mask to get bottom 8 bits
|
145
|
-
// Right-shift the value by 8 bits to process the next byte
|
146
|
-
// Note: This uses unsigned right shift (>>> would be signed)
|
147
|
-
value >>= 8;
|
148
|
-
// If the loop completes with value != 0, we've overflowed the buffer length,
|
149
|
-
// but this isn't currently checked/handled
|
150
|
-
}
|
151
|
-
return buf;
|
152
|
-
}
|