Coverage Report

Created: 2022-04-16 11:23

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