home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (C) 1989, 1990, 1991 Aladdin Enterprises. All rights reserved.
- Distributed by Free Software Foundation, Inc.
-
- This file is part of Ghostscript.
-
- Ghostscript is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
- to anyone for the consequences of using it or for whether it serves any
- particular purpose or works at all, unless he says so in writing. Refer
- to the Ghostscript General Public License for full details.
-
- Everyone is granted permission to copy, modify and redistribute
- Ghostscript, but only under the conditions described in the Ghostscript
- General Public License. A copy of this license is supposed to have been
- given to you along with Ghostscript so you can know your rights and
- responsibilities. It should be in a file named COPYING. Among other
- things, the copyright notice and this notice must be preserved on all
- copies. */
-
- /* stream.c */
- /* Stream package for Ghostscript interpreter */
- #include <stdio.h>
- #include "memory_.h"
- #include "std.h"
- #include "stream.h"
- #include "scanchar.h"
- #include "gxfixed.h" /* for gstype1.h */
- #include "gstype1.h"
-
- /* Forward declarations */
- /* Generic */
- /* Export these for filters */
- void
- s_std_init(P5(stream *, byte *, uint, stream_procs *, int)); /* last is writing flag */
- int
- s_std_null(P1(stream *)),
- s_std_noavailable(P2(stream *, long *)),
- s_std_close(P1(stream *));
- /* Strings */
- private int
- s_string_read_buf(P1(stream *)),
- s_string_write_buf(P1(stream *)),
- s_string_available(P2(stream *, long *)),
- s_string_seek(P2(stream *, long));
- private void
- s_string_init(P4(stream *, byte *, uint, stream_procs *));
- /* Files */
- private int
- s_file_read_buf(P1(stream *)),
- s_file_available(P2(stream *, long *)),
- s_file_read_seek(P2(stream *, long)),
- s_file_read_close(P1(stream *));
- private int
- s_file_write_buf(P1(stream *)),
- s_file_write_seek(P2(stream *, long)),
- s_file_write_flush(P1(stream *)),
- s_file_write_close(P1(stream *));
- /* decrypting */
- private int
- s_eexec_read_buf(P1(stream *)),
- s_eexec_available(P2(stream *, long *));
-
- /* ------ Generic procedures ------ */
-
- /* Standard stream initialization */
- void
- s_std_init(register stream *s, byte *ptr, uint len, stream_procs *pp,
- int writing)
- { s->cbuf = ptr;
- s->cptr = ptr - 1;
- s->endptr = (writing ? s->cptr + len : s->cptr);
- s->writing = writing;
- s->bsize = len;
- s->procs = *pp;
- }
-
- /* Implement a stream procedure as a no-op. */
- int
- s_std_null(stream *s)
- { return 0;
- }
-
- /* Indicate an error when asked for available input bytes. */
- int
- s_std_noavailable(stream *s, long *pl)
- { return -1;
- }
-
- /* Standard stream finalization. Disable the stream. */
- int
- s_std_close(stream *s)
- { s_disable(s);
- return 0;
- }
- void
- s_disable(register stream *s)
- { s->bsize = 0;
- /****** SHOULD DO A LOT MORE THAN THIS ******/
- }
-
- /* ------ Implementation-independent procedures ------ */
-
- /* Implement sgetc when the buffer is empty */
- /* by refilling the buffer and then reading a byte. */
- int
- spgetc(register stream *s)
- { int count;
- if ( s->eof )
- return EOFC;
- count = (*s->procs.read_buf)(s);
- if ( count > 0 )
- { s->endptr = s->cptr + count;
- return (int)*++(s->cptr);
- }
- else if ( count == 0 )
- { s->endptr = s->cptr;
- s->eof = 1;
- return EOFC;
- }
- else /* error or EOF */
- { s->endptr = s->cptr;
- return EOFC;
- }
- }
-
- /* Implementing sputc when the buffer is full */
- /* by flushing the buffer and then writing the byte. */
- int
- spputc(register stream *s, byte b)
- { int code = (*s->procs.write_buf)(s);
- if ( code < 0 ) return code;
- return sputc(s, b);
- }
-
- /* Push back a character onto a (read) stream. */
- /* Return 0 on success, -1 on failure. */
- int
- sungetc(register stream *s, byte c)
- { if ( s->writing || s->cptr < s->cbuf ) return -1;
- *(s->cptr)-- = c;
- return 0;
- }
-
- /* Read a string from a stream. */
- /* Return the number of bytes read. */
- uint
- sgets(register stream *s, byte *str, uint rlen)
- { uint len = rlen;
- while ( len > 0 )
- { uint count = sbufavailable(s);
- if ( count == 0 )
- { if ( s->eof ) return rlen - len;
- count = (*s->procs.read_buf)(s);
- if ( count == 0 )
- { s->eof = 1;
- return rlen - len;
- }
- s->endptr = s->cptr + count;
- }
- if ( count > len ) count = len;
- memcpy(str, s->cptr + 1, count);
- s->cptr += count;
- str += count;
- len -= count;
- }
- return rlen;
- }
-
- /* Write a string on a stream. */
- /* Return the number of bytes written. */
- uint
- sputs(register stream *s, byte *str, uint wlen)
- { uint len = wlen;
- if ( wlen > s->bsize && s->procs.write_buf == s_file_write_buf )
- { /* Write directly on the file. */
- uint write_count;
- (*s->procs.write_buf)(s);
- write_count = fwrite(str, 1, wlen, s->file);
- if ( s->position >= 0 ) /* file is positionable */
- s->position = ftell(s->file);
- return write_count;
- }
- while ( len > 0 )
- { uint count = sbufavailable(s);
- if ( count > 0 )
- { if ( count > len ) count = len;
- memcpy(s->cptr + 1, str, count);
- s->cptr += count;
- str += count;
- len -= count;
- }
- else
- { byte ch = *str++;
- sputc(s, ch);
- if ( s->eof ) return wlen - len;
- len--;
- }
- }
- return wlen;
- }
-
- /* Read a hex string from a stream. */
- /* Skip all characters other than hex digits. */
- /* Answer 1 if we reached end-of-file before filling the string, */
- /* 0 if we filled the string first, or <0 on error. */
- /* *odd_digit should be -1 initially: */
- /* if an odd number of hex digits was read, *odd_digit is set to */
- /* the odd digit value, otherwise *odd_digit is set to -1. */
- int
- sreadhex(stream *s, byte *str, uint rlen, uint *nread,
- int *odd_digit)
- { byte *ptr = str;
- byte *limit = ptr + rlen;
- byte val1 = (byte)*odd_digit;
- byte val2;
- register byte _ds *decoder = scan_char_decoder;
- register byte *sptr, *endp;
- int ch;
- #define begin_inline(sptr, endp, s)\
- sptr = s->cptr, endp = s->endptr
- #define sgetc_inline(sptr, endp, s)\
- (sptr < endp ? *++sptr :\
- (end_inline(sptr, s), ch = spgetc(s), begin_inline(sptr, endp, s), ch))
- #define end_inline(sptr, s)\
- s->cptr = sptr
- if ( rlen == 0 )
- { *nread = 0;
- return 0;
- }
- begin_inline(sptr, endp, s);
- if ( val1 <= 0xf ) goto d2;
- d1: while ( (val1 = decoder[sgetc_inline(sptr, endp, s)]) > 0xf )
- { if ( val1 == ctype_eof ) { *odd_digit = -1; goto ended; }
- }
- d2: while ( (val2 = decoder[sgetc_inline(sptr, endp, s)]) > 0xf )
- { if ( val2 == ctype_eof ) { *odd_digit = val1; goto ended; }
- }
- *ptr++ = (val1 << 4) + val2;
- if ( ptr < limit ) goto d1;
- *nread = rlen;
- end_inline(sptr, s);
- return 0;
- ended: *nread = ptr - str;
- end_inline(sptr, s);
- return 1;
- }
-
- /* ------ String streams ------ */
-
- /* Initialize a stream for reading a string. */
- void
- sread_string(register stream *s, byte *ptr, uint len)
- { static stream_procs p =
- { s_string_available, s_string_seek, s_std_null, s_std_null,
- s_string_read_buf, NULL
- };
- s_string_init(s, ptr, len, &p);
- s->writing = 0;
- }
- /* Handle end-of-buffer when reading from a string. */
- private int
- s_string_read_buf(stream *s)
- { s->cptr = s->endptr;
- return EOFC;
- }
- /* Return the number of available bytes when reading from a string. */
- private int
- s_string_available(stream *s, long *pl)
- { *pl = sbufavailable(s);
- if ( *pl == 0 ) *pl = -1; /* EOF */
- return 0;
- }
-
- /* Initialize a stream for writing a string. */
- void
- swrite_string(register stream *s, byte *ptr, uint len)
- { static stream_procs p =
- { s_std_noavailable, s_string_seek, s_std_null, s_std_null,
- NULL, s_string_write_buf
- };
- s_string_init(s, ptr, len, &p);
- s->writing = 1;
- }
- /* Handle end-of-buffer when writing a string. */
- private int
- s_string_write_buf(stream *s)
- { s->cptr = s->endptr;
- return EOFC;
- }
-
- /* Seek in a string. Return 0 if OK, -1 if not. */
- private int
- s_string_seek(register stream *s, long pos)
- { if ( pos < 0 || pos > s->bsize ) return -1;
- s->cptr = s->cbuf + pos - 1;
- return 0;
- }
-
- /* Private initialization */
- private void
- s_string_init(register stream *s, byte *ptr, uint len, stream_procs *p)
- { s_std_init(s, ptr, len, p, 1);
- s->eof = 1; /* this is all there is */
- s->position = 0;
- s->file = 0; /* not a file stream */
- s->strm = 0; /* not a filter either */
- }
-
- /* ------ File streams ------ */
-
- /* Initialize a stream for reading an OS file. */
- void
- sread_file(register stream *s, FILE *file, byte *buf, uint len)
- { static stream_procs p =
- { s_file_available, s_file_read_seek,
- s_std_null, s_file_read_close,
- s_file_read_buf, NULL
- };
- s_std_init(s, buf, len, &p, 0);
- s->file = file;
- s->eof = 0;
- s->strm = 0; /* not a filter */
- s->position = (file == stdin ? -1 : 0);
- }
- /* Procedures for reading from a file */
- private int
- s_file_read_buf(register stream *s)
- { int nread;
- if ( s->eof )
- { s->cptr = s->endptr;
- return EOFC;
- }
- if ( s->position >= 0 ) /* file is positionable */
- s->position = ftell(s->file);
- nread = fread(s->cbuf, 1, s->bsize, s->file);
- s->cptr = s->cbuf - 1;
- s->eof = feof(s->file);
- return nread;
- }
- private int
- s_file_available(register stream *s, long *pl)
- { *pl = sbufavailable(s);
- if ( sseekable(s) )
- { long pos, end;
- pos = ftell(s->file);
- if ( fseek(s->file, 0L, 2) ) return -1;
- end = ftell(s->file);
- if ( fseek(s->file, pos, 0) ) return -1;
- *pl += end - pos;
- if ( *pl == 0 ) *pl = -1; /* EOF */
- }
- else
- { if ( *pl == 0 && feof(s->file) ) *pl = -1; /* EOF */
- }
- return 0;
- }
- private int
- s_file_read_seek(register stream *s, long pos)
- { uint end = s->endptr - s->cbuf + 1;
- long offset = pos - s->position;
- if ( offset >= 0 && offset <= end )
- { /* Staying within the same buffer */
- s->cptr = s->cbuf + offset - 1;
- return 0;
- }
- if ( fseek(s->file, pos, 0) != 0 )
- return -1;
- s->endptr = s->cptr = s->cbuf - 1;
- s->eof = 0;
- return 0;
- }
- private int
- s_file_read_close(stream *s)
- { return fclose(s->file);
- }
-
- /* Initialize a stream for writing an OS file. */
- void
- swrite_file(register stream *s, FILE *file, byte *buf, uint len)
- { static stream_procs p =
- { s_std_noavailable, s_file_write_seek,
- s_file_write_flush, s_file_write_close,
- NULL, s_file_write_buf
- };
- s_std_init(s, buf, len, &p, 1);
- s->file = file;
- s->eof = 0;
- s->strm = 0; /* not a filter */
- s->position = (file == stdout || file == stderr ? -1 : 0);
- }
- /* Procedures for writing on a file */
- private int
- s_file_write_buf(register stream *s)
- { uint count = s->cptr + 1 - s->cbuf;
- uint write_count = fwrite(s->cbuf, 1, count, s->file);
- if ( s->position >= 0 ) /* file is positionable */
- s->position = ftell(s->file);
- s->cptr = s->cbuf - 1;
- s->endptr = s->cptr + s->bsize;
- return (write_count == count ? 0 : EOFC);
- }
- private int
- s_file_write_seek(stream *s, long pos)
- { /* Output files are not positionable */
- return -1;
- }
- private int
- s_file_write_flush(register stream *s)
- { int result = s_file_write_buf(s);
- fflush(s->file);
- return result;
- }
- private int
- s_file_write_close(register stream *s)
- { s_file_write_buf(s);
- return fclose(s->file);
- }
-
- /* ------ Encrypted streams ------ */
-
- /* Initialize a stream for reading and decrypting another stream. */
- /* Decrypting streams are not positionable. */
- void
- sread_decrypt(register stream *s, stream *xs, byte *buf, uint len,
- ushort /*crypt_state*/ state)
- { static stream_procs p =
- { s_eexec_available, NULL, s_std_null, s_std_null,
- s_eexec_read_buf, NULL
- };
- s_std_init(s, buf, len, &p, 0);
- s->eof = 0;
- s->position = -1; /* not positionable */
- s->file = 0;
- s->strm = xs;
- s->cstate = state;
- s->odd = -1;
- s->binary = -1; /* unknown */
- }
- /* Refill the buffer of a decrypting stream. */
- private int
- s_eexec_read_buf(register stream *s)
- { byte *buf = s->cbuf;
- uint nread;
- int skip = (s->binary < 0 ? 4 : 0);
- s->cptr = buf - 1;
- top: nread = sgets(s->strm, buf, s->bsize);
- if ( nread == 0 ) /* end of stream */
- { s->eof = 1;
- return EOFC;
- }
- if ( s->binary < 0 )
- { /* This is the very first time we're filling the buffer. */
- /* Determine whether this is ASCII or hex encoding. */
- register byte _ds *decoder = scan_char_decoder;
- if ( nread < 4 ) return EOFC;
- if ( decoder[buf[0]] == ctype_space ||
- (decoder[buf[0]] | decoder[buf[1]] | decoder[buf[2]] |
- decoder[buf[3]]) <= 0xf )
- { /* Would be invalid if binary, hence must be hex. */
- s->binary = 0;
- }
- else s->binary = 1;
-
- }
- if ( !s->binary )
- { /* Convert the buffer from binary to hex in place. */
- stream sst;
- sread_string(&sst, buf, nread);
- sreadhex(&sst, buf, nread, &nread, &s->odd);
- if ( nread == 0 ) goto top; /* try again */
- }
- /* Now decrypt the buffer. */
- gs_type1_decrypt(buf, buf, nread, (crypt_state *)&s->cstate);
- if ( skip )
- { /* Very first buffer-load, strip off leading bytes. */
- if ( nread < skip ) return EOFC;
- s->cptr += skip;
- nread -= skip;
- }
- return nread;
- }
- /* Estimate the number of remaining bytes in a decrypting stream. */
- private int
- s_eexec_available(stream *s, long *pl)
- { if ( savailable(s->strm, pl) < 0 ) return -1;
- if ( *pl >= 0 ) *pl /= 2;
- return 0;
- }
-