From 6c83491116e0a4db4dd8667367f3a86f929ef1b2 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Fri, 13 Sep 2024 14:13:53 -0700
Subject: [PATCH] Added SDL_FlushIO()
Also added SDL_PROP_IOSTREAM_FILE_DESCRIPTOR_NUMBER and refactored the internal API to be able to create SDL_IOStream objects from native file handles.
---
include/SDL3/SDL_iostream.h | 41 +++++-
src/dynapi/SDL_dynapi.sym | 1 +
src/dynapi/SDL_dynapi_overrides.h | 1 +
src/dynapi/SDL_dynapi_procs.h | 1 +
src/file/SDL_iostream.c | 205 +++++++++++++++++++-----------
src/file/SDL_iostream_c.h | 32 +++++
6 files changed, 205 insertions(+), 76 deletions(-)
create mode 100644 src/file/SDL_iostream_c.h
diff --git a/include/SDL3/SDL_iostream.h b/include/SDL3/SDL_iostream.h
index b5cb2f03bdf9d..745e35aae1123 100644
--- a/include/SDL3/SDL_iostream.h
+++ b/include/SDL3/SDL_iostream.h
@@ -133,6 +133,17 @@ typedef struct SDL_IOStreamInterface
*/
size_t (SDLCALL *write)(void *userdata, const void *ptr, size_t size, SDL_IOStatus *status);
+ /**
+ * If the stream is buffering, make sure the data is written out.
+ *
+ * On failure, you should set `*status` to a value from the
+ * SDL_IOStatus enum. You do not have to explicitly set this on
+ * a successful flush.
+ *
+ * \return SDL_TRUE if successful or SDL_FALSE on write error when flushing data.
+ */
+ SDL_bool (SDLCALL *flush)(void *userdata, SDL_IOStatus *status);
+
/**
* Close and free any allocated resources.
*
@@ -152,8 +163,8 @@ typedef struct SDL_IOStreamInterface
* the code using this interface should be updated to handle the old version.
*/
SDL_COMPILE_TIME_ASSERT(SDL_IOStreamInterface_SIZE,
- (sizeof(void *) == 4 && sizeof(SDL_IOStreamInterface) == 24) ||
- (sizeof(void *) == 8 && sizeof(SDL_IOStreamInterface) == 48));
+ (sizeof(void *) == 4 && sizeof(SDL_IOStreamInterface) == 28) ||
+ (sizeof(void *) == 8 && sizeof(SDL_IOStreamInterface) == 56));
/**
* The read/write operation structure.
@@ -233,6 +244,7 @@ typedef struct SDL_IOStream SDL_IOStream;
* than your app, trying to use this pointer will almost certainly result in
* a crash! This is mostly a problem on Windows; make sure you build SDL and
* your app with the same compiler and settings to avoid it.
+ * - `SDL_PROP_IOSTREAM_FILE_DESCRIPTOR_NUMBER`: a file descriptor that this SDL_IOStream is using to access the filesystem.
* - `SDL_PROP_IOSTREAM_ANDROID_AASSET_POINTER`: a pointer, that can be cast
* to an Android NDK `AAsset *`, that this SDL_IOStream is using to access
* the filesystem. If SDL used some other method to access the filesystem,
@@ -247,6 +259,7 @@ typedef struct SDL_IOStream SDL_IOStream;
* \since This function is available since SDL 3.0.0.
*
* \sa SDL_CloseIO
+ * \sa SDL_FlushIO
* \sa SDL_ReadIO
* \sa SDL_SeekIO
* \sa SDL_TellIO
@@ -256,6 +269,7 @@ extern SDL_DECLSPEC SDL_IOStream * SDLCALL SDL_IOFromFile(const char *file, cons
#define SDL_PROP_IOSTREAM_WINDOWS_HANDLE_POINTER "SDL.iostream.windows.handle"
#define SDL_PROP_IOSTREAM_STDIO_FILE_POINTER "SDL.iostream.stdio.file"
+#define SDL_PROP_IOSTREAM_FILE_DESCRIPTOR_NUMBER "SDL.iostream.file_descriptor"
#define SDL_PROP_IOSTREAM_ANDROID_AASSET_POINTER "SDL.iostream.android.aasset"
/**
@@ -282,6 +296,7 @@ extern SDL_DECLSPEC SDL_IOStream * SDLCALL SDL_IOFromFile(const char *file, cons
*
* \sa SDL_IOFromConstMem
* \sa SDL_CloseIO
+ * \sa SDL_FlushIO
* \sa SDL_ReadIO
* \sa SDL_SeekIO
* \sa SDL_TellIO
@@ -465,8 +480,7 @@ extern SDL_DECLSPEC Sint64 SDLCALL SDL_GetIOSize(SDL_IOStream *context);
* negative.
* \param whence any of `SDL_IO_SEEK_SET`, `SDL_IO_SEEK_CUR`,
* `SDL_IO_SEEK_END`.
- * \returns the final offset in the data stream after the seek or a negative
- * error code on failure; call SDL_GetError() for more information.
+ * \returns the final offset in the data stream after the seek or -1 on failure; call SDL_GetError() for more information.
*
* \since This function is available since SDL 3.0.0.
*
@@ -539,6 +553,7 @@ extern SDL_DECLSPEC size_t SDLCALL SDL_ReadIO(SDL_IOStream *context, void *ptr,
* \sa SDL_IOprintf
* \sa SDL_ReadIO
* \sa SDL_SeekIO
+ * \sa SDL_FlushIO
* \sa SDL_GetIOStatus
*/
extern SDL_DECLSPEC size_t SDLCALL SDL_WriteIO(SDL_IOStream *context, const void *ptr, size_t size);
@@ -580,6 +595,22 @@ extern SDL_DECLSPEC size_t SDLCALL SDL_IOprintf(SDL_IOStream *context, SDL_PRINT
*/
extern SDL_DECLSPEC size_t SDLCALL SDL_IOvprintf(SDL_IOStream *context, SDL_PRINTF_FORMAT_STRING const char *fmt, va_list ap) SDL_PRINTF_VARARG_FUNCV(2);
+/**
+ * Flush any buffered data in the stream.
+ *
+ * This function makes sure that any buffered data is written to the stream. Normally this isn't necessary but if the stream is a pipe or socket it guarantees that any pending data is sent.
+ *
+ * \param context SDL_IOStream structure to flush.
+ * \returns SDL_TRUE on success or SDL_FALSE on failure; call SDL_GetError()
+ * for more information.
+ *
+ * \since This function is available since SDL 3.0.0.
+ *
+ * \sa SDL_OpenIO
+ * \sa SDL_WriteIO
+ */
+extern SDL_DECLSPEC SDL_bool SDLCALL SDL_FlushIO(SDL_IOStream *context);
+
/**
* Load all the data from an SDL data stream.
*
@@ -590,7 +621,7 @@ extern SDL_DECLSPEC size_t SDLCALL SDL_IOvprintf(SDL_IOStream *context, SDL_PRIN
* The data should be freed with SDL_free().
*
* \param src the SDL_IOStream to read all available data from.
- * \param datasize if not NULL, will store the number of bytes read.
+ * \param datasize a pointer filled in with the number of bytes read, may be NULL.
* \param closeio if SDL_TRUE, calls SDL_CloseIO() on `src` before returning,
* even in the case of an error.
* \returns the data or NULL on failure; call SDL_GetError() for more
diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym
index 1b5f1a40a3bf5..2b906b96d1161 100644
--- a/src/dynapi/SDL_dynapi.sym
+++ b/src/dynapi/SDL_dynapi.sym
@@ -169,6 +169,7 @@ SDL3_0.0.0 {
SDL_FlushAudioStream;
SDL_FlushEvent;
SDL_FlushEvents;
+ SDL_FlushIO;
SDL_FlushRenderer;
SDL_GDKResumeGPU;
SDL_GDKSuspendComplete;
diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h
index 8bad28dbdee6c..212ccf4de0d29 100644
--- a/src/dynapi/SDL_dynapi_overrides.h
+++ b/src/dynapi/SDL_dynapi_overrides.h
@@ -194,6 +194,7 @@
#define SDL_FlushAudioStream SDL_FlushAudioStream_REAL
#define SDL_FlushEvent SDL_FlushEvent_REAL
#define SDL_FlushEvents SDL_FlushEvents_REAL
+#define SDL_FlushIO SDL_FlushIO_REAL
#define SDL_FlushRenderer SDL_FlushRenderer_REAL
#define SDL_GDKResumeGPU SDL_GDKResumeGPU_REAL
#define SDL_GDKSuspendComplete SDL_GDKSuspendComplete_REAL
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index 250089ab4c216..fad787ac34c32 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -214,6 +214,7 @@ SDL_DYNAPI_PROC(SDL_bool,SDL_FlipSurface,(SDL_Surface *a, SDL_FlipMode b),(a,b),
SDL_DYNAPI_PROC(SDL_bool,SDL_FlushAudioStream,(SDL_AudioStream *a),(a),return)
SDL_DYNAPI_PROC(void,SDL_FlushEvent,(Uint32 a),(a),)
SDL_DYNAPI_PROC(void,SDL_FlushEvents,(Uint32 a, Uint32 b),(a,b),)
+SDL_DYNAPI_PROC(SDL_bool,SDL_FlushIO,(SDL_IOStream *a),(a),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_FlushRenderer,(SDL_Renderer *a),(a),return)
SDL_DYNAPI_PROC(void,SDL_GDKResumeGPU,(SDL_GPUDevice *a),(a),)
SDL_DYNAPI_PROC(void,SDL_GDKSuspendComplete,(void),(),)
diff --git a/src/file/SDL_iostream.c b/src/file/SDL_iostream.c
index e00438bde4e1a..0d9f39fbb055a 100644
--- a/src/file/SDL_iostream.c
+++ b/src/file/SDL_iostream.c
@@ -58,11 +58,12 @@ struct SDL_IOStream
typedef struct IOStreamWindowsData
{
- bool append;
HANDLE h;
void *data;
size_t size;
size_t left;
+ bool append;
+ bool autoclose;
} IOStreamWindowsData;
@@ -73,7 +74,7 @@ typedef struct IOStreamWindowsData
#define READAHEAD_BUFFER_SIZE 1024
-static bool SDLCALL windows_file_open(IOStreamWindowsData *iodata, const char *filename, const char *mode)
+static HANDLE SDLCALL windows_file_open(const char *filename, const char *mode)
{
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
UINT old_error_mode;
@@ -83,9 +84,6 @@ static bool SDLCALL windows_file_open(IOStreamWindowsData *iodata, const char *f
DWORD must_exist, truncate;
int a_mode;
- SDL_zerop(iodata);
- iodata->h = INVALID_HANDLE_VALUE; // mark this as unusable
-
// "r" = reading, file must exist
// "w" = writing, truncate existing, file may not exist
// "r+"= reading or writing, file must exist
@@ -100,18 +98,13 @@ static bool SDLCALL windows_file_open(IOStreamWindowsData *iodata, const char *f
w_right = (a_mode || SDL_strchr(mode, '+') || truncate) ? GENERIC_WRITE : 0;
if (!r_right && !w_right) {
- return false; // inconsistent mode
+ return INVALID_HANDLE_VALUE; // inconsistent mode
}
// failed (invalid call)
- iodata->data = (char *)SDL_malloc(READAHEAD_BUFFER_SIZE);
- if (!iodata->data) {
- return false;
- }
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
// Do not open a dialog box if failure
- old_error_mode =
- SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
+ old_error_mode = SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
#endif
{
@@ -132,15 +125,9 @@ static bool SDLCALL windows_file_open(IOStreamWindowsData *iodata, const char *f
#endif
if (h == INVALID_HANDLE_VALUE) {
- SDL_free(iodata->data);
- iodata->data = NULL;
SDL_SetError("Couldn't open %s", filename);
- return false; // failed (CreateFile)
}
- iodata->h = h;
- iodata->append = a_mode ? true : false;
-
- return true; // ok
+ return h;
}
static Sint64 SDLCALL windows_file_size(void *userdata)
@@ -184,7 +171,7 @@ static Sint64 SDLCALL windows_file_seek(void *userdata, Sint64 offset, SDL_IOWhe
windowsoffset.QuadPart = offset;
if (!SetFilePointerEx(iodata->h, windowsoffset, &windowsoffset, windowswhence)) {
- return WIN_SetError("windows_file_seek");
+ return WIN_SetError("Error seeking in datastream");
}
return windowsoffset.QuadPart;
}
@@ -215,7 +202,9 @@ static size_t SDLCALL windows_file_read(void *userdata, void *ptr, size_t size,
if (total_need < READAHEAD_BUFFER_SIZE) {
if (!ReadFile(iodata->h, iodata->data, READAHEAD_BUFFER_SIZE, &bytes, NULL)) {
- SDL_SetError("Error reading from datastream");
+ if (GetLastError() != ERROR_HANDLE_EOF && GetLastError() != ERROR_BROKEN_PIPE) {
+ WIN_SetError("Error reading from datastream");
+ }
return 0;
}
read_ahead = SDL_min(total_need, bytes);
@@ -225,7 +214,9 @@ static size_t SDLCALL windows_file_read(void *userdata, void *ptr, size_t size,
total_read += read_ahead;
} else {
if (!ReadFile(iodata->h, ptr, (DWORD)total_need, &bytes, NULL)) {
- SDL_SetError("Error reading from datastream");
+ if (GetLastError() != ERROR_HANDLE_EOF && GetLastError() != ERROR_BROKEN_PIPE) {
+ WIN_SetError("Error reading from datastream");
+ }
return 0;
}
total_read += bytes;
@@ -241,7 +232,7 @@ static size_t SDLCALL windows_file_write(void *userdata, const void *ptr, size_t
if (iodata->left) {
if (!SetFilePointer(iodata->h, -(LONG)iodata->left, NULL, FILE_CURRENT)) {
- SDL_SetError("Error seeking in datastream");
+ WIN_SetError("Error seeking in datastream");
return 0;
}
iodata->left = 0;
@@ -252,13 +243,13 @@ static size_t SDLCALL windows_file_write(void *userdata, const void *ptr, size_t
LARGE_INTEGER windowsoffset;
windowsoffset.QuadPart = 0;
if (!SetFilePointerEx(iodata->h, windowsoffset, &windowsoffset, FILE_END)) {
- SDL_SetError("Error seeking in datastream");
+ WIN_SetError("Error seeking in datastream");
return 0;
}
}
if (!WriteFile(iodata->h, ptr, (DWORD)total_bytes, &bytes, NULL)) {
- SDL_SetError("Error writing to datastream");
+ WIN_SetError("Error writing to datastream");
return 0;
}
@@ -269,13 +260,58 @@ static SDL_bool SDLCALL windows_file_close(void *userdata)
{
IOStreamWindowsData *iodata = (IOStreamWindowsData *) userdata;
if (iodata->h != INVALID_HANDLE_VALUE) {
- CloseHandle(iodata->h);
+ if (iodata->autoclose) {
+ CloseHandle(iodata->h);
+ }
iodata->h = INVALID_HANDLE_VALUE; // to be sure
}
SDL_free(iodata->data);
SDL_free(iodata);
return true;
}
+
+SDL_IOStream *SDL_IOFromHandle(HANDLE handle, const char *mode, bool autoclose)
+{
+ IOStreamWindowsData *iodata = (IOStreamWindowsData *) SDL_calloc(1, sizeof (*iodata));
+ if (!iodata) {
+ if (autoclose) {
+ CloseHandle(handle);
+ }
+ return NULL;
+ }
+
+ SDL_IOStreamInterface iface;
+ SDL_INIT_INTERFACE(&iface);
+ if (GetFileType(handle) == FILE_TYPE_DISK) {
+ iface.size = windows_file_size;
+ iface.seek = windows_file_seek;
+ }
+ iface.read = windows_file_read;
+ iface.write = windows_file_write;
+ iface.close = windows_file_close;
+
+ iodata->h = handle;
+ iodata->append = (SDL_strchr(mode, 'a') != NULL);
+ iodata->autoclose = autoclose;
+
+ iodata->data = (char *)SDL_malloc(READAHEAD_BUFFER_SIZE);
+ if (!iodata->data) {
+ iface.close(iodata);
+ return NULL;
+ }
+
+ SDL_IOStream *iostr = SDL_OpenIO(&iface, iodata);
+ if (!iostr) {
+ iface.close(iodata);
+ } else {
+ const SDL_PropertiesID props = SDL_GetIOProperties(iostr);
+ if (props) {
+ SDL_SetPointerProperty(props, SDL_PROP_IOSTREAM_WINDOWS_HANDLE_POINTER, iodata->h);
+ }
+ }
+
+ return iostr;
+}
#endif // defined(SDL_PLATFORM_WINDOWS)
#if defined(HAVE_STDIO_H) && !defined(SDL_PLATFORM_WINDOWS)
@@ -357,12 +393,12 @@ static Sint64 SDLCALL stdio_seek(void *userdata, Sint64 offset, SDL_IOWhence whe
if (is_noop || fseek(iodata->fp, (fseek_off_t)offset, stdiowhence) == 0) {
const Sint64 pos = ftell(iodata->fp);
if (pos < 0) {
- SDL_SetError("Couldn't get stream offset");
+ SDL_SetError("Couldn't get stream offset: %s", strerror(errno));
return -1;
}
return pos;
}
- SDL_SetError("Error seeking in datastream");
+ SDL_SetError("Error seeking in datastream: %s", strerror(errno));
return -1;
}
@@ -371,7 +407,12 @@ static size_t SDLCALL stdio_read(void *userdata, void *ptr, size_t size, SDL_IOS
IOStreamStdioData *iodata = (IOStreamStdioData *) userdata;
const size_t bytes = fread(ptr, 1, size, iodata->fp);
if (bytes == 0 && ferror(iodata->fp)) {
- SDL_SetError("Error reading from datastream");
+ if (errno == EAGAIN) {
+ *status = SDL_IO_STATUS_NOT_READY;
+ clearerr(iodata->fp);
+ } else {
+ SDL_SetError("Error reading from datastream: %s", strerror(errno));
+ }
}
return bytes;
}
@@ -381,28 +422,50 @@ static size_t SDLCALL stdio_write(void *userdata, const void *ptr, size_t size,
IOStreamStdioData *iodata = (IOStreamStdioData *) userdata;
const size_t bytes = fwrite(ptr, 1, size, iodata->fp);
if (bytes == 0 && ferror(iodata->fp)) {
- SDL_SetError("Error writing to datastream");
+ if (errno == EAGAIN) {
+ *status = SDL_IO_STATUS_NOT_READY;
+ clearerr(iodata->fp);
+ } else {
+ SDL_SetError("Error writing to datastream: %s", strerror(errno));
+ }
}
return bytes;
}
+static SDL_bool SDLCALL stdio_flush(void *userdata, SDL_IOStatus *status)
+{
+ IOStreamStdioData *iodata = (IOStreamStdioData *) userdata;
+ if (fflush(iodata->fp) != 0) {
+ if (errno == EAGAIN) {
+ *status = SDL_IO_STATUS_NOT_READY;
+ return false;
+ } else {
+ return SDL_SetError("Error flushing datastream: %s", strerror(errno));
+ }
+ }
+ return true;
+}
+
static SDL_bool SDLCALL stdio_close(void *userdata)
{
IOStreamStdioData *iodata = (IOStreamStdioData *) userdata;
bool status = true;
if (iodata->autoclose) {
if (fclose(iodata->fp) != 0) {
- status = SDL_SetError("Error writing to datastream");
+ status = SDL_SetError("Error writing to datastream: %s", strerror(errno));
}
}
SDL_free(iodata);
return status;
}
-static SDL_IOStream *SDL_IOFromFP(FILE *fp, bool autoclose)
+SDL_IOStream *SDL_IOFromFP(FILE *fp, bool autoclose)
{
- IOStreamStdioData *iodata = (IOStreamStdioData *) SDL_malloc(sizeof (*iodata));
+ IOStreamStdioData *iodata = (IOStreamStdioData *) SDL_calloc(1, sizeof (*iodata));
if (!iodata) {
+ if (autoclose) {
+ fclose(fp);
+ }
return NULL;
}
@@ -412,6 +475,7 @@ static SDL_IOStream *SDL_IOFromFP(FILE *fp, bool autoclose)
iface.seek = stdio_seek;
iface.read = stdio_read;
iface.write = stdio_write;
+ iface.flush = stdio_flush;
iface.close = stdio_close;
iodata->fp = fp;
@@ -424,6 +488,7 @@ static SDL_IOStream *SDL_IOFromFP(FILE *fp, bool autoclose)
const SDL_PropertiesID props = SDL_GetIOProperties(iostr);
if (props) {
SDL_SetPointerProperty(props, SDL_PROP_IOSTREAM_STDIO_FILE_POINTER, fp);
+ SDL_SetNumberProperty(props, SDL_PROP_IOSTREAM_FILE_DESCRIPTOR_NUMBER, fileno(fp));
}
}
@@ -542,7 +607,7 @@ SDL_IOStream *SDL_IOFromFile(const char *file, const char *mode)
SDL_SetError("%s is not a regular file or pipe", file);
return NULL;
}
- return SDL_IOFromFP(fp, 1);
+ return SDL_IOFromFP(fp, true);
}
} else if (SDL_strncmp(file, "content://", 10) == 0) {
// Try opening content:// URI
@@ -573,7 +638,7 @@ SDL_IOStream *SDL_IOFromFile(const char *file, const char *mode)
SDL_SetError("%s is not a regular file or pipe", path);
return NULL;
}
- return SDL_IOFromFP(fp, 1);
+ return SDL_IOFromFP(fp, true);
}
}
}
@@ -605,32 +670,9 @@ SDL_IOStream *SDL_IOFromFile(const char *file, const char *mode)
}
#elif defined(SDL_PLATFORM_WINDOWS)
- IOStreamWindowsData *iodata = (IOStreamWindowsData *) SDL_malloc(sizeof (*iodata));
- if (!iodata) {
- return NULL;
- }
-
- if (!windows_file_open(iodata, file, mode)) {
- windows_file_close(iodata);
- return NULL;
- }
-
- SDL_IOStreamInterface iface;
- SDL_INIT_INTERFACE(&iface);
- iface.size = windows_file_size;
- iface.seek = windows_file_seek;
- iface.read = windows_file_read;
- iface.write = windows_file_write;
- iface.close = windows_file_close;
-
- iostr = SDL_OpenIO(&iface, iodata);
- if (!iostr) {
- windows_file_close(iodata);
- } else {
- const SDL_PropertiesID props = SDL_GetIOProperties(iostr);
- if (props) {
- SDL_SetPointerProperty(props, SDL_PROP_IOSTREAM_WINDOWS_HANDLE_POINTER, iodata->h);
- }
+ HANDLE handle = windows_file_open(file, mode);
+ if (handle != INVALID_HANDLE_VALUE) {
+ iostr = SDL_IOFromHandle(handle, mode, true);
}
#elif defined(HAVE_STDIO_H)
@@ -669,7 +711,7 @@ SDL_IOStream *SDL_IOFromMem(void *mem, size_t size)
return NULL;
}
- IOStreamMemData *iodata = (IOStreamMemData *) SDL_malloc(sizeof (*iodata));
+ IOStreamMemData *iodata = (IOStreamMemData *) SDL_calloc(1, sizeof (*iodata));
if (!iodata) {
return NULL;
}
@@ -703,7 +745,7 @@ SDL_IOStream *SDL_IOFromConstMem(const void *mem, size_t size)
return NULL;
}
- IOStreamMemData *iodata = (IOStreamMemData *) SDL_malloc(sizeof (*iodata));
+ IOStreamMemData *iodata = (IOStreamMemData *) SDL_calloc(1, sizeof (*iodata));
if (!iodata) {
return NULL;
}
@@ -803,7 +845,7 @@ static SDL_bool SDLCALL dynamic_mem_close(void *userdata)
SDL_IOStream *SDL_IOFromDynamicMem(void)
{
- IOStreamDynamicMemData *iodata = (IOStreamDynamicMemData *) SDL_malloc(sizeof (*iodata));
+ IOStreamDynamicMemData *iodata = (IOStreamDynamicMemData *) SDL_calloc(1, sizeof (*iodata));
if (!iodata) {
return NULL;
}
@@ -816,11 +858,6 @@ SDL_IOStream *SDL_IOFromDynamicMem(void)
iface.write = dynamic_mem_write;
iface.close = dynamic_mem_close;
- iodata->data.base = NULL;
- iodata->data.here = NULL;
- iodata->data.stop = NULL;
- iodata->end = NULL;
-
SDL_IOStream *iostr = SDL_OpenIO(&iface, iodata);
if (iostr) {
iodata->stream = iostr;
@@ -922,6 +959,10 @@ void *SDL_LoadFile_IO(SDL_IOStream *src, size_t *datasize, SDL_bool closeio)
if (size_read > 0) {
size_total += size_read;
continue;
+ } else if (SDL_GetIOStatus(src) == SDL_IO_STATUS_NOT_READY) {
+ // Wait for the stream to be ready
+ SDL_Delay(1);
+ continue;
}
// The stream status will remain set for the caller to check
@@ -981,9 +1022,11 @@ Sint64 SDL_GetIOSize(SDL_IOStream *context)
Sint64 SDL_SeekIO(SDL_IOStream *context, Sint64 offset, SDL_IOWhence whence)
{
if (!context) {
- return SDL_InvalidParamError("context");
+ SDL_InvalidParamError("context");
+ return -1;
} else if (!context->iface.seek) {
- return SDL_Unsupported();
+ SDL_Unsupported();
+ return -1;
}
return context->iface.seek(context->userdata, offset, whence);
}
@@ -1086,6 +1129,26 @@ size_t SDL_IOvprintf(SDL_IOStream *context, SDL_PRINTF_FORMAT_STRING const char
return bytes;
}
+SDL_bool SDL_FlushIO(SDL_IOStream *context)
+{
+ bool result = true;
+
+ if (!context) {
+ return SDL_InvalidParamError("context");
+ }
+
+ context->status = SDL_IO_STATUS_READY;
+ SDL_ClearError();
+
+ if (context->iface.flush) {
+ result = context->iface.flush(context->userdata, &context->status);
+ }
+ if (!result && (context->status == SDL_IO_STATUS_READY)) {
+ context->status = SDL_IO_STATUS_ERROR;
+ }
+ return result;
+}
+
// Functions for dynamically reading and writing endian-specific values
SDL_bool SDL_ReadU8(SDL_IOStream *src, Uint8 *value)
diff --git a/src/file/SDL_iostream_c.h b/src/file/SDL_iostream_c.h
new file mode 100644
index 0000000000000..005eb72bcc7ac
--- /dev/null
+++ b/src/file/SDL_iostream_c.h
@@ -0,0 +1,32 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "SDL_internal.h"
+
+#ifndef SDL_iostream_c_h_
+#define SDL_iostream_c_h_
+
+#if defined(SDL_PLATFORM_WINDOWS)
+SDL_IOStream *SDL_IOFromHandle(HANDLE handle, const char *mode, bool autoclose);
+#elif defined(HAVE_STDIO_H)
+extern SDL_IOStream *SDL_IOFromFP(FILE *fp, bool autoclose);
+#endif
+
+#endif // SDL_iostream_c_h_