diff options
author | m-holger <m-holger@kubitscheck.org> | 2024-02-09 14:03:53 +0100 |
---|---|---|
committer | m-holger <m-holger@kubitscheck.org> | 2024-02-16 11:32:41 +0100 |
commit | 9e90007a4a490dd1335b63079fc3e2a74420911f (patch) | |
tree | 69e485e96e7aba218e3e3c3d6c9c29683e8480e9 | |
parent | b1b789df4203296a848fec6a3513f30efceb1a45 (diff) | |
download | qpdf-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.hh | 5 | ||||
-rw-r--r-- | libqpdf/JSON.cc | 8 | ||||
-rw-r--r-- | libqpdf/qpdf/JSON_writer.hh | 125 |
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 |