xref: /reactos/dll/3rdparty/libtiff/tif_stream.cxx (revision 4561998a)
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 
431