~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to mysys/base64.cc

  • Committer: Padraig O'Sullivan
  • Date: 2009-09-13 01:03:01 UTC
  • mto: (1126.9.2 captain-20090915-01)
  • mto: This revision was merged to the branch mainline in revision 1133.
  • Revision ID: osullivan.padraig@gmail.com-20090913010301-tcvvezipx1124acy
Added calls to the dtrace delete begin/end probes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2003 MySQL AB
 
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 as published by
 
5
   the Free Software Foundation; version 2 of the License.
 
6
 
 
7
   This program is distributed in the hope that it will be useful,
 
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
10
   GNU General Public License for more details.
 
11
 
 
12
   You should have received a copy of the GNU General Public License
 
13
   along with this program; if not, write to the Free Software
 
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
15
 
 
16
#include <drizzled/global.h>
 
17
#include <mystrings/m_string.h>  /* strchr() */
 
18
#include <mystrings/m_ctype.h>  /* my_isspace() */
 
19
#include <mysys/base64.h>
 
20
#include <cstdio>
 
21
#include <cmath>
 
22
 
 
23
using namespace std;
 
24
 
 
25
template <class T, class U>
 
26
inline void skip_space(T src, U i, const U size)
 
27
{
 
28
  while (i < size && my_isspace(&my_charset_utf8_general_ci, * src))
 
29
  {
 
30
    i++;
 
31
    src++;
 
32
 
 
33
    if (i == size)
 
34
    {
 
35
      break;
 
36
    }
 
37
  }
 
38
}
 
39
 
 
40
#ifndef MAIN
 
41
 
 
42
static char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
 
43
                             "abcdefghijklmnopqrstuvwxyz"
 
44
                             "0123456789+/";
 
45
 
 
46
 
 
47
int
 
48
base64_needed_encoded_length(int length_of_data)
 
49
{
 
50
  int nb_base64_chars;
 
51
  nb_base64_chars= (length_of_data + 2) / 3 * 4;
 
52
 
 
53
  return
 
54
    nb_base64_chars +            /* base64 char incl padding */
 
55
    (nb_base64_chars - 1)/ 76 +  /* newlines */
 
56
    1;                           /* NUL termination of string */
 
57
}
 
58
 
 
59
 
 
60
int
 
61
base64_needed_decoded_length(int length_of_encoded_data)
 
62
{
 
63
  return (int) ceil((double)(length_of_encoded_data * 3 / 4));
 
64
}
 
65
 
 
66
 
 
67
/*
 
68
  Encode a data as base64.
 
69
 
 
70
  Note: We require that dst is pre-allocated to correct size.
 
71
        See base64_needed_encoded_length().
 
72
*/
 
73
 
 
74
int
 
75
base64_encode(const void *src, size_t src_len, char *dst)
 
76
{
 
77
  const unsigned char *s= (const unsigned char*)src;
 
78
  size_t i= 0;
 
79
  size_t len= 0;
 
80
 
 
81
  for (; i < src_len; len += 4)
 
82
  {
 
83
    unsigned c;
 
84
 
 
85
    if (len == 76)
 
86
    {
 
87
      len= 0;
 
88
      *dst++= '\n';
 
89
    }
 
90
 
 
91
    c= s[i++];
 
92
    c <<= 8;
 
93
 
 
94
    if (i < src_len)
 
95
      c += s[i];
 
96
    c <<= 8;
 
97
    i++;
 
98
 
 
99
    if (i < src_len)
 
100
      c += s[i];
 
101
    i++;
 
102
 
 
103
    *dst++= base64_table[(c >> 18) & 0x3f];
 
104
    *dst++= base64_table[(c >> 12) & 0x3f];
 
105
 
 
106
    if (i > (src_len + 1))
 
107
      *dst++= '=';
 
108
    else
 
109
      *dst++= base64_table[(c >> 6) & 0x3f];
 
110
 
 
111
    if (i > src_len)
 
112
      *dst++= '=';
 
113
    else
 
114
      *dst++= base64_table[(c >> 0) & 0x3f];
 
115
  }
 
116
  *dst= '\0';
 
117
 
 
118
  return 0;
 
119
}
 
120
 
 
121
 
 
122
static inline uint
 
123
pos(unsigned char c)
 
124
{
 
125
  return (uint32_t) (strchr(base64_table, c) - base64_table);
 
126
}
 
127
 
 
128
 
 
129
/*
 
130
  Decode a base64 string
 
131
 
 
132
  SYNOPSIS
 
133
    base64_decode()
 
134
    src      Pointer to base64-encoded string
 
135
    len      Length of string at 'src'
 
136
    dst      Pointer to location where decoded data will be stored
 
137
    end_ptr  Pointer to variable that will refer to the character
 
138
             after the end of the encoded data that were decoded. Can
 
139
             be NULL.
 
140
 
 
141
  DESCRIPTION
 
142
 
 
143
    The base64-encoded data in the range ['src','*end_ptr') will be
 
144
    decoded and stored starting at 'dst'.  The decoding will stop
 
145
    after 'len' characters have been read from 'src', or when padding
 
146
    occurs in the base64-encoded data. In either case: if 'end_ptr' is
 
147
    non-null, '*end_ptr' will be set to point to the character after
 
148
    the last read character, even in the presence of error.
 
149
 
 
150
  NOTE
 
151
    We require that 'dst' is pre-allocated to correct size.
 
152
 
 
153
  SEE ALSO
 
154
    base64_needed_decoded_length().
 
155
 
 
156
  RETURN VALUE
 
157
    Number of bytes written at 'dst' or -1 in case of failure
 
158
*/
 
159
int
 
160
base64_decode(const char *src_base, size_t len,
 
161
              void *dst, const char **end_ptr)
 
162
{
 
163
  char b[3];
 
164
  size_t i= 0;
 
165
  char *dst_base= (char *)dst;
 
166
  char const *src= src_base;
 
167
  char *d= dst_base;
 
168
  size_t j;
 
169
 
 
170
  while (i < len)
 
171
  {
 
172
    unsigned c= 0;
 
173
    size_t mark= 0;
 
174
 
 
175
    skip_space(src, i, len);
 
176
 
 
177
    c += pos(*src++);
 
178
    c <<= 6;
 
179
    i++;
 
180
 
 
181
    skip_space(src, i, len);
 
182
 
 
183
    c += pos(*src++);
 
184
    c <<= 6;
 
185
    i++;
 
186
 
 
187
    skip_space(src, i, len);
 
188
 
 
189
    if (*src != '=')
 
190
      c += pos(*src++);
 
191
    else
 
192
    {
 
193
      src += 2;                /* There should be two bytes padding */
 
194
      i= len;
 
195
      mark= 2;
 
196
      c <<= 6;
 
197
      goto end;
 
198
    }
 
199
    c <<= 6;
 
200
    i++;
 
201
 
 
202
    skip_space(src, i, len);
 
203
 
 
204
    if (*src != '=')
 
205
      c += pos(*src++);
 
206
    else
 
207
    {
 
208
      src += 1;                 /* There should be one byte padding */
 
209
      i= len;
 
210
      mark= 1;
 
211
      goto end;
 
212
    }
 
213
    i++;
 
214
 
 
215
  end:
 
216
    b[0]= char((c >> 16) & 0xff);
 
217
    b[1]= char((c >>  8) & 0xff);
 
218
    b[2]= char((c >>  0) & 0xff);
 
219
 
 
220
    for (j=0; j<3-mark; j++)
 
221
      *d++= b[j];
 
222
  }
 
223
 
 
224
  if (end_ptr != NULL)
 
225
    *end_ptr= src;
 
226
 
 
227
  /*
 
228
    The variable 'i' is set to 'len' when padding has been read, so it
 
229
    does not actually reflect the number of bytes read from 'src'.
 
230
   */
 
231
  return (i != len) ? -1 : int(d - dst_base);
 
232
}
 
233
 
 
234
 
 
235
#else /* MAIN */
 
236
 
 
237
#define require(b) { \
 
238
  if (!(b)) { \
 
239
    printf("Require failed at %s:%d\n", __FILE__, __LINE__); \
 
240
    abort(); \
 
241
  } \
 
242
}
 
243
 
 
244
 
 
245
int
 
246
main(void)
 
247
{
 
248
  int i;
 
249
  size_t j;
 
250
  size_t k, l;
 
251
  size_t dst_len;
 
252
  size_t needed_length;
 
253
 
 
254
  for (i= 0; i < 500; i++)
 
255
  {
 
256
    /* Create source data */
 
257
    const size_t src_len= rand() % 1000 + 1;
 
258
 
 
259
    char * src= (char *) malloc(src_len);
 
260
    char * s= src;
 
261
    char * str;
 
262
    char * dst;
 
263
 
 
264
    require(src);
 
265
    for (j= 0; j<src_len; j++)
 
266
    {
 
267
      char c= rand();
 
268
      *s++= c;
 
269
    }
 
270
 
 
271
    /* Encode */
 
272
    needed_length= base64_needed_encoded_length(src_len);
 
273
    str= (char *) malloc(needed_length);
 
274
    require(str);
 
275
    for (k= 0; k < needed_length; k++)
 
276
      str[k]= 0xff; /* Fill memory to check correct NUL termination */
 
277
    require(base64_encode(src, src_len, str) == 0);
 
278
    require(needed_length == strlen(str) + 1);
 
279
 
 
280
    /* Decode */
 
281
    dst= (char *) malloc(base64_needed_decoded_length(strlen(str)));
 
282
    require(dst);
 
283
    dst_len= base64_decode(str, strlen(str), dst, NULL);
 
284
    require(dst_len == src_len);
 
285
 
 
286
    if (memcmp(src, dst, src_len) != 0)
 
287
    {
 
288
      printf("       --------- src ---------   --------- dst ---------\n");
 
289
      for (k= 0; k<src_len; k+=8)
 
290
      {
 
291
        printf("%.4x   ", (uint32_t) k);
 
292
        for (l=0; l<8 && k+l<src_len; l++)
 
293
        {
 
294
          unsigned char c= src[k+l];
 
295
          printf("%.2x ", (unsigned)c);
 
296
        }
 
297
 
 
298
        printf("  ");
 
299
 
 
300
        for (l=0; l<8 && k+l<dst_len; l++)
 
301
        {
 
302
          unsigned char c= dst[k+l];
 
303
          printf("%.2x ", (unsigned)c);
 
304
        }
 
305
        printf("\n");
 
306
      }
 
307
      printf("src length: %.8x, dst length: %.8x\n",
 
308
             (uint32_t) src_len, (uint32_t) dst_len);
 
309
      require(0);
 
310
    }
 
311
  }
 
312
  printf("Test succeeded.\n");
 
313
  return 0;
 
314
}
 
315
 
 
316
#endif