Home | History | Annotate | Download | only in libjasper
      1 /*
      2  * Copyright (c) 1999-2000 Image Power, Inc. and the University of
      3  *   British Columbia.
      4  * Copyright (c) 2001-2003 Michael David Adams.
      5  * All rights reserved.
      6  */
      7 
      8 /* __START_OF_JASPER_LICENSE__
      9  *
     10  * JasPer License Version 2.0
     11  *
     12  * Copyright (c) 2001-2006 Michael David Adams
     13  * Copyright (c) 1999-2000 Image Power, Inc.
     14  * Copyright (c) 1999-2000 The University of British Columbia
     15  *
     16  * All rights reserved.
     17  *
     18  * Permission is hereby granted, free of charge, to any person (the
     19  * "User") obtaining a copy of this software and associated documentation
     20  * files (the "Software"), to deal in the Software without restriction,
     21  * including without limitation the rights to use, copy, modify, merge,
     22  * publish, distribute, and/or sell copies of the Software, and to permit
     23  * persons to whom the Software is furnished to do so, subject to the
     24  * following conditions:
     25  *
     26  * 1.  The above copyright notices and this permission notice (which
     27  * includes the disclaimer below) shall be included in all copies or
     28  * substantial portions of the Software.
     29  *
     30  * 2.  The name of a copyright holder shall not be used to endorse or
     31  * promote products derived from the Software without specific prior
     32  * written permission.
     33  *
     34  * THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS
     35  * LICENSE.  NO USE OF THE SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER
     36  * THIS DISCLAIMER.  THE SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS
     37  * "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
     38  * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
     39  * PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.  IN NO
     40  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
     41  * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
     42  * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
     43  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
     44  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.  NO ASSURANCES ARE
     45  * PROVIDED BY THE COPYRIGHT HOLDERS THAT THE SOFTWARE DOES NOT INFRINGE
     46  * THE PATENT OR OTHER INTELLECTUAL PROPERTY RIGHTS OF ANY OTHER ENTITY.
     47  * EACH COPYRIGHT HOLDER DISCLAIMS ANY LIABILITY TO THE USER FOR CLAIMS
     48  * BROUGHT BY ANY OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL
     49  * PROPERTY RIGHTS OR OTHERWISE.  AS A CONDITION TO EXERCISING THE RIGHTS
     50  * GRANTED HEREUNDER, EACH USER HEREBY ASSUMES SOLE RESPONSIBILITY TO SECURE
     51  * ANY OTHER INTELLECTUAL PROPERTY RIGHTS NEEDED, IF ANY.  THE SOFTWARE
     52  * IS NOT FAULT-TOLERANT AND IS NOT INTENDED FOR USE IN MISSION-CRITICAL
     53  * SYSTEMS, SUCH AS THOSE USED IN THE OPERATION OF NUCLEAR FACILITIES,
     54  * AIRCRAFT NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL
     55  * SYSTEMS, DIRECT LIFE SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH
     56  * THE FAILURE OF THE SOFTWARE OR SYSTEM COULD LEAD DIRECTLY TO DEATH,
     57  * PERSONAL INJURY, OR SEVERE PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH
     58  * RISK ACTIVITIES").  THE COPYRIGHT HOLDERS SPECIFICALLY DISCLAIM ANY
     59  * EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR HIGH RISK ACTIVITIES.
     60  *
     61  * __END_OF_JASPER_LICENSE__
     62  */
     63 
     64 /*
     65  * I/O Stream Library
     66  *
     67  * $Id: jas_stream.c,v 1.2 2008-05-26 09:40:52 vp153 Exp $
     68  */
     69 
     70 /******************************************************************************\
     71 * Includes.
     72 \******************************************************************************/
     73 
     74 #include <assert.h>
     75 #if defined(HAVE_FCNTL_H)
     76 #include <fcntl.h>
     77 #endif
     78 #include <stdlib.h>
     79 #include <stdarg.h>
     80 #include <stdio.h>
     81 #include <ctype.h>
     82 #if defined(HAVE_UNISTD_H)
     83 #include <unistd.h>
     84 #endif
     85 #if defined(WIN32) || defined(HAVE_IO_H)
     86 #include <io.h>
     87 #endif
     88 
     89 #include "jasper/jas_types.h"
     90 #include "jasper/jas_stream.h"
     91 #include "jasper/jas_malloc.h"
     92 #include "jasper/jas_math.h"
     93 
     94 /******************************************************************************\
     95 * Local function prototypes.
     96 \******************************************************************************/
     97 
     98 static int jas_strtoopenmode(const char *s);
     99 static void jas_stream_destroy(jas_stream_t *stream);
    100 static jas_stream_t *jas_stream_create(void);
    101 static void jas_stream_initbuf(jas_stream_t *stream, int bufmode, char *buf,
    102   int bufsize);
    103 
    104 static int mem_read(jas_stream_obj_t *obj, char *buf, int cnt);
    105 static int mem_write(jas_stream_obj_t *obj, char *buf, int cnt);
    106 static long mem_seek(jas_stream_obj_t *obj, long offset, int origin);
    107 static int mem_close(jas_stream_obj_t *obj);
    108 
    109 static int sfile_read(jas_stream_obj_t *obj, char *buf, int cnt);
    110 static int sfile_write(jas_stream_obj_t *obj, char *buf, int cnt);
    111 static long sfile_seek(jas_stream_obj_t *obj, long offset, int origin);
    112 static int sfile_close(jas_stream_obj_t *obj);
    113 
    114 static int file_read(jas_stream_obj_t *obj, char *buf, int cnt);
    115 static int file_write(jas_stream_obj_t *obj, char *buf, int cnt);
    116 static long file_seek(jas_stream_obj_t *obj, long offset, int origin);
    117 static int file_close(jas_stream_obj_t *obj);
    118 
    119 /******************************************************************************\
    120 * Local data.
    121 \******************************************************************************/
    122 
    123 static jas_stream_ops_t jas_stream_fileops = {
    124     file_read,
    125     file_write,
    126     file_seek,
    127     file_close
    128 };
    129 
    130 static jas_stream_ops_t jas_stream_sfileops = {
    131     sfile_read,
    132     sfile_write,
    133     sfile_seek,
    134     sfile_close
    135 };
    136 
    137 static jas_stream_ops_t jas_stream_memops = {
    138     mem_read,
    139     mem_write,
    140     mem_seek,
    141     mem_close
    142 };
    143 
    144 /******************************************************************************\
    145 * Code for opening and closing streams.
    146 \******************************************************************************/
    147 
    148 static jas_stream_t *jas_stream_create()
    149 {
    150     jas_stream_t *stream;
    151 
    152     if (!(stream = jas_malloc(sizeof(jas_stream_t)))) {
    153         return 0;
    154     }
    155     stream->openmode_ = 0;
    156     stream->bufmode_ = 0;
    157     stream->flags_ = 0;
    158     stream->bufbase_ = 0;
    159     stream->bufstart_ = 0;
    160     stream->bufsize_ = 0;
    161     stream->ptr_ = 0;
    162     stream->cnt_ = 0;
    163     stream->ops_ = 0;
    164     stream->obj_ = 0;
    165     stream->rwcnt_ = 0;
    166     stream->rwlimit_ = -1;
    167 
    168     return stream;
    169 }
    170 
    171 jas_stream_t *jas_stream_memopen(char *buf, int bufsize)
    172 {
    173     jas_stream_t *stream;
    174     jas_stream_memobj_t *obj;
    175 
    176     if (!(stream = jas_stream_create())) {
    177         return 0;
    178     }
    179 
    180     /* A stream associated with a memory buffer is always opened
    181     for both reading and writing in binary mode. */
    182     stream->openmode_ = JAS_STREAM_READ | JAS_STREAM_WRITE | JAS_STREAM_BINARY;
    183 
    184     /* Since the stream data is already resident in memory, buffering
    185     is not necessary. */
    186     /* But... It still may be faster to use buffering anyways. */
    187     jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0);
    188 
    189     /* Select the operations for a memory stream. */
    190     stream->ops_ = &jas_stream_memops;
    191 
    192     /* Allocate memory for the underlying memory stream object. */
    193     if (!(obj = jas_malloc(sizeof(jas_stream_memobj_t)))) {
    194         jas_stream_destroy(stream);
    195         return 0;
    196     }
    197     stream->obj_ = (void *) obj;
    198 
    199     /* Initialize a few important members of the memory stream object. */
    200     obj->myalloc_ = 0;
    201     obj->buf_ = 0;
    202 
    203     /* If the buffer size specified is nonpositive, then the buffer
    204     is allocated internally and automatically grown as needed. */
    205     if (bufsize <= 0) {
    206         obj->bufsize_ = 1024;
    207         obj->growable_ = 1;
    208     } else {
    209         obj->bufsize_ = bufsize;
    210         obj->growable_ = 0;
    211     }
    212     if (buf) {
    213         obj->buf_ = (unsigned char *) buf;
    214     } else {
    215         obj->buf_ = jas_malloc(obj->bufsize_);
    216         obj->myalloc_ = 1;
    217     }
    218     if (!obj->buf_) {
    219         jas_stream_close(stream);
    220         return 0;
    221     }
    222 
    223     if (bufsize > 0 && buf) {
    224         /* If a buffer was supplied by the caller and its length is positive,
    225           make the associated buffer data appear in the stream initially. */
    226         obj->len_ = bufsize;
    227     } else {
    228         /* The stream is initially empty. */
    229         obj->len_ = 0;
    230     }
    231     obj->pos_ = 0;
    232 
    233     return stream;
    234 }
    235 
    236 jas_stream_t *jas_stream_fopen(const char *filename, const char *mode)
    237 {
    238     jas_stream_t *stream;
    239     jas_stream_fileobj_t *obj;
    240     int openflags;
    241 
    242     /* Allocate a stream object. */
    243     if (!(stream = jas_stream_create())) {
    244         return 0;
    245     }
    246 
    247     /* Parse the mode string. */
    248     stream->openmode_ = jas_strtoopenmode(mode);
    249 
    250     /* Determine the correct flags to use for opening the file. */
    251     if ((stream->openmode_ & JAS_STREAM_READ) &&
    252       (stream->openmode_ & JAS_STREAM_WRITE)) {
    253         openflags = O_RDWR;
    254     } else if (stream->openmode_ & JAS_STREAM_READ) {
    255         openflags = O_RDONLY;
    256     } else if (stream->openmode_ & JAS_STREAM_WRITE) {
    257         openflags = O_WRONLY;
    258     } else {
    259         openflags = 0;
    260     }
    261     if (stream->openmode_ & JAS_STREAM_APPEND) {
    262         openflags |= O_APPEND;
    263     }
    264     if (stream->openmode_ & JAS_STREAM_BINARY) {
    265         openflags |= O_BINARY;
    266     }
    267     if (stream->openmode_ & JAS_STREAM_CREATE) {
    268         openflags |= O_CREAT | O_TRUNC;
    269     }
    270 
    271     /* Allocate space for the underlying file stream object. */
    272     if (!(obj = jas_malloc(sizeof(jas_stream_fileobj_t)))) {
    273         jas_stream_destroy(stream);
    274         return 0;
    275     }
    276     obj->fd = -1;
    277     obj->flags = 0;
    278     obj->pathname[0] = '\0';
    279     stream->obj_ = (void *) obj;
    280 
    281     /* Select the operations for a file stream object. */
    282     stream->ops_ = &jas_stream_fileops;
    283 
    284     /* Open the underlying file. */
    285     if ((obj->fd = open(filename, openflags, JAS_STREAM_PERMS)) < 0) {
    286         jas_stream_destroy(stream);
    287         return 0;
    288     }
    289 
    290     /* By default, use full buffering for this type of stream. */
    291     jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0);
    292 
    293     return stream;
    294 }
    295 
    296 jas_stream_t *jas_stream_freopen(const char *path, const char *mode, FILE *fp)
    297 {
    298     jas_stream_t *stream;
    299     int openflags;
    300 
    301     /* Eliminate compiler warning about unused variable. */
    302     path = 0;
    303 
    304     /* Allocate a stream object. */
    305     if (!(stream = jas_stream_create())) {
    306         return 0;
    307     }
    308 
    309     /* Parse the mode string. */
    310     stream->openmode_ = jas_strtoopenmode(mode);
    311 
    312     /* Determine the correct flags to use for opening the file. */
    313     if ((stream->openmode_ & JAS_STREAM_READ) &&
    314       (stream->openmode_ & JAS_STREAM_WRITE)) {
    315         openflags = O_RDWR;
    316     } else if (stream->openmode_ & JAS_STREAM_READ) {
    317         openflags = O_RDONLY;
    318     } else if (stream->openmode_ & JAS_STREAM_WRITE) {
    319         openflags = O_WRONLY;
    320     } else {
    321         openflags = 0;
    322     }
    323     if (stream->openmode_ & JAS_STREAM_APPEND) {
    324         openflags |= O_APPEND;
    325     }
    326     if (stream->openmode_ & JAS_STREAM_BINARY) {
    327         openflags |= O_BINARY;
    328     }
    329     if (stream->openmode_ & JAS_STREAM_CREATE) {
    330         openflags |= O_CREAT | O_TRUNC;
    331     }
    332 
    333     stream->obj_ = JAS_CAST(void *, fp);
    334 
    335     /* Select the operations for a file stream object. */
    336     stream->ops_ = &jas_stream_sfileops;
    337 
    338     /* By default, use full buffering for this type of stream. */
    339     jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0);
    340 
    341     return stream;
    342 }
    343 
    344 jas_stream_t *jas_stream_tmpfile()
    345 {
    346     jas_stream_t *stream;
    347     jas_stream_fileobj_t *obj;
    348     char *tmpname;
    349 
    350     if (!(stream = jas_stream_create())) {
    351         return 0;
    352     }
    353 
    354     /* A temporary file stream is always opened for both reading and
    355     writing in binary mode. */
    356     stream->openmode_ = JAS_STREAM_READ | JAS_STREAM_WRITE | JAS_STREAM_BINARY;
    357 
    358     /* Allocate memory for the underlying temporary file object. */
    359     if (!(obj = jas_malloc(sizeof(jas_stream_fileobj_t)))) {
    360         jas_stream_destroy(stream);
    361         return 0;
    362     }
    363     obj->fd = -1;
    364     obj->flags = 0;
    365     stream->obj_ = obj;
    366 
    367 #ifdef _WIN32
    368     /* Choose a file name. */
    369     tmpname = tempnam(NULL, NULL);
    370     strcpy(obj->pathname, tmpname);
    371     free(tmpname);
    372 
    373     /* Open the underlying file. */
    374     if ((obj->fd = open(obj->pathname, O_CREAT | O_EXCL | O_RDWR | O_TRUNC | O_BINARY | O_TEMPORARY | _O_SHORT_LIVED,
    375       JAS_STREAM_PERMS)) < 0) {
    376         jas_stream_destroy(stream);
    377         return 0;
    378     }
    379 #else
    380     /* Choose a file name. */
    381     snprintf(obj->pathname, L_tmpnam, "%s/tmp.XXXXXXXXXX", P_tmpdir);
    382 
    383     /* Open the underlying file. */
    384     if ((obj->fd = mkstemp(obj->pathname)) < 0) {
    385         jas_stream_destroy(stream);
    386         return 0;
    387     }
    388 #endif
    389 
    390     /* Unlink the file so that it will disappear if the program
    391     terminates abnormally. */
    392     if (unlink(obj->pathname)) {
    393         jas_stream_destroy(stream);
    394         return 0;
    395     }
    396 
    397     /* Use full buffering. */
    398     jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0);
    399 
    400     stream->ops_ = &jas_stream_fileops;
    401 
    402     return stream;
    403 }
    404 
    405 jas_stream_t *jas_stream_fdopen(int fd, const char *mode)
    406 {
    407     jas_stream_t *stream;
    408     jas_stream_fileobj_t *obj;
    409 
    410     /* Allocate a stream object. */
    411     if (!(stream = jas_stream_create())) {
    412         return 0;
    413     }
    414 
    415     /* Parse the mode string. */
    416     stream->openmode_ = jas_strtoopenmode(mode);
    417 
    418 #if defined(WIN32)
    419     /* Argh!!!  Someone ought to banish text mode (i.e., O_TEXT) to the
    420       greatest depths of purgatory! */
    421     /* Ensure that the file descriptor is in binary mode, if the caller
    422       has specified the binary mode flag.  Arguably, the caller ought to
    423       take care of this, but text mode is a ugly wart anyways, so we save
    424       the caller some grief by handling this within the stream library. */
    425     /* This ugliness is mainly for the benefit of those who run the
    426       JasPer software under Windows from shells that insist on opening
    427       files in text mode.  For example, in the Cygwin environment,
    428       shells often open files in text mode when I/O redirection is
    429       used.  Grr... */
    430     if (stream->openmode_ & JAS_STREAM_BINARY) {
    431         setmode(fd, O_BINARY);
    432     }
    433 #endif
    434 
    435     /* Allocate space for the underlying file stream object. */
    436     if (!(obj = jas_malloc(sizeof(jas_stream_fileobj_t)))) {
    437         jas_stream_destroy(stream);
    438         return 0;
    439     }
    440     obj->fd = fd;
    441     obj->flags = 0;
    442     obj->pathname[0] = '\0';
    443     stream->obj_ = (void *) obj;
    444 
    445     /* Do not close the underlying file descriptor when the stream is
    446     closed. */
    447     obj->flags |= JAS_STREAM_FILEOBJ_NOCLOSE;
    448 
    449     /* By default, use full buffering for this type of stream. */
    450     jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0);
    451 
    452     /* Select the operations for a file stream object. */
    453     stream->ops_ = &jas_stream_fileops;
    454 
    455     return stream;
    456 }
    457 
    458 static void jas_stream_destroy(jas_stream_t *stream)
    459 {
    460     /* If the memory for the buffer was allocated with malloc, free
    461     this memory. */
    462     if ((stream->bufmode_ & JAS_STREAM_FREEBUF) && stream->bufbase_) {
    463         jas_free(stream->bufbase_);
    464         stream->bufbase_ = 0;
    465     }
    466     jas_free(stream);
    467 }
    468 
    469 int jas_stream_close(jas_stream_t *stream)
    470 {
    471     /* Flush buffer if necessary. */
    472     jas_stream_flush(stream);
    473 
    474     /* Close the underlying stream object. */
    475     (*stream->ops_->close_)(stream->obj_);
    476 
    477     jas_stream_destroy(stream);
    478 
    479     return 0;
    480 }
    481 
    482 /******************************************************************************\
    483 * Code for reading and writing streams.
    484 \******************************************************************************/
    485 
    486 int jas_stream_getc_func(jas_stream_t *stream)
    487 {
    488     assert(stream->ptr_ - stream->bufbase_ <= stream->bufsize_ +
    489       JAS_STREAM_MAXPUTBACK);
    490     return jas_stream_getc_macro(stream);
    491 }
    492 
    493 int jas_stream_putc_func(jas_stream_t *stream, int c)
    494 {
    495     assert(stream->ptr_ - stream->bufstart_ <= stream->bufsize_);
    496     return jas_stream_putc_macro(stream, c);
    497 }
    498 
    499 int jas_stream_ungetc(jas_stream_t *stream, int c)
    500 {
    501     if (!stream->ptr_ || stream->ptr_ == stream->bufbase_) {
    502         return -1;
    503     }
    504 
    505     /* Reset the EOF indicator (since we now have at least one character
    506       to read). */
    507     stream->flags_ &= ~JAS_STREAM_EOF;
    508 
    509     --stream->rwcnt_;
    510     --stream->ptr_;
    511     ++stream->cnt_;
    512     *stream->ptr_ = c;
    513     return 0;
    514 }
    515 
    516 int jas_stream_read(jas_stream_t *stream, void *buf, int cnt)
    517 {
    518     int n;
    519     int c;
    520     char *bufptr;
    521 
    522     bufptr = buf;
    523 
    524     n = 0;
    525     while (n < cnt) {
    526         if ((c = jas_stream_getc(stream)) == EOF) {
    527             return n;
    528         }
    529         *bufptr++ = c;
    530         ++n;
    531     }
    532 
    533     return n;
    534 }
    535 
    536 int jas_stream_write(jas_stream_t *stream, const void *buf, int cnt)
    537 {
    538     int n;
    539     const char *bufptr;
    540 
    541     bufptr = buf;
    542 
    543     n = 0;
    544     while (n < cnt) {
    545         if (jas_stream_putc(stream, *bufptr) == EOF) {
    546             return n;
    547         }
    548         ++bufptr;
    549         ++n;
    550     }
    551 
    552     return n;
    553 }
    554 
    555 /* Note: This function uses a fixed size buffer.  Therefore, it cannot
    556   handle invocations that will produce more output than can be held
    557   by the buffer. */
    558 int jas_stream_printf(jas_stream_t *stream, const char *fmt, ...)
    559 {
    560     va_list ap;
    561     char buf[4096];
    562     int ret;
    563 
    564     va_start(ap, fmt);
    565     ret = vsnprintf(buf, sizeof buf, fmt, ap);
    566     jas_stream_puts(stream, buf);
    567     va_end(ap);
    568     return ret;
    569 }
    570 
    571 int jas_stream_puts(jas_stream_t *stream, const char *s)
    572 {
    573     while (*s != '\0') {
    574         if (jas_stream_putc_macro(stream, *s) == EOF) {
    575             return -1;
    576         }
    577         ++s;
    578     }
    579     return 0;
    580 }
    581 
    582 char *jas_stream_gets(jas_stream_t *stream, char *buf, int bufsize)
    583 {
    584     int c;
    585     char *bufptr;
    586     assert(bufsize > 0);
    587 
    588     bufptr = buf;
    589     while (bufsize > 1) {
    590         if ((c = jas_stream_getc(stream)) == EOF) {
    591             break;
    592         }
    593         *bufptr++ = c;
    594         --bufsize;
    595         if (c == '\n') {
    596             break;
    597         }
    598     }
    599     *bufptr = '\0';
    600     return buf;
    601 }
    602 
    603 int jas_stream_gobble(jas_stream_t *stream, int n)
    604 {
    605     int m;
    606     m = n;
    607     for (m = n; m > 0; --m) {
    608         if (jas_stream_getc(stream) == EOF) {
    609             return n - m;
    610         }
    611     }
    612     return n;
    613 }
    614 
    615 int jas_stream_pad(jas_stream_t *stream, int n, int c)
    616 {
    617     int m;
    618     m = n;
    619     for (m = n; m > 0; --m) {
    620         if (jas_stream_putc(stream, c) == EOF)
    621             return n - m;
    622     }
    623     return n;
    624 }
    625 
    626 /******************************************************************************\
    627 * Code for getting and setting the stream position.
    628 \******************************************************************************/
    629 
    630 int jas_stream_isseekable(jas_stream_t *stream)
    631 {
    632     if (stream->ops_ == &jas_stream_memops) {
    633         return 1;
    634     } else if (stream->ops_ == &jas_stream_fileops) {
    635         if ((*stream->ops_->seek_)(stream->obj_, 0, SEEK_CUR) < 0) {
    636             return 0;
    637         }
    638         return 1;
    639     } else {
    640         return 0;
    641     }
    642 }
    643 
    644 int jas_stream_rewind(jas_stream_t *stream)
    645 {
    646     return jas_stream_seek(stream, 0, SEEK_SET);
    647 }
    648 
    649 long jas_stream_seek(jas_stream_t *stream, long offset, int origin)
    650 {
    651     long newpos;
    652 
    653     /* The buffer cannot be in use for both reading and writing. */
    654     assert(!((stream->bufmode_ & JAS_STREAM_RDBUF) && (stream->bufmode_ &
    655       JAS_STREAM_WRBUF)));
    656 
    657     /* Reset the EOF indicator (since we may not be at the EOF anymore). */
    658     stream->flags_ &= ~JAS_STREAM_EOF;
    659 
    660     if (stream->bufmode_ & JAS_STREAM_RDBUF) {
    661         if (origin == SEEK_CUR) {
    662             offset -= stream->cnt_;
    663         }
    664     } else if (stream->bufmode_ & JAS_STREAM_WRBUF) {
    665         if (jas_stream_flush(stream)) {
    666             return -1;
    667         }
    668     }
    669     stream->cnt_ = 0;
    670     stream->ptr_ = stream->bufstart_;
    671     stream->bufmode_ &= ~(JAS_STREAM_RDBUF | JAS_STREAM_WRBUF);
    672 
    673     if ((newpos = (*stream->ops_->seek_)(stream->obj_, offset, origin))
    674       < 0) {
    675         return -1;
    676     }
    677 
    678     return newpos;
    679 }
    680 
    681 long jas_stream_tell(jas_stream_t *stream)
    682 {
    683     int adjust;
    684     int offset;
    685 
    686     if (stream->bufmode_ & JAS_STREAM_RDBUF) {
    687         adjust = -stream->cnt_;
    688     } else if (stream->bufmode_ & JAS_STREAM_WRBUF) {
    689         adjust = stream->ptr_ - stream->bufstart_;
    690     } else {
    691         adjust = 0;
    692     }
    693 
    694     if ((offset = (*stream->ops_->seek_)(stream->obj_, 0, SEEK_CUR)) < 0) {
    695         return -1;
    696     }
    697 
    698     return offset + adjust;
    699 }
    700 
    701 /******************************************************************************\
    702 * Buffer initialization code.
    703 \******************************************************************************/
    704 
    705 static void jas_stream_initbuf(jas_stream_t *stream, int bufmode, char *buf,
    706   int bufsize)
    707 {
    708     /* If this function is being called, the buffer should not have been
    709       initialized yet. */
    710     assert(!stream->bufbase_);
    711 
    712     if (bufmode != JAS_STREAM_UNBUF) {
    713         /* The full- or line-buffered mode is being employed. */
    714         if (!buf) {
    715             /* The caller has not specified a buffer to employ, so allocate
    716               one. */
    717             if ((stream->bufbase_ = jas_malloc(JAS_STREAM_BUFSIZE +
    718               JAS_STREAM_MAXPUTBACK))) {
    719                 stream->bufmode_ |= JAS_STREAM_FREEBUF;
    720                 stream->bufsize_ = JAS_STREAM_BUFSIZE;
    721             } else {
    722                 /* The buffer allocation has failed.  Resort to unbuffered
    723                   operation. */
    724                 stream->bufbase_ = stream->tinybuf_;
    725                 stream->bufsize_ = 1;
    726             }
    727         } else {
    728             /* The caller has specified a buffer to employ. */
    729             /* The buffer must be large enough to accommodate maximum
    730               putback. */
    731             assert(bufsize > JAS_STREAM_MAXPUTBACK);
    732             stream->bufbase_ = JAS_CAST(uchar *, buf);
    733             stream->bufsize_ = bufsize - JAS_STREAM_MAXPUTBACK;
    734         }
    735     } else {
    736         /* The unbuffered mode is being employed. */
    737         /* A buffer should not have been supplied by the caller. */
    738         assert(!buf);
    739         /* Use a trivial one-character buffer. */
    740         stream->bufbase_ = stream->tinybuf_;
    741         stream->bufsize_ = 1;
    742     }
    743     stream->bufstart_ = &stream->bufbase_[JAS_STREAM_MAXPUTBACK];
    744     stream->ptr_ = stream->bufstart_;
    745     stream->cnt_ = 0;
    746     stream->bufmode_ |= bufmode & JAS_STREAM_BUFMODEMASK;
    747 }
    748 
    749 /******************************************************************************\
    750 * Buffer filling and flushing code.
    751 \******************************************************************************/
    752 
    753 int jas_stream_flush(jas_stream_t *stream)
    754 {
    755     if (stream->bufmode_ & JAS_STREAM_RDBUF) {
    756         return 0;
    757     }
    758     return jas_stream_flushbuf(stream, EOF);
    759 }
    760 
    761 int jas_stream_fillbuf(jas_stream_t *stream, int getflag)
    762 {
    763     int c;
    764 
    765     /* The stream must not be in an error or EOF state. */
    766     if ((stream->flags_ & (JAS_STREAM_ERRMASK)) != 0) {
    767         return EOF;
    768     }
    769 
    770     /* The stream must be open for reading. */
    771     if ((stream->openmode_ & JAS_STREAM_READ) == 0) {
    772         return EOF;
    773     }
    774 
    775     /* Make a half-hearted attempt to confirm that the buffer is not
    776     currently being used for writing.  This check is not intended
    777     to be foolproof! */
    778     assert((stream->bufmode_ & JAS_STREAM_WRBUF) == 0);
    779 
    780     assert(stream->ptr_ - stream->bufstart_ <= stream->bufsize_);
    781 
    782     /* Mark the buffer as being used for reading. */
    783     stream->bufmode_ |= JAS_STREAM_RDBUF;
    784 
    785     /* Read new data into the buffer. */
    786     stream->ptr_ = stream->bufstart_;
    787     if ((stream->cnt_ = (*stream->ops_->read_)(stream->obj_,
    788       (char *) stream->bufstart_, stream->bufsize_)) <= 0) {
    789         if (stream->cnt_ < 0) {
    790             stream->flags_ |= JAS_STREAM_ERR;
    791         } else {
    792             stream->flags_ |= JAS_STREAM_EOF;
    793         }
    794         stream->cnt_ = 0;
    795         return EOF;
    796     }
    797 
    798     assert(stream->cnt_ > 0);
    799     /* Get or peek at the first character in the buffer. */
    800     c = (getflag) ? jas_stream_getc2(stream) : (*stream->ptr_);
    801 
    802     return c;
    803 }
    804 
    805 int jas_stream_flushbuf(jas_stream_t *stream, int c)
    806 {
    807     int len;
    808     int n;
    809 
    810     /* The stream should not be in an error or EOF state. */
    811     if ((stream->flags_ & (JAS_STREAM_ERRMASK)) != 0) {
    812         return EOF;
    813     }
    814 
    815     /* The stream must be open for writing. */
    816     if ((stream->openmode_ & (JAS_STREAM_WRITE | JAS_STREAM_APPEND)) == 0) {
    817         return EOF;
    818     }
    819 
    820     /* The buffer should not currently be in use for reading. */
    821     assert(!(stream->bufmode_ & JAS_STREAM_RDBUF));
    822 
    823     /* Note: Do not use the quantity stream->cnt to determine the number
    824     of characters in the buffer!  Depending on how this function was
    825     called, the stream->cnt value may be "off-by-one". */
    826     len = stream->ptr_ - stream->bufstart_;
    827     if (len > 0) {
    828         n = (*stream->ops_->write_)(stream->obj_, (char *)
    829           stream->bufstart_, len);
    830         if (n != len) {
    831             stream->flags_ |= JAS_STREAM_ERR;
    832             return EOF;
    833         }
    834     }
    835     stream->cnt_ = stream->bufsize_;
    836     stream->ptr_ = stream->bufstart_;
    837 
    838     stream->bufmode_ |= JAS_STREAM_WRBUF;
    839 
    840     if (c != EOF) {
    841         assert(stream->cnt_ > 0);
    842         return jas_stream_putc2(stream, c);
    843     }
    844 
    845     return 0;
    846 }
    847 
    848 /******************************************************************************\
    849 * Miscellaneous code.
    850 \******************************************************************************/
    851 
    852 static int jas_strtoopenmode(const char *s)
    853 {
    854     int openmode = 0;
    855     while (*s != '\0') {
    856         switch (*s) {
    857         case 'r':
    858             openmode |= JAS_STREAM_READ;
    859             break;
    860         case 'w':
    861             openmode |= JAS_STREAM_WRITE | JAS_STREAM_CREATE;
    862             break;
    863         case 'b':
    864             openmode |= JAS_STREAM_BINARY;
    865             break;
    866         case 'a':
    867             openmode |= JAS_STREAM_APPEND;
    868             break;
    869         case '+':
    870             openmode |= JAS_STREAM_READ | JAS_STREAM_WRITE;
    871             break;
    872         default:
    873             break;
    874         }
    875         ++s;
    876     }
    877     return openmode;
    878 }
    879 
    880 int jas_stream_copy(jas_stream_t *out, jas_stream_t *in, int n)
    881 {
    882     int all;
    883     int c;
    884     int m;
    885 
    886     all = (n < 0) ? 1 : 0;
    887 
    888     m = n;
    889     while (all || m > 0) {
    890         if ((c = jas_stream_getc_macro(in)) == EOF) {
    891             /* The next character of input could not be read. */
    892             /* Return with an error if an I/O error occured
    893               (not including EOF) or if an explicit copy count
    894               was specified. */
    895             return (!all || jas_stream_error(in)) ? (-1) : 0;
    896         }
    897         if (jas_stream_putc_macro(out, c) == EOF) {
    898             return -1;
    899         }
    900         --m;
    901     }
    902     return 0;
    903 }
    904 
    905 long jas_stream_setrwcount(jas_stream_t *stream, long rwcnt)
    906 {
    907     int old;
    908 
    909     old = stream->rwcnt_;
    910     stream->rwcnt_ = rwcnt;
    911     return old;
    912 }
    913 
    914 int jas_stream_display(jas_stream_t *stream, FILE *fp, int n)
    915 {
    916     unsigned char buf[16];
    917     int i;
    918     int j;
    919     int m;
    920     int c;
    921     int display;
    922     int cnt;
    923 
    924     cnt = n - (n % 16);
    925     display = 1;
    926 
    927     for (i = 0; i < n; i += 16) {
    928         if (n > 16 && i > 0) {
    929             display = (i >= cnt) ? 1 : 0;
    930         }
    931         if (display) {
    932             fprintf(fp, "%08x:", i);
    933         }
    934         m = JAS_MIN(n - i, 16);
    935         for (j = 0; j < m; ++j) {
    936             if ((c = jas_stream_getc(stream)) == EOF) {
    937                 abort();
    938                 return -1;
    939             }
    940             buf[j] = c;
    941         }
    942         if (display) {
    943             for (j = 0; j < m; ++j) {
    944                 fprintf(fp, " %02x", buf[j]);
    945             }
    946             fputc(' ', fp);
    947             for (; j < 16; ++j) {
    948                 fprintf(fp, "   ");
    949             }
    950             for (j = 0; j < m; ++j) {
    951                 if (isprint(buf[j])) {
    952                     fputc(buf[j], fp);
    953                 } else {
    954                     fputc(' ', fp);
    955                 }
    956             }
    957             fprintf(fp, "\n");
    958         }
    959 
    960 
    961     }
    962     return 0;
    963 }
    964 
    965 long jas_stream_length(jas_stream_t *stream)
    966 {
    967     long oldpos;
    968     long pos;
    969     if ((oldpos = jas_stream_tell(stream)) < 0) {
    970         return -1;
    971     }
    972     if (jas_stream_seek(stream, 0, SEEK_END) < 0) {
    973         return -1;
    974     }
    975     if ((pos = jas_stream_tell(stream)) < 0) {
    976         return -1;
    977     }
    978     if (jas_stream_seek(stream, oldpos, SEEK_SET) < 0) {
    979         return -1;
    980     }
    981     return pos;
    982 }
    983 
    984 /******************************************************************************\
    985 * Memory stream object.
    986 \******************************************************************************/
    987 
    988 static int mem_read(jas_stream_obj_t *obj, char *buf, int cnt)
    989 {
    990     int n;
    991     jas_stream_memobj_t *m = (jas_stream_memobj_t *)obj;
    992     n = m->len_ - m->pos_;
    993     cnt = JAS_MIN(n, cnt);
    994     memcpy(buf, &m->buf_[m->pos_], cnt);
    995     m->pos_ += cnt;
    996     return cnt;
    997 }
    998 
    999 static int mem_resize(jas_stream_memobj_t *m, int bufsize)
   1000 {
   1001     unsigned char *buf;
   1002 
   1003     assert(m->buf_);
   1004     if (!(buf = jas_realloc(m->buf_, bufsize))) {
   1005         return -1;
   1006     }
   1007     m->buf_ = buf;
   1008     m->bufsize_ = bufsize;
   1009     return 0;
   1010 }
   1011 
   1012 static int mem_write(jas_stream_obj_t *obj, char *buf, int cnt)
   1013 {
   1014     int n;
   1015     int ret;
   1016     jas_stream_memobj_t *m = (jas_stream_memobj_t *)obj;
   1017     long newbufsize;
   1018     long newpos;
   1019 
   1020     newpos = m->pos_ + cnt;
   1021     if (newpos > m->bufsize_ && m->growable_) {
   1022         newbufsize = m->bufsize_;
   1023         while (newbufsize < newpos) {
   1024             newbufsize <<= 1;
   1025             assert(newbufsize >= 0);
   1026         }
   1027         if (mem_resize(m, newbufsize)) {
   1028             return -1;
   1029         }
   1030     }
   1031     if (m->pos_ > m->len_) {
   1032         /* The current position is beyond the end of the file, so
   1033           pad the file to the current position with zeros. */
   1034         n = JAS_MIN(m->pos_, m->bufsize_) - m->len_;
   1035         if (n > 0) {
   1036             memset(&m->buf_[m->len_], 0, n);
   1037             m->len_ += n;
   1038         }
   1039         if (m->pos_ != m->len_) {
   1040             /* The buffer is not big enough. */
   1041             return 0;
   1042         }
   1043     }
   1044     n = m->bufsize_ - m->pos_;
   1045     ret = JAS_MIN(n, cnt);
   1046     if (ret > 0) {
   1047         memcpy(&m->buf_[m->pos_], buf, ret);
   1048         m->pos_ += ret;
   1049     }
   1050     if (m->pos_ > m->len_) {
   1051         m->len_ = m->pos_;
   1052     }
   1053 assert(ret == cnt);
   1054     return ret;
   1055 }
   1056 
   1057 static long mem_seek(jas_stream_obj_t *obj, long offset, int origin)
   1058 {
   1059     jas_stream_memobj_t *m = (jas_stream_memobj_t *)obj;
   1060     long newpos;
   1061 
   1062     switch (origin) {
   1063     case SEEK_SET:
   1064         newpos = offset;
   1065         break;
   1066     case SEEK_END:
   1067         newpos = m->len_ - offset;
   1068         break;
   1069     case SEEK_CUR:
   1070         newpos = m->pos_ + offset;
   1071         break;
   1072     default:
   1073         abort();
   1074         break;
   1075     }
   1076     if (newpos < 0) {
   1077         return -1;
   1078     }
   1079     m->pos_ = newpos;
   1080 
   1081     return m->pos_;
   1082 }
   1083 
   1084 static int mem_close(jas_stream_obj_t *obj)
   1085 {
   1086     jas_stream_memobj_t *m = (jas_stream_memobj_t *)obj;
   1087     if (m->myalloc_ && m->buf_) {
   1088         jas_free(m->buf_);
   1089         m->buf_ = 0;
   1090     }
   1091     jas_free(obj);
   1092     return 0;
   1093 }
   1094 
   1095 /******************************************************************************\
   1096 * File stream object.
   1097 \******************************************************************************/
   1098 
   1099 static int file_read(jas_stream_obj_t *obj, char *buf, int cnt)
   1100 {
   1101     jas_stream_fileobj_t *fileobj = JAS_CAST(jas_stream_fileobj_t *, obj);
   1102     return read(fileobj->fd, buf, cnt);
   1103 }
   1104 
   1105 static int file_write(jas_stream_obj_t *obj, char *buf, int cnt)
   1106 {
   1107     jas_stream_fileobj_t *fileobj = JAS_CAST(jas_stream_fileobj_t *, obj);
   1108     return write(fileobj->fd, buf, cnt);
   1109 }
   1110 
   1111 static long file_seek(jas_stream_obj_t *obj, long offset, int origin)
   1112 {
   1113     jas_stream_fileobj_t *fileobj = JAS_CAST(jas_stream_fileobj_t *, obj);
   1114     return lseek(fileobj->fd, offset, origin);
   1115 }
   1116 
   1117 static int file_close(jas_stream_obj_t *obj)
   1118 {
   1119     jas_stream_fileobj_t *fileobj = JAS_CAST(jas_stream_fileobj_t *, obj);
   1120     int ret;
   1121     ret = close(fileobj->fd);
   1122     if (fileobj->flags & JAS_STREAM_FILEOBJ_DELONCLOSE) {
   1123         unlink(fileobj->pathname);
   1124     }
   1125     jas_free(fileobj);
   1126     return ret;
   1127 }
   1128 
   1129 /******************************************************************************\
   1130 * Stdio file stream object.
   1131 \******************************************************************************/
   1132 
   1133 static int sfile_read(jas_stream_obj_t *obj, char *buf, int cnt)
   1134 {
   1135     FILE *fp;
   1136     fp = JAS_CAST(FILE *, obj);
   1137     return fread(buf, 1, cnt, fp);
   1138 }
   1139 
   1140 static int sfile_write(jas_stream_obj_t *obj, char *buf, int cnt)
   1141 {
   1142     FILE *fp;
   1143     fp = JAS_CAST(FILE *, obj);
   1144     return fwrite(buf, 1, cnt, fp);
   1145 }
   1146 
   1147 static long sfile_seek(jas_stream_obj_t *obj, long offset, int origin)
   1148 {
   1149     FILE *fp;
   1150     fp = JAS_CAST(FILE *, obj);
   1151     return fseek(fp, offset, origin);
   1152 }
   1153 
   1154 static int sfile_close(jas_stream_obj_t *obj)
   1155 {
   1156     FILE *fp;
   1157     fp = JAS_CAST(FILE *, obj);
   1158     return fclose(fp);
   1159 }
   1160