1
0
mirror of synced 2024-11-12 02:00:52 +01:00

impr: Load small files into memory, open larger files as read-only by default

#841, #1585
This commit is contained in:
WerWolv 2024-03-10 14:31:39 +01:00
parent f050c69ccd
commit 45a3bdffe0
13 changed files with 127 additions and 132 deletions

@ -1 +1 @@
Subproject commit 7806c1939d5aa6c9af794e4b2ff9116bb89d54d8
Subproject commit 8698c778c02b0e29cf681f7a3d65e020fd26a643

View File

@ -35,8 +35,6 @@ namespace hex::prv {
[[nodiscard]] u64 getActualSize() const override { return m_data.size(); }
void resizeRaw(u64 newSize) override;
void insertRaw(u64 offset, u64 size) override;
void removeRaw(u64 offset, u64 size) override;
[[nodiscard]] std::string getName() const override { return m_name; }

View File

@ -166,8 +166,8 @@ namespace hex::prv {
void remove(u64 offset, u64 size);
virtual void resizeRaw(u64 newSize) { hex::unused(newSize); }
virtual void insertRaw(u64 offset, u64 size) { hex::unused(offset, size); }
virtual void removeRaw(u64 offset, u64 size) { hex::unused(offset, size); }
virtual void insertRaw(u64 offset, u64 size);
virtual void removeRaw(u64 offset, u64 size);
virtual void save();
virtual void saveAs(const std::fs::path &path);

View File

@ -27,6 +27,7 @@ namespace hex::prv::undo {
void groupOperations(u32 count, const UnlocalizedString &unlocalizedName);
void apply(const Stack &otherStack);
void reapply();
[[nodiscard]] bool canUndo() const;
[[nodiscard]] bool canRedo() const;

View File

@ -31,41 +31,4 @@ namespace hex::prv {
m_data.resize(newSize);
}
void MemoryProvider::insertRaw(u64 offset, u64 size) {
auto oldSize = this->getActualSize();
this->resizeRaw(oldSize + size);
std::vector<u8> buffer(0x1000);
const std::vector<u8> zeroBuffer(0x1000);
auto position = oldSize;
while (position > offset) {
const auto readSize = std::min<size_t>(position - offset, buffer.size());
position -= readSize;
this->readRaw(position, buffer.data(), readSize);
this->writeRaw(position, zeroBuffer.data(), readSize);
this->writeRaw(position + size, buffer.data(), readSize);
}
}
void MemoryProvider::removeRaw(u64 offset, u64 size) {
auto oldSize = this->getActualSize();
std::vector<u8> buffer(0x1000);
const auto newSize = oldSize - size;
auto position = offset;
while (position < newSize) {
const auto readSize = std::min<size_t>(newSize - position, buffer.size());
this->readRaw(position + size, buffer.data(), readSize);
this->writeRaw(position, buffer.data(), readSize);
position += readSize;
}
this->resizeRaw(oldSize - size);
}
}

View File

@ -102,6 +102,52 @@ namespace hex::prv {
this->markDirty();
}
void Provider::insertRaw(u64 offset, u64 size) {
auto oldSize = this->getActualSize();
this->resizeRaw(oldSize + size);
std::vector<u8> buffer(0x1000);
const std::vector<u8> zeroBuffer(0x1000);
auto position = oldSize;
while (position > offset) {
const auto readSize = std::min<size_t>(position - offset, buffer.size());
position -= readSize;
this->readRaw(position, buffer.data(), readSize);
this->writeRaw(position, zeroBuffer.data(), readSize);
this->writeRaw(position + size, buffer.data(), readSize);
}
}
void Provider::removeRaw(u64 offset, u64 size) {
if (offset > this->getActualSize() || size == 0)
return;
if ((offset + size) > this->getActualSize())
size = this->getActualSize() - offset;
auto oldSize = this->getActualSize();
std::vector<u8> buffer(0x1000);
const auto newSize = oldSize - size;
auto position = offset;
while (position < newSize) {
const auto readSize = std::min<size_t>(newSize - position, buffer.size());
this->readRaw(position + size, buffer.data(), readSize);
this->writeRaw(position, buffer.data(), readSize);
position += readSize;
}
this->resizeRaw(newSize);
}
void Provider::applyOverlays(u64 offset, void *buffer, size_t size) const {
for (auto &overlay : m_overlays) {
auto overlayOffset = overlay->getAddress();

View File

@ -93,6 +93,13 @@ namespace hex::prv::undo {
}
}
void Stack::reapply() {
for (const auto &operation : m_undoStack) {
operation->redo(m_provider);
}
}
bool Stack::add(std::unique_ptr<Operation> &&operation) {

View File

@ -11,6 +11,8 @@ namespace hex::plugin::builtin {
class FileProvider : public hex::prv::Provider {
public:
constexpr static u64 MaxMemoryFileSize = 128 * 1024 * 1024;
FileProvider() = default;
~FileProvider() override = default;
@ -21,8 +23,6 @@ namespace hex::plugin::builtin {
[[nodiscard]] bool isSavable() const override;
void resizeRaw(u64 newSize) override;
void insertRaw(u64 offset, u64 size) override;
void removeRaw(u64 offset, u64 size) override;
void readRaw(u64 offset, void *buffer, size_t size) override;
void writeRaw(u64 offset, const void *buffer, size_t size) override;
@ -57,12 +57,17 @@ namespace hex::plugin::builtin {
private:
void convertToMemoryFile();
void handleFileChange();
protected:
std::fs::path m_path;
wolv::io::File m_file;
size_t m_fileSize = 0;
wolv::io::ChangeTracker m_changeTracker;
std::vector<u8> m_data;
bool m_loadedIntoMemory = false;
std::optional<struct stat> m_fileStats;
bool m_readable = false, m_writable = false;

View File

@ -24,8 +24,6 @@ namespace hex::plugin::builtin {
[[nodiscard]] u64 getActualSize() const override { return m_data.size(); }
void resizeRaw(u64 newSize) override;
void insertRaw(u64 offset, u64 size) override;
void removeRaw(u64 offset, u64 size) override;
void save() override;

View File

@ -402,6 +402,8 @@
"hex.builtin.provider.file.size": "Size",
"hex.builtin.provider.file.menu.open_file": "Open file externally",
"hex.builtin.provider.file.menu.open_folder": "Open containing folder",
"hex.builtin.provider.file.too_large": "This file is too large to be loaded into memory. Opening it anyways will result in modifications to be written directly to the file. Would you like to open it as Read-Only instead?",
"hex.builtin.provider.file.reload_changes": "The file has been modified by an external source. Do you want to reload it?",
"hex.builtin.provider.gdb": "GDB Server Provider",
"hex.builtin.provider.gdb.ip": "IP Address",
"hex.builtin.provider.gdb.name": "GDB Server <{0}:{1}>",

View File

@ -16,6 +16,7 @@
#include <nlohmann/json.hpp>
#include <cstring>
#include <popups/popup_question.hpp>
#if defined(OS_WINDOWS)
#include <windows.h>
@ -42,25 +43,37 @@ namespace hex::plugin::builtin {
}
bool FileProvider::isSavable() const {
return m_undoRedoStack.canUndo();
return m_loadedIntoMemory;
}
void FileProvider::readRaw(u64 offset, void *buffer, size_t size) {
if (m_fileSize == 0 || (offset + size) > m_fileSize || buffer == nullptr || size == 0)
return;
m_file.readBufferAtomic(offset, static_cast<u8*>(buffer), size);
if (m_loadedIntoMemory)
std::memcpy(buffer, m_data.data() + offset, size);
else
m_file.readBufferAtomic(offset, static_cast<u8*>(buffer), size);
}
void FileProvider::writeRaw(u64 offset, const void *buffer, size_t size) {
if ((offset + size) > this->getActualSize() || buffer == nullptr || size == 0)
return;
m_file.writeBufferAtomic(offset, static_cast<const u8*>(buffer), size);
if (m_loadedIntoMemory)
std::memcpy(m_data.data() + offset, buffer, size);
else
m_file.writeBufferAtomic(offset, static_cast<const u8*>(buffer), size);
}
void FileProvider::save() {
m_file.flush();
if (m_loadedIntoMemory) {
m_file.open();
m_file.writeVectorAtomic(0x00, m_data);
m_file.setSize(m_data.size());
} else {
m_file.flush();
}
#if defined(OS_WINDOWS)
FILETIME ft;
@ -75,6 +88,9 @@ namespace hex::plugin::builtin {
}
#endif
if (m_loadedIntoMemory)
m_file.close();
Provider::save();
}
@ -86,54 +102,14 @@ namespace hex::plugin::builtin {
}
void FileProvider::resizeRaw(u64 newSize) {
m_file.setSize(newSize);
if (m_loadedIntoMemory)
m_data.resize(newSize);
else
m_file.setSize(newSize);
m_fileSize = newSize;
}
void FileProvider::insertRaw(u64 offset, u64 size) {
auto oldSize = this->getActualSize();
this->resizeRaw(oldSize + size);
std::vector<u8> buffer(0x1000);
const std::vector<u8> zeroBuffer(0x1000);
auto position = oldSize;
while (position > offset) {
const auto readSize = std::min<size_t>(position - offset, buffer.size());
position -= readSize;
this->readRaw(position, buffer.data(), readSize);
this->writeRaw(position, zeroBuffer.data(), readSize);
this->writeRaw(position + size, buffer.data(), readSize);
}
}
void FileProvider::removeRaw(u64 offset, u64 size) {
if (offset > this->getActualSize() || size == 0)
return;
if ((offset + size) > this->getActualSize())
size = this->getActualSize() - offset;
auto oldSize = this->getActualSize();
std::vector<u8> buffer(0x1000);
const auto newSize = oldSize - size;
auto position = offset;
while (position < newSize) {
const auto readSize = std::min<size_t>(newSize - position, buffer.size());
this->readRaw(position + size, buffer.data(), readSize);
this->writeRaw(position, buffer.data(), readSize);
position += readSize;
}
this->resizeRaw(newSize);
}
u64 FileProvider::getActualSize() const {
return m_fileSize;
}
@ -246,12 +222,36 @@ namespace hex::plugin::builtin {
}
}
if (m_writable) {
if (m_fileSize < MaxMemoryFileSize && !m_writable) {
m_data = m_file.readVectorAtomic(0x00, m_fileSize);
if (!m_data.empty()) {
m_changeTracker = wolv::io::ChangeTracker(m_file);
m_changeTracker.startTracking(std::bind_front(FileProvider::handleFileChange, this));
m_file.close();
m_loadedIntoMemory = true;
}
} else {
m_writable = false;
ui::PopupQuestion::open("hex.builtin.provider.file.too_large"_lang,
[this] {
m_writable = false;
},
[this] {
m_writable = true;
RequestUpdateWindowTitle::post();
});
}
}
return true;
}
void FileProvider::close() {
m_file.close();
m_data.clear();
s_openedFiles.erase(this);
m_changeTracker.stopTracking();
}
void FileProvider::loadSettings(const nlohmann::json &settings) {
@ -332,4 +332,14 @@ namespace hex::plugin::builtin {
}
}
void FileProvider::handleFileChange() {
ui::PopupQuestion::open("hex.builtin.provider.file.reload_changes"_lang, [this] {
this->close();
(void)this->open();
getUndoStack().reapply();
},
[]{});
}
}

View File

@ -69,43 +69,6 @@ namespace hex::plugin::builtin {
m_data.resize(newSize);
}
void MemoryFileProvider::insertRaw(u64 offset, u64 size) {
auto oldSize = this->getActualSize();
this->resizeRaw(oldSize + size);
std::vector<u8> buffer(0x1000);
const std::vector<u8> zeroBuffer(0x1000);
auto position = oldSize;
while (position > offset) {
const auto readSize = std::min<size_t>(position - offset, buffer.size());
position -= readSize;
this->readRaw(position, buffer.data(), readSize);
this->writeRaw(position, zeroBuffer.data(), readSize);
this->writeRaw(position + size, buffer.data(), readSize);
}
}
void MemoryFileProvider::removeRaw(u64 offset, u64 size) {
auto oldSize = this->getActualSize();
std::vector<u8> buffer(0x1000);
const auto newSize = oldSize - size;
auto position = offset;
while (position < newSize) {
const auto readSize = std::min<size_t>(newSize - position, buffer.size());
this->readRaw(position + size, buffer.data(), readSize);
this->writeRaw(position, buffer.data(), readSize);
position += readSize;
}
this->resizeRaw(oldSize - size);
}
[[nodiscard]] std::string MemoryFileProvider::getName() const {
if (m_name.empty())
return Lang("hex.builtin.provider.mem_file.unsaved");

View File

@ -50,6 +50,8 @@ namespace hex::plugin::builtin {
return std::nullopt;
auto provider = ImHexApi::Provider::get();
if (!provider->isSavable())
return std::nullopt;
offset -= provider->getBaseAddress();