mirror of https://github.com/WerWolv/ImHex.git
Use file mapping instead of of normal file IO
This drastically reduces disk reads and improves performance
This commit is contained in:
parent
206be8b110
commit
5a0f965125
|
@ -1,11 +1,18 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "providers/provider.hpp"
|
#include "providers/provider.hpp"
|
||||||
|
#include "helpers/utils.hpp"
|
||||||
|
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#if defined(OS_WINDOWS)
|
||||||
|
#include <windows.h>
|
||||||
|
#else
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace hex::prv {
|
namespace hex::prv {
|
||||||
|
|
||||||
class FileProvider : public Provider {
|
class FileProvider : public Provider {
|
||||||
|
@ -27,8 +34,15 @@ namespace hex::prv {
|
||||||
std::vector<std::pair<std::string, std::string>> getDataInformation() override;
|
std::vector<std::pair<std::string, std::string>> getDataInformation() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FILE *m_file;
|
#if defined(OS_WINDOWS)
|
||||||
|
HANDLE m_file;
|
||||||
|
HANDLE m_mapping;
|
||||||
|
#else
|
||||||
|
int m_file;
|
||||||
|
#endif
|
||||||
std::string m_path;
|
std::string m_path;
|
||||||
|
void *m_mappedFile;
|
||||||
|
size_t m_fileSize;
|
||||||
|
|
||||||
bool m_fileStatsValid = false;
|
bool m_fileStatsValid = false;
|
||||||
struct stat m_fileStats = { 0 };
|
struct stat m_fileStats = { 0 };
|
||||||
|
|
|
@ -4,46 +4,105 @@
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <sys/fcntl.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#include "helpers/utils.hpp"
|
#include "helpers/utils.hpp"
|
||||||
#include "helpers/project_file_handler.hpp"
|
#include "helpers/project_file_handler.hpp"
|
||||||
|
|
||||||
|
|
||||||
#ifdef OS_MACOS
|
|
||||||
#define off64_t off_t
|
|
||||||
#define fopen64 fopen
|
|
||||||
#define fseeko64 fseek
|
|
||||||
#define ftello64 ftell
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace hex::prv {
|
namespace hex::prv {
|
||||||
|
|
||||||
FileProvider::FileProvider(std::string_view path) : Provider(), m_path(path) {
|
FileProvider::FileProvider(std::string_view path) : Provider(), m_path(path) {
|
||||||
this->m_fileStatsValid = stat(path.data(), &this->m_fileStats) == 0;
|
this->m_fileStatsValid = stat(path.data(), &this->m_fileStats) == 0;
|
||||||
|
|
||||||
this->m_file = fopen64(path.data(), "r+b");
|
|
||||||
|
|
||||||
this->m_readable = true;
|
this->m_readable = true;
|
||||||
this->m_writable = true;
|
this->m_writable = true;
|
||||||
|
|
||||||
if (this->m_file == nullptr) {
|
#if defined(OS_WINDOWS)
|
||||||
this->m_file = fopen64(path.data(), "rb");
|
LARGE_INTEGER fileSize = { 0 };
|
||||||
|
OFSTRUCT ofStruct;
|
||||||
|
this->m_file = reinterpret_cast<HANDLE>(OpenFile(path.data(), &ofStruct, OF_READ));
|
||||||
|
|
||||||
|
GetFileSizeEx(this->m_file, &fileSize);
|
||||||
|
this->m_fileSize = fileSize.QuadPart;
|
||||||
|
|
||||||
|
this->m_file = reinterpret_cast<HANDLE>(OpenFile(path.data(), &ofStruct, OF_READWRITE));
|
||||||
|
if (this->m_file == nullptr || this->m_file == INVALID_HANDLE_VALUE) {
|
||||||
|
this->m_file = reinterpret_cast<HANDLE>(OpenFile(path.data(), &ofStruct, OF_READ));
|
||||||
this->m_writable = false;
|
this->m_writable = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->m_file != nullptr)
|
ScopeExit fileCleanup([this]{
|
||||||
ProjectFile::setFilePath(path);
|
this->m_readable = false;
|
||||||
|
this->m_file = nullptr;
|
||||||
|
CloseHandle(this->m_file);
|
||||||
|
});
|
||||||
|
if (this->m_file == nullptr || this->m_file == INVALID_HANDLE_VALUE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->m_mapping = CreateFileMapping(this->m_file, nullptr, PAGE_READWRITE, fileSize.HighPart, fileSize.LowPart, path.data());
|
||||||
|
if (this->m_file == nullptr || this->m_file == INVALID_HANDLE_VALUE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScopeExit mappingCleanup([this]{
|
||||||
|
this->m_readable = false;
|
||||||
|
this->m_mapping = nullptr;
|
||||||
|
CloseHandle(this->m_mapping);
|
||||||
|
});
|
||||||
|
|
||||||
|
this->m_mappedFile = MapViewOfFile(this->m_mapping, FILE_MAP_ALL_ACCESS, 0, 0, this->m_fileSize);
|
||||||
|
if (this->m_mappedFile == nullptr) {
|
||||||
|
this->m_readable = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fileCleanup.release();
|
||||||
|
mappingCleanup.release();
|
||||||
|
|
||||||
|
ProjectFile::setFilePath(path);
|
||||||
|
|
||||||
|
#else
|
||||||
|
this->m_file = open(path.data(), O_RDWR);
|
||||||
|
if (this->m_file == -1) {
|
||||||
|
this->m_file = open(path.data(), O_RDONLY);
|
||||||
|
this->m_writable = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->m_file == -1) {
|
||||||
|
this->m_readable = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->m_fileSize = this->m_fileStats.st_size;
|
||||||
|
|
||||||
|
this->m_mappedFile = mmap(nullptr, this->m_fileSize, PROT_READ | PROT_WRITE, MAP_PRIVATE, this->m_file, 0);
|
||||||
|
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
FileProvider::~FileProvider() {
|
FileProvider::~FileProvider() {
|
||||||
|
#if defined(OS_WINDOWS)
|
||||||
|
if (this->m_mappedFile != nullptr)
|
||||||
|
UnmapViewOfFile(this->m_mappedFile);
|
||||||
|
if (this->m_mapping != nullptr)
|
||||||
|
CloseHandle(this->m_mapping);
|
||||||
if (this->m_file != nullptr)
|
if (this->m_file != nullptr)
|
||||||
fclose(this->m_file);
|
CloseHandle(this->m_file);
|
||||||
|
#else
|
||||||
|
munmap(this->m_mappedFile, this->m_fileSize);
|
||||||
|
close(this->m_file);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool FileProvider::isAvailable() {
|
bool FileProvider::isAvailable() {
|
||||||
return this->m_file != nullptr;
|
#if defined(OS_WINDOWS)
|
||||||
|
return this->m_file != nullptr && this->m_mapping != nullptr && this->m_mappedFile != nullptr;
|
||||||
|
#else
|
||||||
|
return this->m_file != -1 && this->m_mappedFile != nullptr;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FileProvider::isReadable() {
|
bool FileProvider::isReadable() {
|
||||||
|
@ -59,12 +118,9 @@ namespace hex::prv {
|
||||||
if ((offset + size) > this->getSize() || buffer == nullptr || size == 0)
|
if ((offset + size) > this->getSize() || buffer == nullptr || size == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
fseeko64(this->m_file, this->getCurrentPage() * PageSize + offset, SEEK_SET);
|
memcpy(buffer, reinterpret_cast<u8*>(this->m_mappedFile) + offset, size);
|
||||||
size_t readSize = fread(buffer, 1, size, this->m_file);
|
|
||||||
|
|
||||||
|
for (u64 i = 0; i < size; i++)
|
||||||
|
|
||||||
for (u64 i = 0; i < readSize; i++)
|
|
||||||
if (this->m_patches.back().contains(offset + i))
|
if (this->m_patches.back().contains(offset + i))
|
||||||
reinterpret_cast<u8*>(buffer)[i] = this->m_patches.back()[offset + i];
|
reinterpret_cast<u8*>(buffer)[i] = this->m_patches.back()[offset + i];
|
||||||
}
|
}
|
||||||
|
@ -83,20 +139,17 @@ namespace hex::prv {
|
||||||
if ((offset + size) > this->getSize() || buffer == nullptr || size == 0)
|
if ((offset + size) > this->getSize() || buffer == nullptr || size == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
fseeko64(this->m_file, this->getCurrentPage() * PageSize + offset, SEEK_SET);
|
memcpy(buffer, reinterpret_cast<u8*>(this->m_mappedFile) + offset, size);
|
||||||
fread(buffer, 1, size, this->m_file);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileProvider::writeRaw(u64 offset, const void *buffer, size_t size) {
|
void FileProvider::writeRaw(u64 offset, const void *buffer, size_t size) {
|
||||||
if (buffer == nullptr || size == 0)
|
if (buffer == nullptr || size == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
fseeko64(this->m_file, offset, SEEK_SET);
|
memcpy(reinterpret_cast<u8*>(this->m_mappedFile) + offset, buffer, size);
|
||||||
fwrite(buffer, 1, size, this->m_file);
|
|
||||||
}
|
}
|
||||||
size_t FileProvider::getActualSize() {
|
size_t FileProvider::getActualSize() {
|
||||||
fseeko64(this->m_file, 0, SEEK_END);
|
return this->m_fileSize;
|
||||||
return ftello64(this->m_file);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::pair<std::string, std::string>> FileProvider::getDataInformation() {
|
std::vector<std::pair<std::string, std::string>> FileProvider::getDataInformation() {
|
||||||
|
|
Loading…
Reference in New Issue