1 /* Copyright (c) 2000, 2021, Oracle and/or its affiliates.
2 
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License, version 2.0,
5    as published by the Free Software Foundation.
6 
7    This program is also distributed with certain software (including
8    but not limited to OpenSSL) that is licensed under separate terms,
9    as designated in a particular file or component or in included license
10    documentation.  The authors of MySQL hereby grant you an additional
11    permission to link the program and your derivative works with the
12    separately licensed software that they have included with MySQL.
13 
14    Without limiting anything contained in the foregoing, this file,
15    which is part of C Driver for MySQL (Connector/C), is also subject to the
16    Universal FOSS Exception, version 1.0, a copy of which can be found at
17    http://oss.oracle.com/licenses/universal-foss-exception.
18 
19    This program is distributed in the hope that it will be useful,
20    but WITHOUT ANY WARRANTY; without even the implied warranty of
21    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22    GNU General Public License, version 2.0, for more details.
23 
24    You should have received a copy of the GNU General Public License
25    along with this program; if not, write to the Free Software
26    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
27 
28 /* Written by Sinisa Milivojevic <sinisa@mysql.com> */
29 
30 #include <my_global.h>
31 #include <mysys_priv.h>
32 #ifdef HAVE_COMPRESS
33 #include <my_sys.h>
34 #include <m_string.h>
35 #include <zlib.h>
36 
37 /*
38    This replaces the packet with a compressed packet
39 
40    SYNOPSIS
41      my_compress()
42      packet	Data to compress. This is is replaced with the compressed data.
43      len	Length of data to compress at 'packet'
44      complen	out: 0 if packet was not compressed
45 
46    RETURN
47      1   error. 'len' is not changed'
48      0   ok.  In this case 'len' contains the size of the compressed packet
49 */
50 
my_compress(uchar * packet,size_t * len,size_t * complen)51 my_bool my_compress(uchar *packet, size_t *len, size_t *complen)
52 {
53   DBUG_ENTER("my_compress");
54   if (*len < MIN_COMPRESS_LENGTH)
55   {
56     *complen=0;
57     DBUG_PRINT("note",("Packet too short: Not compressed"));
58   }
59   else
60   {
61     uchar *compbuf=my_compress_alloc(packet,len,complen);
62     if (!compbuf)
63       DBUG_RETURN(*complen ? 0 : 1);
64     memcpy(packet,compbuf,*len);
65     my_free(compbuf);
66   }
67   DBUG_RETURN(0);
68 }
69 
70 
my_compress_alloc(const uchar * packet,size_t * len,size_t * complen)71 uchar *my_compress_alloc(const uchar *packet, size_t *len, size_t *complen)
72 {
73   uchar *compbuf;
74   uLongf tmp_complen;
75   int res;
76   *complen=  *len * 120 / 100 + 12;
77 
78   if (!(compbuf= (uchar *) my_malloc(key_memory_my_compress_alloc,
79                                      *complen, MYF(MY_WME))))
80     return 0;					/* Not enough memory */
81 
82   tmp_complen= (uint) *complen;
83   res= compress((Bytef*) compbuf, &tmp_complen, (Bytef*) packet, (uLong) *len);
84   *complen=    tmp_complen;
85 
86   if (res != Z_OK)
87   {
88     my_free(compbuf);
89     return 0;
90   }
91 
92   if (*complen >= *len)
93   {
94     *complen= 0;
95     my_free(compbuf);
96     DBUG_PRINT("note",("Packet got longer on compression; Not compressed"));
97     return 0;
98   }
99   /* Store length of compressed packet in *len */
100   swap_variables(size_t, *len, *complen);
101   return compbuf;
102 }
103 
104 
105 /*
106   Uncompress packet
107 
108    SYNOPSIS
109      my_uncompress()
110      packet	Compressed data. This is is replaced with the orignal data.
111      len	Length of compressed data
112      complen	Length of the packet buffer (must be enough for the original
113 	        data)
114 
115    RETURN
116      1   error
117      0   ok.  In this case 'complen' contains the updated size of the
118               real data.
119 */
120 
my_uncompress(uchar * packet,size_t len,size_t * complen)121 my_bool my_uncompress(uchar *packet, size_t len, size_t *complen)
122 {
123   uLongf tmp_complen;
124   DBUG_ENTER("my_uncompress");
125 
126   if (*complen)					/* If compressed */
127   {
128     uchar *compbuf= (uchar *) my_malloc(key_memory_my_compress_alloc,
129                                         *complen,MYF(MY_WME));
130     int error;
131     if (!compbuf)
132       DBUG_RETURN(1);				/* Not enough memory */
133 
134     tmp_complen= (uint) *complen;
135     error= uncompress((Bytef*) compbuf, &tmp_complen, (Bytef*) packet,
136                       (uLong) len);
137     *complen= tmp_complen;
138     if (error != Z_OK)
139     {						/* Probably wrong packet */
140       DBUG_PRINT("error",("Can't uncompress packet, error: %d",error));
141       my_free(compbuf);
142       DBUG_RETURN(1);
143     }
144     memcpy(packet, compbuf, *complen);
145     my_free(compbuf);
146   }
147   else
148     *complen= len;
149   DBUG_RETURN(0);
150 }
151 
152 /*
153   Internal representation of the frm blob is:
154 
155   ver	  4 bytes
156   orglen  4 bytes
157   complen 4 bytes
158 */
159 
160 #define BLOB_HEADER 12
161 
162 
163 /*
164   packfrm is a method used to compress the frm file for storage in a
165   handler. This method was developed for the NDB handler and has been moved
166   here to serve also other uses.
167 
168   SYNOPSIS
169     packfrm()
170     data                    Data reference to frm file data.
171     len                     Length of frm file data
172     out:pack_data           Reference to the pointer to the packed frm data
173     out:pack_len            Length of packed frm file data
174 
175   NOTES
176     data is replaced with compressed content
177 
178   RETURN VALUES
179     0                       Success
180     >0                      Failure
181 */
182 
packfrm(uchar * data,size_t len,uchar ** pack_data,size_t * pack_len)183 int packfrm(uchar *data, size_t len,
184             uchar **pack_data, size_t *pack_len)
185 {
186   int error;
187   size_t org_len, comp_len, blob_len;
188   uchar *blob;
189   DBUG_ENTER("packfrm");
190   DBUG_PRINT("enter", ("data: 0x%lx  len: %lu", (long) data, (ulong) len));
191 
192   error= 1;
193   org_len= len;
194   if (my_compress((uchar*)data, &org_len, &comp_len))
195     goto err;
196 
197   DBUG_PRINT("info", ("org_len: %lu  comp_len: %lu", (ulong) org_len,
198                       (ulong) comp_len));
199   DBUG_DUMP("compressed", data, org_len);
200 
201   error= 2;
202   blob_len= BLOB_HEADER + org_len;
203   if (!(blob= (uchar*) my_malloc(key_memory_pack_frm,
204                                  blob_len,MYF(MY_WME))))
205     goto err;
206 
207   /* Store compressed blob in machine independent format */
208   int4store(blob, 1);
209   int4store(blob+4, (uint32) len);
210   int4store(blob+8, (uint32) org_len);          /* compressed length */
211 
212   /* Copy frm data into blob, already in machine independent format */
213   memcpy(blob+BLOB_HEADER, data, org_len);
214 
215   *pack_data= blob;
216   *pack_len=  blob_len;
217   error= 0;
218 
219   DBUG_PRINT("exit", ("pack_data: 0x%lx  pack_len: %lu",
220                       (long) *pack_data, (ulong) *pack_len));
221 err:
222   DBUG_RETURN(error);
223 
224 }
225 
226 /*
227   unpackfrm is a method used to decompress the frm file received from a
228   handler. This method was developed for the NDB handler and has been moved
229   here to serve also other uses for other clustered storage engines.
230 
231   SYNOPSIS
232     unpackfrm()
233     pack_data               Data reference to packed frm file data
234     out:unpack_data         Reference to the pointer to the unpacked frm data
235     out:unpack_len          Length of unpacked frm file data
236 
237   RETURN VALUES¨
238     0                       Success
239     >0                      Failure
240 */
241 
unpackfrm(uchar ** unpack_data,size_t * unpack_len,const uchar * pack_data)242 int unpackfrm(uchar **unpack_data, size_t *unpack_len,
243               const uchar *pack_data)
244 {
245    uchar *data;
246    size_t complen, orglen;
247    ulong ver;
248    DBUG_ENTER("unpackfrm");
249    DBUG_PRINT("enter", ("pack_data: 0x%lx", (long) pack_data));
250 
251    ver=         uint4korr(pack_data);
252    orglen=      uint4korr(pack_data+4);
253    complen=     uint4korr(pack_data+8);
254 
255    DBUG_PRINT("blob",("ver: %lu  complen: %lu  orglen: %lu",
256                       ver, (ulong) complen, (ulong) orglen));
257    DBUG_DUMP("blob->data", pack_data + BLOB_HEADER, complen);
258 
259    if (ver != 1)
260      DBUG_RETURN(1);
261    if (!(data= my_malloc(key_memory_pack_frm,
262                          MY_MAX(orglen, complen), MYF(MY_WME))))
263      DBUG_RETURN(2);
264    memcpy(data, pack_data + BLOB_HEADER, complen);
265 
266    if (my_uncompress(data, complen, &orglen))
267    {
268      my_free(data);
269      DBUG_RETURN(3);
270    }
271 
272    *unpack_data= data;
273    *unpack_len=  orglen;
274 
275    DBUG_PRINT("exit", ("frmdata: 0x%lx  len: %lu", (long) *unpack_data,
276                        (ulong) *unpack_len));
277    DBUG_RETURN(0);
278 }
279 #endif /* HAVE_COMPRESS */
280