/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 | } |