Merge commit '4b885e206' into merge-2.4
[profile/ivi/opencv.git] / 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_);
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     stream->obj_ = obj;
365
366 #ifdef _WIN32
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 #else
377     /* Choose a file name. */
378     snprintf(obj->pathname, L_tmpnam, "%s/tmp.XXXXXXXXXX", P_tmpdir);
379
380     /* Open the underlying file. */
381     if ((obj->fd = mkstemp(obj->pathname)) < 0) {
382         jas_stream_destroy(stream);
383         return 0;
384     }
385 #endif
386
387     /* Unlink the file so that it will disappear if the program
388     terminates abnormally. */
389     if (unlink(obj->pathname)) {
390         jas_stream_destroy(stream);
391         return 0;
392     }
393
394     /* Use full buffering. */
395     jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0);
396
397     stream->ops_ = &jas_stream_fileops;
398
399     return stream;
400 }
401
402 jas_stream_t *jas_stream_fdopen(int fd, const char *mode)
403 {
404     jas_stream_t *stream;
405     jas_stream_fileobj_t *obj;
406
407     /* Allocate a stream object. */
408     if (!(stream = jas_stream_create())) {
409         return 0;
410     }
411
412     /* Parse the mode string. */
413     stream->openmode_ = jas_strtoopenmode(mode);
414
415 #if defined(WIN32)
416     /* Argh!!!  Someone ought to banish text mode (i.e., O_TEXT) to the
417       greatest depths of purgatory! */
418     /* Ensure that the file descriptor is in binary mode, if the caller
419       has specified the binary mode flag.  Arguably, the caller ought to
420       take care of this, but text mode is a ugly wart anyways, so we save
421       the caller some grief by handling this within the stream library. */
422     /* This ugliness is mainly for the benefit of those who run the
423       JasPer software under Windows from shells that insist on opening
424       files in text mode.  For example, in the Cygwin environment,
425       shells often open files in text mode when I/O redirection is
426       used.  Grr... */
427     if (stream->openmode_ & JAS_STREAM_BINARY) {
428         setmode(fd, O_BINARY);
429     }
430 #endif
431
432     /* Allocate space for the underlying file stream object. */
433     if (!(obj = jas_malloc(sizeof(jas_stream_fileobj_t)))) {
434         jas_stream_destroy(stream);
435         return 0;
436     }
437     obj->fd = fd;
438     obj->flags = 0;
439     obj->pathname[0] = '\0';
440     stream->obj_ = (void *) obj;
441
442     /* Do not close the underlying file descriptor when the stream is
443     closed. */
444     obj->flags |= JAS_STREAM_FILEOBJ_NOCLOSE;
445
446     /* By default, use full buffering for this type of stream. */
447     jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0);
448
449     /* Select the operations for a file stream object. */
450     stream->ops_ = &jas_stream_fileops;
451
452     return stream;
453 }
454
455 static void jas_stream_destroy(jas_stream_t *stream)
456 {
457     /* If the memory for the buffer was allocated with malloc, free
458     this memory. */
459     if ((stream->bufmode_ & JAS_STREAM_FREEBUF) && stream->bufbase_) {
460         jas_free(stream->bufbase_);
461         stream->bufbase_ = 0;
462     }
463     jas_free(stream);
464 }
465
466 int jas_stream_close(jas_stream_t *stream)
467 {
468     /* Flush buffer if necessary. */
469     jas_stream_flush(stream);
470
471     /* Close the underlying stream object. */
472     (*stream->ops_->close_)(stream->obj_);
473
474     jas_stream_destroy(stream);
475
476     return 0;
477 }
478
479 /******************************************************************************\
480 * Code for reading and writing streams.
481 \******************************************************************************/
482
483 int jas_stream_getc_func(jas_stream_t *stream)
484 {
485     assert(stream->ptr_ - stream->bufbase_ <= stream->bufsize_ +
486       JAS_STREAM_MAXPUTBACK);
487     return jas_stream_getc_macro(stream);
488 }
489
490 int jas_stream_putc_func(jas_stream_t *stream, int c)
491 {
492     assert(stream->ptr_ - stream->bufstart_ <= stream->bufsize_);
493     return jas_stream_putc_macro(stream, c);
494 }
495
496 int jas_stream_ungetc(jas_stream_t *stream, int c)
497 {
498     if (!stream->ptr_ || stream->ptr_ == stream->bufbase_) {
499         return -1;
500     }
501
502     /* Reset the EOF indicator (since we now have at least one character
503       to read). */
504     stream->flags_ &= ~JAS_STREAM_EOF;
505
506     --stream->rwcnt_;
507     --stream->ptr_;
508     ++stream->cnt_;
509     *stream->ptr_ = c;
510     return 0;
511 }
512
513 int jas_stream_read(jas_stream_t *stream, void *buf, int cnt)
514 {
515     int n;
516     int c;
517     char *bufptr;
518
519     bufptr = buf;
520
521     n = 0;
522     while (n < cnt) {
523         if ((c = jas_stream_getc(stream)) == EOF) {
524             return n;
525         }
526         *bufptr++ = c;
527         ++n;
528     }
529
530     return n;
531 }
532
533 int jas_stream_write(jas_stream_t *stream, const void *buf, int cnt)
534 {
535     int n;
536     const char *bufptr;
537
538     bufptr = buf;
539
540     n = 0;
541     while (n < cnt) {
542         if (jas_stream_putc(stream, *bufptr) == EOF) {
543             return n;
544         }
545         ++bufptr;
546         ++n;
547     }
548
549     return n;
550 }
551
552 /* Note: This function uses a fixed size buffer.  Therefore, it cannot
553   handle invocations that will produce more output than can be held
554   by the buffer. */
555 int jas_stream_printf(jas_stream_t *stream, const char *fmt, ...)
556 {
557     va_list ap;
558     char buf[4096];
559     int ret;
560
561     va_start(ap, fmt);
562     ret = vsnprintf(buf, sizeof buf, fmt, ap);
563     jas_stream_puts(stream, buf);
564     va_end(ap);
565     return ret;
566 }
567
568 int jas_stream_puts(jas_stream_t *stream, const char *s)
569 {
570     while (*s != '\0') {
571         if (jas_stream_putc_macro(stream, *s) == EOF) {
572             return -1;
573         }
574         ++s;
575     }
576     return 0;
577 }
578
579 char *jas_stream_gets(jas_stream_t *stream, char *buf, int bufsize)
580 {
581     int c;
582     char *bufptr;
583     assert(bufsize > 0);
584
585     bufptr = buf;
586     while (bufsize > 1) {
587         if ((c = jas_stream_getc(stream)) == EOF) {
588             break;
589         }
590         *bufptr++ = c;
591         --bufsize;
592         if (c == '\n') {
593             break;
594         }
595     }
596     *bufptr = '\0';
597     return buf;
598 }
599
600 int jas_stream_gobble(jas_stream_t *stream, int n)
601 {
602     int m;
603     m = n;
604     for (m = n; m > 0; --m) {
605         if (jas_stream_getc(stream) == EOF) {
606             return n - m;
607         }
608     }
609     return n;
610 }
611
612 int jas_stream_pad(jas_stream_t *stream, int n, int c)
613 {
614     int m;
615     m = n;
616     for (m = n; m > 0; --m) {
617         if (jas_stream_putc(stream, c) == EOF)
618             return n - m;
619     }
620     return n;
621 }
622
623 /******************************************************************************\
624 * Code for getting and setting the stream position.
625 \******************************************************************************/
626
627 int jas_stream_isseekable(jas_stream_t *stream)
628 {
629     if (stream->ops_ == &jas_stream_memops) {
630         return 1;
631     } else if (stream->ops_ == &jas_stream_fileops) {
632         if ((*stream->ops_->seek_)(stream->obj_, 0, SEEK_CUR) < 0) {
633             return 0;
634         }
635         return 1;
636     } else {
637         return 0;
638     }
639 }
640
641 int jas_stream_rewind(jas_stream_t *stream)
642 {
643     return jas_stream_seek(stream, 0, SEEK_SET);
644 }
645
646 long jas_stream_seek(jas_stream_t *stream, long offset, int origin)
647 {
648     long newpos;
649
650     /* The buffer cannot be in use for both reading and writing. */
651     assert(!((stream->bufmode_ & JAS_STREAM_RDBUF) && (stream->bufmode_ &
652       JAS_STREAM_WRBUF)));
653
654     /* Reset the EOF indicator (since we may not be at the EOF anymore). */
655     stream->flags_ &= ~JAS_STREAM_EOF;
656
657     if (stream->bufmode_ & JAS_STREAM_RDBUF) {
658         if (origin == SEEK_CUR) {
659             offset -= stream->cnt_;
660         }
661     } else if (stream->bufmode_ & JAS_STREAM_WRBUF) {
662         if (jas_stream_flush(stream)) {
663             return -1;
664         }
665     }
666     stream->cnt_ = 0;
667     stream->ptr_ = stream->bufstart_;
668     stream->bufmode_ &= ~(JAS_STREAM_RDBUF | JAS_STREAM_WRBUF);
669
670     if ((newpos = (*stream->ops_->seek_)(stream->obj_, offset, origin))
671       < 0) {
672         return -1;
673     }
674
675     return newpos;
676 }
677
678 long jas_stream_tell(jas_stream_t *stream)
679 {
680     int adjust;
681     int offset;
682
683     if (stream->bufmode_ & JAS_STREAM_RDBUF) {
684         adjust = -stream->cnt_;
685     } else if (stream->bufmode_ & JAS_STREAM_WRBUF) {
686         adjust = stream->ptr_ - stream->bufstart_;
687     } else {
688         adjust = 0;
689     }
690
691     if ((offset = (*stream->ops_->seek_)(stream->obj_, 0, SEEK_CUR)) < 0) {
692         return -1;
693     }
694
695     return offset + adjust;
696 }
697
698 /******************************************************************************\
699 * Buffer initialization code.
700 \******************************************************************************/
701
702 static void jas_stream_initbuf(jas_stream_t *stream, int bufmode, char *buf,
703   int bufsize)
704 {
705     /* If this function is being called, the buffer should not have been
706       initialized yet. */
707     assert(!stream->bufbase_);
708
709     if (bufmode != JAS_STREAM_UNBUF) {
710         /* The full- or line-buffered mode is being employed. */
711         if (!buf) {
712             /* The caller has not specified a buffer to employ, so allocate
713               one. */
714             if ((stream->bufbase_ = jas_malloc(JAS_STREAM_BUFSIZE +
715               JAS_STREAM_MAXPUTBACK))) {
716                 stream->bufmode_ |= JAS_STREAM_FREEBUF;
717                 stream->bufsize_ = JAS_STREAM_BUFSIZE;
718             } else {
719                 /* The buffer allocation has failed.  Resort to unbuffered
720                   operation. */
721                 stream->bufbase_ = stream->tinybuf_;
722                 stream->bufsize_ = 1;
723             }
724         } else {
725             /* The caller has specified a buffer to employ. */
726             /* The buffer must be large enough to accommodate maximum
727               putback. */
728             assert(bufsize > JAS_STREAM_MAXPUTBACK);
729             stream->bufbase_ = JAS_CAST(uchar *, buf);
730             stream->bufsize_ = bufsize - JAS_STREAM_MAXPUTBACK;
731         }
732     } else {
733         /* The unbuffered mode is being employed. */
734         /* A buffer should not have been supplied by the caller. */
735         assert(!buf);
736         /* Use a trivial one-character buffer. */
737         stream->bufbase_ = stream->tinybuf_;
738         stream->bufsize_ = 1;
739     }
740     stream->bufstart_ = &stream->bufbase_[JAS_STREAM_MAXPUTBACK];
741     stream->ptr_ = stream->bufstart_;
742     stream->cnt_ = 0;
743     stream->bufmode_ |= bufmode & JAS_STREAM_BUFMODEMASK;
744 }
745
746 /******************************************************************************\
747 * Buffer filling and flushing code.
748 \******************************************************************************/
749
750 int jas_stream_flush(jas_stream_t *stream)
751 {
752     if (stream->bufmode_ & JAS_STREAM_RDBUF) {
753         return 0;
754     }
755     return jas_stream_flushbuf(stream, EOF);
756 }
757
758 int jas_stream_fillbuf(jas_stream_t *stream, int getflag)
759 {
760     int c;
761
762     /* The stream must not be in an error or EOF state. */
763     if ((stream->flags_ & (JAS_STREAM_ERRMASK)) != 0) {
764         return EOF;
765     }
766
767     /* The stream must be open for reading. */
768     if ((stream->openmode_ & JAS_STREAM_READ) == 0) {
769         return EOF;
770     }
771
772     /* Make a half-hearted attempt to confirm that the buffer is not
773     currently being used for writing.  This check is not intended
774     to be foolproof! */
775     assert((stream->bufmode_ & JAS_STREAM_WRBUF) == 0);
776
777     assert(stream->ptr_ - stream->bufstart_ <= stream->bufsize_);
778
779     /* Mark the buffer as being used for reading. */
780     stream->bufmode_ |= JAS_STREAM_RDBUF;
781
782     /* Read new data into the buffer. */
783     stream->ptr_ = stream->bufstart_;
784     if ((stream->cnt_ = (*stream->ops_->read_)(stream->obj_,
785       (char *) stream->bufstart_, stream->bufsize_)) <= 0) {
786         if (stream->cnt_ < 0) {
787             stream->flags_ |= JAS_STREAM_ERR;
788         } else {
789             stream->flags_ |= JAS_STREAM_EOF;
790         }
791         stream->cnt_ = 0;
792         return EOF;
793     }
794
795     assert(stream->cnt_ > 0);
796     /* Get or peek at the first character in the buffer. */
797     c = (getflag) ? jas_stream_getc2(stream) : (*stream->ptr_);
798
799     return c;
800 }
801
802 int jas_stream_flushbuf(jas_stream_t *stream, int c)
803 {
804     int len;
805     int n;
806
807     /* The stream should not be in an error or EOF state. */
808     if ((stream->flags_ & (JAS_STREAM_ERRMASK)) != 0) {
809         return EOF;
810     }
811
812     /* The stream must be open for writing. */
813     if ((stream->openmode_ & (JAS_STREAM_WRITE | JAS_STREAM_APPEND)) == 0) {
814         return EOF;
815     }
816
817     /* The buffer should not currently be in use for reading. */
818     assert(!(stream->bufmode_ & JAS_STREAM_RDBUF));
819
820     /* Note: Do not use the quantity stream->cnt to determine the number
821     of characters in the buffer!  Depending on how this function was
822     called, the stream->cnt value may be "off-by-one". */
823     len = stream->ptr_ - stream->bufstart_;
824     if (len > 0) {
825         n = (*stream->ops_->write_)(stream->obj_, (char *)
826           stream->bufstart_, len);
827         if (n != len) {
828             stream->flags_ |= JAS_STREAM_ERR;
829             return EOF;
830         }
831     }
832     stream->cnt_ = stream->bufsize_;
833     stream->ptr_ = stream->bufstart_;
834
835     stream->bufmode_ |= JAS_STREAM_WRBUF;
836
837     if (c != EOF) {
838         assert(stream->cnt_ > 0);
839         return jas_stream_putc2(stream, c);
840     }
841
842     return 0;
843 }
844
845 /******************************************************************************\
846 * Miscellaneous code.
847 \******************************************************************************/
848
849 static int jas_strtoopenmode(const char *s)
850 {
851     int openmode = 0;
852     while (*s != '\0') {
853         switch (*s) {
854         case 'r':
855             openmode |= JAS_STREAM_READ;
856             break;
857         case 'w':
858             openmode |= JAS_STREAM_WRITE | JAS_STREAM_CREATE;
859             break;
860         case 'b':
861             openmode |= JAS_STREAM_BINARY;
862             break;
863         case 'a':
864             openmode |= JAS_STREAM_APPEND;
865             break;
866         case '+':
867             openmode |= JAS_STREAM_READ | JAS_STREAM_WRITE;
868             break;
869         default:
870             break;
871         }
872         ++s;
873     }
874     return openmode;
875 }
876
877 int jas_stream_copy(jas_stream_t *out, jas_stream_t *in, int n)
878 {
879     int all;
880     int c;
881     int m;
882
883     all = (n < 0) ? 1 : 0;
884
885     m = n;
886     while (all || m > 0) {
887         if ((c = jas_stream_getc_macro(in)) == EOF) {
888             /* The next character of input could not be read. */
889             /* Return with an error if an I/O error occured
890               (not including EOF) or if an explicit copy count
891               was specified. */
892             return (!all || jas_stream_error(in)) ? (-1) : 0;
893         }
894         if (jas_stream_putc_macro(out, c) == EOF) {
895             return -1;
896         }
897         --m;
898     }
899     return 0;
900 }
901
902 long jas_stream_setrwcount(jas_stream_t *stream, long rwcnt)
903 {
904     int old;
905
906     old = stream->rwcnt_;
907     stream->rwcnt_ = rwcnt;
908     return old;
909 }
910
911 int jas_stream_display(jas_stream_t *stream, FILE *fp, int n)
912 {
913     unsigned char buf[16];
914     int i;
915     int j;
916     int m;
917     int c;
918     int display;
919     int cnt;
920
921     cnt = n - (n % 16);
922     display = 1;
923
924     for (i = 0; i < n; i += 16) {
925         if (n > 16 && i > 0) {
926             display = (i >= cnt) ? 1 : 0;
927         }
928         if (display) {
929             fprintf(fp, "%08x:", i);
930         }
931         m = JAS_MIN(n - i, 16);
932         for (j = 0; j < m; ++j) {
933             if ((c = jas_stream_getc(stream)) == EOF) {
934                 abort();
935                 return -1;
936             }
937             buf[j] = c;
938         }
939         if (display) {
940             for (j = 0; j < m; ++j) {
941                 fprintf(fp, " %02x", buf[j]);
942             }
943             fputc(' ', fp);
944             for (; j < 16; ++j) {
945                 fprintf(fp, "   ");
946             }
947             for (j = 0; j < m; ++j) {
948                 if (isprint(buf[j])) {
949                     fputc(buf[j], fp);
950                 } else {
951                     fputc(' ', fp);
952                 }
953             }
954             fprintf(fp, "\n");
955         }
956
957
958     }
959     return 0;
960 }
961
962 long jas_stream_length(jas_stream_t *stream)
963 {
964     long oldpos;
965     long pos;
966     if ((oldpos = jas_stream_tell(stream)) < 0) {
967         return -1;
968     }
969     if (jas_stream_seek(stream, 0, SEEK_END) < 0) {
970         return -1;
971     }
972     if ((pos = jas_stream_tell(stream)) < 0) {
973         return -1;
974     }
975     if (jas_stream_seek(stream, oldpos, SEEK_SET) < 0) {
976         return -1;
977     }
978     return pos;
979 }
980
981 /******************************************************************************\
982 * Memory stream object.
983 \******************************************************************************/
984
985 static int mem_read(jas_stream_obj_t *obj, char *buf, int cnt)
986 {
987     int n;
988     jas_stream_memobj_t *m = (jas_stream_memobj_t *)obj;
989     n = m->len_ - m->pos_;
990     cnt = JAS_MIN(n, cnt);
991     memcpy(buf, &m->buf_[m->pos_], cnt);
992     m->pos_ += cnt;
993     return cnt;
994 }
995
996 static int mem_resize(jas_stream_memobj_t *m, int bufsize)
997 {
998     unsigned char *buf;
999
1000     assert(m->buf_);
1001     if (!(buf = jas_realloc(m->buf_, bufsize))) {
1002         return -1;
1003     }
1004     m->buf_ = buf;
1005     m->bufsize_ = bufsize;
1006     return 0;
1007 }
1008
1009 static int mem_write(jas_stream_obj_t *obj, char *buf, int cnt)
1010 {
1011     int n;
1012     int ret;
1013     jas_stream_memobj_t *m = (jas_stream_memobj_t *)obj;
1014     long newbufsize;
1015     long newpos;
1016
1017     newpos = m->pos_ + cnt;
1018     if (newpos > m->bufsize_ && m->growable_) {
1019         newbufsize = m->bufsize_;
1020         while (newbufsize < newpos) {
1021             newbufsize <<= 1;
1022             assert(newbufsize >= 0);
1023         }
1024         if (mem_resize(m, newbufsize)) {
1025             return -1;
1026         }
1027     }
1028     if (m->pos_ > m->len_) {
1029         /* The current position is beyond the end of the file, so
1030           pad the file to the current position with zeros. */
1031         n = JAS_MIN(m->pos_, m->bufsize_) - m->len_;
1032         if (n > 0) {
1033             memset(&m->buf_[m->len_], 0, n);
1034             m->len_ += n;
1035         }
1036         if (m->pos_ != m->len_) {
1037             /* The buffer is not big enough. */
1038             return 0;
1039         }
1040     }
1041     n = m->bufsize_ - m->pos_;
1042     ret = JAS_MIN(n, cnt);
1043     if (ret > 0) {
1044         memcpy(&m->buf_[m->pos_], buf, ret);
1045         m->pos_ += ret;
1046     }
1047     if (m->pos_ > m->len_) {
1048         m->len_ = m->pos_;
1049     }
1050 assert(ret == cnt);
1051     return ret;
1052 }
1053
1054 static long mem_seek(jas_stream_obj_t *obj, long offset, int origin)
1055 {
1056     jas_stream_memobj_t *m = (jas_stream_memobj_t *)obj;
1057     long newpos;
1058
1059     switch (origin) {
1060     case SEEK_SET:
1061         newpos = offset;
1062         break;
1063     case SEEK_END:
1064         newpos = m->len_ - offset;
1065         break;
1066     case SEEK_CUR:
1067         newpos = m->pos_ + offset;
1068         break;
1069     default:
1070         abort();
1071         break;
1072     }
1073     if (newpos < 0) {
1074         return -1;
1075     }
1076     m->pos_ = newpos;
1077
1078     return m->pos_;
1079 }
1080
1081 static int mem_close(jas_stream_obj_t *obj)
1082 {
1083     jas_stream_memobj_t *m = (jas_stream_memobj_t *)obj;
1084     if (m->myalloc_ && m->buf_) {
1085         jas_free(m->buf_);
1086         m->buf_ = 0;
1087     }
1088     jas_free(obj);
1089     return 0;
1090 }
1091
1092 /******************************************************************************\
1093 * File stream object.
1094 \******************************************************************************/
1095
1096 static int file_read(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 read(fileobj->fd, buf, cnt);
1100 }
1101
1102 static int file_write(jas_stream_obj_t *obj, char *buf, int cnt)
1103 {
1104     jas_stream_fileobj_t *fileobj = JAS_CAST(jas_stream_fileobj_t *, obj);
1105     return write(fileobj->fd, buf, cnt);
1106 }
1107
1108 static long file_seek(jas_stream_obj_t *obj, long offset, int origin)
1109 {
1110     jas_stream_fileobj_t *fileobj = JAS_CAST(jas_stream_fileobj_t *, obj);
1111     return lseek(fileobj->fd, offset, origin);
1112 }
1113
1114 static int file_close(jas_stream_obj_t *obj)
1115 {
1116     jas_stream_fileobj_t *fileobj = JAS_CAST(jas_stream_fileobj_t *, obj);
1117     int ret;
1118     ret = close(fileobj->fd);
1119     if (fileobj->flags & JAS_STREAM_FILEOBJ_DELONCLOSE) {
1120         unlink(fileobj->pathname);
1121     }
1122     jas_free(fileobj);
1123     return ret;
1124 }
1125
1126 /******************************************************************************\
1127 * Stdio file stream object.
1128 \******************************************************************************/
1129
1130 static int sfile_read(jas_stream_obj_t *obj, char *buf, int cnt)
1131 {
1132     FILE *fp;
1133     fp = JAS_CAST(FILE *, obj);
1134     return fread(buf, 1, cnt, fp);
1135 }
1136
1137 static int sfile_write(jas_stream_obj_t *obj, char *buf, int cnt)
1138 {
1139     FILE *fp;
1140     fp = JAS_CAST(FILE *, obj);
1141     return fwrite(buf, 1, cnt, fp);
1142 }
1143
1144 static long sfile_seek(jas_stream_obj_t *obj, long offset, int origin)
1145 {
1146     FILE *fp;
1147     fp = JAS_CAST(FILE *, obj);
1148     return fseek(fp, offset, origin);
1149 }
1150
1151 static int sfile_close(jas_stream_obj_t *obj)
1152 {
1153     FILE *fp;
1154     fp = JAS_CAST(FILE *, obj);
1155     return fclose(fp);
1156 }