- implemented frontend
- namespaced Core
- imported qdevicewatcher
- fixed bug in logging (more like in misc)
This commit is contained in:
zhupengfei
2019-08-28 19:16:05 +08:00
parent fd5106759a
commit 7df0b63a1e
22 changed files with 351 additions and 166 deletions
+3
View File
@@ -4,3 +4,6 @@
[submodule "cryptopp"] [submodule "cryptopp"]
path = externals/cryptopp/cryptopp path = externals/cryptopp/cryptopp
url = https://github.com/weidai11/cryptopp.git url = https://github.com/weidai11/cryptopp.git
[submodule "qdevicewatcher"]
path = externals/qdevicewatcher/qdevicewatcher
url = https://github.com/wang-bin/qdevicewatcher.git
+6
View File
@@ -1,2 +1,8 @@
# Crypto++
add_subdirectory(cryptopp) add_subdirectory(cryptopp)
# fmt
add_subdirectory(fmt) add_subdirectory(fmt)
# QDeviceWatcher
add_subdirectory(qdevicewatcher)
+26
View File
@@ -0,0 +1,26 @@
set(CMAKE_AUTOMOC ON)
add_definitions(-DUNICODE -D_UNICODE)
add_library(qdevicewatcher STATIC
qdevicewatcher/src/qdevicewatcher_p.h
qdevicewatcher/src/qdevicewatcher.cpp
qdevicewatcher/src/qdevicewatcher.h
)
target_link_libraries(qdevicewatcher PRIVATE Qt5::Core)
target_include_directories(qdevicewatcher INTERFACE qdevicewatcher/src)
if (WIN32)
target_sources(qdevicewatcher PRIVATE
qdevicewatcher/src/qdevicewatcher_win32.cpp
)
elseif(APPLE)
target_sources(qdevicewatcher PRIVATE
qdevicewatcher/src/qdevicewatcher_mac.cpp
)
elseif(UNIX)
target_sources(qdevicewatcher PRIVATE
qdevicewatcher/src/qdevicewatcher_linux.cpp
)
endif()
+9 -3
View File
@@ -14,6 +14,8 @@
#include <fmt/format.h> #include <fmt/format.h>
#include "common/string_util.h" #include "common/string_util.h"
#include <iostream>
template <typename... Args> template <typename... Args>
void PrintLog(std::FILE* f, const std::string& log_class, const std::string& level, void PrintLog(std::FILE* f, const std::string& log_class, const std::string& level,
const std::string& color, const std::string& file, int line, const std::string& func, const std::string& color, const std::string& file, int line, const std::string& func,
@@ -23,9 +25,13 @@ void PrintLog(std::FILE* f, const std::string& log_class, const std::string& lev
std::chrono::steady_clock::now() - time_origin) std::chrono::steady_clock::now() - time_origin)
.count(); .count();
const auto real_class = Common::ReplaceAll(log_class, "_", "."); const auto real_class = Common::ReplaceAll(log_class, "_", ".");
fmt::print(f, "\x1b{}[{:12.6f}] {} <{}> {}:{}:{}: " + format + "\x1b[0m\n", color, try {
us / 1000000.0, log_class, level, file, line, func, args...); fmt::print(f, "\x1b{}[{:12.6f}] {} <{}> {}:{}:{}: " + format + "\x1b[0m\n", color,
fflush(stderr); us / 1000000.0, real_class, level, file, line, func, args...);
fflush(stderr);
} catch (...) {
std::cerr << "FMT failed with exception" << std::endl;
}
} }
#ifdef _DEBUG #ifdef _DEBUG
+2 -2
View File
@@ -3,11 +3,11 @@
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include <cstddef> #include <cstddef>
#include <cstring>
#ifdef _WIN32 #ifdef _WIN32
#include <windows.h> #include <windows.h>
#else #else
#include <cerrno> #include <cerrno>
#include <cstring>
#endif #endif
#include "common/common_funcs.h" #include "common/common_funcs.h"
@@ -27,5 +27,5 @@ std::string GetLastErrorMsg() {
strerror_r(errno, err_str, buff_size); strerror_r(errno, err_str, buff_size);
#endif #endif
return std::string(err_str, buff_size); return std::string(err_str, strnlen(err_str, buff_size));
} }
+4
View File
@@ -6,6 +6,8 @@
#include "common/assert.h" #include "common/assert.h"
#include "core/data_container.h" #include "core/data_container.h"
namespace Core {
constexpr u32 MakeMagic(char a, char b, char c, char d) { constexpr u32 MakeMagic(char a, char b, char c, char d) {
return a | b << 8 | c << 16 | d << 24; return a | b << 8 | c << 16 | d << 24;
} }
@@ -150,3 +152,5 @@ std::vector<std::vector<u8>> DataContainer::GetIVFCLevel4Data() const {
return {GetPartitionData(0), GetPartitionData(1)}; return {GetPartitionData(0), GetPartitionData(1)};
} }
} }
} // namespace Core
+4
View File
@@ -10,6 +10,8 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "common/swap.h" #include "common/swap.h"
namespace Core {
#pragma pack(push, 1) #pragma pack(push, 1)
struct DataDescriptor { struct DataDescriptor {
u64_le offset; u64_le offset;
@@ -127,3 +129,5 @@ private:
std::vector<DataDescriptor> partition_descriptors; std::vector<DataDescriptor> partition_descriptors;
std::vector<DataDescriptor> partitions; std::vector<DataDescriptor> partitions;
}; };
} // namespace Core
+4
View File
@@ -15,6 +15,8 @@
#include "core/decryptor.h" #include "core/decryptor.h"
#include "core/key/key.h" #include "core/key/key.h"
namespace Core {
SDMCDecryptor::SDMCDecryptor(const std::string& root_folder_) : root_folder(root_folder_) { SDMCDecryptor::SDMCDecryptor(const std::string& root_folder_) : root_folder(root_folder_) {
ASSERT_MSG(Key::IsNormalKeyAvailable(Key::SDKey), ASSERT_MSG(Key::IsNormalKeyAvailable(Key::SDKey),
"SD Key must be available in order to decrypt"); "SD Key must be available in order to decrypt");
@@ -89,3 +91,5 @@ std::vector<u8> SDMCDecryptor::DecryptFile(const std::string& source) const {
aes.ProcessData(data.data(), encrypted_data.data(), encrypted_data.size()); aes.ProcessData(data.data(), encrypted_data.data(), encrypted_data.size());
return data; return data;
} }
} // namespace Core
+4
View File
@@ -8,6 +8,8 @@
#include <vector> #include <vector>
#include "common/common_types.h" #include "common/common_types.h"
namespace Core {
class SDMCDecryptor { class SDMCDecryptor {
public: public:
/** /**
@@ -35,3 +37,5 @@ public:
private: private:
std::string root_folder; std::string root_folder;
}; };
} // namespace Core
+6 -2
View File
@@ -11,6 +11,8 @@
#include "core/inner_fat.h" #include "core/inner_fat.h"
#include "core/key/key.h" #include "core/key/key.h"
namespace Core {
SDMCImporter::SDMCImporter(const Config& config_) : config(config_) { SDMCImporter::SDMCImporter(const Config& config_) : config(config_) {
is_good = Init(); is_good = Init();
} }
@@ -305,7 +307,7 @@ std::vector<Config> LoadPresetConfig(std::string mount_point) {
nullptr, mount_point + "Nintendo 3DS/", nullptr, mount_point + "Nintendo 3DS/",
[&id_regex, &ProcessDirectory](u64* /*num_entries_out*/, const std::string& directory, [&id_regex, &ProcessDirectory](u64* /*num_entries_out*/, const std::string& directory,
const std::string& virtual_name) { const std::string& virtual_name) {
if (!FileUtil::IsDirectory(directory + virtual_name)) { if (!FileUtil::IsDirectory(directory + virtual_name + "/")) {
return true; return true;
} }
@@ -313,8 +315,10 @@ std::vector<Config> LoadPresetConfig(std::string mount_point) {
return true; return true;
} }
return ProcessDirectory(directory + virtual_name); return ProcessDirectory(directory + virtual_name + "/");
}); });
return out; return out;
} }
} // namespace Core
+4
View File
@@ -9,6 +9,8 @@
#include <vector> #include <vector>
#include "common/common_types.h" #include "common/common_types.h"
namespace Core {
class SDMCDecryptor; class SDMCDecryptor;
/** /**
@@ -99,3 +101,5 @@ private:
* @return a list of preset config available. can be empty * @return a list of preset config available. can be empty
*/ */
std::vector<Config> LoadPresetConfig(std::string mount_point); std::vector<Config> LoadPresetConfig(std::string mount_point);
} // namespace Core
+4
View File
@@ -9,6 +9,8 @@
#include "core/decryptor.h" #include "core/decryptor.h"
#include "core/inner_fat.h" #include "core/inner_fat.h"
namespace Core {
constexpr u32 MakeMagic(char a, char b, char c, char d) { constexpr u32 MakeMagic(char a, char b, char c, char d) {
return a | b << 8 | c << 16 | d << 24; return a | b << 8 | c << 16 | d << 24;
} }
@@ -334,3 +336,5 @@ ArchiveFormatInfo SDExtdata::GetFormatInfo() const {
return format_info; return format_info;
} }
} // namespace Core
+4
View File
@@ -4,6 +4,8 @@
#pragma once #pragma once
namespace Core {
#include <array> #include <array>
#include <type_traits> #include <type_traits>
#include <vector> #include <vector>
@@ -194,3 +196,5 @@ private:
std::string data_path; std::string data_path;
const SDMCDecryptor& decryptor; const SDMCDecryptor& decryptor;
}; };
} // namespace Core
+2 -2
View File
@@ -6,7 +6,7 @@
#include <functional> #include <functional>
#include "core/key/arithmetic128.h" #include "core/key/arithmetic128.h"
namespace Key { namespace Core::Key {
AESKey Lrot128(const AESKey& in, u32 rot) { AESKey Lrot128(const AESKey& in, u32 rot) {
AESKey out; AESKey out;
@@ -56,4 +56,4 @@ AESKey Xor128(const AESKey& a, const AESKey& b) {
return out; return out;
} }
} // namespace Key } // namespace Core::Key
+2 -2
View File
@@ -7,11 +7,11 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "core/key/key.h" #include "core/key/key.h"
namespace Key { namespace Core::Key {
AESKey Lrot128(const AESKey& in, u32 rot); AESKey Lrot128(const AESKey& in, u32 rot);
AESKey Add128(const AESKey& a, const AESKey& b); AESKey Add128(const AESKey& a, const AESKey& b);
AESKey Add128(const AESKey& a, u64 b); AESKey Add128(const AESKey& a, u64 b);
AESKey Xor128(const AESKey& a, const AESKey& b); AESKey Xor128(const AESKey& a, const AESKey& b);
} // namespace Key } // namespace Core::Key
+2 -2
View File
@@ -11,7 +11,7 @@
#include "core/key/arithmetic128.h" #include "core/key/arithmetic128.h"
#include "core/key/key.h" #include "core/key/key.h"
namespace Key { namespace Core::Key {
namespace { namespace {
@@ -216,4 +216,4 @@ void SelectCommonKeyIndex(u8 index) {
key_slots[KeySlotID::TicketCommonKey].SetKeyY(common_key_y_slots.at(index)); key_slots[KeySlotID::TicketCommonKey].SetKeyY(common_key_y_slots.at(index));
} }
} // namespace Key } // namespace Core::Key
+2 -2
View File
@@ -9,7 +9,7 @@
#include <string> #include <string>
#include "common/common_types.h" #include "common/common_types.h"
namespace Key { namespace Core::Key {
enum KeySlotID : std::size_t { enum KeySlotID : std::size_t {
@@ -69,4 +69,4 @@ AESKey GetNormalKey(std::size_t slot_id);
void SelectCommonKeyIndex(u8 index); void SelectCommonKeyIndex(u8 index);
} // namespace Key } // namespace Core::Key
+1
View File
@@ -14,6 +14,7 @@ add_executable(threeSD
target_link_libraries(threeSD PRIVATE common core) target_link_libraries(threeSD PRIVATE common core)
target_link_libraries(threeSD PRIVATE Qt5::Widgets) target_link_libraries(threeSD PRIVATE Qt5::Widgets)
target_link_libraries(threeSD PRIVATE qdevicewatcher)
target_link_libraries(threeSD PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) target_link_libraries(threeSD PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads)
if (APPLE) if (APPLE)
+107 -2
View File
@@ -2,23 +2,128 @@
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include <string>
#include <QApplication> #include <QApplication>
#include <QStorageInfo>
#include <qdevicewatcher.h>
#include "common/file_util.h"
#include "frontend/main.h" #include "frontend/main.h"
#include "ui_main.h" #include "ui_main.h"
#ifdef __APPLE__ #ifdef __APPLE__
#include <string>
#include <unistd.h> #include <unistd.h>
#include "common/common_paths.h" #include "common/common_paths.h"
#include "common/file_util.h"
#endif #endif
MainDialog::MainDialog(QWidget* parent) : QDialog(parent), ui(std::make_unique<Ui::MainDialog>()) { MainDialog::MainDialog(QWidget* parent) : QDialog(parent), ui(std::make_unique<Ui::MainDialog>()) {
ui->setupUi(this); ui->setupUi(this);
setFixedWidth(width());
ui->buttonBox->button(QDialogButtonBox::StandardButton::Reset)->setText(tr("Refresh"));
LoadPresetConfig();
connect(ui->advancedButton, &QPushButton::clicked, [this] {
if (ui->customGroupBox->isVisible()) {
HideAdvanced();
} else {
ShowAdvanced();
}
});
connect(ui->buttonBox, &QDialogButtonBox::clicked, [this](QAbstractButton* button) {
if (button == ui->buttonBox->button(QDialogButtonBox::StandardButton::Reset)) {
LoadPresetConfig();
}
});
// Set up device watcher
auto* device_watcher = new QDeviceWatcher(this);
device_watcher->start();
connect(device_watcher, &QDeviceWatcher::deviceAdded, this, &MainDialog::LoadPresetConfig);
connect(device_watcher, &QDeviceWatcher::deviceChanged, this, &MainDialog::LoadPresetConfig);
connect(device_watcher, &QDeviceWatcher::deviceRemoved, this, &MainDialog::LoadPresetConfig);
} }
MainDialog::~MainDialog() = default; MainDialog::~MainDialog() = default;
void MainDialog::LoadPresetConfig() {
ui->configSelect->clear();
preset_config_list.clear();
for (const auto& storage : QStorageInfo::mountedVolumes()) {
if (!storage.isValid() || !storage.isReady()) {
continue;
}
auto list = Core::LoadPresetConfig(storage.rootPath().toStdString());
for (std::size_t i = 0; i < list.size(); ++i) {
preset_config_list.emplace_back(list[i]);
ui->configSelect->addItem(QString::fromStdString(list[i].sdmc_path));
}
}
if (preset_config_list.empty()) {
// Clear the text
ui->sdmcPath->setText(QString{});
ui->userPath->setText(
QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::UserDir)));
ui->movableSedPath->setText(QString{});
ui->bootrom9Path->setText(QString{});
ui->safeModeFirmPath->setText(QString{});
ui->seeddbPath->setText(QString{});
ui->secretSectorPath->setText(QString{});
ui->advancedButton->setVisible(false);
ShowAdvanced();
ui->configSelect->addItem(tr("None"));
ui->configSelect->setCurrentText(tr("None"));
} else {
ui->advancedButton->setVisible(true);
if (ui->customGroupBox->isVisible()) {
HideAdvanced();
}
}
}
void MainDialog::ShowAdvanced() {
ui->configSelect->setEnabled(false);
ui->advancedButton->setText(tr("Hide Custom Config"));
ui->customGroupBox->setVisible(true);
setMaximumHeight(1000000);
adjustSize();
const int index = ui->configSelect->currentIndex();
ui->configSelect->addItem(tr("Custom"));
ui->configSelect->setCurrentText(tr("Custom"));
if (index == -1) {
return;
}
// Load preset data
const auto config = preset_config_list[static_cast<u32>(index)];
ui->sdmcPath->setText(QString::fromStdString(config.sdmc_path));
ui->userPath->setText(QString::fromStdString(config.user_path));
ui->movableSedPath->setText(QString::fromStdString(config.movable_sed_path));
ui->bootrom9Path->setText(QString::fromStdString(config.bootrom_path));
ui->safeModeFirmPath->setText(QString::fromStdString(config.safe_mode_firm_path));
ui->seeddbPath->setText(QString::fromStdString(config.seed_db_path));
ui->secretSectorPath->setText(QString::fromStdString(config.secret_sector_path));
}
void MainDialog::HideAdvanced() {
ui->configSelect->setEnabled(true);
ui->advancedButton->setText(tr("Customize..."));
ui->customGroupBox->setVisible(false);
LoadPresetConfig();
setMaximumHeight(130);
adjustSize();
}
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
// Init settings params // Init settings params
QCoreApplication::setOrganizationName("zhaowenlan1779"); QCoreApplication::setOrganizationName("zhaowenlan1779");
+6
View File
@@ -6,6 +6,7 @@
#include <memory> #include <memory>
#include <QDialog> #include <QDialog>
#include "core/importer.h"
namespace Ui { namespace Ui {
class MainDialog; class MainDialog;
@@ -19,5 +20,10 @@ public:
~MainDialog() override; ~MainDialog() override;
private: private:
void LoadPresetConfig();
void ShowAdvanced();
void HideAdvanced();
std::vector<Core::Config> preset_config_list;
std::unique_ptr<Ui::MainDialog> ui; std::unique_ptr<Ui::MainDialog> ui;
}; };
+148 -149
View File
@@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>800</width> <width>800</width>
<height>450</height> <height>130</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@@ -26,11 +26,11 @@
<item> <item>
<widget class="QComboBox" name="configSelect"> <widget class="QComboBox" name="configSelect">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed"> <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch> <horstretch>0</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
</widget> </widget>
</item> </item>
</layout> </layout>
@@ -40,7 +40,7 @@
<item> <item>
<widget class="QPushButton" name="advancedButton"> <widget class="QPushButton" name="advancedButton">
<property name="text"> <property name="text">
<string>Advanced...</string> <string>Customize...</string>
</property> </property>
</widget> </widget>
</item> </item>
@@ -54,160 +54,159 @@
</layout> </layout>
</item> </item>
<item> <item>
<widget class="QGroupBox"> <widget class="QGroupBox" name="customGroupBox">
<property name="title"> <property name="title">
<string>Custom</string> <string>Custom</string>
</property> </property>
<property name="visible"> <property name="visible">
<bool>false</bool> <bool>false</bool>
</property> </property>
<layout class="QVBoxLayout"> <layout class="QGridLayout">
<item> <item row="0" column="0">
<layout class="QHBoxLayout"> <widget class="QLabel">
<item> <property name="text">
<widget class="QLabel"> <string>SDMC (Required)</string>
<property name="text"> </property>
<string>SDMC:</string> <property name="toolTip">
</property> <string>Path to the Nintendo 3DS/&lt;ID0>/&lt;ID1> folder.</string>
</widget> </property>
</item> </widget>
<item>
<widget class="QLineEdit" name="sdmcPath"/>
</item>
<item>
<widget class="QPushButton" name="sdmcPathExplore">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</item> </item>
<item> <item row="0" column="1">
<layout class="QHBoxLayout"> <widget class="QLineEdit" name="sdmcPath">
<item> <property name="toolTip">
<widget class="QLabel"> <string>Path to the Nintendo 3DS/&lt;ID0>/&lt;ID1> folder.</string>
<property name="text"> </property>
<string>User Directory:</string> </widget>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="userPath"/>
</item>
<item>
<widget class="QPushButton" name="userPathExplore">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</item> </item>
<item> <item row="0" column="2">
<layout class="QHBoxLayout"> <widget class="QToolButton" name="sdmcPathExplore">
<item> <property name="text">
<widget class="QLabel"> <string>...</string>
<property name="text"> </property>
<string>movable.sed:</string> </widget>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="movableSedPath"/>
</item>
<item>
<widget class="QPushButton" name="movableSedExplore">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</item> </item>
<item> <item row="1" column="0">
<layout class="QHBoxLayout"> <widget class="QLabel">
<item> <property name="text">
<widget class="QLabel"> <string>Citra User Directory (Required)</string>
<property name="text"> </property>
<string>boot9.bin:</string> <property name="toolTip">
</property> <string>Path to the User Directory of Citra to put imported content into.</string>
</widget> </property>
</item> </widget>
<item>
<widget class="QLineEdit" name="bootrom9Path"/>
</item>
<item>
<widget class="QPushButton" name="bootrom9Explore">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</item> </item>
<item> <item row="1" column="1">
<layout class="QHBoxLayout"> <widget class="QLineEdit" name="userPath">
<item> <property name="toolTip">
<widget class="QLabel"> <string>Path to the User Directory of Citra to put imported content into.</string>
<property name="text"> </property>
<string>Safe mode firm Path:</string> </widget>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="safeModeFirmPath"/>
</item>
<item>
<widget class="QPushButton" name="safeModeFirmExplore">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</item> </item>
<item> <item row="1" column="2">
<layout class="QHBoxLayout"> <widget class="QToolButton" name="userPathExplore">
<item> <property name="text">
<widget class="QLabel"> <string>...</string>
<property name="text"> </property>
<string>seeddb.bin:</string> </widget>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="seeddbPath"/>
</item>
<item>
<widget class="QPushButton" name="seeddbExplore">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</item> </item>
<item> <item row="2" column="0">
<layout class="QHBoxLayout"> <widget class="QLabel">
<item> <property name="text">
<widget class="QLabel"> <string>movable.sed (Required)</string>
<property name="text"> </property>
<string>sector0x96.bin:</string> </widget>
</property> </item>
</widget> <item row="2" column="1">
</item> <widget class="QLineEdit" name="movableSedPath"/>
<item> </item>
<widget class="QLineEdit" name="secretSectorPath"/> <item row="2" column="2">
</item> <widget class="QToolButton" name="movableSedExplore">
<item> <property name="sizePolicy">
<widget class="QPushButton" name="secretSectorExplore"> <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<property name="text"> <horstretch>0</horstretch>
<string>...</string> <verstretch>0</verstretch>
</property> </sizepolicy>
</widget> </property>
</item> <property name="text">
</layout> <string>...</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel">
<property name="text">
<string>boot9.bin (Required)</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="bootrom9Path"/>
</item>
<item row="3" column="2">
<widget class="QToolButton" name="bootrom9Explore">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel">
<property name="text">
<string>Safe mode firm</string>
</property>
<property name="toolTip">
<string>Path to the safe mode firm.&lt;br>This is a folder, and needs to contain another folder named 'new' or 'old' corresponding to the system's type.&lt;br>The 'new' or 'old' folder should hold files from the 'content' folder of the firm title in NAND. (i.e. tmd and app)</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="safeModeFirmPath">
<property name="toolTip">
<string>Path to the safe mode firm.&lt;br>This is a folder, and needs to contain another folder named 'new' or 'old' corresponding to the system's type.&lt;br>The 'new' or 'old' folder should hold files from the 'content' folder of the firm title in NAND. (i.e. tmd and app)</string>
</property>
</widget>
</item>
<item row="4" column="2">
<widget class="QToolButton" name="safeModeFirmExplore">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel">
<property name="text">
<string>seeddb.bin</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLineEdit" name="seeddbPath"/>
</item>
<item row="5" column="2">
<widget class="QToolButton" name="seeddbExplore">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel">
<property name="text">
<string>sector0x96.bin</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLineEdit" name="secretSectorPath"/>
</item>
<item row="6" column="2">
<widget class="QToolButton" name="secretSectorExplore">
<property name="text">
<string>...</string>
</property>
</widget>
</item> </item>
</layout> </layout>
</widget> </widget>