aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libqpdf/JSON.cc26
-rw-r--r--libtests/json.cc11
-rw-r--r--libtests/qtest/json/json.out4
-rw-r--r--manual/qpdf-manual.xml17
4 files changed, 51 insertions, 7 deletions
diff --git a/libqpdf/JSON.cc b/libqpdf/JSON.cc
index 8565a831..247d3c86 100644
--- a/libqpdf/JSON.cc
+++ b/libqpdf/JSON.cc
@@ -323,6 +323,7 @@ JSON::checkSchemaInternal(JSON_value* this_v, JSON_value* sch_v,
err_prefix = "json key \"" + prefix + "\"";
}
+ std::string pattern_key;
if (sch_dict)
{
if (! this_dict)
@@ -331,6 +332,31 @@ JSON::checkSchemaInternal(JSON_value* this_v, JSON_value* sch_v,
errors.push_back(err_prefix + " is supposed to be a dictionary");
return false;
}
+ auto members = sch_dict->members;
+ std::string key;
+ if ((members.size() == 1) &&
+ ((key = members.begin()->first, key.length() > 2) &&
+ (key.at(0) == '<') &&
+ (key.at(key.length() - 1) == '>')))
+ {
+ pattern_key = key;
+ }
+ }
+
+ if (sch_dict && (! pattern_key.empty()))
+ {
+ auto pattern_schema = sch_dict->members[pattern_key].getPointer();
+ for (auto iter: this_dict->members)
+ {
+ std::string const& key = iter.first;
+ checkSchemaInternal(
+ this_dict->members[key].getPointer(),
+ pattern_schema,
+ errors, prefix + "." + key);
+ }
+ }
+ else if (sch_dict)
+ {
for (std::map<std::string, PointerHolder<JSON_value> >::iterator iter =
sch_dict->members.begin();
iter != sch_dict->members.end(); ++iter)
diff --git a/libtests/json.cc b/libtests/json.cc
index e3086c18..1ee7a5d3 100644
--- a/libtests/json.cc
+++ b/libtests/json.cc
@@ -112,6 +112,11 @@ static void test_schema()
" >>"
" ]"
">>").getJSON();
+ JSON three = JSON::makeDictionary();
+ three.addDictionaryMember(
+ "<objid>",
+ QPDFObjectHandle::parse("<< /z (ebra) >>").getJSON());
+ schema.addDictionaryMember("/three", three);
JSON a = QPDFObjectHandle::parse("[(not a) (dictionary)]").getJSON();
check_schema(a, schema, false, "top-level type mismatch");
JSON b = QPDFObjectHandle::parse(
@@ -142,8 +147,12 @@ static void test_schema()
" /glarp (4 enspliel)"
" >>"
" ]"
+ " /three <<"
+ " /anything << /x (oops) >>"
+ " /else << /z (okay) >>"
+ " >>"
">>").getJSON();
- check_schema(b, schema, false, "top-level type mismatch");
+ check_schema(b, schema, false, "missing items");
check_schema(a, a, false, "top-level schema array error");
check_schema(b, b, false, "lower-level schema array error");
check_schema(schema, schema, true, "pass");
diff --git a/libtests/qtest/json/json.out b/libtests/qtest/json/json.out
index f06cc1fb..ad668e51 100644
--- a/libtests/qtest/json/json.out
+++ b/libtests/qtest/json/json.out
@@ -1,11 +1,13 @@
--- top-level type mismatch
top-level object is supposed to be a dictionary
---
---- top-level type mismatch
+--- missing items
json key "./one./a": key "/q" is present in schema but missing in object
json key "./one./a./r" is supposed to be a dictionary
json key "./one./a./s" is supposed to be an array
json key "./one./a": key "/t" is not present in schema but appears in object
+json key "./three./anything": key "/z" is present in schema but missing in object
+json key "./three./anything": key "/x" is not present in schema but appears in object
json key "./two.1": key "/glarp" is present in schema but missing in object
json key "./two.1": key "/flarp" is not present in schema but appears in object
json key "./two.2" is supposed to be a dictionary
diff --git a/manual/qpdf-manual.xml b/manual/qpdf-manual.xml
index 83cb6bf9..a2dff114 100644
--- a/manual/qpdf-manual.xml
+++ b/manual/qpdf-manual.xml
@@ -3082,11 +3082,18 @@ outfile.pdf</option>
<itemizedlist>
<listitem>
<para>
- A dictionary in the help output means that the corresponding
- location in the actual JSON output is also a dictionary with
- exactly the same keys; that is, no keys present in help are
- absent in the real output, and no keys will be present in
- the real output that are not in help.
+ A dictionary in the help output means that the
+ corresponding location in the actual JSON output is also a
+ dictionary with exactly the same keys; that is, no keys
+ present in help are absent in the real output, and no keys
+ will be present in the real output that are not in help. As
+ a special case, if the dictionary has a single key whose
+ name starts with <literal>&lt;</literal> and ends with
+ <literal>&gt;</literal>, it means that the JSON output is a
+ dictionary that can have any keys, each of which conforms
+ to the value of the special key. This is used for cases in
+ which the keys of the dictionary are things like object
+ IDs.
</para>
</listitem>
<listitem>