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
qstringconverter.h
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:critical reason:data-parser
4
5#if 0
6// keep existing syncqt header working after the move of the class
7// into qstringconverter_base
8#pragma qt_class(QStringConverter)
9#endif
10
11#ifndef QSTRINGCONVERTER_H
12#define QSTRINGCONVERTER_H
13
14#include <QtCore/qstringconverter_base.h>
15#include <QtCore/qstring.h>
16#include <QtCore/qstringbuilder.h>
17
18QT_BEGIN_NAMESPACE
19
20class QStringEncoder : public QStringConverter
21{
22protected:
23 constexpr explicit QStringEncoder(const Interface *i) noexcept
24 : QStringConverter(i)
25 {}
26public:
27 constexpr QStringEncoder() noexcept
28 : QStringConverter()
29 {}
30 constexpr explicit QStringEncoder(Encoding encoding, Flags flags = Flag::Default)
31 : QStringConverter(encoding, flags)
32 {}
33 explicit QStringEncoder(QAnyStringView name, Flags flags = Flag::Default)
34 : QStringConverter(name, flags)
35 {}
36
37 template<typename T>
38 struct DecodedData
39 {
40 QStringEncoder *encoder;
41 T data;
42 operator QByteArray() const { return encoder->encodeAsByteArray(data); }
43 };
44 Q_WEAK_OVERLOAD
45 DecodedData<const QString &> operator()(const QString &str)
46 { return DecodedData<const QString &>{this, str}; }
47 DecodedData<QStringView> operator()(QStringView in)
48 { return DecodedData<QStringView>{this, in}; }
49 Q_WEAK_OVERLOAD
50 DecodedData<const QString &> encode(const QString &str)
51 { return DecodedData<const QString &>{this, str}; }
52 DecodedData<QStringView> encode(QStringView in)
53 { return DecodedData<QStringView>{this, in}; }
54
55 qsizetype requiredSpace(qsizetype inputLength) const
56 { return iface ? iface->fromUtf16Len(inputLength) : 0; }
57 char *appendToBuffer(char *out, QStringView in)
58 {
59 if (!iface) {
60 state.invalidChars = 1;
61 return out;
62 }
63 return iface->fromUtf16(out, in, &state);
64 }
65
66 using FinalizeResult = FinalizeResultChar<char>;
67 [[nodiscard]] Q_CORE_EXPORT FinalizeResult finalize(char *out, qsizetype maxlen);
68 [[nodiscard]] FinalizeResult finalize() { return finalize(nullptr, 0); }
69
70private:
71 QByteArray invalidateAndReturnNull()
72 {
73 // ensure that hasError returns true
74 state.invalidChars = 1;
75 return QByteArray();
76 }
77 QByteArray encodeAsByteArrayImpl(QStringView in)
78 {
79 QByteArray result(iface->fromUtf16Len(in.size()), Qt::Uninitialized);
80 char *out = result.data();
81 out = iface->fromUtf16(out, in, &state);
82 result.truncate(out - result.constData());
83 return result;
84 }
85 QByteArray encodeAsByteArray(QStringView in)
86 {
87 return iface ? encodeAsByteArrayImpl(in) : invalidateAndReturnNull();
88 }
89};
90
92{
93protected:
94 constexpr explicit QStringDecoder(const Interface *i) noexcept
96 {}
97public:
98 constexpr explicit QStringDecoder(Encoding encoding, Flags flags = Flag::Default)
100 {}
101 constexpr QStringDecoder() noexcept
103 {}
104 explicit QStringDecoder(QAnyStringView name, Flags f = Flag::Default)
106 {}
107
108 template<typename T>
117 { return EncodedData<const QByteArray &>{this, ba}; }
122 { return EncodedData<const QByteArray &>{this, ba}; }
125
129 {
130 if (!iface) {
132 return out;
133 }
134 return iface->toUtf16(out, ba, &state);
135 }
136 char16_t *appendToBuffer(char16_t *out, QByteArrayView ba)
137 { return reinterpret_cast<char16_t *>(appendToBuffer(reinterpret_cast<QChar *>(out), ba)); }
138
139
142 [[nodiscard]] FinalizeResultQChar finalize(QChar *out, qsizetype maxlen)
143 {
144 auto r = finalize(reinterpret_cast<char16_t *>(out), maxlen);
145 return {reinterpret_cast<QChar *>(r.next), r.invalidChars, r.error};
146 }
147 [[nodiscard]] Q_CORE_EXPORT FinalizeResult finalize(char16_t *out, qsizetype maxlen);
148 [[nodiscard]] FinalizeResult finalize()
149 {
150 return finalize(static_cast<char16_t *>(nullptr), 0);
151 }
152
153 Q_CORE_EXPORT static QStringDecoder decoderForHtml(QByteArrayView data);
154
155private:
156 QString invalidateAndReturnNull()
157 {
158 // ensure that hasError returns true
159 state.invalidChars = 1;
160 return QString();
161 }
162 QString decodeAsStringImpl(QByteArrayView in)
163 {
164 QString result(iface->toUtf16Len(in.size()), Qt::Uninitialized);
165 const QChar *out = iface->toUtf16(result.data(), in, &state);
166 result.truncate(out - result.constData());
167 return result;
168 }
169 QString decodeAsString(QByteArrayView in)
170 {
171 return iface ? decodeAsStringImpl(in) : invalidateAndReturnNull();
172 }
173};
174
175
176#if defined(QT_USE_FAST_OPERATOR_PLUS) || defined(QT_USE_QSTRINGBUILDER)
177template <typename T>
178struct QConcatenable<QStringDecoder::EncodedData<T>>
179 : private QAbstractConcatenable
180{
181 typedef QChar type;
182 typedef QString ConvertTo;
183 enum { ExactSize = false };
184 static qsizetype size(const QStringDecoder::EncodedData<T> &s) { return s.decoder->requiredSpace(s.data.size()); }
185 static inline void appendTo(const QStringDecoder::EncodedData<T> &s, QChar *&out)
186 {
187 out = s.decoder->appendToBuffer(out, s.data);
188 }
189};
190
191template <typename T>
192struct QConcatenable<QStringEncoder::DecodedData<T>>
193 : private QAbstractConcatenable
194{
195 typedef char type;
196 typedef QByteArray ConvertTo;
197 enum { ExactSize = false };
198 static qsizetype size(const QStringEncoder::DecodedData<T> &s) { return s.encoder->requiredSpace(s.data.size()); }
199 static inline void appendTo(const QStringEncoder::DecodedData<T> &s, char *&out)
200 {
201 out = s.encoder->appendToBuffer(out, s.data);
202 }
203};
204
205template <typename T>
206QString &operator+=(QString &a, const QStringDecoder::EncodedData<T> &b)
207{
208 qsizetype len = a.size() + QConcatenable<QStringDecoder::EncodedData<T>>::size(b);
209 a.reserve(len);
210 QChar *it = a.data() + a.size();
211 QConcatenable<QStringDecoder::EncodedData<T>>::appendTo(b, it);
212 a.resize(qsizetype(it - a.constData())); //may be smaller than len
213 return a;
214}
215
216template <typename T>
217QByteArray &operator+=(QByteArray &a, const QStringEncoder::DecodedData<T> &b)
218{
219 qsizetype len = a.size() + QConcatenable<QStringEncoder::DecodedData<T>>::size(b);
220 a.reserve(len);
221 char *it = a.data() + a.size();
222 QConcatenable<QStringEncoder::DecodedData<T>>::appendTo(b, it);
223 a.resize(qsizetype(it - a.constData())); //may be smaller than len
224 return a;
225}
226#endif
227
228template <typename InputIterator>
229void QString::assign_helper_char8(InputIterator first, InputIterator last)
230{
231 static_assert(!QString::is_contiguous_iterator_v<InputIterator>,
232 "Internal error: Should have been handed over to the QAnyStringView overload."
233 );
234
235 using ValueType = typename std::iterator_traits<InputIterator>::value_type;
236 constexpr bool IsFwdIt = std::is_convertible_v<
237 typename std::iterator_traits<InputIterator>::iterator_category,
238 std::forward_iterator_tag
239 >;
240
241 resize(0);
242 // In case of not being shared, there is the possibility of having free space at begin
243 // even after the resize to zero.
244 if (const auto offset = d.freeSpaceAtBegin())
245 d.setBegin(d.begin() - offset);
246
247 if constexpr (IsFwdIt)
248 reserve(static_cast<qsizetype>(std::distance(first, last)));
249
250 auto toUtf16 = QStringDecoder(QStringDecoder::Utf8);
251 auto availableCapacity = d.constAllocatedCapacity();
252 auto *dst = d.data();
253 auto *dend = d.data() + availableCapacity;
254
255 while (true) {
256 if (first == last) { // ran out of input elements
257 Q_ASSERT(!std::less<>{}(dend, dst));
258 d.size = dst - d.begin();
259 return;
260 }
261 const ValueType next = *first; // decays proxies, if any
262 const auto chunk = QUtf8StringView(&next, 1);
263 // UTF-8 characters can have a maximum size of 4 bytes and may result in a surrogate
264 // pair of UTF-16 code units. In the input-iterator case, we don't know the size
265 // and would need to always reserve space for 2 code units. To keep our promise
266 // of 'not allocating if it fits', we have to pre-check this condition.
267 // We know that it fits in the forward-iterator case.
268 if constexpr (!IsFwdIt) {
269 constexpr qsizetype Pair = 2;
270 char16_t buf[Pair];
271 const qptrdiff n = toUtf16.appendToBuffer(buf, chunk) - buf;
272 if (dend - dst < n) { // ran out of allocated memory
273 const auto offset = dst - d.begin();
274 reallocData(d.constAllocatedCapacity() + Pair, QArrayData::Grow);
275 // update the pointers since we've re-allocated
276 availableCapacity = d.constAllocatedCapacity();
277 dst = d.data() + offset;
278 dend = d.data() + availableCapacity;
279 }
280 dst = std::copy_n(buf, n, dst);
281 } else { // take the fast path
282 dst = toUtf16.appendToBuffer(dst, chunk);
283 }
284 ++first;
285 }
286}
287
288QT_END_NAMESPACE
289
290#endif
\inmodule QtCore
constexpr QStringDecoder(Encoding encoding, Flags flags=Flag::Default)
Creates an decoder object using encoding and flags.
FinalizeResultQChar finalize(QChar *out, qsizetype maxlen)
constexpr QStringDecoder(const Interface *i) noexcept
FinalizeResult finalize()
Signals to the decoder that no further data will arrive.
constexpr QStringDecoder() noexcept
Default constructs an decoder.