Coverage Report

Created: 2026-04-01 07:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/pcl/pxl/pxstream.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
/* pxstream.c */
18
/* PCL XL user-defined stream operators */
19
20
#include "memory_.h"
21
#include "gsmemory.h"
22
#include "scommon.h"
23
#include "pxoper.h"
24
#include "pxstate.h"
25
#include "pxparse.h"
26
#include "pxptable.h"
27
28
/* ---------------- Internal procedures ---------------- */
29
30
/* Tag a stream name with its character width. */
31
static int
32
tag_stream_name(const px_value_t * psnv, gs_string * pstr,
33
                gs_memory_t * mem, client_name_t cname)
34
0
{
35
0
    uint size = array_value_size(psnv);
36
0
    byte *str = gs_alloc_string(mem, size + 1, cname);
37
38
0
    if (str == 0)
39
0
        return_error(errorInsufficientMemory);
40
0
    str[0] = value_size(psnv);
41
0
    memcpy(str + 1, psnv->value.array.data, size);
42
0
    pstr->data = str;
43
0
    pstr->size = size + 1;
44
0
    return 0;
45
0
}
46
47
/* ---------------- Operators ---------------- */
48
49
const byte apxBeginStream[] = {
50
    pxaStreamName, 0, 0
51
};
52
int
53
pxBeginStream(px_args_t * par, px_state_t * pxs)
54
0
{
55
0
    int code = tag_stream_name(par->pv[0], &pxs->stream_name, pxs->memory,
56
0
                               "pxBeginStream(name)");
57
58
0
    if (code < 0)
59
0
        return code;
60
0
    pxs->stream_def.size = 0;
61
0
    pl_dict_undef(&pxs->stream_dict, pxs->stream_name.data,
62
0
                  pxs->stream_name.size);
63
0
    return 0;
64
0
}
65
66
const byte apxReadStream[] = {
67
    pxaStreamDataLength, 0, 0
68
};
69
int
70
pxReadStream(px_args_t * par, px_state_t * pxs)
71
0
{
72
0
    ulong len = par->pv[0]->value.i;
73
0
    ulong copy = min(len - par->source.position, par->source.available);
74
0
    uint old_size = pxs->stream_def.size;
75
0
    byte *str;
76
77
0
    if (copy == 0)
78
0
        return pxNeedData;
79
0
    if (old_size == 0)
80
0
        str = gs_alloc_bytes(pxs->memory, copy, "pxReadStream");
81
0
    else
82
0
        str = gs_resize_object(pxs->memory, pxs->stream_def.data,
83
0
                               old_size + copy, "pxReadStream");
84
0
    if (str == 0)
85
0
        return_error(errorInsufficientMemory);
86
0
    memcpy(str + old_size, par->source.data, copy);
87
0
    pxs->stream_def.data = str;
88
0
    pxs->stream_def.size = old_size + copy;
89
0
    par->source.data += copy;
90
0
    par->source.available -= copy;
91
0
    return ((par->source.position += copy) == len ? 0 : pxNeedData);
92
0
}
93
94
const byte apxEndStream[] = { 0, 0 };
95
int
96
pxEndStream(px_args_t * par, px_state_t * pxs)
97
0
{
98
0
    int code = pl_dict_put(&pxs->stream_dict, pxs->stream_name.data,
99
0
                           pxs->stream_name.size, pxs->stream_def.data);
100
101
0
    gs_free_string(pxs->memory, pxs->stream_name.data,
102
0
                   pxs->stream_name.size, "pxEndStream(name)");
103
0
    return (code < 0 ? gs_note_error(errorInsufficientMemory) : 0);
104
0
}
105
106
const byte apxRemoveStream[] = {
107
    pxaStreamName, 0, 0
108
};
109
110
int
111
pxRemoveStream(px_args_t * par, px_state_t * pxs)
112
0
{
113
0
    gs_string str;
114
0
    void *def;
115
116
0
    int code = tag_stream_name(par->pv[0], &str, pxs->memory,
117
0
                               "pxExecStream(name)");
118
119
0
    if (code < 0)
120
0
        return code;
121
0
    {
122
0
        bool found = pl_dict_find(&pxs->stream_dict, str.data, str.size,
123
0
                                  &def);
124
125
0
        if (!found)
126
0
            return_error(errorStreamUndefined);
127
0
        pl_dict_undef(&pxs->stream_dict, str.data, str.size);
128
0
        gs_free_string(pxs->memory, str.data, str.size,
129
0
                       "pxRemoveStream(name)");
130
0
    }
131
0
    return 0;
132
0
}
133
134
const byte apxExecStream[] = {
135
    pxaStreamName, 0, 0
136
};
137
int
138
pxExecStream(px_args_t * par, px_state_t * pxs)
139
0
{
140
0
    gs_string str;
141
0
    void *def;
142
0
    const byte *def_data;
143
0
    uint def_size;
144
0
    bool big_endian;
145
0
    const byte *start;
146
0
    px_parser_state_t *pst = par->parser;
147
0
    px_parser_state_t st;
148
0
    stream_cursor_read r;
149
150
0
    int code = tag_stream_name(par->pv[0], &str, pxs->memory,
151
0
                               "pxExecStream(name)");
152
153
0
    if (code < 0)
154
0
        return code;
155
156
0
    if (pxs->stream_level > 32)
157
0
        return_error(errorStreamNestingFull);
158
159
0
    {
160
0
        bool found = pl_dict_find(&pxs->stream_dict, str.data, str.size,
161
0
                                  &def);
162
163
0
        gs_free_string(pxs->memory, str.data, str.size, "pxExecStream(name)");
164
0
        if (!found)
165
0
            return_error(errorStreamUndefined);
166
0
    }
167
0
    def_data = def;
168
0
    def_size = gs_object_size(pxs->memory, def);
169
    /* We do all the syntax checking for streams here, rather than */
170
    /* in ReadStream or EndStream, for simplicity. */
171
0
    switch (def_data[0]) {
172
0
        case '(':
173
0
            big_endian = true;
174
0
            break;
175
0
        case ')':
176
0
            big_endian = false;
177
0
            break;
178
0
        default:
179
0
            return_error(errorUnsupportedBinding);
180
0
    }
181
0
    if (def_size < 16 || strncmp((const char *)def_data + 1, " HP-PCL XL", 10)
182
0
        )
183
0
        return_error(errorUnsupportedClassName);
184
    /* support protocol level 1, 2 and 3 */
185
0
    if (strncmp((const char *)def_data + 11, ";1;", 3) &&
186
0
        strncmp((const char *)def_data + 11, ";2;", 3) &&
187
0
        strncmp((const char *)def_data + 11, ";3;", 3))
188
0
        return_error(errorUnsupportedProtocol);
189
0
    start = memchr(def_data + 14, '\n', def_size - 14);
190
0
    if (!start)
191
0
        return_error(errorIllegalStreamHeader);
192
0
    st.memory = pxs->memory;
193
0
    px_process_init(&st, big_endian);
194
0
    st.macro_state = pst->macro_state | ptsExecStream;
195
0
    st.last_operator = pst->last_operator;
196
0
    r.ptr = start;
197
0
    r.limit = def_data + def_size - 1;
198
0
    pxs->stream_level++;
199
0
    code = px_process(&st, pxs, &r);
200
0
    pxs->stream_level--;
201
0
    pst->macro_state = st.macro_state & ~ptsExecStream;
202
0
    if (code < 0) {             /* Set the operator counts for error reporting. */
203
0
        pst->parent_operator_count = pst->operator_count;
204
0
        pst->operator_count = st.operator_count;
205
0
        pst->last_operator = st.last_operator;
206
0
    }
207
0
    return code;
208
0
}