QIODevice: fix interleaving read() and write() in text mode under Windows

Skip the correct number of bytes in the read buffer when expanding '\n'
into "\r\n" upon writing.

Change-Id: I5b01fc47c330dee5c83001abf0acd7d63d790b96
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com>
This commit is contained in:
Alex Trotsenko 2015-09-11 12:15:03 +03:00
parent 33486e0ae7
commit 1e32ade79c
2 changed files with 45 additions and 3 deletions

View File

@ -1289,6 +1289,7 @@ qint64 QIODevice::write(const char *data, qint64 maxSize)
const char *startOfBlock = data;
qint64 writtenSoFar = 0;
const qint64 savedPos = d->pos;
forever {
const char *endOfBlock = startOfBlock;
@ -1300,7 +1301,7 @@ qint64 QIODevice::write(const char *data, qint64 maxSize)
qint64 ret = writeData(startOfBlock, blockSize);
if (ret <= 0) {
if (writtenSoFar && !sequential)
d->buffer.skip(writtenSoFar);
d->buffer.skip(d->pos - savedPos);
return writtenSoFar ? writtenSoFar : ret;
}
if (!sequential) {
@ -1316,7 +1317,7 @@ qint64 QIODevice::write(const char *data, qint64 maxSize)
qint64 ret = writeData("\r\n", 2);
if (ret <= 0) {
if (writtenSoFar && !sequential)
d->buffer.skip(writtenSoFar);
d->buffer.skip(d->pos - savedPos);
return writtenSoFar ? writtenSoFar : ret;
}
if (!sequential) {
@ -1329,7 +1330,7 @@ qint64 QIODevice::write(const char *data, qint64 maxSize)
}
if (writtenSoFar && !sequential)
d->buffer.skip(writtenSoFar);
d->buffer.skip(d->pos - savedPos);
return writtenSoFar;
}
#endif

View File

@ -59,6 +59,7 @@ private slots:
void peekBug();
void readAllKeepPosition();
void writeInTextMode();
};
void tst_QIODevice::initTestCase()
@ -628,5 +629,45 @@ void tst_QIODevice::readAllKeepPosition()
QCOMPARE(resultArray, buffer.buffer());
}
class RandomAccessBuffer : public QIODevice
{
public:
RandomAccessBuffer(const char *data) : QIODevice(), buf(data) { }
protected:
qint64 readData(char *data, qint64 maxSize) Q_DECL_OVERRIDE
{
maxSize = qMin(maxSize, qint64(buf.size() - pos()));
memcpy(data, buf.constData() + pos(), maxSize);
return maxSize;
}
qint64 writeData(const char *data, qint64 maxSize) Q_DECL_OVERRIDE
{
maxSize = qMin(maxSize, qint64(buf.size() - pos()));
memcpy(buf.data() + pos(), data, maxSize);
return maxSize;
}
private:
QByteArray buf;
};
// Test write() on skipping correct number of bytes in read buffer
void tst_QIODevice::writeInTextMode()
{
// Unlike other platforms, Windows implementation expands '\n' into
// "\r\n" sequence in write(). Ensure that write() properly works with
// a read buffer on random-access devices.
#ifndef Q_OS_WIN
QSKIP("This is a Windows-only test");
#else
RandomAccessBuffer buffer("one\r\ntwo\r\nthree\r\n");
buffer.open(QBuffer::ReadWrite | QBuffer::Text);
QCOMPARE(buffer.readLine(), QByteArray("one\n"));
QCOMPARE(buffer.write("two\n"), 4);
QCOMPARE(buffer.readLine(), QByteArray("three\n"));
#endif
}
QTEST_MAIN(tst_QIODevice)
#include "tst_qiodevice.moc"