1 // -*- related-file-name: "../include/efont/t1cs.hh" -*-
2 
3 /* t1cs.{cc,hh} -- Type 1/2 charstrings
4  *
5  * Copyright (c) 1998-2014 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/t1cs.hh>
20 #include <efont/t1interp.hh>
21 #include <string.h>
22 namespace Efont {
23 
24 const char * const Charstring::command_names[] = {
25     "error", "hstem", "UNKNOWN_2", "vstem", "vmoveto",
26     "rlineto", "hlineto", "vlineto", "rrcurveto", "closepath",
27 
28     "callsubr", "return", "escape", "hsbw", "endchar",
29     "UNKNOWN_15", "blend", "UNKNOWN_17", "hstemhm", "hintmask",
30 
31     "cntrmask", "rmoveto", "hmoveto", "vstemhm", "rcurveline",
32     "rlinecurve", "vvcurveto", "hhcurveto", "shortint", "callgsubr",
33 
34     "vhcurveto", "hvcurveto", "dotsection", "vstem3", "hstem3",
35     "and", "or", "not", "seac", "sbw",
36 
37     "store", "abs", "add", "sub", "div",
38     "load", "neg", "eq", "callothersubr", "pop",
39 
40     "drop", "UNKNOWN_12_19", "put", "get", "ifelse",
41     "random", "mul", "UNKNOWN_12_25", "sqrt", "dup",
42 
43     "exch", "index", "roll", "UNKNOWN_12_31", "UNKNOWN_12_32",
44     "setcurrentpoint", "hflex", "flex", "hflex1", "flex1"
45 };
46 
47 const char * const Charstring::standard_encoding[256] = {
48     /* 00x */ 0, 0, 0, 0, 0, 0, 0, 0,
49     /* 01x */ 0, 0, 0, 0, 0, 0, 0, 0,
50     /* 02x */ 0, 0, 0, 0, 0, 0, 0, 0,
51     /* 03x */ 0, 0, 0, 0, 0, 0, 0, 0,
52     /* 04x */ "space", "exclam", "quotedbl", "numbersign", "dollar", "percent",
53     "ampersand", "quoteright",
54     /* 05x */ "parenleft", "parenright", "asterisk", "plus", "comma", "hyphen",
55     "period", "slash",
56     /* 06x */ "zero", "one", "two", "three", "four", "five", "six", "seven",
57     /* 07x */ "eight", "nine", "colon", "semicolon", "less", "equal",
58     "greater", "question",
59     /* 10x */ "at", "A", "B", "C", "D", "E", "F", "G",
60     /* 11x */ "H", "I", "J", "K", "L", "M", "N", "O",
61     /* 12x */ "P", "Q", "R", "S", "T", "U", "V", "W",
62     /* 13x */ "X", "Y", "Z", "bracketleft", "backslash", "bracketright",
63     "asciicircum", "underscore",
64     /* 14x */ "quoteleft", "a", "b", "c", "d", "e", "f", "g",
65     /* 15x */ "h", "i", "j", "k", "l", "m", "n", "o",
66     /* 16x */ "p", "q", "r", "s", "t", "u", "v", "w",
67     /* 17x */ "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde", 0,
68     /* 20x */ 0, 0, 0, 0, 0, 0, 0, 0,
69     /* 21x */ 0, 0, 0, 0, 0, 0, 0, 0,
70     /* 22x */ 0, 0, 0, 0, 0, 0, 0, 0,
71     /* 23x */ 0, 0, 0, 0, 0, 0, 0, 0,
72     /* 24x */ 0, "exclamdown", "cent", "sterling", "fraction", "yen",
73     "florin", "section",
74     /* 25x */ "currency", "quotesingle", "quotedblleft", "guillemotleft",
75     "guilsinglleft", "guilsinglright", "fi", "fl",
76     /* 26x */ 0, "endash", "dagger", "daggerdbl", "periodcentered", 0,
77     "paragraph", "bullet",
78     /* 27x */ "quotesinglbase", "quotedblbase", "quotedblright",
79     "guillemotright", "ellipsis", "perthousand", 0, "questiondown",
80     /* 30x */ 0, "grave", "acute", "circumflex", "tilde", "macron",
81     "breve", "dotaccent",
82     /* 31x */ "dieresis", 0, "ring", "cedilla", 0, "hungarumlaut",
83     "ogonek", "caron",
84     /* 32x */ "emdash", 0, 0, 0, 0, 0, 0, 0,
85     /* 33x */ 0, 0, 0, 0, 0, 0, 0, 0,
86     /* 34x */ 0, "AE", 0, "ordfeminine", 0, 0, 0, 0,
87     /* 35x */ "Lslash", "Oslash", "OE", "ordmasculine", 0, 0, 0, 0,
88     /* 36x */ 0, "ae", 0, 0, 0, "dotlessi", 0, 0,
89     /* 37x */ "lslash", "oslash", "oe", "germandbls", 0, 0, 0, 0,
90 };
91 
92 
~Charstring()93 Charstring::~Charstring()
94 {
95 }
96 
97 String
command_name(int cmd)98 Charstring::command_name(int cmd)
99 {
100     if (cmd >= 0 && cmd <= cLastCommand)
101 	return command_names[cmd];
102     else if (cmd < cEscapeDelta + 256)
103 	return String("COMMAND_12_") + String(cmd - cEscapeDelta);
104     else
105 	return String("<INVALID>");
106 }
107 
108 
Type1Charstring(int lenIV,const String & s)109 Type1Charstring::Type1Charstring(int lenIV, const String &s)
110     : Charstring(), _key(-1)
111 {
112     if (lenIV < 0)		// no charstring encryption
113 	_s = s;
114     else if (lenIV < s.length()) {
115 	const unsigned char *d = reinterpret_cast<const unsigned char*>(s.data());
116 	_key = t1R_cs;
117 	for (int i = 0; i < lenIV; i++, d++)
118 	    _key = ((*d + _key) * t1C1 + t1C2) & 0xFFFF;
119 	_s = s.substring(lenIV);
120     }
121 }
122 
123 void
prepend(const Type1Charstring & t1cs)124 Type1Charstring::prepend(const Type1Charstring &t1cs)
125 {
126     if (_key >= 0)
127 	decrypt();
128     if (t1cs._key >= 0)
129 	t1cs.decrypt();
130     _s = t1cs._s + _s;
131 }
132 
133 void
decrypt() const134 Type1Charstring::decrypt() const
135 {
136     if (_key >= 0) {
137 	int r = _key;
138 	uint8_t *d = reinterpret_cast<uint8_t *>(_s.mutable_data());
139 	for (int i = 0; i < _s.length(); i++, d++) {
140 	    uint8_t encrypted = *d;
141 	    *d = encrypted ^ (r >> 8);
142 	    r = ((encrypted + r) * t1C1 + t1C2) & 0xFFFF;
143 	}
144 	_key = -1;
145     }
146 }
147 
148 bool
process(CharstringInterp & interp) const149 Type1Charstring::process(CharstringInterp &interp) const
150 {
151     const uint8_t *data = Type1Charstring::data();
152     int left = _s.length();
153 
154     while (left > 0) {
155 	bool more;
156 	int ahead;
157 
158 	if (*data >= 32 && *data <= 246) {		// push small number
159 	    more = interp.number(data[0] - 139);
160 	    ahead = 1;
161 
162 	} else if (*data < 32) {			// a command
163 	    if (*data == cEscape) {
164 		if (left < 2)
165 		    goto runoff_error;
166 		more = interp.type1_command(cEscapeDelta + data[1]);
167 		ahead = 2;
168 	    } else if (*data == cShortint) { // short integer
169 		if (left < 3)
170 		    goto runoff_error;
171 		int16_t val = (data[1] << 8) | data[2];
172 		more = interp.number(val);
173 		ahead = 3;
174 	    } else {
175 		more = interp.type1_command(data[0]);
176 		ahead = 1;
177 	    }
178 
179 	} else if (*data >= 247 && *data <= 250) {	// push medium number
180 	    if (left < 2)
181 		goto runoff_error;
182 	    int val = + ((data[0] - 247) << 8) + 108 + data[1];
183 	    more = interp.number(val);
184 	    ahead = 2;
185 
186 	} else if (*data >= 251 && *data <= 254) {	// push negative medium number
187 	    if (left < 2)
188 		goto runoff_error;
189 	    int val = - ((data[0] - 251) << 8) - 108 - data[1];
190 	    more = interp.number(val);
191 	    ahead = 2;
192 
193 	} else {					// 255: push huge number
194 	    if (left < 5)
195 		goto runoff_error;
196 	    int32_t val = (data[1] << 24) | (data[2] << 16) | (data[3] << 8) | data[4];
197 	    more = interp.number(val);
198 	    ahead = 5;
199 	}
200 
201 	if (!more)
202 	    return interp.error() == CharstringInterp::errOK;
203 
204 	data += ahead;
205 	left -= ahead;
206     }
207 
208   runoff_error:
209     interp.error(CharstringInterp::errRunoff);
210     return false;
211 }
212 
213 int
first_caret_after(int pos) const214 Type1Charstring::first_caret_after(int pos) const
215 {
216     const uint8_t *data = Type1Charstring::data();
217     const uint8_t *edata = data + (pos < length() ? pos : length());
218 
219     while (data < edata) {
220 	if (*data >= 32 && *data <= 246)	// push small number
221 	    data++;
222 	else if (*data < 32) {			// a command
223 	    if (*data == cEscape)
224 		data += 2;
225 	    else if (*data == cShortint)
226 		data += 3;
227 	    else
228 		data++;
229 	} else if (*data >= 247 && *data <= 254)	// push medium number
230 	    data += 2;
231 	else					// 255: push huge number
232 	    data += 5;
233     }
234 
235     const uint8_t *odata = Type1Charstring::data();
236     return (data > odata + length() ? length() : data - odata);
237 }
238 
239 void
assign_substring(int pos,int len,const String & cs)240 Type1Charstring::assign_substring(int pos, int len, const String &cs)
241 {
242     if (_key >= 0)
243 	decrypt();
244     if (pos < 0 || len < 0 || pos + len >= _s.length())
245 	/* do nothing */;
246     else if (cs.length() == len) {
247 	char *d = _s.mutable_data();
248 	memcpy(d + pos, cs.data(), cs.length());
249     } else if (cs.length() <= len) {
250 	char *d = _s.mutable_data();
251 	memcpy(d + pos, cs.data(), cs.length());
252 	memmove(d + pos + cs.length(), d + pos + len, _s.length() - pos - len);
253 	_s = _s.substring(0, cs.length() - len);
254     } else
255 	_s = _s.substring(0, pos) + cs + _s.substring(pos + len);
256 }
257 
258 
259 bool
process(CharstringInterp & interp) const260 Type2Charstring::process(CharstringInterp &interp) const
261 {
262     const uint8_t *data = Type2Charstring::data();
263     int left = _s.length();
264 
265     while (left > 0) {
266 	bool more;
267 	int ahead;
268 
269 	if (*data >= 32 && *data <= 246) {		// push small number
270 	    more = interp.number(data[0] - 139);
271 	    ahead = 1;
272 
273 	} else if (*data < 32) {			// a command
274 	    if (*data == cEscape) {
275 		if (left < 2)
276 		    goto runoff_error;
277 		more = interp.type2_command(cEscapeDelta + data[1], 0, 0);
278 		ahead = 2;
279 	    } else if (*data == cShortint) { // short integer
280 		if (left < 3)
281 		    goto runoff_error;
282 		int16_t val = (data[1] << 8) | data[2];
283 		more = interp.number(val);
284 		ahead = 3;
285 	    } else if (*data == cHintmask || *data == cCntrmask) {
286 		int left_ptr = left - 1;
287 		more = interp.type2_command(data[0], data + 1, &left_ptr);
288 		ahead = 1 + (left - 1) - left_ptr;
289 	    } else {
290 		more = interp.type2_command(data[0], 0, 0);
291 		ahead = 1;
292 	    }
293 
294 	} else if (*data >= 247 && *data <= 250) {	// push medium number
295 	    if (left < 2)
296 		goto runoff_error;
297 	    int val = + ((data[0] - 247) << 8) + 108 + data[1];
298 	    more = interp.number(val);
299 	    ahead = 2;
300 
301 	} else if (*data >= 251 && *data <= 254) {	// push negative medium number
302 	    if (left < 2)
303 		goto runoff_error;
304 	    int val = - ((data[0] - 251) << 8) - 108 - data[1];
305 	    more = interp.number(val);
306 	    ahead = 2;
307 
308 	} else {					// 255: push huge number
309 	    if (left < 5)
310 		goto runoff_error;
311 	    int32_t val = (data[1] << 24) | (data[2] << 16) | (data[3] << 8) | data[4];
312 	    more = interp.number(val / 65536.);
313 	    ahead = 5;
314 	}
315 
316 	if (!more)
317 	    return interp.error() == CharstringInterp::errOK;
318 
319 	data += ahead;
320 	left -= ahead;
321     }
322 
323   runoff_error:
324     interp.error(CharstringInterp::errRunoff);
325     return false;
326 }
327 
328 
CharstringProgram(unsigned units_per_em)329 CharstringProgram::CharstringProgram(unsigned units_per_em)
330     : _parent_program(false),
331       _units_per_em(units_per_em ? units_per_em : 1000) {
332 }
333 
334 const CharstringProgram *
child_program(int) const335 CharstringProgram::child_program(int) const
336 {
337     return this;
338 }
339 
340 void
font_matrix(double matrix[6]) const341 CharstringProgram::font_matrix(double matrix[6]) const
342 {
343     matrix[0] = matrix[3] = 0.001;
344     matrix[1] = matrix[2] = matrix[4] = matrix[5] = 0;
345 }
346 
347 void
glyph_names(Vector<PermString> & gnames) const348 CharstringProgram::glyph_names(Vector<PermString> &gnames) const
349 {
350     int n = nglyphs();
351     gnames.resize(n);
352     for (int i = 0; i < n; i++)
353 	gnames[i] = glyph_name(i);
354 }
355 
356 Vector<double> *
mm_vector(VectorType,bool) const357 CharstringProgram::mm_vector(VectorType, bool) const
358 {
359     return 0;
360 }
361 
362 double
global_width_x(bool) const363 CharstringProgram::global_width_x(bool) const
364 {
365     return UNKDOUBLE;
366 }
367 
368 }
369 
370