/src/FreeImage/Source/OpenEXR/IlmImf/ImfTileOffsets.cpp

https://bitbucket.org/cabalistic/ogredeps/ · C++ · 385 lines · 222 code · 84 blank · 79 comment · 36 complexity · e1df6fb95e4d04407c8481a0f3d30203 MD5 · raw file

  1. ///////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
  4. // Digital Ltd. LLC
  5. //
  6. // All rights reserved.
  7. //
  8. // Redistribution and use in source and binary forms, with or without
  9. // modification, are permitted provided that the following conditions are
  10. // met:
  11. // * Redistributions of source code must retain the above copyright
  12. // notice, this list of conditions and the following disclaimer.
  13. // * Redistributions in binary form must reproduce the above
  14. // copyright notice, this list of conditions and the following disclaimer
  15. // in the documentation and/or other materials provided with the
  16. // distribution.
  17. // * Neither the name of Industrial Light & Magic nor the names of
  18. // its contributors may be used to endorse or promote products derived
  19. // from this software without specific prior written permission.
  20. //
  21. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  24. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  25. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  26. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  27. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  28. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  29. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  30. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  31. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32. //
  33. ///////////////////////////////////////////////////////////////////////////
  34. //-----------------------------------------------------------------------------
  35. //
  36. // class TileOffsets
  37. //
  38. //-----------------------------------------------------------------------------
  39. #include <ImfTileOffsets.h>
  40. #include <ImfXdr.h>
  41. #include <ImfIO.h>
  42. #include "Iex.h"
  43. namespace Imf {
  44. TileOffsets::TileOffsets (LevelMode mode,
  45. int numXLevels, int numYLevels,
  46. const int *numXTiles, const int *numYTiles)
  47. :
  48. _mode (mode),
  49. _numXLevels (numXLevels),
  50. _numYLevels (numYLevels)
  51. {
  52. switch (_mode)
  53. {
  54. case ONE_LEVEL:
  55. case MIPMAP_LEVELS:
  56. _offsets.resize (_numXLevels);
  57. for (unsigned int l = 0; l < _offsets.size(); ++l)
  58. {
  59. _offsets[l].resize (numYTiles[l]);
  60. for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
  61. {
  62. _offsets[l][dy].resize (numXTiles[l]);
  63. }
  64. }
  65. break;
  66. case RIPMAP_LEVELS:
  67. _offsets.resize (_numXLevels * _numYLevels);
  68. for (unsigned int ly = 0; ly < _numYLevels; ++ly)
  69. {
  70. for (unsigned int lx = 0; lx < _numXLevels; ++lx)
  71. {
  72. int l = ly * _numXLevels + lx;
  73. _offsets[l].resize (numYTiles[ly]);
  74. for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
  75. {
  76. _offsets[l][dy].resize (numXTiles[lx]);
  77. }
  78. }
  79. }
  80. break;
  81. }
  82. }
  83. bool
  84. TileOffsets::anyOffsetsAreInvalid () const
  85. {
  86. for (unsigned int l = 0; l < _offsets.size(); ++l)
  87. for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
  88. for (unsigned int dx = 0; dx < _offsets[l][dy].size(); ++dx)
  89. if (_offsets[l][dy][dx] <= 0)
  90. return true;
  91. return false;
  92. }
  93. void
  94. TileOffsets::findTiles (IStream &is)
  95. {
  96. for (unsigned int l = 0; l < _offsets.size(); ++l)
  97. {
  98. for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
  99. {
  100. for (unsigned int dx = 0; dx < _offsets[l][dy].size(); ++dx)
  101. {
  102. Int64 tileOffset = is.tellg();
  103. int tileX;
  104. Xdr::read <StreamIO> (is, tileX);
  105. int tileY;
  106. Xdr::read <StreamIO> (is, tileY);
  107. int levelX;
  108. Xdr::read <StreamIO> (is, levelX);
  109. int levelY;
  110. Xdr::read <StreamIO> (is, levelY);
  111. int dataSize;
  112. Xdr::read <StreamIO> (is, dataSize);
  113. Xdr::skip <StreamIO> (is, dataSize);
  114. if (!isValidTile(tileX, tileY, levelX, levelY))
  115. return;
  116. operator () (tileX, tileY, levelX, levelY) = tileOffset;
  117. }
  118. }
  119. }
  120. }
  121. void
  122. TileOffsets::reconstructFromFile (IStream &is)
  123. {
  124. //
  125. // Try to reconstruct a missing tile offset table by sequentially
  126. // scanning through the file, and recording the offsets in the file
  127. // of the tiles we find.
  128. //
  129. Int64 position = is.tellg();
  130. try
  131. {
  132. findTiles (is);
  133. }
  134. catch (...)
  135. {
  136. //
  137. // Suppress all exceptions. This function is called only to
  138. // reconstruct the tile offset table for incomplete files,
  139. // and exceptions are likely.
  140. //
  141. }
  142. is.clear();
  143. is.seekg (position);
  144. }
  145. void
  146. TileOffsets::readFrom (IStream &is, bool &complete)
  147. {
  148. //
  149. // Read in the tile offsets from the file's tile offset table
  150. //
  151. for (unsigned int l = 0; l < _offsets.size(); ++l)
  152. for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
  153. for (unsigned int dx = 0; dx < _offsets[l][dy].size(); ++dx)
  154. Xdr::read <StreamIO> (is, _offsets[l][dy][dx]);
  155. //
  156. // Check if any tile offsets are invalid.
  157. //
  158. // Invalid offsets mean that the file is probably incomplete
  159. // (the offset table is the last thing written to the file).
  160. // Either some process is still busy writing the file, or
  161. // writing the file was aborted.
  162. //
  163. // We should still be able to read the existing parts of the
  164. // file. In order to do this, we have to make a sequential
  165. // scan over the scan tile to reconstruct the tile offset
  166. // table.
  167. //
  168. if (anyOffsetsAreInvalid())
  169. {
  170. complete = false;
  171. reconstructFromFile (is);
  172. }
  173. else
  174. {
  175. complete = true;
  176. }
  177. }
  178. Int64
  179. TileOffsets::writeTo (OStream &os) const
  180. {
  181. //
  182. // Write the tile offset table to the file, and
  183. // return the position of the start of the table
  184. // in the file.
  185. //
  186. Int64 pos = os.tellp();
  187. if (pos == -1)
  188. Iex::throwErrnoExc ("Cannot determine current file position (%T).");
  189. for (unsigned int l = 0; l < _offsets.size(); ++l)
  190. for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
  191. for (unsigned int dx = 0; dx < _offsets[l][dy].size(); ++dx)
  192. Xdr::write <StreamIO> (os, _offsets[l][dy][dx]);
  193. return pos;
  194. }
  195. bool
  196. TileOffsets::isEmpty () const
  197. {
  198. for (unsigned int l = 0; l < _offsets.size(); ++l)
  199. for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
  200. for (unsigned int dx = 0; dx < _offsets[l][dy].size(); ++dx)
  201. if (_offsets[l][dy][dx] != 0)
  202. return false;
  203. return true;
  204. }
  205. bool
  206. TileOffsets::isValidTile (int dx, int dy, int lx, int ly) const
  207. {
  208. switch (_mode)
  209. {
  210. case ONE_LEVEL:
  211. if (lx == 0 &&
  212. ly == 0 &&
  213. _offsets.size() > 0 &&
  214. _offsets[0].size() > dy &&
  215. _offsets[0][dy].size() > dx)
  216. {
  217. return true;
  218. }
  219. break;
  220. case MIPMAP_LEVELS:
  221. if (lx < _numXLevels &&
  222. ly < _numYLevels &&
  223. _offsets.size() > lx &&
  224. _offsets[lx].size() > dy &&
  225. _offsets[lx][dy].size() > dx)
  226. {
  227. return true;
  228. }
  229. break;
  230. case RIPMAP_LEVELS:
  231. if (lx < _numXLevels &&
  232. ly < _numYLevels &&
  233. _offsets.size() > lx + ly * _numXLevels &&
  234. _offsets[lx + ly * _numXLevels].size() > dy &&
  235. _offsets[lx + ly * _numXLevels][dy].size() > dx)
  236. {
  237. return true;
  238. }
  239. break;
  240. default:
  241. return false;
  242. }
  243. return false;
  244. }
  245. Int64 &
  246. TileOffsets::operator () (int dx, int dy, int lx, int ly)
  247. {
  248. //
  249. // Looks up the value of the tile with tile coordinate (dx, dy)
  250. // and level number (lx, ly) in the _offsets array, and returns
  251. // the cooresponding offset.
  252. //
  253. switch (_mode)
  254. {
  255. case ONE_LEVEL:
  256. return _offsets[0][dy][dx];
  257. break;
  258. case MIPMAP_LEVELS:
  259. return _offsets[lx][dy][dx];
  260. break;
  261. case RIPMAP_LEVELS:
  262. return _offsets[lx + ly * _numXLevels][dy][dx];
  263. break;
  264. default:
  265. throw Iex::ArgExc ("Unknown LevelMode format.");
  266. }
  267. }
  268. Int64 &
  269. TileOffsets::operator () (int dx, int dy, int l)
  270. {
  271. return operator () (dx, dy, l, l);
  272. }
  273. const Int64 &
  274. TileOffsets::operator () (int dx, int dy, int lx, int ly) const
  275. {
  276. //
  277. // Looks up the value of the tile with tile coordinate (dx, dy)
  278. // and level number (lx, ly) in the _offsets array, and returns
  279. // the cooresponding offset.
  280. //
  281. switch (_mode)
  282. {
  283. case ONE_LEVEL:
  284. return _offsets[0][dy][dx];
  285. break;
  286. case MIPMAP_LEVELS:
  287. return _offsets[lx][dy][dx];
  288. break;
  289. case RIPMAP_LEVELS:
  290. return _offsets[lx + ly * _numXLevels][dy][dx];
  291. break;
  292. default:
  293. throw Iex::ArgExc ("Unknown LevelMode format.");
  294. }
  295. }
  296. const Int64 &
  297. TileOffsets::operator () (int dx, int dy, int l) const
  298. {
  299. return operator () (dx, dy, l, l);
  300. }
  301. } // namespace Imf