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