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