mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-01-03 02:31:03 -08:00
* decompress.c: Fix bugs with large buffers and weird inputs.
Tune a bit. Reindent as per usual Emacs style. (BUFFER_SIZE): Remove. (Fdecompress_gzipped_region): Do not mishandle input buffers with more than UINT_MAX bytes. Decompress into the gap instead of into an auto buffer, as this should avoid copying. Return nil if 'inflate' returns Z_NEED_DICT, as we have no dictionary. Do not set immediate_quit; we shouldn't trust zlib code that much.
This commit is contained in:
parent
8d28d0ac2a
commit
d0e615c324
2 changed files with 63 additions and 46 deletions
|
|
@ -1,3 +1,14 @@
|
|||
2013-08-11 Paul Eggert <eggert@cs.ucla.edu>
|
||||
|
||||
* decompress.c: Fix bugs with large buffers and weird inputs.
|
||||
Tune a bit. Reindent as per usual Emacs style.
|
||||
(BUFFER_SIZE): Remove.
|
||||
(Fdecompress_gzipped_region): Do not mishandle input buffers with
|
||||
more than UINT_MAX bytes. Decompress into the gap instead of into
|
||||
an auto buffer, as this should avoid copying. Return nil if
|
||||
'inflate' returns Z_NEED_DICT, as we have no dictionary. Do not
|
||||
set immediate_quit; we shouldn't trust zlib code that much.
|
||||
|
||||
2013-08-11 Lars Magne Ingebrigtsen <larsi@gnus.org>
|
||||
|
||||
* decompress.c (Fdecompress_gzipped_region): Respect all zlib
|
||||
|
|
|
|||
|
|
@ -27,48 +27,48 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
|
|||
#include "buffer.h"
|
||||
|
||||
|
||||
#define BUFFER_SIZE 16384
|
||||
|
||||
struct decompress_unwind_data {
|
||||
struct decompress_unwind_data
|
||||
{
|
||||
ptrdiff_t old_point, start;
|
||||
z_stream *stream;
|
||||
};
|
||||
|
||||
static void
|
||||
unwind_decompress (void *ddata) {
|
||||
unwind_decompress (void *ddata)
|
||||
{
|
||||
struct decompress_unwind_data *data = ddata;
|
||||
inflateEnd (data->stream);
|
||||
/* Delete any uncompressed data already inserted and restore
|
||||
point. */
|
||||
if (data->start) {
|
||||
del_range (data->start, PT);
|
||||
SET_PT (data->old_point);
|
||||
}
|
||||
|
||||
/* Delete any uncompressed data already inserted and restore point. */
|
||||
if (data->start)
|
||||
{
|
||||
del_range (data->start, PT);
|
||||
SET_PT (data->old_point);
|
||||
}
|
||||
}
|
||||
|
||||
DEFUN ("decompress-gzipped-region", Fdecompress_gzipped_region,
|
||||
Sdecompress_gzipped_region,
|
||||
2, 2, 0,
|
||||
doc: /* Decompress a gzip-compressed region.
|
||||
The text in the region will be replaced by the decompressed data.
|
||||
On failure, nil is returned and the data is left in place.
|
||||
This function can only be called in unibyte buffers.*/)
|
||||
Replace the text in the region by the decompressed data.
|
||||
On failure, return nil and leave the data in place.
|
||||
This function can be called only in unibyte buffers. */)
|
||||
(Lisp_Object start, Lisp_Object end)
|
||||
{
|
||||
ptrdiff_t istart, iend, point = PT;
|
||||
ptrdiff_t istart, iend, pos_byte;
|
||||
z_stream stream;
|
||||
int decompressed;
|
||||
char out[16384];
|
||||
int inflate_status;
|
||||
struct decompress_unwind_data unwind_data;
|
||||
ptrdiff_t count = SPECPDL_INDEX ();
|
||||
|
||||
validate_region (&start, &end);
|
||||
|
||||
if (! NILP (BVAR (current_buffer, enable_multibyte_characters)))
|
||||
error ("This function can only be called in unibyte buffers");
|
||||
error ("This function can be called only in unibyte buffers");
|
||||
|
||||
/* This is a unibyte buffer, so character positions and bytes are
|
||||
the same. */
|
||||
the same. */
|
||||
istart = XINT (start);
|
||||
iend = XINT (end);
|
||||
move_gap_both (iend, iend);
|
||||
|
|
@ -79,49 +79,55 @@ This function can only be called in unibyte buffers.*/)
|
|||
stream.avail_in = 0;
|
||||
stream.next_in = Z_NULL;
|
||||
|
||||
/* This magic number apparently means "this is gzip". */
|
||||
/* This magic number apparently means "this is gzip". */
|
||||
if (inflateInit2 (&stream, 16 + MAX_WBITS) != Z_OK)
|
||||
return Qnil;
|
||||
|
||||
/* We're inserting the decompressed data at the end of the
|
||||
compressed data. */
|
||||
SET_PT (iend);
|
||||
|
||||
stream.avail_in = iend - istart;
|
||||
stream.next_in = (char *) BYTE_POS_ADDR (istart);
|
||||
|
||||
unwind_data.start = iend;
|
||||
unwind_data.stream = &stream;
|
||||
unwind_data.old_point = point;
|
||||
unwind_data.old_point = PT;
|
||||
|
||||
record_unwind_protect_ptr (unwind_decompress, &unwind_data);
|
||||
|
||||
immediate_quit = 1;
|
||||
/* Insert the decompressed data at the end of the compressed data. */
|
||||
SET_PT (iend);
|
||||
|
||||
/* Run inflate() on input until the output buffer isn't full. */
|
||||
do {
|
||||
int result;
|
||||
stream.avail_out = BUFFER_SIZE;
|
||||
stream.next_out = out;
|
||||
result = inflate (&stream, Z_NO_FLUSH);
|
||||
if (result < 0) {
|
||||
unbind_to (count, Qnil);
|
||||
return Qnil;
|
||||
pos_byte = istart;
|
||||
|
||||
/* Keep calling 'inflate' until it reports an error or end-of-input. */
|
||||
do
|
||||
{
|
||||
/* Maximum number of bytes that one 'inflate' call should read and write.
|
||||
zlib requires that these values not exceed UINT_MAX.
|
||||
Do not make avail_out too large, as that might unduly delay C-g. */
|
||||
ptrdiff_t avail_in = min (iend - pos_byte, UINT_MAX);
|
||||
ptrdiff_t avail_out = min (1 << 14, UINT_MAX);
|
||||
|
||||
ptrdiff_t decompressed;
|
||||
|
||||
if (GAP_SIZE < avail_out)
|
||||
make_gap (avail_out - GAP_SIZE);
|
||||
stream.next_in = BYTE_POS_ADDR (pos_byte);
|
||||
stream.avail_in = avail_in;
|
||||
stream.next_out = GPT_ADDR;
|
||||
stream.avail_out = avail_out;
|
||||
inflate_status = inflate (&stream, Z_NO_FLUSH);
|
||||
pos_byte += avail_in - stream.avail_in;
|
||||
decompressed = avail_out - stream.avail_out;
|
||||
insert_from_gap (decompressed, decompressed, 0);
|
||||
QUIT;
|
||||
}
|
||||
while (inflate_status == Z_OK);
|
||||
|
||||
decompressed = BUFFER_SIZE - stream.avail_out;
|
||||
insert_1_both (out, decompressed, decompressed, 0, 0, 0);
|
||||
QUIT;
|
||||
} while (stream.avail_out == 0);
|
||||
|
||||
immediate_quit = 0;
|
||||
if (inflate_status != Z_STREAM_END)
|
||||
return unbind_to (count, Qnil);
|
||||
|
||||
unwind_data.start = 0;
|
||||
unbind_to (count, Qnil);
|
||||
|
||||
/* Delete the compressed data. */
|
||||
/* Delete the compressed data. */
|
||||
del_range (istart, iend);
|
||||
|
||||
return Qt;
|
||||
return unbind_to (count, Qt);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue