@neoware_inc/neozipkit 0.5.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.
Files changed (171) hide show
  1. package/README.md +134 -0
  2. package/dist/browser/ZipkitBrowser.d.ts +27 -0
  3. package/dist/browser/ZipkitBrowser.d.ts.map +1 -0
  4. package/dist/browser/ZipkitBrowser.js +303 -0
  5. package/dist/browser/ZipkitBrowser.js.map +1 -0
  6. package/dist/browser/index.d.ts +9 -0
  7. package/dist/browser/index.d.ts.map +1 -0
  8. package/dist/browser/index.esm.d.ts +12 -0
  9. package/dist/browser/index.esm.d.ts.map +1 -0
  10. package/dist/browser/index.esm.js +46 -0
  11. package/dist/browser/index.esm.js.map +1 -0
  12. package/dist/browser/index.js +38 -0
  13. package/dist/browser/index.js.map +1 -0
  14. package/dist/browser-esm/index.d.ts +9 -0
  15. package/dist/browser-esm/index.js +50211 -0
  16. package/dist/browser-esm/index.js.map +7 -0
  17. package/dist/browser-umd/index.d.ts +9 -0
  18. package/dist/browser-umd/index.js +50221 -0
  19. package/dist/browser-umd/index.js.map +7 -0
  20. package/dist/browser-umd/index.min.js +39 -0
  21. package/dist/browser.d.ts +9 -0
  22. package/dist/browser.js +38 -0
  23. package/dist/core/ZipCompress.d.ts +99 -0
  24. package/dist/core/ZipCompress.d.ts.map +1 -0
  25. package/dist/core/ZipCompress.js +287 -0
  26. package/dist/core/ZipCompress.js.map +1 -0
  27. package/dist/core/ZipCopy.d.ts +175 -0
  28. package/dist/core/ZipCopy.d.ts.map +1 -0
  29. package/dist/core/ZipCopy.js +310 -0
  30. package/dist/core/ZipCopy.js.map +1 -0
  31. package/dist/core/ZipDecompress.d.ts +57 -0
  32. package/dist/core/ZipDecompress.d.ts.map +1 -0
  33. package/dist/core/ZipDecompress.js +155 -0
  34. package/dist/core/ZipDecompress.js.map +1 -0
  35. package/dist/core/ZipEntry.d.ts +138 -0
  36. package/dist/core/ZipEntry.d.ts.map +1 -0
  37. package/dist/core/ZipEntry.js +829 -0
  38. package/dist/core/ZipEntry.js.map +1 -0
  39. package/dist/core/Zipkit.d.ts +315 -0
  40. package/dist/core/Zipkit.d.ts.map +1 -0
  41. package/dist/core/Zipkit.js +647 -0
  42. package/dist/core/Zipkit.js.map +1 -0
  43. package/dist/core/ZstdManager.d.ts +56 -0
  44. package/dist/core/ZstdManager.d.ts.map +1 -0
  45. package/dist/core/ZstdManager.js +144 -0
  46. package/dist/core/ZstdManager.js.map +1 -0
  47. package/dist/core/components/HashCalculator.d.ts +138 -0
  48. package/dist/core/components/HashCalculator.d.ts.map +1 -0
  49. package/dist/core/components/HashCalculator.js +360 -0
  50. package/dist/core/components/HashCalculator.js.map +1 -0
  51. package/dist/core/components/Logger.d.ts +73 -0
  52. package/dist/core/components/Logger.d.ts.map +1 -0
  53. package/dist/core/components/Logger.js +156 -0
  54. package/dist/core/components/Logger.js.map +1 -0
  55. package/dist/core/components/ProgressTracker.d.ts +43 -0
  56. package/dist/core/components/ProgressTracker.d.ts.map +1 -0
  57. package/dist/core/components/ProgressTracker.js +112 -0
  58. package/dist/core/components/ProgressTracker.js.map +1 -0
  59. package/dist/core/components/Support.d.ts +64 -0
  60. package/dist/core/components/Support.d.ts.map +1 -0
  61. package/dist/core/components/Support.js +71 -0
  62. package/dist/core/components/Support.js.map +1 -0
  63. package/dist/core/components/Util.d.ts +26 -0
  64. package/dist/core/components/Util.d.ts.map +1 -0
  65. package/dist/core/components/Util.js +95 -0
  66. package/dist/core/components/Util.js.map +1 -0
  67. package/dist/core/constants/Errors.d.ts +52 -0
  68. package/dist/core/constants/Errors.d.ts.map +1 -0
  69. package/dist/core/constants/Errors.js +67 -0
  70. package/dist/core/constants/Errors.js.map +1 -0
  71. package/dist/core/constants/Headers.d.ts +170 -0
  72. package/dist/core/constants/Headers.d.ts.map +1 -0
  73. package/dist/core/constants/Headers.js +194 -0
  74. package/dist/core/constants/Headers.js.map +1 -0
  75. package/dist/core/encryption/Manager.d.ts +58 -0
  76. package/dist/core/encryption/Manager.d.ts.map +1 -0
  77. package/dist/core/encryption/Manager.js +121 -0
  78. package/dist/core/encryption/Manager.js.map +1 -0
  79. package/dist/core/encryption/ZipCrypto.d.ts +172 -0
  80. package/dist/core/encryption/ZipCrypto.d.ts.map +1 -0
  81. package/dist/core/encryption/ZipCrypto.js +554 -0
  82. package/dist/core/encryption/ZipCrypto.js.map +1 -0
  83. package/dist/core/encryption/index.d.ts +9 -0
  84. package/dist/core/encryption/index.d.ts.map +1 -0
  85. package/dist/core/encryption/index.js +17 -0
  86. package/dist/core/encryption/index.js.map +1 -0
  87. package/dist/core/encryption/types.d.ts +29 -0
  88. package/dist/core/encryption/types.d.ts.map +1 -0
  89. package/dist/core/encryption/types.js +12 -0
  90. package/dist/core/encryption/types.js.map +1 -0
  91. package/dist/core/index.d.ts +27 -0
  92. package/dist/core/index.d.ts.map +1 -0
  93. package/dist/core/index.js +59 -0
  94. package/dist/core/index.js.map +1 -0
  95. package/dist/core/version.d.ts +5 -0
  96. package/dist/core/version.d.ts.map +1 -0
  97. package/dist/core/version.js +31 -0
  98. package/dist/core/version.js.map +1 -0
  99. package/dist/index.d.ts +9 -0
  100. package/dist/index.d.ts.map +1 -0
  101. package/dist/index.js +38 -0
  102. package/dist/index.js.map +1 -0
  103. package/dist/node/ZipCompressNode.d.ts +123 -0
  104. package/dist/node/ZipCompressNode.d.ts.map +1 -0
  105. package/dist/node/ZipCompressNode.js +565 -0
  106. package/dist/node/ZipCompressNode.js.map +1 -0
  107. package/dist/node/ZipCopyNode.d.ts +165 -0
  108. package/dist/node/ZipCopyNode.d.ts.map +1 -0
  109. package/dist/node/ZipCopyNode.js +347 -0
  110. package/dist/node/ZipCopyNode.js.map +1 -0
  111. package/dist/node/ZipDecompressNode.d.ts +197 -0
  112. package/dist/node/ZipDecompressNode.d.ts.map +1 -0
  113. package/dist/node/ZipDecompressNode.js +678 -0
  114. package/dist/node/ZipDecompressNode.js.map +1 -0
  115. package/dist/node/ZipkitNode.d.ts +466 -0
  116. package/dist/node/ZipkitNode.d.ts.map +1 -0
  117. package/dist/node/ZipkitNode.js +1426 -0
  118. package/dist/node/ZipkitNode.js.map +1 -0
  119. package/dist/node/index.d.ts +25 -0
  120. package/dist/node/index.d.ts.map +1 -0
  121. package/dist/node/index.js +54 -0
  122. package/dist/node/index.js.map +1 -0
  123. package/dist/types/index.d.ts +45 -0
  124. package/dist/types/index.d.ts.map +1 -0
  125. package/dist/types/index.js +11 -0
  126. package/dist/types/index.js.map +1 -0
  127. package/examples/README.md +261 -0
  128. package/examples/append-data.json +44 -0
  129. package/examples/copy-zip-append.ts +139 -0
  130. package/examples/copy-zip.ts +152 -0
  131. package/examples/create-zip.ts +172 -0
  132. package/examples/extract-zip.ts +118 -0
  133. package/examples/list-zip.ts +161 -0
  134. package/examples/test-files/data.json +116 -0
  135. package/examples/test-files/document.md +80 -0
  136. package/examples/test-files/document.txt +6 -0
  137. package/examples/test-files/file1.txt +48 -0
  138. package/examples/test-files/file2.txt +80 -0
  139. package/examples/tsconfig.json +44 -0
  140. package/package.json +167 -0
  141. package/src/browser/ZipkitBrowser.ts +305 -0
  142. package/src/browser/index.esm.ts +32 -0
  143. package/src/browser/index.ts +19 -0
  144. package/src/core/ZipCompress.ts +370 -0
  145. package/src/core/ZipCopy.ts +434 -0
  146. package/src/core/ZipDecompress.ts +191 -0
  147. package/src/core/ZipEntry.ts +917 -0
  148. package/src/core/Zipkit.ts +794 -0
  149. package/src/core/ZstdManager.ts +165 -0
  150. package/src/core/components/HashCalculator.ts +384 -0
  151. package/src/core/components/Logger.ts +180 -0
  152. package/src/core/components/ProgressTracker.ts +134 -0
  153. package/src/core/components/Support.ts +77 -0
  154. package/src/core/components/Util.ts +91 -0
  155. package/src/core/constants/Errors.ts +78 -0
  156. package/src/core/constants/Headers.ts +205 -0
  157. package/src/core/encryption/Manager.ts +137 -0
  158. package/src/core/encryption/ZipCrypto.ts +650 -0
  159. package/src/core/encryption/index.ts +15 -0
  160. package/src/core/encryption/types.ts +33 -0
  161. package/src/core/index.ts +42 -0
  162. package/src/core/version.ts +33 -0
  163. package/src/index.ts +19 -0
  164. package/src/node/ZipCompressNode.ts +618 -0
  165. package/src/node/ZipCopyNode.ts +437 -0
  166. package/src/node/ZipDecompressNode.ts +793 -0
  167. package/src/node/ZipkitNode.ts +1706 -0
  168. package/src/node/index.ts +40 -0
  169. package/src/types/index.ts +68 -0
  170. package/src/types/modules.d.ts +22 -0
  171. package/src/types/opentimestamps.d.ts +1 -0
@@ -0,0 +1,370 @@
1
+ // ======================================
2
+ // ZipkitCompress.ts - Compression Module
3
+ // Copyright (c) 2025 NeoWare, Inc. All rights reserved.
4
+ // ======================================
5
+ //
6
+ // LOGGING INSTRUCTIONS:
7
+ // ---------------------
8
+ // To enable/disable logging, set loggingEnabled to true/false in the class:
9
+ // private static loggingEnabled: boolean = true; // Enable logging
10
+ // private static loggingEnabled: boolean = false; // Disable logging
11
+ //
12
+ // Logging respects the global Logger level (debug, info, warn, error, silent).
13
+ // Logger level is automatically set to 'debug' when loggingEnabled is true.
14
+ //
15
+
16
+ const pako = require('pako');
17
+ import { ZstdManager } from './ZstdManager';
18
+ import Zipkit from './Zipkit';
19
+ import { Logger } from './components/Logger';
20
+ import ZipEntry from './ZipEntry';
21
+ import Errors from './constants/Errors';
22
+ import { CMP_METHOD, GP_FLAG, ENCRYPT_HDR_SIZE } from './constants/Headers';
23
+ import { HashCalculator } from './components/HashCalculator';
24
+ import { ZipCrypto } from './encryption/ZipCrypto';
25
+
26
+ /**
27
+ * Options for compressing files in a ZIP archive
28
+ */
29
+ export interface CompressOptions {
30
+ level?: number; // Compression level (1-9, 0=store)
31
+ password?: string | null; // Password for encryption
32
+ useSHA256?: boolean; // Whether to calculate SHA256 hash default is false
33
+ useZstd?: boolean; // Whether to use Zstandard compression default is true
34
+ bufferSize?: number; // Override default buffer size
35
+ }
36
+
37
+ /**
38
+ * Callbacks for ZIP file creation process
39
+ * Buffer-based only - no file I/O operations
40
+ */
41
+ export interface CreateZipOptions {
42
+ onError?: (error: Error) => void; // Called when an error occurs
43
+ onEntryDone?: (entry: ZipEntry, status: string) => void; // Called when entry processing completes
44
+ onOutputBuffer?: (data: Buffer) => Promise<void>; // Called to write output data
45
+ }
46
+
47
+ /**
48
+ * Compression handler for ZIP files
49
+ * Supports Deflate, Zstandard, and Store methods
50
+ */
51
+ export class ZipCompress {
52
+ private zipkit: Zipkit;
53
+ private debug: boolean;
54
+
55
+ // Class-level logging control - set to true to enable logging
56
+ private static loggingEnabled: boolean = false;
57
+
58
+ /**
59
+ * Internal logging method - only logs if class logging is enabled
60
+ */
61
+ private log(...args: any[]): void {
62
+ if (ZipCompress.loggingEnabled) {
63
+ Logger.debug(`[ZipCompress]`, ...args);
64
+ }
65
+ }
66
+
67
+ /**
68
+ * Creates a new ZipCompress instance
69
+ * @param zipkit - Zipkit instance to use for ZIP operations
70
+ */
71
+ constructor(zipkit: Zipkit) {
72
+ this.zipkit = zipkit;
73
+ // Debug disabled by default (controlled by class-level logging)
74
+ this.debug = false;
75
+ // If logging is enabled, ensure Logger level is set to debug
76
+ if (ZipCompress.loggingEnabled) {
77
+ Logger.setLevel('debug');
78
+ }
79
+ this.log(`ZipCompress initialized`);
80
+ }
81
+
82
+ /**
83
+ * Compresses data for a ZIP entry (Buffer-based only)
84
+ * @param entry - ZIP entry to compress
85
+ * @param data - Buffer containing data to compress
86
+ * @param options - Compression options
87
+ * @param onOutputBuffer - Optional callback for streaming output
88
+ * @returns Buffer containing compressed data
89
+ */
90
+ async compressData(entry: ZipEntry, data: Buffer, options?: CompressOptions, onOutputBuffer?: (data: Buffer) => Promise<void>): Promise<Buffer> {
91
+ this.log(`compressData() called for entry: ${entry.filename}`);
92
+
93
+ // Set uncompressed size if not already set
94
+ if (!entry.uncompressedSize || entry.uncompressedSize === 0) {
95
+ entry.uncompressedSize = data.length;
96
+ }
97
+ const totalSize = data.length;
98
+ const bufferSize = options?.bufferSize || this.zipkit.getBufferSize(); // Use Zipkit's bufferSize
99
+
100
+ this.log(`Compressing ${totalSize} bytes for entry: ${entry.filename}`);
101
+ this.log(`Compression options:`, { level: options?.level, useZstd: options?.useZstd, bufferSize });
102
+
103
+ // Determine compression method
104
+ let compressionMethod: number;
105
+
106
+ if (options?.level === 0) {
107
+ compressionMethod = CMP_METHOD.STORED;
108
+ this.log(`Using STORED method (no compression)`);
109
+ } else if (options?.useZstd) {
110
+ // ZSTD fallback to STORED if file too small
111
+ if (totalSize < 100) {
112
+ compressionMethod = CMP_METHOD.STORED;
113
+ this.log(`ZSTD fallback to STORED (file too small: ${totalSize} bytes)`);
114
+ } else {
115
+ compressionMethod = CMP_METHOD.ZSTD;
116
+ this.log(`Using ZSTD method (zstd compression)`);
117
+ }
118
+ } else {
119
+ compressionMethod = CMP_METHOD.DEFLATED;
120
+ this.log(`Using DEFLATED method (default compression)`);
121
+ }
122
+
123
+ entry.cmpMethod = compressionMethod;
124
+
125
+ // Initialize hash calculator
126
+ const needsHashCalculation = (!entry.crc || entry.crc === 0) || (options?.useSHA256 && !entry.sha256);
127
+ const hashCalculator = needsHashCalculation ? new HashCalculator({ useSHA256: options?.useSHA256 && !entry.sha256 || false }) : null;
128
+
129
+ // Calculate hashes if needed
130
+ if (hashCalculator) {
131
+ hashCalculator.update(data);
132
+ if (!entry.crc || entry.crc === 0) {
133
+ entry.crc = hashCalculator.finalizeCRC32();
134
+ }
135
+ if (options?.useSHA256 && !entry.sha256) {
136
+ entry.sha256 = hashCalculator.finalizeSHA256();
137
+ }
138
+ this.log(`Final hashes: CRC32=0x${entry.crc.toString(16).padStart(8, '0')}, SHA256=${entry.sha256 || 'N/A'}`);
139
+ }
140
+
141
+ // Encrypt if password provided
142
+ if (options?.password) {
143
+ this.log(`Encrypting compressed data for entry: ${entry.filename}`);
144
+ (entry as any).gpFlag = ((entry as any).gpFlag || 0) | GP_FLAG.ENCRYPTED;
145
+ (entry as any).isEncrypted = true;
146
+ }
147
+
148
+ // Compress data based on method
149
+ let compressedData: Buffer;
150
+ const methodName = compressionMethod === CMP_METHOD.ZSTD ? 'ZSTD' : compressionMethod === CMP_METHOD.DEFLATED ? 'DEFLATED' : 'STORED';
151
+
152
+ if (compressionMethod === CMP_METHOD.STORED) {
153
+ compressedData = data;
154
+ } else {
155
+ this.log(`Processing sequence for ${methodName}: [HASH] -> [COMPRESS] -> [OUTPUT]`);
156
+ this.log(`Compressing: method=${methodName}, input=${totalSize} bytes, buffer size=${bufferSize} bytes`);
157
+ this.log(`Calculating hashes: CRC32=${!entry.crc || entry.crc === 0}, SHA256=${options?.useSHA256}`);
158
+
159
+ if (compressionMethod === CMP_METHOD.ZSTD) {
160
+ compressedData = await this.zstdCompress(data, options, bufferSize, entry, onOutputBuffer);
161
+ } else {
162
+ compressedData = await this.deflateCompress(data, options, bufferSize, entry, onOutputBuffer);
163
+ }
164
+ }
165
+
166
+ // Encrypt compressed data if password provided
167
+ if (options?.password) {
168
+ compressedData = this.encryptCompressedData(entry, compressedData, options.password);
169
+ }
170
+
171
+ entry.compressedSize = compressedData.length;
172
+
173
+ return compressedData;
174
+ }
175
+
176
+ /**
177
+ * Compress data using deflate algorithm with chunked processing
178
+ * @param data - Data to compress (Buffer or chunked reader)
179
+ * @param options - Compression options
180
+ * @param bufferSize - Buffer size for chunked processing
181
+ * @param entry - ZIP entry being compressed
182
+ * @param onOutputBuffer - Optional callback for streaming output
183
+ * @returns Buffer containing compressed data
184
+ */
185
+ async deflateCompress(
186
+ data: Buffer | { totalSize: number, onReadChunk: (position: number, size: number) => Buffer, onOutChunk: (chunk: Buffer) => void },
187
+ options?: CompressOptions,
188
+ bufferSize?: number,
189
+ entry?: ZipEntry,
190
+ onOutputBuffer?: (data: Buffer) => Promise<void>
191
+ ): Promise<Buffer> {
192
+ this.log(`deflateCompress() called - entry: ${entry?.filename ?? 'unknown'}, bufferSize: ${bufferSize}, level: ${options?.level ?? 6}`);
193
+
194
+ const effectiveBufferSize = bufferSize || this.zipkit.getBufferSize();
195
+ const level = options?.level ?? 6;
196
+
197
+ // Handle chunked reader
198
+ if (typeof data === 'object' && 'totalSize' in data && 'onReadChunk' in data) {
199
+ // Chunked reader mode - not implemented in simplified version
200
+ throw new Error('Chunked reader mode not supported in ZipCompress');
201
+ }
202
+
203
+ // For small data, use synchronous deflate
204
+ if (data.length <= effectiveBufferSize) {
205
+ return this.deflate(data, options);
206
+ }
207
+
208
+ // For large data, use chunked deflate
209
+ const deflator = new pako.Deflate({ level, raw: true });
210
+ const compressedChunks: Buffer[] = [];
211
+ let totalProcessed = 0;
212
+ let totalCompressedSize = 0;
213
+
214
+ try {
215
+ // Process data in chunks
216
+ for (let offset = 0; offset < data.length; offset += effectiveBufferSize) {
217
+ const chunk = data.slice(offset, offset + effectiveBufferSize);
218
+ const isLast = offset + effectiveBufferSize >= data.length;
219
+
220
+ deflator.push(chunk, isLast);
221
+
222
+ // Collect compressed chunks
223
+ if (deflator.result && deflator.result.length > 0) {
224
+ const compressedChunk = Buffer.from(deflator.result);
225
+ compressedChunks.push(compressedChunk);
226
+ totalCompressedSize += compressedChunk.length;
227
+
228
+ // Stream output if callback provided
229
+ if (onOutputBuffer) {
230
+ await onOutputBuffer(compressedChunk);
231
+ }
232
+ }
233
+
234
+ totalProcessed += chunk.length;
235
+ }
236
+
237
+ // Calculate compression ratio
238
+ const ratio = totalProcessed > 0 ? Math.round((totalCompressedSize / totalProcessed) * 100) : 0;
239
+ this.log(`Final hashes: CRC32=0x${entry?.crc?.toString(16).padStart(8, '0')}, SHA256=${entry?.sha256 || 'N/A'}`);
240
+ this.log(`Deflate compression complete: ${totalCompressedSize} bytes from ${totalProcessed} bytes (ratio=${ratio}%)`);
241
+
242
+ return Buffer.concat(compressedChunks);
243
+ } catch (e) {
244
+ throw new Error(`Deflate compression failed: ${e instanceof Error ? e.message : String(e)}`);
245
+ }
246
+ }
247
+
248
+ /**
249
+ * Compress data using deflate algorithm (synchronous, small buffers only)
250
+ * @param inbuf - Buffer containing data to compress
251
+ * @param options - Compression options
252
+ * @returns Buffer containing compressed data
253
+ */
254
+ deflate(inbuf: Buffer, options?: CompressOptions): Buffer {
255
+ this.log(`deflate() called with buffer size: ${inbuf.length}, level: ${options?.level ?? 6}`);
256
+ const level = options?.level ?? 6;
257
+ const result = pako.deflateRaw(inbuf, { level });
258
+ const ratio = inbuf.length > 0 ? Math.round((result.length / inbuf.length) * 100) : 0;
259
+ this.log(`Deflate compression complete: ${result.length} bytes from ${inbuf.length} bytes (ratio=${ratio}%)`);
260
+ return Buffer.from(result.buffer, result.byteOffset, result.byteLength);
261
+ }
262
+
263
+ /**
264
+ * Compress data using Zstandard (zstd) algorithm
265
+ * @param input - Input data to compress (Buffer or chunked reader)
266
+ * @param options - Compression options
267
+ * @param bufferSize - Buffer size for chunked processing
268
+ * @param entry - ZIP entry being compressed
269
+ * @param onOutputBuffer - Optional callback for streaming output
270
+ * @returns Buffer containing compressed data
271
+ */
272
+ async zstdCompress(
273
+ input: Buffer | { totalSize: number, readChunk: (position: number, size: number) => Buffer },
274
+ options?: CompressOptions,
275
+ bufferSize?: number,
276
+ entry?: ZipEntry,
277
+ onOutputBuffer?: (data: Buffer) => Promise<void>
278
+ ): Promise<Buffer> {
279
+ this.log(`zstdCompress() called - entry: ${entry?.filename ?? 'unknown'}, bufferSize: ${bufferSize}, level: ${options?.level ?? 6}`);
280
+
281
+ const effectiveBufferSize = bufferSize || this.zipkit.getBufferSize();
282
+ const level = options?.level ?? 6;
283
+
284
+ // Handle chunked reader
285
+ if (typeof input === 'object' && 'totalSize' in input && 'readChunk' in input) {
286
+ // Chunked reader mode - not implemented in simplified version
287
+ throw new Error('Chunked reader mode not supported in ZipCompress');
288
+ }
289
+
290
+ // Validate input
291
+ if (!input || input.length === 0) {
292
+ throw new Error('ZSTD compression: empty input buffer');
293
+ }
294
+
295
+ // Convert Buffer to Uint8Array for WASM module
296
+ const inputArray = new Uint8Array(input.buffer, input.byteOffset, input.byteLength);
297
+
298
+ // Use global ZstdManager for compression (handles queuing and initialization)
299
+ const compressed = await ZstdManager.compress(inputArray, level);
300
+ const compressedBuffer = Buffer.from(compressed);
301
+
302
+ if (onOutputBuffer) {
303
+ await onOutputBuffer(compressedBuffer);
304
+ }
305
+
306
+ return compressedBuffer;
307
+ }
308
+
309
+ /**
310
+ * Encrypt compressed data using PKZIP encryption
311
+ * @param entry - ZIP entry to encrypt
312
+ * @param compressedData - Compressed data to encrypt
313
+ * @param password - Password for encryption
314
+ * @returns Buffer containing encrypted data (includes 12-byte header)
315
+ */
316
+ encryptCompressedData(entry: ZipEntry, compressedData: Buffer, password: string): Buffer {
317
+ this.log(`encryptCompressedData() called for entry: ${entry.filename}, compressed size: ${compressedData.length}`);
318
+
319
+ const zipCrypto = new ZipCrypto();
320
+ const encryptedData = zipCrypto.encryptBuffer(entry, compressedData, password);
321
+
322
+ this.log(`Encryption complete: ${compressedData.length} bytes compressed -> ${encryptedData.length} bytes encrypted (includes ${ENCRYPT_HDR_SIZE}-byte header)`);
323
+
324
+ return encryptedData;
325
+ }
326
+
327
+ /**
328
+ * Compress file data in memory and return ZIP entry information as Buffer
329
+ * @param entry - ZIP entry to compress
330
+ * @param fileData - File data buffer to compress
331
+ * @param cmpOptions - Compression options
332
+ * @returns Buffer containing local header + compressed data
333
+ */
334
+ async compressFileBuffer(
335
+ entry: ZipEntry,
336
+ fileData: Buffer,
337
+ cmpOptions?: CompressOptions
338
+ ): Promise<Buffer> {
339
+ this.log(`compressFileBuffer() called for entry: ${entry.filename}, size: ${fileData.length}`);
340
+
341
+ // Set uncompressed size
342
+ entry.uncompressedSize = fileData.length;
343
+
344
+ // Initialize hash calculator
345
+ const hashCalculator = new HashCalculator({ useSHA256: cmpOptions?.useSHA256 || false });
346
+ hashCalculator.update(fileData);
347
+
348
+ // Set hashes
349
+ entry.crc = hashCalculator.finalizeCRC32();
350
+ if (cmpOptions?.useSHA256) {
351
+ entry.sha256 = hashCalculator.finalizeSHA256();
352
+ this.log(`SHA-256 calculated: ${entry.sha256}`);
353
+ }
354
+
355
+ // Compress data
356
+ const compressedData = await this.compressData(entry, fileData, cmpOptions);
357
+
358
+ // Encrypt if password provided
359
+ if (cmpOptions?.password) {
360
+ this.log(`Encrypting compressed data for entry: ${entry.filename}`);
361
+ (entry as any).gpFlag = ((entry as any).gpFlag || 0) | GP_FLAG.ENCRYPTED;
362
+ (entry as any).isEncrypted = true;
363
+ const zipCrypto = new ZipCrypto();
364
+ const encryptedData = zipCrypto.encryptBuffer(entry, compressedData, cmpOptions.password);
365
+ return encryptedData;
366
+ }
367
+
368
+ return compressedData;
369
+ }
370
+ }