| 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 |