Coverage Report

Created: 2025-06-10 07:24

/src/ghostpdl/base/sa85d.c
Line
Count
Source (jump to first uncovered line)
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
/* ASCII85Decode filter */
18
#include "std.h"
19
#include "strimpl.h"
20
#include "sa85d.h"
21
#include "scanchar.h"
22
23
/* ------ ASCII85Decode ------ */
24
25
private_st_A85D_state();
26
27
/* Initialize the state */
28
static int
29
s_A85D_init(stream_state * st)
30
74
{
31
74
    stream_A85D_state *const ss = (stream_A85D_state *) st;
32
33
74
    s_A85D_init_inline(ss);
34
74
    return 0;
35
74
}
36
37
/* Process a buffer */
38
static int a85d_finish(int, ulong, stream_cursor_write *);
39
static int
40
s_A85D_process(stream_state * st, stream_cursor_read * pr,
41
               stream_cursor_write * pw, bool last)
42
35.9k
{
43
35.9k
    stream_A85D_state *const ss = (stream_A85D_state *) st;
44
35.9k
    register const byte *p = pr->ptr;
45
35.9k
    register byte *q = pw->ptr;
46
    /* stop processing early unless the target is empty (last == true)  */
47
    /* to make sure we consume the EOD marker correctly. The EOD marker */
48
    /* might be as many as 6 characters after the last valid data char  */
49
    /* D <cr> <lf> '~' <cr> <lf> '>' where 'D' is a data character.     */
50
35.9k
    const byte *rlimit = pr->limit - (last ? 0 : 7); /* max EOD len + 1 */
51
35.9k
    const byte *r = max(p, rlimit);
52
35.9k
    byte *wlimit = pw->limit;
53
35.9k
    int ccount = ss->odd;
54
35.9k
    ulong word = ss->word;
55
35.9k
    int status = 0;
56
57
    /* scan to make sure that an EOD isn't fully contained in the */
58
    /* last part of the buffer (between rlimit and pr->limit).    */
59
75.2k
    while (r < pr->limit) {
60
39.2k
        if (*++r == '~')
61
247k
            while (r < pr->limit)
62
211k
                if (*++r == '>') {
63
                    /* we have both characters of a complete EOD. */
64
3
                    rlimit = pr->limit; /* go ahead and process everything */
65
3
                    r = rlimit;   /* break out of the while loops */
66
3
                    break;
67
3
                }
68
39.2k
    }
69
403k
    while (p < rlimit) {
70
403k
        int ch = *++p;
71
403k
        uint ccode = ch - '!';
72
73
403k
        if (ccode < 85) { /* catches ch < '!' as well */
74
366k
            if (ccount == 4) {
75
                /*
76
                 * We've completed a 32-bit group.  Make sure we have
77
                 * room for it in the output.
78
                 */
79
73.4k
                if (wlimit - q < 4) {
80
120
                    p--;
81
120
                    status = 1;
82
120
                    break;
83
120
                }
84
                /* Check for overflow condition, throw ioerror if so */
85
73.3k
                if (word >= 0x03030303 && ccode > 0) {
86
17
                    status = ERRC;
87
17
                    break;
88
17
                }
89
73.2k
                word = word * 85 + ccode;
90
73.2k
                q[1] = (byte) (word >> 24);
91
73.2k
                q[2] = (byte) (word >> 16);
92
73.2k
                q[3] = (byte) ((uint) word >> 8);
93
73.2k
                q[4] = (byte) word;
94
73.2k
                q += 4;
95
73.2k
                word = 0;
96
73.2k
                ccount = 0;
97
293k
            } else {
98
293k
                word = word * 85 + ccode;
99
293k
                ++ccount;
100
293k
            }
101
366k
        } else if (ch == 'z' && ccount == 0) {
102
39
            if (wlimit - q < 4) {
103
0
                p--;
104
0
                status = 1;
105
0
                break;
106
0
            }
107
39
            q[1] = q[2] = q[3] = q[4] = 0,
108
39
                q += 4;
109
36.5k
        } else if (scan_char_decoder[ch] == ctype_space)
110
36.5k
            DO_NOTHING;
111
35.5k
        else if (ch == '~') {
112
35.5k
            int i = 1;
113
114
35.5k
            rlimit = pr->limit;   /* Here we use the real "limit" */
115
            /* Handle odd bytes. */
116
35.5k
            if (p == rlimit) {
117
1
                if (!last)
118
0
                  p--;
119
1
                else if (ss->pdf_rules)
120
0
                  goto finish;
121
1
                else
122
1
                    status = ERRC;
123
1
                break;
124
1
            }
125
35.5k
            if ((int)(wlimit - q) < ccount - 1) {
126
9
                status = 1;
127
9
                p--;
128
9
                break;
129
9
            }
130
131
            /* According to PLRM 3rd, if the A85 filter encounters '~',
132
             * the next character must be '>'.
133
             * And any other characters should raise an ioerror.
134
             * But Adobe Acrobat allows CR/LF between ~ and >.
135
             * So we allow CR/LF between them. */
136
            /* PDF further relaxes the requirements and accepts bare '~'.
137
             */
138
35.5k
            while ((p + i <= rlimit) && (p[i] == 13 || p[i] == 10))
139
35
                i++;
140
35.5k
            if (p + i <= rlimit && p[i] != '>') {
141
35.5k
                if (ss->pdf_rules) {
142
0
                    if (p[i] == 13 || p[i] == 10) {
143
0
                        if (!last)
144
0
                            break;
145
0
                    } else {
146
0
                        p--;
147
0
                    }
148
35.5k
                } else {
149
35.5k
                    if (p + i == rlimit) {
150
1
                        if (last)
151
1
                            status = ERRC;
152
0
                        else
153
0
                            p--; /* we'll see the '~' after filling the buffer */
154
1
                    }
155
35.5k
                    break;
156
35.5k
                }
157
35.5k
            }
158
20
          finish:
159
20
            if (p + i <= rlimit)
160
18
                p += i;    /* advance to the '>' */
161
2
            else
162
2
                p = rlimit; /* Can happen if the '>' is missing */
163
20
            pw->ptr = q;
164
20
            status = a85d_finish(ccount, word, pw);
165
20
            q = pw->ptr;
166
20
            break;
167
35.5k
        } else {   /* syntax error or exception */
168
50
            status = ERRC;
169
50
            break;
170
50
        }
171
403k
    }
172
35.9k
    pw->ptr = q;
173
35.9k
    if (status == 0 && last) {
174
30
        if ((int)(wlimit - q) < ccount - 1)
175
0
            status = 1;
176
30
        else if (ss->require_eod)
177
29
            status = ERRC;
178
1
        else
179
1
            status = a85d_finish(ccount, word, pw);
180
30
    }
181
35.9k
    pr->ptr = p;
182
35.9k
    ss->odd = ccount;
183
35.9k
    ss->word = word;
184
35.9k
    return status;
185
35.9k
}
186
/* Handle the end of input data. */
187
static int
188
a85d_finish(int ccount, ulong word, stream_cursor_write * pw)
189
21
{
190
    /* Assume there is enough room in the output buffer! */
191
21
    byte *q = pw->ptr;
192
21
    int status = EOFC;
193
194
21
    switch (ccount) {
195
4
        case 0:
196
4
            break;
197
1
        case 1:   /* syntax error */
198
1
            status = ERRC;
199
1
            break;
200
5
        case 2:   /* 1 odd byte */
201
5
            word = word * (85L * 85 * 85) + 85L * 85 * 85 - 1L;
202
5
            goto o1;
203
6
        case 3:   /* 2 odd bytes */
204
6
            word = word * (85L * 85) + 85L * 85L - 1L;
205
6
            goto o2;
206
5
        case 4:   /* 3 odd bytes */
207
5
            word = word * 85L + 84L;
208
5
            q[3] = (byte) (word >> 8);
209
11
o2:     q[2] = (byte) (word >> 16);
210
16
o1:     q[1] = (byte) (word >> 24);
211
16
            q += ccount - 1;
212
16
            pw->ptr = q;
213
21
    }
214
21
    return status;
215
21
}
216
217
/* Stream template */
218
const stream_template s_A85D_template = {
219
    &st_A85D_state, s_A85D_init, s_A85D_process, 2, 4
220
};