all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: "Juan José García-Ripoll" <juanjose.garciaripoll@gmail.com>
To: emacs-devel@gnu.org
Subject: Re: decompress.c now also compresses
Date: Sun, 29 Mar 2020 17:57:23 +0200	[thread overview]
Message-ID: <86sghr17do.fsf@csic.es> (raw)
In-Reply-To: 86zhbz17mk.fsf@csic.es

[-- Attachment #1: Type: text/plain, Size: 232 bytes --]

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


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: decompress.diff --]
[-- Type: text/x-patch, Size: 6952 bytes --]

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);
 }

+\f
+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);
+}
+
 \f
 /***********************************************************************
 			    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);
 }

  reply	other threads:[~2020-03-29 15:57 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-03-29 15:52 decompress.c now also compresses Juan José García-Ripoll
2020-03-29 15:57 ` Juan José García-Ripoll [this message]
2020-03-29 16:11 ` Eli Zaretskii
2020-03-29 16:48   ` Juan José García-Ripoll
2020-03-29 16:54 ` Stefan Monnier
2020-03-29 19:27   ` Juan José García-Ripoll

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=86sghr17do.fsf@csic.es \
    --to=juanjose.garciaripoll@gmail.com \
    --cc=emacs-devel@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.