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

source code of qtbase/src/corelib/serialization/qdatastream.h