diff options
Diffstat (limited to 'lib/base64.c')
-rw-r--r-- | lib/base64.c | 247 |
1 files changed, 247 insertions, 0 deletions
diff --git a/lib/base64.c b/lib/base64.c new file mode 100644 index 000000000..edccf5402 --- /dev/null +++ b/lib/base64.c @@ -0,0 +1,247 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* Base64 encoding/decoding + * + * Test harnesses down the bottom - compile with -DTEST_ENCODE for + * a program that will read in raw data from stdin and write out + * a base64-encoded version to stdout, and the length returned by the + * encoding function to stderr. Compile with -DTEST_DECODE for a program that + * will go the other way. + * + * This code will break if int is smaller than 32 bits + */ + +#include "setup.h" + +#include <stdlib.h> +#include <string.h> + +#define _MPRINTF_REPLACE /* use our functions only */ +#include <curl/mprintf.h> + +#include "urldata.h" /* for the SessionHandle definition */ +#include "easyif.h" /* for Curl_convert_... prototypes */ +#include "warnless.h" +#include "curl_base64.h" +#include "curl_memory.h" + +/* include memdebug.h last */ +#include "memdebug.h" + +/* ---- Base64 Encoding/Decoding Table --- */ +static const char table64[]= + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static void decodeQuantum(unsigned char *dest, const char *src) +{ + const char *s, *p; + unsigned long i, v, x = 0; + + for(i = 0, s = src; i < 4; i++, s++) { + v = 0; + p = table64; + while(*p && (*p != *s)) { + v++; + p++; + } + if(*p == *s) + x = (x << 6) + v; + else if(*s == '=') + x = (x << 6); + } + + dest[2] = curlx_ultouc(x); + x >>= 8; + dest[1] = curlx_ultouc(x); + x >>= 8; + dest[0] = curlx_ultouc(x); +} + +/* + * Curl_base64_decode() + * + * Given a base64 string at src, decode it and return an allocated memory in + * the *outptr. Returns the length of the decoded data. + */ +size_t Curl_base64_decode(const char *src, unsigned char **outptr) +{ + size_t length = 0; + size_t equalsTerm = 0; + size_t i; + size_t numQuantums; + unsigned char lastQuantum[3]; + size_t rawlen = 0; + unsigned char *newstr; + + *outptr = NULL; + + while((src[length] != '=') && src[length]) + length++; + /* A maximum of two = padding characters is allowed */ + if(src[length] == '=') { + equalsTerm++; + if(src[length+equalsTerm] == '=') + equalsTerm++; + } + numQuantums = (length + equalsTerm) / 4; + + /* Don't allocate a buffer if the decoded length is 0 */ + if(numQuantums == 0) + return 0; + + rawlen = (numQuantums * 3) - equalsTerm; + + /* The buffer must be large enough to make room for the last quantum + (which may be partially thrown out) and the zero terminator. */ + newstr = malloc(rawlen+4); + if(!newstr) + return 0; + + *outptr = newstr; + + /* Decode all but the last quantum (which may not decode to a + multiple of 3 bytes) */ + for(i = 0; i < numQuantums - 1; i++) { + decodeQuantum(newstr, src); + newstr += 3; src += 4; + } + + /* This final decode may actually read slightly past the end of the buffer + if the input string is missing pad bytes. This will almost always be + harmless. */ + decodeQuantum(lastQuantum, src); + for(i = 0; i < 3 - equalsTerm; i++) + newstr[i] = lastQuantum[i]; + + newstr[i] = '\0'; /* zero terminate */ + return rawlen; +} + +/* + * Curl_base64_encode() + * + * Returns the length of the newly created base64 string. The third argument + * is a pointer to an allocated area holding the base64 data. If something + * went wrong, 0 is returned. + * + */ +size_t Curl_base64_encode(struct SessionHandle *data, + const char *inputbuff, size_t insize, + char **outptr) +{ + unsigned char ibuf[3]; + unsigned char obuf[4]; + int i; + int inputparts; + char *output; + char *base64data; +#ifdef CURL_DOES_CONVERSIONS + char *convbuf = NULL; +#endif + + const char *indata = inputbuff; + + *outptr = NULL; /* set to NULL in case of failure before we reach the end */ + + if(0 == insize) + insize = strlen(indata); + + base64data = output = malloc(insize*4/3+4); + if(NULL == output) + return 0; + +#ifdef CURL_DOES_CONVERSIONS + /* + * The base64 data needs to be created using the network encoding + * not the host encoding. And we can't change the actual input + * so we copy it to a buffer, translate it, and use that instead. + */ + if(data) { + convbuf = malloc(insize); + if(!convbuf) { + free(output); + return 0; + } + memcpy(convbuf, indata, insize); + if(CURLE_OK != Curl_convert_to_network(data, convbuf, insize)) { + free(convbuf); + free(output); + return 0; + } + indata = convbuf; /* switch to the converted buffer */ + } +#else + (void)data; +#endif + + while(insize > 0) { + for (i = inputparts = 0; i < 3; i++) { + if(insize > 0) { + inputparts++; + ibuf[i] = (unsigned char) *indata; + indata++; + insize--; + } + else + ibuf[i] = 0; + } + + obuf[0] = (unsigned char) ((ibuf[0] & 0xFC) >> 2); + obuf[1] = (unsigned char) (((ibuf[0] & 0x03) << 4) | \ + ((ibuf[1] & 0xF0) >> 4)); + obuf[2] = (unsigned char) (((ibuf[1] & 0x0F) << 2) | \ + ((ibuf[2] & 0xC0) >> 6)); + obuf[3] = (unsigned char) (ibuf[2] & 0x3F); + + switch(inputparts) { + case 1: /* only one byte read */ + snprintf(output, 5, "%c%c==", + table64[obuf[0]], + table64[obuf[1]]); + break; + case 2: /* two bytes read */ + snprintf(output, 5, "%c%c%c=", + table64[obuf[0]], + table64[obuf[1]], + table64[obuf[2]]); + break; + default: + snprintf(output, 5, "%c%c%c%c", + table64[obuf[0]], + table64[obuf[1]], + table64[obuf[2]], + table64[obuf[3]] ); + break; + } + output += 4; + } + *output=0; + *outptr = base64data; /* make it return the actual data memory */ + +#ifdef CURL_DOES_CONVERSIONS + if(data) + free(convbuf); +#endif + return strlen(base64data); /* return the length of the new data */ +} +/* ---- End of Base64 Encoding ---- */ |