1 /* 2 * Copyright (c) 1988-1996 Sam Leffler 3 * Copyright (c) 1991-1996 Silicon Graphics, Inc. 4 * 5 * Permission to use, copy, modify, distribute, and sell this software and 6 * its documentation for any purpose is hereby granted without fee, provided 7 * that (i) the above copyright notices and this permission notice appear in 8 * all copies of the software and related documentation, and (ii) the names of 9 * Sam Leffler and Silicon Graphics may not be used in any advertising or 10 * publicity relating to the software without the specific, prior written 11 * permission of Sam Leffler and Silicon Graphics. 12 * 13 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 14 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 15 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. 16 * 17 * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR 18 * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, 19 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 20 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 21 * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 22 * OF THIS SOFTWARE. 23 */ 24 25 /* 26 * TIFF Library UNIX-specific Routines. 27 */ 28 #include "tiffiop.h" 29 #include <iostream> 30 31 #ifndef __VMS 32 using namespace std; 33 #endif 34 35 /* 36 ISO C++ uses a 'std::streamsize' type to define counts. This makes 37 it similar to, (but perhaps not the same as) size_t. 38 39 The std::ios::pos_type is used to represent stream positions as used 40 by tellg(), tellp(), seekg(), and seekp(). This makes it similar to 41 (but perhaps not the same as) 'off_t'. The std::ios::streampos type 42 is used for character streams, but is documented to not be an 43 integral type anymore, so it should *not* be assigned to an integral 44 type. 45 46 The std::ios::off_type is used to specify relative offsets needed by 47 the variants of seekg() and seekp() which accept a relative offset 48 argument. 49 50 Useful prototype knowledge: 51 52 Obtain read position 53 ios::pos_type basic_istream::tellg() 54 55 Set read position 56 basic_istream& basic_istream::seekg(ios::pos_type) 57 basic_istream& basic_istream::seekg(ios::off_type, ios_base::seekdir) 58 59 Read data 60 basic_istream& istream::read(char *str, streamsize count) 61 62 Number of characters read in last unformatted read 63 streamsize istream::gcount(); 64 65 Obtain write position 66 ios::pos_type basic_ostream::tellp() 67 68 Set write position 69 basic_ostream& basic_ostream::seekp(ios::pos_type) 70 basic_ostream& basic_ostream::seekp(ios::off_type, ios_base::seekdir) 71 72 Write data 73 basic_ostream& ostream::write(const char *str, streamsize count) 74 */ 75 76 struct tiffis_data; 77 struct tiffos_data; 78 79 extern "C" { 80 81 static tmsize_t _tiffosReadProc(thandle_t, void*, tmsize_t); 82 static tmsize_t _tiffisReadProc(thandle_t fd, void* buf, tmsize_t size); 83 static tmsize_t _tiffosWriteProc(thandle_t fd, void* buf, tmsize_t size); 84 static tmsize_t _tiffisWriteProc(thandle_t, void*, tmsize_t); 85 static uint64 _tiffosSeekProc(thandle_t fd, uint64 off, int whence); 86 static uint64 _tiffisSeekProc(thandle_t fd, uint64 off, int whence); 87 static uint64 _tiffosSizeProc(thandle_t fd); 88 static uint64 _tiffisSizeProc(thandle_t fd); 89 static int _tiffosCloseProc(thandle_t fd); 90 static int _tiffisCloseProc(thandle_t fd); 91 static int _tiffDummyMapProc(thandle_t , void** base, toff_t* size ); 92 static void _tiffDummyUnmapProc(thandle_t , void* base, toff_t size ); 93 static TIFF* _tiffStreamOpen(const char* name, const char* mode, void *fd); 94 95 struct tiffis_data 96 { 97 istream *stream; 98 ios::pos_type start_pos; 99 }; 100 101 struct tiffos_data 102 { 103 ostream *stream; 104 ios::pos_type start_pos; 105 }; 106 107 static tmsize_t 108 _tiffosReadProc(thandle_t, void*, tmsize_t) 109 { 110 return 0; 111 } 112 113 static tmsize_t 114 _tiffisReadProc(thandle_t fd, void* buf, tmsize_t size) 115 { 116 tiffis_data *data = reinterpret_cast<tiffis_data *>(fd); 117 118 // Verify that type does not overflow. 119 streamsize request_size = size; 120 if (static_cast<tmsize_t>(request_size) != size) 121 return static_cast<tmsize_t>(-1); 122 123 data->stream->read((char *) buf, request_size); 124 125 return static_cast<tmsize_t>(data->stream->gcount()); 126 } 127 128 static tmsize_t 129 _tiffosWriteProc(thandle_t fd, void* buf, tmsize_t size) 130 { 131 tiffos_data *data = reinterpret_cast<tiffos_data *>(fd); 132 ostream *os = data->stream; 133 ios::pos_type pos = os->tellp(); 134 135 // Verify that type does not overflow. 136 streamsize request_size = size; 137 if (static_cast<tmsize_t>(request_size) != size) 138 return static_cast<tmsize_t>(-1); 139 140 os->write(reinterpret_cast<const char *>(buf), request_size); 141 142 return static_cast<tmsize_t>(os->tellp() - pos); 143 } 144 145 static tmsize_t 146 _tiffisWriteProc(thandle_t, void*, tmsize_t) 147 { 148 return 0; 149 } 150 151 static uint64 152 _tiffosSeekProc(thandle_t fd, uint64 off, int whence) 153 { 154 tiffos_data *data = reinterpret_cast<tiffos_data *>(fd); 155 ostream *os = data->stream; 156 157 // if the stream has already failed, don't do anything 158 if( os->fail() ) 159 return static_cast<uint64>(-1); 160 161 switch(whence) { 162 case SEEK_SET: 163 { 164 // Compute 64-bit offset 165 uint64 new_offset = static_cast<uint64>(data->start_pos) + off; 166 167 // Verify that value does not overflow 168 ios::off_type offset = static_cast<ios::off_type>(new_offset); 169 if (static_cast<uint64>(offset) != new_offset) 170 return static_cast<uint64>(-1); 171 172 os->seekp(offset, ios::beg); 173 break; 174 } 175 case SEEK_CUR: 176 { 177 // Verify that value does not overflow 178 ios::off_type offset = static_cast<ios::off_type>(off); 179 if (static_cast<uint64>(offset) != off) 180 return static_cast<uint64>(-1); 181 182 os->seekp(offset, ios::cur); 183 break; 184 } 185 case SEEK_END: 186 { 187 // Verify that value does not overflow 188 ios::off_type offset = static_cast<ios::off_type>(off); 189 if (static_cast<uint64>(offset) != off) 190 return static_cast<uint64>(-1); 191 192 os->seekp(offset, ios::end); 193 break; 194 } 195 } 196 197 // Attempt to workaround problems with seeking past the end of the 198 // stream. ofstream doesn't have a problem with this but 199 // ostrstream/ostringstream does. In that situation, add intermediate 200 // '\0' characters. 201 if( os->fail() ) { 202 #ifdef __VMS 203 int old_state; 204 #else 205 ios::iostate old_state; 206 #endif 207 ios::pos_type origin; 208 209 old_state = os->rdstate(); 210 // reset the fail bit or else tellp() won't work below 211 os->clear(os->rdstate() & ~ios::failbit); 212 switch( whence ) { 213 case SEEK_SET: 214 default: 215 origin = data->start_pos; 216 break; 217 case SEEK_CUR: 218 origin = os->tellp(); 219 break; 220 case SEEK_END: 221 os->seekp(0, ios::end); 222 origin = os->tellp(); 223 break; 224 } 225 // restore original stream state 226 os->clear(old_state); 227 228 // only do something if desired seek position is valid 229 if( (static_cast<uint64>(origin) + off) > static_cast<uint64>(data->start_pos) ) { 230 uint64 num_fill; 231 232 // clear the fail bit 233 os->clear(os->rdstate() & ~ios::failbit); 234 235 // extend the stream to the expected size 236 os->seekp(0, ios::end); 237 num_fill = (static_cast<uint64>(origin)) + off - os->tellp(); 238 for( uint64 i = 0; i < num_fill; i++ ) 239 os->put('\0'); 240 241 // retry the seek 242 os->seekp(static_cast<ios::off_type>(static_cast<uint64>(origin) + off), ios::beg); 243 } 244 } 245 246 return static_cast<uint64>(os->tellp()); 247 } 248 249 static uint64 250 _tiffisSeekProc(thandle_t fd, uint64 off, int whence) 251 { 252 tiffis_data *data = reinterpret_cast<tiffis_data *>(fd); 253 254 switch(whence) { 255 case SEEK_SET: 256 { 257 // Compute 64-bit offset 258 uint64 new_offset = static_cast<uint64>(data->start_pos) + off; 259 260 // Verify that value does not overflow 261 ios::off_type offset = static_cast<ios::off_type>(new_offset); 262 if (static_cast<uint64>(offset) != new_offset) 263 return static_cast<uint64>(-1); 264 265 data->stream->seekg(offset, ios::beg); 266 break; 267 } 268 case SEEK_CUR: 269 { 270 // Verify that value does not overflow 271 ios::off_type offset = static_cast<ios::off_type>(off); 272 if (static_cast<uint64>(offset) != off) 273 return static_cast<uint64>(-1); 274 275 data->stream->seekg(offset, ios::cur); 276 break; 277 } 278 case SEEK_END: 279 { 280 // Verify that value does not overflow 281 ios::off_type offset = static_cast<ios::off_type>(off); 282 if (static_cast<uint64>(offset) != off) 283 return static_cast<uint64>(-1); 284 285 data->stream->seekg(offset, ios::end); 286 break; 287 } 288 } 289 290 return (uint64) (data->stream->tellg() - data->start_pos); 291 } 292 293 static uint64 294 _tiffosSizeProc(thandle_t fd) 295 { 296 tiffos_data *data = reinterpret_cast<tiffos_data *>(fd); 297 ostream *os = data->stream; 298 ios::pos_type pos = os->tellp(); 299 ios::pos_type len; 300 301 os->seekp(0, ios::end); 302 len = os->tellp(); 303 os->seekp(pos); 304 305 return (uint64) len; 306 } 307 308 static uint64 309 _tiffisSizeProc(thandle_t fd) 310 { 311 tiffis_data *data = reinterpret_cast<tiffis_data *>(fd); 312 ios::pos_type pos = data->stream->tellg(); 313 ios::pos_type len; 314 315 data->stream->seekg(0, ios::end); 316 len = data->stream->tellg(); 317 data->stream->seekg(pos); 318 319 return (uint64) len; 320 } 321 322 static int 323 _tiffosCloseProc(thandle_t fd) 324 { 325 // Our stream was not allocated by us, so it shouldn't be closed by us. 326 delete reinterpret_cast<tiffos_data *>(fd); 327 return 0; 328 } 329 330 static int 331 _tiffisCloseProc(thandle_t fd) 332 { 333 // Our stream was not allocated by us, so it shouldn't be closed by us. 334 delete reinterpret_cast<tiffis_data *>(fd); 335 return 0; 336 } 337 338 static int 339 _tiffDummyMapProc(thandle_t , void** base, toff_t* size ) 340 { 341 (void) base; 342 (void) size; 343 return (0); 344 } 345 346 static void 347 _tiffDummyUnmapProc(thandle_t , void* base, toff_t size ) 348 { 349 (void) base; 350 (void) size; 351 } 352 353 /* 354 * Open a TIFF file descriptor for read/writing. 355 */ 356 static TIFF* 357 _tiffStreamOpen(const char* name, const char* mode, void *fd) 358 { 359 TIFF* tif; 360 361 if( strchr(mode, 'w') ) { 362 tiffos_data *data = new tiffos_data; 363 data->stream = reinterpret_cast<ostream *>(fd); 364 data->start_pos = data->stream->tellp(); 365 366 // Open for writing. 367 tif = TIFFClientOpen(name, mode, 368 reinterpret_cast<thandle_t>(data), 369 _tiffosReadProc, 370 _tiffosWriteProc, 371 _tiffosSeekProc, 372 _tiffosCloseProc, 373 _tiffosSizeProc, 374 _tiffDummyMapProc, 375 _tiffDummyUnmapProc); 376 if (!tif) { 377 delete data; 378 } 379 } else { 380 tiffis_data *data = new tiffis_data; 381 data->stream = reinterpret_cast<istream *>(fd); 382 data->start_pos = data->stream->tellg(); 383 // Open for reading. 384 tif = TIFFClientOpen(name, mode, 385 reinterpret_cast<thandle_t>(data), 386 _tiffisReadProc, 387 _tiffisWriteProc, 388 _tiffisSeekProc, 389 _tiffisCloseProc, 390 _tiffisSizeProc, 391 _tiffDummyMapProc, 392 _tiffDummyUnmapProc); 393 if (!tif) { 394 delete data; 395 } 396 } 397 398 return (tif); 399 } 400 401 } /* extern "C" */ 402 403 TIFF* 404 TIFFStreamOpen(const char* name, ostream *os) 405 { 406 // If os is either a ostrstream or ostringstream, and has no data 407 // written to it yet, then tellp() will return -1 which will break us. 408 // We workaround this by writing out a dummy character and 409 // then seek back to the beginning. 410 if( !os->fail() && static_cast<int>(os->tellp()) < 0 ) { 411 *os << '\0'; 412 os->seekp(0); 413 } 414 415 // NB: We don't support mapped files with streams so add 'm' 416 return _tiffStreamOpen(name, "wm", os); 417 } 418 419 TIFF* 420 TIFFStreamOpen(const char* name, istream *is) 421 { 422 // NB: We don't support mapped files with streams so add 'm' 423 return _tiffStreamOpen(name, "rm", is); 424 } 425 426 /* vim: set ts=8 sts=8 sw=8 noet: */ 427 /* 428 * Local Variables: 429 * mode: c 430 * c-basic-offset: 8 431 * fill-column: 78 432 * End: 433 */ 434 435