OpenVDB: nanovdb/util/GridValidator.h Source File

OpenVDB 11.0.0

Loading...
Searching...
No Matches
GridValidator.h
Go to the documentation of this file.
1// Copyright Contributors to the OpenVDB Project
2// SPDX-License-Identifier: MPL-2.0
3
4/*!
5 \file GridValidator.h
6
7 \author Ken Museth
8
9 \date August 30, 2020
10
11 \brief Checks the validity of an existing NanoVDB grid.
12*/
13
14#ifndef NANOVDB_GRIDVALIDATOR_H_HAS_BEEN_INCLUDED
15#define NANOVDB_GRIDVALIDATOR_H_HAS_BEEN_INCLUDED
16
17#include <nanovdb/NanoVDB.h>
18#include "GridChecksum.h"
19
20namespace nanovdb {
21
22/// @brief Return true if the specified grid passes several validation tests.
23///
24/// @param grid Grid to validate
25/// @param detailed If true the validation test is detailed and relatively slow.
26/// @param verbose If true information about the first failed test is printed to std::cerr
27template <typename ValueT>
28bool isValid(const NanoGrid<ValueT> &grid, bool detailed = true, bool verbose = false);
29
30/// @brief Allows for the construction of NanoVDB grids without any dependecy
31template <typename ValueT>
32 class GridValidator
33{
34 using GridT = NanoGrid<ValueT>;
35 inline static void checkTree( const GridT&, std::string&, bool);
36 inline static void checkRoot( const GridT&, std::string&, bool);
37 inline static void checkNodes(const GridT&, std::string&);
38
39public:
40 /// @brief Returns an error message (an empty string means no error)
41 ///
42 /// @param grid NanoVDB grid to be tested
43 /// @param detailed If true the checksum is computed and validated as well as all the node pointers
44 ///
45 /// @note The validation is much slower if @c detailed == true!
46 static std::string check(const GridT &grid, bool detailed = true);
47
48};// GridValidator
49
50//================================================================================================
51
52template <typename ValueT>
53std::string GridValidator<ValueT>::check(const GridT &grid, bool detailed)
54{
55 std::string errorStr;
56
57 // First check the Grid
58 auto *data = reinterpret_cast<const typename GridT::DataType*>(&grid);
59 std::stringstream ss;
60 if (!isValid(data)) {
61 errorStr.assign("Grid is not 32B aligned");
62 } else if (data->mMagic != NANOVDB_MAGIC_NUMBER && data->mMagic != NANOVDB_MAGIC_GRID) {
63 const uint64_t magic1 = NANOVDB_MAGIC_NUMBER, magic2 = NANOVDB_MAGIC_GRID;
64 const char *c0 = (const char*)&(data->mMagic), *c1=(const char*)&magic1, *c2=(const char*)&magic2;
65 ss << "Incorrect magic number: Expected \"";
66 for (int i=0; i<8; ++i) ss << c1[i];
67 ss << "\" or \"";
68 for (int i=0; i<8; ++i) ss << c2[i];
69 ss << "\", but found \"";
70 for (int i=0; i<8; ++i) ss << c0[i];
71 ss << "\"";
72 errorStr = ss.str();
73 } else if (!validateChecksum(grid, detailed ? ChecksumMode::Full : ChecksumMode::Partial)) {
74 errorStr.assign("Mis-matching checksum");
75 } else if (data->mVersion >= Version(29,0,0) && data->mVersion.getMajor() != NANOVDB_MAJOR_VERSION_NUMBER) {
76 ss << "Invalid major version number: Expected " << NANOVDB_MAJOR_VERSION_NUMBER << ", but read " << data->mVersion.c_str();
77 errorStr = ss.str();
78 } else if (data->mVersion < Version(29,0,0) && data->mVersion.id() != 28u) {
79 ss << "Invalid old major version number: Expected 28 or newer, but read " << data->mVersion.id();
80 errorStr = ss.str();
81 } else if (data->mGridClass >= GridClass::End) {
82 errorStr.assign("Invalid GridClass");
83 } else if (data->mGridType >= GridType::End) {
84 errorStr.assign("Invalid GridType");
85 } else if (data->mGridType != mapToGridType<ValueT>()) {
86 errorStr.assign("Invalid combination of ValueType and GridType");
87 } else if (!isValid(data->mGridType, data->mGridClass)) {
88 errorStr.assign("Invalid combination of GridType and GridClass");
89 } else if ( (const uint8_t*)(&(grid.tree())) != (const uint8_t*)(&grid+1) ) {
90 errorStr.assign("Invalid Tree pointer");
91 } else {
92 checkTree(grid, errorStr, detailed);
93 }
94 return errorStr;
95}
96
97//================================================================================================
98
99template<typename ValueT>
100void GridValidator<ValueT>::checkTree(const GridT &grid, std::string &errorStr, bool detailed)
101{
102 if (!isValid(&grid.tree())) {
103 errorStr.assign("Tree is not 32B aligned");
104 } else if ( (const uint8_t*)(&grid.tree().root()) < (const uint8_t*)(&grid.tree()+1)) {
105 errorStr.assign("Invalid root pointer (should be located after the Grid and Tree)");
106 } else if ( (const uint8_t*)(&grid.tree().root()) > (const uint8_t*)(&grid) + grid.gridSize() - sizeof(grid.tree().root()) ) {
107 errorStr.assign("Invalid root pointer (appears to be located after the end of the buffer)");
108 } else {
109 checkRoot(grid, errorStr, detailed);
110 }
111}// GridValidator::checkTree
112
113//================================================================================================
114
115template<typename ValueT>
116void GridValidator<ValueT>::checkRoot(const GridT &grid, std::string &errorStr, bool detailed)
117{
118 auto &root = grid.tree().root();
119 auto *data = root.data();
120 if (!isValid(data)) {
121 errorStr.assign("Root is not 32B aligned");
122 }
123 const uint8_t *minPtr = (const uint8_t*)(&root + 1);
124 const uint8_t *maxPtr = (const uint8_t*)(&root) + root.memUsage();
125 for (uint32_t i = 0; errorStr.empty() && i<data->mTableSize; ++i) {
126 const auto *tile = data->tile(i);
127 if ( (const uint8_t *) tile < minPtr ) {
128 errorStr.assign("Invalid root tile pointer (below lower bound");
129 } else if ( (const uint8_t *) tile > maxPtr - sizeof(*tile) ) {
130 errorStr.assign("Invalid root tile pointer (above higher bound");
131 }
132 }
133 if (detailed && errorStr.empty()) {
134 checkNodes(grid, errorStr);
135 }
136}// GridValidator::processRoot
137
138//================================================================================================
139template<typename ValueT>
140void GridValidator<ValueT>::checkNodes(const GridT &grid, std::string &errorStr)
141{
142 auto &root = grid.tree().root();// note, the root node was already checked
143 const uint8_t *minPtr = (const uint8_t*)(&root) + root.memUsage();
144 const uint8_t *maxPtr = (const uint8_t*)(&grid) + grid.gridSize();
145
146 auto check = [&](const void * ptr, size_t ptrSize) -> bool {
147 if (!isValid(ptr)) {
148 errorStr.assign("Invalid node pointer: not 32B aligned");
149 } else if ( (const uint8_t *) ptr < minPtr ) {
150 errorStr.assign("Invalid node pointer: below lower bound");
151 } else if ( (const uint8_t *) ptr > maxPtr - ptrSize ) {
152 errorStr.assign("Invalid node pointer: above higher bound");
153 }
154 return errorStr.empty();
155 };
156
157 for (auto it2 = grid.tree().root().cbeginChild(); it2; ++it2) {
158 auto &node2 = *it2;
159 if (!check(&node2, sizeof(node2))) return;
160 for (auto it1 = node2.cbeginChild(); it1; ++it1) {
161 auto &node1 = *it1;
162 if (!check(&node1, sizeof(node1))) return;
163 for (auto it0 = node1.cbeginChild(); it0; ++it0) {
164 auto &node0 = *it0;
165 if (!check(&node2, sizeof(node2))) return;
166 }// loop over child nodes of the lower internal node
167 }// loop over child nodes of the upper internal node
168 }// loop over child nodes of the root node
169
170} // GridValidator::processNodes
171
172
173//================================================================================================
174
175template <typename ValueT>
176 bool isValid(const NanoGrid<ValueT> &grid, bool detailed, bool verbose)
177{
178 const std::string str = GridValidator<ValueT>::check( grid, detailed );
179 if (verbose && !str.empty()) std::cerr << "Validation failed: " << str << std::endl;
180 return str.empty();
181}
182
183} // namespace nanovdb
184
185#endif // NANOVDB_GRIDVALIDATOR_H_HAS_BEEN_INCLUDED
GridChecksum.h
Computes a pair of 32bit checksums, of a Grid, by means of Cyclic Redundancy Check (CRC)
NanoVDB.h
Implements a light-weight self-contained VDB data-structure in a single file! In other words,...
NANOVDB_MAGIC_GRID
#define NANOVDB_MAGIC_GRID
Definition NanoVDB.h:127
NANOVDB_MAJOR_VERSION_NUMBER
#define NANOVDB_MAJOR_VERSION_NUMBER
Definition NanoVDB.h:133
NANOVDB_MAGIC_NUMBER
#define NANOVDB_MAGIC_NUMBER
Definition NanoVDB.h:126
nanovdb::GridValidator
Allows for the construction of NanoVDB grids without any dependecy.
Definition GridValidator.h:33
nanovdb::GridValidator::check
static std::string check(const GridT &grid, bool detailed=true)
Returns an error message (an empty string means no error)
Definition GridValidator.h:53
nanovdb::Grid
Highest level of the data structure. Contains a tree and a world->index transform (that currently onl...
Definition NanoVDB.h:3699
nanovdb::Grid::tree
const TreeT & tree() const
Return a const reference to the tree.
Definition NanoVDB.h:3753
nanovdb::Version
Bit-compacted representation of all three version numbers.
Definition NanoVDB.h:948
nanovdb::Version::c_str
const char * c_str() const
Definition NanoVDB.h:981
nanovdb::Version::getMajor
uint32_t getMajor() const
Definition NanoVDB.h:971
nanovdb::Version::id
uint32_t id() const
Definition NanoVDB.h:970
nanovdb
Convert a base-pointer to an openvdb grid, denoted srcGrid, to a nanovdb grid of the same type,...
Definition NanoVDB.h:247
nanovdb::GridClass::End
@ End
nanovdb::GridType::End
@ End
nanovdb::validateChecksum
bool validateChecksum(const NanoGrid< BuildT > &grid, ChecksumMode mode=ChecksumMode::Default)
Return true if the checksum of the grid matches the expected value already encoded into the grid's me...
nanovdb::ChecksumMode::Partial
@ Partial
nanovdb::ChecksumMode::Full
@ Full
nanovdb::isValid
static bool isValid(const void *p)
return true if the specified pointer is aligned and not NULL
Definition NanoVDB.h:743
nanovdb::GridData
Struct with all the member data of the Grid (useful during serialization of an openvdb grid)
Definition NanoVDB.h:3512
nanovdb::GridData::mVersion
Version mVersion
Definition NanoVDB.h:3516