summaryrefslogtreecommitdiffstats
path: root/src/libs/installer
diff options
context:
space:
mode:
authorkh1 <karsten.heimrich@digia.com>2014-10-14 17:03:54 +0200
committerKarsten Heimrich <karsten.heimrich@digia.com>2014-10-15 17:10:18 +0200
commit84875396b75f5615afa637f9633d19bbc79e08e0 (patch)
tree012fe931425ae267361a608c0c63e0d05e4ee03e /src/libs/installer
parentec92e19193eb9d69a3cf18979d6434cf04764902 (diff)
Overhaul the binary format API.
Adjust some naming. Add documentation. Make the Resource class handle files only, this is sufficient to read and map inbuild resources. Keep the QResources inside the manager as well, no need to handle them separate. Remove read, write functions from collection class, the API was just unclear how to use. Still it is far from intuitive in the manager class either. If we open a Resource, we need to close it on our own case they are pointers. Change-Id: Ic8aa32a84a15ac774fe1194ba0dbb5733f7216d6 Reviewed-by: Leena Miettinen <riitta-leena.miettinen@digia.com> Reviewed-by: Kai Koehne <kai.koehne@theqtcompany.com>
Diffstat (limited to 'src/libs/installer')
-rw-r--r--src/libs/installer/binarycontent.cpp136
-rw-r--r--src/libs/installer/binarycontent.h6
-rw-r--r--src/libs/installer/binaryformat.cpp393
-rw-r--r--src/libs/installer/binaryformat.h41
-rw-r--r--src/libs/installer/binaryformatengine.cpp34
-rw-r--r--src/libs/installer/binaryformatenginehandler.cpp37
-rw-r--r--src/libs/installer/binaryformatenginehandler.h2
-rw-r--r--src/libs/installer/binarylayout.cpp21
-rw-r--r--src/libs/installer/createlocalrepositoryoperation.cpp16
-rw-r--r--src/libs/installer/packagemanagercore_p.cpp2
10 files changed, 392 insertions, 296 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