Update to 2.0.0 tree from current Fremantle build
[opencv] / 3rdparty / libtiff / tif_stream.cxx
1 /* $Id: tif_stream.cxx,v 1.1 2005-06-17 13:54:52 vp153 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 <iostream>
31 #include <cstring>
32 #include "tiffiop.h"
33
34 using namespace std;
35
36 class tiffis_data
37 {
38   public:
39
40         istream *myIS;
41         long    myStreamStartPos;
42 };
43
44 class tiffos_data
45 {
46   public:
47
48         ostream *myOS;
49         long    myStreamStartPos;
50 };
51
52 static tsize_t
53 _tiffosReadProc(thandle_t, tdata_t, tsize_t)
54 {
55         return 0;
56 }
57
58 static tsize_t
59 _tiffisReadProc(thandle_t fd, tdata_t buf, tsize_t size)
60 {
61         tiffis_data     *data = (tiffis_data *)fd;
62
63         data->myIS->read((char *)buf, (int)size);
64
65         return data->myIS->gcount();
66 }
67
68 static tsize_t
69 _tiffosWriteProc(thandle_t fd, tdata_t buf, tsize_t size)
70 {
71         tiffos_data     *data = (tiffos_data *)fd;
72         ostream         *os = data->myOS;
73         int             pos = os->tellp();
74
75         os->write((const char *)buf, size);
76
77         return ((int)os->tellp()) - pos;
78 }
79
80 static tsize_t
81 _tiffisWriteProc(thandle_t, tdata_t, tsize_t)
82 {
83         return 0;
84 }
85
86 static toff_t
87 _tiffosSeekProc(thandle_t fd, toff_t off, int whence)
88 {
89         tiffos_data     *data = (tiffos_data *)fd;
90         ostream *os = data->myOS;
91
92         // if the stream has already failed, don't do anything
93         if( os->fail() )
94                 return os->tellp();
95
96         switch(whence) {
97         case SEEK_SET:
98             os->seekp(data->myStreamStartPos + off, ios::beg);
99                 break;
100         case SEEK_CUR:
101                 os->seekp(off, ios::cur);
102                 break;
103         case SEEK_END:
104                 os->seekp(off, ios::end);
105                 break;
106         }
107
108         // Attempt to workaround problems with seeking past the end of the
109         // stream.  ofstream doesn't have a problem with this but
110         // ostrstream/ostringstream does. In that situation, add intermediate
111         // '\0' characters.
112         if( os->fail() ) {
113                 ios::iostate    old_state;
114                 toff_t          origin;
115
116                 old_state = os->rdstate();
117                 // reset the fail bit or else tellp() won't work below
118                 os->clear(os->rdstate() & ~ios::failbit);
119                 switch( whence ) {
120                         case SEEK_SET:
121                                 origin = data->myStreamStartPos;
122                                 break;
123                         case SEEK_CUR:
124                                 origin = os->tellp();
125                                 break;
126                         case SEEK_END:
127                                 os->seekp(0, ios::end);
128                                 origin = os->tellp();
129                                 break;
130                 }
131                 // restore original stream state
132                 os->clear(old_state);   
133
134                 // only do something if desired seek position is valid
135                 if( origin + off > data->myStreamStartPos ) {
136                         toff_t  num_fill;
137
138                         // clear the fail bit 
139                         os->clear(os->rdstate() & ~ios::failbit);
140
141                         // extend the stream to the expected size
142                         os->seekp(0, ios::end);
143                         num_fill = origin + off - (toff_t)os->tellp();
144                         for( toff_t i = 0; i < num_fill; i++ )
145                                 os->put('\0');
146
147                         // retry the seek
148                         os->seekp(origin + off, ios::beg);
149                 }
150         }
151
152         return os->tellp();
153 }
154
155 static toff_t
156 _tiffisSeekProc(thandle_t fd, toff_t off, int whence)
157 {
158         tiffis_data     *data = (tiffis_data *)fd;
159
160         switch(whence) {
161         case SEEK_SET:
162                 data->myIS->seekg(data->myStreamStartPos + off, ios::beg);
163                 break;
164         case SEEK_CUR:
165                 data->myIS->seekg(off, ios::cur);
166                 break;
167         case SEEK_END:
168                 data->myIS->seekg(off, ios::end);
169                 break;
170         }
171
172         return ((long)data->myIS->tellg()) - data->myStreamStartPos;
173 }
174
175 static toff_t
176 _tiffosSizeProc(thandle_t fd)
177 {
178         tiffos_data     *data = (tiffos_data *)fd;
179         ostream         *os = data->myOS;
180         toff_t          pos = os->tellp();
181         toff_t          len;
182
183         os->seekp(0, ios::end);
184         len = os->tellp();
185         os->seekp(pos);
186
187         return len;
188 }
189
190 static toff_t
191 _tiffisSizeProc(thandle_t fd)
192 {
193         tiffis_data     *data = (tiffis_data *)fd;
194         int             pos = data->myIS->tellg();
195         int             len;
196
197         data->myIS->seekg(0, ios::end);
198         len = data->myIS->tellg();
199         data->myIS->seekg(pos);
200
201         return len;
202 }
203
204 static int
205 _tiffosCloseProc(thandle_t fd)
206 {
207         // Our stream was not allocated by us, so it shouldn't be closed by us.
208         delete (tiffos_data *)fd;
209         return 0;
210 }
211
212 static int
213 _tiffisCloseProc(thandle_t fd)
214 {
215         // Our stream was not allocated by us, so it shouldn't be closed by us.
216         delete (tiffis_data *)fd;
217         return 0;
218 }
219
220 static int
221 _tiffDummyMapProc(thandle_t , tdata_t* , toff_t* )
222 {
223         return (0);
224 }
225
226 static void
227 _tiffDummyUnmapProc(thandle_t , tdata_t , toff_t )
228 {
229 }
230
231 /*
232  * Open a TIFF file descriptor for read/writing.
233  */
234 static TIFF*
235 _tiffStreamOpen(const char* name, const char* mode, void *fd)
236 {
237         TIFF*   tif;
238
239         if( strchr(mode, 'w') ) {
240                 tiffos_data     *data = new tiffos_data;
241                 data->myOS = (ostream *)fd;
242                 data->myStreamStartPos = data->myOS->tellp();
243
244                 // Open for writing.
245                 tif = TIFFClientOpen(name, mode,
246                                 (thandle_t) data,
247                                 _tiffosReadProc, _tiffosWriteProc,
248                                 _tiffosSeekProc, _tiffosCloseProc,
249                                 _tiffosSizeProc,
250                                 _tiffDummyMapProc, _tiffDummyUnmapProc);
251         } else {
252                 tiffis_data     *data = new tiffis_data;
253                 data->myIS = (istream *)fd;
254                 data->myStreamStartPos = data->myIS->tellg();
255                 // Open for reading.
256                 tif = TIFFClientOpen(name, mode,
257                                 (thandle_t) data,
258                                 _tiffisReadProc, _tiffisWriteProc,
259                                 _tiffisSeekProc, _tiffisCloseProc,
260                                 _tiffisSizeProc,
261                                 _tiffDummyMapProc, _tiffDummyUnmapProc);
262         }
263
264         return (tif);
265 }
266
267 TIFF*
268 TIFFStreamOpen(const char* name, ostream *os)
269 {
270         // If os is either a ostrstream or ostringstream, and has no data
271         // written to it yet, then tellp() will return -1 which will break us.
272         // We workaround this by writing out a dummy character and
273         // then seek back to the beginning.
274         if( !os->fail() && (int)os->tellp() < 0 ) {
275                 *os << '\0';
276                 os->seekp(0);
277         }
278
279         // NB: We don't support mapped files with streams so add 'm'
280         return _tiffStreamOpen(name, "wm", os);
281 }
282
283 TIFF*
284 TIFFStreamOpen(const char* name, istream *is)
285 {
286         // NB: We don't support mapped files with streams so add 'm'
287         return _tiffStreamOpen(name, "rm", is);
288 }
289
290 /* vim: set ts=8 sts=8 sw=8 noet: */