1// Copyright (C) 2022 The Qt Company Ltd.
2// Copyright (C) 2016 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#ifndef QBYTEARRAY_H
6#define QBYTEARRAY_H
7
8#include <QtCore/qrefcount.h>
9#include <QtCore/qnamespace.h>
10#include <QtCore/qarraydata.h>
11#include <QtCore/qarraydatapointer.h>
12#include <QtCore/qcompare.h>
13#include <QtCore/qcontainerfwd.h>
14#include <QtCore/qbytearrayalgorithms.h>
15#include <QtCore/qbytearrayview.h>
16
17#include <stdlib.h>
18#include <string.h>
19
20#include <string>
21#include <iterator>
22
23#ifndef QT5_NULL_STRINGS
24// Would ideally be off, but in practice breaks too much (Qt 6.0).
25#define QT5_NULL_STRINGS 1
26#endif
27
28#ifdef truncate
29#error qbytearray.h must be included before any header file that defines truncate
30#endif
31
32#if defined(Q_OS_DARWIN) || defined(Q_QDOC)
33Q_FORWARD_DECLARE_CF_TYPE(CFData);
34Q_FORWARD_DECLARE_OBJC_CLASS(NSData);
35#endif
36
37#if defined(Q_OS_WASM) || defined(Q_QDOC)
38namespace emscripten {
39 class val;
40}
41#endif
42
43class tst_QByteArray;
44
45QT_BEGIN_NAMESPACE
46
47class QString;
48class QDataStream;
49
50using QByteArrayData = QArrayDataPointer<char>;
51
52# define QByteArrayLiteral(str) \
53 (QByteArray(QByteArrayData(nullptr, const_cast<char *>(str), sizeof(str) - 1))) \
54 /**/
55
56class Q_CORE_EXPORT QByteArray
57{
58public:
59 using DataPointer = QByteArrayData;
60private:
61 typedef QTypedArrayData<char> Data;
62
63 DataPointer d;
64 static const char _empty;
65
66 friend class ::tst_QByteArray;
67
68 template <typename InputIterator>
69 using if_input_iterator = QtPrivate::IfIsInputIterator<InputIterator>;
70public:
71 enum Base64Option {
72 Base64Encoding = 0,
73 Base64UrlEncoding = 1,
74
75 KeepTrailingEquals = 0,
76 OmitTrailingEquals = 2,
77
78 IgnoreBase64DecodingErrors = 0,
79 AbortOnBase64DecodingErrors = 4,
80 };
81 Q_DECLARE_FLAGS(Base64Options, Base64Option)
82
83 enum class Base64DecodingStatus {
84 Ok,
85 IllegalInputLength,
86 IllegalCharacter,
87 IllegalPadding,
88 };
89
90 inline constexpr QByteArray() noexcept;
91 QByteArray(const char *, qsizetype size = -1);
92 QByteArray(qsizetype size, char c);
93 QByteArray(qsizetype size, Qt::Initialization);
94 explicit QByteArray(QByteArrayView v) : QByteArray(v.data(), v.size()) {}
95 inline QByteArray(const QByteArray &) noexcept;
96 inline ~QByteArray();
97
98 QByteArray &operator=(const QByteArray &) noexcept;
99 QByteArray &operator=(const char *str);
100 inline QByteArray(QByteArray && other) noexcept
101 = default;
102 QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QByteArray)
103 inline void swap(QByteArray &other) noexcept
104 { d.swap(other&: other.d); }
105
106 bool isEmpty() const noexcept { return size() == 0; }
107 void resize(qsizetype size);
108 void resize(qsizetype size, char c);
109 void resizeForOverwrite(qsizetype size);
110
111 QByteArray &fill(char c, qsizetype size = -1);
112
113 inline qsizetype capacity() const;
114 inline void reserve(qsizetype size);
115 inline void squeeze();
116
117#ifndef QT_NO_CAST_FROM_BYTEARRAY
118 inline operator const char *() const;
119 inline operator const void *() const;
120#endif
121 inline char *data();
122 inline const char *data() const noexcept;
123 const char *constData() const noexcept { return data(); }
124 inline void detach();
125 inline bool isDetached() const;
126 inline bool isSharedWith(const QByteArray &other) const noexcept
127 { return data() == other.data() && size() == other.size(); }
128 void clear();
129
130 inline char at(qsizetype i) const;
131 inline char operator[](qsizetype i) const;
132 [[nodiscard]] inline char &operator[](qsizetype i);
133 [[nodiscard]] char front() const { return at(i: 0); }
134 [[nodiscard]] inline char &front();
135 [[nodiscard]] char back() const { return at(i: size() - 1); }
136 [[nodiscard]] inline char &back();
137
138 QT_CORE_INLINE_SINCE(6, 8)
139 qsizetype indexOf(char c, qsizetype from = 0) const;
140 qsizetype indexOf(QByteArrayView bv, qsizetype from = 0) const
141 { return QtPrivate::findByteArray(haystack: qToByteArrayViewIgnoringNull(b: *this), from, needle: bv); }
142
143 QT_CORE_INLINE_SINCE(6, 8)
144 qsizetype lastIndexOf(char c, qsizetype from = -1) const;
145 qsizetype lastIndexOf(QByteArrayView bv) const
146 { return lastIndexOf(bv, from: size()); }
147 qsizetype lastIndexOf(QByteArrayView bv, qsizetype from) const
148 { return QtPrivate::lastIndexOf(haystack: qToByteArrayViewIgnoringNull(b: *this), from, needle: bv); }
149
150 inline bool contains(char c) const;
151 inline bool contains(QByteArrayView bv) const;
152 qsizetype count(char c) const;
153 qsizetype count(QByteArrayView bv) const
154 { return QtPrivate::count(haystack: qToByteArrayViewIgnoringNull(b: *this), needle: bv); }
155
156 inline int compare(QByteArrayView a, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept;
157
158#if QT_CORE_REMOVED_SINCE(6, 7)
159 QByteArray left(qsizetype len) const;
160 QByteArray right(qsizetype len) const;
161 QByteArray mid(qsizetype index, qsizetype len = -1) const;
162 QByteArray first(qsizetype n) const;
163 QByteArray last(qsizetype n) const;
164 QByteArray sliced(qsizetype pos) const;
165 QByteArray sliced(qsizetype pos, qsizetype n) const;
166 QByteArray chopped(qsizetype len) const;
167#else
168 [[nodiscard]] QByteArray left(qsizetype n) const &
169 {
170 if (n >= size())
171 return *this;
172 return first(n: qMax(a: n, b: 0));
173 }
174 [[nodiscard]] QByteArray left(qsizetype n) &&
175 {
176 if (n >= size())
177 return std::move(*this);
178 return std::move(*this).first(n: qMax(a: n, b: 0));
179 }
180 [[nodiscard]] QByteArray right(qsizetype n) const &
181 {
182 if (n >= size())
183 return *this;
184 return last(n: qMax(a: n, b: 0));
185 }
186 [[nodiscard]] QByteArray right(qsizetype n) &&
187 {
188 if (n >= size())
189 return std::move(*this);
190 return std::move(*this).last(n: qMax(a: n, b: 0));
191 }
192 [[nodiscard]] QByteArray mid(qsizetype index, qsizetype len = -1) const &;
193 [[nodiscard]] QByteArray mid(qsizetype index, qsizetype len = -1) &&;
194
195 [[nodiscard]] QByteArray first(qsizetype n) const &
196 { verify(pos: 0, n); return sliced(pos: 0, n); }
197 [[nodiscard]] QByteArray last(qsizetype n) const &
198 { verify(pos: 0, n); return sliced(pos: size() - n, n); }
199 [[nodiscard]] QByteArray sliced(qsizetype pos) const &
200 { verify(pos, n: 0); return sliced(pos, n: size() - pos); }
201 [[nodiscard]] QByteArray sliced(qsizetype pos, qsizetype n) const &
202 { verify(pos, n); return QByteArray(d.data() + pos, n); }
203 [[nodiscard]] QByteArray chopped(qsizetype len) const &
204 { verify(pos: 0, n: len); return sliced(pos: 0, n: size() - len); }
205
206 [[nodiscard]] QByteArray first(qsizetype n) &&
207 {
208 verify(pos: 0, n);
209 resize(size: n); // may detach and allocate memory
210 return std::move(*this);
211 }
212 [[nodiscard]] QByteArray last(qsizetype n) &&
213 { verify(pos: 0, n); return sliced_helper(a&: *this, pos: size() - n, n); }
214 [[nodiscard]] QByteArray sliced(qsizetype pos) &&
215 { verify(pos, n: 0); return sliced_helper(a&: *this, pos, n: size() - pos); }
216 [[nodiscard]] QByteArray sliced(qsizetype pos, qsizetype n) &&
217 { verify(pos, n); return sliced_helper(a&: *this, pos, n); }
218 [[nodiscard]] QByteArray chopped(qsizetype len) &&
219 { verify(pos: 0, n: len); return std::move(*this).first(n: size() - len); }
220#endif
221
222 bool startsWith(QByteArrayView bv) const
223 { return QtPrivate::startsWith(haystack: qToByteArrayViewIgnoringNull(b: *this), needle: bv); }
224 bool startsWith(char c) const { return size() > 0 && front() == c; }
225
226 bool endsWith(char c) const { return size() > 0 && back() == c; }
227 bool endsWith(QByteArrayView bv) const
228 { return QtPrivate::endsWith(haystack: qToByteArrayViewIgnoringNull(b: *this), needle: bv); }
229
230 bool isUpper() const;
231 bool isLower() const;
232
233 [[nodiscard]] bool isValidUtf8() const noexcept
234 {
235 return QtPrivate::isValidUtf8(s: qToByteArrayViewIgnoringNull(b: *this));
236 }
237
238 void truncate(qsizetype pos);
239 void chop(qsizetype n);
240
241 QByteArray &slice(qsizetype pos)
242 { verify(pos, n: 0); return remove(index: 0, len: pos); }
243 QByteArray &slice(qsizetype pos, qsizetype n)
244 {
245 verify(pos, n);
246 if (isNull())
247 return *this;
248 resize(size: pos + n);
249 return remove(index: 0, len: pos);
250 }
251
252#if !defined(Q_QDOC)
253 [[nodiscard]] QByteArray toLower() const &
254 { return toLower_helper(a: *this); }
255 [[nodiscard]] QByteArray toLower() &&
256 { return toLower_helper(a&: *this); }
257 [[nodiscard]] QByteArray toUpper() const &
258 { return toUpper_helper(a: *this); }
259 [[nodiscard]] QByteArray toUpper() &&
260 { return toUpper_helper(a&: *this); }
261 [[nodiscard]] QByteArray trimmed() const &
262 { return trimmed_helper(a: *this); }
263 [[nodiscard]] QByteArray trimmed() &&
264 { return trimmed_helper(a&: *this); }
265 [[nodiscard]] QByteArray simplified() const &
266 { return simplified_helper(a: *this); }
267 [[nodiscard]] QByteArray simplified() &&
268 { return simplified_helper(a&: *this); }
269#else
270 [[nodiscard]] QByteArray toLower() const;
271 [[nodiscard]] QByteArray toUpper() const;
272 [[nodiscard]] QByteArray trimmed() const;
273 [[nodiscard]] QByteArray simplified() const;
274#endif
275
276 [[nodiscard]] QByteArray leftJustified(qsizetype width, char fill = ' ', bool truncate = false) const;
277 [[nodiscard]] QByteArray rightJustified(qsizetype width, char fill = ' ', bool truncate = false) const;
278
279 QByteArray &prepend(char c)
280 { return insert(i: 0, data: QByteArrayView(&c, 1)); }
281 inline QByteArray &prepend(qsizetype count, char c);
282 QByteArray &prepend(const char *s)
283 { return insert(i: 0, data: QByteArrayView(s, qsizetype(qstrlen(str: s)))); }
284 QByteArray &prepend(const char *s, qsizetype len)
285 { return insert(i: 0, data: QByteArrayView(s, len)); }
286 QByteArray &prepend(const QByteArray &a);
287 QByteArray &prepend(QByteArrayView a)
288 { return insert(i: 0, data: a); }
289
290 QByteArray &append(char c);
291 inline QByteArray &append(qsizetype count, char c);
292 QByteArray &append(const char *s)
293 { return append(s, len: -1); }
294 QByteArray &append(const char *s, qsizetype len)
295 { return append(a: QByteArrayView(s, len < 0 ? qsizetype(qstrlen(str: s)) : len)); }
296 QByteArray &append(const QByteArray &a);
297 QByteArray &append(QByteArrayView a)
298 { return insert(i: size(), data: a); }
299
300 QByteArray &assign(QByteArrayView v);
301 QByteArray &assign(qsizetype n, char c)
302 {
303 Q_ASSERT(n >= 0);
304 return fill(c, size: n);
305 }
306 template <typename InputIterator, if_input_iterator<InputIterator> = true>
307 QByteArray &assign(InputIterator first, InputIterator last)
308 {
309 d.assign(first, last);
310 if (d.data())
311 d.data()[d.size] = '\0';
312 return *this;
313 }
314
315 QByteArray &insert(qsizetype i, QByteArrayView data);
316 inline QByteArray &insert(qsizetype i, const char *s)
317 { return insert(i, data: QByteArrayView(s)); }
318 inline QByteArray &insert(qsizetype i, const QByteArray &data)
319 { return insert(i, data: QByteArrayView(data)); }
320 QByteArray &insert(qsizetype i, qsizetype count, char c);
321 QByteArray &insert(qsizetype i, char c)
322 { return insert(i, data: QByteArrayView(&c, 1)); }
323 QByteArray &insert(qsizetype i, const char *s, qsizetype len)
324 { return insert(i, data: QByteArrayView(s, len)); }
325
326 QByteArray &remove(qsizetype index, qsizetype len);
327 QByteArray &removeAt(qsizetype pos)
328 { return size_t(pos) < size_t(size()) ? remove(index: pos, len: 1) : *this; }
329 QByteArray &removeFirst() { return !isEmpty() ? remove(index: 0, len: 1) : *this; }
330 QByteArray &removeLast() { return !isEmpty() ? remove(index: size() - 1, len: 1) : *this; }
331
332 template <typename Predicate>
333 QByteArray &removeIf(Predicate pred)
334 {
335 removeIf_helper(pred);
336 return *this;
337 }
338
339 QByteArray &replace(qsizetype index, qsizetype len, const char *s, qsizetype alen)
340 { return replace(index, len, s: QByteArrayView(s, alen)); }
341 QByteArray &replace(qsizetype index, qsizetype len, QByteArrayView s);
342 QByteArray &replace(char before, QByteArrayView after)
343 { return replace(before: QByteArrayView(&before, 1), after); }
344 QByteArray &replace(const char *before, qsizetype bsize, const char *after, qsizetype asize)
345 { return replace(before: QByteArrayView(before, bsize), after: QByteArrayView(after, asize)); }
346 QByteArray &replace(QByteArrayView before, QByteArrayView after);
347 QByteArray &replace(char before, char after);
348
349 QByteArray &operator+=(char c)
350 { return append(c); }
351 QByteArray &operator+=(const char *s)
352 { return append(s); }
353 QByteArray &operator+=(const QByteArray &a)
354 { return append(a); }
355 QByteArray &operator+=(QByteArrayView a)
356 { return append(a); }
357
358 QList<QByteArray> split(char sep) const;
359
360 [[nodiscard]] QByteArray repeated(qsizetype times) const;
361
362#if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
363#if QT_CORE_REMOVED_SINCE(6, 8)
364 QT_ASCII_CAST_WARN inline bool operator==(const QString &s2) const;
365 QT_ASCII_CAST_WARN inline bool operator!=(const QString &s2) const;
366 QT_ASCII_CAST_WARN inline bool operator<(const QString &s2) const;
367 QT_ASCII_CAST_WARN inline bool operator>(const QString &s2) const;
368 QT_ASCII_CAST_WARN inline bool operator<=(const QString &s2) const;
369 QT_ASCII_CAST_WARN inline bool operator>=(const QString &s2) const;
370#endif // QT_CORE_REMOVED_SINCE(6, 8)
371#endif // !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
372
373 short toShort(bool *ok = nullptr, int base = 10) const;
374 ushort toUShort(bool *ok = nullptr, int base = 10) const;
375 int toInt(bool *ok = nullptr, int base = 10) const;
376 uint toUInt(bool *ok = nullptr, int base = 10) const;
377 long toLong(bool *ok = nullptr, int base = 10) const;
378 ulong toULong(bool *ok = nullptr, int base = 10) const;
379 qlonglong toLongLong(bool *ok = nullptr, int base = 10) const;
380 qulonglong toULongLong(bool *ok = nullptr, int base = 10) const;
381 float toFloat(bool *ok = nullptr) const;
382 double toDouble(bool *ok = nullptr) const;
383 QByteArray toBase64(Base64Options options = Base64Encoding) const;
384 QByteArray toHex(char separator = '\0') const;
385 QByteArray toPercentEncoding(const QByteArray &exclude = QByteArray(),
386 const QByteArray &include = QByteArray(),
387 char percent = '%') const;
388 [[nodiscard]] QByteArray percentDecoded(char percent = '%') const;
389
390 inline QByteArray &setNum(short, int base = 10);
391 inline QByteArray &setNum(ushort, int base = 10);
392 inline QByteArray &setNum(int, int base = 10);
393 inline QByteArray &setNum(uint, int base = 10);
394 inline QByteArray &setNum(long, int base = 10);
395 inline QByteArray &setNum(ulong, int base = 10);
396 QByteArray &setNum(qlonglong, int base = 10);
397 QByteArray &setNum(qulonglong, int base = 10);
398 inline QByteArray &setNum(float, char format = 'g', int precision = 6);
399 QByteArray &setNum(double, char format = 'g', int precision = 6);
400 QByteArray &setRawData(const char *a, qsizetype n);
401
402 [[nodiscard]] static QByteArray number(int, int base = 10);
403 [[nodiscard]] static QByteArray number(uint, int base = 10);
404 [[nodiscard]] static QByteArray number(long, int base = 10);
405 [[nodiscard]] static QByteArray number(ulong, int base = 10);
406 [[nodiscard]] static QByteArray number(qlonglong, int base = 10);
407 [[nodiscard]] static QByteArray number(qulonglong, int base = 10);
408 [[nodiscard]] static QByteArray number(double, char format = 'g', int precision = 6);
409 [[nodiscard]] static QByteArray fromRawData(const char *data, qsizetype size)
410 {
411 return QByteArray(DataPointer(nullptr, const_cast<char *>(data), size));
412 }
413
414 class FromBase64Result;
415 [[nodiscard]] static FromBase64Result fromBase64Encoding(QByteArray &&base64, Base64Options options = Base64Encoding);
416 [[nodiscard]] static FromBase64Result fromBase64Encoding(const QByteArray &base64, Base64Options options = Base64Encoding);
417 [[nodiscard]] static QByteArray fromBase64(const QByteArray &base64, Base64Options options = Base64Encoding);
418 [[nodiscard]] static QByteArray fromHex(const QByteArray &hexEncoded);
419 [[nodiscard]] static QByteArray fromPercentEncoding(const QByteArray &pctEncoded, char percent = '%');
420
421#if defined(Q_OS_DARWIN) || defined(Q_QDOC)
422 static QByteArray fromCFData(CFDataRef data);
423 static QByteArray fromRawCFData(CFDataRef data);
424 CFDataRef toCFData() const Q_DECL_CF_RETURNS_RETAINED;
425 CFDataRef toRawCFData() const Q_DECL_CF_RETURNS_RETAINED;
426 static QByteArray fromNSData(const NSData *data);
427 static QByteArray fromRawNSData(const NSData *data);
428 NSData *toNSData() const Q_DECL_NS_RETURNS_AUTORELEASED;
429 NSData *toRawNSData() const Q_DECL_NS_RETURNS_AUTORELEASED;
430#endif
431
432#if defined(Q_OS_WASM) || defined(Q_QDOC)
433 static QByteArray fromEcmaUint8Array(emscripten::val uint8array);
434 emscripten::val toEcmaUint8Array();
435#endif
436
437 typedef char *iterator;
438 typedef const char *const_iterator;
439 typedef iterator Iterator;
440 typedef const_iterator ConstIterator;
441 typedef std::reverse_iterator<iterator> reverse_iterator;
442 typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
443 iterator begin() { return data(); }
444 const_iterator begin() const noexcept { return d.data(); }
445 const_iterator cbegin() const noexcept { return begin(); }
446 const_iterator constBegin() const noexcept { return begin(); }
447 iterator end() { return begin() + size(); }
448 const_iterator end() const noexcept { return begin() + size(); }
449 const_iterator cend() const noexcept { return end(); }
450 const_iterator constEnd() const noexcept { return end(); }
451 reverse_iterator rbegin() { return reverse_iterator(end()); }
452 reverse_iterator rend() { return reverse_iterator(begin()); }
453 const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); }
454 const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); }
455 const_reverse_iterator crbegin() const noexcept { return rbegin(); }
456 const_reverse_iterator crend() const noexcept { return rend(); }
457
458 // stl compatibility
459 typedef qsizetype size_type;
460 typedef qptrdiff difference_type;
461 typedef const char & const_reference;
462 typedef char & reference;
463 typedef char *pointer;
464 typedef const char *const_pointer;
465 typedef char value_type;
466 void push_back(char c)
467 { append(c); }
468 void push_back(const char *s)
469 { append(s); }
470 void push_back(const QByteArray &a)
471 { append(a); }
472 void push_back(QByteArrayView a)
473 { append(a); }
474 void push_front(char c)
475 { prepend(c); }
476 void push_front(const char *c)
477 { prepend(s: c); }
478 void push_front(const QByteArray &a)
479 { prepend(a); }
480 void push_front(QByteArrayView a)
481 { prepend(a); }
482 void shrink_to_fit() { squeeze(); }
483 iterator erase(const_iterator first, const_iterator last);
484 inline iterator erase(const_iterator it) { return erase(first: it, last: it + 1); }
485 constexpr qsizetype max_size() const noexcept
486 {
487 return maxSize();
488 }
489
490 static QByteArray fromStdString(const std::string &s);
491 std::string toStdString() const;
492
493 static constexpr qsizetype maxSize() noexcept
494 {
495 // -1 to deal with the NUL terminator
496 return Data::maxSize() - 1;
497 }
498 inline qsizetype size() const noexcept { return d.size; }
499#if QT_DEPRECATED_SINCE(6, 4)
500 QT_DEPRECATED_VERSION_X_6_4("Use size() or length() instead.")
501 inline qsizetype count() const noexcept { return size(); }
502#endif
503 inline qsizetype length() const noexcept { return size(); }
504 QT_CORE_INLINE_SINCE(6, 4)
505 bool isNull() const noexcept;
506
507 inline const DataPointer &data_ptr() const { return d; }
508 inline DataPointer &data_ptr() { return d; }
509#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
510 explicit inline QByteArray(const DataPointer &dd) : d(dd) {}
511#endif
512 explicit inline QByteArray(DataPointer &&dd) : d(std::move(dd)) {}
513
514private:
515 friend bool comparesEqual(const QByteArray &lhs, const QByteArrayView &rhs) noexcept
516 { return QByteArrayView(lhs) == rhs; }
517 friend Qt::strong_ordering
518 compareThreeWay(const QByteArray &lhs, const QByteArrayView &rhs) noexcept
519 {
520 const int res = QtPrivate::compareMemory(lhs: QByteArrayView(lhs), rhs);
521 return Qt::compareThreeWay(lhs: res, rhs: 0);
522 }
523 Q_DECLARE_STRONGLY_ORDERED(QByteArray)
524 Q_DECLARE_STRONGLY_ORDERED(QByteArray, QByteArrayView)
525 Q_DECLARE_STRONGLY_ORDERED(QByteArray, const char *)
526#if defined(__GLIBCXX__) && defined(__cpp_lib_three_way_comparison)
527 // libstdc++ has a bug [0] when `operator const void *()` is preferred over
528 // `operator<=>()` when calling std::less<> and other similar methods.
529 // Fix it by explicitly providing relational operators in such case.
530 // [0]: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114153
531 friend bool operator<(const QByteArray &lhs, const QByteArray &rhs) noexcept
532 { return is_lt(compareThreeWay(lhs, rhs)); }
533 friend bool operator<=(const QByteArray &lhs, const QByteArray &rhs) noexcept
534 { return is_lteq(compareThreeWay(lhs, rhs)); }
535 friend bool operator>(const QByteArray &lhs, const QByteArray &rhs) noexcept
536 { return is_gt(compareThreeWay(lhs, rhs)); }
537 friend bool operator>=(const QByteArray &lhs, const QByteArray &rhs) noexcept
538 { return is_gteq(compareThreeWay(lhs, rhs)); }
539#endif // defined(__GLIBCXX__) && defined(__cpp_lib_three_way_comparison)
540
541 // Check isEmpty() instead of isNull() for backwards compatibility.
542 friend bool comparesEqual(const QByteArray &lhs, std::nullptr_t) noexcept
543 { return lhs.isEmpty(); }
544 friend Qt::strong_ordering compareThreeWay(const QByteArray &lhs, std::nullptr_t) noexcept
545 { return lhs.isEmpty() ? Qt::strong_ordering::equivalent : Qt::strong_ordering::greater; }
546 Q_DECLARE_STRONGLY_ORDERED(QByteArray, std::nullptr_t)
547
548 // defined in qstring.cpp
549 friend Q_CORE_EXPORT bool comparesEqual(const QByteArray &lhs, const QChar &rhs) noexcept;
550 friend Q_CORE_EXPORT Qt::strong_ordering
551 compareThreeWay(const QByteArray &lhs, const QChar &rhs) noexcept;
552 friend Q_CORE_EXPORT bool comparesEqual(const QByteArray &lhs, char16_t rhs) noexcept;
553 friend Q_CORE_EXPORT Qt::strong_ordering
554 compareThreeWay(const QByteArray &lhs, char16_t rhs) noexcept;
555#if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
556 Q_DECLARE_STRONGLY_ORDERED(QByteArray, QChar, QT_ASCII_CAST_WARN)
557 Q_DECLARE_STRONGLY_ORDERED(QByteArray, char16_t, QT_ASCII_CAST_WARN)
558#endif // !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
559
560
561 void reallocData(qsizetype alloc, QArrayData::AllocationOption option);
562 void reallocGrowData(qsizetype n);
563 void expand(qsizetype i);
564
565 Q_ALWAYS_INLINE constexpr void verify([[maybe_unused]] qsizetype pos = 0,
566 [[maybe_unused]] qsizetype n = 1) const
567 {
568 Q_ASSERT(pos >= 0);
569 Q_ASSERT(pos <= d.size);
570 Q_ASSERT(n >= 0);
571 Q_ASSERT(n <= d.size - pos);
572 }
573
574 static QByteArray sliced_helper(QByteArray &a, qsizetype pos, qsizetype n);
575 static QByteArray toLower_helper(const QByteArray &a);
576 static QByteArray toLower_helper(QByteArray &a);
577 static QByteArray toUpper_helper(const QByteArray &a);
578 static QByteArray toUpper_helper(QByteArray &a);
579 static QByteArray trimmed_helper(const QByteArray &a);
580 static QByteArray trimmed_helper(QByteArray &a);
581 static QByteArray simplified_helper(const QByteArray &a);
582 static QByteArray simplified_helper(QByteArray &a);
583 template <typename Predicate>
584 qsizetype removeIf_helper(Predicate pred)
585 {
586 const qsizetype result = d->eraseIf(pred);
587 if (result > 0)
588 d.data()[d.size] = '\0';
589 return result;
590 }
591
592 friend class QString;
593 friend Q_CORE_EXPORT QByteArray qUncompress(const uchar *data, qsizetype nbytes);
594
595 template <typename T> friend qsizetype erase(QByteArray &ba, const T &t);
596 template <typename Predicate> friend qsizetype erase_if(QByteArray &ba, Predicate pred);
597};
598
599Q_DECLARE_OPERATORS_FOR_FLAGS(QByteArray::Base64Options)
600
601inline constexpr QByteArray::QByteArray() noexcept {}
602inline QByteArray::~QByteArray() {}
603
604inline char QByteArray::at(qsizetype i) const
605{ verify(pos: i, n: 1); return d.data()[i]; }
606inline char QByteArray::operator[](qsizetype i) const
607{ verify(pos: i, n: 1); return d.data()[i]; }
608
609#ifndef QT_NO_CAST_FROM_BYTEARRAY
610inline QByteArray::operator const char *() const
611{ return data(); }
612inline QByteArray::operator const void *() const
613{ return data(); }
614#endif
615inline char *QByteArray::data()
616{
617 detach();
618 Q_ASSERT(d.data());
619 return d.data();
620}
621inline const char *QByteArray::data() const noexcept
622{
623#if QT5_NULL_STRINGS == 1
624 return d.data() ? d.data() : &_empty;
625#else
626 return d.data();
627#endif
628}
629inline void QByteArray::detach()
630{ if (d.needsDetach()) reallocData(alloc: size(), option: QArrayData::KeepSize); }
631inline bool QByteArray::isDetached() const
632{ return !d.isShared(); }
633inline QByteArray::QByteArray(const QByteArray &a) noexcept : d(a.d)
634{}
635
636inline qsizetype QByteArray::capacity() const { return qsizetype(d.constAllocatedCapacity()); }
637
638inline void QByteArray::reserve(qsizetype asize)
639{
640 if (d.needsDetach() || asize > capacity() - d.freeSpaceAtBegin())
641 reallocData(alloc: qMax(a: size(), b: asize), option: QArrayData::KeepSize);
642 if (d.constAllocatedCapacity())
643 d.setFlag(Data::CapacityReserved);
644}
645
646inline void QByteArray::squeeze()
647{
648 if (!d.isMutable())
649 return;
650 if (d.needsDetach() || size() < capacity())
651 reallocData(alloc: size(), option: QArrayData::KeepSize);
652 if (d.constAllocatedCapacity())
653 d.clearFlag(f: Data::CapacityReserved);
654}
655
656inline char &QByteArray::operator[](qsizetype i)
657{ verify(pos: i, n: 1); return data()[i]; }
658inline char &QByteArray::front() { return operator[](i: 0); }
659inline char &QByteArray::back() { return operator[](i: size() - 1); }
660inline QByteArray &QByteArray::append(qsizetype n, char ch)
661{ return insert(i: size(), count: n, c: ch); }
662inline QByteArray &QByteArray::prepend(qsizetype n, char ch)
663{ return insert(i: 0, count: n, c: ch); }
664inline bool QByteArray::contains(char c) const
665{ return indexOf(c) != -1; }
666inline bool QByteArray::contains(QByteArrayView bv) const
667{ return indexOf(bv) != -1; }
668inline int QByteArray::compare(QByteArrayView a, Qt::CaseSensitivity cs) const noexcept
669{
670 return cs == Qt::CaseSensitive ? QtPrivate::compareMemory(lhs: *this, rhs: a) :
671 qstrnicmp(data(), size(), a.data(), a.size());
672}
673#if !defined(QT_USE_QSTRINGBUILDER)
674inline QByteArray operator+(const QByteArray &a1, const QByteArray &a2)
675{ return QByteArray(a1) += a2; }
676inline QByteArray operator+(QByteArray &&lhs, const QByteArray &rhs)
677{ return std::move(lhs += rhs); }
678inline QByteArray operator+(const QByteArray &a1, const char *a2)
679{ return QByteArray(a1) += a2; }
680inline QByteArray operator+(QByteArray &&lhs, const char *rhs)
681{ return std::move(lhs += rhs); }
682inline QByteArray operator+(const QByteArray &a1, char a2)
683{ return QByteArray(a1) += a2; }
684inline QByteArray operator+(QByteArray &&lhs, char rhs)
685{ return std::move(lhs += rhs); }
686inline QByteArray operator+(const char *a1, const QByteArray &a2)
687{ return QByteArray(a1) += a2; }
688inline QByteArray operator+(char a1, const QByteArray &a2)
689{ return QByteArray(&a1, 1) += a2; }
690#endif // QT_USE_QSTRINGBUILDER
691
692inline QByteArray &QByteArray::setNum(short n, int base)
693{ return setNum(qlonglong(n), base); }
694inline QByteArray &QByteArray::setNum(ushort n, int base)
695{ return setNum(qulonglong(n), base); }
696inline QByteArray &QByteArray::setNum(int n, int base)
697{ return setNum(qlonglong(n), base); }
698inline QByteArray &QByteArray::setNum(uint n, int base)
699{ return setNum(qulonglong(n), base); }
700inline QByteArray &QByteArray::setNum(long n, int base)
701{ return setNum(qlonglong(n), base); }
702inline QByteArray &QByteArray::setNum(ulong n, int base)
703{ return setNum(qulonglong(n), base); }
704inline QByteArray &QByteArray::setNum(float n, char format, int precision)
705{ return setNum(double(n), format, precision); }
706
707#if QT_CORE_INLINE_IMPL_SINCE(6, 4)
708bool QByteArray::isNull() const noexcept
709{
710 return d.isNull();
711}
712#endif
713#if QT_CORE_INLINE_IMPL_SINCE(6, 8)
714qsizetype QByteArray::indexOf(char ch, qsizetype from) const
715{
716 return qToByteArrayViewIgnoringNull(b: *this).indexOf(ch, from);
717}
718qsizetype QByteArray::lastIndexOf(char ch, qsizetype from) const
719{
720 return qToByteArrayViewIgnoringNull(b: *this).lastIndexOf(ch, from);
721}
722#endif
723
724#if !defined(QT_NO_DATASTREAM) || defined(QT_BOOTSTRAPPED)
725Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, const QByteArray &);
726Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QByteArray &);
727#endif
728
729#ifndef QT_NO_COMPRESS
730Q_CORE_EXPORT QByteArray qCompress(const uchar* data, qsizetype nbytes, int compressionLevel = -1);
731Q_CORE_EXPORT QByteArray qUncompress(const uchar* data, qsizetype nbytes);
732inline QByteArray qCompress(const QByteArray& data, int compressionLevel = -1)
733{ return qCompress(data: reinterpret_cast<const uchar *>(data.constData()), nbytes: data.size(), compressionLevel); }
734inline QByteArray qUncompress(const QByteArray& data)
735{ return qUncompress(data: reinterpret_cast<const uchar*>(data.constData()), nbytes: data.size()); }
736#endif
737
738Q_DECLARE_SHARED(QByteArray)
739
740class QByteArray::FromBase64Result
741{
742public:
743 QByteArray decoded;
744 QByteArray::Base64DecodingStatus decodingStatus;
745
746 void swap(QByteArray::FromBase64Result &other) noexcept
747 {
748 decoded.swap(other&: other.decoded);
749 std::swap(a&: decodingStatus, b&: other.decodingStatus);
750 }
751
752 explicit operator bool() const noexcept { return decodingStatus == QByteArray::Base64DecodingStatus::Ok; }
753
754#if defined(Q_COMPILER_REF_QUALIFIERS) && !defined(Q_QDOC)
755 QByteArray &operator*() & noexcept { return decoded; }
756 const QByteArray &operator*() const & noexcept { return decoded; }
757 QByteArray &&operator*() && noexcept { return std::move(decoded); }
758#else
759 QByteArray &operator*() noexcept { return decoded; }
760 const QByteArray &operator*() const noexcept { return decoded; }
761#endif
762
763 friend inline bool operator==(const QByteArray::FromBase64Result &lhs, const QByteArray::FromBase64Result &rhs) noexcept
764 {
765 if (lhs.decodingStatus != rhs.decodingStatus)
766 return false;
767
768 if (lhs.decodingStatus == QByteArray::Base64DecodingStatus::Ok && lhs.decoded != rhs.decoded)
769 return false;
770
771 return true;
772 }
773
774 friend inline bool operator!=(const QByteArray::FromBase64Result &lhs, const QByteArray::FromBase64Result &rhs) noexcept
775 {
776 return !(lhs == rhs);
777 }
778};
779
780Q_DECLARE_SHARED(QByteArray::FromBase64Result)
781
782
783Q_CORE_EXPORT Q_DECL_PURE_FUNCTION size_t qHash(const QByteArray::FromBase64Result &key, size_t seed = 0) noexcept;
784
785template <typename T>
786qsizetype erase(QByteArray &ba, const T &t)
787{
788 return ba.removeIf_helper([&t](const auto &e) { return t == e; });
789}
790
791template <typename Predicate>
792qsizetype erase_if(QByteArray &ba, Predicate pred)
793{
794 return ba.removeIf_helper(pred);
795}
796
797//
798// QByteArrayView members that require QByteArray:
799//
800QByteArray QByteArrayView::toByteArray() const
801{
802 return QByteArray(*this);
803}
804
805namespace Qt {
806inline namespace Literals {
807inline namespace StringLiterals {
808
809inline QByteArray operator""_ba(const char *str, size_t size) noexcept
810{
811 return QByteArray(QByteArrayData(nullptr, const_cast<char *>(str), qsizetype(size)));
812}
813
814} // StringLiterals
815} // Literals
816} // Qt
817
818inline namespace QtLiterals {
819#if QT_DEPRECATED_SINCE(6, 8)
820
821QT_DEPRECATED_VERSION_X_6_8("Use _ba from Qt::StringLiterals namespace instead.")
822inline QByteArray operator""_qba(const char *str, size_t size) noexcept
823{
824 return Qt::StringLiterals::operator""_ba(str, size);
825}
826
827#endif // QT_DEPRECATED_SINCE(6, 8)
828} // QtLiterals
829
830QT_END_NAMESPACE
831
832#endif // QBYTEARRAY_H
833

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

source code of qtbase/src/corelib/text/qbytearray.h