2 * Copyright (c) 1999-2000 Image Power, Inc. and the University of
4 * Copyright (c) 2001-2003 Michael David Adams.
8 /* __START_OF_JASPER_LICENSE__
10 * JasPer License Version 2.0
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
16 * All rights reserved.
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:
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.
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
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.
61 * __END_OF_JASPER_LICENSE__
67 * $Id: jas_stream.c,v 1.2 2005/06/04 01:54:02 malaterre Exp $
70 /******************************************************************************\
72 \******************************************************************************/
75 #if defined(HAVE_FCNTL_H)
82 #if defined(HAVE_UNISTD_H)
85 #if defined(WIN32) || defined(HAVE_IO_H)
89 #include "jasper/jas_types.h"
90 #include "jasper/jas_stream.h"
91 #include "jasper/jas_malloc.h"
92 #include "jasper/jas_math.h"
94 /******************************************************************************\
95 * Local function prototypes.
96 \******************************************************************************/
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,
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);
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);
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);
119 /******************************************************************************\
121 \******************************************************************************/
123 static jas_stream_ops_t jas_stream_fileops = {
130 static jas_stream_ops_t jas_stream_sfileops = {
137 static jas_stream_ops_t jas_stream_memops = {
144 /******************************************************************************\
145 * Code for opening and closing streams.
146 \******************************************************************************/
148 static jas_stream_t *jas_stream_create()
150 jas_stream_t *stream;
152 if (!(stream = jas_malloc(sizeof(jas_stream_t)))) {
155 stream->openmode_ = 0;
156 stream->bufmode_ = 0;
158 stream->bufbase_ = 0;
159 stream->bufstart_ = 0;
160 stream->bufsize_ = 0;
166 stream->rwlimit_ = -1;
171 GLOBAL(jas_stream_t) *jas_stream_memopen(char *buf, int bufsize)
173 jas_stream_t *stream;
174 jas_stream_memobj_t *obj;
176 if (!(stream = jas_stream_create())) {
180 /* A stream associated with a memory buffer is always opened
181 for both reading and writing in binary mode. */
182 stream->openmode_ = JAS_STREAM_READ | JAS_STREAM_WRITE | JAS_STREAM_BINARY;
184 /* Since the stream data is already resident in memory, buffering
186 /* But... It still may be faster to use buffering anyways. */
187 jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0);
189 /* Select the operations for a memory stream. */
190 stream->ops_ = &jas_stream_memops;
192 /* Allocate memory for the underlying memory stream object. */
193 if (!(obj = jas_malloc(sizeof(jas_stream_memobj_t)))) {
194 jas_stream_destroy(stream);
197 stream->obj_ = (void *) obj;
199 /* Initialize a few important members of the memory stream object. */
203 /* If the buffer size specified is nonpositive, then the buffer
204 is allocated internally and automatically grown as needed. */
206 obj->bufsize_ = 1024;
209 obj->bufsize_ = bufsize;
213 obj->buf_ = (unsigned char *) buf;
215 obj->buf_ = jas_malloc(obj->bufsize_ * sizeof(char));
219 jas_stream_close(stream);
223 if (bufsize > 0 && buf) {
224 /* If a buffer was supplied by the caller and its length is positive,
225 make the associated buffer data appear in the stream initially. */
228 /* The stream is initially empty. */
236 jas_stream_t *jas_stream_fopen(const char *filename, const char *mode)
238 jas_stream_t *stream;
239 jas_stream_fileobj_t *obj;
242 /* Allocate a stream object. */
243 if (!(stream = jas_stream_create())) {
247 /* Parse the mode string. */
248 stream->openmode_ = jas_strtoopenmode(mode);
250 /* Determine the correct flags to use for opening the file. */
251 if ((stream->openmode_ & JAS_STREAM_READ) &&
252 (stream->openmode_ & JAS_STREAM_WRITE)) {
254 } else if (stream->openmode_ & JAS_STREAM_READ) {
255 openflags = O_RDONLY;
256 } else if (stream->openmode_ & JAS_STREAM_WRITE) {
257 openflags = O_WRONLY;
261 if (stream->openmode_ & JAS_STREAM_APPEND) {
262 openflags |= O_APPEND;
264 if (stream->openmode_ & JAS_STREAM_BINARY) {
265 openflags |= O_BINARY;
267 if (stream->openmode_ & JAS_STREAM_CREATE) {
268 openflags |= O_CREAT | O_TRUNC;
271 /* Allocate space for the underlying file stream object. */
272 if (!(obj = jas_malloc(sizeof(jas_stream_fileobj_t)))) {
273 jas_stream_destroy(stream);
278 obj->pathname[0] = '\0';
279 stream->obj_ = (void *) obj;
281 /* Select the operations for a file stream object. */
282 stream->ops_ = &jas_stream_fileops;
284 /* Open the underlying file. */
285 if ((obj->fd = open(filename, openflags, JAS_STREAM_PERMS)) < 0) {
286 jas_stream_destroy(stream);
290 /* By default, use full buffering for this type of stream. */
291 jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0);
296 jas_stream_t *jas_stream_freopen(const char *path, const char *mode, FILE *fp)
298 jas_stream_t *stream;
301 /* Eliminate compiler warning about unused variable. */
304 /* Allocate a stream object. */
305 if (!(stream = jas_stream_create())) {
309 /* Parse the mode string. */
310 stream->openmode_ = jas_strtoopenmode(mode);
312 /* Determine the correct flags to use for opening the file. */
313 if ((stream->openmode_ & JAS_STREAM_READ) &&
314 (stream->openmode_ & JAS_STREAM_WRITE)) {
316 } else if (stream->openmode_ & JAS_STREAM_READ) {
317 openflags = O_RDONLY;
318 } else if (stream->openmode_ & JAS_STREAM_WRITE) {
319 openflags = O_WRONLY;
323 if (stream->openmode_ & JAS_STREAM_APPEND) {
324 openflags |= O_APPEND;
326 if (stream->openmode_ & JAS_STREAM_BINARY) {
327 openflags |= O_BINARY;
329 if (stream->openmode_ & JAS_STREAM_CREATE) {
330 openflags |= O_CREAT | O_TRUNC;
333 stream->obj_ = JAS_CAST(void *, fp);
335 /* Select the operations for a file stream object. */
336 stream->ops_ = &jas_stream_sfileops;
338 /* By default, use full buffering for this type of stream. */
339 jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0);
344 jas_stream_t *jas_stream_tmpfile()
346 jas_stream_t *stream;
347 jas_stream_fileobj_t *obj;
349 if (!(stream = jas_stream_create())) {
353 /* A temporary file stream is always opened for both reading and
354 writing in binary mode. */
355 stream->openmode_ = JAS_STREAM_READ | JAS_STREAM_WRITE | JAS_STREAM_BINARY;
357 /* Allocate memory for the underlying temporary file object. */
358 if (!(obj = jas_malloc(sizeof(jas_stream_fileobj_t)))) {
359 jas_stream_destroy(stream);
364 obj->pathname[0] = '\0';
367 /* Choose a file name. */
368 tmpnam(obj->pathname);
370 /* Open the underlying file. */
371 if ((obj->fd = open(obj->pathname, O_CREAT | O_EXCL | O_RDWR | O_TRUNC | O_BINARY,
372 JAS_STREAM_PERMS)) < 0) {
373 jas_stream_destroy(stream);
377 /* Unlink the file so that it will disappear if the program
378 terminates abnormally. */
379 /* Under UNIX, one can unlink an open file and continue to do I/O
380 on it. Not all operating systems support this functionality, however.
381 For example, under Microsoft Windows the unlink operation will fail,
382 since the file is open. */
383 if (unlink(obj->pathname)) {
384 /* We will try unlinking the file again after it is closed. */
385 obj->flags |= JAS_STREAM_FILEOBJ_DELONCLOSE;
388 /* Use full buffering. */
389 jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0);
391 stream->ops_ = &jas_stream_fileops;
396 jas_stream_t *jas_stream_fdopen(int fd, const char *mode)
398 jas_stream_t *stream;
399 jas_stream_fileobj_t *obj;
401 /* Allocate a stream object. */
402 if (!(stream = jas_stream_create())) {
406 /* Parse the mode string. */
407 stream->openmode_ = jas_strtoopenmode(mode);
410 /* Argh!!! Someone ought to banish text mode (i.e., O_TEXT) to the
411 greatest depths of purgatory! */
412 /* Ensure that the file descriptor is in binary mode, if the caller
413 has specified the binary mode flag. Arguably, the caller ought to
414 take care of this, but text mode is a ugly wart anyways, so we save
415 the caller some grief by handling this within the stream library. */
416 /* This ugliness is mainly for the benefit of those who run the
417 JasPer software under Windows from shells that insist on opening
418 files in text mode. For example, in the Cygwin environment,
419 shells often open files in text mode when I/O redirection is
421 if (stream->openmode_ & JAS_STREAM_BINARY) {
422 setmode(fd, O_BINARY);
426 /* Allocate space for the underlying file stream object. */
427 if (!(obj = jas_malloc(sizeof(jas_stream_fileobj_t)))) {
428 jas_stream_destroy(stream);
433 obj->pathname[0] = '\0';
434 stream->obj_ = (void *) obj;
436 /* Do not close the underlying file descriptor when the stream is
438 obj->flags |= JAS_STREAM_FILEOBJ_NOCLOSE;
440 /* By default, use full buffering for this type of stream. */
441 jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0);
443 /* Select the operations for a file stream object. */
444 stream->ops_ = &jas_stream_fileops;
449 static void jas_stream_destroy(jas_stream_t *stream)
451 /* If the memory for the buffer was allocated with malloc, free
453 if ((stream->bufmode_ & JAS_STREAM_FREEBUF) && stream->bufbase_) {
454 jas_free(stream->bufbase_);
455 stream->bufbase_ = 0;
460 GLOBAL(int) jas_stream_close(jas_stream_t *stream)
462 /* Flush buffer if necessary. */
463 jas_stream_flush(stream);
465 /* Close the underlying stream object. */
466 (*stream->ops_->close_)(stream->obj_);
468 jas_stream_destroy(stream);
473 /******************************************************************************\
474 * Code for reading and writing streams.
475 \******************************************************************************/
477 int jas_stream_getc_func(jas_stream_t *stream)
479 assert(stream->ptr_ - stream->bufbase_ <= stream->bufsize_ +
480 JAS_STREAM_MAXPUTBACK);
481 return jas_stream_getc_macro(stream);
484 int jas_stream_putc_func(jas_stream_t *stream, int c)
486 assert(stream->ptr_ - stream->bufstart_ <= stream->bufsize_);
487 return jas_stream_putc_macro(stream, c);
490 int jas_stream_ungetc(jas_stream_t *stream, int c)
492 if (!stream->ptr_ || stream->ptr_ == stream->bufbase_) {
496 /* Reset the EOF indicator (since we now have at least one character
498 stream->flags_ &= ~JAS_STREAM_EOF;
507 int jas_stream_read(jas_stream_t *stream, void *buf, int cnt)
517 if ((c = jas_stream_getc(stream)) == EOF) {
527 int jas_stream_write(jas_stream_t *stream, const void *buf, int cnt)
536 if (jas_stream_putc(stream, *bufptr) == EOF) {
546 /* Note: This function uses a fixed size buffer. Therefore, it cannot
547 handle invocations that will produce more output than can be held
549 int jas_stream_printf(jas_stream_t *stream, const char *fmt, ...)
556 ret = vsprintf(buf, fmt, ap);
557 jas_stream_puts(stream, buf);
562 int jas_stream_puts(jas_stream_t *stream, const char *s)
565 if (jas_stream_putc_macro(stream, *s) == EOF) {
573 char *jas_stream_gets(jas_stream_t *stream, char *buf, int bufsize)
580 while (bufsize > 1) {
581 if ((c = jas_stream_getc(stream)) == EOF) {
594 int jas_stream_gobble(jas_stream_t *stream, int n)
598 for (m = n; m > 0; --m) {
599 if (jas_stream_getc(stream) == EOF) {
606 int jas_stream_pad(jas_stream_t *stream, int n, int c)
610 for (m = n; m > 0; --m) {
611 if (jas_stream_putc(stream, c) == EOF)
617 /******************************************************************************\
618 * Code for getting and setting the stream position.
619 \******************************************************************************/
621 int jas_stream_isseekable(jas_stream_t *stream)
623 if (stream->ops_ == &jas_stream_memops) {
625 } else if (stream->ops_ == &jas_stream_fileops) {
626 if ((*stream->ops_->seek_)(stream->obj_, 0, SEEK_CUR) < 0) {
635 int jas_stream_rewind(jas_stream_t *stream)
637 return jas_stream_seek(stream, 0, SEEK_SET);
640 long jas_stream_seek(jas_stream_t *stream, long offset, int origin)
644 /* The buffer cannot be in use for both reading and writing. */
645 assert(!((stream->bufmode_ & JAS_STREAM_RDBUF) && (stream->bufmode_ &
648 /* Reset the EOF indicator (since we may not be at the EOF anymore). */
649 stream->flags_ &= ~JAS_STREAM_EOF;
651 if (stream->bufmode_ & JAS_STREAM_RDBUF) {
652 if (origin == SEEK_CUR) {
653 offset -= stream->cnt_;
655 } else if (stream->bufmode_ & JAS_STREAM_WRBUF) {
656 if (jas_stream_flush(stream)) {
661 stream->ptr_ = stream->bufstart_;
662 stream->bufmode_ &= ~(JAS_STREAM_RDBUF | JAS_STREAM_WRBUF);
664 if ((newpos = (*stream->ops_->seek_)(stream->obj_, offset, origin))
672 long jas_stream_tell(jas_stream_t *stream)
677 if (stream->bufmode_ & JAS_STREAM_RDBUF) {
678 adjust = -stream->cnt_;
679 } else if (stream->bufmode_ & JAS_STREAM_WRBUF) {
680 adjust = stream->ptr_ - stream->bufstart_;
685 if ((offset = (*stream->ops_->seek_)(stream->obj_, 0, SEEK_CUR)) < 0) {
689 return offset + adjust;
692 /******************************************************************************\
693 * Buffer initialization code.
694 \******************************************************************************/
696 static void jas_stream_initbuf(jas_stream_t *stream, int bufmode, char *buf,
699 /* If this function is being called, the buffer should not have been
701 assert(!stream->bufbase_);
703 if (bufmode != JAS_STREAM_UNBUF) {
704 /* The full- or line-buffered mode is being employed. */
706 /* The caller has not specified a buffer to employ, so allocate
708 if ((stream->bufbase_ = jas_malloc(JAS_STREAM_BUFSIZE +
709 JAS_STREAM_MAXPUTBACK))) {
710 stream->bufmode_ |= JAS_STREAM_FREEBUF;
711 stream->bufsize_ = JAS_STREAM_BUFSIZE;
713 /* The buffer allocation has failed. Resort to unbuffered
715 stream->bufbase_ = stream->tinybuf_;
716 stream->bufsize_ = 1;
719 /* The caller has specified a buffer to employ. */
720 /* The buffer must be large enough to accommodate maximum
722 assert(bufsize > JAS_STREAM_MAXPUTBACK);
723 stream->bufbase_ = JAS_CAST(uchar *, buf);
724 stream->bufsize_ = bufsize - JAS_STREAM_MAXPUTBACK;
727 /* The unbuffered mode is being employed. */
728 /* A buffer should not have been supplied by the caller. */
730 /* Use a trivial one-character buffer. */
731 stream->bufbase_ = stream->tinybuf_;
732 stream->bufsize_ = 1;
734 stream->bufstart_ = &stream->bufbase_[JAS_STREAM_MAXPUTBACK];
735 stream->ptr_ = stream->bufstart_;
737 stream->bufmode_ |= bufmode & JAS_STREAM_BUFMODEMASK;
740 /******************************************************************************\
741 * Buffer filling and flushing code.
742 \******************************************************************************/
744 int jas_stream_flush(jas_stream_t *stream)
746 if (stream->bufmode_ & JAS_STREAM_RDBUF) {
749 return jas_stream_flushbuf(stream, EOF);
752 int jas_stream_fillbuf(jas_stream_t *stream, int getflag)
756 /* The stream must not be in an error or EOF state. */
757 if ((stream->flags_ & (JAS_STREAM_ERRMASK)) != 0) {
761 /* The stream must be open for reading. */
762 if ((stream->openmode_ & JAS_STREAM_READ) == 0) {
766 /* Make a half-hearted attempt to confirm that the buffer is not
767 currently being used for writing. This check is not intended
769 assert((stream->bufmode_ & JAS_STREAM_WRBUF) == 0);
771 assert(stream->ptr_ - stream->bufstart_ <= stream->bufsize_);
773 /* Mark the buffer as being used for reading. */
774 stream->bufmode_ |= JAS_STREAM_RDBUF;
776 /* Read new data into the buffer. */
777 stream->ptr_ = stream->bufstart_;
778 if ((stream->cnt_ = (*stream->ops_->read_)(stream->obj_,
779 (char *) stream->bufstart_, stream->bufsize_)) <= 0) {
780 if (stream->cnt_ < 0) {
781 stream->flags_ |= JAS_STREAM_ERR;
783 stream->flags_ |= JAS_STREAM_EOF;
789 assert(stream->cnt_ > 0);
790 /* Get or peek at the first character in the buffer. */
791 c = (getflag) ? jas_stream_getc2(stream) : (*stream->ptr_);
796 int jas_stream_flushbuf(jas_stream_t *stream, int c)
801 /* The stream should not be in an error or EOF state. */
802 if ((stream->flags_ & (JAS_STREAM_ERRMASK)) != 0) {
806 /* The stream must be open for writing. */
807 if ((stream->openmode_ & (JAS_STREAM_WRITE | JAS_STREAM_APPEND)) == 0) {
811 /* The buffer should not currently be in use for reading. */
812 assert(!(stream->bufmode_ & JAS_STREAM_RDBUF));
814 /* Note: Do not use the quantity stream->cnt to determine the number
815 of characters in the buffer! Depending on how this function was
816 called, the stream->cnt value may be "off-by-one". */
817 len = stream->ptr_ - stream->bufstart_;
819 n = (*stream->ops_->write_)(stream->obj_, (char *)
820 stream->bufstart_, len);
822 stream->flags_ |= JAS_STREAM_ERR;
826 stream->cnt_ = stream->bufsize_;
827 stream->ptr_ = stream->bufstart_;
829 stream->bufmode_ |= JAS_STREAM_WRBUF;
832 assert(stream->cnt_ > 0);
833 return jas_stream_putc2(stream, c);
839 /******************************************************************************\
840 * Miscellaneous code.
841 \******************************************************************************/
843 static int jas_strtoopenmode(const char *s)
849 openmode |= JAS_STREAM_READ;
852 openmode |= JAS_STREAM_WRITE | JAS_STREAM_CREATE;
855 openmode |= JAS_STREAM_BINARY;
858 openmode |= JAS_STREAM_APPEND;
861 openmode |= JAS_STREAM_READ | JAS_STREAM_WRITE;
871 int jas_stream_copy(jas_stream_t *out, jas_stream_t *in, int n)
877 all = (n < 0) ? 1 : 0;
880 while (all || m > 0) {
881 if ((c = jas_stream_getc_macro(in)) == EOF) {
882 /* The next character of input could not be read. */
883 /* Return with an error if an I/O error occured
884 (not including EOF) or if an explicit copy count
886 return (!all || jas_stream_error(in)) ? (-1) : 0;
888 if (jas_stream_putc_macro(out, c) == EOF) {
896 long jas_stream_setrwcount(jas_stream_t *stream, long rwcnt)
900 old = stream->rwcnt_;
901 stream->rwcnt_ = rwcnt;
905 int jas_stream_display(jas_stream_t *stream, FILE *fp, int n)
907 unsigned char buf[16];
918 for (i = 0; i < n; i += 16) {
919 if (n > 16 && i > 0) {
920 display = (i >= cnt) ? 1 : 0;
923 fprintf(fp, "%08x:", i);
925 m = JAS_MIN(n - i, 16);
926 for (j = 0; j < m; ++j) {
927 if ((c = jas_stream_getc(stream)) == EOF) {
934 for (j = 0; j < m; ++j) {
935 fprintf(fp, " %02x", buf[j]);
938 for (; j < 16; ++j) {
941 for (j = 0; j < m; ++j) {
942 if (isprint(buf[j])) {
956 long jas_stream_length(jas_stream_t *stream)
960 if ((oldpos = jas_stream_tell(stream)) < 0) {
963 if (jas_stream_seek(stream, 0, SEEK_END) < 0) {
966 if ((pos = jas_stream_tell(stream)) < 0) {
969 if (jas_stream_seek(stream, oldpos, SEEK_SET) < 0) {
975 /******************************************************************************\
976 * Memory stream object.
977 \******************************************************************************/
979 static int mem_read(jas_stream_obj_t *obj, char *buf, int cnt)
982 jas_stream_memobj_t *m = (jas_stream_memobj_t *)obj;
983 n = m->len_ - m->pos_;
984 cnt = JAS_MIN(n, cnt);
985 memcpy(buf, &m->buf_[m->pos_], cnt);
990 static int mem_resize(jas_stream_memobj_t *m, int bufsize)
995 if (!(buf = jas_realloc(m->buf_, bufsize * sizeof(unsigned char)))) {
999 m->bufsize_ = bufsize;
1003 static int mem_write(jas_stream_obj_t *obj, char *buf, int cnt)
1007 jas_stream_memobj_t *m = (jas_stream_memobj_t *)obj;
1011 newpos = m->pos_ + cnt;
1012 if (newpos > m->bufsize_ && m->growable_) {
1013 newbufsize = m->bufsize_;
1014 while (newbufsize < newpos) {
1016 assert(newbufsize >= 0);
1018 if (mem_resize(m, newbufsize)) {
1022 if (m->pos_ > m->len_) {
1023 /* The current position is beyond the end of the file, so
1024 pad the file to the current position with zeros. */
1025 n = JAS_MIN(m->pos_, m->bufsize_) - m->len_;
1027 memset(&m->buf_[m->len_], 0, n);
1030 if (m->pos_ != m->len_) {
1031 /* The buffer is not big enough. */
1035 n = m->bufsize_ - m->pos_;
1036 ret = JAS_MIN(n, cnt);
1038 memcpy(&m->buf_[m->pos_], buf, ret);
1041 if (m->pos_ > m->len_) {
1048 static long mem_seek(jas_stream_obj_t *obj, long offset, int origin)
1050 jas_stream_memobj_t *m = (jas_stream_memobj_t *)obj;
1058 newpos = m->len_ - offset;
1061 newpos = m->pos_ + offset;
1075 static int mem_close(jas_stream_obj_t *obj)
1077 jas_stream_memobj_t *m = (jas_stream_memobj_t *)obj;
1078 if (m->myalloc_ && m->buf_) {
1086 /******************************************************************************\
1087 * File stream object.
1088 \******************************************************************************/
1090 static int file_read(jas_stream_obj_t *obj, char *buf, int cnt)
1092 jas_stream_fileobj_t *fileobj = JAS_CAST(jas_stream_fileobj_t *, obj);
1093 return read(fileobj->fd, buf, cnt);
1096 static int file_write(jas_stream_obj_t *obj, char *buf, int cnt)
1098 jas_stream_fileobj_t *fileobj = JAS_CAST(jas_stream_fileobj_t *, obj);
1099 return write(fileobj->fd, buf, cnt);
1102 static long file_seek(jas_stream_obj_t *obj, long offset, int origin)
1104 jas_stream_fileobj_t *fileobj = JAS_CAST(jas_stream_fileobj_t *, obj);
1105 return lseek(fileobj->fd, offset, origin);
1108 static int file_close(jas_stream_obj_t *obj)
1110 jas_stream_fileobj_t *fileobj = JAS_CAST(jas_stream_fileobj_t *, obj);
1112 ret = close(fileobj->fd);
1113 if (fileobj->flags & JAS_STREAM_FILEOBJ_DELONCLOSE) {
1114 unlink(fileobj->pathname);
1120 /******************************************************************************\
1121 * Stdio file stream object.
1122 \******************************************************************************/
1124 static int sfile_read(jas_stream_obj_t *obj, char *buf, int cnt)
1127 fp = JAS_CAST(FILE *, obj);
1128 return fread(buf, 1, cnt, fp);
1131 static int sfile_write(jas_stream_obj_t *obj, char *buf, int cnt)
1134 fp = JAS_CAST(FILE *, obj);
1135 return fwrite(buf, 1, cnt, fp);
1138 static long sfile_seek(jas_stream_obj_t *obj, long offset, int origin)
1141 fp = JAS_CAST(FILE *, obj);
1142 return fseek(fp, offset, origin);
1145 static int sfile_close(jas_stream_obj_t *obj)
1148 fp = JAS_CAST(FILE *, obj);