/src/ghostpdl/pcl/pxl/pxerrors.c
Line | Count | Source |
1 | | /* Copyright (C) 2001-2023 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 | | /* pxerrors.c */ |
18 | | /* PCL XL error reporting */ |
19 | | |
20 | | #include "memory_.h" |
21 | | #include "stdio_.h" /* for sprintf */ |
22 | | #include "string_.h" |
23 | | #include "gsmemory.h" |
24 | | #include "gstypes.h" /* for gsmatrix.h */ |
25 | | #include "gsccode.h" /* for gxfont.h */ |
26 | | #include "gsmatrix.h" /* for gsfont.h */ |
27 | | #include "gsstate.h" /* for gsfont.h, gspath.h */ |
28 | | #include "gspaint.h" /* for gs_erasepage */ |
29 | | #include "gscoord.h" |
30 | | #include "gspath.h" |
31 | | #include "gsutil.h" |
32 | | #include "gxfixed.h" /* for gxchar.h */ |
33 | | #include "gxchar.h" |
34 | | #include "gxfont.h" |
35 | | #include "scommon.h" /* for pxparse.h */ |
36 | | #include "pxbfont.h" |
37 | | #include "pxerrors.h" |
38 | | #include "pxparse.h" |
39 | | #include "pxptable.h" /* for px_operator_names */ |
40 | | #include "pxstate.h" |
41 | | #include "pxfont.h" |
42 | | |
43 | | /* Imported operators */ |
44 | | px_operator_proc(pxEndPage); |
45 | | px_operator_proc(pxSetPageDefaultCTM); |
46 | | |
47 | | /* set the font for the error page */ |
48 | | static px_font_t * |
49 | | px_error_setfont(px_state_t * pxs) |
50 | 12.0k | { |
51 | 12.0k | int code; |
52 | | |
53 | 12.0k | px_font_t *pxfont = pl_alloc_font(pxs->memory, "px_error_setfont"); |
54 | | |
55 | 12.0k | if (pxfont == 0) |
56 | 0 | return NULL; |
57 | | |
58 | 12.0k | pxfont->storage = pxfsInternal; |
59 | 12.0k | pxfont->font_type = plft_Unicode; /* as good as any */ |
60 | 12.0k | pxfont->data_are_permanent = true; |
61 | 12.0k | code = px_define_font(pxfont, (byte *) px_bitmap_font_header, |
62 | 12.0k | px_bitmap_font_header_size, |
63 | 12.0k | gs_next_ids(pxs->memory, 1), pxs); |
64 | 12.0k | { |
65 | 12.0k | const byte *cdatanext, *cdata = px_bitmap_font_char_data; |
66 | | |
67 | 876k | while (*cdata && code >= 0) { |
68 | 864k | cdatanext = cdata + 16 + |
69 | 864k | ((uint16at(cdata + 11, true) + 7) >> 3) * |
70 | 864k | uint16at(cdata + 13, true) + 1; /* add one to clear the char code */ |
71 | | |
72 | 864k | code = pl_font_add_glyph(pxfont, *cdata, cdata + 1, (int)(cdatanext - cdata - 2)); |
73 | 864k | cdata = cdatanext; |
74 | 864k | } |
75 | 12.0k | } |
76 | 12.0k | if (code < 0) { |
77 | 0 | pl_free_font(pxs->memory, pxfont, "px_error_setfont"); |
78 | 0 | return NULL; |
79 | 0 | } |
80 | 12.0k | gs_setfont(pxs->pgs, pxfont->pfont); |
81 | 12.0k | pxfont->pfont->FontMatrix = pxfont->pfont->orig_FontMatrix; |
82 | 12.0k | return pxfont; |
83 | 12.0k | } |
84 | | |
85 | | /* ---------------- Procedures ---------------- */ |
86 | | |
87 | | /* Record a warning. */ |
88 | | /* Return 1 if the warning table overflowed. */ |
89 | | /* If save_all is false, only remember the last warning with the same */ |
90 | | /* first word as this one. */ |
91 | | int |
92 | | px_record_warning(const char *message, bool save_all, px_state_t * pxs) |
93 | 29 | { |
94 | 29 | uint end = pxs->warning_length; |
95 | | |
96 | 29 | char *str = pxs->warnings + end; |
97 | | |
98 | 29 | char *word_end = strchr(message, ' '); |
99 | | |
100 | 29 | if (end + strlen(message) + 1 > px_max_warning_message) |
101 | 0 | return 1; |
102 | 29 | if (!save_all && word_end) { /* Delete any existing message of the same type. */ |
103 | | /* (There is at most one.) */ |
104 | 26 | uint word_len = word_end - message; |
105 | | |
106 | 26 | char *next = pxs->warnings; |
107 | | |
108 | 26 | uint len1; |
109 | | |
110 | 26 | for (; next != str; next += len1) { |
111 | 0 | len1 = strlen(next) + 1; |
112 | 0 | if (len1 > word_len && !strncmp(next, message, word_len)) { /* Delete the old message. */ |
113 | 0 | memmove(next, next + len1, str - (next + len1)); |
114 | 0 | str -= len1; |
115 | 0 | break; |
116 | 0 | } |
117 | 0 | } |
118 | 26 | } |
119 | 29 | strcpy(str, message); |
120 | 29 | pxs->warning_length = str + strlen(str) + 1 - pxs->warnings; |
121 | 29 | return 0; |
122 | 29 | } |
123 | | |
124 | | /* Generate a line of an error message starting at internal position N; */ |
125 | | /* return an updated value of N. When done, return -1. */ |
126 | | int |
127 | | px_error_message_line(char message[px_max_error_line + 1], int N, |
128 | | const char *subsystem, int code, |
129 | | const px_parser_state_t * st, const px_state_t * pxs) |
130 | 14.4k | { |
131 | 14.4k | if (N == 0) { |
132 | 2.40k | strcpy(message, "PCL XL error\n"); |
133 | 2.40k | return 1; |
134 | 2.40k | } |
135 | 12.0k | if (code == errorWarningsReported) { |
136 | | /* |
137 | | * Generate a line of warnings. |
138 | | * 1 = first line, otherwise N = position in warnings buffer. |
139 | | */ |
140 | 0 | switch (N) { |
141 | 0 | case 1: |
142 | 0 | N = 0; |
143 | | /* falls through */ |
144 | 0 | default: |
145 | 0 | if (N == pxs->warning_length) |
146 | 0 | return -1; |
147 | 0 | { |
148 | 0 | const char *str = pxs->warnings + N; |
149 | |
|
150 | 0 | uint len = strlen(str); |
151 | |
|
152 | 0 | uint warn_len; |
153 | |
|
154 | 0 | strcpy(message, " Warning: "); |
155 | 0 | warn_len = strlen(message) + 1; |
156 | 0 | if (len > px_max_error_line - warn_len) { |
157 | 0 | strncat(message, str, px_max_error_line - warn_len); |
158 | 0 | message[px_max_error_line - 1] = 0; |
159 | 0 | } else |
160 | 0 | strcat(message, str); |
161 | 0 | strcat(message, "\n"); |
162 | 0 | return N + len + 1; |
163 | 0 | } |
164 | 0 | } |
165 | 12.0k | } else { /* Generate the N'th line of an error message. */ |
166 | 12.0k | char *end; |
167 | | |
168 | 12.0k | switch (N) { |
169 | 2.40k | case 1: |
170 | 2.40k | gs_snprintf(message, px_max_error_line, " Subsystem: %s\n", subsystem); |
171 | 2.40k | break; |
172 | 2.40k | case 2: |
173 | 2.40k | strcpy(message, " Error: "); |
174 | 2.40k | { |
175 | 2.40k | char *end = message + strlen(message); |
176 | | |
177 | 2.40k | if (pxs->error_line[0]) { /* Ignore the error code, use the error line. */ |
178 | 0 | int len = strlen(pxs->error_line); |
179 | |
|
180 | 0 | int max_len = px_max_error_line - 2 - strlen(message); |
181 | |
|
182 | 0 | if (len <= max_len) |
183 | 0 | strcpy(end, pxs->error_line); |
184 | 0 | else { |
185 | 0 | strncpy(end, pxs->error_line, max_len); |
186 | 0 | message[px_max_error_line - 1] = 0; |
187 | 0 | } |
188 | 0 | strcat(end, "\n"); |
189 | 2.40k | } else if (code >= px_error_first && code < px_error_next) |
190 | 2.37k | gs_snprintf(end, px_max_error_line - strlen(message), "%s\n", |
191 | 2.37k | px_error_names[code - px_error_first]); |
192 | 26 | else |
193 | 26 | gs_snprintf(end, px_max_error_line - strlen(message), "Internal error 0x%x\n", code); |
194 | 2.40k | } |
195 | 2.40k | break; |
196 | 2.40k | case 3: |
197 | 2.40k | { |
198 | 2.40k | int last_operator = st->last_operator; |
199 | | |
200 | 2.40k | const char *oname; |
201 | | |
202 | 2.40k | strcpy(message, " Operator: "); |
203 | 2.40k | end = message + strlen(message); |
204 | 2.40k | if (last_operator >= 0x40 && last_operator < 0xc0 && |
205 | 1.31k | (oname = |
206 | 1.31k | px_operator_names[last_operator - 0x40]) != 0) |
207 | 1.07k | gs_snprintf(end, px_max_error_line - strlen(message), "%s\n", oname); |
208 | 1.32k | else |
209 | 1.32k | gs_snprintf(end, px_max_error_line - strlen(message), "0x%02x\n", last_operator); |
210 | 2.40k | } |
211 | 2.40k | break; |
212 | 2.40k | case 4: |
213 | 2.40k | strcpy(message, " Position: "); |
214 | 2.40k | end = message + strlen(message); |
215 | 2.40k | if (st->parent_operator_count) |
216 | 0 | gs_snprintf(end, px_max_error_line - strlen(message), "%ld;%ld\n", st->parent_operator_count, |
217 | 0 | st->operator_count); |
218 | 2.40k | else |
219 | 2.40k | gs_snprintf(end, px_max_error_line - strlen(message), "%ld\n", st->operator_count); |
220 | 2.40k | break; |
221 | 2.40k | default: |
222 | 2.40k | return -1; |
223 | 12.0k | } |
224 | 9.60k | return N + 1; |
225 | 12.0k | } |
226 | 12.0k | } |
227 | | |
228 | | /* Begin an error page. Return the initial Y value. */ |
229 | | int |
230 | | px_begin_error_page(px_state_t * pxs, int* y) |
231 | 2.40k | { |
232 | 2.40k | int code; |
233 | | |
234 | 2.40k | gs_gstate *pgs = pxs->pgs; |
235 | | |
236 | 2.40k | code = gs_initgraphics(pgs); |
237 | 2.40k | if (code < 0) return code; |
238 | | |
239 | 2.40k | code = gs_erasepage(pgs); |
240 | 2.40k | if (code < 0) return code; |
241 | | /* Don't call pxSetPageDefaultCTM -- we don't want rotation or */ |
242 | | /* unusual Units of Measure -- but do invert the Y axis. */ |
243 | | /*pxSetPageDefaultCTM(NULL, pxs); */ |
244 | 2.40k | { |
245 | 2.40k | gs_point pt; |
246 | | |
247 | 2.40k | px_get_default_media_size(pxs, &pt); |
248 | 2.40k | gs_translate(pgs, 0.0, pt.y); |
249 | 2.40k | gs_scale(pgs, 1.0, -1.0); |
250 | 2.40k | *y = 90; |
251 | 2.40k | } |
252 | 2.40k | return 0; |
253 | 2.40k | } |
254 | | |
255 | | /* Print a message on an error page. */ |
256 | | /* Return the updated Y value. */ |
257 | | int |
258 | | px_error_page_show(const char *message, int ytop, px_state_t * pxs) |
259 | 12.0k | { |
260 | 12.0k | gs_gstate *pgs = pxs->pgs; |
261 | 12.0k | int y = ytop; |
262 | 12.0k | const char *m = message; |
263 | 12.0k | const char *p; |
264 | 12.0k | gs_text_enum_t *penum; |
265 | 12.0k | gs_text_params_t text; |
266 | 12.0k | int code; |
267 | | |
268 | | /* Normalize for a 10-point font. */ |
269 | 24.0k | #define point_size 10.0 |
270 | 12.0k | double scale = 72.0 / px_bitmap_font_resolution * |
271 | 12.0k | point_size / px_bitmap_font_point_size; |
272 | 12.0k | px_font_t *pxfont = px_error_setfont(pxs); |
273 | | |
274 | 12.0k | if (pxfont == NULL) |
275 | 0 | return_error(errorInsufficientMemory); |
276 | | |
277 | 12.0k | text.operation = TEXT_FROM_STRING | TEXT_DO_DRAW | TEXT_RETURN_WIDTH; |
278 | | /* Peel off the next line and display it. */ |
279 | 12.0k | for (p = m;; m = ++p) { |
280 | 266k | while (*p != 0 && *p != '\n') |
281 | 254k | ++p; |
282 | 12.0k | gs_moveto(pgs, 36.0, y); |
283 | 12.0k | gs_scale(pgs, scale, scale); |
284 | 12.0k | text.data.chars = (gs_char *) m; |
285 | 12.0k | text.size = p - m; |
286 | 12.0k | code = gs_text_begin(pgs, &text, pxs->memory, &penum); |
287 | 12.0k | if (code >= 0) { |
288 | 12.0k | code = gs_text_process(penum); |
289 | 12.0k | if (code > 0) |
290 | 0 | code = gs_note_error(errorBadFontData); /* shouldn't happen! */ |
291 | 12.0k | if (code >= 0) { |
292 | 12.0k | gs_text_release(pgs, penum, "pxtext"); |
293 | 12.0k | } |
294 | 12.0k | } |
295 | 12.0k | gs_scale(pgs, 1 / scale, 1 / scale); |
296 | 12.0k | y += (int)(point_size * 8 / 5); |
297 | 12.0k | if (code < 0) |
298 | 0 | break; |
299 | 12.0k | if (!*p || !p[1]) |
300 | 12.0k | break; |
301 | 12.0k | } |
302 | 12.0k | pl_free_font(pxs->memory, pxfont, "px_error_page_show"); |
303 | 12.0k | return (code < 0 ? code : y); |
304 | 12.0k | } |
305 | | |
306 | | /* Reset the warning table. */ |
307 | | void |
308 | | px_reset_errors(px_state_t * pxs) |
309 | 6.98k | { |
310 | 6.98k | pxs->error_line[0] = 0; |
311 | 6.98k | pxs->warning_length = 0; |
312 | 6.98k | } |
313 | | |
314 | | /* ---------------- Error names ---------------- */ |
315 | | |
316 | | #undef pxerrors_INCLUDED |
317 | | #define INCLUDE_ERROR_NAMES |
318 | | #include "pxerrors.h" |
319 | | #undef INCLUDE_ERROR_NAMES |