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
43static const char hexChars[17] = "0123456789ABCDEF";
44
45//------------------------------------------------------------------------
46// FoFiType1C
47//------------------------------------------------------------------------
48
49FoFiType1C *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
59FoFiType1C *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
76FoFiType1C::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
86FoFiType1C::~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
110const char *FoFiType1C::getName() const
111{
112 return name ? name->c_str() : nullptr;
113}
114
115char **FoFiType1C::getEncoding() const
116{
117 return encoding;
118}
119
120GooString *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
136int *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
165void 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
189void 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
443void 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
732void 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
1017void 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
1034void 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
1671void 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
1693void 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
1745void 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
1767void 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
1790void 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
1822bool 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
1927void 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.
2076void 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
2132void 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
2245void 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
2300void 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
2390bool 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
2459int 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.
2557int 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.
2581int 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
2597void 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
2621void 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
2639char *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

source code of poppler/fofi/FoFiType1C.cc