pdf-codec 1.6.0 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +67 -9
- package/dist/cff-bounds.cjs +432 -0
- package/dist/cff-bounds.d.cts +9 -0
- package/dist/cff-bounds.d.ts +9 -0
- package/dist/cff-bounds.js +431 -0
- package/dist/cff-probe.cjs +8 -106
- package/dist/cff-probe.js +9 -107
- package/dist/cff.cjs +158 -0
- package/dist/cff.d.cts +17 -0
- package/dist/cff.d.ts +17 -0
- package/dist/cff.js +150 -0
- package/dist/filters.cjs +45 -2
- package/dist/filters.d.cts +4 -3
- package/dist/filters.d.ts +4 -3
- package/dist/filters.js +45 -2
- package/dist/formula.d.cts +1 -1
- package/dist/formula.d.ts +1 -1
- package/dist/glyf.cjs +62 -6
- package/dist/glyf.d.cts +2 -0
- package/dist/glyf.d.ts +2 -0
- package/dist/glyf.js +62 -6
- package/dist/glyph-bounds-BV_Z40KS.d.cts +10 -0
- package/dist/glyph-bounds-BV_Z40KS.d.ts +10 -0
- package/dist/glyph-bounds.cjs +12 -0
- package/dist/glyph-bounds.d.cts +2 -0
- package/dist/glyph-bounds.d.ts +2 -0
- package/dist/glyph-bounds.js +11 -0
- package/dist/image/jbig2-arith.cjs +432 -0
- package/dist/image/jbig2-arith.d.cts +23 -0
- package/dist/image/jbig2-arith.d.ts +23 -0
- package/dist/image/jbig2-arith.js +426 -0
- package/dist/image/jbig2-bitmap.cjs +80 -0
- package/dist/image/jbig2-bitmap.d.cts +20 -0
- package/dist/image/jbig2-bitmap.d.ts +20 -0
- package/dist/image/jbig2-bitmap.js +72 -0
- package/dist/image/jbig2-errors.cjs +17 -0
- package/dist/image/jbig2-errors.d.cts +2 -0
- package/dist/image/jbig2-errors.d.ts +2 -0
- package/dist/image/jbig2-errors.js +15 -0
- package/dist/image/jbig2-generic.cjs +242 -0
- package/dist/image/jbig2-generic.d.cts +27 -0
- package/dist/image/jbig2-generic.d.ts +27 -0
- package/dist/image/jbig2-generic.js +237 -0
- package/dist/image/jbig2-text.cjs +175 -0
- package/dist/image/jbig2-text.d.cts +58 -0
- package/dist/image/jbig2-text.d.ts +58 -0
- package/dist/image/jbig2-text.js +170 -0
- package/dist/image/jbig2.cjs +333 -0
- package/dist/image/jbig2.d.cts +15 -0
- package/dist/image/jbig2.d.ts +15 -0
- package/dist/image/jbig2.js +332 -0
- package/dist/image/jp2-boxes.cjs +148 -0
- package/dist/image/jp2-boxes.d.cts +26 -0
- package/dist/image/jp2-boxes.d.ts +26 -0
- package/dist/image/jp2-boxes.js +146 -0
- package/dist/image/jpeg2000-codestream.cjs +309 -0
- package/dist/image/jpeg2000-codestream.d.cts +78 -0
- package/dist/image/jpeg2000-codestream.d.ts +78 -0
- package/dist/image/jpeg2000-codestream.js +308 -0
- package/dist/image/jpeg2000-dwt.cjs +148 -0
- package/dist/image/jpeg2000-dwt.d.cts +34 -0
- package/dist/image/jpeg2000-dwt.d.ts +34 -0
- package/dist/image/jpeg2000-dwt.js +145 -0
- package/dist/image/jpeg2000-errors.cjs +17 -0
- package/dist/image/jpeg2000-errors.d.cts +9 -0
- package/dist/image/jpeg2000-errors.d.ts +9 -0
- package/dist/image/jpeg2000-errors.js +15 -0
- package/dist/image/jpeg2000-t1.cjs +254 -0
- package/dist/image/jpeg2000-t1.d.cts +18 -0
- package/dist/image/jpeg2000-t1.d.ts +18 -0
- package/dist/image/jpeg2000-t1.js +253 -0
- package/dist/image/jpeg2000-t2.cjs +316 -0
- package/dist/image/jpeg2000-t2.d.cts +79 -0
- package/dist/image/jpeg2000-t2.d.ts +79 -0
- package/dist/image/jpeg2000-t2.js +311 -0
- package/dist/image/jpeg2000-tagtree.cjs +105 -0
- package/dist/image/jpeg2000-tagtree.d.cts +29 -0
- package/dist/image/jpeg2000-tagtree.d.ts +29 -0
- package/dist/image/jpeg2000-tagtree.js +103 -0
- package/dist/image/jpeg2000.cjs +322 -0
- package/dist/image/jpeg2000.d.cts +54 -0
- package/dist/image/jpeg2000.d.ts +54 -0
- package/dist/image/jpeg2000.js +320 -0
- package/dist/images-read.cjs +78 -1
- package/dist/images-read.js +78 -1
- package/dist/index.cjs +17 -0
- package/dist/index.d.cts +11 -2
- package/dist/index.d.ts +11 -2
- package/dist/index.js +7 -1
- package/dist/jbig2-errors-Bj6MPxrx.d.cts +9 -0
- package/dist/jbig2-errors-Bj6MPxrx.d.ts +9 -0
- package/dist/math-font.cjs +43 -18
- package/dist/math-font.d.cts +8 -1
- package/dist/math-font.d.ts +8 -1
- package/dist/math-font.js +43 -18
- package/dist/math-stretch-Bwk_bxh1.d.ts +24 -0
- package/dist/math-stretch-DXWjs8gL.d.cts +24 -0
- package/dist/math-stretch.cjs +96 -0
- package/dist/math-stretch.d.cts +2 -0
- package/dist/math-stretch.d.ts +2 -0
- package/dist/math-stretch.js +94 -0
- package/dist/math-table-DhPrNoPa.d.ts +70 -0
- package/dist/math-table-gFNB8DmQ.d.cts +70 -0
- package/dist/math-table.cjs +69 -1
- package/dist/math-table.d.cts +2 -45
- package/dist/math-table.d.ts +2 -45
- package/dist/math-table.js +69 -1
- package/dist/{math-types-Ba8qAf1p.d.cts → math-types-YSQUTviw.d.cts} +2 -0
- package/dist/{math-types-Ba8qAf1p.d.ts → math-types-YSQUTviw.d.ts} +2 -0
- package/dist/math-types.d.cts +1 -1
- package/dist/math-types.d.ts +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
import { hasBytes, u16, u32, u8 } from "./sfnt.js";
|
|
2
|
+
import { parseCffDict, readCffIndex } from "./cff.js";
|
|
3
|
+
//#region src/cff-bounds.ts
|
|
4
|
+
const CFF_HEADER_MIN_SIZE = 4;
|
|
5
|
+
const CFF_MAJOR_VERSION = 1;
|
|
6
|
+
const CFF_HEADER_SIZE_OFFSET = 2;
|
|
7
|
+
const CS_OPERAND_INT16 = 28;
|
|
8
|
+
const CS_OPERAND_FIXED = 255;
|
|
9
|
+
const CS_OPERAND_SMALL_FIRST = 32;
|
|
10
|
+
const CS_OPERAND_SMALL_LAST = 246;
|
|
11
|
+
const CS_OPERAND_MEDIUM_FIRST = 247;
|
|
12
|
+
const CS_OPERAND_MEDIUM_LAST = 250;
|
|
13
|
+
const CS_OPERAND_NEGATIVE_MEDIUM_FIRST = 251;
|
|
14
|
+
const CS_OPERAND_NEGATIVE_MEDIUM_LAST = 254;
|
|
15
|
+
const CS_OPERAND_SMALL_BIAS = 139;
|
|
16
|
+
const CS_OPERAND_MEDIUM_BIAS = 108;
|
|
17
|
+
const CS_OPERAND_MEDIUM_FIRST_BYTE_BIAS = 247;
|
|
18
|
+
const CS_OPERAND_NEGATIVE_MEDIUM_FIRST_BYTE_BIAS = 251;
|
|
19
|
+
const BYTE_RADIX = 256;
|
|
20
|
+
const FIXED_POINT_SCALE = 65536;
|
|
21
|
+
const OP_HSTEM = 1;
|
|
22
|
+
const OP_VSTEM = 3;
|
|
23
|
+
const OP_VMOVETO = 4;
|
|
24
|
+
const OP_RLINETO = 5;
|
|
25
|
+
const OP_HLINETO = 6;
|
|
26
|
+
const OP_VLINETO = 7;
|
|
27
|
+
const OP_RRCURVETO = 8;
|
|
28
|
+
const OP_CALLSUBR = 10;
|
|
29
|
+
const OP_RETURN = 11;
|
|
30
|
+
const OP_ESCAPE = 12;
|
|
31
|
+
const OP_ENDCHAR = 14;
|
|
32
|
+
const OP_HSTEMHM = 18;
|
|
33
|
+
const OP_HINTMASK = 19;
|
|
34
|
+
const OP_CNTRMASK = 20;
|
|
35
|
+
const OP_RMOVETO = 21;
|
|
36
|
+
const OP_HMOVETO = 22;
|
|
37
|
+
const OP_VSTEMHM = 23;
|
|
38
|
+
const OP_RCURVELINE = 24;
|
|
39
|
+
const OP_RLINECURVE = 25;
|
|
40
|
+
const OP_VVCURVETO = 26;
|
|
41
|
+
const OP_HHCURVETO = 27;
|
|
42
|
+
const OP_CALLGSUBR = 29;
|
|
43
|
+
const OP_VHCURVETO = 30;
|
|
44
|
+
const OP_HVCURVETO = 31;
|
|
45
|
+
const CHARSTRING_OPERATOR_LIMIT = 31;
|
|
46
|
+
const ESC_HFLEX = 34;
|
|
47
|
+
const ESC_FLEX = 35;
|
|
48
|
+
const ESC_HFLEX1 = 36;
|
|
49
|
+
const ESC_FLEX1 = 37;
|
|
50
|
+
const SUBR_BIAS_SMALL_LIMIT = 1240;
|
|
51
|
+
const SUBR_BIAS_MEDIUM_LIMIT = 33900;
|
|
52
|
+
const SUBR_BIAS_SMALL = 107;
|
|
53
|
+
const SUBR_BIAS_MEDIUM = 1131;
|
|
54
|
+
const SUBR_BIAS_LARGE = 32768;
|
|
55
|
+
const HINT_MASK_BITS_PER_BYTE = 8;
|
|
56
|
+
const STEM_ARGS_PER_STEM = 2;
|
|
57
|
+
const MAX_OPERAND_STACK = 48;
|
|
58
|
+
const MAX_SUBR_DEPTH = 10;
|
|
59
|
+
const MAX_OPERATIONS_PER_GLYPH = 1e5;
|
|
60
|
+
const ENDCHAR_SEAC_ARG_COUNT = 4;
|
|
61
|
+
function subrBias(count) {
|
|
62
|
+
if (count < SUBR_BIAS_SMALL_LIMIT) return SUBR_BIAS_SMALL;
|
|
63
|
+
if (count < SUBR_BIAS_MEDIUM_LIMIT) return SUBR_BIAS_MEDIUM;
|
|
64
|
+
return SUBR_BIAS_LARGE;
|
|
65
|
+
}
|
|
66
|
+
function includePoint(box, x, y) {
|
|
67
|
+
box.minX = Math.min(box.minX, x);
|
|
68
|
+
box.minY = Math.min(box.minY, y);
|
|
69
|
+
box.maxX = Math.max(box.maxX, x);
|
|
70
|
+
box.maxY = Math.max(box.maxY, y);
|
|
71
|
+
box.drawn = true;
|
|
72
|
+
}
|
|
73
|
+
function cubicAt(p0, p1, p2, p3, t) {
|
|
74
|
+
const s = 1 - t;
|
|
75
|
+
return s * s * s * p0 + 3 * s * s * t * p1 + 3 * s * t * t * p2 + t * t * t * p3;
|
|
76
|
+
}
|
|
77
|
+
function includeCubicAxis(p0, p1, p2, p3, apply) {
|
|
78
|
+
apply(p0);
|
|
79
|
+
apply(p3);
|
|
80
|
+
const a = -p0 + 3 * p1 - 3 * p2 + p3;
|
|
81
|
+
const b = 2 * (p0 - 2 * p1 + p2);
|
|
82
|
+
const c = p1 - p0;
|
|
83
|
+
const roots = [];
|
|
84
|
+
if (a === 0) {
|
|
85
|
+
if (b !== 0) roots.push(-c / b);
|
|
86
|
+
} else {
|
|
87
|
+
const discriminant = b * b - 4 * a * c;
|
|
88
|
+
if (discriminant >= 0) {
|
|
89
|
+
const root = Math.sqrt(discriminant);
|
|
90
|
+
roots.push((-b + root) / (2 * a), (-b - root) / (2 * a));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
for (const t of roots) if (t > 0 && t < 1) apply(cubicAt(p0, p1, p2, p3, t));
|
|
94
|
+
}
|
|
95
|
+
function includeCubic(box, x0, y0, x1, y1, x2, y2, x3, y3) {
|
|
96
|
+
includeCubicAxis(x0, x1, x2, x3, (value) => {
|
|
97
|
+
box.minX = Math.min(box.minX, value);
|
|
98
|
+
box.maxX = Math.max(box.maxX, value);
|
|
99
|
+
});
|
|
100
|
+
includeCubicAxis(y0, y1, y2, y3, (value) => {
|
|
101
|
+
box.minY = Math.min(box.minY, value);
|
|
102
|
+
box.maxY = Math.max(box.maxY, value);
|
|
103
|
+
});
|
|
104
|
+
box.drawn = true;
|
|
105
|
+
}
|
|
106
|
+
function curveTo(state, dx1, dy1, dx2, dy2, dx3, dy3) {
|
|
107
|
+
const x0 = state.x;
|
|
108
|
+
const y0 = state.y;
|
|
109
|
+
const x1 = x0 + dx1;
|
|
110
|
+
const y1 = y0 + dy1;
|
|
111
|
+
const x2 = x1 + dx2;
|
|
112
|
+
const y2 = y1 + dy2;
|
|
113
|
+
const x3 = x2 + dx3;
|
|
114
|
+
const y3 = y2 + dy3;
|
|
115
|
+
includeCubic(state.box, x0, y0, x1, y1, x2, y2, x3, y3);
|
|
116
|
+
state.x = x3;
|
|
117
|
+
state.y = y3;
|
|
118
|
+
}
|
|
119
|
+
function lineTo(state, dx, dy) {
|
|
120
|
+
includePoint(state.box, state.x, state.y);
|
|
121
|
+
state.x += dx;
|
|
122
|
+
state.y += dy;
|
|
123
|
+
includePoint(state.box, state.x, state.y);
|
|
124
|
+
}
|
|
125
|
+
function moveTo(state, dx, dy) {
|
|
126
|
+
state.x += dx;
|
|
127
|
+
state.y += dy;
|
|
128
|
+
}
|
|
129
|
+
function takeWidth(state, evenArgs, expected) {
|
|
130
|
+
if (state.widthParsed) return;
|
|
131
|
+
state.widthParsed = true;
|
|
132
|
+
if (evenArgs ? state.stack.length % STEM_ARGS_PER_STEM !== 0 : state.stack.length > expected) state.stack.shift();
|
|
133
|
+
}
|
|
134
|
+
function readOperand(code, offset) {
|
|
135
|
+
const b0 = code[offset];
|
|
136
|
+
if (b0 === CS_OPERAND_INT16) {
|
|
137
|
+
if (!hasBytes(code, offset + 1, 2)) return;
|
|
138
|
+
const raw = u16(code, offset + 1);
|
|
139
|
+
return {
|
|
140
|
+
value: raw >= 32768 ? raw - 65536 : raw,
|
|
141
|
+
endOffset: offset + 3
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
if (b0 === CS_OPERAND_FIXED) {
|
|
145
|
+
if (!hasBytes(code, offset + 1, 4)) return;
|
|
146
|
+
return {
|
|
147
|
+
value: (u32(code, offset + 1) | 0) / FIXED_POINT_SCALE,
|
|
148
|
+
endOffset: offset + 5
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
if (b0 >= CS_OPERAND_SMALL_FIRST && b0 <= CS_OPERAND_SMALL_LAST) return {
|
|
152
|
+
value: b0 - CS_OPERAND_SMALL_BIAS,
|
|
153
|
+
endOffset: offset + 1
|
|
154
|
+
};
|
|
155
|
+
if (b0 >= CS_OPERAND_MEDIUM_FIRST && b0 <= CS_OPERAND_MEDIUM_LAST) {
|
|
156
|
+
if (!hasBytes(code, offset + 1, 1)) return;
|
|
157
|
+
return {
|
|
158
|
+
value: (b0 - CS_OPERAND_MEDIUM_FIRST_BYTE_BIAS) * BYTE_RADIX + u8(code, offset + 1) + CS_OPERAND_MEDIUM_BIAS,
|
|
159
|
+
endOffset: offset + 2
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
if (b0 >= CS_OPERAND_NEGATIVE_MEDIUM_FIRST && b0 <= CS_OPERAND_NEGATIVE_MEDIUM_LAST) {
|
|
163
|
+
if (!hasBytes(code, offset + 1, 1)) return;
|
|
164
|
+
return {
|
|
165
|
+
value: -(b0 - CS_OPERAND_NEGATIVE_MEDIUM_FIRST_BYTE_BIAS) * BYTE_RADIX - u8(code, offset + 1) - CS_OPERAND_MEDIUM_BIAS,
|
|
166
|
+
endOffset: offset + 2
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
function execute(code, state, context, depth) {
|
|
171
|
+
if (depth > MAX_SUBR_DEPTH) return false;
|
|
172
|
+
const stack = state.stack;
|
|
173
|
+
let i = 0;
|
|
174
|
+
while (i < code.length) {
|
|
175
|
+
state.operations += 1;
|
|
176
|
+
if (state.operations > MAX_OPERATIONS_PER_GLYPH) return false;
|
|
177
|
+
const b0 = code[i];
|
|
178
|
+
const operand = readOperand(code, i);
|
|
179
|
+
if (operand !== void 0) {
|
|
180
|
+
if (stack.length >= MAX_OPERAND_STACK) return false;
|
|
181
|
+
stack.push(operand.value);
|
|
182
|
+
i = operand.endOffset;
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
if (b0 > CHARSTRING_OPERATOR_LIMIT) return false;
|
|
186
|
+
i += 1;
|
|
187
|
+
switch (b0) {
|
|
188
|
+
case OP_HSTEM:
|
|
189
|
+
case OP_VSTEM:
|
|
190
|
+
case OP_HSTEMHM:
|
|
191
|
+
case OP_VSTEMHM:
|
|
192
|
+
takeWidth(state, true, 0);
|
|
193
|
+
state.stems += Math.floor(stack.length / STEM_ARGS_PER_STEM);
|
|
194
|
+
stack.length = 0;
|
|
195
|
+
break;
|
|
196
|
+
case OP_HINTMASK:
|
|
197
|
+
case OP_CNTRMASK: {
|
|
198
|
+
takeWidth(state, true, 0);
|
|
199
|
+
state.stems += Math.floor(stack.length / STEM_ARGS_PER_STEM);
|
|
200
|
+
stack.length = 0;
|
|
201
|
+
const maskBytes = Math.ceil(state.stems / HINT_MASK_BITS_PER_BYTE);
|
|
202
|
+
if (!hasBytes(code, i, maskBytes)) return false;
|
|
203
|
+
i += maskBytes;
|
|
204
|
+
break;
|
|
205
|
+
}
|
|
206
|
+
case OP_RMOVETO:
|
|
207
|
+
takeWidth(state, false, 2);
|
|
208
|
+
if (stack.length < 2) return false;
|
|
209
|
+
moveTo(state, stack[stack.length - 2], stack[stack.length - 1]);
|
|
210
|
+
stack.length = 0;
|
|
211
|
+
break;
|
|
212
|
+
case OP_HMOVETO:
|
|
213
|
+
case OP_VMOVETO: {
|
|
214
|
+
takeWidth(state, false, 1);
|
|
215
|
+
if (stack.length < 1) return false;
|
|
216
|
+
const delta = stack[stack.length - 1];
|
|
217
|
+
moveTo(state, b0 === OP_HMOVETO ? delta : 0, b0 === OP_HMOVETO ? 0 : delta);
|
|
218
|
+
stack.length = 0;
|
|
219
|
+
break;
|
|
220
|
+
}
|
|
221
|
+
case OP_RLINETO:
|
|
222
|
+
for (let k = 0; k + 1 < stack.length; k += 2) lineTo(state, stack[k], stack[k + 1]);
|
|
223
|
+
stack.length = 0;
|
|
224
|
+
break;
|
|
225
|
+
case OP_HLINETO:
|
|
226
|
+
case OP_VLINETO: {
|
|
227
|
+
let horizontal = b0 === OP_HLINETO;
|
|
228
|
+
for (const delta of stack) {
|
|
229
|
+
lineTo(state, horizontal ? delta : 0, horizontal ? 0 : delta);
|
|
230
|
+
horizontal = !horizontal;
|
|
231
|
+
}
|
|
232
|
+
stack.length = 0;
|
|
233
|
+
break;
|
|
234
|
+
}
|
|
235
|
+
case OP_RRCURVETO:
|
|
236
|
+
for (let k = 0; k + 5 < stack.length; k += 6) curveTo(state, stack[k], stack[k + 1], stack[k + 2], stack[k + 3], stack[k + 4], stack[k + 5]);
|
|
237
|
+
stack.length = 0;
|
|
238
|
+
break;
|
|
239
|
+
case OP_RCURVELINE: {
|
|
240
|
+
let k = 0;
|
|
241
|
+
for (; k + 5 < stack.length - 2; k += 6) curveTo(state, stack[k], stack[k + 1], stack[k + 2], stack[k + 3], stack[k + 4], stack[k + 5]);
|
|
242
|
+
if (k + 1 < stack.length) lineTo(state, stack[k], stack[k + 1]);
|
|
243
|
+
stack.length = 0;
|
|
244
|
+
break;
|
|
245
|
+
}
|
|
246
|
+
case OP_RLINECURVE: {
|
|
247
|
+
let k = 0;
|
|
248
|
+
for (; k + 1 < stack.length - 6; k += 2) lineTo(state, stack[k], stack[k + 1]);
|
|
249
|
+
if (k + 5 < stack.length) curveTo(state, stack[k], stack[k + 1], stack[k + 2], stack[k + 3], stack[k + 4], stack[k + 5]);
|
|
250
|
+
stack.length = 0;
|
|
251
|
+
break;
|
|
252
|
+
}
|
|
253
|
+
case OP_VVCURVETO:
|
|
254
|
+
case OP_HHCURVETO: {
|
|
255
|
+
let k = 0;
|
|
256
|
+
let firstCross = 0;
|
|
257
|
+
if (stack.length % 4 === 1) {
|
|
258
|
+
firstCross = stack[0];
|
|
259
|
+
k = 1;
|
|
260
|
+
}
|
|
261
|
+
for (; k + 3 < stack.length; k += 4) {
|
|
262
|
+
const cross = k <= 1 ? firstCross : 0;
|
|
263
|
+
if (b0 === OP_VVCURVETO) curveTo(state, cross, stack[k], stack[k + 1], stack[k + 2], 0, stack[k + 3]);
|
|
264
|
+
else curveTo(state, stack[k], cross, stack[k + 1], stack[k + 2], stack[k + 3], 0);
|
|
265
|
+
}
|
|
266
|
+
stack.length = 0;
|
|
267
|
+
break;
|
|
268
|
+
}
|
|
269
|
+
case OP_VHCURVETO:
|
|
270
|
+
case OP_HVCURVETO: {
|
|
271
|
+
let horizontal = b0 === OP_HVCURVETO;
|
|
272
|
+
let k = 0;
|
|
273
|
+
while (stack.length - k >= 4) {
|
|
274
|
+
const extra = stack.length - k === 5 ? stack[k + 4] : 0;
|
|
275
|
+
if (horizontal) curveTo(state, stack[k], 0, stack[k + 1], stack[k + 2], extra, stack[k + 3]);
|
|
276
|
+
else curveTo(state, 0, stack[k], stack[k + 1], stack[k + 2], stack[k + 3], extra);
|
|
277
|
+
k += 4;
|
|
278
|
+
horizontal = !horizontal;
|
|
279
|
+
}
|
|
280
|
+
stack.length = 0;
|
|
281
|
+
break;
|
|
282
|
+
}
|
|
283
|
+
case OP_CALLSUBR:
|
|
284
|
+
case OP_CALLGSUBR: {
|
|
285
|
+
const index = stack.pop();
|
|
286
|
+
if (index === void 0) return false;
|
|
287
|
+
const subrs = b0 === OP_CALLSUBR ? context.localSubrs : context.globalSubrs;
|
|
288
|
+
const bias = b0 === OP_CALLSUBR ? context.localBias : context.globalBias;
|
|
289
|
+
const code2 = subrs?.entry(index + bias);
|
|
290
|
+
if (code2 === void 0) return false;
|
|
291
|
+
if (!execute(code2, state, context, depth + 1)) return false;
|
|
292
|
+
break;
|
|
293
|
+
}
|
|
294
|
+
case OP_RETURN: return true;
|
|
295
|
+
case OP_ENDCHAR:
|
|
296
|
+
if (!state.widthParsed) {
|
|
297
|
+
state.widthParsed = true;
|
|
298
|
+
if (stack.length === 1 || stack.length === 5) stack.shift();
|
|
299
|
+
}
|
|
300
|
+
return stack.length < ENDCHAR_SEAC_ARG_COUNT;
|
|
301
|
+
case OP_ESCAPE: {
|
|
302
|
+
if (i >= code.length) return false;
|
|
303
|
+
const b1 = code[i];
|
|
304
|
+
i += 1;
|
|
305
|
+
if (!executeEscaped(b1, state)) return false;
|
|
306
|
+
break;
|
|
307
|
+
}
|
|
308
|
+
default: return false;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
return true;
|
|
312
|
+
}
|
|
313
|
+
function executeEscaped(operator, state) {
|
|
314
|
+
const stack = state.stack;
|
|
315
|
+
const startY = state.y;
|
|
316
|
+
if (operator === ESC_FLEX) {
|
|
317
|
+
if (stack.length < 13) return false;
|
|
318
|
+
curveTo(state, stack[0], stack[1], stack[2], stack[3], stack[4], stack[5]);
|
|
319
|
+
curveTo(state, stack[6], stack[7], stack[8], stack[9], stack[10], stack[11]);
|
|
320
|
+
stack.length = 0;
|
|
321
|
+
return true;
|
|
322
|
+
}
|
|
323
|
+
if (operator === ESC_HFLEX) {
|
|
324
|
+
if (stack.length < 7) return false;
|
|
325
|
+
curveTo(state, stack[0], 0, stack[1], stack[2], stack[3], 0);
|
|
326
|
+
curveTo(state, stack[4], 0, stack[5], -stack[2], stack[6], 0);
|
|
327
|
+
stack.length = 0;
|
|
328
|
+
return true;
|
|
329
|
+
}
|
|
330
|
+
if (operator === ESC_HFLEX1) {
|
|
331
|
+
if (stack.length < 9) return false;
|
|
332
|
+
curveTo(state, stack[0], stack[1], stack[2], stack[3], stack[4], 0);
|
|
333
|
+
const dy5 = stack[7];
|
|
334
|
+
curveTo(state, stack[5], 0, stack[6], dy5, stack[8], startY - (state.y + dy5));
|
|
335
|
+
stack.length = 0;
|
|
336
|
+
return true;
|
|
337
|
+
}
|
|
338
|
+
if (operator === ESC_FLEX1) {
|
|
339
|
+
if (stack.length < 11) return false;
|
|
340
|
+
const startX = state.x;
|
|
341
|
+
let dx = 0;
|
|
342
|
+
let dy = 0;
|
|
343
|
+
for (let k = 0; k < 10; k += 2) {
|
|
344
|
+
dx += stack[k];
|
|
345
|
+
dy += stack[k + 1];
|
|
346
|
+
}
|
|
347
|
+
curveTo(state, stack[0], stack[1], stack[2], stack[3], stack[4], stack[5]);
|
|
348
|
+
const controlX = state.x + stack[6] + stack[8];
|
|
349
|
+
const controlY = state.y + stack[7] + stack[9];
|
|
350
|
+
if (Math.abs(dx) > Math.abs(dy)) curveTo(state, stack[6], stack[7], stack[8], stack[9], stack[10], startY - controlY);
|
|
351
|
+
else curveTo(state, stack[6], stack[7], stack[8], stack[9], startX - controlX, stack[10]);
|
|
352
|
+
stack.length = 0;
|
|
353
|
+
return true;
|
|
354
|
+
}
|
|
355
|
+
return false;
|
|
356
|
+
}
|
|
357
|
+
function readPrivateSubrs(bytes, privateOperands) {
|
|
358
|
+
if (privateOperands === void 0 || privateOperands.length < 2) return;
|
|
359
|
+
const size = privateOperands[0];
|
|
360
|
+
const offset = privateOperands[1];
|
|
361
|
+
if (!Number.isInteger(size) || !Number.isInteger(offset) || !hasBytes(bytes, offset, size)) return;
|
|
362
|
+
const subrsOffset = parseCffDict(bytes.subarray(offset, offset + size))?.get(19)?.[0];
|
|
363
|
+
if (subrsOffset === void 0 || !Number.isInteger(subrsOffset)) return;
|
|
364
|
+
return readCffIndex(bytes, offset + subrsOffset);
|
|
365
|
+
}
|
|
366
|
+
function parseCffGlyphBounds(bytes) {
|
|
367
|
+
if (!hasBytes(bytes, 0, CFF_HEADER_MIN_SIZE) || u8(bytes, 0) !== CFF_MAJOR_VERSION) return;
|
|
368
|
+
const headerSize = u8(bytes, CFF_HEADER_SIZE_OFFSET);
|
|
369
|
+
if (headerSize < CFF_HEADER_MIN_SIZE) return;
|
|
370
|
+
const nameIndex = readCffIndex(bytes, headerSize);
|
|
371
|
+
if (nameIndex === void 0) return;
|
|
372
|
+
const topDictIndex = readCffIndex(bytes, nameIndex.endOffset);
|
|
373
|
+
const topDictBytes = topDictIndex?.entry(0);
|
|
374
|
+
if (topDictIndex === void 0 || topDictBytes === void 0) return;
|
|
375
|
+
const topDict = parseCffDict(topDictBytes);
|
|
376
|
+
if (topDict === void 0 || topDict.has(1230)) return;
|
|
377
|
+
const stringIndex = readCffIndex(bytes, topDictIndex.endOffset);
|
|
378
|
+
if (stringIndex === void 0) return;
|
|
379
|
+
const globalSubrs = readCffIndex(bytes, stringIndex.endOffset);
|
|
380
|
+
if (globalSubrs === void 0) return;
|
|
381
|
+
const charStringsOffset = topDict.get(17)?.[0];
|
|
382
|
+
if (charStringsOffset === void 0 || !Number.isInteger(charStringsOffset)) return;
|
|
383
|
+
const charStrings = readCffIndex(bytes, charStringsOffset);
|
|
384
|
+
if (charStrings === void 0) return;
|
|
385
|
+
const localSubrs = readPrivateSubrs(bytes, topDict.get(18));
|
|
386
|
+
const context = {
|
|
387
|
+
charStrings,
|
|
388
|
+
globalSubrs,
|
|
389
|
+
localSubrs,
|
|
390
|
+
globalBias: subrBias(globalSubrs.count),
|
|
391
|
+
localBias: localSubrs === void 0 ? 0 : subrBias(localSubrs.count)
|
|
392
|
+
};
|
|
393
|
+
const memo = /* @__PURE__ */ new Map();
|
|
394
|
+
return {
|
|
395
|
+
numGlyphs: charStrings.count,
|
|
396
|
+
bounds(glyphId) {
|
|
397
|
+
if (memo.has(glyphId)) return memo.get(glyphId);
|
|
398
|
+
const computed = computeBounds(glyphId, context);
|
|
399
|
+
memo.set(glyphId, computed);
|
|
400
|
+
return computed;
|
|
401
|
+
}
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
function computeBounds(glyphId, context) {
|
|
405
|
+
const code = context.charStrings.entry(glyphId);
|
|
406
|
+
if (code === void 0) return;
|
|
407
|
+
const state = {
|
|
408
|
+
x: 0,
|
|
409
|
+
y: 0,
|
|
410
|
+
stack: [],
|
|
411
|
+
stems: 0,
|
|
412
|
+
widthParsed: false,
|
|
413
|
+
operations: 0,
|
|
414
|
+
box: {
|
|
415
|
+
minX: Infinity,
|
|
416
|
+
minY: Infinity,
|
|
417
|
+
maxX: -Infinity,
|
|
418
|
+
maxY: -Infinity,
|
|
419
|
+
drawn: false
|
|
420
|
+
}
|
|
421
|
+
};
|
|
422
|
+
if (!execute(code, state, context, 0) || !state.box.drawn) return;
|
|
423
|
+
return {
|
|
424
|
+
xMin: state.box.minX,
|
|
425
|
+
yMin: state.box.minY,
|
|
426
|
+
xMax: state.box.maxX,
|
|
427
|
+
yMax: state.box.maxY
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
//#endregion
|
|
431
|
+
export { parseCffGlyphBounds };
|
package/dist/cff-probe.cjs
CHANGED
|
@@ -1,108 +1,10 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_sfnt = require("./sfnt.cjs");
|
|
3
|
+
const require_cff = require("./cff.cjs");
|
|
3
4
|
//#region src/cff-probe.ts
|
|
4
5
|
const CFF_HEADER_SIZE = 4;
|
|
5
6
|
const CFF_MAJOR_VERSION = 1;
|
|
6
|
-
const
|
|
7
|
-
const INDEX_OFF_SIZE_SIZE = 1;
|
|
8
|
-
const MIN_OFF_SIZE = 1;
|
|
9
|
-
const MAX_OFF_SIZE = 4;
|
|
10
|
-
const DICT_OPERATOR_MAX = 21;
|
|
11
|
-
const DICT_OPERATOR_ESCAPE = 12;
|
|
12
|
-
const DICT_ROS_ESCAPED_OPERATOR = 30;
|
|
13
|
-
const DICT_OPERAND_INT16 = 28;
|
|
14
|
-
const DICT_OPERAND_INT32 = 29;
|
|
15
|
-
const DICT_OPERAND_REAL = 30;
|
|
16
|
-
const DICT_OPERAND_INT16_SIZE = 3;
|
|
17
|
-
const DICT_OPERAND_INT32_SIZE = 5;
|
|
18
|
-
const DICT_OPERAND_SMALL_FIRST = 32;
|
|
19
|
-
const DICT_OPERAND_SMALL_LAST = 246;
|
|
20
|
-
const DICT_OPERAND_MEDIUM_FIRST = 247;
|
|
21
|
-
const DICT_OPERAND_MEDIUM_LAST = 254;
|
|
22
|
-
const DICT_OPERAND_MEDIUM_SIZE = 2;
|
|
23
|
-
const DICT_REAL_TERMINATOR_NIBBLE = 15;
|
|
24
|
-
function readOffsetAt(bytes, offset, offSize) {
|
|
25
|
-
if (offSize === 1) return require_sfnt.u8(bytes, offset);
|
|
26
|
-
if (offSize === 2) return require_sfnt.u16(bytes, offset);
|
|
27
|
-
if (offSize === 3) return require_sfnt.u24(bytes, offset);
|
|
28
|
-
return require_sfnt.u32(bytes, offset);
|
|
29
|
-
}
|
|
30
|
-
function readIndex(bytes, offset) {
|
|
31
|
-
if (!require_sfnt.hasBytes(bytes, offset, INDEX_COUNT_SIZE)) return;
|
|
32
|
-
const count = require_sfnt.u16(bytes, offset);
|
|
33
|
-
if (count === 0) return {
|
|
34
|
-
count: 0,
|
|
35
|
-
endOffset: offset + INDEX_COUNT_SIZE,
|
|
36
|
-
entry: () => void 0
|
|
37
|
-
};
|
|
38
|
-
if (!require_sfnt.hasBytes(bytes, offset + INDEX_COUNT_SIZE, INDEX_OFF_SIZE_SIZE)) return;
|
|
39
|
-
const offSize = require_sfnt.u8(bytes, offset + INDEX_COUNT_SIZE);
|
|
40
|
-
if (offSize < MIN_OFF_SIZE || offSize > MAX_OFF_SIZE) return;
|
|
41
|
-
const offsetArrayStart = offset + INDEX_COUNT_SIZE + INDEX_OFF_SIZE_SIZE;
|
|
42
|
-
const offsetArrayLength = (count + 1) * offSize;
|
|
43
|
-
if (!require_sfnt.hasBytes(bytes, offsetArrayStart, offsetArrayLength)) return;
|
|
44
|
-
const offsets = [];
|
|
45
|
-
for (let i = 0; i <= count; i++) offsets.push(readOffsetAt(bytes, offsetArrayStart + i * offSize, offSize));
|
|
46
|
-
if (offsets[0] !== 1) return;
|
|
47
|
-
for (let i = 1; i <= count; i++) if (offsets[i] < offsets[i - 1]) return;
|
|
48
|
-
const dataOrigin = offsetArrayStart + offsetArrayLength - 1;
|
|
49
|
-
const dataLength = offsets[count] - 1;
|
|
50
|
-
if (!require_sfnt.hasBytes(bytes, dataOrigin + 1, dataLength)) return;
|
|
51
|
-
return {
|
|
52
|
-
count,
|
|
53
|
-
endOffset: dataOrigin + 1 + dataLength,
|
|
54
|
-
entry: (index) => index < 0 || index >= count ? void 0 : bytes.subarray(dataOrigin + offsets[index], dataOrigin + offsets[index + 1])
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
function dictDeclaresRos(data) {
|
|
58
|
-
let i = 0;
|
|
59
|
-
while (i < data.length) {
|
|
60
|
-
const b0 = data[i];
|
|
61
|
-
if (b0 <= DICT_OPERATOR_MAX) {
|
|
62
|
-
if (b0 !== DICT_OPERATOR_ESCAPE) {
|
|
63
|
-
i += 1;
|
|
64
|
-
continue;
|
|
65
|
-
}
|
|
66
|
-
if (i + 1 >= data.length) return;
|
|
67
|
-
if (data[i + 1] === DICT_ROS_ESCAPED_OPERATOR) return true;
|
|
68
|
-
i += 2;
|
|
69
|
-
continue;
|
|
70
|
-
}
|
|
71
|
-
if (b0 === DICT_OPERAND_INT16) {
|
|
72
|
-
if (i + DICT_OPERAND_INT16_SIZE > data.length) return;
|
|
73
|
-
i += DICT_OPERAND_INT16_SIZE;
|
|
74
|
-
continue;
|
|
75
|
-
}
|
|
76
|
-
if (b0 === DICT_OPERAND_INT32) {
|
|
77
|
-
if (i + DICT_OPERAND_INT32_SIZE > data.length) return;
|
|
78
|
-
i += DICT_OPERAND_INT32_SIZE;
|
|
79
|
-
continue;
|
|
80
|
-
}
|
|
81
|
-
if (b0 === DICT_OPERAND_REAL) {
|
|
82
|
-
const end = findRealOperandEnd(data, i + 1);
|
|
83
|
-
if (end === void 0) return;
|
|
84
|
-
i = end;
|
|
85
|
-
continue;
|
|
86
|
-
}
|
|
87
|
-
if (b0 >= DICT_OPERAND_SMALL_FIRST && b0 <= DICT_OPERAND_SMALL_LAST) {
|
|
88
|
-
i += 1;
|
|
89
|
-
continue;
|
|
90
|
-
}
|
|
91
|
-
if (b0 >= DICT_OPERAND_MEDIUM_FIRST && b0 <= DICT_OPERAND_MEDIUM_LAST) {
|
|
92
|
-
if (i + DICT_OPERAND_MEDIUM_SIZE > data.length) return;
|
|
93
|
-
i += DICT_OPERAND_MEDIUM_SIZE;
|
|
94
|
-
continue;
|
|
95
|
-
}
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
return false;
|
|
99
|
-
}
|
|
100
|
-
function findRealOperandEnd(data, start) {
|
|
101
|
-
for (let i = start; i < data.length; i++) {
|
|
102
|
-
const byte = data[i];
|
|
103
|
-
if (byte >> 4 === DICT_REAL_TERMINATOR_NIBBLE || (byte & 15) === DICT_REAL_TERMINATOR_NIBBLE) return i + 1;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
7
|
+
const CFF_HEADER_SIZE_OFFSET = 2;
|
|
106
8
|
function decodeAscii(bytes) {
|
|
107
9
|
let text = "";
|
|
108
10
|
for (const byte of bytes) text += String.fromCharCode(byte);
|
|
@@ -112,21 +14,21 @@ function probeCff(bytes) {
|
|
|
112
14
|
if (!require_sfnt.hasBytes(bytes, 0, CFF_HEADER_SIZE)) return;
|
|
113
15
|
const majorVersion = require_sfnt.u8(bytes, 0);
|
|
114
16
|
const minorVersion = require_sfnt.u8(bytes, 1);
|
|
115
|
-
const headerSize = require_sfnt.u8(bytes,
|
|
17
|
+
const headerSize = require_sfnt.u8(bytes, CFF_HEADER_SIZE_OFFSET);
|
|
116
18
|
if (majorVersion !== CFF_MAJOR_VERSION || headerSize < CFF_HEADER_SIZE) return;
|
|
117
|
-
const nameIndex =
|
|
19
|
+
const nameIndex = require_cff.readCffIndex(bytes, headerSize);
|
|
118
20
|
if (nameIndex === void 0 || nameIndex.count === 0) return;
|
|
119
21
|
const nameBytes = nameIndex.entry(0);
|
|
120
22
|
if (nameBytes === void 0) return;
|
|
121
|
-
const
|
|
23
|
+
const topDictBytes = require_cff.readCffIndex(bytes, nameIndex.endOffset)?.entry(0);
|
|
24
|
+
if (topDictBytes === void 0) return;
|
|
25
|
+
const topDict = require_cff.parseCffDict(topDictBytes);
|
|
122
26
|
if (topDict === void 0) return;
|
|
123
|
-
const cidKeyed = dictDeclaresRos(topDict);
|
|
124
|
-
if (cidKeyed === void 0) return;
|
|
125
27
|
return {
|
|
126
28
|
majorVersion,
|
|
127
29
|
minorVersion,
|
|
128
30
|
name: decodeAscii(nameBytes),
|
|
129
|
-
cidKeyed
|
|
31
|
+
cidKeyed: topDict.has(require_cff.CFF_DICT_OP_ROS)
|
|
130
32
|
};
|
|
131
33
|
}
|
|
132
34
|
//#endregion
|
package/dist/cff-probe.js
CHANGED
|
@@ -1,107 +1,9 @@
|
|
|
1
|
-
import { hasBytes,
|
|
1
|
+
import { hasBytes, u8 } from "./sfnt.js";
|
|
2
|
+
import { CFF_DICT_OP_ROS, parseCffDict, readCffIndex } from "./cff.js";
|
|
2
3
|
//#region src/cff-probe.ts
|
|
3
4
|
const CFF_HEADER_SIZE = 4;
|
|
4
5
|
const CFF_MAJOR_VERSION = 1;
|
|
5
|
-
const
|
|
6
|
-
const INDEX_OFF_SIZE_SIZE = 1;
|
|
7
|
-
const MIN_OFF_SIZE = 1;
|
|
8
|
-
const MAX_OFF_SIZE = 4;
|
|
9
|
-
const DICT_OPERATOR_MAX = 21;
|
|
10
|
-
const DICT_OPERATOR_ESCAPE = 12;
|
|
11
|
-
const DICT_ROS_ESCAPED_OPERATOR = 30;
|
|
12
|
-
const DICT_OPERAND_INT16 = 28;
|
|
13
|
-
const DICT_OPERAND_INT32 = 29;
|
|
14
|
-
const DICT_OPERAND_REAL = 30;
|
|
15
|
-
const DICT_OPERAND_INT16_SIZE = 3;
|
|
16
|
-
const DICT_OPERAND_INT32_SIZE = 5;
|
|
17
|
-
const DICT_OPERAND_SMALL_FIRST = 32;
|
|
18
|
-
const DICT_OPERAND_SMALL_LAST = 246;
|
|
19
|
-
const DICT_OPERAND_MEDIUM_FIRST = 247;
|
|
20
|
-
const DICT_OPERAND_MEDIUM_LAST = 254;
|
|
21
|
-
const DICT_OPERAND_MEDIUM_SIZE = 2;
|
|
22
|
-
const DICT_REAL_TERMINATOR_NIBBLE = 15;
|
|
23
|
-
function readOffsetAt(bytes, offset, offSize) {
|
|
24
|
-
if (offSize === 1) return u8(bytes, offset);
|
|
25
|
-
if (offSize === 2) return u16(bytes, offset);
|
|
26
|
-
if (offSize === 3) return u24(bytes, offset);
|
|
27
|
-
return u32(bytes, offset);
|
|
28
|
-
}
|
|
29
|
-
function readIndex(bytes, offset) {
|
|
30
|
-
if (!hasBytes(bytes, offset, INDEX_COUNT_SIZE)) return;
|
|
31
|
-
const count = u16(bytes, offset);
|
|
32
|
-
if (count === 0) return {
|
|
33
|
-
count: 0,
|
|
34
|
-
endOffset: offset + INDEX_COUNT_SIZE,
|
|
35
|
-
entry: () => void 0
|
|
36
|
-
};
|
|
37
|
-
if (!hasBytes(bytes, offset + INDEX_COUNT_SIZE, INDEX_OFF_SIZE_SIZE)) return;
|
|
38
|
-
const offSize = u8(bytes, offset + INDEX_COUNT_SIZE);
|
|
39
|
-
if (offSize < MIN_OFF_SIZE || offSize > MAX_OFF_SIZE) return;
|
|
40
|
-
const offsetArrayStart = offset + INDEX_COUNT_SIZE + INDEX_OFF_SIZE_SIZE;
|
|
41
|
-
const offsetArrayLength = (count + 1) * offSize;
|
|
42
|
-
if (!hasBytes(bytes, offsetArrayStart, offsetArrayLength)) return;
|
|
43
|
-
const offsets = [];
|
|
44
|
-
for (let i = 0; i <= count; i++) offsets.push(readOffsetAt(bytes, offsetArrayStart + i * offSize, offSize));
|
|
45
|
-
if (offsets[0] !== 1) return;
|
|
46
|
-
for (let i = 1; i <= count; i++) if (offsets[i] < offsets[i - 1]) return;
|
|
47
|
-
const dataOrigin = offsetArrayStart + offsetArrayLength - 1;
|
|
48
|
-
const dataLength = offsets[count] - 1;
|
|
49
|
-
if (!hasBytes(bytes, dataOrigin + 1, dataLength)) return;
|
|
50
|
-
return {
|
|
51
|
-
count,
|
|
52
|
-
endOffset: dataOrigin + 1 + dataLength,
|
|
53
|
-
entry: (index) => index < 0 || index >= count ? void 0 : bytes.subarray(dataOrigin + offsets[index], dataOrigin + offsets[index + 1])
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
function dictDeclaresRos(data) {
|
|
57
|
-
let i = 0;
|
|
58
|
-
while (i < data.length) {
|
|
59
|
-
const b0 = data[i];
|
|
60
|
-
if (b0 <= DICT_OPERATOR_MAX) {
|
|
61
|
-
if (b0 !== DICT_OPERATOR_ESCAPE) {
|
|
62
|
-
i += 1;
|
|
63
|
-
continue;
|
|
64
|
-
}
|
|
65
|
-
if (i + 1 >= data.length) return;
|
|
66
|
-
if (data[i + 1] === DICT_ROS_ESCAPED_OPERATOR) return true;
|
|
67
|
-
i += 2;
|
|
68
|
-
continue;
|
|
69
|
-
}
|
|
70
|
-
if (b0 === DICT_OPERAND_INT16) {
|
|
71
|
-
if (i + DICT_OPERAND_INT16_SIZE > data.length) return;
|
|
72
|
-
i += DICT_OPERAND_INT16_SIZE;
|
|
73
|
-
continue;
|
|
74
|
-
}
|
|
75
|
-
if (b0 === DICT_OPERAND_INT32) {
|
|
76
|
-
if (i + DICT_OPERAND_INT32_SIZE > data.length) return;
|
|
77
|
-
i += DICT_OPERAND_INT32_SIZE;
|
|
78
|
-
continue;
|
|
79
|
-
}
|
|
80
|
-
if (b0 === DICT_OPERAND_REAL) {
|
|
81
|
-
const end = findRealOperandEnd(data, i + 1);
|
|
82
|
-
if (end === void 0) return;
|
|
83
|
-
i = end;
|
|
84
|
-
continue;
|
|
85
|
-
}
|
|
86
|
-
if (b0 >= DICT_OPERAND_SMALL_FIRST && b0 <= DICT_OPERAND_SMALL_LAST) {
|
|
87
|
-
i += 1;
|
|
88
|
-
continue;
|
|
89
|
-
}
|
|
90
|
-
if (b0 >= DICT_OPERAND_MEDIUM_FIRST && b0 <= DICT_OPERAND_MEDIUM_LAST) {
|
|
91
|
-
if (i + DICT_OPERAND_MEDIUM_SIZE > data.length) return;
|
|
92
|
-
i += DICT_OPERAND_MEDIUM_SIZE;
|
|
93
|
-
continue;
|
|
94
|
-
}
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
return false;
|
|
98
|
-
}
|
|
99
|
-
function findRealOperandEnd(data, start) {
|
|
100
|
-
for (let i = start; i < data.length; i++) {
|
|
101
|
-
const byte = data[i];
|
|
102
|
-
if (byte >> 4 === DICT_REAL_TERMINATOR_NIBBLE || (byte & 15) === DICT_REAL_TERMINATOR_NIBBLE) return i + 1;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
6
|
+
const CFF_HEADER_SIZE_OFFSET = 2;
|
|
105
7
|
function decodeAscii(bytes) {
|
|
106
8
|
let text = "";
|
|
107
9
|
for (const byte of bytes) text += String.fromCharCode(byte);
|
|
@@ -111,21 +13,21 @@ function probeCff(bytes) {
|
|
|
111
13
|
if (!hasBytes(bytes, 0, CFF_HEADER_SIZE)) return;
|
|
112
14
|
const majorVersion = u8(bytes, 0);
|
|
113
15
|
const minorVersion = u8(bytes, 1);
|
|
114
|
-
const headerSize = u8(bytes,
|
|
16
|
+
const headerSize = u8(bytes, CFF_HEADER_SIZE_OFFSET);
|
|
115
17
|
if (majorVersion !== CFF_MAJOR_VERSION || headerSize < CFF_HEADER_SIZE) return;
|
|
116
|
-
const nameIndex =
|
|
18
|
+
const nameIndex = readCffIndex(bytes, headerSize);
|
|
117
19
|
if (nameIndex === void 0 || nameIndex.count === 0) return;
|
|
118
20
|
const nameBytes = nameIndex.entry(0);
|
|
119
21
|
if (nameBytes === void 0) return;
|
|
120
|
-
const
|
|
22
|
+
const topDictBytes = readCffIndex(bytes, nameIndex.endOffset)?.entry(0);
|
|
23
|
+
if (topDictBytes === void 0) return;
|
|
24
|
+
const topDict = parseCffDict(topDictBytes);
|
|
121
25
|
if (topDict === void 0) return;
|
|
122
|
-
const cidKeyed = dictDeclaresRos(topDict);
|
|
123
|
-
if (cidKeyed === void 0) return;
|
|
124
26
|
return {
|
|
125
27
|
majorVersion,
|
|
126
28
|
minorVersion,
|
|
127
29
|
name: decodeAscii(nameBytes),
|
|
128
|
-
cidKeyed
|
|
30
|
+
cidKeyed: topDict.has(CFF_DICT_OP_ROS)
|
|
129
31
|
};
|
|
130
32
|
}
|
|
131
33
|
//#endregion
|