Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify pygame resource loaders #2695

Merged
merged 8 commits into from Oct 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 7 additions & 1 deletion docs/reST/c_api/rwobject.rst
Expand Up @@ -31,11 +31,17 @@ Header file: src_c/include/pygame.h
If threads are available, the Python GIL is acquired before calling any of the *obj* methods.
On error raise a Python exception and return ``NULL``.

.. c:function:: int pgRWops_CheckObject(SDL_RWops *rw)
.. c:function:: int pgRWops_IsFileObject(SDL_RWops *rw)

Return true if *rw* is a Python file-like object wrapper returned by :c:func:`pgRWops_FromObject`
or :c:func:`pgRWops_FromFileObject`.

.. c:function:: char* pgRWops_GetFileExtension(SDL_RWops *rw)

Return a string that contains the file extension of the original file
loaded into the SDL_RWops object, or NULL if the SDL_RWops object comes
from a file object.

.. c:function:: int pgRWops_ReleaseObject(SDL_RWops *context)

Free a SDL_RWops struct. If it is attached to a Python file-like object, decrement its
Expand Down
2 changes: 1 addition & 1 deletion src_c/_pygame.h
Expand Up @@ -344,7 +344,7 @@ struct pgColorObject {
#define PYGAMEAPI_DISPLAY_NUMSLOTS 2
#define PYGAMEAPI_SURFACE_NUMSLOTS 4
#define PYGAMEAPI_SURFLOCK_NUMSLOTS 8
#define PYGAMEAPI_RWOBJECT_NUMSLOTS 6
#define PYGAMEAPI_RWOBJECT_NUMSLOTS 7
#define PYGAMEAPI_PIXELARRAY_NUMSLOTS 2
#define PYGAMEAPI_COLOR_NUMSLOTS 5
#define PYGAMEAPI_MATH_NUMSLOTS 2
Expand Down
25 changes: 5 additions & 20 deletions src_c/image.c
Expand Up @@ -79,29 +79,14 @@ image_load_basic(PyObject *self, PyObject *obj)
PyObject *final;
PyObject *oencoded;
SDL_Surface *surf;
SDL_RWops *rw;

oencoded = pg_EncodeString(obj, "UTF-8", NULL, pgExc_SDLError);
if (oencoded == NULL) {
SDL_RWops *rw = pgRWops_FromObject(obj);
if (rw == NULL) {
return NULL;
}

if (oencoded != Py_None) {
Py_BEGIN_ALLOW_THREADS;
surf = SDL_LoadBMP(Bytes_AS_STRING(oencoded));
Py_END_ALLOW_THREADS;
Py_DECREF(oencoded);
}
else {
Py_DECREF(oencoded);
rw = pgRWops_FromFileObject(obj);
if (rw == NULL) {
return NULL;
}
Py_BEGIN_ALLOW_THREADS;
surf = SDL_LoadBMP_RW(rw, 1);
Py_END_ALLOW_THREADS;
}
Py_BEGIN_ALLOW_THREADS;
surf = SDL_LoadBMP_RW(rw, 1);
Py_END_ALLOW_THREADS;

if (surf == NULL) {
return RAISE(pgExc_SDLError, SDL_GetError());
Expand Down
129 changes: 23 additions & 106 deletions src_c/imageext.c
Expand Up @@ -108,127 +108,44 @@ image_load_ext(PyObject *self, PyObject *arg)
{
PyObject *obj;
PyObject *final;
PyObject *oencoded;
PyObject *oname;
size_t namelen;
const char *name = NULL;
const char *cext;
char *ext = NULL;
SDL_Surface *surf;
SDL_RWops *rw;
SDL_RWops *rw = NULL;
int lock_mutex = 0;

if (!PyArg_ParseTuple(arg, "O|s", &obj, &name)) {
return NULL;
}

oencoded = pg_EncodeString(obj, "UTF-8", NULL, pgExc_SDLError);
if (oencoded == NULL) {
rw = pgRWops_FromObject(obj);
if (rw == NULL) /* stop on NULL, error already set */
return NULL;
}
if (oencoded != Py_None) {
name = Bytes_AS_STRING(oencoded);
ext = pgRWops_GetFileExtension(rw);
if (name) /* override extension with namehint if given */
ext = find_extension(name);

#ifdef WITH_THREAD
namelen = Bytes_GET_SIZE(oencoded);
Py_BEGIN_ALLOW_THREADS;
if (namelen > 4 && !strcasecmp(name + namelen - 4, ".gif")) {
/* using multiple threads does not work for (at least) SDL_image <= 2.0.4 */
SDL_LockMutex(_pg_img_mutex);
surf = IMG_Load(name);
SDL_UnlockMutex(_pg_img_mutex);
}
else {
surf = IMG_Load(name);
}
Py_END_ALLOW_THREADS;
#else /* ~WITH_THREAD */
surf = IMG_Load(name);
#endif /* WITH_THREAD */
Py_DECREF(oencoded);
if (ext)
lock_mutex = !strcasecmp(ext, "gif");
Py_BEGIN_ALLOW_THREADS;
if (0) {
/* using multiple threads does not work for (at least) SDL_image <= 2.0.4 */
SDL_LockMutex(_pg_img_mutex);
surf = IMG_LoadTyped_RW(rw, 1, ext);
SDL_UnlockMutex(_pg_img_mutex);
}
else {
#ifdef WITH_THREAD
int lock_mutex = 0;
#endif /* WITH_THREAD */
Py_DECREF(oencoded);
oencoded = NULL;
#if PY2
if (name == NULL && PyFile_Check(obj)) {
oencoded = PyFile_Name(obj);
if (oencoded == NULL) {
/* This should never happen */
return NULL;
}
Py_INCREF(oencoded);
name = Bytes_AS_STRING(oencoded);
}
#endif
if (name == NULL) {
oname = PyObject_GetAttrString(obj, "name");
if (oname != NULL) {
oencoded = pg_EncodeString(oname, "UTF-8", NULL, NULL);
Py_DECREF(oname);
if (oencoded == NULL) {
return NULL;
}
if (oencoded != Py_None) {
name = Bytes_AS_STRING(oencoded);
}
}
else {
PyErr_Clear();
}
}
rw = pgRWops_FromFileObject(obj);
if (rw == NULL) {
Py_XDECREF(oencoded);
return NULL;
}

cext = find_extension(name);
if (cext != NULL) {
ext = (char *)PyMem_Malloc(strlen(cext) + 1);
if (ext == NULL) {
Py_XDECREF(oencoded);
return PyErr_NoMemory();
}
strcpy(ext, cext);
#ifdef WITH_THREAD
lock_mutex = !strcasecmp(ext, "gif");
#endif /* WITH_THREAD */
}
Py_XDECREF(oencoded);
#ifdef WITH_THREAD
Py_BEGIN_ALLOW_THREADS;
if (lock_mutex) {
/* using multiple threads does not work for (at least) SDL_image <= 2.0.4 */
SDL_LockMutex(_pg_img_mutex);
surf = IMG_LoadTyped_RW(rw, 1, ext);
SDL_UnlockMutex(_pg_img_mutex);
}
else {
surf = IMG_LoadTyped_RW(rw, 1, ext);
}
Py_END_ALLOW_THREADS;
#else /* ~WITH_THREAD */
surf = IMG_LoadTyped_RW(rw, 1, ext);
#endif /* ~WITH_THREAD */
PyMem_Free(ext);
}
Py_END_ALLOW_THREADS;
#else /* ~WITH_THREAD */
surf = IMG_LoadTyped_RW(rw, 1, ext);
#endif /* ~WITH_THREAD */

if (surf == NULL)
return RAISE(pgExc_SDLError, IMG_GetError());

if (surf == NULL){
if (!strncmp(IMG_GetError(), "Couldn't open", 12)){
SDL_ClearError();
#if PY3
PyErr_SetString(PyExc_FileNotFoundError, "No such file or directory.");
#else
PyErr_SetString(PyExc_IOError, "No such file or directory.");
#endif
return NULL;
}
else{
return RAISE(pgExc_SDLError, IMG_GetError());
}
}
final = (PyObject *)pgSurface_New(surf);
if (final == NULL) {
SDL_FreeSurface(surf);
Expand Down
4 changes: 4 additions & 0 deletions src_c/include/_pygame.h
Expand Up @@ -538,6 +538,10 @@ typedef struct pgEventObject pgEventObject;
(*(int (*)(SDL_RWops *)) \
PYGAMEAPI_GET_SLOT(rwobject, 5))

#define pgRWops_GetFileExtension \
(*(char * (*)(SDL_RWops *)) \
PYGAMEAPI_GET_SLOT(rwobject, 6))

#define import_pygame_rwobject() IMPORT_PYGAME_MODULE(rwobject)

#endif
Expand Down
62 changes: 27 additions & 35 deletions src_c/music.c
Expand Up @@ -311,6 +311,9 @@ _get_type_from_hint(char *namehint)
namehint = dot + 1;
}
}
else {
return type;
}

/* Copied almost directly from SDL_mixer. Originally meant to check file extensions
* to get a hint of what music type it should be.
Expand Down Expand Up @@ -368,45 +371,33 @@ _get_type_from_hint(char *namehint)

Mix_Music *
_load_music(PyObject *obj, char *namehint) {
PyObject *oencoded;
Mix_Music *new_music = NULL;
const char *name;

oencoded = pg_EncodeString(obj, "UTF-8", NULL, pgExc_SDLError);
if (oencoded == Py_None) {
SDL_RWops *rw;

Py_DECREF(oencoded);
if (!PG_CHECK_THREADS())
return NULL;
rw = pgRWops_FromFileObject(obj);
if (rw == NULL) {
return NULL;
}
Py_BEGIN_ALLOW_THREADS
#if IS_SDLv1
new_music = Mix_LoadMUS_RW(rw);
#else /* IS_SDLv2 */
if (namehint)
new_music = Mix_LoadMUSType_RW(rw, _get_type_from_hint(namehint), SDL_TRUE);
else
new_music = Mix_LoadMUS_RW(rw, SDL_TRUE);
#endif /* IS_SDLv2 */
Py_END_ALLOW_THREADS
}
else if (oencoded != NULL) {
name = Bytes_AS_STRING(oencoded);
char* ext = NULL;
SDL_RWops *rw = NULL;
PyObject* _type = NULL;
PyObject* error = NULL;
PyObject* _traceback = NULL;

Py_BEGIN_ALLOW_THREADS
new_music = Mix_LoadMUS(name);
Py_END_ALLOW_THREADS
MIXER_INIT_CHECK();

Py_DECREF(oencoded);
}
else {
rw = pgRWops_FromObject(obj);
if (rw == NULL) { /* stop on NULL, error already set is what we SHOULD do */
PyErr_Fetch(&_type, &error, &_traceback);
PyErr_SetObject(pgExc_SDLError, error);
Py_XDECREF(_type);
Py_XDECREF(_traceback);
return NULL;
}
if (namehint) {
ext = namehint;
} else {
ext = pgRWops_GetFileExtension(rw);
}

Py_BEGIN_ALLOW_THREADS
new_music = Mix_LoadMUSType_RW(rw, _get_type_from_hint(ext), SDL_TRUE);
Py_END_ALLOW_THREADS

if (!new_music) {
PyErr_SetString(pgExc_SDLError, SDL_GetError());
return NULL;
Expand All @@ -432,7 +423,9 @@ music_load(PyObject *self, PyObject *args, PyObject *keywds)
if (new_music == NULL) // meaning it has an error to return
return NULL;

Py_BEGIN_ALLOW_THREADS if (current_music != NULL) {
Py_BEGIN_ALLOW_THREADS
if (current_music != NULL)
{
Mix_FreeMusic(current_music);
current_music = NULL;
}
Expand All @@ -444,7 +437,6 @@ music_load(PyObject *self, PyObject *args, PyObject *keywds)
Py_END_ALLOW_THREADS

current_music = new_music;

Py_RETURN_NONE;
}

Expand Down