1/****************************************************************************
2**
3** Copyright (C) 2020 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtCore module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#ifndef QSTRINGCONVERTER_H
41#define QSTRINGCONVERTER_H
42
43#include <QtCore/qstring.h>
44#if defined(QT_USE_FAST_OPERATOR_PLUS) || defined(QT_USE_QSTRINGBUILDER)
45#include <QtCore/qstringbuilder.h>
46#endif
47
48#include <optional>
49
50QT_BEGIN_NAMESPACE
51
52// work around a compiler bug in GCC 7
53#if (defined(Q_CC_GNU) && __GNUC__ == 7) || defined(Q_QDOC)
54#define QSTRINGCONVERTER_CONSTEXPR
55#else
56#define QSTRINGCONVERTER_CONSTEXPR constexpr
57#endif
58
59class QStringConverterBase
60{
61public:
62 enum class Flag {
63 Default = 0,
64 Stateless = 0x1,
65 ConvertInvalidToNull = 0x2,
66 WriteBom = 0x4,
67 ConvertInitialBom = 0x8
68 };
69 Q_DECLARE_FLAGS(Flags, Flag)
70
71 struct State {
72 constexpr State(Flags f = Flag::Default)
73 : flags(f), state_data{0, 0, 0, 0} {}
74 ~State() { clear(); }
75 State(State &&other)
76 : flags(other.flags),
77 remainingChars(other.remainingChars),
78 invalidChars(other.invalidChars),
79 d{other.d[0], other.d[1]},
80 clearFn(other.clearFn)
81 { other.clearFn = nullptr; }
82 State &operator=(State &&other)
83 {
84 clear();
85 flags = other.flags;
86 remainingChars = other.remainingChars;
87 invalidChars = other.invalidChars;
88 d[0] = other.d[0];
89 d[1] = other.d[1];
90 clearFn = other.clearFn;
91 other.clearFn = nullptr;
92 return *this;
93 }
94 Q_CORE_EXPORT void clear();
95
96 Flags flags;
97 int internalState = 0;
98 qsizetype remainingChars = 0;
99 qsizetype invalidChars = 0;
100
101 union {
102 uint state_data[4];
103 void *d[2];
104 };
105 using ClearDataFn = void (*)(State *);
106 ClearDataFn clearFn = nullptr;
107 private:
108 Q_DISABLE_COPY(State)
109 };
110};
111Q_DECLARE_OPERATORS_FOR_FLAGS(QStringConverterBase::Flags)
112
113class QStringConverter : public QStringConverterBase
114{
115public:
116
117 enum Encoding {
118 Utf8,
119 Utf16,
120 Utf16LE,
121 Utf16BE,
122 Utf32,
123 Utf32LE,
124 Utf32BE,
125 Latin1,
126 System,
127 LastEncoding = System
128 };
129#ifdef Q_QDOC
130 // document the flags here
131 enum class Flag {
132 Default = 0,
133 Stateless = 0x1,
134 ConvertInvalidToNull = 0x2,
135 WriteBom = 0x4,
136 ConvertInitialBom = 0x8
137 };
138 Q_DECLARE_FLAGS(Flags, Flag)
139#endif
140
141protected:
142
143 struct Interface
144 {
145 using DecoderFn = QChar * (*)(QChar *out, QByteArrayView in, State *state);
146 using LengthFn = qsizetype (*)(qsizetype inLength);
147 using EncoderFn = char * (*)(char *out, QStringView in, State *state);
148 const char *name = nullptr;
149 DecoderFn toUtf16 = nullptr;
150 LengthFn toUtf16Len = nullptr;
151 EncoderFn fromUtf16 = nullptr;
152 LengthFn fromUtf16Len = nullptr;
153 };
154
155 QSTRINGCONVERTER_CONSTEXPR QStringConverter()
156 : iface(nullptr)
157 {}
158 QSTRINGCONVERTER_CONSTEXPR QStringConverter(Encoding encoding, Flags f)
159 : iface(&encodingInterfaces[int(encoding)]), state(f)
160 {}
161 QSTRINGCONVERTER_CONSTEXPR QStringConverter(const Interface *i)
162 : iface(i)
163 {}
164 Q_CORE_EXPORT QStringConverter(const char *name, Flags f);
165
166
167public:
168 bool isValid() const { return iface != nullptr; }
169
170 void resetState()
171 {
172 state.clear();
173 }
174 bool hasError() const { return state.invalidChars != 0; }
175
176 const char *name() const
177 { return isValid() ? iface->name : nullptr; }
178
179 Q_CORE_EXPORT static std::optional<Encoding> encodingForName(const char *name);
180 Q_CORE_EXPORT static const char *nameForEncoding(Encoding e);
181 Q_CORE_EXPORT static std::optional<Encoding> encodingForData(QByteArrayView data, char16_t expectedFirstCharacter = 0);
182 Q_CORE_EXPORT static std::optional<Encoding> encodingForHtml(QByteArrayView data);
183
184protected:
185 const Interface *iface;
186 State state;
187private:
188 Q_CORE_EXPORT static const Interface encodingInterfaces[Encoding::LastEncoding + 1];
189};
190
191class QStringEncoder : public QStringConverter
192{
193protected:
194 QSTRINGCONVERTER_CONSTEXPR QStringEncoder(const Interface *i)
195 : QStringConverter(i)
196 {}
197public:
198 QSTRINGCONVERTER_CONSTEXPR QStringEncoder()
199 : QStringConverter()
200 {}
201 QSTRINGCONVERTER_CONSTEXPR QStringEncoder(Encoding encoding, Flags flags = Flag::Default)
202 : QStringConverter(encoding, flags)
203 {}
204 QStringEncoder(const char *name, Flags flags = Flag::Default)
205 : QStringConverter(name, flags)
206 {}
207
208#if defined(Q_QDOC)
209 QByteArray operator()(const QString &in);
210 QByteArray operator()(QStringView in);
211 QByteArray encode(const QString &in);
212 QByteArray encode(QStringView in);
213#else
214 template<typename T>
215 struct DecodedData
216 {
217 QStringEncoder *encoder;
218 T data;
219 operator QByteArray() const { return encoder->encodeAsByteArray(data); }
220 };
221 Q_WEAK_OVERLOAD
222 DecodedData<const QString &> operator()(const QString &str)
223 { return DecodedData<const QString &>{this, str}; }
224 DecodedData<QStringView> operator()(QStringView in)
225 { return DecodedData<QStringView>{this, in}; }
226 Q_WEAK_OVERLOAD
227 DecodedData<const QString &> encode(const QString &str)
228 { return DecodedData<const QString &>{this, str}; }
229 DecodedData<QStringView> encode(QStringView in)
230 { return DecodedData<QStringView>{this, in}; }
231#endif
232
233 qsizetype requiredSpace(qsizetype inputLength) const
234 { return iface->fromUtf16Len(inputLength); }
235 char *appendToBuffer(char *out, QStringView in)
236 { return iface->fromUtf16(out, in, &state); }
237private:
238 QByteArray encodeAsByteArray(QStringView in)
239 {
240 QByteArray result(iface->fromUtf16Len(in.size()), Qt::Uninitialized);
241 char *out = result.data();
242 out = iface->fromUtf16(out, in, &state);
243 result.truncate(out - result.constData());
244 return result;
245 }
246
247};
248
249class QStringDecoder : public QStringConverter
250{
251protected:
252 QSTRINGCONVERTER_CONSTEXPR QStringDecoder(const Interface *i)
253 : QStringConverter(i)
254 {}
255public:
256 QSTRINGCONVERTER_CONSTEXPR QStringDecoder(Encoding encoding, Flags flags = Flag::Default)
257 : QStringConverter(encoding, flags)
258 {}
259 QSTRINGCONVERTER_CONSTEXPR QStringDecoder()
260 : QStringConverter()
261 {}
262 QStringDecoder(const char *name, Flags f = Flag::Default)
263 : QStringConverter(name, f)
264 {}
265
266#if defined(Q_QDOC)
267 QString operator()(const QByteArray &ba);
268 QString operator()(QByteArrayView ba);
269 QString decode(const QByteArray &ba);
270 QString decode(QByteArrayView ba);
271#else
272 template<typename T>
273 struct EncodedData
274 {
275 QStringDecoder *decoder;
276 T data;
277 operator QString() const { return decoder->decodeAsString(data); }
278 };
279 Q_WEAK_OVERLOAD
280 EncodedData<const QByteArray &> operator()(const QByteArray &ba)
281 { return EncodedData<const QByteArray &>{this, ba}; }
282 EncodedData<QByteArrayView> operator()(QByteArrayView ba)
283 { return EncodedData<QByteArrayView>{this, ba}; }
284 Q_WEAK_OVERLOAD
285 EncodedData<const QByteArray &> decode(const QByteArray &ba)
286 { return EncodedData<const QByteArray &>{this, ba}; }
287 EncodedData<QByteArrayView> decode(QByteArrayView ba)
288 { return EncodedData<QByteArrayView>{this, ba}; }
289#endif
290
291 qsizetype requiredSpace(qsizetype inputLength) const
292 { return iface->toUtf16Len(inputLength); }
293 QChar *appendToBuffer(QChar *out, QByteArrayView ba)
294 { return iface->toUtf16(out, ba, &state); }
295private:
296 QString decodeAsString(QByteArrayView in)
297 {
298 QString result(iface->toUtf16Len(in.size()), Qt::Uninitialized);
299 const QChar *out = iface->toUtf16(result.data(), in, &state);
300 result.truncate(out - result.constData());
301 return result;
302 }
303};
304
305
306#if defined(QT_USE_FAST_OPERATOR_PLUS) || defined(QT_USE_QSTRINGBUILDER)
307template <typename T>
308struct QConcatenable<QStringDecoder::EncodedData<T>>
309 : private QAbstractConcatenable
310{
311 typedef QChar type;
312 typedef QString ConvertTo;
313 enum { ExactSize = false };
314 static qsizetype size(const QStringDecoder::EncodedData<T> &s) { return s.decoder->requiredSpace(s.data.size()); }
315 static inline void appendTo(const QStringDecoder::EncodedData<T> &s, QChar *&out)
316 {
317 out = s.decoder->appendToBuffer(out, s.data);
318 }
319};
320
321template <typename T>
322struct QConcatenable<QStringEncoder::DecodedData<T>>
323 : private QAbstractConcatenable
324{
325 typedef char type;
326 typedef QByteArray ConvertTo;
327 enum { ExactSize = false };
328 static qsizetype size(const QStringEncoder::DecodedData<T> &s) { return s.encoder->requiredSpace(s.data.size()); }
329 static inline void appendTo(const QStringEncoder::DecodedData<T> &s, char *&out)
330 {
331 out = s.encoder->appendToBuffer(out, s.data);
332 }
333};
334
335template <typename T>
336QString &operator+=(QString &a, const QStringDecoder::EncodedData<T> &b)
337{
338 qsizetype len = a.size() + QConcatenable<QStringDecoder::EncodedData<T>>::size(b);
339 a.reserve(len);
340 QChar *it = a.data() + a.size();
341 QConcatenable<QStringDecoder::EncodedData<T>>::appendTo(b, it);
342 a.resize(qsizetype(it - a.constData())); //may be smaller than len
343 return a;
344}
345
346template <typename T>
347QByteArray &operator+=(QByteArray &a, const QStringEncoder::DecodedData<T> &b)
348{
349 qsizetype len = a.size() + QConcatenable<QStringEncoder::DecodedData<T>>::size(b);
350 a.reserve(len);
351 char *it = a.data() + a.size();
352 QConcatenable<QStringEncoder::DecodedData<T>>::appendTo(b, it);
353 a.resize(qsizetype(it - a.constData())); //may be smaller than len
354 return a;
355}
356#endif
357
358QT_END_NAMESPACE
359
360#undef QSTRINGCONVERTER_CONSTEXPR
361
362#endif
363