class JSON { class Object; class Array; class JsonValueItem; enum JSONValueItemTypes { JSONStringType, JSONNumberType, JSONBoolType, JSONObjetType, JSONArrayType, JSONUndefinedType }; public: class Object { public: Object() { ArrayResize(this._jsonValueItemsArray, 0, 10); }; Object(string &json) { ArrayResize(this._jsonValueItemsArray, 0, 10); int parceJsonCharCounter = 0; bool isSuccess = true; JSON::_parseJSONObject(json, parceJsonCharCounter, isSuccess, &this); if (!isSuccess) this._clearResources(); }; JSON::Object* setProperty(string key, string value) { return this._setProperty(key, new JsonValueItem(key, value)); } JSON::Object* setProperty(string key, int value) { return this._setProperty(key, new JsonValueItem(key, value)); } JSON::Object* setProperty(string key, double value) { return this._setProperty(key, new JsonValueItem(key, value)); } JSON::Object* setProperty(string key, bool value) { return this._setProperty(key, new JsonValueItem(key, value)); } JSON::Object* setProperty(string key, JSON::Object* value) { return this._setProperty(key, new JsonValueItem(key, value)); } JSON::Object* setProperty(string key, JSON::Array* value) { return this._setProperty(key, new JsonValueItem(key, value)); } bool hasValue(string key) const { return this._getPropertyType(key) != JSONUndefinedType; } bool isBoolean(string key) const { return this._getPropertyType(key) == JSONBoolType; } bool isNumber(string key) const { return this._getPropertyType(key) == JSONNumberType; } bool isString(string key) const { return this._getPropertyType(key) == JSONStringType; } bool isObject(string key) const { return this._getPropertyType(key) == JSONObjetType; } bool isArray(string key) const { return this._getPropertyType(key) == JSONArrayType; } string getString(string key) const { const JsonValueItem* item = this._getProperty(key); if (item == NULL || item.valueType != JSONStringType) return ""; return item.stringValue; } double getNumber(string key) const { const JsonValueItem* item = this._getProperty(key); if (item == NULL || item.valueType != JSONNumberType) return 0.0; return item.doubleValue; } bool getBoolean(string key) const { const JsonValueItem* item = this._getProperty(key); if (item == NULL || item.valueType != JSONBoolType) return false; return item.booleanValue; } JSON::Object* getObject(string key) const { const JsonValueItem* item = this._getProperty(key); if (item == NULL || item.valueType != JSONObjetType) return NULL; return item.objectValue; } JSON::Array* getArray(string key) const { const JsonValueItem* item = this._getProperty(key); if (item == NULL || item.valueType != JSONArrayType) return NULL; return item.arrayValue; } void getKeysToArray(string &array[]) const { ArrayResize(array, ArraySize(this._jsonValueItemsArray)); for (int i = 0; i < ArraySize(this._jsonValueItemsArray); array[i] = this._jsonValueItemsArray[i].key, i++); } string toString() const { int arraySize = ArraySize(this._jsonValueItemsArray); string result = ""; for (int i = 0; i < arraySize; i++) { const JsonValueItem* item = this._jsonValueItemsArray[i]; result += "\""+ item.key +"\": " + item.toString() + (i < arraySize -1 ? "," : ""); } return "{" + result + "}"; } ~Object() { this._clearResources(); } private: const JsonValueItem* _jsonValueItemsArray[]; JSON::Object* _setProperty(string key, const JsonValueItem* valueItem) { int arraySize = ArraySize(this._jsonValueItemsArray); for (int i = 0; i < arraySize; i++) { if (this._jsonValueItemsArray[i].key == key) { delete this._jsonValueItemsArray[i]; this._jsonValueItemsArray[i] = valueItem; return &this; } } ArrayResize(this._jsonValueItemsArray, arraySize + 1, 10); this._jsonValueItemsArray[arraySize] = valueItem; return &this; } const JsonValueItem* _getProperty(string key) const { for (int i = 0; i < ArraySize(this._jsonValueItemsArray); i++) { if (this._jsonValueItemsArray[i].key == key) { return this._jsonValueItemsArray[i]; } } return NULL; } JSONValueItemTypes _getPropertyType(string key) const { for (int i = 0; i < ArraySize(this._jsonValueItemsArray); i++) { if (this._jsonValueItemsArray[i].key == key) { return this._jsonValueItemsArray[i].valueType; } } return JSONUndefinedType; } void _clearResources() { for (int i = 0; i < ArraySize(this._jsonValueItemsArray); i++) delete this._jsonValueItemsArray[i]; ArrayResize(this._jsonValueItemsArray, 0); } }; class Array { public: Array() { ArrayResize(this._jsonValueItemsArray, 0, 10); }; Array(string &json) { ArrayResize(this._jsonValueItemsArray, 0, 10); int parceJsonCharCounter = 0; bool isSuccess = true; JSON::_parseJSONArray(json, parceJsonCharCounter, isSuccess, &this); if (!isSuccess) this._clearResources(); }; JSON::Array* add(string value) { return this._add(new JsonValueItem("", value)); } JSON::Array* add(int value) { return this._add(new JsonValueItem("", value)); } JSON::Array* add(double value) { return this._add(new JsonValueItem("", value)); } JSON::Array* add(bool value) { return this._add(new JsonValueItem("", value)); } JSON::Array* add(JSON::Object* value) { return this._add(new JsonValueItem("", value)); } JSON::Array* add(JSON::Array* value) { return this._add(new JsonValueItem("", value)); } bool isBoolean(int index) const { return this._getPropertyType(index) == JSONBoolType; } bool isNumber(int index) const { return this._getPropertyType(index) == JSONNumberType; } bool isString(int index) const { return this._getPropertyType(index) == JSONStringType; } bool isObject(int index) const { return this._getPropertyType(index) == JSONObjetType; } bool isArray(int index) const { return this._getPropertyType(index) == JSONArrayType; } string getString(int index) const { if (index < 0 || index > ArraySize(this._jsonValueItemsArray)) return ""; const JsonValueItem* item = this._jsonValueItemsArray[index]; if (item == NULL || item.valueType != JSONStringType) return ""; return item.stringValue; } double getNumber(int index) const { if (index < 0 || index > ArraySize(this._jsonValueItemsArray)) return 0.0; const JsonValueItem* item = this._jsonValueItemsArray[index]; if (item == NULL || item.valueType != JSONNumberType) return 0.0; return item.doubleValue; } bool getBoolean(int index) const { if (index < 0 || index > ArraySize(this._jsonValueItemsArray)) return false; const JsonValueItem* item = this._jsonValueItemsArray[index]; if (item == NULL || item.valueType != JSONBoolType) return false; return item.booleanValue; } JSON::Object* getObject(int index) const { if (index < 0 || index > ArraySize(this._jsonValueItemsArray)) return NULL; const JsonValueItem* item = this._jsonValueItemsArray[index]; if (item == NULL || item.valueType != JSONObjetType) return NULL; return item.objectValue; } JSON::Array* getArray(int index) const { if (index < 0 || index > ArraySize(this._jsonValueItemsArray)) return NULL; const JsonValueItem* item = this._jsonValueItemsArray[index]; if (item == NULL || item.valueType != JSONArrayType) return NULL; return item.arrayValue; } int getLength() const { return ArraySize(_jsonValueItemsArray); } string toString() const { int arraySize = ArraySize(this._jsonValueItemsArray); string result = ""; for (int i = 0; i < arraySize; i++) { const JsonValueItem* item = this._jsonValueItemsArray[i]; result += item.toString() + (i < arraySize -1 ? "," : ""); } return "[" + result + "]"; } ~Array() { this._clearResources(); } private: JsonValueItem* _jsonValueItemsArray[]; JSON::Array* _add(JsonValueItem* elem) { int arraySize = ArraySize(this._jsonValueItemsArray); ArrayResize(this._jsonValueItemsArray, arraySize + 1, 10); _jsonValueItemsArray[arraySize] = elem; return &this; } JSONValueItemTypes _getPropertyType(int index) const { if (index >= ArraySize(this._jsonValueItemsArray)) return JSONUndefinedType; return this._jsonValueItemsArray[index].valueType; } void _clearResources() { for (int i = 0; i < ArraySize(this._jsonValueItemsArray); i++) delete this._jsonValueItemsArray[i]; ArrayResize(this._jsonValueItemsArray, 0); } }; private: JSON() {} static void _parseJSONObject(const string &json, int &i, bool &isSuccess, JSON::Object* object) { JSON::_skipWhitespace(json, i); while (i < StringLen(json) && json[i++] != '{'); // skip '{' JSON::_skipWhitespace(json, i); while (i < StringLen(json)) { JSON::_skipWhitespace(json, i); string key = JSON::_parseKey(json, i, isSuccess); if (!isSuccess) return; JSON::_skipWhitespace(json, i); if (json[i++] != ':') isSuccess = false; // wait ':' if (!isSuccess) return; JSON::_skipWhitespace(json, i); if (JSON::_isDigit(json[i]) || json[i] == '-') { object.setProperty(key, JSON::_parseNumber(json, i, isSuccess)); } else if (json[i] == 'n' || json[i] == 'N') { object.setProperty(key, JSON::_parseNull(json, i, isSuccess)); } else if (json[i] == 't' || json[i] == 'f') { object.setProperty(key, JSON::_parseBoolean(json, i, isSuccess)); } else if (json[i] == '"') { object.setProperty(key, JSON::_parseString(json, i, isSuccess)); } else if (json[i] == '{') { object.setProperty(key, JSON::_parseObject(json, i, isSuccess)); } else if (json[i] == '[') { object.setProperty(key, JSON::_parseArray(json, i, isSuccess)); } if (!isSuccess) break; JSON::_skipWhitespace(json, i); if (json[i] == ',') { i++; continue; } else if (json[i] == '}') { i++; break; // end } else { isSuccess = false; } } } static void _parseJSONArray(const string &json, int &i, bool &isSuccess, JSON::Array* arrayObject) { JSON::_skipWhitespace(json, i); while (i < StringLen(json) && json[i++] != '['); // skip '[' JSON::_skipWhitespace(json, i); while (i < StringLen(json)) { JSON::_skipWhitespace(json, i); // check value type if (JSON::_isDigit(json[i]) || json[i] == '-') { arrayObject.add(JSON::_parseNumber(json, i, isSuccess)); } else if (json[i] == '"') { arrayObject.add(JSON::_parseString(json, i, isSuccess)); } else if (json[i] == 'n' || json[i] == 'N') { arrayObject.add(JSON::_parseNull(json, i, isSuccess)); } else if (json[i] == 't' || json[i] == 'f') { arrayObject.add(JSON::_parseBoolean(json, i, isSuccess)); } else if (json[i] == '{') { arrayObject.add(JSON::_parseObject(json, i, isSuccess)); } else if (json[i] == '[') { arrayObject.add(JSON::_parseArray(json, i, isSuccess)); } if (!isSuccess) break; JSON::_skipWhitespace(json, i); if (json[i] == ',') { i++; // skip ',' } else if (json[i] == ']') { i++; break; // end } else { isSuccess = false; break; } } } static bool _isDigit(ushort ch) { return (ch >= '0' && ch <= '9'); } static void _skipWhitespace(const string &json, int &i) { while (i < StringLen(json) && (json[i] == ' ' || json[i] == '\n' || json[i] == '\r' || json[i] == '\t')) i++; } static string _parseKey(const string &json, int &i, bool &isSuccess) { if (i < StringLen(json) && json[i] == '"') { i++; // skip '"' string key = ""; while (i < StringLen(json) && json[i] != '"') key += ShortToString(json[i++]); if (i < StringLen(json) && json[i] == '"') { // check end '"' i++; // skip '"' return key; } } isSuccess = false; return ""; } static double _parseNumber(const string &json, int &i, bool &isSuccess) { string numberStr = ""; bool isNegative = false; if (json[i] == '-') { isNegative = true; i++; } while (i < StringLen(json) && JSON::_isDigit(json[i])) { numberStr += ShortToString(json[i++]); } if (i < StringLen(json) && json[i] == '.') { numberStr += ShortToString(json[i++]); while (i < StringLen(json) && JSON::_isDigit(json[i])) { numberStr += ShortToString(json[i++]); } } if (StringLen(numberStr) > 0) { double result = StringToDouble(numberStr); return isNegative ? -result : result; } isSuccess = false; return 0.0; } static string _parseString(const string &json, int &i, bool &isSuccess) { string result = ""; i++; // skip '"' while (i < StringLen(json)) { if (json[i] == '"') { // if end of string i++; // skip '"' return result; } else if (json[i] == '\\') { // check escape i++; // // skip '\' if (i < StringLen(json)) { switch (json[i]) { case 'n': result += "\n"; break; case 't': result += "\t"; break; case 'r': result += "\r"; break; case '"': result += "\""; break; case '\\': result += "\\"; break; default: isSuccess = false; return ""; } } } else { result += ShortToString(json[i]); } i++; // next char } // not find end '"' isSuccess = false; return ""; } static bool _parseBoolean(const string &json, int &i, bool &isSuccess) { if (StringLen(json) >= i + 4) { string substringTrue = StringSubstr(json, i, 4); StringToLower(substringTrue); if (substringTrue == "true") { i += 4; return true; } } if (StringLen(json) >= i + 5) { string substringFalse = StringSubstr(json, i, 5); StringToLower(substringFalse); if (substringFalse == "false") { i += 5; return false; } } isSuccess = false; return false; } static string _parseNull(const string &json, int &i, bool &isSuccess) { if (StringLen(json) >= i + 4) { string substring = StringSubstr(json, i, 4); StringToLower(substring); if (substring == "null") { i += 4; return "null"; } } isSuccess = false; return ""; } static JSON::Object* _parseObject(const string &json, int &i, bool &isSuccess) { JSON::Object* childObject = new JSON::Object(); JSON::_parseJSONObject(json, i, isSuccess, childObject); return childObject; } static JSON::Array* _parseArray(const string &json, int &i, bool &isSuccess) { JSON::Array* childObject = new JSON::Array(); JSON::_parseJSONArray(json, i, isSuccess, childObject); return childObject; } class JsonValueItem { public: string key; JSONValueItemTypes valueType; string stringValue; double doubleValue; bool booleanValue; JSON::Object* objectValue; JSON::Array* arrayValue; JsonValueItem(string k, string value): key(k), valueType(JSONStringType), stringValue(value) {}; JsonValueItem(string k, int value): key(k), valueType(JSONNumberType), doubleValue(value) {}; JsonValueItem(string k, double value): key(k), valueType(JSONNumberType), doubleValue(value) {}; JsonValueItem(string k, bool value): key(k), valueType(JSONBoolType), booleanValue(value) {}; JsonValueItem(string k, JSON::Object* value): key(k), valueType(JSONObjetType), objectValue(value) {}; JsonValueItem(string k, JSON::Array* value): key(k), valueType(JSONArrayType), arrayValue(value) {}; string toString() const { if (this.valueType == JSONBoolType) return string(this.booleanValue); if (this.valueType == JSONNumberType) return string(this.doubleValue); if (this.valueType == JSONObjetType) return this.objectValue.toString(); if (this.valueType == JSONArrayType) return this.arrayValue.toString(); if (this.valueType == JSONStringType) { string copy = this.stringValue; StringReplace(copy, "\"","\\\""); return "\"" + copy + "\""; } return ""; // JSONUndefinedType , never returns } ~JsonValueItem() { if (this.valueType == JSONObjetType) delete this.objectValue; if (this.valueType == JSONArrayType) delete this.arrayValue; } }; };