1 | //======================================================================== |
2 | // |
3 | // FoFiType1C.cc |
4 | // |
5 | // Copyright 1999-2003 Glyph & Cog, LLC |
6 | // |
7 | //======================================================================== |
8 | |
9 | //======================================================================== |
10 | // |
11 | // Modified under the Poppler project - http://poppler.freedesktop.org |
12 | // |
13 | // All changes made under the Poppler project to this file are licensed |
14 | // under GPL version 2 or later |
15 | // |
16 | // Copyright (C) 2009, 2010, 2017-2022 Albert Astals Cid <aacid@kde.org> |
17 | // Copyright (C) 2012 Thomas Freitag <Thomas.Freitag@alfa.de> |
18 | // Copyright (C) 2018 Adam Reichold <adam.reichold@t-online.de> |
19 | // Copyright (C) 2019 Tomoyuki Kubota <himajin100000@gmail.com> |
20 | // Copyright (C) 2019 Volker Krause <vkrause@kde.org> |
21 | // Copyright (C) 2022 Oliver Sander <oliver.sander@tu-dresden.de> |
22 | // |
23 | // To see a description of the changes please see the Changelog file that |
24 | // came with your tarball or type make ChangeLog if you are building from git |
25 | // |
26 | //======================================================================== |
27 | |
28 | #include <config.h> |
29 | |
30 | #include <cstdlib> |
31 | #include <cstring> |
32 | #include <cmath> |
33 | #include "goo/gmem.h" |
34 | #include "goo/gstrtod.h" |
35 | #include "goo/GooLikely.h" |
36 | #include "goo/GooString.h" |
37 | #include "poppler/Error.h" |
38 | #include "FoFiEncodings.h" |
39 | #include "FoFiType1C.h" |
40 | |
41 | //------------------------------------------------------------------------ |
42 | |
43 | static const char hexChars[17] = "0123456789ABCDEF" ; |
44 | |
45 | //------------------------------------------------------------------------ |
46 | // FoFiType1C |
47 | //------------------------------------------------------------------------ |
48 | |
49 | FoFiType1C *FoFiType1C::make(const unsigned char *fileA, int lenA) |
50 | { |
51 | FoFiType1C *ff = new FoFiType1C(fileA, lenA, false); |
52 | if (!ff->parse()) { |
53 | delete ff; |
54 | return nullptr; |
55 | } |
56 | return ff; |
57 | } |
58 | |
59 | FoFiType1C *FoFiType1C::load(const char *fileName) |
60 | { |
61 | FoFiType1C *ff; |
62 | char *fileA; |
63 | int lenA; |
64 | |
65 | if (!(fileA = FoFiBase::readFile(fileName, fileLen: &lenA))) { |
66 | return nullptr; |
67 | } |
68 | ff = new FoFiType1C((unsigned char *)fileA, lenA, true); |
69 | if (!ff->parse()) { |
70 | delete ff; |
71 | return nullptr; |
72 | } |
73 | return ff; |
74 | } |
75 | |
76 | FoFiType1C::FoFiType1C(const unsigned char *fileA, int lenA, bool freeFileDataA) : FoFiBase(fileA, lenA, freeFileDataA) |
77 | { |
78 | name = nullptr; |
79 | encoding = nullptr; |
80 | privateDicts = nullptr; |
81 | fdSelect = nullptr; |
82 | charset = nullptr; |
83 | charsetLength = 0; |
84 | } |
85 | |
86 | FoFiType1C::~FoFiType1C() |
87 | { |
88 | int i; |
89 | |
90 | if (name) { |
91 | delete name; |
92 | } |
93 | if (encoding && encoding != fofiType1StandardEncoding && encoding != fofiType1ExpertEncoding) { |
94 | for (i = 0; i < 256; ++i) { |
95 | gfree(p: encoding[i]); |
96 | } |
97 | gfree(p: encoding); |
98 | } |
99 | if (privateDicts) { |
100 | gfree(p: privateDicts); |
101 | } |
102 | if (fdSelect) { |
103 | gfree(p: fdSelect); |
104 | } |
105 | if (charset && charset != fofiType1CISOAdobeCharset && charset != fofiType1CExpertCharset && charset != fofiType1CExpertSubsetCharset) { |
106 | gfree(p: const_cast<unsigned short *>(charset)); |
107 | } |
108 | } |
109 | |
110 | const char *FoFiType1C::getName() const |
111 | { |
112 | return name ? name->c_str() : nullptr; |
113 | } |
114 | |
115 | char **FoFiType1C::getEncoding() const |
116 | { |
117 | return encoding; |
118 | } |
119 | |
120 | GooString *FoFiType1C::getGlyphName(int gid) const |
121 | { |
122 | char buf[256]; |
123 | bool ok; |
124 | |
125 | ok = true; |
126 | if (gid < 0 || gid >= charsetLength) { |
127 | return nullptr; |
128 | } |
129 | getString(sid: charset[gid], buf, ok: &ok); |
130 | if (!ok) { |
131 | return nullptr; |
132 | } |
133 | return new GooString(buf); |
134 | } |
135 | |
136 | int *FoFiType1C::getCIDToGIDMap(int *nCIDs) const |
137 | { |
138 | int *map; |
139 | int n, i; |
140 | |
141 | // a CID font's top dict has ROS as the first operator |
142 | if (topDict.firstOp != 0x0c1e) { |
143 | *nCIDs = 0; |
144 | return nullptr; |
145 | } |
146 | |
147 | // in a CID font, the charset data is the GID-to-CID mapping, so all |
148 | // we have to do is reverse it |
149 | n = 0; |
150 | for (i = 0; i < nGlyphs && i < charsetLength; ++i) { |
151 | if (charset[i] > n) { |
152 | n = charset[i]; |
153 | } |
154 | } |
155 | ++n; |
156 | map = (int *)gmallocn(count: n, size: sizeof(int)); |
157 | memset(s: map, c: 0, n: n * sizeof(int)); |
158 | for (i = 0; i < nGlyphs; ++i) { |
159 | map[charset[i]] = i; |
160 | } |
161 | *nCIDs = n; |
162 | return map; |
163 | } |
164 | |
165 | void FoFiType1C::getFontMatrix(double *mat) const |
166 | { |
167 | int i; |
168 | |
169 | if (topDict.firstOp == 0x0c1e && privateDicts[0].hasFontMatrix) { |
170 | if (topDict.hasFontMatrix) { |
171 | mat[0] = topDict.fontMatrix[0] * privateDicts[0].fontMatrix[0] + topDict.fontMatrix[1] * privateDicts[0].fontMatrix[2]; |
172 | mat[1] = topDict.fontMatrix[0] * privateDicts[0].fontMatrix[1] + topDict.fontMatrix[1] * privateDicts[0].fontMatrix[3]; |
173 | mat[2] = topDict.fontMatrix[2] * privateDicts[0].fontMatrix[0] + topDict.fontMatrix[3] * privateDicts[0].fontMatrix[2]; |
174 | mat[3] = topDict.fontMatrix[2] * privateDicts[0].fontMatrix[1] + topDict.fontMatrix[3] * privateDicts[0].fontMatrix[3]; |
175 | mat[4] = topDict.fontMatrix[4] * privateDicts[0].fontMatrix[0] + topDict.fontMatrix[5] * privateDicts[0].fontMatrix[2]; |
176 | mat[5] = topDict.fontMatrix[4] * privateDicts[0].fontMatrix[1] + topDict.fontMatrix[5] * privateDicts[0].fontMatrix[3]; |
177 | } else { |
178 | for (i = 0; i < 6; ++i) { |
179 | mat[i] = privateDicts[0].fontMatrix[i]; |
180 | } |
181 | } |
182 | } else { |
183 | for (i = 0; i < 6; ++i) { |
184 | mat[i] = topDict.fontMatrix[i]; |
185 | } |
186 | } |
187 | } |
188 | |
189 | void FoFiType1C::convertToType1(const char *psName, const char **newEncoding, bool ascii, FoFiOutputFunc outputFunc, void *outputStream) |
190 | { |
191 | int psNameLen; |
192 | Type1CEexecBuf eb; |
193 | Type1CIndex subrIdx; |
194 | Type1CIndexVal val; |
195 | char buf2[256]; |
196 | bool ok; |
197 | int i; |
198 | |
199 | if (psName) { |
200 | psNameLen = strlen(s: psName); |
201 | } else { |
202 | psName = name->c_str(); |
203 | psNameLen = name->getLength(); |
204 | } |
205 | |
206 | // write header and font dictionary, up to encoding |
207 | ok = true; |
208 | (*outputFunc)(outputStream, "%!FontType1-1.0: " , 17); |
209 | (*outputFunc)(outputStream, psName, psNameLen); |
210 | if (topDict.versionSID != 0) { |
211 | getString(sid: topDict.versionSID, buf: buf2, ok: &ok); |
212 | (*outputFunc)(outputStream, buf2, strlen(s: buf2)); |
213 | } |
214 | (*outputFunc)(outputStream, "\n" , 1); |
215 | // the dictionary needs room for 12 entries: the following 9, plus |
216 | // Private and CharStrings (in the eexec section) and FID (which is |
217 | // added by definefont) |
218 | (*outputFunc)(outputStream, "12 dict begin\n" , 14); |
219 | (*outputFunc)(outputStream, "/FontInfo 10 dict dup begin\n" , 28); |
220 | if (topDict.versionSID != 0) { |
221 | (*outputFunc)(outputStream, "/version " , 9); |
222 | writePSString(s: buf2, outputFunc, outputStream); |
223 | (*outputFunc)(outputStream, " readonly def\n" , 14); |
224 | } |
225 | if (topDict.noticeSID != 0) { |
226 | getString(sid: topDict.noticeSID, buf: buf2, ok: &ok); |
227 | (*outputFunc)(outputStream, "/Notice " , 8); |
228 | writePSString(s: buf2, outputFunc, outputStream); |
229 | (*outputFunc)(outputStream, " readonly def\n" , 14); |
230 | } |
231 | if (topDict.copyrightSID != 0) { |
232 | getString(sid: topDict.copyrightSID, buf: buf2, ok: &ok); |
233 | (*outputFunc)(outputStream, "/Copyright " , 11); |
234 | writePSString(s: buf2, outputFunc, outputStream); |
235 | (*outputFunc)(outputStream, " readonly def\n" , 14); |
236 | } |
237 | if (topDict.fullNameSID != 0) { |
238 | getString(sid: topDict.fullNameSID, buf: buf2, ok: &ok); |
239 | (*outputFunc)(outputStream, "/FullName " , 10); |
240 | writePSString(s: buf2, outputFunc, outputStream); |
241 | (*outputFunc)(outputStream, " readonly def\n" , 14); |
242 | } |
243 | if (topDict.familyNameSID != 0) { |
244 | getString(sid: topDict.familyNameSID, buf: buf2, ok: &ok); |
245 | (*outputFunc)(outputStream, "/FamilyName " , 12); |
246 | writePSString(s: buf2, outputFunc, outputStream); |
247 | (*outputFunc)(outputStream, " readonly def\n" , 14); |
248 | } |
249 | if (topDict.weightSID != 0) { |
250 | getString(sid: topDict.weightSID, buf: buf2, ok: &ok); |
251 | (*outputFunc)(outputStream, "/Weight " , 8); |
252 | writePSString(s: buf2, outputFunc, outputStream); |
253 | (*outputFunc)(outputStream, " readonly def\n" , 14); |
254 | } |
255 | if (topDict.isFixedPitch) { |
256 | (*outputFunc)(outputStream, "/isFixedPitch true def\n" , 23); |
257 | } else { |
258 | (*outputFunc)(outputStream, "/isFixedPitch false def\n" , 24); |
259 | } |
260 | std::unique_ptr<GooString> buf = GooString::format(fmt: "/ItalicAngle {0:.4g} def\n" , topDict.italicAngle); |
261 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
262 | buf = GooString::format(fmt: "/UnderlinePosition {0:.4g} def\n" , topDict.underlinePosition); |
263 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
264 | buf = GooString::format(fmt: "/UnderlineThickness {0:.4g} def\n" , topDict.underlineThickness); |
265 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
266 | (*outputFunc)(outputStream, "end readonly def\n" , 17); |
267 | (*outputFunc)(outputStream, "/FontName /" , 11); |
268 | (*outputFunc)(outputStream, psName, psNameLen); |
269 | (*outputFunc)(outputStream, " def\n" , 5); |
270 | buf = GooString::format(fmt: "/PaintType {0:d} def\n" , topDict.paintType); |
271 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
272 | (*outputFunc)(outputStream, "/FontType 1 def\n" , 16); |
273 | buf = GooString::format(fmt: "/FontMatrix [{0:.8g} {1:.8g} {2:.8g} {3:.8g} {4:.8g} {5:.8g}] readonly def\n" , topDict.fontMatrix[0], topDict.fontMatrix[1], topDict.fontMatrix[2], topDict.fontMatrix[3], topDict.fontMatrix[4], |
274 | topDict.fontMatrix[5]); |
275 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
276 | buf = GooString::format(fmt: "/FontBBox [{0:.4g} {1:.4g} {2:.4g} {3:.4g}] readonly def\n" , topDict.fontBBox[0], topDict.fontBBox[1], topDict.fontBBox[2], topDict.fontBBox[3]); |
277 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
278 | buf = GooString::format(fmt: "/StrokeWidth {0:.4g} def\n" , topDict.strokeWidth); |
279 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
280 | if (topDict.uniqueID != 0) { |
281 | buf = GooString::format(fmt: "/UniqueID {0:d} def\n" , topDict.uniqueID); |
282 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
283 | } |
284 | |
285 | // write the encoding |
286 | (*outputFunc)(outputStream, "/Encoding " , 10); |
287 | if (!newEncoding && encoding == fofiType1StandardEncoding) { |
288 | (*outputFunc)(outputStream, "StandardEncoding def\n" , 21); |
289 | } else { |
290 | (*outputFunc)(outputStream, "256 array\n" , 10); |
291 | (*outputFunc)(outputStream, "0 1 255 {1 index exch /.notdef put} for\n" , 40); |
292 | const char **enc = newEncoding ? newEncoding : (const char **)encoding; |
293 | for (i = 0; i < 256; ++i) { |
294 | if (enc && enc[i]) { |
295 | buf = GooString::format(fmt: "dup {0:d} /{1:s} put\n" , i, enc[i]); |
296 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
297 | } |
298 | } |
299 | (*outputFunc)(outputStream, "readonly def\n" , 13); |
300 | } |
301 | (*outputFunc)(outputStream, "currentdict end\n" , 16); |
302 | |
303 | // start the binary section |
304 | (*outputFunc)(outputStream, "currentfile eexec\n" , 18); |
305 | eb.outputFunc = outputFunc; |
306 | eb.outputStream = outputStream; |
307 | eb.ascii = ascii; |
308 | eb.r1 = 55665; |
309 | eb.line = 0; |
310 | |
311 | // write the private dictionary |
312 | eexecWrite(eb: &eb, s: "\x83\xca\x73\xd5" ); |
313 | eexecWrite(eb: &eb, s: "dup /Private 32 dict dup begin\n" ); |
314 | eexecWrite(eb: &eb, |
315 | s: "/RD {string currentfile exch readstring pop}" |
316 | " executeonly def\n" ); |
317 | eexecWrite(eb: &eb, s: "/ND {noaccess def} executeonly def\n" ); |
318 | eexecWrite(eb: &eb, s: "/NP {noaccess put} executeonly def\n" ); |
319 | eexecWrite(eb: &eb, s: "/MinFeature {16 16} def\n" ); |
320 | eexecWrite(eb: &eb, s: "/password 5839 def\n" ); |
321 | if (privateDicts[0].nBlueValues) { |
322 | eexecWrite(eb: &eb, s: "/BlueValues [" ); |
323 | for (i = 0; i < privateDicts[0].nBlueValues; ++i) { |
324 | buf = GooString::format(fmt: "{0:s}{1:d}" , i > 0 ? " " : "" , privateDicts[0].blueValues[i]); |
325 | eexecWrite(eb: &eb, s: buf->c_str()); |
326 | } |
327 | eexecWrite(eb: &eb, s: "] def\n" ); |
328 | } |
329 | if (privateDicts[0].nOtherBlues) { |
330 | eexecWrite(eb: &eb, s: "/OtherBlues [" ); |
331 | for (i = 0; i < privateDicts[0].nOtherBlues; ++i) { |
332 | buf = GooString::format(fmt: "{0:s}{1:d}" , i > 0 ? " " : "" , privateDicts[0].otherBlues[i]); |
333 | eexecWrite(eb: &eb, s: buf->c_str()); |
334 | } |
335 | eexecWrite(eb: &eb, s: "] def\n" ); |
336 | } |
337 | if (privateDicts[0].nFamilyBlues) { |
338 | eexecWrite(eb: &eb, s: "/FamilyBlues [" ); |
339 | for (i = 0; i < privateDicts[0].nFamilyBlues; ++i) { |
340 | buf = GooString::format(fmt: "{0:s}{1:d}" , i > 0 ? " " : "" , privateDicts[0].familyBlues[i]); |
341 | eexecWrite(eb: &eb, s: buf->c_str()); |
342 | } |
343 | eexecWrite(eb: &eb, s: "] def\n" ); |
344 | } |
345 | if (privateDicts[0].nFamilyOtherBlues) { |
346 | eexecWrite(eb: &eb, s: "/FamilyOtherBlues [" ); |
347 | for (i = 0; i < privateDicts[0].nFamilyOtherBlues; ++i) { |
348 | buf = GooString::format(fmt: "{0:s}{1:d}" , i > 0 ? " " : "" , privateDicts[0].familyOtherBlues[i]); |
349 | eexecWrite(eb: &eb, s: buf->c_str()); |
350 | } |
351 | eexecWrite(eb: &eb, s: "] def\n" ); |
352 | } |
353 | if (privateDicts[0].blueScale != 0.039625) { |
354 | buf = GooString::format(fmt: "/BlueScale {0:.4g} def\n" , privateDicts[0].blueScale); |
355 | eexecWrite(eb: &eb, s: buf->c_str()); |
356 | } |
357 | if (privateDicts[0].blueShift != 7) { |
358 | buf = GooString::format(fmt: "/BlueShift {0:d} def\n" , privateDicts[0].blueShift); |
359 | eexecWrite(eb: &eb, s: buf->c_str()); |
360 | } |
361 | if (privateDicts[0].blueFuzz != 1) { |
362 | buf = GooString::format(fmt: "/BlueFuzz {0:d} def\n" , privateDicts[0].blueFuzz); |
363 | eexecWrite(eb: &eb, s: buf->c_str()); |
364 | } |
365 | if (privateDicts[0].hasStdHW) { |
366 | buf = GooString::format(fmt: "/StdHW [{0:.4g}] def\n" , privateDicts[0].stdHW); |
367 | eexecWrite(eb: &eb, s: buf->c_str()); |
368 | } |
369 | if (privateDicts[0].hasStdVW) { |
370 | buf = GooString::format(fmt: "/StdVW [{0:.4g}] def\n" , privateDicts[0].stdVW); |
371 | eexecWrite(eb: &eb, s: buf->c_str()); |
372 | } |
373 | if (privateDicts[0].nStemSnapH) { |
374 | eexecWrite(eb: &eb, s: "/StemSnapH [" ); |
375 | for (i = 0; i < privateDicts[0].nStemSnapH; ++i) { |
376 | buf = GooString::format(fmt: "{0:s}{1:.4g}" , i > 0 ? " " : "" , privateDicts[0].stemSnapH[i]); |
377 | eexecWrite(eb: &eb, s: buf->c_str()); |
378 | } |
379 | eexecWrite(eb: &eb, s: "] def\n" ); |
380 | } |
381 | if (privateDicts[0].nStemSnapV) { |
382 | eexecWrite(eb: &eb, s: "/StemSnapV [" ); |
383 | for (i = 0; i < privateDicts[0].nStemSnapV; ++i) { |
384 | buf = GooString::format(fmt: "{0:s}{1:.4g}" , i > 0 ? " " : "" , privateDicts[0].stemSnapV[i]); |
385 | eexecWrite(eb: &eb, s: buf->c_str()); |
386 | } |
387 | eexecWrite(eb: &eb, s: "] def\n" ); |
388 | } |
389 | if (privateDicts[0].hasForceBold) { |
390 | buf = GooString::format(fmt: "/ForceBold {0:s} def\n" , privateDicts[0].forceBold ? "true" : "false" ); |
391 | eexecWrite(eb: &eb, s: buf->c_str()); |
392 | } |
393 | if (privateDicts[0].forceBoldThreshold != 0) { |
394 | buf = GooString::format(fmt: "/ForceBoldThreshold {0:.4g} def\n" , privateDicts[0].forceBoldThreshold); |
395 | eexecWrite(eb: &eb, s: buf->c_str()); |
396 | } |
397 | if (privateDicts[0].languageGroup != 0) { |
398 | buf = GooString::format(fmt: "/LanguageGroup {0:d} def\n" , privateDicts[0].languageGroup); |
399 | eexecWrite(eb: &eb, s: buf->c_str()); |
400 | } |
401 | if (privateDicts[0].expansionFactor != 0.06) { |
402 | buf = GooString::format(fmt: "/ExpansionFactor {0:.4g} def\n" , privateDicts[0].expansionFactor); |
403 | eexecWrite(eb: &eb, s: buf->c_str()); |
404 | } |
405 | |
406 | // set up subroutines |
407 | ok = true; |
408 | getIndex(pos: privateDicts[0].subrsOffset, idx: &subrIdx, ok: &ok); |
409 | if (!ok) { |
410 | subrIdx.pos = -1; |
411 | } |
412 | |
413 | // write the CharStrings |
414 | buf = GooString::format(fmt: "2 index /CharStrings {0:d} dict dup begin\n" , nGlyphs); |
415 | eexecWrite(eb: &eb, s: buf->c_str()); |
416 | for (i = 0; i < nGlyphs; ++i) { |
417 | ok = true; |
418 | getIndexVal(idx: &charStringsIdx, i, val: &val, ok: &ok); |
419 | if (ok && i < charsetLength) { |
420 | getString(sid: charset[i], buf: buf2, ok: &ok); |
421 | if (ok) { |
422 | eexecCvtGlyph(eb: &eb, glyphName: buf2, offset: val.pos, nBytes: val.len, subrIdx: &subrIdx, pDict: &privateDicts[0]); |
423 | } |
424 | } |
425 | } |
426 | eexecWrite(eb: &eb, s: "end\n" ); |
427 | eexecWrite(eb: &eb, s: "end\n" ); |
428 | eexecWrite(eb: &eb, s: "readonly put\n" ); |
429 | eexecWrite(eb: &eb, s: "noaccess put\n" ); |
430 | eexecWrite(eb: &eb, s: "dup /FontName get exch definefont pop\n" ); |
431 | eexecWrite(eb: &eb, s: "mark currentfile closefile\n" ); |
432 | |
433 | // trailer |
434 | if (ascii && eb.line > 0) { |
435 | (*outputFunc)(outputStream, "\n" , 1); |
436 | } |
437 | for (i = 0; i < 8; ++i) { |
438 | (*outputFunc)(outputStream, "0000000000000000000000000000000000000000000000000000000000000000\n" , 65); |
439 | } |
440 | (*outputFunc)(outputStream, "cleartomark\n" , 12); |
441 | } |
442 | |
443 | void FoFiType1C::convertToCIDType0(const char *psName, const int *codeMap, int nCodes, FoFiOutputFunc outputFunc, void *outputStream) |
444 | { |
445 | int *cidMap; |
446 | GooString *charStrings; |
447 | int *charStringOffsets; |
448 | Type1CIndex subrIdx; |
449 | Type1CIndexVal val; |
450 | int nCIDs, gdBytes; |
451 | char buf2[256]; |
452 | bool ok; |
453 | int gid, offset, n, i, j, k; |
454 | |
455 | // compute the CID count and build the CID-to-GID mapping |
456 | if (codeMap) { |
457 | nCIDs = nCodes; |
458 | cidMap = (int *)gmallocn(count: nCIDs, size: sizeof(int)); |
459 | for (i = 0; i < nCodes; ++i) { |
460 | if (codeMap[i] >= 0 && codeMap[i] < nGlyphs) { |
461 | cidMap[i] = codeMap[i]; |
462 | } else { |
463 | cidMap[i] = -1; |
464 | } |
465 | } |
466 | } else if (topDict.firstOp == 0x0c1e) { |
467 | nCIDs = 0; |
468 | for (i = 0; i < nGlyphs && i < charsetLength; ++i) { |
469 | if (charset[i] >= nCIDs) { |
470 | nCIDs = charset[i] + 1; |
471 | } |
472 | } |
473 | cidMap = (int *)gmallocn(count: nCIDs, size: sizeof(int)); |
474 | for (i = 0; i < nCIDs; ++i) { |
475 | cidMap[i] = -1; |
476 | } |
477 | for (i = 0; i < nGlyphs && i < charsetLength; ++i) { |
478 | cidMap[charset[i]] = i; |
479 | } |
480 | } else { |
481 | nCIDs = nGlyphs; |
482 | cidMap = (int *)gmallocn(count: nCIDs, size: sizeof(int)); |
483 | for (i = 0; i < nCIDs; ++i) { |
484 | cidMap[i] = i; |
485 | } |
486 | } |
487 | |
488 | // build the charstrings |
489 | charStrings = new GooString(); |
490 | charStringOffsets = (int *)gmallocn(count: nCIDs + 1, size: sizeof(int)); |
491 | for (i = 0; i < nCIDs; ++i) { |
492 | charStringOffsets[i] = charStrings->getLength(); |
493 | if ((gid = cidMap[i]) >= 0) { |
494 | ok = true; |
495 | getIndexVal(idx: &charStringsIdx, i: gid, val: &val, ok: &ok); |
496 | if (ok) { |
497 | getIndex(pos: privateDicts[fdSelect ? fdSelect[gid] : 0].subrsOffset, idx: &subrIdx, ok: &ok); |
498 | if (!ok) { |
499 | subrIdx.pos = -1; |
500 | } |
501 | std::set<int> offsetBeingParsed; |
502 | cvtGlyph(offset: val.pos, nBytes: val.len, charBuf: charStrings, subrIdx: &subrIdx, pDict: &privateDicts[fdSelect ? fdSelect[gid] : 0], top: true, offsetBeingParsed); |
503 | } |
504 | } |
505 | } |
506 | charStringOffsets[nCIDs] = charStrings->getLength(); |
507 | |
508 | // compute gdBytes = number of bytes needed for charstring offsets |
509 | // (offset size needs to account for the charstring offset table, |
510 | // with a worst case of five bytes per entry, plus the charstrings |
511 | // themselves) |
512 | i = (nCIDs + 1) * 5 + charStrings->getLength(); |
513 | if (i < 0x100) { |
514 | gdBytes = 1; |
515 | } else if (i < 0x10000) { |
516 | gdBytes = 2; |
517 | } else if (i < 0x1000000) { |
518 | gdBytes = 3; |
519 | } else { |
520 | gdBytes = 4; |
521 | } |
522 | |
523 | // begin the font dictionary |
524 | (*outputFunc)(outputStream, "/CIDInit /ProcSet findresource begin\n" , 37); |
525 | (*outputFunc)(outputStream, "20 dict begin\n" , 14); |
526 | (*outputFunc)(outputStream, "/CIDFontName /" , 14); |
527 | (*outputFunc)(outputStream, psName, strlen(s: psName)); |
528 | (*outputFunc)(outputStream, " def\n" , 5); |
529 | (*outputFunc)(outputStream, "/CIDFontType 0 def\n" , 19); |
530 | (*outputFunc)(outputStream, "/CIDSystemInfo 3 dict dup begin\n" , 32); |
531 | if (topDict.registrySID > 0 && topDict.orderingSID > 0) { |
532 | ok = true; |
533 | getString(sid: topDict.registrySID, buf: buf2, ok: &ok); |
534 | if (ok) { |
535 | (*outputFunc)(outputStream, " /Registry (" , 13); |
536 | (*outputFunc)(outputStream, buf2, strlen(s: buf2)); |
537 | (*outputFunc)(outputStream, ") def\n" , 6); |
538 | } |
539 | ok = true; |
540 | getString(sid: topDict.orderingSID, buf: buf2, ok: &ok); |
541 | if (ok) { |
542 | (*outputFunc)(outputStream, " /Ordering (" , 13); |
543 | (*outputFunc)(outputStream, buf2, strlen(s: buf2)); |
544 | (*outputFunc)(outputStream, ") def\n" , 6); |
545 | } |
546 | } else { |
547 | (*outputFunc)(outputStream, " /Registry (Adobe) def\n" , 24); |
548 | (*outputFunc)(outputStream, " /Ordering (Identity) def\n" , 27); |
549 | } |
550 | std::unique_ptr<GooString> buf = GooString::format(fmt: " /Supplement {0:d} def\n" , topDict.supplement); |
551 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
552 | (*outputFunc)(outputStream, "end def\n" , 8); |
553 | if (topDict.hasFontMatrix) { |
554 | buf = GooString::format(fmt: "/FontMatrix [{0:.8g} {1:.8g} {2:.8g} {3:.8g} {4:.8g} {5:.8g}] def\n" , topDict.fontMatrix[0], topDict.fontMatrix[1], topDict.fontMatrix[2], topDict.fontMatrix[3], topDict.fontMatrix[4], |
555 | topDict.fontMatrix[5]); |
556 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
557 | } else if (privateDicts[0].hasFontMatrix) { |
558 | (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n" , 30); |
559 | } else { |
560 | (*outputFunc)(outputStream, "/FontMatrix [0.001 0 0 0.001 0 0] def\n" , 38); |
561 | } |
562 | buf = GooString::format(fmt: "/FontBBox [{0:.4g} {1:.4g} {2:.4g} {3:.4g}] def\n" , topDict.fontBBox[0], topDict.fontBBox[1], topDict.fontBBox[2], topDict.fontBBox[3]); |
563 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
564 | (*outputFunc)(outputStream, "/FontInfo 1 dict dup begin\n" , 27); |
565 | (*outputFunc)(outputStream, " /FSType 8 def\n" , 16); |
566 | (*outputFunc)(outputStream, "end def\n" , 8); |
567 | |
568 | // CIDFont-specific entries |
569 | buf = GooString::format(fmt: "/CIDCount {0:d} def\n" , nCIDs); |
570 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
571 | (*outputFunc)(outputStream, "/FDBytes 1 def\n" , 15); |
572 | buf = GooString::format(fmt: "/GDBytes {0:d} def\n" , gdBytes); |
573 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
574 | (*outputFunc)(outputStream, "/CIDMapOffset 0 def\n" , 20); |
575 | if (topDict.paintType != 0) { |
576 | buf = GooString::format(fmt: "/PaintType {0:d} def\n" , topDict.paintType); |
577 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
578 | buf = GooString::format(fmt: "/StrokeWidth {0:.4g} def\n" , topDict.strokeWidth); |
579 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
580 | } |
581 | |
582 | // FDArray entry |
583 | buf = GooString::format(fmt: "/FDArray {0:d} array\n" , nFDs); |
584 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
585 | for (i = 0; i < nFDs; ++i) { |
586 | buf = GooString::format(fmt: "dup {0:d} 10 dict begin\n" , i); |
587 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
588 | (*outputFunc)(outputStream, "/FontType 1 def\n" , 16); |
589 | if (privateDicts[i].hasFontMatrix) { |
590 | buf = GooString::format(fmt: "/FontMatrix [{0:.8g} {1:.8g} {2:.8g} {3:.8g} {4:.8g} {5:.8g}] def\n" , privateDicts[i].fontMatrix[0], privateDicts[i].fontMatrix[1], privateDicts[i].fontMatrix[2], privateDicts[i].fontMatrix[3], |
591 | privateDicts[i].fontMatrix[4], privateDicts[i].fontMatrix[5]); |
592 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
593 | } else { |
594 | (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n" , 30); |
595 | } |
596 | buf = GooString::format(fmt: "/PaintType {0:d} def\n" , topDict.paintType); |
597 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
598 | (*outputFunc)(outputStream, "/Private 32 dict begin\n" , 23); |
599 | if (privateDicts[i].nBlueValues) { |
600 | (*outputFunc)(outputStream, "/BlueValues [" , 13); |
601 | for (j = 0; j < privateDicts[i].nBlueValues; ++j) { |
602 | buf = GooString::format(fmt: "{0:s}{1:d}" , j > 0 ? " " : "" , privateDicts[i].blueValues[j]); |
603 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
604 | } |
605 | (*outputFunc)(outputStream, "] def\n" , 6); |
606 | } |
607 | if (privateDicts[i].nOtherBlues) { |
608 | (*outputFunc)(outputStream, "/OtherBlues [" , 13); |
609 | for (j = 0; j < privateDicts[i].nOtherBlues; ++j) { |
610 | buf = GooString::format(fmt: "{0:s}{1:d}" , j > 0 ? " " : "" , privateDicts[i].otherBlues[j]); |
611 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
612 | } |
613 | (*outputFunc)(outputStream, "] def\n" , 6); |
614 | } |
615 | if (privateDicts[i].nFamilyBlues) { |
616 | (*outputFunc)(outputStream, "/FamilyBlues [" , 14); |
617 | for (j = 0; j < privateDicts[i].nFamilyBlues; ++j) { |
618 | buf = GooString::format(fmt: "{0:s}{1:d}" , j > 0 ? " " : "" , privateDicts[i].familyBlues[j]); |
619 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
620 | } |
621 | (*outputFunc)(outputStream, "] def\n" , 6); |
622 | } |
623 | if (privateDicts[i].nFamilyOtherBlues) { |
624 | (*outputFunc)(outputStream, "/FamilyOtherBlues [" , 19); |
625 | for (j = 0; j < privateDicts[i].nFamilyOtherBlues; ++j) { |
626 | buf = GooString::format(fmt: "{0:s}{1:d}" , j > 0 ? " " : "" , privateDicts[i].familyOtherBlues[j]); |
627 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
628 | } |
629 | (*outputFunc)(outputStream, "] def\n" , 6); |
630 | } |
631 | if (privateDicts[i].blueScale != 0.039625) { |
632 | buf = GooString::format(fmt: "/BlueScale {0:.4g} def\n" , privateDicts[i].blueScale); |
633 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
634 | } |
635 | if (privateDicts[i].blueShift != 7) { |
636 | buf = GooString::format(fmt: "/BlueShift {0:d} def\n" , privateDicts[i].blueShift); |
637 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
638 | } |
639 | if (privateDicts[i].blueFuzz != 1) { |
640 | buf = GooString::format(fmt: "/BlueFuzz {0:d} def\n" , privateDicts[i].blueFuzz); |
641 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
642 | } |
643 | if (privateDicts[i].hasStdHW) { |
644 | buf = GooString::format(fmt: "/StdHW [{0:.4g}] def\n" , privateDicts[i].stdHW); |
645 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
646 | } |
647 | if (privateDicts[i].hasStdVW) { |
648 | buf = GooString::format(fmt: "/StdVW [{0:.4g}] def\n" , privateDicts[i].stdVW); |
649 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
650 | } |
651 | if (privateDicts[i].nStemSnapH) { |
652 | (*outputFunc)(outputStream, "/StemSnapH [" , 12); |
653 | for (j = 0; j < privateDicts[i].nStemSnapH; ++j) { |
654 | buf = GooString::format(fmt: "{0:s}{1:.4g}" , j > 0 ? " " : "" , privateDicts[i].stemSnapH[j]); |
655 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
656 | } |
657 | (*outputFunc)(outputStream, "] def\n" , 6); |
658 | } |
659 | if (privateDicts[i].nStemSnapV) { |
660 | (*outputFunc)(outputStream, "/StemSnapV [" , 12); |
661 | for (j = 0; j < privateDicts[i].nStemSnapV; ++j) { |
662 | buf = GooString::format(fmt: "{0:s}{1:.4g}" , j > 0 ? " " : "" , privateDicts[i].stemSnapV[j]); |
663 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
664 | } |
665 | (*outputFunc)(outputStream, "] def\n" , 6); |
666 | } |
667 | if (privateDicts[i].hasForceBold) { |
668 | buf = GooString::format(fmt: "/ForceBold {0:s} def\n" , privateDicts[i].forceBold ? "true" : "false" ); |
669 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
670 | } |
671 | if (privateDicts[i].forceBoldThreshold != 0) { |
672 | buf = GooString::format(fmt: "/ForceBoldThreshold {0:.4g} def\n" , privateDicts[i].forceBoldThreshold); |
673 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
674 | } |
675 | if (privateDicts[i].languageGroup != 0) { |
676 | buf = GooString::format(fmt: "/LanguageGroup {0:d} def\n" , privateDicts[i].languageGroup); |
677 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
678 | } |
679 | if (privateDicts[i].expansionFactor != 0.06) { |
680 | buf = GooString::format(fmt: "/ExpansionFactor {0:.4g} def\n" , privateDicts[i].expansionFactor); |
681 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
682 | } |
683 | (*outputFunc)(outputStream, "currentdict end def\n" , 20); |
684 | (*outputFunc)(outputStream, "currentdict end put\n" , 20); |
685 | } |
686 | (*outputFunc)(outputStream, "def\n" , 4); |
687 | |
688 | // start the binary section |
689 | offset = (nCIDs + 1) * (1 + gdBytes); |
690 | buf = GooString::format(fmt: "(Hex) {0:d} StartData\n" , offset + charStrings->getLength()); |
691 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
692 | |
693 | // write the charstring offset (CIDMap) table |
694 | for (i = 0; i <= nCIDs; i += 6) { |
695 | for (j = 0; j < 6 && i + j <= nCIDs; ++j) { |
696 | if (i + j < nCIDs && cidMap[i + j] >= 0 && fdSelect) { |
697 | buf2[0] = (char)fdSelect[cidMap[i + j]]; |
698 | } else { |
699 | buf2[0] = (char)0; |
700 | } |
701 | n = offset + charStringOffsets[i + j]; |
702 | for (k = gdBytes; k >= 1; --k) { |
703 | buf2[k] = (char)(n & 0xff); |
704 | n >>= 8; |
705 | } |
706 | for (k = 0; k <= gdBytes; ++k) { |
707 | buf = GooString::format(fmt: "{0:02x}" , buf2[k] & 0xff); |
708 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
709 | } |
710 | } |
711 | (*outputFunc)(outputStream, "\n" , 1); |
712 | } |
713 | |
714 | // write the charstring data |
715 | n = charStrings->getLength(); |
716 | for (i = 0; i < n; i += 32) { |
717 | for (j = 0; j < 32 && i + j < n; ++j) { |
718 | buf = GooString::format(fmt: "{0:02x}" , charStrings->getChar(i: i + j) & 0xff); |
719 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
720 | } |
721 | if (i + 32 >= n) { |
722 | (*outputFunc)(outputStream, ">" , 1); |
723 | } |
724 | (*outputFunc)(outputStream, "\n" , 1); |
725 | } |
726 | |
727 | gfree(p: charStringOffsets); |
728 | delete charStrings; |
729 | gfree(p: cidMap); |
730 | } |
731 | |
732 | void FoFiType1C::convertToType0(const char *psName, const int *codeMap, int nCodes, FoFiOutputFunc outputFunc, void *outputStream) |
733 | { |
734 | int *cidMap; |
735 | Type1CIndex subrIdx; |
736 | Type1CIndexVal val; |
737 | int nCIDs; |
738 | Type1CEexecBuf eb; |
739 | bool ok; |
740 | int fd, i, j, k; |
741 | |
742 | // compute the CID count and build the CID-to-GID mapping |
743 | if (codeMap) { |
744 | nCIDs = nCodes; |
745 | cidMap = (int *)gmallocn(count: nCIDs, size: sizeof(int)); |
746 | for (i = 0; i < nCodes; ++i) { |
747 | if (codeMap[i] >= 0 && codeMap[i] < nGlyphs) { |
748 | cidMap[i] = codeMap[i]; |
749 | } else { |
750 | cidMap[i] = -1; |
751 | } |
752 | } |
753 | } else if (topDict.firstOp == 0x0c1e) { |
754 | nCIDs = 0; |
755 | for (i = 0; i < nGlyphs && i < charsetLength; ++i) { |
756 | if (charset[i] >= nCIDs) { |
757 | nCIDs = charset[i] + 1; |
758 | } |
759 | } |
760 | cidMap = (int *)gmallocn(count: nCIDs, size: sizeof(int)); |
761 | for (i = 0; i < nCIDs; ++i) { |
762 | cidMap[i] = -1; |
763 | } |
764 | for (i = 0; i < nGlyphs && i < charsetLength; ++i) { |
765 | cidMap[charset[i]] = i; |
766 | } |
767 | } else { |
768 | nCIDs = nGlyphs; |
769 | cidMap = (int *)gmallocn(count: nCIDs, size: sizeof(int)); |
770 | for (i = 0; i < nCIDs; ++i) { |
771 | cidMap[i] = i; |
772 | } |
773 | } |
774 | |
775 | if (privateDicts) { |
776 | // write the descendant Type 1 fonts |
777 | for (i = 0; i < nCIDs; i += 256) { |
778 | |
779 | //~ this assumes that all CIDs in this block have the same FD -- |
780 | //~ to handle multiple FDs correctly, need to somehow divide the |
781 | //~ font up by FD; as a kludge we ignore CID 0, which is .notdef |
782 | fd = 0; |
783 | // if fdSelect is NULL, we have an 8-bit font, so just leave fd=0 |
784 | if (fdSelect) { |
785 | for (j = i == 0 ? 1 : 0; j < 256 && i + j < nCIDs; ++j) { |
786 | if (cidMap[i + j] >= 0) { |
787 | fd = fdSelect[cidMap[i + j]]; |
788 | break; |
789 | } |
790 | } |
791 | } |
792 | |
793 | if (fd >= nFDs) { |
794 | continue; |
795 | } |
796 | |
797 | // font dictionary (unencrypted section) |
798 | (*outputFunc)(outputStream, "16 dict begin\n" , 14); |
799 | (*outputFunc)(outputStream, "/FontName /" , 11); |
800 | (*outputFunc)(outputStream, psName, strlen(s: psName)); |
801 | std::unique_ptr<GooString> buf = GooString::format(fmt: "_{0:02x} def\n" , i >> 8); |
802 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
803 | (*outputFunc)(outputStream, "/FontType 1 def\n" , 16); |
804 | if (privateDicts[fd].hasFontMatrix) { |
805 | buf = GooString::format(fmt: "/FontMatrix [{0:.8g} {1:.8g} {2:.8g} {3:.8g} {4:.8g} {5:.8g}] def\n" , privateDicts[fd].fontMatrix[0], privateDicts[fd].fontMatrix[1], privateDicts[fd].fontMatrix[2], privateDicts[fd].fontMatrix[3], |
806 | privateDicts[fd].fontMatrix[4], privateDicts[fd].fontMatrix[5]); |
807 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
808 | } else if (topDict.hasFontMatrix) { |
809 | (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n" , 30); |
810 | } else { |
811 | (*outputFunc)(outputStream, "/FontMatrix [0.001 0 0 0.001 0 0] def\n" , 38); |
812 | } |
813 | buf = GooString::format(fmt: "/FontBBox [{0:.4g} {1:.4g} {2:.4g} {3:.4g}] def\n" , topDict.fontBBox[0], topDict.fontBBox[1], topDict.fontBBox[2], topDict.fontBBox[3]); |
814 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
815 | buf = GooString::format(fmt: "/PaintType {0:d} def\n" , topDict.paintType); |
816 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
817 | if (topDict.paintType != 0) { |
818 | buf = GooString::format(fmt: "/StrokeWidth {0:.4g} def\n" , topDict.strokeWidth); |
819 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
820 | } |
821 | (*outputFunc)(outputStream, "/Encoding 256 array\n" , 20); |
822 | for (j = 0; j < 256 && i + j < nCIDs; ++j) { |
823 | buf = GooString::format(fmt: "dup {0:d} /c{1:02x} put\n" , j, j); |
824 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
825 | } |
826 | if (j < 256) { |
827 | buf = GooString::format(fmt: "{0:d} 1 255 {{ 1 index exch /.notdef put }} for\n" , j); |
828 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
829 | } |
830 | (*outputFunc)(outputStream, "readonly def\n" , 13); |
831 | (*outputFunc)(outputStream, "currentdict end\n" , 16); |
832 | |
833 | // start the binary section |
834 | (*outputFunc)(outputStream, "currentfile eexec\n" , 18); |
835 | eb.outputFunc = outputFunc; |
836 | eb.outputStream = outputStream; |
837 | eb.ascii = true; |
838 | eb.r1 = 55665; |
839 | eb.line = 0; |
840 | |
841 | // start the private dictionary |
842 | eexecWrite(eb: &eb, s: "\x83\xca\x73\xd5" ); |
843 | eexecWrite(eb: &eb, s: "dup /Private 32 dict dup begin\n" ); |
844 | eexecWrite(eb: &eb, |
845 | s: "/RD {string currentfile exch readstring pop}" |
846 | " executeonly def\n" ); |
847 | eexecWrite(eb: &eb, s: "/ND {noaccess def} executeonly def\n" ); |
848 | eexecWrite(eb: &eb, s: "/NP {noaccess put} executeonly def\n" ); |
849 | eexecWrite(eb: &eb, s: "/MinFeature {16 16} def\n" ); |
850 | eexecWrite(eb: &eb, s: "/password 5839 def\n" ); |
851 | if (privateDicts[fd].nBlueValues) { |
852 | eexecWrite(eb: &eb, s: "/BlueValues [" ); |
853 | for (k = 0; k < privateDicts[fd].nBlueValues; ++k) { |
854 | buf = GooString::format(fmt: "{0:s}{1:d}" , k > 0 ? " " : "" , privateDicts[fd].blueValues[k]); |
855 | eexecWrite(eb: &eb, s: buf->c_str()); |
856 | } |
857 | eexecWrite(eb: &eb, s: "] def\n" ); |
858 | } |
859 | if (privateDicts[fd].nOtherBlues) { |
860 | eexecWrite(eb: &eb, s: "/OtherBlues [" ); |
861 | for (k = 0; k < privateDicts[fd].nOtherBlues; ++k) { |
862 | buf = GooString::format(fmt: "{0:s}{1:d}" , k > 0 ? " " : "" , privateDicts[fd].otherBlues[k]); |
863 | eexecWrite(eb: &eb, s: buf->c_str()); |
864 | } |
865 | eexecWrite(eb: &eb, s: "] def\n" ); |
866 | } |
867 | if (privateDicts[fd].nFamilyBlues) { |
868 | eexecWrite(eb: &eb, s: "/FamilyBlues [" ); |
869 | for (k = 0; k < privateDicts[fd].nFamilyBlues; ++k) { |
870 | buf = GooString::format(fmt: "{0:s}{1:d}" , k > 0 ? " " : "" , privateDicts[fd].familyBlues[k]); |
871 | eexecWrite(eb: &eb, s: buf->c_str()); |
872 | } |
873 | eexecWrite(eb: &eb, s: "] def\n" ); |
874 | } |
875 | if (privateDicts[fd].nFamilyOtherBlues) { |
876 | eexecWrite(eb: &eb, s: "/FamilyOtherBlues [" ); |
877 | for (k = 0; k < privateDicts[fd].nFamilyOtherBlues; ++k) { |
878 | buf = GooString::format(fmt: "{0:s}{1:d}" , k > 0 ? " " : "" , privateDicts[fd].familyOtherBlues[k]); |
879 | eexecWrite(eb: &eb, s: buf->c_str()); |
880 | } |
881 | eexecWrite(eb: &eb, s: "] def\n" ); |
882 | } |
883 | if (privateDicts[fd].blueScale != 0.039625) { |
884 | buf = GooString::format(fmt: "/BlueScale {0:.4g} def\n" , privateDicts[fd].blueScale); |
885 | eexecWrite(eb: &eb, s: buf->c_str()); |
886 | } |
887 | if (privateDicts[fd].blueShift != 7) { |
888 | buf = GooString::format(fmt: "/BlueShift {0:d} def\n" , privateDicts[fd].blueShift); |
889 | eexecWrite(eb: &eb, s: buf->c_str()); |
890 | } |
891 | if (privateDicts[fd].blueFuzz != 1) { |
892 | buf = GooString::format(fmt: "/BlueFuzz {0:d} def\n" , privateDicts[fd].blueFuzz); |
893 | eexecWrite(eb: &eb, s: buf->c_str()); |
894 | } |
895 | if (privateDicts[fd].hasStdHW) { |
896 | buf = GooString::format(fmt: "/StdHW [{0:.4g}] def\n" , privateDicts[fd].stdHW); |
897 | eexecWrite(eb: &eb, s: buf->c_str()); |
898 | } |
899 | if (privateDicts[fd].hasStdVW) { |
900 | buf = GooString::format(fmt: "/StdVW [{0:.4g}] def\n" , privateDicts[fd].stdVW); |
901 | eexecWrite(eb: &eb, s: buf->c_str()); |
902 | } |
903 | if (privateDicts[fd].nStemSnapH) { |
904 | eexecWrite(eb: &eb, s: "/StemSnapH [" ); |
905 | for (k = 0; k < privateDicts[fd].nStemSnapH; ++k) { |
906 | buf = GooString::format(fmt: "{0:s}{1:.4g}" , k > 0 ? " " : "" , privateDicts[fd].stemSnapH[k]); |
907 | eexecWrite(eb: &eb, s: buf->c_str()); |
908 | } |
909 | eexecWrite(eb: &eb, s: "] def\n" ); |
910 | } |
911 | if (privateDicts[fd].nStemSnapV) { |
912 | eexecWrite(eb: &eb, s: "/StemSnapV [" ); |
913 | for (k = 0; k < privateDicts[fd].nStemSnapV; ++k) { |
914 | buf = GooString::format(fmt: "{0:s}{1:.4g}" , k > 0 ? " " : "" , privateDicts[fd].stemSnapV[k]); |
915 | eexecWrite(eb: &eb, s: buf->c_str()); |
916 | } |
917 | eexecWrite(eb: &eb, s: "] def\n" ); |
918 | } |
919 | if (privateDicts[fd].hasForceBold) { |
920 | buf = GooString::format(fmt: "/ForceBold {0:s} def\n" , privateDicts[fd].forceBold ? "true" : "false" ); |
921 | eexecWrite(eb: &eb, s: buf->c_str()); |
922 | } |
923 | if (privateDicts[fd].forceBoldThreshold != 0) { |
924 | buf = GooString::format(fmt: "/ForceBoldThreshold {0:.4g} def\n" , privateDicts[fd].forceBoldThreshold); |
925 | eexecWrite(eb: &eb, s: buf->c_str()); |
926 | } |
927 | if (privateDicts[fd].languageGroup != 0) { |
928 | buf = GooString::format(fmt: "/LanguageGroup {0:d} def\n" , privateDicts[fd].languageGroup); |
929 | eexecWrite(eb: &eb, s: buf->c_str()); |
930 | } |
931 | if (privateDicts[fd].expansionFactor != 0.06) { |
932 | buf = GooString::format(fmt: "/ExpansionFactor {0:.4g} def\n" , privateDicts[fd].expansionFactor); |
933 | eexecWrite(eb: &eb, s: buf->c_str()); |
934 | } |
935 | |
936 | // set up the subroutines |
937 | ok = true; |
938 | getIndex(pos: privateDicts[fd].subrsOffset, idx: &subrIdx, ok: &ok); |
939 | if (!ok) { |
940 | subrIdx.pos = -1; |
941 | } |
942 | |
943 | // start the CharStrings |
944 | eexecWrite(eb: &eb, s: "2 index /CharStrings 256 dict dup begin\n" ); |
945 | |
946 | // write the .notdef CharString |
947 | ok = true; |
948 | getIndexVal(idx: &charStringsIdx, i: 0, val: &val, ok: &ok); |
949 | if (ok) { |
950 | eexecCvtGlyph(eb: &eb, glyphName: ".notdef" , offset: val.pos, nBytes: val.len, subrIdx: &subrIdx, pDict: &privateDicts[fd]); |
951 | } |
952 | |
953 | // write the CharStrings |
954 | for (j = 0; j < 256 && i + j < nCIDs; ++j) { |
955 | if (cidMap[i + j] >= 0) { |
956 | ok = true; |
957 | getIndexVal(idx: &charStringsIdx, i: cidMap[i + j], val: &val, ok: &ok); |
958 | if (ok) { |
959 | buf = GooString::format(fmt: "c{0:02x}" , j); |
960 | eexecCvtGlyph(eb: &eb, glyphName: buf->c_str(), offset: val.pos, nBytes: val.len, subrIdx: &subrIdx, pDict: &privateDicts[fd]); |
961 | } |
962 | } |
963 | } |
964 | eexecWrite(eb: &eb, s: "end\n" ); |
965 | eexecWrite(eb: &eb, s: "end\n" ); |
966 | eexecWrite(eb: &eb, s: "readonly put\n" ); |
967 | eexecWrite(eb: &eb, s: "noaccess put\n" ); |
968 | eexecWrite(eb: &eb, s: "dup /FontName get exch definefont pop\n" ); |
969 | eexecWrite(eb: &eb, s: "mark currentfile closefile\n" ); |
970 | |
971 | // trailer |
972 | if (eb.line > 0) { |
973 | (*outputFunc)(outputStream, "\n" , 1); |
974 | } |
975 | for (j = 0; j < 8; ++j) { |
976 | (*outputFunc)(outputStream, "0000000000000000000000000000000000000000000000000000000000000000\n" , 65); |
977 | } |
978 | (*outputFunc)(outputStream, "cleartomark\n" , 12); |
979 | } |
980 | } else { |
981 | error(category: errSyntaxError, pos: -1, msg: "FoFiType1C::convertToType0 without privateDicts" ); |
982 | } |
983 | |
984 | // write the Type 0 parent font |
985 | (*outputFunc)(outputStream, "16 dict begin\n" , 14); |
986 | (*outputFunc)(outputStream, "/FontName /" , 11); |
987 | (*outputFunc)(outputStream, psName, strlen(s: psName)); |
988 | (*outputFunc)(outputStream, " def\n" , 5); |
989 | (*outputFunc)(outputStream, "/FontType 0 def\n" , 16); |
990 | if (topDict.hasFontMatrix) { |
991 | const std::unique_ptr<GooString> buf = GooString::format(fmt: "/FontMatrix [{0:.8g} {1:.8g} {2:.8g} {3:.8g} {4:.8g} {5:.8g}] def\n" , topDict.fontMatrix[0], topDict.fontMatrix[1], topDict.fontMatrix[2], topDict.fontMatrix[3], |
992 | topDict.fontMatrix[4], topDict.fontMatrix[5]); |
993 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
994 | } else { |
995 | (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n" , 30); |
996 | } |
997 | (*outputFunc)(outputStream, "/FMapType 2 def\n" , 16); |
998 | (*outputFunc)(outputStream, "/Encoding [\n" , 12); |
999 | for (i = 0; i < nCIDs; i += 256) { |
1000 | const std::unique_ptr<GooString> buf = GooString::format(fmt: "{0:d}\n" , i >> 8); |
1001 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
1002 | } |
1003 | (*outputFunc)(outputStream, "] def\n" , 6); |
1004 | (*outputFunc)(outputStream, "/FDepVector [\n" , 14); |
1005 | for (i = 0; i < nCIDs; i += 256) { |
1006 | (*outputFunc)(outputStream, "/" , 1); |
1007 | (*outputFunc)(outputStream, psName, strlen(s: psName)); |
1008 | const std::unique_ptr<GooString> buf = GooString::format(fmt: "_{0:02x} findfont\n" , i >> 8); |
1009 | (*outputFunc)(outputStream, buf->c_str(), buf->getLength()); |
1010 | } |
1011 | (*outputFunc)(outputStream, "] def\n" , 6); |
1012 | (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n" , 40); |
1013 | |
1014 | gfree(p: cidMap); |
1015 | } |
1016 | |
1017 | void FoFiType1C::eexecCvtGlyph(Type1CEexecBuf *eb, const char *glyphName, int offset, int nBytes, const Type1CIndex *subrIdx, const Type1CPrivateDict *pDict) |
1018 | { |
1019 | GooString *charBuf; |
1020 | |
1021 | // generate the charstring |
1022 | charBuf = new GooString(); |
1023 | std::set<int> offsetBeingParsed; |
1024 | cvtGlyph(offset, nBytes, charBuf, subrIdx, pDict, top: true, offsetBeingParsed); |
1025 | |
1026 | const std::unique_ptr<GooString> buf = GooString::format(fmt: "/{0:s} {1:d} RD " , glyphName, charBuf->getLength()); |
1027 | eexecWrite(eb, s: buf->c_str()); |
1028 | eexecWriteCharstring(eb, s: (unsigned char *)charBuf->c_str(), n: charBuf->getLength()); |
1029 | eexecWrite(eb, s: " ND\n" ); |
1030 | |
1031 | delete charBuf; |
1032 | } |
1033 | |
1034 | void FoFiType1C::cvtGlyph(int offset, int nBytes, GooString *charBuf, const Type1CIndex *subrIdx, const Type1CPrivateDict *pDict, bool top, std::set<int> &offsetBeingParsed) |
1035 | { |
1036 | Type1CIndexVal val; |
1037 | bool ok, dFP; |
1038 | double d, dx, dy; |
1039 | unsigned short r2; |
1040 | unsigned char byte; |
1041 | int pos, subrBias, start, i, k; |
1042 | |
1043 | if (offsetBeingParsed.find(x: offset) != offsetBeingParsed.end()) { |
1044 | return; |
1045 | } |
1046 | |
1047 | auto offsetEmplaceResult = offsetBeingParsed.emplace(args&: offset); |
1048 | |
1049 | start = charBuf->getLength(); |
1050 | if (top) { |
1051 | charBuf->append(c: '\x49'); // 73; |
1052 | charBuf->append(c: '\x3A'); // 58; |
1053 | charBuf->append(c: '\x93'); // 147; |
1054 | charBuf->append(c: '\x86'); // 134; |
1055 | nOps = 0; |
1056 | nHints = 0; |
1057 | firstOp = true; |
1058 | openPath = false; |
1059 | } |
1060 | |
1061 | pos = offset; |
1062 | while (pos < offset + nBytes) { |
1063 | ok = true; |
1064 | pos = getOp(pos, charstring: true, ok: &ok); |
1065 | if (!ok) { |
1066 | break; |
1067 | } |
1068 | if (!ops[nOps - 1].isNum) { |
1069 | --nOps; // drop the operator |
1070 | switch (ops[nOps].op) { |
1071 | case 0x0001: // hstem |
1072 | if (firstOp) { |
1073 | cvtGlyphWidth(useOp: nOps & 1, charBuf, pDict); |
1074 | firstOp = false; |
1075 | } |
1076 | if (nOps & 1) { |
1077 | //~ error(-1, "Wrong number of args (%d) to Type 2 hstem", nOps); |
1078 | } |
1079 | d = 0; |
1080 | dFP = false; |
1081 | for (k = 0; k < nOps; k += 2) { |
1082 | // convert Type 2 edge hints (-20 or -21) to Type 1 ghost hints |
1083 | if (ops[k + 1].num < 0) { |
1084 | d += ops[k].num + ops[k + 1].num; |
1085 | dFP |= ops[k].isFP | ops[k + 1].isFP; |
1086 | cvtNum(x: d, isFP: dFP, charBuf); |
1087 | cvtNum(x: -ops[k + 1].num, isFP: ops[k + 1].isFP, charBuf); |
1088 | } else { |
1089 | d += ops[k].num; |
1090 | dFP |= ops[k].isFP; |
1091 | cvtNum(x: d, isFP: dFP, charBuf); |
1092 | cvtNum(x: ops[k + 1].num, isFP: ops[k + 1].isFP, charBuf); |
1093 | d += ops[k + 1].num; |
1094 | dFP |= ops[k + 1].isFP; |
1095 | } |
1096 | charBuf->append(c: (char)1); |
1097 | } |
1098 | nHints += nOps / 2; |
1099 | nOps = 0; |
1100 | break; |
1101 | case 0x0003: // vstem |
1102 | if (firstOp) { |
1103 | cvtGlyphWidth(useOp: nOps & 1, charBuf, pDict); |
1104 | firstOp = false; |
1105 | } |
1106 | if (nOps & 1) { |
1107 | //~ error(-1, "Wrong number of args (%d) to Type 2 vstem", nOps); |
1108 | } |
1109 | d = 0; |
1110 | dFP = false; |
1111 | for (k = 0; k < nOps; k += 2) { |
1112 | // convert Type 2 edge hints (-20 or -21) to Type 1 ghost hints |
1113 | if (ops[k + 1].num < 0) { |
1114 | d += ops[k].num + ops[k + 1].num; |
1115 | dFP |= ops[k].isFP | ops[k + 1].isFP; |
1116 | cvtNum(x: d, isFP: dFP, charBuf); |
1117 | cvtNum(x: -ops[k + 1].num, isFP: ops[k + 1].isFP, charBuf); |
1118 | } else { |
1119 | d += ops[k].num; |
1120 | dFP |= ops[k].isFP; |
1121 | cvtNum(x: d, isFP: dFP, charBuf); |
1122 | cvtNum(x: ops[k + 1].num, isFP: ops[k + 1].isFP, charBuf); |
1123 | d += ops[k + 1].num; |
1124 | dFP |= ops[k + 1].isFP; |
1125 | } |
1126 | charBuf->append(c: (char)3); |
1127 | } |
1128 | nHints += nOps / 2; |
1129 | nOps = 0; |
1130 | break; |
1131 | case 0x0004: // vmoveto |
1132 | if (firstOp) { |
1133 | cvtGlyphWidth(useOp: nOps == 2, charBuf, pDict); |
1134 | firstOp = false; |
1135 | } |
1136 | if (openPath) { |
1137 | charBuf->append(c: (char)9); |
1138 | openPath = false; |
1139 | } |
1140 | if (nOps != 1) { |
1141 | //~ error(-1, "Wrong number of args (%d) to Type 2 vmoveto", nOps); |
1142 | } |
1143 | cvtNum(x: ops[0].num, isFP: ops[0].isFP, charBuf); |
1144 | charBuf->append(c: (char)4); |
1145 | nOps = 0; |
1146 | break; |
1147 | case 0x0005: // rlineto |
1148 | if (nOps < 2 || nOps % 2 != 0) { |
1149 | //~ error(-1, "Wrong number of args (%d) to Type 2 rlineto", nOps); |
1150 | } |
1151 | for (k = 0; k < nOps; k += 2) { |
1152 | cvtNum(x: ops[k].num, isFP: ops[k].isFP, charBuf); |
1153 | cvtNum(x: ops[k + 1].num, isFP: ops[k + 1].isFP, charBuf); |
1154 | charBuf->append(c: (char)5); |
1155 | } |
1156 | nOps = 0; |
1157 | openPath = true; |
1158 | break; |
1159 | case 0x0006: // hlineto |
1160 | if (nOps < 1) { |
1161 | //~ error(-1, "Wrong number of args (%d) to Type 2 hlineto", nOps); |
1162 | } |
1163 | for (k = 0; k < nOps; ++k) { |
1164 | cvtNum(x: ops[k].num, isFP: ops[k].isFP, charBuf); |
1165 | charBuf->append(c: (char)((k & 1) ? 7 : 6)); |
1166 | } |
1167 | nOps = 0; |
1168 | openPath = true; |
1169 | break; |
1170 | case 0x0007: // vlineto |
1171 | if (nOps < 1) { |
1172 | //~ error(-1, "Wrong number of args (%d) to Type 2 vlineto", nOps); |
1173 | } |
1174 | for (k = 0; k < nOps; ++k) { |
1175 | cvtNum(x: ops[k].num, isFP: ops[k].isFP, charBuf); |
1176 | charBuf->append(c: (char)((k & 1) ? 6 : 7)); |
1177 | } |
1178 | nOps = 0; |
1179 | openPath = true; |
1180 | break; |
1181 | case 0x0008: // rrcurveto |
1182 | if (nOps < 6 || nOps % 6 != 0) { |
1183 | //~ error(-1, "Wrong number of args (%d) to Type 2 rrcurveto", nOps); |
1184 | } |
1185 | for (k = 0; k < nOps; k += 6) { |
1186 | cvtNum(x: ops[k].num, isFP: ops[k].isFP, charBuf); |
1187 | cvtNum(x: ops[k + 1].num, isFP: ops[k + 1].isFP, charBuf); |
1188 | cvtNum(x: ops[k + 2].num, isFP: ops[k + 2].isFP, charBuf); |
1189 | cvtNum(x: ops[k + 3].num, isFP: ops[k + 3].isFP, charBuf); |
1190 | cvtNum(x: ops[k + 4].num, isFP: ops[k + 4].isFP, charBuf); |
1191 | cvtNum(x: ops[k + 5].num, isFP: ops[k + 5].isFP, charBuf); |
1192 | charBuf->append(c: (char)8); |
1193 | } |
1194 | nOps = 0; |
1195 | openPath = true; |
1196 | break; |
1197 | case 0x000a: // callsubr |
1198 | if (nOps >= 1) { |
1199 | subrBias = (subrIdx->len < 1240) ? 107 : (subrIdx->len < 33900) ? 1131 : 32768; |
1200 | k = subrBias + (int)ops[nOps - 1].num; |
1201 | --nOps; |
1202 | ok = true; |
1203 | getIndexVal(idx: subrIdx, i: k, val: &val, ok: &ok); |
1204 | if (likely(ok && val.pos != offset)) { |
1205 | cvtGlyph(offset: val.pos, nBytes: val.len, charBuf, subrIdx, pDict, top: false, offsetBeingParsed); |
1206 | } |
1207 | } else { |
1208 | //~ error(-1, "Too few args to Type 2 callsubr"); |
1209 | } |
1210 | // don't clear the stack |
1211 | break; |
1212 | case 0x000b: // return |
1213 | // don't clear the stack |
1214 | break; |
1215 | case 0x000e: // endchar / seac |
1216 | if (firstOp) { |
1217 | cvtGlyphWidth(useOp: nOps == 1 || nOps == 5, charBuf, pDict); |
1218 | firstOp = false; |
1219 | } |
1220 | if (openPath) { |
1221 | charBuf->append(c: (char)9); |
1222 | openPath = false; |
1223 | } |
1224 | if (nOps == 4) { |
1225 | cvtNum(x: 0, isFP: false, charBuf); |
1226 | cvtNum(x: ops[0].num, isFP: ops[0].isFP, charBuf); |
1227 | cvtNum(x: ops[1].num, isFP: ops[1].isFP, charBuf); |
1228 | cvtNum(x: ops[2].num, isFP: ops[2].isFP, charBuf); |
1229 | cvtNum(x: ops[3].num, isFP: ops[3].isFP, charBuf); |
1230 | charBuf->append(c: (char)12)->append(c: (char)6); |
1231 | } else if (nOps == 0) { |
1232 | charBuf->append(c: (char)14); |
1233 | } else { |
1234 | //~ error(-1, "Wrong number of args (%d) to Type 2 endchar", nOps); |
1235 | } |
1236 | nOps = 0; |
1237 | break; |
1238 | case 0x000f: // (obsolete) |
1239 | // this op is ignored, but we need the glyph width |
1240 | if (firstOp) { |
1241 | cvtGlyphWidth(useOp: nOps > 0, charBuf, pDict); |
1242 | firstOp = false; |
1243 | } |
1244 | nOps = 0; |
1245 | break; |
1246 | case 0x0010: // blend |
1247 | //~ error(-1, "Unimplemented Type 2 charstring op: %d", file[i]); |
1248 | nOps = 0; |
1249 | break; |
1250 | case 0x0012: // hstemhm |
1251 | // ignored |
1252 | if (firstOp) { |
1253 | cvtGlyphWidth(useOp: nOps & 1, charBuf, pDict); |
1254 | firstOp = false; |
1255 | } |
1256 | if (nOps & 1) { |
1257 | //~ error(-1, "Wrong number of args (%d) to Type 2 hstemhm", nOps); |
1258 | } |
1259 | nHints += nOps / 2; |
1260 | nOps = 0; |
1261 | break; |
1262 | case 0x0013: // hintmask |
1263 | // ignored |
1264 | if (firstOp) { |
1265 | cvtGlyphWidth(useOp: nOps & 1, charBuf, pDict); |
1266 | firstOp = false; |
1267 | } |
1268 | if (nOps > 0) { |
1269 | if (nOps & 1) { |
1270 | //~ error(-1, "Wrong number of args (%d) to Type 2 hintmask/vstemhm", |
1271 | //~ nOps); |
1272 | } |
1273 | nHints += nOps / 2; |
1274 | } |
1275 | pos += (nHints + 7) >> 3; |
1276 | nOps = 0; |
1277 | break; |
1278 | case 0x0014: // cntrmask |
1279 | // ignored |
1280 | if (firstOp) { |
1281 | cvtGlyphWidth(useOp: nOps & 1, charBuf, pDict); |
1282 | firstOp = false; |
1283 | } |
1284 | if (nOps > 0) { |
1285 | if (nOps & 1) { |
1286 | //~ error(-1, "Wrong number of args (%d) to Type 2 cntrmask/vstemhm", |
1287 | //~ nOps); |
1288 | } |
1289 | nHints += nOps / 2; |
1290 | } |
1291 | pos += (nHints + 7) >> 3; |
1292 | nOps = 0; |
1293 | break; |
1294 | case 0x0015: // rmoveto |
1295 | if (firstOp) { |
1296 | cvtGlyphWidth(useOp: nOps == 3, charBuf, pDict); |
1297 | firstOp = false; |
1298 | } |
1299 | if (openPath) { |
1300 | charBuf->append(c: (char)9); |
1301 | openPath = false; |
1302 | } |
1303 | if (nOps != 2) { |
1304 | //~ error(-1, "Wrong number of args (%d) to Type 2 rmoveto", nOps); |
1305 | } |
1306 | cvtNum(x: ops[0].num, isFP: ops[0].isFP, charBuf); |
1307 | cvtNum(x: ops[1].num, isFP: ops[1].isFP, charBuf); |
1308 | charBuf->append(c: (char)21); |
1309 | nOps = 0; |
1310 | break; |
1311 | case 0x0016: // hmoveto |
1312 | if (firstOp) { |
1313 | cvtGlyphWidth(useOp: nOps == 2, charBuf, pDict); |
1314 | firstOp = false; |
1315 | } |
1316 | if (openPath) { |
1317 | charBuf->append(c: (char)9); |
1318 | openPath = false; |
1319 | } |
1320 | if (nOps != 1) { |
1321 | //~ error(-1, "Wrong number of args (%d) to Type 2 hmoveto", nOps); |
1322 | } |
1323 | cvtNum(x: ops[0].num, isFP: ops[0].isFP, charBuf); |
1324 | charBuf->append(c: (char)22); |
1325 | nOps = 0; |
1326 | break; |
1327 | case 0x0017: // vstemhm |
1328 | // ignored |
1329 | if (firstOp) { |
1330 | cvtGlyphWidth(useOp: nOps & 1, charBuf, pDict); |
1331 | firstOp = false; |
1332 | } |
1333 | if (nOps & 1) { |
1334 | //~ error(-1, "Wrong number of args (%d) to Type 2 vstemhm", nOps); |
1335 | } |
1336 | nHints += nOps / 2; |
1337 | nOps = 0; |
1338 | break; |
1339 | case 0x0018: // rcurveline |
1340 | if (nOps < 8 || (nOps - 2) % 6 != 0) { |
1341 | //~ error(-1, "Wrong number of args (%d) to Type 2 rcurveline", nOps); |
1342 | } |
1343 | for (k = 0; k < nOps - 2; k += 6) { |
1344 | cvtNum(x: ops[k].num, isFP: ops[k].isFP, charBuf); |
1345 | cvtNum(x: ops[k + 1].num, isFP: ops[k + 1].isFP, charBuf); |
1346 | cvtNum(x: ops[k + 2].num, isFP: ops[k + 2].isFP, charBuf); |
1347 | cvtNum(x: ops[k + 3].num, isFP: ops[k + 3].isFP, charBuf); |
1348 | cvtNum(x: ops[k + 4].num, isFP: ops[k + 4].isFP, charBuf); |
1349 | cvtNum(x: ops[k + 5].num, isFP: ops[k + 5].isFP, charBuf); |
1350 | charBuf->append(c: (char)8); |
1351 | } |
1352 | if (likely(k + 1 < nOps)) { |
1353 | cvtNum(x: ops[k].num, isFP: ops[k].isFP, charBuf); |
1354 | cvtNum(x: ops[k + 1].num, isFP: ops[k + 1].isFP, charBuf); |
1355 | charBuf->append(c: (char)5); |
1356 | } |
1357 | nOps = 0; |
1358 | openPath = true; |
1359 | break; |
1360 | case 0x0019: // rlinecurve |
1361 | if (nOps < 8 || (nOps - 6) % 2 != 0) { |
1362 | //~ error(-1, "Wrong number of args (%d) to Type 2 rlinecurve", nOps); |
1363 | } |
1364 | for (k = 0; k < nOps - 6; k += 2) { |
1365 | cvtNum(x: ops[k].num, isFP: ops[k].isFP, charBuf); |
1366 | cvtNum(x: ops[k + 1].num, isFP: ops[k + 1].isFP, charBuf); |
1367 | charBuf->append(c: (char)5); |
1368 | } |
1369 | cvtNum(x: ops[k].num, isFP: ops[k].isFP, charBuf); |
1370 | cvtNum(x: ops[k + 1].num, isFP: ops[k + 1].isFP, charBuf); |
1371 | cvtNum(x: ops[k + 2].num, isFP: ops[k + 2].isFP, charBuf); |
1372 | cvtNum(x: ops[k + 3].num, isFP: ops[k + 3].isFP, charBuf); |
1373 | cvtNum(x: ops[k + 4].num, isFP: ops[k + 4].isFP, charBuf); |
1374 | cvtNum(x: ops[k + 5].num, isFP: ops[k + 5].isFP, charBuf); |
1375 | charBuf->append(c: (char)8); |
1376 | nOps = 0; |
1377 | openPath = true; |
1378 | break; |
1379 | case 0x001a: // vvcurveto |
1380 | if (nOps < 4 || !(nOps % 4 == 0 || (nOps - 1) % 4 == 0)) { |
1381 | //~ error(-1, "Wrong number of args (%d) to Type 2 vvcurveto", nOps); |
1382 | } |
1383 | if (nOps % 2 == 1) { |
1384 | cvtNum(x: ops[0].num, isFP: ops[0].isFP, charBuf); |
1385 | cvtNum(x: ops[1].num, isFP: ops[1].isFP, charBuf); |
1386 | cvtNum(x: ops[2].num, isFP: ops[2].isFP, charBuf); |
1387 | cvtNum(x: ops[3].num, isFP: ops[3].isFP, charBuf); |
1388 | cvtNum(x: 0, isFP: false, charBuf); |
1389 | cvtNum(x: ops[4].num, isFP: ops[4].isFP, charBuf); |
1390 | charBuf->append(c: (char)8); |
1391 | k = 5; |
1392 | } else { |
1393 | k = 0; |
1394 | } |
1395 | for (; k < nOps; k += 4) { |
1396 | cvtNum(x: 0, isFP: false, charBuf); |
1397 | cvtNum(x: ops[k].num, isFP: ops[k].isFP, charBuf); |
1398 | cvtNum(x: ops[k + 1].num, isFP: ops[k + 1].isFP, charBuf); |
1399 | cvtNum(x: ops[k + 2].num, isFP: ops[k + 2].isFP, charBuf); |
1400 | cvtNum(x: 0, isFP: false, charBuf); |
1401 | cvtNum(x: ops[k + 3].num, isFP: ops[k + 3].isFP, charBuf); |
1402 | charBuf->append(c: (char)8); |
1403 | } |
1404 | nOps = 0; |
1405 | openPath = true; |
1406 | break; |
1407 | case 0x001b: // hhcurveto |
1408 | if (nOps < 4 || !(nOps % 4 == 0 || (nOps - 1) % 4 == 0)) { |
1409 | //~ error(-1, "Wrong number of args (%d) to Type 2 hhcurveto", nOps); |
1410 | } |
1411 | if (nOps % 2 == 1) { |
1412 | cvtNum(x: ops[1].num, isFP: ops[1].isFP, charBuf); |
1413 | cvtNum(x: ops[0].num, isFP: ops[0].isFP, charBuf); |
1414 | cvtNum(x: ops[2].num, isFP: ops[2].isFP, charBuf); |
1415 | cvtNum(x: ops[3].num, isFP: ops[3].isFP, charBuf); |
1416 | cvtNum(x: ops[4].num, isFP: ops[4].isFP, charBuf); |
1417 | cvtNum(x: 0, isFP: false, charBuf); |
1418 | charBuf->append(c: (char)8); |
1419 | k = 5; |
1420 | } else { |
1421 | k = 0; |
1422 | } |
1423 | for (; k < nOps; k += 4) { |
1424 | cvtNum(x: ops[k].num, isFP: ops[k].isFP, charBuf); |
1425 | cvtNum(x: 0, isFP: false, charBuf); |
1426 | cvtNum(x: ops[k + 1].num, isFP: ops[k + 1].isFP, charBuf); |
1427 | cvtNum(x: ops[k + 2].num, isFP: ops[k + 2].isFP, charBuf); |
1428 | cvtNum(x: ops[k + 3].num, isFP: ops[k + 3].isFP, charBuf); |
1429 | cvtNum(x: 0, isFP: false, charBuf); |
1430 | charBuf->append(c: (char)8); |
1431 | } |
1432 | nOps = 0; |
1433 | openPath = true; |
1434 | break; |
1435 | case 0x001d: // callgsubr |
1436 | if (nOps >= 1) { |
1437 | k = gsubrBias + (int)ops[nOps - 1].num; |
1438 | --nOps; |
1439 | ok = true; |
1440 | getIndexVal(idx: &gsubrIdx, i: k, val: &val, ok: &ok); |
1441 | if (likely(ok && val.pos != offset)) { |
1442 | cvtGlyph(offset: val.pos, nBytes: val.len, charBuf, subrIdx, pDict, top: false, offsetBeingParsed); |
1443 | } |
1444 | } else { |
1445 | //~ error(-1, "Too few args to Type 2 callgsubr"); |
1446 | } |
1447 | // don't clear the stack |
1448 | break; |
1449 | case 0x001e: // vhcurveto |
1450 | if (nOps < 4 || !(nOps % 4 == 0 || (nOps - 1) % 4 == 0)) { |
1451 | //~ error(-1, "Wrong number of args (%d) to Type 2 vhcurveto", nOps); |
1452 | } |
1453 | for (k = 0; k < nOps && k != nOps - 5; k += 4) { |
1454 | if (k % 8 == 0) { |
1455 | cvtNum(x: ops[k].num, isFP: ops[k].isFP, charBuf); |
1456 | cvtNum(x: ops[k + 1].num, isFP: ops[k + 1].isFP, charBuf); |
1457 | cvtNum(x: ops[k + 2].num, isFP: ops[k + 2].isFP, charBuf); |
1458 | cvtNum(x: ops[k + 3].num, isFP: ops[k + 3].isFP, charBuf); |
1459 | charBuf->append(c: (char)30); |
1460 | } else { |
1461 | cvtNum(x: ops[k].num, isFP: ops[k].isFP, charBuf); |
1462 | cvtNum(x: ops[k + 1].num, isFP: ops[k + 1].isFP, charBuf); |
1463 | cvtNum(x: ops[k + 2].num, isFP: ops[k + 2].isFP, charBuf); |
1464 | cvtNum(x: ops[k + 3].num, isFP: ops[k + 3].isFP, charBuf); |
1465 | charBuf->append(c: (char)31); |
1466 | } |
1467 | } |
1468 | if (k == nOps - 5) { |
1469 | if (k % 8 == 0) { |
1470 | cvtNum(x: 0, isFP: false, charBuf); |
1471 | cvtNum(x: ops[k].num, isFP: ops[k].isFP, charBuf); |
1472 | cvtNum(x: ops[k + 1].num, isFP: ops[k + 1].isFP, charBuf); |
1473 | cvtNum(x: ops[k + 2].num, isFP: ops[k + 2].isFP, charBuf); |
1474 | cvtNum(x: ops[k + 3].num, isFP: ops[k + 3].isFP, charBuf); |
1475 | cvtNum(x: ops[k + 4].num, isFP: ops[k + 4].isFP, charBuf); |
1476 | } else { |
1477 | cvtNum(x: ops[k].num, isFP: ops[k].isFP, charBuf); |
1478 | cvtNum(x: 0, isFP: false, charBuf); |
1479 | cvtNum(x: ops[k + 1].num, isFP: ops[k + 1].isFP, charBuf); |
1480 | cvtNum(x: ops[k + 2].num, isFP: ops[k + 2].isFP, charBuf); |
1481 | cvtNum(x: ops[k + 4].num, isFP: ops[k + 4].isFP, charBuf); |
1482 | cvtNum(x: ops[k + 3].num, isFP: ops[k + 3].isFP, charBuf); |
1483 | } |
1484 | charBuf->append(c: (char)8); |
1485 | } |
1486 | nOps = 0; |
1487 | openPath = true; |
1488 | break; |
1489 | case 0x001f: // hvcurveto |
1490 | if (nOps < 4 || !(nOps % 4 == 0 || (nOps - 1) % 4 == 0)) { |
1491 | //~ error(-1, "Wrong number of args (%d) to Type 2 hvcurveto", nOps); |
1492 | } |
1493 | for (k = 0; k < nOps && k != nOps - 5; k += 4) { |
1494 | if (k % 8 == 0) { |
1495 | cvtNum(x: ops[k].num, isFP: ops[k].isFP, charBuf); |
1496 | cvtNum(x: ops[k + 1].num, isFP: ops[k + 1].isFP, charBuf); |
1497 | cvtNum(x: ops[k + 2].num, isFP: ops[k + 2].isFP, charBuf); |
1498 | cvtNum(x: ops[k + 3].num, isFP: ops[k + 3].isFP, charBuf); |
1499 | charBuf->append(c: (char)31); |
1500 | } else { |
1501 | cvtNum(x: ops[k].num, isFP: ops[k].isFP, charBuf); |
1502 | cvtNum(x: ops[k + 1].num, isFP: ops[k + 1].isFP, charBuf); |
1503 | cvtNum(x: ops[k + 2].num, isFP: ops[k + 2].isFP, charBuf); |
1504 | cvtNum(x: ops[k + 3].num, isFP: ops[k + 3].isFP, charBuf); |
1505 | charBuf->append(c: (char)30); |
1506 | } |
1507 | } |
1508 | if (k == nOps - 5) { |
1509 | if (k % 8 == 0) { |
1510 | cvtNum(x: ops[k].num, isFP: ops[k].isFP, charBuf); |
1511 | cvtNum(x: 0, isFP: false, charBuf); |
1512 | cvtNum(x: ops[k + 1].num, isFP: ops[k + 1].isFP, charBuf); |
1513 | cvtNum(x: ops[k + 2].num, isFP: ops[k + 2].isFP, charBuf); |
1514 | cvtNum(x: ops[k + 4].num, isFP: ops[k + 4].isFP, charBuf); |
1515 | cvtNum(x: ops[k + 3].num, isFP: ops[k + 3].isFP, charBuf); |
1516 | } else { |
1517 | cvtNum(x: 0, isFP: false, charBuf); |
1518 | cvtNum(x: ops[k].num, isFP: ops[k].isFP, charBuf); |
1519 | cvtNum(x: ops[k + 1].num, isFP: ops[k + 1].isFP, charBuf); |
1520 | cvtNum(x: ops[k + 2].num, isFP: ops[k + 2].isFP, charBuf); |
1521 | cvtNum(x: ops[k + 3].num, isFP: ops[k + 3].isFP, charBuf); |
1522 | cvtNum(x: ops[k + 4].num, isFP: ops[k + 4].isFP, charBuf); |
1523 | } |
1524 | charBuf->append(c: (char)8); |
1525 | } |
1526 | nOps = 0; |
1527 | openPath = true; |
1528 | break; |
1529 | case 0x0c00: // dotsection (should be Type 1 only?) |
1530 | // ignored |
1531 | nOps = 0; |
1532 | break; |
1533 | case 0x0c03: // and |
1534 | case 0x0c04: // or |
1535 | case 0x0c05: // not |
1536 | case 0x0c08: // store |
1537 | case 0x0c09: // abs |
1538 | case 0x0c0a: // add |
1539 | case 0x0c0b: // sub |
1540 | case 0x0c0c: // div |
1541 | case 0x0c0d: // load |
1542 | case 0x0c0e: // neg |
1543 | case 0x0c0f: // eq |
1544 | case 0x0c12: // drop |
1545 | case 0x0c14: // put |
1546 | case 0x0c15: // get |
1547 | case 0x0c16: // ifelse |
1548 | case 0x0c17: // random |
1549 | case 0x0c18: // mul |
1550 | case 0x0c1a: // sqrt |
1551 | case 0x0c1b: // dup |
1552 | case 0x0c1c: // exch |
1553 | case 0x0c1d: // index |
1554 | case 0x0c1e: // roll |
1555 | //~ error(-1, "Unimplemented Type 2 charstring op: 12.%d", file[i+1]); |
1556 | nOps = 0; |
1557 | break; |
1558 | case 0x0c22: // hflex |
1559 | if (nOps != 7) { |
1560 | //~ error(-1, "Wrong number of args (%d) to Type 2 hflex", nOps); |
1561 | } |
1562 | cvtNum(x: ops[0].num, isFP: ops[0].isFP, charBuf); |
1563 | cvtNum(x: 0, isFP: false, charBuf); |
1564 | cvtNum(x: ops[1].num, isFP: ops[1].isFP, charBuf); |
1565 | cvtNum(x: ops[2].num, isFP: ops[2].isFP, charBuf); |
1566 | cvtNum(x: ops[3].num, isFP: ops[3].isFP, charBuf); |
1567 | cvtNum(x: 0, isFP: false, charBuf); |
1568 | charBuf->append(c: (char)8); |
1569 | cvtNum(x: ops[4].num, isFP: ops[4].isFP, charBuf); |
1570 | cvtNum(x: 0, isFP: false, charBuf); |
1571 | cvtNum(x: ops[5].num, isFP: ops[5].isFP, charBuf); |
1572 | cvtNum(x: -ops[2].num, isFP: ops[2].isFP, charBuf); |
1573 | cvtNum(x: ops[6].num, isFP: ops[6].isFP, charBuf); |
1574 | cvtNum(x: 0, isFP: false, charBuf); |
1575 | charBuf->append(c: (char)8); |
1576 | nOps = 0; |
1577 | openPath = true; |
1578 | break; |
1579 | case 0x0c23: // flex |
1580 | if (nOps != 13) { |
1581 | //~ error(-1, "Wrong number of args (%d) to Type 2 flex", nOps); |
1582 | } |
1583 | cvtNum(x: ops[0].num, isFP: ops[0].isFP, charBuf); |
1584 | cvtNum(x: ops[1].num, isFP: ops[1].isFP, charBuf); |
1585 | cvtNum(x: ops[2].num, isFP: ops[2].isFP, charBuf); |
1586 | cvtNum(x: ops[3].num, isFP: ops[3].isFP, charBuf); |
1587 | cvtNum(x: ops[4].num, isFP: ops[4].isFP, charBuf); |
1588 | cvtNum(x: ops[5].num, isFP: ops[5].isFP, charBuf); |
1589 | charBuf->append(c: (char)8); |
1590 | cvtNum(x: ops[6].num, isFP: ops[6].isFP, charBuf); |
1591 | cvtNum(x: ops[7].num, isFP: ops[7].isFP, charBuf); |
1592 | cvtNum(x: ops[8].num, isFP: ops[8].isFP, charBuf); |
1593 | cvtNum(x: ops[9].num, isFP: ops[9].isFP, charBuf); |
1594 | cvtNum(x: ops[10].num, isFP: ops[10].isFP, charBuf); |
1595 | cvtNum(x: ops[11].num, isFP: ops[11].isFP, charBuf); |
1596 | charBuf->append(c: (char)8); |
1597 | nOps = 0; |
1598 | openPath = true; |
1599 | break; |
1600 | case 0x0c24: // hflex1 |
1601 | if (nOps != 9) { |
1602 | //~ error(-1, "Wrong number of args (%d) to Type 2 hflex1", nOps); |
1603 | } |
1604 | cvtNum(x: ops[0].num, isFP: ops[0].isFP, charBuf); |
1605 | cvtNum(x: ops[1].num, isFP: ops[1].isFP, charBuf); |
1606 | cvtNum(x: ops[2].num, isFP: ops[2].isFP, charBuf); |
1607 | cvtNum(x: ops[3].num, isFP: ops[3].isFP, charBuf); |
1608 | cvtNum(x: ops[4].num, isFP: ops[4].isFP, charBuf); |
1609 | cvtNum(x: 0, isFP: false, charBuf); |
1610 | charBuf->append(c: (char)8); |
1611 | cvtNum(x: ops[5].num, isFP: ops[5].isFP, charBuf); |
1612 | cvtNum(x: 0, isFP: false, charBuf); |
1613 | cvtNum(x: ops[6].num, isFP: ops[6].isFP, charBuf); |
1614 | cvtNum(x: ops[7].num, isFP: ops[7].isFP, charBuf); |
1615 | cvtNum(x: ops[8].num, isFP: ops[8].isFP, charBuf); |
1616 | cvtNum(x: -(ops[1].num + ops[3].num + ops[7].num), isFP: ops[1].isFP | ops[3].isFP | ops[7].isFP, charBuf); |
1617 | charBuf->append(c: (char)8); |
1618 | nOps = 0; |
1619 | openPath = true; |
1620 | break; |
1621 | case 0x0c25: // flex1 |
1622 | if (nOps != 11) { |
1623 | //~ error(-1, "Wrong number of args (%d) to Type 2 flex1", nOps); |
1624 | } |
1625 | cvtNum(x: ops[0].num, isFP: ops[0].isFP, charBuf); |
1626 | cvtNum(x: ops[1].num, isFP: ops[1].isFP, charBuf); |
1627 | cvtNum(x: ops[2].num, isFP: ops[2].isFP, charBuf); |
1628 | cvtNum(x: ops[3].num, isFP: ops[3].isFP, charBuf); |
1629 | cvtNum(x: ops[4].num, isFP: ops[4].isFP, charBuf); |
1630 | cvtNum(x: ops[5].num, isFP: ops[5].isFP, charBuf); |
1631 | charBuf->append(c: (char)8); |
1632 | cvtNum(x: ops[6].num, isFP: ops[6].isFP, charBuf); |
1633 | cvtNum(x: ops[7].num, isFP: ops[7].isFP, charBuf); |
1634 | cvtNum(x: ops[8].num, isFP: ops[8].isFP, charBuf); |
1635 | cvtNum(x: ops[9].num, isFP: ops[9].isFP, charBuf); |
1636 | dx = ops[0].num + ops[2].num + ops[4].num + ops[6].num + ops[8].num; |
1637 | dy = ops[1].num + ops[3].num + ops[5].num + ops[7].num + ops[9].num; |
1638 | if (fabs(x: dx) > fabs(x: dy)) { |
1639 | cvtNum(x: ops[10].num, isFP: ops[10].isFP, charBuf); |
1640 | cvtNum(x: -dy, isFP: ops[1].isFP | ops[3].isFP | ops[5].isFP | ops[7].isFP | ops[9].isFP, charBuf); |
1641 | } else { |
1642 | cvtNum(x: -dx, isFP: ops[0].isFP | ops[2].isFP | ops[4].isFP | ops[6].isFP | ops[8].isFP, charBuf); |
1643 | cvtNum(x: ops[10].num, isFP: ops[10].isFP, charBuf); |
1644 | } |
1645 | charBuf->append(c: (char)8); |
1646 | nOps = 0; |
1647 | openPath = true; |
1648 | break; |
1649 | default: |
1650 | //~ error(-1, "Illegal Type 2 charstring op: %04x", |
1651 | //~ ops[nOps].op); |
1652 | nOps = 0; |
1653 | break; |
1654 | } |
1655 | } |
1656 | } |
1657 | |
1658 | // charstring encryption |
1659 | if (top) { |
1660 | r2 = 4330; |
1661 | for (i = start; i < charBuf->getLength(); ++i) { |
1662 | byte = charBuf->getChar(i) ^ (r2 >> 8); |
1663 | charBuf->setChar(i, c: byte); |
1664 | r2 = (byte + r2) * 52845 + 22719; |
1665 | } |
1666 | } |
1667 | |
1668 | offsetBeingParsed.erase(position: offsetEmplaceResult.first); |
1669 | } |
1670 | |
1671 | void FoFiType1C::cvtGlyphWidth(bool useOp, GooString *charBuf, const Type1CPrivateDict *pDict) |
1672 | { |
1673 | double w; |
1674 | bool wFP; |
1675 | int i; |
1676 | |
1677 | if (useOp) { |
1678 | w = pDict->nominalWidthX + ops[0].num; |
1679 | wFP = pDict->nominalWidthXFP | ops[0].isFP; |
1680 | for (i = 1; i < nOps; ++i) { |
1681 | ops[i - 1] = ops[i]; |
1682 | } |
1683 | --nOps; |
1684 | } else { |
1685 | w = pDict->defaultWidthX; |
1686 | wFP = pDict->defaultWidthXFP; |
1687 | } |
1688 | cvtNum(x: 0, isFP: false, charBuf); |
1689 | cvtNum(x: w, isFP: wFP, charBuf); |
1690 | charBuf->append(c: (char)13); |
1691 | } |
1692 | |
1693 | void FoFiType1C::cvtNum(double x, bool isFP, GooString *charBuf) const |
1694 | { |
1695 | unsigned char buf[12]; |
1696 | int y, n; |
1697 | |
1698 | n = 0; |
1699 | if (isFP) { |
1700 | if (x >= -32768 && x < 32768) { |
1701 | y = (int)(x * 256.0); |
1702 | buf[0] = 255; |
1703 | buf[1] = (unsigned char)(y >> 24); |
1704 | buf[2] = (unsigned char)(y >> 16); |
1705 | buf[3] = (unsigned char)(y >> 8); |
1706 | buf[4] = (unsigned char)y; |
1707 | buf[5] = 255; |
1708 | buf[6] = 0; |
1709 | buf[7] = 0; |
1710 | buf[8] = 1; |
1711 | buf[9] = 0; |
1712 | buf[10] = 12; |
1713 | buf[11] = 12; |
1714 | n = 12; |
1715 | } else { |
1716 | //~ error(-1, "Type 2 fixed point constant out of range"); |
1717 | } |
1718 | } else { |
1719 | y = (int)x; |
1720 | if (y >= -107 && y <= 107) { |
1721 | buf[0] = (unsigned char)(y + 139); |
1722 | n = 1; |
1723 | } else if (y > 107 && y <= 1131) { |
1724 | y -= 108; |
1725 | buf[0] = (unsigned char)((y >> 8) + 247); |
1726 | buf[1] = (unsigned char)(y & 0xff); |
1727 | n = 2; |
1728 | } else if (y < -107 && y >= -1131) { |
1729 | y = -y - 108; |
1730 | buf[0] = (unsigned char)((y >> 8) + 251); |
1731 | buf[1] = (unsigned char)(y & 0xff); |
1732 | n = 2; |
1733 | } else { |
1734 | buf[0] = 255; |
1735 | buf[1] = (unsigned char)(y >> 24); |
1736 | buf[2] = (unsigned char)(y >> 16); |
1737 | buf[3] = (unsigned char)(y >> 8); |
1738 | buf[4] = (unsigned char)y; |
1739 | n = 5; |
1740 | } |
1741 | } |
1742 | charBuf->append(str: (char *)buf, lengthA: n); |
1743 | } |
1744 | |
1745 | void FoFiType1C::eexecWrite(Type1CEexecBuf *eb, const char *s) const |
1746 | { |
1747 | unsigned char *p; |
1748 | unsigned char x; |
1749 | |
1750 | for (p = (unsigned char *)s; *p; ++p) { |
1751 | x = *p ^ (eb->r1 >> 8); |
1752 | eb->r1 = (x + eb->r1) * 52845 + 22719; |
1753 | if (eb->ascii) { |
1754 | (*eb->outputFunc)(eb->outputStream, &hexChars[x >> 4], 1); |
1755 | (*eb->outputFunc)(eb->outputStream, &hexChars[x & 0x0f], 1); |
1756 | eb->line += 2; |
1757 | if (eb->line == 64) { |
1758 | (*eb->outputFunc)(eb->outputStream, "\n" , 1); |
1759 | eb->line = 0; |
1760 | } |
1761 | } else { |
1762 | (*eb->outputFunc)(eb->outputStream, (char *)&x, 1); |
1763 | } |
1764 | } |
1765 | } |
1766 | |
1767 | void FoFiType1C::eexecWriteCharstring(Type1CEexecBuf *eb, const unsigned char *s, int n) const |
1768 | { |
1769 | unsigned char x; |
1770 | int i; |
1771 | |
1772 | // eexec encryption |
1773 | for (i = 0; i < n; ++i) { |
1774 | x = s[i] ^ (eb->r1 >> 8); |
1775 | eb->r1 = (x + eb->r1) * 52845 + 22719; |
1776 | if (eb->ascii) { |
1777 | (*eb->outputFunc)(eb->outputStream, &hexChars[x >> 4], 1); |
1778 | (*eb->outputFunc)(eb->outputStream, &hexChars[x & 0x0f], 1); |
1779 | eb->line += 2; |
1780 | if (eb->line == 64) { |
1781 | (*eb->outputFunc)(eb->outputStream, "\n" , 1); |
1782 | eb->line = 0; |
1783 | } |
1784 | } else { |
1785 | (*eb->outputFunc)(eb->outputStream, (char *)&x, 1); |
1786 | } |
1787 | } |
1788 | } |
1789 | |
1790 | void FoFiType1C::writePSString(const char *s, FoFiOutputFunc outputFunc, void *outputStream) const |
1791 | { |
1792 | char buf[80]; |
1793 | const char *p; |
1794 | int i, c; |
1795 | |
1796 | i = 0; |
1797 | buf[i++] = '('; |
1798 | for (p = s; *p; ++p) { |
1799 | c = *p & 0xff; |
1800 | if (c == '(' || c == ')' || c == '\\') { |
1801 | buf[i++] = '\\'; |
1802 | buf[i++] = c; |
1803 | } else if (c < 0x20 || c >= 0x80) { |
1804 | buf[i++] = '\\'; |
1805 | buf[i++] = '0' + ((c >> 6) & 7); |
1806 | buf[i++] = '0' + ((c >> 3) & 7); |
1807 | buf[i++] = '0' + (c & 7); |
1808 | } else { |
1809 | buf[i++] = c; |
1810 | } |
1811 | if (i >= 64) { |
1812 | buf[i++] = '\\'; |
1813 | buf[i++] = '\n'; |
1814 | (*outputFunc)(outputStream, buf, i); |
1815 | i = 0; |
1816 | } |
1817 | } |
1818 | buf[i++] = ')'; |
1819 | (*outputFunc)(outputStream, buf, i); |
1820 | } |
1821 | |
1822 | bool FoFiType1C::parse() |
1823 | { |
1824 | Type1CIndex fdIdx; |
1825 | Type1CIndexVal val; |
1826 | int i; |
1827 | |
1828 | parsedOk = true; |
1829 | |
1830 | // some tools embed Type 1C fonts with an extra whitespace char at |
1831 | // the beginning |
1832 | if (len > 0 && file[0] != '\x01') { |
1833 | ++file; |
1834 | --len; |
1835 | } |
1836 | |
1837 | // find the indexes |
1838 | getIndex(pos: getU8(pos: 2, ok: &parsedOk), idx: &nameIdx, ok: &parsedOk); |
1839 | getIndex(pos: nameIdx.endPos, idx: &topDictIdx, ok: &parsedOk); |
1840 | getIndex(pos: topDictIdx.endPos, idx: &stringIdx, ok: &parsedOk); |
1841 | getIndex(pos: stringIdx.endPos, idx: &gsubrIdx, ok: &parsedOk); |
1842 | if (!parsedOk) { |
1843 | return false; |
1844 | } |
1845 | gsubrBias = (gsubrIdx.len < 1240) ? 107 : (gsubrIdx.len < 33900) ? 1131 : 32768; |
1846 | |
1847 | // read the first font name |
1848 | getIndexVal(idx: &nameIdx, i: 0, val: &val, ok: &parsedOk); |
1849 | if (!parsedOk) { |
1850 | return false; |
1851 | } |
1852 | name = new GooString((char *)&file[val.pos], val.len); |
1853 | |
1854 | // read the top dict for the first font |
1855 | readTopDict(); |
1856 | |
1857 | // for CID fonts: read the FDArray dicts and private dicts |
1858 | if (topDict.firstOp == 0x0c1e) { |
1859 | if (topDict.fdArrayOffset == 0) { |
1860 | nFDs = 1; |
1861 | privateDicts = (Type1CPrivateDict *)gmalloc(size: sizeof(Type1CPrivateDict)); |
1862 | readPrivateDict(offset: 0, length: 0, pDict: &privateDicts[0]); |
1863 | } else { |
1864 | getIndex(pos: topDict.fdArrayOffset, idx: &fdIdx, ok: &parsedOk); |
1865 | if (!parsedOk || fdIdx.len <= 0) { |
1866 | return false; |
1867 | } |
1868 | nFDs = fdIdx.len; |
1869 | privateDicts = (Type1CPrivateDict *)gmallocn(count: nFDs, size: sizeof(Type1CPrivateDict)); |
1870 | for (i = 0; i < nFDs; ++i) { |
1871 | getIndexVal(idx: &fdIdx, i, val: &val, ok: &parsedOk); |
1872 | if (!parsedOk) { |
1873 | return false; |
1874 | } |
1875 | readFD(offset: val.pos, length: val.len, pDict: &privateDicts[i]); |
1876 | } |
1877 | } |
1878 | |
1879 | // for 8-bit fonts: read the private dict |
1880 | } else { |
1881 | nFDs = 1; |
1882 | privateDicts = (Type1CPrivateDict *)gmalloc(size: sizeof(Type1CPrivateDict)); |
1883 | readPrivateDict(offset: topDict.privateOffset, length: topDict.privateSize, pDict: &privateDicts[0]); |
1884 | } |
1885 | |
1886 | // check for parse errors in the private dict(s) |
1887 | if (!parsedOk) { |
1888 | return false; |
1889 | } |
1890 | |
1891 | // get the charstrings index |
1892 | if (topDict.charStringsOffset <= 0) { |
1893 | parsedOk = false; |
1894 | return false; |
1895 | } |
1896 | getIndex(pos: topDict.charStringsOffset, idx: &charStringsIdx, ok: &parsedOk); |
1897 | if (!parsedOk) { |
1898 | return false; |
1899 | } |
1900 | nGlyphs = charStringsIdx.len; |
1901 | |
1902 | // for CID fonts: read the FDSelect table |
1903 | if (topDict.firstOp == 0x0c1e) { |
1904 | readFDSelect(); |
1905 | if (!parsedOk) { |
1906 | return false; |
1907 | } |
1908 | } |
1909 | |
1910 | // read the charset |
1911 | if (!readCharset()) { |
1912 | parsedOk = false; |
1913 | return false; |
1914 | } |
1915 | |
1916 | // for 8-bit fonts: build the encoding |
1917 | if (topDict.firstOp != 0x0c14 && topDict.firstOp != 0x0c1e) { |
1918 | buildEncoding(); |
1919 | if (!parsedOk) { |
1920 | return false; |
1921 | } |
1922 | } |
1923 | |
1924 | return parsedOk; |
1925 | } |
1926 | |
1927 | void FoFiType1C::readTopDict() |
1928 | { |
1929 | Type1CIndexVal topDictPtr; |
1930 | int pos; |
1931 | |
1932 | topDict.firstOp = -1; |
1933 | topDict.versionSID = 0; |
1934 | topDict.noticeSID = 0; |
1935 | topDict.copyrightSID = 0; |
1936 | topDict.fullNameSID = 0; |
1937 | topDict.familyNameSID = 0; |
1938 | topDict.weightSID = 0; |
1939 | topDict.isFixedPitch = 0; |
1940 | topDict.italicAngle = 0; |
1941 | topDict.underlinePosition = -100; |
1942 | topDict.underlineThickness = 50; |
1943 | topDict.paintType = 0; |
1944 | topDict.charstringType = 2; |
1945 | topDict.fontMatrix[0] = 0.001; |
1946 | topDict.fontMatrix[1] = 0; |
1947 | topDict.fontMatrix[2] = 0; |
1948 | topDict.fontMatrix[3] = 0.001; |
1949 | topDict.fontMatrix[4] = 0; |
1950 | topDict.fontMatrix[5] = 0; |
1951 | topDict.hasFontMatrix = false; |
1952 | topDict.uniqueID = 0; |
1953 | topDict.fontBBox[0] = 0; |
1954 | topDict.fontBBox[1] = 0; |
1955 | topDict.fontBBox[2] = 0; |
1956 | topDict.fontBBox[3] = 0; |
1957 | topDict.strokeWidth = 0; |
1958 | topDict.charsetOffset = 0; |
1959 | topDict.encodingOffset = 0; |
1960 | topDict.charStringsOffset = 0; |
1961 | topDict.privateSize = 0; |
1962 | topDict.privateOffset = 0; |
1963 | topDict.registrySID = 0; |
1964 | topDict.orderingSID = 0; |
1965 | topDict.supplement = 0; |
1966 | topDict.fdArrayOffset = 0; |
1967 | topDict.fdSelectOffset = 0; |
1968 | |
1969 | getIndexVal(idx: &topDictIdx, i: 0, val: &topDictPtr, ok: &parsedOk); |
1970 | if (!parsedOk) { |
1971 | return; |
1972 | } |
1973 | pos = topDictPtr.pos; |
1974 | nOps = 0; |
1975 | while (pos < topDictPtr.pos + topDictPtr.len) { |
1976 | pos = getOp(pos, charstring: false, ok: &parsedOk); |
1977 | if (!parsedOk) { |
1978 | break; |
1979 | } |
1980 | if (!ops[nOps - 1].isNum) { |
1981 | --nOps; // drop the operator |
1982 | if (topDict.firstOp < 0) { |
1983 | topDict.firstOp = ops[nOps].op; |
1984 | } |
1985 | switch (ops[nOps].op) { |
1986 | case 0x0000: |
1987 | topDict.versionSID = (int)ops[0].num; |
1988 | break; |
1989 | case 0x0001: |
1990 | topDict.noticeSID = (int)ops[0].num; |
1991 | break; |
1992 | case 0x0c00: |
1993 | topDict.copyrightSID = (int)ops[0].num; |
1994 | break; |
1995 | case 0x0002: |
1996 | topDict.fullNameSID = (int)ops[0].num; |
1997 | break; |
1998 | case 0x0003: |
1999 | topDict.familyNameSID = (int)ops[0].num; |
2000 | break; |
2001 | case 0x0004: |
2002 | topDict.weightSID = (int)ops[0].num; |
2003 | break; |
2004 | case 0x0c01: |
2005 | topDict.isFixedPitch = (int)ops[0].num; |
2006 | break; |
2007 | case 0x0c02: |
2008 | topDict.italicAngle = ops[0].num; |
2009 | break; |
2010 | case 0x0c03: |
2011 | topDict.underlinePosition = ops[0].num; |
2012 | break; |
2013 | case 0x0c04: |
2014 | topDict.underlineThickness = ops[0].num; |
2015 | break; |
2016 | case 0x0c05: |
2017 | topDict.paintType = (int)ops[0].num; |
2018 | break; |
2019 | case 0x0c06: |
2020 | topDict.charstringType = (int)ops[0].num; |
2021 | break; |
2022 | case 0x0c07: |
2023 | topDict.fontMatrix[0] = ops[0].num; |
2024 | topDict.fontMatrix[1] = ops[1].num; |
2025 | topDict.fontMatrix[2] = ops[2].num; |
2026 | topDict.fontMatrix[3] = ops[3].num; |
2027 | topDict.fontMatrix[4] = ops[4].num; |
2028 | topDict.fontMatrix[5] = ops[5].num; |
2029 | topDict.hasFontMatrix = true; |
2030 | break; |
2031 | case 0x000d: |
2032 | topDict.uniqueID = (int)ops[0].num; |
2033 | break; |
2034 | case 0x0005: |
2035 | topDict.fontBBox[0] = ops[0].num; |
2036 | topDict.fontBBox[1] = ops[1].num; |
2037 | topDict.fontBBox[2] = ops[2].num; |
2038 | topDict.fontBBox[3] = ops[3].num; |
2039 | break; |
2040 | case 0x0c08: |
2041 | topDict.strokeWidth = ops[0].num; |
2042 | break; |
2043 | case 0x000f: |
2044 | topDict.charsetOffset = (int)ops[0].num; |
2045 | break; |
2046 | case 0x0010: |
2047 | topDict.encodingOffset = (int)ops[0].num; |
2048 | break; |
2049 | case 0x0011: |
2050 | topDict.charStringsOffset = (int)ops[0].num; |
2051 | break; |
2052 | case 0x0012: |
2053 | topDict.privateSize = (int)ops[0].num; |
2054 | topDict.privateOffset = (int)ops[1].num; |
2055 | break; |
2056 | case 0x0c1e: |
2057 | topDict.registrySID = (int)ops[0].num; |
2058 | topDict.orderingSID = (int)ops[1].num; |
2059 | topDict.supplement = (int)ops[2].num; |
2060 | break; |
2061 | case 0x0c24: |
2062 | topDict.fdArrayOffset = (int)ops[0].num; |
2063 | break; |
2064 | case 0x0c25: |
2065 | topDict.fdSelectOffset = (int)ops[0].num; |
2066 | break; |
2067 | } |
2068 | nOps = 0; |
2069 | } |
2070 | } |
2071 | } |
2072 | |
2073 | // Read a CID font dict (FD) - this pulls out the private dict |
2074 | // pointer, and reads the private dict. It also pulls the FontMatrix |
2075 | // (if any) out of the FD. |
2076 | void FoFiType1C::readFD(int offset, int length, Type1CPrivateDict *pDict) |
2077 | { |
2078 | int pSize, pOffset; |
2079 | double fontMatrix[6] = { 0 }; |
2080 | bool hasFontMatrix; |
2081 | |
2082 | hasFontMatrix = false; |
2083 | fontMatrix[0] = fontMatrix[1] = fontMatrix[2] = 0; // make gcc happy |
2084 | fontMatrix[3] = fontMatrix[4] = fontMatrix[5] = 0; |
2085 | pSize = pOffset = 0; |
2086 | |
2087 | int posEnd; |
2088 | if (checkedAdd(x: offset, y: length, z: &posEnd)) { |
2089 | return; |
2090 | } |
2091 | |
2092 | int pos = offset; |
2093 | nOps = 0; |
2094 | while (pos < posEnd) { |
2095 | pos = getOp(pos, charstring: false, ok: &parsedOk); |
2096 | if (!parsedOk) { |
2097 | return; |
2098 | } |
2099 | if (!ops[nOps - 1].isNum) { |
2100 | if (ops[nOps - 1].op == 0x0012) { |
2101 | if (nOps < 3) { |
2102 | parsedOk = false; |
2103 | return; |
2104 | } |
2105 | pSize = (int)ops[0].num; |
2106 | pOffset = (int)ops[1].num; |
2107 | break; |
2108 | } else if (ops[nOps - 1].op == 0x0c07) { |
2109 | fontMatrix[0] = ops[0].num; |
2110 | fontMatrix[1] = ops[1].num; |
2111 | fontMatrix[2] = ops[2].num; |
2112 | fontMatrix[3] = ops[3].num; |
2113 | fontMatrix[4] = ops[4].num; |
2114 | fontMatrix[5] = ops[5].num; |
2115 | hasFontMatrix = true; |
2116 | } |
2117 | nOps = 0; |
2118 | } |
2119 | } |
2120 | readPrivateDict(offset: pOffset, length: pSize, pDict); |
2121 | if (hasFontMatrix) { |
2122 | pDict->fontMatrix[0] = fontMatrix[0]; |
2123 | pDict->fontMatrix[1] = fontMatrix[1]; |
2124 | pDict->fontMatrix[2] = fontMatrix[2]; |
2125 | pDict->fontMatrix[3] = fontMatrix[3]; |
2126 | pDict->fontMatrix[4] = fontMatrix[4]; |
2127 | pDict->fontMatrix[5] = fontMatrix[5]; |
2128 | pDict->hasFontMatrix = true; |
2129 | } |
2130 | } |
2131 | |
2132 | void FoFiType1C::readPrivateDict(int offset, int length, Type1CPrivateDict *pDict) |
2133 | { |
2134 | pDict->hasFontMatrix = false; |
2135 | pDict->nBlueValues = 0; |
2136 | pDict->nOtherBlues = 0; |
2137 | pDict->nFamilyBlues = 0; |
2138 | pDict->nFamilyOtherBlues = 0; |
2139 | pDict->blueScale = 0.039625; |
2140 | pDict->blueShift = 7; |
2141 | pDict->blueFuzz = 1; |
2142 | pDict->hasStdHW = false; |
2143 | pDict->hasStdVW = false; |
2144 | pDict->nStemSnapH = 0; |
2145 | pDict->nStemSnapV = 0; |
2146 | pDict->hasForceBold = false; |
2147 | pDict->forceBoldThreshold = 0; |
2148 | pDict->languageGroup = 0; |
2149 | pDict->expansionFactor = 0.06; |
2150 | pDict->initialRandomSeed = 0; |
2151 | pDict->subrsOffset = 0; |
2152 | pDict->defaultWidthX = 0; |
2153 | pDict->defaultWidthXFP = false; |
2154 | pDict->nominalWidthX = 0; |
2155 | pDict->nominalWidthXFP = false; |
2156 | |
2157 | // no dictionary |
2158 | if (offset == 0 || length == 0) { |
2159 | return; |
2160 | } |
2161 | |
2162 | int posEnd; |
2163 | if (checkedAdd(x: offset, y: length, z: &posEnd)) { |
2164 | return; |
2165 | } |
2166 | |
2167 | int pos = offset; |
2168 | nOps = 0; |
2169 | while (pos < posEnd) { |
2170 | pos = getOp(pos, charstring: false, ok: &parsedOk); |
2171 | if (!parsedOk) { |
2172 | break; |
2173 | } |
2174 | if (!ops[nOps - 1].isNum) { |
2175 | --nOps; // drop the operator |
2176 | switch (ops[nOps].op) { |
2177 | case 0x0006: |
2178 | pDict->nBlueValues = getDeltaIntArray(arr: pDict->blueValues, type1CMaxBlueValues); |
2179 | break; |
2180 | case 0x0007: |
2181 | pDict->nOtherBlues = getDeltaIntArray(arr: pDict->otherBlues, type1CMaxOtherBlues); |
2182 | break; |
2183 | case 0x0008: |
2184 | pDict->nFamilyBlues = getDeltaIntArray(arr: pDict->familyBlues, type1CMaxBlueValues); |
2185 | break; |
2186 | case 0x0009: |
2187 | pDict->nFamilyOtherBlues = getDeltaIntArray(arr: pDict->familyOtherBlues, type1CMaxOtherBlues); |
2188 | break; |
2189 | case 0x0c09: |
2190 | pDict->blueScale = ops[0].num; |
2191 | break; |
2192 | case 0x0c0a: |
2193 | pDict->blueShift = (int)ops[0].num; |
2194 | break; |
2195 | case 0x0c0b: |
2196 | pDict->blueFuzz = (int)ops[0].num; |
2197 | break; |
2198 | case 0x000a: |
2199 | pDict->stdHW = ops[0].num; |
2200 | pDict->hasStdHW = true; |
2201 | break; |
2202 | case 0x000b: |
2203 | pDict->stdVW = ops[0].num; |
2204 | pDict->hasStdVW = true; |
2205 | break; |
2206 | case 0x0c0c: |
2207 | pDict->nStemSnapH = getDeltaFPArray(arr: pDict->stemSnapH, type1CMaxStemSnap); |
2208 | break; |
2209 | case 0x0c0d: |
2210 | pDict->nStemSnapV = getDeltaFPArray(arr: pDict->stemSnapV, type1CMaxStemSnap); |
2211 | break; |
2212 | case 0x0c0e: |
2213 | pDict->forceBold = ops[0].num != 0; |
2214 | pDict->hasForceBold = true; |
2215 | break; |
2216 | case 0x0c0f: |
2217 | pDict->forceBoldThreshold = ops[0].num; |
2218 | break; |
2219 | case 0x0c11: |
2220 | pDict->languageGroup = (int)ops[0].num; |
2221 | break; |
2222 | case 0x0c12: |
2223 | pDict->expansionFactor = ops[0].num; |
2224 | break; |
2225 | case 0x0c13: |
2226 | pDict->initialRandomSeed = (int)ops[0].num; |
2227 | break; |
2228 | case 0x0013: |
2229 | pDict->subrsOffset = offset + (int)ops[0].num; |
2230 | break; |
2231 | case 0x0014: |
2232 | pDict->defaultWidthX = ops[0].num; |
2233 | pDict->defaultWidthXFP = ops[0].isFP; |
2234 | break; |
2235 | case 0x0015: |
2236 | pDict->nominalWidthX = ops[0].num; |
2237 | pDict->nominalWidthXFP = ops[0].isFP; |
2238 | break; |
2239 | } |
2240 | nOps = 0; |
2241 | } |
2242 | } |
2243 | } |
2244 | |
2245 | void FoFiType1C::readFDSelect() |
2246 | { |
2247 | int fdSelectFmt, pos, nRanges, gid0, gid1, fd; |
2248 | |
2249 | fdSelect = (unsigned char *)gmalloc(size: nGlyphs); |
2250 | if (topDict.fdSelectOffset == 0) { |
2251 | for (int i = 0; i < nGlyphs; ++i) { |
2252 | fdSelect[i] = 0; |
2253 | } |
2254 | } else { |
2255 | pos = topDict.fdSelectOffset; |
2256 | fdSelectFmt = getU8(pos: pos++, ok: &parsedOk); |
2257 | if (!parsedOk) { |
2258 | return; |
2259 | } |
2260 | if (fdSelectFmt == 0) { |
2261 | if (!checkRegion(pos, size: nGlyphs)) { |
2262 | parsedOk = false; |
2263 | return; |
2264 | } |
2265 | memcpy(dest: fdSelect, src: file + pos, n: nGlyphs); |
2266 | } else if (fdSelectFmt == 3) { |
2267 | nRanges = getU16BE(pos, ok: &parsedOk); |
2268 | pos += 2; |
2269 | gid0 = getU16BE(pos, ok: &parsedOk); |
2270 | pos += 2; |
2271 | for (int i = 1; i <= nRanges; ++i) { |
2272 | fd = getU8(pos: pos++, ok: &parsedOk); |
2273 | gid1 = getU16BE(pos, ok: &parsedOk); |
2274 | if (!parsedOk) { |
2275 | return; |
2276 | } |
2277 | pos += 2; |
2278 | if (gid0 > gid1 || gid1 > nGlyphs) { |
2279 | //~ error(-1, "Bad FDSelect table in CID font"); |
2280 | parsedOk = false; |
2281 | return; |
2282 | } |
2283 | for (int j = gid0; j < gid1; ++j) { |
2284 | fdSelect[j] = fd; |
2285 | } |
2286 | gid0 = gid1; |
2287 | } |
2288 | for (int i = gid0; i < nGlyphs; ++i) { |
2289 | fdSelect[i] = 0; |
2290 | } |
2291 | } else { |
2292 | //~ error(-1, "Unknown FDSelect table format in CID font"); |
2293 | for (int i = 0; i < nGlyphs; ++i) { |
2294 | fdSelect[i] = 0; |
2295 | } |
2296 | } |
2297 | } |
2298 | } |
2299 | |
2300 | void FoFiType1C::buildEncoding() |
2301 | { |
2302 | char buf[256]; |
2303 | int nCodes, nRanges, encFormat; |
2304 | int pos, c, sid, nLeft, nSups, i, j; |
2305 | |
2306 | if (topDict.encodingOffset == 0) { |
2307 | encoding = (char **)fofiType1StandardEncoding; |
2308 | |
2309 | } else if (topDict.encodingOffset == 1) { |
2310 | encoding = (char **)fofiType1ExpertEncoding; |
2311 | |
2312 | } else { |
2313 | encoding = (char **)gmallocn(count: 256, size: sizeof(char *)); |
2314 | for (i = 0; i < 256; ++i) { |
2315 | encoding[i] = nullptr; |
2316 | } |
2317 | pos = topDict.encodingOffset; |
2318 | encFormat = getU8(pos: pos++, ok: &parsedOk); |
2319 | if (!parsedOk) { |
2320 | return; |
2321 | } |
2322 | if ((encFormat & 0x7f) == 0) { |
2323 | nCodes = 1 + getU8(pos: pos++, ok: &parsedOk); |
2324 | if (!parsedOk) { |
2325 | return; |
2326 | } |
2327 | if (nCodes > nGlyphs) { |
2328 | nCodes = nGlyphs; |
2329 | } |
2330 | for (i = 1; i < nCodes && i < charsetLength; ++i) { |
2331 | c = getU8(pos: pos++, ok: &parsedOk); |
2332 | if (!parsedOk) { |
2333 | return; |
2334 | } |
2335 | if (encoding[c]) { |
2336 | gfree(p: encoding[c]); |
2337 | } |
2338 | encoding[c] = copyString(s: getString(sid: charset[i], buf, ok: &parsedOk)); |
2339 | } |
2340 | } else if ((encFormat & 0x7f) == 1) { |
2341 | nRanges = getU8(pos: pos++, ok: &parsedOk); |
2342 | if (!parsedOk) { |
2343 | return; |
2344 | } |
2345 | nCodes = 1; |
2346 | for (i = 0; i < nRanges; ++i) { |
2347 | c = getU8(pos: pos++, ok: &parsedOk); |
2348 | nLeft = getU8(pos: pos++, ok: &parsedOk); |
2349 | if (!parsedOk) { |
2350 | return; |
2351 | } |
2352 | for (j = 0; j <= nLeft && nCodes < nGlyphs && nCodes < charsetLength; ++j) { |
2353 | if (c < 256) { |
2354 | if (encoding[c]) { |
2355 | gfree(p: encoding[c]); |
2356 | } |
2357 | encoding[c] = copyString(s: getString(sid: charset[nCodes], buf, ok: &parsedOk)); |
2358 | } |
2359 | ++nCodes; |
2360 | ++c; |
2361 | } |
2362 | } |
2363 | } |
2364 | if (encFormat & 0x80) { |
2365 | nSups = getU8(pos: pos++, ok: &parsedOk); |
2366 | if (!parsedOk) { |
2367 | return; |
2368 | } |
2369 | for (i = 0; i < nSups; ++i) { |
2370 | c = getU8(pos: pos++, ok: &parsedOk); |
2371 | ; |
2372 | if (!parsedOk) { |
2373 | return; |
2374 | ; |
2375 | } |
2376 | sid = getU16BE(pos, ok: &parsedOk); |
2377 | pos += 2; |
2378 | if (!parsedOk) { |
2379 | return; |
2380 | } |
2381 | if (encoding[c]) { |
2382 | gfree(p: encoding[c]); |
2383 | } |
2384 | encoding[c] = copyString(s: getString(sid, buf, ok: &parsedOk)); |
2385 | } |
2386 | } |
2387 | } |
2388 | } |
2389 | |
2390 | bool FoFiType1C::readCharset() |
2391 | { |
2392 | int charsetFormat, c, pos; |
2393 | int nLeft, i, j; |
2394 | |
2395 | if (topDict.charsetOffset == 0) { |
2396 | charset = fofiType1CISOAdobeCharset; |
2397 | charsetLength = sizeof(fofiType1CISOAdobeCharset) / sizeof(unsigned short); |
2398 | } else if (topDict.charsetOffset == 1) { |
2399 | charset = fofiType1CExpertCharset; |
2400 | charsetLength = sizeof(fofiType1CExpertCharset) / sizeof(unsigned short); |
2401 | } else if (topDict.charsetOffset == 2) { |
2402 | charset = fofiType1CExpertSubsetCharset; |
2403 | charsetLength = sizeof(fofiType1CExpertSubsetCharset) / sizeof(unsigned short); |
2404 | } else { |
2405 | unsigned short *customCharset = (unsigned short *)gmallocn(count: nGlyphs, size: sizeof(unsigned short)); |
2406 | charsetLength = nGlyphs; |
2407 | for (i = 0; i < nGlyphs; ++i) { |
2408 | customCharset[i] = 0; |
2409 | } |
2410 | pos = topDict.charsetOffset; |
2411 | charsetFormat = getU8(pos: pos++, ok: &parsedOk); |
2412 | if (charsetFormat == 0) { |
2413 | for (i = 1; i < nGlyphs; ++i) { |
2414 | customCharset[i] = (unsigned short)getU16BE(pos, ok: &parsedOk); |
2415 | pos += 2; |
2416 | if (!parsedOk) { |
2417 | break; |
2418 | } |
2419 | } |
2420 | } else if (charsetFormat == 1) { |
2421 | i = 1; |
2422 | while (i < nGlyphs) { |
2423 | c = getU16BE(pos, ok: &parsedOk); |
2424 | pos += 2; |
2425 | nLeft = getU8(pos: pos++, ok: &parsedOk); |
2426 | if (!parsedOk) { |
2427 | break; |
2428 | } |
2429 | for (j = 0; j <= nLeft && i < nGlyphs; ++j) { |
2430 | customCharset[i++] = (unsigned short)c++; |
2431 | } |
2432 | } |
2433 | } else if (charsetFormat == 2) { |
2434 | i = 1; |
2435 | while (i < nGlyphs) { |
2436 | c = getU16BE(pos, ok: &parsedOk); |
2437 | pos += 2; |
2438 | nLeft = getU16BE(pos, ok: &parsedOk); |
2439 | pos += 2; |
2440 | if (!parsedOk) { |
2441 | break; |
2442 | } |
2443 | for (j = 0; j <= nLeft && i < nGlyphs; ++j) { |
2444 | customCharset[i++] = (unsigned short)c++; |
2445 | } |
2446 | } |
2447 | } |
2448 | if (!parsedOk) { |
2449 | gfree(p: customCharset); |
2450 | charset = nullptr; |
2451 | charsetLength = 0; |
2452 | return false; |
2453 | } |
2454 | charset = customCharset; |
2455 | } |
2456 | return true; |
2457 | } |
2458 | |
2459 | int FoFiType1C::getOp(int pos, bool charstring, bool *ok) |
2460 | { |
2461 | static const char nybChars[16] = "0123456789.ee -" ; |
2462 | Type1COp op; |
2463 | char buf[65]; |
2464 | int b0, b1, nyb0, nyb1, x, i; |
2465 | |
2466 | b0 = getU8(pos: pos++, ok); |
2467 | |
2468 | if (b0 == 28) { |
2469 | x = getU8(pos: pos++, ok); |
2470 | x = (x << 8) | getU8(pos: pos++, ok); |
2471 | if (x & 0x8000) { |
2472 | x |= ~0xffff; |
2473 | } |
2474 | op.num = x; |
2475 | |
2476 | } else if (!charstring && b0 == 29) { |
2477 | x = getU8(pos: pos++, ok); |
2478 | x = (x << 8) | getU8(pos: pos++, ok); |
2479 | x = (x << 8) | getU8(pos: pos++, ok); |
2480 | x = (x << 8) | getU8(pos: pos++, ok); |
2481 | if (x & 0x80000000) { |
2482 | x |= ~0xffffffff; |
2483 | } |
2484 | op.num = x; |
2485 | |
2486 | } else if (!charstring && b0 == 30) { |
2487 | i = 0; |
2488 | do { |
2489 | b1 = getU8(pos: pos++, ok); |
2490 | nyb0 = b1 >> 4; |
2491 | nyb1 = b1 & 0x0f; |
2492 | if (nyb0 == 0xf) { |
2493 | break; |
2494 | } |
2495 | buf[i++] = nybChars[nyb0]; |
2496 | if (i == 64) { |
2497 | break; |
2498 | } |
2499 | if (nyb0 == 0xc) { |
2500 | buf[i++] = '-'; |
2501 | } |
2502 | if (i == 64) { |
2503 | break; |
2504 | } |
2505 | if (nyb1 == 0xf) { |
2506 | break; |
2507 | } |
2508 | buf[i++] = nybChars[nyb1]; |
2509 | if (i == 64) { |
2510 | break; |
2511 | } |
2512 | if (nyb1 == 0xc) { |
2513 | buf[i++] = '-'; |
2514 | } |
2515 | } while (i < 64); |
2516 | buf[i] = '\0'; |
2517 | op.num = gatof(nptr: buf); |
2518 | op.isFP = true; |
2519 | |
2520 | } else if (b0 >= 32 && b0 <= 246) { |
2521 | op.num = b0 - 139; |
2522 | |
2523 | } else if (b0 >= 247 && b0 <= 250) { |
2524 | op.num = ((b0 - 247) << 8) + getU8(pos: pos++, ok) + 108; |
2525 | |
2526 | } else if (b0 >= 251 && b0 <= 254) { |
2527 | op.num = -((b0 - 251) << 8) - getU8(pos: pos++, ok) - 108; |
2528 | |
2529 | } else if (charstring && b0 == 255) { |
2530 | x = getU8(pos: pos++, ok); |
2531 | x = (x << 8) | getU8(pos: pos++, ok); |
2532 | x = (x << 8) | getU8(pos: pos++, ok); |
2533 | x = (x << 8) | getU8(pos: pos++, ok); |
2534 | if (x & 0x80000000) { |
2535 | x |= ~0xffffffff; |
2536 | } |
2537 | op.num = (double)x / 65536.0; |
2538 | op.isFP = true; |
2539 | |
2540 | } else if (b0 == 12) { |
2541 | op.isNum = false; |
2542 | op.op = 0x0c00 + getU8(pos: pos++, ok); |
2543 | |
2544 | } else { |
2545 | op.isNum = false; |
2546 | op.op = b0; |
2547 | } |
2548 | |
2549 | if (nOps < 49) { |
2550 | ops[nOps++] = op; |
2551 | } |
2552 | |
2553 | return pos; |
2554 | } |
2555 | |
2556 | // Convert the delta-encoded ops array to an array of ints. |
2557 | int FoFiType1C::getDeltaIntArray(int *arr, int maxLen) const |
2558 | { |
2559 | int x; |
2560 | int n, i; |
2561 | |
2562 | if ((n = nOps) > maxLen) { |
2563 | n = maxLen; |
2564 | } |
2565 | x = 0; |
2566 | for (i = 0; i < n; ++i) { |
2567 | int y; |
2568 | if (unlikely(std::isinf(ops[i].num))) { |
2569 | return i; |
2570 | } |
2571 | if (checkedAdd(x, y: (int)ops[i].num, z: &y)) { |
2572 | return i; |
2573 | } |
2574 | x = y; |
2575 | arr[i] = x; |
2576 | } |
2577 | return n; |
2578 | } |
2579 | |
2580 | // Convert the delta-encoded ops array to an array of doubles. |
2581 | int FoFiType1C::getDeltaFPArray(double *arr, int maxLen) const |
2582 | { |
2583 | double x; |
2584 | int n, i; |
2585 | |
2586 | if ((n = nOps) > maxLen) { |
2587 | n = maxLen; |
2588 | } |
2589 | x = 0; |
2590 | for (i = 0; i < n; ++i) { |
2591 | x += ops[i].num; |
2592 | arr[i] = x; |
2593 | } |
2594 | return n; |
2595 | } |
2596 | |
2597 | void FoFiType1C::getIndex(int pos, Type1CIndex *idx, bool *ok) const |
2598 | { |
2599 | idx->pos = pos; |
2600 | idx->len = getU16BE(pos, ok); |
2601 | if (idx->len == 0) { |
2602 | // empty indexes are legal and contain just the length field |
2603 | idx->offSize = 0; |
2604 | idx->startPos = idx->endPos = pos + 2; |
2605 | } else { |
2606 | idx->offSize = getU8(pos: pos + 2, ok); |
2607 | if (idx->offSize < 1 || idx->offSize > 4) { |
2608 | *ok = false; |
2609 | } |
2610 | idx->startPos = pos + 3 + (idx->len + 1) * idx->offSize - 1; |
2611 | if (idx->startPos < 0 || idx->startPos >= len) { |
2612 | *ok = false; |
2613 | } |
2614 | idx->endPos = idx->startPos + getUVarBE(pos: pos + 3 + idx->len * idx->offSize, size: idx->offSize, ok); |
2615 | if (idx->endPos < idx->startPos || idx->endPos > len) { |
2616 | *ok = false; |
2617 | } |
2618 | } |
2619 | } |
2620 | |
2621 | void FoFiType1C::getIndexVal(const Type1CIndex *idx, int i, Type1CIndexVal *val, bool *ok) const |
2622 | { |
2623 | int pos0, pos1; |
2624 | |
2625 | if (i < 0 || i >= idx->len) { |
2626 | *ok = false; |
2627 | return; |
2628 | } |
2629 | pos0 = idx->startPos + getUVarBE(pos: idx->pos + 3 + i * idx->offSize, size: idx->offSize, ok); |
2630 | pos1 = idx->startPos + getUVarBE(pos: idx->pos + 3 + (i + 1) * idx->offSize, size: idx->offSize, ok); |
2631 | if (pos0 < idx->startPos || pos0 > idx->endPos || pos1 <= idx->startPos || pos1 > idx->endPos || pos1 < pos0) { |
2632 | *ok = false; |
2633 | return; |
2634 | } |
2635 | val->pos = pos0; |
2636 | val->len = pos1 - pos0; |
2637 | } |
2638 | |
2639 | char *FoFiType1C::getString(int sid, char *buf, bool *ok) const |
2640 | { |
2641 | Type1CIndexVal val; |
2642 | int n; |
2643 | |
2644 | if (sid < 0) { |
2645 | buf[0] = '\0'; |
2646 | } else if (sid < 391) { |
2647 | strcpy(dest: buf, src: fofiType1CStdStrings[sid]); |
2648 | } else { |
2649 | sid -= 391; |
2650 | getIndexVal(idx: &stringIdx, i: sid, val: &val, ok); |
2651 | if (*ok) { |
2652 | if ((n = val.len) > 255) { |
2653 | n = 255; |
2654 | } |
2655 | strncpy(dest: buf, src: (char *)&file[val.pos], n: n); |
2656 | buf[n] = '\0'; |
2657 | } else { |
2658 | buf[0] = '\0'; |
2659 | } |
2660 | } |
2661 | return buf; |
2662 | } |
2663 | |