]>
Commit | Line | Data |
---|---|---|
1 | /* $Id: tif_stream.cxx,v 1.5 2005/07/26 08:11:13 dron 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 | 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: */ |