json/InputArchive.h terse/Archive.h terse/archives/Common.h terse/archives/Traits.h terse/types/Anchor.h terse/types/ArchiveOffset.h terse/types/ArchiveSize.h terse/types/Blob.h terse/types/CharInputStreamBuf.h terse/types/DynArray.h terse/types/Transparent.h terse/utils/Base64.h array cassert cstddef cstdint cstring memory sstream string tuple type_traits utility vector JSONStreamReaderImpl.h terse::ExtendableJSONInputArchive terse::ExtendableJSONInputArchive::SerializationState terse::JSONInputArchive terse //CopyrightEpicGames,Inc.AllRightsReserved. #pragmaonce #include"terse/Archive.h" #include"terse/archives/Common.h" #include"terse/archives/Traits.h" #include"terse/types/Anchor.h" #include"terse/types/ArchiveOffset.h" #include"terse/types/ArchiveSize.h" #include"terse/types/Blob.h" #include"terse/types/CharInputStreamBuf.h" #include"terse/types/DynArray.h" #include"terse/types/Transparent.h" #include"terse/utils/Base64.h" #ifdef_MSC_VER #pragmawarning(push) #pragmawarning(disable:43654987) #endif #include<array> #include<cassert> #include<cstddef> #include<cstdint> #include<cstring> #include<memory> #include<sstream> #include<string> #include<tuple> #include<type_traits> #include<utility> #include<vector> #ifdef_MSC_VER #pragmawarning(pop) #endif namespaceterse{ template<classTExtender,classTStream,typenameTSize,typenameTOffset> classExtendableJSONInputArchive:publicArchive<TExtender>{ public: //Giventhepossibilityofboth32and64bitplatforms,useafixedwidthtypeduringserialization usingSizeType=TSize; usingOffsetType=TOffset; private: usingBaseArchive=Archive<TExtender>; public: ExtendableJSONInputArchive(TExtender*extender,TStream*stream_):BaseArchive{extender},streamBuf{stream_}, stream{&streamBuf},state{false,false,false}{ } boolisOk()const{ return!state.malformed; } voidsync(){ } voidlabel(constchar*value){ if(state.malformed){ return; } skipWhiteSpace(); if(state.firstMember){ state.firstMember=false; }else{ if(!expectChar(',')){ return; } skipWhiteSpace(); } if(!expectChar('"')){ return; } for(std::size_ti={};i<std::strlen(value);++i){ if(!expectChar(value[i])){ return; } } if(!expectChar('"')){ return; } skipWhiteSpace(); if(!expectChar(':')){ return; } skipWhiteSpace(); } protected: template<typenameT> voidprocess(Transparent<T>&&dest){ pushTransparency(); process(dest.data); } voidprocess(Anchor<OffsetType>&/*unused*/){ //Anchor<T>hasnomeaninginanon-binaryformat,soit'sjustsilentlyignored } voidprocess(ArchiveOffset<OffsetType>&dest){ process(dest.value); } voidprocess(typenameArchiveOffset<OffsetType>::Proxy&/*unused*/){ //ArchiveOffset<T>::Proxyhasnomeaninginanon-binaryformat,soit'sjustsilentlyignored } voidprocess(typenameArchiveOffset<OffsetType>::Proxy&&/*unused*/){ //ArchiveOffset<T>::Proxyhasnomeaninginanon-binaryformat,soit'sjustsilentlyignored } voidprocess(ArchiveSize<SizeType, OffsetType>&dest){ process(dest.value); } voidprocess(typenameArchiveSize<SizeType, OffsetType>::Proxy&/*unused*/){ //ArchiveSize<T,U>::Proxyhasnomeaninginanon-binaryformat,soit'sjustsilentlyignored } voidprocess(typenameArchiveSize<SizeType, OffsetType>::Proxy&&/*unused*/){ //ArchiveSize<T,U>::Proxyhasnomeaninginanon-binaryformat,soit'sjustsilentlyignored } template<typenameT,typename...Args> voidprocess(Blob<T, Args...>&dest){ std::basic_string<char,std::char_traits<char>, typenameBlob<T,Args...>::allocator_type>buffer{dest.get_allocator()}; //dest.size()isthesizeofthedecodeddataalready(setbyuser),fromwhichthelengthofthe //encodeddataiscalculatedandusedtoreservestorageforthetemporarybufferwheretheencoded //dataisfirstloaded buffer.reserve(base64encode(dest.size())); //Readbase64-encodeddataintotemporarybuffer process(buffer); //Decodefromtempbufferintodest base64decode(dest.data(),buffer.data(),buffer.size()); } template<typenameT> typenamestd::enable_if<traits::has_load_member<T>::value, void>::typeprocess(T&dest){ if(state.malformed){ return; } constbooltransparent=popTransparency(); if(!transparent){ preStructInput(); } dest.load(*static_cast<TExtender*>(this)); if(!transparent){ postStructInput(); } } template<typenameT> typenamestd::enable_if<traits::has_serialize_member<T>::value, void>::typeprocess(T&dest){ if(state.malformed){ return; } constbooltransparent=popTransparency(); if(!transparent){ preStructInput(); } dest.serialize(*static_cast<TExtender*>(this)); if(!transparent){ postStructInput(); } } template<typenameT> typenamestd::enable_if<traits::has_load_function<T>::value, void>::typeprocess(T&dest){ if(state.malformed){ return; } constbooltransparent=popTransparency(); if(!transparent){ preStructInput(); } load(*static_cast<TExtender*>(this),dest); if(!transparent){ postStructInput(); } } template<typenameT> typenamestd::enable_if<traits::has_serialize_function<T>::value, void>::typeprocess(T&dest){ if(state.malformed){ return; } constbooltransparent=popTransparency(); if(!transparent){ preStructInput(); } serialize(*static_cast<TExtender*>(this),dest); if(!transparent){ postStructInput(); } } template<typenameT> typenamestd::enable_if<!traits::has_load_member<T>::value&&!traits::has_serialize_member<T>::value&& !traits::has_load_function<T>::value&&!traits::has_serialize_function<T>::value, void>::typeprocess(T&dest){ if(state.malformed){ return; } stream>>dest; } voidprocess(char&dest){ if(!expectChar('"')){ return; } if(!readChar(&dest)){ return; } if(!expectChar('"')){ return; } } voidprocess(std::uint8_t&dest){ std::uint16_ttemp={}; stream>>temp; dest=static_cast<std::uint8_t>(temp); } voidprocess(std::int8_t&dest){ std::int16_ttemp={}; stream>>temp; dest=static_cast<std::int8_t>(temp); } template<typenameT,std::size_tN> voidprocess(std::array<T,N>&dest){ if(state.malformed){ return; } skipWhiteSpace(); if(!expectChar('[')){ return; } skipWhiteSpace(); if(stream.peek()==']'){ expectChar(']'); return; } for(auto&element:dest){ BaseArchive::dispatch(element); if(state.malformed){ return; } skipWhiteSpace(); charch={}; if(!readChar(&ch)){ return; } if(ch==','){ skipWhiteSpace(); }elseif(ch==']'){ break; } } skipWhiteSpace(); } template<typenameT,typename...Args> voidprocess(std::vector<T,Args...>&dest){ if(state.malformed){ return; } skipWhiteSpace(); if(!expectChar('[')){ return; } skipWhiteSpace(); if(stream.peek()==']'){ expectChar(']'); return; } dest.clear(); while(true){ dest.push_back(impl::ValueFactory<T>::create(dest.get_allocator())); BaseArchive::dispatch(dest.back()); if(state.malformed){ return; } skipWhiteSpace(); charch={}; if(!readChar(&ch)){ return; } if(ch==','){ skipWhiteSpace(); }elseif(ch==']'){ break; } } skipWhiteSpace(); } template<typenameT,typename...Args> voidprocess(DynArray<T, Args...>&dest){ if(state.malformed){ return; } skipWhiteSpace(); if(!expectChar('[')){ return; } skipWhiteSpace(); if(stream.peek()==']'){ expectChar(']'); return; } dest.resize_uninitialized(1ul); std::size_tvalidElementCount={}; while(true){ BaseArchive::dispatch(dest[validElementCount]); if(state.malformed){ break; } ++validElementCount; if(validElementCount==dest.size()){ dest.resize_uninitialized(dest.size()*2ul); } skipWhiteSpace(); charch={}; if(!readChar(&ch)){ break; } if(ch==','){ skipWhiteSpace(); }elseif(ch==']'){ break; } } dest.resize(validElementCount); skipWhiteSpace(); } template<typenameT,typename...Args> voidprocess(std::basic_string<T,Args...>&dest){ if(state.malformed){ return; } if(!expectChar('"')){ return; } dest.clear(); charch={}; while(readChar(&ch)){ if(ch=='"'){ return; }else{ dest.push_back(ch); } } //Thisshouldnotbereachedifthestringwasproperlyquoted state.malformed=true; } template<typenameK,typenameV> voidprocess(std::pair<K,V>&dest){ if(state.malformed){ return; } skipWhiteSpace(); if(!expectChar('[')){ return; } skipWhiteSpace(); BaseArchive::dispatch(dest.first); skipWhiteSpace(); if(!expectChar(',')){ return; } skipWhiteSpace(); BaseArchive::dispatch(dest.second); skipWhiteSpace(); if(!expectChar(']')){ return; } skipWhiteSpace(); } template<typenameK,typenameV> voidprocess(std::tuple<K,V>&dest){ if(state.malformed){ return; } skipWhiteSpace(); if(!expectChar('[')){ return; } skipWhiteSpace(); BaseArchive::dispatch(std::get<0>(dest)); skipWhiteSpace(); if(!expectChar(',')){ return; } skipWhiteSpace(); BaseArchive::dispatch(std::get<1>(dest)); skipWhiteSpace(); if(!expectChar(']')){ return; } skipWhiteSpace(); } private: boolreadChar(char*dest){ if(!stream.read(dest,1)){ state.malformed=true; returnfalse; } returntrue; } boolexpectChar(charexpected){ charch={}; if(!readChar(&ch)){ returnfalse; } if(ch!=expected){ state.malformed=true; returnfalse; } returntrue; } voidskipWhiteSpace(){ std::ws(stream); } voidpreStructInput(){ state.firstMember=true; skipWhiteSpace(); if(!expectChar('{')){ return; } skipWhiteSpace(); } voidpostStructInput(){ skipWhiteSpace(); if(!expectChar('}')){ return; } skipWhiteSpace(); } voidpushTransparency(){ state.transparent=true; } boolpopTransparency(){ constbooltransparent=state.transparent; state.transparent=false; returntransparent; } private: structSerializationState{ boolmalformed; boolfirstMember; booltransparent; }; private: CharInputStreamBuf<TStream>streamBuf; std::istreamstream; SerializationStatestate; }; template<classTStream,typenameTSize=std::uint32_t,typenameTOffset=TSize> classJSONInputArchive:publicExtendableJSONInputArchive<JSONInputArchive<TStream,TSize,TOffset>,TStream,TSize,TOffset>{ private: usingBaseArchive=ExtendableJSONInputArchive<JSONInputArchive, TStream, TSize, TOffset>; friendArchive<JSONInputArchive>; public: explicitJSONInputArchive(TStream*stream_):BaseArchive{this,stream_}{ } private: template<typenameT> voidprocess(T&&dest){ BaseArchive::process(std::forward<T>(dest)); } }; }//namespaceterse