~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to mysys/base64.cc

  • Committer: Brian Aker
  • Date: 2009-10-12 06:15:02 UTC
  • mfrom: (1165.1.178 static-functions)
  • Revision ID: brian@gaz-20091012061502-cds4m0cya7ow8sj7
Merge Stewart

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