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