/* Copyright (C) 1989, 1992 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
/* Stream package for Ghostscript interpreter */
/* Forward declarations */
/* Export these for filters */
s_std_init(P5(stream
*, byte
*, uint
, stream_procs
*, int /*mode*/));
s_std_null(P1(stream
*)),
s_std_noavailable(P2(stream
*, long *)),
s_std_close(P1(stream
*));
s_string_read_buf(P1(stream
*)),
s_string_write_buf(P1(stream
*)),
s_string_available(P2(stream
*, long *)),
s_string_seek(P2(stream
*, long));
s_string_init(P4(stream
*, byte
*, uint
, stream_procs
*));
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
*));
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
*));
/* ------ Generic procedures ------ */
/* Standard stream initialization */
s_std_init(register stream
*s
, byte
*ptr
, uint len
, stream_procs
*pp
,
s
->endptr
= (mode
== s_mode_write
? s
->cptr
+ len
: s
->cptr
);
s
->bsize
= s
->cbsize
= len
;
s
->strm
= 0; /* not a filter */
/* Implement a stream procedure as a no-op. */
/* Indicate an error when asked for available input bytes. */
s_std_noavailable(stream
*s
, long *pl
)
/* Standard stream finalization. Disable the stream. */
s_disable(register stream
*s
)
/****** SHOULD DO MORE THAN THIS ******/
/* ------ Implementation-independent procedures ------ */
/* Implement sgetc when the buffer is empty, */
/* by refilling the buffer and then reading a byte. */
spgetc(register stream
*s
)
if ( s
->end_status
) return s
->end_status
;
code
= (*s
->procs
.read_buf
)(s
);
if ( code
< 0 ) return code
;
return (s
->end_status
? s
->end_status
: EOFC
);
/* Implementing sputc when the buffer is full, */
/* by flushing the buffer and then writing the byte. */
spputc(register stream
*s
, byte b
)
if ( s
->end_status
) return s
->end_status
;
code
= (*s
->procs
.write_buf
)(s
);
if ( code
< 0 ) return code
;
/* Push back a character onto a (read) stream. */
/* Return 0 on success, ERRC on failure. */
sungetc(register stream
*s
, byte c
)
{ if ( !s_is_reading(s
) || s
->cptr
< s
->cbuf
) return ERRC
;
/* Read a string from a stream. */
/* Return the number of bytes read. */
sgets(register stream
*s
, byte
*str
, uint rlen
)
{ uint count
= sbufavailable(s
);
code
= (*s
->procs
.read_buf
)(s
);
if ( code
< 0 || sendbufp(s
) )
if ( count
> len
) count
= len
;
memcpy(str
, s
->cptr
+ 1, count
);
/* Write a string on a stream. */
/* Return the number of bytes written. */
sputs(register stream
*s
, const byte
*str
, uint wlen
)
if ( wlen
> s
->bsize
&& s
->procs
.write_buf
== s_file_write_buf
)
{ /* Write directly on the file. */
(*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
);
{ uint count
= sbufavailable(s
);
{ if ( count
> len
) count
= len
;
memcpy(s
->cptr
+ 1, str
, count
);
if ( s
->end_status
) return wlen
- len
;
/* Read a hex string from a stream. */
/* Answer EOFC if we reached end-of-file before filling the string, */
/* 0 if we filled the string first, or ERRC on error. */
/* s->odd should be -1 initially: */
/* if an odd number of hex digits was read, s->odd is set to */
/* the odd digit value, otherwise s->odd is set to -1. */
/* If ignore_garbage is true, characters other than hex digits are ignored; */
/* if ignore_garbage is false, characters other than hex digits or */
/* whitespace return an error. */
sreadhex(stream
*s
, byte
*str
, uint rlen
, uint
*nread
,
int *odd_digit
, int ignore_garbage
)
byte
*limit
= ptr
+ rlen
;
byte val1
= (byte
)*odd_digit
;
register byte _ds
*decoder
= scan_char_decoder
;
register byte
*sptr
, *endp
;
#define begin_inline(sptr, endp, s)\
(sptr = s->cptr, endp = s->endptr - 1)
#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)\
begin_inline(sptr
, endp
, s
);
if ( val1
<= 0xf ) goto d2
;
d1
: /* Fast check for common case */
if ( sptr
>= endp
) goto x1
; /* no last char to save */
*endp
= ' '; /* force exit from fast loop */
f1
: if ( (val1
= decoder
[sptr
[1]]) <= 0xf &&
(val2
= decoder
[sptr
[2]]) <= 0xf
*ptr
++ = (val1
<< 4) + val2
;
if ( ptr
< limit
) goto f1
;
x1
: while ( (val1
= decoder
[sgetc_inline(sptr
, endp
, s
)]) > 0xf )
{ if ( val1
== ctype_eof
)
{ code
= ch
; *odd_digit
= -1; goto ended
; }
else if ( val1
!= ctype_space
&& !ignore_garbage
)
{ sptr
--; *odd_digit
= -1; goto err
; }
d2
: while ( (val2
= decoder
[sgetc_inline(sptr
, endp
, s
)]) > 0xf )
{ if ( val2
== ctype_eof
)
{ code
= ch
; *odd_digit
= val1
; goto ended
; }
else if ( val2
!= ctype_space
&& !ignore_garbage
)
{ sptr
--; *odd_digit
= val1
; goto err
; }
*ptr
++ = (val1
<< 4) + val2
;
if ( ptr
< limit
) goto d1
;
ended
: *nread
= ptr
- str
;
/* ------ String streams ------ */
/* Initialize a stream for reading a string. */
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_init(s
, ptr
, len
, &p
);
/* Handle end-of-buffer when reading from a string. */
s_string_read_buf(stream
*s
)
/* Return the number of available bytes when reading from a string. */
s_string_available(stream
*s
, long *pl
)
{ *pl
= sbufavailable(s
);
if ( *pl
== 0 ) *pl
= -1; /* EOF */
/* Initialize a stream for writing a string. */
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
,
s_string_init(s
, ptr
, len
, &p
);
/* Handle end-of-buffer when writing a string. */
s_string_write_buf(stream
*s
)
/* Seek in a string. Return 0 if OK, ERRC if not. */
s_string_seek(register stream
*s
, long pos
)
{ if ( pos
< 0 || pos
> s
->bsize
) return ERRC
;
s
->cptr
= s
->cbuf
+ pos
- 1;
/* Private initialization */
s_string_init(register stream
*s
, byte
*ptr
, uint len
, stream_procs
*p
)
{ s_std_init(s
, ptr
, len
, p
, s_mode_write
);
s
->end_status
= EOFC
; /* this is all there is */
s
->file
= 0; /* not a file stream */
/* ------ File streams ------ */
/* Initialize a stream for reading an OS file. */
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_std_init(s
, buf
, len
, &p
, s_mode_read
);
s
->position
= (file
== stdin
? -1 : 0);
/* Procedures for reading from a file */
s_file_read_buf(register stream
*s
)
if ( s
->position
>= 0 ) /* file is positionable */
s
->position
= ftell(s
->file
);
nread
= fread(s
->cbuf
, 1, s
->bsize
, s
->file
);
s
->end_status
= (ferror(s
->file
) ? ERRC
: feof(s
->file
) ? EOFC
: 0);
if ( nread
<= 0 ) nread
= 0;
s
->endptr
= s
->cptr
+ nread
;
s_file_available(register stream
*s
, long *pl
)
{ *pl
= sbufavailable(s
);
if ( fseek(s
->file
, 0L, 2) ) return ERRC
;
if ( fseek(s
->file
, pos
, 0) ) return ERRC
;
if ( *pl
== 0 ) *pl
= -1; /* EOF */
{ if ( *pl
== 0 && feof(s
->file
) ) *pl
= -1; /* EOF */
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;
if ( fseek(s
->file
, pos
, 0) != 0 )
s
->endptr
= s
->cptr
= s
->cbuf
- 1;
s_file_read_close(stream
*s
)
{ return fclose(s
->file
);
/* Initialize a stream for writing an OS file. */
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
,
s_std_init(s
, buf
, len
, &p
, s_mode_write
);
s
->position
= (file
== stdout
|| file
== stderr
? -1 : 0);
/* Procedures for writing on a file */
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
);
if ( write_count
!= count
)
{ s
->end_status
= (ferror(s
->file
) ? ERRC
: EOFC
);
s
->endptr
= s
->cptr
+ s
->bsize
;
s_file_write_seek(stream
*s
, long pos
)
{ /* Output files are not positionable */
s_file_write_flush(register stream
*s
)
{ int result
= s_file_write_buf(s
);
s_file_write_close(register stream
*s
)