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