From 1ebe784c07e1c3d9c0baccbf0b288b368124d45d Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Tue, 14 Jan 2014 07:46:39 -0800 Subject: [PATCH] Merge pull request #2705 from mdboom/fix-numpy-1.9 Build fails on OS X with NumPy 1.9 Conflicts: src/file_compat.h src/ft2font.cpp --- src/_backend_agg.cpp | 13 +++--- src/_png.cpp | 22 +++++----- src/file_compat.h | 118 ++++++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 118 insertions(+), 35 deletions(-) diff --git a/src/_backend_agg.cpp b/src/_backend_agg.cpp index c65af52..edbd3f2 100644 --- a/src/_backend_agg.cpp +++ b/src/_backend_agg.cpp @@ -2125,13 +2125,14 @@ RendererAgg::write_rgba(const Py::Tuple& args) args.verify_length(1); FILE *fp = NULL; + mpl_off_t offset; Py::Object py_fileobj = Py::Object(args[0]); PyObject* py_file = NULL; bool close_file = false; if (py_fileobj.isString()) { - if ((py_file = npy_PyFile_OpenFile(py_fileobj.ptr(), (char *)"wb")) == NULL) { + if ((py_file = mpl_PyFile_OpenFile(py_fileobj.ptr(), (char *)"wb")) == NULL) { throw Py::Exception(); } } @@ -2140,28 +2141,28 @@ RendererAgg::write_rgba(const Py::Tuple& args) py_file = py_fileobj.ptr(); } - if ((fp = npy_PyFile_Dup(py_file, (char *)"wb"))) + if ((fp = mpl_PyFile_Dup(py_file, (char *)"wb", &offset))) { if (fwrite(pixBuffer, 1, NUMBYTES, fp) != NUMBYTES) { - if (npy_PyFile_DupClose(py_file, fp)) { + if (mpl_PyFile_DupClose(py_file, fp, offset)) { throw Py::RuntimeError("Error closing dupe file handle"); } if (close_file) { - npy_PyFile_CloseFile(py_file); + mpl_PyFile_CloseFile(py_file); Py_DECREF(py_file); } throw Py::RuntimeError("Error writing to file"); } - if (npy_PyFile_DupClose(py_file, fp)) { + if (mpl_PyFile_DupClose(py_file, fp, offset)) { throw Py::RuntimeError("Error closing dupe file handle"); } if (close_file) { - npy_PyFile_CloseFile(py_file); + mpl_PyFile_CloseFile(py_file); Py_DECREF(py_file); } } diff --git a/src/_png.cpp b/src/_png.cpp index 840649f..1679448 100644 --- a/src/_png.cpp +++ b/src/_png.cpp @@ -105,6 +105,7 @@ Py::Object _png_module::write_png(const Py::Tuple& args) args.verify_length(4, 5); FILE *fp = NULL; + mpl_off_t offset; bool close_file = false; bool close_dup_file = false; Py::Object buffer_obj = Py::Object(args[0]); @@ -134,7 +135,7 @@ Py::Object _png_module::write_png(const Py::Tuple& args) PyObject* py_file = NULL; if (py_fileobj.isString()) { - if ((py_file = npy_PyFile_OpenFile(py_fileobj.ptr(), (char *)"wb")) == NULL) { + if ((py_file = mpl_PyFile_OpenFile(py_fileobj.ptr(), (char *)"wb")) == NULL) { throw Py::Exception(); } close_file = true; @@ -144,7 +145,7 @@ Py::Object _png_module::write_png(const Py::Tuple& args) py_file = py_fileobj.ptr(); } - if ((fp = npy_PyFile_Dup(py_file, (char *)"wb"))) + if ((fp = mpl_PyFile_Dup(py_file, (char *)"wb", &offset))) { close_dup_file = true; } @@ -240,14 +241,14 @@ Py::Object _png_module::write_png(const Py::Tuple& args) if (close_dup_file) { - if (npy_PyFile_DupClose(py_file, fp)) { + if (mpl_PyFile_DupClose(py_file, fp, offset)) { throw Py::RuntimeError("Error closing dupe file handle"); } } if (close_file) { - npy_PyFile_CloseFile(py_file); + mpl_PyFile_CloseFile(py_file); Py_DECREF(py_file); } /* Changed calls to png_destroy_write_struct to follow @@ -261,14 +262,14 @@ Py::Object _png_module::write_png(const Py::Tuple& args) delete [] row_pointers; if (close_dup_file) { - if (npy_PyFile_DupClose(py_file, fp)) { + if (mpl_PyFile_DupClose(py_file, fp, offset)) { throw Py::RuntimeError("Error closing dupe file handle"); } } if (close_file) { - npy_PyFile_CloseFile(py_file); + mpl_PyFile_CloseFile(py_file); Py_DECREF(py_file); } @@ -312,13 +313,14 @@ _png_module::_read_png(const Py::Object& py_fileobj, const bool float_result, { png_byte header[8]; // 8 is the maximum size that can be checked FILE* fp = NULL; + mpl_off_t offset; bool close_file = false; bool close_dup_file = false; PyObject *py_file = NULL; if (py_fileobj.isString()) { - if ((py_file = npy_PyFile_OpenFile(py_fileobj.ptr(), (char *)"rb")) == NULL) { + if ((py_file = mpl_PyFile_OpenFile(py_fileobj.ptr(), (char *)"rb")) == NULL) { throw Py::Exception(); } close_file = true; @@ -326,7 +328,7 @@ _png_module::_read_png(const Py::Object& py_fileobj, const bool float_result, py_file = py_fileobj.ptr(); } - if ((fp = npy_PyFile_Dup(py_file, "rb"))) + if ((fp = mpl_PyFile_Dup(py_file, "rb", &offset))) { close_dup_file = true; } @@ -574,14 +576,14 @@ _png_module::_read_png(const Py::Object& py_fileobj, const bool float_result, #endif if (close_dup_file) { - if (npy_PyFile_DupClose(py_file, fp)) { + if (mpl_PyFile_DupClose(py_file, fp, offset)) { throw Py::RuntimeError("Error closing dupe file handle"); } } if (close_file) { - npy_PyFile_CloseFile(py_file); + mpl_PyFile_CloseFile(py_file); Py_DECREF(py_file); } diff --git a/src/file_compat.h b/src/file_compat.h index fbb545d..102c8b7 100644 --- a/src/file_compat.h +++ b/src/file_compat.h @@ -1,24 +1,67 @@ #ifndef __FILE_COMPAT_H__ #define __FILE_COMPAT_H__ -#include "numpy/npy_3kcompat.h" +#include +#include +#include "numpy/npy_common.h" +#include "numpy/ndarrayobject.h" +#include "mplutils.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(_MSC_VER) && defined(_WIN64) && (_MSC_VER > 1400) + #include + #define npy_fseek _fseeki64 + #define npy_ftell _ftelli64 + #define npy_lseek _lseeki64 + #define mpl_off_t npy_int64 + + #if NPY_SIZEOF_INT == 8 + #define MPL_OFF_T_PYFMT "i" + #elif NPY_SIZEOF_LONG == 8 + #define MPL_OFF_T_PYFMT "l" + #elif NPY_SIZEOF_LONGLONG == 8 + #define MPL_OFF_T_PYFMT "L" + #else + #error Unsupported size for type off_t + #endif +#else + #define npy_fseek fseek + #define npy_ftell ftell + #define npy_lseek lseek + #define mpl_off_t off_t + + #if NPY_SIZEOF_INT == NPY_SIZEOF_SHORT + #define MPL_OFF_T_PYFMT "h" + #elif NPY_SIZEOF_INT == NPY_SIZEOF_INT + #define MPL_OFF_T_PYFMT "i" + #elif NPY_SIZEOF_INT == NPY_SIZEOF_LONG + #define MPL_OFF_T_PYFMT "l" + #elif NPY_SIZEOF_INT == NPY_SIZEOF_LONGLONG + #define MPL_OFF_T_PYFMT "L" + #else + #error Unsupported size for type off_t + #endif +#endif -#if NPY_API_VERSION < 0x4 /* corresponds to Numpy 1.5 */ /* * PyFile_* compatibility */ -#if defined(NPY_PY3K) +#if PY3K /* * Get a FILE* handle to the file represented by the Python object */ static NPY_INLINE FILE* -npy_PyFile_Dup(PyObject *file, char *mode) +mpl_PyFile_Dup(PyObject *file, char *mode, mpl_off_t *orig_pos) { int fd, fd2; PyObject *ret, *os; - Py_ssize_t pos; + mpl_off_t pos; FILE *handle; + /* Flush first to ensure things end up in the file in the correct order */ ret = PyObject_CallMethod(file, "flush", ""); if (ret == NULL) { @@ -29,6 +72,9 @@ npy_PyFile_Dup(PyObject *file, char *mode) if (fd == -1) { return NULL; } + + /* The handle needs to be dup'd because we have to call fclose + at the end */ os = PyImport_ImportModule("os"); if (os == NULL) { return NULL; @@ -40,6 +86,8 @@ npy_PyFile_Dup(PyObject *file, char *mode) } fd2 = PyNumber_AsSsize_t(ret, NULL); Py_DECREF(ret); + + /* Convert to FILE* handle */ #ifdef _WIN32 handle = _fdopen(fd2, mode); #else @@ -49,6 +97,15 @@ npy_PyFile_Dup(PyObject *file, char *mode) PyErr_SetString(PyExc_IOError, "Getting a FILE* from a Python file object failed"); } + + /* Record the original raw file handle position */ + *orig_pos = npy_ftell(handle); + if (*orig_pos == -1) { + PyErr_SetString(PyExc_IOError, "obtaining file position failed"); + return NULL; + } + + /* Seek raw handle to the Python-side position */ ret = PyObject_CallMethod(file, "tell", ""); if (ret == NULL) { fclose(handle); @@ -60,7 +117,10 @@ npy_PyFile_Dup(PyObject *file, char *mode) fclose(handle); return NULL; } - npy_fseek(handle, pos, SEEK_SET); + if (npy_fseek(handle, pos, SEEK_SET) == -1) { + PyErr_SetString(PyExc_IOError, "seeking file failed"); + return NULL; + } return handle; } @@ -68,14 +128,35 @@ npy_PyFile_Dup(PyObject *file, char *mode) * Close the dup-ed file handle, and seek the Python one to the current position */ static NPY_INLINE int -npy_PyFile_DupClose(PyObject *file, FILE* handle) +mpl_PyFile_DupClose(PyObject *file, FILE* handle, mpl_off_t orig_pos) { + int fd; PyObject *ret; - Py_ssize_t position; + mpl_off_t position; + position = npy_ftell(handle); + + /* Close the FILE* handle */ fclose(handle); - ret = PyObject_CallMethod(file, "seek", NPY_SSIZE_T_PYFMT "i", position, 0); + /* Restore original file handle position, in order to not confuse + Python-side data structures */ + fd = PyObject_AsFileDescriptor(file); + if (fd == -1) { + return -1; + } + if (npy_lseek(fd, orig_pos, SEEK_SET) == -1) { + PyErr_SetString(PyExc_IOError, "seeking file failed"); + return -1; + } + + if (position == -1) { + PyErr_SetString(PyExc_IOError, "obtaining file position failed"); + return -1; + } + + /* Seek Python-side handle to the FILE* handle position */ + ret = PyObject_CallMethod(file, "seek", MPL_OFF_T_PYFMT "i", position, 0); if (ret == NULL) { return -1; } @@ -84,7 +165,7 @@ npy_PyFile_DupClose(PyObject *file, FILE* handle) } static NPY_INLINE int -npy_PyFile_Check(PyObject *file) +mpl_PyFile_Check(PyObject *file) { int fd; fd = PyObject_AsFileDescriptor(file); @@ -97,13 +178,14 @@ npy_PyFile_Check(PyObject *file) #else -#define npy_PyFile_Dup(file, mode) PyFile_AsFile(file) -#define npy_PyFile_DupClose(file, handle) (0) +#define mpl_PyFile_Dup(file, mode, orig_pos_p) PyFile_AsFile(file) +#define mpl_PyFile_DupClose(file, handle, orig_pos) (0) +#define mpl_PyFile_Check PyFile_Check #endif static NPY_INLINE PyObject* -npy_PyFile_OpenFile(PyObject *filename, const char *mode) +mpl_PyFile_OpenFile(PyObject *filename, const char *mode) { PyObject *open; open = PyDict_GetItemString(PyEval_GetBuiltins(), "open"); @@ -113,12 +195,8 @@ npy_PyFile_OpenFile(PyObject *filename, const char *mode) return PyObject_CallFunction(open, "Os", filename, mode); } -#endif /* NPY_API_VERSION < 0x4 */ - -#if NPY_API_VERSION < 0x7 /* corresponds to Numpy 1.7 */ - static NPY_INLINE int -npy_PyFile_CloseFile(PyObject *file) +mpl_PyFile_CloseFile(PyObject *file) { PyObject *ret; @@ -130,6 +208,8 @@ npy_PyFile_CloseFile(PyObject *file) return 0; } -#endif /* NPY_API_VERSION < 0x7 */ +#ifdef __cplusplus +} +#endif #endif /* ifndef __FILE_COMPAT_H__ */