2023-11-12 01:22:01 +01:00
|
|
|
#include <hex/helpers/http_requests.hpp>
|
|
|
|
#include <hex/helpers/fmt.hpp>
|
|
|
|
#include <hex/helpers/fs.hpp>
|
2023-11-21 14:38:01 +01:00
|
|
|
#include <hex/api/localization_manager.hpp>
|
2023-11-12 01:22:01 +01:00
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
#include <random>
|
|
|
|
|
|
|
|
#include <imgui.h>
|
|
|
|
|
|
|
|
#include <hex/ui/imgui_imhex_extensions.h>
|
|
|
|
#include <content/popups/popup_notification.hpp>
|
|
|
|
|
|
|
|
#include <wolv/io/file.hpp>
|
|
|
|
|
|
|
|
namespace hex::plugin::builtin {
|
|
|
|
namespace impl {
|
|
|
|
void drawFileToolCombiner() {
|
|
|
|
static std::vector<std::fs::path> files;
|
|
|
|
static std::u8string outputPath;
|
|
|
|
static u32 selectedIndex;
|
|
|
|
static TaskHolder combinerTask;
|
|
|
|
|
|
|
|
if (ImGui::BeginTable("files_table", 2, ImGuiTableFlags_SizingStretchProp)) {
|
|
|
|
ImGui::TableSetupColumn("file list", ImGuiTableColumnFlags_NoHeaderLabel, 10);
|
|
|
|
ImGui::TableSetupColumn("buttons", ImGuiTableColumnFlags_NoHeaderLabel, 1);
|
|
|
|
ImGui::TableNextRow();
|
|
|
|
ImGui::TableNextColumn();
|
|
|
|
|
|
|
|
if (ImGui::BeginListBox("##files", { -FLT_MIN, 10 * ImGui::GetTextLineHeightWithSpacing() })) {
|
|
|
|
u32 index = 0;
|
|
|
|
for (auto &file : files) {
|
|
|
|
if (ImGui::Selectable(wolv::util::toUTF8String(file).c_str(), index == selectedIndex))
|
|
|
|
selectedIndex = index;
|
|
|
|
index++;
|
|
|
|
}
|
|
|
|
|
|
|
|
ImGui::EndListBox();
|
|
|
|
}
|
|
|
|
|
|
|
|
ImGui::TableNextColumn();
|
|
|
|
|
|
|
|
ImGui::BeginDisabled(selectedIndex <= 0);
|
|
|
|
{
|
|
|
|
if (ImGui::ArrowButton("move_up", ImGuiDir_Up)) {
|
|
|
|
std::iter_swap(files.begin() + selectedIndex, files.begin() + selectedIndex - 1);
|
|
|
|
selectedIndex--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ImGui::EndDisabled();
|
|
|
|
|
|
|
|
ImGui::BeginDisabled(files.empty() || selectedIndex >= files.size() - 1);
|
|
|
|
{
|
|
|
|
if (ImGui::ArrowButton("move_down", ImGuiDir_Down)) {
|
|
|
|
std::iter_swap(files.begin() + selectedIndex, files.begin() + selectedIndex + 1);
|
|
|
|
selectedIndex++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ImGui::EndDisabled();
|
|
|
|
|
|
|
|
ImGui::TableNextRow();
|
|
|
|
ImGui::TableNextColumn();
|
|
|
|
|
|
|
|
ImGui::BeginDisabled(combinerTask.isRunning());
|
|
|
|
{
|
|
|
|
if (ImGui::Button("hex.builtin.tools.file_tools.combiner.add"_lang)) {
|
|
|
|
fs::openFileBrowser(fs::DialogMode::Open, {}, [](const auto &path) {
|
|
|
|
files.push_back(path);
|
|
|
|
}, "", true);
|
|
|
|
}
|
|
|
|
ImGui::SameLine();
|
|
|
|
ImGui::BeginDisabled(files.empty() || selectedIndex >= files.size());
|
|
|
|
if (ImGui::Button("hex.builtin.tools.file_tools.combiner.delete"_lang)) {
|
|
|
|
files.erase(files.begin() + selectedIndex);
|
|
|
|
|
|
|
|
if (selectedIndex > 0)
|
|
|
|
selectedIndex--;
|
|
|
|
}
|
|
|
|
ImGui::EndDisabled();
|
|
|
|
ImGui::SameLine();
|
|
|
|
ImGui::BeginDisabled(files.empty());
|
|
|
|
if (ImGui::Button("hex.builtin.tools.file_tools.combiner.clear"_lang)) {
|
|
|
|
files.clear();
|
|
|
|
}
|
|
|
|
ImGui::EndDisabled();
|
|
|
|
}
|
|
|
|
ImGui::EndDisabled();
|
|
|
|
|
|
|
|
ImGui::EndTable();
|
|
|
|
}
|
|
|
|
|
|
|
|
ImGui::BeginDisabled(combinerTask.isRunning());
|
|
|
|
{
|
|
|
|
ImGui::InputText("##output_path", outputPath);
|
|
|
|
ImGui::SameLine();
|
|
|
|
if (ImGui::Button("...")) {
|
|
|
|
fs::openFileBrowser(fs::DialogMode::Save, {}, [](const auto &path) {
|
|
|
|
outputPath = path.u8string();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
ImGui::SameLine();
|
|
|
|
ImGui::TextUnformatted("hex.builtin.tools.file_tools.combiner.output"_lang);
|
|
|
|
}
|
|
|
|
ImGui::EndDisabled();
|
|
|
|
|
|
|
|
ImGui::BeginDisabled(files.empty() || outputPath.empty());
|
|
|
|
{
|
|
|
|
if (combinerTask.isRunning())
|
2023-11-16 22:24:06 +01:00
|
|
|
ImGuiExt::TextSpinner("hex.builtin.tools.file_tools.combiner.combining"_lang);
|
2023-11-12 01:22:01 +01:00
|
|
|
else {
|
|
|
|
if (ImGui::Button("hex.builtin.tools.file_tools.combiner.combine"_lang)) {
|
|
|
|
combinerTask = TaskManager::createTask("hex.builtin.tools.file_tools.combiner.combining", 0, [](auto &task) {
|
|
|
|
wolv::io::File output(outputPath, wolv::io::File::Mode::Create);
|
|
|
|
|
|
|
|
if (!output.isValid()) {
|
|
|
|
PopupError::open("hex.builtin.tools.file_tools.combiner.error.open_output"_lang);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
task.setMaxValue(files.size());
|
|
|
|
|
|
|
|
u64 fileIndex = 0;
|
|
|
|
for (const auto &file : files) {
|
|
|
|
task.update(fileIndex);
|
|
|
|
fileIndex++;
|
|
|
|
|
|
|
|
wolv::io::File input(file, wolv::io::File::Mode::Read);
|
|
|
|
if (!input.isValid()) {
|
|
|
|
PopupError::open(hex::format("hex.builtin.tools.file_tools.combiner.open_input"_lang, wolv::util::toUTF8String(file)));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
constexpr static auto BufferSize = 0xFF'FFFF;
|
|
|
|
auto inputSize = input.getSize();
|
|
|
|
for (u64 inputOffset = 0; inputOffset < inputSize; inputOffset += BufferSize) {
|
|
|
|
output.writeVector(input.readVector(std::min<u64>(BufferSize, inputSize - inputOffset)));
|
|
|
|
output.flush();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
files.clear();
|
|
|
|
selectedIndex = 0;
|
|
|
|
outputPath.clear();
|
|
|
|
|
|
|
|
PopupInfo::open("hex.builtin.tools.file_tools.combiner.success"_lang);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ImGui::EndDisabled();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|