EVOLUTION-MANAGER
Edit File: proj_json_streaming_writer.cpp
/****************************************************************************** * * Project: CPL - Common Portability Library * Purpose: JSon streaming writer * Author: Even Rouault, even.rouault at spatialys.com * ****************************************************************************** * Copyright (c) 2019, Even Rouault <even.rouault at spatialys.com> * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ****************************************************************************/ /*! @cond Doxygen_Suppress */ #include <vector> #include <string> #include "proj_json_streaming_writer.hpp" #include <string.h> #include <sqlite3.h> #include <stdarg.h> #include <cmath> #define CPLAssert(x) do {} while(0) #define CPLIsNan std::isnan #define CPLIsInf std::isinf #define CPL_FRMT_GIB "%lld" #define CPL_FRMT_GUIB "%llu" typedef std::uint64_t GUIntBig; static std::string CPLSPrintf(const char* fmt, ...) { std::string res; res.resize(256); va_list list; va_start(list, fmt); sqlite3_vsnprintf(256, &res[0], fmt, list); va_end(list); res.resize(strlen(&res[0])); return res; } NS_PROJ_START CPLJSonStreamingWriter::CPLJSonStreamingWriter( SerializationFuncType pfnSerializationFunc, void* pUserData): m_pfnSerializationFunc(pfnSerializationFunc), m_pUserData(pUserData) {} CPLJSonStreamingWriter::~CPLJSonStreamingWriter() { CPLAssert( m_nLevel == 0 ); CPLAssert( m_states.empty() ); } void CPLJSonStreamingWriter::Print(const std::string& text) { if( m_pfnSerializationFunc ) { m_pfnSerializationFunc(text.c_str(), m_pUserData); } else { m_osStr += text; } } void CPLJSonStreamingWriter::SetIndentationSize(int nSpaces) { CPLAssert( m_nLevel == 0 ); m_osIndent.clear(); m_osIndent.resize(nSpaces, ' '); } void CPLJSonStreamingWriter::IncIndent() { m_nLevel ++; if( m_bPretty ) m_osIndentAcc += m_osIndent; } void CPLJSonStreamingWriter::DecIndent() { CPLAssert(m_nLevel > 0); m_nLevel --; if( m_bPretty ) m_osIndentAcc.resize(m_osIndentAcc.size() - m_osIndent.size()); } std::string CPLJSonStreamingWriter::FormatString(const std::string& str) { std::string ret; ret += '"'; for( char ch: str ) { switch(ch) { case '"' : ret += "\\\""; break; case '\\': ret += "\\\\"; break; case '\b': ret += "\\b"; break; case '\f': ret += "\\f"; break; case '\n': ret += "\\n"; break; case '\r': ret += "\\r"; break; case '\t': ret += "\\t"; break; default: if( static_cast<unsigned char>(ch) < ' ' ) ret += CPLSPrintf("\\u%04X", ch); else ret += ch; break; } } ret += '"'; return ret; } void CPLJSonStreamingWriter::EmitCommaIfNeeded() { if( m_bWaitForValue ) { m_bWaitForValue = false; } else if( !m_states.empty() ) { if( !m_states.back().bFirstChild ) { Print(","); if( m_bPretty && !m_bNewLineEnabled ) Print(" "); } if( m_bPretty && m_bNewLineEnabled ) { Print("\n"); Print(m_osIndentAcc); } m_states.back().bFirstChild = false; } } void CPLJSonStreamingWriter::StartObj() { EmitCommaIfNeeded(); Print("{"); IncIndent(); m_states.emplace_back(State(true)); } void CPLJSonStreamingWriter::EndObj() { CPLAssert(!m_bWaitForValue); CPLAssert( !m_states.empty() ); CPLAssert( m_states.back().bIsObj ); DecIndent(); if( !m_states.back().bFirstChild ) { if( m_bPretty && m_bNewLineEnabled ) { Print("\n"); Print(m_osIndentAcc); } } m_states.pop_back(); Print("}"); } void CPLJSonStreamingWriter::StartArray() { EmitCommaIfNeeded(); Print("["); IncIndent(); m_states.emplace_back(State(false)); } void CPLJSonStreamingWriter::EndArray() { CPLAssert( !m_states.empty() ); CPLAssert( !m_states.back().bIsObj ); DecIndent(); if( !m_states.back().bFirstChild ) { if( m_bPretty && m_bNewLineEnabled ) { Print("\n"); Print(m_osIndentAcc); } } m_states.pop_back(); Print("]"); } void CPLJSonStreamingWriter::AddObjKey(const std::string& key) { CPLAssert( !m_states.empty() ); CPLAssert( m_states.back().bIsObj ); CPLAssert(!m_bWaitForValue); EmitCommaIfNeeded(); Print(FormatString(key)); Print(m_bPretty ? ": " : ":"); m_bWaitForValue = true; } void CPLJSonStreamingWriter::Add(bool bVal) { EmitCommaIfNeeded(); Print(bVal ? "true" : "false"); } void CPLJSonStreamingWriter::Add(const std::string& str) { EmitCommaIfNeeded(); Print(FormatString(str)); } void CPLJSonStreamingWriter::Add(const char* pszStr) { EmitCommaIfNeeded(); Print(FormatString(pszStr)); } void CPLJSonStreamingWriter::Add(GIntBig nVal) { EmitCommaIfNeeded(); Print(CPLSPrintf(CPL_FRMT_GIB, nVal)); } void CPLJSonStreamingWriter::Add(GUInt64 nVal) { EmitCommaIfNeeded(); Print(CPLSPrintf(CPL_FRMT_GUIB, static_cast<GUIntBig>(nVal))); } void CPLJSonStreamingWriter::Add(float fVal, int nPrecision) { EmitCommaIfNeeded(); if( CPLIsNan(fVal) ) { Print("\"NaN\""); } else if( CPLIsInf(fVal) ) { Print( fVal > 0 ? "\"Infinity\"" : "\"-Infinity\"" ); } else { char szFormatting[10]; snprintf(szFormatting, sizeof(szFormatting), "%%.%dg", nPrecision); Print(CPLSPrintf(szFormatting, fVal)); } } void CPLJSonStreamingWriter::Add(double dfVal, int nPrecision) { EmitCommaIfNeeded(); if( CPLIsNan(dfVal) ) { Print("\"NaN\""); } else if( CPLIsInf(dfVal) ) { Print( dfVal > 0 ? "\"Infinity\"" : "\"-Infinity\"" ); } else { char szFormatting[10]; snprintf(szFormatting, sizeof(szFormatting), "%%.%dg", nPrecision); Print(CPLSPrintf(szFormatting, dfVal)); } } void CPLJSonStreamingWriter::AddNull() { EmitCommaIfNeeded(); Print("null"); } NS_PROJ_END /*! @endcond */