Back to index

php5  5.3.10
base64.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Author: Jim Winstead <jimw@php.net>                                  |
00016    +----------------------------------------------------------------------+
00017  */
00018 /* $Id: base64.c 321634 2012-01-01 13:15:04Z felipe $ */
00019 
00020 #include <string.h>
00021 
00022 #include "php.h"
00023 #include "base64.h"
00024 
00025 /* {{{ base64 tables */
00026 static const char base64_table[] = {
00027        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
00028        'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
00029        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
00030        'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
00031        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', '\0'
00032 };
00033 
00034 static const char base64_pad = '=';
00035 
00036 static const short base64_reverse_table[256] = {
00037        -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -1, -2, -2, -1, -2, -2,
00038        -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
00039        -1, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, 62, -2, -2, -2, 63,
00040        52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -2, -2, -2, -2, -2, -2,
00041        -2,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
00042        15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -2, -2, -2, -2, -2,
00043        -2, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
00044        41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -2, -2, -2, -2, -2,
00045        -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
00046        -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
00047        -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
00048        -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
00049        -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
00050        -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
00051        -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
00052        -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2
00053 };
00054 /* }}} */
00055 
00056 PHPAPI unsigned char *php_base64_encode(const unsigned char *str, int length, int *ret_length) /* {{{ */
00057 {
00058        const unsigned char *current = str;
00059        unsigned char *p;
00060        unsigned char *result;
00061 
00062        if ((length + 2) < 0 || ((length + 2) / 3) >= (1 << (sizeof(int) * 8 - 2))) {
00063               if (ret_length != NULL) {
00064                      *ret_length = 0;
00065               }
00066               return NULL;
00067        }
00068 
00069        result = (unsigned char *)safe_emalloc(((length + 2) / 3) * 4, sizeof(char), 1);
00070        p = result;
00071 
00072        while (length > 2) { /* keep going until we have less than 24 bits */
00073               *p++ = base64_table[current[0] >> 2];
00074               *p++ = base64_table[((current[0] & 0x03) << 4) + (current[1] >> 4)];
00075               *p++ = base64_table[((current[1] & 0x0f) << 2) + (current[2] >> 6)];
00076               *p++ = base64_table[current[2] & 0x3f];
00077 
00078               current += 3;
00079               length -= 3; /* we just handle 3 octets of data */
00080        }
00081 
00082        /* now deal with the tail end of things */
00083        if (length != 0) {
00084               *p++ = base64_table[current[0] >> 2];
00085               if (length > 1) {
00086                      *p++ = base64_table[((current[0] & 0x03) << 4) + (current[1] >> 4)];
00087                      *p++ = base64_table[(current[1] & 0x0f) << 2];
00088                      *p++ = base64_pad;
00089               } else {
00090                      *p++ = base64_table[(current[0] & 0x03) << 4];
00091                      *p++ = base64_pad;
00092                      *p++ = base64_pad;
00093               }
00094        }
00095        if (ret_length != NULL) {
00096               *ret_length = (int)(p - result);
00097        }
00098        *p = '\0';
00099        return result;
00100 }
00101 /* }}} */
00102 
00103 /* {{{ */
00104 /* generate reverse table (do not set index 0 to 64)
00105 static unsigned short base64_reverse_table[256];
00106 #define rt base64_reverse_table
00107 void php_base64_init(void)
00108 {
00109        char *s = emalloc(10240), *sp;
00110        char *chp;
00111        short idx;
00112 
00113        for(ch = 0; ch < 256; ch++) {
00114               chp = strchr(base64_table, ch);
00115               if(ch && chp) {
00116                      idx = chp - base64_table;
00117                      if (idx >= 64) idx = -1;
00118                      rt[ch] = idx;
00119               } else {
00120                      rt[ch] = -1;
00121               }
00122        }
00123        sp = s;
00124        sprintf(sp, "static const short base64_reverse_table[256] = {\n");
00125        for(ch =0; ch < 256;) {
00126               sp = s+strlen(s);
00127               sprintf(sp, "\t% 3d,% 3d,% 3d,% 3d,% 3d,% 3d,% 3d,% 3d,% 3d,% 3d,% 3d,% 3d,% 3d,% 3d,% 3d,% 3d,\n", rt[ch+0], rt[ch+1], rt[ch+2], rt[ch+3], rt[ch+4], rt[ch+5], rt[ch+6], rt[ch+7], rt[ch+8], rt[ch+9], rt[ch+10], rt[ch+11], rt[ch+12], rt[ch+13], rt[ch+14], rt[ch+15]);
00128               ch += 16;
00129        }
00130        sprintf(sp, "};");
00131        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Reverse_table:\n%s", s);
00132        efree(s);
00133 }
00134 */
00135 /* }}} */
00136 
00137 PHPAPI unsigned char *php_base64_decode(const unsigned char *str, int length, int *ret_length) /* {{{ */
00138 {
00139        return php_base64_decode_ex(str, length, ret_length, 0);
00140 }
00141 /* }}} */
00142 
00143 PHPAPI unsigned char *php_base64_decode_ex(const unsigned char *str, int length, int *ret_length, zend_bool strict) /* {{{ */
00144 {
00145        const unsigned char *current = str;
00146        int ch, i = 0, j = 0, k;
00147        /* this sucks for threaded environments */
00148        unsigned char *result;
00149 
00150        result = (unsigned char *)safe_emalloc(length, 1, 1);
00151 
00152        /* run through the whole string, converting as we go */
00153        while ((ch = *current++) != '\0' && length-- > 0) {
00154               if (ch == base64_pad) {
00155                      if (*current != '=' && ((i % 4) == 1 || (strict && length > 0))) {
00156                             if ((i % 4) != 1) {
00157                                    while (isspace(*(++current))) {
00158                                           continue;
00159                                    }
00160                                    if (*current == '\0') {
00161                                           continue;
00162                                    }
00163                             }
00164                             efree(result);
00165                             return NULL;
00166                      }
00167                      continue;
00168               }
00169 
00170               ch = base64_reverse_table[ch];
00171               if ((!strict && ch < 0) || ch == -1) { /* a space or some other separator character, we simply skip over */
00172                      continue;
00173               } else if (ch == -2) {
00174                      efree(result);
00175                      return NULL;
00176               }
00177 
00178               switch(i % 4) {
00179               case 0:
00180                      result[j] = ch << 2;
00181                      break;
00182               case 1:
00183                      result[j++] |= ch >> 4;
00184                      result[j] = (ch & 0x0f) << 4;
00185                      break;
00186               case 2:
00187                      result[j++] |= ch >>2;
00188                      result[j] = (ch & 0x03) << 6;
00189                      break;
00190               case 3:
00191                      result[j++] |= ch;
00192                      break;
00193               }
00194               i++;
00195        }
00196 
00197        k = j;
00198        /* mop things up if we ended on a boundary */
00199        if (ch == base64_pad) {
00200               switch(i % 4) {
00201               case 1:
00202                      efree(result);
00203                      return NULL;
00204               case 2:
00205                      k++;
00206               case 3:
00207                      result[k] = 0;
00208               }
00209        }
00210        if(ret_length) {
00211               *ret_length = j;
00212        }
00213        result[j] = '\0';
00214        return result;
00215 }
00216 /* }}} */
00217 
00218 /* {{{ proto string base64_encode(string str)
00219    Encodes string using MIME base64 algorithm */
00220 PHP_FUNCTION(base64_encode)
00221 {
00222        char *str;
00223        unsigned char *result;
00224        int str_len, ret_length;
00225 
00226        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
00227               return;
00228        }
00229        result = php_base64_encode((unsigned char*)str, str_len, &ret_length);
00230        if (result != NULL) {
00231               RETVAL_STRINGL((char*)result, ret_length, 0);
00232        } else {
00233               RETURN_FALSE;
00234        }
00235 }
00236 /* }}} */
00237 
00238 /* {{{ proto string base64_decode(string str[, bool strict])
00239    Decodes string using MIME base64 algorithm */
00240 PHP_FUNCTION(base64_decode)
00241 {
00242        char *str;
00243        unsigned char *result;
00244        zend_bool strict = 0;
00245        int str_len, ret_length;
00246 
00247        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &str, &str_len, &strict) == FAILURE) {
00248               return;
00249        }
00250        result = php_base64_decode_ex((unsigned char*)str, str_len, &ret_length, strict);
00251        if (result != NULL) {
00252               RETVAL_STRINGL((char*)result, ret_length, 0);
00253        } else {
00254               RETURN_FALSE;
00255        }
00256 }
00257 /* }}} */
00258 
00259 /*
00260  * Local variables:
00261  * tab-width: 4
00262  * c-basic-offset: 4
00263  * End:
00264  * vim600: sw=4 ts=4 fdm=marker
00265  * vim<600: sw=4 ts=4
00266  */