mirror of
https://github.com/libretro/bsnes-libretro.git
synced 2024-11-23 08:59:40 +00:00
4c4e79aa0e
byuu says: Changelog: - moved to GCC 8.2 and C++17 - fixed compilation under FreeBSD 12.0 - don't read beyond the file size in SuperFamicom::Cartridge::loadMemory - add missing I/O cycle HuC6280::instructionImmediate - serialize Mega Drive's Game Genie state - serialize SPC7110::Thread information - enable 30-bit color depth support under the GLX/OpenGL 2.0 driver (doesn't work with OpenGL 3.2 yet) The 30-bit color depth option isn't super useful, but why not? I need to update ruby to detect that the display is actually capable of it before exposing an option that can result in the driver failing to initialize, however.
226 lines
5.2 KiB
C++
226 lines
5.2 KiB
C++
#pragma once
|
|
|
|
#include <nall/file.hpp>
|
|
#include <nall/stdint.hpp>
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#if defined(PLATFORM_WINDOWS)
|
|
#include <nall/windows/utf8.hpp>
|
|
#else
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#endif
|
|
|
|
#if !defined(MAP_NORESERVE)
|
|
//not supported on FreeBSD; flag removed in 11.0
|
|
#define MAP_NORESERVE 0
|
|
#endif
|
|
|
|
namespace nall {
|
|
|
|
struct file_map {
|
|
struct mode { enum : uint { read, write, modify, append }; };
|
|
|
|
file_map(const file_map&) = delete;
|
|
auto operator=(const file_map&) = delete;
|
|
|
|
file_map() = default;
|
|
file_map(file_map&& source) { operator=(move(source)); }
|
|
file_map(const string& filename, uint mode) { open(filename, mode); }
|
|
|
|
~file_map() { close(); }
|
|
|
|
explicit operator bool() const { return _open; }
|
|
auto size() const -> uint64_t { return _size; }
|
|
auto data() -> uint8_t* { return _data; }
|
|
auto data() const -> const uint8_t* { return _data; }
|
|
|
|
//auto operator=(file_map&& source) -> file_map&;
|
|
//auto open(const string& filename, uint mode) -> bool;
|
|
//auto close() -> void;
|
|
|
|
private:
|
|
bool _open = false; //zero-byte files return _data = nullptr, _size = 0
|
|
uint8_t* _data = nullptr;
|
|
uint64_t _size = 0;
|
|
|
|
#if defined(API_WINDOWS)
|
|
|
|
HANDLE _file = INVALID_HANDLE_VALUE;
|
|
HANDLE _map = INVALID_HANDLE_VALUE;
|
|
|
|
public:
|
|
auto operator=(file_map&& source) -> file_map& {
|
|
_open = source._open;
|
|
_data = source._data;
|
|
_size = source._size;
|
|
_file = source._file;
|
|
_map = source._map;
|
|
|
|
source._open = false;
|
|
source._data = nullptr;
|
|
source._size = 0;
|
|
source._file = INVALID_HANDLE_VALUE;
|
|
source._map = INVALID_HANDLE_VALUE;
|
|
|
|
return *this;
|
|
}
|
|
|
|
auto open(const string& filename, uint mode_) -> bool {
|
|
close();
|
|
if(file::exists(filename) && file::size(filename) == 0) return _open = true;
|
|
|
|
int desiredAccess, creationDisposition, protection, mapAccess;
|
|
|
|
switch(mode_) {
|
|
default: return false;
|
|
case mode::read:
|
|
desiredAccess = GENERIC_READ;
|
|
creationDisposition = OPEN_EXISTING;
|
|
protection = PAGE_READONLY;
|
|
mapAccess = FILE_MAP_READ;
|
|
break;
|
|
case mode::write:
|
|
//write access requires read access
|
|
desiredAccess = GENERIC_WRITE;
|
|
creationDisposition = CREATE_ALWAYS;
|
|
protection = PAGE_READWRITE;
|
|
mapAccess = FILE_MAP_ALL_ACCESS;
|
|
break;
|
|
case mode::modify:
|
|
desiredAccess = GENERIC_READ | GENERIC_WRITE;
|
|
creationDisposition = OPEN_EXISTING;
|
|
protection = PAGE_READWRITE;
|
|
mapAccess = FILE_MAP_ALL_ACCESS;
|
|
break;
|
|
case mode::append:
|
|
desiredAccess = GENERIC_READ | GENERIC_WRITE;
|
|
creationDisposition = CREATE_NEW;
|
|
protection = PAGE_READWRITE;
|
|
mapAccess = FILE_MAP_ALL_ACCESS;
|
|
break;
|
|
}
|
|
|
|
_file = CreateFileW(utf16_t(filename), desiredAccess, FILE_SHARE_READ, nullptr,
|
|
creationDisposition, FILE_ATTRIBUTE_NORMAL, nullptr);
|
|
if(_file == INVALID_HANDLE_VALUE) return false;
|
|
|
|
_size = GetFileSize(_file, nullptr);
|
|
|
|
_map = CreateFileMapping(_file, nullptr, protection, 0, _size, nullptr);
|
|
if(_map == INVALID_HANDLE_VALUE) {
|
|
CloseHandle(_file);
|
|
_file = INVALID_HANDLE_VALUE;
|
|
return false;
|
|
}
|
|
|
|
_data = (uint8_t*)MapViewOfFile(_map, mapAccess, 0, 0, _size);
|
|
return _open = true;
|
|
}
|
|
|
|
auto close() -> void {
|
|
if(_data) {
|
|
UnmapViewOfFile(_data);
|
|
_data = nullptr;
|
|
}
|
|
|
|
if(_map != INVALID_HANDLE_VALUE) {
|
|
CloseHandle(_map);
|
|
_map = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
if(_file != INVALID_HANDLE_VALUE) {
|
|
CloseHandle(_file);
|
|
_file = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
_open = false;
|
|
}
|
|
|
|
#else
|
|
|
|
int _fd = -1;
|
|
|
|
public:
|
|
auto operator=(file_map&& source) -> file_map& {
|
|
_open = source._open;
|
|
_data = source._data;
|
|
_size = source._size;
|
|
_fd = source._fd;
|
|
|
|
source._open = false;
|
|
source._data = nullptr;
|
|
source._size = 0;
|
|
source._fd = -1;
|
|
|
|
return *this;
|
|
}
|
|
|
|
auto open(const string& filename, uint mode_) -> bool {
|
|
close();
|
|
if(file::exists(filename) && file::size(filename) == 0) return _open = true;
|
|
|
|
int openFlags = 0;
|
|
int mmapFlags = 0;
|
|
|
|
switch(mode_) {
|
|
default: return false;
|
|
case mode::read:
|
|
openFlags = O_RDONLY;
|
|
mmapFlags = PROT_READ;
|
|
break;
|
|
case mode::write:
|
|
openFlags = O_RDWR | O_CREAT; //mmap() requires read access
|
|
mmapFlags = PROT_WRITE;
|
|
break;
|
|
case mode::modify:
|
|
openFlags = O_RDWR;
|
|
mmapFlags = PROT_READ | PROT_WRITE;
|
|
break;
|
|
case mode::append:
|
|
openFlags = O_RDWR | O_CREAT;
|
|
mmapFlags = PROT_READ | PROT_WRITE;
|
|
break;
|
|
}
|
|
|
|
_fd = ::open(filename, openFlags, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
|
|
if(_fd < 0) return false;
|
|
|
|
struct stat _stat;
|
|
fstat(_fd, &_stat);
|
|
_size = _stat.st_size;
|
|
|
|
_data = (uint8_t*)mmap(nullptr, _size, mmapFlags, MAP_SHARED | MAP_NORESERVE, _fd, 0);
|
|
if(_data == MAP_FAILED) {
|
|
_data = nullptr;
|
|
::close(_fd);
|
|
_fd = -1;
|
|
return false;
|
|
}
|
|
|
|
return _open = true;
|
|
}
|
|
|
|
auto close() -> void {
|
|
if(_data) {
|
|
munmap(_data, _size);
|
|
_data = nullptr;
|
|
}
|
|
|
|
if(_fd >= 0) {
|
|
::close(_fd);
|
|
_fd = -1;
|
|
}
|
|
|
|
_open = false;
|
|
}
|
|
|
|
#endif
|
|
};
|
|
|
|
}
|