aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorm-holger <m-holger@kubitscheck.org>2024-02-09 14:03:53 +0100
committerm-holger <m-holger@kubitscheck.org>2024-02-16 11:32:41 +0100
commit9e90007a4a490dd1335b63079fc3e2a74420911f (patch)
tree69e485e96e7aba218e3e3c3d6c9c29683e8480e9
parentb1b789df4203296a848fec6a3513f30efceb1a45 (diff)
downloadqpdf-9e90007a4a490dd1335b63079fc3e2a74420911f.tar.zst
Add new private class JSON::Writer
Create a simple utility class for writing JSON to a pipeline.
-rw-r--r--include/qpdf/JSON.hh5
-rw-r--r--libqpdf/JSON.cc8
-rw-r--r--libqpdf/qpdf/JSON_writer.hh125
3 files changed, 134 insertions, 4 deletions
diff --git a/include/qpdf/JSON.hh b/include/qpdf/JSON.hh
index e3c8a7dc..3272800d 100644
--- a/include/qpdf/JSON.hh
+++ b/include/qpdf/JSON.hh
@@ -290,8 +290,11 @@ class JSON
QPDF_DLL
qpdf_offset_t getEnd() const;
+ // The following class does not form part of the public API and is for internal use only.
+
+ class Writer;
+
private:
- static std::string encode_string(std::string const& utf8);
static void writeClose(Pipeline* p, bool first, size_t depth, char const* delimeter);
enum value_type_e {
diff --git a/libqpdf/JSON.cc b/libqpdf/JSON.cc
index 27405df7..bc28f236 100644
--- a/libqpdf/JSON.cc
+++ b/libqpdf/JSON.cc
@@ -1,5 +1,7 @@
#include <qpdf/JSON.hh>
+#include <qpdf/JSON_writer.hh>
+
#include <qpdf/BufferInputSource.hh>
#include <qpdf/Pl_Base64.hh>
#include <qpdf/Pl_Concatenate.hh>
@@ -119,7 +121,7 @@ JSON::JSON_array::write(Pipeline* p, size_t depth) const
JSON::JSON_string::JSON_string(std::string const& utf8) :
JSON_value(vt_string),
utf8(utf8),
- encoded(encode_string(utf8))
+ encoded(Writer::encode_string(utf8))
{
}
@@ -211,7 +213,7 @@ JSON::unparse() const
}
std::string
-JSON::encode_string(std::string const& str)
+JSON::Writer::encode_string(std::string const& str)
{
static auto constexpr hexchars = "0123456789abcdef";
@@ -279,7 +281,7 @@ JSON
JSON::addDictionaryMember(std::string const& key, JSON const& val)
{
if (auto* obj = m ? dynamic_cast<JSON_dictionary*>(m->value.get()) : nullptr) {
- return obj->members[encode_string(key)] = val.m ? val : makeNull();
+ return obj->members[Writer::encode_string(key)] = val.m ? val : makeNull();
} else {
throw std::runtime_error("JSON::addDictionaryMember called on non-dictionary");
}
diff --git a/libqpdf/qpdf/JSON_writer.hh b/libqpdf/qpdf/JSON_writer.hh
new file mode 100644
index 00000000..6d870b88
--- /dev/null
+++ b/libqpdf/qpdf/JSON_writer.hh
@@ -0,0 +1,125 @@
+#ifndef JSON_WRITER_HH
+#define JSON_WRITER_HH
+
+#include <qpdf/JSON.hh>
+#include <qpdf/Pipeline.hh>
+
+#include <string_view>
+
+// Writer is a small utility class to aid writing JSON to a pipeline. Methods are designed to allow
+// chaining of calls.
+//
+// Some uses of the class have a significant performance impact. The class is intended purely for
+// internal use to allow it to be adapted as needed to maintain performance.
+class JSON::Writer
+{
+ public:
+ Writer(Pipeline* p, size_t depth) :
+ p(p),
+ indent(2 * depth)
+ {
+ }
+
+ Writer&
+ write(char const* data, size_t len)
+ {
+ p->write(reinterpret_cast<unsigned char const*>(data), len);
+ return *this;
+ }
+
+ Writer&
+ writeNext()
+ {
+ auto n = indent;
+ if (first) {
+ first = false;
+ write(&spaces[1], n % n_spaces + 1);
+ } else {
+ write(&spaces[0], n % n_spaces + 2);
+ }
+ while (n >= n_spaces) {
+ write(&spaces[2], n_spaces);
+ n -= n_spaces;
+ }
+ return *this;
+ }
+
+ Writer&
+ writeStart(char const& c)
+ {
+ write(&c, 1);
+ first = true;
+ indent += 2;
+ return *this;
+ }
+
+ Writer&
+ writeEnd(char const& c)
+ {
+ if (indent > 1) {
+ indent -= 2;
+ }
+ if (!first) {
+ first = true;
+ writeNext();
+ }
+ first = false;
+ write(&c, 1);
+ return *this;
+ }
+
+ Writer&
+ operator<<(std::string_view sv)
+ {
+ p->write(reinterpret_cast<unsigned char const*>(sv.data()), sv.size());
+ return *this;
+ }
+
+ Writer&
+ operator<<(char const* s)
+ {
+ *this << std::string_view{s};
+ return *this;
+ }
+
+ Writer&
+ operator<<(bool val)
+ {
+ *this << (val ? "true" : "false");
+ return *this;
+ }
+
+ Writer&
+ operator<<(int val)
+ {
+ *this << std::to_string(val);
+ return *this;
+ }
+
+ Writer&
+ operator<<(size_t val)
+ {
+ *this << std::to_string(val);
+ return *this;
+ }
+
+ Writer&
+ operator<<(JSON&& j)
+ {
+ j.write(p, indent / 2);
+ return *this;
+ }
+
+ static std::string encode_string(std::string const& utf8);
+
+ private:
+ Pipeline* p;
+ bool first{true};
+ size_t indent;
+
+ static constexpr std::string_view spaces =
+ ",\n ";
+ static constexpr auto n_spaces = spaces.size() - 2;
+};
+
+#endif // JSON_WRITER_HH