Refactor binascii.rledecode_hqx()

Rewrite the code to handle the output buffer.
This commit is contained in:
Victor Stinner 2015-10-14 15:20:07 +02:00
parent 1bfe930585
commit f9c9a3fedf
1 changed files with 25 additions and 28 deletions

View File

@ -784,7 +784,7 @@ binascii_rledecode_hqx_impl(PyModuleDef *module, Py_buffer *data)
{ {
unsigned char *in_data, *out_data; unsigned char *in_data, *out_data;
unsigned char in_byte, in_repeat; unsigned char in_byte, in_repeat;
Py_ssize_t in_len, out_len, out_len_left; Py_ssize_t in_len;
_PyBytesWriter writer; _PyBytesWriter writer;
in_data = data->buf; in_data = data->buf;
@ -800,15 +800,12 @@ binascii_rledecode_hqx_impl(PyModuleDef *module, Py_buffer *data)
return PyErr_NoMemory(); return PyErr_NoMemory();
/* Allocate a buffer of reasonable size. Resized when needed */ /* Allocate a buffer of reasonable size. Resized when needed */
out_len = in_len; out_data = _PyBytesWriter_Alloc(&writer, in_len);
out_data = _PyBytesWriter_Alloc(&writer, out_len);
if (out_data == NULL) if (out_data == NULL)
return NULL; return NULL;
/* Use overallocation */ /* Use overallocation */
writer.overallocate = 1; writer.overallocate = 1;
out_len = writer.allocated;
out_len_left = out_len;
/* /*
** We need two macros here to get/put bytes and handle ** We need two macros here to get/put bytes and handle
@ -823,24 +820,6 @@ binascii_rledecode_hqx_impl(PyModuleDef *module, Py_buffer *data)
b = *in_data++; \ b = *in_data++; \
} while(0) } while(0)
#define OUTBYTE(b) \
do { \
if ( --out_len_left < 0 ) { \
if (in_len <= 0) { \
/* We are done after this write, no need to \
overallocate the buffer anymore */ \
writer.overallocate = 0; \
} \
out_data = _PyBytesWriter_Resize(&writer, out_data, \
writer.allocated + 1); \
if (out_data == NULL) \
goto error; \
out_len_left = writer.allocated - out_len - 1; \
out_len = writer.allocated; \
} \
*out_data++ = b; \
} while(0)
/* /*
** Handle first byte separately (since we have to get angry ** Handle first byte separately (since we have to get angry
** in case of an orphaned RLE code). ** in case of an orphaned RLE code).
@ -849,6 +828,10 @@ binascii_rledecode_hqx_impl(PyModuleDef *module, Py_buffer *data)
if (in_byte == RUNCHAR) { if (in_byte == RUNCHAR) {
INBYTE(in_repeat); INBYTE(in_repeat);
/* only 1 byte will be written, but 2 bytes were preallocated:
substract 1 byte to prevent overallocation */
writer.min_size--;
if (in_repeat != 0) { if (in_repeat != 0) {
/* Note Error, not Incomplete (which is at the end /* Note Error, not Incomplete (which is at the end
** of the string only). This is a programmer error. ** of the string only). This is a programmer error.
@ -856,9 +839,9 @@ binascii_rledecode_hqx_impl(PyModuleDef *module, Py_buffer *data)
PyErr_SetString(Error, "Orphaned RLE code at start"); PyErr_SetString(Error, "Orphaned RLE code at start");
goto error; goto error;
} }
OUTBYTE(RUNCHAR); *out_data++ = RUNCHAR;
} else { } else {
OUTBYTE(in_byte); *out_data++ = in_byte;
} }
while( in_len > 0 ) { while( in_len > 0 ) {
@ -866,18 +849,32 @@ binascii_rledecode_hqx_impl(PyModuleDef *module, Py_buffer *data)
if (in_byte == RUNCHAR) { if (in_byte == RUNCHAR) {
INBYTE(in_repeat); INBYTE(in_repeat);
/* only 1 byte will be written, but 2 bytes were preallocated:
substract 1 byte to prevent overallocation */
writer.min_size--;
if ( in_repeat == 0 ) { if ( in_repeat == 0 ) {
/* Just an escaped RUNCHAR value */ /* Just an escaped RUNCHAR value */
OUTBYTE(RUNCHAR); *out_data++ = RUNCHAR;
} else { } else {
/* Pick up value and output a sequence of it */ /* Pick up value and output a sequence of it */
in_byte = out_data[-1]; in_byte = out_data[-1];
/* enlarge the buffer if needed */
if (in_repeat > 1) {
/* -1 because we already preallocated 1 byte */
out_data = _PyBytesWriter_Prepare(&writer, out_data,
in_repeat - 1);
if (out_data == NULL)
goto error;
}
while ( --in_repeat > 0 ) while ( --in_repeat > 0 )
OUTBYTE(in_byte); *out_data++ = in_byte;
} }
} else { } else {
/* Normal byte */ /* Normal byte */
OUTBYTE(in_byte); *out_data++ = in_byte;
} }
} }
return _PyBytesWriter_Finish(&writer, out_data); return _PyBytesWriter_Finish(&writer, out_data);