diff --git a/CMakeLists.txt b/CMakeLists.txt index 8ce7aee..084a4d5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,8 +49,30 @@ SET (DEP_LIBS -lfcgi -lglib-2.0 -ldl + -ljson-glib-1.0 + -lgobject-2.0 ) +# JSON-GLIB +MESSAGE ("") +MESSAGE ("Try to find the JSON-glib-1.0..") +pkg_check_modules (JSONGLIB REQUIRED json-glib-1.0) + +IF (NOT JSONGLIB_FOUND) + MESSAGE(SEND_ERROR "Can not find json-glib-1.0") +ELSE () + MESSAGE ("json-glib-1.0 is found: ") + MESSAGE ("JSONGLIB_LIB_INCLUDE_DIR : " ${JSONGLIB_LIB_INCLUDE_DIR}) + MESSAGE ("JSONGLIB_INCLUDE_DIR : " ${JSONGLIB_INCLUDE_DIR}) + MESSAGE ("JSONGLIB_LIBRARY_DIR : " ${JSONGLIB_LIBRARY_DIR}) + MESSAGE ("JSONGLIB_INCLUDE_DIRS : " ${JSONGLIB_INCLUDE_DIRS}) + MESSAGE ("JSONGLIB_LIBRARY_DIRS : " ${JSONGLIB_LIBRARY_DIRS}) + MESSAGE ("JSONGLIB_LIBRARIES : " ${JSONGLIB_LIBRARIES}) +ENDIF (NOT JSONGLIB_FOUND) +MESSAGE ("") + +INCLUDE_DIRECTORIES ("${JSONGLIB_INCLUDE_DIRS}") + # version.h CONFIGURE_FILE (${SOURCE_DIR}/version.h.in ${SOURCE_DIR}/version.h) @@ -88,6 +110,8 @@ ADD_EXECUTABLE (${PROJECT_NAME} ${UTILS_DIR}/conf_file_context.c ${UTILS_DIR}/cryptopro.c ${UTILS_DIR}/gconf_file.c + ${UTILS_DIR}/glib_utils.c + ${UTILS_DIR}/json_parser.c ${UTILS_DIR}/library.c ${UTILS_DIR}/logger.c ${UTILS_DIR}/str_t.c diff --git a/src/utils/gconf_file.c b/src/utils/gconf_file.c index ecd57f7..4bcfc11 100644 --- a/src/utils/gconf_file.c +++ b/src/utils/gconf_file.c @@ -1,69 +1,9 @@ #include "gconf_file.h" +#include "glib_utils.h" #include "logger.h" #include -/** Returns the length of the gchar string @str - */ -static inline size_t gstr_byte_len(const gchar* str) -{ - return strlen((char*) str); -} - -/* - * Copies the gchar string pointed by src into the content pointed by dst, including - * the terminating null character (and stopping at that point). - * Uses to avoid dependence from glib. - * @src: gchar string to be copied - * @dst: pointer to destination of type str_t where content is to be copied - * Return value: 0 - success, -1 - error - */ -static int -copy_gchar2strt(const gchar* src, str_t* dst) -{ - assert(src != NULL); - assert(dst != NULL); - - size_t len = gstr_byte_len(src); - char* data = (char*) malloc(len + 1); - if (data == NULL) { - LOG_ERROR("gchar2strt exit with error: could not allocate memory for dst"); - return -1; - } - - dst->data = data; - dst->len = len; - memcpy(dst->data, src, dst->len + 1); - dst->data[dst->len] = '\0'; - return 0; -} - - -/* - * Copies the gchar string pointed by src into the content pointed by return value, - * including the terminating null character (and stopping at that point). - * Uses to avoid dependence from glib. - * @src: gchar string to be copied - * Return value: pointer to destination where content is to be copied - */ -static char* -copy_gchar2char(const gchar* src) -{ - assert(src != NULL); - - // char* tmp_end = strchr(src, '\0'); - char* dst = NULL; - size_t len = gstr_byte_len(src); - dst = (char*) malloc(len + 1); - if (dst == NULL) { - LOG_ERROR("gchar2char exit with error: could not allocate memory for dst"); - return NULL; - } - memcpy(dst, src, len + 1); - return dst; -} - - /* Returns the string value from GKeyFile associated with key under section and converted to str_t * @ini_file: GKeyFile * @section: section name in config file diff --git a/src/utils/glib_utils.c b/src/utils/glib_utils.c new file mode 100644 index 0000000..b08797b --- /dev/null +++ b/src/utils/glib_utils.c @@ -0,0 +1,49 @@ +#include "glib_utils.h" + +#include "logger.h" + +#include + +/** Returns the length of the gchar string @str + */ +static inline size_t +gstr_byte_len(const gchar* str) +{ + return strlen((char*) str); +} + +int +copy_gchar2strt(const gchar* src, str_t* dst) +{ + assert(src != NULL); + assert(dst != NULL); + + size_t len = gstr_byte_len(src); + char* data = (char*) malloc(len + 1); + if (data == NULL) { + LOG_ERROR("gchar2strt exit with error: could not allocate memory for dst"); + return -1; + } + + dst->data = data; + dst->len = len; + memcpy(dst->data, src, dst->len + 1); + dst->data[dst->len] = '\0'; + return 0; +} + +char* +copy_gchar2char(const gchar* src) +{ + assert(src != NULL); + + char* dst = NULL; + size_t len = gstr_byte_len(src); + dst = (char*) malloc(len + 1); + if (dst == NULL) { + LOG_ERROR("gchar2char exit with error: could not allocate memory for dst"); + return NULL; + } + memcpy(dst, src, len + 1); + return dst; +} \ No newline at end of file diff --git a/src/utils/glib_utils.h b/src/utils/glib_utils.h new file mode 100644 index 0000000..3873e1d --- /dev/null +++ b/src/utils/glib_utils.h @@ -0,0 +1,32 @@ +#ifndef GLIB_UTULS_H_INCLUDED +#define GLIB_UTULS_H_INCLUDED + +#include "str_t.h" + +#include + + +/* + * Copies the gchar string pointed by src into the content pointed by dst, including + * the terminating null character (and stopping at that point). + * Uses to avoid dependence from glib. + * @src: gchar string to be copied + * @dst: pointer to destination of type str_t where content is to be copied + * Return value: 0 - success, -1 - error + */ +int +copy_gchar2strt(const gchar* src, str_t* dst); + + +/* + * Copies the gchar string pointed by src into the content pointed by return value, + * including the terminating null character (and stopping at that point). + * Uses to avoid dependence from glib. + * @src: gchar string to be copied + * Return value: pointer to destination where content is to be copied + */ +char* +copy_gchar2char(const gchar* src); + + +#endif // GLIB_UTULS_H_INCLUDED diff --git a/src/utils/json_parser.c b/src/utils/json_parser.c new file mode 100644 index 0000000..8f2b797 --- /dev/null +++ b/src/utils/json_parser.c @@ -0,0 +1,239 @@ +#include "json_parser.h" + +#include "glib_utils.h" +#include "logger.h" + +#include +#include + + +typedef struct json_parser_s { + JsonParser *parser; + void *root; + json_parser_type root_type; + +} json_parser_t; + + +static JsonObject* get_object_from_node(JsonNode *node); +static int json_get_object_member_as_string(Hjson_parser hparser, const char* field_name, + /*out*/ str_t* field_value); + + +Hjson_parser +json_parser_create(const char* data, size_t data_len) +{ + GError* gerror = NULL; + JsonNode* json_node = NULL; + JsonNodeType json_node_type; + const char *desc = ""; + + LOG_TRACE("json_parser_create enter"); + + assert(data != NULL && data_len != 0 && "json data is empty"); + + json_parser_t* parser = calloc (sizeof(json_parser_t), 1); + if (parser == NULL) { + desc = "Could not allocate memory for json_parser_t"; + goto error; + } + + parser->parser = json_parser_new(); + if (parser->parser == NULL) { + desc = "Could not create JsonParser"; + goto error; + } + + LOG_DEBUG("json_parser_create. json data: %.*s", (int)data_len, data); + + if (json_parser_load_from_data(parser->parser, data, data_len, &gerror) != TRUE) { + LOG_ERROR("json_parser_create. json_parser_load_from_data failed: %s", gerror->message); + g_error_free(gerror); + goto error; + } + + /* get root node */ + json_node = json_parser_get_root(parser->parser); + if (json_node == NULL) { + desc = "Could not parse json object: json_parser_get_root failed"; + goto error; + } + + json_node_type = json_node_get_node_type(json_node); + if (json_node_type != JSON_NODE_OBJECT) { + desc = "Could not parse json object: unexpected root type"; + goto error; + } + + parser->root_type = JSON_PARSER_TYPE_OBJECT; + + /* try to get root as object */ + parser->root = get_object_from_node(json_node); + if (parser->root == NULL) { + desc = "Could not parse json object: json_node_get_object failed"; + goto error; + } + + return (Hjson_parser)parser; + +error: + json_parser_free((Hjson_parser)parser); + LOG_ERROR("json_parser_create exit with error. Desc: %s", desc); + return NULL;; +} + + +void +json_parser_free(Hjson_parser hparser) +{ + json_parser_t* parser = (json_parser_t*) hparser; + + if (parser == NULL) return; + + if (parser->parser != NULL) { + g_object_unref(parser->parser); + } + + free(parser); +} + + +int +json_get_string_member(Hjson_parser hparser, const char* field_name, + /*out*/ str_t* field_value) +{ + LOG_TRACE("json_get_string_member enter"); + + switch (json_get_object_member_as_string(hparser, field_name, field_value)) { + case 0: + LOG_TRACE("json_get_string_member exit successfully. field_value: %.*s", + (int) field_value->len, + field_value->data); + return 0; + case 1: + LOG_ERROR("Could not retrieve '%.*s' from json object. " + "Desc: field does not exist or it has not proper type. " + "Expected: string member", + (int) field_value->len, field_value->data); + break; + default: + LOG_ERROR("json_get_object_member_as_string failed, member: '%.*s'", + (int) field_value->len, field_value->data); + break; + + } + + LOG_ERROR("json_get_string_member exit with error"); + return -1; +} + + +static JsonObject* +get_object_from_node(JsonNode *node) +{ + JsonObject *ret = NULL; + + if (node == NULL) { + LOG_WARN("get_object_from_node. node is NULL"); + return NULL; + } + + if (!JSON_NODE_HOLDS_OBJECT(node)) { + LOG_ERROR("Bad json scheme. Expected node: object"); + return NULL; + } + + ret = json_node_get_object(node); + assert(ret != NULL && "Could not extract the node of correct type"); + + return ret; +} + + +static int +get_string_from_node(JsonNode *node, /*out*/ const gchar **value) +{ + assert(value != NULL); + + *value = NULL; + + if (node == NULL) { + LOG_WARN("get_string_from_node. node is NULL"); + return 0; + } + + /* если нод содержит нулевое значение, оставляем наш указатель так же нулевым */ + if (JSON_NODE_HOLDS_NULL(node)) { + LOG_DEBUG("get_string_from_node. node holds NULL"); + return 0; + } + + if (!JSON_NODE_HOLDS_VALUE(node) || G_TYPE_STRING != json_node_get_value_type(node)) { + LOG_ERROR("Bad json scheme. Expected node: string value. Actual node type: %s", + json_node_type_name(node)); + return -1; + } + + *value = json_node_get_string(node); + if (*value == NULL) { + LOG_ERROR("Bad json node. Expected node: string value"); + return -1; + } + + return 0; +} + + +static int +json_object_get_string(JsonObject *object, const gchar *key, /*out*/const gchar** value) +{ + JsonNode *node = NULL; + + LOG_TRACE("json_object_get_string"); + + assert(object != NULL); + assert(key != NULL); + assert(value != NULL); + + *value = NULL; + + node = json_object_get_member(object, key); + + if (node == NULL) { + LOG_DEBUG("object member by key '%s' is not exists", key); + /* ret = NULL; */ + return 0; + } + + return get_string_from_node(node, value); +} + + +static int +json_get_object_member_as_string(Hjson_parser hparser, const char* field_name, + /*out*/ str_t* field_value) +{ + json_parser_t* parser = (json_parser_t*) hparser; + const gchar* value = NULL; + + assert(parser != NULL); + assert(parser->root_type == JSON_PARSER_TYPE_OBJECT); + assert(parser->root != NULL); + assert(field_name != NULL); + assert(field_value != NULL && str_t_is_null(*field_value)); + + LOG_DEBUG("json_get_object_member_as_string. field name: %s", field_name); + + if (json_object_get_string((JsonObject*) (parser->root), field_name, &value)) { + return -1; + } + if (value == NULL) { + return 1; + } + if (copy_gchar2strt(value, field_value) != 0) { + LOG_ERROR("json_get_object_member_as_string. Could not copy field_value"); + return -1; + } + + return 0; +} diff --git a/src/utils/json_parser.h b/src/utils/json_parser.h new file mode 100644 index 0000000..a99ade1 --- /dev/null +++ b/src/utils/json_parser.h @@ -0,0 +1,31 @@ +#ifndef JSON_PARSER_H_INCLUDED +#define JSON_PARSER_H_INCLUDED + +#include "str_t.h" + +#include +#include + + +typedef struct json_parser_t *Hjson_parser; + + +typedef enum json_parser_type_e { + JSON_PARSER_TYPE_UNKNOWN, + JSON_PARSER_TYPE_STRING, + JSON_PARSER_TYPE_OBJECT, + JSON_PARSER_TYPE_ARRAY + +} json_parser_type; + + +Hjson_parser json_parser_create(const char* data, size_t data_len); + +void json_parser_free(Hjson_parser hparser); + + +int json_get_string_member(Hjson_parser hparser, const char* field_name, + /*out*/ str_t* field_value); + + +#endif // JSON_PARSER_H_INCLUDED