#include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_json_lib.h" #include "jsonapi_objects.h" /** * Get a JSON API object resource count * * @param resp the JSON API object * @return the number of resources */ int GNUNET_JSONAPI_document_resource_count (struct GNUNET_JSONAPI_Document *doc) { return doc->res_count; } /** * Get a JSON API object resource by index * * @param resp the JSON API object * @param idx index of the resource * @return the resource */ struct GNUNET_JSONAPI_Resource* GNUNET_JSONAPI_document_get_resource (struct GNUNET_JSONAPI_Document *doc, int idx) { struct GNUNET_JSONAPI_Resource *res; int i; if ((0 == doc->res_count) || (idx >= doc->res_count)) return NULL; res = doc->res_list_head; for (i = 0; i < idx; i++) { res = res->next; } return res; } /** * Delete a JSON API primary data * * @param type the JSON API resource type * @param id the JSON API resource id * @return a new JSON API resource or NULL on error. */ void GNUNET_JSONAPI_document_delete (struct GNUNET_JSONAPI_Document *doc) { struct GNUNET_JSONAPI_Resource *res; struct GNUNET_JSONAPI_Resource *res_next; struct GNUNET_JSONAPI_Error *err; struct GNUNET_JSONAPI_Error *err_next; for (err = doc->err_list_head; err != NULL;) { err_next = err->next; GNUNET_CONTAINER_DLL_remove (doc->err_list_head, doc->err_list_tail, err); GNUNET_JSONAPI_error_delete (err); err = err_next; } for (res = doc->res_list_head; res != NULL;) { res_next = res->next; GNUNET_CONTAINER_DLL_remove (doc->res_list_head, doc->res_list_tail, res); GNUNET_JSONAPI_resource_delete (res); res = res_next; } if (NULL != doc->meta) json_decref (doc->meta); GNUNET_free (doc); doc = NULL; } /** * Create a JSON API primary data * * @return a new JSON API resource or NULL on error. */ struct GNUNET_JSONAPI_Document* GNUNET_JSONAPI_document_new () { struct GNUNET_JSONAPI_Document *result; result = GNUNET_new (struct GNUNET_JSONAPI_Document); result->res_count = 0; result->err_count = 0; result->meta = 0; return result; } /** * Add a JSON API error to document * * @param data The JSON API document to add to * @param res the JSON API error to add * @return the new number of resources */ void GNUNET_JSONAPI_document_error_add (struct GNUNET_JSONAPI_Document *doc, struct GNUNET_JSONAPI_Error *err) { GNUNET_CONTAINER_DLL_insert (doc->err_list_head, doc->err_list_tail, err); doc->err_count++; } /** * Add a JSON API resource to primary data * * @param data The JSON API data to add to * @param res the JSON API resource to add * @return the new number of resources */ void GNUNET_JSONAPI_document_resource_add (struct GNUNET_JSONAPI_Document *doc, struct GNUNET_JSONAPI_Resource *res) { GNUNET_CONTAINER_DLL_insert (doc->res_list_head, doc->res_list_tail, res); doc->res_count++; } /** * Parse given JSON object to jsonapi document. * * @param cls closure, NULL * @param root the json object representing data * @param[out] spec where to write the data * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error */ static int parse_jsonapiobject (void *cls, json_t *root, struct GNUNET_JSON_Specification *spec) { struct GNUNET_JSONAPI_Document *result; struct GNUNET_JSONAPI_Error *error; struct GNUNET_JSONAPI_Resource *resource; json_t *meta_json; json_t *resource_json; json_t *errors_json; json_t *value; size_t index; struct GNUNET_JSON_Specification jsonapispecerrors[] = { GNUNET_JSON_spec_json (GNUNET_JSONAPI_KEY_ERRORS, &errors_json), GNUNET_JSON_spec_end() }; if (GNUNET_OK != GNUNET_JSON_parse (root, jsonapispecerrors, NULL, NULL)) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "JSONAPI document does not contain error objects\n"); } else if (!json_is_array (errors_json)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error object is not array!\n"); GNUNET_JSON_parse_free (jsonapispecerrors); return GNUNET_SYSERR; } struct GNUNET_JSON_Specification jsonapispecmeta[] = { GNUNET_JSON_spec_json (GNUNET_JSONAPI_KEY_META, &meta_json), GNUNET_JSON_spec_end() }; if (GNUNET_OK != GNUNET_JSON_parse (root, jsonapispecmeta, NULL, NULL)) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "JSONAPI document does not contain error objects\n"); } struct GNUNET_JSON_Specification jsonapispecresource[] = { GNUNET_JSON_spec_json (GNUNET_JSONAPI_KEY_DATA, &resource_json), GNUNET_JSON_spec_end() }; if (GNUNET_OK != GNUNET_JSON_parse (root, jsonapispecresource, NULL, NULL)) { if (NULL == errors_json) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "JSONAPI document contains neither error nor data!\n"); GNUNET_JSON_parse_free (jsonapispecerrors); GNUNET_JSON_parse_free (jsonapispecmeta); return GNUNET_SYSERR; } } else { if (NULL != errors_json) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "JSONAPI document contains both error and data!\n"); GNUNET_JSON_parse_free (jsonapispecerrors); GNUNET_JSON_parse_free (jsonapispecmeta); GNUNET_JSON_parse_free (jsonapispecresource); return GNUNET_SYSERR; } } result = GNUNET_new (struct GNUNET_JSONAPI_Document); result->res_count = 0; result->err_count = 0; if (NULL != meta_json) result->meta = json_deep_copy (meta_json); if (NULL != errors_json) { json_array_foreach(errors_json, index, value) { GNUNET_assert (GNUNET_OK == GNUNET_JSONAPI_json_to_error (value, &error)); GNUNET_JSONAPI_document_error_add (result, error); } } if (NULL != resource_json) { if (0 != json_is_array (resource_json)) { json_array_foreach(resource_json, index, value) { GNUNET_assert (GNUNET_OK == GNUNET_JSONAPI_json_to_resource (value, &resource)); GNUNET_JSONAPI_document_resource_add (result, resource); } } else { GNUNET_assert (GNUNET_OK == GNUNET_JSONAPI_json_to_resource (resource_json, &resource)); GNUNET_JSONAPI_document_resource_add (result, resource); } } if (NULL != errors_json) GNUNET_JSON_parse_free (jsonapispecerrors); if (NULL != resource) GNUNET_JSON_parse_free (jsonapispecresource); if (NULL != meta_json) GNUNET_JSON_parse_free (jsonapispecmeta); *(struct GNUNET_JSONAPI_Document **) spec->ptr = result; return GNUNET_OK; } /** * Cleanup data left from parsing RSA public key. * * @param cls closure, NULL * @param[out] spec where to free the data */ static void clean_jsonapiobject (void *cls, struct GNUNET_JSON_Specification *spec) { struct GNUNET_JSONAPI_Document **jsonapi_obj; jsonapi_obj = (struct GNUNET_JSONAPI_Document **) spec->ptr; if (NULL != *jsonapi_obj) { GNUNET_JSONAPI_document_delete (*jsonapi_obj); *jsonapi_obj = NULL; } } /** * Add a JSON API resource to primary data * * @param data The JSON API data to add to * @param res the JSON API resource to add * @return the new number of resources */ void GNUNET_JSONAPI_document_resource_remove (struct GNUNET_JSONAPI_Document *resp, struct GNUNET_JSONAPI_Resource *res) { GNUNET_CONTAINER_DLL_remove (resp->res_list_head, resp->res_list_tail, res); resp->res_count--; } /** * String serialze jsonapi primary data * * @param data the JSON API primary data * @param result where to store the result * @return GNUNET_SYSERR on error else GNUNET_OK */ int GNUNET_JSONAPI_document_to_json (const struct GNUNET_JSONAPI_Document *doc, json_t **root_json) { struct GNUNET_JSONAPI_Resource *res; struct GNUNET_JSONAPI_Error *error; json_t *res_json; json_t *res_json_tmp; if ((NULL == doc)) return GNUNET_SYSERR; *root_json = json_object (); //Check for errors first if (doc->err_count != 0) { res_json = json_array (); for (error = doc->err_list_head; error != NULL; error = error->next) { GNUNET_assert (GNUNET_OK == GNUNET_JSONAPI_error_to_json (error, &res_json_tmp)); json_array_append_new (res_json, res_json_tmp); } json_object_set_new (*root_json, GNUNET_JSONAPI_KEY_ERRORS, res_json); } else { if (0 == doc->res_count) { res_json = json_null(); } else { res_json = json_array (); for (res = doc->res_list_head; res != NULL; res = res->next) { GNUNET_assert (GNUNET_OK == GNUNET_JSONAPI_resource_to_json (res, &res_json_tmp)); json_array_append_new (res_json, res_json_tmp); } } json_object_set_new (*root_json, GNUNET_JSONAPI_KEY_DATA, res_json); } json_object_set (*root_json, GNUNET_JSONAPI_KEY_META, doc->meta); return GNUNET_OK; } /** * String serialze jsonapi primary data * * @param data the JSON API primary data * @param result where to store the result * @return GNUNET_SYSERR on error else GNUNET_OK */ int GNUNET_JSONAPI_document_serialize (const struct GNUNET_JSONAPI_Document *doc, char **result) { json_t *json_doc; if (GNUNET_OK != GNUNET_JSONAPI_document_to_json (doc, &json_doc)) return GNUNET_SYSERR; *result = json_dumps (json_doc, JSON_INDENT(2)); json_decref (json_doc); return GNUNET_OK; } /** * JSON object. * * @param name name of the JSON field * @param[out] jsonp where to store the JSON found under @a name */ struct GNUNET_JSON_Specification GNUNET_JSON_spec_jsonapi_document (struct GNUNET_JSONAPI_Document **jsonapi_object) { struct GNUNET_JSON_Specification ret = { .parser = &parse_jsonapiobject, .cleaner = &clean_jsonapiobject, .cls = NULL, .field = NULL, .ptr = jsonapi_object, .ptr_size = 0, .size_ptr = NULL }; *jsonapi_object = NULL; return ret; }