1 /* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
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 #ifdef HAVE_COMPRESS
32 #include <my_sys.h>
33 #ifndef SCO
34 #include <m_string.h>
35 #endif
36 #include <zlib.h>
37
38 /*
39 This replaces the packet with a compressed packet
40
41 SYNOPSIS
42 my_compress()
43 packet Data to compress. This is is replaced with the compressed data.
44 len Length of data to compress at 'packet'
45 complen out: 0 if packet was not compressed
46
47 RETURN
48 1 error. 'len' is not changed'
49 0 ok. In this case 'len' contains the size of the compressed packet
50 */
51
my_compress(uchar * packet,size_t * len,size_t * complen)52 my_bool my_compress(uchar *packet, size_t *len, size_t *complen)
53 {
54 DBUG_ENTER("my_compress");
55 if (*len < MIN_COMPRESS_LENGTH)
56 {
57 *complen=0;
58 DBUG_PRINT("note",("Packet too short: Not compressed"));
59 }
60 else
61 {
62 uchar *compbuf=my_compress_alloc(packet,len,complen);
63 if (!compbuf)
64 DBUG_RETURN(*complen ? 0 : 1);
65 memcpy(packet,compbuf,*len);
66 my_free(compbuf);
67 }
68 DBUG_RETURN(0);
69 }
70
71
my_compress_alloc(const uchar * packet,size_t * len,size_t * complen)72 uchar *my_compress_alloc(const uchar *packet, size_t *len, size_t *complen)
73 {
74 uchar *compbuf;
75 uLongf tmp_complen;
76 int res;
77 *complen= *len * 120 / 100 + 12;
78
79 if (!(compbuf= (uchar *) my_malloc(*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(*complen,MYF(MY_WME));
129 int error;
130 if (!compbuf)
131 DBUG_RETURN(1); /* Not enough memory */
132
133 tmp_complen= (uint) *complen;
134 error= uncompress((Bytef*) compbuf, &tmp_complen, (Bytef*) packet,
135 (uLong) len);
136 *complen= tmp_complen;
137 if (error != Z_OK)
138 { /* Probably wrong packet */
139 DBUG_PRINT("error",("Can't uncompress packet, error: %d",error));
140 my_free(compbuf);
141 DBUG_RETURN(1);
142 }
143 memcpy(packet, compbuf, *complen);
144 my_free(compbuf);
145 }
146 else
147 *complen= len;
148 DBUG_RETURN(0);
149 }
150
151 /*
152 Internal representation of the frm blob is:
153
154 ver 4 bytes
155 orglen 4 bytes
156 complen 4 bytes
157 */
158
159 #define BLOB_HEADER 12
160
161
162 /*
163 packfrm is a method used to compress the frm file for storage in a
164 handler. This method was developed for the NDB handler and has been moved
165 here to serve also other uses.
166
167 SYNOPSIS
168 packfrm()
169 data Data reference to frm file data.
170 len Length of frm file data
171 out:pack_data Reference to the pointer to the packed frm data
172 out:pack_len Length of packed frm file data
173
174 NOTES
175 data is replaced with compressed content
176
177 RETURN VALUES
178 0 Success
179 >0 Failure
180 */
181
packfrm(uchar * data,size_t len,uchar ** pack_data,size_t * pack_len)182 int packfrm(uchar *data, size_t len,
183 uchar **pack_data, size_t *pack_len)
184 {
185 int error;
186 size_t org_len, comp_len, blob_len;
187 uchar *blob;
188 DBUG_ENTER("packfrm");
189 DBUG_PRINT("enter", ("data: 0x%lx len: %lu", (long) data, (ulong) len));
190
191 error= 1;
192 org_len= len;
193 if (my_compress((uchar*)data, &org_len, &comp_len))
194 goto err;
195
196 DBUG_PRINT("info", ("org_len: %lu comp_len: %lu", (ulong) org_len,
197 (ulong) comp_len));
198 DBUG_DUMP("compressed", data, org_len);
199
200 error= 2;
201 blob_len= BLOB_HEADER + org_len;
202 if (!(blob= (uchar*) my_malloc(blob_len,MYF(MY_WME))))
203 goto err;
204
205 /* Store compressed blob in machine independent format */
206 int4store(blob, 1);
207 int4store(blob+4, (uint32) len);
208 int4store(blob+8, (uint32) org_len); /* compressed length */
209
210 /* Copy frm data into blob, already in machine independent format */
211 memcpy(blob+BLOB_HEADER, data, org_len);
212
213 *pack_data= blob;
214 *pack_len= blob_len;
215 error= 0;
216
217 DBUG_PRINT("exit", ("pack_data: 0x%lx pack_len: %lu",
218 (long) *pack_data, (ulong) *pack_len));
219 err:
220 DBUG_RETURN(error);
221
222 }
223
224 /*
225 unpackfrm is a method used to decompress the frm file received from a
226 handler. This method was developed for the NDB handler and has been moved
227 here to serve also other uses for other clustered storage engines.
228
229 SYNOPSIS
230 unpackfrm()
231 pack_data Data reference to packed frm file data
232 out:unpack_data Reference to the pointer to the unpacked frm data
233 out:unpack_len Length of unpacked frm file data
234
235 RETURN VALUES¨
236 0 Success
237 >0 Failure
238 */
239
unpackfrm(uchar ** unpack_data,size_t * unpack_len,const uchar * pack_data)240 int unpackfrm(uchar **unpack_data, size_t *unpack_len,
241 const uchar *pack_data)
242 {
243 uchar *data;
244 size_t complen, orglen;
245 ulong ver;
246 DBUG_ENTER("unpackfrm");
247 DBUG_PRINT("enter", ("pack_data: 0x%lx", (long) pack_data));
248
249 ver= uint4korr(pack_data);
250 orglen= uint4korr(pack_data+4);
251 complen= uint4korr(pack_data+8);
252
253 DBUG_PRINT("blob",("ver: %lu complen: %lu orglen: %lu",
254 ver, (ulong) complen, (ulong) orglen));
255 DBUG_DUMP("blob->data", pack_data + BLOB_HEADER, complen);
256
257 if (ver != 1)
258 DBUG_RETURN(1);
259 if (!(data= my_malloc(MY_MAX(orglen, complen), MYF(MY_WME))))
260 DBUG_RETURN(2);
261 memcpy(data, pack_data + BLOB_HEADER, complen);
262
263 if (my_uncompress(data, complen, &orglen))
264 {
265 my_free(data);
266 DBUG_RETURN(3);
267 }
268
269 *unpack_data= data;
270 *unpack_len= orglen;
271
272 DBUG_PRINT("exit", ("frmdata: 0x%lx len: %lu", (long) *unpack_data,
273 (ulong) *unpack_len));
274 DBUG_RETURN(0);
275 }
276 #endif /* HAVE_COMPRESS */
277