beta-0.89.2
[luatex.git] / source / texk / web2c / luatexdir / luafontloader / fontforge / fontforge / parsepfa.c
blob1cff6a4858ae069b1ccb3b79493ba074a8c3d93c
1 /* Copyright (C) 2000-2008 by George Williams */
2 /*
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are met:
6 * Redistributions of source code must retain the above copyright notice, this
7 * list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright notice,
10 * this list of conditions and the following disclaimer in the documentation
11 * and/or other materials provided with the distribution.
13 * The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include "pfaedit.h"
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <ustring.h>
32 #include <utype.h>
33 #include <unistd.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include "psfont.h"
37 #include <locale.h>
39 struct fontparse {
40 FontDict *fd, *mainfd;
41 /* always in font data */
42 unsigned int infi:1;
43 unsigned int inchars:1;
44 unsigned int inprivate:1;
45 unsigned int insubs:1;
46 unsigned int inmetrics: 1;
47 unsigned int inmetrics2: 1;
48 unsigned int inbb: 1;
49 unsigned int inencoding: 1;
50 unsigned int simpleencoding: 1;
51 unsigned int multiline: 1;
52 unsigned int incidsysteminfo: 1;
53 unsigned int inblendfi:1;
54 unsigned int inblendprivate:1;
55 unsigned int skipping_mbf: 1;
56 unsigned int inblend: 1;
57 unsigned int iscid: 1;
58 unsigned int iscff: 1;
59 unsigned int useshexstrings: 1;
60 unsigned int doneencoding: 1;
61 unsigned int ignore: 1;
62 int simple_enc_pos;
63 int instring;
64 int fdindex;
65 char **pending_parse;
66 FILE *sfnts;
68 unsigned int alreadycomplained: 1;
70 char *vbuf, *vmax, *vpt;
71 int depth;
74 static void copyenc(char *encoding[256],char *std[256]) {
75 int i;
76 for ( i=0; i<256; ++i )
77 encoding[i] = copy(std[i]);
80 char *AdobeStandardEncoding[] = {
81 /* 0000 */ ".notdef",
82 /* 0001 */ ".notdef",
83 /* 0002 */ ".notdef",
84 /* 0003 */ ".notdef",
85 /* 0004 */ ".notdef",
86 /* 0005 */ ".notdef",
87 /* 0006 */ ".notdef",
88 /* 0007 */ ".notdef",
89 /* 0008 */ ".notdef",
90 /* 0009 */ ".notdef",
91 /* 000a */ ".notdef",
92 /* 000b */ ".notdef",
93 /* 000c */ ".notdef",
94 /* 000d */ ".notdef",
95 /* 000e */ ".notdef",
96 /* 000f */ ".notdef",
97 /* 0010 */ ".notdef",
98 /* 0011 */ ".notdef",
99 /* 0012 */ ".notdef",
100 /* 0013 */ ".notdef",
101 /* 0014 */ ".notdef",
102 /* 0015 */ ".notdef",
103 /* 0016 */ ".notdef",
104 /* 0017 */ ".notdef",
105 /* 0018 */ ".notdef",
106 /* 0019 */ ".notdef",
107 /* 001a */ ".notdef",
108 /* 001b */ ".notdef",
109 /* 001c */ ".notdef",
110 /* 001d */ ".notdef",
111 /* 001e */ ".notdef",
112 /* 001f */ ".notdef",
113 /* 0020 */ "space",
114 /* 0021 */ "exclam",
115 /* 0022 */ "quotedbl",
116 /* 0023 */ "numbersign",
117 /* 0024 */ "dollar",
118 /* 0025 */ "percent",
119 /* 0026 */ "ampersand",
120 /* 0027 */ "quoteright",
121 /* 0028 */ "parenleft",
122 /* 0029 */ "parenright",
123 /* 002a */ "asterisk",
124 /* 002b */ "plus",
125 /* 002c */ "comma",
126 /* 002d */ "hyphen",
127 /* 002e */ "period",
128 /* 002f */ "slash",
129 /* 0030 */ "zero",
130 /* 0031 */ "one",
131 /* 0032 */ "two",
132 /* 0033 */ "three",
133 /* 0034 */ "four",
134 /* 0035 */ "five",
135 /* 0036 */ "six",
136 /* 0037 */ "seven",
137 /* 0038 */ "eight",
138 /* 0039 */ "nine",
139 /* 003a */ "colon",
140 /* 003b */ "semicolon",
141 /* 003c */ "less",
142 /* 003d */ "equal",
143 /* 003e */ "greater",
144 /* 003f */ "question",
145 /* 0040 */ "at",
146 /* 0041 */ "A",
147 /* 0042 */ "B",
148 /* 0043 */ "C",
149 /* 0044 */ "D",
150 /* 0045 */ "E",
151 /* 0046 */ "F",
152 /* 0047 */ "G",
153 /* 0048 */ "H",
154 /* 0049 */ "I",
155 /* 004a */ "J",
156 /* 004b */ "K",
157 /* 004c */ "L",
158 /* 004d */ "M",
159 /* 004e */ "N",
160 /* 004f */ "O",
161 /* 0050 */ "P",
162 /* 0051 */ "Q",
163 /* 0052 */ "R",
164 /* 0053 */ "S",
165 /* 0054 */ "T",
166 /* 0055 */ "U",
167 /* 0056 */ "V",
168 /* 0057 */ "W",
169 /* 0058 */ "X",
170 /* 0059 */ "Y",
171 /* 005a */ "Z",
172 /* 005b */ "bracketleft",
173 /* 005c */ "backslash",
174 /* 005d */ "bracketright",
175 /* 005e */ "asciicircum",
176 /* 005f */ "underscore",
177 /* 0060 */ "quoteleft",
178 /* 0061 */ "a",
179 /* 0062 */ "b",
180 /* 0063 */ "c",
181 /* 0064 */ "d",
182 /* 0065 */ "e",
183 /* 0066 */ "f",
184 /* 0067 */ "g",
185 /* 0068 */ "h",
186 /* 0069 */ "i",
187 /* 006a */ "j",
188 /* 006b */ "k",
189 /* 006c */ "l",
190 /* 006d */ "m",
191 /* 006e */ "n",
192 /* 006f */ "o",
193 /* 0070 */ "p",
194 /* 0071 */ "q",
195 /* 0072 */ "r",
196 /* 0073 */ "s",
197 /* 0074 */ "t",
198 /* 0075 */ "u",
199 /* 0076 */ "v",
200 /* 0077 */ "w",
201 /* 0078 */ "x",
202 /* 0079 */ "y",
203 /* 007a */ "z",
204 /* 007b */ "braceleft",
205 /* 007c */ "bar",
206 /* 007d */ "braceright",
207 /* 007e */ "asciitilde",
208 /* 007f */ ".notdef",
209 /* 0080 */ ".notdef",
210 /* 0081 */ ".notdef",
211 /* 0082 */ ".notdef",
212 /* 0083 */ ".notdef",
213 /* 0084 */ ".notdef",
214 /* 0085 */ ".notdef",
215 /* 0086 */ ".notdef",
216 /* 0087 */ ".notdef",
217 /* 0088 */ ".notdef",
218 /* 0089 */ ".notdef",
219 /* 008a */ ".notdef",
220 /* 008b */ ".notdef",
221 /* 008c */ ".notdef",
222 /* 008d */ ".notdef",
223 /* 008e */ ".notdef",
224 /* 008f */ ".notdef",
225 /* 0090 */ ".notdef",
226 /* 0091 */ ".notdef",
227 /* 0092 */ ".notdef",
228 /* 0093 */ ".notdef",
229 /* 0094 */ ".notdef",
230 /* 0095 */ ".notdef",
231 /* 0096 */ ".notdef",
232 /* 0097 */ ".notdef",
233 /* 0098 */ ".notdef",
234 /* 0099 */ ".notdef",
235 /* 009a */ ".notdef",
236 /* 009b */ ".notdef",
237 /* 009c */ ".notdef",
238 /* 009d */ ".notdef",
239 /* 009e */ ".notdef",
240 /* 009f */ ".notdef",
241 /* 00a0 */ ".notdef",
242 /* 00a1 */ "exclamdown",
243 /* 00a2 */ "cent",
244 /* 00a3 */ "sterling",
245 /* 00a4 */ "fraction",
246 /* 00a5 */ "yen",
247 /* 00a6 */ "florin",
248 /* 00a7 */ "section",
249 /* 00a8 */ "currency",
250 /* 00a9 */ "quotesingle",
251 /* 00aa */ "quotedblleft",
252 /* 00ab */ "guillemotleft",
253 /* 00ac */ "guilsinglleft",
254 /* 00ad */ "guilsinglright",
255 /* 00ae */ "fi",
256 /* 00af */ "fl",
257 /* 00b0 */ ".notdef",
258 /* 00b1 */ "endash",
259 /* 00b2 */ "dagger",
260 /* 00b3 */ "daggerdbl",
261 /* 00b4 */ "periodcentered",
262 /* 00b5 */ ".notdef",
263 /* 00b6 */ "paragraph",
264 /* 00b7 */ "bullet",
265 /* 00b8 */ "quotesinglbase",
266 /* 00b9 */ "quotedblbase",
267 /* 00ba */ "quotedblright",
268 /* 00bb */ "guillemotright",
269 /* 00bc */ "ellipsis",
270 /* 00bd */ "perthousand",
271 /* 00be */ ".notdef",
272 /* 00bf */ "questiondown",
273 /* 00c0 */ ".notdef",
274 /* 00c1 */ "grave",
275 /* 00c2 */ "acute",
276 /* 00c3 */ "circumflex",
277 /* 00c4 */ "tilde",
278 /* 00c5 */ "macron",
279 /* 00c6 */ "breve",
280 /* 00c7 */ "dotaccent",
281 /* 00c8 */ "dieresis",
282 /* 00c9 */ ".notdef",
283 /* 00ca */ "ring",
284 /* 00cb */ "cedilla",
285 /* 00cc */ ".notdef",
286 /* 00cd */ "hungarumlaut",
287 /* 00ce */ "ogonek",
288 /* 00cf */ "caron",
289 /* 00d0 */ "emdash",
290 /* 00d1 */ ".notdef",
291 /* 00d2 */ ".notdef",
292 /* 00d3 */ ".notdef",
293 /* 00d4 */ ".notdef",
294 /* 00d5 */ ".notdef",
295 /* 00d6 */ ".notdef",
296 /* 00d7 */ ".notdef",
297 /* 00d8 */ ".notdef",
298 /* 00d9 */ ".notdef",
299 /* 00da */ ".notdef",
300 /* 00db */ ".notdef",
301 /* 00dc */ ".notdef",
302 /* 00dd */ ".notdef",
303 /* 00de */ ".notdef",
304 /* 00df */ ".notdef",
305 /* 00e0 */ ".notdef",
306 /* 00e1 */ "AE",
307 /* 00e2 */ ".notdef",
308 /* 00e3 */ "ordfeminine",
309 /* 00e4 */ ".notdef",
310 /* 00e5 */ ".notdef",
311 /* 00e6 */ ".notdef",
312 /* 00e7 */ ".notdef",
313 /* 00e8 */ "Lslash",
314 /* 00e9 */ "Oslash",
315 /* 00ea */ "OE",
316 /* 00eb */ "ordmasculine",
317 /* 00ec */ ".notdef",
318 /* 00ed */ ".notdef",
319 /* 00ee */ ".notdef",
320 /* 00ef */ ".notdef",
321 /* 00f0 */ ".notdef",
322 /* 00f1 */ "ae",
323 /* 00f2 */ ".notdef",
324 /* 00f3 */ ".notdef",
325 /* 00f4 */ ".notdef",
326 /* 00f5 */ "dotlessi",
327 /* 00f6 */ ".notdef",
328 /* 00f7 */ ".notdef",
329 /* 00f8 */ "lslash",
330 /* 00f9 */ "oslash",
331 /* 00fa */ "oe",
332 /* 00fb */ "germandbls",
333 /* 00fc */ ".notdef",
334 /* 00fd */ ".notdef",
335 /* 00fe */ ".notdef",
336 /* 00ff */ ".notdef"
338 static void setStdEnc(char *encoding[256]) {
339 copyenc(encoding,AdobeStandardEncoding);
342 static void setLatin1Enc(char *encoding[256]) {
343 static char *latin1enc[] = {
344 /* 0000 */ ".notdef",
345 /* 0001 */ ".notdef",
346 /* 0002 */ ".notdef",
347 /* 0003 */ ".notdef",
348 /* 0004 */ ".notdef",
349 /* 0005 */ ".notdef",
350 /* 0006 */ ".notdef",
351 /* 0007 */ ".notdef",
352 /* 0008 */ ".notdef",
353 /* 0009 */ ".notdef",
354 /* 000a */ ".notdef",
355 /* 000b */ ".notdef",
356 /* 000c */ ".notdef",
357 /* 000d */ ".notdef",
358 /* 000e */ ".notdef",
359 /* 000f */ ".notdef",
360 /* 0010 */ ".notdef",
361 /* 0011 */ ".notdef",
362 /* 0012 */ ".notdef",
363 /* 0013 */ ".notdef",
364 /* 0014 */ ".notdef",
365 /* 0015 */ ".notdef",
366 /* 0016 */ ".notdef",
367 /* 0017 */ ".notdef",
368 /* 0018 */ ".notdef",
369 /* 0019 */ ".notdef",
370 /* 001a */ ".notdef",
371 /* 001b */ ".notdef",
372 /* 001c */ ".notdef",
373 /* 001d */ ".notdef",
374 /* 001e */ ".notdef",
375 /* 001f */ ".notdef",
376 /* 0020 */ "space",
377 /* 0021 */ "exclam",
378 /* 0022 */ "quotedbl",
379 /* 0023 */ "numbersign",
380 /* 0024 */ "dollar",
381 /* 0025 */ "percent",
382 /* 0026 */ "ampersand",
383 /* 0027 */ "quoteright",
384 /* 0028 */ "parenleft",
385 /* 0029 */ "parenright",
386 /* 002a */ "asterisk",
387 /* 002b */ "plus",
388 /* 002c */ "comma",
389 /* 002d */ "hyphen",
390 /* 002e */ "period",
391 /* 002f */ "slash",
392 /* 0030 */ "zero",
393 /* 0031 */ "one",
394 /* 0032 */ "two",
395 /* 0033 */ "three",
396 /* 0034 */ "four",
397 /* 0035 */ "five",
398 /* 0036 */ "six",
399 /* 0037 */ "seven",
400 /* 0038 */ "eight",
401 /* 0039 */ "nine",
402 /* 003a */ "colon",
403 /* 003b */ "semicolon",
404 /* 003c */ "less",
405 /* 003d */ "equal",
406 /* 003e */ "greater",
407 /* 003f */ "question",
408 /* 0040 */ "at",
409 /* 0041 */ "A",
410 /* 0042 */ "B",
411 /* 0043 */ "C",
412 /* 0044 */ "D",
413 /* 0045 */ "E",
414 /* 0046 */ "F",
415 /* 0047 */ "G",
416 /* 0048 */ "H",
417 /* 0049 */ "I",
418 /* 004a */ "J",
419 /* 004b */ "K",
420 /* 004c */ "L",
421 /* 004d */ "M",
422 /* 004e */ "N",
423 /* 004f */ "O",
424 /* 0050 */ "P",
425 /* 0051 */ "Q",
426 /* 0052 */ "R",
427 /* 0053 */ "S",
428 /* 0054 */ "T",
429 /* 0055 */ "U",
430 /* 0056 */ "V",
431 /* 0057 */ "W",
432 /* 0058 */ "X",
433 /* 0059 */ "Y",
434 /* 005a */ "Z",
435 /* 005b */ "bracketleft",
436 /* 005c */ "backslash",
437 /* 005d */ "bracketright",
438 /* 005e */ "asciicircum",
439 /* 005f */ "underscore",
440 /* 0060 */ "grave",
441 /* 0061 */ "a",
442 /* 0062 */ "b",
443 /* 0063 */ "c",
444 /* 0064 */ "d",
445 /* 0065 */ "e",
446 /* 0066 */ "f",
447 /* 0067 */ "g",
448 /* 0068 */ "h",
449 /* 0069 */ "i",
450 /* 006a */ "j",
451 /* 006b */ "k",
452 /* 006c */ "l",
453 /* 006d */ "m",
454 /* 006e */ "n",
455 /* 006f */ "o",
456 /* 0070 */ "p",
457 /* 0071 */ "q",
458 /* 0072 */ "r",
459 /* 0073 */ "s",
460 /* 0074 */ "t",
461 /* 0075 */ "u",
462 /* 0076 */ "v",
463 /* 0077 */ "w",
464 /* 0078 */ "x",
465 /* 0079 */ "y",
466 /* 007a */ "z",
467 /* 007b */ "braceleft",
468 /* 007c */ "bar",
469 /* 007d */ "braceright",
470 /* 007e */ "asciitilde",
471 /* 007f */ ".notdef",
472 /* 0080 */ ".notdef",
473 /* 0081 */ ".notdef",
474 /* 0082 */ ".notdef",
475 /* 0083 */ ".notdef",
476 /* 0084 */ ".notdef",
477 /* 0085 */ ".notdef",
478 /* 0086 */ ".notdef",
479 /* 0087 */ ".notdef",
480 /* 0088 */ ".notdef",
481 /* 0089 */ ".notdef",
482 /* 008a */ ".notdef",
483 /* 008b */ ".notdef",
484 /* 008c */ ".notdef",
485 /* 008d */ ".notdef",
486 /* 008e */ ".notdef",
487 /* 008f */ ".notdef",
488 /* 0090 */ "dotlessi", /* Um, Adobe's Latin1 has some extra chars */
489 /* 0091 */ "grave",
490 /* 0092 */ "accute", /* This is a duplicate... */
491 /* 0093 */ "circumflex",
492 /* 0094 */ "tilde",
493 /* 0095 */ "macron",
494 /* 0096 */ "breve",
495 /* 0097 */ "dotaccent",
496 /* 0098 */ "dieresis",
497 /* 0099 */ ".notdef",
498 /* 009a */ "ring",
499 /* 009b */ "cedilla",
500 /* 009c */ ".notdef",
501 /* 009d */ "hungarumlaut",
502 /* 009e */ "ogonek",
503 /* 009f */ "caron",
504 /* 00a0 */ "space",
505 /* 00a1 */ "exclamdown",
506 /* 00a2 */ "cent",
507 /* 00a3 */ "sterling",
508 /* 00a4 */ "currency",
509 /* 00a5 */ "yen",
510 /* 00a6 */ "brokenbar",
511 /* 00a7 */ "section",
512 /* 00a8 */ "dieresis",
513 /* 00a9 */ "copyright",
514 /* 00aa */ "ordfeminine",
515 /* 00ab */ "guillemotleft",
516 /* 00ac */ "logicalnot",
517 /* 00ad */ "hyphen",
518 /* 00ae */ "registered",
519 /* 00af */ "macron",
520 /* 00b0 */ "degree",
521 /* 00b1 */ "plusminus",
522 /* 00b2 */ "twosuperior",
523 /* 00b3 */ "threesuperior",
524 /* 00b4 */ "acute",
525 /* 00b5 */ "mu",
526 /* 00b6 */ "paragraph",
527 /* 00b7 */ "periodcentered",
528 /* 00b8 */ "cedilla",
529 /* 00b9 */ "onesuperior",
530 /* 00ba */ "ordmasculine",
531 /* 00bb */ "guillemotright",
532 /* 00bc */ "onequarter",
533 /* 00bd */ "onehalf",
534 /* 00be */ "threequarters",
535 /* 00bf */ "questiondown",
536 /* 00c0 */ "Agrave",
537 /* 00c1 */ "Aacute",
538 /* 00c2 */ "Acircumflex",
539 /* 00c3 */ "Atilde",
540 /* 00c4 */ "Adieresis",
541 /* 00c5 */ "Aring",
542 /* 00c6 */ "AE",
543 /* 00c7 */ "Ccedilla",
544 /* 00c8 */ "Egrave",
545 /* 00c9 */ "Eacute",
546 /* 00ca */ "Ecircumflex",
547 /* 00cb */ "Edieresis",
548 /* 00cc */ "Igrave",
549 /* 00cd */ "Iacute",
550 /* 00ce */ "Icircumflex",
551 /* 00cf */ "Idieresis",
552 /* 00d0 */ "Eth",
553 /* 00d1 */ "Ntilde",
554 /* 00d2 */ "Ograve",
555 /* 00d3 */ "Oacute",
556 /* 00d4 */ "Ocircumflex",
557 /* 00d5 */ "Otilde",
558 /* 00d6 */ "Odieresis",
559 /* 00d7 */ "multiply",
560 /* 00d8 */ "Oslash",
561 /* 00d9 */ "Ugrave",
562 /* 00da */ "Uacute",
563 /* 00db */ "Ucircumflex",
564 /* 00dc */ "Udieresis",
565 /* 00dd */ "Yacute",
566 /* 00de */ "Thorn",
567 /* 00df */ "germandbls",
568 /* 00e0 */ "agrave",
569 /* 00e1 */ "aacute",
570 /* 00e2 */ "acircumflex",
571 /* 00e3 */ "atilde",
572 /* 00e4 */ "adieresis",
573 /* 00e5 */ "aring",
574 /* 00e6 */ "ae",
575 /* 00e7 */ "ccedilla",
576 /* 00e8 */ "egrave",
577 /* 00e9 */ "eacute",
578 /* 00ea */ "ecircumflex",
579 /* 00eb */ "edieresis",
580 /* 00ec */ "igrave",
581 /* 00ed */ "iacute",
582 /* 00ee */ "icircumflex",
583 /* 00ef */ "idieresis",
584 /* 00f0 */ "eth",
585 /* 00f1 */ "ntilde",
586 /* 00f2 */ "ograve",
587 /* 00f3 */ "oacute",
588 /* 00f4 */ "ocircumflex",
589 /* 00f5 */ "otilde",
590 /* 00f6 */ "odieresis",
591 /* 00f7 */ "divide",
592 /* 00f8 */ "oslash",
593 /* 00f9 */ "ugrave",
594 /* 00fa */ "uacute",
595 /* 00fb */ "ucircumflex",
596 /* 00fc */ "udieresis",
597 /* 00fd */ "yacute",
598 /* 00fe */ "thorn",
599 /* 00ff */ "ydieresis"
601 copyenc(encoding,latin1enc);
604 char *AdobeExpertEncoding[] = {
605 /* 0000 */ ".notdef",
606 /* 0001 */ ".notdef",
607 /* 0002 */ ".notdef",
608 /* 0003 */ ".notdef",
609 /* 0004 */ ".notdef",
610 /* 0005 */ ".notdef",
611 /* 0006 */ ".notdef",
612 /* 0007 */ ".notdef",
613 /* 0008 */ ".notdef",
614 /* 0009 */ ".notdef",
615 /* 000a */ ".notdef",
616 /* 000b */ ".notdef",
617 /* 000c */ ".notdef",
618 /* 000d */ ".notdef",
619 /* 000e */ ".notdef",
620 /* 000f */ ".notdef",
621 /* 0010 */ ".notdef",
622 /* 0011 */ ".notdef",
623 /* 0012 */ ".notdef",
624 /* 0013 */ ".notdef",
625 /* 0014 */ ".notdef",
626 /* 0015 */ ".notdef",
627 /* 0016 */ ".notdef",
628 /* 0017 */ ".notdef",
629 /* 0018 */ ".notdef",
630 /* 0019 */ ".notdef",
631 /* 001a */ ".notdef",
632 /* 001b */ ".notdef",
633 /* 001c */ ".notdef",
634 /* 001d */ ".notdef",
635 /* 001e */ ".notdef",
636 /* 001f */ ".notdef",
637 /* 0020 */ "space",
638 /* 0021 */ "exclamsmall",
639 /* 0022 */ "Hungarumlautsmal",
640 /* 0023 */ ".notdef",
641 /* 0024 */ "dollaroldstyle",
642 /* 0025 */ "dollarsuperior",
643 /* 0026 */ "ampersandsmall",
644 /* 0027 */ "Acutesmall",
645 /* 0028 */ "parenleftsuperior",
646 /* 0029 */ "parenrightsuperior",
647 /* 002a */ "twodotenleader",
648 /* 002b */ "onedotenleader",
649 /* 002c */ "comma",
650 /* 002d */ "hyphen",
651 /* 002e */ "period",
652 /* 002f */ "fraction",
653 /* 0030 */ "zerooldstyle",
654 /* 0031 */ "oneoldstyle",
655 /* 0032 */ "twooldstyle",
656 /* 0033 */ "threeoldstyle",
657 /* 0034 */ "fouroldstyle",
658 /* 0035 */ "fiveoldstyle",
659 /* 0036 */ "sixoldstyle",
660 /* 0037 */ "sevenoldstyle",
661 /* 0038 */ "eightoldstyle",
662 /* 0039 */ "nineoldstyle",
663 /* 003a */ "colon",
664 /* 003b */ "semicolon",
665 /* 003c */ "commasuperior",
666 /* 003d */ "threequartersemdash",
667 /* 003e */ "periodsuperior",
668 /* 003f */ "questionsmall",
669 /* 0040 */ ".notdef",
670 /* 0041 */ "asuperior",
671 /* 0042 */ "bsuperior",
672 /* 0043 */ "centsuperior",
673 /* 0044 */ "dsuperior",
674 /* 0045 */ "esuperior",
675 /* 0046 */ ".notdef",
676 /* 0047 */ ".notdef",
677 /* 0048 */ ".notdef",
678 /* 0049 */ "isuperior",
679 /* 004a */ ".notdef",
680 /* 004b */ ".notdef",
681 /* 004c */ "lsuperior",
682 /* 004d */ "msuperior",
683 /* 004e */ "nsuperior",
684 /* 004f */ "osuperior",
685 /* 0050 */ ".notdef",
686 /* 0051 */ ".notdef",
687 /* 0052 */ "rsuperior",
688 /* 0053 */ "ssuperior",
689 /* 0054 */ "tsuperior",
690 /* 0055 */ ".notdef",
691 /* 0056 */ "ff",
692 /* 0057 */ "fi",
693 /* 0058 */ "fl",
694 /* 0059 */ "ffi",
695 /* 005a */ "ffl",
696 /* 005b */ "parenleftinferior",
697 /* 005c */ ".notdef",
698 /* 005d */ "parenrightinferior",
699 /* 005e */ "Circumflexsmall",
700 /* 005f */ "hyphensuperior",
701 /* 0060 */ "Gravesmall",
702 /* 0061 */ "Asmall",
703 /* 0062 */ "Bsmall",
704 /* 0063 */ "Csmall",
705 /* 0064 */ "Dsmall",
706 /* 0065 */ "Esmall",
707 /* 0066 */ "Fsmall",
708 /* 0067 */ "Gsmall",
709 /* 0068 */ "Hsmall",
710 /* 0069 */ "Ismall",
711 /* 006a */ "Jsmall",
712 /* 006b */ "Ksmall",
713 /* 006c */ "Lsmall",
714 /* 006d */ "Msmall",
715 /* 006e */ "Nsmall",
716 /* 006f */ "Osmall",
717 /* 0070 */ "Psmall",
718 /* 0071 */ "Qsmall",
719 /* 0072 */ "Rsmall",
720 /* 0073 */ "Ssmall",
721 /* 0074 */ "Tsmall",
722 /* 0075 */ "Usmall",
723 /* 0076 */ "Vsmall",
724 /* 0077 */ "Wsmall",
725 /* 0078 */ "Xsmall",
726 /* 0079 */ "Ysmall",
727 /* 007a */ "Zsmall",
728 /* 007b */ "colonmonetary",
729 /* 007c */ "onefitted",
730 /* 007d */ "rupiah",
731 /* 007e */ "Tildesmall",
732 /* 007f */ ".notdef",
733 /* 0080 */ ".notdef",
734 /* 0081 */ ".notdef",
735 /* 0082 */ ".notdef",
736 /* 0083 */ ".notdef",
737 /* 0084 */ ".notdef",
738 /* 0085 */ ".notdef",
739 /* 0086 */ ".notdef",
740 /* 0087 */ ".notdef",
741 /* 0088 */ ".notdef",
742 /* 0089 */ ".notdef",
743 /* 008a */ ".notdef",
744 /* 008b */ ".notdef",
745 /* 008c */ ".notdef",
746 /* 008d */ ".notdef",
747 /* 008e */ ".notdef",
748 /* 008f */ ".notdef",
749 /* 0090 */ ".notdef",
750 /* 0091 */ ".notdef",
751 /* 0092 */ ".notdef",
752 /* 0093 */ ".notdef",
753 /* 0094 */ ".notdef",
754 /* 0095 */ ".notdef",
755 /* 0096 */ ".notdef",
756 /* 0097 */ ".notdef",
757 /* 0098 */ ".notdef",
758 /* 0099 */ ".notdef",
759 /* 009a */ ".notdef",
760 /* 009b */ ".notdef",
761 /* 009c */ ".notdef",
762 /* 009d */ ".notdef",
763 /* 009e */ ".notdef",
764 /* 009f */ ".notdef",
765 /* 00a0 */ ".notdef",
766 /* 00a1 */ "exclamdownsmall",
767 /* 00a2 */ "centoldstyle",
768 /* 00a3 */ "Lslashsmall",
769 /* 00a4 */ ".notdef",
770 /* 00a5 */ ".notdef",
771 /* 00a6 */ "Scaronsmall",
772 /* 00a7 */ "Zcaronsmall",
773 /* 00a8 */ "Dieresissmall",
774 /* 00a9 */ "Brevesmall",
775 /* 00aa */ "Caronsmall",
776 /* 00ab */ ".notdef",
777 /* 00ac */ "Dotaccentsmall",
778 /* 00ad */ ".notdef",
779 /* 00ae */ ".notdef",
780 /* 00af */ "Macronsmall",
781 /* 00b0 */ ".notdef",
782 /* 00b1 */ ".notdef",
783 /* 00b2 */ "figuredash",
784 /* 00b3 */ "hypheninferior",
785 /* 00b4 */ ".notdef",
786 /* 00b5 */ ".notdef",
787 /* 00b6 */ "Ogoneksmall",
788 /* 00b7 */ "Ringsmall",
789 /* 00b8 */ "Cedillasmall",
790 /* 00b9 */ ".notdef",
791 /* 00ba */ ".notdef",
792 /* 00bb */ ".notdef",
793 /* 00bc */ "onequarter",
794 /* 00bd */ "onehalf",
795 /* 00be */ "threequarters",
796 /* 00bf */ "questiondownsmall",
797 /* 00c0 */ "oneeighth",
798 /* 00c1 */ "threeeighths",
799 /* 00c2 */ "fiveeighths",
800 /* 00c3 */ "seveneighths",
801 /* 00c4 */ "onethird",
802 /* 00c5 */ "twothirds",
803 /* 00c6 */ ".notdef",
804 /* 00c7 */ ".notdef",
805 /* 00c8 */ "zerosuperior",
806 /* 00c9 */ "onesuperior",
807 /* 00ca */ "twosuperior",
808 /* 00cb */ "threesuperior",
809 /* 00cc */ "foursuperior",
810 /* 00cd */ "fivesuperior",
811 /* 00ce */ "sixsuperior",
812 /* 00cf */ "sevensuperior",
813 /* 00d0 */ "eightsuperior",
814 /* 00d1 */ "ninesuperior",
815 /* 00d2 */ "zeroinferior",
816 /* 00d3 */ "oneinferior",
817 /* 00d4 */ "twoinferior",
818 /* 00d5 */ "threeinferior",
819 /* 00d6 */ "fourinferior",
820 /* 00d7 */ "fiveinferior",
821 /* 00d8 */ "sixinferior",
822 /* 00d9 */ "seveninferior",
823 /* 00da */ "eightinferior",
824 /* 00db */ "nineinferior",
825 /* 00dc */ "centinferior",
826 /* 00dd */ "dollarinferior",
827 /* 00de */ "periodinferior",
828 /* 00df */ "commainferior",
829 /* 00e0 */ "Agravesmall",
830 /* 00e1 */ "Aacutesmall",
831 /* 00e2 */ "Acircumflexsmall",
832 /* 00e3 */ "Atildesmall",
833 /* 00e4 */ "Adieresissmall",
834 /* 00e5 */ "Aringsmall",
835 /* 00e6 */ "AEsmall",
836 /* 00e7 */ "Ccedillasmall",
837 /* 00e8 */ "Egravesmall",
838 /* 00e9 */ "Eacutesmall",
839 /* 00ea */ "Ecircumflexsmall",
840 /* 00eb */ "Edieresissmall",
841 /* 00ec */ "Igravesmall",
842 /* 00ed */ "Iacutesmall",
843 /* 00ee */ "Icircumflexsmall",
844 /* 00ef */ "Idieresissmall",
845 /* 00f0 */ "Ethsmall",
846 /* 00f1 */ "Ntildesmall",
847 /* 00f2 */ "Ogravesmall",
848 /* 00f3 */ "Oacutesmall",
849 /* 00f4 */ "Ocircumflexsmall",
850 /* 00f5 */ "Otildesmall",
851 /* 00f6 */ "Odieresissmall",
852 /* 00f7 */ "OEsmall",
853 /* 00f8 */ "Oslashsmall",
854 /* 00f9 */ "Ugravesmall",
855 /* 00fa */ "Uacutesmall",
856 /* 00fb */ "Ucircumflexsmall",
857 /* 00fc */ "Udieresissmall",
858 /* 00fd */ "Yacutesmall",
859 /* 00fe */ "Thornsmall",
860 /* 00ff */ "Ydieresissmall"
863 static struct fontdict *MakeEmptyFont(void) {
864 struct fontdict *ret;
866 ret = gcalloc(1,sizeof(struct fontdict));
867 ret->fontinfo = gcalloc(1,sizeof(struct fontinfo));
868 ret->chars = gcalloc(1,sizeof(struct pschars));
869 ret->private = gcalloc(1,sizeof(struct private));
870 ret->private->subrs = gcalloc(1,sizeof(struct pschars));
871 ret->private->private = gcalloc(1,sizeof(struct psdict));
872 ret->private->leniv = 4;
873 ret->encoding_name = &custom;
874 ret->fontinfo->fstype = -1;
875 return( ret );
878 static struct fontdict *PSMakeEmptyFont(void) {
879 struct fontdict *ret;
881 ret = gcalloc(1,sizeof(struct fontdict));
882 ret->fontinfo = gcalloc(1,sizeof(struct fontinfo));
883 ret->chars = gcalloc(1,sizeof(struct pschars));
884 ret->private = gcalloc(1,sizeof(struct private));
885 ret->private->subrs = gcalloc(1,sizeof(struct pschars));
886 ret->private->private = gcalloc(1,sizeof(struct psdict));
887 ret->private->leniv = 4;
888 ret->charprocs = gcalloc(1,sizeof(struct charprocs));
889 ret->encoding_name = &custom;
890 ret->fontinfo->fstype = -1;
891 return( ret );
894 static char *myfgets(char *str, int len, FILE *file) {
895 char *pt, *end;
896 int ch=0;
898 for ( pt = str, end = str+len-1; pt<end && (ch=getc(file))!=EOF && ch!='\r' && ch!='\n';
899 *pt++ = ch );
900 if ( ch=='\n' )
901 *pt++ = '\n';
902 else if ( ch=='\r' ) {
903 *pt++ = '\r';
904 if ((ch=getc(file))!='\n' )
905 ungetc(ch,file);
906 else
907 *pt++ = '\n';
909 if ( pt==str )
910 return( NULL );
911 *pt = '\0';
912 return( str );
915 static char *myfgetsNoNulls(char *str, int len, FILE *file) {
916 char *pt, *end;
917 int ch=0;
919 for ( pt = str, end = str+len-1; pt<end && (ch=getc(file))!=EOF && ch!='\r' && ch!='\n'; ) {
920 if ( ch!='\0' )
921 *pt++ = ch;
923 if ( ch=='\n' )
924 *pt++ = '\n';
925 else if ( ch=='\r' ) {
926 *pt++ = '\r';
927 if ((ch=getc(file))!='\n' )
928 ungetc(ch,file);
929 else
930 *pt++ = '\n';
932 if ( pt==str )
933 return( NULL );
934 *pt = '\0';
935 return( str );
938 static char *getstring(char *start,FILE *in) {
939 char *end, *ret;
940 int parencnt=0, len=0;
941 char buffer[512];
943 forever {
944 while ( *start!='\0' && *start!='(' ) ++start;
945 if ( *start=='\0' ) {
946 if ( myfgetsNoNulls(buffer,sizeof(buffer),in)==NULL )
947 return( copy(""));
948 start = buffer;
949 } else
950 break;
952 ++start;
953 ret = NULL; len = 1;
954 forever {
955 for ( end = start; *end!='\0' && (*end!=')' || parencnt>0); ++end ) {
956 if ( *end=='\\' && (end[1]=='(' || end[1]==')'))
957 ++end;
958 else if ( *end=='(' ) ++parencnt;
959 else if ( *end==')' ) --parencnt;
961 if ( end>start ) {
962 if ( ret==NULL )
963 ret = galloc(end-start+1);
964 else
965 ret = grealloc(ret,len+end-start);
966 strncpy(ret+len-1,start,end-start);
967 len += end-start;
968 ret[len-1] = '\0';
970 if ( *end!='\0' )
971 break;
972 if ( myfgetsNoNulls(buffer,sizeof(buffer),in)==NULL )
973 return( ret );
974 start = buffer;
976 return( ret );
979 static char *gettoken(char *start) {
980 char *end, *ret;
982 while ( *start!='\0' && *start!='/' && *start!='(' ) ++start;
983 if ( *start=='/' || *start=='(' ) ++start;
984 for ( end = start; *end!='\0' && !isspace(*end) && *end!='[' && *end!='/' && *end!='{' && *end!='(' && *end!=')'; ++end );
985 ret = galloc(end-start+1);
986 if ( end>start )
987 strncpy(ret,start,end-start);
988 ret[end-start] = '\0';
989 return( ret );
992 static int getbool(char *start) {
994 while ( isspace(*start) ) ++start;
995 if ( *start=='T' || *start=='t' )
996 return( 1 );
998 return( 0 );
1001 static void fillintarray(int *array,char *start,int maxentries) {
1002 int i;
1003 char *end;
1005 while ( *start!='\0' && *start!='[' && *start!='{' ) ++start;
1006 if ( *start=='[' || *start=='{' ) ++start;
1007 for ( i=0; i<maxentries && *start!=']' && *start!='}'; ++i ) {
1008 array[i] = (int) strtod(start,&end);
1009 if ( start==end )
1010 return;
1011 start = end;
1012 while ( isspace(*start) ) ++start;
1016 static void fillrealarray(real *array,char *start,int maxentries) {
1017 int i;
1018 char *end;
1020 while ( *start!='\0' && *start!='[' && *start!='{' ) ++start;
1021 if ( *start=='[' || *start=='{' ) ++start;
1022 for ( i=0; i<maxentries && *start!=']' && *start!='}'; ++i ) {
1023 while ( isspace( *start )) ++start;
1024 if ( isdigit(*start) || *start=='-' || *start=='.' )
1025 array[i] = strtod(start,&end);
1026 else if ( strncmp(start,"div",3)==0 && i>=2 ) {
1027 /* Some of Luc Devroye's fonts have a "div" in the FontMatrix */
1028 array[i-2] /= array[i-1];
1029 i -= 2;
1030 end = start+3;
1031 } else
1032 return;
1033 if ( start==end )
1034 return;
1035 start = end;
1036 while ( isspace(*start) ) ++start;
1040 static void InitDict(struct psdict *dict,char *line) {
1041 while ( *line!='/' && *line!='\0' ) ++line;
1042 while ( !isspace(*line) && *line!='\0' ) ++line;
1043 dict->cnt += strtol(line,NULL,10);
1044 if ( dict->next>0 ) { int i; /* Shouldn't happen, but did in a bad file */
1045 dict->keys = grealloc(dict->keys,dict->cnt*sizeof(char *));
1046 dict->values = grealloc(dict->values,dict->cnt*sizeof(char *));
1047 for ( i=dict->next; i<dict->cnt; ++i ) {
1048 dict->keys[i] = NULL; dict->values[i] = NULL;
1050 } else {
1051 dict->keys = gcalloc(dict->cnt,sizeof(char *));
1052 dict->values = gcalloc(dict->cnt,sizeof(char *));
1056 static void InitChars(struct pschars *chars,char *line) {
1057 while ( *line!='/' && *line!='\0' ) ++line;
1058 while ( !isspace(*line) && *line!='\0' ) ++line;
1059 chars->cnt = strtol(line,NULL,10);
1060 if ( chars->cnt>0 ) {
1061 chars->keys = gcalloc(chars->cnt,sizeof(char *));
1062 chars->values = gcalloc(chars->cnt,sizeof(char *));
1063 chars->lens = gcalloc(chars->cnt,sizeof(int));
1064 ff_progress_change_total(chars->cnt);
1068 static void InitCharProcs(struct charprocs *cp, char *line) {
1069 while ( *line!='/' && *line!='\0' ) ++line;
1070 while ( !isspace(*line) && *line!='\0' ) ++line;
1071 cp->cnt = strtol(line,NULL,10);
1072 if ( cp->cnt>0 ) {
1073 cp->keys = gcalloc(cp->cnt,sizeof(char *));
1074 cp->values = gcalloc(cp->cnt,sizeof(SplineChar *));
1075 ff_progress_change_total(cp->cnt);
1079 static int mycmp(char *str,char *within, char *end ) {
1080 while ( within<end ) {
1081 if ( *str!=*within )
1082 return( *str-*within );
1083 ++str; ++within;
1085 return( *str=='\0'?0:1 );
1088 static void ContinueValue(struct fontparse *fp, struct psdict *dict, char *line) {
1089 int incomment = false;
1091 while ( *line ) {
1092 if ( !fp->instring && fp->depth==0 &&
1093 (strncmp(line,"def",3)==0 ||
1094 strncmp(line,"|-",2)==0 || strncmp(line,"ND",2)==0)) {
1095 while ( 1 ) {
1096 while ( fp->vpt>fp->vbuf+1 && isspace(fp->vpt[-1]) )
1097 --fp->vpt;
1098 if ( fp->vpt>fp->vbuf+8 && strncmp(fp->vpt-8,"noaccess",8)==0 )
1099 fp->vpt -= 8;
1100 else if ( fp->vpt>fp->vbuf+8 && strncmp(fp->vpt-8,"readonly",8)==0 )
1101 fp->vpt -= 8;
1102 else if ( fp->vpt>fp->vbuf+4 && strncmp(fp->vpt-4,"bind",4)==0 )
1103 fp->vpt -= 4;
1104 else
1105 break;
1107 /* In some URW fonts (Nimbus Sans L, n019003l) we get a complex */
1108 /* expression rather than just an array. This is ok. The expression */
1109 /* converts itself into an array. We could just truncate to the */
1110 /* default array, but I don't see any reason to do so */
1111 if ( fp->pending_parse!=NULL ) {
1112 *fp->pending_parse = copyn(fp->vbuf,fp->vpt-fp->vbuf);
1113 fp->pending_parse = NULL;
1114 } else {
1115 dict->values[dict->next] = copyn(fp->vbuf,fp->vpt-fp->vbuf);
1116 ++dict->next;
1118 fp->vpt = fp->vbuf;
1119 fp->multiline = false;
1120 return;
1122 if ( fp->vpt>=fp->vmax ) {
1123 int len = fp->vmax-fp->vbuf+1000, off=fp->vpt-fp->vbuf;
1124 fp->vbuf = grealloc(fp->vbuf,len);
1125 fp->vpt = fp->vbuf+off;
1126 fp->vmax = fp->vbuf+len;
1128 if ( fp->instring ) {
1129 if ( *line==')' ) --fp->instring;
1130 } else if ( incomment ) {
1131 /* Do Nothing */;
1132 } else if ( *line=='(' )
1133 ++fp->instring;
1134 else if ( *line=='%' )
1135 incomment = true;
1136 else if ( *line=='[' || *line=='{' )
1137 ++fp->depth;
1138 else if ( *line=='}' || *line==']' )
1139 --fp->depth;
1140 *fp->vpt++ = *line++;
1144 static void AddValue(struct fontparse *fp, struct psdict *dict, char *line, char *endtok) {
1145 char *pt;
1147 if ( dict!=NULL ) {
1148 if ( dict->next>=dict->cnt ) {
1149 dict->cnt += 10;
1150 dict->keys = grealloc(dict->keys,dict->cnt*sizeof(char *));
1151 dict->values = grealloc(dict->values,dict->cnt*sizeof(char *));
1153 dict->keys[dict->next] = copyn(line+1,endtok-(line+1));
1155 pt = line+strlen(line)-1;
1156 while ( isspace(*endtok)) ++endtok;
1157 while ( pt>endtok && isspace(*pt)) --pt;
1158 ++pt;
1159 if ( strncmp(pt-3,"def",3)==0 )
1160 pt -= 3;
1161 else if ( strncmp(pt-2,"|-",2)==0 || strncmp(pt-2,"ND",2)==0 )
1162 pt -= 2;
1163 else {
1164 fp->multiline = true;
1165 ContinueValue(fp,dict,endtok);
1166 return;
1168 forever {
1169 while ( pt-1>endtok && isspace(pt[-1])) --pt;
1170 if ( pt-8>endtok && strncmp(pt-8,"noaccess",8)==0 )
1171 pt -= 8;
1172 else if ( pt-8>endtok && strncmp(pt-8,"readonly",8)==0 )
1173 pt -= 8;
1174 else if ( pt-4>endtok && strncmp(pt-4,"bind",4)==0 )
1175 pt -= 4;
1176 else
1177 break;
1179 if ( dict!=NULL ) {
1180 dict->values[dict->next] = copyn(endtok,pt-endtok);
1181 ++dict->next;
1182 } else {
1183 *fp->pending_parse = copyn(endtok,pt-endtok);
1184 fp->pending_parse = NULL;
1188 static int hex(int ch1, int ch2) {
1189 if ( ch1>='0' && ch1<='9' )
1190 ch1 -= '0';
1191 else if ( ch1>='a' )
1192 ch1 -= 'a'-10;
1193 else
1194 ch1 -= 'A'-10;
1195 if ( ch2>='0' && ch2<='9' )
1196 ch2 -= '0';
1197 else if ( ch2>='a' )
1198 ch2 -= 'a'-10;
1199 else
1200 ch2 -= 'A'-10;
1201 return( (ch1<<4)|ch2 );
1204 unsigned short r;
1205 #define c1 52845
1206 #define c2 22719
1208 static void initcode(void) {
1209 r = 55665;
1212 static int decode(unsigned char cypher) {
1213 unsigned char plain = ( cypher ^ (r>>8));
1214 r = (cypher + r) * c1 + c2;
1215 return( plain );
1218 static void dumpzeros(FILE *out, unsigned char *zeros, int zcnt) {
1219 while ( --zcnt >= 0 )
1220 fputc(*zeros++,out);
1223 static void decodestr(unsigned char *str, int len) {
1224 unsigned short r = 4330;
1225 unsigned char plain, cypher;
1227 while ( len-->0 ) {
1228 cypher = *str;
1229 plain = ( cypher ^ (r>>8));
1230 r = (cypher + r) * c1 + c2;
1231 *str++ = plain;
1235 static void findstring(struct fontparse *fp,struct pschars *subrs,int index,char *nametok,char *str) {
1236 char buffer[1024], *bpt, *bs, *end = buffer+sizeof(buffer)-1;
1237 int val;
1239 while ( isspace(*str)) ++str;
1240 if ( *str=='(' ) {
1241 ++str;
1242 bpt = buffer;
1243 while ( *str!=')' && *str!='\0' ) {
1244 if ( *str!='\\' )
1245 val = *str++;
1246 else {
1247 if ( isdigit( *++str )) {
1248 val = *str++-'0';
1249 if ( isdigit( *str )) {
1250 val = (val<<3) | (*str++-'0');
1251 if ( isdigit( *str ))
1252 val = (val<<3) | (*str++-'0');
1254 } else
1255 val = *str++;
1257 if ( bpt<end )
1258 *bpt++ = val;
1260 decodestr((unsigned char *) buffer,bpt-buffer);
1261 bs = buffer + fp->fd->private->leniv;
1262 if ( bpt<bs ) bs=bpt; /* garbage */
1263 subrs->lens[index] = bpt-bs;
1264 subrs->keys[index] = copy(nametok);
1265 subrs->values[index] = galloc(bpt-bs);
1266 memcpy(subrs->values[index],bs,bpt-bs);
1267 if ( index>=subrs->next ) subrs->next = index+1;
1271 /* Type42 charstrings are actually numbers */
1272 static void findnumbers(struct fontparse *fp,struct pschars *chars,char *str) {
1273 int val;
1274 char *end;
1275 (void)fp;
1276 forever {
1277 int index = chars->next;
1278 char *namestrt;
1280 while ( isspace(*str)) ++str;
1281 if ( *str!='/' )
1282 break;
1283 namestrt = ++str;
1284 while ( isalnum(*str) || *str=='.' ) ++str;
1285 *str = '\0';
1286 index = chars->next;
1288 ++str;
1289 val = strtol(str,&end,10);
1290 chars->lens[index] = 0;
1291 chars->keys[index] = copy(namestrt);
1292 chars->values[index] = (void *) (intpt) val;
1293 chars->next = index+1;
1294 str = end;
1295 while ( isspace(*str)) ++str;
1296 if ( str[0]=='d' && str[1]=='e' && str[2]=='f' )
1297 str += 3;
1301 static char *rmbinary(char *line) {
1302 char *pt;
1304 for ( pt=line; *pt; ++pt ) {
1305 if (( *pt<' ' || *pt>=0x7f ) && *pt!='\n' ) {
1306 if ( strlen(pt)>5 ) {
1307 pt[0] = '.';
1308 pt[1] = '.';
1309 pt[2] = '.';
1310 pt[3] = '\n';
1311 pt[4] = '\0';
1312 } else {
1313 pt[0] = '\n';
1314 pt[1] = '\0';
1316 break;
1319 return( line );
1322 static void sfnts2tempfile(struct fontparse *fp,FILE *in,char *line) {
1323 char *pt;
1324 int instring = false, firstnibble=true, sofar=0, nibble;
1325 int complained = false;
1326 int ch=0;
1328 fp->sfnts = tmpfile();
1330 /* first finish off anything in the current line */
1331 while ( (pt=strpbrk(line,"<]" ))!=NULL ) {
1332 if ( *pt==']' )
1333 goto skip_to_eol;
1335 instring = true;
1336 for ( ++pt; *pt && *pt!='>'; ++pt ) {
1337 if ( isspace(*pt))
1338 continue;
1339 if ( isdigit(*pt))
1340 nibble = *pt-'0';
1341 else if ( *pt>='a' && *pt<='f' )
1342 nibble = *pt-'a'+10;
1343 else if ( *pt>='A' && *pt<='F' )
1344 nibble = *pt-'A'+10;
1345 else {
1346 if ( !complained ) {
1347 LogError( _("Invalid hex digit in sfnts array\n") );
1348 complained = true;
1350 ++pt;
1351 continue;
1353 if ( firstnibble ) {
1354 sofar = nibble<<4;
1355 firstnibble = false;
1356 } else {
1357 putc(sofar|nibble,fp->sfnts);
1358 sofar = 0;
1359 firstnibble = true;
1362 if ( *pt=='>' ) {
1363 if ( ftell(fp->sfnts)&1 ) { /* Strings must be contain an even number of bytes */
1364 /* But may be padded with a trailing NUL */
1365 fseek(fp->sfnts,-1,SEEK_CUR);
1367 ++pt;
1368 instring = false;
1370 line = pt;
1373 while ( (ch=getc(in))!=EOF ) {
1374 if ( ch==']' )
1375 goto skip_to_eol;
1376 if ( isspace(ch))
1377 continue;
1378 if ( !instring && ch=='<' ) {
1379 instring = true;
1380 firstnibble = true;
1381 sofar = 0;
1382 } else if ( !instring ) {
1383 if ( !complained ) {
1384 LogError( _("Invalid character outside of string in sfnts array\n") );
1385 complained = true;
1387 } else if ( instring && ch=='>' ) {
1388 if ( ftell(fp->sfnts)&1 ) { /* Strings must be contain an even number of bytes */
1389 /* But may be padded with a trailing NUL */
1390 fseek(fp->sfnts,-1,SEEK_CUR);
1392 instring = false;
1393 } else {
1394 if ( isdigit(ch))
1395 nibble = ch-'0';
1396 else if ( ch>='a' && ch<='f' )
1397 nibble = ch-'a'+10;
1398 else if ( ch>='A' && ch<='F' )
1399 nibble = ch-'A'+10;
1400 else {
1401 if ( !complained ) {
1402 LogError( _("Invalid hex digit in sfnts array\n") );
1403 complained = true;
1405 continue;
1407 if ( firstnibble ) {
1408 sofar = nibble<<4;
1409 firstnibble = false;
1410 } else {
1411 putc(sofar|nibble,fp->sfnts);
1412 sofar = 0;
1413 firstnibble = true;
1417 skip_to_eol:
1418 while ( ch!=EOF && ch!='\n' && ch!='\r' )
1419 ch = getc(in);
1420 rewind(fp->sfnts);
1423 static void ParseSimpleEncoding(struct fontparse *fp,char *line) {
1424 char tok[200], *pt;
1426 while ( *line!='\0' && *line!=']' ) {
1427 while ( isspace(*line)) ++line;
1428 if ( *line==']' )
1429 break;
1430 if ( *line!='/' ) {
1431 ++line;
1432 continue;
1434 ++line;
1435 while ( isspace(*line)) ++line;
1436 for ( pt=tok; !isspace(*line) && *line!='\0' && *line!='/' && *line!=']'; ) {
1437 if ( pt<tok+sizeof(tok)-2 )
1438 *pt++ = *line++;
1439 else
1440 ++line;
1442 *pt = '\0';
1443 if ( fp->simple_enc_pos<256 )
1444 fp->fd->encoding[fp->simple_enc_pos++] = copy(tok);
1446 if ( *line==']' ) {
1447 fp->simpleencoding = false;
1448 fp->inencoding = false;
1452 static void parseline(struct fontparse *fp,char *line,FILE *in) {
1453 char buffer[200], *pt, *endtok;
1455 while ( *line==' ' || *line=='\t' ) ++line;
1456 if ( line[0]=='%' && !fp->multiline )
1457 return;
1459 if ( fp->simpleencoding ) {
1460 ParseSimpleEncoding(fp,line);
1461 return;
1462 } else if (( fp->inencoding && strncmp(line,"dup",3)==0 ) ||
1463 ( strncmp(line,"dup ",4)==0 && isdigit(line[4]) &&
1464 strstr(line+strlen(line)-6," put")!=NULL && strchr(line,'/')!=NULL )) {
1465 /* Fontographer's type3 fonts claim to be standard, but then aren't */
1466 fp->fd->encoding_name = &custom;
1467 /* Metamorphasis has multiple entries on a line */
1468 while ( strncmp(line,"dup",3)==0 ) {
1469 char *end;
1470 int pos = strtol(line+3,&end,10);
1471 line = end;
1472 while ( isspace( *line )) ++line;
1473 if ( *line=='/' ) ++line;
1474 for ( pt = buffer; !isspace(*line); *pt++ = *line++ );
1475 *pt = '\0';
1476 if ( pos>=0 && pos<256 ) {
1477 free(fp->fd->encoding[pos]);
1478 fp->fd->encoding[pos] = copy(buffer);
1480 while ( isspace(*line)) ++line;
1481 if ( strncmp(line,"put",3)==0 ) line+=3;
1482 while ( isspace(*line)) ++line;
1484 return;
1485 } else if ( fp->inencoding && strstr(line,"for")!=NULL && strstr(line,"/.notdef")!=NULL ) {
1486 /* the T1 spec I've got doesn't allow for this, but I've seen it anyway*/
1487 /* 0 1 255 {1 index exch /.notdef put} for */
1488 /* 0 1 31 { 1 index exch /.notdef put } bind for */
1489 int i;
1490 for ( i=0; i<256; ++i )
1491 if ( fp->fd->encoding[i]==NULL )
1492 fp->fd->encoding[i] = copy(".notdef");
1493 return;
1494 } else if ( fp->inencoding && strstr(line,"Encoding")!=NULL && strstr(line,"put")!=NULL ) {
1495 /* Saw a type 3 font with lines like "Encoding 1 /_a0 put" */
1496 char *end;
1497 int pos;
1498 while ( isspace(*line)) ++line;
1499 if ( strncmp(line,"Encoding ",9)==0 ) {
1500 line+=9;
1501 pos = strtol(line,&end,10);
1502 line = end;
1503 while ( isspace(*line)) ++line;
1504 if ( *line=='/' ) {
1505 ++line;
1506 for ( pt = buffer; !isspace(*line); *pt++ = *line++ );
1507 *pt = '\0';
1508 if ( pos>=0 && pos<256 )
1509 fp->fd->encoding[pos] = copy(buffer);
1512 return;
1513 } else if ( fp->insubs ) {
1514 struct pschars *subrs = fp->fd->private->subrs;
1515 while ( isspace(*line)) ++line;
1516 if ( strncmp(line,"dup ",4)==0 ) {
1517 int i;
1518 char *ept;
1519 for ( line += 4; *line==' '; ++line );
1520 i = strtol(line,&ept,10);
1521 if ( fp->ignore )
1522 /* Do Nothing */;
1523 else if ( i<subrs->cnt ) {
1524 findstring(fp,subrs,i,NULL,ept);
1525 } else if ( !fp->alreadycomplained ) {
1526 LogError( _("Index too big (must be <%d) \"%s"), subrs->cnt, rmbinary(line));
1527 fp->alreadycomplained = true;
1529 } else if ( strncmp(line, "readonly put", 12)==0 || strncmp(line, "ND", 2)==0 || strncmp(line, "|-", 2)==0 ) {
1530 fp->insubs = false;
1531 fp->ignore = false;
1532 } else if ( *line=='\n' || *line=='\0' ) {
1533 /* Ignore blank lines */;
1534 } else if ( !fp->alreadycomplained ) {
1535 LogError( _("Didn't understand \"%s"), rmbinary(line) );
1536 fp->alreadycomplained = true;
1538 } else if ( fp->inchars ) {
1539 struct pschars *chars = fp->fd->chars;
1540 while ( isspace(*line)) ++line;
1541 if ( strncmp(line,"end",3)==0 )
1542 fp->ignore = fp->inchars = false;
1543 else if ( *line=='\n' || *line=='\0' )
1544 /* Ignore it */;
1545 else if ( *line!='/' || !(isalpha(line[1]) || line[1]=='.')) {
1546 LogError( _("No name for CharStrings dictionary \"%s"), rmbinary(line) );
1547 fp->alreadycomplained = true;
1548 } else if ( fp->ignore ) {
1549 /* Do Nothing */;
1550 } else if ( chars->next>=chars->cnt )
1551 LogError( _("Too many entries in CharStrings dictionary \"%s"), rmbinary(line) );
1552 else if ( fp->fd->fonttype==42 || fp->fd->fonttype==11 || fp->fd->cidfonttype==2 )
1553 findnumbers(fp,chars,line);
1554 else {
1555 int i = chars->next;
1556 char *namestrt = ++line;
1557 while ( isalnum(*line) || *line=='.' ) ++line;
1558 *line = '\0';
1559 findstring(fp,chars,i,namestrt,line+1);
1560 ff_progress_next();
1562 return;
1564 fp->inencoding = 0;
1566 while ( isspace(*line)) ++line;
1567 endtok = NULL;
1568 if ( *line=='/' )
1569 for ( endtok=line+1; !isspace(*endtok) && *endtok!='(' && *endtok!='/' &&
1570 *endtok!='{' && *endtok!='[' && *endtok!='\0'; ++endtok );
1572 if ( strstr(line,"/shareddict")!=NULL && strstr(line,"where")!=NULL ) {
1573 fp->infi = fp->inbb = fp->inmetrics = fp->inmetrics2 = false;
1574 fp->inprivate = fp->inblendprivate = fp->inblendfi = false;
1575 fp->skipping_mbf = true;
1576 return;
1579 if ( mycmp("Encoding",line+1,endtok)==0 && !fp->doneencoding ) {
1580 if ( strstr(endtok,"StandardEncoding")!=NULL ) {
1581 fp->fd->encoding_name = FindOrMakeEncoding("AdobeStandard");
1582 setStdEnc(fp->fd->encoding);
1583 } else if ( strstr(endtok,"ISOLatin1Encoding")!=NULL ) {
1584 fp->fd->encoding_name = FindOrMakeEncoding("ISO8859-1");
1585 setLatin1Enc(fp->fd->encoding);
1586 } else {
1587 fp->fd->encoding_name = &custom;
1588 fp->inencoding = 1;
1590 if ( fp->fd->encoding_name==NULL )
1591 fp->fd->encoding_name = &custom;
1592 fp->infi = fp->inprivate = fp->inbb = fp->inmetrics = fp->inmetrics2 = false;
1593 fp->doneencoding = true;
1594 while ( *endtok==' ' || *endtok=='\t' ) ++endtok;
1595 if ( *endtok=='[' ) { /* It's a literal array */
1596 fp->simpleencoding = true;
1597 fp->simple_enc_pos = 0;
1598 ParseSimpleEncoding(fp,endtok+1);
1600 } else if ( mycmp("BoundingBoxes",line+1,endtok)==0 ) {
1601 fp->infi = fp->inprivate = fp->inencoding = fp->inmetrics = fp->inmetrics2 = false;
1602 fp->inbb = true;
1603 } else if ( mycmp("Metrics",line+1,endtok)==0 ) {
1604 fp->infi = fp->inprivate = fp->inbb = fp->inencoding = fp->inmetrics2 = false;
1605 fp->inmetrics = true;
1606 fp->fd->metrics = gcalloc(1,sizeof(struct psdict));
1607 fp->fd->metrics->cnt = strtol(endtok,NULL,10);
1608 fp->fd->metrics->keys = galloc(fp->fd->metrics->cnt*sizeof(char *));
1609 fp->fd->metrics->values = galloc(fp->fd->metrics->cnt*sizeof(char *));
1610 } else if ( strstr(line,"/Private")!=NULL && strstr(line,"/Blend")!=NULL ) {
1611 fp->infi = fp->inbb = fp->inmetrics = fp->inmetrics2 = false;
1612 fp->inprivate = fp->inblendprivate = fp->inblendfi = false;
1613 fp->inblendprivate = 1;
1614 fp->fd->blendprivate = gcalloc(1,sizeof(struct psdict));
1615 InitDict(fp->fd->blendprivate,line);
1616 return;
1617 } else if ( strstr(line,"/FontInfo")!=NULL && strstr(line,"/Blend")!=NULL ) {
1618 fp->infi = fp->inbb = fp->inmetrics = fp->inmetrics2 = false;
1619 fp->inprivate = fp->inblendprivate = fp->inblendfi = false;
1620 fp->inblendfi = 1;
1621 fp->fd->blendfontinfo = gcalloc(1,sizeof(struct psdict));
1622 InitDict(fp->fd->blendfontinfo,line);
1623 return;
1624 } else if ( fp->infi ) {
1625 if ( fp->multiline ) {
1626 ContinueValue(fp,NULL,line);
1627 return;
1629 if ( endtok==NULL && (strncmp(line,"end", 3)==0 || strncmp(line,">>",2)==0)) {
1630 fp->infi=0;
1631 return;
1632 } else if ( endtok==NULL )
1633 return;
1634 if ( mycmp("version",line+1,endtok)==0 ) {
1635 free(fp->fd->fontinfo->version);
1636 fp->fd->fontinfo->version = getstring(endtok,in);
1637 } else if ( mycmp("Notice",line+1,endtok)==0 ) {
1638 if ( fp->fd->fontinfo->notice!=NULL )
1639 free(fp->fd->fontinfo->notice);
1640 fp->fd->fontinfo->notice = getstring(endtok,in);
1641 } else if ( mycmp("Copyright",line+1,endtok)==0 ) { /* cff spec allows for copyright and notice */
1642 if ( fp->fd->fontinfo->notice!=NULL )
1643 free(fp->fd->fontinfo->notice);
1644 fp->fd->fontinfo->notice = getstring(endtok,in);
1645 } else if ( mycmp("FullName",line+1,endtok)==0 ) {
1646 if ( fp->fd->fontinfo->fullname==NULL )
1647 fp->fd->fontinfo->fullname = getstring(endtok,in);
1648 else
1649 free(getstring(endtok,in));
1650 } else if ( mycmp("FamilyName",line+1,endtok)==0 ) {
1651 free( fp->fd->fontinfo->familyname );
1652 fp->fd->fontinfo->familyname = getstring(endtok,in);
1653 } else if ( mycmp("Weight",line+1,endtok)==0 ) {
1654 free( fp->fd->fontinfo->weight );
1655 fp->fd->fontinfo->weight = getstring(endtok,in);
1656 } else if ( mycmp("ItalicAngle",line+1,endtok)==0 )
1657 fp->fd->fontinfo->italicangle = strtod(endtok,NULL);
1658 else if ( mycmp("UnderlinePosition",line+1,endtok)==0 )
1659 fp->fd->fontinfo->underlineposition = strtod(endtok,NULL);
1660 else if ( mycmp("UnderlineThickness",line+1,endtok)==0 )
1661 fp->fd->fontinfo->underlinethickness = strtod(endtok,NULL);
1662 else if ( mycmp("isFixedPitch",line+1,endtok)==0 )
1663 fp->fd->fontinfo->isfixedpitch = getbool(endtok);
1664 else if ( mycmp("em",line+1,endtok)==0 )
1665 fp->fd->fontinfo->em = strtol(endtok,NULL,10);
1666 else if ( mycmp("ascent",line+1,endtok)==0 )
1667 fp->fd->fontinfo->ascent = strtol(endtok,NULL,10);
1668 else if ( mycmp("descent",line+1,endtok)==0 )
1669 fp->fd->fontinfo->descent = strtol(endtok,NULL,10);
1670 else if ( mycmp("FSType",line+1,endtok)==0 )
1671 fp->fd->fontinfo->fstype = strtol(endtok,NULL,10);
1672 else if ( mycmp("BlendDesignPositions",line+1,endtok)==0 ) {
1673 fp->pending_parse = &fp->fd->fontinfo->blenddesignpositions;
1674 AddValue(fp,NULL,line,endtok);
1675 } else if ( mycmp("BlendDesignMap",line+1,endtok)==0 ) {
1676 fp->pending_parse = &fp->fd->fontinfo->blenddesignmap;
1677 AddValue(fp,NULL,line,endtok);
1678 } else if ( mycmp("BlendAxisTypes",line+1,endtok)==0 ) {
1679 fp->pending_parse = &fp->fd->fontinfo->blendaxistypes;
1680 AddValue(fp,NULL,line,endtok);
1681 } else if ( !fp->alreadycomplained ) {
1682 LogError( _("Didn't understand \"%s"), rmbinary(line) );
1683 fp->alreadycomplained = true;
1685 } else if ( fp->inblend ) {
1686 if ( endtok==NULL ) {
1687 if ( *line!='/' && strstr(line,"end")!=NULL )
1688 fp->inblend = false;
1689 return;
1691 /* Ignore anything in the blend dict defn */
1692 } else if ( fp->inblendprivate || fp->inblendfi ) {
1693 struct psdict *subdict = fp->inblendfi ? fp->fd->blendfontinfo : fp->fd->blendprivate;
1694 if ( fp->multiline ) {
1695 ContinueValue(fp,subdict,line);
1696 return;
1697 } else if ( endtok==NULL ) {
1698 if ( *line!='/' && strstr(line,"end")!=NULL ) {
1699 fp->inblendprivate = fp->inblendfi = false;
1700 fp->inprivate = true;
1702 return;
1703 } else
1704 AddValue(fp,subdict,line,endtok);
1705 } else if ( fp->inprivate ) {
1706 if ( strstr(line,"/CharStrings")!=NULL && strstr(line,"dict")!=NULL ) {
1707 if ( fp->fd->chars->next==0 ) {
1708 InitChars(fp->fd->chars,line);
1709 fp->ignore = false;
1710 } else {
1711 fp->ignore = true;
1712 LogError( _("Ignoring duplicate /CharStrings entry\n") );
1714 fp->inchars = 1;
1715 fp->insubs = 0;
1716 return;
1717 } else if ( strstr(line,"/Subrs")!=NULL ) {
1718 if ( fp->fd->private->subrs->next>0 ) {
1719 fp->ignore = true;
1720 LogError( _("Ignoring duplicate /Subrs entry\n") );
1721 } else {
1722 InitChars(fp->fd->private->subrs,line);
1723 fp->ignore = false;
1725 fp->insubs = 1;
1726 fp->inchars = 0;
1727 return;
1728 } else if ( fp->multiline ) {
1729 ContinueValue(fp,fp->fd->private->private,line);
1730 return;
1732 if ( endtok==NULL ) {
1733 char *pt = line;
1734 if ( *pt!='/' ) while ( (pt=strstr(pt,"end"))!=NULL ) {
1735 if ( fp->inchars ) fp->inchars = false;
1736 else fp->inprivate = false;
1737 pt += 3;
1739 return;
1741 if ( mycmp("ND",line+1,endtok)==0 || mycmp("|-",line+1,endtok)==0 ||
1742 mycmp("NP",line+1,endtok)==0 || mycmp("|",line+1,endtok)==0 ||
1743 mycmp("RD",line+1,endtok)==0 || mycmp("-|",line+1,endtok)==0 ||
1744 mycmp("password",line+1,endtok)==0 ||
1745 mycmp("MinFeature",line+1,endtok)==0 )
1746 /* These conveigh no information, but are required */;
1747 else if ( mycmp("UniqueID",line+1,endtok)==0 ) {
1748 if ( fp->fd->uniqueid==0 )
1749 fp->fd->uniqueid = strtol(endtok,NULL,10);
1750 } else {
1751 if ( mycmp("lenIV",line+1,endtok)==0 )
1752 fp->fd->private->leniv = strtol(endtok,NULL,10); /* We need this value */
1753 AddValue(fp,fp->fd->private->private,line,endtok);
1755 } else if ( fp->incidsysteminfo ) {
1756 if ( endtok==NULL && strncmp(line,"end", 3)==0 ) {
1757 fp->incidsysteminfo=0;
1758 return;
1759 } else if ( endtok==NULL )
1760 return;
1761 if ( mycmp("Registry",line+1,endtok)==0 ) {
1762 free( fp->fd->registry );
1763 fp->fd->registry = getstring(endtok,in);
1764 } else if ( mycmp("Ordering",line+1,endtok)==0 ) {
1765 free( fp->fd->ordering );
1766 fp->fd->ordering = getstring(endtok,in);
1767 } else if ( mycmp("Supplement",line+1,endtok)==0 ) /* cff spec allows for copyright and notice */
1768 fp->fd->supplement = strtol(endtok,NULL,0);
1769 } else {
1770 if ( strstr(line,"/Private")!=NULL && (strstr(line,"dict")!=NULL || strstr(line,"<<")!=NULL )) {
1771 fp->infi = fp->inbb = fp->inmetrics = fp->inmetrics2 = false;
1772 fp->inprivate = fp->inblendprivate = fp->inblendfi = false;
1773 if ( strstr(line,"/Blend")!=NULL ) {
1774 fp->inblendprivate = 1;
1775 fp->fd->blendprivate = gcalloc(1,sizeof(struct psdict));
1776 InitDict(fp->fd->blendprivate,line);
1777 } else {
1778 fp->inprivate = 1;
1779 InitDict(fp->fd->private->private,line);
1781 return;
1782 } else if ( strstr(line,"/FontInfo")!=NULL && (strstr(line,"dict")!=NULL || strstr(line,"<<")!=NULL)) {
1783 fp->inprivate = fp->inbb = fp->inmetrics = fp->inmetrics2 = false;
1784 fp->infi = fp->inblendprivate = fp->inblendfi = false;
1785 if ( strstr(line,"/Blend")!=NULL ) {
1786 fp->inblendfi = 1;
1787 fp->fd->blendfontinfo = gcalloc(1,sizeof(struct psdict));
1788 InitDict(fp->fd->blendfontinfo,line);
1789 } else {
1790 fp->infi = 1;
1792 return;
1793 } else if ( strstr(line,"/Blend")!=NULL && strstr(line,"dict")!=NULL ) {
1794 fp->inprivate = fp->inbb = fp->inmetrics = fp->inmetrics2 = false;
1795 fp->infi = fp->inblendprivate = fp->inblendfi = false;
1796 fp->inblend = true;
1797 return;
1798 } else if ( strstr(line,"/sfnts")!=NULL && strstr(line,"[")!=NULL ) {
1799 sfnts2tempfile(fp,in,line);
1800 return;
1801 } else if ( strstr(line,"/CharStrings")!=NULL && strstr(line,"dict")!=NULL
1802 && fp->fd->fonttype!=3 ) {
1803 if ( fp->fd->chars->next==0 ) {
1804 InitChars(fp->fd->chars,line);
1805 fp->ignore = false;
1806 } else {
1807 fp->ignore = true;
1808 LogError( _("Ignoring duplicate /CharStrings entry\n") );
1810 fp->inchars = 1;
1811 fp->insubs = 0;
1812 fp->infi = fp->inprivate = fp->inbb = fp->inmetrics = fp->inmetrics2 = false;
1813 fp->inblendprivate = fp->inblendfi = false;
1814 return;
1815 } else if ( mycmp("/CharProcs",line,endtok)==0 ) {
1816 InitCharProcs(fp->fd->charprocs,line);
1817 fp->infi = fp->inprivate = fp->inbb = fp->inmetrics = fp->inmetrics2 = false;
1818 fp->insubs = 0;
1819 return;
1820 } else if ( strstr(line,"/CIDSystemInfo")!=NULL ) {
1821 fp->incidsysteminfo = 1;
1822 return;
1823 } else if ( fp->inmetrics ) {
1824 if ( endtok!=NULL )
1825 AddValue(fp,fp->fd->metrics,line,endtok);
1826 return;
1827 } else if ( fp->inbb ) {
1828 /* Ignore it */;
1829 return;
1832 if ( fp->multiline ) {
1833 ContinueValue(fp,NULL,line);
1834 return;
1837 if ( endtok==NULL ) {
1838 if ( fp->skipping_mbf )
1840 else if ( fp->fdindex!=-1 && strstr(line,"end")!=NULL ) {
1841 if ( ++fp->fdindex>=fp->mainfd->fdcnt )
1842 fp->fd = fp->mainfd;
1843 else
1844 fp->fd = fp->mainfd->fds[fp->fdindex];
1846 return;
1848 if ( mycmp("FontName",line+1,endtok)==0 ) {
1849 if ( fp->fd->fontname==NULL )
1850 fp->fd->fontname = gettoken(endtok);
1851 else
1852 free(gettoken(endtok)); /* skip it */
1853 } else if ( mycmp("PaintType",line+1,endtok)==0 )
1854 fp->fd->painttype = strtol(endtok,NULL,10);
1855 else if ( mycmp("FontType",line+1,endtok)==0 )
1856 fp->fd->fonttype = strtol(endtok,NULL,10);
1857 else if ( mycmp("FontMatrix",line+1,endtok)==0 ) {
1858 if ( fp->fd->fontmatrix[0]==0 )
1859 fillrealarray(fp->fd->fontmatrix,endtok,6);
1860 else {
1861 real temp[6];
1862 fillrealarray(temp,endtok,6);
1864 } else if ( mycmp("LanguageLevel",line+1,endtok)==0 )
1865 fp->fd->languagelevel = strtol(endtok,NULL,10);
1866 else if ( mycmp("WMode",line+1,endtok)==0 )
1867 fp->fd->wmode = strtol(endtok,NULL,10);
1868 else if ( mycmp("FontBBox",line+1,endtok)==0 )
1869 fillrealarray(fp->fd->fontbb,endtok,4);
1870 else if ( mycmp("UniqueID",line+1,endtok)==0 ) {
1871 if ( fp->fd->uniqueid==0 )
1872 fp->fd->uniqueid = strtol(endtok,NULL,10);
1873 } else if ( mycmp("UniqueId",line+1,endtok)==0 ) {
1874 LogError(_("This font contains a \"UniqueId\" variable, but the correct name for it is\n\t\"UniqueID\" (postscript is case concious)\n") );
1875 if ( fp->fd->uniqueid==0 )
1876 fp->fd->uniqueid = strtol(endtok,NULL,10);
1877 } else if ( mycmp("XUID",line+1,endtok)==0 ) {
1878 if ( fp->fd->xuid[0]==0 )
1879 fillintarray(fp->fd->xuid,endtok,20);
1880 } else if ( mycmp("StrokeWidth",line+1,endtok)==0 )
1881 fp->fd->strokewidth = strtod(endtok,NULL);
1882 else if ( mycmp("WeightVector",line+1,endtok)==0 ) {
1883 if ( fp->fd->weightvector==NULL ) {
1884 fp->pending_parse = &fp->fd->weightvector;
1885 AddValue(fp,NULL,line,endtok);
1887 } else if ( mycmp("$Blend",line+1,endtok)==0 ) {
1888 fp->pending_parse = &fp->fd->blendfunc;
1889 AddValue(fp,NULL,line,endtok);
1890 } else if ( strstr( line,"/NormalizeDesignVector" )!=NULL ) {
1891 fp->pending_parse = &fp->fd->ndv;
1892 AddValue(fp,NULL,line,endtok);
1893 } else if ( strstr( line,"/ConvertDesignVector" )!=NULL ) {
1894 fp->pending_parse = &fp->fd->cdv;
1895 AddValue(fp,NULL,line,endtok);
1896 } else if ( mycmp("BuildChar",line+1,endtok)==0 )
1897 /* Do Nothing */;
1898 else if ( mycmp("BuildGlyph",line+1,endtok)==0 )
1899 /* Do Nothing */;
1900 else if ( mycmp("CIDFontName",line+1,endtok)==0 ) {
1901 free( fp->fd->cidfontname );
1902 fp->fd->cidfontname = gettoken(endtok);
1903 } else if ( mycmp("CIDFontVersion",line+1,endtok)==0 ) {
1904 fp->fd->cidversion = strtod(endtok,NULL);
1905 #if 0
1906 if ( fp->fd->fontinfo->version==NULL ) {
1907 char temp[40];
1908 sprintf(temp,"%f", fp->fd->cidversion);
1909 fp->fd->fontinfo->version = copy(temp);
1911 #endif
1912 } else if ( mycmp("CIDFontType",line+1,endtok)==0 )
1913 fp->fd->cidfonttype = strtol(endtok,NULL,10);
1914 else if ( mycmp("UIDBase",line+1,endtok)==0 )
1915 fp->fd->uniqueid = strtol(endtok,NULL,10);
1916 else if ( mycmp("CIDMapOffset",line+1,endtok)==0 )
1917 fp->fd->mapoffset = strtol(endtok,NULL,10);
1918 else if ( mycmp("FDBytes",line+1,endtok)==0 )
1919 fp->fd->fdbytes = strtol(endtok,NULL,10);
1920 else if ( mycmp("GDBytes",line+1,endtok)==0 )
1921 fp->fd->gdbytes = strtol(endtok,NULL,10);
1922 else if ( mycmp("CIDCount",line+1,endtok)==0 )
1923 fp->fd->cidcnt = strtol(endtok,NULL,10);
1924 else if ( mycmp("FDArray",line+1,endtok)==0 ) { int i;
1925 fp->mainfd = fp->fd;
1926 fp->fd->fdcnt = strtol(endtok,NULL,10);
1927 fp->fd->fds = gcalloc(fp->fd->fdcnt,sizeof(struct fontdict *));
1928 for ( i=0; i<fp->fd->fdcnt; ++i )
1929 fp->fd->fds[i] = MakeEmptyFont();
1930 fp->fdindex = 0;
1931 fp->fd = fp->fd->fds[0];
1932 } else if ( mycmp("FontSetInit",line+1,endtok)==0 ) {
1933 fp->iscff = true;
1934 fp->iscid = false;
1935 } else if ( mycmp("CIDInit",line+1,endtok)==0 ) {
1936 fp->iscid = true;
1937 fp->iscff = false;
1938 } else if ( fp->skipping_mbf ) { /* Skip over the makeblendedfont defn in a multimaster font */
1939 /* Do Nothing */
1940 } else if ( !fp->alreadycomplained ) {
1941 LogError( _("Didn't understand \"%s"), rmbinary(line) );
1942 fp->alreadycomplained = true;
1947 static void addinfo(struct fontparse *fp,char *line,char *tok,char *binstart,int binlen,FILE *in) {
1948 char *pt;
1950 decodestr((unsigned char *) binstart,binlen);
1951 binstart += fp->fd->private->leniv;
1952 binlen -= fp->fd->private->leniv;
1953 if ( binlen<0 ) {
1954 LogError( _("Bad CharString. Does not include lenIV bytes.\n") );
1955 return;
1958 retry:
1959 if ( fp->insubs ) {
1960 struct pschars *chars = /*fp->insubs ?*/ fp->fd->private->subrs /*: fp->fd->private->othersubrs*/;
1961 while ( isspace(*line)) ++line;
1962 if ( strncmp(line,"dup ",4)==0 ) {
1963 int i = strtol(line+4,NULL,10);
1964 if ( fp->ignore )
1965 /* Do Nothing */;
1966 else if ( i<chars->cnt ) {
1967 if ( chars->values[i]!=NULL )
1968 LogError( _("Duplicate definition of subroutine %d\n"), i );
1969 chars->lens[i] = binlen;
1970 chars->values[i] = galloc(binlen);
1971 memcpy(chars->values[i],binstart,binlen);
1972 if ( i>=chars->next ) chars->next = i+1;
1973 } else if ( !fp->alreadycomplained ) {
1974 LogError( _("Index too big (must be <%d) \"%s"), chars->cnt, rmbinary(line));
1975 fp->alreadycomplained = true;
1977 } else if ( !fp->alreadycomplained ) {
1978 LogError( _("Didn't understand \"%s"), rmbinary(line) );
1979 fp->alreadycomplained = true;
1981 } else if ( fp->inchars ) {
1982 struct pschars *chars = fp->fd->chars;
1983 if ( *tok=='\0' )
1984 LogError( _("No name for CharStrings dictionary \"%s"), rmbinary(line) );
1985 else if ( fp->ignore )
1986 /* Do Nothing */;
1987 else if ( chars->next>=chars->cnt )
1988 LogError( _("Too many entries in CharStrings dictionary \"%s"), rmbinary(line) );
1989 else {
1990 int i = chars->next;
1991 chars->lens[i] = binlen;
1992 chars->keys[i] = copy(tok);
1993 chars->values[i] = galloc(binlen);
1994 memcpy(chars->values[i],binstart,binlen);
1995 ++chars->next;
1996 ff_progress_next();
1998 } else if ( !fp->alreadycomplained ) {
1999 /* Special hacks for known badly formatted fonts */
2000 if ( strstr(line,"/CharStrings")!=NULL ) {
2001 for ( pt=line; *pt!='/'; ++pt );
2002 pt = strchr(pt+1,'/');
2003 if ( pt!=NULL )
2004 *pt = '\0';
2005 parseline(fp,line,in);
2006 if ( pt!=NULL ) {
2007 *pt = '/';
2008 line = pt;
2009 goto retry;
2011 return;
2012 } else if ( strstr(line,"/Subrs")!=NULL ) {
2013 pt = strstr(line,"dup");
2014 if ( pt!=NULL )
2015 *pt = '\0';
2016 parseline(fp,line,in);
2017 if ( pt!=NULL ) {
2018 *pt = 'd';
2019 line = pt;
2020 goto retry;
2022 return;
2024 LogError( _("Shouldn't be in addinfo \"%s"), rmbinary(line) );
2025 fp->alreadycomplained = true;
2029 /* In the book the token which starts a character description is always RD but*/
2030 /* it's just the name of a subroutine which is defined in the private diction*/
2031 /* and it could be anything. in one case it was "-|" (hyphen bar) so we can't*/
2032 /* just look for RD we must be a bit smarter and figure out what the token is*/
2033 /* (oh. I see now. it's allowed to be either one "RD" or "-|", but nothing else*/
2034 /* right) */
2035 /* It's defined as {string currentfile exch readstring pop} so look for that */
2036 /* Except that in gsf files we've also got "/-!{string currentfile exch readhexstring pop} readonly def" */
2037 /* NOTE: readhexstring!!! */
2038 /* And in files generated by GNU fontutils */
2039 static int glorpline(struct fontparse *fp, FILE *temp, char *rdtok) {
2040 static char *buffer=NULL, *end;
2041 char *pt, *binstart;
2042 int binlen;
2043 int ch;
2044 int innum, val=0, inbinary, cnt=0, inr, wasspace, nownum, nowr, nowspace, sptok;
2045 char *rdline = "{string currentfile exch readstring pop}", *rpt;
2046 char *rdline2 = "{string currentfile exch readhexstring pop}";
2047 char *tokpt = NULL, *rdpt;
2048 char temptok[255];
2049 int intok, first;
2050 int wasminus=false, isminus, nibble=0, firstnibble=true, inhex;
2051 int willbehex = false;
2053 ch = getc(temp);
2054 if ( ch==EOF )
2055 return( 0 );
2056 ungetc(ch,temp);
2058 if ( buffer==NULL ) {
2059 buffer = galloc(3000);
2060 end = buffer+3000;
2062 innum = inr = 0; wasspace = 0; inbinary = 0; rpt = NULL; rdpt = NULL;
2063 inhex = 0;
2064 pt = buffer; binstart=NULL; binlen = 0; intok=0; sptok=0; first=1;
2065 temptok[0] = '\0';
2066 while ( (ch=getc(temp))!=EOF ) {
2067 if ( pt>=end ) {
2068 char *old = buffer;
2069 int len = (end-buffer)+2000;
2070 buffer = grealloc(buffer,len);
2071 end = buffer+len;
2072 pt = buffer+(pt-old);
2073 if ( binstart!=NULL )
2074 binstart = buffer+(binstart-old);
2076 *pt++ = ch;
2077 isminus = ch=='-' && wasspace;
2078 nownum = nowspace = nowr = 0;
2079 if ( rpt!=NULL && ch!=*rpt && ch=='h' && rpt-rdline>25 && rpt-rdline<30 &&
2080 rdline2[rpt-rdline]=='h' ) {
2081 rpt = rdline2 + (rpt-rdline);
2082 willbehex = true;
2084 if ( inbinary ) {
2085 if ( --cnt==0 )
2086 inbinary = 0;
2087 } else if ( inhex ) {
2088 if ( ishexdigit(ch)) {
2089 int h;
2090 if ( isdigit(ch)) h = ch-'0';
2091 else if ( ch>='a' && ch<='f' ) h = ch-'a'+10;
2092 else h = ch-'A'+10;
2093 if ( firstnibble ) {
2094 nibble = h;
2095 --pt;
2096 } else {
2097 pt[-1] = (nibble<<4)|h;
2098 if ( --cnt==0 )
2099 inbinary = inhex = 0;
2101 firstnibble = !firstnibble;
2102 } else {
2103 --pt;
2104 /* skip everything not hex */
2106 } else if ( ch=='/' ) {
2107 intok = 1;
2108 tokpt = temptok;
2109 } else if ( intok && !isspace(ch) && ch!='{' && ch!='[' ) {
2110 *tokpt++ = ch;
2111 } else if ( (intok||sptok) && (ch=='{' || ch=='[')) {
2112 *tokpt = '\0';
2113 rpt = rdline+1;
2114 intok = sptok = 0;
2115 } else if ( intok ) {
2116 *tokpt = '\0';
2117 intok = 0;
2118 sptok = 1;
2119 } else if ( sptok && isspace(ch)) {
2120 nowspace = 1;
2121 if ( ch=='\n' || ch=='\r' )
2122 break;
2123 } else if ( sptok && !isdigit(ch))
2124 sptok = 0;
2125 else if ( rpt!=NULL && ch==*rpt ) {
2126 if ( *++rpt=='\0' ) {
2127 /* it matched the character definition string so this is the */
2128 /* token we want to search for */
2129 strcpy(rdtok,temptok);
2130 fp->useshexstrings = willbehex;
2131 rpt = NULL;
2133 } else if ( rpt!=NULL && ch==' ' ) {
2134 /* Extra spaces are ok */
2135 } else if ( rpt!=NULL ) {
2136 rpt = NULL;
2137 willbehex = false;
2138 } else if ( isdigit(ch)) {
2139 sptok = 0;
2140 nownum = 1;
2141 if ( innum )
2142 val = 10*val + ch-'0';
2143 else
2144 val = ch-'0';
2145 } else if ( isspace(ch)) {
2146 nowspace = 1;
2147 if ( ch=='\n' || ch=='\r' )
2148 break;
2149 } else if ( wasspace && ch==*rdtok ) {
2150 nowr = 1;
2151 fp->useshexstrings = willbehex;
2152 rdpt = rdtok+1;
2153 } else if ( wasspace && ch=='-' ) { /* fonts produced by type1fix seem to define both "RD" and "-|" which confused me. so just respond to either */
2154 nowr = 1;
2155 fp->useshexstrings = false;
2156 rdpt = "|";
2157 } else if ( wasspace && ch=='R' ) { /* fonts produced by type1fix seem to define both "RD" and "-|" which confused me. so just respond to either */
2158 nowr = 1;
2159 fp->useshexstrings = false;
2160 rdpt = "D";
2161 } else if ( inr && ch==*rdpt ) {
2162 if ( *++rdpt =='\0' ) {
2163 ch = getc(temp);
2164 *pt++ = ch;
2165 if ( isspace(ch) && val!=0 ) {
2166 inhex = fp->useshexstrings;
2167 inbinary = !fp->useshexstrings;
2168 firstnibble = true;
2169 cnt = val;
2170 binstart = pt;
2171 binlen = val;
2173 } else
2174 nowr = 1;
2175 } else if ( wasminus && ch=='!' ) {
2176 ch = getc(temp);
2177 *pt++ = ch;
2178 if ( isspace(ch) && val!=0 ) {
2179 inhex = 1;
2180 cnt = val;
2181 binstart = pt;
2182 binlen = val;
2183 firstnibble = true;
2186 innum = nownum; wasspace = nowspace; inr = nowr;
2187 wasminus = isminus;
2188 first = 0;
2190 *pt = '\0';
2191 if ( binstart==NULL ) {
2192 parseline(fp,buffer,temp);
2193 } else {
2194 addinfo(fp,buffer,temptok,binstart,binlen,temp);
2196 return( 1 );
2199 static int nrandombytes[4];
2200 #define EODMARKLEN 16
2202 #define bgetc(extra,in) (*(extra)=='\0' ? getc(in) : (unsigned char ) *(extra)++ )
2204 static void decrypteexec(FILE *in,FILE *temp, int hassectionheads,char *extra) {
2205 int ch1, ch2, ch3, ch4, binary;
2206 int zcnt;
2207 unsigned char zeros[EODMARKLEN+6+1];
2208 int sect_len=0x7fffffff;
2210 if ( extra==(void *) 5 ) extra = "";
2212 /* The PLRM defines white space to include form-feed and null. The t1_spec*/
2213 /* does not. The t1_spec wins here. Someone gave me a font which began */
2214 /* with a formfeed and that was part of the encrypted body */
2215 while ( (ch1=bgetc(extra,in))!=EOF && (ch1==' ' || ch1=='\t' || ch1=='\n' || ch1=='\r'));
2216 if ( ch1==0200 && hassectionheads ) {
2217 /* skip the 6 byte section header in pfb files that follows eexec */
2218 ch1 = bgetc(extra,in);
2219 sect_len = bgetc(extra,in);
2220 sect_len |= bgetc(extra,in)<<8;
2221 sect_len |= bgetc(extra,in)<<16;
2222 sect_len |= bgetc(extra,in)<<24;
2223 sect_len -= 3;
2224 ch1 = bgetc(extra,in);
2226 ch2 = bgetc(extra,in); ch3 = bgetc(extra,in); ch4 = bgetc(extra,in);
2227 binary = 0;
2228 if ( ch1<'0' || (ch1>'9' && ch1<'A') || ( ch1>'F' && ch1<'a') || (ch1>'f') ||
2229 ch2<'0' || (ch2>'9' && ch2<'A') || (ch2>'F' && ch2<'a') || (ch2>'f') ||
2230 ch3<'0' || (ch3>'9' && ch3<'A') || (ch3>'F' && ch3<'a') || (ch3>'f') ||
2231 ch4<'0' || (ch4>'9' && ch4<'A') || (ch4>'F' && ch4<'a') || (ch4>'f') )
2232 binary = 1;
2233 if ( ch1==EOF || ch2==EOF || ch3==EOF || ch4==EOF ) {
2234 return;
2237 initcode();
2238 if ( binary ) {
2239 nrandombytes[0] = decode(ch1);
2240 nrandombytes[1] = decode(ch2);
2241 nrandombytes[2] = decode(ch3);
2242 nrandombytes[3] = decode(ch4);
2243 zcnt = 0;
2244 while (( ch1=bgetc(extra,in))!=EOF ) {
2245 --sect_len;
2246 if ( hassectionheads ) {
2247 if ( sect_len==0 && ch1==0200 ) {
2248 ch1 = bgetc(extra,in);
2249 sect_len = bgetc(extra,in);
2250 sect_len |= bgetc(extra,in)<<8;
2251 sect_len |= bgetc(extra,in)<<16;
2252 sect_len |= bgetc(extra,in)<<24;
2253 sect_len += 1;
2254 if ( ch1=='\1' )
2255 break;
2256 } else {
2257 dumpzeros(temp,zeros,zcnt);
2258 zcnt = 0;
2259 putc(decode(ch1),temp);
2261 } else {
2262 if ( ch1=='0' ) ++zcnt; else {dumpzeros(temp,zeros,zcnt); zcnt = 0; }
2263 if ( zcnt>EODMARKLEN )
2264 break;
2265 if ( zcnt==0 )
2266 putc(decode(ch1),temp);
2267 else
2268 zeros[zcnt-1] = decode(ch1);
2271 } else {
2272 nrandombytes[0] = decode(hex(ch1,ch2));
2273 nrandombytes[1] = decode(hex(ch3,ch4));
2274 ch1 = bgetc(extra,in); ch2 = bgetc(extra,in); ch3 = bgetc(extra,in); ch4 = bgetc(extra,in);
2275 nrandombytes[2] = decode(hex(ch1,ch2));
2276 nrandombytes[3] = decode(hex(ch3,ch4));
2277 zcnt = 0;
2278 while (( ch1=bgetc(extra,in))!=EOF ) {
2279 while ( ch1!=EOF && isspace(ch1)) ch1 = bgetc(extra,in);
2280 while ( (ch2=bgetc(extra,in))!=EOF && isspace(ch2));
2281 if ( ch1=='0' && ch2=='0' ) ++zcnt; else { dumpzeros(temp,zeros,zcnt); zcnt = 0;}
2282 if ( zcnt>EODMARKLEN )
2283 break;
2284 if ( zcnt==0 )
2285 putc(decode(hex(ch1,ch2)),temp);
2286 else
2287 zeros[zcnt-1] = decode(hex(ch1,ch2));
2290 while (( ch1=bgetc(extra,in))=='0' || isspace(ch1) );
2291 if ( ch1!=EOF ) ungetc(ch1,in);
2294 static void decryptagain(struct fontparse *fp,FILE *temp,char *rdtok) {
2295 while ( glorpline(fp,temp,rdtok));
2298 static void parsetype3(struct fontparse *fp,FILE *in) {
2299 PSFontInterpretPS(in,fp->fd->charprocs,fp->fd->encoding );
2302 static unsigned char *readt1str(FILE *temp,int offset,int len,int leniv) {
2303 int i;
2304 unsigned char *str, *pt;
2305 unsigned short r = 4330;
2306 unsigned char plain, cypher;
2307 /* The CID spec doesn't mention this, but the type 1 strings are all */
2308 /* eexec encrupted (with the nested encryption). Remember leniv varies */
2309 /* from fd to fd (potentially) */
2310 /* I'm told (by Ian Kemmish) that leniv==-1 => no eexec encryption */
2312 fseek(temp,offset,SEEK_SET);
2313 if ( leniv<0 ) {
2314 str = pt = galloc(len+1);
2315 for ( i=0 ; i<len; ++i )
2316 *pt++ = getc(temp);
2317 } else {
2318 for ( i=0; i<leniv; ++i ) {
2319 cypher = getc(temp);
2320 plain = ( cypher ^ (r>>8));
2321 r = (cypher + r) * c1 + c2;
2323 str = pt = galloc(len-leniv+1);
2324 for (; i<len; ++i ) {
2325 cypher = getc(temp);
2326 plain = ( cypher ^ (r>>8));
2327 r = (cypher + r) * c1 + c2;
2328 *pt++ = plain;
2331 *pt = '\0';
2332 return( str );
2335 static void figurecids(struct fontparse *fp,FILE *temp) {
2336 struct fontdict *fd = fp->mainfd;
2337 int i,j,k,val;
2338 int *offsets;
2339 int cidcnt = fd->cidcnt;
2340 int leniv;
2341 /* Some cid formats don't have any of these */
2343 fd->cidstrs = galloc(cidcnt*sizeof(uint8 *));
2344 fd->cidlens = galloc(cidcnt*sizeof(int16));
2345 fd->cidfds = galloc((cidcnt+1)*sizeof(int16));
2346 offsets = galloc((cidcnt+1)*sizeof(int));
2347 ff_progress_change_total(cidcnt);
2349 fseek(temp,fd->mapoffset,SEEK_SET);
2350 for ( i=0; i<=fd->cidcnt; ++i ) {
2351 for ( j=val=0; j<fd->fdbytes; ++j )
2352 val = (val<<8) + getc(temp);
2353 if ( val >= fd->fdcnt && val!=255 ) { /* 255 is a special mark */
2354 LogError( _("Invalid FD (%d) assigned to CID %d.\n"), val, i );
2355 val = 0;
2357 fd->cidfds[i] = val;
2358 for ( j=val=0; j<fd->gdbytes; ++j )
2359 val = (val<<8) + getc(temp);
2360 offsets[i] = val;
2361 if ( i!=0 ) {
2362 fd->cidlens[i-1] = offsets[i]-offsets[i-1];
2363 if ( fd->cidlens[i-1]<0 ) {
2364 LogError( _("Bad CID offset for CID %d\n"), i-1 );
2365 fd->cidlens[i-1] = 0;
2370 for ( i=0; i<fd->cidcnt; ++i ) {
2371 if ( fd->cidlens[i]== 0 )
2372 fd->cidstrs[i] = NULL;
2373 else {
2374 fd->cidstrs[i] = readt1str(temp,offsets[i],fd->cidlens[i],
2375 fd->fds[fd->cidfds[i]]->private->leniv);
2376 fd->cidlens[i] -= fd->fds[fd->cidfds[i]]->private->leniv;
2378 ff_progress_next();
2380 free(offsets);
2382 for ( k=0; k<fd->fdcnt; ++k ) {
2383 struct private *private = fd->fds[k]->private;
2384 char *ssubroff = PSDictHasEntry(private->private,"SubrMapOffset");
2385 char *ssdbytes = PSDictHasEntry(private->private,"SDBytes");
2386 char *ssubrcnt = PSDictHasEntry(private->private,"SubrCount");
2387 int subroff, sdbytes, subrcnt;
2389 if ( ssubroff!=NULL && ssdbytes!=NULL && ssubrcnt!=NULL &&
2390 (subroff=strtol(ssubroff,NULL,10))>=0 &&
2391 (sdbytes=strtol(ssdbytes,NULL,10))>0 &&
2392 (subrcnt=strtol(ssubrcnt,NULL,10))>0 ) {
2393 private->subrs->cnt = subrcnt;
2394 private->subrs->values = gcalloc(subrcnt,sizeof(char *));
2395 private->subrs->lens = gcalloc(subrcnt,sizeof(int));
2396 leniv = private->leniv;
2397 offsets = galloc((subrcnt+1)*sizeof(int));
2398 fseek(temp,subroff,SEEK_SET);
2399 for ( i=0; i<=subrcnt; ++i ) {
2400 for ( j=val=0; j<sdbytes; ++j )
2401 val = (val<<8) + getc(temp);
2402 offsets[i] = val;
2403 if ( i!=0 )
2404 private->subrs->lens[i-1] = offsets[i]-offsets[i-1];
2406 for ( i=0; i<subrcnt; ++i ) {
2407 private->subrs->values[i] = readt1str(temp,offsets[i],
2408 private->subrs->lens[i],leniv);
2410 private->subrs->next = i;
2411 free(offsets);
2413 PSDictRemoveEntry(private->private,"SubrMapOffset");
2414 PSDictRemoveEntry(private->private,"SDBytes");
2415 PSDictRemoveEntry(private->private,"SubrCount");
2419 static void dodata( struct fontparse *fp, FILE *in, FILE *temp) {
2420 int binary, cnt, len;
2421 int ch, ch2;
2422 char *pt;
2423 char fontsetname[256];
2425 while ( (ch=getc(in))!='(' && ch!='/' && ch!=EOF );
2426 if ( ch=='/' ) {
2427 /* There appears to be no provision for a hex encoding here */
2428 /* Why can't they use the same format for routines with the same name? */
2429 binary = true;
2430 for ( pt=fontsetname; (ch=getc(in))!=' ' && ch!=EOF; )
2431 if ( pt<fontsetname+sizeof(fontsetname)-1 )
2432 *pt++= ch;
2433 *pt = '\0';
2434 } else {
2435 if ( (ch=getc(in))=='B' || ch=='b' ) binary = true;
2436 else if ( ch=='H' || ch=='h' ) binary = false;
2437 else {
2438 binary = true; /* Who knows? */
2439 LogError( _("Failed to parse the StartData command properly\n") );
2441 fontsetname[0] = '\0';
2442 while ( (ch=getc(in))!=')' && ch!=EOF );
2444 if ( fscanf( in, "%d", &len )!=1 || len<=0 ) {
2445 len = 0;
2446 LogError( _("Failed to parse the StartData command properly, bad count\n") );
2448 cnt = len;
2449 while ( isspace(ch=getc(in)) );
2450 ungetc(ch,in);
2451 for ( pt="StartData "; *pt; ++pt )
2452 getc(in); /* And if it didn't match, what could I do about it? */
2453 if ( binary ) {
2454 while ( cnt>0 ) {
2455 ch = getc(in);
2456 putc(ch,temp);
2457 --cnt;
2459 } else {
2460 while ( cnt>0 ) {
2461 /* Hex data are allowed to contain whitespace */
2462 while ( isspace(ch=getc(in)) );
2463 while ( isspace(ch2=getc(in)) );
2464 ch = hex(ch,ch2);
2465 putc(ch,temp);
2466 --cnt;
2468 if ( (ch=getc(in))!='>' ) ungetc(ch,in);
2470 rewind(temp);
2471 if ( fp->iscid )
2472 figurecids(fp,temp);
2473 else {
2474 fp->fd->sf = _CFFParse(temp,len,fontsetname);
2475 fp->fd->wascff = true;
2479 static void realdecrypt(struct fontparse *fp,FILE *in, FILE *temp) {
2480 char buffer[256];
2481 int first, hassectionheads;
2482 char rdtok[20];
2483 int saw_blend = false;
2485 strcpy(rdtok,"RD");
2487 first = 1; hassectionheads = 0;
2488 while ( myfgets(buffer,sizeof(buffer),in)!=NULL ) {
2489 if ( strstr(buffer, "Blend")!=NULL )
2490 saw_blend = true;
2491 if ( first && buffer[0]=='\200' ) {
2492 int len = strlen( buffer );
2493 hassectionheads = 1;
2494 fp->fd->wasbinary = true;
2495 /* if there were a newline in the section header (in the length word)*/
2496 /* we would stop at it, and not read the full header */
2497 if ( len<6 ) /* eat the header */
2498 while ( len<6 ) { getc(in); ++len; }
2499 else /* Otherwise parse anything else on the line */
2500 parseline(fp,buffer+6,in);
2501 } else if ( strstr(buffer,"CharProcs")!=NULL && strstr(buffer,"begin")!=NULL ) {
2502 parsetype3(fp,in);
2503 return;
2504 } else if ( fp->fd->fonttype!=42 && strstr(buffer,"CharStrings")!=NULL && strstr(buffer,"begin")!=NULL ) {
2505 /* Fontographer uses CharStrings even though they aren't */
2506 parsetype3(fp,in);
2507 return;
2508 } else if ( !fp->iscid ) {
2509 if ( saw_blend )
2510 parseline(fp,buffer,in);
2511 /* But if it's a multi master font, don't do the special private hack */
2512 else if ( strstr(buffer,"/CharStrings")!=NULL &&
2513 strstr(buffer,"begin")!=NULL &&
2514 (fp->fd->fonttype!=42 && fp->fd->cidfonttype!=2)) {
2515 /* gsf files are not eexec encoded, but the charstrings are encoded*/
2516 InitChars(fp->fd->chars,buffer);
2517 fp->inchars = 1;
2518 decryptagain(fp,in,rdtok);
2519 return;
2520 } else if ( strstr(buffer,"/Subrs")!=NULL && strstr(buffer,"array")!=NULL ) {
2521 /* Same case as above */
2522 InitChars(fp->fd->private->subrs,buffer);
2523 fp->insubs = 1;
2524 decryptagain(fp,in,rdtok);
2525 return;
2526 } else if ( strstr(buffer,"/Private")!=NULL && (strstr(buffer,"dict")!=NULL || strstr(buffer,"<<")!=NULL )) {
2527 /* files produced by GNU fontutils have some of the same issues */
2528 fp->inprivate = 1;
2529 fp->infi = false;
2530 decryptagain(fp,in,rdtok);
2531 return;
2532 } else
2533 parseline(fp,buffer,in);
2534 } else
2535 parseline(fp,buffer,in);
2536 first = 0;
2537 if ( strstr(buffer,"%%BeginData: ")!=NULL )
2538 break;
2539 if ( strstr(buffer,"currentfile")!=NULL && strstr(buffer, "eexec")!=NULL ) {
2540 fp->skipping_mbf = false;
2541 break;
2543 /* Hmm. These lines were put in to handle parsing type42 fonts, but */
2544 /* they break multimaster fonts, and they don't seem to be needed */
2545 /* for type42s any more either. So... Away with them */
2546 #if 0
2547 if ( strstr(buffer,"definefont")!=NULL )
2548 break;
2549 #endif
2552 if ( strstr(buffer,"%%BeginData: ")!=NULL ) {
2553 /* used by both CID fonts and CFF fonts (and chameleons, whatever they are) */
2554 dodata(fp,in,temp);
2555 } else if ( strstr(buffer,"eexec")!=NULL ) {
2556 decrypteexec(in,temp,hassectionheads,strstr(buffer, "eexec")+5);
2557 rewind(temp);
2558 decryptagain(fp,temp,rdtok);
2559 while ( myfgets(buffer,sizeof(buffer),in)!=NULL ) {
2560 if ( buffer[0]!='\200' || !hassectionheads )
2561 parseline(fp,buffer,in);
2563 } else if (( fp->fd->fonttype==42 || fp->fd->cidfonttype==2 ) && fp->sfnts!=NULL ) {
2564 fp->fd->sf = _SFReadTTF(fp->sfnts,0,0,"<Temp File>",fp->fd);
2565 fclose(fp->sfnts);
2569 FontDict *_ReadPSFont(FILE *in) {
2570 FILE *temp;
2571 struct fontparse fp;
2572 char *oldloc;
2573 struct stat b;
2575 temp = tmpfile();
2576 if ( temp==NULL ) {
2577 LogError( _("Cannot open a temporary file\n") );
2578 return(NULL);
2581 oldloc = setlocale(LC_NUMERIC,"C");
2582 memset(&fp,'\0',sizeof(fp));
2583 fp.fd = fp.mainfd = PSMakeEmptyFont();
2584 fp.fdindex = -1;
2585 realdecrypt(&fp,in,temp);
2586 free(fp.vbuf);
2587 setlocale(LC_NUMERIC,oldloc);
2589 fclose(temp);
2591 if ( fstat(fileno(in),&b)!=-1 ) {
2592 fp.fd->modificationtime = b.st_mtime;
2593 fp.fd->creationtime = b.st_mtime;
2595 return( fp.fd );
2598 FontDict *ReadPSFont(char *fontname) {
2599 FILE *in;
2600 FontDict *fd;
2602 in = fopen(fontname,"rb");
2603 if ( in==NULL ) {
2604 LogError( _("Cannot open %s\n"), fontname );
2605 return(NULL);
2607 fd = _ReadPSFont(in);
2608 fclose(in);
2609 return( fd );
2612 void PSCharsFree(struct pschars *chrs) {
2613 int i;
2615 if ( chrs==NULL )
2616 return;
2617 for ( i=0; i<chrs->next; ++i ) {
2618 if ( chrs->keys!=NULL ) free(chrs->keys[i]);
2619 free(chrs->values[i]);
2621 free(chrs->lens);
2622 free(chrs->keys);
2623 free(chrs->values);
2624 free(chrs);
2627 void PSDictFree(struct psdict *dict) {
2628 int i;
2630 if ( dict==NULL )
2631 return;
2632 for ( i=0; i<dict->next; ++i ) {
2633 if ( dict->keys!=NULL ) free(dict->keys[i]);
2634 free(dict->values[i]);
2636 free(dict->keys);
2637 free(dict->values);
2638 free(dict);
2641 static void PrivateFree(struct private *prv) {
2642 PSCharsFree(prv->subrs);
2643 #if 1
2644 PSDictFree(prv->private);
2645 #else
2646 PSCharsFree(prv->othersubrs);
2647 free(prv->minfeature);
2648 free(prv->nd);
2649 free(prv->np);
2650 free(prv->rd);
2651 #endif
2652 free(prv);
2655 static void FontInfoFree(struct fontinfo *fi) {
2656 free(fi->familyname);
2657 free(fi->fullname);
2658 free(fi->notice);
2659 free(fi->weight);
2660 free(fi->version);
2661 free(fi->blenddesignpositions);
2662 free(fi->blenddesignmap);
2663 free(fi->blendaxistypes);
2664 free(fi);
2667 void PSFontFree(FontDict *fd) {
2668 int i;
2670 if ( fd->encoding!=NULL )
2671 for ( i=0; i<256; ++i )
2672 free( fd->encoding[i]);
2673 free(fd->fontname);
2674 free(fd->cidfontname);
2675 free(fd->registry);
2676 free(fd->ordering);
2677 FontInfoFree(fd->fontinfo);
2678 PSCharsFree(fd->chars);
2679 PrivateFree(fd->private);
2680 if ( fd->charprocs!=NULL ) {
2681 for ( i=0; i<fd->charprocs->cnt; ++i )
2682 free(fd->charprocs->keys[i]);
2683 free(fd->charprocs->keys);
2684 free(fd->charprocs->values);
2685 free(fd->charprocs);
2687 if ( fd->cidstrs!=NULL ) {
2688 for ( i=0; i<fd->cidcnt; ++i )
2689 free( fd->cidstrs[i]);
2690 free(fd->cidstrs);
2692 free(fd->cidlens);
2693 free(fd->cidfds);
2694 if ( fd->fds!=NULL ) {
2695 for ( i=0; i<fd->fdcnt; ++i )
2696 PSFontFree(fd->fds[i]);
2697 free(fd->fds);
2699 free(fd->blendfunc);
2700 free(fd->weightvector);
2701 free(fd->cdv);
2702 free(fd->ndv);
2704 PSDictFree(fd->blendprivate);
2705 PSDictFree(fd->blendfontinfo);
2707 free(fd);
2710 char **_NamesReadPostscript(FILE *ps) {
2711 char **ret = NULL;
2712 char buffer[2000], *pt, *end;
2714 if ( ps!=NULL ) {
2715 while ( fgets(buffer,sizeof(buffer),ps)!=NULL ) {
2716 if ( strstr(buffer,"/FontName")!=NULL ||
2717 strstr(buffer,"/CIDFontName")!=NULL ) {
2718 pt = strstr(buffer,"FontName");
2719 pt += strlen("FontName");
2720 while ( isspace(*pt)) ++pt;
2721 if ( *pt=='/' ) ++pt;
2722 for ( end = pt; *end!='\0' && !isspace(*end); ++end );
2723 ret = galloc(2*sizeof(char *));
2724 ret[0] = copyn(pt,end-pt);
2725 ret[1] = NULL;
2726 break;
2727 } else if ( strstr(buffer,"currentfile")!=NULL && strstr(buffer,"eexec")!=NULL )
2728 break;
2729 else if ( strstr(buffer,"%%BeginData")!=NULL )
2730 break;
2732 fclose(ps);
2734 return( ret );
2737 char **NamesReadPostscript(char *filename) {
2738 return( _NamesReadPostscript( fopen(filename,"rb")));