Coverage Report

Created: 2026-04-01 07:17

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-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