~drizzle-trunk/drizzle/development

1 by brian
clean slate
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
575.3.1 by Monty Taylor
Made mysys and mystrings c++. Fixed the resulting bugs the compiler found.
16
#include <drizzled/global.h>
212.5.18 by Monty Taylor
Moved m_ctype, m_string and my_bitmap. Removed t_ctype.
17
#include <mystrings/m_string.h>  /* strchr() */
18
#include <mystrings/m_ctype.h>  /* my_isspace() */
212.5.3 by Monty Taylor
Moved base64.h to mysys.
19
#include <mysys/base64.h>
919.2.11 by Monty Taylor
Removed C99 isnan() usage, which allows us to remove the util/math.{cc,h} workarounds. Yay for standards!
20
#include <cstdio>
21
#include <cmath>
575.3.1 by Monty Taylor
Made mysys and mystrings c++. Fixed the resulting bugs the compiler found.
22
919.2.13 by Monty Taylor
Added missing using namespace std;
23
using namespace std;
24
997.5.3 by chris
First stab at a #define to template replace
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
1 by brian
clean slate
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
{
595 by Brian Aker
Fix, partial, for Sun Studio.
63
  return (int) ceil((double)(length_of_encoded_data * 3 / 4));
1 by brian
clean slate
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
{
895 by Brian Aker
Completion (?) of uint conversion.
125
  return (uint32_t) (strchr(base64_table, c) - base64_table);
1 by brian
clean slate
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
997.5.3 by chris
First stab at a #define to template replace
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);
1 by brian
clean slate
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
997.5.3 by chris
First stab at a #define to template replace
202
    skip_space(src, i, len);
1 by brian
clean slate
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]= (c >> 16) & 0xff;
217
    b[1]= (c >>  8) & 0xff;
218
    b[2]= (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 : 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
      {
895 by Brian Aker
Completion (?) of uint conversion.
291
        printf("%.4x   ", (uint32_t) k);
1 by brian
clean slate
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",
895 by Brian Aker
Completion (?) of uint conversion.
308
             (uint32_t) src_len, (uint32_t) dst_len);
1 by brian
clean slate
309
      require(0);
310
    }
311
  }
312
  printf("Test succeeded.\n");
313
  return 0;
314
}
315
316
#endif