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