2020-11-21 00:12:58 +01:00
|
|
|
#include "views/view_data_inspector.hpp"
|
|
|
|
|
|
|
|
#include "providers/provider.hpp"
|
2020-11-28 21:55:52 +01:00
|
|
|
#include "helpers/utils.hpp"
|
2020-11-21 00:12:58 +01:00
|
|
|
|
|
|
|
#include <cstring>
|
|
|
|
|
|
|
|
extern int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end);
|
|
|
|
|
|
|
|
namespace hex {
|
|
|
|
|
2020-12-27 15:39:06 +01:00
|
|
|
ViewDataInspector::ViewDataInspector() : View("Data Inspector") {
|
2020-11-28 15:53:11 +01:00
|
|
|
View::subscribeEvent(Events::RegionSelected, [this](const void* userData){
|
|
|
|
Region region = *static_cast<const Region*>(userData);
|
2020-11-21 00:12:58 +01:00
|
|
|
|
2020-12-27 15:39:06 +01:00
|
|
|
auto provider = prv::Provider::getCurrentProvider();
|
|
|
|
|
|
|
|
if (provider == nullptr) {
|
2020-12-21 11:23:57 +01:00
|
|
|
this->m_validBytes = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (region.address == (size_t)-1) {
|
|
|
|
this->m_validBytes = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-12-27 15:39:06 +01:00
|
|
|
this->m_validBytes = std::min(u64(provider->getSize() - region.address), u64(sizeof(PreviewData)));
|
2020-11-21 00:12:58 +01:00
|
|
|
std::memset(&this->m_previewData, 0x00, sizeof(PreviewData));
|
2020-12-27 15:39:06 +01:00
|
|
|
provider->read(region.address, &this->m_previewData, this->m_validBytes);
|
2020-11-21 00:12:58 +01:00
|
|
|
|
|
|
|
this->m_shouldInvalidate = true;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
ViewDataInspector::~ViewDataInspector() {
|
2020-11-28 15:53:11 +01:00
|
|
|
View::unsubscribeEvent(Events::RegionSelected);
|
2020-11-21 00:12:58 +01:00
|
|
|
}
|
|
|
|
|
2020-12-22 18:10:01 +01:00
|
|
|
void ViewDataInspector::drawContent() {
|
2020-11-21 00:12:58 +01:00
|
|
|
if (this->m_shouldInvalidate) {
|
|
|
|
this->m_shouldInvalidate = false;
|
|
|
|
|
|
|
|
this->m_cachedData.clear();
|
|
|
|
|
|
|
|
{
|
|
|
|
std::string binary;
|
|
|
|
for (u8 i = 0; i < 8; i++)
|
|
|
|
binary += ((this->m_previewData.unsigned8 << i) & 0x80) == 0 ? '0' : '1';
|
2020-12-21 11:23:57 +01:00
|
|
|
this->m_cachedData.emplace_back("Binary (8 bit)", binary, sizeof(u8));
|
2020-11-21 00:12:58 +01:00
|
|
|
}
|
|
|
|
|
2020-12-21 11:23:57 +01:00
|
|
|
this->m_cachedData.emplace_back("uint8_t", hex::format("%u", hex::changeEndianess(this->m_previewData.unsigned8, this->m_endianess)), sizeof(u8));
|
|
|
|
this->m_cachedData.emplace_back("int8_t", hex::format("%d", hex::changeEndianess(this->m_previewData.signed8, this->m_endianess)), sizeof(s8));
|
|
|
|
this->m_cachedData.emplace_back("uint16_t", hex::format("%u", hex::changeEndianess(this->m_previewData.unsigned16, this->m_endianess)), sizeof(u16));
|
|
|
|
this->m_cachedData.emplace_back("int16_t", hex::format("%d", hex::changeEndianess(this->m_previewData.signed16, this->m_endianess)), sizeof(s16));
|
|
|
|
this->m_cachedData.emplace_back("uint32_t", hex::format("%lu", hex::changeEndianess(this->m_previewData.unsigned32, this->m_endianess)), sizeof(u32));
|
|
|
|
this->m_cachedData.emplace_back("int32_t", hex::format("%ld", hex::changeEndianess(this->m_previewData.signed32, this->m_endianess)), sizeof(s32));
|
|
|
|
this->m_cachedData.emplace_back("uint64_t", hex::format("%llu", hex::changeEndianess(this->m_previewData.unsigned64, this->m_endianess)), sizeof(u64));
|
|
|
|
this->m_cachedData.emplace_back("int64_t", hex::format("%lld", hex::changeEndianess(this->m_previewData.signed64, this->m_endianess)), sizeof(s64));
|
|
|
|
|
|
|
|
this->m_cachedData.emplace_back("ASCII Character", hex::format("'%s'", makePrintable(this->m_previewData.ansiChar).c_str()), sizeof(char));
|
|
|
|
this->m_cachedData.emplace_back("Wide Character", hex::format("'%lc'", this->m_previewData.wideChar == 0 ? '\x01' : hex::changeEndianess(this->m_previewData.wideChar, this->m_endianess)), sizeof(wchar_t));
|
2020-11-21 00:12:58 +01:00
|
|
|
{
|
|
|
|
char buffer[5] = { 0 };
|
2020-11-22 15:32:37 +01:00
|
|
|
char codepointString[5] = { 0 };
|
|
|
|
u32 codepoint = 0;
|
|
|
|
|
2020-11-21 00:12:58 +01:00
|
|
|
std::memcpy(buffer, &this->m_previewData.utf8Char, 4);
|
2020-11-22 16:22:23 +01:00
|
|
|
u8 codepointSize = ImTextCharFromUtf8(&codepoint, buffer, buffer + 4);
|
2020-11-22 15:32:37 +01:00
|
|
|
|
2020-11-22 16:22:23 +01:00
|
|
|
std::memcpy(codepointString, &codepoint, std::min(codepointSize, u8(4)));
|
2020-12-21 11:23:57 +01:00
|
|
|
this->m_cachedData.emplace_back("UTF-8 code point", hex::format("'%s' (U+%04lx)", codepoint == 0xFFFD ? "Invalid" : codepointString, codepoint), sizeof(char8_t));
|
2020-11-21 00:12:58 +01:00
|
|
|
}
|
|
|
|
|
2020-12-21 11:23:57 +01:00
|
|
|
this->m_cachedData.emplace_back("float (32 bit)", hex::format("%e", hex::changeEndianess(this->m_previewData.float32, this->m_endianess)), sizeof(float));
|
|
|
|
this->m_cachedData.emplace_back("double (64 bit)", hex::format("%e", hex::changeEndianess(this->m_previewData.float64, this->m_endianess)), sizeof(double));
|
2020-11-21 00:12:58 +01:00
|
|
|
|
2020-12-21 12:38:30 +01:00
|
|
|
#if defined(OS_WINDOWS) && defined(ARCH_64_BIT)
|
2020-11-21 00:12:58 +01:00
|
|
|
{
|
2020-11-22 15:32:37 +01:00
|
|
|
auto endianAdjustedTime = hex::changeEndianess(this->m_previewData.time32, this->m_endianess);
|
|
|
|
std::tm * ptm = _localtime32(&endianAdjustedTime);
|
2020-11-21 00:12:58 +01:00
|
|
|
char buffer[32];
|
2020-11-23 00:20:29 +01:00
|
|
|
if (ptm != nullptr && std::strftime(buffer, 32, "%a, %d.%m.%Y %H:%M:%S", ptm))
|
2020-12-21 11:23:57 +01:00
|
|
|
this->m_cachedData.emplace_back("__time32_t", buffer, sizeof(__time32_t));
|
2020-11-21 00:12:58 +01:00
|
|
|
else
|
2020-12-21 11:23:57 +01:00
|
|
|
this->m_cachedData.emplace_back("__time32_t", "Invalid", sizeof(__time32_t));
|
2020-11-21 00:12:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2020-11-22 15:32:37 +01:00
|
|
|
auto endianAdjustedTime = hex::changeEndianess(this->m_previewData.time64, this->m_endianess);
|
|
|
|
std::tm * ptm = _localtime64(&endianAdjustedTime);
|
2020-11-21 00:12:58 +01:00
|
|
|
char buffer[64];
|
2020-11-23 00:20:29 +01:00
|
|
|
if (ptm != nullptr && std::strftime(buffer, 64, "%a, %d.%m.%Y %H:%M:%S", ptm) != 0)
|
2020-12-21 11:23:57 +01:00
|
|
|
this->m_cachedData.emplace_back("__time64_t", buffer, sizeof(__time64_t));
|
2020-11-21 00:12:58 +01:00
|
|
|
else
|
2020-12-21 11:23:57 +01:00
|
|
|
this->m_cachedData.emplace_back("__time64_t", "Invalid", sizeof(__time64_t));
|
2020-11-21 00:12:58 +01:00
|
|
|
}
|
2020-11-21 00:36:38 +01:00
|
|
|
#else
|
|
|
|
{
|
2020-11-22 15:32:37 +01:00
|
|
|
auto endianAdjustedTime = hex::changeEndianess(this->m_previewData.time, this->m_endianess);
|
|
|
|
std::tm * ptm = localtime(&endianAdjustedTime);
|
2020-11-21 00:36:38 +01:00
|
|
|
char buffer[64];
|
2020-11-23 03:00:17 +01:00
|
|
|
if (ptm != nullptr && std::strftime(buffer, 64, "%a, %d.%m.%Y %H:%M:%S", ptm) != 0)
|
2020-12-21 11:23:57 +01:00
|
|
|
this->m_cachedData.emplace_back("time_t", buffer, sizeof(time_t));
|
2020-11-21 00:36:38 +01:00
|
|
|
else
|
2020-12-21 11:23:57 +01:00
|
|
|
this->m_cachedData.emplace_back("time_t", "Invalid", sizeof(time_t));
|
2020-11-21 00:36:38 +01:00
|
|
|
}
|
|
|
|
#endif
|
2020-11-21 00:12:58 +01:00
|
|
|
|
2020-12-05 11:00:56 +01:00
|
|
|
this->m_cachedData.emplace_back("GUID", hex::format("%s{%08lX-%04hX-%04hX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX}",
|
2020-12-21 12:38:30 +01:00
|
|
|
(this->m_previewData.guid.data3 >> 12) <= 5 && ((this->m_previewData.guid.data4[0] >> 4) >= 8 || (this->m_previewData.guid.data4[0] >> 4) == 0) ? "" : "Invalid ",
|
2020-11-22 15:32:37 +01:00
|
|
|
hex::changeEndianess(this->m_previewData.guid.data1, this->m_endianess),
|
|
|
|
hex::changeEndianess(this->m_previewData.guid.data2, this->m_endianess),
|
|
|
|
hex::changeEndianess(this->m_previewData.guid.data3, this->m_endianess),
|
2020-11-21 00:12:58 +01:00
|
|
|
this->m_previewData.guid.data4[0], this->m_previewData.guid.data4[1], this->m_previewData.guid.data4[2], this->m_previewData.guid.data4[3],
|
2020-12-21 11:23:57 +01:00
|
|
|
this->m_previewData.guid.data4[4], this->m_previewData.guid.data4[5], this->m_previewData.guid.data4[6], this->m_previewData.guid.data4[7]),
|
|
|
|
sizeof(GUID));
|
2020-11-21 00:12:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-11-23 23:57:19 +01:00
|
|
|
if (ImGui::Begin("Data Inspector", &this->getWindowOpenState(), ImGuiWindowFlags_NoCollapse)) {
|
2020-12-27 15:39:06 +01:00
|
|
|
auto provider = prv::Provider::getCurrentProvider();
|
|
|
|
|
|
|
|
if (provider != nullptr && provider->isReadable()) {
|
2020-11-22 15:32:37 +01:00
|
|
|
if (ImGui::BeginChild("##scrolling", ImVec2(0, ImGui::GetWindowHeight() - 60))) {
|
2020-11-22 20:41:54 +01:00
|
|
|
if (ImGui::BeginTable("##datainspector", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoBordersInBody)) {
|
2020-11-21 00:12:58 +01:00
|
|
|
ImGui::TableSetupColumn("Name");
|
|
|
|
ImGui::TableSetupColumn("Value");
|
|
|
|
|
|
|
|
ImGui::TableHeadersRow();
|
2020-11-22 20:41:54 +01:00
|
|
|
|
2020-12-21 11:23:57 +01:00
|
|
|
for (const auto &[name, value, size] : this->m_cachedData) {
|
|
|
|
if (this->m_validBytes < size) continue;
|
|
|
|
|
2020-11-21 00:12:58 +01:00
|
|
|
ImGui::TableNextRow();
|
|
|
|
ImGui::TableNextColumn();
|
|
|
|
ImGui::TextUnformatted(name.c_str());
|
|
|
|
ImGui::TableNextColumn();
|
|
|
|
ImGui::TextUnformatted(value.c_str());
|
|
|
|
}
|
|
|
|
|
2020-12-21 11:23:57 +01:00
|
|
|
if (this->m_validBytes >= 4) {
|
2020-11-21 00:12:58 +01:00
|
|
|
ImGui::TableNextRow();
|
|
|
|
ImGui::TableNextColumn();
|
|
|
|
ImGui::TextUnformatted("RGBA Color");
|
|
|
|
ImGui::TableNextColumn();
|
2020-11-22 15:32:37 +01:00
|
|
|
ImGui::ColorButton("##nolabel", ImColor(hex::changeEndianess(this->m_previewData.unsigned32, this->m_endianess)),
|
2020-11-21 00:12:58 +01:00
|
|
|
ImGuiColorEditFlags_None, ImVec2(ImGui::GetColumnWidth(), 15));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ImGui::EndTable();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ImGui::EndChild();
|
2020-11-22 15:32:37 +01:00
|
|
|
|
|
|
|
if (ImGui::RadioButton("Little Endian", this->m_endianess == std::endian::little)) {
|
|
|
|
this->m_endianess = std::endian::little;
|
|
|
|
this->m_shouldInvalidate = true;
|
|
|
|
}
|
|
|
|
ImGui::SameLine();
|
|
|
|
if (ImGui::RadioButton("Big Endian", this->m_endianess == std::endian::big)) {
|
|
|
|
this->m_endianess = std::endian::big;
|
|
|
|
this->m_shouldInvalidate = true;
|
|
|
|
}
|
2020-11-21 00:12:58 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ImGui::End();
|
|
|
|
}
|
|
|
|
|
2020-12-22 18:10:01 +01:00
|
|
|
void ViewDataInspector::drawMenu() {
|
2020-11-23 23:57:19 +01:00
|
|
|
|
2020-11-21 00:12:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|