~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>
612.2.6 by Monty Taylor
OpenSolaris builds.
20
#include <stdio.h>
21
#include CMATH_H
1 by brian
clean slate
22
575.3.1 by Monty Taylor
Made mysys and mystrings c++. Fixed the resulting bugs the compiler found.
23
#if defined(CMATH_NAMESPACE)
24
using namespace CMATH_NAMESPACE;
25
#endif
26
1 by brian
clean slate
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
{
595 by Brian Aker
Fix, partial, for Sun Studio.
50
  return (int) ceil((double)(length_of_encoded_data * 3 / 4));
1 by brian
clean slate
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 (uint) (strchr(base64_table, c) - base64_table);
113
}
114
115
116
#define SKIP_SPACE(src, i, size)                                \
117
{                                                               \
383.1.12 by Brian Aker
Much closer toward UTF8 being around all the time...
118
  while (i < size && my_isspace(&my_charset_utf8_general_ci, * src))     \
1 by brian
clean slate
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   ", (uint) 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
             (uint) src_len, (uint) dst_len);
310
      require(0);
311
    }
312
  }
313
  printf("Test succeeded.\n");
314
  return 0;
315
}
316
317
#endif