Commit b00647d5e2be529b6295f07332cad949a1b8d032
1 parent
4490c23f
Add `validate()` to `NNTree` helpers and implementations
- Introduced a `validate()` method in `QPDFNameTreeObjectHelper`, `QPDFNumberTreeObjectHelper`, and `NNTreeImpl`. - Ensure proper validation of tree keys and values, detecting invalid entries, unsorted keys, and inconsistencies. - Added support for auto-repair in case of validation errors.
Showing
6 changed files
with
58 additions
and
2 deletions
include/qpdf/QPDFNameTreeObjectHelper.hh
| ... | ... | @@ -50,7 +50,13 @@ class QPDF_DLL_CLASS QPDFNameTreeObjectHelper: public QPDFObjectHelper |
| 50 | 50 | QPDFObjectHandle, |
| 51 | 51 | QPDF&, |
| 52 | 52 | std::function<bool(QPDFObjectHandle const&)> value_validator, |
| 53 | - bool auto_repair = true); | |
| 53 | + bool auto_repair); | |
| 54 | + | |
| 55 | + // Validate the name tree. Returns true if the tree is valid. | |
| 56 | + // | |
| 57 | + // If the tree is not valid and auto_repair is true, attempt to repair the tree. | |
| 58 | + QPDF_DLL | |
| 59 | + bool validate(bool repair = true); | |
| 54 | 60 | |
| 55 | 61 | // Create an empty name tree |
| 56 | 62 | QPDF_DLL | ... | ... |
include/qpdf/QPDFNumberTreeObjectHelper.hh
| ... | ... | @@ -48,7 +48,7 @@ class QPDF_DLL_CLASS QPDFNumberTreeObjectHelper: public QPDFObjectHelper |
| 48 | 48 | QPDFObjectHandle, |
| 49 | 49 | QPDF&, |
| 50 | 50 | std::function<bool(QPDFObjectHandle const&)> value_validator, |
| 51 | - bool auto_repair = true); | |
| 51 | + bool auto_repair); | |
| 52 | 52 | |
| 53 | 53 | QPDF_DLL |
| 54 | 54 | ~QPDFNumberTreeObjectHelper() override; |
| ... | ... | @@ -59,6 +59,12 @@ class QPDF_DLL_CLASS QPDFNumberTreeObjectHelper: public QPDFObjectHelper |
| 59 | 59 | |
| 60 | 60 | typedef long long int numtree_number; |
| 61 | 61 | |
| 62 | + // Validate the name tree. Returns true if the tree is valid. | |
| 63 | + // | |
| 64 | + // If the tree is not valid and auto_repair is true, attempt to repair the tree. | |
| 65 | + QPDF_DLL | |
| 66 | + bool validate(bool repair = true); | |
| 67 | + | |
| 62 | 68 | // Return overall minimum and maximum indices |
| 63 | 69 | QPDF_DLL |
| 64 | 70 | numtree_number getMin(); | ... | ... |
libqpdf/NNTree.cc
| ... | ... | @@ -891,3 +891,33 @@ NNTreeImpl::remove(QPDFObjectHandle const& key, QPDFObjectHandle* value) |
| 891 | 891 | iter.remove(); |
| 892 | 892 | return true; |
| 893 | 893 | } |
| 894 | + | |
| 895 | +bool | |
| 896 | +NNTreeImpl::validate(bool a_repair) | |
| 897 | +{ | |
| 898 | + bool first = true; | |
| 899 | + QPDFObjectHandle last_key; | |
| 900 | + try { | |
| 901 | + for (auto const& [key, value]: *this) { | |
| 902 | + if (!details.keyValid(key)) { | |
| 903 | + error(oh, "invalid key in validate"); | |
| 904 | + } | |
| 905 | + if (!value_valid(value)) { | |
| 906 | + error(oh, "invalid value in validate"); | |
| 907 | + } | |
| 908 | + if (first) { | |
| 909 | + first = false; | |
| 910 | + } else if (last_key && details.compareKeys(last_key, key) != -1) { | |
| 911 | + error(oh, "keys are not sorted in validate"); | |
| 912 | + } | |
| 913 | + last_key = key; | |
| 914 | + } | |
| 915 | + } catch (QPDFExc& e) { | |
| 916 | + if (a_repair) { | |
| 917 | + warn(oh, std::string("attempting to repair after error: ") + e.what()); | |
| 918 | + repair(); | |
| 919 | + } | |
| 920 | + return false; | |
| 921 | + } | |
| 922 | + return true; | |
| 923 | +} | ... | ... |
libqpdf/QPDFNameTreeObjectHelper.cc
libqpdf/QPDFNumberTreeObjectHelper.cc
libqpdf/qpdf/NNTree.hh
| ... | ... | @@ -109,6 +109,8 @@ class NNTreeImpl |
| 109 | 109 | iterator insert(QPDFObjectHandle const& key, QPDFObjectHandle const& value); |
| 110 | 110 | bool remove(QPDFObjectHandle const& key, QPDFObjectHandle* value = nullptr); |
| 111 | 111 | |
| 112 | + bool validate(bool repair = true); | |
| 113 | + | |
| 112 | 114 | // Change the split threshold for easier testing. There's no real reason to expose this to |
| 113 | 115 | // downstream tree helpers, but it has to be public so we can call it from the test suite. |
| 114 | 116 | void setSplitThreshold(int split_threshold); | ... | ... |