Return to base64.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / standard |
1.1 ! misho 1: /* ! 2: +----------------------------------------------------------------------+ ! 3: | PHP Version 5 | ! 4: +----------------------------------------------------------------------+ ! 5: | Copyright (c) 1997-2012 The PHP Group | ! 6: +----------------------------------------------------------------------+ ! 7: | This source file is subject to version 3.01 of the PHP license, | ! 8: | that is bundled with this package in the file LICENSE, and is | ! 9: | available through the world-wide-web at the following url: | ! 10: | http://www.php.net/license/3_01.txt | ! 11: | If you did not receive a copy of the PHP license and are unable to | ! 12: | obtain it through the world-wide-web, please send a note to | ! 13: | license@php.net so we can mail you a copy immediately. | ! 14: +----------------------------------------------------------------------+ ! 15: | Author: Jim Winstead <jimw@php.net> | ! 16: +----------------------------------------------------------------------+ ! 17: */ ! 18: /* $Id: base64.c 321634 2012-01-01 13:15:04Z felipe $ */ ! 19: ! 20: #include <string.h> ! 21: ! 22: #include "php.h" ! 23: #include "base64.h" ! 24: ! 25: /* {{{ base64 tables */ ! 26: static const char base64_table[] = { ! 27: 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', ! 28: 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ! 29: 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', ! 30: 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', ! 31: '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', '\0' ! 32: }; ! 33: ! 34: static const char base64_pad = '='; ! 35: ! 36: static const short base64_reverse_table[256] = { ! 37: -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -1, -2, -2, -1, -2, -2, ! 38: -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, ! 39: -1, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, 62, -2, -2, -2, 63, ! 40: 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -2, -2, -2, -2, -2, -2, ! 41: -2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, ! 42: 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -2, -2, -2, -2, -2, ! 43: -2, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, ! 44: 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -2, -2, -2, -2, -2, ! 45: -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, ! 46: -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, ! 47: -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, ! 48: -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, ! 49: -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, ! 50: -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, ! 51: -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, ! 52: -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2 ! 53: }; ! 54: /* }}} */ ! 55: ! 56: PHPAPI unsigned char *php_base64_encode(const unsigned char *str, int length, int *ret_length) /* {{{ */ ! 57: { ! 58: const unsigned char *current = str; ! 59: unsigned char *p; ! 60: unsigned char *result; ! 61: ! 62: if ((length + 2) < 0 || ((length + 2) / 3) >= (1 << (sizeof(int) * 8 - 2))) { ! 63: if (ret_length != NULL) { ! 64: *ret_length = 0; ! 65: } ! 66: return NULL; ! 67: } ! 68: ! 69: result = (unsigned char *)safe_emalloc(((length + 2) / 3) * 4, sizeof(char), 1); ! 70: p = result; ! 71: ! 72: while (length > 2) { /* keep going until we have less than 24 bits */ ! 73: *p++ = base64_table[current[0] >> 2]; ! 74: *p++ = base64_table[((current[0] & 0x03) << 4) + (current[1] >> 4)]; ! 75: *p++ = base64_table[((current[1] & 0x0f) << 2) + (current[2] >> 6)]; ! 76: *p++ = base64_table[current[2] & 0x3f]; ! 77: ! 78: current += 3; ! 79: length -= 3; /* we just handle 3 octets of data */ ! 80: } ! 81: ! 82: /* now deal with the tail end of things */ ! 83: if (length != 0) { ! 84: *p++ = base64_table[current[0] >> 2]; ! 85: if (length > 1) { ! 86: *p++ = base64_table[((current[0] & 0x03) << 4) + (current[1] >> 4)]; ! 87: *p++ = base64_table[(current[1] & 0x0f) << 2]; ! 88: *p++ = base64_pad; ! 89: } else { ! 90: *p++ = base64_table[(current[0] & 0x03) << 4]; ! 91: *p++ = base64_pad; ! 92: *p++ = base64_pad; ! 93: } ! 94: } ! 95: if (ret_length != NULL) { ! 96: *ret_length = (int)(p - result); ! 97: } ! 98: *p = '\0'; ! 99: return result; ! 100: } ! 101: /* }}} */ ! 102: ! 103: /* {{{ */ ! 104: /* generate reverse table (do not set index 0 to 64) ! 105: static unsigned short base64_reverse_table[256]; ! 106: #define rt base64_reverse_table ! 107: void php_base64_init(void) ! 108: { ! 109: char *s = emalloc(10240), *sp; ! 110: char *chp; ! 111: short idx; ! 112: ! 113: for(ch = 0; ch < 256; ch++) { ! 114: chp = strchr(base64_table, ch); ! 115: if(ch && chp) { ! 116: idx = chp - base64_table; ! 117: if (idx >= 64) idx = -1; ! 118: rt[ch] = idx; ! 119: } else { ! 120: rt[ch] = -1; ! 121: } ! 122: } ! 123: sp = s; ! 124: sprintf(sp, "static const short base64_reverse_table[256] = {\n"); ! 125: for(ch =0; ch < 256;) { ! 126: sp = s+strlen(s); ! 127: 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]); ! 128: ch += 16; ! 129: } ! 130: sprintf(sp, "};"); ! 131: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Reverse_table:\n%s", s); ! 132: efree(s); ! 133: } ! 134: */ ! 135: /* }}} */ ! 136: ! 137: PHPAPI unsigned char *php_base64_decode(const unsigned char *str, int length, int *ret_length) /* {{{ */ ! 138: { ! 139: return php_base64_decode_ex(str, length, ret_length, 0); ! 140: } ! 141: /* }}} */ ! 142: ! 143: PHPAPI unsigned char *php_base64_decode_ex(const unsigned char *str, int length, int *ret_length, zend_bool strict) /* {{{ */ ! 144: { ! 145: const unsigned char *current = str; ! 146: int ch, i = 0, j = 0, k; ! 147: /* this sucks for threaded environments */ ! 148: unsigned char *result; ! 149: ! 150: result = (unsigned char *)safe_emalloc(length, 1, 1); ! 151: ! 152: /* run through the whole string, converting as we go */ ! 153: while ((ch = *current++) != '\0' && length-- > 0) { ! 154: if (ch == base64_pad) { ! 155: if (*current != '=' && ((i % 4) == 1 || (strict && length > 0))) { ! 156: if ((i % 4) != 1) { ! 157: while (isspace(*(++current))) { ! 158: continue; ! 159: } ! 160: if (*current == '\0') { ! 161: continue; ! 162: } ! 163: } ! 164: efree(result); ! 165: return NULL; ! 166: } ! 167: continue; ! 168: } ! 169: ! 170: ch = base64_reverse_table[ch]; ! 171: if ((!strict && ch < 0) || ch == -1) { /* a space or some other separator character, we simply skip over */ ! 172: continue; ! 173: } else if (ch == -2) { ! 174: efree(result); ! 175: return NULL; ! 176: } ! 177: ! 178: switch(i % 4) { ! 179: case 0: ! 180: result[j] = ch << 2; ! 181: break; ! 182: case 1: ! 183: result[j++] |= ch >> 4; ! 184: result[j] = (ch & 0x0f) << 4; ! 185: break; ! 186: case 2: ! 187: result[j++] |= ch >>2; ! 188: result[j] = (ch & 0x03) << 6; ! 189: break; ! 190: case 3: ! 191: result[j++] |= ch; ! 192: break; ! 193: } ! 194: i++; ! 195: } ! 196: ! 197: k = j; ! 198: /* mop things up if we ended on a boundary */ ! 199: if (ch == base64_pad) { ! 200: switch(i % 4) { ! 201: case 1: ! 202: efree(result); ! 203: return NULL; ! 204: case 2: ! 205: k++; ! 206: case 3: ! 207: result[k] = 0; ! 208: } ! 209: } ! 210: if(ret_length) { ! 211: *ret_length = j; ! 212: } ! 213: result[j] = '\0'; ! 214: return result; ! 215: } ! 216: /* }}} */ ! 217: ! 218: /* {{{ proto string base64_encode(string str) ! 219: Encodes string using MIME base64 algorithm */ ! 220: PHP_FUNCTION(base64_encode) ! 221: { ! 222: char *str; ! 223: unsigned char *result; ! 224: int str_len, ret_length; ! 225: ! 226: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) { ! 227: return; ! 228: } ! 229: result = php_base64_encode((unsigned char*)str, str_len, &ret_length); ! 230: if (result != NULL) { ! 231: RETVAL_STRINGL((char*)result, ret_length, 0); ! 232: } else { ! 233: RETURN_FALSE; ! 234: } ! 235: } ! 236: /* }}} */ ! 237: ! 238: /* {{{ proto string base64_decode(string str[, bool strict]) ! 239: Decodes string using MIME base64 algorithm */ ! 240: PHP_FUNCTION(base64_decode) ! 241: { ! 242: char *str; ! 243: unsigned char *result; ! 244: zend_bool strict = 0; ! 245: int str_len, ret_length; ! 246: ! 247: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &str, &str_len, &strict) == FAILURE) { ! 248: return; ! 249: } ! 250: result = php_base64_decode_ex((unsigned char*)str, str_len, &ret_length, strict); ! 251: if (result != NULL) { ! 252: RETVAL_STRINGL((char*)result, ret_length, 0); ! 253: } else { ! 254: RETURN_FALSE; ! 255: } ! 256: } ! 257: /* }}} */ ! 258: ! 259: /* ! 260: * Local variables: ! 261: * tab-width: 4 ! 262: * c-basic-offset: 4 ! 263: * End: ! 264: * vim600: sw=4 ts=4 fdm=marker ! 265: * vim<600: sw=4 ts=4 ! 266: */