Coverage Report

Created: 2022-10-31 07:00

/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
1.40M
{
47
1.40M
    os_ptr op = osp;
48
1.40M
    stream *s;
49
50
1.40M
    check_type(*op, t_file);
51
1.40M
    if (file_is_valid(s, op)) { /* closing a closed file is a no-op */
52
837k
        int status = sclose(s);
53
54
837k
        if (status != 0 && status != EOFC) {
55
193k
            if (s_is_writing(s))
56
193k
                return handle_write_status(i_ctx_p, status, op, NULL,
57
193k
                                           zclosefile);
58
0
            else
59
0
                return handle_read_status(i_ctx_p, status, op, NULL,
60
0
                                          zclosefile);
61
193k
        }
62
837k
    }
63
1.21M
    pop(1);
64
1.21M
    return 0;
65
1.40M
}
66
67
/* <file> read <int> -true- */
68
/* <file> read -false- */
69
static int
70
zread(i_ctx_t *i_ctx_p)
71
27.6M
{
72
27.6M
    os_ptr op = osp;
73
27.6M
    stream *s;
74
27.6M
    int ch;
75
76
27.6M
    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
27.6M
    push(1);
86
27.6M
    ch = sgetc(s);
87
27.6M
    if (ch >= 0) {
88
27.6M
        make_int(op - 1, ch);
89
27.6M
        make_bool(op, 1);
90
27.6M
    } else {
91
38
        pop(1);    /* Adjust ostack back from preparatory 'pop' */
92
38
        op--;
93
38
        if (ch == EOFC)
94
38
        make_bool(op, 0);
95
0
    else
96
0
        return handle_read_status(i_ctx_p, ch, op, NULL, zread);
97
38
    }
98
27.6M
    return 0;
99
27.6M
}
100
101
/* <file> <int> write - */
102
int
103
zwrite(i_ctx_t *i_ctx_p)
104
13
{
105
13
    os_ptr op = osp;
106
13
    stream *s;
107
13
    byte ch;
108
13
    int status;
109
110
13
    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
220
{
129
220
    stream *s;
130
220
    uint len, nread;
131
220
    byte *str;
132
220
    int odd_byte = odd;
133
220
    stream_cursor_write cw;
134
220
    int status;
135
136
220
    check_read_file(i_ctx_p, s, op - 1);
137
    /*check_write_type(*op, t_string); *//* done by caller */
138
218
    str = op->value.bytes;
139
218
    len = r_size(op);
140
218
    cw.ptr = str + start - 1;
141
218
    cw.limit = str + len - 1;
142
498
    for (;;) {
143
498
        status = s_hex_process(&s->cursor.r, &cw, &odd_byte,
144
498
                               hex_ignore_garbage);
145
498
        if (status == 1) { /* filled the string */
146
152
            ref_assign_inline(op - 1, op);
147
152
            make_true(op);
148
152
            return 0;
149
346
        } else if (status != 0)  /* error or EOF */
150
0
            break;
151
        /* Didn't fill, keep going. */
152
346
        status = spgetc(s);
153
346
        if (status < 0)
154
66
            break;
155
280
        sputback(s);
156
280
    }
157
66
    nread = cw.ptr + 1 - str;
158
66
    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
66
    ref_assign_inline(op - 1, op);
166
66
    r_set_size(op - 1, nread);
167
66
    make_false(op);
168
66
    return 0;
169
66
}
170
static int
171
zreadhexstring(i_ctx_t *i_ctx_p)
172
232
{
173
232
    os_ptr op = osp;
174
175
232
    check_write_type(*op, t_string);
176
220
    return zreadhexstring_at(i_ctx_p, op, 0, -1);
177
232
}
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
15
{
204
15
    register stream *s;
205
15
    register byte ch;
206
15
    register const byte *p;
207
15
    register const char *const hex_digits = "0123456789abcdef";
208
15
    register uint len;
209
15
    int status;
210
211
15
#define MAX_HEX 128
212
15
    byte buf[MAX_HEX];
213
214
15
    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
15
{
257
15
    os_ptr op = osp;
258
259
15
    return zwritehexstring_at(i_ctx_p, op, 0);
260
15
}
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
6.55M
{
283
6.55M
    stream *s;
284
6.55M
    uint len, rlen;
285
6.55M
    int status;
286
287
6.55M
    check_write_type(*op, t_string);
288
6.55M
    check_read_file(i_ctx_p, s, op - 1);
289
6.55M
    len = r_size(op);
290
6.55M
    status = sgets(s, op->value.bytes + start, len - start, &rlen);
291
6.55M
    rlen += start;
292
6.55M
    switch (status) {
293
40.8k
        case EOFC:
294
6.55M
        case 0:
295
6.55M
            break;
296
0
        default:
297
0
            return handle_read_status(i_ctx_p, status, op - 1, &rlen,
298
0
                                      zreadstring_continue);
299
6.55M
    }
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
6.55M
    if (len == 0)
308
0
        return_error(gs_error_rangecheck);
309
6.55M
    r_set_size(op, rlen);
310
6.55M
    op[-1] = *op;
311
6.55M
    make_bool(op, (rlen == len ? 1 : 0));
312
6.55M
    return 0;
313
6.55M
}
314
static int
315
zreadstring(i_ctx_t *i_ctx_p)
316
6.55M
{
317
6.55M
    os_ptr op = osp;
318
319
6.55M
    return zreadstring_at(i_ctx_p, op, 0);
320
6.55M
}
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
1.09M
{
342
1.09M
    os_ptr op = osp;
343
1.09M
    stream *s;
344
1.09M
    int status;
345
346
1.09M
    check_write_file(s, op - 1);
347
1.09M
    check_read_type(*op, t_string);
348
1.09M
    status = write_string(op, s);
349
1.09M
    if (status >= 0) {
350
1.09M
        pop(2);
351
1.09M
        return 0;
352
1.09M
    }
353
0
    return handle_write_status(i_ctx_p, status, op - 1, NULL, zwritestring);
354
1.09M
}
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
20
{
373
20
    stream *s;
374
20
    int status;
375
20
    gs_string str;
376
377
20
    check_write_type(*op, t_string);
378
20
    check_read_file(i_ctx_p, s, op - 1);
379
5
    str.data = op->value.bytes;
380
5
    str.size = r_size(op);
381
5
    status = zreadline_from(s, &str, NULL, &count, &in_eol);
382
5
    switch (status) {
383
5
        case 0:
384
5
        case EOFC:
385
5
            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
5
    }
401
5
    r_set_size(op, count);
402
5
    op[-1] = *op;
403
5
    make_bool(op, status == 0);
404
5
    return 0;
405
5
}
406
static int
407
zreadline(i_ctx_t *i_ctx_p)
408
20
{
409
20
    os_ptr op = osp;
410
411
20
    return zreadline_at(i_ctx_p, op, 0, false);
412
20
}
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
5
{
441
5
    sreadline_proc((*readline));
442
443
5
    if (zis_stdin(s))
444
0
        readline = gp_readline;
445
5
    else
446
5
        readline = sreadline;
447
5
    return readline(s, NULL, NULL /*WRONG*/, NULL, buf, bufmem,
448
5
                    pcount, pin_eol, zis_stdin);
449
5
}
450
451
/* <file> bytesavailable <int> */
452
static int
453
zbytesavailable(i_ctx_t *i_ctx_p)
454
5
{
455
5
    os_ptr op = osp;
456
5
    stream *s;
457
5
    gs_offset_t avail;
458
459
5
    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
1.53M
{
479
1.53M
    stream *s;
480
1.53M
    int status;
481
1.53M
    ref rstdout;
482
1.53M
    int code = zget_stdout(i_ctx_p, &s);
483
484
1.53M
    if (code < 0)
485
0
        return code;
486
487
1.53M
    make_stream_file(&rstdout, s, "w");
488
1.53M
    status = sflush(s);
489
1.53M
    if (status == 0 || status == EOFC) {
490
1.53M
        return 0;
491
1.53M
    }
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
1.53M
}
497
498
/* <file> flushfile - */
499
static int
500
zflushfile(i_ctx_t *i_ctx_p)
501
373k
{
502
373k
    os_ptr op = osp;
503
373k
    stream *s;
504
373k
    int status;
505
506
373k
    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
373k
    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
373k
    status = sflush(s);
518
373k
    if (status == 0 || status == EOFC) {
519
373k
        pop(1);
520
373k
        return 0;
521
373k
    }
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
373k
}
527
528
/* <file> resetfile - */
529
static int
530
zresetfile(i_ctx_t *i_ctx_p)
531
7
{
532
7
    os_ptr op = osp;
533
7
    stream *s;
534
535
    /* According to Adobe, resetfile is a no-op on closed files. */
536
7
    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
7
}
542
543
/* <string> print - */
544
static int
545
zprint(i_ctx_t *i_ctx_p)
546
19.8M
{
547
19.8M
    os_ptr op = osp;
548
19.8M
    stream *s;
549
19.8M
    int status;
550
19.8M
    ref rstdout;
551
19.8M
    int code;
552
553
19.8M
    check_read_type(*op, t_string);
554
19.8M
    code = zget_stdout(i_ctx_p, &s);
555
19.8M
    if (code < 0)
556
0
        return code;
557
19.8M
    status = write_string(op, s);
558
19.8M
    if (status >= 0) {
559
19.8M
        pop(1);
560
19.8M
        return 0;
561
19.8M
    }
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
4
{
578
4
    os_ptr op = osp;
579
580
4
    check_type(*op, t_boolean);
581
    /****** NOT IMPLEMENTED YET ******/
582
0
    pop(1);
583
0
    return 0;
584
4
}
585
586
/* ------ Level 2 extensions ------ */
587
588
/* <file> fileposition <int> */
589
static int
590
zfileposition(i_ctx_t *i_ctx_p)
591
78.4k
{
592
78.4k
    os_ptr op = osp;
593
78.4k
    stream *s;
594
595
78.4k
    check_file(s, op);
596
    /*
597
     * The PLRM says fileposition must give an error for non-seekable
598
     * streams.
599
     */
600
78.4k
    if (!s_can_seek(s))
601
78.4k
        return_error(gs_error_ioerror);
602
0
    make_int(op, stell(s));
603
0
    return 0;
604
78.4k
}
605
/* <file> .fileposition <int> */
606
static int
607
zxfileposition(i_ctx_t *i_ctx_p)
608
3
{
609
3
    os_ptr op = osp;
610
3
    stream *s;
611
612
3
    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
3
}
620
621
/* <file> <int> setfileposition - */
622
static int
623
zsetfileposition(i_ctx_t *i_ctx_p)
624
56.0k
{
625
56.0k
    os_ptr op = osp;
626
56.0k
    stream *s;
627
628
56.0k
    check_type(*op, t_integer);
629
56.0k
    check_file(s, op - 1);
630
56.0k
    if (sseek(s, (gs_offset_t)op->value.intval) < 0)
631
11
        return_error(gs_error_ioerror);
632
55.9k
    pop(2);
633
55.9k
    return 0;
634
56.0k
}
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
178k
{
643
178k
    os_ptr op = osp;
644
178k
    stream *s;
645
178k
    gs_const_string fname;
646
178k
    byte *str;
647
648
178k
    check_file(s, op);
649
178k
    if (sfilename(s, &fname) < 0) {
650
0
        make_false(op);
651
0
        return 0;
652
0
    }
653
178k
    check_ostack(1);
654
178k
    str = ialloc_string(fname.size, "filename");
655
178k
    if (str == 0)
656
0
        return_error(gs_error_VMerror);
657
178k
    memcpy(str, fname.data, fname.size);
658
178k
    push(1);      /* can't fail */
659
178k
    make_const_string( op - 1 ,
660
178k
                      a_all | imemory_space((const struct gs_ref_memory_s*) imemory),
661
178k
                      fname.size,
662
178k
                      str);
663
178k
    make_true(op);
664
178k
    return 0;
665
178k
}
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
28.2M
{
685
28.2M
    os_ptr op = osp;
686
28.2M
    stream *s;
687
28.2M
    uint len, rlen;
688
689
28.2M
    check_read_file(i_ctx_p, s, op - 1);
690
28.2M
    check_write_type(*op, t_string);
691
28.2M
    len = r_size(op);
692
28.4M
    while ((rlen = sbufavailable(s)) < len) {
693
240k
        int status = s->end_status;
694
695
240k
        switch (status) {
696
50.9k
        case EOFC:
697
50.9k
            break;
698
189k
        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
189k
            if (len >= s->bsize)
705
0
                return_error(gs_error_rangecheck);
706
189k
            s_process_read_buf(s);
707
189k
            continue;
708
1
        default:
709
1
            return handle_read_status(i_ctx_p, status, op - 1, NULL,
710
1
                                      zpeekstring);
711
240k
        }
712
50.9k
        break;
713
240k
    }
714
28.2M
    if (rlen > len)
715
28.1M
        rlen = len;
716
    /* Don't remove the data from the buffer. */
717
28.2M
    memcpy(op->value.bytes, sbufptr(s), rlen);
718
28.2M
    r_set_size(op, rlen);
719
28.2M
    op[-1] = *op;
720
28.2M
    make_bool(op, (rlen == len ? 1 : 0));
721
28.2M
    return 0;
722
28.2M
}
723
724
/* <file> <int> .unread - */
725
static int
726
zunread(i_ctx_t *i_ctx_p)
727
15.0k
{
728
15.0k
    os_ptr op = osp;
729
15.0k
    stream *s;
730
15.0k
    ulong ch;
731
732
15.0k
    check_read_file(i_ctx_p, s, op - 1);
733
15.0k
    check_type(*op, t_integer);
734
15.0k
    ch = op->value.intval;
735
15.0k
    if (ch > 0xff)
736
0
        return_error(gs_error_rangecheck);
737
15.0k
    if (sungetc(s, (byte) ch) < 0)
738
0
        return_error(gs_error_ioerror);
739
15.0k
    pop(2);
740
15.0k
    return 0;
741
15.0k
}
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
20.5M
{
748
20.5M
    stream *s;
749
20.5M
    byte str[100];    /* arbitrary */
750
20.5M
    ref rstr;
751
20.5M
    const byte *data = str;
752
20.5M
    uint len;
753
20.5M
    int code, status;
754
755
20.5M
    check_write_file(s, op - 2);
756
20.5M
    check_type(*op, t_integer);
757
20.5M
    code = obj_cvp(op - 1, str, sizeof(str), &len, (int)op->value.intval,
758
20.5M
                   start, imemory, true);
759
20.5M
    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
20.5M
    if (code < 0)
767
2
        return code;
768
20.5M
    r_set_size(&rstr, len);
769
20.5M
    rstr.value.const_bytes = data;
770
20.5M
    status = write_string(&rstr, s);
771
20.5M
    switch (status) {
772
0
        default:
773
0
            return_error(gs_error_ioerror);
774
20.5M
        case 0:
775
20.5M
            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
20.5M
    }
784
20.5M
    if (code == 1) {
785
359k
        if (first)
786
359k
            check_ostack(1);
787
359k
        push_op_estack(zwritecvp_continue);
788
359k
        if (first)
789
359k
            push(1);
790
359k
        make_int(osp, start + len);
791
359k
        return o_push_estack;
792
359k
    }
793
20.1M
    if (first)      /* zwritecvp */
794
20.0M
        pop(3);
795
51.2k
    else      /* zwritecvp_continue */
796
51.2k
        pop(4);
797
20.1M
    return 0;
798
20.5M
}
799
static int
800
zwritecvp(i_ctx_t *i_ctx_p)
801
20.1M
{
802
20.1M
    return zwritecvp_at(i_ctx_p, osp, 0, true);
803
20.1M
}
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
359k
{
809
359k
    os_ptr op = osp;
810
811
359k
    check_type(*op, t_integer);
812
359k
    if (op->value.intval != (uint) op->value.intval)
813
0
        return_error(gs_error_rangecheck);
814
359k
    return zwritecvp_at(i_ctx_p, op - 1, (uint) op->value.intval, false);
815
359k
}
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
40.8k
{
863
40.8k
    stream *s = fptr(op);
864
865
40.8k
    if (s->write_id != r_size(op) || s->file == 0)  /* not valid */
866
0
        return_error(gs_error_invalidaccess);
867
40.8k
    if (sswitch(s, false) < 0)
868
0
        return_error(gs_error_ioerror);
869
40.8k
    s->read_id = s->write_id; /* enable reading */
870
40.8k
    s->write_id = 0;    /* disable writing */
871
40.8k
    return 0;
872
40.8k
}
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
41.4M
{
897
41.4M
    const byte *data = op->value.const_bytes;
898
41.4M
    uint len = r_size(op);
899
41.4M
    uint wlen;
900
41.4M
    int status = sputs(s, data, len, &wlen);
901
902
41.4M
    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
41.4M
        default:    /* 0, EOFC, ERRC */
909
41.4M
            return status;
910
41.4M
    }
911
41.4M
}
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
1
{
920
1
    stream *s;
921
922
2
    for (s = fptr(fop); s->strm != 0 && s->state->error_string[0] == 0;)
923
1
        s = s->strm;
924
1
    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
1
    return_error(gs_error_ioerror);
932
1
}
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
1
{
942
1
    switch (ch) {
943
1
        default:    /* error */
944
1
            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
1
    }
959
1
}
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
193k
{
969
193k
    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
193k
        case CALLC:
976
193k
            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
193k
                return s_handle_write_exception(i_ctx_p, ch, fop, NULL, 0,
984
193k
                                                cont);
985
193k
    }
986
193k
}