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