vx32

Local 9vx git repository for patches.
git clone git://r-36.net/vx32
Log | Files | 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