OpenVDB  10.0.1
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.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) {
63  ss << "Incorrect magic number: Expected " << NANOVDB_MAGIC_NUMBER << ", but read " << data->mMagic;
64  errorStr = ss.str();
65  } else if (!validateChecksum(grid, detailed ? ChecksumMode::Full : ChecksumMode::Partial)) {
66  errorStr.assign("Mis-matching checksum");
67  } else if (data->mVersion >= Version(29,0,0) && data->mVersion.getMajor() != NANOVDB_MAJOR_VERSION_NUMBER) {
68  ss << "Invalid major version number: Expected " << NANOVDB_MAJOR_VERSION_NUMBER << ", but read " << data->mVersion.c_str();
69  errorStr = ss.str();
70  } else if (data->mVersion < Version(29,0,0) && data->mVersion.id() != 28u) {
71  ss << "Invalid old major version number: Expected 28 or newer, but read " << data->mVersion.id();
72  errorStr = ss.str();
73  } else if (data->mGridClass >= GridClass::End) {
74  errorStr.assign("Invalid GridClass");
75  } else if (data->mGridType >= GridType::End) {
76  errorStr.assign("Invalid GridType");
77  } else if (data->mGridType != mapToGridType<ValueT>()) {
78  errorStr.assign("Invalid combination of ValueType and GridType");
79  } else if (!isValid(data->mGridType, data->mGridClass)) {
80  errorStr.assign("Invalid combination of GridType and GridClass");
81  } else if ( (const uint8_t*)(&(grid.tree())) != (const uint8_t*)(&grid+1) ) {
82  errorStr.assign("Invalid Tree pointer");
83  } else {
84  checkTree(grid, errorStr, detailed);
85  }
86  return errorStr;
87 }
88 
89 //================================================================================================
90 
91 template<typename ValueT>
92 void GridValidator<ValueT>::checkTree(const GridT &grid, std::string &errorStr, bool detailed)
93 {
94  if (!isValid(&grid.tree())) {
95  errorStr.assign("Tree is not 32B aligned");
96  } else if ( (const uint8_t*)(&grid.tree().root()) < (const uint8_t*)(&grid.tree()+1)) {
97  errorStr.assign("Invalid root pointer (should be located after the Grid and Tree)");
98  } else if ( (const uint8_t*)(&grid.tree().root()) > (const uint8_t*)(&grid) + grid.gridSize() - sizeof(grid.tree().root()) ) {
99  errorStr.assign("Invalid root pointer (appears to be located after the end of the buffer)");
100  } else {
101  checkRoot(grid, errorStr, detailed);
102  }
103 }// GridValidator::checkTree
104 
105 //================================================================================================
106 
107 template<typename ValueT>
108 void GridValidator<ValueT>::checkRoot(const GridT &grid, std::string &errorStr, bool detailed)
109 {
110  auto &root = grid.tree().root();
111  auto *data = root.data();
112  if (!isValid(data)) {
113  errorStr.assign("Root is not 32B aligned");
114  }
115  const uint8_t *minPtr = (const uint8_t*)(&root + 1);
116  const uint8_t *maxPtr = (const uint8_t*)(&root) + root.memUsage();
117  for (uint32_t i = 0; errorStr.empty() && i<data->mTableSize; ++i) {
118  const auto *tile = data->tile(i);
119  if ( (const uint8_t *) tile < minPtr ) {
120  errorStr.assign("Invalid root tile pointer (below lower bound");
121  } else if ( (const uint8_t *) tile > maxPtr - sizeof(*tile) ) {
122  errorStr.assign("Invalid root tile pointer (above higher bound");
123  }
124  }
125  if (detailed && errorStr.empty()) {
126  checkNodes(grid, errorStr);
127  }
128 }// GridValidator::processRoot
129 
130 //================================================================================================
131 template<typename ValueT>
132 void GridValidator<ValueT>::checkNodes(const GridT &grid, std::string &errorStr)
133 {
134  auto &root = grid.tree().root();// note, the root node was already checked
135  const uint8_t *minPtr = (const uint8_t*)(&root) + root.memUsage();
136  const uint8_t *maxPtr = (const uint8_t*)(&grid) + grid.gridSize();
137 
138  auto check = [&](const void * ptr, size_t ptrSize) -> bool {
139  if (!isValid(ptr)) {
140  errorStr.assign("Invalid node pointer: not 32B aligned");
141  } else if ( (const uint8_t *) ptr < minPtr ) {
142  errorStr.assign("Invalid node pointer: below lower bound");
143  } else if ( (const uint8_t *) ptr > maxPtr - ptrSize ) {
144  errorStr.assign("Invalid node pointer: above higher bound");
145  }
146  return errorStr.empty();
147  };
148 
149  for (auto it2 = grid.tree().root().beginChild(); it2; ++it2) {
150  auto &node2 = *it2;
151  if (!check(&node2, sizeof(node2))) return;
152  for (auto it1 = node2.beginChild(); it1; ++it1) {
153  auto &node1 = *it1;
154  if (!check(&node1, sizeof(node1))) return;
155  for (auto it0 = node1.beginChild(); it0; ++it0) {
156  auto &node0 = *it0;
157  if (!check(&node2, sizeof(node2))) return;
158  }// loop over child nodes of the lower internal node
159  }// loop over child nodes of the upper internal node
160  }// loop over child nodes of the root node
161 
162 } // GridValidator::processNodes
163 
164 
165 //================================================================================================
166 
167 template <typename ValueT>
168 bool isValid(const NanoGrid<ValueT> &grid, bool detailed, bool verbose)
169 {
170  const std::string str = GridValidator<ValueT>::check( grid, detailed );
171  if (verbose && !str.empty()) std::cerr << "Validation failed: " << str << std::endl;
172  return str.empty();
173 }
174 
175 } // namespace nanovdb
176 
177 #endif // NANOVDB_GRIDVALIDATOR_H_HAS_BEEN_INCLUDED
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:2555
const TreeT & tree() const
Return a const reference to the tree.
Definition: NanoVDB.h:2598
Computes a pair of 32bit checksums, og a Grid, by means of Cyclic Redundancy Check (CRC) ...
Bit-compacted representation of all three version numbers.
Definition: NanoVDB.h:647
Definition: NanoVDB.h:208
#define NANOVDB_MAJOR_VERSION_NUMBER
Definition: NanoVDB.h:123
uint32_t id() const
Definition: NanoVDB.h:668
#define NANOVDB_MAGIC_NUMBER
Definition: NanoVDB.h:121
bool validateChecksum(const NanoGrid< ValueT > &grid, ChecksumMode mode=ChecksumMode::Default)
Return true if the checksum of the grid matches the expected value already encoded into the grid&#39;s me...
Definition: GridChecksum.h:269
uint32_t getMajor() const
Definition: NanoVDB.h:669
Struct with all the member data of the Grid (useful during serialization of an openvdb grid) ...
Definition: NanoVDB.h:2431
static bool isValid(const void *p)
return true if the specified pointer is aligned and not NULL
Definition: NanoVDB.h:504
uint64_t gridSize() const
Return the memory footprint of the entire grid, i.e. including all nodes and blind data...
Definition: NanoVDB.h:2583
Allows for the construction of NanoVDB grids without any dependecy.
Definition: GridValidator.h:32