diff options
-rw-r--r-- | src/libs/installer/binarycontent.cpp | 136 | ||||
-rw-r--r-- | src/libs/installer/binarycontent.h | 6 | ||||
-rw-r--r-- | src/libs/installer/binaryformat.cpp | 393 | ||||
-rw-r--r-- | src/libs/installer/binaryformat.h | 41 | ||||
-rw-r--r-- | src/libs/installer/binaryformatengine.cpp | 34 | ||||
-rw-r--r-- | src/libs/installer/binaryformatenginehandler.cpp | 37 | ||||
-rw-r--r-- | src/libs/installer/binaryformatenginehandler.h | 2 | ||||
-rw-r--r-- | src/libs/installer/binarylayout.cpp | 21 | ||||
-rw-r--r-- | src/libs/installer/createlocalrepositoryoperation.cpp | 16 | ||||
-rw-r--r-- | src/libs/installer/packagemanagercore_p.cpp | 2 | ||||
-rw-r--r-- | src/sdk/installerbase.cpp | 16 | ||||
-rw-r--r-- | src/sdk/sdkapp.h | 32 | ||||
-rw-r--r-- | src/sdk/updatechecker.cpp | 11 | ||||
-rw-r--r-- | tests/auto/installer/binaryformat/tst_binaryformat.cpp | 174 | ||||
-rw-r--r-- | tools/binarycreator/binarycreator.cpp | 49 | ||||
-rw-r--r-- | tools/devtool/binarydump.cpp | 6 | ||||
-rw-r--r-- | tools/devtool/main.cpp | 17 |
17 files changed, 533 insertions, 460 deletions
diff --git a/src/libs/installer/binarycontent.cpp b/src/libs/installer/binarycontent.cpp index 7ba285f3a..49f381318 100644 --- a/src/libs/installer/binarycontent.cpp +++ b/src/libs/installer/binarycontent.cpp @@ -49,11 +49,25 @@ namespace QInstaller { /*! - Search through 1MB, if smaller through the whole file. Note: QFile::map() does - not change QFile::pos(). Fallback to read the file content in case we can't map it. + \class QInstaller::BinaryContent + \inmodule QtInstallerFramework + \brief The BinaryContent class handles binary information embedded into executables. - Note: Failing to map the file can happen for example while having a remote connection - established to the admin server process and we do not support map over the socket. + The following types of binary information can be embedded into executable files: Qt resources, + performed operations, and resource collections. + + The magic marker is a \c quint64 that identifies the kind of the binary: \c installer or + \c uninstaller (maintenance tool). + + The magic cookie is a \c quint64 describing whether the binary is the file holding just data + or whether it includes the executable as well. +*/ + +/*! + Searches for the given magic cookie \a magicCookie starting from the end of the file \a in. + Returns the position of the magic cookie inside the binary. Throws Error on failure. + + \note Searches through up to 1MB of data, if smaller, through the whole file. */ qint64 BinaryContent::findMagicCookie(QFile *in, quint64 magicCookie) { @@ -68,6 +82,10 @@ qint64 BinaryContent::findMagicCookie(QFile *in, quint64 magicCookie) QByteArray data(maxSearch, Qt::Uninitialized); uchar *const mapped = in->map(fileSize - maxSearch, maxSearch); if (!mapped) { + // Fallback to read the file content in case we can't map it. + + // Note: Failing to map the file can happen for example while having a remote connection + // established to the privileged server process and we do not support map over the socket. const int pos = in->pos(); try { in->seek(fileSize - maxSearch); @@ -78,6 +96,7 @@ qint64 BinaryContent::findMagicCookie(QFile *in, quint64 magicCookie) throw error; } } else { + // map does not change QFile::pos() data = QByteArray((const char*) mapped, maxSearch); in->unmap(mapped); } @@ -94,6 +113,11 @@ qint64 BinaryContent::findMagicCookie(QFile *in, quint64 magicCookie) return -1; // never reached } +/*! + Tries to read the binary layout of the file \a file. It starts searching from the end of the + file \a file for the given \a magicCookie using findMagicCookie(). If the cookie was found, it + fills a BinaryLayout structure and returns it. Throws Error on failure. +*/ BinaryLayout BinaryContent::binaryLayout(QFile *file, quint64 magicCookie) { BinaryLayout layout; @@ -110,7 +134,7 @@ BinaryLayout BinaryContent::binaryLayout(QFile *file, quint64 magicCookie) const qint64 posOfResourceCollectionsSegment = layout.endOfBinaryContent - ((metaResourcesCount * (2 * sizeof(qint64))) // minus the size of the meta data segments - + (8 * sizeof(qint64))); // meta count, offset/length component index, marker, cookie... + + (8 * sizeof(qint64))); // meta count, offset/length collection index, marker, cookie... if (!file->seek(posOfResourceCollectionsSegment)) { throw Error(QCoreApplication::translate("BinaryLayout", "Could not seek to %1 to read the resource collection segment.") @@ -155,58 +179,92 @@ BinaryLayout BinaryContent::binaryLayout(QFile *file, quint64 magicCookie) return layout; } -void BinaryContent::readBinaryContent(const QSharedPointer<QFile> &in, - ResourceCollection *metaResources, QList<OperationBlob> *operations, +/*! + Reads the binary content of the given file \a file. It starts by reading the binary layout of + the file using binaryLayout() using \a magicCookie. Throws Error on failure. + + If \a operations is not 0, it is set to the performed operations from a previous run of for + example the maintenance tool. + + If \a manager is not 0, it is first cleared and then set to the resource collections embedded + into the binary. + + If \a magicMarker is not 0, it is set to the magic marker found in the binary. +*/ +void BinaryContent::readBinaryContent(QFile *file, QList<OperationBlob> *operations, ResourceCollectionManager *manager, qint64 *magicMarker, quint64 magicCookie) { - const BinaryLayout layout = BinaryContent::binaryLayout(in.data(), magicCookie); + const BinaryLayout layout = BinaryContent::binaryLayout(file, magicCookie); - if (metaResources) { // append the meta resources - foreach (const Range<qint64> &segment, layout.metaResourceSegments) - metaResources->appendResource(QSharedPointer<Resource>(new Resource(in, segment))); + if (manager) + manager->clear(); + + if (manager) { // append the meta resources + ResourceCollection metaResources("QResources"); + foreach (const Range<qint64> &segment, layout.metaResourceSegments) { + metaResources.appendResource(QSharedPointer<Resource>(new Resource(file->fileName(), + segment))); + } + manager->insertCollection(metaResources); } if (operations) { const qint64 posOfOperationsBlock = layout.operationsSegment.start(); - if (!in->seek(posOfOperationsBlock)) { + if (!file->seek(posOfOperationsBlock)) { throw Error(QCoreApplication::translate("BinaryContent", "Could not seek to %1 to read the operation data.").arg(posOfOperationsBlock)); } // read the operations count - qint64 operationsCount = QInstaller::retrieveInt64(in.data()); + qint64 operationsCount = QInstaller::retrieveInt64(file); // read the operations for (int i = 0; i < operationsCount; ++i) { - const QString name = QInstaller::retrieveString(in.data()); - const QString xml = QInstaller::retrieveString(in.data()); + const QString name = QInstaller::retrieveString(file); + const QString xml = QInstaller::retrieveString(file); operations->append(OperationBlob(name, xml)); } // operations count - Q_UNUSED(QInstaller::retrieveInt64(in.data())) // read it, but deliberately not used + Q_UNUSED(QInstaller::retrieveInt64(file)) // read it, but deliberately not used } - if (manager) { // read the component index and data + if (manager) { // read the collection index and data const qint64 posOfResourceCollectionBlock = layout.resourceCollectionsSegment.start(); - if (!in->seek(posOfResourceCollectionBlock)) { + if (!file->seek(posOfResourceCollectionBlock)) { throw Error(QCoreApplication::translate("BinaryContent", "Could not seek to %1 to " "read the resource collection block.").arg(posOfResourceCollectionBlock)); } - manager->read(in, layout.endOfExectuable); + manager->read(file, layout.endOfExectuable); } if (magicMarker) *magicMarker = layout.magicMarker; } -void BinaryContent::writeBinaryContent(const QSharedPointer<QFile> &out, - const ResourceCollection &metaResources, const QList<OperationBlob> &operations, +/*! + Writes the binary content to the given file \a out. Throws Error on failure. + + The binary content is written in the following order: + + \list + \li Meta resources \a manager + \li Operations \a operations + \li Resource collections \a manager + \li Magic marker \a magicMarker + \li Magic cookie \a magicCookie + \endlist + + For more information see the BinaryLayout documentation. +*/ +void BinaryContent::writeBinaryContent(QFile *out, const QList<OperationBlob> &operations, const ResourceCollectionManager &manager, qint64 magicMarker, quint64 magicCookie) { const qint64 endOfBinary = out->pos(); + ResourceCollectionManager localManager = manager; // resources qint64 pos = out->pos(); QVector<Range<qint64> > metaResourceSegments; - foreach (const QSharedPointer<Resource> &resource, metaResources.resources()) { + const ResourceCollection collection = localManager.collectionByName("QResources"); + foreach (const QSharedPointer<Resource> &resource, collection.resources()) { const bool isOpen = resource->isOpen(); if ((!isOpen) && (!resource->open())) { throw Error(QCoreApplication::translate("BinaryContent", @@ -214,44 +272,42 @@ void BinaryContent::writeBinaryContent(const QSharedPointer<QFile> &out, } resource->seek(0); - resource->copyData(out.data()); - metaResourceSegments.append(Range<qint64>::fromStartAndEnd(pos, out->pos()) - .moved(-endOfBinary)); + resource->copyData(out); + metaResourceSegments.append(Range<qint64>::fromStartAndEnd(pos, out->pos())); pos = out->pos(); if (!isOpen) // If we reach that point, either the resource was opened already... resource->close(); // or we did open it and have to close it again. } + localManager.removeCollection("QResources"); // operations - QInstaller::appendInt64(out.data(), operations.count()); + QInstaller::appendInt64(out, operations.count()); foreach (const OperationBlob &operation, operations) { - QInstaller::appendString(out.data(), operation.name); - QInstaller::appendString(out.data(), operation.xml); + QInstaller::appendString(out, operation.name); + QInstaller::appendString(out, operation.xml); } - QInstaller::appendInt64(out.data(), operations.count()); - const Range<qint64> operationsSegment = Range<qint64>::fromStartAndEnd(pos, out->pos()) - .moved(-endOfBinary); + QInstaller::appendInt64(out, operations.count()); + const Range<qint64> operationsSegment = Range<qint64>::fromStartAndEnd(pos, out->pos()); // resource collections data and index - const Range<qint64> resourceCollectionsSegment = manager.write(out.data(), -endOfBinary) - .moved(-endOfBinary); - QInstaller::appendInt64Range(out.data(), resourceCollectionsSegment); + const Range<qint64> resourceCollectionsSegment = localManager.write(out, -endOfBinary); + QInstaller::appendInt64Range(out, resourceCollectionsSegment.moved(-endOfBinary)); // meta resource segments foreach (const Range<qint64> &segment, metaResourceSegments) - QInstaller::appendInt64Range(out.data(), segment); + QInstaller::appendInt64Range(out, segment.moved(-endOfBinary)); // operations segment - QInstaller::appendInt64Range(out.data(), operationsSegment); + QInstaller::appendInt64Range(out, operationsSegment.moved(-endOfBinary)); // resources count - QInstaller::appendInt64(out.data(), metaResourceSegments.count()); + QInstaller::appendInt64(out, metaResourceSegments.count()); const qint64 binaryContentSize = (out->pos() + (3 * sizeof(qint64))) - endOfBinary; - QInstaller::appendInt64(out.data(), binaryContentSize); - QInstaller::appendInt64(out.data(), magicMarker); - QInstaller::appendInt64(out.data(), magicCookie); + QInstaller::appendInt64(out, binaryContentSize); + QInstaller::appendInt64(out, magicMarker); + QInstaller::appendInt64(out, magicCookie); } } // namespace QInstaller diff --git a/src/libs/installer/binarycontent.h b/src/libs/installer/binarycontent.h index b4527a74a..9821561cf 100644 --- a/src/libs/installer/binarycontent.h +++ b/src/libs/installer/binarycontent.h @@ -68,15 +68,13 @@ public: static qint64 findMagicCookie(QFile *file, quint64 magicCookie); static BinaryLayout binaryLayout(QFile *file, quint64 magicCookie); - static void readBinaryContent(const QSharedPointer<QFile> &in, - ResourceCollection *metaResources, + static void readBinaryContent(QFile *file, QList<OperationBlob> *operations, ResourceCollectionManager *manager, qint64 *magicMarker, quint64 magicCookie); - static void writeBinaryContent(const QSharedPointer<QFile> &out, - const ResourceCollection &metaResources, + static void writeBinaryContent(QFile *out, const QList<OperationBlob> &operations, const ResourceCollectionManager &manager, qint64 magicMarker, diff --git a/src/libs/installer/binaryformat.cpp b/src/libs/installer/binaryformat.cpp index 91cfba676..b23def68c 100644 --- a/src/libs/installer/binaryformat.cpp +++ b/src/libs/installer/binaryformat.cpp @@ -51,86 +51,87 @@ namespace QInstaller { /*! - \class Resource - \brief The Resource class provides an interface for reading from an underlying device. + \class QInstaller::OperationBlob + \inmodule QtInstallerFramework + \brief The OperationBlob class is a textual representation of an operation that can be + instantiated and executed by the Qt Installer Framework. +*/ - Resource is an interface for reading inside a device, but is not supposed to write to the - the device it wraps. The resource class is created by either passing a path to an already - existing binary (e.g. a zipped archive, a Qt Resource file etc.) or by passing an name and - segment inside an already existing QIODevice, passed as device. +/*! + \fn OperationBlob::OperationBlob(const QString &n, const QString &x) - The resource name can be set at any time using setName(). The segment passed inside the - constructor represents the offset and size of the resource inside the device. + Constructs the operation blob with the given arguments, while \a n stands for the name part and + \a x for the XML representation of the operation. */ /*! - Creates a resource providing the data in \a path. + \variable QInstaller::OperationBlob::name + \brief The name of the operation. +*/ - \sa open() - */ -Resource::Resource(const QString &path) - : m_device(0) - , m_name(QFileInfo(path).fileName().toUtf8()) - , m_deviceOpened(false) -{ - m_inputFile.setFileName(path); - m_segment = Range<qint64>::fromStartAndLength(0, m_inputFile.size()); -} +/*! + \variable QInstaller::OperationBlob::xml + \brief The XML representation of the operation. +*/ /*! - Creates a resource identified by \a name providing the data in \a path. + \class QInstaller::Resource + \inmodule QtInstallerFramework + \brief The Resource class is an interface for wrapping a file as read only device. + + Resource is an interface for reading inside a file, but is not supposed to write to the file it + wraps. The resource class is created by passing a path to an existing binary (such as a zipped + archive or a Qt resource file). - \sa open() + The resource name can be set at any time using setName() or during construction. The segment + supplied during construction represents the offset and size of the resource inside the file. */ -Resource::Resource(const QByteArray &name, const QString &path) - : m_device(0) - , m_name(name) - , m_deviceOpened(false) -{ - m_inputFile.setFileName(path); - m_segment = Range<qint64>::fromStartAndLength(0, m_inputFile.size()); -} /*! - Creates a resource providing the data in a \a device. + \fn Range<qint64> Resource::segment() const - \sa open() + Returns the range inside the file this resource represents. */ -Resource::Resource(const QSharedPointer<QIODevice> &device) - : m_device(device) - , m_segment(Range<qint64>::fromStartAndLength(0, device->size())) - , m_name(QUuid::createUuid().toByteArray()) - , m_deviceOpened(false) -{ -} /*! - Creates a resource providing a data \a segment within a \a device. + \fn void Resource::setSegment(const Range<qint64> &segment) - \sa open() + Sets the range inside the file this resource represents. */ -Resource::Resource(const QSharedPointer<QIODevice> &device, const Range<qint64> &segment) - : m_device(device) - , m_segment(segment) - , m_name(QUuid::createUuid().toByteArray()) - , m_deviceOpened(false) + +/*! + Creates a resource providing the data in \a path. + */ +Resource::Resource(const QString &path) + : m_file(path) + , m_name(QFileInfo(path).fileName().toUtf8()) + , m_segment(Range<qint64>::fromStartAndLength(0, m_file.size())) { } /*! - Creates a resource identified by \a name providing a data \a segment within a \a device. + Creates a resource providing the data in \a path identified by \a name. +*/ +Resource::Resource(const QString &path, const QByteArray &name) + : m_file(path) + , m_name(name) + , m_segment(Range<qint64>::fromStartAndLength(0, m_file.size())) +{ +} - \sa open() - */ -Resource::Resource(const QByteArray &name, const QSharedPointer<QIODevice> &device, - const Range<qint64> &segment) - : m_device(device) +/*! + Creates a resource providing the data in \a path limited to \a segment. +*/ +Resource::Resource(const QString &path, const Range<qint64> &segment) + : m_file(path) + , m_name(QFileInfo(path).fileName().toUtf8()) , m_segment(segment) - , m_name(name) - , m_deviceOpened(false) { } +/*! + Destroys the resource. Calls close() if necessary before destroying the resource. +*/ Resource::~Resource() { if (isOpen()) @@ -142,16 +143,20 @@ Resource::~Resource() */ bool Resource::seek(qint64 pos) { - if (m_inputFile.isOpen()) - return m_inputFile.seek(pos) && QIODevice::seek(pos); return QIODevice::seek(pos); } +/*! + Returns the name of the resource. +*/ QByteArray Resource::name() const { return m_name; } +/*! + Sets the name of the resource to \a name. +*/ void Resource::setName(const QByteArray &name) { m_name = name; @@ -166,39 +171,23 @@ bool Resource::open() if (isOpen()) return false; - if (m_device.isNull()) { - if (!m_inputFile.open(QIODevice::ReadOnly)) { - setErrorString(m_inputFile.errorString()); - return false; - } - return open(QIODevice::ReadOnly); - } - - if (m_device->isOpen()) { - if (!QFlags<QIODevice::OpenModeFlag>(m_device->openMode()).testFlag(QIODevice::ReadOnly)) { - setErrorString(tr("Could not open the underlying device. Already opened write only.")); - return false; - } - return open(QIODevice::ReadOnly); + if (!m_file.open(QIODevice::ReadOnly)) { + setErrorString(m_file.errorString()); + return false; } - m_deviceOpened = m_device->open(QIODevice::ReadOnly); - if (!m_deviceOpened) { - setErrorString(m_device->errorString()); + if (!QIODevice::open(QIODevice::ReadOnly)) { + setErrorString(tr("Could not open Resource '%1' read-only.").arg(QString::fromUtf8(m_name))); return false; } - return open(QIODevice::ReadOnly); + return true; } /*! \reimp */ void Resource::close() { - m_inputFile.close(); - if (!m_device.isNull() && m_deviceOpened) { - m_device->close(); - m_deviceOpened = false; - } + m_file.close(); QIODevice::close(); } @@ -215,13 +204,10 @@ qint64 Resource::size() const */ qint64 Resource::readData(char* data, qint64 maxSize) { - if (m_device == 0) - return m_inputFile.read(data, maxSize); - - const qint64 p = m_device->pos(); - m_device->seek(m_segment.start() + pos()); - const qint64 amountRead = m_device->read(data, qMin<quint64>(maxSize, m_segment.length() - pos())); - m_device->seek(p); + const qint64 p = m_file.pos(); + m_file.seek(m_segment.start() + pos()); + const qint64 amountRead = m_file.read(data, qMin<quint64>(maxSize, m_segment.length() - pos())); + m_file.seek(p); return amountRead; } @@ -236,6 +222,17 @@ qint64 Resource::writeData(const char* data, qint64 maxSize) return -1; } +/*! + \fn void Resource::copyData(QFileDevice *out) + + Copies the resource data to a file called \a out. Throws Error on failure. +*/ + +/*! + \overload + + Copies the resource data of \a resource to a file called \a out. Throws Error on failure. +*/ void Resource::copyData(Resource *resource, QFileDevice *out) { qint64 left = resource->size(); @@ -258,88 +255,44 @@ void Resource::copyData(Resource *resource, QFileDevice *out) /*! - \class ResourceCollection - \brief A Resource Collection is an abstraction that groups together a number of resources. + \class QInstaller::ResourceCollection + \inmodule QtInstallerFramework + \brief The ResourceCollection class is an abstraction that groups together a number of resources. The resources are supposed to be sequential, so the collection keeps them ordered once a new - resource is added. + resource is added. The name can be set at any time using setName(). +*/ - The resources collection can be written to and read from a QFileDevice. The resource - collection name can be set at any time using setName(). +/*! + The class constructor creates an empty resource collection. By default the collection gets a + unique name assigned using QUuid. */ +ResourceCollection::ResourceCollection() + : ResourceCollection(QUuid::createUuid().toByteArray()) +{ +} +/*! + The class constructor creates an empty resource collection with a name set to \a name. +*/ ResourceCollection::ResourceCollection(const QByteArray &name) : m_name(name) -{ -} +{} +/*! + Returns the name of the resource collection. +*/ QByteArray ResourceCollection::name() const { return m_name; } -void ResourceCollection::setName(const QByteArray &ba) -{ - m_name = ba; -} - -void ResourceCollection::write(QFileDevice *out, qint64 offset) const -{ - const qint64 dataBegin = out->pos(); - - QInstaller::appendInt64(out, m_resources.count()); - - qint64 start = out->pos() + offset; - - // Why 16 + 16? This is 24, not 32??? - const int foo = 3 * sizeof(qint64); - // add 16 + 16 + number of name characters for each resource (the size of the table) - foreach (const QSharedPointer<Resource> &resource, m_resources) - start += foo + resource->name().count(); - - QList<qint64> starts; - foreach (const QSharedPointer<Resource> &resource, m_resources) { - QInstaller::appendByteArray(out, resource->name()); - starts.push_back(start); - QInstaller::appendInt64Range(out, Range<qint64>::fromStartAndLength(start, resource->size())); - start += resource->size(); - } - - foreach (const QSharedPointer<Resource> &resource, m_resources) { - if (!resource->open()) { - throw QInstaller::Error(tr("Could not open resource %1: %2") - .arg(QString::fromUtf8(resource->name()), resource->errorString())); - } - - const qint64 expectedStart = starts.takeFirst(); - const qint64 actualStart = out->pos() + offset; - Q_UNUSED(expectedStart); - Q_UNUSED(actualStart); - Q_ASSERT(expectedStart == actualStart); - resource->copyData(out); - } - - m_segment = Range<qint64>::fromStartAndEnd(dataBegin, out->pos()).moved(offset); -} - -void ResourceCollection::read(const QSharedPointer<QFile> &in, qint64 offset) +/*! + Sets the name of the resource collection to \a name. +*/ +void ResourceCollection::setName(const QByteArray &name) { - const qint64 pos = in->pos(); - - in->seek(m_segment.start()); - const qint64 count = QInstaller::retrieveInt64(in.data()); - - QList<QByteArray> names; - QList<Range<qint64> > ranges; - for (int i = 0; i < count; ++i) { - names.push_back(QInstaller::retrieveByteArray(in.data())); - ranges.push_back(QInstaller::retrieveInt64Range(in.data()).moved(offset)); - } - - for (int i = 0; i < ranges.count(); ++i) - m_resources.append(QSharedPointer<Resource>(new Resource(names.at(i), in, ranges.at(i)))); - - in->seek(pos); + m_name = name; } /*! @@ -349,9 +302,13 @@ void ResourceCollection::appendResource(const QSharedPointer<Resource>& resource { Q_ASSERT(resource); resource->setParent(0); - m_resources.push_back(resource); + m_resources.append(resource); } +/*! + Appends a list of \a resources to this collection. The collection takes ownership of \a + resources. +*/ void ResourceCollection::appendResources(const QList<QSharedPointer<Resource> > &resources) { foreach (const QSharedPointer<Resource> &resource, resources) @@ -359,13 +316,16 @@ void ResourceCollection::appendResources(const QList<QSharedPointer<Resource> > } /*! - Returns the resources associated with this component. - */ + Returns the resources associated with this collection. +*/ QList<QSharedPointer<Resource> > ResourceCollection::resources() const { return m_resources; } +/*! + Returns the resource associated with the name \a name. +*/ QSharedPointer<Resource> ResourceCollection::resourceByName(const QByteArray &name) const { foreach (const QSharedPointer<Resource>& i, m_resources) { @@ -377,84 +337,139 @@ QSharedPointer<Resource> ResourceCollection::resourceByName(const QByteArray &na /*! - \class ResourceCollectionManager - \brief A Resource Collection Manager is an abstraction that groups together a number of - resource collections. + \class QInstaller::ResourceCollectionManager + \inmodule QtInstallerFramework + \brief The ResourceCollectionManager class is an abstraction that groups together a number of + resource collections. - The resources collections can be written to and read from a QFileDevice. + The resources collections it groups can be written to and read from a QFileDevice. */ -void ResourceCollectionManager::read(const QSharedPointer<QFile> &dev, qint64 offset) -{ - const qint64 size = QInstaller::retrieveInt64(dev.data()); - for (int i = 0; i < size; ++i) - insertCollection(readIndexEntry(dev, offset)); - QInstaller::retrieveInt64(dev.data()); +/*! + Reads the resource collection from the file \a dev. The \a offset argument is used to + set the collection's resources segment information. +*/ +void ResourceCollectionManager::read(QFileDevice *dev, qint64 offset) +{ + const qint64 size = QInstaller::retrieveInt64(dev); + for (int i = 0; i < size; ++i) { + ResourceCollection collection(QInstaller::retrieveByteArray(dev)); + const Range<qint64> segment = QInstaller::retrieveInt64Range(dev).moved(offset); + + const qint64 pos = dev->pos(); + + dev->seek(segment.start()); + const qint64 count = QInstaller::retrieveInt64(dev); + for (int i = 0; i < count; ++i) { + QSharedPointer<Resource> resource(new Resource(dev->fileName())); + resource->setName(QInstaller::retrieveByteArray(dev)); + resource->setSegment(QInstaller::retrieveInt64Range(dev).moved(offset)); + collection.appendResource(resource); + } + dev->seek(pos); + + insertCollection(collection); + } } +/*! + Writes the resource collection to the file \a out. The \a offset argument is used to + set the collection's segment information. +*/ Range<qint64> ResourceCollectionManager::write(QFileDevice *out, qint64 offset) const { + QHash < QByteArray, Range<qint64> > table; QInstaller::appendInt64(out, collectionCount()); - foreach (const ResourceCollection &collection, m_collections) - collection.write(out, offset); + foreach (const ResourceCollection &collection, m_collections) { + const qint64 dataBegin = out->pos(); + QInstaller::appendInt64(out, collection.resources().count()); + + qint64 start = out->pos() + offset; + foreach (const QSharedPointer<Resource> &resource, collection.resources()) { + start += (sizeof(qint64)) // the number of bytes that get written and the + + resource->name().size() // resource name (see QInstaller::appendByteArray) + + (2 * sizeof(qint64)); // the resource range (see QInstaller::appendInt64Range) + } + + foreach (const QSharedPointer<Resource> &resource, collection.resources()) { + QInstaller::appendByteArray(out, resource->name()); + QInstaller::appendInt64Range(out, Range<qint64>::fromStartAndLength(start, + resource->size())); // the actual range once the table has been written + start += resource->size(); // adjust for next resource data + } + + foreach (const QSharedPointer<Resource> &resource, collection.resources()) { + if (!resource->open()) { + throw QInstaller::Error(tr("Could not open resource %1: %2") + .arg(QString::fromUtf8(resource->name()), resource->errorString())); + } + resource->copyData(out); + } + + table.insert(collection.name(), Range<qint64>::fromStartAndEnd(dataBegin, out->pos()) + .moved(offset)); + } const qint64 start = out->pos(); // Q: why do we write the size twice? // A: for us to be able to read it beginning from the end of the file as well QInstaller::appendInt64(out, collectionCount()); - foreach (const ResourceCollection &collection, m_collections) - writeIndexEntry(collection, out); + foreach (const QByteArray &name, table.keys()) { + QInstaller::appendByteArray(out, name); + QInstaller::appendInt64Range(out, table.value(name)); + } QInstaller::appendInt64(out, collectionCount()); return Range<qint64>::fromStartAndEnd(start, out->pos()); } +/*! + Returns the collection associated with the name \a name. +*/ ResourceCollection ResourceCollectionManager::collectionByName(const QByteArray &name) const { return m_collections.value(name); } +/*! + Inserts the \a collection into the collection manager. +*/ void ResourceCollectionManager::insertCollection(const ResourceCollection& collection) { m_collections.insert(collection.name(), collection); } +/*! + Removes all occurrences of \a name from the collection manager. +*/ void ResourceCollectionManager::removeCollection(const QByteArray &name) { m_collections.remove(name); } +/*! + Returns the collections the collection manager contains. +*/ QList<ResourceCollection> ResourceCollectionManager::collections() const { return m_collections.values(); } -void ResourceCollectionManager::reset() +/*! + Clears the contents of the collection manager. +*/ +void ResourceCollectionManager::clear() { m_collections.clear(); } +/*! + Returns the number of collections in the collection manager. +*/ int ResourceCollectionManager::collectionCount() const { - return m_collections.size(); -} - -void ResourceCollectionManager::writeIndexEntry(const ResourceCollection &collection, - QFileDevice *dev) const -{ - QInstaller::appendByteArray(dev, collection.name()); - QInstaller::appendInt64Range(dev, collection.segment()); -} - -ResourceCollection ResourceCollectionManager::readIndexEntry(const QSharedPointer<QFile> &in, - qint64 offset) -{ - ResourceCollection c(QInstaller::retrieveByteArray(in.data())); - c.setSegment(QInstaller::retrieveInt64Range(in.data()).moved(offset)); - c.read(in, offset); - - return c; + return m_collections.count(); } } // namespace QInstaller diff --git a/src/libs/installer/binaryformat.h b/src/libs/installer/binaryformat.h index d2fc68987..e09e79318 100644 --- a/src/libs/installer/binaryformat.h +++ b/src/libs/installer/binaryformat.h @@ -42,11 +42,13 @@ #ifndef BINARYFORMAT_H #define BINARYFORMAT_H +#include "installer_global.h" #include "range.h" -#include "qinstallerglobal.h" +#include <QCoreApplication> #include <QFile> #include <QList> +#include <QSharedPointer> namespace QInstaller { @@ -65,12 +67,8 @@ class INSTALLER_EXPORT Resource : public QIODevice public: explicit Resource(const QString &path); - Resource(const QByteArray &name, const QString &path); - - explicit Resource(const QSharedPointer<QIODevice> &device); - Resource(const QSharedPointer<QIODevice> &device, const Range<qint64> &segment); - Resource(const QByteArray &name, const QSharedPointer<QIODevice> &device, - const Range<qint64> &segment); + Resource(const QString &path, const QByteArray &name); + Resource(const QString &path, const Range<qint64> &segment); ~Resource(); bool open(); @@ -83,6 +81,7 @@ public: void setName(const QByteArray &name); Range<qint64> segment() const { return m_segment; } + void setSegment(const Range<qint64> &segment) { m_segment = segment; } void copyData(QFileDevice *out) { copyData(this, out); } static void copyData(Resource *archive, QFileDevice *out); @@ -90,14 +89,14 @@ public: private: qint64 readData(char *data, qint64 maxSize); qint64 writeData(const char *data, qint64 maxSize); + bool open(OpenMode mode) { return QIODevice::open(mode); } + void setOpenMode(OpenMode mode) { QIODevice::setOpenMode(mode); } private: - QSharedPointer<QIODevice> m_device; - Range<qint64> m_segment; - QFile m_inputFile; + QFile m_file; QByteArray m_name; - bool m_deviceOpened; + Range<qint64> m_segment; }; @@ -106,39 +105,33 @@ class INSTALLER_EXPORT ResourceCollection Q_DECLARE_TR_FUNCTIONS(ResourceCollection) public: - ResourceCollection() {} + ResourceCollection(); explicit ResourceCollection(const QByteArray &name); QByteArray name() const; void setName(const QByteArray &ba); - Range<qint64> segment() const { return m_segment; } - void setSegment(const Range<qint64> &segment) const { m_segment = segment; } - - void write(QFileDevice *dev, qint64 positionOffset) const; - void read(const QSharedPointer<QFile> &dev, qint64 offset); - QList<QSharedPointer<Resource> > resources() const; QSharedPointer<Resource> resourceByName(const QByteArray &name) const; void appendResource(const QSharedPointer<Resource> &resource); void appendResources(const QList<QSharedPointer<Resource> > &resources); - private: QByteArray m_name; - mutable Range<qint64> m_segment; QList<QSharedPointer<Resource> > m_resources; }; class INSTALLER_EXPORT ResourceCollectionManager { + Q_DECLARE_TR_FUNCTIONS(ResourceCollectionManager) + public: + void read(QFileDevice *dev, qint64 offset); Range<qint64> write(QFileDevice *dev, qint64 offset) const; - void read(const QSharedPointer<QFile> &dev, qint64 offset); - void reset(); + void clear(); int collectionCount() const; QList<ResourceCollection> collections() const; @@ -148,10 +141,6 @@ public: void insertCollection(const ResourceCollection &collection); private: - void writeIndexEntry(const ResourceCollection &coll, QFileDevice *dev) const; - ResourceCollection readIndexEntry(const QSharedPointer<QFile> &dev, qint64 offset); - -private: QHash<QByteArray, ResourceCollection> m_collections; }; diff --git a/src/libs/installer/binaryformatengine.cpp b/src/libs/installer/binaryformatengine.cpp index d493018ea..d9645c2fe 100644 --- a/src/libs/installer/binaryformatengine.cpp +++ b/src/libs/installer/binaryformatengine.cpp @@ -80,6 +80,13 @@ private: namespace QInstaller { +/*! + \class QInstaller::BinaryFormatEngine + \inmodule QtInstallerFramework + \brief The BinaryFormatEngine class is the default file engine for accessing resource + collections and resource files. +*/ + BinaryFormatEngine::BinaryFormatEngine(const QHash<QByteArray, ResourceCollection> &collections, const QString &fileName) : m_resource(0) @@ -89,7 +96,7 @@ BinaryFormatEngine::BinaryFormatEngine(const QHash<QByteArray, ResourceCollectio } /*! - \reimp + \internal */ void BinaryFormatEngine::setFileName(const QString &file) { @@ -110,7 +117,7 @@ void BinaryFormatEngine::setFileName(const QString &file) } /*! - \reimp + \internal */ bool BinaryFormatEngine::close() { @@ -123,15 +130,16 @@ bool BinaryFormatEngine::close() } /*! - \reimp + \internal */ -bool BinaryFormatEngine::open(QIODevice::OpenMode /*mode*/) +bool BinaryFormatEngine::open(QIODevice::OpenMode mode) { + Q_UNUSED(mode) return m_resource.isNull() ? false : m_resource->open(); } /*! - \reimp + \internal */ qint64 BinaryFormatEngine::pos() const { @@ -139,7 +147,7 @@ qint64 BinaryFormatEngine::pos() const } /*! - \reimp + \internal */ qint64 BinaryFormatEngine::read(char *data, qint64 maxlen) { @@ -147,7 +155,7 @@ qint64 BinaryFormatEngine::read(char *data, qint64 maxlen) } /*! - \reimp + \internal */ bool BinaryFormatEngine::seek(qint64 offset) { @@ -155,7 +163,7 @@ bool BinaryFormatEngine::seek(qint64 offset) } /*! - \reimp + \internal */ QString BinaryFormatEngine::fileName(FileName file) const { @@ -177,7 +185,7 @@ QString BinaryFormatEngine::fileName(FileName file) const } /*! - \reimp + \internal */ bool BinaryFormatEngine::copy(const QString &newName) { @@ -213,7 +221,7 @@ bool BinaryFormatEngine::copy(const QString &newName) } /*! - \reimp + \internal */ QAbstractFileEngine::FileFlags BinaryFormatEngine::fileFlags(FileFlags type) const { @@ -231,7 +239,7 @@ QAbstractFileEngine::FileFlags BinaryFormatEngine::fileFlags(FileFlags type) con } /*! - \reimp + \internal */ QAbstractFileEngineIterator *BinaryFormatEngine::beginEntryList(QDir::Filters filters, const QStringList &filterNames) { @@ -240,7 +248,7 @@ QAbstractFileEngineIterator *BinaryFormatEngine::beginEntryList(QDir::Filters fi } /*! - \reimp + \internal */ QStringList BinaryFormatEngine::entryList(QDir::Filters filters, const QStringList &filterNames) const { @@ -280,7 +288,7 @@ QStringList BinaryFormatEngine::entryList(QDir::Filters filters, const QStringLi } /*! - \reimp + \internal */ qint64 BinaryFormatEngine::size() const { diff --git a/src/libs/installer/binaryformatenginehandler.cpp b/src/libs/installer/binaryformatenginehandler.cpp index 3388c5800..4d83a000b 100644 --- a/src/libs/installer/binaryformatenginehandler.cpp +++ b/src/libs/installer/binaryformatenginehandler.cpp @@ -42,33 +42,60 @@ #include "binaryformatenginehandler.h" #include "binaryformatengine.h" -#include <QFile> - namespace QInstaller { +/*! + \class QInstaller::BinaryFormatEngineHandler + \inmodule QtInstallerFramework + \brief The BinaryFormatEngineHandler class provides a way to register resource collections and + resource files. +*/ + +/*! + Creates a file engine for the file specified by \a fileName. To be able to create a file + engine, the file name needs to be prefixed with \c {installer://}. + + Returns 0 if the engine cannot handle \a fileName. +*/ QAbstractFileEngine *BinaryFormatEngineHandler::create(const QString &fileName) const { return fileName.startsWith(QLatin1String("installer://"), Qt::CaseInsensitive ) ? new BinaryFormatEngine(m_resources, fileName) : 0; } -void BinaryFormatEngineHandler::reset() +/*! + Clears the contents of the binary format engine. +*/ +void BinaryFormatEngineHandler::clear() { m_resources.clear(); } +/*! + Returns the active instance of the engine. +*/ BinaryFormatEngineHandler *BinaryFormatEngineHandler::instance() { static BinaryFormatEngineHandler instance; return &instance; } +/*! + Registers the given resource collections \a collections in the engine. +*/ void BinaryFormatEngineHandler::registerResources(const QList<ResourceCollection> &collections) { foreach (const ResourceCollection &collection, collections) m_resources.insert(collection.name(), collection); } +/*! + Registers the resource specified by \a resourcePath in a resource collection specified + by \a fileName. The file name \a fileName must be in the form of \c {installer://}, followed + by the collection name and resource name separated by a forward slash. + + A valid file name looks like this: installer://collectionName/resourceName +*/ void BinaryFormatEngineHandler::registerResource(const QString &fileName, const QString &resourcePath) { @@ -85,8 +112,8 @@ BinaryFormatEngineHandler::registerResource(const QString &fileName, const QStri const QByteArray collectionName = path.section(sep, 0, 0).toUtf8(); m_resources[collectionName].setName(collectionName); - m_resources[collectionName].appendResource(QSharedPointer<Resource>(new Resource(resourceName, - resourcePath))); + m_resources[collectionName].appendResource(QSharedPointer<Resource>(new Resource(resourcePath, + resourceName))); } } // namespace QInstaller diff --git a/src/libs/installer/binaryformatenginehandler.h b/src/libs/installer/binaryformatenginehandler.h index 213861118..6ff56480a 100644 --- a/src/libs/installer/binaryformatenginehandler.h +++ b/src/libs/installer/binaryformatenginehandler.h @@ -55,7 +55,7 @@ class INSTALLER_EXPORT BinaryFormatEngineHandler : public QAbstractFileEngineHan public: QAbstractFileEngine *create(const QString &fileName) const; - void reset(); + void clear(); static BinaryFormatEngineHandler *instance(); void registerResources(const QList<ResourceCollection> &collections); diff --git a/src/libs/installer/binarylayout.cpp b/src/libs/installer/binarylayout.cpp index 6437262af..e759e5f17 100644 --- a/src/libs/installer/binarylayout.cpp +++ b/src/libs/installer/binarylayout.cpp @@ -41,11 +41,10 @@ /*! \class QInstaller::BinaryLayout + \inmodule QtInstallerFramework + \brief The BinaryLayout class describes the binary content appended to a file. - BinaryLayout handles binary information embedded into executables. - Qt resources as well as resource collections can be stored. - - Explanation of the binary blob at the end of the installer or separate data file: + Explanation of the binary content at the end of the installer or the separate data file: \code @@ -62,8 +61,8 @@ [Format] Operation count (qint64) ---------------------------------------------------------- - Component count - Component data entry [1 ... n] + Collection count + Collection data entry [1 ... n] [Format] Archive count (qint64), Name entry [1 ... n] @@ -78,17 +77,17 @@ [Format] [Format] ---------------------------------------------------------- - Component count (qint64) - Component index entry [1 ... n] + Collection count (qint64) + Collection index entry [1 ... n] [Format] Name (qint64, QByteArray) Offset (qint64) Length (qint64) [Format] - Component count (qint64) + Collection count (qint64) ---------------------------------------------------------- - Component index block [Offset (qint64)] - Component index block [Length (qint64)] + Collection index block [Offset (qint64)] + Collection index block [Length (qint64)] ---------------------------------------------------------- Resource segments [1 ... n] [Format] diff --git a/src/libs/installer/createlocalrepositoryoperation.cpp b/src/libs/installer/createlocalrepositoryoperation.cpp index cfec09585..e550a8997 100644 --- a/src/libs/installer/createlocalrepositoryoperation.cpp +++ b/src/libs/installer/createlocalrepositoryoperation.cpp @@ -250,15 +250,15 @@ bool CreateLocalRepositoryOperation::performOperation() emit progressChanged(0.50); - QSharedPointer<QFile> file(new QFile(binaryPath)); - if (!file->open(QIODevice::ReadOnly)) { - throw QInstaller::Error(tr("Could not open file: %1. Error: %2").arg(file->fileName(), - file->errorString())); + QFile file(binaryPath); + if (!file.open(QIODevice::ReadOnly)) { + throw QInstaller::Error(tr("Could not open file: %1. Error: %2").arg(file.fileName(), + file.errorString())); } // start to read the binary layout ResourceCollectionManager manager; - BinaryContent::readBinaryContent(file, 0, 0, &manager, 0, BinaryContent::MagicCookie); + BinaryContent::readBinaryContent(&file, 0, &manager, 0, BinaryContent::MagicCookie); QDirIterator it(repoPath, QDirIterator::Subdirectories); while (it.hasNext() && !it.next().isEmpty()) { @@ -277,7 +277,8 @@ bool CreateLocalRepositoryOperation::performOperation() // copy the 7z files that are inside the component index into the target const ResourceCollection collection = manager.collectionByName(fileName.toUtf8()); foreach (const QSharedPointer<Resource> &resource, collection.resources()) { - if (!resource->open()) + const bool isOpen = resource->isOpen(); + if ((!isOpen) && (!resource->open())) continue; QFile target(absoluteTargetPath + QDir::separator() @@ -286,6 +287,9 @@ bool CreateLocalRepositoryOperation::performOperation() resource->copyData(&target); helper.m_files.prepend(target.fileName()); emit outputTextChanged(helper.m_files.first()); + + if (!isOpen) // If we reach that point, either the resource was opened already. + resource->close(); // or we did open it and have to close it again. } } } diff --git a/src/libs/installer/packagemanagercore_p.cpp b/src/libs/installer/packagemanagercore_p.cpp index 5b31255e5..d7c534baa 100644 --- a/src/libs/installer/packagemanagercore_p.cpp +++ b/src/libs/installer/packagemanagercore_p.cpp @@ -410,7 +410,7 @@ void PackageManagerCorePrivate::cleanUpComponentEnvironment() { // clean up registered (downloaded) data if (m_core->isUpdater() || m_core->isPackageManager()) - BinaryFormatEngineHandler::instance()->reset(); + BinaryFormatEngineHandler::instance()->clear(); // there could be still some references to already deleted components, // so we need to remove the current component script engine diff --git a/src/sdk/installerbase.cpp b/src/sdk/installerbase.cpp index 33f8d39e3..d5280a8bc 100644 --- a/src/sdk/installerbase.cpp +++ b/src/sdk/installerbase.cpp @@ -95,15 +95,14 @@ int InstallerBase::run() cookie = QInstaller::BinaryContent::MagicCookie; } - QSharedPointer<QFile> binary(new QFile(fileName)); - QInstaller::openForRead(binary.data()); + QFile binary(fileName); + QInstaller::openForRead(&binary); qint64 magicMarker; - QInstaller::ResourceCollection resources; QInstaller::ResourceCollectionManager manager; QList<QInstaller::OperationBlob> oldOperations; - QInstaller::BinaryContent::readBinaryContent(binary, &resources, &oldOperations, &manager, - &magicMarker, cookie); + QInstaller::BinaryContent::readBinaryContent(&binary, &oldOperations, &manager, &magicMarker, + cookie); if (QInstaller::isVerbose()) { qDebug() << "Language:" << QLocale().uiLanguages().value(0, @@ -111,7 +110,7 @@ int InstallerBase::run() qDebug() << "Arguments: " << arguments().join(QLatin1String(", ")).toUtf8().constData(); } - registerMetaResources(resources); // the base class will unregister the resources + SDKApp::registerMetaResources(manager.collectionByName("QResources")); QInstaller::BinaryFormatEngineHandler::instance()->registerResources(manager.collections()); if (QInstaller::isVerbose()) @@ -121,11 +120,6 @@ int InstallerBase::run() m_core = new QInstaller::PackageManagerCore(magicMarker, oldOperations); QInstaller::ProductKeyCheck::instance()->init(m_core); - // We can close the binary file if we are an online installer or no installer at all, cause no - // embedded archives exist inside the component index. Keeps the .dat file unlocked on Windows. - if ((!m_core->isInstaller()) || (!m_core->isOfflineOnly())) - binary->close(); - CommandLineParser parser; parser.parse(arguments()); diff --git a/src/sdk/sdkapp.h b/src/sdk/sdkapp.h index a00e2d0e8..d6f830b37 100644 --- a/src/sdk/sdkapp.h +++ b/src/sdk/sdkapp.h @@ -48,7 +48,6 @@ #include <fileutils.h> #include <QApplication> -#include <QBuffer> #include <QDir> #include <QFileInfo> #include <QResource> @@ -64,12 +63,8 @@ public: virtual ~SDKApp() { - using namespace QInstaller; - foreach (const QSharedPointer<Resource> &resource, resourceMappings.resources()) { - resource->open(); // ignore error here, either we opened it or it is opened - QResource::unregisterResource((const uchar *) resource->readAll().constData(), - QLatin1String(":/metadata")); - } + foreach (const QByteArray &ba, m_resourceMappings) + QResource::unregisterResource((const uchar*) ba.data(), QLatin1String(":/metadata")); } bool notify(QObject *receiver, QEvent *event) @@ -132,14 +127,9 @@ public: return QString(); } - QInstaller::ResourceCollection registeredMetaResources() - { - return resourceMappings; - } - - void registerMetaResources(const QInstaller::ResourceCollection &resources) + void registerMetaResources(const QInstaller::ResourceCollection &collection) { - foreach (const QSharedPointer<QInstaller::Resource> &resource, resources.resources()) { + foreach (const QSharedPointer<QInstaller::Resource> &resource, collection.resources()) { const bool isOpen = resource->isOpen(); if ((!isOpen) && (!resource->open())) continue; @@ -151,20 +141,16 @@ public: if (ba.isEmpty()) continue; - if (QResource::registerResource((const uchar*) ba.data(), QLatin1String(":/metadata"))) { - using namespace QInstaller; - QSharedPointer<QBuffer> buffer(new QBuffer); - buffer->setData(ba); // set the buffers internal data - resourceMappings.appendResource(QSharedPointer<Resource>(new Resource(buffer))); - } + if (QResource::registerResource((const uchar*) ba.data(), QLatin1String(":/metadata"))) + m_resourceMappings.append(ba); - if (!isOpen) // If we reach that point, either the resource was opened already... - resource->close(); // or we did open it and have to close it again. + if (!isOpen) // If we reach that point, either the resource was opened already... + resource->close(); // or we did open it and have to close it again. } } private: - QInstaller::ResourceCollection resourceMappings; + QList<QByteArray> m_resourceMappings; }; #endif // SDKAPP_H diff --git a/src/sdk/updatechecker.cpp b/src/sdk/updatechecker.cpp index 115db45ea..69bfe1732 100644 --- a/src/sdk/updatechecker.cpp +++ b/src/sdk/updatechecker.cpp @@ -72,20 +72,19 @@ int UpdateChecker::check() cookie = QInstaller::BinaryContent::MagicCookie; } - QSharedPointer<QFile> binary(new QFile(fileName)); - QInstaller::openForRead(binary.data()); + QFile binary(fileName); + QInstaller::openForRead(&binary); qint64 magicMarker; - QInstaller::ResourceCollection resources; QList<QInstaller::OperationBlob> operations; QInstaller::ResourceCollectionManager manager; - QInstaller::BinaryContent::readBinaryContent(binary, &resources, &operations, &manager, - &magicMarker, cookie); + QInstaller::BinaryContent::readBinaryContent(&binary, &operations, &manager, &magicMarker, + cookie); if (magicMarker != QInstaller::BinaryContent::MagicInstallerMarker) throw QInstaller::Error(QLatin1String("Installers cannot check for updates.")); - registerMetaResources(resources); // the base class will unregister the resources + SDKApp::registerMetaResources(manager.collectionByName("QResources")); // instantiate the installer we are actually going to use QInstaller::PackageManagerCore core(QInstaller::BinaryContent::MagicUpdaterMarker, operations); diff --git a/tests/auto/installer/binaryformat/tst_binaryformat.cpp b/tests/auto/installer/binaryformat/tst_binaryformat.cpp index 87a1f7ef8..548d4fb1a 100644 --- a/tests/auto/installer/binaryformat/tst_binaryformat.cpp +++ b/tests/auto/installer/binaryformat/tst_binaryformat.cpp @@ -70,7 +70,7 @@ public: virtual bool performOperation() { return true; } virtual bool undoOperation() { return true; } virtual bool testOperation() { return true; } - virtual Operation *clone() const { return 0; } + virtual KDUpdater::UpdateOperation *clone() const { return 0; } }; class tst_BinaryFormat : public QObject @@ -183,42 +183,29 @@ private slots: layout.operationsSegment = Range<qint64>::fromStartAndEnd(start, end); QTemporaryFile data; - QTemporaryFile data2; - { // put into the scope to make the temporary file auto remove feature work - - ResourceCollectionManager manager; - - QInstaller::openForWrite(&data); - QInstaller::blockingWrite(&data, QByteArray("Collection 1, Resource 1.")); - data.close(); - - ResourceCollection collection; - collection.setName(QByteArray("Collection 1")); - - QSharedPointer<Resource> resource(new Resource(data.fileName())); - resource->setName("Resource 1"); - collection.appendResource(resource); - manager.insertCollection(collection); + QInstaller::openForWrite(&data); + QInstaller::blockingWrite(&data, QByteArray("Collection 1, Resource 1.")); + data.close(); - QInstaller::openForWrite(&data2); - QInstaller::blockingWrite(&data2, QByteArray("Collection 2, Resource 2.")); - data2.close(); + QSharedPointer<Resource> resource(new Resource(data.fileName(), QByteArray("Resource 1"))); + ResourceCollection collection(QByteArray("Collection 1")); + collection.appendResource(resource); - ResourceCollection collection2; - collection2.setName(QByteArray("Collection 2")); + QTemporaryFile data2; + QInstaller::openForWrite(&data2); + QInstaller::blockingWrite(&data2, QByteArray("Collection 2, Resource 2.")); + data2.close(); - QSharedPointer<Resource> resource2(new - Resource(data2.fileName())); - resource2->setName("Resource 2"); - collection2.appendResource(resource2); - manager.insertCollection(collection2); + QSharedPointer<Resource> resource2(new Resource(data2.fileName(), QByteArray("Resource 2"))); + ResourceCollection collection2(QByteArray("Collection 2")); + collection2.appendResource(resource2); - layout.collectionCount = manager.collectionCount(); - layout.resourceCollectionsSegment = manager.write(&binary, -layout.endOfExectuable); + ResourceCollectionManager manager; + manager.insertCollection(collection); + manager.insertCollection(collection2); - resource->close(); - resource2->close(); - } + layout.collectionCount = manager.collectionCount(); + layout.resourceCollectionsSegment = manager.write(&binary, -layout.endOfExectuable); QInstaller::appendInt64Range(&binary, layout.resourceCollectionsSegment.moved(-layout .endOfExectuable)); @@ -247,35 +234,35 @@ private slots: void readBinaryContent() { - const QSharedPointer<QFile> binary(new QFile(m_binary)); - QInstaller::openForRead(binary.data()); - QCOMPARE(QInstaller::retrieveData(binary.data(), scTinySize), QByteArray(scTinySize, '1')); + QFile binary(m_binary); + QInstaller::openForRead(&binary); + QCOMPARE(QInstaller::retrieveData(&binary, scTinySize), QByteArray(scTinySize, '1')); Layout layout; - layout.endOfExectuable = binary->pos(); + layout.endOfExectuable = binary.pos(); QCOMPARE(layout.endOfExectuable, m_layout.endOfExectuable); - const qint64 pos = BinaryContent::findMagicCookie(binary.data(), BinaryContent::MagicCookie); + const qint64 pos = BinaryContent::findMagicCookie(&binary, BinaryContent::MagicCookie); layout.endOfBinaryContent = pos + sizeof(qint64); QCOMPARE(layout.endOfBinaryContent, m_layout.endOfBinaryContent); - binary->seek(layout.endOfBinaryContent - (4 * sizeof(qint64))); + binary.seek(layout.endOfBinaryContent - (4 * sizeof(qint64))); - layout.metaSegmentsCount = QInstaller::retrieveInt64(binary.data()); + layout.metaSegmentsCount = QInstaller::retrieveInt64(&binary); QCOMPARE(layout.metaSegmentsCount, m_layout.metaSegmentsCount); const qint64 offsetCollectionIndexSegments = layout.endOfBinaryContent - ((layout.metaSegmentsCount * (2 * sizeof(qint64))) // minus size of the meta segments - + (8 * sizeof(qint64))); // meta count, offset/length component index, marker, cookie... + + (8 * sizeof(qint64))); // meta count, offset/length collection index, marker, cookie... - binary->seek(offsetCollectionIndexSegments); + binary.seek(offsetCollectionIndexSegments); - layout.resourceCollectionsSegment = QInstaller::retrieveInt64Range(binary.data()) + layout.resourceCollectionsSegment = QInstaller::retrieveInt64Range(&binary) .moved(layout.endOfExectuable); QCOMPARE(layout.resourceCollectionsSegment, m_layout.resourceCollectionsSegment); for (int i = 0; i < layout.metaSegmentsCount; ++i) { - layout.metaResourceSegments.append(QInstaller::retrieveInt64Range(binary.data()) + layout.metaResourceSegments.append(QInstaller::retrieveInt64Range(&binary) .moved(layout.endOfExectuable)); } layout.metaResourcesSegment = Range<qint64>::fromStartAndEnd(layout.metaResourceSegments @@ -285,58 +272,58 @@ private slots: QCOMPARE(layout.metaResourceSegments.first(), m_layout.metaResourceSegments.first()); QCOMPARE(layout.metaResourceSegments.last(), m_layout.metaResourceSegments.last()); - layout.operationsSegment = QInstaller::retrieveInt64Range(binary.data()).moved(layout + layout.operationsSegment = QInstaller::retrieveInt64Range(&binary).moved(layout .endOfExectuable); QCOMPARE(layout.operationsSegment, m_layout.operationsSegment); - QCOMPARE(layout.metaSegmentsCount, QInstaller::retrieveInt64(binary.data())); + QCOMPARE(layout.metaSegmentsCount, QInstaller::retrieveInt64(&binary)); - layout.binaryContentSize = QInstaller::retrieveInt64(binary.data()); + layout.binaryContentSize = QInstaller::retrieveInt64(&binary); QCOMPARE(layout.binaryContentSize, m_layout.binaryContentSize); QCOMPARE(layout.endOfExectuable, layout.endOfBinaryContent - layout.binaryContentSize); - layout.magicMarker = QInstaller::retrieveInt64(binary.data()); + layout.magicMarker = QInstaller::retrieveInt64(&binary); QCOMPARE(layout.magicMarker, m_layout.magicMarker); - layout.magicCookie = QInstaller::retrieveInt64(binary.data()); + layout.magicCookie = QInstaller::retrieveInt64(&binary); QCOMPARE(layout.magicCookie, m_layout.magicCookie); - binary->seek(layout.operationsSegment.start()); + binary.seek(layout.operationsSegment.start()); - layout.operationsCount = QInstaller::retrieveInt64(binary.data()); + layout.operationsCount = QInstaller::retrieveInt64(&binary); QCOMPARE(layout.operationsCount, m_layout.operationsCount); for (int i = 0; i < layout.operationsCount; ++i) { - QCOMPARE(m_operations.at(i).name, QInstaller::retrieveString(binary.data())); - QCOMPARE(m_operations.at(i).xml, QInstaller::retrieveString(binary.data())); + QCOMPARE(m_operations.at(i).name, QInstaller::retrieveString(&binary)); + QCOMPARE(m_operations.at(i).xml, QInstaller::retrieveString(&binary)); } - layout.operationsCount = QInstaller::retrieveInt64(binary.data()); + layout.operationsCount = QInstaller::retrieveInt64(&binary); QCOMPARE(layout.operationsCount, m_layout.operationsCount); - layout.collectionCount = QInstaller::retrieveInt64(binary.data()); + layout.collectionCount = QInstaller::retrieveInt64(&binary); QCOMPARE(layout.collectionCount, m_layout.collectionCount); - binary->seek(layout.resourceCollectionsSegment.start()); - m_manager.read(binary, layout.endOfExectuable); + binary.seek(layout.resourceCollectionsSegment.start()); + m_manager.read(&binary, layout.endOfExectuable); - const QList<ResourceCollection> components = m_manager.collections(); - QCOMPARE(components.count(), m_layout.collectionCount); + const QList<ResourceCollection> collections = m_manager.collections(); + QCOMPARE(collections.count(), m_layout.collectionCount); - ResourceCollection component = m_manager.collectionByName("Collection 1"); - QCOMPARE(component.resources().count(), 1); + ResourceCollection collection = m_manager.collectionByName(QByteArray("Collection 1")); + QCOMPARE(collection.resources().count(), 1); - QSharedPointer<Resource> resource(component.resourceByName("Resource 1")); + QSharedPointer<Resource> resource(collection.resourceByName(QByteArray("Resource 1"))); QCOMPARE(resource.isNull(), false); QCOMPARE(resource->isOpen(), false); QCOMPARE(resource->open(), true); QCOMPARE(resource->readAll(), QByteArray("Collection 1, Resource 1.")); resource->close(); - component = m_manager.collectionByName("Collection 2"); - QCOMPARE(component.resources().count(), 1); + collection = m_manager.collectionByName(QByteArray("Collection 2")); + QCOMPARE(collection.resources().count(), 1); - resource = component.resourceByName("Resource 2"); + resource = collection.resourceByName(QByteArray("Resource 2")); QCOMPARE(resource.isNull(), false); QCOMPARE(resource->isOpen(), false); QCOMPARE(resource->open(), true); @@ -346,46 +333,45 @@ private slots: void testWriteBinaryContentFunction() { - QSharedPointer<QFile> existingBinary(new QFile(m_binary)); - QInstaller::openForRead(existingBinary.data()); - - QSharedPointer<QFile> file(new QTemporaryFile); - QInstaller::openForWrite(file.data()); - QInstaller::blockingWrite(file.data(), QByteArray(scTinySize, '1')); - - ResourceCollection resources; - foreach (const Range<qint64> &segment, m_layout.metaResourceSegments) { - resources.appendResource(QSharedPointer<Resource> (new Resource(existingBinary, - segment))); - } + ResourceCollection collection(QByteArray("QResources")); + foreach (const Range<qint64> &segment, m_layout.metaResourceSegments) + collection.appendResource(QSharedPointer<Resource>(new Resource(m_binary, segment))); + m_manager.insertCollection(collection); QList<OperationBlob> operations; foreach (const OperationBlob &operation, m_operations) operations.append(operation); - BinaryContent::writeBinaryContent(file, resources, operations, m_manager, - m_layout.magicMarker, m_layout.magicCookie); - file->close(); - existingBinary->close(); + QTemporaryFile file; + QInstaller::openForWrite(&file); + + QInstaller::blockingWrite(&file, QByteArray(scTinySize, '1')); + BinaryContent::writeBinaryContent(&file, operations, m_manager, m_layout.magicMarker, + m_layout.magicCookie); + file.close(); + + QFile existingBinary(m_binary); + QInstaller::openForRead(&existingBinary); - QInstaller::openForRead(file.data()); - QInstaller::openForRead(existingBinary.data()); - QCOMPARE(file->readAll(), existingBinary->readAll()); + QInstaller::openForRead(&file); + QCOMPARE(file.readAll(), existingBinary.readAll()); } void testReadBinaryContentFunction() { - QSharedPointer<QFile> file(new QFile(m_binary)); - QInstaller::openForRead(file.data()); + QFile file(m_binary); + QInstaller::openForRead(&file); qint64 magicMarker; - ResourceCollection collection; QList<OperationBlob> operations; ResourceCollectionManager manager; - BinaryContent::readBinaryContent(file, &collection, &operations, &manager, &magicMarker, + BinaryContent::readBinaryContent(&file, &operations, &manager, &magicMarker, m_layout.magicCookie); + file.close(); QCOMPARE(magicMarker, m_layout.magicMarker); + + ResourceCollection collection = manager.collectionByName("QResources"); QCOMPARE(collection.resources().count(), m_layout.metaResourceSegments.count()); for (int i = 0; i < collection.resources().count(); ++i) QCOMPARE(collection.resources().at(i)->segment(), m_layout.metaResourceSegments.at(i)); @@ -398,20 +384,20 @@ private slots: QCOMPARE(manager.collectionCount(), m_manager.collectionCount()); - ResourceCollection component = manager.collectionByName("Collection 1"); - QCOMPARE(component.resources().count(), 1); + collection = manager.collectionByName(QByteArray("Collection 1")); + QCOMPARE(collection.resources().count(), 1); - QSharedPointer<Resource> resource(component.resourceByName("Resource 1")); + QSharedPointer<Resource> resource(collection.resourceByName(QByteArray("Resource 1"))); QCOMPARE(resource.isNull(), false); QCOMPARE(resource->isOpen(), false); QCOMPARE(resource->open(), true); QCOMPARE(resource->readAll(), QByteArray("Collection 1, Resource 1.")); resource->close(); - component = manager.collectionByName("Collection 2"); - QCOMPARE(component.resources().count(), 1); + collection = manager.collectionByName(QByteArray("Collection 2")); + QCOMPARE(collection.resources().count(), 1); - resource = component.resourceByName("Resource 2"); + resource = collection.resourceByName(QByteArray("Resource 2")); QCOMPARE(resource.isNull(), false); QCOMPARE(resource->isOpen(), false); QCOMPARE(resource->open(), true); @@ -421,7 +407,7 @@ private slots: void cleanupTestCase() { - m_manager.reset(); + m_manager.clear(); QFile::remove(m_binary); } diff --git a/tools/binarycreator/binarycreator.cpp b/tools/binarycreator/binarycreator.cpp index 1a14c4bf0..6b40f44d3 100644 --- a/tools/binarycreator/binarycreator.cpp +++ b/tools/binarycreator/binarycreator.cpp @@ -52,10 +52,12 @@ #include <settings.h> #include <utils.h> -#include <QtCore/QDirIterator> -#include <QtCore/QProcess> -#include <QtCore/QSettings> -#include <QtCore/QTemporaryFile> +#include <QDateTime> +#include <QDirIterator> +#include <QDomDocument> +#include <QProcess> +#include <QSettings> +#include <QTemporaryFile> #include <QTemporaryDir> #include <iostream> @@ -66,7 +68,7 @@ struct Input { QString outputPath; QString installerExePath; QInstallerTools::PackageInfoVector packages; - QInstaller::ResourceCollection metaCollection; + QInstaller::ResourceCollectionManager manager; }; class BundleBackup @@ -250,7 +252,7 @@ static int assemble(Input input, const QInstaller::Settings &settings) } #endif - QSharedPointer<QTemporaryFile> out(new QTemporaryFile); + QTemporaryFile out; QString targetName = input.outputPath; #ifdef Q_OS_OSX QDir resourcePath(QFileInfo(input.outputPath).dir()); @@ -270,7 +272,7 @@ static int assemble(Input input, const QInstaller::Settings &settings) } try { - QInstaller::openForWrite(out.data()); + QInstaller::openForWrite(&out); QFile exe(input.installerExePath); #ifdef Q_OS_OSX @@ -280,10 +282,9 @@ static int assemble(Input input, const QInstaller::Settings &settings) } #else QInstaller::openForRead(&exe); - QInstaller::appendData(out.data(), &exe, exe.size()); + QInstaller::appendData(&out, &exe, exe.size()); #endif - QInstaller::ResourceCollectionManager manager; foreach (const QInstallerTools::PackageInfo &info, input.packages) { QInstaller::ResourceCollection collection; collection.setName(info.name.toUtf8()); @@ -295,11 +296,11 @@ static int assemble(Input input, const QInstaller::Settings &settings) humanReadableSize(resource->size())); collection.appendResource(resource); } - manager.insertCollection(collection); + input.manager.insertCollection(collection); } const QList<QInstaller::OperationBlob> operations; - BinaryContent::writeBinaryContent(out, input.metaCollection, operations, manager, + BinaryContent::writeBinaryContent(&out, operations, input.manager, BinaryContent::MagicInstallerMarker, BinaryContent::MagicCookie); } catch (const Error &e) { qCritical("Error occurred while assembling the installer: %s", qPrintable(e.message())); @@ -307,16 +308,16 @@ static int assemble(Input input, const QInstaller::Settings &settings) return EXIT_FAILURE; } - if (!out->rename(targetName)) { + if (!out.rename(targetName)) { qCritical("Could not write installer to %s: %s", targetName.toUtf8().constData(), - out->errorString().toUtf8().constData()); + out.errorString().toUtf8().constData()); QFile::remove(tempFile); return EXIT_FAILURE; } - out->setAutoRemove(false); + out.setAutoRemove(false); #ifndef Q_OS_WIN - chmod755(out->fileName()); + chmod755(out.fileName()); #endif QFile::remove(tempFile); @@ -402,8 +403,8 @@ static QSharedPointer<QInstaller::Resource> createDefaultResourceFile(const QStr throw Error(QString::fromLatin1("Could not compile rcc project file.")); } - return QSharedPointer<QInstaller::Resource>(new QInstaller::Resource(binaryName.toUtf8(), - binaryName)); + return QSharedPointer<QInstaller::Resource>(new QInstaller::Resource(binaryName, binaryName + .toUtf8())); } static @@ -420,8 +421,8 @@ QList<QSharedPointer<QInstaller::Resource> > createBinaryResourceFiles(const QSt if (status != EXIT_SUCCESS) continue; - result.append(QSharedPointer<QInstaller::Resource> (new QInstaller::Resource(binaryName - .toUtf8(), binaryName))); + result.append(QSharedPointer<QInstaller::Resource> (new QInstaller::Resource(binaryName, + binaryName.toUtf8()))); } } return result; @@ -731,9 +732,12 @@ int main(int argc, char **argv) input.packages = packages; input.outputPath = target; input.installerExePath = templateBinary; - input.metaCollection.appendResource(createDefaultResourceFile(tmpMetaDir, + + QInstaller::ResourceCollection metaCollection("QResources"); + metaCollection.appendResource(createDefaultResourceFile(tmpMetaDir, generateTemporaryFileName())); - input.metaCollection.appendResources(createBinaryResourceFiles(resources)); + metaCollection.appendResources(createBinaryResourceFiles(resources)); + input.manager.insertCollection(metaCollection); qDebug() << "Creating the binary"; exitCode = assemble(input, settings); @@ -750,7 +754,8 @@ int main(int argc, char **argv) } qDebug() << "Cleaning up..."; - foreach (const QSharedPointer<QInstaller::Resource> &resource, input.metaCollection.resources()) + const QInstaller::ResourceCollection collection = input.manager.collectionByName("QResources"); + foreach (const QSharedPointer<QInstaller::Resource> &resource, collection.resources()) QFile::remove(QString::fromUtf8(resource->name())); QInstaller::removeDirectory(tmpMetaDir, true); diff --git a/tools/devtool/binarydump.cpp b/tools/devtool/binarydump.cpp index 8c73d7642..7efa13960 100644 --- a/tools/devtool/binarydump.cpp +++ b/tools/devtool/binarydump.cpp @@ -126,13 +126,17 @@ int BinaryDump::dump(const QInstaller::ResourceCollectionManager &manager, const continue; foreach (const QSharedPointer<QInstaller::Resource> &resource, c.resources()) { - if (!resource->open()) + const bool isOpen = resource->isOpen(); + if ((!isOpen) && (!resource->open())) continue; // TODO: should we throw here? QFile target(targetDir.filePath(fileName) + QDir::separator() + QString::fromUtf8(resource->name())); QInstaller::openForWrite(&target); resource->copyData(&target); // copy the 7z files into the target directory + + if (!isOpen) // If we reach that point, either the resource was opened already... + resource->close(); // or we did open it and have to close it again. } } result = EXIT_SUCCESS; diff --git a/tools/devtool/main.cpp b/tools/devtool/main.cpp index 9ef611ce2..61be6c9f7 100644 --- a/tools/devtool/main.cpp +++ b/tools/devtool/main.cpp @@ -136,24 +136,27 @@ int main(int argc, char *argv[]) } } - QSharedPointer<QFile> file(new QFile(path)); - QInstaller::openForRead(file.data()); + QFile file(path); + QInstaller::openForRead(&file); qint64 magicMarker; - QInstaller::ResourceCollection meta; QList<QInstaller::OperationBlob> operations; QInstaller::ResourceCollectionManager manager; - QInstaller::BinaryContent::readBinaryContent(file, &meta, &operations, &manager, - &magicMarker, cookie); + QInstaller::BinaryContent::readBinaryContent(&file, &operations, &manager, &magicMarker, + cookie); // map the inbuilt resources + const QInstaller::ResourceCollection meta = manager.collectionByName("QResources"); foreach (const QSharedPointer<QInstaller::Resource> &resource, meta.resources()) { - const bool opened = resource->open(); + const bool isOpen = resource->isOpen(); + if ((!isOpen) && (!resource->open())) + continue; // TODO: should we throw here? + const QByteArray ba = resource->readAll(); if (!QResource::registerResource((const uchar*) ba.data(), QLatin1String(":/metadata"))) throw QInstaller::Error(QLatin1String("Could not register in-binary resource.")); resourceMappings.append(ba); - if (opened) + if (!isOpen) resource->close(); } |