1// Copyright (C) 2021 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 QDATASTREAM_H
5#define QDATASTREAM_H
6
7#include <QtCore/qscopedpointer.h>
8#include <QtCore/qiodevicebase.h>
9#include <QtCore/qcontainerfwd.h>
10#include <QtCore/qnamespace.h>
11
12#include <iterator> // std::distance(), std::next()
13
14#ifdef Status
15#error qdatastream.h must be included before any header file that defines Status
16#endif
17
18QT_BEGIN_NAMESPACE
19
20#if QT_CORE_REMOVED_SINCE(6, 3)
21class qfloat16;
22#endif
23class QByteArray;
24class QDataStream;
25class QIODevice;
26class QString;
27
28#if !defined(QT_NO_DATASTREAM) || defined(QT_BOOTSTRAPPED)
29class QDataStreamPrivate;
30namespace QtPrivate {
31class StreamStateSaver;
32template <typename Container>
33QDataStream &readArrayBasedContainer(QDataStream &s, Container &c);
34template <typename Container>
35QDataStream &readListBasedContainer(QDataStream &s, Container &c);
36template <typename Container>
37QDataStream &readAssociativeContainer(QDataStream &s, Container &c);
38template <typename Container>
39QDataStream &writeSequentialContainer(QDataStream &s, const Container &c);
40template <typename Container>
41QDataStream &writeAssociativeContainer(QDataStream &s, const Container &c);
42template <typename Container>
43QDataStream &writeAssociativeMultiContainer(QDataStream &s, const Container &c);
44}
45class Q_CORE_EXPORT QDataStream : public QIODeviceBase
46{
47public:
48 enum Version {
49 Qt_1_0 = 1,
50 Qt_2_0 = 2,
51 Qt_2_1 = 3,
52 Qt_3_0 = 4,
53 Qt_3_1 = 5,
54 Qt_3_3 = 6,
55 Qt_4_0 = 7,
56 Qt_4_1 = Qt_4_0,
57 Qt_4_2 = 8,
58 Qt_4_3 = 9,
59 Qt_4_4 = 10,
60 Qt_4_5 = 11,
61 Qt_4_6 = 12,
62 Qt_4_7 = Qt_4_6,
63 Qt_4_8 = Qt_4_7,
64 Qt_4_9 = Qt_4_8,
65 Qt_5_0 = 13,
66 Qt_5_1 = 14,
67 Qt_5_2 = 15,
68 Qt_5_3 = Qt_5_2,
69 Qt_5_4 = 16,
70 Qt_5_5 = Qt_5_4,
71 Qt_5_6 = 17,
72 Qt_5_7 = Qt_5_6,
73 Qt_5_8 = Qt_5_7,
74 Qt_5_9 = Qt_5_8,
75 Qt_5_10 = Qt_5_9,
76 Qt_5_11 = Qt_5_10,
77 Qt_5_12 = 18,
78 Qt_5_13 = 19,
79 Qt_5_14 = Qt_5_13,
80 Qt_5_15 = Qt_5_14,
81 Qt_6_0 = 20,
82 Qt_6_1 = Qt_6_0,
83 Qt_6_2 = Qt_6_0,
84 Qt_6_3 = Qt_6_0,
85 Qt_6_4 = Qt_6_0,
86 Qt_6_5 = Qt_6_0,
87 Qt_6_6 = 21,
88 Qt_6_7 = 22,
89 Qt_DefaultCompiledVersion = Qt_6_7
90#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
91#error Add the datastream version for this Qt version and update Qt_DefaultCompiledVersion
92#endif
93 };
94
95 enum ByteOrder {
96 BigEndian = QSysInfo::BigEndian,
97 LittleEndian = QSysInfo::LittleEndian
98 };
99
100 enum Status {
101 Ok,
102 ReadPastEnd,
103 ReadCorruptData,
104 WriteFailed,
105 SizeLimitExceeded,
106 };
107
108 enum FloatingPointPrecision {
109 SinglePrecision,
110 DoublePrecision
111 };
112
113 QDataStream();
114 explicit QDataStream(QIODevice *);
115 QDataStream(QByteArray *, OpenMode flags);
116 QDataStream(const QByteArray &);
117 ~QDataStream();
118
119 QIODevice *device() const;
120 void setDevice(QIODevice *);
121
122 bool atEnd() const;
123
124 Status status() const;
125 void setStatus(Status status);
126 void resetStatus();
127
128 FloatingPointPrecision floatingPointPrecision() const;
129 void setFloatingPointPrecision(FloatingPointPrecision precision);
130
131 ByteOrder byteOrder() const;
132 void setByteOrder(ByteOrder);
133
134 int version() const;
135 void setVersion(int);
136
137 QDataStream &operator>>(char &i);
138 QDataStream &operator>>(qint8 &i);
139 QDataStream &operator>>(quint8 &i);
140 QDataStream &operator>>(qint16 &i);
141 QDataStream &operator>>(quint16 &i);
142 QDataStream &operator>>(qint32 &i);
143 inline QDataStream &operator>>(quint32 &i);
144 QDataStream &operator>>(qint64 &i);
145 QDataStream &operator>>(quint64 &i);
146 QDataStream &operator>>(std::nullptr_t &ptr) { ptr = nullptr; return *this; }
147
148 QDataStream &operator>>(bool &i);
149#if QT_CORE_REMOVED_SINCE(6, 3)
150 QDataStream &operator>>(qfloat16 &f);
151#endif
152 QDataStream &operator>>(float &f);
153 QDataStream &operator>>(double &f);
154 QDataStream &operator>>(char *&str);
155 QDataStream &operator>>(char16_t &c);
156 QDataStream &operator>>(char32_t &c);
157
158 QDataStream &operator<<(char i);
159 QDataStream &operator<<(qint8 i);
160 QDataStream &operator<<(quint8 i);
161 QDataStream &operator<<(qint16 i);
162 QDataStream &operator<<(quint16 i);
163 QDataStream &operator<<(qint32 i);
164 inline QDataStream &operator<<(quint32 i);
165 QDataStream &operator<<(qint64 i);
166 QDataStream &operator<<(quint64 i);
167 QDataStream &operator<<(std::nullptr_t) { return *this; }
168 QDataStream &operator<<(bool i);
169#if QT_CORE_REMOVED_SINCE(6, 3)
170 QDataStream &operator<<(qfloat16 f);
171#endif
172 QDataStream &operator<<(float f);
173 QDataStream &operator<<(double f);
174 QDataStream &operator<<(const char *str);
175 QDataStream &operator<<(char16_t c);
176 QDataStream &operator<<(char32_t c);
177 QDataStream &operator<<(const volatile void *) = delete;
178
179#if QT_DEPRECATED_SINCE(6, 11)
180 QT_DEPRECATED_VERSION_X_6_11("Use an overload that takes qint64 length.")
181 QDataStream &readBytes(char *&, uint &len);
182#endif
183#if QT_CORE_REMOVED_SINCE(6, 7)
184 QDataStream &writeBytes(const char *, uint len);
185 int skipRawData(int len);
186 int readRawData(char *, int len);
187 int writeRawData(const char *, int len);
188#endif
189 QDataStream &readBytes(char *&, qint64 &len);
190 qint64 readRawData(char *, qint64 len);
191 QDataStream &writeBytes(const char *, qint64 len);
192 qint64 writeRawData(const char *, qint64 len);
193 qint64 skipRawData(qint64 len);
194
195 void startTransaction();
196 bool commitTransaction();
197 void rollbackTransaction();
198 void abortTransaction();
199
200 bool isDeviceTransactionStarted() const;
201private:
202 Q_DISABLE_COPY(QDataStream)
203
204 QScopedPointer<QDataStreamPrivate> d;
205
206 QIODevice *dev;
207 bool owndev;
208 bool noswap;
209 ByteOrder byteorder;
210 int ver;
211 Status q_status;
212#if QT_CORE_REMOVED_SINCE(6, 7)
213 int readBlock(char *data, int len);
214#endif
215 qint64 readBlock(char *data, qint64 len);
216 static inline qint64 readQSizeType(QDataStream &s);
217 static inline bool writeQSizeType(QDataStream &s, qint64 value);
218 static constexpr quint32 NullCode = 0xffffffffu;
219 static constexpr quint32 ExtendedSize = 0xfffffffeu;
220
221 friend class QtPrivate::StreamStateSaver;
222 Q_CORE_EXPORT friend QDataStream &operator<<(QDataStream &out, const QString &str);
223 Q_CORE_EXPORT friend QDataStream &operator>>(QDataStream &in, QString &str);
224 Q_CORE_EXPORT friend QDataStream &operator<<(QDataStream &out, const QByteArray &ba);
225 Q_CORE_EXPORT friend QDataStream &operator>>(QDataStream &in, QByteArray &ba);
226 template <typename Container>
227 friend QDataStream &QtPrivate::readArrayBasedContainer(QDataStream &s, Container &c);
228 template <typename Container>
229 friend QDataStream &QtPrivate::readListBasedContainer(QDataStream &s, Container &c);
230 template <typename Container>
231 friend QDataStream &QtPrivate::readAssociativeContainer(QDataStream &s, Container &c);
232 template <typename Container>
233 friend QDataStream &QtPrivate::writeSequentialContainer(QDataStream &s, const Container &c);
234 template <typename Container>
235 friend QDataStream &QtPrivate::writeAssociativeContainer(QDataStream &s, const Container &c);
236 template <typename Container>
237 friend QDataStream &QtPrivate::writeAssociativeMultiContainer(QDataStream &s,
238 const Container &c);
239};
240
241namespace QtPrivate {
242
243class StreamStateSaver
244{
245 Q_DISABLE_COPY_MOVE(StreamStateSaver)
246public:
247 inline StreamStateSaver(QDataStream *s) : stream(s), oldStatus(s->status())
248 {
249 if (!stream->isDeviceTransactionStarted())
250 stream->resetStatus();
251 }
252 inline ~StreamStateSaver()
253 {
254 if (oldStatus != QDataStream::Ok) {
255 stream->resetStatus();
256 stream->setStatus(oldStatus);
257 }
258 }
259
260private:
261 QDataStream *stream;
262 QDataStream::Status oldStatus;
263};
264
265template <typename Container>
266QDataStream &readArrayBasedContainer(QDataStream &s, Container &c)
267{
268 StreamStateSaver stateSaver(&s);
269
270 c.clear();
271 qint64 size = QDataStream::readQSizeType(s);
272 qsizetype n = size;
273 if (size != n || size < 0) {
274 s.setStatus(QDataStream::SizeLimitExceeded);
275 return s;
276 }
277 c.reserve(n);
278 for (qsizetype i = 0; i < n; ++i) {
279 typename Container::value_type t;
280 s >> t;
281 if (s.status() != QDataStream::Ok) {
282 c.clear();
283 break;
284 }
285 c.append(t);
286 }
287
288 return s;
289}
290
291template <typename Container>
292QDataStream &readListBasedContainer(QDataStream &s, Container &c)
293{
294 StreamStateSaver stateSaver(&s);
295
296 c.clear();
297 qint64 size = QDataStream::readQSizeType(s);
298 qsizetype n = size;
299 if (size != n || size < 0) {
300 s.setStatus(QDataStream::SizeLimitExceeded);
301 return s;
302 }
303 for (qsizetype i = 0; i < n; ++i) {
304 typename Container::value_type t;
305 s >> t;
306 if (s.status() != QDataStream::Ok) {
307 c.clear();
308 break;
309 }
310 c << t;
311 }
312
313 return s;
314}
315
316template <typename Container>
317QDataStream &readAssociativeContainer(QDataStream &s, Container &c)
318{
319 StreamStateSaver stateSaver(&s);
320
321 c.clear();
322 qint64 size = QDataStream::readQSizeType(s);
323 qsizetype n = size;
324 if (size != n || size < 0) {
325 s.setStatus(QDataStream::SizeLimitExceeded);
326 return s;
327 }
328 for (qsizetype i = 0; i < n; ++i) {
329 typename Container::key_type k;
330 typename Container::mapped_type t;
331 s >> k >> t;
332 if (s.status() != QDataStream::Ok) {
333 c.clear();
334 break;
335 }
336 c.insert(k, t);
337 }
338
339 return s;
340}
341
342template <typename Container>
343QDataStream &writeSequentialContainer(QDataStream &s, const Container &c)
344{
345 if (!QDataStream::writeQSizeType(s, value: c.size()))
346 return s;
347 for (const typename Container::value_type &t : c)
348 s << t;
349
350 return s;
351}
352
353template <typename Container>
354QDataStream &writeAssociativeContainer(QDataStream &s, const Container &c)
355{
356 if (!QDataStream::writeQSizeType(s, value: c.size()))
357 return s;
358 auto it = c.constBegin();
359 auto end = c.constEnd();
360 while (it != end) {
361 s << it.key() << it.value();
362 ++it;
363 }
364
365 return s;
366}
367
368template <typename Container>
369QDataStream &writeAssociativeMultiContainer(QDataStream &s, const Container &c)
370{
371 if (!QDataStream::writeQSizeType(s, value: c.size()))
372 return s;
373 auto it = c.constBegin();
374 auto end = c.constEnd();
375 while (it != end) {
376 const auto rangeStart = it++;
377 while (it != end && rangeStart.key() == it.key())
378 ++it;
379 const qint64 last = std::distance(rangeStart, it) - 1;
380 for (qint64 i = last; i >= 0; --i) {
381 auto next = std::next(rangeStart, i);
382 s << next.key() << next.value();
383 }
384 }
385
386 return s;
387}
388
389} // QtPrivate namespace
390
391template<typename ...T>
392using QDataStreamIfHasOStreamOperators =
393 std::enable_if_t<std::conjunction_v<QTypeTraits::has_ostream_operator<QDataStream, T>...>, QDataStream &>;
394template<typename Container, typename ...T>
395using QDataStreamIfHasOStreamOperatorsContainer =
396 std::enable_if_t<std::conjunction_v<QTypeTraits::has_ostream_operator_container<QDataStream, Container, T>...>, QDataStream &>;
397
398template<typename ...T>
399using QDataStreamIfHasIStreamOperators =
400 std::enable_if_t<std::conjunction_v<QTypeTraits::has_istream_operator<QDataStream, T>...>, QDataStream &>;
401template<typename Container, typename ...T>
402using QDataStreamIfHasIStreamOperatorsContainer =
403 std::enable_if_t<std::conjunction_v<QTypeTraits::has_istream_operator_container<QDataStream, Container, T>...>, QDataStream &>;
404
405/*****************************************************************************
406 QDataStream inline functions
407 *****************************************************************************/
408
409inline QIODevice *QDataStream::device() const
410{ return dev; }
411
412inline QDataStream::ByteOrder QDataStream::byteOrder() const
413{ return byteorder; }
414
415inline int QDataStream::version() const
416{ return ver; }
417
418inline void QDataStream::setVersion(int v)
419{ ver = v; }
420
421qint64 QDataStream::readQSizeType(QDataStream &s)
422{
423 quint32 first;
424 s >> first;
425 if (first == NullCode)
426 return -1;
427 if (first < ExtendedSize || s.version() < QDataStream::Qt_6_7)
428 return qint64(first);
429 qint64 extendedLen;
430 s >> extendedLen;
431 return extendedLen;
432}
433
434bool QDataStream::writeQSizeType(QDataStream &s, qint64 value)
435{
436 if (value < qint64(ExtendedSize)) {
437 s << quint32(value);
438 } else if (s.version() >= QDataStream::Qt_6_7) {
439 s << ExtendedSize << value;
440 } else if (value == qint64(ExtendedSize)) {
441 s << ExtendedSize;
442 } else {
443 s.setStatus(QDataStream::SizeLimitExceeded); // value is too big for old format
444 return false;
445 }
446 return true;
447}
448
449inline QDataStream &QDataStream::operator>>(char &i)
450{ return *this >> reinterpret_cast<qint8&>(i); }
451
452inline QDataStream &QDataStream::operator>>(quint8 &i)
453{ return *this >> reinterpret_cast<qint8&>(i); }
454
455inline QDataStream &QDataStream::operator>>(quint16 &i)
456{ return *this >> reinterpret_cast<qint16&>(i); }
457
458inline QDataStream &QDataStream::operator>>(quint32 &i)
459{ return *this >> reinterpret_cast<qint32&>(i); }
460
461inline QDataStream &QDataStream::operator>>(quint64 &i)
462{ return *this >> reinterpret_cast<qint64&>(i); }
463
464inline QDataStream &QDataStream::operator<<(char i)
465{ return *this << qint8(i); }
466
467inline QDataStream &QDataStream::operator<<(quint8 i)
468{ return *this << qint8(i); }
469
470inline QDataStream &QDataStream::operator<<(quint16 i)
471{ return *this << qint16(i); }
472
473inline QDataStream &QDataStream::operator<<(quint32 i)
474{ return *this << qint32(i); }
475
476inline QDataStream &QDataStream::operator<<(quint64 i)
477{ return *this << qint64(i); }
478
479template <typename Enum>
480inline QDataStream &operator<<(QDataStream &s, QFlags<Enum> e)
481{ return s << typename QFlags<Enum>::Int(e); }
482
483template <typename Enum>
484inline QDataStream &operator>>(QDataStream &s, QFlags<Enum> &e)
485{
486 typename QFlags<Enum>::Int i;
487 s >> i;
488 e = QFlag(i);
489 return s;
490}
491
492template <typename T>
493typename std::enable_if_t<std::is_enum<T>::value, QDataStream &>
494operator<<(QDataStream &s, const T &t)
495{ return s << static_cast<typename std::underlying_type<T>::type>(t); }
496
497template <typename T>
498typename std::enable_if_t<std::is_enum<T>::value, QDataStream &>
499operator>>(QDataStream &s, T &t)
500{ return s >> reinterpret_cast<typename std::underlying_type<T>::type &>(t); }
501
502#ifndef Q_QDOC
503
504template<typename T>
505inline QDataStreamIfHasIStreamOperatorsContainer<QList<T>, T> operator>>(QDataStream &s, QList<T> &v)
506{
507 return QtPrivate::readArrayBasedContainer(s, v);
508}
509
510template<typename T>
511inline QDataStreamIfHasOStreamOperatorsContainer<QList<T>, T> operator<<(QDataStream &s, const QList<T> &v)
512{
513 return QtPrivate::writeSequentialContainer(s, v);
514}
515
516template <typename T>
517inline QDataStreamIfHasIStreamOperatorsContainer<QSet<T>, T> operator>>(QDataStream &s, QSet<T> &set)
518{
519 return QtPrivate::readListBasedContainer(s, set);
520}
521
522template <typename T>
523inline QDataStreamIfHasOStreamOperatorsContainer<QSet<T>, T> operator<<(QDataStream &s, const QSet<T> &set)
524{
525 return QtPrivate::writeSequentialContainer(s, set);
526}
527
528template <class Key, class T>
529inline QDataStreamIfHasIStreamOperatorsContainer<QHash<Key, T>, Key, T> operator>>(QDataStream &s, QHash<Key, T> &hash)
530{
531 return QtPrivate::readAssociativeContainer(s, hash);
532}
533
534template <class Key, class T>
535
536inline QDataStreamIfHasOStreamOperatorsContainer<QHash<Key, T>, Key, T> operator<<(QDataStream &s, const QHash<Key, T> &hash)
537{
538 return QtPrivate::writeAssociativeContainer(s, hash);
539}
540
541template <class Key, class T>
542inline QDataStreamIfHasIStreamOperatorsContainer<QMultiHash<Key, T>, Key, T> operator>>(QDataStream &s, QMultiHash<Key, T> &hash)
543{
544 return QtPrivate::readAssociativeContainer(s, hash);
545}
546
547template <class Key, class T>
548inline QDataStreamIfHasOStreamOperatorsContainer<QMultiHash<Key, T>, Key, T> operator<<(QDataStream &s, const QMultiHash<Key, T> &hash)
549{
550 return QtPrivate::writeAssociativeMultiContainer(s, hash);
551}
552
553template <class Key, class T>
554inline QDataStreamIfHasIStreamOperatorsContainer<QMap<Key, T>, Key, T> operator>>(QDataStream &s, QMap<Key, T> &map)
555{
556 return QtPrivate::readAssociativeContainer(s, map);
557}
558
559template <class Key, class T>
560inline QDataStreamIfHasOStreamOperatorsContainer<QMap<Key, T>, Key, T> operator<<(QDataStream &s, const QMap<Key, T> &map)
561{
562 return QtPrivate::writeAssociativeContainer(s, map);
563}
564
565template <class Key, class T>
566inline QDataStreamIfHasIStreamOperatorsContainer<QMultiMap<Key, T>, Key, T> operator>>(QDataStream &s, QMultiMap<Key, T> &map)
567{
568 return QtPrivate::readAssociativeContainer(s, map);
569}
570
571template <class Key, class T>
572inline QDataStreamIfHasOStreamOperatorsContainer<QMultiMap<Key, T>, Key, T> operator<<(QDataStream &s, const QMultiMap<Key, T> &map)
573{
574 return QtPrivate::writeAssociativeMultiContainer(s, map);
575}
576
577template <class T1, class T2>
578inline QDataStreamIfHasIStreamOperators<T1, T2> operator>>(QDataStream& s, std::pair<T1, T2> &p)
579{
580 s >> p.first >> p.second;
581 return s;
582}
583
584template <class T1, class T2>
585inline QDataStreamIfHasOStreamOperators<T1, T2> operator<<(QDataStream& s, const std::pair<T1, T2> &p)
586{
587 s << p.first << p.second;
588 return s;
589}
590
591#else
592
593template <class T>
594QDataStream &operator>>(QDataStream &s, QList<T> &l);
595
596template <class T>
597QDataStream &operator<<(QDataStream &s, const QList<T> &l);
598
599template <class T>
600QDataStream &operator>>(QDataStream &s, QSet<T> &set);
601
602template <class T>
603QDataStream &operator<<(QDataStream &s, const QSet<T> &set);
604
605template <class Key, class T>
606QDataStream &operator>>(QDataStream &s, QHash<Key, T> &hash);
607
608template <class Key, class T>
609QDataStream &operator<<(QDataStream &s, const QHash<Key, T> &hash);
610
611template <class Key, class T>
612QDataStream &operator>>(QDataStream &s, QMultiHash<Key, T> &hash);
613
614template <class Key, class T>
615QDataStream &operator<<(QDataStream &s, const QMultiHash<Key, T> &hash);
616
617template <class Key, class T>
618QDataStream &operator>>(QDataStream &s, QMap<Key, T> &map);
619
620template <class Key, class T>
621QDataStream &operator<<(QDataStream &s, const QMap<Key, T> &map);
622
623template <class Key, class T>
624QDataStream &operator>>(QDataStream &s, QMultiMap<Key, T> &map);
625
626template <class Key, class T>
627QDataStream &operator<<(QDataStream &s, const QMultiMap<Key, T> &map);
628
629template <class T1, class T2>
630QDataStream &operator>>(QDataStream& s, std::pair<T1, T2> &p);
631
632template <class T1, class T2>
633QDataStream &operator<<(QDataStream& s, const std::pair<T1, T2> &p);
634
635#endif // Q_QDOC
636
637inline QDataStream &operator>>(QDataStream &s, QKeyCombination &combination)
638{
639 int combined;
640 s >> combined;
641 combination = QKeyCombination::fromCombined(combined);
642 return s;
643}
644
645inline QDataStream &operator<<(QDataStream &s, QKeyCombination combination)
646{
647 return s << combination.toCombined();
648}
649
650#endif // QT_NO_DATASTREAM
651
652QT_END_NAMESPACE
653
654#endif // QDATASTREAM_H
655