@l1yp/file-viewer 0.1.4 → 0.1.6

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 (177) hide show
  1. package/README.md +57 -6
  2. package/dist/assets/step.worker-CfDTYOf_.js.map +1 -0
  3. package/dist/components/AnsiText.d.ts +47 -0
  4. package/dist/components/AnsiText.js +41 -0
  5. package/dist/components/AnsiText.js.map +1 -0
  6. package/dist/components/CertViewer.js +1 -1
  7. package/dist/components/CertViewer.js.map +1 -1
  8. package/dist/components/CertViewer.vue_vue_type_script_setup_true_lang.js.map +1 -1
  9. package/dist/components/CodeView.js +1 -1
  10. package/dist/components/CodeView.js.map +1 -1
  11. package/dist/components/CodeView.vue_vue_type_script_setup_true_lang.js +80 -71
  12. package/dist/components/CodeView.vue_vue_type_script_setup_true_lang.js.map +1 -1
  13. package/dist/components/DocxEmbeddedFiles.js +9 -0
  14. package/dist/components/DocxEmbeddedFiles.js.map +1 -0
  15. package/dist/components/DocxEmbeddedFiles.vue.d.ts +15 -0
  16. package/dist/components/DocxEmbeddedFiles.vue_vue_type_script_setup_true_lang.js +69 -0
  17. package/dist/components/DocxEmbeddedFiles.vue_vue_type_script_setup_true_lang.js.map +1 -0
  18. package/dist/components/DocxNavigationPane.js +1 -1
  19. package/dist/components/DocxNavigationPane.js.map +1 -1
  20. package/dist/components/DocxNavigationPane.vue_vue_type_script_setup_true_lang.js.map +1 -1
  21. package/dist/components/DocxViewer.js +1 -1
  22. package/dist/components/DocxViewer.js.map +1 -1
  23. package/dist/components/DocxViewer.vue.d.ts +1 -1
  24. package/dist/components/DocxViewer.vue_vue_type_script_setup_true_lang.js +182 -50
  25. package/dist/components/DocxViewer.vue_vue_type_script_setup_true_lang.js.map +1 -1
  26. package/dist/components/EplViewer.js +1 -1
  27. package/dist/components/EplViewer.js.map +1 -1
  28. package/dist/components/EplViewer.vue_vue_type_script_setup_true_lang.js.map +1 -1
  29. package/dist/components/FileViewerBody.js +1 -1
  30. package/dist/components/FileViewerBody.js.map +1 -1
  31. package/dist/components/FileViewerBody.vue.d.ts +1 -0
  32. package/dist/components/FileViewerBody.vue_vue_type_script_setup_true_lang.js +292 -281
  33. package/dist/components/FileViewerBody.vue_vue_type_script_setup_true_lang.js.map +1 -1
  34. package/dist/components/FileViewerPanel.js +1 -1
  35. package/dist/components/FileViewerPanel.js.map +1 -1
  36. package/dist/components/FileViewerPanel.vue.d.ts +6 -1
  37. package/dist/components/FileViewerPanel.vue_vue_type_script_setup_true_lang.js +53 -51
  38. package/dist/components/FileViewerPanel.vue_vue_type_script_setup_true_lang.js.map +1 -1
  39. package/dist/components/HarViewer.js +1 -1
  40. package/dist/components/HarViewer.js.map +1 -1
  41. package/dist/components/HarViewer.vue_vue_type_script_setup_true_lang.js.map +1 -1
  42. package/dist/components/JksViewer.js +1 -1
  43. package/dist/components/JksViewer.js.map +1 -1
  44. package/dist/components/JksViewer.vue_vue_type_script_setup_true_lang.js.map +1 -1
  45. package/dist/components/LogViewer.js +1 -1
  46. package/dist/components/LogViewer.js.map +1 -1
  47. package/dist/components/LogViewer.vue.d.ts +3 -1
  48. package/dist/components/LogViewer.vue_vue_type_script_setup_true_lang.js +284 -280
  49. package/dist/components/LogViewer.vue_vue_type_script_setup_true_lang.js.map +1 -1
  50. package/dist/components/ModelViewModes.js +9 -0
  51. package/dist/components/ModelViewModes.js.map +1 -0
  52. package/dist/components/ModelViewModes.vue.d.ts +11 -0
  53. package/dist/components/ModelViewModes.vue_vue_type_script_setup_true_lang.js +49 -0
  54. package/dist/components/ModelViewModes.vue_vue_type_script_setup_true_lang.js.map +1 -0
  55. package/dist/components/ModelViewer.js +1 -1
  56. package/dist/components/ModelViewer.js.map +1 -1
  57. package/dist/components/ModelViewer.vue.d.ts +2 -1
  58. package/dist/components/ModelViewer.vue_vue_type_script_setup_true_lang.js +183 -96
  59. package/dist/components/ModelViewer.vue_vue_type_script_setup_true_lang.js.map +1 -1
  60. package/dist/components/PdfNavigationPane.js +1 -1
  61. package/dist/components/PdfNavigationPane.js.map +1 -1
  62. package/dist/components/PdfNavigationPane.vue_vue_type_script_setup_true_lang.js.map +1 -1
  63. package/dist/components/PdfViewer.js +1 -1
  64. package/dist/components/PdfViewer.js.map +1 -1
  65. package/dist/components/PdfViewer.vue_vue_type_script_setup_true_lang.js.map +1 -1
  66. package/dist/components/PptxNavigationPane.js +1 -1
  67. package/dist/components/PptxNavigationPane.js.map +1 -1
  68. package/dist/components/PptxNavigationPane.vue_vue_type_script_setup_true_lang.js.map +1 -1
  69. package/dist/components/PsdViewer.js +1 -1
  70. package/dist/components/PsdViewer.js.map +1 -1
  71. package/dist/components/PsdViewer.vue_vue_type_script_setup_true_lang.js.map +1 -1
  72. package/dist/components/SqliteViewer.js +1 -1
  73. package/dist/components/SqliteViewer.js.map +1 -1
  74. package/dist/components/SqliteViewer.vue_vue_type_script_setup_true_lang.js.map +1 -1
  75. package/dist/components/ViewerLoadError.js +9 -0
  76. package/dist/components/ViewerLoadError.js.map +1 -0
  77. package/dist/components/ViewerLoadError.vue.d.ts +17 -0
  78. package/dist/components/ViewerLoadError.vue_vue_type_script_setup_true_lang.js +58 -0
  79. package/dist/components/ViewerLoadError.vue_vue_type_script_setup_true_lang.js.map +1 -0
  80. package/dist/components/XlsxChart.js +1 -1
  81. package/dist/components/XlsxChart.js.map +1 -1
  82. package/dist/components/XlsxChart.vue_vue_type_script_setup_true_lang.js +9 -9
  83. package/dist/components/XlsxChart.vue_vue_type_script_setup_true_lang.js.map +1 -1
  84. package/dist/components/XlsxImageLayer.js +9 -0
  85. package/dist/components/XlsxImageLayer.js.map +1 -0
  86. package/dist/components/XlsxImageLayer.vue.d.ts +9 -0
  87. package/dist/components/XlsxImageLayer.vue_vue_type_script_setup_true_lang.js +46 -0
  88. package/dist/components/XlsxImageLayer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  89. package/dist/components/XlsxViewer.js +1 -1
  90. package/dist/components/XlsxViewer.js.map +1 -1
  91. package/dist/components/XlsxViewer.vue_vue_type_script_setup_true_lang.js +230 -216
  92. package/dist/components/XlsxViewer.vue_vue_type_script_setup_true_lang.js.map +1 -1
  93. package/dist/components/epl/EplResource.js +1 -1
  94. package/dist/components/epl/EplResource.js.map +1 -1
  95. package/dist/components/epl/EplResource.vue_vue_type_script_setup_true_lang.js.map +1 -1
  96. package/dist/components/optionalViewer.d.ts +3 -2
  97. package/dist/components/optionalViewer.js +6 -3
  98. package/dist/components/optionalViewer.js.map +1 -1
  99. package/dist/composables/useFileViewer.d.ts +11 -3
  100. package/dist/composables/useFileViewer.js.map +1 -1
  101. package/dist/composables/useTeleportTheme.d.ts +7 -0
  102. package/dist/composables/useTeleportTheme.js +42 -0
  103. package/dist/composables/useTeleportTheme.js.map +1 -0
  104. package/dist/index.d.ts +1 -0
  105. package/dist/index.js +29 -28
  106. package/dist/lib/ansi.d.ts +44 -0
  107. package/dist/lib/ansi.js +224 -0
  108. package/dist/lib/ansi.js.map +1 -0
  109. package/dist/lib/cfb.d.ts +37 -0
  110. package/dist/lib/cfb.js +112 -0
  111. package/dist/lib/cfb.js.map +1 -0
  112. package/dist/lib/docxEmbeddedDom.d.ts +22 -0
  113. package/dist/lib/docxEmbeddedDom.js +128 -0
  114. package/dist/lib/docxEmbeddedDom.js.map +1 -0
  115. package/dist/lib/docxEmbeddings.d.ts +41 -0
  116. package/dist/lib/docxEmbeddings.js +226 -0
  117. package/dist/lib/docxEmbeddings.js.map +1 -0
  118. package/dist/lib/docxTheme.d.ts +6 -0
  119. package/dist/lib/docxTheme.js +64 -0
  120. package/dist/lib/docxTheme.js.map +1 -0
  121. package/dist/lib/epl/code/structures.js +82 -0
  122. package/dist/lib/epl/code/structures.js.map +1 -0
  123. package/dist/lib/epl/code/variable.js +16 -0
  124. package/dist/lib/epl/code/variable.js.map +1 -0
  125. package/dist/lib/epl/eplDocument.js +28 -22
  126. package/dist/lib/epl/eplDocument.js.map +1 -1
  127. package/dist/lib/epl/index.d.ts +2 -1
  128. package/dist/lib/epl/index.js.map +1 -1
  129. package/dist/lib/epl/sections/code.js +37 -0
  130. package/dist/lib/epl/sections/code.js.map +1 -0
  131. package/dist/lib/epl/sections/esystemInfo.js +29 -0
  132. package/dist/lib/epl/sections/esystemInfo.js.map +1 -0
  133. package/dist/lib/epl/sections/losable.js +33 -0
  134. package/dist/lib/epl/sections/losable.js.map +1 -0
  135. package/dist/lib/epl/sections/projectConfig.js +39 -0
  136. package/dist/lib/epl/sections/projectConfig.js.map +1 -0
  137. package/dist/lib/epl/sections/resource.js +84 -0
  138. package/dist/lib/epl/sections/resource.js.map +1 -0
  139. package/dist/lib/fileType.d.ts +3 -1
  140. package/dist/lib/fileType.js +150 -137
  141. package/dist/lib/fileType.js.map +1 -1
  142. package/dist/lib/modelAppearance.d.ts +7 -0
  143. package/dist/lib/modelAppearance.js +41 -0
  144. package/dist/lib/modelAppearance.js.map +1 -0
  145. package/dist/lib/msi.js +62 -154
  146. package/dist/lib/msi.js.map +1 -1
  147. package/dist/lib/olePackage.d.ts +8 -0
  148. package/dist/lib/olePackage.js +37 -0
  149. package/dist/lib/olePackage.js.map +1 -0
  150. package/dist/lib/pptxFirstSlide.d.ts +11 -0
  151. package/dist/lib/pptxFirstSlide.js +34 -0
  152. package/dist/lib/pptxFirstSlide.js.map +1 -0
  153. package/dist/lib/step.d.ts +10 -0
  154. package/dist/lib/step.js +35 -0
  155. package/dist/lib/step.js.map +1 -0
  156. package/dist/lib/step.worker.d.ts +1 -0
  157. package/dist/lib/step.worker.js +18 -0
  158. package/dist/lib/step.worker.js.map +1 -0
  159. package/dist/lib/stepObject.d.ts +4 -0
  160. package/dist/lib/stepObject.js +52 -0
  161. package/dist/lib/stepObject.js.map +1 -0
  162. package/dist/lib/stepTypes.d.ts +60 -0
  163. package/dist/lib/viewerKind.js +10 -5
  164. package/dist/lib/viewerKind.js.map +1 -1
  165. package/dist/lib/xlsx.d.ts +1 -1
  166. package/dist/lib/xlsx.js +106 -89
  167. package/dist/lib/xlsx.js.map +1 -1
  168. package/dist/lib/xlsxCharts.js +71 -119
  169. package/dist/lib/xlsxCharts.js.map +1 -1
  170. package/dist/lib/xlsxImages.d.ts +43 -0
  171. package/dist/lib/xlsxImages.js +114 -0
  172. package/dist/lib/xlsxImages.js.map +1 -0
  173. package/dist/lib/xlsxParts.d.ts +17 -0
  174. package/dist/lib/xlsxParts.js +86 -0
  175. package/dist/lib/xlsxParts.js.map +1 -0
  176. package/dist/style.css +1 -1
  177. package/package.json +8 -3
package/dist/lib/msi.js CHANGED
@@ -1,126 +1,28 @@
1
+ import { CompoundFile as e, CompoundFileError as t } from "./cfb.js";
1
2
  //#region src/lib/msi.ts
2
- var e = class extends Error {
3
+ var n = class extends Error {
3
4
  constructor(e) {
4
5
  super(e), this.name = "NotMsiError";
5
6
  }
6
- }, t = [
7
- 208,
8
- 207,
9
- 17,
10
- 224,
11
- 161,
12
- 177,
13
- 26,
14
- 225
15
- ], n = 4294967294, r = 4294967295, i = class {
16
- dv;
17
- buf;
18
- sectorSize;
19
- miniSectorSize;
20
- miniCutoff;
21
- fat = [];
22
- miniFat = [];
23
- miniStream = new Uint8Array();
24
- entries = [];
25
- constructor(i) {
26
- this.buf = i;
27
- let a = new DataView(i);
28
- if (this.dv = a, i.byteLength < 512) throw new e("文件过小,不是有效的复合文件");
29
- for (let n = 0; n < 8; n++) if (a.getUint8(n) !== t[n]) throw new e("不是 OLE 复合文件(缺少 D0CF11E0 魔数)");
30
- let o = a.getUint16(26, !0);
31
- this.sectorSize = 1 << a.getUint16(30, !0), this.miniSectorSize = 1 << a.getUint16(32, !0);
32
- let s = a.getUint32(48, !0);
33
- this.miniCutoff = a.getUint32(56, !0);
34
- let c = a.getUint32(60, !0), l = a.getUint32(68, !0), u = this.sectorSize / 4, d = [];
35
- for (let e = 0; e < 109; e++) {
36
- let t = a.getUint32(76 + e * 4, !0);
37
- t !== r && t !== n && d.push(t);
38
- }
39
- let f = l, p = 0;
40
- for (; f !== n && f !== r && p++ < 1e6;) {
41
- let e = this.sectorOffset(f);
42
- for (let t = 0; t < u - 1; t++) {
43
- let n = a.getUint32(e + t * 4, !0);
44
- n !== r && d.push(n);
45
- }
46
- f = a.getUint32(e + (u - 1) * 4, !0);
47
- }
48
- for (let e of d) {
49
- let t = this.sectorOffset(e);
50
- for (let e = 0; e < u; e++) this.fat.push(a.getUint32(t + e * 4, !0));
51
- }
52
- let m = this.readFatStream(s, this.chain(s).length * this.sectorSize), h = new DataView(m.buffer, m.byteOffset, m.byteLength);
53
- for (let e = 0; e + 128 <= m.length; e += 128) {
54
- let t = h.getUint8(e + 66);
55
- if (t === 0) continue;
56
- let n = h.getUint16(e + 64, !0), r = "";
57
- for (let t = 0; t + 1 < n; t += 2) {
58
- let n = h.getUint16(e + t, !0);
59
- if (n === 0) break;
60
- r += String.fromCharCode(n);
61
- }
62
- let i = h.getUint32(e + 116, !0), a = o <= 3 ? h.getUint32(e + 120, !0) : Number(h.getBigUint64(e + 120, !0));
63
- this.entries.push({
64
- name: r,
65
- type: t,
66
- start: i,
67
- size: a
68
- });
69
- }
70
- let g = this.entries.find((e) => e.type === 5);
71
- g && (this.miniStream = this.readFatStream(g.start, g.size));
72
- for (let e of this.chain(c)) {
73
- let t = this.sectorOffset(e);
74
- for (let e = 0; e < u; e++) this.miniFat.push(a.getUint32(t + e * 4, !0));
75
- }
76
- }
77
- sectorOffset(e) {
78
- return (e + 1) * this.sectorSize;
79
- }
80
- chain(e) {
81
- let t = [], i = e, a = 0;
82
- for (; i !== n && i !== r && i < this.fat.length && a++ < 1e7;) t.push(i), i = this.fat[i];
83
- return t;
84
- }
85
- sectorBytes(e) {
86
- let t = this.sectorOffset(e), n = Math.min(this.buf.byteLength, t + this.sectorSize), r = new Uint8Array(this.sectorSize);
87
- return t < this.buf.byteLength && r.set(new Uint8Array(this.buf, t, n - t)), r;
88
- }
89
- readFatStream(e, t) {
90
- let n = this.chain(e), r = new Uint8Array(n.length * this.sectorSize);
91
- for (let e = 0; e < n.length; e++) r.set(this.sectorBytes(n[e]), e * this.sectorSize);
92
- return r.subarray(0, t);
93
- }
94
- readMiniStream(e, t) {
95
- let i = Math.ceil(t / this.miniSectorSize), a = new Uint8Array(i * this.miniSectorSize), o = e, s = 0;
96
- for (; o !== n && o !== r && s < i;) {
97
- let e = o * this.miniSectorSize;
98
- a.set(this.miniStream.subarray(e, e + this.miniSectorSize), s * this.miniSectorSize), s++, o = this.miniFat[o];
99
- }
100
- return a.subarray(0, t);
101
- }
102
- stream(e) {
103
- return e.size === 0 ? new Uint8Array() : e.type === 5 || e.size >= this.miniCutoff ? this.readFatStream(e.start, e.size) : this.readMiniStream(e.start, e.size);
104
- }
105
7
  };
106
- function a(e) {
8
+ function r(e) {
107
9
  return e < 10 ? String.fromCharCode(e + 48) : e < 36 ? String.fromCharCode(e - 10 + 65) : e < 62 ? String.fromCharCode(e - 36 + 97) : e === 62 ? "." : "_";
108
10
  }
109
- function o(e) {
11
+ function i(e) {
110
12
  let t = "", n = !1;
111
- for (let r = 0; r < e.length; r++) {
112
- let i = e.charCodeAt(r);
113
- if (i >= 14336 && i < 18432) {
114
- let e = i - 14336;
115
- t += a(e & 63) + a(e >> 6 & 63);
116
- } else i >= 18432 && i < 18496 ? t += a(i - 18432) : i === 18496 ? n = !0 : t += String.fromCharCode(i);
13
+ for (let i = 0; i < e.length; i++) {
14
+ let a = e.charCodeAt(i);
15
+ if (a >= 14336 && a < 18432) {
16
+ let e = a - 14336;
17
+ t += r(e & 63) + r(e >> 6 & 63);
18
+ } else a >= 18432 && a < 18496 ? t += r(a - 18432) : a === 18496 ? n = !0 : t += String.fromCharCode(a);
117
19
  }
118
20
  return {
119
21
  name: t,
120
22
  isTable: n
121
23
  };
122
24
  }
123
- function s(e) {
25
+ function a(e) {
124
26
  let t = new DataView(e.buffer, e.byteOffset, e.byteLength), n = t.getUint32(44, !0), r = t.getUint32(n + 4, !0), i = [];
125
27
  for (let e = 0; e < r; e++) {
126
28
  let r = t.getUint32(n + 8 + e * 8, !0), a = t.getUint32(n + 8 + e * 8 + 4, !0);
@@ -134,7 +36,7 @@ function s(e) {
134
36
  let e = t.getInt16(o.abs + 4, !0);
135
37
  e < 0 && (e += 65536), a = e;
136
38
  }
137
- let s = new TextDecoder(p(a)), c = /* @__PURE__ */ new Map();
39
+ let s = new TextDecoder(d(a)), c = /* @__PURE__ */ new Map();
138
40
  for (let { pid: n, abs: r } of i) {
139
41
  let i = t.getUint32(r, !0);
140
42
  if (i === 2) c.set(n, {
@@ -153,7 +55,7 @@ function s(e) {
153
55
  });
154
56
  } else i === 64 && c.set(n, {
155
57
  type: i,
156
- value: m(t.getUint32(r + 4, !0), t.getUint32(r + 8, !0))
58
+ value: f(t.getUint32(r + 4, !0), t.getUint32(r + 8, !0))
157
59
  });
158
60
  }
159
61
  return {
@@ -161,7 +63,7 @@ function s(e) {
161
63
  props: c
162
64
  };
163
65
  }
164
- function c(e) {
66
+ function o(e) {
165
67
  let t = [], n = (n, r, i) => {
166
68
  let a = e.get(n);
167
69
  if (a == null) return;
@@ -171,12 +73,12 @@ function c(e) {
171
73
  value: o
172
74
  });
173
75
  };
174
- return n(3, "主题", String), n(4, "作者 / 厂商", String), n(6, "备注", String), n(2, "标题", String), n(5, "关键字", String), n(7, "平台 / 语言", (e) => h(String(e))), n(9, "包代码", String), n(18, "制作工具", String), n(12, "创建时间", String), n(13, "上次保存", String), n(14, "架构版本", (e) => g(Number(e))), n(15, "源类型", (e) => _(Number(e))), n(19, "安全", (e) => v(Number(e))), t;
76
+ return n(3, "主题", String), n(4, "作者 / 厂商", String), n(6, "备注", String), n(2, "标题", String), n(5, "关键字", String), n(7, "平台 / 语言", (e) => p(String(e))), n(9, "包代码", String), n(18, "制作工具", String), n(12, "创建时间", String), n(13, "上次保存", String), n(14, "架构版本", (e) => m(Number(e))), n(15, "源类型", (e) => h(Number(e))), n(19, "安全", (e) => g(Number(e))), t;
175
77
  }
176
- function l(e, t, n) {
78
+ function s(e, t, n) {
177
79
  let r = new DataView(e.buffer, e.byteOffset, e.byteLength), i = r.getUint16(0, !0) | r.getUint16(2, !0) << 16, a = (i & 2147483648) != 0, o = i & 2147483647;
178
80
  o === 0 && (o = n || 1252);
179
- let s = new TextDecoder(p(o)), c = [""], l = 0, u = Math.floor(e.length / 4);
81
+ let s = new TextDecoder(d(o)), c = [""], l = 0, u = Math.floor(e.length / 4);
180
82
  for (let e = 1; e < u; e++) {
181
83
  let n = r.getUint16(e * 4, !0);
182
84
  if (n === 0) {
@@ -190,7 +92,7 @@ function l(e, t, n) {
190
92
  longRefs: a
191
93
  };
192
94
  }
193
- function u(e, t) {
95
+ function c(e, t) {
194
96
  let n = t.longRefs ? 3 : 2, r = new DataView(e.buffer, e.byteOffset, e.byteLength), i = Math.floor(e.length / (n * 2)), a = (e) => {
195
97
  let t = e * n, i = r.getUint16(t, !0);
196
98
  return n === 3 && (i += r.getUint8(t + 2) << 16), i;
@@ -204,42 +106,48 @@ function u(e, t) {
204
106
  }
205
107
  return o;
206
108
  }
207
- function d(e) {
208
- let t = new i(e), n = t.entries.map((e) => ({
209
- e,
210
- ...o(e.name)
211
- })), r = [], a = n.filter((e) => e.isTable).map((e) => e.name).sort((e, t) => e.localeCompare(t)), d = [], p = 0, m = n.find((e) => e.name === "SummaryInformation");
212
- if (m) try {
213
- let e = s(t.stream(m.e));
214
- p = e.codepage, d = c(e.props);
109
+ function l(r) {
110
+ let l;
111
+ try {
112
+ l = new e(r);
215
113
  } catch (e) {
216
- r.push("SummaryInformation 解析失败:" + f(e));
114
+ throw e instanceof t ? new n(e.message) : e;
217
115
  }
218
- let h = [], g = n.find((e) => e.name === "_StringData"), _ = n.find((e) => e.name === "_StringPool"), v = n.find((e) => e.name === "Property");
219
- if (g && _ && v) try {
220
- let e = l(t.stream(_.e), t.stream(g.e), p);
221
- h = u(t.stream(v.e), e);
116
+ let d = l.entries.map((e) => ({
117
+ e,
118
+ ...i(e.name)
119
+ })), f = [], p = d.filter((e) => e.isTable).map((e) => e.name).sort((e, t) => e.localeCompare(t)), m = [], h = 0, g = d.find((e) => e.name === "SummaryInformation");
120
+ if (g) try {
121
+ let e = a(l.stream(g.e));
122
+ h = e.codepage, m = o(e.props);
222
123
  } catch (e) {
223
- r.push("Property 表解析失败:" + f(e));
124
+ f.push("SummaryInformation 解析失败:" + u(e));
224
125
  }
225
- let y = new Map(h.map((e) => [e.name, e.value])), x = y.get("ProductLanguage"), S = {
226
- productName: y.get("ProductName"),
227
- productVersion: y.get("ProductVersion"),
228
- manufacturer: y.get("Manufacturer"),
229
- productCode: y.get("ProductCode"),
230
- upgradeCode: y.get("UpgradeCode"),
231
- language: x ? b(x) : void 0,
232
- properties: h,
233
- summary: d,
234
- tables: a,
235
- notes: r
126
+ let _ = [], y = d.find((e) => e.name === "_StringData"), b = d.find((e) => e.name === "_StringPool"), x = d.find((e) => e.name === "Property");
127
+ if (y && b && x) try {
128
+ let e = s(l.stream(b.e), l.stream(y.e), h);
129
+ _ = c(l.stream(x.e), e);
130
+ } catch (e) {
131
+ f.push("Property 表解析失败:" + u(e));
132
+ }
133
+ let S = new Map(_.map((e) => [e.name, e.value])), C = S.get("ProductLanguage"), w = {
134
+ productName: S.get("ProductName"),
135
+ productVersion: S.get("ProductVersion"),
136
+ manufacturer: S.get("Manufacturer"),
137
+ productCode: S.get("ProductCode"),
138
+ upgradeCode: S.get("UpgradeCode"),
139
+ language: C ? v(C) : void 0,
140
+ properties: _,
141
+ summary: m,
142
+ tables: p,
143
+ notes: f
236
144
  };
237
- return !h.length && !d.length && r.push("未找到 MSI 摘要信息或属性表(可能是别的复合文件,而非 MSI 数据库)"), S;
145
+ return !_.length && !m.length && f.push("未找到 MSI 摘要信息或属性表(可能是别的复合文件,而非 MSI 数据库)"), w;
238
146
  }
239
- function f(e) {
147
+ function u(e) {
240
148
  return e instanceof Error ? e.message : String(e);
241
149
  }
242
- function p(e) {
150
+ function d(e) {
243
151
  switch (e) {
244
152
  case 65001: return "utf-8";
245
153
  case 1200: return "utf-16le";
@@ -259,7 +167,7 @@ function p(e) {
259
167
  default: return "windows-1252";
260
168
  }
261
169
  }
262
- function m(e, t) {
170
+ function f(e, t) {
263
171
  let n = t * 4294967296 + e;
264
172
  if (!n) return "";
265
173
  let r = n / 1e4 - 0xa9730b66800, i = new Date(r);
@@ -267,18 +175,18 @@ function m(e, t) {
267
175
  let a = (e) => String(e).padStart(2, "0");
268
176
  return `${i.getUTCFullYear()}-${a(i.getUTCMonth() + 1)}-${a(i.getUTCDate())} ${a(i.getUTCHours())}:${a(i.getUTCMinutes())} UTC`;
269
177
  }
270
- function h(e) {
271
- let [t, n] = e.split(";"), r = (n ?? "").split(",").map((e) => e.trim()).filter(Boolean).map((e) => b(e)), i = [];
178
+ function p(e) {
179
+ let [t, n] = e.split(";"), r = (n ?? "").split(",").map((e) => e.trim()).filter(Boolean).map((e) => v(e)), i = [];
272
180
  return t && t.trim() && i.push(t.trim()), r.length && i.push(r.join(", ")), i.join(" · ") || e;
273
181
  }
274
- function g(e) {
182
+ function m(e) {
275
183
  return e ? `${Math.floor(e / 100)}.${String(e % 100).padStart(2, "0")}` : "";
276
184
  }
277
- function _(e) {
185
+ function h(e) {
278
186
  let t = [];
279
187
  return t.push(e & 2 ? "压缩 (cabinet)" : "未压缩"), e & 1 && t.push("短文件名"), e & 4 && t.push("管理映像"), e & 8 && t.push("从源运行"), t.join(" · ");
280
188
  }
281
- function v(e) {
189
+ function g(e) {
282
190
  switch (e) {
283
191
  case 0: return "无限制";
284
192
  case 1: return "建议只读";
@@ -287,7 +195,7 @@ function v(e) {
287
195
  default: return String(e);
288
196
  }
289
197
  }
290
- var y = {
198
+ var _ = {
291
199
  0: "语言中性",
292
200
  1025: "阿拉伯语",
293
201
  1028: "中文(繁体)",
@@ -324,11 +232,11 @@ var y = {
324
232
  3082: "西班牙语(西班牙)",
325
233
  4100: "中文(新加坡)"
326
234
  };
327
- function b(e) {
328
- let t = y[Number(e)];
235
+ function v(e) {
236
+ let t = _[Number(e)];
329
237
  return t ? `${t} (${e})` : e;
330
238
  }
331
239
  //#endregion
332
- export { e as NotMsiError, d as parseMsi };
240
+ export { n as NotMsiError, l as parseMsi };
333
241
 
334
242
  //# sourceMappingURL=msi.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"msi.js","names":[],"sources":["../../src/lib/msi.ts"],"sourcesContent":["/**\n * Minimal in-browser MSI (Windows Installer) reader — no dependency, no WASM.\n *\n * An `.msi` is NOT a PE executable (that's `.exe`/`.dll` — see lib/binobj.ts), and NOT a zip (that's\n * `.appx`/`.msix` — see lib/appx.ts). It's an OLE2 **Compound File** (a.k.a. structured storage / CFBF):\n * a mini-filesystem of \"streams\" inside one file (the same container legacy `.doc`/`.xls`/`.msg` use). The\n * install metadata we surface lives in two of those streams:\n * - the standard **SummaryInformation** property set (`\\x05SummaryInformation`): title / subject / author /\n * comments, the target platform+language template, the package (revision) code, the authoring tool, dates.\n * - the **Property table** (ProductName / ProductVersion / ProductCode / UpgradeCode / Manufacturer / …),\n * spread across the MSI string pool (`_StringData` + `_StringPool`) and the `Property` table stream.\n *\n * We parse only what a \"what is this installer?\" view needs — never the embedded cabinet / payload files.\n * The logic is validated byte-for-byte against real installers using the Windows `WindowsInstaller.Installer`\n * COM automation as an oracle (the Property table + SummaryInformation match it exactly).\n *\n * Used by MsiViewer (the side viewer's MSI mode): the bytes come from the same download endpoint as any\n * other file, are parsed entirely client-side, and never leave the browser.\n */\n\nexport interface MsiMeta {\n label: string\n value: string\n}\nexport interface MsiProperty {\n name: string\n value: string\n}\n\nexport interface MsiInfo {\n /** Resolved product identity from the Property table (any field may be absent if the table is unreadable). */\n productName?: string\n productVersion?: string\n manufacturer?: string\n productCode?: string\n upgradeCode?: string\n /** Install language: a human label when the LCID is recognized (with the raw id), else the raw id. */\n language?: string\n /** Full Property table (name → value), in stored order. Empty if the table couldn't be decoded. */\n properties: MsiProperty[]\n /** SummaryInformation rows, pre-labeled (Chinese), in display order. */\n summary: MsiMeta[]\n /** Decoded names of the database tables present — a quick \"shape of the installer\" cue. */\n tables: string[]\n /** Non-fatal notes (e.g. the Property table was unreadable but SummaryInformation succeeded). */\n notes: string[]\n}\n\n/** Thrown when the bytes aren't an OLE compound file at all (so the viewer can show a clear message). */\nexport class NotMsiError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'NotMsiError'\n }\n}\n\n// ── Compound File (CFBF / MS-CFB) reader ────────────────────────────────────────────────────────────\nconst CFB_SIG = [0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1]\nconst ENDOFCHAIN = 0xfffffffe\nconst FREESECT = 0xffffffff\n\ninterface CfbEntry {\n /** Raw UTF-16 directory name (null-stripped) — MSI table names are still mangled (see decodeStreamName). */\n name: string\n /** 1 = storage, 2 = stream, 5 = root storage. */\n type: number\n start: number\n size: number\n}\n\nclass Cfb {\n private dv: DataView\n private buf: ArrayBuffer\n private sectorSize: number\n private miniSectorSize: number\n private miniCutoff: number\n private fat: number[] = []\n private miniFat: number[] = []\n private miniStream: Uint8Array = new Uint8Array(0)\n readonly entries: CfbEntry[] = []\n\n constructor(buf: ArrayBuffer) {\n this.buf = buf\n const dv = new DataView(buf)\n this.dv = dv\n if (buf.byteLength < 512) throw new NotMsiError('文件过小,不是有效的复合文件')\n for (let i = 0; i < 8; i++) {\n if (dv.getUint8(i) !== CFB_SIG[i]) {\n throw new NotMsiError('不是 OLE 复合文件(缺少 D0CF11E0 魔数)')\n }\n }\n const major = dv.getUint16(0x1a, true)\n this.sectorSize = 1 << dv.getUint16(0x1e, true)\n this.miniSectorSize = 1 << dv.getUint16(0x20, true)\n const firstDir = dv.getUint32(0x30, true)\n this.miniCutoff = dv.getUint32(0x38, true)\n const firstMiniFat = dv.getUint32(0x3c, true)\n const firstDifat = dv.getUint32(0x44, true)\n const per = this.sectorSize / 4\n\n // DIFAT (109 entries in the header, then any chained DIFAT sectors) → list of FAT sectors → FAT array.\n const difat: number[] = []\n for (let i = 0; i < 109; i++) {\n const v = dv.getUint32(0x4c + i * 4, true)\n if (v !== FREESECT && v !== ENDOFCHAIN) difat.push(v)\n }\n let ds = firstDifat\n let guard = 0\n while (ds !== ENDOFCHAIN && ds !== FREESECT && guard++ < 1_000_000) {\n const base = this.sectorOffset(ds)\n for (let i = 0; i < per - 1; i++) {\n const v = dv.getUint32(base + i * 4, true)\n if (v !== FREESECT) difat.push(v)\n }\n ds = dv.getUint32(base + (per - 1) * 4, true)\n }\n for (const fs of difat) {\n const base = this.sectorOffset(fs)\n for (let i = 0; i < per; i++) this.fat.push(dv.getUint32(base + i * 4, true))\n }\n\n // Directory: a chain of 128-byte entries starting at firstDir.\n const dirBytes = this.readFatStream(firstDir, this.chain(firstDir).length * this.sectorSize)\n const ddv = new DataView(dirBytes.buffer, dirBytes.byteOffset, dirBytes.byteLength)\n for (let o = 0; o + 128 <= dirBytes.length; o += 128) {\n const type = ddv.getUint8(o + 66)\n if (type === 0) continue // unallocated entry\n const nameLen = ddv.getUint16(o + 64, true) // bytes incl. null terminator\n let name = ''\n for (let c = 0; c + 1 < nameLen; c += 2) {\n const code = ddv.getUint16(o + c, true)\n if (code === 0) break\n name += String.fromCharCode(code)\n }\n const start = ddv.getUint32(o + 116, true)\n // v3 stores the size in 4 bytes (the high 4 may be garbage); v4 uses the full 8.\n const size =\n major <= 3 ? ddv.getUint32(o + 120, true) : Number(ddv.getBigUint64(o + 120, true))\n this.entries.push({ name, type, start, size })\n }\n\n // Mini stream (held by the root entry, in the regular FAT) + the MiniFAT (chained from firstMiniFat).\n const root = this.entries.find((e) => e.type === 5)\n if (root) this.miniStream = this.readFatStream(root.start, root.size)\n for (const s of this.chain(firstMiniFat)) {\n const base = this.sectorOffset(s)\n for (let i = 0; i < per; i++) this.miniFat.push(dv.getUint32(base + i * 4, true))\n }\n }\n\n private sectorOffset(s: number): number {\n // Sector S starts at (S+1)*sectorSize: the 512-byte header is padded to a full sector, so for v3\n // (512-byte) this is 512 + S*512, and for v4 (4096-byte) it's 4096 + S*4096 (NOT 512 + S*4096).\n return (s + 1) * this.sectorSize\n }\n /** Follow a FAT chain to a list of sector indices (bounded against corruption). */\n private chain(start: number): number[] {\n const out: number[] = []\n let s = start\n let guard = 0\n while (s !== ENDOFCHAIN && s !== FREESECT && s < this.fat.length && guard++ < 10_000_000) {\n out.push(s)\n s = this.fat[s]\n }\n return out\n }\n /** Copy one big-FAT sector, clamped to the buffer (a truncated file yields short data, not a throw). */\n private sectorBytes(s: number): Uint8Array {\n const off = this.sectorOffset(s)\n const end = Math.min(this.buf.byteLength, off + this.sectorSize)\n const out = new Uint8Array(this.sectorSize)\n if (off < this.buf.byteLength) out.set(new Uint8Array(this.buf, off, end - off))\n return out\n }\n private readFatStream(start: number, size: number): Uint8Array {\n const ch = this.chain(start)\n const out = new Uint8Array(ch.length * this.sectorSize)\n for (let i = 0; i < ch.length; i++) out.set(this.sectorBytes(ch[i]), i * this.sectorSize)\n return out.subarray(0, size)\n }\n private readMiniStream(start: number, size: number): Uint8Array {\n // The stream occupies exactly `need` mini-sectors; read only that many even if the chain runs longer\n // (some writers leave trailing/looping links past the stream end — copying them would overflow `out`).\n const need = Math.ceil(size / this.miniSectorSize)\n const out = new Uint8Array(need * this.miniSectorSize)\n let s = start\n let i = 0\n while (s !== ENDOFCHAIN && s !== FREESECT && i < need) {\n const off = s * this.miniSectorSize\n out.set(this.miniStream.subarray(off, off + this.miniSectorSize), i * this.miniSectorSize)\n i++\n s = this.miniFat[s]\n }\n return out.subarray(0, size)\n }\n /** The decompressed bytes of one directory entry's stream (small streams live in the mini stream). */\n stream(e: CfbEntry): Uint8Array {\n if (e.size === 0) return new Uint8Array(0)\n if (e.type === 5 || e.size >= this.miniCutoff) return this.readFatStream(e.start, e.size)\n return this.readMiniStream(e.start, e.size)\n }\n}\n\n// ── MSI stream-name (un)mangling ────────────────────────────────────────────────────────────────────\n// MSI encodes table/stream names into a private Unicode range using a 64-char alphabet (Wine's\n// decode_streamname). A leading 0x4840 wide-char marks \"this is a database table\".\nfunction mime2utf(x: number): string {\n if (x < 10) return String.fromCharCode(x + 48) // 0-9\n if (x < 36) return String.fromCharCode(x - 10 + 65) // A-Z\n if (x < 62) return String.fromCharCode(x - 36 + 97) // a-z\n return x === 62 ? '.' : '_'\n}\nfunction decodeStreamName(raw: string): { name: string; isTable: boolean } {\n let out = ''\n let isTable = false\n for (let i = 0; i < raw.length; i++) {\n const ch = raw.charCodeAt(i)\n if (ch >= 0x3800 && ch < 0x4800) {\n const v = ch - 0x3800 // two 6-bit characters packed into one wide-char\n out += mime2utf(v & 0x3f) + mime2utf((v >> 6) & 0x3f)\n } else if (ch >= 0x4800 && ch < 0x4840) {\n out += mime2utf(ch - 0x4800) // a single character\n } else if (ch === 0x4840) {\n isTable = true // table marker (prefix); contributes nothing to the name\n } else {\n out += String.fromCharCode(ch) // literal (ASCII names, the \\x05 property-set prefix, …)\n }\n }\n return { name: out, isTable }\n}\n\n// ── SummaryInformation (OLE property set, MS-OLEPS) ─────────────────────────────────────────────────\ninterface PropVal {\n type: number\n value: string | number\n}\n\nfunction parsePropertySet(bytes: Uint8Array): { codepage: number; props: Map<number, PropVal> } {\n const v = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength)\n // 28-byte set header + one 20-byte (FMTID + offset) section locator; the section offset sits at byte 44.\n const sectionOff = v.getUint32(44, true)\n const numProps = v.getUint32(sectionOff + 4, true)\n const rows: { pid: number; abs: number }[] = []\n for (let i = 0; i < numProps; i++) {\n const pid = v.getUint32(sectionOff + 8 + i * 8, true)\n const off = v.getUint32(sectionOff + 8 + i * 8 + 4, true)\n rows.push({ pid, abs: sectionOff + off })\n }\n // The codepage (PID 1) governs how the LPSTR string properties decode — read it first.\n let codepage = 1252\n const cpRow = rows.find((r) => r.pid === 1)\n if (cpRow && v.getUint32(cpRow.abs, true) === 2) {\n let cp = v.getInt16(cpRow.abs + 4, true)\n if (cp < 0) cp += 65536 // 65001 (UTF-8) overflows a signed 16-bit read\n codepage = cp\n }\n const dec = new TextDecoder(cpLabel(codepage))\n const props = new Map<number, PropVal>()\n for (const { pid, abs } of rows) {\n const type = v.getUint32(abs, true)\n if (type === 2) props.set(pid, { type, value: v.getInt16(abs + 4, true) })\n else if (type === 3) props.set(pid, { type, value: v.getInt32(abs + 4, true) })\n else if (type === 30) {\n // LPSTR: codepage bytes, NUL-terminated — cut at the first NUL (avoids a control-char regex).\n let raw = bytes.subarray(abs + 8, abs + 8 + v.getUint32(abs + 4, true))\n const nul = raw.indexOf(0)\n if (nul >= 0) raw = raw.subarray(0, nul)\n props.set(pid, { type, value: dec.decode(raw) })\n } else if (type === 64) {\n props.set(pid, {\n type,\n value: formatFiletime(v.getUint32(abs + 4, true), v.getUint32(abs + 8, true)),\n })\n }\n }\n return { codepage, props }\n}\n\nfunction buildSummary(props: Map<number, PropVal>): MsiMeta[] {\n const out: MsiMeta[] = []\n const push = (pid: number, label: string, fmt?: (v: string | number) => string): void => {\n const p = props.get(pid)\n if (p == null) return\n const value = fmt ? fmt(p.value) : String(p.value)\n if (value) out.push({ label, value })\n }\n push(3, '主题', String) // PID_SUBJECT — usually the product/package name\n push(4, '作者 / 厂商', String) // PID_AUTHOR\n push(6, '备注', String) // PID_COMMENTS — description\n push(2, '标题', String) // PID_TITLE\n push(5, '关键字', String) // PID_KEYWORDS\n push(7, '平台 / 语言', (v) => formatTemplate(String(v))) // PID_TEMPLATE\n push(9, '包代码', String) // PID_REVNUMBER — the package (revision) code GUID\n push(18, '制作工具', String) // PID_APPNAME — authoring application\n push(12, '创建时间', String) // PID_CREATE_DTM\n push(13, '上次保存', String) // PID_LASTSAVE_DTM\n push(14, '架构版本', (v) => formatSchema(Number(v))) // PID_PAGECOUNT — min installer version\n push(15, '源类型', (v) => formatWordCount(Number(v))) // PID_WORDCOUNT — source flags\n push(19, '安全', (v) => formatSecurity(Number(v))) // PID_SECURITY\n return out\n}\n\n// ── MSI string pool + Property table ────────────────────────────────────────────────────────────────\n// `_StringPool` is an array of 4-byte slots: [length: u16][refcount: u16] (length FIRST — validated against\n// the COM oracle). Slot 0 carries the codepage (+ a long-string-refs flag in the high bit). `_StringData` is\n// every string concatenated in index order; string i lives at the running offset, `length` bytes long.\nfunction buildStringTable(\n pool: Uint8Array,\n data: Uint8Array,\n fallbackCp: number,\n): { strings: string[]; longRefs: boolean } {\n const pdv = new DataView(pool.buffer, pool.byteOffset, pool.byteLength)\n const cpRaw = pdv.getUint16(0, true) | (pdv.getUint16(2, true) << 16)\n const longRefs = (cpRaw & 0x80000000) !== 0 // ⇒ 3-byte string references in table data\n let cp = cpRaw & 0x7fffffff\n if (cp === 0) cp = fallbackCp || 1252 // codepage 0 = system ANSI; fall back to the SummaryInfo codepage\n const dec = new TextDecoder(cpLabel(cp))\n const strings: string[] = ['']\n let off = 0\n const count = Math.floor(pool.length / 4)\n for (let i = 1; i < count; i++) {\n const len = pdv.getUint16(i * 4, true)\n if (len === 0) {\n strings.push('')\n continue\n }\n strings.push(dec.decode(data.subarray(off, off + len)))\n off += len\n }\n return { strings, longRefs }\n}\n\n// The Property table is two string columns (Property name, Value) stored column-major: all the name refs,\n// then all the value refs. Each ref is a 2-byte (or 3-byte, with long string refs) index into the pool.\nfunction decodePropertyTable(\n tbl: Uint8Array,\n st: { strings: string[]; longRefs: boolean },\n): MsiProperty[] {\n const refSize = st.longRefs ? 3 : 2\n const dv = new DataView(tbl.buffer, tbl.byteOffset, tbl.byteLength)\n const rows = Math.floor(tbl.length / (refSize * 2))\n const ref = (idx: number): number => {\n const o = idx * refSize\n let v = dv.getUint16(o, true)\n if (refSize === 3) v += dv.getUint8(o + 2) << 16\n return v\n }\n const out: MsiProperty[] = []\n for (let r = 0; r < rows; r++) {\n const name = st.strings[ref(r)] ?? ''\n const value = st.strings[ref(rows + r)] ?? ''\n if (name) out.push({ name, value })\n }\n return out\n}\n\n// ── orchestrator ────────────────────────────────────────────────────────────────────────────────────\nexport function parseMsi(buf: ArrayBuffer): MsiInfo {\n const cfb = new Cfb(buf) // throws NotMsiError if the bytes aren't a compound file\n const decoded = cfb.entries.map((e) => ({ e, ...decodeStreamName(e.name) }))\n const notes: string[] = []\n\n const tables = decoded\n .filter((d) => d.isTable)\n .map((d) => d.name)\n .sort((a, b) => a.localeCompare(b))\n\n // SummaryInformation (standard, near-universal in MSIs).\n let summary: MsiMeta[] = []\n let siCodepage = 0\n const siD = decoded.find((d) => d.name === '\u0005SummaryInformation')\n if (siD) {\n try {\n const ps = parsePropertySet(cfb.stream(siD.e))\n siCodepage = ps.codepage\n summary = buildSummary(ps.props)\n } catch (e) {\n notes.push('SummaryInformation 解析失败:' + errMsg(e))\n }\n }\n\n // Property table (best-effort: a malformed string pool never blanks the summary above).\n let properties: MsiProperty[] = []\n const sd = decoded.find((d) => d.name === '_StringData')\n const sp = decoded.find((d) => d.name === '_StringPool')\n const pr = decoded.find((d) => d.name === 'Property')\n if (sd && sp && pr) {\n try {\n const st = buildStringTable(cfb.stream(sp.e), cfb.stream(sd.e), siCodepage)\n properties = decodePropertyTable(cfb.stream(pr.e), st)\n } catch (e) {\n notes.push('Property 表解析失败:' + errMsg(e))\n }\n }\n\n const map = new Map(properties.map((p) => [p.name, p.value]))\n const langId = map.get('ProductLanguage')\n const info: MsiInfo = {\n productName: map.get('ProductName'),\n productVersion: map.get('ProductVersion'),\n manufacturer: map.get('Manufacturer'),\n productCode: map.get('ProductCode'),\n upgradeCode: map.get('UpgradeCode'),\n language: langId ? formatLanguage(langId) : undefined,\n properties,\n summary,\n tables,\n notes,\n }\n if (!properties.length && !summary.length) {\n notes.push('未找到 MSI 摘要信息或属性表(可能是别的复合文件,而非 MSI 数据库)')\n }\n return info\n}\n\n// ── formatting helpers ──────────────────────────────────────────────────────────────────────────────\nfunction errMsg(e: unknown): string {\n return e instanceof Error ? e.message : String(e)\n}\n\nfunction cpLabel(cp: number): string {\n switch (cp) {\n case 65001:\n return 'utf-8'\n case 1200:\n return 'utf-16le'\n case 1201:\n return 'utf-16be'\n case 932:\n return 'shift_jis'\n case 936:\n return 'gbk'\n case 949:\n return 'euc-kr'\n case 950:\n return 'big5'\n case 1250:\n return 'windows-1250'\n case 1251:\n return 'windows-1251'\n case 1253:\n return 'windows-1253'\n case 1254:\n return 'windows-1254'\n case 1255:\n return 'windows-1255'\n case 1256:\n return 'windows-1256'\n case 1257:\n return 'windows-1257'\n case 1258:\n return 'windows-1258'\n default:\n return 'windows-1252' // 1252 and the system-ANSI (0) fallback\n }\n}\n\nfunction formatFiletime(lo: number, hi: number): string {\n const ft = hi * 4294967296 + lo\n if (!ft) return ''\n const ms = ft / 10000 - 11644473600000\n const d = new Date(ms)\n if (Number.isNaN(d.getTime())) return ''\n const p = (n: number): string => String(n).padStart(2, '0')\n return `${d.getUTCFullYear()}-${p(d.getUTCMonth() + 1)}-${p(d.getUTCDate())} ${p(d.getUTCHours())}:${p(d.getUTCMinutes())} UTC`\n}\n\n// MSI \"Template\" = \"<platform>;<langid>[,<langid>…]\" e.g. \"x64;1033\". Surface the platform + language names.\nfunction formatTemplate(t: string): string {\n const [platform, langs] = t.split(';')\n const names = (langs ?? '')\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean)\n .map((id) => formatLanguage(id))\n const parts: string[] = []\n if (platform && platform.trim()) parts.push(platform.trim())\n if (names.length) parts.push(names.join(', '))\n return parts.join(' · ') || t\n}\n\n// PID_PAGECOUNT for an install package = the minimum Windows Installer version (e.g. 200 ⇒ 2.00, 500 ⇒ 5.00).\nfunction formatSchema(n: number): string {\n if (!n) return ''\n return `${Math.floor(n / 100)}.${String(n % 100).padStart(2, '0')}`\n}\n\n// PID_WORDCOUNT = source flags bitfield.\nfunction formatWordCount(n: number): string {\n const flags: string[] = []\n flags.push(n & 0x2 ? '压缩 (cabinet)' : '未压缩')\n if (n & 0x1) flags.push('短文件名')\n if (n & 0x4) flags.push('管理映像')\n if (n & 0x8) flags.push('从源运行')\n return flags.join(' · ')\n}\n\nfunction formatSecurity(n: number): string {\n switch (n) {\n case 0:\n return '无限制'\n case 1:\n return '建议只读'\n case 2:\n return '强制只读'\n case 4:\n return '已锁定'\n default:\n return String(n)\n }\n}\n\n// Common Windows LCIDs → Chinese language names (best-effort; unknown ids fall back to the raw number).\nconst LCID_NAMES: Record<number, string> = {\n 0: '语言中性',\n 1025: '阿拉伯语',\n 1028: '中文(繁体)',\n 1029: '捷克语',\n 1030: '丹麦语',\n 1031: '德语',\n 1032: '希腊语',\n 1033: '英语(美国)',\n 1034: '西班牙语',\n 1035: '芬兰语',\n 1036: '法语',\n 1037: '希伯来语',\n 1038: '匈牙利语',\n 1040: '意大利语',\n 1041: '日语',\n 1042: '韩语',\n 1043: '荷兰语',\n 1044: '挪威语',\n 1045: '波兰语',\n 1046: '葡萄牙语(巴西)',\n 1049: '俄语',\n 1051: '斯洛伐克语',\n 1053: '瑞典语',\n 1054: '泰语',\n 1055: '土耳其语',\n 1057: '印尼语',\n 1058: '乌克兰语',\n 1060: '斯洛文尼亚语',\n 1066: '越南语',\n 2052: '中文(简体)',\n 2057: '英语(英国)',\n 2070: '葡萄牙语',\n 3076: '中文(香港)',\n 3082: '西班牙语(西班牙)',\n 4100: '中文(新加坡)',\n}\nfunction formatLanguage(id: string): string {\n const n = Number(id)\n const name = LCID_NAMES[n]\n return name ? `${name} (${id})` : id\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"msi.js","names":[],"sources":["../../src/lib/msi.ts"],"sourcesContent":["/**\n * Minimal in-browser MSI (Windows Installer) reader — no dependency, no WASM.\n *\n * An `.msi` is NOT a PE executable (that's `.exe`/`.dll` — see lib/binobj.ts), and NOT a zip (that's\n * `.appx`/`.msix` — see lib/appx.ts). It's an OLE2 **Compound File** (a.k.a. structured storage / CFBF):\n * a mini-filesystem of \"streams\" inside one file (the same container legacy `.doc`/`.xls`/`.msg` use). The\n * install metadata we surface lives in two of those streams:\n * - the standard **SummaryInformation** property set (`\\x05SummaryInformation`): title / subject / author /\n * comments, the target platform+language template, the package (revision) code, the authoring tool, dates.\n * - the **Property table** (ProductName / ProductVersion / ProductCode / UpgradeCode / Manufacturer / …),\n * spread across the MSI string pool (`_StringData` + `_StringPool`) and the `Property` table stream.\n *\n * We parse only what a \"what is this installer?\" view needs — never the embedded cabinet / payload files.\n * The logic is validated byte-for-byte against real installers using the Windows `WindowsInstaller.Installer`\n * COM automation as an oracle (the Property table + SummaryInformation match it exactly).\n *\n * Used by MsiViewer (the side viewer's MSI mode): the bytes come from the same download endpoint as any\n * other file, are parsed entirely client-side, and never leave the browser.\n */\n\nimport { CompoundFile, CompoundFileError } from '@/lib/cfb'\n\nexport interface MsiMeta {\n label: string\n value: string\n}\nexport interface MsiProperty {\n name: string\n value: string\n}\n\nexport interface MsiInfo {\n /** Resolved product identity from the Property table (any field may be absent if the table is unreadable). */\n productName?: string\n productVersion?: string\n manufacturer?: string\n productCode?: string\n upgradeCode?: string\n /** Install language: a human label when the LCID is recognized (with the raw id), else the raw id. */\n language?: string\n /** Full Property table (name → value), in stored order. Empty if the table couldn't be decoded. */\n properties: MsiProperty[]\n /** SummaryInformation rows, pre-labeled (Chinese), in display order. */\n summary: MsiMeta[]\n /** Decoded names of the database tables present — a quick \"shape of the installer\" cue. */\n tables: string[]\n /** Non-fatal notes (e.g. the Property table was unreadable but SummaryInformation succeeded). */\n notes: string[]\n}\n\n/** Thrown when the bytes aren't an OLE compound file at all (so the viewer can show a clear message). */\nexport class NotMsiError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'NotMsiError'\n }\n}\n\n// ── MSI stream-name (un)mangling ────────────────────────────────────────────────────────────────────\n// MSI encodes table/stream names into a private Unicode range using a 64-char alphabet (Wine's\n// decode_streamname). A leading 0x4840 wide-char marks \"this is a database table\".\nfunction mime2utf(x: number): string {\n if (x < 10) return String.fromCharCode(x + 48) // 0-9\n if (x < 36) return String.fromCharCode(x - 10 + 65) // A-Z\n if (x < 62) return String.fromCharCode(x - 36 + 97) // a-z\n return x === 62 ? '.' : '_'\n}\nfunction decodeStreamName(raw: string): { name: string; isTable: boolean } {\n let out = ''\n let isTable = false\n for (let i = 0; i < raw.length; i++) {\n const ch = raw.charCodeAt(i)\n if (ch >= 0x3800 && ch < 0x4800) {\n const v = ch - 0x3800 // two 6-bit characters packed into one wide-char\n out += mime2utf(v & 0x3f) + mime2utf((v >> 6) & 0x3f)\n } else if (ch >= 0x4800 && ch < 0x4840) {\n out += mime2utf(ch - 0x4800) // a single character\n } else if (ch === 0x4840) {\n isTable = true // table marker (prefix); contributes nothing to the name\n } else {\n out += String.fromCharCode(ch) // literal (ASCII names, the \\x05 property-set prefix, …)\n }\n }\n return { name: out, isTable }\n}\n\n// ── SummaryInformation (OLE property set, MS-OLEPS) ─────────────────────────────────────────────────\ninterface PropVal {\n type: number\n value: string | number\n}\n\nfunction parsePropertySet(bytes: Uint8Array): { codepage: number; props: Map<number, PropVal> } {\n const v = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength)\n // 28-byte set header + one 20-byte (FMTID + offset) section locator; the section offset sits at byte 44.\n const sectionOff = v.getUint32(44, true)\n const numProps = v.getUint32(sectionOff + 4, true)\n const rows: { pid: number; abs: number }[] = []\n for (let i = 0; i < numProps; i++) {\n const pid = v.getUint32(sectionOff + 8 + i * 8, true)\n const off = v.getUint32(sectionOff + 8 + i * 8 + 4, true)\n rows.push({ pid, abs: sectionOff + off })\n }\n // The codepage (PID 1) governs how the LPSTR string properties decode — read it first.\n let codepage = 1252\n const cpRow = rows.find((r) => r.pid === 1)\n if (cpRow && v.getUint32(cpRow.abs, true) === 2) {\n let cp = v.getInt16(cpRow.abs + 4, true)\n if (cp < 0) cp += 65536 // 65001 (UTF-8) overflows a signed 16-bit read\n codepage = cp\n }\n const dec = new TextDecoder(cpLabel(codepage))\n const props = new Map<number, PropVal>()\n for (const { pid, abs } of rows) {\n const type = v.getUint32(abs, true)\n if (type === 2) props.set(pid, { type, value: v.getInt16(abs + 4, true) })\n else if (type === 3) props.set(pid, { type, value: v.getInt32(abs + 4, true) })\n else if (type === 30) {\n // LPSTR: codepage bytes, NUL-terminated — cut at the first NUL (avoids a control-char regex).\n let raw = bytes.subarray(abs + 8, abs + 8 + v.getUint32(abs + 4, true))\n const nul = raw.indexOf(0)\n if (nul >= 0) raw = raw.subarray(0, nul)\n props.set(pid, { type, value: dec.decode(raw) })\n } else if (type === 64) {\n props.set(pid, {\n type,\n value: formatFiletime(v.getUint32(abs + 4, true), v.getUint32(abs + 8, true)),\n })\n }\n }\n return { codepage, props }\n}\n\nfunction buildSummary(props: Map<number, PropVal>): MsiMeta[] {\n const out: MsiMeta[] = []\n const push = (pid: number, label: string, fmt?: (v: string | number) => string): void => {\n const p = props.get(pid)\n if (p == null) return\n const value = fmt ? fmt(p.value) : String(p.value)\n if (value) out.push({ label, value })\n }\n push(3, '主题', String) // PID_SUBJECT — usually the product/package name\n push(4, '作者 / 厂商', String) // PID_AUTHOR\n push(6, '备注', String) // PID_COMMENTS — description\n push(2, '标题', String) // PID_TITLE\n push(5, '关键字', String) // PID_KEYWORDS\n push(7, '平台 / 语言', (v) => formatTemplate(String(v))) // PID_TEMPLATE\n push(9, '包代码', String) // PID_REVNUMBER — the package (revision) code GUID\n push(18, '制作工具', String) // PID_APPNAME — authoring application\n push(12, '创建时间', String) // PID_CREATE_DTM\n push(13, '上次保存', String) // PID_LASTSAVE_DTM\n push(14, '架构版本', (v) => formatSchema(Number(v))) // PID_PAGECOUNT — min installer version\n push(15, '源类型', (v) => formatWordCount(Number(v))) // PID_WORDCOUNT — source flags\n push(19, '安全', (v) => formatSecurity(Number(v))) // PID_SECURITY\n return out\n}\n\n// ── MSI string pool + Property table ────────────────────────────────────────────────────────────────\n// `_StringPool` is an array of 4-byte slots: [length: u16][refcount: u16] (length FIRST — validated against\n// the COM oracle). Slot 0 carries the codepage (+ a long-string-refs flag in the high bit). `_StringData` is\n// every string concatenated in index order; string i lives at the running offset, `length` bytes long.\nfunction buildStringTable(\n pool: Uint8Array,\n data: Uint8Array,\n fallbackCp: number,\n): { strings: string[]; longRefs: boolean } {\n const pdv = new DataView(pool.buffer, pool.byteOffset, pool.byteLength)\n const cpRaw = pdv.getUint16(0, true) | (pdv.getUint16(2, true) << 16)\n const longRefs = (cpRaw & 0x80000000) !== 0 // ⇒ 3-byte string references in table data\n let cp = cpRaw & 0x7fffffff\n if (cp === 0) cp = fallbackCp || 1252 // codepage 0 = system ANSI; fall back to the SummaryInfo codepage\n const dec = new TextDecoder(cpLabel(cp))\n const strings: string[] = ['']\n let off = 0\n const count = Math.floor(pool.length / 4)\n for (let i = 1; i < count; i++) {\n const len = pdv.getUint16(i * 4, true)\n if (len === 0) {\n strings.push('')\n continue\n }\n strings.push(dec.decode(data.subarray(off, off + len)))\n off += len\n }\n return { strings, longRefs }\n}\n\n// The Property table is two string columns (Property name, Value) stored column-major: all the name refs,\n// then all the value refs. Each ref is a 2-byte (or 3-byte, with long string refs) index into the pool.\nfunction decodePropertyTable(\n tbl: Uint8Array,\n st: { strings: string[]; longRefs: boolean },\n): MsiProperty[] {\n const refSize = st.longRefs ? 3 : 2\n const dv = new DataView(tbl.buffer, tbl.byteOffset, tbl.byteLength)\n const rows = Math.floor(tbl.length / (refSize * 2))\n const ref = (idx: number): number => {\n const o = idx * refSize\n let v = dv.getUint16(o, true)\n if (refSize === 3) v += dv.getUint8(o + 2) << 16\n return v\n }\n const out: MsiProperty[] = []\n for (let r = 0; r < rows; r++) {\n const name = st.strings[ref(r)] ?? ''\n const value = st.strings[ref(rows + r)] ?? ''\n if (name) out.push({ name, value })\n }\n return out\n}\n\n// ── orchestrator ────────────────────────────────────────────────────────────────────────────────────\nexport function parseMsi(buf: ArrayBuffer): MsiInfo {\n let cfb: CompoundFile\n try {\n cfb = new CompoundFile(buf)\n } catch (error) {\n if (error instanceof CompoundFileError) throw new NotMsiError(error.message)\n throw error\n }\n const decoded = cfb.entries.map((e) => ({ e, ...decodeStreamName(e.name) }))\n const notes: string[] = []\n\n const tables = decoded\n .filter((d) => d.isTable)\n .map((d) => d.name)\n .sort((a, b) => a.localeCompare(b))\n\n // SummaryInformation (standard, near-universal in MSIs).\n let summary: MsiMeta[] = []\n let siCodepage = 0\n const siD = decoded.find((d) => d.name === '\u0005SummaryInformation')\n if (siD) {\n try {\n const ps = parsePropertySet(cfb.stream(siD.e))\n siCodepage = ps.codepage\n summary = buildSummary(ps.props)\n } catch (e) {\n notes.push('SummaryInformation 解析失败:' + errMsg(e))\n }\n }\n\n // Property table (best-effort: a malformed string pool never blanks the summary above).\n let properties: MsiProperty[] = []\n const sd = decoded.find((d) => d.name === '_StringData')\n const sp = decoded.find((d) => d.name === '_StringPool')\n const pr = decoded.find((d) => d.name === 'Property')\n if (sd && sp && pr) {\n try {\n const st = buildStringTable(cfb.stream(sp.e), cfb.stream(sd.e), siCodepage)\n properties = decodePropertyTable(cfb.stream(pr.e), st)\n } catch (e) {\n notes.push('Property 表解析失败:' + errMsg(e))\n }\n }\n\n const map = new Map(properties.map((p) => [p.name, p.value]))\n const langId = map.get('ProductLanguage')\n const info: MsiInfo = {\n productName: map.get('ProductName'),\n productVersion: map.get('ProductVersion'),\n manufacturer: map.get('Manufacturer'),\n productCode: map.get('ProductCode'),\n upgradeCode: map.get('UpgradeCode'),\n language: langId ? formatLanguage(langId) : undefined,\n properties,\n summary,\n tables,\n notes,\n }\n if (!properties.length && !summary.length) {\n notes.push('未找到 MSI 摘要信息或属性表(可能是别的复合文件,而非 MSI 数据库)')\n }\n return info\n}\n\n// ── formatting helpers ──────────────────────────────────────────────────────────────────────────────\nfunction errMsg(e: unknown): string {\n return e instanceof Error ? e.message : String(e)\n}\n\nfunction cpLabel(cp: number): string {\n switch (cp) {\n case 65001:\n return 'utf-8'\n case 1200:\n return 'utf-16le'\n case 1201:\n return 'utf-16be'\n case 932:\n return 'shift_jis'\n case 936:\n return 'gbk'\n case 949:\n return 'euc-kr'\n case 950:\n return 'big5'\n case 1250:\n return 'windows-1250'\n case 1251:\n return 'windows-1251'\n case 1253:\n return 'windows-1253'\n case 1254:\n return 'windows-1254'\n case 1255:\n return 'windows-1255'\n case 1256:\n return 'windows-1256'\n case 1257:\n return 'windows-1257'\n case 1258:\n return 'windows-1258'\n default:\n return 'windows-1252' // 1252 and the system-ANSI (0) fallback\n }\n}\n\nfunction formatFiletime(lo: number, hi: number): string {\n const ft = hi * 4294967296 + lo\n if (!ft) return ''\n const ms = ft / 10000 - 11644473600000\n const d = new Date(ms)\n if (Number.isNaN(d.getTime())) return ''\n const p = (n: number): string => String(n).padStart(2, '0')\n return `${d.getUTCFullYear()}-${p(d.getUTCMonth() + 1)}-${p(d.getUTCDate())} ${p(d.getUTCHours())}:${p(d.getUTCMinutes())} UTC`\n}\n\n// MSI \"Template\" = \"<platform>;<langid>[,<langid>…]\" e.g. \"x64;1033\". Surface the platform + language names.\nfunction formatTemplate(t: string): string {\n const [platform, langs] = t.split(';')\n const names = (langs ?? '')\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean)\n .map((id) => formatLanguage(id))\n const parts: string[] = []\n if (platform && platform.trim()) parts.push(platform.trim())\n if (names.length) parts.push(names.join(', '))\n return parts.join(' · ') || t\n}\n\n// PID_PAGECOUNT for an install package = the minimum Windows Installer version (e.g. 200 ⇒ 2.00, 500 ⇒ 5.00).\nfunction formatSchema(n: number): string {\n if (!n) return ''\n return `${Math.floor(n / 100)}.${String(n % 100).padStart(2, '0')}`\n}\n\n// PID_WORDCOUNT = source flags bitfield.\nfunction formatWordCount(n: number): string {\n const flags: string[] = []\n flags.push(n & 0x2 ? '压缩 (cabinet)' : '未压缩')\n if (n & 0x1) flags.push('短文件名')\n if (n & 0x4) flags.push('管理映像')\n if (n & 0x8) flags.push('从源运行')\n return flags.join(' · ')\n}\n\nfunction formatSecurity(n: number): string {\n switch (n) {\n case 0:\n return '无限制'\n case 1:\n return '建议只读'\n case 2:\n return '强制只读'\n case 4:\n return '已锁定'\n default:\n return String(n)\n }\n}\n\n// Common Windows LCIDs → Chinese language names (best-effort; unknown ids fall back to the raw number).\nconst LCID_NAMES: Record<number, string> = {\n 0: '语言中性',\n 1025: '阿拉伯语',\n 1028: '中文(繁体)',\n 1029: '捷克语',\n 1030: '丹麦语',\n 1031: '德语',\n 1032: '希腊语',\n 1033: '英语(美国)',\n 1034: '西班牙语',\n 1035: '芬兰语',\n 1036: '法语',\n 1037: '希伯来语',\n 1038: '匈牙利语',\n 1040: '意大利语',\n 1041: '日语',\n 1042: '韩语',\n 1043: '荷兰语',\n 1044: '挪威语',\n 1045: '波兰语',\n 1046: '葡萄牙语(巴西)',\n 1049: '俄语',\n 1051: '斯洛伐克语',\n 1053: '瑞典语',\n 1054: '泰语',\n 1055: '土耳其语',\n 1057: '印尼语',\n 1058: '乌克兰语',\n 1060: '斯洛文尼亚语',\n 1066: '越南语',\n 2052: '中文(简体)',\n 2057: '英语(英国)',\n 2070: '葡萄牙语',\n 3076: '中文(香港)',\n 3082: '西班牙语(西班牙)',\n 4100: '中文(新加坡)',\n}\nfunction formatLanguage(id: string): string {\n const n = Number(id)\n const name = LCID_NAMES[n]\n return name ? `${name} (${id})` : id\n}\n"],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export declare class OlePackageError extends Error {
2
+ constructor(message: string);
3
+ }
4
+ /**
5
+ * Extract the OOXML ZIP stored in an Office OLE object's `Package` stream.
6
+ * Modern Word/WPS commonly wrap embedded PPTX/DOCX/XLSX this way instead of linking the package directly.
7
+ */
8
+ export declare function extractOlePackage(oleBytes: Uint8Array, maxPackageBytes?: number): Uint8Array;
@@ -0,0 +1,37 @@
1
+ import { CompoundFile as e, CompoundFileError as t } from "./cfb.js";
2
+ //#region src/lib/olePackage.ts
3
+ var n = [
4
+ 80,
5
+ 75,
6
+ 3,
7
+ 4
8
+ ], r = 100 * 1024 * 1024, i = class extends Error {
9
+ constructor(e) {
10
+ super(e), this.name = "OlePackageError";
11
+ }
12
+ };
13
+ function a(e) {
14
+ let t = new ArrayBuffer(e.byteLength);
15
+ return new Uint8Array(t).set(e), t;
16
+ }
17
+ function o(e) {
18
+ return n.every((t, n) => e[n] === t);
19
+ }
20
+ function s(n, s = r) {
21
+ let c;
22
+ try {
23
+ c = new e(a(n));
24
+ } catch (e) {
25
+ throw e instanceof t ? new i(e.message) : e;
26
+ }
27
+ let l = c.findStream("Package");
28
+ if (!l) throw new i("OLE 对象中没有 Package stream");
29
+ if (l.size > s) throw new i(`OLE Package 超过 ${s / 1024 / 1024} MiB,已拒绝展开`);
30
+ let u = c.stream(l);
31
+ if (!o(u)) throw new i("OLE Package 不是有效的 OOXML ZIP");
32
+ return u.slice();
33
+ }
34
+ //#endregion
35
+ export { s as extractOlePackage };
36
+
37
+ //# sourceMappingURL=olePackage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"olePackage.js","names":[],"sources":["../../src/lib/olePackage.ts"],"sourcesContent":["import { CompoundFile, CompoundFileError } from '@/lib/cfb'\n\nconst ZIP_LOCAL_FILE_SIGNATURE = [0x50, 0x4b, 0x03, 0x04]\nconst DEFAULT_MAX_PACKAGE_BYTES = 100 * 1024 * 1024\n\nexport class OlePackageError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'OlePackageError'\n }\n}\n\nfunction exactArrayBuffer(bytes: Uint8Array): ArrayBuffer {\n const result = new ArrayBuffer(bytes.byteLength)\n new Uint8Array(result).set(bytes)\n return result\n}\n\nfunction startsWithZipSignature(bytes: Uint8Array): boolean {\n return ZIP_LOCAL_FILE_SIGNATURE.every((value, index) => bytes[index] === value)\n}\n\n/**\n * Extract the OOXML ZIP stored in an Office OLE object's `Package` stream.\n * Modern Word/WPS commonly wrap embedded PPTX/DOCX/XLSX this way instead of linking the package directly.\n */\nexport function extractOlePackage(\n oleBytes: Uint8Array,\n maxPackageBytes = DEFAULT_MAX_PACKAGE_BYTES,\n): Uint8Array {\n let compound: CompoundFile\n try {\n compound = new CompoundFile(exactArrayBuffer(oleBytes))\n } catch (error) {\n if (error instanceof CompoundFileError) throw new OlePackageError(error.message)\n throw error\n }\n const entry = compound.findStream('Package')\n if (!entry) throw new OlePackageError('OLE 对象中没有 Package stream')\n if (entry.size > maxPackageBytes) {\n throw new OlePackageError(`OLE Package 超过 ${maxPackageBytes / 1024 / 1024} MiB,已拒绝展开`)\n }\n const bytes = compound.stream(entry)\n if (!startsWithZipSignature(bytes)) throw new OlePackageError('OLE Package 不是有效的 OOXML ZIP')\n return bytes.slice()\n}\n"],"mappings":";;AAEA,IAAM,IAA2B;CAAC;CAAM;CAAM;CAAM;AAAI,GAClD,IAA4B,MAAM,OAAO,MAElC,IAAb,cAAqC,MAAM;CACzC,YAAY,GAAiB;EAE3B,AADA,MAAM,CAAO,GACb,KAAK,OAAO;CACd;AACF;AAEA,SAAS,EAAiB,GAAgC;CACxD,IAAM,IAAS,IAAI,YAAY,EAAM,UAAU;CAE/C,OADA,IAAI,WAAW,CAAM,CAAC,CAAC,IAAI,CAAK,GACzB;AACT;AAEA,SAAS,EAAuB,GAA4B;CAC1D,OAAO,EAAyB,OAAO,GAAO,MAAU,EAAM,OAAW,CAAK;AAChF;AAMA,SAAgB,EACd,GACA,IAAkB,GACN;CACZ,IAAI;CACJ,IAAI;EACF,IAAW,IAAI,EAAa,EAAiB,CAAQ,CAAC;CACxD,SAAS,GAAO;EAEd,MADI,aAAiB,IAAyB,IAAI,EAAgB,EAAM,OAAO,IACzE;CACR;CACA,IAAM,IAAQ,EAAS,WAAW,SAAS;CAC3C,IAAI,CAAC,GAAO,MAAM,IAAI,EAAgB,0BAA0B;CAChE,IAAI,EAAM,OAAO,GACf,MAAM,IAAI,EAAgB,kBAAkB,IAAkB,OAAO,KAAK,WAAW;CAEvF,IAAM,IAAQ,EAAS,OAAO,CAAK;CACnC,IAAI,CAAC,EAAuB,CAAK,GAAG,MAAM,IAAI,EAAgB,6BAA6B;CAC3F,OAAO,EAAM,MAAM;AACrB"}
@@ -0,0 +1,11 @@
1
+ export interface PptxFirstSlideController {
2
+ dispose: () => void;
3
+ }
4
+ interface MountPptxFirstSlideOptions {
5
+ container: HTMLElement;
6
+ bytes: Uint8Array;
7
+ signal?: AbortSignal;
8
+ }
9
+ /** Render only the first slide of an extracted PPTX into an existing inline document host. */
10
+ export declare function mountPptxFirstSlide(options: MountPptxFirstSlideOptions): Promise<PptxFirstSlideController>;
11
+ export {};
@@ -0,0 +1,34 @@
1
+ import e from "pdfjs-dist/build/pdf.worker.min.mjs?url";
2
+ import { PptxViewer as t, RECOMMENDED_ZIP_LIMITS as n } from "@aiden0z/pptx-renderer";
3
+ import r from "pdfjs-dist/build/pdf.min.mjs?url";
4
+ //#region src/lib/pptxFirstSlide.ts
5
+ async function i(i) {
6
+ let a = new t(i.container, {
7
+ fitMode: "contain",
8
+ zipLimits: n,
9
+ lazyMedia: !0,
10
+ lazySlides: !0,
11
+ pdfjs: {
12
+ moduleUrl: r,
13
+ workerUrl: e
14
+ }
15
+ }), o = !1;
16
+ try {
17
+ if (await a.open(i.bytes, {
18
+ renderMode: "slide",
19
+ lazyMedia: !0,
20
+ lazySlides: !0,
21
+ signal: i.signal
22
+ }), i.signal?.aborted) throw Error("PPTX 首屏渲染已取消");
23
+ if (a.slideCount < 1) throw Error("PPTX 中没有可渲染的幻灯片");
24
+ } catch (e) {
25
+ throw a.destroy(), i.container.replaceChildren(), e;
26
+ }
27
+ return { dispose: () => {
28
+ o || (o = !0, a.destroy(), i.container.replaceChildren());
29
+ } };
30
+ }
31
+ //#endregion
32
+ export { i as mountPptxFirstSlide };
33
+
34
+ //# sourceMappingURL=pptxFirstSlide.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pptxFirstSlide.js","names":[],"sources":["../../src/lib/pptxFirstSlide.ts"],"sourcesContent":["import { PptxViewer, RECOMMENDED_ZIP_LIMITS } from '@aiden0z/pptx-renderer'\nimport pdfModuleUrl from 'pdfjs-dist/build/pdf.min.mjs?url'\nimport pdfWorkerUrl from 'pdfjs-dist/build/pdf.worker.min.mjs?url'\n\nexport interface PptxFirstSlideController {\n dispose: () => void\n}\n\ninterface MountPptxFirstSlideOptions {\n container: HTMLElement\n bytes: Uint8Array\n signal?: AbortSignal\n}\n\n/** Render only the first slide of an extracted PPTX into an existing inline document host. */\nexport async function mountPptxFirstSlide(\n options: MountPptxFirstSlideOptions,\n): Promise<PptxFirstSlideController> {\n const viewer = new PptxViewer(options.container, {\n fitMode: 'contain',\n zipLimits: RECOMMENDED_ZIP_LIMITS,\n lazyMedia: true,\n lazySlides: true,\n pdfjs: { moduleUrl: pdfModuleUrl, workerUrl: pdfWorkerUrl },\n })\n let disposed = false\n\n try {\n await viewer.open(options.bytes, {\n renderMode: 'slide',\n lazyMedia: true,\n lazySlides: true,\n signal: options.signal,\n })\n if (options.signal?.aborted) throw new Error('PPTX 首屏渲染已取消')\n if (viewer.slideCount < 1) throw new Error('PPTX 中没有可渲染的幻灯片')\n } catch (error) {\n viewer.destroy()\n options.container.replaceChildren()\n throw error\n }\n\n return {\n dispose: () => {\n if (disposed) return\n disposed = true\n viewer.destroy()\n options.container.replaceChildren()\n },\n }\n}\n"],"mappings":";;;;AAeA,eAAsB,EACpB,GACmC;CACnC,IAAM,IAAS,IAAI,EAAW,EAAQ,WAAW;EAC/C,SAAS;EACT,WAAW;EACX,WAAW;EACX,YAAY;EACZ,OAAO;GAAE,WAAW;GAAc,WAAW;EAAa;CAC5D,CAAC,GACG,IAAW;CAEf,IAAI;EAOF,IANA,MAAM,EAAO,KAAK,EAAQ,OAAO;GAC/B,YAAY;GACZ,WAAW;GACX,YAAY;GACZ,QAAQ,EAAQ;EAClB,CAAC,GACG,EAAQ,QAAQ,SAAS,MAAU,MAAM,cAAc;EAC3D,IAAI,EAAO,aAAa,GAAG,MAAU,MAAM,iBAAiB;CAC9D,SAAS,GAAO;EAGd,MAFA,EAAO,QAAQ,GACf,EAAQ,UAAU,gBAAgB,GAC5B;CACR;CAEA,OAAO,EACL,eAAe;EACT,MACJ,IAAW,IACX,EAAO,QAAQ,GACf,EAAQ,UAAU,gBAAgB;CACpC,EACF;AACF"}
@@ -0,0 +1,10 @@
1
+ import type { StepModel, StepPhase } from './stepTypes';
2
+ interface StepOptions {
3
+ signal?: AbortSignal;
4
+ onPhase?: (phase: StepPhase) => void;
5
+ /** Includes engine loading and tessellation. The UI can always cancel sooner. */
6
+ timeoutMs?: number;
7
+ }
8
+ /** Consumes (transfers) buffer. No DOM or CAD work executes on the caller's thread. */
9
+ export declare function parseStep(buffer: ArrayBuffer, options?: StepOptions): Promise<StepModel>;
10
+ export {};
@@ -0,0 +1,35 @@
1
+ import e from "./step.worker.js";
2
+ import t from "occt-import-js/dist/occt-import-js.js?url";
3
+ import n from "occt-import-js/dist/occt-import-js.wasm?url";
4
+ //#region src/lib/step.ts
5
+ function r(r, i = {}) {
6
+ return new Promise((a, o) => {
7
+ let { signal: s } = i;
8
+ if (s?.aborted) {
9
+ o(new DOMException("已取消模型解析", "AbortError"));
10
+ return;
11
+ }
12
+ let c = new e(), l = !1, u = (e, t) => {
13
+ l || (l = !0, clearTimeout(f), s?.removeEventListener("abort", d), c.terminate(), e ? o(e) : a(t));
14
+ }, d = () => u(new DOMException("已取消模型解析", "AbortError")), f = setTimeout(() => u(/* @__PURE__ */ Error("STEP 解析超过两分钟,已停止。可重试或下载后使用本地 CAD 工具打开。")), i.timeoutMs ?? 12e4);
15
+ s?.addEventListener("abort", d, { once: !0 }), c.onmessage = ({ data: e }) => {
16
+ e.type === "phase" ? i.onPhase?.(e.phase) : e.type === "error" ? u(Error(e.message)) : u(void 0, e.model);
17
+ }, c.onerror = (e) => {
18
+ e.preventDefault(), u(Error(e.message || "STEP 解析器加载失败。"));
19
+ }, c.onmessageerror = () => u(/* @__PURE__ */ Error("无法读取 STEP 解析结果。"));
20
+ try {
21
+ let e = {
22
+ buffer: r,
23
+ scriptUrl: new URL(t, window.location.href).href,
24
+ wasmUrl: new URL(n, window.location.href).href
25
+ };
26
+ c.postMessage(e, [r]);
27
+ } catch (e) {
28
+ u(e instanceof Error ? e : Error(String(e)));
29
+ }
30
+ });
31
+ }
32
+ //#endregion
33
+ export { r as parseStep };
34
+
35
+ //# sourceMappingURL=step.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"step.js","names":[],"sources":["../../src/lib/step.ts"],"sourcesContent":["import StepWorker from './step.worker?worker&inline'\nimport scriptUrl from 'occt-import-js/dist/occt-import-js.js?url'\nimport wasmUrl from 'occt-import-js/dist/occt-import-js.wasm?url'\nimport type { StepModel, StepPhase, StepReply, StepRequest } from './stepTypes'\n\ninterface StepOptions {\n signal?: AbortSignal\n onPhase?: (phase: StepPhase) => void\n /** Includes engine loading and tessellation. The UI can always cancel sooner. */\n timeoutMs?: number\n}\n\n/** Consumes (transfers) buffer. No DOM or CAD work executes on the caller's thread. */\nexport function parseStep(buffer: ArrayBuffer, options: StepOptions = {}): Promise<StepModel> {\n return new Promise((resolve, reject) => {\n const { signal } = options\n if (signal?.aborted) {\n reject(new DOMException('已取消模型解析', 'AbortError'))\n return\n }\n const worker = new StepWorker()\n let settled = false\n const finish = (error?: Error, model?: StepModel): void => {\n if (settled) return\n settled = true\n clearTimeout(timer)\n signal?.removeEventListener('abort', abort)\n worker.terminate()\n if (error) reject(error)\n else resolve(model!)\n }\n const abort = (): void => finish(new DOMException('已取消模型解析', 'AbortError'))\n const timer = setTimeout(\n () => finish(new Error('STEP 解析超过两分钟,已停止。可重试或下载后使用本地 CAD 工具打开。')),\n options.timeoutMs ?? 120_000,\n )\n signal?.addEventListener('abort', abort, { once: true })\n worker.onmessage = ({ data }: MessageEvent<StepReply>) => {\n if (data.type === 'phase') options.onPhase?.(data.phase)\n else if (data.type === 'error') finish(new Error(data.message))\n else finish(undefined, data.model)\n }\n worker.onerror = (event) => {\n event.preventDefault()\n finish(new Error(event.message || 'STEP 解析器加载失败。'))\n }\n worker.onmessageerror = () => finish(new Error('无法读取 STEP 解析结果。'))\n try {\n // The worker is a blob URL; resolve asset URLs in the host page, before crossing that boundary.\n const request: StepRequest = {\n buffer,\n scriptUrl: new URL(scriptUrl, window.location.href).href,\n wasmUrl: new URL(wasmUrl, window.location.href).href,\n }\n worker.postMessage(request, [buffer])\n } catch (error) {\n finish(error instanceof Error ? error : new Error(String(error)))\n }\n })\n}\n"],"mappings":";;;;AAaA,SAAgB,EAAU,GAAqB,IAAuB,CAAC,GAAuB;CAC5F,OAAO,IAAI,SAAS,GAAS,MAAW;EACtC,IAAM,EAAE,cAAW;EACnB,IAAI,GAAQ,SAAS;GACnB,EAAO,IAAI,aAAa,WAAW,YAAY,CAAC;GAChD;EACF;EACA,IAAM,IAAS,IAAI,EAAW,GAC1B,IAAU,IACR,KAAU,GAAe,MAA4B;GACrD,MACJ,IAAU,IACV,aAAa,CAAK,GAClB,GAAQ,oBAAoB,SAAS,CAAK,GAC1C,EAAO,UAAU,GACb,IAAO,EAAO,CAAK,IAClB,EAAQ,CAAM;EACrB,GACM,UAAoB,EAAO,IAAI,aAAa,WAAW,YAAY,CAAC,GACpE,IAAQ,iBACN,EAAO,gBAAI,MAAM,wCAAwC,CAAC,GAChE,EAAQ,aAAa,IACvB;EAWA,AAVA,GAAQ,iBAAiB,SAAS,GAAO,EAAE,MAAM,GAAK,CAAC,GACvD,EAAO,aAAa,EAAE,cAAoC;GACxD,AAAI,EAAK,SAAS,UAAS,EAAQ,UAAU,EAAK,KAAK,IAC9C,EAAK,SAAS,UAAS,EAAW,MAAM,EAAK,OAAO,CAAC,IACzD,EAAO,KAAA,GAAW,EAAK,KAAK;EACnC,GACA,EAAO,WAAW,MAAU;GAE1B,AADA,EAAM,eAAe,GACrB,EAAW,MAAM,EAAM,WAAW,eAAe,CAAC;EACpD,GACA,EAAO,uBAAuB,EAAO,gBAAI,MAAM,iBAAiB,CAAC;EACjE,IAAI;GAEF,IAAM,IAAuB;IAC3B;IACA,WAAW,IAAI,IAAI,GAAW,OAAO,SAAS,IAAI,CAAC,CAAC;IACpD,SAAS,IAAI,IAAI,GAAS,OAAO,SAAS,IAAI,CAAC,CAAC;GAClD;GACA,EAAO,YAAY,GAAS,CAAC,CAAM,CAAC;EACtC,SAAS,GAAO;GACd,EAAO,aAAiB,QAAQ,IAAY,MAAM,OAAO,CAAK,CAAC,CAAC;EAClE;CACF,CAAC;AACH"}
@@ -0,0 +1 @@
1
+ export {};