Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/base/strmio.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2023 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
17
/* Interface for streams that mimic stdio functions (fopen, fread, fseek, ftell) */
18
19
#include "malloc_.h"
20
#include "memory_.h"
21
#include "gxiodev.h"
22
#include "gdebug.h"
23
#include "gsfname.h"
24
#include "gslibctx.h"
25
#include "gsmemret.h" /* for gs_memory_type_ptr_t */
26
#include "gsmalloc.h"
27
#include "gsstype.h"
28
#include "stream.h"
29
#include "strmio.h"
30
#include "gserrors.h"
31
32
/*
33
 * Open a stream using a filename that can include a PS style IODevice prefix
34
 * If iodev_default is the '%os' device, then the file will be on the host
35
 * file system transparently to the caller. The "%os%" prefix can be used
36
 * to explicilty access the host file system.
37
 */
38
stream *
39
sfopen(const char *path, const char *mode, gs_memory_t *mem)
40
57.2M
{
41
57.2M
    gs_parsed_file_name_t pfn;
42
57.2M
    stream *s;
43
57.2M
    iodev_proc_open_file((*open_file));
44
45
57.2M
    int code = gs_parse_file_name(&pfn, path, strlen(path), mem);
46
57.2M
    if (code < 0) {
47
0
#       define EMSG     "sfopen: gs_parse_file_name failed.\n"
48
0
        errwrite(mem, EMSG, strlen(EMSG));
49
0
#       undef EMSG
50
0
        return NULL;
51
0
    }
52
57.2M
    if (pfn.fname == NULL) {    /* just a device */
53
0
#       define EMSG     "sfopen: not allowed with %device only.\n"
54
0
        errwrite(mem, EMSG, strlen(EMSG));
55
0
#       undef EMSG
56
0
        return NULL;
57
0
    }
58
57.2M
    if (pfn.iodev == NULL)
59
37.1M
        pfn.iodev = iodev_default(mem);
60
57.2M
    open_file = pfn.iodev->procs.open_file;
61
57.2M
    if (open_file == 0)
62
37.1M
        code = file_open_stream(pfn.fname, pfn.len, mode, 2048, &s,
63
37.1M
                                pfn.iodev, pfn.iodev->procs.gp_fopen, mem);
64
20.1M
    else
65
20.1M
        code = open_file(pfn.iodev, pfn.fname, pfn.len, mode, &s, mem);
66
57.2M
    if (code < 0)
67
43.7M
        return NULL;
68
13.5M
    s->position = 0;
69
13.5M
    code = ssetfilename(s, (const byte *)path, strlen(path));
70
13.5M
    if (code < 0) {
71
        /* Only error is gs_error_VMerror */
72
0
        sclose(s);
73
0
        gs_free_object(s->memory, s, "sfopen: allocation error");
74
0
#       define EMSG     "sfopen: allocation error setting path name into stream.\n"
75
0
        errwrite(mem, EMSG, strlen(EMSG));
76
0
#       undef EMSG
77
0
        return NULL;
78
0
    }
79
13.5M
    return s;
80
13.5M
}
81
82
/*
83
 * Read a number of bytes from a stream, returning number read. Return count
84
 * will be less than count if EOF or error. Return count is number of elements.
85
 */
86
int
87
sfread(void *ptr, size_t size, size_t count, stream *s)
88
14.8M
{
89
14.8M
    int code;
90
14.8M
    uint nread;
91
92
14.8M
    code = sgets(s, ptr, size*count, &nread);
93
14.8M
    if (code < 0)
94
12.1k
        return code;
95
14.8M
    return nread*size;
96
14.8M
}
97
98
/*
99
 * Read a byte from a stream
100
 */
101
int
102
sfgetc(stream *s)
103
0
{
104
0
    int code = sgetc(s);
105
106
0
    return code >= 0 ? code : EOF;
107
0
}
108
109
/*
110
 * Seek to a position in the stream. Returns the 0, or -1 if error
111
 */
112
int
113
sfseek(stream *s, gs_offset_t offset, int whence)
114
56.5M
{
115
56.5M
    gs_offset_t newpos = offset;
116
117
56.5M
    if (whence == SEEK_CUR)
118
647k
        newpos += stell(s);
119
56.5M
    if (whence == SEEK_END) {
120
13.8M
        gs_offset_t endpos;
121
122
13.8M
        if (savailable(s, &endpos) < 0)
123
0
            return -1;
124
13.8M
        newpos = endpos - offset;
125
13.8M
    }
126
56.5M
    if (s_can_seek(s) || newpos == stell(s)) {
127
56.5M
        return sseek(s, newpos);
128
56.5M
    }
129
54
    return -1;          /* fail */
130
56.5M
}
131
132
/*
133
 * Position to the beginning of the file
134
 */
135
int
136
srewind(stream *s)
137
27.0M
{
138
27.0M
    return sfseek(s, 0, SEEK_SET);
139
27.0M
}
140
141
/*
142
 * Return the current position in the stream or -1 if error.
143
 */
144
long
145
sftell(stream *s)
146
13.6M
{
147
13.6M
    return stell(s);
148
13.6M
}
149
150
/*
151
 * Return the EOF status, or 0 if not at EOF.
152
 */
153
int
154
sfeof(stream *s)
155
0
{
156
0
    return (s->end_status == EOFC) ? -1 : 0;
157
0
}
158
159
/*
160
 * Return the error status, or 0 if no error
161
 */
162
int
163
sferror(stream *s)
164
0
{
165
0
    return (s->end_status == ERRC) ? -1 : 0;
166
0
}
167
168
int
169
sfclose(stream *s)
170
18.9M
{
171
    /* no need to flush since these are 'read' only */
172
18.9M
    gs_memory_t *mem;
173
174
18.9M
    if (s == NULL)
175
0
        return 0;
176
18.9M
    mem = s->memory;
177
18.9M
    sclose(s);
178
18.9M
    gs_free_object(mem, s, "sfclose(stream)");
179
18.9M
    return 0;
180
18.9M
}
181
182
/* And now, a special version of the stdin iodev that can
183
 * read via the gsapi callout. This is lifted and modified
184
 * from gsiodev.c. Maybe at some point in the future we
185
 * can unify the two. */
186
187
0
#define STDIN_BUF_SIZE 1024
188
/* Read from stdin into the buffer. */
189
/* If interactive, only read one character. */
190
static int
191
s_stdin_read_process(stream_state * st, stream_cursor_read * ignore_pr,
192
                     stream_cursor_write * pw, bool last)
193
0
{
194
0
    int wcount = (int)(pw->limit - pw->ptr);
195
0
    int count;
196
0
    gs_memory_t *mem = st->memory;
197
0
    gs_lib_ctx_core_t *core = mem->gs_lib_ctx->core;
198
199
0
    if (wcount <= 0)
200
0
        return 0;
201
202
    /* do the callout */
203
0
    if (core->stdin_fn)
204
0
        count = (*core->stdin_fn)
205
0
            (core->std_caller_handle, (char *)pw->ptr + 1,
206
0
             core->stdin_is_interactive ? 1 : wcount);
207
0
    else
208
0
        count = gp_stdin_read((char *)pw->ptr + 1, wcount,
209
0
                      core->stdin_is_interactive,
210
0
                      core->fstdin);
211
212
0
    pw->ptr += (count < 0) ? 0 : count;
213
0
    return ((count < 0) ? ERRC : (count == 0) ? EOFC : count);
214
0
}
215
216
int
217
gs_get_callout_stdin(stream **ps, gs_memory_t *mem)
218
0
{
219
0
    stream *s;
220
0
    byte *buf;
221
0
    static const stream_procs p = {
222
0
        s_std_noavailable, s_std_noseek, s_std_read_reset,
223
0
        s_std_read_flush, file_close_file, s_stdin_read_process
224
0
    };
225
226
0
    s = file_alloc_stream(mem, "gs_get_callout_stdin(stream)");
227
228
    /* We want stdin to read only one character at a time, */
229
    /* but it must have a substantial buffer, in case it is used */
230
    /* by a stream that requires more than one input byte */
231
    /* to make progress. */
232
0
    buf = gs_alloc_bytes(mem, STDIN_BUF_SIZE, "gs_get_callout_stdin(buffer)");
233
0
    if (s == 0 || buf == 0)
234
0
        return_error(gs_error_VMerror);
235
236
0
    s_std_init(s, buf, STDIN_BUF_SIZE, &p, s_mode_read);
237
0
    s->file = 0;
238
0
    s->file_modes = s->modes;
239
0
    s->file_offset = 0;
240
0
    s->file_limit = S_FILE_LIMIT_MAX;
241
0
    s->save_close = s_std_null;
242
0
    *ps = s;
243
0
    return 0;
244
0
}