1/* 2 * Copyright (c) 1999-2000 Image Power, Inc. and the University of 3 * British Columbia. 4 * Copyright (c) 2001-2002 Michael David Adams. 5 * All rights reserved. 6 */ 7 8/* __START_OF_JASPER_LICENSE__ 9 * 10 * JasPer Software License 11 * 12 * IMAGE POWER JPEG-2000 PUBLIC LICENSE 13 * ************************************ 14 * 15 * GRANT: 16 * 17 * Permission is hereby granted, free of charge, to any person (the "User") 18 * obtaining a copy of this software and associated documentation, to deal 19 * in the JasPer Software without restriction, including without limitation 20 * the right to use, copy, modify, merge, publish, distribute, sublicense, 21 * and/or sell copies of the JasPer Software (in source and binary forms), 22 * and to permit persons to whom the JasPer Software is furnished to do so, 23 * provided further that the License Conditions below are met. 24 * 25 * License Conditions 26 * ****************** 27 * 28 * A. Redistributions of source code must retain the above copyright notice, 29 * and this list of conditions, and the following disclaimer. 30 * 31 * B. Redistributions in binary form must reproduce the above copyright 32 * notice, and this list of conditions, and the following disclaimer in 33 * the documentation and/or other materials provided with the distribution. 34 * 35 * C. Neither the name of Image Power, Inc. nor any other contributor 36 * (including, but not limited to, the University of British Columbia and 37 * Michael David Adams) may be used to endorse or promote products derived 38 * from this software without specific prior written permission. 39 * 40 * D. User agrees that it shall not commence any action against Image Power, 41 * Inc., the University of British Columbia, Michael David Adams, or any 42 * other contributors (collectively "Licensors") for infringement of any 43 * intellectual property rights ("IPR") held by the User in respect of any 44 * technology that User owns or has a right to license or sublicense and 45 * which is an element required in order to claim compliance with ISO/IEC 46 * 15444-1 (i.e., JPEG-2000 Part 1). "IPR" means all intellectual property 47 * rights worldwide arising under statutory or common law, and whether 48 * or not perfected, including, without limitation, all (i) patents and 49 * patent applications owned or licensable by User; (ii) rights associated 50 * with works of authorship including copyrights, copyright applications, 51 * copyright registrations, mask work rights, mask work applications, 52 * mask work registrations; (iii) rights relating to the protection of 53 * trade secrets and confidential information; (iv) any right analogous 54 * to those set forth in subsections (i), (ii), or (iii) and any other 55 * proprietary rights relating to intangible property (other than trademark, 56 * trade dress, or service mark rights); and (v) divisions, continuations, 57 * renewals, reissues and extensions of the foregoing (as and to the extent 58 * applicable) now existing, hereafter filed, issued or acquired. 59 * 60 * E. If User commences an infringement action against any Licensor(s) then 61 * such Licensor(s) shall have the right to terminate User's license and 62 * all sublicenses that have been granted hereunder by User to other parties. 63 * 64 * F. This software is for use only in hardware or software products that 65 * are compliant with ISO/IEC 15444-1 (i.e., JPEG-2000 Part 1). No license 66 * or right to this Software is granted for products that do not comply 67 * with ISO/IEC 15444-1. The JPEG-2000 Part 1 standard can be purchased 68 * from the ISO. 69 * 70 * THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. 71 * NO USE OF THE JASPER SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER 72 * THIS DISCLAIMER. THE JASPER SOFTWARE IS PROVIDED BY THE LICENSORS AND 73 * CONTRIBUTORS UNDER THIS LICENSE ON AN ``AS-IS'' BASIS, WITHOUT WARRANTY 74 * OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, 75 * WARRANTIES THAT THE JASPER SOFTWARE IS FREE OF DEFECTS, IS MERCHANTABLE, 76 * IS FIT FOR A PARTICULAR PURPOSE OR IS NON-INFRINGING. THOSE INTENDING 77 * TO USE THE JASPER SOFTWARE OR MODIFICATIONS THEREOF FOR USE IN HARDWARE 78 * OR SOFTWARE PRODUCTS ARE ADVISED THAT THEIR USE MAY INFRINGE EXISTING 79 * PATENTS, COPYRIGHTS, TRADEMARKS, OR OTHER INTELLECTUAL PROPERTY RIGHTS. 80 * THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE JASPER SOFTWARE 81 * IS WITH THE USER. SHOULD ANY PART OF THE JASPER SOFTWARE PROVE DEFECTIVE 82 * IN ANY RESPECT, THE USER (AND NOT THE INITIAL DEVELOPERS, THE UNIVERSITY 83 * OF BRITISH COLUMBIA, IMAGE POWER, INC., MICHAEL DAVID ADAMS, OR ANY 84 * OTHER CONTRIBUTOR) SHALL ASSUME THE COST OF ANY NECESSARY SERVICING, 85 * REPAIR OR CORRECTION. UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, 86 * WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL THE 87 * INITIAL DEVELOPER, THE UNIVERSITY OF BRITISH COLUMBIA, IMAGE POWER, INC., 88 * MICHAEL DAVID ADAMS, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF THE 89 * JASPER SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO 90 * THE USER OR ANY OTHER PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR 91 * CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, 92 * DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR 93 * MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF 94 * SUCH PARTY HAD BEEN INFORMED, OR OUGHT TO HAVE KNOWN, OF THE POSSIBILITY 95 * OF SUCH DAMAGES. THE JASPER SOFTWARE AND UNDERLYING TECHNOLOGY ARE NOT 96 * FAULT-TOLERANT AND ARE NOT DESIGNED, MANUFACTURED OR INTENDED FOR USE OR 97 * RESALE AS ON-LINE CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING 98 * FAIL-SAFE PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, 99 * AIRCRAFT NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT 100 * LIFE SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE 101 * JASPER SOFTWARE OR UNDERLYING TECHNOLOGY OR PRODUCT COULD LEAD DIRECTLY 102 * TO DEATH, PERSONAL INJURY, OR SEVERE PHYSICAL OR ENVIRONMENTAL DAMAGE 103 * ("HIGH RISK ACTIVITIES"). LICENSOR SPECIFICALLY DISCLAIMS ANY EXPRESS 104 * OR IMPLIED WARRANTY OF FITNESS FOR HIGH RISK ACTIVITIES. USER WILL NOT 105 * KNOWINGLY USE, DISTRIBUTE OR RESELL THE JASPER SOFTWARE OR UNDERLYING 106 * TECHNOLOGY OR PRODUCTS FOR HIGH RISK ACTIVITIES AND WILL ENSURE THAT ITS 107 * CUSTOMERS AND END-USERS OF ITS PRODUCTS ARE PROVIDED WITH A COPY OF THE 108 * NOTICE SPECIFIED IN THIS SECTION. 109 * 110 * __END_OF_JASPER_LICENSE__ 111 */ 112 113/* 114 * I/O Stream Library 115 * 116 * $Id: jas_stream.c 14449 2005-10-20 12:15:56Z stippi $ 117 */ 118 119/******************************************************************************\ 120* Includes. 121\******************************************************************************/ 122 123#include <assert.h> 124#include <fcntl.h> 125#include <stdlib.h> 126#include <stdarg.h> 127#include <stdio.h> 128#include <ctype.h> 129#if defined(HAVE_UNISTD_H) 130#include <unistd.h> 131#endif 132#if defined(WIN32) || defined(HAVE_IO_H) 133#include <io.h> 134#endif 135 136#include "jasper/jas_types.h" 137#include "jasper/jas_stream.h" 138#include "jasper/jas_malloc.h" 139#include "jasper/jas_math.h" 140 141/******************************************************************************\ 142* Local function prototypes. 143\******************************************************************************/ 144 145static int jas_strtoopenmode(const char *s); 146static void jas_stream_destroy(jas_stream_t *stream); 147static jas_stream_t *jas_stream_create(void); 148static void jas_stream_initbuf(jas_stream_t *stream, int bufmode, char *buf, 149 int bufsize); 150 151static int mem_read(jas_stream_obj_t *obj, char *buf, int cnt); 152static int mem_write(jas_stream_obj_t *obj, char *buf, int cnt); 153static long mem_seek(jas_stream_obj_t *obj, long offset, int origin); 154static int mem_close(jas_stream_obj_t *obj); 155 156static int sfile_read(jas_stream_obj_t *obj, char *buf, int cnt); 157static int sfile_write(jas_stream_obj_t *obj, char *buf, int cnt); 158static long sfile_seek(jas_stream_obj_t *obj, long offset, int origin); 159static int sfile_close(jas_stream_obj_t *obj); 160 161static int file_read(jas_stream_obj_t *obj, char *buf, int cnt); 162static int file_write(jas_stream_obj_t *obj, char *buf, int cnt); 163static long file_seek(jas_stream_obj_t *obj, long offset, int origin); 164static int file_close(jas_stream_obj_t *obj); 165 166/******************************************************************************\ 167* Local data. 168\******************************************************************************/ 169 170static jas_stream_ops_t jas_stream_fileops = { 171 file_read, 172 file_write, 173 file_seek, 174 file_close 175}; 176 177static jas_stream_ops_t jas_stream_sfileops = { 178 sfile_read, 179 sfile_write, 180 sfile_seek, 181 sfile_close 182}; 183 184static jas_stream_ops_t jas_stream_memops = { 185 mem_read, 186 mem_write, 187 mem_seek, 188 mem_close 189}; 190 191/******************************************************************************\ 192* Code for opening and closing streams. 193\******************************************************************************/ 194 195static jas_stream_t *jas_stream_create() 196{ 197 jas_stream_t *stream; 198 199 if (!(stream = jas_malloc(sizeof(jas_stream_t)))) { 200 return 0; 201 } 202 stream->openmode_ = 0; 203 stream->bufmode_ = 0; 204 stream->flags_ = 0; 205 stream->bufbase_ = 0; 206 stream->bufstart_ = 0; 207 stream->bufsize_ = 0; 208 stream->ptr_ = 0; 209 stream->cnt_ = 0; 210 stream->ops_ = 0; 211 stream->obj_ = 0; 212 stream->rwcnt_ = 0; 213 stream->rwlimit_ = -1; 214 215 return stream; 216} 217 218jas_stream_t *jas_stream_memopen(char *buf, int bufsize) 219{ 220 jas_stream_t *stream; 221 jas_stream_memobj_t *obj; 222 223 if (!(stream = jas_stream_create())) { 224 return 0; 225 } 226 227 /* A stream associated with a memory buffer is always opened 228 for both reading and writing in binary mode. */ 229 stream->openmode_ = JAS_STREAM_READ | JAS_STREAM_WRITE | JAS_STREAM_BINARY; 230 231 /* Since the stream data is already resident in memory, buffering 232 is not necessary. */ 233 /* But... It still may be faster to use buffering anyways. */ 234 jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0); 235 236 /* Select the operations for a memory stream. */ 237 stream->ops_ = &jas_stream_memops; 238 239 /* Allocate memory for the underlying memory stream object. */ 240 if (!(obj = jas_malloc(sizeof(jas_stream_memobj_t)))) { 241 jas_stream_destroy(stream); 242 return 0; 243 } 244 stream->obj_ = (void *) obj; 245 246 /* Initialize a few important members of the memory stream object. */ 247 obj->myalloc_ = 0; 248 obj->buf_ = 0; 249 250 /* If the buffer size specified is nonpositive, then the buffer 251 is allocated internally and automatically grown as needed. */ 252 if (bufsize <= 0) { 253 obj->bufsize_ = 1024; 254 obj->growable_ = 1; 255 } else { 256 obj->bufsize_ = bufsize; 257 obj->growable_ = 0; 258 } 259 if (buf) { 260 obj->buf_ = (unsigned char *) buf; 261 } else { 262 obj->buf_ = jas_malloc(obj->bufsize_ * sizeof(char)); 263 obj->myalloc_ = 1; 264 } 265 if (!obj->buf_) { 266 jas_stream_close(stream); 267 return 0; 268 } 269 270 if (bufsize > 0 && buf) { 271 /* If a buffer was supplied by the caller and its length is positive, 272 make the associated buffer data appear in the stream initially. */ 273 obj->len_ = bufsize; 274 } else { 275 /* The stream is initially empty. */ 276 obj->len_ = 0; 277 } 278 obj->pos_ = 0; 279 280 return stream; 281} 282 283jas_stream_t *jas_stream_fopen(const char *filename, const char *mode) 284{ 285 jas_stream_t *stream; 286 int *obj; 287 int openflags; 288 289 /* Allocate a stream object. */ 290 if (!(stream = jas_stream_create())) { 291 return 0; 292 } 293 294 /* Parse the mode string. */ 295 stream->openmode_ = jas_strtoopenmode(mode); 296 297 /* Determine the correct flags to use for opening the file. */ 298 if ((stream->openmode_ & JAS_STREAM_READ) && 299 (stream->openmode_ & JAS_STREAM_WRITE)) { 300 openflags = O_RDWR; 301 } else if (stream->openmode_ & JAS_STREAM_READ) { 302 openflags = O_RDONLY; 303 } else if (stream->openmode_ & JAS_STREAM_WRITE) { 304 openflags = O_WRONLY; 305 } else { 306 openflags = 0; 307 } 308 if (stream->openmode_ & JAS_STREAM_APPEND) { 309 openflags |= O_APPEND; 310 } 311 if (stream->openmode_ & JAS_STREAM_BINARY) { 312 openflags |= O_BINARY; 313 } 314 if (stream->openmode_ & JAS_STREAM_CREATE) { 315 openflags |= O_CREAT | O_TRUNC; 316 } 317 318 /* Allocate space for the underlying file stream object. */ 319 if (!(obj = jas_malloc(sizeof(int)))) { 320 jas_stream_destroy(stream); 321 return 0; 322 } 323 stream->obj_ = (void *) obj; 324 325 /* Select the operations for a file stream object. */ 326 stream->ops_ = &jas_stream_fileops; 327 328 /* Open the underlying file. */ 329 if ((*obj = open(filename, openflags, JAS_STREAM_PERMS)) < 0) { 330 jas_stream_destroy(stream); 331 return 0; 332 } 333 334 /* By default, use full buffering for this type of stream. */ 335 jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0); 336 337 return stream; 338} 339 340jas_stream_t *jas_stream_freopen(const char *path, const char *mode, FILE *fp) 341{ 342 jas_stream_t *stream; 343 int openflags; 344 345 /* Allocate a stream object. */ 346 if (!(stream = jas_stream_create())) { 347 return 0; 348 } 349 350 /* Parse the mode string. */ 351 stream->openmode_ = jas_strtoopenmode(mode); 352 353 /* Determine the correct flags to use for opening the file. */ 354 if ((stream->openmode_ & JAS_STREAM_READ) && 355 (stream->openmode_ & JAS_STREAM_WRITE)) { 356 openflags = O_RDWR; 357 } else if (stream->openmode_ & JAS_STREAM_READ) { 358 openflags = O_RDONLY; 359 } else if (stream->openmode_ & JAS_STREAM_WRITE) { 360 openflags = O_WRONLY; 361 } else { 362 openflags = 0; 363 } 364 if (stream->openmode_ & JAS_STREAM_APPEND) { 365 openflags |= O_APPEND; 366 } 367 if (stream->openmode_ & JAS_STREAM_BINARY) { 368 openflags |= O_BINARY; 369 } 370 if (stream->openmode_ & JAS_STREAM_CREATE) { 371 openflags |= O_CREAT | O_TRUNC; 372 } 373 374 stream->obj_ = JAS_CAST(void *, fp); 375 376 /* Select the operations for a file stream object. */ 377 stream->ops_ = &jas_stream_sfileops; 378 379 /* By default, use full buffering for this type of stream. */ 380 jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0); 381 382 return stream; 383} 384 385jas_stream_t *jas_stream_tmpfile() 386{ 387 jas_stream_t *stream; 388 int *obj; 389 char filename[L_tmpnam + 1]; 390 391 if (!(stream = jas_stream_create())) { 392 return 0; 393 } 394 395 /* A temporary file stream is always opened for both reading and 396 writing in binary mode. */ 397 stream->openmode_ = JAS_STREAM_READ | JAS_STREAM_WRITE | JAS_STREAM_BINARY; 398 399 /* Allocate memory for the underlying temporary file object. */ 400 if (!(obj = jas_malloc(sizeof(int)))) { 401 jas_stream_destroy(stream); 402 return 0; 403 } 404 stream->obj_ = obj; 405 406 /* Choose a file name. */ 407 tmpnam(filename); 408 409 /* Open the underlying file. */ 410 if ((*obj = open(filename, O_CREAT | O_EXCL | O_RDWR | O_TRUNC | O_BINARY, 411 JAS_STREAM_PERMS)) < 0) { 412 jas_stream_destroy(stream); 413 return 0; 414 } 415 416 /* Unlink the file so that it will disappear if the program 417 terminates abnormally. */ 418 /* Under UNIX, one can unlink an open file and continue to do I/O 419 on it. This also appears to work under MS Windows. If you use 420 some other operating system, this may not work. :-) If this 421 functionality is not supported by the operating system, the unlink 422 operation must be deferred until the file is closed. */ 423 unlink(filename); 424 425 /* Use full buffering. */ 426 jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0); 427 428 stream->ops_ = &jas_stream_fileops; 429 430 return stream; 431} 432 433jas_stream_t *jas_stream_fdopen(int fd, const char *mode) 434{ 435 jas_stream_t *stream; 436 int *obj; 437 438 /* Allocate a stream object. */ 439 if (!(stream = jas_stream_create())) { 440 return 0; 441 } 442 443 /* Parse the mode string. */ 444 stream->openmode_ = jas_strtoopenmode(mode); 445 446#if defined(WIN32) 447 /* Argh!!! Someone ought to banish text mode (i.e., O_TEXT) to the 448 greatest depths of purgatory! */ 449 /* Ensure that the file descriptor is in binary mode, if the caller 450 has specified the binary mode flag. Arguably, the caller ought to 451 take care of this, but text mode is a ugly wart anyways, so we save 452 the caller some grief by handling this within the stream library. */ 453 /* This ugliness is mainly for the benefit of those who run the 454 JasPer software under Windows from shells that insist on opening 455 files in text mode. For example, in the Cygwin environment, 456 shells often open files in text mode when I/O redirection is 457 used. Grr... */ 458 if (stream->openmode_ & JAS_STREAM_BINARY) { 459 setmode(fd, O_BINARY); 460 } 461#endif 462 463 /* Allocate space for the underlying file stream object. */ 464 if (!(obj = jas_malloc(sizeof(int)))) { 465 jas_stream_destroy(stream); 466 return 0; 467 } 468 stream->obj_ = (void *) obj; 469 *obj = fd; 470 471 /* By default, use full buffering for this type of stream. */ 472 jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0); 473 474 /* Select the operations for a file stream object. */ 475 stream->ops_ = &jas_stream_fileops; 476 477/* Do not close the underlying file descriptor when the stream is closed. */ 478 stream->openmode_ |= JAS_STREAM_NOCLOSE; 479 480 return stream; 481} 482 483static void jas_stream_destroy(jas_stream_t *stream) 484{ 485 /* If the memory for the buffer was allocated with malloc, free 486 this memory. */ 487 if ((stream->bufmode_ & JAS_STREAM_FREEBUF) && stream->bufbase_) { 488 jas_free(stream->bufbase_); 489 stream->bufbase_ = 0; 490 } 491 jas_free(stream); 492} 493 494int jas_stream_close(jas_stream_t *stream) 495{ 496 /* Flush buffer if necessary. */ 497 jas_stream_flush(stream); 498 499 /* Close the underlying stream object. */ 500 if (!(stream->openmode_ & JAS_STREAM_NOCLOSE)) { 501 (*stream->ops_->close_)(stream->obj_); 502 } 503 504 jas_stream_destroy(stream); 505 506 return 0; 507} 508 509/******************************************************************************\ 510* Code for reading and writing streams. 511\******************************************************************************/ 512 513int jas_stream_getc_func(jas_stream_t *stream) 514{ 515 assert(stream->ptr_ - stream->bufbase_ <= stream->bufsize_ + 516 JAS_STREAM_MAXPUTBACK); 517 return jas_stream_getc_macro(stream); 518} 519 520int jas_stream_putc_func(jas_stream_t *stream, int c) 521{ 522 assert(stream->ptr_ - stream->bufstart_ <= stream->bufsize_); 523 return jas_stream_putc_macro(stream, c); 524} 525 526int jas_stream_ungetc(jas_stream_t *stream, int c) 527{ 528 if (!stream->ptr_ || stream->ptr_ == stream->bufbase_) { 529 return -1; 530 } 531 532 /* Reset the EOF indicator (since we now have at least one character 533 to read). */ 534 stream->flags_ &= ~JAS_STREAM_EOF; 535 536 --stream->rwcnt_; 537 --stream->ptr_; 538 ++stream->cnt_; 539 *stream->ptr_ = c; 540 return 0; 541} 542 543int jas_stream_read(jas_stream_t *stream, void *buf, int cnt) 544{ 545 int n; 546 int c; 547 char *bufptr; 548 549 bufptr = buf; 550 551 n = 0; 552 while (n < cnt) { 553 if ((c = jas_stream_getc(stream)) == EOF) { 554 return n; 555 } 556 *bufptr++ = c; 557 ++n; 558 } 559 560 return n; 561} 562 563int jas_stream_write(jas_stream_t *stream, const void *buf, int cnt) 564{ 565 int n; 566 const char *bufptr; 567 568 bufptr = buf; 569 570 n = 0; 571 while (n < cnt) { 572 if (jas_stream_putc(stream, *bufptr) == EOF) { 573 return n; 574 } 575 ++bufptr; 576 ++n; 577 } 578 579 return n; 580} 581 582/* Note: This function uses a fixed size buffer. Therefore, it cannot 583 handle invocations that will produce more output than can be held 584 by the buffer. */ 585int jas_stream_printf(jas_stream_t *stream, const char *fmt, ...) 586{ 587 va_list ap; 588 char buf[4096]; 589 int ret; 590 591 va_start(ap, fmt); 592 ret = vsprintf(buf, fmt, ap); 593 jas_stream_puts(stream, buf); 594 va_end(ap); 595 return ret; 596} 597 598int jas_stream_puts(jas_stream_t *stream, const char *s) 599{ 600 while (*s != '\0') { 601 if (jas_stream_putc_macro(stream, *s) == EOF) { 602 return -1; 603 } 604 ++s; 605 } 606 return 0; 607} 608 609char *jas_stream_gets(jas_stream_t *stream, char *buf, int bufsize) 610{ 611 int c; 612 char *bufptr; 613 assert(bufsize > 0); 614 615 bufptr = buf; 616 while (bufsize > 1) { 617 if ((c = jas_stream_getc(stream)) == EOF) { 618 break; 619 } 620 *bufptr++ = c; 621 --bufsize; 622 if (c == '\n') { 623 break; 624 } 625 } 626 *bufptr = '\0'; 627 return buf; 628} 629 630int jas_stream_gobble(jas_stream_t *stream, int n) 631{ 632 int m; 633 m = n; 634 for (m = n; m > 0; --m) { 635 if (jas_stream_getc(stream) == EOF) { 636 return n - m; 637 } 638 } 639 return n; 640} 641 642/******************************************************************************\ 643* Code for getting and setting the stream position. 644\******************************************************************************/ 645 646int jas_stream_isseekable(jas_stream_t *stream) 647{ 648 if (stream->ops_ == &jas_stream_memops) { 649 return 1; 650 } else if (stream->ops_ == &jas_stream_fileops) { 651 if ((*stream->ops_->seek_)(stream->obj_, 0, SEEK_CUR) < 0) { 652 return 0; 653 } 654 return 1; 655 } else { 656 return 0; 657 } 658} 659 660int jas_stream_rewind(jas_stream_t *stream) 661{ 662 return jas_stream_seek(stream, 0, SEEK_SET); 663} 664 665long jas_stream_seek(jas_stream_t *stream, long offset, int origin) 666{ 667 long newpos; 668 669 /* The buffer cannot be in use for both reading and writing. */ 670 assert(!((stream->bufmode_ & JAS_STREAM_RDBUF) && (stream->bufmode_ & 671 JAS_STREAM_WRBUF))); 672 673 /* Reset the EOF indicator (since we may not be at the EOF anymore). */ 674 stream->flags_ &= ~JAS_STREAM_EOF; 675 676 if (stream->bufmode_ & JAS_STREAM_RDBUF) { 677 if (origin == SEEK_CUR) { 678 offset -= stream->cnt_; 679 } 680 } else if (stream->bufmode_ & JAS_STREAM_WRBUF) { 681 if (jas_stream_flush(stream)) { 682 return -1; 683 } 684 } 685 stream->cnt_ = 0; 686 stream->ptr_ = stream->bufstart_; 687 stream->bufmode_ &= ~(JAS_STREAM_RDBUF | JAS_STREAM_WRBUF); 688 689 if ((newpos = (*stream->ops_->seek_)(stream->obj_, offset, origin)) 690 < 0) { 691 return -1; 692 } 693 694 return newpos; 695} 696 697long jas_stream_tell(jas_stream_t *stream) 698{ 699 int adjust; 700 int offset; 701 702 if (stream->bufmode_ & JAS_STREAM_RDBUF) { 703 adjust = -stream->cnt_; 704 } else if (stream->bufmode_ & JAS_STREAM_WRBUF) { 705 adjust = stream->ptr_ - stream->bufstart_; 706 } else { 707 adjust = 0; 708 } 709 710 if ((offset = (*stream->ops_->seek_)(stream->obj_, 0, SEEK_CUR)) < 0) { 711 return -1; 712 } 713 714 return offset + adjust; 715} 716 717/******************************************************************************\ 718* Buffer initialization code. 719\******************************************************************************/ 720 721static void jas_stream_initbuf(jas_stream_t *stream, int bufmode, char *buf, 722 int bufsize) 723{ 724 /* If this function is being called, the buffer should not have been 725 initialized yet. */ 726 assert(!stream->bufbase_); 727 728 if (bufmode != JAS_STREAM_UNBUF) { 729 /* The full- or line-buffered mode is being employed. */ 730 if (!buf) { 731 /* The caller has not specified a buffer to employ, so allocate 732 one. */ 733 if ((stream->bufbase_ = jas_malloc(JAS_STREAM_BUFSIZE + 734 JAS_STREAM_MAXPUTBACK))) { 735 stream->bufmode_ |= JAS_STREAM_FREEBUF; 736 stream->bufsize_ = JAS_STREAM_BUFSIZE; 737 } else { 738 /* The buffer allocation has failed. Resort to unbuffered 739 operation. */ 740 stream->bufbase_ = stream->tinybuf_; 741 stream->bufsize_ = 1; 742 } 743 } else { 744 /* The caller has specified a buffer to employ. */ 745 /* The buffer must be large enough to accommodate maximum 746 putback. */ 747 assert(bufsize > JAS_STREAM_MAXPUTBACK); 748 stream->bufbase_ = JAS_CAST(jpr_uchar_t *, buf); 749 stream->bufsize_ = bufsize - JAS_STREAM_MAXPUTBACK; 750 } 751 } else { 752 /* The unbuffered mode is being employed. */ 753 /* A buffer should not have been supplied by the caller. */ 754 assert(!buf); 755 /* Use a trivial one-character buffer. */ 756 stream->bufbase_ = stream->tinybuf_; 757 stream->bufsize_ = 1; 758 } 759 stream->bufstart_ = &stream->bufbase_[JAS_STREAM_MAXPUTBACK]; 760 stream->ptr_ = stream->bufstart_; 761 stream->cnt_ = 0; 762 stream->bufmode_ |= bufmode & JAS_STREAM_BUFMODEMASK; 763} 764 765/******************************************************************************\ 766* Buffer filling and flushing code. 767\******************************************************************************/ 768 769int jas_stream_flush(jas_stream_t *stream) 770{ 771 if (stream->bufmode_ & JAS_STREAM_RDBUF) { 772 return 0; 773 } 774 return jas_stream_flushbuf(stream, EOF); 775} 776 777int jas_stream_fillbuf(jas_stream_t *stream, int getflag) 778{ 779 int c; 780 781 /* The stream must not be in an error or EOF state. */ 782 if ((stream->flags_ & (JAS_STREAM_ERRMASK)) != 0) { 783 return EOF; 784 } 785 786 /* The stream must be open for reading. */ 787 if ((stream->openmode_ & JAS_STREAM_READ) == 0) { 788 return EOF; 789 } 790 791 /* Make a half-hearted attempt to confirm that the buffer is not 792 currently being used for writing. This check is not intended 793 to be foolproof! */ 794 assert((stream->bufmode_ & JAS_STREAM_WRBUF) == 0); 795 796 assert(stream->ptr_ - stream->bufstart_ <= stream->bufsize_); 797 798 /* Mark the buffer as being used for reading. */ 799 stream->bufmode_ |= JAS_STREAM_RDBUF; 800 801 /* Read new data into the buffer. */ 802 stream->ptr_ = stream->bufstart_; 803 if ((stream->cnt_ = (*stream->ops_->read_)(stream->obj_, 804 (char *) stream->bufstart_, stream->bufsize_)) <= 0) { 805 if (stream->cnt_ < 0) { 806 stream->flags_ |= JAS_STREAM_ERR; 807 } else { 808 stream->flags_ |= JAS_STREAM_EOF; 809 } 810 stream->cnt_ = 0; 811 return EOF; 812 } 813 814 assert(stream->cnt_ > 0); 815 /* Get or peek at the first character in the buffer. */ 816 c = (getflag) ? jas_stream_getc2(stream) : (*stream->ptr_); 817 818 return c; 819} 820 821int jas_stream_flushbuf(jas_stream_t *stream, int c) 822{ 823 int len; 824 int n; 825 826 /* The stream should not be in an error or EOF state. */ 827 if ((stream->flags_ & (JAS_STREAM_ERRMASK)) != 0) { 828 return EOF; 829 } 830 831 /* The stream must be open for writing. */ 832 if ((stream->openmode_ & (JAS_STREAM_WRITE | JAS_STREAM_APPEND)) == 0) { 833 return EOF; 834 } 835 836 /* The buffer should not currently be in use for reading. */ 837 assert(!(stream->bufmode_ & JAS_STREAM_RDBUF)); 838 839 /* Note: Do not use the quantity stream->cnt to determine the number 840 of characters in the buffer! Depending on how this function was 841 called, the stream->cnt value may be "off-by-one". */ 842 len = stream->ptr_ - stream->bufstart_; 843 if (len > 0) { 844 n = (*stream->ops_->write_)(stream->obj_, (char *) 845 stream->bufstart_, len); 846 if (n != len) { 847 stream->flags_ |= JAS_STREAM_ERR; 848 return EOF; 849 } 850 } 851 stream->cnt_ = stream->bufsize_; 852 stream->ptr_ = stream->bufstart_; 853 854 stream->bufmode_ |= JAS_STREAM_WRBUF; 855 856 if (c != EOF) { 857 assert(stream->cnt_ > 0); 858 jas_stream_putc2(stream, c); 859 } 860 861 return 0; 862} 863 864/******************************************************************************\ 865* Miscellaneous code. 866\******************************************************************************/ 867 868static int jas_strtoopenmode(const char *s) 869{ 870 int openmode = 0; 871 while (*s != '\0') { 872 switch (*s) { 873 case 'r': 874 openmode |= JAS_STREAM_READ; 875 break; 876 case 'w': 877 openmode |= JAS_STREAM_WRITE | JAS_STREAM_CREATE; 878 break; 879 case 'b': 880 openmode |= JAS_STREAM_BINARY; 881 break; 882 case 'a': 883 openmode |= JAS_STREAM_APPEND; 884 break; 885 case '+': 886 openmode |= JAS_STREAM_READ | JAS_STREAM_WRITE; 887 break; 888 default: 889 break; 890 } 891 ++s; 892 } 893 return openmode; 894} 895 896int jas_stream_copy(jas_stream_t *out, jas_stream_t *in, int n) 897{ 898 int all; 899 int c; 900 int m; 901 902 all = (n < 0) ? 1 : 0; 903 904 m = n; 905 while (all || m > 0) { 906 if ((c = jas_stream_getc_macro(in)) == EOF) { 907 /* The next character of input could not be read. */ 908 /* Return with an error if an I/O error occured 909 (not including EOF) or if an explicit copy count 910 was specified. */ 911 return (!all || jas_stream_error(in)) ? (-1) : 0; 912 } 913 if (jas_stream_putc_macro(out, c) == EOF) { 914 return -1; 915 } 916 --m; 917 } 918 return 0; 919} 920 921long jas_stream_setrwcount(jas_stream_t *stream, long rwcnt) 922{ 923 int old; 924 925 old = stream->rwcnt_; 926 stream->rwcnt_ = rwcnt; 927 return old; 928} 929 930int jas_stream_display(jas_stream_t *stream, FILE *fp, int n) 931{ 932 unsigned char buf[16]; 933 int i; 934 int j; 935 int m; 936 int c; 937 int display; 938 int cnt; 939 940 cnt = n - (n % 16); 941 display = 1; 942 943 for (i = 0; i < n; i += 16) { 944 if (n > 16 && i > 0) { 945 display = (i >= cnt) ? 1 : 0; 946 } 947 if (display) { 948 fprintf(fp, "%08x:", i); 949 } 950 m = JAS_MIN(n - i, 16); 951 for (j = 0; j < m; ++j) { 952 if ((c = jas_stream_getc(stream)) == EOF) { 953 abort(); 954 return -1; 955 } 956 buf[j] = c; 957 } 958 if (display) { 959 for (j = 0; j < m; ++j) { 960 fprintf(fp, " %02x", buf[j]); 961 } 962 fputc(' ', fp); 963 for (; j < 16; ++j) { 964 fprintf(fp, " "); 965 } 966 for (j = 0; j < m; ++j) { 967 if (isprint(buf[j])) { 968 fputc(buf[j], fp); 969 } else { 970 fputc(' ', fp); 971 } 972 } 973 fprintf(fp, "\n"); 974 } 975 976 977 } 978 return 0; 979} 980 981long jas_stream_length(jas_stream_t *stream) 982{ 983 long oldpos; 984 long pos; 985 if ((oldpos = jas_stream_tell(stream)) < 0) { 986 return -1; 987 } 988 if (jas_stream_seek(stream, 0, SEEK_END) < 0) { 989 return -1; 990 } 991 if ((pos = jas_stream_tell(stream)) < 0) { 992 return -1; 993 } 994 if (jas_stream_seek(stream, oldpos, SEEK_SET) < 0) { 995 return -1; 996 } 997 return pos; 998} 999 1000/******************************************************************************\ 1001* Memory stream object. 1002\******************************************************************************/ 1003 1004static int mem_read(jas_stream_obj_t *obj, char *buf, int cnt) 1005{ 1006 int n; 1007 jas_stream_memobj_t *m = (jas_stream_memobj_t *)obj; 1008 n = m->len_ - m->pos_; 1009 cnt = JAS_MIN(n, cnt); 1010 memcpy(buf, &m->buf_[m->pos_], cnt); 1011 m->pos_ += cnt; 1012 return cnt; 1013} 1014 1015static int mem_resize(jas_stream_memobj_t *m, int bufsize) 1016{ 1017 unsigned char *buf; 1018 1019 assert(m->buf_); 1020 if (!(buf = jas_realloc(m->buf_, bufsize * sizeof(unsigned char)))) { 1021 return -1; 1022 } 1023 m->buf_ = buf; 1024 m->bufsize_ = bufsize; 1025 return 0; 1026} 1027 1028static int mem_write(jas_stream_obj_t *obj, char *buf, int cnt) 1029{ 1030 int n; 1031 int ret; 1032 jas_stream_memobj_t *m = (jas_stream_memobj_t *)obj; 1033 long newbufsize; 1034 long newpos; 1035 1036 newpos = m->pos_ + cnt; 1037 if (newpos > m->bufsize_ && m->growable_) { 1038 newbufsize = m->bufsize_; 1039 while (newbufsize < newpos) { 1040 newbufsize <<= 1; 1041 assert(newbufsize >= 0); 1042 } 1043 if (mem_resize(m, newbufsize)) { 1044 return -1; 1045 } 1046 } 1047 if (m->pos_ > m->len_) { 1048 /* The current position is beyond the end of the file, so 1049 pad the file to the current position with zeros. */ 1050 n = JAS_MIN(m->pos_, m->bufsize_) - m->len_; 1051 if (n > 0) { 1052 memset(&m->buf_[m->len_], 0, n); 1053 m->len_ += n; 1054 } 1055 if (m->pos_ != m->len_) { 1056 /* The buffer is not big enough. */ 1057 return 0; 1058 } 1059 } 1060 n = m->bufsize_ - m->pos_; 1061 ret = JAS_MIN(n, cnt); 1062 if (ret > 0) { 1063 memcpy(&m->buf_[m->pos_], buf, ret); 1064 m->pos_ += ret; 1065 } 1066 if (m->pos_ > m->len_) { 1067 m->len_ = m->pos_; 1068 } 1069assert(ret == cnt); 1070 return ret; 1071} 1072 1073static long mem_seek(jas_stream_obj_t *obj, long offset, int origin) 1074{ 1075 jas_stream_memobj_t *m = (jas_stream_memobj_t *)obj; 1076 long newpos; 1077 1078 switch (origin) { 1079 case SEEK_SET: 1080 newpos = offset; 1081 break; 1082 case SEEK_END: 1083 newpos = m->len_ - offset; 1084 break; 1085 case SEEK_CUR: 1086 newpos = m->pos_ + offset; 1087 break; 1088 default: 1089 abort(); 1090 break; 1091 } 1092 if (newpos < 0) { 1093 return -1; 1094 } 1095 m->pos_ = newpos; 1096 1097 return m->pos_; 1098} 1099 1100static int mem_close(jas_stream_obj_t *obj) 1101{ 1102 jas_stream_memobj_t *m = (jas_stream_memobj_t *)obj; 1103 if (m->myalloc_ && m->buf_) { 1104 jas_free(m->buf_); 1105 m->buf_ = 0; 1106 } 1107 jas_free(obj); 1108 return 0; 1109} 1110 1111/******************************************************************************\ 1112* File stream object. 1113\******************************************************************************/ 1114 1115static int file_read(jas_stream_obj_t *obj, char *buf, int cnt) 1116{ 1117 int fd; 1118 fd = *((int *)obj); 1119 return read(fd, buf, cnt); 1120} 1121 1122static int file_write(jas_stream_obj_t *obj, char *buf, int cnt) 1123{ 1124 int fd; 1125 fd = *((int *)obj); 1126 return write(fd, buf, cnt); 1127} 1128 1129static long file_seek(jas_stream_obj_t *obj, long offset, int origin) 1130{ 1131 int fd; 1132 fd = *((int *)obj); 1133 return lseek(fd, offset, origin); 1134} 1135 1136static int file_close(jas_stream_obj_t *obj) 1137{ 1138 int fd; 1139 fd = *((int *)obj); 1140 jas_free(obj); 1141 return close(fd); 1142} 1143 1144/******************************************************************************\ 1145* Stdio file stream object. 1146\******************************************************************************/ 1147 1148static int sfile_read(jas_stream_obj_t *obj, char *buf, int cnt) 1149{ 1150 FILE *fp; 1151 fp = JAS_CAST(FILE *, obj); 1152 return fread(buf, 1, cnt, fp); 1153} 1154 1155static int sfile_write(jas_stream_obj_t *obj, char *buf, int cnt) 1156{ 1157 FILE *fp; 1158 fp = JAS_CAST(FILE *, obj); 1159 return fwrite(buf, 1, cnt, fp); 1160} 1161 1162static long sfile_seek(jas_stream_obj_t *obj, long offset, int origin) 1163{ 1164 FILE *fp; 1165 fp = JAS_CAST(FILE *, obj); 1166 return fseek(fp, offset, origin); 1167} 1168 1169static int sfile_close(jas_stream_obj_t *obj) 1170{ 1171 FILE *fp; 1172 fp = JAS_CAST(FILE *, obj); 1173 return fclose(fp); 1174} 1175