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