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