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