1 // -*- related-file-name: "../include/efont/t1item.hh" -*-
2 
3 /* t1item.{cc,hh} -- items in a Type 1 font
4  *
5  * Copyright (c) 1998-2019 Eddie Kohler
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the Free
9  * Software Foundation; either version 2 of the License, or (at your option)
10  * any later version. This program is distributed in the hope that it will be
11  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
13  * Public License for more details.
14  */
15 
16 #ifdef HAVE_CONFIG_H
17 # include <config.h>
18 #endif
19 #include <efont/t1item.hh>
20 #include <efont/t1rw.hh>
21 #include <efont/t1interp.hh>
22 #include <efont/t1font.hh>
23 #include <lcdf/strtonum.h>
24 #include <ctype.h>
25 #include <string.h>
26 #include <sys/stat.h>
27 #ifndef WIN32
28 # include <unistd.h>
29 #endif
30 #if HAVE_BROKEN_STRTOD
31 # define strtod good_strtod
32 #endif
33 namespace Efont {
34 
35 /*****
36  * Type1NullItem
37  **/
38 
39 void
gen(Type1Writer &)40 Type1NullItem::gen(Type1Writer &)
41 {
42 }
43 
44 /*****
45  * Type1CopyItem
46  **/
47 
48 void
gen(Type1Writer & w)49 Type1CopyItem::gen(Type1Writer &w)
50 {
51     w << _value << '\n';
52 }
53 
54 
55 /*****
56  * Type1EexecItem
57  **/
58 
59 void
gen(Type1Writer & w)60 Type1EexecItem::gen(Type1Writer &w)
61 {
62     if (_eexec_on)
63         w << "currentfile eexec\n";
64     w.switch_eexec(_eexec_on);
65 }
66 
67 
68 /*****
69  * Type1Definition
70  **/
71 
72 typedef Vector<double> NumVector;
73 
74 
Type1Definition(PermString n,const String & v,PermString d)75 Type1Definition::Type1Definition(PermString n, const String &v, PermString d)
76     : _name(n), _val(v), _definer(d)
77 {
78     _val.c_str();               // ensure it ends with '\0'
79 }
80 
81 Type1Definition *
make_string(PermString n,const String & v,PermString d)82 Type1Definition::make_string(PermString n, const String &v, PermString d)
83 {
84     Type1Definition *t1d = new Type1Definition(n, "", d);
85     t1d->set_string(v);
86     return t1d;
87 }
88 
89 int
slurp_string(StringAccum & accum,int pos,Type1Reader * reader)90 Type1Definition::slurp_string(StringAccum &accum, int pos, Type1Reader *reader)
91 {
92     int paren_level = 0;
93     char *s = accum.data() + pos;
94 
95     do {
96         switch (*s++) {
97           case '(': paren_level++; break;
98           case ')': paren_level--; break;
99           case '\\': if (paren_level && *s) s++; break;
100           case 0:
101             if (!reader) return -1;
102             pos = s - accum.data();
103             accum.append('\n'); // add \n
104             if (!reader->next_line(accum)) return -1;
105             accum.c_str();      // ensure null termination
106             s = accum.data() + pos;
107             break;
108         }
109     } while (paren_level);
110 
111     return s - accum.data();
112 }
113 
114 int
slurp_proc(StringAccum & accum,int pos,Type1Reader * reader)115 Type1Definition::slurp_proc(StringAccum &accum, int pos, Type1Reader *reader)
116 {
117     int paren_level = 0;
118     int brace_level = 0;
119     char *s = accum.data() + pos;
120 
121     do {
122         switch (*s++) {
123           case '{': if (!paren_level) brace_level++; break;
124           case '}': if (!paren_level) brace_level--; break;
125           case '(': paren_level++; break;
126           case ')': paren_level--; break;
127           case '\\': if (paren_level && *s) s++; break;
128           case '%':
129             if (!paren_level)
130                 while (*s != '\n' && *s != '\r' && *s)
131                     s++;
132             break;
133           case 0:
134             if (!reader) return -1;
135             pos = s - accum.data();
136             accum.append('\n'); // add \n
137             if (!reader->next_line(accum)) return -1;
138             accum.c_str();      // ensure null termination
139             s = accum.data() + pos;
140             break;
141         }
142     } while (brace_level);
143 
144     return s - accum.data();
145 }
146 
147 Type1Definition *
make(StringAccum & accum,Type1Reader * reader,bool force_definition)148 Type1Definition::make(StringAccum &accum, Type1Reader *reader,
149                       bool force_definition)
150 {
151     char *s = accum.data();
152     while (isspace((unsigned char) *s))
153         s++;
154     if (*s != '/')
155         return 0;
156     s++;
157     int name_start_pos = s - accum.data();
158 
159     // find NAME LENGTH
160     while (!isspace((unsigned char) *s) && *s != '[' && *s != '{' && *s != '('
161            && *s != ']' && *s != '}' && *s != ')' && *s)
162         s++;
163     if (!*s)
164         return 0;
165     int name_end_pos = s - accum.data();
166 
167     while (isspace((unsigned char) *s))
168         s++;
169     int val_pos = s - accum.data();
170     int val_end_pos = -1;
171     bool check_def = false;
172 
173     if (*s == '}' || *s == ']' || *s == ')' || *s == 0)
174         return 0;
175 
176     else if (*s == '(')
177         val_end_pos = slurp_string(accum, val_pos, reader);
178 
179     else if (*s == '{')
180         val_end_pos = slurp_proc(accum, val_pos, reader);
181 
182     else if (*s == '[') {
183         int brack_level = 0;
184         do {
185             switch (*s++) {
186               case '[': brack_level++; break;
187               case ']': brack_level--; break;
188               case '(': case ')': case 0: return 0;
189             }
190         } while (brack_level);
191         val_end_pos = s - accum.data();
192 
193     } else {
194         while (!isspace((unsigned char) *s) && *s)
195             s++;
196         val_end_pos = s - accum.data();
197         if (!force_definition) check_def = true;
198     }
199 
200     if (val_end_pos < 0)
201         return 0;
202     s = accum.data() + val_end_pos;
203     while (isspace((unsigned char) *s))
204         s++;
205     if (check_def && (s[0] != 'd' || s[1] != 'e' || s[2] != 'f'))
206         if (strncmp(s, "dict def", 8) != 0)
207             return 0;
208 
209     PermString name(accum.data()+name_start_pos, name_end_pos - name_start_pos);
210     PermString def(s, accum.length() - (s - accum.data()));
211     String value = String(accum.data() + val_pos, val_end_pos - val_pos);
212     return new Type1Definition(name, value, def);
213 }
214 
215 void
gen(Type1Writer & w)216 Type1Definition::gen(Type1Writer &w)
217 {
218     w << '/' << _name << ' ' << _val << ' ' << _definer << '\n';
219 }
220 
221 void
gen(StringAccum & sa)222 Type1Definition::gen(StringAccum &sa)
223 {
224     sa << '/' << _name << ' ' << _val << ' ' << _definer;
225 }
226 
227 
228 bool
value_bool(bool & b) const229 Type1Definition::value_bool(bool &b) const
230 {
231     if (_val == "true") {
232         b = true;
233         return true;
234     } else if (_val == "false") {
235         b = false;
236         return true;
237     } else
238         return false;
239 }
240 
241 bool
value_int(int & i) const242 Type1Definition::value_int(int &i) const
243 {
244     char *s;
245     i = strtol(_val.data(), &s, 10);
246     return (*s == 0);
247 }
248 
249 bool
value_num(double & d) const250 Type1Definition::value_num(double &d) const
251 {
252     char *s;
253     d = strtonumber(_val.data(), &s);
254     return (*s == 0);
255 }
256 
257 bool
value_string(String & str) const258 Type1Definition::value_string(String &str) const
259 {
260     if (_val.length() == 0 || _val[0] != '(' || _val.back() != ')')
261         return false;
262     StringAccum sa;
263     int pos, first_pos = 1, len = _val.length() - 1;
264     for (pos = 1; pos < len; pos++)
265         if (_val[pos] == '\\') {
266             sa.append(_val.data() + first_pos, pos - first_pos);
267             pos++;
268             switch (pos < len ? _val[pos] : -1) {
269               case '\r':
270                 pos++;
271                 if (pos < len && _val[pos] == '\n')
272                     pos++;
273                 break;
274               case '\n':
275                 pos++;
276                 break;
277               case '0': case '1': case '2': case '3':
278               case '4': case '5': case '6': case '7': {
279                   int c = _val[pos++] - '0';
280                   for (int i = 1; pos < len && i < 3 && _val[pos] >= '0' && _val[pos] <= '7'; i++, pos++)
281                       c = (c << 3) | (_val[pos] - '0');
282                   sa.append((char) c);
283                   break;
284               }
285               case 'n':
286                 sa << '\n';
287                 pos++;
288                 break;
289               case 'r':
290                 sa << '\r';
291                 pos++;
292                 break;
293               case 't':
294                 sa << '\t';
295                 pos++;
296                 break;
297               case 'b':
298                 sa << '\b';
299                 pos++;
300                 break;
301               case 'f':
302                 sa << '\f';
303                 pos++;
304                 break;
305               default:
306                 sa << _val[pos];
307                 pos++;
308                 break;
309             }
310             first_pos = pos;
311         }
312     sa.append(_val.data() + first_pos, len - first_pos);
313     str = sa.take_string();
314     return true;
315 }
316 
317 bool
value_name(PermString & str) const318 Type1Definition::value_name(PermString &str) const
319 {
320     if (_val.length() == 0 || _val[0] != '/')
321         return false;
322     int pos;
323     for (pos = 1; pos < _val.length(); pos++)
324         if (isspace((unsigned char) _val[pos]) || _val[pos] == '/')
325             return false;
326     str = PermString(_val.data() + 1, pos - 1);
327     return true;
328 }
329 
330 static bool
strtonumvec(const char * f,const char ** endf,NumVector & v)331 strtonumvec(const char *f, const char **endf, NumVector &v)
332 {
333     v.clear();
334     char *s = (char *)f;
335     if (*s != '[' && *s != '{')
336         return false;
337     s++;
338     while (1) {
339         while (isspace((unsigned char) *s))
340             s++;
341         if (isdigit((unsigned char) *s) || *s == '.' || *s == '-')
342             v.push_back( strtonumber(s, &s) );
343         else {
344             if (endf)
345                 *endf = s + 1;
346             return (*s == ']' || *s == '}');
347         }
348     }
349 }
350 
351 bool
value_numvec(NumVector & v) const352 Type1Definition::value_numvec(NumVector &v) const
353 {
354     return strtonumvec(_val.data(), 0, v);
355 }
356 
357 static bool
strtonumvec_vec(const char * f,const char ** endf,Vector<NumVector> & v)358 strtonumvec_vec(const char *f, const char **endf, Vector<NumVector> &v)
359 {
360     v.clear();
361     const char *s = f;
362     if (*s != '[' && *s != '{')
363         return false;
364     s++;
365     while (1) {
366         while (isspace((unsigned char) *s))
367             s++;
368         if (*s == '[' || *s == '{') {
369             NumVector subv;
370             if (!strtonumvec(s, &s, subv))
371                 return false;
372             v.push_back(subv);
373         } else {
374             if (endf)
375                 *endf = s + 1;
376             return (*s == ']' || *s == '}');
377         }
378     }
379 }
380 
381 bool
value_numvec_vec(Vector<NumVector> & v) const382 Type1Definition::value_numvec_vec(Vector<NumVector> &v) const
383 {
384     return strtonumvec_vec(_val.data(), 0, v);
385 }
386 
387 bool
value_normalize(Vector<NumVector> & in,Vector<NumVector> & out) const388 Type1Definition::value_normalize(Vector<NumVector> &in,
389                                  Vector<NumVector> &out) const
390 {
391     in.clear();
392     out.clear();
393     const char *s = _val.data();
394     if (*s++ != '[')
395         return false;
396     while (1) {
397         while (isspace((unsigned char) *s))
398             s++;
399         if (*s == '[') {
400             Vector<NumVector> sub;
401             if (!strtonumvec_vec(s, &s, sub))
402                 return false;
403 
404             NumVector subin;
405             NumVector subout;
406             for (int i = 0; i < sub.size(); i++)
407                 if (sub[i].size() == 2) {
408                     subin.push_back(sub[i][0]);
409                     subout.push_back(sub[i][1]);
410                 } else
411                     return false;
412             in.push_back(subin);
413             out.push_back(subout);
414         } else
415             return (*s == ']');
416     }
417 }
418 
419 bool
value_namevec(Vector<PermString> & v) const420 Type1Definition::value_namevec(Vector<PermString> &v) const
421 {
422     v.clear();
423     const char *s = _val.data();
424     if (*s++ != '[')
425         return false;
426     while (1) {
427         while (isspace((unsigned char) *s))
428             s++;
429         if (*s == '/')
430             s++;
431         if (isalnum((unsigned char) *s)) {
432             const char *start = s;
433             while (*s && !isspace((unsigned char) *s) && *s != ']' && *s != '/')
434                 s++;
435             v.push_back(PermString(start, s - start));
436         } else
437             return (*s == ']');
438     }
439 }
440 
441 
442 void
set_bool(bool b)443 Type1Definition::set_bool(bool b)
444 {
445     set_val(b ? "true" : "false");
446 }
447 
448 void
set_int(int i)449 Type1Definition::set_int(int i)
450 {
451     set_val(String(i));
452 }
453 
454 void
set_num(double n)455 Type1Definition::set_num(double n)
456 {
457     set_val(String(n));
458 }
459 
460 void
set_string(const String & v)461 Type1Definition::set_string(const String &v)
462 {
463     const char *s = v.data();
464     int len = v.length();
465     int left = 0;
466     StringAccum sa;
467     sa << '(';
468     for (int pos = 0; pos < len; pos++)
469         if ((s[pos] < ' ' && !isspace((unsigned char) s[pos])) || ((unsigned char)s[pos]) > 0176 || s[pos] == '(' || s[pos] == ')' || s[pos] == '\\') {
470             sa << v.substring(left, pos - left) << '\\';
471             if (s[pos] == '(' || s[pos] == ')' || s[pos] == '\\')
472                 sa << s[pos];
473             else
474                 sprintf(sa.reserve(8), "%03o", (unsigned char) (s[pos]));
475             left = pos + 1;
476         }
477     sa << v.substring(left) << ')';
478     _val = sa.take_string();
479 }
480 
481 void
set_name(PermString str,bool name)482 Type1Definition::set_name(PermString str, bool name)
483 {
484     StringAccum sa;
485     if (name)
486         sa << '/';
487     sa << str;
488     set_val(sa);
489 }
490 
491 static void
accum_numvec(StringAccum & sa,const NumVector & nv,bool executable)492 accum_numvec(StringAccum &sa, const NumVector &nv, bool executable)
493 {
494     char open = (executable ? '{' : '[');
495     for (int i = 0; i < nv.size(); i++)
496         sa << (i ? ' ' : open) << nv[i];
497     sa << (executable ? '}' : ']');
498 }
499 
500 void
set_numvec(const NumVector & nv,bool executable)501 Type1Definition::set_numvec(const NumVector &nv, bool executable)
502 {
503     StringAccum sa;
504     accum_numvec(sa, nv, executable);
505     set_val(sa);
506 }
507 
508 void
set_numvec_vec(const Vector<NumVector> & nv)509 Type1Definition::set_numvec_vec(const Vector<NumVector> &nv)
510 {
511     StringAccum sa;
512     sa << '[';
513     for (int i = 0; i < nv.size(); i++)
514         accum_numvec(sa, nv[i], false);
515     sa << ']';
516     set_val(sa);
517 }
518 
519 void
set_normalize(const Vector<NumVector> & vin,const Vector<NumVector> & vout)520 Type1Definition::set_normalize(const Vector<NumVector> &vin,
521                                const Vector<NumVector> &vout)
522 {
523     StringAccum sa;
524     sa << '[';
525     for (int i = 0; i < vin.size(); i++) {
526         const NumVector &vini = vin[i];
527         const NumVector &vouti = vout[i];
528         sa << '[';
529         for (int j = 0; j < vini.size(); j++)
530             sa << '[' << vini[j] << ' ' << vouti[j] << ']';
531         sa << ']';
532     }
533     sa << ']';
534     set_val(sa);
535 }
536 
537 void
set_namevec(const Vector<PermString> & v,bool executable)538 Type1Definition::set_namevec(const Vector<PermString> &v, bool executable)
539 {
540     StringAccum sa;
541     sa << '[';
542     for (int i = 0; i < v.size(); i++) {
543         if (i) sa << ' ';
544         if (executable) sa << '/';
545         sa << v[i];
546     }
547     sa << ']';
548     set_val(sa);
549 }
550 
551 
552 /*****
553  * Type1Encoding
554  **/
555 
556 static PermString::Initializer initializer;
557 static PermString dot_notdef(".notdef");
558 
559 
Type1Encoding()560 Type1Encoding::Type1Encoding()
561     : _v(new PermString[256]), _copy_of(0), _definer("readonly def")
562 {
563     for (int i = 0; i < 256; i++)
564         _v[i] = dot_notdef;
565 }
566 
Type1Encoding(const Type1Encoding & o)567 Type1Encoding::Type1Encoding(const Type1Encoding &o)
568     : Type1Item(), _definer(o._definer)
569 {
570     if (o._copy_of) {
571         _v = o._v;
572         _copy_of = o._copy_of;
573     } else {
574         _v = new PermString[256];
575         _copy_of = 0;
576         for (int i = 0; i < 256; i++)
577             _v[i] = o._v[i];
578     }
579 }
580 
Type1Encoding(Type1Encoding * copy_of)581 Type1Encoding::Type1Encoding(Type1Encoding *copy_of)
582     : _v(copy_of->_v), _copy_of(copy_of), _definer(copy_of->_definer)
583 {
584 }
585 
~Type1Encoding()586 Type1Encoding::~Type1Encoding()
587 {
588     if (!_copy_of)
589         delete[] _v;
590 }
591 
592 void
unshare()593 Type1Encoding::unshare()
594 {
595     if (_copy_of) {
596         PermString *new_v = new PermString[256];
597         memcpy(new_v, _v, sizeof(PermString) * 256);
598         _v = new_v;
599         _copy_of = 0;
600     }
601 }
602 
603 void
clear()604 Type1Encoding::clear()
605 {
606     unshare();
607     for (int i = 0; i < 256; i++)
608         _v[i] = dot_notdef;
609 }
610 
611 
612 static Type1Encoding *canonical_standard_encoding;
613 
614 Type1Encoding *
standard_encoding()615 Type1Encoding::standard_encoding()
616 {
617     if (!canonical_standard_encoding) {
618         canonical_standard_encoding = new Type1Encoding;
619         for (int i = 0; i < 256; i++)
620             if (Charstring::standard_encoding[i])
621                 canonical_standard_encoding->put(i, Charstring::standard_encoding[i]);
622     }
623     // Return a copy of the cached encoding. When it's deleted, we won't be.
624     return new Type1Encoding(canonical_standard_encoding);
625 }
626 
627 
628 void
gen(Type1Writer & w)629 Type1Encoding::gen(Type1Writer &w)
630 {
631     if (_copy_of && _copy_of == canonical_standard_encoding)
632         w << "/Encoding StandardEncoding def\n";
633     else {
634         w << "/Encoding 256 array\n0 1 255 {1 index exch /.notdef put} for\n";
635         for (int i = 0; i < 256; i++)
636             if (_v[i] != dot_notdef)
637                 w << "dup " << i << " /" << _v[i] << " put\n";
638         w << _definer << '\n';
639     }
640 }
641 
642 
643 /*****
644  * Type1Subr
645  **/
646 
Type1Subr(PermString n,int num,PermString definer,int lenIV,const String & s)647 Type1Subr::Type1Subr(PermString n, int num, PermString definer,
648                      int lenIV, const String &s)
649     : _name(n), _subrno(num), _definer(definer), _cs(lenIV, s)
650 {
651 }
652 
Type1Subr(PermString n,int num,PermString definer,const Type1Charstring & t1cs)653 Type1Subr::Type1Subr(PermString n, int num, PermString definer,
654                      const Type1Charstring &t1cs)
655     : _name(n), _subrno(num), _definer(definer), _cs(t1cs)
656 {
657 }
658 
659 Type1Subr *
make(const char * s_in,int s_len,int cs_pos,int cs_len,int lenIV)660 Type1Subr::make(const char *s_in, int s_len, int cs_pos, int cs_len, int lenIV)
661 {
662     /* USAGE NOTE: You must ensure that s_in contains a valid subroutine string
663        before calling Type1Subr::make. Type1Reader::was_charstring() is a good
664        guarantee of this.
665        A valid subroutine string is one of the following:
666        /[char_name] ### charstring_start ........
667        dup [subrno] ### charstring_start .... */
668 
669     const char *s = s_in;
670     PermString name;
671     int subrno = 0;
672 
673     // Force literal spaces rather than isspace().
674     if (*s == '/') {
675         const char *nstart = ++s;
676         while (!isspace((unsigned char) *s) && *s)
677             s++;
678         name = PermString(nstart, s - nstart);
679 
680     } else {
681         // dup [subrno] ...
682         s += 3;
683         while (isspace((unsigned char) *s))
684             s++;
685         subrno = strtol(s, (char **)&s, 10);
686     }
687 
688     s = s_in + cs_pos;
689 
690     // Lazily decrypt the charstring.
691     PermString definer = PermString(s + cs_len, s_len - cs_len - cs_pos);
692     return new Type1Subr(name, subrno, definer, lenIV, String(s, cs_len));
693 }
694 
695 Type1Subr *
make_subr(int subrno,const Type1Charstring & cs,PermString definer)696 Type1Subr::make_subr(int subrno, const Type1Charstring &cs, PermString definer)
697 {
698     return new Type1Subr(PermString(), subrno, definer, cs);
699 }
700 
701 Type1Subr *
make_glyph(PermString glyph,const Type1Charstring & cs,PermString definer)702 Type1Subr::make_glyph(PermString glyph, const Type1Charstring &cs, PermString definer)
703 {
704     return new Type1Subr(glyph, -1, definer, cs);
705 }
706 
707 
708 void
gen(Type1Writer & w)709 Type1Subr::gen(Type1Writer &w)
710 {
711     int len = _cs.length();
712     const unsigned char *data = _cs.data();
713 
714     if (is_subr())
715         w << "dup " << _subrno << ' ' << len + w.lenIV() << w.charstring_start();
716     else
717         w << '/' << _name << ' ' << len + w.lenIV() << w.charstring_start();
718 
719     if (w.lenIV() < 0) {
720         // lenIV < 0 means charstrings are unencrypted
721         w.print((const char *)data, len);
722 
723     } else {
724         // PERFORMANCE NOTE: Putting the charstring in a buffer of known length
725         // and printing that buffer rather than one char at a time is an OK
726         // optimization. (around 10%)
727         unsigned char *buf = new unsigned char[len + w.lenIV()];
728         unsigned char *t = buf;
729 
730         int r = t1R_cs;
731         for (int i = 0; i < w.lenIV(); i++) {
732             unsigned char c = (unsigned char)(r >> 8);
733             *t++ = c;
734             r = ((c + r) * (uint32_t) t1C1 + t1C2) & 0xFFFF;
735         }
736         for (int i = 0; i < len; i++, data++) {
737             unsigned char c = (*data ^ (r >> 8));
738             *t++ = c;
739             r = ((c + r) * (uint32_t) t1C1 + t1C2) & 0xFFFF;
740         }
741 
742         w.print((char *)buf, len + w.lenIV());
743         delete[] buf;
744     }
745 
746     w << _definer << '\n';
747 }
748 
749 /*****
750  * Type1SubrGroupItem
751  **/
752 
Type1SubrGroupItem(Type1Font * font,bool is_subrs,const String & value)753 Type1SubrGroupItem::Type1SubrGroupItem(Type1Font *font, bool is_subrs, const String &value)
754     : _font(font), _is_subrs(is_subrs), _value(value)
755 {
756 }
757 
Type1SubrGroupItem(const Type1SubrGroupItem & from,Type1Font * font)758 Type1SubrGroupItem::Type1SubrGroupItem(const Type1SubrGroupItem &from, Type1Font *font)
759     : _font(font), _is_subrs(from._is_subrs),
760       _value(from._value), _end_text(from._end_text)
761 {
762 }
763 
764 void
add_end_text(const String & s)765 Type1SubrGroupItem::add_end_text(const String &s)
766 {
767     _end_text += s + "\n";
768 }
769 
770 void
gen(Type1Writer & w)771 Type1SubrGroupItem::gen(Type1Writer &w)
772 {
773     Type1Font *font = _font;
774 
775     int pos = _value.find_left(_is_subrs ? " array" : " dict");
776     if (pos >= 1 && isdigit((unsigned char) _value[pos - 1])) {
777         int numpos = pos - 1;
778         while (numpos >= 1 && isdigit((unsigned char) _value[numpos - 1]))
779             numpos--;
780 
781         int n;
782         if (_is_subrs) {
783             n = font->nsubrs();
784             while (n && !font->subr(n - 1))
785                 n--;
786         } else
787             n = font->nglyphs();
788 
789         w << _value.substring(0, numpos) << n << _value.substring(pos);
790     } else
791         w << _value;
792 
793     w << '\n';
794 
795     if (_is_subrs) {
796         int count = font->nsubrs();
797         for (int i = 0; i < count; i++)
798             if (Type1Subr *g = font->subr_x(i))
799                 g->gen(w);
800     } else {
801         int count = font->nglyphs();
802         for (int i = 0; i < count; i++)
803             if (Type1Subr *g = font->glyph_x(i))
804                 g->gen(w);
805     }
806 
807     w << _end_text;
808 }
809 
810 /*****
811  * Type1IncludedFont
812  **/
813 
Type1IncludedFont(Type1Font * font,int unique_id)814 Type1IncludedFont::Type1IncludedFont(Type1Font *font, int unique_id)
815     : _included_font(font), _unique_id(unique_id)
816 {
817 }
818 
~Type1IncludedFont()819 Type1IncludedFont::~Type1IncludedFont()
820 {
821     delete _included_font;
822 }
823 
824 void
gen(Type1Writer & w)825 Type1IncludedFont::gen(Type1Writer &w)
826 {
827     FILE *f = tmpfile();
828     if (!f)
829         return;
830 
831     // write included font
832     Type1PFAWriter new_w(f);
833     _included_font->write(new_w);
834     fflush(f);
835 
836     struct stat s;
837     fstat(fileno(f), &s);
838 
839     w << "FontDirectory /" << _included_font->font_name() << " known{\n"
840       << "/" << _included_font->font_name()
841       << " findfont dup /UniqueID known {dup /UniqueID get "
842       << _unique_id
843       << " eq exch /FontType get 1 eq and}{pop false}ifelse {\nsave userdict/fbufstr 512 string put\n"
844       << (int)(s.st_size / 512)
845       << "{currentfile fbufstr readstring{pop}{clear currentfile\nclosefile/fontdownload/unexpectedEOF/.error cvx exec}ifelse}repeat\ncurrentfile "
846       << (int)(s.st_size % 512)
847       << " string readstring{pop}{clear currentfile\nclosefile/fontdownload/unexpectedEOF/.error cvx exec}ifelse\nrestore}if}if\n";
848 
849     rewind(f);
850     char str[2048];
851     while (1) {
852         int r = fread(str, 1, 2048, f);
853         if (r <= 0)
854             break;
855         w.print(str, r);
856     }
857 
858     fclose(f);
859 }
860 
861 }
862