jas_stream.c
来自「SumatraPDF是一款小型开源的pdf阅读工具。虽然玲珑小巧(只有800多K」· C语言 代码 · 共 1,170 行 · 第 1/3 页
C
1,170 行
terminates abnormally. */
/* Under UNIX, one can unlink an open file and continue to do I/O
on it. Not all operating systems support this functionality, however.
For example, under Microsoft Windows the unlink operation will fail,
since the file is open. */
if (unlink(obj->pathname)) {
/* We will try unlinking the file again after it is closed. */
obj->flags |= JAS_STREAM_FILEOBJ_DELONCLOSE;
}
/* Use full buffering. */
jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0);
stream->ops_ = &jas_stream_fileops;
return stream;
}
jas_stream_t *jas_stream_fdopen(int fd, const char *mode)
{
jas_stream_t *stream;
jas_stream_fileobj_t *obj;
/* Allocate a stream object. */
if (!(stream = jas_stream_create())) {
return 0;
}
/* Parse the mode string. */
stream->openmode_ = jas_strtoopenmode(mode);
#if defined(WIN32)
/* Argh!!! Someone ought to banish text mode (i.e., O_TEXT) to the
greatest depths of purgatory! */
/* Ensure that the file descriptor is in binary mode, if the caller
has specified the binary mode flag. Arguably, the caller ought to
take care of this, but text mode is a ugly wart anyways, so we save
the caller some grief by handling this within the stream library. */
/* This ugliness is mainly for the benefit of those who run the
JasPer software under Windows from shells that insist on opening
files in text mode. For example, in the Cygwin environment,
shells often open files in text mode when I/O redirection is
used. Grr... */
if (stream->openmode_ & JAS_STREAM_BINARY) {
setmode(fd, O_BINARY);
}
#endif
/* Allocate space for the underlying file stream object. */
if (!(obj = jas_malloc(sizeof(jas_stream_fileobj_t)))) {
jas_stream_destroy(stream);
return 0;
}
obj->fd = fd;
obj->flags = 0;
obj->pathname[0] = '\0';
stream->obj_ = (void *) obj;
/* Do not close the underlying file descriptor when the stream is
closed. */
obj->flags |= JAS_STREAM_FILEOBJ_NOCLOSE;
/* By default, use full buffering for this type of stream. */
jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0);
/* Select the operations for a file stream object. */
stream->ops_ = &jas_stream_fileops;
return stream;
}
static void jas_stream_destroy(jas_stream_t *stream)
{
/* If the memory for the buffer was allocated with malloc, free
this memory. */
if ((stream->bufmode_ & JAS_STREAM_FREEBUF) && stream->bufbase_) {
jas_free(stream->bufbase_);
stream->bufbase_ = 0;
}
jas_free(stream);
}
int jas_stream_close(jas_stream_t *stream)
{
/* Flush buffer if necessary. */
jas_stream_flush(stream);
/* Close the underlying stream object. */
(*stream->ops_->close_)(stream->obj_);
jas_stream_destroy(stream);
return 0;
}
/******************************************************************************\
* Code for reading and writing streams.
\******************************************************************************/
int jas_stream_getc_func(jas_stream_t *stream)
{
assert(stream->ptr_ - stream->bufbase_ <= stream->bufsize_ +
JAS_STREAM_MAXPUTBACK);
return jas_stream_getc_macro(stream);
}
int jas_stream_putc_func(jas_stream_t *stream, int c)
{
assert(stream->ptr_ - stream->bufstart_ <= stream->bufsize_);
return jas_stream_putc_macro(stream, c);
}
int jas_stream_ungetc(jas_stream_t *stream, int c)
{
if (!stream->ptr_ || stream->ptr_ == stream->bufbase_) {
return -1;
}
/* Reset the EOF indicator (since we now have at least one character
to read). */
stream->flags_ &= ~JAS_STREAM_EOF;
--stream->rwcnt_;
--stream->ptr_;
++stream->cnt_;
*stream->ptr_ = c;
return 0;
}
int jas_stream_read(jas_stream_t *stream, void *buf, int cnt)
{
int n;
int c;
char *bufptr;
bufptr = buf;
n = 0;
while (n < cnt) {
if ((c = jas_stream_getc(stream)) == EOF) {
return n;
}
*bufptr++ = c;
++n;
}
return n;
}
int jas_stream_write(jas_stream_t *stream, const void *buf, int cnt)
{
int n;
const char *bufptr;
bufptr = buf;
n = 0;
while (n < cnt) {
if (jas_stream_putc(stream, *bufptr) == EOF) {
return n;
}
++bufptr;
++n;
}
return n;
}
/* Note: This function uses a fixed size buffer. Therefore, it cannot
handle invocations that will produce more output than can be held
by the buffer. */
int jas_stream_printf(jas_stream_t *stream, const char *fmt, ...)
{
va_list ap;
char buf[4096];
int ret;
va_start(ap, fmt);
ret = vsprintf(buf, fmt, ap);
jas_stream_puts(stream, buf);
va_end(ap);
return ret;
}
int jas_stream_puts(jas_stream_t *stream, const char *s)
{
while (*s != '\0') {
if (jas_stream_putc_macro(stream, *s) == EOF) {
return -1;
}
++s;
}
return 0;
}
char *jas_stream_gets(jas_stream_t *stream, char *buf, int bufsize)
{
int c;
char *bufptr;
assert(bufsize > 0);
bufptr = buf;
while (bufsize > 1) {
if ((c = jas_stream_getc(stream)) == EOF) {
break;
}
*bufptr++ = c;
--bufsize;
if (c == '\n') {
break;
}
}
*bufptr = '\0';
return buf;
}
int jas_stream_gobble(jas_stream_t *stream, int n)
{
int m;
m = n;
for (m = n; m > 0; --m) {
if (jas_stream_getc(stream) == EOF) {
return n - m;
}
}
return n;
}
int jas_stream_pad(jas_stream_t *stream, int n, int c)
{
int m;
m = n;
for (m = n; m > 0; --m) {
if (jas_stream_putc(stream, c) == EOF)
return n - m;
}
return n;
}
/******************************************************************************\
* Code for getting and setting the stream position.
\******************************************************************************/
int jas_stream_isseekable(jas_stream_t *stream)
{
if (stream->ops_ == &jas_stream_memops) {
return 1;
} else if (stream->ops_ == &jas_stream_fileops) {
if ((*stream->ops_->seek_)(stream->obj_, 0, SEEK_CUR) < 0) {
return 0;
}
return 1;
} else {
return 0;
}
}
int jas_stream_rewind(jas_stream_t *stream)
{
return jas_stream_seek(stream, 0, SEEK_SET);
}
long jas_stream_seek(jas_stream_t *stream, long offset, int origin)
{
long newpos;
/* The buffer cannot be in use for both reading and writing. */
assert(!((stream->bufmode_ & JAS_STREAM_RDBUF) && (stream->bufmode_ &
JAS_STREAM_WRBUF)));
/* Reset the EOF indicator (since we may not be at the EOF anymore). */
stream->flags_ &= ~JAS_STREAM_EOF;
if (stream->bufmode_ & JAS_STREAM_RDBUF) {
if (origin == SEEK_CUR) {
offset -= stream->cnt_;
}
} else if (stream->bufmode_ & JAS_STREAM_WRBUF) {
if (jas_stream_flush(stream)) {
return -1;
}
}
stream->cnt_ = 0;
stream->ptr_ = stream->bufstart_;
stream->bufmode_ &= ~(JAS_STREAM_RDBUF | JAS_STREAM_WRBUF);
if ((newpos = (*stream->ops_->seek_)(stream->obj_, offset, origin))
< 0) {
return -1;
}
return newpos;
}
long jas_stream_tell(jas_stream_t *stream)
{
int adjust;
int offset;
if (stream->bufmode_ & JAS_STREAM_RDBUF) {
adjust = -stream->cnt_;
} else if (stream->bufmode_ & JAS_STREAM_WRBUF) {
adjust = stream->ptr_ - stream->bufstart_;
} else {
adjust = 0;
}
if ((offset = (*stream->ops_->seek_)(stream->obj_, 0, SEEK_CUR)) < 0) {
return -1;
}
return offset + adjust;
}
/******************************************************************************\
* Buffer initialization code.
\******************************************************************************/
static void jas_stream_initbuf(jas_stream_t *stream, int bufmode, char *buf,
int bufsize)
{
/* If this function is being called, the buffer should not have been
initialized yet. */
assert(!stream->bufbase_);
if (bufmode != JAS_STREAM_UNBUF) {
/* The full- or line-buffered mode is being employed. */
if (!buf) {
/* The caller has not specified a buffer to employ, so allocate
one. */
if ((stream->bufbase_ = jas_malloc(JAS_STREAM_BUFSIZE +
JAS_STREAM_MAXPUTBACK))) {
stream->bufmode_ |= JAS_STREAM_FREEBUF;
stream->bufsize_ = JAS_STREAM_BUFSIZE;
} else {
/* The buffer allocation has failed. Resort to unbuffered
operation. */
stream->bufbase_ = stream->tinybuf_;
stream->bufsize_ = 1;
}
} else {
/* The caller has specified a buffer to employ. */
/* The buffer must be large enough to accommodate maximum
putback. */
assert(bufsize > JAS_STREAM_MAXPUTBACK);
stream->bufbase_ = JAS_CAST(uchar *, buf);
stream->bufsize_ = bufsize - JAS_STREAM_MAXPUTBACK;
}
} else {
/* The unbuffered mode is being employed. */
/* A buffer should not have been supplied by the caller. */
assert(!buf);
/* Use a trivial one-character buffer. */
stream->bufbase_ = stream->tinybuf_;
stream->bufsize_ = 1;
}
stream->bufstart_ = &stream->bufbase_[JAS_STREAM_MAXPUTBACK];
stream->ptr_ = stream->bufstart_;
stream->cnt_ = 0;
stream->bufmode_ |= bufmode & JAS_STREAM_BUFMODEMASK;
}
/******************************************************************************\
* Buffer filling and flushing code.
\******************************************************************************/
int jas_stream_flush(jas_stream_t *stream)
{
if (stream->bufmode_ & JAS_STREAM_RDBUF) {
return 0;
}
return jas_stream_flushbuf(stream, EOF);
}
int jas_stream_fillbuf(jas_stream_t *stream, int getflag)
{
int c;
/* The stream must not be in an error or EOF state. */
if ((stream->flags_ & (JAS_STREAM_ERRMASK)) != 0) {
return EOF;
}
/* The stream must be open for reading. */
if ((stream->openmode_ & JAS_STREAM_READ) == 0) {
return EOF;
}
/* Make a half-hearted attempt to confirm that the buffer is not
currently being used for writing. This check is not intended
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?