1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  */
9 #pragma once
10 
11 #include <tools/toolsdllapi.h>
12 #include <rtl/ustring.hxx>
13 
14 namespace rtl
15 {
16 class OStringBuffer;
17 }
18 
19 /** Simple JSON encoder designed specifically for LibreOfficeKit purposes.
20  *
21  * (1) Minimal allocations/re-allocations/copying
22  * (2) Small/simple JSON documents
23  * (3) ascii property names
24  */
25 namespace tools
26 {
27 class ScopedJsonWriterNode;
28 class ScopedJsonWriterArray;
29 class ScopedJsonWriterStruct;
30 
31 class TOOLS_DLLPUBLIC JsonWriter
32 {
33     friend class ScopedJsonWriterNode;
34     friend class ScopedJsonWriterArray;
35     friend class ScopedJsonWriterStruct;
36 
37     int mSpaceAllocated;
38     char* mpBuffer;
39     int mStartNodeCount;
40     char* mPos;
41     bool mbFirstFieldInNode;
42 
43 public:
44     JsonWriter();
45     ~JsonWriter();
46 
47     [[nodiscard]] ScopedJsonWriterNode startNode(const char*);
48     [[nodiscard]] ScopedJsonWriterArray startArray(const char*);
49     [[nodiscard]] ScopedJsonWriterStruct startStruct();
50 
51     void put(const char* pPropName, const OUString& rPropValue);
52     void put(const char* pPropName, const OString& rPropValue);
53     void put(const char* pPropName, const char* pPropVal);
put(const char * pPropName,const std::string & rPropValue)54     void put(const char* pPropName, const std::string& rPropValue)
55     {
56         put(pPropName, rPropValue.data());
57     }
58 
put(const char * pPropName,sal_uInt16 nPropVal)59     void put(const char* pPropName, sal_uInt16 nPropVal) { put(pPropName, sal_Int64(nPropVal)); }
put(const char * pPropName,sal_Int16 nPropVal)60     void put(const char* pPropName, sal_Int16 nPropVal) { put(pPropName, sal_Int64(nPropVal)); }
put(const char * pPropName,sal_Int32 nPropVal)61     void put(const char* pPropName, sal_Int32 nPropVal) { put(pPropName, sal_Int64(nPropVal)); }
put(const char * pPropName,sal_uInt32 nPropVal)62     void put(const char* pPropName, sal_uInt32 nPropVal) { put(pPropName, sal_Int64(nPropVal)); }
63     void put(const char* pPropName, sal_Int64);
64     void put(const char* pPropName, bool);
65     void put(const char* pPropName, double);
66 
67     void putSimpleValue(const OUString& rPropValue);
68 
69     /// This assumes that this data belongs at this point in the stream, and is valid, and properly encoded
70     void putRaw(const rtl::OStringBuffer&);
71 
72     /** Hands ownership of the underlying storage buffer to the caller,
73      * after this no more document modifications may be written. */
74     char* extractData();
75     OString extractAsOString();
76     std::string extractAsStdString();
77 
78     /** returns true if the current JSON data matches the string */
79     bool isDataEquals(const std::string&) const;
80 
81 private:
82     void endNode();
83     void endArray();
84     void endStruct();
85     void addCommaBeforeField();
86     void reallocBuffer(int noMoreBytesRequired);
87     void writeEscapedOUString(const OUString& rPropVal);
88 
89     // this part inline to speed up the fast path
ensureSpace(int noMoreBytesRequired)90     inline void ensureSpace(int noMoreBytesRequired)
91     {
92         assert(mpBuffer && "already extracted data");
93         int currentUsed = mPos - mpBuffer;
94         if (currentUsed + noMoreBytesRequired >= mSpaceAllocated)
95             reallocBuffer(noMoreBytesRequired);
96     }
97 };
98 
99 /**
100  * Auto-closes the node.
101  */
102 class ScopedJsonWriterNode
103 {
104     friend class JsonWriter;
105 
106     JsonWriter& mrWriter;
107 
ScopedJsonWriterNode(JsonWriter & rWriter)108     ScopedJsonWriterNode(JsonWriter& rWriter)
109         : mrWriter(rWriter)
110     {
111     }
112 
113 public:
~ScopedJsonWriterNode()114     ~ScopedJsonWriterNode() { mrWriter.endNode(); }
115 };
116 
117 /**
118  * Auto-closes the node.
119  */
120 class ScopedJsonWriterArray
121 {
122     friend class JsonWriter;
123 
124     JsonWriter& mrWriter;
125 
ScopedJsonWriterArray(JsonWriter & rWriter)126     ScopedJsonWriterArray(JsonWriter& rWriter)
127         : mrWriter(rWriter)
128     {
129     }
130 
131 public:
~ScopedJsonWriterArray()132     ~ScopedJsonWriterArray() { mrWriter.endArray(); }
133 };
134 
135 /**
136  * Auto-closes the node.
137  */
138 class ScopedJsonWriterStruct
139 {
140     friend class JsonWriter;
141 
142     JsonWriter& mrWriter;
143 
ScopedJsonWriterStruct(JsonWriter & rWriter)144     ScopedJsonWriterStruct(JsonWriter& rWriter)
145         : mrWriter(rWriter)
146     {
147     }
148 
149 public:
~ScopedJsonWriterStruct()150     ~ScopedJsonWriterStruct() { mrWriter.endStruct(); }
151 };
152 };
153 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
154