diff --git a/CMakeLists.txt b/CMakeLists.txt index c92a9fa..dcf6584 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,11 +10,23 @@ include_directories(${QT_INCLUDES} ${CMAKE_CURRENT_BINARY_DIR} ${ZLIB_INCLUDE_DI set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra") set(paalternativelauncher_SRCS information.cpp advanceddialog.cpp bundle.cpp sha1.cpp patcher.cpp paalternativelauncher.cpp main.cpp) + +set(RES_FILES "") +if(WIN32) + if(MINGW) + set(RES_FILES "paalternativelauncher.rc") + set(CMAKE_RC_COMPILER_INIT windres) + ENABLE_LANGUAGE(RC) + SET(CMAKE_RC_COMPILE_OBJECT + " -O coff -i -o ") + endif() +endif() + qt4_automoc(${paalternativelauncher_SRCS}) QT4_ADD_RESOURCES(paalternativelauncher_RCC_SRCS paalternativelauncher.qrc) -add_executable(paalternativelauncher ${paalternativelauncher_SRCS} ${paalternativelauncher_RCC_SRCS}) +add_executable(paalternativelauncher ${paalternativelauncher_SRCS} ${paalternativelauncher_RCC_SRCS} ${RES_FILES}) if(WIN32) target_link_libraries(paalternativelauncher ${QT_QTNETWORK_LIBRARIES} ${QT_QTGUI_LIBRARY} ${QT_QTCORE_LIBRARY} ${ZLIB_LIBRARY} ${QJSON_LIBRARIES} -mwindows -lws2_32 -ljpeg -lpng -ltiff -llzma -lmng -lz -limm32 -llcms -lwinmm -lssl -lcrypto) else() diff --git a/bundle.cpp b/bundle.cpp index 50f5c93..792eb62 100644 --- a/bundle.cpp +++ b/bundle.cpp @@ -13,7 +13,7 @@ #include "information.h" Bundle::Bundle(QString installpath, QVariant bundlevariant, QString downloadurl, QString titlefolder, QString authsuffix, QNetworkAccessManager *networkaccessmanager, QWidget *parent) - : m_parent(parent), m_verification_state(unknown) + : m_parent(parent), m_verification_state(unknown), m_error_occured(false) { m_network_access_manager = networkaccessmanager; @@ -159,8 +159,10 @@ void Bundle::download() m_entry_file << entryfile; if(!m_entry_file[i]->open(QIODevice::WriteOnly)) { + m_error_occured = true; info.critical(tr("I/O error"), tr("Could not open file \"%1\" for writing.").arg(m_entries[0].fullfilename[i])); - exit(1); + emit errorOccurred(); + return; } info.log("File creation", m_entries[0].fullfilename[i]); @@ -180,8 +182,10 @@ void Bundle::download() // 16+MAX_WBITS means read as gzip. if(inflateInit2(&m_gzipstream, 16 + MAX_WBITS) != Z_OK) { + m_error_occured = true; + emit errorOccurred(); info.critical("ZLib", tr("Couldn't init zlibstream.")); - exit(1); + return; } m_alreadyread = 0; @@ -193,7 +197,7 @@ void Bundle::download() connect(reply, SIGNAL(readyRead()), SLOT(readyRead())); } -void Bundle::nextFile() +void Bundle::nextFile(QNetworkReply* reply) { for(int i = 0; i < m_entry_file.count(); i++) { @@ -202,6 +206,9 @@ void Bundle::nextFile() } m_entry_file.clear(); + info.log("Next file", QString("%1:%2").arg(m_checksum).arg(m_current_entry_index+1), true); + + m_current_entry_index++; if(m_current_entry_index == m_entries.count()) { @@ -211,8 +218,11 @@ void Bundle::nextFile() if(m_current_entry_index >= m_entries.count()) { + m_error_occured = true; + emit errorOccurred(); + reply->abort(); info.critical("I/O error", "More files than expected!"); - exit(1); + return; } for(int i = 0; i < m_entries[m_current_entry_index].fullfilename.count(); i++) @@ -245,8 +255,11 @@ void Bundle::nextFile() // 16+MAX_WBITS means read as gzip. if(inflateInit2(&m_gzipstream, 16 + MAX_WBITS) != Z_OK) { + m_error_occured = true; + emit errorOccurred(); + reply->abort(); info.critical("ZLib", tr("Couldn't init zlibstream.")); - exit(1); + return; } } @@ -288,7 +301,10 @@ void Bundle::downloadProgress(qint64 value, qint64) void Bundle::readyRead() { - QIODevice *reply = dynamic_cast(sender()); + if(m_error_occured) + return; + + QNetworkReply *reply = dynamic_cast(sender()); if(reply) { do @@ -306,11 +322,22 @@ void Bundle::readyRead() if(m_entries[m_current_entry_index].checksumZ == "") { for(QList::iterator entryfile = m_entry_file.begin(); entryfile != m_entry_file.end(); ++entryfile) - (*entryfile)->write(streamdata); + { + qint64 really_written = (*entryfile)->write(streamdata); + if(really_written == -1) + { + m_error_occured = true; + emit errorOccurred(); + reply->abort(); + info.critical(tr("Write error"), tr("Error while writing to %1 (%2).").arg((*entryfile)->fileName()).arg((*entryfile)->errorString())); + return; + } + } + info.log(tr("Writing to file"), QString("(1) ") + tr("%1 bytes written to %2.").arg(streamdata.count()).arg(m_entry_file[0]->fileName()), true); m_alreadyread += streamdata.count(); if(m_alreadyread == m_entries[m_current_entry_index].next_offset) - nextFile(); + nextFile(reply); } else { @@ -326,7 +353,18 @@ void Bundle::readyRead() if(m_gzipstream.avail_out == 0) { for(QList::iterator entryfile = m_entry_file.begin(); entryfile != m_entry_file.end(); ++entryfile) - (*entryfile)->write(outputdata); + { + qint64 really_written = (*entryfile)->write(outputdata); + if(really_written == -1) + { + m_error_occured = true; + emit errorOccurred(); + reply->abort(); + info.critical(tr("Write error"), tr("Error while writing to %1 (%2).").arg((*entryfile)->fileName()).arg((*entryfile)->errorString())); + return; + } + } + info.log("Writing to file", QString("(2) %1 bytes written to %2.").arg(outputdata.count()).arg(m_entry_file[0]->fileName()), true); m_gzipstream.next_out = (Bytef *)outputdata.data(); m_gzipstream.avail_out = outputdata.count(); } @@ -335,15 +373,29 @@ void Bundle::readyRead() outputdata.truncate(outputdata.count()-m_gzipstream.avail_out); for(QList::iterator entryfile = m_entry_file.begin(); entryfile != m_entry_file.end(); ++entryfile) - (*entryfile)->write(outputdata); + { + qint64 really_written = (*entryfile)->write(outputdata); + if(really_written == -1) + { + m_error_occured = true; + emit errorOccurred(); + reply->abort(); + info.critical(tr("Write error"), tr("Error while writing to %1 (%2).").arg((*entryfile)->fileName()).arg((*entryfile)->errorString())); + return; + } + } + info.log("Writing to file", QString("(3) %1 bytes written to %2.").arg(outputdata.count()).arg(m_entry_file[0]->fileName()), true); m_alreadyread += streamdata.count(); if(inflate_status == Z_STREAM_END) - nextFile(); + nextFile(reply); else if(inflate_status < 0) { + m_error_occured = true; + emit errorOccurred(); + reply->abort(); info.critical(tr("I/O error"), tr("Decompress error")); - exit(1); + return; } } } diff --git a/bundle.h b/bundle.h index 461f1b3..6f2037a 100644 --- a/bundle.h +++ b/bundle.h @@ -59,11 +59,12 @@ class Bundle : public QObject int m_current_entry_index; int m_alreadyread; qint64 m_alreadydownloaded; - + bool m_error_occured; + QFile m_cache_file; static bool verifyEntry(entry_t entry); - void nextFile(); + void nextFile(QNetworkReply *reply); private slots: void verifyFinished(); @@ -75,6 +76,7 @@ private slots: signals: void verifyDone(size_t bytes_to_download); void downloadProgress(qint64); + void errorOccurred(); void done(); }; diff --git a/information.cpp b/information.cpp index 17048ad..7ba0450 100644 --- a/information.cpp +++ b/information.cpp @@ -33,16 +33,18 @@ void Information::critical(const QString& title, const QString& text) m_logfile.write(" ", 1); m_logfile.write(text.toUtf8()); m_logfile.write("\n", 1); + m_logfile.flush(); } -void Information::warning(const QString& title, const QString& text) +bool Information::warning(const QString& title, const QString& text) { - QMessageBox::warning(m_parent, title, text); m_logfile.write("[WARN] ", 8); m_logfile.write(title.toUtf8()); m_logfile.write(" ", 1); m_logfile.write(text.toUtf8()); m_logfile.write("\n", 1); + m_logfile.flush(); + return(QMessageBox::warning(m_parent, title, text, QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes); } void Information::log(const QString& title, const QString& text, bool verbose) @@ -55,6 +57,7 @@ void Information::log(const QString& title, const QString& text, bool verbose) m_logfile.write(" ", 1); m_logfile.write(text.toUtf8()); m_logfile.write("\n", 1); + m_logfile.flush(); } Information info; diff --git a/information.h b/information.h index f8703ee..bf7c6fb 100644 --- a/information.h +++ b/information.h @@ -17,7 +17,7 @@ class Information : public QObject void setParent(QWidget *parent); void setVerbose(bool verbose); void critical(const QString& title, const QString& text); - void warning(const QString& title, const QString& text); + bool warning(const QString& title, const QString& text); void log(const QString& title, const QString& text, bool verbose = false); private: diff --git a/main.cpp b/main.cpp index 68b1347..d9c36c2 100644 --- a/main.cpp +++ b/main.cpp @@ -6,7 +6,7 @@ int main(int argc, char** argv) { QApplication app(argc, argv); - if(app.arguments().contains("-v")) +// if(app.arguments().contains("-v")) info.setVerbose(true); PAAlternativeLauncher foo; diff --git a/paalternativelauncher.cpp b/paalternativelauncher.cpp index 670cb4c..625fd3f 100644 --- a/paalternativelauncher.cpp +++ b/paalternativelauncher.cpp @@ -1,4 +1,4 @@ -#define VERSION "0.3" +#define VERSION "0.3.1" #include "paalternativelauncher.h" #include "advanceddialog.h" @@ -27,10 +27,15 @@ #include #include #include -#ifdef _WIN32 +#if defined(linux) || defined(__APPLE__) +# include +# include +#elif defined(_WIN32) +# include # define QJSON_STATIC #endif #include +#include PAAlternativeLauncher::PAAlternativeLauncher() : m_network_access_manager(new QNetworkAccessManager(this)) @@ -429,6 +434,13 @@ void PAAlternativeLauncher::showEvent(QShowEvent* event) void PAAlternativeLauncher::downloadPushButtonClicked(bool) { + quint64 freespace = getFreeDiskspaceInMB(m_installPathLineEdit->text()); + if(freespace < 1024) + { + if(!info.warning(tr("Available disk space"), tr("Only %1 MB available. Continue anyway?").arg(freespace))) + return; + } + m_download_button->setEnabled(false); QSettings settings(QSettings::UserScope, "DeathByDenim", "PAAlternativeLauncher"); @@ -480,6 +492,7 @@ void PAAlternativeLauncher::launchPushButtonClicked(bool) "/PA" #elif _WIN32 "\\bin_x64\\PA.exe" +// or: "\\bin_x86\\PA.exe" #elif __APPLE__ # error Right... #endif @@ -566,4 +579,27 @@ void PAAlternativeLauncher::checkForUpdates(QStringList streamnames) } } +quint64 PAAlternativeLauncher::getFreeDiskspaceInMB(QString directory) +{ + QByteArray dir = directory.toLatin1(); +#if defined(linux) || defined(__APPLE__) + struct statvfs diskinfo; + int rc = statvfs(dir.constData(), &diskinfo); + if(rc != 0) + { + info.log(tr("Disk space"), QString("could not be determined (%1)").arg(errno)); + return ULONG_MAX; + } + return (diskinfo.f_bavail / 1024) * (diskinfo.f_bsize / 1024); +#elif defined(_WIN32) + ULARGE_INTEGER FreeBytesAvailable, TotalNumberOfBytes, TotalNumberOfFreeBytes; + if(GetDiskFreeSpaceEx(dir.constData(), &FreeBytesAvailable, &TotalNumberOfBytes, &TotalNumberOfFreeBytes)) + { + return FreeBytesAvailable.QuadPart / (1024*1024); + } +#endif + + return ULONG_MAX; +} + #include "paalternativelauncher.moc" diff --git a/paalternativelauncher.h b/paalternativelauncher.h index be9e0fe..0125b1a 100644 --- a/paalternativelauncher.h +++ b/paalternativelauncher.h @@ -52,6 +52,7 @@ Q_OBJECT QWidget *createWaitWidget(QWidget *parent); QString decodeLoginData(const QByteArray& data); void checkForUpdates(QStringList streamnames); + quint64 getFreeDiskspaceInMB(QString directory); protected: void closeEvent(QCloseEvent *event); diff --git a/paalternativelauncher.rc b/paalternativelauncher.rc new file mode 100644 index 0000000..1593147 --- /dev/null +++ b/paalternativelauncher.rc @@ -0,0 +1,25 @@ +id ICON "img/icon.ico" + +1 VERSIONINFO +FILEVERSION 0,3,1,0 +PRODUCTVERSION 0,3,1,0 +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "080904E4" + BEGIN + VALUE "CompanyName", "DeathByDenim" + VALUE "FileDescription", "Alternative launcher for Planetary Annihilation" + VALUE "FileVersion", "0.3.1" + VALUE "InternalName", "paalternativelauncher" + VALUE "OriginalFilename", "paalternativelauncher.exe" + VALUE "ProductName", "PA Alternative Launcher" + VALUE "ProductVersion", "0.3.1" + END + END + + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x809, 1252 + END +END