source: trunk/src/corelib/io/qnoncontiguousbytedevice.cpp@ 780

Last change on this file since 780 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

  • Property svn:eol-style set to native
File size: 14.3 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtCore module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qnoncontiguousbytedevice_p.h"
43#include <qbuffer.h>
44#include <qdebug.h>
45#include <qfile.h>
46
47QT_BEGIN_NAMESPACE
48
49/*!
50 \class QNonContiguousByteDevice
51 \brief A QNonContiguousByteDevice is a representation of a
52 file, array or buffer that allows access with a read pointer.
53 \since 4.6
54
55 \inmodule QtCore
56
57 The goal of this class is to have a data representation that
58 allows us to avoid doing a memcpy as we have to do with QIODevice.
59
60 \sa QNonContiguousByteDeviceFactory
61
62 \internal
63*/
64/*!
65 \fn virtual const char* QNonContiguousByteDevice::readPointer(qint64 maximumLength, qint64 &len)
66
67 Return a byte pointer for at most \a maximumLength bytes of that device.
68 if \a maximumLength is -1, the caller does not care about the length and
69 the device may return what it desires to.
70 The actual number of bytes the pointer is valid for is returned in
71 the \a len variable.
72 \a len will be -1 if EOF or an error occurs.
73 If it was really EOF can then afterwards be checked with atEnd()
74 Returns 0 if it is not possible to read at that position.
75
76 \sa atEnd()
77
78 \internal
79*/
80/*!
81 \fn virtual bool QNonContiguousByteDevice::advanceReadPointer(qint64 amount)
82
83 will advance the internal read pointer by \a amount bytes.
84 The old readPointer is invalid after this call.
85
86 \sa readPointer()
87
88 \internal
89*/
90/*!
91 \fn virtual bool QNonContiguousByteDevice::atEnd()
92
93 Returns true if everything has been read and the read
94 pointer cannot be advanced anymore.
95
96 \sa readPointer(), advanceReadPointer(), reset()
97
98 \internal
99*/
100/*!
101 \fn virtual bool QNonContiguousByteDevice::reset()
102
103 Moves the internal read pointer back to the beginning.
104 Returns false if this was not possible.
105
106 \sa atEnd(), disableReset()
107
108 \internal
109*/
110/*!
111 \fn void QNonContiguousByteDevice::disableReset()
112
113 Disable the reset() call, e.g. it will always
114 do nothing and return false.
115
116 \sa reset()
117
118 \internal
119*/
120/*!
121 \fn virtual qint64 QNonContiguousByteDevice::size()
122
123 Returns the size of the complete device or -1 if unknown.
124 May also return less/more than what can be actually read with readPointer()
125
126 \internal
127*/
128/*!
129 \fn void QNonContiguousByteDevice::readyRead()
130
131 Emitted when there is data available
132
133 \internal
134*/
135/*!
136 \fn void QNonContiguousByteDevice::readProgress(qint64 current, qint64 total)
137
138 Emitted when data has been "read" by advancing the read pointer
139
140 \internal
141*/
142
143QNonContiguousByteDevice::QNonContiguousByteDevice() : QObject((QObject*)0), resetDisabled(false)
144{
145}
146
147QNonContiguousByteDevice::~QNonContiguousByteDevice()
148{
149}
150
151void QNonContiguousByteDevice::disableReset()
152{
153 resetDisabled = true;
154}
155
156QNonContiguousByteDeviceBufferImpl::QNonContiguousByteDeviceBufferImpl(QBuffer *b) : QNonContiguousByteDevice()
157{
158 buffer = b;
159 byteArray = QByteArray::fromRawData(buffer->buffer().constData() + buffer->pos(), buffer->size() - buffer->pos());
160 arrayImpl = new QNonContiguousByteDeviceByteArrayImpl(&byteArray);
161 arrayImpl->setParent(this);
162 connect(arrayImpl, SIGNAL(readyRead()), SIGNAL(readyRead()));
163 connect(arrayImpl, SIGNAL(readProgress(qint64,qint64)), SIGNAL(readProgress(qint64,qint64)));
164}
165
166QNonContiguousByteDeviceBufferImpl::~QNonContiguousByteDeviceBufferImpl()
167{
168}
169
170const char* QNonContiguousByteDeviceBufferImpl::readPointer(qint64 maximumLength, qint64 &len)
171{
172 return arrayImpl->readPointer(maximumLength, len);
173}
174
175bool QNonContiguousByteDeviceBufferImpl::advanceReadPointer(qint64 amount)
176{
177 return arrayImpl->advanceReadPointer(amount);
178}
179
180bool QNonContiguousByteDeviceBufferImpl::atEnd()
181{
182 return arrayImpl->atEnd();
183}
184
185bool QNonContiguousByteDeviceBufferImpl::reset()
186{
187 if (resetDisabled)
188 return false;
189 return arrayImpl->reset();
190}
191
192qint64 QNonContiguousByteDeviceBufferImpl::size()
193{
194 return arrayImpl->size();
195}
196
197QNonContiguousByteDeviceByteArrayImpl::QNonContiguousByteDeviceByteArrayImpl(QByteArray *ba) : QNonContiguousByteDevice(), currentPosition(0)
198{
199 byteArray = ba;
200}
201
202QNonContiguousByteDeviceByteArrayImpl::~QNonContiguousByteDeviceByteArrayImpl()
203{
204}
205
206const char* QNonContiguousByteDeviceByteArrayImpl::readPointer(qint64 maximumLength, qint64 &len)
207{
208 if (atEnd()) {
209 len = -1;
210 return 0;
211 }
212
213 if (maximumLength != -1)
214 len = qMin(maximumLength, size() - currentPosition);
215 else
216 len = size() - currentPosition;
217
218 return byteArray->constData() + currentPosition;
219}
220
221bool QNonContiguousByteDeviceByteArrayImpl::advanceReadPointer(qint64 amount)
222{
223 currentPosition += amount;
224 emit readProgress(currentPosition, size());
225 return true;
226}
227
228bool QNonContiguousByteDeviceByteArrayImpl::atEnd()
229{
230 return currentPosition >= size();
231}
232
233bool QNonContiguousByteDeviceByteArrayImpl::reset()
234{
235 if (resetDisabled)
236 return false;
237
238 currentPosition = 0;
239 return true;
240}
241
242qint64 QNonContiguousByteDeviceByteArrayImpl::size()
243{
244 return byteArray->size();
245}
246
247QNonContiguousByteDeviceRingBufferImpl::QNonContiguousByteDeviceRingBufferImpl(QRingBuffer *rb)
248 : QNonContiguousByteDevice(), currentPosition(0)
249{
250 ringBuffer = rb;
251}
252
253QNonContiguousByteDeviceRingBufferImpl::~QNonContiguousByteDeviceRingBufferImpl()
254{
255}
256
257const char* QNonContiguousByteDeviceRingBufferImpl::readPointer(qint64 maximumLength, qint64 &len)
258{
259 if (atEnd()) {
260 len = -1;
261 return 0;
262 }
263
264 const char *returnValue = ringBuffer->readPointerAtPosition(currentPosition, len);
265
266 if (maximumLength != -1)
267 len = qMin(len, maximumLength);
268
269 return returnValue;
270}
271
272bool QNonContiguousByteDeviceRingBufferImpl::advanceReadPointer(qint64 amount)
273{
274 currentPosition += amount;
275 emit readProgress(currentPosition, size());
276 return true;
277}
278
279bool QNonContiguousByteDeviceRingBufferImpl::atEnd()
280{
281 return currentPosition >= size();
282}
283
284bool QNonContiguousByteDeviceRingBufferImpl::reset()
285{
286 if (resetDisabled)
287 return false;
288
289 currentPosition = 0;
290 return true;
291}
292
293qint64 QNonContiguousByteDeviceRingBufferImpl::size()
294{
295 return ringBuffer->size();
296}
297
298QNonContiguousByteDeviceIoDeviceImpl::QNonContiguousByteDeviceIoDeviceImpl(QIODevice *d)
299 : QNonContiguousByteDevice(),
300 currentReadBuffer(0), currentReadBufferSize(16*1024),
301 currentReadBufferAmount(0), currentReadBufferPosition(0), totalAdvancements(0),
302 eof(false)
303{
304 device = d;
305 initialPosition = d->pos();
306 connect(device, SIGNAL(readyRead()), this, SIGNAL(readyRead()), Qt::QueuedConnection);
307 connect(device, SIGNAL(readChannelFinished()), this, SIGNAL(readyRead()), Qt::QueuedConnection);
308}
309
310QNonContiguousByteDeviceIoDeviceImpl::~QNonContiguousByteDeviceIoDeviceImpl()
311{
312 delete currentReadBuffer;
313}
314
315const char* QNonContiguousByteDeviceIoDeviceImpl::readPointer(qint64 maximumLength, qint64 &len)
316{
317 if (eof == true) {
318 len = -1;
319 return 0;
320 }
321
322 if (currentReadBuffer == 0)
323 currentReadBuffer = new QByteArray(currentReadBufferSize, '\0'); // lazy alloc
324
325 if (maximumLength == -1)
326 maximumLength = currentReadBufferSize;
327
328 if (currentReadBufferAmount - currentReadBufferPosition > 0) {
329 len = currentReadBufferAmount - currentReadBufferPosition;
330 return currentReadBuffer->data() + currentReadBufferPosition;
331 }
332
333 qint64 haveRead = device->read(currentReadBuffer->data(), qMin(maximumLength, currentReadBufferSize));
334
335 if ((haveRead == -1) || (haveRead == 0 && device->atEnd() && !device->isSequential())) {
336 eof = true;
337 len = -1;
338 // size was unknown before, emit a readProgress with the final size
339 if (size() == -1)
340 emit readProgress(totalAdvancements, totalAdvancements);
341 return 0;
342 }
343
344 currentReadBufferAmount = haveRead;
345 currentReadBufferPosition = 0;
346
347 len = haveRead;
348 return currentReadBuffer->data();
349}
350
351bool QNonContiguousByteDeviceIoDeviceImpl::advanceReadPointer(qint64 amount)
352{
353 totalAdvancements += amount;
354
355 // normal advancement
356 currentReadBufferPosition += amount;
357
358 // advancing over that what has actually been read before
359 if (currentReadBufferPosition > currentReadBufferAmount) {
360 qint64 i = currentReadBufferPosition - currentReadBufferAmount;
361 while (i > 0) {
362 if (device->getChar(0) == false) {
363 emit readProgress(totalAdvancements - i, size());
364 return false; // ### FIXME handle eof
365 }
366 i--;
367 }
368
369 currentReadBufferPosition = 0;
370 currentReadBufferAmount = 0;
371 }
372
373 if (size() == -1)
374 emit readProgress(totalAdvancements, totalAdvancements);
375 else
376 emit readProgress(totalAdvancements, size());
377
378 return true;
379}
380
381bool QNonContiguousByteDeviceIoDeviceImpl::atEnd()
382{
383 return eof == true;
384}
385
386bool QNonContiguousByteDeviceIoDeviceImpl::reset()
387{
388 if (resetDisabled)
389 return false;
390
391 if (device->seek(initialPosition)) {
392 eof = false; // assume eof is false, it will be true after a read has been attempted
393 return true;
394 }
395
396 return false;
397}
398
399qint64 QNonContiguousByteDeviceIoDeviceImpl::size()
400{
401 // note that this is different from the size() implementation of QIODevice!
402
403 if (device->isSequential())
404 return -1;
405
406 return device->size() - initialPosition;
407}
408
409QByteDeviceWrappingIoDevice::QByteDeviceWrappingIoDevice(QNonContiguousByteDevice *bd) : QIODevice((QObject*)0)
410{
411 byteDevice = bd;
412 connect(bd, SIGNAL(readyRead()), SIGNAL(readyRead()));
413
414 open(ReadOnly);
415}
416
417QByteDeviceWrappingIoDevice::~QByteDeviceWrappingIoDevice()
418{
419
420}
421
422bool QByteDeviceWrappingIoDevice::isSequential() const
423{
424 return (byteDevice->size() == -1);
425}
426
427bool QByteDeviceWrappingIoDevice::atEnd() const
428{
429 return byteDevice->atEnd();
430}
431
432bool QByteDeviceWrappingIoDevice::reset()
433{
434 return byteDevice->reset();
435}
436
437qint64 QByteDeviceWrappingIoDevice::size() const
438{
439 if (isSequential())
440 return 0;
441
442 return byteDevice->size();
443}
444
445
446qint64 QByteDeviceWrappingIoDevice::readData( char * data, qint64 maxSize)
447{
448 qint64 len;
449 const char *readPointer = byteDevice->readPointer(maxSize, len);
450 if (len == -1)
451 return -1;
452
453 memcpy(data, readPointer, len);
454 byteDevice->advanceReadPointer(len);
455 return len;
456}
457
458qint64 QByteDeviceWrappingIoDevice::writeData( const char* data, qint64 maxSize)
459{
460 Q_UNUSED(data);
461 Q_UNUSED(maxSize);
462 return -1;
463}
464
465/*!
466 \class QNonContiguousByteDeviceFactory
467 \since 4.6
468
469 \inmodule QtCore
470
471 Creates a QNonContiguousByteDevice out of a QIODevice,
472 QByteArray etc.
473
474 \sa QNonContiguousByteDevice
475
476 \internal
477*/
478
479/*!
480 \fn static QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QIODevice *device);
481
482 Create a QNonContiguousByteDevice out of a QIODevice.
483 For QFile, QBuffer and all other QIoDevice, sequential or not.
484
485 \internal
486*/
487QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QIODevice *device)
488{
489 // shortcut if it is a QBuffer
490 if (QBuffer* buffer = qobject_cast<QBuffer*>(device)) {
491 return new QNonContiguousByteDeviceBufferImpl(buffer);
492 }
493
494 // ### FIXME special case if device is a QFile that supports map()
495 // then we can actually deal with the file without using read/peek
496
497 // generic QIODevice
498 return new QNonContiguousByteDeviceIoDeviceImpl(device); // FIXME
499}
500
501/*!
502 \fn static QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QRingBuffer *ringBuffer);
503
504 Create a QNonContiguousByteDevice out of a QRingBuffer.
505
506 \internal
507*/
508QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QRingBuffer *ringBuffer)
509{
510 return new QNonContiguousByteDeviceRingBufferImpl(ringBuffer);
511}
512
513/*!
514 \fn static QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QByteArray *byteArray);
515
516 Create a QNonContiguousByteDevice out of a QByteArray.
517
518 \internal
519*/
520QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QByteArray *byteArray)
521{
522 return new QNonContiguousByteDeviceByteArrayImpl(byteArray);
523}
524
525/*!
526 \fn static QIODevice* QNonContiguousByteDeviceFactory::wrap(QNonContiguousByteDevice* byteDevice);
527
528 Wrap the \a byteDevice (possibly again) into a QIODevice.
529
530 \internal
531*/
532QIODevice* QNonContiguousByteDeviceFactory::wrap(QNonContiguousByteDevice* byteDevice)
533{
534 // ### FIXME if it already has been based on QIoDevice, we could that one out again
535 // and save some calling
536
537 // needed for FTP backend
538
539 return new QByteDeviceWrappingIoDevice(byteDevice);
540}
541
542QT_END_NAMESPACE
543
Note: See TracBrowser for help on using the repository browser.