Api wrapper to communicate with EVRYTHNG's Engine.
Dependencies: EthernetInterface mbed-rtos
Dependents: EvrythngApiExample
JsonParser.cpp
- Committer:
- vladounet
- Date:
- 2012-08-30
- Revision:
- 0:d38d192c2f5f
File content as of revision 0:d38d192c2f5f:
/* * (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); }