~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to mysys/base64.cc

  • Committer: Monty Taylor
  • Date: 2009-04-14 19:16:51 UTC
  • mto: (997.2.5 mordred)
  • mto: This revision was merged to the branch mainline in revision 994.
  • Revision ID: mordred@inaugust.com-20090414191651-ltbww6hpqks8k7qk
Clarified instructions in README.

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