aboutsummaryrefslogtreecommitdiff
path: root/libs/bsapacker/src/ArchiveAutoService.cpp
blob: 4c89c6932ed5e4423874a0c67b3eb18fd52de197 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#include <bsapacker/ArchiveAutoService.h>
#include <uibase/utility.h>
#include <QProgressDialog>
#include <QtConcurrent>
#include <QLabel>
#include <QDebug>

#include "NexusId.h"

#ifdef __linux__
#include <bsa_ffi.h>
#endif

namespace BsaPacker
{
	static const char* gameIdFromNexusId(const int nexusId)
	{
		switch (nexusId) {
		case NexusId::Morrowind: return "morrowind";
		case NexusId::Oblivion: return "oblivion";
		case NexusId::Fallout3: return "fo3";
		case NexusId::NewVegas: return "fonv";
		case NexusId::Skyrim:
		case NexusId::Enderal: return "skyrimle";
		case NexusId::SkyrimSE:
		case NexusId::EnderalSE: return "skyrimse";
		case NexusId::Fallout4: return "fo4-fo76";
		case NexusId::Starfield: return "starfield-v3";
		default: return "fo4-fo76";
		}
	}

	static int includeModeFromArchiveType(const bsa_archive_type_e type)
	{
		switch (type) {
		case bsa_archive_type_e::baFO4: return 1;     // non-dds
		case bsa_archive_type_e::baFO4dds: return 2;  // dds only
		case bsa_archive_type_e::baSF: return 1;      // non-dds
		case bsa_archive_type_e::baSFdds: return 2;   // dds only
		default: return 0;                            // all files
		}
	}

	bool ArchiveAutoService::CreateBSA(libbsarch::bs_archive_auto* archive,
									   const QString& archiveName,
									   const bsa_archive_type_e type,
									   const QString& sourceDir,
									   const int nexusId) const
	{
		const QString hostArchiveName = MOBase::normalizePathForHost(archiveName);
		const QString hostSourceDir = MOBase::normalizePathForHost(sourceDir);
		const char* gameId = gameIdFromNexusId(nexusId);
		const int includeMode = includeModeFromArchiveType(type);

		QProgressDialog savingDialog;
		savingDialog.setWindowFlags(savingDialog.windowFlags() & ~Qt::WindowCloseButtonHint);
		savingDialog.setWindowTitle(QObject::tr("Writing Archive"));
		savingDialog.setCancelButton(0);
		QLabel text;
		text.setText(QObject::tr("Writing %1").arg(hostArchiveName));
		savingDialog.setLabel(&text);
		savingDialog.setRange(0, 0);
		savingDialog.show();
		auto future = QtConcurrent::run([=]() -> bool {
#ifdef __linux__
			char* err = bsa_ffi_pack_dir_filtered(
				hostSourceDir.toUtf8().constData(),
				hostArchiveName.toUtf8().constData(),
				gameId,
				includeMode,
				nullptr,
				nullptr);
			if (err == nullptr) {
				qDebug() << "packed archive via bsa_ffi for" << hostArchiveName;
				return true;
			}

			qWarning() << "bsa_ffi primary pack failed for" << hostArchiveName
					   << ":" << QString::fromUtf8(err)
					   << "- falling back to libbsarch";
			bsa_ffi_string_free(err);
#endif
			try {
				archive->save_to_disk(hostArchiveName.toStdString());
			} catch (std::exception&) {
				return false;
			}
			return true;
			});
		while (!future.isFinished())
		{
			QCoreApplication::processEvents();
		}
		savingDialog.hide();

		if (future.result()) {
			return true;
		}

		return false;
	}
} // namespace BsaPacker