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