Fix decompress gap handling bug
[emacs.git] / src / decompress.c
bloba6323a843e91dfc6f5198447949a4f7e666a9dde
1 /* Interface to zlib.
2 Copyright (C) 2013 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
19 #include <config.h>
21 #ifdef HAVE_ZLIB
23 #include <zlib.h>
25 #include "lisp.h"
26 #include "character.h"
27 #include "buffer.h"
30 #define BUFFER_SIZE 16384
32 struct decompress_unwind_data {
33 ptrdiff_t old_point, start;
34 z_stream *stream;
37 static void
38 unwind_decompress (void *ddata) {
39 struct decompress_unwind_data *data = ddata;
40 inflateEnd (data->stream);
41 /* Delete any uncompressed data already inserted and restore
42 point. */
43 if (data->start) {
44 del_range (data->start, PT);
45 SET_PT (data->old_point);
49 DEFUN ("decompress-gzipped-region", Fdecompress_gzipped_region,
50 Sdecompress_gzipped_region,
51 2, 2, 0,
52 doc: /* Decompress a gzip-compressed region.
53 The text in the region will be replaced by the decompressed data.
54 On failure, nil is returned and the data is left in place.
55 This function can only be called in unibyte buffers.*/)
56 (Lisp_Object start, Lisp_Object end)
58 ptrdiff_t istart, iend, point = PT;
59 z_stream stream;
60 int decompressed;
61 char out[16384];
62 struct decompress_unwind_data unwind_data;
63 ptrdiff_t count = SPECPDL_INDEX ();
65 validate_region (&start, &end);
67 if (! NILP (BVAR (current_buffer, enable_multibyte_characters)))
68 error ("This function can only be called in unibyte buffers");
70 /* This is a unibyte buffer, so character positions and bytes are
71 the same. */
72 istart = XINT (start);
73 iend = XINT (end);
74 move_gap_both (iend, iend);
76 stream.zalloc = Z_NULL;
77 stream.zfree = Z_NULL;
78 stream.opaque = Z_NULL;
79 stream.avail_in = 0;
80 stream.next_in = Z_NULL;
82 /* This magic number apparently means "this is gzip". */
83 if (inflateInit2 (&stream, 16 + MAX_WBITS) != Z_OK)
84 return Qnil;
86 /* We're inserting the decompressed data at the end of the
87 compressed data. */
88 SET_PT (iend);
90 stream.avail_in = iend - istart;
91 stream.next_in = (char *) BYTE_POS_ADDR (istart);
93 unwind_data.start = iend;
94 unwind_data.stream = &stream;
95 unwind_data.old_point = point;
96 record_unwind_protect_ptr (unwind_decompress, &unwind_data);
98 immediate_quit = 1;
100 /* Run inflate() on input until the output buffer isn't full. */
101 do {
102 int result;
103 stream.avail_out = BUFFER_SIZE;
104 stream.next_out = out;
105 result = inflate (&stream, Z_NO_FLUSH);
106 if (result < 0) {
107 unbind_to (count, Qnil);
108 return Qnil;
111 decompressed = BUFFER_SIZE - stream.avail_out;
112 insert_1_both (out, decompressed, decompressed, 0, 0, 0);
113 QUIT;
114 } while (stream.avail_out == 0);
116 immediate_quit = 0;
118 unwind_data.start = 0;
119 unbind_to (count, Qnil);
121 /* Delete the compressed data. */
122 del_range (istart, iend);
124 return Qt;
128 /***********************************************************************
129 Initialization
130 ***********************************************************************/
131 void
132 syms_of_decompress (void)
134 defsubr (&Sdecompress_gzipped_region);
137 #endif /* HAVE_ZLIB */