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