/* * e4base64.c -- * * Implementation of BASE64 encoding/decoing (RFC 1341). * * Authors: Jacob Levy and Jean-Claude Wippler. * jyl@best.com jcw@equi4.com * * Copyright: JYL Software, Inc., (c) 2000-2003. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE, EVEN IF * JYL SOFTWARE INC. IS MADE AWARE OF THE POSSIBILITY OF SUCH DAMAGE. */ #include /* * Ensure propert exporting of symbols on WIN32: */ /* * Export declarations: */ #ifndef e4_XMLDLL #if defined(_WIN32) && !defined(E4_STATIC) #ifdef E4_XMLDLL #define e4_XMLDLL __declspec(dllexport) #else #define e4_XMLDLL __declspec(dllimport) #endif #else #define e4_XMLDLL #endif #endif /* * Implementation of base64 encode/decode exported by e4XML as a courtesy. */ typedef unsigned char byte; /* Byte (8 bit quantity) type. */ /* * The base64 encoder and decoder functions: */ #define LINELEN 72 /* Encoded line length (max 76). */ #define FILLER '=' /* Fill with this at end of input. */ static int initialized = 0; /* Is encoding table initialized? */ static byte etable[256]; /* Encode table. */ static byte dtable[256]; /* Decode table. */ /* * Functions declared in this file: */ static int base64_countchars(const char *base64str, int *slen); static const char * base64_getfour(const char *r, byte *a, byte *b); static void base64_initialize(); /* * base64_countchars -- * * Count the number of non-blank characters in the base64 encoded input. */ static int base64_countchars(const char *base64str, int *slen) { const char *r; int i, j; for (i = 0, j = 0, r = base64str; *r != 0; r++, j++) { if ((*r != ' ') && (*r != '\n') && (*r != '\r') && (*r != '\t')) { i++; } } if (slen != NULL) { *slen = j; } return i; } /* * base64_getfour -- * * Get four characters out of the input string, skipping whitespace. */ static const char * base64_getfour(const char *r, byte *a, byte *b) { int i; byte c; for (i = 0; i < 4; i++) { c = (byte) *r++; if (c == '\0') { return NULL; } if ((c == ' ') || (c == '\n') || (c == '\r') || (c == '\t')) { i--; continue; } a[i] = c; b[i] = (byte) dtable[c]; } return r; } /* * base64_initialize -- * * Ensure that the encode/decode tables are initialized. */ static void base64_initialize() { int i; if (!initialized) { initialized = 1; for (i = 0; i < 26; i++) { etable[i] = 'A' + i; etable[i + 26] = 'a' + i; } for (i = 0; i < 10; i++) { etable[i + 52] = '0' + i; } etable[62] = '+'; etable[63] = '/'; for (i = 0; i < 255; i++) { dtable[i] = 0x80; } for (i = 'A'; i <= 'Z'; i++) { dtable[i] = 0 + (i - 'A'); } for (i = 'a'; i <= 'z'; i++) { dtable[i] = 26 + (i - 'a'); } for (i = '0'; i <= '9'; i++) { dtable[i] = 52 + (i - '0'); } dtable['+'] = 62; dtable['/'] = 63; dtable['='] = 0; } } /* * base64_encode -- * * Encode a string of 8-bit bytes into a base64 encoded character string. */ e4_XMLDLL char * base64_encode(const byte *bytes, int len) { int groups = (len / 3) + (((len % 3) == 0) ? 0 : 1); /* Figure out how many 3-byte * groups there are in the input. */ int charlen = groups * 4; /* How many encoded characters? */ int nlines = charlen / LINELEN; /* How many lines in output? */ int totallen = nlines + charlen + 1;/* One more for NULL at end. */ int i, j, k, l, bytesingroup, charsonline; byte igroup[3]; char ogroup[4]; char *encoded; /* * Ensure the encode/decode table is initialized. */ base64_initialize(); /* * Allocate encoded data buffer. */ encoded = (char *) malloc((unsigned) totallen); /* * Now encode every 24 bits of input into 32 bits of encoded data. */ for (j = 0, k = 0, bytesingroup = 0, charsonline = 0, i = 0; i < groups; i++, bytesingroup = 0) { /* * Grab up to 3 input bytes. */ if (j < len) { igroup[0] = bytes[j++]; bytesingroup++; } else { igroup[0] = 0; } if (j < len) { igroup[1] = bytes[j++]; bytesingroup++; } else { igroup[1] = 0; } if (j < len) { igroup[2] = bytes[j++]; bytesingroup++; } else { igroup[2] = 0; } /* * Encode the 3 input bytes into 4 output bytes. */ ogroup[0] = etable[igroup[0] >> 2]; ogroup[1] = etable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)]; ogroup[2] = etable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)]; ogroup[3] = etable[igroup[2] & 0x3F]; if (bytesingroup < 3) { ogroup[3] = FILLER; if (bytesingroup < 2) { ogroup[2] = FILLER; } } /* * Copy the new 4 output characters to the string of output. */ for (l = 0; l < 4; l++, k++) { encoded[k] = ogroup[l]; charsonline++; if (charsonline == LINELEN) { encoded[++k] = '\n'; charsonline = 0; } } } encoded[k] = '\0'; return encoded; } /* * base64_decode -- * * Decode a base64 character string into a string of 8-bit bytes. */ e4_XMLDLL byte * base64_decode(const char *base64str, int *len) { const char *r; byte *p; byte a[4], b[4], o[3]; int slen, blen, j, k; int reallen, quads; byte *decoded; /* * Ensure the encode/decode tables are initialized. */ base64_initialize(); /* * Sanity check -- the number of real characters in the input string * must be a multiple of 4. If not, the input is not a base64 encoded * character string. */ reallen = base64_countchars(base64str, &slen); if ((reallen % 4) != 0) { return NULL; } /* * The length of the encoded string is ((reallen / 4) * 3) - number of * filler characters at end. */ quads = reallen / 4; blen = (quads * 3); if (base64str[slen - 1] == FILLER) { blen--; } if (base64str[slen - 2] == FILLER) { blen--; } /* * Allocate the buffer of 8-bit bytes. */ decoded = (byte *) malloc((unsigned int) blen); if (decoded == NULL) { return NULL; } /* * Loop over the input, decoding 4 characters at a time into 3 bytes. */ // for (p = decoded, r = base64str; *r != '\0'; ) { for (p = decoded, r = base64str; quads--; ) { /* * Get the next four input characters, skipping over white space. */ r = base64_getfour(r, a, b); if (r == NULL) { free(decoded); return NULL; } /* * Decode the next four input characters into three 8-bit bytes. */ o[0] = (b[0] << 2) | (b[1] >> 4); o[1] = (b[1] << 4) | (b[2] >> 2); o[2] = (b[2] << 6) | b[3]; /* * Determine how many valid 8-bit bytes were actually decoded. */ j = 3; if (a[3] == FILLER) { j--; } if (a[2] == FILLER) { j--; } /* * Copy the decoded bytes into the output buffer. */ for (k = 0; j > 0; k++, j--) { *p++ = o[k]; } } /* * Finally return the decoded bytes and if desired, the length of * the decoded bytes. */ if (len != NULL) { *len = blen; } return decoded; }