refactor: refactor tools_entries.cpp into several smaller files (#1418)
This commit is contained in:
parent
46b1b0ba17
commit
b04cb7648e
@ -50,6 +50,25 @@ add_imhex_plugin(
|
|||||||
source/content/providers/motorola_srec_provider.cpp
|
source/content/providers/motorola_srec_provider.cpp
|
||||||
source/content/providers/memory_file_provider.cpp
|
source/content/providers/memory_file_provider.cpp
|
||||||
|
|
||||||
|
source/content/tools/ascii_table.cpp
|
||||||
|
source/content/tools/base_converter.cpp
|
||||||
|
source/content/tools/byte_swapper.cpp
|
||||||
|
source/content/tools/color_picker.cpp
|
||||||
|
source/content/tools/demangler.cpp
|
||||||
|
source/content/tools/euclidean_alg.cpp
|
||||||
|
source/content/tools/file_tool_shredder.cpp
|
||||||
|
source/content/tools/file_tool_splitter.cpp
|
||||||
|
source/content/tools/file_tool_combiner.cpp
|
||||||
|
source/content/tools/file_uploader.cpp
|
||||||
|
source/content/tools/graphing_calc.cpp
|
||||||
|
source/content/tools/ieee_decoder.cpp
|
||||||
|
source/content/tools/math_eval.cpp
|
||||||
|
source/content/tools/multiplication_decoder.cpp
|
||||||
|
source/content/tools/perms_calc.cpp
|
||||||
|
source/content/tools/regex_replacer.cpp
|
||||||
|
source/content/tools/tcp_client_server.cpp
|
||||||
|
source/content/tools/wiki_explainer.cpp
|
||||||
|
|
||||||
source/content/views/view_hex_editor.cpp
|
source/content/views/view_hex_editor.cpp
|
||||||
source/content/views/view_pattern_editor.cpp
|
source/content/views/view_pattern_editor.cpp
|
||||||
source/content/views/view_pattern_data.cpp
|
source/content/views/view_pattern_data.cpp
|
||||||
|
30
plugins/builtin/include/content/tools_entries.hpp
Normal file
30
plugins/builtin/include/content/tools_entries.hpp
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#include <hex/helpers/literals.hpp>
|
||||||
|
|
||||||
|
namespace hex::plugin::builtin {
|
||||||
|
namespace impl {
|
||||||
|
using namespace std::literals::string_literals;
|
||||||
|
using namespace std::literals::chrono_literals;
|
||||||
|
using namespace hex::literals;
|
||||||
|
|
||||||
|
void drawDemangler();
|
||||||
|
void drawASCIITable();
|
||||||
|
void drawRegexReplacer();
|
||||||
|
void drawColorPicker();
|
||||||
|
void drawMathEvaluator();
|
||||||
|
void drawGraphingCalculator();
|
||||||
|
void drawBaseConverter();
|
||||||
|
void drawByteSwapper();
|
||||||
|
void drawPermissionsCalculator();
|
||||||
|
// void drawFileUploader();
|
||||||
|
void drawWikiExplainer();
|
||||||
|
|
||||||
|
void drawIEEE754Decoder();
|
||||||
|
void drawInvariantMultiplicationDecoder();
|
||||||
|
void drawTCPClientServer();
|
||||||
|
void drawEuclidianAlgorithm();
|
||||||
|
|
||||||
|
void drawFileToolShredder();
|
||||||
|
void drawFileToolSplitter();
|
||||||
|
void drawFileToolCombiner();
|
||||||
|
}
|
||||||
|
}
|
61
plugins/builtin/source/content/tools/ascii_table.cpp
Normal file
61
plugins/builtin/source/content/tools/ascii_table.cpp
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
#include <hex/helpers/utils.hpp>
|
||||||
|
#include <hex/api/localization.hpp>
|
||||||
|
|
||||||
|
#include <content/tools_entries.hpp>
|
||||||
|
|
||||||
|
#include <imgui.h>
|
||||||
|
|
||||||
|
#include <hex/ui/imgui_imhex_extensions.h>
|
||||||
|
|
||||||
|
#include <wolv/net/socket_client.hpp>
|
||||||
|
|
||||||
|
namespace hex::plugin::builtin {
|
||||||
|
namespace impl {
|
||||||
|
void drawASCIITable() {
|
||||||
|
static bool asciiTableShowOctal = false;
|
||||||
|
|
||||||
|
ImGui::BeginTable("##asciitable", 4);
|
||||||
|
ImGui::TableSetupColumn("");
|
||||||
|
ImGui::TableSetupColumn("");
|
||||||
|
ImGui::TableSetupColumn("");
|
||||||
|
ImGui::TableSetupColumn("");
|
||||||
|
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
|
||||||
|
for (u8 tablePart = 0; tablePart < 4; tablePart++) {
|
||||||
|
ImGui::BeginTable("##asciitablepart", asciiTableShowOctal ? 4 : 3, ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_RowBg);
|
||||||
|
ImGui::TableSetupColumn("dec");
|
||||||
|
if (asciiTableShowOctal)
|
||||||
|
ImGui::TableSetupColumn("oct");
|
||||||
|
ImGui::TableSetupColumn("hex");
|
||||||
|
ImGui::TableSetupColumn("char");
|
||||||
|
|
||||||
|
ImGui::TableHeadersRow();
|
||||||
|
|
||||||
|
for (u8 i = 0; i < 0x80 / 4; i++) {
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::TextFormatted("{0:03d}", i + 32 * tablePart);
|
||||||
|
|
||||||
|
if (asciiTableShowOctal) {
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::TextFormatted("0o{0:03o}", i + 32 * tablePart);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::TextFormatted("0x{0:02X}", i + 32 * tablePart);
|
||||||
|
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::TextFormatted("{0}", hex::makePrintable(i + 32 * tablePart));
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndTable();
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
}
|
||||||
|
ImGui::EndTable();
|
||||||
|
|
||||||
|
ImGui::Checkbox("hex.builtin.tools.ascii_table.octal"_lang, &asciiTableShowOctal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
59
plugins/builtin/source/content/tools/base_converter.cpp
Normal file
59
plugins/builtin/source/content/tools/base_converter.cpp
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
#include <hex/helpers/utils.hpp>
|
||||||
|
#include <hex/helpers/fmt.hpp>
|
||||||
|
#include <hex/api/localization.hpp>
|
||||||
|
|
||||||
|
#include <hex/ui/view.hpp>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include <llvm/Demangle/Demangle.h>
|
||||||
|
#include <content/helpers/math_evaluator.hpp>
|
||||||
|
#include <content/tools_entries.hpp>
|
||||||
|
|
||||||
|
#include <hex/ui/imgui_imhex_extensions.h>
|
||||||
|
|
||||||
|
namespace hex::plugin::builtin {
|
||||||
|
namespace impl {
|
||||||
|
void drawBaseConverter() {
|
||||||
|
static std::array<std::string, 4> buffers;
|
||||||
|
|
||||||
|
static auto ConvertBases = [](u8 base) {
|
||||||
|
u64 number;
|
||||||
|
|
||||||
|
switch (base) {
|
||||||
|
case 16:
|
||||||
|
number = std::strtoull(buffers[1].c_str(), nullptr, base);
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
number = std::strtoull(buffers[0].c_str(), nullptr, base);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
number = std::strtoull(buffers[2].c_str(), nullptr, base);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
number = std::strtoull(buffers[3].c_str(), nullptr, base);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffers[0] = std::to_string(number);
|
||||||
|
buffers[1] = hex::format("0x{0:X}", number);
|
||||||
|
buffers[2] = hex::format("{0:#o}", number);
|
||||||
|
buffers[3] = hex::toBinaryString(number);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (ImGui::InputTextIcon("hex.builtin.tools.base_converter.dec"_lang, ICON_VS_SYMBOL_NUMERIC, buffers[0]))
|
||||||
|
ConvertBases(10);
|
||||||
|
|
||||||
|
if (ImGui::InputTextIcon("hex.builtin.tools.base_converter.hex"_lang, ICON_VS_SYMBOL_NUMERIC, buffers[1]))
|
||||||
|
ConvertBases(16);
|
||||||
|
|
||||||
|
if (ImGui::InputTextIcon("hex.builtin.tools.base_converter.oct"_lang, ICON_VS_SYMBOL_NUMERIC, buffers[2]))
|
||||||
|
ConvertBases(8);
|
||||||
|
|
||||||
|
if (ImGui::InputTextIcon("hex.builtin.tools.base_converter.bin"_lang, ICON_VS_SYMBOL_NUMERIC, buffers[3]))
|
||||||
|
ConvertBases(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
38
plugins/builtin/source/content/tools/byte_swapper.cpp
Normal file
38
plugins/builtin/source/content/tools/byte_swapper.cpp
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#include <hex/api/localization.hpp>
|
||||||
|
|
||||||
|
#include <hex/ui/view.hpp>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include <llvm/Demangle/Demangle.h>
|
||||||
|
#include <content/tools_entries.hpp>
|
||||||
|
|
||||||
|
#include <imgui.h>
|
||||||
|
|
||||||
|
#include <hex/ui/imgui_imhex_extensions.h>
|
||||||
|
|
||||||
|
namespace hex::plugin::builtin {
|
||||||
|
namespace impl {
|
||||||
|
void drawByteSwapper() {
|
||||||
|
static std::string input, buffer, output;
|
||||||
|
|
||||||
|
if (ImGui::InputTextIcon("hex.builtin.tools.input"_lang, ICON_VS_SYMBOL_NUMERIC, input, ImGuiInputTextFlags_CharsHexadecimal)) {
|
||||||
|
auto nextAlignedSize = std::max<size_t>(2, std::bit_ceil(input.size()));
|
||||||
|
|
||||||
|
buffer.clear();
|
||||||
|
buffer.resize(nextAlignedSize - input.size(), '0');
|
||||||
|
buffer += input;
|
||||||
|
|
||||||
|
output.clear();
|
||||||
|
for (u32 i = 0; i < buffer.size(); i += 2) {
|
||||||
|
output += buffer[buffer.size() - i - 2];
|
||||||
|
output += buffer[buffer.size() - i - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().DisabledAlpha);
|
||||||
|
ImGui::InputTextIcon("hex.builtin.tools.output"_lang, ICON_VS_SYMBOL_NUMERIC, output, ImGuiInputTextFlags_ReadOnly);
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
212
plugins/builtin/source/content/tools/color_picker.cpp
Normal file
212
plugins/builtin/source/content/tools/color_picker.cpp
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
#include <hex/api/content_registry.hpp>
|
||||||
|
#include <hex/api/imhex_api.hpp>
|
||||||
|
|
||||||
|
#include <hex/helpers/http_requests.hpp>
|
||||||
|
#include <hex/helpers/utils.hpp>
|
||||||
|
#include <hex/helpers/fmt.hpp>
|
||||||
|
#include <hex/helpers/literals.hpp>
|
||||||
|
#include <hex/helpers/fs.hpp>
|
||||||
|
#include <hex/api/localization.hpp>
|
||||||
|
|
||||||
|
#include <hex/ui/view.hpp>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <chrono>
|
||||||
|
#include <random>
|
||||||
|
#include <regex>
|
||||||
|
|
||||||
|
#include <llvm/Demangle/Demangle.h>
|
||||||
|
#include <content/helpers/math_evaluator.hpp>
|
||||||
|
#include <content/tools_entries.hpp>
|
||||||
|
|
||||||
|
#include <imgui.h>
|
||||||
|
#include <implot.h>
|
||||||
|
|
||||||
|
#include <hex/ui/imgui_imhex_extensions.h>
|
||||||
|
#include <content/popups/popup_notification.hpp>
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
#include <wolv/io/file.hpp>
|
||||||
|
#include <wolv/utils/guards.hpp>
|
||||||
|
#include <wolv/net/socket_client.hpp>
|
||||||
|
#include <wolv/net/socket_server.hpp>
|
||||||
|
|
||||||
|
namespace hex::plugin::builtin {
|
||||||
|
namespace impl {
|
||||||
|
void drawColorPicker() {
|
||||||
|
static std::array<float, 4> pickedColor = { 0 };
|
||||||
|
static std::string rgba8;
|
||||||
|
|
||||||
|
struct BitValue {
|
||||||
|
int bits;
|
||||||
|
float color;
|
||||||
|
float saturationMultiplier;
|
||||||
|
char name;
|
||||||
|
u8 index;
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::array bitValues = {
|
||||||
|
BitValue{ 8, 0.00F, 1.0F, 'R', 0 },
|
||||||
|
BitValue{ 8, 0.33F, 1.0F, 'G', 1 },
|
||||||
|
BitValue{ 8, 0.66F, 1.0F, 'B', 2 },
|
||||||
|
BitValue{ 8, 0.00F, 0.0F, 'A', 3 }
|
||||||
|
};
|
||||||
|
|
||||||
|
if (ImGui::BeginTable("##color_picker_table", 3, ImGuiTableFlags_BordersInnerV)) {
|
||||||
|
ImGui::TableSetupColumn(" Color Picker", ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoResize, 300_scaled);
|
||||||
|
ImGui::TableSetupColumn(" Components", ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoResize, 105_scaled);
|
||||||
|
ImGui::TableSetupColumn(" Formats", ImGuiTableColumnFlags_WidthStretch | ImGuiTableColumnFlags_NoResize);
|
||||||
|
|
||||||
|
ImGui::TableHeadersRow();
|
||||||
|
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
|
||||||
|
// Draw main color picker widget
|
||||||
|
ImVec2 startCursor, endCursor;
|
||||||
|
{
|
||||||
|
ImGui::PushItemWidth(-1);
|
||||||
|
startCursor = ImGui::GetCursorPos();
|
||||||
|
ImGui::ColorPicker4("hex.builtin.tools.color"_lang, pickedColor.data(), ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_AlphaBar | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoSmallPreview | ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_DisplayHex);
|
||||||
|
endCursor = ImGui::GetCursorPos();
|
||||||
|
ImGui::ColorButton("##color_button", ImColor(pickedColor[0], pickedColor[1], pickedColor[2], pickedColor[3]), ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoDragDrop | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(300_scaled, 0));
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
|
||||||
|
const auto colorName = hex::format("{}{}{}{}", bitValues[0].name, bitValues[1].name, bitValues[2].name, bitValues[3].name);
|
||||||
|
|
||||||
|
// Draw color bit count sliders
|
||||||
|
{
|
||||||
|
ImGui::Indent();
|
||||||
|
|
||||||
|
static auto drawBitsSlider = [&](BitValue *bitValue) {
|
||||||
|
// Change slider color
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImColor::HSV(bitValue->color, 0.5f * bitValue->saturationMultiplier, 0.5f).Value);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImColor::HSV(bitValue->color, 0.6f * bitValue->saturationMultiplier, 0.5f).Value);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImColor::HSV(bitValue->color, 0.7f * bitValue->saturationMultiplier, 0.5f).Value);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_SliderGrab, ImColor::HSV(bitValue->color, 0.9f * bitValue->saturationMultiplier, 0.9f).Value);
|
||||||
|
|
||||||
|
// Draw slider
|
||||||
|
ImGui::PushID(&bitValue->bits);
|
||||||
|
auto format = hex::format("%d\n{}", bitValue->name);
|
||||||
|
ImGui::VSliderInt("##slider", ImVec2(18_scaled, (endCursor - startCursor).y - 3_scaled), &bitValue->bits, 0, 16, format.c_str(), ImGuiSliderFlags_AlwaysClamp);
|
||||||
|
ImGui::PopID();
|
||||||
|
|
||||||
|
ImGui::PopStyleColor(4);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Force sliders closer together
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 4));
|
||||||
|
|
||||||
|
// Draw a slider for each color component
|
||||||
|
for (u32 index = 0; auto &bitValue : bitValues) {
|
||||||
|
// Draw slider
|
||||||
|
drawBitsSlider(&bitValue);
|
||||||
|
|
||||||
|
// Configure drag and drop source and target
|
||||||
|
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) {
|
||||||
|
// Set the current slider index as the payload
|
||||||
|
ImGui::SetDragDropPayload("BIT_VALUE", &index, sizeof(u32));
|
||||||
|
|
||||||
|
// Draw a color button to show the color being dragged
|
||||||
|
ImGui::ColorButton("##color_button", ImColor::HSV(bitValue.color, 0.5f * bitValue.saturationMultiplier, 0.5f).Value);
|
||||||
|
|
||||||
|
ImGui::EndDragDropSource();
|
||||||
|
}
|
||||||
|
if (ImGui::BeginDragDropTarget()) {
|
||||||
|
if (const ImGuiPayload *payload = ImGui::AcceptDragDropPayload("BIT_VALUE"); payload != nullptr) {
|
||||||
|
auto otherIndex = *static_cast<const u32 *>(payload->Data);
|
||||||
|
|
||||||
|
// Swap the currently hovered slider with the one being dragged
|
||||||
|
std::swap(bitValues[index], bitValues[otherIndex]);
|
||||||
|
}
|
||||||
|
ImGui::EndDragDropTarget();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::NewLine();
|
||||||
|
|
||||||
|
// Draw color name below sliders
|
||||||
|
ImGui::TextFormatted("{}", colorName);
|
||||||
|
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
|
||||||
|
ImGui::Unindent();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
|
||||||
|
// Draw encoded color values
|
||||||
|
{
|
||||||
|
// Calculate int and float representations of the selected color
|
||||||
|
std::array<u32, 4> intColor = {};
|
||||||
|
std::array<float, 4> floatColor = {};
|
||||||
|
for (u32 index = 0; auto &bitValue : bitValues) {
|
||||||
|
intColor[index] = u64(std::round(static_cast<long double>(pickedColor[bitValue.index]) * std::numeric_limits<u32>::max())) >> (32 - bitValue.bits);
|
||||||
|
floatColor[index] = pickedColor[bitValue.index];
|
||||||
|
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw a table with the color values
|
||||||
|
if (ImGui::BeginTable("##value_table", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoHostExtendX , ImVec2(0, 0))) {
|
||||||
|
ImGui::TableSetupColumn("name", ImGuiTableColumnFlags_WidthFixed);
|
||||||
|
ImGui::TableSetupColumn("value", ImGuiTableColumnFlags_WidthStretch);
|
||||||
|
|
||||||
|
const static auto drawValue = [](const char *name, auto formatter) {
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
|
||||||
|
// Draw name of the formatting
|
||||||
|
ImGui::TextUnformatted(name);
|
||||||
|
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
|
||||||
|
// Draw value
|
||||||
|
ImGui::PushID(name);
|
||||||
|
ImGui::TextFormattedSelectable("{}", formatter());
|
||||||
|
ImGui::PopID();
|
||||||
|
};
|
||||||
|
|
||||||
|
const u32 bitCount = bitValues[0].bits + bitValues[1].bits + bitValues[2].bits + bitValues[3].bits;
|
||||||
|
|
||||||
|
// Draw the different representations
|
||||||
|
|
||||||
|
drawValue("HEX", [&] {
|
||||||
|
u64 hexValue = 0;
|
||||||
|
for (u32 index = 0; auto &bitValue : bitValues) {
|
||||||
|
hexValue <<= bitValue.bits;
|
||||||
|
hexValue |= u64(intColor[index]) & hex::bitmask(bitValue.bits);
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hex::format("#{0:0{1}X}", hexValue, bitCount / 4);
|
||||||
|
});
|
||||||
|
|
||||||
|
drawValue(colorName.c_str(), [&] {
|
||||||
|
return hex::format("{}({}, {}, {}, {})", colorName, intColor[0], intColor[1], intColor[2], intColor[3]);
|
||||||
|
});
|
||||||
|
|
||||||
|
drawValue("Vector4f", [&] {
|
||||||
|
return hex::format("{{ {:.2}F, {:.2}F, {:.2}F, {:.2}F }}", floatColor[0], floatColor[1], floatColor[2], floatColor[3]);
|
||||||
|
});
|
||||||
|
|
||||||
|
drawValue("Percentage", [&] {
|
||||||
|
return hex::format("{{ {}%, {}%, {}%, {}% }}", u32(floatColor[0] * 100), u32(floatColor[1] * 100), u32(floatColor[2] * 100), u32(floatColor[3] * 100));
|
||||||
|
});
|
||||||
|
|
||||||
|
ImGui::EndTable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndTable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
30
plugins/builtin/source/content/tools/demangler.cpp
Normal file
30
plugins/builtin/source/content/tools/demangler.cpp
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#include <hex/helpers/utils.hpp>
|
||||||
|
#include <hex/api/localization.hpp>
|
||||||
|
|
||||||
|
#include <llvm/Demangle/Demangle.h>
|
||||||
|
|
||||||
|
#include <imgui.h>
|
||||||
|
|
||||||
|
#include <hex/ui/imgui_imhex_extensions.h>
|
||||||
|
|
||||||
|
namespace hex::plugin::builtin {
|
||||||
|
namespace impl {
|
||||||
|
void drawDemangler() {
|
||||||
|
static std::string mangledName, demangledName;
|
||||||
|
|
||||||
|
if (ImGui::InputTextWithHint("hex.builtin.tools.demangler.mangled"_lang, "Itanium, MSVC, Dlang & Rust", mangledName)) {
|
||||||
|
demangledName = llvm::demangle(mangledName);
|
||||||
|
|
||||||
|
if (demangledName == mangledName) {
|
||||||
|
demangledName = "???";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Header("hex.builtin.tools.demangler.demangled"_lang);
|
||||||
|
if (ImGui::BeginChild("demangled", ImVec2(0, 200_scaled), true)) {
|
||||||
|
ImGui::TextFormattedWrappedSelectable("{}", demangledName);
|
||||||
|
}
|
||||||
|
ImGui::EndChild();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
112
plugins/builtin/source/content/tools/euclidean_alg.cpp
Normal file
112
plugins/builtin/source/content/tools/euclidean_alg.cpp
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
#include <hex/api/content_registry.hpp>
|
||||||
|
#include <hex/api/imhex_api.hpp>
|
||||||
|
|
||||||
|
#include <hex/helpers/http_requests.hpp>
|
||||||
|
#include <hex/helpers/utils.hpp>
|
||||||
|
#include <hex/helpers/fmt.hpp>
|
||||||
|
#include <hex/helpers/literals.hpp>
|
||||||
|
#include <hex/helpers/fs.hpp>
|
||||||
|
#include <hex/api/localization.hpp>
|
||||||
|
|
||||||
|
#include <hex/ui/view.hpp>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <chrono>
|
||||||
|
#include <random>
|
||||||
|
#include <regex>
|
||||||
|
|
||||||
|
#include <llvm/Demangle/Demangle.h>
|
||||||
|
#include <content/helpers/math_evaluator.hpp>
|
||||||
|
#include <content/tools_entries.hpp>
|
||||||
|
|
||||||
|
#include <imgui.h>
|
||||||
|
#include <implot.h>
|
||||||
|
|
||||||
|
#include <hex/ui/imgui_imhex_extensions.h>
|
||||||
|
#include <content/popups/popup_notification.hpp>
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
#include <wolv/io/file.hpp>
|
||||||
|
#include <wolv/utils/guards.hpp>
|
||||||
|
#include <wolv/net/socket_client.hpp>
|
||||||
|
#include <wolv/net/socket_server.hpp>
|
||||||
|
|
||||||
|
namespace hex::plugin::builtin {
|
||||||
|
namespace impl {
|
||||||
|
void drawEuclidianAlgorithm() {
|
||||||
|
static u64 a, b;
|
||||||
|
|
||||||
|
static i64 gcdResult = 0;
|
||||||
|
static i64 lcmResult = 0;
|
||||||
|
static i64 p = 0, q = 0;
|
||||||
|
static bool overflow = false;
|
||||||
|
|
||||||
|
constexpr static auto extendedGcd = []<typename T>(T a, T b) -> std::pair<T, T> {
|
||||||
|
T x = 1, y = 0;
|
||||||
|
|
||||||
|
T xLast = 0, yLast = 1;
|
||||||
|
|
||||||
|
while (b > 0) {
|
||||||
|
T quotient = a / b;
|
||||||
|
|
||||||
|
std::tie(x, xLast) = std::tuple { xLast, x - quotient * xLast };
|
||||||
|
std::tie(y, yLast) = std::tuple { yLast, y - quotient * yLast };
|
||||||
|
std::tie(a, b) = std::tuple { b, a - quotient * b };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { x, y };
|
||||||
|
};
|
||||||
|
|
||||||
|
ImGui::TextFormattedWrapped("{}", "hex.builtin.tools.euclidean_algorithm.description"_lang);
|
||||||
|
|
||||||
|
ImGui::NewLine();
|
||||||
|
|
||||||
|
if (ImGui::BeginBox()) {
|
||||||
|
bool hasChanged = false;
|
||||||
|
hasChanged = ImGui::InputScalar("A", ImGuiDataType_U64, &a) || hasChanged;
|
||||||
|
hasChanged = ImGui::InputScalar("B", ImGuiDataType_U64, &b) || hasChanged;
|
||||||
|
|
||||||
|
// Update results when input changed
|
||||||
|
if (hasChanged) {
|
||||||
|
|
||||||
|
// Detect overflow
|
||||||
|
const u64 multiplicationResult = a * b;
|
||||||
|
if (a != 0 && multiplicationResult / a != b) {
|
||||||
|
gcdResult = 0;
|
||||||
|
lcmResult = 0;
|
||||||
|
p = 0;
|
||||||
|
q = 0;
|
||||||
|
|
||||||
|
overflow = true;
|
||||||
|
} else {
|
||||||
|
gcdResult = std::gcd<i128, i128>(a, b);
|
||||||
|
lcmResult = std::lcm<i128, i128>(a, b);
|
||||||
|
std::tie(p, q) = extendedGcd(a, b);
|
||||||
|
|
||||||
|
overflow = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().DisabledAlpha);
|
||||||
|
ImGui::InputScalar("gcd(A, B)", ImGuiDataType_S64, &gcdResult, nullptr, nullptr, "%llu", ImGuiInputTextFlags_ReadOnly);
|
||||||
|
|
||||||
|
ImGui::Indent();
|
||||||
|
ImGui::TextFormatted(ICON_VS_ARROW_RIGHT " a \u00D7 p + b \u00D7 q = ({0}) \u00D7 ({1}) + ({2}) \u00D7 ({3})", a, p, b, q);
|
||||||
|
ImGui::Unindent();
|
||||||
|
|
||||||
|
ImGui::InputScalar("lcm(A, B)", ImGuiDataType_S64, &lcmResult, nullptr, nullptr, "%llu", ImGuiInputTextFlags_ReadOnly);
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
|
||||||
|
ImGui::EndBox();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (overflow)
|
||||||
|
ImGui::TextFormattedColored(ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarRed), "{}", "hex.builtin.tools.euclidean_algorithm.overflow"_lang);
|
||||||
|
else
|
||||||
|
ImGui::NewLine();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
155
plugins/builtin/source/content/tools/file_tool_combiner.cpp
Normal file
155
plugins/builtin/source/content/tools/file_tool_combiner.cpp
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
#include <hex/helpers/http_requests.hpp>
|
||||||
|
#include <hex/helpers/fmt.hpp>
|
||||||
|
#include <hex/helpers/fs.hpp>
|
||||||
|
#include <hex/api/localization.hpp>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <random>
|
||||||
|
|
||||||
|
#include <llvm/Demangle/Demangle.h>
|
||||||
|
|
||||||
|
#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())
|
||||||
|
ImGui::TextSpinner("hex.builtin.tools.file_tools.combiner.combining"_lang);
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
142
plugins/builtin/source/content/tools/file_tool_shredder.cpp
Normal file
142
plugins/builtin/source/content/tools/file_tool_shredder.cpp
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
#include <hex/helpers/fs.hpp>
|
||||||
|
#include <hex/api/localization.hpp>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <random>
|
||||||
|
|
||||||
|
#include <llvm/Demangle/Demangle.h>
|
||||||
|
#include <content/helpers/math_evaluator.hpp>
|
||||||
|
|
||||||
|
#include <imgui.h>
|
||||||
|
|
||||||
|
#include <hex/ui/imgui_imhex_extensions.h>
|
||||||
|
#include <content/popups/popup_notification.hpp>
|
||||||
|
|
||||||
|
#include <wolv/io/file.hpp>
|
||||||
|
#include <wolv/utils/guards.hpp>
|
||||||
|
|
||||||
|
namespace hex::plugin::builtin {
|
||||||
|
namespace impl {
|
||||||
|
void drawFileToolShredder() {
|
||||||
|
static std::u8string selectedFile;
|
||||||
|
static bool fastMode = false;
|
||||||
|
static TaskHolder shredderTask;
|
||||||
|
|
||||||
|
ImGui::TextUnformatted("hex.builtin.tools.file_tools.shredder.warning"_lang);
|
||||||
|
ImGui::NewLine();
|
||||||
|
|
||||||
|
if (ImGui::BeginChild("settings", { 0, ImGui::GetTextLineHeightWithSpacing() * 4 }, true, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse)) {
|
||||||
|
ImGui::BeginDisabled(shredderTask.isRunning());
|
||||||
|
{
|
||||||
|
ImGui::TextUnformatted("hex.builtin.tools.file_tools.shredder.input"_lang);
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::InputText("##path", selectedFile);
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("...")) {
|
||||||
|
fs::openFileBrowser(fs::DialogMode::Open, {}, [](const auto &path) {
|
||||||
|
selectedFile = path.u8string();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Checkbox("hex.builtin.tools.file_tools.shredder.fast"_lang, &fastMode);
|
||||||
|
}
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
}
|
||||||
|
ImGui::EndChild();
|
||||||
|
|
||||||
|
if (shredderTask.isRunning())
|
||||||
|
ImGui::TextSpinner("hex.builtin.tools.file_tools.shredder.shredding"_lang);
|
||||||
|
else {
|
||||||
|
ImGui::BeginDisabled(selectedFile.empty());
|
||||||
|
{
|
||||||
|
if (ImGui::Button("hex.builtin.tools.file_tools.shredder.shred"_lang)) {
|
||||||
|
shredderTask = TaskManager::createTask("hex.builtin.tools.file_tools.shredder.shredding", 0, [](auto &task) {
|
||||||
|
ON_SCOPE_EXIT {
|
||||||
|
selectedFile.clear();
|
||||||
|
};
|
||||||
|
wolv::io::File file(selectedFile, wolv::io::File::Mode::Write);
|
||||||
|
|
||||||
|
if (!file.isValid()) {
|
||||||
|
PopupError::open("hex.builtin.tools.file_tools.shredder.error.open"_lang);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
task.setMaxValue(file.getSize());
|
||||||
|
|
||||||
|
std::vector<std::array<u8, 3>> overwritePattern;
|
||||||
|
if (fastMode) {
|
||||||
|
/* Should be sufficient for modern disks */
|
||||||
|
overwritePattern.push_back({ 0x00, 0x00, 0x00 });
|
||||||
|
overwritePattern.push_back({ 0xFF, 0xFF, 0xFF });
|
||||||
|
} else {
|
||||||
|
/* Gutmann's method. Secure for magnetic storage */
|
||||||
|
std::random_device rd;
|
||||||
|
std::uniform_int_distribution<u8> dist(0x00, 0xFF);
|
||||||
|
|
||||||
|
/* Fill fixed patterns */
|
||||||
|
overwritePattern = {
|
||||||
|
{ },
|
||||||
|
{ },
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
{ 0x55, 0x55, 0x55 },
|
||||||
|
{ 0xAA, 0xAA, 0xAA },
|
||||||
|
{ 0x92, 0x49, 0x24 },
|
||||||
|
{ 0x49, 0x24, 0x92 },
|
||||||
|
{ 0x24, 0x92, 0x49 },
|
||||||
|
{ 0x00, 0x00, 0x00 },
|
||||||
|
{ 0x11, 0x11, 0x11 },
|
||||||
|
{ 0x22, 0x22, 0x22 },
|
||||||
|
{ 0x33, 0x33, 0x44 },
|
||||||
|
{ 0x55, 0x55, 0x55 },
|
||||||
|
{ 0x66, 0x66, 0x66 },
|
||||||
|
{ 0x77, 0x77, 0x77 },
|
||||||
|
{ 0x88, 0x88, 0x88 },
|
||||||
|
{ 0x99, 0x99, 0x99 },
|
||||||
|
{ 0xAA, 0xAA, 0xAA },
|
||||||
|
{ 0xBB, 0xBB, 0xBB },
|
||||||
|
{ 0xCC, 0xCC, 0xCC },
|
||||||
|
{ 0xDD, 0xDD, 0xDD },
|
||||||
|
{ 0xEE, 0xEE, 0xEE },
|
||||||
|
{ 0xFF, 0xFF, 0xFF },
|
||||||
|
{ 0x92, 0x49, 0x24 },
|
||||||
|
{ 0x49, 0x24, 0x92 },
|
||||||
|
{ 0x24, 0x92, 0x49 },
|
||||||
|
{ 0x6D, 0xB6, 0xDB },
|
||||||
|
{ 0xB6, 0xDB, 0x6D },
|
||||||
|
{ 0xBD, 0x6D, 0xB6 },
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Fill random patterns */
|
||||||
|
for (u8 i = 0; i < 4; i++)
|
||||||
|
overwritePattern[i] = { dist(rd), dist(rd), dist(rd) };
|
||||||
|
for (u8 i = 0; i < 4; i++)
|
||||||
|
overwritePattern[overwritePattern.size() - 1 - i] = { dist(rd), dist(rd), dist(rd) };
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t fileSize = file.getSize();
|
||||||
|
|
||||||
|
for (const auto &pattern : overwritePattern) {
|
||||||
|
for (u64 offset = 0; offset < fileSize; offset += 3) {
|
||||||
|
file.writeBuffer(pattern.data(), std::min<u64>(pattern.size(), fileSize - offset));
|
||||||
|
task.update(offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
file.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
file.remove();
|
||||||
|
|
||||||
|
PopupInfo::open("hex.builtin.tools.file_tools.shredder.success"_lang);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
162
plugins/builtin/source/content/tools/file_tool_splitter.cpp
Normal file
162
plugins/builtin/source/content/tools/file_tool_splitter.cpp
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
#include <hex/api/content_registry.hpp>
|
||||||
|
#include <hex/api/imhex_api.hpp>
|
||||||
|
|
||||||
|
#include <hex/helpers/http_requests.hpp>
|
||||||
|
#include <hex/helpers/utils.hpp>
|
||||||
|
#include <hex/helpers/fmt.hpp>
|
||||||
|
#include <hex/helpers/literals.hpp>
|
||||||
|
#include <hex/helpers/fs.hpp>
|
||||||
|
#include <hex/api/localization.hpp>
|
||||||
|
|
||||||
|
#include <hex/ui/view.hpp>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <chrono>
|
||||||
|
#include <random>
|
||||||
|
#include <regex>
|
||||||
|
|
||||||
|
#include <llvm/Demangle/Demangle.h>
|
||||||
|
#include <content/helpers/math_evaluator.hpp>
|
||||||
|
|
||||||
|
#include <imgui.h>
|
||||||
|
#include <implot.h>
|
||||||
|
|
||||||
|
#include <hex/ui/imgui_imhex_extensions.h>
|
||||||
|
#include <content/popups/popup_notification.hpp>
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
#include <wolv/io/file.hpp>
|
||||||
|
#include <wolv/utils/guards.hpp>
|
||||||
|
#include <wolv/net/socket_client.hpp>
|
||||||
|
#include <wolv/net/socket_server.hpp>
|
||||||
|
|
||||||
|
namespace hex::plugin::builtin {
|
||||||
|
namespace impl {
|
||||||
|
using namespace hex::literals;
|
||||||
|
|
||||||
|
void drawFileToolSplitter() {
|
||||||
|
std::array sizeText = {
|
||||||
|
static_cast<const char*>("hex.builtin.tools.file_tools.splitter.sizes.5_75_floppy"_lang),
|
||||||
|
static_cast<const char*>("hex.builtin.tools.file_tools.splitter.sizes.3_5_floppy"_lang),
|
||||||
|
static_cast<const char*>("hex.builtin.tools.file_tools.splitter.sizes.zip100"_lang),
|
||||||
|
static_cast<const char*>("hex.builtin.tools.file_tools.splitter.sizes.zip200"_lang),
|
||||||
|
static_cast<const char*>("hex.builtin.tools.file_tools.splitter.sizes.cdrom650"_lang),
|
||||||
|
static_cast<const char*>("hex.builtin.tools.file_tools.splitter.sizes.cdrom700"_lang),
|
||||||
|
static_cast<const char*>("hex.builtin.tools.file_tools.splitter.sizes.fat32"_lang),
|
||||||
|
static_cast<const char*>("hex.builtin.tools.file_tools.splitter.sizes.custom"_lang)
|
||||||
|
};
|
||||||
|
std::array<u64, sizeText.size()> sizes = {
|
||||||
|
1200_KiB,
|
||||||
|
1400_KiB,
|
||||||
|
100_MiB,
|
||||||
|
200_MiB,
|
||||||
|
650_MiB,
|
||||||
|
700_MiB,
|
||||||
|
4_GiB,
|
||||||
|
1
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::u8string selectedFile;
|
||||||
|
static std::u8string baseOutputPath;
|
||||||
|
static u64 splitSize = sizes[0];
|
||||||
|
static int selectedItem = 0;
|
||||||
|
static TaskHolder splitterTask;
|
||||||
|
|
||||||
|
if (ImGui::BeginChild("split_settings", { 0, ImGui::GetTextLineHeightWithSpacing() * 7 }, true, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse)) {
|
||||||
|
ImGui::BeginDisabled(splitterTask.isRunning());
|
||||||
|
{
|
||||||
|
ImGui::InputText("##path", selectedFile);
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("...##input")) {
|
||||||
|
fs::openFileBrowser(fs::DialogMode::Open, {}, [](const auto &path) {
|
||||||
|
selectedFile = path.u8string();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::TextUnformatted("hex.builtin.tools.file_tools.splitter.input"_lang);
|
||||||
|
|
||||||
|
ImGui::InputText("##base_path", baseOutputPath);
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("...##output")) {
|
||||||
|
fs::openFileBrowser(fs::DialogMode::Save, {}, [](const auto &path) {
|
||||||
|
baseOutputPath = path.u8string();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::TextUnformatted("hex.builtin.tools.file_tools.splitter.output"_lang);
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
if (ImGui::Combo("###part_size", &selectedItem, sizeText.data(), sizeText.size())) {
|
||||||
|
splitSize = sizes[selectedItem];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
ImGui::BeginDisabled(splitterTask.isRunning() || selectedItem != sizes.size() - 1);
|
||||||
|
{
|
||||||
|
ImGui::InputScalar("###custom_size", ImGuiDataType_U64, &splitSize);
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::TextUnformatted("Bytes");
|
||||||
|
}
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
}
|
||||||
|
ImGui::EndChild();
|
||||||
|
|
||||||
|
ImGui::BeginDisabled(selectedFile.empty() || baseOutputPath.empty() || splitSize == 0);
|
||||||
|
{
|
||||||
|
if (splitterTask.isRunning())
|
||||||
|
ImGui::TextSpinner("hex.builtin.tools.file_tools.splitter.picker.splitting"_lang);
|
||||||
|
else {
|
||||||
|
if (ImGui::Button("hex.builtin.tools.file_tools.splitter.picker.split"_lang)) {
|
||||||
|
splitterTask = TaskManager::createTask("hex.builtin.tools.file_tools.splitter.picker.splitting", 0, [](auto &task) {
|
||||||
|
ON_SCOPE_EXIT {
|
||||||
|
selectedFile.clear();
|
||||||
|
baseOutputPath.clear();
|
||||||
|
};
|
||||||
|
|
||||||
|
wolv::io::File file(selectedFile, wolv::io::File::Mode::Read);
|
||||||
|
|
||||||
|
if (!file.isValid()) {
|
||||||
|
PopupError::open("hex.builtin.tools.file_tools.splitter.picker.error.open"_lang);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file.getSize() < splitSize) {
|
||||||
|
PopupError::open("hex.builtin.tools.file_tools.splitter.picker.error.size"_lang);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
task.setMaxValue(file.getSize());
|
||||||
|
|
||||||
|
u32 index = 1;
|
||||||
|
for (u64 offset = 0; offset < file.getSize(); offset += splitSize) {
|
||||||
|
task.update(offset);
|
||||||
|
|
||||||
|
std::fs::path path = baseOutputPath;
|
||||||
|
path += hex::format(".{:05}", index);
|
||||||
|
|
||||||
|
wolv::io::File partFile(path, wolv::io::File::Mode::Create);
|
||||||
|
|
||||||
|
if (!partFile.isValid()) {
|
||||||
|
PopupError::open(hex::format("hex.builtin.tools.file_tools.splitter.picker.error.create"_lang, index));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr static auto BufferSize = 0xFF'FFFF;
|
||||||
|
for (u64 partOffset = 0; partOffset < splitSize; partOffset += BufferSize) {
|
||||||
|
partFile.writeVector(file.readVector(std::min<u64>(BufferSize, splitSize - partOffset)));
|
||||||
|
partFile.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
PopupInfo::open("hex.builtin.tools.file_tools.splitter.picker.success"_lang);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
96
plugins/builtin/source/content/tools/file_uploader.cpp
Normal file
96
plugins/builtin/source/content/tools/file_uploader.cpp
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
namespace hex::plugin::builtin {
|
||||||
|
namespace impl {
|
||||||
|
|
||||||
|
/*void drawFileUploader() {
|
||||||
|
struct UploadedFile {
|
||||||
|
std::string fileName, link, size;
|
||||||
|
};
|
||||||
|
|
||||||
|
static HttpRequest request("POST", "https://api.anonfiles.com/upload");
|
||||||
|
static std::future<HttpRequest::Result<std::string>> uploadProcess;
|
||||||
|
static std::fs::path currFile;
|
||||||
|
static std::vector<UploadedFile> links;
|
||||||
|
|
||||||
|
bool uploading = uploadProcess.valid() && uploadProcess.wait_for(0s) != std::future_status::ready;
|
||||||
|
|
||||||
|
ImGui::Header("hex.builtin.tools.file_uploader.control"_lang, true);
|
||||||
|
if (!uploading) {
|
||||||
|
if (ImGui::Button("hex.builtin.tools.file_uploader.upload"_lang)) {
|
||||||
|
fs::openFileBrowser(fs::DialogMode::Open, {}, [&](auto path) {
|
||||||
|
uploadProcess = request.uploadFile(path);
|
||||||
|
currFile = path;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (ImGui::Button("hex.builtin.common.cancel"_lang)) {
|
||||||
|
request.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
ImGui::ProgressBar(request.getProgress(), ImVec2(0, 0), uploading ? nullptr : "Done!");
|
||||||
|
|
||||||
|
ImGui::Header("hex.builtin.tools.file_uploader.recent"_lang);
|
||||||
|
|
||||||
|
if (ImGui::BeginTable("##links", 3, ImGuiTableFlags_ScrollY | ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg, ImVec2(0, 200))) {
|
||||||
|
ImGui::TableSetupColumn("hex.builtin.common.file"_lang);
|
||||||
|
ImGui::TableSetupColumn("hex.builtin.common.link"_lang);
|
||||||
|
ImGui::TableSetupColumn("hex.builtin.common.size"_lang);
|
||||||
|
ImGui::TableSetupScrollFreeze(0, 1);
|
||||||
|
ImGui::TableHeadersRow();
|
||||||
|
|
||||||
|
ImGuiListClipper clipper;
|
||||||
|
clipper.Begin(links.size());
|
||||||
|
|
||||||
|
while (clipper.Step()) {
|
||||||
|
for (i32 i = clipper.DisplayEnd - 1; i >= clipper.DisplayStart; i--) {
|
||||||
|
auto &[fileName, link, size] = links[i];
|
||||||
|
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::TextUnformatted(fileName.c_str());
|
||||||
|
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
if (ImGui::Hyperlink(link.c_str())) {
|
||||||
|
if (ImGui::IsKeyDown(ImGuiKey_LeftCtrl))
|
||||||
|
hex::openWebpage(link);
|
||||||
|
else
|
||||||
|
ImGui::SetClipboardText(link.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::InfoTooltip("hex.builtin.tools.file_uploader.tooltip"_lang);
|
||||||
|
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::TextUnformatted(size.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clipper.End();
|
||||||
|
|
||||||
|
ImGui::EndTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uploadProcess.valid() && uploadProcess.wait_for(0s) == std::future_status::ready) {
|
||||||
|
auto response = uploadProcess.get();
|
||||||
|
if (response.getStatusCode() == 200) {
|
||||||
|
try {
|
||||||
|
auto json = nlohmann::json::parse(response.getData());
|
||||||
|
links.push_back({
|
||||||
|
wolv::util::toUTF8String(currFile.filename()),
|
||||||
|
json.at("data").at("file").at("url").at("short"),
|
||||||
|
json.at("data").at("file").at("metadata").at("size").at("readable")
|
||||||
|
});
|
||||||
|
} catch (...) {
|
||||||
|
PopupError::open("hex.builtin.tools.file_uploader.invalid_response"_lang);
|
||||||
|
}
|
||||||
|
} else if (response.getStatusCode() == 0) {
|
||||||
|
// Canceled by user, no action needed
|
||||||
|
} else PopupError::open(hex::format("hex.builtin.tools.file_uploader.error"_lang, response.getStatusCode()));
|
||||||
|
|
||||||
|
uploadProcess = {};
|
||||||
|
currFile.clear();
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
}
|
78
plugins/builtin/source/content/tools/graphing_calc.cpp
Normal file
78
plugins/builtin/source/content/tools/graphing_calc.cpp
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
#include <hex/helpers/http_requests.hpp>
|
||||||
|
|
||||||
|
#include <hex/ui/view.hpp>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <regex>
|
||||||
|
|
||||||
|
#include <llvm/Demangle/Demangle.h>
|
||||||
|
#include <content/helpers/math_evaluator.hpp>
|
||||||
|
#include <content/tools_entries.hpp>
|
||||||
|
|
||||||
|
#include <imgui.h>
|
||||||
|
#include <implot.h>
|
||||||
|
|
||||||
|
#include <hex/ui/imgui_imhex_extensions.h>
|
||||||
|
|
||||||
|
#include <wolv/net/socket_server.hpp>
|
||||||
|
|
||||||
|
namespace hex::plugin::builtin {
|
||||||
|
namespace impl {
|
||||||
|
void drawGraphingCalculator() {
|
||||||
|
static std::array<long double, 1000> x, y;
|
||||||
|
static std::string mathInput;
|
||||||
|
static ImPlotRect limits;
|
||||||
|
static double prevPos = 0;
|
||||||
|
static long double stepSize = 0.1;
|
||||||
|
|
||||||
|
if (ImPlot::BeginPlot("Function", ImVec2(-1, 0), ImPlotFlags_NoTitle | ImPlotFlags_NoMenus | ImPlotFlags_NoBoxSelect | ImPlotFlags_NoMouseText | ImPlotFlags_NoFrame)) {
|
||||||
|
ImPlot::SetupAxesLimits(-10, 10, -5, 5, ImPlotCond_Once);
|
||||||
|
|
||||||
|
limits = ImPlot::GetPlotLimits(ImAxis_X1, ImAxis_Y1);
|
||||||
|
|
||||||
|
ImPlot::PlotLine("f(x)", x.data(), y.data(), x.size());
|
||||||
|
ImPlot::EndPlot();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::PushItemWidth(-1);
|
||||||
|
ImGui::InputTextIcon("##graphing_math_input", ICON_VS_SYMBOL_OPERATOR, mathInput, ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_AutoSelectAll);
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
|
||||||
|
if ((prevPos != limits.X.Min && (ImGui::IsMouseReleased(ImGuiMouseButton_Left) || ImGui::GetIO().MouseWheel != 0)) || (ImGui::IsItemFocused() && ImGui::IsKeyPressed(ImGuiKey_Enter))) {
|
||||||
|
MathEvaluator<long double> evaluator;
|
||||||
|
|
||||||
|
y = {};
|
||||||
|
|
||||||
|
u32 i = 0;
|
||||||
|
evaluator.setFunction("y", [&](auto args) -> std::optional<long double> {
|
||||||
|
i32 index = i + args[0];
|
||||||
|
if (index < 0 || u32(index) >= y.size())
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return y[index];
|
||||||
|
}, 1, 1);
|
||||||
|
|
||||||
|
evaluator.registerStandardVariables();
|
||||||
|
evaluator.registerStandardFunctions();
|
||||||
|
|
||||||
|
stepSize = (limits.X.Size()) / x.size();
|
||||||
|
|
||||||
|
for (i = 0; i < x.size(); i++) {
|
||||||
|
evaluator.setVariable("x", limits.X.Min + i * stepSize);
|
||||||
|
x[i] = limits.X.Min + i * stepSize;
|
||||||
|
y[i] = evaluator.evaluate(mathInput).value_or(0);
|
||||||
|
|
||||||
|
if (y[i] < limits.Y.Min)
|
||||||
|
limits.Y.Min = y[i];
|
||||||
|
if (y[i] > limits.Y.Max)
|
||||||
|
limits.X.Max = y[i];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
limits.X.Max = limits.X.Min + x.size() * stepSize;
|
||||||
|
prevPos = limits.X.Min;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
709
plugins/builtin/source/content/tools/ieee_decoder.cpp
Normal file
709
plugins/builtin/source/content/tools/ieee_decoder.cpp
Normal file
@ -0,0 +1,709 @@
|
|||||||
|
#include <hex/api/content_registry.hpp>
|
||||||
|
#include <hex/api/localization.hpp>
|
||||||
|
#include <hex/helpers/utils.hpp>
|
||||||
|
#include <hex/ui/imgui_imhex_extensions.h>
|
||||||
|
|
||||||
|
#include <imgui.h>
|
||||||
|
|
||||||
|
namespace hex::plugin::builtin {
|
||||||
|
namespace impl {
|
||||||
|
// Tool for converting between different number formats.
|
||||||
|
// There are three places where input can be changed; the bit checkboxes, the hex input, and the decimal input.
|
||||||
|
// The bit checkboxes and the hex input are directly related and can be converted between each other easily.
|
||||||
|
// The decimal input is a bit more complicated. IEEE 754 floating point numbers are represented as a sign bit,
|
||||||
|
// an exponent and a mantissa. For details see https://en.wikipedia.org/wiki/IEEE_754.
|
||||||
|
// Workflow is as follows:
|
||||||
|
// From the bit checkboxes determine the integer hex value. This is straightforward.
|
||||||
|
// From the hex value determine the binary floating point value by extracting the sign, exponent, and mantissa.
|
||||||
|
// From the binary floating point value determine the decimal floating point value using a third party library.
|
||||||
|
// From the decimal floating point we reconstruct the binary floating point value using internal hardware.
|
||||||
|
// If the format is non-standard, the reconstruction is done using properties of the format.
|
||||||
|
void drawIEEE754Decoder() {
|
||||||
|
|
||||||
|
constexpr static auto flags = ImGuiInputTextFlags_EnterReturnsTrue;
|
||||||
|
|
||||||
|
class IEEE754STATICS {
|
||||||
|
public:
|
||||||
|
IEEE754STATICS() {
|
||||||
|
value = 0;
|
||||||
|
exponentBitCount = 8;
|
||||||
|
mantissaBitCount = 23;
|
||||||
|
resultFloat = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
u128 value;
|
||||||
|
i32 exponentBitCount;
|
||||||
|
i32 mantissaBitCount;
|
||||||
|
long double resultFloat;
|
||||||
|
};
|
||||||
|
|
||||||
|
static IEEE754STATICS ieee754statics;
|
||||||
|
|
||||||
|
|
||||||
|
enum class NumberType {
|
||||||
|
Normal,
|
||||||
|
Zero,
|
||||||
|
Denormal,
|
||||||
|
Infinity,
|
||||||
|
NaN,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class InputType {
|
||||||
|
Infinity,
|
||||||
|
NotANumber,
|
||||||
|
QuietNotANumber,
|
||||||
|
SignalingNotANumber,
|
||||||
|
Regular,
|
||||||
|
Invalid
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class ValueType {
|
||||||
|
Regular,
|
||||||
|
SignalingNaN,
|
||||||
|
QuietNaN,
|
||||||
|
NegativeInfinity,
|
||||||
|
PositiveInfinity,
|
||||||
|
};
|
||||||
|
|
||||||
|
class IEEE754 {
|
||||||
|
public:
|
||||||
|
ValueType valueType;
|
||||||
|
NumberType numberType;
|
||||||
|
i64 exponentBias;
|
||||||
|
long double signValue;
|
||||||
|
long double exponentValue;
|
||||||
|
long double mantissaValue;
|
||||||
|
i64 signBits;
|
||||||
|
i64 exponentBits;
|
||||||
|
i64 mantissaBits;
|
||||||
|
i64 precision;
|
||||||
|
} ieee754 = {};
|
||||||
|
|
||||||
|
std::string specialNumbers[] = {
|
||||||
|
"inf" , "Inf", "INF" , "nan" , "Nan" , "NAN",
|
||||||
|
"qnan","Qnan", "QNAN", "snan", "Snan", "SNAN"
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const auto totalBitCount = ieee754statics.exponentBitCount + ieee754statics.mantissaBitCount;
|
||||||
|
const auto signBitPosition = totalBitCount - 0;
|
||||||
|
const auto exponentBitPosition = totalBitCount - 1;
|
||||||
|
const auto mantissaBitPosition = totalBitCount - 1 - ieee754statics.exponentBitCount;
|
||||||
|
|
||||||
|
const static auto ExtractBits = [](u32 startBit, u32 count) {
|
||||||
|
return hex::extract(startBit, startBit - (count - 1), ieee754statics.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
ieee754.signBits = ExtractBits(signBitPosition, 1);
|
||||||
|
ieee754.exponentBits = ExtractBits(exponentBitPosition, ieee754statics.exponentBitCount);
|
||||||
|
ieee754.mantissaBits = ExtractBits(mantissaBitPosition, ieee754statics.mantissaBitCount);
|
||||||
|
|
||||||
|
|
||||||
|
static i64 inputFieldWidth = 0;
|
||||||
|
ImGui::TextFormattedWrapped("{}", "hex.builtin.tools.ieee754.description"_lang);
|
||||||
|
ImGui::NewLine();
|
||||||
|
|
||||||
|
static i64 displayMode = ContentRegistry::Settings::read("hex.builtin.tools.ieee754.settings", "display_mode", 0);
|
||||||
|
i64 displayModeTemp = displayMode;
|
||||||
|
ImGui::RadioButton("hex.builtin.tools.ieee754.settings.display_mode.detailed"_lang, reinterpret_cast<int *>(&displayMode), 0);
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
ImGui::RadioButton("hex.builtin.tools.ieee754.settings.display_mode.simplified"_lang, reinterpret_cast<int *>(&displayMode), 1);
|
||||||
|
if (displayModeTemp != displayMode) {
|
||||||
|
ContentRegistry::Settings::write("hex.builtin.tools.ieee754.settings", "display_mode", displayMode);
|
||||||
|
displayModeTemp = displayMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto tableFlags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoKeepColumnsVisible |
|
||||||
|
ImGuiTableFlags_ScrollX | ImGuiTableFlags_NoPadInnerX;
|
||||||
|
|
||||||
|
const static auto IndentBoxOrLabel = [](u32 startBit, u32 bitIndex, u32 count, bool isLabel) {
|
||||||
|
auto checkBoxWidth = ImGui::CalcTextSize("0").x + ImGui::GetStyle().FramePadding.x * 2.0f;
|
||||||
|
auto columnWidth = ImGui::GetColumnWidth();
|
||||||
|
float boxesPerColumn=columnWidth/checkBoxWidth;
|
||||||
|
float result;
|
||||||
|
if (isLabel) {
|
||||||
|
std::string labelString = fmt::format("{}", bitIndex);
|
||||||
|
auto labelWidth = ImGui::CalcTextSize(labelString.c_str()).x;
|
||||||
|
auto leadingBoxes = (boxesPerColumn-count)/2.0f;
|
||||||
|
if (leadingBoxes < 0.0f)
|
||||||
|
leadingBoxes = 0.0f;
|
||||||
|
result = checkBoxWidth*(leadingBoxes + startBit - bitIndex + 0.5f)-labelWidth/2.0f;
|
||||||
|
} else {
|
||||||
|
if (count < boxesPerColumn)
|
||||||
|
result = (columnWidth - count * checkBoxWidth) / 2.0f;
|
||||||
|
else
|
||||||
|
result = 0.0;
|
||||||
|
}
|
||||||
|
if (result <= 0.0f)
|
||||||
|
result = 0.05;
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
const static auto DisplayBitLabels = [](int startBit, int count) {
|
||||||
|
static i32 lastLabelAdded = -1;
|
||||||
|
i32 labelIndex;
|
||||||
|
if (lastLabelAdded == -1 || count < 4)
|
||||||
|
labelIndex = startBit - (count >> 1);
|
||||||
|
else
|
||||||
|
labelIndex = lastLabelAdded - 4;
|
||||||
|
|
||||||
|
while (labelIndex + count > startBit) {
|
||||||
|
auto indentSize = IndentBoxOrLabel(startBit, labelIndex, count, true);
|
||||||
|
ImGui::Indent(indentSize );
|
||||||
|
ImGui::TextFormatted("{}", labelIndex);
|
||||||
|
lastLabelAdded = labelIndex;
|
||||||
|
ImGui::Unindent(indentSize );
|
||||||
|
labelIndex -= 4;
|
||||||
|
ImGui::SameLine();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const static auto FormatBitLabels = [](i32 totalBitCount, i32 exponentBitPosition, i32 mantissaBitPosition) {
|
||||||
|
// Row for bit labels. Due to font size constrains each bit cannot have its own label.
|
||||||
|
// Instead, we label each 4 bits and then use the bit position to determine the bit label.
|
||||||
|
// Result.
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
// Equals.
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
// Sign bit label is always shown.
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
|
||||||
|
DisplayBitLabels(totalBitCount + 1, 1);
|
||||||
|
// Times.
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
// Exponent.
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
|
||||||
|
DisplayBitLabels(exponentBitPosition + 1, ieee754statics.exponentBitCount);
|
||||||
|
|
||||||
|
// Times.
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
// Mantissa.
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
|
||||||
|
DisplayBitLabels(mantissaBitPosition + 1, ieee754statics.mantissaBitCount);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const static auto BitCheckbox = [](u8 bit) {
|
||||||
|
bool checkbox = false;
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f);
|
||||||
|
checkbox = (ieee754statics.value & (u128(1) << bit)) != 0;
|
||||||
|
ImGui::BitCheckbox("##checkbox", &checkbox);
|
||||||
|
ieee754statics.value = (ieee754statics.value & ~(u128(1) << bit)) | (u128(checkbox) << bit);
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const static auto BitCheckboxes = [](u32 startBit, u32 count) {
|
||||||
|
for (u32 i = 0; i < count; i++) {
|
||||||
|
ImGui::PushID(startBit - i);
|
||||||
|
BitCheckbox(startBit - i);
|
||||||
|
ImGui::SameLine(0, 0);
|
||||||
|
ImGui::PopID();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const static auto FormatBits = [](i32 signBitPosition, i32 exponentBitPosition, i32 mantissaBitPosition) {
|
||||||
|
|
||||||
|
// Sign.
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
|
||||||
|
ImVec4 signColor = ImGui::GetCustomColorVec4(ImGuiCustomCol_IEEEToolSign);
|
||||||
|
ImVec4 expColor = ImGui::GetCustomColorVec4(ImGuiCustomCol_IEEEToolExp);
|
||||||
|
ImVec4 mantColor = ImGui::GetCustomColorVec4(ImGuiCustomCol_IEEEToolMantissa);
|
||||||
|
ImVec4 black = ImVec4(0.0, 0.0, 0.0, 1.0);
|
||||||
|
|
||||||
|
float indent = IndentBoxOrLabel(signBitPosition,signBitPosition, 1, false);
|
||||||
|
ImGui::Indent(indent);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_FrameBg, signColor);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Border, black);
|
||||||
|
|
||||||
|
BitCheckboxes(signBitPosition, 1);
|
||||||
|
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
ImGui::Unindent(indent);
|
||||||
|
|
||||||
|
// Times.
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
// Exponent.
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
indent = IndentBoxOrLabel(exponentBitPosition,exponentBitPosition, ieee754statics.exponentBitCount, false);
|
||||||
|
ImGui::Indent(indent);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_FrameBg, expColor);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Border, black);
|
||||||
|
|
||||||
|
BitCheckboxes(exponentBitPosition, ieee754statics.exponentBitCount);
|
||||||
|
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
ImGui::Unindent(indent);
|
||||||
|
// Times.
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
// Mantissa.
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
|
||||||
|
indent = IndentBoxOrLabel(mantissaBitPosition,mantissaBitPosition, ieee754statics.mantissaBitCount, false);
|
||||||
|
ImGui::Indent(indent);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_FrameBg, mantColor);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Border, black);
|
||||||
|
|
||||||
|
BitCheckboxes(mantissaBitPosition, ieee754statics.mantissaBitCount);
|
||||||
|
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
ImGui::Unindent(indent);
|
||||||
|
};
|
||||||
|
|
||||||
|
const static auto BitsToFloat = [](IEEE754 &ieee754) {
|
||||||
|
// Zero or denormal.
|
||||||
|
if (ieee754.exponentBits == 0) {
|
||||||
|
// Result doesn't fit in 128 bits.
|
||||||
|
if ((ieee754.exponentBias - 1) > 128)
|
||||||
|
ieee754.exponentValue = std::pow(2.0L, static_cast<long double>(-ieee754.exponentBias + 1));
|
||||||
|
else {
|
||||||
|
if (ieee754.exponentBias == 0) {
|
||||||
|
// Exponent is zero.
|
||||||
|
if (ieee754.mantissaBits == 0)
|
||||||
|
ieee754.exponentValue = 1.0;
|
||||||
|
else
|
||||||
|
// Exponent is one.
|
||||||
|
ieee754.exponentValue = 2.0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ieee754.exponentValue = 1.0 / static_cast<long double>(u128(1) << (ieee754.exponentBias - 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Normal.
|
||||||
|
else {
|
||||||
|
// Result doesn't fit in 128 bits.
|
||||||
|
if (std::abs(ieee754.exponentBits - ieee754.exponentBias) > 128)
|
||||||
|
ieee754.exponentValue = std::pow(2.0L, static_cast<long double>(ieee754.exponentBits - ieee754.exponentBias));
|
||||||
|
//Result fits in 128 bits.
|
||||||
|
else {
|
||||||
|
// Exponent is positive.
|
||||||
|
if (ieee754.exponentBits > ieee754.exponentBias)
|
||||||
|
ieee754.exponentValue = static_cast<long double>(u128(1) << (ieee754.exponentBits - ieee754.exponentBias));
|
||||||
|
// Exponent is negative.
|
||||||
|
else if (ieee754.exponentBits < ieee754.exponentBias)
|
||||||
|
ieee754.exponentValue = 1.0 / static_cast<long double>(u128(1) << (ieee754.exponentBias - ieee754.exponentBits));
|
||||||
|
// Exponent is zero.
|
||||||
|
else ieee754.exponentValue = 1.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ieee754.mantissaValue = static_cast<long double>(ieee754.mantissaBits) / static_cast<long double>(u128(1) << (ieee754statics.mantissaBitCount));
|
||||||
|
if (ieee754.exponentBits != 0)
|
||||||
|
ieee754.mantissaValue += 1.0;
|
||||||
|
|
||||||
|
// Check if all exponent bits are set.
|
||||||
|
if (std::popcount(static_cast<u64>(ieee754.exponentBits)) == static_cast<i64>(ieee754statics.exponentBitCount)) {
|
||||||
|
// If fraction is zero number is infinity,
|
||||||
|
if (ieee754.mantissaBits == 0) {
|
||||||
|
if (ieee754.signBits == 0) {
|
||||||
|
|
||||||
|
ieee754.valueType = ValueType::PositiveInfinity;
|
||||||
|
ieee754statics.resultFloat = std::numeric_limits<long double>::infinity();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
ieee754.valueType = ValueType::NegativeInfinity;
|
||||||
|
ieee754statics.resultFloat = -std::numeric_limits<long double>::infinity();
|
||||||
|
|
||||||
|
}
|
||||||
|
ieee754.numberType = NumberType::Infinity;
|
||||||
|
|
||||||
|
// otherwise number is NaN.
|
||||||
|
} else {
|
||||||
|
if (ieee754.mantissaBits & (u128(1) << (ieee754statics.mantissaBitCount - 1))) {
|
||||||
|
|
||||||
|
ieee754.valueType = ValueType::QuietNaN;
|
||||||
|
ieee754statics.resultFloat = std::numeric_limits<long double>::quiet_NaN();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
ieee754.valueType = ValueType::SignalingNaN;
|
||||||
|
ieee754statics.resultFloat = std::numeric_limits<long double>::signaling_NaN();
|
||||||
|
|
||||||
|
}
|
||||||
|
ieee754.numberType = NumberType::NaN;
|
||||||
|
}
|
||||||
|
// If all exponent bits are zero, but we have a non-zero fraction
|
||||||
|
// then the number is denormal which are smaller than regular numbers
|
||||||
|
// but not as precise.
|
||||||
|
} else if (ieee754.exponentBits == 0 && ieee754.mantissaBits != 0) {
|
||||||
|
|
||||||
|
ieee754.numberType = NumberType::Denormal;
|
||||||
|
ieee754.valueType = ValueType::Regular;
|
||||||
|
ieee754statics.resultFloat = ieee754.signValue * ieee754.exponentValue * ieee754.mantissaValue;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
ieee754.numberType = NumberType::Normal;
|
||||||
|
ieee754.valueType = ValueType::Regular;
|
||||||
|
ieee754statics.resultFloat = ieee754.signValue * ieee754.exponentValue * ieee754.mantissaValue;
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const static auto FloatToBits = [&specialNumbers](IEEE754 &ieee754, std::string decimalFloatingPointNumberString, int totalBitCount) {
|
||||||
|
|
||||||
|
// Always obtain sign first.
|
||||||
|
if (decimalFloatingPointNumberString[0] == '-') {
|
||||||
|
// And remove it from the string.
|
||||||
|
ieee754.signBits = 1;
|
||||||
|
decimalFloatingPointNumberString.erase(0, 1);
|
||||||
|
} else
|
||||||
|
// Important to switch from - to +.
|
||||||
|
ieee754.signBits = 0;
|
||||||
|
|
||||||
|
InputType inputType = InputType::Regular;
|
||||||
|
bool matchFound = false;
|
||||||
|
|
||||||
|
// Detect and use special numbers.
|
||||||
|
for (u32 i = 0; i < 12; i++) {
|
||||||
|
if (decimalFloatingPointNumberString == specialNumbers[i]) {
|
||||||
|
inputType = InputType(i/3);
|
||||||
|
matchFound = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!matchFound)
|
||||||
|
inputType = InputType::Regular;
|
||||||
|
|
||||||
|
if (inputType == InputType::Regular) {
|
||||||
|
try {
|
||||||
|
ieee754statics.resultFloat = stod(decimalFloatingPointNumberString);
|
||||||
|
} catch(const std::invalid_argument& _) {
|
||||||
|
inputType = InputType::Invalid;
|
||||||
|
}
|
||||||
|
} else if (inputType == InputType::Infinity) {
|
||||||
|
ieee754statics.resultFloat = std::numeric_limits<long double>::infinity();
|
||||||
|
ieee754statics.resultFloat *= (ieee754.signBits == 1 ? -1 : 1);
|
||||||
|
|
||||||
|
} else if (inputType == InputType::NotANumber)
|
||||||
|
ieee754statics.resultFloat = std::numeric_limits<long double>::quiet_NaN();
|
||||||
|
|
||||||
|
else if (inputType == InputType::QuietNotANumber)
|
||||||
|
ieee754statics.resultFloat = std::numeric_limits<long double>::quiet_NaN();
|
||||||
|
|
||||||
|
else if (inputType == InputType::SignalingNotANumber)
|
||||||
|
ieee754statics.resultFloat = std::numeric_limits<long double>::signaling_NaN();
|
||||||
|
|
||||||
|
|
||||||
|
if (inputType != InputType::Invalid) {
|
||||||
|
// Deal with zero first so we can use log2.
|
||||||
|
if (ieee754statics.resultFloat == 0.0) {
|
||||||
|
if (ieee754.signBits == 1)
|
||||||
|
ieee754statics.resultFloat = -0.0;
|
||||||
|
else
|
||||||
|
ieee754statics.resultFloat = 0.0;
|
||||||
|
ieee754.numberType = NumberType::Zero;
|
||||||
|
ieee754.valueType = ValueType::Regular;
|
||||||
|
ieee754.exponentBits = 0;
|
||||||
|
ieee754.mantissaBits = 0;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
long double log2Result = std::log2(ieee754statics.resultFloat);
|
||||||
|
// 2^(bias+1)-2^(bias-prec) is the largest number that can be represented.
|
||||||
|
// If the number entered is larger than this then the input is set to infinity.
|
||||||
|
if (ieee754statics.resultFloat > (std::pow(2.0L, ieee754.exponentBias + 1) - std::pow(2.0L, ieee754.exponentBias - ieee754statics.mantissaBitCount)) || inputType == InputType::Infinity ) {
|
||||||
|
|
||||||
|
ieee754statics.resultFloat = std::numeric_limits<long double>::infinity();
|
||||||
|
ieee754.numberType = NumberType::Infinity;
|
||||||
|
ieee754.valueType = ieee754.signBits == 1 ? ValueType::NegativeInfinity : ValueType::PositiveInfinity;
|
||||||
|
ieee754.exponentBits = (u128(1) << ieee754statics.exponentBitCount) - 1;
|
||||||
|
ieee754.mantissaBits = 0;
|
||||||
|
|
||||||
|
} else if (-std::rint(log2Result) > ieee754.exponentBias + ieee754statics.mantissaBitCount - 1) {
|
||||||
|
|
||||||
|
// 1/2^(bias-1+prec) is the smallest number that can be represented.
|
||||||
|
// If the number entered is smaller than this then the input is set to zero.
|
||||||
|
if (ieee754.signBits == 1)
|
||||||
|
ieee754statics.resultFloat = -0.0;
|
||||||
|
else
|
||||||
|
ieee754statics.resultFloat = 0.0;
|
||||||
|
|
||||||
|
ieee754.numberType = NumberType::Zero;
|
||||||
|
ieee754.valueType = ValueType::Regular;
|
||||||
|
ieee754.exponentBits = 0;
|
||||||
|
ieee754.mantissaBits = 0;
|
||||||
|
|
||||||
|
} else if (inputType == InputType::SignalingNotANumber) {
|
||||||
|
|
||||||
|
ieee754statics.resultFloat = std::numeric_limits<long double>::signaling_NaN();
|
||||||
|
ieee754.valueType = ValueType::SignalingNaN;
|
||||||
|
ieee754.numberType = NumberType::NaN;
|
||||||
|
ieee754.exponentBits = (u128(1) << ieee754statics.exponentBitCount) - 1;
|
||||||
|
ieee754.mantissaBits = 1;
|
||||||
|
|
||||||
|
} else if (inputType == InputType::QuietNotANumber || inputType == InputType::NotANumber ) {
|
||||||
|
|
||||||
|
ieee754statics.resultFloat = std::numeric_limits<long double>::quiet_NaN();
|
||||||
|
ieee754.valueType = ValueType::QuietNaN;
|
||||||
|
ieee754.numberType = NumberType::NaN;
|
||||||
|
ieee754.exponentBits = (u128(1) << ieee754statics.exponentBitCount) - 1;
|
||||||
|
ieee754.mantissaBits = (u128(1) << (ieee754statics.mantissaBitCount - 1));
|
||||||
|
|
||||||
|
} else if (static_cast<i64>(std::floor(log2Result)) + ieee754.exponentBias <= 0) {
|
||||||
|
|
||||||
|
ieee754.numberType = NumberType::Denormal;
|
||||||
|
ieee754.valueType = ValueType::Regular;
|
||||||
|
ieee754.exponentBits = 0;
|
||||||
|
auto mantissaExp = log2Result + ieee754.exponentBias + ieee754statics.mantissaBitCount - 1;
|
||||||
|
ieee754.mantissaBits = static_cast<i64>(std::round(std::pow(2.0L, mantissaExp)));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
ieee754.valueType = ValueType::Regular;
|
||||||
|
ieee754.numberType = NumberType::Normal;
|
||||||
|
i64 unBiasedExponent = static_cast<i64>(std::floor(log2Result));
|
||||||
|
ieee754.exponentBits = unBiasedExponent + ieee754.exponentBias;
|
||||||
|
ieee754.mantissaValue = ieee754statics.resultFloat * std::pow(2.0L, -unBiasedExponent) - 1;
|
||||||
|
ieee754.mantissaBits = static_cast<i64>(std::round( static_cast<long double>(u128(1) << (ieee754statics.mantissaBitCount)) * ieee754.mantissaValue));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Put the bits together.
|
||||||
|
ieee754statics.value = (ieee754.signBits << (totalBitCount)) | (ieee754.exponentBits << (totalBitCount - ieee754statics.exponentBitCount)) | ieee754.mantissaBits;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const static auto DisplayDecimal = [](IEEE754 &ieee754) {
|
||||||
|
|
||||||
|
unsigned signColorU32 = ImGui::GetCustomColorU32(ImGuiCustomCol_IEEEToolSign);
|
||||||
|
unsigned expColorU32 = ImGui::GetCustomColorU32(ImGuiCustomCol_IEEEToolExp);
|
||||||
|
unsigned mantColorU32 = ImGui::GetCustomColorU32(ImGuiCustomCol_IEEEToolMantissa);
|
||||||
|
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
|
||||||
|
ImGui::Text("=");
|
||||||
|
|
||||||
|
// Sign.
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
|
||||||
|
// This has the effect of dimming the color of the numbers so user doesn't try
|
||||||
|
// to interact with them.
|
||||||
|
ImVec4 textColor = ImGui::GetStyleColorVec4(ImGuiCol_Text);
|
||||||
|
ImGui::BeginDisabled();
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, textColor);
|
||||||
|
|
||||||
|
ImGui::Indent(10_scaled);
|
||||||
|
ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, signColorU32);
|
||||||
|
if (ieee754.signBits == 1)
|
||||||
|
ImGui::Text("-1");
|
||||||
|
else
|
||||||
|
ImGui::Text("+1");
|
||||||
|
ImGui::Unindent(10_scaled);
|
||||||
|
|
||||||
|
// Times.
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::Text("x");
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
|
||||||
|
// Exponent.
|
||||||
|
ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, expColorU32);
|
||||||
|
|
||||||
|
ImGui::Indent(20_scaled);
|
||||||
|
if (ieee754.numberType == NumberType::NaN) {
|
||||||
|
if (ieee754.valueType == ValueType::QuietNaN)
|
||||||
|
ImGui::Text("qNaN");
|
||||||
|
else
|
||||||
|
ImGui::Text("sNaN");
|
||||||
|
|
||||||
|
} else if (ieee754.numberType == NumberType::Infinity)
|
||||||
|
ImGui::Text("Inf");
|
||||||
|
else if (ieee754.numberType == NumberType::Zero)
|
||||||
|
ImGui::Text("0");
|
||||||
|
else if (ieee754.numberType == NumberType::Denormal)
|
||||||
|
ImGui::TextFormatted("2^{0}", 1 - ieee754.exponentBias);
|
||||||
|
else
|
||||||
|
ImGui::TextFormatted("2^{0}", ieee754.exponentBits - ieee754.exponentBias);
|
||||||
|
|
||||||
|
ImGui::Unindent(20_scaled);
|
||||||
|
|
||||||
|
// Times.
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::Text("x");
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
|
||||||
|
// Mantissa.
|
||||||
|
ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, mantColorU32);
|
||||||
|
ImGui::Indent(20_scaled);
|
||||||
|
ImGui::TextFormatted("{:.{}}", ieee754.mantissaValue,ieee754.precision);
|
||||||
|
ImGui::Unindent(20_scaled);
|
||||||
|
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const static auto ToolMenu = [](i64 &inputFieldWidth) {
|
||||||
|
// If precision and exponent match one of the IEEE 754 formats the format is highlighted
|
||||||
|
// and remains highlighted until user changes to a different format. Matching formats occur when
|
||||||
|
// the user clicks on one of the selections or if the slider values match the format in question.
|
||||||
|
// When a new format is selected, it may have a smaller number of digits than
|
||||||
|
// the previous selection. Since the largest of the hexadecimal and the decimal
|
||||||
|
// representation widths set both field widths to the same value, we need to
|
||||||
|
// reset it here when a new choice is set.
|
||||||
|
|
||||||
|
auto exponentBitCount = ieee754statics.exponentBitCount;
|
||||||
|
auto mantissaBitCount = ieee754statics.mantissaBitCount;
|
||||||
|
if (ImGui::SliderInt("hex.builtin.tools.ieee754.exponent_size"_lang, &exponentBitCount, 1, 63 - mantissaBitCount)) {
|
||||||
|
inputFieldWidth = 0;
|
||||||
|
ieee754statics.exponentBitCount = exponentBitCount;
|
||||||
|
}
|
||||||
|
if (ImGui::SliderInt("hex.builtin.tools.ieee754.mantissa_size"_lang, &mantissaBitCount, 1, 63 - exponentBitCount)) {
|
||||||
|
inputFieldWidth = 0;
|
||||||
|
ieee754statics.mantissaBitCount = mantissaBitCount;
|
||||||
|
}
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
auto color = ImGui::GetColorU32(ImGuiCol_ButtonActive);
|
||||||
|
|
||||||
|
bool needsPop = false;
|
||||||
|
if (ieee754statics.exponentBitCount == 5 && ieee754statics.mantissaBitCount == 10) {
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Button, color);
|
||||||
|
needsPop = true;
|
||||||
|
}
|
||||||
|
if (ImGui::Button("hex.builtin.tools.ieee754.half_precision"_lang)) {
|
||||||
|
ieee754statics.exponentBitCount = 5;
|
||||||
|
ieee754statics.mantissaBitCount = 10;
|
||||||
|
inputFieldWidth = 0;
|
||||||
|
}
|
||||||
|
if (needsPop) ImGui::PopStyleColor();
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
needsPop = false;
|
||||||
|
if (ieee754statics.exponentBitCount == 8 && ieee754statics.mantissaBitCount == 23) {
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Button, color);
|
||||||
|
needsPop = true;
|
||||||
|
}
|
||||||
|
if (ImGui::Button("hex.builtin.tools.ieee754.single_precision"_lang)) {
|
||||||
|
ieee754statics.exponentBitCount = 8;
|
||||||
|
ieee754statics.mantissaBitCount = 23;
|
||||||
|
inputFieldWidth = 0;
|
||||||
|
}
|
||||||
|
if (needsPop) ImGui::PopStyleColor();
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
needsPop = false;
|
||||||
|
if (ieee754statics.exponentBitCount == 11 && ieee754statics.mantissaBitCount == 52) {
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Button, color);
|
||||||
|
needsPop = true;
|
||||||
|
}
|
||||||
|
if (ImGui::Button("hex.builtin.tools.ieee754.double_precision"_lang)) {
|
||||||
|
ieee754statics.exponentBitCount = 11;
|
||||||
|
ieee754statics.mantissaBitCount = 52;
|
||||||
|
inputFieldWidth = 0;
|
||||||
|
}
|
||||||
|
if (needsPop) ImGui::PopStyleColor();
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
needsPop = false;
|
||||||
|
if (ImGui::Button("hex.builtin.tools.ieee754.clear"_lang))
|
||||||
|
// This will reset all interactive widgets to zero.
|
||||||
|
ieee754statics.value = 0;
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
ImGui::NewLine();
|
||||||
|
};
|
||||||
|
|
||||||
|
if (ImGui::BeginTable("##outer", 7, tableFlags, ImVec2(0, ImGui::GetTextLineHeightWithSpacing() * 5.5 ))) {
|
||||||
|
ImGui::TableSetupColumn("hex.builtin.tools.ieee754.result.title"_lang);
|
||||||
|
ImGui::TableSetupColumn("##equals");
|
||||||
|
ImGui::TableSetupColumn("hex.builtin.tools.ieee754.sign"_lang);
|
||||||
|
ImGui::TableSetupColumn("##times");
|
||||||
|
ImGui::TableSetupColumn("hex.builtin.tools.ieee754.exponent"_lang);
|
||||||
|
ImGui::TableSetupColumn("##times");
|
||||||
|
ImGui::TableSetupColumn("hex.builtin.tools.ieee754.mantissa"_lang);
|
||||||
|
ImGui::TableHeadersRow();
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
|
||||||
|
FormatBitLabels(totalBitCount, exponentBitPosition, mantissaBitPosition);
|
||||||
|
|
||||||
|
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
// Row for bit checkboxes
|
||||||
|
// Result.
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
|
||||||
|
u64 mask = hex::bitmask(totalBitCount+1);
|
||||||
|
std::string maskString = hex::format("0x{:X} ", mask);
|
||||||
|
|
||||||
|
auto style = ImGui::GetStyle();
|
||||||
|
inputFieldWidth = std::fmax(inputFieldWidth,
|
||||||
|
ImGui::CalcTextSize(maskString.c_str()).x + style.FramePadding.x * 2.0f);
|
||||||
|
ImGui::PushItemWidth(inputFieldWidth);
|
||||||
|
|
||||||
|
u64 newValue = ieee754statics.value & mask;
|
||||||
|
if (ImGui::InputHexadecimal("##hex", &newValue, flags))
|
||||||
|
ieee754statics.value = newValue;
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
|
||||||
|
// Equals.
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::Text("=");
|
||||||
|
|
||||||
|
FormatBits(signBitPosition, exponentBitPosition, mantissaBitPosition);
|
||||||
|
|
||||||
|
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
|
||||||
|
ieee754.exponentBias = (u128(1) << (ieee754statics.exponentBitCount - 1)) - 1;
|
||||||
|
|
||||||
|
ieee754.signValue = ieee754.signBits == 0 ? 1.0 : -1.0;
|
||||||
|
|
||||||
|
BitsToFloat(ieee754);
|
||||||
|
|
||||||
|
if (ieee754.numberType == NumberType::Denormal)
|
||||||
|
ieee754.precision = std::ceil(1+ieee754statics.mantissaBitCount * std::log10(2.0L));
|
||||||
|
else
|
||||||
|
ieee754.precision = std::ceil(1+(ieee754statics.mantissaBitCount + 1) * std::log10(2.0L));
|
||||||
|
|
||||||
|
// For C++ from_chars is better than strtold.
|
||||||
|
// The main problem is that from_chars will not process special numbers
|
||||||
|
// like inf and nan, so we handle them manually.
|
||||||
|
static std::string decimalFloatingPointNumberString;
|
||||||
|
|
||||||
|
// Use qnan for quiet NaN and snan for signaling NaN.
|
||||||
|
if (ieee754.numberType == NumberType::NaN) {
|
||||||
|
if (ieee754.valueType == ValueType::QuietNaN)
|
||||||
|
decimalFloatingPointNumberString = "qnan";
|
||||||
|
else
|
||||||
|
decimalFloatingPointNumberString = "snan";
|
||||||
|
} else
|
||||||
|
decimalFloatingPointNumberString = fmt::format("{:.{}}", ieee754statics.resultFloat, ieee754.precision);
|
||||||
|
|
||||||
|
auto style1 = ImGui::GetStyle();
|
||||||
|
inputFieldWidth = std::fmax(inputFieldWidth, ImGui::CalcTextSize(decimalFloatingPointNumberString.c_str()).x + 2 * style1.FramePadding.x);
|
||||||
|
ImGui::PushItemWidth(inputFieldWidth);
|
||||||
|
|
||||||
|
|
||||||
|
// We allow any input in order to accept infinities and NaNs, all invalid entries
|
||||||
|
// are detected catching exceptions. You can also enter -0 or -inf.
|
||||||
|
if (ImGui::InputText("##resultFloat", decimalFloatingPointNumberString, flags)) {
|
||||||
|
FloatToBits(ieee754, decimalFloatingPointNumberString, totalBitCount);
|
||||||
|
}
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
|
||||||
|
if (displayMode == 0)
|
||||||
|
DisplayDecimal(ieee754);
|
||||||
|
|
||||||
|
ImGui::EndTable();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ToolMenu(inputFieldWidth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
332
plugins/builtin/source/content/tools/math_eval.cpp
Normal file
332
plugins/builtin/source/content/tools/math_eval.cpp
Normal file
@ -0,0 +1,332 @@
|
|||||||
|
#include <hex/api/localization.hpp>
|
||||||
|
#include <hex/api/imhex_api.hpp>
|
||||||
|
#include <hex/providers/provider.hpp>
|
||||||
|
#include <hex/ui/imgui_imhex_extensions.h>
|
||||||
|
#include <hex/helpers/utils.hpp>
|
||||||
|
#include <content/helpers/math_evaluator.hpp>
|
||||||
|
|
||||||
|
#include <imgui.h>
|
||||||
|
#include <fonts/fontawesome_font.h>
|
||||||
|
#include <fonts/codicons_font.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace hex::plugin::builtin {
|
||||||
|
namespace impl {
|
||||||
|
void drawMathEvaluator() {
|
||||||
|
static std::vector<long double> mathHistory;
|
||||||
|
static std::string lastMathError;
|
||||||
|
static std::string mathInput;
|
||||||
|
bool evaluate = false;
|
||||||
|
|
||||||
|
static MathEvaluator<long double> mathEvaluator = [&] {
|
||||||
|
MathEvaluator<long double> evaluator;
|
||||||
|
|
||||||
|
evaluator.registerStandardVariables();
|
||||||
|
evaluator.registerStandardFunctions();
|
||||||
|
|
||||||
|
evaluator.setFunction(
|
||||||
|
"clear", [&](auto args) -> std::optional<long double> {
|
||||||
|
hex::unused(args);
|
||||||
|
|
||||||
|
mathHistory.clear();
|
||||||
|
lastMathError.clear();
|
||||||
|
mathEvaluator.getVariables().clear();
|
||||||
|
mathEvaluator.registerStandardVariables();
|
||||||
|
mathInput.clear();
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
},
|
||||||
|
0,
|
||||||
|
0);
|
||||||
|
|
||||||
|
evaluator.setFunction(
|
||||||
|
"read", [](auto args) -> std::optional<long double> {
|
||||||
|
u8 value = 0;
|
||||||
|
|
||||||
|
auto provider = ImHexApi::Provider::get();
|
||||||
|
if (!ImHexApi::Provider::isValid() || !provider->isReadable() || args[0] >= provider->getActualSize())
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
provider->read(args[0], &value, sizeof(u8));
|
||||||
|
|
||||||
|
return value;
|
||||||
|
},
|
||||||
|
1,
|
||||||
|
1);
|
||||||
|
|
||||||
|
evaluator.setFunction(
|
||||||
|
"write", [](auto args) -> std::optional<long double> {
|
||||||
|
auto provider = ImHexApi::Provider::get();
|
||||||
|
if (!ImHexApi::Provider::isValid() || !provider->isWritable() || args[0] >= provider->getActualSize())
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
if (args[1] > 0xFF)
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
u8 value = args[1];
|
||||||
|
provider->write(args[0], &value, sizeof(u8));
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
},
|
||||||
|
2,
|
||||||
|
2);
|
||||||
|
|
||||||
|
return evaluator;
|
||||||
|
}();
|
||||||
|
|
||||||
|
enum class MathDisplayType : u8 {
|
||||||
|
Standard,
|
||||||
|
Scientific,
|
||||||
|
Engineering,
|
||||||
|
Programmer
|
||||||
|
} mathDisplayType = MathDisplayType::Standard;
|
||||||
|
|
||||||
|
if (ImGui::BeginTabBar("##mathFormatTabBar")) {
|
||||||
|
if (ImGui::BeginTabItem("hex.builtin.tools.format.standard"_lang)) {
|
||||||
|
mathDisplayType = MathDisplayType::Standard;
|
||||||
|
ImGui::EndTabItem();
|
||||||
|
}
|
||||||
|
if (ImGui::BeginTabItem("hex.builtin.tools.format.scientific"_lang)) {
|
||||||
|
mathDisplayType = MathDisplayType::Scientific;
|
||||||
|
ImGui::EndTabItem();
|
||||||
|
}
|
||||||
|
if (ImGui::BeginTabItem("hex.builtin.tools.format.engineering"_lang)) {
|
||||||
|
mathDisplayType = MathDisplayType::Engineering;
|
||||||
|
ImGui::EndTabItem();
|
||||||
|
}
|
||||||
|
if (ImGui::BeginTabItem("hex.builtin.tools.format.programmer"_lang)) {
|
||||||
|
mathDisplayType = MathDisplayType::Programmer;
|
||||||
|
ImGui::EndTabItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndTabBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::BeginTable("##mathWrapper", 3)) {
|
||||||
|
ImGui::TableSetupColumn("##keypad", ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoResize);
|
||||||
|
ImGui::TableSetupColumn("##results", ImGuiTableColumnFlags_WidthStretch, 0.666);
|
||||||
|
ImGui::TableSetupColumn("##variables", ImGuiTableColumnFlags_WidthStretch, 0.666);
|
||||||
|
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
|
||||||
|
auto buttonSize = ImVec2(3, 2) * ImGui::GetTextLineHeightWithSpacing();
|
||||||
|
|
||||||
|
if (ImGui::Button("Ans", buttonSize)) mathInput += "ans";
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("Pi", buttonSize)) mathInput += "pi";
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("e", buttonSize)) mathInput += "e";
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("CE", buttonSize)) mathInput.clear();
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button(ICON_FA_BACKSPACE, buttonSize)) mathInput.clear();
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::NewLine();
|
||||||
|
|
||||||
|
switch (mathDisplayType) {
|
||||||
|
case MathDisplayType::Standard:
|
||||||
|
case MathDisplayType::Scientific:
|
||||||
|
case MathDisplayType::Engineering:
|
||||||
|
if (ImGui::Button("x²", buttonSize)) mathInput += "** 2";
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("1/x", buttonSize)) mathInput += "1/";
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("|x|", buttonSize)) mathInput += "abs";
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("exp", buttonSize)) mathInput += "e ** ";
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("%", buttonSize)) mathInput += "%";
|
||||||
|
ImGui::SameLine();
|
||||||
|
break;
|
||||||
|
case MathDisplayType::Programmer:
|
||||||
|
if (ImGui::Button("<<", buttonSize)) mathInput += "<<";
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button(">>", buttonSize)) mathInput += ">>";
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("&", buttonSize)) mathInput += "&";
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("|", buttonSize)) mathInput += "|";
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("^", buttonSize)) mathInput += "^";
|
||||||
|
ImGui::SameLine();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ImGui::NewLine();
|
||||||
|
if (ImGui::Button("sqrt", buttonSize)) mathInput += "sqrt";
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("(", buttonSize)) mathInput += "(";
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button(")", buttonSize)) mathInput += ")";
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("sign", buttonSize)) mathInput += "sign";
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("÷", buttonSize)) mathInput += "/";
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::NewLine();
|
||||||
|
if (ImGui::Button("xª", buttonSize)) mathInput += "**";
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("7", buttonSize)) mathInput += "7";
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("8", buttonSize)) mathInput += "8";
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("9", buttonSize)) mathInput += "9";
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("×", buttonSize)) mathInput += "*";
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::NewLine();
|
||||||
|
if (ImGui::Button("log", buttonSize)) mathInput += "log";
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("4", buttonSize)) mathInput += "4";
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("5", buttonSize)) mathInput += "5";
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("6", buttonSize)) mathInput += "6";
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("-", buttonSize)) mathInput += "-";
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::NewLine();
|
||||||
|
if (ImGui::Button("ln", buttonSize)) mathInput += "ln";
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("1", buttonSize)) mathInput += "1";
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("2", buttonSize)) mathInput += "2";
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("3", buttonSize)) mathInput += "3";
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("+", buttonSize)) mathInput += "+";
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::NewLine();
|
||||||
|
if (ImGui::Button("lb", buttonSize)) mathInput += "lb";
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("x=", buttonSize)) mathInput += "=";
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("0", buttonSize)) mathInput += "0";
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button(".", buttonSize)) mathInput += ".";
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetCustomColorVec4(ImGuiCustomCol_DescButtonHovered));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImGui::GetCustomColorVec4(ImGuiCustomCol_DescButton));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImGui::GetCustomColorVec4(ImGuiCustomCol_DescButtonActive));
|
||||||
|
if (ImGui::Button("=", buttonSize)) evaluate = true;
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::PopStyleColor(3);
|
||||||
|
|
||||||
|
ImGui::NewLine();
|
||||||
|
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
|
||||||
|
if (ImGui::BeginTable("##mathHistory", 1, ImGuiTableFlags_ScrollY | ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg, ImVec2(0, 300))) {
|
||||||
|
ImGui::TableSetupColumn("hex.builtin.tools.history"_lang);
|
||||||
|
ImGui::TableSetupScrollFreeze(0, 1);
|
||||||
|
|
||||||
|
ImGuiListClipper clipper;
|
||||||
|
clipper.Begin(mathHistory.size());
|
||||||
|
|
||||||
|
ImGui::TableHeadersRow();
|
||||||
|
while (clipper.Step()) {
|
||||||
|
for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) {
|
||||||
|
if (i == 0)
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, ImU32(ImColor(0xA5, 0x45, 0x45)));
|
||||||
|
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
|
||||||
|
switch (mathDisplayType) {
|
||||||
|
case MathDisplayType::Standard:
|
||||||
|
ImGui::TextFormatted("{0:.3Lf}", mathHistory[(mathHistory.size() - 1) - i]);
|
||||||
|
break;
|
||||||
|
case MathDisplayType::Scientific:
|
||||||
|
ImGui::TextFormatted("{0:.6Lg}", mathHistory[(mathHistory.size() - 1) - i]);
|
||||||
|
break;
|
||||||
|
case MathDisplayType::Engineering:
|
||||||
|
ImGui::TextFormatted("{0}", hex::toEngineeringString(mathHistory[(mathHistory.size() - 1) - i]).c_str());
|
||||||
|
break;
|
||||||
|
case MathDisplayType::Programmer:
|
||||||
|
ImGui::TextFormatted("0x{0:X} ({1})",
|
||||||
|
u64(mathHistory[(mathHistory.size() - 1) - i]),
|
||||||
|
u64(mathHistory[(mathHistory.size() - 1) - i]));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == 0)
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clipper.End();
|
||||||
|
|
||||||
|
ImGui::EndTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
if (ImGui::BeginTable("##mathVariables", 2, ImGuiTableFlags_ScrollY | ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg, ImVec2(0, 300))) {
|
||||||
|
ImGui::TableSetupColumn("hex.builtin.tools.name"_lang);
|
||||||
|
ImGui::TableSetupColumn("hex.builtin.tools.value"_lang);
|
||||||
|
ImGui::TableSetupScrollFreeze(0, 1);
|
||||||
|
|
||||||
|
ImGui::TableHeadersRow();
|
||||||
|
for (const auto &[name, variable] : mathEvaluator.getVariables()) {
|
||||||
|
const auto &[value, constant] = variable;
|
||||||
|
|
||||||
|
if (constant)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::TextUnformatted(name.c_str());
|
||||||
|
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
switch (mathDisplayType) {
|
||||||
|
case MathDisplayType::Standard:
|
||||||
|
ImGui::TextFormatted("{0:.3Lf}", value);
|
||||||
|
break;
|
||||||
|
case MathDisplayType::Scientific:
|
||||||
|
ImGui::TextFormatted("{0:.6Lg}", value);
|
||||||
|
break;
|
||||||
|
case MathDisplayType::Engineering:
|
||||||
|
ImGui::TextFormatted("{}", hex::toEngineeringString(value));
|
||||||
|
break;
|
||||||
|
case MathDisplayType::Programmer:
|
||||||
|
ImGui::TextFormatted("0x{0:X} ({1})", u64(value), u64(value));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x);
|
||||||
|
if (ImGui::InputTextIcon("##input", ICON_VS_SYMBOL_OPERATOR, mathInput, ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_AutoSelectAll)) {
|
||||||
|
ImGui::SetKeyboardFocusHere();
|
||||||
|
evaluate = true;
|
||||||
|
}
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
|
||||||
|
if (!lastMathError.empty())
|
||||||
|
ImGui::TextFormattedColored(ImColor(0xA00040FF), "hex.builtin.tools.error"_lang, lastMathError);
|
||||||
|
else
|
||||||
|
ImGui::NewLine();
|
||||||
|
|
||||||
|
if (evaluate) {
|
||||||
|
try {
|
||||||
|
auto result = mathEvaluator.evaluate(mathInput);
|
||||||
|
mathInput.clear();
|
||||||
|
if (result.has_value()) {
|
||||||
|
mathHistory.push_back(result.value());
|
||||||
|
lastMathError.clear();
|
||||||
|
}
|
||||||
|
} catch (std::invalid_argument &e) {
|
||||||
|
lastMathError = e.what();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
#include <hex/helpers/utils.hpp>
|
||||||
|
#include <hex/api/localization.hpp>
|
||||||
|
|
||||||
|
#include <content/tools_entries.hpp>
|
||||||
|
|
||||||
|
#include <imgui.h>
|
||||||
|
|
||||||
|
#include <hex/ui/imgui_imhex_extensions.h>
|
||||||
|
|
||||||
|
#include <wolv/net/socket_client.hpp>
|
||||||
|
|
||||||
|
namespace hex::plugin::builtin {
|
||||||
|
namespace impl {
|
||||||
|
void drawInvariantMultiplicationDecoder() {
|
||||||
|
static u64 divisor = 1;
|
||||||
|
static u64 multiplier = 1;
|
||||||
|
static u64 numBits = 32;
|
||||||
|
|
||||||
|
ImGui::TextFormattedWrapped("{}", "hex.builtin.tools.invariant_multiplication.description"_lang);
|
||||||
|
|
||||||
|
ImGui::NewLine();
|
||||||
|
|
||||||
|
if (ImGui::BeginChild("##calculator", ImVec2(0, ImGui::GetTextLineHeightWithSpacing() * 5), true)) {
|
||||||
|
constexpr static u64 min = 1, max = 64;
|
||||||
|
ImGui::SliderScalar("hex.builtin.tools.invariant_multiplication.num_bits"_lang, ImGuiDataType_U64, &numBits, &min, &max);
|
||||||
|
ImGui::NewLine();
|
||||||
|
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::GetStyleColorVec4(ImGuiCol_TableRowBgAlt));
|
||||||
|
if (ImGui::BeginChild("##calculator", ImVec2(0, ImGui::GetTextLineHeightWithSpacing() + 12_scaled), true)) {
|
||||||
|
ImGui::PushItemWidth(100_scaled);
|
||||||
|
|
||||||
|
ImGui::TextUnformatted("X /");
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::InputScalar("##divisor", ImGuiDataType_U64, &divisor)) {
|
||||||
|
if (divisor == 0)
|
||||||
|
divisor = 1;
|
||||||
|
|
||||||
|
multiplier = ((1LLU << (numBits + 1)) / divisor) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
ImGui::TextUnformatted(" <=> ");
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::TextUnformatted("( X *");
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::InputHexadecimal("##multiplier", &multiplier)) {
|
||||||
|
if (multiplier == 0)
|
||||||
|
multiplier = 1;
|
||||||
|
divisor = ((1LLU << (numBits + 1)) / multiplier) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::TextFormatted(") >> {}", numBits + 1);
|
||||||
|
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
}
|
||||||
|
ImGui::EndChild();
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
}
|
||||||
|
ImGui::EndChild();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
70
plugins/builtin/source/content/tools/perms_calc.cpp
Normal file
70
plugins/builtin/source/content/tools/perms_calc.cpp
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
#include <hex/helpers/fmt.hpp>
|
||||||
|
#include <hex/api/localization.hpp>
|
||||||
|
|
||||||
|
#include <imgui.h>
|
||||||
|
|
||||||
|
#include <hex/ui/imgui_imhex_extensions.h>
|
||||||
|
|
||||||
|
#include <wolv/net/socket_client.hpp>
|
||||||
|
|
||||||
|
namespace hex::plugin::builtin {
|
||||||
|
namespace impl {
|
||||||
|
void drawPermissionsCalculator() {
|
||||||
|
static bool setuid, setgid, sticky;
|
||||||
|
static bool r[3], w[3], x[3];
|
||||||
|
|
||||||
|
ImGui::TextUnformatted("hex.builtin.tools.permissions.perm_bits"_lang);
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
if (ImGui::BeginTable("Permissions", 4, ImGuiTableFlags_Borders)) {
|
||||||
|
ImGui::TableSetupColumn("Special", ImGuiTableColumnFlags_NoSort);
|
||||||
|
ImGui::TableSetupColumn("User", ImGuiTableColumnFlags_NoSort);
|
||||||
|
ImGui::TableSetupColumn("Group", ImGuiTableColumnFlags_NoSort);
|
||||||
|
ImGui::TableSetupColumn("Other", ImGuiTableColumnFlags_NoSort);
|
||||||
|
ImGui::TableSetupScrollFreeze(0, 1);
|
||||||
|
|
||||||
|
ImGui::TableHeadersRow();
|
||||||
|
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
|
||||||
|
ImGui::Checkbox("setuid", &setuid);
|
||||||
|
ImGui::Checkbox("setgid", &setgid);
|
||||||
|
ImGui::Checkbox("Sticky bit", &sticky);
|
||||||
|
|
||||||
|
for (u8 i = 0; i < 3; i++) {
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
|
||||||
|
ImGui::PushID(i);
|
||||||
|
ImGui::Checkbox("Read", &r[i]);
|
||||||
|
ImGui::Checkbox("Write", &w[i]);
|
||||||
|
ImGui::Checkbox("Execute", &x[i]);
|
||||||
|
ImGui::PopID();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::NewLine();
|
||||||
|
ImGui::TextUnformatted("hex.builtin.tools.permissions.absolute"_lang);
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
auto result = hex::format("{}{}{}{}",
|
||||||
|
(setuid << 2) | (setgid << 1) | (sticky << 0),
|
||||||
|
(r[0] << 2) | (w[0] << 1) | (x[0] << 0),
|
||||||
|
(r[1] << 2) | (w[1] << 1) | (x[1] << 0),
|
||||||
|
(r[2] << 2) | (w[2] << 1) | (x[2] << 0));
|
||||||
|
ImGui::InputText("##permissions_absolute", result.data(), result.size(), ImGuiInputTextFlags_ReadOnly);
|
||||||
|
|
||||||
|
ImGui::NewLine();
|
||||||
|
|
||||||
|
constexpr static auto WarningColor = ImColor(0.92F, 0.25F, 0.2F, 1.0F);
|
||||||
|
if (setuid && !x[0])
|
||||||
|
ImGui::TextFormattedColored(WarningColor, "{}", "hex.builtin.tools.permissions.setuid_error"_lang);
|
||||||
|
if (setgid && !x[1])
|
||||||
|
ImGui::TextFormattedColored(WarningColor, "{}", "hex.builtin.tools.permissions.setgid_error"_lang);
|
||||||
|
if (sticky && !x[2])
|
||||||
|
ImGui::TextFormattedColored(WarningColor, "{}", "hex.builtin.tools.permissions.sticky_error"_lang);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
42
plugins/builtin/source/content/tools/regex_replacer.cpp
Normal file
42
plugins/builtin/source/content/tools/regex_replacer.cpp
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
#include <hex/helpers/http_requests.hpp>
|
||||||
|
#include <hex/helpers/utils.hpp>
|
||||||
|
#include <hex/api/localization.hpp>
|
||||||
|
|
||||||
|
#include <hex/ui/view.hpp>
|
||||||
|
|
||||||
|
#include <regex>
|
||||||
|
|
||||||
|
#include <llvm/Demangle/Demangle.h>
|
||||||
|
#include <content/tools_entries.hpp>
|
||||||
|
|
||||||
|
#include <imgui.h>
|
||||||
|
|
||||||
|
#include <hex/ui/imgui_imhex_extensions.h>
|
||||||
|
|
||||||
|
#include <wolv/net/socket_server.hpp>
|
||||||
|
|
||||||
|
namespace hex::plugin::builtin {
|
||||||
|
namespace impl {
|
||||||
|
void drawRegexReplacer() {
|
||||||
|
static auto regexInput = [] { std::string s; s.reserve(0xFFF); return s; }();
|
||||||
|
static auto regexPattern = [] { std::string s; s.reserve(0xFFF); return s; }();
|
||||||
|
static auto replacePattern = [] { std::string s; s.reserve(0xFFF); return s; }();
|
||||||
|
static auto regexOutput = [] { std::string s; s.reserve(0xFFF); return s; }();
|
||||||
|
|
||||||
|
ImGui::PushItemWidth(-150_scaled);
|
||||||
|
bool changed1 = ImGui::InputTextIcon("hex.builtin.tools.regex_replacer.pattern"_lang, ICON_VS_REGEX, regexPattern);
|
||||||
|
bool changed2 = ImGui::InputTextIcon("hex.builtin.tools.regex_replacer.replace"_lang, ICON_VS_REGEX, replacePattern);
|
||||||
|
bool changed3 = ImGui::InputTextMultiline("hex.builtin.tools.regex_replacer.input"_lang, regexInput, ImVec2(0, 0));
|
||||||
|
|
||||||
|
if (changed1 || changed2 || changed3) {
|
||||||
|
try {
|
||||||
|
regexOutput = std::regex_replace(regexInput.data(), std::regex(regexPattern.data()), replacePattern.data());
|
||||||
|
} catch (std::regex_error &) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::InputTextMultiline("hex.builtin.tools.regex_replacer.output"_lang, regexOutput.data(), regexOutput.size(), ImVec2(0, 0), ImGuiInputTextFlags_ReadOnly);
|
||||||
|
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
194
plugins/builtin/source/content/tools/tcp_client_server.cpp
Normal file
194
plugins/builtin/source/content/tools/tcp_client_server.cpp
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
#include <hex/api/localization.hpp>
|
||||||
|
#include <hex/helpers/utils.hpp>
|
||||||
|
#include <hex/ui/imgui_imhex_extensions.h>
|
||||||
|
#include <wolv/net/socket_client.hpp>
|
||||||
|
#include <wolv/net/socket_server.hpp>
|
||||||
|
|
||||||
|
#include <fonts/codicons_font.h>
|
||||||
|
#include <imgui.h>
|
||||||
|
#include <jthread.hpp>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace hex::plugin::builtin {
|
||||||
|
namespace impl {
|
||||||
|
using namespace std::literals::chrono_literals;
|
||||||
|
|
||||||
|
void drawTCPClientServer() {
|
||||||
|
if (ImGui::BeginTabBar("##tcpTransceiver", ImGuiTabBarFlags_None)) {
|
||||||
|
if (ImGui::BeginTabItem("hex.builtin.tools.tcp_client_server.client"_lang)) {
|
||||||
|
static wolv::net::SocketClient client;
|
||||||
|
|
||||||
|
static std::string ipAddress;
|
||||||
|
static int port;
|
||||||
|
|
||||||
|
static std::vector<std::string> messages;
|
||||||
|
static std::string input;
|
||||||
|
static std::jthread receiverThread;
|
||||||
|
static std::mutex receiverMutex;
|
||||||
|
|
||||||
|
ImGui::Header("hex.builtin.tools.tcp_client_server.settings"_lang, true);
|
||||||
|
|
||||||
|
ImGui::BeginDisabled(client.isConnected());
|
||||||
|
{
|
||||||
|
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x * 0.3F);
|
||||||
|
ImGui::InputText("##ipAddress", ipAddress);
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
ImGui::SameLine(0, 0);
|
||||||
|
ImGui::TextUnformatted(":");
|
||||||
|
ImGui::SameLine(0, 0);
|
||||||
|
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x * 0.2F);
|
||||||
|
ImGui::InputInt("##port", &port, 0, 0);
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
}
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x * 0.2F);
|
||||||
|
if (client.isConnected()) {
|
||||||
|
if (ImGui::IconButton(ICON_VS_DEBUG_DISCONNECT, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarRed))) {
|
||||||
|
client.disconnect();
|
||||||
|
|
||||||
|
receiverThread.request_stop();
|
||||||
|
receiverThread.join();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (ImGui::IconButton(ICON_VS_PLAY, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarGreen))) {
|
||||||
|
client.connect(ipAddress, port);
|
||||||
|
|
||||||
|
receiverThread = std::jthread([](const std::stop_token& stopToken) {
|
||||||
|
while (!stopToken.stop_requested()) {
|
||||||
|
auto message = client.readString();
|
||||||
|
if (!message.empty()) {
|
||||||
|
std::scoped_lock lock(receiverMutex);
|
||||||
|
messages.push_back(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
|
||||||
|
if (port < 1)
|
||||||
|
port = 1;
|
||||||
|
else if (port > 65535)
|
||||||
|
port = 65535;
|
||||||
|
|
||||||
|
ImGui::Header("hex.builtin.tools.tcp_client_server.messages"_lang);
|
||||||
|
if (ImGui::BeginTable("##response", 1, ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders, ImVec2(0, 200_scaled))) {
|
||||||
|
{
|
||||||
|
std::scoped_lock lock(receiverMutex);
|
||||||
|
for (const auto &message : messages) {
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::TextFormattedSelectable("{}", message.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::BeginDisabled(!client.isConnected());
|
||||||
|
{
|
||||||
|
ImGui::PushItemWidth(-(50_scaled));
|
||||||
|
bool pressedEnter = ImGui::InputText("##input", input, ImGuiInputTextFlags_EnterReturnsTrue);
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
if (pressedEnter)
|
||||||
|
ImGui::SetKeyboardFocusHere(-1);
|
||||||
|
|
||||||
|
if (ImGui::IconButton(ICON_VS_DEBUG_STACKFRAME, ImGui::GetStyleColorVec4(ImGuiCol_Text)) || pressedEnter) {
|
||||||
|
client.writeString(input);
|
||||||
|
input.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
|
||||||
|
ImGui::EndTabItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::BeginTabItem("hex.builtin.tools.tcp_client_server.server"_lang)) {
|
||||||
|
static wolv::net::SocketServer server;
|
||||||
|
static int port;
|
||||||
|
|
||||||
|
static std::vector<std::string> messages;
|
||||||
|
static std::mutex receiverMutex;
|
||||||
|
static std::jthread receiverThread;
|
||||||
|
|
||||||
|
ImGui::Header("hex.builtin.tools.tcp_client_server.settings"_lang, true);
|
||||||
|
|
||||||
|
ImGui::BeginDisabled(server.isActive());
|
||||||
|
{
|
||||||
|
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x * 0.2F);
|
||||||
|
ImGui::InputInt("##port", &port, 0, 0);
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
}
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
if (port < 1)
|
||||||
|
port = 1;
|
||||||
|
else if (port > 65535)
|
||||||
|
port = 65535;
|
||||||
|
|
||||||
|
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x * 0.2F);
|
||||||
|
if (server.isActive()) {
|
||||||
|
if (ImGui::IconButton(ICON_VS_DEBUG_DISCONNECT, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarRed))) {
|
||||||
|
server.shutdown();
|
||||||
|
|
||||||
|
receiverThread.request_stop();
|
||||||
|
receiverThread.join();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (ImGui::IconButton(ICON_VS_PLAY, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarGreen))) {
|
||||||
|
receiverThread = std::jthread([](const std::stop_token& stopToken){
|
||||||
|
server = wolv::net::SocketServer(port);
|
||||||
|
|
||||||
|
while (!stopToken.stop_requested()) {
|
||||||
|
server.accept([](wolv::net::SocketHandle, const std::vector<u8> &data) -> std::vector<u8> {
|
||||||
|
std::scoped_lock lock(receiverMutex);
|
||||||
|
|
||||||
|
messages.emplace_back(data.begin(), data.end());
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}, nullptr, true);
|
||||||
|
|
||||||
|
std::this_thread::sleep_for(100ms);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
|
||||||
|
ImGui::Header("hex.builtin.tools.tcp_client_server.messages"_lang);
|
||||||
|
|
||||||
|
if (ImGui::BeginTable("##response", 1, ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders, ImVec2(0, 200_scaled))) {
|
||||||
|
{
|
||||||
|
std::scoped_lock lock(receiverMutex);
|
||||||
|
u32 index = 0;
|
||||||
|
for (const auto &message : messages) {
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::PushID(index);
|
||||||
|
ImGui::TextFormattedSelectable("{}", message.c_str());
|
||||||
|
ImGui::PopID();
|
||||||
|
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndTabItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndTabBar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
95
plugins/builtin/source/content/tools/wiki_explainer.cpp
Normal file
95
plugins/builtin/source/content/tools/wiki_explainer.cpp
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
#include <hex/api/content_registry.hpp>
|
||||||
|
|
||||||
|
#include <hex/helpers/http_requests.hpp>
|
||||||
|
#include <hex/api/localization.hpp>
|
||||||
|
|
||||||
|
#include <hex/ui/view.hpp>
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
#include <llvm/Demangle/Demangle.h>
|
||||||
|
#include <content/tools_entries.hpp>
|
||||||
|
|
||||||
|
#include <imgui.h>
|
||||||
|
|
||||||
|
#include <hex/ui/imgui_imhex_extensions.h>
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
namespace hex::plugin::builtin {
|
||||||
|
namespace impl {
|
||||||
|
|
||||||
|
std::string getWikipediaApiUrl() {
|
||||||
|
std::string setting = ContentRegistry::Settings::read("hex.builtin.setting.interface", "hex.builtin.setting.interface.wiki_explain_language", "en").get<std::string>();
|
||||||
|
return "https://" + setting + ".wikipedia.org/w/api.php?format=json&action=query&prop=extracts&explaintext&redirects=10&formatversion=2";
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawWikiExplainer() {
|
||||||
|
static HttpRequest request("GET", "");
|
||||||
|
|
||||||
|
static std::string resultTitle, resultExtract;
|
||||||
|
static std::future<HttpRequest::Result<std::string>> searchProcess;
|
||||||
|
static bool extendedSearch = false;
|
||||||
|
static std::string searchString;
|
||||||
|
|
||||||
|
ImGui::Header("hex.builtin.tools.wiki_explain.control"_lang, true);
|
||||||
|
|
||||||
|
bool startSearch = ImGui::InputTextIcon("##search", ICON_VS_SYMBOL_KEY, searchString, ImGuiInputTextFlags_EnterReturnsTrue);
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
ImGui::BeginDisabled((searchProcess.valid() && searchProcess.wait_for(0s) != std::future_status::ready) || searchString.empty());
|
||||||
|
startSearch = ImGui::Button("hex.builtin.tools.wiki_explain.search"_lang) || startSearch;
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
|
||||||
|
if (startSearch && !searchString.empty()) {
|
||||||
|
request.setUrl(getWikipediaApiUrl() + "&exintro"s + "&titles="s + request.urlEncode(searchString));
|
||||||
|
searchProcess = request.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Header("hex.builtin.tools.wiki_explain.results"_lang);
|
||||||
|
|
||||||
|
if (ImGui::BeginChild("##summary", ImVec2(0, 300), true)) {
|
||||||
|
if (!resultTitle.empty() && !resultExtract.empty()) {
|
||||||
|
ImGui::HeaderColored(resultTitle.c_str(), ImGui::GetCustomColorVec4(ImGuiCustomCol_Highlight), true);
|
||||||
|
ImGui::TextFormattedWrapped("{}", resultExtract.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndChild();
|
||||||
|
|
||||||
|
if (searchProcess.valid() && searchProcess.wait_for(0s) == std::future_status::ready) {
|
||||||
|
try {
|
||||||
|
auto response = searchProcess.get();
|
||||||
|
if (response.getStatusCode() != 200) throw std::runtime_error("Invalid response");
|
||||||
|
|
||||||
|
auto json = nlohmann::json::parse(response.getData());
|
||||||
|
|
||||||
|
resultTitle = json.at("query").at("pages").at(0).at("title").get<std::string>();
|
||||||
|
resultExtract = json.at("query").at("pages").at(0).at("extract").get<std::string>();
|
||||||
|
|
||||||
|
if (!extendedSearch && resultExtract.ends_with(':')) {
|
||||||
|
extendedSearch = true;
|
||||||
|
|
||||||
|
request.setUrl(getWikipediaApiUrl() + "&titles="s + request.urlEncode(searchString));
|
||||||
|
searchProcess = request.execute();
|
||||||
|
|
||||||
|
resultTitle.clear();
|
||||||
|
resultExtract.clear();
|
||||||
|
searchString.clear();
|
||||||
|
} else {
|
||||||
|
extendedSearch = false;
|
||||||
|
searchString.clear();
|
||||||
|
}
|
||||||
|
} catch (...) {
|
||||||
|
searchString.clear();
|
||||||
|
resultTitle.clear();
|
||||||
|
resultExtract.clear();
|
||||||
|
extendedSearch = false;
|
||||||
|
searchProcess = {};
|
||||||
|
|
||||||
|
resultTitle = "???";
|
||||||
|
resultExtract = "hex.builtin.tools.wiki_explain.invalid_response"_lang.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user