1 /**
2 * Copyright (C) 2008 Happy Fish / YuQing
3 *
4 * FastDFS may be copied only under the terms of the GNU General
5 * Public License V3, which may be found in the FastDFS source kit.
6 * Please visit the FastDFS Home Page http://www.fastken.com/ for more detail.
7 **/
8
9 #include <time.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <ctype.h>
14 #include <unistd.h>
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #include <fcntl.h>
18 #include <errno.h>
19 #include "base64.h"
20
21 /**
22 * Marker value for chars we just ignore, e.g. \n \r high ascii
23 */
24 #define BASE64_IGNORE -1
25
26 /**
27 * Marker for = trailing pad
28 */
29 #define BASE64_PAD -2
30
31 /**
32 * determines how long the lines are that are generated by encode.
33 * Ignored by decode.
34 * @param length 0 means no newlines inserted. Must be a multiple of 4.
35 */
base64_set_line_length(struct base64_context * context,const int length)36 void base64_set_line_length(struct base64_context *context, const int length)
37 {
38 context->line_length = (length / 4) * 4;
39 }
40
41 /**
42 * How lines are separated.
43 * Ignored by decode.
44 * @param context->line_separator may be "" but not null.
45 * Usually contains only a combination of chars \n and \r.
46 * Could be any chars not in set A-Z a-z 0-9 + /.
47 */
base64_set_line_separator(struct base64_context * context,const char * pLineSeparator)48 void base64_set_line_separator(struct base64_context *context, \
49 const char *pLineSeparator)
50 {
51 context->line_sep_len = snprintf(context->line_separator, \
52 sizeof(context->line_separator), "%s", pLineSeparator);
53 if (context->line_sep_len >= sizeof(context->line_separator))
54 {
55 context->line_sep_len = sizeof(context->line_separator) - 1;
56 }
57 }
58
base64_init_ex(struct base64_context * context,const int nLineLength,const unsigned char chPlus,const unsigned char chSplash,const unsigned char chPad)59 void base64_init_ex(struct base64_context *context, const int nLineLength, \
60 const unsigned char chPlus, const unsigned char chSplash, \
61 const unsigned char chPad)
62 {
63 int i;
64
65 memset(context, 0, sizeof(struct base64_context));
66
67 context->line_length = nLineLength;
68 context->line_separator[0] = '\n';
69 context->line_separator[1] = '\0';
70 context->line_sep_len = 1;
71
72 // build translate valueToChar table only once.
73 // 0..25 -> 'A'..'Z'
74 for (i=0; i<=25; i++)
75 {
76 context->valueToChar[i] = (char)('A'+i);
77 }
78 // 26..51 -> 'a'..'z'
79 for (i=0; i<=25; i++ )
80 {
81 context->valueToChar[i+26] = (char)('a'+i);
82 }
83 // 52..61 -> '0'..'9'
84 for (i=0; i<=9; i++ )
85 {
86 context->valueToChar[i+52] = (char)('0'+i);
87 }
88 context->valueToChar[62] = chPlus;
89 context->valueToChar[63] = chSplash;
90
91 memset(context->charToValue, BASE64_IGNORE, sizeof(context->charToValue));
92 for (i=0; i<64; i++ )
93 {
94 context->charToValue[context->valueToChar[i]] = i;
95 }
96
97 context->pad_ch = chPad;
98 context->charToValue[chPad] = BASE64_PAD;
99 }
100
base64_get_encode_length(struct base64_context * context,const int nSrcLen)101 int base64_get_encode_length(struct base64_context *context, const int nSrcLen)
102 {
103 // Each group or partial group of 3 bytes becomes four chars
104 // covered quotient
105 int outputLength;
106
107 outputLength = ((nSrcLen + 2) / 3) * 4;
108
109 // account for trailing newlines, on all but the very last line
110 if (context->line_length != 0)
111 {
112 int lines = (outputLength + context->line_length - 1) /
113 context->line_length - 1;
114 if ( lines > 0 )
115 {
116 outputLength += lines * context->line_sep_len;
117 }
118 }
119
120 return outputLength;
121 }
122
123 /**
124 * Encode an arbitrary array of bytes as base64 printable ASCII.
125 * It will be broken into lines of 72 chars each. The last line is not
126 * terminated with a line separator.
127 * The output will always have an even multiple of data characters,
128 * exclusive of \n. It is padded out with =.
129 */
base64_encode_ex(struct base64_context * context,const char * src,const int nSrcLen,char * dest,int * dest_len,const bool bPad)130 char *base64_encode_ex(struct base64_context *context, const char *src, \
131 const int nSrcLen, char *dest, int *dest_len, const bool bPad)
132 {
133 int linePos;
134 int leftover;
135 int combined;
136 char *pDest;
137 int c0, c1, c2, c3;
138 unsigned char *pRaw;
139 unsigned char *pEnd;
140 const char *ppSrcs[2];
141 int lens[2];
142 char szPad[3];
143 int k;
144 int loop;
145
146 if (nSrcLen <= 0)
147 {
148 *dest = '\0';
149 *dest_len = 0;
150 return dest;
151 }
152
153 linePos = 0;
154 lens[0] = (nSrcLen / 3) * 3;
155 lens[1] = 3;
156 leftover = nSrcLen - lens[0];
157 ppSrcs[0] = src;
158 ppSrcs[1] = szPad;
159
160 szPad[0] = szPad[1] = szPad[2] = '\0';
161 switch (leftover)
162 {
163 case 0:
164 default:
165 loop = 1;
166 break;
167 case 1:
168 loop = 2;
169 szPad[0] = src[nSrcLen-1];
170 break;
171 case 2:
172 loop = 2;
173 szPad[0] = src[nSrcLen-2];
174 szPad[1] = src[nSrcLen-1];
175 break;
176 }
177
178 pDest = dest;
179 for (k=0; k<loop; k++)
180 {
181 pEnd = (unsigned char *)ppSrcs[k] + lens[k];
182 for (pRaw=(unsigned char *)ppSrcs[k]; pRaw<pEnd; pRaw+=3)
183 {
184 // Start a new line if next 4 chars won't fit on the current line
185 // We can't encapsulete the following code since the variable need to
186 // be local to this incarnation of encode.
187 linePos += 4;
188 if (linePos > context->line_length)
189 {
190 if (context->line_length != 0)
191 {
192 memcpy(pDest, context->line_separator, context->line_sep_len);
193 pDest += context->line_sep_len;
194 }
195 linePos = 4;
196 }
197
198 // get next three bytes in unsigned form lined up,
199 // in big-endian order
200 combined = ((*pRaw) << 16) | ((*(pRaw+1)) << 8) | (*(pRaw+2));
201
202 // break those 24 bits into a 4 groups of 6 bits,
203 // working LSB to MSB.
204 c3 = combined & 0x3f;
205 combined >>= 6;
206 c2 = combined & 0x3f;
207 combined >>= 6;
208 c1 = combined & 0x3f;
209 combined >>= 6;
210 c0 = combined & 0x3f;
211
212 // Translate into the equivalent alpha character
213 // emitting them in big-endian order.
214 *pDest++ = context->valueToChar[c0];
215 *pDest++ = context->valueToChar[c1];
216 *pDest++ = context->valueToChar[c2];
217 *pDest++ = context->valueToChar[c3];
218 }
219 }
220
221 *pDest = '\0';
222 *dest_len = pDest - dest;
223
224 // deal with leftover bytes
225 switch (leftover)
226 {
227 case 0:
228 default:
229 // nothing to do
230 break;
231 case 1:
232 // One leftover byte generates xx==
233 if (bPad)
234 {
235 *(pDest-1) = context->pad_ch;
236 *(pDest-2) = context->pad_ch;
237 }
238 else
239 {
240 *(pDest-2) = '\0';
241 *dest_len -= 2;
242 }
243 break;
244 case 2:
245 // Two leftover bytes generates xxx=
246 if (bPad)
247 {
248 *(pDest-1) = context->pad_ch;
249 }
250 else
251 {
252 *(pDest-1) = '\0';
253 *dest_len -= 1;
254 }
255 break;
256 } // end switch;
257
258 return dest;
259 }
260
base64_decode_auto(struct base64_context * context,const char * src,const int nSrcLen,char * dest,int * dest_len)261 char *base64_decode_auto(struct base64_context *context, const char *src, \
262 const int nSrcLen, char *dest, int *dest_len)
263 {
264 int nRemain;
265 int nPadLen;
266 int nNewLen;
267 char tmpBuff[256];
268 char *pBuff;
269
270 nRemain = nSrcLen % 4;
271 if (nRemain == 0)
272 {
273 return base64_decode(context, src, nSrcLen, dest, dest_len);
274 }
275
276 nPadLen = 4 - nRemain;
277 nNewLen = nSrcLen + nPadLen;
278 if (nNewLen <= sizeof(tmpBuff))
279 {
280 pBuff = tmpBuff;
281 }
282 else
283 {
284 pBuff = (char *)malloc(nNewLen);
285 if (pBuff == NULL)
286 {
287 fprintf(stderr, "Can't malloc %d bytes\n", \
288 nSrcLen + nPadLen + 1);
289 *dest_len = 0;
290 *dest = '\0';
291 return dest;
292 }
293 }
294
295 memcpy(pBuff, src, nSrcLen);
296 memset(pBuff + nSrcLen, context->pad_ch, nPadLen);
297
298 base64_decode(context, pBuff, nNewLen, dest, dest_len);
299
300 if (pBuff != tmpBuff)
301 {
302 free(pBuff);
303 }
304
305 return dest;
306 }
307
308 /**
309 * decode a well-formed complete base64 string back into an array of bytes.
310 * It must have an even multiple of 4 data characters (not counting \n),
311 * padded out with = as needed.
312 */
base64_decode(struct base64_context * context,const char * src,const int nSrcLen,char * dest,int * dest_len)313 char *base64_decode(struct base64_context *context, const char *src, \
314 const int nSrcLen, char *dest, int *dest_len)
315 {
316 // tracks where we are in a cycle of 4 input chars.
317 int cycle;
318
319 // where we combine 4 groups of 6 bits and take apart as 3 groups of 8.
320 int combined;
321
322 // will be an even multiple of 4 chars, plus some embedded \n
323 int dummies;
324 int value;
325 unsigned char *pSrc;
326 unsigned char *pSrcEnd;
327 char *pDest;
328
329 cycle = 0;
330 combined = 0;
331 dummies = 0;
332 pDest = dest;
333 pSrcEnd = (unsigned char *)src + nSrcLen;
334 for (pSrc=(unsigned char *)src; pSrc<pSrcEnd; pSrc++)
335 {
336 value = context->charToValue[*pSrc];
337 switch (value)
338 {
339 case BASE64_IGNORE:
340 // e.g. \n, just ignore it.
341 break;
342 case BASE64_PAD:
343 value = 0;
344 dummies++;
345 // fallthrough
346 default:
347 /* regular value character */
348 switch (cycle)
349 {
350 case 0:
351 combined = value;
352 cycle = 1;
353 break;
354 case 1:
355 combined <<= 6;
356 combined |= value;
357 cycle = 2;
358 break;
359 case 2:
360 combined <<= 6;
361 combined |= value;
362 cycle = 3;
363 break;
364 case 3:
365 combined <<= 6;
366 combined |= value;
367 // we have just completed a cycle of 4 chars.
368 // the four 6-bit values are in combined in big-endian order
369 // peel them off 8 bits at a time working lsb to msb
370 // to get our original 3 8-bit bytes back
371
372 *pDest++ = (char)(combined >> 16);
373 *pDest++ = (char)((combined & 0x0000FF00) >> 8);
374 *pDest++ = (char)(combined & 0x000000FF);
375
376 cycle = 0;
377 break;
378 }
379 break;
380 }
381 } // end for
382
383 if (cycle != 0)
384 {
385 *dest = '\0';
386 *dest_len = 0;
387 fprintf(stderr, "Input to decode not an even multiple of " \
388 "4 characters; pad with %c\n", context->pad_ch);
389 return dest;
390 }
391
392 *dest_len = (pDest - dest) - dummies;
393 *(dest + (*dest_len)) = '\0';
394
395 return dest;
396 }
397
398