summaryrefslogtreecommitdiffstats
path: root/installerbuilder/common/binaryformat.cpp
diff options
context:
space:
mode:
authorkh1 <karsten.heimrich@nokia.com>2012-03-13 16:38:56 +0100
committerKarsten Heimrich <karsten.heimrich@nokia.com>2012-03-13 19:49:28 +0100
commit06100e103459d0149c8c3c37e524715e7e7fbdd5 (patch)
tree9ca460952b2e4787ca38e2b7d3e36c400996f895 /installerbuilder/common/binaryformat.cpp
parentb294bdc12d2523be67584b3fb200ca612f0d1e06 (diff)
Keep common just for the tools.
All other files should be in the lib anyway. Fix includes. Change-Id: I654fadf0a77b8d19953a6b47820e6398af11e2df Reviewed-by: Tim Jenssen <tim.jenssen@nokia.com>
Diffstat (limited to 'installerbuilder/common/binaryformat.cpp')
-rw-r--r--installerbuilder/common/binaryformat.cpp1115
1 files changed, 0 insertions, 1115 deletions
diff --git a/installerbuilder/common/binaryformat.cpp b/installerbuilder/common/binaryformat.cpp
deleted file mode 100644
index 133df3690..000000000
--- a/installerbuilder/common/binaryformat.cpp
+++ /dev/null
@@ -1,1115 +0,0 @@
-/**************************************************************************
-**
-** This file is part of Installer Framework
-**
-** Copyright (c) 2011-2012 Nokia Corporation and/or its subsidiary(-ies).
-**
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-**
-** GNU Lesser General Public License Usage
-**
-** This file may be used under the terms of the GNU Lesser General Public
-** License version 2.1 as published by the Free Software Foundation and
-** appearing in the file LICENSE.LGPL included in the packaging of this file.
-** Please review the following information to ensure the GNU Lesser General
-** Public License version 2.1 requirements will be met:
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** Other Usage
-**
-** Alternatively, this file may be used in accordance with the terms and
-** conditions contained in a signed written agreement between you and Nokia.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**************************************************************************/
-
-#include "binaryformat.h"
-
-#include "errors.h"
-#include "fileutils.h"
-#include "lib7z_facade.h"
-#include "utils.h"
-#include "zipjob.h"
-
-#include <kdupdaterupdateoperationfactory.h>
-
-#include <QtCore/QResource>
-#include <QtCore/QTemporaryFile>
-
-#include <errno.h>
-
-using namespace QInstaller;
-using namespace QInstallerCreator;
-
-/*
-TRANSLATOR QInstallerCreator::Archive
-*/
-
-/*
-TRANSLATOR QInstallerCreator::Component
-*/
-
-static inline QByteArray &theBuffer(int size)
-{
- static QByteArray b;
- if (size > b.size())
- b.resize(size);
- return b;
-}
-
-void QInstaller::appendFileData(QIODevice *out, QIODevice *in)
-{
- Q_ASSERT(!in->isSequential());
- const qint64 size = in->size();
- blockingCopy(in, out, size);
-}
-
-
-void QInstaller::retrieveFileData(QIODevice *out, QIODevice *in)
-{
- qint64 size = QInstaller::retrieveInt64(in);
- appendData(in, out, size);
-/* QByteArray &b = theBuffer(size);
- blockingRead(in, b.data(), size);
- blockingWrite(out, b.constData(), size);*/
-}
-
-void QInstaller::appendInt64(QIODevice *out, qint64 n)
-{
- blockingWrite(out, reinterpret_cast<const char*>(&n), sizeof(n));
-}
-
-void QInstaller::appendInt64Range(QIODevice *out, const Range<qint64> &r)
-{
- appendInt64(out, r.start());
- appendInt64(out, r.length());
-}
-
-qint64 QInstaller::retrieveInt64(QIODevice *in)
-{
- qint64 n = 0;
- blockingRead(in, reinterpret_cast<char*>(&n), sizeof(n));
- return n;
-}
-
-Range<qint64> QInstaller::retrieveInt64Range(QIODevice *in)
-{
- const quint64 start = retrieveInt64(in);
- const quint64 length = retrieveInt64(in);
- return Range<qint64>::fromStartAndLength(start, length);
-}
-
-void QInstaller::appendData(QIODevice *out, QIODevice *in, qint64 size)
-{
- while (size > 0) {
- const qint64 nextSize = qMin(size, 16384LL);
- QByteArray &b = theBuffer(nextSize);
- blockingRead(in, b.data(), nextSize);
- blockingWrite(out, b.constData(), nextSize);
- size -= nextSize;
- }
-}
-
-void QInstaller::appendString(QIODevice *out, const QString &str)
-{
- appendByteArray(out, str.toUtf8());
-}
-
-void QInstaller::appendByteArray(QIODevice *out, const QByteArray &ba)
-{
- appendInt64(out, ba.size());
- blockingWrite(out, ba.constData(), ba.size());
-}
-
-void QInstaller::appendStringList(QIODevice *out, const QStringList &list)
-{
- appendInt64(out, list.size());
- foreach (const QString &s, list)
- appendString(out, s);
-}
-
-void QInstaller::appendDictionary(QIODevice *out, const QHash<QString,QString> &dict)
-{
- appendInt64(out, dict.size());
- foreach (const QString &key, dict.keys()) {
- appendString(out, key);
- appendString(out, dict.value(key));
- }
-}
-
-qint64 QInstaller::appendCompressedData(QIODevice *out, QIODevice *in, qint64 size)
-{
- QByteArray ba;
- ba.resize(size);
- blockingRead(in, ba.data(), size);
-
- QByteArray cba = qCompress(ba);
- blockingWrite(out, cba, cba.size());
- return cba.size();
-}
-
-QString QInstaller::retrieveString(QIODevice *in)
-{
- const QByteArray b = retrieveByteArray(in);
- return QString::fromUtf8(b);
-}
-
-QByteArray QInstaller::retrieveByteArray(QIODevice *in)
-{
- QByteArray ba;
- const qint64 n = retrieveInt64(in);
- ba.resize(n);
- blockingRead(in, ba.data(), n);
- return ba;
-}
-
-QStringList QInstaller::retrieveStringList(QIODevice *in)
-{
- QStringList list;
- for (qint64 i = retrieveInt64(in); --i >= 0;)
- list << retrieveString(in);
- return list;
-}
-
-QHash<QString,QString> QInstaller::retrieveDictionary(QIODevice *in)
-{
- QHash<QString,QString> dict;
- for (qint64 i = retrieveInt64(in); --i >= 0;) {
- QString key = retrieveString(in);
- dict.insert(key, retrieveString(in));
- }
- return dict;
-}
-
-QByteArray QInstaller::retrieveData(QIODevice *in, qint64 size)
-{
- QByteArray ba;
- ba.resize(size);
- blockingRead(in, ba.data(), size);
- return ba;
-}
-
-QByteArray QInstaller::retrieveCompressedData(QIODevice *in, qint64 size)
-{
- QByteArray ba;
- ba.resize(size);
- blockingRead(in, ba.data(), size);
- return qUncompress(ba);
-}
-
-qint64 QInstaller::findMagicCookie(QFile *in, quint64 magicCookie)
-{
- Q_ASSERT(in);
- Q_ASSERT(in->isOpen());
- Q_ASSERT(in->isReadable());
- const qint64 oldPos = in->pos();
- const qint64 MAX_SEARCH = 1024 * 1024; // stop searching after one MB
- qint64 searched = 0;
- try {
- while (searched < MAX_SEARCH) {
- const qint64 pos = in->size() - searched - sizeof(qint64);
- if (pos < 0)
- throw Error(QObject::tr("Searched whole file, no marker found"));
- if (!in->seek(pos)) {
- throw Error(QObject::tr("Could not seek to %1 in file %2: %3").arg(QString::number(pos),
- in->fileName(), in->errorString()));
- }
- const quint64 num = static_cast<quint64>(retrieveInt64(in));
- if (num == magicCookie) {
- in->seek(oldPos);
- return pos;
- }
- searched += 1;
- }
- throw Error(QObject::tr("No marker found, stopped after %1 bytes.").arg(QString::number(MAX_SEARCH)));
- } catch (const Error& err) {
- in->seek(oldPos);
- throw err;
- } catch (...) {
- in->seek(oldPos);
- throw Error(QObject::tr("No marker found, unknown exception caught."));
- }
- return -1; // never reached
-}
-
-/*!
- Creates an archive providing the data in \a path.
- \a path can be a path to a file or to a directory. If it's a file, it's considered to be
- pre-zipped and gets delivered as it is. If it's a directory, it gets zipped by Archive.
- */
-Archive::Archive(const QString &path)
- : m_device(0),
- m_isTempFile(false),
- m_path(path),
- m_name(QFileInfo(path).fileName().toUtf8())
-{
-}
-
-Archive::Archive(const QByteArray &identifier, const QByteArray &data)
- : m_device(0),
- m_isTempFile(true),
- m_path(generateTemporaryFileName()),
- m_name(identifier)
-{
- QFile file(m_path);
- file.open(QIODevice::WriteOnly);
- file.write(data);
-}
-
-/*!
- Creates an archive identified by \a identifier providing a data \a segment within a \a device.
- */
-Archive::Archive(const QByteArray &identifier, const QSharedPointer<QFile> &device, const Range<qint64> &segment)
- : m_device(device),
- m_segment(segment),
- m_isTempFile(false),
- m_name(identifier)
-{
-}
-
-Archive::~Archive()
-{
- if (isOpen())
- close();
- if (m_isTempFile)
- QFile::remove(m_path);
-}
-
-/*!
- Copies the archives contents to the path \a name.
- If the archive is a zipped directory, \a name is treated as a directory. The archive gets extracted there.
-
- If the archive is a plain file and \a name an existing directory, it gets created
- with it's name. Otherwise it gets saved as \a name.
- Note that if a file with the \a name already exists, copy() return false (i.e. Archive will not overwrite it).
- */
-bool Archive::copy(const QString &name)
-{
- const QFileInfo fileInfo(name);
- if (isZippedDirectory()) {
- if (fileInfo.exists() && !fileInfo.isDir())
- return false;
-
- errno = 0;
- const QString absoluteFilePath = fileInfo.absoluteFilePath();
- if (!fileInfo.exists() && !QDir().mkpath(absoluteFilePath)) {
- setErrorString(tr("Could not create %1: %2").arg(name, QString::fromLocal8Bit(strerror(errno))));
- return false;
- }
-
- if (isOpen())
- close();
- open(QIODevice::ReadOnly);
-
- UnzipJob job;
- job.setInputDevice(this);
- job.setOutputPath(absoluteFilePath);
- job.run();
- } else {
- if (isOpen())
- close();
- open(QIODevice::ReadOnly);
-
- QFile target(fileInfo.isDir() ? QString::fromLatin1("%1/%2").arg(name)
- .arg(QString::fromUtf8(m_name.data(), m_name.count())) : name);
- if (target.exists())
- return false;
- target.open(QIODevice::WriteOnly);
- blockingCopy(this, &target, size());
- }
- close();
- return true;
-}
-
-/*!
- \reimp
- */
-bool Archive::seek(qint64 pos)
-{
- if (m_inputFile.isOpen())
- return m_inputFile.seek(pos) && QIODevice::seek(pos);
- return QIODevice::seek(pos);
-}
-
-/*!
- Returns true, if this archive was created by zipping a directory.
- */
-bool Archive::isZippedDirectory() const
-{
- if (m_device == 0) {
- // easy, just check whether it's a dir
- return QFileInfo(m_path).isDir();
- }
-
- // more complex, check the zip header magic
- Archive* const arch = const_cast<Archive*> (this);
-
- const bool notOpened = !isOpen();
- if (notOpened)
- arch->open(QIODevice::ReadOnly);
- const qint64 p = pos();
- arch->seek(0);
-
- const QByteArray ba = arch->read(4);
- const bool result = ba == QByteArray("\x50\x4b\x03\04");
-
- arch->seek(p);
- if (notOpened)
- arch->close();
- return result;
-}
-
-QByteArray Archive::name() const
-{
- return m_name;
-}
-
-void Archive::setName(const QByteArray &name)
-{
- m_name = name;
-}
-
-/*!
- \reimpl
- */
-void Archive::close()
-{
- m_inputFile.close();
- if (QFileInfo(m_path).isDir())
- m_inputFile.remove();
- QIODevice::close();
-}
-
-/*!
- \reimp
- */
-bool Archive::open(OpenMode mode)
-{
- if (isOpen())
- return false;
-
- const bool writeOnly = (mode & QIODevice::WriteOnly) != QIODevice::NotOpen;
- const bool append = (mode & QIODevice::Append) != QIODevice::NotOpen;
-
- // no write support
- if (writeOnly || append)
- return false;
-
- if (m_device != 0)
- return QIODevice::open(mode);
-
- const QFileInfo fi(m_path);
- if (fi.isFile()) {
- m_inputFile.setFileName(m_path);
- if (!m_inputFile.open(mode)) {
- setErrorString(tr("Could not open archive file %1 for reading.").arg(m_path));
- return false;
- }
- setOpenMode(mode);
- return true;
- }
-
- if (fi.isDir()) {
- if (m_inputFile.fileName().isEmpty() || !m_inputFile.exists()) {
- if (!createZippedFile())
- return false;
- }
- Q_ASSERT(!m_inputFile.fileName().isEmpty());
- if (!m_inputFile.open(mode))
- return false;
- setOpenMode(mode);
- return true;
- }
-
- setErrorString(tr("Could not create archive from %1: Not a file.").arg(m_path));
- return false;
-}
-
-bool Archive::createZippedFile()
-{
- QTemporaryFile file;
- file.setAutoRemove(false);
- if (!file.open())
- return false;
-
- m_inputFile.setFileName(file.fileName());
- file.close();
- m_inputFile.open(QIODevice::ReadWrite);
- try {
- Lib7z::createArchive(&m_inputFile, QStringList() << m_path);
- } catch(Lib7z::SevenZipException &e) {
- m_inputFile.close();
- setErrorString(e.message());
- return false;
- }
-
- if (!Lib7z::isSupportedArchive(&m_inputFile)) {
- m_inputFile.close();
- setErrorString(tr("Error while packing directory at %1").arg(m_path));
- return false;
- }
- m_inputFile.close();
- return true;
-}
-
-/*!
- \reimp
- */
-qint64 Archive::size() const
-{
- // if we got a device, we just pass the length of the segment
- if (m_device != 0)
- return m_segment.length();
-
- const QFileInfo fi(m_path);
- // if we got a regular file, we pass the size of the file
- if (fi.isFile())
- return fi.size();
-
- if (fi.isDir()) {
- if (m_inputFile.fileName().isEmpty() || !m_inputFile.exists()) {
- if (!const_cast< Archive* >(this)->createZippedFile()) {
- throw Error(QObject::tr("Cannot create zipped file for path %1: %2").arg(m_path,
- errorString()));
- }
- }
- Q_ASSERT(!m_inputFile.fileName().isEmpty());
- return m_inputFile.size();
- }
- return 0;
-}
-
-/*!
- \reimp
- */
-qint64 Archive::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);
- return amountRead;
-}
-
-/*!
- \reimp
- */
-qint64 Archive::writeData(const char* data, qint64 maxSize)
-{
- Q_UNUSED(data);
- Q_UNUSED(maxSize);
- // should never be called, as we're read only
- return -1;
-}
-
-QByteArray Component::name() const
-{
- return m_name;
-}
-
-void Component::setName(const QByteArray &ba)
-{
- m_name = ba;
-}
-
-Range<qint64> Component::binarySegment() const
-{
- return m_binarySegment;
-}
-
-void Component::setBinarySegment(const Range<qint64> &r)
-{
- m_binarySegment = r;
-}
-
-Component Component::readFromIndexEntry(const QSharedPointer<QFile> &in, qint64 offset)
-{
- Component c;
- c.m_name = retrieveByteArray(in.data());
- c.m_binarySegment = retrieveInt64Range(in.data()).moved(offset);
-
- c.readData(in, offset);
-
- return c;
-}
-
-void Component::writeIndexEntry(QIODevice *out, qint64 positionOffset) const
-{
- appendByteArray(out, m_name);
- const Range<qint64> relative = m_binarySegment.moved(positionOffset);
- appendInt64(out, binarySegment().start());
- appendInt64(out, binarySegment().length());
-}
-
-void Component::writeData(QIODevice *out, qint64 offset) const
-{
- const qint64 dataBegin = out->pos() + offset;
-
- appendInt64(out, m_archives.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 archive (the size of the table)
- foreach (const QSharedPointer<Archive> &archive, m_archives)
- start += foo + archive->name().count();
-
- QList<qint64> starts;
- foreach (const QSharedPointer<Archive> &archive, m_archives) {
- appendByteArray(out, archive->name());
- starts.push_back(start);
- appendInt64Range(out, Range<qint64>::fromStartAndLength(start, archive->size()));
- start += archive->size();
- }
-
- foreach (const QSharedPointer<Archive> &archive, m_archives) {
- if (!archive->open(QIODevice::ReadOnly)) {
- throw Error(tr("Could not open archive %1: %2").arg(QLatin1String(archive->name()),
- archive->errorString()));
- }
-
- const qint64 expectedStart = starts.takeFirst();
- const qint64 actualStart = out->pos() + offset;
- Q_UNUSED(expectedStart);
- Q_UNUSED(actualStart);
- Q_ASSERT(expectedStart == actualStart);
- blockingCopy(archive.data(), out, archive->size());
- }
-
- m_binarySegment = Range<qint64>::fromStartAndEnd(dataBegin, out->pos() + offset);
-}
-
-void Component::readData(const QSharedPointer<QFile> &in, qint64 offset)
-{
- const qint64 pos = in->pos();
-
- in->seek(m_binarySegment.start());
- const qint64 count = retrieveInt64(in.data());
-
- QVector<QByteArray> names;
- QVector<Range<qint64> > ranges;
- for (int i = 0; i < count; ++i) {
- names.push_back(retrieveByteArray(in.data()));
- ranges.push_back(retrieveInt64Range(in.data()).moved(offset));
- }
-
- for (int i = 0; i < ranges.count(); ++i)
- m_archives.append(QSharedPointer<Archive>(new Archive(names.at(i), in, ranges.at(i))));
-
- in->seek(pos);
-}
-
-QString Component::dataDirectory() const
-{
- return m_dataDirectory;
-}
-
-void Component::setDataDirectory(const QString &path)
-{
- m_dataDirectory = path;
-}
-
-bool Component::operator<(const Component& other) const
-{
- if (m_name != other.name())
- return m_name < other.m_name;
- return m_binarySegment < other.m_binarySegment;
-}
-
-bool Component::operator==(const Component& other) const
-{
- return m_name == other.m_name && m_binarySegment == other.m_binarySegment;
-}
-
-/*!
- Destroys this component.
- */
-Component::~Component()
-{
-}
-
-/*!
- Appends \a archive to this component. The component takes ownership of \a archive.
- */
-void Component::appendArchive(const QSharedPointer<Archive>& archive)
-{
- Q_ASSERT(archive);
- archive->setParent(0);
- m_archives.push_back(archive);
-}
-
-/*!
- Returns the archives associated with this component.
- */
-QVector<QSharedPointer<Archive> > Component::archives() const
-{
- return m_archives;
-}
-
-QSharedPointer<Archive> Component::archiveByName(const QByteArray &name) const
-{
- foreach (const QSharedPointer<Archive>& i, m_archives) {
- if (i->name() == name)
- return i;
- }
- return QSharedPointer<Archive>();
-}
-
-
-// -- ComponentIndex
-
-ComponentIndex::ComponentIndex()
-{
-}
-
-ComponentIndex ComponentIndex::read(const QSharedPointer<QFile> &dev, qint64 offset)
-{
- ComponentIndex result;
- const qint64 size = retrieveInt64(dev.data());
- for (int i = 0; i < size; ++i)
- result.insertComponent(Component::readFromIndexEntry(dev, offset));
- retrieveInt64(dev.data());
- return result;
-}
-
-void ComponentIndex::writeIndex(QIODevice *out, qint64 offset) const
-{
- // 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
- appendInt64(out, componentCount());
- foreach (const Component& i, components())
- i.writeIndexEntry(out, offset);
- appendInt64(out, componentCount());
-}
-
-void ComponentIndex::writeComponentData(QIODevice *out, qint64 offset) const
-{
- appendInt64(out, componentCount());
-
- foreach (const Component &component, m_components)
- component.writeData(out, offset);
-}
-
-Component ComponentIndex::componentByName(const QByteArray &id) const
-{
- return m_components.value(id);
-}
-
-void ComponentIndex::insertComponent(const Component& c)
-{
- m_components.insert(c.name(), c);
-}
-
-void ComponentIndex::removeComponent(const QByteArray &name)
-{
- m_components.remove(name);
-}
-
-QVector<Component> ComponentIndex::components() const
-{
- return m_components.values().toVector();
-}
-
-int ComponentIndex::componentCount() const
-{
- return m_components.size();
-}
-
-
-static QVector<QByteArray> sResourceVec;
-/*!
- \internal
- Registers the resource found at \a segment within \a file into the Qt resource system.
- */
-static const uchar* addResourceFromBinary(QFile* file, const Range<qint64> &segment)
-{
- if (segment.length() <= 0)
- return 0;
-
- if (!file->seek(segment.start())) {
- throw Error(QObject::tr("Could not seek to in-binary resource. (offset: %1, length: %2)")
- .arg(QString::number(segment.start()), QString::number(segment.length())));
- }
- sResourceVec.append(retrieveData(file, segment.length()));
-
- if (!QResource::registerResource((const uchar*)(sResourceVec.last().constData()),
- QLatin1String(":/metadata"))) {
- throw Error(QObject::tr("Could not register in-binary resource."));
- }
- return (const uchar*)(sResourceVec.last().constData());
-}
-
-
-// -- BinaryContentPrivate
-
-BinaryContentPrivate::BinaryContentPrivate(const QString &path)
- : m_magicMarker(0)
- , m_dataBlockStart(0)
- , m_appBinary(new QFile(path))
- , m_binaryDataFile(0)
- , m_binaryFormatEngineHandler(m_componentIndex)
-{
-}
-
-BinaryContentPrivate::BinaryContentPrivate(const BinaryContentPrivate &other)
- : QSharedData(other)
- , m_magicMarker(other.m_magicMarker)
- , m_dataBlockStart(other.m_dataBlockStart)
- , m_appBinary(other.m_appBinary)
- , m_binaryDataFile(other.m_binaryDataFile)
- , m_performedOperations(other.m_performedOperations)
- , m_performedOperationsData(other.m_performedOperationsData)
- , m_resourceMappings(other.m_resourceMappings)
- , m_metadataResourceSegments(other.m_metadataResourceSegments)
- , m_componentIndex(other.m_componentIndex)
- , m_binaryFormatEngineHandler(other.m_binaryFormatEngineHandler)
-{
-}
-
-BinaryContentPrivate::~BinaryContentPrivate()
-{
- foreach (const uchar *rccData, m_resourceMappings)
- QResource::unregisterResource(rccData);
- sResourceVec.clear();
- m_resourceMappings.clear();
-}
-
-
-// -- BinaryContent
-
-BinaryContent::BinaryContent(const QString &path)
- : d(new BinaryContentPrivate(path))
-{
-}
-
-BinaryContent::~BinaryContent()
-{
-}
-
-/*!
- Reads binary content stored in the current application binary. Maps the embedded resources into memory
- and instantiates performed operations if available.
-*/
-BinaryContent BinaryContent::readAndRegisterFromApplicationFile()
-{
- BinaryContent c = BinaryContent::readFromApplicationFile();
- c.registerEmbeddedQResources();
- c.registerPerformedOperations();
- return c;
-}
-
-/*!
- Reads binary content stored in the passed application binary. Maps the embedded resources into memory
- and instantiates performed operations if available.
-*/
-BinaryContent BinaryContent::readAndRegisterFromBinary(const QString &path)
-{
- BinaryContent c = BinaryContent::readFromBinary(path);
- c.registerEmbeddedQResources();
- c.registerPerformedOperations();
- return c;
-}
-
-/*!
- Reads binary content stored in the current application binary.
-*/
-BinaryContent BinaryContent::readFromApplicationFile()
-{
- return BinaryContent::readFromBinary(QCoreApplication::applicationFilePath());;
-}
-
-/*!
- * \class QInstaller::BinaryContent
- *
- * BinaryContent handles binary information embedded into executables.
- * Qt resources as well as component information can be stored.
- *
- * Explanation of the binary blob at the end of the installer or separate data file:
- *
- * \verbatim
- * Meta data segment 0
- * Meta data segment ...
- * Meta data segment n
- * ------------------------------------------------------
- * Component data segment 0
- * Component data segment ..
- * Component data segment n
- * ------------------------------------------------------
- * Component index segment
- * ------------------------------------------------------
- * quint64 offset of component index segment
- * quint64 length of component index segment
- * ------------------------------------------------------
- * qint64 offset of meta data segment 0
- * qint64 length of meta data segment 0
- * qint64 offset of meta data segment ..
- * qint64 length of meta data segment ..
- * qint64 offset of meta data segment n
- * qint64 length of meta data segment n
- * ------------------------------------------------------
- * operations start offest
- * operations end
- * quint64 embedded resource count
- * quint64 data block size
- * quint64 Magic marker
- * quint64 Magic cookie (0xc2 0x63 0x0a 0x1c 0x99 0xd6 0x68 0xf8)
- * <eof>
- *
- * All offsets are addresses relative to the end of the file.
- *
- * Meta data segments are stored as Qt resources, which must be "mounted"
- * via QResource::registerResource()
- *
- * Component index segment:
- * quint64 number of index entries
- * QString identifier of component 0
- * quint64 offset of component data segment 0
- * quint64 length of component data segment 0
- * QString identifier of component ..
- * quint64 offset of component data segment ..
- * quint64 length of component data segment ..
- * QString identifier of component n
- * quint64 offset of component data segment n
- * quint64 length of component data segment n
- * quint64 number of index entries
- *
- * Component data segment:
- * quint64 number of archives in this component
- * QString name of archive 0
- * quint64 offset of archive 0
- * quint64 length of archive 0
- * QString name of archive ..
- * quint64 offset of archive ..
- * quint64 length of archive ..
- * QString name of archive n
- * quint64 offset of archive n
- * quint64 length of archive n
- * Archive 0
- * Archive ..
- * Archive n
- * \endverbatim
- */
-
-BinaryContent BinaryContent::readFromBinary(const QString &path)
-{
- BinaryContent c(path);
- if (!c.d->m_appBinary->open(QIODevice::ReadOnly))
- throw Error(QObject::tr("Could not open binary %1: %2").arg(path, c.d->m_appBinary->errorString()));
-
- // check for supported binary, will throw if we can't find a marker
- const BinaryLayout layout = readBinaryLayout(c.d->m_appBinary.data(),
- findMagicCookie(c.d->m_appBinary.data(), QInstaller::MagicCookie));
-
- bool retry = true;
- if (layout.magicMarker != MagicInstallerMarker) {
- QString binaryDataPath = path;
- QFileInfo fi(path + QLatin1String("/../../.."));
- if (QFileInfo(fi.absoluteFilePath()).isBundle())
- binaryDataPath = fi.absoluteFilePath();
- fi.setFile(binaryDataPath);
-
- c.d->m_binaryDataFile = QSharedPointer<QFile>(new QFile(fi.absolutePath() + QLatin1Char('/')
- + fi.baseName() + QLatin1String(".dat")));
- if (c.d->m_binaryDataFile->exists() && c.d->m_binaryDataFile->open(QIODevice::ReadOnly)) {
- // check for supported binary data file, will throw if we can't find a marker
- try {
- const qint64 cookiePos = findMagicCookie(c.d->m_binaryDataFile.data(),
- QInstaller::MagicCookieDat);
- const BinaryLayout binaryLayout = readBinaryLayout(c.d->m_binaryDataFile.data(), cookiePos);
- readBinaryData(c, c.d->m_binaryDataFile, binaryLayout);
- retry = false;
- } catch (const Error &error) {
- // this seems to be an unsupported dat file, try to read from original binary
- c.d->m_binaryDataFile.clear();
- qDebug() << error.message();
- }
- } else {
- c.d->m_binaryDataFile.clear();
- }
- }
-
- if (retry)
- readBinaryData(c, c.d->m_appBinary, layout);
-
- return c;
-}
-
-/* static */
-BinaryLayout BinaryContent::readBinaryLayout(QIODevice *const file, qint64 cookiePos)
-{
- const qint64 indexSize = 5 * sizeof(qint64);
- if (!file->seek(cookiePos - indexSize))
- throw Error(QObject::tr("Could not seek to binary layout section."));
-
- BinaryLayout layout;
- layout.operationsStart = retrieveInt64(file);
- layout.operationsEnd = retrieveInt64(file);
- layout.resourceCount = retrieveInt64(file);
- layout.dataBlockSize = retrieveInt64(file);
- layout.magicMarker = retrieveInt64(file);
- layout.magicCookie = retrieveInt64(file);
- layout.indexSize = indexSize + sizeof(qint64);
- layout.endOfData = file->pos();
-
- qDebug() << "Operations start:" << layout.operationsStart;
- qDebug() << "Operations end:" << layout.operationsEnd;
- qDebug() << "Resource count:" << layout.resourceCount;
- qDebug() << "Data block size:" << layout.dataBlockSize;
- qDebug() << "Magic marker:" << layout.magicMarker;
- qDebug() << "Magic cookie:" << layout.magicCookie;
- qDebug() << "Index size:" << layout.indexSize;
- qDebug() << "End of data:" << layout.endOfData;
-
- const qint64 resourceOffsetAndLengtSize = 2 * sizeof(qint64);
- const qint64 dataBlockStart = layout.endOfData - layout.dataBlockSize;
- for (int i = 0; i < layout.resourceCount; ++i) {
- if (!file->seek(layout.endOfData - layout.indexSize - resourceOffsetAndLengtSize * (i + 1)))
- throw Error(QObject::tr("Could not seek to metadata index."));
-
- const qint64 metadataResourceOffset = retrieveInt64(file);
- const qint64 metadataResourceLength = retrieveInt64(file);
- layout.metadataResourceSegments.append(Range<qint64>::fromStartAndLength(metadataResourceOffset
- + dataBlockStart, metadataResourceLength));
- }
-
- return layout;
-}
-
-/* static */
-void BinaryContent::readBinaryData(BinaryContent &content, const QSharedPointer<QFile> &file,
- const BinaryLayout &layout)
-{
- content.d->m_magicMarker = layout.magicMarker;
- content.d->m_metadataResourceSegments = layout.metadataResourceSegments;
-
- const qint64 dataBlockStart = layout.endOfData - layout.dataBlockSize;
- const qint64 operationsStart = layout.operationsStart + dataBlockStart;
- if (!file->seek(operationsStart))
- throw Error(QObject::tr("Could not seek to operation list."));
-
- const qint64 operationsCount = retrieveInt64(file.data());
- qDebug() << "Number of operations:" << operationsCount;
-
- for (int i = 0; i < operationsCount; ++i) {
- const QString name = retrieveString(file.data());
- const QString data = retrieveString(file.data());
- content.d->m_performedOperationsData.append(qMakePair(name, data));
- }
-
- // seek to the position of the component index
- const qint64 resourceOffsetAndLengtSize = 2 * sizeof(qint64);
- const qint64 resourceSectionSize = resourceOffsetAndLengtSize * layout.resourceCount;
- if (!file->seek(layout.endOfData - layout.indexSize - resourceSectionSize - resourceOffsetAndLengtSize))
- throw Error(QObject::tr("Could not seek to component index information."));
-
- const qint64 compIndexStart = retrieveInt64(file.data()) + dataBlockStart;
- if (!file->seek(compIndexStart))
- throw Error(QObject::tr("Could not seek to component index."));
-
- content.d->m_componentIndex = QInstallerCreator::ComponentIndex::read(file, dataBlockStart);
- content.d->m_binaryFormatEngineHandler.setComponentIndex(content.d->m_componentIndex);
-
- if (isVerbose()) {
- const QVector<QInstallerCreator::Component> components = content.d->m_componentIndex.components();
- qDebug() << "Number of components loaded:" << components.count();
- foreach (const QInstallerCreator::Component &component, components) {
- const QVector<QSharedPointer<Archive> > archives = component.archives();
- qDebug() << component.name().data() << "loaded...";
- QStringList archivesWithSize;
- foreach (const QSharedPointer<Archive> &archive, archives) {
- QString archiveWithSize(QLatin1String("%1 - %2 Bytes"));
- archiveWithSize = archiveWithSize.arg(QString::fromLocal8Bit(archive->name()),
- QString::number(archive->size()));
- archivesWithSize.append(archiveWithSize);
- }
- if (!archivesWithSize.isEmpty()) {
- qDebug() << " - " << archives.count() << "archives: "
- << qPrintable(archivesWithSize.join(QLatin1String("; ")));
- }
- }
- }
-}
-
-/*!
- Registers already performed operations.
-*/
-int BinaryContent::registerPerformedOperations()
-{
- if (d->m_performedOperations.count() > 0)
- return d->m_performedOperations.count();
-
- for (int i = 0; i < d->m_performedOperationsData.count(); ++ i) {
- const QPair<QString, QString> opPair = d->m_performedOperationsData.at(i);
- QScopedPointer<Operation> op(KDUpdater::UpdateOperationFactory::instance().create(opPair.first));
- Q_ASSERT_X(!op.isNull(), __FUNCTION__, QString::fromLatin1("Invalid operation name: %1.")
- .arg(opPair.first).toLatin1());
-
- if (!op->fromXml(opPair.second)) {
- qWarning() << "Failed to load XML for operation:" << opPair.first;
- continue;
- }
- d->m_performedOperations.append(op.take());
- }
- return d->m_performedOperations.count();
-}
-
-/*!
- Returns the operations performed during installation. Returns an empty list if no operations are
- instantiated, performed or the binary is the installer application.
-*/
-OperationList BinaryContent::performedOperations() const
-{
- return d->m_performedOperations;
-}
-
-/*!
- Returns the magic marker found in the binary. Returns 0 if no marker has been found.
-*/
-qint64 BinaryContent::magicMarker() const
-{
- return d->m_magicMarker;
-}
-
-/*!
- Registers the Qt resources embedded in this binary.
- */
-int BinaryContent::registerEmbeddedQResources()
-{
- if (d->m_resourceMappings.count() > 0)
- return d->m_resourceMappings.count();
-
- const bool hasBinaryDataFile = !d->m_binaryDataFile.isNull();
- QFile *const data = hasBinaryDataFile ? d->m_binaryDataFile.data() : d->m_appBinary.data();
- if (!data->isOpen() && !data->open(QIODevice::ReadOnly)) {
- throw Error(QObject::tr("Could not open binary %1: %2").arg(data->fileName(),
- data->errorString()));
- }
-
- foreach (const Range<qint64> &i, d->m_metadataResourceSegments)
- d->m_resourceMappings.append(addResourceFromBinary(data, i));
-
- d->m_appBinary.clear();
- if (hasBinaryDataFile)
- d->m_binaryDataFile.clear();
-
- return d->m_resourceMappings.count();
-}
-
-/*!
- Returns the binary component index as read from the file.
-*/
-QInstallerCreator::ComponentIndex BinaryContent::componentIndex() const
-{
- return d->m_componentIndex;
-}