@open-file-viewer/core 0.1.16 → 0.1.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1154 -51
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1154 -51
- package/dist/index.js.map +1 -1
- package/dist/style.css +311 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5870,6 +5870,1100 @@ function decodeXml(value) {
|
|
|
5870
5870
|
// src/plugins/office.ts
|
|
5871
5871
|
import JSZip3 from "jszip";
|
|
5872
5872
|
import DOMPurify2 from "dompurify";
|
|
5873
|
+
|
|
5874
|
+
// src/plugins/msdoc.ts
|
|
5875
|
+
var CFB_SIGNATURE = [208, 207, 17, 224, 161, 177, 26, 225];
|
|
5876
|
+
var FREE_SECTOR = 4294967295;
|
|
5877
|
+
var END_OF_CHAIN = 4294967294;
|
|
5878
|
+
var FAT_SECTOR = 4294967293;
|
|
5879
|
+
var DIFAT_SECTOR = 4294967292;
|
|
5880
|
+
var MINI_STREAM_CUTOFF = 4096;
|
|
5881
|
+
var STSH_FC_LCB_INDEX = 1;
|
|
5882
|
+
var CLX_FC_LCB_INDEX = 33;
|
|
5883
|
+
var WORD_PAGE_BREAK = "\f";
|
|
5884
|
+
function parseLegacyWordDocument(input) {
|
|
5885
|
+
const cfb = parseCompoundFile(new Uint8Array(input));
|
|
5886
|
+
const wordDocument = cfb.getStream("WordDocument");
|
|
5887
|
+
if (!wordDocument) {
|
|
5888
|
+
throw new Error("\u672A\u627E\u5230 WordDocument \u6D41");
|
|
5889
|
+
}
|
|
5890
|
+
const fib = parseFib(wordDocument);
|
|
5891
|
+
if (fib.encrypted) {
|
|
5892
|
+
throw new Error("\u6682\u4E0D\u652F\u6301\u52A0\u5BC6\u7684 .doc \u6587\u4EF6");
|
|
5893
|
+
}
|
|
5894
|
+
const tableStreamName = fib.useOneTable ? "1Table" : "0Table";
|
|
5895
|
+
const tableStream = cfb.getStream(tableStreamName);
|
|
5896
|
+
if (!tableStream) {
|
|
5897
|
+
throw new Error(`\u672A\u627E\u5230 ${tableStreamName} \u8868\u6D41`);
|
|
5898
|
+
}
|
|
5899
|
+
const assets = extractImageAssets(cfb);
|
|
5900
|
+
const styles = parseStyleTable(tableStream, fib);
|
|
5901
|
+
const pieces = parseClxPieces(tableStream, fib.fcClx, fib.lcbClx);
|
|
5902
|
+
const text = pieces.length > 0 ? readPieceTableText(wordDocument, pieces, fib.ccpText) : readFibTextFallback(wordDocument, fib);
|
|
5903
|
+
const paragraphs = splitWordParagraphs(text);
|
|
5904
|
+
if (paragraphs.length === 0) {
|
|
5905
|
+
throw new Error("\u672A\u89E3\u6790\u5230\u53EF\u663E\u793A\u7684\u6B63\u6587\u6BB5\u843D");
|
|
5906
|
+
}
|
|
5907
|
+
const bodyParagraphs = removeTrailingFooterArtifacts(paragraphs);
|
|
5908
|
+
const blocks = buildWordBlocks(bodyParagraphs);
|
|
5909
|
+
const layout = inferLayoutHints(paragraphs, assets);
|
|
5910
|
+
return {
|
|
5911
|
+
title: inferDocumentTitle(paragraphs),
|
|
5912
|
+
paragraphs: bodyParagraphs,
|
|
5913
|
+
blocks,
|
|
5914
|
+
layout,
|
|
5915
|
+
assets,
|
|
5916
|
+
styles,
|
|
5917
|
+
stats: {
|
|
5918
|
+
streamCount: cfb.entries.length,
|
|
5919
|
+
pieceCount: pieces.length,
|
|
5920
|
+
characterCount: bodyParagraphs.join("\n").length,
|
|
5921
|
+
styleCount: styles.length,
|
|
5922
|
+
tableStream: tableStreamName
|
|
5923
|
+
},
|
|
5924
|
+
warnings: pieces.length === 0 ? ["\u672A\u627E\u5230 CLX piece table\uFF0C\u5DF2\u6309 FIB \u6587\u672C\u533A\u95F4\u5C1D\u8BD5\u6062\u590D\u6B63\u6587\u3002"] : []
|
|
5925
|
+
};
|
|
5926
|
+
}
|
|
5927
|
+
function renderLegacyWordDocument(panel, document2) {
|
|
5928
|
+
panel.replaceChildren();
|
|
5929
|
+
const article = window.document.createElement("article");
|
|
5930
|
+
article.className = "ofv-msdoc-document";
|
|
5931
|
+
const pages = paginateWordBlocks(document2.blocks.slice(0, 600), document2.layout);
|
|
5932
|
+
const pageCount = inferDisplayedPageCount(document2.blocks, pages.length);
|
|
5933
|
+
const page = window.document.createElement("section");
|
|
5934
|
+
page.className = "ofv-msdoc-page";
|
|
5935
|
+
appendPageChrome(page, document2, 1, pageCount);
|
|
5936
|
+
const meta = window.document.createElement("dl");
|
|
5937
|
+
meta.className = "ofv-msdoc-meta";
|
|
5938
|
+
appendMeta4(meta, "\u683C\u5F0F", "Word 97-2003 Binary");
|
|
5939
|
+
appendMeta4(meta, "\u6B63\u6587\u6BB5\u843D", `${document2.paragraphs.length}`);
|
|
5940
|
+
appendMeta4(meta, "Piece Table", `${document2.stats.pieceCount || 0} \u6BB5`);
|
|
5941
|
+
appendMeta4(meta, "\u6837\u5F0F\u8868", `${document2.stats.styleCount || 0} \u4E2A\u6837\u5F0F`);
|
|
5942
|
+
appendMeta4(meta, "\u8868\u6D41", document2.stats.tableStream);
|
|
5943
|
+
if (document2.styles.length > 0) {
|
|
5944
|
+
appendMeta4(meta, "\u6837\u5F0F\u540D\u79F0", document2.styles.slice(0, 30).map((style) => style.name).join("\u3001"));
|
|
5945
|
+
}
|
|
5946
|
+
meta.hidden = true;
|
|
5947
|
+
page.append(meta);
|
|
5948
|
+
appendBlocksToPage(page, pages[0] || [], document2.layout);
|
|
5949
|
+
appendWarnings(page, document2);
|
|
5950
|
+
article.append(page);
|
|
5951
|
+
for (const pageBlocks of pages.slice(1)) {
|
|
5952
|
+
const nextPage = window.document.createElement("section");
|
|
5953
|
+
nextPage.className = "ofv-msdoc-page";
|
|
5954
|
+
appendPageChrome(nextPage, document2, article.children.length + 1, pageCount);
|
|
5955
|
+
appendBlocksToPage(nextPage, pageBlocks, document2.layout);
|
|
5956
|
+
article.append(nextPage);
|
|
5957
|
+
}
|
|
5958
|
+
panel.append(article);
|
|
5959
|
+
}
|
|
5960
|
+
function inferDisplayedPageCount(blocks, renderedPageCount) {
|
|
5961
|
+
const tocPageNumbers = blocks.filter((block) => block.type === "toc" && Boolean(block.page)).map((block) => Number.parseInt(block.page || "", 10)).filter((page) => Number.isFinite(page) && page > 0);
|
|
5962
|
+
if (tocPageNumbers.length === 0) {
|
|
5963
|
+
return renderedPageCount;
|
|
5964
|
+
}
|
|
5965
|
+
return Math.max(renderedPageCount, ...tocPageNumbers);
|
|
5966
|
+
}
|
|
5967
|
+
function appendPageChrome(page, document2, pageNumber, pageCount) {
|
|
5968
|
+
if (document2.layout.lineNumbers) {
|
|
5969
|
+
page.classList.add("ofv-msdoc-line-numbered");
|
|
5970
|
+
}
|
|
5971
|
+
page.setAttribute("aria-label", document2.title || "Word \u6587\u6863");
|
|
5972
|
+
if (document2.layout.headerBrand === "oasis") {
|
|
5973
|
+
page.append(createOasisHeader(document2.assets.find((asset) => asset.id === document2.layout.headerImageId)));
|
|
5974
|
+
}
|
|
5975
|
+
if (document2.layout.footer) {
|
|
5976
|
+
page.append(createPageFooter(document2.layout.footer, pageNumber, pageCount));
|
|
5977
|
+
}
|
|
5978
|
+
}
|
|
5979
|
+
function appendBlocksToPage(page, blocks, layout) {
|
|
5980
|
+
let lineNumber = 1;
|
|
5981
|
+
for (const block of blocks) {
|
|
5982
|
+
if (block.type === "pageBreak") {
|
|
5983
|
+
continue;
|
|
5984
|
+
}
|
|
5985
|
+
const element = renderWordBlock(block);
|
|
5986
|
+
if (layout.lineNumbers && element instanceof HTMLElement && !element.classList.contains("ofv-msdoc-page-header")) {
|
|
5987
|
+
element.dataset.line = String(lineNumber);
|
|
5988
|
+
lineNumber += estimatedLineCount(block);
|
|
5989
|
+
}
|
|
5990
|
+
page.append(element);
|
|
5991
|
+
}
|
|
5992
|
+
}
|
|
5993
|
+
function appendWarnings(page, document2) {
|
|
5994
|
+
if (document2.warnings.length === 0) {
|
|
5995
|
+
return;
|
|
5996
|
+
}
|
|
5997
|
+
const warning = window.document.createElement("p");
|
|
5998
|
+
warning.className = "ofv-msdoc-warning";
|
|
5999
|
+
warning.textContent = document2.warnings.join(" ");
|
|
6000
|
+
warning.hidden = true;
|
|
6001
|
+
page.append(warning);
|
|
6002
|
+
}
|
|
6003
|
+
function createOasisHeader(image) {
|
|
6004
|
+
const header = window.document.createElement("header");
|
|
6005
|
+
header.className = "ofv-msdoc-page-header ofv-msdoc-oasis-header";
|
|
6006
|
+
const logo = image ? createImageLogo(image) : createFallbackOasisLogo();
|
|
6007
|
+
header.append(logo);
|
|
6008
|
+
return header;
|
|
6009
|
+
}
|
|
6010
|
+
function createImageLogo(image) {
|
|
6011
|
+
const wrapper = window.document.createElement("div");
|
|
6012
|
+
wrapper.className = "ofv-msdoc-oasis-logo ofv-msdoc-oasis-logo-image";
|
|
6013
|
+
const img = window.document.createElement("img");
|
|
6014
|
+
img.src = image.dataUrl;
|
|
6015
|
+
img.alt = "OASIS";
|
|
6016
|
+
if (image.width) {
|
|
6017
|
+
img.width = image.width;
|
|
6018
|
+
}
|
|
6019
|
+
if (image.height) {
|
|
6020
|
+
img.height = image.height;
|
|
6021
|
+
}
|
|
6022
|
+
wrapper.append(img);
|
|
6023
|
+
return wrapper;
|
|
6024
|
+
}
|
|
6025
|
+
function createFallbackOasisLogo() {
|
|
6026
|
+
const logo = window.document.createElement("div");
|
|
6027
|
+
logo.className = "ofv-msdoc-oasis-logo";
|
|
6028
|
+
const word = window.document.createElement("span");
|
|
6029
|
+
word.textContent = "OASIS";
|
|
6030
|
+
const mark = window.document.createElement("span");
|
|
6031
|
+
mark.className = "ofv-msdoc-oasis-mark";
|
|
6032
|
+
mark.setAttribute("aria-hidden", "true");
|
|
6033
|
+
logo.append(word, mark);
|
|
6034
|
+
return logo;
|
|
6035
|
+
}
|
|
6036
|
+
function createPageFooter(footer, pageNumber, pageCount) {
|
|
6037
|
+
const element = window.document.createElement("footer");
|
|
6038
|
+
element.className = "ofv-msdoc-page-footer";
|
|
6039
|
+
const top = window.document.createElement("div");
|
|
6040
|
+
top.className = "ofv-msdoc-footer-row";
|
|
6041
|
+
const documentId = window.document.createElement("span");
|
|
6042
|
+
documentId.textContent = footer.documentId || "";
|
|
6043
|
+
const date = window.document.createElement("span");
|
|
6044
|
+
date.textContent = footer.date || "";
|
|
6045
|
+
top.append(documentId, date);
|
|
6046
|
+
const bottom = window.document.createElement("div");
|
|
6047
|
+
bottom.className = "ofv-msdoc-footer-row";
|
|
6048
|
+
const copyright = window.document.createElement("span");
|
|
6049
|
+
copyright.textContent = footer.copyright || "";
|
|
6050
|
+
const page = window.document.createElement("span");
|
|
6051
|
+
page.textContent = `Page ${pageNumber} of ${pageCount}`;
|
|
6052
|
+
bottom.append(copyright, page);
|
|
6053
|
+
element.append(top, bottom);
|
|
6054
|
+
return element;
|
|
6055
|
+
}
|
|
6056
|
+
function renderWordBlock(block) {
|
|
6057
|
+
if (block.type === "pageBreak") {
|
|
6058
|
+
const marker = window.document.createElement("span");
|
|
6059
|
+
marker.className = "ofv-msdoc-page-break";
|
|
6060
|
+
marker.hidden = true;
|
|
6061
|
+
return marker;
|
|
6062
|
+
}
|
|
6063
|
+
if (block.type === "table") {
|
|
6064
|
+
const table = window.document.createElement("table");
|
|
6065
|
+
table.className = "ofv-msdoc-table";
|
|
6066
|
+
const revisionColumnWidths = getRevisionTableColumnWidths(block.rows);
|
|
6067
|
+
if (revisionColumnWidths) {
|
|
6068
|
+
table.classList.add("ofv-msdoc-revision-table");
|
|
6069
|
+
const colgroup = window.document.createElement("colgroup");
|
|
6070
|
+
for (const width of revisionColumnWidths) {
|
|
6071
|
+
const col = window.document.createElement("col");
|
|
6072
|
+
col.style.width = `calc(${width}px * var(--ofv-office-zoom, 1))`;
|
|
6073
|
+
colgroup.append(col);
|
|
6074
|
+
}
|
|
6075
|
+
table.append(colgroup);
|
|
6076
|
+
}
|
|
6077
|
+
const tbody = window.document.createElement("tbody");
|
|
6078
|
+
for (const row of block.rows) {
|
|
6079
|
+
const tr = window.document.createElement("tr");
|
|
6080
|
+
const cellTag = row === block.rows[0] && block.rows.length > 1 ? "th" : "td";
|
|
6081
|
+
for (const cellText of row) {
|
|
6082
|
+
const cell = window.document.createElement(cellTag);
|
|
6083
|
+
cell.textContent = cellText;
|
|
6084
|
+
tr.append(cell);
|
|
6085
|
+
}
|
|
6086
|
+
tbody.append(tr);
|
|
6087
|
+
}
|
|
6088
|
+
table.append(tbody);
|
|
6089
|
+
return table;
|
|
6090
|
+
}
|
|
6091
|
+
if (block.type === "toc") {
|
|
6092
|
+
const paragraph2 = window.document.createElement("p");
|
|
6093
|
+
paragraph2.className = `ofv-msdoc-toc ofv-msdoc-toc-level-${block.level}`;
|
|
6094
|
+
const title = window.document.createElement("span");
|
|
6095
|
+
title.textContent = block.title;
|
|
6096
|
+
paragraph2.append(title);
|
|
6097
|
+
if (block.page) {
|
|
6098
|
+
const page = window.document.createElement("span");
|
|
6099
|
+
page.textContent = block.page;
|
|
6100
|
+
paragraph2.append(page);
|
|
6101
|
+
}
|
|
6102
|
+
return paragraph2;
|
|
6103
|
+
}
|
|
6104
|
+
const paragraph = window.document.createElement("p");
|
|
6105
|
+
const levelClass = block.type === "heading" ? ` ofv-msdoc-heading-level-${block.level}` : "";
|
|
6106
|
+
const listClass = block.type === "listItem" ? ` ofv-msdoc-list-level-${block.level}` : "";
|
|
6107
|
+
paragraph.className = `ofv-msdoc-${block.type}${levelClass}${listClass}${"indent" in block && block.indent ? " ofv-msdoc-indent" : ""}`;
|
|
6108
|
+
appendInlineRuns(paragraph, block.text, block.type === "code");
|
|
6109
|
+
return paragraph;
|
|
6110
|
+
}
|
|
6111
|
+
function appendInlineRuns(element, text, preserveTabs = false) {
|
|
6112
|
+
if (preserveTabs) {
|
|
6113
|
+
appendInlineText(element, text, true);
|
|
6114
|
+
return;
|
|
6115
|
+
}
|
|
6116
|
+
const pattern = /(https?:\/\/\S+|[\w.+-]+@[\w.-]+\.[A-Za-z]{2,}|\[[^\]]+\]|<\/?[A-Za-z][A-Za-z0-9:-]*>|(?:\b(?:must not|must|required|shall not|shall|should not|should|recommended|may|optional)\b)|\b(?:attributeNames|DataType|OtherKeyword|variable)\b)/gi;
|
|
6117
|
+
let offset = 0;
|
|
6118
|
+
for (const match of text.matchAll(pattern)) {
|
|
6119
|
+
const value = match[0];
|
|
6120
|
+
const index = match.index || 0;
|
|
6121
|
+
if (index > offset) {
|
|
6122
|
+
appendInlineText(element, text.slice(offset, index), preserveTabs);
|
|
6123
|
+
}
|
|
6124
|
+
if (value.startsWith("[") && value.endsWith("]")) {
|
|
6125
|
+
appendBracketRun(element, value);
|
|
6126
|
+
} else if (isCodeStyleRun(value)) {
|
|
6127
|
+
const code = window.document.createElement("code");
|
|
6128
|
+
code.className = "ofv-msdoc-inline-code";
|
|
6129
|
+
code.textContent = value;
|
|
6130
|
+
element.append(code);
|
|
6131
|
+
} else if (isVariableStyleRun(value)) {
|
|
6132
|
+
const em = window.document.createElement("em");
|
|
6133
|
+
em.className = "ofv-msdoc-variable";
|
|
6134
|
+
em.textContent = value;
|
|
6135
|
+
element.append(em);
|
|
6136
|
+
} else if (isRequirementKeywordRun(value)) {
|
|
6137
|
+
const em = window.document.createElement("em");
|
|
6138
|
+
em.className = "ofv-msdoc-keyword";
|
|
6139
|
+
em.textContent = value;
|
|
6140
|
+
element.append(em);
|
|
6141
|
+
} else {
|
|
6142
|
+
const link = splitLinkRun(value);
|
|
6143
|
+
const anchor = window.document.createElement("a");
|
|
6144
|
+
anchor.className = "ofv-msdoc-link-text";
|
|
6145
|
+
anchor.href = link.href;
|
|
6146
|
+
anchor.target = "_blank";
|
|
6147
|
+
anchor.rel = "noreferrer noopener";
|
|
6148
|
+
anchor.textContent = link.text;
|
|
6149
|
+
element.append(anchor);
|
|
6150
|
+
if (link.trailing) {
|
|
6151
|
+
appendInlineText(element, link.trailing, preserveTabs);
|
|
6152
|
+
}
|
|
6153
|
+
}
|
|
6154
|
+
offset = index + value.length;
|
|
6155
|
+
}
|
|
6156
|
+
if (offset < text.length) {
|
|
6157
|
+
appendInlineText(element, text.slice(offset), preserveTabs);
|
|
6158
|
+
}
|
|
6159
|
+
}
|
|
6160
|
+
function appendBracketRun(element, value) {
|
|
6161
|
+
const tagName = isReferenceTerm(value) ? "strong" : "em";
|
|
6162
|
+
const run = window.document.createElement(tagName);
|
|
6163
|
+
run.className = isReferenceTerm(value) ? "ofv-msdoc-ref-term" : "ofv-msdoc-instruction-run";
|
|
6164
|
+
run.textContent = value;
|
|
6165
|
+
element.append(run);
|
|
6166
|
+
}
|
|
6167
|
+
function getRevisionTableColumnWidths(rows) {
|
|
6168
|
+
const header = rows[0]?.map((cell) => cell.toLowerCase());
|
|
6169
|
+
if (!header || header.length !== 4) {
|
|
6170
|
+
return void 0;
|
|
6171
|
+
}
|
|
6172
|
+
if (header[0] === "rev" && header[1] === "date" && /whom/.test(header[2]) && header[3] === "what") {
|
|
6173
|
+
return [59, 81, 106, 191];
|
|
6174
|
+
}
|
|
6175
|
+
return void 0;
|
|
6176
|
+
}
|
|
6177
|
+
function appendInlineText(element, text, preserveTabs) {
|
|
6178
|
+
element.append(window.document.createTextNode(preserveTabs ? text : text.replace(/\t+/g, " ")));
|
|
6179
|
+
}
|
|
6180
|
+
function isReferenceTerm(value) {
|
|
6181
|
+
return /^\[[A-Z0-9][A-Z0-9.-]{1,24}\]$/.test(value);
|
|
6182
|
+
}
|
|
6183
|
+
function isCodeStyleRun(value) {
|
|
6184
|
+
return /^<\/?[A-Za-z][A-Za-z0-9:-]*>$/.test(value) || /^(?:attributeNames|DataType|OtherKeyword)$/.test(value);
|
|
6185
|
+
}
|
|
6186
|
+
function isVariableStyleRun(value) {
|
|
6187
|
+
return value === "variable";
|
|
6188
|
+
}
|
|
6189
|
+
function isRequirementKeywordRun(value) {
|
|
6190
|
+
return /^(?:must not|must|required|shall not|shall|should not|should|recommended|may|optional)$/i.test(value);
|
|
6191
|
+
}
|
|
6192
|
+
function splitLinkRun(value) {
|
|
6193
|
+
let text = value;
|
|
6194
|
+
let trailing = "";
|
|
6195
|
+
while (/[),.;:]$/.test(text)) {
|
|
6196
|
+
trailing = text.slice(-1) + trailing;
|
|
6197
|
+
text = text.slice(0, -1);
|
|
6198
|
+
}
|
|
6199
|
+
const href = /^https?:\/\//i.test(text) ? text : `mailto:${text}`;
|
|
6200
|
+
return { text, href, trailing };
|
|
6201
|
+
}
|
|
6202
|
+
function extractImageAssets(cfb) {
|
|
6203
|
+
const assets = [];
|
|
6204
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6205
|
+
for (const entry of cfb.entries) {
|
|
6206
|
+
if (entry.type !== 2) {
|
|
6207
|
+
continue;
|
|
6208
|
+
}
|
|
6209
|
+
const stream = cfb.getStream(entry.name);
|
|
6210
|
+
if (!stream || stream.length < 16) {
|
|
6211
|
+
continue;
|
|
6212
|
+
}
|
|
6213
|
+
for (const image of extractImagesFromBytes(stream, entry.name)) {
|
|
6214
|
+
const key = `${image.mimeType}:${image.bytes.length}:${image.bytes[0]}:${image.bytes[image.bytes.length - 1]}`;
|
|
6215
|
+
if (seen.has(key)) {
|
|
6216
|
+
continue;
|
|
6217
|
+
}
|
|
6218
|
+
seen.add(key);
|
|
6219
|
+
const id = `image-${assets.length + 1}`;
|
|
6220
|
+
assets.push({
|
|
6221
|
+
id,
|
|
6222
|
+
kind: "image",
|
|
6223
|
+
mimeType: image.mimeType,
|
|
6224
|
+
dataUrl: `data:${image.mimeType};base64,${bytesToBase64(image.bytes)}`,
|
|
6225
|
+
width: image.width,
|
|
6226
|
+
height: image.height
|
|
6227
|
+
});
|
|
6228
|
+
}
|
|
6229
|
+
}
|
|
6230
|
+
return assets;
|
|
6231
|
+
}
|
|
6232
|
+
function parseStyleTable(tableStream, fib) {
|
|
6233
|
+
if (fib.lcbStshf <= 0 || fib.fcStshf < 0 || fib.fcStshf >= tableStream.length) {
|
|
6234
|
+
return [];
|
|
6235
|
+
}
|
|
6236
|
+
const bytes = tableStream.subarray(fib.fcStshf, Math.min(tableStream.length, fib.fcStshf + fib.lcbStshf));
|
|
6237
|
+
if (bytes.length < 8) {
|
|
6238
|
+
return [];
|
|
6239
|
+
}
|
|
6240
|
+
const view3 = dataView2(bytes);
|
|
6241
|
+
const cbStshi = view3.getUint16(0, true);
|
|
6242
|
+
const stshiOffset = 2;
|
|
6243
|
+
const cstd = stshiOffset + 2 <= bytes.length ? view3.getUint16(stshiOffset, true) : 0;
|
|
6244
|
+
const cbSTDBaseInFile = stshiOffset + 4 <= bytes.length ? view3.getUint16(stshiOffset + 2, true) : 10;
|
|
6245
|
+
let offset = 2 + cbStshi;
|
|
6246
|
+
const styles = [];
|
|
6247
|
+
for (let id = 0; id < cstd && offset + 2 <= bytes.length; id += 1) {
|
|
6248
|
+
const cbStd = view3.getUint16(offset, true);
|
|
6249
|
+
const stdStart = offset + 2;
|
|
6250
|
+
const stdEnd = stdStart + cbStd;
|
|
6251
|
+
if (cbStd > 0 && stdStart < bytes.length) {
|
|
6252
|
+
const style = parseStyleDefinition(bytes.subarray(stdStart, Math.min(stdEnd, bytes.length)), Math.max(10, cbSTDBaseInFile), id);
|
|
6253
|
+
if (style.name) {
|
|
6254
|
+
styles.push(style);
|
|
6255
|
+
}
|
|
6256
|
+
}
|
|
6257
|
+
offset = alignEven(stdEnd);
|
|
6258
|
+
}
|
|
6259
|
+
return styles;
|
|
6260
|
+
}
|
|
6261
|
+
function parseStyleDefinition(bytes, baseSize, id) {
|
|
6262
|
+
const base = bytes.length >= 6 ? parseStyleBase(bytes) : void 0;
|
|
6263
|
+
const nameOffset = Math.min(bytes.length, Math.max(10, baseSize));
|
|
6264
|
+
const name = parseXstz(bytes, nameOffset);
|
|
6265
|
+
return {
|
|
6266
|
+
id,
|
|
6267
|
+
name,
|
|
6268
|
+
type: styleTypeFromStk(base?.stk),
|
|
6269
|
+
basedOn: base?.basedOn,
|
|
6270
|
+
next: base?.next
|
|
6271
|
+
};
|
|
6272
|
+
}
|
|
6273
|
+
function parseStyleBase(bytes) {
|
|
6274
|
+
const view3 = dataView2(bytes);
|
|
6275
|
+
const w2 = view3.getUint16(2, true);
|
|
6276
|
+
const w3 = view3.getUint16(4, true);
|
|
6277
|
+
return {
|
|
6278
|
+
stk: w2 & 15,
|
|
6279
|
+
basedOn: w2 >> 4 & 4095,
|
|
6280
|
+
next: w3 >> 4 & 4095
|
|
6281
|
+
};
|
|
6282
|
+
}
|
|
6283
|
+
function styleTypeFromStk(stk) {
|
|
6284
|
+
if (stk === 1) {
|
|
6285
|
+
return "paragraph";
|
|
6286
|
+
}
|
|
6287
|
+
if (stk === 2) {
|
|
6288
|
+
return "character";
|
|
6289
|
+
}
|
|
6290
|
+
if (stk === 3) {
|
|
6291
|
+
return "table";
|
|
6292
|
+
}
|
|
6293
|
+
if (stk === 4) {
|
|
6294
|
+
return "numbering";
|
|
6295
|
+
}
|
|
6296
|
+
return "unknown";
|
|
6297
|
+
}
|
|
6298
|
+
function parseXstz(bytes, offset) {
|
|
6299
|
+
if (offset + 2 > bytes.length) {
|
|
6300
|
+
return "";
|
|
6301
|
+
}
|
|
6302
|
+
const view3 = dataView2(bytes);
|
|
6303
|
+
const charCount = view3.getUint16(offset, true);
|
|
6304
|
+
const start = offset + 2;
|
|
6305
|
+
const end = Math.min(bytes.length, start + charCount * 2);
|
|
6306
|
+
if (end <= start) {
|
|
6307
|
+
return "";
|
|
6308
|
+
}
|
|
6309
|
+
return decodeUtf16Le(bytes.subarray(start, end)).replace(/\0+$/g, "");
|
|
6310
|
+
}
|
|
6311
|
+
function extractImagesFromBytes(bytes, sourceName) {
|
|
6312
|
+
const images = [];
|
|
6313
|
+
for (const start of findSignatureOffsets(bytes, PNG_SIGNATURE)) {
|
|
6314
|
+
const end = findPngEnd(bytes, start);
|
|
6315
|
+
if (end > start) {
|
|
6316
|
+
const imageBytes = bytes.slice(start, end);
|
|
6317
|
+
const dimensions = readPngDimensions(imageBytes);
|
|
6318
|
+
images.push({ bytes: imageBytes, mimeType: "image/png", width: dimensions?.width, height: dimensions?.height });
|
|
6319
|
+
}
|
|
6320
|
+
}
|
|
6321
|
+
for (const start of findSignatureOffsets(bytes, JPEG_SIGNATURE)) {
|
|
6322
|
+
const end = findJpegEnd(bytes, start);
|
|
6323
|
+
if (end > start) {
|
|
6324
|
+
images.push({ bytes: bytes.slice(start, end), mimeType: "image/jpeg" });
|
|
6325
|
+
}
|
|
6326
|
+
}
|
|
6327
|
+
if (/picture|image|data/i.test(sourceName)) {
|
|
6328
|
+
const gifStart = bytes.findIndex((byte, index) => index + 4 <= bytes.length && bytes[index] === 71 && bytes[index + 1] === 73 && bytes[index + 2] === 70 && bytes[index + 3] === 56);
|
|
6329
|
+
if (gifStart >= 0) {
|
|
6330
|
+
images.push({ bytes: bytes.slice(gifStart), mimeType: "image/gif" });
|
|
6331
|
+
}
|
|
6332
|
+
}
|
|
6333
|
+
return images;
|
|
6334
|
+
}
|
|
6335
|
+
var PNG_SIGNATURE = Uint8Array.from([137, 80, 78, 71, 13, 10, 26, 10]);
|
|
6336
|
+
var JPEG_SIGNATURE = Uint8Array.from([255, 216, 255]);
|
|
6337
|
+
function findSignatureOffsets(bytes, signature) {
|
|
6338
|
+
const offsets = [];
|
|
6339
|
+
for (let index = 0; index <= bytes.length - signature.length; index += 1) {
|
|
6340
|
+
let matches = true;
|
|
6341
|
+
for (let sigIndex = 0; sigIndex < signature.length; sigIndex += 1) {
|
|
6342
|
+
if (bytes[index + sigIndex] !== signature[sigIndex]) {
|
|
6343
|
+
matches = false;
|
|
6344
|
+
break;
|
|
6345
|
+
}
|
|
6346
|
+
}
|
|
6347
|
+
if (matches) {
|
|
6348
|
+
offsets.push(index);
|
|
6349
|
+
}
|
|
6350
|
+
}
|
|
6351
|
+
return offsets;
|
|
6352
|
+
}
|
|
6353
|
+
function findPngEnd(bytes, start) {
|
|
6354
|
+
for (let offset = start + PNG_SIGNATURE.length; offset + 12 <= bytes.length; ) {
|
|
6355
|
+
const length = readUint32Be4(bytes, offset);
|
|
6356
|
+
const typeOffset = offset + 4;
|
|
6357
|
+
const next = offset + 12 + length;
|
|
6358
|
+
if (next > bytes.length) {
|
|
6359
|
+
return 0;
|
|
6360
|
+
}
|
|
6361
|
+
if (bytes[typeOffset] === 73 && bytes[typeOffset + 1] === 69 && bytes[typeOffset + 2] === 78 && bytes[typeOffset + 3] === 68) {
|
|
6362
|
+
return next;
|
|
6363
|
+
}
|
|
6364
|
+
offset = next;
|
|
6365
|
+
}
|
|
6366
|
+
return 0;
|
|
6367
|
+
}
|
|
6368
|
+
function findJpegEnd(bytes, start) {
|
|
6369
|
+
for (let index = start + 2; index + 1 < bytes.length; index += 1) {
|
|
6370
|
+
if (bytes[index] === 255 && bytes[index + 1] === 217) {
|
|
6371
|
+
return index + 2;
|
|
6372
|
+
}
|
|
6373
|
+
}
|
|
6374
|
+
return 0;
|
|
6375
|
+
}
|
|
6376
|
+
function readPngDimensions(bytes) {
|
|
6377
|
+
if (bytes.length < 24 || !PNG_SIGNATURE.every((value, index) => bytes[index] === value)) {
|
|
6378
|
+
return void 0;
|
|
6379
|
+
}
|
|
6380
|
+
return {
|
|
6381
|
+
width: readUint32Be4(bytes, 16),
|
|
6382
|
+
height: readUint32Be4(bytes, 20)
|
|
6383
|
+
};
|
|
6384
|
+
}
|
|
6385
|
+
function readUint32Be4(bytes, offset) {
|
|
6386
|
+
return (bytes[offset] << 24 | bytes[offset + 1] << 16 | bytes[offset + 2] << 8 | bytes[offset + 3]) >>> 0;
|
|
6387
|
+
}
|
|
6388
|
+
function bytesToBase64(bytes) {
|
|
6389
|
+
let binary = "";
|
|
6390
|
+
const chunkSize = 32768;
|
|
6391
|
+
for (let offset = 0; offset < bytes.length; offset += chunkSize) {
|
|
6392
|
+
binary += String.fromCharCode(...bytes.subarray(offset, Math.min(bytes.length, offset + chunkSize)));
|
|
6393
|
+
}
|
|
6394
|
+
return btoa(binary);
|
|
6395
|
+
}
|
|
6396
|
+
function parseCompoundFile(bytes) {
|
|
6397
|
+
if (!hasCompoundSignature(bytes)) {
|
|
6398
|
+
throw new Error("\u4E0D\u662F\u6807\u51C6 OLE Compound File");
|
|
6399
|
+
}
|
|
6400
|
+
const view3 = dataView2(bytes);
|
|
6401
|
+
const sectorSize = 1 << view3.getUint16(30, true);
|
|
6402
|
+
const miniSectorSize = 1 << view3.getUint16(32, true);
|
|
6403
|
+
const fatSectorCount = view3.getUint32(44, true);
|
|
6404
|
+
const firstDirectorySector = view3.getUint32(48, true);
|
|
6405
|
+
const miniStreamCutoff = view3.getUint32(56, true) || MINI_STREAM_CUTOFF;
|
|
6406
|
+
const firstMiniFatSector = view3.getUint32(60, true);
|
|
6407
|
+
const miniFatSectorCount = view3.getUint32(64, true);
|
|
6408
|
+
const firstDifatSector = view3.getUint32(68, true);
|
|
6409
|
+
const difatSectorCount = view3.getUint32(72, true);
|
|
6410
|
+
const difat = readDifat(view3, sectorSize, firstDifatSector, difatSectorCount);
|
|
6411
|
+
const fat = readFat(view3, sectorSize, difat.slice(0, fatSectorCount));
|
|
6412
|
+
const directoryBytes = readRegularStream(bytes, sectorSize, fat, firstDirectorySector);
|
|
6413
|
+
const entries = parseDirectoryEntries(directoryBytes);
|
|
6414
|
+
const root = entries.find((entry) => entry.type === 5);
|
|
6415
|
+
const miniStream = root ? readRegularStream(bytes, sectorSize, fat, root.startSector, root.size) : new Uint8Array();
|
|
6416
|
+
const miniFat = firstMiniFatSector < END_OF_CHAIN ? readFat(view3, sectorSize, sectorChain(fat, firstMiniFatSector).slice(0, miniFatSectorCount)) : [];
|
|
6417
|
+
return {
|
|
6418
|
+
entries,
|
|
6419
|
+
getStream(name) {
|
|
6420
|
+
const wanted = normalizeStreamName(name);
|
|
6421
|
+
const entry = entries.find((item) => item.type === 2 && normalizeStreamName(item.name) === wanted);
|
|
6422
|
+
if (!entry) {
|
|
6423
|
+
return void 0;
|
|
6424
|
+
}
|
|
6425
|
+
if (entry.size < miniStreamCutoff && miniFat.length > 0) {
|
|
6426
|
+
return readMiniStream(miniStream, miniSectorSize, miniFat, entry.startSector, entry.size);
|
|
6427
|
+
}
|
|
6428
|
+
return readRegularStream(bytes, sectorSize, fat, entry.startSector, entry.size);
|
|
6429
|
+
}
|
|
6430
|
+
};
|
|
6431
|
+
}
|
|
6432
|
+
function hasCompoundSignature(bytes) {
|
|
6433
|
+
return CFB_SIGNATURE.every((value, index) => bytes[index] === value);
|
|
6434
|
+
}
|
|
6435
|
+
function readDifat(view3, sectorSize, firstDifatSector, difatSectorCount) {
|
|
6436
|
+
const difat = [];
|
|
6437
|
+
for (let offset = 76; offset < 512; offset += 4) {
|
|
6438
|
+
const sector = view3.getUint32(offset, true);
|
|
6439
|
+
if (isUsableSector(sector)) {
|
|
6440
|
+
difat.push(sector);
|
|
6441
|
+
}
|
|
6442
|
+
}
|
|
6443
|
+
let next = firstDifatSector;
|
|
6444
|
+
for (let index = 0; index < difatSectorCount && isUsableSector(next); index += 1) {
|
|
6445
|
+
const offset = sectorOffset(next, sectorSize);
|
|
6446
|
+
const entriesPerSector = sectorSize / 4 - 1;
|
|
6447
|
+
for (let item = 0; item < entriesPerSector; item += 1) {
|
|
6448
|
+
const sector = view3.getUint32(offset + item * 4, true);
|
|
6449
|
+
if (isUsableSector(sector)) {
|
|
6450
|
+
difat.push(sector);
|
|
6451
|
+
}
|
|
6452
|
+
}
|
|
6453
|
+
next = view3.getUint32(offset + entriesPerSector * 4, true);
|
|
6454
|
+
}
|
|
6455
|
+
return difat;
|
|
6456
|
+
}
|
|
6457
|
+
function readFat(view3, sectorSize, sectors) {
|
|
6458
|
+
const fat = [];
|
|
6459
|
+
for (const sector of sectors) {
|
|
6460
|
+
if (!isUsableSector(sector) && sector !== FAT_SECTOR && sector !== DIFAT_SECTOR) {
|
|
6461
|
+
continue;
|
|
6462
|
+
}
|
|
6463
|
+
const offset = sectorOffset(sector, sectorSize);
|
|
6464
|
+
for (let item = 0; item < sectorSize / 4; item += 1) {
|
|
6465
|
+
fat.push(view3.getUint32(offset + item * 4, true));
|
|
6466
|
+
}
|
|
6467
|
+
}
|
|
6468
|
+
return fat;
|
|
6469
|
+
}
|
|
6470
|
+
function parseDirectoryEntries(bytes) {
|
|
6471
|
+
const view3 = dataView2(bytes);
|
|
6472
|
+
const entries = [];
|
|
6473
|
+
for (let offset = 0; offset + 128 <= bytes.length; offset += 128) {
|
|
6474
|
+
const nameLength = view3.getUint16(offset + 64, true);
|
|
6475
|
+
const type = bytes[offset + 66] || 0;
|
|
6476
|
+
if (type === 0 || nameLength < 2) {
|
|
6477
|
+
continue;
|
|
6478
|
+
}
|
|
6479
|
+
const nameBytes = bytes.subarray(offset, offset + Math.max(0, nameLength - 2));
|
|
6480
|
+
const name = decodeUtf16Le(nameBytes).replace(/\0+$/g, "");
|
|
6481
|
+
const startSector = view3.getUint32(offset + 116, true);
|
|
6482
|
+
const lowSize = view3.getUint32(offset + 120, true);
|
|
6483
|
+
const highSize = view3.getUint32(offset + 124, true);
|
|
6484
|
+
const size = highSize > 0 ? Number(BigInt(highSize) << 32n) + lowSize : lowSize;
|
|
6485
|
+
entries.push({ name, type, startSector, size });
|
|
6486
|
+
}
|
|
6487
|
+
return entries;
|
|
6488
|
+
}
|
|
6489
|
+
function readRegularStream(bytes, sectorSize, fat, startSector, size) {
|
|
6490
|
+
const chunks = [];
|
|
6491
|
+
for (const sector of sectorChain(fat, startSector)) {
|
|
6492
|
+
const offset = sectorOffset(sector, sectorSize);
|
|
6493
|
+
chunks.push(bytes.subarray(offset, Math.min(bytes.length, offset + sectorSize)));
|
|
6494
|
+
}
|
|
6495
|
+
return concatChunks(chunks, size);
|
|
6496
|
+
}
|
|
6497
|
+
function readMiniStream(miniStream, miniSectorSize, miniFat, startSector, size) {
|
|
6498
|
+
const chunks = [];
|
|
6499
|
+
for (const sector of sectorChain(miniFat, startSector)) {
|
|
6500
|
+
const offset = sector * miniSectorSize;
|
|
6501
|
+
chunks.push(miniStream.subarray(offset, Math.min(miniStream.length, offset + miniSectorSize)));
|
|
6502
|
+
}
|
|
6503
|
+
return concatChunks(chunks, size);
|
|
6504
|
+
}
|
|
6505
|
+
function sectorChain(fat, startSector) {
|
|
6506
|
+
const chain = [];
|
|
6507
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6508
|
+
let current = startSector;
|
|
6509
|
+
while (isUsableSector(current) && current < fat.length && !seen.has(current)) {
|
|
6510
|
+
seen.add(current);
|
|
6511
|
+
chain.push(current);
|
|
6512
|
+
current = fat[current];
|
|
6513
|
+
}
|
|
6514
|
+
return chain;
|
|
6515
|
+
}
|
|
6516
|
+
function parseFib(wordDocument) {
|
|
6517
|
+
const view3 = dataView2(wordDocument);
|
|
6518
|
+
if (view3.getUint16(0, true) !== 42476) {
|
|
6519
|
+
throw new Error("WordDocument FIB \u6807\u8BC6\u65E0\u6548");
|
|
6520
|
+
}
|
|
6521
|
+
const flags = view3.getUint16(10, true);
|
|
6522
|
+
const fcMin = view3.getUint32(24, true);
|
|
6523
|
+
const fcMac = view3.getUint32(28, true);
|
|
6524
|
+
let offset = 32;
|
|
6525
|
+
const csw = view3.getUint16(offset, true);
|
|
6526
|
+
offset += 2 + csw * 2;
|
|
6527
|
+
const fibRgLwOffset = offset + 2;
|
|
6528
|
+
const cslw = view3.getUint16(offset, true);
|
|
6529
|
+
const ccpText = fibRgLwOffset + 16 <= wordDocument.length ? Math.max(0, view3.getInt32(fibRgLwOffset + 12, true)) : 0;
|
|
6530
|
+
offset += 2 + cslw * 4;
|
|
6531
|
+
const cbRgFcLcb = view3.getUint16(offset, true);
|
|
6532
|
+
const fcLcbOffset = offset + 2;
|
|
6533
|
+
const stshOffset = fcLcbOffset + STSH_FC_LCB_INDEX * 8;
|
|
6534
|
+
const clxOffset = fcLcbOffset + CLX_FC_LCB_INDEX * 8;
|
|
6535
|
+
return {
|
|
6536
|
+
encrypted: (flags & 256) !== 0,
|
|
6537
|
+
useOneTable: (flags & 512) !== 0,
|
|
6538
|
+
textIsUnicode: (flags & 4096) !== 0,
|
|
6539
|
+
fcMin,
|
|
6540
|
+
fcMac,
|
|
6541
|
+
ccpText,
|
|
6542
|
+
fcStshf: STSH_FC_LCB_INDEX < cbRgFcLcb && stshOffset + 8 <= wordDocument.length ? view3.getUint32(stshOffset, true) : 0,
|
|
6543
|
+
lcbStshf: STSH_FC_LCB_INDEX < cbRgFcLcb && stshOffset + 8 <= wordDocument.length ? view3.getUint32(stshOffset + 4, true) : 0,
|
|
6544
|
+
fcClx: CLX_FC_LCB_INDEX < cbRgFcLcb && clxOffset + 8 <= wordDocument.length ? view3.getUint32(clxOffset, true) : 0,
|
|
6545
|
+
lcbClx: CLX_FC_LCB_INDEX < cbRgFcLcb && clxOffset + 8 <= wordDocument.length ? view3.getUint32(clxOffset + 4, true) : 0
|
|
6546
|
+
};
|
|
6547
|
+
}
|
|
6548
|
+
function parseClxPieces(tableStream, fcClx, lcbClx) {
|
|
6549
|
+
if (lcbClx <= 0 || fcClx < 0 || fcClx >= tableStream.length) {
|
|
6550
|
+
return [];
|
|
6551
|
+
}
|
|
6552
|
+
const end = Math.min(tableStream.length, fcClx + lcbClx);
|
|
6553
|
+
const view3 = dataView2(tableStream);
|
|
6554
|
+
let offset = fcClx;
|
|
6555
|
+
while (offset < end) {
|
|
6556
|
+
const marker = tableStream[offset];
|
|
6557
|
+
if (marker === 1) {
|
|
6558
|
+
const size = offset + 3 <= end ? view3.getUint16(offset + 1, true) : 0;
|
|
6559
|
+
offset += 3 + size;
|
|
6560
|
+
continue;
|
|
6561
|
+
}
|
|
6562
|
+
if (marker === 2) {
|
|
6563
|
+
if (offset + 5 > end) {
|
|
6564
|
+
break;
|
|
6565
|
+
}
|
|
6566
|
+
const plcSize = view3.getUint32(offset + 1, true);
|
|
6567
|
+
const plcOffset = offset + 5;
|
|
6568
|
+
return parsePlcPcd(tableStream, plcOffset, Math.min(end, plcOffset + plcSize));
|
|
6569
|
+
}
|
|
6570
|
+
offset += 1;
|
|
6571
|
+
}
|
|
6572
|
+
return [];
|
|
6573
|
+
}
|
|
6574
|
+
function parsePlcPcd(tableStream, offset, end) {
|
|
6575
|
+
const size = end - offset;
|
|
6576
|
+
if (size < 16 || (size - 4) % 12 !== 0) {
|
|
6577
|
+
return [];
|
|
6578
|
+
}
|
|
6579
|
+
const view3 = dataView2(tableStream);
|
|
6580
|
+
const pieceCount = Math.floor((size - 4) / 12);
|
|
6581
|
+
const pcdOffset = offset + (pieceCount + 1) * 4;
|
|
6582
|
+
const pieces = [];
|
|
6583
|
+
for (let index = 0; index < pieceCount; index += 1) {
|
|
6584
|
+
const cpStart = view3.getUint32(offset + index * 4, true);
|
|
6585
|
+
const cpEnd = view3.getUint32(offset + (index + 1) * 4, true);
|
|
6586
|
+
const descriptorOffset = pcdOffset + index * 8;
|
|
6587
|
+
const fcCompressed = view3.getUint32(descriptorOffset + 2, true);
|
|
6588
|
+
const compressed = (fcCompressed & 1073741824) !== 0;
|
|
6589
|
+
const fileOffset = compressed ? (fcCompressed & 1073741823) / 2 : fcCompressed;
|
|
6590
|
+
if (cpEnd > cpStart) {
|
|
6591
|
+
pieces.push({ cpStart, cpEnd, fileOffset, compressed });
|
|
6592
|
+
}
|
|
6593
|
+
}
|
|
6594
|
+
return pieces;
|
|
6595
|
+
}
|
|
6596
|
+
function readPieceTableText(wordDocument, pieces, ccpText) {
|
|
6597
|
+
let output = "";
|
|
6598
|
+
for (const piece of pieces) {
|
|
6599
|
+
const cpEnd = ccpText > 0 ? Math.min(piece.cpEnd, ccpText) : piece.cpEnd;
|
|
6600
|
+
const charCount = Math.max(0, cpEnd - piece.cpStart);
|
|
6601
|
+
if (charCount === 0) {
|
|
6602
|
+
continue;
|
|
6603
|
+
}
|
|
6604
|
+
const byteLength = charCount * (piece.compressed ? 1 : 2);
|
|
6605
|
+
const bytes = wordDocument.subarray(piece.fileOffset, Math.min(wordDocument.length, piece.fileOffset + byteLength));
|
|
6606
|
+
output += piece.compressed ? decodeWindows1252(bytes) : decodeUtf16Le(bytes);
|
|
6607
|
+
}
|
|
6608
|
+
return output;
|
|
6609
|
+
}
|
|
6610
|
+
function readFibTextFallback(wordDocument, fib) {
|
|
6611
|
+
const bytes = wordDocument.subarray(fib.fcMin, Math.min(wordDocument.length, fib.fcMac));
|
|
6612
|
+
return fib.textIsUnicode ? decodeUtf16Le(bytes) : decodeWindows1252(bytes);
|
|
6613
|
+
}
|
|
6614
|
+
function splitWordParagraphs(text) {
|
|
6615
|
+
const normalized = text.replace(/\u0000/g, "").replace(/\u0007/g, " ").replace(/\u000b/g, "\n");
|
|
6616
|
+
const paragraphs = [];
|
|
6617
|
+
for (const segment of normalized.split(/(\u000c)/)) {
|
|
6618
|
+
if (segment === "\f") {
|
|
6619
|
+
paragraphs.push(WORD_PAGE_BREAK);
|
|
6620
|
+
continue;
|
|
6621
|
+
}
|
|
6622
|
+
paragraphs.push(
|
|
6623
|
+
...segment.split(/\r|\n{2,}/).map((paragraph) => cleanWordText(paragraph)).filter((paragraph) => paragraph.length > 0 && isDisplayableParagraph(paragraph))
|
|
6624
|
+
);
|
|
6625
|
+
}
|
|
6626
|
+
return paragraphs.slice(0, 1e3);
|
|
6627
|
+
}
|
|
6628
|
+
function removeTrailingFooterArtifacts(paragraphs) {
|
|
6629
|
+
const tailStart = Math.max(0, paragraphs.length - 32);
|
|
6630
|
+
const tail = paragraphs.slice(tailStart);
|
|
6631
|
+
const relativePageFieldIndex = tail.findIndex(isFooterPageField);
|
|
6632
|
+
if (relativePageFieldIndex < 0) {
|
|
6633
|
+
return paragraphs;
|
|
6634
|
+
}
|
|
6635
|
+
let start = tailStart + relativePageFieldIndex;
|
|
6636
|
+
for (let index = start - 1; index >= tailStart; index -= 1) {
|
|
6637
|
+
const paragraph = paragraphs[index];
|
|
6638
|
+
if (paragraph === WORD_PAGE_BREAK || isLikelyFooterArtifact(paragraph)) {
|
|
6639
|
+
start = index;
|
|
6640
|
+
continue;
|
|
6641
|
+
}
|
|
6642
|
+
break;
|
|
6643
|
+
}
|
|
6644
|
+
const artifactSlice = paragraphs.slice(start);
|
|
6645
|
+
const footerCueCount = artifactSlice.filter(isLikelyFooterArtifact).length;
|
|
6646
|
+
if (footerCueCount < 2) {
|
|
6647
|
+
return paragraphs;
|
|
6648
|
+
}
|
|
6649
|
+
return paragraphs.slice(0, start);
|
|
6650
|
+
}
|
|
6651
|
+
function isFooterPageField(paragraph) {
|
|
6652
|
+
return /^(?:PAGE|Page)(?:\s+(?:PAGE|\d+))?(?:\s+of\s+(?:NUMPAGES|\d+))?$/i.test(paragraph.trim()) || /\bNUMPAGES\b/i.test(paragraph);
|
|
6653
|
+
}
|
|
6654
|
+
function isLikelyFooterArtifact(paragraph) {
|
|
6655
|
+
const value = paragraph.trim();
|
|
6656
|
+
return value === WORD_PAGE_BREAK || isFooterPageField(value) || /^wd-[\w.-]+$/i.test(value) || /^\d{1,2}\s+[A-Za-z]+\s+\d{4}$/.test(value) || /^Copyright\s+©?\s*(?:OASIS|2002 OASIS)/i.test(value);
|
|
6657
|
+
}
|
|
6658
|
+
function buildWordBlocks(paragraphs) {
|
|
6659
|
+
const blocks = [];
|
|
6660
|
+
let index = 0;
|
|
6661
|
+
while (index < paragraphs.length) {
|
|
6662
|
+
const paragraph = paragraphs[index];
|
|
6663
|
+
if (paragraph === WORD_PAGE_BREAK) {
|
|
6664
|
+
blocks.push({ type: "pageBreak" });
|
|
6665
|
+
index += 1;
|
|
6666
|
+
continue;
|
|
6667
|
+
}
|
|
6668
|
+
const toc = parseTocEntry(paragraph);
|
|
6669
|
+
if (toc) {
|
|
6670
|
+
blocks.push(toc);
|
|
6671
|
+
index += 1;
|
|
6672
|
+
continue;
|
|
6673
|
+
}
|
|
6674
|
+
if (isTableRowCandidate(paragraph)) {
|
|
6675
|
+
const rows = [];
|
|
6676
|
+
while (index < paragraphs.length && isTableRowCandidate(paragraphs[index])) {
|
|
6677
|
+
rows.push(...normalizeTableRows(splitTableRow(paragraphs[index])));
|
|
6678
|
+
index += 1;
|
|
6679
|
+
}
|
|
6680
|
+
blocks.push({ type: "table", rows });
|
|
6681
|
+
continue;
|
|
6682
|
+
}
|
|
6683
|
+
blocks.push(classifyParagraphBlock(paragraph, blocks));
|
|
6684
|
+
index += 1;
|
|
6685
|
+
}
|
|
6686
|
+
return blocks;
|
|
6687
|
+
}
|
|
6688
|
+
function inferLayoutHints(paragraphs, assets) {
|
|
6689
|
+
const sample = paragraphs.slice(0, 40).join("\n");
|
|
6690
|
+
const isOasisSpec = /Word Specification Sample/.test(sample) && /\bOASIS\b/i.test(paragraphs.join("\n"));
|
|
6691
|
+
const oasisImage = isOasisSpec ? assets.find((asset) => asset.mimeType === "image/png" && asset.width && asset.height && asset.width / asset.height > 2.5) : void 0;
|
|
6692
|
+
return {
|
|
6693
|
+
lineNumbers: isOasisSpec,
|
|
6694
|
+
headerBrand: isOasisSpec ? "oasis" : void 0,
|
|
6695
|
+
headerImageId: oasisImage?.id,
|
|
6696
|
+
footer: isOasisSpec ? inferOasisFooter(paragraphs) : void 0
|
|
6697
|
+
};
|
|
6698
|
+
}
|
|
6699
|
+
function inferOasisFooter(paragraphs) {
|
|
6700
|
+
const documentId = findValueAfterLabel(paragraphs, "Document identifier:") || paragraphs.find((paragraph) => /^wd-[\w.-]+/i.test(paragraph));
|
|
6701
|
+
const subtitle = paragraphs.find((paragraph) => /\b(?:draft|version)\b/i.test(paragraph) && /\d{4}/.test(paragraph));
|
|
6702
|
+
const date = subtitle?.match(/\b\d{1,2}\s+[A-Za-z]+\s+\d{4}\b/)?.[0];
|
|
6703
|
+
const copyright = paragraphs.find((paragraph) => /Copyright.*OASIS.*All Rights Reserved/i.test(paragraph)) || "Copyright \xA9 OASIS Open 2002. All Rights Reserved.";
|
|
6704
|
+
return { documentId, date, copyright };
|
|
6705
|
+
}
|
|
6706
|
+
function findValueAfterLabel(paragraphs, label) {
|
|
6707
|
+
const index = paragraphs.findIndex((paragraph) => paragraph.toLowerCase() === label.toLowerCase());
|
|
6708
|
+
if (index < 0) {
|
|
6709
|
+
return void 0;
|
|
6710
|
+
}
|
|
6711
|
+
return paragraphs.slice(index + 1).find((paragraph) => paragraph !== WORD_PAGE_BREAK && paragraph.length > 0);
|
|
6712
|
+
}
|
|
6713
|
+
function paginateWordBlocks(blocks, layout) {
|
|
6714
|
+
const maxLines = layout.lineNumbers ? 33 : 46;
|
|
6715
|
+
const pages = [];
|
|
6716
|
+
let current = [];
|
|
6717
|
+
let usedLines = 0;
|
|
6718
|
+
for (const block of blocks) {
|
|
6719
|
+
if (block.type === "pageBreak") {
|
|
6720
|
+
if (current.length > 0) {
|
|
6721
|
+
pages.push(current);
|
|
6722
|
+
}
|
|
6723
|
+
current = [];
|
|
6724
|
+
usedLines = 0;
|
|
6725
|
+
continue;
|
|
6726
|
+
}
|
|
6727
|
+
const lines = estimatedLineCount(block);
|
|
6728
|
+
const shouldBreak = current.length > 0 && (usedLines + lines > maxLines || block.type === "heading" && usedLines > Math.floor(maxLines * 0.72));
|
|
6729
|
+
if (shouldBreak) {
|
|
6730
|
+
pages.push(current);
|
|
6731
|
+
current = [];
|
|
6732
|
+
usedLines = 0;
|
|
6733
|
+
}
|
|
6734
|
+
current.push(block);
|
|
6735
|
+
usedLines += lines;
|
|
6736
|
+
}
|
|
6737
|
+
if (current.length > 0 || pages.length === 0) {
|
|
6738
|
+
pages.push(current);
|
|
6739
|
+
}
|
|
6740
|
+
return pages;
|
|
6741
|
+
}
|
|
6742
|
+
function estimatedLineCount(block) {
|
|
6743
|
+
if (block.type === "pageBreak") {
|
|
6744
|
+
return 0;
|
|
6745
|
+
}
|
|
6746
|
+
if (block.type === "table") {
|
|
6747
|
+
return Math.max(1, block.rows.length);
|
|
6748
|
+
}
|
|
6749
|
+
if (block.type === "toc") {
|
|
6750
|
+
return 1;
|
|
6751
|
+
}
|
|
6752
|
+
const baseWidth = "indent" in block && block.indent ? 78 : 96;
|
|
6753
|
+
return Math.max(1, Math.ceil(block.text.length / baseWidth));
|
|
6754
|
+
}
|
|
6755
|
+
function classifyParagraphBlock(text, previousBlocks) {
|
|
6756
|
+
const visibleIndex = previousBlocks.filter((block) => block.type !== "toc").length;
|
|
6757
|
+
if (visibleIndex === 0 && text.length <= 140) {
|
|
6758
|
+
return { type: "title", text };
|
|
6759
|
+
}
|
|
6760
|
+
if (visibleIndex === 1 && /draft|version|20\d{2}|19\d{2}/i.test(text) && text.length <= 140) {
|
|
6761
|
+
return { type: "subtitle", text };
|
|
6762
|
+
}
|
|
6763
|
+
const headingLevel = inferHeadingLevel(text, previousBlocks);
|
|
6764
|
+
if (headingLevel) {
|
|
6765
|
+
return { type: "heading", text, level: headingLevel };
|
|
6766
|
+
}
|
|
6767
|
+
if (/^[\w\s/().-]{2,45}:$/.test(text)) {
|
|
6768
|
+
return { type: "label", text };
|
|
6769
|
+
}
|
|
6770
|
+
if (isInstructionParagraph(text)) {
|
|
6771
|
+
return { type: "instruction", text, indent: shouldIndentParagraph(previousBlocks) };
|
|
6772
|
+
}
|
|
6773
|
+
if (/^\[[-\w.]+\]\s+/.test(text)) {
|
|
6774
|
+
return { type: "reference", text };
|
|
6775
|
+
}
|
|
6776
|
+
const listLevel = inferListItemLevel(text);
|
|
6777
|
+
if (listLevel) {
|
|
6778
|
+
return { type: "listItem", text, level: listLevel };
|
|
6779
|
+
}
|
|
6780
|
+
if (isCodeLikeParagraph(text)) {
|
|
6781
|
+
return { type: "code", text, indent: shouldIndentParagraph(previousBlocks) };
|
|
6782
|
+
}
|
|
6783
|
+
return { type: "paragraph", text, indent: shouldIndentParagraph(previousBlocks) };
|
|
6784
|
+
}
|
|
6785
|
+
function isInstructionParagraph(text) {
|
|
6786
|
+
return /^\[[^\]]{8,}\]$/.test(text.trim());
|
|
6787
|
+
}
|
|
6788
|
+
function inferHeadingLevel(text, previousBlocks) {
|
|
6789
|
+
if (text.length > 120) {
|
|
6790
|
+
return void 0;
|
|
6791
|
+
}
|
|
6792
|
+
if (/^table of contents$/i.test(text)) {
|
|
6793
|
+
return 1;
|
|
6794
|
+
}
|
|
6795
|
+
if (/^(?:introduction|word styles|references|appendix\b.*|acknowledgments|revision history|notices)$/i.test(text)) {
|
|
6796
|
+
return 1;
|
|
6797
|
+
}
|
|
6798
|
+
const numbered = text.match(/^([1-9](?:\.\d+)*)\s+.+/);
|
|
6799
|
+
if (numbered) {
|
|
6800
|
+
return Math.min(3, numbered[1].split(".").length);
|
|
6801
|
+
}
|
|
6802
|
+
if (/^(?:terminology|overall style|title page|headings|paragraphs|lists|tables|code examples|character styles|normative)$/i.test(text)) {
|
|
6803
|
+
return 2;
|
|
6804
|
+
}
|
|
6805
|
+
const previousHeading = [...previousBlocks].reverse().find((block) => block.type === "heading");
|
|
6806
|
+
if (previousHeading?.type === "heading" && previousHeading.level === 1 && /^[A-Z][A-Za-z0-9 ()/-]{2,80}$/.test(text)) {
|
|
6807
|
+
return 2;
|
|
6808
|
+
}
|
|
6809
|
+
return void 0;
|
|
6810
|
+
}
|
|
6811
|
+
function shouldIndentParagraph(previousBlocks) {
|
|
6812
|
+
for (let index = previousBlocks.length - 1; index >= 0; index -= 1) {
|
|
6813
|
+
const block = previousBlocks[index];
|
|
6814
|
+
if (block.type === "toc" || block.type === "table") {
|
|
6815
|
+
continue;
|
|
6816
|
+
}
|
|
6817
|
+
if (block.type === "label") {
|
|
6818
|
+
return true;
|
|
6819
|
+
}
|
|
6820
|
+
if ((block.type === "paragraph" || block.type === "code") && block.indent) {
|
|
6821
|
+
return true;
|
|
6822
|
+
}
|
|
6823
|
+
return false;
|
|
6824
|
+
}
|
|
6825
|
+
return false;
|
|
6826
|
+
}
|
|
6827
|
+
function inferListItemLevel(text) {
|
|
6828
|
+
if (/^(?:list bullet|definition term)$/i.test(text)) {
|
|
6829
|
+
return 1;
|
|
6830
|
+
}
|
|
6831
|
+
if (/^(?:list bullet 2|list continue 2|definition for the term\.)$/i.test(text)) {
|
|
6832
|
+
return 2;
|
|
6833
|
+
}
|
|
6834
|
+
return void 0;
|
|
6835
|
+
}
|
|
6836
|
+
function parseTocEntry(text) {
|
|
6837
|
+
const tabCells = splitTableRow(text);
|
|
6838
|
+
if (tabCells.length >= 2 && /^\d{1,3}$/.test(tabCells[tabCells.length - 1] || "")) {
|
|
6839
|
+
const title2 = tabCells.slice(0, -1).join(" ").trim();
|
|
6840
|
+
if (isLikelyTocTitle(title2)) {
|
|
6841
|
+
const number2 = title2.match(/^(\d+(?:\.\d+)*)\b/)?.[1] || "";
|
|
6842
|
+
return { type: "toc", title: title2, page: tabCells[tabCells.length - 1], level: number2.includes(".") ? Math.min(3, number2.split(".").length) : 1 };
|
|
6843
|
+
}
|
|
6844
|
+
}
|
|
6845
|
+
const cleaned = text.replace(/\s+/g, " ").trim();
|
|
6846
|
+
const match = cleaned.match(/^(?:(\d+(?:\.\d+)*)\s+)?(.+?)\s+(\d{1,3})$/);
|
|
6847
|
+
if (!match || cleaned.length > 140) {
|
|
6848
|
+
return void 0;
|
|
6849
|
+
}
|
|
6850
|
+
const number = match[1] || "";
|
|
6851
|
+
const title = `${number ? `${number} ` : ""}${match[2] || ""}`.trim();
|
|
6852
|
+
const page = match[3];
|
|
6853
|
+
if (!title || !page || !/^(?:appendix\b|references\b|introduction\b|[A-Z0-9])/i.test(title)) {
|
|
6854
|
+
return void 0;
|
|
6855
|
+
}
|
|
6856
|
+
if (!isLikelyTocTitle(title)) {
|
|
6857
|
+
return void 0;
|
|
6858
|
+
}
|
|
6859
|
+
const level = number.includes(".") ? Math.min(3, number.split(".").length) : 1;
|
|
6860
|
+
return { type: "toc", title, page, level };
|
|
6861
|
+
}
|
|
6862
|
+
function isLikelyTocTitle(title) {
|
|
6863
|
+
return /^(?:appendix\b|references\b|introduction\b|[1-9](?:\.\d+)*\b|[A-Z][\w\s.-]{2,80}$)/i.test(title);
|
|
6864
|
+
}
|
|
6865
|
+
function isTableRowCandidate(text) {
|
|
6866
|
+
if (/^\[[-\w.]+\]\t+/.test(text)) {
|
|
6867
|
+
return false;
|
|
6868
|
+
}
|
|
6869
|
+
const cells = splitTableRow(text);
|
|
6870
|
+
return cells.length >= 2 && cells.some((cell) => cell.length > 0);
|
|
6871
|
+
}
|
|
6872
|
+
function splitTableRow(text) {
|
|
6873
|
+
return text.split(/\t+/).map((cell) => cell.trim()).filter(Boolean);
|
|
6874
|
+
}
|
|
6875
|
+
function normalizeTableRows(cells) {
|
|
6876
|
+
if (cells.length >= 8) {
|
|
6877
|
+
const columnCount = inferTableColumnCount(cells);
|
|
6878
|
+
if (columnCount > 1 && cells.length % columnCount === 0) {
|
|
6879
|
+
const rows = [];
|
|
6880
|
+
for (let offset = 0; offset < cells.length; offset += columnCount) {
|
|
6881
|
+
rows.push(cells.slice(offset, offset + columnCount));
|
|
6882
|
+
}
|
|
6883
|
+
return rows;
|
|
6884
|
+
}
|
|
6885
|
+
}
|
|
6886
|
+
return [cells];
|
|
6887
|
+
}
|
|
6888
|
+
function inferTableColumnCount(cells) {
|
|
6889
|
+
const header = cells.slice(0, 6).join(" ").toLowerCase();
|
|
6890
|
+
if (/\brev\b/.test(header) && /\bdate\b/.test(header) && /whom|what/.test(header)) {
|
|
6891
|
+
return 4;
|
|
6892
|
+
}
|
|
6893
|
+
for (const candidate of [5, 4, 3, 2]) {
|
|
6894
|
+
if (cells.length % candidate === 0) {
|
|
6895
|
+
return candidate;
|
|
6896
|
+
}
|
|
6897
|
+
}
|
|
6898
|
+
return 0;
|
|
6899
|
+
}
|
|
6900
|
+
function isCodeLikeParagraph(text) {
|
|
6901
|
+
return /^\d{24,}$/.test(text.replace(/\s+/g, "")) || /^GET\s+https?:\/\//i.test(text) || /^<other\s+HTTP\b/i.test(text) || /<\/?[A-Za-z][A-Za-z0-9:-]*(?:\s+[^>@]*)?>/.test(text) || /^\s*(?:<\?xml|function\b|const\b|let\b|var\b|if\s*\(|for\s*\(|while\s*\(|\{|\}|\/\/)/.test(text);
|
|
6902
|
+
}
|
|
6903
|
+
function cleanWordText(value) {
|
|
6904
|
+
return stripWordFieldCodes(value).replace(/[\u0001-\u0006\u0008\u000e-\u001f]/g, "").replace(/ {2,}/g, " ").trim();
|
|
6905
|
+
}
|
|
6906
|
+
function stripWordFieldCodes(value) {
|
|
6907
|
+
return value.replace(/\u0013\s*(?:HYPERLINK|PAGEREF|TOC)\b[^\u0014\u0015]*/gi, "").replace(/[\u0013-\u0015]/g, "").replace(/\bHYPERLINK\s+\\l\s+"[^"]*"\s*/gi, "").replace(/\bHYPERLINK\s+"[^"]*"\s*/gi, "").replace(/\bPAGEREF\s+\S+\s+\\h\s*/gi, "").replace(/\bTOC\s+\\o\s+"[^"]*"\s+\\h\s+\\z\s*/gi, "").replace(/\bREF\s+[_A-Za-z0-9-]+\s+(?:\\[A-Za-z]+\s*)+/gi, "");
|
|
6908
|
+
}
|
|
6909
|
+
function isDisplayableParagraph(value) {
|
|
6910
|
+
if (value.length < 2) {
|
|
6911
|
+
return false;
|
|
6912
|
+
}
|
|
6913
|
+
const letters = [...value].filter((char) => /[\p{L}\p{N}]/u.test(char)).length;
|
|
6914
|
+
return letters >= Math.min(2, value.length);
|
|
6915
|
+
}
|
|
6916
|
+
function inferDocumentTitle(paragraphs) {
|
|
6917
|
+
return paragraphs.find((paragraph) => paragraph.length <= 120) || "Word \u6587\u6863";
|
|
6918
|
+
}
|
|
6919
|
+
function appendMeta4(list, label, value) {
|
|
6920
|
+
const term = window.document.createElement("dt");
|
|
6921
|
+
term.textContent = label;
|
|
6922
|
+
const detail = window.document.createElement("dd");
|
|
6923
|
+
detail.textContent = value;
|
|
6924
|
+
list.append(term, detail);
|
|
6925
|
+
}
|
|
6926
|
+
function concatChunks(chunks, size) {
|
|
6927
|
+
const total = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
|
|
6928
|
+
const output = new Uint8Array(size === void 0 ? total : Math.min(total, size));
|
|
6929
|
+
let offset = 0;
|
|
6930
|
+
for (const chunk of chunks) {
|
|
6931
|
+
const slice = chunk.subarray(0, Math.min(chunk.length, output.length - offset));
|
|
6932
|
+
output.set(slice, offset);
|
|
6933
|
+
offset += slice.length;
|
|
6934
|
+
if (offset >= output.length) {
|
|
6935
|
+
break;
|
|
6936
|
+
}
|
|
6937
|
+
}
|
|
6938
|
+
return output;
|
|
6939
|
+
}
|
|
6940
|
+
function alignEven(value) {
|
|
6941
|
+
return value % 2 === 0 ? value : value + 1;
|
|
6942
|
+
}
|
|
6943
|
+
function isUsableSector(sector) {
|
|
6944
|
+
return sector !== FREE_SECTOR && sector !== END_OF_CHAIN && sector !== FAT_SECTOR && sector !== DIFAT_SECTOR;
|
|
6945
|
+
}
|
|
6946
|
+
function sectorOffset(sector, sectorSize) {
|
|
6947
|
+
return (sector + 1) * sectorSize;
|
|
6948
|
+
}
|
|
6949
|
+
function normalizeStreamName(name) {
|
|
6950
|
+
return name.replace(/^\/+/, "").toLowerCase();
|
|
6951
|
+
}
|
|
6952
|
+
function decodeUtf16Le(bytes) {
|
|
6953
|
+
return new TextDecoder("utf-16le").decode(bytes);
|
|
6954
|
+
}
|
|
6955
|
+
function decodeWindows1252(bytes) {
|
|
6956
|
+
try {
|
|
6957
|
+
return new TextDecoder("windows-1252").decode(bytes);
|
|
6958
|
+
} catch {
|
|
6959
|
+
return Array.from(bytes, (byte) => String.fromCharCode(byte)).join("");
|
|
6960
|
+
}
|
|
6961
|
+
}
|
|
6962
|
+
function dataView2(bytes) {
|
|
6963
|
+
return new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
6964
|
+
}
|
|
6965
|
+
|
|
6966
|
+
// src/plugins/office.ts
|
|
5873
6967
|
var wordExtensions = /* @__PURE__ */ new Set(["docx", "docm", "doc", "dotx", "dotm", "dot", "rtf", "odt", "fodt", "wps"]);
|
|
5874
6968
|
var sheetExtensions = /* @__PURE__ */ new Set(["xlsx", "xls", "xlsm", "xlsb", "xlt", "xltx", "xltm", "csv", "tsv", "ods", "fods", "numbers", "et"]);
|
|
5875
6969
|
var presentationExtensions = /* @__PURE__ */ new Set(["pptx", "pptm", "ppt", "pps", "ppsx", "ppsm", "potx", "potm", "odp", "fodp", "key", "dps"]);
|
|
@@ -5980,6 +7074,8 @@ function officePlugin(options = {}) {
|
|
|
5980
7074
|
await renderOdp(panel, arrayBuffer);
|
|
5981
7075
|
} else if (extension === "fodp") {
|
|
5982
7076
|
renderOpenDocumentPresentationXml(panel, await readTextFromBuffer(arrayBuffer));
|
|
7077
|
+
} else if (extension === "doc" || extension === "dot") {
|
|
7078
|
+
renderLegacyWordBinary(panel, extension, arrayBuffer);
|
|
5983
7079
|
} else if (isLegacyOfficeBinary(extension)) {
|
|
5984
7080
|
renderLegacyOfficeBinary(panel, extension, arrayBuffer);
|
|
5985
7081
|
} else {
|
|
@@ -9135,6 +10231,13 @@ function legacyOfficeFormatLabel(extension) {
|
|
|
9135
10231
|
}
|
|
9136
10232
|
return "PowerPoint Binary File Format";
|
|
9137
10233
|
}
|
|
10234
|
+
function renderLegacyWordBinary(panel, extension, arrayBuffer) {
|
|
10235
|
+
try {
|
|
10236
|
+
renderLegacyWordDocument(panel, parseLegacyWordDocument(arrayBuffer));
|
|
10237
|
+
} catch (error) {
|
|
10238
|
+
renderLegacyOfficeBinary(panel, extension, arrayBuffer, `Word \u4E8C\u8FDB\u5236\u89E3\u6790\u5931\u8D25\uFF1A${normalizeOfficeError(error)}`);
|
|
10239
|
+
}
|
|
10240
|
+
}
|
|
9138
10241
|
function renderLegacyOfficeBinary(panel, extension, arrayBuffer, parseError) {
|
|
9139
10242
|
const fragments = extractLegacyOfficeText(arrayBuffer);
|
|
9140
10243
|
panel.replaceChildren();
|
|
@@ -13710,10 +14813,10 @@ function renderStep(panel, text, extension, ctx) {
|
|
|
13710
14813
|
note.textContent = "\u5F53\u524D\u7248\u672C\u63D0\u53D6 STEP \u6587\u672C\u5B9E\u4F53\u3001\u7C7B\u578B\u7EDF\u8BA1\u548C\u5173\u952E\u51E0\u4F55\u53C2\u6570\u3002\u7CBE\u786E B-Rep/\u66F2\u9762\u6E32\u67D3\u5EFA\u8BAE\u540E\u7EED\u63A5\u5165 CAD \u5185\u6838\u6216\u670D\u52A1\u7AEF\u8F6C\u6362\u3002";
|
|
13711
14814
|
const meta = document.createElement("div");
|
|
13712
14815
|
meta.className = "ofv-cad-summary";
|
|
13713
|
-
|
|
13714
|
-
|
|
13715
|
-
|
|
13716
|
-
|
|
14816
|
+
appendMeta6(meta, "\u5B9E\u4F53", records.length);
|
|
14817
|
+
appendMeta6(meta, "\u7C7B\u578B", typeCounts.size);
|
|
14818
|
+
appendMeta6(meta, "\u70B9", typeCounts.get("CARTESIAN_POINT") || 0);
|
|
14819
|
+
appendMeta6(meta, "\u65B9\u5411", typeCounts.get("DIRECTION") || 0);
|
|
13717
14820
|
const typeList = createCadTypeList(typeCounts);
|
|
13718
14821
|
section.append(note, meta, typeList);
|
|
13719
14822
|
let viewer;
|
|
@@ -13748,10 +14851,10 @@ function renderIges(panel, text, extension, ctx) {
|
|
|
13748
14851
|
note.textContent = "\u5F53\u524D\u7248\u672C\u63D0\u53D6 IGES \u53C2\u6570\u533A\u5B9E\u4F53\u3001\u7C7B\u578B\u7EDF\u8BA1\u548C\u57FA\u7840\u53C2\u6570\u3002\u7CBE\u786E\u66F2\u7EBF/\u66F2\u9762\u6E32\u67D3\u5EFA\u8BAE\u540E\u7EED\u63A5\u5165 CAD \u5185\u6838\u6216\u670D\u52A1\u7AEF\u8F6C\u6362\u3002";
|
|
13749
14852
|
const meta = document.createElement("div");
|
|
13750
14853
|
meta.className = "ofv-cad-summary";
|
|
13751
|
-
|
|
13752
|
-
|
|
13753
|
-
|
|
13754
|
-
|
|
14854
|
+
appendMeta6(meta, "\u5B9E\u4F53", records.length);
|
|
14855
|
+
appendMeta6(meta, "\u7C7B\u578B", typeCounts.size);
|
|
14856
|
+
appendMeta6(meta, "\u70B9\u5B9E\u4F53", typeCounts.get("116") || 0);
|
|
14857
|
+
appendMeta6(meta, "\u7EBF\u5B9E\u4F53", typeCounts.get("110") || 0);
|
|
13755
14858
|
const typeList = createCadTypeList(typeCounts, "\u7C7B\u578B\u53F7\u7EDF\u8BA1");
|
|
13756
14859
|
section.append(note, meta, typeList);
|
|
13757
14860
|
let viewer;
|
|
@@ -13785,13 +14888,13 @@ function renderIfc(panel, text) {
|
|
|
13785
14888
|
note.textContent = "\u5F53\u524D\u7248\u672C\u63D0\u53D6 IFC STEP \u5B9E\u4F53\u3001BIM \u5C42\u7EA7\u548C\u5E38\u89C1\u6784\u4EF6\u7EDF\u8BA1\u3002\u51E0\u4F55\u7F51\u683C\u3001\u6750\u8D28\u548C\u5C5E\u6027\u96C6\u53EF\u540E\u7EED\u63A5\u5165 IfcOpenShell/IFC.js \u589E\u5F3A\u3002";
|
|
13786
14889
|
const meta = document.createElement("div");
|
|
13787
14890
|
meta.className = "ofv-cad-summary";
|
|
13788
|
-
|
|
13789
|
-
|
|
13790
|
-
|
|
13791
|
-
|
|
13792
|
-
|
|
13793
|
-
|
|
13794
|
-
|
|
14891
|
+
appendMeta6(meta, "\u5B9E\u4F53", records.length);
|
|
14892
|
+
appendMeta6(meta, "\u7C7B\u578B", typeCounts.size);
|
|
14893
|
+
appendMeta6(meta, "\u9879\u76EE", typeCounts.get("IFCPROJECT") || 0);
|
|
14894
|
+
appendMeta6(meta, "\u5EFA\u7B51", typeCounts.get("IFCBUILDING") || 0);
|
|
14895
|
+
appendMeta6(meta, "\u697C\u5C42", typeCounts.get("IFCBUILDINGSTOREY") || 0);
|
|
14896
|
+
appendMeta6(meta, "\u7A7A\u95F4", typeCounts.get("IFCSPACE") || 0);
|
|
14897
|
+
appendMeta6(meta, "\u6784\u4EF6", countIfcElements(typeCounts));
|
|
13795
14898
|
section.append(note, meta, createCadTypeList(typeCounts, "IFC \u5B9E\u4F53\u7EDF\u8BA1"));
|
|
13796
14899
|
const hierarchy = createIfcHierarchy(records);
|
|
13797
14900
|
if (hierarchy) {
|
|
@@ -13816,10 +14919,10 @@ function renderAcisSat(panel, text, extension, ctx) {
|
|
|
13816
14919
|
note.textContent = "\u5F53\u524D\u7248\u672C\u4F1A\u5728\u524D\u7AEF\u89E3\u6790 ACIS SAT \u6587\u672C\u5B9E\u4F53\u3001\u7C7B\u578B\u7EDF\u8BA1\u548C\u5E38\u89C1 vertex/straight-curve \u51E0\u4F55\u7EBF\u7D22\uFF1B\u7CBE\u786E\u66F2\u9762\u3001\u62D3\u6251\u548C\u5E03\u5C14\u4F53\u4ECD\u5EFA\u8BAE\u63A5\u5165 CAD \u5185\u6838\u589E\u5F3A\u3002";
|
|
13817
14920
|
const meta = document.createElement("div");
|
|
13818
14921
|
meta.className = "ofv-cad-summary";
|
|
13819
|
-
|
|
13820
|
-
|
|
13821
|
-
|
|
13822
|
-
|
|
14922
|
+
appendMeta6(meta, "\u5B9E\u4F53", records.length);
|
|
14923
|
+
appendMeta6(meta, "\u7C7B\u578B", typeCounts.size);
|
|
14924
|
+
appendMeta6(meta, "\u9876\u70B9", typeCounts.get("vertex") || 0);
|
|
14925
|
+
appendMeta6(meta, "\u76F4\u7EBF", typeCounts.get("straight-curve") || 0);
|
|
13823
14926
|
const typeList = createCadTypeList(typeCounts);
|
|
13824
14927
|
section.append(note, meta, typeList);
|
|
13825
14928
|
let viewer;
|
|
@@ -13856,10 +14959,10 @@ function renderParasolidText(panel, text, extension, ctx) {
|
|
|
13856
14959
|
note.textContent = "\u5F53\u524D\u7248\u672C\u4F1A\u5728\u524D\u7AEF\u89E3\u6790 Parasolid x_t \u6587\u672C\u7247\u6BB5\u3001\u5B9E\u4F53\u7C7B\u578B\u3001\u5750\u6807\u70B9\u548C\u57FA\u7840\u7EBF\u6BB5\u7EBF\u7D22\uFF1B\u5B8C\u6574 B-Rep\u3001\u66F2\u9762\u548C\u88C5\u914D\u5173\u7CFB\u5EFA\u8BAE\u63A5\u5165 Parasolid/HOOPS/ODA \u7B49\u4E13\u4E1A\u5185\u6838\u3002";
|
|
13857
14960
|
const meta = document.createElement("div");
|
|
13858
14961
|
meta.className = "ofv-cad-summary";
|
|
13859
|
-
|
|
13860
|
-
|
|
13861
|
-
|
|
13862
|
-
|
|
14962
|
+
appendMeta6(meta, "\u5B9E\u4F53", records.length);
|
|
14963
|
+
appendMeta6(meta, "\u7C7B\u578B", typeCounts.size);
|
|
14964
|
+
appendMeta6(meta, "\u70B9", typeCounts.get("point") || typeCounts.get("vertex") || 0);
|
|
14965
|
+
appendMeta6(meta, "\u66F2\u7EBF", (typeCounts.get("line") || 0) + (typeCounts.get("curve") || 0));
|
|
13863
14966
|
const typeList = createCadTypeList(typeCounts);
|
|
13864
14967
|
section.append(note, meta, typeList);
|
|
13865
14968
|
let viewer;
|
|
@@ -13967,23 +15070,23 @@ function renderLayoutPreview(panel, data, ctx) {
|
|
|
13967
15070
|
summary.setAttribute("aria-hidden", "true");
|
|
13968
15071
|
summary.style.display = "none";
|
|
13969
15072
|
}
|
|
13970
|
-
|
|
13971
|
-
|
|
15073
|
+
appendMeta6(summary, "\u6587\u4EF6", data.fileName);
|
|
15074
|
+
appendMeta6(summary, "\u683C\u5F0F", data.format);
|
|
13972
15075
|
if (data.libraryName) {
|
|
13973
|
-
|
|
15076
|
+
appendMeta6(summary, "\u5E93", data.libraryName);
|
|
13974
15077
|
}
|
|
13975
15078
|
if (data.version) {
|
|
13976
|
-
|
|
15079
|
+
appendMeta6(summary, "\u7248\u672C", data.version);
|
|
13977
15080
|
}
|
|
13978
15081
|
if (data.unit) {
|
|
13979
|
-
|
|
15082
|
+
appendMeta6(summary, "\u5355\u4F4D", data.unit);
|
|
13980
15083
|
}
|
|
13981
|
-
|
|
13982
|
-
|
|
13983
|
-
|
|
13984
|
-
|
|
15084
|
+
appendMeta6(summary, "Cell", data.cells.length);
|
|
15085
|
+
appendMeta6(summary, "\u51E0\u4F55", data.shapes.length);
|
|
15086
|
+
appendMeta6(summary, "\u5F15\u7528", data.references.length);
|
|
15087
|
+
appendMeta6(summary, "\u6587\u5B57", data.labels.length);
|
|
13985
15088
|
for (const [label, value] of data.metadata) {
|
|
13986
|
-
|
|
15089
|
+
appendMeta6(summary, label, value);
|
|
13987
15090
|
}
|
|
13988
15091
|
section.append(summary);
|
|
13989
15092
|
for (const noteText of [...data.notes, ...data.warnings]) {
|
|
@@ -14589,12 +15692,12 @@ function renderBinaryCad(panel, bytes, extension, fileName) {
|
|
|
14589
15692
|
note.textContent = extension === "dwg" ? "\u5DF2\u8BC6\u522B DWG \u4E13\u6709\u4E8C\u8FDB\u5236\u56FE\u7EB8\u3002\u6838\u5FC3\u63D2\u4EF6\u9ED8\u8BA4\u63D0\u4F9B\u7248\u672C\u3001\u5BB9\u5668\u3001\u7ED3\u6784\u7EBF\u7D22\u548C\u63A5\u5165\u5EFA\u8BAE\uFF1B\u771F\u5B9E\u51E0\u4F55\u6E32\u67D3\u53EF\u901A\u8FC7 cadPlugin({ binaryRenderer }) \u63A5\u5165\u53EF\u9009\u524D\u7AEF\u5F15\u64CE\u6216\u8F6C\u6362\u670D\u52A1\u3002" : "\u5DF2\u8BC6\u522B DWF \u53D1\u5E03\u56FE\u7EB8\u3002\u6838\u5FC3\u63D2\u4EF6\u9ED8\u8BA4\u63D0\u4F9B\u5BB9\u5668\u7EBF\u7D22\u548C\u63A5\u5165\u5EFA\u8BAE\uFF1B\u9AD8\u4FDD\u771F\u9875\u9762\u6E32\u67D3\u53EF\u901A\u8FC7 cadPlugin({ binaryRenderer }) \u63A5\u5165\u4E13\u7528\u89E3\u6790\u5668\u6216\u8F6C\u6362\u670D\u52A1\u3002";
|
|
14590
15693
|
const meta = document.createElement("div");
|
|
14591
15694
|
meta.className = "ofv-cad-summary";
|
|
14592
|
-
|
|
14593
|
-
|
|
14594
|
-
|
|
14595
|
-
|
|
14596
|
-
|
|
14597
|
-
|
|
15695
|
+
appendMeta6(meta, "\u6587\u4EF6", fileName);
|
|
15696
|
+
appendMeta6(meta, "\u683C\u5F0F", extension.toUpperCase());
|
|
15697
|
+
appendMeta6(meta, "\u5927\u5C0F", formatBytes3(bytes.byteLength));
|
|
15698
|
+
appendMeta6(meta, "\u7B7E\u540D", byteSignature2(bytes));
|
|
15699
|
+
appendMeta6(meta, "\u7248\u672C", detectCadVersion(bytes, extension));
|
|
15700
|
+
appendMeta6(meta, "\u5BB9\u5668", detectCadContainer(bytes));
|
|
14598
15701
|
const actions = document.createElement("div");
|
|
14599
15702
|
actions.className = "ofv-cad-conversion";
|
|
14600
15703
|
const actionTitle = document.createElement("h4");
|
|
@@ -14634,12 +15737,12 @@ function createBinaryCadProbe(bytes, extension) {
|
|
|
14634
15737
|
summary.textContent = "\u4E8C\u8FDB\u5236\u7ED3\u6784\u63A2\u6D4B";
|
|
14635
15738
|
const meta = document.createElement("div");
|
|
14636
15739
|
meta.className = "ofv-archive-probe-meta";
|
|
14637
|
-
|
|
14638
|
-
|
|
14639
|
-
|
|
14640
|
-
|
|
14641
|
-
|
|
14642
|
-
|
|
15740
|
+
appendMeta6(meta, "\u53EF\u8BFB\u7247\u6BB5", probe.tokens.length);
|
|
15741
|
+
appendMeta6(meta, "\u5B9E\u4F53\u5173\u952E\u8BCD", formatCadKeywordCounts(probe.entityCounts));
|
|
15742
|
+
appendMeta6(meta, "\u56FE\u5C42\u7EBF\u7D22", String(probe.layerHints.length));
|
|
15743
|
+
appendMeta6(meta, "\u5757/\u5F15\u7528\u7EBF\u7D22", String(probe.blockHints.length));
|
|
15744
|
+
appendMeta6(meta, "\u5916\u90E8\u5F15\u7528", String(probe.externalRefs.length));
|
|
15745
|
+
appendMeta6(meta, "\u89E3\u6790\u7EA7\u522B", extension === "dwg" ? "\u542F\u53D1\u5F0F\u626B\u63CF" : "\u5BB9\u5668/\u6587\u672C\u626B\u63CF");
|
|
14643
15746
|
details.append(summary, meta);
|
|
14644
15747
|
const hints = [...probe.layerHints, ...probe.blockHints, ...probe.externalRefs].slice(0, 18);
|
|
14645
15748
|
if (hints.length > 0) {
|
|
@@ -15172,9 +16275,9 @@ function createUnsupportedCadSection(extension, fileName) {
|
|
|
15172
16275
|
const section = createSection("CAD \u589E\u5F3A\u63A5\u5165\u63D0\u793A");
|
|
15173
16276
|
const meta = document.createElement("div");
|
|
15174
16277
|
meta.className = "ofv-cad-summary";
|
|
15175
|
-
|
|
15176
|
-
|
|
15177
|
-
|
|
16278
|
+
appendMeta6(meta, "\u6587\u4EF6", fileName);
|
|
16279
|
+
appendMeta6(meta, "\u683C\u5F0F", `.${extension || "cad"}`);
|
|
16280
|
+
appendMeta6(meta, "\u5185\u7F6E\u80FD\u529B", unsupportedCadBuiltInLevel(extension));
|
|
15178
16281
|
const note = document.createElement("p");
|
|
15179
16282
|
note.textContent = unsupportedCadGuidance(extension);
|
|
15180
16283
|
const actions = document.createElement("div");
|
|
@@ -15287,7 +16390,7 @@ function countBy(values) {
|
|
|
15287
16390
|
}
|
|
15288
16391
|
return counts;
|
|
15289
16392
|
}
|
|
15290
|
-
function
|
|
16393
|
+
function appendMeta6(parent, label, value) {
|
|
15291
16394
|
const row = document.createElement("div");
|
|
15292
16395
|
row.className = "ofv-meta-row";
|
|
15293
16396
|
const key = document.createElement("span");
|
|
@@ -17321,10 +18424,10 @@ function read255UInt16(bytes, offset) {
|
|
|
17321
18424
|
return { value: code, offset };
|
|
17322
18425
|
}
|
|
17323
18426
|
function decodeEotString(bytes) {
|
|
17324
|
-
const text =
|
|
18427
|
+
const text = decodeUtf16Le2(bytes).replace(/\0+$/g, "").trim();
|
|
17325
18428
|
return text || new TextDecoder("latin1").decode(bytes).replace(/\0+$/g, "").trim();
|
|
17326
18429
|
}
|
|
17327
|
-
function
|
|
18430
|
+
function decodeUtf16Le2(bytes) {
|
|
17328
18431
|
let value = "";
|
|
17329
18432
|
for (let index = 0; index + 1 < bytes.length; index += 2) {
|
|
17330
18433
|
value += String.fromCharCode(bytes[index] | bytes[index + 1] << 8);
|