@aglyn/aglyn 1.0.0-beta.197 → 1.0.0-beta.199
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/package.json +11 -11
- package/src/lib/app-utils/docs-help.generated.d.ts +1 -1
- package/src/lib/app-utils/docs-help.generated.js +1 -0
- package/src/lib/app-utils/docs-help.generated.js.map +1 -1
- package/src/lib/app-utils/docs-index.generated.js +3 -3
- package/src/lib/app-utils/docs-index.generated.js.map +1 -1
- package/src/lib/app-utils/media-embedded-fields.d.ts +471 -0
- package/src/lib/app-utils/media-embedded-fields.js +619 -0
- package/src/lib/app-utils/media-embedded-fields.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/exif.d.ts +160 -0
- package/src/lib/app-utils/media-embedded-metadata/exif.js +1267 -0
- package/src/lib/app-utils/media-embedded-metadata/exif.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/gif.d.ts +44 -0
- package/src/lib/app-utils/media-embedded-metadata/gif.js +134 -0
- package/src/lib/app-utils/media-embedded-metadata/gif.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/heif.d.ts +23 -0
- package/src/lib/app-utils/media-embedded-metadata/heif.js +354 -0
- package/src/lib/app-utils/media-embedded-metadata/heif.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/icc.d.ts +22 -0
- package/src/lib/app-utils/media-embedded-metadata/icc.js +85 -0
- package/src/lib/app-utils/media-embedded-metadata/icc.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/image-blocks.d.ts +145 -0
- package/src/lib/app-utils/media-embedded-metadata/image-blocks.js +200 -0
- package/src/lib/app-utils/media-embedded-metadata/image-blocks.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/index.d.ts +93 -0
- package/src/lib/app-utils/media-embedded-metadata/index.js +744 -0
- package/src/lib/app-utils/media-embedded-metadata/index.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/iptc.d.ts +59 -0
- package/src/lib/app-utils/media-embedded-metadata/iptc.js +529 -0
- package/src/lib/app-utils/media-embedded-metadata/iptc.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/jpeg.d.ts +43 -0
- package/src/lib/app-utils/media-embedded-metadata/jpeg.js +456 -0
- package/src/lib/app-utils/media-embedded-metadata/jpeg.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/mp4.d.ts +37 -0
- package/src/lib/app-utils/media-embedded-metadata/mp4.js +621 -0
- package/src/lib/app-utils/media-embedded-metadata/mp4.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/ooxml.d.ts +131 -0
- package/src/lib/app-utils/media-embedded-metadata/ooxml.js +1058 -0
- package/src/lib/app-utils/media-embedded-metadata/ooxml.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/pdf-objects.d.ts +223 -0
- package/src/lib/app-utils/media-embedded-metadata/pdf-objects.js +936 -0
- package/src/lib/app-utils/media-embedded-metadata/pdf-objects.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/pdf.d.ts +82 -0
- package/src/lib/app-utils/media-embedded-metadata/pdf.js +1167 -0
- package/src/lib/app-utils/media-embedded-metadata/pdf.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/png.d.ts +41 -0
- package/src/lib/app-utils/media-embedded-metadata/png.js +512 -0
- package/src/lib/app-utils/media-embedded-metadata/png.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/svg.d.ts +30 -0
- package/src/lib/app-utils/media-embedded-metadata/svg.js +154 -0
- package/src/lib/app-utils/media-embedded-metadata/svg.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/tiff.d.ts +40 -0
- package/src/lib/app-utils/media-embedded-metadata/tiff.js +158 -0
- package/src/lib/app-utils/media-embedded-metadata/tiff.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/types.d.ts +60 -0
- package/src/lib/app-utils/media-embedded-metadata/types.js +32 -0
- package/src/lib/app-utils/media-embedded-metadata/types.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/webm.d.ts +26 -0
- package/src/lib/app-utils/media-embedded-metadata/webm.js +417 -0
- package/src/lib/app-utils/media-embedded-metadata/webm.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/webp.d.ts +37 -0
- package/src/lib/app-utils/media-embedded-metadata/webp.js +272 -0
- package/src/lib/app-utils/media-embedded-metadata/webp.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/xml.d.ts +231 -0
- package/src/lib/app-utils/media-embedded-metadata/xml.js +598 -0
- package/src/lib/app-utils/media-embedded-metadata/xml.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/xmp.d.ts +100 -0
- package/src/lib/app-utils/media-embedded-metadata/xmp.js +1475 -0
- package/src/lib/app-utils/media-embedded-metadata/xmp.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/zip.d.ts +93 -0
- package/src/lib/app-utils/media-embedded-metadata/zip.js +531 -0
- package/src/lib/app-utils/media-embedded-metadata/zip.js.map +1 -0
- package/src/lib/app-utils/name-search.d.ts +12 -0
- package/src/lib/app-utils/name-search.js +11 -0
- package/src/lib/app-utils/name-search.js.map +1 -1
- package/src/lib/foundation/definitions/platform.types.d.ts +11 -0
- package/src/lib/foundation/definitions/platform.types.js.map +1 -1
- package/src/server.d.ts +1 -0
- package/src/server.js +7 -0
- package/src/server.js.map +1 -1
|
@@ -0,0 +1,531 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/ /**
|
|
17
|
+
* A minimal ZIP reader and entry-replacing rewriter (AGL-3331) — enough to
|
|
18
|
+
* read an Office package's property parts and write them back without
|
|
19
|
+
* touching any other part of the package.
|
|
20
|
+
*
|
|
21
|
+
* Section numbers cite PKWARE's APPNOTE.TXT, version 6.3.10.
|
|
22
|
+
*
|
|
23
|
+
* ## What the rewriter promises
|
|
24
|
+
*
|
|
25
|
+
* Only the entries it is handed new content for change. Every other entry
|
|
26
|
+
* is copied through byte for byte — local header, data and data descriptor,
|
|
27
|
+
* in the original order, together with any bytes that sat between it and
|
|
28
|
+
* the next entry — so a Word file's `document.xml` and every embedded image
|
|
29
|
+
* leave exactly as they arrived. A replaced entry gets a fresh local header
|
|
30
|
+
* (deflate, real CRC-32 and sizes, no data descriptor). The central
|
|
31
|
+
* directory is rebuilt from the original records, changing only what the
|
|
32
|
+
* move forced: every entry's local-header offset, and the method, flags,
|
|
33
|
+
* CRC and sizes of a replaced one. The archive comment survives.
|
|
34
|
+
*
|
|
35
|
+
* ## What it refuses
|
|
36
|
+
*
|
|
37
|
+
* A ZIP64 archive, an encrypted or ZIP64 target entry, a target named twice,
|
|
38
|
+
* and a layout whose entries overlap — each an {@link EmbeddedWriteError},
|
|
39
|
+
* never a guess that could produce a corrupt file.
|
|
40
|
+
*/ import { deflateRawSync, inflateRawSync } from "zlib";
|
|
41
|
+
import { EmbeddedWriteError } from "./types.js";
|
|
42
|
+
/** 4.3.7 local file header, 4.3.12 central directory header, 4.3.16 EOCD. */ const SIG_LOCAL = 0x04034b50;
|
|
43
|
+
const SIG_CENTRAL = 0x02014b50;
|
|
44
|
+
const SIG_EOCD = 0x06054b50;
|
|
45
|
+
/** 4.3.15 ZIP64 end of central directory locator, 4.3.14 its record. */ const SIG_ZIP64_LOCATOR = 0x07064b50;
|
|
46
|
+
const SIG_ZIP64_EOCD = 0x06064b50;
|
|
47
|
+
const LOCAL_HEADER_SIZE = 30;
|
|
48
|
+
const CENTRAL_HEADER_SIZE = 46;
|
|
49
|
+
const EOCD_SIZE = 22;
|
|
50
|
+
const ZIP64_LOCATOR_SIZE = 20;
|
|
51
|
+
const ZIP64_EOCD_MIN_SIZE = 56;
|
|
52
|
+
/** The EOCD comment length is a 16-bit field (4.3.16). */ const MAX_COMMENT_LENGTH = 0xffff;
|
|
53
|
+
/** 4.4.4 general purpose bit flags. */ const FLAG_ENCRYPTED = 0x0001;
|
|
54
|
+
const FLAG_UTF8 = 0x0800;
|
|
55
|
+
/** 4.4.5 compression methods. */ const METHOD_STORED = 0;
|
|
56
|
+
const METHOD_DEFLATE = 8;
|
|
57
|
+
/** 4.5.2 extra field header id of the ZIP64 extended information. */ const EXTRA_ZIP64 = 0x0001;
|
|
58
|
+
const U16_MAX = 0xffff;
|
|
59
|
+
const U32_MAX = 0xffffffff;
|
|
60
|
+
/** The default cap on one entry's inflated size. */ export const ZIP_ENTRY_READ_MAX_BYTES = 16 * 1024 * 1024;
|
|
61
|
+
const CRC_TABLE = (()=>{
|
|
62
|
+
const table = new Uint32Array(256);
|
|
63
|
+
for(let n = 0; n < 256; n++){
|
|
64
|
+
let c = n;
|
|
65
|
+
for(let k = 0; k < 8; k++)c = c & 1 ? 0xedb88320 ^ c >>> 1 : c >>> 1;
|
|
66
|
+
table[n] = c >>> 0;
|
|
67
|
+
}
|
|
68
|
+
return table;
|
|
69
|
+
})();
|
|
70
|
+
/**
|
|
71
|
+
* CRC-32 as ZIP uses it (4.4.7): the reflected IEEE 802.3 polynomial
|
|
72
|
+
* `0xEDB88320`, initial value and final XOR `0xFFFFFFFF`. Pass a previous
|
|
73
|
+
* result as `seed` to continue a running checksum.
|
|
74
|
+
*/ export function crc32(bytes, seed = 0) {
|
|
75
|
+
var _CRC_TABLE_;
|
|
76
|
+
let c = (seed ^ U32_MAX) >>> 0;
|
|
77
|
+
for (const byte of bytes)c = ((_CRC_TABLE_ = CRC_TABLE[(c ^ byte) & 0xff]) != null ? _CRC_TABLE_ : 0) ^ c >>> 8;
|
|
78
|
+
return (c ^ U32_MAX) >>> 0;
|
|
79
|
+
}
|
|
80
|
+
const utf8 = new TextDecoder('utf-8');
|
|
81
|
+
const utf8Encoder = new TextEncoder();
|
|
82
|
+
/** A 64-bit little-endian integer, or null past `Number.MAX_SAFE_INTEGER`. */ function readU64(view, at) {
|
|
83
|
+
const low = view.getUint32(at, true);
|
|
84
|
+
const high = view.getUint32(at + 4, true);
|
|
85
|
+
const value = high * 0x100000000 + low;
|
|
86
|
+
return Number.isSafeInteger(value) ? value : null;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Find the end-of-central-directory record (4.3.16).
|
|
90
|
+
*
|
|
91
|
+
* It is the last 22 bytes of the archive plus a comment of up to 64 KB, so
|
|
92
|
+
* only that tail is searched, backwards. A record whose comment length ends
|
|
93
|
+
* exactly at the end of the file wins; failing that, the last one whose
|
|
94
|
+
* comment fits, which tolerates junk appended after the archive.
|
|
95
|
+
*/ function findEndOfCentralDirectory(bytes, view) {
|
|
96
|
+
const last = bytes.length - EOCD_SIZE;
|
|
97
|
+
const floor = Math.max(0, last - MAX_COMMENT_LENGTH);
|
|
98
|
+
let loose = -1;
|
|
99
|
+
for(let at = last; at >= floor; at--){
|
|
100
|
+
if (view.getUint32(at, true) !== SIG_EOCD) continue;
|
|
101
|
+
const end = at + EOCD_SIZE + view.getUint16(at + 20, true);
|
|
102
|
+
if (end === bytes.length) return at;
|
|
103
|
+
if (end < bytes.length && loose < 0) loose = at;
|
|
104
|
+
}
|
|
105
|
+
return loose;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Where a central record's ZIP64 extended-information values sit (4.5.3).
|
|
109
|
+
* Each value is present only when its 32-bit field is saturated, in the
|
|
110
|
+
* fixed order uncompressed size, compressed size, local header offset.
|
|
111
|
+
* Returns offsets within `view`, or null for a malformed field that was
|
|
112
|
+
* needed.
|
|
113
|
+
*/ function zip64Fields(view, extraStart, extraEnd, saturated) {
|
|
114
|
+
// A sloppy extra field is harmless while nothing needs to be read from it.
|
|
115
|
+
const needed = saturated.uncompressed || saturated.compressed || saturated.offset;
|
|
116
|
+
const malformed = needed ? null : {
|
|
117
|
+
present: false
|
|
118
|
+
};
|
|
119
|
+
let at = extraStart;
|
|
120
|
+
// Each extra block is a 2-byte id, a 2-byte length and its data (4.5.1).
|
|
121
|
+
for(let guard = 0; at + 4 <= extraEnd && guard < 1024; guard++){
|
|
122
|
+
const id = view.getUint16(at, true);
|
|
123
|
+
const length = view.getUint16(at + 2, true);
|
|
124
|
+
const dataStart = at + 4;
|
|
125
|
+
const dataEnd = dataStart + length;
|
|
126
|
+
if (dataEnd > extraEnd) return malformed;
|
|
127
|
+
if (id === EXTRA_ZIP64) {
|
|
128
|
+
const out = {
|
|
129
|
+
present: true
|
|
130
|
+
};
|
|
131
|
+
let cursor = dataStart;
|
|
132
|
+
for (const field of [
|
|
133
|
+
'uncompressed',
|
|
134
|
+
'compressed',
|
|
135
|
+
'offset'
|
|
136
|
+
]){
|
|
137
|
+
if (!saturated[field]) continue;
|
|
138
|
+
if (cursor + 8 > dataEnd) return null;
|
|
139
|
+
out[field] = cursor;
|
|
140
|
+
cursor += 8;
|
|
141
|
+
}
|
|
142
|
+
return out;
|
|
143
|
+
}
|
|
144
|
+
at = dataEnd;
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
present: false
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Parse an archive's central directory.
|
|
152
|
+
*
|
|
153
|
+
* Returns null for anything that is not a single-disk ZIP whose central
|
|
154
|
+
* directory reads cleanly from end to end: a partial entry list is worse
|
|
155
|
+
* than none here, because a rewrite built from it would silently drop
|
|
156
|
+
* whatever was not listed.
|
|
157
|
+
*/ export function readZip(bytes) {
|
|
158
|
+
if (bytes.length < EOCD_SIZE) return null;
|
|
159
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
160
|
+
const eocd = findEndOfCentralDirectory(bytes, view);
|
|
161
|
+
if (eocd < 0) return null;
|
|
162
|
+
let disk = view.getUint16(eocd + 4, true);
|
|
163
|
+
let centralDisk = view.getUint16(eocd + 6, true);
|
|
164
|
+
let entriesOnDisk = view.getUint16(eocd + 8, true);
|
|
165
|
+
let totalEntries = view.getUint16(eocd + 10, true);
|
|
166
|
+
let centralSize = view.getUint32(eocd + 12, true);
|
|
167
|
+
let centralOffset = view.getUint32(eocd + 16, true);
|
|
168
|
+
const commentLength = view.getUint16(eocd + 20, true);
|
|
169
|
+
const comment = bytes.subarray(eocd + EOCD_SIZE, eocd + EOCD_SIZE + commentLength);
|
|
170
|
+
let centralLimit = eocd;
|
|
171
|
+
let zip64 = false;
|
|
172
|
+
const locator = eocd - ZIP64_LOCATOR_SIZE;
|
|
173
|
+
if (locator >= 0 && view.getUint32(locator, true) === SIG_ZIP64_LOCATOR) {
|
|
174
|
+
const record = readU64(view, locator + 8);
|
|
175
|
+
if (record === null || record + ZIP64_EOCD_MIN_SIZE > locator) return null;
|
|
176
|
+
if (view.getUint32(record, true) !== SIG_ZIP64_EOCD) return null;
|
|
177
|
+
const onDisk = readU64(view, record + 24);
|
|
178
|
+
const total = readU64(view, record + 32);
|
|
179
|
+
const size = readU64(view, record + 40);
|
|
180
|
+
const offset = readU64(view, record + 48);
|
|
181
|
+
if (onDisk === null || total === null || size === null || offset === null) return null;
|
|
182
|
+
disk = view.getUint32(record + 16, true);
|
|
183
|
+
centralDisk = view.getUint32(record + 20, true);
|
|
184
|
+
entriesOnDisk = onDisk;
|
|
185
|
+
totalEntries = total;
|
|
186
|
+
centralSize = size;
|
|
187
|
+
centralOffset = offset;
|
|
188
|
+
centralLimit = record;
|
|
189
|
+
zip64 = true;
|
|
190
|
+
}
|
|
191
|
+
// Spanned and split archives (8.0) are not something an upload can be.
|
|
192
|
+
if (disk !== 0 || centralDisk !== 0 || entriesOnDisk !== totalEntries) return null;
|
|
193
|
+
const centralEnd = centralOffset + centralSize;
|
|
194
|
+
if (centralEnd > centralLimit) return null;
|
|
195
|
+
// Every record is at least 46 bytes, which bounds the loop below.
|
|
196
|
+
if (totalEntries * CENTRAL_HEADER_SIZE > centralSize) return null;
|
|
197
|
+
const entries = [];
|
|
198
|
+
let at = centralOffset;
|
|
199
|
+
for(let index = 0; index < totalEntries; index++){
|
|
200
|
+
if (at + CENTRAL_HEADER_SIZE > centralEnd) return null;
|
|
201
|
+
if (view.getUint32(at, true) !== SIG_CENTRAL) return null;
|
|
202
|
+
const flags = view.getUint16(at + 8, true);
|
|
203
|
+
const method = view.getUint16(at + 10, true);
|
|
204
|
+
const crc = view.getUint32(at + 16, true);
|
|
205
|
+
let compressedSize = view.getUint32(at + 20, true);
|
|
206
|
+
let uncompressedSize = view.getUint32(at + 24, true);
|
|
207
|
+
const nameLength = view.getUint16(at + 28, true);
|
|
208
|
+
const extraLength = view.getUint16(at + 30, true);
|
|
209
|
+
const commentLen = view.getUint16(at + 32, true);
|
|
210
|
+
let localHeaderOffset = view.getUint32(at + 42, true);
|
|
211
|
+
const nameStart = at + CENTRAL_HEADER_SIZE;
|
|
212
|
+
const extraStart = nameStart + nameLength;
|
|
213
|
+
const extraEnd = extraStart + extraLength;
|
|
214
|
+
const recordEnd = extraEnd + commentLen;
|
|
215
|
+
if (recordEnd > centralEnd) return null;
|
|
216
|
+
const zip = zip64Fields(view, extraStart, extraEnd, {
|
|
217
|
+
uncompressed: uncompressedSize === U32_MAX,
|
|
218
|
+
compressed: compressedSize === U32_MAX,
|
|
219
|
+
offset: localHeaderOffset === U32_MAX
|
|
220
|
+
});
|
|
221
|
+
if (!zip) return null;
|
|
222
|
+
if (zip.uncompressed !== undefined) {
|
|
223
|
+
const value = readU64(view, zip.uncompressed);
|
|
224
|
+
if (value === null) return null;
|
|
225
|
+
uncompressedSize = value;
|
|
226
|
+
}
|
|
227
|
+
if (zip.compressed !== undefined) {
|
|
228
|
+
const value = readU64(view, zip.compressed);
|
|
229
|
+
if (value === null) return null;
|
|
230
|
+
compressedSize = value;
|
|
231
|
+
}
|
|
232
|
+
if (zip.offset !== undefined) {
|
|
233
|
+
const value = readU64(view, zip.offset);
|
|
234
|
+
if (value === null) return null;
|
|
235
|
+
localHeaderOffset = value;
|
|
236
|
+
}
|
|
237
|
+
entries.push({
|
|
238
|
+
name: utf8.decode(bytes.subarray(nameStart, extraStart)),
|
|
239
|
+
flags,
|
|
240
|
+
method,
|
|
241
|
+
crc32: crc,
|
|
242
|
+
compressedSize,
|
|
243
|
+
uncompressedSize,
|
|
244
|
+
localHeaderOffset,
|
|
245
|
+
dataOffset: localDataOffset(bytes, view, localHeaderOffset, compressedSize),
|
|
246
|
+
encrypted: (flags & FLAG_ENCRYPTED) !== 0,
|
|
247
|
+
zip64: zip.present,
|
|
248
|
+
centralRecord: bytes.subarray(at, recordEnd)
|
|
249
|
+
});
|
|
250
|
+
at = recordEnd;
|
|
251
|
+
}
|
|
252
|
+
return {
|
|
253
|
+
bytes,
|
|
254
|
+
entries,
|
|
255
|
+
centralDirectoryOffset: centralOffset,
|
|
256
|
+
centralDirectorySize: centralSize,
|
|
257
|
+
endOfCentralDirectoryOffset: eocd,
|
|
258
|
+
comment,
|
|
259
|
+
zip64
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
/** Start of an entry's data from its local header (4.3.7), or -1. */ function localDataOffset(bytes, view, offset, compressedSize) {
|
|
263
|
+
if (offset + LOCAL_HEADER_SIZE > bytes.length) return -1;
|
|
264
|
+
if (view.getUint32(offset, true) !== SIG_LOCAL) return -1;
|
|
265
|
+
const start = offset + LOCAL_HEADER_SIZE + view.getUint16(offset + 26, true) + view.getUint16(offset + 28, true);
|
|
266
|
+
return start + compressedSize <= bytes.length ? start : -1;
|
|
267
|
+
}
|
|
268
|
+
/** The first entry of that exact name. */ export function findZipEntry(archive, name) {
|
|
269
|
+
return archive.entries.find((entry)=>entry.name === name);
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* An entry's content, inflated and CRC-checked.
|
|
273
|
+
*
|
|
274
|
+
* Null for an encrypted entry, a method other than stored or deflate, a
|
|
275
|
+
* declared size over `maxBytes`, output that disagrees with the declared
|
|
276
|
+
* size, or a CRC mismatch. `maxOutputLength` stops a deflate bomb at the
|
|
277
|
+
* declared size, whatever the stream would expand to.
|
|
278
|
+
*/ export function readZipEntry(archive, entry, maxBytes = ZIP_ENTRY_READ_MAX_BYTES) {
|
|
279
|
+
if (entry.encrypted || entry.dataOffset < 0) return null;
|
|
280
|
+
if (entry.uncompressedSize > maxBytes) return null;
|
|
281
|
+
const data = archive.bytes.subarray(entry.dataOffset, entry.dataOffset + entry.compressedSize);
|
|
282
|
+
let content;
|
|
283
|
+
if (entry.method === METHOD_STORED) {
|
|
284
|
+
if (entry.compressedSize !== entry.uncompressedSize) return null;
|
|
285
|
+
content = data;
|
|
286
|
+
} else if (entry.method === METHOD_DEFLATE) {
|
|
287
|
+
try {
|
|
288
|
+
const out = inflateRawSync(data, {
|
|
289
|
+
maxOutputLength: Math.max(1, entry.uncompressedSize)
|
|
290
|
+
});
|
|
291
|
+
content = new Uint8Array(out.buffer, out.byteOffset, out.byteLength);
|
|
292
|
+
} catch (unused) {
|
|
293
|
+
return null;
|
|
294
|
+
}
|
|
295
|
+
if (content.length !== entry.uncompressedSize) return null;
|
|
296
|
+
} else {
|
|
297
|
+
return null;
|
|
298
|
+
}
|
|
299
|
+
return crc32(content) === entry.crc32 ? content : null;
|
|
300
|
+
}
|
|
301
|
+
/** MS-DOS date and time (4.4.6), from the UTC fields; floors at 1980. */ function dosDateTime(date) {
|
|
302
|
+
if (date.getUTCFullYear() < 1980 || Number.isNaN(date.getTime())) {
|
|
303
|
+
return {
|
|
304
|
+
time: 0,
|
|
305
|
+
date: 1 << 5 | 1
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
return {
|
|
309
|
+
time: date.getUTCHours() << 11 | date.getUTCMinutes() << 5 | date.getUTCSeconds() >> 1,
|
|
310
|
+
date: Math.min(127, date.getUTCFullYear() - 1980) << 9 | date.getUTCMonth() + 1 << 5 | date.getUTCDate()
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
/** A fresh local header plus deflated data (4.3.7) — never a descriptor. */ function freshLocalRecord(nameBytes, content, flags, time, date) {
|
|
314
|
+
const deflated = deflateRawSync(content);
|
|
315
|
+
const crc = crc32(content);
|
|
316
|
+
const record = new Uint8Array(LOCAL_HEADER_SIZE + nameBytes.length + deflated.length);
|
|
317
|
+
const view = new DataView(record.buffer);
|
|
318
|
+
view.setUint32(0, SIG_LOCAL, true);
|
|
319
|
+
view.setUint16(4, 20, true); // version needed: 2.0, for deflate (4.4.3.2)
|
|
320
|
+
view.setUint16(6, flags, true);
|
|
321
|
+
view.setUint16(8, METHOD_DEFLATE, true);
|
|
322
|
+
view.setUint16(10, time, true);
|
|
323
|
+
view.setUint16(12, date, true);
|
|
324
|
+
view.setUint32(14, crc, true);
|
|
325
|
+
view.setUint32(18, deflated.length, true);
|
|
326
|
+
view.setUint32(22, content.length, true);
|
|
327
|
+
view.setUint16(26, nameBytes.length, true);
|
|
328
|
+
view.setUint16(28, 0, true);
|
|
329
|
+
record.set(nameBytes, LOCAL_HEADER_SIZE);
|
|
330
|
+
record.set(deflated, LOCAL_HEADER_SIZE + nameBytes.length);
|
|
331
|
+
return {
|
|
332
|
+
record,
|
|
333
|
+
crc,
|
|
334
|
+
compressedSize: deflated.length
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Replace (or add) entries, copying everything else through verbatim.
|
|
339
|
+
*
|
|
340
|
+
* `changes` maps an entry name to its new, uncompressed content. A name the
|
|
341
|
+
* archive already holds is replaced where it stands; a name it does not is
|
|
342
|
+
* appended as a new entry after the last one, dated `options.now` (or
|
|
343
|
+
* 1980-01-01, which is what Office stamps every part with).
|
|
344
|
+
*/ export function rewriteZip(archive, changes, options = {}) {
|
|
345
|
+
var _ref, _options_now;
|
|
346
|
+
var _ordered_;
|
|
347
|
+
const { bytes, entries } = archive;
|
|
348
|
+
if (archive.zip64) {
|
|
349
|
+
throw new EmbeddedWriteError('This file is too large a ZIP archive (ZIP64) to be edited in place.');
|
|
350
|
+
}
|
|
351
|
+
for (const name of changes.keys()){
|
|
352
|
+
const matches = entries.filter((entry)=>entry.name === name);
|
|
353
|
+
if (matches.length > 1) {
|
|
354
|
+
throw new EmbeddedWriteError(`This file holds "${name}" more than once, so it cannot be edited safely.`);
|
|
355
|
+
}
|
|
356
|
+
const target = matches[0];
|
|
357
|
+
if (target == null ? void 0 : target.encrypted) {
|
|
358
|
+
throw new EmbeddedWriteError('This file is encrypted, so its details can only be read.');
|
|
359
|
+
}
|
|
360
|
+
if (target == null ? void 0 : target.zip64) {
|
|
361
|
+
throw new EmbeddedWriteError('This file stores its details in a ZIP64 entry, which cannot be edited in place.');
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
// Each entry owns the bytes from its local header to the next entry's —
|
|
365
|
+
// or to the central directory — so a data descriptor, and any padding a
|
|
366
|
+
// writer left, travels with it. That only works if entries do not
|
|
367
|
+
// overlap, which a crafted archive may not honor.
|
|
368
|
+
const ordered = [
|
|
369
|
+
...entries
|
|
370
|
+
].sort((a, b)=>a.localHeaderOffset - b.localHeaderOffset);
|
|
371
|
+
const spanEnd = new Map();
|
|
372
|
+
for(let index = 0; index < ordered.length; index++){
|
|
373
|
+
var _ref1;
|
|
374
|
+
var _ordered_1;
|
|
375
|
+
const entry = ordered[index];
|
|
376
|
+
if (!entry) continue;
|
|
377
|
+
const next = (_ref1 = (_ordered_1 = ordered[index + 1]) == null ? void 0 : _ordered_1.localHeaderOffset) != null ? _ref1 : archive.centralDirectoryOffset;
|
|
378
|
+
if (entry.dataOffset < 0 || entry.dataOffset + entry.compressedSize > next || entry.localHeaderOffset >= next) {
|
|
379
|
+
throw new EmbeddedWriteError('The parts of this file overlap or are damaged, so it cannot be edited safely.');
|
|
380
|
+
}
|
|
381
|
+
spanEnd.set(entry, next);
|
|
382
|
+
}
|
|
383
|
+
const chunks = [];
|
|
384
|
+
let position = 0;
|
|
385
|
+
const push = (chunk)=>{
|
|
386
|
+
chunks.push(chunk);
|
|
387
|
+
position += chunk.length;
|
|
388
|
+
};
|
|
389
|
+
const firstOffset = (_ref = (_ordered_ = ordered[0]) == null ? void 0 : _ordered_.localHeaderOffset) != null ? _ref : archive.centralDirectoryOffset;
|
|
390
|
+
// Anything ahead of the first entry — a self-extractor stub — stays put,
|
|
391
|
+
// and so do the offsets that count from the start of the file.
|
|
392
|
+
push(bytes.subarray(0, firstOffset));
|
|
393
|
+
const written = new Map();
|
|
394
|
+
const moved = new Map();
|
|
395
|
+
for (const entry of ordered){
|
|
396
|
+
var _spanEnd_get;
|
|
397
|
+
const content = changes.get(entry.name);
|
|
398
|
+
const end = (_spanEnd_get = spanEnd.get(entry)) != null ? _spanEnd_get : entry.localHeaderOffset;
|
|
399
|
+
if (!content) {
|
|
400
|
+
moved.set(entry, position);
|
|
401
|
+
push(bytes.subarray(entry.localHeaderOffset, end));
|
|
402
|
+
continue;
|
|
403
|
+
}
|
|
404
|
+
const record = entry.centralRecord;
|
|
405
|
+
const recordView = new DataView(record.buffer, record.byteOffset, record.byteLength);
|
|
406
|
+
const nameBytes = record.subarray(CENTRAL_HEADER_SIZE, CENTRAL_HEADER_SIZE + recordView.getUint16(28, true));
|
|
407
|
+
// Bit 11 (UTF-8 names) is kept; the descriptor bit 3, the deflate
|
|
408
|
+
// option bits 1-2 and anything else describing the OLD data are not.
|
|
409
|
+
const flags = entry.flags & FLAG_UTF8;
|
|
410
|
+
const fresh = freshLocalRecord(nameBytes, content, flags, recordView.getUint16(12, true), recordView.getUint16(14, true));
|
|
411
|
+
written.set(entry, {
|
|
412
|
+
offset: position,
|
|
413
|
+
crc: fresh.crc,
|
|
414
|
+
compressedSize: fresh.compressedSize,
|
|
415
|
+
uncompressedSize: content.length,
|
|
416
|
+
flags
|
|
417
|
+
});
|
|
418
|
+
push(fresh.record);
|
|
419
|
+
}
|
|
420
|
+
const known = new Set(entries.map((entry)=>entry.name));
|
|
421
|
+
const stamp = dosDateTime((_options_now = options.now) != null ? _options_now : new Date(Date.UTC(1980, 0, 1)));
|
|
422
|
+
const added = [];
|
|
423
|
+
for (const [name, content] of changes){
|
|
424
|
+
if (known.has(name)) continue;
|
|
425
|
+
const nameBytes = utf8Encoder.encode(name);
|
|
426
|
+
if (nameBytes.length > U16_MAX) {
|
|
427
|
+
throw new EmbeddedWriteError('A part name in this file is too long.');
|
|
428
|
+
}
|
|
429
|
+
// eslint-disable-next-line no-control-regex
|
|
430
|
+
const flags = /^[\x00-\x7f]*$/.test(name) ? 0 : FLAG_UTF8;
|
|
431
|
+
const fresh = freshLocalRecord(nameBytes, content, flags, stamp.time, stamp.date);
|
|
432
|
+
added.push({
|
|
433
|
+
nameBytes,
|
|
434
|
+
written: {
|
|
435
|
+
offset: position,
|
|
436
|
+
crc: fresh.crc,
|
|
437
|
+
compressedSize: fresh.compressedSize,
|
|
438
|
+
uncompressedSize: content.length,
|
|
439
|
+
flags
|
|
440
|
+
}
|
|
441
|
+
});
|
|
442
|
+
push(fresh.record);
|
|
443
|
+
}
|
|
444
|
+
const centralOffset = position;
|
|
445
|
+
for (const entry of entries){
|
|
446
|
+
var _ref2;
|
|
447
|
+
const record = entry.centralRecord.slice();
|
|
448
|
+
const recordView = new DataView(record.buffer);
|
|
449
|
+
const replaced = written.get(entry);
|
|
450
|
+
const offset = (_ref2 = replaced == null ? void 0 : replaced.offset) != null ? _ref2 : moved.get(entry);
|
|
451
|
+
if (offset === undefined || offset > U32_MAX - 1) {
|
|
452
|
+
throw new EmbeddedWriteError('This file is too large to be edited in place.');
|
|
453
|
+
}
|
|
454
|
+
if (recordView.getUint32(42, true) === U32_MAX) {
|
|
455
|
+
// The offset lives in the ZIP64 extra field instead (4.5.3).
|
|
456
|
+
const extraStart = CENTRAL_HEADER_SIZE + recordView.getUint16(28, true);
|
|
457
|
+
const zip = zip64Fields(recordView, extraStart, extraStart + recordView.getUint16(30, true), {
|
|
458
|
+
uncompressed: recordView.getUint32(24, true) === U32_MAX,
|
|
459
|
+
compressed: recordView.getUint32(20, true) === U32_MAX,
|
|
460
|
+
offset: true
|
|
461
|
+
});
|
|
462
|
+
if (!zip || zip.offset === undefined) {
|
|
463
|
+
throw new EmbeddedWriteError('This file is damaged and cannot be edited safely.');
|
|
464
|
+
}
|
|
465
|
+
recordView.setUint32(zip.offset, offset, true);
|
|
466
|
+
recordView.setUint32(zip.offset + 4, 0, true);
|
|
467
|
+
} else {
|
|
468
|
+
recordView.setUint32(42, offset, true);
|
|
469
|
+
}
|
|
470
|
+
if (replaced) {
|
|
471
|
+
recordView.setUint16(6, Math.max(20, recordView.getUint16(6, true)), true);
|
|
472
|
+
recordView.setUint16(8, replaced.flags, true);
|
|
473
|
+
recordView.setUint16(10, METHOD_DEFLATE, true);
|
|
474
|
+
recordView.setUint32(16, replaced.crc, true);
|
|
475
|
+
recordView.setUint32(20, replaced.compressedSize, true);
|
|
476
|
+
recordView.setUint32(24, replaced.uncompressedSize, true);
|
|
477
|
+
}
|
|
478
|
+
push(record);
|
|
479
|
+
}
|
|
480
|
+
for (const { nameBytes, written: entry } of added){
|
|
481
|
+
const record = new Uint8Array(CENTRAL_HEADER_SIZE + nameBytes.length);
|
|
482
|
+
const recordView = new DataView(record.buffer);
|
|
483
|
+
recordView.setUint32(0, SIG_CENTRAL, true);
|
|
484
|
+
recordView.setUint16(4, 20, true); // made by: MS-DOS, 2.0 (4.4.2)
|
|
485
|
+
recordView.setUint16(6, 20, true);
|
|
486
|
+
recordView.setUint16(8, entry.flags, true);
|
|
487
|
+
recordView.setUint16(10, METHOD_DEFLATE, true);
|
|
488
|
+
recordView.setUint16(12, stamp.time, true);
|
|
489
|
+
recordView.setUint16(14, stamp.date, true);
|
|
490
|
+
recordView.setUint32(16, entry.crc, true);
|
|
491
|
+
recordView.setUint32(20, entry.compressedSize, true);
|
|
492
|
+
recordView.setUint32(24, entry.uncompressedSize, true);
|
|
493
|
+
recordView.setUint16(28, nameBytes.length, true);
|
|
494
|
+
recordView.setUint32(42, entry.offset, true);
|
|
495
|
+
record.set(nameBytes, CENTRAL_HEADER_SIZE);
|
|
496
|
+
push(record);
|
|
497
|
+
}
|
|
498
|
+
const centralSize = position - centralOffset;
|
|
499
|
+
const count = entries.length + added.length;
|
|
500
|
+
if (count > U16_MAX || position > U32_MAX - 1) {
|
|
501
|
+
throw new EmbeddedWriteError('This file is too large to be edited in place.');
|
|
502
|
+
}
|
|
503
|
+
// Whatever sat between the directory and its end record (nothing, in a
|
|
504
|
+
// non-ZIP64 archive written by anyone sane) is carried through as found.
|
|
505
|
+
push(bytes.subarray(archive.centralDirectoryOffset + archive.centralDirectorySize, archive.endOfCentralDirectoryOffset));
|
|
506
|
+
const eocd = new Uint8Array(EOCD_SIZE + archive.comment.length);
|
|
507
|
+
const eocdView = new DataView(eocd.buffer);
|
|
508
|
+
eocdView.setUint32(0, SIG_EOCD, true);
|
|
509
|
+
eocdView.setUint16(8, count, true);
|
|
510
|
+
eocdView.setUint16(10, count, true);
|
|
511
|
+
eocdView.setUint32(12, centralSize, true);
|
|
512
|
+
eocdView.setUint32(16, centralOffset, true);
|
|
513
|
+
eocdView.setUint16(20, archive.comment.length, true);
|
|
514
|
+
eocd.set(archive.comment, EOCD_SIZE);
|
|
515
|
+
push(eocd);
|
|
516
|
+
const out = new Uint8Array(position);
|
|
517
|
+
let at = 0;
|
|
518
|
+
for (const chunk of chunks){
|
|
519
|
+
out.set(chunk, at);
|
|
520
|
+
at += chunk.length;
|
|
521
|
+
}
|
|
522
|
+
// The rewritten archive must read back, entry for entry, or it is not
|
|
523
|
+
// returned at all.
|
|
524
|
+
const check = readZip(out);
|
|
525
|
+
if (!check || check.entries.length !== count) {
|
|
526
|
+
throw new EmbeddedWriteError('The edited file did not verify, so it was not saved.');
|
|
527
|
+
}
|
|
528
|
+
return out;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
//# sourceMappingURL=zip.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/aglyn/src/lib/app-utils/media-embedded-metadata/zip.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * A minimal ZIP reader and entry-replacing rewriter (AGL-3331) — enough to\n * read an Office package's property parts and write them back without\n * touching any other part of the package.\n *\n * Section numbers cite PKWARE's APPNOTE.TXT, version 6.3.10.\n *\n * ## What the rewriter promises\n *\n * Only the entries it is handed new content for change. Every other entry\n * is copied through byte for byte — local header, data and data descriptor,\n * in the original order, together with any bytes that sat between it and\n * the next entry — so a Word file's `document.xml` and every embedded image\n * leave exactly as they arrived. A replaced entry gets a fresh local header\n * (deflate, real CRC-32 and sizes, no data descriptor). The central\n * directory is rebuilt from the original records, changing only what the\n * move forced: every entry's local-header offset, and the method, flags,\n * CRC and sizes of a replaced one. The archive comment survives.\n *\n * ## What it refuses\n *\n * A ZIP64 archive, an encrypted or ZIP64 target entry, a target named twice,\n * and a layout whose entries overlap — each an {@link EmbeddedWriteError},\n * never a guess that could produce a corrupt file.\n */\n\nimport { deflateRawSync, inflateRawSync } from 'zlib'\n\nimport { EmbeddedWriteError } from './types'\n\n/** 4.3.7 local file header, 4.3.12 central directory header, 4.3.16 EOCD. */\nconst SIG_LOCAL = 0x04034b50\nconst SIG_CENTRAL = 0x02014b50\nconst SIG_EOCD = 0x06054b50\n/** 4.3.15 ZIP64 end of central directory locator, 4.3.14 its record. */\nconst SIG_ZIP64_LOCATOR = 0x07064b50\nconst SIG_ZIP64_EOCD = 0x06064b50\n\nconst LOCAL_HEADER_SIZE = 30\nconst CENTRAL_HEADER_SIZE = 46\nconst EOCD_SIZE = 22\nconst ZIP64_LOCATOR_SIZE = 20\nconst ZIP64_EOCD_MIN_SIZE = 56\n/** The EOCD comment length is a 16-bit field (4.3.16). */\nconst MAX_COMMENT_LENGTH = 0xffff\n\n/** 4.4.4 general purpose bit flags. */\nconst FLAG_ENCRYPTED = 0x0001\nconst FLAG_UTF8 = 0x0800\n\n/** 4.4.5 compression methods. */\nconst METHOD_STORED = 0\nconst METHOD_DEFLATE = 8\n\n/** 4.5.2 extra field header id of the ZIP64 extended information. */\nconst EXTRA_ZIP64 = 0x0001\n\nconst U16_MAX = 0xffff\nconst U32_MAX = 0xffffffff\n\n/** The default cap on one entry's inflated size. */\nexport const ZIP_ENTRY_READ_MAX_BYTES = 16 * 1024 * 1024\n\nexport interface ZipEntry {\n /**\n * The entry name. Decoded as UTF-8 whether or not bit 11 is set (4.4.4):\n * the alternative is IBM 437, and every writer this module meets — Office,\n * LibreOffice, Google's exporters — writes ASCII part names either way.\n */\n name: string\n flags: number\n method: number\n crc32: number\n compressedSize: number\n uncompressedSize: number\n localHeaderOffset: number\n /**\n * Where the entry's stored bytes begin, from the lengths in its LOCAL\n * header (which may differ from the central record's, 4.3.7 vs 4.3.12);\n * `-1` when the local header is missing or runs off the archive.\n */\n dataOffset: number\n /** Bit 0 of the flags: traditional or strong encryption (4.4.4). */\n encrypted: boolean\n /** The central record carries a ZIP64 extended-information field (4.5.3). */\n zip64: boolean\n /** This entry's central-directory record, verbatim (a view into the archive). */\n centralRecord: Uint8Array\n}\n\nexport interface ZipArchive {\n bytes: Uint8Array\n /** In central-directory order. */\n entries: ZipEntry[]\n centralDirectoryOffset: number\n centralDirectorySize: number\n endOfCentralDirectoryOffset: number\n /** The archive comment, verbatim. */\n comment: Uint8Array\n /** The archive's own end records are ZIP64 (4.3.14, 4.3.15). */\n zip64: boolean\n}\n\nconst CRC_TABLE = (() => {\n const table = new Uint32Array(256)\n for (let n = 0; n < 256; n++) {\n let c = n\n for (let k = 0; k < 8; k++) c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1\n table[n] = c >>> 0\n }\n return table\n})()\n\n/**\n * CRC-32 as ZIP uses it (4.4.7): the reflected IEEE 802.3 polynomial\n * `0xEDB88320`, initial value and final XOR `0xFFFFFFFF`. Pass a previous\n * result as `seed` to continue a running checksum.\n */\nexport function crc32(bytes: Uint8Array, seed = 0): number {\n let c = (seed ^ U32_MAX) >>> 0\n for (const byte of bytes) c = (CRC_TABLE[(c ^ byte) & 0xff] ?? 0) ^ (c >>> 8)\n return (c ^ U32_MAX) >>> 0\n}\n\nconst utf8 = new TextDecoder('utf-8')\nconst utf8Encoder = new TextEncoder()\n\n/** A 64-bit little-endian integer, or null past `Number.MAX_SAFE_INTEGER`. */\nfunction readU64(view: DataView, at: number): number | null {\n const low = view.getUint32(at, true)\n const high = view.getUint32(at + 4, true)\n const value = high * 0x100000000 + low\n return Number.isSafeInteger(value) ? value : null\n}\n\n/**\n * Find the end-of-central-directory record (4.3.16).\n *\n * It is the last 22 bytes of the archive plus a comment of up to 64 KB, so\n * only that tail is searched, backwards. A record whose comment length ends\n * exactly at the end of the file wins; failing that, the last one whose\n * comment fits, which tolerates junk appended after the archive.\n */\nfunction findEndOfCentralDirectory(bytes: Uint8Array, view: DataView): number {\n const last = bytes.length - EOCD_SIZE\n const floor = Math.max(0, last - MAX_COMMENT_LENGTH)\n let loose = -1\n for (let at = last; at >= floor; at--) {\n if (view.getUint32(at, true) !== SIG_EOCD) continue\n const end = at + EOCD_SIZE + view.getUint16(at + 20, true)\n if (end === bytes.length) return at\n if (end < bytes.length && loose < 0) loose = at\n }\n return loose\n}\n\n/**\n * Where a central record's ZIP64 extended-information values sit (4.5.3).\n * Each value is present only when its 32-bit field is saturated, in the\n * fixed order uncompressed size, compressed size, local header offset.\n * Returns offsets within `view`, or null for a malformed field that was\n * needed.\n */\nfunction zip64Fields(\n view: DataView,\n extraStart: number,\n extraEnd: number,\n saturated: { uncompressed: boolean; compressed: boolean; offset: boolean },\n): {\n present: boolean\n uncompressed?: number\n compressed?: number\n offset?: number\n} | null {\n // A sloppy extra field is harmless while nothing needs to be read from it.\n const needed =\n saturated.uncompressed || saturated.compressed || saturated.offset\n const malformed = needed ? null : { present: false }\n let at = extraStart\n // Each extra block is a 2-byte id, a 2-byte length and its data (4.5.1).\n for (let guard = 0; at + 4 <= extraEnd && guard < 1024; guard++) {\n const id = view.getUint16(at, true)\n const length = view.getUint16(at + 2, true)\n const dataStart = at + 4\n const dataEnd = dataStart + length\n if (dataEnd > extraEnd) return malformed\n if (id === EXTRA_ZIP64) {\n const out: {\n present: boolean\n uncompressed?: number\n compressed?: number\n offset?: number\n } = { present: true }\n let cursor = dataStart\n for (const field of ['uncompressed', 'compressed', 'offset'] as const) {\n if (!saturated[field]) continue\n if (cursor + 8 > dataEnd) return null\n out[field] = cursor\n cursor += 8\n }\n return out\n }\n at = dataEnd\n }\n return { present: false }\n}\n\n/**\n * Parse an archive's central directory.\n *\n * Returns null for anything that is not a single-disk ZIP whose central\n * directory reads cleanly from end to end: a partial entry list is worse\n * than none here, because a rewrite built from it would silently drop\n * whatever was not listed.\n */\nexport function readZip(bytes: Uint8Array): ZipArchive | null {\n if (bytes.length < EOCD_SIZE) return null\n const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength)\n const eocd = findEndOfCentralDirectory(bytes, view)\n if (eocd < 0) return null\n\n let disk = view.getUint16(eocd + 4, true)\n let centralDisk = view.getUint16(eocd + 6, true)\n let entriesOnDisk = view.getUint16(eocd + 8, true)\n let totalEntries = view.getUint16(eocd + 10, true)\n let centralSize = view.getUint32(eocd + 12, true)\n let centralOffset = view.getUint32(eocd + 16, true)\n const commentLength = view.getUint16(eocd + 20, true)\n const comment = bytes.subarray(\n eocd + EOCD_SIZE,\n eocd + EOCD_SIZE + commentLength,\n )\n let centralLimit = eocd\n let zip64 = false\n\n const locator = eocd - ZIP64_LOCATOR_SIZE\n if (locator >= 0 && view.getUint32(locator, true) === SIG_ZIP64_LOCATOR) {\n const record = readU64(view, locator + 8)\n if (record === null || record + ZIP64_EOCD_MIN_SIZE > locator) return null\n if (view.getUint32(record, true) !== SIG_ZIP64_EOCD) return null\n const onDisk = readU64(view, record + 24)\n const total = readU64(view, record + 32)\n const size = readU64(view, record + 40)\n const offset = readU64(view, record + 48)\n if (onDisk === null || total === null || size === null || offset === null)\n return null\n disk = view.getUint32(record + 16, true)\n centralDisk = view.getUint32(record + 20, true)\n entriesOnDisk = onDisk\n totalEntries = total\n centralSize = size\n centralOffset = offset\n centralLimit = record\n zip64 = true\n }\n\n // Spanned and split archives (8.0) are not something an upload can be.\n if (disk !== 0 || centralDisk !== 0 || entriesOnDisk !== totalEntries)\n return null\n const centralEnd = centralOffset + centralSize\n if (centralEnd > centralLimit) return null\n // Every record is at least 46 bytes, which bounds the loop below.\n if (totalEntries * CENTRAL_HEADER_SIZE > centralSize) return null\n\n const entries: ZipEntry[] = []\n let at = centralOffset\n for (let index = 0; index < totalEntries; index++) {\n if (at + CENTRAL_HEADER_SIZE > centralEnd) return null\n if (view.getUint32(at, true) !== SIG_CENTRAL) return null\n const flags = view.getUint16(at + 8, true)\n const method = view.getUint16(at + 10, true)\n const crc = view.getUint32(at + 16, true)\n let compressedSize = view.getUint32(at + 20, true)\n let uncompressedSize = view.getUint32(at + 24, true)\n const nameLength = view.getUint16(at + 28, true)\n const extraLength = view.getUint16(at + 30, true)\n const commentLen = view.getUint16(at + 32, true)\n let localHeaderOffset = view.getUint32(at + 42, true)\n const nameStart = at + CENTRAL_HEADER_SIZE\n const extraStart = nameStart + nameLength\n const extraEnd = extraStart + extraLength\n const recordEnd = extraEnd + commentLen\n if (recordEnd > centralEnd) return null\n\n const zip = zip64Fields(view, extraStart, extraEnd, {\n uncompressed: uncompressedSize === U32_MAX,\n compressed: compressedSize === U32_MAX,\n offset: localHeaderOffset === U32_MAX,\n })\n if (!zip) return null\n if (zip.uncompressed !== undefined) {\n const value = readU64(view, zip.uncompressed)\n if (value === null) return null\n uncompressedSize = value\n }\n if (zip.compressed !== undefined) {\n const value = readU64(view, zip.compressed)\n if (value === null) return null\n compressedSize = value\n }\n if (zip.offset !== undefined) {\n const value = readU64(view, zip.offset)\n if (value === null) return null\n localHeaderOffset = value\n }\n\n entries.push({\n name: utf8.decode(bytes.subarray(nameStart, extraStart)),\n flags,\n method,\n crc32: crc,\n compressedSize,\n uncompressedSize,\n localHeaderOffset,\n dataOffset: localDataOffset(\n bytes,\n view,\n localHeaderOffset,\n compressedSize,\n ),\n encrypted: (flags & FLAG_ENCRYPTED) !== 0,\n zip64: zip.present,\n centralRecord: bytes.subarray(at, recordEnd),\n })\n at = recordEnd\n }\n\n return {\n bytes,\n entries,\n centralDirectoryOffset: centralOffset,\n centralDirectorySize: centralSize,\n endOfCentralDirectoryOffset: eocd,\n comment,\n zip64,\n }\n}\n\n/** Start of an entry's data from its local header (4.3.7), or -1. */\nfunction localDataOffset(\n bytes: Uint8Array,\n view: DataView,\n offset: number,\n compressedSize: number,\n): number {\n if (offset + LOCAL_HEADER_SIZE > bytes.length) return -1\n if (view.getUint32(offset, true) !== SIG_LOCAL) return -1\n const start =\n offset +\n LOCAL_HEADER_SIZE +\n view.getUint16(offset + 26, true) +\n view.getUint16(offset + 28, true)\n return start + compressedSize <= bytes.length ? start : -1\n}\n\n/** The first entry of that exact name. */\nexport function findZipEntry(\n archive: ZipArchive,\n name: string,\n): ZipEntry | undefined {\n return archive.entries.find((entry) => entry.name === name)\n}\n\n/**\n * An entry's content, inflated and CRC-checked.\n *\n * Null for an encrypted entry, a method other than stored or deflate, a\n * declared size over `maxBytes`, output that disagrees with the declared\n * size, or a CRC mismatch. `maxOutputLength` stops a deflate bomb at the\n * declared size, whatever the stream would expand to.\n */\nexport function readZipEntry(\n archive: ZipArchive,\n entry: ZipEntry,\n maxBytes = ZIP_ENTRY_READ_MAX_BYTES,\n): Uint8Array | null {\n if (entry.encrypted || entry.dataOffset < 0) return null\n if (entry.uncompressedSize > maxBytes) return null\n const data = archive.bytes.subarray(\n entry.dataOffset,\n entry.dataOffset + entry.compressedSize,\n )\n let content: Uint8Array\n if (entry.method === METHOD_STORED) {\n if (entry.compressedSize !== entry.uncompressedSize) return null\n content = data\n } else if (entry.method === METHOD_DEFLATE) {\n try {\n const out = inflateRawSync(data, {\n maxOutputLength: Math.max(1, entry.uncompressedSize),\n })\n content = new Uint8Array(out.buffer, out.byteOffset, out.byteLength)\n } catch {\n return null\n }\n if (content.length !== entry.uncompressedSize) return null\n } else {\n return null\n }\n return crc32(content) === entry.crc32 ? content : null\n}\n\n/** MS-DOS date and time (4.4.6), from the UTC fields; floors at 1980. */\nfunction dosDateTime(date: Date): { time: number; date: number } {\n if (date.getUTCFullYear() < 1980 || Number.isNaN(date.getTime())) {\n return { time: 0, date: (1 << 5) | 1 }\n }\n return {\n time:\n (date.getUTCHours() << 11) |\n (date.getUTCMinutes() << 5) |\n (date.getUTCSeconds() >> 1),\n date:\n (Math.min(127, date.getUTCFullYear() - 1980) << 9) |\n ((date.getUTCMonth() + 1) << 5) |\n date.getUTCDate(),\n }\n}\n\ninterface WrittenEntry {\n offset: number\n crc: number\n compressedSize: number\n uncompressedSize: number\n flags: number\n}\n\n/** A fresh local header plus deflated data (4.3.7) — never a descriptor. */\nfunction freshLocalRecord(\n nameBytes: Uint8Array,\n content: Uint8Array,\n flags: number,\n time: number,\n date: number,\n): { record: Uint8Array; crc: number; compressedSize: number } {\n const deflated = deflateRawSync(content)\n const crc = crc32(content)\n const record = new Uint8Array(\n LOCAL_HEADER_SIZE + nameBytes.length + deflated.length,\n )\n const view = new DataView(record.buffer)\n view.setUint32(0, SIG_LOCAL, true)\n view.setUint16(4, 20, true) // version needed: 2.0, for deflate (4.4.3.2)\n view.setUint16(6, flags, true)\n view.setUint16(8, METHOD_DEFLATE, true)\n view.setUint16(10, time, true)\n view.setUint16(12, date, true)\n view.setUint32(14, crc, true)\n view.setUint32(18, deflated.length, true)\n view.setUint32(22, content.length, true)\n view.setUint16(26, nameBytes.length, true)\n view.setUint16(28, 0, true)\n record.set(nameBytes, LOCAL_HEADER_SIZE)\n record.set(deflated, LOCAL_HEADER_SIZE + nameBytes.length)\n return { record, crc, compressedSize: deflated.length }\n}\n\n/**\n * Replace (or add) entries, copying everything else through verbatim.\n *\n * `changes` maps an entry name to its new, uncompressed content. A name the\n * archive already holds is replaced where it stands; a name it does not is\n * appended as a new entry after the last one, dated `options.now` (or\n * 1980-01-01, which is what Office stamps every part with).\n */\nexport function rewriteZip(\n archive: ZipArchive,\n changes: ReadonlyMap<string, Uint8Array>,\n options: { now?: Date } = {},\n): Uint8Array {\n const { bytes, entries } = archive\n if (archive.zip64) {\n throw new EmbeddedWriteError(\n 'This file is too large a ZIP archive (ZIP64) to be edited in place.',\n )\n }\n for (const name of changes.keys()) {\n const matches = entries.filter((entry) => entry.name === name)\n if (matches.length > 1) {\n throw new EmbeddedWriteError(\n `This file holds \"${name}\" more than once, so it cannot be edited safely.`,\n )\n }\n const target = matches[0]\n if (target?.encrypted) {\n throw new EmbeddedWriteError(\n 'This file is encrypted, so its details can only be read.',\n )\n }\n if (target?.zip64) {\n throw new EmbeddedWriteError(\n 'This file stores its details in a ZIP64 entry, which cannot be edited in place.',\n )\n }\n }\n\n // Each entry owns the bytes from its local header to the next entry's —\n // or to the central directory — so a data descriptor, and any padding a\n // writer left, travels with it. That only works if entries do not\n // overlap, which a crafted archive may not honor.\n const ordered = [...entries].sort(\n (a, b) => a.localHeaderOffset - b.localHeaderOffset,\n )\n const spanEnd = new Map<ZipEntry, number>()\n for (let index = 0; index < ordered.length; index++) {\n const entry = ordered[index]\n if (!entry) continue\n const next =\n ordered[index + 1]?.localHeaderOffset ?? archive.centralDirectoryOffset\n if (\n entry.dataOffset < 0 ||\n entry.dataOffset + entry.compressedSize > next ||\n entry.localHeaderOffset >= next\n ) {\n throw new EmbeddedWriteError(\n 'The parts of this file overlap or are damaged, so it cannot be edited safely.',\n )\n }\n spanEnd.set(entry, next)\n }\n\n const chunks: Uint8Array[] = []\n let position = 0\n const push = (chunk: Uint8Array) => {\n chunks.push(chunk)\n position += chunk.length\n }\n const firstOffset =\n ordered[0]?.localHeaderOffset ?? archive.centralDirectoryOffset\n // Anything ahead of the first entry — a self-extractor stub — stays put,\n // and so do the offsets that count from the start of the file.\n push(bytes.subarray(0, firstOffset))\n\n const written = new Map<ZipEntry, WrittenEntry>()\n const moved = new Map<ZipEntry, number>()\n for (const entry of ordered) {\n const content = changes.get(entry.name)\n const end = spanEnd.get(entry) ?? entry.localHeaderOffset\n if (!content) {\n moved.set(entry, position)\n push(bytes.subarray(entry.localHeaderOffset, end))\n continue\n }\n const record = entry.centralRecord\n const recordView = new DataView(\n record.buffer,\n record.byteOffset,\n record.byteLength,\n )\n const nameBytes = record.subarray(\n CENTRAL_HEADER_SIZE,\n CENTRAL_HEADER_SIZE + recordView.getUint16(28, true),\n )\n // Bit 11 (UTF-8 names) is kept; the descriptor bit 3, the deflate\n // option bits 1-2 and anything else describing the OLD data are not.\n const flags = entry.flags & FLAG_UTF8\n const fresh = freshLocalRecord(\n nameBytes,\n content,\n flags,\n recordView.getUint16(12, true),\n recordView.getUint16(14, true),\n )\n written.set(entry, {\n offset: position,\n crc: fresh.crc,\n compressedSize: fresh.compressedSize,\n uncompressedSize: content.length,\n flags,\n })\n push(fresh.record)\n }\n\n const known = new Set(entries.map((entry) => entry.name))\n const stamp = dosDateTime(options.now ?? new Date(Date.UTC(1980, 0, 1)))\n const added: Array<{ nameBytes: Uint8Array; written: WrittenEntry }> = []\n for (const [name, content] of changes) {\n if (known.has(name)) continue\n const nameBytes = utf8Encoder.encode(name)\n if (nameBytes.length > U16_MAX) {\n throw new EmbeddedWriteError('A part name in this file is too long.')\n }\n // eslint-disable-next-line no-control-regex\n const flags = /^[\\x00-\\x7f]*$/.test(name) ? 0 : FLAG_UTF8\n const fresh = freshLocalRecord(\n nameBytes,\n content,\n flags,\n stamp.time,\n stamp.date,\n )\n added.push({\n nameBytes,\n written: {\n offset: position,\n crc: fresh.crc,\n compressedSize: fresh.compressedSize,\n uncompressedSize: content.length,\n flags,\n },\n })\n push(fresh.record)\n }\n\n const centralOffset = position\n for (const entry of entries) {\n const record = entry.centralRecord.slice()\n const recordView = new DataView(record.buffer)\n const replaced = written.get(entry)\n const offset = replaced?.offset ?? moved.get(entry)\n if (offset === undefined || offset > U32_MAX - 1) {\n throw new EmbeddedWriteError(\n 'This file is too large to be edited in place.',\n )\n }\n if (recordView.getUint32(42, true) === U32_MAX) {\n // The offset lives in the ZIP64 extra field instead (4.5.3).\n const extraStart = CENTRAL_HEADER_SIZE + recordView.getUint16(28, true)\n const zip = zip64Fields(\n recordView,\n extraStart,\n extraStart + recordView.getUint16(30, true),\n {\n uncompressed: recordView.getUint32(24, true) === U32_MAX,\n compressed: recordView.getUint32(20, true) === U32_MAX,\n offset: true,\n },\n )\n if (!zip || zip.offset === undefined) {\n throw new EmbeddedWriteError(\n 'This file is damaged and cannot be edited safely.',\n )\n }\n recordView.setUint32(zip.offset, offset, true)\n recordView.setUint32(zip.offset + 4, 0, true)\n } else {\n recordView.setUint32(42, offset, true)\n }\n if (replaced) {\n recordView.setUint16(6, Math.max(20, recordView.getUint16(6, true)), true)\n recordView.setUint16(8, replaced.flags, true)\n recordView.setUint16(10, METHOD_DEFLATE, true)\n recordView.setUint32(16, replaced.crc, true)\n recordView.setUint32(20, replaced.compressedSize, true)\n recordView.setUint32(24, replaced.uncompressedSize, true)\n }\n push(record)\n }\n for (const { nameBytes, written: entry } of added) {\n const record = new Uint8Array(CENTRAL_HEADER_SIZE + nameBytes.length)\n const recordView = new DataView(record.buffer)\n recordView.setUint32(0, SIG_CENTRAL, true)\n recordView.setUint16(4, 20, true) // made by: MS-DOS, 2.0 (4.4.2)\n recordView.setUint16(6, 20, true)\n recordView.setUint16(8, entry.flags, true)\n recordView.setUint16(10, METHOD_DEFLATE, true)\n recordView.setUint16(12, stamp.time, true)\n recordView.setUint16(14, stamp.date, true)\n recordView.setUint32(16, entry.crc, true)\n recordView.setUint32(20, entry.compressedSize, true)\n recordView.setUint32(24, entry.uncompressedSize, true)\n recordView.setUint16(28, nameBytes.length, true)\n recordView.setUint32(42, entry.offset, true)\n record.set(nameBytes, CENTRAL_HEADER_SIZE)\n push(record)\n }\n const centralSize = position - centralOffset\n const count = entries.length + added.length\n if (count > U16_MAX || position > U32_MAX - 1) {\n throw new EmbeddedWriteError(\n 'This file is too large to be edited in place.',\n )\n }\n\n // Whatever sat between the directory and its end record (nothing, in a\n // non-ZIP64 archive written by anyone sane) is carried through as found.\n push(\n bytes.subarray(\n archive.centralDirectoryOffset + archive.centralDirectorySize,\n archive.endOfCentralDirectoryOffset,\n ),\n )\n\n const eocd = new Uint8Array(EOCD_SIZE + archive.comment.length)\n const eocdView = new DataView(eocd.buffer)\n eocdView.setUint32(0, SIG_EOCD, true)\n eocdView.setUint16(8, count, true)\n eocdView.setUint16(10, count, true)\n eocdView.setUint32(12, centralSize, true)\n eocdView.setUint32(16, centralOffset, true)\n eocdView.setUint16(20, archive.comment.length, true)\n eocd.set(archive.comment, EOCD_SIZE)\n push(eocd)\n\n const out = new Uint8Array(position)\n let at = 0\n for (const chunk of chunks) {\n out.set(chunk, at)\n at += chunk.length\n }\n // The rewritten archive must read back, entry for entry, or it is not\n // returned at all.\n const check = readZip(out)\n if (!check || check.entries.length !== count) {\n throw new EmbeddedWriteError(\n 'The edited file did not verify, so it was not saved.',\n )\n }\n return out\n}\n"],"names":["deflateRawSync","inflateRawSync","EmbeddedWriteError","SIG_LOCAL","SIG_CENTRAL","SIG_EOCD","SIG_ZIP64_LOCATOR","SIG_ZIP64_EOCD","LOCAL_HEADER_SIZE","CENTRAL_HEADER_SIZE","EOCD_SIZE","ZIP64_LOCATOR_SIZE","ZIP64_EOCD_MIN_SIZE","MAX_COMMENT_LENGTH","FLAG_ENCRYPTED","FLAG_UTF8","METHOD_STORED","METHOD_DEFLATE","EXTRA_ZIP64","U16_MAX","U32_MAX","ZIP_ENTRY_READ_MAX_BYTES","CRC_TABLE","table","Uint32Array","n","c","k","crc32","bytes","seed","byte","utf8","TextDecoder","utf8Encoder","TextEncoder","readU64","view","at","low","getUint32","high","value","Number","isSafeInteger","findEndOfCentralDirectory","last","length","floor","Math","max","loose","end","getUint16","zip64Fields","extraStart","extraEnd","saturated","needed","uncompressed","compressed","offset","malformed","present","guard","id","dataStart","dataEnd","out","cursor","field","readZip","DataView","buffer","byteOffset","byteLength","eocd","disk","centralDisk","entriesOnDisk","totalEntries","centralSize","centralOffset","commentLength","comment","subarray","centralLimit","zip64","locator","record","onDisk","total","size","centralEnd","entries","index","flags","method","crc","compressedSize","uncompressedSize","nameLength","extraLength","commentLen","localHeaderOffset","nameStart","recordEnd","zip","undefined","push","name","decode","dataOffset","localDataOffset","encrypted","centralRecord","centralDirectoryOffset","centralDirectorySize","endOfCentralDirectoryOffset","start","findZipEntry","archive","find","entry","readZipEntry","maxBytes","data","content","maxOutputLength","Uint8Array","dosDateTime","date","getUTCFullYear","isNaN","getTime","time","getUTCHours","getUTCMinutes","getUTCSeconds","min","getUTCMonth","getUTCDate","freshLocalRecord","nameBytes","deflated","setUint32","setUint16","set","rewriteZip","changes","options","ordered","keys","matches","filter","target","sort","a","b","spanEnd","Map","next","chunks","position","chunk","firstOffset","written","moved","get","recordView","fresh","known","Set","map","stamp","now","Date","UTC","added","has","encode","test","slice","replaced","count","eocdView","check"],"mappings":"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"}
|
|
@@ -115,3 +115,15 @@ export declare function nameSearchFields(name: string): {
|
|
|
115
115
|
nameTokens: string[];
|
|
116
116
|
nameReversed: string;
|
|
117
117
|
};
|
|
118
|
+
/**
|
|
119
|
+
* The normalizers a list query plan (`planListQuery` in
|
|
120
|
+
* `@aglyn/shared-ui-jsx/const/list-query-plan`) turns typed values into keys
|
|
121
|
+
* with: the same functions the writers stamp `nameLower`, `nameTokens` and
|
|
122
|
+
* `nameReversed` with, so a query asks for what was stored (AGL-3321).
|
|
123
|
+
*/
|
|
124
|
+
export declare const nameSearchNormalizers: {
|
|
125
|
+
readonly key: (value: string) => string;
|
|
126
|
+
readonly token: (value: string) => string;
|
|
127
|
+
readonly reversed: (value: string) => string;
|
|
128
|
+
readonly maxPrefix: 12;
|
|
129
|
+
};
|
|
@@ -141,5 +141,16 @@
|
|
|
141
141
|
nameReversed: nameSearchReversed(name)
|
|
142
142
|
};
|
|
143
143
|
}
|
|
144
|
+
/**
|
|
145
|
+
* The normalizers a list query plan (`planListQuery` in
|
|
146
|
+
* `@aglyn/shared-ui-jsx/const/list-query-plan`) turns typed values into keys
|
|
147
|
+
* with: the same functions the writers stamp `nameLower`, `nameTokens` and
|
|
148
|
+
* `nameReversed` with, so a query asks for what was stored (AGL-3321).
|
|
149
|
+
*/ export const nameSearchNormalizers = {
|
|
150
|
+
key: (value)=>nameSearchKey(value),
|
|
151
|
+
token: (value)=>nameSearchToken(value),
|
|
152
|
+
reversed: (value)=>nameSearchReversed(value),
|
|
153
|
+
maxPrefix: NAME_TOKEN_MAX_PREFIX
|
|
154
|
+
};
|
|
144
155
|
|
|
145
156
|
//# sourceMappingURL=name-search.js.map
|