Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qiodevice.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 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//#define QIODEVICE_DEBUG
5
6#include "qbytearray.h"
7#include "qdebug.h"
8#include "qiodevice_p.h"
9#include "qfile.h"
10#include "qstringlist.h"
11#include "qdir.h"
12#include "private/qtools_p.h"
13
14#include <algorithm>
15
17
18using namespace Qt::StringLiterals;
19using namespace QtMiscUtils;
20
21[[maybe_unused]]
22static void debugBinaryString(const char *input, qint64 maxlen)
23{
24 QByteArray tmp;
25 qlonglong startOffset = 0;
26 for (qint64 i = 0; i < maxlen; ++i) {
27 tmp += input[i];
28
29 if ((i % 16) == 15 || i == (maxlen - 1)) {
30 printf("\n%15lld:", startOffset);
31 startOffset += tmp.size();
32
33 for (qsizetype j = 0; j < tmp.size(); ++j)
34 printf(" %02x", int(uchar(tmp[j])));
35 for (qsizetype j = tmp.size(); j < 16 + 1; ++j)
36 printf(" ");
37 for (qsizetype j = 0; j < tmp.size(); ++j)
38 printf("%c", isAsciiPrintable(tmp[j]) ? tmp[j] : '.');
39 tmp.clear();
40 }
41 }
42 printf("\n\n");
43}
44
45#define Q_VOID
46
48static void checkWarnMessage(const QIODevice *device, const char *function, const char *what)
49{
50#ifndef QT_NO_WARNING_OUTPUT
51 QDebug d = qWarning();
52 d.noquote();
53 d.nospace();
54 d << "QIODevice::" << function;
55#ifndef QT_NO_QOBJECT
56 d << " (" << device->metaObject()->className();
57 if (!device->objectName().isEmpty())
58 d << ", \"" << device->objectName() << '"';
59 if (const QFile *f = qobject_cast<const QFile *>(device))
60 d << ", \"" << QDir::toNativeSeparators(f->fileName()) << '"';
61 d << ')';
62#else
64#endif // !QT_NO_QOBJECT
65 d << ": " << what;
66#else
68 Q_UNUSED(function);
69 Q_UNUSED(what);
70#endif // QT_NO_WARNING_OUTPUT
71}
72
73#define CHECK_MAXLEN(function, returnType) \
74 do { \
75 if (maxSize < 0) { \
76 checkWarnMessage(this, #function, "Called with maxSize < 0"); \
77 return returnType; \
78 } \
79 } while (0)
80
81#define CHECK_LINEMAXLEN(function, returnType) \
82 do { \
83 if (maxSize < 2) { \
84 checkWarnMessage(this, #function, "Called with maxSize < 2"); \
85 return returnType; \
86 } \
87 } while (0)
88
89#define CHECK_MAXBYTEARRAYSIZE(function) \
90 do { \
91 if (maxSize >= QByteArray::max_size()) { \
92 checkWarnMessage(this, #function, "maxSize argument exceeds QByteArray size limit"); \
93 maxSize = QByteArray::max_size() - 1; \
94 } \
95 } while (0)
96
97#define CHECK_WRITABLE(function, returnType) \
98 do { \
99 if ((d->openMode & WriteOnly) == 0) { \
100 if (d->openMode == NotOpen) { \
101 checkWarnMessage(this, #function, "device not open"); \
102 return returnType; \
103 } \
104 checkWarnMessage(this, #function, "ReadOnly device"); \
105 return returnType; \
106 } \
107 } while (0)
108
109#define CHECK_READABLE(function, returnType) \
110 do { \
111 if ((d->openMode & ReadOnly) == 0) { \
112 if (d->openMode == NotOpen) { \
113 checkWarnMessage(this, #function, "device not open"); \
114 return returnType; \
115 } \
116 checkWarnMessage(this, #function, "WriteOnly device"); \
117 return returnType; \
118 } \
119 } while (0)
120
127
134
401#ifdef QT_NO_QOBJECT
403 : d_ptr(new QIODevicePrivate)
404{
405 d_ptr->q_ptr = this;
406}
407
412 : d_ptr(&dd)
413{
414 d_ptr->q_ptr = this;
415}
416#else
417
424{
425#if defined QIODEVICE_DEBUG
426 QFile *file = qobject_cast<QFile *>(this);
427 printf("%p QIODevice::QIODevice(\"%s\") %s\n", this, metaObject()->className(),
429#endif
430}
431
437 : QObject(*new QIODevicePrivate, parent)
438{
439#if defined QIODEVICE_DEBUG
440 printf("%p QIODevice::QIODevice(%p \"%s\")\n", this, parent, metaObject()->className());
441#endif
442}
443
448 : QObject(dd, parent)
449{
450}
451#endif
452
453
461{
462#if defined QIODEVICE_DEBUG
463 printf("%p QIODevice::~QIODevice()\n", this);
464#endif
465}
466
486{
487 return false;
488}
489
496QIODeviceBase::OpenMode QIODevice::openMode() const
497{
498 return d_func()->openMode;
499}
500
508void QIODevice::setOpenMode(QIODeviceBase::OpenMode openMode)
509{
510 Q_D(QIODevice);
511#if defined QIODEVICE_DEBUG
512 printf("%p QIODevice::setOpenMode(0x%x)\n", this, openMode.toInt());
513#endif
514 d->openMode = openMode;
515 d->accessMode = QIODevicePrivate::Unset;
516 d->setReadChannelCount(isReadable() ? qMax(d->readChannelCount, 1) : 0);
517 d->setWriteChannelCount(isWritable() ? qMax(d->writeChannelCount, 1) : 0);
518}
519
530{
531 Q_D(QIODevice);
532 if (!isOpen()) {
533 checkWarnMessage(this, "setTextModeEnabled", "The device is not open");
534 return;
535 }
536 if (enabled)
537 d->openMode |= Text;
538 else
539 d->openMode &= ~Text;
540}
541
548{
549 return d_func()->openMode.testAnyFlag(Text);
550}
551
561{
562 return d_func()->openMode != NotOpen;
563}
564
575{
576 return (openMode() & ReadOnly) != 0;
577}
578
589{
590 return (openMode() & WriteOnly) != 0;
591}
592
602{
603 return d_func()->readChannelCount;
604}
605
615{
616 return d_func()->writeChannelCount;
617}
618
627{
628 return d_func()->currentReadChannel;
629}
630
642{
643 Q_D(QIODevice);
644
645 if (d->transactionStarted) {
646 checkWarnMessage(this, "setReadChannel", "Failed due to read transaction being in progress");
647 return;
648 }
649
650#if defined QIODEVICE_DEBUG
651 qDebug("%p QIODevice::setCurrentReadChannel(%d), d->currentReadChannel = %d, d->readChannelCount = %d\n",
652 this, channel, d->currentReadChannel, d->readChannelCount);
653#endif
654
655 d->setCurrentReadChannel(channel);
656}
657
662{
663 if (count > readBuffers.size()) {
665
666 // If readBufferChunkSize is zero, we should bypass QIODevice's
667 // read buffers, even if the QIODeviceBase::Unbuffered flag is not
668 // set when opened. However, if a read transaction is started or
669 // ungetChar() is called, we still have to use the internal buffer.
670 // To support these cases, pass a default value to the QRingBuffer
671 // constructor.
672
673 while (readBuffers.size() < count)
676 } else {
678 }
681}
682
691{
692 return d_func()->currentWriteChannel;
693}
694
706{
707 Q_D(QIODevice);
708
709#if defined QIODEVICE_DEBUG
710 qDebug("%p QIODevice::setCurrentWriteChannel(%d), d->currentWriteChannel = %d, d->writeChannelCount = %d\n",
711 this, channel, d->currentWriteChannel, d->writeChannelCount);
712#endif
713
714 d->setCurrentWriteChannel(channel);
715}
716
721{
722 if (count > writeBuffers.size()) {
723 // If writeBufferChunkSize is zero (default value), we don't use
724 // QIODevice's write buffers.
725 if (writeBufferChunkSize != 0) {
727 while (writeBuffers.size() < count)
729 }
730 } else {
732 }
735}
736
741{
742 for (const QRingBuffer &ringBuffer : writeBuffers) {
743 if (!ringBuffer.isEmpty())
744 return false;
745 }
746 return true;
747}
748
756bool QIODevice::open(QIODeviceBase::OpenMode mode)
757{
758 Q_D(QIODevice);
759 d->openMode = mode;
760 d->pos = (mode & Append) ? size() : qint64(0);
761 d->accessMode = QIODevicePrivate::Unset;
762 d->readBuffers.clear();
763 d->writeBuffers.clear();
764 d->setReadChannelCount(isReadable() ? 1 : 0);
765 d->setWriteChannelCount(isWritable() ? 1 : 0);
766 d->errorString.clear();
767#if defined QIODEVICE_DEBUG
768 printf("%p QIODevice::open(0x%x)\n", this, mode.toInt());
769#endif
770 return true;
771}
772
780{
781 Q_D(QIODevice);
782 if (d->openMode == NotOpen)
783 return;
784
785#if defined QIODEVICE_DEBUG
786 printf("%p QIODevice::close()\n", this);
787#endif
788
789#ifndef QT_NO_QOBJECT
791#endif
792 d->openMode = NotOpen;
793 d->pos = 0;
794 d->transactionStarted = false;
795 d->transactionPos = 0;
796 d->setReadChannelCount(0);
797 // Do not clear write buffers to allow delayed close in sockets
798 d->writeChannelCount = 0;
799}
800
815{
816 Q_D(const QIODevice);
817#if defined QIODEVICE_DEBUG
818 printf("%p QIODevice::pos() == %lld\n", this, d->pos);
819#endif
820 return d->pos;
821}
822
833{
834 return d_func()->isSequential() ? bytesAvailable() : qint64(0);
835}
836
850{
851 Q_D(QIODevice);
852 if (d->isSequential()) {
853 checkWarnMessage(this, "seek", "Cannot call seek on a sequential device");
854 return false;
855 }
856 if (d->openMode == NotOpen) {
857 checkWarnMessage(this, "seek", "The device is not open");
858 return false;
859 }
860 if (pos < 0) {
861 qWarning("QIODevice::seek: Invalid pos: %lld", pos);
862 return false;
863 }
864
865#if defined QIODEVICE_DEBUG
866 printf("%p QIODevice::seek(%lld), before: d->pos = %lld, d->buffer.size() = %lld\n",
867 this, pos, d->pos, d->buffer.size());
868#endif
869
870 d->devicePos = pos;
871 d->seekBuffer(pos);
872
873#if defined QIODEVICE_DEBUG
874 printf("%p \tafter: d->pos == %lld, d->buffer.size() == %lld\n", this, d->pos,
875 d->buffer.size());
876#endif
877 return true;
878}
879
884{
885 const qint64 offset = newPos - pos;
886 pos = newPos;
887
888 if (offset < 0 || offset >= buffer.size()) {
889 // When seeking backwards, an operation that is only allowed for
890 // random-access devices, the buffer is cleared. The next read
891 // operation will then refill the buffer.
892 buffer.clear();
893 } else {
894 buffer.free(offset);
895 }
896}
897
911{
912 Q_D(const QIODevice);
913 const bool result = (d->openMode == NotOpen || (d->isBufferEmpty()
914 && bytesAvailable() == 0));
915#if defined QIODEVICE_DEBUG
916 printf("%p QIODevice::atEnd() returns %s, d->openMode == %d, d->pos == %lld\n", this,
917 result ? "true" : "false", d->openMode.toInt(), d->pos);
918#endif
919 return result;
920}
921
934{
935#if defined QIODEVICE_DEBUG
936 printf("%p QIODevice::reset()\n", this);
937#endif
938 return seek(0);
939}
940
954{
955 Q_D(const QIODevice);
956 if (!d->isSequential())
957 return qMax(size() - d->pos, qint64(0));
958 return d->buffer.size() - d->transactionPos;
959}
960
971{
972 return d_func()->writeBuffer.size();
973}
974
989{
990 Q_D(QIODevice);
991#if defined QIODEVICE_DEBUG
992 printf("%p QIODevice::read(%p, %lld), d->pos = %lld, d->buffer.size() = %lld\n",
993 this, data, maxSize, d->pos, d->buffer.size());
994#endif
995
997 const bool sequential = d->isSequential();
998
999 // Short-cut for getChar(), unless we need to keep the data in the buffer.
1000 if (maxSize == 1 && !(sequential && d->transactionStarted)) {
1001 int chint;
1002 while ((chint = d->buffer.getChar()) != -1) {
1003 if (!sequential)
1004 ++d->pos;
1005
1006 char c = char(uchar(chint));
1007 if (c == '\r' && (d->openMode & Text))
1008 continue;
1009 *data = c;
1010#if defined QIODEVICE_DEBUG
1011 printf("%p \tread 0x%hhx (%c) returning 1 (shortcut)\n", this,
1012 int(c), isAsciiPrintable(c) ? c : '?');
1013#endif
1014 if (d->buffer.isEmpty())
1015 readData(data, 0);
1016 return qint64(1);
1017 }
1018 }
1019
1020 CHECK_MAXLEN(read, qint64(-1));
1021 const qint64 readBytes = d->read(data, maxSize);
1022
1023#if defined QIODEVICE_DEBUG
1024 printf("%p \treturning %lld, d->pos == %lld, d->buffer.size() == %lld\n", this,
1025 readBytes, d->pos, d->buffer.size());
1026 if (readBytes > 0)
1027 debugBinaryString(data - readBytes, readBytes);
1028#endif
1029
1030 return readBytes;
1031}
1032
1036qint64 QIODevicePrivate::read(char *data, qint64 maxSize, bool peeking)
1037{
1038 Q_Q(QIODevice);
1039
1040 const bool buffered = (readBufferChunkSize != 0 && (openMode & QIODevice::Unbuffered) == 0);
1041 const bool sequential = isSequential();
1042 const bool keepDataInBuffer = sequential
1043 ? peeking || transactionStarted
1044 : peeking && buffered;
1045 const qint64 savedPos = pos;
1046 qint64 readSoFar = 0;
1047 bool madeBufferReadsOnly = true;
1048 bool deviceAtEof = false;
1049 char *readPtr = data;
1050 qint64 bufferPos = (sequential && transactionStarted) ? transactionPos : Q_INT64_C(0);
1051 forever {
1052 // Try reading from the buffer.
1053 qint64 bufferReadChunkSize = keepDataInBuffer
1054 ? buffer.peek(data, maxSize, bufferPos)
1055 : buffer.read(data, maxSize);
1056 if (bufferReadChunkSize > 0) {
1057 bufferPos += bufferReadChunkSize;
1058 if (!sequential)
1059 pos += bufferReadChunkSize;
1060#if defined QIODEVICE_DEBUG
1061 printf("%p \treading %lld bytes from buffer into position %lld\n", q,
1062 bufferReadChunkSize, readSoFar);
1063#endif
1064 readSoFar += bufferReadChunkSize;
1065 data += bufferReadChunkSize;
1066 maxSize -= bufferReadChunkSize;
1067 }
1068
1069 if (maxSize > 0 && !deviceAtEof) {
1071 // Make sure the device is positioned correctly.
1072 if (sequential || pos == devicePos || q->seek(pos)) {
1073 madeBufferReadsOnly = false; // fix readData attempt
1074 if ((!buffered || maxSize >= readBufferChunkSize) && !keepDataInBuffer) {
1075 // Read big chunk directly to output buffer
1076 readFromDevice = q->readData(data, maxSize);
1077 deviceAtEof = (readFromDevice != maxSize);
1078#if defined QIODEVICE_DEBUG
1079 printf("%p \treading %lld bytes from device (total %lld)\n", q,
1080 readFromDevice, readSoFar);
1081#endif
1082 if (readFromDevice > 0) {
1083 readSoFar += readFromDevice;
1085 maxSize -= readFromDevice;
1086 if (!sequential) {
1089 }
1090 }
1091 } else {
1092 // Do not read more than maxSize on unbuffered devices
1093 const qint64 bytesToBuffer = (!buffered && maxSize < buffer.chunkSize())
1094 ? maxSize
1095 : qint64(buffer.chunkSize());
1096 // Try to fill QIODevice buffer by single read
1097 readFromDevice = q->readData(buffer.reserve(bytesToBuffer), bytesToBuffer);
1098 deviceAtEof = (readFromDevice != bytesToBuffer);
1099 buffer.chop(bytesToBuffer - qMax(Q_INT64_C(0), readFromDevice));
1100 if (readFromDevice > 0) {
1101 if (!sequential)
1103#if defined QIODEVICE_DEBUG
1104 printf("%p \treading %lld from device into buffer\n", q,
1106#endif
1107 continue;
1108 }
1109 }
1110 } else {
1111 readFromDevice = -1;
1112 }
1113
1114 if (readFromDevice < 0 && readSoFar == 0) {
1115 // error and we haven't read anything: return immediately
1116 return qint64(-1);
1117 }
1118 }
1119
1120 if ((openMode & QIODevice::Text) && readPtr < data) {
1121 const char *endPtr = data;
1122
1123 // optimization to avoid initial self-assignment
1124 while (*readPtr != '\r') {
1125 if (++readPtr == endPtr)
1126 break;
1127 }
1128
1129 char *writePtr = readPtr;
1130
1131 while (readPtr < endPtr) {
1132 char ch = *readPtr++;
1133 if (ch != '\r')
1134 *writePtr++ = ch;
1135 else {
1136 --readSoFar;
1137 --data;
1138 ++maxSize;
1139 }
1140 }
1141
1142 // Make sure we get more data if there is room for more. This
1143 // is very important for when someone seeks to the start of a
1144 // '\r\n' and reads one character - they should get the '\n'.
1145 readPtr = data;
1146 continue;
1147 }
1148
1149 break;
1150 }
1151
1152 // Restore positions after reading
1153 if (keepDataInBuffer) {
1154 if (peeking)
1155 pos = savedPos; // does nothing on sequential devices
1156 else
1157 transactionPos = bufferPos;
1158 } else if (peeking) {
1159 seekBuffer(savedPos); // unbuffered random-access device
1160 }
1161
1162 if (madeBufferReadsOnly && isBufferEmpty())
1163 q->readData(data, 0);
1164
1165 return readSoFar;
1166}
1167
1180{
1181 Q_D(QIODevice);
1182#if defined QIODEVICE_DEBUG
1183 printf("%p QIODevice::read(%lld), d->pos = %lld, d->buffer.size() = %lld\n",
1184 this, maxSize, d->pos, d->buffer.size());
1185#endif
1186
1189
1190 // Try to prevent the data from being copied, if we have a chunk
1191 // with the same size in the read buffer.
1192 if (maxSize == d->buffer.nextDataBlockSize() && !d->transactionStarted
1193 && (d->openMode & QIODevice::Text) == 0) {
1194 result = d->buffer.read();
1195 if (!d->isSequential())
1196 d->pos += maxSize;
1197 if (d->buffer.isEmpty())
1198 readData(nullptr, 0);
1199 return result;
1200 }
1201
1204
1205 result.resize(qsizetype(maxSize));
1206 qint64 readBytes = d->read(result.data(), result.size());
1207
1208 if (readBytes <= 0)
1209 result.clear();
1210 else
1211 result.resize(qsizetype(readBytes));
1212
1213 return result;
1214}
1215
1227{
1228 Q_D(QIODevice);
1229#if defined QIODEVICE_DEBUG
1230 printf("%p QIODevice::readAll(), d->pos = %lld, d->buffer.size() = %lld\n",
1231 this, d->pos, d->buffer.size());
1232#endif
1233
1236
1237 qint64 readBytes = (d->isSequential() ? Q_INT64_C(0) : size());
1238 if (readBytes == 0) {
1239 // Size is unknown, read incrementally.
1240 qint64 readChunkSize = qMax(qint64(d->buffer.chunkSize()),
1241 d->isSequential() ? (d->buffer.size() - d->transactionPos)
1242 : d->buffer.size());
1243 qint64 readResult;
1244 do {
1245 if (readBytes + readChunkSize >= QByteArray::max_size()) {
1246 // If resize would fail, don't read more, return what we have.
1247 break;
1248 }
1249 result.resize(readBytes + readChunkSize);
1250 readResult = d->read(result.data() + readBytes, readChunkSize);
1251 if (readResult > 0 || readBytes == 0) {
1252 readBytes += readResult;
1253 readChunkSize = d->buffer.chunkSize();
1254 }
1255 } while (readResult > 0);
1256 } else {
1257 // Read it all in one go.
1258 readBytes -= d->pos;
1259 if (readBytes >= QByteArray::max_size())
1260 readBytes = QByteArray::max_size();
1261 result.resize(readBytes);
1262 readBytes = d->read(result.data(), readBytes);
1263 }
1264
1265 if (readBytes <= 0)
1266 result.clear();
1267 else
1268 result.resize(qsizetype(readBytes));
1269
1270 return result;
1271}
1272
1315{
1316 Q_D(QIODevice);
1317#if defined QIODEVICE_DEBUG
1318 printf("%p QIODevice::readLine(%p, %lld), d->pos = %lld, d->buffer.size() = %lld\n",
1319 this, data, maxSize, d->pos, d->buffer.size());
1320#endif
1321
1324 const qint64 readBytes = d->readLine(data, maxSize);
1325
1326#if defined QIODEVICE_DEBUG
1327 printf("%p \treturning %lld, d->pos = %lld, d->buffer.size() = %lld, size() = %lld\n",
1328 this, readBytes, d->pos, d->buffer.size(), size());
1329 debugBinaryString(data, readBytes);
1330#endif
1331
1332 return readBytes;
1333}
1334
1339{
1340 Q_Q(QIODevice);
1341 Q_ASSERT(maxSize >= 2);
1342
1343 // Leave room for a '\0'
1344 --maxSize;
1345
1346 const bool sequential = isSequential();
1347 const bool keepDataInBuffer = sequential && transactionStarted;
1348
1349 qint64 readSoFar = 0;
1350 if (keepDataInBuffer) {
1351 if (transactionPos < buffer.size()) {
1352 // Peek line from the specified position
1353 const qint64 i = buffer.indexOf('\n', maxSize, transactionPos);
1354 readSoFar = buffer.peek(data, i >= 0 ? (i - transactionPos + 1) : maxSize,
1356 transactionPos += readSoFar;
1357 if (transactionPos == buffer.size())
1358 q->readData(data, 0);
1359 }
1360 } else if (!buffer.isEmpty()) {
1361 // QRingBuffer::readLine() terminates the line with '\0'
1362 readSoFar = buffer.readLine(data, maxSize + 1);
1363 if (buffer.isEmpty())
1364 q->readData(data, 0);
1365 if (!sequential)
1366 pos += readSoFar;
1367 }
1368
1369 if (readSoFar) {
1370#if defined QIODEVICE_DEBUG
1371 printf("%p \tread from buffer: %lld bytes, last character read: %hhx\n", q,
1372 readSoFar, data[readSoFar - 1]);
1373 debugBinaryString(data, readSoFar);
1374#endif
1375 if (data[readSoFar - 1] == '\n') {
1376 if (openMode & QIODevice::Text) {
1377 // QRingBuffer::readLine() isn't Text aware.
1378 if (readSoFar > 1 && data[readSoFar - 2] == '\r') {
1379 --readSoFar;
1380 data[readSoFar - 1] = '\n';
1381 }
1382 }
1383 data[readSoFar] = '\0';
1384 return readSoFar;
1385 }
1386 }
1387
1388 if (pos != devicePos && !sequential && !q->seek(pos))
1389 return qint64(-1);
1390 baseReadLineDataCalled = false;
1391 // Force base implementation for transaction on sequential device
1392 // as it stores the data in internal buffer automatically.
1393 qint64 readBytes = keepDataInBuffer
1394 ? q->QIODevice::readLineData(data + readSoFar, maxSize - readSoFar)
1395 : q->readLineData(data + readSoFar, maxSize - readSoFar);
1396#if defined QIODEVICE_DEBUG
1397 printf("%p \tread from readLineData: %lld bytes, readSoFar = %lld bytes\n", q,
1398 readBytes, readSoFar);
1399 if (readBytes > 0) {
1400 debugBinaryString(data, readSoFar + readBytes);
1401 }
1402#endif
1403 if (readBytes < 0) {
1404 data[readSoFar] = '\0';
1405 return readSoFar ? readSoFar : -1;
1406 }
1407 readSoFar += readBytes;
1408 if (!baseReadLineDataCalled && !sequential) {
1409 pos += readBytes;
1410 // If the base implementation was not called, then we must
1411 // assume the device position is invalid and force a seek.
1412 devicePos = qint64(-1);
1413 }
1414 data[readSoFar] = '\0';
1415
1416 if (openMode & QIODevice::Text) {
1417 if (readSoFar > 1 && data[readSoFar - 1] == '\n' && data[readSoFar - 2] == '\r') {
1418 data[readSoFar - 2] = '\n';
1419 data[readSoFar - 1] = '\0';
1420 --readSoFar;
1421 }
1422 }
1423
1424 return readSoFar;
1425}
1426
1438{
1439 Q_D(QIODevice);
1440#if defined QIODEVICE_DEBUG
1441 printf("%p QIODevice::readLine(%lld), d->pos = %lld, d->buffer.size() = %lld\n",
1442 this, maxSize, d->pos, d->buffer.size());
1443#endif
1444
1447
1448 qint64 readBytes = 0;
1449 if (maxSize == 0) {
1450 // Size is unknown, read incrementally.
1451 maxSize = QByteArray::max_size() - 1;
1452
1453 // The first iteration needs to leave an extra byte for the terminating null
1454 result.resize(1);
1455
1456 qint64 readResult;
1457 do {
1458 result.resize(qsizetype(qMin(maxSize, qint64(result.size() + d->buffer.chunkSize()))));
1459 readResult = d->readLine(result.data() + readBytes, result.size() - readBytes);
1460 if (readResult > 0 || readBytes == 0)
1461 readBytes += readResult;
1462 } while (readResult == d->buffer.chunkSize()
1463 && result[qsizetype(readBytes - 1)] != '\n');
1464 } else {
1467
1468 result.resize(maxSize);
1469 readBytes = d->readLine(result.data(), result.size());
1470 }
1471
1472 if (readBytes <= 0)
1473 result.clear();
1474 else
1475 result.resize(readBytes);
1476
1477 result.squeeze();
1478 return result;
1479}
1480
1499{
1500 Q_D(QIODevice);
1501 qint64 readSoFar = 0;
1502 char c;
1503 qint64 lastReadReturn = 0;
1504 d->baseReadLineDataCalled = true;
1505
1506 while (readSoFar < maxSize && (lastReadReturn = read(&c, 1)) == 1) {
1507 *data++ = c;
1508 ++readSoFar;
1509 if (c == '\n')
1510 break;
1511 }
1512
1513#if defined QIODEVICE_DEBUG
1514 printf("%p QIODevice::readLineData(%p, %lld), d->pos = %lld, d->buffer.size() = %lld, "
1515 "returns %lld\n", this, data, maxSize, d->pos, d->buffer.size(), readSoFar);
1516#endif
1517 if (lastReadReturn != 1 && readSoFar == 0)
1518 return isSequential() ? lastReadReturn : -1;
1519 return readSoFar;
1520}
1521
1540{
1541 Q_D(const QIODevice);
1542 return d->buffer.indexOf('\n', d->buffer.size(),
1543 d->isSequential() ? d->transactionPos : Q_INT64_C(0)) >= 0;
1544}
1545
1562{
1563 Q_D(QIODevice);
1564 if (d->transactionStarted) {
1565 checkWarnMessage(this, "startTransaction", "Called while transaction already in progress");
1566 return;
1567 }
1568 d->transactionPos = d->pos;
1569 d->transactionStarted = true;
1570}
1571
1583{
1584 Q_D(QIODevice);
1585 if (!d->transactionStarted) {
1586 checkWarnMessage(this, "commitTransaction", "Called while no transaction in progress");
1587 return;
1588 }
1589 if (d->isSequential())
1590 d->buffer.free(d->transactionPos);
1591 d->transactionStarted = false;
1592 d->transactionPos = 0;
1593}
1594
1607{
1608 Q_D(QIODevice);
1609 if (!d->transactionStarted) {
1610 checkWarnMessage(this, "rollbackTransaction", "Called while no transaction in progress");
1611 return;
1612 }
1613 if (!d->isSequential())
1614 d->seekBuffer(d->transactionPos);
1615 d->transactionStarted = false;
1616 d->transactionPos = 0;
1617}
1618
1628{
1629 return d_func()->transactionStarted;
1630}
1631
1639qint64 QIODevice::write(const char *data, qint64 maxSize)
1640{
1641 Q_D(QIODevice);
1644
1645 const bool sequential = d->isSequential();
1646 // Make sure the device is positioned correctly.
1647 if (d->pos != d->devicePos && !sequential && !seek(d->pos))
1648 return qint64(-1);
1649
1650#ifdef Q_OS_WIN
1651 if (d->openMode & Text) {
1652 const char *endOfData = data + maxSize;
1653 const char *startOfBlock = data;
1654
1655 qint64 writtenSoFar = 0;
1656 const qint64 savedPos = d->pos;
1657
1658 forever {
1659 const char *endOfBlock = startOfBlock;
1660 while (endOfBlock < endOfData && *endOfBlock != '\n')
1661 ++endOfBlock;
1662
1663 qint64 blockSize = endOfBlock - startOfBlock;
1664 if (blockSize > 0) {
1665 qint64 ret = writeData(startOfBlock, blockSize);
1666 if (ret <= 0) {
1667 if (writtenSoFar && !sequential)
1668 d->buffer.skip(d->pos - savedPos);
1669 return writtenSoFar ? writtenSoFar : ret;
1670 }
1671 if (!sequential) {
1672 d->pos += ret;
1673 d->devicePos += ret;
1674 }
1675 writtenSoFar += ret;
1676 }
1677
1678 if (endOfBlock == endOfData)
1679 break;
1680
1681 qint64 ret = writeData("\r\n", 2);
1682 if (ret <= 0) {
1683 if (writtenSoFar && !sequential)
1684 d->buffer.skip(d->pos - savedPos);
1685 return writtenSoFar ? writtenSoFar : ret;
1686 }
1687 if (!sequential) {
1688 d->pos += ret;
1689 d->devicePos += ret;
1690 }
1691 ++writtenSoFar;
1692
1693 startOfBlock = endOfBlock + 1;
1694 }
1695
1696 if (writtenSoFar && !sequential)
1697 d->buffer.skip(d->pos - savedPos);
1698 return writtenSoFar;
1699 }
1700#endif
1701
1702 qint64 written = writeData(data, maxSize);
1703 if (!sequential && written > 0) {
1704 d->pos += written;
1705 d->devicePos += written;
1706 d->buffer.skip(written);
1707 }
1708 return written;
1709}
1710
1728{
1729 return write(data, qstrlen(data));
1730}
1731
1742{
1743 Q_D(QIODevice);
1744
1745 // Keep the chunk pointer for further processing in
1746 // QIODevicePrivate::write(). To reduce fragmentation,
1747 // the chunk size must be sufficiently large.
1748 if (data.size() >= QRINGBUFFER_CHUNKSIZE)
1749 d->currentWriteChunk = &data;
1750
1751 const qint64 ret = write(data.constData(), data.size());
1752
1753 d->currentWriteChunk = nullptr;
1754 return ret;
1755}
1756
1761{
1763 // We are called from write(const QByteArray &) overload.
1764 // So, we can make a shallow copy of chunk.
1766 } else {
1767 writeBuffer.append(data, size);
1768 }
1769}
1770
1783{
1784 Q_D(QIODevice);
1786
1787 if (d->transactionStarted) {
1788 checkWarnMessage(this, "ungetChar", "Called while transaction is in progress");
1789 return;
1790 }
1791
1792#if defined QIODEVICE_DEBUG
1793 printf("%p QIODevice::ungetChar(0x%hhx '%c')\n", this, c, isAsciiPrintable(c) ? c : '?');
1794#endif
1795
1796 d->buffer.ungetChar(c);
1797 if (!d->isSequential())
1798 --d->pos;
1799}
1800
1809{
1810 return d_func()->putCharHelper(c);
1811}
1812
1817{
1818 return q_func()->write(&c, 1) == 1;
1819}
1820
1825{
1826 return read(data, maxSize, true);
1827}
1828
1833{
1835
1836 const qint64 readBytes = read(result.data(), maxSize, true);
1837
1838 if (readBytes < maxSize) {
1839 if (readBytes <= 0)
1840 result.clear();
1841 else
1842 result.resize(readBytes);
1843 }
1844
1845 return result;
1846}
1847
1857{
1858 // readability checked in read()
1859 char ch;
1860 return (1 == read(c ? c : &ch, 1));
1861}
1862
1881{
1882 Q_D(QIODevice);
1883
1884 CHECK_MAXLEN(peek, qint64(-1));
1886
1887 return d->peek(data, maxSize);
1888}
1889
1908{
1909 Q_D(QIODevice);
1910
1914
1915 return d->peek(maxSize);
1916}
1917
1940{
1941 Q_D(QIODevice);
1942 CHECK_MAXLEN(skip, qint64(-1));
1944
1945 const bool sequential = d->isSequential();
1946
1947#if defined QIODEVICE_DEBUG
1948 printf("%p QIODevice::skip(%lld), d->pos = %lld, d->buffer.size() = %lld\n",
1949 this, maxSize, d->pos, d->buffer.size());
1950#endif
1951
1952 if ((sequential && d->transactionStarted) || (d->openMode & QIODevice::Text) != 0)
1953 return d->skipByReading(maxSize);
1954
1955 // First, skip over any data in the internal buffer.
1956 qint64 skippedSoFar = 0;
1957 if (!d->buffer.isEmpty()) {
1958 skippedSoFar = d->buffer.skip(maxSize);
1959#if defined QIODEVICE_DEBUG
1960 printf("%p \tskipping %lld bytes in buffer\n", this, skippedSoFar);
1961#endif
1962 if (!sequential)
1963 d->pos += skippedSoFar;
1964 if (d->buffer.isEmpty())
1965 readData(nullptr, 0);
1966 if (skippedSoFar == maxSize)
1967 return skippedSoFar;
1968
1969 maxSize -= skippedSoFar;
1970 }
1971
1972 // Try to seek on random-access device. At this point,
1973 // the internal read buffer is empty.
1974 if (!sequential) {
1975 const qint64 bytesToSkip = qMin(size() - d->pos, maxSize);
1976
1977 // If the size is unknown or file position is at the end,
1978 // fall back to reading below.
1979 if (bytesToSkip > 0) {
1980 if (!seek(d->pos + bytesToSkip))
1981 return skippedSoFar ? skippedSoFar : Q_INT64_C(-1);
1982 if (bytesToSkip == maxSize)
1983 return skippedSoFar + bytesToSkip;
1984
1985 skippedSoFar += bytesToSkip;
1986 maxSize -= bytesToSkip;
1987 }
1988 }
1989
1990 const qint64 skipResult = skipData(maxSize);
1991 if (skippedSoFar == 0)
1992 return skipResult;
1993
1994 if (skipResult == -1)
1995 return skippedSoFar;
1996
1997 return skippedSoFar + skipResult;
1998}
1999
2004{
2005 qint64 readSoFar = 0;
2006 do {
2007 char dummy[4096];
2008 const qint64 readBytes = qMin<qint64>(maxSize, sizeof(dummy));
2009 const qint64 readResult = read(dummy, readBytes);
2010
2011 // Do not try again, if we got less data.
2012 if (readResult != readBytes) {
2013 if (readSoFar == 0)
2014 return readResult;
2015
2016 if (readResult == -1)
2017 return readSoFar;
2018
2019 return readSoFar + readResult;
2020 }
2021
2022 readSoFar += readResult;
2023 maxSize -= readResult;
2024 } while (maxSize > 0);
2025
2026 return readSoFar;
2027}
2028
2045{
2046 return d_func()->skipByReading(maxSize);
2047}
2048
2073{
2074 Q_UNUSED(msecs);
2075 return false;
2076}
2077
2105{
2106 Q_UNUSED(msecs);
2107 return false;
2108}
2109
2117{
2118 d_func()->errorString = str;
2119}
2120
2128{
2129 Q_D(const QIODevice);
2130 if (d->errorString.isEmpty()) {
2131#ifdef QT_NO_QOBJECT
2132 return QLatin1StringView(QT_TRANSLATE_NOOP(QIODevice, "Unknown error"));
2133#else
2134 return tr("Unknown error");
2135#endif
2136 }
2137 return d->errorString;
2138}
2139
2192{
2193 if (timeout == -1)
2194 return -1;
2195
2197 return timeout < 0 ? 0 : timeout;
2198}
2199
2200
2201#if !defined(QT_NO_DEBUG_STREAM)
2202QDebug operator<<(QDebug debug, QIODevice::OpenMode modes)
2203{
2204 debug << "OpenMode(";
2205 QStringList modeList;
2206 if (modes == QIODevice::NotOpen) {
2207 modeList << "NotOpen"_L1;
2208 } else {
2209 if (modes & QIODevice::ReadOnly)
2210 modeList << "ReadOnly"_L1;
2211 if (modes & QIODevice::WriteOnly)
2212 modeList << "WriteOnly"_L1;
2213 if (modes & QIODevice::Append)
2214 modeList << "Append"_L1;
2215 if (modes & QIODevice::Truncate)
2216 modeList << "Truncate"_L1;
2217 if (modes & QIODevice::Text)
2218 modeList << "Text"_L1;
2219 if (modes & QIODevice::Unbuffered)
2220 modeList << "Unbuffered"_L1;
2221 }
2222 std::sort(modeList.begin(), modeList.end());
2223 debug << modeList.join(u'|');
2224 debug << ')';
2225 return debug;
2226}
2227#endif
2228
2230
2231#ifndef QT_NO_QOBJECT
2232#include "moc_qiodevice.cpp"
2233#endif
IOBluetoothL2CAPChannel * channel
IOBluetoothDevice * device
\inmodule QtCore
Definition qbytearray.h:57
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
Definition qbytearray.h:494
static constexpr qsizetype max_size() noexcept
Definition qbytearray.h:485
void clear()
Clears the contents of the byte array and makes it null.
\inmodule QtCore
static QString toNativeSeparators(const QString &pathName)
Definition qdir.cpp:929
\inmodule QtCore
Definition qfile.h:93
QString fileName() const override
Returns the name set by setFileName() or to the QFile constructors.
Definition qfile.cpp:277
void setCurrentWriteChannel(int channel)
QIODevice::OpenMode openMode
void write(const char *data, qint64 size)
QVarLengthArray< QRingBuffer, 1 > writeBuffers
bool allWriteBuffersEmpty() const
virtual ~QIODevicePrivate()
qint64 transactionPos
Definition qiodevice_p.h:55
bool isBufferEmpty() const
bool isSequential() const
void setReadChannelCount(int count)
void seekBuffer(qint64 newPos)
QVarLengthArray< QRingBuffer, 2 > readBuffers
bool baseReadLineDataCalled
qint64 skipByReading(qint64 maxSize)
void setCurrentReadChannel(int channel)
qint64 readLine(char *data, qint64 maxSize)
const QByteArray * currentWriteChunk
Definition qiodevice_p.h:94
qint64 read(char *data, qint64 maxSize, bool peeking=false)
bool isWriteChunkCached(const char *data, qint64 size) const
virtual bool putCharHelper(char c)
virtual qint64 peek(char *data, qint64 maxSize)
void setWriteChannelCount(int count)
\inmodule QtCore \reentrant
Definition qiodevice.h:34
virtual bool open(QIODeviceBase::OpenMode mode)
Opens the device and sets its OpenMode to mode.
int writeChannelCount() const
virtual qint64 size() const
For open random-access devices, this function returns the size of the device.
virtual qint64 pos() const
For random-access devices, this function returns the position that data is written to or read from.
void setOpenMode(QIODeviceBase::OpenMode openMode)
Sets the OpenMode of the device to openMode.
virtual bool isSequential() const
Returns true if this device is sequential; otherwise returns false.
virtual bool waitForBytesWritten(int msecs)
For buffered devices, this function waits until a payload of buffered written data has been written t...
qint64 readLine(char *data, qint64 maxlen)
This function reads a line of ASCII characters from the device, up to a maximum of maxSize - 1 bytes,...
virtual ~QIODevice()
The destructor is virtual, and QIODevice is an abstract base class.
bool putChar(char c)
Writes the character c to the device.
int currentReadChannel() const
bool isOpen() const
Returns true if the device is open; otherwise returns false.
QByteArray readAll()
Reads all remaining data from the device, and returns it as a byte array.
int currentWriteChannel() const
virtual bool waitForReadyRead(int msecs)
Blocks until new data is available for reading and the readyRead() signal has been emitted,...
bool isReadable() const
Returns true if data can be read from the device; otherwise returns false.
void setErrorString(const QString &errorString)
Sets the human readable description of the last device error that occurred to str.
void rollbackTransaction()
QIODevice()
Constructs a QIODevice object.
void setTextModeEnabled(bool enabled)
If enabled is true, this function sets the \l Text flag on the device; otherwise the \l Text flag is ...
qint64 write(const char *data, qint64 len)
Writes at most maxSize bytes of data from data to the device.
QIODeviceBase::OpenMode openMode() const
Returns the mode in which the device has been opened; i.e.
qint64 peek(char *data, qint64 maxlen)
virtual qint64 bytesAvailable() const
Returns the number of bytes that are available for reading.
void startTransaction()
qint64 skip(qint64 maxSize)
QString errorString() const
Returns a human-readable description of the last device error that occurred.
bool getChar(char *c)
Reads one character from the device and stores it in c.
virtual qint64 skipData(qint64 maxSize)
bool isTransactionStarted() const
bool isWritable() const
Returns true if data can be written to the device; otherwise returns false.
virtual qint64 readLineData(char *data, qint64 maxlen)
Reads up to maxSize characters into data and returns the number of characters read.
virtual qint64 writeData(const char *data, qint64 len)=0
Writes up to maxSize bytes from data to the device.
virtual qint64 bytesToWrite() const
For buffered devices, this function returns the number of bytes waiting to be written.
virtual void close()
First emits aboutToClose(), then closes the device and sets its OpenMode to NotOpen.
virtual bool seek(qint64 pos)
For random-access devices, this function sets the current position to pos, returning true on success,...
virtual bool reset()
Seeks to the start of input for random-access devices.
virtual bool atEnd() const
Returns true if the current read and write position is at the end of the device (i....
void setCurrentWriteChannel(int channel)
void aboutToClose()
This signal is emitted when the device is about to close.
bool isTextModeEnabled() const
Returns true if the \l Text flag is enabled; otherwise returns false.
void ungetChar(char c)
Puts the character c back into the device, and decrements the current position unless the position is...
int readChannelCount() const
void setCurrentReadChannel(int channel)
void commitTransaction()
virtual bool canReadLine() const
Returns true if a complete line of data can be read from the device; otherwise returns false.
qint64 read(char *data, qint64 maxlen)
Reads at most maxSize bytes from the device into data, and returns the number of bytes read.
\inmodule QtCore
Definition qobject.h:103
QObject * parent() const
Returns a pointer to the parent object.
Definition qobject.h:346
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
constexpr size_type size() const noexcept
T & emplace_back(Args &&...args)
void resize(qsizetype sz)
void reserve(qsizetype sz)
static bool readFromDevice(QIODevice *device, QJsonArray *allMetaObjects)
QString str
[2]
Combined button and popup list for selecting options.
constexpr int isAsciiPrintable(char32_t ch) noexcept
Definition qtools_p.h:104
constexpr Initialization Uninitialized
const int blockSize
size_t qstrlen(const char *str)
#define Q_DECL_COLD_FUNCTION
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction function
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
#define forever
Definition qforeach.h:78
int qt_subtract_from_timeout(int timeout, int elapsed)
#define CHECK_WRITABLE(function, returnType)
Definition qiodevice.cpp:97
static Q_DECL_COLD_FUNCTION void checkWarnMessage(const QIODevice *device, const char *function, const char *what)
Definition qiodevice.cpp:48
#define CHECK_MAXLEN(function, returnType)
Definition qiodevice.cpp:73
static void debugBinaryString(const char *input, qint64 maxlen)
Definition qiodevice.cpp:22
QDebug operator<<(QDebug debug, QIODevice::OpenMode modes)
#define CHECK_MAXBYTEARRAYSIZE(function)
Definition qiodevice.cpp:89
#define Q_VOID
Definition qiodevice.cpp:45
#define CHECK_READABLE(function, returnType)
#define CHECK_LINEMAXLEN(function, returnType)
Definition qiodevice.cpp:81
#define QIODEVICE_BUFFERSIZE
Definition qiodevice_p.h:31
#define qDebug
[1]
Definition qlogging.h:164
#define qWarning
Definition qlogging.h:166
return ret
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
GLenum mode
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum GLenum GLsizei count
GLbitfield GLuint64 timeout
[4]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLenum GLsizei const GLuint GLboolean enabled
GLfloat GLfloat f
GLenum GLuint buffer
GLenum GLuint GLintptr offset
const GLubyte * c
GLuint writeBuffer
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLuint64EXT * result
[6]
GLenum GLenum GLenum input
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define QRINGBUFFER_CHUNKSIZE
#define qPrintable(string)
Definition qstring.h:1531
static double elapsed(qint64 after, qint64 before)
#define tr(X)
#define emit
#define Q_UNUSED(x)
#define QT_TRANSLATE_NOOP(scope, x)
unsigned char uchar
Definition qtypes.h:32
ptrdiff_t qsizetype
Definition qtypes.h:165
long long qint64
Definition qtypes.h:60
qint64 qlonglong
Definition qtypes.h:63
#define Q_INT64_C(c)
Definition qtypes.h:57
const char className[16]
[1]
Definition qwizard.cpp:100
QFile file
[0]
obj metaObject() -> className()
QObject::connect nullptr
QByteArray readData()