Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ jobs:
steps:
- name: Build BSA Extractor
id: build-bsa-extractor
uses: ModOrganizer2/build-with-mob-action
uses: ModOrganizer2/build-with-mob-action@master
with:
mo2-dependencies: uibase bsatk
17 changes: 17 additions & 0 deletions .github/workflows/linting.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: Lint BSA Extractor

on:
push:
pull_request:
types: [opened, synchronize, reopened]

jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Check format
uses: ModOrganizer2/check-formatting-action@master
with:
check-path: "."
exclude-regex: "third-party"
10 changes: 5 additions & 5 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ repos:
- id: end-of-file-fixer
- id: check-merge-conflict
- id: check-case-conflict
# - repo: https://github.com/pre-commit/mirrors-clang-format
# rev: v19.1.5
# hooks:
# - id: clang-format
# 'types_or': [c++, c]
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: v22.1.2
hooks:
- id: clang-format
'types_or': [c++, c]

ci:
autofix_commit_msg: "[pre-commit.ci] Auto fixes from pre-commit.com hooks."
Expand Down
126 changes: 61 additions & 65 deletions src/bsaextractor.cpp
Original file line number Diff line number Diff line change
@@ -1,111 +1,104 @@
#include "bsaextractor.h"

#include <uibase/iplugingame.h>
#include <uibase/imodlist.h>
#include <uibase/versioninfo.h>
#include <uibase/imodinterface.h>
#include <uibase/imodlist.h>
#include <uibase/iplugingame.h>
#include <uibase/questionboxmemory.h>
#include <uibase/report.h>
#include <uibase/versioninfo.h>

#include <bsatk/bsaarchive.h>

#include <QCoreApplication>
#include <QDir>
#include <QFileInfoList>
#include <QCoreApplication>
#include <QMessageBox>
#include <QtPlugin>

#include <functional>

using namespace MOBase;

BsaExtractor::BsaExtractor() : m_Organizer(nullptr) {}

BsaExtractor::BsaExtractor()
: m_Organizer(nullptr)
{
}

bool BsaExtractor::init(MOBase::IOrganizer *moInfo)
{
bool BsaExtractor::init(MOBase::IOrganizer *moInfo) {
m_Organizer = moInfo;
moInfo->modList()->onModInstalled([this](auto* mod) { modInstalledHandler(mod); });
moInfo->modList()->onModInstalled(
[this](auto *mod) { modInstalledHandler(mod); });
return true;
}

QString BsaExtractor::name() const
{
return "BSA Extractor";
}

QString BsaExtractor::localizedName() const
{
return tr("BSA Extractor");
}
QString BsaExtractor::name() const { return "BSA Extractor"; }

QString BsaExtractor::localizedName() const { return tr("BSA Extractor"); }

QString BsaExtractor::author() const
{
return "Tannin & MO2 Team";
}
QString BsaExtractor::author() const { return "Tannin & MO2 Team"; }

QString BsaExtractor::description() const
{
return tr("Offers a dialog during installation of a mod to unpack all its BSAs");
QString BsaExtractor::description() const {
return tr(
"Offers a dialog during installation of a mod to unpack all its BSAs");
}

VersionInfo BsaExtractor::version() const
{
VersionInfo BsaExtractor::version() const {
return VersionInfo(1, 5, 0, VersionInfo::RELEASE_FINAL);
}

QList<PluginSetting> BsaExtractor::settings() const
{
return {
PluginSetting("only_alternate_source", "only trigger bsa extraction for alternate game sources", true)
};
QList<PluginSetting> BsaExtractor::settings() const {
return {PluginSetting(
"only_alternate_source",
"only trigger bsa extraction for alternate game sources", true)};
}


bool BsaExtractor::extractProgress(QProgressDialog &progress, int percentage, std::string fileName)
{
bool BsaExtractor::extractProgress(QProgressDialog &progress, int percentage,
std::string fileName) {
progress.setLabelText(fileName.c_str());
progress.setValue(percentage);
qApp->processEvents();
return !progress.wasCanceled();
}


void BsaExtractor::modInstalledHandler(IModInterface *mod)
{
void BsaExtractor::modInstalledHandler(IModInterface *mod) {

if (m_Organizer->pluginSetting(name(), "only_alternate_source").toBool() &&
!(m_Organizer->modList()->state(mod->name()) & IModList::STATE_ALTERNATE)) {
!(m_Organizer->modList()->state(mod->name()) &
IModList::STATE_ALTERNATE)) {
return;
}

if (QFileInfo(mod->absolutePath()) == QFileInfo(m_Organizer->managedGame()->dataDirectory().absolutePath())) {
QMessageBox::information(nullptr, tr("invalid mod name"),
tr("BSA extraction doesn't work on mods that have the same name as a non-MO mod."
"Please remove the mod then reinstall with a different name."));
if (QFileInfo(mod->absolutePath()) ==
QFileInfo(m_Organizer->managedGame()->dataDirectory().absolutePath())) {
QMessageBox::information(
nullptr, tr("invalid mod name"),
tr("BSA extraction doesn't work on mods that have the same name as a "
"non-MO mod."
"Please remove the mod then reinstall with a different name."));
return;
}
QDir dir(mod->absolutePath());

QFileInfoList archives = dir.entryInfoList(QStringList({ "*.bsa", "*.ba2" }));
QFileInfoList archives = dir.entryInfoList(QStringList({"*.bsa", "*.ba2"}));
if (archives.length() != 0 &&
(QuestionBoxMemory::query(nullptr, "unpackBSA", tr("Extract BSA"),
tr("This mod contains at least one BSA. Do you want to unpack it?\n"
"(If you don't know about BSAs, just select no)"),
QDialogButtonBox::Yes | QDialogButtonBox::No, QDialogButtonBox::No) == QDialogButtonBox::Yes)) {

bool removeBSAs = (QuestionBoxMemory::query(nullptr, "removeUnpackedBSA", tr("Remove extracted archives"),
tr("Do you wish to remove BSAs after extraction completed?\n"),
QDialogButtonBox::Yes | QDialogButtonBox::No, QDialogButtonBox::No) == QDialogButtonBox::Yes);
(QuestionBoxMemory::query(
nullptr, "unpackBSA", tr("Extract BSA"),
tr("This mod contains at least one BSA. Do you want to unpack it?\n"
"(If you don't know about BSAs, just select no)"),
QDialogButtonBox::Yes | QDialogButtonBox::No,
QDialogButtonBox::No) == QDialogButtonBox::Yes)) {

bool removeBSAs =
(QuestionBoxMemory::query(
nullptr, "removeUnpackedBSA", tr("Remove extracted archives"),
tr("Do you wish to remove BSAs after extraction completed?\n"),
QDialogButtonBox::Yes | QDialogButtonBox::No,
QDialogButtonBox::No) == QDialogButtonBox::Yes);
foreach (QFileInfo archiveInfo, archives) {
BSA::Archive archive;
BSA::EErrorCode result = archive.read(archiveInfo.absoluteFilePath().toLocal8Bit().constData(), true);
BSA::EErrorCode result = archive.read(
archiveInfo.absoluteFilePath().toLocal8Bit().constData(), true);
if ((result != BSA::ERROR_NONE) && (result != BSA::ERROR_INVALIDHASHES)) {
reportError(tr("failed to read %1: %2").arg(archiveInfo.fileName()).arg(result));
reportError(tr("failed to read %1: %2")
.arg(archiveInfo.fileName())
.arg(result));
return;
}

Expand All @@ -114,27 +107,30 @@ void BsaExtractor::modInstalledHandler(IModInterface *mod)
progress.setValue(0);
progress.show();

archive.extractAll(mod->absolutePath().toLocal8Bit().constData(),
[this, &progress](int value, std::string filename) {
return extractProgress(progress, value, filename);
},
false);
archive.extractAll(
mod->absolutePath().toLocal8Bit().constData(),
[this, &progress](int value, std::string filename) {
return extractProgress(progress, value, filename);
},
false);

if (result == BSA::ERROR_INVALIDHASHES) {
reportError(tr("This archive contains invalid hashes. Some files may be broken."));
reportError(tr(
"This archive contains invalid hashes. Some files may be broken."));
}

archive.close();

if (removeBSAs) {
if (!QFile::remove(archiveInfo.absoluteFilePath())) {
qCritical("failed to remove archive %s", archiveInfo.absoluteFilePath().toUtf8().constData());
qCritical("failed to remove archive %s",
archiveInfo.absoluteFilePath().toUtf8().constData());
}
}
}
}
}

#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
Q_EXPORT_PLUGIN2(bsaextractor, BsaExtractor)
#endif
9 changes: 4 additions & 5 deletions src/bsaextractor.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,10 @@

#include <uibase/iplugin.h>

class BsaExtractor : public QObject, public MOBase::IPlugin
{
class BsaExtractor : public QObject, public MOBase::IPlugin {
Q_OBJECT
Q_INTERFACES(MOBase::IPlugin)
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
Q_PLUGIN_METADATA(IID "org.tannin.BSAExtractor")
#endif

public:
BsaExtractor();
Expand All @@ -26,7 +23,9 @@ class BsaExtractor : public QObject, public MOBase::IPlugin

private:
void modInstalledHandler(MOBase::IModInterface *mod);
bool extractProgress(QProgressDialog &progress, int percentage, std::string fileName);
bool extractProgress(QProgressDialog &progress, int percentage,
std::string fileName);

private:
MOBase::IOrganizer *m_Organizer;
};
Expand Down
6 changes: 3 additions & 3 deletions vcpkg.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,19 @@
"default-registry": {
"kind": "git",
"repository": "https://github.com/Microsoft/vcpkg",
"baseline": "294f76666c3000630d828703e675814c05a4fd43"
"baseline": "74e6536215718009aae747d86d84b78376bf9e09"
},
"registries": [
{
"kind": "git",
"repository": "https://github.com/Microsoft/vcpkg",
"baseline": "294f76666c3000630d828703e675814c05a4fd43",
"baseline": "74e6536215718009aae747d86d84b78376bf9e09",
"packages": ["boost*", "boost-*"]
},
{
"kind": "git",
"repository": "https://github.com/ModOrganizer2/vcpkg-registry",
"baseline": "8beb2e0efa9c17dd6d17bb05288dd1e40727f673",
"baseline": "92f063c71cebea1926c7eb183fbe719145395985",
"packages": ["mo2-*"]
}
]
Expand Down
Loading