Ivailo Monev 2019-05-19 02:06:26 +00:00
parent 977546e00f
commit a0ef87cd2b
7 changed files with 213 additions and 196 deletions

2
README
View file

@ -61,7 +61,7 @@ QTBUG-21548, QTBUG-6133, QTBUG-18188, QTBUG-36767, QTBUG-35387, QTBUG-37035,
QTBUG-28321, QTBUG-21993, QTBUG-26590, QTBUG-2124, QTBUG-20482, QTBUG-41361, QTBUG-28321, QTBUG-21993, QTBUG-26590, QTBUG-2124, QTBUG-20482, QTBUG-41361,
QTBUG-40153, QTBUG-35479, QTBUG-1628, QTBUG-42989, QTBUG-34861, QTBUG-46767, QTBUG-40153, QTBUG-35479, QTBUG-1628, QTBUG-42989, QTBUG-34861, QTBUG-46767,
QTBUG-25114, QTBUG-24672, QTBUG-23524 (WIP), QTBUG-56088, QTBUG-42189, QTBUG-25114, QTBUG-24672, QTBUG-23524 (WIP), QTBUG-56088, QTBUG-42189,
QTBUG-39285 QTBUG-39285, QTBUG-18173, QTBUG-28968, QTBUG-34336, QTBUG-40974, QTBUG-44286
Unless you use QMake and QDoc porting to Katie or even supporting it along with Unless you use QMake and QDoc porting to Katie or even supporting it along with
Qt4 in the same codebase is trivial and requires only minor changes because Qt4 in the same codebase is trivial and requires only minor changes because

View file

@ -45,12 +45,12 @@
#include "qdatetime.h" #include "qdatetime.h"
#include "qdiriterator.h" #include "qdiriterator.h"
#include "qset.h" #include "qset.h"
#include <QtCore/qdebug.h> #include "qdebug.h"
#include "qcore_unix_p.h"
#ifndef QT_NO_FSFILEENGINE #ifndef QT_NO_FSFILEENGINE
#include <errno.h> #include <errno.h>
#include "qcore_unix_p.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>

View file

@ -54,6 +54,8 @@
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
#define QBYTEARRAY_MAX INT_MAX
#ifdef QIODEVICE_DEBUG #ifdef QIODEVICE_DEBUG
void debugBinaryString(const QByteArray &input) void debugBinaryString(const QByteArray &input)
{ {
@ -97,8 +99,10 @@ inline void debugBinaryString(const char *data, qint64 maxlen)
#define CHECK_WRITABLE(function, returnType) \ #define CHECK_WRITABLE(function, returnType) \
do { \ do { \
if ((d->openMode & WriteOnly) == 0) { \ if ((d->openMode & WriteOnly) == 0) { \
if (d->openMode == NotOpen) \ if (d->openMode == NotOpen) { \
qWarning("QIODevice::"#function": device not open"); \
return returnType; \ return returnType; \
} \
qWarning("QIODevice::"#function": ReadOnly device"); \ qWarning("QIODevice::"#function": ReadOnly device"); \
return returnType; \ return returnType; \
} \ } \
@ -107,8 +111,10 @@ inline void debugBinaryString(const char *data, qint64 maxlen)
#define CHECK_READABLE(function, returnType) \ #define CHECK_READABLE(function, returnType) \
do { \ do { \
if ((d->openMode & ReadOnly) == 0) { \ if ((d->openMode & ReadOnly) == 0) { \
if (d->openMode == NotOpen) \ if (d->openMode == NotOpen) { \
qWarning("QIODevice::"#function": device not open"); \
return returnType; \ return returnType; \
} \
qWarning("QIODevice::"#function": WriteOnly device"); \ qWarning("QIODevice::"#function": WriteOnly device"); \
return returnType; \ return returnType; \
} \ } \
@ -118,8 +124,7 @@ inline void debugBinaryString(const char *data, qint64 maxlen)
*/ */
QIODevicePrivate::QIODevicePrivate() QIODevicePrivate::QIODevicePrivate()
: openMode(QIODevice::NotOpen), buffer(QIODEVICE_BUFFERSIZE), : openMode(QIODevice::NotOpen), buffer(QIODEVICE_BUFFERSIZE),
pos(0), devicePos(0), seqDumpPos(0) pos(0), devicePos(0)
, pPos(&pos), pDevicePos(&devicePos)
, baseReadLineDataCalled(false) , baseReadLineDataCalled(false)
, firstRead(true) , firstRead(true)
, accessMode(Unset) , accessMode(Unset)
@ -265,9 +270,10 @@ QIODevicePrivate::~QIODevicePrivate()
\value NotOpen The device is not open. \value NotOpen The device is not open.
\value ReadOnly The device is open for reading. \value ReadOnly The device is open for reading.
\value WriteOnly The device is open for writing. \value WriteOnly The device is open for writing. Note that this mode implies
Truncate.
\value ReadWrite The device is open for reading and writing. \value ReadWrite The device is open for reading and writing.
\value Append The device is opened in append mode, so that all data is \value Append The device is opened in append mode so that all data is
written to the end of the file. written to the end of the file.
\value Truncate If possible, the device is truncated before it is opened. \value Truncate If possible, the device is truncated before it is opened.
All earlier contents of the device are lost. All earlier contents of the device are lost.
@ -582,7 +588,6 @@ void QIODevice::close()
d->openMode = NotOpen; d->openMode = NotOpen;
d->errorString.clear(); d->errorString.clear();
d->pos = 0; d->pos = 0;
d->seqDumpPos = 0;
d->buffer.clear(); d->buffer.clear();
d->firstRead = true; d->firstRead = true;
} }
@ -604,7 +609,7 @@ qint64 QIODevice::pos() const
{ {
Q_D(const QIODevice); Q_D(const QIODevice);
#if defined QIODEVICE_DEBUG #if defined QIODEVICE_DEBUG
printf("%p QIODevice::pos() == %d\n", this, int(d->pos)); printf("%p QIODevice::pos() == %lld\n", this, d->pos);
#endif #endif
return d->pos; return d->pos;
} }
@ -626,30 +631,34 @@ qint64 QIODevice::size() const
/*! /*!
For random-access devices, this function sets the current position For random-access devices, this function sets the current position
to \a pos, returning true on success, or false if an error occurred. to \a pos, returning true on success, or false if an error occurred.
For sequential devices, the default behavior is to do nothing and For sequential devices, the default behavior is to produce a warning
return false. and return false.
When subclassing QIODevice, you must call QIODevice::seek() at the When subclassing QIODevice, you must call QIODevice::seek() at the
start of your function to ensure integrity with QIODevice's start of your function to ensure integrity with QIODevice's
built-in buffer. The base implementation always returns true. built-in buffer.
\sa pos(), isSequential() \sa pos(), isSequential()
*/ */
bool QIODevice::seek(qint64 pos) bool QIODevice::seek(qint64 pos)
{ {
Q_D(QIODevice); Q_D(QIODevice);
if (d->isSequential()) {
qWarning("QIODevice::seek: Cannot call seek on a sequential device");
return false;
}
if (d->openMode == NotOpen) { if (d->openMode == NotOpen) {
qWarning("QIODevice::seek: The device is not open"); qWarning("QIODevice::seek: The device is not open");
return false; return false;
} }
if (pos < 0) { if (pos < 0) {
qWarning("QIODevice::seek: Invalid pos: %d", int(pos)); qWarning("QIODevice::seek: Invalid pos: %lld", pos);
return false; return false;
} }
#if defined QIODEVICE_DEBUG #if defined QIODEVICE_DEBUG
printf("%p QIODevice::seek(%d), before: d->pos = %d, d->buffer.size() = %d\n", printf("%p QIODevice::seek(%lld), before: d->pos = %lld, d->buffer.size() = %lld\n",
this, int(pos), int(d->pos), d->buffer.size()); this, pos, d->pos, d->buffer.size());
#endif #endif
qint64 offset = pos - d->pos; qint64 offset = pos - d->pos;
@ -658,18 +667,17 @@ bool QIODevice::seek(qint64 pos)
d->devicePos = pos; d->devicePos = pos;
} }
if (offset < 0 if (offset < 0 || offset >= d->buffer.size())
|| offset >= qint64(d->buffer.size()))
// When seeking backwards, an operation that is only allowed for // When seeking backwards, an operation that is only allowed for
// random-access devices, the buffer is cleared. The next read // random-access devices, the buffer is cleared. The next read
// operation will then refill the buffer. We can optimize this, if we // operation will then refill the buffer. We can optimize this, if we
// find that seeking backwards becomes a significant performance hit. // find that seeking backwards becomes a significant performance hit.
d->buffer.clear(); d->buffer.clear();
else if (!d->buffer.isEmpty()) else if (!d->buffer.isEmpty())
d->buffer.skip(int(offset)); d->buffer.skip(offset);
#if defined QIODEVICE_DEBUG #if defined QIODEVICE_DEBUG
printf("%p \tafter: d->pos == %d, d->buffer.size() == %d\n", this, int(d->pos), printf("%p \tafter: d->pos == %lld, d->buffer.size() == %lld\n", this, d->pos,
d->buffer.size()); d->buffer.size());
#endif #endif
return true; return true;
@ -691,8 +699,9 @@ bool QIODevice::atEnd() const
{ {
Q_D(const QIODevice); Q_D(const QIODevice);
#if defined QIODEVICE_DEBUG #if defined QIODEVICE_DEBUG
printf("%p QIODevice::atEnd() returns %s, d->openMode == %d, d->pos == %d\n", this, (d->openMode == NotOpen || d->pos == size()) ? "true" : "false", printf("%p QIODevice::atEnd() returns %s, d->openMode == %d, d->pos == %lld\n", this,
int(d->openMode), int(d->pos)); (d->openMode == NotOpen || d->pos == size()) ? "true" : "false", int(d->openMode),
d->pos);
#endif #endif
return d->openMode == NotOpen || (d->buffer.isEmpty() && bytesAvailable() == 0); return d->openMode == NotOpen || (d->buffer.isEmpty() && bytesAvailable() == 0);
} }
@ -766,15 +775,18 @@ qint64 QIODevice::read(char *data, qint64 maxSize)
Q_D(QIODevice); Q_D(QIODevice);
#if defined QIODEVICE_DEBUG #if defined QIODEVICE_DEBUG
printf("%p QIODevice::read(%p, %d), d->pos = %d, d->buffer.size() = %d\n", printf("%p QIODevice::read(%p, %lld), d->pos = %lld, d->buffer.size() = %lld\n",
this, data, int(maxSize), int(d->pos), int(d->buffer.size())); this, data, maxSize, d->pos, d->buffer.size());
#endif #endif
const bool sequential = d->isSequential();
// Short circuit for getChar() // Short circuit for getChar()
if (maxSize == 1) { if (maxSize == 1) {
int chint; int chint;
while ((chint = d->buffer.getChar()) != -1) { while ((chint = d->buffer.getChar()) != -1) {
++(*d->pPos); if (!sequential)
++d->pos;
char c = char(uchar(chint)); char c = char(uchar(chint));
if (c == '\r' && (d->openMode & Text)) if (c == '\r' && (d->openMode & Text))
@ -784,28 +796,29 @@ qint64 QIODevice::read(char *data, qint64 maxSize)
printf("%p \tread 0x%hhx (%c) returning 1 (shortcut)\n", this, printf("%p \tread 0x%hhx (%c) returning 1 (shortcut)\n", this,
int(c), isprint(c) ? c : '?'); int(c), isprint(c) ? c : '?');
#endif #endif
if (d->buffer.isEmpty())
readData(data, 0);
return qint64(1); return qint64(1);
} }
} }
CHECK_MAXLEN(read, qint64(-1)); CHECK_MAXLEN(read, qint64(-1));
qint64 readSoFar = 0; qint64 readSoFar = 0;
bool moreToRead = true; bool madeBufferReadsOnly = true;
do { bool deviceAtEof = false;
char *readPtr = data;
forever {
// Try reading from the buffer. // Try reading from the buffer.
int lastReadChunkSize = d->buffer.read(data, maxSize); qint64 bufferReadChunkSize = d->buffer.read(data, maxSize);
if (lastReadChunkSize > 0) { if (bufferReadChunkSize > 0) {
*d->pPos += lastReadChunkSize; if (!sequential)
readSoFar += lastReadChunkSize; d->pos += bufferReadChunkSize;
// fast exit when satisfied by buffer readSoFar += bufferReadChunkSize;
if (lastReadChunkSize == maxSize && !(d->openMode & Text)) data += bufferReadChunkSize;
return readSoFar; maxSize -= bufferReadChunkSize;
data += lastReadChunkSize;
maxSize -= lastReadChunkSize;
#if defined QIODEVICE_DEBUG #if defined QIODEVICE_DEBUG
printf("%p \treading %d bytes from buffer into position %d\n", this, lastReadChunkSize, printf("%p \treading %lld bytes from buffer into position %lld\n", this,
int(readSoFar) - lastReadChunkSize); bufferReadChunkSize, readSoFar - bufferReadChunkSize);
#endif #endif
} else { } else {
if (d->firstRead) { if (d->firstRead) {
@ -813,111 +826,99 @@ qint64 QIODevice::read(char *data, qint64 maxSize)
// for fast pos updates. // for fast pos updates.
CHECK_READABLE(read, qint64(-1)); CHECK_READABLE(read, qint64(-1));
d->firstRead = false; d->firstRead = false;
if (d->isSequential()) {
d->pPos = &d->seqDumpPos;
d->pDevicePos = &d->seqDumpPos;
}
} }
}
if (!maxSize) if (maxSize > 0 && !deviceAtEof) {
return readSoFar; qint64 readFromDevice = 0;
// Make sure the device is positioned correctly.
if ((d->openMode & Unbuffered) == 0 && maxSize < QIODEVICE_BUFFERSIZE) { if (sequential || d->pos == d->devicePos || seek(d->pos)) {
// In buffered mode, we try to fill up the QIODevice buffer before madeBufferReadsOnly = false; // fix readData attempt
// we do anything else. if (maxSize >= QIODEVICE_BUFFERSIZE || (d->openMode & Unbuffered)) {
// buffer is empty at this point, try to fill it // Read big chunk directly to output buffer
int bytesToBuffer = QIODEVICE_BUFFERSIZE; readFromDevice = readData(data, maxSize);
char *writePointer = d->buffer.reserve(bytesToBuffer); deviceAtEof = (readFromDevice != maxSize);
// Make sure the device is positioned correctly.
if (d->pos != d->devicePos && !d->isSequential() && !seek(d->pos))
return readSoFar ? readSoFar : qint64(-1);
qint64 readFromDevice = readData(writePointer, bytesToBuffer);
d->buffer.chop(bytesToBuffer - (readFromDevice < 0 ? 0 : int(readFromDevice)));
if (readFromDevice > 0) {
*d->pDevicePos += readFromDevice;
#if defined QIODEVICE_DEBUG #if defined QIODEVICE_DEBUG
printf("%p \treading %d from device into buffer\n", this, int(readFromDevice)); printf("%p \treading %lld bytes from device (total %lld)\n", this,
readFromDevice, readSoFar);
#endif #endif
if (readFromDevice > 0) {
if (!d->buffer.isEmpty()) { readSoFar += readFromDevice;
lastReadChunkSize = d->buffer.read(data, maxSize); data += readFromDevice;
readSoFar += lastReadChunkSize; maxSize -= readFromDevice;
data += lastReadChunkSize; if (!sequential) {
maxSize -= lastReadChunkSize; d->pos += readFromDevice;
*d->pPos += lastReadChunkSize; d->devicePos += readFromDevice;
}
}
} else {
const qint64 bytesToBuffer = QIODEVICE_BUFFERSIZE;
// Try to fill QIODevice buffer by single read
readFromDevice = readData(d->buffer.reserve(bytesToBuffer), bytesToBuffer);
deviceAtEof = (readFromDevice != bytesToBuffer);
d->buffer.chop(bytesToBuffer - qMax(Q_INT64_C(0), readFromDevice));
if (readFromDevice > 0) {
if (!sequential)
d->devicePos += readFromDevice;
#if defined QIODEVICE_DEBUG #if defined QIODEVICE_DEBUG
printf("%p \treading %d bytes from buffer at position %d\n", this, printf("%p \treading %lld from device into buffer\n", this,
lastReadChunkSize, int(readSoFar)); readFromDevice);
#endif #endif
continue;
} }
} }
} else {
readFromDevice = -1;
} }
}
// If we need more, try reading from the device. if (readFromDevice < 0 && readSoFar == 0) {
if (maxSize > 0) {
// Make sure the device is positioned correctly.
if (d->pos != d->devicePos && !d->isSequential() && !seek(d->pos))
return readSoFar ? readSoFar : qint64(-1);
qint64 readFromDevice = readData(data, maxSize);
#if defined QIODEVICE_DEBUG
printf("%p \treading %d bytes from device (total %d)\n", this, int(readFromDevice), int(readSoFar));
#endif
if (readFromDevice == -1 && readSoFar == 0) {
// error and we haven't read anything: return immediately // error and we haven't read anything: return immediately
return -1; return qint64(-1);
}
if (readFromDevice > 0) {
lastReadChunkSize += int(readFromDevice);
readSoFar += readFromDevice;
data += readFromDevice;
maxSize -= readFromDevice;
*d->pPos += readFromDevice;
*d->pDevicePos += readFromDevice;
} }
} }
// Best attempt has been made to read data, don't try again except for text mode adjustment below
moreToRead = false;
if (readSoFar && d->openMode & Text) { if ((d->openMode & Text) && readPtr < data) {
char *readPtr = data - lastReadChunkSize;
const char *endPtr = data; const char *endPtr = data;
if (readPtr < endPtr) { // optimization to avoid initial self-assignment
// optimization to avoid initial self-assignment while (*readPtr != '\r') {
while (*readPtr != '\r') { if (++readPtr == endPtr)
if (++readPtr == endPtr) break;
return readSoFar;
}
char *writePtr = readPtr;
while (readPtr < endPtr) {
char ch = *readPtr++;
if (ch != '\r')
*writePtr++ = ch;
else {
--readSoFar;
--data;
++maxSize;
}
}
// Make sure we get more data if there is room for more. This
// is very important for when someone seeks to the start of a
// '\r\n' and reads one character - they should get the '\n'.
moreToRead = (readPtr != writePtr);
} }
char *writePtr = readPtr;
while (readPtr < endPtr) {
char ch = *readPtr++;
if (ch != '\r')
*writePtr++ = ch;
else {
--readSoFar;
--data;
++maxSize;
}
}
// Make sure we get more data if there is room for more. This
// is very important for when someone seeks to the start of a
// '\r\n' and reads one character - they should get the '\n'.
readPtr = data;
continue;
} }
} while (moreToRead);
break;
}
#if defined QIODEVICE_DEBUG #if defined QIODEVICE_DEBUG
printf("%p \treturning %d, d->pos == %d, d->buffer.size() == %d\n", this, printf("%p \treturning %lld, d->pos == %lld, d->buffer.size() == %lld\n", this,
int(readSoFar), int(d->pos), d->buffer.size()); readSoFar, d->pos, d->buffer.size());
debugBinaryString(data - readSoFar, readSoFar); debugBinaryString(data - readSoFar, readSoFar);
#endif #endif
if (madeBufferReadsOnly && d->buffer.isEmpty()) {
d->buffer.clear();
readData(data, 0);
}
return readSoFar; return readSoFar;
} }
@ -939,15 +940,15 @@ QByteArray QIODevice::read(qint64 maxSize)
CHECK_MAXLEN(read, result); CHECK_MAXLEN(read, result);
#if defined QIODEVICE_DEBUG #if defined QIODEVICE_DEBUG
printf("%p QIODevice::read(%d), d->pos = %d, d->buffer.size() = %d\n", printf("%p QIODevice::read(%lld), d->pos = %lld, d->buffer.size() = %lld\n",
this, int(maxSize), int(d->pos), int(d->buffer.size())); this, maxSize, d->pos, d->buffer.size());
#else #else
Q_UNUSED(d); Q_UNUSED(d);
#endif #endif
if (maxSize != qint64(int(maxSize))) { if (quint64(maxSize) >= QBYTEARRAY_MAX) {
qWarning("QIODevice::read: maxSize argument exceeds QByteArray size limit"); qWarning("QIODevice::read: maxSize argument exceeds QByteArray size limit");
maxSize = INT_MAX; maxSize = QBYTEARRAY_MAX - 1;
} }
qint64 readBytes = 0; qint64 readBytes = 0;
@ -989,33 +990,43 @@ QByteArray QIODevice::readAll()
{ {
Q_D(QIODevice); Q_D(QIODevice);
#if defined QIODEVICE_DEBUG #if defined QIODEVICE_DEBUG
printf("%p QIODevice::readAll(), d->pos = %d, d->buffer.size() = %d\n", printf("%p QIODevice::readAll(), d->pos = %lld, d->buffer.size() = %lld\n",
this, int(d->pos), int(d->buffer.size())); this, d->pos, d->buffer.size());
#endif #endif
QByteArray result; QByteArray result;
qint64 readBytes = 0; qint64 readBytes = 0;
const bool sequential = d->isSequential();
// flush internal read buffer // flush internal read buffer
if (!(d->openMode & Text) && !d->buffer.isEmpty()) { if (!(d->openMode & Text) && !d->buffer.isEmpty()) {
if (quint64(d->buffer.size()) >= QBYTEARRAY_MAX)
return QByteArray();
result = d->buffer.readAll(); result = d->buffer.readAll();
readBytes = result.size(); readBytes = result.size();
d->pos += readBytes; if (!sequential)
d->pos += readBytes;
} }
qint64 theSize; qint64 theSize;
if (d->isSequential() || (theSize = size()) == 0) { if (sequential || (theSize = size()) == 0) {
// Size is unknown, read incrementally. // Size is unknown, read incrementally.
qint64 readResult; qint64 readResult;
do { do {
result.resize(result.size() + QIODEVICE_BUFFERSIZE); if (quint64(readBytes) + QIODEVICE_BUFFERSIZE >= QBYTEARRAY_MAX) {
readResult = read(result.data() + readBytes, result.size() - readBytes); // If resize would fail, don't read more, return what we have.
break;
}
result.resize(readBytes + QIODEVICE_BUFFERSIZE);
readResult = read(result.data() + readBytes, QIODEVICE_BUFFERSIZE);
if (readResult > 0 || readBytes == 0) if (readResult > 0 || readBytes == 0)
readBytes += readResult; readBytes += readResult;
} while (readResult > 0); } while (readResult > 0);
} else { } else {
// Read it all in one go. // Read it all in one go.
// If resize fails, don't read anything. // If resize fails, don't read anything.
if (quint64(readBytes + theSize - d->pos) >= QBYTEARRAY_MAX)
return QByteArray();
result.resize(int(readBytes + theSize - d->pos)); result.resize(int(readBytes + theSize - d->pos));
readBytes += read(result.data() + readBytes, result.size() - readBytes); readBytes += read(result.data() + readBytes, result.size() - readBytes);
} }
@ -1073,8 +1084,8 @@ qint64 QIODevice::readLine(char *data, qint64 maxSize)
} }
#if defined QIODEVICE_DEBUG #if defined QIODEVICE_DEBUG
printf("%p QIODevice::readLine(%p, %d), d->pos = %d, d->buffer.size() = %d\n", printf("%p QIODevice::readLine(%p, %lld), d->pos = %lld, d->buffer.size() = %lld\n",
this, data, int(maxSize), int(d->pos), int(d->buffer.size())); this, data, maxSize, d->pos, d->buffer.size());
#endif #endif
// Leave room for a '\0' // Leave room for a '\0'
@ -1085,11 +1096,13 @@ qint64 QIODevice::readLine(char *data, qint64 maxSize)
qint64 readSoFar = 0; qint64 readSoFar = 0;
if (!d->buffer.isEmpty()) { if (!d->buffer.isEmpty()) {
readSoFar = d->buffer.readLine(data, maxSize); readSoFar = d->buffer.readLine(data, maxSize);
if (d->buffer.isEmpty())
readData(data, 0);
if (!sequential) if (!sequential)
d->pos += readSoFar; d->pos += readSoFar;
#if defined QIODEVICE_DEBUG #if defined QIODEVICE_DEBUG
printf("%p \tread from buffer: %d bytes, last character read: %hhx\n", this, printf("%p \tread from buffer: %lld bytes, last character read: %hhx\n", this,
int(readSoFar), data[int(readSoFar) - 1]); readSoFar, data[readSoFar - 1]);
if (readSoFar) if (readSoFar)
debugBinaryString(data, int(readSoFar)); debugBinaryString(data, int(readSoFar));
#endif #endif
@ -1111,8 +1124,8 @@ qint64 QIODevice::readLine(char *data, qint64 maxSize)
d->baseReadLineDataCalled = false; d->baseReadLineDataCalled = false;
qint64 readBytes = readLineData(data + readSoFar, maxSize - readSoFar); qint64 readBytes = readLineData(data + readSoFar, maxSize - readSoFar);
#if defined QIODEVICE_DEBUG #if defined QIODEVICE_DEBUG
printf("%p \tread from readLineData: %d bytes, readSoFar = %d bytes\n", this, printf("%p \tread from readLineData: %lld bytes, readSoFar = %lld bytes\n", this,
int(readBytes), int(readSoFar)); readBytes, readSoFar);
if (readBytes > 0) { if (readBytes > 0) {
debugBinaryString(data, int(readSoFar + readBytes)); debugBinaryString(data, int(readSoFar + readBytes));
} }
@ -1139,8 +1152,8 @@ qint64 QIODevice::readLine(char *data, qint64 maxSize)
} }
#if defined QIODEVICE_DEBUG #if defined QIODEVICE_DEBUG
printf("%p \treturning %d, d->pos = %d, d->buffer.size() = %d, size() = %d\n", printf("%p \treturning %lld, d->pos = %lld, d->buffer.size() = %lld, size() = %lld\n",
this, int(readSoFar), int(d->pos), d->buffer.size(), int(size())); this, readSoFar, d->pos, d->buffer.size(), size());
debugBinaryString(data, int(readSoFar)); debugBinaryString(data, int(readSoFar));
#endif #endif
return readSoFar; return readSoFar;
@ -1164,15 +1177,15 @@ QByteArray QIODevice::readLine(qint64 maxSize)
CHECK_MAXLEN(readLine, result); CHECK_MAXLEN(readLine, result);
#if defined QIODEVICE_DEBUG #if defined QIODEVICE_DEBUG
printf("%p QIODevice::readLine(%d), d->pos = %d, d->buffer.size() = %d\n", printf("%p QIODevice::readLine(%lld), d->pos = %lld, d->buffer.size() = %lld\n",
this, int(maxSize), int(d->pos), int(d->buffer.size())); this, maxSize, d->pos, d->buffer.size());
#else #else
Q_UNUSED(d); Q_UNUSED(d);
#endif #endif
if (maxSize > INT_MAX) { if (quint64(maxSize) >= QBYTEARRAY_MAX) {
qWarning("QIODevice::read: maxSize argument exceeds QByteArray size limit"); qWarning("QIODevice::read: maxSize argument exceeds QByteArray size limit");
maxSize = INT_MAX; maxSize = QBYTEARRAY_MAX - 1;
} }
result.resize(int(maxSize)); result.resize(int(maxSize));
@ -1180,7 +1193,7 @@ QByteArray QIODevice::readLine(qint64 maxSize)
if (!result.size()) { if (!result.size()) {
// If resize fails or maxSize == 0, read incrementally // If resize fails or maxSize == 0, read incrementally
if (maxSize == 0) if (maxSize == 0)
maxSize = INT_MAX; maxSize = QBYTEARRAY_MAX - 1;
// The first iteration needs to leave an extra byte for the terminating null // The first iteration needs to leave an extra byte for the terminating null
result.resize(1); result.resize(1);
@ -1237,8 +1250,8 @@ qint64 QIODevice::readLineData(char *data, qint64 maxSize)
} }
#if defined QIODEVICE_DEBUG #if defined QIODEVICE_DEBUG
printf("%p QIODevice::readLineData(%p, %d), d->pos = %d, d->buffer.size() = %d, returns %d\n", printf("%p QIODevice::readLineData(%p, %lld), d->pos = %lld, d->buffer.size() = %lld, "
this, data, int(maxSize), int(d->pos), int(d->buffer.size()), int(readSoFar)); "returns %lld\n", this, data, maxSize, d->pos, d->buffer.size(), readSoFar);
#endif #endif
if (lastReadReturn != 1 && readSoFar == 0) if (lastReadReturn != 1 && readSoFar == 0)
return isSequential() ? lastReadReturn : -1; return isSequential() ? lastReadReturn : -1;
@ -1381,7 +1394,8 @@ qint64 QIODevicePrivate::peek(char *data, qint64 maxSize)
return readBytes; return readBytes;
buffer.ungetBlock(data, readBytes); buffer.ungetBlock(data, readBytes);
*pPos -= readBytes; if (!isSequential())
pos -= readBytes;
return readBytes; return readBytes;
} }
@ -1396,7 +1410,8 @@ QByteArray QIODevicePrivate::peek(qint64 maxSize)
return result; return result;
buffer.ungetBlock(result.constData(), result.size()); buffer.ungetBlock(result.constData(), result.size());
*pPos -= result.size(); if (!isSequential())
pos -= result.size();
return result; return result;
} }
@ -1569,6 +1584,9 @@ QString QIODevice::errorString() const
all the requested information was read and therefore does not retry reading all the requested information was read and therefore does not retry reading
if there was a problem. if there was a problem.
This function might be called with a maxSize of 0, which can be used to
perform post-reading operations.
\sa read() readLine() writeData() \sa read() readLine() writeData()
*/ */

View file

@ -80,13 +80,13 @@ public:
first = buf; first = buf;
len = 0; len = 0;
} }
int size() const { qint64 size() const {
return len; return len;
} }
bool isEmpty() const { bool isEmpty() const {
return len == 0; return len == 0;
} }
void skip(const int n) { void skip(const qint64 n) {
if (n >= len) { if (n >= len) {
clear(); clear();
} else { } else {
@ -102,25 +102,25 @@ public:
first++; first++;
return ch; return ch;
} }
int read(char* target, const int size) { qint64 read(char* target, const qint64 size) {
const int r = qMin(size, len); const qint64 r = qMin(size, len);
memcpy(target, first, r); memcpy(target, first, r);
len -= r; len -= r;
first += r; first += r;
return r; return r;
} }
int peek(char* target, const int size) { qint64 peek(char* target, const qint64 size) {
const int r = qMin(size, len); const qint64 r = qMin(size, len);
memcpy(target, first, r); memcpy(target, first, r);
return r; return r;
} }
char* reserve(const int size) { char* reserve(const qint64 size) {
makeSpace(size + len, freeSpaceAtEnd); makeSpace(size + len, freeSpaceAtEnd);
char* writePtr = first + len; char* writePtr = first + len;
len += size; len += size;
return writePtr; return writePtr;
} }
void chop(const int size) { void chop(const qint64 size) {
if (size >= len) { if (size >= len) {
clear(); clear();
} else { } else {
@ -133,15 +133,15 @@ public:
clear(); clear();
return QByteArray(f, l); return QByteArray(f, l);
} }
int readLine(char* target, int size) { qint64 readLine(char* target, qint64 size) {
int r = qMin(size, len); qint64 r = qMin(size, len);
char* eol = static_cast<char*>(memchr(first, '\n', r)); char* eol = static_cast<char*>(memchr(first, '\n', r));
if (eol) if (eol)
r = 1+(eol-first); r = 1+(eol-first);
memcpy(target, first, r); memcpy(target, first, r);
len -= r; len -= r;
first += r; first += r;
return int(r); return r;
} }
bool canReadLine() const { bool canReadLine() const {
return memchr(first, '\n', len); return memchr(first, '\n', len);
@ -155,7 +155,7 @@ public:
len++; len++;
*first = c; *first = c;
} }
void ungetBlock(const char* block, int size) { void ungetBlock(const char* block, qint64 size) {
if ((first - buf) < size) { if ((first - buf) < size) {
// underflow, the existing valid data needs to move to the end of the (potentially bigger) buffer // underflow, the existing valid data needs to move to the end of the (potentially bigger) buffer
makeSpace(len + size, freeSpaceAtStart); makeSpace(len + size, freeSpaceAtStart);
@ -187,7 +187,7 @@ private:
} }
// length of the unread data // length of the unread data
int len; qint64 len;
// start of the unread data // start of the unread data
char* first; char* first;
// the allocated buffer // the allocated buffer
@ -213,10 +213,6 @@ public:
QIODevicePrivateLinearBuffer buffer; QIODevicePrivateLinearBuffer buffer;
qint64 pos; qint64 pos;
qint64 devicePos; qint64 devicePos;
// these three are for fast position updates during read, avoiding isSequential test
qint64 seqDumpPos;
qint64 *pPos;
qint64 *pDevicePos;
bool baseReadLineDataCalled; bool baseReadLineDataCalled;
bool firstRead; bool firstRead;

View file

@ -39,11 +39,22 @@
** **
****************************************************************************/ ****************************************************************************/
#include "qprocess.h"
#include "qprocess_p.h"
#include <qdebug.h>
#include <qstring.h>
#include <qbytearray.h>
#include <qelapsedtimer.h>
#include <qcoreapplication.h>
#include <qsocketnotifier.h>
#include <qtimer.h>
#include <qcore_unix_p.h>
//#define QPROCESS_DEBUG //#define QPROCESS_DEBUG
#if defined QPROCESS_DEBUG #if defined QPROCESS_DEBUG
#include <qdebug.h>
#include <qstring.h>
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
@ -82,17 +93,7 @@ QT_END_NAMESPACE
#endif #endif
#include "qprocess.h"
#include "qprocess_p.h"
#include <qbytearray.h>
#include <qelapsedtimer.h>
#include <qcoreapplication.h>
#include <qsocketnotifier.h>
#include <qtimer.h>
#ifndef QT_NO_PROCESS #ifndef QT_NO_PROCESS
extern char **environ; extern char **environ;
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@ -1566,8 +1567,7 @@ bool QProcess::waitForBytesWritten(int msecs)
bool started = waitForStarted(msecs); bool started = waitForStarted(msecs);
if (!started) if (!started)
return false; return false;
if (msecs != -1) msecs = qt_timeout_value(msecs, stopWatch.elapsed());
msecs -= stopWatch.elapsed();
} }
return d->waitForBytesWritten(msecs); return d->waitForBytesWritten(msecs);
@ -1603,8 +1603,7 @@ bool QProcess::waitForFinished(int msecs)
bool started = waitForStarted(msecs); bool started = waitForStarted(msecs);
if (!started) if (!started)
return false; return false;
if (msecs != -1) msecs = qt_timeout_value(msecs, stopWatch.elapsed());
msecs -= stopWatch.elapsed();
} }
return d->waitForFinished(msecs); return d->waitForFinished(msecs);
@ -1646,6 +1645,8 @@ void QProcess::setupChildProcess()
qint64 QProcess::readData(char *data, qint64 maxlen) qint64 QProcess::readData(char *data, qint64 maxlen)
{ {
Q_D(QProcess); Q_D(QProcess);
if (!maxlen)
return 0;
QRingBuffer *readBuffer = (d->processChannel == QProcess::StandardError) QRingBuffer *readBuffer = (d->processChannel == QProcess::StandardError)
? &d->errorReadBuffer ? &d->errorReadBuffer
: &d->outputReadBuffer; : &d->outputReadBuffer;

View file

@ -862,19 +862,6 @@ static int select_msecs(int nfds, fd_set *fdread, fd_set *fdwrite, int timeout)
return qt_safe_select(nfds, fdread, fdwrite, 0, &tv); return qt_safe_select(nfds, fdread, fdwrite, 0, &tv);
} }
/*
Returns the difference between msecs and elapsed. If msecs is -1,
however, -1 is returned.
*/
static int qt_timeout_value(int msecs, int elapsed)
{
if (msecs == -1)
return -1;
int timeout = msecs - elapsed;
return timeout < 0 ? 0 : timeout;
}
bool QProcessPrivate::waitForStarted(int msecs) bool QProcessPrivate::waitForStarted(int msecs)
{ {
Q_Q(QProcess); Q_Q(QProcess);

View file

@ -338,6 +338,21 @@ union qt_semun {
unsigned short *array; /* array for GETALL, SETALL */ unsigned short *array; /* array for GETALL, SETALL */
}; };
/*
Returns the difference between msecs and elapsed. If msecs is -1,
however, -1 is returned.
*/
static int qt_timeout_value(int msecs, int elapsed)
{
if (msecs == -1)
return -1;
int timeout = msecs - elapsed;
return timeout < 0 ? 0 : timeout;
}
QT_END_NAMESPACE QT_END_NAMESPACE
#endif #endif