GCC Code Coverage Report


Directory: ./
File: openvdb/openvdb/io/Archive.cc
Date: 2022-07-25 17:40:05
Exec Total Coverage
Lines: 400 525 76.2%
Functions: 80 122 65.6%
Branches: 315 728 43.3%

Line Branch Exec Source
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3
4 #include "Archive.h"
5
6 #include "GridDescriptor.h"
7 #include "DelayedLoadMetadata.h"
8 #include "io.h"
9
10 #include <openvdb/Exceptions.h>
11 #include <openvdb/Metadata.h>
12 #include <openvdb/tree/LeafManager.h>
13 #include <openvdb/util/logging.h>
14 #include <openvdb/openvdb.h>
15
16 // Boost.Interprocess uses a header-only portion of Boost.DateTime
17 #ifdef __clang__
18 #pragma clang diagnostic push
19 #pragma clang diagnostic ignored "-Wunused-macros"
20 #endif
21 #define BOOST_DATE_TIME_NO_LIB
22 #ifdef __clang__
23 #pragma clang diagnostic pop
24 #endif
25 #include <boost/interprocess/file_mapping.hpp>
26 #include <boost/interprocess/mapped_region.hpp>
27 #include <boost/iostreams/device/array.hpp>
28 #include <boost/iostreams/stream.hpp>
29 #include <boost/uuid/uuid_generators.hpp>
30 #include <boost/uuid/uuid_io.hpp>
31
32 #include <atomic>
33
34 #ifdef _WIN32
35 #include <boost/interprocess/detail/os_file_functions.hpp> // open_existing_file(), close_file()
36 extern "C" __declspec(dllimport) bool __stdcall GetFileTime(
37 void* fh, void* ctime, void* atime, void* mtime);
38 // boost::interprocess::detail was renamed to boost::interprocess::ipcdetail in Boost 1.48.
39 // Ensure that both namespaces exist.
40 namespace boost { namespace interprocess { namespace detail {} namespace ipcdetail {} } }
41 #else
42 #include <sys/types.h> // for struct stat
43 #include <sys/stat.h> // for stat()
44 #include <unistd.h> // for unlink()
45 #endif
46 #include <algorithm> // for std::find_if()
47 #include <cerrno> // for errno
48 #include <cstdlib> // for getenv()
49 #include <cstring> // for std::memcpy()
50 #include <ctime> // for std::time()
51 #include <iostream>
52 #include <map>
53 #include <random>
54 #include <set>
55 #include <sstream>
56 #include <system_error> // for std::error_code()
57
58
59 namespace openvdb {
60 OPENVDB_USE_VERSION_NAMESPACE
61 namespace OPENVDB_VERSION_NAME {
62 namespace io {
63
64 #ifdef OPENVDB_USE_BLOSC
65 const uint32_t Archive::DEFAULT_COMPRESSION_FLAGS = (COMPRESS_BLOSC | COMPRESS_ACTIVE_MASK);
66 #else
67 #ifdef OPENVDB_USE_ZLIB
68 const uint32_t Archive::DEFAULT_COMPRESSION_FLAGS = (COMPRESS_ZIP | COMPRESS_ACTIVE_MASK);
69 #else
70 const uint32_t Archive::DEFAULT_COMPRESSION_FLAGS = (COMPRESS_ACTIVE_MASK);
71 #endif
72 #endif
73
74
75 namespace {
76
77 // Indices into a stream's internal extensible array of values used by readers and writers
78 struct StreamState
79 {
80 static const long MAGIC_NUMBER;
81
82 StreamState();
83 ~StreamState();
84
85 // Important: The size and order of these member variables must *only* change when
86 // OpenVDB ABI changes to avoid potential segfaults when performing I/O
87 // across two different versions of the library. Adding new member
88 // variables to the end of the struct is allowed provided that they
89 // are only accessed from within an appropriate ABI guard.
90 int magicNumber;
91 int fileVersion;
92 int libraryMajorVersion;
93 int libraryMinorVersion;
94 int dataCompression;
95 int writeGridStatsMetadata;
96 int gridBackground;
97 int gridClass;
98 int halfFloat;
99 int mappedFile;
100 int metadata;
101 }
102 sStreamState;
103
104 const long StreamState::MAGIC_NUMBER =
105 long((uint64_t(OPENVDB_MAGIC) << 32) | (uint64_t(OPENVDB_MAGIC)));
106
107
108 ////////////////////////////////////////
109
110
111
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 StreamState::StreamState(): magicNumber(std::ios_base::xalloc())
112 {
113 // Having reserved an entry (the one at index magicNumber) in the extensible array
114 // associated with every stream, store a magic number at that location in the
115 // array belonging to the cout stream.
116 2 std::cout.iword(magicNumber) = MAGIC_NUMBER;
117
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
4 std::cout.pword(magicNumber) = this;
118
119 // Search for a lower-numbered entry in cout's array that already contains the magic number.
120 /// @todo This assumes that the indices returned by xalloc() increase monotonically.
121 int existingArray = -1;
122
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2 times.
10 for (int i = 0; i < magicNumber; ++i) {
123
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if (std::cout.iword(i) == MAGIC_NUMBER) {
124 existingArray = i;
125 break;
126 }
127 }
128
129
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2 if (existingArray >= 0 && std::cout.pword(existingArray) != nullptr) {
130 // If a lower-numbered entry was found to contain the magic number,
131 // a coexisting version of this library must have registered it.
132 // In that case, the corresponding pointer should point to an existing
133 // StreamState struct. Copy the other array indices from that StreamState
134 // into this one, so as to share state with the other library.
135 const StreamState& other =
136 *static_cast<const StreamState*>(std::cout.pword(existingArray));
137 fileVersion = other.fileVersion;
138 libraryMajorVersion = other.libraryMajorVersion;
139 libraryMinorVersion = other.libraryMinorVersion;
140 dataCompression = other.dataCompression;
141 writeGridStatsMetadata = other.writeGridStatsMetadata;
142 gridBackground = other.gridBackground;
143 gridClass = other.gridClass;
144 if (other.mappedFile != 0) { // memory-mapped file support was added in OpenVDB 3.0.0
145 mappedFile = other.mappedFile;
146 metadata = other.metadata;
147 halfFloat = other.halfFloat;
148 } else {
149 mappedFile = std::ios_base::xalloc();
150 metadata = std::ios_base::xalloc();
151 halfFloat = std::ios_base::xalloc();
152 }
153 } else {
154 // Reserve storage for per-stream file format and library version numbers
155 // and other values of use to readers and writers. Each of the following
156 // values is an index into the extensible arrays associated with all streams.
157 // The indices are common to all streams, but the values stored at those indices
158 // are unique to each stream.
159 2 fileVersion = std::ios_base::xalloc();
160 2 libraryMajorVersion = std::ios_base::xalloc();
161 2 libraryMinorVersion = std::ios_base::xalloc();
162 2 dataCompression = std::ios_base::xalloc();
163 2 writeGridStatsMetadata = std::ios_base::xalloc();
164 2 gridBackground = std::ios_base::xalloc();
165 2 gridClass = std::ios_base::xalloc();
166 2 mappedFile = std::ios_base::xalloc();
167 2 metadata = std::ios_base::xalloc();
168 2 halfFloat = std::ios_base::xalloc();
169 }
170 2 }
171
172
173 4 StreamState::~StreamState()
174 {
175 // Ensure that this StreamState struct can no longer be accessed.
176
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 std::cout.iword(magicNumber) = 0;
177
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 std::cout.pword(magicNumber) = nullptr;
178 2 }
179
180 } // unnamed namespace
181
182
183 ////////////////////////////////////////
184
185
186 struct StreamMetadata::Impl
187 {
188 // Important: The size and order of these member variables must *only* change when
189 // OpenVDB ABI changes to avoid potential segfaults when performing I/O
190 // across two different versions of the library. Adding new member
191 // variables to the end of the struct is allowed provided that they
192 // are only accessed from within an appropriate ABI guard.
193
194 uint32_t mFileVersion = OPENVDB_FILE_VERSION;
195 VersionId mLibraryVersion = { OPENVDB_LIBRARY_MAJOR_VERSION, OPENVDB_LIBRARY_MINOR_VERSION };
196 uint32_t mCompression = COMPRESS_NONE;
197 uint32_t mGridClass = GRID_UNKNOWN;
198 const void* mBackgroundPtr = nullptr; ///< @todo use Metadata::Ptr?
199 bool mHalfFloat = false;
200 bool mWriteGridStats = false;
201 bool mSeekable = false;
202 bool mCountingPasses = false;
203 uint32_t mPass = 0;
204 MetaMap mGridMetadata;
205 AuxDataMap mAuxData;
206 bool mDelayedLoadMeta = DelayedLoadMetadata::isRegisteredType();
207 uint64_t mLeaf = 0;
208 uint32_t mTest = 0; // for testing only
209 }; // struct StreamMetadata
210
211
212
1/2
✓ Branch 2 taken 137 times.
✗ Branch 3 not taken.
137 StreamMetadata::StreamMetadata(): mImpl(new Impl)
213 {
214 137 }
215
216
217
1/2
✓ Branch 2 taken 264 times.
✗ Branch 3 not taken.
264 StreamMetadata::StreamMetadata(const StreamMetadata& other): mImpl(new Impl(*other.mImpl))
218 {
219 264 }
220
221
222 StreamMetadata::StreamMetadata(std::ios_base& strm): mImpl(new Impl)
223 {
224 mImpl->mFileVersion = getFormatVersion(strm);
225 mImpl->mLibraryVersion = getLibraryVersion(strm);
226 mImpl->mCompression = getDataCompression(strm);
227 mImpl->mGridClass = getGridClass(strm);
228 mImpl->mHalfFloat = getHalfFloat(strm);
229 mImpl->mWriteGridStats = getWriteGridStatsMetadata(strm);
230 }
231
232
233 401 StreamMetadata::~StreamMetadata()
234 {
235 401 }
236
237
238 StreamMetadata&
239 StreamMetadata::operator=(const StreamMetadata& other)
240 {
241 if (&other != this) {
242 mImpl.reset(new Impl(*other.mImpl));
243 }
244 return *this;
245 }
246
247
248 void
249 19334 StreamMetadata::transferTo(std::ios_base& strm) const
250 {
251 19334 io::setVersion(strm, mImpl->mLibraryVersion, mImpl->mFileVersion);
252 19334 io::setDataCompression(strm, mImpl->mCompression);
253 19334 io::setGridBackgroundValuePtr(strm, mImpl->mBackgroundPtr);
254 19334 io::setGridClass(strm, mImpl->mGridClass);
255 19334 io::setHalfFloat(strm, mImpl->mHalfFloat);
256 19334 io::setWriteGridStatsMetadata(strm, mImpl->mWriteGridStats);
257 19334 }
258
259
260 uint32_t StreamMetadata::fileVersion() const { return mImpl->mFileVersion; }
261 VersionId StreamMetadata::libraryVersion() const { return mImpl->mLibraryVersion; }
262 uint32_t StreamMetadata::compression() const { return mImpl->mCompression; }
263 uint32_t StreamMetadata::gridClass() const { return mImpl->mGridClass; }
264 const void* StreamMetadata::backgroundPtr() const { return mImpl->mBackgroundPtr; }
265 bool StreamMetadata::halfFloat() const { return mImpl->mHalfFloat; }
266 bool StreamMetadata::writeGridStats() const { return mImpl->mWriteGridStats; }
267 48365 bool StreamMetadata::seekable() const { return mImpl->mSeekable; }
268 12654 bool StreamMetadata::delayedLoadMeta() const { return mImpl->mDelayedLoadMeta; }
269 55125 bool StreamMetadata::countingPasses() const { return mImpl->mCountingPasses; }
270 354253 uint32_t StreamMetadata::pass() const { return mImpl->mPass; }
271 35711 uint64_t StreamMetadata::leaf() const { return mImpl->mLeaf; }
272 12929 MetaMap& StreamMetadata::gridMetadata() { return mImpl->mGridMetadata; }
273 const MetaMap& StreamMetadata::gridMetadata() const { return mImpl->mGridMetadata; }
274 125 uint32_t StreamMetadata::__test() const { return mImpl->mTest; }
275
276 230382 StreamMetadata::AuxDataMap& StreamMetadata::auxData() { return mImpl->mAuxData; }
277 const StreamMetadata::AuxDataMap& StreamMetadata::auxData() const { return mImpl->mAuxData; }
278
279 19391 void StreamMetadata::setFileVersion(uint32_t v) { mImpl->mFileVersion = v; }
280 19391 void StreamMetadata::setLibraryVersion(VersionId v) { mImpl->mLibraryVersion = v; }
281 19965 void StreamMetadata::setCompression(uint32_t c) { mImpl->mCompression = c; }
282 19584 void StreamMetadata::setGridClass(uint32_t c) { mImpl->mGridClass = c; }
283 19717 void StreamMetadata::setBackgroundPtr(const void* ptr) { mImpl->mBackgroundPtr = ptr; }
284 19609 void StreamMetadata::setHalfFloat(bool b) { mImpl->mHalfFloat = b; }
285 19399 void StreamMetadata::setWriteGridStats(bool b) { mImpl->mWriteGridStats = b; }
286 56 void StreamMetadata::setSeekable(bool b) { mImpl->mSeekable = b; }
287 22 void StreamMetadata::setCountingPasses(bool b) { mImpl->mCountingPasses = b; }
288 20731 void StreamMetadata::setPass(uint32_t i) { mImpl->mPass = i; }
289 23182 void StreamMetadata::setLeaf(uint64_t i) { mImpl->mLeaf = i; }
290 1 void StreamMetadata::__setTest(uint32_t t) { mImpl->mTest = t; }
291
292 std::string
293 StreamMetadata::str() const
294 {
295 std::ostringstream ostr;
296 ostr << std::boolalpha;
297 ostr << "version: " << libraryVersion().first << "." << libraryVersion().second
298 << "/" << fileVersion() << "\n";
299 ostr << "class: " << GridBase::gridClassToString(static_cast<GridClass>(gridClass())) << "\n";
300 ostr << "compression: " << compressionToString(compression()) << "\n";
301 ostr << "half_float: " << halfFloat() << "\n";
302 ostr << "seekable: " << seekable() << "\n";
303 ostr << "delayed_load_meta: " << delayedLoadMeta() << "\n";
304 ostr << "pass: " << pass() << "\n";
305 ostr << "counting_passes: " << countingPasses() << "\n";
306 ostr << "write_grid_stats_metadata: " << writeGridStats() << "\n";
307 if (!auxData().empty()) ostr << auxData();
308 if (gridMetadata().metaCount() != 0) {
309 ostr << "grid_metadata:\n" << gridMetadata().str(/*indent=*/" ");
310 }
311 return ostr.str();
312 }
313
314
315 std::ostream&
316 operator<<(std::ostream& os, const StreamMetadata& meta)
317 {
318 os << meta.str();
319 return os;
320 }
321
322
323 namespace {
324
325 template<typename T>
326 inline bool
327 writeAsType(std::ostream& os, const boost::any& val)
328 {
329 if (val.type() == typeid(T)) {
330 os << boost::any_cast<T>(val);
331 return true;
332 }
333 return false;
334 }
335
336 struct PopulateDelayedLoadMetadataOp
337 {
338 DelayedLoadMetadata& metadata;
339 uint32_t compression;
340
341 PopulateDelayedLoadMetadataOp(DelayedLoadMetadata& _metadata, uint32_t _compression)
342 150 : metadata(_metadata)
343 150 , compression(_compression) { }
344
345 template<typename GridT>
346 266 void operator()(const GridT& grid) const
347 {
348 using TreeT = typename GridT::TreeType;
349 using ValueT = typename TreeT::ValueType;
350 using LeafT = typename TreeT::LeafNodeType;
351 using MaskT = typename LeafT::NodeMaskType;
352
353 const TreeT& tree = grid.constTree();
354 266 const Index32 leafCount = tree.leafCount();
355
356 // early exit if not leaf nodes
357
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 130 times.
266 if (leafCount == Index32(0)) return;
358
359 260 metadata.resizeMask(leafCount);
360
361
2/2
✓ Branch 0 taken 124 times.
✓ Branch 1 taken 6 times.
260 if (compression & (COMPRESS_BLOSC | COMPRESS_ZIP)) {
362 248 metadata.resizeCompressedSize(leafCount);
363 }
364
365 260 const auto background = tree.background();
366 260 const bool saveFloatAsHalf = grid.saveFloatAsHalf();
367
368 260 tree::LeafManager<const TreeT> leafManager(tree);
369
370
1/2
✓ Branch 1 taken 130 times.
✗ Branch 2 not taken.
260 leafManager.foreach(
371 23803 [&](const LeafT& leaf, size_t idx) {
372 // set mask value
373 47606 MaskCompress<ValueT, MaskT> maskCompressData(
374 leaf.valueMask(), /*childMask=*/MaskT(), leaf.buffer().data(), background);
375 23803 metadata.setMask(idx, maskCompressData.metadata);
376
377
5/14
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 366 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 21063 times.
✓ Branch 9 taken 606 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 1194 times.
✓ Branch 13 taken 574 times.
23803 if (compression & (COMPRESS_BLOSC | COMPRESS_ZIP)) {
378 // set compressed size value
379 size_t sizeBytes(8);
380 22623 size_t compressedSize = io::writeCompressedValuesSize(
381 leaf.buffer().data(), LeafT::SIZE,
382 22623 leaf.valueMask(), maskCompressData.metadata, saveFloatAsHalf, compression);
383 22623 metadata.setCompressedSize(idx, compressedSize+sizeBytes);
384 }
385 }
386 );
387 }
388 };
389
390 150 bool populateDelayedLoadMetadata(DelayedLoadMetadata& metadata,
391 const GridBase& gridBase, uint32_t compression)
392 {
393 PopulateDelayedLoadMetadataOp op(metadata, compression);
394
395 using AllowedTypes = TypeList<
396 Int32Grid, Int64Grid,
397 FloatGrid, DoubleGrid,
398 Vec3IGrid, Vec3SGrid, Vec3DGrid>;
399
400 150 return gridBase.apply<AllowedTypes>(op);
401 }
402
403 } // unnamed namespace
404
405 std::ostream&
406 operator<<(std::ostream& os, const StreamMetadata::AuxDataMap& auxData)
407 {
408 for (StreamMetadata::AuxDataMap::const_iterator it = auxData.begin(), end = auxData.end();
409 it != end; ++it)
410 {
411 os << it->first << ": ";
412 // Note: boost::any doesn't support serialization.
413 const boost::any& val = it->second;
414 if (!writeAsType<int32_t>(os, val)
415 && !writeAsType<int64_t>(os, val)
416 && !writeAsType<int16_t>(os, val)
417 && !writeAsType<int8_t>(os, val)
418 && !writeAsType<uint32_t>(os, val)
419 && !writeAsType<uint64_t>(os, val)
420 && !writeAsType<uint16_t>(os, val)
421 && !writeAsType<uint8_t>(os, val)
422 && !writeAsType<float>(os, val)
423 && !writeAsType<double>(os, val)
424 && !writeAsType<long double>(os, val)
425 && !writeAsType<bool>(os, val)
426 && !writeAsType<std::string>(os, val)
427 && !writeAsType<const char*>(os, val))
428 {
429 os << val.type().name() << "(...)";
430 }
431 os << "\n";
432 }
433 return os;
434 }
435
436
437 ////////////////////////////////////////
438
439
440 // Memory-mapping a VDB file permits threaded input (and output, potentially,
441 // though that might not be practical for compressed files or files containing
442 // multiple grids). In particular, a memory-mapped file can be loaded lazily,
443 // meaning that the voxel buffers of the leaf nodes of a grid's tree are not allocated
444 // until they are actually accessed. When access to its buffer is requested,
445 // a leaf node allocates memory for the buffer and then streams in (and decompresses)
446 // its contents from the memory map, starting from a stream offset that was recorded
447 // at the time the node was constructed. The memory map must persist as long as
448 // there are unloaded leaf nodes; this is ensured by storing a shared pointer
449 // to the map in each unloaded node.
450
451 class MappedFile::Impl
452 {
453 public:
454 62 Impl(const std::string& filename, bool autoDelete)
455 62 : mMap(filename.c_str(), boost::interprocess::read_only)
456 , mRegion(mMap, boost::interprocess::read_only)
457
1/2
✓ Branch 2 taken 62 times.
✗ Branch 3 not taken.
62 , mAutoDelete(autoDelete)
458 {
459 mLastWriteTime = this->getLastWriteTime();
460
461
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 8 times.
62 if (mAutoDelete) {
462 #ifndef _WIN32
463 // On Unix systems, unlink the file so that it gets deleted once it is closed.
464 54 ::unlink(mMap.get_name());
465 #endif
466 }
467 62 }
468
469
1/2
✓ Branch 0 taken 63 times.
✗ Branch 1 not taken.
63 ~Impl()
470 63 {
471 std::string filename;
472
1/2
✓ Branch 0 taken 63 times.
✗ Branch 1 not taken.
63 if (const char* s = mMap.get_name()) filename = s;
473 OPENVDB_LOG_DEBUG_RUNTIME("closing memory-mapped file " << filename);
474
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 60 times.
66 if (mNotifier) mNotifier(filename);
475
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 9 times.
63 if (mAutoDelete) {
476
1/2
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
54 if (!boost::interprocess::file_mapping::remove(filename.c_str())) {
477
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
54 if (errno != ENOENT) {
478 // Warn if the file exists but couldn't be removed.
479 std::string mesg = getErrorString();
480 if (!mesg.empty()) mesg = " (" + mesg + ")";
481 OPENVDB_LOG_WARN("failed to remove temporary file " << filename << mesg);
482 }
483 }
484 }
485 63 }
486
487 Index64 getLastWriteTime() const
488 {
489 Index64 result = 0;
490 const char* filename = mMap.get_name();
491
492 #ifdef _WIN32
493 // boost::interprocess::detail was renamed to boost::interprocess::ipcdetail in Boost 1.48.
494 using namespace boost::interprocess::detail;
495 using namespace boost::interprocess::ipcdetail;
496
497 if (void* fh = open_existing_file(filename, boost::interprocess::read_only)) {
498 struct { unsigned long lo, hi; } mtime; // Windows FILETIME struct
499 if (GetFileTime(fh, nullptr, nullptr, &mtime)) {
500 result = (Index64(mtime.hi) << 32) | mtime.lo;
501 }
502 close_file(fh);
503 }
504 #else
505 struct stat info;
506
2/4
✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 62 times.
✗ Branch 3 not taken.
88 if (0 == ::stat(filename, &info)) {
507 88 result = Index64(info.st_mtime);
508 }
509 #endif
510 return result;
511 }
512
513 boost::interprocess::file_mapping mMap;
514 boost::interprocess::mapped_region mRegion;
515 bool mAutoDelete;
516 Notifier mNotifier;
517 mutable std::atomic<Index64> mLastWriteTime;
518
519 private:
520 Impl(const Impl&); // not copyable
521 Impl& operator=(const Impl&); // not copyable
522 };
523
524
525 62 MappedFile::MappedFile(const std::string& filename, bool autoDelete):
526
1/2
✓ Branch 2 taken 62 times.
✗ Branch 3 not taken.
62 mImpl(new Impl(filename, autoDelete))
527 {
528 62 }
529
530
531 63 MappedFile::~MappedFile()
532 {
533 63 }
534
535
536 std::string
537
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 MappedFile::filename() const
538 {
539 std::string result;
540
2/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
5 if (const char* s = mImpl->mMap.get_name()) result = s;
541 5 return result;
542 }
543
544
545 SharedPtr<std::streambuf>
546
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 19333 times.
19359 MappedFile::createBuffer() const
547 {
548
3/4
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 19333 times.
✓ Branch 2 taken 26 times.
✗ Branch 3 not taken.
19359 if (!mImpl->mAutoDelete && mImpl->mLastWriteTime > 0) {
549 // Warn if the file has been modified since it was opened
550 // (but don't bother checking if it is a private, temporary file).
551
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
26 if (mImpl->getLastWriteTime() > mImpl->mLastWriteTime) {
552 OPENVDB_LOG_WARN("file " << this->filename() << " might have changed on disk"
553 << " since it was opened");
554 mImpl->mLastWriteTime = 0; // suppress further warnings
555 }
556 }
557
558 return SharedPtr<std::streambuf>{
559 new boost::iostreams::stream_buffer<boost::iostreams::array_source>{
560
1/2
✓ Branch 2 taken 19359 times.
✗ Branch 3 not taken.
38718 static_cast<const char*>(mImpl->mRegion.get_address()), mImpl->mRegion.get_size()}};
561 }
562
563
564 void
565 56 MappedFile::setNotifier(const Notifier& notifier)
566 {
567 56 mImpl->mNotifier = notifier;
568 56 }
569
570
571 void
572 MappedFile::clearNotifier()
573 {
574 mImpl->mNotifier = nullptr;
575 }
576
577
578 ////////////////////////////////////////
579
580
581 std::string
582 1 getErrorString(int errorNum)
583 {
584 1 return std::error_code(errorNum, std::generic_category()).message();
585 }
586
587
588 std::string
589 1 getErrorString()
590 {
591 1 return getErrorString(errno);
592 }
593
594
595 ////////////////////////////////////////
596
597
598 129 Archive::Archive()
599 : mFileVersion(OPENVDB_FILE_VERSION)
600 , mLibraryVersion(OPENVDB_LIBRARY_MAJOR_VERSION, OPENVDB_LIBRARY_MINOR_VERSION)
601 129 , mUuid(boost::uuids::nil_uuid())
602 , mInputHasGridOffsets(false)
603 , mEnableInstancing(true)
604 , mCompression(DEFAULT_COMPRESSION_FLAGS)
605 129 , mEnableGridStats(true)
606 {
607 129 }
608
609
610 298 Archive::~Archive()
611 {
612 }
613
614
615 Archive::Ptr
616 Archive::copy() const
617 {
618 return Archive::Ptr(new Archive(*this));
619 }
620
621
622 ////////////////////////////////////////
623
624
625 std::string
626 5 Archive::getUniqueTag() const
627 {
628 5 return boost::uuids::to_string(mUuid);
629 }
630
631
632 bool
633 2 Archive::isIdentical(const std::string& uuidStr) const
634 {
635 2 return uuidStr == getUniqueTag();
636 }
637
638
639 ////////////////////////////////////////
640
641
642 uint32_t
643 63455 getFormatVersion(std::ios_base& is)
644 {
645 /// @todo get from StreamMetadata
646
1/2
✓ Branch 0 taken 63455 times.
✗ Branch 1 not taken.
63455 return static_cast<uint32_t>(is.iword(sStreamState.fileVersion));
647 }
648
649
650 void
651 56 Archive::setFormatVersion(std::istream& is)
652 {
653
1/2
✓ Branch 0 taken 56 times.
✗ Branch 1 not taken.
56 is.iword(sStreamState.fileVersion) = mFileVersion; ///< @todo remove
654
1/2
✓ Branch 1 taken 56 times.
✗ Branch 2 not taken.
56 if (StreamMetadata::Ptr meta = getStreamMetadataPtr(is)) {
655
1/2
✓ Branch 1 taken 56 times.
✗ Branch 2 not taken.
56 meta->setFileVersion(mFileVersion);
656 }
657 56 }
658
659
660 VersionId
661
1/2
✓ Branch 0 taken 127 times.
✗ Branch 1 not taken.
127 getLibraryVersion(std::ios_base& is)
662 {
663 /// @todo get from StreamMetadata
664 VersionId version;
665
1/2
✓ Branch 0 taken 127 times.
✗ Branch 1 not taken.
127 version.first = static_cast<uint32_t>(is.iword(sStreamState.libraryMajorVersion));
666
1/2
✓ Branch 0 taken 127 times.
✗ Branch 1 not taken.
127 version.second = static_cast<uint32_t>(is.iword(sStreamState.libraryMinorVersion));
667 127 return version;
668 }
669
670
671 void
672 56 Archive::setLibraryVersion(std::istream& is)
673 {
674
1/2
✓ Branch 0 taken 56 times.
✗ Branch 1 not taken.
56 is.iword(sStreamState.libraryMajorVersion) = mLibraryVersion.first; ///< @todo remove
675
1/2
✓ Branch 0 taken 56 times.
✗ Branch 1 not taken.
56 is.iword(sStreamState.libraryMinorVersion) = mLibraryVersion.second; ///< @todo remove
676
1/2
✓ Branch 1 taken 56 times.
✗ Branch 2 not taken.
56 if (StreamMetadata::Ptr meta = getStreamMetadataPtr(is)) {
677
1/2
✓ Branch 1 taken 56 times.
✗ Branch 2 not taken.
56 meta->setLibraryVersion(mLibraryVersion);
678 }
679 56 }
680
681
682 std::string
683 getVersion(std::ios_base& is)
684 {
685 VersionId version = getLibraryVersion(is);
686 std::ostringstream ostr;
687 ostr << version.first << "." << version.second << "/" << getFormatVersion(is);
688 return ostr.str();
689 }
690
691
692 void
693 28 setCurrentVersion(std::istream& is)
694 {
695
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 is.iword(sStreamState.fileVersion) = OPENVDB_FILE_VERSION; ///< @todo remove
696
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 is.iword(sStreamState.libraryMajorVersion) = OPENVDB_LIBRARY_MAJOR_VERSION; ///< @todo remove
697
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 is.iword(sStreamState.libraryMinorVersion) = OPENVDB_LIBRARY_MINOR_VERSION; ///< @todo remove
698
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 27 times.
28 if (StreamMetadata::Ptr meta = getStreamMetadataPtr(is)) {
699
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 meta->setFileVersion(OPENVDB_FILE_VERSION);
700
1/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
1 meta->setLibraryVersion(VersionId(
701 OPENVDB_LIBRARY_MAJOR_VERSION, OPENVDB_LIBRARY_MINOR_VERSION));
702 }
703 28 }
704
705
706 void
707 19341 setVersion(std::ios_base& strm, const VersionId& libraryVersion, uint32_t fileVersion)
708 {
709
1/2
✓ Branch 0 taken 19341 times.
✗ Branch 1 not taken.
19341 strm.iword(sStreamState.fileVersion) = fileVersion; ///< @todo remove
710
1/2
✓ Branch 0 taken 19341 times.
✗ Branch 1 not taken.
19341 strm.iword(sStreamState.libraryMajorVersion) = libraryVersion.first; ///< @todo remove
711
1/2
✓ Branch 0 taken 19341 times.
✗ Branch 1 not taken.
19341 strm.iword(sStreamState.libraryMinorVersion) = libraryVersion.second; ///< @todo remove
712
2/2
✓ Branch 1 taken 19334 times.
✓ Branch 2 taken 7 times.
19341 if (StreamMetadata::Ptr meta = getStreamMetadataPtr(strm)) {
713
1/2
✓ Branch 1 taken 19334 times.
✗ Branch 2 not taken.
19334 meta->setFileVersion(fileVersion);
714
1/2
✓ Branch 1 taken 19334 times.
✗ Branch 2 not taken.
19334 meta->setLibraryVersion(libraryVersion);
715 }
716 19341 }
717
718
719 std::string
720 Archive::version() const
721 {
722 std::ostringstream ostr;
723 ostr << mLibraryVersion.first << "." << mLibraryVersion.second << "/" << mFileVersion;
724 return ostr.str();
725 }
726
727
728 ////////////////////////////////////////
729
730
731 uint32_t
732 110748 getDataCompression(std::ios_base& strm)
733 {
734 /// @todo get from StreamMetadata
735
2/2
✓ Branch 0 taken 110712 times.
✓ Branch 1 taken 36 times.
110748 return uint32_t(strm.iword(sStreamState.dataCompression));
736 }
737
738
739 void
740 19918 setDataCompression(std::ios_base& strm, uint32_t c)
741 {
742
2/2
✓ Branch 0 taken 19916 times.
✓ Branch 1 taken 2 times.
19918 strm.iword(sStreamState.dataCompression) = c; ///< @todo remove
743
2/2
✓ Branch 1 taken 19909 times.
✓ Branch 2 taken 9 times.
19918 if (StreamMetadata::Ptr meta = getStreamMetadataPtr(strm)) {
744
1/2
✓ Branch 1 taken 19909 times.
✗ Branch 2 not taken.
19909 meta->setCompression(c);
745 }
746 19918 }
747
748
749 void
750 56 Archive::setDataCompression(std::istream& is)
751 {
752 56 io::setDataCompression(is, mCompression); ///< @todo remove
753
1/2
✓ Branch 1 taken 56 times.
✗ Branch 2 not taken.
56 if (StreamMetadata::Ptr meta = getStreamMetadataPtr(is)) {
754
1/2
✓ Branch 1 taken 56 times.
✗ Branch 2 not taken.
56 meta->setCompression(mCompression);
755 }
756 56 }
757
758
759 //static
760 bool
761 1 Archive::hasBloscCompression()
762 {
763 #ifdef OPENVDB_USE_BLOSC
764 1 return true;
765 #else
766 return false;
767 #endif
768 }
769
770
771 //static
772 bool
773 Archive::hasZLibCompression()
774 {
775 #ifdef OPENVDB_USE_ZLIB
776 return true;
777 #else
778 return false;
779 #endif
780 }
781
782
783 void
784 163 Archive::setGridCompression(std::ostream& os, const GridBase& grid) const
785 {
786 // Start with the options that are enabled globally for this archive.
787 163 uint32_t c = compression();
788
789 // Disable options that are inappropriate for the given grid.
790
2/2
✓ Branch 1 taken 79 times.
✓ Branch 2 taken 84 times.
163 switch (grid.getGridClass()) {
791 79 case GRID_LEVEL_SET:
792 case GRID_FOG_VOLUME:
793 // ZLIB compression is not used on level sets or fog volumes.
794 79 c = c & ~COMPRESS_ZIP;
795 79 break;
796 case GRID_STAGGERED:
797 case GRID_UNKNOWN:
798 break;
799 }
800 163 io::setDataCompression(os, c);
801
802 163 os.write(reinterpret_cast<const char*>(&c), sizeof(uint32_t));
803 163 }
804
805
806 void
807 134 Archive::readGridCompression(std::istream& is)
808 {
809
1/2
✓ Branch 1 taken 134 times.
✗ Branch 2 not taken.
134 if (getFormatVersion(is) >= OPENVDB_FILE_VERSION_NODE_MASK_COMPRESSION) {
810 134 uint32_t c = COMPRESS_NONE;
811 134 is.read(reinterpret_cast<char*>(&c), sizeof(uint32_t));
812 134 io::setDataCompression(is, c);
813 }
814 134 }
815
816
817 ////////////////////////////////////////
818
819
820 bool
821 150 getWriteGridStatsMetadata(std::ios_base& strm)
822 {
823 /// @todo get from StreamMetadata
824
1/2
✓ Branch 0 taken 150 times.
✗ Branch 1 not taken.
150 return strm.iword(sStreamState.writeGridStatsMetadata) != 0;
825 }
826
827
828 void
829 19399 setWriteGridStatsMetadata(std::ios_base& strm, bool writeGridStats)
830 {
831
1/2
✓ Branch 0 taken 19399 times.
✗ Branch 1 not taken.
19399 strm.iword(sStreamState.writeGridStatsMetadata) = writeGridStats; ///< @todo remove
832
1/2
✓ Branch 1 taken 19399 times.
✗ Branch 2 not taken.
19399 if (StreamMetadata::Ptr meta = getStreamMetadataPtr(strm)) {
833
1/2
✓ Branch 1 taken 19399 times.
✗ Branch 2 not taken.
19399 meta->setWriteGridStats(writeGridStats);
834 }
835 19399 }
836
837
838 ////////////////////////////////////////
839
840
841 uint32_t
842 getGridClass(std::ios_base& strm)
843 {
844 /// @todo get from StreamMetadata
845 const uint32_t val = static_cast<uint32_t>(strm.iword(sStreamState.gridClass));
846 if (val >= NUM_GRID_CLASSES) return GRID_UNKNOWN;
847 return val;
848 }
849
850
851 void
852 19584 setGridClass(std::ios_base& strm, uint32_t cls)
853 {
854
1/2
✓ Branch 0 taken 19584 times.
✗ Branch 1 not taken.
19584 strm.iword(sStreamState.gridClass) = long(cls); ///< @todo remove
855
1/2
✓ Branch 1 taken 19584 times.
✗ Branch 2 not taken.
19584 if (StreamMetadata::Ptr meta = getStreamMetadataPtr(strm)) {
856
1/2
✓ Branch 1 taken 19584 times.
✗ Branch 2 not taken.
19584 meta->setGridClass(cls);
857 }
858 19584 }
859
860
861 bool
862 18978 getHalfFloat(std::ios_base& strm)
863 {
864 /// @todo get from StreamMetadata
865
1/2
✓ Branch 0 taken 18978 times.
✗ Branch 1 not taken.
18978 return strm.iword(sStreamState.halfFloat) != 0;
866 }
867
868
869 void
870 19334 setHalfFloat(std::ios_base& strm, bool halfFloat)
871 {
872
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 19333 times.
19334 strm.iword(sStreamState.halfFloat) = halfFloat; ///< @todo remove
873
1/2
✓ Branch 1 taken 19334 times.
✗ Branch 2 not taken.
19334 if (StreamMetadata::Ptr meta = getStreamMetadataPtr(strm)) {
874
1/2
✓ Branch 1 taken 19334 times.
✗ Branch 2 not taken.
19334 meta->setHalfFloat(halfFloat);
875 }
876 19334 }
877
878
879 const void*
880 48744 getGridBackgroundValuePtr(std::ios_base& strm)
881 {
882 /// @todo get from StreamMetadata
883
1/2
✓ Branch 0 taken 48744 times.
✗ Branch 1 not taken.
48744 return strm.pword(sStreamState.gridBackground);
884 }
885
886
887 void
888 19724 setGridBackgroundValuePtr(std::ios_base& strm, const void* background)
889 {
890
2/2
✓ Branch 0 taken 19723 times.
✓ Branch 1 taken 1 times.
19724 strm.pword(sStreamState.gridBackground) = const_cast<void*>(background); ///< @todo remove
891
2/2
✓ Branch 1 taken 19717 times.
✓ Branch 2 taken 7 times.
19724 if (StreamMetadata::Ptr meta = getStreamMetadataPtr(strm)) {
892
1/2
✓ Branch 1 taken 19717 times.
✗ Branch 2 not taken.
19717 meta->setBackgroundPtr(background);
893 }
894 19724 }
895
896
897 MappedFile::Ptr
898 100148 getMappedFilePtr(std::ios_base& strm)
899 {
900
4/4
✓ Branch 0 taken 100147 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 96030 times.
✓ Branch 3 taken 4118 times.
200296 if (const void* ptr = strm.pword(sStreamState.mappedFile)) {
901 return *static_cast<const MappedFile::Ptr*>(ptr);
902 }
903 return MappedFile::Ptr();
904 }
905
906
907 void
908 76 setMappedFilePtr(std::ios_base& strm, io::MappedFile::Ptr& mappedFile)
909 {
910
1/2
✓ Branch 0 taken 76 times.
✗ Branch 1 not taken.
76 strm.pword(sStreamState.mappedFile) = &mappedFile;
911 76 }
912
913
914 StreamMetadata::Ptr
915 386261 getStreamMetadataPtr(std::ios_base& strm)
916 {
917
4/4
✓ Branch 0 taken 386157 times.
✓ Branch 1 taken 104 times.
✓ Branch 2 taken 377902 times.
✓ Branch 3 taken 8359 times.
772522 if (const void* ptr = strm.pword(sStreamState.metadata)) {
918 return *static_cast<const StreamMetadata::Ptr*>(ptr);
919 }
920 return StreamMetadata::Ptr();
921 }
922
923
924 void
925 19738 setStreamMetadataPtr(std::ios_base& strm, StreamMetadata::Ptr& meta, bool transfer)
926 {
927
2/2
✓ Branch 0 taken 350 times.
✓ Branch 1 taken 19388 times.
19738 strm.pword(sStreamState.metadata) = &meta;
928
4/4
✓ Branch 0 taken 19337 times.
✓ Branch 1 taken 401 times.
✓ Branch 2 taken 19334 times.
✓ Branch 3 taken 3 times.
19738 if (transfer && meta) meta->transferTo(strm);
929 19738 }
930
931
932 StreamMetadata::Ptr
933 clearStreamMetadataPtr(std::ios_base& strm)
934 {
935 StreamMetadata::Ptr result = getStreamMetadataPtr(strm);
936 strm.pword(sStreamState.metadata) = nullptr;
937 return result;
938 }
939
940
941 ////////////////////////////////////////
942
943
944 bool
945 58 Archive::readHeader(std::istream& is)
946 {
947 // 1) Read the magic number for VDB.
948 int64_t magic;
949 58 is.read(reinterpret_cast<char*>(&magic), sizeof(int64_t));
950
951
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 57 times.
58 if (magic != OPENVDB_MAGIC) {
952
2/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
4 OPENVDB_THROW(IoError, "not a VDB file");
953 }
954
955 // 2) Read the file format version number.
956 57 is.read(reinterpret_cast<char*>(&mFileVersion), sizeof(uint32_t));
957
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 57 times.
57 if (mFileVersion > OPENVDB_FILE_VERSION) {
958 OPENVDB_LOG_WARN("unsupported VDB file format (expected version "
959 << OPENVDB_FILE_VERSION << " or earlier, got version " << mFileVersion << ")");
960
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 57 times.
57 } else if (mFileVersion < 211) {
961 // Versions prior to 211 stored separate major, minor and patch numbers.
962 uint32_t version;
963 is.read(reinterpret_cast<char*>(&version), sizeof(uint32_t));
964 mFileVersion = 100 * mFileVersion + 10 * version;
965 is.read(reinterpret_cast<char*>(&version), sizeof(uint32_t));
966 mFileVersion += version;
967 }
968
969 // 3) Read the library version numbers (not stored prior to file format version 211).
970 57 mLibraryVersion.first = mLibraryVersion.second = 0;
971
1/2
✓ Branch 0 taken 57 times.
✗ Branch 1 not taken.
57 if (mFileVersion >= 211) {
972 uint32_t version;
973 57 is.read(reinterpret_cast<char*>(&version), sizeof(uint32_t));
974 57 mLibraryVersion.first = version; // major version
975 57 is.read(reinterpret_cast<char*>(&version), sizeof(uint32_t));
976 57 mLibraryVersion.second = version; // minor version
977 }
978
979 // 4) Read the flag indicating whether the stream supports partial reading.
980 // (Versions prior to 212 have no flag because they always supported partial reading.)
981 57 mInputHasGridOffsets = true;
982
1/2
✓ Branch 0 taken 57 times.
✗ Branch 1 not taken.
57 if (mFileVersion >= 212) {
983 char hasGridOffsets;
984 57 is.read(&hasGridOffsets, sizeof(char));
985 57 mInputHasGridOffsets = hasGridOffsets;
986 }
987
988 // 5) Read the flag that indicates whether data is compressed.
989 // (From version 222 on, compression information is stored per grid.)
990 57 mCompression = DEFAULT_COMPRESSION_FLAGS;
991
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 57 times.
57 if (mFileVersion < OPENVDB_FILE_VERSION_BLOSC_COMPRESSION) {
992 // Prior to the introduction of Blosc, ZLIB was the default compression scheme.
993 mCompression = (COMPRESS_ZIP | COMPRESS_ACTIVE_MASK);
994 }
995
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 57 times.
57 if (mFileVersion >= OPENVDB_FILE_VERSION_SELECTIVE_COMPRESSION &&
996 mFileVersion < OPENVDB_FILE_VERSION_NODE_MASK_COMPRESSION)
997 {
998 char isCompressed;
999 is.read(&isCompressed, sizeof(char));
1000 mCompression = (isCompressed != 0 ? COMPRESS_ZIP : COMPRESS_NONE);
1001 }
1002
1003 // 6) Read the 16-byte (128-bit) uuid.
1004 57 boost::uuids::uuid oldUuid = mUuid;
1005
1/2
✓ Branch 0 taken 57 times.
✗ Branch 1 not taken.
57 if (mFileVersion >= OPENVDB_FILE_VERSION_BOOST_UUID) {
1006 // UUID is stored as an ASCII string.
1007 57 is >> mUuid;
1008 } else {
1009 // Older versions stored the UUID as a byte string.
1010 char uuidBytes[16];
1011 is.read(uuidBytes, 16);
1012 std::memcpy(&mUuid.data[0], uuidBytes, std::min<size_t>(16, mUuid.size()));
1013 }
1014 57 return oldUuid != mUuid; // true if UUID in input stream differs from old UUID
1015 }
1016
1017
1018 void
1019 67 Archive::writeHeader(std::ostream& os, bool seekable) const
1020 {
1021 // 1) Write the magic number for VDB.
1022 67 int64_t magic = OPENVDB_MAGIC;
1023 67 os.write(reinterpret_cast<char*>(&magic), sizeof(int64_t));
1024
1025 // 2) Write the file format version number.
1026 67 uint32_t version = OPENVDB_FILE_VERSION;
1027 67 os.write(reinterpret_cast<char*>(&version), sizeof(uint32_t));
1028
1029 // 3) Write the library version numbers.
1030 67 version = OPENVDB_LIBRARY_MAJOR_VERSION;
1031 67 os.write(reinterpret_cast<char*>(&version), sizeof(uint32_t));
1032 67 version = OPENVDB_LIBRARY_MINOR_VERSION;
1033 67 os.write(reinterpret_cast<char*>(&version), sizeof(uint32_t));
1034
1035 // 4) Write a flag indicating that this stream contains no grid offsets.
1036 67 char hasGridOffsets = seekable;
1037 67 os.write(&hasGridOffsets, sizeof(char));
1038
1039 // 5) Write a flag indicating that this stream contains compressed leaf data.
1040 // (Omitted as of version 222)
1041
1042 // 6) Generate a new random 16-byte (128-bit) uuid and write it to the stream.
1043 std::mt19937 ran;
1044 134 ran.seed(std::mt19937::result_type(std::random_device()() + std::time(nullptr)));
1045 67 boost::uuids::basic_random_generator<std::mt19937> gen(&ran);
1046 67 mUuid = gen(); // mUuid is mutable
1047
1/2
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
67 os << mUuid;
1048 67 }
1049
1050
1051 ////////////////////////////////////////
1052
1053
1054 int32_t
1055 58 Archive::readGridCount(std::istream& is)
1056 {
1057 58 int32_t gridCount = 0;
1058 58 is.read(reinterpret_cast<char*>(&gridCount), sizeof(int32_t));
1059 58 return gridCount;
1060 }
1061
1062
1063 ////////////////////////////////////////
1064
1065
1066 void
1067
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 61 times.
70 Archive::connectInstance(const GridDescriptor& gd, const NamedGridMap& grids) const
1068 {
1069
3/4
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 61 times.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
70 if (!gd.isInstance() || grids.empty()) return;
1070
1071
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 NamedGridMap::const_iterator it = grids.find(gd.uniqueName());
1072
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 if (it == grids.end()) return;
1073 GridBase::Ptr grid = it->second;
1074
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (!grid) return;
1075
1076
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 it = grids.find(gd.instanceParentName());
1077
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 if (it != grids.end()) {
1078 GridBase::Ptr parent = it->second;
1079
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 2 times.
9 if (mEnableInstancing) {
1080 // Share the instance parent's tree.
1081
2/4
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
14 grid->setTree(parent->baseTreePtr());
1082 } else {
1083 // Copy the instance parent's tree.
1084
3/8
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
4 grid->setTree(parent->baseTree().copy());
1085 }
1086 } else {
1087 OPENVDB_THROW(KeyError, "missing instance parent \""
1088 << GridDescriptor::nameAsString(gd.instanceParentName())
1089 << "\" for grid " << GridDescriptor::nameAsString(gd.uniqueName()));
1090 }
1091 }
1092
1093
1094 ////////////////////////////////////////
1095
1096
1097 //static
1098 bool
1099 62 Archive::isDelayedLoadingEnabled()
1100 {
1101 62 return (nullptr == std::getenv("OPENVDB_DISABLE_DELAYED_LOAD"));
1102 }
1103
1104
1105 namespace {
1106
1107 struct NoBBox {};
1108
1109 template<typename BoxType>
1110 void
1111 250 doReadGrid(GridBase::Ptr grid, const GridDescriptor& gd, std::istream& is, const BoxType& bbox)
1112 {
1113 struct Local {
1114
1/4
✓ Branch 1 taken 103 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
206 static void readBuffers(GridBase& g, std::istream& istrm, NoBBox) { g.readBuffers(istrm); }
1115 static void readBuffers(GridBase& g, std::istream& istrm, const CoordBBox& indexBBox) {
1116 g.readBuffers(istrm, indexBBox);
1117 }
1118 5 static void readBuffers(GridBase& g, std::istream& istrm, const BBoxd& worldBBox) {
1119 5 g.readBuffers(istrm, g.constTransform().worldToIndexNodeCentered(worldBBox));
1120 }
1121 };
1122
1123 // Restore the file-level stream metadata on exit.
1124 struct OnExit {
1125 125 OnExit(std::ios_base& strm_): strm(&strm_), ptr(strm_.pword(sStreamState.metadata)) {}
1126 125 ~OnExit() { strm->pword(sStreamState.metadata) = ptr; }
1127 std::ios_base* strm;
1128 void* ptr;
1129 };
1130 500 OnExit restore(is);
1131
1132 // Stream metadata varies per grid, and it needs to persist
1133 // in case delayed load is in effect.
1134 250 io::StreamMetadata::Ptr streamMetadata;
1135
3/4
✓ Branch 1 taken 125 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 123 times.
✓ Branch 4 taken 2 times.
250 if (io::StreamMetadata::Ptr meta = io::getStreamMetadataPtr(is)) {
1136 // Make a grid-level copy of the file-level stream metadata.
1137
3/6
✓ Branch 1 taken 123 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 123 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 123 times.
✗ Branch 8 not taken.
246 streamMetadata.reset(new StreamMetadata(*meta));
1138 } else {
1139
3/6
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
4 streamMetadata.reset(new StreamMetadata);
1140 }
1141
2/4
✓ Branch 1 taken 125 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 125 times.
✗ Branch 5 not taken.
250 streamMetadata->setHalfFloat(grid->saveFloatAsHalf());
1142
1/2
✓ Branch 1 taken 125 times.
✗ Branch 2 not taken.
250 io::setStreamMetadataPtr(is, streamMetadata, /*transfer=*/false);
1143
1144
1/2
✓ Branch 1 taken 125 times.
✗ Branch 2 not taken.
250 io::setGridClass(is, GRID_UNKNOWN);
1145
1/2
✓ Branch 1 taken 125 times.
✗ Branch 2 not taken.
250 io::setGridBackgroundValuePtr(is, nullptr);
1146
1147
1/2
✓ Branch 1 taken 125 times.
✗ Branch 2 not taken.
250 grid->readMeta(is);
1148
1149 // Add a description of the compression settings to the grid as metadata.
1150 /// @todo Would this be useful?
1151 //const uint32_t c = getDataCompression(is);
1152 //grid->insertMeta(GridBase::META_FILE_COMPRESSION,
1153 // StringMetadata(compressionToString(c)));
1154
1155
1/2
✓ Branch 1 taken 125 times.
✗ Branch 2 not taken.
250 const VersionId version = getLibraryVersion(is);
1156
6/6
✓ Branch 0 taken 123 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 121 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1 times.
250 if (version.first < 6 || (version.first == 6 && version.second <= 1)) {
1157 // If delay load metadata exists, but the file format version does not support
1158 // delay load metadata, this likely means the original grid was read and then
1159 // written using a prior version of OpenVDB and ABI>=5 where unknown metadata
1160 // can be blindly copied. This means that it is possible for the metadata to
1161 // no longer be in sync with the grid, so we remove it to ensure correctness.
1162
1163
2/4
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
12 if ((*grid)[GridBase::META_FILE_DELAYED_LOAD]) {
1164
2/4
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
12 grid->removeMeta(GridBase::META_FILE_DELAYED_LOAD);
1165 }
1166 }
1167
1168
2/4
✓ Branch 1 taken 125 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 125 times.
✗ Branch 5 not taken.
250 streamMetadata->gridMetadata() = static_cast<MetaMap&>(*grid);
1169
1/2
✓ Branch 1 taken 125 times.
✗ Branch 2 not taken.
250 const GridClass gridClass = grid->getGridClass();
1170
1/2
✓ Branch 1 taken 125 times.
✗ Branch 2 not taken.
250 io::setGridClass(is, gridClass);
1171
1172 // reset leaf value to zero
1173
1/2
✓ Branch 1 taken 125 times.
✗ Branch 2 not taken.
250 streamMetadata->setLeaf(0);
1174
1175 // drop DelayedLoadMetadata from the grid as it is only useful for IO
1176 // a stream metadata non-zero value disables this behaviour for testing
1177
1178
3/4
✓ Branch 1 taken 125 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 120 times.
✓ Branch 4 taken 5 times.
250 if (streamMetadata->__test() == uint32_t(0)) {
1179
3/6
✓ Branch 1 taken 120 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 76 times.
✓ Branch 6 taken 44 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
480 if ((*grid)[GridBase::META_FILE_DELAYED_LOAD]) {
1180
2/4
✓ Branch 1 taken 76 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 76 times.
✗ Branch 5 not taken.
304 grid->removeMeta(GridBase::META_FILE_DELAYED_LOAD);
1181 }
1182 }
1183
1184
2/4
✓ Branch 1 taken 125 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 125 times.
✗ Branch 4 not taken.
250 if (getFormatVersion(is) >= OPENVDB_FILE_VERSION_GRID_INSTANCING) {
1185 grid->readTransform(is);
1186
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 17 times.
250 if (!gd.isInstance()) {
1187
1/2
✓ Branch 1 taken 108 times.
✗ Branch 2 not taken.
216 grid->readTopology(is);
1188
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
10 Local::readBuffers(*grid, is, bbox);
1189 }
1190 } else {
1191 // Older versions of the library stored the transform after the topology.
1192 grid->readTopology(is);
1193 grid->readTransform(is);
1194 Local::readBuffers(*grid, is, bbox);
1195 }
1196
2/4
✓ Branch 1 taken 125 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 125 times.
250 if (getFormatVersion(is) < OPENVDB_FILE_VERSION_NO_GRIDMAP) {
1197 // Older versions of the library didn't store grid names as metadata,
1198 // so when reading older files, copy the grid name from the descriptor
1199 // to the grid's metadata.
1200 if (grid->getName().empty()) {
1201 grid->setName(gd.gridName());
1202 }
1203 }
1204 }
1205
1206 } // unnamed namespace
1207
1208
1209 void
1210 120 Archive::readGrid(GridBase::Ptr grid, const GridDescriptor& gd, std::istream& is)
1211 {
1212 // Read the compression settings for this grid and tag the stream with them
1213 // so that downstream functions can reference them.
1214 120 readGridCompression(is);
1215
1216
1/2
✓ Branch 1 taken 120 times.
✗ Branch 2 not taken.
120 doReadGrid(grid, gd, is, NoBBox());
1217 120 }
1218
1219 void
1220 5 Archive::readGrid(GridBase::Ptr grid, const GridDescriptor& gd,
1221 std::istream& is, const BBoxd& worldBBox)
1222 {
1223 5 readGridCompression(is);
1224
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 doReadGrid(grid, gd, is, worldBBox);
1225 5 }
1226
1227 void
1228 Archive::readGrid(GridBase::Ptr grid, const GridDescriptor& gd,
1229 std::istream& is, const CoordBBox& indexBBox)
1230 {
1231 readGridCompression(is);
1232 doReadGrid(grid, gd, is, indexBBox);
1233 }
1234
1235
1236 ////////////////////////////////////////
1237
1238
1239 void
1240 Archive::write(std::ostream& os, const GridPtrVec& grids, bool seekable,
1241 const MetaMap& metadata) const
1242 {
1243 this->write(os, GridCPtrVec(grids.begin(), grids.end()), seekable, metadata);
1244 }
1245
1246
1247 void
1248 65 Archive::write(std::ostream& os, const GridCPtrVec& grids, bool seekable,
1249 const MetaMap& metadata) const
1250 {
1251 // Set stream flags so that downstream functions can reference them.
1252 65 io::StreamMetadata::Ptr streamMetadata = io::getStreamMetadataPtr(os);
1253
1/2
✓ Branch 0 taken 65 times.
✗ Branch 1 not taken.
65 if (!streamMetadata) {
1254
3/6
✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 65 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 65 times.
✗ Branch 8 not taken.
65 streamMetadata.reset(new StreamMetadata);
1255
1/2
✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
65 io::setStreamMetadataPtr(os, streamMetadata, /*transfer=*/false);
1256 }
1257
1/2
✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
65 io::setDataCompression(os, compression());
1258
1/2
✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
65 io::setWriteGridStatsMetadata(os, isGridStatsMetadataEnabled());
1259
1260
1/2
✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
65 this->writeHeader(os, seekable);
1261
1262
1/2
✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
65 metadata.writeMeta(os);
1263
1264 // Write the number of non-null grids.
1265 65 int32_t gridCount = 0;
1266
2/2
✓ Branch 0 taken 154 times.
✓ Branch 1 taken 65 times.
219 for (GridCPtrVecCIter i = grids.begin(), e = grids.end(); i != e; ++i) {
1267
1/2
✓ Branch 0 taken 154 times.
✗ Branch 1 not taken.
154 if (*i) ++gridCount;
1268 }
1269
1/2
✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
65 os.write(reinterpret_cast<char*>(&gridCount), sizeof(int32_t));
1270
1271 using TreeMap = std::map<const TreeBase*, GridDescriptor>;
1272 using TreeMapIter = TreeMap::iterator;
1273 TreeMap treeMap;
1274
1275 // Determine which grid names are unique and which are not.
1276 using NameHistogram = std::map<std::string, int /*count*/>;
1277 NameHistogram nameCount;
1278
2/2
✓ Branch 0 taken 154 times.
✓ Branch 1 taken 65 times.
219 for (GridCPtrVecCIter i = grids.begin(), e = grids.end(); i != e; ++i) {
1279
1/2
✓ Branch 0 taken 154 times.
✗ Branch 1 not taken.
154 if (const GridBase::ConstPtr& grid = *i) {
1280
1/2
✓ Branch 1 taken 154 times.
✗ Branch 2 not taken.
154 const std::string name = grid->getName();
1281
2/2
✓ Branch 0 taken 61 times.
✓ Branch 1 taken 93 times.
154 NameHistogram::iterator it = nameCount.find(name);
1282
2/2
✓ Branch 0 taken 61 times.
✓ Branch 1 taken 93 times.
154 if (it != nameCount.end()) it->second++;
1283
1/2
✓ Branch 1 taken 93 times.
✗ Branch 2 not taken.
93 else nameCount[name] = 1;
1284 }
1285 }
1286
1287 std::set<std::string> uniqueNames;
1288
1289 // Write out the non-null grids.
1290
2/2
✓ Branch 0 taken 154 times.
✓ Branch 1 taken 65 times.
219 for (GridCPtrVecCIter i = grids.begin(), e = grids.end(); i != e; ++i) {
1291
1/2
✓ Branch 0 taken 154 times.
✗ Branch 1 not taken.
154 if (const GridBase::ConstPtr& grid = *i) {
1292
1293 // Ensure that the grid's descriptor has a unique grid name, by appending
1294 // a number to it if a grid with the same name was already written.
1295 // Always add a number if the grid name is empty, so that the grid can be
1296 // properly identified as an instance parent, if necessary.
1297
1/2
✓ Branch 1 taken 154 times.
✗ Branch 2 not taken.
154 std::string name = grid->getName();
1298
5/6
✓ Branch 0 taken 65 times.
✓ Branch 1 taken 89 times.
✓ Branch 3 taken 65 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 10 times.
✓ Branch 6 taken 55 times.
154 if (name.empty() || nameCount[name] > 1) {
1299
1/2
✓ Branch 1 taken 99 times.
✗ Branch 2 not taken.
198 name = GridDescriptor::addSuffix(name, 0);
1300 }
1301
2/2
✓ Branch 0 taken 89 times.
✓ Branch 1 taken 154 times.
243 for (int n = 1; uniqueNames.find(name) != uniqueNames.end(); ++n) {
1302
2/4
✓ Branch 1 taken 89 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 89 times.
✗ Branch 5 not taken.
178 name = GridDescriptor::addSuffix(grid->getName(), n);
1303 }
1304 uniqueNames.insert(name);
1305
1306 // Create a grid descriptor.
1307
4/8
✓ Branch 1 taken 154 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 154 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 154 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 154 times.
✗ Branch 11 not taken.
462 GridDescriptor gd(name, grid->type(), grid->saveFloatAsHalf());
1308
1309 // Check if this grid's tree is shared with a grid that has already been written.
1310 154 const TreeBase* treePtr = &(grid->baseTree());
1311
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 139 times.
154 TreeMapIter mapIter = treeMap.find(treePtr);
1312
1313 bool isInstance = ((mapIter != treeMap.end())
1314
3/4
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 139 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 15 times.
154 && (mapIter->second.saveFloatAsHalf() == gd.saveFloatAsHalf()));
1315
1316
4/4
✓ Branch 0 taken 147 times.
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 134 times.
154 if (mEnableInstancing && isInstance) {
1317 // This grid's tree is shared with another grid that has already been written.
1318 // Get the name of the other grid.
1319 gd.setInstanceParentName(mapIter->second.uniqueName());
1320 // Write out this grid's descriptor and metadata, but not its tree.
1321
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
26 writeGridInstance(gd, grid, os, seekable);
1322
1323 OPENVDB_LOG_DEBUG_RUNTIME("io::Archive::write(): "
1324 << GridDescriptor::nameAsString(gd.uniqueName())
1325 << " (" << std::hex << treePtr << std::dec << ")"
1326 << " is an instance of "
1327 << GridDescriptor::nameAsString(gd.instanceParentName()));
1328 } else {
1329 // Write out the grid descriptor and its associated grid.
1330
1/2
✓ Branch 1 taken 141 times.
✗ Branch 2 not taken.
141 writeGrid(gd, grid, os, seekable);
1331 // Record the grid's tree pointer so that the tree doesn't get written
1332 // more than once.
1333
2/4
✓ Branch 1 taken 141 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 141 times.
✗ Branch 5 not taken.
141 treeMap[treePtr] = gd;
1334 }
1335 }
1336
1337 // Some compression options (e.g., mask compression) are set per grid.
1338 // Restore the original settings before writing the next grid.
1339
1/2
✓ Branch 1 taken 154 times.
✗ Branch 2 not taken.
154 io::setDataCompression(os, compression());
1340 }
1341 65 }
1342
1343
1344 void
1345 150 Archive::writeGrid(GridDescriptor& gd, GridBase::ConstPtr grid,
1346 std::ostream& os, bool seekable) const
1347 {
1348 // Restore file-level stream metadata on exit.
1349 struct OnExit {
1350
2/2
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 6 times.
150 OnExit(std::ios_base& strm_): strm(&strm_), ptr(strm_.pword(sStreamState.metadata)) {}
1351
1/2
✓ Branch 0 taken 150 times.
✗ Branch 1 not taken.
150 ~OnExit() { strm->pword(sStreamState.metadata) = ptr; }
1352 std::ios_base* strm;
1353 void* ptr;
1354 };
1355 300 OnExit restore(os);
1356
1357 // Stream metadata varies per grid, so make a copy of the file-level stream metadata.
1358 150 io::StreamMetadata::Ptr streamMetadata;
1359
3/4
✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 141 times.
✓ Branch 4 taken 9 times.
150 if (io::StreamMetadata::Ptr meta = io::getStreamMetadataPtr(os)) {
1360
3/6
✓ Branch 1 taken 141 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 141 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 141 times.
✗ Branch 8 not taken.
141 streamMetadata.reset(new StreamMetadata(*meta));
1361 } else {
1362
3/6
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 9 times.
✗ Branch 8 not taken.
9 streamMetadata.reset(new StreamMetadata);
1363 }
1364
2/4
✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 150 times.
✗ Branch 5 not taken.
150 streamMetadata->setHalfFloat(grid->saveFloatAsHalf());
1365
2/4
✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 150 times.
✗ Branch 5 not taken.
150 streamMetadata->gridMetadata() = static_cast<const MetaMap&>(*grid);
1366
1/2
✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
150 io::setStreamMetadataPtr(os, streamMetadata, /*transfer=*/false);
1367
1368 // Write out the Descriptor's header information (grid name and type)
1369
1/2
✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
150 gd.writeHeader(os);
1370
1371 // Save the curent stream position as postion to where the offsets for
1372 // this GridDescriptor will be written to.
1373
3/6
✓ Branch 0 taken 137 times.
✓ Branch 1 taken 13 times.
✓ Branch 3 taken 137 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
150 int64_t offsetPos = (seekable ? int64_t(os.tellp()) : 0);
1374
1375 // Write out the offset information. At this point it will be incorrect.
1376 // But we need to write it out to move the stream head forward.
1377
1/2
✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
150 gd.writeStreamPos(os);
1378
1379 // Now we know the starting grid storage position.
1380
3/4
✓ Branch 0 taken 137 times.
✓ Branch 1 taken 13 times.
✓ Branch 3 taken 137 times.
✗ Branch 4 not taken.
150 if (seekable) gd.setGridPos(os.tellp());
1381
1382 // Save the compression settings for this grid.
1383
1/2
✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
150 setGridCompression(os, *grid);
1384
1385 // copy grid and add delay load metadata
1386
1/2
✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
150 const auto copyOfGrid = grid->copyGrid(); // shallow copy
1387 const auto nonConstCopyOfGrid = ConstPtrCast<GridBase>(copyOfGrid);
1388
2/4
✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 150 times.
✗ Branch 5 not taken.
150 nonConstCopyOfGrid->insertMeta(GridBase::META_FILE_DELAYED_LOAD,
1389
1/4
✓ Branch 2 taken 150 times.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
150 DelayedLoadMetadata());
1390 DelayedLoadMetadata::Ptr delayLoadMeta =
1391
3/6
✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 150 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 150 times.
✗ Branch 8 not taken.
300 nonConstCopyOfGrid->getMetadata<DelayedLoadMetadata>(GridBase::META_FILE_DELAYED_LOAD);
1392
3/4
✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 17 times.
✓ Branch 4 taken 133 times.
150 if (!populateDelayedLoadMetadata(*delayLoadMeta, *grid, compression())) {
1393
2/4
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 17 times.
✗ Branch 5 not taken.
34 nonConstCopyOfGrid->removeMeta(GridBase::META_FILE_DELAYED_LOAD);
1394 }
1395
1396 // Save the grid's metadata and transform.
1397
3/4
✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 141 times.
✓ Branch 4 taken 9 times.
150 if (getWriteGridStatsMetadata(os)) {
1398 // Compute and add grid statistics metadata.
1399
1/2
✓ Branch 1 taken 141 times.
✗ Branch 2 not taken.
141 nonConstCopyOfGrid->addStatsMetadata();
1400
2/4
✓ Branch 1 taken 141 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 141 times.
✗ Branch 5 not taken.
282 nonConstCopyOfGrid->insertMeta(GridBase::META_FILE_COMPRESSION,
1401
2/6
✓ Branch 1 taken 141 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 141 times.
✗ Branch 5 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
282 StringMetadata(compressionToString(getDataCompression(os))));
1402 }
1403
1/2
✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
150 copyOfGrid->writeMeta(os);
1404 grid->writeTransform(os);
1405
1406 // Save the grid's structure.
1407
1/2
✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
150 grid->writeTopology(os);
1408
1409 // Now we know the grid block storage position.
1410
3/4
✓ Branch 0 taken 137 times.
✓ Branch 1 taken 13 times.
✓ Branch 3 taken 137 times.
✗ Branch 4 not taken.
150 if (seekable) gd.setBlockPos(os.tellp());
1411
1412 // Save out the data blocks of the grid.
1413
1/2
✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
150 grid->writeBuffers(os);
1414
1415 // Now we know the end position of this grid.
1416
3/4
✓ Branch 0 taken 137 times.
✓ Branch 1 taken 13 times.
✓ Branch 3 taken 137 times.
✗ Branch 4 not taken.
150 if (seekable) gd.setEndPos(os.tellp());
1417
1418
2/2
✓ Branch 0 taken 137 times.
✓ Branch 1 taken 13 times.
150 if (seekable) {
1419 // Now, go back to where the Descriptor's offset information is written
1420 // and write the offsets again.
1421
1/2
✓ Branch 1 taken 137 times.
✗ Branch 2 not taken.
137 os.seekp(offsetPos, std::ios_base::beg);
1422
1/2
✓ Branch 1 taken 137 times.
✗ Branch 2 not taken.
137 gd.writeStreamPos(os);
1423
1424 // Now seek back to the end.
1425
1/2
✓ Branch 1 taken 137 times.
✗ Branch 2 not taken.
137 gd.seekToEnd(os);
1426 }
1427 150 }
1428
1429
1430 void
1431 13 Archive::writeGridInstance(GridDescriptor& gd, GridBase::ConstPtr grid,
1432 std::ostream& os, bool seekable) const
1433 {
1434 // Write out the Descriptor's header information (grid name, type
1435 // and instance parent name).
1436 13 gd.writeHeader(os);
1437
1438 // Save the curent stream position as postion to where the offsets for
1439 // this GridDescriptor will be written to.
1440
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 2 times.
13 int64_t offsetPos = (seekable ? int64_t(os.tellp()) : 0);
1441
1442 // Write out the offset information. At this point it will be incorrect.
1443 // But we need to write it out to move the stream head forward.
1444 13 gd.writeStreamPos(os);
1445
1446 // Now we know the starting grid storage position.
1447
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 2 times.
13 if (seekable) gd.setGridPos(os.tellp());
1448
1449 // Save the compression settings for this grid.
1450 13 setGridCompression(os, *grid);
1451
1452 // Save the grid's metadata and transform.
1453 13 grid->writeMeta(os);
1454 grid->writeTransform(os);
1455
1456 // Now we know the end position of this grid.
1457
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 2 times.
13 if (seekable) gd.setEndPos(os.tellp());
1458
1459
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 2 times.
13 if (seekable) {
1460 // Now, go back to where the Descriptor's offset information is written
1461 // and write the offsets again.
1462 11 os.seekp(offsetPos, std::ios_base::beg);
1463 11 gd.writeStreamPos(os);
1464
1465 // Now seek back to the end.
1466 11 gd.seekToEnd(os);
1467 }
1468 13 }
1469
1470 } // namespace io
1471 } // namespace OPENVDB_VERSION_NAME
1472 } // namespace openvdb
1473