~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to mysys/base64.cc

  • Committer: Brian Aker
  • Date: 2009-02-21 00:18:15 UTC
  • Revision ID: brian@tangent.org-20090221001815-x20e8h71e984lvs1
Completion (?) of uint conversion.

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