Merge from emacs-24; up to 2013-01-02T16:37:04Z!eggert@cs.ucla.edu
[bpt/emacs.git] / src / decompress.c
1 /* Interface to zlib.
2 Copyright (C) 2013 Free Software Foundation, Inc.
3
4 This file is part of GNU Emacs.
5
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
9 (at your option) any later version.
10
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.
15
16 You should have received a copy of the GNU General Public License
17 along 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
29 static 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 false; \
42 }
43
44 DEF_ZLIB_FN (int, inflateInit2_,
45 (z_streamp strm, int windowBits, const char *version, int stream_size));
46
47 DEF_ZLIB_FN (int, inflate,
48 (z_streamp strm, int flush));
49
50 DEF_ZLIB_FN (int, inflateEnd,
51 (z_streamp strm));
52
53 static bool zlib_initialized;
54
55 static bool
56 init_zlib_functions (void)
57 {
58 HMODULE library = w32_delayed_load (Qzlib_dll);
59
60 if (!library)
61 {
62 message1 ("zlib library not found");
63 return false;
64 }
65
66 LOAD_ZLIB_FN (library, inflateInit2_);
67 LOAD_ZLIB_FN (library, inflate);
68 LOAD_ZLIB_FN (library, inflateEnd);
69 return true;
70 }
71
72 #define fn_inflateInit2(strm, windowBits) \
73 fn_inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
74
75 #else /* !WINDOWSNT */
76
77 #define fn_inflateInit2 inflateInit2
78 #define fn_inflate inflate
79 #define fn_inflateEnd inflateEnd
80
81 #endif /* WINDOWSNT */
82
83 \f
84 struct decompress_unwind_data
85 {
86 ptrdiff_t old_point, start;
87 z_stream *stream;
88 };
89
90 static void
91 unwind_decompress (void *ddata)
92 {
93 struct decompress_unwind_data *data = ddata;
94 fn_inflateEnd (data->stream);
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 }
102 }
103
104 DEFUN ("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
124 DEFUN ("zlib-decompress-region", Fzlib_decompress_region,
125 Szlib_decompress_region,
126 2, 2, 0,
127 doc: /* Decompress a gzip- or zlib-compressed region.
128 Replace the text in the region by the decompressed data.
129 On failure, return nil and leave the data in place.
130 This function can be called only in unibyte buffers. */)
131 (Lisp_Object start, Lisp_Object end)
132 {
133 ptrdiff_t istart, iend, pos_byte;
134 z_stream stream;
135 int inflate_status;
136 struct decompress_unwind_data unwind_data;
137 ptrdiff_t count = SPECPDL_INDEX ();
138
139 validate_region (&start, &end);
140
141 if (! NILP (BVAR (current_buffer, enable_multibyte_characters)))
142 error ("This function can be called only in unibyte buffers");
143
144 #ifdef WINDOWSNT
145 if (!zlib_initialized)
146 zlib_initialized = init_zlib_functions ();
147 #endif
148
149 /* This is a unibyte buffer, so character positions and bytes are
150 the same. */
151 istart = XINT (start);
152 iend = XINT (end);
153 move_gap_both (iend, iend);
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
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)
164 return Qnil;
165
166 unwind_data.start = iend;
167 unwind_data.stream = &stream;
168 unwind_data.old_point = PT;
169
170 record_unwind_protect_ptr (unwind_decompress, &unwind_data);
171
172 /* Insert the decompressed data at the end of the compressed data. */
173 SET_PT (iend);
174
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;
194 inflate_status = fn_inflate (&stream, Z_NO_FLUSH);
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);
201
202 if (inflate_status != Z_STREAM_END)
203 return unbind_to (count, Qnil);
204
205 unwind_data.start = 0;
206
207 /* Delete the compressed data. */
208 del_range (istart, iend);
209
210 return unbind_to (count, Qt);
211 }
212
213 \f
214 /***********************************************************************
215 Initialization
216 ***********************************************************************/
217 void
218 syms_of_decompress (void)
219 {
220 DEFSYM (Qzlib_dll, "zlib");
221 defsubr (&Szlib_decompress_region);
222 defsubr (&Szlib_available_p);
223 }
224
225 #endif /* HAVE_ZLIB */