compiler warning: fix
[platform/upstream/curl.git] / lib / base64.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
10  * This software is licensed as described in the file COPYING, which
11  * you should have received as part of this distribution. The terms
12  * are also available at http://curl.haxx.se/docs/copyright.html.
13  *
14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15  * copies of the Software, and permit persons to whom the Software is
16  * furnished to do so, under the terms of the COPYING file.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  ***************************************************************************/
22
23 /* Base64 encoding/decoding */
24
25 #include "setup.h"
26
27 #include <stdlib.h>
28 #include <string.h>
29
30 #define _MPRINTF_REPLACE /* use our functions only */
31 #include <curl/mprintf.h>
32
33 #include "urldata.h" /* for the SessionHandle definition */
34 #include "warnless.h"
35 #include "curl_base64.h"
36 #include "curl_memory.h"
37 #include "non-ascii.h"
38
39 /* include memdebug.h last */
40 #include "memdebug.h"
41
42 /* ---- Base64 Encoding/Decoding Table --- */
43 static const char table64[]=
44   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
45
46 static void decodeQuantum(unsigned char *dest, const char *src)
47 {
48   const char *s, *p;
49   unsigned long i, v, x = 0;
50
51   for(i = 0, s = src; i < 4; i++, s++) {
52     v = 0;
53     p = table64;
54     while(*p && (*p != *s)) {
55       v++;
56       p++;
57     }
58     if(*p == *s)
59       x = (x << 6) + v;
60     else if(*s == '=')
61       x = (x << 6);
62   }
63
64   dest[2] = curlx_ultouc(x);
65   x >>= 8;
66   dest[1] = curlx_ultouc(x);
67   x >>= 8;
68   dest[0] = curlx_ultouc(x);
69 }
70
71 /*
72  * Curl_base64_decode()
73  *
74  * Given a base64 string at src, decode it and return an allocated memory in
75  * the *outptr. Returns the length of the decoded data.
76  */
77 size_t Curl_base64_decode(const char *src, unsigned char **outptr)
78 {
79   size_t length = 0;
80   size_t equalsTerm = 0;
81   size_t i;
82   size_t numQuantums;
83   unsigned char lastQuantum[3];
84   size_t rawlen = 0;
85   unsigned char *newstr;
86
87   *outptr = NULL;
88
89   while((src[length] != '=') && src[length])
90     length++;
91   /* A maximum of two = padding characters is allowed */
92   if(src[length] == '=') {
93     equalsTerm++;
94     if(src[length+equalsTerm] == '=')
95       equalsTerm++;
96   }
97   numQuantums = (length + equalsTerm) / 4;
98
99   /* Don't allocate a buffer if the decoded length is 0 */
100   if(numQuantums == 0)
101     return 0;
102
103   rawlen = (numQuantums * 3) - equalsTerm;
104
105   /* The buffer must be large enough to make room for the last quantum
106   (which may be partially thrown out) and the zero terminator. */
107   newstr = malloc(rawlen+4);
108   if(!newstr)
109     return 0;
110
111   *outptr = newstr;
112
113   /* Decode all but the last quantum (which may not decode to a
114   multiple of 3 bytes) */
115   for(i = 0; i < numQuantums - 1; i++) {
116     decodeQuantum(newstr, src);
117     newstr += 3; src += 4;
118   }
119
120   /* This final decode may actually read slightly past the end of the buffer
121   if the input string is missing pad bytes.  This will almost always be
122   harmless. */
123   decodeQuantum(lastQuantum, src);
124   for(i = 0; i < 3 - equalsTerm; i++)
125     newstr[i] = lastQuantum[i];
126
127   newstr[i] = '\0'; /* zero terminate */
128   return rawlen;
129 }
130
131 /*
132  * Curl_base64_encode()
133  *
134  * Returns the length of the newly created base64 string. The third argument
135  * is a pointer to an allocated area holding the base64 data. If something
136  * went wrong, 0 is returned.
137  *
138  */
139 size_t Curl_base64_encode(struct SessionHandle *data,
140                           const char *inputbuff, size_t insize,
141                           char **outptr)
142 {
143   CURLcode res;
144   unsigned char ibuf[3];
145   unsigned char obuf[4];
146   int i;
147   int inputparts;
148   char *output;
149   char *base64data;
150   char *convbuf = NULL;
151
152   const char *indata = inputbuff;
153
154   *outptr = NULL; /* set to NULL in case of failure before we reach the end */
155
156   if(0 == insize)
157     insize = strlen(indata);
158
159   base64data = output = malloc(insize*4/3+4);
160   if(NULL == output)
161     return 0;
162
163   /*
164    * The base64 data needs to be created using the network encoding
165    * not the host encoding.  And we can't change the actual input
166    * so we copy it to a buffer, translate it, and use that instead.
167    */
168   res = Curl_convert_clone(data, indata, insize, &convbuf);
169   if(res) {
170     free(output);
171     return 0;
172   }
173
174   if(convbuf)
175     indata = (char *)convbuf;
176
177   while(insize > 0) {
178     for(i = inputparts = 0; i < 3; i++) {
179       if(insize > 0) {
180         inputparts++;
181         ibuf[i] = (unsigned char) *indata;
182         indata++;
183         insize--;
184       }
185       else
186         ibuf[i] = 0;
187     }
188
189     obuf[0] = (unsigned char)  ((ibuf[0] & 0xFC) >> 2);
190     obuf[1] = (unsigned char) (((ibuf[0] & 0x03) << 4) | \
191                                ((ibuf[1] & 0xF0) >> 4));
192     obuf[2] = (unsigned char) (((ibuf[1] & 0x0F) << 2) | \
193                                ((ibuf[2] & 0xC0) >> 6));
194     obuf[3] = (unsigned char)   (ibuf[2] & 0x3F);
195
196     switch(inputparts) {
197     case 1: /* only one byte read */
198       snprintf(output, 5, "%c%c==",
199                table64[obuf[0]],
200                table64[obuf[1]]);
201       break;
202     case 2: /* two bytes read */
203       snprintf(output, 5, "%c%c%c=",
204                table64[obuf[0]],
205                table64[obuf[1]],
206                table64[obuf[2]]);
207       break;
208     default:
209       snprintf(output, 5, "%c%c%c%c",
210                table64[obuf[0]],
211                table64[obuf[1]],
212                table64[obuf[2]],
213                table64[obuf[3]] );
214       break;
215     }
216     output += 4;
217   }
218   *output=0;
219   *outptr = base64data; /* make it return the actual data memory */
220
221   if(convbuf)
222     free(convbuf);
223
224   return strlen(base64data); /* return the length of the new data */
225 }
226 /* ---- End of Base64 Encoding ---- */