Api wrapper to communicate with EVRYTHNG's Engine.
Dependencies: EthernetInterface mbed-rtos
Dependents: EvrythngApiExample
Diff: JsonParser.cpp
- Revision:
- 0:d38d192c2f5f
--- /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);
+}
+