tif_stream.cxx 13 KB

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