mirror of
https://github.com/NationalSecurityAgency/maat.git
synced 2026-11-09 20:21:24 -10:00
804 lines
20 KiB
C
804 lines
20 KiB
C
/*
|
|
* Copyright 2023 United States Government
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* Simplified graph library for Maat
|
|
*
|
|
* json.c: Serialize the graph to and from JSON
|
|
*/
|
|
#include <sgraph_internal.h>
|
|
#include <json.h>
|
|
|
|
/*
|
|
* A preprocessor macro to avoid code duplication when converting from
|
|
* a JSON array to a list of a specific type
|
|
*/
|
|
|
|
#define ARRAY_TO_LIST_TYPE(TYPE) \
|
|
static GList *json_array_to_##TYPE##_list(json_object *array) \
|
|
{ \
|
|
GList *list = NULL; \
|
|
int arraylen; \
|
|
int i; \
|
|
\
|
|
if (json_object_get_type(array) != json_type_array) { \
|
|
log("Non-array passed to array parser\n"); \
|
|
return NULL; \
|
|
} \
|
|
\
|
|
arraylen = json_object_array_length(array); \
|
|
\
|
|
for(i=0; i<arraylen; i++) { \
|
|
json_object *tmp = json_object_array_get_idx(array, i); \
|
|
struct sg_##TYPE *x = json_to_##TYPE(tmp); \
|
|
if (x != NULL) { \
|
|
list = g_list_append(list, x); \
|
|
} \
|
|
} \
|
|
\
|
|
return list; \
|
|
}
|
|
|
|
|
|
/*
|
|
* Address handling functions.
|
|
*/
|
|
static json_object *address_to_json(const struct sg_address *a)
|
|
{
|
|
json_object *ja;
|
|
json_object *jspace;
|
|
json_object *jaddr;
|
|
|
|
if (a == NULL) {
|
|
log("Invalid arguments\n");
|
|
return NULL;
|
|
}
|
|
|
|
ja = json_object_new_object();
|
|
if (ja == NULL) {
|
|
log("Error allocating JSON address object");
|
|
return NULL;
|
|
}
|
|
|
|
jspace = json_object_new_string(a->space);
|
|
if (jspace == NULL) {
|
|
log("Error allocating JSON address space string");
|
|
json_object_put(ja);
|
|
return NULL;
|
|
}
|
|
|
|
jaddr = json_object_new_string(a->addr);
|
|
if (jaddr == NULL) {
|
|
log("Error allocating JSON address string");
|
|
json_object_put(ja);
|
|
return NULL;
|
|
}
|
|
|
|
#if JSON_C_MINOR_VERSION > 12
|
|
int ret;
|
|
|
|
ret = json_object_object_add(ja, "space", jspace);
|
|
if (ret != 0) {
|
|
log("Error adding JSON address space");
|
|
json_object_put(ja);
|
|
return NULL;
|
|
}
|
|
|
|
ret = json_object_object_add(ja, "addr", jaddr);
|
|
if (ret != 0) {
|
|
log("Error adding JSON address");
|
|
json_object_put(ja);
|
|
return NULL;
|
|
}
|
|
#else
|
|
json_object_object_add(ja, "space", jspace);
|
|
json_object_object_add(ja, "addr", jaddr);
|
|
#endif
|
|
return ja;
|
|
}
|
|
|
|
static struct sg_address *json_to_address(json_object *a)
|
|
{
|
|
char *addr = NULL;
|
|
char *space = NULL;
|
|
struct sg_address *sa;
|
|
|
|
if (a == NULL) {
|
|
log("Invalid arguments\n");
|
|
return NULL;
|
|
}
|
|
|
|
json_object_object_foreach(a, key, val) {
|
|
if (json_object_get_type(val) == json_type_string) {
|
|
if (strcmp(key, "space") == 0) {
|
|
space = strdup(json_object_get_string(val));
|
|
}
|
|
if (strcmp(key, "addr") == 0) {
|
|
addr = strdup(json_object_get_string(val));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (space == NULL || addr == NULL) {
|
|
log("Failed to parse JSON address struct");
|
|
free(space);
|
|
free(addr);
|
|
return NULL;
|
|
}
|
|
|
|
sa = sg_address_create(space, addr);
|
|
free(space);
|
|
free(addr);
|
|
return sa;
|
|
}
|
|
|
|
/*
|
|
* Data handling functions
|
|
*
|
|
* Note: aways encode blob as base64.
|
|
*/
|
|
static json_object *data_to_json(const struct sg_data *d)
|
|
{
|
|
json_object *jd;
|
|
json_object *jtag;
|
|
json_object *jblob;
|
|
char *b64;
|
|
|
|
if (d == NULL) {
|
|
log("Invalid arguments\n");
|
|
return NULL;
|
|
}
|
|
|
|
b64 = g_base64_encode(d->blob, d->len);
|
|
if (b64 == NULL) {
|
|
log("Error base64 encoding data entry");
|
|
return NULL;
|
|
}
|
|
|
|
jd = json_object_new_object();
|
|
if (jd == NULL) {
|
|
log("Error allocating JSON data object");
|
|
g_free(b64);
|
|
return NULL;
|
|
}
|
|
|
|
jtag = json_object_new_string(d->tag);
|
|
if (jtag == NULL) {
|
|
log("Error allocating JSON data tag string");
|
|
json_object_put(jd);
|
|
g_free(b64);
|
|
return NULL;
|
|
}
|
|
|
|
jblob = json_object_new_string(b64);
|
|
if (jblob == NULL) {
|
|
log("Error allocating JSON blob");
|
|
json_object_put(jd);
|
|
g_free(b64);
|
|
return NULL;
|
|
}
|
|
g_free(b64);
|
|
|
|
#if JSON_C_MINOR_VERSION > 12
|
|
int ret;
|
|
|
|
ret = json_object_object_add(jd, "tag", jtag);
|
|
if (ret != 0) {
|
|
log("Error adding JSON data tag");
|
|
json_object_put(jd);
|
|
return NULL;
|
|
}
|
|
|
|
ret = json_object_object_add(jd, "blob", jblob);
|
|
if (ret != 0) {
|
|
log("Error adding JSON data blob");
|
|
json_object_put(jd);
|
|
return NULL;
|
|
}
|
|
#else
|
|
json_object_object_add(jd, "tag", jtag);
|
|
json_object_object_add(jd, "blob", jblob);
|
|
#endif
|
|
return jd;
|
|
}
|
|
|
|
static struct sg_data *json_to_data(json_object *d)
|
|
{
|
|
char *tag = NULL;
|
|
char *b64 = NULL;
|
|
uint8_t *blob = NULL;
|
|
size_t len = 0;
|
|
struct sg_data *sd;
|
|
|
|
if (d == NULL) {
|
|
log("Invalid arguments\n");
|
|
return NULL;
|
|
}
|
|
|
|
json_object_object_foreach(d, key, val) {
|
|
if (json_object_get_type(val) == json_type_string) {
|
|
if (strcmp(key, "tag") == 0) {
|
|
tag = strdup(json_object_get_string(val));
|
|
}
|
|
if (strcmp(key, "blob") == 0) {
|
|
b64 = strdup(json_object_get_string(val));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (tag == NULL || b64 == NULL) {
|
|
log("Failed to parse JSON address struct");
|
|
free(tag);
|
|
free(b64);
|
|
return NULL;
|
|
}
|
|
|
|
blob = g_base64_decode(b64, &len);
|
|
if (blob == NULL) {
|
|
log("Error b64 decoding JSON data blob");
|
|
free(tag);
|
|
free(b64);
|
|
return NULL;
|
|
}
|
|
free(b64);
|
|
|
|
sd = sg_data_create(tag,blob,len);
|
|
g_free(blob);
|
|
free(tag);
|
|
return sd;
|
|
}
|
|
|
|
/*
|
|
* node handling functions
|
|
*/
|
|
static json_object *node_to_json(const struct sg_node *n)
|
|
{
|
|
json_object *jn;
|
|
json_object *ja;
|
|
json_object *jdata_array;
|
|
json_object *jdata;
|
|
json_object *jlabel_array;
|
|
json_object *jlabel;
|
|
GList *iter;
|
|
|
|
if (n == NULL) {
|
|
log("Invalid arguments\n");
|
|
return NULL;
|
|
}
|
|
|
|
jn = json_object_new_object();
|
|
if (jn == NULL) {
|
|
log("Error allocating JSON node object\n");
|
|
return NULL;
|
|
}
|
|
|
|
ja = address_to_json(&n->a);
|
|
if (ja == NULL) {
|
|
json_object_put(jn);
|
|
return NULL;
|
|
}
|
|
|
|
jdata_array = json_object_new_array();
|
|
if (jdata_array == NULL) {
|
|
log("Error allocating JSON node data array\n");
|
|
json_object_put(jn);
|
|
json_object_put(ja);
|
|
return NULL;
|
|
}
|
|
|
|
for (iter = g_list_first(n->data); iter && iter->data;
|
|
iter = iter->next) {
|
|
struct sg_data *d = (struct sg_data *)iter->data;
|
|
jdata = data_to_json(d);
|
|
if (jdata != NULL) {
|
|
//XXX silent error pre 0.13.x
|
|
json_object_array_add(jdata_array, jdata);
|
|
}
|
|
}
|
|
|
|
jlabel_array = json_object_new_array();
|
|
if (jlabel_array == NULL) {
|
|
log("Error allocating JSON node label array\n");
|
|
json_object_put(jn);
|
|
json_object_put(ja);
|
|
json_object_put(jdata_array);
|
|
return NULL;
|
|
}
|
|
|
|
for (iter = g_list_first(n->labels); iter && iter->data;
|
|
iter = iter->next) {
|
|
char *l = (char *)iter->data;
|
|
jlabel = json_object_new_string(l);
|
|
if (jlabel != NULL) {
|
|
//XXX silent error pre 0.13.x
|
|
json_object_array_add(jlabel_array, jlabel);
|
|
}
|
|
}
|
|
|
|
#if JSON_C_MINOR_VERSION > 12
|
|
int ret;
|
|
|
|
ret = json_object_object_add(jn, "address", ja);
|
|
if (ret != 0) {
|
|
log("Error adding JSON node address");
|
|
json_object_put(jn);
|
|
json_object_put(ja);
|
|
json_object_put(jdata_array);
|
|
json_object_put(jlabel_array);
|
|
return NULL;
|
|
}
|
|
|
|
ret = json_object_object_add(jn, "data", jdata_array);
|
|
if (ret != 0) {
|
|
log("Error adding JSON node data array");
|
|
json_object_put(jn);
|
|
json_object_put(jdata_array);
|
|
json_object_put(jlabel_array);
|
|
return NULL;
|
|
}
|
|
|
|
ret = json_object_object_add(jn, "labels", jlabel_array);
|
|
if (ret != 0) {
|
|
log("Error adding JSON node data array");
|
|
json_object_put(jn);
|
|
json_object_put(jlabel_array);
|
|
return NULL;
|
|
}
|
|
#else
|
|
json_object_object_add(jn, "address", ja);
|
|
json_object_object_add(jn, "data", jdata_array);
|
|
json_object_object_add(jn, "labels", jlabel_array);
|
|
#endif
|
|
return jn;
|
|
}
|
|
|
|
/*
|
|
* JSON array to GList utility function for strings
|
|
*/
|
|
static GList *json_array_to_string_list(json_object *array)
|
|
{
|
|
GList *strs = NULL;
|
|
int arraylen;
|
|
int i;
|
|
|
|
if (json_object_get_type(array) != json_type_array) {
|
|
log("Non-array passed to array parser\n");
|
|
return NULL;
|
|
}
|
|
|
|
arraylen = json_object_array_length(array);
|
|
|
|
for(i=0; i<arraylen; i++) {
|
|
json_object *tmp = json_object_array_get_idx(array, i);
|
|
const char *str = json_object_get_string(tmp);
|
|
if (str != NULL) {
|
|
char *stmp = strdup(str);
|
|
if (stmp != NULL) {
|
|
strs = g_list_append(strs, stmp);
|
|
}
|
|
}
|
|
}
|
|
|
|
return strs;
|
|
}
|
|
|
|
ARRAY_TO_LIST_TYPE(data);
|
|
|
|
static struct sg_node *json_to_node(json_object *n)
|
|
{
|
|
struct sg_node *sn;
|
|
struct sg_address *a = NULL;
|
|
GList *data = NULL;
|
|
GList *labels = NULL;
|
|
|
|
if (n == NULL) {
|
|
log("Invalid arguments\n");
|
|
return NULL;
|
|
}
|
|
|
|
json_object_object_foreach(n, key, val) {
|
|
if (json_object_get_type(val) == json_type_object &&
|
|
strcmp(key, "address") == 0) {
|
|
a = json_to_address(val);
|
|
}
|
|
|
|
if (json_object_get_type(val) == json_type_array) {
|
|
if (strcmp(key, "data") == 0) {
|
|
data = json_array_to_data_list(val);
|
|
}
|
|
if (strcmp(key, "labels") == 0) {
|
|
labels = json_array_to_string_list(val);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (a == NULL) {
|
|
log("Failed to parse JSON address struct");
|
|
g_list_free_full(data, (void (*)(void *))sg_free_data);
|
|
g_list_free_full(labels, free);
|
|
return NULL;
|
|
}
|
|
|
|
sn = sg_node_create(a->space, a->addr);
|
|
if (!sn) {
|
|
log("Error allocating JSON node");
|
|
sg_free_address(a);
|
|
g_list_free_full(data, (void (*)(void *))sg_free_data);
|
|
g_list_free_full(labels, free);
|
|
return NULL;
|
|
}
|
|
sg_free_address(a);
|
|
|
|
sn->data = data;
|
|
sn->labels = labels;
|
|
|
|
return sn;
|
|
}
|
|
|
|
/*
|
|
* edge handling functions
|
|
*/
|
|
static json_object *edge_to_json(const struct sg_edge *e)
|
|
{
|
|
json_object *je;
|
|
json_object *jsrc;
|
|
json_object *jdest;
|
|
json_object *jlabel_array;
|
|
json_object *jlabel;
|
|
GList *iter;
|
|
|
|
if (e == NULL) {
|
|
log("Invalid arguments\n");
|
|
return NULL;
|
|
}
|
|
|
|
|
|
je = json_object_new_object();
|
|
if (je == NULL) {
|
|
log("Error allocating JSON node object\n");
|
|
return NULL;
|
|
}
|
|
|
|
jsrc = address_to_json(&e->source);
|
|
if (jsrc == NULL) {
|
|
json_object_put(je);
|
|
return NULL;
|
|
}
|
|
|
|
jdest = address_to_json(&e->dest);
|
|
if (jsrc == NULL) {
|
|
json_object_put(je);
|
|
json_object_put(jsrc);
|
|
return NULL;
|
|
}
|
|
|
|
jlabel_array = json_object_new_array();
|
|
if (jlabel_array == NULL) {
|
|
log("Error allocating JSON node label array\n");
|
|
json_object_put(je);
|
|
json_object_put(jsrc);
|
|
json_object_put(jdest);
|
|
return NULL;
|
|
}
|
|
|
|
for (iter = g_list_first(e->labels); iter && iter->data;
|
|
iter = iter->next) {
|
|
char *l = (char *)iter->data;
|
|
jlabel = json_object_new_string(l);
|
|
if (jlabel != NULL) {
|
|
//XXX silent error pre 0.13.x
|
|
json_object_array_add(jlabel_array, jlabel);
|
|
}
|
|
}
|
|
|
|
#if JSON_C_MINOR_VERSION > 12
|
|
int ret;
|
|
|
|
ret = json_object_object_add(je, "source", jsrc);
|
|
if (ret != 0) {
|
|
log("Error adding JSON edge src address");
|
|
json_object_put(je);
|
|
json_object_put(jsrc);
|
|
json_object_put(jdest);
|
|
json_object_put(jlabel_array);
|
|
return NULL;
|
|
}
|
|
|
|
ret = json_object_object_add(je, "dest", jdest);
|
|
if (ret != 0) {
|
|
log("Error adding JSON edge dest address");
|
|
json_object_put(je);
|
|
json_object_put(jdest);
|
|
json_object_put(jlabel_array);
|
|
return NULL;
|
|
}
|
|
|
|
ret = json_object_object_add(je, "labels", jlabel_array);
|
|
if (ret != 0) {
|
|
log("Error adding JSON edge labels array");
|
|
json_object_put(je);
|
|
json_object_put(jlabel_array);
|
|
return NULL;
|
|
}
|
|
|
|
#else
|
|
json_object_object_add(je, "source", jsrc);
|
|
json_object_object_add(je, "dest", jdest);
|
|
json_object_object_add(je, "labels", jlabel_array);
|
|
#endif
|
|
return je;
|
|
}
|
|
|
|
|
|
static struct sg_edge *json_to_edge(json_object *e)
|
|
{
|
|
struct sg_edge *se;
|
|
struct sg_address *src = NULL;
|
|
struct sg_address *dest = NULL;
|
|
GList *labels = NULL;
|
|
|
|
if (e == NULL) {
|
|
log("Invalid arguments\n");
|
|
return NULL;
|
|
}
|
|
|
|
json_object_object_foreach(e, key, val) {
|
|
if (json_object_get_type(val) == json_type_object &&
|
|
strcmp(key, "source") == 0) {
|
|
src = json_to_address(val);
|
|
}
|
|
|
|
if (json_object_get_type(val) == json_type_object &&
|
|
strcmp(key, "dest") == 0) {
|
|
dest = json_to_address(val);
|
|
}
|
|
|
|
if (json_object_get_type(val) == json_type_array) {
|
|
if (strcmp(key, "labels") == 0) {
|
|
labels = json_array_to_string_list(val);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (src == NULL || dest == NULL) {
|
|
log("Failed to parse JSON address structs for edge");
|
|
sg_free_address(src);
|
|
sg_free_address(dest);
|
|
g_list_free_full(labels, free);
|
|
return NULL;
|
|
}
|
|
|
|
se = sg_edge_create_from_addr(src, dest);
|
|
if (!se) {
|
|
log("Error allocating JSON edge");
|
|
sg_free_address(src);
|
|
sg_free_address(dest);
|
|
g_list_free_full(labels, free);
|
|
return NULL;
|
|
}
|
|
sg_free_address(src);
|
|
sg_free_address(dest);
|
|
se->labels = labels;
|
|
|
|
return se;
|
|
}
|
|
|
|
/*
|
|
* graph handling functions
|
|
*/
|
|
|
|
ARRAY_TO_LIST_TYPE(node);
|
|
ARRAY_TO_LIST_TYPE(edge);
|
|
|
|
static json_object *graph_to_json(const struct sg_graph *g)
|
|
{
|
|
json_object *jg;
|
|
json_object *jver;
|
|
json_object *jnode_array;
|
|
json_object *jnode;
|
|
json_object *jedge_array;
|
|
json_object *jedge;
|
|
json_object *jlabel_array;
|
|
json_object *jlabel;
|
|
GList *iter;
|
|
|
|
if (g == NULL) {
|
|
log("Invalid arguments\n");
|
|
return NULL;
|
|
}
|
|
|
|
jg = json_object_new_object();
|
|
if (jg == NULL) {
|
|
log("Error allocating JSON graph object\n");
|
|
return NULL;
|
|
}
|
|
|
|
jver = json_object_new_string(SGRAPH_VERSION);
|
|
if (jver == NULL) {
|
|
log("Error allocating JSON version string");
|
|
json_object_put(jg);
|
|
return NULL;
|
|
}
|
|
|
|
jnode_array = json_object_new_array();
|
|
if (jnode_array == NULL) {
|
|
log("Error allocating JSON graph nodes array\n");
|
|
json_object_put(jg);
|
|
return NULL;
|
|
}
|
|
|
|
for (iter = g_list_first(g->nodes); iter && iter->data;
|
|
iter = iter->next) {
|
|
struct sg_node *n = (struct sg_node *)iter->data;
|
|
jnode = node_to_json(n);
|
|
if (jnode != NULL) {
|
|
//XXX silent error pre 0.13.x
|
|
json_object_array_add(jnode_array, jnode);
|
|
}
|
|
}
|
|
|
|
jedge_array = json_object_new_array();
|
|
if (jedge_array == NULL) {
|
|
log("Error allocating JSON graph edges array\n");
|
|
json_object_put(jg);
|
|
json_object_put(jnode_array);
|
|
return NULL;
|
|
}
|
|
|
|
for (iter = g_list_first(g->edges); iter && iter->data;
|
|
iter = iter->next) {
|
|
struct sg_edge *n = (struct sg_edge *)iter->data;
|
|
jedge = edge_to_json(n);
|
|
if (jedge != NULL) {
|
|
//XXX silent error pre 0.13.x
|
|
json_object_array_add(jedge_array, jedge);
|
|
}
|
|
}
|
|
|
|
jlabel_array = json_object_new_array();
|
|
if (jlabel_array == NULL) {
|
|
log("Error allocating JSON graph label array\n");
|
|
json_object_put(jg);
|
|
json_object_put(jnode_array);
|
|
json_object_put(jedge_array);
|
|
return NULL;
|
|
}
|
|
|
|
for (iter = g_list_first(g->labels); iter && iter->data;
|
|
iter = iter->next) {
|
|
char *l = (char *)iter->data;
|
|
jlabel = json_object_new_string(l);
|
|
if (jlabel != NULL) {
|
|
//XXX silent error pre 0.13.x
|
|
json_object_array_add(jlabel_array, jlabel);
|
|
}
|
|
}
|
|
|
|
#if JSON_C_MINOR_VERSION > 12
|
|
int ret;
|
|
|
|
ret = json_object_object_add(jg, "nodes", jnode_array);
|
|
if (ret != 0) {
|
|
log("Error adding JSON graph nodes array");
|
|
json_object_put(jg);
|
|
json_object_put(jnode_array);
|
|
json_object_put(jedge_array);
|
|
json_object_put(jlabel_array);
|
|
return NULL;
|
|
}
|
|
|
|
ret = json_object_object_add(jg, "edges", jedge_array);
|
|
if (ret != 0) {
|
|
log("Error adding JSON graph edges array");
|
|
json_object_put(jg);
|
|
json_object_put(jedge_array);
|
|
json_object_put(jlabel_array);
|
|
return NULL;
|
|
}
|
|
|
|
ret = json_object_object_add(jg, "labels", jlabel_array);
|
|
if (ret != 0) {
|
|
log("Error adding JSON graph labels array");
|
|
json_object_put(jg);
|
|
json_object_put(jlabel_array);
|
|
return NULL;
|
|
}
|
|
|
|
ret = json_object_object_add(jg, "version", jver);
|
|
if (ret != 0) {
|
|
log("Error adding JSON version");
|
|
json_object_put(jg);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
json_object_object_add(jg, "version", jver);
|
|
json_object_object_add(jg, "nodes", jnode_array);
|
|
json_object_object_add(jg, "edges", jedge_array);
|
|
json_object_object_add(jg, "labels", jlabel_array);
|
|
#endif
|
|
return jg;
|
|
}
|
|
|
|
static struct sg_graph *json_to_graph(json_object *g)
|
|
{
|
|
struct sg_graph *sg;
|
|
GList *nodes = NULL;
|
|
GList *edges = NULL;
|
|
GList *labels = NULL;
|
|
|
|
if (g == NULL) {
|
|
log("Invalid arguments\n");
|
|
return NULL;
|
|
}
|
|
|
|
json_object_object_foreach(g, key, val) {
|
|
if (json_object_get_type(val) == json_type_array) {
|
|
if (strcmp(key, "nodes") == 0) {
|
|
nodes = json_array_to_node_list(val);
|
|
}
|
|
if (strcmp(key, "edges") == 0) {
|
|
edges = json_array_to_edge_list(val);
|
|
}
|
|
if (strcmp(key, "labels") == 0) {
|
|
labels = json_array_to_string_list(val);
|
|
}
|
|
}
|
|
}
|
|
|
|
sg = sg_graph_create();
|
|
if (!sg) {
|
|
log("Error allocating graph");
|
|
g_list_free_full(nodes, (void (*)(void *))sg_free_node);
|
|
g_list_free_full(edges, (void (*)(void *))sg_free_edge);
|
|
g_list_free_full(labels, free);
|
|
return NULL;
|
|
}
|
|
sg->nodes = nodes;
|
|
sg->edges = edges;
|
|
sg->labels = labels;
|
|
|
|
return sg;
|
|
}
|
|
|
|
char *sg_graph_to_string(struct sg_graph *g)
|
|
{
|
|
char *tmp;
|
|
|
|
if (g == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
json_object *jg = graph_to_json(g);
|
|
tmp = strdup(json_object_to_json_string(jg));
|
|
json_object_put(jg);
|
|
return tmp;
|
|
}
|
|
|
|
struct sg_graph *sg_string_to_graph(const char *str)
|
|
{
|
|
if (str == NULL) {
|
|
return NULL;
|
|
}
|
|
json_object *json = json_tokener_parse(str);
|
|
struct sg_graph *ret = json_to_graph(json);
|
|
json_object_put(json);
|
|
return ret;
|
|
}
|