diff --git a/uppsrc/Core/Core.h b/uppsrc/Core/Core.h index 79f156640..0d4b48d1c 100644 --- a/uppsrc/Core/Core.h +++ b/uppsrc/Core/Core.h @@ -258,6 +258,7 @@ NAMESPACE_UPP #include "Parser.h" #include "XML.h" +#include "JSON.h" #include "Lang.h" #include "i18n.h" #include "Topic.h" diff --git a/uppsrc/Core/Core.upp b/uppsrc/Core/Core.upp index f07b924c5..291978961 100644 --- a/uppsrc/Core/Core.upp +++ b/uppsrc/Core/Core.upp @@ -124,6 +124,8 @@ file XML.cpp optimize_speed, Xmlize.h, Xmlize.cpp optimize_speed, + JSON.h, + JSON.cpp, Uuid.h, Uuid.cpp optimize_speed, Ptr.h, diff --git a/uppsrc/Core/JSON.cpp b/uppsrc/Core/JSON.cpp new file mode 100644 index 000000000..93b5a2485 --- /dev/null +++ b/uppsrc/Core/JSON.cpp @@ -0,0 +1,118 @@ +#include "Core.h" + +NAMESPACE_UPP + +Value ParseJSON(CParser& p) +{ + if(p.IsNumber()) + return p.ReadDouble(); + if(p.IsString()) + return p.ReadString(); + if(p.Id("null")) + return Null; + if(p.Id("true")) + return true; + if(p.Id("false")) + return false; + if(p.Char('{')) { + ValueMap m; + if(!p.IsChar('}')) + do { + String key = p.ReadString(); + p.PassChar(':'); + m.Add(key, ParseJSON(p)); + } + while(p.Char(',')); + p.PassChar('}'); + return m; + } + if(p.Char('[')) { + ValueArray va; + if(!p.IsChar(']')) + do + va.Add(ParseJSON(p)); + while(p.Char(',')); + p.PassChar(']'); + return va; + } + p.ThrowError("Unrecognized JSON element"); + return Null; +} + +Value ParseJSON(const char *s) +{ + CParser p(s); + return ParseJSON(p); +} + +String AsJSON(const Value& v, const String& sep, bool pretty) +{ + String r; + if(v.GetType() == VALUEMAP_V) { + r << "{"; + String sep1; + if(pretty) { + r << "\r\n"; + sep1 = sep + '\t'; + } + ValueMap m = v; + ValueArray va = m.GetValues(); + for(int i = 0; i < m.GetCount(); i++) { + if(i) { + r << ","; + if(pretty) + r << "\r\n"; + } + if(pretty) + r << sep1; + r << AsCString((String)m.GetKeys()[i]) << (pretty ? ": " : ":") + << AsJSON(va[i], sep1, pretty); + } + if(pretty) + r << "\r\n" << sep; + r << "}"; + return r; + } + if(v.GetType() == VALUEARRAY_V) { + r << "["; + String sep1; + if(pretty) { + r << "\r\n"; + sep1 = sep + '\t'; + } + ValueArray va = v; + for(int i = 0; i < va.GetCount(); i++) { + if(i) { + r << ","; + if(pretty) + r << "\r\n"; + } + if(pretty) + r << sep1; + r << AsJSON(va[i], sep1, pretty); + } + if(pretty) + r << "\r\n" << sep; + r << "]"; + return r; + } + if(IsNumber(v) && IsNull(v)) + return "null"; + if(v.GetType() == INT_V) + return Format("%d", (int)v); + if(v.GetType() == BOOL_V) + return (bool)v ? "true" : "false"; + if(IsNumber(v)) + return Format("%.16g", (double)v); + if(IsString(v)) + return AsCString((String)v); + NEVER(); + return "null"; +} + +String AsJSON(const Value& v, bool pretty) +{ + return AsJSON(v, String(), pretty); +} + +END_UPP_NAMESPACE diff --git a/uppsrc/Core/JSON.h b/uppsrc/Core/JSON.h new file mode 100644 index 000000000..492784809 --- /dev/null +++ b/uppsrc/Core/JSON.h @@ -0,0 +1,5 @@ +Value ParseJSON(CParser& p); +Value ParseJSON(const char *s); + +String AsJSON(const Value& v, const String& indent, bool pretty = false); +String AsJSON(const Value& v, bool pretty = false); diff --git a/uppsrc/Core/Value.cpp b/uppsrc/Core/Value.cpp index bf5adda77..45482bb86 100644 --- a/uppsrc/Core/Value.cpp +++ b/uppsrc/Core/Value.cpp @@ -219,8 +219,13 @@ Value ErrorValue(const char *s) { return ErrorValue(String(s)); } -Value ErrorValue() { - return ErrorValue(String()); +const Value& ErrorValue() { + static Value *p; + ONCELOCK { + static Value v = ErrorValue(String()); + p = &v; + } + return *p; } String GetErrorText(const Value& v) { @@ -604,7 +609,7 @@ void ValueMap::Remove(int i) d.value.Remove(i); } -Value ValueMap::operator[](const Value& key) const +const Value& ValueMap::operator[](const Value& key) const { int q = data->key.Find(key); return q >= 0 ? data->value[q] : ErrorValue(); diff --git a/uppsrc/Core/Value.h b/uppsrc/Core/Value.h index 4a8926951..c628f1bc7 100644 --- a/uppsrc/Core/Value.h +++ b/uppsrc/Core/Value.h @@ -147,6 +147,12 @@ public: Value& operator=(const Value& v); Value(const Value& v); + + int GetCount() const; + const Value& operator[](int i) const; + const Value& operator[](const String& key) const; + const Value& operator[](const char *key) const; + const Value& operator[](const Id& key) const; Value(); ~Value(); @@ -482,9 +488,9 @@ public: template inline Value RichToValue(const T& data) { return RichValue(data); } -Value ErrorValue(const char *s); -Value ErrorValue(const String& s); -Value ErrorValue(); +Value ErrorValue(const char *s); +Value ErrorValue(const String& s); +const Value& ErrorValue(); String GetErrorText(const Value& v); @@ -630,6 +636,7 @@ public: bool IsEmpty() const { return data->data.IsEmpty(); } void Add(const Value& v); + ValueArray& operator<<(const Value& v) { Add(v); return *this; } void Set(int i, const Value& v); const Value& Get(int i) const; const Vector& Get() const { return data->data; } @@ -713,27 +720,60 @@ public: void SetKey(int i, Id id) { SetKey(i, Value(id.ToString())); } void Remove(int i); - const Index& GetKeys() const { return data->key; } - ValueArray GetValues() const { return data->value; } + const Index& GetKeys() const { return data->key; } + ValueArray GetValues() const { return data->value; } - operator ValueArray() const { return GetValues(); } + operator ValueArray() const { return GetValues(); } - Value operator[](const Value& k) const; - Value operator[](const String& s) const { return operator[](Value(s)); } - Value operator[](const char *s) const { return operator[](Value(s)); } - Value operator[](const Id& k) const { return operator[](Value(k.ToString())); } + const Value& operator[](const Value& k) const; + const Value& operator[](const String& s) const{ return operator[](Value(s)); } + const Value& operator[](const char *s) const { return operator[](Value(s)); } + const Value& operator[](const Id& k) const { return operator[](Value(k.ToString())); } - unsigned GetHashValue() const { return data->GetHashValue(); } + unsigned GetHashValue() const { return data->GetHashValue(); } void Serialize(Stream& s); - String ToString() const { return data->AsString(); } + String ToString() const { return data->AsString(); } bool operator==(const ValueMap& v) const; - bool operator!=(const ValueMap& v) const { return !operator==(v); } + bool operator!=(const ValueMap& v) const { return !operator==(v); } }; inline bool IsValueArray(const Value& v) { return v.GetType() == VALUEARRAY_V || v.GetType() == VALUEMAP_V; } inline bool IsValueMap(const Value& v) { return IsValueArray(v); } +inline +int Value::GetCount() const +{ + return IsValueArray(*this) ? ValueArray(*this).GetCount() : 0; +} + +inline +const Value& Value::operator[](int i) const +{ + ASSERT(IsValueArray(*this)); + return ValueArray(*this)[i]; +} + +inline +const Value& Value::operator[](const String& key) const +{ + ASSERT(IsValueMap(*this)); + return ValueMap(*this)[key]; +} + +inline +const Value& Value::operator[](const char *key) const +{ + ASSERT(IsValueMap(*this)); + return ValueMap(*this)[key]; +} + +inline +const Value& Value::operator[](const Id& key) const +{ + ASSERT(IsValueMap(*this)); + return ValueMap(*this)[key]; +} class ValueGen { public: