Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qnoncontiguousbytedevice.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// Qt-Security score:significant reason:default
4
6#include <qbuffer.h>
7#include <qdebug.h>
8#include <qfile.h>
9
10#include <utility>
11
13
14/*!
15 \class QNonContiguousByteDevice
16 \inmodule QtCore
17 \brief A QNonContiguousByteDevice is a representation of a
18 file, array or buffer that allows access with a read pointer.
19 \since 4.6
20
21 The goal of this class is to have a data representation that
22 allows us to avoid doing a memcpy as we have to do with QIODevice.
23
24 \sa QNonContiguousByteDeviceFactory
25
26 \internal
27*/
28/*!
29 \fn virtual const char* QNonContiguousByteDevice::readPointer(qint64 maximumLength, qint64 &len)
30
31 Return a byte pointer for at most \a maximumLength bytes of that device.
32 if \a maximumLength is -1, the caller does not care about the length and
33 the device may return what it desires to.
34 The actual number of bytes the pointer is valid for is returned in
35 the \a len variable.
36 \a len will be -1 if EOF or an error occurs.
37 If it was really EOF can then afterwards be checked with atEnd()
38 Returns 0 if it is not possible to read at that position.
39
40 \sa atEnd()
41
42 \internal
43*/
44/*!
45 \fn virtual bool QNonContiguousByteDevice::advanceReadPointer(qint64 amount)
46
47 will advance the internal read pointer by \a amount bytes.
48 The old readPointer is invalid after this call.
49
50 \sa readPointer()
51
52 \internal
53*/
54/*!
55 \fn virtual bool QNonContiguousByteDevice::atEnd() const
56
57 Returns \c true if everything has been read and the read
58 pointer cannot be advanced anymore.
59
60 \sa readPointer(), advanceReadPointer(), reset()
61
62 \internal
63*/
64/*!
65 \fn virtual bool QNonContiguousByteDevice::reset()
66
67 Moves the internal read pointer back to the beginning.
68 Returns \c false if this was not possible.
69
70 \sa atEnd()
71
72 \internal
73*/
74/*!
75 \fn virtual qint64 QNonContiguousByteDevice::size() const
76
77 Returns the size of the complete device or -1 if unknown.
78 May also return less/more than what can be actually read with readPointer()
79
80 \internal
81*/
82/*!
83 \fn void QNonContiguousByteDevice::readyRead()
84
85 Emitted when there is data available
86
87 \internal
88*/
89/*!
90 \fn void QNonContiguousByteDevice::readProgress(qint64 current, qint64 total)
91
92 Emitted when data has been "read" by advancing the read pointer
93
94 \internal
95*/
96
97QNonContiguousByteDevice::QNonContiguousByteDevice() : QObject((QObject*)nullptr)
98{
99}
100
101QNonContiguousByteDevice::~QNonContiguousByteDevice()
102{
103}
104
105QNonContiguousByteDeviceByteArrayImpl::QNonContiguousByteDeviceByteArrayImpl(QByteArray ba)
106 : QNonContiguousByteDevice(), byteArray(std::move(ba)), view(byteArray)
107{
108}
109
116
120
121const char* QNonContiguousByteDeviceByteArrayImpl::readPointer(qint64 maximumLength, qint64 &len)
122{
123 if (atEnd()) {
124 len = -1;
125 return nullptr;
126 }
127
128 if (maximumLength != -1)
129 len = qMin(maximumLength, size() - currentPosition);
130 else
131 len = size() - currentPosition;
132
133 return view.data() + currentPosition;
134}
135
137{
138 currentPosition += amount;
139 emit readProgress(currentPosition, size());
140 return true;
141}
142
144{
145 return currentPosition >= size();
146}
147
149{
150 currentPosition = 0;
151 return true;
152}
153
155{
156 return view.size();
157}
158
160{
161 return currentPosition;
162}
163
164QNonContiguousByteDeviceRingBufferImpl::QNonContiguousByteDeviceRingBufferImpl(std::shared_ptr<QRingBuffer> rb)
165 : QNonContiguousByteDevice(), ringBuffer(std::move(rb))
166{
167}
168
172
173const char* QNonContiguousByteDeviceRingBufferImpl::readPointer(qint64 maximumLength, qint64 &len)
174{
175 if (atEnd()) {
176 len = -1;
177 return nullptr;
178 }
179
180 const char *returnValue = ringBuffer->readPointerAtPosition(currentPosition, len);
181
182 if (maximumLength != -1)
183 len = qMin(len, maximumLength);
184
185 return returnValue;
186}
187
189{
190 currentPosition += amount;
191 emit readProgress(currentPosition, size());
192 return true;
193}
194
196{
197 return currentPosition >= size();
198}
199
201{
202 return currentPosition;
203}
204
206{
207 currentPosition = 0;
208 return true;
209}
210
212{
213 return ringBuffer->size();
214}
215
216QNonContiguousByteDeviceIoDeviceImpl::QNonContiguousByteDeviceIoDeviceImpl(QIODevice *d)
217 : QNonContiguousByteDevice(),
218 device(d),
219 currentReadBuffer(nullptr),
220 currentReadBufferSize(16 * 1024),
221 currentReadBufferAmount(0),
222 currentReadBufferPosition(0),
223 totalAdvancements(0),
224 eof(false),
225 initialPosition(d->pos())
226{
227 connect(device, &QIODevice::readyRead, this,
228 &QNonContiguousByteDevice::readyRead);
229 connect(device, &QIODevice::readChannelFinished, this,
230 &QNonContiguousByteDevice::readyRead);
231}
232
237
238const char *QNonContiguousByteDeviceIoDeviceImpl::readPointer(qint64 maximumLength, qint64 &len)
239{
240 if (eof) {
241 len = -1;
242 return nullptr;
243 }
244
245 if (currentReadBuffer == nullptr)
246 currentReadBuffer = new QByteArray(currentReadBufferSize, '\0'); // lazy alloc
247
248 if (maximumLength == -1)
249 maximumLength = currentReadBufferSize;
250
251 if (currentReadBufferAmount - currentReadBufferPosition > 0) {
252 len = currentReadBufferAmount - currentReadBufferPosition;
253 return currentReadBuffer->data() + currentReadBufferPosition;
254 }
255
256 qint64 haveRead = device->read(currentReadBuffer->data(),
257 qMin(maximumLength, currentReadBufferSize));
258
259 if ((haveRead == -1) || (haveRead == 0 && device->atEnd() && !device->isSequential())) {
260 eof = true;
261 len = -1;
262 // size was unknown before, emit a readProgress with the final size
263 if (size() == -1)
264 emit readProgress(totalAdvancements, totalAdvancements);
265 return nullptr;
266 }
267
268 currentReadBufferAmount = haveRead;
269 currentReadBufferPosition = 0;
270
271 len = haveRead;
272 return currentReadBuffer->data();
273}
274
276{
277 totalAdvancements += amount;
278
279 // normal advancement
280 currentReadBufferPosition += amount;
281
282 if (size() == -1)
283 emit readProgress(totalAdvancements, totalAdvancements);
284 else
285 emit readProgress(totalAdvancements, size());
286
287 // advancing over that what has actually been read before
288 if (currentReadBufferPosition > currentReadBufferAmount) {
289 qint64 i = currentReadBufferPosition - currentReadBufferAmount;
290 while (i > 0) {
291 if (!device->getChar(nullptr)) {
292 emit readProgress(totalAdvancements - i, size());
293 return false; // ### FIXME handle eof
294 }
295 i--;
296 }
297
298 currentReadBufferPosition = 0;
299 currentReadBufferAmount = 0;
300 }
301
302 return true;
303}
304
306{
307 return eof;
308}
309
311{
312 bool reset = (initialPosition == 0) ? device->reset() : device->seek(initialPosition);
313 if (reset) {
314 eof = false; // assume eof is false, it will be true after a read has been attempted
315 totalAdvancements = 0; // reset the progress counter
316 if (currentReadBuffer) {
317 delete currentReadBuffer;
318 currentReadBuffer = nullptr;
319 }
320 currentReadBufferAmount = 0;
321 currentReadBufferPosition = 0;
322 return true;
323 }
324
325 return false;
326}
327
329{
330 // note that this is different from the size() implementation of QIODevice!
331
332 if (device->isSequential())
333 return -1;
334
335 return device->size() - initialPosition;
336}
337
339{
340 if (device->isSequential())
341 return -1;
342
343 return device->pos();
344}
345
346QByteDeviceWrappingIoDevice::QByteDeviceWrappingIoDevice(QNonContiguousByteDevice *bd)
347 : QIODevice(nullptr), byteDevice(bd)
348{
349 connect(bd, &QNonContiguousByteDevice::readyRead, this, &QIODevice::readyRead);
350
351 open(ReadOnly);
352}
353
355 = default;
356
358{
359 return (byteDevice->size() == -1);
360}
361
363{
364 return byteDevice->atEnd();
365}
366
368{
369 return byteDevice->reset();
370}
371
373{
374 if (isSequential())
375 return 0;
376
377 return byteDevice->size();
378}
379
380qint64 QByteDeviceWrappingIoDevice::readData(char *data, qint64 maxSize)
381{
382 qint64 len;
383 const char *readPointer = byteDevice->readPointer(maxSize, len);
384 if (len == -1)
385 return -1;
386
387 memcpy(data, readPointer, len);
388 byteDevice->advanceReadPointer(len);
389 return len;
390}
391
392qint64 QByteDeviceWrappingIoDevice::writeData(const char *data, qint64 maxSize)
393{
394 Q_UNUSED(data);
395 Q_UNUSED(maxSize);
396 return -1;
397}
398
399/*!
400 \class QNonContiguousByteDeviceFactory
401 \inmodule QtCore
402 \since 4.6
403
404 Creates a QNonContiguousByteDevice out of a QIODevice,
405 QByteArray etc.
406
407 \sa QNonContiguousByteDevice
408
409 \internal
410*/
411
412/*!
413 \fn static QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QIODevice *device)
414
415 Create a QNonContiguousByteDevice out of a QIODevice.
416 For QFile, QBuffer and all other QIoDevice, sequential or not.
417
418 \internal
419*/
420QNonContiguousByteDevice *QNonContiguousByteDeviceFactory::create(QIODevice *device)
421{
422 // shortcut if it is a QBuffer
423 if (QBuffer *buffer = qobject_cast<QBuffer *>(device)) {
424 return new QNonContiguousByteDeviceByteArrayImpl(buffer);
425 }
426
427 // ### FIXME special case if device is a QFile that supports map()
428 // then we can actually deal with the file without using read/peek
429
430 // generic QIODevice
431 return new QNonContiguousByteDeviceIoDeviceImpl(device); // FIXME
432}
433
434/*!
435 Create a QNonContiguousByteDevice out of a QIODevice, return it in a std::shared_ptr.
436 For QFile, QBuffer and all other QIODevice, sequential or not.
437
438 \internal
439*/
440std::shared_ptr<QNonContiguousByteDevice> QNonContiguousByteDeviceFactory::createShared(QIODevice *device)
441{
442 // shortcut if it is a QBuffer
443 if (QBuffer *buffer = qobject_cast<QBuffer*>(device))
444 return std::make_shared<QNonContiguousByteDeviceByteArrayImpl>(buffer);
445
446 // ### FIXME special case if device is a QFile that supports map()
447 // then we can actually deal with the file without using read/peek
448
449 // generic QIODevice
450 return std::make_shared<QNonContiguousByteDeviceIoDeviceImpl>(device); // FIXME
451}
452
453/*!
454 \fn static QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(std::shared_ptr<QRingBuffer> ringBuffer)
455
456 Create a QNonContiguousByteDevice out of a QRingBuffer.
457
458 \internal
459*/
460QNonContiguousByteDevice *
461QNonContiguousByteDeviceFactory::create(std::shared_ptr<QRingBuffer> ringBuffer)
462{
463 return new QNonContiguousByteDeviceRingBufferImpl(std::move(ringBuffer));
464}
465
466/*!
467 Create a QNonContiguousByteDevice out of a QRingBuffer, return it in a std::shared_ptr.
468
469 \internal
470*/
471std::shared_ptr<QNonContiguousByteDevice>
472QNonContiguousByteDeviceFactory::createShared(std::shared_ptr<QRingBuffer> ringBuffer)
473{
474 return std::make_shared<QNonContiguousByteDeviceRingBufferImpl>(std::move(ringBuffer));
475}
476
477/*!
478 \fn static QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QByteArray *byteArray)
479
480 Create a QNonContiguousByteDevice out of a QByteArray.
481
482 \internal
483*/
484QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(const QByteArray &byteArray)
485{
486 return new QNonContiguousByteDeviceByteArrayImpl(byteArray);
487}
488
489/*!
490 Create a QNonContiguousByteDevice out of a QByteArray.
491
492 \internal
493*/
494std::shared_ptr<QNonContiguousByteDevice>
495QNonContiguousByteDeviceFactory::createShared(const QByteArray &byteArray)
496{
497 return std::make_shared<QNonContiguousByteDeviceByteArrayImpl>(byteArray);
498}
499
500/*!
501 \fn static QIODevice* QNonContiguousByteDeviceFactory::wrap(QNonContiguousByteDevice* byteDevice)
502
503 Wrap the \a byteDevice (possibly again) into a QIODevice.
504
505 \internal
506*/
507QIODevice *QNonContiguousByteDeviceFactory::wrap(QNonContiguousByteDevice *byteDevice)
508{
509 // ### FIXME if it already has been based on QIoDevice, we could that one out again
510 // and save some calling
511
512 // needed for FTP backend
513
514 return new QByteDeviceWrappingIoDevice(byteDevice);
515}
516
517QT_END_NAMESPACE
518
519#include "moc_qnoncontiguousbytedevice_p.cpp"
qint64 readData(char *data, qint64 maxSize) override
Reads up to maxSize bytes from the device into data, and returns the number of bytes read or -1 if an...
qint64 size() const override
For open random-access devices, this function returns the size of the device.
bool isSequential() const override
Returns true if this device is sequential; otherwise returns false.
bool atEnd() const override
Returns true if the current read and write position is at the end of the device (i....
bool reset() override
Seeks to the start of input for random-access devices.
qint64 writeData(const char *data, qint64 maxSize) override
Writes up to maxSize bytes from data to the device.
bool reset() override
Moves the internal read pointer back to the beginning.
qint64 size() const override
Returns the size of the complete device or -1 if unknown.
bool advanceReadPointer(qint64 amount) override
will advance the internal read pointer by amount bytes.
const char * readPointer(qint64 maximumLength, qint64 &len) override
Return a byte pointer for at most maximumLength bytes of that device.
bool atEnd() const override
Returns true if everything has been read and the read pointer cannot be advanced anymore.
bool atEnd() const override
Returns true if everything has been read and the read pointer cannot be advanced anymore.
qint64 size() const override
Returns the size of the complete device or -1 if unknown.
bool advanceReadPointer(qint64 amount) override
will advance the internal read pointer by amount bytes.
bool reset() override
Moves the internal read pointer back to the beginning.
const char * readPointer(qint64 maximumLength, qint64 &len) override
Return a byte pointer for at most maximumLength bytes of that device.
qint64 size() const override
Returns the size of the complete device or -1 if unknown.
bool atEnd() const override
Returns true if everything has been read and the read pointer cannot be advanced anymore.
bool advanceReadPointer(qint64 amount) override
will advance the internal read pointer by amount bytes.
bool reset() override
Moves the internal read pointer back to the beginning.
const char * readPointer(qint64 maximumLength, qint64 &len) override
Return a byte pointer for at most maximumLength bytes of that device.