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 //-----------------------------------------------------------------------------
37 //
38 // class TileOffsets
39 //
40 //-----------------------------------------------------------------------------
41
42 #include <ImfTileOffsets.h>
43 #include <ImfXdr.h>
44 #include <ImfIO.h>
45 #include "Iex.h"
46
47 namespace Imf {
48
49
TileOffsets(LevelMode mode,int numXLevels,int numYLevels,const int * numXTiles,const int * numYTiles)50 TileOffsets::TileOffsets (LevelMode mode,
51 int numXLevels, int numYLevels,
52 const int *numXTiles, const int *numYTiles)
53 :
54 _mode (mode),
55 _numXLevels (numXLevels),
56 _numYLevels (numYLevels)
57 {
58 switch (_mode)
59 {
60 case ONE_LEVEL:
61 case MIPMAP_LEVELS:
62
63 _offsets.resize (_numXLevels);
64
65 for (unsigned int l = 0; l < _offsets.size(); ++l)
66 {
67 _offsets[l].resize (numYTiles[l]);
68
69 for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
70 {
71 _offsets[l][dy].resize (numXTiles[l]);
72 }
73 }
74 break;
75
76 case RIPMAP_LEVELS:
77
78 _offsets.resize (_numXLevels * _numYLevels);
79
80 for (unsigned int ly = 0; ly < _numYLevels; ++ly)
81 {
82 for (unsigned int lx = 0; lx < _numXLevels; ++lx)
83 {
84 int l = ly * _numXLevels + lx;
85 _offsets[l].resize (numYTiles[ly]);
86
87 for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
88 {
89 _offsets[l][dy].resize (numXTiles[lx]);
90 }
91 }
92 }
93 break;
94 }
95 }
96
97
98 bool
anyOffsetsAreInvalid() const99 TileOffsets::anyOffsetsAreInvalid () const
100 {
101 for (unsigned int l = 0; l < _offsets.size(); ++l)
102 for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
103 for (unsigned int dx = 0; dx < _offsets[l][dy].size(); ++dx)
104 if (_offsets[l][dy][dx] <= 0)
105 return true;
106
107 return false;
108 }
109
110
111 void
findTiles(IStream & is)112 TileOffsets::findTiles (IStream &is)
113 {
114 for (unsigned int l = 0; l < _offsets.size(); ++l)
115 {
116 for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
117 {
118 for (unsigned int dx = 0; dx < _offsets[l][dy].size(); ++dx)
119 {
120 Int64 tileOffset = is.tellg();
121
122 int tileX;
123 Xdr::read <StreamIO> (is, tileX);
124
125 int tileY;
126 Xdr::read <StreamIO> (is, tileY);
127
128 int levelX;
129 Xdr::read <StreamIO> (is, levelX);
130
131 int levelY;
132 Xdr::read <StreamIO> (is, levelY);
133
134 int dataSize;
135 Xdr::read <StreamIO> (is, dataSize);
136
137 Xdr::skip <StreamIO> (is, dataSize);
138
139 if (!isValidTile(tileX, tileY, levelX, levelY))
140 return;
141
142 operator () (tileX, tileY, levelX, levelY) = tileOffset;
143 }
144 }
145 }
146 }
147
148
149 void
reconstructFromFile(IStream & is)150 TileOffsets::reconstructFromFile (IStream &is)
151 {
152 //
153 // Try to reconstruct a missing tile offset table by sequentially
154 // scanning through the file, and recording the offsets in the file
155 // of the tiles we find.
156 //
157
158 Int64 position = is.tellg();
159
160 try
161 {
162 findTiles (is);
163 }
164 catch (...)
165 {
166 //
167 // Suppress all exceptions. This function is called only to
168 // reconstruct the tile offset table for incomplete files,
169 // and exceptions are likely.
170 //
171 }
172
173 is.clear();
174 is.seekg (position);
175 }
176
177
178 void
readFrom(IStream & is,bool & complete)179 TileOffsets::readFrom (IStream &is, bool &complete)
180 {
181 //
182 // Read in the tile offsets from the file's tile offset table
183 //
184
185 for (unsigned int l = 0; l < _offsets.size(); ++l)
186 for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
187 for (unsigned int dx = 0; dx < _offsets[l][dy].size(); ++dx)
188 Xdr::read <StreamIO> (is, _offsets[l][dy][dx]);
189
190 //
191 // Check if any tile offsets are invalid.
192 //
193 // Invalid offsets mean that the file is probably incomplete
194 // (the offset table is the last thing written to the file).
195 // Either some process is still busy writing the file, or
196 // writing the file was aborted.
197 //
198 // We should still be able to read the existing parts of the
199 // file. In order to do this, we have to make a sequential
200 // scan over the scan tile to reconstruct the tile offset
201 // table.
202 //
203
204 if (anyOffsetsAreInvalid())
205 {
206 complete = false;
207 reconstructFromFile (is);
208 }
209 else
210 {
211 complete = true;
212 }
213
214 }
215
216
217 Int64
writeTo(OStream & os) const218 TileOffsets::writeTo (OStream &os) const
219 {
220 //
221 // Write the tile offset table to the file, and
222 // return the position of the start of the table
223 // in the file.
224 //
225
226 Int64 pos = os.tellp();
227
228 if (pos == -1)
229 Iex::throwErrnoExc ("Cannot determine current file position (%T).");
230
231 for (unsigned int l = 0; l < _offsets.size(); ++l)
232 for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
233 for (unsigned int dx = 0; dx < _offsets[l][dy].size(); ++dx)
234 Xdr::write <StreamIO> (os, _offsets[l][dy][dx]);
235
236 return pos;
237 }
238
239
240 bool
isEmpty() const241 TileOffsets::isEmpty () const
242 {
243 for (unsigned int l = 0; l < _offsets.size(); ++l)
244 for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
245 for (unsigned int dx = 0; dx < _offsets[l][dy].size(); ++dx)
246 if (_offsets[l][dy][dx] != 0)
247 return false;
248 return true;
249 }
250
251
252 bool
isValidTile(int dx,int dy,int lx,int ly) const253 TileOffsets::isValidTile (int dx, int dy, int lx, int ly) const
254 {
255 switch (_mode)
256 {
257 case ONE_LEVEL:
258
259 if (lx == 0 &&
260 ly == 0 &&
261 _offsets.size() > 0 &&
262 _offsets[0].size() > dy &&
263 _offsets[0][dy].size() > dx)
264 {
265 return true;
266 }
267
268 break;
269
270 case MIPMAP_LEVELS:
271
272 if (lx < _numXLevels &&
273 ly < _numYLevels &&
274 _offsets.size() > lx &&
275 _offsets[lx].size() > dy &&
276 _offsets[lx][dy].size() > dx)
277 {
278 return true;
279 }
280
281 break;
282
283 case RIPMAP_LEVELS:
284
285 if (lx < _numXLevels &&
286 ly < _numYLevels &&
287 _offsets.size() > lx + ly * _numXLevels &&
288 _offsets[lx + ly * _numXLevels].size() > dy &&
289 _offsets[lx + ly * _numXLevels][dy].size() > dx)
290 {
291 return true;
292 }
293
294 break;
295
296 default:
297
298 return false;
299 }
300
301 return false;
302 }
303
304
305 Int64 &
operator ()(int dx,int dy,int lx,int ly)306 TileOffsets::operator () (int dx, int dy, int lx, int ly)
307 {
308 //
309 // Looks up the value of the tile with tile coordinate (dx, dy)
310 // and level number (lx, ly) in the _offsets array, and returns
311 // the cooresponding offset.
312 //
313
314 switch (_mode)
315 {
316 case ONE_LEVEL:
317
318 return _offsets[0][dy][dx];
319 break;
320
321 case MIPMAP_LEVELS:
322
323 return _offsets[lx][dy][dx];
324 break;
325
326 case RIPMAP_LEVELS:
327
328 return _offsets[lx + ly * _numXLevels][dy][dx];
329 break;
330
331 default:
332
333 throw Iex::ArgExc ("Unknown LevelMode format.");
334 }
335 }
336
337
338 Int64 &
operator ()(int dx,int dy,int l)339 TileOffsets::operator () (int dx, int dy, int l)
340 {
341 return operator () (dx, dy, l, l);
342 }
343
344
345 const Int64 &
operator ()(int dx,int dy,int lx,int ly) const346 TileOffsets::operator () (int dx, int dy, int lx, int ly) const
347 {
348 //
349 // Looks up the value of the tile with tile coordinate (dx, dy)
350 // and level number (lx, ly) in the _offsets array, and returns
351 // the cooresponding offset.
352 //
353
354 switch (_mode)
355 {
356 case ONE_LEVEL:
357
358 return _offsets[0][dy][dx];
359 break;
360
361 case MIPMAP_LEVELS:
362
363 return _offsets[lx][dy][dx];
364 break;
365
366 case RIPMAP_LEVELS:
367
368 return _offsets[lx + ly * _numXLevels][dy][dx];
369 break;
370
371 default:
372
373 throw Iex::ArgExc ("Unknown LevelMode format.");
374 }
375 }
376
377
378 const Int64 &
operator ()(int dx,int dy,int l) const379 TileOffsets::operator () (int dx, int dy, int l) const
380 {
381 return operator () (dx, dy, l, l);
382 }
383
384
385 } // namespace Imf
386