Skip to content

Commit 45df153

Browse files
committed
Update file handling
1 parent d19fd95 commit 45df153

File tree

4 files changed

+123
-45
lines changed

4 files changed

+123
-45
lines changed

src/face.c

+21-31
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ either expressed or implied, of the FreeBSD Project.
3636
#include "charmap.h"
3737
#include "constants.h"
3838
#include "encoding.h"
39-
#include "file.h"
4039
#include "glyph.h"
4140
#include "sfntnames.h"
4241
#include "size.h"
@@ -71,26 +70,18 @@ ftpy_ConstantType Py_FT_KERNING_ConstantType;
7170
*/
7271

7372

74-
typedef struct
75-
{
76-
PyObject *py_file;
77-
FILE *fp;
78-
int close_file;
79-
} py_file_def;
80-
81-
8273
static unsigned long read_from_file_callback(
8374
FT_Stream stream, unsigned long offset, unsigned char *buffer,
8475
unsigned long count) {
8576

86-
py_file_def *def = (py_file_def *)stream->descriptor.pointer;
77+
Py_Face *self = (Py_Face *)stream->descriptor.pointer;
8778

88-
if (fseek(def->fp, offset, SEEK_SET) == -1) {
79+
if (ftpy_fseek(self->fp, offset, SEEK_SET) == -1) {
8980
return 0;
9081
}
9182

9283
if (count > 0) {
93-
return fread(buffer, 1, count, def->fp);
84+
return fread(buffer, 1, count, self->fp);
9485
}
9586

9687
return 0;
@@ -99,15 +90,16 @@ static unsigned long read_from_file_callback(
9990

10091
static void close_file_callback(FT_Stream stream)
10192
{
102-
py_file_def *def = (py_file_def *)stream->descriptor.pointer;
93+
Py_Face *self = (Py_Face *)stream->descriptor.pointer;
10394

104-
ftpy_PyFile_DupClose(def->py_file, def->fp);
95+
ftpy_PyFile_DupClose(self->py_file, self->fp, self->offset);
10596

106-
if (def->close_file) {
107-
ftpy_PyFile_CloseFile(def->py_file);
97+
if (self->close_file) {
98+
ftpy_PyFile_CloseFile(self->py_file);
10899
}
109100

110-
Py_DECREF(def->py_file);
101+
Py_DECREF(self->py_file);
102+
self->py_file = NULL;
111103
}
112104

113105

@@ -127,10 +119,10 @@ static int _py_file_to_open_args(
127119
PyObject *data = NULL;
128120
char *data_ptr;
129121
Py_ssize_t data_len;
130-
py_file_def *stream_info = NULL;
131122
long file_size;
132123
void *new_memory;
133124
PyObject *read_string = NULL;
125+
ftpy_offset_t offset;
134126

135127
int result = -1;
136128

@@ -146,25 +138,20 @@ static int _py_file_to_open_args(
146138
py_file = py_file_arg;
147139
}
148140

149-
if ((fp = ftpy_PyFile_Dup(py_file, (char *)"rb"))) {
150-
stream_info = PyMem_Malloc(sizeof(py_file_def));
151-
if (stream_info == NULL) {
152-
goto exit;
153-
}
154-
memset(stream_info, 0, sizeof(py_file_def));
155-
141+
if ((fp = ftpy_PyFile_Dup(py_file, (char *)"rb", &offset))) {
156142
Py_INCREF(py_file);
157-
stream_info->py_file = py_file;
158-
stream_info->close_file = close_file;
159-
stream_info->fp = fp;
143+
face->py_file = py_file;
144+
face->close_file = close_file;
145+
face->fp = fp;
146+
face->offset = offset;
160147
fseek(fp, 0, SEEK_END);
161-
file_size = ftell(fp);
148+
file_size = ftpy_ftell(fp);
162149
fseek(fp, 0, SEEK_SET);
163150

164151
face->stream.base = NULL;
165152
face->stream.size = (unsigned long)file_size;
166153
face->stream.pos = 0;
167-
face->stream.descriptor.pointer = stream_info;
154+
face->stream.descriptor.pointer = face;
168155
face->stream.read = &read_from_file_callback;
169156
face->stream.close = &close_file_callback;
170157

@@ -236,7 +223,10 @@ static int _py_file_to_open_args(
236223
static void
237224
Py_Face_dealloc(Py_Face* self)
238225
{
239-
FT_Done_Face(self->x);
226+
if (self->x) {
227+
FT_Done_Face(self->x);
228+
}
229+
Py_XDECREF(self->py_file);
240230
Py_XDECREF(self->filename);
241231
free(self->mem);
242232
Py_TYPE(self)->tp_clear((PyObject*)self);

src/face.h

+7
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ either expressed or implied, of the FreeBSD Project.
3232

3333
#include "freetypy.h"
3434
#include "constants.h"
35+
#include "file.h"
3536

3637

3738
typedef struct {
@@ -42,6 +43,12 @@ typedef struct {
4243
size_t mem_size;
4344
PyObject *filename;
4445
int load_flags;
46+
47+
/* For stream reading */
48+
PyObject *py_file;
49+
FILE *fp;
50+
int close_file;
51+
ftpy_offset_t offset;
4552
} Py_Face;
4653

4754

src/file.c

+55-12
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,14 @@ either expressed or implied, of the FreeBSD Project.
4444
/*
4545
* Get a FILE* handle to the file represented by the Python object
4646
*/
47-
FILE *ftpy_PyFile_Dup(PyObject *file, char *mode)
47+
FILE *ftpy_PyFile_Dup(PyObject *file, char *mode, ftpy_offset_t *orig_pos)
4848
{
4949
int fd, fd2;
5050
PyObject *ret, *os;
5151
Py_ssize_t pos;
5252
FILE *handle;
5353
/* Flush first to ensure things end up in the file in the correct order */
54-
ret = PyObject_CallMethod(file, "flush", "");
54+
ret = PyObject_CallMethod(file, (char *)"flush", (char *)"");
5555
if (ret == NULL) {
5656
return NULL;
5757
}
@@ -60,17 +60,22 @@ FILE *ftpy_PyFile_Dup(PyObject *file, char *mode)
6060
if (fd == -1) {
6161
return NULL;
6262
}
63+
64+
/* The handle needs to be dup'd because we have to call fclose
65+
at the end */
6366
os = PyImport_ImportModule("os");
6467
if (os == NULL) {
6568
return NULL;
6669
}
67-
ret = PyObject_CallMethod(os, "dup", "i", fd);
70+
ret = PyObject_CallMethod(os, (char *)"dup", (char *)"i", fd);
6871
Py_DECREF(os);
6972
if (ret == NULL) {
7073
return NULL;
7174
}
7275
fd2 = PyNumber_AsSsize_t(ret, NULL);
7376
Py_DECREF(ret);
77+
78+
/* Convert to FILE* handle */
7479
#ifdef _WIN32
7580
handle = _fdopen(fd2, mode);
7681
#else
@@ -80,7 +85,16 @@ FILE *ftpy_PyFile_Dup(PyObject *file, char *mode)
8085
PyErr_SetString(PyExc_IOError,
8186
"Getting a FILE* from a Python file object failed");
8287
}
83-
ret = PyObject_CallMethod(file, "tell", "");
88+
89+
/* Record the original raw file handle position */
90+
*orig_pos = ftpy_ftell(handle);
91+
if (*orig_pos == -1) {
92+
// handle is a stream, so we don't have to worry about this
93+
return handle;
94+
}
95+
96+
/* Seek raw handle to the Python-side position */
97+
ret = PyObject_CallMethod(file, (char *)"tell", (char *)"");
8498
if (ret == NULL) {
8599
fclose(handle);
86100
return NULL;
@@ -91,25 +105,48 @@ FILE *ftpy_PyFile_Dup(PyObject *file, char *mode)
91105
fclose(handle);
92106
return NULL;
93107
}
94-
fseek(handle, pos, SEEK_SET);
108+
109+
if (ftpy_fseek(handle, pos, SEEK_SET) == -1) {
110+
PyErr_SetString(PyExc_IOError, "seeking file failed");
111+
return NULL;
112+
}
113+
95114
return handle;
96115
}
97116

98117
/*
99118
* Close the dup-ed file handle, and seek the Python one to the current position
100119
*/
101-
int ftpy_PyFile_DupClose(PyObject *file, FILE* handle)
120+
int ftpy_PyFile_DupClose(PyObject *file, FILE* handle, ftpy_offset_t orig_pos)
102121
{
122+
int fd;
103123
PyObject *ret;
104124
Py_ssize_t position;
105-
position = ftell(handle);
125+
126+
position = ftpy_ftell(handle);
106127
fclose(handle);
107128

108-
ret = PyObject_CallMethod(file, "seek", "ni", position, 0);
109-
if (ret == NULL) {
129+
/* Restore original file handle position, in order to not confuse
130+
Python-side data structures */
131+
fd = PyObject_AsFileDescriptor(file);
132+
if (fd == -1) {
110133
return -1;
111134
}
112-
Py_DECREF(ret);
135+
136+
if (ftpy_lseek(fd, orig_pos, SEEK_SET) != -1) {
137+
if (position == -1) {
138+
PyErr_SetString(PyExc_IOError, "obtaining file position failed");
139+
return -1;
140+
}
141+
142+
/* Seek Python-side handle to the FILE* handle position */
143+
ret = PyObject_CallMethod(file, (char *)"seek", (char *)(FTPY_OFF_T_PYFMT "i"), position, 0);
144+
if (ret == NULL) {
145+
return -1;
146+
}
147+
Py_DECREF(ret);
148+
}
149+
113150
return 0;
114151
}
115152

@@ -128,16 +165,22 @@ int ftpy_PyFile_Check(PyObject *file)
128165

129166
/* Python 2.x */
130167

131-
FILE* ftpy_PyFile_Dup(PyObject *file, char *mode)
168+
FILE* ftpy_PyFile_Dup(PyObject *file, char *mode, ftpy_offset_t *orig_pos)
132169
{
133170
return PyFile_AsFile(file);
134171
}
135172

136-
int ftpy_PyFile_DupClose(PyObject *file, FILE* handle)
173+
int ftpy_PyFile_DupClose(PyObject *file, FILE* handle, ftpy_offset_t orig_pos)
137174
{
175+
// deliberately nothing
138176
return 0;
139177
}
140178

179+
int ftpy_PyFile_Check(PyObject *file)
180+
{
181+
return PyFile_Check(file);
182+
}
183+
141184
#endif
142185

143186
PyObject* ftpy_PyFile_OpenFile(PyObject *filename, const char *mode)

src/file.h

+40-2
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,46 @@ either expressed or implied, of the FreeBSD Project.
3434

3535
#include <stdio.h>
3636

37-
FILE* ftpy_PyFile_Dup(PyObject *file, char *mode);
38-
int ftpy_PyFile_DupClose(PyObject *file, FILE* handle);
37+
#ifdef __cplusplus
38+
extern "C" {
39+
#endif
40+
#if defined(_MSC_VER) && defined(_WIN64) && (_MSC_VER > 1400)
41+
#include <io.h>
42+
#define ftpy_offset_t npy_int64
43+
#define ftpy_fseek _fseeki64
44+
#define ftpy_ftell _ftelli64
45+
#define ftpy_lseek _lseeki64
46+
47+
#if NPY_SIZEOF_INT == 8
48+
#define FTPY_OFF_T_PYFMT "i"
49+
#elif NPY_SIZEOF_LONG == 8
50+
#define FTPY_OFF_T_PYFMT "l"
51+
#elif NPY_SIZEOF_LONGLONG == 8
52+
#define FTPY_OFF_T_PYFMT "L"
53+
#else
54+
#error Unsupported size for type off_t
55+
#endif
56+
#else
57+
#define ftpy_fseek fseek
58+
#define ftpy_ftell ftell
59+
#define ftpy_lseek lseek
60+
#define ftpy_offset_t off_t
61+
62+
#if NPY_SIZEOF_INT == NPY_SIZEOF_SHORT
63+
#define FTPY_OFF_T_PYFMT "h"
64+
#elif NPY_SIZEOF_INT == NPY_SIZEOF_INT
65+
#define FTPY_OFF_T_PYFMT "i"
66+
#elif NPY_SIZEOF_INT == NPY_SIZEOF_LONG
67+
#define FTPY_OFF_T_PYFMT "l"
68+
#elif NPY_SIZEOF_INT == NPY_SIZEOF_LONGLONG
69+
#define FTPY_OFF_T_PYFMT "L"
70+
#else
71+
#error Unsupported size for type off_t
72+
#endif
73+
#endif
74+
75+
FILE* ftpy_PyFile_Dup(PyObject *file, char *mode, ftpy_offset_t *orig_pos);
76+
int ftpy_PyFile_DupClose(PyObject *file, FILE* handle, ftpy_offset_t orig_pos);
3977
int ftpy_PyFile_Check(PyObject *file);
4078
PyObject* ftpy_PyFile_OpenFile(PyObject *filename, const char *mode);
4179
int ftpy_PyFile_CloseFile(PyObject *file);

0 commit comments

Comments
 (0)