Coverage Report

Created: 2025-06-10 07:06

/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
117k
{
47
117k
    os_ptr op = osp;
48
117k
    stream *s;
49
50
117k
    check_op(1);
51
117k
    check_type(*op, t_file);
52
117k
    if (file_is_valid(s, op)) { /* closing a closed file is a no-op */
53
58.6k
        int status = sclose(s);
54
55
58.6k
        if (status != 0 && status != EOFC) {
56
202
            if (s_is_writing(s))
57
202
                return handle_write_status(i_ctx_p, status, op, NULL,
58
202
                                           zclosefile);
59
0
            else
60
0
                return handle_read_status(i_ctx_p, status, op, NULL,
61
0
                                          zclosefile);
62
202
        }
63
58.6k
    }
64
117k
    pop(1);
65
117k
    return 0;
66
117k
}
67
68
/* <file> read <int> -true- */
69
/* <file> read -false- */
70
static int
71
zread(i_ctx_t *i_ctx_p)
72
1.90M
{
73
1.90M
    os_ptr op = osp;
74
1.90M
    stream *s;
75
1.90M
    int ch;
76
77
1.90M
    check_op(1);
78
1.90M
    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.90M
    push(1);
88
1.90M
    ch = sgetc(s);
89
1.90M
    if (ch >= 0) {
90
1.90M
        make_int(op - 1, ch);
91
1.90M
        make_bool(op, 1);
92
1.90M
    } else {
93
5
        pop(1);    /* Adjust ostack back from preparatory 'pop' */
94
5
        op--;
95
5
        if (ch == EOFC)
96
5
        make_bool(op, 0);
97
0
    else
98
0
        return handle_read_status(i_ctx_p, ch, op, NULL, zread);
99
5
    }
100
1.90M
    return 0;
101
1.90M
}
102
103
/* <file> <int> write - */
104
int
105
zwrite(i_ctx_t *i_ctx_p)
106
1
{
107
1
    os_ptr op = osp;
108
1
    stream *s;
109
1
    byte ch;
110
1
    int status;
111
112
1
    check_op(1);
113
1
    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
3
{
132
3
    stream *s;
133
3
    uint len, nread;
134
3
    byte *str;
135
3
    int odd_byte = odd;
136
3
    stream_cursor_write cw;
137
3
    int status;
138
139
3
    check_read_file(i_ctx_p, s, op - 1);
140
    /*check_write_type(*op, t_string); *//* done by caller */
141
3
    str = op->value.bytes;
142
3
    len = r_size(op);
143
3
    cw.ptr = str + start - 1;
144
3
    cw.limit = str + len - 1;
145
6
    for (;;) {
146
6
        status = s_hex_process(&s->cursor.r, &cw, &odd_byte,
147
6
                               hex_ignore_garbage);
148
6
        if (status == 1) { /* filled the string */
149
0
            ref_assign_inline(op - 1, op);
150
0
            make_true(op);
151
0
            return 0;
152
6
        } else if (status != 0)  /* error or EOF */
153
0
            break;
154
        /* Didn't fill, keep going. */
155
6
        status = spgetc(s);
156
6
        if (status < 0)
157
3
            break;
158
3
        sputback(s);
159
3
    }
160
3
    nread = cw.ptr + 1 - str;
161
3
    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
3
    ref_assign_inline(op - 1, op);
169
3
    r_set_size(op - 1, nread);
170
3
    make_false(op);
171
3
    return 0;
172
3
}
173
static int
174
zreadhexstring(i_ctx_t *i_ctx_p)
175
4
{
176
4
    os_ptr op = osp;
177
178
4
    check_op(2);
179
3
    check_write_type(*op, t_string);
180
3
    return zreadhexstring_at(i_ctx_p, op, 0, -1);
181
3
}
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
340k
{
288
340k
    stream *s;
289
340k
    uint len, rlen;
290
340k
    int status;
291
292
340k
    check_write_type(*op, t_string);
293
340k
    check_read_file(i_ctx_p, s, op - 1);
294
340k
    len = r_size(op);
295
340k
    status = sgets(s, op->value.bytes + start, len - start, &rlen);
296
340k
    rlen += start;
297
340k
    switch (status) {
298
5.40k
        case EOFC:
299
340k
        case 0:
300
340k
            break;
301
1
        default:
302
1
            return handle_read_status(i_ctx_p, status, op - 1, &rlen,
303
1
                                      zreadstring_continue);
304
340k
    }
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
340k
    if (len == 0)
313
0
        return_error(gs_error_rangecheck);
314
340k
    r_set_size(op, rlen);
315
340k
    op[-1] = *op;
316
340k
    make_bool(op, (rlen == len ? 1 : 0));
317
340k
    return 0;
318
340k
}
319
static int
320
zreadstring(i_ctx_t *i_ctx_p)
321
340k
{
322
340k
    os_ptr op = osp;
323
324
340k
    return zreadstring_at(i_ctx_p, op, 0);
325
340k
}
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
18.5k
{
347
18.5k
    os_ptr op = osp;
348
18.5k
    stream *s;
349
18.5k
    int status;
350
351
18.5k
    check_op(2);
352
18.5k
    check_write_file(s, op - 1);
353
18.5k
    check_read_type(*op, t_string);
354
18.5k
    status = write_string(op, s);
355
18.5k
    if (status >= 0) {
356
18.5k
        pop(2);
357
18.5k
        return 0;
358
18.5k
    }
359
0
    return handle_write_status(i_ctx_p, status, op - 1, NULL, zwritestring);
360
18.5k
}
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
0
{
462
0
    os_ptr op = osp;
463
0
    stream *s;
464
0
    gs_offset_t avail;
465
466
0
    check_op(1);
467
0
    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
23.7k
{
487
23.7k
    stream *s;
488
23.7k
    int status;
489
23.7k
    ref rstdout;
490
23.7k
    int code = zget_stdout(i_ctx_p, &s);
491
492
23.7k
    if (code < 0)
493
0
        return code;
494
495
23.7k
    make_stream_file(&rstdout, s, "w");
496
23.7k
    status = sflush(s);
497
23.7k
    if (status == 0 || status == EOFC) {
498
23.7k
        return 0;
499
23.7k
    }
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
23.7k
}
505
506
/* <file> flushfile - */
507
static int
508
zflushfile(i_ctx_t *i_ctx_p)
509
37.2k
{
510
37.2k
    os_ptr op = osp;
511
37.2k
    stream *s;
512
37.2k
    int status;
513
514
37.2k
    check_op(1);
515
37.2k
    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
37.2k
    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
37.2k
    status = sflush(s);
527
37.2k
    if (status == 0 || status == EOFC) {
528
37.2k
        pop(1);
529
37.2k
        return 0;
530
37.2k
    }
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
37.2k
}
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
0
    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
0
}
552
553
/* <string> print - */
554
static int
555
zprint(i_ctx_t *i_ctx_p)
556
1.95M
{
557
1.95M
    os_ptr op = osp;
558
1.95M
    stream *s;
559
1.95M
    int status;
560
1.95M
    ref rstdout;
561
1.95M
    int code;
562
563
1.95M
    check_op(1);
564
1.95M
    check_read_type(*op, t_string);
565
1.95M
    code = zget_stdout(i_ctx_p, &s);
566
1.95M
    if (code < 0)
567
0
        return code;
568
1.95M
    status = write_string(op, s);
569
1.95M
    if (status >= 0) {
570
1.95M
        pop(1);
571
1.95M
        return 0;
572
1.95M
    }
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
1
{
589
1
    os_ptr op = osp;
590
591
1
    check_op(1);
592
1
    check_type(*op, t_boolean);
593
    /****** NOT IMPLEMENTED YET ******/
594
0
    pop(1);
595
0
    return 0;
596
1
}
597
598
/* ------ Level 2 extensions ------ */
599
600
/* <file> fileposition <int> */
601
static int
602
zfileposition(i_ctx_t *i_ctx_p)
603
2.15k
{
604
2.15k
    os_ptr op = osp;
605
2.15k
    stream *s;
606
607
2.15k
    check_op(1);
608
2.15k
    check_file(s, op);
609
    /*
610
     * The PLRM says fileposition must give an error for non-seekable
611
     * streams.
612
     */
613
2.15k
    if (!s_can_seek(s))
614
2.15k
        return_error(gs_error_ioerror);
615
0
    make_int(op, stell(s));
616
0
    return 0;
617
2.15k
}
618
/* <file> .fileposition <int> */
619
static int
620
zxfileposition(i_ctx_t *i_ctx_p)
621
0
{
622
0
    os_ptr op = osp;
623
0
    stream *s;
624
625
0
    check_op(1);
626
0
    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
6.17k
{
639
6.17k
    os_ptr op = osp;
640
6.17k
    stream *s;
641
642
6.17k
    check_op(2);
643
6.17k
    check_type(*op, t_integer);
644
6.17k
    if ((gs_offset_t)op->value.intval < 0)
645
0
        return_error(gs_error_rangecheck);
646
6.17k
    check_file(s, op - 1);
647
6.17k
    if (sseek(s, (gs_offset_t)op->value.intval) < 0)
648
1
        return_error(gs_error_ioerror);
649
6.17k
    pop(2);
650
6.17k
    return 0;
651
6.17k
}
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
18.4k
{
660
18.4k
    os_ptr op = osp;
661
18.4k
    stream *s;
662
18.4k
    gs_const_string fname;
663
18.4k
    byte *str;
664
665
18.4k
    check_op(1);
666
18.4k
    check_file(s, op);
667
18.4k
    if (sfilename(s, &fname) < 0) {
668
0
        make_false(op);
669
0
        return 0;
670
0
    }
671
18.4k
    check_ostack(1);
672
18.4k
    str = ialloc_string(fname.size, "filename");
673
18.4k
    if (str == 0)
674
0
        return_error(gs_error_VMerror);
675
18.4k
    memcpy(str, fname.data, fname.size);
676
18.4k
    push(1);      /* can't fail */
677
18.4k
    make_const_string( op - 1 ,
678
18.4k
                      a_all | imemory_space((const struct gs_ref_memory_s*) imemory),
679
18.4k
                      fname.size,
680
18.4k
                      str);
681
18.4k
    make_true(op);
682
18.4k
    return 0;
683
18.4k
}
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.94M
{
704
1.94M
    os_ptr op = osp;
705
1.94M
    stream *s;
706
1.94M
    uint len, rlen = 0;
707
708
1.94M
    check_op(2);
709
1.94M
    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.94M
    if (s->end_status < 0 && sbufptr(s) - 1 == NULL) {
714
0
        return_error(gs_error_ioerror);
715
0
    }
716
1.94M
    check_write_type(*op, t_string);
717
1.94M
    len = r_size(op);
718
1.95M
    while ((rlen = sbufavailable(s)) < len) {
719
21.7k
        int status = s->end_status;
720
721
21.7k
        switch (status) {
722
5.35k
        case EOFC:
723
5.35k
            break;
724
16.3k
        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.3k
            if (len >= s->bsize)
731
0
                return_error(gs_error_rangecheck);
732
16.3k
            s_process_read_buf(s);
733
16.3k
            continue;
734
0
        default:
735
0
            return handle_read_status(i_ctx_p, status, op - 1, NULL,
736
0
                                      zpeekstring);
737
21.7k
        }
738
5.35k
        break;
739
21.7k
    }
740
1.94M
    if (rlen > len)
741
1.93M
        rlen = len;
742
    /* Don't remove the data from the buffer. */
743
1.94M
    memcpy(op->value.bytes, sbufptr(s), rlen);
744
1.94M
    r_set_size(op, rlen);
745
1.94M
    op[-1] = *op;
746
1.94M
    make_bool(op, (rlen == len ? 1 : 0));
747
1.94M
    return 0;
748
1.94M
}
749
750
/* <file> <int> .unread - */
751
static int
752
zunread(i_ctx_t *i_ctx_p)
753
774
{
754
774
    os_ptr op = osp;
755
774
    stream *s;
756
774
    ulong ch;
757
758
774
    check_op(2);
759
774
    check_read_file(i_ctx_p, s, op - 1);
760
774
    check_type(*op, t_integer);
761
774
    ch = op->value.intval;
762
774
    if (ch > 0xff)
763
0
        return_error(gs_error_rangecheck);
764
774
    if (sungetc(s, (byte) ch) < 0)
765
0
        return_error(gs_error_ioerror);
766
774
    pop(2);
767
774
    return 0;
768
774
}
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.92M
{
775
1.92M
    stream *s;
776
1.92M
    byte str[100];    /* arbitrary */
777
1.92M
    ref rstr;
778
1.92M
    const byte *data = str;
779
1.92M
    uint len;
780
1.92M
    int code, status;
781
782
1.92M
    check_write_file(s, op - 2);
783
1.92M
    check_type(*op, t_integer);
784
1.92M
    code = obj_cvp(op - 1, str, sizeof(str), &len, (int)op->value.intval,
785
1.92M
                   start, imemory, true);
786
1.92M
    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.92M
    if (code < 0)
794
0
        return code;
795
1.92M
    r_set_size(&rstr, len);
796
1.92M
    rstr.value.const_bytes = data;
797
1.92M
    status = write_string(&rstr, s);
798
1.92M
    switch (status) {
799
0
        default:
800
0
            return_error(gs_error_ioerror);
801
1.92M
        case 0:
802
1.92M
            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.92M
    }
811
1.92M
    if (code == 1) {
812
3.32k
        if (first)
813
3.32k
            check_ostack(1);
814
3.32k
        push_op_estack(zwritecvp_continue);
815
3.32k
        if (first)
816
3.32k
            push(1);
817
3.32k
        make_int(osp, start + len);
818
3.32k
        return o_push_estack;
819
3.32k
    }
820
1.91M
    if (first)      /* zwritecvp */
821
1.91M
        pop(3);
822
1.34k
    else      /* zwritecvp_continue */
823
1.34k
        pop(4);
824
1.91M
    return 0;
825
1.92M
}
826
static int
827
zwritecvp(i_ctx_t *i_ctx_p)
828
1.91M
{
829
1.91M
    return zwritecvp_at(i_ctx_p, osp, 0, true);
830
1.91M
}
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.32k
{
836
3.32k
    os_ptr op = osp;
837
838
3.32k
    check_type(*op, t_integer);
839
3.32k
    if (op->value.intval != (uint) op->value.intval)
840
0
        return_error(gs_error_rangecheck);
841
3.32k
    return zwritecvp_at(i_ctx_p, op - 1, (uint) op->value.intval, false);
842
3.32k
}
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
5.40k
{
890
5.40k
    stream *s = fptr(op);
891
892
5.40k
    if (s->write_id != r_size(op) || s->file == 0)  /* not valid */
893
0
        return_error(gs_error_invalidaccess);
894
5.40k
    if (sswitch(s, false) < 0)
895
0
        return_error(gs_error_ioerror);
896
5.40k
    s->read_id = s->write_id; /* enable reading */
897
5.40k
    s->write_id = 0;    /* disable writing */
898
5.40k
    return 0;
899
5.40k
}
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
3.89M
{
924
3.89M
    const byte *data = op->value.const_bytes;
925
3.89M
    uint len = r_size(op);
926
3.89M
    uint wlen;
927
3.89M
    int status = sputs(s, data, len, &wlen);
928
929
3.89M
    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
3.89M
        default:    /* 0, EOFC, ERRC */
936
3.89M
            return status;
937
3.89M
    }
938
3.89M
}
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
1
{
947
1
    stream *s;
948
949
2
    for (s = fptr(fop); s->strm != 0 && s->state->error_string[0] == 0;)
950
1
        s = s->strm;
951
1
    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
1
    return_error(gs_error_ioerror);
959
1
}
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
1
{
969
1
    switch (ch) {
970
1
        default:    /* error */
971
1
            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
1
    }
986
1
}
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
202
{
996
202
    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
202
        case CALLC:
1003
202
            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
202
                return s_handle_write_exception(i_ctx_p, ch, fop, NULL, 0,
1011
202
                                                cont);
1012
202
    }
1013
202
}