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