1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
3 * This file is part of the LibreOffice project.
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/.
10 #include <tools/json_writer.hxx>
13 #include <rtl/strbuf.hxx>
17 /** These buffers are short-lived, so rather waste some space and avoid the cost of
18 * repeated calls into the allocator */
19 constexpr int DEFAULT_BUFFER_SIZE
= 2048;
21 JsonWriter::JsonWriter()
22 : mSpaceAllocated(DEFAULT_BUFFER_SIZE
)
23 , mpBuffer(static_cast<char*>(malloc(mSpaceAllocated
)))
26 , mbFirstFieldInNode(true)
34 JsonWriter::~JsonWriter()
36 assert(!mpBuffer
&& "forgot to extract data?");
40 ScopedJsonWriterNode
JsonWriter::startNode(const char* pNodeName
)
42 auto len
= strlen(pNodeName
);
45 addCommaBeforeField();
49 memcpy(mPos
, pNodeName
, len
);
51 memcpy(mPos
, "\": { ", 5);
54 mbFirstFieldInNode
= true;
55 return ScopedJsonWriterNode(*this);
58 void JsonWriter::endNode()
60 assert(mStartNodeCount
&& "mismatched StartNode/EndNode somewhere");
65 mbFirstFieldInNode
= false;
68 ScopedJsonWriterArray
JsonWriter::startArray(const char* pNodeName
)
70 auto len
= strlen(pNodeName
);
73 addCommaBeforeField();
77 memcpy(mPos
, pNodeName
, len
);
79 memcpy(mPos
, "\": [ ", 5);
82 mbFirstFieldInNode
= true;
83 return ScopedJsonWriterArray(*this);
86 void JsonWriter::endArray()
88 assert(mStartNodeCount
&& "mismatched StartNode/EndNode somewhere");
93 mbFirstFieldInNode
= false;
96 ScopedJsonWriterStruct
JsonWriter::startStruct()
100 addCommaBeforeField();
107 mbFirstFieldInNode
= true;
108 return ScopedJsonWriterStruct(*this);
111 void JsonWriter::endStruct()
113 assert(mStartNodeCount
&& "mismatched StartNode/EndNode somewhere");
118 mbFirstFieldInNode
= false;
121 void JsonWriter::put(const char* pPropName
, const OUString
& rPropVal
)
123 auto nPropNameLength
= strlen(pPropName
);
124 auto nWorstCasePropValLength
= rPropVal
.getLength() * 2;
125 ensureSpace(nPropNameLength
+ nWorstCasePropValLength
+ 8);
127 addCommaBeforeField();
131 memcpy(mPos
, pPropName
, nPropNameLength
);
132 mPos
+= nPropNameLength
;
133 memcpy(mPos
, "\": \"", 4);
136 // Convert from UTF-16 to UTF-8 and perform escaping
137 for (int i
= 0; i
< rPropVal
.getLength(); ++i
)
139 sal_Unicode ch
= rPropVal
[i
];
142 *mPos
= static_cast<char>(ch
);
144 *mPos
= static_cast<char>(ch
);
151 *mPos
= static_cast<char>(ch
);
156 *mPos
= static_cast<char>(ch
);
159 else if (ch
<= 0x7FF)
161 *mPos
= 0xC0 | (ch
>> 6); /* 110xxxxx */
163 *mPos
= 0x80 | (ch
& 0x3F); /* 10xxxxxx */
168 *mPos
= 0xE0 | (ch
>> 12); /* 1110xxxx */
170 *mPos
= 0x80 | ((ch
>> 6) & 0x3F); /* 10xxxxxx */
172 *mPos
= 0x80 | (ch
& 0x3F); /* 10xxxxxx */
181 void JsonWriter::put(const char* pPropName
, const OString
& rPropVal
)
183 auto nPropNameLength
= strlen(pPropName
);
184 auto nWorstCasePropValLength
= rPropVal
.getLength();
185 ensureSpace(nPropNameLength
+ nWorstCasePropValLength
+ 8);
187 addCommaBeforeField();
191 memcpy(mPos
, pPropName
, nPropNameLength
);
192 mPos
+= nPropNameLength
;
193 memcpy(mPos
, "\": \"", 4);
196 // copy and perform escaping
197 for (int i
= 0; i
< rPropVal
.getLength(); ++i
)
199 char ch
= rPropVal
[i
];
225 void JsonWriter::put(const char* pPropName
, const char* pPropVal
)
227 auto nPropNameLength
= strlen(pPropName
);
228 auto nPropValLength
= strlen(pPropVal
);
229 auto nWorstCasePropValLength
= nPropValLength
* 2;
230 ensureSpace(nPropNameLength
+ nWorstCasePropValLength
+ 8);
232 addCommaBeforeField();
236 memcpy(mPos
, pPropName
, nPropNameLength
);
237 mPos
+= nPropNameLength
;
238 memcpy(mPos
, "\": \"", 4);
241 // copy and perform escaping
273 void JsonWriter::put(const char* pPropName
, int nPropVal
)
275 auto nPropNameLength
= strlen(pPropName
);
276 auto nWorstCasePropValLength
= 32;
277 ensureSpace(nPropNameLength
+ nWorstCasePropValLength
+ 8);
279 addCommaBeforeField();
283 memcpy(mPos
, pPropName
, nPropNameLength
);
284 mPos
+= nPropNameLength
;
285 memcpy(mPos
, "\": ", 3);
288 mPos
+= sprintf(mPos
, "%d", nPropVal
);
291 void JsonWriter::putRaw(const rtl::OStringBuffer
& rRawBuf
)
293 ensureSpace(rRawBuf
.getLength() + 2);
295 addCommaBeforeField();
297 memcpy(mPos
, rRawBuf
.getStr(), rRawBuf
.getLength());
298 mPos
+= rRawBuf
.getLength();
301 void JsonWriter::addCommaBeforeField()
303 if (mbFirstFieldInNode
)
304 mbFirstFieldInNode
= false;
314 void JsonWriter::reallocBuffer(int noMoreBytesRequired
)
316 int currentUsed
= mPos
- mpBuffer
;
317 auto newSize
= std::max
<int>(mSpaceAllocated
* 2, (currentUsed
+ noMoreBytesRequired
) * 2);
318 char* pNew
= static_cast<char*>(malloc(newSize
));
319 memcpy(pNew
, mpBuffer
, currentUsed
);
322 mPos
= mpBuffer
+ currentUsed
;
323 mSpaceAllocated
= newSize
;
326 /** Hands ownership of the underlying storage buffer to the caller,
327 * after this no more document modifications may be written. */
328 char* JsonWriter::extractData()
330 assert(mStartNodeCount
== 0 && "did not close all nodes");
331 assert(mpBuffer
&& "data already extracted");
339 char* pRet
= nullptr;
340 std::swap(pRet
, mpBuffer
);
344 OString
JsonWriter::extractAsOString()
346 char* pChar
= extractData();
353 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */