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
_tiffosReadProc(thandle_t,tdata_t,tsize_t)52 _tiffosReadProc(thandle_t, tdata_t, tsize_t)
53 {
54         return 0;
55 }
56 
57 static tsize_t
_tiffisReadProc(thandle_t fd,tdata_t buf,tsize_t size)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
_tiffosWriteProc(thandle_t fd,tdata_t buf,tsize_t size)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
_tiffisWriteProc(thandle_t,tdata_t,tsize_t)80 _tiffisWriteProc(thandle_t, tdata_t, tsize_t)
81 {
82 	return 0;
83 }
84 
85 static toff_t
_tiffosSeekProc(thandle_t fd,toff_t off,int whence)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
_tiffisSeekProc(thandle_t fd,toff_t off,int whence)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
_tiffosSizeProc(thandle_t fd)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
_tiffisSizeProc(thandle_t fd)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
_tiffosCloseProc(thandle_t fd)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
_tiffisCloseProc(thandle_t fd)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
_tiffDummyMapProc(thandle_t,tdata_t *,toff_t *)220 _tiffDummyMapProc(thandle_t , tdata_t* , toff_t* )
221 {
222 	return (0);
223 }
224 
225 static void
_tiffDummyUnmapProc(thandle_t,tdata_t,toff_t)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*
_tiffStreamOpen(const char * name,const char * mode,void * fd)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*
TIFFStreamOpen(const char * name,ostream * os)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*
TIFFStreamOpen(const char * name,istream * is)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: */
290