1/* $Id: tif_stream.cxx,v 1.6.2.1 2009-01-01 00:10:43 bfriesen Exp $ */ 2 3/* 4 * Copyright (c) 1988-1996 Sam Leffler 5 * Copyright (c) 1991-1996 Silicon Graphics, Inc. 6 * 7 * Permission to use, copy, modify, distribute, and sell this software and 8 * its documentation for any purpose is hereby granted without fee, provided 9 * that (i) the above copyright notices and this permission notice appear in 10 * all copies of the software and related documentation, and (ii) the names of 11 * Sam Leffler and Silicon Graphics may not be used in any advertising or 12 * publicity relating to the software without the specific, prior written 13 * permission of Sam Leffler and Silicon Graphics. 14 * 15 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 16 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 17 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. 18 * 19 * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR 20 * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, 21 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 22 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 23 * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 24 * OF THIS SOFTWARE. 25 */ 26 27/* 28 * TIFF Library UNIX-specific Routines. 29 */ 30#include "tiffiop.h" 31#include <iostream> 32 33#ifndef __VMS 34using namespace std; 35#endif 36 37class tiffis_data 38{ 39 public: 40 41 istream *myIS; 42 long myStreamStartPos; 43}; 44 45class tiffos_data 46{ 47 public: 48 49 ostream *myOS; 50 long myStreamStartPos; 51}; 52 53static tsize_t 54_tiffosReadProc(thandle_t, tdata_t, tsize_t) 55{ 56 return 0; 57} 58 59static tsize_t 60_tiffisReadProc(thandle_t fd, tdata_t buf, tsize_t size) 61{ 62 tiffis_data *data = (tiffis_data *)fd; 63 64 data->myIS->read((char *)buf, (int)size); 65 66 return data->myIS->gcount(); 67} 68 69static tsize_t 70_tiffosWriteProc(thandle_t fd, tdata_t buf, tsize_t size) 71{ 72 tiffos_data *data = (tiffos_data *)fd; 73 ostream *os = data->myOS; 74 int pos = os->tellp(); 75 76 os->write((const char *)buf, size); 77 78 return ((int)os->tellp()) - pos; 79} 80 81static tsize_t 82_tiffisWriteProc(thandle_t, tdata_t, tsize_t) 83{ 84 return 0; 85} 86 87static toff_t 88_tiffosSeekProc(thandle_t fd, toff_t off, int whence) 89{ 90 tiffos_data *data = (tiffos_data *)fd; 91 ostream *os = data->myOS; 92 93 // if the stream has already failed, don't do anything 94 if( os->fail() ) 95 return os->tellp(); 96 97 switch(whence) { 98 case SEEK_SET: 99 os->seekp(data->myStreamStartPos + off, ios::beg); 100 break; 101 case SEEK_CUR: 102 os->seekp(off, ios::cur); 103 break; 104 case SEEK_END: 105 os->seekp(off, ios::end); 106 break; 107 } 108 109 // Attempt to workaround problems with seeking past the end of the 110 // stream. ofstream doesn't have a problem with this but 111 // ostrstream/ostringstream does. In that situation, add intermediate 112 // '\0' characters. 113 if( os->fail() ) { 114#ifdef __VMS 115 int old_state; 116#else 117 ios::iostate old_state; 118#endif 119 toff_t origin=0; 120 121 old_state = os->rdstate(); 122 // reset the fail bit or else tellp() won't work below 123 os->clear(os->rdstate() & ~ios::failbit); 124 switch( whence ) { 125 case SEEK_SET: 126 origin = data->myStreamStartPos; 127 break; 128 case SEEK_CUR: 129 origin = os->tellp(); 130 break; 131 case SEEK_END: 132 os->seekp(0, ios::end); 133 origin = os->tellp(); 134 break; 135 } 136 // restore original stream state 137 os->clear(old_state); 138 139 // only do something if desired seek position is valid 140 if( origin + off > data->myStreamStartPos ) { 141 toff_t num_fill; 142 143 // clear the fail bit 144 os->clear(os->rdstate() & ~ios::failbit); 145 146 // extend the stream to the expected size 147 os->seekp(0, ios::end); 148 num_fill = origin + off - (toff_t)os->tellp(); 149 for( toff_t i = 0; i < num_fill; i++ ) 150 os->put('\0'); 151 152 // retry the seek 153 os->seekp(origin + off, ios::beg); 154 } 155 } 156 157 return os->tellp(); 158} 159 160static toff_t 161_tiffisSeekProc(thandle_t fd, toff_t off, int whence) 162{ 163 tiffis_data *data = (tiffis_data *)fd; 164 165 switch(whence) { 166 case SEEK_SET: 167 data->myIS->seekg(data->myStreamStartPos + off, ios::beg); 168 break; 169 case SEEK_CUR: 170 data->myIS->seekg(off, ios::cur); 171 break; 172 case SEEK_END: 173 data->myIS->seekg(off, ios::end); 174 break; 175 } 176 177 return ((long)data->myIS->tellg()) - data->myStreamStartPos; 178} 179 180static toff_t 181_tiffosSizeProc(thandle_t fd) 182{ 183 tiffos_data *data = (tiffos_data *)fd; 184 ostream *os = data->myOS; 185 toff_t pos = os->tellp(); 186 toff_t len; 187 188 os->seekp(0, ios::end); 189 len = os->tellp(); 190 os->seekp(pos); 191 192 return len; 193} 194 195static toff_t 196_tiffisSizeProc(thandle_t fd) 197{ 198 tiffis_data *data = (tiffis_data *)fd; 199 int pos = data->myIS->tellg(); 200 int len; 201 202 data->myIS->seekg(0, ios::end); 203 len = data->myIS->tellg(); 204 data->myIS->seekg(pos); 205 206 return len; 207} 208 209static int 210_tiffosCloseProc(thandle_t fd) 211{ 212 // Our stream was not allocated by us, so it shouldn't be closed by us. 213 delete (tiffos_data *)fd; 214 return 0; 215} 216 217static int 218_tiffisCloseProc(thandle_t fd) 219{ 220 // Our stream was not allocated by us, so it shouldn't be closed by us. 221 delete (tiffis_data *)fd; 222 return 0; 223} 224 225static int 226_tiffDummyMapProc(thandle_t , tdata_t* , toff_t* ) 227{ 228 return (0); 229} 230 231static void 232_tiffDummyUnmapProc(thandle_t , tdata_t , toff_t ) 233{ 234} 235 236/* 237 * Open a TIFF file descriptor for read/writing. 238 */ 239static TIFF* 240_tiffStreamOpen(const char* name, const char* mode, void *fd) 241{ 242 TIFF* tif; 243 244 if( strchr(mode, 'w') ) { 245 tiffos_data *data = new tiffos_data; 246 data->myOS = (ostream *)fd; 247 data->myStreamStartPos = data->myOS->tellp(); 248 249 // Open for writing. 250 tif = TIFFClientOpen(name, mode, 251 (thandle_t) data, 252 _tiffosReadProc, _tiffosWriteProc, 253 _tiffosSeekProc, _tiffosCloseProc, 254 _tiffosSizeProc, 255 _tiffDummyMapProc, _tiffDummyUnmapProc); 256 } else { 257 tiffis_data *data = new tiffis_data; 258 data->myIS = (istream *)fd; 259 data->myStreamStartPos = data->myIS->tellg(); 260 // Open for reading. 261 tif = TIFFClientOpen(name, mode, 262 (thandle_t) data, 263 _tiffisReadProc, _tiffisWriteProc, 264 _tiffisSeekProc, _tiffisCloseProc, 265 _tiffisSizeProc, 266 _tiffDummyMapProc, _tiffDummyUnmapProc); 267 } 268 269 return (tif); 270} 271 272TIFF* 273TIFFStreamOpen(const char* name, ostream *os) 274{ 275 // If os is either a ostrstream or ostringstream, and has no data 276 // written to it yet, then tellp() will return -1 which will break us. 277 // We workaround this by writing out a dummy character and 278 // then seek back to the beginning. 279 if( !os->fail() && (int)os->tellp() < 0 ) { 280 *os << '\0'; 281 os->seekp(0); 282 } 283 284 // NB: We don't support mapped files with streams so add 'm' 285 return _tiffStreamOpen(name, "wm", os); 286} 287 288TIFF* 289TIFFStreamOpen(const char* name, istream *is) 290{ 291 // NB: We don't support mapped files with streams so add 'm' 292 return _tiffStreamOpen(name, "rm", is); 293} 294 295/* vim: set ts=8 sts=8 sw=8 noet: */ 296