diff options
Diffstat (limited to 'base/strmio.c')
-rw-r--r-- | base/strmio.c | 244 |
1 files changed, 244 insertions, 0 deletions
diff --git a/base/strmio.c b/base/strmio.c new file mode 100644 index 00000000..fbbfe871 --- /dev/null +++ b/base/strmio.c @@ -0,0 +1,244 @@ +/* Copyright (C) 2001-2019 Artifex Software, Inc. + All Rights Reserved. + + This software is provided AS-IS with no warranty, either express or + implied. + + This software is distributed under license and may not be copied, + modified or distributed except as expressly authorized under the terms + of the license contained in the file LICENSE in this distribution. + + Refer to licensing information at http://www.artifex.com or contact + Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato, + CA 94945, U.S.A., +1(415)492-9861, for further information. +*/ + + +/* Interface for streams that mimic stdio functions (fopen, fread, fseek, ftell) */ + +#include "malloc_.h" +#include "memory_.h" +#include "gxiodev.h" +#include "gdebug.h" +#include "gsfname.h" +#include "gslibctx.h" +#include "gsmemret.h" /* for gs_memory_type_ptr_t */ +#include "gsmalloc.h" +#include "gsstype.h" +#include "stream.h" +#include "strmio.h" +#include "gserrors.h" + +/* + * Open a stream using a filename that can include a PS style IODevice prefix + * If iodev_default is the '%os' device, then the file will be on the host + * file system transparently to the caller. The "%os%" prefix can be used + * to explicilty access the host file system. + */ +stream * +sfopen(const char *path, const char *mode, gs_memory_t *mem) +{ + gs_parsed_file_name_t pfn; + stream *s; + iodev_proc_open_file((*open_file)); + + int code = gs_parse_file_name(&pfn, path, strlen(path), mem); + if (code < 0) { +# define EMSG "sfopen: gs_parse_file_name failed.\n" + errwrite(mem, EMSG, strlen(EMSG)); +# undef EMSG + return NULL; + } + if (pfn.fname == NULL) { /* just a device */ +# define EMSG "sfopen: not allowed with %device only.\n" + errwrite(mem, EMSG, strlen(EMSG)); +# undef EMSG + return NULL; + } + if (pfn.iodev == NULL) + pfn.iodev = iodev_default(mem); + open_file = pfn.iodev->procs.open_file; + if (open_file == 0) + code = file_open_stream(pfn.fname, pfn.len, mode, 2048, &s, + pfn.iodev, pfn.iodev->procs.gp_fopen, mem); + else + code = open_file(pfn.iodev, pfn.fname, pfn.len, mode, &s, mem); + if (code < 0) + return NULL; + s->position = 0; + code = ssetfilename(s, (const byte *)path, strlen(path)); + if (code < 0) { + /* Only error is gs_error_VMerror */ + sclose(s); + gs_free_object(s->memory, s, "sfopen: allocation error"); +# define EMSG "sfopen: allocation error setting path name into stream.\n" + errwrite(mem, EMSG, strlen(EMSG)); +# undef EMSG + return NULL; + } + return s; +} + +/* + * Read a number of bytes from a stream, returning number read. Return count + * will be less than count if EOF or error. Return count is number of elements. + */ +int +sfread(void *ptr, size_t size, size_t count, stream *s) +{ + int code; + uint nread; + + code = sgets(s, ptr, size*count, &nread); + if (code < 0) + return code; + return nread*size; +} + +/* + * Read a byte from a stream + */ +int +sfgetc(stream *s) +{ + int code = sgetc(s); + + return code >= 0 ? code : EOF; +} + +/* + * Seek to a position in the stream. Returns the 0, or -1 if error + */ +int +sfseek(stream *s, gs_offset_t offset, int whence) +{ + gs_offset_t newpos = offset; + + if (whence == SEEK_CUR) + newpos += stell(s); + if (whence == SEEK_END) { + gs_offset_t endpos; + + if (savailable(s, &endpos) < 0) + return -1; + newpos = endpos - offset; + } + if (s_can_seek(s) || newpos == stell(s)) { + return sseek(s, newpos); + } + return -1; /* fail */ +} + +/* + * Position to the beginning of the file + */ +int +srewind(stream *s) +{ + return sfseek(s, 0, SEEK_SET); +} + +/* + * Return the current position in the stream or -1 if error. + */ +long +sftell(stream *s) +{ + return stell(s); +} + +/* + * Return the EOF status, or 0 if not at EOF. + */ +int +sfeof(stream *s) +{ + return (s->end_status == EOFC) ? -1 : 0; +} + +/* + * Return the error status, or 0 if no error + */ +int +sferror(stream *s) +{ + return (s->end_status == ERRC) ? -1 : 0; +} + +int +sfclose(stream *s) +{ + /* no need to flush since these are 'read' only */ + gs_memory_t *mem; + + if (s == NULL) + return 0; + mem = s->memory; + sclose(s); + gs_free_object(mem, s, "sfclose(stream)"); + return 0; +} + +/* And now, a special version of the stdin iodev that can + * read via the gsapi callout. This is lifted and modified + * from gsiodev.c. Maybe at some point in the future we + * can unify the two. */ + +#define STDIN_BUF_SIZE 1024 +/* Read from stdin into the buffer. */ +/* If interactive, only read one character. */ +static int +s_stdin_read_process(stream_state * st, stream_cursor_read * ignore_pr, + stream_cursor_write * pw, bool last) +{ + int wcount = (int)(pw->limit - pw->ptr); + int count; + gs_memory_t *mem = st->memory; + gs_lib_ctx_core_t *core = mem->gs_lib_ctx->core; + + if (wcount <= 0) + return 0; + + /* do the callout */ + if (core->stdin_fn) + count = (*core->stdin_fn) + (core->caller_handle, (char *)pw->ptr + 1, + core->stdin_is_interactive ? 1 : wcount); + else + count = gp_stdin_read((char *)pw->ptr + 1, wcount, + core->stdin_is_interactive, + core->fstdin); + + pw->ptr += (count < 0) ? 0 : count; + return ((count < 0) ? ERRC : (count == 0) ? EOFC : count); +} + +int +gs_get_callout_stdin(stream **ps, gs_memory_t *mem) +{ + stream *s; + byte *buf; + static const stream_procs p = { + s_std_noavailable, s_std_noseek, s_std_read_reset, + s_std_read_flush, file_close_file, s_stdin_read_process + }; + + s = file_alloc_stream(mem, "gs_get_callout_stdin(stream)"); + + /* We want stdin to read only one character at a time, */ + /* but it must have a substantial buffer, in case it is used */ + /* by a stream that requires more than one input byte */ + /* to make progress. */ + buf = gs_alloc_bytes(mem, STDIN_BUF_SIZE, "gs_get_callout_stdin(buffer)"); + if (s == 0 || buf == 0) + return_error(gs_error_VMerror); + + s_std_init(s, buf, STDIN_BUF_SIZE, &p, s_mode_read); + s->file = 0; + s->file_modes = s->modes; + s->file_offset = 0; + s->file_limit = S_FILE_LIMIT_MAX; + s->save_close = s_std_null; + *ps = s; + return 0; +} |