Merge pull request #163 from vincentbernat/fix/unpack-mix-optional-and-strict

Fix unpack when mixing strict mode and optional keys
This commit is contained in:
Petri Lehtinen 2014-02-16 22:09:41 +02:00
commit 49fc6b1194
2 changed files with 41 additions and 5 deletions

View File

@ -350,6 +350,7 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap)
{
int ret = -1;
int strict = 0;
int gotopt = 0;
/* Use a set (emulated by a hashtable) to check that all object
keys are accessed. Checking that the correct number of keys
@ -406,7 +407,7 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap)
next_token(s);
if(token(s) == '?') {
opt = 1;
opt = gotopt = 1;
next_token(s);
}
@ -432,10 +433,26 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap)
if(strict == 0 && (s->flags & JSON_STRICT))
strict = 1;
if(root && strict == 1 && key_set.size != json_object_size(root)) {
long diff = (long)json_object_size(root) - (long)key_set.size;
set_error(s, "<validation>", "%li object item(s) left unpacked", diff);
goto out;
if(root && strict == 1) {
/* We need to check that all non optional items have been parsed */
const char *key;
json_t *value;
long unpacked = 0;
if (gotopt) {
/* We have optional keys, we need to iter on each key */
json_object_foreach(root, key, value) {
if(!hashtable_get(&key_set, key)) {
unpacked++;
}
}
} else {
/* No optional keys, we can just compare the number of items */
unpacked = (long)json_object_size(root) - (long)key_set.size;
}
if (unpacked) {
set_error(s, "<validation>", "%li object item(s) left unpacked", unpacked);
goto out;
}
}
ret = 0;

View File

@ -378,4 +378,23 @@ static void run_tests()
if(i1 != 42)
fail("json_unpack failed to unpack");
json_decref(j);
/* Combine ? and ! */
j = json_pack("{si}", "foo", 42);
i1 = i2 = 0;
if(json_unpack(j, "{sis?i!}", "foo", &i1, "bar", &i2))
fail("json_unpack failed for optional values with strict mode");
if(i1 != 42)
fail("json_unpack failed to unpack");
if(i2 != 0)
fail("json_unpack failed to unpack");
json_decref(j);
/* But don't compensate a missing key with an optional one. */
j = json_pack("{sisi}", "foo", 42, "baz", 43);
i1 = i2 = i3 = 0;
if(!json_unpack_ex(j, &error, 0, "{sis?i!}", "foo", &i1, "bar", &i2))
fail("json_unpack failed for optional values with strict mode and compensation");
check_error("1 object item(s) left unpacked", "<validation>", 1, 8, 8);
json_decref(j);
}