OpenVDB  11.0.0
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 
20 namespace 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
27 template <typename ValueT>
28 bool isValid(const NanoGrid<ValueT> &grid, bool detailed = true, bool verbose = false);
29 
30 /// @brief Allows for the construction of NanoVDB grids without any dependecy
31 template <typename ValueT>
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 
39 public:
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 
52 template <typename ValueT>
53 std::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 
99 template<typename ValueT>
100 void 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 
115 template<typename ValueT>
116 void 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 //================================================================================================
139 template<typename ValueT>
140 void 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 
175 template <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
Computes a pair of 32bit checksums, of a Grid, by means of Cyclic Redundancy Check (CRC)
Implements a light-weight self-contained VDB data-structure in a single file! In other words,...
#define NANOVDB_MAGIC_GRID
Definition: NanoVDB.h:127
#define NANOVDB_MAJOR_VERSION_NUMBER
Definition: NanoVDB.h:133
#define NANOVDB_MAGIC_NUMBER
Definition: NanoVDB.h:126
Allows for the construction of NanoVDB grids without any dependecy.
Definition: GridValidator.h:33
static std::string check(const GridT &grid, bool detailed=true)
Returns an error message (an empty string means no error)
Definition: GridValidator.h:53
Highest level of the data structure. Contains a tree and a world->index transform (that currently onl...
Definition: NanoVDB.h:3699
const TreeT & tree() const
Return a const reference to the tree.
Definition: NanoVDB.h:3753
Bit-compacted representation of all three version numbers.
Definition: NanoVDB.h:948
uint32_t getMajor() const
Definition: NanoVDB.h:971
uint32_t id() const
Definition: NanoVDB.h:970
Convert a base-pointer to an openvdb grid, denoted srcGrid, to a nanovdb grid of the same type,...
Definition: NanoVDB.h:247
static bool isValid(const void *p)
return true if the specified pointer is aligned and not NULL
Definition: NanoVDB.h:743
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...
Struct with all the member data of the Grid (useful during serialization of an openvdb grid)
Definition: NanoVDB.h:3512