jas_stream.c - vx32 - Local 9vx git repository for patches.
 (HTM) git clone git://r-36.net/vx32
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       jas_stream.c (30310B)
       ---
            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) 1999-2000 Image Power, Inc.
           13  * Copyright (c) 1999-2000 The University of British Columbia
           14  * Copyright (c) 2001-2003 Michael David Adams
           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 1969 2005-12-19 23:31:53Z baford $
           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 
          172 jas_stream_t *jas_stream_memopen(char *buf, int bufsize)
          173 {
          174         jas_stream_t *stream;
          175         jas_stream_memobj_t *obj;
          176 
          177         if (!(stream = jas_stream_create())) {
          178                 return 0;
          179         }
          180 
          181         /* A stream associated with a memory buffer is always opened
          182         for both reading and writing in binary mode. */
          183         stream->openmode_ = JAS_STREAM_READ | JAS_STREAM_WRITE | JAS_STREAM_BINARY;
          184 
          185         /* Since the stream data is already resident in memory, buffering
          186         is not necessary. */
          187         /* But... It still may be faster to use buffering anyways. */
          188         jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0);
          189 
          190         /* Select the operations for a memory stream. */
          191         stream->ops_ = &jas_stream_memops;
          192 
          193         /* Allocate memory for the underlying memory stream object. */
          194         if (!(obj = jas_malloc(sizeof(jas_stream_memobj_t)))) {
          195                 jas_stream_destroy(stream);
          196                 return 0;
          197         }
          198         stream->obj_ = (void *) obj;
          199 
          200         /* Initialize a few important members of the memory stream object. */
          201         obj->myalloc_ = 0;
          202         obj->buf_ = 0;
          203 
          204         /* If the buffer size specified is nonpositive, then the buffer
          205         is allocated internally and automatically grown as needed. */
          206         if (bufsize <= 0) {
          207                 obj->bufsize_ = 1024;
          208                 obj->growable_ = 1;
          209         } else {
          210                 obj->bufsize_ = bufsize;
          211                 obj->growable_ = 0;
          212         }
          213         if (buf) {
          214                 obj->buf_ = (unsigned char *) buf;
          215         } else {
          216                 obj->buf_ = jas_malloc(obj->bufsize_ * sizeof(char));
          217                 obj->myalloc_ = 1;
          218         }
          219         if (!obj->buf_) {
          220                 jas_stream_close(stream);
          221                 return 0;
          222         }
          223 
          224         if (bufsize > 0 && buf) {
          225                 /* If a buffer was supplied by the caller and its length is positive,
          226                   make the associated buffer data appear in the stream initially. */
          227                 obj->len_ = bufsize;
          228         } else {
          229                 /* The stream is initially empty. */
          230                 obj->len_ = 0;
          231         }
          232         obj->pos_ = 0;
          233         
          234         return stream;
          235 }
          236 
          237 jas_stream_t *jas_stream_fopen(const char *filename, const char *mode)
          238 {
          239         jas_stream_t *stream;
          240         jas_stream_fileobj_t *obj;
          241         int openflags;
          242 
          243         /* Allocate a stream object. */
          244         if (!(stream = jas_stream_create())) {
          245                 return 0;
          246         }
          247 
          248         /* Parse the mode string. */
          249         stream->openmode_ = jas_strtoopenmode(mode);
          250 
          251         /* Determine the correct flags to use for opening the file. */
          252         if ((stream->openmode_ & JAS_STREAM_READ) &&
          253           (stream->openmode_ & JAS_STREAM_WRITE)) {
          254                 openflags = O_RDWR;
          255         } else if (stream->openmode_ & JAS_STREAM_READ) {
          256                 openflags = O_RDONLY;
          257         } else if (stream->openmode_ & JAS_STREAM_WRITE) {
          258                 openflags = O_WRONLY;
          259         } else {
          260                 openflags = 0;
          261         }
          262         if (stream->openmode_ & JAS_STREAM_APPEND) {
          263                 openflags |= O_APPEND;
          264         }
          265         if (stream->openmode_ & JAS_STREAM_BINARY) {
          266                 openflags |= O_BINARY;
          267         }
          268         if (stream->openmode_ & JAS_STREAM_CREATE) {
          269                 openflags |= O_CREAT | O_TRUNC;
          270         }
          271 
          272         /* Allocate space for the underlying file stream object. */
          273         if (!(obj = jas_malloc(sizeof(jas_stream_fileobj_t)))) {
          274                 jas_stream_destroy(stream);
          275                 return 0;
          276         }
          277         obj->fd = -1;
          278         obj->flags = 0;
          279         obj->pathname[0] = '\0';
          280         stream->obj_ = (void *) obj;
          281 
          282         /* Select the operations for a file stream object. */
          283         stream->ops_ = &jas_stream_fileops;
          284 
          285         /* Open the underlying file. */
          286         if ((obj->fd = open(filename, openflags, JAS_STREAM_PERMS)) < 0) {
          287                 jas_stream_destroy(stream);
          288                 return 0;
          289         }
          290 
          291         /* By default, use full buffering for this type of stream. */
          292         jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0);
          293 
          294         return stream;
          295 }
          296 
          297 jas_stream_t *jas_stream_freopen(const char *path, const char *mode, FILE *fp)
          298 {
          299         jas_stream_t *stream;
          300         int openflags;
          301 
          302         /* Eliminate compiler warning about unused variable. */
          303         path = 0;
          304 
          305         /* Allocate a stream object. */
          306         if (!(stream = jas_stream_create())) {
          307                 return 0;
          308         }
          309 
          310         /* Parse the mode string. */
          311         stream->openmode_ = jas_strtoopenmode(mode);
          312 
          313         /* Determine the correct flags to use for opening the file. */
          314         if ((stream->openmode_ & JAS_STREAM_READ) &&
          315           (stream->openmode_ & JAS_STREAM_WRITE)) {
          316                 openflags = O_RDWR;
          317         } else if (stream->openmode_ & JAS_STREAM_READ) {
          318                 openflags = O_RDONLY;
          319         } else if (stream->openmode_ & JAS_STREAM_WRITE) {
          320                 openflags = O_WRONLY;
          321         } else {
          322                 openflags = 0;
          323         }
          324         if (stream->openmode_ & JAS_STREAM_APPEND) {
          325                 openflags |= O_APPEND;
          326         }
          327         if (stream->openmode_ & JAS_STREAM_BINARY) {
          328                 openflags |= O_BINARY;
          329         }
          330         if (stream->openmode_ & JAS_STREAM_CREATE) {
          331                 openflags |= O_CREAT | O_TRUNC;
          332         }
          333 
          334         stream->obj_ = JAS_CAST(void *, fp);
          335 
          336         /* Select the operations for a file stream object. */
          337         stream->ops_ = &jas_stream_sfileops;
          338 
          339         /* By default, use full buffering for this type of stream. */
          340         jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0);
          341 
          342         return stream;
          343 }
          344 
          345 jas_stream_t *jas_stream_tmpfile()
          346 {
          347         jas_stream_t *stream;
          348         jas_stream_fileobj_t *obj;
          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         obj->pathname[0] = '\0';
          366         stream->obj_ = obj;
          367 
          368         /* Choose a file name. */
          369         if(tmpnam(obj->pathname)){}
          370 
          371         /* Open the underlying file. */
          372         if ((obj->fd = open(obj->pathname, O_CREAT | O_EXCL | O_RDWR | O_TRUNC | O_BINARY,
          373           JAS_STREAM_PERMS)) < 0) {
          374                 jas_stream_destroy(stream);
          375                 return 0;
          376         }
          377 
          378         /* Unlink the file so that it will disappear if the program
          379         terminates abnormally. */
          380         /* Under UNIX, one can unlink an open file and continue to do I/O
          381         on it.  Not all operating systems support this functionality, however.
          382         For example, under Microsoft Windows the unlink operation will fail,
          383         since the file is open. */
          384         if (unlink(obj->pathname)) {
          385                 /* We will try unlinking the file again after it is closed. */
          386                 obj->flags |= JAS_STREAM_FILEOBJ_DELONCLOSE;
          387         }
          388 
          389         /* Use full buffering. */
          390         jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0);
          391 
          392         stream->ops_ = &jas_stream_fileops;
          393 
          394         return stream;
          395 }
          396 
          397 jas_stream_t *jas_stream_fdopen(int fd, const char *mode)
          398 {
          399         jas_stream_t *stream;
          400         jas_stream_fileobj_t *obj;
          401 
          402         /* Allocate a stream object. */
          403         if (!(stream = jas_stream_create())) {
          404                 return 0;
          405         }
          406 
          407         /* Parse the mode string. */
          408         stream->openmode_ = jas_strtoopenmode(mode);
          409 
          410 #if defined(WIN32)
          411         /* Argh!!!  Someone ought to banish text mode (i.e., O_TEXT) to the
          412           greatest depths of purgatory! */
          413         /* Ensure that the file descriptor is in binary mode, if the caller
          414           has specified the binary mode flag.  Arguably, the caller ought to
          415           take care of this, but text mode is a ugly wart anyways, so we save
          416           the caller some grief by handling this within the stream library. */
          417         /* This ugliness is mainly for the benefit of those who run the
          418           JasPer software under Windows from shells that insist on opening
          419           files in text mode.  For example, in the Cygwin environment,
          420           shells often open files in text mode when I/O redirection is
          421           used.  Grr... */
          422         if (stream->openmode_ & JAS_STREAM_BINARY) {
          423                 setmode(fd, O_BINARY);
          424         }
          425 #endif
          426 
          427         /* Allocate space for the underlying file stream object. */
          428         if (!(obj = jas_malloc(sizeof(jas_stream_fileobj_t)))) {
          429                 jas_stream_destroy(stream);
          430                 return 0;
          431         }
          432         obj->fd = fd;
          433         obj->flags = 0;
          434         obj->pathname[0] = '\0';
          435         stream->obj_ = (void *) obj;
          436 
          437         /* Do not close the underlying file descriptor when the stream is
          438         closed. */
          439         obj->flags |= JAS_STREAM_FILEOBJ_NOCLOSE;
          440 
          441         /* By default, use full buffering for this type of stream. */
          442         jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0);
          443 
          444         /* Select the operations for a file stream object. */
          445         stream->ops_ = &jas_stream_fileops;
          446 
          447         return stream;
          448 }
          449 
          450 static void jas_stream_destroy(jas_stream_t *stream)
          451 {
          452         /* If the memory for the buffer was allocated with malloc, free
          453         this memory. */
          454         if ((stream->bufmode_ & JAS_STREAM_FREEBUF) && stream->bufbase_) {
          455                 jas_free(stream->bufbase_);
          456                 stream->bufbase_ = 0;
          457         }
          458         jas_free(stream);
          459 }
          460 
          461 int jas_stream_close(jas_stream_t *stream)
          462 {
          463         /* Flush buffer if necessary. */
          464         jas_stream_flush(stream);
          465 
          466         /* Close the underlying stream object. */
          467         (*stream->ops_->close_)(stream->obj_);
          468 
          469         jas_stream_destroy(stream);
          470 
          471         return 0;
          472 }
          473 
          474 /******************************************************************************\
          475 * Code for reading and writing streams.
          476 \******************************************************************************/
          477 
          478 int jas_stream_getc_func(jas_stream_t *stream)
          479 {
          480         assert(stream->ptr_ - stream->bufbase_ <= stream->bufsize_ +
          481           JAS_STREAM_MAXPUTBACK);
          482         return jas_stream_getc_macro(stream);
          483 }
          484 
          485 int jas_stream_putc_func(jas_stream_t *stream, int c)
          486 {
          487         assert(stream->ptr_ - stream->bufstart_ <= stream->bufsize_);
          488         return jas_stream_putc_macro(stream, c);
          489 }
          490 
          491 int jas_stream_ungetc(jas_stream_t *stream, int c)
          492 {
          493         if (!stream->ptr_ || stream->ptr_ == stream->bufbase_) {
          494                 return -1;
          495         }
          496 
          497         /* Reset the EOF indicator (since we now have at least one character
          498           to read). */
          499         stream->flags_ &= ~JAS_STREAM_EOF;
          500 
          501         --stream->rwcnt_;
          502         --stream->ptr_;
          503         ++stream->cnt_;
          504         *stream->ptr_ = c;
          505         return 0;
          506 }
          507 
          508 int jas_stream_read(jas_stream_t *stream, void *buf, int cnt)
          509 {
          510         int n;
          511         int c;
          512         char *bufptr;
          513 
          514         bufptr = buf;
          515 
          516         n = 0;
          517         while (n < cnt) {
          518                 if ((c = jas_stream_getc(stream)) == EOF) {
          519                         return n;
          520                 }
          521                 *bufptr++ = c;
          522                 ++n;
          523         }
          524 
          525         return n;
          526 }
          527 
          528 int jas_stream_write(jas_stream_t *stream, const void *buf, int cnt)
          529 {
          530         int n;
          531         const char *bufptr;
          532 
          533         bufptr = buf;
          534 
          535         n = 0;
          536         while (n < cnt) {
          537                 if (jas_stream_putc(stream, *bufptr) == EOF) {
          538                         return n;
          539                 }
          540                 ++bufptr;
          541                 ++n;
          542         }
          543 
          544         return n;
          545 }
          546 
          547 /* Note: This function uses a fixed size buffer.  Therefore, it cannot
          548   handle invocations that will produce more output than can be held
          549   by the buffer. */
          550 int jas_stream_printf(jas_stream_t *stream, const char *fmt, ...)
          551 {
          552         va_list ap;
          553         char buf[4096];
          554         int ret;
          555 
          556         va_start(ap, fmt);
          557         ret = vsprintf(buf, fmt, ap);
          558         jas_stream_puts(stream, buf);
          559         va_end(ap);
          560         return ret;
          561 }
          562 
          563 int jas_stream_puts(jas_stream_t *stream, const char *s)
          564 {
          565         while (*s != '\0') {
          566                 if (jas_stream_putc_macro(stream, *s) == EOF) {
          567                         return -1;
          568                 }
          569                 ++s;
          570         }
          571         return 0;
          572 }
          573 
          574 char *jas_stream_gets(jas_stream_t *stream, char *buf, int bufsize)
          575 {
          576         int c;
          577         char *bufptr;
          578         assert(bufsize > 0);
          579 
          580         bufptr = buf;
          581         while (bufsize > 1) {
          582                 if ((c = jas_stream_getc(stream)) == EOF) {
          583                         break;
          584                 }
          585                 *bufptr++ = c;
          586                 --bufsize;
          587                 if (c == '\n') {
          588                         break;
          589                 }
          590         }
          591         *bufptr = '\0';
          592         return buf;
          593 }
          594 
          595 int jas_stream_gobble(jas_stream_t *stream, int n)
          596 {
          597         int m;
          598         m = n;
          599         for (m = n; m > 0; --m) {
          600                 if (jas_stream_getc(stream) == EOF) {
          601                         return n - m;
          602                 }
          603         }
          604         return n;
          605 }
          606 
          607 int jas_stream_pad(jas_stream_t *stream, int n, int c)
          608 {
          609         int m;
          610         m = n;
          611         for (m = n; m > 0; --m) {
          612                 if (jas_stream_putc(stream, c) == EOF)
          613                         return n - m;
          614         }
          615         return n;
          616 }
          617 
          618 /******************************************************************************\
          619 * Code for getting and setting the stream position.
          620 \******************************************************************************/
          621 
          622 int jas_stream_isseekable(jas_stream_t *stream)
          623 {
          624         if (stream->ops_ == &jas_stream_memops) {
          625                 return 1;
          626         } else if (stream->ops_ == &jas_stream_fileops) {
          627                 if ((*stream->ops_->seek_)(stream->obj_, 0, SEEK_CUR) < 0) {
          628                         return 0;
          629                 }
          630                 return 1;
          631         } else {
          632                 return 0;
          633         }
          634 }
          635 
          636 int jas_stream_rewind(jas_stream_t *stream)
          637 {
          638         return jas_stream_seek(stream, 0, SEEK_SET);
          639 }
          640 
          641 long jas_stream_seek(jas_stream_t *stream, long offset, int origin)
          642 {
          643         long newpos;
          644 
          645         /* The buffer cannot be in use for both reading and writing. */
          646         assert(!((stream->bufmode_ & JAS_STREAM_RDBUF) && (stream->bufmode_ &
          647           JAS_STREAM_WRBUF)));
          648 
          649         /* Reset the EOF indicator (since we may not be at the EOF anymore). */
          650         stream->flags_ &= ~JAS_STREAM_EOF;
          651 
          652         if (stream->bufmode_ & JAS_STREAM_RDBUF) {
          653                 if (origin == SEEK_CUR) {
          654                         offset -= stream->cnt_;
          655                 }
          656         } else if (stream->bufmode_ & JAS_STREAM_WRBUF) {
          657                 if (jas_stream_flush(stream)) {
          658                         return -1;
          659                 }
          660         }
          661         stream->cnt_ = 0;
          662         stream->ptr_ = stream->bufstart_;
          663         stream->bufmode_ &= ~(JAS_STREAM_RDBUF | JAS_STREAM_WRBUF);
          664 
          665         if ((newpos = (*stream->ops_->seek_)(stream->obj_, offset, origin))
          666           < 0) {
          667                 return -1;
          668         }
          669 
          670         return newpos;
          671 }
          672 
          673 long jas_stream_tell(jas_stream_t *stream)
          674 {
          675         int adjust;
          676         int offset;
          677 
          678         if (stream->bufmode_ & JAS_STREAM_RDBUF) {
          679                 adjust = -stream->cnt_;
          680         } else if (stream->bufmode_ & JAS_STREAM_WRBUF) {
          681                 adjust = stream->ptr_ - stream->bufstart_;
          682         } else {
          683                 adjust = 0;
          684         }
          685 
          686         if ((offset = (*stream->ops_->seek_)(stream->obj_, 0, SEEK_CUR)) < 0) {
          687                 return -1;
          688         }
          689 
          690         return offset + adjust;
          691 }
          692 
          693 /******************************************************************************\
          694 * Buffer initialization code.
          695 \******************************************************************************/
          696 
          697 static void jas_stream_initbuf(jas_stream_t *stream, int bufmode, char *buf,
          698   int bufsize)
          699 {
          700         /* If this function is being called, the buffer should not have been
          701           initialized yet. */
          702         assert(!stream->bufbase_);
          703 
          704         if (bufmode != JAS_STREAM_UNBUF) {
          705                 /* The full- or line-buffered mode is being employed. */
          706                 if (!buf) {
          707                         /* The caller has not specified a buffer to employ, so allocate
          708                           one. */
          709                         if ((stream->bufbase_ = jas_malloc(JAS_STREAM_BUFSIZE +
          710                           JAS_STREAM_MAXPUTBACK))) {
          711                                 stream->bufmode_ |= JAS_STREAM_FREEBUF;
          712                                 stream->bufsize_ = JAS_STREAM_BUFSIZE;
          713                         } else {
          714                                 /* The buffer allocation has failed.  Resort to unbuffered
          715                                   operation. */
          716                                 stream->bufbase_ = stream->tinybuf_;
          717                                 stream->bufsize_ = 1;
          718                         }
          719                 } else {
          720                         /* The caller has specified a buffer to employ. */
          721                         /* The buffer must be large enough to accommodate maximum
          722                           putback. */
          723                         assert(bufsize > JAS_STREAM_MAXPUTBACK);
          724                         stream->bufbase_ = JAS_CAST(uchar *, buf);
          725                         stream->bufsize_ = bufsize - JAS_STREAM_MAXPUTBACK;
          726                 }
          727         } else {
          728                 /* The unbuffered mode is being employed. */
          729                 /* A buffer should not have been supplied by the caller. */
          730                 assert(!buf);
          731                 /* Use a trivial one-character buffer. */
          732                 stream->bufbase_ = stream->tinybuf_;
          733                 stream->bufsize_ = 1;
          734         }
          735         stream->bufstart_ = &stream->bufbase_[JAS_STREAM_MAXPUTBACK];
          736         stream->ptr_ = stream->bufstart_;
          737         stream->cnt_ = 0;
          738         stream->bufmode_ |= bufmode & JAS_STREAM_BUFMODEMASK;
          739 }
          740 
          741 /******************************************************************************\
          742 * Buffer filling and flushing code.
          743 \******************************************************************************/
          744 
          745 int jas_stream_flush(jas_stream_t *stream)
          746 {
          747         if (stream->bufmode_ & JAS_STREAM_RDBUF) {
          748                 return 0;
          749         }
          750         return jas_stream_flushbuf(stream, EOF);
          751 }
          752 
          753 int jas_stream_fillbuf(jas_stream_t *stream, int getflag)
          754 {
          755         int c;
          756 
          757         /* The stream must not be in an error or EOF state. */
          758         if ((stream->flags_ & (JAS_STREAM_ERRMASK)) != 0) {
          759                 return EOF;
          760         }
          761 
          762         /* The stream must be open for reading. */
          763         if ((stream->openmode_ & JAS_STREAM_READ) == 0) {
          764                 return EOF;
          765         }
          766 
          767         /* Make a half-hearted attempt to confirm that the buffer is not
          768         currently being used for writing.  This check is not intended
          769         to be foolproof! */
          770         assert((stream->bufmode_ & JAS_STREAM_WRBUF) == 0);
          771 
          772         assert(stream->ptr_ - stream->bufstart_ <= stream->bufsize_);
          773 
          774         /* Mark the buffer as being used for reading. */
          775         stream->bufmode_ |= JAS_STREAM_RDBUF;
          776 
          777         /* Read new data into the buffer. */
          778         stream->ptr_ = stream->bufstart_;
          779         if ((stream->cnt_ = (*stream->ops_->read_)(stream->obj_,
          780           (char *) stream->bufstart_, stream->bufsize_)) <= 0) {
          781                 if (stream->cnt_ < 0) {
          782                         stream->flags_ |= JAS_STREAM_ERR;
          783                 } else {
          784                         stream->flags_ |= JAS_STREAM_EOF;
          785                 }
          786                 stream->cnt_ = 0;
          787                 return EOF;
          788         }
          789 
          790         assert(stream->cnt_ > 0);
          791         /* Get or peek at the first character in the buffer. */
          792         c = (getflag) ? jas_stream_getc2(stream) : (*stream->ptr_);
          793 
          794         return c;
          795 }
          796 
          797 int jas_stream_flushbuf(jas_stream_t *stream, int c)
          798 {
          799         int len;
          800         int n;
          801 
          802         /* The stream should not be in an error or EOF state. */
          803         if ((stream->flags_ & (JAS_STREAM_ERRMASK)) != 0) {
          804                 return EOF;
          805         }
          806 
          807         /* The stream must be open for writing. */
          808         if ((stream->openmode_ & (JAS_STREAM_WRITE | JAS_STREAM_APPEND)) == 0) {
          809                 return EOF;
          810         }
          811 
          812         /* The buffer should not currently be in use for reading. */
          813         assert(!(stream->bufmode_ & JAS_STREAM_RDBUF));
          814 
          815         /* Note: Do not use the quantity stream->cnt to determine the number
          816         of characters in the buffer!  Depending on how this function was
          817         called, the stream->cnt value may be "off-by-one". */
          818         len = stream->ptr_ - stream->bufstart_;
          819         if (len > 0) {
          820                 n = (*stream->ops_->write_)(stream->obj_, (char *)
          821                   stream->bufstart_, len);
          822                 if (n != len) {
          823                         stream->flags_ |= JAS_STREAM_ERR;
          824                         return EOF;
          825                 }
          826         }
          827         stream->cnt_ = stream->bufsize_;
          828         stream->ptr_ = stream->bufstart_;
          829 
          830         stream->bufmode_ |= JAS_STREAM_WRBUF;
          831 
          832         if (c != EOF) {
          833                 assert(stream->cnt_ > 0);
          834                 return jas_stream_putc2(stream, c);
          835         }
          836 
          837         return 0;
          838 }
          839 
          840 /******************************************************************************\
          841 * Miscellaneous code.
          842 \******************************************************************************/
          843 
          844 static int jas_strtoopenmode(const char *s)
          845 {
          846         int openmode = 0;
          847         while (*s != '\0') {
          848                 switch (*s) {
          849                 case 'r':
          850                         openmode |= JAS_STREAM_READ;
          851                         break;
          852                 case 'w':
          853                         openmode |= JAS_STREAM_WRITE | JAS_STREAM_CREATE;
          854                         break;
          855                 case 'b':
          856                         openmode |= JAS_STREAM_BINARY;
          857                         break;
          858                 case 'a':
          859                         openmode |= JAS_STREAM_APPEND;
          860                         break;
          861                 case '+':
          862                         openmode |= JAS_STREAM_READ | JAS_STREAM_WRITE;
          863                         break;
          864                 default:
          865                         break;
          866                 }
          867                 ++s;
          868         }
          869         return openmode;
          870 }
          871 
          872 int jas_stream_copy(jas_stream_t *out, jas_stream_t *in, int n)
          873 {
          874         int all;
          875         int c;
          876         int m;
          877 
          878         all = (n < 0) ? 1 : 0;
          879 
          880         m = n;
          881         while (all || m > 0) {
          882                 if ((c = jas_stream_getc_macro(in)) == EOF) {
          883                         /* The next character of input could not be read. */
          884                         /* Return with an error if an I/O error occured
          885                           (not including EOF) or if an explicit copy count
          886                           was specified. */
          887                         return (!all || jas_stream_error(in)) ? (-1) : 0;
          888                 }
          889                 if (jas_stream_putc_macro(out, c) == EOF) {
          890                         return -1;
          891                 }
          892                 --m;
          893         }
          894         return 0;
          895 }
          896 
          897 long jas_stream_setrwcount(jas_stream_t *stream, long rwcnt)
          898 {
          899         int old;
          900 
          901         old = stream->rwcnt_;
          902         stream->rwcnt_ = rwcnt;
          903         return old;
          904 }
          905 
          906 int jas_stream_display(jas_stream_t *stream, FILE *fp, int n)
          907 {
          908         unsigned char buf[16];
          909         int i;
          910         int j;
          911         int m;
          912         int c;
          913         int display;
          914         int cnt;
          915 
          916         cnt = n - (n % 16);
          917         display = 1;
          918 
          919         for (i = 0; i < n; i += 16) {
          920                 if (n > 16 && i > 0) {
          921                         display = (i >= cnt) ? 1 : 0;
          922                 }
          923                 if (display) {
          924                         fprintf(fp, "%08x:", i);
          925                 }
          926                 m = JAS_MIN(n - i, 16);
          927                 for (j = 0; j < m; ++j) {
          928                         if ((c = jas_stream_getc(stream)) == EOF) {
          929                                 abort();
          930                                 return -1;
          931                         }
          932                         buf[j] = c;
          933                 }
          934                 if (display) {
          935                         for (j = 0; j < m; ++j) {
          936                                 fprintf(fp, " %02x", buf[j]);
          937                         }
          938                         fputc(' ', fp);
          939                         for (; j < 16; ++j) {
          940                                 fprintf(fp, "   ");
          941                         }
          942                         for (j = 0; j < m; ++j) {
          943                                 if (isprint(buf[j])) {
          944                                         fputc(buf[j], fp);
          945                                 } else {
          946                                         fputc(' ', fp);
          947                                 }
          948                         }
          949                         fprintf(fp, "\n");
          950                 }
          951 
          952 
          953         }
          954         return 0;
          955 }
          956 
          957 long jas_stream_length(jas_stream_t *stream)
          958 {
          959         long oldpos;
          960         long pos;
          961         if ((oldpos = jas_stream_tell(stream)) < 0) {
          962                 return -1;
          963         }
          964         if (jas_stream_seek(stream, 0, SEEK_END) < 0) {
          965                 return -1;
          966         }
          967         if ((pos = jas_stream_tell(stream)) < 0) {
          968                 return -1;
          969         }
          970         if (jas_stream_seek(stream, oldpos, SEEK_SET) < 0) {
          971                 return -1;
          972         }
          973         return pos;
          974 }
          975 
          976 /******************************************************************************\
          977 * Memory stream object.
          978 \******************************************************************************/
          979 
          980 static int mem_read(jas_stream_obj_t *obj, char *buf, int cnt)
          981 {
          982         int n;
          983         jas_stream_memobj_t *m = (jas_stream_memobj_t *)obj;
          984         n = m->len_ - m->pos_;
          985         cnt = JAS_MIN(n, cnt);
          986         memcpy(buf, &m->buf_[m->pos_], cnt);
          987         m->pos_ += cnt;
          988         return cnt;
          989 }
          990 
          991 static int mem_resize(jas_stream_memobj_t *m, int bufsize)
          992 {
          993         unsigned char *buf;
          994 
          995         assert(m->buf_);
          996         if (!(buf = jas_realloc(m->buf_, bufsize * sizeof(unsigned char)))) {
          997                 return -1;
          998         }
          999         m->buf_ = buf;
         1000         m->bufsize_ = bufsize;
         1001         return 0;
         1002 }
         1003 
         1004 static int mem_write(jas_stream_obj_t *obj, char *buf, int cnt)
         1005 {
         1006         int n;
         1007         int ret;
         1008         jas_stream_memobj_t *m = (jas_stream_memobj_t *)obj;
         1009         long newbufsize;
         1010         long newpos;
         1011 
         1012         newpos = m->pos_ + cnt;
         1013         if (newpos > m->bufsize_ && m->growable_) {
         1014                 newbufsize = m->bufsize_;
         1015                 while (newbufsize < newpos) {
         1016                         newbufsize <<= 1;
         1017                         assert(newbufsize >= 0);
         1018                 }
         1019                 if (mem_resize(m, newbufsize)) {
         1020                         return -1;
         1021                 }
         1022         }
         1023         if (m->pos_ > m->len_) {
         1024                 /* The current position is beyond the end of the file, so
         1025                   pad the file to the current position with zeros. */
         1026                 n = JAS_MIN(m->pos_, m->bufsize_) - m->len_;
         1027                 if (n > 0) {
         1028                         memset(&m->buf_[m->len_], 0, n);
         1029                         m->len_ += n;
         1030                 }
         1031                 if (m->pos_ != m->len_) {
         1032                         /* The buffer is not big enough. */
         1033                         return 0;
         1034                 }
         1035         }
         1036         n = m->bufsize_ - m->pos_;
         1037         ret = JAS_MIN(n, cnt);
         1038         if (ret > 0) {
         1039                 memcpy(&m->buf_[m->pos_], buf, ret);
         1040                 m->pos_ += ret;
         1041         }
         1042         if (m->pos_ > m->len_) {
         1043                 m->len_ = m->pos_;
         1044         }
         1045 assert(ret == cnt);
         1046         return ret;
         1047 }
         1048 
         1049 static long mem_seek(jas_stream_obj_t *obj, long offset, int origin)
         1050 {
         1051         jas_stream_memobj_t *m = (jas_stream_memobj_t *)obj;
         1052         long newpos;
         1053 
         1054         switch (origin) {
         1055         case SEEK_SET:
         1056                 newpos = offset;
         1057                 break;
         1058         case SEEK_END:
         1059                 newpos = m->len_ - offset;
         1060                 break;
         1061         case SEEK_CUR:
         1062                 newpos = m->pos_ + offset;
         1063                 break;
         1064         default:
         1065                 abort();
         1066                 break;
         1067         }
         1068         if (newpos < 0) {
         1069                 return -1;
         1070         }
         1071         m->pos_ = newpos;
         1072 
         1073         return m->pos_;
         1074 }
         1075 
         1076 static int mem_close(jas_stream_obj_t *obj)
         1077 {
         1078         jas_stream_memobj_t *m = (jas_stream_memobj_t *)obj;
         1079         if (m->myalloc_ && m->buf_) {
         1080                 jas_free(m->buf_);
         1081                 m->buf_ = 0;
         1082         }
         1083         jas_free(obj);
         1084         return 0;
         1085 }
         1086 
         1087 /******************************************************************************\
         1088 * File stream object.
         1089 \******************************************************************************/
         1090 
         1091 static int file_read(jas_stream_obj_t *obj, char *buf, int cnt)
         1092 {
         1093         jas_stream_fileobj_t *fileobj = JAS_CAST(jas_stream_fileobj_t *, obj);
         1094         return read(fileobj->fd, buf, cnt);
         1095 }
         1096 
         1097 static int file_write(jas_stream_obj_t *obj, char *buf, int cnt)
         1098 {
         1099         jas_stream_fileobj_t *fileobj = JAS_CAST(jas_stream_fileobj_t *, obj);
         1100         return write(fileobj->fd, buf, cnt);
         1101 }
         1102 
         1103 static long file_seek(jas_stream_obj_t *obj, long offset, int origin)
         1104 {
         1105         jas_stream_fileobj_t *fileobj = JAS_CAST(jas_stream_fileobj_t *, obj);
         1106         return lseek(fileobj->fd, offset, origin);
         1107 }
         1108 
         1109 static int file_close(jas_stream_obj_t *obj)
         1110 {
         1111         jas_stream_fileobj_t *fileobj = JAS_CAST(jas_stream_fileobj_t *, obj);
         1112         int ret;
         1113         ret = close(fileobj->fd);
         1114         if (fileobj->flags & JAS_STREAM_FILEOBJ_DELONCLOSE) {
         1115                 unlink(fileobj->pathname);
         1116         }
         1117         jas_free(fileobj);
         1118         return ret;
         1119 }
         1120 
         1121 /******************************************************************************\
         1122 * Stdio file stream object.
         1123 \******************************************************************************/
         1124 
         1125 static int sfile_read(jas_stream_obj_t *obj, char *buf, int cnt)
         1126 {
         1127         FILE *fp;
         1128         fp = JAS_CAST(FILE *, obj);
         1129         return fread(buf, 1, cnt, fp);
         1130 }
         1131 
         1132 static int sfile_write(jas_stream_obj_t *obj, char *buf, int cnt)
         1133 {
         1134         FILE *fp;
         1135         fp = JAS_CAST(FILE *, obj);
         1136         return fwrite(buf, 1, cnt, fp);
         1137 }
         1138 
         1139 static long sfile_seek(jas_stream_obj_t *obj, long offset, int origin)
         1140 {
         1141         FILE *fp;
         1142         fp = JAS_CAST(FILE *, obj);
         1143         return fseek(fp, offset, origin);
         1144 }
         1145 
         1146 static int sfile_close(jas_stream_obj_t *obj)
         1147 {
         1148         FILE *fp;
         1149         fp = JAS_CAST(FILE *, obj);
         1150         return fclose(fp);
         1151 }
         1152 
         1153 
         1154 
         1155 // Kinda stupid that we have to add his extension hack,
         1156 // but it appears the JAS stream stuff wasn't really designed
         1157 // to be open-ended but to support only the above four stream types.
         1158 #ifdef VXA_NATIVE
         1159 #include "vxa/vxa.h"
         1160 #include "jp2/native.h"
         1161 
         1162 static int vxa_read(jas_stream_obj_t *obj, char *buf, int cnt)
         1163 {
         1164         vxaio *io = (vxaio*)obj;
         1165         return io->readf(io, buf, cnt);
         1166 }
         1167 
         1168 static int vxa_write(jas_stream_obj_t *obj, char *buf, int cnt)
         1169 {
         1170         vxaio *io = (vxaio*)obj;
         1171         return io->writef(io, buf, cnt);
         1172 }
         1173 
         1174 static long vxa_seek(jas_stream_obj_t *obj, long offset, int origin)
         1175 {
         1176         return -1;
         1177 }
         1178 
         1179 static int vxa_close(jas_stream_obj_t *obj)
         1180 {
         1181         return 0;
         1182 }
         1183 
         1184 
         1185 static jas_stream_ops_t jas_stream_vxaops = {
         1186         vxa_read,
         1187         vxa_write,
         1188         vxa_seek,
         1189         vxa_close
         1190 };
         1191 
         1192 jas_stream_t *jas_stream_vxaopen(vxaio *io, int openmode)
         1193 {
         1194         jas_stream_t *stream;
         1195 
         1196         if (!(stream = jas_stream_create())) {
         1197                 return 0;
         1198         }
         1199 
         1200         stream->openmode_ = openmode | JAS_STREAM_BINARY;
         1201         stream->ops_ = &jas_stream_vxaops;
         1202         stream->obj_ = (void*)io;
         1203 
         1204         jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0);
         1205 
         1206         return stream;
         1207 }
         1208 
         1209 #endif        // VXA_NATIVE