Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SDL_MemoryMapFile implementation #10960

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions include/SDL3/SDL_filesystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,62 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetPathInfo(const char *path, SDL_PathInfo
*/
extern SDL_DECLSPEC char ** SDLCALL SDL_GlobDirectory(const char *path, const char *pattern, SDL_GlobFlags flags, int *count);

/**
* The memory mapped file structure.
*
* This operates an opaque handle.
*
* \since This struct is available since SDL 3.0.0.
*/
typedef struct SDL_MemoryMappedFile SDL_MemoryMappedFile;

/**
* Memory map all the data from a file path.
*
* The data will not be loaded into the memory right away, but the
* operating system will create memory region where you can read from.
* Every read from that memory region will cause the operating system
* to load that specific part from the file to RAM and cache it there.
*
* You have to unmap the file.
*
* \param file the path to read all available data from.
* \param offset the absolute offset of the file where the mapping
* should start.
* \returns a pointer to a new SDL_MemoryMappedFile structure or NULL on
* failure; call SDL_GetError() for more information.
*
* \since This function is available since SDL 3.0.0.
*
*/
extern SDL_DECLSPEC SDL_MemoryMappedFile * SDLCALL SDL_MemoryMapFile(const char *file, size_t offset);

/**
* Unmap a memory mapped file.
*
* This will unmap a previously mapped memory file.
*
* \param mmfile a pointer to SDL_MemoryMappedFile
* \returns true when the operation was successful or false on failure;
* call SDL_GetError() for more information.
*
* \since This function is available since SDL 3.0.0.
*/
extern SDL_DECLSPEC bool SDLCALL SDL_UnmapMemoryFile(SDL_MemoryMappedFile *mmfile);

/**
* Get the data and size from a memory mapped file.
*
* This will return a pointer to the memory mapped file content.
*
* \param mmfile a pointer to SDL_MemoryMappedFile
* \param datasize if not NULL, will store the number of bytes mapped
* \returns the data or NULL on failure; call SDL_GetError() for more information.
*
* \since This function is available since SDL 3.0.0.
*/
extern SDL_DECLSPEC void * SDLCALL SDL_GetMemoryMappedData(const SDL_MemoryMappedFile *mmfile, size_t *datasize);

/* Ends C function definitions when using C++ */
#ifdef __cplusplus
}
Expand Down
26 changes: 26 additions & 0 deletions src/filesystem/SDL_filesystem.c
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,32 @@ char *SDL_GetPrefPath(const char *org, const char *app)
}


SDL_MemoryMappedFile * SDL_MemoryMapFile(const char *file, size_t offset) {
if (file == NULL) {
SDL_InvalidParamError("file");
return NULL;
}
return SDL_SYS_MemoryMapFile(file, offset);
}


bool SDL_UnmapMemoryFile(SDL_MemoryMappedFile *mmfile) {
if (mmfile == NULL) {
return SDL_InvalidParamError("mmfile");
}
return SDL_SYS_UnmapMemoryFile(mmfile);
}


void * SDL_GetMemoryMappedData(const SDL_MemoryMappedFile *mmfile, size_t *datasize) {
if (mmfile == NULL) {
SDL_InvalidParamError("mmfile");
return NULL;
}
return SDL_SYS_GetMemoryMappedData(mmfile, datasize);
}


void SDL_InitFilesystem(void)
{
}
Expand Down
4 changes: 4 additions & 0 deletions src/filesystem/SDL_sysfilesystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ extern bool SDL_SYS_CopyFile(const char *oldpath, const char *newpath);
extern bool SDL_SYS_CreateDirectory(const char *path);
extern bool SDL_SYS_GetPathInfo(const char *path, SDL_PathInfo *info);

extern SDL_MemoryMappedFile *SDL_SYS_MemoryMapFile(const char *file, size_t offset);
extern bool SDL_SYS_UnmapMemoryFile(SDL_MemoryMappedFile *mmfile);
extern void *SDL_SYS_GetMemoryMappedData(const SDL_MemoryMappedFile *mmfile, size_t *datasize);

typedef bool (*SDL_GlobEnumeratorFunc)(const char *path, SDL_EnumerateDirectoryCallback cb, void *cbuserdata, void *userdata);
typedef bool (*SDL_GlobGetPathInfoFunc)(const char *path, SDL_PathInfo *info, void *userdata);
extern char **SDL_InternalGlobDirectory(const char *path, const char *pattern, SDL_GlobFlags flags, int *count, SDL_GlobEnumeratorFunc enumerator, SDL_GlobGetPathInfoFunc getpathinfo, void *userdata);
Expand Down
19 changes: 19 additions & 0 deletions src/filesystem/dummy/SDL_sysfsops.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,24 @@ bool SDL_SYS_GetPathInfo(const char *path, SDL_PathInfo *info)
return SDL_Unsupported();
}

struct SDL_MemoryMappedFile {};

SDL_MemoryMappedFile *SDL_SYS_MemoryMapFile(const char *file, size_t offset) {
(void)file; (void)offset;
SDL_Unsupported();
return NULL;
}

bool SDL_SYS_UnmapMemoryFile(SDL_MemoryMappedFile *mmfile) {
(void)mmfile;
return SDL_Unsupported();
}

void *SDL_SYS_GetMemoryMappedData(const SDL_MemoryMappedFile *mmfile, size_t *datasize) {
(void)mmfile; (void)datasize;
SDL_Unsupported();
return NULL;
}

#endif // SDL_FSOPS_DUMMY

66 changes: 66 additions & 0 deletions src/filesystem/posix/SDL_sysfsops.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@
#include <errno.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>

bool SDL_SYS_EnumerateDirectory(const char *path, const char *dirname, SDL_EnumerateDirectoryCallback cb, void *userdata)
{
Expand Down Expand Up @@ -186,5 +189,68 @@ bool SDL_SYS_GetPathInfo(const char *path, SDL_PathInfo *info)
return true;
}

/* define the internal SDL_MemoryMappedFile structure */
struct SDL_MemoryMappedFile {
void *addr;
size_t size;
};

SDL_MemoryMappedFile *SDL_SYS_MemoryMapFile(const char *file, size_t offset) {
struct stat statbuf;
SDL_MemoryMappedFile *mmfile;

const int fd = open(file, O_RDONLY);
if (fd < 0) {
SDL_SetError("Can't open file: %s", strerror(errno));
return NULL;
}
if (fstat(fd, &statbuf)) {
close(fd);
SDL_SetError("Can't stat: %s", strerror(errno));
return NULL;
}
if (offset >= statbuf.st_size) {
close(fd);
SDL_SetError("Can't use bigger offset");
return NULL;
}
if ((mmfile = SDL_malloc(sizeof(SDL_MemoryMappedFile))) == NULL) {
close(fd);
SDL_SetError("Can't allocate SDL_MemoryMappedFile");
return NULL;
}
mmfile->size = statbuf.st_size - offset;
if ((mmfile->addr = mmap(NULL, mmfile->size, PROT_READ, MAP_PRIVATE, fd, offset)) == NULL) {
close(fd);
SDL_free(mmfile);
SDL_SetError("Can't mmap: %s", strerror(errno));
return NULL;
}
close(fd); /* file descriptor can be closed after mapping the file */
return mmfile;
}

bool SDL_SYS_UnmapMemoryFile(SDL_MemoryMappedFile *mmfile) {
if (mmfile->addr == NULL) {
return SDL_SetError("Invalid memory mapped file");
}
if (munmap(mmfile->addr, mmfile->size)) {
return SDL_SetError("Can't munmap: %s", strerror(errno));
}
SDL_free(mmfile);
return true;
}

void * SDL_SYS_GetMemoryMappedData(const SDL_MemoryMappedFile *mmfile, size_t *datasize) {
if ((mmfile == NULL) || (mmfile->addr == NULL)) {
SDL_SetError("Invalid memory mapped file");
return NULL;
}
if (datasize != NULL) {
*datasize = mmfile->size;
}
return mmfile->addr;
}

#endif // SDL_FSOPS_POSIX

72 changes: 72 additions & 0 deletions src/filesystem/windows/SDL_sysfsops.c
Original file line number Diff line number Diff line change
Expand Up @@ -207,5 +207,77 @@ bool SDL_SYS_GetPathInfo(const char *path, SDL_PathInfo *info)
return true;
}

/* define the internal SDL_MemoryMappedFile structure */
struct SDL_MemoryMappedFile {
void *addr;
size_t size;
HANDLE file_handle, map_handle;
};

SDL_MemoryMappedFile *SDL_SYS_MemoryMapFile(const char *file, size_t offset) {
HANDLE fileHandle, mapHandle;
size_t size;
void *addr;
SDL_MemoryMappedFile *mmfile;

file_handle = CreateFile(file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (file_handle == INVALID_HANDLE_VALUE) {
WIN_SetError("Can't open");
return NULL;
}
size = GetFileLength(file_handle);
if (offset >= size) {
CloseHandle(file_handle);
SDL_SetError("Can't use offset");
return NULL;
}
map_handle = CreateFileMapping(file_handle, NULL, PAGE_READONLY, 0, 0, NULL);
if (map_handle == NULL) {
CloseHandle(file_handle);
WIN_SetError("Can't create map");
return NULL;
}
addr = MapViewOfFile(map_handle, FILE_MAP_READ, 0, offset, 0);
if (addr == NULL) {
CloseHandle(map_handle);
CloseHandle(file_handle);
WIN_SetError("Can't crate view");
return NULL;
}
mmfile = SDL_malloc(sizeof(SDL_MemoryMappedFile));
if (mmfile == NULL) {
CloseHandle(map_handle);
CloseHandle(file_handle);
SDL_SetError("Can't allocate SDL_MemoryMappedFile");
return NULL;
}
mmfile->addr = addr;
mmfile->size = size - offset;
mmfile->file_handle = file_handle;
mmfile->map_handle = map_handle;
return mmfile;
}

bool SDL_UnmapMemoryFile(SDL_MemoryMappedFile *mmfile) {
if (mmfile->addr != NULL) {
UnmapViewOfFile(mmfile->addr);
}
if (mmfile->map_handle != NULL) {
CloseHandle(mmfile->map_handle);
}
if (mmfile->file_handle != INVALID_FILE_HANDLE) {
CloseHandle(mmfile->file_handle);
}
SDL_free(mmfile);
return true;
}

void *SDL_GetMemoryMappedData(const SDL_MemoryMappedFile *mmfile, size_t *datasize) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SDL_SYS_GetMemoryMappedData?

if (datasize != NULL) {
*datasize = mmfile->size;
}
return mmfile->addr;
}

#endif // SDL_FSOPS_WINDOWS

Loading