Coverage Report

Created: 2025-06-24 07:01

/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
2.38M
{
47
2.38M
    os_ptr op = osp;
48
2.38M
    stream *s;
49
50
2.38M
    check_op(1);
51
2.38M
    check_type(*op, t_file);
52
2.38M
    if (file_is_valid(s, op)) { /* closing a closed file is a no-op */
53
1.31M
        int status = sclose(s);
54
55
1.31M
        if (status != 0 && status != EOFC) {
56
184k
            if (s_is_writing(s))
57
184k
                return handle_write_status(i_ctx_p, status, op, NULL,
58
184k
                                           zclosefile);
59
0
            else
60
0
                return handle_read_status(i_ctx_p, status, op, NULL,
61
0
                                          zclosefile);
62
184k
        }
63
1.31M
    }
64
2.19M
    pop(1);
65
2.19M
    return 0;
66
2.38M
}
67
68
/* <file> read <int> -true- */
69
/* <file> read -false- */
70
static int
71
zread(i_ctx_t *i_ctx_p)
72
34.7M
{
73
34.7M
    os_ptr op = osp;
74
34.7M
    stream *s;
75
34.7M
    int ch;
76
77
34.7M
    check_op(1);
78
34.7M
    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
34.7M
    push(1);
88
34.7M
    ch = sgetc(s);
89
34.7M
    if (ch >= 0) {
90
34.7M
        make_int(op - 1, ch);
91
34.7M
        make_bool(op, 1);
92
34.7M
    } else {
93
80
        pop(1);    /* Adjust ostack back from preparatory 'pop' */
94
80
        op--;
95
80
        if (ch == EOFC)
96
80
        make_bool(op, 0);
97
0
    else
98
0
        return handle_read_status(i_ctx_p, ch, op, NULL, zread);
99
80
    }
100
34.7M
    return 0;
101
34.7M
}
102
103
/* <file> <int> write - */
104
int
105
zwrite(i_ctx_t *i_ctx_p)
106
22
{
107
22
    os_ptr op = osp;
108
22
    stream *s;
109
22
    byte ch;
110
22
    int status;
111
112
22
    check_op(1);
113
22
    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
1.26k
{
132
1.26k
    stream *s;
133
1.26k
    uint len, nread;
134
1.26k
    byte *str;
135
1.26k
    int odd_byte = odd;
136
1.26k
    stream_cursor_write cw;
137
1.26k
    int status;
138
139
1.26k
    check_read_file(i_ctx_p, s, op - 1);
140
    /*check_write_type(*op, t_string); *//* done by caller */
141
1.26k
    str = op->value.bytes;
142
1.26k
    len = r_size(op);
143
1.26k
    cw.ptr = str + start - 1;
144
1.26k
    cw.limit = str + len - 1;
145
2.87k
    for (;;) {
146
2.87k
        status = s_hex_process(&s->cursor.r, &cw, &odd_byte,
147
2.87k
                               hex_ignore_garbage);
148
2.87k
        if (status == 1) { /* filled the string */
149
853
            ref_assign_inline(op - 1, op);
150
853
            make_true(op);
151
853
            return 0;
152
2.02k
        } else if (status != 0)  /* error or EOF */
153
0
            break;
154
        /* Didn't fill, keep going. */
155
2.02k
        status = spgetc(s);
156
2.02k
        if (status < 0)
157
410
            break;
158
1.61k
        sputback(s);
159
1.61k
    }
160
410
    nread = cw.ptr + 1 - str;
161
410
    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
410
    ref_assign_inline(op - 1, op);
169
410
    r_set_size(op - 1, nread);
170
410
    make_false(op);
171
410
    return 0;
172
410
}
173
static int
174
zreadhexstring(i_ctx_t *i_ctx_p)
175
1.28k
{
176
1.28k
    os_ptr op = osp;
177
178
1.28k
    check_op(2);
179
1.27k
    check_write_type(*op, t_string);
180
1.26k
    return zreadhexstring_at(i_ctx_p, op, 0, -1);
181
1.27k
}
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
15
{
208
15
    register stream *s;
209
15
    register byte ch;
210
15
    register const byte *p;
211
15
    register const char *const hex_digits = "0123456789abcdef";
212
15
    register uint len;
213
15
    int status;
214
215
15
#define MAX_HEX 128
216
15
    byte buf[MAX_HEX];
217
218
15
    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
28
{
261
28
    os_ptr op = osp;
262
28
    check_op(2);
263
264
15
    return zwritehexstring_at(i_ctx_p, op, 0);
265
28
}
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
11.3M
{
288
11.3M
    stream *s;
289
11.3M
    uint len, rlen;
290
11.3M
    int status;
291
292
11.3M
    check_write_type(*op, t_string);
293
11.3M
    check_read_file(i_ctx_p, s, op - 1);
294
11.3M
    len = r_size(op);
295
11.3M
    status = sgets(s, op->value.bytes + start, len - start, &rlen);
296
11.3M
    rlen += start;
297
11.3M
    switch (status) {
298
94.7k
        case EOFC:
299
11.3M
        case 0:
300
11.3M
            break;
301
3
        default:
302
3
            return handle_read_status(i_ctx_p, status, op - 1, &rlen,
303
3
                                      zreadstring_continue);
304
11.3M
    }
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
11.3M
    if (len == 0)
313
0
        return_error(gs_error_rangecheck);
314
11.3M
    r_set_size(op, rlen);
315
11.3M
    op[-1] = *op;
316
11.3M
    make_bool(op, (rlen == len ? 1 : 0));
317
11.3M
    return 0;
318
11.3M
}
319
static int
320
zreadstring(i_ctx_t *i_ctx_p)
321
11.3M
{
322
11.3M
    os_ptr op = osp;
323
324
11.3M
    return zreadstring_at(i_ctx_p, op, 0);
325
11.3M
}
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
505k
{
347
505k
    os_ptr op = osp;
348
505k
    stream *s;
349
505k
    int status;
350
351
505k
    check_op(2);
352
505k
    check_write_file(s, op - 1);
353
504k
    check_read_type(*op, t_string);
354
504k
    status = write_string(op, s);
355
504k
    if (status >= 0) {
356
504k
        pop(2);
357
504k
        return 0;
358
504k
    }
359
0
    return handle_write_status(i_ctx_p, status, op - 1, NULL, zwritestring);
360
504k
}
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
44
{
379
44
    stream *s;
380
44
    int status;
381
44
    gs_string str;
382
383
44
    check_write_type(*op, t_string);
384
44
    check_read_file(i_ctx_p, s, op - 1);
385
38
    str.data = op->value.bytes;
386
38
    str.size = r_size(op);
387
38
    status = zreadline_from(s, &str, NULL, &count, &in_eol);
388
38
    switch (status) {
389
38
        case 0:
390
38
        case EOFC:
391
38
            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
38
    }
407
38
    r_set_size(op, count);
408
38
    op[-1] = *op;
409
38
    make_bool(op, status == 0);
410
38
    return 0;
411
38
}
412
static int
413
zreadline(i_ctx_t *i_ctx_p)
414
58
{
415
58
    os_ptr op = osp;
416
58
    check_op(2);
417
418
44
    return zreadline_at(i_ctx_p, op, 0, false);
419
58
}
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
38
{
448
38
    sreadline_proc((*readline));
449
450
38
    if (zis_stdin(s))
451
0
        readline = gp_readline;
452
38
    else
453
38
        readline = sreadline;
454
38
    return readline(s, NULL, NULL /*WRONG*/, NULL, buf, bufmem,
455
38
                    pcount, pin_eol, zis_stdin);
456
38
}
457
458
/* <file> bytesavailable <int> */
459
static int
460
zbytesavailable(i_ctx_t *i_ctx_p)
461
11
{
462
11
    os_ptr op = osp;
463
11
    stream *s;
464
11
    gs_offset_t avail;
465
466
11
    check_op(1);
467
11
    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
403k
{
487
403k
    stream *s;
488
403k
    int status;
489
403k
    ref rstdout;
490
403k
    int code = zget_stdout(i_ctx_p, &s);
491
492
403k
    if (code < 0)
493
0
        return code;
494
495
403k
    make_stream_file(&rstdout, s, "w");
496
403k
    status = sflush(s);
497
403k
    if (status == 0 || status == EOFC) {
498
403k
        return 0;
499
403k
    }
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
403k
}
505
506
/* <file> flushfile - */
507
static int
508
zflushfile(i_ctx_t *i_ctx_p)
509
761k
{
510
761k
    os_ptr op = osp;
511
761k
    stream *s;
512
761k
    int status;
513
514
761k
    check_op(1);
515
761k
    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
761k
    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
761k
    status = sflush(s);
527
761k
    if (status == 0 || status == EOFC) {
528
761k
        pop(1);
529
761k
        return 0;
530
761k
    }
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
761k
}
536
537
/* <file> resetfile - */
538
static int
539
zresetfile(i_ctx_t *i_ctx_p)
540
12
{
541
12
    os_ptr op = osp;
542
12
    stream *s;
543
544
12
    check_op(1);
545
    /* According to Adobe, resetfile is a no-op on closed files. */
546
4
    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
4
}
552
553
/* <string> print - */
554
static int
555
zprint(i_ctx_t *i_ctx_p)
556
38.2M
{
557
38.2M
    os_ptr op = osp;
558
38.2M
    stream *s;
559
38.2M
    int status;
560
38.2M
    ref rstdout;
561
38.2M
    int code;
562
563
38.2M
    check_op(1);
564
38.2M
    check_read_type(*op, t_string);
565
38.2M
    code = zget_stdout(i_ctx_p, &s);
566
38.2M
    if (code < 0)
567
0
        return code;
568
38.2M
    status = write_string(op, s);
569
38.2M
    if (status >= 0) {
570
38.2M
        pop(1);
571
38.2M
        return 0;
572
38.2M
    }
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
8
{
589
8
    os_ptr op = osp;
590
591
8
    check_op(1);
592
8
    check_type(*op, t_boolean);
593
    /****** NOT IMPLEMENTED YET ******/
594
0
    pop(1);
595
0
    return 0;
596
8
}
597
598
/* ------ Level 2 extensions ------ */
599
600
/* <file> fileposition <int> */
601
static int
602
zfileposition(i_ctx_t *i_ctx_p)
603
232k
{
604
232k
    os_ptr op = osp;
605
232k
    stream *s;
606
607
232k
    check_op(1);
608
232k
    check_file(s, op);
609
    /*
610
     * The PLRM says fileposition must give an error for non-seekable
611
     * streams.
612
     */
613
232k
    if (!s_can_seek(s))
614
232k
        return_error(gs_error_ioerror);
615
0
    make_int(op, stell(s));
616
0
    return 0;
617
232k
}
618
/* <file> .fileposition <int> */
619
static int
620
zxfileposition(i_ctx_t *i_ctx_p)
621
6
{
622
6
    os_ptr op = osp;
623
6
    stream *s;
624
625
6
    check_op(1);
626
6
    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
121k
{
639
121k
    os_ptr op = osp;
640
121k
    stream *s;
641
642
121k
    check_op(2);
643
121k
    check_type(*op, t_integer);
644
121k
    if ((gs_offset_t)op->value.intval < 0)
645
0
        return_error(gs_error_rangecheck);
646
121k
    check_file(s, op - 1);
647
121k
    if (sseek(s, (gs_offset_t)op->value.intval) < 0)
648
65
        return_error(gs_error_ioerror);
649
120k
    pop(2);
650
120k
    return 0;
651
121k
}
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
324k
{
660
324k
    os_ptr op = osp;
661
324k
    stream *s;
662
324k
    gs_const_string fname;
663
324k
    byte *str;
664
665
324k
    check_op(1);
666
324k
    check_file(s, op);
667
324k
    if (sfilename(s, &fname) < 0) {
668
0
        make_false(op);
669
0
        return 0;
670
0
    }
671
324k
    check_ostack(1);
672
324k
    str = ialloc_string(fname.size, "filename");
673
324k
    if (str == 0)
674
0
        return_error(gs_error_VMerror);
675
324k
    memcpy(str, fname.data, fname.size);
676
324k
    push(1);      /* can't fail */
677
324k
    make_const_string( op - 1 ,
678
324k
                      a_all | imemory_space((const struct gs_ref_memory_s*) imemory),
679
324k
                      fname.size,
680
324k
                      str);
681
324k
    make_true(op);
682
324k
    return 0;
683
324k
}
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
35.5M
{
704
35.5M
    os_ptr op = osp;
705
35.5M
    stream *s;
706
35.5M
    uint len, rlen = 0;
707
708
35.5M
    check_op(2);
709
35.5M
    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
35.5M
    if (s->end_status < 0 && sbufptr(s) - 1 == NULL) {
714
0
        return_error(gs_error_ioerror);
715
0
    }
716
35.5M
    check_write_type(*op, t_string);
717
35.5M
    len = r_size(op);
718
35.9M
    while ((rlen = sbufavailable(s)) < len) {
719
396k
        int status = s->end_status;
720
721
396k
        switch (status) {
722
81.4k
        case EOFC:
723
81.4k
            break;
724
314k
        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
314k
            if (len >= s->bsize)
731
0
                return_error(gs_error_rangecheck);
732
314k
            s_process_read_buf(s);
733
314k
            continue;
734
0
        default:
735
0
            return handle_read_status(i_ctx_p, status, op - 1, NULL,
736
0
                                      zpeekstring);
737
396k
        }
738
81.4k
        break;
739
396k
    }
740
35.5M
    if (rlen > len)
741
35.4M
        rlen = len;
742
    /* Don't remove the data from the buffer. */
743
35.5M
    memcpy(op->value.bytes, sbufptr(s), rlen);
744
35.5M
    r_set_size(op, rlen);
745
35.5M
    op[-1] = *op;
746
35.5M
    make_bool(op, (rlen == len ? 1 : 0));
747
35.5M
    return 0;
748
35.5M
}
749
750
/* <file> <int> .unread - */
751
static int
752
zunread(i_ctx_t *i_ctx_p)
753
26.0k
{
754
26.0k
    os_ptr op = osp;
755
26.0k
    stream *s;
756
26.0k
    ulong ch;
757
758
26.0k
    check_op(2);
759
26.0k
    check_read_file(i_ctx_p, s, op - 1);
760
26.0k
    check_type(*op, t_integer);
761
26.0k
    ch = op->value.intval;
762
26.0k
    if (ch > 0xff)
763
0
        return_error(gs_error_rangecheck);
764
26.0k
    if (sungetc(s, (byte) ch) < 0)
765
0
        return_error(gs_error_ioerror);
766
26.0k
    pop(2);
767
26.0k
    return 0;
768
26.0k
}
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
40.1M
{
775
40.1M
    stream *s;
776
40.1M
    byte str[100];    /* arbitrary */
777
40.1M
    ref rstr;
778
40.1M
    const byte *data = str;
779
40.1M
    uint len;
780
40.1M
    int code, status;
781
782
40.1M
    check_write_file(s, op - 2);
783
40.1M
    check_type(*op, t_integer);
784
40.1M
    code = obj_cvp(op - 1, str, sizeof(str), &len, (int)op->value.intval,
785
40.1M
                   start, imemory, true);
786
40.1M
    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
40.1M
    if (code < 0)
794
10
        return code;
795
40.1M
    r_set_size(&rstr, len);
796
40.1M
    rstr.value.const_bytes = data;
797
40.1M
    status = write_string(&rstr, s);
798
40.1M
    switch (status) {
799
0
        default:
800
0
            return_error(gs_error_ioerror);
801
40.1M
        case 0:
802
40.1M
            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
40.1M
    }
811
40.1M
    if (code == 1) {
812
2.56M
        if (first)
813
2.56M
            check_ostack(1);
814
2.56M
        push_op_estack(zwritecvp_continue);
815
2.56M
        if (first)
816
2.56M
            push(1);
817
2.56M
        make_int(osp, start + len);
818
2.56M
        return o_push_estack;
819
2.56M
    }
820
37.6M
    if (first)      /* zwritecvp */
821
36.7M
        pop(3);
822
824k
    else      /* zwritecvp_continue */
823
824k
        pop(4);
824
37.6M
    return 0;
825
40.1M
}
826
static int
827
zwritecvp(i_ctx_t *i_ctx_p)
828
37.6M
{
829
37.6M
    return zwritecvp_at(i_ctx_p, osp, 0, true);
830
37.6M
}
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
2.56M
{
836
2.56M
    os_ptr op = osp;
837
838
2.56M
    check_type(*op, t_integer);
839
2.56M
    if (op->value.intval != (uint) op->value.intval)
840
0
        return_error(gs_error_rangecheck);
841
2.56M
    return zwritecvp_at(i_ctx_p, op - 1, (uint) op->value.intval, false);
842
2.56M
}
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
94.5k
{
890
94.5k
    stream *s = fptr(op);
891
892
94.5k
    if (s->write_id != r_size(op) || s->file == 0)  /* not valid */
893
0
        return_error(gs_error_invalidaccess);
894
94.5k
    if (sswitch(s, false) < 0)
895
0
        return_error(gs_error_ioerror);
896
94.5k
    s->read_id = s->write_id; /* enable reading */
897
94.5k
    s->write_id = 0;    /* disable writing */
898
94.5k
    return 0;
899
94.5k
}
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
78.8M
{
924
78.8M
    const byte *data = op->value.const_bytes;
925
78.8M
    uint len = r_size(op);
926
78.8M
    uint wlen;
927
78.8M
    int status = sputs(s, data, len, &wlen);
928
929
78.8M
    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
78.8M
        default:    /* 0, EOFC, ERRC */
936
78.8M
            return status;
937
78.8M
    }
938
78.8M
}
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
3
{
947
3
    stream *s;
948
949
6
    for (s = fptr(fop); s->strm != 0 && s->state->error_string[0] == 0;)
950
3
        s = s->strm;
951
3
    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
3
    return_error(gs_error_ioerror);
959
3
}
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
3
{
969
3
    switch (ch) {
970
3
        default:    /* error */
971
3
            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
3
    }
986
3
}
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
184k
{
996
184k
    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
184k
        case CALLC:
1003
184k
            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
184k
                return s_handle_write_exception(i_ctx_p, ch, fop, NULL, 0,
1011
184k
                                                cont);
1012
184k
    }
1013
184k
}