[APP] Create and Extract Zarchive packages
This commit is contained in:
parent
06d7a5f0a3
commit
0fcdc12cb9
|
@ -553,17 +553,26 @@ bool EmulatorWindow::Initialize() {
|
||||||
auto main_menu = MenuItem::Create(MenuItem::Type::kNormal);
|
auto main_menu = MenuItem::Create(MenuItem::Type::kNormal);
|
||||||
auto file_menu = MenuItem::Create(MenuItem::Type::kPopup, "&File");
|
auto file_menu = MenuItem::Create(MenuItem::Type::kPopup, "&File");
|
||||||
auto recent_menu = MenuItem::Create(MenuItem::Type::kPopup, "&Open Recent");
|
auto recent_menu = MenuItem::Create(MenuItem::Type::kPopup, "&Open Recent");
|
||||||
|
auto zar_menu = MenuItem::Create(MenuItem::Type::kPopup, "&Zar Package");
|
||||||
FillRecentlyLaunchedTitlesMenu(recent_menu.get());
|
FillRecentlyLaunchedTitlesMenu(recent_menu.get());
|
||||||
{
|
{
|
||||||
file_menu->AddChild(
|
file_menu->AddChild(
|
||||||
MenuItem::Create(MenuItem::Type::kString, "&Open...", "Ctrl+O",
|
MenuItem::Create(MenuItem::Type::kString, "&Open...", "Ctrl+O",
|
||||||
std::bind(&EmulatorWindow::FileOpen, this)));
|
std::bind(&EmulatorWindow::FileOpen, this)));
|
||||||
file_menu->AddChild(std::move(recent_menu));
|
file_menu->AddChild(std::move(recent_menu));
|
||||||
|
file_menu->AddChild(MenuItem::Create(MenuItem::Type::kSeparator));
|
||||||
file_menu->AddChild(
|
file_menu->AddChild(
|
||||||
MenuItem::Create(MenuItem::Type::kString, "Install Content...",
|
MenuItem::Create(MenuItem::Type::kString, "Install Content...",
|
||||||
std::bind(&EmulatorWindow::InstallContent, this)));
|
std::bind(&EmulatorWindow::InstallContent, this)));
|
||||||
|
zar_menu->AddChild(
|
||||||
|
MenuItem::Create(MenuItem::Type::kString, "Create",
|
||||||
|
std::bind(&EmulatorWindow::CreateZarchive, this)));
|
||||||
|
zar_menu->AddChild(
|
||||||
|
MenuItem::Create(MenuItem::Type::kString, "Extract",
|
||||||
|
std::bind(&EmulatorWindow::ExtractZarchive, this)));
|
||||||
|
file_menu->AddChild(std::move(zar_menu));
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
file_menu->AddChild(MenuItem::Create(MenuItem::Type::kSeparator));
|
||||||
file_menu->AddChild(
|
file_menu->AddChild(
|
||||||
MenuItem::Create(MenuItem::Type::kString, "Close",
|
MenuItem::Create(MenuItem::Type::kString, "Close",
|
||||||
std::bind(&EmulatorWindow::FileClose, this)));
|
std::bind(&EmulatorWindow::FileClose, this)));
|
||||||
|
@ -958,20 +967,158 @@ void EmulatorWindow::InstallContent() {
|
||||||
paths = file_picker->selected_files();
|
paths = file_picker->selected_files();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!paths.empty()) {
|
if (paths.empty()) {
|
||||||
for (auto path : paths) {
|
return;
|
||||||
// Normalize the path and make absolute.
|
}
|
||||||
auto abs_path = std::filesystem::absolute(path);
|
|
||||||
auto result = emulator_->InstallContentPackage(abs_path);
|
|
||||||
|
|
||||||
if (result != X_STATUS_SUCCESS) {
|
for (auto path : paths) {
|
||||||
XELOGE("Failed to install content! Error code: {:08X}", result);
|
// Normalize the path and make absolute.
|
||||||
|
auto abs_path = std::filesystem::absolute(path);
|
||||||
|
auto result = emulator_->InstallContentPackage(abs_path);
|
||||||
|
|
||||||
xe::ui::ImGuiDialog::ShowMessageBox(
|
if (result != X_STATUS_SUCCESS) {
|
||||||
imgui_drawer_.get(), "Failed to install content!",
|
XELOGE("Failed to install content! Error code: {:08X}", result);
|
||||||
"Failed to install content!\n\nCheck xenia.log for technical "
|
|
||||||
"details.");
|
xe::ui::ImGuiDialog::ShowMessageBox(
|
||||||
}
|
imgui_drawer_.get(), "Failed to install content!",
|
||||||
|
"Failed to install content!\n\nCheck xenia.log for technical "
|
||||||
|
"details.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmulatorWindow::ExtractZarchive() {
|
||||||
|
std::vector<std::filesystem::path> zarchive_files;
|
||||||
|
std::filesystem::path extract_dir;
|
||||||
|
|
||||||
|
auto file_picker = xe::ui::FilePicker::Create();
|
||||||
|
file_picker->set_mode(ui::FilePicker::Mode::kOpen);
|
||||||
|
file_picker->set_type(ui::FilePicker::Type::kFile);
|
||||||
|
file_picker->set_multi_selection(true);
|
||||||
|
file_picker->set_title("Select Zar Package");
|
||||||
|
file_picker->set_extensions({
|
||||||
|
{"Zarchive Files (*.zar)", "*.zar"},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (file_picker->Show(window_.get())) {
|
||||||
|
zarchive_files = file_picker->selected_files();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zarchive_files.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
file_picker->set_type(ui::FilePicker::Type::kDirectory);
|
||||||
|
file_picker->set_title("Select Directory to Extract");
|
||||||
|
|
||||||
|
if (file_picker->Show(window_.get())) {
|
||||||
|
extract_dir = file_picker->selected_files().front();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extract_dir.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& zarchive_file_path : zarchive_files) {
|
||||||
|
// Normalize the path and make absolute.
|
||||||
|
auto abs_path = std::filesystem::absolute(zarchive_file_path);
|
||||||
|
std::filesystem::path abs_extract_dir;
|
||||||
|
|
||||||
|
if (zarchive_files.size() > 1) {
|
||||||
|
abs_extract_dir =
|
||||||
|
std::filesystem::absolute((extract_dir / abs_path.stem()));
|
||||||
|
} else {
|
||||||
|
abs_extract_dir = std::filesystem::absolute(extract_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
XELOGI("Extracting zar package: {}\n",
|
||||||
|
zarchive_file_path.filename().string());
|
||||||
|
|
||||||
|
auto result = emulator_->ExtractZarchivePackage(abs_path, abs_extract_dir);
|
||||||
|
|
||||||
|
if (result != X_STATUS_SUCCESS) {
|
||||||
|
std::error_code ec;
|
||||||
|
|
||||||
|
// delete incomplete output file
|
||||||
|
std::filesystem::remove(abs_extract_dir, ec);
|
||||||
|
|
||||||
|
XELOGE("Failed to extract Zarchive package.", result);
|
||||||
|
|
||||||
|
xe::ui::ImGuiDialog::ShowMessageBox(
|
||||||
|
imgui_drawer_.get(), "Failed to extract Zarchive package.",
|
||||||
|
"Failed to extract Zarchive package.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmulatorWindow::CreateZarchive() {
|
||||||
|
std::vector<std::filesystem::path> content_dirs;
|
||||||
|
std::filesystem::path zarchive_dir;
|
||||||
|
|
||||||
|
auto file_picker = xe::ui::FilePicker::Create();
|
||||||
|
file_picker->set_mode(ui::FilePicker::Mode::kOpen);
|
||||||
|
file_picker->set_type(ui::FilePicker::Type::kDirectory);
|
||||||
|
file_picker->set_multi_selection(true);
|
||||||
|
file_picker->set_title("Select Contents");
|
||||||
|
|
||||||
|
if (file_picker->Show(window_.get())) {
|
||||||
|
content_dirs = file_picker->selected_files();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (content_dirs.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (content_dirs.size() == 1) {
|
||||||
|
file_picker->set_mode(ui::FilePicker::Mode::kSave);
|
||||||
|
file_picker->set_type(ui::FilePicker::Type::kFile);
|
||||||
|
file_picker->set_multi_selection(false);
|
||||||
|
file_picker->set_file_name(content_dirs.front().stem().string());
|
||||||
|
file_picker->set_default_extension("zar");
|
||||||
|
file_picker->set_title("Zarchive File");
|
||||||
|
file_picker->set_extensions({
|
||||||
|
{"Zarchive File (*.zar)", "*.zar"},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
file_picker->set_title("Output Directory");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_picker->Show(window_.get())) {
|
||||||
|
zarchive_dir = file_picker->selected_files().front();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zarchive_dir.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& content_path : content_dirs) {
|
||||||
|
// Normalize the path and make absolute.
|
||||||
|
auto abs_content_dir = std::filesystem::absolute(content_path);
|
||||||
|
std::filesystem::path abs_zarchive_file;
|
||||||
|
|
||||||
|
if (content_dirs.size() > 1) {
|
||||||
|
abs_zarchive_file = std::filesystem::absolute(
|
||||||
|
(zarchive_dir / abs_content_dir.stem()).replace_extension("zar"));
|
||||||
|
} else {
|
||||||
|
abs_zarchive_file = std::filesystem::absolute(zarchive_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
XELOGI("Creating zar package: {}\n", abs_zarchive_file.filename().string());
|
||||||
|
|
||||||
|
auto result =
|
||||||
|
emulator_->CreateZarchivePackage(abs_content_dir, abs_zarchive_file);
|
||||||
|
|
||||||
|
if (result != X_ERROR_SUCCESS) {
|
||||||
|
std::error_code ec;
|
||||||
|
|
||||||
|
// delete incomplete output file
|
||||||
|
std::filesystem::remove(abs_zarchive_file, ec);
|
||||||
|
|
||||||
|
XELOGE("Failed to create Zarchive package.", result);
|
||||||
|
|
||||||
|
xe::ui::ImGuiDialog::ShowMessageBox(imgui_drawer_.get(),
|
||||||
|
"Failed to create Zarchive package.",
|
||||||
|
"Failed to create Zarchive package.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -206,6 +206,8 @@ class EmulatorWindow {
|
||||||
void FileOpen();
|
void FileOpen();
|
||||||
void FileClose();
|
void FileClose();
|
||||||
void InstallContent();
|
void InstallContent();
|
||||||
|
void ExtractZarchive();
|
||||||
|
void CreateZarchive();
|
||||||
void ShowContentDirectory();
|
void ShowContentDirectory();
|
||||||
void CpuTimeScalarReset();
|
void CpuTimeScalarReset();
|
||||||
void CpuTimeScalarSetHalf();
|
void CpuTimeScalarSetHalf();
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
#include "third_party/fmt/include/fmt/format.h"
|
#include "third_party/fmt/include/fmt/format.h"
|
||||||
#include "third_party/tabulate/single_include/tabulate/tabulate.hpp"
|
#include "third_party/tabulate/single_include/tabulate/tabulate.hpp"
|
||||||
#include "third_party/zarchive/include/zarchive/zarchivecommon.h"
|
#include "third_party/zarchive/include/zarchive/zarchivecommon.h"
|
||||||
|
#include "third_party/zarchive/include/zarchive/zarchivewriter.h"
|
||||||
|
#include "third_party/zarchive/src/sha_256.h"
|
||||||
#include "xenia/apu/audio_system.h"
|
#include "xenia/apu/audio_system.h"
|
||||||
#include "xenia/base/assert.h"
|
#include "xenia/base/assert.h"
|
||||||
#include "xenia/base/byte_stream.h"
|
#include "xenia/base/byte_stream.h"
|
||||||
|
@ -613,6 +615,124 @@ X_STATUS Emulator::InstallContentPackage(const std::filesystem::path& path) {
|
||||||
installation_path);
|
installation_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
X_STATUS Emulator::ExtractZarchivePackage(
|
||||||
|
const std::filesystem::path& path,
|
||||||
|
const std::filesystem::path& extract_dir) {
|
||||||
|
std::unique_ptr<vfs::Device> device =
|
||||||
|
std::make_unique<vfs::DiscZarchiveDevice>("", path);
|
||||||
|
if (!device->Initialize()) {
|
||||||
|
XELOGE("Failed to initialize device");
|
||||||
|
return X_STATUS_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (std::filesystem::exists(extract_dir)) {
|
||||||
|
// TODO(Gliniak): Popup
|
||||||
|
// Do you want to overwrite already existing data?
|
||||||
|
} else {
|
||||||
|
std::error_code error_code;
|
||||||
|
std::filesystem::create_directories(extract_dir, error_code);
|
||||||
|
if (error_code) {
|
||||||
|
return error_code.value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return vfs::VirtualFileSystem::ExtractContentFiles(device.get(), extract_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
X_STATUS Emulator::CreateZarchivePackage(
|
||||||
|
const std::filesystem::path& inputDirectory,
|
||||||
|
const std::filesystem::path& outputFile) {
|
||||||
|
std::vector<uint8_t> buffer;
|
||||||
|
buffer.resize(64 * 1024);
|
||||||
|
|
||||||
|
std::error_code ec;
|
||||||
|
PackContext packContext;
|
||||||
|
packContext.outputFilePath = outputFile;
|
||||||
|
|
||||||
|
ZArchiveWriter zWriter(
|
||||||
|
[](int32_t partIndex, void* ctx) {
|
||||||
|
PackContext* packContext = reinterpret_cast<PackContext*>(ctx);
|
||||||
|
packContext->currentOutputFile =
|
||||||
|
std::ofstream(packContext->outputFilePath, std::ios::binary);
|
||||||
|
|
||||||
|
if (!packContext->currentOutputFile.is_open()) {
|
||||||
|
XELOGI("Failed to create output file: {}\n",
|
||||||
|
packContext->outputFilePath.string());
|
||||||
|
packContext->hasError = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[](const void* data, size_t length, void* ctx) {
|
||||||
|
PackContext* packContext = reinterpret_cast<PackContext*>(ctx);
|
||||||
|
packContext->currentOutputFile.write(
|
||||||
|
reinterpret_cast<const char*>(data), length);
|
||||||
|
},
|
||||||
|
&packContext);
|
||||||
|
|
||||||
|
if (packContext.hasError) {
|
||||||
|
return X_STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto const& dirEntry :
|
||||||
|
std::filesystem::recursive_directory_iterator(inputDirectory)) {
|
||||||
|
std::filesystem::path pathEntry =
|
||||||
|
std::filesystem::relative(dirEntry.path(), inputDirectory, ec);
|
||||||
|
|
||||||
|
if (ec) {
|
||||||
|
XELOGI("Failed to get relative path {}\n", pathEntry.string());
|
||||||
|
return X_STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dirEntry.is_directory()) {
|
||||||
|
if (!zWriter.MakeDir(pathEntry.generic_string().c_str(), false)) {
|
||||||
|
XELOGI("Failed to create directory {}\n", pathEntry.string());
|
||||||
|
return X_STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
} else if (dirEntry.is_regular_file()) {
|
||||||
|
// Don't pack itself to prevent infinite packing.
|
||||||
|
if (dirEntry == outputFile) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
XELOGI("Adding file: {}\n", pathEntry.string());
|
||||||
|
|
||||||
|
if (!zWriter.StartNewFile(pathEntry.generic_string().c_str())) {
|
||||||
|
XELOGI("Failed to create archive file {}\n", pathEntry.string());
|
||||||
|
return X_STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::filesystem::path file_to_pack_path = inputDirectory / pathEntry;
|
||||||
|
FILE* file = xe::filesystem::OpenFile(file_to_pack_path, "rb");
|
||||||
|
|
||||||
|
if (!file) {
|
||||||
|
XELOGI("Failed to open input file {}\n", pathEntry.string());
|
||||||
|
return X_STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint64_t file_size = std::filesystem::file_size(file_to_pack_path);
|
||||||
|
uint64_t total_bytes_read = 0;
|
||||||
|
|
||||||
|
while (total_bytes_read < file_size) {
|
||||||
|
uint64_t bytes_read =
|
||||||
|
fread_s(buffer.data(), buffer.size(), 1, buffer.size(), file);
|
||||||
|
|
||||||
|
total_bytes_read += bytes_read;
|
||||||
|
|
||||||
|
zWriter.AppendData(buffer.data(), bytes_read);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (packContext.hasError) {
|
||||||
|
return X_STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
zWriter.Finalize();
|
||||||
|
|
||||||
|
return X_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
void Emulator::Pause() {
|
void Emulator::Pause() {
|
||||||
if (paused_) {
|
if (paused_) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -226,6 +226,21 @@ class Emulator {
|
||||||
// Extract content of package to content specific directory.
|
// Extract content of package to content specific directory.
|
||||||
X_STATUS InstallContentPackage(const std::filesystem::path& path);
|
X_STATUS InstallContentPackage(const std::filesystem::path& path);
|
||||||
|
|
||||||
|
// Extract content of zar package to desired directory.
|
||||||
|
X_STATUS Emulator::ExtractZarchivePackage(
|
||||||
|
const std::filesystem::path& path,
|
||||||
|
const std::filesystem::path& extract_dir);
|
||||||
|
|
||||||
|
// Pack contents of a folder into a zar package.
|
||||||
|
X_STATUS CreateZarchivePackage(const std::filesystem::path& inputDirectory,
|
||||||
|
const std::filesystem::path& outputFile);
|
||||||
|
|
||||||
|
struct PackContext {
|
||||||
|
std::filesystem::path outputFilePath;
|
||||||
|
std::ofstream currentOutputFile;
|
||||||
|
bool hasError{false};
|
||||||
|
};
|
||||||
|
|
||||||
void Pause();
|
void Pause();
|
||||||
void Resume();
|
void Resume();
|
||||||
bool is_paused() const { return paused_; }
|
bool is_paused() const { return paused_; }
|
||||||
|
|
|
@ -50,6 +50,16 @@ class FilePicker {
|
||||||
const std::string& title() const { return title_; }
|
const std::string& title() const { return title_; }
|
||||||
void set_title(std::string title) { title_ = std::move(title); }
|
void set_title(std::string title) { title_ = std::move(title); }
|
||||||
|
|
||||||
|
const std::string& default_extension() const { return default_extension_; }
|
||||||
|
void set_default_extension(std::string default_extension) {
|
||||||
|
default_extension_ = std::move(default_extension);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& file_name() const { return file_name_; }
|
||||||
|
void set_file_name(std::string file_name) {
|
||||||
|
file_name_ = std::move(file_name);
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<std::pair<std::string, std::string>> extensions() const {
|
std::vector<std::pair<std::string, std::string>> extensions() const {
|
||||||
return extensions_;
|
return extensions_;
|
||||||
}
|
}
|
||||||
|
@ -76,6 +86,8 @@ class FilePicker {
|
||||||
Mode mode_;
|
Mode mode_;
|
||||||
Type type_;
|
Type type_;
|
||||||
std::string title_;
|
std::string title_;
|
||||||
|
std::string default_extension_;
|
||||||
|
std::string file_name_;
|
||||||
std::vector<std::pair<std::string, std::string>> extensions_;
|
std::vector<std::pair<std::string, std::string>> extensions_;
|
||||||
bool multi_selection_;
|
bool multi_selection_;
|
||||||
|
|
||||||
|
|
|
@ -111,13 +111,37 @@ Win32FilePicker::Win32FilePicker() = default;
|
||||||
Win32FilePicker::~Win32FilePicker() = default;
|
Win32FilePicker::~Win32FilePicker() = default;
|
||||||
|
|
||||||
bool Win32FilePicker::Show(Window* parent_window) {
|
bool Win32FilePicker::Show(Window* parent_window) {
|
||||||
// TODO(benvanik): FileSaveDialog.
|
Microsoft::WRL::ComPtr<IFileDialog> file_dialog;
|
||||||
assert_true(mode() == Mode::kOpen);
|
|
||||||
|
|
||||||
Microsoft::WRL::ComPtr<IFileOpenDialog> file_dialog;
|
Microsoft::WRL::ComPtr<IFileOpenDialog> open_dialog;
|
||||||
HRESULT hr =
|
Microsoft::WRL::ComPtr<IFileSaveDialog> save_dialog;
|
||||||
CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER,
|
|
||||||
IID_PPV_ARGS(&file_dialog));
|
HRESULT hr;
|
||||||
|
|
||||||
|
if (mode() == Mode::kOpen) {
|
||||||
|
hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER,
|
||||||
|
IID_PPV_ARGS(&file_dialog));
|
||||||
|
if (!SUCCEEDED(hr)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = file_dialog.As(&open_dialog);
|
||||||
|
} else {
|
||||||
|
hr = CoCreateInstance(CLSID_FileSaveDialog, NULL, CLSCTX_INPROC_SERVER,
|
||||||
|
IID_PPV_ARGS(&file_dialog));
|
||||||
|
if (!SUCCEEDED(hr)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = file_dialog.As(&save_dialog);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SUCCEEDED(hr)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = file_dialog->SetDefaultExtension(
|
||||||
|
(LPCWSTR)xe::to_utf16(default_extension()).c_str());
|
||||||
if (!SUCCEEDED(hr)) {
|
if (!SUCCEEDED(hr)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -127,6 +151,17 @@ bool Win32FilePicker::Show(Window* parent_window) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hr = file_dialog->SetDefaultExtension(
|
||||||
|
(LPCWSTR)xe::to_utf16(default_extension()).c_str());
|
||||||
|
if (!SUCCEEDED(hr)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = file_dialog->SetFileName((LPCWSTR)xe::to_utf16(file_name()).c_str());
|
||||||
|
if (!SUCCEEDED(hr)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
DWORD flags;
|
DWORD flags;
|
||||||
hr = file_dialog->GetOptions(&flags);
|
hr = file_dialog->GetOptions(&flags);
|
||||||
if (!SUCCEEDED(hr)) {
|
if (!SUCCEEDED(hr)) {
|
||||||
|
@ -192,23 +227,44 @@ bool Win32FilePicker::Show(Window* parent_window) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Obtain the result once the user clicks the 'Open' button.
|
if (mode() == Mode::kOpen) {
|
||||||
// The result is an IShellItem object.
|
// Obtain the result once the user clicks the 'Open' button.
|
||||||
Microsoft::WRL::ComPtr<IShellItemArray> shell_items;
|
// The result is an IShellItem object.
|
||||||
hr = file_dialog->GetResults(&shell_items);
|
Microsoft::WRL::ComPtr<IShellItemArray> shell_items;
|
||||||
if (!SUCCEEDED(hr)) {
|
hr = open_dialog->GetResults(&shell_items);
|
||||||
return false;
|
if (!SUCCEEDED(hr)) {
|
||||||
}
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<std::filesystem::path> selected_files;
|
std::vector<std::filesystem::path> selected_files;
|
||||||
|
|
||||||
DWORD items_count = 0;
|
DWORD items_count = 0;
|
||||||
shell_items->GetCount(&items_count);
|
shell_items->GetCount(&items_count);
|
||||||
// Iterate over selected files
|
// Iterate over selected files
|
||||||
for (DWORD i = 0; i < items_count; i++) {
|
for (DWORD i = 0; i < items_count; i++) {
|
||||||
|
Microsoft::WRL::ComPtr<IShellItem> shell_item;
|
||||||
|
shell_items->GetItemAt(i, &shell_item);
|
||||||
|
// We are just going to print out the name of the file for sample sake.
|
||||||
|
PWSTR file_path = nullptr;
|
||||||
|
hr = shell_item->GetDisplayName(SIGDN_FILESYSPATH, &file_path);
|
||||||
|
if (!SUCCEEDED(hr)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
selected_files.push_back(std::filesystem::path(file_path));
|
||||||
|
CoTaskMemFree(file_path);
|
||||||
|
}
|
||||||
|
set_selected_files(selected_files);
|
||||||
|
} else {
|
||||||
|
// Obtain the result once the user clicks the 'Save' button.
|
||||||
|
// The result is an IShellItem object.
|
||||||
Microsoft::WRL::ComPtr<IShellItem> shell_item;
|
Microsoft::WRL::ComPtr<IShellItem> shell_item;
|
||||||
shell_items->GetItemAt(i, &shell_item);
|
hr = save_dialog->GetResult(&shell_item);
|
||||||
// We are just going to print out the name of the file for sample sake.
|
if (!SUCCEEDED(hr)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::filesystem::path> selected_files;
|
||||||
|
|
||||||
PWSTR file_path = nullptr;
|
PWSTR file_path = nullptr;
|
||||||
hr = shell_item->GetDisplayName(SIGDN_FILESYSPATH, &file_path);
|
hr = shell_item->GetDisplayName(SIGDN_FILESYSPATH, &file_path);
|
||||||
if (!SUCCEEDED(hr)) {
|
if (!SUCCEEDED(hr)) {
|
||||||
|
@ -216,8 +272,9 @@ bool Win32FilePicker::Show(Window* parent_window) {
|
||||||
}
|
}
|
||||||
selected_files.push_back(std::filesystem::path(file_path));
|
selected_files.push_back(std::filesystem::path(file_path));
|
||||||
CoTaskMemFree(file_path);
|
CoTaskMemFree(file_path);
|
||||||
|
set_selected_files(selected_files);
|
||||||
}
|
}
|
||||||
set_selected_files(selected_files);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,4 +18,6 @@ project("zarchive")
|
||||||
"zarchive/include/zarchive/zarchivewriter.h",
|
"zarchive/include/zarchive/zarchivewriter.h",
|
||||||
"zarchive/src/zarchivereader.cpp",
|
"zarchive/src/zarchivereader.cpp",
|
||||||
"zarchive/src/zarchivewriter.cpp",
|
"zarchive/src/zarchivewriter.cpp",
|
||||||
|
"zarchive/src/sha_256.c",
|
||||||
|
"zarchive/src/sha_256.h",
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue