summaryrefslogtreecommitdiffstats
path: root/installerbuilder/common/fileutils.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'installerbuilder/common/fileutils.cpp')
-rw-r--r--installerbuilder/common/fileutils.cpp468
1 files changed, 468 insertions, 0 deletions
diff --git a/installerbuilder/common/fileutils.cpp b/installerbuilder/common/fileutils.cpp
new file mode 100644
index 000000000..04fa9ae94
--- /dev/null
+++ b/installerbuilder/common/fileutils.cpp
@@ -0,0 +1,468 @@
+/**************************************************************************
+**
+** 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 "fileutils.h"
+#include <common/errors.h>
+#include <common/utils.h>
+
+#include <QDateTime>
+#include <QDir>
+#include <QDirIterator>
+#include <QEventLoop>
+#include <QFileInfo>
+#include <QString>
+#include <QTemporaryFile>
+#include <QThread>
+#include <QUrl>
+
+#include <cassert>
+#include <cerrno>
+
+using namespace QInstaller;
+
+TempDirDeleter::TempDirDeleter( const QString& path )
+ : m_paths( QStringList() << path )
+{
+}
+
+TempDirDeleter::TempDirDeleter( const QStringList& paths_ )
+ : m_paths( paths_ )
+{
+}
+
+TempDirDeleter::~TempDirDeleter()
+{
+ for( QStringList::const_iterator it = m_paths.constBegin(); it != m_paths.constEnd(); ++it )
+ {
+ const QString& path = *it;
+ if( !path.isEmpty() )
+ try {
+ removeDirectory( path );
+ } catch ( const Error& e ) {
+ qCritical() << Q_FUNC_INFO << "Exception caught:" << e.message();
+ } catch ( ... ) {
+ qCritical() << Q_FUNC_INFO << "Unknown exception caught.";
+ }
+ }
+}
+
+void TempDirDeleter::passAndReleaseAll( TempDirDeleter& tdd ) {
+ tdd.m_paths = m_paths;
+ releaseAll();
+}
+
+void TempDirDeleter::passAndRelease( TempDirDeleter& tdd, const QString& path ) {
+ tdd.add( path );
+ release( path );
+}
+
+void TempDirDeleter::releaseAll() {
+ m_paths.clear();
+}
+
+void TempDirDeleter::release( const QString& path ) {
+ m_paths.removeAll( path );
+}
+
+QStringList TempDirDeleter::paths() const {
+ return m_paths;
+}
+
+void TempDirDeleter::add( const QString& path )
+{
+ if( !m_paths.contains( path ) )
+ m_paths.push_back( path );
+}
+
+void TempDirDeleter::add( const QStringList& paths )
+{
+ for( QStringList::const_iterator it = paths.begin(); it != paths.end(); ++it )
+ add( *it );
+}
+
+bool QInstaller::isLocalUrl( const QUrl& url ) {
+ return url.scheme().isEmpty() || url.scheme().toLower() == QLatin1String("file");
+}
+
+QString QInstaller::pathFromUrl( const QUrl& url )
+{
+ if( isLocalUrl( url ) )
+ return url.toLocalFile();
+ const QString str = url.toString();
+ if ( url.scheme() == QLatin1String("resource") )
+ return str.mid( QString::fromLatin1("resource").length() );
+ return str;
+}
+
+
+void QInstaller::openForWrite(QIODevice* dev, const QString& name)
+{
+ assert( dev );
+ if (!dev->open(QIODevice::WriteOnly))
+ throw Error(QObject::tr("Cannot open file %1 for writing: %2").arg( name, dev->errorString() ) );
+}
+
+void QInstaller::openForRead(QIODevice* dev, const QString& name)
+{
+ assert( dev );
+ if (!dev->open(QIODevice::ReadOnly))
+ throw Error(QObject::tr( "Cannot open file %1 for reading: %2" ).arg( name, dev->errorString() ) );
+}
+
+qint64 QInstaller::blockingWrite(QIODevice *out, const char *buffer, qint64 size)
+{
+ qint64 left = size;
+ while (left > 0) {
+ const qint64 n = out->write(buffer, left);
+ if (n < 0)
+ throw Error( QObject::tr("Write failed after %1 bytes: %2").arg( QString::number(size-left), out->errorString() ) );
+ left -= n;
+ }
+ return size;
+}
+
+qint64 QInstaller::blockingWrite(QIODevice *out, const QByteArray& ba)
+{
+ return blockingWrite( out, ba.constData(), ba.size() );
+}
+
+qint64 QInstaller::blockingRead(QIODevice *in, char *buffer, qint64 size)
+{
+ if ( in->atEnd() )
+ return 0;
+ qint64 left = size;
+ while (left > 0) {
+ const qint64 n = in->read(buffer, left);
+ if ( n < 0 )
+ throw Error( QObject::tr("Read failed after %1 bytes: %2").arg( QString::number(size-left), in->errorString() ) );
+
+ left -= n;
+ buffer += n;
+ }
+ return size;
+}
+
+void QInstaller::blockingCopy( QIODevice* in, QIODevice* out, qint64 size )
+{
+ static const qint64 blockSize = 4096;
+ QByteArray ba( blockSize, '\0' );
+ qint64 actual = qMin( blockSize, size );
+ while( actual > 0 )
+ {
+ blockingRead( in, ba.data(), actual );
+ blockingWrite( out, ba.constData(), actual );
+ size -= actual;
+ actual = qMin( blockSize, size );
+ }
+}
+
+void QInstaller::removeDirectory( const QString& path, bool ignoreErrors )
+{
+ if ( path.isEmpty() ) // QDir( "" ) points to the working directory! We never want to remove that one.
+ return;
+
+ QDirIterator it( path, QDir::NoDotAndDotDot | QDir::AllEntries | QDir::Hidden );
+ while( it.hasNext() )
+ {
+ it.next();
+ const QFileInfo fi = it.fileInfo();
+
+ if( fi.isDir() && !fi.isSymLink() )
+ {
+ removeDirectory( fi.filePath(), ignoreErrors );
+ }
+ else
+ {
+ QFile f( fi.filePath() );
+ if( !f.remove() && !ignoreErrors )
+ throw Error( QObject::tr("Could not remove file %1: %2").arg( f.fileName(), f.errorString() ) );
+ }
+ }
+
+ errno = 0;
+ if ( !QDir().rmdir( path ) && !ignoreErrors )
+ throw Error( QObject::tr("Could not remove folder %1: %2").arg( path, QLatin1String(strerror(errno)) ) );
+}
+
+/*!
+ \internal
+ */
+class RemoveDirectoryThread : public QThread
+{
+public:
+ explicit RemoveDirectoryThread( const QString& path, bool ignoreErrors = false, QObject* parent = 0 )
+ : QThread( parent ),
+ p( path ),
+ ignore( ignoreErrors )
+ {
+ }
+
+ const QString& error() const
+ {
+ return err;
+ }
+
+protected:
+ /*!
+ \reimp
+ */
+ void run()
+ {
+ try
+ {
+ removeDirectory( p, ignore );
+ }
+ catch( const Error& e )
+ {
+ err = e.message();
+ }
+ }
+
+private:
+ QString err;
+ const QString p;
+ const bool ignore;
+};
+
+void QInstaller::removeDirectoryThreaded( const QString& path, bool ignoreErrors )
+{
+ RemoveDirectoryThread thread( path, ignoreErrors );
+ QEventLoop loop;
+ QObject::connect( &thread, SIGNAL( finished() ), &loop, SLOT( quit() ) );
+ thread.start();
+ loop.exec();
+ if( !thread.error().isEmpty() )
+ throw Error( thread.error() );
+}
+
+void QInstaller::copyDirectoryContents( const QString& sourceDir, const QString& targetDir ) {
+ verbose() << "Copying " << sourceDir << " to " << targetDir << std::endl;
+ Q_ASSERT( QFileInfo( sourceDir ).isDir() );
+ Q_ASSERT( !QFileInfo( targetDir ).exists() || QFileInfo( targetDir ).isDir() );
+ if ( !QDir().mkpath( targetDir ) )
+ throw Error( QObject::tr("Could not create folder %1").arg( targetDir ) );
+
+ QDirIterator it( sourceDir, QDir::NoDotAndDotDot | QDir::AllEntries );
+ while( it.hasNext() )
+ {
+ const QFileInfo i( it.next() );
+ if( i.isDir() )
+ {
+ copyDirectoryContents( QDir( sourceDir ).absoluteFilePath( i.fileName() ), QDir( targetDir ).absoluteFilePath( i.fileName() ) );
+ }
+ else
+ {
+ QFile f( i.filePath() );
+ const QString target = QDir( targetDir ).absoluteFilePath( i.fileName() );
+ if( !f.copy( target ) )
+ throw Error( QObject::tr("Could not copy file from %1 to %2: %3").arg( f.fileName(), target, f.errorString() ) );
+ }
+ }
+}
+
+void QInstaller::moveDirectoryContents( const QString& sourceDir, const QString& targetDir ) {
+ verbose() << "Moving " << sourceDir << " to " << targetDir << std::endl;
+ Q_ASSERT( QFileInfo( sourceDir ).isDir() );
+ Q_ASSERT( !QFileInfo( targetDir ).exists() || QFileInfo( targetDir ).isDir() );
+ if ( !QDir().mkpath( targetDir ) )
+ throw Error( QObject::tr("Could not create folder %1").arg( targetDir ) );
+
+ QDirIterator it( sourceDir, QDir::NoDotAndDotDot | QDir::AllEntries );
+ while( it.hasNext() )
+ {
+ const QFileInfo i( it.next() );
+ if( i.isDir() )
+ {
+ moveDirectoryContents( QDir( sourceDir ).absoluteFilePath( i.fileName() ), QDir( targetDir ).absoluteFilePath( i.fileName() ) );
+ }
+ else
+ {
+ QFile f( i.filePath() );
+ const QString target = QDir( targetDir ).absoluteFilePath( i.fileName() );
+ if( !f.rename( target ) )
+ throw Error( QObject::tr("Could not move file from %1 to %2: %3").arg( f.fileName(), target, f.errorString() ) );
+ }
+ }
+}
+
+void QInstaller::mkdir( const QString& path ) {
+ errno = 0;
+ if ( !QDir().mkdir( QFileInfo( path ).absoluteFilePath() ) )
+ throw Error( QObject::tr("Could not create folder %1: %2" ).arg( path, QString::fromLocal8Bit( strerror( errno ) ) ) );
+}
+
+void QInstaller::mkpath( const QString& path ) {
+ errno = 0;
+ if ( !QDir().mkpath( QFileInfo( path ).absoluteFilePath() ) )
+ throw Error( QObject::tr("Could not create folder %1: %2" ).arg( path, QString::fromLocal8Bit( strerror( errno ) ) ) );
+}
+
+QString QInstaller::generateTemporaryFileName( const QString& templ )
+{
+ if ( templ.isEmpty() )
+ {
+ QTemporaryFile f;
+ if ( !f.open() )
+ throw Error( QObject::tr("Could not open temporary file: %1").arg( f.errorString() ) );
+ return f.fileName();
+ }
+ else
+ {
+ static const QString characters = QLatin1String( "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890" );
+/* const QFileInfo fi( path );
+ const QString dir = fi.absolutePath();
+ const QString file = fi.fileName();*/
+ QString suffix;
+ qsrand( qrand() * QDateTime::currentDateTime().toTime_t() );
+ for( int i = 0; i < 5; ++i )
+ suffix += characters[ qrand() % characters.length() ];
+ const QString tmp = QLatin1String( "%1.tmp.%2.%3" );
+ int count = 1;
+ while ( QFile::exists( tmp.arg( templ, suffix ).arg( count ) ) )
+ ++count;
+ QFile f( tmp.arg( templ, suffix ).arg( count ) );
+ if( !f.open( QIODevice::WriteOnly ) )
+ throw Error( QObject::tr("Could not open temporary file for template %1: %2").arg( templ, f.errorString() ) );
+ f.remove();
+ return f.fileName();
+ }
+}
+
+QString QInstaller::createTemporaryDirectory( const QString& templ ) {
+ const QString t = QDir::tempPath() + QLatin1String("/") + templ + QLatin1String("XXXXXX");
+ QTemporaryFile f( t );
+ if ( !f.open() )
+ throw Error( QObject::tr("Could not create temporary folder for template %1: %2").arg( t, f.errorString() ) );
+ const QString path = f.fileName() + QString::fromLatin1( "meta" );
+ verbose() << "Creating meta data directory at " << path << std::endl;
+
+ QInstaller::mkpath( path );
+ return path;
+}
+
+#ifdef Q_WS_WIN
+#include <windows.h>
+
+#pragma pack( push )
+#pragma pack(2)
+
+typedef struct
+{
+BYTE bWidth; // Width, in pixels, of the image
+BYTE bHeight; // Height, in pixels, of the image
+BYTE bColorCount; // Number of colors in image (0 if >=8bpp)
+BYTE bReserved; // Reserved
+WORD wPlanes; // Color Planes
+WORD wBitCount; // Bits per pixel
+DWORD dwBytesInRes; // how many bytes in this resource?
+DWORD dwImageOffset; // the ID
+} ICONDIRENTRY;
+
+typedef struct
+{
+WORD idReserved; // Reserved (must be 0)
+WORD idType; // Resource type (1 for icons)
+WORD idCount; // How many images?
+ICONDIRENTRY idEntries[1]; // The entries for each image
+} ICONDIR;
+
+typedef struct
+{
+BYTE bWidth; // Width, in pixels, of the image
+BYTE bHeight; // Height, in pixels, of the image
+BYTE bColorCount; // Number of colors in image (0 if >=8bpp)
+BYTE bReserved; // Reserved
+WORD wPlanes; // Color Planes
+WORD wBitCount; // Bits per pixel
+DWORD dwBytesInRes; // how many bytes in this resource?
+WORD nID; // the ID
+} GRPICONDIRENTRY, *LPGRPICONDIRENTRY;
+
+typedef struct
+{
+WORD idReserved; // Reserved (must be 0)
+WORD idType; // Resource type (1 for icons)
+WORD idCount; // How many images?
+GRPICONDIRENTRY idEntries[1]; // The entries for each image
+} GRPICONDIR, *LPGRPICONDIR;
+
+
+#pragma pack( pop )
+
+void QInstaller::setApplicationIcon( const QString& application, const QString& icon )
+{
+ wchar_t* const path = new wchar_t[ application.length() + 1 ];
+ QDir::toNativeSeparators( application ).toWCharArray( path );
+ path[ application.length() ] = 0;
+
+ HANDLE updateRes = BeginUpdateResource( path, false );
+ delete[] path;
+
+ QFile iconFile( icon );
+ if( !iconFile.open( QIODevice::ReadOnly ) )
+ return;
+
+ QByteArray temp = iconFile.readAll();
+
+ ICONDIR* ig = reinterpret_cast< ICONDIR* >( temp.data() );
+
+ DWORD newSize = sizeof( GRPICONDIR ) + sizeof( GRPICONDIRENTRY ) * ( ig->idCount - 1 );
+ GRPICONDIR* newDir = reinterpret_cast< GRPICONDIR* >( new char[ newSize ] );
+ newDir->idReserved = ig->idReserved;
+ newDir->idType = ig->idType;
+ newDir->idCount = ig->idCount;
+
+ for( int i = 0; i < ig->idCount; ++i )
+ {
+ char* temp1 = temp.data() + ig->idEntries[ i ].dwImageOffset;
+ DWORD size1 = ig->idEntries[ i ].dwBytesInRes;
+
+ newDir->idEntries[ i ].bWidth = ig->idEntries[ i ].bWidth;
+ newDir->idEntries[ i ].bHeight = ig->idEntries[ i ].bHeight;
+ newDir->idEntries[ i ].bColorCount = ig->idEntries[ i ].bColorCount;
+ newDir->idEntries[ i ].bReserved = ig->idEntries[ i ].bReserved;
+ newDir->idEntries[ i ].wPlanes = ig->idEntries[ i ].wPlanes;
+ newDir->idEntries[ i ].wBitCount = ig->idEntries[ i ].wBitCount;
+ newDir->idEntries[ i ].dwBytesInRes = ig->idEntries[ i ].dwBytesInRes;
+ newDir->idEntries[ i ].nID = i + 1;
+
+ UpdateResource( updateRes, RT_ICON, MAKEINTRESOURCE( i + 1 ),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), temp1, size1 );
+ }
+
+ UpdateResource( updateRes, RT_GROUP_ICON, L"IDI_ICON1", MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), newDir, newSize );
+
+ delete[] newDir;
+
+ EndUpdateResource( updateRes, false );
+}
+#endif