/**************************************************************************** * JSON utils functions * ****************************************************************************/ /** * @file json_utils.c * @author Celine Mercier (celine.mercier@metabarcoding.org) * @date August 23th 2018 * @brief Functions formatting and handling json-formatted comments for DMS', views and columns. */ #include #include #include #include #include "../obierrno.h" #include "../obidebug.h" #include "./json_utils.h" #include "./cJSON.h" #define DEBUG_LEVEL 0 // TODO has to be defined somewhere else (cython compil flag?) /************************************************************************** * * D E C L A R A T I O N O F T H E P R I V A T E F U N C T I O N S * **************************************************************************/ /** * Internal function reading a character string as a cJSON structure. * * @warning The returned pointer has to be freed by the caller. * * @param comments The character string to read. * * @returns A pointer on a cJSON structure. * @retval NULL if an error occurred. * * @since August 2018 * @author Celine Mercier (celine.mercier@metabarcoding.org) */ cJSON* read_comments(const char* comments); /** * Internal function adding a key/value pair to a cJSON structure. * * @warning If the key is already in the structure, its associated value is turned * into an array if needed and the new value is added to that array. * // TODO discuss replace boolean * * @param comments_struct The cJSON structure to which the pair should be added. * @param key The key of the key/value pair to add. * @param value The value of the key/value pair to add. * * @returns A pointer on the cJSON structure with the added element. * @retval NULL if an error occurred. * * @since August 2018 * @author Celine Mercier (celine.mercier@metabarcoding.org) */ cJSON* add_comment_to_struct(cJSON* comments_struct, const char* key, const char* value); /************************************************************************ * * D E F I N I T I O N O F T H E P R I V A T E F U N C T I O N S * ************************************************************************/ cJSON* read_comments(const char* comments) { cJSON* comments_struct = cJSON_Parse(comments); if (comments_struct == NULL) { const char* error_ptr = cJSON_GetErrorPtr(); if (error_ptr != NULL) fprintf(stderr, "JSON error before: %s\n", error_ptr); obi_set_errno(OBI_JSON_ERROR); obidebug(1, "\nError reading comments as a cJSON structure"); return NULL; } return comments_struct; } cJSON* add_comment_to_struct(cJSON* comments_struct, const char* key, const char* value) { cJSON* array = NULL; cJSON* element = NULL; cJSON* array_element = NULL; cJSON* value_struct = NULL; cJSON* old_string = NULL; char* elt_value=NULL; cJSON_ArrayForEach(element, comments_struct) { if (strcmp(key, element->string) == 0) { // Check if value is already in // If string, compare value if (cJSON_IsString(element)) { elt_value = cJSON_Print(element); if (strcmp(value, elt_value) == 0) {// If same value, done free(elt_value); return comments_struct; } free(elt_value); } else { if (cJSON_IsArray(element)) // Go through values to check if new value is already in { cJSON_ArrayForEach(array_element, element) { // Compare value elt_value = cJSON_Print(array_element); if (strcmp(value, elt_value) == 0) {// If same value, done free(elt_value); return comments_struct; } free(elt_value); } } } // If value was not found, turn the element into an array (if not array already) and append if (cJSON_IsString(element)) { // Turn the string item into an array array = cJSON_CreateArray(); if (array == NULL) { obi_set_errno(OBI_JSON_ERROR); obidebug(1, "\nError creating an array in a cJSON structure"); return NULL; } cJSON_AddItemToObject(comments_struct, key, array); // Detach the existing string and insert it in the array old_string = cJSON_DetachItemFromObjectCaseSensitive(comments_struct, key); cJSON_AddItemToArray(array, old_string); } else if (cJSON_IsArray(element)) { // Add value in array array = element; } else { obi_set_errno(OBI_JSON_ERROR); obidebug(1, "\nError adding a key/value pair to a cJSON structure: a new value can be added to an existing key" "only if the existing value is either a character string or an array"); return NULL; } // Convert value to cJSON structure value_struct = cJSON_CreateString(value); if (value_struct == NULL) { obi_set_errno(OBI_JSON_ERROR); obidebug(1, "\nError creating a cJSON character string to add a new value to a cJSON structure"); return NULL; } // Add new value item to the array cJSON_AddItemToArray(array, value_struct); // Done return comments_struct; } } // If key not already in, add with value value_struct = cJSON_CreateString(value); if (value_struct == NULL) { obi_set_errno(OBI_JSON_ERROR); obidebug(1, "\nError creating a cJSON character string to add a new value to a cJSON structure"); return NULL; } cJSON_AddItemToObject(comments_struct, key, value_struct); return comments_struct; } /********************************************************************** * * D E F I N I T I O N O F T H E P U B L I C F U N C T I O N S * **********************************************************************/ char* obi_add_comment(char* comments, const char* key, const char* value) { cJSON* comments_struct=NULL; char* new_comments=NULL; // If NULL or empty comments, error if ((comments == NULL) || (strcmp(comments, "") == 0)) { obi_set_errno(OBI_JSON_ERROR); obidebug(1, "\nError adding a key/value pair to a comments character string: comments is NULL"); return NULL; } comments_struct = cJSON_Parse(comments); if (comments_struct == NULL) { obi_set_errno(OBI_JSON_ERROR); obidebug(1, "\nError parsing the comments when adding a comment to a view, key: %s, value: %s", key, value); return NULL; } comments_struct = add_comment_to_struct(comments_struct, key, value); if (comments_struct == NULL) { obi_set_errno(OBI_JSON_ERROR); obidebug(1, "\nError adding a comment to a view, key: %s, value: %s", key, value); return NULL; } // Print to char* new_comments = cJSON_Print(comments_struct); if (new_comments == NULL) { obi_set_errno(OBI_JSON_ERROR); obidebug(1, "\nError building the new comments string when adding a comment to a view, key: %s, value: %s", key, value); return NULL; } // Free structure cJSON_Delete(comments_struct); return new_comments; } char* obi_read_comment(char* comments, const char* key) { cJSON* comments_struct = NULL; cJSON* value_json = NULL; char* value = NULL; comments_struct = cJSON_Parse(comments); if (comments_struct == NULL) { obi_set_errno(OBI_JSON_ERROR); obidebug(1, "\nError parsing the comments when reading comments, key: %s", key); return NULL; } value_json = cJSON_GetObjectItem(comments_struct, key); if (value_json == NULL) { obi_set_errno(OBI_JSON_ERROR); obidebug(1, "\nError getting a value when reading a comment, key: %s", key); return NULL; } value = cJSON_Print(value_json); if (value == NULL) { obi_set_errno(OBI_JSON_ERROR); obidebug(1, "\nError formatting a value when reading a comment, key: %s", key); return NULL; } // Free structure cJSON_Delete(comments_struct); return value; }