aboutsummaryrefslogtreecommitdiff
path: root/src/proj_json_streaming_writer.cpp
diff options
context:
space:
mode:
authorEven Rouault <even.rouault@spatialys.com>2019-07-06 02:03:50 +0200
committerEven Rouault <even.rouault@spatialys.com>2019-07-06 02:27:46 +0200
commit17f0b0b3bc65ffba39bf6f22a12b2cc7fcb9bafd (patch)
tree5993d701145e2117fb8598faa186312b98d54f00 /src/proj_json_streaming_writer.cpp
parent1da55c8be619a21153845607a553c9d1206bc792 (diff)
downloadPROJ-17f0b0b3bc65ffba39bf6f22a12b2cc7fcb9bafd.tar.gz
PROJ-17f0b0b3bc65ffba39bf6f22a12b2cc7fcb9bafd.zip
Proof-of-concept of JSON export limited to PrimeMeridian (refs #1545)
Diffstat (limited to 'src/proj_json_streaming_writer.cpp')
-rw-r--r--src/proj_json_streaming_writer.cpp297
1 files changed, 297 insertions, 0 deletions
diff --git a/src/proj_json_streaming_writer.cpp b/src/proj_json_streaming_writer.cpp
new file mode 100644
index 00000000..3198308b
--- /dev/null
+++ b/src/proj_json_streaming_writer.cpp
@@ -0,0 +1,297 @@
+/******************************************************************************
+ *
+ * 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;
+}
+
+namespace PROJ
+{
+
+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");
+}
+
+} // namespace PROJ
+
+/*! @endcond */