summaryrefslogtreecommitdiffstats
path: root/mysys/my_compress.c
diff options
context:
space:
mode:
Diffstat (limited to 'mysys/my_compress.c')
-rw-r--r--mysys/my_compress.c186
1 files changed, 186 insertions, 0 deletions
diff --git a/mysys/my_compress.c b/mysys/my_compress.c
new file mode 100644
index 00000000..e30d42c2
--- /dev/null
+++ b/mysys/my_compress.c
@@ -0,0 +1,186 @@
+/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2022, MariaDB Corporation.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+/* Written by Sinisa Milivojevic <sinisa@mysql.com> */
+
+#include <mysys_priv.h>
+#ifdef HAVE_COMPRESS
+#include <my_sys.h>
+#ifndef SCO
+#include <m_string.h>
+#endif
+#include <zlib.h>
+
+/*
+ This replaces the packet with a compressed packet
+
+ SYNOPSIS
+ my_compress()
+ packet Data to compress. This is is replaced with the compressed data.
+ len Length of data to compress at 'packet'
+ complen out: 0 if packet was not compressed
+
+ RETURN
+ 1 error. 'len' is not changed'
+ 0 ok. In this case 'len' contains the size of the compressed packet
+*/
+
+my_bool my_compress(uchar *packet, size_t *len, size_t *complen)
+{
+ DBUG_ENTER("my_compress");
+ if (*len < MIN_COMPRESS_LENGTH)
+ {
+ *complen=0;
+ DBUG_PRINT("note",("Packet too short: Not compressed"));
+ }
+ else
+ {
+ uchar *compbuf=my_compress_alloc(packet,len,complen);
+ if (!compbuf)
+ DBUG_RETURN(*complen ? 0 : 1);
+ memcpy(packet,compbuf,*len);
+ my_free(compbuf);
+ }
+ DBUG_RETURN(0);
+}
+
+
+void *my_az_allocator(void *dummy __attribute__((unused)), unsigned int items,
+ unsigned int size)
+{
+ return my_malloc(key_memory_my_compress_alloc, (size_t)items*(size_t)size,
+ MYF(0));
+}
+
+void my_az_free(void *dummy __attribute__((unused)), void *address)
+{
+ my_free(address);
+}
+
+/*
+ This works like zlib compress(), but using custom memory allocators to work
+ better with my_malloc leak detection and Valgrind.
+*/
+int my_compress_buffer(uchar *dest, size_t *destLen,
+ const uchar *source, size_t sourceLen)
+{
+ z_stream stream;
+ int err;
+
+ stream.next_in = (Bytef*)source;
+ stream.avail_in = (uInt)sourceLen;
+ stream.next_out = (Bytef*)dest;
+ stream.avail_out = (uInt)*destLen;
+ if ((size_t)stream.avail_out != *destLen)
+ return Z_BUF_ERROR;
+
+ stream.zalloc = (alloc_func)my_az_allocator;
+ stream.zfree = (free_func)my_az_free;
+ stream.opaque = (voidpf)0;
+
+ err = deflateInit(&stream, Z_DEFAULT_COMPRESSION);
+ if (err != Z_OK) return err;
+
+ err = deflate(&stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ deflateEnd(&stream);
+ return err == Z_OK ? Z_BUF_ERROR : err;
+ }
+ *destLen = stream.total_out;
+
+ err = deflateEnd(&stream);
+ return err;
+}
+
+uchar *my_compress_alloc(const uchar *packet, size_t *len, size_t *complen)
+{
+ uchar *compbuf;
+ int res;
+ *complen= *len * 120 / 100 + 12;
+
+ if (!(compbuf= (uchar *) my_malloc(key_memory_my_compress_alloc,
+ *complen, MYF(MY_WME))))
+ return 0;
+
+ res= my_compress_buffer(compbuf, complen, packet, *len);
+
+ if (res != Z_OK)
+ {
+ my_free(compbuf);
+ return 0;
+ }
+
+ if (*complen >= *len)
+ {
+ *complen= 0;
+ my_free(compbuf);
+ DBUG_PRINT("note",("Packet got longer on compression; Not compressed"));
+ return 0;
+ }
+ /* Store length of compressed packet in *len */
+ swap_variables(size_t, *len, *complen);
+ return compbuf;
+}
+
+
+/*
+ Uncompress packet
+
+ SYNOPSIS
+ my_uncompress()
+ packet Compressed data. This is is replaced with the original data.
+ len Length of compressed data
+ complen Length of the packet buffer (must be enough for the original
+ data)
+
+ RETURN
+ 1 error
+ 0 ok. In this case 'complen' contains the updated size of the
+ real data.
+*/
+
+my_bool my_uncompress(uchar *packet, size_t len, size_t *complen)
+{
+ uLongf tmp_complen;
+ DBUG_ENTER("my_uncompress");
+
+ if (*complen) /* If compressed */
+ {
+ uchar *compbuf= (uchar *) my_malloc(key_memory_my_compress_alloc,
+ *complen,MYF(MY_WME));
+ int error;
+ if (!compbuf)
+ DBUG_RETURN(1); /* Not enough memory */
+
+ tmp_complen= (uLongf) *complen;
+ error= uncompress((Bytef*) compbuf, &tmp_complen, (Bytef*) packet,
+ (uLong) len);
+ *complen= tmp_complen;
+ if (error != Z_OK)
+ { /* Probably wrong packet */
+ DBUG_PRINT("error",("Can't uncompress packet, error: %d",error));
+ my_free(compbuf);
+ DBUG_RETURN(1);
+ }
+ memcpy(packet, compbuf, *complen);
+ my_free(compbuf);
+ }
+ else
+ *complen= len;
+ DBUG_RETURN(0);
+}
+
+#endif /* HAVE_COMPRESS */