tif_stream.cxx 11 KB

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