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