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