* lisp/vc/vc-filewise.el: Comment fixes.
[emacs.git] / src / decompress.c
blob24ce852245c99de12c087d7461a39f5664da868e
1 /* Interface to zlib.
2 Copyright (C) 2013-2014 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
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.
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.
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/>. */
19 #include <config.h>
21 #ifdef HAVE_ZLIB
23 #include <zlib.h>
25 #include "lisp.h"
26 #include "character.h"
27 #include "buffer.h"
29 #include <verify.h>
31 static Lisp_Object Qzlib_dll;
33 #ifdef WINDOWSNT
34 #include <windows.h>
35 #include "w32.h"
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
40 /* Macro for loading zlib functions from the library. */
41 #define LOAD_ZLIB_FN(lib,func) { \
42 fn_##func = (void *) GetProcAddress (lib, #func); \
43 if (!fn_##func) return false; \
46 DEF_ZLIB_FN (int, inflateInit2_,
47 (z_streamp strm, int windowBits, const char *version, int stream_size));
49 DEF_ZLIB_FN (int, inflate,
50 (z_streamp strm, int flush));
52 DEF_ZLIB_FN (int, inflateEnd,
53 (z_streamp strm));
55 static bool zlib_initialized;
57 static bool
58 init_zlib_functions (void)
60 HMODULE library = w32_delayed_load (Qzlib_dll);
62 if (!library)
63 return false;
65 LOAD_ZLIB_FN (library, inflateInit2_);
66 LOAD_ZLIB_FN (library, inflate);
67 LOAD_ZLIB_FN (library, inflateEnd);
68 return true;
71 #define fn_inflateInit2(strm, windowBits) \
72 fn_inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
74 #else /* !WINDOWSNT */
76 #define fn_inflateInit2 inflateInit2
77 #define fn_inflate inflate
78 #define fn_inflateEnd inflateEnd
80 #endif /* WINDOWSNT */
83 struct decompress_unwind_data
85 ptrdiff_t old_point, start, nbytes;
86 z_stream *stream;
89 static void
90 unwind_decompress (void *ddata)
92 struct decompress_unwind_data *data = ddata;
93 fn_inflateEnd (data->stream);
95 /* Delete any uncompressed data already inserted on error. */
96 if (data->start)
97 del_range (data->start, data->start + data->nbytes);
99 /* Put point where it was, or if the buffer has shrunk because the
100 compressed data is bigger than the uncompressed, at
101 point-max. */
102 SET_PT (min (data->old_point, ZV));
105 DEFUN ("zlib-available-p", Fzlib_available_p, Szlib_available_p, 0, 0, 0,
106 doc: /* Return t if zlib decompression is available in this instance of Emacs. */)
107 (void)
109 #ifdef WINDOWSNT
110 Lisp_Object found = Fassq (Qzlib_dll, Vlibrary_cache);
111 if (CONSP (found))
112 return XCDR (found);
113 else
115 Lisp_Object status;
116 zlib_initialized = init_zlib_functions ();
117 status = zlib_initialized ? Qt : Qnil;
118 Vlibrary_cache = Fcons (Fcons (Qzlib_dll, status), Vlibrary_cache);
119 return status;
121 #else
122 return Qt;
123 #endif
126 DEFUN ("zlib-decompress-region", Fzlib_decompress_region,
127 Szlib_decompress_region,
128 2, 2, 0,
129 doc: /* Decompress a gzip- or zlib-compressed region.
130 Replace the text in the region by the decompressed data.
131 On failure, return nil and leave the data in place.
132 This function can be called only in unibyte buffers. */)
133 (Lisp_Object start, Lisp_Object end)
135 ptrdiff_t istart, iend, pos_byte;
136 z_stream stream;
137 int inflate_status;
138 struct decompress_unwind_data unwind_data;
139 ptrdiff_t count = SPECPDL_INDEX ();
141 validate_region (&start, &end);
143 if (! NILP (BVAR (current_buffer, enable_multibyte_characters)))
144 error ("This function can be called only in unibyte buffers");
146 #ifdef WINDOWSNT
147 if (!zlib_initialized)
148 zlib_initialized = init_zlib_functions ();
149 if (!zlib_initialized)
151 message1 ("zlib library not found");
152 return Qnil;
154 #endif
156 /* This is a unibyte buffer, so character positions and bytes are
157 the same. */
158 istart = XINT (start);
159 iend = XINT (end);
160 move_gap_both (iend, iend);
162 stream.zalloc = Z_NULL;
163 stream.zfree = Z_NULL;
164 stream.opaque = Z_NULL;
165 stream.avail_in = 0;
166 stream.next_in = Z_NULL;
168 /* The magic number 32 apparently means "autodetect both the gzip and
169 zlib formats" according to zlib.h. */
170 if (fn_inflateInit2 (&stream, MAX_WBITS + 32) != Z_OK)
171 return Qnil;
173 unwind_data.start = iend;
174 unwind_data.stream = &stream;
175 unwind_data.old_point = PT;
176 unwind_data.nbytes = 0;
177 record_unwind_protect_ptr (unwind_decompress, &unwind_data);
179 /* Insert the decompressed data at the end of the compressed data. */
180 SET_PT (iend);
182 pos_byte = istart;
184 /* Keep calling 'inflate' until it reports an error or end-of-input. */
187 /* Maximum number of bytes that one 'inflate' call should read and write.
188 Do not make avail_out too large, as that might unduly delay C-g.
189 zlib requires that avail_in and avail_out not exceed UINT_MAX. */
190 ptrdiff_t avail_in = min (iend - pos_byte, UINT_MAX);
191 int avail_out = 16 * 1024;
192 int decompressed;
194 if (GAP_SIZE < avail_out)
195 make_gap (avail_out - GAP_SIZE);
196 stream.next_in = BYTE_POS_ADDR (pos_byte);
197 stream.avail_in = avail_in;
198 stream.next_out = GPT_ADDR;
199 stream.avail_out = avail_out;
200 inflate_status = fn_inflate (&stream, Z_NO_FLUSH);
201 pos_byte += avail_in - stream.avail_in;
202 decompressed = avail_out - stream.avail_out;
203 insert_from_gap (decompressed, decompressed, 0);
204 unwind_data.nbytes += decompressed;
205 QUIT;
207 while (inflate_status == Z_OK);
209 if (inflate_status != Z_STREAM_END)
210 return unbind_to (count, Qnil);
212 unwind_data.start = 0;
214 /* Delete the compressed data. */
215 del_range (istart, iend);
217 return unbind_to (count, Qt);
221 /***********************************************************************
222 Initialization
223 ***********************************************************************/
224 void
225 syms_of_decompress (void)
227 DEFSYM (Qzlib_dll, "zlib");
228 defsubr (&Szlib_decompress_region);
229 defsubr (&Szlib_available_p);
232 #endif /* HAVE_ZLIB */