Skip to content
Snippets Groups Projects
json-editor.c 12.5 KiB
Newer Older
  • Learn to ignore specific revisions
  • #include <unistd.h>
    #include <string.h>
    #include <stdio.h>
    #include <stdbool.h>
    
    #include <libubox/blobmsg.h>
    #include <libubox/blobmsg_json.h>
    #include <json-c/json.h>
    
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    #include "json-editor.h"
    
    
    /* will allocate memory! remember to free! */
    
    static char *get_file(const char *path)
    
    	size_t nread;
    	long int len;
    
    	char *buffer;
    
    	f = fopen(path, "r");
    	if (!f)
    		goto out;
    
    	if (fseek(f, 0, SEEK_END))
    		goto out_close;
    
    	len = ftell(f);
    	if (len < 0)
    		goto out_close;
    
    	if (fseek(f, 0, SEEK_SET))
    		goto out_close;
    
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    	buffer = calloc(1, len + 1);
    
    	if (!buffer)
    		goto out_close;
    
    	nread = fread(buffer, sizeof(char), len, f);
    	if (nread < len)
    		goto out_free;
    
    	fclose(f);
    	return buffer;
    out_free:
    	free(buffer);
    out_close:
    	fclose(f);
    out:
    	return NULL;
    }
    
    
    struct json_object *json_object_file_to_obj(const char *path)
    
    {
    	struct json_object *obj;
    	char *file_str;
    
    	file_str = get_file(path);
    	if (!file_str)
    		goto out;
    
    	obj = json_tokener_parse(file_str);
    
    	free(file_str);
    	return obj;
    out:
    	return NULL;
    }
    
    
    int json_object_obj_to_file(struct json_object *obj, const char *path)
    {
    	FILE *out;
        int rv = -1;
    
    	const char *data;
    
    
    	if (!obj) {
    		fprintf(stderr, "%s error: No object provided!\n", __func__);
    		goto out;
    	}
    
    	if (!path) {
    		fprintf(stderr, "%s error: No file path provided!\n", __func__);
    		goto out;
    	}
    
    	data = json_object_get_string(obj);
    	if (!data) {
    		fprintf(stderr, "%s error: Converting object to string!\n", __func__);
    		goto out;
    	}
    
    	out = fopen (path, "ab+");
        if (out != NULL) {
            if (fputs (data, out) != EOF)
    			goto out_fclose;
    
    		rv = 0;
        }
    
    out_fclose:
    	fclose (out);
    out:
        return rv;
    }
    
    
    static int get_idx(char *key, int *idx, char *out)
    
    	char *open_brace;
    	int len = 0;
    	char buffer[64] = {0};
    	char *ptr;
    
    
    		return -1;
    
    	strncpy(buffer, key, sizeof(buffer) - 1);
    	ptr = (char *)buffer;
    
    	while((open_brace = strchr(ptr, '['))) {
    
    		char *close_brace = strchr(open_brace, ']');
    
    		if (close_brace) {
    
    			int str_len;
    
    			str_len = close_brace - open_brace;
    			idx_str = calloc(1, str_len);
    			strncpy(idx_str, open_brace + 1, str_len-1);
    			idx[len++] = atoi(idx_str);
    
    			*open_brace = '\0';
    
    			ptr = close_brace;
    
    	strncpy(out, buffer, 31);
    
    	return len;
    
    static struct json_object *dummy_val(char *val, enum json_type type)
    
    {
    	struct json_object *j_val;
    
    	switch(type) {
    	case json_type_array:
    		j_val = json_tokener_parse(val);
    	break;
    	case json_type_boolean:
    		;;
    	break;
    	case json_type_object:
    		j_val = json_tokener_parse(val);
    	break;
    	case json_type_string:
    		j_val = json_object_new_string(val);
    	break;
    	case json_type_double:
    		j_val = json_object_new_double(atof(val));
    	break;
    	case json_type_int:
    
    		j_val = json_object_new_int(atoi(val));
    
    	break;
    	default:
    
    /**
     * If key to be added is indexed, makes sure specified key is an array and selects appropriate index.
     * Should the key not be an array, it will be converted to an array and appropriate indexes will be prepared.
     *
     */
    
    static int iterate_array(struct json_object *src, int *idx, int len, struct json_object *j_val, char *key)
    
    	struct json_object *val;
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    	if (len < 1)
    		return -1;
    
    
    
    	/* select key, if it does not exist or is not an array, create one */
    	json_object_object_get_ex(src, key, &val);
    	if (!val || !json_object_is_type(val, json_type_array)) {
    		val = json_object_new_array();
    		json_object_object_add(src, key, val);
    
    	/* iterate every index that was appended to the key */
    
    	for (int i = 0; i < len; i++) {
    
    		struct json_object *j_idx;
    
    		/* select specified idx from currently selected array */
    		j_idx = json_object_array_get_idx(val, idx[i]);
    
    		/* if we are not at final idx, make sure next entry is an array */
    
    		if (i < len -1) {
    
    			if (!j_idx || !json_object_is_type(j_idx, json_type_array)) {
    				j_idx = json_object_new_array();
    
    				if (idx[i] > -1)
    
    					json_object_array_put_idx(val, idx[i], j_idx);
    
    					json_object_array_add(val, j_idx);
    
    			val = j_idx;
    		}
    		/* at final index, place passed object at specified idx */
    		else {
    
    			if (idx[i] > -1)
    
    				json_object_array_put_idx(val, idx[i], j_val);
    
    				json_object_array_add(val, j_val);
    
    static void copy_object_into_object(struct json_object *src, struct json_object *dst)
    {
    	json_object_object_foreach(src, key, val)
    		json_object_object_add(dst, key, json_object_get(val));
    
    	json_object_put(src);
    }
    
    /**
     * Add a value key pair to src object
     *
     */
    static int add_val(struct json_object *src, char *key, char *val, enum json_type type)
    
    {
    	struct json_object *j_val;
    
    	int idx[32];
    	int len;
    	char parsed_key[32] = {0};
    
    	len = get_idx(key, idx, parsed_key);
    
    	j_val = dummy_val(val, type);
    	if (!j_val || !json_object_is_type(j_val, type)) {
    
    		fprintf(stderr, "Invalid input value, parsed value and input type does not match!\n");
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    		json_object_put(j_val);
    
    	/* if input object is of type object we need to iterate the object and copy {key:value} into specified key */
    
    	if (json_type_object == type) {
    
    		if (len < 1) {
    
    			/* if a key is provided, place input under that key, else place in root */
    			if (key) {
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    				struct json_object *j_new;
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    				j_new = json_object_new_object();
    				if (!j_new)
    
    					return -1;
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    				copy_object_into_object(j_val, j_new);
    				json_object_object_add(src, parsed_key, j_new);
    
    			} else
    				copy_object_into_object(j_val, src);
    
    		} else
    
    			iterate_array(src, idx, len, j_val, parsed_key);
    
    		goto out;
    
    	/* object type is not an object, attach to provided key */
    
    	if (len < 1 || type == json_type_array)
    
    		json_object_object_add(src, parsed_key, j_val);
    
    		iterate_array(src, idx, len, j_val, parsed_key);
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    /**
     * del a value key pair to src object
     *
     */
    static int del_val(struct json_object *src, char *key)
    {
    	struct json_object *val;
    	int idx[32];
    	int len, rv = -1;
    	char parsed_key[32] = {0};
    
    	len = get_idx(key, idx, parsed_key);
    
    	json_object_object_get_ex(src, parsed_key, &val);
    	if (len < 1 || !val || !json_object_is_type(val, json_type_array)) {
    		json_object_object_del(src, parsed_key);
    		rv = 0;
    	} else {
    		/* iterate every index that was appended to the key */
    		for (int i = 0; i < len; i++) {
    			struct json_object *j_idx;
    
    			/* select specified idx from currently selected array */
    			j_idx = json_object_array_get_idx(val, idx[i]);
    
    			/* if we are not at final idx, make sure next entry is an array */
    			if (i < len -1) {
    				if (!j_idx || !json_object_is_type(j_idx, json_type_array)) {
    					fprintf(stderr, "%s error: type is not array!\n", __func__);
    					goto out;
    				}
    				val = j_idx;
    			}
    			/* at final index, delete at specified idx */
    			else {
    				if (idx[i] > -1)
    					json_object_array_del_idx(val, idx[i], 1);
    				else
    					json_object_array_del_idx(val, json_object_array_length(val) - 1, 1);
    
    				rv = 0;
    			}
    		}
    	}
    
    out:
    	return rv;
    }
    
    
    int json_object_set_by_string(struct json_object **src, char *fmt, char *val, enum json_type type)
    {
    	return json_object_set_by_string_delimiter(src, fmt, val, type, ".");
    }
    
    
    /**
     * Generate object according to javascript style format
     *
     */
    
    int json_object_set_by_string_delimiter(struct json_object **src, char *fmt, char *val, enum json_type type, const char *delimiter)
    
    	struct json_object *ptr, *outer_obj, *j_idx;
    
    	char fmt_cpy[1024] = {0}, parsed_key[32] = {0};
    
    	char *p, *key = fmt;
    
    	int idx[32];
    	int len;
    
    		*src = json_object_new_object();
    
    
    	ptr = outer_obj = *src;
    
    
    	strcpy(fmt_cpy, fmt);
    	p = strtok(fmt_cpy,delimiter);
    
    
    		key = p;
    
    		/* if next key exists, parse key, let switch-case add/alter last key */
    
    			memset(idx, 0, sizeof(idx));
    
    			len = get_idx(key, idx, parsed_key);
    
    
    			/* as next key exists (p), we muts create an object here if it is currently not an object */
    
    			json_object_object_get_ex(outer_obj, parsed_key, &ptr);
    
    			if (!json_object_is_type(ptr, json_type_object) && !json_object_is_type(ptr, json_type_array)) {
    
    				/* we know its an object because it is not the last key */
    
    				ptr = json_object_new_object();
    
    				json_object_object_add(outer_obj, parsed_key, ptr);
    
    			/* if the key is indexed, we need step into the array */
    			for (int i = 0; i < len; i++) {
    				/* make sure ptr is an array, step into specified index */
    				if (ptr && json_object_get_type(ptr) == json_type_array) {
    					if (idx[i] > -1 && idx[i] < json_object_array_length(ptr)) {
    						j_idx = json_object_array_get_idx(ptr, idx[i]);
    						if (!json_object_is_type(j_idx, json_type_object)) {
    							struct json_object *obj = json_object_new_object();
    							if (!obj)
    								return -1;
    
    							json_object_array_put_idx(ptr, idx[i], obj);
    							j_idx = json_object_array_get_idx(ptr, idx[i]);
    
    						ptr = j_idx;
    					}
    					else {
    						if (i == len - 1)
    
    							json_object_array_add(ptr, json_object_new_object());
    
    						else if (i < len -1)
    							json_object_array_add(ptr, json_object_new_array());
    						ptr = json_object_array_get_idx(ptr, json_object_array_length(ptr) - 1);
    					}
    				} else {
    					ptr = json_object_new_array();
    					json_object_object_add(outer_obj, parsed_key, ptr);
    					if (i == len - 1) {
    						json_object_array_add(ptr, json_object_new_object());
    						ptr = json_object_array_get_idx(ptr, json_object_array_length(ptr) - 1);
    
    			/* if this point is reached and ptr is not set, a key is specified which does not exist - create it */
    
    			if (!ptr) {
    				ptr = json_object_new_object();
    
    				if (json_object_get_type(outer_obj) == json_type_array)
    					json_object_array_add(outer_obj, ptr);
    				else if (json_object_get_type(outer_obj) == json_type_object)
    					json_object_object_add(outer_obj, parsed_key, ptr);
    
    		outer_obj = ptr;
    
    	add_val(ptr, key, val, type);
    
    int json_object_set(struct json_object *src, char *fmt, struct json_object *val)
    {
    	return json_object_set_delimiter(src, fmt, val, ".");
    }
    
    int json_object_set_delimiter(struct json_object *src, char *fmt, struct json_object *val, const char *delimiter)
    
    	char fmt_cpy[1024] = {0};
    
    	char *p;
    
    	if (json_object_get_type(val) != json_type_object) {
    		fprintf(stderr, "object must be of type object!\n");
    		return -1;
    	}
    
    
    	src = json_object_get_by_string(src, fmt);
    
    	strcpy(fmt_cpy, fmt);
    
    	for (p = strtok(fmt_cpy,delimiter); p != NULL; p = strtok(NULL, delimiter)) {
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    		struct json_object *ptr, *outer_obj = src;
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    		json_object_object_get_ex(outer_obj, p, &ptr);
    
    		if (!ptr) {
    			ptr = json_object_new_object();
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    			json_object_object_add(outer_obj, p, ptr);
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    		outer_obj = ptr;
    
    	json_object_object_foreach(val, key, j_val)
    		json_object_object_add(src, key, j_val);
    
    struct json_object *json_object_get_by_string(struct json_object *src, char *fmt)
    {
    	return json_object_get_by_string_delimiter(src, fmt, ".");
    }
    
    struct json_object *json_object_get_by_string_delimiter(struct json_object *src, char *fmt, const char *delimiter)
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    	struct json_object *ptr, *outer_obj = src;
    
    	char fmt_cpy[1024] = {0};
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    	char parsed_key[32] = {0};
    	int idx[32];
    
    	strcpy(fmt_cpy, fmt);
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    	for (char *key = strtok(fmt_cpy,delimiter); key != NULL; key = strtok(NULL, delimiter)) {
    		int len = 0;
    		len = get_idx(key, idx, parsed_key);
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    		json_object_object_get_ex(outer_obj, parsed_key, &ptr);
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    
    		for (int i = 0; i < len; i++) {
    			if (!json_object_is_type(ptr, json_type_array))
    				return NULL;
    
    			int index = (idx[i] == -1 ? json_object_array_length(ptr) -1 : idx[i]);
    			ptr = json_object_array_get_idx(ptr, index);
    		}
    
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    		outer_obj = ptr;
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    
    int json_object_del_by_string(struct json_object *src, char *fmt)
    {
    	return json_object_del_by_string_delimiter(src, fmt, ".");
    }
    
    
    int json_object_del_by_string_delimiter(struct json_object *src, char *fmt, const char *delimiter)
    {
    	struct json_object *ptr, *outer_obj, *j_idx;
    	char fmt_cpy[1024] = {0}, parsed_key[32] = {0};
    	char *p, *key = fmt;
    	int idx[32];
    	int len;
    
    	if (!src) {
    		fprintf(stderr, "%s error: No object\n", __func__);
    		return -1;
    	}
    
    	if (!fmt) {
    		fprintf(stderr, "%s error: Invalid format\n", __func__);
    		return -1;
    	}
    
    	ptr = outer_obj = src;
    
    	strcpy(fmt_cpy, fmt);
    	p = strtok(fmt_cpy,delimiter);
    
    	while (p != NULL) {
    		key = p;
    		p = strtok(NULL, delimiter);
    
    		if (p) {
    			int len = 0;
    			len = get_idx(key, idx, parsed_key);
    			json_object_object_get_ex(outer_obj, parsed_key, &ptr);
    
    			for (int i = 0; i < len; i++) {
    				if (!json_object_is_type(ptr, json_type_array))
    					return -1;
    
    				int index = (idx[i] == -1 ? json_object_array_length(ptr) -1 : idx[i]);
    				ptr = json_object_array_get_idx(ptr, index);
    			}
    
    		}
    
    		outer_obj = ptr;
    	}
    
    	del_val(ptr, key);
    
    	return 0;
    }