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