0
);
}
-
-static ssize_t PyObject_AsFileHandle_read(void* cookie, char* buffer, size_t size) {
- PyObject* object = (PyObject*)cookie;
- PyObject* pybuffer = NULL;
- const char* bytes = NULL;
- Py_ssize_t bytes_read = -1;
-
- // Make sure we acquired the GIL
- PyGILState_STATE state = PyGILState_Ensure();
-
- // Read data from the object
- pybuffer = PyObject_CallMethod(object, "read", "i", size);
- if (!pybuffer)
- goto ERROR;
-
- // Handle strings
- if (PyUnicode_Check(pybuffer)) {
- bytes = PyUnicode_AsUTF8AndSize(pybuffer, &bytes_read);
- if (!bytes)
- goto ERROR;
-
- // Handle bytes
- } else if (PyBytes_Check(pybuffer)) {
- bytes = PyBytes_AsString(pybuffer);
- if (!bytes)
- goto ERROR;
-
- bytes_read = PyBytes_Size(pybuffer);
-
- // Fail on anything else
- } else {
- PyErr_SetString(PyExc_TypeError, "read() returned an unexpected data type\n");
- goto ERROR;
- }
-
- // Copy the data into the target buffer
- memcpy(buffer, bytes, bytes_read);
-
-ERROR:
- if (pybuffer)
- Py_DECREF(pybuffer);
-
- // Release the GIL
- PyGILState_Release(state);
-
- return bytes_read;
-}
-
-static ssize_t PyObject_AsFileHandle_write(void* cookie, const char* buffer, size_t size) {
- PyObject* object = (PyObject*)cookie;
- ssize_t r = 0;
-
- // Make sure we acquired the GIL
- PyGILState_STATE state = PyGILState_Ensure();
-
- PyObject* pybuffer = PyBytes_FromStringAndSize(buffer, size);
- if (!pybuffer)
- goto ERROR;
-
- PyObject* result = PyObject_CallMethod(object, "write", "b", pybuffer);
- if (!result)
- goto ERROR;
-
- // It looks like we successfully wrote the data
- r = size;
-
-ERROR:
- Py_XDECREF(pybuffer);
-
- // Release the GIL
- PyGILState_Release(state);
-
- return r;
-}
-
-static int PyObject_AsFileHandle_close(void* cookie) {
- PyObject* object = (PyObject*)cookie;
-
- // Make sure we acquired the GIL
- PyGILState_STATE state = PyGILState_Ensure();
-
- // Decrement the reference counter for the object
- Py_DECREF(object);
-
- // Release the GIL
- PyGILState_Release(state);
-
- return 0;
-}
-
-static cookie_io_functions_t PyFileHandleMethods = {
- .read = PyObject_AsFileHandle_read,
- .write = PyObject_AsFileHandle_write,
- .close = PyObject_AsFileHandle_close,
-};
-
-FILE* PyObject_AsFileHandle(PyObject* object, const char* mode) {
- // We only support reading files
- if (!mode || *mode != 'r') {
- errno = ENOTSUP;
- return NULL;
- }
-
- // Increment the reference counter for the object
- Py_INCREF(object);
-
- return fopencookie(object, mode, PyFileHandleMethods);
-}