mirror of
https://github.com/libsdl-org/SDL.git
synced 2024-11-26 21:33:26 +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);
|
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.
|
* 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.
|
* the code using this interface should be updated to handle the old version.
|
||||||
*/
|
*/
|
||||||
SDL_COMPILE_TIME_ASSERT(SDL_IOStreamInterface_SIZE,
|
SDL_COMPILE_TIME_ASSERT(SDL_IOStreamInterface_SIZE,
|
||||||
(sizeof(void *) == 4 && sizeof(SDL_IOStreamInterface) == 24) ||
|
(sizeof(void *) == 4 && sizeof(SDL_IOStreamInterface) == 28) ||
|
||||||
(sizeof(void *) == 8 && sizeof(SDL_IOStreamInterface) == 48));
|
(sizeof(void *) == 8 && sizeof(SDL_IOStreamInterface) == 56));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The read/write operation structure.
|
* 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
|
* 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
|
* 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.
|
* 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
|
* - `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
|
* 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,
|
* 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.
|
* \since This function is available since SDL 3.0.0.
|
||||||
*
|
*
|
||||||
* \sa SDL_CloseIO
|
* \sa SDL_CloseIO
|
||||||
|
* \sa SDL_FlushIO
|
||||||
* \sa SDL_ReadIO
|
* \sa SDL_ReadIO
|
||||||
* \sa SDL_SeekIO
|
* \sa SDL_SeekIO
|
||||||
* \sa SDL_TellIO
|
* \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_WINDOWS_HANDLE_POINTER "SDL.iostream.windows.handle"
|
||||||
#define SDL_PROP_IOSTREAM_STDIO_FILE_POINTER "SDL.iostream.stdio.file"
|
#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"
|
#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_IOFromConstMem
|
||||||
* \sa SDL_CloseIO
|
* \sa SDL_CloseIO
|
||||||
|
* \sa SDL_FlushIO
|
||||||
* \sa SDL_ReadIO
|
* \sa SDL_ReadIO
|
||||||
* \sa SDL_SeekIO
|
* \sa SDL_SeekIO
|
||||||
* \sa SDL_TellIO
|
* \sa SDL_TellIO
|
||||||
@ -465,8 +480,7 @@ extern SDL_DECLSPEC Sint64 SDLCALL SDL_GetIOSize(SDL_IOStream *context);
|
|||||||
* negative.
|
* negative.
|
||||||
* \param whence any of `SDL_IO_SEEK_SET`, `SDL_IO_SEEK_CUR`,
|
* \param whence any of `SDL_IO_SEEK_SET`, `SDL_IO_SEEK_CUR`,
|
||||||
* `SDL_IO_SEEK_END`.
|
* `SDL_IO_SEEK_END`.
|
||||||
* \returns the final offset in the data stream after the seek or a negative
|
* \returns the final offset in the data stream after the seek or -1 on failure; call SDL_GetError() for more information.
|
||||||
* error code on failure; call SDL_GetError() for more information.
|
|
||||||
*
|
*
|
||||||
* \since This function is available since SDL 3.0.0.
|
* \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_IOprintf
|
||||||
* \sa SDL_ReadIO
|
* \sa SDL_ReadIO
|
||||||
* \sa SDL_SeekIO
|
* \sa SDL_SeekIO
|
||||||
|
* \sa SDL_FlushIO
|
||||||
* \sa SDL_GetIOStatus
|
* \sa SDL_GetIOStatus
|
||||||
*/
|
*/
|
||||||
extern SDL_DECLSPEC size_t SDLCALL SDL_WriteIO(SDL_IOStream *context, const void *ptr, size_t size);
|
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);
|
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.
|
* 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().
|
* The data should be freed with SDL_free().
|
||||||
*
|
*
|
||||||
* \param src the SDL_IOStream to read all available data from.
|
* \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,
|
* \param closeio if SDL_TRUE, calls SDL_CloseIO() on `src` before returning,
|
||||||
* even in the case of an error.
|
* even in the case of an error.
|
||||||
* \returns the data or NULL on failure; call SDL_GetError() for more
|
* \returns the data or NULL on failure; call SDL_GetError() for more
|
||||||
|
@ -169,6 +169,7 @@ SDL3_0.0.0 {
|
|||||||
SDL_FlushAudioStream;
|
SDL_FlushAudioStream;
|
||||||
SDL_FlushEvent;
|
SDL_FlushEvent;
|
||||||
SDL_FlushEvents;
|
SDL_FlushEvents;
|
||||||
|
SDL_FlushIO;
|
||||||
SDL_FlushRenderer;
|
SDL_FlushRenderer;
|
||||||
SDL_GDKResumeGPU;
|
SDL_GDKResumeGPU;
|
||||||
SDL_GDKSuspendComplete;
|
SDL_GDKSuspendComplete;
|
||||||
|
@ -194,6 +194,7 @@
|
|||||||
#define SDL_FlushAudioStream SDL_FlushAudioStream_REAL
|
#define SDL_FlushAudioStream SDL_FlushAudioStream_REAL
|
||||||
#define SDL_FlushEvent SDL_FlushEvent_REAL
|
#define SDL_FlushEvent SDL_FlushEvent_REAL
|
||||||
#define SDL_FlushEvents SDL_FlushEvents_REAL
|
#define SDL_FlushEvents SDL_FlushEvents_REAL
|
||||||
|
#define SDL_FlushIO SDL_FlushIO_REAL
|
||||||
#define SDL_FlushRenderer SDL_FlushRenderer_REAL
|
#define SDL_FlushRenderer SDL_FlushRenderer_REAL
|
||||||
#define SDL_GDKResumeGPU SDL_GDKResumeGPU_REAL
|
#define SDL_GDKResumeGPU SDL_GDKResumeGPU_REAL
|
||||||
#define SDL_GDKSuspendComplete SDL_GDKSuspendComplete_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(SDL_bool,SDL_FlushAudioStream,(SDL_AudioStream *a),(a),return)
|
||||||
SDL_DYNAPI_PROC(void,SDL_FlushEvent,(Uint32 a),(a),)
|
SDL_DYNAPI_PROC(void,SDL_FlushEvent,(Uint32 a),(a),)
|
||||||
SDL_DYNAPI_PROC(void,SDL_FlushEvents,(Uint32 a, Uint32 b),(a,b),)
|
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(SDL_bool,SDL_FlushRenderer,(SDL_Renderer *a),(a),return)
|
||||||
SDL_DYNAPI_PROC(void,SDL_GDKResumeGPU,(SDL_GPUDevice *a),(a),)
|
SDL_DYNAPI_PROC(void,SDL_GDKResumeGPU,(SDL_GPUDevice *a),(a),)
|
||||||
SDL_DYNAPI_PROC(void,SDL_GDKSuspendComplete,(void),(),)
|
SDL_DYNAPI_PROC(void,SDL_GDKSuspendComplete,(void),(),)
|
||||||
|
@ -58,11 +58,12 @@ struct SDL_IOStream
|
|||||||
|
|
||||||
typedef struct IOStreamWindowsData
|
typedef struct IOStreamWindowsData
|
||||||
{
|
{
|
||||||
bool append;
|
|
||||||
HANDLE h;
|
HANDLE h;
|
||||||
void *data;
|
void *data;
|
||||||
size_t size;
|
size_t size;
|
||||||
size_t left;
|
size_t left;
|
||||||
|
bool append;
|
||||||
|
bool autoclose;
|
||||||
} IOStreamWindowsData;
|
} IOStreamWindowsData;
|
||||||
|
|
||||||
|
|
||||||
@ -73,7 +74,7 @@ typedef struct IOStreamWindowsData
|
|||||||
|
|
||||||
#define READAHEAD_BUFFER_SIZE 1024
|
#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)
|
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
||||||
UINT old_error_mode;
|
UINT old_error_mode;
|
||||||
@ -83,9 +84,6 @@ static bool SDLCALL windows_file_open(IOStreamWindowsData *iodata, const char *f
|
|||||||
DWORD must_exist, truncate;
|
DWORD must_exist, truncate;
|
||||||
int a_mode;
|
int a_mode;
|
||||||
|
|
||||||
SDL_zerop(iodata);
|
|
||||||
iodata->h = INVALID_HANDLE_VALUE; // mark this as unusable
|
|
||||||
|
|
||||||
// "r" = reading, file must exist
|
// "r" = reading, file must exist
|
||||||
// "w" = writing, truncate existing, file may not exist
|
// "w" = writing, truncate existing, file may not exist
|
||||||
// "r+"= reading or writing, file must 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;
|
w_right = (a_mode || SDL_strchr(mode, '+') || truncate) ? GENERIC_WRITE : 0;
|
||||||
|
|
||||||
if (!r_right && !w_right) {
|
if (!r_right && !w_right) {
|
||||||
return false; // inconsistent mode
|
return INVALID_HANDLE_VALUE; // inconsistent mode
|
||||||
}
|
}
|
||||||
// failed (invalid call)
|
// 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)
|
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
||||||
// Do not open a dialog box if failure
|
// Do not open a dialog box if failure
|
||||||
old_error_mode =
|
old_error_mode = SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
|
||||||
SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -132,15 +125,9 @@ static bool SDLCALL windows_file_open(IOStreamWindowsData *iodata, const char *f
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (h == INVALID_HANDLE_VALUE) {
|
if (h == INVALID_HANDLE_VALUE) {
|
||||||
SDL_free(iodata->data);
|
|
||||||
iodata->data = NULL;
|
|
||||||
SDL_SetError("Couldn't open %s", filename);
|
SDL_SetError("Couldn't open %s", filename);
|
||||||
return false; // failed (CreateFile)
|
|
||||||
}
|
}
|
||||||
iodata->h = h;
|
return h;
|
||||||
iodata->append = a_mode ? true : false;
|
|
||||||
|
|
||||||
return true; // ok
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Sint64 SDLCALL windows_file_size(void *userdata)
|
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;
|
windowsoffset.QuadPart = offset;
|
||||||
if (!SetFilePointerEx(iodata->h, windowsoffset, &windowsoffset, windowswhence)) {
|
if (!SetFilePointerEx(iodata->h, windowsoffset, &windowsoffset, windowswhence)) {
|
||||||
return WIN_SetError("windows_file_seek");
|
return WIN_SetError("Error seeking in datastream");
|
||||||
}
|
}
|
||||||
return windowsoffset.QuadPart;
|
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 (total_need < READAHEAD_BUFFER_SIZE) {
|
||||||
if (!ReadFile(iodata->h, iodata->data, READAHEAD_BUFFER_SIZE, &bytes, NULL)) {
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
read_ahead = SDL_min(total_need, bytes);
|
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;
|
total_read += read_ahead;
|
||||||
} else {
|
} else {
|
||||||
if (!ReadFile(iodata->h, ptr, (DWORD)total_need, &bytes, NULL)) {
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
total_read += bytes;
|
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 (iodata->left) {
|
||||||
if (!SetFilePointer(iodata->h, -(LONG)iodata->left, NULL, FILE_CURRENT)) {
|
if (!SetFilePointer(iodata->h, -(LONG)iodata->left, NULL, FILE_CURRENT)) {
|
||||||
SDL_SetError("Error seeking in datastream");
|
WIN_SetError("Error seeking in datastream");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
iodata->left = 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;
|
LARGE_INTEGER windowsoffset;
|
||||||
windowsoffset.QuadPart = 0;
|
windowsoffset.QuadPart = 0;
|
||||||
if (!SetFilePointerEx(iodata->h, windowsoffset, &windowsoffset, FILE_END)) {
|
if (!SetFilePointerEx(iodata->h, windowsoffset, &windowsoffset, FILE_END)) {
|
||||||
SDL_SetError("Error seeking in datastream");
|
WIN_SetError("Error seeking in datastream");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!WriteFile(iodata->h, ptr, (DWORD)total_bytes, &bytes, NULL)) {
|
if (!WriteFile(iodata->h, ptr, (DWORD)total_bytes, &bytes, NULL)) {
|
||||||
SDL_SetError("Error writing to datastream");
|
WIN_SetError("Error writing to datastream");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -269,13 +260,58 @@ static SDL_bool SDLCALL windows_file_close(void *userdata)
|
|||||||
{
|
{
|
||||||
IOStreamWindowsData *iodata = (IOStreamWindowsData *) userdata;
|
IOStreamWindowsData *iodata = (IOStreamWindowsData *) userdata;
|
||||||
if (iodata->h != INVALID_HANDLE_VALUE) {
|
if (iodata->h != INVALID_HANDLE_VALUE) {
|
||||||
CloseHandle(iodata->h);
|
if (iodata->autoclose) {
|
||||||
|
CloseHandle(iodata->h);
|
||||||
|
}
|
||||||
iodata->h = INVALID_HANDLE_VALUE; // to be sure
|
iodata->h = INVALID_HANDLE_VALUE; // to be sure
|
||||||
}
|
}
|
||||||
SDL_free(iodata->data);
|
SDL_free(iodata->data);
|
||||||
SDL_free(iodata);
|
SDL_free(iodata);
|
||||||
return true;
|
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)
|
#endif // defined(SDL_PLATFORM_WINDOWS)
|
||||||
|
|
||||||
#if defined(HAVE_STDIO_H) && !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) {
|
if (is_noop || fseek(iodata->fp, (fseek_off_t)offset, stdiowhence) == 0) {
|
||||||
const Sint64 pos = ftell(iodata->fp);
|
const Sint64 pos = ftell(iodata->fp);
|
||||||
if (pos < 0) {
|
if (pos < 0) {
|
||||||
SDL_SetError("Couldn't get stream offset");
|
SDL_SetError("Couldn't get stream offset: %s", strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
SDL_SetError("Error seeking in datastream");
|
SDL_SetError("Error seeking in datastream: %s", strerror(errno));
|
||||||
return -1;
|
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;
|
IOStreamStdioData *iodata = (IOStreamStdioData *) userdata;
|
||||||
const size_t bytes = fread(ptr, 1, size, iodata->fp);
|
const size_t bytes = fread(ptr, 1, size, iodata->fp);
|
||||||
if (bytes == 0 && ferror(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;
|
return bytes;
|
||||||
}
|
}
|
||||||
@ -381,28 +422,50 @@ static size_t SDLCALL stdio_write(void *userdata, const void *ptr, size_t size,
|
|||||||
IOStreamStdioData *iodata = (IOStreamStdioData *) userdata;
|
IOStreamStdioData *iodata = (IOStreamStdioData *) userdata;
|
||||||
const size_t bytes = fwrite(ptr, 1, size, iodata->fp);
|
const size_t bytes = fwrite(ptr, 1, size, iodata->fp);
|
||||||
if (bytes == 0 && ferror(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;
|
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)
|
static SDL_bool SDLCALL stdio_close(void *userdata)
|
||||||
{
|
{
|
||||||
IOStreamStdioData *iodata = (IOStreamStdioData *) userdata;
|
IOStreamStdioData *iodata = (IOStreamStdioData *) userdata;
|
||||||
bool status = true;
|
bool status = true;
|
||||||
if (iodata->autoclose) {
|
if (iodata->autoclose) {
|
||||||
if (fclose(iodata->fp) != 0) {
|
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);
|
SDL_free(iodata);
|
||||||
return status;
|
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 (!iodata) {
|
||||||
|
if (autoclose) {
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -412,6 +475,7 @@ static SDL_IOStream *SDL_IOFromFP(FILE *fp, bool autoclose)
|
|||||||
iface.seek = stdio_seek;
|
iface.seek = stdio_seek;
|
||||||
iface.read = stdio_read;
|
iface.read = stdio_read;
|
||||||
iface.write = stdio_write;
|
iface.write = stdio_write;
|
||||||
|
iface.flush = stdio_flush;
|
||||||
iface.close = stdio_close;
|
iface.close = stdio_close;
|
||||||
|
|
||||||
iodata->fp = fp;
|
iodata->fp = fp;
|
||||||
@ -424,6 +488,7 @@ static SDL_IOStream *SDL_IOFromFP(FILE *fp, bool autoclose)
|
|||||||
const SDL_PropertiesID props = SDL_GetIOProperties(iostr);
|
const SDL_PropertiesID props = SDL_GetIOProperties(iostr);
|
||||||
if (props) {
|
if (props) {
|
||||||
SDL_SetPointerProperty(props, SDL_PROP_IOSTREAM_STDIO_FILE_POINTER, fp);
|
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);
|
SDL_SetError("%s is not a regular file or pipe", file);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return SDL_IOFromFP(fp, 1);
|
return SDL_IOFromFP(fp, true);
|
||||||
}
|
}
|
||||||
} else if (SDL_strncmp(file, "content://", 10) == 0) {
|
} else if (SDL_strncmp(file, "content://", 10) == 0) {
|
||||||
// Try opening content:// URI
|
// 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);
|
SDL_SetError("%s is not a regular file or pipe", path);
|
||||||
return NULL;
|
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)
|
#elif defined(SDL_PLATFORM_WINDOWS)
|
||||||
IOStreamWindowsData *iodata = (IOStreamWindowsData *) SDL_malloc(sizeof (*iodata));
|
HANDLE handle = windows_file_open(file, mode);
|
||||||
if (!iodata) {
|
if (handle != INVALID_HANDLE_VALUE) {
|
||||||
return NULL;
|
iostr = SDL_IOFromHandle(handle, mode, true);
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(HAVE_STDIO_H)
|
#elif defined(HAVE_STDIO_H)
|
||||||
@ -669,7 +711,7 @@ SDL_IOStream *SDL_IOFromMem(void *mem, size_t size)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
IOStreamMemData *iodata = (IOStreamMemData *) SDL_malloc(sizeof (*iodata));
|
IOStreamMemData *iodata = (IOStreamMemData *) SDL_calloc(1, sizeof (*iodata));
|
||||||
if (!iodata) {
|
if (!iodata) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -703,7 +745,7 @@ SDL_IOStream *SDL_IOFromConstMem(const void *mem, size_t size)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
IOStreamMemData *iodata = (IOStreamMemData *) SDL_malloc(sizeof (*iodata));
|
IOStreamMemData *iodata = (IOStreamMemData *) SDL_calloc(1, sizeof (*iodata));
|
||||||
if (!iodata) {
|
if (!iodata) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -803,7 +845,7 @@ static SDL_bool SDLCALL dynamic_mem_close(void *userdata)
|
|||||||
|
|
||||||
SDL_IOStream *SDL_IOFromDynamicMem(void)
|
SDL_IOStream *SDL_IOFromDynamicMem(void)
|
||||||
{
|
{
|
||||||
IOStreamDynamicMemData *iodata = (IOStreamDynamicMemData *) SDL_malloc(sizeof (*iodata));
|
IOStreamDynamicMemData *iodata = (IOStreamDynamicMemData *) SDL_calloc(1, sizeof (*iodata));
|
||||||
if (!iodata) {
|
if (!iodata) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -816,11 +858,6 @@ SDL_IOStream *SDL_IOFromDynamicMem(void)
|
|||||||
iface.write = dynamic_mem_write;
|
iface.write = dynamic_mem_write;
|
||||||
iface.close = dynamic_mem_close;
|
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);
|
SDL_IOStream *iostr = SDL_OpenIO(&iface, iodata);
|
||||||
if (iostr) {
|
if (iostr) {
|
||||||
iodata->stream = 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) {
|
if (size_read > 0) {
|
||||||
size_total += size_read;
|
size_total += size_read;
|
||||||
continue;
|
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
|
// 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)
|
Sint64 SDL_SeekIO(SDL_IOStream *context, Sint64 offset, SDL_IOWhence whence)
|
||||||
{
|
{
|
||||||
if (!context) {
|
if (!context) {
|
||||||
return SDL_InvalidParamError("context");
|
SDL_InvalidParamError("context");
|
||||||
|
return -1;
|
||||||
} else if (!context->iface.seek) {
|
} else if (!context->iface.seek) {
|
||||||
return SDL_Unsupported();
|
SDL_Unsupported();
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
return context->iface.seek(context->userdata, offset, whence);
|
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;
|
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
|
// Functions for dynamically reading and writing endian-specific values
|
||||||
|
|
||||||
SDL_bool SDL_ReadU8(SDL_IOStream *src, Uint8 *value)
|
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