/src/ghostpdl/devices/vector/gdevpsf1.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2024 Artifex Software, Inc. |
2 | | All Rights Reserved. |
3 | | |
4 | | This software is provided AS-IS with no warranty, either express or |
5 | | implied. |
6 | | |
7 | | This software is distributed under license and may not be copied, |
8 | | modified or distributed except as expressly authorized under the terms |
9 | | of the license contained in the file LICENSE in this distribution. |
10 | | |
11 | | Refer to licensing information at http://www.artifex.com or contact |
12 | | Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
13 | | CA 94129, USA, for further information. |
14 | | */ |
15 | | |
16 | | |
17 | | /* Write an embedded Type 1 font */ |
18 | | #include "math.h" |
19 | | #include "memory_.h" |
20 | | #include "gx.h" |
21 | | #include "gserrors.h" |
22 | | #include "gsccode.h" |
23 | | #include "gsmatrix.h" |
24 | | #include "gxfixed.h" |
25 | | #include "gxfont.h" |
26 | | #include "gxfont1.h" |
27 | | #include "gxmatrix.h" /* for gxtype1.h */ |
28 | | #include "gxtype1.h" |
29 | | #include "strimpl.h" /* required by Watcom compiler (why?) */ |
30 | | #include "stream.h" |
31 | | #include "sfilter.h" |
32 | | #include "spsdf.h" |
33 | | #include "sstring.h" |
34 | | #include "spprint.h" |
35 | | #include "gdevpsf.h" |
36 | | |
37 | | /* ------ Utilities shared with CFF writer ------ */ |
38 | | |
39 | | /* Gather glyph information for a Type 1 or Type 2 font. */ |
40 | | int |
41 | | psf_type1_glyph_data(gs_font_base *pbfont, gs_glyph glyph, |
42 | | gs_glyph_data_t *pgd, gs_font_type1 **ppfont) |
43 | 1.27M | { |
44 | 1.27M | gs_font_type1 *const pfont = (gs_font_type1 *)pbfont; |
45 | | |
46 | 1.27M | *ppfont = pfont; |
47 | 1.27M | return pfont->data.procs.glyph_data(pfont, glyph, pgd); |
48 | 1.27M | } |
49 | | int |
50 | | psf_get_type1_glyphs(psf_outline_glyphs_t *pglyphs, gs_font_type1 *pfont, |
51 | | gs_glyph *subset_glyphs, uint subset_size) |
52 | 18.4k | { |
53 | 18.4k | return psf_get_outline_glyphs(pglyphs, (gs_font_base *)pfont, |
54 | 18.4k | subset_glyphs, subset_size, |
55 | 18.4k | psf_type1_glyph_data); |
56 | 18.4k | } |
57 | | |
58 | | /* ------ Main program ------ */ |
59 | | |
60 | | /* Write a (named) array of floats. */ |
61 | | static int |
62 | | write_float_array(gs_param_list *plist, const char *key, const float *values, |
63 | | int count) |
64 | 105k | { |
65 | 105k | if (count != 0) { |
66 | 63.8k | gs_param_float_array fa; |
67 | | |
68 | 63.8k | fa.persistent = false; |
69 | 63.8k | fa.size = count; |
70 | 63.8k | fa.data = values; |
71 | 63.8k | return param_write_float_array(plist, key, &fa); |
72 | 63.8k | } |
73 | 41.3k | return 0; |
74 | 105k | } |
75 | | |
76 | | /* Write a UniqueID and/or XUID. */ |
77 | | static void |
78 | | write_uid(stream *s, const gs_uid *puid, int options) |
79 | 26.3k | { |
80 | 26.3k | if (uid_is_UniqueID(puid)) |
81 | 0 | pprintld1(s, "/UniqueID %ld def\n", puid->id); |
82 | 26.3k | else if (uid_is_XUID(puid) && (options & WRITE_TYPE1_XUID) != 0) { |
83 | 0 | uint i, n = uid_XUID_size(puid); |
84 | | |
85 | | /* Adobe products (specifically Acrobat but the same limitation is mentioned |
86 | | * in the PLRM) cannot handle XUIDs > 16 entries. |
87 | | */ |
88 | 0 | if (n > 16) |
89 | 0 | n = 16; |
90 | |
|
91 | 0 | stream_puts(s, "/XUID ["); |
92 | 0 | for (i = 0; i < n; ++i) |
93 | 0 | pprintld1(s, "%ld ", uid_XUID_values(puid)[i]); |
94 | 0 | stream_puts(s, "] readonly def\n"); |
95 | 0 | } |
96 | 26.3k | } |
97 | | |
98 | | /* Write the font name. */ |
99 | | static void |
100 | | write_font_name(stream *s, const gs_font_type1 *pfont, |
101 | | const gs_const_string *alt_font_name, bool as_name) |
102 | 26.3k | { |
103 | 26.3k | const byte *c; |
104 | 26.3k | const byte *name = (alt_font_name ? alt_font_name->data : pfont->font_name.chars); |
105 | 26.3k | int n = (alt_font_name ? alt_font_name->size : pfont->font_name.size); |
106 | | |
107 | 26.3k | if (n == 0) |
108 | | /* empty name, may need to write it as empty string */ |
109 | 0 | stream_puts(s, (as_name ? "/" : "()")); |
110 | 26.3k | else { |
111 | 499k | for (c = (byte *)"()<>[]{}/% \n\r\t\b\f\004\033"; *c; c++) |
112 | 472k | if (memchr(name, *c, n)) |
113 | 76 | break; |
114 | 26.3k | if (*c || memchr(name, 0, n)) { |
115 | | /* name contains whitespace (NUL included) or a PostScript separator */ |
116 | 76 | byte pssebuf[1 + 4 * gs_font_name_max + 1]; /* "(" + "\ooo" * gs_font_name_max + ")" */ |
117 | 76 | stream_cursor_read r; |
118 | 76 | stream_cursor_write w; |
119 | | |
120 | 76 | pssebuf[0] = '('; |
121 | 76 | r.limit = (r.ptr = name - 1) + n; |
122 | 76 | w.limit = (w.ptr = pssebuf) + sizeof pssebuf - 1; |
123 | 76 | s_PSSE_template.process(NULL, &r, &w, true); |
124 | 76 | stream_write(s, pssebuf, w.ptr - pssebuf + 1); |
125 | 76 | if (as_name) |
126 | 38 | stream_puts(s, " cvn"); |
127 | 26.2k | } else { |
128 | | /* name without any special characters */ |
129 | 26.2k | if (as_name) |
130 | 13.1k | stream_putc(s, '/'); |
131 | 26.2k | stream_write(s, name, n); |
132 | 26.2k | } |
133 | 26.3k | } |
134 | 26.3k | } |
135 | | /* |
136 | | * Write the Encoding array. This is a separate procedure only for |
137 | | * readability. |
138 | | */ |
139 | | static int |
140 | | write_Encoding(stream *s, gs_font_type1 *pfont, int options, |
141 | | gs_glyph *subset_glyphs, uint subset_size, gs_glyph notdef) |
142 | 13.1k | { |
143 | 13.1k | stream_puts(s, "/Encoding "); |
144 | 13.1k | switch (pfont->encoding_index) { |
145 | 0 | case ENCODING_INDEX_STANDARD: |
146 | 0 | stream_puts(s, "StandardEncoding"); |
147 | 0 | break; |
148 | 0 | case ENCODING_INDEX_ISOLATIN1: |
149 | | /* ATM only recognizes StandardEncoding. */ |
150 | 0 | if (options & WRITE_TYPE1_POSTSCRIPT) { |
151 | 0 | stream_puts(s, "ISOLatin1Encoding"); |
152 | 0 | break; |
153 | 0 | } |
154 | 13.1k | default:{ |
155 | 13.1k | gs_char i; |
156 | | |
157 | 13.1k | stream_puts(s, "256 array\n"); |
158 | 13.1k | stream_puts(s, "0 1 255 {1 index exch /.notdef put} for\n"); |
159 | 3.37M | for (i = 0; i < 256; ++i) { |
160 | 3.36M | gs_glyph glyph = |
161 | 3.36M | (*pfont->procs.encode_char) |
162 | 3.36M | ((gs_font *)pfont, (gs_char)i, GLYPH_SPACE_NAME); |
163 | 3.36M | gs_const_string namestr; |
164 | | |
165 | 3.36M | if (subset_glyphs && subset_size) { |
166 | | /* |
167 | | * Only write Encoding entries for glyphs in the |
168 | | * subset. Use binary search to check each glyph, |
169 | | * since subset_glyphs are sorted. |
170 | | */ |
171 | 0 | if (!psf_sorted_glyphs_include(subset_glyphs, |
172 | 0 | subset_size, glyph)) |
173 | 0 | continue; |
174 | 0 | } |
175 | 3.36M | if (glyph != GS_NO_GLYPH && glyph != notdef && |
176 | 3.36M | pfont->procs.glyph_name((gs_font *)pfont, glyph, |
177 | 240k | &namestr) >= 0 |
178 | 3.36M | ) { |
179 | 240k | pprintd1(s, "dup %d /", (int)i); |
180 | 240k | stream_write(s, namestr.data, namestr.size); |
181 | 240k | stream_puts(s, " put\n"); |
182 | 240k | } |
183 | 3.36M | } |
184 | 13.1k | stream_puts(s, "readonly"); |
185 | 13.1k | } |
186 | 13.1k | } |
187 | 13.1k | stream_puts(s, " def\n"); |
188 | 13.1k | return 0; |
189 | 13.1k | } |
190 | | |
191 | | static int WriteNumber (byte *dest, int value) |
192 | 0 | { |
193 | 0 | if (value >= -107 && value <= 107) { |
194 | 0 | *dest = value + 139; |
195 | 0 | return 1; |
196 | 0 | } else { |
197 | 0 | if (value >= 108 && value <= 1131) { |
198 | 0 | int quotient = (int)floor((value - 108) / (double)256); |
199 | 0 | dest[0] = quotient + 247; |
200 | 0 | dest[1] = value - 108 - quotient * 256; |
201 | 0 | return 2; |
202 | 0 | } else { |
203 | 0 | if (value <= -108 && value >= -1131) { |
204 | 0 | int quotient = (int)floor((value + 108) / -256); |
205 | 0 | int newval = value + 256 * quotient + 108; |
206 | 0 | dest[0] = quotient + 251; |
207 | 0 | dest[1] = newval * -1; |
208 | 0 | return 2; |
209 | 0 | } else { |
210 | 0 | dest[0] = 255; |
211 | 0 | dest[1] = value >> 24; |
212 | 0 | dest[2] = (value & 0xFF0000) >> 16; |
213 | 0 | dest[3] = (value & 0xFF00) >> 8; |
214 | 0 | dest[4] = value & 0xFF; |
215 | 0 | return 5; |
216 | 0 | } |
217 | 0 | } |
218 | 0 | } |
219 | 0 | return 0; |
220 | 0 | } |
221 | | |
222 | | /* The following 2 routines attempt to parse out Multiple Master 'OtherSubrs' |
223 | | * calls, and replace the multiple arguments to $Blend with the two 'base' |
224 | | * parameters. This works reasonably well but can be defeated. FOr example a |
225 | | * CharString which puts some parameters on the operand stack, then calls a |
226 | | * Subr which puts the remaining parameters on the stack, and calls a MM |
227 | | * OtherSubr (constructions like this have been observed). In general we |
228 | | * work around this by storing the operands on the stack, but it is possible |
229 | | * that the values are calculated (eg x y div) which is a common way to get |
230 | | * float values into the interpreter. This will defeat the code below. |
231 | | * |
232 | | * The only way to solve this is to actually fully interpret the CharString |
233 | | * and any /Subrs it calls, and then emit the result as a non-MM CharString |
234 | | * by blending the values. This would mean writing a new routine like |
235 | | * 'psf_convert_type1_to_type2' (see gdevpsfx.c) or modifying that routine |
236 | | * so that it outputs type 1 CharStrings (which is probably simpler to do). |
237 | | */ |
238 | | static int CheckSubrForMM (gs_glyph_data_t *gdata, gs_font_type1 *pfont) |
239 | 0 | { |
240 | 0 | crypt_state state = crypt_charstring_seed; |
241 | 0 | int code = 0; |
242 | 0 | gs_bytestring *data = (gs_bytestring *)&gdata->bits; |
243 | 0 | byte *source = data->data, *end = source + data->size; |
244 | 0 | int CurrentNumberIndex = 0, Stack[32]; |
245 | |
|
246 | 0 | memset(Stack, 0x00, sizeof(Stack)); |
247 | 0 | gs_type1_decrypt(source, source, data->size, &state); |
248 | |
|
249 | 0 | if (pfont->data.lenIV >= data->size) { |
250 | 0 | code = gs_note_error(gs_error_invalidfont); |
251 | 0 | goto error; |
252 | 0 | } |
253 | | |
254 | 0 | if(pfont->data.lenIV > 0) |
255 | 0 | source += pfont->data.lenIV; |
256 | |
|
257 | 0 | while (source < end) { |
258 | 0 | if (*source < 32) { |
259 | | /* Command */ |
260 | 0 | switch (*source) { |
261 | 0 | case 12: |
262 | 0 | if (source + 2 > end) { |
263 | 0 | code = gs_note_error(gs_error_invalidfont); |
264 | 0 | goto error; |
265 | 0 | } |
266 | 0 | if (*(source + 1) == 16) { |
267 | 0 | if (CurrentNumberIndex < 1) { |
268 | 0 | code = gs_note_error(gs_error_rangecheck); |
269 | 0 | goto error; |
270 | 0 | } |
271 | 0 | switch(Stack[CurrentNumberIndex-1]) { |
272 | 0 | case 18: |
273 | 0 | code = 6; |
274 | 0 | break; |
275 | 0 | case 17: |
276 | 0 | code = 4; |
277 | 0 | break; |
278 | 0 | case 16: |
279 | 0 | code = 3; |
280 | 0 | break; |
281 | 0 | case 15: |
282 | 0 | code = 2; |
283 | 0 | break; |
284 | 0 | case 14: |
285 | 0 | code = 1; |
286 | 0 | break; |
287 | 0 | default: |
288 | 0 | code = 0; |
289 | 0 | break; |
290 | 0 | } |
291 | 0 | source += 2; |
292 | 0 | } else { |
293 | 0 | source +=2; |
294 | 0 | } |
295 | 0 | break; |
296 | 0 | default: |
297 | 0 | source++; |
298 | 0 | break; |
299 | 0 | } |
300 | 0 | CurrentNumberIndex = 0; |
301 | 0 | } else { |
302 | | /* Number */ |
303 | 0 | if (CurrentNumberIndex >= count_of(Stack)) { |
304 | 0 | code = gs_note_error(gs_error_rangecheck); |
305 | 0 | goto error; |
306 | 0 | } |
307 | 0 | if (*source < 247) { |
308 | 0 | Stack[CurrentNumberIndex++] = *source++ - 139; |
309 | 0 | } else { |
310 | 0 | if (*source < 251) { |
311 | 0 | if (source + 2 > end) { |
312 | 0 | code = gs_note_error(gs_error_invalidfont); |
313 | 0 | goto error; |
314 | 0 | } |
315 | 0 | Stack[CurrentNumberIndex] = ((*source++ - 247) * 256) + 108; |
316 | 0 | Stack[CurrentNumberIndex++] += *source++; |
317 | 0 | } else { |
318 | 0 | if (*source < 255) { |
319 | 0 | if (source + 2 > end) { |
320 | 0 | code = gs_note_error(gs_error_invalidfont); |
321 | 0 | goto error; |
322 | 0 | } |
323 | 0 | Stack[CurrentNumberIndex] = ((*source++ - 251) * -256) - 108; |
324 | 0 | Stack[CurrentNumberIndex++] -= *source++; |
325 | 0 | } else { |
326 | 0 | if (source + 5 > end) { |
327 | 0 | code = gs_note_error(gs_error_invalidfont); |
328 | 0 | goto error; |
329 | 0 | } |
330 | 0 | source++; |
331 | 0 | Stack[CurrentNumberIndex] = *source++ << 24; |
332 | 0 | Stack[CurrentNumberIndex] += *source++ << 16; |
333 | 0 | Stack[CurrentNumberIndex] += *source++ << 8; |
334 | 0 | Stack[CurrentNumberIndex++] += *source++; |
335 | 0 | } |
336 | 0 | } |
337 | 0 | } |
338 | 0 | } |
339 | 0 | } |
340 | | /* We decrypted the data in place at the start of the routine, we must re-encrypt it |
341 | | * before we return, even if there's an error. |
342 | | */ |
343 | 0 | error: |
344 | 0 | state = crypt_charstring_seed; |
345 | 0 | source = data->data; |
346 | 0 | gs_type1_encrypt(source, source, data->size, &state); |
347 | 0 | return code; |
348 | 0 | } |
349 | | #undef MM_STACK_SIZE |
350 | | |
351 | | static int strip_othersubrs(gs_glyph_data_t *gdata, gs_font_type1 *pfont, byte *stripped, byte *SubrsWithMM, int SubrsCount) |
352 | 0 | { |
353 | 0 | crypt_state state = crypt_charstring_seed; |
354 | 0 | gs_bytestring *data = (gs_bytestring *)&gdata->bits; |
355 | 0 | byte *source = data->data, *dest = stripped, *end = source + data->size; |
356 | 0 | int i, dest_length = 0, CurrentNumberIndex = 0, Stack[64], written; |
357 | 0 | int OnlyCalcLength = 0; |
358 | 0 | char Buffer[16]; |
359 | |
|
360 | 0 | memset(Stack, 0x00, 64 * sizeof(int)); |
361 | 0 | if (stripped == NULL) { |
362 | 0 | OnlyCalcLength = 1; |
363 | 0 | dest = (byte *)&Buffer; |
364 | 0 | } |
365 | |
|
366 | 0 | if (pfont->data.lenIV >= data->size) |
367 | 0 | return gs_note_error(gs_error_invalidfont); |
368 | | |
369 | 0 | gs_type1_decrypt(source, source, data->size, &state); |
370 | |
|
371 | 0 | if(pfont->data.lenIV >= 0) { |
372 | 0 | for (i=0;i<pfont->data.lenIV;i++) { |
373 | 0 | if (!OnlyCalcLength) |
374 | 0 | *dest++ = *source++; |
375 | 0 | else |
376 | 0 | source++; |
377 | 0 | } |
378 | 0 | dest_length += pfont->data.lenIV; |
379 | 0 | } |
380 | 0 | while (source < end) { |
381 | 0 | if (*source < 32) { |
382 | | /* Command */ |
383 | 0 | switch (*source) { |
384 | 0 | case 12: |
385 | 0 | if (source + 2 > end) { |
386 | 0 | dest_length = gs_note_error(gs_error_invalidfont); |
387 | 0 | goto error; |
388 | 0 | } |
389 | 0 | if (*(source + 1) == 16) { |
390 | 0 | if (CurrentNumberIndex < 1) { |
391 | 0 | dest_length = gs_note_error(gs_error_rangecheck); |
392 | 0 | goto error; |
393 | 0 | } |
394 | | /* Callothersubsr, the only thing we care about */ |
395 | 0 | switch(Stack[CurrentNumberIndex-1]) { |
396 | | /* If we find a Multiple Master call, remove all but the |
397 | | * first set of arguments. Mimics the result of a call. |
398 | | * Adobe 'encourages' the use of Subrs to do MM, but |
399 | | * the spec doens't say you have to, so we need to be |
400 | | * prepared, just in case. I doubt we will ever execute |
401 | | * this code. |
402 | | */ |
403 | 0 | case 14: |
404 | 0 | CurrentNumberIndex -= pfont->data.WeightVector.count - 1; |
405 | 0 | for (i = 0;i < CurrentNumberIndex;i++) { |
406 | 0 | written = WriteNumber(dest, Stack[i]); |
407 | 0 | dest_length += written; |
408 | 0 | if (!OnlyCalcLength) |
409 | 0 | dest += written; |
410 | 0 | } |
411 | 0 | source += 2; |
412 | 0 | break; |
413 | 0 | case 15: |
414 | 0 | CurrentNumberIndex -= (pfont->data.WeightVector.count - 1) * 2; |
415 | 0 | for (i = 0;i < CurrentNumberIndex;i++) { |
416 | 0 | written = WriteNumber(dest, Stack[i]); |
417 | 0 | dest_length += written; |
418 | 0 | if (!OnlyCalcLength) |
419 | 0 | dest += written; |
420 | 0 | } |
421 | 0 | source += 2; |
422 | 0 | break; |
423 | 0 | case 16: |
424 | 0 | CurrentNumberIndex -= (pfont->data.WeightVector.count - 1) * 3; |
425 | 0 | for (i = 0;i < CurrentNumberIndex;i++) { |
426 | 0 | written = WriteNumber(dest, Stack[i]); |
427 | 0 | dest_length += written; |
428 | 0 | if (!OnlyCalcLength) |
429 | 0 | dest += written; |
430 | 0 | } |
431 | 0 | source += 2; |
432 | 0 | break; |
433 | 0 | case 17: |
434 | 0 | CurrentNumberIndex -= (pfont->data.WeightVector.count - 1) * 4; |
435 | 0 | for (i = 0;i < CurrentNumberIndex;i++) { |
436 | 0 | written = WriteNumber(dest, Stack[i]); |
437 | 0 | dest_length += written; |
438 | 0 | if (!OnlyCalcLength) |
439 | 0 | dest += written; |
440 | 0 | } |
441 | 0 | source += 2; |
442 | 0 | break; |
443 | 0 | case 18: |
444 | 0 | CurrentNumberIndex -= (pfont->data.WeightVector.count - 1) * 6; |
445 | 0 | for (i = 0;i < CurrentNumberIndex;i++) { |
446 | 0 | written = WriteNumber(dest, Stack[i]); |
447 | 0 | dest_length += written; |
448 | 0 | if (!OnlyCalcLength) |
449 | 0 | dest += written; |
450 | 0 | } |
451 | 0 | source += 2; |
452 | 0 | break; |
453 | 0 | default: |
454 | 0 | for (i = 0;i < CurrentNumberIndex;i++) { |
455 | 0 | written = WriteNumber(dest, Stack[i]); |
456 | 0 | dest_length += written; |
457 | 0 | if (!OnlyCalcLength) |
458 | 0 | dest += written; |
459 | 0 | } |
460 | 0 | if (!OnlyCalcLength) { |
461 | 0 | *dest++ = *source++; |
462 | 0 | *dest++ = *source++; |
463 | 0 | } else { |
464 | 0 | source += 2; |
465 | 0 | } |
466 | 0 | dest_length += 2; |
467 | 0 | break; |
468 | 0 | } |
469 | 0 | } else { |
470 | 0 | for (i = 0;i < CurrentNumberIndex;i++) { |
471 | 0 | written = WriteNumber(dest, Stack[i]); |
472 | 0 | dest_length += written; |
473 | 0 | if (!OnlyCalcLength) |
474 | 0 | dest += written; |
475 | 0 | } |
476 | 0 | if (!OnlyCalcLength) { |
477 | 0 | *dest++ = *source++; |
478 | 0 | *dest++ = *source++; |
479 | 0 | } else { |
480 | 0 | source += 2; |
481 | 0 | } |
482 | 0 | dest_length += 2; |
483 | 0 | } |
484 | 0 | break; |
485 | 0 | case 10: |
486 | 0 | if (CurrentNumberIndex != 0 && Stack[CurrentNumberIndex - 1] >= 0 && |
487 | 0 | Stack[CurrentNumberIndex - 1] < SubrsCount && SubrsWithMM != NULL && SubrsWithMM[Stack[CurrentNumberIndex - 1]] != 0) |
488 | 0 | { |
489 | 0 | int index = Stack[CurrentNumberIndex - 1]; |
490 | 0 | int StackBase = CurrentNumberIndex - 1 - pfont->data.WeightVector.count * SubrsWithMM[index]; |
491 | |
|
492 | 0 | CurrentNumberIndex--; /* Remove the subr index */ |
493 | |
|
494 | 0 | if (StackBase > CurrentNumberIndex) { |
495 | 0 | dest_length = gs_note_error(gs_error_invalidfont); |
496 | 0 | goto error; |
497 | 0 | } |
498 | | |
499 | 0 | for (i=0;i < StackBase; i++) { |
500 | 0 | written = WriteNumber(dest, Stack[i]); |
501 | 0 | dest_length += written; |
502 | 0 | if (!OnlyCalcLength) |
503 | 0 | dest += written; |
504 | 0 | } |
505 | 0 | for (i=0;i<SubrsWithMM[index];i++) { |
506 | | /* See above, it may be that we don't have enough numbers on the stack |
507 | | * (due to constructs such as x y div), if we don't have enough parameters |
508 | | * just write a 0 instead. We know this is incorrect..... |
509 | | */ |
510 | 0 | if (StackBase + i >= 0 && StackBase + i < CurrentNumberIndex) |
511 | 0 | written = WriteNumber(dest, Stack[StackBase + i]); |
512 | 0 | else |
513 | 0 | written = WriteNumber(dest, 0); |
514 | 0 | dest_length += written; |
515 | 0 | if (!OnlyCalcLength) |
516 | 0 | dest += written; |
517 | 0 | } |
518 | 0 | source++; |
519 | 0 | } else { |
520 | 0 | for (i = 0;i < CurrentNumberIndex;i++) { |
521 | 0 | written = WriteNumber(dest, Stack[i]); |
522 | 0 | dest_length += written; |
523 | 0 | if (!OnlyCalcLength) |
524 | 0 | dest += written; |
525 | 0 | } |
526 | 0 | if (!OnlyCalcLength) |
527 | 0 | *dest++ = *source++; |
528 | 0 | else |
529 | 0 | source++; |
530 | 0 | dest_length++; |
531 | 0 | } |
532 | 0 | break; |
533 | 0 | default: |
534 | 0 | for (i = 0;i < CurrentNumberIndex;i++) { |
535 | 0 | written = WriteNumber(dest, Stack[i]); |
536 | 0 | dest_length += written; |
537 | 0 | if (!OnlyCalcLength) |
538 | 0 | dest += written; |
539 | 0 | } |
540 | 0 | if (!OnlyCalcLength) |
541 | 0 | *dest++ = *source++; |
542 | 0 | else |
543 | 0 | source++; |
544 | 0 | dest_length++; |
545 | 0 | } |
546 | 0 | CurrentNumberIndex = 0; |
547 | 0 | } else { |
548 | 0 | if (CurrentNumberIndex >= count_of(Stack)) { |
549 | 0 | dest_length = gs_note_error(gs_error_rangecheck); |
550 | 0 | goto error; |
551 | 0 | } |
552 | | /* Number */ |
553 | 0 | if (*source < 247) { |
554 | 0 | Stack[CurrentNumberIndex++] = *source++ - 139; |
555 | 0 | } else { |
556 | 0 | if (*source < 251) { |
557 | 0 | if (source + 2 > end) { |
558 | 0 | dest_length = gs_note_error(gs_error_invalidfont); |
559 | 0 | goto error; |
560 | 0 | } |
561 | 0 | Stack[CurrentNumberIndex] = ((*source++ - 247) * 256) + 108; |
562 | 0 | Stack[CurrentNumberIndex++] += *source++; |
563 | 0 | } else { |
564 | 0 | if (*source < 255) { |
565 | 0 | if (source + 2 > end) { |
566 | 0 | dest_length = gs_note_error(gs_error_invalidfont); |
567 | 0 | goto error; |
568 | 0 | } |
569 | 0 | Stack[CurrentNumberIndex] = ((*source++ - 251) * -256) - 108; |
570 | 0 | Stack[CurrentNumberIndex++] -= *source++; |
571 | 0 | } else { |
572 | 0 | if (source + 5 > end) { |
573 | 0 | dest_length = gs_note_error(gs_error_invalidfont); |
574 | 0 | goto error; |
575 | 0 | } |
576 | 0 | source++; |
577 | 0 | Stack[CurrentNumberIndex] = *source++ << 24; |
578 | 0 | Stack[CurrentNumberIndex] += *source++ << 16; |
579 | 0 | Stack[CurrentNumberIndex] += *source++ << 8; |
580 | 0 | Stack[CurrentNumberIndex++] += *source++; |
581 | 0 | } |
582 | 0 | } |
583 | 0 | } |
584 | 0 | } |
585 | 0 | } |
586 | | /* We decrypted the data in place at the start of the routine, we must re-encrypt it |
587 | | * before we return, even if there's an error. |
588 | | */ |
589 | 0 | error: |
590 | 0 | source = data->data; |
591 | 0 | state = crypt_charstring_seed; |
592 | 0 | gs_type1_encrypt(source, source, data->size, &state); |
593 | |
|
594 | 0 | if (!OnlyCalcLength && dest_length > 0) { |
595 | 0 | state = crypt_charstring_seed; |
596 | 0 | gs_type1_encrypt(stripped, stripped, dest_length, &state); |
597 | 0 | } |
598 | 0 | return dest_length; |
599 | 0 | } |
600 | | |
601 | | /* |
602 | | * Write the Private dictionary. This is a separate procedure only for |
603 | | * readability. write_CharString is a parameter so that we can encrypt |
604 | | * Subrs and CharStrings when the font's lenIV == -1 but we are writing |
605 | | * the font with lenIV = 0. |
606 | | */ |
607 | | static int |
608 | | write_Private(stream *s, gs_font_type1 *pfont, |
609 | | gs_glyph *subset_glyphs, uint subset_size, |
610 | | gs_glyph notdef, int lenIV, |
611 | | int (*write_CharString)(stream *, const void *, uint), |
612 | | const param_printer_params_t *ppp, int options) |
613 | 13.1k | { |
614 | 13.1k | const gs_type1_data *const pdata = &pfont->data; |
615 | 13.1k | printer_param_list_t rlist; |
616 | 13.1k | gs_param_list *const plist = (gs_param_list *)&rlist; |
617 | 13.1k | int code = s_init_param_printer(&rlist, ppp, s); |
618 | 13.1k | byte *SubrsWithMM = 0; |
619 | 13.1k | int SubrsCount = 0; |
620 | | |
621 | 13.1k | if (code < 0) |
622 | 0 | return 0; |
623 | 13.1k | stream_puts(s, "dup /Private 17 dict dup begin\n"); |
624 | 13.1k | stream_puts(s, "/-|{string currentfile exch readstring pop}executeonly def\n"); |
625 | 13.1k | stream_puts(s, "/|-{noaccess def}executeonly def\n"); |
626 | 13.1k | stream_puts(s, "/|{noaccess put}executeonly def\n"); |
627 | 13.1k | { |
628 | 13.1k | static const gs_param_item_t private_items[] = { |
629 | 13.1k | {"BlueFuzz", gs_param_type_int, |
630 | 13.1k | offset_of(gs_type1_data, BlueFuzz)}, |
631 | 13.1k | {"BlueScale", gs_param_type_float, |
632 | 13.1k | offset_of(gs_type1_data, BlueScale)}, |
633 | 13.1k | {"BlueShift", gs_param_type_float, |
634 | 13.1k | offset_of(gs_type1_data, BlueShift)}, |
635 | 13.1k | {"ExpansionFactor", gs_param_type_float, |
636 | 13.1k | offset_of(gs_type1_data, ExpansionFactor)}, |
637 | 13.1k | {"ForceBold", gs_param_type_bool, |
638 | 13.1k | offset_of(gs_type1_data, ForceBold)}, |
639 | 13.1k | {"LanguageGroup", gs_param_type_int, |
640 | 13.1k | offset_of(gs_type1_data, LanguageGroup)}, |
641 | 13.1k | {"RndStemUp", gs_param_type_bool, |
642 | 13.1k | offset_of(gs_type1_data, RndStemUp)}, |
643 | 13.1k | gs_param_item_end |
644 | 13.1k | }; |
645 | 13.1k | gs_type1_data defaults; |
646 | | |
647 | 13.1k | defaults.BlueFuzz = 1; |
648 | 13.1k | defaults.BlueScale = (float)0.039625; |
649 | 13.1k | defaults.BlueShift = 7.0; |
650 | 13.1k | defaults.ExpansionFactor = (float)0.06; |
651 | 13.1k | defaults.ForceBold = false; |
652 | 13.1k | defaults.LanguageGroup = 0; |
653 | 13.1k | defaults.RndStemUp = true; |
654 | 13.1k | code = gs_param_write_items(plist, pdata, &defaults, private_items); |
655 | 13.1k | if (code < 0) |
656 | 0 | return code; |
657 | 13.1k | if (lenIV != 4) { |
658 | 24 | code = param_write_int(plist, "lenIV", &lenIV); |
659 | 24 | if (code < 0) |
660 | 0 | return code; |
661 | 24 | } |
662 | 13.1k | write_float_array(plist, "BlueValues", pdata->BlueValues.values, |
663 | 13.1k | pdata->BlueValues.count); |
664 | 13.1k | write_float_array(plist, "OtherBlues", pdata->OtherBlues.values, |
665 | 13.1k | pdata->OtherBlues.count); |
666 | 13.1k | write_float_array(plist, "FamilyBlues", pdata->FamilyBlues.values, |
667 | 13.1k | pdata->FamilyBlues.count); |
668 | 13.1k | write_float_array(plist, "FamilyOtherBlues", pdata->FamilyOtherBlues.values, |
669 | 13.1k | pdata->FamilyOtherBlues.count); |
670 | 13.1k | write_float_array(plist, "StdHW", pdata->StdHW.values, |
671 | 13.1k | pdata->StdHW.count); |
672 | 13.1k | write_float_array(plist, "StdVW", pdata->StdVW.values, |
673 | 13.1k | pdata->StdVW.count); |
674 | 13.1k | write_float_array(plist, "StemSnapH", pdata->StemSnapH.values, |
675 | 13.1k | pdata->StemSnapH.count); |
676 | 13.1k | write_float_array(plist, "StemSnapV", pdata->StemSnapV.values, |
677 | 13.1k | pdata->StemSnapV.count); |
678 | 13.1k | } |
679 | 0 | write_uid(s, &pfont->UID, options); |
680 | 13.1k | stream_puts(s, "/MinFeature{16 16} def\n"); |
681 | 13.1k | stream_puts(s, "/password 5839 def\n"); |
682 | | |
683 | | /* |
684 | | * Write the Subrs. We always write them all, even for subsets. |
685 | | * (We will fix this someday.) |
686 | | */ |
687 | | |
688 | 13.1k | { |
689 | 13.1k | int n, i; |
690 | 13.1k | gs_glyph_data_t gdata; |
691 | 13.1k | int code; |
692 | | |
693 | 13.1k | gdata.memory = pfont->memory; |
694 | 13.1k | for (n = 0; |
695 | 206k | (code = pdata->procs.subr_data(pfont, n, false, &gdata)) != |
696 | 206k | gs_error_rangecheck; |
697 | 193k | ) { |
698 | 193k | ++n; |
699 | 193k | if (code >= 0) |
700 | 193k | gs_glyph_data_free(&gdata, "write_Private(Subrs)"); |
701 | 193k | } |
702 | 13.1k | if (pfont->data.WeightVector.count != 0) { |
703 | 0 | SubrsCount = n; |
704 | 0 | SubrsWithMM = gs_alloc_bytes(pfont->memory, n, "Subrs record"); |
705 | 0 | } |
706 | | |
707 | 13.1k | pprintd1(s, "/Subrs %d array\n", n); |
708 | | |
709 | | /* prescan the /Subrs array to see if any of the Subrs call out to OtherSubrs */ |
710 | 13.1k | if (pfont->data.WeightVector.count != 0) { |
711 | 0 | for (i = 0; i < n; ++i) { |
712 | 0 | if ((code = pdata->procs.subr_data(pfont, i, false, &gdata)) >= 0) { |
713 | 0 | code = CheckSubrForMM(&gdata, pfont); |
714 | 0 | gs_glyph_data_free(&gdata, "write_Private(Subrs)"); |
715 | 0 | if (code < 0) { |
716 | 0 | if (SubrsWithMM != 0) |
717 | 0 | gs_free_object(pfont->memory, SubrsWithMM, "free Subrs record"); |
718 | 0 | return code; |
719 | 0 | } |
720 | 0 | if (SubrsWithMM != 0) |
721 | 0 | SubrsWithMM[i] = code; |
722 | 0 | } |
723 | 0 | } |
724 | 0 | } |
725 | | |
726 | 206k | for (i = 0; i < n; ++i) |
727 | 193k | if ((code = pdata->procs.subr_data(pfont, i, false, &gdata)) >= 0) { |
728 | 193k | char buf[50]; |
729 | | |
730 | 193k | if (gdata.bits.size) { |
731 | 193k | if (pfont->data.WeightVector.count != 0) { |
732 | 0 | byte *stripped = NULL; |
733 | 0 | int length = 0; |
734 | |
|
735 | 0 | length = strip_othersubrs(&gdata, pfont, NULL, SubrsWithMM, SubrsCount); |
736 | 0 | if (length < 0) { |
737 | 0 | gs_glyph_data_free(&gdata, "write_Private(CharStrings)"); |
738 | 0 | if (SubrsWithMM != 0) |
739 | 0 | gs_free_object(pfont->memory, SubrsWithMM, "free Subrs record"); |
740 | 0 | return length; |
741 | 0 | } |
742 | 0 | if (length > 0) { |
743 | 0 | stripped = gs_alloc_bytes(pfont->memory, length, "Subrs copy for OtherSubrs"); |
744 | 0 | if (stripped == NULL) { |
745 | 0 | if (SubrsWithMM != 0) |
746 | 0 | gs_free_object(pfont->memory, SubrsWithMM, "free Subrs record"); |
747 | 0 | gs_glyph_data_free(&gdata, "write_Private(Subrs)"); |
748 | 0 | return gs_note_error(gs_error_VMerror); |
749 | 0 | } |
750 | 0 | length = strip_othersubrs(&gdata, pfont, stripped, SubrsWithMM, SubrsCount); |
751 | 0 | if (length < 0) { |
752 | 0 | gs_glyph_data_free(&gdata, "write_Private(CharStrings)"); |
753 | 0 | gs_free_object(pfont->memory, stripped, "free CharStrings copy for OtherSubrs"); |
754 | 0 | if (SubrsWithMM != 0) |
755 | 0 | gs_free_object(pfont->memory, SubrsWithMM, "free Subrs record"); |
756 | 0 | return length; |
757 | 0 | } |
758 | 0 | gs_snprintf(buf, sizeof(buf), "dup %d %u -| ", i, length); |
759 | 0 | stream_puts(s, buf); |
760 | 0 | write_CharString(s, stripped, length); |
761 | 0 | gs_free_object(pfont->memory, stripped, "free Subrs copy for OtherSubrs"); |
762 | 0 | } else { |
763 | 0 | gs_snprintf(buf, sizeof(buf), "dup %d 0 -| ", i); |
764 | 0 | stream_puts(s, buf); |
765 | 0 | } |
766 | 193k | } else { |
767 | 193k | gs_snprintf(buf, sizeof(buf), "dup %d %u -| ", i, gdata.bits.size); |
768 | 193k | stream_puts(s, buf); |
769 | 193k | write_CharString(s, gdata.bits.data, gdata.bits.size); |
770 | 193k | } |
771 | 193k | stream_puts(s, " |\n"); |
772 | 193k | } |
773 | 193k | gs_glyph_data_free(&gdata, "write_Private(Subrs)"); |
774 | 193k | } |
775 | 13.1k | stream_puts(s, "|-\n"); |
776 | 13.1k | } |
777 | | |
778 | | /* We don't write OtherSubrs -- there had better not be any! */ |
779 | | |
780 | | /* Write the CharStrings. */ |
781 | | |
782 | 0 | { |
783 | 13.1k | int num_chars = 0; |
784 | 13.1k | gs_glyph glyph; |
785 | 13.1k | psf_glyph_enum_t genum; |
786 | 13.1k | gs_glyph_data_t gdata; |
787 | 13.1k | int code; |
788 | | |
789 | 13.1k | gdata.memory = pfont->memory; |
790 | 13.1k | psf_enumerate_glyphs_begin(&genum, (gs_font *)pfont, subset_glyphs, |
791 | 13.1k | (subset_glyphs ? subset_size : 0), |
792 | 13.1k | GLYPH_SPACE_NAME); |
793 | 13.1k | for (glyph = GS_NO_GLYPH; |
794 | 266k | (code = psf_enumerate_glyphs_next(&genum, &glyph)) != 1; |
795 | 13.1k | ) |
796 | 253k | if (code == 0 && |
797 | 253k | (code = pdata->procs.glyph_data(pfont, glyph, &gdata)) >= 0 |
798 | 253k | ) { |
799 | 253k | ++num_chars; |
800 | 253k | gs_glyph_data_free(&gdata, "write_Private(CharStrings)"); |
801 | 253k | } |
802 | 13.1k | pprintd1(s, "2 index /CharStrings %d dict dup begin\n", num_chars); |
803 | 13.1k | psf_enumerate_glyphs_reset(&genum); |
804 | 13.1k | for (glyph = GS_NO_GLYPH; |
805 | 266k | (code = psf_enumerate_glyphs_next(&genum, &glyph)) != 1; |
806 | 13.1k | ) |
807 | 253k | if (code == 0 && |
808 | 253k | (code = pdata->procs.glyph_data(pfont, glyph, &gdata)) >= 0 |
809 | 253k | ) { |
810 | 253k | gs_const_string gstr; |
811 | 253k | int code; |
812 | | |
813 | 253k | code = pfont->procs.glyph_name((gs_font *)pfont, glyph, &gstr); |
814 | 253k | if (code < 0) { |
815 | 0 | if (SubrsWithMM != 0) |
816 | 0 | gs_free_object(pfont->memory, SubrsWithMM, "free Subrs record"); |
817 | 0 | gs_glyph_data_free(&gdata, "write_Private(Subrs)"); |
818 | 0 | return code; |
819 | 0 | } |
820 | | |
821 | 253k | stream_puts(s, "/"); |
822 | 253k | stream_write(s, gstr.data, gstr.size); |
823 | | |
824 | 253k | if (pfont->data.WeightVector.count != 0) { |
825 | 0 | byte *stripped = NULL; |
826 | 0 | int length = 0; |
827 | |
|
828 | 0 | length = strip_othersubrs(&gdata, pfont, NULL, SubrsWithMM, SubrsCount); |
829 | 0 | if (length < 0) { |
830 | 0 | gs_glyph_data_free(&gdata, "write_Private(CharStrings)"); |
831 | 0 | if (SubrsWithMM != 0) |
832 | 0 | gs_free_object(pfont->memory, SubrsWithMM, "free Subrs record"); |
833 | 0 | return length; |
834 | 0 | } |
835 | 0 | if (length > 0) { |
836 | 0 | stripped = gs_alloc_bytes(pfont->memory, length, "Subrs copy for OtherSubrs"); |
837 | 0 | if (stripped == NULL) { |
838 | 0 | if (SubrsWithMM != 0) |
839 | 0 | gs_free_object(pfont->memory, SubrsWithMM, "free Subrs record"); |
840 | 0 | gs_glyph_data_free(&gdata, "write_Private(Subrs)"); |
841 | 0 | return gs_note_error(gs_error_VMerror); |
842 | 0 | } |
843 | 0 | length = strip_othersubrs(&gdata, pfont, stripped, SubrsWithMM, SubrsCount); |
844 | 0 | if (length < 0) { |
845 | 0 | gs_glyph_data_free(&gdata, "write_Private(CharStrings)"); |
846 | 0 | gs_free_object(pfont->memory, stripped, "free CharStrings copy for OtherSubrs"); |
847 | 0 | if (SubrsWithMM != 0) |
848 | 0 | gs_free_object(pfont->memory, SubrsWithMM, "free Subrs record"); |
849 | 0 | return length; |
850 | 0 | } |
851 | 0 | pprintd1(s, " %d -| ", length); |
852 | 0 | write_CharString(s, stripped, length); |
853 | 0 | gs_free_object(pfont->memory, stripped, "free CharStrings copy for OtherSubrs"); |
854 | 0 | } else |
855 | 0 | pprintd1(s, " %d -| ", 0); |
856 | 253k | } else { |
857 | 253k | pprintd1(s, " %d -| ", gdata.bits.size); |
858 | 253k | write_CharString(s, gdata.bits.data, gdata.bits.size); |
859 | 253k | } |
860 | | |
861 | 253k | stream_puts(s, " |-\n"); |
862 | 253k | gs_glyph_data_free(&gdata, "write_Private(CharStrings)"); |
863 | 253k | } |
864 | 13.1k | } |
865 | 13.1k | if (SubrsWithMM != 0) |
866 | 0 | gs_free_object(pfont->memory, SubrsWithMM, "free Subrs record"); |
867 | | |
868 | | /* Wrap up. */ |
869 | | |
870 | 13.1k | stream_puts(s, "end\nend\nreadonly put\nnoaccess put\n"); |
871 | 13.1k | s_release_param_printer(&rlist); |
872 | 13.1k | return 0; |
873 | 13.1k | } |
874 | | |
875 | | /* Encrypt and write a CharString. */ |
876 | | static int |
877 | | stream_write_encrypted(stream *s, const void *ptr, uint count) |
878 | 138 | { |
879 | 138 | const byte *const data = ptr; |
880 | 138 | crypt_state state = crypt_charstring_seed; |
881 | 138 | byte buf[50]; /* arbitrary */ |
882 | 138 | uint left, n; |
883 | 138 | int code = 0; |
884 | | |
885 | 679 | for (left = count; left > 0; left -= n) { |
886 | 541 | n = min(left, sizeof(buf)); |
887 | 541 | gs_type1_encrypt(buf, data + count - left, n, &state); |
888 | 541 | code = stream_write(s, buf, n); |
889 | 541 | } |
890 | 138 | return code; |
891 | 138 | } |
892 | | |
893 | | /* Write one FontInfo entry. */ |
894 | | static void |
895 | | write_font_info(stream *s, const char *key, const gs_const_string *pvalue, |
896 | | int do_write) |
897 | 52.6k | { |
898 | 52.6k | if (do_write) { |
899 | 51.3k | pprints1(s, "\n/%s ", key); |
900 | 51.3k | s_write_ps_string(s, pvalue->data, pvalue->size, PRINT_HEX_NOT_OK); |
901 | 51.3k | stream_puts(s, " def"); |
902 | 51.3k | } |
903 | 52.6k | } |
904 | | |
905 | | /* Write the definition of a Type 1 font. */ |
906 | | int |
907 | | psf_write_type1_font(stream *s, gs_font_type1 *pfont, int options, |
908 | | gs_glyph *orig_subset_glyphs, uint orig_subset_size, |
909 | | const gs_const_string *alt_font_name, int lengths[3]) |
910 | 13.1k | { |
911 | 13.1k | stream *es = s; |
912 | 13.1k | gs_offset_t start = stell(s); |
913 | 13.1k | param_printer_params_t ppp; |
914 | 13.1k | printer_param_list_t rlist; |
915 | 13.1k | gs_param_list *const plist = (gs_param_list *)&rlist; |
916 | 13.1k | stream AXE_stream; |
917 | 13.1k | stream_AXE_state AXE_state; |
918 | 13.1k | byte AXE_buf[200]; /* arbitrary */ |
919 | 13.1k | stream exE_stream; |
920 | 13.1k | stream_exE_state exE_state; |
921 | 13.1k | byte exE_buf[200]; /* arbitrary */ |
922 | 13.1k | psf_outline_glyphs_t glyphs; |
923 | 13.1k | int lenIV = pfont->data.lenIV; |
924 | 13.1k | int (*write_CharString)(stream *, const void *, uint) = stream_write; |
925 | 13.1k | int code = psf_get_type1_glyphs(&glyphs, pfont, orig_subset_glyphs, |
926 | 13.1k | orig_subset_size); |
927 | | |
928 | 13.1k | if (code < 0) |
929 | 0 | return code; |
930 | | |
931 | | /* Initialize the parameter printer. */ |
932 | | |
933 | 13.1k | ppp = param_printer_params_default; |
934 | 13.1k | ppp.item_suffix = " def\n"; |
935 | 13.1k | ppp.print_ok = |
936 | 13.1k | (options & WRITE_TYPE1_ASCIIHEX ? 0 : PRINT_BINARY_OK) | |
937 | 13.1k | PRINT_HEX_NOT_OK; |
938 | 13.1k | code = s_init_param_printer(&rlist, &ppp, s); |
939 | 13.1k | if (code < 0) |
940 | 0 | return code; |
941 | | |
942 | | /* Write the font header. */ |
943 | | |
944 | 13.1k | stream_puts(s, "%!FontType1-1.0: "); |
945 | 13.1k | write_font_name(s, pfont, alt_font_name, false); |
946 | 13.1k | stream_puts(s, "\n11 dict begin\n"); |
947 | | |
948 | | /* Write FontInfo. */ |
949 | | |
950 | 13.1k | stream_puts(s, "/FontInfo 5 dict dup begin"); |
951 | 13.1k | { |
952 | 13.1k | gs_font_info_t info; |
953 | 13.1k | int code = pfont->procs.font_info((gs_font *)pfont, NULL, |
954 | 13.1k | (FONT_INFO_COPYRIGHT | FONT_INFO_NOTICE | |
955 | 13.1k | FONT_INFO_FAMILY_NAME | FONT_INFO_FULL_NAME), |
956 | 13.1k | &info); |
957 | | |
958 | 13.1k | if (code >= 0) { |
959 | 13.1k | write_font_info(s, "Copyright", &info.Copyright, |
960 | 13.1k | info.members & FONT_INFO_COPYRIGHT); |
961 | 13.1k | write_font_info(s, "Notice", &info.Notice, |
962 | 13.1k | info.members & FONT_INFO_NOTICE); |
963 | 13.1k | write_font_info(s, "FamilyName", &info.FamilyName, |
964 | 13.1k | info.members & FONT_INFO_FAMILY_NAME); |
965 | 13.1k | write_font_info(s, "FullName", &info.FullName, |
966 | 13.1k | info.members & FONT_INFO_FULL_NAME); |
967 | 13.1k | } |
968 | 13.1k | } |
969 | 13.1k | stream_puts(s, "\nend readonly def\n"); |
970 | | |
971 | | /* Write the main font dictionary. */ |
972 | | |
973 | 13.1k | stream_puts(s, "/FontName "); |
974 | 13.1k | write_font_name(s, pfont, alt_font_name, true); |
975 | 13.1k | stream_puts(s, " def\n"); |
976 | 13.1k | code = write_Encoding(s, pfont, options, glyphs.subset_glyphs, |
977 | 13.1k | glyphs.subset_size, glyphs.notdef); |
978 | 13.1k | if (code < 0) |
979 | 0 | return code; |
980 | 13.1k | pprintg6(s, "/FontMatrix [%g %g %g %g %g %g] readonly def\n", |
981 | 13.1k | pfont->FontMatrix.xx, pfont->FontMatrix.xy, |
982 | 13.1k | pfont->FontMatrix.yx, pfont->FontMatrix.yy, |
983 | 13.1k | pfont->FontMatrix.tx, pfont->FontMatrix.ty); |
984 | 13.1k | write_uid(s, &pfont->UID, options); |
985 | 13.1k | pprintg4(s, "/FontBBox {%g %g %g %g} readonly def\n", |
986 | 13.1k | pfont->FontBBox.p.x, pfont->FontBBox.p.y, |
987 | 13.1k | pfont->FontBBox.q.x, pfont->FontBBox.q.y); |
988 | 13.1k | { |
989 | 13.1k | static const gs_param_item_t font_items[] = { |
990 | 13.1k | {"FontType", gs_param_type_int, |
991 | 13.1k | offset_of(gs_font_type1, FontType)}, |
992 | 13.1k | {"PaintType", gs_param_type_int, |
993 | 13.1k | offset_of(gs_font_type1, PaintType)}, |
994 | 13.1k | {"StrokeWidth", gs_param_type_float, |
995 | 13.1k | offset_of(gs_font_type1, StrokeWidth)}, |
996 | 13.1k | gs_param_item_end |
997 | 13.1k | }; |
998 | | |
999 | 13.1k | code = gs_param_write_items(plist, pfont, NULL, font_items); |
1000 | 13.1k | if (code < 0) |
1001 | 0 | return code; |
1002 | 13.1k | } |
1003 | | |
1004 | | /* |
1005 | | * This is nonsense. We cna't write the WeightVector alonr from a Multiple |
1006 | | * Master and expect any sensible results. Since its useless alone, there's |
1007 | | * no point in emitting it at all. Leaving the code in place in case we |
1008 | | * decide to write MM fonts one day. |
1009 | | { |
1010 | | const gs_type1_data *const pdata = &pfont->data; |
1011 | | |
1012 | | write_float_array(plist, "WeightVector", pdata->WeightVector.values, |
1013 | | pdata->WeightVector.count); |
1014 | | } |
1015 | | */ |
1016 | 13.1k | stream_puts(s, "currentdict end\n"); |
1017 | | |
1018 | | /* Write the Private dictionary. */ |
1019 | | |
1020 | 13.1k | if (lenIV < 0 && (options & WRITE_TYPE1_WITH_LENIV)) { |
1021 | | /* We'll have to encrypt the CharStrings. */ |
1022 | 16 | lenIV = 0; |
1023 | 16 | write_CharString = stream_write_encrypted; |
1024 | 16 | } |
1025 | 13.1k | if (options & WRITE_TYPE1_EEXEC) { |
1026 | 13.1k | stream_puts(s, "currentfile eexec\n"); |
1027 | 13.1k | lengths[0] = (int)(stell(s) - start); |
1028 | 13.1k | start = stell(s); |
1029 | 13.1k | if (options & WRITE_TYPE1_ASCIIHEX) { |
1030 | 13.1k | s_init(&AXE_stream, s->memory); |
1031 | 13.1k | s_init_state((stream_state *)&AXE_state, &s_AXE_template, NULL); |
1032 | 13.1k | s_init_filter(&AXE_stream, (stream_state *)&AXE_state, |
1033 | 13.1k | AXE_buf, sizeof(AXE_buf), es); |
1034 | | /* We have to set this after s_init_filter() as that function |
1035 | | * sets it to true. |
1036 | | */ |
1037 | 13.1k | AXE_state.EndOfData = false; |
1038 | 13.1k | es = &AXE_stream; |
1039 | 13.1k | } |
1040 | 13.1k | s_init(&exE_stream, s->memory); |
1041 | 13.1k | s_init_state((stream_state *)&exE_state, &s_exE_template, NULL); |
1042 | 13.1k | exE_state.cstate = 55665; |
1043 | 13.1k | s_init_filter(&exE_stream, (stream_state *)&exE_state, |
1044 | 13.1k | exE_buf, sizeof(exE_buf), es); |
1045 | 13.1k | es = &exE_stream; |
1046 | | /* |
1047 | | * Note: eexec encryption always writes/skips 4 initial bytes, not |
1048 | | * the number of initial bytes given by pdata->lenIV. |
1049 | | */ |
1050 | 13.1k | stream_puts(es, "****"); |
1051 | 13.1k | } |
1052 | 13.1k | code = write_Private(es, pfont, glyphs.subset_glyphs, glyphs.subset_size, |
1053 | 13.1k | glyphs.notdef, lenIV, write_CharString, &ppp, options); |
1054 | 13.1k | if (code < 0) |
1055 | 0 | return code; |
1056 | 13.1k | stream_puts(es, "dup/FontName get exch definefont pop\n"); |
1057 | 13.1k | if (options & WRITE_TYPE1_EEXEC) { |
1058 | 13.1k | if (options & (WRITE_TYPE1_EEXEC_PAD | WRITE_TYPE1_EEXEC_MARK)) |
1059 | 13.1k | stream_puts(es, "mark "); |
1060 | 13.1k | stream_puts(es, "currentfile closefile\n"); |
1061 | 13.1k | s_close_filters(&es, s); |
1062 | 13.1k | lengths[1] = (int)(stell(s) - start); |
1063 | 13.1k | start = stell(s); |
1064 | 13.1k | if (options & WRITE_TYPE1_EEXEC_PAD) { |
1065 | 13.1k | int i; |
1066 | | |
1067 | 118k | for (i = 0; i < 8; ++i) |
1068 | 105k | stream_puts(s, "\n0000000000000000000000000000000000000000000000000000000000000000"); |
1069 | 13.1k | stream_puts(s, "\ncleartomark\n"); |
1070 | 13.1k | } |
1071 | 13.1k | lengths[2] = (int)(stell(s) - start); |
1072 | 13.1k | } else { |
1073 | 0 | lengths[0] = (int)(stell(s) - start); |
1074 | 0 | lengths[1] = lengths[2] = 0; |
1075 | 0 | } |
1076 | | |
1077 | | /* Wrap up. */ |
1078 | | |
1079 | 13.1k | s_release_param_printer(&rlist); |
1080 | 13.1k | return 0; |
1081 | 13.1k | } |