@@ -13,39 +13,35 @@ static const Py_ssize_t MASK_LEN = 4;
13
13
/* Similar to PyBytes_AsStringAndSize, but accepts more types */
14
14
15
15
static int
16
- _PyBytesLike_AsStringAndSize (PyObject * obj , char * * buffer , Py_ssize_t * length )
16
+ _PyBytesLike_AsStringAndSize (PyObject * obj , PyObject * * tmp , char * * buffer , Py_ssize_t * length )
17
17
{
18
- // This supports bytes, bytearrays, and C-contiguous memoryview objects,
19
- // which are the most useful data structures for handling byte streams.
20
- // websockets.framing.prepare_data() returns only values of these types.
21
- // Any object implementing the buffer protocol could be supported, however
22
- // that would require allocation or copying memory, which is expensive.
18
+ // This supports bytes, bytearrays, and memoryview objects,
19
+ // which are common data structures for handling byte streams.
20
+ // websockets.framing.prepare_data() returns only these types.
21
+ // If *tmp isn't NULL, the caller gets a new reference.
23
22
if (PyBytes_Check (obj ))
24
23
{
24
+ * tmp = NULL ;
25
25
* buffer = PyBytes_AS_STRING (obj );
26
26
* length = PyBytes_GET_SIZE (obj );
27
27
}
28
28
else if (PyByteArray_Check (obj ))
29
29
{
30
+ * tmp = NULL ;
30
31
* buffer = PyByteArray_AS_STRING (obj );
31
32
* length = PyByteArray_GET_SIZE (obj );
32
33
}
33
34
else if (PyMemoryView_Check (obj ))
34
35
{
35
- Py_buffer * mv_buf ;
36
- mv_buf = PyMemoryView_GET_BUFFER (obj );
37
- if (PyBuffer_IsContiguous (mv_buf , 'C' ))
38
- {
39
- * buffer = mv_buf -> buf ;
40
- * length = mv_buf -> len ;
41
- }
42
- else
36
+ * tmp = PyMemoryView_GetContiguous (obj , PyBUF_READ , 'C' );
37
+ if (* tmp == NULL )
43
38
{
44
- PyErr_Format (
45
- PyExc_TypeError ,
46
- "expected a contiguous memoryview" );
47
39
return -1 ;
48
40
}
41
+ Py_buffer * mv_buf ;
42
+ mv_buf = PyMemoryView_GET_BUFFER (* tmp );
43
+ * buffer = mv_buf -> buf ;
44
+ * length = mv_buf -> len ;
49
45
}
50
46
else
51
47
{
@@ -74,15 +70,17 @@ apply_mask(PyObject *self, PyObject *args, PyObject *kwds)
74
70
// A pointer to a char * + length will be extracted from the data and mask
75
71
// arguments, possibly via a Py_buffer.
76
72
73
+ PyObject * input_tmp = NULL ;
77
74
char * input ;
78
75
Py_ssize_t input_len ;
76
+ PyObject * mask_tmp = NULL ;
79
77
char * mask ;
80
78
Py_ssize_t mask_len ;
81
79
82
80
// Initialize a PyBytesObject then get a pointer to the underlying char *
83
81
// in order to avoid an extra memory copy in PyBytes_FromStringAndSize.
84
82
85
- PyObject * result ;
83
+ PyObject * result = NULL ;
86
84
char * output ;
87
85
88
86
// Other variables.
@@ -94,31 +92,31 @@ apply_mask(PyObject *self, PyObject *args, PyObject *kwds)
94
92
if (!PyArg_ParseTupleAndKeywords (
95
93
args , kwds , "OO" , kwlist , & input_obj , & mask_obj ))
96
94
{
97
- return NULL ;
95
+ goto exit ;
98
96
}
99
97
100
- if (_PyBytesLike_AsStringAndSize (input_obj , & input , & input_len ) == -1 )
98
+ if (_PyBytesLike_AsStringAndSize (input_obj , & input_tmp , & input , & input_len ) == -1 )
101
99
{
102
- return NULL ;
100
+ goto exit ;
103
101
}
104
102
105
- if (_PyBytesLike_AsStringAndSize (mask_obj , & mask , & mask_len ) == -1 )
103
+ if (_PyBytesLike_AsStringAndSize (mask_obj , & mask_tmp , & mask , & mask_len ) == -1 )
106
104
{
107
- return NULL ;
105
+ goto exit ;
108
106
}
109
107
110
108
if (mask_len != MASK_LEN )
111
109
{
112
110
PyErr_SetString (PyExc_ValueError , "mask must contain 4 bytes" );
113
- return NULL ;
111
+ goto exit ;
114
112
}
115
113
116
114
// Create output.
117
115
118
116
result = PyBytes_FromStringAndSize (NULL , input_len );
119
117
if (result == NULL )
120
118
{
121
- return NULL ;
119
+ goto exit ;
122
120
}
123
121
124
122
// Since we juste created result, we don't need error checks.
@@ -172,6 +170,9 @@ apply_mask(PyObject *self, PyObject *args, PyObject *kwds)
172
170
output [i ] = input [i ] ^ mask [i & (MASK_LEN - 1 )];
173
171
}
174
172
173
+ exit :
174
+ Py_XDECREF (input_tmp );
175
+ Py_XDECREF (mask_tmp );
175
176
return result ;
176
177
177
178
}
0 commit comments