[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH v2 2/2] pk-mi-json: Improve JSON schema & rewrite pk_val parser
From: |
Mohammad-Reza Nabipoor |
Subject: |
[PATCH v2 2/2] pk-mi-json: Improve JSON schema & rewrite pk_val parser |
Date: |
Sun, 28 Mar 2021 22:37:16 +0430 |
Improved areas:
- More declarative JSON to pk_val conversion
- Improved error handling (error messages are now stacked)
- Reduced assertions on user inputs (There's one case in `pexpect_arr`
that will be removed in future when we change the array schema to
support types).
This commit removed `Null` object and replaced them by JSON `null` value
whenever possible. And changed `Mapping` accordingly.
2021-03-28 Mohammad-Reza Nabipoor <m.nabipoor@yahoo.com>
* etc/pk-mi-json-schema.json: Re-order fields. Remove `Null` object.
Change `Mapping` to accept one required field `mapped` and three
optional fields: `strict`, `IOS` and `offset`.
* poke/pk-mi-json.c: Re-write the JSON to pk_val conversion.
(jerror): New function.
(jexpect): Likewise.
(pvalue): Likewise.
(pexpect): Likewise.
(pexpect_sct): Likewise.
(pexpect_aelem): Likewise.
(pexpect_arr): Likewise.
(pexpect_map): Likewise.
(pk_mi_jsonobj_to_val): Likewise.
(pk_mi_null_to_json): Removed.
(pk_mi_json_to_val_1): Likewise.
(pk_mi_json_poke_value_type): Likewise.
(pk_mi_json_to_int): Likewise.
(pk_mi_json_to_uint): Likewise.
(pk_mi_json_to_string): Likewise.
(pk_mi_json_to_offset): Likewise.
(pk_mi_json_to_mapping): Likewise.
(pk_mi_json_to_sct): Likewise.
(pk_mi_json_array_element_pair): Likewise.
(pk_mi_json_to_array): Likewise.
(collect_json_arg): Use `pk_mi_jsonobj_to_val` function.
(pk_mi_json_to_val): Re-write.
(RETURN_ON_JERR): New macro.
(RETURN_ERR_IF): Likewise.
* testsuite/poke.mi-json/mi-json.c (JFIELD_IMPL): New macro.
(JFIELD): Likewise.
(CHK_IMPL): Likewise.
(CHK): Likewise.
(STREQ_LIT): Likewise.
(test_json_pk_int): Re-write.
(test_json_pk_uint): Likewise.
(test_json_pk_string): Likewise.
(test_json_pk_offset): Likewise.
(test_json_pk_null): Likewise.
(test_json_pk_sct): Likewise.
(test_json_pk_array): Likewise.
(test_json_to_val): Report more info to the `stdout`.
* testsuite/poke.mi-json/pk_offset_uint.json: New sample file.
* testsuite/poke.mi-json/pk_sct_empty.json: Likewise.
* testsuite/poke.mi-json/pk_sct_empty_mapped.json: Likewise.
* testsuite/poke.mi-json/pk_array.json: Change `mapping`.
* testsuite/poke.mi-json/pk_sct.json: Likewise.
* testsuite/Makefile.am (EXTRA_DIST): Updated.
---
Hi, Jose and Kostas.
As before, this is a full rewrite of JSON->pk_val conversion and tests.
Still don't support `null` for array items and empty arrays, which requires
adding types to JSON schema.
Changes from v1:
- I changed the JSON Schema and removed the `Null` object to make everything
more consistent. I chose the `null` value of JSON itself to represent null.
(Also re-wrote the `pk_mi_null_to_json` to support this).
- `Mapping` now only has one required field: `mapped`.
If it is `true`, parser expects the three other fields:
`strict`, `IOS` and `offset`.
(See `testsuite/poke.mi-json/pk_sct_empty.json` and
`testsuite/poke.mi-json/pk_sct_empty_mapped.json` as examples)
- Error handling macros now explicitly uses `errmsg`.
Comments are welcome!
Regards,
Mohammad-Reza
P.S. I used `--patience` this time for diff generation, so diffs are
more readable now.
ChangeLog | 50 +
etc/pk-mi-json-schema.json | 54 +-
poke/pk-mi-json.c | 1136 +++++++++--------
testsuite/Makefile.am | 3 +
testsuite/poke.mi-json/Makefile.am | 3 +-
testsuite/poke.mi-json/mi-json.c | 461 ++++---
testsuite/poke.mi-json/pk_array.json | 2 +-
testsuite/poke.mi-json/pk_offset_uint.json | 18 +
testsuite/poke.mi-json/pk_sct.json | 3 +-
testsuite/poke.mi-json/pk_sct_empty.json | 17 +
.../poke.mi-json/pk_sct_empty_mapped.json | 33 +
11 files changed, 1004 insertions(+), 776 deletions(-)
create mode 100644 testsuite/poke.mi-json/pk_offset_uint.json
create mode 100644 testsuite/poke.mi-json/pk_sct_empty.json
create mode 100644 testsuite/poke.mi-json/pk_sct_empty_mapped.json
diff --git a/ChangeLog b/ChangeLog
index ff49f4fd..964ab5ae 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,53 @@
+2021-03-28 Mohammad-Reza Nabipoor <m.nabipoor@yahoo.com>
+
+ * etc/pk-mi-json-schema.json: Re-order fields. Remove `Null` object.
+ Change `Mapping` to accept one required field `mapped` and three
+ optional fields: `strict`, `IOS` and `offset`.
+ * poke/pk-mi-json.c: Re-write the JSON to pk_val conversion.
+ (jerror): New function.
+ (jexpect): Likewise.
+ (pvalue): Likewise.
+ (pexpect): Likewise.
+ (pexpect_sct): Likewise.
+ (pexpect_aelem): Likewise.
+ (pexpect_arr): Likewise.
+ (pexpect_map): Likewise.
+ (pk_mi_jsonobj_to_val): Likewise.
+ (pk_mi_null_to_json): Removed.
+ (pk_mi_json_to_val_1): Likewise.
+ (pk_mi_json_poke_value_type): Likewise.
+ (pk_mi_json_to_int): Likewise.
+ (pk_mi_json_to_uint): Likewise.
+ (pk_mi_json_to_string): Likewise.
+ (pk_mi_json_to_offset): Likewise.
+ (pk_mi_json_to_mapping): Likewise.
+ (pk_mi_json_to_sct): Likewise.
+ (pk_mi_json_array_element_pair): Likewise.
+ (pk_mi_json_to_array): Likewise.
+ (collect_json_arg): Use `pk_mi_jsonobj_to_val` function.
+ (pk_mi_json_to_val): Re-write.
+ (RETURN_ON_JERR): New macro.
+ (RETURN_ERR_IF): Likewise.
+ * testsuite/poke.mi-json/mi-json.c (JFIELD_IMPL): New macro.
+ (JFIELD): Likewise.
+ (CHK_IMPL): Likewise.
+ (CHK): Likewise.
+ (STREQ_LIT): Likewise.
+ (test_json_pk_int): Re-write.
+ (test_json_pk_uint): Likewise.
+ (test_json_pk_string): Likewise.
+ (test_json_pk_offset): Likewise.
+ (test_json_pk_null): Likewise.
+ (test_json_pk_sct): Likewise.
+ (test_json_pk_array): Likewise.
+ (test_json_to_val): Report more info to the `stdout`.
+ * testsuite/poke.mi-json/pk_offset_uint.json: New sample file.
+ * testsuite/poke.mi-json/pk_sct_empty.json: Likewise.
+ * testsuite/poke.mi-json/pk_sct_empty_mapped.json: Likewise.
+ * testsuite/poke.mi-json/pk_array.json: Change `mapping`.
+ * testsuite/poke.mi-json/pk_sct.json: Likewise.
+ * testsuite/Makefile.am (EXTRA_DIST): Updated.
+
2021-03-28 Mohammad-Reza Nabipoor <m.nabipoor@yahoo.com>
* libpoke/libpoke.h (pk_val_mappable_p): New function declaration.
diff --git a/etc/pk-mi-json-schema.json b/etc/pk-mi-json-schema.json
index 5b0a980c..827e083a 100644
--- a/etc/pk-mi-json-schema.json
+++ b/etc/pk-mi-json-schema.json
@@ -105,9 +105,9 @@
},
"maxProperties" : 3,
"required": [
+ "type"
"magnitude",
- "base",
- "type"
+ "unit",
],
"title": "Offset"
},
@@ -168,24 +168,28 @@
},
"mapping" : {
"type" : "object",
- "oneOf" : [
- { "$ref" : "#/definitions/Mapping" },
- { "$ref" : "#/definitions/Null" }
+ "$ref" : "#/definitions/Mapping"
]
}
},
"maxProperties" : 4,
"required": [
+ "type",
+ "name",
"fields",
- "type",
- "mapping",
- "name"
+ "mapping"
],
"title": "Struct"
},
"Mapping": {
"type": "object",
"properties": {
+ "mapped": {
+ "type": "boolean",
+ },
+ "strict": {
+ "type": "boolean",
+ },
"IOS": {
"type": "integer",
"minimum" : -2147483648,
@@ -196,10 +200,9 @@
"$ref": "#/definitions/Offset"
}
},
- "maxProperties": 2,
+ "maxProperties": 4,
"required": [
- "IOS",
- "offset"
+ "mapped"
],
"title": "Mapping"
},
@@ -211,7 +214,7 @@
"const" : "Array"
},
"elements" : {
- "type": "array",
+ "type": "array",
"items": {
"type": "object",
"properties" : {
@@ -224,7 +227,7 @@
{ "$ref": "#/definitions/Struct" },
{ "$ref": "#/definitions/Array" },
{ "$ref": "#/definitions/Offset" },
- { "$ref": "#/definitions/Null" }
+ { "type": null }
]
},
"boffset" : {
@@ -248,10 +251,7 @@
},
"mapping" : {
"type" : "object",
- "oneOf" : [
- { "$ref" : "#/definitions/Mapping" },
- { "$ref" : "#/definitions/Null" }
- ]
+ "$ref" : "#/definitions/Mapping"
}
},
"maxProperties" : 3,
@@ -260,24 +260,6 @@
"type",
"mapping"
]
- },
- "Null": {
- "type": "object",
- "properties" : {
- "type" : {
- "type" : "string",
- "const" : "Null"
- },
- "value" : {
- "type" : "null"
- }
- },
- "maxProperties" : 2,
- "required" : [
- "type",
- "value"
- ],
- "title": "Null"
}
},
"type": "object",
@@ -291,7 +273,7 @@
{ "$ref": "#/definitions/Struct" },
{ "$ref": "#/definitions/Array" },
{ "$ref": "#/definitions/Offset" },
- { "$ref": "#/definitions/Null" }
+ { "type": "null" }
]
}
},
diff --git a/poke/pk-mi-json.c b/poke/pk-mi-json.c
index bc2f4daa..d6ab81d8 100644
--- a/poke/pk-mi-json.c
+++ b/poke/pk-mi-json.c
@@ -19,29 +19,94 @@
#include <config.h>
#include <assert.h>
+#include <stdio.h>
#include <string.h>
#include <json.h>
-#include "pk-term.h"
#include "pk-mi.h"
#include "pk-mi-json.h"
#include "pk-mi-msg.h"
#include "libpoke.h"
+#include "pk-utils.h"
-#define PK_MI_CHECK(errmsg, A, M, ...) \
- do \
- { \
- int r; \
- if (A) \
- break; \
- if (errmsg != NULL && \
- (r = asprintf (errmsg, "[ERROR] " M , ##__VA_ARGS__)) == -1) { \
- *errmsg = NULL; \
- assert (0 && "asprintf () failed"); \
- } \
- goto error; \
- } \
- while (0)
+#define J_OK 1
+#define J_NOK 0 /* Not OK */
+
+#define PK_MI_CHECK(errmsg, A, ...) \
+ do \
+ { \
+ if (A) \
+ break; \
+ if (errmsg != NULL && asprintf (errmsg, "[ERROR] " __VA_ARGS__) == -1) \
+ { \
+ *errmsg = NULL; \
+ assert (0 && "asprintf () failed"); \
+ } \
+ goto error; \
+ } \
+ while (0)
+
+/* Error message handling */
+
+/* Prepend the error message to OUT */
+static int __attribute__ ((format (printf, 3, 4)))
+jerror (int ok, char **out, const char *fmt, ...)
+{
+#define BUFSZ 512 /* FIXME use dynamic mem */
+
+ char buf[BUFSZ];
+ va_list ap;
+
+ if (ok == J_OK || out == NULL)
+ return ok;
+
+ if (*out == NULL)
+ {
+ va_start (ap, fmt);
+ vsnprintf (buf, BUFSZ, fmt, ap);
+ va_end (ap);
+ }
+ else
+ {
+ int n;
+
+ /* prepend the new error message */
+ va_start (ap, fmt);
+ n = vsnprintf (buf, BUFSZ, fmt, ap);
+ va_end (ap);
+
+ /* append the old error message (if there's enough space) */
+ if (0 <= n && n < BUFSZ)
+ snprintf (buf + n, BUFSZ - n, ": %s", *out);
+ free (*out);
+ }
+
+ *out = strdup (buf);
+ return ok;
+
+#undef BUFSZ
+}
+
+#define RETURN_ON_JERR(cond, errmsg, ...) \
+ do \
+ { \
+ int _cond = (cond); \
+ \
+ if (_cond != J_OK) \
+ return jerror (_cond, errmsg, __VA_ARGS__); \
+ } \
+ while (0)
+
+#define RETURN_ERR_IF(cond, errmsg, ...) \
+ do \
+ { \
+ if ((cond)) \
+ return jerror (J_NOK, errmsg, __VA_ARGS__); \
+ } \
+ while (0)
+
+
+/* MI Messages */
/* Message::
{
@@ -250,42 +315,60 @@ pk_mi_offset_to_json (pk_val pk_offset, char **errmsg)
static json_object *
pk_mi_mapping_to_json (pk_val val, char **errmsg)
{
- json_object *mapping_object, *ios_object, *offset_object;
-
- offset_object = pk_mi_offset_to_json (pk_val_offset (val), errmsg);
-
- ios_object = json_object_new_int64 (pk_int_value (pk_val_ios (val)));
- PK_MI_CHECK (errmsg, ios_object != NULL, "json_object_new_object () failed");
-
- mapping_object = json_object_new_object ();
- PK_MI_CHECK (errmsg, mapping_object != NULL, "json_object_new_object ()
failed");
-
- json_object_object_add (mapping_object, "IOS", ios_object);
- json_object_object_add (mapping_object, "offset", offset_object);
-
- return mapping_object;
-
- error:
- return NULL;
-}
-
-static json_object *
-pk_mi_null_to_json (char **errmsg)
-{
- json_object *pk_null_object;
-
- pk_null_object = json_object_new_object ();
- PK_MI_CHECK (errmsg, pk_null_object != NULL,
- "json_object_new_object () failed");
-
- json_object_object_add (pk_null_object, "type",
- json_object_new_string ("Null"));
- json_object_object_add (pk_null_object, "value", NULL);
-
- return pk_null_object;
-
- error:
- return NULL;
+ enum
+ {
+ mapping,
+ mapped,
+ strict,
+ ios,
+ offset
+ };
+ const int LEN = 5;
+ /* Store all JSON objects in an array to make resource management easier */
+ json_object *j[LEN];
+ int mapped_p;
+
+ memset (j, 0, sizeof (j));
+
+ j[mapping] = json_object_new_object ();
+ PK_MI_CHECK (errmsg, j[mapping] != NULL, "json_object_new_object () failed");
+
+ mapped_p = pk_val_mapped_p (val);
+ j[mapped] = json_object_new_boolean (mapped_p);
+ PK_MI_CHECK (errmsg, j[mapped] != NULL, "json_object_new_boolean () failed");
+
+ if (!mapped_p)
+ {
+ json_object_object_add (j[mapping], "mapped", j[mapped]);
+ return j[mapping];
+ }
+
+ j[strict] = json_object_new_boolean (pk_val_strict_p (val));
+ PK_MI_CHECK (errmsg, j[strict] != NULL, "json_object_new_boolean () failed");
+
+ j[offset] = pk_mi_offset_to_json (pk_val_offset (val), errmsg);
+ if (j[offset] == NULL)
+ goto error;
+
+ j[ios] = json_object_new_int64 (pk_int_value (pk_val_ios (val)));
+ PK_MI_CHECK (errmsg, j[ios] != NULL, "json_object_new_object () failed");
+
+ json_object_object_add (j[mapping], "mapped", j[mapped]);
+ json_object_object_add (j[mapping], "strict", j[strict]);
+ json_object_object_add (j[mapping], "IOS", j[ios]);
+ json_object_object_add (j[mapping], "offset", j[offset]);
+
+ return j[mapping];
+
+error:
+ for (int i = 0; i < LEN; i++)
+ if (j[i])
+ {
+ int free_p = json_object_put (j[i]);
+
+ assert (free_p == 1);
+ }
+ return NULL;
}
static json_object *
@@ -349,10 +432,9 @@ pk_mi_sct_to_json (pk_val pk_sct, char **errmsg)
"failed to add name object to struct field");
}
- /* Optionally, add a mapping. */
- pk_sct_mapping_object = pk_val_mapped_p (pk_sct) ?
- pk_mi_mapping_to_json (pk_sct, errmsg) :
- pk_mi_null_to_json (errmsg);
+ pk_sct_mapping_object = pk_mi_mapping_to_json (pk_sct, errmsg);
+ if (pk_sct_mapping_object == NULL)
+ goto error;
pk_sct_object = json_object_new_object ();
PK_MI_CHECK (errmsg, pk_sct_object != NULL,
@@ -418,11 +500,7 @@ pk_mi_array_to_json (pk_val pk_array, char **errmsg)
PK_MI_CHECK (errmsg, err != -1, "failed to add element to array");
}
- /* Optionally, add a mapping. */
- pk_array_mapping_object = pk_val_mapped_p (pk_array) ?
- pk_mi_mapping_to_json (pk_array, errmsg) :
- pk_mi_null_to_json (errmsg);
-
+ pk_array_mapping_object = pk_mi_mapping_to_json (pk_array, errmsg);
if (pk_array_mapping_object == NULL)
goto error;
@@ -443,39 +521,33 @@ pk_mi_val_to_json_1 (pk_val val, char **errmsg)
{
json_object *pk_val_object = NULL;
- if (val == PK_NULL) {
- pk_val_object = pk_mi_null_to_json (errmsg);
- }
- else {
- switch (pk_type_code (pk_typeof (val)))
- {
- case PK_INT:
- pk_val_object = pk_mi_int_to_json (val, errmsg);
- break;
- case PK_UINT:
- pk_val_object = pk_mi_uint_to_json (val, errmsg);
- break;
- case PK_STRING:
- pk_val_object = pk_mi_string_to_json (val, errmsg);
- break;
- case PK_OFFSET:
- pk_val_object = pk_mi_offset_to_json (val, errmsg);
- break;
- case PK_STRUCT:
- pk_val_object = pk_mi_sct_to_json (val, errmsg);
- break;
- case PK_ARRAY:
- pk_val_object = pk_mi_array_to_json (val, errmsg);
- break;
- case PK_CLOSURE:
- case PK_ANY:
- default:
- assert (0);
- }
- if (!pk_val_object)
- return NULL;
- }
-
+ if (val == PK_NULL)
+ return NULL;
+ switch (pk_type_code (pk_typeof (val)))
+ {
+ case PK_INT:
+ pk_val_object = pk_mi_int_to_json (val, errmsg);
+ break;
+ case PK_UINT:
+ pk_val_object = pk_mi_uint_to_json (val, errmsg);
+ break;
+ case PK_STRING:
+ pk_val_object = pk_mi_string_to_json (val, errmsg);
+ break;
+ case PK_OFFSET:
+ pk_val_object = pk_mi_offset_to_json (val, errmsg);
+ break;
+ case PK_STRUCT:
+ pk_val_object = pk_mi_sct_to_json (val, errmsg);
+ break;
+ case PK_ARRAY:
+ pk_val_object = pk_mi_array_to_json (val, errmsg);
+ break;
+ case PK_CLOSURE:
+ case PK_ANY:
+ default:
+ assert (0);
+ }
return pk_val_object;
}
@@ -492,463 +564,475 @@ pk_mi_val_to_json (pk_val val, char **errmsg)
json_object_object_add (pk_object, "PokeValue", pk_val_object);
- return pk_object != NULL ?
- json_object_to_json_string_ext (pk_object, JSON_C_TO_STRING_PRETTY)
- : NULL;
+ return json_object_to_json_string_ext (pk_object, JSON_C_TO_STRING_PRETTY);
error:
return NULL;
}
/* Functions to convert JSON object to Poke value. */
-static int pk_mi_json_to_val_1 (pk_val *poke_value, json_object *obj,
- char **errmsg);
-static const char *
-pk_mi_json_poke_value_type (json_object *obj)
-{
- json_object *search_object;
-
- /* Get the Poke value type. */
- if (json_object_object_get_ex (obj, "type", &search_object) == 0)
- return NULL;
-
- return json_object_to_json_string (search_object);
-}
-
-static int
-pk_mi_json_to_int (pk_val *pk_int, json_object *int_obj, char **errmsg)
-{
- json_object *value_object, *size_object;
- int64_t value;
- int size, err;
-
- err = json_object_object_get_ex (int_obj, "value", &value_object);
- PK_MI_CHECK (errmsg, err != 0,
- "json type %s does not contain key \"value\"",
- pk_mi_json_poke_value_type (int_obj));
- value = json_object_get_int64 (value_object);
-
- err = json_object_object_get_ex (int_obj, "size", &size_object);
- PK_MI_CHECK (errmsg, err != 0,
- "json type %s does not contain key \"size\"",
- pk_mi_json_poke_value_type (int_obj));
- size = json_object_get_int (size_object);
-
- *pk_int = pk_make_int (value, size);
- PK_MI_CHECK (errmsg, *pk_int != PK_NULL, "pk_make_int failed");
-
- return 0;
-
- error:
- return -1;
-}
-
-static int
-pk_mi_json_to_uint (pk_val *pk_uint, json_object *uint_obj,
- char **errmsg)
-{
- json_object *value_object, *size_object;
- uint64_t value;
- int size, err;
-
- err = json_object_object_get_ex (uint_obj, "value", &value_object);
- PK_MI_CHECK (errmsg, err != 0,
- "json type %s does not contain key \"value\"",
- pk_mi_json_poke_value_type (uint_obj));
-
- /* Older versions of libjson-c (0.3.1 & under) do not support
- json_object_get_uint64 (only json_object_get_int64).
-
- In order to support previous versions, we store unsigned integers
- as signed integers despite them being too large to represent as
- signed. (i.e. they are stored as negative).
-
- However, users expect to get the unsigned integer they stored.
-
- Thus, we have to convert it back to uint64_t. */
- value = (uint64_t) json_object_get_int64 (value_object);
-
- err = json_object_object_get_ex (uint_obj, "size", &size_object);
- PK_MI_CHECK (errmsg, err != 0,
- "json type %s does not contain key \"size\"",
- pk_mi_json_poke_value_type (uint_obj));
- size = json_object_get_int (size_object);
-
- *pk_uint = pk_make_uint (value, size);
- PK_MI_CHECK (errmsg, *pk_uint != PK_NULL, "pk_make_uint failed");
-
- return 0;
-
- error:
- return -1;
-}
-
-static int
-pk_mi_json_to_string (pk_val *pk_string, json_object *str_obj,
- char **errmsg)
-{
- json_object *value_object;
- const char *value_str;
- int err;
-
- err = json_object_object_get_ex (str_obj, "value", &value_object);
- PK_MI_CHECK (errmsg, err != 0,
- "json type %s does not contain key \"value\"",
- pk_mi_json_poke_value_type (str_obj));
- value_str = json_object_get_string (value_object);
-
- *pk_string = pk_make_string (value_str);
- PK_MI_CHECK (errmsg, *pk_string != PK_NULL, "pk_make_string failed");
-
- return 0;
-
- error:
- return -1;
-}
-
-static int
-pk_mi_json_to_offset (pk_val *pk_offset, json_object *offset_obj,
- char **errmsg)
-{
- /* To build a pk_offset, we need its magnitude and its unit. */
- pk_val magnitude, unit;
- json_object *magnitude_object, *unit_object;
- int err;
-
- err = json_object_object_get_ex (offset_obj, "magnitude", &magnitude_object);
- PK_MI_CHECK (errmsg, err != 0,
- "json type %s does not contain key \"magnitude\"",
- pk_mi_json_poke_value_type (offset_obj));
-
- if (pk_mi_json_to_val_1 (&magnitude, magnitude_object, errmsg) == -1)
- goto error;
-
- err = json_object_object_get_ex (offset_obj, "unit", &unit_object);
- PK_MI_CHECK (errmsg, err != 0,
- "json type %s does not contain key \"unit\"",
- pk_mi_json_poke_value_type (offset_obj));
-
- assert (json_object_get_type (unit_object) == json_type_object);
-
- err = pk_mi_json_to_uint (&unit, unit_object, errmsg);
- PK_MI_CHECK (errmsg, err != -1,
- "unable to convert offset unit to pk_uint");
- assert (pk_uint_size (unit) == 64);
-
- *pk_offset = pk_make_offset (magnitude, unit);
- PK_MI_CHECK(errmsg, *pk_offset != PK_NULL, "pk_make_offset failed");
-
- return 0;
-
- error:
- return -1;
-}
-
-static int
-pk_mi_json_to_mapping (pk_val *poke_value, json_object *obj,
- char **errmsg)
-{
- /* TODO: write me. */
- return 0;
-}
-
-static int
-pk_mi_json_to_sct (pk_val *pk_sct, json_object *sct_obj,
- char **errmsg)
-{
- /* To build a pk_struct, we need its fields, its name and its mapping. */
- json_object *array_object, *fields_object, *search_object;
- pk_val mapping, sct_type, sct_field_name, sct_field_value, sct_field_boffset;
- pk_val sct, *fnames, *ftypes, nfields, name;
- size_t fields_len;
- int err;
-
- err = json_object_object_get_ex (sct_obj, "fields", &search_object);
- PK_MI_CHECK (errmsg, err != 0,
- "json type %s does does not contain key \"fields\"",
- pk_mi_json_poke_value_type (sct_obj));
-
- fields_object = search_object;
- assert (json_object_get_type (fields_object) == json_type_array);
-
- fields_len = json_object_array_length (fields_object);
-
- if (fields_len > 0)
- {
- err = json_object_object_get_ex (sct_obj, "name", &search_object);
- PK_MI_CHECK (errmsg, err != 0,
- "json type %s does does not contain key \"name\"",
- pk_mi_json_poke_value_type (sct_obj));
- nfields = pk_make_uint (fields_len, 64);
-
- /* Here, we don't use PK_MI_CHECK because
- it would reallocate & refill errmsg.
-
- TODO (kostas): check if there is a bug anywhere in the code
- if asprintf () gets called more than once. */
- if (pk_mi_json_to_val_1 (&name, search_object, errmsg) == -1)
- goto error;
-
- pk_allocate_struct_attrs (nfields, &fnames, &ftypes);
-
- sct_type = pk_make_struct_type (nfields, name, fnames, ftypes);
- sct = pk_make_struct (nfields, sct_type);
- for (size_t i = 0 ; i < fields_len ; i++)
- {
- array_object = json_object_array_get_idx (fields_object, i);
-
- err = json_object_object_get_ex (array_object, "name",
- &search_object);
- PK_MI_CHECK (errmsg, err != 0,
- "json type %s does not contain key \"name\"",
- pk_mi_json_poke_value_type (array_object));
-
- if (pk_mi_json_to_val_1 (&sct_field_name, search_object, errmsg) ==
-1)
- goto error;
-
- err = json_object_object_get_ex (array_object, "value",
- &search_object);
- PK_MI_CHECK (errmsg, err != 0,
- "json type %s does not contain key \"value\"",
- pk_mi_json_poke_value_type (array_object));
-
- if (pk_mi_json_to_val_1 (&sct_field_value, search_object, errmsg) ==
-1)
- goto error;
-
- err = json_object_object_get_ex (array_object, "boffset",
- &search_object);
- PK_MI_CHECK (errmsg, err != 0,
- "json type %s does not contain key \"boffset\"",
- pk_mi_json_poke_value_type (array_object));
-
- if (pk_mi_json_to_val_1 (&sct_field_boffset, search_object, errmsg)
== -1)
- goto error;
-
- assert (pk_type_code (pk_typeof (sct_field_name)) == PK_STRING);
- assert (pk_type_code (pk_typeof (sct_field_boffset)) == PK_UINT);
-
- pk_struct_type_set_fname (sct_type, i, sct_field_name);
- pk_struct_type_set_ftype (sct_type, i, pk_typeof (sct_field_value));
- pk_struct_set_field_boffset (sct, i, sct_field_boffset);
- pk_struct_set_field_name (sct, i, sct_field_name);
- pk_struct_set_field_value (sct, i, sct_field_value);
- }
-
- err = json_object_object_get_ex (sct_obj, "mapping", &search_object);
- PK_MI_CHECK (errmsg, err != 0,
- "json type %s does not contain key \"mapping\"",
- pk_mi_json_poke_value_type (sct_obj));
- PK_MI_CHECK (errmsg,
- pk_mi_json_to_mapping (&mapping, search_object, errmsg) != -1,
- "failed to create mapping for struct");
- }
- else
- {
- sct = PK_NULL;
- }
-
- *pk_sct = sct;
-
- return 0;
-
- error:
- return -1;
-}
-
-static pk_val *
-pk_mi_json_array_element_pair (json_object *elements_object, size_t idx,
- char **errmsg)
-{
- json_object *element_object, *search_object;
- int err;
-
- /* value-offset pair. */
- pk_val *pair = (pk_val *) malloc (sizeof (pk_val) * 2);
-
- element_object = json_object_array_get_idx (elements_object, idx);
-
- err = json_object_object_get_ex (element_object, "value", &search_object);
- PK_MI_CHECK (errmsg, err != 0,
- "json type %s does not contain key \"value\"",
- pk_mi_json_poke_value_type (element_object));
- if (pk_mi_json_to_val_1 (&(pair[0]), search_object, errmsg) == -1)
- goto error;
-
- err = json_object_object_get_ex (element_object, "boffset", &search_object);
- PK_MI_CHECK (errmsg, err != 0,
- "json type %s does not contain key \"boffset\"",
- pk_mi_json_poke_value_type (element_object));
-
- if (pk_mi_json_to_val_1 (&(pair[1]), search_object, errmsg) == -1)
- goto error;
-
- return pair;
-
- error:
- return NULL;
-}
+static int pvalue (json_object *j, pk_val *pval, char **errmsg);
+static int pexpect (json_object *j, int type_code, pk_val *pval,
+ char **errmsg);
+/* Adapter function */
static int
-pk_mi_json_to_array (pk_val *pk_array, json_object *array_obj,
- char **errmsg)
+pk_mi_jsonobj_to_val (pk_val *value, json_object *obj, char **errmsg)
{
- /* To build a pk_array, we need its elements and its mapping. */
- json_object *elements_object, *search_object;
- pk_val array_type, mapping, array_etype, array, *element_pair;
- size_t elements_len;
- int err;
-
- err = json_object_object_get_ex (array_obj, "elements", &search_object);
- PK_MI_CHECK (errmsg, err != 0,
- "json type %s does not contain key \"elements\"",
- pk_mi_json_poke_value_type (array_obj));
-
- elements_object = search_object;
- assert (json_object_get_type (elements_object) == json_type_array);
-
- elements_len = json_object_array_length (elements_object);
-
- if (elements_len > 0)
- {
- /* We need to get the type of array elements first. */
- element_pair = pk_mi_json_array_element_pair (elements_object, 0,
errmsg);
- if (element_pair == NULL)
- goto error;
-
- array_etype = pk_typeof (element_pair[0]);
- array_type = pk_make_array_type (array_etype, PK_NULL);
- array = pk_make_array (pk_make_uint (elements_len, 64), array_type);
-
- assert (pk_type_code (pk_typeof (element_pair[1])) == PK_UINT);
-
- pk_array_insert_elem (array, 0, element_pair[0]);
- free (element_pair);
-
- for (size_t i = 1 ; i < elements_len ; i++)
- {
- element_pair = pk_mi_json_array_element_pair (elements_object, i,
- errmsg);
- if (element_pair == NULL)
- goto error;
-
- assert (pk_type_code (pk_typeof (element_pair[0]))
- == pk_type_code (array_etype));
- assert (pk_type_code (pk_typeof (element_pair[1])) == PK_UINT);
-
- pk_array_insert_elem (array, i, element_pair[0]);
- free (element_pair);
- }
-
- err = json_object_object_get_ex (array_obj, "mapping", &search_object);
- PK_MI_CHECK (errmsg, err != 0,
- "json type %s does not contain key \"mapping\"",
- pk_mi_json_poke_value_type (array_obj));
-
- PK_MI_CHECK(errmsg,
- pk_mi_json_to_mapping (&mapping, search_object, errmsg) != -1,
- "failed to create mapping for struct");
- }
- else
- {
- array = PK_NULL;
- }
-
- *pk_array = array;
-
- return 0;
-
- error:
- return -1;
+ return pvalue (obj, value, errmsg) == J_OK ? 0 : -1;
}
-static int
-pk_mi_json_to_val_1 (pk_val *poke_value, json_object *obj,
- char **errmsg)
-{
- const char *poke_object_type;
-
- poke_object_type = pk_mi_json_poke_value_type (obj);
- if (poke_object_type == NULL)
- goto error;
-
- if (!strncmp (poke_object_type, "\"Integer\"", strlen ("\"Integer\"")))
- {
- if (pk_mi_json_to_int (poke_value, obj, errmsg) == -1)
- goto error;
- }
- else if (!strncmp (poke_object_type, "\"UnsignedInteger\"",
- strlen ("\"UnsignedInteger\"")))
- {
- if (pk_mi_json_to_uint (poke_value, obj, errmsg) == -1)
- goto error;
- }
- else if (!strncmp (poke_object_type, "\"String\"", strlen ("\"String\"")))
- {
- if (pk_mi_json_to_string (poke_value, obj, errmsg) == -1)
- goto error;
- }
- else if (!strncmp (poke_object_type, "\"Offset\"", strlen ("\"Offset\"")))
- {
- if (pk_mi_json_to_offset (poke_value, obj, errmsg) == -1)
- goto error;
- }
- else if (!strncmp (poke_object_type, "\"Array\"", strlen ("Array")))
- {
- if (pk_mi_json_to_array (poke_value, obj, errmsg) == -1)
- goto error;
- }
- else if (!strncmp (poke_object_type, "\"Struct\"", strlen ("\"Struct\"")))
- {
- if (pk_mi_json_to_sct (poke_value, obj, errmsg) == -1)
- goto error;
- }
- else if (!strncmp (poke_object_type, "\"Null\"", strlen ("\"Null\"")))
- *poke_value = PK_NULL;
- else
- {
- asprintf (errmsg, "An unexpected error happened, this is a bug.");
- return -1;
- }
-
- return 0;
-
- error:
- return -1;
-}
-
-
int
pk_mi_json_to_val (pk_val *value, const char *json_str, char **errmsg)
{
- json_object *search_object, *poke_object = NULL;
- json_tokener *tok = json_tokener_new ();
+ json_object *j_obj = NULL, *j_pokevalue;
+ json_tokener *tok = NULL;
enum json_tokener_error jerr;
- int err;
+ char *local_errmsg = NULL;
+ int ret, free_p;
- /* Parse the current object and get its PK_TYPE. */
- do
+ /* All internal functions assume `errmsg` is either NULL or valid pointer
+ to a memory allocated by `malloc`. */
+ if (errmsg)
+ *errmsg = NULL; /* success */
+
+ tok = json_tokener_new ();
+ PK_MI_CHECK (errmsg, tok != NULL, "json_tokener_new () failed");
+
+ j_obj = json_tokener_parse_ex (tok, json_str, strlen (json_str) + 1);
+ jerr = json_tokener_get_error (tok);
+ PK_MI_CHECK (errmsg, j_obj != NULL, "json_tokener_parse_ex () failed: %s",
+ json_tokener_error_desc (jerr));
+ PK_MI_CHECK (errmsg, jerr == json_tokener_success,
+ "json_tokener_parse_ex () failed: %s",
+ json_tokener_error_desc (jerr));
+
+ PK_MI_CHECK (errmsg,
+ json_object_object_get_ex (j_obj, "PokeValue", &j_pokevalue)
+ == J_OK,
+ "expects \"PokeValue\" field");
+ PK_MI_CHECK (errmsg, pvalue (j_pokevalue, value, &local_errmsg) == J_OK,
+ "Invalid PokeValue object: %s", local_errmsg);
+
+ ret = 0;
+ goto deinit; /* because of the `goto error` inside the PK_MI_CHECK macro */
+
+error:
+ ret = -1;
+
+deinit:
+ free (local_errmsg);
+ if (j_obj)
+ {
+ free_p = json_object_put (j_obj);
+ assert (free_p == 1);
+ }
+ if (tok)
+ json_tokener_free (tok);
+ return ret;
+}
+
+/* Expects field FIELD of type EXPECTED_TYPE in JSON object.
+ *
+ * Returns J_OK on success, J_NOK otherwise.
+ */
+static int
+jexpect (json_object *obj, const char *field, json_type expected_type,
+ json_object **j_val, char **errmsg)
+{
+ json_object *j_field;
+
+ RETURN_ON_JERR (json_object_object_get_ex (obj, field, &j_field), errmsg,
+ "expects key \"%s\"", field);
+ RETURN_ON_JERR (json_object_is_type (j_field, expected_type), errmsg,
+ "expects JSON item of type \"%s\" for field \"%s\"",
+ json_type_to_name (expected_type), field);
+ *j_val = j_field;
+ return J_OK;
+}
+
+/* Parses JSON object as a Poke value.
+ *
+ * Returns J_OK on success, J_NOK otherwise.
+ */
+static inline int
+pvalue (json_object *obj, pk_val *pval, char **errmsg)
+{
+ static const struct
+ {
+ int type_code;
+ const char *name;
+ } TYPES[] = {
+ { PK_UNKNOWN, "\"Unknown\"" },
+ { PK_INT, "\"Integer\"" },
+ { PK_UINT, "\"UnsignedInteger\"" },
+ { PK_STRING, "\"String\"" },
+ { PK_OFFSET, "\"Offset\"" },
+ { PK_ARRAY, "\"Array\"" },
+ { PK_STRUCT, "\"Struct\"" },
+ { PK_CLOSURE, "\"Closure\"" },
+ { PK_ANY, "\"Any\"" },
+ };
+ static const int TYPES_LEN = sizeof (TYPES) / sizeof (TYPES[0]);
+ int type_code;
+ const char *type_str;
+ json_object *j_type;
+
+ if (obj == NULL) {
+ *pval = PK_NULL;
+ return J_OK;
+ }
+
+ RETURN_ON_JERR (json_object_object_get_ex (obj, "type", &j_type), errmsg,
+ "expects \"type\" key");
+ type_str = json_object_to_json_string (j_type);
+
+ type_code = PK_UNKNOWN;
+ for (int i = 0; i < TYPES_LEN; ++i)
+ if (STREQ (type_str, TYPES[i].name))
+ {
+ type_code = TYPES[i].type_code;
+ break;
+ }
+ return pexpect (obj, type_code, pval, errmsg);
+}
+
+static int pexpect_sct (json_object *j_sct, pk_val *pk_sct, char **errmsg);
+static int pexpect_arr (json_object *j_arr, pk_val *p_array, char **errmsg);
+
+/* Expects a Poke value of type specified by TYPE_CODE in JSON object.
+ *
+ * Valid values for TYPE_CODE:
+ * PK_UNKNOWN, PK_INT, PK_UINT, PK_STRING, PK_OFFSET, PK_ARRAY, PK_STRUCT,
+ * PK_CLOSURE, PK_ANY.
+ *
+ * Returns J_OK on success, J_NOK otherwise.
+ */
+static int
+pexpect (json_object *j, int type_code, pk_val *pval, char **errmsg)
+{
+ json_object *j_tmp;
+ const char *str;
+
+ switch (type_code)
+ {
+ case PK_STRING:
+ RETURN_ON_JERR (jexpect (j, "type", json_type_string, &j_tmp, errmsg),
+ errmsg, "invalid String");
+ str = json_object_get_string (j_tmp);
+ RETURN_ERR_IF (STRNEQ (str, "String"), errmsg,
+ "expects \"String\" in field \"type\" but got \"%s\"",
+ str);
+
+ RETURN_ON_JERR (jexpect (j, "value", json_type_string, &j_tmp, errmsg),
+ errmsg, "invalid String");
+ str = json_object_get_string (j_tmp);
+ RETURN_ERR_IF ((*pval = pk_make_string (str)) == PK_NULL, errmsg,
+ "pk_make_string () failed");
+
+ return J_OK;
+
+ case PK_OFFSET:
+ {
+ pk_val mag, unit;
+ int code;
+
+ RETURN_ON_JERR (jexpect (j, "type", json_type_string, &j_tmp, errmsg),
+ errmsg, "invalid Offset");
+ str = json_object_get_string (j_tmp);
+ RETURN_ERR_IF (STRNEQ (str, "Offset"), errmsg,
+ "expects \"Offset\" in field \"type\" but got \"%s\"",
+ str);
+
+ RETURN_ON_JERR (
+ jexpect (j, "magnitude", json_type_object, &j_tmp, errmsg), errmsg,
+ "invalid Offset");
+ RETURN_ON_JERR (pvalue (j_tmp, &mag, errmsg), errmsg,
+ "invalid Offset");
+ code = pk_type_code (pk_typeof (mag));
+ RETURN_ERR_IF (code != PK_INT && code != PK_UINT, errmsg,
+ "invalid Offset magnitude");
+
+ RETURN_ON_JERR (jexpect (j, "unit", json_type_object, &j_tmp, errmsg),
+ errmsg, "invalid Offset");
+ RETURN_ON_JERR (pexpect (j_tmp, PK_UINT, &unit, errmsg), errmsg,
+ "invalid Offset unit");
+
+ RETURN_ERR_IF ((*pval = pk_make_offset (mag, unit)) == PK_NULL, errmsg,
+ "pk_make_offset () failed");
+ return J_OK;
+ }
+
+ case PK_INT:
+ {
+ int64_t value;
+ int size;
+
+ RETURN_ON_JERR (jexpect (j, "type", json_type_string, &j_tmp, errmsg),
+ errmsg, "invalid Integer");
+ str = json_object_get_string (j_tmp);
+ RETURN_ERR_IF (STRNEQ (str, "Integer"), errmsg,
+ "expects \"Integer\" in field \"type\" but got \"%s\"",
+ str);
+
+ RETURN_ON_JERR (jexpect (j, "value", json_type_int, &j_tmp, errmsg),
+ errmsg, "invalid Integer");
+ value = json_object_get_int64 (j_tmp);
+ RETURN_ON_JERR (jexpect (j, "size", json_type_int, &j_tmp, errmsg),
+ errmsg, "invalid Integer");
+ size = json_object_get_int (j_tmp);
+
+ RETURN_ERR_IF ((*pval = pk_make_int (value, size)) == PK_NULL, errmsg,
+ "pk_make_int () failed");
+ return J_OK;
+ }
+
+ case PK_UINT:
+ {
+ uint64_t value;
+ int size;
+
+ RETURN_ON_JERR (jexpect (j, "type", json_type_string, &j_tmp, errmsg),
+ errmsg, "invalid UnsignedInteger");
+ str = json_object_get_string (j_tmp);
+ RETURN_ERR_IF (
+ STRNEQ (str, "UnsignedInteger"), errmsg,
+ "expects \"UnsignedInteger\" in field \"type\" but got \"%s\"",
+ str);
+
+ RETURN_ON_JERR (jexpect (j, "value", json_type_int, &j_tmp, errmsg),
+ errmsg, "invalid UnsignedInteger");
+
+ /* Older versions of libjson-c (0.3.1 & older) do not support
+ json_object_get_uint64 (only json_object_get_int64).
+
+ In order to support previous versions, we store unsigned integers
+ as signed integers despite them being too large to represent as
+ signed. (i.e. they are stored as negative).
+
+ However, users expect to get the unsigned integer they stored.
+
+ Thus, we have to convert it back to uint64_t. */
+ value = (uint64_t)json_object_get_int64 (j_tmp);
+
+ RETURN_ON_JERR (jexpect (j, "size", json_type_int, &j_tmp, errmsg),
+ errmsg, "invalid UnsignedInteger");
+ size = json_object_get_int (j_tmp);
+
+ RETURN_ERR_IF ((*pval = pk_make_uint (value, size)) == PK_NULL, errmsg,
+ "pk_make_uint () failed");
+ return J_OK;
+ }
+
+ case PK_STRUCT:
+ RETURN_ON_JERR (jexpect (j, "type", json_type_string, &j_tmp, errmsg),
+ errmsg, "invalid Struct");
+ str = json_object_get_string (j_tmp);
+ RETURN_ERR_IF (STRNEQ (str, "Struct"), errmsg,
+ "expects \"Struct\" in field \"type\" but got \"%s\"",
+ str);
+ return pexpect_sct (j, pval, errmsg);
+
+ case PK_ARRAY:
+ RETURN_ON_JERR (jexpect (j, "type", json_type_string, &j_tmp, errmsg),
+ errmsg, "invalid Array");
+ str = json_object_get_string (j_tmp);
+ RETURN_ERR_IF (STRNEQ (str, "Array"), errmsg,
+ "expects \"Array\" in field \"type\" but got \"%s\"",
+ str);
+ return pexpect_arr (j, pval, errmsg);
+
+ case PK_ANY:
+ case PK_CLOSURE:
+ return jerror (J_NOK, errmsg, "unsupported Poke type (code:%d)",
+ type_code);
+
+ case PK_UNKNOWN:
+ default:
+ return jerror (J_NOK, errmsg, "unknown Poke type (code:%d)", type_code);
+ }
+
+ return J_NOK;
+}
+
+static int
+pexpect_map (json_object *j_map, pk_val p_val, char **errmsg)
+{
+ json_object *j_tmp;
+ pk_val p_ios, p_off;
+ int strict_p;
+
+#define MAP_JERR(cond) RETURN_ON_JERR ((cond), errmsg, "invalid Mapping")
+
+ MAP_JERR (jexpect (j_map, "mapped", json_type_boolean, &j_tmp, errmsg));
+ if (!json_object_get_boolean (j_tmp)) /* The value is not mapped */
+ return J_OK;
+
+ MAP_JERR (jexpect (j_map, "strict", json_type_boolean, &j_tmp, errmsg));
+ strict_p = json_object_get_boolean (j_tmp);
+
+ MAP_JERR (jexpect (j_map, "IOS", json_type_int, &j_tmp, errmsg));
+ RETURN_ERR_IF ((p_ios = pk_make_int (json_object_get_int (j_tmp), 32))
+ == PK_NULL,
+ errmsg, "pk_make_int (, 32) failed");
+
+ MAP_JERR (jexpect (j_map, "offset", json_type_object, &j_tmp, errmsg));
+ MAP_JERR (pexpect (j_tmp, PK_OFFSET, &p_off, errmsg));
+
+ pk_val_set_mapped (p_val, 1);
+ pk_val_set_strict (p_val, strict_p);
+ pk_val_set_ios (p_val, p_ios);
+ pk_val_set_offset (p_val, p_off);
+
+ return J_OK;
+}
+
+/* Expects a Poke struct value in JSON object.
+ *
+ * Returns J_OK on success, J_NOK otherwise.
+ */
+static int
+pexpect_sct (json_object *j_sct, pk_val *p_struct, char **errmsg)
+{
+ json_object *j_fields, *j_mapping, *j_name;
+ pk_val p_sct_name, p_nfields, p_sct_type, p_sct;
+ pk_val *p_fnames, *p_ftypes;
+ size_t fields_len;
+
+#define SCT_JERR(cond) RETURN_ON_JERR ((cond), errmsg, "invalid Struct")
+
+ SCT_JERR (jexpect (j_sct, "name", json_type_object, &j_name, errmsg));
+ SCT_JERR (jexpect (j_sct, "fields", json_type_array, &j_fields, errmsg));
+ SCT_JERR (jexpect (j_sct, "mapping", json_type_object, &j_mapping, errmsg));
+
+ fields_len = json_object_array_length (j_fields);
+ p_nfields = pk_make_uint (fields_len, 64);
+
+ SCT_JERR (pexpect (j_name, PK_STRING, &p_sct_name, errmsg));
+
+ pk_allocate_struct_attrs (p_nfields, &p_fnames, &p_ftypes);
+ p_sct_type = pk_make_struct_type (p_nfields, p_sct_name, p_fnames, p_ftypes);
+ p_sct = pk_make_struct (p_nfields, p_sct_type);
+
+ for (size_t i = 0; i < fields_len; i++)
+ {
+ json_object *j_elem, *j_name, *j_value, *j_boffset;
+ pk_val p_sct_name, p_sct_value, p_sct_boffset;
+
+ j_elem = json_object_array_get_idx (j_fields, i);
+
+ SCT_JERR (jexpect (j_elem, "name", json_type_object, &j_name, errmsg));
+ SCT_JERR (jexpect (j_elem, "value", json_type_object, &j_value, errmsg));
+ SCT_JERR (
+ jexpect (j_elem, "boffset", json_type_object, &j_boffset, errmsg));
+
+ SCT_JERR (pexpect (j_name, PK_STRING, &p_sct_name, errmsg));
+ SCT_JERR (pvalue (j_value, &p_sct_value, errmsg));
+ SCT_JERR (pexpect (j_boffset, PK_UINT, &p_sct_boffset, errmsg));
+
+ RETURN_ERR_IF (p_sct_value == PK_NULL, errmsg, "invalid Struct");
+
+ pk_struct_type_set_fname (p_sct_type, i, p_sct_name);
+ pk_struct_type_set_ftype (p_sct_type, i, pk_typeof (p_sct_value));
+ pk_struct_set_field_name (p_sct, i, p_sct_name);
+ pk_struct_set_field_value (p_sct, i, p_sct_value);
+ pk_struct_set_field_boffset (p_sct, i, p_sct_boffset);
+ }
+
+ SCT_JERR (pexpect_map (j_mapping, p_sct, errmsg));
+ *p_struct = p_sct;
+ return J_OK;
+
+#undef SCT_JERR
+}
+
+/* Expects a Poke array elem in JSON object.
+ *
+ * Returns J_OK on success, J_NOK otherwise.
+ */
+static int
+pexpect_aelem (json_object *j_elem, pk_val *p_elem_val, pk_val *p_elem_boff,
+ char **errmsg)
+{
+ json_object *j_val, *j_boff;
+
+#define AELEM_JERR(cond) \
+ RETURN_ON_JERR ((cond), errmsg, "invalid Array element")
+
+ AELEM_JERR (jexpect (j_elem, "value", json_type_object, &j_val, errmsg));
+ AELEM_JERR (jexpect (j_elem, "boffset", json_type_object, &j_boff, errmsg));
+
+ AELEM_JERR (pvalue (j_val, p_elem_val, errmsg));
+ AELEM_JERR (pexpect (j_boff, PK_UINT, p_elem_boff, errmsg));
+
+ RETURN_ERR_IF (pk_integral_type_size (pk_typeof (*p_elem_boff)) == 64,
+ errmsg, "boffset should be an uint<64>");
+
+ return J_OK;
+
+#undef AELEM_JER
+}
+
+/* Expects a Poke array in JSON object.
+ *
+ * Returns J_OK on success, J_NOK otherwise.
+ */
+static int
+pexpect_arr (json_object *j_arr, pk_val *p_array, char **errmsg)
+{
+ json_object *j_elems, *j_elem, *j_mapping;
+ pk_val p_arr, p_value, p_boffset, p_aelem_type /*array element type*/,
+ p_arr_type;
+ size_t elems_len;
+
+#define ARR_JERR(cond) RETURN_ON_JERR ((cond), errmsg, "invalid Array")
+
+ ARR_JERR (jexpect (j_arr, "elements", json_type_array, &j_elems, errmsg));
+ ARR_JERR (jexpect (j_arr, "mapping", json_type_object, &j_mapping, errmsg));
+
+ elems_len = json_object_array_length (j_elems);
+
+ /* FIXME no empty array */
+ if (elems_len == 0)
{
- poke_object = json_tokener_parse_ex (tok, json_str,
- strlen (json_str));
+ *p_array = PK_NULL;
+ return J_OK;
}
- while ((jerr = json_tokener_get_error (tok)) == json_tokener_continue);
- PK_MI_CHECK(errmsg, jerr == json_tokener_success, "%s",
- json_tokener_error_desc (jerr));
+ /* assert (elems_len != 0); */
+
+ /* Type of the array will be the type of first element */
+ j_elem = json_object_array_get_idx (j_elems, 0);
+
+ /* FIXME no support for null items */
+ assert (j_elem != NULL);
- err = json_object_object_get_ex (poke_object, "PokeValue", &search_object);
- PK_MI_CHECK(errmsg, err != 0, "Not a valid PokeValue object");
+ ARR_JERR (pexpect_aelem (j_elem, &p_value, &p_boffset, errmsg));
+ p_aelem_type = pk_typeof (p_value);
+ p_arr_type = pk_make_array_type (p_aelem_type, PK_NULL);
+ p_arr = pk_make_array (pk_make_uint (elems_len, 64), p_arr_type);
- if (pk_mi_json_to_val_1 (value, search_object, errmsg) == -1)
- goto error;
+ pk_array_insert_elem (p_arr, 0, p_value);
+ RETURN_ERR_IF (!pk_val_equal_p (pk_array_elem_boffset (p_arr, 0), p_boffset),
+ errmsg, "invalid Array: boffset mismatch at index 0");
- json_tokener_free (tok);
+ for (size_t i = 1; i < elems_len; ++i)
+ {
+ j_elem = json_object_array_get_idx (j_elems, i);
+ assert (j_elem != NULL);
+ ARR_JERR (pexpect_aelem (j_elem, &p_value, &p_boffset, errmsg));
+ pk_array_insert_elem (p_arr, i, p_value);
+ RETURN_ERR_IF (
+ !pk_val_equal_p (pk_array_elem_boffset (p_arr, i), p_boffset),
+ errmsg, "invalid Array: boffset mismatch at index %zu", i);
+ }
- return 0;
+ ARR_JERR (pexpect_map (j_mapping, p_arr, errmsg));
+ *p_array = p_arr;
+ return J_OK;
- error:
- return -1;
+#undef ARR_JERR
}
static int
@@ -989,7 +1073,7 @@ collect_json_arg (const char *name, pk_val value /* Note
unused */,
if (!json_object_object_get_ex (args, name, &obj))
return 0;
- if (!pk_mi_json_to_val_1 (&val, obj, NULL))
+ if (!pk_mi_jsonobj_to_val (&val, obj, NULL))
return 0;
pk_mi_set_arg (msg, name, val);
diff --git a/testsuite/Makefile.am b/testsuite/Makefile.am
index 8653249d..f71f2f56 100644
--- a/testsuite/Makefile.am
+++ b/testsuite/Makefile.am
@@ -1917,5 +1917,8 @@ EXTRA_DIST = \
poke.mi-json/pk_uint.json \
poke.mi-json/pk_string.json \
poke.mi-json/pk_offset.json \
+ poke.mi-json/pk_offset_uint.json \
poke.mi-json/pk_array.json \
+ poke.mi-json/pk_sct_empty.json \
+ poke.mi-json/pk_sct_empty_mapped.json \
poke.mi-json/pk_sct.json
diff --git a/testsuite/poke.mi-json/Makefile.am
b/testsuite/poke.mi-json/Makefile.am
index 80e466f0..ac56beb1 100644
--- a/testsuite/poke.mi-json/Makefile.am
+++ b/testsuite/poke.mi-json/Makefile.am
@@ -34,7 +34,8 @@ mi_json_CPPFLAGS = -I$(top_builddir)/gl -I$(top_srcdir)/gl \
-I$(top_srcdir)/common \
-DTESTDIR=\"$(abs_srcdir)\" \
-DPKGDATADIR=\"$(pkgdatadir)\" \
- -I$(top_srcdir)/libpoke -I$(top_builddir)/libpoke
+ -I$(top_srcdir)/libpoke -I$(top_builddir)/libpoke \
+ -I$(top_srcdir)/common
# Old DejaGnu versions need a specific old interpretation of 'inline'.
mi_json_CFLAGS = -fgnu89-inline $(JSON_C_CFLAGS)
diff --git a/testsuite/poke.mi-json/mi-json.c b/testsuite/poke.mi-json/mi-json.c
index 2ea077f7..0940dc6a 100644
--- a/testsuite/poke.mi-json/mi-json.c
+++ b/testsuite/poke.mi-json/mi-json.c
@@ -18,6 +18,7 @@
#include <config.h>
+#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -33,6 +34,7 @@
#include "pk-mi-json.h"
#include "libpoke.h"
#include "../poke.libpoke/term-if.h"
+#include "pk-utils.h"
#define PASS 1
#define FAIL 0
@@ -83,276 +85,310 @@ parse_json_str_object (const char *json_str, json_object
**pk_obj)
int test_json_pk_val (json_object *obj, pk_val val);
+#define J_OK 1
+#define J_NOK 0 /* Not OK */
+
+#define JFIELD_IMPL(funcname, line, jobj, field, jval, ...) \
+ do \
+ { \
+ if (json_object_object_get_ex ((jobj), (field), (jval)) != J_OK) \
+ { \
+ fprintf (stderr, "%s:%d ", (funcname), (line)); \
+ fprintf (stderr, __VA_ARGS__); \
+ fputs ("\n", stderr); \
+ return FAIL; \
+ } \
+ } \
+ while (0)
+#define JFIELD(...) JFIELD_IMPL (__func__, __LINE__, __VA_ARGS__)
+
+#define CHK_IMPL(funcname, line, cond, ...) \
+ do \
+ { \
+ if (!(cond)) \
+ { \
+ fprintf (stderr, "%s:%d ", (funcname), (line)); \
+ fprintf (stderr, __VA_ARGS__); \
+ fputs ("\n", stderr); \
+ return FAIL; \
+ } \
+ } \
+ while (0)
+#define CHK(...) CHK_IMPL (__func__, __LINE__, __VA_ARGS__)
+
+#define STREQ_LIT(str, string_literal) \
+ (strncmp (str, string_literal, strlen (string_literal)) == 0)
+
int
-test_json_pk_int (json_object *pk_int_obj, pk_val pk_int)
+test_json_pk_int (json_object *j_int, pk_val p_int)
{
- json_object *current;
- const char *typename;
+ json_object *j_type, *j_value, *j_size;
- /* Poke integers properties are : "type", "value" and "size". */
- if (json_object_object_length (pk_int_obj) != 3)
- return FAIL;
+ CHK (json_object_object_length (j_int) == 3,
+ "Integer expects 3 fields: type, value, size");
- if (!json_object_object_get_ex (pk_int_obj, "type", ¤t))
- return FAIL;
+ JFIELD (j_int, "type", &j_type, "Integer expects `type` field");
+ JFIELD (j_int, "value", &j_value, "Integer expects `value` field");
+ JFIELD (j_int, "size", &j_size, "Integer expects `size` field");
- typename = json_object_get_string (current);
- if (strncmp (typename, "Integer", strlen ("Integer")))
- return FAIL;
+ {
+ const char *str = json_object_get_string (j_type);
- if (!json_object_object_get_ex (pk_int_obj, "value", ¤t))
- return FAIL;
+ CHK (STREQ_LIT (str, "Integer"),
+ "Integer type: expects `Integer`, got `%s`", str);
+ }
+ {
+ int64_t value = pk_int_value (p_int);
+ int64_t v = json_object_get_int64 (j_value);
- if (json_object_get_int64 (current) != pk_int_value (pk_int))
- return FAIL;
+ CHK (value == v, "Integer value: expects %" PRIi64 ", got %" PRIi64, value,
+ v);
+ }
+ {
+ int size = pk_int_size (p_int);
+ int s = json_object_get_int (j_size);
- if (!json_object_object_get_ex (pk_int_obj, "size", ¤t))
- return FAIL;
+ CHK (size == s, "Integer size: expects %d, got %d", size, s);
+ }
- if (json_object_get_int (current) != pk_int_size (pk_int))
- return FAIL;
return PASS;
}
int
-test_json_pk_uint (json_object *pk_uint_obj, pk_val pk_uint)
+test_json_pk_uint (json_object *j_uint, pk_val p_uint)
{
- json_object *current;
- const char *typename;
-
- /* Poke unsigned integers properties are : "type", "value" and "size". */
- if (json_object_object_length (pk_uint_obj) != 3)
- return FAIL;
-
- if (!json_object_object_get_ex (pk_uint_obj, "type", ¤t))
- return FAIL;
-
- typename = json_object_get_string (current);
- if (strncmp (typename, "UnsignedInteger",
- strlen ("UnsignedInteger")))
- return FAIL;
-
- if (!json_object_object_get_ex (pk_uint_obj, "value", ¤t))
- return FAIL;
-
- /* NOTE: This version of libjson-c does not support *_get_uint64 so we use
- the int64 version and always cast to the unsigned type. */
- if ((uint64_t) json_object_get_int64 (current) != pk_uint_value (pk_uint))
- return FAIL;
-
- if (!json_object_object_get_ex (pk_uint_obj, "size", ¤t))
- return FAIL;
-
- if (json_object_get_int (current) != pk_uint_size (pk_uint))
- return FAIL;
+ json_object *j_type, *j_value, *j_size;
+
+ CHK (json_object_object_length (j_uint) == 3,
+ "UnsignedInteger expects 3 fields: type, value, size");
+
+ JFIELD (j_uint, "type", &j_type, "UnsignedInteger expects `type` field");
+ JFIELD (j_uint, "value", &j_value,
+ "UnsignedInteger expects `value` field");
+ JFIELD (j_uint, "size", &j_size, "UnsignedInteger expects `size` field");
+
+ {
+ const char *str = json_object_get_string (j_type);
+
+ CHK (STREQ_LIT (str, "UnsignedInteger"),
+ "UnsignedInteger type: expects `UnsignedInteger`, got `%s`", str);
+ }
+ {
+ /* Older versions of libjson-c (0.3.1 & older) do not support
+ * `json_object_get_uint64` (only `json_object_get_int64`).
+ */
+ uint64_t v = (uint64_t)json_object_get_int64 (j_value);
+ uint64_t value = pk_uint_value (p_uint);
+
+ CHK (value == v,
+ "UnsignedInteger value: expects %" PRIi64 ", got %" PRIi64, value, v);
+ }
+ {
+ int s = json_object_get_int (j_size);
+ int size = pk_uint_size (p_uint);
+
+ CHK (size == s, "UnsignedInteger size: expects %d, got %d", size, s);
+ }
return PASS;
}
int
-test_json_pk_string (json_object *pk_string_obj, pk_val pk_string)
+test_json_pk_string (json_object *j_string, pk_val p_string)
{
- json_object *current;
- const char *typename, *json_str_value, *pk_string_value;
+ json_object *j_type, *j_value;
- /* Poke string properties are : "type" and "value". */
- if (json_object_object_length (pk_string_obj) != 2)
- return FAIL;
+ CHK (json_object_object_length (j_string) == 2,
+ "String expects 2 fields: type, value");
- if (!json_object_object_get_ex (pk_string_obj, "type", ¤t))
- return FAIL;
+ JFIELD (j_string, "type", &j_type, "String expects `type` field");
+ JFIELD (j_string, "value", &j_value, "String expects `value` field");
- typename = json_object_get_string (current);
- if (strncmp (typename, "String", strlen ("String")))
- return FAIL;
+ {
+ const char *str = json_object_get_string (j_type);
- if (!json_object_object_get_ex (pk_string_obj, "value", ¤t))
- return FAIL;
+ CHK (STREQ_LIT (str, "String"),
+ "String type: expects `String`, got `%s`", str);
+ }
+ {
+ const char* str = pk_string_str (p_string);
+ const char* s = json_object_get_string (j_value);
- json_str_value = json_object_get_string (current);
- pk_string_value = pk_string_str (pk_string);
- if (strncmp (json_str_value, pk_string_value, strlen (pk_string_value)))
- return FAIL;
+ CHK (STREQ (str, s), "String value: expects \"%s\", got \"%s\"",
+ str, s);
+ }
return PASS;
}
int
-test_json_pk_offset (json_object *pk_offset_obj, pk_val pk_offset)
+test_json_pk_offset (json_object *j_offset, pk_val p_offset)
{
- json_object *current;
- pk_val pk_magnitude, pk_unit;
- const char *typename;
- int signed_p;
+ json_object *j_type, *j_magnitude, *j_unit;
+
+ CHK (json_object_object_length (j_offset) == 3,
+ "Offset expects 3 fields: type, magnitude, unit");
/* Poke offset properties are : "type", "magnitude" and "unit". */
- if (json_object_object_length (pk_offset_obj) != 3)
- return FAIL;
-
- if (!json_object_object_get_ex (pk_offset_obj, "type", ¤t))
- return FAIL;
-
- typename = json_object_get_string (current);
- if (strncmp (typename, "Offset", strlen ("Offset")))
- return FAIL;
-
- if (!json_object_object_get_ex (pk_offset_obj, "magnitude", ¤t))
- return FAIL;
-
- /* "magnitude" is either an UnsignedInteger or an Integer.
- Check if its UnsignedInteger or Integer. */
- pk_magnitude = pk_offset_magnitude (pk_offset);
- signed_p = pk_int_value (pk_integral_type_signed_p (pk_typeof
(pk_magnitude)));
- if (signed_p && test_json_pk_int (current, pk_magnitude) == FAIL)
- return FAIL;
-
- if (!signed_p && test_json_pk_uint (current, pk_magnitude) == FAIL)
- return FAIL;
-
- /* "unit" is an UnsignedInteger. */
- if (!json_object_object_get_ex (pk_offset_obj, "unit", ¤t))
- return FAIL;
-
- pk_unit = pk_offset_unit (pk_offset);
- if (test_json_pk_uint (current, pk_unit) == FAIL)
- return FAIL;
+ JFIELD (j_offset, "type", &j_type, "Offset expects `type` field");
+ JFIELD (j_offset, "magnitude", &j_magnitude,
+ "Offset expects `magnitude` field");
+ JFIELD (j_offset, "unit", &j_unit, "Offset expects `unit` field");
+
+ {
+ const char *str = json_object_get_string (j_type);
+
+ CHK (STREQ_LIT (str, "Offset"), "Offset type: expects `Offset`, got `%s`",
+ str);
+ }
+ {
+ pk_val p_mag, p_unit;
+ int signed_p;
+ uint64_t size;
+
+ p_mag = pk_offset_magnitude (p_offset);
+ signed_p = pk_int_value (pk_integral_type_signed_p (pk_typeof (p_mag)));
+
+ if (signed_p)
+ CHK (test_json_pk_int (j_magnitude, p_mag) == PASS,
+ "Invalid Offset magnitude");
+ else
+ CHK (test_json_pk_uint (j_magnitude, p_mag) == PASS,
+ "Invalid Offset magnitude");
+
+ p_unit = pk_offset_unit (p_offset);
+ signed_p = pk_int_value (pk_integral_type_signed_p (pk_typeof (p_unit)));
+
+ /* `unit` is a uint<64> */
+ CHK (!signed_p, "Offset unit: expects to be unsigned");
+ CHK (test_json_pk_uint (j_unit, p_unit) == PASS, "Invalid Offset unit");
+ CHK ((size = pk_uint_value (pk_integral_type_size (pk_typeof (p_unit))))
+ == 64,
+ "Offset unit: expects uint<64>, got uint<%d>", size);
+ }
return PASS;
}
int
-test_json_pk_null (json_object *pk_null_obj, pk_val pk_null)
+test_json_pk_null (json_object *j_null, pk_val p_null)
{
- json_object *current;
- const char *typename;
-
- /* Poke null properties are : "type" and "value". */
- if (json_object_object_length (pk_null_obj) != 2)
- return FAIL;
+ json_object *j_type, *j_value;
+ const char *str = json_object_get_string (j_type);
- if (!json_object_object_get_ex (pk_null_obj, "type", ¤t))
- return FAIL;
+ CHK (json_object_object_length (j_null) == 2,
+ "Null expects 2 fields: type, value");
- typename = json_object_get_string (current);
- if (strncmp (typename, "Null", strlen ("Null")))
- return FAIL;
+ JFIELD (j_null, "type", &j_type, "Null expects `type` field");
+ JFIELD (j_null, "value", &j_value, "Null expects `value` field");
- if (!json_object_object_get_ex (pk_null_obj, "value", ¤t))
- return FAIL;
-
- if (current != NULL)
- return FAIL;
+ CHK (STREQ_LIT (str, "Null"), "Null type: expects `Null`, got `%s`", str);
+ CHK (json_object_is_type (j_value, json_type_null),
+ "Null value: expects `null`, got `%s`",
+ json_type_to_name (json_object_get_type (j_value)));
return PASS;
}
int
-test_json_pk_sct (json_object *pk_sct_obj, pk_val pk_sct)
+test_json_pk_sct (json_object *j_sct, pk_val p_sct)
{
- json_object *current, *pk_sct_fields_obj, *pk_sct_field_obj;
- pk_val pk_sct_name, pk_sct_fname, pk_sct_fboffset, pk_sct_fvalue;
- const char *typename;
-
- /* Poke struct properties are : "type", "name", "fields" and "mapping". */
- if (json_object_object_length (pk_sct_obj) != 4)
- return FAIL;
-
- if (!json_object_object_get_ex (pk_sct_obj, "type", ¤t))
- return FAIL;
-
- typename = json_object_get_string (current);
- if (strncmp (typename, "Struct", strlen ("Struct")))
- return FAIL;
-
- if (!json_object_object_get_ex (pk_sct_obj, "name", ¤t))
- return FAIL;
-
- pk_sct_name = pk_struct_type_name (pk_struct_type (pk_sct));
-
- if (test_json_pk_string (current, pk_sct_name) == FAIL)
- return FAIL;
-
- /* Get the fields of a struct and check them. */
- if (!json_object_object_get_ex (pk_sct_obj, "fields", &pk_sct_fields_obj))
- return FAIL;
-
- for (size_t i = 0 ; i < pk_uint_value (pk_struct_nfields (pk_sct)) ; i++)
- pk_sct_fboffset = pk_struct_field_boffset (pk_sct, i);
-
- for (size_t i = 0 ; i < pk_uint_value (pk_struct_nfields (pk_sct)) ; i++)
+ json_object *j_type, *j_name, *j_fields, *j_mapping;
+ uint64_t nfields;
+
+ CHK (json_object_object_length (j_sct) == 4,
+ "Struct expects 4 fields: type, name, fields, mapping");
+
+ JFIELD (j_sct, "type", &j_type, "Struct expects `type` field");
+ JFIELD (j_sct, "name", &j_name, "Struct expects `name` field");
+ JFIELD (j_sct, "fields", &j_fields, "Struct expects `fields` field");
+ JFIELD (j_sct, "mapping", &j_mapping, "Struct expects `fields` field");
+
+ {
+ const char *str = json_object_get_string (j_type);
+
+ CHK (STREQ_LIT (str, "Struct"), "Struct type: expects `Struct`, got `%s`",
+ str);
+ }
+ CHK (test_json_pk_string (j_name,
+ pk_struct_type_name (pk_struct_type (p_sct))),
+ "Struct name: name mismatch");
+
+ nfields = pk_uint_value (pk_struct_nfields (p_sct));
+ CHK (nfields == json_object_array_length (j_fields),
+ "Struct fields: length mismatch");
+ for (uint64_t i = 0; i < nfields; i++)
{
- pk_sct_fname = pk_struct_field_name (pk_sct, i);
- pk_sct_fboffset = pk_struct_field_boffset (pk_sct, i);
- pk_sct_fvalue = pk_struct_field_value (pk_sct, i);
-
- pk_sct_field_obj = json_object_array_get_idx (pk_sct_fields_obj, i);
-
- if (!json_object_object_get_ex (pk_sct_field_obj, "name", ¤t))
- return FAIL;
-
- if (test_json_pk_string (current, pk_sct_fname) == FAIL)
- return FAIL;
-
- if (!json_object_object_get_ex (pk_sct_field_obj, "boffset", ¤t))
- return FAIL;
-
- if (test_json_pk_uint (current, pk_sct_fboffset) == FAIL)
- return FAIL;
-
- if (!json_object_object_get_ex (pk_sct_field_obj, "value", ¤t))
- return FAIL;
-
- if (test_json_pk_val (current, pk_sct_fvalue) == FAIL)
- return FAIL;
+ json_object *j_field, *j_fname, *j_fvalue, *j_fboffset;
+
+ j_field = json_object_array_get_idx (j_fields, i);
+ assert (j_field != NULL);
+
+ JFIELD (j_field, "name", &j_fname,
+ "Struct field at index %zu expects `name` field", i);
+ JFIELD (j_field, "value", &j_fvalue,
+ "Struct field at index %zu expects `value` field", i);
+ JFIELD (j_field, "boffset", &j_fboffset,
+ "Struct field at index %zu expects `boffset` field", i);
+
+ CHK (test_json_pk_string (j_fname, pk_struct_field_name (p_sct, i))
+ == PASS,
+ "Struct field at index %zu: invalid name", i);
+ CHK (test_json_pk_val (j_fvalue, pk_struct_field_value (p_sct, i))
+ == PASS,
+ "Struct field at index %zu: invalid value", i);
+ CHK (test_json_pk_uint (j_fboffset, pk_struct_field_boffset (p_sct, i))
+ == PASS,
+ "Struct field at index %zu: invalid boffset", i);
}
+ /* TODO: add test for mapping */
- /* TODO: add test for mapping when its added on pk-mi-json.c. */
return PASS;
}
int
-test_json_pk_array (json_object *pk_array_obj, pk_val pk_array)
+test_json_pk_array (json_object *j_array, pk_val p_array)
{
- json_object *current, *pk_array_elems_obj, *pk_array_elem_obj;
- pk_val pk_array_elem_value, pk_array_elem_boff;
- const char *typename;
+ json_object *j_type, *j_elems, *j_boffset, *j_mapping, *j_elem, *j_elem_boff,
+ *j_elem_value;
+ pk_val p_elem_value, p_elem_boff;
+ uint64_t nelems;
- /* Poke array properties are : "type", "elements" and "mapping". */
- if (json_object_object_length (pk_array_obj) != 3)
- return FAIL;
+ CHK (json_object_object_length (j_array) == 3,
+ "Array expects 3 fields: type, elements, mapping (got %d keys)",
+ json_object_object_length (j_array));
- if (!json_object_object_get_ex (pk_array_obj, "type", ¤t))
- return FAIL;
+ JFIELD (j_array, "type", &j_type, "Array expects `type` field");
+ JFIELD (j_array, "elements", &j_elems, "Array expects `elements` field");
+ JFIELD (j_array, "mapping", &j_mapping, "Array expects `mapping` field");
- typename = json_object_get_string (current);
- if (strncmp (typename, "Array", strlen ("Array")))
- return FAIL;
+ {
+ const char *str = json_object_get_string (j_type);
- if (!json_object_object_get_ex (pk_array_obj, "elements",
&pk_array_elems_obj))
- return FAIL;
+ CHK (STREQ_LIT (str, "Array"), "Array type: expects `Array`, got `%s`",
+ str);
+ }
- /* Access every element of the array and check it. */
- for (size_t i = 0 ; i < pk_uint_value (pk_array_nelem (pk_array)) ; i++)
+ nelems = pk_uint_value (pk_array_nelem (p_array));
+ for (uint64_t i = 0; i < nelems; i++)
{
- pk_array_elem_value = pk_array_elem_val (pk_array, i);
- pk_array_elem_boff = pk_array_elem_boffset (pk_array, i);
-
- pk_array_elem_obj = json_object_array_get_idx (pk_array_elems_obj, i);
-
- if (!json_object_object_get_ex (pk_array_elem_obj, "boffset", ¤t))
- return FAIL;
-
- if (test_json_pk_uint (current, pk_array_elem_boff) == FAIL)
- return FAIL;
-
- if (!json_object_object_get_ex (pk_array_elem_obj, "value", ¤t))
- return FAIL;
-
- if (test_json_pk_val (current, pk_array_elem_value) == FAIL)
- return FAIL;
+ j_elem = json_object_array_get_idx (j_elems, i);
+ JFIELD (j_elem, "boffset", &j_elem_boff,
+ "Array type: expects `boffset` field for element at index %zu",
+ i);
+ JFIELD (j_elem, "value", &j_elem_value,
+ "Array type: expects `value` field for element at index %zu", i);
+
+ p_elem_value = pk_array_elem_val (p_array, i);
+ p_elem_boff = pk_array_elem_boffset (p_array, i);
+
+ CHK (test_json_pk_uint (j_elem_boff, p_elem_boff) == PASS,
+ "Array type: invalid `boffset` for element at index %zu", i);
+ CHK (test_json_pk_val (j_elem_value, p_elem_value) == PASS,
+ "Array type: invalid `value` for element at index %zu", i);
}
+ /* TODO: add test for mapping */
- /* TODO: add test for mapping when its added on pk-mi-json.c. */
return PASS;
}
@@ -498,18 +534,23 @@ test_json_to_val (pk_compiler pk, const char *pk_obj_str,
pk_val val)
json_object *pk_obj, *current;
char *errmsg;
- if (pk_mi_json_to_val (&pk_test_val, pk_obj_str, &errmsg) == -1)
+ if (pk_mi_json_to_val (&pk_test_val, pk_obj_str, &errmsg) == -1) {
+ fprintf (stderr, "pk_mi_json_to_val () failed: %s\n", errmsg);
return FAIL;
+ }
+
+ printf ("\nParsed value:\n ");
+ pk_print_val_with_params (pk, pk_test_val, 0, 0, 16, 2, 0, PK_PRINT_F_MAPS);
+ puts ("");
/* Check if the pk_val returned from pk_mi_json_to_val
is the same as the pk_val that we read from the test file. */
if (!pk_val_equal_p (pk_test_val, val))
{
- printf ("Expected value:\n");
+ printf ("Equality failure:\n Expected value:\n ");
pk_print_val_with_params (pk, val, 0, 0, 16, 2, 0, PK_PRINT_F_MAPS);
- printf ("\n");
- printf ("Parsed value:\n");
+ printf ("\n Parsed value:\n ");
pk_print_val_with_params (pk, pk_test_val, 0, 0, 16, 2, 0,
PK_PRINT_F_MAPS);
printf ("\n");
return FAIL;
diff --git a/testsuite/poke.mi-json/pk_array.json
b/testsuite/poke.mi-json/pk_array.json
index 1a42c5be..b473b7e8 100644
--- a/testsuite/poke.mi-json/pk_array.json
+++ b/testsuite/poke.mi-json/pk_array.json
@@ -103,7 +103,7 @@
}
],
"mapping" : {
- "type" : "Null", "value" : null
+ "mapped": false
}
}
}
diff --git a/testsuite/poke.mi-json/pk_offset_uint.json
b/testsuite/poke.mi-json/pk_offset_uint.json
new file mode 100644
index 00000000..d03a9aa8
--- /dev/null
+++ b/testsuite/poke.mi-json/pk_offset_uint.json
@@ -0,0 +1,18 @@
+##
+23U#B
+##
+{
+ "PokeValue" : {
+ "type" : "Offset",
+ "magnitude" : {
+ "type" : "UnsignedInteger",
+ "value" : 23,
+ "size" : 32
+ },
+ "unit" : {
+ "type" : "UnsignedInteger",
+ "value" : 8,
+ "size" : 64
+ }
+ }
+}
diff --git a/testsuite/poke.mi-json/pk_sct.json
b/testsuite/poke.mi-json/pk_sct.json
index 6efac2d7..e17b374a 100644
--- a/testsuite/poke.mi-json/pk_sct.json
+++ b/testsuite/poke.mi-json/pk_sct.json
@@ -44,8 +44,7 @@ Packet { i = 1, j = 2}
}
],
"mapping" : {
- "type" : "Null",
- "value" : null
+ "mapped": false
}
}
}
diff --git a/testsuite/poke.mi-json/pk_sct_empty.json
b/testsuite/poke.mi-json/pk_sct_empty.json
new file mode 100644
index 00000000..9535140d
--- /dev/null
+++ b/testsuite/poke.mi-json/pk_sct_empty.json
@@ -0,0 +1,17 @@
+type Empty = struct {};
+##
+Empty { }
+##
+{
+ "PokeValue" : {
+ "type" : "Struct",
+ "name" : {
+ "type" : "String",
+ "value" : "Empty"
+ },
+ "fields" : [],
+ "mapping" : {
+ "mapped": false
+ }
+ }
+}
diff --git a/testsuite/poke.mi-json/pk_sct_empty_mapped.json
b/testsuite/poke.mi-json/pk_sct_empty_mapped.json
new file mode 100644
index 00000000..2b2169df
--- /dev/null
+++ b/testsuite/poke.mi-json/pk_sct_empty_mapped.json
@@ -0,0 +1,33 @@
+var fd = open ("*mem*");
+type Empty = struct {};
+##
+Empty @ fd : 1#B
+##
+{
+ "PokeValue" : {
+ "type" : "Struct",
+ "name" : {
+ "type" : "String",
+ "value" : "Empty"
+ },
+ "fields" : [],
+ "mapping" : {
+ "mapped": true,
+ "strict": true,
+ "IOS": 0,
+ "offset": {
+ "type": "Offset",
+ "magnitude" : {
+ "type" : "Integer",
+ "value" : 1,
+ "size" : 32
+ },
+ "unit" : {
+ "type" : "UnsignedInteger",
+ "value" : 8,
+ "size" : 64
+ }
+ },
+ }
+ }
+}
--
2.31.0
Re: [PATCH v2 1/2] libpoke: Add new getter and setters for pk_vals, Jose E. Marchesi, 2021/03/28