123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636 |
- #include "json_reader.h"
- #include "rapidjson_helpers.h"
- #include <contrib/libs/rapidjson/include/rapidjson/error/en.h>
- #include <contrib/libs/rapidjson/include/rapidjson/error/error.h>
- #include <contrib/libs/rapidjson/include/rapidjson/reader.h>
- #include <util/generic/stack.h>
- #include <util/string/cast.h>
- #include <util/system/yassert.h>
- #include <util/string/builder.h>
- namespace NJson {
- namespace {
- TString PrintError(const rapidjson::ParseResult& result) {
- return TStringBuilder() << TStringBuf("Offset: ") << result.Offset()
- << TStringBuf(", Code: ") << (int)result.Code()
- << TStringBuf(", Error: ") << GetParseError_En(result.Code());
- }
- }
- static const size_t DEFAULT_BUFFER_LEN = 65536;
- bool TParserCallbacks::OpenComplexValue(EJsonValueType type) {
- TJsonValue* pvalue;
- switch (CurrentState) {
- case START:
- Value.SetType(type);
- ValuesStack.push_back(&Value);
- break;
- case IN_ARRAY:
- pvalue = &ValuesStack.back()->AppendValue(type);
- ValuesStack.push_back(pvalue);
- break;
- case AFTER_MAP_KEY:
- pvalue = &ValuesStack.back()->InsertValue(Key, type);
- ValuesStack.push_back(pvalue);
- CurrentState = IN_MAP;
- break;
- default:
- return false;
- }
- return true;
- }
- bool TParserCallbacks::CloseComplexValue() {
- if (ValuesStack.empty()) {
- return false;
- }
- ValuesStack.pop_back();
- if (!ValuesStack.empty()) {
- switch (ValuesStack.back()->GetType()) {
- case JSON_ARRAY:
- CurrentState = IN_ARRAY;
- break;
- case JSON_MAP:
- CurrentState = IN_MAP;
- break;
- default:
- return false;
- }
- } else {
- CurrentState = FINISH;
- }
- return true;
- }
- TParserCallbacks::TParserCallbacks(TJsonValue& value, bool throwOnError, bool notClosedBracketIsError)
- : TJsonCallbacks(throwOnError)
- , Value(value)
- , NotClosedBracketIsError(notClosedBracketIsError)
- , CurrentState(START)
- {
- }
- bool TParserCallbacks::OnNull() {
- return SetValue(JSON_NULL);
- }
- bool TParserCallbacks::OnBoolean(bool val) {
- return SetValue(val);
- }
- bool TParserCallbacks::OnInteger(long long val) {
- return SetValue(val);
- }
- bool TParserCallbacks::OnUInteger(unsigned long long val) {
- return SetValue(val);
- }
- bool TParserCallbacks::OnString(const TStringBuf& val) {
- return SetValue(val);
- }
- bool TParserCallbacks::OnDouble(double val) {
- return SetValue(val);
- }
- bool TParserCallbacks::OnOpenArray() {
- bool res = OpenComplexValue(JSON_ARRAY);
- if (res)
- CurrentState = IN_ARRAY;
- return res;
- }
- bool TParserCallbacks::OnCloseArray() {
- return CloseComplexValue();
- }
- bool TParserCallbacks::OnOpenMap() {
- bool res = OpenComplexValue(JSON_MAP);
- if (res)
- CurrentState = IN_MAP;
- return res;
- }
- bool TParserCallbacks::OnCloseMap() {
- return CloseComplexValue();
- }
- bool TParserCallbacks::OnMapKey(const TStringBuf& val) {
- switch (CurrentState) {
- case IN_MAP:
- Key = val;
- CurrentState = AFTER_MAP_KEY;
- break;
- default:
- return false;
- }
- return true;
- }
- bool TParserCallbacks::OnEnd() {
- if (NotClosedBracketIsError){
- return ValuesStack.empty();
- }
- return true;
- }
- TJsonReaderConfig::TJsonReaderConfig()
- : BufferSize(DEFAULT_BUFFER_LEN)
- {
- }
- void TJsonReaderConfig::SetBufferSize(size_t bufferSize) {
- BufferSize = Max((size_t)1, Min(bufferSize, DEFAULT_BUFFER_LEN));
- }
- size_t TJsonReaderConfig::GetBufferSize() const {
- return BufferSize;
- }
- namespace {
- struct TJsonValueBuilderConfig {
- ui64 MaxDepth = 0;
- };
- struct TJsonValueBuilder {
- #ifdef NDEBUG
- using TItem = TJsonValue*;
- inline TJsonValue& Access(TItem& item) const {
- return *item;
- }
- #else
- struct TItem {
- TJsonValue* V;
- size_t DuplicateKeyCount;
- TItem(TJsonValue* v)
- : V(v)
- , DuplicateKeyCount(0)
- {
- }
- };
- inline TJsonValue& Access(TItem& item) const {
- return *item.V;
- }
- #endif
- NJson::TJsonValue& V;
- TStack<TItem> S;
- TJsonValueBuilderConfig Config;
- TJsonValueBuilder(NJson::TJsonValue& v)
- : V(v)
- {
- S.emplace(&V);
- }
- TJsonValueBuilder(NJson::TJsonValue& v, const TJsonValueBuilderConfig& config)
- : V(v)
- , Config(config)
- {
- S.emplace(&V);
- }
- template <class T>
- void Set(const T& t) {
- if (Access(S.top()).IsArray()) {
- Access(S.top()).AppendValue(t);
- } else {
- Access(S.top()) = t;
- S.pop();
- }
- }
- bool Null() {
- Set(NJson::JSON_NULL);
- return true;
- }
- bool Bool(bool b) {
- Set(b);
- return true;
- }
- bool Int(int i) {
- Set(i);
- return true;
- }
- template <class U>
- bool ProcessUint(U u) {
- if (Y_LIKELY(u <= static_cast<ui64>(Max<i64>()))) {
- Set(i64(u));
- } else {
- Set(u);
- }
- return true;
- }
- bool Uint(unsigned u) {
- return ProcessUint(u);
- }
- bool Int64(i64 i) {
- Set(i);
- return true;
- }
- bool Uint64(ui64 u) {
- return ProcessUint(u);
- }
- bool Double(double d) {
- Set(d);
- return true;
- }
- bool RawNumber(const char* str, rapidjson::SizeType length, bool copy) {
- Y_ASSERT(false && "this method should never be called");
- Y_UNUSED(str);
- Y_UNUSED(length);
- Y_UNUSED(copy);
- return true;
- }
- bool String(const char* str, rapidjson::SizeType length, bool copy) {
- Y_ASSERT(copy);
- Set(TStringBuf(str, length));
- return true;
- }
- bool StartObject() {
- if (Access(S.top()).IsArray()) {
- S.emplace(&Access(S.top()).AppendValue(NJson::JSON_MAP));
- if (!IsWithinStackBounds()) {
- return false;
- }
- } else {
- Access(S.top()).SetType(NJson::JSON_MAP);
- }
- return true;
- }
- bool Key(const char* str, rapidjson::SizeType length, bool copy) {
- Y_ASSERT(copy);
- auto& value = Access(S.top())[TStringBuf(str, length)];
- if (Y_UNLIKELY(value.GetType() != JSON_UNDEFINED)) {
- #ifndef NDEBUG
- ++S.top().DuplicateKeyCount;
- #endif
- value.SetType(JSON_UNDEFINED);
- }
- S.emplace(&value);
- if (!IsWithinStackBounds()) {
- return false;
- }
- return true;
- }
- inline int GetDuplicateKeyCount() const {
- #ifdef NDEBUG
- return 0;
- #else
- return S.top().DuplicateKeyCount;
- #endif
- }
- bool EndObject(rapidjson::SizeType memberCount) {
- Y_ASSERT(memberCount == Access(S.top()).GetMap().size() + GetDuplicateKeyCount());
- S.pop();
- return true;
- }
- bool StartArray() {
- if (Access(S.top()).IsArray()) {
- S.emplace(&Access(S.top()).AppendValue(NJson::JSON_ARRAY));
- if (!IsWithinStackBounds()) {
- return false;
- }
- } else {
- Access(S.top()).SetType(NJson::JSON_ARRAY);
- }
- return true;
- }
- bool EndArray(rapidjson::SizeType elementCount) {
- Y_ASSERT(elementCount == Access(S.top()).GetArray().size());
- S.pop();
- return true;
- }
- bool IsWithinStackBounds() {
- return Config.MaxDepth == 0 || (S.size() <= Config.MaxDepth);
- }
- };
- constexpr ui32 ConvertToRapidJsonFlags(ui8 flags) {
- ui32 rapidjsonFlags = rapidjson::kParseNoFlags;
- if (flags & ReaderConfigFlags::NANINF) {
- rapidjsonFlags |= rapidjson::kParseNanAndInfFlag;
- }
- if (flags & ReaderConfigFlags::ITERATIVE) {
- rapidjsonFlags |= rapidjson::kParseIterativeFlag;
- }
- if (flags & ReaderConfigFlags::COMMENTS) {
- rapidjsonFlags |= rapidjson::kParseCommentsFlag;
- }
- if (flags & ReaderConfigFlags::VALIDATE) {
- rapidjsonFlags |= rapidjson::kParseValidateEncodingFlag;
- }
- if (flags & ReaderConfigFlags::ESCAPE) {
- rapidjsonFlags |= rapidjson::kParseEscapedApostropheFlag;
- }
- return rapidjsonFlags;
- }
- template <class TRapidJsonCompliantInputStream, class THandler, ui8 currentFlags = 0>
- auto ReadWithRuntimeFlags(ui8 runtimeFlags,
- rapidjson::Reader& reader,
- TRapidJsonCompliantInputStream& is,
- THandler& handler) {
- if (runtimeFlags == 0) {
- return reader.Parse<ConvertToRapidJsonFlags(currentFlags)>(is, handler);
- }
- #define TRY_EXTRACT_FLAG(flag) \
- if (runtimeFlags & flag) { \
- return ReadWithRuntimeFlags<TRapidJsonCompliantInputStream, THandler, currentFlags | flag>( \
- runtimeFlags ^ flag, reader, is, handler \
- ); \
- }
- TRY_EXTRACT_FLAG(ReaderConfigFlags::NANINF);
- TRY_EXTRACT_FLAG(ReaderConfigFlags::ITERATIVE);
- TRY_EXTRACT_FLAG(ReaderConfigFlags::COMMENTS);
- TRY_EXTRACT_FLAG(ReaderConfigFlags::VALIDATE);
- TRY_EXTRACT_FLAG(ReaderConfigFlags::ESCAPE);
- #undef TRY_EXTRACT_FLAG
- return reader.Parse<ConvertToRapidJsonFlags(currentFlags)>(is, handler);
- }
- template <class TRapidJsonCompliantInputStream, class THandler>
- auto Read(const TJsonReaderConfig& config,
- rapidjson::Reader& reader,
- TRapidJsonCompliantInputStream& is,
- THandler& handler) {
- // validate by default
- ui8 flags = ReaderConfigFlags::VALIDATE;
- if (config.UseIterativeParser) {
- flags |= ReaderConfigFlags::ITERATIVE;
- }
- if (config.AllowComments) {
- flags |= ReaderConfigFlags::COMMENTS;
- }
- if (config.DontValidateUtf8) {
- flags &= ~(ReaderConfigFlags::VALIDATE);
- }
- if (config.AllowEscapedApostrophe) {
- flags |= ReaderConfigFlags::ESCAPE;
- }
- if (config.AllowReadNanInf) {
- flags |= ReaderConfigFlags::NANINF;
- }
- return ReadWithRuntimeFlags(flags, reader, is, handler);
- }
- template <class TRapidJsonCompliantInputStream, class THandler>
- bool ReadJson(TRapidJsonCompliantInputStream& is, const TJsonReaderConfig* config, THandler& handler, bool throwOnError) {
- rapidjson::Reader reader;
- auto result = Read(*config, reader, is, handler);
- if (result.IsError()) {
- if (throwOnError) {
- ythrow TJsonException() << PrintError(result);
- } else {
- return false;
- }
- }
- return true;
- }
- template <class TRapidJsonCompliantInputStream>
- bool ReadJsonTree(TRapidJsonCompliantInputStream& is, const TJsonReaderConfig* config, TJsonValue* out, bool throwOnError) {
- out->SetType(NJson::JSON_NULL);
- TJsonValueBuilder handler(*out, { .MaxDepth = config->MaxDepth });
- return ReadJson(is, config, handler, throwOnError);
- }
- template <class TData>
- bool ReadJsonTreeImpl(TData* in, const TJsonReaderConfig* config, TJsonValue* out, bool throwOnError) {
- std::conditional_t<std::is_same<TData, TStringBuf>::value, TStringBufStreamWrapper, TInputStreamWrapper> is(*in);
- return ReadJsonTree(is, config, out, throwOnError);
- }
- template <class TData>
- bool ReadJsonTreeImpl(TData* in, bool allowComments, TJsonValue* out, bool throwOnError) {
- TJsonReaderConfig config;
- config.AllowComments = allowComments;
- return ReadJsonTreeImpl(in, &config, out, throwOnError);
- }
- template <class TData>
- bool ReadJsonTreeImpl(TData* in, TJsonValue* out, bool throwOnError) {
- return ReadJsonTreeImpl(in, false, out, throwOnError);
- }
- } //namespace
- bool ReadJsonTree(TStringBuf in, TJsonValue* out, bool throwOnError) {
- return ReadJsonTreeImpl(&in, out, throwOnError);
- }
- bool ReadJsonTree(TStringBuf in, bool allowComments, TJsonValue* out, bool throwOnError) {
- return ReadJsonTreeImpl(&in, allowComments, out, throwOnError);
- }
- bool ReadJsonTree(TStringBuf in, const TJsonReaderConfig* config, TJsonValue* out, bool throwOnError) {
- return ReadJsonTreeImpl(&in, config, out, throwOnError);
- }
- bool ReadJsonTree(IInputStream* in, TJsonValue* out, bool throwOnError) {
- return ReadJsonTreeImpl(in, out, throwOnError);
- }
- bool ReadJsonTree(IInputStream* in, bool allowComments, TJsonValue* out, bool throwOnError) {
- return ReadJsonTreeImpl(in, allowComments, out, throwOnError);
- }
- bool ReadJsonTree(IInputStream* in, const TJsonReaderConfig* config, TJsonValue* out, bool throwOnError) {
- return ReadJsonTreeImpl(in, config, out, throwOnError);
- }
- bool ReadJsonFastTree(TStringBuf in, TJsonValue* out, bool throwOnError, bool notClosedBracketIsError) {
- TParserCallbacks cb(*out, throwOnError, notClosedBracketIsError);
- return ReadJsonFast(in, &cb);
- }
- TJsonValue ReadJsonFastTree(TStringBuf in, bool notClosedBracketIsError) {
- TJsonValue value;
- // There is no way to report an error apart from throwing an exception when we return result by value.
- ReadJsonFastTree(in, &value, /* throwOnError = */ true, notClosedBracketIsError);
- return value;
- }
- namespace {
- struct TJsonCallbacksWrapper {
- TJsonCallbacks& Impl;
- TJsonCallbacksWrapper(TJsonCallbacks& impl)
- : Impl(impl)
- {
- }
- bool Null() {
- return Impl.OnNull();
- }
- bool Bool(bool b) {
- return Impl.OnBoolean(b);
- }
- template <class U>
- bool ProcessUint(U u) {
- if (Y_LIKELY(u <= ui64(Max<i64>()))) {
- return Impl.OnInteger(i64(u));
- } else {
- return Impl.OnUInteger(u);
- }
- }
- bool Int(int i) {
- return Impl.OnInteger(i);
- }
- bool Uint(unsigned u) {
- return ProcessUint(u);
- }
- bool Int64(i64 i) {
- return Impl.OnInteger(i);
- }
- bool Uint64(ui64 u) {
- return ProcessUint(u);
- }
- bool Double(double d) {
- return Impl.OnDouble(d);
- }
- bool RawNumber(const char* str, rapidjson::SizeType length, bool copy) {
- Y_ASSERT(false && "this method should never be called");
- Y_UNUSED(str);
- Y_UNUSED(length);
- Y_UNUSED(copy);
- return true;
- }
- bool String(const char* str, rapidjson::SizeType length, bool copy) {
- Y_ASSERT(copy);
- return Impl.OnString(TStringBuf(str, length));
- }
- bool StartObject() {
- return Impl.OnOpenMap();
- }
- bool Key(const char* str, rapidjson::SizeType length, bool copy) {
- Y_ASSERT(copy);
- return Impl.OnMapKey(TStringBuf(str, length));
- }
- bool EndObject(rapidjson::SizeType memberCount) {
- Y_UNUSED(memberCount);
- return Impl.OnCloseMap();
- }
- bool StartArray() {
- return Impl.OnOpenArray();
- }
- bool EndArray(rapidjson::SizeType elementCount) {
- Y_UNUSED(elementCount);
- return Impl.OnCloseArray();
- }
- };
- }
- bool ReadJson(IInputStream* in, TJsonCallbacks* cbs) {
- return ReadJson(in, false, cbs);
- }
- bool ReadJson(IInputStream* in, bool allowComments, TJsonCallbacks* cbs) {
- TJsonReaderConfig config;
- config.AllowComments = allowComments;
- return ReadJson(in, &config, cbs);
- }
- bool ReadJson(IInputStream* in, bool allowComments, bool allowEscapedApostrophe, TJsonCallbacks* cbs) {
- TJsonReaderConfig config;
- config.AllowComments = allowComments;
- config.AllowEscapedApostrophe = allowEscapedApostrophe;
- return ReadJson(in, &config, cbs);
- }
- bool ReadJson(IInputStream* in, const TJsonReaderConfig* config, TJsonCallbacks* cbs) {
- TJsonCallbacksWrapper wrapper(*cbs);
- TInputStreamWrapper is(*in);
- rapidjson::Reader reader;
- auto result = Read(*config, reader, is, wrapper);
- if (result.IsError()) {
- cbs->OnError(result.Offset(), PrintError(result));
- return false;
- }
- return cbs->OnEnd();
- }
- TJsonValue ReadJsonTree(IInputStream* in, bool throwOnError) {
- TJsonValue out;
- ReadJsonTree(in, &out, throwOnError);
- return out;
- }
- TJsonValue ReadJsonTree(IInputStream* in, bool allowComments, bool throwOnError) {
- TJsonValue out;
- ReadJsonTree(in, allowComments, &out, throwOnError);
- return out;
- }
- TJsonValue ReadJsonTree(IInputStream* in, const TJsonReaderConfig* config, bool throwOnError) {
- TJsonValue out;
- ReadJsonTree(in, config, &out, throwOnError);
- return out;
- }
- }
|