@patrickdk77/office-defuse 0.1.1 → 0.2.1
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 +211 -43
- package/dist/cfb-writer.d.ts +25 -0
- package/dist/cfb-writer.js +314 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +357 -0
- package/dist/contained.d.ts +46 -0
- package/dist/contained.js +152 -0
- package/dist/context.d.ts +107 -12
- package/dist/context.js +101 -24
- package/dist/detect.d.ts +13 -0
- package/dist/detect.js +83 -0
- package/dist/engine.d.ts +66 -1
- package/dist/engine.js +290 -35
- package/dist/errors.d.ts +17 -0
- package/dist/errors.js +27 -1
- package/dist/fields.d.ts +20 -13
- package/dist/fields.js +65 -23
- package/dist/findings.d.ts +2 -1
- package/dist/findings.js +17 -1
- package/dist/flat.d.ts +33 -0
- package/dist/flat.js +555 -0
- package/dist/formats.d.ts +9 -0
- package/dist/formats.js +7 -1
- package/dist/formulas.d.ts +27 -0
- package/dist/formulas.js +157 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +11 -1
- package/dist/index.mjs +1 -1
- package/dist/io.d.ts +62 -1
- package/dist/io.js +245 -1
- package/dist/links.d.ts +27 -0
- package/dist/links.js +106 -1
- package/dist/msg.d.ts +3 -2
- package/dist/msg.js +172 -18
- package/dist/objects.d.ts +8 -5
- package/dist/objects.js +90 -20
- package/dist/odf.d.ts +87 -1
- package/dist/odf.js +204 -76
- package/dist/offcrypto.d.ts +24 -1
- package/dist/offcrypto.js +308 -69
- package/dist/ole.d.ts +19 -2
- package/dist/ole.js +98 -58
- package/dist/oleobj.d.ts +11 -0
- package/dist/oleobj.js +20 -3
- package/dist/ooxml.d.ts +108 -2
- package/dist/ooxml.js +392 -109
- package/dist/package.d.ts +14 -0
- package/dist/package.js +23 -7
- package/dist/plan.d.ts +104 -0
- package/dist/plan.js +73 -0
- package/dist/plugins.d.ts +8 -0
- package/dist/plugins.js +35 -0
- package/dist/ppt.js +45 -5
- package/dist/rewrite-cfb.d.ts +14 -0
- package/dist/rewrite-cfb.js +52 -0
- package/dist/rewrite-rtf.d.ts +9 -0
- package/dist/rewrite-rtf.js +45 -0
- package/dist/rewrite-xml.d.ts +36 -0
- package/dist/rewrite-xml.js +341 -0
- package/dist/rewrite-zip.d.ts +8 -0
- package/dist/rewrite-zip.js +498 -0
- package/dist/rtf.js +216 -42
- package/dist/rtfcomp.d.ts +7 -0
- package/dist/rtfcomp.js +80 -0
- package/dist/score.js +1 -1
- package/dist/sniff.d.ts +5 -0
- package/dist/sniff.js +38 -0
- package/dist/types.d.ts +66 -6
- package/dist/types.js +14 -0
- package/dist/vsd.d.ts +13 -0
- package/dist/vsd.js +689 -0
- package/dist/word.d.ts +4 -4
- package/dist/word.js +70 -23
- package/dist/xls.d.ts +10 -4
- package/dist/xls.js +58 -10
- package/dist/xml.d.ts +30 -0
- package/dist/xml.js +45 -23
- package/dist/zip-writer.d.ts +4 -0
- package/dist/zip-writer.js +20 -7
- package/dist/zip.d.ts +11 -2
- package/dist/zip.js +67 -6
- package/package.json +4 -1
package/dist/ole.js
CHANGED
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.families = families;
|
|
4
|
+
exports.mainFamily = mainFamily;
|
|
5
|
+
exports.compoundFormat = compoundFormat;
|
|
6
|
+
exports.openEncryptedPackage = openEncryptedPackage;
|
|
4
7
|
exports.inspectCompound = inspectCompound;
|
|
5
8
|
const errors_1 = require("./errors");
|
|
6
9
|
const msg_1 = require("./msg");
|
|
7
10
|
const objects_1 = require("./objects");
|
|
8
11
|
const offcrypto_1 = require("./offcrypto");
|
|
9
12
|
const package_1 = require("./package");
|
|
13
|
+
const plan_1 = require("./plan");
|
|
10
14
|
const ppt_1 = require("./ppt");
|
|
11
15
|
const types_1 = require("./types");
|
|
16
|
+
const vsd_1 = require("./vsd");
|
|
12
17
|
const word_1 = require("./word");
|
|
13
18
|
const xls_1 = require("./xls");
|
|
14
19
|
const zip_1 = require("./zip");
|
|
@@ -41,10 +46,10 @@ function families(cfb) {
|
|
|
41
46
|
return out;
|
|
42
47
|
}
|
|
43
48
|
/**
|
|
44
|
-
*
|
|
45
|
-
*
|
|
49
|
+
* The family whose format a compound file holds, by the streams and storages at its root. Throws for a root that
|
|
50
|
+
* holds no Office document, or the documents of two families.
|
|
46
51
|
*/
|
|
47
|
-
|
|
52
|
+
function mainFamily(cfb) {
|
|
48
53
|
const found = families(cfb);
|
|
49
54
|
// Word 2007 writes a Word document beside an encrypted package, for readers that cannot decrypt it.
|
|
50
55
|
const main = found.filter(x => !(x === 'word' && found.includes('encrypted')));
|
|
@@ -52,76 +57,111 @@ async function inspectCompound(ctx, cfb) {
|
|
|
52
57
|
throw new errors_1.StopError(types_1.OfficeCategory.Package, types_1.OfficeDetail.AmbiguousFormat, `The compound file holds ${main.join(' and ')} streams`, { reason: `${main.join(' and ')} streams` });
|
|
53
58
|
if (main.length === 0)
|
|
54
59
|
throw new errors_1.StopError(types_1.OfficeCategory.Package, types_1.OfficeDetail.Unrecognized, 'The compound file holds no Office document stream', { reason: 'a compound file of another kind' });
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
return main[0];
|
|
61
|
+
}
|
|
62
|
+
/** A stream at the root of a compound file, by name, ignoring case. */
|
|
63
|
+
const rootStream = (cfb, name) => {
|
|
64
|
+
const e = cfb.child(cfb.root, name);
|
|
65
|
+
return e?.kind === 'stream' ? e : undefined;
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* The format of a compound file of `family`. A Word document is a template when its FIB says so, and a workbook a
|
|
69
|
+
* template or an add-in when its globals do; both are read without a password. An encrypted package names no format
|
|
70
|
+
* until it is decrypted, so for one this is undefined.
|
|
71
|
+
*/
|
|
72
|
+
async function compoundFormat(cfb, family, deadline) {
|
|
73
|
+
switch (family) {
|
|
74
|
+
case 'word': {
|
|
75
|
+
const word = rootStream(cfb, 'WordDocument');
|
|
76
|
+
return word && (await (0, word_1.isWordTemplate)(cfb, word)) ? f('dot', 'application/msword') : f('doc', 'application/msword');
|
|
77
|
+
}
|
|
78
|
+
case 'excel': {
|
|
79
|
+
// Excel 97 to 2003 reads Workbook, and Excel 5.0 and 95 read Book. A file can hold both.
|
|
80
|
+
let template = false;
|
|
81
|
+
let addIn = false;
|
|
82
|
+
for (const name of ['Workbook', 'Book']) {
|
|
83
|
+
const s = rootStream(cfb, name);
|
|
84
|
+
if (!s)
|
|
85
|
+
continue;
|
|
86
|
+
const kind = await (0, xls_1.workbookKind)(cfb, s, deadline);
|
|
87
|
+
template ||= kind.template;
|
|
88
|
+
addIn ||= kind.addIn;
|
|
89
|
+
}
|
|
90
|
+
return addIn ? f('xla', 'application/vnd.ms-excel') : template ? f('xlt', 'application/vnd.ms-excel') : f('xls', 'application/vnd.ms-excel');
|
|
91
|
+
}
|
|
92
|
+
case 'powerpoint':
|
|
93
|
+
return f('ppt', 'application/vnd.ms-powerpoint');
|
|
94
|
+
case 'visio':
|
|
95
|
+
return f('vsd', 'application/vnd.visio');
|
|
96
|
+
case 'outlook':
|
|
97
|
+
return cfb.root.clsid === '0006F046-0000-0000-C000-000000000046' ? f('oft', 'application/vnd.ms-outlook') : f('msg', 'application/vnd.ms-outlook');
|
|
98
|
+
case 'publisher':
|
|
99
|
+
return f('pub', 'application/x-mspublisher');
|
|
100
|
+
case 'project':
|
|
101
|
+
return f('mpp', 'application/vnd.ms-project');
|
|
102
|
+
default:
|
|
103
|
+
// An encrypted package names its format only once it is decrypted.
|
|
104
|
+
return undefined;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Decrypts the package of an encrypted compound file with the run's passwords, then VelvetSweatshop, and reads it as
|
|
109
|
+
* a ZIP archive. Throws ENCRYPTED/PASSWORD_REQUIRED when no password opens it.
|
|
110
|
+
*/
|
|
111
|
+
async function openEncryptedPackage(ctx, cfb) {
|
|
112
|
+
const info = rootStream(cfb, 'EncryptionInfo');
|
|
113
|
+
const pkg = rootStream(cfb, 'EncryptedPackage');
|
|
114
|
+
if (!info || !pkg)
|
|
115
|
+
throw new errors_1.StopError(types_1.OfficeCategory.Package, types_1.OfficeDetail.Unrecognized, 'The compound file holds no encrypted package', { reason: 'no EncryptionInfo and EncryptedPackage streams' });
|
|
116
|
+
const { source } = await (0, offcrypto_1.openPackage)(ctx, cfb, info, pkg);
|
|
117
|
+
return zip_1.ZipArchive.open(source, ctx.settings, ctx.settings.deadline);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Inspects a compound file: the rules every compound file gets, over its whole tree, and then those of the format
|
|
121
|
+
* its root names.
|
|
122
|
+
*/
|
|
123
|
+
async function inspectCompound(ctx, cfb) {
|
|
124
|
+
const family = mainFamily(cfb);
|
|
125
|
+
ctx.format = await compoundFormat(cfb, family, ctx.settings.deadline);
|
|
126
|
+
const plan = new plan_1.CompoundPlan();
|
|
127
|
+
if (family !== 'encrypted')
|
|
128
|
+
ctx.run.output = { kind: 'cfb', cfb, plan };
|
|
129
|
+
await (0, objects_1.compoundRules)(ctx, cfb, '', false, plan);
|
|
130
|
+
const stream = (name) => rootStream(cfb, name);
|
|
62
131
|
// Beside an encrypted package, Word 2007 writes a WordDocument stream for older readers, of zeros in the files at
|
|
63
132
|
// hand. Those readers read it if it holds a document, so it gets the Word rules when it does.
|
|
64
133
|
const word = stream('WordDocument');
|
|
65
|
-
if (word)
|
|
66
|
-
|
|
67
|
-
if (r?.template && family === 'word')
|
|
68
|
-
ctx.format = f('dot', 'application/msword');
|
|
69
|
-
}
|
|
134
|
+
if (word)
|
|
135
|
+
await (0, word_1.wordRules)(ctx, cfb, word, family === 'encrypted');
|
|
70
136
|
if (family === 'excel') {
|
|
71
|
-
// Excel 97 to 2003 reads Workbook, and Excel 5.0 and 95 read Book. A file can hold both.
|
|
72
|
-
let template = false;
|
|
73
|
-
let addIn = false;
|
|
74
137
|
for (const name of ['Workbook', 'Book']) {
|
|
75
138
|
const s = stream(name);
|
|
76
|
-
if (
|
|
77
|
-
|
|
78
|
-
const r = await (0, xls_1.excelRules)(ctx, cfb, s, offcrypto_1.unlockWorkbook);
|
|
79
|
-
template ||= r.template;
|
|
80
|
-
addIn ||= r.addIn;
|
|
139
|
+
if (s)
|
|
140
|
+
await (0, xls_1.excelRules)(ctx, cfb, s, offcrypto_1.unlockWorkbook);
|
|
81
141
|
}
|
|
82
|
-
if (addIn)
|
|
83
|
-
ctx.format = f('xla', 'application/vnd.ms-excel');
|
|
84
|
-
else if (template)
|
|
85
|
-
ctx.format = f('xlt', 'application/vnd.ms-excel');
|
|
86
142
|
// Excel keeps the data of a workbook's ActiveX controls in one Ctls stream.
|
|
87
143
|
const controls = stream('Ctls');
|
|
88
|
-
if (controls && controls.size > 0)
|
|
89
|
-
|
|
144
|
+
if (controls && controls.size > 0 && ctx.report(types_1.OfficeCategory.Control, types_1.OfficeDetail.ActiveX, controls.name, { stream: controls.name }).action === 'strip')
|
|
145
|
+
plan.drop.add(controls);
|
|
90
146
|
}
|
|
91
147
|
if (family === 'outlook')
|
|
92
|
-
await (0, msg_1.messageRules)(ctx, cfb, cfb.root);
|
|
148
|
+
await (0, msg_1.messageRules)(ctx, cfb, cfb.root, 0, plan);
|
|
93
149
|
const ppt = stream('PowerPoint Document');
|
|
94
150
|
if (family === 'powerpoint' && ppt)
|
|
95
151
|
await (0, ppt_1.powerPointRules)(ctx, cfb, ppt);
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
152
|
+
const visio = stream('VisioDocument');
|
|
153
|
+
if (family === 'visio' && visio)
|
|
154
|
+
await (0, vsd_1.visioRules)(ctx, cfb, visio);
|
|
155
|
+
if (family === 'encrypted') {
|
|
99
156
|
// The package goes through the OOXML rules once a password opens it, and names the format.
|
|
100
|
-
const
|
|
101
|
-
const
|
|
157
|
+
const zip = await openEncryptedPackage(ctx, cfb);
|
|
158
|
+
const location = stream('EncryptedPackage')?.name ?? 'EncryptedPackage';
|
|
102
159
|
for (const n of zip.notes)
|
|
103
|
-
ctx.report(types_1.OfficeCategory.Container, n.detail,
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
case 'word':
|
|
110
|
-
return f('doc', 'application/msword');
|
|
111
|
-
case 'excel':
|
|
112
|
-
return f('xls', 'application/vnd.ms-excel');
|
|
113
|
-
case 'powerpoint':
|
|
114
|
-
return f('ppt', 'application/vnd.ms-powerpoint');
|
|
115
|
-
case 'visio':
|
|
116
|
-
return f('vsd', 'application/vnd.visio');
|
|
117
|
-
case 'outlook':
|
|
118
|
-
return cfb.root.clsid === '0006F046-0000-0000-C000-000000000046' ? f('oft', 'application/vnd.ms-outlook') : f('msg', 'application/vnd.ms-outlook');
|
|
119
|
-
case 'publisher':
|
|
120
|
-
return f('pub', 'application/x-mspublisher');
|
|
121
|
-
case 'project':
|
|
122
|
-
return f('mpp', 'application/vnd.ms-project');
|
|
123
|
-
default:
|
|
124
|
-
// An encrypted package names its format only once it is decrypted.
|
|
125
|
-
return undefined;
|
|
160
|
+
ctx.report(types_1.OfficeCategory.Container, n.detail, location, { bytes: n.bytes });
|
|
161
|
+
// The rewrite writes the package decrypted, since office-defuse does not encrypt.
|
|
162
|
+
const zctx = ctx.withZip(zip);
|
|
163
|
+
await (0, package_1.inspectPackage)(zctx);
|
|
164
|
+
if (ctx.format)
|
|
165
|
+
ctx.run.output = { kind: 'zip', zip, plan: zctx.plan, format: ctx.format };
|
|
126
166
|
}
|
|
127
167
|
}
|
package/dist/oleobj.d.ts
CHANGED
|
@@ -54,6 +54,8 @@ export interface PackagedFile {
|
|
|
54
54
|
/** False when the data names a file it does not hold, a link. */
|
|
55
55
|
embedded: boolean;
|
|
56
56
|
size: number;
|
|
57
|
+
/** Where the file's bytes start in the native data. */
|
|
58
|
+
dataAt: number;
|
|
57
59
|
}
|
|
58
60
|
/**
|
|
59
61
|
* Packager's native data, as oleobj reads it: a 16-bit type, the label and source path ended by NULs, eight bytes,
|
|
@@ -70,5 +72,14 @@ export interface Ole1Object {
|
|
|
70
72
|
itemName: string;
|
|
71
73
|
/** The native data of an embedded object. */
|
|
72
74
|
data?: Uint8Array;
|
|
75
|
+
/** Where the native data starts in the object's bytes, after the size before it. */
|
|
76
|
+
dataAt?: number;
|
|
73
77
|
}
|
|
74
78
|
export declare function parseOle1(b: Uint8Array): Ole1Object | undefined;
|
|
79
|
+
/**
|
|
80
|
+
* Data that holds a 32-bit size at `dataAt - 4` and that many bytes at `dataAt`, with `data` in their place and the
|
|
81
|
+
* size set to match. What came before and after stays. Packager's native data and an OLE 1.0 object have this layout.
|
|
82
|
+
*/
|
|
83
|
+
export declare function replaceSized(bytes: Uint8Array, dataAt: number, oldSize: number, data: Uint8Array): Uint8Array;
|
|
84
|
+
/** A stream that starts with the size of what follows, such as Ole10Native, around `data`. */
|
|
85
|
+
export declare const sizedStream: (data: Uint8Array) => Buffer<ArrayBuffer>;
|
package/dist/oleobj.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.utf16 = exports.latin1 = exports.ByteReader = exports.Truncated = void 0;
|
|
3
|
+
exports.sizedStream = exports.utf16 = exports.latin1 = exports.ByteReader = exports.Truncated = void 0;
|
|
4
4
|
exports.bounded = bounded;
|
|
5
5
|
exports.parseCompObj = parseCompObj;
|
|
6
6
|
exports.readMoniker = readMoniker;
|
|
7
7
|
exports.parseOleStream = parseOleStream;
|
|
8
8
|
exports.parsePackage = parsePackage;
|
|
9
9
|
exports.parseOle1 = parseOle1;
|
|
10
|
+
exports.replaceSized = replaceSized;
|
|
10
11
|
const cfb_1 = require("./cfb");
|
|
11
12
|
/** Thrown by ByteReader when a structure runs past the end of its bytes. Parsers catch it and keep what they read. */
|
|
12
13
|
class Truncated extends Error {
|
|
@@ -177,7 +178,7 @@ function parsePackage(b) {
|
|
|
177
178
|
const sourcePath = r.ansiz();
|
|
178
179
|
r.skip(8);
|
|
179
180
|
const tempPath = r.ansiz();
|
|
180
|
-
return bounded(() => ({ fileName, sourcePath, tempPath, embedded: true, size: r.u32() }), () => ({ fileName, sourcePath, tempPath, embedded: false, size: 0 }));
|
|
181
|
+
return bounded(() => ({ fileName, sourcePath, tempPath, embedded: true, size: r.u32(), dataAt: r.pos }), () => ({ fileName, sourcePath, tempPath, embedded: false, size: 0, dataAt: r.pos }));
|
|
181
182
|
}, () => undefined);
|
|
182
183
|
}
|
|
183
184
|
function parseOle1(b) {
|
|
@@ -193,6 +194,22 @@ function parseOle1(b) {
|
|
|
193
194
|
if (formatId === 1)
|
|
194
195
|
return { formatId, className, topicName, itemName };
|
|
195
196
|
const size = r.u32();
|
|
196
|
-
|
|
197
|
+
const dataAt = r.pos;
|
|
198
|
+
return { formatId, className, topicName, itemName, data: r.bytes(Math.min(size, r.left)), dataAt };
|
|
197
199
|
}, () => undefined);
|
|
198
200
|
}
|
|
201
|
+
const le32 = (n) => {
|
|
202
|
+
const b = Buffer.alloc(4);
|
|
203
|
+
b.writeUInt32LE(n >>> 0);
|
|
204
|
+
return b;
|
|
205
|
+
};
|
|
206
|
+
/**
|
|
207
|
+
* Data that holds a 32-bit size at `dataAt - 4` and that many bytes at `dataAt`, with `data` in their place and the
|
|
208
|
+
* size set to match. What came before and after stays. Packager's native data and an OLE 1.0 object have this layout.
|
|
209
|
+
*/
|
|
210
|
+
function replaceSized(bytes, dataAt, oldSize, data) {
|
|
211
|
+
return Buffer.concat([bytes.subarray(0, dataAt - 4), le32(data.length), data, bytes.subarray(Math.min(bytes.length, dataAt + oldSize))]);
|
|
212
|
+
}
|
|
213
|
+
/** A stream that starts with the size of what follows, such as Ole10Native, around `data`. */
|
|
214
|
+
const sizedStream = (data) => Buffer.concat([le32(data.length), data]);
|
|
215
|
+
exports.sizedStream = sizedStream;
|
package/dist/ooxml.d.ts
CHANGED
|
@@ -1,8 +1,114 @@
|
|
|
1
1
|
import { type ZipContext } from './context';
|
|
2
|
+
import { type Format } from './formats';
|
|
3
|
+
import { type XmlElement } from './xml';
|
|
2
4
|
import { type ZipEntry } from './zip';
|
|
5
|
+
export declare const CONTENT_TYPES_NS = "http://schemas.openxmlformats.org/package/2006/content-types";
|
|
6
|
+
export declare const RELS_NS = "http://schemas.openxmlformats.org/package/2006/relationships";
|
|
7
|
+
/** The relationship types that name an XPS package's FixedDocumentSequence, lowercased. */
|
|
8
|
+
export declare const XPS_MAIN: {
|
|
9
|
+
xps: string;
|
|
10
|
+
oxps: string;
|
|
11
|
+
};
|
|
12
|
+
/** The XPS and OpenXPS markup namespaces, lowercased. */
|
|
13
|
+
export declare const XPS_NS: Set<string>;
|
|
14
|
+
/** Relationship types, lowercased, as OPC compares them without regard to case. */
|
|
15
|
+
export declare const REL: {
|
|
16
|
+
main: Set<string>;
|
|
17
|
+
hyperlink: Set<string>;
|
|
18
|
+
template: Set<string>;
|
|
19
|
+
image: Set<string>;
|
|
20
|
+
frame: Set<string>;
|
|
21
|
+
subDocument: Set<string>;
|
|
22
|
+
workbook: Set<string>;
|
|
23
|
+
};
|
|
24
|
+
/** Content types, lowercased. */
|
|
25
|
+
export declare const TYPE: {
|
|
26
|
+
vba: Set<string>;
|
|
27
|
+
macrosheet: Set<string>;
|
|
28
|
+
ole: Set<string>;
|
|
29
|
+
control: Set<string>;
|
|
30
|
+
controlBinary: Set<string>;
|
|
31
|
+
vml: string;
|
|
32
|
+
xlsbExternalLink: string;
|
|
33
|
+
};
|
|
34
|
+
/** Whether the rules read a part of this content type as XML. */
|
|
35
|
+
export declare const isXmlType: (ct: string | undefined) => boolean;
|
|
36
|
+
export declare const WORD_NS: Set<string>;
|
|
37
|
+
export declare const SHEET_NS: Set<string>;
|
|
38
|
+
export declare const R_NS: Set<string>;
|
|
39
|
+
export interface Relationship {
|
|
40
|
+
id: string;
|
|
41
|
+
type: string;
|
|
42
|
+
target: string;
|
|
43
|
+
external: boolean;
|
|
44
|
+
}
|
|
45
|
+
export interface Part {
|
|
46
|
+
entry: ZipEntry;
|
|
47
|
+
contentType?: string;
|
|
48
|
+
/** The AS bits of the relationship types that reach the part. */
|
|
49
|
+
reachedAs: number;
|
|
50
|
+
/** A relationship of an ActiveX control part reaches it, so it is that control's binary. */
|
|
51
|
+
claimed: boolean;
|
|
52
|
+
/** The parts its own relationships reach. */
|
|
53
|
+
targets: Set<Part>;
|
|
54
|
+
ole: boolean;
|
|
55
|
+
}
|
|
56
|
+
/** What the rewrite needs of an OOXML package: its parts, which part each relationships part belongs to, and the roots. */
|
|
57
|
+
export interface OoxmlGraph {
|
|
58
|
+
contentTypes: ZipEntry;
|
|
59
|
+
parts: Map<string, Part>;
|
|
60
|
+
relsOf: Map<string, ZipEntry>;
|
|
61
|
+
/** The parts the package relationships reach. */
|
|
62
|
+
roots: Set<Part>;
|
|
63
|
+
/** The package uses the relationship types of Strict OOXML. */
|
|
64
|
+
strict: boolean;
|
|
65
|
+
/** The package is XPS or OpenXPS, whose parts name the parts they use in attributes. */
|
|
66
|
+
xps: boolean;
|
|
67
|
+
}
|
|
68
|
+
/** The key of the part a relationships part belongs to, '' for the package, or undefined for any other part. */
|
|
69
|
+
export declare const relsSource: (relsName: string) => string | undefined;
|
|
70
|
+
/**
|
|
71
|
+
* Resolves an internal target against the folder of the part it belongs to, as RFC 3986 resolves a relative
|
|
72
|
+
* reference: a ".." at the root of the package stays at the root. LibreOffice writes "../customXml/item1.xml" in the
|
|
73
|
+
* package relationships of workbooks it saves.
|
|
74
|
+
*/
|
|
75
|
+
export declare function resolveTarget(relsName: string, target: string): string;
|
|
76
|
+
/** A reference in an XPS part to another part: an absolute part name, or a path relative to the part's folder. */
|
|
77
|
+
export declare function resolvePartRef(part: string, ref: string): string;
|
|
78
|
+
/**
|
|
79
|
+
* The resources an XPS element names in its attributes, as the attribute and the URI: a document, page or resource
|
|
80
|
+
* dictionary's Source, a font's FontUri, an image brush's image and profile, and a ContextColor's profile.
|
|
81
|
+
*/
|
|
82
|
+
export declare function xpsResources(el: XmlElement): Array<[string, string]>;
|
|
83
|
+
/** Reads a relationships part and hands each relationship to `each` as it is read. Ids given twice are reported. */
|
|
84
|
+
export declare function readRelationships(ctx: ZipContext, entry: ZipEntry, each: (r: Relationship) => void): Promise<void>;
|
|
85
|
+
/** An OOXML package's parts, typed by its [Content_Types].xml, and its relationships parts by the key of the part each belongs to. */
|
|
86
|
+
export interface OoxmlParts {
|
|
87
|
+
parts: Map<string, Part>;
|
|
88
|
+
relsOf: Map<string, ZipEntry>;
|
|
89
|
+
}
|
|
90
|
+
/** Reads [Content_Types].xml and types each part by it. Directory entries are neither parts nor relationships parts. */
|
|
91
|
+
export declare function readParts(ctx: ZipContext, contentTypes: ZipEntry): Promise<OoxmlParts>;
|
|
92
|
+
/** The format the package relationships name, and the relationship types they use. */
|
|
93
|
+
export interface OoxmlMain {
|
|
94
|
+
format: Format;
|
|
95
|
+
/** The package uses the relationship types of Strict OOXML. */
|
|
96
|
+
strict: boolean;
|
|
97
|
+
/** The package is XPS or OpenXPS. */
|
|
98
|
+
xps: boolean;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Reads the package relationships and names the format by the one main part they name: by its content type, or for
|
|
102
|
+
* XPS by the relationship type too, since XPS and OpenXPS share their content types. `each` sees every package
|
|
103
|
+
* relationship as it is read. Throws when no main part, or more than one, is named, or its format is unknown.
|
|
104
|
+
*/
|
|
105
|
+
export declare function readMain(ctx: ZipContext, { parts, relsOf }: OoxmlParts, each?: (rels: ZipEntry, r: Relationship) => void): Promise<OoxmlMain>;
|
|
106
|
+
/** Names an OOXML package's format as its inspection does, reading only [Content_Types].xml and the package relationships. */
|
|
107
|
+
export declare function nameOoxml(ctx: ZipContext, contentTypes: ZipEntry): Promise<Format>;
|
|
3
108
|
/**
|
|
4
109
|
* Inspects an OOXML package. The package relationships come first, since they name the main part and so the format.
|
|
5
110
|
* Then each part is read in archive order, followed by its relationships, which are reported as they are read and
|
|
6
|
-
* leave behind only which parts they reach and how.
|
|
111
|
+
* leave behind only which parts they reach and how. The run names `outer` as the format when given, as for a Flat
|
|
112
|
+
* OPC package unpacked into a ZIP archive, and the package's own format is returned.
|
|
7
113
|
*/
|
|
8
|
-
export declare function inspectOoxml(ctx: ZipContext, contentTypes: ZipEntry): Promise<
|
|
114
|
+
export declare function inspectOoxml(ctx: ZipContext, contentTypes: ZipEntry, outer?: Format): Promise<Format>;
|