1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtCore module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#ifndef QDATASTREAM_H
41#define QDATASTREAM_H
42
43#include <QtCore/qscopedpointer.h>
44#include <QtCore/qiodevice.h>
45#include <QtCore/qpair.h>
46
47#ifdef Status
48#error qdatastream.h must be included before any header file that defines Status
49#endif
50
51QT_BEGIN_NAMESPACE
52
53class qfloat16;
54class QByteArray;
55class QIODevice;
56
57template <typename T> class QList;
58template <typename T> class QVector;
59template <typename T> class QSet;
60template <class Key, class T> class QHash;
61template <class Key, class T> class QMap;
62
63#if !defined(QT_NO_DATASTREAM) || defined(QT_BOOTSTRAPPED)
64class QDataStreamPrivate;
65namespace QtPrivate {
66class StreamStateSaver;
67}
68class Q_CORE_EXPORT QDataStream
69{
70public:
71 enum Version {
72 Qt_1_0 = 1,
73 Qt_2_0 = 2,
74 Qt_2_1 = 3,
75 Qt_3_0 = 4,
76 Qt_3_1 = 5,
77 Qt_3_3 = 6,
78 Qt_4_0 = 7,
79 Qt_4_1 = Qt_4_0,
80 Qt_4_2 = 8,
81 Qt_4_3 = 9,
82 Qt_4_4 = 10,
83 Qt_4_5 = 11,
84 Qt_4_6 = 12,
85 Qt_4_7 = Qt_4_6,
86 Qt_4_8 = Qt_4_7,
87 Qt_4_9 = Qt_4_8,
88 Qt_5_0 = 13,
89 Qt_5_1 = 14,
90 Qt_5_2 = 15,
91 Qt_5_3 = Qt_5_2,
92 Qt_5_4 = 16,
93 Qt_5_5 = Qt_5_4,
94 Qt_5_6 = 17,
95 Qt_5_7 = Qt_5_6,
96 Qt_5_8 = Qt_5_7,
97 Qt_5_9 = Qt_5_8,
98 Qt_5_10 = Qt_5_9,
99 Qt_5_11 = Qt_5_10,
100 Qt_5_12 = 18,
101 Qt_5_13 = 19,
102 Qt_5_14 = Qt_5_13,
103#if QT_VERSION >= 0x050f00
104 Qt_5_15 = Qt_5_14,
105 Qt_DefaultCompiledVersion = Qt_5_15
106#elif QT_VERSION >= 0x060000
107 Qt_6_0 = Qt_5_15,
108 Qt_DefaultCompiledVersion = Qt_6_0
109#else
110 Qt_DefaultCompiledVersion = Qt_5_14
111#endif
112#if QT_VERSION >= 0x060100
113#error Add the datastream version for this Qt version and update Qt_DefaultCompiledVersion
114#endif
115 };
116
117 enum ByteOrder {
118 BigEndian = QSysInfo::BigEndian,
119 LittleEndian = QSysInfo::LittleEndian
120 };
121
122 enum Status {
123 Ok,
124 ReadPastEnd,
125 ReadCorruptData,
126 WriteFailed
127 };
128
129 enum FloatingPointPrecision {
130 SinglePrecision,
131 DoublePrecision
132 };
133
134 QDataStream();
135 explicit QDataStream(QIODevice *);
136 QDataStream(QByteArray *, QIODevice::OpenMode flags);
137 QDataStream(const QByteArray &);
138 ~QDataStream();
139
140 QIODevice *device() const;
141 void setDevice(QIODevice *);
142#if QT_DEPRECATED_SINCE(5, 13)
143 QT_DEPRECATED_X("Use QDataStream::setDevice(nullptr) instead")
144 void unsetDevice();
145#endif
146
147 bool atEnd() const;
148
149 Status status() const;
150 void setStatus(Status status);
151 void resetStatus();
152
153 FloatingPointPrecision floatingPointPrecision() const;
154 void setFloatingPointPrecision(FloatingPointPrecision precision);
155
156 ByteOrder byteOrder() const;
157 void setByteOrder(ByteOrder);
158
159 int version() const;
160 void setVersion(int);
161
162 QDataStream &operator>>(qint8 &i);
163 QDataStream &operator>>(quint8 &i);
164 QDataStream &operator>>(qint16 &i);
165 QDataStream &operator>>(quint16 &i);
166 QDataStream &operator>>(qint32 &i);
167 inline QDataStream &operator>>(quint32 &i);
168 QDataStream &operator>>(qint64 &i);
169 QDataStream &operator>>(quint64 &i);
170 QDataStream &operator>>(std::nullptr_t &ptr) { ptr = nullptr; return *this; }
171
172 QDataStream &operator>>(bool &i);
173 QDataStream &operator>>(qfloat16 &f);
174 QDataStream &operator>>(float &f);
175 QDataStream &operator>>(double &f);
176 QDataStream &operator>>(char *&str);
177
178 QDataStream &operator<<(qint8 i);
179 QDataStream &operator<<(quint8 i);
180 QDataStream &operator<<(qint16 i);
181 QDataStream &operator<<(quint16 i);
182 QDataStream &operator<<(qint32 i);
183 inline QDataStream &operator<<(quint32 i);
184 QDataStream &operator<<(qint64 i);
185 QDataStream &operator<<(quint64 i);
186 QDataStream &operator<<(std::nullptr_t) { return *this; }
187 QDataStream &operator<<(bool i);
188 QDataStream &operator<<(qfloat16 f);
189 QDataStream &operator<<(float f);
190 QDataStream &operator<<(double f);
191 QDataStream &operator<<(const char *str);
192
193 QDataStream &readBytes(char *&, uint &len);
194 int readRawData(char *, int len);
195
196 QDataStream &writeBytes(const char *, uint len);
197 int writeRawData(const char *, int len);
198
199 int skipRawData(int len);
200
201 void startTransaction();
202 bool commitTransaction();
203 void rollbackTransaction();
204 void abortTransaction();
205
206private:
207 Q_DISABLE_COPY(QDataStream)
208
209 QScopedPointer<QDataStreamPrivate> d;
210
211 QIODevice *dev;
212 bool owndev;
213 bool noswap;
214 ByteOrder byteorder;
215 int ver;
216 Status q_status;
217
218 int readBlock(char *data, int len);
219 friend class QtPrivate::StreamStateSaver;
220};
221
222namespace QtPrivate {
223
224class StreamStateSaver
225{
226public:
227 inline StreamStateSaver(QDataStream *s) : stream(s), oldStatus(s->status())
228 {
229 if (!stream->dev || !stream->dev->isTransactionStarted())
230 stream->resetStatus();
231 }
232 inline ~StreamStateSaver()
233 {
234 if (oldStatus != QDataStream::Ok) {
235 stream->resetStatus();
236 stream->setStatus(oldStatus);
237 }
238 }
239
240private:
241 QDataStream *stream;
242 QDataStream::Status oldStatus;
243};
244
245template <typename Container>
246QDataStream &readArrayBasedContainer(QDataStream &s, Container &c)
247{
248 StreamStateSaver stateSaver(&s);
249
250 c.clear();
251 quint32 n;
252 s >> n;
253 c.reserve(n);
254 for (quint32 i = 0; i < n; ++i) {
255 typename Container::value_type t;
256 s >> t;
257 if (s.status() != QDataStream::Ok) {
258 c.clear();
259 break;
260 }
261 c.append(t);
262 }
263
264 return s;
265}
266
267template <typename Container>
268QDataStream &readListBasedContainer(QDataStream &s, Container &c)
269{
270 StreamStateSaver stateSaver(&s);
271
272 c.clear();
273 quint32 n;
274 s >> n;
275 for (quint32 i = 0; i < n; ++i) {
276 typename Container::value_type t;
277 s >> t;
278 if (s.status() != QDataStream::Ok) {
279 c.clear();
280 break;
281 }
282 c << t;
283 }
284
285 return s;
286}
287
288template <typename T>
289struct MultiContainer { using type = T; };
290template <typename K, typename V>
291struct MultiContainer<QMap<K, V>> { using type = QMultiMap<K, V>; };
292template <typename K, typename V>
293struct MultiContainer<QHash<K, V>> { using type = QMultiHash<K, V>; };
294
295template <typename Container>
296QDataStream &readAssociativeContainer(QDataStream &s, Container &c)
297{
298 StreamStateSaver stateSaver(&s);
299
300 c.clear();
301 quint32 n;
302 s >> n;
303 for (quint32 i = 0; i < n; ++i) {
304 typename Container::key_type k;
305 typename Container::mapped_type t;
306 s >> k >> t;
307 if (s.status() != QDataStream::Ok) {
308 c.clear();
309 break;
310 }
311 static_cast<typename MultiContainer<Container>::type &>(c).insert(k, t);
312 }
313
314 return s;
315}
316
317template <typename Container>
318QDataStream &writeSequentialContainer(QDataStream &s, const Container &c)
319{
320 s << quint32(c.size());
321 for (const typename Container::value_type &t : c)
322 s << t;
323
324 return s;
325}
326
327template <typename Container>
328QDataStream &writeAssociativeContainer(QDataStream &s, const Container &c)
329{
330 s << quint32(c.size());
331#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) && QT_DEPRECATED_SINCE(5, 15)
332 // Deserialization should occur in the reverse order.
333 // Otherwise, value() will return the least recently inserted
334 // value instead of the most recently inserted one.
335 auto it = c.constEnd();
336 auto begin = c.constBegin();
337 while (it != begin) {
338 QT_WARNING_PUSH
339 QT_WARNING_DISABLE_DEPRECATED
340 --it;
341 QT_WARNING_POP
342 s << it.key() << it.value();
343 }
344#else
345 auto it = c.constBegin();
346 auto end = c.constEnd();
347 while (it != end) {
348 const auto rangeStart = it++;
349 while (it != end && rangeStart.key() == it.key())
350 ++it;
351 const qint64 last = std::distance(rangeStart, it) - 1;
352 for (qint64 i = last; i >= 0; --i) {
353 auto next = std::next(rangeStart, i);
354 s << next.key() << next.value();
355 }
356 }
357#endif
358
359 return s;
360}
361
362} // QtPrivate namespace
363
364/*****************************************************************************
365 QDataStream inline functions
366 *****************************************************************************/
367
368inline QIODevice *QDataStream::device() const
369{ return dev; }
370
371inline QDataStream::ByteOrder QDataStream::byteOrder() const
372{ return byteorder; }
373
374inline int QDataStream::version() const
375{ return ver; }
376
377inline void QDataStream::setVersion(int v)
378{ ver = v; }
379
380inline QDataStream &QDataStream::operator>>(quint8 &i)
381{ return *this >> reinterpret_cast<qint8&>(i); }
382
383inline QDataStream &QDataStream::operator>>(quint16 &i)
384{ return *this >> reinterpret_cast<qint16&>(i); }
385
386inline QDataStream &QDataStream::operator>>(quint32 &i)
387{ return *this >> reinterpret_cast<qint32&>(i); }
388
389inline QDataStream &QDataStream::operator>>(quint64 &i)
390{ return *this >> reinterpret_cast<qint64&>(i); }
391
392inline QDataStream &QDataStream::operator<<(quint8 i)
393{ return *this << qint8(i); }
394
395inline QDataStream &QDataStream::operator<<(quint16 i)
396{ return *this << qint16(i); }
397
398inline QDataStream &QDataStream::operator<<(quint32 i)
399{ return *this << qint32(i); }
400
401inline QDataStream &QDataStream::operator<<(quint64 i)
402{ return *this << qint64(i); }
403
404template <typename Enum>
405inline QDataStream &operator<<(QDataStream &s, QFlags<Enum> e)
406{ return s << e.i; }
407
408template <typename Enum>
409inline QDataStream &operator>>(QDataStream &s, QFlags<Enum> &e)
410{ return s >> e.i; }
411
412template <typename T>
413typename std::enable_if<std::is_enum<T>::value, QDataStream &>::type&
414operator<<(QDataStream &s, const T &t)
415{ return s << static_cast<typename std::underlying_type<T>::type>(t); }
416
417template <typename T>
418typename std::enable_if<std::is_enum<T>::value, QDataStream &>::type&
419operator>>(QDataStream &s, T &t)
420{ return s >> reinterpret_cast<typename std::underlying_type<T>::type &>(t); }
421
422template <typename T>
423inline QDataStream &operator>>(QDataStream &s, QList<T> &l)
424{
425 return QtPrivate::readArrayBasedContainer(s, l);
426}
427
428template <typename T>
429inline QDataStream &operator<<(QDataStream &s, const QList<T> &l)
430{
431 return QtPrivate::writeSequentialContainer(s, l);
432}
433
434template<typename T>
435inline QDataStream &operator>>(QDataStream &s, QVector<T> &v)
436{
437 return QtPrivate::readArrayBasedContainer(s, v);
438}
439
440template<typename T>
441inline QDataStream &operator<<(QDataStream &s, const QVector<T> &v)
442{
443 return QtPrivate::writeSequentialContainer(s, v);
444}
445
446template <typename T>
447inline QDataStream &operator>>(QDataStream &s, QSet<T> &set)
448{
449 return QtPrivate::readListBasedContainer(s, set);
450}
451
452template <typename T>
453inline QDataStream &operator<<(QDataStream &s, const QSet<T> &set)
454{
455 return QtPrivate::writeSequentialContainer(s, set);
456}
457
458template <class Key, class T>
459inline QDataStream &operator>>(QDataStream &s, QHash<Key, T> &hash)
460{
461 return QtPrivate::readAssociativeContainer(s, hash);
462}
463
464template <class Key, class T>
465inline QDataStream &operator<<(QDataStream &s, const QHash<Key, T> &hash)
466{
467 return QtPrivate::writeAssociativeContainer(s, hash);
468}
469
470template <class Key, class T>
471inline QDataStream &operator>>(QDataStream &s, QMap<Key, T> &map)
472{
473 return QtPrivate::readAssociativeContainer(s, map);
474}
475
476template <class Key, class T>
477inline QDataStream &operator<<(QDataStream &s, const QMap<Key, T> &map)
478{
479 return QtPrivate::writeAssociativeContainer(s, map);
480}
481
482#ifndef QT_NO_DATASTREAM
483template <class T1, class T2>
484inline QDataStream& operator>>(QDataStream& s, QPair<T1, T2>& p)
485{
486 s >> p.first >> p.second;
487 return s;
488}
489
490template <class T1, class T2>
491inline QDataStream& operator<<(QDataStream& s, const QPair<T1, T2>& p)
492{
493 s << p.first << p.second;
494 return s;
495}
496#endif
497
498#endif // QT_NO_DATASTREAM
499
500QT_END_NAMESPACE
501
502#endif // QDATASTREAM_H
503