aboutsummaryrefslogtreecommitdiff
path: root/src
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
parent1da55c8be619a21153845607a553c9d1206bc792 (diff)
downloadPROJ-17f0b0b3bc65ffba39bf6f22a12b2cc7fcb9bafd.tar.gz
PROJ-17f0b0b3bc65ffba39bf6f22a12b2cc7fcb9bafd.zip
Proof-of-concept of JSON export limited to PrimeMeridian (refs #1545)
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am6
-rw-r--r--src/iso19111/common.cpp65
-rw-r--r--src/iso19111/datum.cpp35
-rw-r--r--src/iso19111/io.cpp87
-rw-r--r--src/iso19111/metadata.cpp20
-rw-r--r--src/lib_proj.cmake2
-rw-r--r--src/proj_json_streaming_writer.cpp297
-rw-r--r--src/proj_json_streaming_writer.hpp145
8 files changed, 655 insertions, 2 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index aed5a393..e50a5638 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -11,7 +11,7 @@ AM_CPPFLAGS = -DPROJ_LIB=\"$(pkgdatadir)\" \
AM_CXXFLAGS = @CXX_WFLAGS@ @FLTO_FLAG@
include_HEADERS = proj.h proj_experimental.h proj_constants.h proj_api.h geodesic.h \
- org_proj4_PJ.h proj_symbol_rename.h
+ org_proj4_PJ.h proj_symbol_rename.h proj_json_streaming_writer.hpp
EXTRA_DIST = bin_cct.cmake bin_gie.cmake bin_cs2cs.cmake \
bin_geod.cmake bin_proj.cmake bin_projinfo.cmake \
@@ -208,7 +208,9 @@ libproj_la_SOURCES = \
wkt1_parser.h wkt1_parser.cpp \
wkt1_generated_parser.h wkt1_generated_parser.c \
wkt2_parser.h wkt2_parser.cpp \
- wkt2_generated_parser.h wkt2_generated_parser.c
+ wkt2_generated_parser.h wkt2_generated_parser.c \
+ \
+ proj_json_streaming_writer.cpp
# The sed hack is to please MSVC
diff --git a/src/iso19111/common.cpp b/src/iso19111/common.cpp
index d46da0da..f2a51032 100644
--- a/src/iso19111/common.cpp
+++ b/src/iso19111/common.cpp
@@ -236,6 +236,54 @@ void UnitOfMeasure::_exportToWKT(
}
formatter->endNode();
}
+
+// ---------------------------------------------------------------------------
+
+void UnitOfMeasure::_exportToJSON(
+ JSONFormatter *formatter) const // throw(FormattingException)
+{
+ auto &writer = formatter->writer();
+ PROJ::CPLJSonStreamingWriter::ObjectContext objContext(writer);
+ writer.AddObjKey("type");
+ const auto l_type = type();
+ if (l_type == Type::LINEAR) {
+ writer.Add("LinearUnit");
+ } else if (l_type == Type::ANGULAR) {
+ writer.Add("AngularUnit");
+ } else if (l_type == Type::SCALE) {
+ writer.Add("ScaleUnit");
+ } else if (l_type == Type::TIME) {
+ writer.Add("TimeUnit");
+ } else if (l_type == Type::PARAMETRIC) {
+ writer.Add("ParametericUnit");
+ } else {
+ writer.Add("Unit");
+ }
+
+ writer.AddObjKey("name");
+ const auto &l_name = name();
+ writer.Add(l_name);
+
+ const auto &factor = conversionToSI();
+ writer.AddObjKey("conversion_factor");
+ writer.Add(factor, 15);
+
+ const auto &l_codeSpace = codeSpace();
+ if (!l_codeSpace.empty() && formatter->outputId()) {
+ writer.AddObjKey("id");
+ PROJ::CPLJSonStreamingWriter::ObjectContext idContext(writer);
+ writer.AddObjKey("authority");
+ writer.Add(l_codeSpace);
+ writer.AddObjKey("code");
+ const auto &l_code = code();
+ try {
+ writer.Add(std::stoi(l_code));
+ } catch (const std::exception &) {
+ writer.Add(l_code);
+ }
+ }
+}
+
//! @endcond
// ---------------------------------------------------------------------------
@@ -815,6 +863,23 @@ void IdentifiedObject::formatRemarks(WKTFormatter *formatter) const {
// ---------------------------------------------------------------------------
+void IdentifiedObject::formatID(JSONFormatter *formatter) const {
+ const auto &ids(identifiers());
+ auto &writer = formatter->writer();
+ if (ids.size() == 1) {
+ writer.AddObjKey("id");
+ ids.front()->_exportToJSON(formatter);
+ } else if (!ids.empty()) {
+ writer.AddObjKey("ids");
+ PROJ::CPLJSonStreamingWriter::ArrayContext arrayContext(writer);
+ for (const auto &id : ids) {
+ id->_exportToJSON(formatter);
+ }
+ }
+}
+
+// ---------------------------------------------------------------------------
+
bool IdentifiedObject::_isEquivalentTo(
const util::IComparable *other,
util::IComparable::Criterion criterion) const {
diff --git a/src/iso19111/datum.cpp b/src/iso19111/datum.cpp
index bf3092c1..6ba219d4 100644
--- a/src/iso19111/datum.cpp
+++ b/src/iso19111/datum.cpp
@@ -348,6 +348,41 @@ void PrimeMeridian::_exportToWKT(
// ---------------------------------------------------------------------------
//! @cond Doxygen_Suppress
+void PrimeMeridian::_exportToJSON(
+ io::JSONFormatter *formatter) const // throw(FormattingException)
+{
+ auto &writer = formatter->writer();
+ PROJ::CPLJSonStreamingWriter::ObjectContext objectContext(writer);
+
+ writer.AddObjKey("type");
+ writer.Add("PrimeMeridian");
+
+ writer.AddObjKey("name");
+ std::string l_name =
+ name()->description().has_value() ? nameStr() : "Greenwich";
+ writer.Add(l_name);
+
+ const auto &l_long = longitude();
+ writer.AddObjKey("longitude");
+ {
+ PROJ::CPLJSonStreamingWriter::ObjectContext longitudeContext(writer);
+ writer.AddObjKey("value");
+ writer.Add(l_long.value(), 15);
+
+ const auto &unit = l_long.unit();
+ writer.AddObjKey("unit");
+ unit._exportToJSON(formatter);
+ }
+
+ if (formatter->outputId()) {
+ formatID(formatter);
+ }
+}
+//! @endcond
+
+// ---------------------------------------------------------------------------
+
+//! @cond Doxygen_Suppress
std::string
PrimeMeridian::getPROJStringWellKnownName(const common::Angle &angle) {
const double valRad = angle.getSIValue();
diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp
index 0db97d0b..0c9f8a0c 100644
--- a/src/iso19111/io.cpp
+++ b/src/iso19111/io.cpp
@@ -60,6 +60,7 @@
#include "proj_constants.h"
+#include "proj_json_streaming_writer.hpp"
#include "wkt1_parser.h"
#include "wkt2_parser.h"
@@ -8016,5 +8017,91 @@ PROJStringParser::createFromPROJString(const std::string &projString) {
nullptr, nullptr, {});
}
+// ---------------------------------------------------------------------------
+
+//! @cond Doxygen_Suppress
+struct JSONFormatter::Private {
+ PROJ::CPLJSonStreamingWriter writer_{nullptr, nullptr};
+ DatabaseContextPtr dbContext_{};
+ std::string result_{};
+};
+//! @endcond
+
+// ---------------------------------------------------------------------------
+
+/** \brief Constructs a new formatter.
+ *
+ * A formatter can be used only once (its internal state is mutated)
+ *
+ * @return new formatter.
+ */
+JSONFormatterNNPtr JSONFormatter::create( // cppcheck-suppress passedByValue
+ DatabaseContextPtr dbContext) {
+ auto ret = NN_NO_CHECK(JSONFormatter::make_unique<JSONFormatter>());
+ ret->d->dbContext_ = dbContext;
+ return ret;
+}
+
+// ---------------------------------------------------------------------------
+
+/** \brief Whether to use multi line output or not. */
+JSONFormatter &JSONFormatter::setMultiLine(bool multiLine) noexcept {
+ d->writer_.SetPrettyFormatting(multiLine);
+ return *this;
+}
+
+// ---------------------------------------------------------------------------
+
+/** \brief Set number of spaces for each indentation level (defaults to 4).
+ */
+JSONFormatter &JSONFormatter::setIndentationWidth(int width) noexcept {
+ d->writer_.SetIndentationSize(width);
+ return *this;
+}
+
+// ---------------------------------------------------------------------------
+
+//! @cond Doxygen_Suppress
+
+JSONFormatter::JSONFormatter() : d(internal::make_unique<Private>()) {}
+
+// ---------------------------------------------------------------------------
+
+JSONFormatter::~JSONFormatter() = default;
+
+// ---------------------------------------------------------------------------
+
+PROJ::CPLJSonStreamingWriter &JSONFormatter::writer() const {
+ return d->writer_;
+}
+
+// ---------------------------------------------------------------------------
+
+bool JSONFormatter::outputId() const { return true; }
+
+//! @endcond
+
+// ---------------------------------------------------------------------------
+
+/** \brief Return the serialized JSON.
+ */
+const std::string &JSONFormatter::toString() const {
+ return d->writer_.GetString();
+}
+
+// ---------------------------------------------------------------------------
+
+//! @cond Doxygen_Suppress
+IJSONExportable::~IJSONExportable() = default;
+
+// ---------------------------------------------------------------------------
+
+std::string IJSONExportable::exportToJSON(JSONFormatter *formatter) const {
+ _exportToJSON(formatter);
+ return formatter->toString();
+}
+
+//! @endcond
+
} // namespace io
NS_PROJ_END
diff --git a/src/iso19111/metadata.cpp b/src/iso19111/metadata.cpp
index 3725b072..761b909b 100644
--- a/src/iso19111/metadata.cpp
+++ b/src/iso19111/metadata.cpp
@@ -1088,6 +1088,26 @@ void Identifier::_exportToWKT(WKTFormatter *formatter) const {
}
}
}
+
+// ---------------------------------------------------------------------------
+
+void Identifier::_exportToJSON(JSONFormatter *formatter) const {
+ const std::string &l_code = code();
+ const std::string &l_codeSpace = *codeSpace();
+ if (!l_codeSpace.empty() && !l_code.empty()) {
+ auto &writer = formatter->writer();
+ PROJ::CPLJSonStreamingWriter::ObjectContext objContext(writer);
+ writer.AddObjKey("authority");
+ writer.Add(l_codeSpace);
+ writer.AddObjKey("code");
+ try {
+ writer.Add(std::stoi(l_code));
+ } catch (const std::exception &) {
+ writer.Add(l_code);
+ }
+ }
+}
+
//! @endcond
// ---------------------------------------------------------------------------
diff --git a/src/lib_proj.cmake b/src/lib_proj.cmake
index 5a0a8070..bad60324 100644
--- a/src/lib_proj.cmake
+++ b/src/lib_proj.cmake
@@ -285,6 +285,7 @@ set(SRC_LIBPROJ_CORE
wkt_parser.cpp
wkt_parser.hpp
zpoly1.cpp
+ proj_json_streaming_writer.cpp
${CMAKE_CURRENT_BINARY_DIR}/proj_config.h
)
@@ -293,6 +294,7 @@ set(HEADERS_LIBPROJ
proj.h
proj_experimental.h
proj_constants.h
+ proj_json_streaming_writer.hpp
geodesic.h
)
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 */
diff --git a/src/proj_json_streaming_writer.hpp b/src/proj_json_streaming_writer.hpp
new file mode 100644
index 00000000..d1510449
--- /dev/null
+++ b/src/proj_json_streaming_writer.hpp
@@ -0,0 +1,145 @@
+/******************************************************************************
+ *
+ * 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.
+ ****************************************************************************/
+
+#ifndef PROJ_JSON_STREAMING_WRITER_H
+#define PROJ_JSON_STREAMING_WRITER_H
+
+/*! @cond Doxygen_Suppress */
+
+#include <vector>
+#include <string>
+
+#define CPL_DLL
+
+namespace PROJ
+{
+
+typedef std::int64_t GIntBig;
+typedef std::uint64_t GUInt64;
+
+class CPL_DLL CPLJSonStreamingWriter
+{
+public:
+ typedef void (*SerializationFuncType)(const char* pszTxt, void* pUserData);
+
+private:
+ CPLJSonStreamingWriter(const CPLJSonStreamingWriter&) = delete;
+ CPLJSonStreamingWriter& operator=(const CPLJSonStreamingWriter&) = delete;
+
+ std::string m_osStr{};
+ SerializationFuncType m_pfnSerializationFunc = nullptr;
+ void* m_pUserData = nullptr;
+ bool m_bPretty = true;
+ std::string m_osIndent = std::string(" ");
+ std::string m_osIndentAcc{};
+ int m_nLevel = 0;
+ bool m_bNewLineEnabled = true;
+ struct State
+ {
+ bool bIsObj = false;
+ bool bFirstChild = true;
+ explicit State(bool bIsObjIn): bIsObj(bIsObjIn) {}
+ };
+ std::vector<State> m_states{};
+ bool m_bWaitForValue = false;
+
+ void Print(const std::string& text);
+ void IncIndent();
+ void DecIndent();
+ static std::string FormatString(const std::string& str);
+ void EmitCommaIfNeeded();
+
+public:
+ CPLJSonStreamingWriter(SerializationFuncType pfnSerializationFunc,
+ void* pUserData);
+ ~CPLJSonStreamingWriter();
+
+ void SetPrettyFormatting(bool bPretty) { m_bPretty = bPretty; }
+ void SetIndentationSize(int nSpaces);
+
+ // cppcheck-suppress functionStatic
+ const std::string& GetString() const { return m_osStr; }
+
+ void Add(const std::string& str);
+ void Add(const char* pszStr);
+ void Add(bool bVal);
+ void Add(int nVal) { Add(static_cast<GIntBig>(nVal)); }
+ void Add(unsigned int nVal) { Add(static_cast<GIntBig>(nVal)); }
+ void Add(GIntBig nVal);
+ void Add(GUInt64 nVal);
+ void Add(float fVal, int nPrecision = 9);
+ void Add(double dfVal, int nPrecision = 18);
+ void AddNull();
+
+ void StartObj();
+ void EndObj();
+ void AddObjKey(const std::string& key);
+ struct CPL_DLL ObjectContext
+ {
+ CPLJSonStreamingWriter& m_serializer;
+ explicit ObjectContext(CPLJSonStreamingWriter& serializer):
+ m_serializer(serializer) { m_serializer.StartObj(); }
+ ~ObjectContext() { m_serializer.EndObj(); }
+ };
+
+ void StartArray();
+ void EndArray();
+ struct CPL_DLL ArrayContext
+ {
+ CPLJSonStreamingWriter& m_serializer;
+ bool m_bForceSingleLine;
+ bool m_bNewLineEnabledBackup;
+
+ ArrayContext(CPLJSonStreamingWriter& serializer,
+ bool bForceSingleLine = false):
+ m_serializer(serializer),
+ m_bForceSingleLine(bForceSingleLine),
+ m_bNewLineEnabledBackup(serializer.GetNewLine())
+ {
+ if( m_bForceSingleLine )
+ serializer.SetNewline(false);
+ m_serializer.StartArray();
+
+ }
+ ~ArrayContext()
+ {
+ m_serializer.EndArray();
+ if( m_bForceSingleLine )
+ m_serializer.SetNewline(m_bNewLineEnabledBackup);
+ }
+ };
+
+ bool GetNewLine() const { return m_bNewLineEnabled; }
+ void SetNewline(bool bEnabled) { m_bNewLineEnabled = bEnabled; }
+};
+
+} // namespace PROJ
+
+/*! @endcond */
+
+#endif // PROJ_JSON_STREAMING_WRITER_H