~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to mysys/base64.c

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

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 <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