|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the QtCore module of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
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 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
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 |
|
47 QT_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 |
|
143 QNonContiguousByteDevice::QNonContiguousByteDevice() : QObject((QObject*)0), resetDisabled(false) |
|
144 { |
|
145 } |
|
146 |
|
147 QNonContiguousByteDevice::~QNonContiguousByteDevice() |
|
148 { |
|
149 } |
|
150 |
|
151 void QNonContiguousByteDevice::disableReset() |
|
152 { |
|
153 resetDisabled = true; |
|
154 } |
|
155 |
|
156 QNonContiguousByteDeviceBufferImpl::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 |
|
166 QNonContiguousByteDeviceBufferImpl::~QNonContiguousByteDeviceBufferImpl() |
|
167 { |
|
168 } |
|
169 |
|
170 const char* QNonContiguousByteDeviceBufferImpl::readPointer(qint64 maximumLength, qint64 &len) |
|
171 { |
|
172 return arrayImpl->readPointer(maximumLength, len); |
|
173 } |
|
174 |
|
175 bool QNonContiguousByteDeviceBufferImpl::advanceReadPointer(qint64 amount) |
|
176 { |
|
177 return arrayImpl->advanceReadPointer(amount); |
|
178 } |
|
179 |
|
180 bool QNonContiguousByteDeviceBufferImpl::atEnd() |
|
181 { |
|
182 return arrayImpl->atEnd(); |
|
183 } |
|
184 |
|
185 bool QNonContiguousByteDeviceBufferImpl::reset() |
|
186 { |
|
187 if (resetDisabled) |
|
188 return false; |
|
189 return arrayImpl->reset(); |
|
190 } |
|
191 |
|
192 qint64 QNonContiguousByteDeviceBufferImpl::size() |
|
193 { |
|
194 return arrayImpl->size(); |
|
195 } |
|
196 |
|
197 QNonContiguousByteDeviceByteArrayImpl::QNonContiguousByteDeviceByteArrayImpl(QByteArray *ba) : QNonContiguousByteDevice(), currentPosition(0) |
|
198 { |
|
199 byteArray = ba; |
|
200 } |
|
201 |
|
202 QNonContiguousByteDeviceByteArrayImpl::~QNonContiguousByteDeviceByteArrayImpl() |
|
203 { |
|
204 } |
|
205 |
|
206 const 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 |
|
221 bool QNonContiguousByteDeviceByteArrayImpl::advanceReadPointer(qint64 amount) |
|
222 { |
|
223 currentPosition += amount; |
|
224 emit readProgress(currentPosition, size()); |
|
225 return true; |
|
226 } |
|
227 |
|
228 bool QNonContiguousByteDeviceByteArrayImpl::atEnd() |
|
229 { |
|
230 return currentPosition >= size(); |
|
231 } |
|
232 |
|
233 bool QNonContiguousByteDeviceByteArrayImpl::reset() |
|
234 { |
|
235 if (resetDisabled) |
|
236 return false; |
|
237 |
|
238 currentPosition = 0; |
|
239 return true; |
|
240 } |
|
241 |
|
242 qint64 QNonContiguousByteDeviceByteArrayImpl::size() |
|
243 { |
|
244 return byteArray->size(); |
|
245 } |
|
246 |
|
247 QNonContiguousByteDeviceRingBufferImpl::QNonContiguousByteDeviceRingBufferImpl(QRingBuffer *rb) |
|
248 : QNonContiguousByteDevice(), currentPosition(0) |
|
249 { |
|
250 ringBuffer = rb; |
|
251 } |
|
252 |
|
253 QNonContiguousByteDeviceRingBufferImpl::~QNonContiguousByteDeviceRingBufferImpl() |
|
254 { |
|
255 } |
|
256 |
|
257 const 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 |
|
272 bool QNonContiguousByteDeviceRingBufferImpl::advanceReadPointer(qint64 amount) |
|
273 { |
|
274 currentPosition += amount; |
|
275 emit readProgress(currentPosition, size()); |
|
276 return true; |
|
277 } |
|
278 |
|
279 bool QNonContiguousByteDeviceRingBufferImpl::atEnd() |
|
280 { |
|
281 return currentPosition >= size(); |
|
282 } |
|
283 |
|
284 bool QNonContiguousByteDeviceRingBufferImpl::reset() |
|
285 { |
|
286 if (resetDisabled) |
|
287 return false; |
|
288 |
|
289 currentPosition = 0; |
|
290 return true; |
|
291 } |
|
292 |
|
293 qint64 QNonContiguousByteDeviceRingBufferImpl::size() |
|
294 { |
|
295 return ringBuffer->size(); |
|
296 } |
|
297 |
|
298 QNonContiguousByteDeviceIoDeviceImpl::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 |
|
310 QNonContiguousByteDeviceIoDeviceImpl::~QNonContiguousByteDeviceIoDeviceImpl() |
|
311 { |
|
312 delete currentReadBuffer; |
|
313 } |
|
314 |
|
315 const 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 |
|
351 bool 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 |
|
381 bool QNonContiguousByteDeviceIoDeviceImpl::atEnd() |
|
382 { |
|
383 return eof == true; |
|
384 } |
|
385 |
|
386 bool 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 |
|
399 qint64 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 |
|
409 QByteDeviceWrappingIoDevice::QByteDeviceWrappingIoDevice(QNonContiguousByteDevice *bd) : QIODevice((QObject*)0) |
|
410 { |
|
411 byteDevice = bd; |
|
412 connect(bd, SIGNAL(readyRead()), SIGNAL(readyRead())); |
|
413 |
|
414 open(ReadOnly); |
|
415 } |
|
416 |
|
417 QByteDeviceWrappingIoDevice::~QByteDeviceWrappingIoDevice() |
|
418 { |
|
419 |
|
420 } |
|
421 |
|
422 bool QByteDeviceWrappingIoDevice::isSequential() const |
|
423 { |
|
424 return (byteDevice->size() == -1); |
|
425 } |
|
426 |
|
427 bool QByteDeviceWrappingIoDevice::atEnd() const |
|
428 { |
|
429 return byteDevice->atEnd(); |
|
430 } |
|
431 |
|
432 bool QByteDeviceWrappingIoDevice::reset() |
|
433 { |
|
434 return byteDevice->reset(); |
|
435 } |
|
436 |
|
437 qint64 QByteDeviceWrappingIoDevice::size() const |
|
438 { |
|
439 if (isSequential()) |
|
440 return 0; |
|
441 |
|
442 return byteDevice->size(); |
|
443 } |
|
444 |
|
445 |
|
446 qint64 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 |
|
458 qint64 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 */ |
|
487 QNonContiguousByteDevice* 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 */ |
|
508 QNonContiguousByteDevice* 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 */ |
|
520 QNonContiguousByteDevice* 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 */ |
|
532 QIODevice* 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 |
|
542 QT_END_NAMESPACE |
|
543 |