Evrythng API for W5500, WIZ550io
Dependencies: W5500Interface
Dependents: EvrythngApiExampleW5500
Fork of EvrythngApi by
Diff: JsonParser.cpp
- Revision:
- 0:d38d192c2f5f
diff -r 000000000000 -r d38d192c2f5f JsonParser.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/JsonParser.cpp Thu Aug 30 13:20:01 2012 +0000 @@ -0,0 +1,574 @@ +/* + * (c) Copyright 2012 EVRYTHNG Ltd London / Zurich + * www.evrythng.com + * + * --- DISCLAIMER --- + * + * EVRYTHNG provides this source code "as is" and without warranty of any kind, + * and hereby disclaims all express or implied warranties, including without + * limitation warranties of merchantability, fitness for a particular purpose, + * performance, accuracy, reliability, and non-infringement. + * + * Author: Michel Yerly + * + */ +#include "JsonParser.h" +#include "string.h" +#include "stdlib.h" +#include "errno.h" +#include "util.h" + +//#define DEBUG_JSONTOKENIZER +//#define DEBUG_JSONPARSER +//#define DEBUG_JSONGET + +using namespace std; + +bool isDigit(char c) +{ + return c >= '0' && c <= '9'; +} + +JsonParser::JsonParser() +{ + this->pDocument = NULL; +} + +JsonParser::~JsonParser() +{ + if (this->pDocument) { + delete this->pDocument; + } +} + +int JsonParser::parse(const char* json) +{ + this->json = json; + this->json_len = strlen(json); + + if (this->pDocument) { + delete this->pDocument; + this->pDocument = NULL; + } + + ctPos = 0; + ctLen = 0; + if (goToNextToken() != 0) return -1; + bool ok = true; + if (json[ctPos] == '{') { + if (parseObject(&pDocument) != 0) { + ok = false; + } + } else { + if (parseArray(&pDocument) != 0) ok = false; + } + if (ct != TOKEN_EOS) { + ok = false; + } + + if (!ok) { + delete pDocument; + pDocument = NULL; + return -1; + } + + return 0; +} + +JsonValue* JsonParser::getDocument() +{ + return pDocument; +} + +int JsonParser::goToNextToken() +{ + +#ifdef DEBUG_JSONTOKENIZER + + dbg.printf("Token: "); + +#endif + + ctPos += ctLen; + + // Skip whitespaces + while (ctPos < json_len && + (json[ctPos] == ' ' || json[ctPos] == '\t' || + json[ctPos] == '\r' || json[ctPos] == '\n')) + ++ctPos; + + if (ctPos < json_len) { + if (json[ctPos] == '"') { + ct = TOKEN_STRING; + int i = ctPos+1; + while (i < json_len && json[i] != '"') { + if (json[i] == '\\') { + if (i+1 < json_len) { + switch (json[i+1]) { + case '\\': + case '"': + case '/': + case 'b': + case 'f': + case 'n': + case 'r': + case 't': + ++i; + break; + case 'u': + i+= 5; + break; + default: + return -1; + } + } else { + return -1; + } + } + ++i; + } + if (i >= json_len || json[i] != '"') return -1; + ctLen = i - ctPos + 1; + } else if (isDigit(json[ctPos]) || json[ctPos] == '-') { + ct = TOKEN_NUMBER; + char* e; + errno = 0; + ctNumberVal = strtod(json+ctPos, &e); + if (errno || e - json <= 0) return -1; + ctLen = (e - json) - ctPos; + + } else if (strncmp(json+ctPos,"true",4) == 0) { + ct = TOKEN_TRUE; + ctLen = 4; + } else if (strncmp(json+ctPos,"false",5) == 0) { + ct = TOKEN_FALSE; + ctLen = 5; + } else if (strncmp(json+ctPos,"null",4) == 0) { + ct = TOKEN_NULL; + ctLen = 4; + } else { + ct = TOKEN_DELIMITER; + ctLen = 1; + } + } else { + ct = TOKEN_EOS; + ctLen = 0; + } + +#ifdef DEBUG_JSONTOKENIZER + + switch (ct) { + case TOKEN_DELIMITER: + dbg.printf("Delimtier - "); + break; + case TOKEN_EOS: + dbg.printf("End of stream"); + break; + case TOKEN_NUMBER: + dbg.printf("Number %g - ", ctNumberVal); + break; + case TOKEN_STRING: + dbg.printf("String - "); + break; + case TOKEN_FALSE: + dbg.printf("False - "); + break; + case TOKEN_TRUE: + dbg.printf("True - "); + break; + case TOKEN_NULL: + dbg.printf("Null - "); + break; + } + if (ct != TOKEN_EOS) { + for (int i = 0; i < ctLen; ++i) + dbg.printf("%c", json[ctPos+i]); + } + dbg.printf(" (%d,%d)\r\n", ctPos, ctLen); + +#endif + + return 0; +} + +int JsonParser::parseObject(JsonValue** object) +{ + +#ifdef DEBUG_JSONPARSER + dbg.printf("Enter parseObject\r\n"); +#endif + + *object = JsonValue::createMap(); + map<string,JsonValue*>* m = (*object)->value.map; + + if (ct != TOKEN_DELIMITER || json[ctPos] != '{') return -1; + if (goToNextToken() != 0) return -1; + + if (ct == TOKEN_STRING) { + + string key; + key.assign(json+ctPos+1, ctLen-2); + + if (goToNextToken() != 0) return -1; + + if (ct != TOKEN_DELIMITER || json[ctPos] != ':') return -1; + if (goToNextToken() != 0) return -1; + + JsonValue* pValue; + if (parseValue(&pValue) != 0) { + delete pValue; + return -1; + } + (*m)[key] = pValue; + + while (ct == TOKEN_DELIMITER && json[ctPos] == ',') { + if (goToNextToken() != 0) return -1; + + if (ct != TOKEN_STRING) return -1; + key.assign(json+ctPos+1, ctLen-2); + if (goToNextToken() != 0) return -1; + + if (ct != TOKEN_DELIMITER || json[ctPos] != ':') return -1; + if (goToNextToken() != 0) return -1; + + if (parseValue(&pValue) != 0) { + delete pValue; + return -1; + } + (*m)[key] = pValue; + } + } + + if (ct != TOKEN_DELIMITER || json[ctPos] != '}') return -1; + if (goToNextToken() != 0) return -1; + +#ifdef DEBUG_JSONPARSER + dbg.printf("Exit parseObject\r\n"); +#endif + return 0; +} + +int JsonParser::parseValue(JsonValue** value) +{ + +#ifdef DEBUG_JSONPARSER + dbg.printf("Enter parseValue\r\n"); +#endif + + switch (ct) { + case TOKEN_STRING: + *value = JsonValue::createString(json+ctPos+1,ctLen-2); + if (goToNextToken() != 0) return -1; + break; + case TOKEN_NUMBER: + *value = JsonValue::createDouble(ctNumberVal); + if (goToNextToken() != 0) return -1; + break; + case TOKEN_NULL: + *value = JsonValue::createNull(); + if (goToNextToken() != 0) return -1; + break; + case TOKEN_FALSE: + *value = JsonValue::createBoolean(false); + if (goToNextToken() != 0) return -1; + break; + case TOKEN_TRUE: + *value = JsonValue::createBoolean(true); + if (goToNextToken() != 0) return -1; + break; + case TOKEN_DELIMITER: + if (json[ctPos] == '{') { + if (parseObject(value) != 0) return -1; + } else if (json[ctPos] == '[') { + if (parseArray(value) != 0) return -1; + } + break; + default: + *value = JsonValue::createNull(); + return -1; + } + +#ifdef DEBUG_JSONPARSER + dbg.printf("Exit parseValue\r\n"); +#endif + + return 0; +} + +int JsonParser::parseArray(JsonValue** array) +{ + +#ifdef DEBUG_JSONPARSER + dbg.printf("Enter parseArray\r\n"); +#endif + + *array = JsonValue::createVector(); + vector<JsonValue*>* vec = (*array)->value.vec; + + if (ct != TOKEN_DELIMITER || json[ctPos] != '[') return -1; + if (goToNextToken() != 0) return -1; + + if (ct != TOKEN_DELIMITER || json[ctPos] != ']') { + + JsonValue* pValue; + if (parseValue(&pValue) != 0) { + delete pValue; + return -1; + }; + vec->push_back(pValue); + + while (ct == TOKEN_DELIMITER && json[ctPos] == ',') { + if (goToNextToken() != 0) return -1; + + if (parseValue(&pValue) != 0) { + delete pValue; + return -1; + }; + vec->push_back(pValue); + } + } + + if (ct != TOKEN_DELIMITER || json[ctPos] != ']') return -1; + if (goToNextToken() != 0) return -1; + +#ifdef DEBUG_JSONPARSER + dbg.printf("Exit parseArray\r\n"); +#endif + + return 0; +} + +int inst = 0; + +JsonValue::JsonValue(const char* buffer, int len) +{ + type = VT_CHAR_PTR; + value.s = new char[len+1]; + strncpy(value.s, buffer, len); + value.s[len] = '\0'; +} + +JsonValue::JsonValue(double d) +{ + type = VT_DOUBLE; + value.d = d; +} + +JsonValue::JsonValue(bool b) +{ + type = b ? VT_CST_TRUE : VT_CST_FALSE; + +} + +JsonValue::JsonValue() +{ +} + +JsonValue::~JsonValue() +{ + switch (type) { + case VT_CHAR_PTR: + delete[] value.s; + break; + case VT_MAP_PTR: + for (map<string,JsonValue*>::iterator itr = value.map->begin(); itr != value.map->end(); itr++) + delete ((*itr).second); + delete value.map; + break; + case VT_VEC_PTR: + for (vector<JsonValue*>::iterator itr = value.vec->begin(); itr != value.vec->end(); itr++) + delete (*itr); + delete value.vec; + break; + default: + break; + } +} + +JsonValue* JsonValue::createString(const char* buffer, int len) +{ + return new JsonValue(buffer, len); +} + +JsonValue* JsonValue::createDouble(double d) +{ + return new JsonValue(d); +} + +JsonValue* JsonValue::createBoolean(bool b) +{ + return new JsonValue(b); +} + +JsonValue* JsonValue::createMap() +{ + JsonValue* ret = new JsonValue(); + ret->type = VT_MAP_PTR; + ret->value.map = new map<string,JsonValue*>(); + return ret; +} + +JsonValue* JsonValue::createVector() +{ + JsonValue* ret = new JsonValue(); + ret->type = VT_VEC_PTR; + ret->value.vec = new vector<JsonValue*>(); + return ret; +} + +JsonValue* JsonValue::createNull() +{ + JsonValue* ret = new JsonValue(); + ret->type = VT_CST_NULL; + return ret; +} + +void JsonValue::print() +{ + bool c = false; + switch (type) { + case VT_CHAR_PTR: + dbg.printf("\"%s\"", value.s); + break; + case VT_MAP_PTR: + dbg.printf("{"); + for (map<string,JsonValue*>::iterator itr = value.map->begin(); itr != value.map->end(); itr++) { + if (c) dbg.printf(","); + else c = true; + dbg.printf("\"%s\":",(*itr).first.c_str()); + (*itr).second->print(); + } + dbg.printf("}"); + break; + case VT_VEC_PTR: + dbg.printf("["); + for (vector<JsonValue*>::iterator itr = value.vec->begin(); itr != value.vec->end(); itr++) { + if (c) dbg.printf(","); + else c = true; + (*itr)->print(); + } + dbg.printf("]"); + break; + case VT_DOUBLE: + dbg.printf("%g", value.d); + break; + case VT_CST_TRUE: + dbg.printf("true"); + break; + case VT_CST_FALSE: + dbg.printf("false"); + break; + case VT_CST_NULL: + dbg.printf("null"); + break; + default: + break; + } +} + +JsonValue* JsonValue::get(const char* path) +{ + JsonValue* pValue = this; + int pos = 0; + while (path != NULL && path[pos] != '\0') { + +#ifdef DEBUG_JSONGET + dbg.printf("::get "); + pValue->print(); + dbg.printf("\r\n"); +#endif + + const char* start = path+pos; + const char* pSl = strchr(start, '/'); + int len = pSl == NULL ? strlen(start) : pSl - start; + if (len <= 0) return NULL; + if (pValue->type == VT_VEC_PTR) { + int v = atoi(start); + if (v == 0 && path[pos] != '0') { + return NULL; + } + if (v < 0 || v >= pValue->value.vec->size()) { + return NULL; + } + pValue = (*pValue->value.vec)[v]; + } else if (pValue->type == VT_MAP_PTR) { + char* pKey = new char[len+1]; + strncpy(pKey, start, len); + pKey[len] = '\0'; + pValue = (*pValue->value.map)[pKey]; + delete[] pKey; + if (pValue == NULL) { + return NULL; + } + } else { + return NULL; + } + pos += len; + if (pSl) ++pos; + } + +#ifdef DEBUG_JSONGET + dbg.printf("::get "); + pValue->print(); + dbg.printf("\r\n"); +#endif + + return pValue; +} + +const double* JsonValue::getDouble(const char* path) +{ + JsonValue* pV = get(path); + if (pV != NULL && pV->type == VT_DOUBLE) { + return &(pV->value.d); + } else { + return NULL; + } +} + +const char* JsonValue::getString(const char* path) +{ + JsonValue* pV = get(path); + if (pV != NULL && pV->type == VT_CHAR_PTR) { + return pV->value.s; + } else { + return NULL; + } +} +const std::vector<JsonValue*>* JsonValue::getVector(const char* path) +{ + JsonValue* pV = get(path); + if (pV != NULL && pV->type == VT_VEC_PTR) { + return pV->value.vec; + } else { + return NULL; + } +} +const std::map<std::string,JsonValue*>* JsonValue::getMap(const char* path) +{ + JsonValue* pV = get(path); + if (pV != NULL && pV->type == VT_MAP_PTR) { + return pV->value.map; + } else { + return NULL; + } +} + +static const bool FALSE = false; +static const bool TRUE = true; + +const bool* JsonValue::getBoolean(const char* path) +{ + JsonValue* pV = get(path); + if (pV != NULL && (pV->type == VT_CST_TRUE || pV->type == VT_CST_FALSE)) { + return (pV->type == VT_CST_TRUE) ? &TRUE : &FALSE; + } else { + return NULL; + } +} +bool JsonValue::isNull(const char* path) +{ + JsonValue* pV = get(path); + return (pV != NULL) && (pV->type == VT_CST_NULL); +} +