From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.ciao.gmane.io!not-for-mail From: Juan =?utf-8?Q?Jos=C3=A9_Garc=C3=ADa-Ripoll?= Newsgroups: gmane.emacs.devel Subject: Re: decompress.c now also compresses Date: Sun, 29 Mar 2020 17:57:23 +0200 Message-ID: <86sghr17do.fsf@csic.es> References: <86zhbz17mk.fsf@csic.es> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: ciao.gmane.io; posting-host="ciao.gmane.io:159.69.161.202"; logging-data="122889"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/26.3 (windows-nt) To: emacs-devel@gnu.org Cancel-Lock: sha1:w9KuUAjpDtiPZevIWFr/oGAOmkw= Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Sun Mar 29 17:58:07 2020 Return-path: Envelope-to: ged-emacs-devel@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1jIaK6-000Vsx-LT for ged-emacs-devel@m.gmane-mx.org; Sun, 29 Mar 2020 17:58:06 +0200 Original-Received: from localhost ([::1]:38954 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jIaK5-0001Hj-Nn for ged-emacs-devel@m.gmane-mx.org; Sun, 29 Mar 2020 11:58:05 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:42773) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jIaJa-0000sT-W8 for emacs-devel@gnu.org; Sun, 29 Mar 2020 11:57:36 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1jIaJZ-0004S5-0x for emacs-devel@gnu.org; Sun, 29 Mar 2020 11:57:34 -0400 Original-Received: from ciao.gmane.io ([159.69.161.202]:36372) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1jIaJY-0004R4-P6 for emacs-devel@gnu.org; Sun, 29 Mar 2020 11:57:32 -0400 Original-Received: from list by ciao.gmane.io with local (Exim 4.92) (envelope-from ) id 1jIaJX-000VCz-9v for emacs-devel@gnu.org; Sun, 29 Mar 2020 17:57:31 +0200 X-Injected-Via-Gmane: http://gmane.org/ X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 159.69.161.202 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.io gmane.emacs.devel:245942 Archived-At: --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Apologies for the corrupted patch: I used emacs' C-c C-v and it looked good, but "git diff" failed because of cr/lf issues. Here it goes again. -- Juan José García Ripoll http://juanjose.garciaripoll.com http://quinfog.hbar.es --=-=-= Content-Type: text/x-patch Content-Disposition: inline; filename=decompress.diff diff --git a/src/decompress.c b/src/decompress.c index 5d24638..7f20cb0 100644 --- a/src/decompress.c +++ b/src/decompress.c @@ -33,11 +33,23 @@ # include "w32common.h" # include "w32.h" +/* We import inflateInit2_ and deflateInit2_ because inflateInit and + deflateInit are macros defined on top of these symbols by zlib.h */ DEF_DLL_FN (int, inflateInit2_, (z_streamp strm, int windowBits, const char *version, int stream_size)); DEF_DLL_FN (int, inflate, (z_streamp strm, int flush)); DEF_DLL_FN (int, inflateEnd, (z_streamp strm)); +DEF_DLL_FN (int, deflateInit2_, + (z_streamp strm, int level, int method, int windowBits, + int memLevel, int strategy, const char *version, + int stream_size)); +DEF_DLL_FN (int, deflateInit2_, + (z_streamp strm, int level, int method, int windowBits, + int memLevel, int strategy, const char *version, + int stream_size)); +DEF_DLL_FN (int, deflate, (z_streamp strm, int flush)); +DEF_DLL_FN (int, deflateEnd, (z_streamp strm)); static bool zlib_initialized; @@ -52,16 +64,25 @@ init_zlib_functions (void) LOAD_DLL_FN (library, inflateInit2_); LOAD_DLL_FN (library, inflate); LOAD_DLL_FN (library, inflateEnd); + LOAD_DLL_FN (library, deflateInit2_); + LOAD_DLL_FN (library, deflate); + LOAD_DLL_FN (library, deflateEnd); return true; } # undef inflate # undef inflateEnd # undef inflateInit2_ +# undef deflate +# undef deflateEnd +# undef deflateInit2_ # define inflate fn_inflate # define inflateEnd fn_inflateEnd # define inflateInit2_ fn_inflateInit2_ +# define deflate fn_deflate +# define deflateEnd fn_deflateEnd +# define deflateInit2_ fn_deflateInit2_ #endif /* WINDOWSNT */ @@ -70,13 +91,14 @@ init_zlib_functions (void) { ptrdiff_t old_point, orig, start, nbytes; z_stream *stream; + int deflating; }; static void -unwind_decompress (void *ddata) +unwind_zlib (void *ddata) { struct decompress_unwind_data *data = ddata; - inflateEnd (data->stream); + (data->deflating? deflateEnd : inflateEnd) (data->stream); /* Delete any uncompressed data already inserted on error, but without calling the change hooks. */ @@ -180,7 +202,8 @@ DEFUN ("zlib-decompress-region", Fzlib_decompress_region, unwind_data.stream = &stream; unwind_data.old_point = PT; unwind_data.nbytes = 0; - record_unwind_protect_ptr (unwind_decompress, &unwind_data); + unwind_data.deflating = 0; + record_unwind_protect_ptr (unwind_zlib, &unwind_data); /* Insert the decompressed data at the end of the compressed data. */ SET_PT (iend); @@ -233,6 +256,129 @@ DEFUN ("zlib-decompress-region", Fzlib_decompress_region, return unbind_to (count, ret); } + +DEFUN ("zlib-compress-region", Fzlib_compress_region, + Szlib_compress_region, + 2, 3, 0, + doc: /* Compress a region to a gzip or zlib stream. +Replace the text in the region by the compressed data. + +If optional parameter NO-WRAPPER is nil or omitted, use the GZIP +wrapper format; otherwise, output just a deflated stream of +bytes. If decompression is completely successful return t. + +This function can be called only in unibyte buffers.*/) + (Lisp_Object start, Lisp_Object end, Lisp_Object zlib) +{ + ptrdiff_t istart, iend, pos_byte; + z_stream stream; + int deflate_status, flush; + struct decompress_unwind_data unwind_data; + ptrdiff_t count = SPECPDL_INDEX (); + bool gzipp = NILP (zlib); + + validate_region (&start, &end); + + if (! NILP (BVAR (current_buffer, enable_multibyte_characters))) + error ("This function can be called only in unibyte buffers"); + +#ifdef WINDOWSNT + if (!zlib_initialized) + zlib_initialized = init_zlib_functions (); + if (!zlib_initialized) + { + message1 ("zlib library not found"); + return Qnil; + } +#endif + + /* This is a unibyte buffer, so character positions and bytes are + the same. */ + istart = XFIXNUM (start); + iend = XFIXNUM (end); + + /* Do the following before manipulating the gap. */ + modify_text (istart, iend); + + move_gap_both (iend, iend); + + stream.zalloc = Z_NULL; + stream.zfree = Z_NULL; + stream.opaque = Z_NULL; + stream.avail_in = 0; + stream.next_in = Z_NULL; + + /* Initiate the deflate() process, choosing the format, compression + strategy and level (9), and amount of memory used. */ + if (deflateInit2 (&stream, 9, Z_DEFLATED, MAX_WBITS + (gzipp? 16: 0), + 8, Z_DEFAULT_STRATEGY) != Z_OK) + return Qnil; + + unwind_data.orig = istart; + unwind_data.start = iend; + unwind_data.stream = &stream; + unwind_data.old_point = PT; + unwind_data.nbytes = 0; + unwind_data.deflating = 1; + record_unwind_protect_ptr (unwind_zlib, &unwind_data); + + /* Insert the decompressed data at the end of the compressed data. */ + SET_PT (iend); + + pos_byte = istart; + + /* Keep calling 'deflate' until it reports an error or end-of-input. */ + flush = Z_NO_FLUSH; + do + { + /* Maximum number of bytes that one 'deflate' call should read and write. + Do not make avail_out too large, as that might unduly delay C-g. + zlib requires that avail_in and avail_out not exceed UINT_MAX. */ + ptrdiff_t avail_in = min (iend - pos_byte, UINT_MAX); + int avail_out = 16 * 1024; + int compressed; + + if (GAP_SIZE < avail_out) + make_gap (avail_out - GAP_SIZE); + stream.next_in = BYTE_POS_ADDR (pos_byte); + stream.avail_in = avail_in; + stream.next_out = GPT_ADDR; + stream.avail_out = avail_out; + deflate_status = deflate (&stream, flush); + + pos_byte += avail_in - stream.avail_in; + compressed = avail_out - stream.avail_out; + insert_from_gap (compressed, compressed, 0); + unwind_data.nbytes += compressed; + if (deflate_status == Z_BUF_ERROR && flush == Z_NO_FLUSH) { + /* When we run out of input, zlib returns Z_BUF_ERROR. + We then have to flush all output. */ + flush = Z_FINISH; + deflate_status = Z_OK; + } + maybe_quit (); + } + while (deflate_status == Z_OK); + + Lisp_Object ret = Qt; + if (deflate_status != Z_STREAM_END) + { + /* When compression did not succeed, delete output. */ + ret = make_int (iend - pos_byte); + } + + unwind_data.start = 0; + + /* Delete the uncompressed data. */ + del_range_2 (istart, istart, /* byte and char offsets are the same. */ + iend, iend, 0); + + signal_after_change (istart, iend - istart, unwind_data.nbytes); + update_compositions (istart, istart, CHECK_HEAD); + + return unbind_to (count, ret); +} + /*********************************************************************** Initialization @@ -241,6 +387,7 @@ DEFUN ("zlib-decompress-region", Fzlib_decompress_region, syms_of_decompress (void) { defsubr (&Szlib_decompress_region); + defsubr (&Szlib_compress_region); defsubr (&Szlib_available_p); } --=-=-=--