copyright year update in the source header
[platform/upstream/curl.git] / lib / base64.c
1 /***************************************************************************
2  *                                  _   _ ____  _     
3  *  Project                     ___| | | |  _ \| |    
4  *                             / __| | | | |_) | |    
5  *                            | (__| |_| |  _ <| |___ 
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2003, 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  * $Id$
22  ***************************************************************************/
23
24 /* Base64 encoding/decoding
25  *
26  * Test harnesses down the bottom - compile with -DTEST_ENCODE for
27  * a program that will read in raw data from stdin and write out
28  * a base64-encoded version to stdout, and the length returned by the
29  * encoding function to stderr. Compile with -DTEST_DECODE for a program that
30  * will go the other way.
31  * 
32  * This code will break if int is smaller than 32 bits
33  */
34
35 #include "setup.h"
36
37 #include <stdlib.h>
38 #include <string.h>
39
40 #define _MPRINTF_REPLACE /* use our functions only */
41 #include <curl/mprintf.h>
42
43 #include "base64.h"
44
45 #ifdef MALLOCDEBUG
46 #include "memdebug.h"
47 #endif
48
49 static void decodeQuantum(unsigned char *dest, char *src)
50 {
51   unsigned int x = 0;
52   int i;
53   for(i = 0; i < 4; i++) {
54     if(src[i] >= 'A' && src[i] <= 'Z')
55       x = (x << 6) + (unsigned int)(src[i] - 'A' + 0);
56     else if(src[i] >= 'a' && src[i] <= 'z')
57       x = (x << 6) + (unsigned int)(src[i] - 'a' + 26);
58     else if(src[i] >= '0' && src[i] <= '9') 
59       x = (x << 6) + (unsigned int)(src[i] - '0' + 52);
60     else if(src[i] == '+')
61       x = (x << 6) + 62;
62     else if(src[i] == '/')
63       x = (x << 6) + 63;
64     else if(src[i] == '=')
65       x = (x << 6);
66   }
67
68   dest[2] = (unsigned char)(x & 255); x >>= 8;
69   dest[1] = (unsigned char)(x & 255); x >>= 8;
70   dest[0] = (unsigned char)(x & 255); x >>= 8;
71 }
72
73 /* base64Decode
74  * Given a base64 string at src, decode it into the memory pointed
75  * to by dest. If rawLength points to a valid address (ie not NULL),
76  * store the length of the decoded data to it.
77  */
78 static void base64Decode(unsigned char *dest, char *src, int *rawLength)
79 {
80   int length = 0;
81   int equalsTerm = 0;
82   int i;
83   int numQuantums;
84   unsigned char lastQuantum[3];
85         
86   while((src[length] != '=') && src[length])
87     length++;
88   while(src[length+equalsTerm] == '=')
89     equalsTerm++;
90   
91   numQuantums = (length + equalsTerm) / 4;
92   if(rawLength)
93     *rawLength = (numQuantums * 3) - equalsTerm;
94   
95   for(i = 0; i < numQuantums - 1; i++) {
96     decodeQuantum(dest, src);
97     dest += 3; src += 4;
98   }
99
100   decodeQuantum(lastQuantum, src);
101   for(i = 0; i < 3 - equalsTerm; i++)
102     dest[i] = lastQuantum[i];
103         
104 }
105
106 /* ---- Base64 Encoding --- */
107 static char table64[]=
108   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
109   
110 /*
111  * Curl_base64_encode()
112  *
113  * Returns the length of the newly created base64 string. The third argument
114  * is a pointer to an allocated area holding the base64 data. If something
115  * went wrong, -1 is returned.
116  *
117  */
118 int Curl_base64_encode(const void *inp, int insize, char **outptr)
119 {
120   unsigned char ibuf[3];
121   unsigned char obuf[4];
122   int i;
123   int inputparts;
124   char *output;
125   char *base64data;
126
127   char *indata = (char *)inp;
128
129   if(0 == insize)
130     insize = strlen(indata);
131
132   base64data = output = (char*)malloc(insize*4/3+4);
133   if(NULL == output)
134     return -1;
135
136   while(insize > 0) {
137     for (i = inputparts = 0; i < 3; i++) { 
138       if(*indata) {
139         inputparts++;
140         ibuf[i] = *indata;
141         indata++;
142         insize--;
143       }
144       else
145         ibuf[i] = 0;
146     }
147                        
148     obuf [0] = (ibuf [0] & 0xFC) >> 2;
149     obuf [1] = ((ibuf [0] & 0x03) << 4) | ((ibuf [1] & 0xF0) >> 4);
150     obuf [2] = ((ibuf [1] & 0x0F) << 2) | ((ibuf [2] & 0xC0) >> 6);
151     obuf [3] = ibuf [2] & 0x3F;
152
153     switch(inputparts) {
154     case 1: /* only one byte read */
155       sprintf(output, "%c%c==", 
156               table64[obuf[0]],
157               table64[obuf[1]]);
158       break;
159     case 2: /* two bytes read */
160       sprintf(output, "%c%c%c=", 
161               table64[obuf[0]],
162               table64[obuf[1]],
163               table64[obuf[2]]);
164       break;
165     default:
166       sprintf(output, "%c%c%c%c", 
167               table64[obuf[0]],
168               table64[obuf[1]],
169               table64[obuf[2]],
170               table64[obuf[3]] );
171       break;
172     }
173     output += 4;
174   }
175   *output=0;
176   *outptr = base64data; /* make it return the actual data memory */
177
178   return strlen(base64data); /* return the length of the new data */
179 }
180 /* ---- End of Base64 Encoding ---- */
181
182 int Curl_base64_decode(const char *str, void *data)
183 {
184   int ret;
185
186   base64Decode((unsigned char *)data, (char *)str, &ret);
187   return ret;
188 }
189
190 /************* TEST HARNESS STUFF ****************/
191
192
193 #ifdef TEST_ENCODE
194 /* encoding test harness. Read in standard input and write out the length
195  * returned by Curl_base64_encode, followed by the base64'd data itself
196  */
197 #include <stdio.h>
198
199 #define TEST_NEED_SUCK
200 void *suck(int *);
201
202 int main(int argc, char **argv, char **envp)
203 {
204   char *base64;
205   int base64Len;
206   unsigned char *data;
207   int dataLen;
208         
209   data = (unsigned char *)suck(&dataLen);
210   base64Len = Curl_base64_encode(data, dataLen, &base64);
211
212   fprintf(stderr, "%d\n", base64Len);
213   fprintf(stdout, "%s",   base64);
214   
215   free(base64); free(data);
216   return 0;
217 }
218 #endif
219
220 #ifdef TEST_DECODE
221 /* decoding test harness. Read in a base64 string from stdin and write out the 
222  * length returned by Curl_base64_decode, followed by the decoded data itself
223  */
224 #include <stdio.h>
225
226 #define TEST_NEED_SUCK
227 void *suck(int *);
228
229 int main(int argc, char **argv, char **envp)
230 {
231   char *base64;
232   int base64Len;
233   unsigned char *data;
234   int dataLen;
235         
236   base64 = (char *)suck(&base64Len);
237   data = (unsigned char *)malloc(base64Len * 3/4 + 8);
238   dataLen = Curl_base64_decode(base64, data);
239   
240   fprintf(stderr, "%d\n", dataLen);
241   fwrite(data,1,dataLen,stdout);
242   
243   free(base64); free(data);
244   return 0;
245 }
246 #endif
247
248 #ifdef TEST_NEED_SUCK
249 /* this function 'sucks' in as much as possible from stdin */
250 void *suck(int *lenptr)
251 {
252   int cursize = 8192;
253   unsigned char *buf = NULL;
254   int lastread;
255   int len = 0;
256         
257   do {
258     cursize *= 2;
259     buf = (unsigned char *)realloc(buf, cursize);
260     memset(buf + len, 0, cursize - len);
261     lastread = fread(buf + len, 1, cursize - len, stdin);
262     len += lastread;
263   } while(!feof(stdin));
264   
265   lenptr[0] = len;
266   return (void *)buf;
267 }
268 #endif
269
270 /*
271  * local variables:
272  * eval: (load-file "../curl-mode.el")
273  * end:
274  * vim600: fdm=marker
275  * vim: et sw=2 ts=2 sts=2 tw=78
276  */