Skip to content

Commit

Permalink
Clean up the loading
Browse files Browse the repository at this point in the history
Unify the load API and implementation to always go through FPDFAvail.
  • Loading branch information
Simon Hausmann committed Dec 15, 2014
1 parent 86b7ed4 commit c5c391e
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 62 deletions.
111 changes: 62 additions & 49 deletions src/pdf/qpdfdocument.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ void QPdfDocumentPrivate::clear()
asyncBuffer.close();
asyncBuffer.setData(QByteArray());
asyncBuffer.open(QIODevice::ReadWrite);

if (sequentialSourceDevice)
sequentialSourceDevice->disconnect(q);
}

void QPdfDocumentPrivate::updateLastError()
Expand All @@ -81,65 +84,77 @@ void QPdfDocumentPrivate::updateLastError()
}
}

QPdfDocument::Error QPdfDocumentPrivate::load(QIODevice *newDevice, bool transferDeviceOwnership, const QString &documentPassword)
void QPdfDocumentPrivate::load(QIODevice *newDevice, bool transferDeviceOwnership)
{
clear();

if (transferDeviceOwnership)
ownDevice.reset(newDevice);
else
ownDevice.reset();
device = newDevice;

if (!device->isOpen() && !device->open(QIODevice::ReadOnly))
return QPdfDocument::FileNotFoundError;

// FPDF_FILEACCESS setup
m_FileLen = device->size();

password = documentPassword.toUtf8();

doc = FPDF_LoadCustomDocument(this, password.constData());
updateLastError();
return lastError;
if (newDevice->isSequential()) {
sequentialSourceDevice = newDevice;
device = &asyncBuffer;
QNetworkReply *reply = qobject_cast<QNetworkReply*>(sequentialSourceDevice);
if (!reply) {
qWarning() << "QPdfDocument: Loading from sequential devices only supported with QNetworkAccessManager.";
return;
}

if (reply->header(QNetworkRequest::ContentLengthHeader).isValid())
_q_tryLoadingWithSizeFromContentHeader();
else
QObject::connect(reply, SIGNAL(metaDataChanged()), q, SLOT(_q_tryLoadingWithSizeFromContentHeader()));
} else {
device = newDevice;
initiateAsyncLoadWithTotalSizeKnown(device->size());
checkComplete();
}
}

void QPdfDocumentPrivate::_q_initiateAsyncLoad()
void QPdfDocumentPrivate::_q_tryLoadingWithSizeFromContentHeader()
{
QMutexLocker lock(pdfMutex());
if (avail)
return;

QVariant contentLength = remoteDevice->header(QNetworkRequest::ContentLengthHeader);
QNetworkReply *networkReply = qobject_cast<QNetworkReply*>(sequentialSourceDevice);
if(!networkReply)
return;

QVariant contentLength = networkReply->header(QNetworkRequest::ContentLengthHeader);
if (!contentLength.isValid())
return;

// FPDF_FILEACCESS setup
m_FileLen = contentLength.toULongLong();
QObject::connect(sequentialSourceDevice, SIGNAL(readyRead()), q, SLOT(_q_copyFromSequentialSourceDevice()));

QObject::connect(remoteDevice, SIGNAL(readyRead()), q, SLOT(_q_readFromDevice()));
initiateAsyncLoadWithTotalSizeKnown(contentLength.toULongLong());

avail = FPDFAvail_Create(this, this);
if (sequentialSourceDevice->bytesAvailable())
_q_copyFromSequentialSourceDevice();
}

if (remoteDevice->bytesAvailable())
_q_readFromDevice();
void QPdfDocumentPrivate::initiateAsyncLoadWithTotalSizeKnown(quint64 totalSize)
{
// FPDF_FILEACCESS setup
m_FileLen = totalSize;

avail = FPDFAvail_Create(this, this);
}

void QPdfDocumentPrivate::_q_readFromDevice()
void QPdfDocumentPrivate::_q_copyFromSequentialSourceDevice()
{
QMutexLocker lock(pdfMutex());
if (loadComplete)
return;
QByteArray data = remoteDevice->read(remoteDevice->bytesAvailable());
QByteArray data = sequentialSourceDevice->read(sequentialSourceDevice->bytesAvailable());
if (data.isEmpty())
return;
asyncBuffer.seek(asyncBuffer.size());
asyncBuffer.write(data);

if (!doc)
tryLoadDocument();
if (doc)
checkComplete();
checkComplete();
}

void QPdfDocumentPrivate::tryLoadDocument()
Expand All @@ -161,7 +176,13 @@ void QPdfDocumentPrivate::tryLoadDocument()
void QPdfDocumentPrivate::checkComplete()
{
QMutexLocker lock(pdfMutex());
if (!doc || !avail)
if (!avail || loadComplete)
return;

if (!doc)
tryLoadDocument();

if (!doc)
return;

loadComplete = true;
Expand All @@ -175,7 +196,7 @@ void QPdfDocumentPrivate::checkComplete()
bool QPdfDocumentPrivate::fpdf_IsDataAvail(_FX_FILEAVAIL *pThis, size_t offset, size_t size)
{
QPdfDocumentPrivate *d = static_cast<QPdfDocumentPrivate*>(pThis);
return offset + size <= static_cast<quint64>(d->asyncBuffer.size());
return offset + size <= static_cast<quint64>(d->device->size());
}

int QPdfDocumentPrivate::fpdf_GetBlock(void *param, unsigned long position, unsigned char *pBuf, unsigned long size)
Expand Down Expand Up @@ -204,35 +225,27 @@ QPdfDocument::~QPdfDocument()
{
}

QPdfDocument::Error QPdfDocument::load(const QString &fileName, const QString &password)
QPdfDocument::Error QPdfDocument::load(const QString &fileName)
{
QMutexLocker lock(pdfMutex());
return d->load(new QFile(fileName), /*transfer ownership*/true, password);
QScopedPointer<QFile> f(new QFile(fileName));
if (!f->open(QIODevice::ReadOnly)) {
d->lastError = FileNotFoundError;
} else {
d->load(f.take(), /*transfer ownership*/true);
}
return d->lastError;
}

QPdfDocument::Error QPdfDocument::load(QIODevice *device, const QString &password)
bool QPdfDocument::isLoading() const
{
QMutexLocker lock(pdfMutex());
return d->load(device, /*transfer ownership*/false, password);
return !d->loadComplete;
}

void QPdfDocument::loadAsynchronously(QNetworkReply *device)
void QPdfDocument::load(QIODevice *device)
{
QMutexLocker lock(pdfMutex());
d->clear();

d->ownDevice.reset();
d->device = &d->asyncBuffer;

if (d->remoteDevice)
d->remoteDevice->disconnect(this);

d->remoteDevice = device;

if (d->remoteDevice->header(QNetworkRequest::ContentLengthHeader).isValid())
d->_q_initiateAsyncLoad();
else
connect(d->remoteDevice, SIGNAL(metaDataChanged()), this, SLOT(_q_initiateAsyncLoad()));
d->load(device, /*transfer ownership*/false);
}

void QPdfDocument::setPassword(const QString &password)
Expand Down
12 changes: 7 additions & 5 deletions src/pdf/qpdfdocument.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class Q_PDF_EXPORT QPdfDocument : public QObject
Q_OBJECT
Q_PROPERTY(int pageCount READ pageCount NOTIFY pageCountChanged FINAL)
Q_PROPERTY(QString password READ password WRITE setPassword FINAL)
Q_PROPERTY(bool loading READ isLoading FINAL)
public:

enum Error {
Expand All @@ -29,10 +30,11 @@ class Q_PDF_EXPORT QPdfDocument : public QObject
explicit QPdfDocument(QObject *parent = 0);
~QPdfDocument();

Error load(const QString &fileName, const QString &password = QString());
Error load(QIODevice *device, const QString &password = QString());
Error load(const QString &fileName);

void loadAsynchronously(QNetworkReply *device);
bool isLoading() const;

void load(QIODevice *device);
void setPassword(const QString &password);
QString password() const;

Expand All @@ -51,8 +53,8 @@ class Q_PDF_EXPORT QPdfDocument : public QObject
void pageCountChanged();

private:
Q_PRIVATE_SLOT(d, void _q_initiateAsyncLoad())
Q_PRIVATE_SLOT(d, void _q_readFromDevice())
Q_PRIVATE_SLOT(d, void _q_tryLoadingWithSizeFromContentHeader())
Q_PRIVATE_SLOT(d, void _q_copyFromSequentialSourceDevice())
QScopedPointer<QPdfDocumentPrivate> d;
};

Expand Down
9 changes: 5 additions & 4 deletions src/pdf/qpdfdocument_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,19 @@ class QPdfDocumentPrivate: public FPDF_FILEACCESS, public FX_FILEAVAIL, public F
QPointer<QIODevice> device;
QScopedPointer<QIODevice> ownDevice;
QBuffer asyncBuffer;
QPointer<QNetworkReply> remoteDevice;
QPointer<QIODevice> sequentialSourceDevice;
QByteArray password;

QPdfDocument::Error lastError;

void clear();

QPdfDocument::Error load(QIODevice *device, bool ownDevice, const QString &documentPassword);
void load(QIODevice *device, bool ownDevice);
void loadAsync(QIODevice *device);

void _q_initiateAsyncLoad();
void _q_readFromDevice();
void _q_tryLoadingWithSizeFromContentHeader();
void initiateAsyncLoadWithTotalSizeKnown(quint64 totalSize);
void _q_copyFromSequentialSourceDevice();
void tryLoadDocument();
void checkComplete();

Expand Down
15 changes: 11 additions & 4 deletions tests/auto/qpdfdocument/tst_qpdfdocument.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,12 @@ void tst_QPdfDocument::loadFromIODevice()
{
TemporaryPdf tempPdf;
QPdfDocument doc;
QCOMPARE(doc.load(&tempPdf), QPdfDocument::NoError);
QSignalSpy startedSpy(&doc, SIGNAL(documentLoadStarted()));
QSignalSpy finishedSpy(&doc, SIGNAL(documentLoadFinished()));
doc.load(&tempPdf);
QCOMPARE(startedSpy.count(), 1);
QCOMPARE(finishedSpy.count(), 1);
QCOMPARE(doc.error(), QPdfDocument::NoError);
QCOMPARE(doc.pageCount(), 2);
}

Expand All @@ -83,7 +88,7 @@ void tst_QPdfDocument::loadAsync()
QSignalSpy startedSpy(&doc, SIGNAL(documentLoadStarted()));
QSignalSpy finishedSpy(&doc, SIGNAL(documentLoadFinished()));

doc.loadAsynchronously(reply.data());
doc.load(reply.data());

QCOMPARE(startedSpy.count(), 1);
QCOMPARE(finishedSpy.count(), 1);
Expand All @@ -95,8 +100,10 @@ void tst_QPdfDocument::password()
QPdfDocument doc;
QCOMPARE(doc.pageCount(), 0);
QCOMPARE(doc.load(QFINDTESTDATA("pdf-sample.protected.pdf")), QPdfDocument::IncorrectPasswordError);
QCOMPARE(doc.load(QFINDTESTDATA("pdf-sample.protected.pdf"), QStringLiteral("WrongPassword")), QPdfDocument::IncorrectPasswordError);
QCOMPARE(doc.load(QFINDTESTDATA("pdf-sample.protected.pdf"), QStringLiteral("Qt")), QPdfDocument::NoError);
doc.setPassword(QStringLiteral("WrongPassword"));
QCOMPARE(doc.load(QFINDTESTDATA("pdf-sample.protected.pdf")), QPdfDocument::IncorrectPasswordError);
doc.setPassword(QStringLiteral("Qt"));
QCOMPARE(doc.load(QFINDTESTDATA("pdf-sample.protected.pdf")), QPdfDocument::NoError);
QCOMPARE(doc.pageCount(), 1);
}

Expand Down

0 comments on commit c5c391e

Please sign in to comment.