json/OutputArchive.h terse/Archive.h terse/archives/Traits.h terse/types/Anchor.h terse/types/ArchiveOffset.h terse/types/ArchiveSize.h terse/types/Blob.h terse/types/CharOutputStreamBuf.h terse/types/DynArray.h terse/types/Transparent.h terse/utils/Base64.h array cassert cstddef cstdint cstring limits memory sstream string tuple type_traits utility vector JSONStreamWriterImpl.h terse::ExtendableJSONOutputArchive terse::ExtendableJSONOutputArchive::SerializationState terse::JSONOutputArchive terse //CopyrightEpicGames,Inc.AllRightsReserved. #pragmaonce #include"terse/Archive.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/CharOutputStreamBuf.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<limits> #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> classExtendableJSONOutputArchive:publicArchive<TExtender>{ private: usingBaseArchive=Archive<TExtender>; public: //Giventhepossibilityofboth32and64bitplatforms,useafixedwidthtypeduringserialization usingSizeType=TSize; usingOffsetType=TOffset; public: ExtendableJSONOutputArchive(TExtender*extender,TStream*stream_,std::uint32_tindentWidth):BaseArchive{extender}, streamBuf{stream_}, stream{&streamBuf}, state{indentWidth,0u,false,false}{ } boolisOk(){ returntrue; } voidsync(){ stream<<std::flush; } voidlabel(constchar*value){ if(state.firstMember){ state.firstMember=false; }else{ stream<<",\n"; } indent(); stream<<"\""<<value<<"\""<<":"; } protected: template<typenameT> voidprocess(Transparent<T>&&source){ pushTransparency(); process(source.data); } voidprocess(Anchor<OffsetType>&/*unused*/){ //Anchor<T>hasnomeaninginanon-binaryformat,soit'sjustsilentlyignored } voidprocess(ArchiveOffset<OffsetType>&source){ process(source.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>&source){ process(source.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(constBlob<T, Args...>&source){ constautoencodedSize=base64encode(source.size()); std::basic_string<char,std::char_traits<char>,typenameBlob<T,Args...>::allocator_type>buffer{encodedSize,'\0', source.get_allocator()}; base64encode(&buffer[0],source.data(),source.size()); //Writebase64-encodeddatafromstringtemporarybuffer process(buffer); } template<typenameT> typenamestd::enable_if<traits::has_save_member<T>::value, void>::typeprocess(constT&source){ constbooltransparent=popTransparency(); if(!transparent){ preStructOutput(); } const_cast<T&>(source).save(*static_cast<TExtender*>(this)); if(!transparent){ postStructOutput(); } } template<typenameT> typenamestd::enable_if<traits::has_serialize_member<T>::value, void>::typeprocess(constT&source){ constbooltransparent=popTransparency(); if(!transparent){ preStructOutput(); } const_cast<T&>(source).serialize(*static_cast<TExtender*>(this)); if(!transparent){ postStructOutput(); } } template<typenameT> typenamestd::enable_if<traits::has_save_function<T>::value, void>::typeprocess(constT&source){ constbooltransparent=popTransparency(); if(!transparent){ preStructOutput(); } save(*static_cast<TExtender*>(this),const_cast<T&>(source)); if(!transparent){ postStructOutput(); } } template<typenameT> typenamestd::enable_if<traits::has_serialize_function<T>::value, void>::typeprocess(constT&source){ constbooltransparent=popTransparency(); if(!transparent){ preStructOutput(); } serialize(*static_cast<TExtender*>(this),const_cast<T&>(source)); if(!transparent){ postStructOutput(); } } template<typenameT> typenamestd::enable_if<!traits::has_save_member<T>::value&&!traits::has_serialize_member<T>::value&& !traits::has_save_function<T>::value&&!traits::has_serialize_function<T>::value, void>::typeprocess(constT&source){ stream<<source; } voidprocess(charsource){ stream<<"\""<<source<<"\""; } voidprocess(std::uint8_tsource){ stream<<static_cast<std::uint32_t>(source); } voidprocess(std::int8_tsource){ stream<<static_cast<std::int32_t>(source); } template<typenameT,std::size_tN> voidprocess(conststd::array<T,N>&source){ processElements(source); } template<typenameT,typename...Args> voidprocess(conststd::vector<T,Args...>&source){ processElements(source); } template<typenameT,typename...Args> voidprocess(constDynArray<T, Args...>&source){ processElements(source); } template<typenameT,typename...Args> voidprocess(conststd::basic_string<T,Args...>&source){ stream<<"\""<<source<<"\""; } template<typenameK,typenameV> voidprocess(conststd::pair<K,V>&source){ stream<<"["; BaseArchive::dispatch(source.first); stream<<","; BaseArchive::dispatch(source.second); stream<<"]"; } template<typenameK,typenameV> voidprocess(conststd::tuple<K,V>&source){ stream<<"["; BaseArchive::dispatch(std::get<0>(source)); stream<<","; BaseArchive::dispatch(std::get<1>(source)); stream<<"]"; } template<classTContainer> voidprocessElements(constTContainer&source){ stream<<"["; if(!source.empty()){ for(autoit=source.begin();;){ BaseArchive::dispatch(*it); ++it; if(it==source.end()){ break; }else{ stream<<","; } } } stream<<"]"; } private: voidindent(){ std::fill_n(std::ostream_iterator<char>(stream),state.indentLevel*state.indentWidth,''); } voidpreStructOutput(){ state.firstMember=true; stream<<"{"; stream<<"\n"; ++state.indentLevel; } voidpostStructOutput(){ --state.indentLevel; stream<<"\n"; indent(); stream<<"}"; } voidpushTransparency(){ state.transparent=true; } boolpopTransparency(){ constbooltransparent=state.transparent; state.transparent=false; returntransparent; } private: structSerializationState{ std::uint32_tindentWidth; std::uint32_tindentLevel; boolfirstMember; booltransparent; }; private: CharOutputStreamBuf<TStream>streamBuf; std::ostreamstream; SerializationStatestate; }; template<classTStream,typenameTSize=std::uint32_t,typenameTOffset=TSize> classJSONOutputArchive:publicExtendableJSONOutputArchive<JSONOutputArchive<TStream,TSize,TOffset>,TStream,TSize, TOffset>{ public: usingBaseArchive=ExtendableJSONOutputArchive<JSONOutputArchive, TStream, TSize, TOffset>; friendArchive<JSONOutputArchive>; public: JSONOutputArchive(TStream*stream_,std::uint32_tindentWidth_):BaseArchive{this,stream_,indentWidth_}{ } private: template<typenameT> voidprocess(T&&dest){ BaseArchive::process(std::forward<T>(dest)); } }; }//namespaceterse