mirror of
https://github.com/qpdf/qpdf.git
synced 2025-01-03 07:12:28 +00:00
JSON schema -- accept single item in place of array
When the schema wants a variable-length array, allow a single item as well as allowing an array.
This commit is contained in:
parent
b3e6d445cb
commit
f8d1ab9462
10
ChangeLog
10
ChangeLog
@ -1,5 +1,15 @@
|
|||||||
2022-07-24 Jay Berkenbilt <ejb@ql.org>
|
2022-07-24 Jay Berkenbilt <ejb@ql.org>
|
||||||
|
|
||||||
|
* include/qpdf/JSON.hh: Schema validation: allow a single item to
|
||||||
|
appear anywhere that the schema has an array of a single item.
|
||||||
|
This makes it possible to change an element of the schema from an
|
||||||
|
item to an array to allow the data to accept an array where a
|
||||||
|
single value was previously required. This change is needed to
|
||||||
|
allow QPDFJob JSON to start accepting multiple items where a
|
||||||
|
single item used to be expected without breaking backward
|
||||||
|
compatibility. Without this change, the earlier fix to
|
||||||
|
removeAttachment would be a breaking change.
|
||||||
|
|
||||||
* QPDFObjectHandle: for the methods insertItem, appendItem,
|
* QPDFObjectHandle: for the methods insertItem, appendItem,
|
||||||
eraseItem, replaceKey, and removeKey, add a corresponding
|
eraseItem, replaceKey, and removeKey, add a corresponding
|
||||||
"AndGetNew" and/or "AndGetOld" methods. The ones that end with
|
"AndGetNew" and/or "AndGetOld" methods. The ones that end with
|
||||||
|
4
TODO
4
TODO
@ -19,10 +19,6 @@ Pending changes:
|
|||||||
appimage build specifically is setting the runpath, which is
|
appimage build specifically is setting the runpath, which is
|
||||||
actually desirable in this case. Make sure to understand and
|
actually desirable in this case. Make sure to understand and
|
||||||
document this. Maybe add a check for it in the build.
|
document this. Maybe add a check for it in the build.
|
||||||
* Make job JSON accept a single element and treat as an array of one
|
|
||||||
when an array is expected. This allows for making things repeatable
|
|
||||||
in the future without breaking compatibility and is needed for the
|
|
||||||
remote-attachment fix to be backward-compatible.
|
|
||||||
* Decide what to do about #664 (get*Box)
|
* Decide what to do about #664 (get*Box)
|
||||||
* Add an option --ignore-encryption to ignore encryption information
|
* Add an option --ignore-encryption to ignore encryption information
|
||||||
and treat encrypted files as if they weren't encrypted. This should
|
and treat encrypted files as if they weren't encrypted. This should
|
||||||
|
@ -184,6 +184,14 @@ class JSON
|
|||||||
// * The schema is a nested structure containing dictionaries,
|
// * The schema is a nested structure containing dictionaries,
|
||||||
// single-element arrays, and strings only.
|
// single-element arrays, and strings only.
|
||||||
// * Recursively walk the schema.
|
// * Recursively walk the schema.
|
||||||
|
// * Whenever the schema has an array of length 1 and the object
|
||||||
|
// does not have an array in the corresponding location,
|
||||||
|
// validate the object against the array's single element.
|
||||||
|
// This effectively enables a single element to appear in
|
||||||
|
// place of an array and be treated as if it were an array of
|
||||||
|
// one element. This makes it possible to decide later that
|
||||||
|
// something that used to contain a single element now allows
|
||||||
|
// an array without invalidating any old data.
|
||||||
// * If the current value is a dictionary, this object must have
|
// * If the current value is a dictionary, this object must have
|
||||||
// a dictionary in the same place with the same keys. If flags
|
// a dictionary in the same place with the same keys. If flags
|
||||||
// contains f_optional, a key in the schema does not have to
|
// contains f_optional, a key in the schema does not have to
|
||||||
|
@ -538,26 +538,27 @@ JSON::checkSchemaInternal(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (sch_arr) {
|
} else if (sch_arr) {
|
||||||
if (!this_arr) {
|
|
||||||
QTC::TC("libtests", "JSON wanted array");
|
|
||||||
errors.push_back(err_prefix + " is supposed to be an array");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (sch_arr->elements.size() != 1) {
|
if (sch_arr->elements.size() != 1) {
|
||||||
QTC::TC("libtests", "JSON schema array error");
|
QTC::TC("libtests", "JSON schema array error");
|
||||||
errors.push_back(
|
errors.push_back(
|
||||||
err_prefix + " schema array contains other than one item");
|
err_prefix + " schema array contains other than one item");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int i = 0;
|
if (this_arr) {
|
||||||
for (auto const& element: this_arr->elements) {
|
int i = 0;
|
||||||
|
for (auto const& element: this_arr->elements) {
|
||||||
|
checkSchemaInternal(
|
||||||
|
element.get(),
|
||||||
|
sch_arr->elements.at(0).get(),
|
||||||
|
flags,
|
||||||
|
errors,
|
||||||
|
prefix + "." + QUtil::int_to_string(i));
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
QTC::TC("libtests", "JSON schema array for single item");
|
||||||
checkSchemaInternal(
|
checkSchemaInternal(
|
||||||
element.get(),
|
this_v, sch_arr->elements.at(0).get(), flags, errors, prefix);
|
||||||
sch_arr->elements.at(0).get(),
|
|
||||||
flags,
|
|
||||||
errors,
|
|
||||||
prefix + "." + QUtil::int_to_string(i));
|
|
||||||
++i;
|
|
||||||
}
|
}
|
||||||
} else if (!sch_str) {
|
} else if (!sch_str) {
|
||||||
QTC::TC("libtests", "JSON schema other type");
|
QTC::TC("libtests", "JSON schema other type");
|
||||||
|
@ -162,7 +162,9 @@ test_schema()
|
|||||||
"x": "ecks"
|
"x": "ecks"
|
||||||
},
|
},
|
||||||
"s": [
|
"s": [
|
||||||
"esses"
|
{
|
||||||
|
"ss": "esses"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -236,6 +238,8 @@ test_schema()
|
|||||||
JSON bad_schema = JSON::parse(R"({"a": true, "b": "potato?"})");
|
JSON bad_schema = JSON::parse(R"({"a": true, "b": "potato?"})");
|
||||||
check_schema(bad_schema, bad_schema, 0, false, "bad schema field type");
|
check_schema(bad_schema, bad_schema, 0, false, "bad schema field type");
|
||||||
|
|
||||||
|
// "two" exercises the case of the JSON containing a single
|
||||||
|
// element where the schema has an array.
|
||||||
JSON good = JSON::parse(R"(
|
JSON good = JSON::parse(R"(
|
||||||
{
|
{
|
||||||
"one": {
|
"one": {
|
||||||
@ -245,17 +249,15 @@ test_schema()
|
|||||||
"x": [1, null]
|
"x": [1, null]
|
||||||
},
|
},
|
||||||
"s": [
|
"s": [
|
||||||
null,
|
{"ss": null},
|
||||||
"anything"
|
{"ss": "anything"}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"two": [
|
"two": {
|
||||||
{
|
"glarp": "enspliel",
|
||||||
"glarp": "enspliel",
|
"goose": 3.14
|
||||||
"goose": 3.14
|
},
|
||||||
}
|
|
||||||
],
|
|
||||||
"three": {
|
"three": {
|
||||||
"<objid>": {
|
"<objid>": {
|
||||||
"z": "ebra"
|
"z": "ebra"
|
||||||
|
@ -36,7 +36,6 @@ Pl_PNGFilter decodePaeth 0
|
|||||||
Pl_TIFFPredictor processRow 1
|
Pl_TIFFPredictor processRow 1
|
||||||
JSON wanted dictionary 0
|
JSON wanted dictionary 0
|
||||||
JSON key missing in object 0
|
JSON key missing in object 0
|
||||||
JSON wanted array 0
|
|
||||||
JSON schema array error 0
|
JSON schema array error 0
|
||||||
JSON key extra in object 0
|
JSON key extra in object 0
|
||||||
QPDFArgParser read args from stdin 0
|
QPDFArgParser read args from stdin 0
|
||||||
@ -93,3 +92,4 @@ JSON 16 high high 0
|
|||||||
JSON 16 low not after high 0
|
JSON 16 low not after high 0
|
||||||
JSON 16 dangling high 0
|
JSON 16 dangling high 0
|
||||||
JSON parse duplicate key 0
|
JSON parse duplicate key 0
|
||||||
|
JSON schema array for single item 0
|
||||||
|
@ -4,7 +4,8 @@ top-level object is supposed to be a dictionary
|
|||||||
--- missing items
|
--- missing items
|
||||||
json key ".one.a": key "q" is present in schema but missing in object
|
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.r" is supposed to be a dictionary
|
||||||
json key ".one.a.s" is supposed to be an array
|
json key ".one.a.s": key "ss" is present in schema but missing in object
|
||||||
|
json key ".one.a.s": key "z" is not present in schema but appears in object
|
||||||
json key ".one.a": key "t" is not present in schema but appears in object
|
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 "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 ".three.anything": key "x" is not present in schema but appears in object
|
||||||
|
Loading…
Reference in New Issue
Block a user