aboutsummaryrefslogtreecommitdiffstats
path: root/libqpdf/qpdf/JSON_writer.hh
blob: 3f770c585bf2047bb8e6d786ff466fc998f9fb8e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#ifndef JSON_WRITER_HH
#define JSON_WRITER_HH

#include <qpdf/JSON.hh>
#include <qpdf/Pipeline.hh>
#include <qpdf/Pl_Base64.hh>
#include <qpdf/Pl_Concatenate.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&
    writeBase64(std::string_view sv)
    {
        Pl_Concatenate cat{"writer concat", p};
        Pl_Base64 base{"writer base64", &cat, Pl_Base64::a_encode};
        base.write(reinterpret_cast<unsigned char const*>(sv.data()), sv.size());
        base.finish();
        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