From 05139f4a2ea1d4f848cd66769eb12e7a9098ad1a Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Fri, 25 Nov 2022 10:46:26 -0800 Subject: [PATCH] Removed SDL_RWFromFP from the public API This will blow up if the SDL library and the application have a different C runtime, which can easily happen on Windows. --- WhatsNew.txt | 1 + docs/README-migration.md | 113 +++++++++++++++++++++++++++++ include/SDL_rwops.h | 36 --------- src/dynapi/SDL_dynapi_overrides.h | 1 - src/dynapi/SDL_dynapi_procs.h | 6 -- src/file/SDL_rwops.c | 49 ++++++------- test/testautomation_rwops.c | 117 +----------------------------- 7 files changed, 138 insertions(+), 185 deletions(-) diff --git a/WhatsNew.txt b/WhatsNew.txt index e196247f1..3d90d8f53 100644 --- a/WhatsNew.txt +++ b/WhatsNew.txt @@ -8,3 +8,4 @@ This is a list of major changes in SDL's version history. General: * M_PI is no longer defined in SDL_stdinc.h, now the symbols SDL_M_PIl (double) and SDL_M_PIf (float) are available * SDL_GetWindowWMInfo() returns a standard int result code instead of SDL_bool, and takes SDL_SYSWM_CURRENT_VERSION as a new third parameter +* SDL_RWFromFP has been removed from the API diff --git a/docs/README-migration.md b/docs/README-migration.md index 6e83c8a88..3e165d18c 100644 --- a/docs/README-migration.md +++ b/docs/README-migration.md @@ -4,6 +4,119 @@ This guide provides useful information for migrating applications from SDL 2.0 t We have provided a handy Python script to automate some of this work for you [link to script], and details on the changes are organized by SDL 2.0 header below. +## SDL_rwops.h + +SDL_RWFromFP has been removed from the API, due to issues when the SDL library uses a different C runtime from the application. + +You can implement this in your own code easily: +```c +#include + + +static Sint64 SDLCALL +stdio_size(SDL_RWops * context) +{ + Sint64 pos, size; + + pos = SDL_RWseek(context, 0, RW_SEEK_CUR); + if (pos < 0) { + return -1; + } + size = SDL_RWseek(context, 0, RW_SEEK_END); + + SDL_RWseek(context, pos, RW_SEEK_SET); + return size; +} + +static Sint64 SDLCALL +stdio_seek(SDL_RWops * context, Sint64 offset, int whence) +{ + int stdiowhence; + + switch (whence) { + case RW_SEEK_SET: + stdiowhence = SEEK_SET; + break; + case RW_SEEK_CUR: + stdiowhence = SEEK_CUR; + break; + case RW_SEEK_END: + stdiowhence = SEEK_END; + break; + default: + return SDL_SetError("Unknown value for 'whence'"); + } + + if (fseek((FILE *)context->hidden.stdio.fp, (fseek_off_t)offset, stdiowhence) == 0) { + Sint64 pos = ftell((FILE *)context->hidden.stdio.fp); + if (pos < 0) { + return SDL_SetError("Couldn't get stream offset"); + } + return pos; + } + return SDL_Error(SDL_EFSEEK); +} + +static size_t SDLCALL +stdio_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum) +{ + size_t nread; + + nread = fread(ptr, size, maxnum, (FILE *)context->hidden.stdio.fp); + if (nread == 0 && ferror((FILE *)context->hidden.stdio.fp)) { + SDL_Error(SDL_EFREAD); + } + return nread; +} + +static size_t SDLCALL +stdio_write(SDL_RWops * context, const void *ptr, size_t size, size_t num) +{ + size_t nwrote; + + nwrote = fwrite(ptr, size, num, (FILE *)context->hidden.stdio.fp); + if (nwrote == 0 && ferror((FILE *)context->hidden.stdio.fp)) { + SDL_Error(SDL_EFWRITE); + } + return nwrote; +} + +static int SDLCALL +stdio_close(SDL_RWops * context) +{ + int status = 0; + if (context) { + if (context->hidden.stdio.autoclose) { + /* WARNING: Check the return value here! */ + if (fclose((FILE *)context->hidden.stdio.fp) != 0) { + status = SDL_Error(SDL_EFWRITE); + } + } + SDL_FreeRW(context); + } + return status; +} + +SDL_RWops * +SDL_RWFromFP(void *fp, SDL_bool autoclose) +{ + SDL_RWops *rwops = NULL; + + rwops = SDL_AllocRW(); + if (rwops != NULL) { + rwops->size = stdio_size; + rwops->seek = stdio_seek; + rwops->read = stdio_read; + rwops->write = stdio_write; + rwops->close = stdio_close; + rwops->hidden.stdio.fp = fp; + rwops->hidden.stdio.autoclose = autoclose; + rwops->type = SDL_RWOPS_STDFILE; + } + return rwops; +} +``` + ## SDL_stdinc.h M_PI is no longer defined in SDL_stdinc.h, you can use the new symbols SDL_M_PIl (double) and SDL_M_PIf (float) instead. diff --git a/include/SDL_rwops.h b/include/SDL_rwops.h index a9cc2b878..ef6a1807c 100644 --- a/include/SDL_rwops.h +++ b/include/SDL_rwops.h @@ -195,7 +195,6 @@ typedef struct SDL_RWops * * \sa SDL_RWclose * \sa SDL_RWFromConstMem - * \sa SDL_RWFromFP * \sa SDL_RWFromMem * \sa SDL_RWread * \sa SDL_RWseek @@ -205,34 +204,6 @@ typedef struct SDL_RWops extern DECLSPEC SDL_RWops *SDLCALL SDL_RWFromFile(const char *file, const char *mode); -/** - * Use this function to create an SDL_RWops structure from a standard I/O file - * pointer (stdio.h's `FILE *`). - * - * This function is not available on Windows, since files opened in an - * application on that platform cannot be used by a dynamically linked - * library. - * - * \param fp the `FILE *` that feeds the SDL_RWops stream - * \param autoclose SDL_TRUE to close the `FILE*` when closing the SDL_RWops, - * SDL_FALSE to leave the `FILE*` open when the RWops is - * closed - * \returns a pointer to the SDL_RWops structure that is created, or NULL on - * failure; call SDL_GetError() for more information. - * - * \since This function is available since SDL 3.0.0. - * - * \sa SDL_RWclose - * \sa SDL_RWFromConstMem - * \sa SDL_RWFromFile - * \sa SDL_RWFromMem - * \sa SDL_RWread - * \sa SDL_RWseek - * \sa SDL_RWtell - * \sa SDL_RWwrite - */ -extern DECLSPEC SDL_RWops *SDLCALL SDL_RWFromFP(void *fp, SDL_bool autoclose); - /** * Use this function to prepare a read-write memory buffer for use with * SDL_RWops. @@ -257,7 +228,6 @@ extern DECLSPEC SDL_RWops *SDLCALL SDL_RWFromFP(void *fp, SDL_bool autoclose); * \sa SDL_RWclose * \sa SDL_RWFromConstMem * \sa SDL_RWFromFile - * \sa SDL_RWFromFP * \sa SDL_RWFromMem * \sa SDL_RWread * \sa SDL_RWseek @@ -292,7 +262,6 @@ extern DECLSPEC SDL_RWops *SDLCALL SDL_RWFromMem(void *mem, int size); * \sa SDL_RWclose * \sa SDL_RWFromConstMem * \sa SDL_RWFromFile - * \sa SDL_RWFromFP * \sa SDL_RWFromMem * \sa SDL_RWread * \sa SDL_RWseek @@ -400,7 +369,6 @@ extern DECLSPEC Sint64 SDLCALL SDL_RWsize(SDL_RWops *context); * \sa SDL_RWclose * \sa SDL_RWFromConstMem * \sa SDL_RWFromFile - * \sa SDL_RWFromFP * \sa SDL_RWFromMem * \sa SDL_RWread * \sa SDL_RWtell @@ -428,7 +396,6 @@ extern DECLSPEC Sint64 SDLCALL SDL_RWseek(SDL_RWops *context, * \sa SDL_RWclose * \sa SDL_RWFromConstMem * \sa SDL_RWFromFile - * \sa SDL_RWFromFP * \sa SDL_RWFromMem * \sa SDL_RWread * \sa SDL_RWseek @@ -461,7 +428,6 @@ extern DECLSPEC Sint64 SDLCALL SDL_RWtell(SDL_RWops *context); * \sa SDL_RWclose * \sa SDL_RWFromConstMem * \sa SDL_RWFromFile - * \sa SDL_RWFromFP * \sa SDL_RWFromMem * \sa SDL_RWseek * \sa SDL_RWwrite @@ -495,7 +461,6 @@ extern DECLSPEC size_t SDLCALL SDL_RWread(SDL_RWops *context, * \sa SDL_RWclose * \sa SDL_RWFromConstMem * \sa SDL_RWFromFile - * \sa SDL_RWFromFP * \sa SDL_RWFromMem * \sa SDL_RWread * \sa SDL_RWseek @@ -525,7 +490,6 @@ extern DECLSPEC size_t SDLCALL SDL_RWwrite(SDL_RWops *context, * * \sa SDL_RWFromConstMem * \sa SDL_RWFromFile - * \sa SDL_RWFromFP * \sa SDL_RWFromMem * \sa SDL_RWread * \sa SDL_RWseek diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index 953fd8efb..515b854ca 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -39,7 +39,6 @@ #define SDL_sscanf SDL_sscanf_REAL #define SDL_snprintf SDL_snprintf_REAL #define SDL_CreateThread SDL_CreateThread_REAL -#define SDL_RWFromFP SDL_RWFromFP_REAL #define SDL_RegisterApp SDL_RegisterApp_REAL #define SDL_UnregisterApp SDL_UnregisterApp_REAL #define SDL_Direct3D9GetAdapterIndex SDL_Direct3D9GetAdapterIndex_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index 778d8ed79..862878aeb 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -54,12 +54,6 @@ SDL_DYNAPI_PROC(SDL_Thread*,SDL_CreateThread,(SDL_ThreadFunction a, const char * SDL_DYNAPI_PROC(SDL_Thread*,SDL_CreateThread,(SDL_ThreadFunction a, const char *b, void *c),(a,b,c),return) #endif -#ifdef HAVE_STDIO_H -SDL_DYNAPI_PROC(SDL_RWops*,SDL_RWFromFP,(void *a, SDL_bool b),(a,b),return) -#else -SDL_DYNAPI_PROC(SDL_RWops*,SDL_RWFromFP,(void *a, SDL_bool b),(a,b),return) -#endif - #if defined(__WIN32__) || defined(__GDK__) SDL_DYNAPI_PROC(int,SDL_RegisterApp,(const char *a, Uint32 b, void *c),(a,b,c),return) SDL_DYNAPI_PROC(void,SDL_UnregisterApp,(void),(),) diff --git a/src/file/SDL_rwops.c b/src/file/SDL_rwops.c index dfb43b596..2b48e557d 100644 --- a/src/file/SDL_rwops.c +++ b/src/file/SDL_rwops.c @@ -525,6 +525,27 @@ mem_close(SDL_RWops * context) /* Functions to create SDL_RWops structures from various data sources */ +#ifdef HAVE_STDIO_H +static SDL_RWops * +SDL_RWFromFP(void *fp, SDL_bool autoclose) +{ + SDL_RWops *rwops = NULL; + + rwops = SDL_AllocRW(); + if (rwops != NULL) { + rwops->size = stdio_size; + rwops->seek = stdio_seek; + rwops->read = stdio_read; + rwops->write = stdio_write; + rwops->close = stdio_close; + rwops->hidden.stdio.fp = fp; + rwops->hidden.stdio.autoclose = autoclose; + rwops->type = SDL_RWOPS_STDFILE; + } + return rwops; +} +#endif /* HAVE_STDIO_H */ + SDL_RWops * SDL_RWFromFile(const char *file, const char *mode) { @@ -614,34 +635,6 @@ SDL_RWFromFile(const char *file, const char *mode) return rwops; } -#ifdef HAVE_STDIO_H -SDL_RWops * -SDL_RWFromFP(void *fp, SDL_bool autoclose) -{ - SDL_RWops *rwops = NULL; - - rwops = SDL_AllocRW(); - if (rwops != NULL) { - rwops->size = stdio_size; - rwops->seek = stdio_seek; - rwops->read = stdio_read; - rwops->write = stdio_write; - rwops->close = stdio_close; - rwops->hidden.stdio.fp = fp; - rwops->hidden.stdio.autoclose = autoclose; - rwops->type = SDL_RWOPS_STDFILE; - } - return rwops; -} -#else -SDL_RWops * -SDL_RWFromFP(void *fp, SDL_bool autoclose) -{ - SDL_SetError("SDL not compiled with stdio support"); - return NULL; -} -#endif /* HAVE_STDIO_H */ - SDL_RWops * SDL_RWFromMem(void *mem, int size) { diff --git a/test/testautomation_rwops.c b/test/testautomation_rwops.c index 687ff75de..75b84744f 100644 --- a/test/testautomation_rwops.c +++ b/test/testautomation_rwops.c @@ -384,111 +384,6 @@ rwops_testFileWrite(void) } -/** - * @brief Tests reading from file handle - * - * \sa - * http://wiki.libsdl.org/SDL_RWFromFP - * http://wiki.libsdl.org/SDL_RWClose - * - */ -int -rwops_testFPRead(void) -{ -#ifdef HAVE_LIBC - FILE *fp; - SDL_RWops *rw; - int result; - - /* Run read tests. */ - fp = fopen(RWopsReadTestFilename, "r"); - SDLTest_AssertCheck(fp != NULL, "Verify handle from opening file '%s' in read mode is not NULL", RWopsReadTestFilename); - - /* Bail out if NULL */ - if (fp == NULL) return TEST_ABORTED; - - /* Open */ - rw = SDL_RWFromFP( fp, SDL_TRUE ); - SDLTest_AssertPass("Call to SDL_RWFromFP() succeeded"); - SDLTest_AssertCheck(rw != NULL, "Verify opening file with SDL_RWFromFP in read mode does not return NULL"); - - /* Bail out if NULL */ - if (rw == NULL) { - fclose(fp); - return TEST_ABORTED; - } - - /* Check type */ - SDLTest_AssertCheck( - rw->type == SDL_RWOPS_STDFILE, - "Verify RWops type is SDL_RWOPS_STDFILE; expected: %d, got: %" SDL_PRIu32, SDL_RWOPS_STDFILE, rw->type); - - /* Run generic tests */ - _testGenericRWopsValidations( rw, 0 ); - - /* Close handle - does fclose() */ - result = SDL_RWclose(rw); - SDLTest_AssertPass("Call to SDL_RWclose() succeeded"); - SDLTest_AssertCheck(result == 0, "Verify result value is 0; got: %d", result); - -#endif /* HAVE_LIBC */ - - return TEST_COMPLETED; -} - - -/** - * @brief Tests writing to file handle - * - * \sa - * http://wiki.libsdl.org/SDL_RWFromFP - * http://wiki.libsdl.org/SDL_RWClose - * - */ -int -rwops_testFPWrite(void) -{ -#ifdef HAVE_LIBC - FILE *fp; - SDL_RWops *rw; - int result; - - /* Run write tests. */ - fp = fopen(RWopsWriteTestFilename, "w+"); - SDLTest_AssertCheck(fp != NULL, "Verify handle from opening file '%s' in write mode is not NULL", RWopsWriteTestFilename); - - /* Bail out if NULL */ - if (fp == NULL) return TEST_ABORTED; - - /* Open */ - rw = SDL_RWFromFP( fp, SDL_TRUE ); - SDLTest_AssertPass("Call to SDL_RWFromFP() succeeded"); - SDLTest_AssertCheck(rw != NULL, "Verify opening file with SDL_RWFromFP in write mode does not return NULL"); - - /* Bail out if NULL */ - if (rw == NULL) { - fclose(fp); - return TEST_ABORTED; - } - - /* Check type */ - SDLTest_AssertCheck( - rw->type == SDL_RWOPS_STDFILE, - "Verify RWops type is SDL_RWOPS_STDFILE; expected: %d, got: %" SDL_PRIu32, SDL_RWOPS_STDFILE, rw->type); - - /* Run generic tests */ - _testGenericRWopsValidations( rw, 1 ); - - /* Close handle - does fclose() */ - result = SDL_RWclose(rw); - SDLTest_AssertPass("Call to SDL_RWclose() succeeded"); - SDLTest_AssertCheck(result == 0, "Verify result value is 0; got: %d", result); - -#endif /* HAVE_LIBC */ - - return TEST_COMPLETED; -} - /** * @brief Tests alloc and free RW context. * @@ -728,24 +623,18 @@ static const SDLTest_TestCaseReference rwopsTest5 = { (SDLTest_TestCaseFp)rwops_testFileWrite, "rwops_testFileWrite", "Test writing to a file", TEST_ENABLED }; static const SDLTest_TestCaseReference rwopsTest6 = - { (SDLTest_TestCaseFp)rwops_testFPRead, "rwops_testFPRead", "Test reading from file pointer", TEST_ENABLED }; - -static const SDLTest_TestCaseReference rwopsTest7 = - { (SDLTest_TestCaseFp)rwops_testFPWrite, "rwops_testFPWrite", "Test writing to file pointer", TEST_ENABLED }; - -static const SDLTest_TestCaseReference rwopsTest8 = { (SDLTest_TestCaseFp)rwops_testAllocFree, "rwops_testAllocFree", "Test alloc and free of RW context", TEST_ENABLED }; -static const SDLTest_TestCaseReference rwopsTest9 = +static const SDLTest_TestCaseReference rwopsTest7 = { (SDLTest_TestCaseFp)rwops_testFileWriteReadEndian, "rwops_testFileWriteReadEndian", "Test writing and reading via the Endian aware functions", TEST_ENABLED }; -static const SDLTest_TestCaseReference rwopsTest10 = +static const SDLTest_TestCaseReference rwopsTest8 = { (SDLTest_TestCaseFp)rwops_testCompareRWFromMemWithRWFromFile, "rwops_testCompareRWFromMemWithRWFromFile", "Compare RWFromMem and RWFromFile RWops for read and seek", TEST_ENABLED }; /* Sequence of RWops test cases */ static const SDLTest_TestCaseReference *rwopsTests[] = { &rwopsTest1, &rwopsTest2, &rwopsTest3, &rwopsTest4, &rwopsTest5, &rwopsTest6, - &rwopsTest7, &rwopsTest8, &rwopsTest9, &rwopsTest10, NULL + &rwopsTest7, &rwopsTest8, NULL }; /* RWops test suite (global) */