/* * Copyright (c) 1999-2000 Image Power, Inc. and the University of * British Columbia. * Copyright (c) 2001-2003 Michael David Adams. * All rights reserved. */ /* __START_OF_JASPER_LICENSE__ * * JasPer License Version 2.0 * * Copyright (c) 2001-2006 Michael David Adams * Copyright (c) 1999-2000 Image Power, Inc. * Copyright (c) 1999-2000 The University of British Columbia * * All rights reserved. * * Permission is hereby granted, free of charge, to any person (the * "User") obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, and/or sell copies of the Software, and to permit * persons to whom the Software is furnished to do so, subject to the * following conditions: * * 1. The above copyright notices and this permission notice (which * includes the disclaimer below) shall be included in all copies or * substantial portions of the Software. * * 2. The name of a copyright holder shall not be used to endorse or * promote products derived from the Software without specific prior * written permission. * * THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS * LICENSE. NO USE OF THE SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER * THIS DISCLAIMER. THE SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS * "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. NO ASSURANCES ARE * PROVIDED BY THE COPYRIGHT HOLDERS THAT THE SOFTWARE DOES NOT INFRINGE * THE PATENT OR OTHER INTELLECTUAL PROPERTY RIGHTS OF ANY OTHER ENTITY. * EACH COPYRIGHT HOLDER DISCLAIMS ANY LIABILITY TO THE USER FOR CLAIMS * BROUGHT BY ANY OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL * PROPERTY RIGHTS OR OTHERWISE. AS A CONDITION TO EXERCISING THE RIGHTS * GRANTED HEREUNDER, EACH USER HEREBY ASSUMES SOLE RESPONSIBILITY TO SECURE * ANY OTHER INTELLECTUAL PROPERTY RIGHTS NEEDED, IF ANY. THE SOFTWARE * IS NOT FAULT-TOLERANT AND IS NOT INTENDED FOR USE IN MISSION-CRITICAL * SYSTEMS, SUCH AS THOSE USED IN THE OPERATION OF NUCLEAR FACILITIES, * AIRCRAFT NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL * SYSTEMS, DIRECT LIFE SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH * THE FAILURE OF THE SOFTWARE OR SYSTEM COULD LEAD DIRECTLY TO DEATH, * PERSONAL INJURY, OR SEVERE PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH * RISK ACTIVITIES"). THE COPYRIGHT HOLDERS SPECIFICALLY DISCLAIM ANY * EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR HIGH RISK ACTIVITIES. * * __END_OF_JASPER_LICENSE__ */ /* * I/O Stream Library * * $Id$ */ /******************************************************************************\* Includes.\******************************************************************************/ #include "jasper/jas_config.h" /* The following must come before any direct/indirect inclusion of stdlib.h. */#if defined(JAS_HAVE_MKOSTEMP)#define _GNU_SOURCE#endif #define JAS_FOR_INTERNAL_USE_ONLY #include "jasper/jas_stream.h"#include "jasper/jas_debug.h"#include "jasper/jas_types.h"#include "jasper/jas_malloc.h"#include "jasper/jas_math.h" /*O_CLOEXEC is a Linux-specific flag which helps avoid leaking file descriptorsto child processes created by another thread; for simplicity, we alwaysspecify it, and this definition is a fallback for systems where this featureis not available*/#ifndef O_CLOEXEC#define O_CLOEXEC 0#endif /******************************************************************************\* Local function prototypes.\******************************************************************************/ static int jas_strtoopenmode(const char *s);static void jas_stream_destroy(jas_stream_t *stream);static jas_stream_t *jas_stream_create(void);static void jas_stream_initbuf(jas_stream_t *stream, int bufmode, char *buf, int bufsize); static ssize_t mem_read(jas_stream_obj_t *obj, char *buf, size_t cnt);static ssize_t mem_write(jas_stream_obj_t *obj, const char *buf, size_t cnt);static long mem_seek(jas_stream_obj_t *obj, long offset, int origin);static int mem_close(jas_stream_obj_t *obj); static ssize_t sfile_read(jas_stream_obj_t *obj, char *buf, size_t cnt);static ssize_t sfile_write(jas_stream_obj_t *obj, const char *buf, size_t cnt);static long sfile_seek(jas_stream_obj_t *obj, long offset, int origin);static int sfile_close(jas_stream_obj_t *obj); static ssize_t file_read(jas_stream_obj_t *obj, char *buf, size_t cnt);static ssize_t file_write(jas_stream_obj_t *obj, const char *buf, size_t cnt);static long file_seek(jas_stream_obj_t *obj, long offset, int origin);static int file_close(jas_stream_obj_t *obj); /******************************************************************************\* Local data.\******************************************************************************/ static const jas_stream_ops_t jas_stream_fileops = { file_read, file_write, file_seek, file_close}; static const jas_stream_ops_t jas_stream_sfileops = { sfile_read, sfile_write, sfile_seek, sfile_close}; static const jas_stream_ops_t jas_stream_memops = { mem_read, mem_write, mem_seek, mem_close}; /******************************************************************************\* Code for opening and closing streams.\******************************************************************************/ static jas_stream_t *jas_stream_create(){ jas_stream_t *stream; if (!(stream = jas_malloc(sizeof(jas_stream_t)))) { return 0; } stream->openmode_ = 0; stream->bufmode_ = 0; stream->flags_ = 0; stream->bufbase_ = 0; stream->bufstart_ = 0; stream->bufsize_ = 0; stream->ptr_ = 0; stream->cnt_ = 0; stream->ops_ = 0; stream->obj_ = 0; stream->rwcnt_ = 0; stream->rwlimit_ = -1; return stream;} jas_stream_t *jas_stream_memopen(char *buf, size_t bufsize){ jas_stream_t *stream; jas_stream_memobj_t *obj; JAS_LOGDEBUGF(100, "jas_stream_memopen(%p, %zu)\n", buf, bufsize); assert((buf && bufsize > 0) || (!buf)); if (!(stream = jas_stream_create())) { return 0; } /* A stream associated with a memory buffer is always opened for both reading and writing in binary mode. */ stream->openmode_ = JAS_STREAM_READ | JAS_STREAM_WRITE | JAS_STREAM_BINARY; /* Since the stream data is already resident in memory, buffering is not necessary. */ jas_stream_initbuf(stream, JAS_STREAM_UNBUF, 0, 0); /* Select the operations for a memory stream. */ stream->ops_ = &jas_stream_memops; /* Allocate memory for the underlying memory stream object. */ if (!(obj = jas_malloc(sizeof(jas_stream_memobj_t)))) { jas_stream_destroy(stream); return 0; } stream->obj_ = (void *) obj; /* Initialize a few important members of the memory stream object. */ obj->myalloc_ = 0; obj->buf_ = 0; /* If the buffer size specified is nonpositive, then the buffer is allocated internally and automatically grown as needed. */ if (!bufsize) { obj->bufsize_ = 1024; obj->growable_ = 1; } else { obj->bufsize_ = bufsize; obj->growable_ = 0; } if (buf) { obj->buf_ = JAS_CAST(unsigned char *, buf); } else { obj->buf_ = jas_malloc(obj->bufsize_); obj->myalloc_ = 1; } if (!obj->buf_) { jas_stream_close(stream); return 0; } JAS_LOGDEBUGF(100, "jas_stream_memopen buffer buf=%p myalloc=%d\n", obj->buf_, obj->myalloc_); if (bufsize > 0 && buf) { /* If a buffer was supplied by the caller and its length is positive, make the associated buffer data appear in the stream initially. */ obj->len_ = bufsize; } else { /* The stream is initially empty. */ obj->len_ = 0; } obj->pos_ = 0; return stream;} /*This function is deprecated.It will be removed eventually.*/jas_stream_t *jas_stream_memopen2(char *buf, size_t bufsize){ jas_deprecated("jas_stream_memopen2 is deprecated\n"); return jas_stream_memopen(buf, bufsize);} jas_stream_t *jas_stream_fopen(const char *filename, const char *mode){ jas_stream_t *stream; jas_stream_fileobj_t *obj; int openflags; JAS_LOGDEBUGF(100, "jas_stream_fopen(\"%s\", \"%s\")\n", filename, mode); /* Allocate a stream object. */ if (!(stream = jas_stream_create())) { return 0; } /* Parse the mode string. */ stream->openmode_ = jas_strtoopenmode(mode); /* Determine the correct flags to use for opening the file. */ if ((stream->openmode_ & JAS_STREAM_READ) && (stream->openmode_ & JAS_STREAM_WRITE)) { openflags = O_RDWR; } else if (stream->openmode_ & JAS_STREAM_READ) { openflags = O_RDONLY; } else if (stream->openmode_ & JAS_STREAM_WRITE) { openflags = O_WRONLY; } else { openflags = 0; } if (stream->openmode_ & JAS_STREAM_APPEND) { openflags |= O_APPEND; } if (stream->openmode_ & JAS_STREAM_BINARY) { openflags |= O_BINARY; } if (stream->openmode_ & JAS_STREAM_CREATE) { openflags |= O_CREAT | O_TRUNC; } openflags |= O_CLOEXEC; /* Allocate space for the underlying file stream object. */ if (!(obj = jas_malloc(sizeof(jas_stream_fileobj_t)))) { jas_stream_destroy(stream); return 0; } obj->fd = -1; obj->flags = 0; obj->pathname[0] = '\0'; stream->obj_ = (void *) obj; /* Select the operations for a file stream object. */ stream->ops_ = &jas_stream_fileops; /* Open the underlying file. */ if ((obj->fd = open(filename, openflags/*, JAS_STREAM_PERMS*/)) < 0) { // Free the underlying file object, since it will not otherwise // be freed. jas_free(obj); jas_stream_destroy(stream); return 0; } /* By default, use full buffering for this type of stream. */ jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0); return stream;} jas_stream_t *jas_stream_freopen(const char *path, const char *mode, FILE *fp){ jas_stream_t *stream; JAS_LOGDEBUGF(100, "jas_stream_freopen(\"%s\", \"%s\", %p)\n", path, mode, fp); JAS_UNUSED(path); /* Allocate a stream object. */ if (!(stream = jas_stream_create())) { return 0; } /* Parse the mode string. */ stream->openmode_ = jas_strtoopenmode(mode); stream->obj_ = JAS_CAST(void *, fp); /* Select the operations for a file stream object. */ stream->ops_ = &jas_stream_sfileops; /* By default, use full buffering for this type of stream. */ jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0); return stream;} #ifndef _WIN32 /** * Copy the absolute path of the directory for temporary files to the * given buffer (without a null terminator), including a trailing path * separator. * * @return the number of characters copied to the buffer or 0 on error */static size_t get_temp_directory(char *buffer, size_t size){ const char *tmpdir = getenv("TMPDIR"); if (tmpdir == NULL) { tmpdir = "/tmp"; } size_t length = strlen(tmpdir); if (length + 1 > size) { return 0; } memcpy(buffer, tmpdir, length); buffer[length++] = '/'; return length;} #endif /* !_WIN32 */ /** * Generate a template for mkstemp(). * * @return 0 on success, -1 on error */static int make_mkstemp_template(char *buffer, size_t size){#ifdef _WIN32 char temp_directory[MAX_PATH]; if (GetTempPathA(sizeof(temp_directory), temp_directory) == 0) { return -1; } JAS_UNUSED(size); return GetTempFileNameA(temp_directory, "jasper", 0, buffer) > 0 ? 0 : -1;#else static const char base[] = "jasper.XXXXXX"; size_t length = get_temp_directory(buffer, size); if (length == 0 || length + sizeof(base) >= size) { return -1; } memcpy(buffer + length, base, sizeof(base)); return 0;#endif} /** * A wrapper for mkstemp() which generates a template for mkstemp() * before calling the function. * * @return a non-negative file descriptor on success, -1 on error */static int easy_mkstemp(char *buffer, size_t size){ JAS_UNUSED(buffer); JAS_UNUSED(size); return -1;} jas_stream_t *jas_stream_tmpfile(){ jas_stream_t *stream; jas_stream_fileobj_t *obj; JAS_LOGDEBUGF(100, "jas_stream_tmpfile()\n"); if (!(stream = jas_stream_create())) { return 0; } /* A temporary file stream is always opened for both reading and writing in binary mode. */ stream->openmode_ = JAS_STREAM_READ | JAS_STREAM_WRITE | JAS_STREAM_BINARY; /* Allocate memory for the underlying temporary file object. */ if (!(obj = jas_malloc(sizeof(jas_stream_fileobj_t)))) { jas_stream_destroy(stream); return 0; } obj->fd = -1; obj->flags = 0; obj->pathname[0] = '\0'; stream->obj_ = obj; /* Create the temporary file. */ if ((obj->fd = easy_mkstemp(obj->pathname, sizeof(obj->pathname))) < 0) { jas_stream_destroy(stream); return 0; } /* Unlink the file so that it will disappear if the program terminates abnormally. */ /* Under UNIX, one can unlink an open file and continue to do I/O on it. Not all operating systems support this functionality, however. For example, under Microsoft Windows the unlink operation will fail, since the file is open. */ if (*obj->pathname != 0 && unlink(obj->pathname) < 0) { /* We will try unlinking the file again after it is closed. */ obj->flags |= JAS_STREAM_FILEOBJ_DELONCLOSE; } /* Use full buffering. */ jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0); stream->ops_ = &jas_stream_fileops; return stream;} jas_stream_t *jas_stream_fdopen(int fd, const char *mode){ jas_stream_t *stream; jas_stream_fileobj_t *obj; JAS_LOGDEBUGF(100, "jas_stream_fdopen(%d, \"%s\")\n", fd, mode); /* Allocate a stream object. */ if (!(stream = jas_stream_create())) { return 0; } /* Parse the mode string. */ stream->openmode_ = jas_strtoopenmode(mode); #if defined(_WIN32) || defined(JAS_HAVE_IO_H) /* Argh!!! Someone ought to banish text mode (i.e., O_TEXT) to the greatest depths of purgatory! */ /* Ensure that the file descriptor is in binary mode, if the caller has specified the binary mode flag. Arguably, the caller ought to take care of this, but text mode is a ugly wart anyways, so we save the caller some grief by handling this within the stream library. */ /* This ugliness is mainly for the benefit of those who run the JasPer software under Windows from shells that insist on opening files in text mode. For example, in the Cygwin environment, shells often open files in text mode when I/O redirection is used. Grr... */ if (stream->openmode_ & JAS_STREAM_BINARY) { setmode(fd, O_BINARY); }#endifLines 1–500 of 1415. Load more
/* * Copyright (c) 1999-2000 Image Power, Inc. and the University of * British Columbia. * Copyright (c) 2001-2003 Michael David Adams. * All rights reserved. */ /* __START_OF_JASPER_LICENSE__ * * JasPer License Version 2.0 * * Copyright (c) 2001-2006 Michael David Adams * Copyright (c) 1999-2000 Image Power, Inc. * Copyright (c) 1999-2000 The University of British Columbia * * All rights reserved. * * Permission is hereby granted, free of charge, to any person (the * "User") obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, and/or sell copies of the Software, and to permit * persons to whom the Software is furnished to do so, subject to the * following conditions: * * 1. The above copyright notices and this permission notice (which * includes the disclaimer below) shall be included in all copies or * substantial portions of the Software. * * 2. The name of a copyright holder shall not be used to endorse or * promote products derived from the Software without specific prior * written permission. * * THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS * LICENSE. NO USE OF THE SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER * THIS DISCLAIMER. THE SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS * "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. NO ASSURANCES ARE * PROVIDED BY THE COPYRIGHT HOLDERS THAT THE SOFTWARE DOES NOT INFRINGE * THE PATENT OR OTHER INTELLECTUAL PROPERTY RIGHTS OF ANY OTHER ENTITY. * EACH COPYRIGHT HOLDER DISCLAIMS ANY LIABILITY TO THE USER FOR CLAIMS * BROUGHT BY ANY OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL * PROPERTY RIGHTS OR OTHERWISE. AS A CONDITION TO EXERCISING THE RIGHTS * GRANTED HEREUNDER, EACH USER HEREBY ASSUMES SOLE RESPONSIBILITY TO SECURE * ANY OTHER INTELLECTUAL PROPERTY RIGHTS NEEDED, IF ANY. THE SOFTWARE * IS NOT FAULT-TOLERANT AND IS NOT INTENDED FOR USE IN MISSION-CRITICAL * SYSTEMS, SUCH AS THOSE USED IN THE OPERATION OF NUCLEAR FACILITIES, * AIRCRAFT NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL * SYSTEMS, DIRECT LIFE SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH * THE FAILURE OF THE SOFTWARE OR SYSTEM COULD LEAD DIRECTLY TO DEATH, * PERSONAL INJURY, OR SEVERE PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH * RISK ACTIVITIES"). THE COPYRIGHT HOLDERS SPECIFICALLY DISCLAIM ANY * EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR HIGH RISK ACTIVITIES. * * __END_OF_JASPER_LICENSE__ */ /* * I/O Stream Library * * $Id$ */ /******************************************************************************\ * Includes. \******************************************************************************/ #include "jasper/jas_config.h" /* The following must come before any direct/indirect inclusion of stdlib.h. */ #if defined(JAS_HAVE_MKOSTEMP) #define _GNU_SOURCE #endif #define JAS_FOR_INTERNAL_USE_ONLY #include "jasper/jas_stream.h" #include "jasper/jas_debug.h" #include "jasper/jas_types.h" #include "jasper/jas_malloc.h" #include "jasper/jas_math.h" /* O_CLOEXEC is a Linux-specific flag which helps avoid leaking file descriptors to child processes created by another thread; for simplicity, we always specify it, and this definition is a fallback for systems where this feature is not available */ #ifndef O_CLOEXEC #define O_CLOEXEC 0 #endif /******************************************************************************\ * Local function prototypes. \******************************************************************************/ static int jas_strtoopenmode(const char *s); static void jas_stream_destroy(jas_stream_t *stream); static jas_stream_t *jas_stream_create(void); static void jas_stream_initbuf(jas_stream_t *stream, int bufmode, char *buf, int bufsize); static ssize_t mem_read(jas_stream_obj_t *obj, char *buf, size_t cnt); static ssize_t mem_write(jas_stream_obj_t *obj, const char *buf, size_t cnt); static long mem_seek(jas_stream_obj_t *obj, long offset, int origin); static int mem_close(jas_stream_obj_t *obj); static ssize_t sfile_read(jas_stream_obj_t *obj, char *buf, size_t cnt); static ssize_t sfile_write(jas_stream_obj_t *obj, const char *buf, size_t cnt); static long sfile_seek(jas_stream_obj_t *obj, long offset, int origin); static int sfile_close(jas_stream_obj_t *obj); static ssize_t file_read(jas_stream_obj_t *obj, char *buf, size_t cnt); static ssize_t file_write(jas_stream_obj_t *obj, const char *buf, size_t cnt); static long file_seek(jas_stream_obj_t *obj, long offset, int origin); static int file_close(jas_stream_obj_t *obj); /******************************************************************************\ * Local data. \******************************************************************************/ static const jas_stream_ops_t jas_stream_fileops = { file_read, file_write, file_seek, file_close }; static const jas_stream_ops_t jas_stream_sfileops = { sfile_read, sfile_write, sfile_seek, sfile_close }; static const jas_stream_ops_t jas_stream_memops = { mem_read, mem_write, mem_seek, mem_close }; /******************************************************************************\ * Code for opening and closing streams. \******************************************************************************/ static jas_stream_t *jas_stream_create() { jas_stream_t *stream; if (!(stream = jas_malloc(sizeof(jas_stream_t)))) { return 0; } stream->openmode_ = 0; stream->bufmode_ = 0; stream->flags_ = 0; stream->bufbase_ = 0; stream->bufstart_ = 0; stream->bufsize_ = 0; stream->ptr_ = 0; stream->cnt_ = 0; stream->ops_ = 0; stream->obj_ = 0; stream->rwcnt_ = 0; stream->rwlimit_ = -1; return stream; } jas_stream_t *jas_stream_memopen(char *buf, size_t bufsize) { jas_stream_t *stream; jas_stream_memobj_t *obj; JAS_LOGDEBUGF(100, "jas_stream_memopen(%p, %zu)\n", buf, bufsize); assert((buf && bufsize > 0) || (!buf)); if (!(stream = jas_stream_create())) { return 0; } /* A stream associated with a memory buffer is always opened for both reading and writing in binary mode. */ stream->openmode_ = JAS_STREAM_READ | JAS_STREAM_WRITE | JAS_STREAM_BINARY; /* Since the stream data is already resident in memory, buffering is not necessary. */ jas_stream_initbuf(stream, JAS_STREAM_UNBUF, 0, 0); /* Select the operations for a memory stream. */ stream->ops_ = &jas_stream_memops; /* Allocate memory for the underlying memory stream object. */ if (!(obj = jas_malloc(sizeof(jas_stream_memobj_t)))) { jas_stream_destroy(stream); return 0; } stream->obj_ = (void *) obj; /* Initialize a few important members of the memory stream object. */ obj->myalloc_ = 0; obj->buf_ = 0; /* If the buffer size specified is nonpositive, then the buffer is allocated internally and automatically grown as needed. */ if (!bufsize) { obj->bufsize_ = 1024; obj->growable_ = 1; } else { obj->bufsize_ = bufsize; obj->growable_ = 0; } if (buf) { obj->buf_ = JAS_CAST(unsigned char *, buf); } else { obj->buf_ = jas_malloc(obj->bufsize_); obj->myalloc_ = 1; } if (!obj->buf_) { jas_stream_close(stream); return 0; } JAS_LOGDEBUGF(100, "jas_stream_memopen buffer buf=%p myalloc=%d\n", obj->buf_, obj->myalloc_); if (bufsize > 0 && buf) { /* If a buffer was supplied by the caller and its length is positive, make the associated buffer data appear in the stream initially. */ obj->len_ = bufsize; } else { /* The stream is initially empty. */ obj->len_ = 0; } obj->pos_ = 0; return stream; } /* This function is deprecated. It will be removed eventually. */ jas_stream_t *jas_stream_memopen2(char *buf, size_t bufsize) { jas_deprecated("jas_stream_memopen2 is deprecated\n"); return jas_stream_memopen(buf, bufsize); } jas_stream_t *jas_stream_fopen(const char *filename, const char *mode) { jas_stream_t *stream; jas_stream_fileobj_t *obj; int openflags; JAS_LOGDEBUGF(100, "jas_stream_fopen(\"%s\", \"%s\")\n", filename, mode); /* Allocate a stream object. */ if (!(stream = jas_stream_create())) { return 0; } /* Parse the mode string. */ stream->openmode_ = jas_strtoopenmode(mode); /* Determine the correct flags to use for opening the file. */ if ((stream->openmode_ & JAS_STREAM_READ) && (stream->openmode_ & JAS_STREAM_WRITE)) { openflags = O_RDWR; } else if (stream->openmode_ & JAS_STREAM_READ) { openflags = O_RDONLY; } else if (stream->openmode_ & JAS_STREAM_WRITE) { openflags = O_WRONLY; } else { openflags = 0; } if (stream->openmode_ & JAS_STREAM_APPEND) { openflags |= O_APPEND; } if (stream->openmode_ & JAS_STREAM_BINARY) { openflags |= O_BINARY; } if (stream->openmode_ & JAS_STREAM_CREATE) { openflags |= O_CREAT | O_TRUNC; } openflags |= O_CLOEXEC; /* Allocate space for the underlying file stream object. */ if (!(obj = jas_malloc(sizeof(jas_stream_fileobj_t)))) { jas_stream_destroy(stream); return 0; } obj->fd = -1; obj->flags = 0; obj->pathname[0] = '\0'; stream->obj_ = (void *) obj; /* Select the operations for a file stream object. */ stream->ops_ = &jas_stream_fileops; /* Open the underlying file. */ if ((obj->fd = open(filename, openflags/*, JAS_STREAM_PERMS*/)) < 0) { // Free the underlying file object, since it will not otherwise // be freed. jas_free(obj); jas_stream_destroy(stream); return 0; } /* By default, use full buffering for this type of stream. */ jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0); return stream; } jas_stream_t *jas_stream_freopen(const char *path, const char *mode, FILE *fp) { jas_stream_t *stream; JAS_LOGDEBUGF(100, "jas_stream_freopen(\"%s\", \"%s\", %p)\n", path, mode, fp); JAS_UNUSED(path); /* Allocate a stream object. */ if (!(stream = jas_stream_create())) { return 0; } /* Parse the mode string. */ stream->openmode_ = jas_strtoopenmode(mode); stream->obj_ = JAS_CAST(void *, fp); /* Select the operations for a file stream object. */ stream->ops_ = &jas_stream_sfileops; /* By default, use full buffering for this type of stream. */ jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0); return stream; } #ifndef _WIN32 /** * Copy the absolute path of the directory for temporary files to the * given buffer (without a null terminator), including a trailing path * separator. * * @return the number of characters copied to the buffer or 0 on error */ static size_t get_temp_directory(char *buffer, size_t size) { const char *tmpdir = getenv("TMPDIR"); if (tmpdir == NULL) { tmpdir = "/tmp"; } size_t length = strlen(tmpdir); if (length + 1 > size) { return 0; } memcpy(buffer, tmpdir, length); buffer[length++] = '/'; return length; } #endif /* !_WIN32 */ /** * Generate a template for mkstemp(). * * @return 0 on success, -1 on error */ static int make_mkstemp_template(char *buffer, size_t size) { #ifdef _WIN32 char temp_directory[MAX_PATH]; if (GetTempPathA(sizeof(temp_directory), temp_directory) == 0) { return -1; } JAS_UNUSED(size); return GetTempFileNameA(temp_directory, "jasper", 0, buffer) > 0 ? 0 : -1; #else static const char base[] = "jasper.XXXXXX"; size_t length = get_temp_directory(buffer, size); if (length == 0 || length + sizeof(base) >= size) { return -1; } memcpy(buffer + length, base, sizeof(base)); return 0; #endif } /** * A wrapper for mkstemp() which generates a template for mkstemp() * before calling the function. * * @return a non-negative file descriptor on success, -1 on error */ static int easy_mkstemp(char *buffer, size_t size) { JAS_UNUSED(buffer); JAS_UNUSED(size); return -1; } jas_stream_t *jas_stream_tmpfile() { jas_stream_t *stream; jas_stream_fileobj_t *obj; JAS_LOGDEBUGF(100, "jas_stream_tmpfile()\n"); if (!(stream = jas_stream_create())) { return 0; } /* A temporary file stream is always opened for both reading and writing in binary mode. */ stream->openmode_ = JAS_STREAM_READ | JAS_STREAM_WRITE | JAS_STREAM_BINARY; /* Allocate memory for the underlying temporary file object. */ if (!(obj = jas_malloc(sizeof(jas_stream_fileobj_t)))) { jas_stream_destroy(stream); return 0; } obj->fd = -1; obj->flags = 0; obj->pathname[0] = '\0'; stream->obj_ = obj; /* Create the temporary file. */ if ((obj->fd = easy_mkstemp(obj->pathname, sizeof(obj->pathname))) < 0) { jas_stream_destroy(stream); return 0; } /* Unlink the file so that it will disappear if the program terminates abnormally. */ /* Under UNIX, one can unlink an open file and continue to do I/O on it. Not all operating systems support this functionality, however. For example, under Microsoft Windows the unlink operation will fail, since the file is open. */ if (*obj->pathname != 0 && unlink(obj->pathname) < 0) { /* We will try unlinking the file again after it is closed. */ obj->flags |= JAS_STREAM_FILEOBJ_DELONCLOSE; } /* Use full buffering. */ jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0); stream->ops_ = &jas_stream_fileops; return stream; } jas_stream_t *jas_stream_fdopen(int fd, const char *mode) { jas_stream_t *stream; jas_stream_fileobj_t *obj; JAS_LOGDEBUGF(100, "jas_stream_fdopen(%d, \"%s\")\n", fd, mode); /* Allocate a stream object. */ if (!(stream = jas_stream_create())) { return 0; } /* Parse the mode string. */ stream->openmode_ = jas_strtoopenmode(mode); #if defined(_WIN32) || defined(JAS_HAVE_IO_H) /* Argh!!! Someone ought to banish text mode (i.e., O_TEXT) to the greatest depths of purgatory! */ /* Ensure that the file descriptor is in binary mode, if the caller has specified the binary mode flag. Arguably, the caller ought to take care of this, but text mode is a ugly wart anyways, so we save the caller some grief by handling this within the stream library. */ /* This ugliness is mainly for the benefit of those who run the JasPer software under Windows from shells that insist on opening files in text mode. For example, in the Cygwin environment, shells often open files in text mode when I/O redirection is used. Grr... */ if (stream->openmode_ & JAS_STREAM_BINARY) { setmode(fd, O_BINARY); } #endif