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