]> code.delx.au - gnu-emacs/blob - src/decompress.c
merge from trunk
[gnu-emacs] / 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 \f
30 struct decompress_unwind_data
31 {
32 ptrdiff_t old_point, start;
33 z_stream *stream;
34 };
35
36 static void
37 unwind_decompress (void *ddata)
38 {
39 struct decompress_unwind_data *data = ddata;
40 inflateEnd (data->stream);
41
42 /* Delete any uncompressed data already inserted and restore point. */
43 if (data->start)
44 {
45 del_range (data->start, PT);
46 SET_PT (data->old_point);
47 }
48 }
49
50 DEFUN ("decompress-gzipped-region", Fdecompress_gzipped_region,
51 Sdecompress_gzipped_region,
52 2, 2, 0,
53 doc: /* Decompress a gzip-compressed region.
54 Replace the text in the region by the decompressed data.
55 On failure, return nil and leave the data in place.
56 This function can be called only in unibyte buffers. */)
57 (Lisp_Object start, Lisp_Object end)
58 {
59 ptrdiff_t istart, iend, pos_byte;
60 z_stream stream;
61 int inflate_status;
62 struct decompress_unwind_data unwind_data;
63 ptrdiff_t count = SPECPDL_INDEX ();
64
65 validate_region (&start, &end);
66
67 if (! NILP (BVAR (current_buffer, enable_multibyte_characters)))
68 error ("This function can be called only in unibyte buffers");
69
70 /* This is a unibyte buffer, so character positions and bytes are
71 the same. */
72 istart = XINT (start);
73 iend = XINT (end);
74 move_gap_both (iend, iend);
75
76 stream.zalloc = Z_NULL;
77 stream.zfree = Z_NULL;
78 stream.opaque = Z_NULL;
79 stream.avail_in = 0;
80 stream.next_in = Z_NULL;
81
82 /* This magic number apparently means "this is gzip". */
83 if (inflateInit2 (&stream, 16 + MAX_WBITS) != Z_OK)
84 return Qnil;
85
86 unwind_data.start = iend;
87 unwind_data.stream = &stream;
88 unwind_data.old_point = PT;
89
90 record_unwind_protect_ptr (unwind_decompress, &unwind_data);
91
92 /* Insert the decompressed data at the end of the compressed data. */
93 SET_PT (iend);
94
95 pos_byte = istart;
96
97 /* Keep calling 'inflate' until it reports an error or end-of-input. */
98 do
99 {
100 /* Maximum number of bytes that one 'inflate' call should read and write.
101 zlib requires that these values not exceed UINT_MAX.
102 Do not make avail_out too large, as that might unduly delay C-g. */
103 ptrdiff_t avail_in = min (iend - pos_byte, UINT_MAX);
104 ptrdiff_t avail_out = min (1 << 14, UINT_MAX);
105
106 ptrdiff_t decompressed;
107
108 if (GAP_SIZE < avail_out)
109 make_gap (avail_out - GAP_SIZE);
110 stream.next_in = BYTE_POS_ADDR (pos_byte);
111 stream.avail_in = avail_in;
112 stream.next_out = GPT_ADDR;
113 stream.avail_out = avail_out;
114 inflate_status = inflate (&stream, Z_NO_FLUSH);
115 pos_byte += avail_in - stream.avail_in;
116 decompressed = avail_out - stream.avail_out;
117 insert_from_gap (decompressed, decompressed, 0);
118 QUIT;
119 }
120 while (inflate_status == Z_OK);
121
122 if (inflate_status != Z_STREAM_END)
123 return unbind_to (count, Qnil);
124
125 unwind_data.start = 0;
126
127 /* Delete the compressed data. */
128 del_range (istart, iend);
129
130 return unbind_to (count, Qt);
131 }
132
133 \f
134 /***********************************************************************
135 Initialization
136 ***********************************************************************/
137 void
138 syms_of_decompress (void)
139 {
140 defsubr (&Sdecompress_gzipped_region);
141 }
142
143 #endif /* HAVE_ZLIB */