#include #include #include #include #include #include #include #include #include namespace hex { namespace ContentRegistry::Settings { constexpr auto SettingsFile = "settings.json"; void load() { bool loaded = false; for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) { fs::File file(dir / SettingsFile, fs::File::Mode::Read); if (file.isValid()) { getSettingsData() = nlohmann::json::parse(file.readString()); loaded = true; break; } } if (!loaded) store(); } void store() { for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) { fs::File file(dir / SettingsFile, fs::File::Mode::Create); if (file.isValid()) { file.write(getSettingsData().dump(4)); break; } } } void clear() { for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) { hex::fs::remove(dir / SettingsFile); } } static auto getCategoryEntry(const std::string &unlocalizedCategory) { auto &entries = getEntries(); const size_t curSlot = entries.size(); auto found = entries.find(Category { unlocalizedCategory }); if (found == entries.end()) { auto [iter, _] = entries.emplace(Category { unlocalizedCategory, curSlot }, std::vector {}); return iter; } return found; } void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 defaultValue, const Callback &callback, bool requiresRestart) { log::debug("Registered new integer setting: [{}]: {}", unlocalizedCategory, unlocalizedName); getCategoryEntry(unlocalizedCategory)->second.emplace_back(Entry { unlocalizedName, requiresRestart, callback }); auto &json = getSettingsData(); if (!json.contains(unlocalizedCategory)) json[unlocalizedCategory] = nlohmann::json::object(); if (!json[unlocalizedCategory].contains(unlocalizedName) || !json[unlocalizedCategory][unlocalizedName].is_number()) json[unlocalizedCategory][unlocalizedName] = int(defaultValue); } void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &defaultValue, const Callback &callback, bool requiresRestart) { log::debug("Registered new string setting: [{}]: {}", unlocalizedCategory, unlocalizedName); getCategoryEntry(unlocalizedCategory)->second.emplace_back(Entry { unlocalizedName, requiresRestart, callback }); auto &json = getSettingsData(); if (!json.contains(unlocalizedCategory)) json[unlocalizedCategory] = nlohmann::json::object(); if (!json[unlocalizedCategory].contains(unlocalizedName) || !json[unlocalizedCategory][unlocalizedName].is_string()) json[unlocalizedCategory][unlocalizedName] = std::string(defaultValue); } void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector &defaultValue, const Callback &callback, bool requiresRestart) { log::debug("Registered new string array setting: [{}]: {}", unlocalizedCategory, unlocalizedName); getCategoryEntry(unlocalizedCategory)->second.emplace_back(Entry { unlocalizedName, requiresRestart, callback }); auto &json = getSettingsData(); if (!json.contains(unlocalizedCategory)) json[unlocalizedCategory] = nlohmann::json::object(); if (!json[unlocalizedCategory].contains(unlocalizedName) || !json[unlocalizedCategory][unlocalizedName].is_array()) json[unlocalizedCategory][unlocalizedName] = defaultValue; } void addCategoryDescription(const std::string &unlocalizedCategory, const std::string &unlocalizedCategoryDescription) { getCategoryDescriptions()[unlocalizedCategory] = unlocalizedCategoryDescription; } void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 value) { auto &json = getSettingsData(); if (!json.contains(unlocalizedCategory)) json[unlocalizedCategory] = nlohmann::json::object(); json[unlocalizedCategory][unlocalizedName] = value; } void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &value) { auto &json = getSettingsData(); if (!json.contains(unlocalizedCategory)) json[unlocalizedCategory] = nlohmann::json::object(); json[unlocalizedCategory][unlocalizedName] = value; } void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector &value) { auto &json = getSettingsData(); if (!json.contains(unlocalizedCategory)) json[unlocalizedCategory] = nlohmann::json::object(); json[unlocalizedCategory][unlocalizedName] = value; } i64 read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 defaultValue) { auto &json = getSettingsData(); if (!json.contains(unlocalizedCategory)) return defaultValue; if (!json[unlocalizedCategory].contains(unlocalizedName)) return defaultValue; if (!json[unlocalizedCategory][unlocalizedName].is_number()) json[unlocalizedCategory][unlocalizedName] = defaultValue; return json[unlocalizedCategory][unlocalizedName].get(); } std::string read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &defaultValue) { auto &json = getSettingsData(); if (!json.contains(unlocalizedCategory)) return defaultValue; if (!json[unlocalizedCategory].contains(unlocalizedName)) return defaultValue; if (!json[unlocalizedCategory][unlocalizedName].is_string()) json[unlocalizedCategory][unlocalizedName] = defaultValue; return json[unlocalizedCategory][unlocalizedName].get(); } std::vector read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector &defaultValue) { auto &json = getSettingsData(); if (!json.contains(unlocalizedCategory)) return defaultValue; if (!json[unlocalizedCategory].contains(unlocalizedName)) return defaultValue; if (!json[unlocalizedCategory][unlocalizedName].is_array()) json[unlocalizedCategory][unlocalizedName] = defaultValue; if (!json[unlocalizedCategory][unlocalizedName].array().empty() && !json[unlocalizedCategory][unlocalizedName][0].is_string()) json[unlocalizedCategory][unlocalizedName] = defaultValue; return json[unlocalizedCategory][unlocalizedName].get>(); } std::map> &getEntries() { static std::map> entries; return entries; } std::map &getCategoryDescriptions() { static std::map descriptions; return descriptions; } nlohmann::json getSetting(const std::string &unlocalizedCategory, const std::string &unlocalizedName) { auto &settings = getSettingsData(); if (!settings.contains(unlocalizedCategory)) return {}; if (!settings[unlocalizedCategory].contains(unlocalizedName)) return {}; return settings[unlocalizedCategory][unlocalizedName]; } nlohmann::json &getSettingsData() { static nlohmann::json settings; return settings; } } namespace ContentRegistry::CommandPaletteCommands { void add(Type type, const std::string &command, const std::string &unlocalizedDescription, const DisplayCallback &displayCallback, const ExecuteCallback &executeCallback) { log::debug("Registered new command palette command: {}", command); getEntries().push_back(ContentRegistry::CommandPaletteCommands::Entry { type, command, unlocalizedDescription, displayCallback, executeCallback }); } std::vector &getEntries() { static std::vector commands; return commands; } } namespace ContentRegistry::PatternLanguage { static std::string getFunctionName(const pl::api::Namespace &ns, const std::string &name) { std::string functionName; for (auto &scope : ns) functionName += scope + "::"; functionName += name; return functionName; } void configureRuntime(pl::PatternLanguage &runtime, prv::Provider *provider) { runtime.reset(); if (provider != nullptr) { runtime.setDataSource([provider](u64 offset, u8 *buffer, size_t size) { provider->read(offset, buffer, size); }, provider->getBaseAddress(), provider->getActualSize()); } runtime.setIncludePaths(fs::getDefaultPaths(fs::ImHexPath::PatternsInclude) | fs::getDefaultPaths(fs::ImHexPath::Patterns)); for (const auto &func : getFunctions()) { if (func.dangerous) runtime.addDangerousFunction(func.ns, func.name, func.parameterCount, func.callback); else runtime.addFunction(func.ns, func.name, func.parameterCount, func.callback); } for (const auto &[name, callback] : getPragmas()) { runtime.addPragma(name, callback); } runtime.addDefine("__IMHEX__"); runtime.addDefine("__IMHEX_VERSION__", IMHEX_VERSION); } void addPragma(const std::string &name, const pl::api::PragmaHandler &handler) { log::debug("Registered new pattern language pragma: {}", name); getPragmas()[name] = handler; } void addFunction(const pl::api::Namespace &ns, const std::string &name, pl::api::FunctionParameterCount parameterCount, const pl::api::FunctionCallback &func) { log::debug("Registered new pattern language function: {}", getFunctionName(ns, name)); getFunctions().push_back({ ns, name, parameterCount, func, false }); } void addDangerousFunction(const pl::api::Namespace &ns, const std::string &name, pl::api::FunctionParameterCount parameterCount, const pl::api::FunctionCallback &func) { log::debug("Registered new dangerous pattern language function: {}", getFunctionName(ns, name)); getFunctions().push_back({ ns, name, parameterCount, func, true }); } std::map &getPragmas() { static std::map pragmas; return pragmas; } std::vector &getFunctions() { static std::vector functions; return functions; } } namespace ContentRegistry::Views { void impl::add(View *view) { log::debug("Registered new view: {}", view->getUnlocalizedName()); getEntries().insert({ view->getUnlocalizedName(), view }); } std::map &getEntries() { static std::map views; return views; } View *getViewByName(const std::string &unlocalizedName) { auto &views = getEntries(); if (views.contains(unlocalizedName)) return views[unlocalizedName]; else return nullptr; } } namespace ContentRegistry::Tools { void add(const std::string &unlocalizedName, const impl::Callback &function) { log::debug("Registered new tool: {}", unlocalizedName); getEntries().emplace_back(impl::Entry { unlocalizedName, function }); } std::vector &getEntries() { static std::vector entries; return entries; } } namespace ContentRegistry::DataInspector { void add(const std::string &unlocalizedName, size_t requiredSize, impl::GeneratorFunction displayGeneratorFunction, std::optional editingFunction) { log::debug("Registered new data inspector format: {}", unlocalizedName); getEntries().push_back({ unlocalizedName, requiredSize, requiredSize, std::move(displayGeneratorFunction), std::move(editingFunction) }); } void add(const std::string &unlocalizedName, size_t requiredSize, size_t maxSize, impl::GeneratorFunction displayGeneratorFunction, std::optional editingFunction) { log::debug("Registered new data inspector format: {}", unlocalizedName); getEntries().push_back({ unlocalizedName, requiredSize, maxSize, std::move(displayGeneratorFunction), std::move(editingFunction) }); } std::vector &getEntries() { static std::vector entries; return entries; } } namespace ContentRegistry::DataProcessorNode { void impl::add(const impl::Entry &entry) { log::debug("Registered new data processor node type: [{}]: {}", entry.category, entry.name); getEntries().push_back(entry); } void addSeparator() { getEntries().push_back({ "", "", [] { return nullptr; } }); } std::vector &getEntries() { static std::vector nodes; return nodes; } } namespace ContentRegistry::Language { void registerLanguage(const std::string &name, const std::string &languageCode) { log::debug("Registered new language: {} ({})", name, languageCode); getLanguages().insert({ languageCode, name }); } void addLocalizations(const std::string &languageCode, const LanguageDefinition &definition) { log::debug("Registered new localization for language {} with {} entries", languageCode, definition.getEntries().size()); getLanguageDefinitions()[languageCode].push_back(definition); } std::map &getLanguages() { static std::map languages; return languages; } std::map> &getLanguageDefinitions() { static std::map> definitions; return definitions; } } namespace ContentRegistry::Interface { void registerMainMenuItem(const std::string &unlocalizedName, u32 priority) { log::debug("Registered new main menu item: {}", unlocalizedName); getMainMenuItems().insert({ priority, { unlocalizedName } }); } void addMenuItem(const std::string &unlocalizedMainMenuName, u32 priority, const impl::DrawCallback &function) { log::debug("Added new menu item to menu {} with priority {}", unlocalizedMainMenuName, priority); getMenuItems().insert({ priority, {unlocalizedMainMenuName, function} }); } void addWelcomeScreenEntry(const impl::DrawCallback &function) { getWelcomeScreenEntries().push_back(function); } void addFooterItem(const impl::DrawCallback &function) { getFooterItems().push_back(function); } void addToolbarItem(const impl::DrawCallback &function) { getToolbarItems().push_back(function); } void addSidebarItem(const std::string &icon, const impl::DrawCallback &function) { getSidebarItems().push_back({ icon, function }); } void addTitleBarButton(const std::string &icon, const std::string &unlocalizedTooltip, const impl::ClickCallback &function) { getTitleBarButtons().push_back({ icon, unlocalizedTooltip, function }); } void addLayout(const std::string &unlocalizedName, const impl::LayoutFunction &function) { log::debug("Added new layout: {}", unlocalizedName); getLayouts().push_back({ unlocalizedName, function }); } std::multimap &getMainMenuItems() { static std::multimap items; return items; } std::multimap &getMenuItems() { static std::multimap items; return items; } std::vector &getWelcomeScreenEntries() { static std::vector entries; return entries; } std::vector &getFooterItems() { static std::vector items; return items; } std::vector &getToolbarItems() { static std::vector items; return items; } std::vector &getSidebarItems() { static std::vector items; return items; } std::vector &getTitleBarButtons() { static std::vector buttons; return buttons; } std::vector &getLayouts() { static std::vector layouts; return layouts; } } namespace ContentRegistry::Provider { void impl::addProviderName(const std::string &unlocalizedName) { log::debug("Registered new provider: {}", unlocalizedName); getEntries().push_back(unlocalizedName); } std::vector &getEntries() { static std::vector providerNames; return providerNames; } } namespace ContentRegistry::DataFormatter { void add(const std::string &unlocalizedName, const impl::Callback &callback) { log::debug("Registered new data formatter: {}", unlocalizedName); getEntries().push_back({ unlocalizedName, callback }); } std::vector &getEntries() { static std::vector entries; return entries; } } namespace ContentRegistry::FileHandler { void add(const std::vector &extensions, const impl::Callback &callback) { for (const auto &extension : extensions) log::debug("Registered new data handler for extensions: {}", extension); getEntries().push_back({ extensions, callback }); } std::vector &getEntries() { static std::vector entries; return entries; } } namespace ContentRegistry::HexEditor { const int DataVisualizer::TextInputFlags = ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_NoHorizontalScroll; bool DataVisualizer::drawDefaultEditingTextBox(u64 address, const char *format, ImGuiDataType dataType, u8 *data, ImGuiInputTextFlags flags) const { struct UserData { u8 *data; i32 maxChars; bool editingDone; }; UserData userData = { .data = data, .maxChars = this->getMaxCharsPerCell(), .editingDone = false }; ImGui::PushID(reinterpret_cast(address)); ImGui::InputScalarCallback("##editing_input", dataType, data, format, flags | TextInputFlags | ImGuiInputTextFlags_CallbackEdit, [](ImGuiInputTextCallbackData *data) -> int { auto &userData = *reinterpret_cast(data->UserData); if (data->BufTextLen >= userData.maxChars) userData.editingDone = true; return 0; }, &userData); ImGui::PopID(); return userData.editingDone || ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_Enter); } void impl::addDataVisualizer(const std::string &unlocalizedName, DataVisualizer *visualizer) { getVisualizers().insert({ unlocalizedName, visualizer }); } std::map &impl::getVisualizers() { static std::map visualizers; return visualizers; } } namespace ContentRegistry::Hashes { std::vector &impl::getHashes() { static std::vector hashes; return hashes; } void impl::add(Hash *hash) { getHashes().push_back(hash); } } }