summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'base/sfxcommon.c')
-rw-r--r--base/sfxcommon.c214
1 files changed, 214 insertions, 0 deletions
diff --git a/base/sfxcommon.c b/base/sfxcommon.c
new file mode 100644
index 00000000..002651ba
--- /dev/null
+++ b/base/sfxcommon.c
@@ -0,0 +1,214 @@
+/* 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.
+*/
+
+
+/* $Id: sfxcommon.c 8250 2007-09-25 13:31:24Z giles $ */
+/* Common routines for stdio and fd file stream implementations. */
+#include "stdio_.h" /* includes std.h */
+#include "memory_.h"
+#include "unistd_.h"
+#include "gsmemory.h"
+#include "gp.h"
+#include "gserrors.h"
+#include "stream.h"
+#include "assert_.h"
+
+#define DEFAULT_BUFFER_SIZE 2048
+const uint file_default_buffer_size = DEFAULT_BUFFER_SIZE;
+
+/* Allocate and return a file stream. */
+/* Return 0 if the allocation failed. */
+/* The stream is initialized to an invalid state, so the caller need not */
+/* worry about cleaning up if a later step in opening the stream fails. */
+stream *
+file_alloc_stream(gs_memory_t * mem, client_name_t cname)
+{
+ stream *s;
+ s = s_alloc(mem, cname);
+ if (s == 0)
+ return 0;
+ s_init_ids(s);
+ s->is_temp = 0; /* not a temp stream */
+ s->foreign = 0;
+ /*
+ * Disable the stream now (in case we can't open the file,
+ * or a filter init procedure fails) so that `restore' won't
+ * crash when it tries to close open files.
+ */
+ s_disable(s);
+ s->prev = 0;
+ s->next = 0;
+ return s;
+}
+
+/* Open a file stream, optionally on an OS file. */
+/* Return 0 if successful, error code if not. */
+/* On a successful return, the C file name is in the stream buffer. */
+/* If fname==0, set up the file entry, stream, and buffer, */
+/* but don't open an OS file or initialize the stream. */
+int
+file_open_stream(const char *fname, uint len, const char *file_access,
+ uint buffer_size, stream ** ps, gx_io_device *iodev,
+ iodev_proc_fopen_t fopen_proc, gs_memory_t *mem)
+{
+ int code;
+ gp_file *file;
+ char fmode[4]; /* r/w/a, [+], [b], null */
+
+#ifdef DEBUG
+ if (strlen(gp_fmode_binary_suffix) > 0) {
+ if (strchr(file_access, gp_fmode_binary_suffix[0]) != NULL)
+ dmprintf(mem, "\nWarning: spurious 'b' character in file access mode\n");
+ assert(strchr(file_access, gp_fmode_binary_suffix[0]) == NULL);
+ }
+#endif
+
+ if (!iodev)
+ iodev = iodev_default(mem);
+ code = file_prepare_stream(fname, len, file_access, buffer_size, ps, fmode, mem);
+ if (code < 0)
+ return code;
+ if (fname == 0)
+ return 0;
+ if (fname[0] == 0) { /* fopen_proc gets NUL terminated string, not len */
+ /* so this is the same as len == 0, so return NULL */
+ /* discard the stuff we allocated to keep from accumulating stuff needing GC */
+ gs_free_object(mem, (*ps)->cbuf, "file_close(buffer)");
+ gs_free_object(mem, *ps, "file_prepare_stream(stream)");
+ *ps = NULL;
+
+ return 0;
+ }
+ code = (*fopen_proc)(iodev, (char *)(*ps)->cbuf, fmode, &file,
+ (char *)(*ps)->cbuf, (*ps)->bsize, mem);
+ if (code < 0) {
+ /* discard the stuff we allocated to keep from accumulating stuff needing GC */
+ gs_free_object(mem, (*ps)->cbuf, "file_close(buffer)");
+ gs_free_object(mem, *ps, "file_prepare_stream(stream)");
+ *ps = NULL;
+ return code;
+ }
+ if (file_init_stream(*ps, file, fmode, (*ps)->cbuf, (*ps)->bsize) != 0)
+ return_error(gs_error_ioerror);
+ return 0;
+}
+
+/* Close a file stream. This replaces the close procedure in the stream */
+/* for normal (OS) files and for filters. */
+int
+file_close_file(stream * s)
+{
+ stream *stemp = s->strm;
+ gs_memory_t *mem;
+ int code = file_close_disable(s);
+
+ if (code)
+ return code;
+ /*
+ * Check for temporary streams created for filters.
+ * There may be more than one in the case of a procedure-based filter,
+ * or if we created an intermediate stream to ensure
+ * a large enough buffer. Note that these streams may have been
+ * allocated by file_alloc_stream, so we mustn't free them.
+ */
+ while (stemp != 0 && stemp->is_temp != 0) {
+ stream *snext = stemp->strm;
+
+ mem = stemp->memory;
+ if (stemp->is_temp > 1)
+ gs_free_object(mem, stemp->cbuf,
+ "file_close(temp stream buffer)");
+ s_disable(stemp);
+ stemp = snext;
+ }
+ mem = s->memory;
+ gs_free_object(mem, s->cbuf, "file_close(buffer)");
+ if (s->close_strm && stemp != 0)
+ return sclose(stemp);
+ return 0;
+}
+
+/*
+ * Set up a file stream on an OS file. The caller has allocated the
+ * stream and buffer.
+ */
+int
+file_init_stream(stream *s, gp_file *file, const char *fmode, byte *buffer,
+ uint buffer_size)
+{
+ switch (fmode[0]) {
+ case 'a':
+ if (sappend_file(s, file, buffer, buffer_size) != 0)
+ return ERRC;
+ break;
+ case 'r':
+ /* Defeat buffering for terminals. */
+ {
+ int char_buffered = gp_file_is_char_buffered(file);
+ if (char_buffered < 0)
+ return char_buffered;
+ sread_file(s, file, buffer, char_buffered ? 1 : buffer_size);
+ }
+ break;
+ case 'w':
+ swrite_file(s, file, buffer, buffer_size);
+ }
+ if (fmode[1] == '+')
+ s->file_modes |= s_mode_read | s_mode_write;
+ s->save_close = s->procs.close;
+ s->procs.close = file_close_file;
+ return 0;
+}
+
+/* Prepare a stream with a file name. */
+/* Return 0 if successful, error code if not. */
+/* On a successful return, the C file name is in the stream buffer. */
+/* If fname==0, set up stream, and buffer. */
+int
+file_prepare_stream(const char *fname, uint len, const char *file_access,
+ uint buffer_size, stream ** ps, char fmode[4], gs_memory_t *mem)
+{
+ byte *buffer;
+ register stream *s;
+
+ /* Open the file, always in binary mode. */
+ strcpy(fmode, file_access);
+ strcat(fmode, gp_fmode_binary_suffix);
+ if (buffer_size == 0)
+ buffer_size = file_default_buffer_size;
+ if (len >= buffer_size) /* we copy the file name into the buffer */
+ return_error(gs_error_limitcheck);
+ /* Allocate the stream first, since it persists */
+ /* even after the file has been closed. */
+ s = file_alloc_stream(mem, "file_prepare_stream");
+ if (s == 0)
+ return_error(gs_error_VMerror);
+ /* Allocate the buffer. */
+ buffer = gs_alloc_bytes(mem, buffer_size, "file_prepare_stream(buffer)");
+ if (buffer == 0) {
+ gs_free_object(mem, s, "file_prepare_stream");
+ return_error(gs_error_VMerror);
+ }
+ if (fname != 0) {
+ memcpy(buffer, fname, len);
+ buffer[len] = 0; /* terminate string */
+ } else
+ buffer[0] = 0; /* safety */
+ s->cbuf = buffer;
+ s->bsize = s->cbsize = buffer_size;
+ s->save_close = 0; /* in case this stream gets disabled before init finishes */
+ *ps = s;
+ return 0;
+}