@file-viewer/renderer-ofd 2.1.23 → 2.1.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +1 -0
- package/README.md +1 -0
- package/dist/ofd.js +10 -4
- package/package.json +7 -3
- package/vendor/dltech/ofd/ofd_parser.js +148 -21
- package/vendor/dltech/ofd/ofd_render.js +206 -55
- package/vendor/dltech/ofd/ofd_util.js +36 -5
- package/vendor/dltech/ofd/ses_signature_parser.js +196 -0
- package/vendor/lapo-asn1js/README.md +3 -0
- package/vendor/lapo-asn1js/asn1.js +525 -0
- package/vendor/lapo-asn1js/base64.js +82 -0
- package/vendor/lapo-asn1js/hex.js +51 -0
- package/vendor/lapo-asn1js/int10.js +90 -0
- package/vendor/lapo-asn1js/oids.js +2455 -0
|
@@ -61,6 +61,19 @@ export const convertPathAbbreviatedDatatoPoint = abbreviatedData => {
|
|
|
61
61
|
}
|
|
62
62
|
i = i + 7;
|
|
63
63
|
pointList.push(point);
|
|
64
|
+
} else if (array[i] === 'Q') {
|
|
65
|
+
// Q x1 y1 x2 y2:以(x1,y1)为控制点画二次贝塞尔到(x2,y2)。
|
|
66
|
+
// 大量中文字形轮廓(本身是路径而非 TextObject)都靠 Q 描述笔画弧线,
|
|
67
|
+
// 之前完全未识别,会导致后续 token 错位、字形整体丢失。
|
|
68
|
+
let point = {
|
|
69
|
+
'type': 'Q',
|
|
70
|
+
'x1': parseFloat(array[i + 1]),
|
|
71
|
+
'y1': parseFloat(array[i + 2]),
|
|
72
|
+
'x2': parseFloat(array[i + 3]),
|
|
73
|
+
'y2': parseFloat(array[i + 4])
|
|
74
|
+
}
|
|
75
|
+
i = i + 5;
|
|
76
|
+
pointList.push(point);
|
|
64
77
|
} else {
|
|
65
78
|
i++;
|
|
66
79
|
}
|
|
@@ -90,6 +103,13 @@ export const calPathPoint = function (abbreviatedPoint) {
|
|
|
90
103
|
'x3': converterDpi(x3), 'y3': converterDpi(y3)
|
|
91
104
|
}
|
|
92
105
|
pointList.push(realPoint);
|
|
106
|
+
} else if (point.type === 'Q') {
|
|
107
|
+
let realPoint = {
|
|
108
|
+
'type': 'Q',
|
|
109
|
+
'x1': converterDpi(point.x1), 'y1': converterDpi(point.y1),
|
|
110
|
+
'x2': converterDpi(point.x2), 'y2': converterDpi(point.y2)
|
|
111
|
+
}
|
|
112
|
+
pointList.push(realPoint);
|
|
93
113
|
}
|
|
94
114
|
}
|
|
95
115
|
return pointList;
|
|
@@ -192,8 +212,7 @@ export const calTextPoint = function (textCodes) {
|
|
|
192
212
|
let textStr = textCode['#text'];
|
|
193
213
|
if (textStr) {
|
|
194
214
|
textStr += '';
|
|
195
|
-
textStr =
|
|
196
|
-
textStr = textStr.replace(/ /g, ' ');
|
|
215
|
+
textStr = decodeOfdText(textStr);
|
|
197
216
|
for (let i = 0; i < textStr.length; i++) {
|
|
198
217
|
if (i > 0 && deltaXList.length > 0) {
|
|
199
218
|
x += deltaXList[(i - 1)];
|
|
@@ -232,7 +251,7 @@ export const getExtensionByPath = function (path) {
|
|
|
232
251
|
}
|
|
233
252
|
|
|
234
253
|
|
|
235
|
-
let REGX_HTML_DECODE = /&\w+;|&#(
|
|
254
|
+
let REGX_HTML_DECODE = /&\w+;|&#(x?[0-9a-fA-F]+);/g;
|
|
236
255
|
|
|
237
256
|
let HTML_DECODE = {
|
|
238
257
|
"<": "<",
|
|
@@ -253,8 +272,9 @@ export const decodeHtml = function (s) {
|
|
|
253
272
|
var c = HTML_DECODE[$0];
|
|
254
273
|
if (c == undefined) {
|
|
255
274
|
// Maybe is Entity Number
|
|
256
|
-
if (
|
|
257
|
-
|
|
275
|
+
if ($1) {
|
|
276
|
+
const codePoint = /^x/i.test($1) ? parseInt($1.slice(1), 16) : parseInt($1, 10);
|
|
277
|
+
c = Number.isFinite(codePoint) ? String.fromCodePoint((codePoint == 160) ? 32 : codePoint) : $0;
|
|
258
278
|
} else {
|
|
259
279
|
c = $0;
|
|
260
280
|
}
|
|
@@ -263,6 +283,17 @@ export const decodeHtml = function (s) {
|
|
|
263
283
|
});
|
|
264
284
|
};
|
|
265
285
|
|
|
286
|
+
export const decodeOfdText = function (s) {
|
|
287
|
+
s = decodeHtml(s);
|
|
288
|
+
if (typeof s != "string") {
|
|
289
|
+
return s;
|
|
290
|
+
}
|
|
291
|
+
return s.replace(/\\0x([0-9a-fA-F]{4,6})/g, function (_, hex) {
|
|
292
|
+
const codePoint = parseInt(hex, 16);
|
|
293
|
+
return Number.isFinite(codePoint) ? String.fromCodePoint((codePoint == 160) ? 32 : codePoint) : _;
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
|
|
266
297
|
let FONT_FAMILY = {
|
|
267
298
|
'楷体': '楷体, KaiTi, Kai, simkai',
|
|
268
299
|
'kaiti': '楷体, KaiTi, Kai, simkai',
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* ofd.js - A Javascript class for reading and rendering ofd files
|
|
3
|
+
* <https://github.com/DLTech21/ofd.js>
|
|
4
|
+
*
|
|
5
|
+
* Copyright (c) 2020. DLTech21 All Rights Reserved.
|
|
6
|
+
*
|
|
7
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
* you may not use this file except in compliance with the License.
|
|
9
|
+
* You may obtain a copy of the License at
|
|
10
|
+
*
|
|
11
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
*
|
|
13
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
* See the License for the specific language governing permissions and
|
|
17
|
+
* limitations under the License.
|
|
18
|
+
*
|
|
19
|
+
* Display-only SES signature parser for File Viewer:
|
|
20
|
+
* extracts seal picture bytes for preview, skips crypto verification
|
|
21
|
+
* so ASN.1/国密校验不会进入预览主路径。
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import Hex from '../../lapo-asn1js/hex.js';
|
|
25
|
+
import Base64 from '../../lapo-asn1js/base64.js';
|
|
26
|
+
import ASN1 from '../../lapo-asn1js/asn1.js';
|
|
27
|
+
|
|
28
|
+
const reHex = /^\s*(?:[0-9A-Fa-f][0-9A-Fa-f]\s*)+$/;
|
|
29
|
+
|
|
30
|
+
const unwrapDefault = (mod) => (mod && typeof mod === 'object' && 'default' in mod ? mod.default : mod);
|
|
31
|
+
|
|
32
|
+
const HexApi = unwrapDefault(Hex);
|
|
33
|
+
const Base64Api = unwrapDefault(Base64);
|
|
34
|
+
const ASN1Api = unwrapDefault(ASN1);
|
|
35
|
+
|
|
36
|
+
export const parseSesSignature = async function (zip, name, getEntry) {
|
|
37
|
+
const entry = typeof getEntry === 'function' ? getEntry(zip, name) : zip.files[name];
|
|
38
|
+
if (!entry) {
|
|
39
|
+
return {};
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
const bytes = await entry.async('base64');
|
|
43
|
+
return decodeText(bytes);
|
|
44
|
+
} catch (e) {
|
|
45
|
+
console.warn('[ofd] parseSesSignature failed', name, e);
|
|
46
|
+
return {};
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const decodeText = function (val) {
|
|
51
|
+
try {
|
|
52
|
+
const der = reHex.test(val) ? HexApi.decode(val) : Base64Api.unarmor(val);
|
|
53
|
+
return decode(der);
|
|
54
|
+
} catch (e) {
|
|
55
|
+
console.warn('[ofd] decode SES signature text failed', e);
|
|
56
|
+
return {};
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const decode = function (der, offset) {
|
|
61
|
+
offset = offset || 0;
|
|
62
|
+
try {
|
|
63
|
+
const SES_Signature = decodeSES_Signature(der, offset);
|
|
64
|
+
const picture = SES_Signature?.toSign?.eseal?.esealInfo?.picture;
|
|
65
|
+
if (!picture?.data?.byte?.length) {
|
|
66
|
+
return {};
|
|
67
|
+
}
|
|
68
|
+
const type = (picture.type?.str || picture.type || '').toString().toLowerCase();
|
|
69
|
+
return {
|
|
70
|
+
ofdArray: picture.data.byte,
|
|
71
|
+
type,
|
|
72
|
+
// 预览只保留轻量元数据,避免把 DER/证书二进制塞进 DOM data-*。
|
|
73
|
+
SES_Signature: {
|
|
74
|
+
realVersion: SES_Signature.realVersion,
|
|
75
|
+
displayOnly: true,
|
|
76
|
+
pictureType: type,
|
|
77
|
+
pictureWidth: picture.width,
|
|
78
|
+
pictureHeight: picture.height,
|
|
79
|
+
sealName: SES_Signature.toSign?.eseal?.esealInfo?.property?.name,
|
|
80
|
+
},
|
|
81
|
+
verifyRet: true,
|
|
82
|
+
};
|
|
83
|
+
} catch (e) {
|
|
84
|
+
console.warn('[ofd] decode SES signature failed', e);
|
|
85
|
+
return {};
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const decodeUTCTime = function (str) {
|
|
90
|
+
str = String(str || '').replace('Unrecognized time: ', '');
|
|
91
|
+
str = str.replace('Z', '');
|
|
92
|
+
str = str.substr(0, 1) < '5' ? '20' + str : '19' + str;
|
|
93
|
+
return str;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const parseStringUTF = function (node) {
|
|
97
|
+
if (!node) {
|
|
98
|
+
return '';
|
|
99
|
+
}
|
|
100
|
+
return node.stream.parseStringUTF(node.stream.pos + node.header, node.stream.pos + node.header + node.length);
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const parseInteger = function (node) {
|
|
104
|
+
if (!node) {
|
|
105
|
+
return undefined;
|
|
106
|
+
}
|
|
107
|
+
return node.stream.parseInteger(node.stream.pos + node.header, node.stream.pos + node.header + node.length);
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const parseOctetBytes = function (node) {
|
|
111
|
+
if (!node) {
|
|
112
|
+
return new Uint8Array(0);
|
|
113
|
+
}
|
|
114
|
+
return node.stream.enc.subarray(node.stream.pos + node.header, node.stream.pos + node.header + node.length);
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const parseTimeNode = function (node, utc) {
|
|
118
|
+
if (!node) {
|
|
119
|
+
return '';
|
|
120
|
+
}
|
|
121
|
+
const raw = node.stream.parseTime(node.stream.pos + node.header, node.stream.pos + node.header + node.length, utc);
|
|
122
|
+
return decodeUTCTime(raw);
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
const decodeSES_Signature = function (der, offset) {
|
|
126
|
+
offset = offset || 0;
|
|
127
|
+
const asn1 = ASN1Api.decode(der, offset);
|
|
128
|
+
let SES_Signature;
|
|
129
|
+
try {
|
|
130
|
+
// V1
|
|
131
|
+
const createDate = parseTimeNode(asn1.sub[0]?.sub[1]?.sub[0]?.sub[2]?.sub[3]);
|
|
132
|
+
const validStart = parseTimeNode(asn1.sub[0]?.sub[1]?.sub[0]?.sub[2]?.sub[4]);
|
|
133
|
+
const validEnd = parseTimeNode(asn1.sub[0]?.sub[1]?.sub[0]?.sub[2]?.sub[5]);
|
|
134
|
+
const pictureNode = asn1.sub[0]?.sub[1]?.sub[0]?.sub[3];
|
|
135
|
+
SES_Signature = {
|
|
136
|
+
realVersion: 1,
|
|
137
|
+
toSign: {
|
|
138
|
+
eseal: {
|
|
139
|
+
esealInfo: {
|
|
140
|
+
property: {
|
|
141
|
+
name: parseStringUTF(asn1.sub[0]?.sub[1]?.sub[0]?.sub[2]?.sub[1]),
|
|
142
|
+
createDate,
|
|
143
|
+
validStart,
|
|
144
|
+
validEnd,
|
|
145
|
+
},
|
|
146
|
+
picture: {
|
|
147
|
+
type: parseStringUTF(pictureNode?.sub[0]),
|
|
148
|
+
data: { byte: parseOctetBytes(pictureNode?.sub[1]) },
|
|
149
|
+
width: parseInteger(pictureNode?.sub[2]),
|
|
150
|
+
height: parseInteger(pictureNode?.sub[3]),
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
} catch (e) {
|
|
157
|
+
try {
|
|
158
|
+
// V4
|
|
159
|
+
const pictureNode = asn1.sub[0]?.sub[1]?.sub[0]?.sub[3];
|
|
160
|
+
SES_Signature = {
|
|
161
|
+
realVersion: 4,
|
|
162
|
+
toSign: {
|
|
163
|
+
eseal: {
|
|
164
|
+
esealInfo: {
|
|
165
|
+
property: {
|
|
166
|
+
name: parseStringUTF(asn1.sub[0]?.sub[1]?.sub[0]?.sub[2]?.sub[1]),
|
|
167
|
+
createDate: asn1.sub[0]?.sub[1]?.sub[0]?.sub[2]?.sub[4]?.stream.parseTime(
|
|
168
|
+
asn1.sub[0].sub[1].sub[0].sub[2].sub[4].stream.pos + asn1.sub[0].sub[1].sub[0].sub[2].sub[4].header,
|
|
169
|
+
asn1.sub[0].sub[1].sub[0].sub[2].sub[4].stream.pos + asn1.sub[0].sub[1].sub[0].sub[2].sub[4].header + asn1.sub[0].sub[1].sub[0].sub[2].sub[4].length
|
|
170
|
+
),
|
|
171
|
+
validStart: asn1.sub[0]?.sub[1]?.sub[0]?.sub[2]?.sub[5]?.stream.parseTime(
|
|
172
|
+
asn1.sub[0].sub[1].sub[0].sub[2].sub[5].stream.pos + asn1.sub[0].sub[1].sub[0].sub[2].sub[5].header,
|
|
173
|
+
asn1.sub[0].sub[1].sub[0].sub[2].sub[5].stream.pos + asn1.sub[0].sub[1].sub[0].sub[2].sub[5].header + asn1.sub[0].sub[1].sub[0].sub[2].sub[5].length
|
|
174
|
+
),
|
|
175
|
+
validEnd: asn1.sub[0]?.sub[1]?.sub[0]?.sub[2]?.sub[6]?.stream.parseTime(
|
|
176
|
+
asn1.sub[0].sub[1].sub[0].sub[2].sub[6].stream.pos + asn1.sub[0].sub[1].sub[0].sub[2].sub[6].header,
|
|
177
|
+
asn1.sub[0].sub[1].sub[0].sub[2].sub[6].stream.pos + asn1.sub[0].sub[1].sub[0].sub[2].sub[6].header + asn1.sub[0].sub[1].sub[0].sub[2].sub[6].length
|
|
178
|
+
),
|
|
179
|
+
},
|
|
180
|
+
picture: {
|
|
181
|
+
type: parseStringUTF(pictureNode?.sub[0]),
|
|
182
|
+
data: { byte: parseOctetBytes(pictureNode?.sub[1]) },
|
|
183
|
+
width: parseInteger(pictureNode?.sub[2]),
|
|
184
|
+
height: parseInteger(pictureNode?.sub[3]),
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
};
|
|
190
|
+
} catch (inner) {
|
|
191
|
+
console.warn('[ofd] unsupported SES signature structure', inner);
|
|
192
|
+
SES_Signature = {};
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return SES_Signature;
|
|
196
|
+
};
|