jas_stream.c - vx32 - Local 9vx git repository for patches.
(HTM) git clone git://r-36.net/vx32
(DIR) Log
(DIR) Files
(DIR) Refs
---
jas_stream.c (30310B)
---
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) 1999-2000 Image Power, Inc.
13 * Copyright (c) 1999-2000 The University of British Columbia
14 * Copyright (c) 2001-2003 Michael David Adams
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 1969 2005-12-19 23:31:53Z baford $
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
172 jas_stream_t *jas_stream_memopen(char *buf, int bufsize)
173 {
174 jas_stream_t *stream;
175 jas_stream_memobj_t *obj;
176
177 if (!(stream = jas_stream_create())) {
178 return 0;
179 }
180
181 /* A stream associated with a memory buffer is always opened
182 for both reading and writing in binary mode. */
183 stream->openmode_ = JAS_STREAM_READ | JAS_STREAM_WRITE | JAS_STREAM_BINARY;
184
185 /* Since the stream data is already resident in memory, buffering
186 is not necessary. */
187 /* But... It still may be faster to use buffering anyways. */
188 jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0);
189
190 /* Select the operations for a memory stream. */
191 stream->ops_ = &jas_stream_memops;
192
193 /* Allocate memory for the underlying memory stream object. */
194 if (!(obj = jas_malloc(sizeof(jas_stream_memobj_t)))) {
195 jas_stream_destroy(stream);
196 return 0;
197 }
198 stream->obj_ = (void *) obj;
199
200 /* Initialize a few important members of the memory stream object. */
201 obj->myalloc_ = 0;
202 obj->buf_ = 0;
203
204 /* If the buffer size specified is nonpositive, then the buffer
205 is allocated internally and automatically grown as needed. */
206 if (bufsize <= 0) {
207 obj->bufsize_ = 1024;
208 obj->growable_ = 1;
209 } else {
210 obj->bufsize_ = bufsize;
211 obj->growable_ = 0;
212 }
213 if (buf) {
214 obj->buf_ = (unsigned char *) buf;
215 } else {
216 obj->buf_ = jas_malloc(obj->bufsize_ * sizeof(char));
217 obj->myalloc_ = 1;
218 }
219 if (!obj->buf_) {
220 jas_stream_close(stream);
221 return 0;
222 }
223
224 if (bufsize > 0 && buf) {
225 /* If a buffer was supplied by the caller and its length is positive,
226 make the associated buffer data appear in the stream initially. */
227 obj->len_ = bufsize;
228 } else {
229 /* The stream is initially empty. */
230 obj->len_ = 0;
231 }
232 obj->pos_ = 0;
233
234 return stream;
235 }
236
237 jas_stream_t *jas_stream_fopen(const char *filename, const char *mode)
238 {
239 jas_stream_t *stream;
240 jas_stream_fileobj_t *obj;
241 int openflags;
242
243 /* Allocate a stream object. */
244 if (!(stream = jas_stream_create())) {
245 return 0;
246 }
247
248 /* Parse the mode string. */
249 stream->openmode_ = jas_strtoopenmode(mode);
250
251 /* Determine the correct flags to use for opening the file. */
252 if ((stream->openmode_ & JAS_STREAM_READ) &&
253 (stream->openmode_ & JAS_STREAM_WRITE)) {
254 openflags = O_RDWR;
255 } else if (stream->openmode_ & JAS_STREAM_READ) {
256 openflags = O_RDONLY;
257 } else if (stream->openmode_ & JAS_STREAM_WRITE) {
258 openflags = O_WRONLY;
259 } else {
260 openflags = 0;
261 }
262 if (stream->openmode_ & JAS_STREAM_APPEND) {
263 openflags |= O_APPEND;
264 }
265 if (stream->openmode_ & JAS_STREAM_BINARY) {
266 openflags |= O_BINARY;
267 }
268 if (stream->openmode_ & JAS_STREAM_CREATE) {
269 openflags |= O_CREAT | O_TRUNC;
270 }
271
272 /* Allocate space for the underlying file stream object. */
273 if (!(obj = jas_malloc(sizeof(jas_stream_fileobj_t)))) {
274 jas_stream_destroy(stream);
275 return 0;
276 }
277 obj->fd = -1;
278 obj->flags = 0;
279 obj->pathname[0] = '\0';
280 stream->obj_ = (void *) obj;
281
282 /* Select the operations for a file stream object. */
283 stream->ops_ = &jas_stream_fileops;
284
285 /* Open the underlying file. */
286 if ((obj->fd = open(filename, openflags, JAS_STREAM_PERMS)) < 0) {
287 jas_stream_destroy(stream);
288 return 0;
289 }
290
291 /* By default, use full buffering for this type of stream. */
292 jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0);
293
294 return stream;
295 }
296
297 jas_stream_t *jas_stream_freopen(const char *path, const char *mode, FILE *fp)
298 {
299 jas_stream_t *stream;
300 int openflags;
301
302 /* Eliminate compiler warning about unused variable. */
303 path = 0;
304
305 /* Allocate a stream object. */
306 if (!(stream = jas_stream_create())) {
307 return 0;
308 }
309
310 /* Parse the mode string. */
311 stream->openmode_ = jas_strtoopenmode(mode);
312
313 /* Determine the correct flags to use for opening the file. */
314 if ((stream->openmode_ & JAS_STREAM_READ) &&
315 (stream->openmode_ & JAS_STREAM_WRITE)) {
316 openflags = O_RDWR;
317 } else if (stream->openmode_ & JAS_STREAM_READ) {
318 openflags = O_RDONLY;
319 } else if (stream->openmode_ & JAS_STREAM_WRITE) {
320 openflags = O_WRONLY;
321 } else {
322 openflags = 0;
323 }
324 if (stream->openmode_ & JAS_STREAM_APPEND) {
325 openflags |= O_APPEND;
326 }
327 if (stream->openmode_ & JAS_STREAM_BINARY) {
328 openflags |= O_BINARY;
329 }
330 if (stream->openmode_ & JAS_STREAM_CREATE) {
331 openflags |= O_CREAT | O_TRUNC;
332 }
333
334 stream->obj_ = JAS_CAST(void *, fp);
335
336 /* Select the operations for a file stream object. */
337 stream->ops_ = &jas_stream_sfileops;
338
339 /* By default, use full buffering for this type of stream. */
340 jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0);
341
342 return stream;
343 }
344
345 jas_stream_t *jas_stream_tmpfile()
346 {
347 jas_stream_t *stream;
348 jas_stream_fileobj_t *obj;
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 obj->pathname[0] = '\0';
366 stream->obj_ = obj;
367
368 /* Choose a file name. */
369 if(tmpnam(obj->pathname)){}
370
371 /* Open the underlying file. */
372 if ((obj->fd = open(obj->pathname, O_CREAT | O_EXCL | O_RDWR | O_TRUNC | O_BINARY,
373 JAS_STREAM_PERMS)) < 0) {
374 jas_stream_destroy(stream);
375 return 0;
376 }
377
378 /* Unlink the file so that it will disappear if the program
379 terminates abnormally. */
380 /* Under UNIX, one can unlink an open file and continue to do I/O
381 on it. Not all operating systems support this functionality, however.
382 For example, under Microsoft Windows the unlink operation will fail,
383 since the file is open. */
384 if (unlink(obj->pathname)) {
385 /* We will try unlinking the file again after it is closed. */
386 obj->flags |= JAS_STREAM_FILEOBJ_DELONCLOSE;
387 }
388
389 /* Use full buffering. */
390 jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0);
391
392 stream->ops_ = &jas_stream_fileops;
393
394 return stream;
395 }
396
397 jas_stream_t *jas_stream_fdopen(int fd, const char *mode)
398 {
399 jas_stream_t *stream;
400 jas_stream_fileobj_t *obj;
401
402 /* Allocate a stream object. */
403 if (!(stream = jas_stream_create())) {
404 return 0;
405 }
406
407 /* Parse the mode string. */
408 stream->openmode_ = jas_strtoopenmode(mode);
409
410 #if defined(WIN32)
411 /* Argh!!! Someone ought to banish text mode (i.e., O_TEXT) to the
412 greatest depths of purgatory! */
413 /* Ensure that the file descriptor is in binary mode, if the caller
414 has specified the binary mode flag. Arguably, the caller ought to
415 take care of this, but text mode is a ugly wart anyways, so we save
416 the caller some grief by handling this within the stream library. */
417 /* This ugliness is mainly for the benefit of those who run the
418 JasPer software under Windows from shells that insist on opening
419 files in text mode. For example, in the Cygwin environment,
420 shells often open files in text mode when I/O redirection is
421 used. Grr... */
422 if (stream->openmode_ & JAS_STREAM_BINARY) {
423 setmode(fd, O_BINARY);
424 }
425 #endif
426
427 /* Allocate space for the underlying file stream object. */
428 if (!(obj = jas_malloc(sizeof(jas_stream_fileobj_t)))) {
429 jas_stream_destroy(stream);
430 return 0;
431 }
432 obj->fd = fd;
433 obj->flags = 0;
434 obj->pathname[0] = '\0';
435 stream->obj_ = (void *) obj;
436
437 /* Do not close the underlying file descriptor when the stream is
438 closed. */
439 obj->flags |= JAS_STREAM_FILEOBJ_NOCLOSE;
440
441 /* By default, use full buffering for this type of stream. */
442 jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0);
443
444 /* Select the operations for a file stream object. */
445 stream->ops_ = &jas_stream_fileops;
446
447 return stream;
448 }
449
450 static void jas_stream_destroy(jas_stream_t *stream)
451 {
452 /* If the memory for the buffer was allocated with malloc, free
453 this memory. */
454 if ((stream->bufmode_ & JAS_STREAM_FREEBUF) && stream->bufbase_) {
455 jas_free(stream->bufbase_);
456 stream->bufbase_ = 0;
457 }
458 jas_free(stream);
459 }
460
461 int jas_stream_close(jas_stream_t *stream)
462 {
463 /* Flush buffer if necessary. */
464 jas_stream_flush(stream);
465
466 /* Close the underlying stream object. */
467 (*stream->ops_->close_)(stream->obj_);
468
469 jas_stream_destroy(stream);
470
471 return 0;
472 }
473
474 /******************************************************************************\
475 * Code for reading and writing streams.
476 \******************************************************************************/
477
478 int jas_stream_getc_func(jas_stream_t *stream)
479 {
480 assert(stream->ptr_ - stream->bufbase_ <= stream->bufsize_ +
481 JAS_STREAM_MAXPUTBACK);
482 return jas_stream_getc_macro(stream);
483 }
484
485 int jas_stream_putc_func(jas_stream_t *stream, int c)
486 {
487 assert(stream->ptr_ - stream->bufstart_ <= stream->bufsize_);
488 return jas_stream_putc_macro(stream, c);
489 }
490
491 int jas_stream_ungetc(jas_stream_t *stream, int c)
492 {
493 if (!stream->ptr_ || stream->ptr_ == stream->bufbase_) {
494 return -1;
495 }
496
497 /* Reset the EOF indicator (since we now have at least one character
498 to read). */
499 stream->flags_ &= ~JAS_STREAM_EOF;
500
501 --stream->rwcnt_;
502 --stream->ptr_;
503 ++stream->cnt_;
504 *stream->ptr_ = c;
505 return 0;
506 }
507
508 int jas_stream_read(jas_stream_t *stream, void *buf, int cnt)
509 {
510 int n;
511 int c;
512 char *bufptr;
513
514 bufptr = buf;
515
516 n = 0;
517 while (n < cnt) {
518 if ((c = jas_stream_getc(stream)) == EOF) {
519 return n;
520 }
521 *bufptr++ = c;
522 ++n;
523 }
524
525 return n;
526 }
527
528 int jas_stream_write(jas_stream_t *stream, const void *buf, int cnt)
529 {
530 int n;
531 const char *bufptr;
532
533 bufptr = buf;
534
535 n = 0;
536 while (n < cnt) {
537 if (jas_stream_putc(stream, *bufptr) == EOF) {
538 return n;
539 }
540 ++bufptr;
541 ++n;
542 }
543
544 return n;
545 }
546
547 /* Note: This function uses a fixed size buffer. Therefore, it cannot
548 handle invocations that will produce more output than can be held
549 by the buffer. */
550 int jas_stream_printf(jas_stream_t *stream, const char *fmt, ...)
551 {
552 va_list ap;
553 char buf[4096];
554 int ret;
555
556 va_start(ap, fmt);
557 ret = vsprintf(buf, fmt, ap);
558 jas_stream_puts(stream, buf);
559 va_end(ap);
560 return ret;
561 }
562
563 int jas_stream_puts(jas_stream_t *stream, const char *s)
564 {
565 while (*s != '\0') {
566 if (jas_stream_putc_macro(stream, *s) == EOF) {
567 return -1;
568 }
569 ++s;
570 }
571 return 0;
572 }
573
574 char *jas_stream_gets(jas_stream_t *stream, char *buf, int bufsize)
575 {
576 int c;
577 char *bufptr;
578 assert(bufsize > 0);
579
580 bufptr = buf;
581 while (bufsize > 1) {
582 if ((c = jas_stream_getc(stream)) == EOF) {
583 break;
584 }
585 *bufptr++ = c;
586 --bufsize;
587 if (c == '\n') {
588 break;
589 }
590 }
591 *bufptr = '\0';
592 return buf;
593 }
594
595 int jas_stream_gobble(jas_stream_t *stream, int n)
596 {
597 int m;
598 m = n;
599 for (m = n; m > 0; --m) {
600 if (jas_stream_getc(stream) == EOF) {
601 return n - m;
602 }
603 }
604 return n;
605 }
606
607 int jas_stream_pad(jas_stream_t *stream, int n, int c)
608 {
609 int m;
610 m = n;
611 for (m = n; m > 0; --m) {
612 if (jas_stream_putc(stream, c) == EOF)
613 return n - m;
614 }
615 return n;
616 }
617
618 /******************************************************************************\
619 * Code for getting and setting the stream position.
620 \******************************************************************************/
621
622 int jas_stream_isseekable(jas_stream_t *stream)
623 {
624 if (stream->ops_ == &jas_stream_memops) {
625 return 1;
626 } else if (stream->ops_ == &jas_stream_fileops) {
627 if ((*stream->ops_->seek_)(stream->obj_, 0, SEEK_CUR) < 0) {
628 return 0;
629 }
630 return 1;
631 } else {
632 return 0;
633 }
634 }
635
636 int jas_stream_rewind(jas_stream_t *stream)
637 {
638 return jas_stream_seek(stream, 0, SEEK_SET);
639 }
640
641 long jas_stream_seek(jas_stream_t *stream, long offset, int origin)
642 {
643 long newpos;
644
645 /* The buffer cannot be in use for both reading and writing. */
646 assert(!((stream->bufmode_ & JAS_STREAM_RDBUF) && (stream->bufmode_ &
647 JAS_STREAM_WRBUF)));
648
649 /* Reset the EOF indicator (since we may not be at the EOF anymore). */
650 stream->flags_ &= ~JAS_STREAM_EOF;
651
652 if (stream->bufmode_ & JAS_STREAM_RDBUF) {
653 if (origin == SEEK_CUR) {
654 offset -= stream->cnt_;
655 }
656 } else if (stream->bufmode_ & JAS_STREAM_WRBUF) {
657 if (jas_stream_flush(stream)) {
658 return -1;
659 }
660 }
661 stream->cnt_ = 0;
662 stream->ptr_ = stream->bufstart_;
663 stream->bufmode_ &= ~(JAS_STREAM_RDBUF | JAS_STREAM_WRBUF);
664
665 if ((newpos = (*stream->ops_->seek_)(stream->obj_, offset, origin))
666 < 0) {
667 return -1;
668 }
669
670 return newpos;
671 }
672
673 long jas_stream_tell(jas_stream_t *stream)
674 {
675 int adjust;
676 int offset;
677
678 if (stream->bufmode_ & JAS_STREAM_RDBUF) {
679 adjust = -stream->cnt_;
680 } else if (stream->bufmode_ & JAS_STREAM_WRBUF) {
681 adjust = stream->ptr_ - stream->bufstart_;
682 } else {
683 adjust = 0;
684 }
685
686 if ((offset = (*stream->ops_->seek_)(stream->obj_, 0, SEEK_CUR)) < 0) {
687 return -1;
688 }
689
690 return offset + adjust;
691 }
692
693 /******************************************************************************\
694 * Buffer initialization code.
695 \******************************************************************************/
696
697 static void jas_stream_initbuf(jas_stream_t *stream, int bufmode, char *buf,
698 int bufsize)
699 {
700 /* If this function is being called, the buffer should not have been
701 initialized yet. */
702 assert(!stream->bufbase_);
703
704 if (bufmode != JAS_STREAM_UNBUF) {
705 /* The full- or line-buffered mode is being employed. */
706 if (!buf) {
707 /* The caller has not specified a buffer to employ, so allocate
708 one. */
709 if ((stream->bufbase_ = jas_malloc(JAS_STREAM_BUFSIZE +
710 JAS_STREAM_MAXPUTBACK))) {
711 stream->bufmode_ |= JAS_STREAM_FREEBUF;
712 stream->bufsize_ = JAS_STREAM_BUFSIZE;
713 } else {
714 /* The buffer allocation has failed. Resort to unbuffered
715 operation. */
716 stream->bufbase_ = stream->tinybuf_;
717 stream->bufsize_ = 1;
718 }
719 } else {
720 /* The caller has specified a buffer to employ. */
721 /* The buffer must be large enough to accommodate maximum
722 putback. */
723 assert(bufsize > JAS_STREAM_MAXPUTBACK);
724 stream->bufbase_ = JAS_CAST(uchar *, buf);
725 stream->bufsize_ = bufsize - JAS_STREAM_MAXPUTBACK;
726 }
727 } else {
728 /* The unbuffered mode is being employed. */
729 /* A buffer should not have been supplied by the caller. */
730 assert(!buf);
731 /* Use a trivial one-character buffer. */
732 stream->bufbase_ = stream->tinybuf_;
733 stream->bufsize_ = 1;
734 }
735 stream->bufstart_ = &stream->bufbase_[JAS_STREAM_MAXPUTBACK];
736 stream->ptr_ = stream->bufstart_;
737 stream->cnt_ = 0;
738 stream->bufmode_ |= bufmode & JAS_STREAM_BUFMODEMASK;
739 }
740
741 /******************************************************************************\
742 * Buffer filling and flushing code.
743 \******************************************************************************/
744
745 int jas_stream_flush(jas_stream_t *stream)
746 {
747 if (stream->bufmode_ & JAS_STREAM_RDBUF) {
748 return 0;
749 }
750 return jas_stream_flushbuf(stream, EOF);
751 }
752
753 int jas_stream_fillbuf(jas_stream_t *stream, int getflag)
754 {
755 int c;
756
757 /* The stream must not be in an error or EOF state. */
758 if ((stream->flags_ & (JAS_STREAM_ERRMASK)) != 0) {
759 return EOF;
760 }
761
762 /* The stream must be open for reading. */
763 if ((stream->openmode_ & JAS_STREAM_READ) == 0) {
764 return EOF;
765 }
766
767 /* Make a half-hearted attempt to confirm that the buffer is not
768 currently being used for writing. This check is not intended
769 to be foolproof! */
770 assert((stream->bufmode_ & JAS_STREAM_WRBUF) == 0);
771
772 assert(stream->ptr_ - stream->bufstart_ <= stream->bufsize_);
773
774 /* Mark the buffer as being used for reading. */
775 stream->bufmode_ |= JAS_STREAM_RDBUF;
776
777 /* Read new data into the buffer. */
778 stream->ptr_ = stream->bufstart_;
779 if ((stream->cnt_ = (*stream->ops_->read_)(stream->obj_,
780 (char *) stream->bufstart_, stream->bufsize_)) <= 0) {
781 if (stream->cnt_ < 0) {
782 stream->flags_ |= JAS_STREAM_ERR;
783 } else {
784 stream->flags_ |= JAS_STREAM_EOF;
785 }
786 stream->cnt_ = 0;
787 return EOF;
788 }
789
790 assert(stream->cnt_ > 0);
791 /* Get or peek at the first character in the buffer. */
792 c = (getflag) ? jas_stream_getc2(stream) : (*stream->ptr_);
793
794 return c;
795 }
796
797 int jas_stream_flushbuf(jas_stream_t *stream, int c)
798 {
799 int len;
800 int n;
801
802 /* The stream should not be in an error or EOF state. */
803 if ((stream->flags_ & (JAS_STREAM_ERRMASK)) != 0) {
804 return EOF;
805 }
806
807 /* The stream must be open for writing. */
808 if ((stream->openmode_ & (JAS_STREAM_WRITE | JAS_STREAM_APPEND)) == 0) {
809 return EOF;
810 }
811
812 /* The buffer should not currently be in use for reading. */
813 assert(!(stream->bufmode_ & JAS_STREAM_RDBUF));
814
815 /* Note: Do not use the quantity stream->cnt to determine the number
816 of characters in the buffer! Depending on how this function was
817 called, the stream->cnt value may be "off-by-one". */
818 len = stream->ptr_ - stream->bufstart_;
819 if (len > 0) {
820 n = (*stream->ops_->write_)(stream->obj_, (char *)
821 stream->bufstart_, len);
822 if (n != len) {
823 stream->flags_ |= JAS_STREAM_ERR;
824 return EOF;
825 }
826 }
827 stream->cnt_ = stream->bufsize_;
828 stream->ptr_ = stream->bufstart_;
829
830 stream->bufmode_ |= JAS_STREAM_WRBUF;
831
832 if (c != EOF) {
833 assert(stream->cnt_ > 0);
834 return jas_stream_putc2(stream, c);
835 }
836
837 return 0;
838 }
839
840 /******************************************************************************\
841 * Miscellaneous code.
842 \******************************************************************************/
843
844 static int jas_strtoopenmode(const char *s)
845 {
846 int openmode = 0;
847 while (*s != '\0') {
848 switch (*s) {
849 case 'r':
850 openmode |= JAS_STREAM_READ;
851 break;
852 case 'w':
853 openmode |= JAS_STREAM_WRITE | JAS_STREAM_CREATE;
854 break;
855 case 'b':
856 openmode |= JAS_STREAM_BINARY;
857 break;
858 case 'a':
859 openmode |= JAS_STREAM_APPEND;
860 break;
861 case '+':
862 openmode |= JAS_STREAM_READ | JAS_STREAM_WRITE;
863 break;
864 default:
865 break;
866 }
867 ++s;
868 }
869 return openmode;
870 }
871
872 int jas_stream_copy(jas_stream_t *out, jas_stream_t *in, int n)
873 {
874 int all;
875 int c;
876 int m;
877
878 all = (n < 0) ? 1 : 0;
879
880 m = n;
881 while (all || m > 0) {
882 if ((c = jas_stream_getc_macro(in)) == EOF) {
883 /* The next character of input could not be read. */
884 /* Return with an error if an I/O error occured
885 (not including EOF) or if an explicit copy count
886 was specified. */
887 return (!all || jas_stream_error(in)) ? (-1) : 0;
888 }
889 if (jas_stream_putc_macro(out, c) == EOF) {
890 return -1;
891 }
892 --m;
893 }
894 return 0;
895 }
896
897 long jas_stream_setrwcount(jas_stream_t *stream, long rwcnt)
898 {
899 int old;
900
901 old = stream->rwcnt_;
902 stream->rwcnt_ = rwcnt;
903 return old;
904 }
905
906 int jas_stream_display(jas_stream_t *stream, FILE *fp, int n)
907 {
908 unsigned char buf[16];
909 int i;
910 int j;
911 int m;
912 int c;
913 int display;
914 int cnt;
915
916 cnt = n - (n % 16);
917 display = 1;
918
919 for (i = 0; i < n; i += 16) {
920 if (n > 16 && i > 0) {
921 display = (i >= cnt) ? 1 : 0;
922 }
923 if (display) {
924 fprintf(fp, "%08x:", i);
925 }
926 m = JAS_MIN(n - i, 16);
927 for (j = 0; j < m; ++j) {
928 if ((c = jas_stream_getc(stream)) == EOF) {
929 abort();
930 return -1;
931 }
932 buf[j] = c;
933 }
934 if (display) {
935 for (j = 0; j < m; ++j) {
936 fprintf(fp, " %02x", buf[j]);
937 }
938 fputc(' ', fp);
939 for (; j < 16; ++j) {
940 fprintf(fp, " ");
941 }
942 for (j = 0; j < m; ++j) {
943 if (isprint(buf[j])) {
944 fputc(buf[j], fp);
945 } else {
946 fputc(' ', fp);
947 }
948 }
949 fprintf(fp, "\n");
950 }
951
952
953 }
954 return 0;
955 }
956
957 long jas_stream_length(jas_stream_t *stream)
958 {
959 long oldpos;
960 long pos;
961 if ((oldpos = jas_stream_tell(stream)) < 0) {
962 return -1;
963 }
964 if (jas_stream_seek(stream, 0, SEEK_END) < 0) {
965 return -1;
966 }
967 if ((pos = jas_stream_tell(stream)) < 0) {
968 return -1;
969 }
970 if (jas_stream_seek(stream, oldpos, SEEK_SET) < 0) {
971 return -1;
972 }
973 return pos;
974 }
975
976 /******************************************************************************\
977 * Memory stream object.
978 \******************************************************************************/
979
980 static int mem_read(jas_stream_obj_t *obj, char *buf, int cnt)
981 {
982 int n;
983 jas_stream_memobj_t *m = (jas_stream_memobj_t *)obj;
984 n = m->len_ - m->pos_;
985 cnt = JAS_MIN(n, cnt);
986 memcpy(buf, &m->buf_[m->pos_], cnt);
987 m->pos_ += cnt;
988 return cnt;
989 }
990
991 static int mem_resize(jas_stream_memobj_t *m, int bufsize)
992 {
993 unsigned char *buf;
994
995 assert(m->buf_);
996 if (!(buf = jas_realloc(m->buf_, bufsize * sizeof(unsigned char)))) {
997 return -1;
998 }
999 m->buf_ = buf;
1000 m->bufsize_ = bufsize;
1001 return 0;
1002 }
1003
1004 static int mem_write(jas_stream_obj_t *obj, char *buf, int cnt)
1005 {
1006 int n;
1007 int ret;
1008 jas_stream_memobj_t *m = (jas_stream_memobj_t *)obj;
1009 long newbufsize;
1010 long newpos;
1011
1012 newpos = m->pos_ + cnt;
1013 if (newpos > m->bufsize_ && m->growable_) {
1014 newbufsize = m->bufsize_;
1015 while (newbufsize < newpos) {
1016 newbufsize <<= 1;
1017 assert(newbufsize >= 0);
1018 }
1019 if (mem_resize(m, newbufsize)) {
1020 return -1;
1021 }
1022 }
1023 if (m->pos_ > m->len_) {
1024 /* The current position is beyond the end of the file, so
1025 pad the file to the current position with zeros. */
1026 n = JAS_MIN(m->pos_, m->bufsize_) - m->len_;
1027 if (n > 0) {
1028 memset(&m->buf_[m->len_], 0, n);
1029 m->len_ += n;
1030 }
1031 if (m->pos_ != m->len_) {
1032 /* The buffer is not big enough. */
1033 return 0;
1034 }
1035 }
1036 n = m->bufsize_ - m->pos_;
1037 ret = JAS_MIN(n, cnt);
1038 if (ret > 0) {
1039 memcpy(&m->buf_[m->pos_], buf, ret);
1040 m->pos_ += ret;
1041 }
1042 if (m->pos_ > m->len_) {
1043 m->len_ = m->pos_;
1044 }
1045 assert(ret == cnt);
1046 return ret;
1047 }
1048
1049 static long mem_seek(jas_stream_obj_t *obj, long offset, int origin)
1050 {
1051 jas_stream_memobj_t *m = (jas_stream_memobj_t *)obj;
1052 long newpos;
1053
1054 switch (origin) {
1055 case SEEK_SET:
1056 newpos = offset;
1057 break;
1058 case SEEK_END:
1059 newpos = m->len_ - offset;
1060 break;
1061 case SEEK_CUR:
1062 newpos = m->pos_ + offset;
1063 break;
1064 default:
1065 abort();
1066 break;
1067 }
1068 if (newpos < 0) {
1069 return -1;
1070 }
1071 m->pos_ = newpos;
1072
1073 return m->pos_;
1074 }
1075
1076 static int mem_close(jas_stream_obj_t *obj)
1077 {
1078 jas_stream_memobj_t *m = (jas_stream_memobj_t *)obj;
1079 if (m->myalloc_ && m->buf_) {
1080 jas_free(m->buf_);
1081 m->buf_ = 0;
1082 }
1083 jas_free(obj);
1084 return 0;
1085 }
1086
1087 /******************************************************************************\
1088 * File stream object.
1089 \******************************************************************************/
1090
1091 static int file_read(jas_stream_obj_t *obj, char *buf, int cnt)
1092 {
1093 jas_stream_fileobj_t *fileobj = JAS_CAST(jas_stream_fileobj_t *, obj);
1094 return read(fileobj->fd, buf, cnt);
1095 }
1096
1097 static int file_write(jas_stream_obj_t *obj, char *buf, int cnt)
1098 {
1099 jas_stream_fileobj_t *fileobj = JAS_CAST(jas_stream_fileobj_t *, obj);
1100 return write(fileobj->fd, buf, cnt);
1101 }
1102
1103 static long file_seek(jas_stream_obj_t *obj, long offset, int origin)
1104 {
1105 jas_stream_fileobj_t *fileobj = JAS_CAST(jas_stream_fileobj_t *, obj);
1106 return lseek(fileobj->fd, offset, origin);
1107 }
1108
1109 static int file_close(jas_stream_obj_t *obj)
1110 {
1111 jas_stream_fileobj_t *fileobj = JAS_CAST(jas_stream_fileobj_t *, obj);
1112 int ret;
1113 ret = close(fileobj->fd);
1114 if (fileobj->flags & JAS_STREAM_FILEOBJ_DELONCLOSE) {
1115 unlink(fileobj->pathname);
1116 }
1117 jas_free(fileobj);
1118 return ret;
1119 }
1120
1121 /******************************************************************************\
1122 * Stdio file stream object.
1123 \******************************************************************************/
1124
1125 static int sfile_read(jas_stream_obj_t *obj, char *buf, int cnt)
1126 {
1127 FILE *fp;
1128 fp = JAS_CAST(FILE *, obj);
1129 return fread(buf, 1, cnt, fp);
1130 }
1131
1132 static int sfile_write(jas_stream_obj_t *obj, char *buf, int cnt)
1133 {
1134 FILE *fp;
1135 fp = JAS_CAST(FILE *, obj);
1136 return fwrite(buf, 1, cnt, fp);
1137 }
1138
1139 static long sfile_seek(jas_stream_obj_t *obj, long offset, int origin)
1140 {
1141 FILE *fp;
1142 fp = JAS_CAST(FILE *, obj);
1143 return fseek(fp, offset, origin);
1144 }
1145
1146 static int sfile_close(jas_stream_obj_t *obj)
1147 {
1148 FILE *fp;
1149 fp = JAS_CAST(FILE *, obj);
1150 return fclose(fp);
1151 }
1152
1153
1154
1155 // Kinda stupid that we have to add his extension hack,
1156 // but it appears the JAS stream stuff wasn't really designed
1157 // to be open-ended but to support only the above four stream types.
1158 #ifdef VXA_NATIVE
1159 #include "vxa/vxa.h"
1160 #include "jp2/native.h"
1161
1162 static int vxa_read(jas_stream_obj_t *obj, char *buf, int cnt)
1163 {
1164 vxaio *io = (vxaio*)obj;
1165 return io->readf(io, buf, cnt);
1166 }
1167
1168 static int vxa_write(jas_stream_obj_t *obj, char *buf, int cnt)
1169 {
1170 vxaio *io = (vxaio*)obj;
1171 return io->writef(io, buf, cnt);
1172 }
1173
1174 static long vxa_seek(jas_stream_obj_t *obj, long offset, int origin)
1175 {
1176 return -1;
1177 }
1178
1179 static int vxa_close(jas_stream_obj_t *obj)
1180 {
1181 return 0;
1182 }
1183
1184
1185 static jas_stream_ops_t jas_stream_vxaops = {
1186 vxa_read,
1187 vxa_write,
1188 vxa_seek,
1189 vxa_close
1190 };
1191
1192 jas_stream_t *jas_stream_vxaopen(vxaio *io, int openmode)
1193 {
1194 jas_stream_t *stream;
1195
1196 if (!(stream = jas_stream_create())) {
1197 return 0;
1198 }
1199
1200 stream->openmode_ = openmode | JAS_STREAM_BINARY;
1201 stream->ops_ = &jas_stream_vxaops;
1202 stream->obj_ = (void*)io;
1203
1204 jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0);
1205
1206 return stream;
1207 }
1208
1209 #endif // VXA_NATIVE