diff --git a/installwizard.cpp b/installwizard.cpp index fbc1e79..33a998e 100644 --- a/installwizard.cpp +++ b/installwizard.cpp @@ -48,12 +48,14 @@ void InstallWizard::cancel() reject(); } -void InstallWizard::on_InstallWizard_customButtonClicked(int which) +void InstallWizard::on_InstallWizard_finished(int result) { - if (which == QWizard::FinishButton) - { #ifdef Q_OS_WIN32 + if (result == QDialog::Accepted) + { settings->setQuakePath(field("quake3Path").toString()); -#endif } +#else + result = result; // Silence warning. +#endif } diff --git a/installwizard.h b/installwizard.h index fad74bc..19e193b 100644 --- a/installwizard.h +++ b/installwizard.h @@ -28,7 +28,7 @@ public: private slots: void cancel(); - void on_InstallWizard_customButtonClicked(int which); + void on_InstallWizard_finished(int result); private: Ui::InstallWizard *ui; diff --git a/installwizard_locate.cpp b/installwizard_locate.cpp index 9ab338b..c376291 100644 --- a/installwizard_locate.cpp +++ b/installwizard_locate.cpp @@ -53,6 +53,13 @@ bool InstallWizard_LocatePage::validatePage() const QString pakFilename(ui->txtLocation->text() + "/baseq3/pak1.pk3"); QFile file(pakFilename); + if (!file.exists()) + { + // pak1.pk3 doesn't exist, must be a fresh install. + isQuake3PatchRequired = true; + return true; + } + if (!file.open(QIODevice::ReadOnly)) { QMessageBox::warning(this, "Missing file", QString("Unable to open file '%1'").arg(pakFilename)); diff --git a/installwizard_patch.cpp b/installwizard_patch.cpp index fb3bad4..dcd9744 100644 --- a/installwizard_patch.cpp +++ b/installwizard_patch.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -5,6 +6,26 @@ #include "ui_installwizard_patch.h" #include "installwizard.h" +struct TarHeader +{ + char name[100]; + char mode[8]; + char uid[8]; + char gid[8]; + char size[12]; + char mtime[12]; + char chksum[8]; + char typeflag; + char linkname[100]; + char magic[6]; + char version[2]; + char uname[32]; + char gname[32]; + char devmajor[8]; + char devminor[8]; + char prefix[155]; +}; + InstallWizard_Patch::InstallWizard_Patch(QWidget *parent) : QWizardPage(parent), ui(new Ui::InstallWizard_Patch), @@ -13,7 +34,7 @@ InstallWizard_Patch::InstallWizard_Patch(QWidget *parent) : networkReply(NULL), isCancelled(false), isDownloadFinished(false), - isPatchUnzipped(false), + isPatchInstalled(false), usePatchFileBuffer(true) { ui->setupUi(this); @@ -28,7 +49,7 @@ InstallWizard_Patch::~InstallWizard_Patch() void InstallWizard_Patch::initializePage() { - isCancelled = isDownloadFinished = isPatchUnzipped = false; + isCancelled = isDownloadFinished = isPatchInstalled = false; patchFileBuffer.clear(); usePatchFileBuffer = true; @@ -48,7 +69,7 @@ void InstallWizard_Patch::cleanupPage() bool InstallWizard_Patch::isComplete() const { - return isDownloadFinished && isPatchUnzipped; + return isDownloadFinished && isPatchInstalled; } void InstallWizard_Patch::cancel() @@ -113,6 +134,8 @@ void InstallWizard_Patch::downloadFinished() isDownloadFinished = true; // Extract gzip compressed archive. + ui->lblStatus->setText("Installing..."); + z_stream zstream; zstream.zalloc = Z_NULL; zstream.zfree = Z_NULL; @@ -169,6 +192,85 @@ void InstallWizard_Patch::downloadFinished() while (result != Z_STREAM_END); inflateEnd(&zstream); - isPatchUnzipped = true; + + // Extract all the baseq3 pk3 files in the TAR file. + unzippedPatchFile->seek(0); + int nPaksExtracted = 0; + + for (;;) + { + // Read TAR file header (padded to 512 bytes). + TarHeader header; + unzippedPatchFile->read((char *)&header, sizeof(header)); + unzippedPatchFile->seek(unzippedPatchFile->pos() + 512 - sizeof(header)); + + // Convert size from octal string. + qint64 size = 0; + int exponent = 0; + + for (int i = sizeof(header.size) - 1; i >= 0; i--) + { + int digit = (int)(header.size[i] - '0'); + + if (digit < 0 || digit > 7) + continue; + + size += qint64(digit * pow(8.0f, exponent)); + exponent++; + } + + // Extract a pk3 file. + const char *pakPrefix = "baseq3/pak"; + + if (strncmp(header.name, pakPrefix, strlen(pakPrefix)) == 0) + { + QString filename(field("quake3Path").toString()); + filename.append('/'); + filename.append(header.name); + + QFile file(filename); + + if (!file.open(QIODevice::WriteOnly)) + { + ui->lblStatus->setText(QString("Error opening '%1' for writing").arg(filename)); + cancel(); + return; + } + + qint64 totalBytesRead = 0; + + for (;;) + { + qint64 bytesToRead = bufferSize; + + if (totalBytesRead + bytesToRead > size) + { + bytesToRead = size - totalBytesRead; + } + + const qint64 bytesRead = unzippedPatchFile->read(outputBuffer, bytesToRead); + + if (bytesRead == 0) + break; + + file.write(outputBuffer, bytesRead); + totalBytesRead += bytesRead; + } + + nPaksExtracted++; + } + else + { + unzippedPatchFile->seek(unzippedPatchFile->pos() + size); + } + + // TAR file size is padded to 512 byte blocks. + unzippedPatchFile->seek(unzippedPatchFile->pos() + ((size % 512) == 0 ? 0 : 512 - (size % 512))); + + if (nPaksExtracted == 8) + break; + } + + isPatchInstalled = true; emit completeChanged(); } diff --git a/installwizard_patch.h b/installwizard_patch.h index a43c558..fa96027 100644 --- a/installwizard_patch.h +++ b/installwizard_patch.h @@ -33,7 +33,7 @@ private: QNetworkReply *networkReply; bool isCancelled; bool isDownloadFinished; - bool isPatchUnzipped; + bool isPatchInstalled; bool usePatchFileBuffer; QByteArray patchFileBuffer; };