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
|
# 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})
|
set(LIBROMFS_PROJECT_NAME ${IMHEX_PLUGIN_NAME})
|
||||||
add_subdirectory(${IMHEX_BASE_FOLDER}/lib/external/libromfs ${CMAKE_CURRENT_BINARY_DIR}/libromfs)
|
add_subdirectory(${IMHEX_BASE_FOLDER}/lib/external/libromfs ${CMAKE_CURRENT_BINARY_DIR}/libromfs)
|
||||||
set_target_properties(${LIBROMFS_LIBRARY} PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
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 the new plugin to the main dependency list so it gets built by default
|
||||||
add_dependencies(imhex_all ${IMHEX_PLUGIN_NAME})
|
add_dependencies(imhex_all ${IMHEX_PLUGIN_NAME})
|
||||||
endmacro()
|
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
|
// With help from https://github.com/owncloud/client/blob/cba22aa34b3677406e0499aadd126ce1d94637a2/src/gui/openfilemanager.cpp
|
||||||
|
|
||||||
void openFileExternal(const std::fs::path &filePath) {
|
void openFileExternal(const std::fs::path &filePath) {
|
||||||
|
// Make sure the file exists before trying to open it
|
||||||
if (!wolv::io::fs::exists(filePath))
|
if (!wolv::io::fs::exists(filePath))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -57,6 +57,7 @@ namespace hex::fs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void openFolderExternal(const std::fs::path &dirPath) {
|
void openFolderExternal(const std::fs::path &dirPath) {
|
||||||
|
// Make sure the folder exists before trying to open it
|
||||||
if (!wolv::io::fs::exists(dirPath))
|
if (!wolv::io::fs::exists(dirPath))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -74,6 +75,7 @@ namespace hex::fs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void openFolderWithSelectionExternal(const std::fs::path &selectedFilePath) {
|
void openFolderWithSelectionExternal(const std::fs::path &selectedFilePath) {
|
||||||
|
// Make sure the file exists before trying to open it
|
||||||
if (!wolv::io::fs::exists(selectedFilePath))
|
if (!wolv::io::fs::exists(selectedFilePath))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -198,13 +200,18 @@ namespace hex::fs {
|
|||||||
#else
|
#else
|
||||||
|
|
||||||
bool openFileBrowser(DialogMode mode, const std::vector<ItemFilter> &validExtensions, const std::function<void(std::fs::path)> &callback, const std::string &defaultPath, bool multiple) {
|
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;
|
std::vector<nfdfilteritem_t> validExtensionsNfd;
|
||||||
for (const auto &extension : validExtensions) {
|
for (const auto &extension : validExtensions) {
|
||||||
validExtensionsNfd.emplace_back(nfdfilteritem_t{ extension.name.c_str(), extension.spec.c_str() });
|
validExtensionsNfd.emplace_back(nfdfilteritem_t{ extension.name.c_str(), extension.spec.c_str() });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clear errors from previous runs
|
||||||
NFD::ClearError();
|
NFD::ClearError();
|
||||||
|
|
||||||
|
// Try to initialize NFD
|
||||||
if (NFD::Init() != NFD_OKAY) {
|
if (NFD::Init() != NFD_OKAY) {
|
||||||
|
// Handle errors if initialization failed
|
||||||
log::error("NFD init returned an error: {}", NFD::GetError());
|
log::error("NFD init returned an error: {}", NFD::GetError());
|
||||||
if (s_fileBrowserErrorCallback != nullptr) {
|
if (s_fileBrowserErrorCallback != nullptr) {
|
||||||
auto error = NFD::GetError();
|
auto error = NFD::GetError();
|
||||||
@ -216,7 +223,9 @@ namespace hex::fs {
|
|||||||
|
|
||||||
NFD::UniquePathU8 outPath;
|
NFD::UniquePathU8 outPath;
|
||||||
NFD::UniquePathSet outPaths;
|
NFD::UniquePathSet outPaths;
|
||||||
nfdresult_t result;
|
nfdresult_t result = NFD_ERROR;
|
||||||
|
|
||||||
|
// Open the correct file dialog based on the mode
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case DialogMode::Open:
|
case DialogMode::Open:
|
||||||
if (multiple)
|
if (multiple)
|
||||||
@ -230,17 +239,20 @@ namespace hex::fs {
|
|||||||
case DialogMode::Folder:
|
case DialogMode::Folder:
|
||||||
result = NFD::PickFolder(outPath, defaultPath.empty() ? nullptr : defaultPath.c_str());
|
result = NFD::PickFolder(outPath, defaultPath.empty() ? nullptr : defaultPath.c_str());
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
std::unreachable();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result == NFD_OKAY){
|
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()));
|
callback(reinterpret_cast<char8_t*>(outPath.get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle multiple paths if the dialog was opened in multiple mode
|
||||||
if (outPaths != nullptr) {
|
if (outPaths != nullptr) {
|
||||||
nfdpathsetsize_t numPaths = 0;
|
nfdpathsetsize_t numPaths = 0;
|
||||||
if (NFD::PathSet::Count(outPaths, numPaths) == NFD_OKAY) {
|
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++) {
|
for (size_t i = 0; i < numPaths; i++) {
|
||||||
NFD::UniquePathSetPath path;
|
NFD::UniquePathSetPath path;
|
||||||
if (NFD::PathSet::GetPath(outPaths, i, path) == NFD_OKAY)
|
if (NFD::PathSet::GetPath(outPaths, i, path) == NFD_OKAY)
|
||||||
@ -249,9 +261,14 @@ namespace hex::fs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (result == NFD_ERROR) {
|
} else if (result == NFD_ERROR) {
|
||||||
|
// Handle errors that occurred during the file dialog call
|
||||||
|
|
||||||
log::error("Requested file dialog returned an error: {}", NFD::GetError());
|
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();
|
NFD::Quit();
|
||||||
@ -266,6 +283,8 @@ namespace hex::fs {
|
|||||||
|
|
||||||
#if defined(OS_WINDOWS)
|
#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()) {
|
if (!ImHexApi::System::isPortableVersion()) {
|
||||||
PWSTR wAppDataPath = nullptr;
|
PWSTR wAppDataPath = nullptr;
|
||||||
if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_CREATE, nullptr, &wAppDataPath))) {
|
if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_CREATE, nullptr, &wAppDataPath))) {
|
||||||
@ -303,9 +322,11 @@ namespace hex::fs {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// Add additional data directories to the path
|
||||||
auto additionalDirs = ImHexApi::System::getAdditionalFolderPaths();
|
auto additionalDirs = ImHexApi::System::getAdditionalFolderPaths();
|
||||||
std::copy(additionalDirs.begin(), additionalDirs.end(), std::back_inserter(paths));
|
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()) {
|
if (ProjectFile::hasPath()) {
|
||||||
paths.push_back(ProjectFile::getPath().parent_path());
|
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> getPluginPaths() {
|
||||||
std::vector<std::fs::path> paths = getDataPaths();
|
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)
|
#if defined(OS_LINUX) && defined(SYSTEM_PLUGINS_LOCATION)
|
||||||
paths.push_back(SYSTEM_PLUGINS_LOCATION);
|
paths.push_back(SYSTEM_PLUGINS_LOCATION);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return paths;
|
return paths;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -342,6 +366,7 @@ namespace hex::fs {
|
|||||||
std::vector<std::fs::path> getDefaultPaths(ImHexPath path, bool listNonExisting) {
|
std::vector<std::fs::path> getDefaultPaths(ImHexPath path, bool listNonExisting) {
|
||||||
std::vector<std::fs::path> result;
|
std::vector<std::fs::path> result;
|
||||||
|
|
||||||
|
// Return the correct path based on the ImHexPath enum
|
||||||
switch (path) {
|
switch (path) {
|
||||||
case ImHexPath::END:
|
case ImHexPath::END:
|
||||||
return { };
|
return { };
|
||||||
@ -398,6 +423,7 @@ namespace hex::fs {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove all paths that don't exist if requested
|
||||||
if (!listNonExisting) {
|
if (!listNonExisting) {
|
||||||
result.erase(std::remove_if(result.begin(), result.end(), [](const auto &path) {
|
result.erase(std::remove_if(result.begin(), result.end(), [](const auto &path) {
|
||||||
return !wolv::io::fs::isDirectory(path);
|
return !wolv::io::fs::isDirectory(path);
|
||||||
@ -409,6 +435,9 @@ namespace hex::fs {
|
|||||||
|
|
||||||
bool isPathWritable(const std::fs::path &path) {
|
bool isPathWritable(const std::fs::path &path) {
|
||||||
constexpr static auto TestFileName = "__imhex__tmp__";
|
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);
|
wolv::io::File file(path / TestFileName, wolv::io::File::Mode::Read);
|
||||||
if (file.isValid()) {
|
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);
|
wolv::io::File file(path / TestFileName, wolv::io::File::Mode::Create);
|
||||||
bool result = file.isValid();
|
bool result = file.isValid();
|
||||||
if (!file.remove())
|
if (!file.remove())
|
||||||
@ -427,16 +458,19 @@ namespace hex::fs {
|
|||||||
|
|
||||||
std::fs::path toShortPath(const std::fs::path &path) {
|
std::fs::path toShortPath(const std::fs::path &path) {
|
||||||
#if defined(OS_WINDOWS)
|
#if defined(OS_WINDOWS)
|
||||||
|
// Get the size of the short path
|
||||||
size_t size = GetShortPathNameW(path.c_str(), nullptr, 0);
|
size_t size = GetShortPathNameW(path.c_str(), nullptr, 0);
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
return path;
|
return path;
|
||||||
|
|
||||||
|
// Get the short path
|
||||||
std::wstring newPath(size, 0x00);
|
std::wstring newPath(size, 0x00);
|
||||||
GetShortPathNameW(path.c_str(), newPath.data(), newPath.size());
|
GetShortPathNameW(path.c_str(), newPath.data(), newPath.size());
|
||||||
newPath.pop_back();
|
newPath.pop_back();
|
||||||
|
|
||||||
return newPath;
|
return newPath;
|
||||||
#else
|
#else
|
||||||
|
// Other supported platforms don't have short paths
|
||||||
return path;
|
return path;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -30,15 +30,22 @@ namespace hex::magic {
|
|||||||
|
|
||||||
std::error_code error;
|
std::error_code error;
|
||||||
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Magic)) {
|
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());
|
auto path = std::fs::absolute(entry.path());
|
||||||
|
|
||||||
if (entry.is_regular_file() && ((sourceFiles && path.extension().empty()) || (!sourceFiles && path.extension() == ".mgc"))) {
|
if (sourceFiles) {
|
||||||
magicFiles += wolv::util::toUTF8String(wolv::io::fs::toShortPath(path)) + MAGIC_PATH_SEPARATOR;
|
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)
|
if (error)
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
else
|
else
|
||||||
@ -46,7 +53,7 @@ namespace hex::magic {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool compile() {
|
bool compile() {
|
||||||
magic_t ctx = magic_open(MAGIC_NONE);
|
magic_t ctx = magic_open(MAGIC_CHECK);
|
||||||
ON_SCOPE_EXIT { magic_close(ctx); };
|
ON_SCOPE_EXIT { magic_close(ctx); };
|
||||||
|
|
||||||
auto magicFiles = getMagicFiles(true);
|
auto magicFiles = getMagicFiles(true);
|
||||||
@ -75,6 +82,9 @@ namespace hex::magic {
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
auto result = magic_compile(ctx, magicFiles->c_str()) == 0;
|
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)
|
if (chdir(cwd.data()) != 0)
|
||||||
return false;
|
return false;
|
||||||
|
@ -2,6 +2,11 @@ cmake_minimum_required(VERSION 3.16)
|
|||||||
|
|
||||||
include(ImHexPlugin)
|
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(
|
add_imhex_plugin(
|
||||||
NAME
|
NAME
|
||||||
builtin
|
builtin
|
||||||
@ -36,6 +41,7 @@ add_imhex_plugin(
|
|||||||
source/content/file_handlers.cpp
|
source/content/file_handlers.cpp
|
||||||
source/content/project.cpp
|
source/content/project.cpp
|
||||||
source/content/achievements.cpp
|
source/content/achievements.cpp
|
||||||
|
source/content/file_extraction.cpp
|
||||||
|
|
||||||
source/content/providers/file_provider.cpp
|
source/content/providers/file_provider.cpp
|
||||||
source/content/providers/gdb_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 handleBorderlessWindowMode();
|
||||||
|
|
||||||
|
void extractBundledFiles();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IMHEX_PLUGIN_SUBCOMMANDS() {
|
IMHEX_PLUGIN_SUBCOMMANDS() {
|
||||||
@ -107,6 +109,8 @@ IMHEX_PLUGIN_SETUP("Built-in", "WerWolv", "Default ImHex functionality") {
|
|||||||
registerMainMenuEntries();
|
registerMainMenuEntries();
|
||||||
|
|
||||||
handleBorderlessWindowMode();
|
handleBorderlessWindowMode();
|
||||||
|
|
||||||
|
extractBundledFiles();
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is the default plugin
|
// This is the default plugin
|
||||||
|
Loading…
x
Reference in New Issue
Block a user