/src/ghostpdl/pcl/pcl/pcsfont.c
Line | Count | Source |
1 | | /* Copyright (C) 2001-2026 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 | | /* pcsfont.c */ |
18 | | /* PCL5 soft font creation commands */ |
19 | | #include "memory_.h" |
20 | | #include "stdio_.h" /* needed for pl_load_tt_font */ |
21 | | #include "math_.h" |
22 | | #include "gdebug.h" |
23 | | #include "pcommand.h" |
24 | | #include "pcfont.h" |
25 | | #include "pcursor.h" |
26 | | #include "pcpage.h" |
27 | | #include "pcstate.h" |
28 | | #include "pcfsel.h" |
29 | | #include "pcparse.h" |
30 | | #include "pjparse.h" |
31 | | #include "pldict.h" |
32 | | #include "plvalue.h" |
33 | | #include "plmain.h" /* for high_level_device... |
34 | | hopefully this will go away soon */ |
35 | | #include "plfapi.h" |
36 | | |
37 | | #include "gsbitops.h" |
38 | | #include "gsccode.h" |
39 | | #include "gsmatrix.h" |
40 | | #include "gsutil.h" |
41 | | #include "gxfont.h" |
42 | | #include "gxfont42.h" |
43 | | |
44 | | #define IGNORE_BAD_HEADER_FORMAT_SPECIFIER |
45 | | |
46 | | /* Emulate bug in HP printer where component metrics are ignored. */ |
47 | | #define DISABLE_USE_MY_METRICS |
48 | | |
49 | | /* Define the downloaded character data formats. */ |
50 | | typedef enum |
51 | | { |
52 | | pccd_bitmap = 4, |
53 | | pccd_intellifont = 10, |
54 | | pccd_truetype = 15 |
55 | | } pcl_character_format; |
56 | | |
57 | | /* ------ Internal procedures ------ */ |
58 | | |
59 | | /* Delete a soft font. If it is the currently selected font, or the */ |
60 | | /* current primary or secondary font, cause a new one to be chosen. */ |
61 | | static int |
62 | | pcl_delete_soft_font(pcl_state_t * pcs, const byte * key, uint ksize, |
63 | | void *value) |
64 | 123 | { |
65 | 123 | if (value == NULL) { |
66 | 106 | if (!pl_dict_find_no_stack(&pcs->soft_fonts, key, ksize, &value)) |
67 | 94 | return 0; /* not a defined font */ |
68 | 106 | } |
69 | 29 | { |
70 | 29 | pl_font_t *plfontp = (pl_font_t *) value; |
71 | | |
72 | 29 | if (pcs->font_selection[0].font == plfontp) |
73 | 0 | pcs->font_selection[0].font = 0; |
74 | 29 | if (pcs->font_selection[1].font == plfontp) |
75 | 0 | pcs->font_selection[1].font = 0; |
76 | | /* if this is permanent font we need to tell PJL we are |
77 | | removing it */ |
78 | 29 | if (plfontp->storage & pcds_permanent) |
79 | 0 | if (pjl_proc_register_permanent_soft_font_deletion(pcs->pjls, |
80 | 0 | plfontp-> |
81 | 0 | params. |
82 | 0 | pjl_font_number) |
83 | 0 | > 0) { |
84 | 0 | int code = pcl_set_current_font_environment(pcs); |
85 | |
|
86 | 0 | if (code < 0) |
87 | 0 | return code; |
88 | 0 | } |
89 | 29 | pcs->font = pcs->font_selection[pcs->font_selected].font; |
90 | 29 | pl_dict_undef_purge_synonyms(&pcs->soft_fonts, key, ksize); |
91 | 29 | } |
92 | 0 | return 0; |
93 | 29 | } |
94 | | |
95 | | /* ------ Commands ------ */ |
96 | | |
97 | | static int /* ESC * c <id> D */ |
98 | | pcl_assign_font_id(pcl_args_t * pargs, pcl_state_t * pcs) |
99 | 469 | { |
100 | 469 | uint id = uint_arg(pargs); |
101 | | |
102 | 469 | id_set_value(pcs->font_id, id); |
103 | | /* set state to use id's not strings */ |
104 | 469 | pcs->font_id_type = numeric_id; |
105 | 469 | return 0; |
106 | 469 | } |
107 | | |
108 | | /* Supports copy or assignment of resident fonts. Copying a soft font |
109 | | involves a deep copy and a new font. Copying a resident font |
110 | | creates a link to the original (source) font */ |
111 | | |
112 | | static int |
113 | | pcl_make_resident_font_copy(pcl_state_t * pcs) |
114 | 0 | { |
115 | 0 | pl_dict_enum_t dictp; |
116 | 0 | gs_const_string key; |
117 | 0 | void *value; |
118 | 0 | bool found = false; |
119 | | |
120 | | /* first check for a duplicate key, if found remove it */ |
121 | 0 | if (pl_dict_lookup |
122 | 0 | (&pcs->built_in_fonts, CURRENT_FONT_ID, CURRENT_FONT_ID_SIZE, &value, |
123 | 0 | false, (pl_dict_t **) 0)) |
124 | 0 | if (pl_dict_undef |
125 | 0 | (&pcs->built_in_fonts, CURRENT_FONT_ID, |
126 | 0 | CURRENT_FONT_ID_SIZE) == false) |
127 | | /* shouldn't fail */ |
128 | 0 | return -1; |
129 | | |
130 | | /* now search for the value */ |
131 | 0 | pl_dict_enum_begin(&pcs->built_in_fonts, &dictp); |
132 | 0 | while (pl_dict_enum_next(&dictp, &key, &value)) |
133 | 0 | if ((void *)(pcs->font) == value) { |
134 | 0 | found = true; |
135 | 0 | break; |
136 | 0 | } |
137 | 0 | if (found == false) |
138 | 0 | return -1; |
139 | 0 | return pl_dict_put_synonym(&pcs->built_in_fonts, key.data, |
140 | 0 | key.size, CURRENT_FONT_ID, CURRENT_FONT_ID_SIZE); |
141 | 0 | } |
142 | | |
143 | | static int /* ESC * c <fc_enum> F */ |
144 | | pcl_font_control(pcl_args_t * pargs, pcl_state_t * pcs) |
145 | 33.1k | { |
146 | 33.1k | int code = 0; |
147 | 33.1k | gs_const_string key; |
148 | 33.1k | void *value; |
149 | 33.1k | pl_dict_enum_t denum; |
150 | | |
151 | 33.1k | switch (uint_arg(pargs)) { |
152 | 321 | case 0: |
153 | | /* Delete all soft fonts. */ |
154 | 321 | pcs->font = pcs->font_selection[pcs->font_selected].font; |
155 | 321 | pl_dict_enum_stack_begin(&pcs->soft_fonts, &denum, false); |
156 | 324 | while (pl_dict_enum_next(&denum, &key, &value)) { |
157 | 3 | code = pcl_delete_soft_font(pcs, key.data, key.size, value); |
158 | 3 | if (code < 0) |
159 | 0 | return code; |
160 | | /* when deleting fonts we must restart the enumeration |
161 | | each time because the last deleted font may have had |
162 | | deleted synonyms which are not properly registered in |
163 | | the enumeration structure. NB A similar change should |
164 | | be made for deleting all temporary fonts. */ |
165 | 3 | pl_dict_enum_stack_begin(&pcs->soft_fonts, &denum, false); |
166 | 3 | } |
167 | 321 | pl_dict_release(&pcs->soft_fonts); |
168 | 321 | break; |
169 | 32.8k | case 1: |
170 | | /* Delete all temporary soft fonts. */ |
171 | 32.8k | pl_dict_enum_stack_begin(&pcs->soft_fonts, &denum, false); |
172 | 32.8k | while (pl_dict_enum_next(&denum, &key, &value)) |
173 | 14 | if (((pl_font_t *) value)->storage == pcds_temporary) { |
174 | 14 | code = pcl_delete_soft_font(pcs, key.data, key.size, value); |
175 | 14 | if (code < 0) |
176 | 0 | return code; |
177 | | /* Since deleting the softfont also deletes any "synonyms" in |
178 | | the dictionary, it means the dictionary contents can change |
179 | | under our feet. |
180 | | The simplest solution is to start the enumeration with |
181 | | a clean slate. This isn't used often enough for the |
182 | | efficiency to be a worry. |
183 | | */ |
184 | 14 | pl_dict_enum_stack_begin(&pcs->soft_fonts, &denum, false); |
185 | 14 | } |
186 | 32.8k | break; |
187 | 32.8k | case 2: |
188 | | /* Delete soft font <font_id>. */ |
189 | 1 | code = pcl_delete_soft_font(pcs, CURRENT_FONT_ID, CURRENT_FONT_ID_SIZE, |
190 | 1 | NULL); |
191 | | /* decache the currently selected font in case we deleted it. */ |
192 | 1 | pcl_decache_font(pcs, -1, true); |
193 | | |
194 | 1 | break; |
195 | 3 | case 3: |
196 | | /* Delete character <font_id, character_code>. */ |
197 | 3 | if (pl_dict_find_no_stack |
198 | 3 | (&pcs->soft_fonts, CURRENT_FONT_ID, CURRENT_FONT_ID_SIZE, |
199 | 3 | &value)) |
200 | 0 | pl_font_remove_glyph((pl_font_t *) value, |
201 | 0 | pcs->character_code); |
202 | 3 | return 0; |
203 | | |
204 | 0 | break; |
205 | 1 | case 4: |
206 | | /* Make soft font <font_id> temporary. */ |
207 | 1 | if (pl_dict_find_no_stack |
208 | 1 | (&pcs->soft_fonts, CURRENT_FONT_ID, CURRENT_FONT_ID_SIZE, |
209 | 1 | &value)) |
210 | 0 | ((pl_font_t *) value)->storage = pcds_temporary; |
211 | | |
212 | 1 | break; |
213 | 0 | case 5: |
214 | | /* Make soft font <font_id> permanent. */ |
215 | 0 | if (pl_dict_find_no_stack |
216 | 0 | (&pcs->soft_fonts, CURRENT_FONT_ID, CURRENT_FONT_ID_SIZE, |
217 | 0 | &value)) { |
218 | 0 | ((pl_font_t *) value)->storage = pcds_permanent; |
219 | 0 | ((pl_font_t *) value)->params.pjl_font_number = |
220 | 0 | pjl_proc_register_permanent_soft_font_addition(pcs->pjls); |
221 | 0 | } |
222 | 0 | break; |
223 | 0 | case 6: |
224 | 0 | { |
225 | 0 | if (pcs->font == 0) { |
226 | 0 | code = pcl_recompute_font(pcs, false); |
227 | 0 | if (code < 0) |
228 | 0 | return code; |
229 | 0 | } |
230 | 0 | if (pcs->font->storage == pcds_internal) { |
231 | 0 | return pcl_make_resident_font_copy(pcs); |
232 | 0 | } else { |
233 | 0 | pl_font_t *plfont = pl_clone_font(pcs->font, |
234 | 0 | pcs->memory, |
235 | 0 | "pcl_font_control()"); |
236 | |
|
237 | 0 | if (plfont == 0) { |
238 | 0 | dmprintf(pcs->memory, "pcsfont.c clone font FIXME\n"); |
239 | 0 | return 0; |
240 | 0 | } |
241 | 0 | code = gs_definefont(pcs->font_dir, plfont->pfont); |
242 | 0 | if (code < 0) |
243 | 0 | return code; |
244 | 0 | if (plfont->scaling_technology == plfst_TrueType) |
245 | 0 | code = pl_fapi_passfont(plfont, 0, NULL, NULL, NULL, 0); |
246 | 0 | if (code < 0) |
247 | 0 | return code; |
248 | | |
249 | 0 | code = pcl_delete_soft_font(pcs, CURRENT_FONT_ID, |
250 | 0 | CURRENT_FONT_ID_SIZE, NULL); |
251 | 0 | if (code < 0) |
252 | 0 | return code; |
253 | 0 | plfont->storage = pcds_temporary; |
254 | 0 | plfont->data_are_permanent = false; |
255 | 0 | code = pl_dict_put(&pcs->soft_fonts, CURRENT_FONT_ID, |
256 | 0 | CURRENT_FONT_ID_SIZE, plfont); |
257 | 0 | } |
258 | 0 | } |
259 | 0 | break; |
260 | 52 | default: |
261 | 52 | return 0; |
262 | 33.1k | } |
263 | 33.1k | return code; |
264 | 33.1k | } |
265 | | |
266 | | #ifdef DEBUG |
267 | | static void |
268 | | dump_dl_font_header(const gs_memory_t * mem, const pcl_font_header_t *pfh) |
269 | | { |
270 | | const char *header_format; |
271 | | int i; |
272 | | |
273 | | dmprintf1(mem, "FontDescriptorSize:%d\n", pl_get_uint16(pfh->FontDescriptorSize)); |
274 | | |
275 | | switch (pfh->HeaderFormat) { |
276 | | case pcfh_bitmap: |
277 | | header_format = "bitmap"; |
278 | | break; |
279 | | case pcfh_resolution_bitmap: |
280 | | header_format = "resolution bitmap"; |
281 | | break; |
282 | | case pcfh_intellifont_bound: |
283 | | header_format = "bound intellifont"; |
284 | | break; |
285 | | case pcfh_intellifont_unbound: |
286 | | header_format = "unbound intellifont"; |
287 | | break; |
288 | | case pcfh_truetype: |
289 | | header_format = "truetype"; |
290 | | break; |
291 | | case pcfh_truetype_large: |
292 | | header_format = "truetype large"; |
293 | | break; |
294 | | default: |
295 | | header_format = "unknown"; |
296 | | } |
297 | | dmprintf1(mem, "Header Format:%s\n", header_format); |
298 | | dmprintf1(mem, "Font Type:%d\n", (pl_font_type_t) pfh->FontType); |
299 | | dmprintf1(mem, "Style:%d\n", (pfh->StyleMSB << 8) + pfh->StyleLSB); |
300 | | dmprintf1(mem, "BaseLinePostion:%d\n", pl_get_uint16(pfh->BaselinePosition)); |
301 | | dmprintf1(mem, "Reserved (should be 0):%d\n", pfh->Reserved); |
302 | | dmprintf1(mem, "CellWidth:%d\n", pl_get_uint16(pfh->CellWidth)); |
303 | | dmprintf1(mem, "CellHeight:%d\n", pl_get_uint16(pfh->CellHeight)); |
304 | | dmprintf1(mem, "Orientation:%d\n", pfh->Orientation); |
305 | | dmprintf1(mem, "Spacing:%d\n", pfh->Spacing); |
306 | | dmprintf1(mem, "SymbolSet:%d\n", pl_get_uint16(pfh->SymbolSet)); |
307 | | dmprintf1(mem, "Pitch:%d\n", pl_get_uint16(pfh->Pitch)); |
308 | | dmprintf1(mem, "Height:%d\n", pl_get_uint16(pfh->Height)); |
309 | | dmprintf1(mem, "xHeight:%d\n", pl_get_uint16(pfh->xHeight)); |
310 | | dmprintf1(mem, "WidthType:%d\n", pfh->WidthType); |
311 | | dmprintf1(mem, "StrokeWeight:%d\n", pfh->StrokeWeight); |
312 | | dmprintf1(mem, "TypeFace:%d\n", (pfh->TypefaceMSB << 8) + pfh->TypefaceLSB); |
313 | | dmprintf1(mem, "SerifStyle:%d\n", pfh->SerifStyle); |
314 | | dmprintf1(mem, "Quality:%d\n", pfh->Quality); |
315 | | dmprintf1(mem, "Placement:%d\n", pfh->Placement); |
316 | | dmprintf1(mem, "UnderlinePosition:%d\n", pfh->UnderlinePosition); |
317 | | dmprintf1(mem, "UnderlineThickness:%d\n", pfh->UnderlineThickness); |
318 | | dmprintf1(mem, "TextHeight:%d\n", pl_get_uint16(pfh->TextHeight)); |
319 | | dmprintf1(mem, "TextWidth:%d\n", pl_get_uint16(pfh->TextWidth)); |
320 | | dmprintf1(mem, "FirstCode:%d\n", pl_get_uint16(pfh->FirstCode)); |
321 | | dmprintf1(mem, "LastCode:%d\n", pl_get_uint16(pfh->LastCode)); |
322 | | |
323 | | dmprintf1(mem, "PitchExtended:%d\n", pfh->PitchExtended); |
324 | | dmprintf1(mem, "HeightExtended:%d\n", pfh->HeightExtended); |
325 | | dmprintf1(mem, "CapHeight:%d\n", pl_get_uint16(pfh->CapHeight)); |
326 | | dmprintf4(mem, "FontNumber:%d %d %d %d\n", pfh->FontNumber[0], |
327 | | pfh->FontNumber[1], pfh->FontNumber[2], pfh->FontNumber[3]); |
328 | | dmprintf(mem, "FontName:"); |
329 | | for (i = 0; i < sizeof(pfh->FontName); i++) { |
330 | | unsigned char c = pfh->FontName[i]; |
331 | | if (c < 32 || c == 127) |
332 | | dmprintf1(mem, "<%02x>", c); |
333 | | else |
334 | | dmprintf1(mem, "%c", c); |
335 | | } |
336 | | dmprintf(mem, "\n"); |
337 | | if (pfh->HeaderFormat == pcfh_resolution_bitmap) { |
338 | | #define pfhx ((const pcl_resolution_bitmap_header_t *)pfh) |
339 | | dmprintf1(mem, "XResolution:%d\n", pl_get_uint16(pfhx->XResolution)); |
340 | | dmprintf1(mem, "YResolution:%d\n", pl_get_uint16(pfhx->YResolution)); |
341 | | #undef pfhx |
342 | | } |
343 | | |
344 | | return; |
345 | | } |
346 | | #endif |
347 | | static int /* ESC ) s <count> W */ |
348 | | pcl_font_header(pcl_args_t * pargs, pcl_state_t * pcs) |
349 | 113 | { |
350 | 113 | uint count = uint_arg(pargs); |
351 | 113 | const byte *data = arg_data(pargs); |
352 | 113 | pcl_font_header_t *pfh = (pcl_font_header_t *) data; |
353 | 113 | uint desc_size; |
354 | 113 | pl_font_scaling_technology_t fst; |
355 | 113 | gs_memory_t *mem = pcs->memory; |
356 | 113 | pl_font_t *plfont; |
357 | 113 | byte *header; |
358 | 113 | int code; |
359 | 113 | bool has_checksum; |
360 | | |
361 | | #ifdef DEBUG |
362 | | if (gs_debug_c('i')) { |
363 | | pcl_debug_dump_data(pcs->memory, arg_data(pargs), uint_arg(pargs)); |
364 | | } |
365 | | #endif |
366 | | |
367 | 113 | if (count < 64 && pfh->HeaderFormat != pcfh_bitmap) |
368 | 8 | return e_Range; /* pcfh_bitmap defaults short headers to 0 except underline position = 5; */ |
369 | | #ifdef DEBUG |
370 | | if (gs_debug_c('=')) { |
371 | | dump_dl_font_header(pcs->memory, pfh); |
372 | | } |
373 | | #endif |
374 | 105 | desc_size = |
375 | 105 | (pfh->FontDescriptorSize[0] << 8) + pfh->FontDescriptorSize[1]; |
376 | | /* Dispatch on the header format. */ |
377 | 105 | switch (pfh->HeaderFormat) { |
378 | 105 | case pcfh_bitmap: |
379 | 105 | case pcfh_resolution_bitmap: |
380 | 105 | fst = plfst_bitmap; |
381 | 105 | has_checksum = false; |
382 | 105 | break; |
383 | 0 | case pcfh_intellifont_bound: |
384 | 0 | case pcfh_intellifont_unbound: |
385 | 0 | fst = plfst_Intellifont; |
386 | | /* intellifonts do have a checksum but we have seen |
387 | | several fonts in tests that don't follow the |
388 | | documentation. It is possible intellifonts use a |
389 | | different offset than truetype to begin the summation. |
390 | | We have not investigated. */ |
391 | 0 | has_checksum = false; |
392 | 0 | break; |
393 | 0 | case pcfh_truetype: |
394 | 0 | case pcfh_truetype_large: |
395 | 0 | fst = plfst_TrueType; |
396 | 0 | has_checksum = true; |
397 | 0 | break; |
398 | 0 | default: |
399 | 0 | #ifdef IGNORE_BAD_HEADER_FORMAT_SPECIFIER |
400 | 0 | return 0; |
401 | | #else |
402 | | return_error(gs_error_invalidfont); |
403 | | #endif |
404 | | |
405 | 105 | } |
406 | | |
407 | | /* Fonts should include a final byte that makes the sum of the |
408 | | bytes in the font 0 (mod 256). The hp documentation says |
409 | | byte 64 and up should contribute to the checksum. All |
410 | | known examples indicate byte 64 (index 63 of the array |
411 | | below) is not included. */ |
412 | 105 | if (has_checksum) { |
413 | 0 | ulong sum = 0; |
414 | 0 | int i; |
415 | |
|
416 | 0 | for (i = count - 1; i >= 64; i--) { |
417 | 0 | sum += data[i]; |
418 | 0 | sum %= 256; |
419 | 0 | } |
420 | |
|
421 | 0 | if (sum != 0) { |
422 | 0 | dmprintf1(pcs->memory, "corrupt font sum=%ld\n", sum); |
423 | 0 | return_error(gs_error_invalidfont); |
424 | 0 | } |
425 | 0 | } |
426 | | /* Delete any previous font with this ID. */ |
427 | 105 | code = pcl_delete_soft_font(pcs, CURRENT_FONT_ID, CURRENT_FONT_ID_SIZE, NULL); |
428 | 105 | if (code < 0) |
429 | 0 | return code; |
430 | | /* Create the generic font information. */ |
431 | 105 | plfont = pl_alloc_font(mem, "pcl_font_header(pl_font_t)"); |
432 | | #ifdef DEBUG |
433 | | { |
434 | | int i; |
435 | | for (i = 0; i < sizeof(pfh->FontName); i++) |
436 | | plfont->FontName[i] = pfh->FontName[i]; |
437 | | } |
438 | | #endif |
439 | 105 | header = gs_alloc_bytes(mem, count, "pcl_font_header(header)"); |
440 | 105 | if (plfont == NULL || header == NULL) { |
441 | 0 | gs_free_object(mem, header, "pcl_font_header(header)"); |
442 | 0 | gs_free_object(mem, plfont, "pcl_font_header(pl_font_t)"); |
443 | 0 | return_error(e_Memory); |
444 | 0 | } |
445 | 105 | memcpy(header, data, count); |
446 | 105 | plfont->storage = pcds_temporary; |
447 | 105 | plfont->data_are_permanent = false; |
448 | 105 | if (fst == plfst_Intellifont) { |
449 | 0 | if (pfh->HeaderFormat != pcfh_intellifont_bound) { |
450 | | /* copy in the compliment while we are here. */ |
451 | 0 | memcpy(plfont->character_complement, &data[78], 8); |
452 | 0 | } |
453 | 0 | } |
454 | 105 | plfont->header = header; |
455 | 105 | plfont->header_size = count; |
456 | 105 | plfont->is_xl_format = false; |
457 | 105 | plfont->scaling_technology = fst; |
458 | 105 | plfont->font_type = (pl_font_type_t) pfh->FontType; |
459 | 105 | plfont->font_file = (char *)0; |
460 | 105 | code = pl_font_alloc_glyph_table(plfont, 256, mem, |
461 | 105 | "pcl_font_header(char table)"); |
462 | 105 | if (code < 0) |
463 | 0 | goto fail; |
464 | | /* Create the actual font. */ |
465 | 105 | switch (fst) { |
466 | 105 | case plfst_bitmap: |
467 | 105 | { |
468 | 105 | gs_font_base *pfont; |
469 | | |
470 | 105 | bitmap:pfont = gs_alloc_struct(mem, gs_font_base, &st_gs_font_base, |
471 | 105 | "pcl_font_header(bitmap font)"); |
472 | | |
473 | 105 | if (pfont == NULL) { |
474 | 0 | code = e_Memory; |
475 | 0 | goto fail; |
476 | 0 | } |
477 | 105 | code = |
478 | 105 | pl_fill_in_font((gs_font *) pfont, plfont, pcs->font_dir, |
479 | 105 | mem, "nameless_font"); |
480 | 105 | if (code < 0) |
481 | 0 | goto fail; |
482 | 105 | pl_fill_in_bitmap_font(pfont, gs_next_ids(mem, 1)); |
483 | | /* Extract parameters from the font header. */ |
484 | 105 | if (pfh->HeaderFormat == pcfh_resolution_bitmap) { |
485 | 0 | #define pfhx ((const pcl_resolution_bitmap_header_t *)pfh) |
486 | 0 | plfont->resolution.x = pl_get_uint16(pfhx->XResolution); |
487 | 0 | plfont->resolution.y = pl_get_uint16(pfhx->YResolution); |
488 | 0 | #undef pfhx |
489 | 0 | } |
490 | | /* note that we jump to the bitmap label for type 16 - so |
491 | | called truetype large which can also be bitmap but its |
492 | | resolution field is filled in when scanning the |
493 | | segments (see pl_font_scan_segments() the resolution |
494 | | does not show up in the font header. */ |
495 | 105 | else if (pfh->HeaderFormat == pcfh_bitmap) |
496 | 105 | plfont->resolution.x = plfont->resolution.y = 300; |
497 | 105 | { |
498 | 105 | ulong pitch_1024th_dots = |
499 | 105 | ((ulong) pl_get_uint16(pfh->Pitch) << 8) + |
500 | 105 | pfh->PitchExtended; |
501 | 105 | double pitch_cp = (double) |
502 | 105 | (pitch_1024th_dots / 1024.0 /* dots */ |
503 | 105 | / plfont->resolution.x /* => inches */ |
504 | 105 | * 7200.0); |
505 | | |
506 | 105 | pl_fp_set_pitch_cp(&plfont->params, pitch_cp); |
507 | 105 | } |
508 | 105 | { |
509 | 105 | uint height_quarter_dots = pl_get_uint16(pfh->Height); |
510 | | |
511 | 105 | plfont->params.height_4ths = |
512 | 105 | (uint) (floor((double)height_quarter_dots * 72.0 / |
513 | 105 | (double)(plfont->resolution.x) + 0.5)); |
514 | 105 | } |
515 | 105 | break; |
516 | 105 | } |
517 | 0 | case plfst_TrueType: |
518 | 0 | { |
519 | |
|
520 | 0 | gs_font_type42 *pfont; |
521 | |
|
522 | 0 | { |
523 | 0 | static const pl_font_offset_errors_t errors = { |
524 | 0 | gs_error_invalidfont, 0 |
525 | 0 | }; |
526 | 0 | code = |
527 | 0 | pl_font_scan_segments(mem, plfont, 70, desc_size, |
528 | 0 | (ulong) count - 2, |
529 | 0 | pfh->HeaderFormat == |
530 | 0 | pcfh_truetype_large, &errors); |
531 | 0 | if (code < 0) |
532 | 0 | goto fail; |
533 | | /* truetype large format 16 can be truetype or bitmap - |
534 | | absurd */ |
535 | 0 | if ((pfh->HeaderFormat == pcfh_truetype_large) && |
536 | 0 | (plfont->scaling_technology == plfst_bitmap)) |
537 | 0 | goto bitmap; |
538 | |
|
539 | 0 | } |
540 | 0 | pfont = |
541 | 0 | gs_alloc_struct(mem, gs_font_type42, &st_gs_font_type42, |
542 | 0 | "pcl_font_header(truetype font)"); |
543 | 0 | if (pfont == NULL) { |
544 | 0 | code = e_Memory; |
545 | 0 | goto fail; |
546 | 0 | } |
547 | | |
548 | 0 | code = |
549 | 0 | pl_fill_in_font((gs_font *) pfont, plfont, pcs->font_dir, |
550 | 0 | mem, "nameless_font"); |
551 | 0 | if (code < 0) |
552 | 0 | goto fail; |
553 | | |
554 | 0 | { |
555 | 0 | uint num_chars = pl_get_uint16(pfh->LastCode); |
556 | |
|
557 | 0 | if (num_chars < 20) |
558 | 0 | num_chars = 20; |
559 | 0 | else if (num_chars > 300) |
560 | 0 | num_chars = 300; |
561 | 0 | code = pl_tt_alloc_char_glyphs(plfont, num_chars, mem, |
562 | 0 | "pcl_font_header(char_glyphs)"); |
563 | 0 | if (code < 0) |
564 | 0 | goto fail; |
565 | 0 | } |
566 | 0 | code = pl_fill_in_tt_font(pfont, NULL, gs_next_ids(mem, 1)); |
567 | 0 | if (code < 0) |
568 | 0 | goto fail; |
569 | 0 | { |
570 | 0 | uint pitch_cp = |
571 | 0 | (uint) (pl_get_uint16(pfh->Pitch) * 1000.0 / |
572 | 0 | pfont->data.unitsPerEm); |
573 | 0 | pl_fp_set_pitch_cp(&plfont->params, pitch_cp); |
574 | 0 | } |
575 | 0 | } |
576 | 0 | break; |
577 | 0 | case plfst_Intellifont: |
578 | 0 | { |
579 | 0 | gs_font_base *pfont = |
580 | 0 | gs_alloc_struct(mem, gs_font_base, &st_gs_font_base, |
581 | 0 | "pcl_font_header(bitmap font)"); |
582 | |
|
583 | 0 | if (pfont == NULL) { |
584 | 0 | code = e_Memory; |
585 | 0 | goto fail; |
586 | 0 | } |
587 | 0 | code = |
588 | 0 | pl_fill_in_font((gs_font *) pfont, plfont, pcs->font_dir, |
589 | 0 | mem, "nameless_font"); |
590 | 0 | if (code < 0) |
591 | 0 | goto fail; |
592 | 0 | pl_fill_in_intelli_font(pfont, gs_next_ids(mem, 1)); |
593 | 0 | { |
594 | 0 | uint pitch_cp = |
595 | 0 | (uint) (pl_get_uint16(pfh->Pitch) * 1000.0 / 8782.0); |
596 | 0 | pl_fp_set_pitch_cp(&plfont->params, pitch_cp); |
597 | 0 | } |
598 | 0 | break; |
599 | 0 | } |
600 | 0 | default: |
601 | 0 | code = gs_error_invalidfont; /* can't happen */ |
602 | 0 | goto fail; |
603 | 105 | } |
604 | | /* Extract common parameters from the font header. */ |
605 | 105 | plfont->params.symbol_set = pl_get_uint16(pfh->SymbolSet); |
606 | 105 | if (pfh->Spacing > 1) { |
607 | 8 | code = e_Range; |
608 | 8 | goto fail; |
609 | 8 | } |
610 | 97 | plfont->params.proportional_spacing = pfh->Spacing; |
611 | 97 | plfont->params.style = (pfh->StyleMSB << 8) + pfh->StyleLSB; |
612 | 97 | plfont->params.stroke_weight = /* signed byte */ |
613 | 97 | (int)(pfh->StrokeWeight ^ 0x80) - 0x80; |
614 | 97 | plfont->params.typeface_family = |
615 | 97 | (pfh->TypefaceMSB << 8) + pfh->TypefaceLSB; |
616 | 97 | plfont->params.pjl_font_number = pcs->pjl_dlfont_number++; |
617 | | |
618 | 97 | code = pl_dict_put(&pcs->soft_fonts, CURRENT_FONT_ID, |
619 | 97 | CURRENT_FONT_ID_SIZE, plfont); |
620 | 97 | if (code < 0) { |
621 | | /* on error, pl_dict_put consumes plfont */ |
622 | 0 | return code; |
623 | 0 | } |
624 | 97 | plfont->pfont->procs.define_font = gs_no_define_font; |
625 | | |
626 | 97 | if ((code = gs_definefont(pcs->font_dir, plfont->pfont)) != 0) { |
627 | 0 | goto fail; |
628 | 0 | } |
629 | | |
630 | 97 | if (plfont->scaling_technology == plfst_TrueType) |
631 | 0 | code = pl_fapi_passfont(plfont, 0, NULL, NULL, NULL, 0); |
632 | | |
633 | 97 | return code; |
634 | | |
635 | 8 | fail: |
636 | 8 | if (code < 0) |
637 | 0 | pl_free_font(mem, plfont, "pcl_font_header(pl_font_t)"); |
638 | | |
639 | 8 | return (code); |
640 | 97 | } |
641 | | |
642 | | static int /* ESC * c <char_code> E */ |
643 | | pcl_character_code(pcl_args_t * pargs, pcl_state_t * pcs) |
644 | 1.67k | { |
645 | 1.67k | pcs->character_code = uint_arg(pargs); |
646 | 1.67k | return 0; |
647 | 1.67k | } |
648 | | |
649 | | static int /* ESC ( s <count> W */ |
650 | | pcl_character_data(pcl_args_t * pargs, pcl_state_t * pcs) |
651 | 1.37k | { |
652 | 1.37k | uint count = uint_arg(pargs); |
653 | 1.37k | uint font_data_size = count; |
654 | 1.37k | const byte *data = arg_data(pargs); |
655 | 1.37k | void *value; |
656 | 1.37k | pl_font_t *plfont; |
657 | 1.37k | pcl_font_header_format_t format; |
658 | 1.37k | byte *char_data = 0; |
659 | 1.37k | int code; |
660 | | |
661 | | #ifdef DEBUG |
662 | | if (gs_debug_c('i')) { |
663 | | pcl_debug_dump_data(pcs->memory, arg_data(pargs), uint_arg(pargs)); |
664 | | } |
665 | | #endif |
666 | | |
667 | 1.37k | if (!pl_dict_find_no_stack(&pcs->soft_fonts, CURRENT_FONT_ID, |
668 | 1.37k | CURRENT_FONT_ID_SIZE, &value)) |
669 | 465 | return 0; /* font not found */ |
670 | | |
671 | 913 | plfont = ((pl_font_t *) value); |
672 | | |
673 | 913 | if (count < 4 || data[2] > count - 2) |
674 | 2 | goto fail_range; |
675 | 911 | if (data[1]) { /* continuation */ |
676 | | /* Check that we are continuing data - we know this is the |
677 | | case if the previous download character command byte count |
678 | | is smaller than the data indicated calculating the space |
679 | | for the glyph */ |
680 | 0 | if ((pcs->soft_font_char_data == 0)) |
681 | 0 | goto fail_range; |
682 | | /* NB we only enable this for uncompressed bitmap |
683 | | characters for now, since we don't have real world |
684 | | examples for the other font file formats. */ |
685 | 0 | if (data[0] != pccd_bitmap && data[3] != 1) { |
686 | 0 | dmprintf(pcs->memory, |
687 | 0 | "continuation not implemented for this font type\n"); |
688 | 0 | return e_Unimplemented; |
689 | 0 | } |
690 | | /* check for buffer overrun */ |
691 | 0 | if (pcs->soft_font_count + count - 2 > gs_object_size(pcs->memory, pcs->soft_font_char_data)) |
692 | 0 | goto fail_range; |
693 | | |
694 | | /* append the new data to the new object */ |
695 | 0 | memcpy(pcs->soft_font_char_data + pcs->soft_font_count, data + 2, |
696 | 0 | count - 2); |
697 | | /* update the continuation count */ |
698 | 0 | pcs->soft_font_count += (count - 2); |
699 | 0 | return 0; |
700 | 911 | } else { |
701 | 911 | pcs->soft_font_count = 0; |
702 | 911 | pcs->soft_font_char_data = 0; |
703 | 911 | } |
704 | 911 | format = (pcl_font_header_format_t) |
705 | 911 | ((const pcl_font_header_t *)plfont->header)->HeaderFormat; |
706 | 911 | switch (data[0]) { |
707 | 908 | case pccd_bitmap: |
708 | 908 | { |
709 | 908 | uint width, height; |
710 | | |
711 | 908 | if (data[2] != 14 || |
712 | 907 | (format != pcfh_bitmap && |
713 | 0 | format != pcfh_resolution_bitmap && |
714 | 0 | format != pcfh_truetype_large) |
715 | 908 | ) |
716 | 1 | goto fail_range; |
717 | | |
718 | 907 | width = pl_get_uint16(data + 10); |
719 | 907 | if (width < 1 || width > 16384) |
720 | 2 | goto fail_range; |
721 | 905 | height = pl_get_uint16(data + 12); |
722 | 905 | if (height < 1 || height > 16384) |
723 | 23 | goto fail_range; |
724 | | /* more error checking of offsets, delta, width and height. */ |
725 | 882 | { |
726 | 882 | int toff, loff; |
727 | 882 | int deltax; |
728 | | |
729 | 882 | loff = pl_get_int16(data + 6); |
730 | 882 | if ((-16384 > loff) || (loff > 16384)) |
731 | 1 | goto fail_range; |
732 | 881 | toff = pl_get_int16(data + 8); |
733 | 881 | if ((-16384 > toff) || (toff > 16384)) |
734 | 0 | goto fail_range; |
735 | 881 | deltax = pl_get_int16(data + 14); |
736 | 881 | if ((-32768 > deltax) || (deltax > 32767)) |
737 | 0 | goto fail_range; |
738 | | /* also reject if width * height larger than 1MByte */ |
739 | 881 | if ((width * height / 8) > 1024 * 1024) |
740 | 3 | goto fail_range; |
741 | 881 | } |
742 | | |
743 | 878 | switch (data[3]) { |
744 | 876 | case 1: /* uncompressed bitmap */ |
745 | 876 | font_data_size = 16 + (((width + 7) >> 3) * height); |
746 | 876 | break; |
747 | 0 | case 2: /* compressed bitmap */ |
748 | 0 | { |
749 | 0 | uint y = 0; |
750 | 0 | const byte *src = data + 16; |
751 | 0 | const byte *end = data + count; |
752 | 0 | uint width_bytes = (width + 7) >> 3; |
753 | 0 | byte *row; |
754 | |
|
755 | 0 | font_data_size = 16 + width_bytes * height; |
756 | |
|
757 | 0 | char_data = |
758 | 0 | gs_alloc_bytes(pcs->memory, |
759 | 0 | font_data_size, |
760 | 0 | "pcl_character_data(compressed bitmap)"); |
761 | 0 | if (char_data == 0) |
762 | 0 | return_error(e_Memory); |
763 | 0 | memcpy(char_data, data, 16); |
764 | 0 | memset(char_data + 16, 0, (size_t)width_bytes * height); |
765 | 0 | row = char_data + 16; |
766 | 0 | while (src < end && y < height) { /* Read the next compressed row. */ |
767 | 0 | uint x; |
768 | 0 | int color = 0; |
769 | 0 | uint reps = *src++; |
770 | |
|
771 | 0 | for (x = 0; src < end && x < width; color ^= 1) { /* Read the next run. */ |
772 | 0 | uint rlen = *src++; |
773 | |
|
774 | 0 | if (rlen > width - x) |
775 | 0 | goto fail_range; /* row overrun */ |
776 | 0 | if (color) { /* Set the run to black. */ |
777 | 0 | char *data = (char *)row; |
778 | |
|
779 | 0 | while (rlen--) { |
780 | 0 | data[x >> 3] |= (128 >> (x & 7)); |
781 | 0 | x++; |
782 | 0 | } |
783 | 0 | } else |
784 | 0 | x += rlen; |
785 | 0 | } |
786 | 0 | row += width_bytes; |
787 | 0 | ++y; |
788 | | /* Replicate the row if needed. */ |
789 | 0 | for (; reps > 0 && y < height; |
790 | 0 | --reps, ++y, row += width_bytes) |
791 | 0 | memcpy(row, row - width_bytes, |
792 | 0 | width_bytes); |
793 | 0 | } |
794 | 0 | } |
795 | 0 | break; |
796 | 2 | default: |
797 | 2 | goto fail_range; |
798 | 878 | } |
799 | 878 | } |
800 | 876 | break; |
801 | 876 | case pccd_intellifont: |
802 | 0 | if (data[2] != 2 || |
803 | 0 | (format != pcfh_intellifont_bound && |
804 | 0 | format != pcfh_intellifont_unbound) |
805 | 0 | ) |
806 | 0 | goto fail_range; |
807 | 0 | switch (data[3]) { |
808 | 0 | case 3: /* non-compound character */ |
809 | | /* See TRM Table 11-41 (p. 11-60) for the following. */ |
810 | 0 | if (count < 14) |
811 | 0 | goto fail_range; |
812 | 0 | { |
813 | 0 | uint data_size = pl_get_uint16(data + 4); |
814 | | |
815 | | /* The contour data excludes 4 initial bytes of header */ |
816 | | /* and 2 final bytes of padding/checksum. */ |
817 | 0 | if (data_size != count - 6) |
818 | 0 | goto fail_range; |
819 | 0 | } |
820 | 0 | break; |
821 | 0 | case 4: /* compound character */ |
822 | | /* See TRM Figure 11-42 and 11-43 (p. 11-61) */ |
823 | | /* for the following. */ |
824 | 0 | if (count < 8) |
825 | 0 | goto fail_range; |
826 | 0 | { |
827 | 0 | uint num_components = data[6]; |
828 | |
|
829 | 0 | if (count != 8 + num_components * 6 + 2) |
830 | 0 | goto fail_range; |
831 | 0 | } |
832 | 0 | break; |
833 | 0 | default: |
834 | 0 | goto fail_range; |
835 | 0 | } |
836 | 0 | break; |
837 | 0 | case pccd_truetype: |
838 | 0 | if (format != pcfh_truetype && format != pcfh_truetype_large) |
839 | 0 | goto fail_range; |
840 | 0 | break; |
841 | 3 | default: |
842 | 3 | goto fail_range; |
843 | 911 | } |
844 | | /* Register the character. */ |
845 | | /**** FREE PREVIOUS DEFINITION ****/ |
846 | | /* Compressed bitmaps have already allocated and filled in */ |
847 | | /* the character data structure. */ |
848 | 876 | if (char_data == 0) { |
849 | 876 | char_data = gs_alloc_bytes(pcs->memory, font_data_size, |
850 | 876 | "pcl_character_data"); |
851 | 876 | if (char_data == 0) |
852 | 0 | return_error(e_Memory); |
853 | 876 | memset(char_data, 0, font_data_size); |
854 | | /* if count > font_data_size extra data is ignored */ |
855 | 876 | memcpy(char_data, data, min(count, font_data_size)); |
856 | | /* NB we only handle continuation for uncompressed bitmap characters */ |
857 | 876 | if (data[0] == pccd_bitmap && data[3] == 1 && font_data_size > count /* expecting continuation */ |
858 | 876 | ) { |
859 | 9 | pcs->soft_font_char_data = char_data; |
860 | 9 | pcs->soft_font_count = count; |
861 | 867 | } else { |
862 | 867 | pcs->soft_font_char_data = 0; |
863 | 867 | pcs->soft_font_count = 0; |
864 | 867 | } |
865 | 876 | } |
866 | | /* get and set the orientation field */ |
867 | 876 | { |
868 | 876 | pcl_font_header_t *header = (pcl_font_header_t *) plfont->header; |
869 | | |
870 | 876 | plfont->orient = header->Orientation; |
871 | 876 | } |
872 | 876 | code = pl_font_add_glyph(plfont, pcs->character_code, char_data, font_data_size); |
873 | 876 | if (code < 0) { |
874 | 0 | gs_free_object(pcs->memory, char_data, "pcl_character_data"); |
875 | 0 | return code; |
876 | 0 | } |
877 | 876 | #ifdef DISABLE_USE_MY_METRICS |
878 | 876 | if (data[0] == pccd_truetype) |
879 | 0 | code = pl_font_disable_composite_metrics(plfont, pcs->character_code); |
880 | 876 | #endif /* DISABLE_USE_MY_METRICS */ |
881 | 876 | return code; |
882 | 0 | #undef plfont |
883 | | |
884 | 37 | fail_range: |
885 | 37 | gs_free_object(pcs->memory, char_data, "pcl_character_data"); |
886 | 37 | return e_Range; |
887 | 876 | } |
888 | | |
889 | | /* template for casting data to command */ |
890 | | typedef struct alphanumeric_data_s |
891 | | { |
892 | | byte operation; |
893 | | byte string_id[512]; |
894 | | } alphanumeric_data_t; |
895 | | |
896 | | typedef enum resource_type_enum |
897 | | { |
898 | | macro_resource, |
899 | | font_resource |
900 | | } resource_type_t; |
901 | | |
902 | | /* |
903 | | * Search the PJL file system for a macro or font resource and |
904 | | * associate it's name with the current font or macro id |
905 | | */ |
906 | | static int |
907 | | pcl_find_resource(pcl_state_t * pcs, |
908 | | const byte sid[], |
909 | | int sid_size, resource_type_t resource_type) |
910 | 0 | { |
911 | |
|
912 | 0 | void *value = NULL; |
913 | 0 | char alphaname[512 + 1]; |
914 | 0 | long int size; |
915 | 0 | int c; |
916 | 0 | int code = 0; |
917 | | |
918 | | /* a null terminated string is needed for the PJL resource call */ |
919 | 0 | for (c = 0; c < sid_size && c < 512; c++) |
920 | 0 | alphaname[c] = sid[c]; |
921 | 0 | alphaname[c] = '\0'; |
922 | |
|
923 | 0 | size = pjl_proc_get_named_resource_size(pcs->pjls, alphaname); |
924 | | /* resource not found */ |
925 | 0 | if (size <= 0) |
926 | 0 | return 0; |
927 | | |
928 | | /* for a macro we need enough room for the macro header plus the |
929 | | macro itself, fonts are handled differently, see below */ |
930 | 0 | value = gs_alloc_bytes(pcs->memory, |
931 | 0 | size + |
932 | 0 | (resource_type == macro_resource ? |
933 | 0 | sizeof(pcl_macro_t) : 0), |
934 | 0 | "resource"); |
935 | |
|
936 | 0 | if (value == NULL) |
937 | 0 | return_error(gs_error_Fatal); |
938 | | |
939 | | |
940 | 0 | if (pjl_proc_get_named_resource(pcs->pjls, alphaname, |
941 | 0 | (byte *) value + |
942 | 0 | (resource_type == macro_resource ? |
943 | 0 | sizeof(pcl_macro_t) : 0), size) < 0) { |
944 | 0 | gs_free_object(pcs->memory, value, "resource"); |
945 | 0 | return_error(gs_error_Fatal); |
946 | 0 | } |
947 | | |
948 | | /* if this is a font we have to recursively invoke the PCL |
949 | | interpreter to process the data and create the downloaded |
950 | | font. */ |
951 | 0 | if (resource_type == font_resource) { |
952 | 0 | stream_cursor_read r; |
953 | 0 | pcl_parser_state_t state; |
954 | |
|
955 | 0 | r.ptr = (byte *)value - 1; |
956 | 0 | r.limit = r.ptr + size; |
957 | 0 | state.definitions = pcs->pcl_commands; |
958 | 0 | code = pcl_process_init(&state, pcs); |
959 | 0 | if (code < 0 || (code = pcl_process(&state, pcs, &r) < 0)) { |
960 | 0 | gs_free_object(pcs->memory, value, "resource"); |
961 | 0 | return_error(code); |
962 | 0 | } |
963 | 0 | } |
964 | | |
965 | | /* The font resource was added to the dictionary when the font was |
966 | | downloaded in the recursive interpreter invocation above, so we |
967 | | don't need to add (put) it in the dictionary. */ |
968 | 0 | if (resource_type == macro_resource) { |
969 | 0 | code = pl_dict_put(&pcs->macros, CURRENT_MACRO_ID, CURRENT_MACRO_ID_SIZE, value); |
970 | 0 | if (code < 0) { |
971 | 0 | gs_free_object(pcs->memory, value, "resource"); |
972 | 0 | return code; |
973 | 0 | } |
974 | 0 | code = pl_dict_put_synonym(&pcs->macros, CURRENT_MACRO_ID, |
975 | 0 | CURRENT_MACRO_ID_SIZE, sid, sid_size); |
976 | 0 | if (code < 0) { |
977 | 0 | pl_dict_undef_purge_synonyms(&pcs->macros, CURRENT_MACRO_ID, CURRENT_MACRO_ID_SIZE); |
978 | 0 | return code; |
979 | 0 | } |
980 | 0 | } else { |
981 | 0 | code = pl_dict_put_synonym(&pcs->soft_fonts, CURRENT_FONT_ID, |
982 | 0 | CURRENT_FONT_ID_SIZE, sid, sid_size); |
983 | | /* font was constructed separately, don't need the |
984 | | original PCL commands from which the font was |
985 | | constructed. */ |
986 | 0 | gs_free_object(pcs->memory, value, "resource"); |
987 | 0 | if (code < 0) |
988 | 0 | return_error(code); |
989 | 0 | } |
990 | 0 | return code; |
991 | 0 | } |
992 | | |
993 | | static int /* ESC & n <count> W [operation][string ID] */ |
994 | | pcl_alphanumeric_id_data(pcl_args_t * pargs, pcl_state_t * pcs) |
995 | 0 | { |
996 | 0 | uint count = uint_arg(pargs); |
997 | |
|
998 | 0 | const alphanumeric_data_t *alpha_data = |
999 | 0 | (const alphanumeric_data_t *)arg_data(pargs); |
1000 | |
|
1001 | 0 | int string_id_size = (count - 1); /* size of id data size - operation size */ |
1002 | |
|
1003 | | #ifdef DEBUG |
1004 | | if (gs_debug_c('i')) { |
1005 | | pcl_debug_dump_data(pcs->memory, arg_data(pargs), uint_arg(pargs)); |
1006 | | } |
1007 | | #endif |
1008 | |
|
1009 | 0 | if (count == 0) |
1010 | 0 | return 0; |
1011 | 0 | if (count < 1 || count > 512) |
1012 | 0 | return e_Range; |
1013 | 0 | switch (alpha_data->operation) { |
1014 | 0 | case 0: |
1015 | | /* Set the current font id to the given string id. */ |
1016 | 0 | { |
1017 | 0 | char *new_id = |
1018 | 0 | (char *)gs_alloc_bytes(pcs->memory, string_id_size, |
1019 | 0 | "pcl_alphanumeric_id_data"); |
1020 | |
|
1021 | 0 | if (new_id == 0) |
1022 | 0 | return_error(e_Memory); |
1023 | | /* release the previous id, if necessary */ |
1024 | 0 | if (pcs->alpha_font_id.id) |
1025 | 0 | gs_free_object(pcs->memory, |
1026 | 0 | pcs->alpha_font_id.id, |
1027 | 0 | "pcl_free_string_id"); |
1028 | | /* copy in the new id from the data */ |
1029 | 0 | memcpy(new_id, alpha_data->string_id, string_id_size); |
1030 | | /* set new id and size */ |
1031 | 0 | pcs->alpha_font_id.id = (byte *) new_id; |
1032 | 0 | pcs->alpha_font_id.size = string_id_size; |
1033 | | /* now set up the state to use string id's */ |
1034 | 0 | pcs->font_id_type = string_id; |
1035 | 0 | } |
1036 | 0 | break; |
1037 | 0 | case 1: |
1038 | 0 | { |
1039 | | /* Associates the current font's font id to the font |
1040 | | with the string id. */ |
1041 | 0 | void *value; |
1042 | | /* simple case the font is in the dictionary */ |
1043 | 0 | if (pl_dict_find_no_stack(&pcs->soft_fonts, alpha_data->string_id, string_id_size, &value)) { |
1044 | 0 | (void)pl_dict_put_synonym(&pcs->soft_fonts, alpha_data->string_id, |
1045 | 0 | string_id_size, CURRENT_FONT_ID, |
1046 | 0 | CURRENT_FONT_ID_SIZE); |
1047 | 0 | return 0; |
1048 | 0 | } else { |
1049 | | /* search the PJL file system for a font resource */ |
1050 | 0 | return pcl_find_resource(pcs, alpha_data->string_id, |
1051 | 0 | string_id_size, font_resource); |
1052 | 0 | } |
1053 | 0 | } |
1054 | 0 | break; |
1055 | 0 | case 2: |
1056 | 0 | { |
1057 | | /* Select the fonts referred to by the String ID as |
1058 | | primary. Same as font id selection but uses the |
1059 | | string key instead of a numerical key */ |
1060 | 0 | void *value; |
1061 | 0 | pcl_font_selection_t *pfs = &pcs->font_selection[primary]; |
1062 | |
|
1063 | 0 | if (!pl_dict_find_no_stack(&pcs->soft_fonts, |
1064 | 0 | alpha_data->string_id, |
1065 | 0 | string_id_size, &value)) |
1066 | 0 | return 1; |
1067 | | /* NB wrong */ |
1068 | 0 | pcl_set_id_parameters(pcs, pfs, (pl_font_t *) value, 0); |
1069 | 0 | pcl_decache_font(pcs, -1, true); |
1070 | 0 | } |
1071 | 0 | break; |
1072 | 0 | case 3: |
1073 | 0 | { |
1074 | | /* same as case 2 but sets secondary font */ |
1075 | 0 | void *value; |
1076 | 0 | pcl_font_selection_t *pfs = &pcs->font_selection[secondary]; |
1077 | |
|
1078 | 0 | if (!pl_dict_find_no_stack(&pcs->soft_fonts, |
1079 | 0 | alpha_data->string_id, |
1080 | 0 | string_id_size, &value)) |
1081 | 0 | return 1; |
1082 | | /* NB wrong */ |
1083 | 0 | pcl_set_id_parameters(pcs, pfs, (pl_font_t *) value, 0); |
1084 | 0 | pcl_decache_font(pcs, -1, true); |
1085 | 0 | } |
1086 | 0 | break; |
1087 | 0 | case 4: |
1088 | 0 | { |
1089 | | /* sets the current macro id to the string id */ |
1090 | 0 | char *new_id = |
1091 | 0 | (char *)gs_alloc_bytes(pcs->memory, string_id_size, |
1092 | 0 | "pcl_alphanumeric_id_data"); |
1093 | |
|
1094 | 0 | if (new_id == 0) |
1095 | 0 | return_error(e_Memory); |
1096 | | /* release the previous id, if necessary */ |
1097 | 0 | if (pcs->alpha_macro_id.id) |
1098 | 0 | gs_free_object(pcs->memory, |
1099 | 0 | pcs->alpha_macro_id.id, |
1100 | 0 | "pcl_free_string_id"); |
1101 | | /* copy in the new id from the data */ |
1102 | 0 | memcpy(new_id, alpha_data->string_id, string_id_size); |
1103 | | /* set new id and size */ |
1104 | 0 | pcs->alpha_macro_id.id = (byte *) new_id; |
1105 | 0 | pcs->alpha_macro_id.size = string_id_size; |
1106 | | /* now set up the state to use string id's */ |
1107 | 0 | pcs->macro_id_type = string_id; |
1108 | 0 | } |
1109 | 0 | break; |
1110 | 0 | case 5: |
1111 | 0 | { |
1112 | | /* Associates the current macro's id with the string id. */ |
1113 | 0 | void *value; |
1114 | | /* simple case - the macro is in the dictionary */ |
1115 | 0 | if (pl_dict_find_no_stack(&pcs->macros, alpha_data->string_id, string_id_size, &value)) { |
1116 | 0 | (void)pl_dict_put_synonym(&pcs->macros, alpha_data->string_id, |
1117 | 0 | string_id_size, CURRENT_MACRO_ID, |
1118 | 0 | CURRENT_MACRO_ID_SIZE); |
1119 | 0 | return 0; |
1120 | 0 | } else { |
1121 | | /* search the PJL file system for a macro resource */ |
1122 | 0 | return pcl_find_resource(pcs, alpha_data->string_id, |
1123 | 0 | string_id_size, macro_resource); |
1124 | 0 | } |
1125 | 0 | } |
1126 | 0 | break; |
1127 | 0 | case 20: |
1128 | | /* deletes the font association named by the current Font ID */ |
1129 | 0 | if (pcs->font_id_type == string_id) |
1130 | 0 | return pcl_delete_soft_font(pcs, CURRENT_FONT_STRING_ID, |
1131 | 0 | CURRENT_FONT_STRING_ID_SIZE, NULL); |
1132 | 0 | break; |
1133 | 0 | case 21: |
1134 | | /* deletes the macro association named the the current macro id */ |
1135 | 0 | if (pcs->macro_id_type == string_id) |
1136 | 0 | pl_dict_undef(&pcs->macros, CURRENT_MACRO_STRING_ID, |
1137 | 0 | CURRENT_MACRO_STRING_ID_SIZE); |
1138 | 0 | break; |
1139 | 0 | case 100: |
1140 | | /* media select */ |
1141 | | |
1142 | | /* this is not sufficiently specified in the PCL |
1143 | | comparison guide and interacts with the control panel |
1144 | | so we do not implement it completely. We have verified |
1145 | | the following occurs: */ |
1146 | 0 | { |
1147 | 0 | int code = pcl_end_page_if_marked(pcs); |
1148 | 0 | if (code < 0) |
1149 | 0 | return code; |
1150 | 0 | return pcl_home_cursor(pcs); |
1151 | 0 | } |
1152 | 0 | break; |
1153 | 0 | default: |
1154 | 0 | return e_Range; |
1155 | 0 | } |
1156 | 0 | return 0; |
1157 | 0 | } |
1158 | | |
1159 | | /* Initialization */ |
1160 | | static int |
1161 | | pcsfont_do_registration(pcl_parser_state_t * pcl_parser_state, |
1162 | | gs_memory_t * mem) |
1163 | 16.1k | { /* Register commands */ |
1164 | 16.1k | DEFINE_CLASS('*') { |
1165 | 16.1k | 'c', 'D', |
1166 | 16.1k | PCL_COMMAND("Assign Font ID", pcl_assign_font_id, |
1167 | 16.1k | pca_neg_error | pca_big_error)}, { |
1168 | 16.1k | 'c', 'F', |
1169 | 16.1k | PCL_COMMAND("Font Control", pcl_font_control, |
1170 | 16.1k | pca_neg_error | pca_big_error)}, |
1171 | 16.1k | END_CLASS |
1172 | 16.1k | DEFINE_CLASS_COMMAND_ARGS(')', 's', 'W', "Font Header", |
1173 | 16.1k | pcl_font_header, pca_bytes) |
1174 | 16.1k | DEFINE_CLASS_COMMAND_ARGS('*', 'c', 'E', "Character Code", |
1175 | 16.1k | pcl_character_code, |
1176 | 16.1k | pca_neg_error | pca_big_ok) |
1177 | 16.1k | DEFINE_CLASS_COMMAND_ARGS('(', 's', 'W', "Character Data", |
1178 | 16.1k | pcl_character_data, pca_bytes) |
1179 | 16.1k | DEFINE_CLASS_COMMAND_ARGS('&', 'n', 'W', "Alphanumeric ID Data", |
1180 | 16.1k | pcl_alphanumeric_id_data, pca_bytes) |
1181 | 16.1k | return 0; |
1182 | 16.1k | } |
1183 | | static int |
1184 | | pcsfont_do_reset(pcl_state_t * pcs, pcl_reset_type_t type) |
1185 | 48.9k | { |
1186 | 48.9k | if (type & (pcl_reset_initial | pcl_reset_printer | pcl_reset_overlay)) { |
1187 | 48.9k | pcs->soft_font_char_data = 0; |
1188 | 48.9k | pcs->soft_font_count = 0; |
1189 | 48.9k | id_set_value(pcs->font_id, 0); |
1190 | 48.9k | pcs->character_code = 0; |
1191 | 48.9k | pcs->font_id_type = numeric_id; |
1192 | 48.9k | if ((type & pcl_reset_printer) != 0) { |
1193 | 32.7k | int code = 0; |
1194 | 32.7k | pcl_args_t args; |
1195 | | |
1196 | 32.7k | arg_set_uint(&args, 1); /* delete temporary fonts */ |
1197 | 32.7k | code = pcl_font_control(&args, pcs); |
1198 | 32.7k | if (pcs->alpha_font_id.id != 0) |
1199 | 0 | gs_free_object(pcs->memory, |
1200 | 32.7k | pcs->alpha_font_id.id, "pcsfont_do_reset"); |
1201 | 32.7k | if (code < 0) |
1202 | 0 | return code; |
1203 | 32.7k | } |
1204 | 48.9k | pcs->alpha_font_id.id = 0; |
1205 | 48.9k | } |
1206 | 48.9k | return 0; |
1207 | 48.9k | } |
1208 | | static int |
1209 | | pcsfont_do_copy(pcl_state_t * psaved, const pcl_state_t * pcs, |
1210 | | pcl_copy_operation_t operation) |
1211 | 0 | { |
1212 | 0 | if (operation & pcl_copy_after) { /* Don't restore the soft font set. */ |
1213 | 0 | psaved->soft_fonts = pcs->soft_fonts; |
1214 | 0 | psaved->built_in_fonts = pcs->built_in_fonts; |
1215 | 0 | } |
1216 | 0 | return 0; |
1217 | 0 | } |
1218 | | const pcl_init_t pcsfont_init = { |
1219 | | pcsfont_do_registration, pcsfont_do_reset, pcsfont_do_copy |
1220 | | }; |