ecca1fd54b090c5b197a4409a909b0df6f7970e4
[reactos.git] / reactos / dll / 3rdparty / libtiff / tif_stream.cxx
1 /* $Id: tif_stream.cxx,v 1.13 2015-05-28 01:50:22 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
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 (void) base;
344 (void) size;
345 return (0);
346 }
347
348 static void
349 _tiffDummyUnmapProc(thandle_t , void* base, toff_t size )
350 {
351 (void) base;
352 (void) size;
353 }
354
355 /*
356 * Open a TIFF file descriptor for read/writing.
357 */
358 static TIFF*
359 _tiffStreamOpen(const char* name, const char* mode, void *fd)
360 {
361 TIFF* tif;
362
363 if( strchr(mode, 'w') ) {
364 tiffos_data *data = new tiffos_data;
365 data->stream = reinterpret_cast<ostream *>(fd);
366 data->start_pos = data->stream->tellp();
367
368 // Open for writing.
369 tif = TIFFClientOpen(name, mode,
370 reinterpret_cast<thandle_t>(data),
371 _tiffosReadProc,
372 _tiffosWriteProc,
373 _tiffosSeekProc,
374 _tiffosCloseProc,
375 _tiffosSizeProc,
376 _tiffDummyMapProc,
377 _tiffDummyUnmapProc);
378 } else {
379 tiffis_data *data = new tiffis_data;
380 data->stream = reinterpret_cast<istream *>(fd);
381 data->start_pos = data->stream->tellg();
382 // Open for reading.
383 tif = TIFFClientOpen(name, mode,
384 reinterpret_cast<thandle_t>(data),
385 _tiffisReadProc,
386 _tiffisWriteProc,
387 _tiffisSeekProc,
388 _tiffisCloseProc,
389 _tiffisSizeProc,
390 _tiffDummyMapProc,
391 _tiffDummyUnmapProc);
392 }
393
394 return (tif);
395 }
396
397 } /* extern "C" */
398
399 TIFF*
400 TIFFStreamOpen(const char* name, ostream *os)
401 {
402 // If os is either a ostrstream or ostringstream, and has no data
403 // written to it yet, then tellp() will return -1 which will break us.
404 // We workaround this by writing out a dummy character and
405 // then seek back to the beginning.
406 if( !os->fail() && static_cast<int>(os->tellp()) < 0 ) {
407 *os << '\0';
408 os->seekp(0);
409 }
410
411 // NB: We don't support mapped files with streams so add 'm'
412 return _tiffStreamOpen(name, "wm", os);
413 }
414
415 TIFF*
416 TIFFStreamOpen(const char* name, istream *is)
417 {
418 // NB: We don't support mapped files with streams so add 'm'
419 return _tiffStreamOpen(name, "rm", is);
420 }
421
422 /* vim: set ts=8 sts=8 sw=8 noet: */
423 /*
424 * Local Variables:
425 * mode: c
426 * c-basic-offset: 8
427 * fill-column: 78
428 * End:
429 */
430