Add an undo command to url-cookie-mode
[emacs.git] / src / decompress.c
blob6f75f821c406064c3de259a61a9be993e473a76c
1 /* Interface to zlib.
2 Copyright (C) 2013-2018 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 (at
9 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 <https://www.gnu.org/licenses/>. */
19 #include <config.h>
21 #ifdef HAVE_ZLIB
23 #include <zlib.h>
25 #include "lisp.h"
26 #include "buffer.h"
27 #include "composite.h"
29 #include <verify.h>
31 #ifdef WINDOWSNT
32 # include <windows.h>
33 # include "w32.h"
35 DEF_DLL_FN (int, inflateInit2_,
36 (z_streamp strm, int windowBits, const char *version,
37 int stream_size));
38 DEF_DLL_FN (int, inflate, (z_streamp strm, int flush));
39 DEF_DLL_FN (int, inflateEnd, (z_streamp strm));
41 static bool zlib_initialized;
43 static bool
44 init_zlib_functions (void)
46 HMODULE library = w32_delayed_load (Qzlib);
48 if (!library)
49 return false;
51 LOAD_DLL_FN (library, inflateInit2_);
52 LOAD_DLL_FN (library, inflate);
53 LOAD_DLL_FN (library, inflateEnd);
54 return true;
57 # undef inflate
58 # undef inflateEnd
59 # undef inflateInit2_
61 # define inflate fn_inflate
62 # define inflateEnd fn_inflateEnd
63 # define inflateInit2_ fn_inflateInit2_
65 #endif /* WINDOWSNT */
68 struct decompress_unwind_data
70 ptrdiff_t old_point, orig, start, nbytes;
71 z_stream *stream;
74 static void
75 unwind_decompress (void *ddata)
77 struct decompress_unwind_data *data = ddata;
78 inflateEnd (data->stream);
80 /* Delete any uncompressed data already inserted on error, but
81 without calling the change hooks. */
82 if (data->start)
84 del_range_2 (data->start, data->start, /* byte, char offsets the same */
85 data->start + data->nbytes, data->start + data->nbytes,
86 0);
87 update_compositions (data->start, data->start, CHECK_HEAD);
88 /* "Balance" the before-change-functions call, which would
89 otherwise be left "hanging". */
90 signal_after_change (data->orig, data->start - data->orig,
91 data->start - data->orig);
93 /* Put point where it was, or if the buffer has shrunk because the
94 compressed data is bigger than the uncompressed, at
95 point-max. */
96 SET_PT (min (data->old_point, ZV));
99 DEFUN ("zlib-available-p", Fzlib_available_p, Szlib_available_p, 0, 0, 0,
100 doc: /* Return t if zlib decompression is available in this instance of Emacs. */)
101 (void)
103 #ifdef WINDOWSNT
104 Lisp_Object found = Fassq (Qzlib, Vlibrary_cache);
105 if (CONSP (found))
106 return XCDR (found);
107 else
109 Lisp_Object status;
110 zlib_initialized = init_zlib_functions ();
111 status = zlib_initialized ? Qt : Qnil;
112 Vlibrary_cache = Fcons (Fcons (Qzlib, status), Vlibrary_cache);
113 return status;
115 #else
116 return Qt;
117 #endif
120 DEFUN ("zlib-decompress-region", Fzlib_decompress_region,
121 Szlib_decompress_region,
122 2, 2, 0,
123 doc: /* Decompress a gzip- or zlib-compressed region.
124 Replace the text in the region by the decompressed data.
125 On failure, return nil and leave the data in place.
126 This function can be called only in unibyte buffers. */)
127 (Lisp_Object start, Lisp_Object end)
129 ptrdiff_t istart, iend, pos_byte;
130 z_stream stream;
131 int inflate_status;
132 struct decompress_unwind_data unwind_data;
133 ptrdiff_t count = SPECPDL_INDEX ();
135 validate_region (&start, &end);
137 if (! NILP (BVAR (current_buffer, enable_multibyte_characters)))
138 error ("This function can be called only in unibyte buffers");
140 #ifdef WINDOWSNT
141 if (!zlib_initialized)
142 zlib_initialized = init_zlib_functions ();
143 if (!zlib_initialized)
145 message1 ("zlib library not found");
146 return Qnil;
148 #endif
150 /* This is a unibyte buffer, so character positions and bytes are
151 the same. */
152 istart = XINT (start);
153 iend = XINT (end);
155 /* Do the following before manipulating the gap. */
156 modify_text (istart, iend);
158 move_gap_both (iend, iend);
160 stream.zalloc = Z_NULL;
161 stream.zfree = Z_NULL;
162 stream.opaque = Z_NULL;
163 stream.avail_in = 0;
164 stream.next_in = Z_NULL;
166 /* The magic number 32 apparently means "autodetect both the gzip and
167 zlib formats" according to zlib.h. */
168 if (inflateInit2 (&stream, MAX_WBITS + 32) != Z_OK)
169 return Qnil;
171 unwind_data.orig = istart;
172 unwind_data.start = iend;
173 unwind_data.stream = &stream;
174 unwind_data.old_point = PT;
175 unwind_data.nbytes = 0;
176 record_unwind_protect_ptr (unwind_decompress, &unwind_data);
178 /* Insert the decompressed data at the end of the compressed data. */
179 SET_PT (iend);
181 pos_byte = istart;
183 /* Keep calling 'inflate' until it reports an error or end-of-input. */
186 /* Maximum number of bytes that one 'inflate' call should read and write.
187 Do not make avail_out too large, as that might unduly delay C-g.
188 zlib requires that avail_in and avail_out not exceed UINT_MAX. */
189 ptrdiff_t avail_in = min (iend - pos_byte, UINT_MAX);
190 int avail_out = 16 * 1024;
191 int decompressed;
193 if (GAP_SIZE < avail_out)
194 make_gap (avail_out - GAP_SIZE);
195 stream.next_in = BYTE_POS_ADDR (pos_byte);
196 stream.avail_in = avail_in;
197 stream.next_out = GPT_ADDR;
198 stream.avail_out = avail_out;
199 inflate_status = inflate (&stream, Z_NO_FLUSH);
200 pos_byte += avail_in - stream.avail_in;
201 decompressed = avail_out - stream.avail_out;
202 insert_from_gap (decompressed, decompressed, 0);
203 unwind_data.nbytes += decompressed;
204 maybe_quit ();
206 while (inflate_status == Z_OK);
208 if (inflate_status != Z_STREAM_END)
209 return unbind_to (count, Qnil);
211 unwind_data.start = 0;
213 /* Delete the compressed data. */
214 del_range_2 (istart, istart, /* byte and char offsets are the same. */
215 iend, iend, 0);
217 signal_after_change (istart, iend - istart, unwind_data.nbytes);
218 update_compositions (istart, istart, CHECK_HEAD);
220 return unbind_to (count, Qt);
224 /***********************************************************************
225 Initialization
226 ***********************************************************************/
227 void
228 syms_of_decompress (void)
230 defsubr (&Szlib_decompress_region);
231 defsubr (&Szlib_available_p);
234 #endif /* HAVE_ZLIB */