#ifndef NALL_FILEMAP_HPP #define NALL_FILEMAP_HPP #include #include #include #include #include #if defined(_WIN32) #include #else #include #include #include #include #include #endif namespace nall { struct filemap { enum class mode : unsigned { read, write, readwrite, writeread }; explicit operator bool() const { return open(); } bool open() const { return p_open(); } bool open(const string& filename, mode mode_) { return p_open(filename, mode_); } void close() { return p_close(); } unsigned size() const { return p_size; } uint8_t* data() { return p_handle; } const uint8_t* data() const { return p_handle; } filemap() { p_ctor(); } filemap(const string& filename, mode mode_) { p_ctor(); p_open(filename, mode_); } ~filemap() { p_dtor(); } private: uint8_t *p_handle = nullptr; unsigned p_size = 0; #if defined(_WIN32) //============= //MapViewOfFile //============= HANDLE p_filehandle, p_maphandle; bool p_open() const { return p_handle; } bool p_open(const string& filename, mode mode_) { if(file::exists(filename) && file::size(filename) == 0) { p_handle = nullptr; p_size = 0; return true; } int desired_access, creation_disposition, flprotect, map_access; switch(mode_) { default: return false; case mode::read: desired_access = GENERIC_READ; creation_disposition = OPEN_EXISTING; flprotect = PAGE_READONLY; map_access = FILE_MAP_READ; break; case mode::write: //write access requires read access desired_access = GENERIC_WRITE; creation_disposition = CREATE_ALWAYS; flprotect = PAGE_READWRITE; map_access = FILE_MAP_ALL_ACCESS; break; case mode::readwrite: desired_access = GENERIC_READ | GENERIC_WRITE; creation_disposition = OPEN_EXISTING; flprotect = PAGE_READWRITE; map_access = FILE_MAP_ALL_ACCESS; break; case mode::writeread: desired_access = GENERIC_READ | GENERIC_WRITE; creation_disposition = CREATE_NEW; flprotect = PAGE_READWRITE; map_access = FILE_MAP_ALL_ACCESS; break; } p_filehandle = CreateFileW(utf16_t(filename), desired_access, FILE_SHARE_READ, nullptr, creation_disposition, FILE_ATTRIBUTE_NORMAL, nullptr); if(p_filehandle == INVALID_HANDLE_VALUE) return false; p_size = GetFileSize(p_filehandle, nullptr); p_maphandle = CreateFileMapping(p_filehandle, nullptr, flprotect, 0, p_size, nullptr); if(p_maphandle == INVALID_HANDLE_VALUE) { CloseHandle(p_filehandle); p_filehandle = INVALID_HANDLE_VALUE; return false; } p_handle = (uint8_t*)MapViewOfFile(p_maphandle, map_access, 0, 0, p_size); return p_handle; } void p_close() { if(p_handle) { UnmapViewOfFile(p_handle); p_handle = nullptr; } if(p_maphandle != INVALID_HANDLE_VALUE) { CloseHandle(p_maphandle); p_maphandle = INVALID_HANDLE_VALUE; } if(p_filehandle != INVALID_HANDLE_VALUE) { CloseHandle(p_filehandle); p_filehandle = INVALID_HANDLE_VALUE; } } void p_ctor() { p_filehandle = INVALID_HANDLE_VALUE; p_maphandle = INVALID_HANDLE_VALUE; } void p_dtor() { close(); } #else //==== //mmap //==== int p_fd; bool p_open() const { return p_handle; } bool p_open(const string& filename, mode mode_) { if(file::exists(filename) && file::size(filename) == 0) { p_handle = nullptr; p_size = 0; return true; } int open_flags, mmap_flags; switch(mode_) { default: return false; case mode::read: open_flags = O_RDONLY; mmap_flags = PROT_READ; break; case mode::write: open_flags = O_RDWR | O_CREAT; //mmap() requires read access mmap_flags = PROT_WRITE; break; case mode::readwrite: open_flags = O_RDWR; mmap_flags = PROT_READ | PROT_WRITE; break; case mode::writeread: open_flags = O_RDWR | O_CREAT; mmap_flags = PROT_READ | PROT_WRITE; break; } p_fd = ::open(filename, open_flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); if(p_fd < 0) return false; struct stat p_stat; fstat(p_fd, &p_stat); p_size = p_stat.st_size; p_handle = (uint8_t*)mmap(nullptr, p_size, mmap_flags, MAP_SHARED, p_fd, 0); if(p_handle == MAP_FAILED) { p_handle = nullptr; ::close(p_fd); p_fd = -1; return false; } return p_handle; } void p_close() { if(p_handle) { munmap(p_handle, p_size); p_handle = nullptr; } if(p_fd >= 0) { ::close(p_fd); p_fd = -1; } } void p_ctor() { p_fd = -1; } void p_dtor() { p_close(); } #endif }; } #endif