mirror of
https://github.com/majonezz/solarlife.git
synced 2026-03-28 18:42:34 +01:00
888 lines
19 KiB
C
888 lines
19 KiB
C
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include "json.h"
|
|
|
|
|
|
/*
|
|
read and traverse
|
|
*/
|
|
|
|
static void skipWhiteSpaces(const char** pstr)
|
|
{
|
|
while (isspace(**pstr))
|
|
++*pstr;
|
|
}
|
|
|
|
static void fillError(const char* str, char* errorBuf, int errorBufSize)
|
|
{
|
|
static const char errorPrefix[] = "Parse error here: ";
|
|
static const int errorPrefixLen = sizeof(errorPrefix);
|
|
|
|
snprintf(errorBuf, errorBufSize, "%s", errorPrefix);
|
|
snprintf(errorBuf + errorPrefixLen - 1, errorBufSize - errorPrefixLen, "%s", str);
|
|
}
|
|
|
|
static int parseChar(const char **source, char c)
|
|
{
|
|
skipWhiteSpaces(source);
|
|
if (!**source || tolower(**source) != tolower(c))
|
|
return -1;
|
|
|
|
++*source;
|
|
return 0;
|
|
}
|
|
|
|
static int createStringCopy(const char *source, int sourceLen, char **target)
|
|
{
|
|
if (sourceLen == -1)
|
|
sourceLen = strlen(source);
|
|
|
|
*target = malloc(sourceLen + 1);
|
|
|
|
if (!*target)
|
|
return -1;
|
|
|
|
memcpy(*target, source, sourceLen);
|
|
(*target)[sourceLen] = '\0';
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int parseQuotedString(const char **source, char **target)
|
|
{
|
|
const char *begin;
|
|
int strLen;
|
|
|
|
skipWhiteSpaces(source);
|
|
if (parseChar(source, '"') != 0)
|
|
return -1;
|
|
|
|
begin = *source;
|
|
while (**source != '"' && **source)
|
|
++*source;
|
|
|
|
if (!**source)
|
|
return -1;
|
|
|
|
strLen = *source - begin;
|
|
if (createStringCopy(begin, strLen, target) != 0)
|
|
return -1;
|
|
|
|
++*source;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int matchString(const char **source, const char *pattern)
|
|
{
|
|
while (*pattern)
|
|
{
|
|
if (parseChar(source, *pattern) != 0)
|
|
return -1;
|
|
++pattern;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int reallocObject(struct JsonVal *val)
|
|
{
|
|
if (!(val->u.object.keys = realloc(
|
|
val->u.object.keys,
|
|
(val->u.object.len + 1) * sizeof(*val->u.object.keys))))
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
if (!(val->u.object.values = realloc(
|
|
val->u.object.values,
|
|
(val->u.object.len + 1) * sizeof(*val->u.object.values))))
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
val->u.object.len++;
|
|
return 0;
|
|
}
|
|
|
|
static int reallocArray(struct JsonVal *val)
|
|
{
|
|
if (!(val->u.array.values = realloc(
|
|
val->u.array.values,
|
|
(val->u.array.len + 1) * sizeof(*val->u.array.values))))
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
val->u.array.len++;
|
|
return 0;
|
|
}
|
|
|
|
static int parseObject(const char **source, struct JsonVal *value);
|
|
static int parseValue(const char **source, struct JsonVal *val);
|
|
|
|
static int parseArrayEntry(const char **source, struct JsonVal *val)
|
|
{
|
|
if(reallocArray(val) != 0)
|
|
return -1;
|
|
|
|
skipWhiteSpaces(source);
|
|
return parseValue(source, val->u.array.values + val->u.array.len - 1);
|
|
}
|
|
|
|
static int parseArray(const char **source, struct JsonVal *value)
|
|
{
|
|
int finished = 0;
|
|
|
|
value->type = jsonArrayT;
|
|
value->u.array.values = NULL;
|
|
value->u.array.len = 0;
|
|
|
|
if (parseChar(source, '[') != 0)
|
|
return -1;
|
|
|
|
skipWhiteSpaces(source);
|
|
if (**source == ']')
|
|
{
|
|
++*source;
|
|
return 0;
|
|
}
|
|
|
|
while (**source)
|
|
{
|
|
skipWhiteSpaces(source);
|
|
if (parseArrayEntry(source, value) != 0)
|
|
return -1;
|
|
skipWhiteSpaces(source);
|
|
if (**source == ',')
|
|
{
|
|
++*source;
|
|
continue;
|
|
}
|
|
if (**source == ']')
|
|
{
|
|
++*source;
|
|
finished = 1;
|
|
break;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
return finished ? 0 : -1;
|
|
}
|
|
|
|
static int parseString(const char **source, struct JsonVal *value)
|
|
{
|
|
value->type = jsonStringT;
|
|
return parseQuotedString(source, &value->u.string);
|
|
}
|
|
|
|
static int parseTrue(const char **source, struct JsonVal *value)
|
|
{
|
|
value->type = jsonTrueT;
|
|
return matchString(source, "true");
|
|
}
|
|
|
|
static int parseFalse(const char **source, struct JsonVal *value)
|
|
{
|
|
value->type = jsonFalseT;
|
|
return matchString(source, "false");
|
|
}
|
|
|
|
static int parseNum(const char **source, struct JsonVal *value)
|
|
{
|
|
value->type = jsonNumberT;
|
|
value->u.number = strtold(*source, (char**)source);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int parseNull(const char **source, struct JsonVal *value)
|
|
{
|
|
value->type = jsonNullT;
|
|
return matchString(source, "null");
|
|
}
|
|
|
|
static int (*getParser(char c))(const char **, struct JsonVal*)
|
|
{
|
|
switch (tolower(c))
|
|
{
|
|
case '[':
|
|
return &parseArray;
|
|
case '{':
|
|
return &parseObject;
|
|
case '"':
|
|
return &parseString;
|
|
case 'f':
|
|
return &parseFalse;
|
|
case 't':
|
|
return &parseTrue;
|
|
default:
|
|
if (isdigit(c))
|
|
return &parseNum;
|
|
else if (tolower(c) == 'n')
|
|
return &parseNull;
|
|
return NULL;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static int parseValue(const char **source, struct JsonVal *val)
|
|
{
|
|
int (*valueParser)(const char **str, struct JsonVal *val) = getParser(**source);
|
|
|
|
if (valueParser == NULL)
|
|
return -1;
|
|
|
|
return valueParser(source, val);
|
|
}
|
|
|
|
static int parseKeyValue(const char **source, struct JsonVal *val)
|
|
{
|
|
assert(val->type == jsonObjectT);
|
|
if(reallocObject(val) != 0)
|
|
return -1;
|
|
|
|
if (parseQuotedString(source, val->u.object.keys + val->u.object.len - 1) != 0)
|
|
return -1;
|
|
|
|
if (parseChar(source, ':') != 0)
|
|
return -1;
|
|
|
|
skipWhiteSpaces(source);
|
|
return parseValue(source, val->u.object.values + val->u.object.len - 1);
|
|
}
|
|
|
|
static int parseObject(const char **source, struct JsonVal *value)
|
|
{
|
|
int finished = 0;
|
|
|
|
value->type = jsonObjectT;
|
|
value->u.object.keys = NULL;
|
|
value->u.object.values = NULL;
|
|
value->u.object.len = 0;
|
|
|
|
skipWhiteSpaces(source);
|
|
|
|
if (parseChar(source, '{') != 0)
|
|
return -1;
|
|
|
|
skipWhiteSpaces(source);
|
|
if (**source == '}')
|
|
{
|
|
++*source;
|
|
return 0;
|
|
}
|
|
|
|
while (**source)
|
|
{
|
|
skipWhiteSpaces(source);
|
|
if (parseKeyValue(source, value) != 0)
|
|
return -1;
|
|
skipWhiteSpaces(source);
|
|
if (**source == ',')
|
|
{
|
|
++*source;
|
|
continue;
|
|
}
|
|
if (**source == '}')
|
|
{
|
|
++*source;
|
|
finished = 1;
|
|
break;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
return finished ? 0 : -1;
|
|
}
|
|
|
|
struct JsonVal jsonParseString(const char *str, char *errorBuf, int errorBufSize)
|
|
{
|
|
struct JsonVal result;
|
|
const char *_str = str;
|
|
|
|
result = (struct JsonVal){jsonNullT};
|
|
if (parseObject(&_str, &result) != 0)
|
|
fillError(_str, errorBuf, errorBufSize);
|
|
else
|
|
memset(errorBuf, 0, errorBufSize);
|
|
|
|
return result;
|
|
}
|
|
|
|
int JsonVal_isString(const struct JsonVal *val)
|
|
{
|
|
return val->type == jsonStringT;
|
|
}
|
|
|
|
int JsonVal_isNumber(const struct JsonVal *val)
|
|
{
|
|
return val->type == jsonNumberT;
|
|
}
|
|
|
|
int JsonVal_isObject(const struct JsonVal *val)
|
|
{
|
|
return val->type == jsonObjectT;
|
|
}
|
|
|
|
int JsonVal_isArray(const struct JsonVal *val)
|
|
{
|
|
return val->type == jsonArrayT;
|
|
}
|
|
|
|
int JsonVal_isTrue(const struct JsonVal *val)
|
|
{
|
|
return val->type == jsonTrueT;
|
|
}
|
|
|
|
int JsonVal_isFalse(const struct JsonVal *val)
|
|
{
|
|
return val->type == jsonFalseT;
|
|
}
|
|
|
|
int JsonVal_isNull(const struct JsonVal *val)
|
|
{
|
|
return val->type == jsonNullT;
|
|
}
|
|
|
|
int JsonVal_arrayLen(struct JsonVal *val)
|
|
{
|
|
assert(val->type == jsonArrayT);
|
|
if (val->type != jsonArrayT)
|
|
return -1;
|
|
|
|
return val->u.array.len;
|
|
}
|
|
|
|
struct JsonVal *JsonVal_arrayAt(struct JsonVal *val, int index)
|
|
{
|
|
assert(val->type == jsonArrayT);
|
|
if (val->type != jsonArrayT || index >= val->u.array.len)
|
|
return NULL;
|
|
|
|
return &val->u.array.values[index];
|
|
}
|
|
|
|
struct JsonVal *JsonVal_getObjectValueByKey(const struct JsonVal *val, const char *key)
|
|
{
|
|
int i;
|
|
|
|
assert(val->type == jsonObjectT);
|
|
if (val->type != jsonObjectT)
|
|
return NULL;
|
|
|
|
for (i = 0; i < val->u.object.len; ++i)
|
|
{
|
|
if (strcmp(key, val->u.object.keys[i]) == 0)
|
|
return &val->u.object.values[i];
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void JsonVal_forEachArrayElement(
|
|
const struct JsonVal *val,
|
|
void *ctx,
|
|
void (*action)(void *, const struct JsonVal *))
|
|
{
|
|
int i;
|
|
|
|
assert(val->type == jsonArrayT);
|
|
if (val->type != jsonArrayT)
|
|
return;
|
|
|
|
for (i = 0; i < val->u.array.len; ++i)
|
|
action(ctx, &val->u.array.values[i]);
|
|
}
|
|
|
|
void JsonVal_forEachObjectElement(
|
|
const struct JsonVal *val,
|
|
void *ctx,
|
|
void (*action)(void *, const char *key, const struct JsonVal *))
|
|
{
|
|
int i;
|
|
|
|
assert(val->type == jsonObjectT);
|
|
if (val->type != jsonObjectT)
|
|
return;
|
|
|
|
for (i = 0; i < val->u.object.len; ++i)
|
|
action(ctx, val->u.object.keys[i], &val->u.object.values[i]);
|
|
}
|
|
|
|
struct JsonVal jsonCreateObject()
|
|
{
|
|
struct JsonVal result;
|
|
|
|
result.type = jsonObjectT;
|
|
memset(&result.u, 0, sizeof(result.u));
|
|
return result;
|
|
}
|
|
|
|
static struct JsonVal *prepareNewObjectVal(struct JsonVal *val, const char *key)
|
|
{
|
|
struct JsonVal *newValPtr;
|
|
|
|
assert(val->type == jsonObjectT);
|
|
if (val->type != jsonObjectT)
|
|
return NULL;
|
|
|
|
if (reallocObject(val) != 0)
|
|
return NULL;
|
|
|
|
if (createStringCopy(key, strlen(key), val->u.object.keys + val->u.object.len - 1) != 0)
|
|
return NULL;
|
|
|
|
newValPtr = val->u.object.values + val->u.object.len - 1;
|
|
memset(newValPtr, 0, sizeof(*newValPtr));
|
|
|
|
return newValPtr;
|
|
}
|
|
|
|
struct JsonVal *JsonVal_objectAddString(struct JsonVal *val, const char *key, const char *value)
|
|
{
|
|
struct JsonVal *newValPtr = prepareNewObjectVal(val, key);
|
|
|
|
if (newValPtr == NULL)
|
|
return NULL;
|
|
|
|
if (createStringCopy(value, strlen(value), &newValPtr->u.string) != 0)
|
|
return NULL;
|
|
|
|
newValPtr->type = jsonStringT;
|
|
|
|
return newValPtr;
|
|
}
|
|
|
|
struct JsonVal *JsonVal_objectAddNumber(struct JsonVal *val, const char *key, long double number)
|
|
{
|
|
struct JsonVal *newValPtr = prepareNewObjectVal(val, key);
|
|
|
|
if (newValPtr == NULL)
|
|
return NULL;
|
|
|
|
newValPtr->u.number = number;
|
|
newValPtr->type = jsonNumberT;
|
|
|
|
return newValPtr;
|
|
}
|
|
|
|
struct JsonVal *JsonVal_objectAddObject(struct JsonVal *val, const char *key)
|
|
{
|
|
struct JsonVal *newValPtr = prepareNewObjectVal(val, key);
|
|
|
|
if (newValPtr == NULL)
|
|
return NULL;
|
|
|
|
newValPtr->type = jsonObjectT;
|
|
|
|
return newValPtr;
|
|
}
|
|
|
|
struct JsonVal *JsonVal_objectAddArray(struct JsonVal *val, const char *key)
|
|
{
|
|
struct JsonVal *newValPtr = prepareNewObjectVal(val, key);
|
|
|
|
if (newValPtr == NULL)
|
|
return NULL;
|
|
|
|
newValPtr->type = jsonArrayT;
|
|
|
|
return newValPtr;
|
|
}
|
|
|
|
struct JsonVal *JsonVal_objectAddTrue(struct JsonVal *val, const char *key)
|
|
{
|
|
struct JsonVal *newValPtr = prepareNewObjectVal(val, key);
|
|
|
|
if (newValPtr == NULL)
|
|
return NULL;
|
|
|
|
newValPtr->type = jsonTrueT;
|
|
|
|
return newValPtr;
|
|
}
|
|
|
|
struct JsonVal *JsonVal_objectAddFalse(struct JsonVal *val, const char *key)
|
|
{
|
|
struct JsonVal *newValPtr = prepareNewObjectVal(val, key);
|
|
|
|
if (newValPtr == NULL)
|
|
return NULL;
|
|
|
|
newValPtr->type = jsonFalseT;
|
|
|
|
return newValPtr;
|
|
}
|
|
|
|
struct JsonVal *JsonVal_objectAddNull(struct JsonVal *val, const char *key)
|
|
{
|
|
struct JsonVal *newValPtr = prepareNewObjectVal(val, key);
|
|
|
|
if (newValPtr == NULL)
|
|
return NULL;
|
|
|
|
newValPtr->type = jsonNullT;
|
|
|
|
return newValPtr;
|
|
}
|
|
|
|
static struct JsonVal *prepareNewArrayVal(struct JsonVal *val)
|
|
{
|
|
struct JsonVal *newValPtr;
|
|
|
|
assert(val->type == jsonArrayT);
|
|
if (val->type != jsonArrayT)
|
|
return NULL;
|
|
|
|
if (reallocArray(val) != 0)
|
|
return NULL;
|
|
|
|
newValPtr = val->u.array.values + val->u.array.len - 1;
|
|
memset(newValPtr, 0, sizeof(*newValPtr));
|
|
|
|
return newValPtr;
|
|
}
|
|
|
|
struct JsonVal *JsonVal_arrayAddString(struct JsonVal *val, const char *value)
|
|
{
|
|
struct JsonVal *newValPtr = prepareNewArrayVal(val);
|
|
|
|
if (newValPtr == NULL)
|
|
return NULL;
|
|
|
|
if (createStringCopy(value, strlen(value), &newValPtr->u.string) != 0)
|
|
return NULL;
|
|
|
|
newValPtr->type = jsonStringT;
|
|
|
|
return newValPtr;
|
|
}
|
|
|
|
struct JsonVal *JsonVal_arrayAddNumber(struct JsonVal *val, long double number)
|
|
{
|
|
struct JsonVal *newValPtr = prepareNewArrayVal(val);
|
|
|
|
if (newValPtr == NULL)
|
|
return NULL;
|
|
|
|
newValPtr->type = jsonNumberT;
|
|
newValPtr->u.number = number;
|
|
|
|
return newValPtr;
|
|
}
|
|
|
|
struct JsonVal *JsonVal_arrayAddObject(struct JsonVal *val)
|
|
{
|
|
struct JsonVal *newValPtr = prepareNewArrayVal(val);
|
|
|
|
if (newValPtr == NULL)
|
|
return NULL;
|
|
|
|
newValPtr->type = jsonObjectT;
|
|
|
|
return newValPtr;
|
|
}
|
|
|
|
struct JsonVal *JsonVal_arrayAddArray(struct JsonVal *val)
|
|
{
|
|
struct JsonVal *newValPtr = prepareNewArrayVal(val);
|
|
|
|
if (newValPtr == NULL)
|
|
return NULL;
|
|
|
|
newValPtr->type = jsonArrayT;
|
|
|
|
return newValPtr;
|
|
}
|
|
|
|
struct JsonVal *JsonVal_arrayAddTrue(struct JsonVal *val)
|
|
{
|
|
struct JsonVal *newValPtr = prepareNewArrayVal(val);
|
|
|
|
if (newValPtr == NULL)
|
|
return NULL;
|
|
|
|
newValPtr->type = jsonTrueT;
|
|
|
|
return newValPtr;
|
|
}
|
|
|
|
struct JsonVal *JsonVal_arrayAddFalse(struct JsonVal *val)
|
|
{
|
|
struct JsonVal *newValPtr = prepareNewArrayVal(val);
|
|
|
|
if (newValPtr == NULL)
|
|
return NULL;
|
|
|
|
newValPtr->type = jsonFalseT;
|
|
|
|
return newValPtr;
|
|
}
|
|
|
|
struct JsonVal *JsonVal_arrayAddNull(struct JsonVal *val)
|
|
{
|
|
struct JsonVal *newValPtr = prepareNewArrayVal(val);
|
|
|
|
if (newValPtr == NULL)
|
|
return NULL;
|
|
|
|
newValPtr->type = jsonNullT;
|
|
|
|
return newValPtr;
|
|
}
|
|
|
|
/*
|
|
write
|
|
*/
|
|
|
|
struct Buf
|
|
{
|
|
char *buf;
|
|
int spaceLeft;
|
|
};
|
|
|
|
static const int kWriteBufSize = 1024;
|
|
|
|
static int writeToBuf(void *ctx, void *source, int len)
|
|
{
|
|
struct Buf *target = (struct Buf *)ctx;
|
|
int bytesToWrite = len >= target->spaceLeft ? target->spaceLeft : len;
|
|
|
|
memcpy(target->buf, source, bytesToWrite);
|
|
target->spaceLeft -= bytesToWrite;
|
|
target->buf += bytesToWrite;
|
|
|
|
return bytesToWrite;
|
|
}
|
|
|
|
static void writeChar(
|
|
char c, void *ctx,
|
|
char *writeBuf,
|
|
int (*writeFunc)(void *ctx, void *buf, int len))
|
|
{
|
|
writeBuf[0] = c;
|
|
writeFunc(ctx, writeBuf, 1);
|
|
}
|
|
|
|
static void writeString(
|
|
const char *s, void *ctx,
|
|
char *writeBuf,
|
|
int (*writeFunc)(void *ctx, void *buf, int len))
|
|
{
|
|
int writeLen = strlen(s);
|
|
int bytesToWrite;
|
|
|
|
while (writeLen > 0)
|
|
{
|
|
bytesToWrite = writeLen < kWriteBufSize ? writeLen : kWriteBufSize;
|
|
writeFunc(ctx, (void *)s, bytesToWrite);
|
|
writeLen -= bytesToWrite;
|
|
s += bytesToWrite;
|
|
}
|
|
}
|
|
|
|
static void writeObject(
|
|
const struct JsonVal *val,
|
|
void *ctx, char *writeBuf,
|
|
int (*writeFunc)(void *ctx, void *buf, int len));
|
|
|
|
static void writeValue(
|
|
const struct JsonVal *val,
|
|
void *ctx, char *writeBuf,
|
|
int (*writeFunc)(void *ctx, void *buf, int len));
|
|
|
|
static void writeQuotedString(
|
|
const char *s, void *ctx,
|
|
char *writeBuf,
|
|
int (*writeFunc)(void *ctx, void *buf, int len))
|
|
{
|
|
writeBuf[0] = '"';
|
|
writeFunc(ctx, writeBuf, 1);
|
|
|
|
writeString(s, ctx, writeBuf, writeFunc);
|
|
|
|
writeBuf[0] = '"';
|
|
writeFunc(ctx, writeBuf, 1);
|
|
}
|
|
|
|
static void writeNumber(
|
|
long double num,
|
|
void *ctx, char *writeBuf,
|
|
int (*writeFunc)(void *ctx, void *buf, int len))
|
|
{
|
|
char *dot;
|
|
char *end;
|
|
|
|
sprintf(writeBuf, "%.5Lf", num);
|
|
dot = strchr(writeBuf, '.');
|
|
end = writeBuf + strlen(writeBuf) - 1;
|
|
|
|
for (; end != dot; --end)
|
|
if (*end != '0')
|
|
break;
|
|
|
|
if (end == dot)
|
|
*end = '\0';
|
|
else
|
|
*(++end) ='\0';
|
|
|
|
writeString(writeBuf, ctx, NULL, writeFunc);
|
|
}
|
|
|
|
static void writeArray(
|
|
const struct JsonVal *val,
|
|
void *ctx, char *writeBuf,
|
|
int (*writeFunc)(void *ctx, void *buf, int len))
|
|
{
|
|
int i;
|
|
|
|
writeChar('[', ctx, writeBuf, writeFunc);
|
|
|
|
for (i = 0; i < val->u.array.len; ++i)
|
|
{
|
|
writeValue(&val->u.array.values[i], ctx, writeBuf, writeFunc);
|
|
if (i != val->u.array.len - 1)
|
|
writeChar(',', ctx, writeBuf, writeFunc);
|
|
}
|
|
|
|
writeChar(']', ctx, writeBuf, writeFunc);
|
|
}
|
|
|
|
static void writeTrue(void *ctx, char *writeBuf, int (*writeFunc)(void *ctx, void *buf, int len))
|
|
{
|
|
writeString("true", ctx, writeBuf, writeFunc);
|
|
}
|
|
|
|
static void writeFalse(void *ctx, char *writeBuf, int (*writeFunc)(void *ctx, void *buf, int len))
|
|
{
|
|
writeString("false", ctx, writeBuf, writeFunc);
|
|
}
|
|
|
|
static void writeNull(void *ctx, char *writeBuf, int (*writeFunc)(void *ctx, void *buf, int len))
|
|
{
|
|
writeString("null", ctx, writeBuf, writeFunc);
|
|
}
|
|
|
|
static void writeValue(
|
|
const struct JsonVal *val,
|
|
void *ctx, char *writeBuf,
|
|
int (*writeFunc)(void *ctx, void *buf, int len))
|
|
{
|
|
switch (val->type)
|
|
{
|
|
case jsonStringT:
|
|
writeQuotedString(val->u.string, ctx, writeBuf, writeFunc);
|
|
break;
|
|
case jsonNumberT:
|
|
writeNumber(val->u.number, ctx, writeBuf, writeFunc);
|
|
break;
|
|
case jsonObjectT:
|
|
writeObject(val, ctx, writeBuf, writeFunc);
|
|
break;
|
|
case jsonArrayT:
|
|
writeArray(val, ctx, writeBuf, writeFunc);
|
|
break;
|
|
case jsonTrueT:
|
|
writeTrue(ctx, writeBuf, writeFunc);
|
|
break;
|
|
case jsonFalseT:
|
|
writeFalse(ctx, writeBuf, writeFunc);
|
|
break;
|
|
case jsonNullT:
|
|
writeNull(ctx, writeBuf, writeFunc);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void writeObject(
|
|
const struct JsonVal *val,
|
|
void *ctx, char *writeBuf,
|
|
int (*writeFunc)(void *ctx, void *buf, int len))
|
|
{
|
|
int i;
|
|
|
|
writeChar('{', ctx, writeBuf, writeFunc);
|
|
|
|
for (i = 0; i < val->u.object.len; ++i)
|
|
{
|
|
writeQuotedString(val->u.object.keys[i], ctx, writeBuf, writeFunc);
|
|
writeChar(':', ctx, writeBuf, writeFunc);
|
|
writeValue(&val->u.object.values[i], ctx, writeBuf, writeFunc);
|
|
|
|
if (i != val->u.object.len - 1)
|
|
writeChar(',', ctx, writeBuf, writeFunc);
|
|
}
|
|
|
|
writeChar('}', ctx, writeBuf, writeFunc);
|
|
}
|
|
|
|
struct CountingContext
|
|
{
|
|
void *userCtx;
|
|
int (*userWriteFunc)(void *ctx, void *buf, int len);
|
|
int totalWrittenBytes;
|
|
};
|
|
|
|
static int countingWriteWrapper(void *ctx, void *buf, int len)
|
|
{
|
|
struct CountingContext *countingCtx = (struct CountingContext *)ctx;
|
|
countingCtx->totalWrittenBytes += len;
|
|
|
|
return countingCtx->userWriteFunc(countingCtx->userCtx, buf, len);
|
|
}
|
|
|
|
int JsonVal_write(
|
|
const struct JsonVal *val, void *ctx,
|
|
int (*writeFunc)(void *ctx, void *buf, int len))
|
|
{
|
|
char writeBuf[kWriteBufSize];
|
|
struct CountingContext countingCtx = {ctx, writeFunc, 0};
|
|
|
|
writeObject(val, &countingCtx, writeBuf, &countingWriteWrapper);
|
|
writeBuf[0] = '\0';
|
|
countingWriteWrapper(&countingCtx, writeBuf, 1);
|
|
|
|
return countingCtx.totalWrittenBytes;
|
|
}
|
|
|
|
int JsonVal_writeString(const struct JsonVal *val, char *buf, int len)
|
|
{
|
|
struct Buf ctx = {buf, len};
|
|
return JsonVal_write(val, &ctx, &writeToBuf);
|
|
}
|
|
|
|
void JsonVal_destroy(struct JsonVal *val)
|
|
{
|
|
int i;
|
|
|
|
switch (val->type)
|
|
{
|
|
case jsonStringT:
|
|
free(val->u.string);
|
|
break;
|
|
case jsonObjectT:
|
|
for (i = 0; i < val->u.object.len; ++i)
|
|
{
|
|
JsonVal_destroy(&val->u.object.values[i]);
|
|
free(val->u.object.keys[i]);
|
|
}
|
|
free(val->u.object.values);
|
|
free(val->u.object.keys);
|
|
break;
|
|
case jsonArrayT:
|
|
for (i = 0; i < val->u.array.len; ++i)
|
|
JsonVal_destroy(&val->u.array.values[i]);
|
|
free(val->u.array.values);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|