~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to mysys/base64.c

  • Committer: Monty Taylor
  • Date: 2008-09-16 00:00:48 UTC
  • mto: This revision was merged to the branch mainline in revision 391.
  • Revision ID: monty@inaugust.com-20080916000048-3rvrv3gv9l0ad3gs
Fixed copyright headers in drizzled/

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 <mystrings/m_string.h>  /* strchr() */
 
17
#include <mystrings/m_ctype.h>  /* my_isspace() */
 
18
#include <mysys/base64.h>
 
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
{                                                               \
 
111
  while (i < size && my_isspace(&my_charset_utf8_general_ci, * src))     \
 
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