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
qqmljsstreamwriter.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3// Qt-Security score:significant
4
7
8#include <QtCore/QBuffer>
9#include <QtCore/QStringList>
10
12
13// TODO: All of this could be improved by using and re-using one buffer for all the writing.
14// We don't really need to allocate any temporary byte arrays.
15
16static QByteArray enquoteByteArray(QByteArrayView string)
17{
18 const qsizetype length = string.length();
19 QByteArray buffer;
20 buffer.reserve(length + 2);
21 buffer.append(' ');
22 buffer.append(string);
23 buffer.append(' ');
24 buffer.replace('\\', "\\\\").replace('"', "\\\"");
25 buffer[0] = '"';
26 buffer[buffer.length() - 1] = '"';
27 return buffer;
28}
29
30static QByteArray enquoteAnyString(QAnyStringView string)
31{
32 return string.visit([](auto data) {
33 return QAnyStringViewUtils::processAsUtf8(data, [](QByteArrayView view) {
34 return enquoteByteArray(view);
35 });
36 });
37}
38
39QQmlJSStreamWriter::QQmlJSStreamWriter(QByteArray *array)
40 : m_indentDepth(0)
41 , m_pendingLineLength(0)
42 , m_maybeOneline(false)
43 , m_stream(new QBuffer(array))
44{
45 m_stream->open(QIODevice::WriteOnly);
46}
47
48void QQmlJSStreamWriter::writeStartDocument()
49{
50}
51
52void QQmlJSStreamWriter::writeEndDocument()
53{
54}
55
56void QQmlJSStreamWriter::writeLibraryImport(
57 QByteArrayView uri, int majorVersion, int minorVersion, QByteArrayView as)
58{
59 m_stream->write("import ");
60 m_stream->write(uri.data(), uri.length());
61 m_stream->write(" ");
62 m_stream->write(QByteArray::number(majorVersion));
63 m_stream->write(".");
64 m_stream->write(QByteArray::number(minorVersion));
65 if (!as.isEmpty()) {
66 m_stream->write(" as ");
67 m_stream->write(as.data(), as.length());
68 }
69 m_stream->write("\n");
70}
71
72void QQmlJSStreamWriter::writeStartObject(QByteArrayView component)
73{
74 flushPotentialLinesWithNewlines();
75 writeIndent();
76 m_stream->write(component.data(), component.length());
77 m_stream->write(" {");
78 ++m_indentDepth;
79 m_maybeOneline = true;
80}
81
82void QQmlJSStreamWriter::writeEndObject()
83{
84 if (m_maybeOneline) {
85 --m_indentDepth;
86 for (int i = 0; i < m_pendingLines.size(); ++i) {
87 m_stream->write(" ");
88 m_stream->write(m_pendingLines.at(i).trimmed());
89 if (i != m_pendingLines.size() - 1)
90 m_stream->write(";");
91 }
92
93 if (!m_pendingLines.isEmpty())
94 m_stream->write(" }\n");
95 else
96 m_stream->write("}\n");
97
98 m_pendingLines.clear();
99 m_pendingLineLength = 0;
100 m_maybeOneline = false;
101 } else {
102 flushPotentialLinesWithNewlines();
103 --m_indentDepth;
104 writeIndent();
105 m_stream->write("}\n");
106 }
107}
108
109void QQmlJSStreamWriter::writeScriptBinding(QByteArrayView name, QByteArrayView rhs)
110{
111 QByteArray buffer;
112 buffer.reserve(name.length() + 2 + rhs.length());
113 buffer.append(name);
114 buffer.append(": ");
115 buffer.append(rhs);
116 writePotentialLine(buffer);
117}
118
119void QQmlJSStreamWriter::writeStringBinding(QByteArrayView name, QAnyStringView value)
120{
121 writeScriptBinding(name, enquoteAnyString(value));
122}
123
124void QQmlJSStreamWriter::writeNumberBinding(QByteArrayView name, qint64 value)
125{
126 writeScriptBinding(name, QByteArray::number(value));
127}
128
129void QQmlJSStreamWriter::writeBooleanBinding(QByteArrayView name, bool value)
130{
131 writeScriptBinding(name, value ? "true" : "false");
132}
133
134template<typename String, typename ElementHandler>
135void QQmlJSStreamWriter::doWriteArrayBinding(
136 QByteArrayView name, const QList<String> &elements, ElementHandler &&handler)
137{
138 flushPotentialLinesWithNewlines();
139 writeIndent();
140
141 // try to use a single line
142 QByteArray singleLine(name.data(), name.length());
143 singleLine += ": [";
144 for (int i = 0; i < elements.size(); ++i) {
145 QAnyStringViewUtils::processAsUtf8(elements.at(i), [&](QByteArrayView element) {
146 singleLine += handler(element);
147 });
148 if (i != elements.size() - 1)
149 singleLine += ", ";
150 }
151 singleLine += "]\n";
152 if (singleLine.size() + m_indentDepth * 4 < 80) {
153 m_stream->write(singleLine);
154 return;
155 }
156
157 // write multi-line
158 m_stream->write(name.data(), name.length());
159 m_stream->write(": [\n");
160 ++m_indentDepth;
161 for (int i = 0; i < elements.size(); ++i) {
162 writeIndent();
163 QAnyStringViewUtils::processAsUtf8(elements.at(i), [&](QByteArrayView element) {
164 const auto handled = handler(element);
165 m_stream->write(handled.data(), handled.length());
166 });
167 if (i != elements.size() - 1) {
168 m_stream->write(",\n");
169 } else {
170 m_stream->write("\n");
171 }
172 }
173 --m_indentDepth;
174 writeIndent();
175 m_stream->write("]\n");
176}
177
178void QQmlJSStreamWriter::writeArrayBinding(QByteArrayView name, const QByteArrayList &elements)
179{
180 doWriteArrayBinding(name, elements, [](QByteArrayView view) { return view; });
181}
182
183void QQmlJSStreamWriter::writeStringListBinding(
184 QByteArrayView name, const QList<QAnyStringView> &elements)
185{
186 doWriteArrayBinding(name, elements, enquoteByteArray);
187}
188
189void QQmlJSStreamWriter::write(QByteArrayView data)
190{
191 flushPotentialLinesWithNewlines();
192 m_stream->write(data.data(), data.length());
193}
194
195void QQmlJSStreamWriter::writeEnumObjectLiteralBinding(
196 QByteArrayView name, const QList<std::pair<QAnyStringView, int> > &keyValue)
197{
198 flushPotentialLinesWithNewlines();
199 writeIndent();
200 m_stream->write(name.data(), name.length());
201 m_stream->write(": {\n");
202 ++m_indentDepth;
203 for (int i = 0, end = keyValue.size(); i != end; ++i) {
204 writeIndent();
205 const auto &entry = keyValue[i];
206 m_stream->write(enquoteAnyString(entry.first));
207 m_stream->write(": ");
208 m_stream->write(QByteArray::number(entry.second));
209 if (i != end - 1)
210 m_stream->write(",\n");
211 else
212 m_stream->write("\n");
213 }
214 --m_indentDepth;
215 writeIndent();
216 m_stream->write("}\n");
217}
218
219void QQmlJSStreamWriter::writeIndent()
220{
221 for (int i = 0; i < m_indentDepth; ++i)
222 m_stream->write(" ");
223}
224
225void QQmlJSStreamWriter::writePotentialLine(const QByteArray &line)
226{
227 m_pendingLines.append(line);
228 m_pendingLineLength += line.size();
229 if (m_pendingLineLength >= 80) {
230 flushPotentialLinesWithNewlines();
231 }
232}
233
234void QQmlJSStreamWriter::flushPotentialLinesWithNewlines()
235{
236 if (m_maybeOneline)
237 m_stream->write("\n");
238 for (const QByteArray &line : std::as_const(m_pendingLines)) {
239 writeIndent();
240 m_stream->write(line);
241 m_stream->write("\n");
242 }
243 m_pendingLines.clear();
244 m_pendingLineLength = 0;
245 m_maybeOneline = false;
246}
247
248QT_END_NAMESPACE
Combined button and popup list for selecting options.
static QT_BEGIN_NAMESPACE QByteArray enquoteByteArray(QByteArrayView string)
static QByteArray enquoteAnyString(QAnyStringView string)