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:
5 
6  * Redistributions of source code must retain the above copyright notice, this
7  * list of conditions and the following disclaimer.
8 
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.
12 
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.
15 
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.
26  */
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>
38 
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;
67 
68     unsigned int alreadycomplained: 1;
69 
70     char *vbuf, *vmax, *vpt;
71     int depth;
72 };
73 
copyenc(char * encoding[256],char * std[256])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]);
78 }
79 
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"
337 };
setStdEnc(char * encoding[256])338 static void setStdEnc(char *encoding[256]) {
339     copyenc(encoding,AdobeStandardEncoding);
340 }
341 
setLatin1Enc(char * encoding[256])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"
600     };
601     copyenc(encoding,latin1enc);
602 }
603 
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"
861 };
862 
MakeEmptyFont(void)863 static struct fontdict *MakeEmptyFont(void) {
864     struct fontdict *ret;
865 
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 );
876 }
877 
PSMakeEmptyFont(void)878 static struct fontdict *PSMakeEmptyFont(void) {
879     struct fontdict *ret;
880 
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 );
892 }
893 
myfgets(char * str,int len,FILE * file)894 static char *myfgets(char *str, int len, FILE *file) {
895     char *pt, *end;
896     int ch=0;
897 
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';
908     }
909     if ( pt==str )
910 return( NULL );
911     *pt = '\0';
912 return( str );
913 }
914 
myfgetsNoNulls(char * str,int len,FILE * file)915 static char *myfgetsNoNulls(char *str, int len, FILE *file) {
916     char *pt, *end;
917     int ch=0;
918 
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;
922     }
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';
931     }
932     if ( pt==str )
933 return( NULL );
934     *pt = '\0';
935 return( str );
936 }
937 
getstring(char * start,FILE * in)938 static char *getstring(char *start,FILE *in) {
939     char *end, *ret;
940     int parencnt=0, len=0;
941     char buffer[512];
942 
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;
951     }
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;
960 	}
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';
969 	}
970 	if ( *end!='\0' )
971     break;
972 	if ( myfgetsNoNulls(buffer,sizeof(buffer),in)==NULL )
973 return( ret );
974 	start = buffer;
975     }
976 return( ret );
977 }
978 
gettoken(char * start)979 static char *gettoken(char *start) {
980     char *end, *ret;
981 
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 );
990 }
991 
getbool(char * start)992 static int getbool(char *start) {
993 
994     while ( isspace(*start) ) ++start;
995     if ( *start=='T' || *start=='t' )
996 return( 1 );
997 
998 return( 0 );
999 }
1000 
fillintarray(int * array,char * start,int maxentries)1001 static void fillintarray(int *array,char *start,int maxentries) {
1002     int i;
1003     char *end;
1004 
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;
1013     }
1014 }
1015 
fillrealarray(real * array,char * start,int maxentries)1016 static void fillrealarray(real *array,char *start,int maxentries) {
1017     int i;
1018     char *end;
1019 
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;
1037     }
1038 }
1039 
InitDict(struct psdict * dict,char * line)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;
1049 	}
1050     } else {
1051 	dict->keys = gcalloc(dict->cnt,sizeof(char *));
1052 	dict->values = gcalloc(dict->cnt,sizeof(char *));
1053     }
1054 }
1055 
InitChars(struct pschars * chars,char * line)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);
1065     }
1066 }
1067 
InitCharProcs(struct charprocs * cp,char * line)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);
1076     }
1077 }
1078 
mycmp(char * str,char * within,char * end)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;
1084     }
1085 return( *str=='\0'?0:1 );
1086 }
1087 
ContinueValue(struct fontparse * fp,struct psdict * dict,char * line)1088 static void ContinueValue(struct fontparse *fp, struct psdict *dict, char *line) {
1089     int incomment = false;
1090 
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;
1106 	    }
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;
1117 	    }
1118 	    fp->vpt = fp->vbuf;
1119 	    fp->multiline = false;
1120 return;
1121 	}
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;
1127 	}
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++;
1141     }
1142 }
1143 
AddValue(struct fontparse * fp,struct psdict * dict,char * line,char * endtok)1144 static void AddValue(struct fontparse *fp, struct psdict *dict, char *line, char *endtok) {
1145     char *pt;
1146 
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 *));
1152 	}
1153 	dict->keys[dict->next] = copyn(line+1,endtok-(line+1));
1154     }
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;
1167     }
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;
1178     }
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;
1185     }
1186 }
1187 
hex(int ch1,int ch2)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 );
1202 }
1203 
1204 unsigned short r;
1205 #define c1	52845
1206 #define c2	22719
1207 
initcode(void)1208 static void initcode(void) {
1209     r = 55665;
1210 }
1211 
decode(unsigned char cypher)1212 static int decode(unsigned char cypher) {
1213     unsigned char plain = ( cypher ^ (r>>8));
1214     r = (cypher + r) * c1 + c2;
1215 return( plain );
1216 }
1217 
dumpzeros(FILE * out,unsigned char * zeros,int zcnt)1218 static void dumpzeros(FILE *out, unsigned char *zeros, int zcnt) {
1219     while ( --zcnt >= 0 )
1220 	fputc(*zeros++,out);
1221 }
1222 
decodestr(unsigned char * str,int len)1223 static void decodestr(unsigned char *str, int len) {
1224     unsigned short r = 4330;
1225     unsigned char plain, cypher;
1226 
1227     while ( len-->0 ) {
1228 	cypher = *str;
1229 	plain = ( cypher ^ (r>>8));
1230 	r = (cypher + r) * c1 + c2;
1231 	*str++ = plain;
1232     }
1233 }
1234 
findstring(struct fontparse * fp,struct pschars * subrs,int index,char * nametok,char * str)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;
1238 
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');
1253 		    }
1254 		} else
1255 		    val = *str++;
1256 	    }
1257 	    if ( bpt<end )
1258 		*bpt++ = val;
1259 	}
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;
1268     }
1269 }
1270 
1271 /* Type42 charstrings are actually numbers */
findnumbers(struct fontparse * fp,struct pschars * chars,char * str)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;
1279 
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;
1287 
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;
1298     }
1299 }
1300 
rmbinary(char * line)1301 static char *rmbinary(char *line) {
1302     char *pt;
1303 
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';
1315 	    }
1316 	break;
1317 	}
1318     }
1319 return( line );
1320 }
1321 
sfnts2tempfile(struct fontparse * fp,FILE * in,char * 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;
1327 
1328     fp->sfnts = tmpfile();
1329 
1330     /* first finish off anything in the current line */
1331     while ( (pt=strpbrk(line,"<]" ))!=NULL ) {
1332 	if ( *pt==']' )
1333   goto skip_to_eol;
1334 
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;
1349 		}
1350 		++pt;
1351 	continue;
1352 	    }
1353 	    if ( firstnibble ) {
1354 		sofar = nibble<<4;
1355 		firstnibble = false;
1356 	    } else {
1357 		putc(sofar|nibble,fp->sfnts);
1358 		sofar = 0;
1359 		firstnibble = true;
1360 	    }
1361 	}
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);
1366 	    }
1367 	    ++pt;
1368 	    instring = false;
1369 	}
1370 	line = pt;
1371     }
1372 
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;
1386 	    }
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);
1391 	    }
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;
1404 		}
1405     continue;
1406 	    }
1407 	    if ( firstnibble ) {
1408 		sofar = nibble<<4;
1409 		firstnibble = false;
1410 	    } else {
1411 		putc(sofar|nibble,fp->sfnts);
1412 		sofar = 0;
1413 		firstnibble = true;
1414 	    }
1415 	}
1416     }
1417   skip_to_eol:
1418     while ( ch!=EOF && ch!='\n' && ch!='\r' )
1419 	ch = getc(in);
1420     rewind(fp->sfnts);
1421 }
1422 
ParseSimpleEncoding(struct fontparse * fp,char * line)1423 static void ParseSimpleEncoding(struct fontparse *fp,char *line) {
1424     char tok[200], *pt;
1425 
1426     while ( *line!='\0' && *line!=']' ) {
1427 	while ( isspace(*line)) ++line;
1428 	if ( *line==']' )
1429     break;
1430 	if ( *line!='/' ) {
1431 	    ++line;
1432     continue;
1433 	}
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;
1441 	}
1442 	*pt = '\0';
1443 	if ( fp->simple_enc_pos<256 )
1444 	    fp->fd->encoding[fp->simple_enc_pos++] = copy(tok);
1445     }
1446     if ( *line==']' ) {
1447 	fp->simpleencoding = false;
1448 	fp->inencoding = false;
1449     }
1450 }
1451 
parseline(struct fontparse * fp,char * line,FILE * in)1452 static void parseline(struct fontparse *fp,char *line,FILE *in) {
1453     char buffer[200], *pt, *endtok;
1454 
1455     while ( *line==' ' || *line=='\t' ) ++line;
1456     if ( line[0]=='%' && !fp->multiline )
1457 return;
1458 
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);
1479 	    }
1480 	    while ( isspace(*line)) ++line;
1481 	    if ( strncmp(line,"put",3)==0 ) line+=3;
1482 	    while ( isspace(*line)) ++line;
1483 	}
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);
1510 	    }
1511 	}
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;
1528 	    }
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;
1537 	}
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();
1561 	}
1562 return;
1563     }
1564     fp->inencoding = 0;
1565 
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 );
1571 
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;
1577     }
1578 
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;
1589 	}
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);
1599 	}
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;
1628 	}
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;
1684 	}
1685     } else if ( fp->inblend ) {
1686 	if ( endtok==NULL ) {
1687 	    if ( *line!='/' && strstr(line,"end")!=NULL )
1688 		fp->inblend = false;
1689 return;
1690 	}
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;
1701 	    }
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") );
1713 	    }
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;
1724 	    }
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;
1731 	}
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;
1738 	    }
1739 return;
1740 	}
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);
1754 	}
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);
1780 	    }
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;
1791 	    }
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") );
1809 	    }
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;
1830 	}
1831 
1832 	if ( fp->multiline ) {
1833 	    ContinueValue(fp,NULL,line);
1834 return;
1835 	}
1836 
1837 	if ( endtok==NULL ) {
1838 	    if ( fp->skipping_mbf )
1839 		;
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];
1845 	    }
1846 return;
1847 	}
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);
1863 	    }
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);
1886 	    }
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);
1910 	    }
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;
1943 	}
1944     }
1945 }
1946 
addinfo(struct fontparse * fp,char * line,char * tok,char * binstart,int binlen,FILE * in)1947 static void addinfo(struct fontparse *fp,char *line,char *tok,char *binstart,int binlen,FILE *in) {
1948     char *pt;
1949 
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;
1956     }
1957 
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;
1976 	    }
1977 	} else if ( !fp->alreadycomplained ) {
1978 	    LogError( _("Didn't understand \"%s"), rmbinary(line) );
1979 	    fp->alreadycomplained = true;
1980 	}
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();
1997 	}
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;
2010 	    }
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;
2021 	    }
2022 return;
2023 	}
2024 	LogError( _("Shouldn't be in addinfo \"%s"), rmbinary(line) );
2025 	fp->alreadycomplained = true;
2026     }
2027 }
2028 
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 */
glorpline(struct fontparse * fp,FILE * temp,char * rdtok)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;
2052 
2053     ch = getc(temp);
2054     if ( ch==EOF )
2055 return( 0 );
2056     ungetc(ch,temp);
2057 
2058     if ( buffer==NULL ) {
2059 	buffer = galloc(3000);
2060 	end = buffer+3000;
2061     }
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);
2075 	}
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;
2083 	}
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;
2100 		}
2101 		firstnibble = !firstnibble;
2102 	    } else {
2103 		--pt;
2104 		/* skip everything not hex */
2105 	    }
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;
2132 	    }
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;
2172 		}
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;
2184 	    }
2185 	}
2186 	innum = nownum; wasspace = nowspace; inr = nowr;
2187 	wasminus = isminus;
2188 	first = 0;
2189     }
2190     *pt = '\0';
2191     if ( binstart==NULL ) {
2192 	parseline(fp,buffer,temp);
2193     } else {
2194 	addinfo(fp,buffer,temptok,binstart,binlen,temp);
2195     }
2196 return( 1 );
2197 }
2198 
2199 static int nrandombytes[4];
2200 #define EODMARKLEN	16
2201 
2202 #define bgetc(extra,in)	(*(extra)=='\0' ? getc(in) : (unsigned char ) *(extra)++ )
2203 
decrypteexec(FILE * in,FILE * temp,int hassectionheads,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;
2209 
2210     if ( extra==(void *) 5 ) extra = "";
2211 
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);
2225     }
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;
2235     }
2236 
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);
2260 		}
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);
2269 	    }
2270 	}
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));
2288 	}
2289     }
2290     while (( ch1=bgetc(extra,in))=='0' || isspace(ch1) );
2291     if ( ch1!=EOF ) ungetc(ch1,in);
2292 }
2293 
decryptagain(struct fontparse * fp,FILE * temp,char * rdtok)2294 static void decryptagain(struct fontparse *fp,FILE *temp,char *rdtok) {
2295     while ( glorpline(fp,temp,rdtok));
2296 }
2297 
parsetype3(struct fontparse * fp,FILE * in)2298 static void parsetype3(struct fontparse *fp,FILE *in) {
2299     PSFontInterpretPS(in,fp->fd->charprocs,fp->fd->encoding );
2300 }
2301 
readt1str(FILE * temp,int offset,int len,int leniv)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 */
2311 
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;
2322 	}
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;
2329 	}
2330     }
2331     *pt = '\0';
2332 return( str );
2333 }
2334 
figurecids(struct fontparse * fp,FILE * temp)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 */
2342 
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);
2348 
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;
2356 	}
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;
2366 	    }
2367 	}
2368     }
2369 
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;
2377 	}
2378 	ff_progress_next();
2379     }
2380     free(offsets);
2381 
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;
2388 
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];
2405 	    }
2406 	    for ( i=0; i<subrcnt; ++i ) {
2407 		private->subrs->values[i] = readt1str(temp,offsets[i],
2408 			private->subrs->lens[i],leniv);
2409 	    }
2410 	    private->subrs->next = i;
2411 	    free(offsets);
2412 	}
2413 	PSDictRemoveEntry(private->private,"SubrMapOffset");
2414 	PSDictRemoveEntry(private->private,"SDBytes");
2415 	PSDictRemoveEntry(private->private,"SubrCount");
2416     }
2417 }
2418 
dodata(struct fontparse * fp,FILE * in,FILE * temp)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];
2424 
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") );
2440 	}
2441 	fontsetname[0] = '\0';
2442 	while ( (ch=getc(in))!=')' && ch!=EOF );
2443     }
2444     if ( fscanf( in, "%d", &len )!=1 || len<=0 ) {
2445 	len = 0;
2446 	LogError( _("Failed to parse the StartData command properly, bad count\n") );
2447     }
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;
2458 	}
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;
2467 	}
2468 	if ( (ch=getc(in))!='>' ) ungetc(ch,in);
2469     }
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;
2476     }
2477 }
2478 
realdecrypt(struct fontparse * fp,FILE * in,FILE * temp)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;
2484 
2485     strcpy(rdtok,"RD");
2486 
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;
2542 	}
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
2550     }
2551 
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);
2562 	}
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);
2566     }
2567 }
2568 
_ReadPSFont(FILE * in)2569 FontDict *_ReadPSFont(FILE *in) {
2570     FILE *temp;
2571     struct fontparse fp;
2572     char *oldloc;
2573     struct stat b;
2574 
2575     temp = tmpfile();
2576     if ( temp==NULL ) {
2577 	LogError( _("Cannot open a temporary file\n") );
2578 return(NULL);
2579     }
2580 
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);
2588 
2589     fclose(temp);
2590 
2591     if ( fstat(fileno(in),&b)!=-1 ) {
2592 	fp.fd->modificationtime = b.st_mtime;
2593 	fp.fd->creationtime = b.st_mtime;
2594     }
2595 return( fp.fd );
2596 }
2597 
ReadPSFont(char * fontname)2598 FontDict *ReadPSFont(char *fontname) {
2599     FILE *in;
2600     FontDict *fd;
2601 
2602     in = fopen(fontname,"rb");
2603     if ( in==NULL ) {
2604 	LogError( _("Cannot open %s\n"), fontname );
2605 return(NULL);
2606     }
2607     fd = _ReadPSFont(in);
2608     fclose(in);
2609 return( fd );
2610 }
2611 
PSCharsFree(struct pschars * chrs)2612 void PSCharsFree(struct pschars *chrs) {
2613     int i;
2614 
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]);
2620     }
2621     free(chrs->lens);
2622     free(chrs->keys);
2623     free(chrs->values);
2624     free(chrs);
2625 }
2626 
PSDictFree(struct psdict * dict)2627 void PSDictFree(struct psdict *dict) {
2628     int i;
2629 
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]);
2635     }
2636     free(dict->keys);
2637     free(dict->values);
2638     free(dict);
2639 }
2640 
PrivateFree(struct private * prv)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);
2653 }
2654 
FontInfoFree(struct fontinfo * fi)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);
2665 }
2666 
PSFontFree(FontDict * fd)2667 void PSFontFree(FontDict *fd) {
2668     int i;
2669 
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);
2686     }
2687     if ( fd->cidstrs!=NULL ) {
2688 	for ( i=0; i<fd->cidcnt; ++i )
2689 	    free( fd->cidstrs[i]);
2690 	free(fd->cidstrs);
2691     }
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);
2698     }
2699     free(fd->blendfunc);
2700     free(fd->weightvector);
2701     free(fd->cdv);
2702     free(fd->ndv);
2703 
2704     PSDictFree(fd->blendprivate);
2705     PSDictFree(fd->blendfontinfo);
2706 
2707     free(fd);
2708 }
2709 
_NamesReadPostscript(FILE * ps)2710 char **_NamesReadPostscript(FILE *ps) {
2711     char **ret = NULL;
2712     char buffer[2000], *pt, *end;
2713 
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;
2731 	}
2732 	fclose(ps);
2733     }
2734 return( ret );
2735 }
2736 
NamesReadPostscript(char * filename)2737 char **NamesReadPostscript(char *filename) {
2738 return( _NamesReadPostscript( fopen(filename,"rb")));
2739 }
2740