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