Fix zlib support on MS-Windows.
[bpt/emacs.git] / src / decompress.c
CommitLineData
313546eb
LMI
1/* Interface to zlib.
2 Copyright (C) 2013 Free Software Foundation, Inc.
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
594a4307
EZ
29static Lisp_Object Qzlib_dll;
30
31#ifdef WINDOWSNT
32#include <windows.h>
33#include "w32.h"
34
35/* Macro for defining functions that will be loaded from the zlib DLL. */
36#define DEF_ZLIB_FN(rettype,func,args) static rettype (FAR CDECL *fn_##func)args
37
38/* Macro for loading zlib functions from the library. */
39#define LOAD_ZLIB_FN(lib,func) { \
40 fn_##func = (void *) GetProcAddress (lib, #func); \
aa942e2b 41 if (!fn_##func) return false; \
594a4307
EZ
42 }
43
44DEF_ZLIB_FN (int, inflateInit2_,
45 (z_streamp strm, int windowBits, const char *version, int stream_size));
46
47DEF_ZLIB_FN (int, inflate,
48 (z_streamp strm, int flush));
49
50DEF_ZLIB_FN (int, inflateEnd,
51 (z_streamp strm));
52
aa942e2b
EZ
53static bool zlib_initialized;
54
594a4307
EZ
55static bool
56init_zlib_functions (void)
57{
58 HMODULE library = w32_delayed_load (Qzlib_dll);
59
60 if (!library)
61 {
62 message1 ("zlib library not found");
aa942e2b 63 return false;
594a4307
EZ
64 }
65
66 LOAD_ZLIB_FN (library, inflateInit2_);
67 LOAD_ZLIB_FN (library, inflate);
68 LOAD_ZLIB_FN (library, inflateEnd);
aa942e2b 69 return true;
594a4307
EZ
70}
71
1d238bc7
PE
72#define fn_inflateInit2(strm, windowBits) \
73 fn_inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
74
594a4307
EZ
75#else /* !WINDOWSNT */
76
1d238bc7 77#define fn_inflateInit2 inflateInit2
594a4307
EZ
78#define fn_inflate inflate
79#define fn_inflateEnd inflateEnd
80
81#endif /* WINDOWSNT */
82
313546eb 83\f
d0e615c3
PE
84struct decompress_unwind_data
85{
313546eb
LMI
86 ptrdiff_t old_point, start;
87 z_stream *stream;
88};
89
90static void
d0e615c3
PE
91unwind_decompress (void *ddata)
92{
313546eb 93 struct decompress_unwind_data *data = ddata;
594a4307 94 fn_inflateEnd (data->stream);
d0e615c3
PE
95
96 /* Delete any uncompressed data already inserted and restore point. */
97 if (data->start)
98 {
99 del_range (data->start, PT);
100 SET_PT (data->old_point);
101 }
313546eb
LMI
102}
103
594a4307
EZ
104DEFUN ("zlib-available-p", Fzlib_available_p, Szlib_available_p, 0, 0, 0,
105 doc: /* Return t if zlib decompression is available in this instance of Emacs. */)
106 (void)
107{
108#ifdef WINDOWSNT
109 Lisp_Object found = Fassq (Qzlib_dll, Vlibrary_cache);
110 if (CONSP (found))
111 return XCDR (found);
112 else
113 {
114 Lisp_Object status;
115 status = init_zlib_functions () ? Qt : Qnil;
116 Vlibrary_cache = Fcons (Fcons (Qzlib_dll, status), Vlibrary_cache);
117 return status;
118 }
119#else
120 return Qt;
121#endif
122}
123
7699d09e
LMI
124DEFUN ("zlib-decompress-region", Fzlib_decompress_region,
125 Szlib_decompress_region,
313546eb 126 2, 2, 0,
7699d09e 127 doc: /* Decompress a gzip- or zlib-compressed region.
d0e615c3
PE
128Replace the text in the region by the decompressed data.
129On failure, return nil and leave the data in place.
130This function can be called only in unibyte buffers. */)
313546eb
LMI
131 (Lisp_Object start, Lisp_Object end)
132{
d0e615c3 133 ptrdiff_t istart, iend, pos_byte;
313546eb 134 z_stream stream;
d0e615c3 135 int inflate_status;
313546eb
LMI
136 struct decompress_unwind_data unwind_data;
137 ptrdiff_t count = SPECPDL_INDEX ();
138
139 validate_region (&start, &end);
313546eb
LMI
140
141 if (! NILP (BVAR (current_buffer, enable_multibyte_characters)))
d0e615c3 142 error ("This function can be called only in unibyte buffers");
313546eb 143
aa942e2b
EZ
144#ifdef WINDOWSNT
145 if (!zlib_initialized)
146 zlib_initialized = init_zlib_functions ();
147#endif
148
313546eb 149 /* This is a unibyte buffer, so character positions and bytes are
d0e615c3 150 the same. */
313546eb
LMI
151 istart = XINT (start);
152 iend = XINT (end);
99a32242 153 move_gap_both (iend, iend);
313546eb
LMI
154
155 stream.zalloc = Z_NULL;
156 stream.zfree = Z_NULL;
157 stream.opaque = Z_NULL;
158 stream.avail_in = 0;
159 stream.next_in = Z_NULL;
160
7699d09e
LMI
161 /* The magic number 32 apparently means "autodect both the gzip and
162 zlib formats" according to zlib.h. */
163 if (fn_inflateInit2 (&stream, MAX_WBITS + 32) != Z_OK)
313546eb
LMI
164 return Qnil;
165
313546eb
LMI
166 unwind_data.start = iend;
167 unwind_data.stream = &stream;
d0e615c3
PE
168 unwind_data.old_point = PT;
169
313546eb
LMI
170 record_unwind_protect_ptr (unwind_decompress, &unwind_data);
171
d0e615c3
PE
172 /* Insert the decompressed data at the end of the compressed data. */
173 SET_PT (iend);
313546eb 174
d0e615c3
PE
175 pos_byte = istart;
176
177 /* Keep calling 'inflate' until it reports an error or end-of-input. */
178 do
179 {
180 /* Maximum number of bytes that one 'inflate' call should read and write.
181 zlib requires that these values not exceed UINT_MAX.
182 Do not make avail_out too large, as that might unduly delay C-g. */
183 ptrdiff_t avail_in = min (iend - pos_byte, UINT_MAX);
184 ptrdiff_t avail_out = min (1 << 14, UINT_MAX);
185
186 ptrdiff_t decompressed;
187
188 if (GAP_SIZE < avail_out)
189 make_gap (avail_out - GAP_SIZE);
190 stream.next_in = BYTE_POS_ADDR (pos_byte);
191 stream.avail_in = avail_in;
192 stream.next_out = GPT_ADDR;
193 stream.avail_out = avail_out;
594a4307 194 inflate_status = fn_inflate (&stream, Z_NO_FLUSH);
d0e615c3
PE
195 pos_byte += avail_in - stream.avail_in;
196 decompressed = avail_out - stream.avail_out;
197 insert_from_gap (decompressed, decompressed, 0);
198 QUIT;
199 }
200 while (inflate_status == Z_OK);
313546eb 201
d0e615c3
PE
202 if (inflate_status != Z_STREAM_END)
203 return unbind_to (count, Qnil);
313546eb
LMI
204
205 unwind_data.start = 0;
313546eb 206
d0e615c3 207 /* Delete the compressed data. */
313546eb
LMI
208 del_range (istart, iend);
209
d0e615c3 210 return unbind_to (count, Qt);
313546eb
LMI
211}
212
213\f
214/***********************************************************************
215 Initialization
216 ***********************************************************************/
217void
218syms_of_decompress (void)
219{
594a4307 220 DEFSYM (Qzlib_dll, "zlib");
7699d09e 221 defsubr (&Szlib_decompress_region);
594a4307 222 defsubr (&Szlib_available_p);
313546eb
LMI
223}
224
225#endif /* HAVE_ZLIB */