/* Copyright (C) 1989, 2000 artofcode LLC. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA, 02111-1307. */ /*$Id: stream.h,v 1.8.2.1.2.1 2003/01/17 00:49:05 giles Exp $ */ /* Definitions for Ghostscript stream package */ /* Requires stdio.h */ #ifndef stream_INCLUDED # define stream_INCLUDED #include "scommon.h" #include "srdline.h" /* See scommon.h for documentation on the design of streams. */ /* ------ Stream structure definition ------ */ /* * We expose the stream structure definition to clients so that * they can get reasonable performance out of the basic operations. */ /* Define the "virtual" stream procedures. */ typedef struct { /* Store # available for reading. */ /* Return 0 if OK, ERRC if error or not implemented. */ #define stream_proc_available(proc)\ int proc(P2(stream *, long *)) stream_proc_available((*available)); /* Set position. */ /* Return 0 if OK, ERRC if error or not implemented. */ #define stream_proc_seek(proc)\ int proc(P2(stream *, long)) stream_proc_seek((*seek)); /* Clear buffer and, if relevant, unblock channel. */ /* Cannot cause an error. */ #define stream_proc_reset(proc)\ void proc(P1(stream *)) stream_proc_reset((*reset)); /* Flush buffered data to output, or drain input. */ /* Return 0 if OK, ERRC if error. */ #define stream_proc_flush(proc)\ int proc(P1(stream *)) stream_proc_flush((*flush)); /* Flush data (if writing) & close stream. */ /* Return 0 if OK, ERRC if error. */ #define stream_proc_close(proc)\ int proc(P1(stream *)) stream_proc_close((*close)); /* Process a buffer, updating the cursor pointers. */ /* See strimpl.h for details. */ stream_proc_process((*process)); /* Switch the stream to read or write mode. */ /* false = read, true = write. */ /* If the procedure is 0, switching is not allowed. */ #define stream_proc_switch_mode(proc)\ int proc(P2(stream *, bool)) stream_proc_switch_mode((*switch_mode)); } stream_procs; /* ------ The actual stream structure ------ */ struct stream_s { /* * To allow the stream itself to serve as the "state" * of a couple of heavily used types, we start its * definition with the common stream state. */ stream_state_common; /* * The following invariants apply at all times for read streams: * * s->cbuf - 1 <= s->srptr <= s->srlimit. * * The amount of data in the buffer is s->srlimit + 1 - s->cbuf. * * s->position represents the stream position as of the beginning * of the buffer, so the current position is s->position + * (s->srptr + 1 - s->cbuf). * * Analogous invariants apply for write streams: * * s->cbuf - 1 <= s->swptr <= s->swlimit. * * The amount of data in the buffer is s->swptr + 1 - s->cbuf. * * s->position represents the stream position as of the beginning * of the buffer, so the current position is s->position + * (s->swptr + 1 - s->cbuf). */ stream_cursor cursor; /* cursor for reading/writing data */ byte *cbuf; /* base of buffer */ uint bsize; /* size of buffer, 0 if closed */ uint cbsize; /* size of buffer */ /* * end_status indicates what should happen when the client * reaches the end of the buffer: * 0 in the normal case; * EOFC if a read stream has reached EOD or a write * stream has written the EOD marker; * ERRC if an error terminated the last read or write * operation from or to the underlying data source * or sink; * INTC if the last transfer was interrupted (NOT * USED YET); * CALLC if a callout is required. */ short end_status; /* status at end of buffer (when */ /* reading) or now (when writing) */ byte foreign; /* true if buffer is outside heap */ byte modes; /* access modes allowed for this stream */ #define s_mode_read 1 #define s_mode_write 2 #define s_mode_seek 4 #define s_mode_append 8 /* (s_mode_write also set) */ #define s_is_valid(s) ((s)->modes != 0) #define s_is_reading(s) (((s)->modes & s_mode_read) != 0) #define s_is_writing(s) (((s)->modes & s_mode_write) != 0) #define s_can_seek(s) (((s)->modes & s_mode_seek) != 0) gs_string cbuf_string; /* cbuf/cbsize if cbuf is a string, */ /* 0/? if not */ long position; /* file position of beginning of */ /* buffer */ stream_procs procs; stream *strm; /* the underlying stream, non-zero */ /* iff this is a filter stream */ int is_temp; /* if >0, this is a temporary */ /* stream and should be freed */ /* when its source/sink is closed; */ /* if >1, the buffer is also */ /* temporary */ int inline_temp; /* temporary for inline access */ /* (see spgetc_inline below) */ stream_state *state; /* state of process */ /* * The following are for the use of the interpreter. * See files.h for more information on read_id and write_id, * zfile.c for more information on prev and next, * zfilter.c for more information on close_strm. */ ushort read_id; /* "unique" serial # for detecting */ /* references to closed streams */ /* and for validating read access */ ushort write_id; /* ditto to validate write access */ stream *prev, *next; /* keep track of all files */ bool close_strm; /* CloseSource/CloseTarget */ bool close_at_eod; /*(default is true, only false if "reusable")*/ int (*save_close)(P1(stream *)); /* save original close proc */ /* * In order to avoid allocating a separate stream_state for * file streams, which are the most heavily used stream type, * we put their state here. */ FILE *file; /* file handle for C library */ gs_const_string file_name; /* file name (optional) -- clients must */ /* access only through procedures */ uint file_modes; /* access modes for the file, */ /* may be a superset of modes */ /* Clients must only set the following through sread_subfile. */ long file_offset; /* starting point in file (reading) */ long file_limit; /* ending point in file (reading) */ }; /* The descriptor is only public for subclassing. */ extern_st(st_stream); #define public_st_stream() /* in stream.c */\ gs_public_st_composite_final(st_stream, stream, "stream",\ stream_enum_ptrs, stream_reloc_ptrs, stream_finalize) #define STREAM_NUM_PTRS 6 /* Initialize the checking IDs of a stream. */ #define s_init_ids(s) ((s)->read_id = (s)->write_id = 1) #define s_init_read_id(s) ((s)->read_id = 1, (s)->write_id = 0) #define s_init_write_id(s) ((s)->read_id = 0, (s)->write_id = 1) #define s_init_no_id(s) ((s)->read_id = (s)->write_id = 0) /* ------ Stream functions ------ */ #define srptr cursor.r.ptr #define srlimit cursor.r.limit #define swptr cursor.w.ptr #define swlimit cursor.w.limit /* Some of these are macros -- beware. */ /* Note that unlike the C stream library, */ /* ALL stream procedures take the stream as the first argument. */ #define sendrp(s) ((s)->srptr >= (s)->srlimit) /* NOT FOR CLIENTS */ #define sendwp(s) ((s)->swptr >= (s)->swlimit) /* NOT FOR CLIENTS */ /* * Following are valid for all streams. */ /* flush is NOT a no-op for read streams -- it discards data until EOF. */ /* close is NOT a no-op for non-file streams -- */ /* it actively disables them. */ /* The close routine must do a flush if needed. */ #define sseekable(s) s_can_seek(s) int savailable(P2(stream *, long *)); #define sreset(s) (*(s)->procs.reset)(s) #define sflush(s) (*(s)->procs.flush)(s) int sclose(P1(stream *)); int sswitch(P2(stream *, bool)); /* * Following are only valid for read streams. */ int spgetcc(P2(stream *, bool)); /* bool indicates close at EOD */ #define spgetc(s) spgetcc(s, true) /* a procedure equivalent of sgetc */ /* * Note that sgetc must call spgetc one byte early, because filter must read * ahead to detect EOD. * * In the definition of sgetc, the first alternative should read * (int)(*++((s)->srptr)) * but the Borland compiler generates truly atrocious code for this. * The SCO ODT compiler requires the first, pointless cast to int. */ #define sgetc(s)\ ((int)((s)->srlimit - (s)->srptr > 1 ? (++((s)->srptr), (int)*(s)->srptr) : spgetc(s))) int sgets(P4(stream *, byte *, uint, uint *)); int sungetc(P2(stream *, byte)); /* ERRC on error, 0 if OK */ #define sputback(s) ((s)->srptr--) /* can only do this once! */ #define seofp(s) (sendrp(s) && (s)->end_status == EOFC) #define serrorp(s) (sendrp(s) && (s)->end_status == ERRC) int spskip(P3(stream *, long, long *)); #define sskip(s,nskip,pskipped) spskip(s, (long)(nskip), pskipped) /* * Attempt to refill the buffer of a read stream. * Only call this if the end_status is not EOFC, * and if the buffer is (nearly) empty. */ int s_process_read_buf(P1(stream *)); /* * Following are only valid for write streams. */ int spputc(P2(stream *, byte)); /* a procedure equivalent of sputc */ /* * The first alternative should read * ((int)(*++((s)->swptr)=(c))) * but the Borland compiler generates truly atrocious code for this. */ #define sputc(s,c)\ (!sendwp(s) ? (++((s)->swptr), *(s)->swptr=(c), 0) : spputc((s),(c))) int sputs(P4(stream *, const byte *, uint, uint *)); /* * Attempt to empty the buffer of a write stream. * Only call this if the end_status is not EOFC. */ int s_process_write_buf(P2(stream *, bool)); /* Following are only valid for positionable streams. */ long stell(P1(stream *)); int spseek(P2(stream *, long)); #define sseek(s,pos) spseek(s, (long)(pos)) /* Following are for high-performance reading clients. */ /* bufptr points to the next item. */ #define sbufptr(s) ((s)->srptr + 1) #define sbufavailable(s) ((s)->srlimit - (s)->srptr) #define sbufskip(s, n) ((s)->srptr += (n), 0) /* * Define the minimum amount of data that must be left in an input buffer * after a read operation to handle filter read-ahead, either 0 or 1 * byte(s). */ #define max_min_left 1 /* * The stream.state min_left value is the minimum amount of data that must * be left in an input buffer after a read operation to handle filter * read-ahead. Once filters reach EOD, return 0 since read-ahead is * no longer relevant. */ #define sbuf_min_left(s) \ ((s->end_status == EOFC || s->end_status == ERRC ? 0 : s->state->min_left)) /* The following are for very high-performance clients of read streams, */ /* who unpack the stream state into local variables. */ /* Note that any non-inline operations must do a s_end_inline before, */ /* and a s_begin_inline after. */ #define s_declare_inline(s, cp, ep)\ register const byte *cp;\ const byte *ep #define s_begin_inline(s, cp, ep)\ cp = (s)->srptr, ep = (s)->srlimit #define s_end_inline(s, cp, ep)\ (s)->srptr = cp #define sbufavailable_inline(s, cp, ep)\ (ep - cp) #define sendbufp_inline(s, cp, ep)\ (cp >= ep) /* The (int) is needed to pacify the SCO ODT compiler. */ #define sgetc_inline(s, cp, ep)\ ((int)(sendbufp_inline(s, cp, ep) ? spgetc_inline(s, cp, ep) : *++cp)) #define spgetc_inline(s, cp, ep)\ (s_end_inline(s, cp, ep), (s)->inline_temp = spgetc(s),\ s_begin_inline(s, cp, ep), (s)->inline_temp) #define sputback_inline(s, cp, ep)\ --cp /* Allocate a stream or a stream state. */ stream *s_alloc(P2(gs_memory_t *, client_name_t)); stream_state *s_alloc_state(P3(gs_memory_t *, gs_memory_type_ptr_t, client_name_t)); /* * Initialize a separately allocated stream or stream state, as if allocated * by s_alloc[_state]. */ void s_init(P2(stream *, gs_memory_t *)); void s_init_state(P3(stream_state *, const stream_template *, gs_memory_t *)); /* Create a stream on a string or a file. */ void sread_string(P3(stream *, const byte *, uint)), sread_string_reusable(P3(stream *, const byte *, uint)), swrite_string(P3(stream *, byte *, uint)); void sread_file(P4(stream *, FILE *, byte *, uint)), swrite_file(P4(stream *, FILE *, byte *, uint)), sappend_file(P4(stream *, FILE *, byte *, uint)); /* Confine reading to a subfile. This is primarily for reusable streams. */ int sread_subfile(P3(stream *s, long start, long length)); /* Set the file name of a stream, copying the name. */ /* Return <0 if the copy could not be allocated. */ int ssetfilename(P3(stream *, const byte *, uint)); /* Return the file name of a stream, if any. */ /* There is a guaranteed 0 byte after the string. */ int sfilename(P2(stream *, gs_const_string *)); /* Create a stream that tracks the position, */ /* for calculating how much space to allocate when actually writing. */ void swrite_position_only(P1(stream *)); /* Standard stream initialization */ void s_std_init(P5(stream *, byte *, uint, const stream_procs *, int /*mode */ )); /* Standard stream finalization */ void s_disable(P1(stream *)); /* Generic stream procedures exported for templates */ int s_std_null(P1(stream *)); void s_std_read_reset(P1(stream *)), s_std_write_reset(P1(stream *)); int s_std_read_flush(P1(stream *)), s_std_write_flush(P1(stream *)), s_std_noavailable(P2(stream *, long *)), s_std_noseek(P2(stream *, long)), s_std_close(P1(stream *)), s_std_switch_mode(P2(stream *, bool)); /* Generic procedures for filters. */ int s_filter_write_flush(P1(stream *)), s_filter_close(P1(stream *)); /* Generic procedure structures for filters. */ extern const stream_procs s_filter_read_procs, s_filter_write_procs; /* * Add a filter to an output pipeline. The client must have allocated the * stream state, if any, using the given allocator. For s_init_filter, the * client must have called s_init and s_init_state. * * Note that if additional buffering is needed, s_add_filter may add * an additional filter to provide it. */ int s_init_filter(P5(stream *fs, stream_state *fss, byte *buf, uint bsize, stream *target)); stream *s_add_filter(P4(stream **ps, const stream_template *template, stream_state *ss, gs_memory_t *mem)); /* * Close the filters in a pipeline, up to a given target stream, freeing * their buffers and state structures. */ int s_close_filters(P2(stream **ps, stream *target)); /* Define templates for the NullEncode/Decode filters. */ /* They have no state. */ extern const stream_template s_NullE_template; extern const stream_template s_NullD_template; #endif /* stream_INCLUDED */