Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qjsonwriter.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2016 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4// Qt-Security score:critical reason:data-parser
5
6#include <cmath>
7#include <qlocale.h>
9#include "qjson_p.h"
10#include "private/qstringconverter_p.h"
11#include <private/qnumeric_p.h>
12#include <private/qcborvalue_p.h>
13
15
16using namespace QJsonPrivate;
17
18static void objectContentToJson(const QCborContainerPrivate *o, QByteArray &json, int indent, bool compact);
19static void arrayContentToJson(const QCborContainerPrivate *a, QByteArray &json, int indent, bool compact);
20
21static inline uchar hexdig(uint u)
22{
23 return (u < 0xa ? '0' + u : 'a' + u - 0xa);
24}
25
26static QByteArray escapedString(QStringView s)
27{
28 // give it a minimum size to ensure the resize() below always adds enough space
29 QByteArray ba(qMax(s.size(), 16), Qt::Uninitialized);
30
31 auto ba_const_start = [&]() { return reinterpret_cast<const uchar *>(ba.constData()); };
32 uchar *cursor = reinterpret_cast<uchar *>(const_cast<char *>(ba.constData()));
33 const uchar *ba_end = cursor + ba.size();
34 const char16_t *src = s.utf16();
35 const char16_t *const end = s.utf16() + s.size();
36
37 while (src != end) {
38 if (cursor >= ba_end - 6) {
39 // ensure we have enough space
40 qptrdiff pos = cursor - ba_const_start();
41 ba.resize(ba.size()*2);
42 cursor = reinterpret_cast<uchar *>(ba.data()) + pos;
43 ba_end = ba_const_start() + ba.size();
44 }
45
46 char16_t u = *src++;
47 if (u < 0x80) {
48 if (u < 0x20 || u == 0x22 || u == 0x5c) {
49 *cursor++ = '\\';
50 switch (u) {
51 case 0x22:
52 *cursor++ = '"';
53 break;
54 case 0x5c:
55 *cursor++ = '\\';
56 break;
57 case 0x8:
58 *cursor++ = 'b';
59 break;
60 case 0xc:
61 *cursor++ = 'f';
62 break;
63 case 0xa:
64 *cursor++ = 'n';
65 break;
66 case 0xd:
67 *cursor++ = 'r';
68 break;
69 case 0x9:
70 *cursor++ = 't';
71 break;
72 default:
73 *cursor++ = 'u';
74 *cursor++ = '0';
75 *cursor++ = '0';
76 *cursor++ = hexdig(u>>4);
77 *cursor++ = hexdig(u & 0xf);
78 }
79 } else {
80 *cursor++ = (uchar)u;
81 }
82 } else if (QUtf8Functions::toUtf8<QUtf8BaseTraits>(u, cursor, src, end) < 0) {
83 // failed to get valid utf8 use JSON escape sequence
84 *cursor++ = '\\';
85 *cursor++ = 'u';
86 *cursor++ = hexdig(u>>12 & 0x0f);
87 *cursor++ = hexdig(u>>8 & 0x0f);
88 *cursor++ = hexdig(u>>4 & 0x0f);
89 *cursor++ = hexdig(u & 0x0f);
90 }
91 }
92
93 ba.resize(cursor - ba_const_start());
94 return ba;
95}
96
97static void valueContentToJson(const QCborValue &v, QByteArray &json, int indent, bool compact)
98{
99 QCborValue::Type type = v.type();
100 switch (type) {
101 case QCborValue::True:
102 json += "true";
103 break;
104 case QCborValue::False:
105 json += "false";
106 break;
107 case QCborValue::Integer:
108 json += QByteArray::number(v.toInteger());
109 break;
110 case QCborValue::Double: {
111 const double d = v.toDouble();
112 if (qt_is_finite(d))
113 json += QByteArray::number(d, 'g', QLocale::FloatingPointShortest);
114 else
115 json += "null"; // +INF || -INF || NaN (see RFC4627#section2.4)
116 break;
117 }
118 case QCborValue::String:
119 json += '"';
120 json += escapedString(v.toString());
121 json += '"';
122 break;
123 case QCborValue::Array:
124 json += compact ? "[" : "[\n";
125 arrayContentToJson(
126 QJsonPrivate::Value::container(v), json, indent + (compact ? 0 : 1), compact);
127 json += QByteArray(4*indent, ' ');
128 json += ']';
129 break;
130 case QCborValue::Map:
131 json += compact ? "{" : "{\n";
132 objectContentToJson(
133 QJsonPrivate::Value::container(v), json, indent + (compact ? 0 : 1), compact);
134 json += QByteArray(4*indent, ' ');
135 json += '}';
136 break;
137 case QCborValue::Null:
138 default:
139 json += "null";
140 }
141}
142
143static void arrayContentToJson(const QCborContainerPrivate *a, QByteArray &json, int indent, bool compact)
144{
145 if (!a || a->elements.empty())
146 return;
147
148 QByteArray indentString(4*indent, ' ');
149
150 qsizetype i = 0;
151 while (true) {
152 json += indentString;
153 valueContentToJson(a->valueAt(i), json, indent, compact);
154
155 if (++i == a->elements.size()) {
156 if (!compact)
157 json += '\n';
158 break;
159 }
160
161 json += compact ? "," : ",\n";
162 }
163}
164
165
166static void objectContentToJson(const QCborContainerPrivate *o, QByteArray &json, int indent, bool compact)
167{
168 if (!o || o->elements.empty())
169 return;
170
171 QByteArray indentString(4*indent, ' ');
172
173 qsizetype i = 0;
174 while (true) {
175 QCborValue e = o->valueAt(i);
176 json += indentString;
177 json += '"';
178 json += escapedString(o->valueAt(i).toString());
179 json += compact ? "\":" : "\": ";
180 valueContentToJson(o->valueAt(i + 1), json, indent, compact);
181
182 if ((i += 2) == o->elements.size()) {
183 if (!compact)
184 json += '\n';
185 break;
186 }
187
188 json += compact ? "," : ",\n";
189 }
190}
191
192void Writer::objectToJson(const QCborContainerPrivate *o, QByteArray &json, int indent, bool compact)
193{
194 json.reserve(json.size() + (o ? (int)o->elements.size() : 16));
195 json += compact ? "{" : "{\n";
196 objectContentToJson(o, json, indent + (compact ? 0 : 1), compact);
197 json += QByteArray(4*indent, ' ');
198 json += compact ? "}" : "}\n";
199}
200
201void Writer::arrayToJson(const QCborContainerPrivate *a, QByteArray &json, int indent, bool compact)
202{
203 json.reserve(json.size() + (a ? (int)a->elements.size() : 16));
204 json += compact ? "[" : "[\n";
205 arrayContentToJson(a, json, indent + (compact ? 0 : 1), compact);
206 json += QByteArray(4*indent, ' ');
207 json += compact ? "]" : "]\n";
208}
209
210void Writer::valueToJson(const QCborValue &v, QByteArray &json, int indent, bool compact)
211{
212 const QCborContainerPrivate *container = QJsonPrivate::Value::container(v);
213 json.reserve(json.size() + (container ? container->elements.size() : 16));
214 valueContentToJson(v, json, indent, compact);
215
216 if (!compact && (v.isMap() || v.isArray())) {
217 json.append('\n');
218 }
219}
220
221QT_END_NAMESPACE
\inmodule QtCore\reentrant
Definition qcborvalue.h:48
static const QCborContainerPrivate * container(QJsonValueConstRef r) noexcept
Definition qjson_p.h:177
static void arrayContentToJson(const QCborContainerPrivate *a, QByteArray &json, int indent, bool compact)
static QByteArray escapedString(QStringView s)
static void objectContentToJson(const QCborContainerPrivate *o, QByteArray &json, int indent, bool compact)
static void valueContentToJson(const QCborValue &v, QByteArray &json, int indent, bool compact)
static uchar hexdig(uint u)