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