mirror of
https://github.com/libsdl-org/SDL.git
synced 2024-11-23 02:43:30 +08:00
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.
This commit is contained in:
parent
93caf1cd21
commit
6c83491116
@ -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
|
||||
|
@ -169,6 +169,7 @@ SDL3_0.0.0 {
|
||||
SDL_FlushAudioStream;
|
||||
SDL_FlushEvent;
|
||||
SDL_FlushEvents;
|
||||
SDL_FlushIO;
|
||||
SDL_FlushRenderer;
|
||||
SDL_GDKResumeGPU;
|
||||
SDL_GDKSuspendComplete;
|
||||
|
@ -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
|
||||
|
@ -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),(),)
|
||||
|
@ -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)
|
||||
|
32
src/file/SDL_iostream_c.h
Normal file
32
src/file/SDL_iostream_c.h
Normal file
@ -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_
|
Loading…
Reference in New Issue
Block a user