]> www.fi.muni.cz Git - evince.git/blob - xpdf/FontFile.cc
[dualscreen] fix crash on ctrl+w and fix control window closing
[evince.git] / xpdf / FontFile.cc
1 //========================================================================
2 //
3 // FontFile.cc
4 //
5 // Copyright 1999 Derek B. Noonburg
6 //
7 //========================================================================
8
9 #ifdef __GNUC__
10 #pragma implementation
11 #endif
12
13 #include <math.h>
14 #include <stdlib.h>
15 #include <stddef.h>
16 #include <string.h>
17 #include <ctype.h>
18 #include "gmem.h"
19 #include "Error.h"
20 #include "FontFile.h"
21
22 #include "StdFontInfo.h"
23 #include "CompactFontInfo.h"
24
25 //------------------------------------------------------------------------
26
27 static Guint getWord(Guchar *ptr, int size);
28 static double getNum(Guchar **ptr, GBool *fp);
29 static char *getString(int sid, Guchar *stringIdxPtr,
30                        Guchar *stringStartPtr, int stringOffSize,
31                        char *buf);
32
33 //------------------------------------------------------------------------
34
35 static inline char *nextLine(char *line, char *end) {
36   while (line < end && *line != '\n' && *line != '\r')
37     ++line;
38   while (line < end && *line == '\n' || *line == '\r')
39     ++line;
40   return line;
41 }
42
43 static char hexChars[17] = "0123456789ABCDEF";
44
45 //------------------------------------------------------------------------
46 // FontFile
47 //------------------------------------------------------------------------
48
49 FontFile::FontFile() {
50 }
51
52 FontFile::~FontFile() {
53 }
54
55 //------------------------------------------------------------------------
56 // Type1FontFile
57 //------------------------------------------------------------------------
58
59 Type1FontFile::Type1FontFile(char *file, int len) {
60   char *line, *line1, *p;
61   char buf[256];
62   int n, code, i;
63
64   name = NULL;
65   encoding = NULL;
66   freeEnc = gTrue;
67
68   for (i = 1, line = file; i <= 100 && line < file + len && !encoding; ++i) {
69
70     // get font name
71     if (!strncmp(line, "/FontName", 9)) {
72       strncpy(buf, line, 255);
73       buf[255] = '\0';
74       if ((p = strchr(buf+9, '/')) &&
75           (p = strtok(p+1, " \t\n\r")))
76         name = copyString(p);
77       line = nextLine(line, file + len);
78
79     // get encoding
80     } else if (!strncmp(line, "/Encoding StandardEncoding def", 30)) {
81       encoding = type1StdEncoding.copy();
82     } else if (!strncmp(line, "/Encoding 256 array", 19)) {
83       encoding = new FontEncoding();
84       for (i = 0; i < 300; ++i) {
85         line1 = nextLine(line, file + len);
86         if ((n = line1 - line) > 255)
87           n = 255;
88         strncpy(buf, line, n);
89         buf[n] = '\0';
90         p = strtok(buf, " \t");
91         if (p && !strcmp(p, "dup")) {
92           if ((p = strtok(NULL, " \t"))) {
93             if ((code = atoi(p)) < 256) {
94               if ((p = strtok(NULL, " \t"))) {
95                 if (p[0] == '/') {
96                   encoding->addChar(code, copyString(p+1));
97                 }
98               }
99             }
100           }
101         } else {
102           if ((p = strtok(NULL, " \t\n\r")) && !strcmp(p, "def")) {
103             break;
104           }
105         }
106         line = line1;
107       }
108       //~ check for getinterval/putinterval junk
109
110     } else {
111       line = nextLine(line, file + len);
112     }
113   }
114 }
115
116 Type1FontFile::~Type1FontFile() {
117   if (name)
118     delete name;
119   if (encoding && freeEnc)
120     delete encoding;
121 }
122
123 FontEncoding *Type1FontFile::getEncoding(GBool taken) {
124   if (taken)
125     freeEnc = gFalse;
126   return encoding;
127 }
128
129 //------------------------------------------------------------------------
130 // Type1CFontFile
131 //------------------------------------------------------------------------
132
133 Type1CFontFile::Type1CFontFile(char *file, int len) {
134   char buf[256];
135   Guchar *topPtr, *idxStartPtr, *idxPtr0, *idxPtr1;
136   Guchar *stringIdxPtr, *stringStartPtr;
137   int topOffSize, idxOffSize, stringOffSize;
138   int nFonts, nStrings, nGlyphs;
139   int nCodes, nRanges, nLeft, nSups;
140   Gushort *glyphNames;
141   int charset, enc, charstrings;
142   int charsetFormat, encFormat;
143   int c, sid;
144   double op[48];
145   double x;
146   GBool isFP;
147   int key;
148   int i, j, n;
149
150   name = NULL;
151   encoding = NULL;
152   freeEnc = gTrue;
153
154   // read header
155   topPtr = (Guchar *)file + (file[2] & 0xff);
156   topOffSize = file[3] & 0xff;
157
158   // read name index (first font only)
159   nFonts = getWord(topPtr, 2);
160   idxOffSize = topPtr[2];
161   topPtr += 3;
162   idxStartPtr = topPtr + (nFonts + 1) * idxOffSize - 1;
163   idxPtr0 = idxStartPtr + getWord(topPtr, idxOffSize);
164   idxPtr1 = idxStartPtr + getWord(topPtr + idxOffSize, idxOffSize);
165   if ((n = idxPtr1 - idxPtr0) > 255)
166     n = 255;
167   strncpy(buf, (char *)idxPtr0, n);
168   buf[n] = '\0';
169   name = copyString(buf);
170   topPtr = idxStartPtr + getWord(topPtr + nFonts * idxOffSize, idxOffSize);
171
172   // read top dict index (first font only)
173   nFonts = getWord(topPtr, 2);
174   idxOffSize = topPtr[2];
175   topPtr += 3;
176   idxStartPtr = topPtr + (nFonts + 1) * idxOffSize - 1;
177   idxPtr0 = idxStartPtr + getWord(topPtr, idxOffSize);
178   idxPtr1 = idxStartPtr + getWord(topPtr + idxOffSize, idxOffSize);
179   charset = 0;
180   enc = 0;
181   charstrings = 0;
182   i = 0;
183   while (idxPtr0 < idxPtr1) {
184     if (*idxPtr0 <= 27 || *idxPtr0 == 31) {
185       key = *idxPtr0++;
186       if (key == 0x0c)
187         key = (key << 8) | *idxPtr0++;
188       if (key == 0x0f) { // charset
189         charset = (int)op[0];
190       } else if (key == 0x10) { // encoding
191         enc = (int)op[0];
192       } else if (key == 0x11) { // charstrings
193         charstrings = (int)op[0];
194       }
195       i = 0;
196     } else {
197       x = getNum(&idxPtr0, &isFP);
198       if (i < 48)
199         op[i++] = x;
200     }
201   }
202   topPtr = idxStartPtr + getWord(topPtr + nFonts * idxOffSize, idxOffSize);
203
204   // read string index
205   nStrings = getWord(topPtr, 2);
206   stringOffSize = topPtr[2];
207   topPtr += 3;
208   stringIdxPtr = topPtr;
209   stringStartPtr = topPtr + (nStrings + 1) * stringOffSize - 1;
210   topPtr = stringStartPtr + getWord(topPtr + nStrings * stringOffSize,
211                                     stringOffSize);
212
213   // get number of glyphs from charstrings index
214   topPtr = (Guchar *)file + charstrings;
215   nGlyphs = getWord(topPtr, 2);
216
217   // read charset
218   if (charset == 0) {
219     glyphNames = type1CISOAdobeCharset;
220   } else if (charset == 1) {
221     glyphNames = type1CExpertCharset;
222   } else if (charset == 2) {
223     glyphNames = type1CExpertSubsetCharset;
224   } else {
225     glyphNames = (Gushort *)gmalloc(nGlyphs * sizeof(Gushort));
226     glyphNames[0] = 0;
227     topPtr = (Guchar *)file + charset;
228     charsetFormat = *topPtr++;
229     if (charsetFormat == 0) {
230       for (i = 1; i < nGlyphs; ++i) {
231         glyphNames[i] = getWord(topPtr, 2);
232         topPtr += 2;
233       }
234     } else if (charsetFormat == 1) {
235       i = 1;
236       while (i < nGlyphs) {
237         c = getWord(topPtr, 2);
238         topPtr += 2;
239         nLeft = *topPtr++;
240         for (j = 0; j <= nLeft; ++j)
241           glyphNames[i++] = c++;
242       }
243     } else if (charsetFormat == 2) {
244       i = 1;
245       while (i < nGlyphs) {
246         c = getWord(topPtr, 2);
247         topPtr += 2;
248         nLeft = getWord(topPtr, 2);
249         topPtr += 2;
250         for (j = 0; j <= nLeft; ++j)
251           glyphNames[i++] = c++;
252       }
253     }
254   }
255
256   // read encoding (glyph -> code mapping)
257   if (enc == 0) {
258     encoding = type1StdEncoding.copy();
259   } else if (enc == 1) {
260     encoding = type1ExpertEncoding.copy();
261   } else {
262     encoding = new FontEncoding();
263     topPtr = (Guchar *)file + enc;
264     encFormat = *topPtr++;
265     if ((encFormat & 0x7f) == 0) {
266       nCodes = 1 + *topPtr++;
267       if (nCodes > nGlyphs) {
268         nCodes = nGlyphs;
269       }
270       for (i = 1; i < nCodes; ++i) {
271         c = *topPtr++;
272         getString(glyphNames[i], stringIdxPtr, stringStartPtr,
273                   stringOffSize, buf);
274         encoding->addChar(c, copyString(buf));
275       }
276     } else if ((encFormat & 0x7f) == 1) {
277       nRanges = *topPtr++;
278       nCodes = 1;
279       for (i = 0; i < nRanges; ++i) {
280         c = *topPtr++;
281         nLeft = *topPtr++;
282         for (j = 0; j <= nLeft && nCodes < nGlyphs; ++j) {
283           getString(glyphNames[nCodes], stringIdxPtr, stringStartPtr,
284                     stringOffSize, buf);
285           encoding->addChar(c, copyString(buf));
286           ++nCodes;
287           ++c;
288         }
289       }
290     }
291     if (encFormat & 0x80) {
292       nSups = *topPtr++;
293       for (i = 0; i < nSups; ++i) {
294         c = *topPtr++;
295         sid = getWord(topPtr, 2);
296         topPtr += 2;
297         getString(sid, stringIdxPtr, stringStartPtr,
298                   stringOffSize, buf);
299         encoding->addChar(c, copyString(buf));
300       }
301     }
302   }
303
304   if (charset > 2)
305     gfree(glyphNames);
306 }
307
308 Type1CFontFile::~Type1CFontFile() {
309   if (name)
310     delete name;
311   if (encoding && freeEnc)
312     delete encoding;
313 }
314
315 FontEncoding *Type1CFontFile::getEncoding(GBool taken) {
316   if (taken)
317     freeEnc = gFalse;
318   return encoding;
319 }
320
321 static Guint getWord(Guchar *ptr, int size) {
322   Guint x;
323   int i;
324
325   x = 0;
326   for (i = 0; i < size; ++i)
327     x = (x << 8) + *ptr++;
328   return x;
329 }
330
331 static double getNum(Guchar **ptr, GBool *fp) {
332   static char nybChars[16] = "0123456789.ee -";
333   int b0, b, nyb0, nyb1;
334   double x;
335   char buf[65];
336   int i;
337
338   x = 0;
339   *fp = gFalse;
340   b0 = (*ptr)[0];
341   if (b0 < 28) {
342     x = 0;
343   } else if (b0 == 28) {
344     x = ((*ptr)[1] << 8) + (*ptr)[2];
345     *ptr += 3;
346   } else if (b0 == 29) {
347     x = ((*ptr)[1] << 24) + ((*ptr)[2] << 16) + ((*ptr)[3] << 8) + (*ptr)[4];
348     *ptr += 5;
349   } else if (b0 == 30) {
350     *ptr += 1;
351     i = 0;
352     do {
353       b = *(*ptr)++;
354       nyb0 = b >> 4;
355       nyb1 = b & 0x0f;
356       if (nyb0 == 0xf)
357         break;
358       buf[i++] = nybChars[nyb0];
359       if (i == 64)
360         break;
361       if (nyb0 == 0xc)
362         buf[i++] = '-';
363       if (i == 64)
364         break;
365       if (nyb1 == 0xf)
366         break;
367       buf[i++] = nybChars[nyb1];
368       if (i == 64)
369         break;
370       if (nyb1 == 0xc)
371         buf[i++] = '-';
372     } while (i < 64);
373     buf[i] = '\0';
374     x = atof(buf);
375     *fp = gTrue;
376   } else if (b0 == 31) {
377     x = 0;
378   } else if (b0 < 247) {
379     x = b0 - 139;
380     *ptr += 1;
381   } else if (b0 < 251) {
382     x = ((b0 - 247) << 8) + (*ptr)[1] + 108;
383     *ptr += 2;
384   } else {
385     x = -((b0 - 251) << 8) - (*ptr)[1] - 108;
386     *ptr += 2;
387   }
388   return x;
389 }
390
391 static char *getString(int sid, Guchar *stringIdxPtr,
392                        Guchar *stringStartPtr, int stringOffSize,
393                        char *buf) {
394   Guchar *idxPtr0, *idxPtr1;
395   int len;
396
397   if (sid < 391) {
398     strcpy(buf, type1CStdStrings[sid]);
399   } else {
400     sid -= 391;
401     idxPtr0 = stringStartPtr + getWord(stringIdxPtr + sid * stringOffSize,
402                                        stringOffSize);
403     idxPtr1 = stringStartPtr + getWord(stringIdxPtr + (sid+1) * stringOffSize,
404                                        stringOffSize);
405     if ((len = idxPtr1 - idxPtr0) > 255)
406       len = 255;
407     strncpy(buf, (char *)idxPtr0, len);
408     buf[len] = '\0';
409   }
410   return buf;
411 }
412
413 //------------------------------------------------------------------------
414 // Type1CFontConverter
415 //------------------------------------------------------------------------
416
417 Type1CFontConverter::Type1CFontConverter(char *file, int len, FILE *out) {
418   this->file = file;
419   this->len = len;
420   this->out = out;
421   r1 = 55665;
422   line = 0;
423 }
424
425 Type1CFontConverter::~Type1CFontConverter() {
426 }
427
428 void Type1CFontConverter::convert() {
429   char *fontName;
430   struct {
431     int version;
432     int notice;
433     int copyright;
434     int fullName;
435     int familyName;
436     int weight;
437     int isFixedPitch;
438     double italicAngle;
439     double underlinePosition;
440     double underlineThickness;
441     int paintType;
442     int charstringType;         //~ ???
443     double fontMatrix[6];
444     int uniqueID;
445     double fontBBox[4];
446     double strokeWidth;         //~ ???
447     int charset;
448     int encoding;
449     int charStrings;
450     int privateSize;
451     int privateOffset;
452   } dict;
453   char buf[256], eBuf[256];
454   Guchar *topPtr, *idxStartPtr, *idxPtr0, *idxPtr1;
455   Guchar *stringIdxPtr, *stringStartPtr;
456   int topOffSize, idxOffSize, stringOffSize;
457   int nFonts, nStrings, nGlyphs;
458   int nCodes, nRanges, nLeft, nSups;
459   Gushort *glyphNames;
460   int charsetFormat, encFormat;
461   int subrsOffset, nSubrs;
462   int nCharStrings;
463   int c, sid;
464   double x;
465   GBool isFP;
466   int key;
467   int i, j, n;
468
469   // read header
470   topPtr = (Guchar *)file + (file[2] & 0xff);
471   topOffSize = file[3] & 0xff;
472
473   // read name (first font only)
474   nFonts = getWord(topPtr, 2);
475   idxOffSize = topPtr[2];
476   topPtr += 3;
477   idxStartPtr = topPtr + (nFonts + 1) * idxOffSize - 1;
478   idxPtr0 = idxStartPtr + getWord(topPtr, idxOffSize);
479   idxPtr1 = idxStartPtr + getWord(topPtr + idxOffSize, idxOffSize);
480   if ((n = idxPtr1 - idxPtr0) > 255)
481     n = 255;
482   strncpy(buf, (char *)idxPtr0, n);
483   buf[n] = '\0';
484   fontName = copyString(buf);
485   topPtr = idxStartPtr + getWord(topPtr + nFonts * idxOffSize, idxOffSize);
486
487   // read top dict (first font only)
488   nFonts = getWord(topPtr, 2);
489   idxOffSize = topPtr[2];
490   topPtr += 3;
491   idxStartPtr = topPtr + (nFonts + 1) * idxOffSize - 1;
492   idxPtr0 = idxStartPtr + getWord(topPtr, idxOffSize);
493   idxPtr1 = idxStartPtr + getWord(topPtr + idxOffSize, idxOffSize);
494   dict.version = 0;
495   dict.notice = 0;
496   dict.copyright = 0;
497   dict.fullName = 0;
498   dict.familyName = 0;
499   dict.weight = 0;
500   dict.isFixedPitch = 0;
501   dict.italicAngle = 0;
502   dict.underlinePosition = -100;
503   dict.underlineThickness = 50;
504   dict.paintType = 0;
505   dict.charstringType = 2;
506   dict.fontMatrix[0] = 0.001;
507   dict.fontMatrix[1] = 0;
508   dict.fontMatrix[2] = 0;
509   dict.fontMatrix[3] = 0.001;
510   dict.fontMatrix[4] = 0;
511   dict.fontMatrix[5] = 0;
512   dict.uniqueID = 0;
513   dict.fontBBox[0] = 0;
514   dict.fontBBox[1] = 0;
515   dict.fontBBox[2] = 0;
516   dict.fontBBox[3] = 0;
517   dict.strokeWidth = 0;
518   dict.charset = 0;
519   dict.encoding = 0;
520   dict.charStrings = 0;
521   dict.privateSize = 0;
522   dict.privateOffset = 0;
523   i = 0;
524   while (idxPtr0 < idxPtr1) {
525     if (*idxPtr0 <= 27 || *idxPtr0 == 31) {
526       key = *idxPtr0++;
527       if (key == 0x0c)
528         key = (key << 8) | *idxPtr0++;
529       switch (key) {
530       case 0x0000: dict.version = (int)op[0]; break;
531       case 0x0001: dict.notice = (int)op[0]; break;
532       case 0x0c00: dict.copyright = (int)op[0]; break;
533       case 0x0002: dict.fullName = (int)op[0]; break;
534       case 0x0003: dict.familyName = (int)op[0]; break;
535       case 0x0004: dict.weight = (int)op[0]; break;
536       case 0x0c01: dict.isFixedPitch = (int)op[0]; break;
537       case 0x0c02: dict.italicAngle = op[0]; break;
538       case 0x0c03: dict.underlinePosition = op[0]; break;
539       case 0x0c04: dict.underlineThickness = op[0]; break;
540       case 0x0c05: dict.paintType = (int)op[0]; break;
541       case 0x0c06: dict.charstringType = (int)op[0]; break;
542       case 0x0c07: dict.fontMatrix[0] = op[0];
543                    dict.fontMatrix[1] = op[1];
544                    dict.fontMatrix[2] = op[2];
545                    dict.fontMatrix[3] = op[3];
546                    dict.fontMatrix[4] = op[4];
547                    dict.fontMatrix[5] = op[5]; break;
548       case 0x000d: dict.uniqueID = (int)op[0]; break;
549       case 0x0005: dict.fontBBox[0] = op[0];
550                    dict.fontBBox[1] = op[1];
551                    dict.fontBBox[2] = op[2];
552                    dict.fontBBox[3] = op[3]; break;
553       case 0x0c08: dict.strokeWidth = op[0]; break;
554       case 0x000f: dict.charset = (int)op[0]; break;
555       case 0x0010: dict.encoding = (int)op[0]; break;
556       case 0x0011: dict.charStrings = (int)op[0]; break;
557       case 0x0012: dict.privateSize = (int)op[0];
558                    dict.privateOffset = (int)op[1]; break;
559       }
560       i = 0;
561     } else {
562       x = getNum(&idxPtr0, &isFP);
563       if (i < 48) {
564         op[i] = x;
565         fp[i++] = isFP;
566       }
567     }
568   }
569   topPtr = idxStartPtr + getWord(topPtr + nFonts * idxOffSize, idxOffSize);
570
571   // read string index
572   nStrings = getWord(topPtr, 2);
573   stringOffSize = topPtr[2];
574   topPtr += 3;
575   stringIdxPtr = topPtr;
576   stringStartPtr = topPtr + (nStrings + 1) * stringOffSize - 1;
577   topPtr = stringStartPtr + getWord(topPtr + nStrings * stringOffSize,
578                                     stringOffSize);
579
580 #if 1 //~
581   // get global subrs
582   int nGSubrs;
583   int gSubrOffSize;
584
585   nGSubrs = getWord(topPtr, 2);
586   gSubrOffSize = topPtr[2];
587   topPtr += 3;
588 #endif
589
590   // write header and font dictionary, up to encoding
591   fprintf(out, "%%!FontType1-1.0: %s", fontName);
592   if (dict.version != 0) {
593     fprintf(out, "%s",
594             getString(dict.version, stringIdxPtr, stringStartPtr,
595                       stringOffSize, buf));
596   }
597   fprintf(out, "\n");
598   fprintf(out, "11 dict begin\n");
599   fprintf(out, "/FontInfo 10 dict dup begin\n");
600   if (dict.version != 0) {
601     fprintf(out, "/version (%s) readonly def\n",
602             getString(dict.version, stringIdxPtr, stringStartPtr,
603                       stringOffSize, buf));
604   }
605   if (dict.notice != 0) {
606     fprintf(out, "/Notice (%s) readonly def\n",
607             getString(dict.notice, stringIdxPtr, stringStartPtr,
608                       stringOffSize, buf));
609   }
610   if (dict.copyright != 0) {
611     fprintf(out, "/Copyright (%s) readonly def\n",
612             getString(dict.copyright, stringIdxPtr, stringStartPtr,
613                       stringOffSize, buf));
614   }
615   if (dict.fullName != 0) {
616     fprintf(out, "/FullName (%s) readonly def\n",
617             getString(dict.fullName, stringIdxPtr, stringStartPtr,
618                       stringOffSize, buf));
619   }
620   if (dict.familyName != 0) {
621     fprintf(out, "/FamilyName (%s) readonly def\n",
622             getString(dict.familyName, stringIdxPtr, stringStartPtr,
623                       stringOffSize, buf));
624   }
625   if (dict.weight != 0) {
626     fprintf(out, "/Weight (%s) readonly def\n",
627             getString(dict.weight, stringIdxPtr, stringStartPtr,
628                       stringOffSize, buf));
629   }
630   fprintf(out, "/isFixedPitch %s def\n", dict.isFixedPitch ? "true" : "false");
631   fprintf(out, "/ItalicAngle %g def\n", dict.italicAngle);
632   fprintf(out, "/UnderlinePosition %g def\n", dict.underlinePosition);
633   fprintf(out, "/UnderlineThickness %g def\n", dict.underlineThickness);
634   fprintf(out, "end readonly def\n");
635   fprintf(out, "/FontName /%s def\n", fontName);
636   fprintf(out, "/PaintType %d def\n", dict.paintType);
637   fprintf(out, "/FontType 1 def\n");
638   fprintf(out, "/FontMatrix [%g %g %g %g %g %g] readonly def\n",
639           dict.fontMatrix[0], dict.fontMatrix[1], dict.fontMatrix[2],
640           dict.fontMatrix[3], dict.fontMatrix[4], dict.fontMatrix[5]);
641   fprintf(out, "/FontBBox [%g %g %g %g] readonly def\n",
642           dict.fontBBox[0], dict.fontBBox[1],
643           dict.fontBBox[2], dict.fontBBox[3]);
644   if (dict.uniqueID != 0) {
645     fprintf(out, "/UniqueID %d def\n", dict.uniqueID);
646   }
647
648   // get number of glyphs from charstrings index
649   topPtr = (Guchar *)file + dict.charStrings;
650   nGlyphs = getWord(topPtr, 2);
651
652   // read charset
653   if (dict.charset == 0) {
654     glyphNames = type1CISOAdobeCharset;
655   } else if (dict.charset == 1) {
656     glyphNames = type1CExpertCharset;
657   } else if (dict.charset == 2) {
658     glyphNames = type1CExpertSubsetCharset;
659   } else {
660     glyphNames = (Gushort *)gmalloc(nGlyphs * sizeof(Gushort));
661     glyphNames[0] = 0;
662     topPtr = (Guchar *)file + dict.charset;
663     charsetFormat = *topPtr++;
664     if (charsetFormat == 0) {
665       for (i = 1; i < nGlyphs; ++i) {
666         glyphNames[i] = getWord(topPtr, 2);
667         topPtr += 2;
668       }
669     } else if (charsetFormat == 1) {
670       i = 1;
671       while (i < nGlyphs) {
672         c = getWord(topPtr, 2);
673         topPtr += 2;
674         nLeft = *topPtr++;
675         for (j = 0; j <= nLeft; ++j)
676           glyphNames[i++] = c++;
677       }
678     } else if (charsetFormat == 2) {
679       i = 1;
680       while (i < nGlyphs) {
681         c = getWord(topPtr, 2);
682         topPtr += 2;
683         nLeft = getWord(topPtr, 2);
684         topPtr += 2;
685         for (j = 0; j <= nLeft; ++j)
686           glyphNames[i++] = c++;
687       }
688     }
689   }
690
691   // read encoding (glyph -> code mapping), write Type 1 encoding
692   fprintf(out, "/Encoding ");
693   if (dict.encoding == 0) {
694     fprintf(out, "StandardEncoding def\n");
695   } else {
696     fprintf(out, "256 array\n");
697     fprintf(out, "0 1 255 {1 index exch /.notdef put} for\n");
698     if (dict.encoding == 1) {
699       for (i = 0; i < 256; ++i) {
700         if (type1ExpertEncodingNames[i])
701           fprintf(out, "dup %d /%s put\n", i, type1ExpertEncodingNames[i]);
702       }
703     } else {
704       topPtr = (Guchar *)file + dict.encoding;
705       encFormat = *topPtr++;
706       if ((encFormat & 0x7f) == 0) {
707         nCodes = 1 + *topPtr++;
708         if (nCodes > nGlyphs) {
709           nCodes = nGlyphs;
710         }
711         for (i = 1; i < nCodes; ++i) {
712           c = *topPtr++;
713           fprintf(out, "dup %d /%s put\n", c,
714                   getString(glyphNames[i], stringIdxPtr, stringStartPtr,
715                             stringOffSize, buf));
716         }
717       } else if ((encFormat & 0x7f) == 1) {
718         nRanges = *topPtr++;
719         nCodes = 1;
720         for (i = 0; i < nRanges; ++i) {
721           c = *topPtr++;
722           nLeft = *topPtr++;
723           for (j = 0; j <= nLeft && nCodes < nGlyphs; ++j) {
724             fprintf(out, "dup %d /%s put\n", c,
725                     getString(glyphNames[nCodes], stringIdxPtr, stringStartPtr,
726                               stringOffSize, buf));
727             ++nCodes;
728             ++c;
729           }
730         }
731       }
732       if (encFormat & 0x80) {
733         nSups = *topPtr++;
734         for (i = 0; i < nSups; ++i) {
735           c = *topPtr++;
736           sid = getWord(topPtr, 2);
737           topPtr += 2;
738           fprintf(out, "dup %d /%s put\n", c,
739                   getString(sid, stringIdxPtr, stringStartPtr,
740                             stringOffSize, buf));
741         }
742       }
743     }
744     fprintf(out, "readonly def\n");
745   }
746   fprintf(out, "currentdict end\n");
747   fprintf(out, "currentfile eexec\n");
748
749   // get private dictionary
750   eexecWrite("\x83\xca\x73\xd5");
751   eexecWrite("dup /Private 32 dict dup begin\n");
752   eexecWrite("/RD {string currentfile exch readstring pop} executeonly def\n");
753   eexecWrite("/ND {noaccess def} executeonly def\n");
754   eexecWrite("/NP {noaccess put} executeonly def\n");
755   eexecWrite("/MinFeature {16 16} ND\n");
756   eexecWrite("/password 5839 def\n");
757   subrsOffset = 0;
758   defaultWidthX = 0;
759   nominalWidthX = 0;
760   topPtr = (Guchar *)file + dict.privateOffset;
761   idxPtr0 = topPtr;
762   idxPtr1 = idxPtr0 + dict.privateSize;
763   i = 0;
764   while (idxPtr0 < idxPtr1) {
765     if (*idxPtr0 <= 27 || *idxPtr0 == 31) {
766       key = *idxPtr0++;
767       if (key == 0x0c)
768         key = (key << 8) | *idxPtr0++;
769       switch (key) {
770       case 0x0006:
771         getDeltaInt(eBuf, "BlueValues", op, i);
772         eexecWrite(eBuf);
773         break;
774       case 0x0007:
775         getDeltaInt(eBuf, "OtherBlues", op, i);
776         eexecWrite(eBuf);
777         break;
778       case 0x0008:
779         getDeltaInt(eBuf, "FamilyBlues", op, i);
780         eexecWrite(eBuf);
781         break;
782       case 0x0009:
783         getDeltaInt(eBuf, "FamilyOtherBlues", op, i);
784         eexecWrite(eBuf);
785         break;
786       case 0x0c09:
787         sprintf(eBuf, "/BlueScale %g def\n", op[0]);
788         eexecWrite(eBuf);
789         break;
790       case 0x0c0a:
791         sprintf(eBuf, "/BlueShift %d def\n", (int)op[0]);
792         eexecWrite(eBuf);
793         break;
794       case 0x0c0b:
795         sprintf(eBuf, "/BlueFuzz %d def\n", (int)op[0]);
796         eexecWrite(eBuf);
797         break;
798       case 0x000a:
799         sprintf(eBuf, "/StdHW [%g] def\n", op[0]);
800         eexecWrite(eBuf);
801         break;
802       case 0x000b:
803         sprintf(eBuf, "/StdVW [%g] def\n", op[0]);
804         eexecWrite(eBuf);
805         break;
806       case 0x0c0c:
807         getDeltaReal(eBuf, "StemSnapH", op, i);
808         eexecWrite(eBuf);
809         break;
810       case 0x0c0d:
811         getDeltaReal(eBuf, "StemSnapV", op, i);
812         eexecWrite(eBuf);
813         break;
814       case 0x0c0e:
815         sprintf(eBuf, "/ForceBold %s def\n", op[0] ? "true" : "false");
816         eexecWrite(eBuf);
817         break;
818       case 0x0c0f:
819         sprintf(eBuf, "/ForceBoldThreshold %g def\n", op[0]);
820         eexecWrite(eBuf);
821         break;
822       case 0x0c11:
823         sprintf(eBuf, "/LanguageGroup %d def\n", (int)op[0]);
824         eexecWrite(eBuf);
825         break;
826       case 0x0c12:
827         sprintf(eBuf, "/ExpansionFactor %g def\n", op[0]);
828         eexecWrite(eBuf);
829         break;
830       case 0x0c13:
831         error(-1, "Got Type 1C InitialRandomSeed");
832         break;
833       case 0x0013:
834         subrsOffset = (int)op[0];
835         break;
836       case 0x0014:
837         defaultWidthX = op[0];
838         defaultWidthXFP = fp[0];
839         break;
840       case 0x0015:
841         nominalWidthX = op[0];
842         nominalWidthXFP = fp[0];
843         break;
844       default:
845         error(-1, "Uknown Type 1C private dict entry %04x", key);
846         break;
847       }
848       i = 0;
849     } else {
850       x = getNum(&idxPtr0, &isFP);
851       if (i < 48) {
852         op[i] = x;
853         fp[i++] = isFP;
854       }
855     }
856   }
857
858   // get subrs
859   if (subrsOffset != 0) {
860     topPtr += subrsOffset;
861     nSubrs = getWord(topPtr, 2);
862     idxOffSize = topPtr[2];
863     topPtr += 3;
864     sprintf(eBuf, "/Subrs %d array\n", nSubrs);
865     eexecWrite(eBuf);
866     idxStartPtr = topPtr + (nSubrs + 1) * idxOffSize - 1;
867     idxPtr1 = idxStartPtr + getWord(topPtr, idxOffSize);
868     for (i = 0; i < nSubrs; ++i) {
869       idxPtr0 = idxPtr1;
870       idxPtr1 = idxStartPtr + getWord(topPtr + (i+1)*idxOffSize, idxOffSize);
871       n = idxPtr1 - idxPtr0;
872 #if 1 //~
873       error(-1, "Unimplemented Type 2 subrs");
874 #else
875       sprintf(eBuf, "dup %d %d RD ", i, n);
876       eexecWrite(eBuf);
877       cvtGlyph(idxPtr0, n);
878       eexecWrite(" NP\n");
879 #endif
880     }
881     eexecWrite("ND\n");
882   }
883
884   // get CharStrings
885   topPtr = (Guchar *)file + dict.charStrings;
886   nCharStrings = getWord(topPtr, 2);
887   idxOffSize = topPtr[2];
888   topPtr += 3;
889   sprintf(eBuf, "2 index /CharStrings %d dict dup begin\n", nCharStrings);
890   eexecWrite(eBuf);
891   idxStartPtr = topPtr + (nCharStrings + 1) * idxOffSize - 1;
892   idxPtr1 = idxStartPtr + getWord(topPtr, idxOffSize);
893   for (i = 0; i < nCharStrings; ++i) {
894     idxPtr0 = idxPtr1;
895     idxPtr1 = idxStartPtr + getWord(topPtr + (i+1)*idxOffSize, idxOffSize);
896     n = idxPtr1 - idxPtr0;
897     cvtGlyph(getString(glyphNames[i], stringIdxPtr, stringStartPtr,
898                        stringOffSize, buf),
899              idxPtr0, n);
900   }
901   eexecWrite("end\n");
902   eexecWrite("end\n");
903   eexecWrite("readonly put\n");
904   eexecWrite("noaccess put\n");
905   eexecWrite("dup /FontName get exch definefont pop\n");
906   eexecWrite("mark currentfile closefile\n");
907
908   // trailer
909   if (line > 0)
910     fputc('\n', out);
911   for (i = 0; i < 8; ++i) {
912     fprintf(out, "0000000000000000000000000000000000000000000000000000000000000000\n");
913   }
914   fprintf(out, "cleartomark\n");
915
916   // clean up
917   if (dict.charset > 2)
918     gfree(glyphNames);
919   gfree(fontName);
920 }
921
922 void Type1CFontConverter::eexecWrite(char *s) {
923   Guchar *p;
924   Guchar x;
925
926   for (p = (Guchar *)s; *p; ++p) {
927     x = *p ^ (r1 >> 8);
928     r1 = (x + r1) * 52845 + 22719;
929     fputc(hexChars[x >> 4], out);
930     fputc(hexChars[x & 0x0f], out);
931     line += 2;
932     if (line == 64) {
933       fputc('\n', out);
934       line = 0;
935     }
936   }
937 }
938
939 void Type1CFontConverter::cvtGlyph(char *name, Guchar *s, int n) {
940   int nHints;
941   int x;
942   GBool first = gTrue;
943   char eBuf[256];
944   double d, dx, dy;
945   GBool dFP;
946   int i, k;
947
948   charBuf = new GString();
949   charBuf->append((char)73);
950   charBuf->append((char)58);
951   charBuf->append((char)147);
952   charBuf->append((char)134);
953
954   i = 0;
955   nOps = 0;
956   nHints = 0;
957   while (i < n) {
958     if (s[i] == 12) {
959       switch (s[i+1]) {
960       case 0:                   // dotsection (should be Type 1 only?)
961         //~ ignored
962         break;
963       case 34:                  // hflex
964         if (nOps != 7) {
965           error(-1, "Wrong number of args (%d) to Type 2 hflex", nOps);
966         }
967         eexecDumpNum(op[0], fp[0]);
968         eexecDumpNum(0, gFalse);
969         eexecDumpNum(op[1], fp[1]);
970         eexecDumpNum(op[2], fp[2]);
971         eexecDumpNum(op[3], fp[3]);
972         eexecDumpNum(0, gFalse);
973         eexecDumpOp1(8);
974         eexecDumpNum(op[4], fp[4]);
975         eexecDumpNum(0, gFalse);
976         eexecDumpNum(op[5], fp[5]);
977         eexecDumpNum(-op[2], fp[2]);
978         eexecDumpNum(op[6], fp[6]);
979         eexecDumpNum(0, gFalse);
980         eexecDumpOp1(8);
981         break;
982       case 35:                  // flex
983         if (nOps != 13) {
984           error(-1, "Wrong number of args (%d) to Type 2 flex", nOps);
985         }
986         eexecDumpNum(op[0], fp[0]);
987         eexecDumpNum(op[1], fp[1]);
988         eexecDumpNum(op[2], fp[2]);
989         eexecDumpNum(op[3], fp[3]);
990         eexecDumpNum(op[4], fp[4]);
991         eexecDumpNum(op[5], fp[5]);
992         eexecDumpOp1(8);
993         eexecDumpNum(op[6], fp[6]);
994         eexecDumpNum(op[7], fp[7]);
995         eexecDumpNum(op[8], fp[8]);
996         eexecDumpNum(op[9], fp[9]);
997         eexecDumpNum(op[10], fp[10]);
998         eexecDumpNum(op[11], fp[11]);
999         eexecDumpOp1(8);
1000         break;
1001       case 36:                  // hflex1
1002         if (nOps != 9) {
1003           error(-1, "Wrong number of args (%d) to Type 2 hflex1", nOps);
1004         }
1005         eexecDumpNum(op[0], fp[0]);
1006         eexecDumpNum(op[1], fp[1]);
1007         eexecDumpNum(op[2], fp[2]);
1008         eexecDumpNum(op[3], fp[3]);
1009         eexecDumpNum(op[4], fp[4]);
1010         eexecDumpNum(0, gFalse);
1011         eexecDumpOp1(8);
1012         eexecDumpNum(op[5], fp[5]);
1013         eexecDumpNum(0, gFalse);
1014         eexecDumpNum(op[6], fp[6]);
1015         eexecDumpNum(op[7], fp[7]);
1016         eexecDumpNum(op[8], fp[8]);
1017         eexecDumpNum(-(op[1] + op[3] + op[7]), fp[1] | fp[3] | fp[7]);
1018         eexecDumpOp1(8);
1019         break;
1020       case 37:                  // flex1
1021         if (nOps != 11) {
1022           error(-1, "Wrong number of args (%d) to Type 2 flex1", nOps);
1023         }
1024         eexecDumpNum(op[0], fp[0]);
1025         eexecDumpNum(op[1], fp[1]);
1026         eexecDumpNum(op[2], fp[2]);
1027         eexecDumpNum(op[3], fp[3]);
1028         eexecDumpNum(op[4], fp[4]);
1029         eexecDumpNum(op[5], fp[5]);
1030         eexecDumpOp1(8);
1031         eexecDumpNum(op[6], fp[6]);
1032         eexecDumpNum(op[7], fp[7]);
1033         eexecDumpNum(op[8], fp[8]);
1034         eexecDumpNum(op[9], fp[9]);
1035         dx = op[0] + op[2] + op[4] + op[6] + op[8];
1036         dy = op[1] + op[3] + op[5] + op[7] + op[9];
1037         if (fabs(dx) > fabs(dy)) {
1038           eexecDumpNum(op[10], fp[10]);
1039           eexecDumpNum(-dy, fp[1] | fp[3] | fp[5] | fp[7] | fp[9]);
1040         } else {
1041           eexecDumpNum(-dx, fp[0] | fp[2] | fp[4] | fp[6] | fp[8]);
1042           eexecDumpNum(op[10], fp[10]);
1043         }
1044         eexecDumpOp1(8);
1045         break;
1046       case 3:                   // and
1047       case 4:                   // or
1048       case 5:                   // not
1049       case 8:                   // store
1050       case 9:                   // abs
1051       case 10:                  // add
1052       case 11:                  // sub
1053       case 12:                  // div
1054       case 13:                  // load
1055       case 14:                  // neg
1056       case 15:                  // eq
1057       case 18:                  // drop
1058       case 20:                  // put
1059       case 21:                  // get
1060       case 22:                  // ifelse
1061       case 23:                  // random
1062       case 24:                  // mul
1063       case 26:                  // sqrt
1064       case 27:                  // dup
1065       case 28:                  // exch
1066       case 29:                  // index
1067       case 30:                  // roll
1068         error(-1, "Unimplemented Type 2 charstring op: 12.%d", s[i+1]);
1069         break;
1070       default:
1071         error(-1, "Illegal Type 2 charstring op: 12.%d", s[i+1]);
1072         break;
1073       }
1074       i += 2;
1075       nOps = 0;
1076     } else if (s[i] == 19) {    // hintmask
1077       //~ ignored
1078       if (first) {
1079         cvtGlyphWidth(nOps == 1);
1080         first = gFalse;
1081       }
1082       if (nOps > 0) {
1083         if (nOps & 1) {
1084           error(-1, "Wrong number of args (%d) to Type 2 hintmask/vstemhm",
1085                 nOps);
1086         }
1087         nHints += nOps / 2;
1088       }
1089       i += 1 + ((nHints + 7) >> 3);
1090       nOps = 0;
1091     } else if (s[i] == 20) {    // cntrmask
1092       //~ ignored
1093       if (first) {
1094         cvtGlyphWidth(nOps == 1);
1095         first = gFalse;
1096       }
1097       if (nOps > 0) {
1098         if (nOps & 1) {
1099           error(-1, "Wrong number of args (%d) to Type 2 cntrmask/vstemhm",
1100                 nOps);
1101         }
1102         nHints += nOps / 2;
1103       }
1104       i += 1 + ((nHints + 7) >> 3);
1105       nOps = 0;
1106     } else if (s[i] == 28) {
1107       x = (s[i+1] << 8) + s[i+2];
1108       if (x & 0x8000)
1109         x |= -1 << 15;
1110       if (nOps < 48) {
1111         fp[nOps] = gFalse;
1112         op[nOps++] = x;
1113       }
1114       i += 3;
1115     } else if (s[i] <= 31) {
1116       switch (s[i]) {
1117       case 4:                   // vmoveto
1118         if (first) {
1119           cvtGlyphWidth(nOps == 2);
1120           first = gFalse;
1121         }
1122         if (nOps != 1)
1123           error(-1, "Wrong number of args (%d) to Type 2 vmoveto", nOps);
1124         eexecDumpNum(op[0], fp[0]);
1125         eexecDumpOp1(4);
1126         break;
1127       case 5:                   // rlineto
1128         if (nOps < 2 || nOps % 2 != 0)
1129           error(-1, "Wrong number of args (%d) to Type 2 rlineto", nOps);
1130         for (k = 0; k < nOps; k += 2) {
1131           eexecDumpNum(op[k], fp[k]);
1132           eexecDumpNum(op[k+1], fp[k+1]);
1133           eexecDumpOp1(5);
1134         }
1135         break;
1136       case 6:                   // hlineto
1137         if (nOps < 1)
1138           error(-1, "Wrong number of args (%d) to Type 2 hlineto", nOps);
1139         for (k = 0; k < nOps; ++k) {
1140           eexecDumpNum(op[k], fp[k]);
1141           eexecDumpOp1((k & 1) ? 7 : 6);
1142         }
1143         break;
1144       case 7:                   // vlineto
1145         if (nOps < 1)
1146           error(-1, "Wrong number of args (%d) to Type 2 vlineto", nOps);
1147         for (k = 0; k < nOps; ++k) {
1148           eexecDumpNum(op[k], fp[k]);
1149           eexecDumpOp1((k & 1) ? 6 : 7);
1150         }
1151         break;
1152       case 8:                   // rrcurveto
1153         if (nOps < 6 || nOps % 6 != 0)
1154           error(-1, "Wrong number of args (%d) to Type 2 rrcurveto", nOps);
1155         for (k = 0; k < nOps; k += 6) {
1156           eexecDumpNum(op[k], fp[k]);
1157           eexecDumpNum(op[k+1], fp[k+1]);
1158           eexecDumpNum(op[k+2], fp[k+2]);
1159           eexecDumpNum(op[k+3], fp[k+3]);
1160           eexecDumpNum(op[k+4], fp[k+4]);
1161           eexecDumpNum(op[k+5], fp[k+5]);
1162           eexecDumpOp1(8);
1163         }
1164         break;
1165       case 14:                  // endchar / seac
1166         if (first) {
1167           cvtGlyphWidth(nOps == 1 || nOps == 5);
1168           first = gFalse;
1169         }
1170         if (nOps == 4) {
1171           eexecDumpNum(0, 0);
1172           eexecDumpNum(op[0], fp[0]);
1173           eexecDumpNum(op[1], fp[1]);
1174           eexecDumpNum(op[2], fp[2]);
1175           eexecDumpNum(op[3], fp[3]);
1176           eexecDumpOp2(6);
1177         } else if (nOps == 0) {
1178           eexecDumpOp1(14);
1179         } else {
1180           error(-1, "Wrong number of args (%d) to Type 2 endchar", nOps);
1181         }
1182         break;
1183       case 21:                  // rmoveto
1184         if (first) {
1185           cvtGlyphWidth(nOps == 3);
1186           first = gFalse;
1187         }
1188         if (nOps != 2)
1189           error(-1, "Wrong number of args (%d) to Type 2 rmoveto", nOps);
1190         eexecDumpNum(op[0], fp[0]);
1191         eexecDumpNum(op[1], fp[1]);
1192         eexecDumpOp1(21);
1193         break;
1194       case 22:                  // hmoveto
1195         if (first) {
1196           cvtGlyphWidth(nOps == 2);
1197           first = gFalse;
1198         }
1199         if (nOps != 1)
1200           error(-1, "Wrong number of args (%d) to Type 2 hmoveto", nOps);
1201         eexecDumpNum(op[0], fp[0]);
1202         eexecDumpOp1(22);
1203         break;
1204       case 24:                  // rcurveline
1205         if (nOps < 8 || (nOps - 2) % 6 != 0)
1206           error(-1, "Wrong number of args (%d) to Type 2 rcurveline", nOps);
1207         for (k = 0; k < nOps - 2; k += 6) {
1208           eexecDumpNum(op[k], fp[k]);
1209           eexecDumpNum(op[k+1], fp[k+1]);
1210           eexecDumpNum(op[k+2], fp[k+2]);
1211           eexecDumpNum(op[k+3], fp[k+3]);
1212           eexecDumpNum(op[k+4], fp[k+4]);
1213           eexecDumpNum(op[k+5], fp[k+5]);
1214           eexecDumpOp1(8);
1215         }
1216         eexecDumpNum(op[k], fp[k]);
1217         eexecDumpNum(op[k+1], fp[k]);
1218         eexecDumpOp1(5);
1219         break;
1220       case 25:                  // rlinecurve
1221         if (nOps < 8 || (nOps - 6) % 2 != 0)
1222           error(-1, "Wrong number of args (%d) to Type 2 rlinecurve", nOps);
1223         for (k = 0; k < nOps - 6; k += 2) {
1224           eexecDumpNum(op[k], fp[k]);
1225           eexecDumpNum(op[k+1], fp[k]);
1226           eexecDumpOp1(5);
1227         }
1228         eexecDumpNum(op[k], fp[k]);
1229         eexecDumpNum(op[k+1], fp[k+1]);
1230         eexecDumpNum(op[k+2], fp[k+2]);
1231         eexecDumpNum(op[k+3], fp[k+3]);
1232         eexecDumpNum(op[k+4], fp[k+4]);
1233         eexecDumpNum(op[k+5], fp[k+5]);
1234         eexecDumpOp1(8);
1235         break;
1236       case 26:                  // vvcurveto
1237         if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0))
1238           error(-1, "Wrong number of args (%d) to Type 2 vvcurveto", nOps);
1239         if (nOps % 2 == 1) {
1240           eexecDumpNum(op[0], fp[0]);
1241           eexecDumpNum(op[1], fp[1]);
1242           eexecDumpNum(op[2], fp[2]);
1243           eexecDumpNum(op[3], fp[3]);
1244           eexecDumpNum(0, gFalse);
1245           eexecDumpNum(op[4], fp[4]);
1246           eexecDumpOp1(8);
1247           k = 5;
1248         } else {
1249           k = 0;
1250         }
1251         for (; k < nOps; k += 4) {
1252           eexecDumpNum(0, gFalse);
1253           eexecDumpNum(op[k], fp[k]);
1254           eexecDumpNum(op[k+1], fp[k+1]);
1255           eexecDumpNum(op[k+2], fp[k+2]);
1256           eexecDumpNum(0, gFalse);
1257           eexecDumpNum(op[k+3], fp[k+3]);
1258           eexecDumpOp1(8);
1259         }
1260         break;
1261       case 27:                  // hhcurveto
1262         if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0))
1263           error(-1, "Wrong number of args (%d) to Type 2 hhcurveto", nOps);
1264         if (nOps % 2 == 1) {
1265           eexecDumpNum(op[1], fp[1]);
1266           eexecDumpNum(op[0], fp[0]);
1267           eexecDumpNum(op[2], fp[2]);
1268           eexecDumpNum(op[3], fp[3]);
1269           eexecDumpNum(op[4], fp[4]);
1270           eexecDumpNum(0, gFalse);
1271           eexecDumpOp1(8);
1272           k = 5;
1273         } else {
1274           k = 0;
1275         }
1276         for (; k < nOps; k += 4) {
1277           eexecDumpNum(op[k], fp[k]);
1278           eexecDumpNum(0, gFalse);
1279           eexecDumpNum(op[k+1], fp[k+1]);
1280           eexecDumpNum(op[k+2], fp[k+2]);
1281           eexecDumpNum(op[k+3], fp[k+3]);
1282           eexecDumpNum(0, gFalse);
1283           eexecDumpOp1(8);
1284         }
1285         break;
1286       case 30:                  // vhcurveto
1287         if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0))
1288           error(-1, "Wrong number of args (%d) to Type 2 vhcurveto", nOps);
1289         for (k = 0; k < nOps && k != nOps-5; k += 4) {
1290           if (k % 8 == 0) {
1291             eexecDumpNum(op[k], fp[k]);
1292             eexecDumpNum(op[k+1], fp[k+1]);
1293             eexecDumpNum(op[k+2], fp[k+2]);
1294             eexecDumpNum(op[k+3], fp[k+3]);
1295             eexecDumpOp1(30);
1296           } else {
1297             eexecDumpNum(op[k], fp[k]);
1298             eexecDumpNum(op[k+1], fp[k+1]);
1299             eexecDumpNum(op[k+2], fp[k+2]);
1300             eexecDumpNum(op[k+3], fp[k+3]);
1301             eexecDumpOp1(31);
1302           }
1303         }
1304         if (k == nOps-5) {
1305           if (k % 8 == 0) {
1306             eexecDumpNum(0, gFalse);
1307             eexecDumpNum(op[k], fp[k]);
1308             eexecDumpNum(op[k+1], fp[k+1]);
1309             eexecDumpNum(op[k+2], fp[k+2]);
1310             eexecDumpNum(op[k+3], fp[k+3]);
1311             eexecDumpNum(op[k+4], fp[k+4]);
1312           } else {
1313             eexecDumpNum(op[k], fp[k]);
1314             eexecDumpNum(0, gFalse);
1315             eexecDumpNum(op[k+1], fp[k+1]);
1316             eexecDumpNum(op[k+2], fp[k+2]);
1317             eexecDumpNum(op[k+4], fp[k+4]);
1318             eexecDumpNum(op[k+3], fp[k+3]);
1319           }
1320           eexecDumpOp1(8);
1321         }
1322         break;
1323       case 31:                  // hvcurveto
1324         if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0))
1325           error(-1, "Wrong number of args (%d) to Type 2 hvcurveto", nOps);
1326         for (k = 0; k < nOps && k != nOps-5; k += 4) {
1327           if (k % 8 == 0) {
1328             eexecDumpNum(op[k], fp[k]);
1329             eexecDumpNum(op[k+1], fp[k+1]);
1330             eexecDumpNum(op[k+2], fp[k+2]);
1331             eexecDumpNum(op[k+3], fp[k+3]);
1332             eexecDumpOp1(31);
1333           } else {
1334             eexecDumpNum(op[k], fp[k]);
1335             eexecDumpNum(op[k+1], fp[k+1]);
1336             eexecDumpNum(op[k+2], fp[k+2]);
1337             eexecDumpNum(op[k+3], fp[k+3]);
1338             eexecDumpOp1(30);
1339           }
1340         }
1341         if (k == nOps-5) {
1342           if (k % 8 == 0) {
1343             eexecDumpNum(op[k], fp[k]);
1344             eexecDumpNum(0, gFalse);
1345             eexecDumpNum(op[k+1], fp[k+1]);
1346             eexecDumpNum(op[k+2], fp[k+2]);
1347             eexecDumpNum(op[k+4], fp[k+4]);
1348             eexecDumpNum(op[k+3], fp[k+3]);
1349           } else {
1350             eexecDumpNum(0, gFalse);
1351             eexecDumpNum(op[k], fp[k]);
1352             eexecDumpNum(op[k+1], fp[k+1]);
1353             eexecDumpNum(op[k+2], fp[k+2]);
1354             eexecDumpNum(op[k+3], fp[k+3]);
1355             eexecDumpNum(op[k+4], fp[k+4]);
1356           }
1357           eexecDumpOp1(8);
1358         }
1359         break;
1360       case 1:                   // hstem
1361         if (first) {
1362           cvtGlyphWidth(nOps & 1);
1363           first = gFalse;
1364         }
1365         if (nOps & 1) {
1366           error(-1, "Wrong number of args (%d) to Type 2 hstem", nOps);
1367         }
1368         d = 0;
1369         dFP = gFalse;
1370         for (k = 0; k < nOps; k += 2) {
1371           if (op[k+1] < 0) {
1372             d += op[k] + op[k+1];
1373             dFP |= fp[k] | fp[k+1];
1374             eexecDumpNum(d, dFP);
1375             eexecDumpNum(-op[k+1], fp[k+1]);
1376           } else {
1377             d += op[k];
1378             dFP |= fp[k];
1379             eexecDumpNum(d, dFP);
1380             eexecDumpNum(op[k+1], fp[k+1]);
1381             d += op[k+1];
1382             dFP |= fp[k+1];
1383           }
1384           eexecDumpOp1(1);
1385         }
1386         nHints += nOps / 2;
1387         break;
1388       case 3:                   // vstem
1389         if (first) {
1390           cvtGlyphWidth(nOps & 1);
1391           first = gFalse;
1392         }
1393         if (nOps & 1) {
1394           error(-1, "Wrong number of args (%d) to Type 2 vstem", nOps);
1395         }
1396         d = 0;
1397         dFP = gFalse;
1398         for (k = 0; k < nOps; k += 2) {
1399           if (op[k+1] < 0) {
1400             d += op[k] + op[k+1];
1401             dFP |= fp[k] | fp[k+1];
1402             eexecDumpNum(d, dFP);
1403             eexecDumpNum(-op[k+1], fp[k+1]);
1404           } else {
1405             d += op[k];
1406             dFP |= fp[k];
1407             eexecDumpNum(d, dFP);
1408             eexecDumpNum(op[k+1], fp[k+1]);
1409             d += op[k+1];
1410             dFP |= fp[k+1];
1411           }
1412           eexecDumpOp1(3);
1413         }
1414         nHints += nOps / 2;
1415         break;
1416       case 18:                  // hstemhm
1417         //~ ignored
1418         if (first) {
1419           cvtGlyphWidth(nOps & 1);
1420           first = gFalse;
1421         }
1422         if (nOps & 1) {
1423           error(-1, "Wrong number of args (%d) to Type 2 hstemhm", nOps);
1424         }
1425         nHints += nOps / 2;
1426         break;
1427       case 23:                  // vstemhm
1428         //~ ignored
1429         if (first) {
1430           cvtGlyphWidth(nOps & 1);
1431           first = gFalse;
1432         }
1433         if (nOps & 1) {
1434           error(-1, "Wrong number of args (%d) to Type 2 vstemhm", nOps);
1435         }
1436         nHints += nOps / 2;
1437         break;
1438       case 10:                  // callsubr
1439       case 11:                  // return
1440       case 16:                  // blend
1441       case 29:                  // callgsubr
1442         error(-1, "Unimplemented Type 2 charstring op: %d", s[i]);
1443         break;
1444       default:
1445         error(-1, "Illegal Type 2 charstring op: %d", s[i]);
1446         break;
1447       }
1448       ++i;
1449       nOps = 0;
1450     } else if (s[i] <= 246) {
1451       if (nOps < 48) {
1452         fp[nOps] = gFalse;
1453         op[nOps++] = (int)s[i] - 139;
1454       }
1455       ++i;
1456     } else if (s[i] <= 250) {
1457       if (nOps < 48) {
1458         fp[nOps] = gFalse;
1459         op[nOps++] = (((int)s[i] - 247) << 8) + (int)s[i+1] + 108;
1460       }
1461       i += 2;
1462     } else if (s[i] <= 254) {
1463       if (nOps < 48) {
1464         fp[nOps] = gFalse;
1465         op[nOps++] = -(((int)s[i] - 251) << 8) - (int)s[i+1] - 108;
1466       }
1467       i += 2;
1468     } else {
1469       x = (s[i+1] << 24) | (s[i+2] << 16) | (s[i+3] << 8) | s[i+4];
1470       if (x & 0x80000000)
1471         x |= -1 << 31;
1472       if (nOps < 48) {
1473         fp[nOps] = gTrue;
1474         op[nOps++] = (double)x / 65536.0;
1475       }
1476       i += 5;
1477     }
1478   }
1479
1480   sprintf(eBuf, "/%s %d RD ", name, charBuf->getLength());
1481   eexecWrite(eBuf);
1482   eexecWriteCharstring((Guchar *)charBuf->getCString(), charBuf->getLength());
1483   eexecWrite(" ND\n");
1484   delete charBuf;
1485 }
1486
1487 void Type1CFontConverter::cvtGlyphWidth(GBool useOp) {
1488   double w;
1489   GBool wFP;
1490   int i;
1491
1492   if (useOp) {
1493     w = nominalWidthX + op[0];
1494     wFP = nominalWidthXFP | fp[0];
1495     for (i = 1; i < nOps; ++i) {
1496       op[i-1] = op[i];
1497       fp[i-1] = fp[i];
1498     }
1499     --nOps;
1500   } else {
1501     w = defaultWidthX;
1502     wFP = defaultWidthXFP;
1503   }
1504   eexecDumpNum(0, gFalse);
1505   eexecDumpNum(w, wFP);
1506   eexecDumpOp1(13);
1507 }
1508
1509 void Type1CFontConverter::eexecDumpNum(double x, GBool fp) {
1510   Guchar buf[12];
1511   int y, n;
1512
1513   n = 0;
1514   if (fp) {
1515     if (x >= -32768 && x < 32768) {
1516       y = (int)(x * 256.0);
1517       buf[0] = 255;
1518       buf[1] = (Guchar)(y >> 24);
1519       buf[2] = (Guchar)(y >> 16);
1520       buf[3] = (Guchar)(y >> 8);
1521       buf[4] = (Guchar)y;
1522       buf[5] = 255;
1523       buf[6] = 0;
1524       buf[7] = 0;
1525       buf[8] = 1;
1526       buf[9] = 0;
1527       buf[10] = 12;
1528       buf[11] = 12;
1529       n = 12;
1530     } else {
1531       error(-1, "Type 2 fixed point constant out of range");
1532     }
1533   } else {
1534     y = (int)x;
1535     if (y >= -107 && y <= 107) {
1536       buf[0] = (Guchar)(y + 139);
1537       n = 1;
1538     } else if (y > 107 && y <= 1131) {
1539       y -= 108;
1540       buf[0] = (Guchar)((y >> 8) + 247);
1541       buf[1] = (Guchar)(y & 0xff);
1542       n = 2;
1543     } else if (y < -107 && y >= -1131) {
1544       y = -y - 108;
1545       buf[0] = (Guchar)((y >> 8) + 251);
1546       buf[1] = (Guchar)(y & 0xff);
1547       n = 2;
1548     } else {
1549       buf[0] = 255;
1550       buf[1] = (Guchar)(y >> 24);
1551       buf[2] = (Guchar)(y >> 16);
1552       buf[3] = (Guchar)(y >> 8);
1553       buf[4] = (Guchar)y;
1554       n = 5;
1555     }
1556   }
1557   charBuf->append((char *)buf, n);
1558 }
1559
1560 void Type1CFontConverter::eexecDumpOp1(int op) {
1561   charBuf->append((char)op);
1562 }
1563
1564 void Type1CFontConverter::eexecDumpOp2(int op) {
1565   charBuf->append((char)12);
1566   charBuf->append((char)op);
1567 }
1568
1569 void Type1CFontConverter::eexecWriteCharstring(Guchar *s, int n) {
1570   Gushort r2;
1571   Guchar x;
1572   int i;
1573
1574   r2 = 4330;
1575
1576   for (i = 0; i < n; ++i) {
1577     // charstring encryption
1578     x = s[i];
1579     x ^= (r2 >> 8);
1580     r2 = (x + r2) * 52845 + 22719;
1581
1582     // eexec encryption
1583     x ^= (r1 >> 8);
1584     r1 = (x + r1) * 52845 + 22719;
1585     fputc(hexChars[x >> 4], out);
1586     fputc(hexChars[x & 0x0f], out);
1587     line += 2;
1588     if (line == 64) {
1589       fputc('\n', out);
1590       line = 0;
1591     }
1592   }
1593 }
1594
1595 void Type1CFontConverter::getDeltaInt(char *buf, char *name, double *op,
1596                                       int n) {
1597   int x, i;
1598
1599   buf += sprintf(buf, "/%s [", name);
1600   x = 0;
1601   for (i = 0; i < n; ++i) {
1602     x += (int)op[i];
1603     buf += sprintf(buf, "%s%d", i > 0 ? " " : "", x);
1604   }
1605   sprintf(buf, "] def\n");
1606 }
1607
1608 void Type1CFontConverter::getDeltaReal(char *buf, char *name, double *op,
1609                                        int n) {
1610   double x;
1611   int i;
1612
1613   buf += sprintf(buf, "/%s [", name);
1614   x = 0;
1615   for (i = 0; i < n; ++i) {
1616     x += op[i];
1617     buf += sprintf(buf, "%s%g", i > 0 ? " " : "", x);
1618   }
1619   sprintf(buf, "] def\n");
1620 }