radare2/libr/util/r_json.c

335 lines
6.7 KiB
C

/* radare2 - LGPL - Copyright 2017 - wargio */
#include <r_util.h>
#include <r_types.h>
#include <r_util.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
enum {
R_JS_NULL = 0,
R_JS_NUMBERS,
R_JS_BOOLEAN,
R_JS_STRING,
R_JS_ARRAY,
R_JS_OBJECT,
} RJSType;
R_API void r_json_var_free (RJSVar* var) {
ut32 i;
if (!var || var->ref > 1) {
if (var)
var->ref--;
return;
}
var->ref--;
switch (var->type) {
case R_JS_STRING:
free ((char*) var->string.s);
break;
case R_JS_ARRAY:
for (i = 0; i < var->array.l; i++) {
r_json_var_free (var->array.a[i]);
}
free (var->array.a);
break;
case R_JS_OBJECT:
for (i = 0; i < var->object.l; i++) {
r_json_var_free (var->object.a[i]);
free ((char*) var->object.n[i]);
}
free ((char**) var->object.n);
free (var->object.a);
break;
default:
break;
}
free (var);
}
R_API RJSVar* r_json_object_new () {
RJSVar* var = R_NEW0 (RJSVar);
if (var) {
var->type = R_JS_OBJECT;
}
return var;
}
R_API RJSVar* r_json_array_new (int len) {
if (len < 0) {
return NULL;
}
RJSVar* var = R_NEW0 (RJSVar);
if (!var) {
return NULL;
}
if (len) {
var->array.a = R_NEWS0 (RJSVar*, len);
var->array.l = var->array.a ? len : 0;
} else {
var->array.a = NULL;
var->array.l = 0;
}
var->type = R_JS_ARRAY;
return var;
}
R_API RJSVar* r_json_string_new (const char* name) {
if (!name) {
return NULL;
}
RJSVar* var = R_NEW0 (RJSVar);
if (!var) {
return NULL;
}
var->type = R_JS_STRING;
var->string.s = strdup (name);
var->string.l = strlen (name) + 1;
return var;
}
R_API RJSVar* r_json_number_new (int value) {
RJSVar* var = R_NEW0 (RJSVar);
if (!var) {
return NULL;
}
var->type = R_JS_NUMBERS;
var->number = value;
return var;
}
R_API RJSVar* r_json_boolean_new (bool value) {
RJSVar* var = R_NEW0 (RJSVar);
if (!var) {
return NULL;
}
var->type = R_JS_BOOLEAN;
var->boolean = value;
return var;
}
R_API RJSVar* r_json_null_new () {
RJSVar* var = R_NEW0 (RJSVar);
if (!var) {
return NULL;
}
var->type = R_JS_NULL;
return var;
}
R_API bool r_json_object_add (RJSVar* object, const char* name, RJSVar* value) {
ut32 len;
RJSVar** v;
char** c;
if (!object || !name || !value) {
return false;
}
len = object->object.l + 1;
if (len <= 0) {
value->ref--;;
return false;
}
v = (RJSVar**) malloc (len * sizeof (RJSVar*));
if (!v) {
return false;
}
c = (char**) malloc (len * sizeof (char*));
if (!c) {
free (v);
return false;
}
value->ref++;
memcpy (v, object->object.a, (object->object.l * sizeof (RJSVar*)));
memcpy (c, object->object.n, (object->object.l * sizeof (char*)));
v[len - 1] = value;
c[len - 1] = strdup (name);
object->object.l = len;
free (object->object.a);
object->object.a = v;
free ((void *)object->object.n);
object->object.n = (const char**) c;
return true;
}
R_API bool r_json_array_add (RJSVar* array, RJSVar* value) {
ut32 len;
RJSVar** v;
if (!array || !value) {
return false;
}
len = array->array.l + 1;
if (len <= 0) {
return false;
}
v = (RJSVar**) realloc (array->array.a, len * sizeof (RJSVar*));
if (!v) {
return false;
}
value->ref++;
v[len - 1] = value;
array->array.l = len;
array->array.a = v;
return true;
}
R_API RJSVar* r_json_object_get (RJSVar* object, const char* name) {
if (!object || !name) {
return NULL;
}
ut32 i;
for (i = 0; i < object->object.l; i++) {
if (!strcmp (name, object->object.n[i])) {
return object->object.a[i];
}
}
return NULL;
}
R_API RJSVar* r_json_array_get (RJSVar* array, int index) {
if (!array || index <= 0 || index >= array->array.l) {
return NULL;
}
return array->array.a[index];
}
static char* _r_json_null_str (bool expanded) {
if (!expanded) {
return NULL;
}
const int len = sizeof (R_JSON_NULL);
char *c = (char*) malloc (len);
if (c) {
memcpy (c, R_JSON_NULL, len);
}
return c;
}
R_API char* r_json_var_string (RJSVar* var, bool expanded) {
char *c = NULL;
ut32 i, len = 0;
if (!var) {
return _r_json_null_str (expanded);
}
switch (var->type) {
case R_JS_NULL:
c = _r_json_null_str (expanded);
break;
case R_JS_NUMBERS:
len = snprintf (NULL, 0, "%d", var->number) + 1;
c = (char*) malloc (len);
if (!c) {
break;
}
snprintf (c, len, "%d", var->number);
break;
case R_JS_BOOLEAN:
len = var->boolean ? sizeof (R_JSON_TRUE) : sizeof (R_JSON_FALSE);
c = (char*) malloc (len);
if (!c) {
break;
}
snprintf (c, len, "%s", var->boolean ? R_JSON_TRUE : R_JSON_FALSE);
break;
case R_JS_STRING:
len = var->string.l + 2;
c = (char*) malloc (len);
if (!c) {
break;
}
memcpy (c + 1, var->string.s, var->string.l);
c[0] = '"';
c[len - 2] = '"';
c[len - 1] = 0;
break;
case R_JS_ARRAY:
if (var->array.l) {
len = 3;
char* p, *e;
char** t = R_NEWS0 (char*, var->array.l);
if (!t) {
c = (char*) malloc (sizeof (R_JSON_EMPTY_ARR));
memcpy (c, R_JSON_EMPTY_ARR, sizeof (R_JSON_EMPTY_ARR));
break;
}
for (i = 0; i < var->array.l; i++) {
t[i] = r_json_var_string (var->array.a[i], expanded);
if (!t[i]) continue;
len += strlen (t[i]) + 1;
}
c = (char*) calloc (len, 1);
p = c + 1;
e = p + len;
for (i = 0; i < var->array.l; i++) {
if (!t[i]) continue;
if (c) {
p += snprintf (p, e - p, "%s,", t[i]);
}
free (t[i]);
}
if (c) {
c[0] = '[';
if (p == c + 1)
p++;
c[len - (e - p)] = ']';
c[len - 1] = 0;
}
free (t);
} else {
c = (char*) malloc (sizeof (R_JSON_EMPTY_ARR));
memcpy (c, R_JSON_EMPTY_ARR, sizeof (R_JSON_EMPTY_ARR));
}
break;
case R_JS_OBJECT:
if (var->object.l) {
char* p, *e;
char** t = R_NEWS0 (char*, var->object.l);
if (!t) {
c = (char*) malloc (sizeof (R_JSON_EMPTY_OBJ));
memcpy (c, R_JSON_EMPTY_OBJ, sizeof (R_JSON_EMPTY_OBJ));
break;
}
len = 3;
for (i = 0; i < var->object.l; i++) {
t[i] = r_json_var_string (var->object.a[i], expanded);
if (!t[i]) continue;
fflush (stdout);
len += strlen (t[i]) + strlen (var->object.n[i]) + 4;
}
c = (char*) malloc (len);
p = c + 1;
e = p + len;
for (i = 0; i < var->object.l; i++) {
if (!t[i]) continue;
if (c) {
p += snprintf (p, e - p, "\"%s\":%s,", var->object.n[i], t[i]);
}
free (t[i]);
}
if (c) {
c[0] = '{';
if (p == c + 1)
p++;
c[len - (e - p)] = '}';
c[len - 1] = 0;
}
free (t);
} else {
c = (char*) malloc (sizeof (R_JSON_EMPTY_OBJ));
memcpy (c, R_JSON_EMPTY_OBJ, sizeof (R_JSON_EMPTY_OBJ));
}
break;
}
if (!c) {
c = _r_json_null_str (expanded);
}
return c;
}
R_API char* r_json_stringify (RJSVar* var, bool expanded) {
if (!var || (var->type != R_JS_OBJECT && var->type != R_JS_ARRAY)) {
return NULL;
}
return r_json_var_string (var, expanded);
}