tif_stream.cxx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. /* $Id: tif_stream.cxx,v 1.11 2010-12-11 23:12:29 faxguy Exp $ */
  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. * TIFF Library UNIX-specific Routines.
  27. */
  28. #include "tiffiop.h"
  29. #include <iostream>
  30. #ifndef __VMS
  31. using namespace std;
  32. #endif
  33. /*
  34. ISO C++ uses a 'std::streamsize' type to define counts. This makes
  35. it similar to, (but perhaps not the same as) size_t.
  36. The std::ios::pos_type is used to represent stream positions as used
  37. by tellg(), tellp(), seekg(), and seekp(). This makes it similar to
  38. (but perhaps not the same as) 'off_t'. The std::ios::streampos type
  39. is used for character streams, but is documented to not be an
  40. integral type anymore, so it should *not* be assigned to an integral
  41. type.
  42. The std::ios::off_type is used to specify relative offsets needed by
  43. the variants of seekg() and seekp() which accept a relative offset
  44. argument.
  45. Useful prototype knowledge:
  46. Obtain read position
  47. ios::pos_type basic_istream::tellg()
  48. Set read position
  49. basic_istream& basic_istream::seekg(ios::pos_type)
  50. basic_istream& basic_istream::seekg(ios::off_type, ios_base::seekdir)
  51. Read data
  52. basic_istream& istream::read(char *str, streamsize count)
  53. Number of characters read in last unformatted read
  54. streamsize istream::gcount();
  55. Obtain write position
  56. ios::pos_type basic_ostream::tellp()
  57. Set write position
  58. basic_ostream& basic_ostream::seekp(ios::pos_type)
  59. basic_ostream& basic_ostream::seekp(ios::off_type, ios_base::seekdir)
  60. Write data
  61. basic_ostream& ostream::write(const char *str, streamsize count)
  62. */
  63. struct tiffis_data;
  64. struct tiffos_data;
  65. extern "C" {
  66. static tmsize_t _tiffosReadProc(thandle_t, void*, tmsize_t);
  67. static tmsize_t _tiffisReadProc(thandle_t fd, void* buf, tmsize_t size);
  68. static tmsize_t _tiffosWriteProc(thandle_t fd, void* buf, tmsize_t size);
  69. static tmsize_t _tiffisWriteProc(thandle_t, void*, tmsize_t);
  70. static uint64 _tiffosSeekProc(thandle_t fd, uint64 off, int whence);
  71. static uint64 _tiffisSeekProc(thandle_t fd, uint64 off, int whence);
  72. static uint64 _tiffosSizeProc(thandle_t fd);
  73. static uint64 _tiffisSizeProc(thandle_t fd);
  74. static int _tiffosCloseProc(thandle_t fd);
  75. static int _tiffisCloseProc(thandle_t fd);
  76. static int _tiffDummyMapProc(thandle_t , void** base, toff_t* size );
  77. static void _tiffDummyUnmapProc(thandle_t , void* base, toff_t size );
  78. static TIFF* _tiffStreamOpen(const char* name, const char* mode, void *fd);
  79. struct tiffis_data
  80. {
  81. istream *stream;
  82. ios::pos_type start_pos;
  83. };
  84. struct tiffos_data
  85. {
  86. ostream *stream;
  87. ios::pos_type start_pos;
  88. };
  89. static tmsize_t
  90. _tiffosReadProc(thandle_t, void*, tmsize_t)
  91. {
  92. return 0;
  93. }
  94. static tmsize_t
  95. _tiffisReadProc(thandle_t fd, void* buf, tmsize_t size)
  96. {
  97. tiffis_data *data = reinterpret_cast<tiffis_data *>(fd);
  98. // Verify that type does not overflow.
  99. streamsize request_size = size;
  100. if (static_cast<tmsize_t>(request_size) != size)
  101. return static_cast<tmsize_t>(-1);
  102. data->stream->read((char *) buf, request_size);
  103. return static_cast<tmsize_t>(data->stream->gcount());
  104. }
  105. static tmsize_t
  106. _tiffosWriteProc(thandle_t fd, void* buf, tmsize_t size)
  107. {
  108. tiffos_data *data = reinterpret_cast<tiffos_data *>(fd);
  109. ostream *os = data->stream;
  110. ios::pos_type pos = os->tellp();
  111. // Verify that type does not overflow.
  112. streamsize request_size = size;
  113. if (static_cast<tmsize_t>(request_size) != size)
  114. return static_cast<tmsize_t>(-1);
  115. os->write(reinterpret_cast<const char *>(buf), request_size);
  116. return static_cast<tmsize_t>(os->tellp() - pos);
  117. }
  118. static tmsize_t
  119. _tiffisWriteProc(thandle_t, void*, tmsize_t)
  120. {
  121. return 0;
  122. }
  123. static uint64
  124. _tiffosSeekProc(thandle_t fd, uint64 off, int whence)
  125. {
  126. tiffos_data *data = reinterpret_cast<tiffos_data *>(fd);
  127. ostream *os = data->stream;
  128. // if the stream has already failed, don't do anything
  129. if( os->fail() )
  130. return static_cast<uint64>(-1);
  131. switch(whence) {
  132. case SEEK_SET:
  133. {
  134. // Compute 64-bit offset
  135. uint64 new_offset = static_cast<uint64>(data->start_pos) + off;
  136. // Verify that value does not overflow
  137. ios::off_type offset = static_cast<ios::off_type>(new_offset);
  138. if (static_cast<uint64>(offset) != new_offset)
  139. return static_cast<uint64>(-1);
  140. os->seekp(offset, ios::beg);
  141. break;
  142. }
  143. case SEEK_CUR:
  144. {
  145. // Verify that value does not overflow
  146. ios::off_type offset = static_cast<ios::off_type>(off);
  147. if (static_cast<uint64>(offset) != off)
  148. return static_cast<uint64>(-1);
  149. os->seekp(offset, ios::cur);
  150. break;
  151. }
  152. case SEEK_END:
  153. {
  154. // Verify that value does not overflow
  155. ios::off_type offset = static_cast<ios::off_type>(off);
  156. if (static_cast<uint64>(offset) != off)
  157. return static_cast<uint64>(-1);
  158. os->seekp(offset, ios::end);
  159. break;
  160. }
  161. }
  162. // Attempt to workaround problems with seeking past the end of the
  163. // stream. ofstream doesn't have a problem with this but
  164. // ostrstream/ostringstream does. In that situation, add intermediate
  165. // '\0' characters.
  166. if( os->fail() ) {
  167. #ifdef __VMS
  168. int old_state;
  169. #else
  170. ios::iostate old_state;
  171. #endif
  172. ios::pos_type origin;
  173. old_state = os->rdstate();
  174. // reset the fail bit or else tellp() won't work below
  175. os->clear(os->rdstate() & ~ios::failbit);
  176. switch( whence ) {
  177. case SEEK_SET:
  178. default:
  179. origin = data->start_pos;
  180. break;
  181. case SEEK_CUR:
  182. origin = os->tellp();
  183. break;
  184. case SEEK_END:
  185. os->seekp(0, ios::end);
  186. origin = os->tellp();
  187. break;
  188. }
  189. // restore original stream state
  190. os->clear(old_state);
  191. // only do something if desired seek position is valid
  192. if( (static_cast<uint64>(origin) + off) > static_cast<uint64>(data->start_pos) ) {
  193. uint64 num_fill;
  194. // clear the fail bit
  195. os->clear(os->rdstate() & ~ios::failbit);
  196. // extend the stream to the expected size
  197. os->seekp(0, ios::end);
  198. num_fill = (static_cast<uint64>(origin)) + off - os->tellp();
  199. for( uint64 i = 0; i < num_fill; i++ )
  200. os->put('\0');
  201. // retry the seek
  202. os->seekp(static_cast<ios::off_type>(static_cast<uint64>(origin) + off), ios::beg);
  203. }
  204. }
  205. return static_cast<uint64>(os->tellp());
  206. }
  207. static uint64
  208. _tiffisSeekProc(thandle_t fd, uint64 off, int whence)
  209. {
  210. tiffis_data *data = reinterpret_cast<tiffis_data *>(fd);
  211. switch(whence) {
  212. case SEEK_SET:
  213. {
  214. // Compute 64-bit offset
  215. uint64 new_offset = static_cast<uint64>(data->start_pos) + off;
  216. // Verify that value does not overflow
  217. ios::off_type offset = static_cast<ios::off_type>(new_offset);
  218. if (static_cast<uint64>(offset) != new_offset)
  219. return static_cast<uint64>(-1);
  220. data->stream->seekg(offset, ios::beg);
  221. break;
  222. }
  223. case SEEK_CUR:
  224. {
  225. // Verify that value does not overflow
  226. ios::off_type offset = static_cast<ios::off_type>(off);
  227. if (static_cast<uint64>(offset) != off)
  228. return static_cast<uint64>(-1);
  229. data->stream->seekg(offset, ios::cur);
  230. break;
  231. }
  232. case SEEK_END:
  233. {
  234. // Verify that value does not overflow
  235. ios::off_type offset = static_cast<ios::off_type>(off);
  236. if (static_cast<uint64>(offset) != off)
  237. return static_cast<uint64>(-1);
  238. data->stream->seekg(offset, ios::end);
  239. break;
  240. }
  241. }
  242. return (uint64) (data->stream->tellg() - data->start_pos);
  243. }
  244. static uint64
  245. _tiffosSizeProc(thandle_t fd)
  246. {
  247. tiffos_data *data = reinterpret_cast<tiffos_data *>(fd);
  248. ostream *os = data->stream;
  249. ios::pos_type pos = os->tellp();
  250. ios::pos_type len;
  251. os->seekp(0, ios::end);
  252. len = os->tellp();
  253. os->seekp(pos);
  254. return (uint64) len;
  255. }
  256. static uint64
  257. _tiffisSizeProc(thandle_t fd)
  258. {
  259. tiffis_data *data = reinterpret_cast<tiffis_data *>(fd);
  260. ios::pos_type pos = data->stream->tellg();
  261. ios::pos_type len;
  262. data->stream->seekg(0, ios::end);
  263. len = data->stream->tellg();
  264. data->stream->seekg(pos);
  265. return (uint64) len;
  266. }
  267. static int
  268. _tiffosCloseProc(thandle_t fd)
  269. {
  270. // Our stream was not allocated by us, so it shouldn't be closed by us.
  271. delete reinterpret_cast<tiffos_data *>(fd);
  272. return 0;
  273. }
  274. static int
  275. _tiffisCloseProc(thandle_t fd)
  276. {
  277. // Our stream was not allocated by us, so it shouldn't be closed by us.
  278. delete reinterpret_cast<tiffis_data *>(fd);
  279. return 0;
  280. }
  281. static int
  282. _tiffDummyMapProc(thandle_t , void** base, toff_t* size )
  283. {
  284. return (0);
  285. }
  286. static void
  287. _tiffDummyUnmapProc(thandle_t , void* base, toff_t size )
  288. {
  289. }
  290. /*
  291. * Open a TIFF file descriptor for read/writing.
  292. */
  293. static TIFF*
  294. _tiffStreamOpen(const char* name, const char* mode, void *fd)
  295. {
  296. TIFF* tif;
  297. if( strchr(mode, 'w') ) {
  298. tiffos_data *data = new tiffos_data;
  299. data->stream = reinterpret_cast<ostream *>(fd);
  300. data->start_pos = data->stream->tellp();
  301. // Open for writing.
  302. tif = TIFFClientOpen(name, mode,
  303. reinterpret_cast<thandle_t>(data),
  304. _tiffosReadProc,
  305. _tiffosWriteProc,
  306. _tiffosSeekProc,
  307. _tiffosCloseProc,
  308. _tiffosSizeProc,
  309. _tiffDummyMapProc,
  310. _tiffDummyUnmapProc);
  311. } else {
  312. tiffis_data *data = new tiffis_data;
  313. data->stream = reinterpret_cast<istream *>(fd);
  314. data->start_pos = data->stream->tellg();
  315. // Open for reading.
  316. tif = TIFFClientOpen(name, mode,
  317. reinterpret_cast<thandle_t>(data),
  318. _tiffisReadProc,
  319. _tiffisWriteProc,
  320. _tiffisSeekProc,
  321. _tiffisCloseProc,
  322. _tiffisSizeProc,
  323. _tiffDummyMapProc,
  324. _tiffDummyUnmapProc);
  325. }
  326. return (tif);
  327. }
  328. } /* extern "C" */
  329. TIFF*
  330. TIFFStreamOpen(const char* name, ostream *os)
  331. {
  332. // If os is either a ostrstream or ostringstream, and has no data
  333. // written to it yet, then tellp() will return -1 which will break us.
  334. // We workaround this by writing out a dummy character and
  335. // then seek back to the beginning.
  336. if( !os->fail() && static_cast<int>(os->tellp()) < 0 ) {
  337. *os << '\0';
  338. os->seekp(0);
  339. }
  340. // NB: We don't support mapped files with streams so add 'm'
  341. return _tiffStreamOpen(name, "wm", os);
  342. }
  343. TIFF*
  344. TIFFStreamOpen(const char* name, istream *is)
  345. {
  346. // NB: We don't support mapped files with streams so add 'm'
  347. return _tiffStreamOpen(name, "rm", is);
  348. }
  349. /* vim: set ts=8 sts=8 sw=8 noet: */
  350. /*
  351. Local Variables:
  352. mode: c
  353. indent-tabs-mode: true
  354. c-basic-offset: 8
  355. End:
  356. */