* decompress.c: Minor simplifications.
[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
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{
313546eb
LMI
88 ptrdiff_t old_point, start;
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
PE
97
98 /* Delete any uncompressed data already inserted and restore point. */
99 if (data->start)
100 {
101 del_range (data->start, PT);
102 SET_PT (data->old_point);
103 }
313546eb
LMI
104}
105
594a4307
EZ
106DEFUN ("zlib-available-p", Fzlib_available_p, Szlib_available_p, 0, 0, 0,
107 doc: /* Return t if zlib decompression is available in this instance of Emacs. */)
108 (void)
109{
110#ifdef WINDOWSNT
111 Lisp_Object found = Fassq (Qzlib_dll, Vlibrary_cache);
112 if (CONSP (found))
113 return XCDR (found);
114 else
115 {
116 Lisp_Object status;
117 status = init_zlib_functions () ? Qt : Qnil;
118 Vlibrary_cache = Fcons (Fcons (Qzlib_dll, status), Vlibrary_cache);
119 return status;
120 }
121#else
122 return Qt;
123#endif
124}
125
7699d09e
LMI
126DEFUN ("zlib-decompress-region", Fzlib_decompress_region,
127 Szlib_decompress_region,
313546eb 128 2, 2, 0,
7699d09e 129 doc: /* Decompress a gzip- or zlib-compressed region.
d0e615c3
PE
130Replace the text in the region by the decompressed data.
131On failure, return nil and leave the data in place.
132This function can be called only in unibyte buffers. */)
313546eb
LMI
133 (Lisp_Object start, Lisp_Object end)
134{
d0e615c3 135 ptrdiff_t istart, iend, pos_byte;
313546eb 136 z_stream stream;
d0e615c3 137 int inflate_status;
313546eb
LMI
138 struct decompress_unwind_data unwind_data;
139 ptrdiff_t count = SPECPDL_INDEX ();
140
141 validate_region (&start, &end);
313546eb
LMI
142
143 if (! NILP (BVAR (current_buffer, enable_multibyte_characters)))
d0e615c3 144 error ("This function can be called only in unibyte buffers");
313546eb 145
aa942e2b
EZ
146#ifdef WINDOWSNT
147 if (!zlib_initialized)
148 zlib_initialized = init_zlib_functions ();
866c710e
EZ
149 if (!zlib_initialized)
150 return Qnil;
aa942e2b
EZ
151#endif
152
313546eb 153 /* This is a unibyte buffer, so character positions and bytes are
d0e615c3 154 the same. */
313546eb
LMI
155 istart = XINT (start);
156 iend = XINT (end);
99a32242 157 move_gap_both (iend, iend);
313546eb
LMI
158
159 stream.zalloc = Z_NULL;
160 stream.zfree = Z_NULL;
161 stream.opaque = Z_NULL;
162 stream.avail_in = 0;
163 stream.next_in = Z_NULL;
164
7699d09e
LMI
165 /* The magic number 32 apparently means "autodect both the gzip and
166 zlib formats" according to zlib.h. */
167 if (fn_inflateInit2 (&stream, MAX_WBITS + 32) != Z_OK)
313546eb
LMI
168 return Qnil;
169
313546eb
LMI
170 unwind_data.start = iend;
171 unwind_data.stream = &stream;
d0e615c3
PE
172 unwind_data.old_point = PT;
173
313546eb
LMI
174 record_unwind_protect_ptr (unwind_decompress, &unwind_data);
175
d0e615c3
PE
176 /* Insert the decompressed data at the end of the compressed data. */
177 SET_PT (iend);
313546eb 178
d0e615c3
PE
179 pos_byte = istart;
180
181 /* Keep calling 'inflate' until it reports an error or end-of-input. */
182 do
183 {
184 /* Maximum number of bytes that one 'inflate' call should read and write.
53b64418 185 Do not make avail_out too large, as that might unduly delay C-g.
2d065031 186 zlib requires that avail_in and avail_out not exceed UINT_MAX. */
d0e615c3 187 ptrdiff_t avail_in = min (iend - pos_byte, UINT_MAX);
2d065031
PE
188 int avail_out = 16 * 1024;
189 int decompressed;
d0e615c3
PE
190
191 if (GAP_SIZE < avail_out)
192 make_gap (avail_out - GAP_SIZE);
193 stream.next_in = BYTE_POS_ADDR (pos_byte);
194 stream.avail_in = avail_in;
195 stream.next_out = GPT_ADDR;
196 stream.avail_out = avail_out;
594a4307 197 inflate_status = fn_inflate (&stream, Z_NO_FLUSH);
d0e615c3
PE
198 pos_byte += avail_in - stream.avail_in;
199 decompressed = avail_out - stream.avail_out;
200 insert_from_gap (decompressed, decompressed, 0);
201 QUIT;
202 }
203 while (inflate_status == Z_OK);
313546eb 204
d0e615c3
PE
205 if (inflate_status != Z_STREAM_END)
206 return unbind_to (count, Qnil);
313546eb
LMI
207
208 unwind_data.start = 0;
313546eb 209
d0e615c3 210 /* Delete the compressed data. */
313546eb
LMI
211 del_range (istart, iend);
212
d0e615c3 213 return unbind_to (count, Qt);
313546eb
LMI
214}
215
216\f
217/***********************************************************************
218 Initialization
219 ***********************************************************************/
220void
221syms_of_decompress (void)
222{
594a4307 223 DEFSYM (Qzlib_dll, "zlib");
7699d09e 224 defsubr (&Szlib_decompress_region);
594a4307 225 defsubr (&Szlib_available_p);
313546eb
LMI
226}
227
228#endif /* HAVE_ZLIB */