1// Copyright (C) 2022 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#ifndef QSTRINGCONVERTER_BASE_H
5#define QSTRINGCONVERTER_BASE_H
6
7#if 0
8// QStringConverter(Base) class are handled in qstringconverter
9#pragma qt_sync_stop_processing
10#endif
11
12#include <optional>
13
14#include <QtCore/qglobal.h> // QT_{BEGIN,END}_NAMESPACE
15#include <QtCore/qflags.h> // Q_DECLARE_FLAGS
16#include <QtCore/qcontainerfwd.h>
17
18#include <cstring>
19
20QT_BEGIN_NAMESPACE
21
22class QByteArrayView;
23class QChar;
24class QByteArrayView;
25class QStringView;
26
27class QStringConverterBase
28{
29public:
30 enum class Flag {
31 Default = 0,
32 Stateless = 0x1,
33 ConvertInvalidToNull = 0x2,
34 WriteBom = 0x4,
35 ConvertInitialBom = 0x8,
36 UsesIcu = 0x10,
37 };
38 Q_DECLARE_FLAGS(Flags, Flag)
39
40 struct State {
41 constexpr State(Flags f = Flag::Default) noexcept
42 : flags(f), state_data{0, 0, 0, 0} {}
43 ~State() { clear(); }
44
45 State(State &&other) noexcept
46 : flags(other.flags),
47 remainingChars(other.remainingChars),
48 invalidChars(other.invalidChars),
49 state_data{other.state_data[0], other.state_data[1],
50 other.state_data[2], other.state_data[3]},
51 clearFn(other.clearFn)
52 { other.clearFn = nullptr; }
53 State &operator=(State &&other) noexcept
54 {
55 clear();
56 flags = other.flags;
57 remainingChars = other.remainingChars;
58 invalidChars = other.invalidChars;
59 std::memmove(dest: state_data, src: other.state_data, n: sizeof state_data); // self-assignment-safe
60 clearFn = other.clearFn;
61 other.clearFn = nullptr;
62 return *this;
63 }
64 Q_CORE_EXPORT void clear() noexcept;
65 Q_CORE_EXPORT void reset() noexcept;
66
67 Flags flags;
68 int internalState = 0;
69 qsizetype remainingChars = 0;
70 qsizetype invalidChars = 0;
71
72 union {
73 uint state_data[4];
74 void *d[2];
75 };
76 using ClearDataFn = void (*)(State *) noexcept;
77 ClearDataFn clearFn = nullptr;
78 private:
79 Q_DISABLE_COPY(State)
80 };
81protected:
82 ~QStringConverterBase() = default;
83};
84Q_DECLARE_OPERATORS_FOR_FLAGS(QStringConverterBase::Flags)
85
86class QStringConverter : public QStringConverterBase
87{
88public:
89
90 enum Encoding {
91 Utf8,
92 Utf16,
93 Utf16LE,
94 Utf16BE,
95 Utf32,
96 Utf32LE,
97 Utf32BE,
98 Latin1,
99 System,
100 LastEncoding = System
101 };
102#ifdef Q_QDOC
103 // document the flags here
104 enum class Flag {
105 Default = 0,
106 Stateless = 0x1,
107 ConvertInvalidToNull = 0x2,
108 WriteBom = 0x4,
109 ConvertInitialBom = 0x8,
110 UsesIcu = 0x10,
111 };
112 Q_DECLARE_FLAGS(Flags, Flag)
113#endif
114
115protected:
116
117 struct Interface
118 {
119 using DecoderFn = QChar * (*)(QChar *out, QByteArrayView in, State *state);
120 using LengthFn = qsizetype (*)(qsizetype inLength);
121 using EncoderFn = char * (*)(char *out, QStringView in, State *state);
122 const char *name = nullptr;
123 DecoderFn toUtf16 = nullptr;
124 LengthFn toUtf16Len = nullptr;
125 EncoderFn fromUtf16 = nullptr;
126 LengthFn fromUtf16Len = nullptr;
127 };
128
129 constexpr QStringConverter() noexcept
130 : iface(nullptr)
131 {}
132 constexpr explicit QStringConverter(Encoding encoding, Flags f)
133 : iface(&encodingInterfaces[qsizetype(encoding)]), state(f)
134 {}
135 constexpr explicit QStringConverter(const Interface *i) noexcept
136 : iface(i)
137 {}
138 Q_CORE_EXPORT explicit QStringConverter(const char *name, Flags f);
139
140
141 ~QStringConverter() = default;
142
143public:
144 QStringConverter(QStringConverter &&) = default;
145 QStringConverter &operator=(QStringConverter &&) = default;
146
147 bool isValid() const noexcept { return iface != nullptr; }
148
149 void resetState() noexcept
150 {
151 state.reset();
152 }
153 bool hasError() const noexcept { return state.invalidChars != 0; }
154
155 Q_CORE_EXPORT const char *name() const noexcept;
156
157 Q_CORE_EXPORT static std::optional<Encoding> encodingForName(const char *name) noexcept;
158 Q_CORE_EXPORT static const char *nameForEncoding(Encoding e);
159 Q_CORE_EXPORT static std::optional<Encoding>
160 encodingForData(QByteArrayView data, char16_t expectedFirstCharacter = 0) noexcept;
161 Q_CORE_EXPORT static std::optional<Encoding> encodingForHtml(QByteArrayView data);
162
163 Q_CORE_EXPORT static QStringList availableCodecs();
164
165protected:
166 const Interface *iface;
167 State state;
168private:
169 Q_CORE_EXPORT static const Interface encodingInterfaces[Encoding::LastEncoding + 1];
170};
171
172QT_END_NAMESPACE
173
174#endif
175