Format files and add .gitattributes and .clang-format.

This commit is contained in:
Mikaël Capelle
2024-06-09 13:55:35 +02:00
parent 9e31068b53
commit f45b25a7b3
13 changed files with 253 additions and 181 deletions
+41
View File
@@ -0,0 +1,41 @@
---
# We'll use defaults from the LLVM style, but with 4 columns indentation.
BasedOnStyle: LLVM
IndentWidth: 2
---
Language: Cpp
DeriveLineEnding: false
UseCRLF: true
DerivePointerAlignment: false
PointerAlignment: Left
AlignConsecutiveAssignments: true
AllowShortFunctionsOnASingleLine: Inline
AllowShortIfStatementsOnASingleLine: Never
AllowShortLambdasOnASingleLine: Empty
AlwaysBreakTemplateDeclarations: Yes
AccessModifierOffset: -2
AlignTrailingComments: true
SpacesBeforeTrailingComments: 2
NamespaceIndentation: Inner
MaxEmptyLinesToKeep: 1
BreakBeforeBraces: Custom
BraceWrapping:
AfterCaseLabel: false
AfterClass: true
AfterControlStatement: false
AfterEnum: true
AfterFunction: true
AfterNamespace: true
AfterStruct: true
AfterUnion: true
AfterExternBlock: true
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: false
SplitEmptyNamespace: true
ColumnLimit: 88
ForEachMacros: ['Q_FOREACH', 'foreach']
+7
View File
@@ -0,0 +1,7 @@
# Set the default behavior, in case people don't have core.autocrlf set.
* text=auto
# Explicitly declare text files you want to always be normalized and converted
# to native line endings on checkout.
*.cpp text eol=crlf
*.h text eol=crlf
+3 -1
View File
@@ -15,6 +15,8 @@ You should have received a copy of the GNU General Public License
along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
*/
// clang-format off
#include "base_script.h"
#include <filesystem>
@@ -678,4 +680,4 @@ namespace CSharp {
return true;
}
}
}
+10 -8
View File
@@ -15,6 +15,8 @@ You should have received a copy of the GNU General Public License
along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
*/
// clang-format off
#ifndef BASE_SCRIPT_H
#define BASE_SCRIPT_H
@@ -268,7 +270,7 @@ namespace CSharp {
/// The items, previews, and descriptions are repectively ordered. In other words,
/// the i-th item in <paramref name="p_strItems"/> uses the i-th preview in
/// <paramref name="p_strPreviewPaths"/> and the i-th description in <paramref name="p_strDescriptions"/>.
///
///
/// Similarly, the idices return as results correspond to the indices of the items in
/// <paramref name="p_strItems"/>.
/// </remarks>
@@ -294,7 +296,7 @@ namespace CSharp {
/// The items, previews, and descriptions are repectively ordered. In other words,
/// the i-th item in <paramref name="p_strItems"/> uses the i-th preview in
/// <paramref name="p_imgPreviews"/> and the i-th description in <paramref name="p_strDescriptions"/>.
///
///
/// Similarly, the idices return as results correspond to the indices of the items in
/// <paramref name="p_strItems"/>.
/// </remarks>
@@ -492,7 +494,7 @@ namespace CSharp {
/// <returns>The specified value as a string.</returns>
/// <seealso cref="GetPrefsIniInt(string, string)"/>
static String^ GetPrefsIniString(String^ p_strSection, String^ p_strKey) {
// This looks wrong? Yes! But that's what used in other mod managers...
// This looks wrong? Yes! But that's what used in other mod managers...
return GetIniString("FalloutPrefs.ini", p_strSection, p_strKey);
}
@@ -504,7 +506,7 @@ namespace CSharp {
/// <returns>The specified value as an integer.</returns>
/// <seealso cref="GetPrefsIniString(string, string)"/>
static int GetPrefsIniInt(String^ p_strSection, String^ p_strKey) {
// This looks wrong? Yes! But that's what used in other mod managers...
// This looks wrong? Yes! But that's what used in other mod managers...
return GetIniInt("FalloutPrefs.ini", p_strSection, p_strKey);
}
@@ -520,7 +522,7 @@ namespace CSharp {
static bool EditIni(String^ p_strSettingsFileName, String^ p_strSection, String^ p_strKey, String^ p_strValue);
/// <summary>
/// Sets the specified value in the Fallout.ini file to the given value.
/// Sets the specified value in the Fallout.ini file to the given value.
/// </summary>
/// <param name="p_strSection">The section in the Ini file to edit.</param>
/// <param name="p_strKey">The key in the Ini file to edit.</param>
@@ -541,10 +543,10 @@ namespace CSharp {
}
// BaseScript cannot be in a namespace:
public ref struct SelectOption: public CSharp::SelectOption {
SelectOption(System::String^ item, System::String^ preview, System::String^ desc) :
public ref struct SelectOption: public CSharp::SelectOption {
SelectOption(System::String^ item, System::String^ preview, System::String^ desc) :
CSharp::SelectOption(item, preview, desc) { }
};
public ref class BaseScript: public CSharp::BaseScriptImpl { };
#endif
#endif
+3 -1
View File
@@ -1,3 +1,5 @@
// clang-format off
#include "csharp_interface.h"
#include <fstream>
@@ -153,4 +155,4 @@ namespace CSharp {
return postInstall(tree);
}
}
}
+27 -27
View File
@@ -6,35 +6,35 @@
#include "ifiletree.h"
#include "iplugininstaller.h"
namespace CSharp {
namespace CSharp
{
void init(MOBase::IOrganizer* moInfo);
void init(MOBase::IOrganizer* moInfo);
/**
* @brief Initialize the C# interface before starting an installation.
*
* @param installer The FOMOD C# installer.
* @param manager The installation manager from the installer.
* @param parentWidget The parent widget from the installer.
* @param tree The archive tree.
* @param extractedEntries A map from extracted entries to their extracted path.
*/
void beforeInstall(
MOBase::IPlugin const* installer,
MOBase::IInstallationManager* manager,
QWidget* parentWidget,
std::shared_ptr<MOBase::IFileTree> tree,
/**
* @brief Initialize the C# interface before starting an installation.
*
* @param installer The FOMOD C# installer.
* @param manager The installation manager from the installer.
* @param parentWidget The parent widget from the installer.
* @param tree The archive tree.
* @param extractedEntries A map from extracted entries to their extracted path.
*/
void beforeInstall(
MOBase::IPlugin const* installer, MOBase::IInstallationManager* manager,
QWidget* parentWidget, std::shared_ptr<MOBase::IFileTree> tree,
std::map<std::shared_ptr<const MOBase::FileTreeEntry>, QString> extractedEntries);
/**
* @brief Clear the C# interface after an installation.
*
* @param scriptPath Path to the script to execute.
* @param tree Reference where the final tree will be stored (in case of success.
*
* @return the installation result after performing post-installation.
*/
MOBase::IPluginInstaller::EInstallResult executeCSharpScript(QString scriptPath, std::shared_ptr<MOBase::IFileTree>& tree);
/**
* @brief Clear the C# interface after an installation.
*
* @param scriptPath Path to the script to execute.
* @param tree Reference where the final tree will be stored (in case of success.
*
* @return the installation result after performing post-installation.
*/
MOBase::IPluginInstaller::EInstallResult
executeCSharpScript(QString scriptPath, std::shared_ptr<MOBase::IFileTree>& tree);
}
#endif
} // namespace CSharp
#endif
+4 -2
View File
@@ -1,3 +1,5 @@
// clang-format off
#ifndef CSHARP_UTILS_H
#define CSHARP_UTILS_H
@@ -17,7 +19,7 @@ namespace CSharp {
*/
inline std::string to_string(System::String^ value) {
return msclr::interop::marshal_as<std::string>(value);
}
}
inline std::wstring to_wstring(System::String^ value) {
return msclr::interop::marshal_as<std::wstring>(value);
}
@@ -36,4 +38,4 @@ namespace CSharp {
}
#endif
#endif
+30 -17
View File
@@ -17,20 +17,22 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "iinstallationmanager.h"
#include "csharp_interface.h"
#include "installer_fomod_csharp.h"
#include "installer_fomod_predialog.h"
#include "xml_info_reader.h"
#include "installer_fomod_csharp.h"
#include "csharp_interface.h"
using namespace MOBase;
bool InstallerFomodCSharp::init(IOrganizer* moInfo) {
bool InstallerFomodCSharp::init(IOrganizer* moInfo)
{
m_MOInfo = moInfo;
CSharp::init(moInfo);
return true;
}
std::shared_ptr<const IFileTree> InstallerFomodCSharp::findFomodDirectory(std::shared_ptr<const IFileTree> tree) const
std::shared_ptr<const IFileTree>
InstallerFomodCSharp::findFomodDirectory(std::shared_ptr<const IFileTree> tree) const
{
auto entry = tree->find("fomod", FileTreeEntry::DIRECTORY);
@@ -55,7 +57,9 @@ std::shared_ptr<const IFileTree> InstallerFomodCSharp::findFomodDirectory(std::s
return findFomodDirectory(tree->at(0)->astree());
}
std::shared_ptr<const FileTreeEntry> InstallerFomodCSharp::findScriptFile(std::shared_ptr<const IFileTree> tree) const {
std::shared_ptr<const FileTreeEntry>
InstallerFomodCSharp::findScriptFile(std::shared_ptr<const IFileTree> tree) const
{
auto fomodDirectory = findFomodDirectory(tree);
if (fomodDirectory == nullptr) {
@@ -71,7 +75,9 @@ std::shared_ptr<const FileTreeEntry> InstallerFomodCSharp::findScriptFile(std::s
return nullptr;
}
std::shared_ptr<const FileTreeEntry> InstallerFomodCSharp::findInfoFile(std::shared_ptr<const IFileTree> tree) const {
std::shared_ptr<const FileTreeEntry>
InstallerFomodCSharp::findInfoFile(std::shared_ptr<const IFileTree> tree) const
{
auto fomodDirectory = findFomodDirectory(tree);
if (fomodDirectory == nullptr) {
@@ -87,14 +93,19 @@ std::shared_ptr<const FileTreeEntry> InstallerFomodCSharp::findInfoFile(std::sha
return nullptr;
}
bool InstallerFomodCSharp::isArchiveSupported(std::shared_ptr<const MOBase::IFileTree> tree) const {
bool InstallerFomodCSharp::isArchiveSupported(
std::shared_ptr<const MOBase::IFileTree> tree) const
{
return findScriptFile(tree) != nullptr;
}
InstallerFomodCSharp::EInstallResult InstallerFomodCSharp::install(MOBase::GuessedValue<QString>& modName, std::shared_ptr<MOBase::IFileTree>& tree,
QString& version, int& modID)
InstallerFomodCSharp::EInstallResult
InstallerFomodCSharp::install(MOBase::GuessedValue<QString>& modName,
std::shared_ptr<MOBase::IFileTree>& tree,
QString& version, int& modID)
{
static std::set<QString, FileNameComparator> imageSuffixes{ "png", "jpg", "jpeg", "gif", "bmp" };
static std::set<QString, FileNameComparator> imageSuffixes{"png", "jpg", "jpeg",
"gif", "bmp"};
// Extract the script file:
auto scriptFile = findScriptFile(tree);
@@ -106,7 +117,7 @@ InstallerFomodCSharp::EInstallResult InstallerFomodCSharp::install(MOBase::Guess
auto infoFile = findInfoFile(tree);
// Set containing everything to extract except the script and the info file:
std::set<std::shared_ptr<const FileTreeEntry>> toExtractSet{ scriptFile };
std::set<std::shared_ptr<const FileTreeEntry>> toExtractSet{scriptFile};
if (infoFile != nullptr) {
toExtractSet.insert(infoFile);
@@ -118,7 +129,7 @@ InstallerFomodCSharp::EInstallResult InstallerFomodCSharp::install(MOBase::Guess
toExtractSet.insert(entry);
}
return IFileTree::WalkReturn::CONTINUE;
});
});
// Extract everything from the fomod/ folder:
auto fomodFolder = findFomodDirectory(tree);
@@ -127,7 +138,7 @@ InstallerFomodCSharp::EInstallResult InstallerFomodCSharp::install(MOBase::Guess
toExtractSet.insert(entry);
}
return IFileTree::WalkReturn::CONTINUE;
});
});
// Convert to vector:
std::vector toExtract(std::begin(toExtractSet), std::end(toExtractSet));
@@ -166,8 +177,7 @@ InstallerFomodCSharp::EInstallResult InstallerFomodCSharp::install(MOBase::Guess
if (dialog.manualRequested()) {
modName.update(dialog.getName(), GUESS_USER);
return EInstallResult::RESULT_MANUALREQUESTED;
}
else {
} else {
return EInstallResult::RESULT_CANCELED;
}
}
@@ -175,6 +185,9 @@ InstallerFomodCSharp::EInstallResult InstallerFomodCSharp::install(MOBase::Guess
// Run the C# script:
const QString scriptPath = entryToPath[scriptFile];
CSharp::beforeInstall(this, manager(), parentWidget(), std::const_pointer_cast<IFileTree>(scriptFile->parent()->parent()), std::move(entryToPath));
CSharp::beforeInstall(
this, manager(), parentWidget(),
std::const_pointer_cast<IFileTree>(scriptFile->parent()->parent()),
std::move(entryToPath));
return CSharp::executeCSharpScript(scriptPath, tree);
}
}
+29 -31
View File
@@ -20,67 +20,65 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "iplugininstallersimple.h"
class InstallerFomodCSharp : public MOBase::IPluginInstallerSimple
class InstallerFomodCSharp : public MOBase::IPluginInstallerSimple
{
Q_OBJECT
Q_INTERFACES(MOBase::IPlugin MOBase::IPluginInstaller MOBase::IPluginInstallerSimple)
Q_PLUGIN_METADATA(IID "org.holt59.InstallerFomodCSharp")
public:
InstallerFomodCSharp() { }
InstallerFomodCSharp() {}
virtual bool init(MOBase::IOrganizer* moInfo) override;
virtual QString name() const override {
return "Fomod Installer C#";
}
virtual QString name() const override { return "Fomod Installer C#"; }
virtual QString localizedName() const override {
return tr("Fomod Installer C#");
}
virtual QString localizedName() const override { return tr("Fomod Installer C#"); }
virtual QString author() const override {
return "Holt59";
}
virtual QString author() const override { return "Holt59"; }
virtual QString description() const override {
virtual QString description() const override
{
return tr("Installer for C# based FOMOD archives.");
}
virtual MOBase::VersionInfo version() const override {
virtual MOBase::VersionInfo version() const override
{
return MOBase::VersionInfo(1, 0, 0, MOBase::VersionInfo::RELEASE_BETA);
}
virtual QList<MOBase::PluginSetting> settings() const override {
virtual QList<MOBase::PluginSetting> settings() const override
{
return {
MOBase::PluginSetting("enabled", "check to enable this plugin", QVariant(true)),
MOBase::PluginSetting("prefer", "prefer this over the NCC based plugin", QVariant(true))
};
MOBase::PluginSetting("enabled", "check to enable this plugin", QVariant(true)),
MOBase::PluginSetting("prefer", "prefer this over the NCC based plugin",
QVariant(true))};
}
virtual unsigned int priority() const override {
virtual unsigned int priority() const override
{
// It's the same priority as the FOMOD installer but those should never conflict:
return m_MOInfo->pluginSetting(name(), "prefer").toBool() ? 110 : 90;
}
virtual bool isManualInstaller() const override {
return false;
}
virtual bool isManualInstaller() const override { return false; }
virtual bool isArchiveSupported(std::shared_ptr<const MOBase::IFileTree> tree) const override;
virtual bool
isArchiveSupported(std::shared_ptr<const MOBase::IFileTree> tree) const override;
virtual EInstallResult install(MOBase::GuessedValue<QString>& modName, std::shared_ptr<MOBase::IFileTree>& tree,
QString& version, int& modID) override;
virtual EInstallResult install(MOBase::GuessedValue<QString>& modName,
std::shared_ptr<MOBase::IFileTree>& tree,
QString& version, int& modID) override;
private:
MOBase::IOrganizer* m_MOInfo;
std::shared_ptr<const MOBase::IFileTree> findFomodDirectory(std::shared_ptr<const MOBase::IFileTree> tree) const;
std::shared_ptr<const MOBase::FileTreeEntry> findScriptFile(std::shared_ptr<const MOBase::IFileTree> tree) const;
std::shared_ptr<const MOBase::FileTreeEntry> findInfoFile(std::shared_ptr<const MOBase::IFileTree> tree) const;
std::shared_ptr<const MOBase::IFileTree>
findFomodDirectory(std::shared_ptr<const MOBase::IFileTree> tree) const;
std::shared_ptr<const MOBase::FileTreeEntry>
findScriptFile(std::shared_ptr<const MOBase::IFileTree> tree) const;
std::shared_ptr<const MOBase::FileTreeEntry>
findInfoFile(std::shared_ptr<const MOBase::IFileTree> tree) const;
};
#endif
#endif
+17 -14
View File
@@ -16,8 +16,8 @@ class InstallerFomodPostDialog : public QDialog
Q_OBJECT
public:
enum class Result {
enum class Result
{
APPLY,
DISCARD,
MOVE,
@@ -29,13 +29,14 @@ public:
* @param preset suggested name for the mod
* @param parent parent widget
**/
explicit InstallerFomodPostDialog(QWidget* parent = 0) :
QDialog(parent), ui(new Ui::FomodCSharpPostDialog) {
explicit InstallerFomodPostDialog(QWidget* parent = 0)
: QDialog(parent), ui(new Ui::FomodCSharpPostDialog)
{
ui->setupUi(this);
setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint));
}
~InstallerFomodPostDialog() { }
~InstallerFomodPostDialog() {}
/**
* @return the result of this dialog if the user did not cancel.
@@ -45,7 +46,8 @@ public:
/**
*
*/
void setIniSettings(std::map<QString, PSettings> const& settings) {
void setIniSettings(std::map<QString, PSettings> const& settings)
{
for (auto p : settings) {
QTextEdit* widget = new QTextEdit(this);
widget->append(p.second.toString());
@@ -56,29 +58,30 @@ public:
private slots:
void on_discardBtn_clicked() {
void on_discardBtn_clicked()
{
m_Result = Result::DISCARD;
this->accept();
}
void on_applyBtn_clicked() {
void on_applyBtn_clicked()
{
m_Result = Result::APPLY;
this->accept();
}
void on_moveBtn_clicked() {
void on_moveBtn_clicked()
{
m_Result = Result::MOVE;
this->accept();
}
void on_cancelBtn_clicked() {
this->reject();
}
void on_cancelBtn_clicked() { this->reject(); }
private:
std::unique_ptr<Ui::FomodCSharpPostDialog> ui;
Result m_Result{ Result::APPLY };
Result m_Result{Result::APPLY};
};
#endif
#endif
+12 -13
View File
@@ -7,7 +7,6 @@
#include <QCompleter>
/**
* @brief Dialog for the installation of a simple archive
* a simple archive is one that doesn't require any manual changes to work correctly
@@ -23,13 +22,16 @@ public:
* @param preset suggested name for the mod
* @param parent parent widget
**/
explicit InstallerFomodPredialog(const MOBase::GuessedValue<QString>& preset, QWidget* parent = 0) :
QDialog(parent), ui(new Ui::FomodCSharpPredialog), m_Manual(false) {
explicit InstallerFomodPredialog(const MOBase::GuessedValue<QString>& preset,
QWidget* parent = 0)
: QDialog(parent), ui(new Ui::FomodCSharpPredialog), m_Manual(false)
{
ui->setupUi(this);
setWindowTitle(preset + " - " + windowTitle());
for (auto iter = preset.variants().begin(); iter != preset.variants().end(); ++iter) {
for (auto iter = preset.variants().begin(); iter != preset.variants().end();
++iter) {
ui->nameCombo->addItem(*iter);
}
@@ -38,7 +40,7 @@ public:
ui->nameCombo->completer()->setCaseSensitivity(Qt::CaseSensitive);
}
~InstallerFomodPredialog() { }
~InstallerFomodPredialog() {}
/**
* @return true if the user requested a manual installation.
@@ -52,15 +54,12 @@ public:
private slots:
void on_okBtn_clicked() {
this->accept();
}
void on_okBtn_clicked() { this->accept(); }
void on_cancelBtn_clicked() {
this->reject();
}
void on_cancelBtn_clicked() { this->reject(); }
void on_manualBtn_clicked() {
void on_manualBtn_clicked()
{
m_Manual = true;
this->reject();
}
@@ -70,4 +69,4 @@ private:
bool m_Manual;
};
#endif
#endif
+20 -17
View File
@@ -1,9 +1,9 @@
#ifndef PSETTINGS_H
#define PSETTINGS_H
#include <map>
#include <QString>
#include <QSettings>
#include <QString>
#include <map>
/**
* This is a small class that can be used to store INI settings in memory since
@@ -11,15 +11,15 @@
*
* It is a much simpler structure since it stores everything as string.
*/
struct PSettings {
struct PSettings
{
/**
*
*/
PSettings() = default;
public: // Value read/write.
public: // Value read/write.
/**
* @brief Set the value of the given section/key.
*
@@ -27,7 +27,8 @@ public: // Value read/write.
* @param key The key of the value.
* @param value The value to set.
*/
void setValue(QString section, QString key, QString value) {
void setValue(QString section, QString key, QString value)
{
m_Values[std::make_pair(section, key)] = value;
}
@@ -37,9 +38,11 @@ public: // Value read/write.
* @param section The section of the value.
* @param key The key of the value.
*
* @return the corresponding value, or an empty string if the section/key does not exist.
* @return the corresponding value, or an empty string if the section/key does not
* exist.
*/
QString value(QString section, QString key) const {
QString value(QString section, QString key) const
{
auto it = m_Values.find(std::make_pair(section, key));
return it == m_Values.end() ? QString() : it->second;
}
@@ -52,19 +55,20 @@ public: // Value read/write.
*
* @return true if the section/key exist.
*/
bool hasValue(QString section, QString key) const {
bool hasValue(QString section, QString key) const
{
return m_Values.find(std::make_pair(section, key)) != m_Values.end();
}
public: // Output:
public: // Output:
/**
* @brief Convert this PSettings to a string.
*
* @return a string representing the content of a valid INI file corresponding
* to this PSettings.
*/
QString toString() const {
QString toString() const
{
QString result = "";
QString cSection;
for (auto& p : m_Values) {
@@ -85,12 +89,12 @@ public: // Output:
*
* @param settings The settings to update.
*/
void update(QSettings& settings) const {
void update(QSettings& settings) const
{
for (auto& p : m_Values) {
if (p.first.first == "General") {
settings.setValue(p.first.second, p.second);
}
else {
} else {
settings.setValue(p.first.first + "/" + p.first.second, p.second);
}
}
@@ -99,7 +103,6 @@ public: // Output:
private:
// Map from <section, key> to value:
std::map<std::pair<QString, QString>, QString> m_Values;
};
#endif // !PSETTINGS_H
#endif // !PSETTINGS_H
+50 -50
View File
@@ -1,36 +1,37 @@
#ifndef XML_INFO_READER_H
#define XML_INFO_READER_H
#include <QString>
#include <QIODevice>
#include <QXmlStreamReader>
#include <QTextStream>
#include <QFile>
#include <QIODevice>
#include <QString>
#include <QStringEncoder>
#include <QTextStream>
#include <QXmlStreamReader>
#include "utility.h"
#include "log.h"
#include "utility.h"
// This is from installer_fomod, but should probably not be duplicated here.
struct FomodInfoReader: QObject {
struct FomodInfoReader : QObject
{
Q_OBJECT
public:
struct XmlParseError : MOBase::Exception {
XmlParseError(const QString& message): MOBase::Exception(message) {}
struct XmlParseError : MOBase::Exception
{
XmlParseError(const QString& message) : MOBase::Exception(message) {}
};
static QByteArray skipXmlHeader(QIODevice& file)
{
static const unsigned char UTF16LE_BOM[] = { 0xFF, 0xFE };
static const unsigned char UTF16BE_BOM[] = { 0xFE, 0xFF };
static const unsigned char UTF8_BOM[] = { 0xEF, 0xBB, 0xBF };
static const unsigned char UTF16LE[] = { 0x3C, 0x00, 0x3F, 0x00 };
static const unsigned char UTF16BE[] = { 0x00, 0x3C, 0x00, 0x3F };
static const unsigned char UTF8[] = { 0x3C, 0x3F, 0x78, 0x6D };
static const unsigned char UTF16LE_BOM[] = {0xFF, 0xFE};
static const unsigned char UTF16BE_BOM[] = {0xFE, 0xFF};
static const unsigned char UTF8_BOM[] = {0xEF, 0xBB, 0xBF};
static const unsigned char UTF16LE[] = {0x3C, 0x00, 0x3F, 0x00};
static const unsigned char UTF16BE[] = {0x00, 0x3C, 0x00, 0x3F};
static const unsigned char UTF8[] = {0x3C, 0x3F, 0x78, 0x6D};
file.seek(0);
QByteArray rawBytes = file.read(4);
@@ -39,24 +40,19 @@ public:
if (rawBytes.startsWith((const char*)UTF16LE_BOM)) {
stream.setEncoding(QStringEncoder::Encoding::Utf16LE);
bom = 2;
}
else if (rawBytes.startsWith((const char*)UTF16BE_BOM)) {
} else if (rawBytes.startsWith((const char*)UTF16BE_BOM)) {
stream.setEncoding(QStringEncoder::Encoding::Utf16BE);
bom = 2;
}
else if (rawBytes.startsWith((const char*)UTF8_BOM)) {
} else if (rawBytes.startsWith((const char*)UTF8_BOM)) {
stream.setEncoding(QStringEncoder::Encoding::Utf8);
bom = 3;
}
else if (rawBytes.startsWith(QByteArray((const char*)UTF16LE, 4))) {
} else if (rawBytes.startsWith(QByteArray((const char*)UTF16LE, 4))) {
stream.setEncoding(QStringEncoder::Encoding::Utf16LE);
}
else if (rawBytes.startsWith(QByteArray((const char*)UTF16BE, 4))) {
} else if (rawBytes.startsWith(QByteArray((const char*)UTF16BE, 4))) {
stream.setEncoding(QStringEncoder::Encoding::Utf16BE);
}
else if (rawBytes.startsWith(QByteArray((const char*)UTF8, 4))) {
} else if (rawBytes.startsWith(QByteArray((const char*)UTF8, 4))) {
stream.setEncoding(QStringEncoder::Encoding::Utf8);
} // otherwise maybe the textstream knows the encoding?
} // otherwise maybe the textstream knows the encoding?
stream.seek(bom);
QString header = stream.readLine();
@@ -70,18 +66,20 @@ public:
}
template <class Fn>
static auto readXml(QFile& file, Fn &&fn)
static auto readXml(QFile& file, Fn&& fn)
{
// List of encodings to try:
static const std::vector<QStringConverter::Encoding> encodings{ QStringConverter::Utf16, QStringConverter::Utf8, QStringConverter::Latin1 };
static const std::vector<QStringConverter::Encoding> encodings{
QStringConverter::Utf16, QStringConverter::Utf8, QStringConverter::Latin1};
std::string errorMessage;
try {
QXmlStreamReader reader(&file);
return fn(reader);
}
catch (const XmlParseError& e) {
MOBase::log::warn("The {} in this file is incorrectly encoded ({}). Applying heuristics...", file.fileName(), e.what());
} catch (const XmlParseError& e) {
MOBase::log::warn(
"The {} in this file is incorrectly encoded ({}). Applying heuristics...",
file.fileName(), e.what());
}
// nmm's xml parser is less strict than the one from qt and allows files with
@@ -91,50 +89,52 @@ public:
// try parsing the file with several encodings to support broken files
for (auto encoding : encodings) {
MOBase::log::debug("Trying encoding {} for {}... ", QStringConverter::nameForEncoding(encoding), file.fileName());
MOBase::log::debug("Trying encoding {} for {}... ",
QStringConverter::nameForEncoding(encoding), file.fileName());
try {
QStringEncoder encoder(encoding);
QXmlStreamReader reader(encoder.encode(QString("<?xml version=\"1.0\" encoding=\"%1\" ?>").arg(encoder.name())) + headerlessData);
QXmlStreamReader reader(
encoder.encode(QString("<?xml version=\"1.0\" encoding=\"%1\" ?>")
.arg(encoder.name())) +
headerlessData);
MOBase::log::debug("Interpreting {} as {}.", file.fileName(), encoder.name());
return fn(reader);
}
catch (const XmlParseError& e) {
MOBase::log::debug("Not {}: {}.", QStringConverter::nameForEncoding(encoding), e.what());
} catch (const XmlParseError& e) {
MOBase::log::debug("Not {}: {}.", QStringConverter::nameForEncoding(encoding),
e.what());
}
}
throw XmlParseError(tr("Failed to parse %1. See console for details.").arg(file.fileName()));
throw XmlParseError(
tr("Failed to parse %1. See console for details.").arg(file.fileName()));
}
static std::tuple<QString, int, QString> parseInfo(QXmlStreamReader& reader)
{
std::tuple<QString, int, QString> info{ "", -1, "" };
std::tuple<QString, int, QString> info{"", -1, ""};
while (!reader.atEnd()) {
switch (reader.readNext()) {
case QXmlStreamReader::StartElement: {
if (reader.name().toString() == "Name") {
std::get<0>(info) = reader.readElementText();
}
else if (reader.name().toString() == "Author") {
}
else if (reader.name().toString() == "Version") {
} else if (reader.name().toString() == "Author") {
} else if (reader.name().toString() == "Version") {
std::get<2>(info) = reader.readElementText();
}
else if (reader.name().toString() == "Id") {
} else if (reader.name().toString() == "Id") {
std::get<1>(info) = reader.readElementText().toInt();
}
else if (reader.name().toString() == "Website") {
} else if (reader.name().toString() == "Website") {
}
} break;
default: {} break;
default: {
} break;
}
}
if (reader.hasError()) {
throw XmlParseError(QString("%1 in line %2").arg(reader.errorString()).arg(reader.lineNumber()));
throw XmlParseError(
QString("%1 in line %2").arg(reader.errorString()).arg(reader.lineNumber()));
}
return info;
}
};
#endif
#endif