#include #include #include #include #include #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; } }