/*
pygame - Python Game Library
Copyright (C) 2000-2001 Pete Shinners
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Pete Shinners
pete@shinners.org
*/
/*
* SDL_RWops support for python objects
*/
#define NO_PYGAME_C_API
#define PYGAMEAPI_RWOBJECT_INTERNAL
#include "pygame.h"
typedef struct
{
PyObject* read;
PyObject* write;
PyObject* seek;
PyObject* tell;
PyObject* close;
#ifdef WITH_THREAD
PyThreadState* thread;
#endif
}RWHelper;
static int rw_seek(SDL_RWops* context, int offset, int whence);
static int rw_read(SDL_RWops* context, void* ptr, int size, int maxnum);
static int rw_write(SDL_RWops* context, const void* ptr, int size, int maxnum);
static int rw_close(SDL_RWops* context);
#ifdef WITH_THREAD
static int rw_seek_th(SDL_RWops* context, int offset, int whence);
static int rw_read_th(SDL_RWops* context, void* ptr, int size, int maxnum);
static int rw_write_th(SDL_RWops* context, const void* ptr, int size, int maxnum);
static int rw_close_th(SDL_RWops* context);
#endif
static SDL_RWops* get_standard_rwop(PyObject* obj)
{
if(PyString_Check(obj) || PyUnicode_Check(obj))
{
int result;
char* name;
PyObject* tuple = PyTuple_New(1);
PyTuple_SET_ITEM(tuple, 0, obj);
Py_INCREF(obj);
if(!tuple) return NULL;
result = PyArg_ParseTuple(tuple, "s", &name);
Py_DECREF(tuple);
if(!result)
return NULL;
return SDL_RWFromFile(name, "rb");
}
else if(PyFile_Check(obj))
return SDL_RWFromFP(PyFile_AsFile(obj), 0);
return NULL;
}
static void fetch_object_methods(RWHelper* helper, PyObject* obj)
{
helper->read = helper->write = helper->seek = helper->tell = helper->close = NULL;
if(PyObject_HasAttrString(obj, "read"))
{
helper->read = PyObject_GetAttrString(obj, "read");
if(helper->read && !PyCallable_Check(helper->read))
helper->read = NULL;
}
if(PyObject_HasAttrString(obj, "write"))
{
helper->write = PyObject_GetAttrString(obj, "write");
if(helper->write && !PyCallable_Check(helper->write))
helper->write = NULL;
}
if(PyObject_HasAttrString(obj, "seek"))
{
helper->seek = PyObject_GetAttrString(obj, "seek");
if(helper->seek && !PyCallable_Check(helper->seek))
helper->seek = NULL;
}
if(PyObject_HasAttrString(obj, "tell"))
{
helper->tell = PyObject_GetAttrString(obj, "tell");
if(helper->tell && !PyCallable_Check(helper->tell))
helper->tell = NULL;
}
if(PyObject_HasAttrString(obj, "close"))
{
helper->close = PyObject_GetAttrString(obj, "close");
if(helper->close && !PyCallable_Check(helper->close))
helper->close = NULL;
}
}
static SDL_RWops* RWopsFromPython(PyObject* obj)
{
SDL_RWops* rw;
RWHelper* helper;
if(!obj)
return (SDL_RWops*)RAISE(PyExc_TypeError, "Invalid filetype object");
rw = get_standard_rwop(obj);
if(rw) return rw;
helper = PyMem_New(RWHelper, 1);
fetch_object_methods(helper, obj);
rw = SDL_AllocRW();
rw->hidden.unknown.data1 = (void*)helper;
rw->seek = rw_seek;
rw->read = rw_read;
rw->write = rw_write;
rw->close = rw_close;
return rw;
}
static int RWopsCheckPython(SDL_RWops* rw)
{
return rw->close == rw_close;
}
static int rw_seek(SDL_RWops* context, int offset, int whence)
{
RWHelper* helper = (RWHelper*)context->hidden.unknown.data1;
PyObject* result;
int retval;
if(!helper->seek || !helper->tell)
return -1;
if(!(offset == 0 && whence == SEEK_CUR)) /*being called only for 'tell'*/
{
result = PyObject_CallFunction(helper->seek, "ii", offset, whence);
if(!result)
return -1;
Py_DECREF(result);
}
result = PyObject_CallFunction(helper->tell, NULL);
if(!result)
return -1;
retval = PyInt_AsLong(result);
Py_DECREF(result);
return retval;
}
static int rw_read(SDL_RWops* context, void* ptr, int size, int maxnum)
{
RWHelper* helper = (RWHelper*)context->hidden.unknown.data1;
PyObject* result;
int retval;
if(!helper->read)
return -1;
result = PyObject_CallFunction(helper->read, "i", size * maxnum);
if(!result)
return -1;
if(!PyString_Check(result))
{
Py_DECREF(result);
return -1;
}
retval = PyString_GET_SIZE(result);
memcpy(ptr, PyString_AsString(result), retval);
retval /= size;
Py_DECREF(result);
return retval;
}
static int rw_write(SDL_RWops* context, const void* ptr, int size, int num)
{
RWHelper* helper = (RWHelper*)context->hidden.unknown.data1;
PyObject* result;
if(!helper->write)
return -1;
result = PyObject_CallFunction(helper->write, "s#", ptr, size * num);
if(!result)
return -1;
Py_DECREF(result);
return num;
}
static int rw_close(SDL_RWops* context)
{
RWHelper* helper = (RWHelper*)context->hidden.unknown.data1;
PyObject* result;
int retval = 0;
if(helper->close)
{
result = PyObject_CallFunction(helper->close, NULL);
if(result)
retval = -1;
Py_XDECREF(result);
}
Py_XDECREF(helper->seek);
Py_XDECREF(helper->tell);
Py_XDECREF(helper->write);
Py_XDECREF(helper->read);
Py_XDECREF(helper->close);
PyMem_Del(helper);
SDL_FreeRW(context);
return retval;
}
static SDL_RWops* RWopsFromPythonThreaded(PyObject* obj)
{
SDL_RWops* rw;
RWHelper* helper;
PyInterpreterState* interp;
PyThreadState* thread;
if(!obj)
return (SDL_RWops*)RAISE(PyExc_TypeError, "Invalid filetype object");
rw = get_standard_rwop(obj);
if(rw)
return rw;
#ifndef WITH_THREAD
return (SDL_RWops*)RAISE(PyExc_NotImplementedError, "Python built without thread support");
#else
helper = PyMem_New(RWHelper, 1);
fetch_object_methods(helper, obj);
rw = SDL_AllocRW();
rw->hidden.unknown.data1 = (void*)helper;
rw->seek = rw_seek_th;
rw->read = rw_read_th;
rw->write = rw_write_th;
rw->close = rw_close_th;
PyEval_InitThreads();
thread = PyThreadState_Get();
interp = thread->interp;
helper->thread = PyThreadState_New(interp);
return rw;
#endif
}
static int RWopsCheckPythonThreaded(SDL_RWops* rw)
{
#ifdef WITH_THREAD
return rw->close == rw_close_th;
#else
return 0;
#endif
}
#ifdef WITH_THREAD
static int rw_seek_th(SDL_RWops* context, int offset, int whence)
{
RWHelper* helper = (RWHelper*)context->hidden.unknown.data1;
PyObject* result;
int retval;
PyThreadState* oldstate;
if(!helper->seek || !helper->tell)
return -1;
PyEval_AcquireLock();
oldstate = PyThreadState_Swap(helper->thread);
if(!(offset == 0 && whence == SEEK_CUR)) /*being called only for 'tell'*/
{
result = PyObject_CallFunction(helper->seek, "ii", offset, whence);
if(!result)
return -1;
Py_DECREF(result);
}
result = PyObject_CallFunction(helper->tell, NULL);
if(!result)
return -1;
retval = PyInt_AsLong(result);
Py_DECREF(result);
PyThreadState_Swap(oldstate);
PyEval_ReleaseLock();
return retval;
}
static int rw_read_th(SDL_RWops* context, void* ptr, int size, int maxnum)
{
RWHelper* helper = (RWHelper*)context->hidden.unknown.data1;
PyObject* result;
int retval;
PyThreadState* oldstate;
if(!helper->read)
return -1;
PyEval_AcquireLock();
oldstate = PyThreadState_Swap(helper->thread);
result = PyObject_CallFunction(helper->read, "i", size * maxnum);
if(!result)
return -1;
if(!PyString_Check(result))
{
Py_DECREF(result);
return -1;
}
retval = PyString_GET_SIZE(result);
memcpy(ptr, PyString_AsString(result), retval);
retval /= size;
Py_DECREF(result);
PyThreadState_Swap(oldstate);
PyEval_ReleaseLock();
return retval;
}
static int rw_write_th(SDL_RWops* context, const void* ptr, int size, int num)
{
RWHelper* helper = (RWHelper*)context->hidden.unknown.data1;
PyObject* result;
PyThreadState* oldstate;
if(!helper->write)
return -1;
PyEval_AcquireLock();
oldstate = PyThreadState_Swap(helper->thread);
result = PyObject_CallFunction(helper->write, "s#", ptr, size * num);
if(!result)
return -1;
Py_DECREF(result);
PyThreadState_Swap(oldstate);
PyEval_ReleaseLock();
return num;
}
static int rw_close_th(SDL_RWops* context)
{
RWHelper* helper = (RWHelper*)context->hidden.unknown.data1;
PyObject* result;
int retval = 0;
PyThreadState* oldstate;
PyEval_AcquireLock();
oldstate = PyThreadState_Swap(helper->thread);
if(helper->close)
{
result = PyObject_CallFunction(helper->close, NULL);
if(result)
retval = -1;
Py_XDECREF(result);
}
Py_XDECREF(helper->seek);
Py_XDECREF(helper->tell);
Py_XDECREF(helper->write);
Py_XDECREF(helper->read);
Py_XDECREF(helper->close);
PyMem_Del(helper);
PyThreadState_Swap(oldstate);
PyThreadState_Clear(helper->thread);
PyThreadState_Delete(helper->thread);
PyEval_ReleaseLock();
SDL_FreeRW(context);
return retval;
}
#endif
static PyMethodDef rwobject__builtins__[] =
{
{NULL, NULL}
};
PYGAME_EXPORT
void initrwobject(void)
{
PyObject *module, *dict, *apiobj;
static void* c_api[PYGAMEAPI_RWOBJECT_NUMSLOTS];
/* Create the module and add the functions */
module = Py_InitModule3("rwobject", rwobject__builtins__, "SDL_RWops support");
dict = PyModule_GetDict(module);
/* export the c api */
c_api[0] = RWopsFromPython;
c_api[1] = RWopsCheckPython;
c_api[2] = RWopsFromPythonThreaded;
c_api[3] = RWopsCheckPythonThreaded;
apiobj = PyCObject_FromVoidPtr(c_api, NULL);
PyDict_SetItemString(dict, PYGAMEAPI_LOCAL_ENTRY, apiobj);
Py_DECREF(apiobj);
}
syntax highlighted by Code2HTML, v. 0.9.1