@@ -109,6 +109,8 @@ compress (PyObject * Py_UNUSED (self), PyObject * args, PyObject * kwargs)
109
109
char * dest , * dest_start ;
110
110
compression_type comp ;
111
111
int output_size ;
112
+ Py_buffer source ;
113
+ int source_size ;
112
114
113
115
#if IS_PY3
114
116
static char * argnames [] = {
@@ -121,36 +123,14 @@ compress (PyObject * Py_UNUSED (self), PyObject * args, PyObject * kwargs)
121
123
NULL
122
124
};
123
125
int return_bytearray = 0 ;
124
- PyObject * py_source ;
125
- Py_ssize_t source_size ;
126
- char * source ;
127
- if (!PyArg_ParseTupleAndKeywords (args , kwargs , "O|spiip" , argnames ,
128
- & py_source ,
129
- & mode , & store_size , & acceleration ,
130
- & compression , & return_bytearray ))
126
+
127
+ if (!PyArg_ParseTupleAndKeywords (args , kwargs , "y*|siiip" , argnames ,
128
+ & source ,
129
+ & mode , & store_size , & acceleration , & compression ,
130
+ & return_bytearray ))
131
131
{
132
132
return NULL ;
133
133
}
134
- if (PyByteArray_Check (py_source ))
135
- {
136
- source = PyByteArray_AsString (py_source );
137
- if (source == NULL )
138
- {
139
- PyErr_SetString (PyExc_ValueError , "Failed to access source bytearray object" );
140
- return NULL ;
141
- }
142
- source_size = PyByteArray_GET_SIZE (py_source );
143
- }
144
- else
145
- {
146
- source = PyBytes_AsString (py_source );
147
- if (source == NULL )
148
- {
149
- PyErr_SetString (PyExc_ValueError , "Failed to access source object" );
150
- return NULL ;
151
- }
152
- source_size = PyBytes_GET_SIZE (py_source );
153
- }
154
134
#else
155
135
static char * argnames [] = {
156
136
"source" ,
@@ -160,16 +140,22 @@ compress (PyObject * Py_UNUSED (self), PyObject * args, PyObject * kwargs)
160
140
"compression" ,
161
141
NULL
162
142
};
163
- const char * source ;
164
- int source_size ;
165
- if (!PyArg_ParseTupleAndKeywords (args , kwargs , "s#|siii" , argnames ,
166
- & source , & source_size ,
143
+ if (!PyArg_ParseTupleAndKeywords (args , kwargs , "s*|siii" , argnames ,
144
+ & source ,
167
145
& mode , & store_size , & acceleration , & compression ))
168
146
{
169
147
return NULL ;
170
148
}
171
149
#endif
172
150
151
+ source_size = (int ) source .len ;
152
+ if (source .len != (Py_ssize_t ) source_size )
153
+ {
154
+ PyBuffer_Release (& source );
155
+ PyErr_Format (PyExc_OverflowError , "Input too large for C 'int'" );
156
+ return NULL ;
157
+ }
158
+
173
159
if (!strncmp (mode , "default" , sizeof ("default" )))
174
160
{
175
161
comp = DEFAULT ;
@@ -184,6 +170,7 @@ compress (PyObject * Py_UNUSED (self), PyObject * args, PyObject * kwargs)
184
170
}
185
171
else
186
172
{
173
+ PyBuffer_Release (& source );
187
174
PyErr_Format (PyExc_ValueError ,
188
175
"Invalid mode argument: %s. Must be one of: standard, fast, high_compression" ,
189
176
mode );
@@ -207,6 +194,7 @@ compress (PyObject * Py_UNUSED (self), PyObject * args, PyObject * kwargs)
207
194
py_dest = PyByteArray_FromStringAndSize (NULL , total_size );
208
195
if (py_dest == NULL )
209
196
{
197
+ PyBuffer_Release (& source );
210
198
return PyErr_NoMemory ();
211
199
}
212
200
dest = PyByteArray_AS_STRING (py_dest );
@@ -216,6 +204,7 @@ compress (PyObject * Py_UNUSED (self), PyObject * args, PyObject * kwargs)
216
204
py_dest = PyBytes_FromStringAndSize (NULL , total_size );
217
205
if (py_dest == NULL )
218
206
{
207
+ PyBuffer_Release (& source );
219
208
return PyErr_NoMemory ();
220
209
}
221
210
dest = PyBytes_AS_STRING (py_dest );
@@ -224,6 +213,7 @@ compress (PyObject * Py_UNUSED (self), PyObject * args, PyObject * kwargs)
224
213
py_dest = PyBytes_FromStringAndSize (NULL , total_size );
225
214
if (py_dest == NULL )
226
215
{
216
+ PyBuffer_Release (& source );
227
217
return PyErr_NoMemory ();
228
218
}
229
219
dest = PyBytes_AS_STRING (py_dest );
@@ -244,23 +234,26 @@ compress (PyObject * Py_UNUSED (self), PyObject * args, PyObject * kwargs)
244
234
switch (comp )
245
235
{
246
236
case DEFAULT :
247
- output_size = LZ4_compress_default (source , dest_start , source_size ,
237
+ output_size = LZ4_compress_default (source . buf , dest_start , source_size ,
248
238
dest_size );
249
239
break ;
250
240
case FAST :
251
- output_size = LZ4_compress_fast (source , dest_start , source_size ,
241
+ output_size = LZ4_compress_fast (source . buf , dest_start , source_size ,
252
242
dest_size , acceleration );
253
243
break ;
254
244
case HIGH_COMPRESSION :
255
- output_size = LZ4_compress_HC (source , dest_start , source_size ,
245
+ output_size = LZ4_compress_HC (source . buf , dest_start , source_size ,
256
246
dest_size , compression );
257
247
break ;
258
248
}
259
249
250
+ Py_END_ALLOW_THREADS
251
+
252
+ PyBuffer_Release (& source );
253
+
260
254
if (output_size <= 0 )
261
255
{
262
- Py_BLOCK_THREADS
263
- PyErr_SetString (PyExc_ValueError , "Compression failed ");
256
+ PyErr_SetString (PyExc_ValueError , "Compression failed" );
264
257
Py_CLEAR (py_dest );
265
258
return NULL ;
266
259
}
@@ -270,8 +263,6 @@ compress (PyObject * Py_UNUSED (self), PyObject * args, PyObject * kwargs)
270
263
output_size += hdr_size ;
271
264
}
272
265
273
- Py_END_ALLOW_THREADS
274
-
275
266
/* Resizes are expensive; tolerate some slop to avoid. */
276
267
if (output_size < (dest_size / 4 ) * 3 )
277
268
{
@@ -299,83 +290,70 @@ compress (PyObject * Py_UNUSED (self), PyObject * args, PyObject * kwargs)
299
290
static PyObject *
300
291
decompress (PyObject * Py_UNUSED (self ), PyObject * args , PyObject * kwargs )
301
292
{
293
+ Py_buffer source ;
302
294
const char * source_start ;
295
+ int source_size ;
303
296
PyObject * py_dest ;
304
297
char * dest ;
305
298
int output_size ;
306
299
size_t dest_size ;
307
300
int uncompressed_size = -1 ;
308
301
309
302
#if IS_PY3
310
- int return_bytearray = 0 ;
311
303
static char * argnames [] = {
312
304
"source" ,
313
305
"uncompressed_size" ,
314
306
"return_bytearray" ,
315
307
NULL
316
308
};
317
- PyObject * py_source ;
318
- Py_ssize_t source_size ;
319
- char * source ;
320
- if (!PyArg_ParseTupleAndKeywords (args , kwargs , "O|ip" , argnames ,
321
- & py_source , & uncompressed_size ,
309
+ int return_bytearray = 0 ;
310
+ if (!PyArg_ParseTupleAndKeywords (args , kwargs , "y*|ip" , argnames ,
311
+ & source , & uncompressed_size ,
322
312
& return_bytearray ))
323
313
{
324
314
return NULL ;
325
315
}
326
- if (PyByteArray_Check (py_source ))
327
- {
328
- source = PyByteArray_AsString (py_source );
329
- if (source == NULL )
330
- {
331
- PyErr_SetString (PyExc_ValueError , "Failed to access source bytearray object" );
332
- return NULL ;
333
- }
334
- source_size = PyByteArray_Size (py_source );
335
- }
336
- else
337
- {
338
- source = PyBytes_AsString (py_source );
339
- if (source == NULL )
340
- {
341
- PyErr_SetString (PyExc_ValueError , "Failed to access source object" );
342
- return NULL ;
343
- }
344
- source_size = PyBytes_Size (py_source );
345
- }
346
316
#else
347
317
static char * argnames [] = {
348
318
"source" ,
349
319
"uncompressed_size" ,
350
320
NULL
351
321
};
352
- const char * source ;
353
- int source_size = 0 ;
354
- if (!PyArg_ParseTupleAndKeywords (args , kwargs , "s#|i" , argnames ,
355
- & source , & source_size , & uncompressed_size ))
322
+ if (!PyArg_ParseTupleAndKeywords (args , kwargs , "s*|i" , argnames ,
323
+ & source , & uncompressed_size ))
356
324
{
357
325
return NULL ;
358
326
}
359
327
#endif
328
+ source_start = (const char * ) source .buf ;
329
+ source_size = (int ) source .len ;
330
+ if (source .len != (Py_ssize_t ) source_size )
331
+ {
332
+ PyBuffer_Release (& source );
333
+ PyErr_Format (PyExc_OverflowError , "Input too large for C 'int'" );
334
+ return NULL ;
335
+ }
336
+
360
337
if (uncompressed_size > 0 )
361
338
{
362
339
dest_size = uncompressed_size ;
363
- source_start = source ;
364
340
}
365
341
else
366
342
{
367
343
if (source_size < hdr_size )
368
344
{
345
+ PyBuffer_Release (& source );
369
346
PyErr_SetString (PyExc_ValueError , "Input source data size too small" );
370
347
return NULL ;
371
348
}
372
- dest_size = load_le32 (source );
373
- source_start = source + hdr_size ;
349
+ dest_size = load_le32 (source_start );
350
+ source_start += hdr_size ;
374
351
source_size -= hdr_size ;
375
352
}
376
353
377
354
if (dest_size < 0 || dest_size > PY_SSIZE_T_MAX )
378
355
{
356
+ PyBuffer_Release (& source );
379
357
PyErr_Format (PyExc_ValueError , "Invalid size in header: 0x%zu" ,
380
358
dest_size );
381
359
return NULL ;
@@ -387,6 +365,7 @@ decompress (PyObject * Py_UNUSED (self), PyObject * args, PyObject * kwargs)
387
365
py_dest = PyByteArray_FromStringAndSize (NULL , dest_size );
388
366
if (py_dest == NULL )
389
367
{
368
+ PyBuffer_Release (& source );
390
369
return PyErr_NoMemory ();
391
370
}
392
371
dest = PyByteArray_AS_STRING (py_dest );
@@ -396,6 +375,7 @@ decompress (PyObject * Py_UNUSED (self), PyObject * args, PyObject * kwargs)
396
375
py_dest = PyBytes_FromStringAndSize (NULL , dest_size );
397
376
if (py_dest == NULL )
398
377
{
378
+ PyBuffer_Release (& source );
399
379
return PyErr_NoMemory ();
400
380
}
401
381
dest = PyBytes_AS_STRING (py_dest );
@@ -404,6 +384,7 @@ decompress (PyObject * Py_UNUSED (self), PyObject * args, PyObject * kwargs)
404
384
py_dest = PyBytes_FromStringAndSize (NULL , dest_size );
405
385
if (py_dest == NULL )
406
386
{
387
+ PyBuffer_Release (& source );
407
388
return PyErr_NoMemory ();
408
389
}
409
390
dest = PyBytes_AS_STRING (py_dest );
@@ -416,6 +397,8 @@ decompress (PyObject * Py_UNUSED (self), PyObject * args, PyObject * kwargs)
416
397
417
398
Py_END_ALLOW_THREADS
418
399
400
+ PyBuffer_Release (& source );
401
+
419
402
if (output_size < 0 )
420
403
{
421
404
PyErr_Format (PyExc_ValueError , "Corrupt input at byte %d" , - output_size );
@@ -451,7 +434,7 @@ PyDoc_STRVAR(compress__doc,
451
434
"Compress source, returning the compressed data as a string.\n" \
452
435
"Raises an exception if any error occurs.\n\n" \
453
436
"Args:\n" \
454
- " source (str, bytes or bytearray ): Data to compress\n" \
437
+ " source (str, bytes or buffer-compatible object ): Data to compress\n" \
455
438
" mode (str): If 'default' or unspecified use the default LZ4\n" \
456
439
" compression mode. Set to 'fast' to use the fast compression\n" \
457
440
" LZ4 mode at the expense of compression. Set to\n" \
@@ -476,7 +459,7 @@ PyDoc_STRVAR(decompress__doc,
476
459
"Decompress source, returning the uncompressed data as a string.\n" \
477
460
"Raises an exception if any error occurs.\n\n" \
478
461
"Args:\n" \
479
- " source (str, bytes or bytearray ): Data to decompress\n\n" \
462
+ " source (str, bytes or buffer-compatible object ): Data to decompress\n\n" \
480
463
" uncompressed_size (int): If not specified or < 0, the uncompressed data\n" \
481
464
" size is read from the start of the source block. If specified,\n" \
482
465
" it is assumed that the full source data is compressed data.\n" \
0 commit comments