Files
bongo/src/libs/json/json.c
T
Mario Fetka 92e0ba117d
Debian Trixie package bundle / packages (push) Failing after 14m43s
Bound external collector queue growth
2026-07-23 22:15:21 +02:00

1058 lines
25 KiB
C

/****************************************************************************
* <Novell-copyright>
* Copyright (c) 2006 Novell, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public License
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, contact Novell, Inc.
*
* To contact Novell about this file by physical or electronic mail, you
* may find current contact information at www.novell.com.
* </Novell-copyright>
****************************************************************************/
// Parts Copyright (C) 2007 Alex Hudson. See COPYING for details.
#include <config.h>
#include <bongojson.h>
#include <assert.h>
#include <inttypes.h>
#include <limits.h>
#define PRETTY_JSON 1
static void BongoJsonArrayToStringBuilderInternal(GArray *array, BongoStringBuilder *sb, int depth);
static void BongoJsonObjectToStringBuilderInternal(BongoJsonObject *object, BongoStringBuilder *sb, int depth);
BongoJsonNode *
BongoJsonJPath(BongoJsonNode *root, const char *path)
{
char rule[50];
char *select;
const char *nextrule;
size_t rulelen;
BongoJsonResult result;
nextrule = strchr(path, '/');
if (! nextrule) {
rulelen = min(strlen(path), sizeof(rule) - 1);
memcpy(rule, path, rulelen);
} else {
rulelen = min((size_t)(nextrule - path), sizeof(rule) - 1);
memcpy(rule, path, rulelen);
if (rulelen < strlen(path)) {
// there's another rule after this
nextrule++;
}
}
rule[rulelen] = 0;
switch(rule[0]) {
case 'b':
if (root->type == BONGO_JSON_BOOL) return root;
break;
case 'd':
if (root->type == BONGO_JSON_DOUBLE) return root;
break;
case 's':
if (root->type == BONGO_JSON_STRING) return root;
break;
case 'i':
if (root->type == BONGO_JSON_INT) return root;
break;
case 'o':
if (root->type != BONGO_JSON_OBJECT) break;
if (strlen(rule)>2) {
BongoJsonNode *node;
select = rule + 2;
result = BongoJsonObjectGet(root->value.objectVal, select, &node);
if (result != BONGO_JSON_OK) break;
if (nextrule) {
return BongoJsonJPath(node, nextrule);
} else {
return node;
}
}
return root;
break;
case 'a':
if (root->type != BONGO_JSON_ARRAY) break;
if (strlen(rule)>2) {
BongoJsonNode *node;
select = rule + 2;
node = BongoJsonArrayGet(root->value.arrayVal, atoi(select));
if (! node) break;
if (nextrule) {
return BongoJsonJPath(node, nextrule);
} else {
return node;
}
}
return root;
break;
default:
// unknown rule!!
return NULL;
break;
}
return NULL;
}
BongoJsonResult
BongoJsonJPathGetObject(BongoJsonNode *n, const char *path, BongoJsonObject **val) {
BongoJsonNode *result = BongoJsonJPath(n, path);
if (!result) return BONGO_JSON_NOT_FOUND;
if (result->type == BONGO_JSON_OBJECT) {
*val = BongoJsonNodeAsObject(result);
return BONGO_JSON_OK;
}
return BONGO_JSON_BAD_TYPE;
}
BongoJsonResult
BongoJsonJPathGetArray(BongoJsonNode *n, const char *path, GArray **val) {
BongoJsonNode *result = BongoJsonJPath(n, path);
if (!result) return BONGO_JSON_NOT_FOUND;
if (result->type == BONGO_JSON_ARRAY) {
*val = BongoJsonNodeAsArray(result);
return BONGO_JSON_OK;
}
return BONGO_JSON_BAD_TYPE;
}
BongoJsonResult
BongoJsonJPathGetBool(BongoJsonNode *n, const char *path, BOOL *val) {
BongoJsonNode *result = BongoJsonJPath(n, path);
if (!result) return BONGO_JSON_NOT_FOUND;
if (result->type == BONGO_JSON_BOOL) {
*val = BongoJsonNodeAsBool(result);
return BONGO_JSON_OK;
}
return BONGO_JSON_BAD_TYPE;
}
BongoJsonResult
BongoJsonJPathGetInt(BongoJsonNode *n, const char *path, int *val) {
BongoJsonNode *result = BongoJsonJPath(n, path);
if (!result) return BONGO_JSON_NOT_FOUND;
if (result->type == BONGO_JSON_INT &&
BongoJsonNodeAsInt(result) >= INT_MIN &&
BongoJsonNodeAsInt(result) <= INT_MAX) {
*val = (int)BongoJsonNodeAsInt(result);
return BONGO_JSON_OK;
}
return BONGO_JSON_BAD_TYPE;
}
BongoJsonResult
BongoJsonJPathGetInt64(BongoJsonNode *n, const char *path, int64_t *val) {
BongoJsonNode *result = BongoJsonJPath(n, path);
if (!result) return BONGO_JSON_NOT_FOUND;
if (result->type == BONGO_JSON_INT) {
*val = BongoJsonNodeAsInt(result);
return BONGO_JSON_OK;
}
return BONGO_JSON_BAD_TYPE;
}
BongoJsonResult
BongoJsonJPathGetDouble(BongoJsonNode *n, const char *path, double *val) {
BongoJsonNode *result = BongoJsonJPath(n, path);
if (!result) return BONGO_JSON_NOT_FOUND;
if (result->type == BONGO_JSON_DOUBLE) {
*val = BongoJsonNodeAsDouble(result);
return BONGO_JSON_OK;
}
return BONGO_JSON_BAD_TYPE;
}
BongoJsonResult
BongoJsonJPathGetFloat(BongoJsonNode *n, const char *path, float *val) {
BongoJsonNode *result = BongoJsonJPath(n, path);
if (!result) return BONGO_JSON_NOT_FOUND;
if (result->type == BONGO_JSON_DOUBLE) {
double t = BongoJsonNodeAsDouble(result);
*val = (float)t;
return BONGO_JSON_OK;
}
return BONGO_JSON_BAD_TYPE;
}
BongoJsonResult
BongoJsonJPathGetString(BongoJsonNode *n, const char *path, char **val) {
// caller must free the memory allocated
BongoJsonNode *result = BongoJsonJPath(n, path);
if (!result) return BONGO_JSON_NOT_FOUND;
if (result->type == BONGO_JSON_STRING) {
*val = MemStrdup(BongoJsonNodeAsString(result));
return BONGO_JSON_OK;
}
return BONGO_JSON_BAD_TYPE;
}
BongoJsonNode *
BongoJsonNodeNewNull(void)
{
BongoJsonNode *node = MemMalloc0(sizeof(BongoJsonNode));
node->type = BONGO_JSON_NULL;
return node;
}
BongoJsonNode *
BongoJsonNodeNewObject(BongoJsonObject *val)
{
BongoJsonNode *node = MemMalloc0(sizeof(BongoJsonNode));
node->type = BONGO_JSON_OBJECT;
node->value.objectVal = val;
return node;
}
BongoJsonNode *
BongoJsonNodeNewArray(GArray *val)
{
BongoJsonNode *node = MemMalloc0(sizeof(BongoJsonNode));
node->type = BONGO_JSON_ARRAY;
node->value.arrayVal = val;
return node;
}
BongoJsonNode *
BongoJsonNodeNewBool(BOOL val)
{
BongoJsonNode *node = MemMalloc0(sizeof(BongoJsonNode));
node->type = BONGO_JSON_BOOL;
node->value.boolVal = val;
return node;
}
BongoJsonNode *
BongoJsonNodeNewDouble(double val)
{
BongoJsonNode *node = MemMalloc0(sizeof(BongoJsonNode));
node->type = BONGO_JSON_DOUBLE;
node->value.doubleVal = val;
return node;
}
BongoJsonNode *
BongoJsonNodeNewInt(int64_t val)
{
BongoJsonNode *node = MemMalloc0(sizeof(BongoJsonNode));
node->type = BONGO_JSON_INT;
node->value.intVal = val;
return node;
}
BongoJsonNode *
BongoJsonNodeNewString(const char *val)
{
BongoJsonNode *node = MemMalloc0(sizeof(BongoJsonNode));
node->type = BONGO_JSON_STRING;
node->value.stringVal = MemStrdup(val);
return node;
}
BongoJsonNode *
BongoJsonNodeNewStringGive(char *val)
{
BongoJsonNode *node = MemMalloc0(sizeof(BongoJsonNode));
node->type = BONGO_JSON_STRING;
node->value.stringVal = val;
return node;
}
BongoJsonNode *
BongoJsonNodeDup(BongoJsonNode *old)
{
BongoJsonNode *node = MemMalloc0(sizeof(BongoJsonNode));
node->type = old->type;
switch(old->type) {
case BONGO_JSON_NULL :
break;
case BONGO_JSON_OBJECT :
BongoJsonNodeAsObject(node) = BongoJsonObjectDup(BongoJsonNodeAsObject(old));
break;
case BONGO_JSON_ARRAY :
BongoJsonNodeAsArray(node) = BongoJsonArrayDup(BongoJsonNodeAsArray(old));
break;
case BONGO_JSON_BOOL :
BongoJsonNodeAsBool(node) = BongoJsonNodeAsBool(old);
break;
case BONGO_JSON_DOUBLE :
BongoJsonNodeAsDouble(node) = BongoJsonNodeAsDouble(old);
break;
case BONGO_JSON_INT :
BongoJsonNodeAsInt(node) = BongoJsonNodeAsInt(old);
break;
case BONGO_JSON_STRING :
BongoJsonNodeAsString(node) = MemStrdup(BongoJsonNodeAsString(old));
break;
}
return node;
}
BOOL
BongoJsonNodeEqual(BongoJsonNode *left, BongoJsonNode *right)
{
unsigned int index;
if (left == right)
return TRUE;
if (!left || !right || left->type != right->type)
return FALSE;
switch (left->type) {
case BONGO_JSON_NULL:
return TRUE;
case BONGO_JSON_OBJECT: {
BongoJsonObject *leftObject = BongoJsonNodeAsObject(left);
BongoJsonObject *rightObject = BongoJsonNodeAsObject(right);
BongoJsonObjectIter iterator;
if (BongoHashtableSize((BongoHashtable *)leftObject) !=
BongoHashtableSize((BongoHashtable *)rightObject))
return FALSE;
for (BongoJsonObjectIterFirst(leftObject, &iterator);
iterator.key != NULL;
BongoJsonObjectIterNext(leftObject, &iterator)) {
BongoJsonNode *rightValue = NULL;
if (BongoJsonObjectGet(rightObject, iterator.key, &rightValue) !=
BONGO_JSON_OK ||
!BongoJsonNodeEqual(iterator.value, rightValue))
return FALSE;
}
return TRUE;
}
case BONGO_JSON_ARRAY: {
GArray *leftArray = BongoJsonNodeAsArray(left);
GArray *rightArray = BongoJsonNodeAsArray(right);
if (leftArray->len != rightArray->len)
return FALSE;
for (index = 0; index < leftArray->len; index++) {
if (!BongoJsonNodeEqual(BongoJsonArrayGet(leftArray, index),
BongoJsonArrayGet(rightArray, index)))
return FALSE;
}
return TRUE;
}
case BONGO_JSON_BOOL:
return BongoJsonNodeAsBool(left) == BongoJsonNodeAsBool(right);
case BONGO_JSON_DOUBLE:
return BongoJsonNodeAsDouble(left) == BongoJsonNodeAsDouble(right);
case BONGO_JSON_INT:
return BongoJsonNodeAsInt(left) == BongoJsonNodeAsInt(right);
case BONGO_JSON_STRING:
return strcmp(BongoJsonNodeAsString(left),
BongoJsonNodeAsString(right)) == 0;
}
return FALSE;
}
char *
BongoJsonNodeToString(BongoJsonNode *node)
{
BongoStringBuilder sb;
BongoStringBuilderInit(&sb);
BongoJsonNodeToStringBuilder(node, &sb);
return sb.value;
}
#if PRETTY_JSON
static void
NewLine(BongoStringBuilder *sb, int depth)
{
int i;
BongoStringBuilderAppendChar(sb, '\n');
for (i = 0; i < depth; i++) {
BongoStringBuilderAppendChar(sb, '\t');
}
}
#else
#define NewLine(s, n)
#endif
static void
BongoJsonNodeToStringBuilderInternal(BongoJsonNode *node, BongoStringBuilder *sb, int depth)
{
switch(node->type) {
case BONGO_JSON_NULL :
BongoStringBuilderAppend(sb, "null");
break;
case BONGO_JSON_OBJECT :
BongoJsonObjectToStringBuilderInternal(BongoJsonNodeAsObject(node), sb, depth);
break;
case BONGO_JSON_ARRAY :
BongoJsonArrayToStringBuilderInternal(BongoJsonNodeAsArray(node), sb, depth);
break;
case BONGO_JSON_BOOL :
BongoStringBuilderAppend(sb, BongoJsonNodeAsBool(node) ? "true" : "false");
break;
case BONGO_JSON_DOUBLE :
BongoStringBuilderAppendF(sb, "%f", BongoJsonNodeAsDouble(node));
break;
case BONGO_JSON_INT :
BongoStringBuilderAppendF(sb, "%" PRId64,
BongoJsonNodeAsInt(node));
break;
case BONGO_JSON_STRING :
BongoJsonQuoteStringToStringBuilder(BongoJsonNodeAsString(node), sb);
break;
}
}
void
BongoJsonNodeToStringBuilder(BongoJsonNode *node, BongoStringBuilder *sb)
{
BongoJsonNodeToStringBuilderInternal(node, sb, 0);
}
void
BongoJsonNodeFree(BongoJsonNode *node)
{
switch(node->type) {
case BONGO_JSON_OBJECT :
BongoJsonObjectFree(node->value.objectVal);
break;
case BONGO_JSON_ARRAY :
BongoJsonArrayFree(node->value.arrayVal);
break;
case BONGO_JSON_STRING :
MemFree(node->value.stringVal);
break;
default :
break;
}
BongoJsonNodeFreeSteal(node);
}
void
BongoJsonNodeFreeSteal(BongoJsonNode *node)
{
MemFree(node);
}
static BongoJsonResult
BongoJsonLookup(BongoJsonNode *node, const char *name, BongoJsonNode **out)
{
char *endp;
unsigned int i;
switch(node->type) {
case BONGO_JSON_ARRAY :
i = strtol(name, &endp, 10);
if (*endp != '\0') {
return BONGO_JSON_BAD_KEY;
} else if (i >= BongoJsonNodeAsArray(node)->len) {
return BONGO_JSON_BOUNDS_ERROR;
}
*out = BongoJsonArrayGet(BongoJsonNodeAsArray(node), i);
return BONGO_JSON_OK;
case BONGO_JSON_OBJECT :
return BongoJsonObjectGet(BongoJsonNodeAsObject(node), name, out);
default :
return BONGO_JSON_BAD_KEY;
}
}
static BongoJsonResult
BongoJsonNodeResolveSplit(BongoJsonNode *node, char **split, int n, BongoJsonNode **out)
{
int i;
*out = NULL;
if (n < 1) {
*out = node;
return BONGO_JSON_OK;
}
for (i = 0; i < n; i++) {
BongoJsonResult res;
if ((res = BongoJsonLookup(node, split[i], &node)) != BONGO_JSON_OK) {
return res;
}
}
*out = node;
return BONGO_JSON_OK;
}
BongoJsonResult
BongoJsonNodeResolve(BongoJsonNode *node, const char *path, BongoJsonNode **out)
{
BongoJsonResult res;
char *copy;
char *split[20];
int n;
copy = MemStrdup(path);
n = BongoStringSplit(copy, '/', split, 20);
res = BongoJsonNodeResolveSplit(node, split, n, out);
MemFree(copy);
return res;
}
/*** BongoJsonArray **/
GArray *
BongoJsonArrayDup(GArray *old)
{
GArray *array;
unsigned int i;
array = g_array_sized_new(FALSE, FALSE, sizeof(BongoJsonNode*), old->len);
for (i = 0; i < old->len; i++) {
BongoJsonNode *node;
node = BongoJsonNodeDup(BongoJsonArrayGet(old, i));
BongoJsonArrayAppend(array, node);
}
return array;
}
void
BongoJsonArrayAppend(GArray *array, BongoJsonNode *node)
{
g_array_append_val(array, node);
}
void
BongoJsonArrayRemove(GArray *array, int i)
{
BongoJsonNode *node;
node = BongoJsonArrayGet(array, i);
g_array_remove_index(array, i);
BongoJsonNodeFree(node);
}
void
BongoJsonArrayRemoveSteal(GArray *array, int i)
{
g_array_remove_index(array, i);
}
char *
BongoJsonArrayToString(GArray *array)
{
BongoStringBuilder sb;
BongoStringBuilderInit(&sb);
BongoJsonArrayToStringBuilder(array, &sb);
return sb.value;
}
static void
BongoJsonArrayToStringBuilderInternal(GArray *array, BongoStringBuilder *sb, int depth)
{
unsigned int i;
BOOL first;
BongoStringBuilderAppendChar(sb, '[');
first = TRUE;
for (i = 0; i < array->len; i++) {
if (!first) {
BongoStringBuilderAppendChar(sb, ',');
} else {
first = FALSE;
}
BongoJsonNodeToStringBuilderInternal(BongoJsonArrayGet(array, i), sb, depth + 1);
}
BongoStringBuilderAppendChar(sb, ']');
}
void
BongoJsonArrayToStringBuilder(GArray *array, BongoStringBuilder *sb)
{
BongoJsonArrayToStringBuilderInternal(array, sb, 0);
}
void
BongoJsonArrayFree(GArray *array)
{
unsigned int i;
for (i = 0; i < array->len; i++) {
BongoJsonNode *node;
node = BongoJsonArrayGet(array, i);
BongoJsonNodeFree(node);
}
g_array_free(array, TRUE);
}
/*** BongoJsonObject ***/
static void
KeyFree(void *data)
{
MemFree(data);
}
static void
JsonNodeFreeCallback(void *data)
{
BongoJsonNodeFree(data);
}
BongoJsonObject *
BongoJsonObjectNew(void)
{
BongoHashtable *obj = BongoHashtableCreateFull(15,
BongoStringHash,
BongoStringCompare,
KeyFree,
JsonNodeFreeCallback);
return (BongoJsonObject *)obj;
}
BongoJsonObject *
BongoJsonObjectDup(BongoJsonObject *old)
{
BongoJsonObject *obj;
BongoJsonObjectIter iter;
obj = BongoJsonObjectNew();
for (BongoJsonObjectIterFirst(old, &iter);
iter.key != NULL;
BongoJsonObjectIterNext(old, &iter)) {
/* BongoJsonObjectPut() takes a copy of the key itself. */
BongoJsonObjectPut(obj, iter.key, BongoJsonNodeDup(iter.value));
}
return obj;
}
void
BongoJsonObjectFree(BongoJsonObject *obj)
{
BongoHashtableDelete((BongoHashtable*)obj);
}
void
BongoJsonObjectToStringBuilderInternal(BongoJsonObject *obj, BongoStringBuilder *sb, int depth)
{
BongoJsonObjectIter iter;
BOOL first;
NewLine(sb, depth);
BongoStringBuilderAppendChar(sb, '{');
first = TRUE;
for (BongoJsonObjectIterFirst(obj, &iter);
iter.key != NULL;
BongoJsonObjectIterNext(obj, &iter)) {
if (!first) {
BongoStringBuilderAppendChar(sb, ',');
} else {
first = FALSE;
}
NewLine(sb, depth + 1);
BongoJsonQuoteStringToStringBuilder(iter.key, sb);
BongoStringBuilderAppendChar(sb, ':');
BongoJsonNodeToStringBuilderInternal(iter.value, sb, depth + 1);
}
NewLine(sb, depth);
BongoStringBuilderAppendChar(sb, '}');
}
void
BongoJsonObjectToStringBuilder(BongoJsonObject *obj, BongoStringBuilder *sb)
{
BongoJsonObjectToStringBuilderInternal(obj, sb, 0);
}
char *
BongoJsonObjectToString(BongoJsonObject *obj)
{
BongoStringBuilder sb;
BongoStringBuilderInit(&sb);
BongoJsonObjectToStringBuilder(obj, &sb);
return sb.value;
}
BOOL
BongoJsonObjectIterFirst(BongoJsonObject *obj, BongoJsonObjectIter *iter)
{
BOOL ret;
ret = BongoHashtableIterFirst((BongoHashtable*)obj, &iter->iter);
iter->key = (const char *)iter->iter.key;
iter->value = (BongoJsonNode *)iter->iter.value;
return ret;
}
BOOL
BongoJsonObjectIterNext(BongoJsonObject *obj, BongoJsonObjectIter *iter)
{
BOOL ret;
ret = BongoHashtableIterNext((BongoHashtable*)obj, &iter->iter);
iter->key = (const char *)iter->iter.key;
iter->value = (BongoJsonNode *)iter->iter.value;
return ret;
}
BongoJsonResult
BongoJsonObjectGet(BongoJsonObject *obj, const char *key, BongoJsonNode **node)
{
*node = BongoHashtableGet((BongoHashtable *)obj, key);
if (*node) {
return BONGO_JSON_OK;
} else {
return BONGO_JSON_NOT_FOUND;
}
}
BongoJsonResult
BongoJsonObjectGetObject(BongoJsonObject *obj, const char *key, BongoJsonObject **val)
{
BongoJsonNode *node;
BongoJsonResult res;
res = BongoJsonObjectGet(obj, key, &node);
if (res != BONGO_JSON_OK) {
*val = NULL;
return res;
}
if (node->type != BONGO_JSON_OBJECT) {
*val = NULL;
return BONGO_JSON_BAD_TYPE;
}
*val = node->value.objectVal;
return BONGO_JSON_OK;
}
BongoJsonResult
BongoJsonObjectGetArray(BongoJsonObject *obj, const char *key, GArray **val)
{
BongoJsonNode *node;
BongoJsonResult res;
res = BongoJsonObjectGet(obj, key, &node);
if (res != BONGO_JSON_OK) {
*val = NULL;
return res;
}
if (node->type != BONGO_JSON_ARRAY) {
*val = NULL;
return BONGO_JSON_BAD_TYPE;
}
*val = node->value.arrayVal;
return BONGO_JSON_OK;
}
BongoJsonResult
BongoJsonObjectGetBool(BongoJsonObject *obj, const char *key, BOOL *val)
{
BongoJsonNode *node;
BongoJsonResult res;
res = BongoJsonObjectGet(obj, key, &node);
if (res != BONGO_JSON_OK) {
*val = FALSE;
return res;
}
if (node->type != BONGO_JSON_BOOL) {
*val = FALSE;
return BONGO_JSON_BAD_TYPE;
}
*val = node->value.boolVal;
return BONGO_JSON_OK;
}
BongoJsonResult
BongoJsonObjectGetDouble(BongoJsonObject *obj, const char *key, double *val)
{
BongoJsonNode *node;
BongoJsonResult res;
res = BongoJsonObjectGet(obj, key, &node);
if (res != BONGO_JSON_OK) {
*val = 0.0;
return res;
}
if (node->type != BONGO_JSON_DOUBLE) {
*val = 0.0;
return BONGO_JSON_BAD_TYPE;
}
*val = node->value.doubleVal;
return BONGO_JSON_OK;
}
BongoJsonResult
BongoJsonObjectGetInt(BongoJsonObject *obj, const char *key, int *val)
{
BongoJsonNode *node;
BongoJsonResult res;
res = BongoJsonObjectGet(obj, key, &node);
if (res != BONGO_JSON_OK) {
*val = 0;
return res;
}
if (node->type != BONGO_JSON_INT ||
node->value.intVal < INT_MIN || node->value.intVal > INT_MAX) {
*val = 0;
return BONGO_JSON_BAD_TYPE;
}
*val = (int)node->value.intVal;
return BONGO_JSON_OK;
}
BongoJsonResult
BongoJsonObjectGetInt64(BongoJsonObject *obj, const char *key, int64_t *val)
{
BongoJsonNode *node;
BongoJsonResult res;
res = BongoJsonObjectGet(obj, key, &node);
if (res != BONGO_JSON_OK) {
*val = 0;
return res;
}
if (node->type != BONGO_JSON_INT) {
*val = 0;
return BONGO_JSON_BAD_TYPE;
}
*val = node->value.intVal;
return BONGO_JSON_OK;
}
BongoJsonResult
BongoJsonObjectGetString(BongoJsonObject *obj, const char *key, const char **val)
{
BongoJsonNode *node;
BongoJsonResult res;
res = BongoJsonObjectGet(obj, key, &node);
if (res != BONGO_JSON_OK) {
*val = NULL;
return res;
}
if (node->type != BONGO_JSON_STRING) {
*val = NULL;
return BONGO_JSON_BAD_TYPE;
}
*val = node->value.stringVal;
return BONGO_JSON_OK;
}
BongoJsonResult
BongoJsonObjectPut(BongoJsonObject *obj, const char *key, BongoJsonNode *node)
{
assert(node);
BongoHashtablePut((BongoHashtable*)obj, MemStrdup(key), node);
return BONGO_JSON_OK;
}
BongoJsonResult
BongoJsonObjectPutNull(BongoJsonObject *obj, const char *key)
{
BongoJsonNode *node;
node = BongoJsonNodeNewNull();
BongoHashtablePut((BongoHashtable*)obj, MemStrdup(key), node);
return BONGO_JSON_OK;
}
BongoJsonResult
BongoJsonObjectPutObject(BongoJsonObject *obj, const char *key, BongoJsonObject *val)
{
BongoJsonNode *node;
node = BongoJsonNodeNewObject(val);
BongoHashtablePut((BongoHashtable*)obj, MemStrdup(key), node);
return BONGO_JSON_OK;
}
BongoJsonResult
BongoJsonObjectPutArray(BongoJsonObject *obj, const char *key, GArray *val)
{
BongoJsonNode *node;
node = BongoJsonNodeNewArray(val);
BongoHashtablePut((BongoHashtable*)obj, MemStrdup(key), node);
return BONGO_JSON_OK;
}
BongoJsonResult
BongoJsonObjectPutBool(BongoJsonObject *obj, const char *key, BOOL val)
{
BongoJsonNode *node;
node = BongoJsonNodeNewBool(val);
BongoHashtablePut((BongoHashtable*)obj, MemStrdup(key), node);
return BONGO_JSON_OK;
}
BongoJsonResult
BongoJsonObjectPutDouble(BongoJsonObject *obj, const char *key, double val)
{
BongoJsonNode *node;
node = BongoJsonNodeNewDouble(val);
BongoHashtablePut((BongoHashtable*)obj, MemStrdup(key), node);
return BONGO_JSON_OK;
}
BongoJsonResult
BongoJsonObjectPutInt(BongoJsonObject *obj, const char *key, int val)
{
BongoJsonNode *node;
node = BongoJsonNodeNewInt(val);
BongoHashtablePut((BongoHashtable*)obj, MemStrdup(key), node);
return BONGO_JSON_OK;
}
BongoJsonResult
BongoJsonObjectPutString(BongoJsonObject *obj, const char *key, const char *val)
{
BongoJsonNode *node;
node = BongoJsonNodeNewString(val);
BongoHashtablePut((BongoHashtable*)obj, MemStrdup(key), node);
return BONGO_JSON_OK;
}
BongoJsonResult
BongoJsonObjectRemove(BongoJsonObject *obj, const char *key)
{
BongoHashtableRemove((BongoHashtable*)obj, key);
return BONGO_JSON_OK;
}
BongoJsonResult
BongoJsonObjectRemoveSteal(BongoJsonObject *obj, const char *key)
{
BongoHashtableRemoveFull((BongoHashtable*)obj, key, TRUE, FALSE);
return BONGO_JSON_OK;
}
BongoJsonResult
BongoJsonObjectResolve(BongoJsonObject *obj, const char *path, BongoJsonNode **out)
{
BongoJsonNode *node;
BongoJsonResult res;
char *copy;
char *split[20];
int n;
*out = NULL;
copy = MemStrdup(path);
n = BongoStringSplit(copy, '/', split, 20);
if (n < 1) {
MemFree(copy);
return BONGO_JSON_BAD_KEY;
}
res = BongoJsonObjectGet(obj, split[0], &node);
if (!node) {
MemFree(copy);
return BONGO_JSON_NOT_FOUND;
}
if (n < 2) {
*out = node;
MemFree(copy);
return res;
}
res = BongoJsonNodeResolveSplit(node, split + 1, n - 1, out);
MemFree(copy);
return res;
}