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