use dynwind_begin and dynwind_end
[bpt/emacs.git] / src / decompress.c
CommitLineData
313546eb 1/* Interface to zlib.
ba318903 2 Copyright (C) 2013-2014 Free Software Foundation, Inc.
313546eb
LMI
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 3 of the License, or
9(at your option) any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
18
19#include <config.h>
20
21#ifdef HAVE_ZLIB
22
23#include <zlib.h>
24
25#include "lisp.h"
26#include "character.h"
27#include "buffer.h"
28
53b64418
PE
29#include <verify.h>
30
594a4307
EZ
31static Lisp_Object Qzlib_dll;
32
33#ifdef WINDOWSNT
34#include <windows.h>
35#include "w32.h"
36
37/* Macro for defining functions that will be loaded from the zlib DLL. */
38#define DEF_ZLIB_FN(rettype,func,args) static rettype (FAR CDECL *fn_##func)args
39
40/* Macro for loading zlib functions from the library. */
41#define LOAD_ZLIB_FN(lib,func) { \
42 fn_##func = (void *) GetProcAddress (lib, #func); \
aa942e2b 43 if (!fn_##func) return false; \
594a4307
EZ
44 }
45
46DEF_ZLIB_FN (int, inflateInit2_,
47 (z_streamp strm, int windowBits, const char *version, int stream_size));
48
49DEF_ZLIB_FN (int, inflate,
50 (z_streamp strm, int flush));
51
52DEF_ZLIB_FN (int, inflateEnd,
53 (z_streamp strm));
54
aa942e2b
EZ
55static bool zlib_initialized;
56
594a4307
EZ
57static bool
58init_zlib_functions (void)
59{
60 HMODULE library = w32_delayed_load (Qzlib_dll);
61
62 if (!library)
63 {
64 message1 ("zlib library not found");
aa942e2b 65 return false;
594a4307
EZ
66 }
67
68 LOAD_ZLIB_FN (library, inflateInit2_);
69 LOAD_ZLIB_FN (library, inflate);
70 LOAD_ZLIB_FN (library, inflateEnd);
aa942e2b 71 return true;
594a4307
EZ
72}
73
1d238bc7
PE
74#define fn_inflateInit2(strm, windowBits) \
75 fn_inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
76
594a4307
EZ
77#else /* !WINDOWSNT */
78
1d238bc7 79#define fn_inflateInit2 inflateInit2
594a4307
EZ
80#define fn_inflate inflate
81#define fn_inflateEnd inflateEnd
82
83#endif /* WINDOWSNT */
84
313546eb 85\f
d0e615c3
PE
86struct decompress_unwind_data
87{
de396731 88 ptrdiff_t old_point, start, nbytes;
313546eb
LMI
89 z_stream *stream;
90};
91
92static void
d0e615c3
PE
93unwind_decompress (void *ddata)
94{
313546eb 95 struct decompress_unwind_data *data = ddata;
594a4307 96 fn_inflateEnd (data->stream);
d0e615c3 97
71530c97 98 /* Delete any uncompressed data already inserted on error. */
d0e615c3 99 if (data->start)
de396731 100 del_range (data->start, data->start + data->nbytes);
71530c97
LMI
101
102 /* Put point where it was, or if the buffer has shrunk because the
103 compressed data is bigger than the uncompressed, at
104 point-max. */
105 SET_PT (min (data->old_point, ZV));
313546eb
LMI
106}
107
594a4307
EZ
108DEFUN ("zlib-available-p", Fzlib_available_p, Szlib_available_p, 0, 0, 0,
109 doc: /* Return t if zlib decompression is available in this instance of Emacs. */)
110 (void)
111{
112#ifdef WINDOWSNT
113 Lisp_Object found = Fassq (Qzlib_dll, Vlibrary_cache);
114 if (CONSP (found))
115 return XCDR (found);
116 else
117 {
118 Lisp_Object status;
d2c28fab
EZ
119 zlib_initialized = init_zlib_functions ();
120 status = zlib_initialized ? Qt : Qnil;
594a4307
EZ
121 Vlibrary_cache = Fcons (Fcons (Qzlib_dll, status), Vlibrary_cache);
122 return status;
123 }
124#else
125 return Qt;
126#endif
127}
128
7699d09e
LMI
129DEFUN ("zlib-decompress-region", Fzlib_decompress_region,
130 Szlib_decompress_region,
313546eb 131 2, 2, 0,
7699d09e 132 doc: /* Decompress a gzip- or zlib-compressed region.
d0e615c3
PE
133Replace the text in the region by the decompressed data.
134On failure, return nil and leave the data in place.
135This function can be called only in unibyte buffers. */)
313546eb
LMI
136 (Lisp_Object start, Lisp_Object end)
137{
d0e615c3 138 ptrdiff_t istart, iend, pos_byte;
313546eb 139 z_stream stream;
d0e615c3 140 int inflate_status;
313546eb 141 struct decompress_unwind_data unwind_data;
2bfa3d3e 142 dynwind_begin ();
313546eb
LMI
143
144 validate_region (&start, &end);
313546eb
LMI
145
146 if (! NILP (BVAR (current_buffer, enable_multibyte_characters)))
d0e615c3 147 error ("This function can be called only in unibyte buffers");
313546eb 148
aa942e2b
EZ
149#ifdef WINDOWSNT
150 if (!zlib_initialized)
151 zlib_initialized = init_zlib_functions ();
2bfa3d3e
BT
152 if (!zlib_initialized) {
153 dynwind_end ();
866c710e 154 return Qnil;
2bfa3d3e 155 }
aa942e2b
EZ
156#endif
157
313546eb 158 /* This is a unibyte buffer, so character positions and bytes are
d0e615c3 159 the same. */
313546eb
LMI
160 istart = XINT (start);
161 iend = XINT (end);
99a32242 162 move_gap_both (iend, iend);
313546eb
LMI
163
164 stream.zalloc = Z_NULL;
165 stream.zfree = Z_NULL;
166 stream.opaque = Z_NULL;
167 stream.avail_in = 0;
168 stream.next_in = Z_NULL;
169
526e5233 170 /* The magic number 32 apparently means "autodetect both the gzip and
7699d09e 171 zlib formats" according to zlib.h. */
2bfa3d3e
BT
172 if (fn_inflateInit2 (&stream, MAX_WBITS + 32) != Z_OK) {
173 dynwind_end ();
313546eb 174 return Qnil;
2bfa3d3e 175 }
313546eb 176
313546eb
LMI
177 unwind_data.start = iend;
178 unwind_data.stream = &stream;
d0e615c3 179 unwind_data.old_point = PT;
de396731 180 unwind_data.nbytes = 0;
313546eb
LMI
181 record_unwind_protect_ptr (unwind_decompress, &unwind_data);
182
d0e615c3
PE
183 /* Insert the decompressed data at the end of the compressed data. */
184 SET_PT (iend);
313546eb 185
d0e615c3
PE
186 pos_byte = istart;
187
188 /* Keep calling 'inflate' until it reports an error or end-of-input. */
189 do
190 {
191 /* Maximum number of bytes that one 'inflate' call should read and write.
53b64418 192 Do not make avail_out too large, as that might unduly delay C-g.
2d065031 193 zlib requires that avail_in and avail_out not exceed UINT_MAX. */
d0e615c3 194 ptrdiff_t avail_in = min (iend - pos_byte, UINT_MAX);
2d065031
PE
195 int avail_out = 16 * 1024;
196 int decompressed;
d0e615c3
PE
197
198 if (GAP_SIZE < avail_out)
199 make_gap (avail_out - GAP_SIZE);
200 stream.next_in = BYTE_POS_ADDR (pos_byte);
201 stream.avail_in = avail_in;
202 stream.next_out = GPT_ADDR;
203 stream.avail_out = avail_out;
594a4307 204 inflate_status = fn_inflate (&stream, Z_NO_FLUSH);
d0e615c3
PE
205 pos_byte += avail_in - stream.avail_in;
206 decompressed = avail_out - stream.avail_out;
207 insert_from_gap (decompressed, decompressed, 0);
de396731 208 unwind_data.nbytes += decompressed;
d0e615c3
PE
209 QUIT;
210 }
211 while (inflate_status == Z_OK);
313546eb 212
2bfa3d3e
BT
213 if (inflate_status != Z_STREAM_END){
214
215 dynwind_end ();
216 return Qnil;
217 }
313546eb
LMI
218
219 unwind_data.start = 0;
313546eb 220
d0e615c3 221 /* Delete the compressed data. */
313546eb
LMI
222 del_range (istart, iend);
223
2bfa3d3e
BT
224 dynwind_end ();
225 return Qt;
313546eb
LMI
226}
227
228\f
229/***********************************************************************
230 Initialization
231 ***********************************************************************/
232void
233syms_of_decompress (void)
234{
fe6aa7a1
BT
235#include "decompress.x"
236
594a4307 237 DEFSYM (Qzlib_dll, "zlib");
313546eb
LMI
238}
239
240#endif /* HAVE_ZLIB */