Coverage Report

Created: 2026-10-28 08:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/pcl/pxl/pxerrors.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
/* 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
19.2k
{
51
19.2k
    int code;
52
53
19.2k
    px_font_t *pxfont = pl_alloc_font(pxs->memory, "px_error_setfont");
54
55
19.2k
    if (pxfont == 0)
56
0
        return NULL;
57
58
19.2k
    pxfont->storage = pxfsInternal;
59
19.2k
    pxfont->font_type = plft_Unicode;   /* as good as any */
60
19.2k
    pxfont->data_are_permanent = true;
61
19.2k
    code = px_define_font(pxfont, (byte *) px_bitmap_font_header,
62
19.2k
                          px_bitmap_font_header_size,
63
19.2k
                          gs_next_ids(pxs->memory, 1), pxs);
64
19.2k
    {
65
19.2k
        const byte *cdatanext, *cdata = px_bitmap_font_char_data;
66
67
1.40M
        while (*cdata && code >= 0) {
68
1.38M
           cdatanext = cdata + 16 +
69
1.38M
                ((uint16at(cdata + 11, true) + 7) >> 3) *
70
1.38M
                uint16at(cdata + 13, true) + 1; /* add one to clear the char code */
71
72
1.38M
            code = pl_font_add_glyph(pxfont, *cdata, cdata + 1, (int)(cdatanext - cdata - 2));
73
1.38M
            cdata = cdatanext;
74
1.38M
        }
75
19.2k
    }
76
19.2k
    if (code < 0) {
77
0
        pl_free_font(pxs->memory, pxfont, "px_error_setfont");
78
0
        return NULL;
79
0
    }
80
19.2k
    gs_setfont(pxs->pgs, pxfont->pfont);
81
19.2k
    pxfont->pfont->FontMatrix = pxfont->pfont->orig_FontMatrix;
82
19.2k
    return pxfont;
83
19.2k
}
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
44
{
94
44
    uint end = pxs->warning_length;
95
96
44
    char *str = pxs->warnings + end;
97
98
44
    const char *word_end = strchr(message, ' ');
99
100
44
    if (end + strlen(message) + 1 > px_max_warning_message)
101
0
        return 1;
102
44
    if (!save_all && word_end) {        /* Delete any existing message of the same type. */
103
        /* (There is at most one.) */
104
37
        uint word_len = word_end - message;
105
106
37
        char *next = pxs->warnings;
107
108
37
        uint len1;
109
110
37
        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
37
    }
119
44
    strcpy(str, message);
120
44
    pxs->warning_length = str + strlen(str) + 1 - pxs->warnings;
121
44
    return 0;
122
44
}
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
23.0k
{
131
23.0k
    if (N == 0) {
132
3.84k
        strcpy(message, "PCL XL error\n");
133
3.84k
        return 1;
134
3.84k
    }
135
19.2k
    if (code == errorWarningsReported) {
136
        /*
137
         * Generate a line of warnings.
138
         * 1 = first line, otherwise N = position in warnings buffer.
139
         */
140
2
        switch (N) {
141
1
            case 1:
142
1
                N = 0;
143
                /* falls through */
144
2
            default:
145
2
                if (N == pxs->warning_length)
146
1
                    return -1;
147
1
                {
148
1
                    const char *str = pxs->warnings + N;
149
150
1
                    uint len = strlen(str);
151
152
1
                    uint warn_len;
153
154
1
                    strcpy(message, "    Warning:    ");
155
1
                    warn_len = strlen(message) + 1;
156
1
                    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
1
                        strcat(message, str);
161
1
                    strcat(message, "\n");
162
1
                    return N + len + 1;
163
2
                }
164
2
        }
165
19.2k
    } else {                    /* Generate the N'th line of an error message. */
166
19.2k
        char *end;
167
168
19.2k
        switch (N) {
169
3.84k
            case 1:
170
3.84k
                gs_snprintf(message, px_max_error_line, "    Subsystem:  %s\n", subsystem);
171
3.84k
                break;
172
3.84k
            case 2:
173
3.84k
                strcpy(message, "    Error:      ");
174
3.84k
                {
175
3.84k
                    char *end = message + strlen(message);
176
177
3.84k
                    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
3.84k
                    } else if (code >= px_error_first && code < px_error_next)
190
3.81k
                        gs_snprintf(end, px_max_error_line - strlen(message), "%s\n",
191
3.81k
                                px_error_names[code - px_error_first]);
192
33
                    else
193
33
                        gs_snprintf(end, px_max_error_line - strlen(message), "Internal error 0x%x\n", code);
194
3.84k
                }
195
3.84k
                break;
196
3.84k
            case 3:
197
3.84k
                {
198
3.84k
                    int last_operator = st->last_operator;
199
200
3.84k
                    const char *oname;
201
202
3.84k
                    strcpy(message, "    Operator:   ");
203
3.84k
                    end = message + strlen(message);
204
3.84k
                    if (last_operator >= 0x40 && last_operator < 0xc0 &&
205
1.88k
                        (oname =
206
1.88k
                         px_operator_names[last_operator - 0x40]) != 0)
207
1.54k
                        gs_snprintf(end, px_max_error_line - strlen(message), "%s\n", oname);
208
2.30k
                    else
209
2.30k
                        gs_snprintf(end, px_max_error_line - strlen(message), "0x%02x\n", last_operator);
210
3.84k
                }
211
3.84k
                break;
212
3.84k
            case 4:
213
3.84k
                strcpy(message, "    Position:   ");
214
3.84k
                end = message + strlen(message);
215
3.84k
                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
3.84k
                else
219
3.84k
                    gs_snprintf(end,  px_max_error_line - strlen(message), "%ld\n", st->operator_count);
220
3.84k
                break;
221
3.84k
            default:
222
3.84k
                return -1;
223
19.2k
        }
224
15.3k
        return N + 1;
225
19.2k
    }
226
19.2k
}
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
3.84k
{
232
3.84k
    int code;
233
234
3.84k
    gs_gstate *pgs = pxs->pgs;
235
236
3.84k
    code = gs_initgraphics(pgs);
237
3.84k
    if (code < 0)   return code;
238
239
3.84k
    code = gs_erasepage(pgs);
240
3.84k
    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
3.84k
    {
245
3.84k
        gs_point pt;
246
247
3.84k
        px_get_default_media_size(pxs, &pt);
248
3.84k
        gs_translate(pgs, 0.0, pt.y);
249
3.84k
        gs_scale(pgs, 1.0, -1.0);
250
3.84k
        *y = 90;
251
3.84k
    }
252
3.84k
    return 0;
253
3.84k
}
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
19.2k
{
260
19.2k
    gs_gstate *pgs = pxs->pgs;
261
19.2k
    int y = ytop;
262
19.2k
    const char *m = message;
263
19.2k
    const char *p;
264
19.2k
    gs_text_enum_t *penum;
265
19.2k
    gs_text_params_t text;
266
19.2k
    int code;
267
268
    /* Normalize for a 10-point font. */
269
38.4k
#define point_size 10.0
270
19.2k
    double scale = 72.0 / px_bitmap_font_resolution *
271
19.2k
        point_size / px_bitmap_font_point_size;
272
19.2k
    px_font_t *pxfont = px_error_setfont(pxs);
273
274
19.2k
    if (pxfont == NULL)
275
0
        return_error(errorInsufficientMemory);
276
277
19.2k
    text.operation = TEXT_FROM_STRING | TEXT_DO_DRAW | TEXT_RETURN_WIDTH;
278
    /* Peel off the next line and display it. */
279
19.2k
    for (p = m;; m = ++p) {
280
423k
        while (*p != 0 && *p != '\n')
281
404k
            ++p;
282
19.2k
        gs_moveto(pgs, 36.0, y);
283
19.2k
        gs_scale(pgs, scale, scale);
284
19.2k
        text.data.chars = (gs_char *) m;
285
19.2k
        text.size = p - m;
286
19.2k
        code = gs_text_begin(pgs, &text, pxs->memory, &penum);
287
19.2k
        if (code >= 0) {
288
19.2k
            code = gs_text_process(penum);
289
19.2k
            if (code > 0)
290
0
                code = gs_note_error(errorBadFontData); /* shouldn't happen! */
291
19.2k
            if (code >= 0) {
292
19.2k
                gs_text_release(pgs, penum, "pxtext");
293
19.2k
            }
294
19.2k
        }
295
19.2k
        gs_scale(pgs, 1 / scale, 1 / scale);
296
19.2k
        y += (int)(point_size * 8 / 5);
297
19.2k
        if (code < 0)
298
0
            break;
299
19.2k
        if (!*p || !p[1])
300
19.2k
            break;
301
19.2k
    }
302
19.2k
    pl_free_font(pxs->memory, pxfont, "px_error_page_show");
303
19.2k
    return (code < 0 ? code : y);
304
19.2k
}
305
306
/* Reset the warning table. */
307
void
308
px_reset_errors(px_state_t * pxs)
309
10.4k
{
310
10.4k
    pxs->error_line[0] = 0;
311
10.4k
    pxs->warning_length = 0;
312
10.4k
}
313
314
/* ---------------- Error names ---------------- */
315
316
#undef pxerrors_INCLUDED
317
#define INCLUDE_ERROR_NAMES
318
#include "pxerrors.h"
319
#undef INCLUDE_ERROR_NAMES