impr: Bundle default magic file with application
This commit is contained in:
parent
80ca6bf177
commit
c444ad9280
@ -45,7 +45,7 @@ macro(add_imhex_plugin)
|
||||
)
|
||||
|
||||
# Setup a romfs for the plugin
|
||||
set(LIBROMFS_RESOURCE_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/romfs)
|
||||
list(APPEND LIBROMFS_RESOURCE_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/romfs)
|
||||
set(LIBROMFS_PROJECT_NAME ${IMHEX_PLUGIN_NAME})
|
||||
add_subdirectory(${IMHEX_BASE_FOLDER}/lib/external/libromfs ${CMAKE_CURRENT_BINARY_DIR}/libromfs)
|
||||
set_target_properties(${LIBROMFS_LIBRARY} PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
@ -54,3 +54,9 @@ macro(add_imhex_plugin)
|
||||
# Add the new plugin to the main dependency list so it gets built by default
|
||||
add_dependencies(imhex_all ${IMHEX_PLUGIN_NAME})
|
||||
endmacro()
|
||||
|
||||
macro(add_romfs_resource input output)
|
||||
configure_file(${input} ${CMAKE_CURRENT_BINARY_DIR}/romfs/${output} COPYONLY)
|
||||
|
||||
list(APPEND LIBROMFS_RESOURCE_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/romfs)
|
||||
endmacro()
|
2
lib/external/libromfs
vendored
2
lib/external/libromfs
vendored
@ -1 +1 @@
|
||||
Subproject commit 03365d8c5a43baa22cc6bbd5725db15a3038d035
|
||||
Subproject commit fd79e86893e1b71b8d53cd59310a95748388555b
|
@ -38,8 +38,8 @@ namespace hex::fs {
|
||||
}
|
||||
|
||||
// With help from https://github.com/owncloud/client/blob/cba22aa34b3677406e0499aadd126ce1d94637a2/src/gui/openfilemanager.cpp
|
||||
|
||||
void openFileExternal(const std::fs::path &filePath) {
|
||||
// Make sure the file exists before trying to open it
|
||||
if (!wolv::io::fs::exists(filePath))
|
||||
return;
|
||||
|
||||
@ -57,6 +57,7 @@ namespace hex::fs {
|
||||
}
|
||||
|
||||
void openFolderExternal(const std::fs::path &dirPath) {
|
||||
// Make sure the folder exists before trying to open it
|
||||
if (!wolv::io::fs::exists(dirPath))
|
||||
return;
|
||||
|
||||
@ -74,6 +75,7 @@ namespace hex::fs {
|
||||
}
|
||||
|
||||
void openFolderWithSelectionExternal(const std::fs::path &selectedFilePath) {
|
||||
// Make sure the file exists before trying to open it
|
||||
if (!wolv::io::fs::exists(selectedFilePath))
|
||||
return;
|
||||
|
||||
@ -198,13 +200,18 @@ namespace hex::fs {
|
||||
#else
|
||||
|
||||
bool openFileBrowser(DialogMode mode, const std::vector<ItemFilter> &validExtensions, const std::function<void(std::fs::path)> &callback, const std::string &defaultPath, bool multiple) {
|
||||
// Turn the content of the ItemFilter objects into something NFD understands
|
||||
std::vector<nfdfilteritem_t> validExtensionsNfd;
|
||||
for (const auto &extension : validExtensions) {
|
||||
validExtensionsNfd.emplace_back(nfdfilteritem_t{ extension.name.c_str(), extension.spec.c_str() });
|
||||
}
|
||||
|
||||
// Clear errors from previous runs
|
||||
NFD::ClearError();
|
||||
|
||||
// Try to initialize NFD
|
||||
if (NFD::Init() != NFD_OKAY) {
|
||||
// Handle errors if initialization failed
|
||||
log::error("NFD init returned an error: {}", NFD::GetError());
|
||||
if (s_fileBrowserErrorCallback != nullptr) {
|
||||
auto error = NFD::GetError();
|
||||
@ -216,7 +223,9 @@ namespace hex::fs {
|
||||
|
||||
NFD::UniquePathU8 outPath;
|
||||
NFD::UniquePathSet outPaths;
|
||||
nfdresult_t result;
|
||||
nfdresult_t result = NFD_ERROR;
|
||||
|
||||
// Open the correct file dialog based on the mode
|
||||
switch (mode) {
|
||||
case DialogMode::Open:
|
||||
if (multiple)
|
||||
@ -230,17 +239,20 @@ namespace hex::fs {
|
||||
case DialogMode::Folder:
|
||||
result = NFD::PickFolder(outPath, defaultPath.empty() ? nullptr : defaultPath.c_str());
|
||||
break;
|
||||
default:
|
||||
std::unreachable();
|
||||
}
|
||||
|
||||
if (result == NFD_OKAY){
|
||||
if(outPath != nullptr) {
|
||||
// Handle the path if the dialog was opened in single mode
|
||||
if (outPath != nullptr) {
|
||||
// Call the provided callback with the path
|
||||
callback(reinterpret_cast<char8_t*>(outPath.get()));
|
||||
}
|
||||
|
||||
// Handle multiple paths if the dialog was opened in multiple mode
|
||||
if (outPaths != nullptr) {
|
||||
nfdpathsetsize_t numPaths = 0;
|
||||
if (NFD::PathSet::Count(outPaths, numPaths) == NFD_OKAY) {
|
||||
// Loop over all returned paths and call the callback with each of them
|
||||
for (size_t i = 0; i < numPaths; i++) {
|
||||
NFD::UniquePathSetPath path;
|
||||
if (NFD::PathSet::GetPath(outPaths, i, path) == NFD_OKAY)
|
||||
@ -249,9 +261,14 @@ namespace hex::fs {
|
||||
}
|
||||
}
|
||||
} else if (result == NFD_ERROR) {
|
||||
// Handle errors that occurred during the file dialog call
|
||||
|
||||
log::error("Requested file dialog returned an error: {}", NFD::GetError());
|
||||
if (s_fileBrowserErrorCallback != nullptr)
|
||||
s_fileBrowserErrorCallback(NFD::GetError() ? NFD::GetError() : "No details");
|
||||
|
||||
if (s_fileBrowserErrorCallback != nullptr) {
|
||||
auto error = NFD::GetError();
|
||||
s_fileBrowserErrorCallback(error != nullptr ? error : "No details");
|
||||
}
|
||||
}
|
||||
|
||||
NFD::Quit();
|
||||
@ -266,6 +283,8 @@ namespace hex::fs {
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
|
||||
// In the portable Windows version, we just use the executable directory
|
||||
// Prevent the use of the AppData folder here
|
||||
if (!ImHexApi::System::isPortableVersion()) {
|
||||
PWSTR wAppDataPath = nullptr;
|
||||
if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_CREATE, nullptr, &wAppDataPath))) {
|
||||
@ -303,9 +322,11 @@ namespace hex::fs {
|
||||
#endif
|
||||
|
||||
|
||||
// Add additional data directories to the path
|
||||
auto additionalDirs = ImHexApi::System::getAdditionalFolderPaths();
|
||||
std::copy(additionalDirs.begin(), additionalDirs.end(), std::back_inserter(paths));
|
||||
|
||||
// Add the project file directory to the path, if one is loaded
|
||||
if (ProjectFile::hasPath()) {
|
||||
paths.push_back(ProjectFile::getPath().parent_path());
|
||||
}
|
||||
@ -332,9 +353,12 @@ namespace hex::fs {
|
||||
|
||||
std::vector<std::fs::path> getPluginPaths() {
|
||||
std::vector<std::fs::path> paths = getDataPaths();
|
||||
|
||||
// Add the system plugin directory to the path if one was provided at compile time
|
||||
#if defined(OS_LINUX) && defined(SYSTEM_PLUGINS_LOCATION)
|
||||
paths.push_back(SYSTEM_PLUGINS_LOCATION);
|
||||
paths.push_back(SYSTEM_PLUGINS_LOCATION);
|
||||
#endif
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
@ -342,6 +366,7 @@ namespace hex::fs {
|
||||
std::vector<std::fs::path> getDefaultPaths(ImHexPath path, bool listNonExisting) {
|
||||
std::vector<std::fs::path> result;
|
||||
|
||||
// Return the correct path based on the ImHexPath enum
|
||||
switch (path) {
|
||||
case ImHexPath::END:
|
||||
return { };
|
||||
@ -398,6 +423,7 @@ namespace hex::fs {
|
||||
break;
|
||||
}
|
||||
|
||||
// Remove all paths that don't exist if requested
|
||||
if (!listNonExisting) {
|
||||
result.erase(std::remove_if(result.begin(), result.end(), [](const auto &path) {
|
||||
return !wolv::io::fs::isDirectory(path);
|
||||
@ -409,6 +435,9 @@ namespace hex::fs {
|
||||
|
||||
bool isPathWritable(const std::fs::path &path) {
|
||||
constexpr static auto TestFileName = "__imhex__tmp__";
|
||||
|
||||
// Try to open the __imhex__tmp__ file in the given path
|
||||
// If one does exist already, try to delete it
|
||||
{
|
||||
wolv::io::File file(path / TestFileName, wolv::io::File::Mode::Read);
|
||||
if (file.isValid()) {
|
||||
@ -417,6 +446,8 @@ namespace hex::fs {
|
||||
}
|
||||
}
|
||||
|
||||
// Try to create a new file in the given path
|
||||
// If that fails, or the file cannot be deleted anymore afterward; the path is not writable
|
||||
wolv::io::File file(path / TestFileName, wolv::io::File::Mode::Create);
|
||||
bool result = file.isValid();
|
||||
if (!file.remove())
|
||||
@ -427,16 +458,19 @@ namespace hex::fs {
|
||||
|
||||
std::fs::path toShortPath(const std::fs::path &path) {
|
||||
#if defined(OS_WINDOWS)
|
||||
// Get the size of the short path
|
||||
size_t size = GetShortPathNameW(path.c_str(), nullptr, 0);
|
||||
if (size == 0)
|
||||
return path;
|
||||
|
||||
// Get the short path
|
||||
std::wstring newPath(size, 0x00);
|
||||
GetShortPathNameW(path.c_str(), newPath.data(), newPath.size());
|
||||
newPath.pop_back();
|
||||
|
||||
return newPath;
|
||||
#else
|
||||
// Other supported platforms don't have short paths
|
||||
return path;
|
||||
#endif
|
||||
}
|
||||
|
@ -30,15 +30,22 @@ namespace hex::magic {
|
||||
|
||||
std::error_code error;
|
||||
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Magic)) {
|
||||
for (const auto &entry : std::fs::recursive_directory_iterator(dir, error)) {
|
||||
for (const auto &entry : std::fs::directory_iterator(dir, error)) {
|
||||
auto path = std::fs::absolute(entry.path());
|
||||
|
||||
if (entry.is_regular_file() && ((sourceFiles && path.extension().empty()) || (!sourceFiles && path.extension() == ".mgc"))) {
|
||||
magicFiles += wolv::util::toUTF8String(wolv::io::fs::toShortPath(path)) + MAGIC_PATH_SEPARATOR;
|
||||
if (sourceFiles) {
|
||||
if (path.extension().empty() || entry.is_directory())
|
||||
magicFiles += wolv::util::toUTF8String(path) + MAGIC_PATH_SEPARATOR;
|
||||
} else {
|
||||
if (path.extension() == ".mgc")
|
||||
magicFiles += wolv::util::toUTF8String(path) + MAGIC_PATH_SEPARATOR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!magicFiles.empty())
|
||||
magicFiles.pop_back();
|
||||
|
||||
if (error)
|
||||
return std::nullopt;
|
||||
else
|
||||
@ -46,7 +53,7 @@ namespace hex::magic {
|
||||
}
|
||||
|
||||
bool compile() {
|
||||
magic_t ctx = magic_open(MAGIC_NONE);
|
||||
magic_t ctx = magic_open(MAGIC_CHECK);
|
||||
ON_SCOPE_EXIT { magic_close(ctx); };
|
||||
|
||||
auto magicFiles = getMagicFiles(true);
|
||||
@ -75,6 +82,9 @@ namespace hex::magic {
|
||||
return false;
|
||||
|
||||
auto result = magic_compile(ctx, magicFiles->c_str()) == 0;
|
||||
if (!result) {
|
||||
log::error("Failed to compile magic files \"{}\": {}", *magicFiles, magic_error(ctx));
|
||||
}
|
||||
|
||||
if (chdir(cwd.data()) != 0)
|
||||
return false;
|
||||
|
@ -2,6 +2,11 @@ cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include(ImHexPlugin)
|
||||
|
||||
find_file(DEFAULT_MAGIC_FILE_PATH magic.mgc HINTS ${MAGIC_INCLUDE_DIRS}/../share/misc)
|
||||
if (DEFAULT_MAGIC_FILE_PATH)
|
||||
add_romfs_resource(${DEFAULT_MAGIC_FILE_PATH} auto_extract/magic/magic.mgc)
|
||||
endif ()
|
||||
|
||||
add_imhex_plugin(
|
||||
NAME
|
||||
builtin
|
||||
@ -36,6 +41,7 @@ add_imhex_plugin(
|
||||
source/content/file_handlers.cpp
|
||||
source/content/project.cpp
|
||||
source/content/achievements.cpp
|
||||
source/content/file_extraction.cpp
|
||||
|
||||
source/content/providers/file_provider.cpp
|
||||
source/content/providers/gdb_provider.cpp
|
||||
|
26
plugins/builtin/source/content/file_extraction.cpp
Normal file
26
plugins/builtin/source/content/file_extraction.cpp
Normal file
@ -0,0 +1,26 @@
|
||||
#include <hex/helpers/fs.hpp>
|
||||
|
||||
#include <wolv/io/file.hpp>
|
||||
#include <romfs/romfs.hpp>
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
void extractBundledFiles() {
|
||||
for (const auto &romfsPath : romfs::list("auto_extract")) {
|
||||
for (const auto &imhexPath : fs::getDataPaths()) {
|
||||
wolv::io::File file(imhexPath, wolv::io::File::Mode::Create);
|
||||
|
||||
if (!file.isValid())
|
||||
continue;
|
||||
|
||||
auto data = romfs::get(romfsPath).span<u8>();
|
||||
file.writeBuffer(data.data(), data.size());
|
||||
|
||||
if (file.getSize() == data.size())
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -47,6 +47,8 @@ namespace hex::plugin::builtin {
|
||||
|
||||
void handleBorderlessWindowMode();
|
||||
|
||||
void extractBundledFiles();
|
||||
|
||||
}
|
||||
|
||||
IMHEX_PLUGIN_SUBCOMMANDS() {
|
||||
@ -107,6 +109,8 @@ IMHEX_PLUGIN_SETUP("Built-in", "WerWolv", "Default ImHex functionality") {
|
||||
registerMainMenuEntries();
|
||||
|
||||
handleBorderlessWindowMode();
|
||||
|
||||
extractBundledFiles();
|
||||
}
|
||||
|
||||
// This is the default plugin
|
||||
|
Loading…
Reference in New Issue
Block a user