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 | |
51 | QT_BEGIN_NAMESPACE |
52 | |
53 | class qfloat16; |
54 | class QByteArray; |
55 | class QIODevice; |
56 | |
57 | template <typename T> class QList; |
58 | template <typename T> class QVector; |
59 | template <typename T> class QSet; |
60 | template <class Key, class T> class QHash; |
61 | template <class Key, class T> class QMap; |
62 | |
63 | #if !defined(QT_NO_DATASTREAM) || defined(QT_BOOTSTRAPPED) |
64 | class QDataStreamPrivate; |
65 | namespace QtPrivate { |
66 | class StreamStateSaver; |
67 | } |
68 | class Q_CORE_EXPORT QDataStream |
69 | { |
70 | public: |
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 | |
206 | private: |
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 | |
222 | namespace QtPrivate { |
223 | |
224 | class StreamStateSaver |
225 | { |
226 | public: |
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 | |
240 | private: |
241 | QDataStream *stream; |
242 | QDataStream::Status oldStatus; |
243 | }; |
244 | |
245 | template <typename Container> |
246 | QDataStream &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 | |
267 | template <typename Container> |
268 | QDataStream &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 | |
288 | template <typename T> |
289 | struct MultiContainer { using type = T; }; |
290 | template <typename K, typename V> |
291 | struct MultiContainer<QMap<K, V>> { using type = QMultiMap<K, V>; }; |
292 | template <typename K, typename V> |
293 | struct MultiContainer<QHash<K, V>> { using type = QMultiHash<K, V>; }; |
294 | |
295 | template <typename Container> |
296 | QDataStream &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 | |
317 | template <typename Container> |
318 | QDataStream &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 | |
327 | template <typename Container> |
328 | QDataStream &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 | |
368 | inline QIODevice *QDataStream::device() const |
369 | { return dev; } |
370 | |
371 | inline QDataStream::ByteOrder QDataStream::byteOrder() const |
372 | { return byteorder; } |
373 | |
374 | inline int QDataStream::version() const |
375 | { return ver; } |
376 | |
377 | inline void QDataStream::setVersion(int v) |
378 | { ver = v; } |
379 | |
380 | inline QDataStream &QDataStream::operator>>(quint8 &i) |
381 | { return *this >> reinterpret_cast<qint8&>(i); } |
382 | |
383 | inline QDataStream &QDataStream::operator>>(quint16 &i) |
384 | { return *this >> reinterpret_cast<qint16&>(i); } |
385 | |
386 | inline QDataStream &QDataStream::operator>>(quint32 &i) |
387 | { return *this >> reinterpret_cast<qint32&>(i); } |
388 | |
389 | inline QDataStream &QDataStream::operator>>(quint64 &i) |
390 | { return *this >> reinterpret_cast<qint64&>(i); } |
391 | |
392 | inline QDataStream &QDataStream::operator<<(quint8 i) |
393 | { return *this << qint8(i); } |
394 | |
395 | inline QDataStream &QDataStream::operator<<(quint16 i) |
396 | { return *this << qint16(i); } |
397 | |
398 | inline QDataStream &QDataStream::operator<<(quint32 i) |
399 | { return *this << qint32(i); } |
400 | |
401 | inline QDataStream &QDataStream::operator<<(quint64 i) |
402 | { return *this << qint64(i); } |
403 | |
404 | template <typename Enum> |
405 | inline QDataStream &operator<<(QDataStream &s, QFlags<Enum> e) |
406 | { return s << e.i; } |
407 | |
408 | template <typename Enum> |
409 | inline QDataStream &operator>>(QDataStream &s, QFlags<Enum> &e) |
410 | { return s >> e.i; } |
411 | |
412 | template <typename T> |
413 | typename std::enable_if<std::is_enum<T>::value, QDataStream &>::type& |
414 | operator<<(QDataStream &s, const T &t) |
415 | { return s << static_cast<typename std::underlying_type<T>::type>(t); } |
416 | |
417 | template <typename T> |
418 | typename std::enable_if<std::is_enum<T>::value, QDataStream &>::type& |
419 | operator>>(QDataStream &s, T &t) |
420 | { return s >> reinterpret_cast<typename std::underlying_type<T>::type &>(t); } |
421 | |
422 | template <typename T> |
423 | inline QDataStream &operator>>(QDataStream &s, QList<T> &l) |
424 | { |
425 | return QtPrivate::readArrayBasedContainer(s, l); |
426 | } |
427 | |
428 | template <typename T> |
429 | inline QDataStream &operator<<(QDataStream &s, const QList<T> &l) |
430 | { |
431 | return QtPrivate::writeSequentialContainer(s, l); |
432 | } |
433 | |
434 | template<typename T> |
435 | inline QDataStream &operator>>(QDataStream &s, QVector<T> &v) |
436 | { |
437 | return QtPrivate::readArrayBasedContainer(s, v); |
438 | } |
439 | |
440 | template<typename T> |
441 | inline QDataStream &operator<<(QDataStream &s, const QVector<T> &v) |
442 | { |
443 | return QtPrivate::writeSequentialContainer(s, v); |
444 | } |
445 | |
446 | template <typename T> |
447 | inline QDataStream &operator>>(QDataStream &s, QSet<T> &set) |
448 | { |
449 | return QtPrivate::readListBasedContainer(s, set); |
450 | } |
451 | |
452 | template <typename T> |
453 | inline QDataStream &operator<<(QDataStream &s, const QSet<T> &set) |
454 | { |
455 | return QtPrivate::writeSequentialContainer(s, set); |
456 | } |
457 | |
458 | template <class Key, class T> |
459 | inline QDataStream &operator>>(QDataStream &s, QHash<Key, T> &hash) |
460 | { |
461 | return QtPrivate::readAssociativeContainer(s, hash); |
462 | } |
463 | |
464 | template <class Key, class T> |
465 | inline QDataStream &operator<<(QDataStream &s, const QHash<Key, T> &hash) |
466 | { |
467 | return QtPrivate::writeAssociativeContainer(s, hash); |
468 | } |
469 | |
470 | template <class Key, class T> |
471 | inline QDataStream &operator>>(QDataStream &s, QMap<Key, T> &map) |
472 | { |
473 | return QtPrivate::readAssociativeContainer(s, map); |
474 | } |
475 | |
476 | template <class Key, class T> |
477 | inline QDataStream &operator<<(QDataStream &s, const QMap<Key, T> &map) |
478 | { |
479 | return QtPrivate::writeAssociativeContainer(s, map); |
480 | } |
481 | |
482 | #ifndef QT_NO_DATASTREAM |
483 | template <class T1, class T2> |
484 | inline QDataStream& operator>>(QDataStream& s, QPair<T1, T2>& p) |
485 | { |
486 | s >> p.first >> p.second; |
487 | return s; |
488 | } |
489 | |
490 | template <class T1, class T2> |
491 | inline 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 | |
500 | QT_END_NAMESPACE |
501 | |
502 | #endif // QDATASTREAM_H |
503 | |