diff --git a/CMakeLists.txt b/CMakeLists.txt index 575fecd0c..99a7e85a4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -499,6 +499,7 @@ endif(WIN32) add_subdirectory (extern/shiny) add_subdirectory (extern/oics) add_subdirectory (extern/sdl4ogre) +add_subdirectory (extern/unshield) # Components add_subdirectory (components) diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index bff26b63c..bfe932448 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -4,6 +4,8 @@ set(LAUNCHER main.cpp maindialog.cpp playpage.cpp + unshield_thread.cpp + text_slot_msg_box.cpp settings/gamesettings.cpp settings/graphicssettings.cpp @@ -20,6 +22,8 @@ set(LAUNCHER_HEADER graphicspage.hpp maindialog.hpp playpage.hpp + unshield_thread.hpp + text_slot_msg_box.hpp settings/gamesettings.hpp settings/graphicssettings.hpp @@ -37,6 +41,8 @@ set(LAUNCHER_HEADER_MOC graphicspage.hpp maindialog.hpp playpage.hpp + unshield_thread.hpp + text_slot_msg_box.hpp utils/checkablemessagebox.hpp utils/textinputdialog.hpp @@ -64,8 +70,11 @@ QT4_ADD_RESOURCES(RCC_SRCS ${CMAKE_SOURCE_DIR}/files/launcher/launcher.qrc) QT4_WRAP_CPP(MOC_SRCS ${LAUNCHER_HEADER_MOC}) QT4_WRAP_UI(UI_HDRS ${LAUNCHER_UI}) + +message(STATUS "hello ${LIBUNSHIELD_INCLUDE}") + include(${QT_USE_FILE}) -include_directories(${CMAKE_CURRENT_BINARY_DIR}) +include_directories(${CMAKE_CURRENT_BINARY_DIR} ${LIBUNSHIELD_INCLUDE}) # Main executable IF(OGRE_STATIC) @@ -93,8 +102,11 @@ target_link_libraries(omwlauncher ${SDL2_LIBRARY} ${QT_LIBRARIES} components + libunshield ) + + if(DPKG_PROGRAM) INSTALL(TARGETS omwlauncher RUNTIME DESTINATION games COMPONENT omwlauncher) endif() diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index b75d09c51..e274a2896 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -11,6 +11,9 @@ #include +#include "unshield_thread.hpp" +#include "text_slot_msg_box.hpp" + #include "utils/checkablemessagebox.hpp" #include "playpage.hpp" @@ -128,11 +131,16 @@ bool MainDialog::showFirstRunDialog() QDir dir(path); dir.setPath(dir.canonicalPath()); // Resolve symlinks - if (!dir.cdUp()) - continue; // Cannot move from Data Files - if (dir.exists(QString("Morrowind.ini"))) iniPaths.append(dir.absoluteFilePath(QString("Morrowind.ini"))); + else + { + if (!dir.cdUp()) + continue; // Cannot move from Data Files + + if (dir.exists(QString("Morrowind.ini"))) + iniPaths.append(dir.absoluteFilePath(QString("Morrowind.ini"))); + } } // Ask the user where the Morrowind.ini is @@ -344,6 +352,76 @@ bool MainDialog::setupLauncherSettings() return true; } +bool expansions(UnshieldThread& cd) +{ + if(cd.BloodmoonDone()) + { + cd.Done(); + return false; + } + + QMessageBox expansionsBox; + expansionsBox.setText(QObject::tr("
Would you like to install expansions now ? (make sure you have the disc)
\ + If you want to install both Bloodmoon and Tribunal, you have to install Tribunal first.
")); + + QAbstractButton* tribunalButton = NULL; + if(!cd.TribunalDone()) + tribunalButton = expansionsBox.addButton(QObject::tr("&Tribunal"), QMessageBox::ActionRole); + + QAbstractButton* bloodmoonButton = expansionsBox.addButton(QObject::tr("&Bloodmoon"), QMessageBox::ActionRole); + QAbstractButton* noneButton = expansionsBox.addButton(QObject::tr("&None"), QMessageBox::ActionRole); + + expansionsBox.exec(); + + if(expansionsBox.clickedButton() == noneButton) + { + cd.Done(); + return false; + } + else if(expansionsBox.clickedButton() == tribunalButton) + { + + TextSlotMsgBox cdbox; + cdbox.setStandardButtons(QMessageBox::Cancel); + + QObject::connect(&cd,SIGNAL(signalGUI(const QString&)), &cdbox, SLOT(setTextSlot(const QString&))); + QObject::connect(&cd,SIGNAL(close()), &cdbox, SLOT(reject())); + + cd.SetTribunalPath( + QFileDialog::getOpenFileName( + NULL, + QObject::tr("Select data1.hdr from Tribunal Installation CD (Tribunal/data1.hdr on GOTY CDs)"), + QDir::currentPath(), + QString(QObject::tr("Installshield hdr file (*.hdr)"))).toUtf8().constData()); + + cd.start(); + cdbox.exec(); + } + else if(expansionsBox.clickedButton() == bloodmoonButton) + { + + TextSlotMsgBox cdbox; + cdbox.setStandardButtons(QMessageBox::Cancel); + + QObject::connect(&cd,SIGNAL(signalGUI(const QString&)), &cdbox, SLOT(setTextSlot(const QString&))); + QObject::connect(&cd,SIGNAL(close()), &cdbox, SLOT(reject())); + + cd.SetBloodmoonPath( + QFileDialog::getOpenFileName( + NULL, + QObject::tr("Select data1.hdr from Bloodmoon Installation CD (Bloodmoon/data1.hdr on GOTY CDs)"), + QDir::currentPath(), + QString(QObject::tr("Installshield hdr file (*.hdr)"))).toUtf8().constData()); + + cd.start(); + cdbox.exec(); + } + + + + return true; +} + bool MainDialog::setupGameSettings() { QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string()); @@ -401,9 +479,13 @@ bool MainDialog::setupGameSettings() Press \"Browse...\" to specify the location manually.
")); QAbstractButton *dirSelectButton = - msgBox.addButton(QObject::tr("B&rowse..."), QMessageBox::ActionRole); + msgBox.addButton(QObject::tr("Browse to &Install..."), QMessageBox::ActionRole); - msgBox.exec(); + QAbstractButton *cdSelectButton = + msgBox.addButton(QObject::tr("Browse to &CD..."), QMessageBox::ActionRole); + + + msgBox.exec(); QString selectedFile; if (msgBox.clickedButton() == dirSelectButton) { @@ -413,6 +495,38 @@ bool MainDialog::setupGameSettings() QDir::currentPath(), QString(tr("Morrowind master file (*.esm)"))); } + else if(msgBox.clickedButton() == cdSelectButton) { + UnshieldThread cd; + + { + TextSlotMsgBox cdbox; + cdbox.setStandardButtons(QMessageBox::Cancel); + + QObject::connect(&cd,SIGNAL(signalGUI(const QString&)), &cdbox, SLOT(setTextSlot(const QString&))); + QObject::connect(&cd,SIGNAL(close()), &cdbox, SLOT(reject())); + + cd.SetMorrowindPath( + QFileDialog::getOpenFileName( + NULL, + QObject::tr("Select data1.hdr from Morrowind Installation CD"), + QDir::currentPath(), + QString(tr("Installshield hdr file (*.hdr)"))).toUtf8().constData()); + + cd.SetOutputPath( + QFileDialog::getExistingDirectory( + NULL, + QObject::tr("Select where to extract files to"), + QDir::currentPath(), + QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks).toUtf8().constData()); + + cd.start(); + cdbox.exec(); + } + + while(expansions(cd)); + + selectedFile = QString::fromStdString(cd.GetMWEsmPath()); + } if (selectedFile.isEmpty()) return false; // Cancel was clicked; diff --git a/apps/launcher/text_slot_msg_box.cpp b/apps/launcher/text_slot_msg_box.cpp new file mode 100644 index 000000000..25bd5d970 --- /dev/null +++ b/apps/launcher/text_slot_msg_box.cpp @@ -0,0 +1,6 @@ +#include "text_slot_msg_box.hpp" + +void TextSlotMsgBox::setTextSlot(const QString& string) +{ + setText(string); +} diff --git a/apps/launcher/text_slot_msg_box.hpp b/apps/launcher/text_slot_msg_box.hpp new file mode 100644 index 000000000..a29e2c354 --- /dev/null +++ b/apps/launcher/text_slot_msg_box.hpp @@ -0,0 +1,13 @@ +#ifndef TEXT_SLOT_MSG_BOX +#define TEXT_SLOT_MSG_BOX + +#include + +class TextSlotMsgBox : public QMessageBox +{ +Q_OBJECT + public slots: + void setTextSlot(const QString& string); +}; + +#endif diff --git a/apps/launcher/unshield_thread.cpp b/apps/launcher/unshield_thread.cpp new file mode 100644 index 000000000..f8166dba8 --- /dev/null +++ b/apps/launcher/unshield_thread.cpp @@ -0,0 +1,441 @@ +#include "unshield_thread.hpp" + +#include +#include + +namespace bfs = boost::filesystem; + + +typedef enum +{ + FORMAT_NEW, + FORMAT_OLD, + FORMAT_RAW +} FORMAT; + + +static bool make_sure_directory_exists(bfs::path directory) +{ + + if(!bfs::exists(directory)) + { + bfs::create_directories(directory); + } + + return bfs::exists(directory); +} + +void fill_path(bfs::path& path, const std::string& name) +{ + size_t start = 0; + + size_t i; + for(i = 0; i < name.length(); i++) + { + switch(name[i]) + { + case '\\': + path /= name.substr(start, i-start); + start = i+1; + break; + } + } + + path /= name.substr(start, i-start); +} + +bool UnshieldThread::extract_file(Unshield* unshield, bfs::path output_dir, const char* prefix, int index) +{ + bool success; + bfs::path dirname; + bfs::path filename; + int directory = unshield_file_directory(unshield, index); + + dirname = output_dir; + + if (prefix && prefix[0]) + dirname /= prefix; + + if (directory >= 0) + { + const char* tmp = unshield_directory_name(unshield, directory); + if (tmp && tmp[0]) + fill_path(dirname, tmp); + } + + make_sure_directory_exists(dirname); + + filename = dirname; + filename /= unshield_file_name(unshield, index); + + emit signalGUI(QString("Extracting: ") + QString(filename.c_str())); + + FORMAT format = FORMAT_NEW; + switch (format) + { + case FORMAT_NEW: + success = unshield_file_save(unshield, index, filename.c_str()); + break; + case FORMAT_OLD: + success = unshield_file_save_old(unshield, index, filename.c_str()); + break; + case FORMAT_RAW: + success = unshield_file_save_raw(unshield, index, filename.c_str()); + break; + } + + if (!success) + bfs::remove(filename); + + return success; +} + +void UnshieldThread::extract_cab(const bfs::path& cab, const bfs::path& output_dir, bool extract_ini) +{ + Unshield * unshield; + unshield = unshield_open_force_version(cab.c_str(), -1); + + int i; + for (i = 0; i < unshield_file_group_count(unshield); i++) + { + UnshieldFileGroup* file_group = unshield_file_group_get(unshield, i); + + for (size_t j = file_group->first_file; j <= file_group->last_file; j++) + { + if (unshield_file_is_valid(unshield, j)) + extract_file(unshield, output_dir, file_group->name, j); + } + } + unshield_close(unshield); +} + +std::string get_setting(const std::string& category, const std::string& setting, const std::string& inx) +{ + size_t start = inx.find(category); + start = inx.find(setting, start) + setting.length() + 3; + + size_t end = inx.find("!", start); + + return inx.substr(start, end-start); +} + +std::string read_to_string(const bfs::path& path) +{ + std::ifstream strstream(path.c_str(), std::ios::in | std::ios::binary); + std::string str; + + strstream.seekg(0, std::ios::end); + str.resize(strstream.tellg()); + strstream.seekg(0, std::ios::beg); + strstream.read(&str[0], str.size()); + strstream.close(); + + return str; +} + +void add_setting(const std::string& category, const std::string& setting, const std::string& val, std::string& ini) +{ + size_t loc; + loc = ini.find("[" + category + "]"); + + // If category is not found, create it + if(loc == std::string::npos) + { + loc = ini.size() + 2; + ini += ("\r\n[" + category + "]\r\n"); + } + + loc += category.length() +2 +2; + ini.insert(loc, setting + "=" + val + "\r\n"); +} + +void bloodmoon_fix_ini(std::string& ini, const bfs::path inxPath) +{ + std::string inx = read_to_string(inxPath); + + // Remove this one setting (the only one actually changed by bloodmoon, as opposed to just adding new ones) + size_t start = ini.find("[Weather Blight]"); + start = ini.find("Ambient Loop Sound ID", start); + size_t end = ini.find("\r\n", start) +2; + ini.erase(start, end-start); + + std::string category; + std::string setting; + + category = "General"; + { + setting = "Werewolf FOV"; add_setting(category, setting, get_setting(category, setting, inx), ini); + } + category = "Moons"; + { + setting = "Script Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); + } + category = "Weather"; + { + setting = "Snow Ripples"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Snow Ripple Radius"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Snow Ripples Per Flake"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Snow Ripple Scale"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Snow Ripple Speed"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Snow Gravity Scale"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Snow High Kill"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Snow Low Kill"; add_setting(category, setting, get_setting(category, setting, inx), ini); + } + category = "Weather Blight"; + { + setting = "Ambient Loop Sound ID"; add_setting(category, setting, get_setting(category, setting, inx), ini); + } + category = "Weather Snow"; + { + setting = "Sky Sunrise Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Sky Day Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Sky Sunset Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Sky Night Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Fog Sunrise Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Fog Day Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Fog Sunset Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Fog Night Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Ambient Sunrise Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Ambient Day Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Ambient Sunset Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Ambient Night Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Sun Sunrise Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Sun Day Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Sun Sunset Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Sun Night Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Sun Disc Sunset Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Transition Delta"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Land Fog Day Depth"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Land Fog Night Depth"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Clouds Maximum Percent"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Wind Speed"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Cloud Speed"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Glare View"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Cloud Texture"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Ambient Loop Sound ID"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Snow Threshold"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Snow Diameter"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Snow Height Min"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Snow Height Max"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Snow Entrance Speed"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Max Snowflakes"; add_setting(category, setting, get_setting(category, setting, inx), ini); + } + category = "Weather Blizzard"; + { + setting = "Sky Sunrise Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Sky Day Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Sky Sunset Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Sky Night Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Fog Sunrise Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Fog Day Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Fog Sunset Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Fog Night Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Ambient Sunrise Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Ambient Day Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Ambient Sunset Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Ambient Night Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Sun Sunrise Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Sun Day Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Sun Sunset Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Sun Night Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Sun Disc Sunset Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Transition Delta"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Land Fog Day Depth"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Land Fog Night Depth"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Clouds Maximum Percent"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Wind Speed"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Cloud Speed"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Glare View"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Cloud Texture"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Ambient Loop Sound ID"; add_setting(category, setting, get_setting(category, setting, inx), ini); + setting = "Storm Threshold"; add_setting(category, setting, get_setting(category, setting, inx), ini); + } +} + + +void fix_ini(const bfs::path& output_dir, bfs::path cdPath, bool tribunal, bool bloodmoon) +{ + bfs::path ini_path = output_dir; + ini_path /= "Morrowind.ini"; + + std::string ini = read_to_string(ini_path.string()); + + if(tribunal) + { + add_setting("Game Files", "GameFile1", "Tribunal.esm", ini); + add_setting("Archives", "Archive 0", "Tribunal.bsa", ini); + } + if(bloodmoon) + { + bloodmoon_fix_ini(ini, cdPath / "setup.inx"); + add_setting("Game Files", "GameFile2", "Bloodmoon.esm", ini); + add_setting("Archives", "Archive 1", "Bloodmoon.bsa", ini); + } + + std::ofstream inistream(ini_path.c_str()); + inistream << ini; + inistream.close(); +} + +bool UnshieldThread::SetMorrowindPath(const std::string& path) +{ + mMorrowindPath = path; + return true; +} + +bool UnshieldThread::SetTribunalPath(const std::string& path) +{ + mTribunalPath = path; + return true; +} + +bool UnshieldThread::SetBloodmoonPath(const std::string& path) +{ + mBloodmoonPath = path; + return true; +} + +void UnshieldThread::SetOutputPath(const std::string& path) +{ + mOutputPath = path; +} + +void installToPath(const bfs::path& from, const bfs::path& to) +{ + make_sure_directory_exists(to); + + for ( bfs::directory_iterator end, dir(from); dir != end; ++dir ) + { + if(bfs::is_directory(dir->path())) + installToPath(dir->path(), to / dir->path().filename()); + else + bfs::rename(dir->path(), to / dir->path().filename()); + } +} + +bfs::path findFile(const bfs::path& in, std::string filename) +{ + for ( bfs::recursive_directory_iterator end, dir(in); dir != end; ++dir ) + { + if(Misc::StringUtils::lowerCase(dir->path().filename().string()) == filename) + return dir->path(); + } + + return ""; +} + +bool contains(const bfs::path& in, std::string filename) +{ + for(bfs::directory_iterator end, dir(in); dir != end; ++dir) + { + if(Misc::StringUtils::lowerCase(dir->path().filename().string()) == filename) + return true; + } + + return false; +} + +bool UnshieldThread::extract() +{ + bfs::path outputDataFilesDir = mOutputPath; + outputDataFilesDir /= "Data Files"; + bfs::path extractPath = mOutputPath; + extractPath /= "extract-temp"; + + if(!mMorrowindDone && mMorrowindPath.string().length() > 0) + { + mMorrowindDone = true; + + bfs::path mwExtractPath = extractPath / "morrowind"; + extract_cab(mMorrowindPath, mwExtractPath, true); + + bfs::path dFilesDir = findFile(mwExtractPath, "morrowind.esm").parent_path(); + + + installToPath(dFilesDir, outputDataFilesDir); + + bfs::rename(findFile(mwExtractPath, "morrowind.ini"), outputDataFilesDir / "Morrowind.ini"); + + mTribunalDone = contains(outputDataFilesDir, "tribunal.esm"); + mBloodmoonDone = contains(outputDataFilesDir, "bloodmoon.esm"); + + } + + else if(!mTribunalDone && mTribunalPath.string().length() > 0) + { + mTribunalDone = true; + + bfs::path tbExtractPath = extractPath / "tribunal"; + extract_cab(mTribunalPath, tbExtractPath, true); + + bfs::path dFilesDir = findFile(tbExtractPath, "tribunal.esm").parent_path(); + + installToPath(dFilesDir, outputDataFilesDir); + + mBloodmoonDone = contains(outputDataFilesDir, "bloodmoon.esm"); + + fix_ini(outputDataFilesDir, bfs::path(mTribunalPath).parent_path(), mTribunalDone, mBloodmoonDone); + } + + else if(!mBloodmoonDone && mBloodmoonPath.string().length() > 0) + { + mBloodmoonDone = true; + + bfs::path bmExtractPath = extractPath / "bloodmoon"; + extract_cab(mBloodmoonPath, bmExtractPath, true); + + bfs::path dFilesDir = findFile(bmExtractPath, "bloodmoon.esm").parent_path(); + + installToPath(dFilesDir, outputDataFilesDir); + + fix_ini(outputDataFilesDir, bfs::path(mBloodmoonPath).parent_path(), false, mBloodmoonDone); + } + + + return true; +} + +time_t getTime(const char* time) +{ + struct tm tms; + memset(&tms, 0, sizeof(struct tm)); + strptime(time, "%d %B %Y", &tms); + return mktime(&tms); +} + +void UnshieldThread::Done() +{ + // Get rid of unnecessary files + bfs::remove_all(mOutputPath / "extract-temp"); + + // Set modified time to release dates, to preserve load order + if(mMorrowindDone) + bfs::last_write_time(findFile(mOutputPath, "morrowind.esm"), getTime("1 May 2002")); + + if(mTribunalDone) + bfs::last_write_time(findFile(mOutputPath, "tribunal.esm"), getTime("6 November 2002")); + + if(mBloodmoonDone) + bfs::last_write_time(findFile(mOutputPath, "bloodmoon.esm"), getTime("3 June 2003")); +} + +std::string UnshieldThread::GetMWEsmPath() +{ + return findFile(mOutputPath / "Data Files", "morrowind.esm").string(); +} + +bool UnshieldThread::TribunalDone() +{ + return mTribunalDone; +} + +bool UnshieldThread::BloodmoonDone() +{ + return mBloodmoonDone; +} + +void UnshieldThread::run() +{ + extract(); + emit close(); +} diff --git a/apps/launcher/unshield_thread.hpp b/apps/launcher/unshield_thread.hpp new file mode 100644 index 000000000..0def3ab1d --- /dev/null +++ b/apps/launcher/unshield_thread.hpp @@ -0,0 +1,55 @@ +#ifndef UNSHIELD_THREAD_H +#define UNSHIELD_THREAD_H + +#include + +#include + +#include + + +class UnshieldThread : public QThread +{ + Q_OBJECT + + public: + bool SetMorrowindPath(const std::string& path); + bool SetTribunalPath(const std::string& path); + bool SetBloodmoonPath(const std::string& path); + + void SetOutputPath(const std::string& path); + + bool extract(); + + bool TribunalDone(); + bool BloodmoonDone(); + + void Done(); + + std::string GetMWEsmPath(); + + private: + + void extract_cab(const boost::filesystem::path& cab, const boost::filesystem::path& output_dir, bool extract_ini = false); + bool extract_file(Unshield* unshield, boost::filesystem::path output_dir, const char* prefix, int index); + + boost::filesystem::path mMorrowindPath; + boost::filesystem::path mTribunalPath; + boost::filesystem::path mBloodmoonPath; + + bool mMorrowindDone = false; + bool mTribunalDone = false; + bool mBloodmoonDone = false; + + boost::filesystem::path mOutputPath; + + + protected: + virtual void run(); + + signals: + void signalGUI(QString); + void close(); +}; + +#endif