Coverage Report

Created: 2026-04-01 07:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/base/spwgd.c
Line
Count
Source
1
/* Copyright (C) 2017-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
/* PWGDecode filter */
18
#include "stdio_.h"   /* includes std.h */
19
#include "memory_.h"
20
#include "strimpl.h"
21
#include "spwgx.h"
22
#include "gxdevice.h"
23
#include "gserrors.h"
24
25
/* ------ RunLengthDecode ------ */
26
27
private_st_PWGD_state();
28
29
/* Set defaults */
30
static void
31
s_PWGD_set_defaults(stream_state * st)
32
0
{
33
0
    stream_PWGD_state *const ss = (stream_PWGD_state *) st;
34
35
0
    (ss)->bpp = PWG_default_bpp;
36
0
    (ss)->width = PWG_default_width;
37
0
}
38
39
/* Initialize */
40
static int
41
s_PWGD_init(stream_state * st)
42
0
{
43
0
    stream_PWGD_state *const ss = (stream_PWGD_state *) st;
44
45
0
    (ss)->line_pos = 0;
46
0
    (ss)->line_rep = 0;
47
0
    (ss)->state = 0;
48
0
    (ss)->line_buffer = NULL;
49
50
0
    return 0;
51
0
}
52
53
/* Refill the buffer */
54
static int
55
s_PWGD_process(stream_state * st, stream_cursor_read * pr,
56
               stream_cursor_write * pw, bool last)
57
0
{
58
0
    stream_PWGD_state *const ss = (stream_PWGD_state *) st;
59
0
    register const byte *p = pr->ptr;
60
0
    register byte *q = pw->ptr;
61
0
    const byte *rlimit = pr->limit;
62
0
    byte *wlimit = pw->limit;
63
0
    int bpp = (ss->bpp+7)>>3;
64
0
    int wb;
65
0
    int line_pos = ss->line_pos;
66
67
0
    if (check_int_multiply(ss->width, bpp, &wb) != 0)
68
0
        return gs_note_error(gs_error_undefinedresult);
69
70
0
    if (ss->width > max_int / bpp)
71
0
        return ERRC;
72
73
0
    if (ss->line_buffer == NULL) {
74
0
        ss->line_buffer =
75
0
                    gs_alloc_bytes_immovable(gs_memory_stable(ss->memory),
76
0
                                             wb,
77
0
                                             "s_PWGD_process(line_buffer)");
78
0
        if (ss->line_buffer == NULL)
79
0
            return ERRC;
80
0
    }
81
82
0
    while (1) {
83
0
        if (ss->state == 0) {
84
            /* Copy any buffered data out */
85
0
            if (ss->line_rep > 0) {
86
0
                int avail = wb - line_pos;
87
0
                if (avail > wlimit - q)
88
0
                    avail = wlimit - q;
89
0
                if (avail != 0)
90
0
                    memcpy(q+1, &ss->line_buffer[line_pos], avail);
91
0
                line_pos += avail;
92
0
                q += avail;
93
0
                if (line_pos == wb) {
94
0
                    line_pos = 0;
95
0
                    ss->line_rep--;
96
0
                }
97
0
                goto data_produced;
98
0
            }
99
            /* Now unpack data into the line buffer */
100
            /* Awaiting line repeat value */
101
0
            if (p == rlimit)
102
0
                goto need_data;
103
0
            ss->line_rep = (*++p) + 1;
104
0
            ss->state = 1; /* Wait for pixel repeat */
105
0
        }
106
0
        if (ss->state == 1) {
107
0
    int rep, next_state;
108
            /* Awaiting pixel repeat value */
109
0
            if (p == rlimit)
110
0
                goto need_data;
111
0
            rep = *++p;
112
0
            if (rep < 0x80) {
113
                /* Repeat the next pixel multiple times */
114
0
                next_state = (rep+1) * bpp + 1;
115
0
                if (line_pos + next_state - 1 > wb) {
116
                    /* Too many repeats for this line! */
117
0
                    p--;
118
0
                    goto error;
119
0
                }
120
0
            } else {
121
                /* Copy colors */
122
0
                next_state = -(257 - rep) * bpp;
123
0
                if (line_pos + -next_state > wb) {
124
                    /* Too many pixels for this line! */
125
0
                    p--;
126
0
                    goto error;
127
0
                }
128
0
            }
129
0
            ss->state = next_state;
130
0
        }
131
0
        if (ss->state > 1) {
132
            /* Repeating a single pixel */
133
0
            int pixel_pos = line_pos % bpp;
134
0
            int avail = bpp - pixel_pos;
135
0
            if (avail > rlimit - p)
136
0
                avail = rlimit - p;
137
0
            if (avail != 0)
138
0
                memcpy(&ss->line_buffer[line_pos], p+1, avail);
139
0
            p += avail;
140
0
            line_pos += avail;
141
0
            pixel_pos += avail;
142
0
            ss->state -= avail;
143
0
            if (pixel_pos != bpp)
144
0
                goto need_data;
145
0
            while (ss->state > 1) {
146
0
                memcpy(&ss->line_buffer[line_pos], &ss->line_buffer[line_pos - bpp], bpp);
147
0
                line_pos += bpp;
148
0
                ss->state -= bpp;
149
0
            }
150
0
            if (line_pos == wb) {
151
0
                line_pos = 0;
152
0
                ss->state = 0;
153
0
            } else
154
0
                ss->state = 1;
155
0
        }
156
0
        if (ss->state < 0) {
157
            /* Copying literals */
158
0
            int avail = -ss->state;
159
0
            if (avail > rlimit - p)
160
0
                avail = rlimit - p;
161
0
            memcpy(&ss->line_buffer[line_pos], p + 1, avail);
162
0
            p += avail;
163
0
            ss->state += avail;
164
0
            line_pos += avail;
165
0
            if (ss->state)
166
0
                goto need_data;
167
0
            ss->state = 1;
168
0
        }
169
0
    }
170
0
need_data:
171
0
    {
172
0
        int status = 0; /* Need input data */
173
0
        if (0) {
174
0
error:
175
0
            status = ERRC;
176
0
        } else if (0) {
177
0
data_produced:
178
0
            status = 1; /* Need output space */
179
0
        }
180
0
        pr->ptr = p;
181
0
        pw->ptr = q;
182
0
        ss->line_pos = line_pos;
183
0
        return status;
184
0
    }
185
0
}
186
187
static void
188
s_PWGD_release(stream_state * st)
189
0
{
190
0
    stream_PWGD_state *const ss = (stream_PWGD_state *) st;
191
192
0
    gs_free_object(st->memory, ss->line_buffer, "PWGD(close)");
193
    ss->line_buffer = NULL;
194
0
}
195
196
/* Stream template */
197
const stream_template s_PWGD_template = {
198
    &st_PWGD_state, s_PWGD_init, s_PWGD_process, 1, 1, s_PWGD_release,
199
    s_PWGD_set_defaults
200
};