@patrickdk77/office-defuse 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/README.md +197 -42
  2. package/dist/cfb-writer.d.ts +25 -0
  3. package/dist/cfb-writer.js +314 -0
  4. package/dist/cli.d.ts +2 -0
  5. package/dist/cli.js +357 -0
  6. package/dist/contained.d.ts +46 -0
  7. package/dist/contained.js +152 -0
  8. package/dist/context.d.ts +107 -12
  9. package/dist/context.js +101 -24
  10. package/dist/engine.d.ts +12 -1
  11. package/dist/engine.js +276 -31
  12. package/dist/errors.d.ts +17 -0
  13. package/dist/errors.js +27 -1
  14. package/dist/fields.d.ts +20 -13
  15. package/dist/fields.js +65 -23
  16. package/dist/findings.d.ts +2 -1
  17. package/dist/findings.js +17 -1
  18. package/dist/flat.d.ts +33 -0
  19. package/dist/flat.js +486 -0
  20. package/dist/formats.d.ts +7 -0
  21. package/dist/formats.js +5 -1
  22. package/dist/formulas.d.ts +27 -0
  23. package/dist/formulas.js +157 -1
  24. package/dist/index.d.ts +3 -2
  25. package/dist/index.js +8 -1
  26. package/dist/index.mjs +1 -1
  27. package/dist/io.d.ts +62 -1
  28. package/dist/io.js +245 -1
  29. package/dist/links.d.ts +27 -0
  30. package/dist/links.js +106 -1
  31. package/dist/msg.d.ts +3 -2
  32. package/dist/msg.js +172 -18
  33. package/dist/objects.d.ts +8 -5
  34. package/dist/objects.js +90 -20
  35. package/dist/odf.d.ts +65 -1
  36. package/dist/odf.js +181 -64
  37. package/dist/offcrypto.d.ts +24 -1
  38. package/dist/offcrypto.js +308 -69
  39. package/dist/ole.js +17 -5
  40. package/dist/oleobj.d.ts +11 -0
  41. package/dist/oleobj.js +20 -3
  42. package/dist/ooxml.d.ts +81 -0
  43. package/dist/ooxml.js +342 -81
  44. package/dist/plan.d.ts +104 -0
  45. package/dist/plan.js +73 -0
  46. package/dist/plugins.d.ts +8 -0
  47. package/dist/plugins.js +60 -0
  48. package/dist/ppt.js +45 -5
  49. package/dist/rewrite-cfb.d.ts +14 -0
  50. package/dist/rewrite-cfb.js +52 -0
  51. package/dist/rewrite-rtf.d.ts +9 -0
  52. package/dist/rewrite-rtf.js +45 -0
  53. package/dist/rewrite-xml.d.ts +36 -0
  54. package/dist/rewrite-xml.js +341 -0
  55. package/dist/rewrite-zip.d.ts +8 -0
  56. package/dist/rewrite-zip.js +498 -0
  57. package/dist/rtf.js +214 -41
  58. package/dist/rtfcomp.d.ts +7 -0
  59. package/dist/rtfcomp.js +80 -0
  60. package/dist/score.js +1 -1
  61. package/dist/sniff.d.ts +5 -0
  62. package/dist/sniff.js +38 -0
  63. package/dist/types.d.ts +43 -6
  64. package/dist/types.js +14 -0
  65. package/dist/vsd.d.ts +13 -0
  66. package/dist/vsd.js +689 -0
  67. package/dist/word.js +51 -17
  68. package/dist/xls.js +38 -4
  69. package/dist/xml.d.ts +30 -0
  70. package/dist/xml.js +45 -23
  71. package/dist/zip-writer.d.ts +4 -0
  72. package/dist/zip-writer.js +20 -7
  73. package/dist/zip.d.ts +9 -2
  74. package/dist/zip.js +61 -4
  75. package/package.json +4 -1
package/dist/fields.js CHANGED
@@ -10,68 +10,104 @@ const xml_1 = require("./xml");
10
10
  /** How much of a field code is kept, counted from its first word, which names the field. */
11
11
  const MAX_FIELD_CODE = 4096;
12
12
  /**
13
- * Reports a Word field by its code. A field whose name holds the content of an external entity has a type the file
14
- * does not say, as one whose name another field builds does.
13
+ * Reports a Word field by its code, and tells whether any of its findings strips it. A field whose name holds the
14
+ * content of an external entity has a type the file does not say, as one whose name another field builds does. A
15
+ * HYPERLINK field's result is the text the reader sees, and goes with its tooltip into the label check.
15
16
  */
16
- function evaluateField(ctx, location, code, computed) {
17
+ function evaluateField(ctx, location, code, computed, result = '') {
17
18
  const data = { code: (0, context_1.clip)(code.trim()) };
18
19
  const words = (0, formulas_1.fieldWords)(code);
19
20
  const first = words[0]?.text ?? '';
20
21
  const entity = (0, xml_1.unknownEntity)(first);
22
+ const actions = [];
21
23
  if (computed || entity !== undefined)
22
- ctx.report(types_1.OfficeCategory.Field, types_1.OfficeDetail.Computed, location, entity === undefined ? data : { ...data, entity: (0, context_1.clip)(entity) });
24
+ actions.push(ctx.report(types_1.OfficeCategory.Field, types_1.OfficeDetail.Computed, location, entity === undefined ? data : { ...data, entity: (0, context_1.clip)(entity) }).action);
23
25
  const name = first.toUpperCase();
24
26
  // An argument comes before any switch, and a switch is an unquoted word starting with a backslash.
25
27
  const switchAt = words.findIndex(w => !w.quoted && w.text.startsWith('\\'));
26
28
  const arg = (n) => (words[n] !== undefined && (switchAt < 0 || n < switchAt) ? words[n].text : undefined);
27
29
  if (name === 'DDE' || name === 'DDEAUTO')
28
- ctx.report(types_1.OfficeCategory.Dde, types_1.OfficeDetail.Field, location, data);
30
+ actions.push(ctx.report(types_1.OfficeCategory.Dde, types_1.OfficeDetail.Field, location, data).action);
29
31
  else if (name === 'MACROBUTTON')
30
- ctx.report(types_1.OfficeCategory.Field, types_1.OfficeDetail.Macrobutton, location, { ...data, macro: (0, context_1.clip)(words[1]?.text ?? '') });
32
+ actions.push(ctx.report(types_1.OfficeCategory.Field, types_1.OfficeDetail.Macrobutton, location, { ...data, macro: (0, context_1.clip)(words[1]?.text ?? '') }).action);
31
33
  else if (name === 'INCLUDETEXT' || name === 'INCLUDEPICTURE' || name === 'IMPORT' || name === 'LINK') {
32
34
  const target = arg(name === 'LINK' ? 2 : 1);
33
35
  if (target === undefined)
34
- ctx.report(types_1.OfficeCategory.External, types_1.OfficeDetail.Include, location, data);
36
+ actions.push(ctx.report(types_1.OfficeCategory.External, types_1.OfficeDetail.Include, location, data).action);
35
37
  else
36
- ctx.external(types_1.OfficeDetail.Include, target, location, data, 'field');
38
+ actions.push(ctx.external(types_1.OfficeDetail.Include, target, location, data, 'field').action);
37
39
  }
38
40
  else if (name === 'HYPERLINK') {
39
41
  const target = arg(1);
40
- if (target !== undefined && !(0, links_1.isFragment)(target))
41
- ctx.link(target, location, { ...data, source: 'HYPERLINK field' });
42
+ if (target !== undefined && !(0, links_1.isFragment)(target)) {
43
+ const r = ctx.link(target, location, { ...data, source: 'HYPERLINK field' });
44
+ actions.push(r.action);
45
+ // The \o switch gives the tooltip.
46
+ const tip = words.findIndex(w => !w.quoted && w.text.toLowerCase() === '\\o');
47
+ const labels = [result, tip >= 0 ? words[tip + 1]?.text : undefined];
48
+ if (r.action !== 'strip') {
49
+ const m = ctx.labelMismatch(target, labels, location, { ...data, source: 'HYPERLINK field' });
50
+ if (m)
51
+ actions.push(m.action);
52
+ }
53
+ }
42
54
  }
55
+ return actions.includes('strip');
43
56
  }
44
57
  /**
45
58
  * Word field codes, followed through nested fields as the text of a document arrives: a field begins, its code
46
59
  * comes, a separator starts its result, and it ends. Each format says where those marks are.
47
60
  */
61
+ /** The most of a field's result that is kept, for the label check. */
62
+ const MAX_RESULT = 4096;
48
63
  class FieldStack {
49
64
  ctx;
50
65
  location;
66
+ onStrip;
51
67
  stack = [];
52
- constructor(ctx, location) {
68
+ /**
69
+ * `onStrip` hears of each field a strip finding names, with the marks the format gave its begin, separator and end,
70
+ * so the rewrite can find the field again.
71
+ */
72
+ constructor(ctx, location, onStrip) {
53
73
  this.ctx = ctx;
54
74
  this.location = location;
75
+ this.onStrip = onStrip;
55
76
  }
56
77
  /** A field starts. One that starts before its parent's code has a word in it makes that code at run time. */
57
- begin() {
78
+ begin(mark = -1) {
58
79
  this.nest();
59
- this.stack.push({ code: '', inCode: true, computed: false });
80
+ this.stack.push({ code: '', inCode: true, computed: false, marks: { begin: mark, simple: false }, result: '' });
60
81
  }
61
- /** A field that is all code, such as OOXML's fldSimple. */
62
- simple(code) {
82
+ /** A field whose code is given whole, such as OOXML's fldSimple, whose result follows until simpleEnd(). */
83
+ simpleBegin(code, mark = -1) {
63
84
  this.nest();
64
- evaluateField(this.ctx, this.location, code, false);
85
+ this.stack.push({ code, inCode: false, computed: false, marks: { begin: mark, simple: true }, result: '' });
65
86
  }
66
- separate() {
87
+ simpleEnd() {
67
88
  const top = this.stack[this.stack.length - 1];
68
- if (top)
69
- top.inCode = false;
89
+ if (!top?.marks.simple)
90
+ return;
91
+ this.stack.pop();
92
+ this.decide(top);
70
93
  }
71
- end() {
94
+ separate(mark = -1) {
95
+ const top = this.stack[this.stack.length - 1];
96
+ if (!top)
97
+ return;
98
+ top.inCode = false;
99
+ top.marks.separate ??= mark;
100
+ }
101
+ end(mark = -1) {
72
102
  const f = this.stack.pop();
73
- if (f)
74
- evaluateField(this.ctx, this.location, f.code, f.computed);
103
+ if (!f)
104
+ return;
105
+ f.marks.end = mark;
106
+ this.decide(f);
107
+ }
108
+ decide(f) {
109
+ if (evaluateField(this.ctx, this.location, f.code, f.computed, f.result))
110
+ this.onStrip?.(f.marks);
75
111
  }
76
112
  /** Whether a field's code is being read now. */
77
113
  get inCode() {
@@ -83,10 +119,16 @@ class FieldStack {
83
119
  if (top?.inCode && top.code.length < MAX_FIELD_CODE)
84
120
  top.code = top.code ? top.code + t : t.trimStart();
85
121
  }
122
+ /** Text of the innermost field's result, the text the reader sees. */
123
+ result(t) {
124
+ const top = this.stack[this.stack.length - 1];
125
+ if (top && !top.inCode && top.result.length < MAX_RESULT)
126
+ top.result += t;
127
+ }
86
128
  /** A document can end inside a field. Word still reads the code it has. */
87
129
  finish() {
88
130
  for (let f = this.stack.pop(); f; f = this.stack.pop())
89
- evaluateField(this.ctx, this.location, f.code, f.computed);
131
+ this.decide(f);
90
132
  }
91
133
  nest() {
92
134
  const top = this.stack[this.stack.length - 1];
@@ -19,7 +19,8 @@ export declare function allFindingSpecs(): Array<{
19
19
  export declare class FindingFactory {
20
20
  private readonly overrides;
21
21
  constructor(overrides?: OfficeActionOverride[]);
22
- private actionFor;
22
+ /** The action of a kind of finding, after the caller's overrides. */
23
+ actionFor(category: C, detail: D): OfficeFindingAction;
23
24
  make(category: C, detail: D, location?: string, data?: Record<string, string | number>): OfficeFinding;
24
25
  }
25
26
  export {};
package/dist/findings.js CHANGED
@@ -26,6 +26,7 @@ def(types_1.OfficeCategory.Container, types_1.OfficeDetail.BadExtraField, 'rejec
26
26
  def(types_1.OfficeCategory.Container, types_1.OfficeDetail.DataError, 'reject', 0, "An entry's data does not match its declared size or checksum<: {name}|>");
27
27
  def(types_1.OfficeCategory.Container, types_1.OfficeDetail.LeadingBytes, 'strip', 10, 'Data before the first entry of the archive');
28
28
  def(types_1.OfficeCategory.Container, types_1.OfficeDetail.HiddenData, 'strip', 20, 'Data in the file that no entry or stream covers');
29
+ def(types_1.OfficeCategory.Container, types_1.OfficeDetail.HiddenEntry, 'strip', 40, 'A local file header the central directory does not list, which a reader that walks the file in order extracts<: at offset {offset}|>');
29
30
  def(types_1.OfficeCategory.Container, types_1.OfficeDetail.TrailingBytes, 'strip', 10, 'Data after the end of the archive or compound file');
30
31
  def(types_1.OfficeCategory.Container, types_1.OfficeDetail.BadHeader, 'reject', 0, 'The compound file header is invalid<: {reason}|>');
31
32
  def(types_1.OfficeCategory.Container, types_1.OfficeDetail.BrokenChain, 'reject', 0, 'A sector chain of the compound file runs into a free or reserved sector');
@@ -49,18 +50,20 @@ def(types_1.OfficeCategory.Limit, types_1.OfficeDetail.XmlEntityDepth, 'reject',
49
50
  def(types_1.OfficeCategory.Limit, types_1.OfficeDetail.XmlEntityExpansions, 'reject', 0, 'The file exceeds the entity expansion limit');
50
51
  def(types_1.OfficeCategory.Limit, types_1.OfficeDetail.XmlEntitySize, 'reject', 0, 'The file exceeds the expanded entity size limit');
51
52
  def(types_1.OfficeCategory.Limit, types_1.OfficeDetail.RtfDepth, 'reject', 0, 'The RTF file exceeds the group nesting limit');
53
+ def(types_1.OfficeCategory.Limit, types_1.OfficeDetail.NestingDepth, 'reject', 0, 'The file sits deeper in the upload than the nesting limit allows');
52
54
  def(types_1.OfficeCategory.Limit, types_1.OfficeDetail.Time, 'reject', 0, 'The file exceeds the time limit');
53
55
  // PACKAGE
54
56
  def(types_1.OfficeCategory.Package, types_1.OfficeDetail.Unrecognized, 'reject', 0, 'The file is not a recognized Office or OpenDocument file');
55
57
  def(types_1.OfficeCategory.Package, types_1.OfficeDetail.AmbiguousFormat, 'reject', 0, 'The file can be read as more than one format');
56
58
  def(types_1.OfficeCategory.Package, types_1.OfficeDetail.Unreadable, 'reject', 0, 'The file could not be read');
59
+ def(types_1.OfficeCategory.Package, types_1.OfficeDetail.UnreadableBody, 'strip', 10, "An Outlook message's RTF body does not decompress<: {stream}|>");
57
60
  def(types_1.OfficeCategory.Package, types_1.OfficeDetail.DuplicateEntry, 'reject', 0, 'The package names one thing twice, and readers may pick either');
58
61
  def(types_1.OfficeCategory.Package, types_1.OfficeDetail.UntypedPart, 'strip', 10, 'A part has no content type<: {part}|>');
59
62
  def(types_1.OfficeCategory.Package, types_1.OfficeDetail.UnreferencedPart, 'strip', 0, 'A part nothing in the package refers to<: {part}|>');
60
63
  def(types_1.OfficeCategory.Package, types_1.OfficeDetail.OdfLayout, 'strip', 10, 'The OpenDocument package layout is irregular<: {reason}|>');
61
64
  // ENCRYPTED
62
65
  def(types_1.OfficeCategory.Encrypted, types_1.OfficeDetail.PasswordRequired, 'reject', 0, 'The document is encrypted with a password');
63
- def(types_1.OfficeCategory.Encrypted, types_1.OfficeDetail.DefaultPassword, 'strip', 10, 'The file is encrypted with VelvetSweatshop, the password Excel opens it with without asking');
66
+ def(types_1.OfficeCategory.Encrypted, types_1.OfficeDetail.DefaultPassword, 'strip', 10, 'The file is encrypted with <{password}|VelvetSweatshop>, the password <{application}|Excel> opens it with without asking');
64
67
  def(types_1.OfficeCategory.Encrypted, types_1.OfficeDetail.UserPassword, 'strip', 0, 'The file was decrypted with the supplied password');
65
68
  def(types_1.OfficeCategory.Encrypted, types_1.OfficeDetail.Rc4_40, 'info', 0, 'Encryption is RC4 with a 40-bit key');
66
69
  def(types_1.OfficeCategory.Encrypted, types_1.OfficeDetail.Rc4_128, 'info', 0, 'Encryption is RC4 with a 128-bit key');
@@ -68,6 +71,7 @@ def(types_1.OfficeCategory.Encrypted, types_1.OfficeDetail.Rc4Other, 'info', 0,
68
71
  def(types_1.OfficeCategory.Encrypted, types_1.OfficeDetail.Aes128, 'info', 0, 'Encryption is AES with a 128-bit key');
69
72
  def(types_1.OfficeCategory.Encrypted, types_1.OfficeDetail.Aes192, 'info', 0, 'Encryption is AES with a 192-bit key');
70
73
  def(types_1.OfficeCategory.Encrypted, types_1.OfficeDetail.Aes256, 'info', 0, 'Encryption is AES with a 256-bit key');
74
+ def(types_1.OfficeCategory.Encrypted, types_1.OfficeDetail.XorObfuscation, 'info', 0, 'Encryption is XOR obfuscation');
71
75
  def(types_1.OfficeCategory.Encrypted, types_1.OfficeDetail.UnsupportedAlgorithm, 'reject', 0, 'The file is encrypted with an algorithm office-defuse does not decrypt<: {algorithm}|>');
72
76
  // MACRO
73
77
  def(types_1.OfficeCategory.Macro, types_1.OfficeDetail.VbaProject, 'strip', 70, 'The document holds VBA macros');
@@ -85,6 +89,7 @@ def(types_1.OfficeCategory.Ui, types_1.OfficeDetail.Callback, 'strip', 30, 'The
85
89
  def(types_1.OfficeCategory.Ui, types_1.OfficeDetail.OdfConfiguration, 'strip', 10, 'The document carries its own menu, toolbar or key settings, which can call macros');
86
90
  // ACTION
87
91
  def(types_1.OfficeCategory.Action, types_1.OfficeDetail.RunProgram, 'strip', 80, 'A click or hover runs a program or opens a file');
92
+ def(types_1.OfficeCategory.Action, types_1.OfficeDetail.SubmitForm, 'strip', 40, 'A form sends its data to a URL<: {target}|>');
88
93
  def(types_1.OfficeCategory.Action, types_1.OfficeDetail.OleVerb, 'strip', 40, 'A click or hover activates an embedded object');
89
94
  def(types_1.OfficeCategory.Action, types_1.OfficeDetail.ObjectUpdate, 'strip', 50, 'An embedded object updates itself as the document opens, which starts the program it belongs to');
90
95
  // DDE
@@ -103,6 +108,7 @@ def(types_1.OfficeCategory.External, types_1.OfficeDetail.Include, 'strip', 40,
103
108
  def(types_1.OfficeCategory.External, types_1.OfficeDetail.Workbook, 'strip', 30, 'Formulas read another workbook at <{target}|another location>');
104
109
  def(types_1.OfficeCategory.External, types_1.OfficeDetail.Reload, 'strip', 40, 'The document loads <{target}|another address> on its own after a delay');
105
110
  def(types_1.OfficeCategory.External, types_1.OfficeDetail.Other, 'strip', 30, 'The document refers to <{target}|something outside the file>');
111
+ def(types_1.OfficeCategory.External, types_1.OfficeDetail.DataConnection, 'strip', 40, 'A data connection loads from outside the file<: {target}|>');
106
112
  def(types_1.OfficeCategory.External, types_1.OfficeDetail.LocalFile, 'strip', 5, 'The document refers to a local file<: {target}|>');
107
113
  // LINK
108
114
  def(types_1.OfficeCategory.Link, types_1.OfficeDetail.Safe, 'info', 0, 'Web or email link');
@@ -116,6 +122,9 @@ def(types_1.OfficeCategory.Link, types_1.OfficeDetail.IpHost, 'strip', 40, 'A li
116
122
  def(types_1.OfficeCategory.Link, types_1.OfficeDetail.LookalikeHost, 'strip', 40, "A link's host uses punycode or mixed scripts");
117
123
  def(types_1.OfficeCategory.Link, types_1.OfficeDetail.EncodedHost, 'strip', 40, "A link's host is percent-encoded");
118
124
  def(types_1.OfficeCategory.Link, types_1.OfficeDetail.Relative, 'strip', 30, "A relative link, which resolves against the file's own location");
125
+ def(types_1.OfficeCategory.Link, types_1.OfficeDetail.TextMismatch, 'strip', 40, "A link's text or tooltip names a different site than it opens");
126
+ def(types_1.OfficeCategory.External, types_1.OfficeDetail.Formula, 'strip', 40, 'A formula fetches from outside the file when it is calculated<: {function}|>');
127
+ def(types_1.OfficeCategory.Macro, types_1.OfficeDetail.Formula, 'strip', 60, 'A formula runs code outside the file when it is calculated<: {function}|>');
119
128
  // EMBEDDED
120
129
  def(types_1.OfficeCategory.Embedded, types_1.OfficeDetail.OleObject, 'strip', 40, 'An embedded OLE object<, which holds the file {fileName}|>');
121
130
  def(types_1.OfficeCategory.Embedded, types_1.OfficeDetail.Package, 'strip', 30, 'An embedded document<: {contentType}|>');
@@ -124,8 +133,14 @@ def(types_1.OfficeCategory.Embedded, types_1.OfficeDetail.Applet, 'strip', 60, '
124
133
  def(types_1.OfficeCategory.Embedded, types_1.OfficeDetail.Plugin, 'strip', 50, 'An embedded browser plug-in object');
125
134
  def(types_1.OfficeCategory.Embedded, types_1.OfficeDetail.Equation, 'strip', 70, 'An Equation Editor 3.0 object, which CVE-2017-11882 and CVE-2018-0802 exploit');
126
135
  def(types_1.OfficeCategory.Embedded, types_1.OfficeDetail.Attachment, 'strip', 30, '<An attached file "{name}"|An attached file> (<{type}|unknown type>)');
136
+ def(types_1.OfficeCategory.Embedded, types_1.OfficeDetail.PluginPassed, 'info', 20, 'An embedded file was kept by <plugin {plugin}|a plugin> with nothing removed');
137
+ def(types_1.OfficeCategory.Embedded, types_1.OfficeDetail.PluginScrubbed, 'info', 10, 'An embedded file was cleaned and kept by <plugin {plugin}|a plugin>');
138
+ def(types_1.OfficeCategory.Embedded, types_1.OfficeDetail.PluginFailed, 'strip', 0, '<Plugin {plugin}|A plugin> failed, so the embedded file was removed');
139
+ def(types_1.OfficeCategory.Embedded, types_1.OfficeDetail.PluginRemoved, 'strip', 0, 'An embedded file was removed by <plugin {plugin}|a plugin>');
127
140
  // CONTROL
128
141
  def(types_1.OfficeCategory.Control, types_1.OfficeDetail.ActiveX, 'strip', 50, 'An ActiveX control');
142
+ // PROCESSING
143
+ def(types_1.OfficeCategory.Processing, types_1.OfficeDetail.VerificationFailed, 'reject', 0, 'The defused output did not pass its own inspection, so nothing was written');
129
144
  /** The built-in spec for a kind of finding, or undefined for a kind office-defuse does not make, such as one from another package. */
130
145
  function findingSpec(category, detail) {
131
146
  return specs.get(`${category}/${detail}`);
@@ -151,6 +166,7 @@ class FindingFactory {
151
166
  constructor(overrides = []) {
152
167
  this.overrides = overrides;
153
168
  }
169
+ /** The action of a kind of finding, after the caller's overrides. */
154
170
  actionFor(category, detail) {
155
171
  const exact = this.overrides.find(o => o.category === category && o.detail === detail);
156
172
  if (exact)
package/dist/flat.d.ts ADDED
@@ -0,0 +1,33 @@
1
+ import { type Output, type RunContext, type RunState } from './context';
2
+ import type { Format } from './formats';
3
+ import type { PackagePlan } from './plan';
4
+ import { type ByteSink, type ByteSource } from './types';
5
+ import { type XmlLimits } from './xml';
6
+ import { type ZipLimits } from './zip';
7
+ /** The namespace of a Flat OPC package, the single-file form of OOXML that Word, Excel and PowerPoint save as XML. */
8
+ export declare const PKG_NS = "http://schemas.microsoft.com/office/2006/xmlPackage";
9
+ /** The name findings give the one part of a flat OpenDocument file. */
10
+ export declare const FLAT_ODF_PART = "office:document";
11
+ /** Flat OPC has no media type of its own, and Office saves it with the .xml extension. */
12
+ export declare const FLAT_OPC_FORMAT: Format;
13
+ /** Whether the first bytes of a file read as XML: a byte order mark, white space and then "<". */
14
+ export declare function startsAsXml(head: Uint8Array): boolean;
15
+ /**
16
+ * Whether the start of an XML file names a flat OpenDocument document or a Flat OPC package as its root element. The
17
+ * reading of the whole file decides; this tells a router which package to try.
18
+ */
19
+ export declare function isFlatHead(text: string): boolean;
20
+ /**
21
+ * Inspects a flat XML file: flat OpenDocument, read with the OpenDocument rules over its one part, or Flat OPC,
22
+ * which is unpacked into a package of its parts and read with the OOXML rules. Returns what the rewrite needs.
23
+ */
24
+ export declare function inspectFlat(ctx: RunContext, src: ByteSource, size: number, zipLimits: ZipLimits): Promise<Output | undefined>;
25
+ /** Writes a flat OpenDocument file without what the plan removes. */
26
+ export declare function writeFlatOdf(run: RunState, src: ByteSource, plan: PackagePlan, limits: XmlLimits, sink: ByteSink): Promise<void>;
27
+ /**
28
+ * Writes a Flat OPC package without what the plan removes: the package is rewritten as any OOXML package is, and its
29
+ * parts are written back into one XML file, each with its name, content type and attributes.
30
+ */
31
+ export declare function writeFlatOpc(run: RunState, output: Extract<Output, {
32
+ kind: 'flatopc';
33
+ }>, limits: XmlLimits, zipLimits: ZipLimits, sink: ByteSink): Promise<void>;