You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
359 lines
8.0 KiB
359 lines
8.0 KiB
#include <stdlib.h> |
|
#include <string.h> |
|
#include <stdio.h> |
|
#include <errno.h> |
|
#include <stdarg.h> |
|
#include "json.h" |
|
#include "log.h" |
|
|
|
struct json_object *json_create_object(void) |
|
{ |
|
return calloc(1, sizeof(struct json_object)); |
|
} |
|
|
|
struct json_array *json_create_array(void) |
|
{ |
|
return calloc(1, sizeof(struct json_array)); |
|
} |
|
|
|
static struct json_pair *json_create_pair(const char *name, struct json_value *value) |
|
{ |
|
struct json_pair *pair = malloc(sizeof(struct json_pair)); |
|
if (pair) { |
|
pair->name = strdup(name); |
|
pair->value = value; |
|
|
|
value->parent_type = JSON_PARENT_TYPE_PAIR; |
|
value->parent_pair = pair; |
|
} |
|
return pair; |
|
} |
|
|
|
static struct json_value *json_create_value_int(long long number) |
|
{ |
|
struct json_value *value = malloc(sizeof(struct json_value)); |
|
|
|
if (value) { |
|
value->type = JSON_TYPE_INTEGER; |
|
value->integer_number = number; |
|
} |
|
return value; |
|
} |
|
|
|
static struct json_value *json_create_value_float(double number) |
|
{ |
|
struct json_value *value = malloc(sizeof(struct json_value)); |
|
|
|
if (value) { |
|
value->type = JSON_TYPE_FLOAT; |
|
value->float_number = number; |
|
} |
|
return value; |
|
} |
|
|
|
static char *strdup_escape(const char *str) |
|
{ |
|
const char *input = str; |
|
char *p, *ret; |
|
int escapes; |
|
|
|
if (!strlen(str)) |
|
return NULL; |
|
|
|
escapes = 0; |
|
while ((input = strpbrk(input, "\\\"")) != NULL) { |
|
escapes++; |
|
input++; |
|
} |
|
|
|
p = ret = malloc(strlen(str) + escapes + 1); |
|
while (*str) { |
|
if (*str == '\\' || *str == '\"') |
|
*p++ = '\\'; |
|
*p++ = *str++; |
|
} |
|
*p = '\0'; |
|
|
|
return ret; |
|
} |
|
|
|
/* |
|
* Valid JSON strings must escape '"' and '/' with a preceding '/' |
|
*/ |
|
static struct json_value *json_create_value_string(const char *str) |
|
{ |
|
struct json_value *value = malloc(sizeof(struct json_value)); |
|
|
|
if (value) { |
|
value->type = JSON_TYPE_STRING; |
|
value->string = strdup_escape(str); |
|
if (!value->string) { |
|
free(value); |
|
value = NULL; |
|
} |
|
} |
|
return value; |
|
} |
|
|
|
static struct json_value *json_create_value_object(struct json_object *obj) |
|
{ |
|
struct json_value *value = malloc(sizeof(struct json_value)); |
|
|
|
if (value) { |
|
value->type = JSON_TYPE_OBJECT; |
|
value->object = obj; |
|
obj->parent = value; |
|
} |
|
return value; |
|
} |
|
|
|
static struct json_value *json_create_value_array(struct json_array *array) |
|
{ |
|
struct json_value *value = malloc(sizeof(struct json_value)); |
|
|
|
if (value) { |
|
value->type = JSON_TYPE_ARRAY; |
|
value->array = array; |
|
array->parent = value; |
|
} |
|
return value; |
|
} |
|
|
|
static void json_free_pair(struct json_pair *pair); |
|
static void json_free_value(struct json_value *value); |
|
|
|
void json_free_object(struct json_object *obj) |
|
{ |
|
int i; |
|
|
|
for (i = 0; i < obj->pair_cnt; i++) |
|
json_free_pair(obj->pairs[i]); |
|
free(obj->pairs); |
|
free(obj); |
|
} |
|
|
|
static void json_free_array(struct json_array *array) |
|
{ |
|
int i; |
|
|
|
for (i = 0; i < array->value_cnt; i++) |
|
json_free_value(array->values[i]); |
|
free(array->values); |
|
free(array); |
|
} |
|
|
|
static void json_free_pair(struct json_pair *pair) |
|
{ |
|
json_free_value(pair->value); |
|
free(pair->name); |
|
free(pair); |
|
} |
|
|
|
static void json_free_value(struct json_value *value) |
|
{ |
|
switch (value->type) { |
|
case JSON_TYPE_STRING: |
|
free(value->string); |
|
break; |
|
case JSON_TYPE_OBJECT: |
|
json_free_object(value->object); |
|
break; |
|
case JSON_TYPE_ARRAY: |
|
json_free_array(value->array); |
|
break; |
|
} |
|
free(value); |
|
} |
|
|
|
static int json_array_add_value(struct json_array *array, struct json_value *value) |
|
{ |
|
struct json_value **values = realloc(array->values, |
|
sizeof(struct json_value *) * (array->value_cnt + 1)); |
|
|
|
if (!values) |
|
return ENOMEM; |
|
values[array->value_cnt] = value; |
|
array->value_cnt++; |
|
array->values = values; |
|
|
|
value->parent_type = JSON_PARENT_TYPE_ARRAY; |
|
value->parent_array = array; |
|
return 0; |
|
} |
|
|
|
static int json_object_add_pair(struct json_object *obj, struct json_pair *pair) |
|
{ |
|
struct json_pair **pairs = realloc(obj->pairs, |
|
sizeof(struct json_pair *) * (obj->pair_cnt + 1)); |
|
if (!pairs) |
|
return ENOMEM; |
|
pairs[obj->pair_cnt] = pair; |
|
obj->pair_cnt++; |
|
obj->pairs = pairs; |
|
|
|
pair->parent = obj; |
|
return 0; |
|
} |
|
|
|
int json_object_add_value_type(struct json_object *obj, const char *name, int type, ...) |
|
{ |
|
struct json_value *value; |
|
struct json_pair *pair; |
|
va_list args; |
|
int ret; |
|
|
|
va_start(args, type); |
|
if (type == JSON_TYPE_STRING) |
|
value = json_create_value_string(va_arg(args, char *)); |
|
else if (type == JSON_TYPE_INTEGER) |
|
value = json_create_value_int(va_arg(args, long long)); |
|
else if (type == JSON_TYPE_FLOAT) |
|
value = json_create_value_float(va_arg(args, double)); |
|
else if (type == JSON_TYPE_OBJECT) |
|
value = json_create_value_object(va_arg(args, struct json_object *)); |
|
else |
|
value = json_create_value_array(va_arg(args, struct json_array *)); |
|
va_end(args); |
|
|
|
if (!value) |
|
return ENOMEM; |
|
|
|
pair = json_create_pair(name, value); |
|
if (!pair) { |
|
json_free_value(value); |
|
return ENOMEM; |
|
} |
|
ret = json_object_add_pair(obj, pair); |
|
if (ret) { |
|
json_free_pair(pair); |
|
return ENOMEM; |
|
} |
|
return 0; |
|
} |
|
|
|
static void json_print_array(struct json_array *array, struct buf_output *); |
|
int json_array_add_value_type(struct json_array *array, int type, ...) |
|
{ |
|
struct json_value *value; |
|
va_list args; |
|
int ret; |
|
|
|
va_start(args, type); |
|
if (type == JSON_TYPE_STRING) |
|
value = json_create_value_string(va_arg(args, char *)); |
|
else if (type == JSON_TYPE_INTEGER) |
|
value = json_create_value_int(va_arg(args, long long)); |
|
else if (type == JSON_TYPE_FLOAT) |
|
value = json_create_value_float(va_arg(args, double)); |
|
else if (type == JSON_TYPE_OBJECT) |
|
value = json_create_value_object(va_arg(args, struct json_object *)); |
|
else |
|
value = json_create_value_array(va_arg(args, struct json_array *)); |
|
va_end(args); |
|
|
|
if (!value) |
|
return ENOMEM; |
|
|
|
ret = json_array_add_value(array, value); |
|
if (ret) { |
|
json_free_value(value); |
|
return ENOMEM; |
|
} |
|
return 0; |
|
} |
|
|
|
static int json_value_level(struct json_value *value); |
|
static int json_pair_level(struct json_pair *pair); |
|
static int json_array_level(struct json_array *array); |
|
static int json_object_level(struct json_object *object) |
|
{ |
|
if (object->parent == NULL) |
|
return 0; |
|
return json_value_level(object->parent); |
|
} |
|
|
|
static int json_pair_level(struct json_pair *pair) |
|
{ |
|
return json_object_level(pair->parent) + 1; |
|
} |
|
|
|
static int json_array_level(struct json_array *array) |
|
{ |
|
return json_value_level(array->parent); |
|
} |
|
|
|
static int json_value_level(struct json_value *value) |
|
{ |
|
if (value->parent_type == JSON_PARENT_TYPE_PAIR) |
|
return json_pair_level(value->parent_pair); |
|
else |
|
return json_array_level(value->parent_array) + 1; |
|
} |
|
|
|
static void json_print_level(int level, struct buf_output *out) |
|
{ |
|
while (level-- > 0) |
|
log_buf(out, " "); |
|
} |
|
|
|
static void json_print_pair(struct json_pair *pair, struct buf_output *); |
|
static void json_print_array(struct json_array *array, struct buf_output *); |
|
static void json_print_value(struct json_value *value, struct buf_output *); |
|
void json_print_object(struct json_object *obj, struct buf_output *out) |
|
{ |
|
int i; |
|
|
|
log_buf(out, "{\n"); |
|
for (i = 0; i < obj->pair_cnt; i++) { |
|
if (i > 0) |
|
log_buf(out, ",\n"); |
|
json_print_pair(obj->pairs[i], out); |
|
} |
|
log_buf(out, "\n"); |
|
json_print_level(json_object_level(obj), out); |
|
log_buf(out, "}"); |
|
} |
|
|
|
static void json_print_pair(struct json_pair *pair, struct buf_output *out) |
|
{ |
|
json_print_level(json_pair_level(pair), out); |
|
log_buf(out, "\"%s\" : ", pair->name); |
|
json_print_value(pair->value, out); |
|
} |
|
|
|
static void json_print_array(struct json_array *array, struct buf_output *out) |
|
{ |
|
int i; |
|
|
|
log_buf(out, "[\n"); |
|
for (i = 0; i < array->value_cnt; i++) { |
|
if (i > 0) |
|
log_buf(out, ",\n"); |
|
json_print_level(json_value_level(array->values[i]), out); |
|
json_print_value(array->values[i], out); |
|
} |
|
log_buf(out, "\n"); |
|
json_print_level(json_array_level(array), out); |
|
log_buf(out, "]"); |
|
} |
|
|
|
static void json_print_value(struct json_value *value, struct buf_output *out) |
|
{ |
|
switch (value->type) { |
|
case JSON_TYPE_STRING: |
|
log_buf(out, "\"%s\"", value->string); |
|
break; |
|
case JSON_TYPE_INTEGER: |
|
log_buf(out, "%lld", value->integer_number); |
|
break; |
|
case JSON_TYPE_FLOAT: |
|
log_buf(out, "%f", value->float_number); |
|
break; |
|
case JSON_TYPE_OBJECT: |
|
json_print_object(value->object, out); |
|
break; |
|
case JSON_TYPE_ARRAY: |
|
json_print_array(value->array, out); |
|
break; |
|
} |
|
}
|
|
|