1 // -*- related-file-name: "../include/efont/t1rw.hh" -*-
2
3 /* t1rw.{cc,hh} -- Type 1 font reading and writing
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/t1rw.hh>
20 #include <efont/t1cs.hh>
21 #include <lcdf/straccum.hh>
22 #include <stdlib.h>
23 #include <ctype.h>
24 #include <string.h>
25 namespace Efont {
26
27 unsigned char Type1Reader::xvalue_store[257];
28 unsigned char *Type1Reader::xvalue = &Type1Reader::xvalue_store[1];
29
30 void
static_initialize()31 Type1Reader::static_initialize()
32 {
33 if (xvalue['A'])
34 return;
35 // rely on static data being initialized to 0
36 xvalue['0'] = 0; xvalue['1'] = 1; xvalue['2'] = 2; xvalue['3'] = 3;
37 xvalue['4'] = 4; xvalue['5'] = 5; xvalue['6'] = 6; xvalue['7'] = 7;
38 xvalue['8'] = 8; xvalue['9'] = 9;
39 xvalue['A'] = 10; xvalue['B'] = 11; xvalue['C'] = 12; xvalue['D'] = 13;
40 xvalue['E'] = 14; xvalue['F'] = 15;
41 xvalue['a'] = 10; xvalue['b'] = 11; xvalue['c'] = 12; xvalue['d'] = 13;
42 xvalue['e'] = 14; xvalue['f'] = 15;
43 }
44
45
Type1Reader()46 Type1Reader::Type1Reader()
47 : _data(new unsigned char[DATA_SIZE]), _len(0), _pos(0),
48 _ungot(-1), _eexec(false)
49 {
50 static_initialize();
51 }
52
~Type1Reader()53 Type1Reader::~Type1Reader()
54 {
55 delete[] _data;
56 }
57
58
59 void
set_charstring_definer(PermString x)60 Type1Reader::set_charstring_definer(PermString x)
61 {
62 _charstring_definer = x;
63 }
64
65 void
switch_eexec(bool on,unsigned char * data,int len)66 Type1Reader::switch_eexec(bool on, unsigned char *data, int len)
67 {
68 if (on) {
69 if (_pos < len + 3) {
70 unsigned char *new_data = new unsigned char[len + 3 + DATA_SIZE];
71 assert(_len <= DATA_SIZE);
72 memcpy(new_data + len + 3, _data + _pos, _len - _pos);
73 _len = len + 3 + _len - _pos;
74 _pos = len + 3;
75 delete[] _data;
76 _data = new_data;
77 }
78 int original_pos = _pos;
79 // don't forget _ungot!!
80 if (_ungot >= 0)
81 _data[--_pos] = _ungot, _ungot = -1;
82 if (_crlf == 0 || _crlf == 2)
83 _data[--_pos] = '\n';
84 if (_crlf == 1 || _crlf == 2)
85 _data[--_pos] = '\r';
86 memcpy(_data + _pos - len, data, len);
87 _pos -= len;
88 start_eexec(original_pos - _pos);
89 }
90 _eexec = on;
91 }
92
93
94 int
more_data()95 Type1Reader::more_data()
96 {
97 _pos = 0;
98 _len = more_data(_data, DATA_SIZE);
99 if (_len < 0)
100 return -1;
101 else
102 return _data[_pos++];
103 }
104
105
106 inline int
get_base()107 Type1Reader::get_base()
108 {
109 if (_pos >= _len)
110 return more_data();
111 else
112 return _data[_pos++];
113 }
114
115
116 inline int
eexec(int c)117 Type1Reader::eexec(int c)
118 {
119 unsigned char answer = (unsigned char)(c ^ (_r >> 8));
120 _r = (((unsigned char)c + _r) * (uint32_t) t1C1 + t1C2) & 0xFFFF;
121 return answer;
122 }
123
124
125 int
ascii_eexec_get()126 Type1Reader::ascii_eexec_get()
127 {
128 int d1 = get_base();
129 while (isspace(d1))
130 d1 = get_base();
131
132 int d2 = get_base();
133 while (isspace(d2))
134 d2 = get_base();
135 if (d2 < 0)
136 return -1;
137
138 return eexec((xvalue[d1] << 4) | (xvalue[d2]));
139 }
140
141
142 inline int
get()143 Type1Reader::get()
144 {
145 if (!_eexec)
146 return get_base();
147
148 else if (_binary_eexec) {
149 int c = get_base();
150 return c < 0 ? c : eexec(c);
151
152 } else
153 return ascii_eexec_get();
154 }
155
156
157 void
start_eexec(int initial_ascii)158 Type1Reader::start_eexec(int initial_ascii)
159 {
160 /* God damn this _ungot thing!! It makes sense not to check it on every
161 char fetch, since it can only be set at the end of next_line; therefore,
162 only the first get() into a user-visible function might need to check
163 _ungot. The problem is I forgot start_eexec() was such a function! */
164 int c = _ungot < 0 ? get_base() : _ungot;
165 initial_ascii--;
166 _ungot = -1;
167
168 /* Strictly speaking, I should look for whitespace even in binary sections
169 of PFB fonts; but it turns out some PFBs would be unreadable with that
170 pedantic rule. */
171 while (isspace(c) && (initial_ascii >= 0 || !preserve_whitespace()))
172 c = get_base(), initial_ascii--;
173
174 /* Differentiate between ASCII eexec and binary eexec. */
175 int rand_bytes[4];
176 _binary_eexec = false;
177 for (int i = 0; i < 4; i++) {
178 if (i)
179 c = get_base();
180 rand_bytes[i] = c;
181 if (!isxdigit(c))
182 _binary_eexec = true;
183 }
184
185 _r = t1R_ee;
186 if (_binary_eexec)
187 for (int i = 0; i < 4; i++)
188 eexec(rand_bytes[i]);
189 else {
190 for (int i = 0; i < 2; i++) {
191 c = xvalue[rand_bytes[i*2]] * 16 + xvalue[rand_bytes[i*2+1]];
192 eexec(c);
193 }
194 ascii_eexec_get();
195 ascii_eexec_get();
196 }
197 }
198
199
200 bool
test_charstring(StringAccum & str)201 Type1Reader::test_charstring(StringAccum &str)
202 {
203 /* PERFORMANCE NOTE: This function is definitely a bottleneck. Making it
204 more efficient cut time by about 40%. */
205
206 if (!_charstring_definer)
207 return false;
208 if (_charstring_len >= 0)
209 return str.length() <= _charstring_start + _charstring_len;
210
211 str.append('\0'); // protect against running off end of string
212 char *s = str.data();
213 char *start;
214 while (*s == ' ')
215 s++;
216
217 if (s[0] == '/')
218 s++;
219 else if (s[0] == 'd' && s[1] == 'u' && s[2] == 'p' && isspace((unsigned char) s[3])) {
220 s += 4;
221 // 17.Jan.2000 -- some fonts have extra space here.
222 while (isspace((unsigned char) *s))
223 s++;
224 } else
225 goto not_charstring;
226
227 // Force one literal space rather than isspace().
228 // Why? Consistency: we force 1 literal space around _charstring_definer.
229 while (*s != ' ' && *s)
230 s++;
231 if (*s++ != ' ' || !isdigit((unsigned char) *s))
232 goto not_charstring;
233 start = s;
234 s++;
235 while (*s != ' ' && *s)
236 s++;
237 if (strncmp(s, _charstring_definer.c_str(), _charstring_definer.length()) != 0)
238 goto not_charstring;
239
240 _charstring_len = strtol(start, 0, 10);
241 _charstring_start = (s - str.data()) + _charstring_definer.length();
242 str.pop_back();
243 return str.length() <= _charstring_start + _charstring_len;
244
245 not_charstring:
246 str.pop_back();
247 return false;
248 }
249
250
251 /* PERFORMANCE NOTE: All kinds of speedup tricks tried with eexec -- buffering
252 (doing eexec processing at more_data time), etc., and all this stuff -- and
253 found to have essentially zero effect for PFB fonts. Now, it might be
254 effective for PFAs; but who cares? I hate PFAs. */
255
256 bool
next_line(StringAccum & s)257 Type1Reader::next_line(StringAccum &s)
258 {
259 if (_len < 0)
260 return false;
261
262 // Can't be a charstring if incoming accumulator has nonzero length.
263 _charstring_start = 0;
264 _charstring_len = (s.length() > 0 ? 0 : -1);
265
266 int first_char = _ungot < 0 ? get() : _ungot;
267 _ungot = -1;
268
269 for (int c = first_char; c >= 0; c = get())
270 switch (c) {
271
272 case '\n':
273 if (test_charstring(s))
274 goto normal;
275 else {
276 _crlf = 0;
277 goto done;
278 }
279
280 case '\r':
281 // check for \r\n (counts as only one line ending)
282 if (test_charstring(s))
283 goto normal;
284 c = get();
285 if (c != '\n' || preserve_whitespace())
286 _ungot = c, _crlf = 1;
287 else
288 _crlf = 2;
289 goto done;
290
291 normal:
292 default:
293 s.append((char)c);
294 break;
295
296 }
297
298 done:
299 return true;
300 }
301
302
303 int
get_data(unsigned char * data,int len)304 Type1Reader::get_data(unsigned char *data, int len)
305 {
306 if (_len < 0)
307 return -1;
308 if (len <= 0)
309 return 0;
310
311 int pos = 0;
312 if (_ungot >= 0) {
313 *data++ = _ungot;
314 pos++;
315 _ungot = -1;
316 }
317
318 for (; pos < len; pos++) {
319 int c = get();
320 if (c < 0)
321 break;
322 *data++ = c;
323 }
324
325 return pos;
326 }
327
328
329 /*****
330 * Type1PFAReader
331 **/
332
Type1PFAReader(FILE * f)333 Type1PFAReader::Type1PFAReader(FILE *f)
334 : _f(f)
335 {
336 }
337
338 int
more_data(unsigned char * data,int len)339 Type1PFAReader::more_data(unsigned char *data, int len)
340 {
341 size_t size = fread(data, 1, len, _f);
342 return size ? (int)size : -1;
343 }
344
345
346 /*****
347 * Type1PFBReader
348 **/
349
Type1PFBReader(FILE * f)350 Type1PFBReader::Type1PFBReader(FILE *f)
351 : _f(f), _binary(false), _left(0)
352 {
353 }
354
355 int
more_data(unsigned char * data,int len)356 Type1PFBReader::more_data(unsigned char *data, int len)
357 {
358 while (_left == 0) {
359 int c = getc(_f);
360 if (c != 128)
361 return -1;
362
363 c = getc(_f);
364 if (c == 3 || c < 1 || c > 3)
365 return -1;
366 _binary = (c == 2);
367
368 _left = getc(_f);
369 _left |= getc(_f) << 8;
370 _left |= getc(_f) << 16;
371 _left |= getc(_f) << 24;
372 }
373
374 if (_left < 0)
375 return -1;
376
377 if (len > _left)
378 len = _left;
379 _left -= len;
380
381 return fread(data, 1, len, _f);
382 }
383
384 bool
preserve_whitespace() const385 Type1PFBReader::preserve_whitespace() const
386 {
387 return _binary;
388 }
389
390
391 /*****
392 * Type1SubsetReader
393 **/
394
Type1SubsetReader(Type1Reader * r,int left)395 Type1SubsetReader::Type1SubsetReader(Type1Reader *r, int left)
396 : _reader(r), _left(left)
397 {
398 }
399
400 int
more_data(unsigned char * data,int len)401 Type1SubsetReader::more_data(unsigned char *data, int len)
402 {
403 if (_left <= 0)
404 return -1;
405 if (len > _left)
406 len = _left;
407 int how_much = _reader->get_data(data, len);
408 if (how_much > 0)
409 _left -= how_much;
410 return how_much;
411 }
412
413 bool
preserve_whitespace() const414 Type1SubsetReader::preserve_whitespace() const
415 {
416 return _reader->preserve_whitespace();
417 }
418
419
420 /*****
421 * Writer
422 **/
423
Type1Writer()424 Type1Writer::Type1Writer()
425 : _buf(new unsigned char[BufSize]), _pos(0),
426 _eexec(false), _eexec_start(-1), _eexec_end(-1), _lenIV(4)
427 {
428 }
429
430
~Type1Writer()431 Type1Writer::~Type1Writer()
432 {
433 assert(!_pos);
434 delete[] _buf;
435 }
436
437
438 inline unsigned char
eexec(int p)439 Type1Writer::eexec(int p)
440 {
441 unsigned char c = ((unsigned char)p ^ (_r >> 8)) & 0xFF;
442 _r = ((c + _r) * (uint32_t) t1C1 + t1C2) & 0xFFFF;
443 return c;
444 }
445
446
447 void
flush()448 Type1Writer::flush()
449 {
450 local_flush();
451 }
452
453
454 /* PERFORMANCE NOTE: Doing eexec processing during flush -- which streamlines
455 code for the print() methods -- seems to save some time (4-5%). It also
456 makes write performance more consistent. But I have mixed feelings. */
457
458 void
local_flush()459 Type1Writer::local_flush()
460 {
461 if (_eexec_start >= 0 && _eexec_end < 0)
462 _eexec_end = _pos;
463 for (int p = _eexec_start; p < _eexec_end; p++)
464 _buf[p] = eexec(_buf[p]);
465 print0(_buf, _pos);
466 _pos = 0;
467 _eexec_start = _eexec ? 0 : -1;
468 _eexec_end = -1;
469 }
470
471
472 void
print(const char * s,int n)473 Type1Writer::print(const char *s, int n)
474 {
475 while (n > 0) {
476 if (_pos >= BufSize)
477 local_flush();
478 int copy = BufSize - _pos;
479 if (copy > n) copy = n;
480 memcpy(_buf + _pos, s, copy);
481 _pos += copy;
482 s += copy;
483 n -= copy;
484 }
485 }
486
487
488 Type1Writer &
operator <<(int x)489 Type1Writer::operator<<(int x)
490 {
491 char str[128];
492 sprintf(str, "%d", x);
493 print(str, strlen(str));
494 return *this;
495 }
496
497
498 Type1Writer &
operator <<(double x)499 Type1Writer::operator<<(double x)
500 {
501 char str[256];
502 sprintf(str, "%g", x);
503 print(str, strlen(str));
504 return *this;
505 }
506
507
508 void
switch_eexec(bool on)509 Type1Writer::switch_eexec(bool on)
510 {
511 _eexec = on;
512 if (_eexec) {
513 _eexec_start = _pos;
514 _r = t1R_ee;
515 print("SUCK", 4);
516 } else
517 _eexec_end = _pos;
518 }
519
520
521 /*****
522 * Type1PFAWriter
523 **/
524
Type1PFAWriter(FILE * f)525 Type1PFAWriter::Type1PFAWriter(FILE *f)
526 : _f(f), _hex_line(0)
527 {
528 }
529
~Type1PFAWriter()530 Type1PFAWriter::~Type1PFAWriter()
531 {
532 flush();
533 }
534
535
536 void
switch_eexec(bool on)537 Type1PFAWriter::switch_eexec(bool on)
538 {
539 flush();
540 _hex_line = 0;
541 Type1Writer::switch_eexec(on);
542 }
543
544 void
print0(const unsigned char * c,int l)545 Type1PFAWriter::print0(const unsigned char *c, int l)
546 {
547 if (eexecing()) {
548 const char *hex = "0123456789ABCDEF";
549 for (; l; c++, l--) {
550 putc(hex[*c / 16], _f);
551 putc(hex[*c % 16], _f);
552 if (++_hex_line == 39) {
553 putc('\n', _f);
554 _hex_line = 0;
555 }
556 }
557 } else {
558 ssize_t result = fwrite(c, 1, l, _f);
559 (void) result;
560 }
561 }
562
563
564 /*****
565 * Type1PFBWriter
566 **/
567
Type1PFBWriter(FILE * f)568 Type1PFBWriter::Type1PFBWriter(FILE *f)
569 : _f(f), _binary(false)
570 {
571 }
572
~Type1PFBWriter()573 Type1PFBWriter::~Type1PFBWriter()
574 {
575 flush();
576 fputc(128, _f);
577 fputc(3, _f);
578 }
579
580 void
flush()581 Type1PFBWriter::flush()
582 {
583 Type1Writer::flush();
584 if (_save.length()) {
585 fputc(128, _f);
586 fputc(_binary ? 2 : 1, _f);
587 long l = _save.length();
588 fputc(l & 0xFF, _f);
589 fputc((l >> 8) & 0xFF, _f);
590 fputc((l >> 16) & 0xFF, _f);
591 fputc((l >> 24) & 0xFF, _f);
592 ssize_t result = fwrite(_save.data(), 1, _save.length(), _f);
593 (void) result;
594 _save.clear();
595 }
596 }
597
598 void
switch_eexec(bool on)599 Type1PFBWriter::switch_eexec(bool on)
600 {
601 flush();
602 Type1Writer::switch_eexec(on);
603 _binary = on;
604 }
605
606 void
print0(const unsigned char * c,int l)607 Type1PFBWriter::print0(const unsigned char *c, int l)
608 {
609 char *m = _save.extend(l);
610 memcpy(m, c, l);
611 }
612
613 }
614