diff options
author | Tim Jenssen <tim.jenssen@nokia.com> | 2011-02-21 16:30:31 +0100 |
---|---|---|
committer | Tim Jenssen <tim.jenssen@nokia.com> | 2011-02-21 16:41:32 +0100 |
commit | 8457830abdca9d5769e2ec1bdbfb793a05e6c5dd (patch) | |
tree | 4c9e87efd34104ec59ae31efd0394e998a2434f7 /installerbuilder/libinstaller/qtpatch.cpp |
init commit
Diffstat (limited to 'installerbuilder/libinstaller/qtpatch.cpp')
-rw-r--r-- | installerbuilder/libinstaller/qtpatch.cpp | 237 |
1 files changed, 237 insertions, 0 deletions
diff --git a/installerbuilder/libinstaller/qtpatch.cpp b/installerbuilder/libinstaller/qtpatch.cpp new file mode 100644 index 000000000..4f5ad160e --- /dev/null +++ b/installerbuilder/libinstaller/qtpatch.cpp @@ -0,0 +1,237 @@ +/************************************************************************** +** +** This file is part of Qt SDK** +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).* +** +** Contact: Nokia Corporation qt-info@nokia.com** +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please contact +** (qt-info@nokia.com). +** +**************************************************************************/ +#include "qtpatch.h" + +#include "common/utils.h" + +#include <QString> +#include <QStringList> +#include <QFileInfo> +#include <QProcess> +#include <QTextStream> +#include <QVector> +#include <QTime> +#include <QDebug> +#include <QCoreApplication> +#include <QByteArrayMatcher> + + +#ifdef Q_OS_WIN +#include <windows.h> // for Sleep +#endif +#ifdef Q_OS_UNIX +#include <errno.h> +#include <signal.h> +#include <time.h> +#endif + +//"anonymous" namespace to make clear that this is only for inside use +namespace { + void sleepCopiedFromQTest(int ms) + { + if (ms < 0) { + return; + } + #ifdef Q_OS_WIN + Sleep(uint(ms)); + #else + struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 }; + nanosleep(&ts, NULL); + #endif + } + + void uiDetachedWait(int ms) + { + QTime timer; + timer.start(); + do { + QCoreApplication::processEvents(QEventLoop::AllEvents, ms); + sleepCopiedFromQTest(10); + } while (timer.elapsed() < ms); + } + + +}//"anonymous" namespace + + +QHash<QString, QByteArray> QtPatch::qmakeValues(const QString & qmakePath, QByteArray * qmakeOutput) +{ + + QHash<QString, QByteArray> qmakeValueHash; + + // in some cases qmake is not runable, because another process is blocking it(filewatcher ...) + int waitCount = 0; + while (qmakeValueHash.isEmpty() && waitCount < 60) { + QFileInfo qmake(qmakePath); + + if (!qmake.exists() || !qmake.isExecutable()) { + QInstaller::verbose() << qPrintable( QString(QLatin1String("%1 is not existing or not executable")).arg(qmakePath) ) << std::endl; + return qmakeValueHash; + } + + QStringList args; + args << QLatin1String("-query"); + + QProcess process; + process.start(qmake.absoluteFilePath(), args, QIODevice::ReadOnly); + if (process.waitForFinished(2000)) { + if (process.exitStatus() == QProcess::CrashExit) { + QInstaller::verbose() << qPrintable( QString(QLatin1String("%1 was crashed")).arg(qmakePath) ) << std::endl; + return qmakeValueHash; + } + QByteArray output = process.readAllStandardOutput(); + qmakeOutput->append(output); + QTextStream stream(&output); + while (!stream.atEnd()) { + const QString line = stream.readLine(); + const int index = line.indexOf(QLatin1Char(':')); + if (index != -1) { + QString value = line.mid(index+1); + if (value != QLatin1String("**Unknown**") ) + qmakeValueHash.insert(line.left(index), value.toUtf8()); + } + } + } + if (qmakeValueHash.isEmpty()) { + ++waitCount; + static const int waitTimeInMilliSeconds = 500; + uiDetachedWait(waitTimeInMilliSeconds); + } + } //while (qmakeValueHash.isEmpty() && waitCount < 60) + return qmakeValueHash; +} + +bool QtPatch::patchBinaryFile( const QString & fileName, + const QByteArray & oldQtPath, + const QByteArray & newQtPath ) +{ + QFile file(fileName); + if ( !file.exists() ) { + QInstaller::verbose() << "qpatch: warning: file `" << qPrintable(fileName) << "' not found" << std::endl; + return false; + } + + openFileForPatching(&file); + if (! file.isOpen()) { + QInstaller::verbose() << "qpatch: warning: file `" << qPrintable(fileName) << "' can not open." << std::endl; + QInstaller::verbose() << qPrintable(file.errorString()) << std::endl; + return false; + } + + bool isPatched = patchBinaryFile(&file, oldQtPath, newQtPath); + + file.close(); + return isPatched; +} + +// device must be open +bool QtPatch::patchBinaryFile( QIODevice* device, + const QByteArray & oldQtPath, + const QByteArray & newQtPath ) +{ + if (!(device->openMode() == QIODevice::ReadWrite)) { + QInstaller::verbose() << "qpatch: warning: This function needs an open device for writing." << std::endl; + return false; + } + const QByteArray source = device->readAll(); + device->seek(0); + + int offset = 0; + QByteArray overwritePath(newQtPath); + if(overwritePath.size() < oldQtPath.size()) { + QByteArray fillByteArray(oldQtPath.size() - overwritePath.size(), '\0'); + overwritePath.append(fillByteArray); + } + + QByteArrayMatcher byteArrayMatcher(oldQtPath); + forever { + offset = byteArrayMatcher.indexIn(source, offset); + if(offset == -1) + break; + device->seek(offset); + device->write(overwritePath); + offset += overwritePath.size(); + } + device->seek(0); //for next reading we should be at the beginning + return true; +} + +bool QtPatch::patchTextFile( const QString & fileName, + const QHash<QByteArray, QByteArray> &searchReplacePairs) +{ + QFile file(fileName); + + if (! file.open(QFile::ReadOnly)) { + QInstaller::verbose() << "qpatch: warning: Open the file '" + << qPrintable(fileName) << "' stopped: " + << qPrintable(file.errorString()) << std::endl; + return false; + } + + QByteArray source = file.readAll(); + file.close(); + + qDebug() << Q_FUNC_INFO; + QHashIterator<QByteArray, QByteArray> it(searchReplacePairs); + while(it.hasNext()) { + it.next(); + qDebug() << "it.key(): " << it.key(); + qDebug() << "it.value(): " << it.value(); + source.replace(it.key(), it.value()); + } + + if (! file.open(QFile::WriteOnly | QFile::Truncate)) { + QInstaller::verbose() << "qpatch: error: file `" << qPrintable(fileName) << "' not writable" << std::endl; + return false; + } + + file.write(source); + return true; +} + + +bool QtPatch::openFileForPatching(QFile* file) +{ + if (file->openMode() == QIODevice::NotOpen) { + // in some cases the file can not open, because another process is blocking it(filewatcher ...) + int waitCount = 0; + while (! file->open(QFile::ReadWrite) && waitCount < 60) { + ++waitCount; + static const int waitTimeInMilliSeconds = 500; + uiDetachedWait(waitTimeInMilliSeconds); + } + return file->openMode() == QFile::ReadWrite; + } + QInstaller::verbose() << "qpatch: error: File `" << qPrintable(file->fileName()) << "' is open, so it can not open it again." << std::endl; + return false; +} |