#include "scimpl.h" #include #include #include namespace NSc { struct TJsonError { size_t Offset = 0; TMaybe Reason; }; struct TJsonDeserializer : NJson::TJsonCallbacks { struct TContainer { TValue* Container = nullptr; TValue* LastValue = nullptr; bool ExpectKey = false; TContainer(TValue& v) : Container(&v) , ExpectKey(v.IsDict()) { } bool Add(TStringBuf v, bool allowDuplicated) { if (!ExpectKey || Y_UNLIKELY(!Container->IsDict())) return false; if (!allowDuplicated && Y_UNLIKELY(Container->Has(v))) return false; LastValue = &Container->GetOrAdd(v); ExpectKey = false; return true; } void Push() { LastValue = &Container->Push(); } TValue& NextValue() { if (Container->IsArray()) { Push(); } else if (Container->IsDict()) { ExpectKey = true; } return *(LastValue ? LastValue : Container); } bool IsArray() const { return !!Container && Container->IsArray(); } bool IsDict() const { return !!Container && Container->IsDict(); } }; typedef TVector TStackType; public: TValue& Root; TJsonError& Error; const TJsonOpts& Cfg; TStackType Stack; bool Virgin = true; public: TJsonDeserializer(TValue& root, TJsonError& err, const TJsonOpts& cfg) : Root(root) , Error(err) , Cfg(cfg) { Root.SetNull(); Stack.reserve(10); } bool HasNextValue() const { return Virgin | !Stack.empty(); } TValue& NextValue() { Virgin = false; return Stack.empty() ? Root : Stack.back().NextValue(); } bool OnNull() override { if (Y_UNLIKELY(!HasNextValue())) return false; NextValue().SetNull(); return true; } bool OnEnd() override { return Stack.empty(); } template bool OnValue(T v) { if (Y_UNLIKELY(!HasNextValue())) return false; NextValue() = v; return true; } template bool OnIntValue(T v) { if (Y_UNLIKELY(!HasNextValue())) return false; NextValue().SetIntNumber(v); return true; } bool OnBoolean(bool v) override { if (Y_UNLIKELY(!HasNextValue())) return false; NextValue().SetBool(v); return true; } bool OnInteger(long long v) override { return OnIntValue(v); } bool OnUInteger(unsigned long long v) override { return OnIntValue(v); } bool OnDouble(double v) override { return OnValue(v); } bool OnString(const TStringBuf& v) override { return OnValue(v); } bool OnMapKey(const TStringBuf& k) override { if (Y_UNLIKELY(Stack.empty())) return false; return Stack.back().Add(k, !(Cfg.Opts & TJsonOpts::JO_PARSER_DISALLOW_DUPLICATE_KEYS)); } bool OnOpenMap() override { if (Y_UNLIKELY(!HasNextValue())) return false; Stack.push_back(TContainer(NextValue().SetDict())); return true; } bool OnCloseMap() override { if (Y_UNLIKELY(Stack.empty() || !Stack.back().IsDict())) return false; Stack.pop_back(); return true; } bool OnOpenArray() override { if (Y_UNLIKELY(!HasNextValue())) return false; Stack.push_back(TContainer(NextValue().SetArray())); return true; } bool OnCloseArray() override { if (Y_UNLIKELY(Stack.empty() || !Stack.back().IsArray())) return false; Stack.pop_back(); return true; } void OnError(size_t off, TStringBuf reason) override { Error.Offset = off; Error.Reason = reason; } }; static bool DoParseFromJson(TValue& res, TJsonError& err, TStringBuf json, const TJsonOpts& cfg) { TJsonDeserializer d(res, err, cfg); if (cfg.RelaxedJson) { return NJson::ReadJsonFast(json, &d); } else { TMemoryInput min(json.data(), json.size()); return NJson::ReadJson(&min, &cfg, &d); } } static bool DoParseFromJson(TValue& res, TStringBuf json, const TJsonOpts& cfg) { TJsonError err; return DoParseFromJson(res, err, json, cfg); } TValue TValue::FromJson(TStringBuf v, const TJsonOpts& cfg) { TValue res; if (FromJson(res, v, cfg)) { return res; } else { return DefaultValue(); } } TValue TValue::FromJsonThrow(TStringBuf json, const TJsonOpts& cfg) { TValue res; TJsonError err; if (DoParseFromJson(res, err, json, cfg)) { return res; } TString reason = err.Reason.Empty() ? "NULL" : *err.Reason; ythrow TSchemeParseException(err.Offset, reason) << "JSON error at offset " << err.Offset << " (" << reason << ")"; } bool TValue::FromJson(TValue& res, TStringBuf json, const TJsonOpts& cfg) { if (DoParseFromJson(res, json, cfg)) { return true; } res.SetNull(); return false; } }