Coverage Report

Created: 2025-06-10 07:24

/src/ghostpdl/psi/zfileio.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
/* File I/O operators */
18
#include "memory_.h"
19
#include "ghost.h"
20
#include "gp.h"
21
#include "oper.h"
22
#include "stream.h"
23
#include "files.h"
24
#include "store.h"
25
#include "strimpl.h"    /* for ifilter.h */
26
#include "ifilter.h"    /* for procedure streams */
27
#include "interp.h"   /* for gs_errorinfo_put_string */
28
#include "gsmatrix.h"   /* for gxdevice.h */
29
#include "gxdevice.h"
30
#include "gxdevmem.h"
31
#include "estack.h"
32
#include "gsstate.h"
33
34
/* Forward references */
35
static int write_string(ref *, stream *);
36
static int handle_read_status(i_ctx_t *, int, const ref *, const uint *,
37
                               op_proc_t);
38
static int handle_write_status(i_ctx_t *, int, const ref *, const uint *,
39
                                op_proc_t);
40
41
/* ------ Operators ------ */
42
43
/* <file> closefile - */
44
int
45
zclosefile(i_ctx_t *i_ctx_p)
46
141k
{
47
141k
    os_ptr op = osp;
48
141k
    stream *s;
49
50
141k
    check_op(1);
51
141k
    check_type(*op, t_file);
52
141k
    if (file_is_valid(s, op)) { /* closing a closed file is a no-op */
53
77.1k
        int status = sclose(s);
54
55
77.1k
        if (status != 0 && status != EOFC) {
56
9.70k
            if (s_is_writing(s))
57
9.70k
                return handle_write_status(i_ctx_p, status, op, NULL,
58
9.70k
                                           zclosefile);
59
0
            else
60
0
                return handle_read_status(i_ctx_p, status, op, NULL,
61
0
                                          zclosefile);
62
9.70k
        }
63
77.1k
    }
64
131k
    pop(1);
65
131k
    return 0;
66
141k
}
67
68
/* <file> read <int> -true- */
69
/* <file> read -false- */
70
static int
71
zread(i_ctx_t *i_ctx_p)
72
1.50M
{
73
1.50M
    os_ptr op = osp;
74
1.50M
    stream *s;
75
1.50M
    int ch;
76
77
1.50M
    check_op(1);
78
1.50M
    check_read_file(i_ctx_p, s, op);
79
    /* We 'push' first in case of ostack block overflow and the */
80
    /* usual case is we will need to push anyway. If we get EOF */
81
    /* we will need to 'pop' and decrement the 'op' pointer.    */
82
    /* This is required since the 'push' macro might return with*/
83
    /* stackoverflow which will result in another stack block   */
84
    /* added on, then the operator being retried. We can't read */
85
    /* (sgetc) prior to having a place on the ostack to return  */
86
    /* the character.           */
87
1.50M
    push(1);
88
1.50M
    ch = sgetc(s);
89
1.50M
    if (ch >= 0) {
90
1.50M
        make_int(op - 1, ch);
91
1.50M
        make_bool(op, 1);
92
1.50M
    } else {
93
6
        pop(1);    /* Adjust ostack back from preparatory 'pop' */
94
6
        op--;
95
6
        if (ch == EOFC)
96
6
        make_bool(op, 0);
97
0
    else
98
0
        return handle_read_status(i_ctx_p, ch, op, NULL, zread);
99
6
    }
100
1.50M
    return 0;
101
1.50M
}
102
103
/* <file> <int> write - */
104
int
105
zwrite(i_ctx_t *i_ctx_p)
106
2
{
107
2
    os_ptr op = osp;
108
2
    stream *s;
109
2
    byte ch;
110
2
    int status;
111
112
2
    check_op(1);
113
2
    check_write_file(s, op - 1);
114
0
    check_type(*op, t_integer);
115
0
    ch = (byte) op->value.intval;
116
0
    status = sputc(s, (byte) ch);
117
0
    if (status >= 0) {
118
0
        pop(2);
119
0
        return 0;
120
0
    }
121
0
    return handle_write_status(i_ctx_p, status, op - 1, NULL, zwrite);
122
0
}
123
124
/* <file> <string> readhexstring <substring> <filled_bool> */
125
static int zreadhexstring_continue(i_ctx_t *);
126
127
/* We pack the odd digit above the the current position for the  */
128
/* convenience of reusing procedures that take 1 state parameter */
129
static int
130
zreadhexstring_at(i_ctx_t *i_ctx_p, os_ptr op, uint start, int odd)
131
16
{
132
16
    stream *s;
133
16
    uint len, nread;
134
16
    byte *str;
135
16
    int odd_byte = odd;
136
16
    stream_cursor_write cw;
137
16
    int status;
138
139
16
    check_read_file(i_ctx_p, s, op - 1);
140
    /*check_write_type(*op, t_string); *//* done by caller */
141
16
    str = op->value.bytes;
142
16
    len = r_size(op);
143
16
    cw.ptr = str + start - 1;
144
16
    cw.limit = str + len - 1;
145
43
    for (;;) {
146
43
        status = s_hex_process(&s->cursor.r, &cw, &odd_byte,
147
43
                               hex_ignore_garbage);
148
43
        if (status == 1) { /* filled the string */
149
0
            ref_assign_inline(op - 1, op);
150
0
            make_true(op);
151
0
            return 0;
152
43
        } else if (status != 0)  /* error or EOF */
153
0
            break;
154
        /* Didn't fill, keep going. */
155
43
        status = spgetc(s);
156
43
        if (status < 0)
157
16
            break;
158
27
        sputback(s);
159
27
    }
160
16
    nread = cw.ptr + 1 - str;
161
16
    if (status != EOFC) { /* Error */
162
0
        nread |= ((uchar)odd_byte) << 24;
163
0
        return handle_read_status(i_ctx_p, status, op - 1, &nread,
164
0
                                  zreadhexstring_continue);
165
0
    }
166
    /* Reached end-of-file before filling the string. */
167
    /* Return an appropriate substring. */
168
16
    ref_assign_inline(op - 1, op);
169
16
    r_set_size(op - 1, nread);
170
16
    make_false(op);
171
16
    return 0;
172
16
}
173
static int
174
zreadhexstring(i_ctx_t *i_ctx_p)
175
17
{
176
17
    os_ptr op = osp;
177
178
17
    check_op(2);
179
16
    check_write_type(*op, t_string);
180
16
    return zreadhexstring_at(i_ctx_p, op, 0, -1);
181
16
}
182
/* Continue a readhexstring operation after a callout. */
183
/* *op contains the index within the string and the odd flag. */
184
static int
185
zreadhexstring_continue(i_ctx_t *i_ctx_p)
186
0
{
187
0
    os_ptr op = osp;
188
0
    int code, length, odd;
189
190
0
    check_type(*op, t_integer);
191
0
    length = op->value.intval & 0xFFFFFF;
192
0
    odd = (schar)(op->value.intval >> 24);
193
194
0
    if (length > r_size(op - 1) || odd < -1 || odd > 0xF)
195
0
        return_error(gs_error_rangecheck);
196
0
    check_write_type(op[-1], t_string);
197
0
    code = zreadhexstring_at(i_ctx_p, op - 1, (uint)length, odd);
198
0
    if (code >= 0)
199
0
        pop(1);
200
0
    return code;
201
0
}
202
203
/* <file> <string> writehexstring - */
204
static int zwritehexstring_continue(i_ctx_t *);
205
static int
206
zwritehexstring_at(i_ctx_t *i_ctx_p, os_ptr op, uint odd)
207
0
{
208
0
    register stream *s;
209
0
    register byte ch;
210
0
    register const byte *p;
211
0
    register const char *const hex_digits = "0123456789abcdef";
212
0
    register uint len;
213
0
    int status;
214
215
0
#define MAX_HEX 128
216
0
    byte buf[MAX_HEX];
217
218
0
    check_write_file(s, op - 1);
219
0
    check_read_type(*op, t_string);
220
0
    p = op->value.bytes;
221
0
    len = r_size(op);
222
0
    while (len) {
223
0
        uint len1 = min(len, MAX_HEX / 2);
224
0
        register byte *q = buf;
225
0
        uint count = len1;
226
0
        ref rbuf;
227
228
0
        do {
229
0
            ch = *p++;
230
0
            *q++ = hex_digits[ch >> 4];
231
0
            *q++ = hex_digits[ch & 0xf];
232
0
        }
233
0
        while (--count);
234
0
        r_set_size(&rbuf, (len1 << 1) - odd);
235
0
        rbuf.value.bytes = buf + odd;
236
0
        status = write_string(&rbuf, s);
237
0
        switch (status) {
238
0
            default:
239
0
                return_error(gs_error_ioerror);
240
0
            case 0:
241
0
                len -= len1;
242
0
                odd = 0;
243
0
                continue;
244
0
            case INTC:
245
0
            case CALLC:
246
0
                count = rbuf.value.bytes - buf;
247
0
                op->value.bytes += count >> 1;
248
0
                r_set_size(op, len - (count >> 1));
249
0
                count &= 1;
250
0
                return handle_write_status(i_ctx_p, status, op - 1, &count,
251
0
                                           zwritehexstring_continue);
252
0
        }
253
0
    }
254
0
    pop(2);
255
0
    return 0;
256
0
#undef MAX_HEX
257
0
}
258
static int
259
zwritehexstring(i_ctx_t *i_ctx_p)
260
1
{
261
1
    os_ptr op = osp;
262
1
    check_op(2);
263
264
0
    return zwritehexstring_at(i_ctx_p, op, 0);
265
1
}
266
/* Continue a writehexstring operation after a callout. */
267
/* *op is the odd/even hex digit flag for the first byte. */
268
static int
269
zwritehexstring_continue(i_ctx_t *i_ctx_p)
270
0
{
271
0
    os_ptr op = osp;
272
0
    int code;
273
274
0
    check_type(*op, t_integer);
275
0
    if ((op->value.intval & ~1) != 0)
276
0
        return_error(gs_error_rangecheck);
277
0
    code = zwritehexstring_at(i_ctx_p, op - 1, (uint) op->value.intval);
278
0
    if (code >= 0)
279
0
        pop(1);
280
0
    return code;
281
0
}
282
283
/* <file> <string> readstring <substring> <filled_bool> */
284
static int zreadstring_continue(i_ctx_t *);
285
static int
286
zreadstring_at(i_ctx_t *i_ctx_p, os_ptr op, uint start)
287
483k
{
288
483k
    stream *s;
289
483k
    uint len, rlen;
290
483k
    int status;
291
292
483k
    check_write_type(*op, t_string);
293
483k
    check_read_file(i_ctx_p, s, op - 1);
294
483k
    len = r_size(op);
295
483k
    status = sgets(s, op->value.bytes + start, len - start, &rlen);
296
483k
    rlen += start;
297
483k
    switch (status) {
298
6.24k
        case EOFC:
299
483k
        case 0:
300
483k
            break;
301
0
        default:
302
0
            return handle_read_status(i_ctx_p, status, op - 1, &rlen,
303
0
                                      zreadstring_continue);
304
483k
    }
305
    /*
306
     * The most recent Adobe specification says that readstring
307
     * must signal a rangecheck if the string length is zero.
308
     * I can't imagine the motivation for this, but we emulate it.
309
     * It's safe to check it here, rather than earlier, because if
310
     * len is zero, sgets will return 0 immediately with rlen = 0.
311
     */
312
483k
    if (len == 0)
313
0
        return_error(gs_error_rangecheck);
314
483k
    r_set_size(op, rlen);
315
483k
    op[-1] = *op;
316
483k
    make_bool(op, (rlen == len ? 1 : 0));
317
483k
    return 0;
318
483k
}
319
static int
320
zreadstring(i_ctx_t *i_ctx_p)
321
483k
{
322
483k
    os_ptr op = osp;
323
324
483k
    return zreadstring_at(i_ctx_p, op, 0);
325
483k
}
326
/* Continue a readstring operation after a callout. */
327
/* *op is the index within the string. */
328
static int
329
zreadstring_continue(i_ctx_t *i_ctx_p)
330
0
{
331
0
    os_ptr op = osp;
332
0
    int code;
333
334
0
    check_type(*op, t_integer);
335
0
    if (op->value.intval < 0 || op->value.intval > r_size(op - 1))
336
0
        return_error(gs_error_rangecheck);
337
0
    code = zreadstring_at(i_ctx_p, op - 1, (uint) op->value.intval);
338
0
    if (code >= 0)
339
0
        pop(1);
340
0
    return code;
341
0
}
342
343
/* <file> <string> writestring - */
344
static int
345
zwritestring(i_ctx_t *i_ctx_p)
346
34.6k
{
347
34.6k
    os_ptr op = osp;
348
34.6k
    stream *s;
349
34.6k
    int status;
350
351
34.6k
    check_op(2);
352
34.6k
    check_write_file(s, op - 1);
353
34.6k
    check_read_type(*op, t_string);
354
34.6k
    status = write_string(op, s);
355
34.6k
    if (status >= 0) {
356
34.6k
        pop(2);
357
34.6k
        return 0;
358
34.6k
    }
359
0
    return handle_write_status(i_ctx_p, status, op - 1, NULL, zwritestring);
360
34.6k
}
361
362
/* <file> <string> readline <substring> <bool> */
363
static int zreadline(i_ctx_t *);
364
static int zreadline_continue(i_ctx_t *);
365
366
/*
367
 * We could handle readline the same way as readstring,
368
 * except for the anomalous situation where we get interrupted
369
 * between the CR and the LF of an end-of-line marker.
370
 * We hack around this in the following way: if we get interrupted
371
 * before we've read any characters, we just restart the readline;
372
 * if we get interrupted at any other time, we use readline_continue;
373
 * we use start=0 (which we have just ruled out as a possible start value
374
 * for readline_continue) to indicate interruption after the CR.
375
 */
376
static int
377
zreadline_at(i_ctx_t *i_ctx_p, os_ptr op, uint count, bool in_eol)
378
0
{
379
0
    stream *s;
380
0
    int status;
381
0
    gs_string str;
382
383
0
    check_write_type(*op, t_string);
384
0
    check_read_file(i_ctx_p, s, op - 1);
385
0
    str.data = op->value.bytes;
386
0
    str.size = r_size(op);
387
0
    status = zreadline_from(s, &str, NULL, &count, &in_eol);
388
0
    switch (status) {
389
0
        case 0:
390
0
        case EOFC:
391
0
            break;
392
0
        case 1:
393
0
            return_error(gs_error_rangecheck);
394
0
        default:
395
0
            if (count == 0 && !in_eol)
396
0
                return handle_read_status(i_ctx_p, status, op - 1, NULL,
397
0
                                          zreadline);
398
0
            else {
399
0
                if (in_eol) {
400
0
                    r_set_size(op, count);
401
0
                    count = 0;
402
0
                }
403
0
                return handle_read_status(i_ctx_p, status, op - 1, &count,
404
0
                                          zreadline_continue);
405
0
            }
406
0
    }
407
0
    r_set_size(op, count);
408
0
    op[-1] = *op;
409
0
    make_bool(op, status == 0);
410
0
    return 0;
411
0
}
412
static int
413
zreadline(i_ctx_t *i_ctx_p)
414
1
{
415
1
    os_ptr op = osp;
416
1
    check_op(2);
417
418
0
    return zreadline_at(i_ctx_p, op, 0, false);
419
1
}
420
/* Continue a readline operation after a callout. */
421
/* *op is the index within the string, or 0 for an interrupt after a CR. */
422
static int
423
zreadline_continue(i_ctx_t *i_ctx_p)
424
0
{
425
0
    os_ptr op = osp;
426
0
    uint size = r_size(op - 1);
427
0
    uint start;
428
0
    int code;
429
430
0
    check_type(*op, t_integer);
431
0
    if (op->value.intval < 0 || op->value.intval > size)
432
0
        return_error(gs_error_rangecheck);
433
0
    start = (uint) op->value.intval;
434
0
    code = (start == 0 ? zreadline_at(i_ctx_p, op - 1, size, true) :
435
0
            zreadline_at(i_ctx_p, op - 1, start, false));
436
0
    if (code >= 0)
437
0
        pop(1);
438
0
    return code;
439
0
}
440
441
/* Internal readline routine. */
442
/* Returns a stream status value, or 1 if we overflowed the string. */
443
/* This is exported for %lineedit. */
444
int
445
zreadline_from(stream *s, gs_string *buf, gs_memory_t *bufmem,
446
               uint *pcount, bool *pin_eol)
447
0
{
448
0
    sreadline_proc((*readline));
449
450
0
    if (zis_stdin(s))
451
0
        readline = gp_readline;
452
0
    else
453
0
        readline = sreadline;
454
0
    return readline(s, NULL, NULL /*WRONG*/, NULL, buf, bufmem,
455
0
                    pcount, pin_eol, zis_stdin);
456
0
}
457
458
/* <file> bytesavailable <int> */
459
static int
460
zbytesavailable(i_ctx_t *i_ctx_p)
461
1
{
462
1
    os_ptr op = osp;
463
1
    stream *s;
464
1
    gs_offset_t avail;
465
466
1
    check_op(1);
467
1
    check_read_file(i_ctx_p, s, op);
468
0
    switch (savailable(s, &avail)) {
469
0
        default:
470
0
            return_error(gs_error_ioerror);
471
0
        case EOFC:
472
0
            avail = -1;
473
0
        case 0:
474
0
            ;
475
0
    }
476
0
    if (gs_currentcpsimode(imemory)) {
477
0
        avail = (ps_int32)avail;
478
0
    }
479
0
    make_int(op, avail);
480
0
    return 0;
481
0
}
482
483
/* - flush - */
484
int
485
zflush(i_ctx_t *i_ctx_p)
486
22.8k
{
487
22.8k
    stream *s;
488
22.8k
    int status;
489
22.8k
    ref rstdout;
490
22.8k
    int code = zget_stdout(i_ctx_p, &s);
491
492
22.8k
    if (code < 0)
493
0
        return code;
494
495
22.8k
    make_stream_file(&rstdout, s, "w");
496
22.8k
    status = sflush(s);
497
22.8k
    if (status == 0 || status == EOFC) {
498
22.8k
        return 0;
499
22.8k
    }
500
0
    return
501
0
        (s_is_writing(s) ?
502
0
         handle_write_status(i_ctx_p, status, &rstdout, NULL, zflush) :
503
0
         handle_read_status(i_ctx_p, status, &rstdout, NULL, zflush));
504
22.8k
}
505
506
/* <file> flushfile - */
507
static int
508
zflushfile(i_ctx_t *i_ctx_p)
509
51.5k
{
510
51.5k
    os_ptr op = osp;
511
51.5k
    stream *s;
512
51.5k
    int status;
513
514
51.5k
    check_op(1);
515
51.5k
    check_type(*op, t_file);
516
    /*
517
     * We think flushfile is a no-op on closed input files, but causes an
518
     * error on closed output files.
519
     */
520
51.5k
    if (file_is_invalid(s, op)) {
521
0
        if (r_has_attr(op, a_write))
522
0
            return_error(gs_error_invalidaccess);
523
0
        pop(1);
524
0
        return 0;
525
0
    }
526
51.5k
    status = sflush(s);
527
51.5k
    if (status == 0 || status == EOFC) {
528
51.5k
        pop(1);
529
51.5k
        return 0;
530
51.5k
    }
531
0
    return
532
0
        (s_is_writing(s) ?
533
0
         handle_write_status(i_ctx_p, status, op, NULL, zflushfile) :
534
0
         handle_read_status(i_ctx_p, status, op, NULL, zflushfile));
535
51.5k
}
536
537
/* <file> resetfile - */
538
static int
539
zresetfile(i_ctx_t *i_ctx_p)
540
1
{
541
1
    os_ptr op = osp;
542
1
    stream *s;
543
544
1
    check_op(1);
545
    /* According to Adobe, resetfile is a no-op on closed files. */
546
1
    check_type(*op, t_file);
547
0
    if (file_is_valid(s, op))
548
0
        sreset(s);
549
0
    pop(1);
550
0
    return 0;
551
1
}
552
553
/* <string> print - */
554
static int
555
zprint(i_ctx_t *i_ctx_p)
556
1.13M
{
557
1.13M
    os_ptr op = osp;
558
1.13M
    stream *s;
559
1.13M
    int status;
560
1.13M
    ref rstdout;
561
1.13M
    int code;
562
563
1.13M
    check_op(1);
564
1.13M
    check_read_type(*op, t_string);
565
1.13M
    code = zget_stdout(i_ctx_p, &s);
566
1.13M
    if (code < 0)
567
0
        return code;
568
1.13M
    status = write_string(op, s);
569
1.13M
    if (status >= 0) {
570
1.13M
        pop(1);
571
1.13M
        return 0;
572
1.13M
    }
573
    /* Convert print to writestring on the fly. */
574
0
    make_stream_file(&rstdout, s, "w");
575
0
    code = handle_write_status(i_ctx_p, status, &rstdout, NULL,
576
0
                               zwritestring);
577
0
    if (code != o_push_estack)
578
0
        return code;
579
0
    push(1);
580
0
    *op = op[-1];
581
0
    op[-1] = rstdout;
582
0
    return code;
583
0
}
584
585
/* <bool> echo - */
586
static int
587
zecho(i_ctx_t *i_ctx_p)
588
0
{
589
0
    os_ptr op = osp;
590
591
0
    check_op(1);
592
0
    check_type(*op, t_boolean);
593
    /****** NOT IMPLEMENTED YET ******/
594
0
    pop(1);
595
0
    return 0;
596
0
}
597
598
/* ------ Level 2 extensions ------ */
599
600
/* <file> fileposition <int> */
601
static int
602
zfileposition(i_ctx_t *i_ctx_p)
603
3.35k
{
604
3.35k
    os_ptr op = osp;
605
3.35k
    stream *s;
606
607
3.35k
    check_op(1);
608
3.35k
    check_file(s, op);
609
    /*
610
     * The PLRM says fileposition must give an error for non-seekable
611
     * streams.
612
     */
613
3.34k
    if (!s_can_seek(s))
614
3.34k
        return_error(gs_error_ioerror);
615
0
    make_int(op, stell(s));
616
0
    return 0;
617
3.34k
}
618
/* <file> .fileposition <int> */
619
static int
620
zxfileposition(i_ctx_t *i_ctx_p)
621
1
{
622
1
    os_ptr op = osp;
623
1
    stream *s;
624
625
1
    check_op(1);
626
1
    check_file(s, op);
627
    /*
628
     * This version of fileposition doesn't give the error, so we can
629
     * use it to get the position of string or procedure streams.
630
     */
631
0
    make_int(op, stell(s));
632
0
    return 0;
633
0
}
634
635
/* <file> <int> setfileposition - */
636
static int
637
zsetfileposition(i_ctx_t *i_ctx_p)
638
7.36k
{
639
7.36k
    os_ptr op = osp;
640
7.36k
    stream *s;
641
642
7.36k
    check_op(2);
643
7.36k
    check_type(*op, t_integer);
644
7.36k
    if ((gs_offset_t)op->value.intval < 0)
645
0
        return_error(gs_error_rangecheck);
646
7.36k
    check_file(s, op - 1);
647
7.36k
    if (sseek(s, (gs_offset_t)op->value.intval) < 0)
648
6
        return_error(gs_error_ioerror);
649
7.35k
    pop(2);
650
7.35k
    return 0;
651
7.36k
}
652
653
/* ------ Non-standard extensions ------ */
654
655
/* <file> .filename <string> true */
656
/* <file> .filename false */
657
static int
658
zfilename(i_ctx_t *i_ctx_p)
659
19.5k
{
660
19.5k
    os_ptr op = osp;
661
19.5k
    stream *s;
662
19.5k
    gs_const_string fname;
663
19.5k
    byte *str;
664
665
19.5k
    check_op(1);
666
19.5k
    check_file(s, op);
667
19.5k
    if (sfilename(s, &fname) < 0) {
668
0
        make_false(op);
669
0
        return 0;
670
0
    }
671
19.5k
    check_ostack(1);
672
19.5k
    str = ialloc_string(fname.size, "filename");
673
19.5k
    if (str == 0)
674
0
        return_error(gs_error_VMerror);
675
19.5k
    memcpy(str, fname.data, fname.size);
676
19.5k
    push(1);      /* can't fail */
677
19.5k
    make_const_string( op - 1 ,
678
19.5k
                      a_all | imemory_space((const struct gs_ref_memory_s*) imemory),
679
19.5k
                      fname.size,
680
19.5k
                      str);
681
19.5k
    make_true(op);
682
19.5k
    return 0;
683
19.5k
}
684
685
/* <file> .isprocfilter <bool> */
686
static int
687
zisprocfilter(i_ctx_t *i_ctx_p)
688
0
{
689
0
    os_ptr op = osp;
690
0
    stream *s;
691
692
0
    check_op(1);
693
0
    check_file(s, op);
694
0
    while (s->strm != 0)
695
0
        s = s->strm;
696
0
    make_bool(op, s_is_proc(s));
697
0
    return 0;
698
0
}
699
700
/* <file> <string> .peekstring <substring> <filled_bool> */
701
static int
702
zpeekstring(i_ctx_t *i_ctx_p)
703
1.54M
{
704
1.54M
    os_ptr op = osp;
705
1.54M
    stream *s;
706
1.54M
    uint len, rlen = 0;
707
708
1.54M
    check_op(2);
709
1.54M
    check_read_file(i_ctx_p, s, op - 1);
710
    /* The stream has been disabled, probably closed, so we shouldn't
711
       be trying to read from it.
712
     */
713
1.54M
    if (s->end_status < 0 && sbufptr(s) - 1 == NULL) {
714
0
        return_error(gs_error_ioerror);
715
0
    }
716
1.54M
    check_write_type(*op, t_string);
717
1.54M
    len = r_size(op);
718
1.56M
    while ((rlen = sbufavailable(s)) < len) {
719
20.5k
        int status = s->end_status;
720
721
20.5k
        switch (status) {
722
4.07k
        case EOFC:
723
4.07k
            break;
724
16.4k
        case 0:
725
            /*
726
             * The following is a HACK.  It should reallocate the buffer to hold
727
             * at least len bytes.  However, this raises messy problems about
728
             * which allocator to use and how it should interact with restore.
729
             */
730
16.4k
            if (len >= s->bsize)
731
0
                return_error(gs_error_rangecheck);
732
16.4k
            s_process_read_buf(s);
733
16.4k
            continue;
734
0
        default:
735
0
            return handle_read_status(i_ctx_p, status, op - 1, NULL,
736
0
                                      zpeekstring);
737
20.5k
        }
738
4.07k
        break;
739
20.5k
    }
740
1.54M
    if (rlen > len)
741
1.53M
        rlen = len;
742
    /* Don't remove the data from the buffer. */
743
1.54M
    memcpy(op->value.bytes, sbufptr(s), rlen);
744
1.54M
    r_set_size(op, rlen);
745
1.54M
    op[-1] = *op;
746
1.54M
    make_bool(op, (rlen == len ? 1 : 0));
747
1.54M
    return 0;
748
1.54M
}
749
750
/* <file> <int> .unread - */
751
static int
752
zunread(i_ctx_t *i_ctx_p)
753
1.09k
{
754
1.09k
    os_ptr op = osp;
755
1.09k
    stream *s;
756
1.09k
    ulong ch;
757
758
1.09k
    check_op(2);
759
1.09k
    check_read_file(i_ctx_p, s, op - 1);
760
1.09k
    check_type(*op, t_integer);
761
1.09k
    ch = op->value.intval;
762
1.09k
    if (ch > 0xff)
763
0
        return_error(gs_error_rangecheck);
764
1.09k
    if (sungetc(s, (byte) ch) < 0)
765
0
        return_error(gs_error_ioerror);
766
1.09k
    pop(2);
767
1.09k
    return 0;
768
1.09k
}
769
770
/* <file> <obj> <==flag> .writecvp - */
771
static int zwritecvp_continue(i_ctx_t *);
772
static int
773
zwritecvp_at(i_ctx_t *i_ctx_p, os_ptr op, uint start, bool first)
774
1.11M
{
775
1.11M
    stream *s;
776
1.11M
    byte str[100];    /* arbitrary */
777
1.11M
    ref rstr;
778
1.11M
    const byte *data = str;
779
1.11M
    uint len;
780
1.11M
    int code, status;
781
782
1.11M
    check_write_file(s, op - 2);
783
1.11M
    check_type(*op, t_integer);
784
1.11M
    code = obj_cvp(op - 1, str, sizeof(str), &len, (int)op->value.intval,
785
1.11M
                   start, imemory, true);
786
1.11M
    if (code == gs_error_rangecheck) {
787
0
        code = obj_string_data(imemory, op - 1, &data, &len);
788
0
        if (len < start)
789
0
            return_error(gs_error_rangecheck);
790
0
        data += start;
791
0
        len -= start;
792
0
    }
793
1.11M
    if (code < 0)
794
1
        return code;
795
1.11M
    r_set_size(&rstr, len);
796
1.11M
    rstr.value.const_bytes = data;
797
1.11M
    status = write_string(&rstr, s);
798
1.11M
    switch (status) {
799
0
        default:
800
0
            return_error(gs_error_ioerror);
801
1.11M
        case 0:
802
1.11M
            break;
803
0
        case INTC:
804
0
        case CALLC:
805
0
            len = start + len - r_size(&rstr);
806
0
            if (!first)
807
0
                --osp;   /* pop(1) without affecting op */
808
0
            return handle_write_status(i_ctx_p, status, op - 2, &len,
809
0
                                       zwritecvp_continue);
810
1.11M
    }
811
1.11M
    if (code == 1) {
812
3.01k
        if (first)
813
3.01k
            check_ostack(1);
814
3.01k
        push_op_estack(zwritecvp_continue);
815
3.01k
        if (first)
816
3.01k
            push(1);
817
3.01k
        make_int(osp, start + len);
818
3.01k
        return o_push_estack;
819
3.01k
    }
820
1.10M
    if (first)      /* zwritecvp */
821
1.10M
        pop(3);
822
633
    else      /* zwritecvp_continue */
823
633
        pop(4);
824
1.10M
    return 0;
825
1.11M
}
826
static int
827
zwritecvp(i_ctx_t *i_ctx_p)
828
1.10M
{
829
1.10M
    return zwritecvp_at(i_ctx_p, osp, 0, true);
830
1.10M
}
831
/* Continue a .writecvp after a callout. */
832
/* *op is the index within the string. */
833
static int
834
zwritecvp_continue(i_ctx_t *i_ctx_p)
835
3.01k
{
836
3.01k
    os_ptr op = osp;
837
838
3.01k
    check_type(*op, t_integer);
839
3.01k
    if (op->value.intval != (uint) op->value.intval)
840
0
        return_error(gs_error_rangecheck);
841
3.01k
    return zwritecvp_at(i_ctx_p, op - 1, (uint) op->value.intval, false);
842
3.01k
}
843
844
/* ------ Initialization procedure ------ */
845
846
/* We need to split the table because of the 16-element limit. */
847
const op_def zfileio1_op_defs[] = {
848
    {"1bytesavailable", zbytesavailable},
849
    {"1closefile", zclosefile},
850
                /* currentfile is in zcontrol.c */
851
    {"1echo", zecho},
852
    {"1.filename", zfilename},
853
    {"1.fileposition", zxfileposition},
854
    {"1fileposition", zfileposition},
855
    {"0flush", zflush},
856
    {"1flushfile", zflushfile},
857
    {"1.isprocfilter", zisprocfilter},
858
    {"2.peekstring", zpeekstring},
859
    {"1print", zprint},
860
    {"1read", zread},
861
    {"2readhexstring", zreadhexstring},
862
    {"2readline", zreadline},
863
    {"2readstring", zreadstring},
864
    op_def_end(0)
865
};
866
const op_def zfileio2_op_defs[] = {
867
    {"1resetfile", zresetfile},
868
    {"2setfileposition", zsetfileposition},
869
    {"2.unread", zunread},
870
    {"2write", zwrite},
871
    {"3.writecvp", zwritecvp},
872
    {"2writehexstring", zwritehexstring},
873
    {"2writestring", zwritestring},
874
                /* Internal operators */
875
    {"3%zreadhexstring_continue", zreadhexstring_continue},
876
    {"3%zreadline_continue", zreadline_continue},
877
    {"3%zreadstring_continue", zreadstring_continue},
878
    {"4%zwritecvp_continue", zwritecvp_continue},
879
    {"3%zwritehexstring_continue", zwritehexstring_continue},
880
    op_def_end(0)
881
};
882
883
/* ------ Non-operator routines ------ */
884
885
/* Switch a file open for read/write access but currently in write mode */
886
/* to read mode. */
887
int
888
file_switch_to_read(const ref * op)
889
6.24k
{
890
6.24k
    stream *s = fptr(op);
891
892
6.24k
    if (s->write_id != r_size(op) || s->file == 0)  /* not valid */
893
0
        return_error(gs_error_invalidaccess);
894
6.24k
    if (sswitch(s, false) < 0)
895
0
        return_error(gs_error_ioerror);
896
6.24k
    s->read_id = s->write_id; /* enable reading */
897
6.24k
    s->write_id = 0;    /* disable writing */
898
6.24k
    return 0;
899
6.24k
}
900
901
/* Switch a file open for read/write access but currently in read mode */
902
/* to write mode. */
903
int
904
file_switch_to_write(const ref * op)
905
0
{
906
0
    stream *s = fptr(op);
907
908
0
    if (s->read_id != r_size(op) || s->file == 0) /* not valid */
909
0
        return_error(gs_error_invalidaccess);
910
0
    if (sswitch(s, true) < 0)
911
0
        return_error(gs_error_ioerror);
912
0
    s->write_id = s->read_id; /* enable writing */
913
0
    s->read_id = 0;   /* disable reading */
914
0
    return 0;
915
0
}
916
917
/* ------ Internal routines ------ */
918
919
/* Write a string on a file.  The file and string have been validated. */
920
/* If the status is INTC or CALLC, updates the string on the o-stack. */
921
static int
922
write_string(ref * op, stream * s)
923
2.27M
{
924
2.27M
    const byte *data = op->value.const_bytes;
925
2.27M
    uint len = r_size(op);
926
2.27M
    uint wlen;
927
2.27M
    int status = sputs(s, data, len, &wlen);
928
929
2.27M
    switch (status) {
930
0
        case INTC:
931
0
        case CALLC:
932
0
            op->value.const_bytes = data + wlen;
933
0
            r_set_size(op, len - wlen);
934
            /* falls through */
935
2.27M
        default:    /* 0, EOFC, ERRC */
936
2.27M
            return status;
937
2.27M
    }
938
2.27M
}
939
940
/*
941
 * Look for a stream error message that needs to be copied to
942
 * $error.errorinfo, if any.
943
 */
944
static int
945
copy_error_string(i_ctx_t *i_ctx_p, const ref *fop)
946
0
{
947
0
    stream *s;
948
949
0
    for (s = fptr(fop); s->strm != 0 && s->state->error_string[0] == 0;)
950
0
        s = s->strm;
951
0
    if (s->state->error_string[0]) {
952
0
        int code = gs_errorinfo_put_string(i_ctx_p, s->state->error_string);
953
954
0
        if (code < 0)
955
0
            return code;
956
0
        s->state->error_string[0] = 0; /* just do it once */
957
0
    }
958
0
    return_error(gs_error_ioerror);
959
0
}
960
961
/* Handle an exceptional status return from a read stream. */
962
/* fop points to the ref for the stream. */
963
/* ch may be any stream exceptional value. */
964
/* Return 0, 1 (EOF), o_push_estack, or an error. */
965
static int
966
handle_read_status(i_ctx_t *i_ctx_p, int ch, const ref * fop,
967
                   const uint * pindex, op_proc_t cont)
968
0
{
969
0
    switch (ch) {
970
0
        default:    /* error */
971
0
            return copy_error_string(i_ctx_p, fop);
972
0
        case EOFC:
973
0
            return 1;
974
0
        case INTC:
975
0
        case CALLC:
976
0
            if (pindex) {
977
0
                ref index;
978
979
0
                make_int(&index, *pindex);
980
0
                return s_handle_read_exception(i_ctx_p, ch, fop, &index, 1,
981
0
                                               cont);
982
0
            } else
983
0
                return s_handle_read_exception(i_ctx_p, ch, fop, NULL, 0,
984
0
                                               cont);
985
0
    }
986
0
}
987
988
/* Handle an exceptional status return from a write stream. */
989
/* fop points to the ref for the stream. */
990
/* ch may be any stream exceptional value. */
991
/* Return 0, 1 (EOF), o_push_estack, or an error. */
992
static int
993
handle_write_status(i_ctx_t *i_ctx_p, int ch, const ref * fop,
994
                    const uint * pindex, op_proc_t cont)
995
9.70k
{
996
9.70k
    switch (ch) {
997
0
        default:    /* error */
998
0
            return copy_error_string(i_ctx_p, fop);
999
0
        case EOFC:
1000
0
            return 1;
1001
0
        case INTC:
1002
9.70k
        case CALLC:
1003
9.70k
            if (pindex) {
1004
0
                ref index;
1005
1006
0
                make_int(&index, *pindex);
1007
0
                return s_handle_write_exception(i_ctx_p, ch, fop, &index, 1,
1008
0
                                                cont);
1009
0
            } else
1010
9.70k
                return s_handle_write_exception(i_ctx_p, ch, fop, NULL, 0,
1011
9.70k
                                                cont);
1012
9.70k
    }
1013
9.70k
}