1 /* 2 * Copyright (c) 1999-2000 Image Power, Inc. and the University of 3 * British Columbia. 4 * Copyright (c) 2001-2003 Michael David Adams. 5 * All rights reserved. 6 */ 7 8 /* __START_OF_JASPER_LICENSE__ 9 * 10 * JasPer License Version 2.0 11 * 12 * Copyright (c) 2001-2006 Michael David Adams 13 * Copyright (c) 1999-2000 Image Power, Inc. 14 * Copyright (c) 1999-2000 The University of British Columbia 15 * 16 * All rights reserved. 17 * 18 * Permission is hereby granted, free of charge, to any person (the 19 * "User") obtaining a copy of this software and associated documentation 20 * files (the "Software"), to deal in the Software without restriction, 21 * including without limitation the rights to use, copy, modify, merge, 22 * publish, distribute, and/or sell copies of the Software, and to permit 23 * persons to whom the Software is furnished to do so, subject to the 24 * following conditions: 25 * 26 * 1. The above copyright notices and this permission notice (which 27 * includes the disclaimer below) shall be included in all copies or 28 * substantial portions of the Software. 29 * 30 * 2. The name of a copyright holder shall not be used to endorse or 31 * promote products derived from the Software without specific prior 32 * written permission. 33 * 34 * THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS 35 * LICENSE. NO USE OF THE SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER 36 * THIS DISCLAIMER. THE SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 37 * "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 38 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 39 * PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO 40 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL 41 * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING 42 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 43 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 44 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. NO ASSURANCES ARE 45 * PROVIDED BY THE COPYRIGHT HOLDERS THAT THE SOFTWARE DOES NOT INFRINGE 46 * THE PATENT OR OTHER INTELLECTUAL PROPERTY RIGHTS OF ANY OTHER ENTITY. 47 * EACH COPYRIGHT HOLDER DISCLAIMS ANY LIABILITY TO THE USER FOR CLAIMS 48 * BROUGHT BY ANY OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL 49 * PROPERTY RIGHTS OR OTHERWISE. AS A CONDITION TO EXERCISING THE RIGHTS 50 * GRANTED HEREUNDER, EACH USER HEREBY ASSUMES SOLE RESPONSIBILITY TO SECURE 51 * ANY OTHER INTELLECTUAL PROPERTY RIGHTS NEEDED, IF ANY. THE SOFTWARE 52 * IS NOT FAULT-TOLERANT AND IS NOT INTENDED FOR USE IN MISSION-CRITICAL 53 * SYSTEMS, SUCH AS THOSE USED IN THE OPERATION OF NUCLEAR FACILITIES, 54 * AIRCRAFT NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL 55 * SYSTEMS, DIRECT LIFE SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH 56 * THE FAILURE OF THE SOFTWARE OR SYSTEM COULD LEAD DIRECTLY TO DEATH, 57 * PERSONAL INJURY, OR SEVERE PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH 58 * RISK ACTIVITIES"). THE COPYRIGHT HOLDERS SPECIFICALLY DISCLAIM ANY 59 * EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR HIGH RISK ACTIVITIES. 60 * 61 * __END_OF_JASPER_LICENSE__ 62 */ 63 64 /* 65 * I/O Stream Library 66 * 67 * $Id: jas_stream.c,v 1.2 2008-05-26 09:40:52 vp153 Exp $ 68 */ 69 70 /******************************************************************************\ 71 * Includes. 72 \******************************************************************************/ 73 74 #include <assert.h> 75 #if defined(HAVE_FCNTL_H) 76 #include <fcntl.h> 77 #endif 78 #include <stdlib.h> 79 #include <stdarg.h> 80 #include <stdio.h> 81 #include <ctype.h> 82 #if defined(HAVE_UNISTD_H) 83 #include <unistd.h> 84 #endif 85 #if defined(WIN32) || defined(HAVE_IO_H) 86 #include <io.h> 87 #endif 88 89 #include "jasper/jas_types.h" 90 #include "jasper/jas_stream.h" 91 #include "jasper/jas_malloc.h" 92 #include "jasper/jas_math.h" 93 94 /******************************************************************************\ 95 * Local function prototypes. 96 \******************************************************************************/ 97 98 static int jas_strtoopenmode(const char *s); 99 static void jas_stream_destroy(jas_stream_t *stream); 100 static jas_stream_t *jas_stream_create(void); 101 static void jas_stream_initbuf(jas_stream_t *stream, int bufmode, char *buf, 102 int bufsize); 103 104 static int mem_read(jas_stream_obj_t *obj, char *buf, int cnt); 105 static int mem_write(jas_stream_obj_t *obj, char *buf, int cnt); 106 static long mem_seek(jas_stream_obj_t *obj, long offset, int origin); 107 static int mem_close(jas_stream_obj_t *obj); 108 109 static int sfile_read(jas_stream_obj_t *obj, char *buf, int cnt); 110 static int sfile_write(jas_stream_obj_t *obj, char *buf, int cnt); 111 static long sfile_seek(jas_stream_obj_t *obj, long offset, int origin); 112 static int sfile_close(jas_stream_obj_t *obj); 113 114 static int file_read(jas_stream_obj_t *obj, char *buf, int cnt); 115 static int file_write(jas_stream_obj_t *obj, char *buf, int cnt); 116 static long file_seek(jas_stream_obj_t *obj, long offset, int origin); 117 static int file_close(jas_stream_obj_t *obj); 118 119 /******************************************************************************\ 120 * Local data. 121 \******************************************************************************/ 122 123 static jas_stream_ops_t jas_stream_fileops = { 124 file_read, 125 file_write, 126 file_seek, 127 file_close 128 }; 129 130 static jas_stream_ops_t jas_stream_sfileops = { 131 sfile_read, 132 sfile_write, 133 sfile_seek, 134 sfile_close 135 }; 136 137 static jas_stream_ops_t jas_stream_memops = { 138 mem_read, 139 mem_write, 140 mem_seek, 141 mem_close 142 }; 143 144 /******************************************************************************\ 145 * Code for opening and closing streams. 146 \******************************************************************************/ 147 148 static jas_stream_t *jas_stream_create() 149 { 150 jas_stream_t *stream; 151 152 if (!(stream = jas_malloc(sizeof(jas_stream_t)))) { 153 return 0; 154 } 155 stream->openmode_ = 0; 156 stream->bufmode_ = 0; 157 stream->flags_ = 0; 158 stream->bufbase_ = 0; 159 stream->bufstart_ = 0; 160 stream->bufsize_ = 0; 161 stream->ptr_ = 0; 162 stream->cnt_ = 0; 163 stream->ops_ = 0; 164 stream->obj_ = 0; 165 stream->rwcnt_ = 0; 166 stream->rwlimit_ = -1; 167 168 return stream; 169 } 170 171 jas_stream_t *jas_stream_memopen(char *buf, int bufsize) 172 { 173 jas_stream_t *stream; 174 jas_stream_memobj_t *obj; 175 176 if (!(stream = jas_stream_create())) { 177 return 0; 178 } 179 180 /* A stream associated with a memory buffer is always opened 181 for both reading and writing in binary mode. */ 182 stream->openmode_ = JAS_STREAM_READ | JAS_STREAM_WRITE | JAS_STREAM_BINARY; 183 184 /* Since the stream data is already resident in memory, buffering 185 is not necessary. */ 186 /* But... It still may be faster to use buffering anyways. */ 187 jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0); 188 189 /* Select the operations for a memory stream. */ 190 stream->ops_ = &jas_stream_memops; 191 192 /* Allocate memory for the underlying memory stream object. */ 193 if (!(obj = jas_malloc(sizeof(jas_stream_memobj_t)))) { 194 jas_stream_destroy(stream); 195 return 0; 196 } 197 stream->obj_ = (void *) obj; 198 199 /* Initialize a few important members of the memory stream object. */ 200 obj->myalloc_ = 0; 201 obj->buf_ = 0; 202 203 /* If the buffer size specified is nonpositive, then the buffer 204 is allocated internally and automatically grown as needed. */ 205 if (bufsize <= 0) { 206 obj->bufsize_ = 1024; 207 obj->growable_ = 1; 208 } else { 209 obj->bufsize_ = bufsize; 210 obj->growable_ = 0; 211 } 212 if (buf) { 213 obj->buf_ = (unsigned char *) buf; 214 } else { 215 obj->buf_ = jas_malloc(obj->bufsize_); 216 obj->myalloc_ = 1; 217 } 218 if (!obj->buf_) { 219 jas_stream_close(stream); 220 return 0; 221 } 222 223 if (bufsize > 0 && buf) { 224 /* If a buffer was supplied by the caller and its length is positive, 225 make the associated buffer data appear in the stream initially. */ 226 obj->len_ = bufsize; 227 } else { 228 /* The stream is initially empty. */ 229 obj->len_ = 0; 230 } 231 obj->pos_ = 0; 232 233 return stream; 234 } 235 236 jas_stream_t *jas_stream_fopen(const char *filename, const char *mode) 237 { 238 jas_stream_t *stream; 239 jas_stream_fileobj_t *obj; 240 int openflags; 241 242 /* Allocate a stream object. */ 243 if (!(stream = jas_stream_create())) { 244 return 0; 245 } 246 247 /* Parse the mode string. */ 248 stream->openmode_ = jas_strtoopenmode(mode); 249 250 /* Determine the correct flags to use for opening the file. */ 251 if ((stream->openmode_ & JAS_STREAM_READ) && 252 (stream->openmode_ & JAS_STREAM_WRITE)) { 253 openflags = O_RDWR; 254 } else if (stream->openmode_ & JAS_STREAM_READ) { 255 openflags = O_RDONLY; 256 } else if (stream->openmode_ & JAS_STREAM_WRITE) { 257 openflags = O_WRONLY; 258 } else { 259 openflags = 0; 260 } 261 if (stream->openmode_ & JAS_STREAM_APPEND) { 262 openflags |= O_APPEND; 263 } 264 if (stream->openmode_ & JAS_STREAM_BINARY) { 265 openflags |= O_BINARY; 266 } 267 if (stream->openmode_ & JAS_STREAM_CREATE) { 268 openflags |= O_CREAT | O_TRUNC; 269 } 270 271 /* Allocate space for the underlying file stream object. */ 272 if (!(obj = jas_malloc(sizeof(jas_stream_fileobj_t)))) { 273 jas_stream_destroy(stream); 274 return 0; 275 } 276 obj->fd = -1; 277 obj->flags = 0; 278 obj->pathname[0] = '\0'; 279 stream->obj_ = (void *) obj; 280 281 /* Select the operations for a file stream object. */ 282 stream->ops_ = &jas_stream_fileops; 283 284 /* Open the underlying file. */ 285 if ((obj->fd = open(filename, openflags, JAS_STREAM_PERMS)) < 0) { 286 jas_stream_destroy(stream); 287 return 0; 288 } 289 290 /* By default, use full buffering for this type of stream. */ 291 jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0); 292 293 return stream; 294 } 295 296 jas_stream_t *jas_stream_freopen(const char *path, const char *mode, FILE *fp) 297 { 298 jas_stream_t *stream; 299 int openflags; 300 301 /* Eliminate compiler warning about unused variable. */ 302 path = 0; 303 304 /* Allocate a stream object. */ 305 if (!(stream = jas_stream_create())) { 306 return 0; 307 } 308 309 /* Parse the mode string. */ 310 stream->openmode_ = jas_strtoopenmode(mode); 311 312 /* Determine the correct flags to use for opening the file. */ 313 if ((stream->openmode_ & JAS_STREAM_READ) && 314 (stream->openmode_ & JAS_STREAM_WRITE)) { 315 openflags = O_RDWR; 316 } else if (stream->openmode_ & JAS_STREAM_READ) { 317 openflags = O_RDONLY; 318 } else if (stream->openmode_ & JAS_STREAM_WRITE) { 319 openflags = O_WRONLY; 320 } else { 321 openflags = 0; 322 } 323 if (stream->openmode_ & JAS_STREAM_APPEND) { 324 openflags |= O_APPEND; 325 } 326 if (stream->openmode_ & JAS_STREAM_BINARY) { 327 openflags |= O_BINARY; 328 } 329 if (stream->openmode_ & JAS_STREAM_CREATE) { 330 openflags |= O_CREAT | O_TRUNC; 331 } 332 333 stream->obj_ = JAS_CAST(void *, fp); 334 335 /* Select the operations for a file stream object. */ 336 stream->ops_ = &jas_stream_sfileops; 337 338 /* By default, use full buffering for this type of stream. */ 339 jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0); 340 341 return stream; 342 } 343 344 jas_stream_t *jas_stream_tmpfile() 345 { 346 jas_stream_t *stream; 347 jas_stream_fileobj_t *obj; 348 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 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 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 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 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 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 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 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 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. */ 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 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 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 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 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 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 644 int jas_stream_rewind(jas_stream_t *stream) 645 { 646 return jas_stream_seek(stream, 0, SEEK_SET); 647 } 648 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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