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 | |
4 | #if 0 |
5 | // keep existing syncqt header working after the move of the class |
6 | // into qstringconverter_base |
7 | #pragma qt_class(QStringConverter) |
8 | #pragma qt_class(QStringConverterBase) |
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 | |
18 | QT_BEGIN_NAMESPACE |
19 | |
20 | class QStringEncoder : public QStringConverter |
21 | { |
22 | protected: |
23 | constexpr explicit QStringEncoder(const Interface *i) noexcept |
24 | : QStringConverter(i) |
25 | {} |
26 | public: |
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(const char *name, Flags flags = Flag::Default) |
34 | : QStringConverter(name, flags) |
35 | {} |
36 | |
37 | #if defined(Q_QDOC) |
38 | QByteArray operator()(const QString &in); |
39 | QByteArray operator()(QStringView in); |
40 | QByteArray encode(const QString &in); |
41 | QByteArray encode(QStringView in); |
42 | #else |
43 | template<typename T> |
44 | struct DecodedData |
45 | { |
46 | QStringEncoder *encoder; |
47 | T data; |
48 | operator QByteArray() const { return encoder->encodeAsByteArray(in: data); } |
49 | }; |
50 | Q_WEAK_OVERLOAD |
51 | DecodedData<const QString &> operator()(const QString &str) |
52 | { return DecodedData<const QString &>{.encoder: this, .data: str}; } |
53 | DecodedData<QStringView> operator()(QStringView in) |
54 | { return DecodedData<QStringView>{.encoder: this, .data: in}; } |
55 | Q_WEAK_OVERLOAD |
56 | DecodedData<const QString &> encode(const QString &str) |
57 | { return DecodedData<const QString &>{.encoder: this, .data: str}; } |
58 | DecodedData<QStringView> encode(QStringView in) |
59 | { return DecodedData<QStringView>{.encoder: this, .data: in}; } |
60 | #endif |
61 | |
62 | qsizetype requiredSpace(qsizetype inputLength) const |
63 | { return iface ? iface->fromUtf16Len(inputLength) : 0; } |
64 | char *appendToBuffer(char *out, QStringView in) |
65 | { |
66 | if (!iface) { |
67 | state.invalidChars = 1; |
68 | return out; |
69 | } |
70 | return iface->fromUtf16(out, in, &state); |
71 | } |
72 | private: |
73 | QByteArray encodeAsByteArray(QStringView in) |
74 | { |
75 | if (!iface) { |
76 | // ensure that hasError returns true |
77 | state.invalidChars = 1; |
78 | return {}; |
79 | } |
80 | QByteArray result(iface->fromUtf16Len(in.size()), Qt::Uninitialized); |
81 | char *out = result.data(); |
82 | out = iface->fromUtf16(out, in, &state); |
83 | result.truncate(pos: out - result.constData()); |
84 | return result; |
85 | } |
86 | |
87 | }; |
88 | |
89 | class QStringDecoder : public QStringConverter |
90 | { |
91 | protected: |
92 | constexpr explicit QStringDecoder(const Interface *i) noexcept |
93 | : QStringConverter(i) |
94 | {} |
95 | public: |
96 | constexpr explicit QStringDecoder(Encoding encoding, Flags flags = Flag::Default) |
97 | : QStringConverter(encoding, flags) |
98 | {} |
99 | constexpr QStringDecoder() noexcept |
100 | : QStringConverter() |
101 | {} |
102 | explicit QStringDecoder(const char *name, Flags f = Flag::Default) |
103 | : QStringConverter(name, f) |
104 | {} |
105 | |
106 | #if defined(Q_QDOC) |
107 | QString operator()(const QByteArray &ba); |
108 | QString operator()(QByteArrayView ba); |
109 | QString decode(const QByteArray &ba); |
110 | QString decode(QByteArrayView ba); |
111 | #else |
112 | template<typename T> |
113 | struct EncodedData |
114 | { |
115 | QStringDecoder *decoder; |
116 | T data; |
117 | operator QString() const { return decoder->decodeAsString(in: data); } |
118 | }; |
119 | Q_WEAK_OVERLOAD |
120 | EncodedData<const QByteArray &> operator()(const QByteArray &ba) |
121 | { return EncodedData<const QByteArray &>{.decoder: this, .data: ba}; } |
122 | EncodedData<QByteArrayView> operator()(QByteArrayView ba) |
123 | { return EncodedData<QByteArrayView>{.decoder: this, .data: ba}; } |
124 | Q_WEAK_OVERLOAD |
125 | EncodedData<const QByteArray &> decode(const QByteArray &ba) |
126 | { return EncodedData<const QByteArray &>{.decoder: this, .data: ba}; } |
127 | EncodedData<QByteArrayView> decode(QByteArrayView ba) |
128 | { return EncodedData<QByteArrayView>{.decoder: this, .data: ba}; } |
129 | #endif |
130 | |
131 | qsizetype requiredSpace(qsizetype inputLength) const |
132 | { return iface ? iface->toUtf16Len(inputLength) : 0; } |
133 | QChar *appendToBuffer(QChar *out, QByteArrayView ba) |
134 | { |
135 | if (!iface) { |
136 | state.invalidChars = 1; |
137 | return out; |
138 | } |
139 | return iface->toUtf16(out, ba, &state); |
140 | } |
141 | char16_t *appendToBuffer(char16_t *out, QByteArrayView ba) |
142 | { return reinterpret_cast<char16_t *>(appendToBuffer(out: reinterpret_cast<QChar *>(out), ba)); } |
143 | |
144 | Q_CORE_EXPORT static QStringDecoder decoderForHtml(QByteArrayView data); |
145 | |
146 | private: |
147 | QString decodeAsString(QByteArrayView in) |
148 | { |
149 | if (!iface) { |
150 | // ensure that hasError returns true |
151 | state.invalidChars = 1; |
152 | return {}; |
153 | } |
154 | QString result(iface->toUtf16Len(in.size()), Qt::Uninitialized); |
155 | const QChar *out = iface->toUtf16(result.data(), in, &state); |
156 | result.truncate(pos: out - result.constData()); |
157 | return result; |
158 | } |
159 | }; |
160 | |
161 | |
162 | #if defined(QT_USE_FAST_OPERATOR_PLUS) || defined(QT_USE_QSTRINGBUILDER) |
163 | template <typename T> |
164 | struct QConcatenable<QStringDecoder::EncodedData<T>> |
165 | : private QAbstractConcatenable |
166 | { |
167 | typedef QChar type; |
168 | typedef QString ConvertTo; |
169 | enum { ExactSize = false }; |
170 | static qsizetype size(const QStringDecoder::EncodedData<T> &s) { return s.decoder->requiredSpace(s.data.size()); } |
171 | static inline void appendTo(const QStringDecoder::EncodedData<T> &s, QChar *&out) |
172 | { |
173 | out = s.decoder->appendToBuffer(out, s.data); |
174 | } |
175 | }; |
176 | |
177 | template <typename T> |
178 | struct QConcatenable<QStringEncoder::DecodedData<T>> |
179 | : private QAbstractConcatenable |
180 | { |
181 | typedef char type; |
182 | typedef QByteArray ConvertTo; |
183 | enum { ExactSize = false }; |
184 | static qsizetype size(const QStringEncoder::DecodedData<T> &s) { return s.encoder->requiredSpace(s.data.size()); } |
185 | static inline void appendTo(const QStringEncoder::DecodedData<T> &s, char *&out) |
186 | { |
187 | out = s.encoder->appendToBuffer(out, s.data); |
188 | } |
189 | }; |
190 | |
191 | template <typename T> |
192 | QString &operator+=(QString &a, const QStringDecoder::EncodedData<T> &b) |
193 | { |
194 | qsizetype len = a.size() + QConcatenable<QStringDecoder::EncodedData<T>>::size(b); |
195 | a.reserve(asize: len); |
196 | QChar *it = a.data() + a.size(); |
197 | QConcatenable<QStringDecoder::EncodedData<T>>::appendTo(b, it); |
198 | a.resize(size: qsizetype(it - a.constData())); //may be smaller than len |
199 | return a; |
200 | } |
201 | |
202 | template <typename T> |
203 | QByteArray &operator+=(QByteArray &a, const QStringEncoder::DecodedData<T> &b) |
204 | { |
205 | qsizetype len = a.size() + QConcatenable<QStringEncoder::DecodedData<T>>::size(b); |
206 | a.reserve(asize: len); |
207 | char *it = a.data() + a.size(); |
208 | QConcatenable<QStringEncoder::DecodedData<T>>::appendTo(b, it); |
209 | a.resize(size: qsizetype(it - a.constData())); //may be smaller than len |
210 | return a; |
211 | } |
212 | #endif |
213 | |
214 | QT_END_NAMESPACE |
215 | |
216 | #endif |
217 | |