diff --git a/include/SDL3/SDL_iostream.h b/include/SDL3/SDL_iostream.h index b5cb2f03b..745e35aae 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 1b5f1a40a..2b906b96d 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 8bad28dbd..212ccf4de 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 250089ab4..fad787ac3 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 e00438bde..0d9f39fbb 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 000000000..005eb72bc --- /dev/null +++ b/src/file/SDL_iostream_c.h @@ -0,0 +1,32 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2024 Sam Lantinga + + 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_