[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: decompress.c now also compresses
From: |
Juan José García-Ripoll |
Subject: |
Re: decompress.c now also compresses |
Date: |
Sun, 29 Mar 2020 17:57:23 +0200 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/26.3 (windows-nt) |
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
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);
}