1 /*
2     SPDX-FileCopyrightText: 2007-2009 Sergio Pistone <sergio_pistone@yahoo.com.ar>
3     SPDX-FileCopyrightText: 2010-2019 Mladen Milinkovic <max@smoothware.net>
4 
5     SPDX-License-Identifier: GPL-2.0-or-later
6 */
7 
8 #ifndef SSTRING_H
9 #define SSTRING_H
10 
11 #include <string.h>
12 
13 #include <QString>
14 #include <QRegExp>
15 #include <QList>
16 #include <QColor>
17 #include <QDataStream>
18 
19 #include <QDebug>
20 
21 void * memset_n(void *ptr, int value, size_t length, size_t size);
22 
23 namespace SubtitleComposer {
24 class SString;
25 
26 class SStringList : public QList<SString>
27 {
28 public:
29 	SStringList();
30 	SStringList(const SString &str);
31 	SStringList(const SStringList &list);
32 	SStringList(const QList<SString> &list);
33 	SStringList(const QStringList &list);
34 	SStringList(const QList<QString> &list);
35 
36 	SString join(const SString &sep) const;
37 
38 	SStringList& operator=(const SStringList& other) = default;
39 };
40 
41 class SString : public QString
42 {
43 public:
44 	typedef enum {
45 		Bold = 0x1,
46 		Italic = 0x2,
47 		Underline = 0x4,
48 		StrikeThrough = 0x8,
49 		Color = 0x10,
50 		AllStyles = Bold | Italic | Underline | StrikeThrough | Color
51 	} StyleFlag;
52 
53 	typedef enum {
54 		Compact,
55 		Verbose
56 	} RichOutputMode;
57 
58 	SString(const QString &string = QString(), int styleFlags = 0, QRgb styleColor = 0);            // krazy:exclude=c++/explicit
59 	SString(const SString &sstring);
60 	SString & operator=(const SString &sstring);
61 
62 	~SString();
63 
string()64 	inline QString string() const { return *this; }
65 	void setString(const QString &string, int styleFlags = 0, QRgb styleColor = 0);         // always clears all the style flags
66 
67 	QString richString(RichOutputMode mode = Compact) const;
68 	SString & setRichString(const QString &string);
69 
70 	int styleFlagsAt(int index) const;
71 	void setStyleFlagsAt(int index, int styleFlags) const;
72 	QRgb styleColorAt(int index) const;
73 	void setStyleColorAt(int index, QRgb rgbColor) const;
74 
75 	int cummulativeStyleFlags() const;
76 	bool hasStyleFlags(int styleFlags) const;
77 	SString & setStyleFlags(int index, int len, int styleFlags);
78 	SString & setStyleFlags(int index, int len, int styleFlags, bool on);
79 	SString & setStyleColor(int index, int len, QRgb color);
80 
81 	void clear();
82 
83 	SString & insert(int index, QChar ch);
84 	SString & insert(int index, const QString &str);
85 	SString & insert(int index, const SString &str);
86 	SString & append(QChar ch);
87 	SString & append(const QString &str);
88 	SString & append(const SString &str);
89 	SString & prepend(QChar ch);
90 	SString & prepend(const QString &str);
91 	SString & prepend(const SString &str);
92 	SString & operator+=(QChar ch);
93 	SString & operator+=(const QString &str);
94 	SString & operator+=(const SString &str);
95 
96 	SString & remove(int index, int len);
97 	SString & remove(const QString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive);
98 	SString & remove(QChar ch, Qt::CaseSensitivity cs = Qt::CaseSensitive);
99 	SString & remove(const QRegExp &rx);
100 
101 	SString & replace(int index, int len, const QString &replacement);
102 	SString & replace(int index, int len, const SString &replacement);
103 	SString & replace(const QString &before, const QString &after, Qt::CaseSensitivity cs = Qt::CaseSensitive);
104 	SString & replace(const QString &before, const SString &after, Qt::CaseSensitivity cs = Qt::CaseSensitive);
105 	SString & replace(QChar before, QChar after, Qt::CaseSensitivity cs = Qt::CaseSensitive);
106 	SString & replace(QChar ch, const QString &after, Qt::CaseSensitivity cs = Qt::CaseSensitive);
107 	SString & replace(QChar ch, const SString &after, Qt::CaseSensitivity cs = Qt::CaseSensitive);
108 	SString & replace(const QRegExp &regExp, const QString &replacement);
109 	SString & replace(const QRegExp &regExp, const SString &replacement);
110 	SString & replace(const QRegularExpression &regExp, const QString &replacement);
111 	SString & replace(const QRegularExpression &regExp, const SString &replacement, bool styleFromReplacement=true);
112 
113 	SStringList split(const QString &sep, QString::SplitBehavior behavior = QString::KeepEmptyParts, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
114 	SStringList split(const QChar &sep, QString::SplitBehavior behavior = QString::KeepEmptyParts, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
115 	SStringList split(const QRegExp &sep, QString::SplitBehavior behavior = QString::KeepEmptyParts) const;
116 
117 	SString left(int len) const;
118 	SString right(int len) const;
119 	SString mid(int index, int len = -1) const;
120 
121 	SString toLower() const;
122 	SString toUpper() const;
123 	SString toTitleCase(bool lowerFirst) const;
124 	SString toSentenceCase(bool lowerFirst, bool *cont) const;
125 
126 	SString simplified() const;
127 	SString trimmed() const;
128 
129 	static void simplifyWhiteSpace(QString &text);
130 	void simplifyWhiteSpace();
131 
132 	bool operator==(const SString &sstring) const;
133 	bool operator!=(const SString &sstring) const;
134 
135 	friend inline QDataStream & operator<<(QDataStream &stream, const SString &string);
136 	friend inline QDataStream & operator>>(QDataStream &stream, SString &string);
137 
length()138 	inline int length() const { return QString::length(); }
139 
140 private:
141 	char * detachFlags();
142 	QRgb * detachColors();
143 	void setMinFlagsCapacity(int capacity);
144 
145 	int length(int index, int len) const;
146 
147 private:
148 	char *m_styleFlags;
149 	QRgb *m_styleColors;
150 	int m_capacity;
151 };
152 
153 inline int
styleFlagsAt(int index)154 SString::styleFlagsAt(int index) const
155 {
156 	return index < 0 || index >= length() ? 0 : m_styleFlags[index];
157 }
158 
159 inline void
setStyleFlagsAt(int index,int styleFlags)160 SString::setStyleFlagsAt(int index, int styleFlags) const
161 {
162 	if(index < 0 || index >= length())
163 		return;
164 	m_styleFlags[index] = styleFlags;
165 }
166 
167 inline QRgb
styleColorAt(int index)168 SString::styleColorAt(int index) const
169 {
170 	return index < 0 || index >= length() || (m_styleFlags[index] & SString::Color) == 0 ? 0 : m_styleColors[index];
171 }
172 
173 inline void
setStyleColorAt(int index,QRgb rgbColor)174 SString::setStyleColorAt(int index, QRgb rgbColor) const
175 {
176 	if(index < 0 || index >= length())
177 		return;
178 	if(rgbColor == 0)
179 		m_styleFlags[index] &= ~SString::Color;
180 	else
181 		m_styleFlags[index] |= SString::Color;
182 	m_styleColors[index] = rgbColor;
183 }
184 
185 inline SString &
append(QChar ch)186 SString::append(QChar ch)
187 {
188 	return insert(length(), ch);
189 }
190 
191 inline SString &
append(const QString & str)192 SString::append(const QString &str)
193 {
194 	return insert(length(), str);
195 }
196 
197 inline SString &
append(const SString & str)198 SString::append(const SString &str)
199 {
200 	return insert(length(), str);
201 }
202 
203 inline SString &
prepend(QChar ch)204 SString::prepend(QChar ch)
205 {
206 	return insert(0, ch);
207 }
208 
209 inline SString &
prepend(const QString & str)210 SString::prepend(const QString &str)
211 {
212 	return insert(0, str);
213 }
214 
215 inline SString &
prepend(const SString & str)216 SString::prepend(const SString &str)
217 {
218 	return insert(0, str);
219 }
220 
221 inline SString &
222 SString::operator+=(const QChar ch)
223 {
224 	return append(ch);
225 }
226 
227 inline SString &
228 SString::operator+=(const QString &str)
229 {
230 	return append(str);
231 }
232 
233 inline SString &
234 SString::operator+=(const SString &str)
235 {
236 	return append(str);
237 }
238 
239 inline SString &
remove(int index,int len)240 SString::remove(int index, int len)
241 {
242 	return replace(index, len, QString());
243 }
244 
245 inline SString &
remove(const QString & str,Qt::CaseSensitivity cs)246 SString::remove(const QString &str, Qt::CaseSensitivity cs)
247 {
248 	return replace(str, QString(), cs);
249 }
250 
251 inline SString &
remove(QChar ch,Qt::CaseSensitivity cs)252 SString::remove(QChar ch, Qt::CaseSensitivity cs)
253 {
254 	return replace(ch, QString(), cs);
255 }
256 
257 inline SString &
remove(const QRegExp & rx)258 SString::remove(const QRegExp &rx)
259 {
260 	return replace(rx, QString());
261 }
262 
263 inline bool
264 SString::operator==(const SString &sstring) const
265 {
266 	return !operator!=(sstring);
267 }
268 
269 inline int
length(int index,int len)270 SString::length(int index, int len) const
271 {
272 	return len < 0 || (index + len) > length() ? length() - index : len;
273 }
274 
275 inline QDataStream &
276 operator<<(QDataStream &stream, const SubtitleComposer::SString &string) {
277 	stream << static_cast<const QString &>(string);
278 	stream.writeRawData(string.m_styleFlags, string.length() * sizeof(*string.m_styleFlags));
279 	stream.writeRawData(reinterpret_cast<const char *>(string.m_styleColors), string.length() * sizeof(*string.m_styleColors));
280 
281 	return stream;
282 }
283 
284 inline QDataStream &
285 operator>>(QDataStream &stream, SubtitleComposer::SString &string) {
286 	stream >> static_cast<QString &>(string);
287 	string.setMinFlagsCapacity(string.size());
288 	stream.readRawData(string.m_styleFlags, string.length() * sizeof(*string.m_styleFlags));
289 	stream.readRawData(reinterpret_cast<char *>(string.m_styleColors), string.length() * sizeof(*string.m_styleColors));
290 
291 	return stream;
292 }
293 }
294 
295 #endif
296