diff --git a/common/FileSystem.cpp b/common/FileSystem.cpp index c80274a0ad..24eddeb3b8 100644 --- a/common/FileSystem.cpp +++ b/common/FileSystem.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #include #endif @@ -1264,6 +1265,71 @@ size_t FileSystem::ReadFileWithPartialProgress(std::FILE* fp, void* dst, size_t return done; } +#ifdef _WIN32 +static std::span MapBinaryFileForRead(HANDLE handle) +{ + LARGE_INTEGER size; + if (!GetFileSizeEx(handle, &size) || size.QuadPart == 0) + return {}; + HANDLE mapping = CreateFileMappingW(handle, nullptr, PAGE_READONLY, size.HighPart, size.LowPart, nullptr); + if (!mapping) + return {}; + void* ptr = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0); + CloseHandle(mapping); + return {static_cast(ptr), static_cast(size.QuadPart)}; +} +#else +static std::span MapBinaryFileForRead(int fd) +{ + struct stat s; + if (0 != fstat(fd, &s) || s.st_size == 0) + return {}; + size_t size = static_cast(s.st_size); + void* ptr = mmap(nullptr, size, PROT_READ, MAP_FILE | MAP_SHARED, fd, 0); + if (ptr == MAP_FAILED) + return {}; + return {static_cast(ptr), size}; +} +#endif + +std::span FileSystem::MapBinaryFileForRead(const char* path) +{ +#ifdef _WIN32 + const std::wstring wpath = GetWin32Path(path); + HANDLE handle = CreateFileW(wpath.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr); + if (handle == INVALID_HANDLE_VALUE) + return {}; + std::span result = ::MapBinaryFileForRead(handle); + CloseHandle(handle); + return result; +#else + int fd = open(path, O_RDONLY); + if (fd <= 0) + return {}; + std::span result = ::MapBinaryFileForRead(fd); + close(fd); + return result; +#endif +} + +std::span FileSystem::MapBinaryFileForRead(std::FILE* fp) +{ +#ifdef _WIN32 + return ::MapBinaryFileForRead(reinterpret_cast(_get_osfhandle(_fileno(fp)))); +#else + return ::MapBinaryFileForRead(fileno(fp)); +#endif +} + +void FileSystem::UnmapFile(std::span file) +{ +#ifdef _WIN32 + UnmapViewOfFile(const_cast(file.data())); +#else + munmap(const_cast(file.data()), file.size()); +#endif +} + bool FileSystem::EnsureDirectoryExists(const char* path, bool recursive, Error* error) { if (FileSystem::DirectoryExists(path)) diff --git a/common/FileSystem.h b/common/FileSystem.h index a82cd0f189..7003135e53 100644 --- a/common/FileSystem.h +++ b/common/FileSystem.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -146,6 +147,9 @@ namespace FileSystem Error* error = nullptr, size_t chunk_size = 16 * 1024 * 1024); size_t ReadFileWithPartialProgress(std::FILE* fp, void* dst, size_t length, ProgressCallback* progress, int startPercent, int endPercent, Error* error = nullptr, size_t chunk_size = 16 * 1024 * 1024); + std::span MapBinaryFileForRead(const char* filename); + std::span MapBinaryFileForRead(std::FILE* fp); + void UnmapFile(std::span file); /// creates a directory in the local filesystem /// if the directory already exists, the return value will be true.