Coverage Report

Created: 2026-02-14 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/base/sstring.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
/* String and hexstring streams (filters) */
18
#include "stdio_.h"   /* includes std.h */
19
#include "memory_.h"
20
#include "string_.h"
21
#include "strimpl.h"
22
#include "sstring.h"
23
#include "scanchar.h"
24
25
/* ------ ASCIIHexEncode ------ */
26
27
private_st_AXE_state();
28
29
/* Initialize the state */
30
static int
31
s_AXE_init(stream_state * st)
32
9.07k
{
33
9.07k
    stream_AXE_state *const ss = (stream_AXE_state *) st;
34
35
9.07k
    return s_AXE_init_inline(ss);
36
9.07k
}
37
38
/* Process a buffer */
39
static int
40
s_AXE_process(stream_state * st, stream_cursor_read * pr,
41
              stream_cursor_write * pw, bool last)
42
1.54M
{
43
1.54M
    stream_AXE_state *const ss = (stream_AXE_state *) st;
44
1.54M
    const byte *p = pr->ptr;
45
1.54M
    byte *q = pw->ptr;
46
1.54M
    int rcount = pr->limit - p;
47
1.54M
    int wcount = pw->limit - q;
48
1.54M
    int count;
49
1.54M
    int pos = ss->count;
50
1.54M
    const char *hex_digits = "0123456789ABCDEF";
51
1.54M
    int status = 0;
52
53
1.54M
    if (last && ss->EndOfData)
54
883k
        wcount--;   /* leave room for '>' */
55
1.54M
    wcount -= (wcount + pos * 2) / 64; /* leave room for \n */
56
1.54M
    wcount >>= 1;   /* 2 chars per input byte */
57
1.54M
    count = (wcount < rcount ? (status = 1, wcount) : rcount);
58
29.0M
    while (--count >= 0) {
59
27.5M
        *++q = hex_digits[*++p >> 4];
60
27.5M
        *++q = hex_digits[*p & 0xf];
61
27.5M
        if (!(++pos & 31) && (count != 0 || !last))
62
797k
            *++q = '\n';
63
27.5M
    }
64
1.54M
    if (last && status == 0 && ss->EndOfData)
65
882k
        *++q = '>';
66
1.54M
    pr->ptr = p;
67
1.54M
    pw->ptr = q;
68
1.54M
    ss->count = pos & 31;
69
1.54M
    return status;
70
1.54M
}
71
72
/* Stream template */
73
const stream_template s_AXE_template =
74
{&st_AXE_state, s_AXE_init, s_AXE_process, 1, 3
75
};
76
77
/* ------ ASCIIHexDecode ------ */
78
79
private_st_AXD_state();
80
81
/* Initialize the state */
82
static int
83
s_AXD_init(stream_state * st)
84
1.73k
{
85
1.73k
    stream_AXD_state *const ss = (stream_AXD_state *) st;
86
87
1.73k
    return s_AXD_init_inline(ss);
88
1.73k
}
89
90
/* Process a buffer */
91
static int
92
s_AXD_process(stream_state * st, stream_cursor_read * pr,
93
              stream_cursor_write * pw, bool last)
94
6.08M
{
95
6.08M
    stream_AXD_state *const ss = (stream_AXD_state *) st;
96
6.08M
    int code = s_hex_process(pr, pw, &ss->odd, hex_ignore_whitespace);
97
98
6.08M
    switch (code) {
99
10.3k
        case 0:
100
10.3k
            if (ss->odd >= 0 && last) {
101
405
                if (pw->ptr == pw->limit)
102
0
                    return 1;
103
405
                *++(pw->ptr) = ss->odd << 4;
104
405
                ss->odd = -1;
105
405
            }
106
            /* falls through */
107
12.9k
        case 1:
108
            /* We still need to read ahead and check for EOD. */
109
13.0k
            for (; pr->ptr < pr->limit; pr->ptr++)
110
2.44k
                if (scan_char_decoder[pr->ptr[1]] != ctype_space) {
111
2.37k
                    if (pr->ptr[1] == '>') {
112
0
                        pr->ptr++;
113
0
                        goto eod;
114
0
                    }
115
2.37k
                    return 1;
116
2.37k
                }
117
10.5k
            return 0;    /* still need to scan ahead */
118
0
        default:
119
0
            return code;
120
6.07M
        case ERRC:
121
6.07M
            ;
122
6.08M
    }
123
    /*
124
     * Check for EOD.  ERRC implies at least one more character
125
     * was read; we must unread it, since the caller might have
126
     * invoked the filter with exactly the right count to read all
127
     * the available data, and we might be reading past the end.
128
     */
129
6.07M
    if (*pr->ptr != '>') { /* EOD */
130
1.36k
        --(pr->ptr);
131
1.36k
        return ERRC;
132
1.36k
    }
133
6.06M
  eod:if (ss->odd >= 0) {
134
47.5k
        if (pw->ptr == pw->limit)
135
0
            return 1;
136
47.5k
        *++(pw->ptr) = ss->odd << 4;
137
47.5k
    }
138
6.06M
    return EOFC;
139
6.06M
}
140
141
/* Stream template */
142
const stream_template s_AXD_template =
143
{&st_AXD_state, s_AXD_init, s_AXD_process, 2, 1
144
};
145
146
/* ------ PSStringEncode ------ */
147
148
/* Process a buffer */
149
static int
150
s_PSSE_process(stream_state * st, stream_cursor_read * pr,
151
               stream_cursor_write * pw, bool last)
152
4.18M
{
153
4.18M
    const byte *p = pr->ptr;
154
4.18M
    const byte *rlimit = pr->limit;
155
4.18M
    byte *q = pw->ptr;
156
4.18M
    byte *wlimit = pw->limit;
157
4.18M
    int status = 0;
158
159
    /* This doesn't have to be very efficient. */
160
35.4M
    while (p < rlimit) {
161
31.3M
        int c = *++p;
162
163
31.3M
        if (c < 32 || c >= 127) {
164
13.1M
            const char *pesc;
165
13.1M
            const char *const esc = "\n\r\t\b\f";
166
167
13.1M
            if (c < 32 && c != 0 && (pesc = strchr(esc, c)) != 0) {
168
417k
                if (wlimit - q < 2) {
169
7.45k
                    --p;
170
7.45k
                    status = 1;
171
7.45k
                    break;
172
7.45k
                }
173
410k
                *++q = '\\';
174
410k
                *++q = "nrtbf"[pesc - esc];
175
410k
                continue;
176
417k
            }
177
12.7M
            if (wlimit - q < 4) {
178
141k
                --p;
179
141k
                status = 1;
180
141k
                break;
181
141k
            }
182
12.6M
            q[1] = '\\';
183
12.6M
            q[2] = (c >> 6) + '0';
184
12.6M
            q[3] = ((c >> 3) & 7) + '0';
185
12.6M
            q[4] = (c & 7) + '0';
186
12.6M
            q += 4;
187
12.6M
            continue;
188
18.2M
        } else if (c == '(' || c == ')' || c == '\\') {
189
1.17M
            if (wlimit - q < 2) {
190
3.58k
                --p;
191
3.58k
                status = 1;
192
3.58k
                break;
193
3.58k
            }
194
1.16M
            *++q = '\\';
195
17.0M
        } else {
196
17.0M
            if (q == wlimit) {
197
25.3k
                --p;
198
25.3k
                status = 1;
199
25.3k
                break;
200
25.3k
            }
201
17.0M
        }
202
18.2M
        *++q = c;
203
18.2M
    }
204
4.18M
    if (last && status == 0) {
205
2.10M
        if (q == wlimit)
206
840
            status = 1;
207
2.10M
        else
208
2.10M
            *++q = ')';
209
2.10M
    }
210
4.18M
    pr->ptr = p;
211
4.18M
    pw->ptr = q;
212
4.18M
    return status;
213
4.18M
}
214
215
/* Stream template */
216
const stream_template s_PSSE_template =
217
{&st_stream_state, NULL, s_PSSE_process, 1, 4
218
};
219
220
/* ------ PSStringDecode ------ */
221
222
private_st_PSSD_state();
223
224
/* Initialize the state */
225
int
226
s_PSSD_init(stream_state * st)
227
78.0k
{
228
78.0k
    stream_PSSD_state *const ss = (stream_PSSD_state *) st;
229
230
78.0k
    ss->from_string = false;
231
78.0k
    return s_PSSD_partially_init_inline(ss);
232
78.0k
}
233
234
/* Process a buffer */
235
static int
236
s_PSSD_process(stream_state * st, stream_cursor_read * pr,
237
               stream_cursor_write * pw, bool last)
238
194M
{
239
194M
    stream_PSSD_state *const ss = (stream_PSSD_state *) st;
240
194M
    const byte *p = pr->ptr;
241
194M
    const byte *rlimit = pr->limit;
242
194M
    byte *q = pw->ptr;
243
194M
    byte *wlimit = pw->limit;
244
194M
    int status = 0;
245
194M
    int c;
246
247
194M
#define check_p(n)\
248
194M
  if ( p == rlimit ) { p -= n; goto out; }
249
194M
#define check_q(n)\
250
2.91G
  if ( q == wlimit ) { p -= n; status = 1; goto out; }
251
3.11G
    while (p < rlimit) {
252
3.11G
        c = *++p;
253
3.11G
        if (c == '\\' && !ss->from_string) {
254
47.4M
            check_p(1);
255
47.4M
            switch ((c = *++p)) {
256
29.6M
                case 'n':
257
29.6M
                    c = '\n';
258
29.6M
                    goto put;
259
228k
                case 'r':
260
228k
                    c = '\r';
261
228k
                    goto put;
262
756k
                case 't':
263
756k
                    c = '\t';
264
756k
                    goto put;
265
8.64k
                case 'b':
266
8.64k
                    c = '\b';
267
8.64k
                    goto put;
268
286k
                case 'f':
269
286k
                    c = '\f';
270
286k
                    goto put;
271
10.4M
                default:  /* ignore the \ */
272
41.3M
                  put:check_q(2);
273
41.3M
                    *++q = c;
274
41.3M
                    continue;
275
568k
                case char_CR: /* ignore, check for following \n */
276
568k
                    check_p(2);
277
568k
                    if (p[1] == char_EOL)
278
32.2k
                        p++;
279
568k
                    continue;
280
228k
                case char_EOL: /* ignore */
281
228k
                    continue;
282
2.96M
                case '0':
283
4.12M
                case '1':
284
4.18M
                case '2':
285
5.30M
                case '3':
286
5.31M
                case '4':
287
5.31M
                case '5':
288
5.32M
                case '6':
289
5.33M
                case '7':
290
5.33M
                    {
291
5.33M
                        int d;
292
293
5.33M
                        check_p(2);
294
5.32M
                        d = p[1];
295
5.32M
                        c -= '0';
296
5.32M
                        if (d >= '0' && d <= '7') {
297
4.15M
                            if (p + 1 == rlimit) {
298
782
                                p -= 2;
299
782
                                goto out;
300
782
                            }
301
4.15M
                            check_q(2);
302
4.14M
                            c = (c << 3) + d - '0';
303
4.14M
                            d = p[2];
304
4.14M
                            if (d >= '0' && d <= '7') {
305
4.09M
                                c = (c << 3) + d - '0';
306
4.09M
                                p += 2;
307
4.09M
                            } else
308
52.6k
                                p++;
309
4.14M
                        } else
310
5.32M
                            check_q(2);
311
5.32M
                        *++q = c;
312
5.32M
                        continue;
313
5.32M
                    }
314
47.4M
            }
315
47.4M
        } else
316
3.06G
            switch (c) {
317
6.47M
                case '(':
318
6.47M
                    check_q(1);
319
6.47M
                    ss->depth++;
320
6.47M
                    break;
321
198M
                case ')':
322
198M
                    if (ss->depth == 0) {
323
194M
                        status = EOFC;
324
194M
                        goto out;
325
194M
                    }
326
4.00M
                    check_q(1);
327
4.00M
                    ss->depth--;
328
4.00M
                    break;
329
4.59M
                case char_CR: /* convert to \n */
330
4.59M
                    check_p(1);
331
4.59M
                    check_q(1);
332
4.59M
                    if (p[1] == char_EOL)
333
113k
                        p++;
334
4.59M
                    *++q = '\n';
335
4.59M
                    continue;
336
1.11M
                case char_EOL:
337
1.11M
                    c = '\n';
338
                    /* fall through */
339
2.85G
                default:
340
2.85G
                    check_q(1);
341
2.85G
                    break;
342
3.06G
            }
343
2.86G
        *++q = c;
344
2.86G
    }
345
85.2k
#undef check_p
346
85.2k
#undef check_q
347
194M
  out:pr->ptr = p;
348
194M
    pw->ptr = q;
349
194M
    if (last && status == 0 && p != rlimit)
350
1.03k
        status = ERRC;
351
194M
    return status;
352
194M
}
353
354
/* Stream template */
355
const stream_template s_PSSD_template =
356
{&st_PSSD_state, s_PSSD_init, s_PSSD_process, 4, 1
357
};
358
359
/* ------ Utilities ------ */
360
361
/*
362
 * Convert hex data to binary.
363
 * Return 1 if we filled the string,
364
 *        0 if we ran out of input data before filling the string,
365
 *        2 if hex_break_on_whitespace is on and we encounrered
366
 *          a white space.
367
 *        ERRC on error.
368
 * The caller must set *odd_digit to -1 before the first call;
369
 * after each call, if an odd number of hex digits has been read (total),
370
 * *odd_digit is the odd digit value, otherwise *odd_digit = -1.
371
 * See strimpl.h for the definition of syntax.
372
 */
373
int
374
s_hex_process(stream_cursor_read * pr, stream_cursor_write * pw,
375
              int *odd_digit, hex_syntax syntax)
376
35.2M
{
377
35.2M
    const byte *p = pr->ptr;
378
35.2M
    const byte *rlimit = pr->limit;
379
35.2M
    byte *q = pw->ptr;
380
35.2M
    byte *wlimit = pw->limit;
381
35.2M
    byte *q0 = q;
382
35.2M
    byte val1 = (byte) * odd_digit;
383
35.2M
    byte val2;
384
35.2M
    uint rcount;
385
35.2M
    byte *flimit;
386
35.2M
    const byte *const decoder = scan_char_decoder;
387
35.2M
    int code = 0;
388
389
35.2M
    if (q >= wlimit)
390
2.01k
        return 1;
391
35.2M
    if (val1 <= 0xf)
392
32.5k
        goto d2;
393
36.0M
    do {
394
        /* No digits read */
395
36.0M
        if ((rcount = (rlimit - p) >> 1) != 0)
396
35.9M
        {
397
            /* Set up a fast end-of-loop check, so we don't have to test */
398
            /* both p and q against their respective limits. */
399
35.9M
            flimit = (rcount < wlimit - q ? q + rcount : wlimit);
400
197M
            while (1) {
401
197M
                if ((val1 = decoder[p[1]]) <= 0xf &&
402
190M
                    (val2 = decoder[p[2]]) <= 0xf) {
403
190M
                    p += 2;
404
190M
                    *++q = (val1 << 4) + val2;
405
190M
                    if (q < flimit)
406
161M
                        continue;
407
29.0M
                    if (q >= wlimit)
408
43.2k
                        goto px;
409
29.0M
                }
410
35.9M
                break;
411
197M
            }
412
35.9M
        }
413
        /* About to read the first digit */
414
40.3M
        while (1) {
415
40.3M
            if (p >= rlimit)
416
28.9M
                goto end1;
417
11.4M
            if ((val1 = decoder[*++p]) > 0xf) {
418
10.4M
                if (val1 == ctype_space) {
419
1.17M
                    switch (syntax) {
420
317k
                        case hex_ignore_garbage:
421
1.10M
                        case hex_ignore_whitespace:
422
1.10M
                            continue;
423
62.6k
                        case hex_ignore_leading_whitespace:
424
62.6k
                            if (q == q0 && *odd_digit < 0)
425
38.6k
                                continue;
426
                            /* pass through */
427
34.9k
                        case hex_break_on_whitespace:
428
34.9k
                            --p;
429
34.9k
                            code = 2;
430
34.9k
                            goto end1;
431
1.17M
                    }
432
9.25M
                } else if (syntax == hex_ignore_garbage)
433
3.21M
                    continue;
434
6.03M
                code = ERRC;
435
6.03M
                goto end1;
436
10.4M
            }
437
978k
            break;
438
11.4M
        }
439
1.01M
  d2:
440
        /* About to read the second hex digit of a pair */
441
4.41M
        while (1) {
442
4.41M
            if (p >= rlimit) {
443
103k
                *odd_digit = val1;
444
103k
                goto ended;
445
103k
            }
446
4.30M
            if ((val2 = decoder[*++p]) > 0xf) {
447
3.47M
                if (val2 == ctype_space)
448
483k
                    switch (syntax) {
449
286k
                        case hex_ignore_garbage:
450
441k
                        case hex_ignore_whitespace:
451
441k
                            continue;
452
33.0k
                        case hex_ignore_leading_whitespace:
453
33.0k
                            if (q == q0)
454
25.6k
                                continue;
455
                            /* pass through */
456
16.0k
                        case hex_break_on_whitespace:
457
16.0k
                            --p;
458
16.0k
                            *odd_digit = val1;
459
16.0k
                            code = 2;
460
16.0k
                            goto ended;
461
483k
                    }
462
2.99M
                if (syntax == hex_ignore_garbage)
463
2.93M
                    continue;
464
59.9k
                *odd_digit = val1;
465
59.9k
                code = ERRC;
466
59.9k
                goto ended;
467
2.99M
            }
468
832k
            break;
469
4.30M
        }
470
832k
        *++q = (val1 << 4) + val2;
471
832k
    } while (q < wlimit);
472
43.3k
  px:code = 1;
473
35.0M
  end1:*odd_digit = -1;
474
35.2M
  ended:pr->ptr = p;
475
35.2M
    pw->ptr = q;
476
35.2M
    return code;
477
35.0M
}