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