diff --git a/uppsrc/Core/BlockStream.cpp b/uppsrc/Core/BlockStream.cpp index d74976b7e..59e80a0d1 100644 --- a/uppsrc/Core/BlockStream.cpp +++ b/uppsrc/Core/BlockStream.cpp @@ -388,6 +388,11 @@ FileStream::~FileStream() { Close(); } +bool FileOut::Open(const char *fn) +{ + return FileStream::Open(fn, FileStream::CREATE|FileStream::NOWRITESHARE); +} + #endif #ifdef PLATFORM_POSIX @@ -513,19 +518,10 @@ FileStream::~FileStream() { Close(); } -#ifdef PLATFORM_POSIX bool FileOut::Open(const char *fn, mode_t acm) { return FileStream::Open(fn, FileStream::CREATE|FileStream::NOWRITESHARE, acm); } -#endif - -#ifdef PLATFORM_WIN32 -bool FileOut::Open(const char *fn) -{ - return FileStream::Open(fn, FileStream::CREATE|FileStream::NOWRITESHARE); -} -#endif #endif diff --git a/uppsrc/Core/JSON.cpp b/uppsrc/Core/JSON.cpp index b27bf1cb9..edb4d964c 100644 --- a/uppsrc/Core/JSON.cpp +++ b/uppsrc/Core/JSON.cpp @@ -121,4 +121,178 @@ String AsJSON(const Value& v, bool pretty) return AsJSON(v, String(), pretty); } +template<> void Jsonize(JsonIO& io, double& var) +{ + if(io.IsLoading()) { + const Value& v = io.Get(); + if(IsNull(v)) { + var = Null; + return; + } + if(IsNumber(v)) { + var = io.Get(); + return; + } + if(IsString(v)) { + double h = ScanDouble((String)v); + if(!IsNull(h)) { + var = h; + return; + } + } + throw JsonizeError("number expected"); + } + else + io.Set(var); +} + +template<> void Jsonize(JsonIO& io, int& var) +{ + double v = IntDbl(var); + Jsonize(io, v); + if(io.IsLoading()) + if(IsNull(v)) + var = Null; + else + if(v >= INT_MIN && v <= INT_MAX) + var = (int)v; + else + throw JsonizeError("number is not integer"); +} + +template<> void Jsonize(JsonIO& io, bool& var) +{ + if(io.IsLoading()) { + const Value& v = io.Get(); + if(IsNumber(v) && !IsNull(v)) + var = (bool)v; + else + throw JsonizeError("boolean expected"); + } + else + io.Set(var); +} + +template<> void Jsonize(JsonIO& io, int64& var) +{ + if(io.IsLoading()) { + const Value& v = io.Get(); + if(IsNull(v)) { + var = Null; + return; + } + if(v.Is() || v.Is()) { + var = v; + return; + } + if(IsNumber(v)) { + double d = v; + if(d >= INT64_MIN && d <= INT64_MAX) { + var = (int64)d; + return; + } + } + else + if(IsString(v)) { + int64 h = ScanInt64((String)v); + if(!IsNull(h)) { + var = h; + return; + } + } + throw JsonizeError("invalid int64 value"); + } + else + if(IsNull(var)) + io.Set(Null); + else + if(var >= INT_MIN && var <= INT_MAX) + io.Set(var); + else + io.Set(AsString(var)); +} + +template<> void Jsonize(JsonIO& io, String& var) +{ + if(io.IsLoading()) { + const Value& v = io.Get(); + if(IsString(v)) + var = v; + else + throw JsonizeError("string expected"); + } + else + io.Set(var); +} + +template<> void Jsonize(JsonIO& io, WString& var) +{ + if(io.IsLoading()) { + const Value& v = io.Get(); + if(IsString(v)) + var = v; + else + throw JsonizeError("string expected"); + } + else + io.Set(var); +} + +template<> void Jsonize(JsonIO& io, Date& var) +{ + if(io.IsLoading()) { + const Value& v = io.Get(); + if(IsNull(v)) { + var = Null; + return; + } + if(IsString(v)) { + Date d = ScanDate("ymd", (String)v); + if(!IsNull(d)) { + var = d; + return; + } + } + throw JsonizeError("string expected for Date value"); + } + else + if(IsNull(var)) + io.Set(Null); + else + io.Set(Format("%04d-%02d-%02d", var.year, var.month, var.day)); +} + +template<> void Jsonize(JsonIO& io, Time& var) +{ + if(io.IsLoading()) { + const Value& v = io.Get(); + if(IsNull(v)) { + var = Null; + return; + } + if(IsString(v)) { + Time d = ScanTime("ymd", (String)v); + if(!IsNull(d)) { + var = d; + return; + } + } + throw JsonizeError("string expected for Time value"); + } + else + if(IsNull(var)) + io.Set(Null); + else + io.Set(Format("%04d-%02d-%02d %02d:%02d:%02d", + var.year, var.month, var.day, var.hour, var.minute, var.second)); +} + +template<> void Jsonize(JsonIO& io, Complex& var) +{ + double r = var.real(); + double i = var.imag(); + io("real", r)("imag", i); + var = Complex(r, i); +} + END_UPP_NAMESPACE diff --git a/uppsrc/Core/JSON.h b/uppsrc/Core/JSON.h index 93a1b77cc..d1a6fd2e9 100644 --- a/uppsrc/Core/JSON.h +++ b/uppsrc/Core/JSON.h @@ -82,3 +82,213 @@ inline Json& Json::operator()(const char *key, const JsonArray& array) { return CatRaw(key, array); } + +class JsonIO { + const Value *src; + One map; + Value tgt; + +public: + bool IsLoading() const { return src; } + bool IsStoring() const { return !src; } + + const Value& Get() const { ASSERT(IsLoading()); return *src; } + void Set(const Value& v) { ASSERT(IsStoring() && !map); tgt = v; } + void Put(Value& v) { ASSERT(IsStoring()); if(map) v = *map; else v = tgt; } + Value GetResult() const { ASSERT(IsStoring()); return map ? Value(*map) : tgt; } + + template + JsonIO& operator()(const char *key, T& value); + + JsonIO(const Value& src) : src(&src) {} + JsonIO() { src = NULL; } +}; + +struct JsonizeError : Exc { + JsonizeError(const String& s) : Exc(s) {} +}; + +template +void Jsonize(JsonIO& io, T& var) +{ + var.Jsonize(io); +} + +template +JsonIO& JsonIO::operator()(const char *key, T& value) +{ + if(IsLoading()) { + const Value& v = (*src)[key]; + if(!v.IsVoid()) { + JsonIO jio(v); + Jsonize(jio, value); + } + } + else { + ASSERT(tgt.IsVoid()); + if(!map) + map.Create(); + JsonIO jio; + Jsonize(jio, value); + if(jio.map) + map->Add(key, *jio.map); + else + map->Add(key, jio.tgt); + } + return *this; +} + +template +Value StoreAsJsonValue(const T& var) +{ + JsonIO io; + Jsonize(io, const_cast(var)); + return io.GetResult(); +} + +template +void LoadFromJsonValue(T& var, const Value& x) +{ + JsonIO io(x); + Jsonize(io, var); +} + +template +String StoreAsJson(const T& var) +{ + return AsJSON(StoreAsJsonValue(var)); +} + +template +bool LoadFromJson(T& var, const char *json) +{ + try { + LoadFromJsonValue(var, ParseJSON(json)); + } + catch(CParser::Error) { + return false; + } + catch(JsonizeError) { + return false; + } + return true; +} + +template<> void Jsonize(JsonIO& io, int& var); +template<> void Jsonize(JsonIO& io, int64& var); +template<> void Jsonize(JsonIO& io, double& var); +template<> void Jsonize(JsonIO& io, bool& var); +template<> void Jsonize(JsonIO& io, String& var); +template<> void Jsonize(JsonIO& io, WString& var); +template<> void Jsonize(JsonIO& io, Date& var); +template<> void Jsonize(JsonIO& io, Time& var); +template<> void Jsonize(JsonIO& io, Complex& var); + +template +void JsonizeArray(JsonIO& io, T& array) +{ + if(io.IsLoading()) { + const Value& va = io.Get(); + array.SetCount(va.GetCount()); + for(int i = 0; i < va.GetCount(); i++) { + JsonIO jio(va[i]); + Jsonize(jio, array[i]); + } + } + else { + Vector va; + va.SetCount(array.GetCount()); + for(int i = 0; i < array.GetCount(); i++) { + JsonIO jio; + Jsonize(jio, array[i]); + jio.Put(va[i]); + } + io.Set(ValueArray(va)); + } +} + +template +void Jsonize(JsonIO& io, Vector& var) +{ + JsonizeArray, T>(io, var); +} + +template +void Jsonize(JsonIO& io, Array& var) +{ + JsonizeArray, T>(io, var); +} + +template +void JsonizeMap(JsonIO& io, T& map, const char *keyid, const char *valueid) +{ + if(io.IsLoading()) { + map.Clear(); + const Value& va = io.Get(); + map.Reserve(va.GetCount()); + for(int i = 0; i < va.GetCount(); i++) { + K key; + V value; + LoadFromJsonValue(key, va[i][keyid]); + LoadFromJsonValue(value, va[i][valueid]); + map.Add(key, value); + } + } + else { + Vector va; + va.SetCount(map.GetCount()); + for(int i = 0; i < map.GetCount(); i++) + if(!map.IsUnlinked(i)) { + ValueMap item; + item.Add(keyid, StoreAsJsonValue(map.GetKey(i))); + item.Add(valueid, StoreAsJsonValue(map[i])); + va[i] = item; + } + io.Set(ValueArray(va)); + } +} + +template +void Jsonize(JsonIO& io, VectorMap& map) +{ + JsonizeMap(io, map, "key", "value"); +} + +template +void Jsonize(JsonIO& io, ArrayMap& map) +{ + JsonizeMap, K, V>(io, map, "key", "value"); +} + +template +void JsonizeIndex(JsonIO& io, T& index) +{ + if(io.IsLoading()) { + const Value& va = io.Get(); + index.Reserve(va.GetCount()); + for(int i = 0; i < va.GetCount(); i++) { + V v; + LoadFromJsonValue(v, va[i]); + index.Add(v); + } + } + else { + Vector va; + for(int i = 0; i < index.GetCount(); i++) + if(!index.IsUnlinked(i)) + va.Add(StoreAsJsonValue(index[i])); + io.Set(ValueArray(va)); + } +} + +template +void Jsonize(JsonIO& io, Index& var) +{ + JsonizeIndex, T>(io, var); +} + +template +void Jsonize(JsonIO& io, ArrayIndex& var) +{ + JsonizeIndex, T>(io, var); +} diff --git a/uppsrc/Core/Jsonize.h b/uppsrc/Core/Jsonize.h new file mode 100644 index 000000000..e69de29bb