From: kostasch Date: Tue, 21 Jul 2020 21:17:33 +0300 Subject: [PATCH] MI: pk_val->json, json->pk_val convert functions. 2020-07-21 Kostas Chasialis * poke/pk-mi-json.h (pk_mi_val_to_json): Prototype. (pk_mi_json_to_val): Prototype. * poke/pk-mi-json.c (pk_mi_val_to_json): Define. (pk_mi_json_to_val): Define. (pk_mi_val_to_json): New function. (pk_mi_val_to_json_1) : Likewise. (pk_mi_int_to_json): Likewise. (pk_mi_string_to_json): Likewise. (pk_mi_offset_to_json): Likewise. (pk_mi_mapping_to_json): Likewise. (pk_mi_struct_to_json): Likewise. (pk_mi_array_to_json): Likewise. (pk_mi_null_to_json): Likewise. (pk_mi_val_to_json): Likewise. (pk_mi_val_to_json_1): 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_struct): Likewise. (pk_mi_json_to_array): Likewise. (pk_mi_json_poke_value_type): Likewise. (pk_mi_json_array_element_pair): Likewise. --- ChangeLog | 27 ++ poke/pk-mi-json.c | 877 +++++++++++++++++++++++++++++++++++++++++++++- poke/pk-mi-json.h | 44 ++- 3 files changed, 943 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1211f63a..509e0f4f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,30 @@ +2020-07-21 Kostas Chasialis + + * poke/pk-mi-json.h (pk_mi_val_to_json): Prototype. + (pk_mi_json_to_val): Prototype. + * poke/pk-mi-json.c (pk_mi_val_to_json): Define. + (pk_mi_json_to_val): Define. + (pk_mi_val_to_json): New function. + (pk_mi_val_to_json_1) : Likewise. + (pk_mi_int_to_json): Likewise. + (pk_mi_string_to_json): Likewise. + (pk_mi_offset_to_json): Likewise. + (pk_mi_mapping_to_json): Likewise. + (pk_mi_struct_to_json): Likewise. + (pk_mi_array_to_json): Likewise. + (pk_mi_null_to_json): Likewise. + (pk_mi_val_to_json): Likewise. + (pk_mi_val_to_json_1): 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_struct): Likewise. + (pk_mi_json_to_array): Likewise. + (pk_mi_json_poke_value_type): Likewise. + (pk_mi_json_array_element_pair): Likewise. + 2020-07-21 Jose E. Marchesi * testsuite/poke.pkl/scons-int-struct-3.pk: New test. diff --git a/poke/pk-mi-json.c b/poke/pk-mi-json.c index 3ec81924..31d2132c 100644 --- a/poke/pk-mi-json.c +++ b/poke/pk-mi-json.c @@ -17,8 +17,8 @@ */ #include - #include +#include #include #include @@ -429,11 +429,882 @@ pk_mi_json_to_msg (const char *str) return NULL; json = json_tokener_parse_ex (tokener, str, strlen (str)); + assert (json); + json_tokener_free (tokener); - if (json) - msg = pk_mi_json_object_to_msg (json); + msg = pk_mi_json_object_to_msg (json); /* XXX: free the json object */ return msg; } + +/* Functions to convert pk_val to JSON Poke Value. */ +static json_object *pk_mi_struct_to_json (pk_val sct, char **errmsg); +static json_object *pk_mi_array_to_json (pk_val array, char **errmsg); + +static json_object * +pk_mi_int_to_json (pk_val integer, char **errmsg) +{ + struct json_object *int_object, *type_object, *value_object, *size_object; + const char *type; + int size; + + assert (pk_type_code (pk_typeof (integer)) == PK_INT); + + int_object = json_object_new_object (); + PK_MI_CHECK (errmsg, int_object != NULL, "json_object_new_object () failed"); + + if (!(pk_uint_value (pk_integral_type_signed_p (pk_typeof (integer))))) + { + value_object = json_object_new_uint64 (pk_uint_value (integer)); + PK_MI_CHECK (errmsg, value_object != NULL, + "json_object_new_object () failed"); + size = pk_uint_size (integer); + type = "UnsignedInteger"; + } + else + { + value_object = json_object_new_int64 (pk_int_value (integer)); + PK_MI_CHECK (errmsg, value_object != NULL, + "json_object_new_object () failed"); + size = pk_int_size (integer); + type = "Integer"; + } + + size_object = json_object_new_int (size); + type_object = json_object_new_string (type); + PK_MI_CHECK (errmsg, size_object != NULL, "json_object_new_object () failed"); + PK_MI_CHECK (errmsg, type_object != NULL, "json_object_new_object () failed"); + + /* OK, fill the properties of our object. */ + PK_MI_CHECK (errmsg, + json_object_object_add (int_object, "type", type_object) != -1, + "json_object_object_add () failed"); + PK_MI_CHECK (errmsg, + json_object_object_add (int_object, "value", value_object) != -1, + "json_object_object_add () failed"); + PK_MI_CHECK (errmsg, + json_object_object_add (int_object, "size", size_object) != -1, + "json_object_object_add () failed"); + + return int_object; + + error: + return NULL; +} + +static json_object * +pk_mi_string_to_json (pk_val str, char **errmsg) +{ + struct json_object *string_object, *string_type_object, *string_value_object; + int err; + + assert (pk_type_code (pk_typeof (str)) == PK_STRING); + + string_object = json_object_new_object (); + PK_MI_CHECK (errmsg, string_object != NULL, + "json_object_new_object () failed"); + + string_type_object = json_object_new_string ("String"); + PK_MI_CHECK (errmsg, string_type_object != NULL, + "json_object_new_object () failed"); + + string_value_object = json_object_new_string (pk_string_str (str)); + PK_MI_CHECK (errmsg, string_value_object != NULL, + "json_object_new_object () failed"); + + /* OK, fill the properties of our object. */ + err = json_object_object_add (string_object, "type", string_type_object); + PK_MI_CHECK (errmsg, err != -1, "json_object_object_add () failed"); + + err = json_object_object_add (string_object, "value", string_value_object); + PK_MI_CHECK (errmsg, err != -1, "json_object_object_add () failed"); + + return string_object; + + error: + return NULL; +} + +static json_object * +pk_mi_offset_to_json (pk_val offset, char **errmsg) +{ + struct json_object *offset_object, *offset_type_object; + struct json_object *magnitude_object; + struct json_object *unit_object, *unit_type_object, *unit_size_object; + struct json_object *unit_value_object; + pk_val off_unit; + int err; + + assert (pk_type_code (pk_typeof (offset)) == PK_OFFSET); + + offset_type_object = json_object_new_string ("Offset"); + PK_MI_CHECK (errmsg, offset_type_object != NULL, + "json_object_new_object () failed"); + + magnitude_object = pk_mi_int_to_json (pk_offset_magnitude (offset), errmsg); + + unit_type_object = json_object_new_string ("UnsignedInteger"); + PK_MI_CHECK (errmsg, unit_type_object != NULL, + "json_object_new_object () failed"); + + unit_size_object = json_object_new_int (64); + PK_MI_CHECK (errmsg, unit_size_object != NULL, + "json_object_new_object () failed"); + + off_unit = pk_offset_unit (offset); + unit_value_object = json_object_new_uint64 (pk_uint_value (off_unit)); + PK_MI_CHECK (errmsg, unit_value_object != NULL, + "json_object_new_object () failed"); + + unit_object = json_object_new_object (); + PK_MI_CHECK (errmsg, unit_object != NULL, + "json_object_new_object () failed"); + + err = json_object_object_add (unit_object, "type", unit_type_object); + PK_MI_CHECK (errmsg, err != -1, "json_object_object_add () failed"); + + err = json_object_object_add (unit_object, "value", unit_value_object); + PK_MI_CHECK (errmsg, err != -1, "json_object_object_add () failed"); + + err = json_object_object_add (unit_object, "size", unit_size_object); + PK_MI_CHECK (errmsg, err != -1, "json_object_object_add () failed"); + + offset_object = json_object_new_object (); + PK_MI_CHECK (errmsg, offset_object != NULL, "json_object_new_object () failed"); + + /* Built sub-objects, add them to our offset_object. */ + err = json_object_object_add (offset_object, "type", offset_type_object); + PK_MI_CHECK (errmsg, err != -1, "json_object_object_add () failed"); + + err = json_object_object_add (offset_object, "magnitude", magnitude_object); + PK_MI_CHECK (errmsg, err != -1, "json_object_object_add () failed"); + + err = json_object_object_add (offset_object, "unit", unit_object); + PK_MI_CHECK (errmsg, err != -1, "json_object_object_add () failed"); + + return offset_object; + + error: + return NULL; +} + +static json_object * +pk_mi_mapping_to_json (pk_val val, char **errmsg) +{ + struct json_object *mapping_object, *ios_object, *offset_object; + int err; + + 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"); + + err = json_object_object_add (mapping_object, "IOS", ios_object); + PK_MI_CHECK (errmsg, err != -1, "json_object_object_add () failed"); + + err = json_object_object_add (mapping_object, "offset", offset_object); + PK_MI_CHECK (errmsg, err != -1, "json_object_object_add () failed"); + + return mapping_object; + + error: + return NULL; +} + +static json_object * +pk_mi_null_to_json (char **errmsg) +{ + struct json_object *pk_null_object; + int err; + + pk_null_object = json_object_new_object (); + PK_MI_CHECK (errmsg, pk_null_object != NULL, + "json_object_new_object () failed"); + + err = json_object_object_add (pk_null_object, "type", + json_object_new_string ("Null")); + PK_MI_CHECK (errmsg, err != -1, + "json_object_object_add () failed"); + + err = json_object_object_add (pk_null_object, "value", + json_object_new_null ()); + PK_MI_CHECK (errmsg, err != -1, + "json_object_object_add () failed"); + + return pk_null_object; + + error: + return NULL; +} + +static json_object * +pk_mi_val_to_json_1 (pk_val val, char **errmsg) +{ + struct 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_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_struct_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: + assert (0); + } + if (!pk_val_object) return NULL; + } + + return pk_val_object; +} + +static json_object * +pk_mi_struct_to_json (pk_val sct, char **errmsg) +{ + struct json_object *pk_struct_object, *pk_struct_type_object; + struct json_object *pk_struct_fields_object, *pk_struct_field_object; + struct json_object *pk_struct_mapping_object, *pk_struct_name_object; + struct json_object *pk_struct_field_value_object; + struct json_object *pk_struct_field_offset_object; + struct json_object *pk_struct_field_name_object; + pk_val tmp; + int err; + + assert (pk_type_code (pk_typeof (sct)) == PK_STRUCT); + + pk_struct_type_object = json_object_new_string ("Struct"); + PK_MI_CHECK (errmsg, pk_struct_type_object != NULL, + "json_object_new_object () failed"); + + pk_struct_fields_object = json_object_new_array (); + PK_MI_CHECK (errmsg, pk_struct_fields_object != NULL, + "json_object_new_object () failed"); + + /* Get the name of the struct type and convert it to JSON object. */ + tmp = pk_struct_type (sct); + pk_struct_name_object = pk_mi_val_to_json_1 (pk_struct_type_name (tmp), errmsg); + PK_MI_CHECK (errmsg, pk_struct_name_object != NULL, + "json_object_new_object () failed"); + + /* Fill the array of struct fields. */ + for (ssize_t i = 0 ; i < pk_uint_value (pk_struct_nfields (sct)) ; i++) + { + tmp = pk_struct_field_value (sct, i); + pk_struct_field_value_object = pk_mi_val_to_json_1 (tmp, errmsg); + tmp = pk_struct_field_boffset (sct, i); + pk_struct_field_offset_object = pk_mi_offset_to_json (tmp, errmsg); + tmp = pk_struct_field_name (sct, i); + pk_struct_field_name_object = pk_mi_string_to_json (tmp, errmsg); + + if (pk_struct_field_value_object == NULL + || pk_struct_field_offset_object == NULL + || pk_struct_field_name_object == NULL) + goto error; + + pk_struct_field_object = json_object_new_object (); + + err = json_object_object_add (pk_struct_field_object, "name", + pk_struct_field_name_object); + PK_MI_CHECK (errmsg, err != -1, "json_object_object_add () failed"); + + err = json_object_object_add (pk_struct_field_object, "value", + pk_struct_field_value_object); + PK_MI_CHECK (errmsg, err != -1, "json_object_object_add () failed"); + + err = json_object_object_add (pk_struct_field_object, "offset", + pk_struct_field_offset_object); + PK_MI_CHECK (errmsg, err != -1, "json_object_object_add () failed"); + + err = json_object_array_add (pk_struct_fields_object, + pk_struct_field_object); + PK_MI_CHECK (errmsg, err != -1, + "failed to add name object to struct field"); + } + + /* Optionally, add a mapping. */ + pk_struct_mapping_object = pk_val_mapped_p (sct) ? + pk_mi_mapping_to_json (sct, errmsg) : + pk_mi_null_to_json (errmsg); + + pk_struct_object = json_object_new_object (); + PK_MI_CHECK (errmsg, pk_struct_object != NULL, + "json_object_new_object () failed"); + + err = json_object_object_add (pk_struct_object, "type", + pk_struct_type_object); + PK_MI_CHECK (errmsg, err != -1, "failed to add type object to struct"); + + err = json_object_object_add (pk_struct_object, "name", + pk_struct_name_object); + PK_MI_CHECK (errmsg, err != -1, "failed to add type object to struct"); + + err = json_object_object_add (pk_struct_object, "fields", + pk_struct_fields_object); + PK_MI_CHECK (errmsg, err != -1, "failed to add fields object to struct"); + + err = json_object_object_add (pk_struct_object, "mapping", + pk_struct_mapping_object); + PK_MI_CHECK (errmsg, err != -1, "failed to add mapping object to struct"); + + return pk_struct_object; + + error: + return NULL; +} + +static json_object * +pk_mi_array_to_json (pk_val array, char **errmsg) +{ + struct json_object *pk_array_object, *pk_array_type_object; + struct json_object *pk_array_mapping_object, *pk_array_elements_object; + struct json_object *pk_array_element_object, *pk_array_element_value_object; + struct json_object *pk_array_element_offset_object; + pk_val tmp; + int err; + + assert (pk_type_code (pk_typeof (array)) == PK_ARRAY); + + pk_array_object = json_object_new_object (); + PK_MI_CHECK (errmsg, pk_array_object != NULL, + "json_object_new_object () failed"); + + const char *type = "Array"; + pk_array_type_object = json_object_new_string (type); + PK_MI_CHECK (errmsg, pk_array_type_object != NULL, + "json_object_new_object () failed"); + + /* Initialize our array. */ + pk_array_elements_object = json_object_new_array (); + PK_MI_CHECK (errmsg, pk_array_elements_object != NULL, + "json_object_new_object () failed"); + + /* Fill elements object. */ + for (size_t i = 0 ; i < pk_uint_value (pk_array_nelem (array)) ; i++) + { + /* For every element on the array, get its value & offset and build + the corresponding JSON objects. */ + tmp = pk_array_elem_val (array, i); + pk_array_element_value_object = pk_mi_val_to_json_1 (tmp, errmsg); + tmp = pk_array_elem_boffset (array, i); + pk_array_element_offset_object = pk_mi_val_to_json_1 (tmp, errmsg); + + pk_array_element_object = json_object_new_object (); + + err = json_object_object_add (pk_array_element_object, "value", + pk_array_element_value_object); + PK_MI_CHECK (errmsg, err != -1, "json_object_object_add () failed"); + + err = json_object_object_add (pk_array_element_object, "offset", + pk_array_element_offset_object); + PK_MI_CHECK (errmsg, err != -1, "json_object_object_add () failed"); + + err = json_object_array_add (pk_array_elements_object, + pk_array_element_object); + PK_MI_CHECK (errmsg, err != -1, "failed to add element to array"); + } + + /* Optionally, add a mapping. */ + pk_array_mapping_object = pk_val_mapped_p (array) ? + pk_mi_mapping_to_json (array, errmsg) : + pk_mi_null_to_json (errmsg); + + if (pk_array_mapping_object == NULL) goto error; + + /* Everything is built on this point. + Fill the properties of the array object. */ + PK_MI_CHECK (errmsg, + json_object_object_add (pk_array_object, "type", + pk_array_type_object) != -1, + "json_object_object_add () failed"); + PK_MI_CHECK (errmsg, + json_object_object_add (pk_array_object, "elements", + pk_array_elements_object) != -1, + "json_object_object_add () failed"); + PK_MI_CHECK (errmsg, + json_object_object_add (pk_array_object, "mapping", + pk_array_mapping_object) != -1, + "json_object_object_add () failed"); + + return pk_array_object; + + error: + return NULL; +} + +const char * +pk_mi_val_to_json (pk_val val, char **errmsg) +{ + struct json_object *pk_val_object, *pk_object; + int err; + + pk_val_object = pk_mi_val_to_json_1 (val, errmsg); + + pk_object = json_object_new_object (); + PK_MI_CHECK (errmsg, pk_object != NULL, + "failed to create new json_object"); + + err = json_object_object_add (pk_object, "PokeValue", pk_val_object); + PK_MI_CHECK (errmsg, err != -1, + "json_object_object_add () failed"); + + return pk_object != NULL ? + json_object_to_json_string_ext (pk_object, JSON_C_TO_STRING_PRETTY) + : NULL; + + error: + return NULL; +} + +/* Functions to convert JSON object to Poke value. */ +static int pk_mi_json_to_struct (pk_val *pk_struct, struct json_object *sct_obj, + char **errmsg); +static int pk_mi_json_to_array (pk_val *pk_array, struct json_object *array_obj, + char **errmsg); + +static const char * +pk_mi_json_poke_value_type (struct json_object *obj) +{ + struct 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, struct json_object *int_obj, char **errmsg) +{ + struct 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, struct json_object *uint_obj, + char **errmsg) +{ + struct 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)); + value = json_object_get_uint64 (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, struct json_object *str_obj, + char **errmsg) +{ + struct 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, struct json_object *offset_obj, + char **errmsg) +{ + /* To build a pk_offset, we need its magnitude and its unit. */ + pk_val magnitude, unit; + struct 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)); + + err = pk_mi_json_to_uint (&magnitude, magnitude_object, errmsg); + PK_MI_CHECK (errmsg, err != -1, "pk_mi_json_to_uint failed"); + + 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, struct json_object *obj, + char **errmsg) +{ + /* TODO: write me. */ + return 0; +} + +int +pk_mi_json_to_val_1 (pk_val *poke_value, struct 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_struct (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; +} + +static int +pk_mi_json_to_struct (pk_val *pk_struct, struct json_object *sct_obj, + char **errmsg) +{ + /* To build a pk_struct, we need its fields, its name and its mapping. */ + struct json_object *array_object, *fields_object, *search_object; + pk_val mapping, sct_type, sct_field_name, sct_field_value, sct_field_offset; + 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, "offset", + &search_object); + PK_MI_CHECK (errmsg, err != 0, + "json type %s does not contain key \"offset\"", + pk_mi_json_poke_value_type (array_object)); + + if (pk_mi_json_to_val_1 (&sct_field_offset, 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_offset)) == PK_OFFSET); + + 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_offset); + 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_struct = sct; + + return 0; + + error: + return -1; +} + +static pk_val * +pk_mi_json_array_element_pair (struct json_object *elements_object, size_t idx, + char **errmsg) +{ + struct 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, "offset", &search_object); + PK_MI_CHECK (errmsg, err != 0, + "json type %s does not contain key \"offset\"", + 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 +pk_mi_json_to_array (pk_val *pk_array, struct json_object *array_obj, + char **errmsg) +{ + /* To build a pk_array, we need its elements and its mapping. */ + struct 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_type_code (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); + + pk_array_set_elem_val (array, 0, element_pair[0]); + pk_array_set_elem_boffset (array, 0, element_pair[1]); + + for (size_t i = 1 ; i < elements_len ; i++) + { + element_pair = pk_mi_json_array_element_pair (elements_object, i, + errmsg); + + assert (pk_type_code (pk_typeof (element_pair[0])) == array_etype); + assert (pk_type_code (pk_typeof (element_pair[1])) == PK_OFFSET); + + pk_array_set_elem_val (array, i, element_pair[0]); + pk_array_set_elem_boffset (array, i, element_pair[1]); + } + + 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"); + + free (element_pair); + } + else + { + array = PK_NULL; + } + + *pk_array = array; + + return 0; + + error: + return -1; +} + +int +pk_mi_json_to_val (pk_val *value, const char *poke_object_str, char **errmsg) +{ + struct json_object *search_object, *poke_object = NULL; + struct json_tokener *tok = json_tokener_new (); + enum json_tokener_error jerr; + + /* Parse the current object and get its PK_TYPE. */ + do + { + poke_object = json_tokener_parse_ex (tok, poke_object_str, + strlen (poke_object_str)); + } + while ((jerr = json_tokener_get_error (tok)) == json_tokener_continue); + + PK_MI_CHECK(errmsg, jerr == json_tokener_success, "%s", + json_tokener_error_desc (jerr)); + + search_object = json_object_object_get (poke_object, "PokeValue"); + PK_MI_CHECK(errmsg, search_object != NULL, "Not a valid PokeValue object"); + + if (pk_mi_json_to_val_1(value, search_object, errmsg) == -1) goto error; + + json_tokener_free (tok); + + return 0; + + error: + return -1; +} diff --git a/poke/pk-mi-json.h b/poke/pk-mi-json.h index 57898c41..9a2d0483 100644 --- a/poke/pk-mi-json.h +++ b/poke/pk-mi-json.h @@ -22,6 +22,23 @@ #include #include "pk-mi-msg.h" +#include "libpoke.h" + +#define PK_MI_CHECK(errmsg, A, M, ...) \ + do \ + { \ + if (!(A)) \ + { \ + if (errmsg == NULL) goto error; \ + asprintf (errmsg, "[ERROR] " M , ##__VA_ARGS__); \ + } \ + } \ + while (0) + +#define PK_MI_DEBUG(M, ...) \ + fprintf (stderr, "DEBUG %s:%d: " M "\n",\ + __FILE__, __LINE__, ##__VA_ARGS__) + /* Given a string containing a JSON message, parse it and return a MI message. @@ -37,7 +54,30 @@ pk_mi_msg pk_mi_json_to_msg (const char *str); const char *pk_mi_msg_to_json (pk_mi_msg msg); -/* XXX services to pk_val <-> json */ -/* XXX services to pk_type <-> json */ +/* Given a Poke value, return the json object associated with this val + + VAL is the pk_val to be converted. + + ERRMSG is a buffer to be allocated that contains any error messages. + + If ERRMSG is NULL, nothing happens on the buffer. + + In case of error returns NULL and sets errmsg appropriately. */ + +const char *pk_mi_val_to_json (pk_val val, char **errmsg); + +/* Given a json object, create the Poke value associated with it. + + VALUE is the Poke value to be created. + + STR is the string value of a pk_val to be converted. + + ERRMSG is a buffer to be allocated that contains any error messages. + + If ERRMSG is NULL, nothing happens on the buffer. + + In case of error returns -1 and sets errmsg appropriately. */ + +int pk_mi_json_to_val (pk_val *value, const char *str, char **errmsg); #endif /* ! PK_MI_JSON */ -- 2.17.1