11#ifndef __FILE_COMPAT_H__
22#define __FILE_COMPAT_H__
33
4- #include "numpy/npy_3kcompat.h"
4+ #include <Python.h>
5+ #include <stdio.h>
6+ #include "numpy/npy_common.h"
7+ #include "numpy/ndarrayobject.h"
8+ #include "mplutils.h"
9+
10+ #ifdef __cplusplus
11+ extern "C" {
12+ #endif
13+
14+ #if defined(_MSC_VER ) && defined(_WIN64 ) && (_MSC_VER > 1400 )
15+ #include <io.h>
16+ #define npy_fseek _fseeki64
17+ #define npy_ftell _ftelli64
18+ #define npy_lseek _lseeki64
19+ #define mpl_off_t npy_int64
20+
21+ #if NPY_SIZEOF_INT == 8
22+ #define MPL_OFF_T_PYFMT "i"
23+ #elif NPY_SIZEOF_LONG == 8
24+ #define MPL_OFF_T_PYFMT "l"
25+ #elif NPY_SIZEOF_LONGLONG == 8
26+ #define MPL_OFF_T_PYFMT "L"
27+ #else
28+ #error Unsupported size for type off_t
29+ #endif
30+ #else
31+ #define npy_fseek fseek
32+ #define npy_ftell ftell
33+ #define npy_lseek lseek
34+ #define mpl_off_t off_t
35+
36+ #if NPY_SIZEOF_INT == NPY_SIZEOF_SHORT
37+ #define MPL_OFF_T_PYFMT "h"
38+ #elif NPY_SIZEOF_INT == NPY_SIZEOF_INT
39+ #define MPL_OFF_T_PYFMT "i"
40+ #elif NPY_SIZEOF_INT == NPY_SIZEOF_LONG
41+ #define MPL_OFF_T_PYFMT "l"
42+ #elif NPY_SIZEOF_INT == NPY_SIZEOF_LONGLONG
43+ #define MPL_OFF_T_PYFMT "L"
44+ #else
45+ #error Unsupported size for type off_t
46+ #endif
47+ #endif
548
6- #if NPY_API_VERSION < 0x4 /* corresponds to Numpy 1.5 */
749/*
850 * PyFile_* compatibility
951 */
10- #if defined( NPY_PY3K )
52+ #if PY3K
1153
1254/*
1355 * Get a FILE* handle to the file represented by the Python object
1456 */
1557static NPY_INLINE FILE *
16- npy_PyFile_Dup (PyObject * file , char * mode )
58+ mpl_PyFile_Dup (PyObject * file , char * mode , mpl_off_t * orig_pos )
1759{
1860 int fd , fd2 ;
1961 PyObject * ret , * os ;
20- Py_ssize_t pos ;
62+ mpl_off_t pos ;
2163 FILE * handle ;
64+
2265 /* Flush first to ensure things end up in the file in the correct order */
2366 ret = PyObject_CallMethod (file , "flush" , "" );
2467 if (ret == NULL ) {
@@ -29,6 +72,9 @@ npy_PyFile_Dup(PyObject *file, char *mode)
2972 if (fd == -1 ) {
3073 return NULL ;
3174 }
75+
76+ /* The handle needs to be dup'd because we have to call fclose
77+ at the end */
3278 os = PyImport_ImportModule ("os" );
3379 if (os == NULL ) {
3480 return NULL ;
@@ -40,6 +86,8 @@ npy_PyFile_Dup(PyObject *file, char *mode)
4086 }
4187 fd2 = PyNumber_AsSsize_t (ret , NULL );
4288 Py_DECREF (ret );
89+
90+ /* Convert to FILE* handle */
4391#ifdef _WIN32
4492 handle = _fdopen (fd2 , mode );
4593#else
@@ -49,6 +97,15 @@ npy_PyFile_Dup(PyObject *file, char *mode)
4997 PyErr_SetString (PyExc_IOError ,
5098 "Getting a FILE* from a Python file object failed" );
5199 }
100+
101+ /* Record the original raw file handle position */
102+ * orig_pos = npy_ftell (handle );
103+ if (* orig_pos == -1 ) {
104+ PyErr_SetString (PyExc_IOError , "obtaining file position failed" );
105+ return NULL ;
106+ }
107+
108+ /* Seek raw handle to the Python-side position */
52109 ret = PyObject_CallMethod (file , "tell" , "" );
53110 if (ret == NULL ) {
54111 fclose (handle );
@@ -60,22 +117,46 @@ npy_PyFile_Dup(PyObject *file, char *mode)
60117 fclose (handle );
61118 return NULL ;
62119 }
63- npy_fseek (handle , pos , SEEK_SET );
120+ if (npy_fseek (handle , pos , SEEK_SET ) == -1 ) {
121+ PyErr_SetString (PyExc_IOError , "seeking file failed" );
122+ return NULL ;
123+ }
64124 return handle ;
65125}
66126
67127/*
68128 * Close the dup-ed file handle, and seek the Python one to the current position
69129 */
70130static NPY_INLINE int
71- npy_PyFile_DupClose (PyObject * file , FILE * handle )
131+ mpl_PyFile_DupClose (PyObject * file , FILE * handle , mpl_off_t orig_pos )
72132{
133+ int fd ;
73134 PyObject * ret ;
74- Py_ssize_t position ;
135+ mpl_off_t position ;
136+
75137 position = npy_ftell (handle );
138+
139+ /* Close the FILE* handle */
76140 fclose (handle );
77141
78- ret = PyObject_CallMethod (file , "seek" , NPY_SSIZE_T_PYFMT "i" , position , 0 );
142+ /* Restore original file handle position, in order to not confuse
143+ Python-side data structures */
144+ fd = PyObject_AsFileDescriptor (file );
145+ if (fd == -1 ) {
146+ return -1 ;
147+ }
148+ if (npy_lseek (fd , orig_pos , SEEK_SET ) == -1 ) {
149+ PyErr_SetString (PyExc_IOError , "seeking file failed" );
150+ return -1 ;
151+ }
152+
153+ if (position == -1 ) {
154+ PyErr_SetString (PyExc_IOError , "obtaining file position failed" );
155+ return -1 ;
156+ }
157+
158+ /* Seek Python-side handle to the FILE* handle position */
159+ ret = PyObject_CallMethod (file , "seek" , MPL_OFF_T_PYFMT "i" , position , 0 );
79160 if (ret == NULL ) {
80161 return -1 ;
81162 }
@@ -84,7 +165,7 @@ npy_PyFile_DupClose(PyObject *file, FILE* handle)
84165}
85166
86167static NPY_INLINE int
87- npy_PyFile_Check (PyObject * file )
168+ mpl_PyFile_Check (PyObject * file )
88169{
89170 int fd ;
90171 fd = PyObject_AsFileDescriptor (file );
@@ -97,13 +178,14 @@ npy_PyFile_Check(PyObject *file)
97178
98179#else
99180
100- #define npy_PyFile_Dup (file , mode ) PyFile_AsFile(file)
101- #define npy_PyFile_DupClose (file , handle ) (NULL)
181+ #define mpl_PyFile_Dup (file , mode , orig_pos_p ) PyFile_AsFile(file)
182+ #define mpl_PyFile_DupClose (file , handle , orig_pos ) (0)
183+ #define mpl_PyFile_Check PyFile_Check
102184
103185#endif
104186
105187static NPY_INLINE PyObject *
106- npy_PyFile_OpenFile (PyObject * filename , const char * mode )
188+ mpl_PyFile_OpenFile (PyObject * filename , const char * mode )
107189{
108190 PyObject * open ;
109191 open = PyDict_GetItemString (PyEval_GetBuiltins (), "open" );
@@ -113,12 +195,8 @@ npy_PyFile_OpenFile(PyObject *filename, const char *mode)
113195 return PyObject_CallFunction (open , "Os" , filename , mode );
114196}
115197
116- #endif /* NPY_API_VERSION < 0x4 */
117-
118- #if NPY_API_VERSION < 0x7 /* corresponds to Numpy 1.7 */
119-
120198static NPY_INLINE int
121- npy_PyFile_CloseFile (PyObject * file )
199+ mpl_PyFile_CloseFile (PyObject * file )
122200{
123201 PyObject * ret ;
124202
@@ -130,6 +208,8 @@ npy_PyFile_CloseFile(PyObject *file)
130208 return 0 ;
131209}
132210
133- #endif /* NPY_API_VERSION < 0x7 */
211+ #ifdef __cplusplus
212+ }
213+ #endif
134214
135215#endif /* ifndef __FILE_COMPAT_H__ */
0 commit comments