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