@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.
- package/README.md +134 -0
- package/dist/browser/ZipkitBrowser.d.ts +27 -0
- package/dist/browser/ZipkitBrowser.d.ts.map +1 -0
- package/dist/browser/ZipkitBrowser.js +303 -0
- package/dist/browser/ZipkitBrowser.js.map +1 -0
- package/dist/browser/index.d.ts +9 -0
- package/dist/browser/index.d.ts.map +1 -0
- package/dist/browser/index.esm.d.ts +12 -0
- package/dist/browser/index.esm.d.ts.map +1 -0
- package/dist/browser/index.esm.js +46 -0
- package/dist/browser/index.esm.js.map +1 -0
- package/dist/browser/index.js +38 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/browser-esm/index.d.ts +9 -0
- package/dist/browser-esm/index.js +50211 -0
- package/dist/browser-esm/index.js.map +7 -0
- package/dist/browser-umd/index.d.ts +9 -0
- package/dist/browser-umd/index.js +50221 -0
- package/dist/browser-umd/index.js.map +7 -0
- package/dist/browser-umd/index.min.js +39 -0
- package/dist/browser.d.ts +9 -0
- package/dist/browser.js +38 -0
- package/dist/core/ZipCompress.d.ts +99 -0
- package/dist/core/ZipCompress.d.ts.map +1 -0
- package/dist/core/ZipCompress.js +287 -0
- package/dist/core/ZipCompress.js.map +1 -0
- package/dist/core/ZipCopy.d.ts +175 -0
- package/dist/core/ZipCopy.d.ts.map +1 -0
- package/dist/core/ZipCopy.js +310 -0
- package/dist/core/ZipCopy.js.map +1 -0
- package/dist/core/ZipDecompress.d.ts +57 -0
- package/dist/core/ZipDecompress.d.ts.map +1 -0
- package/dist/core/ZipDecompress.js +155 -0
- package/dist/core/ZipDecompress.js.map +1 -0
- package/dist/core/ZipEntry.d.ts +138 -0
- package/dist/core/ZipEntry.d.ts.map +1 -0
- package/dist/core/ZipEntry.js +829 -0
- package/dist/core/ZipEntry.js.map +1 -0
- package/dist/core/Zipkit.d.ts +315 -0
- package/dist/core/Zipkit.d.ts.map +1 -0
- package/dist/core/Zipkit.js +647 -0
- package/dist/core/Zipkit.js.map +1 -0
- package/dist/core/ZstdManager.d.ts +56 -0
- package/dist/core/ZstdManager.d.ts.map +1 -0
- package/dist/core/ZstdManager.js +144 -0
- package/dist/core/ZstdManager.js.map +1 -0
- package/dist/core/components/HashCalculator.d.ts +138 -0
- package/dist/core/components/HashCalculator.d.ts.map +1 -0
- package/dist/core/components/HashCalculator.js +360 -0
- package/dist/core/components/HashCalculator.js.map +1 -0
- package/dist/core/components/Logger.d.ts +73 -0
- package/dist/core/components/Logger.d.ts.map +1 -0
- package/dist/core/components/Logger.js +156 -0
- package/dist/core/components/Logger.js.map +1 -0
- package/dist/core/components/ProgressTracker.d.ts +43 -0
- package/dist/core/components/ProgressTracker.d.ts.map +1 -0
- package/dist/core/components/ProgressTracker.js +112 -0
- package/dist/core/components/ProgressTracker.js.map +1 -0
- package/dist/core/components/Support.d.ts +64 -0
- package/dist/core/components/Support.d.ts.map +1 -0
- package/dist/core/components/Support.js +71 -0
- package/dist/core/components/Support.js.map +1 -0
- package/dist/core/components/Util.d.ts +26 -0
- package/dist/core/components/Util.d.ts.map +1 -0
- package/dist/core/components/Util.js +95 -0
- package/dist/core/components/Util.js.map +1 -0
- package/dist/core/constants/Errors.d.ts +52 -0
- package/dist/core/constants/Errors.d.ts.map +1 -0
- package/dist/core/constants/Errors.js +67 -0
- package/dist/core/constants/Errors.js.map +1 -0
- package/dist/core/constants/Headers.d.ts +170 -0
- package/dist/core/constants/Headers.d.ts.map +1 -0
- package/dist/core/constants/Headers.js +194 -0
- package/dist/core/constants/Headers.js.map +1 -0
- package/dist/core/encryption/Manager.d.ts +58 -0
- package/dist/core/encryption/Manager.d.ts.map +1 -0
- package/dist/core/encryption/Manager.js +121 -0
- package/dist/core/encryption/Manager.js.map +1 -0
- package/dist/core/encryption/ZipCrypto.d.ts +172 -0
- package/dist/core/encryption/ZipCrypto.d.ts.map +1 -0
- package/dist/core/encryption/ZipCrypto.js +554 -0
- package/dist/core/encryption/ZipCrypto.js.map +1 -0
- package/dist/core/encryption/index.d.ts +9 -0
- package/dist/core/encryption/index.d.ts.map +1 -0
- package/dist/core/encryption/index.js +17 -0
- package/dist/core/encryption/index.js.map +1 -0
- package/dist/core/encryption/types.d.ts +29 -0
- package/dist/core/encryption/types.d.ts.map +1 -0
- package/dist/core/encryption/types.js +12 -0
- package/dist/core/encryption/types.js.map +1 -0
- package/dist/core/index.d.ts +27 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +59 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/version.d.ts +5 -0
- package/dist/core/version.d.ts.map +1 -0
- package/dist/core/version.js +31 -0
- package/dist/core/version.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +38 -0
- package/dist/index.js.map +1 -0
- package/dist/node/ZipCompressNode.d.ts +123 -0
- package/dist/node/ZipCompressNode.d.ts.map +1 -0
- package/dist/node/ZipCompressNode.js +565 -0
- package/dist/node/ZipCompressNode.js.map +1 -0
- package/dist/node/ZipCopyNode.d.ts +165 -0
- package/dist/node/ZipCopyNode.d.ts.map +1 -0
- package/dist/node/ZipCopyNode.js +347 -0
- package/dist/node/ZipCopyNode.js.map +1 -0
- package/dist/node/ZipDecompressNode.d.ts +197 -0
- package/dist/node/ZipDecompressNode.d.ts.map +1 -0
- package/dist/node/ZipDecompressNode.js +678 -0
- package/dist/node/ZipDecompressNode.js.map +1 -0
- package/dist/node/ZipkitNode.d.ts +466 -0
- package/dist/node/ZipkitNode.d.ts.map +1 -0
- package/dist/node/ZipkitNode.js +1426 -0
- package/dist/node/ZipkitNode.js.map +1 -0
- package/dist/node/index.d.ts +25 -0
- package/dist/node/index.d.ts.map +1 -0
- package/dist/node/index.js +54 -0
- package/dist/node/index.js.map +1 -0
- package/dist/types/index.d.ts +45 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +11 -0
- package/dist/types/index.js.map +1 -0
- package/examples/README.md +261 -0
- package/examples/append-data.json +44 -0
- package/examples/copy-zip-append.ts +139 -0
- package/examples/copy-zip.ts +152 -0
- package/examples/create-zip.ts +172 -0
- package/examples/extract-zip.ts +118 -0
- package/examples/list-zip.ts +161 -0
- package/examples/test-files/data.json +116 -0
- package/examples/test-files/document.md +80 -0
- package/examples/test-files/document.txt +6 -0
- package/examples/test-files/file1.txt +48 -0
- package/examples/test-files/file2.txt +80 -0
- package/examples/tsconfig.json +44 -0
- package/package.json +167 -0
- package/src/browser/ZipkitBrowser.ts +305 -0
- package/src/browser/index.esm.ts +32 -0
- package/src/browser/index.ts +19 -0
- package/src/core/ZipCompress.ts +370 -0
- package/src/core/ZipCopy.ts +434 -0
- package/src/core/ZipDecompress.ts +191 -0
- package/src/core/ZipEntry.ts +917 -0
- package/src/core/Zipkit.ts +794 -0
- package/src/core/ZstdManager.ts +165 -0
- package/src/core/components/HashCalculator.ts +384 -0
- package/src/core/components/Logger.ts +180 -0
- package/src/core/components/ProgressTracker.ts +134 -0
- package/src/core/components/Support.ts +77 -0
- package/src/core/components/Util.ts +91 -0
- package/src/core/constants/Errors.ts +78 -0
- package/src/core/constants/Headers.ts +205 -0
- package/src/core/encryption/Manager.ts +137 -0
- package/src/core/encryption/ZipCrypto.ts +650 -0
- package/src/core/encryption/index.ts +15 -0
- package/src/core/encryption/types.ts +33 -0
- package/src/core/index.ts +42 -0
- package/src/core/version.ts +33 -0
- package/src/index.ts +19 -0
- package/src/node/ZipCompressNode.ts +618 -0
- package/src/node/ZipCopyNode.ts +437 -0
- package/src/node/ZipDecompressNode.ts +793 -0
- package/src/node/ZipkitNode.ts +1706 -0
- package/src/node/index.ts +40 -0
- package/src/types/index.ts +68 -0
- package/src/types/modules.d.ts +22 -0
- package/src/types/opentimestamps.d.ts +1 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Copy ZIP and Append Example
|
|
5
|
+
*
|
|
6
|
+
* Copies entry data from example.zip into copied.zip, appends append-data.json
|
|
7
|
+
* in a single pass using ZipCopyNode: copyZipEntriesOnly, append the new file,
|
|
8
|
+
* then writeCentralDirectoryAndEOCD.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { ZipCopyNode, ZipkitNode, crc32, CMP_METHOD } from '../src/node';
|
|
12
|
+
import ZipEntry from '../src/core/ZipEntry';
|
|
13
|
+
import * as fs from 'fs';
|
|
14
|
+
import * as path from 'path';
|
|
15
|
+
|
|
16
|
+
function formatBytes(bytes: number): string {
|
|
17
|
+
if (bytes === 0) return '0 B';
|
|
18
|
+
const k = 1024;
|
|
19
|
+
const sizes = ['B', 'KB', 'MB', 'GB'];
|
|
20
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
21
|
+
return (bytes / Math.pow(k, i)).toFixed(1) + ' ' + sizes[i];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function padRight(str: string, length: number): string {
|
|
25
|
+
return (str + ' '.repeat(length)).slice(0, length);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function padLeft(str: string, length: number): string {
|
|
29
|
+
return (' '.repeat(length) + str).slice(-length);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async function main() {
|
|
33
|
+
console.log('Copy ZIP and append file example...\n');
|
|
34
|
+
|
|
35
|
+
const sourceZip = path.join(__dirname, 'output', 'example.zip');
|
|
36
|
+
let actualSourceZip = sourceZip;
|
|
37
|
+
if (!fs.existsSync(sourceZip)) {
|
|
38
|
+
const outputDir = path.dirname(sourceZip);
|
|
39
|
+
if (fs.existsSync(outputDir)) {
|
|
40
|
+
const files = fs.readdirSync(outputDir).filter((f) => f.endsWith('.zip'));
|
|
41
|
+
if (files.length > 0) {
|
|
42
|
+
actualSourceZip = path.join(outputDir, files[0]);
|
|
43
|
+
console.log(`ā ļø example.zip not found, using: ${files[0]}\n`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (!fs.existsSync(actualSourceZip)) {
|
|
49
|
+
console.error(`ā Error: Source ZIP not found: ${actualSourceZip}`);
|
|
50
|
+
console.error(' Run create-zip.ts first, or point sourceZip to an existing ZIP.');
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const appendFilePath = path.join(__dirname, 'append-data.json');
|
|
55
|
+
if (!fs.existsSync(appendFilePath)) {
|
|
56
|
+
console.error(`ā Error: File to append not found: ${appendFilePath}`);
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const destZip = path.join(__dirname, 'output', 'copied.zip');
|
|
61
|
+
const outputDir = path.dirname(destZip);
|
|
62
|
+
if (!fs.existsSync(outputDir)) {
|
|
63
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const zipkitNode = new ZipkitNode();
|
|
67
|
+
const zipCopy = new ZipCopyNode(zipkitNode);
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
// 1. Copy only entry data (no central directory or EOCD yet)
|
|
71
|
+
console.log('1. Copying entry data from source ZIP...');
|
|
72
|
+
const { destPath, dataEndOffset, copiedEntries } = await zipCopy.copyZipEntriesOnly(
|
|
73
|
+
actualSourceZip,
|
|
74
|
+
destZip
|
|
75
|
+
);
|
|
76
|
+
console.log(` Copied ${copiedEntries.length} entries; data ends at offset ${dataEndOffset}\n`);
|
|
77
|
+
|
|
78
|
+
// 2. Append append-data.json as a stored entry
|
|
79
|
+
const entryName = 'append-data.json';
|
|
80
|
+
const fileData = fs.readFileSync(appendFilePath);
|
|
81
|
+
const fileCrc = crc32(fileData) >>> 0;
|
|
82
|
+
const fileSize = fileData.length;
|
|
83
|
+
|
|
84
|
+
const entry = new ZipEntry(entryName, null, false);
|
|
85
|
+
entry.localHdrOffset = dataEndOffset;
|
|
86
|
+
entry.cmpMethod = CMP_METHOD.STORED;
|
|
87
|
+
entry.crc = fileCrc;
|
|
88
|
+
entry.compressedSize = fileSize;
|
|
89
|
+
entry.uncompressedSize = fileSize;
|
|
90
|
+
entry.timeDateDOS = entry.setDateTime(new Date());
|
|
91
|
+
|
|
92
|
+
const localHeaderBuf = entry.createLocalHdr();
|
|
93
|
+
const destFd = fs.openSync(destPath, 'r+');
|
|
94
|
+
try {
|
|
95
|
+
fs.writeSync(destFd, localHeaderBuf, 0, localHeaderBuf.length, dataEndOffset);
|
|
96
|
+
fs.writeSync(destFd, fileData, 0, fileData.length, dataEndOffset + localHeaderBuf.length);
|
|
97
|
+
} finally {
|
|
98
|
+
fs.closeSync(destFd);
|
|
99
|
+
}
|
|
100
|
+
console.log(`2. Appended "${entryName}" (${formatBytes(fileSize)} stored)\n`);
|
|
101
|
+
|
|
102
|
+
// 3. Write central directory and EOCD for all entries (copied + appended)
|
|
103
|
+
const allEntries = [...copiedEntries, entry];
|
|
104
|
+
zipCopy.writeCentralDirectoryAndEOCD(destPath, allEntries, { zipComment: '' });
|
|
105
|
+
console.log('3. Wrote central directory and EOCD.\n');
|
|
106
|
+
|
|
107
|
+
console.log(`ā
Done: ${destZip}\n`);
|
|
108
|
+
|
|
109
|
+
console.log('Entries in final ZIP:');
|
|
110
|
+
console.log('ā'.repeat(80));
|
|
111
|
+
console.log(
|
|
112
|
+
padRight('Filename', 50) + padLeft('Compressed', 14) + padLeft('Offset', 14)
|
|
113
|
+
);
|
|
114
|
+
console.log('ā'.repeat(80));
|
|
115
|
+
allEntries.forEach((e) => {
|
|
116
|
+
console.log(
|
|
117
|
+
padRight(e.filename.length > 48 ? e.filename.slice(0, 45) + '...' : e.filename, 50) +
|
|
118
|
+
padLeft(formatBytes(e.compressedSize), 14) +
|
|
119
|
+
padLeft(`0x${e.localHdrOffset.toString(16)}`, 14)
|
|
120
|
+
);
|
|
121
|
+
});
|
|
122
|
+
console.log('ā'.repeat(80));
|
|
123
|
+
console.log(`Total: ${allEntries.length} entries`);
|
|
124
|
+
|
|
125
|
+
if (fs.existsSync(destZip)) {
|
|
126
|
+
const destStats = fs.statSync(destZip);
|
|
127
|
+
console.log(`\nArchive size: ${formatBytes(destStats.size)}`);
|
|
128
|
+
}
|
|
129
|
+
} catch (error) {
|
|
130
|
+
console.error('ā Error:', error instanceof Error ? error.message : String(error));
|
|
131
|
+
if (error instanceof Error && error.stack) console.error(error.stack);
|
|
132
|
+
process.exit(1);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
main().catch((e) => {
|
|
137
|
+
console.error('Fatal:', e);
|
|
138
|
+
process.exit(1);
|
|
139
|
+
});
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Copy ZIP Example
|
|
5
|
+
*
|
|
6
|
+
* Demonstrates copying entries from an existing ZIP file to a new ZIP file
|
|
7
|
+
* using the ZipCopyNode class. This preserves all original properties
|
|
8
|
+
* (compression, timestamps, etc.) without decompression/recompression.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { ZipCopyNode, ZipkitNode } from '../src/node';
|
|
12
|
+
import * as fs from 'fs';
|
|
13
|
+
import * as path from 'path';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Helper function to format bytes
|
|
17
|
+
*/
|
|
18
|
+
function formatBytes(bytes: number): string {
|
|
19
|
+
if (bytes === 0) return '0 B';
|
|
20
|
+
const k = 1024;
|
|
21
|
+
const sizes = ['B', 'KB', 'MB', 'GB'];
|
|
22
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
23
|
+
return (bytes / Math.pow(k, i)).toFixed(1) + ' ' + sizes[i];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Helper function to pad string to the right
|
|
28
|
+
*/
|
|
29
|
+
function padRight(str: string, length: number): string {
|
|
30
|
+
return (str + ' '.repeat(length)).slice(0, length);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Helper function to pad string to the left
|
|
35
|
+
*/
|
|
36
|
+
function padLeft(str: string, length: number): string {
|
|
37
|
+
return (' '.repeat(length) + str).slice(-length);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function main() {
|
|
41
|
+
console.log('Copy ZIP file example...\n');
|
|
42
|
+
|
|
43
|
+
// Source ZIP file (use the example.zip created by create-zip.ts if it exists)
|
|
44
|
+
const sourceZip = path.join(__dirname, 'output', 'example.zip');
|
|
45
|
+
|
|
46
|
+
// If example.zip doesn't exist, check for any ZIP file in the output directory
|
|
47
|
+
let actualSourceZip = sourceZip;
|
|
48
|
+
if (!fs.existsSync(sourceZip)) {
|
|
49
|
+
const outputDir = path.dirname(sourceZip);
|
|
50
|
+
if (fs.existsSync(outputDir)) {
|
|
51
|
+
const files = fs.readdirSync(outputDir).filter(f => f.endsWith('.zip'));
|
|
52
|
+
if (files.length > 0) {
|
|
53
|
+
actualSourceZip = path.join(outputDir, files[0]);
|
|
54
|
+
console.log(`ā ļø example.zip not found, using: ${files[0]}\n`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Verify source ZIP exists
|
|
60
|
+
if (!fs.existsSync(actualSourceZip)) {
|
|
61
|
+
console.error(`ā Error: Source ZIP file not found: ${actualSourceZip}`);
|
|
62
|
+
console.error(' Please run create-zip.ts first to create a ZIP file, or');
|
|
63
|
+
console.error(' update the sourceZip path in this example to point to an existing ZIP file.');
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const sourceStats = fs.statSync(actualSourceZip);
|
|
68
|
+
console.log(`Source ZIP: ${path.basename(actualSourceZip)}`);
|
|
69
|
+
console.log(` Size: ${formatBytes(sourceStats.size)}`);
|
|
70
|
+
console.log();
|
|
71
|
+
|
|
72
|
+
// Destination ZIP file
|
|
73
|
+
const destZip = path.join(__dirname, 'output', 'copied.zip');
|
|
74
|
+
|
|
75
|
+
// Ensure output directory exists
|
|
76
|
+
const outputDir = path.dirname(destZip);
|
|
77
|
+
if (!fs.existsSync(outputDir)) {
|
|
78
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
console.log('Copying ZIP entries...');
|
|
83
|
+
|
|
84
|
+
// Create ZipCopyNode instance
|
|
85
|
+
const zipkitNode = new ZipkitNode();
|
|
86
|
+
const zipCopy = new ZipCopyNode(zipkitNode);
|
|
87
|
+
|
|
88
|
+
// Option 1: Copy all entries
|
|
89
|
+
console.log(' Copying all entries from source to destination...');
|
|
90
|
+
const result = await zipCopy.copyZipFile(actualSourceZip, destZip);
|
|
91
|
+
|
|
92
|
+
console.log(`ā
ZIP file copied successfully: ${destZip}\n`);
|
|
93
|
+
|
|
94
|
+
// Display summary of copied entries
|
|
95
|
+
console.log('Copied Entries Summary:');
|
|
96
|
+
console.log('ā'.repeat(80));
|
|
97
|
+
console.log(
|
|
98
|
+
padRight('Filename', 50) +
|
|
99
|
+
padLeft('Compressed Size', 20) +
|
|
100
|
+
padLeft('Local Header Offset', 20)
|
|
101
|
+
);
|
|
102
|
+
console.log('ā'.repeat(80));
|
|
103
|
+
|
|
104
|
+
result.entries.forEach((entry) => {
|
|
105
|
+
const filename = entry.filename || '(unnamed)';
|
|
106
|
+
console.log(
|
|
107
|
+
padRight(filename.length > 48 ? filename.substring(0, 45) + '...' : filename, 50) +
|
|
108
|
+
padLeft(formatBytes(entry.compressedSize), 20) +
|
|
109
|
+
padLeft(`0x${entry.localHeaderOffset.toString(16)}`, 20)
|
|
110
|
+
);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
console.log('ā'.repeat(80));
|
|
114
|
+
console.log(`Total entries copied: ${result.totalEntries}`);
|
|
115
|
+
console.log(`Central directory offset: 0x${result.centralDirOffset.toString(16)}`);
|
|
116
|
+
|
|
117
|
+
// Verify the copied ZIP was created
|
|
118
|
+
if (fs.existsSync(destZip)) {
|
|
119
|
+
const destStats = fs.statSync(destZip);
|
|
120
|
+
console.log(`\nDestination ZIP file size: ${formatBytes(destStats.size)}`);
|
|
121
|
+
|
|
122
|
+
// Compare sizes (they should be very similar, possibly identical)
|
|
123
|
+
const sizeDiff = Math.abs(sourceStats.size - destStats.size);
|
|
124
|
+
if (sizeDiff === 0) {
|
|
125
|
+
console.log('ā
File sizes match exactly - perfect copy!');
|
|
126
|
+
} else {
|
|
127
|
+
console.log(`ā¹ļø Size difference: ${formatBytes(sizeDiff)} (expected due to ZIP structure variations)`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
console.log('\nš” Tip: You can also filter entries during copy:');
|
|
132
|
+
console.log(' const zipCopy = new ZipCopyNode(new ZipkitNode());');
|
|
133
|
+
console.log(' await zipCopy.copyZipFile(sourceZip, destZip, {');
|
|
134
|
+
console.log(' entryFilter: (entry) => entry.filename.endsWith(".txt")');
|
|
135
|
+
console.log(' });');
|
|
136
|
+
|
|
137
|
+
} catch (error) {
|
|
138
|
+
console.error('ā Error copying ZIP file:');
|
|
139
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
140
|
+
if (error instanceof Error && error.stack) {
|
|
141
|
+
console.error('\nStack trace:');
|
|
142
|
+
console.error(error.stack);
|
|
143
|
+
}
|
|
144
|
+
process.exit(1);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Run the example
|
|
149
|
+
main().catch((error) => {
|
|
150
|
+
console.error('Fatal error:', error);
|
|
151
|
+
process.exit(1);
|
|
152
|
+
});
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Create ZIP Example
|
|
5
|
+
*
|
|
6
|
+
* Demonstrates creating a ZIP archive from multiple files using ZipkitNode.
|
|
7
|
+
* This is a minimal example showing the basic API usage.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import ZipkitNode from '../src/node';
|
|
11
|
+
import type { CompressOptions } from '../src/core';
|
|
12
|
+
import * as fs from 'fs';
|
|
13
|
+
import * as path from 'path';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Helper function to format bytes
|
|
17
|
+
*/
|
|
18
|
+
function formatBytes(bytes: number): string {
|
|
19
|
+
if (bytes === 0) return '0 B';
|
|
20
|
+
const k = 1024;
|
|
21
|
+
const sizes = ['B', 'KB', 'MB', 'GB'];
|
|
22
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
23
|
+
return (bytes / Math.pow(k, i)).toFixed(1) + ' ' + sizes[i];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Helper function to pad string to the right
|
|
28
|
+
*/
|
|
29
|
+
function padRight(str: string, length: number): string {
|
|
30
|
+
return (str + ' '.repeat(length)).slice(0, length);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Helper function to pad string to the left
|
|
35
|
+
*/
|
|
36
|
+
function padLeft(str: string, length: number): string {
|
|
37
|
+
return (' '.repeat(length) + str).slice(-length);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function main() {
|
|
41
|
+
console.log('Creating ZIP archive example...\n');
|
|
42
|
+
|
|
43
|
+
// Test files to compress (located in test-files directory)
|
|
44
|
+
const testDir = path.join(__dirname, 'test-files');
|
|
45
|
+
const testFiles = [
|
|
46
|
+
path.join(testDir, 'file1.txt'),
|
|
47
|
+
path.join(testDir, 'file2.txt'),
|
|
48
|
+
path.join(testDir, 'document.md'),
|
|
49
|
+
path.join(testDir, 'data.json')
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
// Verify all test files exist
|
|
53
|
+
for (const file of testFiles) {
|
|
54
|
+
if (!fs.existsSync(file)) {
|
|
55
|
+
console.error(`ā Error: Test file not found: ${file}`);
|
|
56
|
+
console.error(' Make sure test-files directory contains the required files.');
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
console.log('Source files:');
|
|
62
|
+
testFiles.forEach(file => {
|
|
63
|
+
const stats = fs.statSync(file);
|
|
64
|
+
console.log(` - ${path.basename(file)} (${stats.size} bytes)`);
|
|
65
|
+
});
|
|
66
|
+
console.log();
|
|
67
|
+
|
|
68
|
+
// Create ZipkitNode instance
|
|
69
|
+
const zip = new ZipkitNode();
|
|
70
|
+
|
|
71
|
+
// Define output ZIP file path
|
|
72
|
+
const outputZip = path.join(__dirname, 'output', 'example.zip');
|
|
73
|
+
|
|
74
|
+
// Ensure output directory exists
|
|
75
|
+
const outputDir = path.dirname(outputZip);
|
|
76
|
+
if (!fs.existsSync(outputDir)) {
|
|
77
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Compression options
|
|
81
|
+
const options: CompressOptions = {
|
|
82
|
+
level: 6, // Compression level (0-9, higher = better compression but slower)
|
|
83
|
+
useZstd: false, // Use Deflate compression (standard ZIP)
|
|
84
|
+
useSHA256: false // Don't calculate SHA-256 hashes (faster, but needed for blockchain features)
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
console.log('Creating ZIP archive...');
|
|
89
|
+
|
|
90
|
+
// Method 1: Simple API - create ZIP from file paths
|
|
91
|
+
// This is the easiest way to create a ZIP file
|
|
92
|
+
await zip.createZipFromFiles(testFiles, outputZip, options);
|
|
93
|
+
|
|
94
|
+
console.log(`ā
ZIP archive created successfully: ${outputZip}\n`);
|
|
95
|
+
|
|
96
|
+
// Load the ZIP to get entry details
|
|
97
|
+
await zip.loadZipFile(outputZip);
|
|
98
|
+
const entries = zip.getDirectory();
|
|
99
|
+
|
|
100
|
+
// Display summary of compressed files
|
|
101
|
+
console.log('Compression Summary:');
|
|
102
|
+
console.log('ā'.repeat(80));
|
|
103
|
+
console.log(
|
|
104
|
+
padRight('Filename', 30) +
|
|
105
|
+
padLeft('Original', 10) +
|
|
106
|
+
padLeft('Compressed', 12) +
|
|
107
|
+
padLeft('Ratio', 10) +
|
|
108
|
+
' ' +
|
|
109
|
+
padRight('Method', 10)
|
|
110
|
+
);
|
|
111
|
+
console.log('ā'.repeat(80));
|
|
112
|
+
|
|
113
|
+
let totalOriginal = 0;
|
|
114
|
+
let totalCompressed = 0;
|
|
115
|
+
|
|
116
|
+
entries.forEach((entry) => {
|
|
117
|
+
const filename = entry.filename || '(unnamed)';
|
|
118
|
+
const original = entry.uncompressedSize || 0;
|
|
119
|
+
const compressed = entry.compressedSize || 0;
|
|
120
|
+
const ratio = original > 0 ? ((1 - compressed / original) * 100).toFixed(1) : '0.0';
|
|
121
|
+
const method = entry.cmpMethodToString();
|
|
122
|
+
|
|
123
|
+
totalOriginal += original;
|
|
124
|
+
totalCompressed += compressed;
|
|
125
|
+
|
|
126
|
+
console.log(
|
|
127
|
+
padRight(filename.length > 28 ? filename.substring(0, 25) + '...' : filename, 30) +
|
|
128
|
+
padLeft(formatBytes(original), 10) +
|
|
129
|
+
padLeft(formatBytes(compressed), 12) +
|
|
130
|
+
padLeft(ratio + '%', 10) +
|
|
131
|
+
' ' +
|
|
132
|
+
padRight(method, 10)
|
|
133
|
+
);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
console.log('ā'.repeat(80));
|
|
137
|
+
const totalRatio = totalOriginal > 0 ? ((1 - totalCompressed / totalOriginal) * 100).toFixed(1) : '0.0';
|
|
138
|
+
console.log(
|
|
139
|
+
padRight('Total', 30) +
|
|
140
|
+
padLeft(formatBytes(totalOriginal), 10) +
|
|
141
|
+
padLeft(formatBytes(totalCompressed), 12) +
|
|
142
|
+
padLeft(totalRatio + '%', 10) +
|
|
143
|
+
' ' +
|
|
144
|
+
padRight('', 10)
|
|
145
|
+
);
|
|
146
|
+
console.log('ā'.repeat(80));
|
|
147
|
+
|
|
148
|
+
// Verify the ZIP was created
|
|
149
|
+
if (fs.existsSync(outputZip)) {
|
|
150
|
+
const zipStats = fs.statSync(outputZip);
|
|
151
|
+
console.log(`\nArchive file size: ${formatBytes(zipStats.size)}`);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
console.log('\nš” Tip: You can also use addFileToZip() for more control:');
|
|
155
|
+
console.log(' const zip = new ZipkitNode();');
|
|
156
|
+
console.log(' await zip.addFileToZip("file.txt", "file.txt", options);');
|
|
157
|
+
console.log(' // ... add more files ...');
|
|
158
|
+
console.log(' // Then manually write ZIP structure');
|
|
159
|
+
|
|
160
|
+
} catch (error) {
|
|
161
|
+
console.error('ā Error creating ZIP archive:');
|
|
162
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
163
|
+
process.exit(1);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Run the example
|
|
168
|
+
main().catch((error) => {
|
|
169
|
+
console.error('Fatal error:', error);
|
|
170
|
+
process.exit(1);
|
|
171
|
+
});
|
|
172
|
+
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Extract ZIP Example
|
|
5
|
+
*
|
|
6
|
+
* Demonstrates extracting files from a ZIP archive using ZipkitNode.
|
|
7
|
+
* This is a minimal example showing the basic extraction API.
|
|
8
|
+
*
|
|
9
|
+
* Note: CRC-32 and SHA-256 validation happens automatically during extraction.
|
|
10
|
+
* If extraction completes without errors, all files have been validated.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import ZipkitNode from '../src/node';
|
|
14
|
+
import * as fs from 'fs';
|
|
15
|
+
import * as path from 'path';
|
|
16
|
+
|
|
17
|
+
async function main() {
|
|
18
|
+
console.log('Extracting ZIP archive example...\n');
|
|
19
|
+
|
|
20
|
+
// Example: Use the ZIP file created by create-zip.ts
|
|
21
|
+
// You can also specify your own ZIP file path here
|
|
22
|
+
const archivePath = path.join(__dirname, 'output', 'example.zip');
|
|
23
|
+
const destination = path.join(__dirname, 'extracted');
|
|
24
|
+
|
|
25
|
+
// Check if ZIP file exists
|
|
26
|
+
if (!fs.existsSync(archivePath)) {
|
|
27
|
+
console.error(`ā ZIP file not found: ${archivePath}`);
|
|
28
|
+
console.error('š” Tip: Run create-zip.ts first to create a test ZIP file,');
|
|
29
|
+
console.error(' or modify archivePath to point to your own ZIP file.');
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
console.log(`Archive: ${archivePath}`);
|
|
34
|
+
console.log(`Destination: ${destination}\n`);
|
|
35
|
+
|
|
36
|
+
// Create ZipkitNode instance
|
|
37
|
+
const zip = new ZipkitNode();
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
// Load ZIP file - this reads the central directory and populates entries
|
|
41
|
+
console.log('Loading ZIP file...');
|
|
42
|
+
await zip.loadZipFile(archivePath);
|
|
43
|
+
|
|
44
|
+
// Get directory listing to show what will be extracted
|
|
45
|
+
const entries = zip.getDirectory();
|
|
46
|
+
console.log(`Found ${entries.length} file(s) in archive:\n`);
|
|
47
|
+
|
|
48
|
+
entries.forEach((entry, index) => {
|
|
49
|
+
const size = entry.uncompressedSize || 0;
|
|
50
|
+
const compressed = entry.compressedSize || 0;
|
|
51
|
+
const method = entry.cmpMethodToString();
|
|
52
|
+
console.log(` ${index + 1}. ${entry.filename}`);
|
|
53
|
+
console.log(` Size: ${size} bytes (compressed: ${compressed} bytes, ${method})`);
|
|
54
|
+
});
|
|
55
|
+
console.log();
|
|
56
|
+
|
|
57
|
+
// Option: Test mode - validate integrity without extracting files
|
|
58
|
+
// Uncomment the following lines to test without extracting:
|
|
59
|
+
/*
|
|
60
|
+
console.log('Testing ZIP integrity (without extracting)...');
|
|
61
|
+
for (const entry of entries) {
|
|
62
|
+
const testResult = await zip.testEntry(entry, {
|
|
63
|
+
skipHashCheck: false // Verify file integrity (CRC-32/SHA-256 checks)
|
|
64
|
+
});
|
|
65
|
+
console.log(`ā
${entry.filename}: Validated`);
|
|
66
|
+
if (testResult.verifiedHash) {
|
|
67
|
+
console.log(` Verified SHA-256: ${testResult.verifiedHash}`);
|
|
68
|
+
} else {
|
|
69
|
+
console.log(` Verified CRC-32: ${entry.crc?.toString(16).toUpperCase().padStart(8, '0')}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
console.log(`ā
All files validated successfully!`);
|
|
73
|
+
return;
|
|
74
|
+
*/
|
|
75
|
+
|
|
76
|
+
// Extract all files to destination directory
|
|
77
|
+
// CRC-32 and SHA-256 validation happens automatically during extraction
|
|
78
|
+
// If extraction completes without errors, all files have been validated
|
|
79
|
+
console.log('Extracting files...');
|
|
80
|
+
const result = await zip.extractZipFile(archivePath, destination, {
|
|
81
|
+
overwrite: true, // Overwrite existing files
|
|
82
|
+
preserveTimestamps: true, // Preserve file timestamps
|
|
83
|
+
skipHashCheck: false // Verify file integrity (CRC-32/SHA-256 checks)
|
|
84
|
+
// Note: skipHashCheck: false is the default - validation happens automatically
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
console.log(`ā
Extraction completed successfully!`);
|
|
88
|
+
console.log(` Files extracted: ${result.filesExtracted}`);
|
|
89
|
+
console.log(` Total bytes: ${result.bytesExtracted}`);
|
|
90
|
+
console.log(`\n All files validated (CRC-32/SHA-256 checks passed automatically)`);
|
|
91
|
+
|
|
92
|
+
console.log('\nš” Tip: You can also extract individual entries:');
|
|
93
|
+
console.log(' await zip.loadZipFile("archive.zip");');
|
|
94
|
+
console.log(' const entries = zip.getDirectory();');
|
|
95
|
+
console.log(' await zip.extractToFile(entries[0], "output.txt");');
|
|
96
|
+
console.log('\nš” Tip: Test integrity without extracting:');
|
|
97
|
+
console.log(' const result = await zip.testEntry(entry);');
|
|
98
|
+
console.log(' if (result.verifiedHash) {');
|
|
99
|
+
console.log(' console.log("SHA-256:", result.verifiedHash);');
|
|
100
|
+
console.log(' }');
|
|
101
|
+
|
|
102
|
+
} catch (error) {
|
|
103
|
+
console.error('ā Error extracting ZIP archive:');
|
|
104
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
105
|
+
if (error instanceof Error && error.stack) {
|
|
106
|
+
console.error('\nStack trace:');
|
|
107
|
+
console.error(error.stack);
|
|
108
|
+
}
|
|
109
|
+
process.exit(1);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Run the example
|
|
114
|
+
main().catch((error) => {
|
|
115
|
+
console.error('Fatal error:', error);
|
|
116
|
+
process.exit(1);
|
|
117
|
+
});
|
|
118
|
+
|