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