Coverage Report

Created: 2026-10-28 08:05

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