Return to iconv.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / iconv |
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: | Authors: Rui Hirokawa <rui_hirokawa@ybb.ne.jp> | ! 16: | Stig Bakken <ssb@php.net> | ! 17: | Moriyoshi Koizumi <moriyoshi@php.net> | ! 18: +----------------------------------------------------------------------+ ! 19: */ ! 20: ! 21: /* $Id: iconv.c 321634 2012-01-01 13:15:04Z felipe $ */ ! 22: ! 23: #ifdef HAVE_CONFIG_H ! 24: #include "config.h" ! 25: #endif ! 26: ! 27: #include "php.h" ! 28: #include "php_globals.h" ! 29: #include "ext/standard/info.h" ! 30: #include "main/php_output.h" ! 31: #include "SAPI.h" ! 32: #include "php_ini.h" ! 33: ! 34: #ifdef HAVE_STDLIB_H ! 35: # include <stdlib.h> ! 36: #endif ! 37: ! 38: #include <errno.h> ! 39: ! 40: #include "php_iconv.h" ! 41: ! 42: #ifdef HAVE_ICONV ! 43: ! 44: #ifdef PHP_ICONV_H_PATH ! 45: #include PHP_ICONV_H_PATH ! 46: #else ! 47: #include <iconv.h> ! 48: #endif ! 49: ! 50: #ifdef HAVE_GLIBC_ICONV ! 51: #include <gnu/libc-version.h> ! 52: #endif ! 53: ! 54: #ifdef HAVE_LIBICONV ! 55: #undef iconv ! 56: #endif ! 57: ! 58: #include "ext/standard/php_smart_str.h" ! 59: #include "ext/standard/base64.h" ! 60: #include "ext/standard/quot_print.h" ! 61: ! 62: #define _php_iconv_memequal(a, b, c) \ ! 63: ((c) == sizeof(unsigned long) ? *((unsigned long *)(a)) == *((unsigned long *)(b)) : ((c) == sizeof(unsigned int) ? *((unsigned int *)(a)) == *((unsigned int *)(b)) : memcmp(a, b, c) == 0)) ! 64: ! 65: /* {{{ arginfo */ ! 66: ZEND_BEGIN_ARG_INFO_EX(arginfo_iconv_strlen, 0, 0, 1) ! 67: ZEND_ARG_INFO(0, str) ! 68: ZEND_ARG_INFO(0, charset) ! 69: ZEND_END_ARG_INFO() ! 70: ! 71: ZEND_BEGIN_ARG_INFO_EX(arginfo_iconv_substr, 0, 0, 2) ! 72: ZEND_ARG_INFO(0, str) ! 73: ZEND_ARG_INFO(0, offset) ! 74: ZEND_ARG_INFO(0, length) ! 75: ZEND_ARG_INFO(0, charset) ! 76: ZEND_END_ARG_INFO() ! 77: ! 78: ZEND_BEGIN_ARG_INFO_EX(arginfo_iconv_strpos, 0, 0, 2) ! 79: ZEND_ARG_INFO(0, haystack) ! 80: ZEND_ARG_INFO(0, needle) ! 81: ZEND_ARG_INFO(0, offset) ! 82: ZEND_ARG_INFO(0, charset) ! 83: ZEND_END_ARG_INFO() ! 84: ! 85: ZEND_BEGIN_ARG_INFO_EX(arginfo_iconv_strrpos, 0, 0, 2) ! 86: ZEND_ARG_INFO(0, haystack) ! 87: ZEND_ARG_INFO(0, needle) ! 88: ZEND_ARG_INFO(0, charset) ! 89: ZEND_END_ARG_INFO() ! 90: ! 91: ZEND_BEGIN_ARG_INFO_EX(arginfo_iconv_mime_encode, 0, 0, 2) ! 92: ZEND_ARG_INFO(0, field_name) ! 93: ZEND_ARG_INFO(0, field_value) ! 94: ZEND_ARG_INFO(0, preference) /* ZEND_ARG_ARRAY_INFO(0, preference, 1) */ ! 95: ZEND_END_ARG_INFO() ! 96: ! 97: ZEND_BEGIN_ARG_INFO_EX(arginfo_iconv_mime_decode, 0, 0, 1) ! 98: ZEND_ARG_INFO(0, encoded_string) ! 99: ZEND_ARG_INFO(0, mode) ! 100: ZEND_ARG_INFO(0, charset) ! 101: ZEND_END_ARG_INFO() ! 102: ! 103: ZEND_BEGIN_ARG_INFO_EX(arginfo_iconv_mime_decode_headers, 0, 0, 1) ! 104: ZEND_ARG_INFO(0, headers) ! 105: ZEND_ARG_INFO(0, mode) ! 106: ZEND_ARG_INFO(0, charset) ! 107: ZEND_END_ARG_INFO() ! 108: ! 109: ZEND_BEGIN_ARG_INFO(arginfo_iconv, 0) ! 110: ZEND_ARG_INFO(0, in_charset) ! 111: ZEND_ARG_INFO(0, out_charset) ! 112: ZEND_ARG_INFO(0, str) ! 113: ZEND_END_ARG_INFO() ! 114: ! 115: ZEND_BEGIN_ARG_INFO(arginfo_ob_iconv_handler, 0) ! 116: ZEND_ARG_INFO(0, contents) ! 117: ZEND_ARG_INFO(0, status) ! 118: ZEND_END_ARG_INFO() ! 119: ! 120: ZEND_BEGIN_ARG_INFO(arginfo_iconv_set_encoding, 0) ! 121: ZEND_ARG_INFO(0, type) ! 122: ZEND_ARG_INFO(0, charset) ! 123: ZEND_END_ARG_INFO() ! 124: ! 125: ZEND_BEGIN_ARG_INFO_EX(arginfo_iconv_get_encoding, 0, 0, 0) ! 126: ZEND_ARG_INFO(0, type) ! 127: ZEND_END_ARG_INFO() ! 128: ! 129: /* }}} */ ! 130: ! 131: /* {{{ iconv_functions[] ! 132: */ ! 133: const zend_function_entry iconv_functions[] = { ! 134: PHP_RAW_NAMED_FE(iconv,php_if_iconv, arginfo_iconv) ! 135: PHP_FE(ob_iconv_handler, arginfo_ob_iconv_handler) ! 136: PHP_FE(iconv_get_encoding, arginfo_iconv_get_encoding) ! 137: PHP_FE(iconv_set_encoding, arginfo_iconv_set_encoding) ! 138: PHP_FE(iconv_strlen, arginfo_iconv_strlen) ! 139: PHP_FE(iconv_substr, arginfo_iconv_substr) ! 140: PHP_FE(iconv_strpos, arginfo_iconv_strpos) ! 141: PHP_FE(iconv_strrpos, arginfo_iconv_strrpos) ! 142: PHP_FE(iconv_mime_encode, arginfo_iconv_mime_encode) ! 143: PHP_FE(iconv_mime_decode, arginfo_iconv_mime_decode) ! 144: PHP_FE(iconv_mime_decode_headers, arginfo_iconv_mime_decode_headers) ! 145: PHP_FE_END ! 146: }; ! 147: /* }}} */ ! 148: ! 149: ZEND_DECLARE_MODULE_GLOBALS(iconv) ! 150: static PHP_GINIT_FUNCTION(iconv); ! 151: ! 152: /* {{{ iconv_module_entry ! 153: */ ! 154: zend_module_entry iconv_module_entry = { ! 155: STANDARD_MODULE_HEADER, ! 156: "iconv", ! 157: iconv_functions, ! 158: PHP_MINIT(miconv), ! 159: PHP_MSHUTDOWN(miconv), ! 160: NULL, ! 161: NULL, ! 162: PHP_MINFO(miconv), ! 163: NO_VERSION_YET, ! 164: PHP_MODULE_GLOBALS(iconv), ! 165: PHP_GINIT(iconv), ! 166: NULL, ! 167: NULL, ! 168: STANDARD_MODULE_PROPERTIES_EX ! 169: }; ! 170: /* }}} */ ! 171: ! 172: #ifdef COMPILE_DL_ICONV ! 173: ZEND_GET_MODULE(iconv) ! 174: #endif ! 175: ! 176: /* {{{ PHP_GINIT_FUNCTION */ ! 177: static PHP_GINIT_FUNCTION(iconv) ! 178: { ! 179: iconv_globals->input_encoding = NULL; ! 180: iconv_globals->output_encoding = NULL; ! 181: iconv_globals->internal_encoding = NULL; ! 182: } ! 183: /* }}} */ ! 184: ! 185: #if defined(HAVE_LIBICONV) && defined(ICONV_ALIASED_LIBICONV) ! 186: #define iconv libiconv ! 187: #endif ! 188: ! 189: /* {{{ typedef enum php_iconv_enc_scheme_t */ ! 190: typedef enum _php_iconv_enc_scheme_t { ! 191: PHP_ICONV_ENC_SCHEME_BASE64, ! 192: PHP_ICONV_ENC_SCHEME_QPRINT ! 193: } php_iconv_enc_scheme_t; ! 194: /* }}} */ ! 195: ! 196: #define PHP_ICONV_MIME_DECODE_STRICT (1<<0) ! 197: #define PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR (1<<1) ! 198: ! 199: /* {{{ prototypes */ ! 200: static php_iconv_err_t _php_iconv_appendl(smart_str *d, const char *s, size_t l, iconv_t cd); ! 201: static php_iconv_err_t _php_iconv_appendc(smart_str *d, const char c, iconv_t cd); ! 202: ! 203: static void _php_iconv_show_error(php_iconv_err_t err, const char *out_charset, const char *in_charset TSRMLS_DC); ! 204: ! 205: static php_iconv_err_t _php_iconv_strlen(unsigned int *pretval, const char *str, size_t nbytes, const char *enc); ! 206: ! 207: static php_iconv_err_t _php_iconv_substr(smart_str *pretval, const char *str, size_t nbytes, int offset, int len, const char *enc); ! 208: ! 209: static php_iconv_err_t _php_iconv_strpos(unsigned int *pretval, const char *haystk, size_t haystk_nbytes, const char *ndl, size_t ndl_nbytes, int offset, const char *enc); ! 210: ! 211: static php_iconv_err_t _php_iconv_mime_encode(smart_str *pretval, const char *fname, size_t fname_nbytes, const char *fval, size_t fval_nbytes, unsigned int max_line_len, const char *lfchars, php_iconv_enc_scheme_t enc_scheme, const char *out_charset, const char *enc); ! 212: ! 213: static php_iconv_err_t _php_iconv_mime_decode(smart_str *pretval, const char *str, size_t str_nbytes, const char *enc, const char **next_pos, int mode); ! 214: ! 215: static php_iconv_err_t php_iconv_stream_filter_register_factory(TSRMLS_D); ! 216: static php_iconv_err_t php_iconv_stream_filter_unregister_factory(TSRMLS_D); ! 217: /* }}} */ ! 218: ! 219: /* {{{ static globals */ ! 220: static char _generic_superset_name[] = ICONV_UCS4_ENCODING; ! 221: #define GENERIC_SUPERSET_NAME _generic_superset_name ! 222: #define GENERIC_SUPERSET_NBYTES 4 ! 223: /* }}} */ ! 224: ! 225: static PHP_INI_MH(OnUpdateStringIconvCharset) ! 226: { ! 227: if(new_value_length >= ICONV_CSNMAXLEN) { ! 228: return FAILURE; ! 229: } ! 230: OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC); ! 231: return SUCCESS; ! 232: } ! 233: ! 234: /* {{{ PHP_INI ! 235: */ ! 236: PHP_INI_BEGIN() ! 237: STD_PHP_INI_ENTRY("iconv.input_encoding", ICONV_INPUT_ENCODING, PHP_INI_ALL, OnUpdateStringIconvCharset, input_encoding, zend_iconv_globals, iconv_globals) ! 238: STD_PHP_INI_ENTRY("iconv.output_encoding", ICONV_OUTPUT_ENCODING, PHP_INI_ALL, OnUpdateStringIconvCharset, output_encoding, zend_iconv_globals, iconv_globals) ! 239: STD_PHP_INI_ENTRY("iconv.internal_encoding", ICONV_INTERNAL_ENCODING, PHP_INI_ALL, OnUpdateStringIconvCharset, internal_encoding, zend_iconv_globals, iconv_globals) ! 240: PHP_INI_END() ! 241: /* }}} */ ! 242: ! 243: /* {{{ PHP_MINIT_FUNCTION */ ! 244: PHP_MINIT_FUNCTION(miconv) ! 245: { ! 246: char *version = "unknown"; ! 247: ! 248: REGISTER_INI_ENTRIES(); ! 249: ! 250: #if HAVE_LIBICONV ! 251: { ! 252: static char buf[16]; ! 253: snprintf(buf, sizeof(buf), "%d.%d", ! 254: ((_libiconv_version >> 8) & 0x0f), (_libiconv_version & 0x0f)); ! 255: version = buf; ! 256: } ! 257: #elif HAVE_GLIBC_ICONV ! 258: version = (char *)gnu_get_libc_version(); ! 259: #elif defined(NETWARE) ! 260: version = "OS built-in"; ! 261: #endif ! 262: ! 263: #ifdef PHP_ICONV_IMPL ! 264: REGISTER_STRING_CONSTANT("ICONV_IMPL", PHP_ICONV_IMPL, CONST_CS | CONST_PERSISTENT); ! 265: #elif HAVE_LIBICONV ! 266: REGISTER_STRING_CONSTANT("ICONV_IMPL", "libiconv", CONST_CS | CONST_PERSISTENT); ! 267: #elif defined(NETWARE) ! 268: REGISTER_STRING_CONSTANT("ICONV_IMPL", "Novell", CONST_CS | CONST_PERSISTENT); ! 269: #else ! 270: REGISTER_STRING_CONSTANT("ICONV_IMPL", "unknown", CONST_CS | CONST_PERSISTENT); ! 271: #endif ! 272: REGISTER_STRING_CONSTANT("ICONV_VERSION", version, CONST_CS | CONST_PERSISTENT); ! 273: ! 274: REGISTER_LONG_CONSTANT("ICONV_MIME_DECODE_STRICT", PHP_ICONV_MIME_DECODE_STRICT, CONST_CS | CONST_PERSISTENT); ! 275: REGISTER_LONG_CONSTANT("ICONV_MIME_DECODE_CONTINUE_ON_ERROR", PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR, CONST_CS | CONST_PERSISTENT); ! 276: ! 277: if (php_iconv_stream_filter_register_factory(TSRMLS_C) != PHP_ICONV_ERR_SUCCESS) { ! 278: return FAILURE; ! 279: } ! 280: ! 281: return SUCCESS; ! 282: } ! 283: /* }}} */ ! 284: ! 285: /* {{{ PHP_MSHUTDOWN_FUNCTION */ ! 286: PHP_MSHUTDOWN_FUNCTION(miconv) ! 287: { ! 288: php_iconv_stream_filter_unregister_factory(TSRMLS_C); ! 289: UNREGISTER_INI_ENTRIES(); ! 290: return SUCCESS; ! 291: } ! 292: /* }}} */ ! 293: ! 294: /* {{{ PHP_MINFO_FUNCTION */ ! 295: PHP_MINFO_FUNCTION(miconv) ! 296: { ! 297: zval iconv_impl, iconv_ver; ! 298: ! 299: zend_get_constant("ICONV_IMPL", sizeof("ICONV_IMPL")-1, &iconv_impl TSRMLS_CC); ! 300: zend_get_constant("ICONV_VERSION", sizeof("ICONV_VERSION")-1, &iconv_ver TSRMLS_CC); ! 301: ! 302: php_info_print_table_start(); ! 303: php_info_print_table_row(2, "iconv support", "enabled"); ! 304: php_info_print_table_row(2, "iconv implementation", Z_STRVAL(iconv_impl)); ! 305: php_info_print_table_row(2, "iconv library version", Z_STRVAL(iconv_ver)); ! 306: php_info_print_table_end(); ! 307: ! 308: DISPLAY_INI_ENTRIES(); ! 309: ! 310: zval_dtor(&iconv_impl); ! 311: zval_dtor(&iconv_ver); ! 312: } ! 313: /* }}} */ ! 314: ! 315: /* {{{ _php_iconv_appendl() */ ! 316: static php_iconv_err_t _php_iconv_appendl(smart_str *d, const char *s, size_t l, iconv_t cd) ! 317: { ! 318: const char *in_p = s; ! 319: size_t in_left = l; ! 320: char *out_p; ! 321: size_t out_left = 0; ! 322: size_t buf_growth = 128; ! 323: #if !ICONV_SUPPORTS_ERRNO ! 324: size_t prev_in_left = in_left; ! 325: #endif ! 326: ! 327: if (in_p != NULL) { ! 328: while (in_left > 0) { ! 329: out_left = buf_growth - out_left; ! 330: { ! 331: size_t newlen; ! 332: smart_str_alloc((d), out_left, 0); ! 333: } ! 334: ! 335: out_p = (d)->c + (d)->len; ! 336: ! 337: if (iconv(cd, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) { ! 338: #if ICONV_SUPPORTS_ERRNO ! 339: switch (errno) { ! 340: case EINVAL: ! 341: return PHP_ICONV_ERR_ILLEGAL_CHAR; ! 342: ! 343: case EILSEQ: ! 344: return PHP_ICONV_ERR_ILLEGAL_SEQ; ! 345: ! 346: case E2BIG: ! 347: break; ! 348: ! 349: default: ! 350: return PHP_ICONV_ERR_UNKNOWN; ! 351: } ! 352: #else ! 353: if (prev_in_left == in_left) { ! 354: return PHP_ICONV_ERR_UNKNOWN; ! 355: } ! 356: #endif ! 357: } ! 358: #if !ICONV_SUPPORTS_ERRNO ! 359: prev_in_left = in_left; ! 360: #endif ! 361: (d)->len += (buf_growth - out_left); ! 362: buf_growth <<= 1; ! 363: } ! 364: } else { ! 365: for (;;) { ! 366: out_left = buf_growth - out_left; ! 367: { ! 368: size_t newlen; ! 369: smart_str_alloc((d), out_left, 0); ! 370: } ! 371: ! 372: out_p = (d)->c + (d)->len; ! 373: ! 374: if (iconv(cd, NULL, NULL, (char **) &out_p, &out_left) == (size_t)0) { ! 375: (d)->len += (buf_growth - out_left); ! 376: break; ! 377: } else { ! 378: #if ICONV_SUPPORTS_ERRNO ! 379: if (errno != E2BIG) { ! 380: return PHP_ICONV_ERR_UNKNOWN; ! 381: } ! 382: #else ! 383: if (out_left != 0) { ! 384: return PHP_ICONV_ERR_UNKNOWN; ! 385: } ! 386: #endif ! 387: } ! 388: (d)->len += (buf_growth - out_left); ! 389: buf_growth <<= 1; ! 390: } ! 391: } ! 392: return PHP_ICONV_ERR_SUCCESS; ! 393: } ! 394: /* }}} */ ! 395: ! 396: /* {{{ _php_iconv_appendc() */ ! 397: static php_iconv_err_t _php_iconv_appendc(smart_str *d, const char c, iconv_t cd) ! 398: { ! 399: return _php_iconv_appendl(d, &c, 1, cd); ! 400: } ! 401: /* }}} */ ! 402: ! 403: /* {{{ php_iconv_string() ! 404: */ ! 405: PHP_ICONV_API php_iconv_err_t php_iconv_string(const char *in_p, size_t in_len, ! 406: char **out, size_t *out_len, ! 407: const char *out_charset, const char *in_charset) ! 408: { ! 409: #if !ICONV_SUPPORTS_ERRNO ! 410: size_t in_size, out_size, out_left; ! 411: char *out_buffer, *out_p; ! 412: iconv_t cd; ! 413: size_t result; ! 414: ! 415: *out = NULL; ! 416: *out_len = 0; ! 417: ! 418: /* ! 419: This is not the right way to get output size... ! 420: This is not space efficient for large text. ! 421: This is also problem for encoding like UTF-7/UTF-8/ISO-2022 which ! 422: a single char can be more than 4 bytes. ! 423: I added 15 extra bytes for safety. <yohgaki@php.net> ! 424: */ ! 425: out_size = in_len * sizeof(int) + 15; ! 426: out_left = out_size; ! 427: ! 428: in_size = in_len; ! 429: ! 430: cd = iconv_open(out_charset, in_charset); ! 431: ! 432: if (cd == (iconv_t)(-1)) { ! 433: return PHP_ICONV_ERR_UNKNOWN; ! 434: } ! 435: ! 436: out_buffer = (char *) emalloc(out_size + 1); ! 437: out_p = out_buffer; ! 438: ! 439: #ifdef NETWARE ! 440: result = iconv(cd, (char **) &in_p, &in_size, (char **) ! 441: #else ! 442: result = iconv(cd, (const char **) &in_p, &in_size, (char **) ! 443: #endif ! 444: &out_p, &out_left); ! 445: ! 446: if (result == (size_t)(-1)) { ! 447: efree(out_buffer); ! 448: return PHP_ICONV_ERR_UNKNOWN; ! 449: } ! 450: ! 451: if (out_left < 8) { ! 452: out_buffer = (char *) erealloc(out_buffer, out_size + 8); ! 453: } ! 454: ! 455: /* flush the shift-out sequences */ ! 456: result = iconv(cd, NULL, NULL, &out_p, &out_left); ! 457: ! 458: if (result == (size_t)(-1)) { ! 459: efree(out_buffer); ! 460: return PHP_ICONV_ERR_UNKNOWN; ! 461: } ! 462: ! 463: *out_len = out_size - out_left; ! 464: out_buffer[*out_len] = '\0'; ! 465: *out = out_buffer; ! 466: ! 467: iconv_close(cd); ! 468: ! 469: return PHP_ICONV_ERR_SUCCESS; ! 470: ! 471: #else ! 472: /* ! 473: iconv supports errno. Handle it better way. ! 474: */ ! 475: iconv_t cd; ! 476: size_t in_left, out_size, out_left; ! 477: char *out_p, *out_buf, *tmp_buf; ! 478: size_t bsz, result = 0; ! 479: php_iconv_err_t retval = PHP_ICONV_ERR_SUCCESS; ! 480: ! 481: *out = NULL; ! 482: *out_len = 0; ! 483: ! 484: cd = iconv_open(out_charset, in_charset); ! 485: ! 486: if (cd == (iconv_t)(-1)) { ! 487: if (errno == EINVAL) { ! 488: return PHP_ICONV_ERR_WRONG_CHARSET; ! 489: } else { ! 490: return PHP_ICONV_ERR_CONVERTER; ! 491: } ! 492: } ! 493: in_left= in_len; ! 494: out_left = in_len + 32; /* Avoid realloc() most cases */ ! 495: out_size = 0; ! 496: bsz = out_left; ! 497: out_buf = (char *) emalloc(bsz+1); ! 498: out_p = out_buf; ! 499: ! 500: while (in_left > 0) { ! 501: result = iconv(cd, (char **) &in_p, &in_left, (char **) &out_p, &out_left); ! 502: out_size = bsz - out_left; ! 503: if (result == (size_t)(-1)) { ! 504: if (errno == E2BIG && in_left > 0) { ! 505: /* converted string is longer than out buffer */ ! 506: bsz += in_len; ! 507: ! 508: tmp_buf = (char*) erealloc(out_buf, bsz+1); ! 509: out_p = out_buf = tmp_buf; ! 510: out_p += out_size; ! 511: out_left = bsz - out_size; ! 512: continue; ! 513: } ! 514: } ! 515: break; ! 516: } ! 517: ! 518: if (result != (size_t)(-1)) { ! 519: /* flush the shift-out sequences */ ! 520: for (;;) { ! 521: result = iconv(cd, NULL, NULL, (char **) &out_p, &out_left); ! 522: out_size = bsz - out_left; ! 523: ! 524: if (result != (size_t)(-1)) { ! 525: break; ! 526: } ! 527: ! 528: if (errno == E2BIG) { ! 529: bsz += 16; ! 530: tmp_buf = (char *) erealloc(out_buf, bsz); ! 531: ! 532: out_p = out_buf = tmp_buf; ! 533: out_p += out_size; ! 534: out_left = bsz - out_size; ! 535: } else { ! 536: break; ! 537: } ! 538: } ! 539: } ! 540: ! 541: iconv_close(cd); ! 542: ! 543: if (result == (size_t)(-1)) { ! 544: switch (errno) { ! 545: case EINVAL: ! 546: retval = PHP_ICONV_ERR_ILLEGAL_CHAR; ! 547: break; ! 548: ! 549: case EILSEQ: ! 550: retval = PHP_ICONV_ERR_ILLEGAL_SEQ; ! 551: break; ! 552: ! 553: case E2BIG: ! 554: /* should not happen */ ! 555: retval = PHP_ICONV_ERR_TOO_BIG; ! 556: break; ! 557: ! 558: default: ! 559: /* other error */ ! 560: retval = PHP_ICONV_ERR_UNKNOWN; ! 561: efree(out_buf); ! 562: return PHP_ICONV_ERR_UNKNOWN; ! 563: } ! 564: } ! 565: *out_p = '\0'; ! 566: *out = out_buf; ! 567: *out_len = out_size; ! 568: return retval; ! 569: #endif ! 570: } ! 571: /* }}} */ ! 572: ! 573: /* {{{ _php_iconv_strlen() */ ! 574: static php_iconv_err_t _php_iconv_strlen(unsigned int *pretval, const char *str, size_t nbytes, const char *enc) ! 575: { ! 576: char buf[GENERIC_SUPERSET_NBYTES*2]; ! 577: ! 578: php_iconv_err_t err = PHP_ICONV_ERR_SUCCESS; ! 579: ! 580: iconv_t cd; ! 581: ! 582: const char *in_p; ! 583: size_t in_left; ! 584: ! 585: char *out_p; ! 586: size_t out_left; ! 587: ! 588: unsigned int cnt; ! 589: ! 590: *pretval = (unsigned int)-1; ! 591: ! 592: cd = iconv_open(GENERIC_SUPERSET_NAME, enc); ! 593: ! 594: if (cd == (iconv_t)(-1)) { ! 595: #if ICONV_SUPPORTS_ERRNO ! 596: if (errno == EINVAL) { ! 597: return PHP_ICONV_ERR_WRONG_CHARSET; ! 598: } else { ! 599: return PHP_ICONV_ERR_CONVERTER; ! 600: } ! 601: #else ! 602: return PHP_ICONV_ERR_UNKNOWN; ! 603: #endif ! 604: } ! 605: ! 606: errno = out_left = 0; ! 607: ! 608: for (in_p = str, in_left = nbytes, cnt = 0; in_left > 0; cnt+=2) { ! 609: size_t prev_in_left; ! 610: out_p = buf; ! 611: out_left = sizeof(buf); ! 612: ! 613: prev_in_left = in_left; ! 614: ! 615: if (iconv(cd, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) { ! 616: if (prev_in_left == in_left) { ! 617: break; ! 618: } ! 619: } ! 620: } ! 621: ! 622: if (out_left > 0) { ! 623: cnt -= out_left / GENERIC_SUPERSET_NBYTES; ! 624: } ! 625: ! 626: #if ICONV_SUPPORTS_ERRNO ! 627: switch (errno) { ! 628: case EINVAL: ! 629: err = PHP_ICONV_ERR_ILLEGAL_CHAR; ! 630: break; ! 631: ! 632: case EILSEQ: ! 633: err = PHP_ICONV_ERR_ILLEGAL_SEQ; ! 634: break; ! 635: ! 636: case E2BIG: ! 637: case 0: ! 638: *pretval = cnt; ! 639: break; ! 640: ! 641: default: ! 642: err = PHP_ICONV_ERR_UNKNOWN; ! 643: break; ! 644: } ! 645: #else ! 646: *pretval = cnt; ! 647: #endif ! 648: ! 649: iconv_close(cd); ! 650: ! 651: return err; ! 652: } ! 653: ! 654: /* }}} */ ! 655: ! 656: /* {{{ _php_iconv_substr() */ ! 657: static php_iconv_err_t _php_iconv_substr(smart_str *pretval, ! 658: const char *str, size_t nbytes, int offset, int len, const char *enc) ! 659: { ! 660: char buf[GENERIC_SUPERSET_NBYTES]; ! 661: ! 662: php_iconv_err_t err = PHP_ICONV_ERR_SUCCESS; ! 663: ! 664: iconv_t cd1, cd2; ! 665: ! 666: const char *in_p; ! 667: size_t in_left; ! 668: ! 669: char *out_p; ! 670: size_t out_left; ! 671: ! 672: unsigned int cnt; ! 673: int total_len; ! 674: ! 675: err = _php_iconv_strlen(&total_len, str, nbytes, enc); ! 676: if (err != PHP_ICONV_ERR_SUCCESS) { ! 677: return err; ! 678: } ! 679: ! 680: if (len < 0) { ! 681: if ((len += (total_len - offset)) < 0) { ! 682: return PHP_ICONV_ERR_SUCCESS; ! 683: } ! 684: } ! 685: ! 686: if (offset < 0) { ! 687: if ((offset += total_len) < 0) { ! 688: return PHP_ICONV_ERR_SUCCESS; ! 689: } ! 690: } ! 691: ! 692: if(len > total_len) { ! 693: len = total_len; ! 694: } ! 695: ! 696: ! 697: if (offset >= total_len) { ! 698: return PHP_ICONV_ERR_SUCCESS; ! 699: } ! 700: ! 701: if ((offset + len) > total_len ) { ! 702: /* trying to compute the length */ ! 703: len = total_len - offset; ! 704: } ! 705: ! 706: if (len == 0) { ! 707: smart_str_appendl(pretval, "", 0); ! 708: smart_str_0(pretval); ! 709: return PHP_ICONV_ERR_SUCCESS; ! 710: } ! 711: ! 712: cd1 = iconv_open(GENERIC_SUPERSET_NAME, enc); ! 713: ! 714: if (cd1 == (iconv_t)(-1)) { ! 715: #if ICONV_SUPPORTS_ERRNO ! 716: if (errno == EINVAL) { ! 717: return PHP_ICONV_ERR_WRONG_CHARSET; ! 718: } else { ! 719: return PHP_ICONV_ERR_CONVERTER; ! 720: } ! 721: #else ! 722: return PHP_ICONV_ERR_UNKNOWN; ! 723: #endif ! 724: } ! 725: ! 726: cd2 = (iconv_t)NULL; ! 727: errno = 0; ! 728: ! 729: for (in_p = str, in_left = nbytes, cnt = 0; in_left > 0 && len > 0; ++cnt) { ! 730: size_t prev_in_left; ! 731: out_p = buf; ! 732: out_left = sizeof(buf); ! 733: ! 734: prev_in_left = in_left; ! 735: ! 736: if (iconv(cd1, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) { ! 737: if (prev_in_left == in_left) { ! 738: break; ! 739: } ! 740: } ! 741: ! 742: if (cnt >= (unsigned int)offset) { ! 743: if (cd2 == (iconv_t)NULL) { ! 744: cd2 = iconv_open(enc, GENERIC_SUPERSET_NAME); ! 745: ! 746: if (cd2 == (iconv_t)(-1)) { ! 747: cd2 = (iconv_t)NULL; ! 748: #if ICONV_SUPPORTS_ERRNO ! 749: if (errno == EINVAL) { ! 750: err = PHP_ICONV_ERR_WRONG_CHARSET; ! 751: } else { ! 752: err = PHP_ICONV_ERR_CONVERTER; ! 753: } ! 754: #else ! 755: err = PHP_ICONV_ERR_UNKNOWN; ! 756: #endif ! 757: break; ! 758: } ! 759: } ! 760: ! 761: if (_php_iconv_appendl(pretval, buf, sizeof(buf), cd2) != PHP_ICONV_ERR_SUCCESS) { ! 762: break; ! 763: } ! 764: --len; ! 765: } ! 766: ! 767: } ! 768: ! 769: #if ICONV_SUPPORTS_ERRNO ! 770: switch (errno) { ! 771: case EINVAL: ! 772: err = PHP_ICONV_ERR_ILLEGAL_CHAR; ! 773: break; ! 774: ! 775: case EILSEQ: ! 776: err = PHP_ICONV_ERR_ILLEGAL_SEQ; ! 777: break; ! 778: ! 779: case E2BIG: ! 780: break; ! 781: } ! 782: #endif ! 783: if (err == PHP_ICONV_ERR_SUCCESS) { ! 784: if (cd2 != (iconv_t)NULL) { ! 785: _php_iconv_appendl(pretval, NULL, 0, cd2); ! 786: } ! 787: smart_str_0(pretval); ! 788: } ! 789: ! 790: if (cd1 != (iconv_t)NULL) { ! 791: iconv_close(cd1); ! 792: } ! 793: ! 794: if (cd2 != (iconv_t)NULL) { ! 795: iconv_close(cd2); ! 796: } ! 797: return err; ! 798: } ! 799: ! 800: /* }}} */ ! 801: ! 802: /* {{{ _php_iconv_strpos() */ ! 803: static php_iconv_err_t _php_iconv_strpos(unsigned int *pretval, ! 804: const char *haystk, size_t haystk_nbytes, ! 805: const char *ndl, size_t ndl_nbytes, ! 806: int offset, const char *enc) ! 807: { ! 808: char buf[GENERIC_SUPERSET_NBYTES]; ! 809: ! 810: php_iconv_err_t err = PHP_ICONV_ERR_SUCCESS; ! 811: ! 812: iconv_t cd; ! 813: ! 814: const char *in_p; ! 815: size_t in_left; ! 816: ! 817: char *out_p; ! 818: size_t out_left; ! 819: ! 820: unsigned int cnt; ! 821: ! 822: char *ndl_buf; ! 823: const char *ndl_buf_p; ! 824: size_t ndl_buf_len, ndl_buf_left; ! 825: ! 826: unsigned int match_ofs; ! 827: ! 828: *pretval = (unsigned int)-1; ! 829: ! 830: err = php_iconv_string(ndl, ndl_nbytes, ! 831: &ndl_buf, &ndl_buf_len, GENERIC_SUPERSET_NAME, enc); ! 832: ! 833: if (err != PHP_ICONV_ERR_SUCCESS) { ! 834: if (ndl_buf != NULL) { ! 835: efree(ndl_buf); ! 836: } ! 837: return err; ! 838: } ! 839: ! 840: cd = iconv_open(GENERIC_SUPERSET_NAME, enc); ! 841: ! 842: if (cd == (iconv_t)(-1)) { ! 843: if (ndl_buf != NULL) { ! 844: efree(ndl_buf); ! 845: } ! 846: #if ICONV_SUPPORTS_ERRNO ! 847: if (errno == EINVAL) { ! 848: return PHP_ICONV_ERR_WRONG_CHARSET; ! 849: } else { ! 850: return PHP_ICONV_ERR_CONVERTER; ! 851: } ! 852: #else ! 853: return PHP_ICONV_ERR_UNKNOWN; ! 854: #endif ! 855: } ! 856: ! 857: ndl_buf_p = ndl_buf; ! 858: ndl_buf_left = ndl_buf_len; ! 859: match_ofs = (unsigned int)-1; ! 860: ! 861: for (in_p = haystk, in_left = haystk_nbytes, cnt = 0; in_left > 0; ++cnt) { ! 862: size_t prev_in_left; ! 863: out_p = buf; ! 864: out_left = sizeof(buf); ! 865: ! 866: prev_in_left = in_left; ! 867: ! 868: if (iconv(cd, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) { ! 869: if (prev_in_left == in_left) { ! 870: #if ICONV_SUPPORTS_ERRNO ! 871: switch (errno) { ! 872: case EINVAL: ! 873: err = PHP_ICONV_ERR_ILLEGAL_CHAR; ! 874: break; ! 875: ! 876: case EILSEQ: ! 877: err = PHP_ICONV_ERR_ILLEGAL_SEQ; ! 878: break; ! 879: ! 880: case E2BIG: ! 881: break; ! 882: ! 883: default: ! 884: err = PHP_ICONV_ERR_UNKNOWN; ! 885: break; ! 886: } ! 887: #endif ! 888: break; ! 889: } ! 890: } ! 891: if (offset >= 0) { ! 892: if (cnt >= (unsigned int)offset) { ! 893: if (_php_iconv_memequal(buf, ndl_buf_p, sizeof(buf))) { ! 894: if (match_ofs == (unsigned int)-1) { ! 895: match_ofs = cnt; ! 896: } ! 897: ndl_buf_p += GENERIC_SUPERSET_NBYTES; ! 898: ndl_buf_left -= GENERIC_SUPERSET_NBYTES; ! 899: if (ndl_buf_left == 0) { ! 900: *pretval = match_ofs; ! 901: break; ! 902: } ! 903: } else { ! 904: unsigned int i, j, lim; ! 905: ! 906: i = 0; ! 907: j = GENERIC_SUPERSET_NBYTES; ! 908: lim = (unsigned int)(ndl_buf_p - ndl_buf); ! 909: ! 910: while (j < lim) { ! 911: if (_php_iconv_memequal(&ndl_buf[j], &ndl_buf[i], ! 912: GENERIC_SUPERSET_NBYTES)) { ! 913: i += GENERIC_SUPERSET_NBYTES; ! 914: } else { ! 915: j -= i; ! 916: i = 0; ! 917: } ! 918: j += GENERIC_SUPERSET_NBYTES; ! 919: } ! 920: ! 921: if (_php_iconv_memequal(buf, &ndl_buf[i], sizeof(buf))) { ! 922: match_ofs += (lim - i) / GENERIC_SUPERSET_NBYTES; ! 923: i += GENERIC_SUPERSET_NBYTES; ! 924: ndl_buf_p = &ndl_buf[i]; ! 925: ndl_buf_left = ndl_buf_len - i; ! 926: } else { ! 927: match_ofs = (unsigned int)-1; ! 928: ndl_buf_p = ndl_buf; ! 929: ndl_buf_left = ndl_buf_len; ! 930: } ! 931: } ! 932: } ! 933: } else { ! 934: if (_php_iconv_memequal(buf, ndl_buf_p, sizeof(buf))) { ! 935: if (match_ofs == (unsigned int)-1) { ! 936: match_ofs = cnt; ! 937: } ! 938: ndl_buf_p += GENERIC_SUPERSET_NBYTES; ! 939: ndl_buf_left -= GENERIC_SUPERSET_NBYTES; ! 940: if (ndl_buf_left == 0) { ! 941: *pretval = match_ofs; ! 942: ndl_buf_p = ndl_buf; ! 943: ndl_buf_left = ndl_buf_len; ! 944: match_ofs = -1; ! 945: } ! 946: } else { ! 947: unsigned int i, j, lim; ! 948: ! 949: i = 0; ! 950: j = GENERIC_SUPERSET_NBYTES; ! 951: lim = (unsigned int)(ndl_buf_p - ndl_buf); ! 952: ! 953: while (j < lim) { ! 954: if (_php_iconv_memequal(&ndl_buf[j], &ndl_buf[i], ! 955: GENERIC_SUPERSET_NBYTES)) { ! 956: i += GENERIC_SUPERSET_NBYTES; ! 957: } else { ! 958: j -= i; ! 959: i = 0; ! 960: } ! 961: j += GENERIC_SUPERSET_NBYTES; ! 962: } ! 963: ! 964: if (_php_iconv_memequal(buf, &ndl_buf[i], sizeof(buf))) { ! 965: match_ofs += (lim - i) / GENERIC_SUPERSET_NBYTES; ! 966: i += GENERIC_SUPERSET_NBYTES; ! 967: ndl_buf_p = &ndl_buf[i]; ! 968: ndl_buf_left = ndl_buf_len - i; ! 969: } else { ! 970: match_ofs = (unsigned int)-1; ! 971: ndl_buf_p = ndl_buf; ! 972: ndl_buf_left = ndl_buf_len; ! 973: } ! 974: } ! 975: } ! 976: } ! 977: ! 978: if (ndl_buf) { ! 979: efree(ndl_buf); ! 980: } ! 981: ! 982: iconv_close(cd); ! 983: ! 984: return err; ! 985: } ! 986: /* }}} */ ! 987: ! 988: /* {{{ _php_iconv_mime_encode() */ ! 989: static php_iconv_err_t _php_iconv_mime_encode(smart_str *pretval, const char *fname, size_t fname_nbytes, const char *fval, size_t fval_nbytes, unsigned int max_line_len, const char *lfchars, php_iconv_enc_scheme_t enc_scheme, const char *out_charset, const char *enc) ! 990: { ! 991: php_iconv_err_t err = PHP_ICONV_ERR_SUCCESS; ! 992: iconv_t cd = (iconv_t)(-1), cd_pl = (iconv_t)(-1); ! 993: unsigned int char_cnt = 0; ! 994: size_t out_charset_len; ! 995: size_t lfchars_len; ! 996: char *buf = NULL; ! 997: char *encoded = NULL; ! 998: size_t encoded_len; ! 999: const char *in_p; ! 1000: size_t in_left; ! 1001: char *out_p; ! 1002: size_t out_left; ! 1003: static int qp_table[256] = { ! 1004: 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x00 */ ! 1005: 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x10 */ ! 1006: 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x20 */ ! 1007: 1, 1, 1, 1, 1, 1, 1 ,1, 1, 1, 1, 1, 1, 3, 1, 3, /* 0x30 */ ! 1008: 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40 */ ! 1009: 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, /* 0x50 */ ! 1010: 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60 */ ! 1011: 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, /* 0x70 */ ! 1012: 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x80 */ ! 1013: 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x90 */ ! 1014: 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xA0 */ ! 1015: 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xB0 */ ! 1016: 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xC0 */ ! 1017: 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xD0 */ ! 1018: 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xE0 */ ! 1019: 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 /* 0xF0 */ ! 1020: }; ! 1021: ! 1022: out_charset_len = strlen(out_charset); ! 1023: lfchars_len = strlen(lfchars); ! 1024: ! 1025: if ((fname_nbytes + 2) >= max_line_len ! 1026: || (out_charset_len + 12) >= max_line_len) { ! 1027: /* field name is too long */ ! 1028: err = PHP_ICONV_ERR_TOO_BIG; ! 1029: goto out; ! 1030: } ! 1031: ! 1032: cd_pl = iconv_open(ICONV_ASCII_ENCODING, enc); ! 1033: if (cd_pl == (iconv_t)(-1)) { ! 1034: #if ICONV_SUPPORTS_ERRNO ! 1035: if (errno == EINVAL) { ! 1036: err = PHP_ICONV_ERR_WRONG_CHARSET; ! 1037: } else { ! 1038: err = PHP_ICONV_ERR_CONVERTER; ! 1039: } ! 1040: #else ! 1041: err = PHP_ICONV_ERR_UNKNOWN; ! 1042: #endif ! 1043: goto out; ! 1044: } ! 1045: ! 1046: cd = iconv_open(out_charset, enc); ! 1047: if (cd == (iconv_t)(-1)) { ! 1048: #if ICONV_SUPPORTS_ERRNO ! 1049: if (errno == EINVAL) { ! 1050: err = PHP_ICONV_ERR_WRONG_CHARSET; ! 1051: } else { ! 1052: err = PHP_ICONV_ERR_CONVERTER; ! 1053: } ! 1054: #else ! 1055: err = PHP_ICONV_ERR_UNKNOWN; ! 1056: #endif ! 1057: goto out; ! 1058: } ! 1059: ! 1060: buf = safe_emalloc(1, max_line_len, 5); ! 1061: ! 1062: char_cnt = max_line_len; ! 1063: ! 1064: _php_iconv_appendl(pretval, fname, fname_nbytes, cd_pl); ! 1065: char_cnt -= fname_nbytes; ! 1066: smart_str_appendl(pretval, ": ", sizeof(": ") - 1); ! 1067: char_cnt -= 2; ! 1068: ! 1069: in_p = fval; ! 1070: in_left = fval_nbytes; ! 1071: ! 1072: do { ! 1073: size_t prev_in_left; ! 1074: size_t out_size; ! 1075: ! 1076: if (char_cnt < (out_charset_len + 12)) { ! 1077: /* lfchars must be encoded in ASCII here*/ ! 1078: smart_str_appendl(pretval, lfchars, lfchars_len); ! 1079: smart_str_appendc(pretval, ' '); ! 1080: char_cnt = max_line_len - 1; ! 1081: } ! 1082: ! 1083: smart_str_appendl(pretval, "=?", sizeof("=?") - 1); ! 1084: char_cnt -= 2; ! 1085: smart_str_appendl(pretval, out_charset, out_charset_len); ! 1086: char_cnt -= out_charset_len; ! 1087: smart_str_appendc(pretval, '?'); ! 1088: char_cnt --; ! 1089: ! 1090: switch (enc_scheme) { ! 1091: case PHP_ICONV_ENC_SCHEME_BASE64: { ! 1092: size_t ini_in_left; ! 1093: const char *ini_in_p; ! 1094: size_t out_reserved = 4; ! 1095: int dummy; ! 1096: ! 1097: smart_str_appendc(pretval, 'B'); ! 1098: char_cnt--; ! 1099: smart_str_appendc(pretval, '?'); ! 1100: char_cnt--; ! 1101: ! 1102: prev_in_left = ini_in_left = in_left; ! 1103: ini_in_p = in_p; ! 1104: ! 1105: out_size = (char_cnt - 2) / 4 * 3; ! 1106: ! 1107: for (;;) { ! 1108: out_p = buf; ! 1109: ! 1110: if (out_size <= out_reserved) { ! 1111: err = PHP_ICONV_ERR_TOO_BIG; ! 1112: goto out; ! 1113: } ! 1114: ! 1115: out_left = out_size - out_reserved; ! 1116: ! 1117: if (iconv(cd, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) { ! 1118: #if ICONV_SUPPORTS_ERRNO ! 1119: switch (errno) { ! 1120: case EINVAL: ! 1121: err = PHP_ICONV_ERR_ILLEGAL_CHAR; ! 1122: goto out; ! 1123: ! 1124: case EILSEQ: ! 1125: err = PHP_ICONV_ERR_ILLEGAL_SEQ; ! 1126: goto out; ! 1127: ! 1128: case E2BIG: ! 1129: if (prev_in_left == in_left) { ! 1130: err = PHP_ICONV_ERR_TOO_BIG; ! 1131: goto out; ! 1132: } ! 1133: break; ! 1134: ! 1135: default: ! 1136: err = PHP_ICONV_ERR_UNKNOWN; ! 1137: goto out; ! 1138: } ! 1139: #else ! 1140: if (prev_in_left == in_left) { ! 1141: err = PHP_ICONV_ERR_UNKNOWN; ! 1142: goto out; ! 1143: } ! 1144: #endif ! 1145: } ! 1146: ! 1147: out_left += out_reserved; ! 1148: ! 1149: if (iconv(cd, NULL, NULL, (char **) &out_p, &out_left) == (size_t)-1) { ! 1150: #if ICONV_SUPPORTS_ERRNO ! 1151: if (errno != E2BIG) { ! 1152: err = PHP_ICONV_ERR_UNKNOWN; ! 1153: goto out; ! 1154: } ! 1155: #else ! 1156: if (out_left != 0) { ! 1157: err = PHP_ICONV_ERR_UNKNOWN; ! 1158: goto out; ! 1159: } ! 1160: #endif ! 1161: } else { ! 1162: break; ! 1163: } ! 1164: ! 1165: if (iconv(cd, NULL, NULL, NULL, NULL) == (size_t)-1) { ! 1166: err = PHP_ICONV_ERR_UNKNOWN; ! 1167: goto out; ! 1168: } ! 1169: ! 1170: out_reserved += 4; ! 1171: in_left = ini_in_left; ! 1172: in_p = ini_in_p; ! 1173: } ! 1174: ! 1175: prev_in_left = in_left; ! 1176: ! 1177: encoded = (char *) php_base64_encode((unsigned char *) buf, (int)(out_size - out_left), &dummy); ! 1178: encoded_len = (size_t)dummy; ! 1179: ! 1180: if (char_cnt < encoded_len) { ! 1181: /* something went wrong! */ ! 1182: err = PHP_ICONV_ERR_UNKNOWN; ! 1183: goto out; ! 1184: } ! 1185: ! 1186: smart_str_appendl(pretval, encoded, encoded_len); ! 1187: char_cnt -= encoded_len; ! 1188: smart_str_appendl(pretval, "?=", sizeof("?=") - 1); ! 1189: char_cnt -= 2; ! 1190: ! 1191: efree(encoded); ! 1192: encoded = NULL; ! 1193: } break; /* case PHP_ICONV_ENC_SCHEME_BASE64: */ ! 1194: ! 1195: case PHP_ICONV_ENC_SCHEME_QPRINT: { ! 1196: size_t ini_in_left; ! 1197: const char *ini_in_p; ! 1198: const unsigned char *p; ! 1199: size_t nbytes_required; ! 1200: ! 1201: smart_str_appendc(pretval, 'Q'); ! 1202: char_cnt--; ! 1203: smart_str_appendc(pretval, '?'); ! 1204: char_cnt--; ! 1205: ! 1206: prev_in_left = ini_in_left = in_left; ! 1207: ini_in_p = in_p; ! 1208: ! 1209: for (out_size = (char_cnt - 2) / 3; out_size > 0;) { ! 1210: size_t prev_out_left; ! 1211: ! 1212: nbytes_required = 0; ! 1213: ! 1214: out_p = buf; ! 1215: out_left = out_size; ! 1216: ! 1217: if (iconv(cd, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) { ! 1218: #if ICONV_SUPPORTS_ERRNO ! 1219: switch (errno) { ! 1220: case EINVAL: ! 1221: err = PHP_ICONV_ERR_ILLEGAL_CHAR; ! 1222: goto out; ! 1223: ! 1224: case EILSEQ: ! 1225: err = PHP_ICONV_ERR_ILLEGAL_SEQ; ! 1226: goto out; ! 1227: ! 1228: case E2BIG: ! 1229: if (prev_in_left == in_left) { ! 1230: err = PHP_ICONV_ERR_UNKNOWN; ! 1231: goto out; ! 1232: } ! 1233: break; ! 1234: ! 1235: default: ! 1236: err = PHP_ICONV_ERR_UNKNOWN; ! 1237: goto out; ! 1238: } ! 1239: #else ! 1240: if (prev_in_left == in_left) { ! 1241: err = PHP_ICONV_ERR_UNKNOWN; ! 1242: goto out; ! 1243: } ! 1244: #endif ! 1245: } ! 1246: ! 1247: prev_out_left = out_left; ! 1248: if (iconv(cd, NULL, NULL, (char **) &out_p, &out_left) == (size_t)-1) { ! 1249: #if ICONV_SUPPORTS_ERRNO ! 1250: if (errno != E2BIG) { ! 1251: err = PHP_ICONV_ERR_UNKNOWN; ! 1252: goto out; ! 1253: } ! 1254: #else ! 1255: if (out_left == prev_out_left) { ! 1256: err = PHP_ICONV_ERR_UNKNOWN; ! 1257: goto out; ! 1258: } ! 1259: #endif ! 1260: } ! 1261: ! 1262: for (p = (unsigned char *)buf; p < (unsigned char *)out_p; p++) { ! 1263: nbytes_required += qp_table[*p]; ! 1264: } ! 1265: ! 1266: if (nbytes_required <= char_cnt - 2) { ! 1267: break; ! 1268: } ! 1269: ! 1270: out_size -= ((nbytes_required - (char_cnt - 2)) + 1) / 3; ! 1271: in_left = ini_in_left; ! 1272: in_p = ini_in_p; ! 1273: } ! 1274: ! 1275: for (p = (unsigned char *)buf; p < (unsigned char *)out_p; p++) { ! 1276: if (qp_table[*p] == 1) { ! 1277: smart_str_appendc(pretval, *(char *)p); ! 1278: char_cnt--; ! 1279: } else { ! 1280: static char qp_digits[] = "0123456789ABCDEF"; ! 1281: smart_str_appendc(pretval, '='); ! 1282: smart_str_appendc(pretval, qp_digits[(*p >> 4) & 0x0f]); ! 1283: smart_str_appendc(pretval, qp_digits[(*p & 0x0f)]); ! 1284: char_cnt -= 3; ! 1285: } ! 1286: } ! 1287: ! 1288: smart_str_appendl(pretval, "?=", sizeof("?=") - 1); ! 1289: char_cnt -= 2; ! 1290: ! 1291: if (iconv(cd, NULL, NULL, NULL, NULL) == (size_t)-1) { ! 1292: err = PHP_ICONV_ERR_UNKNOWN; ! 1293: goto out; ! 1294: } ! 1295: ! 1296: } break; /* case PHP_ICONV_ENC_SCHEME_QPRINT: */ ! 1297: } ! 1298: } while (in_left > 0); ! 1299: ! 1300: smart_str_0(pretval); ! 1301: ! 1302: out: ! 1303: if (cd != (iconv_t)(-1)) { ! 1304: iconv_close(cd); ! 1305: } ! 1306: if (cd_pl != (iconv_t)(-1)) { ! 1307: iconv_close(cd_pl); ! 1308: } ! 1309: if (encoded != NULL) { ! 1310: efree(encoded); ! 1311: } ! 1312: if (buf != NULL) { ! 1313: efree(buf); ! 1314: } ! 1315: return err; ! 1316: } ! 1317: /* }}} */ ! 1318: ! 1319: /* {{{ _php_iconv_mime_decode() */ ! 1320: static php_iconv_err_t _php_iconv_mime_decode(smart_str *pretval, const char *str, size_t str_nbytes, const char *enc, const char **next_pos, int mode) ! 1321: { ! 1322: php_iconv_err_t err = PHP_ICONV_ERR_SUCCESS; ! 1323: ! 1324: iconv_t cd = (iconv_t)(-1), cd_pl = (iconv_t)(-1); ! 1325: ! 1326: const char *p1; ! 1327: size_t str_left; ! 1328: unsigned int scan_stat = 0; ! 1329: const char *csname = NULL; ! 1330: size_t csname_len; ! 1331: const char *encoded_text = NULL; ! 1332: size_t encoded_text_len = 0; ! 1333: const char *encoded_word = NULL; ! 1334: const char *spaces = NULL; ! 1335: ! 1336: php_iconv_enc_scheme_t enc_scheme = PHP_ICONV_ENC_SCHEME_BASE64; ! 1337: ! 1338: if (next_pos != NULL) { ! 1339: *next_pos = NULL; ! 1340: } ! 1341: ! 1342: cd_pl = iconv_open(enc, ICONV_ASCII_ENCODING); ! 1343: ! 1344: if (cd_pl == (iconv_t)(-1)) { ! 1345: #if ICONV_SUPPORTS_ERRNO ! 1346: if (errno == EINVAL) { ! 1347: err = PHP_ICONV_ERR_WRONG_CHARSET; ! 1348: } else { ! 1349: err = PHP_ICONV_ERR_CONVERTER; ! 1350: } ! 1351: #else ! 1352: err = PHP_ICONV_ERR_UNKNOWN; ! 1353: #endif ! 1354: goto out; ! 1355: } ! 1356: ! 1357: p1 = str; ! 1358: for (str_left = str_nbytes; str_left > 0; str_left--, p1++) { ! 1359: int eos = 0; ! 1360: ! 1361: switch (scan_stat) { ! 1362: case 0: /* expecting any character */ ! 1363: switch (*p1) { ! 1364: case '\r': /* part of an EOL sequence? */ ! 1365: scan_stat = 7; ! 1366: break; ! 1367: ! 1368: case '\n': ! 1369: scan_stat = 8; ! 1370: break; ! 1371: ! 1372: case '=': /* first letter of an encoded chunk */ ! 1373: encoded_word = p1; ! 1374: scan_stat = 1; ! 1375: break; ! 1376: ! 1377: case ' ': case '\t': /* a chunk of whitespaces */ ! 1378: spaces = p1; ! 1379: scan_stat = 11; ! 1380: break; ! 1381: ! 1382: default: /* first letter of a non-encoded word */ ! 1383: _php_iconv_appendc(pretval, *p1, cd_pl); ! 1384: encoded_word = NULL; ! 1385: if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) { ! 1386: scan_stat = 12; ! 1387: } ! 1388: break; ! 1389: } ! 1390: break; ! 1391: ! 1392: case 1: /* expecting a delimiter */ ! 1393: if (*p1 != '?') { ! 1394: err = _php_iconv_appendl(pretval, encoded_word, (size_t)((p1 + 1) - encoded_word), cd_pl); ! 1395: if (err != PHP_ICONV_ERR_SUCCESS) { ! 1396: goto out; ! 1397: } ! 1398: encoded_word = NULL; ! 1399: if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) { ! 1400: scan_stat = 12; ! 1401: } else { ! 1402: scan_stat = 0; ! 1403: } ! 1404: break; ! 1405: } ! 1406: csname = p1 + 1; ! 1407: scan_stat = 2; ! 1408: break; ! 1409: ! 1410: case 2: /* expecting a charset name */ ! 1411: switch (*p1) { ! 1412: case '?': /* normal delimiter: encoding scheme follows */ ! 1413: scan_stat = 3; ! 1414: break; ! 1415: ! 1416: case '*': /* new style delimiter: locale id follows */ ! 1417: scan_stat = 10; ! 1418: break; ! 1419: } ! 1420: if (scan_stat != 2) { ! 1421: char tmpbuf[80]; ! 1422: ! 1423: if (csname == NULL) { ! 1424: err = PHP_ICONV_ERR_MALFORMED; ! 1425: goto out; ! 1426: } ! 1427: ! 1428: csname_len = (size_t)(p1 - csname); ! 1429: ! 1430: if (csname_len > sizeof(tmpbuf) - 1) { ! 1431: if ((mode & PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR)) { ! 1432: err = _php_iconv_appendl(pretval, encoded_word, (size_t)((p1 + 1) - encoded_word), cd_pl); ! 1433: if (err != PHP_ICONV_ERR_SUCCESS) { ! 1434: goto out; ! 1435: } ! 1436: encoded_word = NULL; ! 1437: if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) { ! 1438: scan_stat = 12; ! 1439: } else { ! 1440: scan_stat = 0; ! 1441: } ! 1442: break; ! 1443: } else { ! 1444: err = PHP_ICONV_ERR_MALFORMED; ! 1445: goto out; ! 1446: } ! 1447: } ! 1448: ! 1449: memcpy(tmpbuf, csname, csname_len); ! 1450: tmpbuf[csname_len] = '\0'; ! 1451: ! 1452: if (cd != (iconv_t)(-1)) { ! 1453: iconv_close(cd); ! 1454: } ! 1455: ! 1456: cd = iconv_open(enc, tmpbuf); ! 1457: ! 1458: if (cd == (iconv_t)(-1)) { ! 1459: if ((mode & PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR)) { ! 1460: /* Bad character set, but the user wants us to ! 1461: * press on. In this case, we'll just insert the ! 1462: * undecoded encoded word, since there isn't really ! 1463: * a more sensible behaviour available; the only ! 1464: * other options are to swallow the encoded word ! 1465: * entirely or decode it with an arbitrarily chosen ! 1466: * single byte encoding, both of which seem to have ! 1467: * a higher WTF factor than leaving it undecoded. ! 1468: * ! 1469: * Given this approach, we need to skip ahead to ! 1470: * the end of the encoded word. */ ! 1471: int qmarks = 2; ! 1472: while (qmarks > 0 && str_left > 1) { ! 1473: if (*(++p1) == '?') { ! 1474: --qmarks; ! 1475: } ! 1476: --str_left; ! 1477: } ! 1478: ! 1479: /* Look ahead to check for the terminating = that ! 1480: * should be there as well; if it's there, we'll ! 1481: * also include that. If it's not, there isn't much ! 1482: * we can do at this point. */ ! 1483: if (*(p1 + 1) == '=') { ! 1484: ++p1; ! 1485: --str_left; ! 1486: } ! 1487: ! 1488: err = _php_iconv_appendl(pretval, encoded_word, (size_t)((p1 + 1) - encoded_word), cd_pl); ! 1489: if (err != PHP_ICONV_ERR_SUCCESS) { ! 1490: goto out; ! 1491: } ! 1492: ! 1493: /* Let's go back and see if there are further ! 1494: * encoded words or bare content, and hope they ! 1495: * might actually have a valid character set. */ ! 1496: scan_stat = 12; ! 1497: break; ! 1498: } else { ! 1499: #if ICONV_SUPPORTS_ERRNO ! 1500: if (errno == EINVAL) { ! 1501: err = PHP_ICONV_ERR_WRONG_CHARSET; ! 1502: } else { ! 1503: err = PHP_ICONV_ERR_CONVERTER; ! 1504: } ! 1505: #else ! 1506: err = PHP_ICONV_ERR_UNKNOWN; ! 1507: #endif ! 1508: goto out; ! 1509: } ! 1510: } ! 1511: } ! 1512: break; ! 1513: ! 1514: case 3: /* expecting a encoding scheme specifier */ ! 1515: switch (*p1) { ! 1516: case 'b': ! 1517: case 'B': ! 1518: enc_scheme = PHP_ICONV_ENC_SCHEME_BASE64; ! 1519: scan_stat = 4; ! 1520: break; ! 1521: ! 1522: case 'q': ! 1523: case 'Q': ! 1524: enc_scheme = PHP_ICONV_ENC_SCHEME_QPRINT; ! 1525: scan_stat = 4; ! 1526: break; ! 1527: ! 1528: default: ! 1529: if ((mode & PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR)) { ! 1530: err = _php_iconv_appendl(pretval, encoded_word, (size_t)((p1 + 1) - encoded_word), cd_pl); ! 1531: if (err != PHP_ICONV_ERR_SUCCESS) { ! 1532: goto out; ! 1533: } ! 1534: encoded_word = NULL; ! 1535: if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) { ! 1536: scan_stat = 12; ! 1537: } else { ! 1538: scan_stat = 0; ! 1539: } ! 1540: break; ! 1541: } else { ! 1542: err = PHP_ICONV_ERR_MALFORMED; ! 1543: goto out; ! 1544: } ! 1545: } ! 1546: break; ! 1547: ! 1548: case 4: /* expecting a delimiter */ ! 1549: if (*p1 != '?') { ! 1550: if ((mode & PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR)) { ! 1551: /* pass the entire chunk through the converter */ ! 1552: err = _php_iconv_appendl(pretval, encoded_word, (size_t)((p1 + 1) - encoded_word), cd_pl); ! 1553: if (err != PHP_ICONV_ERR_SUCCESS) { ! 1554: goto out; ! 1555: } ! 1556: encoded_word = NULL; ! 1557: if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) { ! 1558: scan_stat = 12; ! 1559: } else { ! 1560: scan_stat = 0; ! 1561: } ! 1562: break; ! 1563: } else { ! 1564: err = PHP_ICONV_ERR_MALFORMED; ! 1565: goto out; ! 1566: } ! 1567: } ! 1568: encoded_text = p1 + 1; ! 1569: scan_stat = 5; ! 1570: break; ! 1571: ! 1572: case 5: /* expecting an encoded portion */ ! 1573: if (*p1 == '?') { ! 1574: encoded_text_len = (size_t)(p1 - encoded_text); ! 1575: scan_stat = 6; ! 1576: } ! 1577: break; ! 1578: ! 1579: case 7: /* expecting a "\n" character */ ! 1580: if (*p1 == '\n') { ! 1581: scan_stat = 8; ! 1582: } else { ! 1583: /* bare CR */ ! 1584: _php_iconv_appendc(pretval, '\r', cd_pl); ! 1585: _php_iconv_appendc(pretval, *p1, cd_pl); ! 1586: scan_stat = 0; ! 1587: } ! 1588: break; ! 1589: ! 1590: case 8: /* checking whether the following line is part of a ! 1591: folded header */ ! 1592: if (*p1 != ' ' && *p1 != '\t') { ! 1593: --p1; ! 1594: str_left = 1; /* quit_loop */ ! 1595: break; ! 1596: } ! 1597: if (encoded_word == NULL) { ! 1598: _php_iconv_appendc(pretval, ' ', cd_pl); ! 1599: } ! 1600: spaces = NULL; ! 1601: scan_stat = 11; ! 1602: break; ! 1603: ! 1604: case 6: /* expecting a End-Of-Chunk character "=" */ ! 1605: if (*p1 != '=') { ! 1606: if ((mode & PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR)) { ! 1607: /* pass the entire chunk through the converter */ ! 1608: err = _php_iconv_appendl(pretval, encoded_word, (size_t)((p1 + 1) - encoded_word), cd_pl); ! 1609: if (err != PHP_ICONV_ERR_SUCCESS) { ! 1610: goto out; ! 1611: } ! 1612: encoded_word = NULL; ! 1613: if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) { ! 1614: scan_stat = 12; ! 1615: } else { ! 1616: scan_stat = 0; ! 1617: } ! 1618: break; ! 1619: } else { ! 1620: err = PHP_ICONV_ERR_MALFORMED; ! 1621: goto out; ! 1622: } ! 1623: } ! 1624: scan_stat = 9; ! 1625: if (str_left == 1) { ! 1626: eos = 1; ! 1627: } else { ! 1628: break; ! 1629: } ! 1630: ! 1631: case 9: /* choice point, seeing what to do next.*/ ! 1632: switch (*p1) { ! 1633: default: ! 1634: /* Handle non-RFC-compliant formats ! 1635: * ! 1636: * RFC2047 requires the character that comes right ! 1637: * after an encoded word (chunk) to be a whitespace, ! 1638: * while there are lots of broken implementations that ! 1639: * generate such malformed headers that don't fulfill ! 1640: * that requirement. ! 1641: */ ! 1642: if (!eos) { ! 1643: if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) { ! 1644: /* pass the entire chunk through the converter */ ! 1645: err = _php_iconv_appendl(pretval, encoded_word, (size_t)((p1 + 1) - encoded_word), cd_pl); ! 1646: if (err != PHP_ICONV_ERR_SUCCESS) { ! 1647: goto out; ! 1648: } ! 1649: scan_stat = 12; ! 1650: break; ! 1651: } ! 1652: } ! 1653: /* break is omitted intentionally */ ! 1654: ! 1655: case '\r': case '\n': case ' ': case '\t': { ! 1656: char *decoded_text; ! 1657: size_t decoded_text_len; ! 1658: int dummy; ! 1659: ! 1660: switch (enc_scheme) { ! 1661: case PHP_ICONV_ENC_SCHEME_BASE64: ! 1662: decoded_text = (char *)php_base64_decode((unsigned char*)encoded_text, (int)encoded_text_len, &dummy); ! 1663: decoded_text_len = (size_t)dummy; ! 1664: break; ! 1665: ! 1666: case PHP_ICONV_ENC_SCHEME_QPRINT: ! 1667: decoded_text = (char *)php_quot_print_decode((unsigned char*)encoded_text, (int)encoded_text_len, &decoded_text_len, 1); ! 1668: break; ! 1669: default: ! 1670: decoded_text = NULL; ! 1671: break; ! 1672: } ! 1673: ! 1674: if (decoded_text == NULL) { ! 1675: if ((mode & PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR)) { ! 1676: /* pass the entire chunk through the converter */ ! 1677: err = _php_iconv_appendl(pretval, encoded_word, (size_t)((p1 + 1) - encoded_word), cd_pl); ! 1678: if (err != PHP_ICONV_ERR_SUCCESS) { ! 1679: goto out; ! 1680: } ! 1681: encoded_word = NULL; ! 1682: if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) { ! 1683: scan_stat = 12; ! 1684: } else { ! 1685: scan_stat = 0; ! 1686: } ! 1687: break; ! 1688: } else { ! 1689: err = PHP_ICONV_ERR_UNKNOWN; ! 1690: goto out; ! 1691: } ! 1692: } ! 1693: ! 1694: err = _php_iconv_appendl(pretval, decoded_text, decoded_text_len, cd); ! 1695: efree(decoded_text); ! 1696: ! 1697: if (err != PHP_ICONV_ERR_SUCCESS) { ! 1698: if ((mode & PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR)) { ! 1699: /* pass the entire chunk through the converter */ ! 1700: err = _php_iconv_appendl(pretval, encoded_word, (size_t)(p1 - encoded_word), cd_pl); ! 1701: encoded_word = NULL; ! 1702: if (err != PHP_ICONV_ERR_SUCCESS) { ! 1703: break; ! 1704: } ! 1705: } else { ! 1706: goto out; ! 1707: } ! 1708: } ! 1709: ! 1710: if (eos) { /* reached end-of-string. done. */ ! 1711: scan_stat = 0; ! 1712: break; ! 1713: } ! 1714: ! 1715: switch (*p1) { ! 1716: case '\r': /* part of an EOL sequence? */ ! 1717: scan_stat = 7; ! 1718: break; ! 1719: ! 1720: case '\n': ! 1721: scan_stat = 8; ! 1722: break; ! 1723: ! 1724: case '=': /* first letter of an encoded chunk */ ! 1725: scan_stat = 1; ! 1726: break; ! 1727: ! 1728: case ' ': case '\t': /* medial whitespaces */ ! 1729: spaces = p1; ! 1730: scan_stat = 11; ! 1731: break; ! 1732: ! 1733: default: /* first letter of a non-encoded word */ ! 1734: _php_iconv_appendc(pretval, *p1, cd_pl); ! 1735: scan_stat = 12; ! 1736: break; ! 1737: } ! 1738: } break; ! 1739: } ! 1740: break; ! 1741: ! 1742: case 10: /* expects a language specifier. dismiss it for now */ ! 1743: if (*p1 == '?') { ! 1744: scan_stat = 3; ! 1745: } ! 1746: break; ! 1747: ! 1748: case 11: /* expecting a chunk of whitespaces */ ! 1749: switch (*p1) { ! 1750: case '\r': /* part of an EOL sequence? */ ! 1751: scan_stat = 7; ! 1752: break; ! 1753: ! 1754: case '\n': ! 1755: scan_stat = 8; ! 1756: break; ! 1757: ! 1758: case '=': /* first letter of an encoded chunk */ ! 1759: if (spaces != NULL && encoded_word == NULL) { ! 1760: _php_iconv_appendl(pretval, spaces, (size_t)(p1 - spaces), cd_pl); ! 1761: spaces = NULL; ! 1762: } ! 1763: encoded_word = p1; ! 1764: scan_stat = 1; ! 1765: break; ! 1766: ! 1767: case ' ': case '\t': ! 1768: break; ! 1769: ! 1770: default: /* first letter of a non-encoded word */ ! 1771: if (spaces != NULL) { ! 1772: _php_iconv_appendl(pretval, spaces, (size_t)(p1 - spaces), cd_pl); ! 1773: spaces = NULL; ! 1774: } ! 1775: _php_iconv_appendc(pretval, *p1, cd_pl); ! 1776: encoded_word = NULL; ! 1777: if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) { ! 1778: scan_stat = 12; ! 1779: } else { ! 1780: scan_stat = 0; ! 1781: } ! 1782: break; ! 1783: } ! 1784: break; ! 1785: ! 1786: case 12: /* expecting a non-encoded word */ ! 1787: switch (*p1) { ! 1788: case '\r': /* part of an EOL sequence? */ ! 1789: scan_stat = 7; ! 1790: break; ! 1791: ! 1792: case '\n': ! 1793: scan_stat = 8; ! 1794: break; ! 1795: ! 1796: case ' ': case '\t': ! 1797: spaces = p1; ! 1798: scan_stat = 11; ! 1799: break; ! 1800: ! 1801: case '=': /* first letter of an encoded chunk */ ! 1802: if (!(mode & PHP_ICONV_MIME_DECODE_STRICT)) { ! 1803: encoded_word = p1; ! 1804: scan_stat = 1; ! 1805: break; ! 1806: } ! 1807: /* break is omitted intentionally */ ! 1808: ! 1809: default: ! 1810: _php_iconv_appendc(pretval, *p1, cd_pl); ! 1811: break; ! 1812: } ! 1813: break; ! 1814: } ! 1815: } ! 1816: switch (scan_stat) { ! 1817: case 0: case 8: case 11: case 12: ! 1818: break; ! 1819: default: ! 1820: if ((mode & PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR)) { ! 1821: if (scan_stat == 1) { ! 1822: _php_iconv_appendc(pretval, '=', cd_pl); ! 1823: } ! 1824: err = PHP_ICONV_ERR_SUCCESS; ! 1825: } else { ! 1826: err = PHP_ICONV_ERR_MALFORMED; ! 1827: goto out; ! 1828: } ! 1829: } ! 1830: ! 1831: if (next_pos != NULL) { ! 1832: *next_pos = p1; ! 1833: } ! 1834: ! 1835: smart_str_0(pretval); ! 1836: out: ! 1837: if (cd != (iconv_t)(-1)) { ! 1838: iconv_close(cd); ! 1839: } ! 1840: if (cd_pl != (iconv_t)(-1)) { ! 1841: iconv_close(cd_pl); ! 1842: } ! 1843: return err; ! 1844: } ! 1845: /* }}} */ ! 1846: ! 1847: /* {{{ php_iconv_show_error() */ ! 1848: static void _php_iconv_show_error(php_iconv_err_t err, const char *out_charset, const char *in_charset TSRMLS_DC) ! 1849: { ! 1850: switch (err) { ! 1851: case PHP_ICONV_ERR_SUCCESS: ! 1852: break; ! 1853: ! 1854: case PHP_ICONV_ERR_CONVERTER: ! 1855: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot open converter"); ! 1856: break; ! 1857: ! 1858: case PHP_ICONV_ERR_WRONG_CHARSET: ! 1859: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Wrong charset, conversion from `%s' to `%s' is not allowed", ! 1860: in_charset, out_charset); ! 1861: break; ! 1862: ! 1863: case PHP_ICONV_ERR_ILLEGAL_CHAR: ! 1864: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected an incomplete multibyte character in input string"); ! 1865: break; ! 1866: ! 1867: case PHP_ICONV_ERR_ILLEGAL_SEQ: ! 1868: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected an illegal character in input string"); ! 1869: break; ! 1870: ! 1871: case PHP_ICONV_ERR_TOO_BIG: ! 1872: /* should not happen */ ! 1873: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Buffer length exceeded"); ! 1874: break; ! 1875: ! 1876: case PHP_ICONV_ERR_MALFORMED: ! 1877: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Malformed string"); ! 1878: break; ! 1879: ! 1880: default: ! 1881: /* other error */ ! 1882: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Unknown error (%d)", errno); ! 1883: break; ! 1884: } ! 1885: } ! 1886: /* }}} */ ! 1887: ! 1888: /* {{{ proto int iconv_strlen(string str [, string charset]) ! 1889: Returns the character count of str */ ! 1890: PHP_FUNCTION(iconv_strlen) ! 1891: { ! 1892: char *charset = ICONVG(internal_encoding); ! 1893: int charset_len = 0; ! 1894: char *str; ! 1895: int str_len; ! 1896: ! 1897: php_iconv_err_t err; ! 1898: ! 1899: unsigned int retval; ! 1900: ! 1901: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", ! 1902: &str, &str_len, &charset, &charset_len) == FAILURE) { ! 1903: RETURN_FALSE; ! 1904: } ! 1905: ! 1906: if (charset_len >= ICONV_CSNMAXLEN) { ! 1907: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN); ! 1908: RETURN_FALSE; ! 1909: } ! 1910: ! 1911: err = _php_iconv_strlen(&retval, str, str_len, charset); ! 1912: _php_iconv_show_error(err, GENERIC_SUPERSET_NAME, charset TSRMLS_CC); ! 1913: if (err == PHP_ICONV_ERR_SUCCESS) { ! 1914: RETVAL_LONG(retval); ! 1915: } else { ! 1916: RETVAL_FALSE; ! 1917: } ! 1918: } ! 1919: /* }}} */ ! 1920: ! 1921: /* {{{ proto string iconv_substr(string str, int offset, [int length, string charset]) ! 1922: Returns specified part of a string */ ! 1923: PHP_FUNCTION(iconv_substr) ! 1924: { ! 1925: char *charset = ICONVG(internal_encoding); ! 1926: int charset_len = 0; ! 1927: char *str; ! 1928: int str_len; ! 1929: long offset, length = 0; ! 1930: ! 1931: php_iconv_err_t err; ! 1932: ! 1933: smart_str retval = {0}; ! 1934: ! 1935: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl|ls", ! 1936: &str, &str_len, &offset, &length, ! 1937: &charset, &charset_len) == FAILURE) { ! 1938: RETURN_FALSE; ! 1939: } ! 1940: ! 1941: if (charset_len >= ICONV_CSNMAXLEN) { ! 1942: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN); ! 1943: RETURN_FALSE; ! 1944: } ! 1945: ! 1946: if (ZEND_NUM_ARGS() < 3) { ! 1947: length = str_len; ! 1948: } ! 1949: ! 1950: err = _php_iconv_substr(&retval, str, str_len, offset, length, charset); ! 1951: _php_iconv_show_error(err, GENERIC_SUPERSET_NAME, charset TSRMLS_CC); ! 1952: ! 1953: if (err == PHP_ICONV_ERR_SUCCESS && str != NULL && retval.c != NULL) { ! 1954: RETURN_STRINGL(retval.c, retval.len, 0); ! 1955: } ! 1956: smart_str_free(&retval); ! 1957: RETURN_FALSE; ! 1958: } ! 1959: /* }}} */ ! 1960: ! 1961: /* {{{ proto int iconv_strpos(string haystack, string needle [, int offset [, string charset]]) ! 1962: Finds position of first occurrence of needle within part of haystack beginning with offset */ ! 1963: PHP_FUNCTION(iconv_strpos) ! 1964: { ! 1965: char *charset = ICONVG(internal_encoding); ! 1966: int charset_len = 0; ! 1967: char *haystk; ! 1968: int haystk_len; ! 1969: char *ndl; ! 1970: int ndl_len; ! 1971: long offset = 0; ! 1972: ! 1973: php_iconv_err_t err; ! 1974: ! 1975: unsigned int retval; ! 1976: ! 1977: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|ls", ! 1978: &haystk, &haystk_len, &ndl, &ndl_len, ! 1979: &offset, &charset, &charset_len) == FAILURE) { ! 1980: RETURN_FALSE; ! 1981: } ! 1982: ! 1983: if (charset_len >= ICONV_CSNMAXLEN) { ! 1984: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN); ! 1985: RETURN_FALSE; ! 1986: } ! 1987: ! 1988: if (offset < 0) { ! 1989: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset not contained in string."); ! 1990: RETURN_FALSE; ! 1991: } ! 1992: ! 1993: if (ndl_len < 1) { ! 1994: RETURN_FALSE; ! 1995: } ! 1996: ! 1997: err = _php_iconv_strpos(&retval, haystk, haystk_len, ndl, ndl_len, ! 1998: offset, charset); ! 1999: _php_iconv_show_error(err, GENERIC_SUPERSET_NAME, charset TSRMLS_CC); ! 2000: ! 2001: if (err == PHP_ICONV_ERR_SUCCESS && retval != (unsigned int)-1) { ! 2002: RETVAL_LONG((long)retval); ! 2003: } else { ! 2004: RETVAL_FALSE; ! 2005: } ! 2006: } ! 2007: /* }}} */ ! 2008: ! 2009: /* {{{ proto int iconv_strrpos(string haystack, string needle [, string charset]) ! 2010: Finds position of last occurrence of needle within part of haystack beginning with offset */ ! 2011: PHP_FUNCTION(iconv_strrpos) ! 2012: { ! 2013: char *charset = ICONVG(internal_encoding); ! 2014: int charset_len = 0; ! 2015: char *haystk; ! 2016: int haystk_len; ! 2017: char *ndl; ! 2018: int ndl_len; ! 2019: ! 2020: php_iconv_err_t err; ! 2021: ! 2022: unsigned int retval; ! 2023: ! 2024: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|s", ! 2025: &haystk, &haystk_len, &ndl, &ndl_len, ! 2026: &charset, &charset_len) == FAILURE) { ! 2027: RETURN_FALSE; ! 2028: } ! 2029: ! 2030: if (ndl_len < 1) { ! 2031: RETURN_FALSE; ! 2032: } ! 2033: ! 2034: if (charset_len >= ICONV_CSNMAXLEN) { ! 2035: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN); ! 2036: RETURN_FALSE; ! 2037: } ! 2038: ! 2039: err = _php_iconv_strpos(&retval, haystk, haystk_len, ndl, ndl_len, ! 2040: -1, charset); ! 2041: _php_iconv_show_error(err, GENERIC_SUPERSET_NAME, charset TSRMLS_CC); ! 2042: ! 2043: if (err == PHP_ICONV_ERR_SUCCESS && retval != (unsigned int)-1) { ! 2044: RETVAL_LONG((long)retval); ! 2045: } else { ! 2046: RETVAL_FALSE; ! 2047: } ! 2048: } ! 2049: /* }}} */ ! 2050: ! 2051: /* {{{ proto string iconv_mime_encode(string field_name, string field_value [, array preference]) ! 2052: Composes a mime header field with field_name and field_value in a specified scheme */ ! 2053: PHP_FUNCTION(iconv_mime_encode) ! 2054: { ! 2055: const char *field_name = NULL; ! 2056: int field_name_len; ! 2057: const char *field_value = NULL; ! 2058: int field_value_len; ! 2059: zval *pref = NULL; ! 2060: zval tmp_zv, *tmp_zv_p = NULL; ! 2061: smart_str retval = {0}; ! 2062: php_iconv_err_t err; ! 2063: ! 2064: const char *in_charset = ICONVG(internal_encoding); ! 2065: const char *out_charset = in_charset; ! 2066: long line_len = 76; ! 2067: const char *lfchars = "\r\n"; ! 2068: php_iconv_enc_scheme_t scheme_id = PHP_ICONV_ENC_SCHEME_BASE64; ! 2069: ! 2070: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a", ! 2071: &field_name, &field_name_len, &field_value, &field_value_len, ! 2072: &pref) == FAILURE) { ! 2073: ! 2074: RETURN_FALSE; ! 2075: } ! 2076: ! 2077: if (pref != NULL) { ! 2078: zval **ppval; ! 2079: ! 2080: if (zend_hash_find(Z_ARRVAL_P(pref), "scheme", sizeof("scheme"), (void **)&ppval) == SUCCESS) { ! 2081: if (Z_TYPE_PP(ppval) == IS_STRING && Z_STRLEN_PP(ppval) > 0) { ! 2082: switch (Z_STRVAL_PP(ppval)[0]) { ! 2083: case 'B': case 'b': ! 2084: scheme_id = PHP_ICONV_ENC_SCHEME_BASE64; ! 2085: break; ! 2086: ! 2087: case 'Q': case 'q': ! 2088: scheme_id = PHP_ICONV_ENC_SCHEME_QPRINT; ! 2089: break; ! 2090: } ! 2091: } ! 2092: } ! 2093: ! 2094: if (zend_hash_find(Z_ARRVAL_P(pref), "input-charset", sizeof("input-charset"), (void **)&ppval) == SUCCESS) { ! 2095: if (Z_STRLEN_PP(ppval) >= ICONV_CSNMAXLEN) { ! 2096: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN); ! 2097: RETURN_FALSE; ! 2098: } ! 2099: ! 2100: if (Z_TYPE_PP(ppval) == IS_STRING && Z_STRLEN_PP(ppval) > 0) { ! 2101: in_charset = Z_STRVAL_PP(ppval); ! 2102: } ! 2103: } ! 2104: ! 2105: ! 2106: if (zend_hash_find(Z_ARRVAL_P(pref), "output-charset", sizeof("output-charset"), (void **)&ppval) == SUCCESS) { ! 2107: if (Z_STRLEN_PP(ppval) >= ICONV_CSNMAXLEN) { ! 2108: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN); ! 2109: RETURN_FALSE; ! 2110: } ! 2111: ! 2112: if (Z_TYPE_PP(ppval) == IS_STRING && Z_STRLEN_PP(ppval) > 0) { ! 2113: out_charset = Z_STRVAL_PP(ppval); ! 2114: } ! 2115: } ! 2116: ! 2117: if (zend_hash_find(Z_ARRVAL_P(pref), "line-length", sizeof("line-length"), (void **)&ppval) == SUCCESS) { ! 2118: zval val, *pval = *ppval; ! 2119: ! 2120: if (Z_TYPE_P(pval) != IS_LONG) { ! 2121: val = *pval; ! 2122: zval_copy_ctor(&val); ! 2123: convert_to_long(&val); ! 2124: pval = &val; ! 2125: } ! 2126: ! 2127: line_len = Z_LVAL_P(pval); ! 2128: ! 2129: if (pval == &val) { ! 2130: zval_dtor(&val); ! 2131: } ! 2132: } ! 2133: ! 2134: if (zend_hash_find(Z_ARRVAL_P(pref), "line-break-chars", sizeof("line-break-chars"), (void **)&ppval) == SUCCESS) { ! 2135: if (Z_TYPE_PP(ppval) != IS_STRING) { ! 2136: tmp_zv = **ppval; ! 2137: zval_copy_ctor(&tmp_zv); ! 2138: convert_to_string(&tmp_zv); ! 2139: ! 2140: lfchars = Z_STRVAL(tmp_zv); ! 2141: ! 2142: tmp_zv_p = &tmp_zv; ! 2143: } else { ! 2144: lfchars = Z_STRVAL_PP(ppval); ! 2145: } ! 2146: } ! 2147: } ! 2148: ! 2149: err = _php_iconv_mime_encode(&retval, field_name, field_name_len, ! 2150: field_value, field_value_len, line_len, lfchars, scheme_id, ! 2151: out_charset, in_charset); ! 2152: _php_iconv_show_error(err, out_charset, in_charset TSRMLS_CC); ! 2153: ! 2154: if (err == PHP_ICONV_ERR_SUCCESS) { ! 2155: if (retval.c != NULL) { ! 2156: RETVAL_STRINGL(retval.c, retval.len, 0); ! 2157: } else { ! 2158: RETVAL_EMPTY_STRING(); ! 2159: } ! 2160: } else { ! 2161: smart_str_free(&retval); ! 2162: RETVAL_FALSE; ! 2163: } ! 2164: ! 2165: if (tmp_zv_p != NULL) { ! 2166: zval_dtor(tmp_zv_p); ! 2167: } ! 2168: } ! 2169: /* }}} */ ! 2170: ! 2171: /* {{{ proto string iconv_mime_decode(string encoded_string [, int mode, string charset]) ! 2172: Decodes a mime header field */ ! 2173: PHP_FUNCTION(iconv_mime_decode) ! 2174: { ! 2175: char *encoded_str; ! 2176: int encoded_str_len; ! 2177: char *charset = ICONVG(internal_encoding); ! 2178: int charset_len = 0; ! 2179: long mode = 0; ! 2180: ! 2181: smart_str retval = {0}; ! 2182: ! 2183: php_iconv_err_t err; ! 2184: ! 2185: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ls", ! 2186: &encoded_str, &encoded_str_len, &mode, &charset, &charset_len) == FAILURE) { ! 2187: ! 2188: RETURN_FALSE; ! 2189: } ! 2190: ! 2191: if (charset_len >= ICONV_CSNMAXLEN) { ! 2192: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN); ! 2193: RETURN_FALSE; ! 2194: } ! 2195: ! 2196: err = _php_iconv_mime_decode(&retval, encoded_str, encoded_str_len, charset, NULL, mode); ! 2197: _php_iconv_show_error(err, charset, "???" TSRMLS_CC); ! 2198: ! 2199: if (err == PHP_ICONV_ERR_SUCCESS) { ! 2200: if (retval.c != NULL) { ! 2201: RETVAL_STRINGL(retval.c, retval.len, 0); ! 2202: } else { ! 2203: RETVAL_EMPTY_STRING(); ! 2204: } ! 2205: } else { ! 2206: smart_str_free(&retval); ! 2207: RETVAL_FALSE; ! 2208: } ! 2209: } ! 2210: /* }}} */ ! 2211: ! 2212: /* {{{ proto array iconv_mime_decode_headers(string headers [, int mode, string charset]) ! 2213: Decodes multiple mime header fields */ ! 2214: PHP_FUNCTION(iconv_mime_decode_headers) ! 2215: { ! 2216: const char *encoded_str; ! 2217: int encoded_str_len; ! 2218: char *charset = ICONVG(internal_encoding); ! 2219: int charset_len = 0; ! 2220: long mode = 0; ! 2221: ! 2222: php_iconv_err_t err = PHP_ICONV_ERR_SUCCESS; ! 2223: ! 2224: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ls", ! 2225: &encoded_str, &encoded_str_len, &mode, &charset, &charset_len) == FAILURE) { ! 2226: ! 2227: RETURN_FALSE; ! 2228: } ! 2229: ! 2230: if (charset_len >= ICONV_CSNMAXLEN) { ! 2231: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN); ! 2232: RETURN_FALSE; ! 2233: } ! 2234: ! 2235: array_init(return_value); ! 2236: ! 2237: while (encoded_str_len > 0) { ! 2238: smart_str decoded_header = {0}; ! 2239: char *header_name = NULL; ! 2240: size_t header_name_len = 0; ! 2241: char *header_value = NULL; ! 2242: size_t header_value_len = 0; ! 2243: char *p, *limit; ! 2244: const char *next_pos; ! 2245: ! 2246: if (PHP_ICONV_ERR_SUCCESS != (err = _php_iconv_mime_decode(&decoded_header, encoded_str, encoded_str_len, charset, &next_pos, mode))) { ! 2247: smart_str_free(&decoded_header); ! 2248: break; ! 2249: } ! 2250: ! 2251: if (decoded_header.c == NULL) { ! 2252: break; ! 2253: } ! 2254: ! 2255: limit = decoded_header.c + decoded_header.len; ! 2256: for (p = decoded_header.c; p < limit; p++) { ! 2257: if (*p == ':') { ! 2258: *p = '\0'; ! 2259: header_name = decoded_header.c; ! 2260: header_name_len = (p - decoded_header.c) + 1; ! 2261: ! 2262: while (++p < limit) { ! 2263: if (*p != ' ' && *p != '\t') { ! 2264: break; ! 2265: } ! 2266: } ! 2267: ! 2268: header_value = p; ! 2269: header_value_len = limit - p; ! 2270: ! 2271: break; ! 2272: } ! 2273: } ! 2274: ! 2275: if (header_name != NULL) { ! 2276: zval **elem, *new_elem; ! 2277: ! 2278: if (zend_hash_find(Z_ARRVAL_P(return_value), header_name, header_name_len, (void **)&elem) == SUCCESS) { ! 2279: if (Z_TYPE_PP(elem) != IS_ARRAY) { ! 2280: MAKE_STD_ZVAL(new_elem); ! 2281: array_init(new_elem); ! 2282: ! 2283: Z_ADDREF_PP(elem); ! 2284: add_next_index_zval(new_elem, *elem); ! 2285: ! 2286: zend_hash_update(Z_ARRVAL_P(return_value), header_name, header_name_len, (void *)&new_elem, sizeof(new_elem), NULL); ! 2287: ! 2288: elem = &new_elem; ! 2289: } ! 2290: add_next_index_stringl(*elem, header_value, header_value_len, 1); ! 2291: } else { ! 2292: add_assoc_stringl_ex(return_value, header_name, header_name_len, header_value, header_value_len, 1); ! 2293: } ! 2294: } ! 2295: encoded_str_len -= next_pos - encoded_str; ! 2296: encoded_str = next_pos; ! 2297: ! 2298: smart_str_free(&decoded_header); ! 2299: } ! 2300: ! 2301: if (err != PHP_ICONV_ERR_SUCCESS) { ! 2302: _php_iconv_show_error(err, charset, "???" TSRMLS_CC); ! 2303: zval_dtor(return_value); ! 2304: RETVAL_FALSE; ! 2305: } ! 2306: } ! 2307: /* }}} */ ! 2308: ! 2309: /* {{{ proto string iconv(string in_charset, string out_charset, string str) ! 2310: Returns str converted to the out_charset character set */ ! 2311: PHP_NAMED_FUNCTION(php_if_iconv) ! 2312: { ! 2313: char *in_charset, *out_charset, *in_buffer, *out_buffer; ! 2314: size_t out_len; ! 2315: int in_charset_len = 0, out_charset_len = 0, in_buffer_len; ! 2316: php_iconv_err_t err; ! 2317: ! 2318: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss", ! 2319: &in_charset, &in_charset_len, &out_charset, &out_charset_len, &in_buffer, &in_buffer_len) == FAILURE) ! 2320: return; ! 2321: ! 2322: if (in_charset_len >= ICONV_CSNMAXLEN || out_charset_len >= ICONV_CSNMAXLEN) { ! 2323: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN); ! 2324: RETURN_FALSE; ! 2325: } ! 2326: ! 2327: err = php_iconv_string(in_buffer, (size_t)in_buffer_len, ! 2328: &out_buffer, &out_len, out_charset, in_charset); ! 2329: _php_iconv_show_error(err, out_charset, in_charset TSRMLS_CC); ! 2330: if (out_buffer != NULL) { ! 2331: RETVAL_STRINGL(out_buffer, out_len, 0); ! 2332: } else { ! 2333: RETURN_FALSE; ! 2334: } ! 2335: } ! 2336: /* }}} */ ! 2337: ! 2338: /* {{{ proto string ob_iconv_handler(string contents, int status) ! 2339: Returns str in output buffer converted to the iconv.output_encoding character set */ ! 2340: PHP_FUNCTION(ob_iconv_handler) ! 2341: { ! 2342: char *out_buffer, *content_type, *mimetype = NULL, *s; ! 2343: zval *zv_string; ! 2344: size_t out_len; ! 2345: int mimetype_alloced = 0; ! 2346: long status; ! 2347: ! 2348: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zl", &zv_string, &status) == FAILURE) ! 2349: return; ! 2350: ! 2351: convert_to_string(zv_string); ! 2352: ! 2353: if (SG(sapi_headers).mimetype && ! 2354: strncasecmp(SG(sapi_headers).mimetype, "text/", 5) == 0) { ! 2355: if ((s = strchr(SG(sapi_headers).mimetype,';')) == NULL){ ! 2356: mimetype = SG(sapi_headers).mimetype; ! 2357: } else { ! 2358: mimetype = estrndup(SG(sapi_headers).mimetype, s-SG(sapi_headers).mimetype); ! 2359: mimetype_alloced = 1; ! 2360: } ! 2361: } else if (SG(sapi_headers).send_default_content_type) { ! 2362: mimetype =(SG(default_mimetype) ? SG(default_mimetype) : SAPI_DEFAULT_MIMETYPE); ! 2363: } ! 2364: if (mimetype != NULL) { ! 2365: php_iconv_err_t err = php_iconv_string(Z_STRVAL_P(zv_string), ! 2366: Z_STRLEN_P(zv_string), &out_buffer, &out_len, ! 2367: ICONVG(output_encoding), ICONVG(internal_encoding)); ! 2368: _php_iconv_show_error(err, ICONVG(output_encoding), ICONVG(internal_encoding) TSRMLS_CC); ! 2369: if (out_buffer != NULL) { ! 2370: int len; ! 2371: char *p = strstr(ICONVG(output_encoding), "//"); ! 2372: if (p) { ! 2373: len = spprintf(&content_type, 0, "Content-Type:%s; charset=%.*s", mimetype, (int)(p - ICONVG(output_encoding)), ICONVG(output_encoding)); ! 2374: } else { ! 2375: len = spprintf(&content_type, 0, "Content-Type:%s; charset=%s", mimetype, ICONVG(output_encoding)); ! 2376: } ! 2377: if (content_type && sapi_add_header(content_type, len, 0) != FAILURE) { ! 2378: SG(sapi_headers).send_default_content_type = 0; ! 2379: } ! 2380: if (mimetype_alloced) { ! 2381: efree(mimetype); ! 2382: } ! 2383: RETURN_STRINGL(out_buffer, out_len, 0); ! 2384: } ! 2385: if (mimetype_alloced) { ! 2386: efree(mimetype); ! 2387: } ! 2388: } ! 2389: ! 2390: zval_dtor(return_value); ! 2391: *return_value = *zv_string; ! 2392: zval_copy_ctor(return_value); ! 2393: } ! 2394: /* }}} */ ! 2395: ! 2396: /* {{{ proto bool iconv_set_encoding(string type, string charset) ! 2397: Sets internal encoding and output encoding for ob_iconv_handler() */ ! 2398: PHP_FUNCTION(iconv_set_encoding) ! 2399: { ! 2400: char *type, *charset; ! 2401: int type_len, charset_len =0, retval; ! 2402: ! 2403: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &type, &type_len, &charset, &charset_len) == FAILURE) ! 2404: return; ! 2405: ! 2406: if (charset_len >= ICONV_CSNMAXLEN) { ! 2407: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN); ! 2408: RETURN_FALSE; ! 2409: } ! 2410: ! 2411: if(!strcasecmp("input_encoding", type)) { ! 2412: retval = zend_alter_ini_entry("iconv.input_encoding", sizeof("iconv.input_encoding"), charset, charset_len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME); ! 2413: } else if(!strcasecmp("output_encoding", type)) { ! 2414: retval = zend_alter_ini_entry("iconv.output_encoding", sizeof("iconv.output_encoding"), charset, charset_len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME); ! 2415: } else if(!strcasecmp("internal_encoding", type)) { ! 2416: retval = zend_alter_ini_entry("iconv.internal_encoding", sizeof("iconv.internal_encoding"), charset, charset_len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME); ! 2417: } else { ! 2418: RETURN_FALSE; ! 2419: } ! 2420: ! 2421: if (retval == SUCCESS) { ! 2422: RETURN_TRUE; ! 2423: } else { ! 2424: RETURN_FALSE; ! 2425: } ! 2426: } ! 2427: /* }}} */ ! 2428: ! 2429: /* {{{ proto mixed iconv_get_encoding([string type]) ! 2430: Get internal encoding and output encoding for ob_iconv_handler() */ ! 2431: PHP_FUNCTION(iconv_get_encoding) ! 2432: { ! 2433: char *type = "all"; ! 2434: int type_len = sizeof("all")-1; ! 2435: ! 2436: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &type, &type_len) == FAILURE) ! 2437: return; ! 2438: ! 2439: if (!strcasecmp("all", type)) { ! 2440: array_init(return_value); ! 2441: add_assoc_string(return_value, "input_encoding", ICONVG(input_encoding), 1); ! 2442: add_assoc_string(return_value, "output_encoding", ICONVG(output_encoding), 1); ! 2443: add_assoc_string(return_value, "internal_encoding", ICONVG(internal_encoding), 1); ! 2444: } else if (!strcasecmp("input_encoding", type)) { ! 2445: RETVAL_STRING(ICONVG(input_encoding), 1); ! 2446: } else if (!strcasecmp("output_encoding", type)) { ! 2447: RETVAL_STRING(ICONVG(output_encoding), 1); ! 2448: } else if (!strcasecmp("internal_encoding", type)) { ! 2449: RETVAL_STRING(ICONVG(internal_encoding), 1); ! 2450: } else { ! 2451: RETURN_FALSE; ! 2452: } ! 2453: ! 2454: } ! 2455: /* }}} */ ! 2456: ! 2457: /* {{{ iconv stream filter */ ! 2458: typedef struct _php_iconv_stream_filter { ! 2459: iconv_t cd; ! 2460: int persistent; ! 2461: char *to_charset; ! 2462: size_t to_charset_len; ! 2463: char *from_charset; ! 2464: size_t from_charset_len; ! 2465: char stub[128]; ! 2466: size_t stub_len; ! 2467: } php_iconv_stream_filter; ! 2468: /* }}} iconv stream filter */ ! 2469: ! 2470: /* {{{ php_iconv_stream_filter_dtor */ ! 2471: static void php_iconv_stream_filter_dtor(php_iconv_stream_filter *self) ! 2472: { ! 2473: iconv_close(self->cd); ! 2474: pefree(self->to_charset, self->persistent); ! 2475: pefree(self->from_charset, self->persistent); ! 2476: } ! 2477: /* }}} */ ! 2478: ! 2479: /* {{{ php_iconv_stream_filter_ctor() */ ! 2480: static php_iconv_err_t php_iconv_stream_filter_ctor(php_iconv_stream_filter *self, ! 2481: const char *to_charset, size_t to_charset_len, ! 2482: const char *from_charset, size_t from_charset_len, int persistent) ! 2483: { ! 2484: if (NULL == (self->to_charset = pemalloc(to_charset_len + 1, persistent))) { ! 2485: return PHP_ICONV_ERR_ALLOC; ! 2486: } ! 2487: self->to_charset_len = to_charset_len; ! 2488: if (NULL == (self->from_charset = pemalloc(from_charset_len + 1, persistent))) { ! 2489: pefree(self->to_charset, persistent); ! 2490: return PHP_ICONV_ERR_ALLOC; ! 2491: } ! 2492: self->from_charset_len = from_charset_len; ! 2493: ! 2494: memcpy(self->to_charset, to_charset, to_charset_len); ! 2495: self->to_charset[to_charset_len] = '\0'; ! 2496: memcpy(self->from_charset, from_charset, from_charset_len); ! 2497: self->from_charset[from_charset_len] = '\0'; ! 2498: ! 2499: if ((iconv_t)-1 == (self->cd = iconv_open(self->to_charset, self->from_charset))) { ! 2500: pefree(self->from_charset, persistent); ! 2501: pefree(self->to_charset, persistent); ! 2502: return PHP_ICONV_ERR_UNKNOWN; ! 2503: } ! 2504: self->persistent = persistent; ! 2505: self->stub_len = 0; ! 2506: return PHP_ICONV_ERR_SUCCESS; ! 2507: } ! 2508: /* }}} */ ! 2509: ! 2510: /* {{{ php_iconv_stream_filter_append_bucket */ ! 2511: static int php_iconv_stream_filter_append_bucket( ! 2512: php_iconv_stream_filter *self, ! 2513: php_stream *stream, php_stream_filter *filter, ! 2514: php_stream_bucket_brigade *buckets_out, ! 2515: const char *ps, size_t buf_len, size_t *consumed, ! 2516: int persistent TSRMLS_DC) ! 2517: { ! 2518: php_stream_bucket *new_bucket; ! 2519: char *out_buf = NULL; ! 2520: size_t out_buf_size; ! 2521: char *pd, *pt; ! 2522: size_t ocnt, prev_ocnt, icnt, tcnt; ! 2523: size_t initial_out_buf_size; ! 2524: ! 2525: if (ps == NULL) { ! 2526: initial_out_buf_size = 64; ! 2527: icnt = 1; ! 2528: } else { ! 2529: initial_out_buf_size = buf_len; ! 2530: icnt = buf_len; ! 2531: } ! 2532: ! 2533: out_buf_size = ocnt = prev_ocnt = initial_out_buf_size; ! 2534: if (NULL == (out_buf = pemalloc(out_buf_size, persistent))) { ! 2535: return FAILURE; ! 2536: } ! 2537: ! 2538: pd = out_buf; ! 2539: ! 2540: if (self->stub_len > 0) { ! 2541: pt = self->stub; ! 2542: tcnt = self->stub_len; ! 2543: ! 2544: while (tcnt > 0) { ! 2545: if (iconv(self->cd, &pt, &tcnt, &pd, &ocnt) == (size_t)-1) { ! 2546: #if ICONV_SUPPORTS_ERRNO ! 2547: switch (errno) { ! 2548: case EILSEQ: ! 2549: php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): invalid multibyte sequence", self->from_charset, self->to_charset); ! 2550: goto out_failure; ! 2551: ! 2552: case EINVAL: ! 2553: if (ps != NULL) { ! 2554: if (icnt > 0) { ! 2555: if (self->stub_len >= sizeof(self->stub)) { ! 2556: php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): insufficient buffer", self->from_charset, self->to_charset); ! 2557: goto out_failure; ! 2558: } ! 2559: self->stub[self->stub_len++] = *(ps++); ! 2560: icnt--; ! 2561: pt = self->stub; ! 2562: tcnt = self->stub_len; ! 2563: } else { ! 2564: tcnt = 0; ! 2565: break; ! 2566: } ! 2567: } ! 2568: break; ! 2569: ! 2570: case E2BIG: { ! 2571: char *new_out_buf; ! 2572: size_t new_out_buf_size; ! 2573: ! 2574: new_out_buf_size = out_buf_size << 1; ! 2575: ! 2576: if (new_out_buf_size < out_buf_size) { ! 2577: /* whoa! no bigger buckets are sold anywhere... */ ! 2578: if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) { ! 2579: goto out_failure; ! 2580: } ! 2581: ! 2582: php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC); ! 2583: ! 2584: out_buf_size = ocnt = initial_out_buf_size; ! 2585: if (NULL == (out_buf = pemalloc(out_buf_size, persistent))) { ! 2586: return FAILURE; ! 2587: } ! 2588: pd = out_buf; ! 2589: } else { ! 2590: if (NULL == (new_out_buf = perealloc(out_buf, new_out_buf_size, persistent))) { ! 2591: if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) { ! 2592: goto out_failure; ! 2593: } ! 2594: ! 2595: php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC); ! 2596: return FAILURE; ! 2597: } ! 2598: pd = new_out_buf + (pd - out_buf); ! 2599: ocnt += (new_out_buf_size - out_buf_size); ! 2600: out_buf = new_out_buf; ! 2601: out_buf_size = new_out_buf_size; ! 2602: } ! 2603: } break; ! 2604: ! 2605: default: ! 2606: php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): unknown error", self->from_charset, self->to_charset); ! 2607: goto out_failure; ! 2608: } ! 2609: #else ! 2610: if (ocnt == prev_ocnt) { ! 2611: php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): unknown error", self->from_charset, self->to_charset); ! 2612: goto out_failure; ! 2613: } ! 2614: #endif ! 2615: } ! 2616: prev_ocnt = ocnt; ! 2617: } ! 2618: memmove(self->stub, pt, tcnt); ! 2619: self->stub_len = tcnt; ! 2620: } ! 2621: ! 2622: while (icnt > 0) { ! 2623: if ((ps == NULL ? iconv(self->cd, NULL, NULL, &pd, &ocnt): ! 2624: iconv(self->cd, (char **)&ps, &icnt, &pd, &ocnt)) == (size_t)-1) { ! 2625: #if ICONV_SUPPORTS_ERRNO ! 2626: switch (errno) { ! 2627: case EILSEQ: ! 2628: php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): invalid multibyte sequence", self->from_charset, self->to_charset); ! 2629: goto out_failure; ! 2630: ! 2631: case EINVAL: ! 2632: if (ps != NULL) { ! 2633: if (icnt > sizeof(self->stub)) { ! 2634: php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): insufficient buffer", self->from_charset, self->to_charset); ! 2635: goto out_failure; ! 2636: } ! 2637: memcpy(self->stub, ps, icnt); ! 2638: self->stub_len = icnt; ! 2639: ps += icnt; ! 2640: icnt = 0; ! 2641: } else { ! 2642: php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): unexpected octet values", self->from_charset, self->to_charset); ! 2643: goto out_failure; ! 2644: } ! 2645: break; ! 2646: ! 2647: case E2BIG: { ! 2648: char *new_out_buf; ! 2649: size_t new_out_buf_size; ! 2650: ! 2651: new_out_buf_size = out_buf_size << 1; ! 2652: ! 2653: if (new_out_buf_size < out_buf_size) { ! 2654: /* whoa! no bigger buckets are sold anywhere... */ ! 2655: if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) { ! 2656: goto out_failure; ! 2657: } ! 2658: ! 2659: php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC); ! 2660: ! 2661: out_buf_size = ocnt = initial_out_buf_size; ! 2662: if (NULL == (out_buf = pemalloc(out_buf_size, persistent))) { ! 2663: return FAILURE; ! 2664: } ! 2665: pd = out_buf; ! 2666: } else { ! 2667: if (NULL == (new_out_buf = perealloc(out_buf, new_out_buf_size, persistent))) { ! 2668: if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) { ! 2669: goto out_failure; ! 2670: } ! 2671: ! 2672: php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC); ! 2673: return FAILURE; ! 2674: } ! 2675: pd = new_out_buf + (pd - out_buf); ! 2676: ocnt += (new_out_buf_size - out_buf_size); ! 2677: out_buf = new_out_buf; ! 2678: out_buf_size = new_out_buf_size; ! 2679: } ! 2680: } break; ! 2681: ! 2682: default: ! 2683: php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): unknown error", self->from_charset, self->to_charset); ! 2684: goto out_failure; ! 2685: } ! 2686: #else ! 2687: if (ocnt == prev_ocnt) { ! 2688: php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): unknown error", self->from_charset, self->to_charset); ! 2689: goto out_failure; ! 2690: } ! 2691: #endif ! 2692: } else { ! 2693: if (ps == NULL) { ! 2694: break; ! 2695: } ! 2696: } ! 2697: prev_ocnt = ocnt; ! 2698: } ! 2699: ! 2700: if (out_buf_size - ocnt > 0) { ! 2701: if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) { ! 2702: goto out_failure; ! 2703: } ! 2704: php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC); ! 2705: } else { ! 2706: pefree(out_buf, persistent); ! 2707: } ! 2708: *consumed += buf_len - icnt; ! 2709: ! 2710: return SUCCESS; ! 2711: ! 2712: out_failure: ! 2713: pefree(out_buf, persistent); ! 2714: return FAILURE; ! 2715: } ! 2716: /* }}} php_iconv_stream_filter_append_bucket */ ! 2717: ! 2718: /* {{{ php_iconv_stream_filter_do_filter */ ! 2719: static php_stream_filter_status_t php_iconv_stream_filter_do_filter( ! 2720: php_stream *stream, php_stream_filter *filter, ! 2721: php_stream_bucket_brigade *buckets_in, ! 2722: php_stream_bucket_brigade *buckets_out, ! 2723: size_t *bytes_consumed, int flags TSRMLS_DC) ! 2724: { ! 2725: php_stream_bucket *bucket = NULL; ! 2726: size_t consumed = 0; ! 2727: php_iconv_stream_filter *self = (php_iconv_stream_filter *)filter->abstract; ! 2728: ! 2729: while (buckets_in->head != NULL) { ! 2730: bucket = buckets_in->head; ! 2731: ! 2732: php_stream_bucket_unlink(bucket TSRMLS_CC); ! 2733: ! 2734: if (php_iconv_stream_filter_append_bucket(self, stream, filter, ! 2735: buckets_out, bucket->buf, bucket->buflen, &consumed, ! 2736: php_stream_is_persistent(stream) TSRMLS_CC) != SUCCESS) { ! 2737: goto out_failure; ! 2738: } ! 2739: ! 2740: php_stream_bucket_delref(bucket TSRMLS_CC); ! 2741: } ! 2742: ! 2743: if (flags != PSFS_FLAG_NORMAL) { ! 2744: if (php_iconv_stream_filter_append_bucket(self, stream, filter, ! 2745: buckets_out, NULL, 0, &consumed, ! 2746: php_stream_is_persistent(stream) TSRMLS_CC) != SUCCESS) { ! 2747: goto out_failure; ! 2748: } ! 2749: } ! 2750: ! 2751: if (bytes_consumed != NULL) { ! 2752: *bytes_consumed = consumed; ! 2753: } ! 2754: ! 2755: return PSFS_PASS_ON; ! 2756: ! 2757: out_failure: ! 2758: if (bucket != NULL) { ! 2759: php_stream_bucket_delref(bucket TSRMLS_CC); ! 2760: } ! 2761: return PSFS_ERR_FATAL; ! 2762: } ! 2763: /* }}} */ ! 2764: ! 2765: /* {{{ php_iconv_stream_filter_cleanup */ ! 2766: static void php_iconv_stream_filter_cleanup(php_stream_filter *filter TSRMLS_DC) ! 2767: { ! 2768: php_iconv_stream_filter_dtor((php_iconv_stream_filter *)filter->abstract); ! 2769: pefree(filter->abstract, ((php_iconv_stream_filter *)filter->abstract)->persistent); ! 2770: } ! 2771: /* }}} */ ! 2772: ! 2773: static php_stream_filter_ops php_iconv_stream_filter_ops = { ! 2774: php_iconv_stream_filter_do_filter, ! 2775: php_iconv_stream_filter_cleanup, ! 2776: "convert.iconv.*" ! 2777: }; ! 2778: ! 2779: /* {{{ php_iconv_stream_filter_create */ ! 2780: static php_stream_filter *php_iconv_stream_filter_factory_create(const char *name, zval *params, int persistent TSRMLS_DC) ! 2781: { ! 2782: php_stream_filter *retval = NULL; ! 2783: php_iconv_stream_filter *inst; ! 2784: char *from_charset = NULL, *to_charset = NULL; ! 2785: size_t from_charset_len, to_charset_len; ! 2786: ! 2787: if ((from_charset = strchr(name, '.')) == NULL) { ! 2788: return NULL; ! 2789: } ! 2790: ++from_charset; ! 2791: if ((from_charset = strchr(from_charset, '.')) == NULL) { ! 2792: return NULL; ! 2793: } ! 2794: ++from_charset; ! 2795: if ((to_charset = strpbrk(from_charset, "/.")) == NULL) { ! 2796: return NULL; ! 2797: } ! 2798: from_charset_len = to_charset - from_charset; ! 2799: ++to_charset; ! 2800: to_charset_len = strlen(to_charset); ! 2801: ! 2802: if (from_charset_len >= ICONV_CSNMAXLEN || to_charset_len >= ICONV_CSNMAXLEN) { ! 2803: return NULL; ! 2804: } ! 2805: ! 2806: if (NULL == (inst = pemalloc(sizeof(php_iconv_stream_filter), persistent))) { ! 2807: return NULL; ! 2808: } ! 2809: ! 2810: if (php_iconv_stream_filter_ctor(inst, to_charset, to_charset_len, from_charset, from_charset_len, persistent) != PHP_ICONV_ERR_SUCCESS) { ! 2811: pefree(inst, persistent); ! 2812: return NULL; ! 2813: } ! 2814: ! 2815: if (NULL == (retval = php_stream_filter_alloc(&php_iconv_stream_filter_ops, inst, persistent))) { ! 2816: php_iconv_stream_filter_dtor(inst); ! 2817: pefree(inst, persistent); ! 2818: } ! 2819: ! 2820: return retval; ! 2821: } ! 2822: /* }}} */ ! 2823: ! 2824: /* {{{ php_iconv_stream_register_factory */ ! 2825: static php_iconv_err_t php_iconv_stream_filter_register_factory(TSRMLS_D) ! 2826: { ! 2827: static php_stream_filter_factory filter_factory = { ! 2828: php_iconv_stream_filter_factory_create ! 2829: }; ! 2830: ! 2831: if (FAILURE == php_stream_filter_register_factory( ! 2832: php_iconv_stream_filter_ops.label, ! 2833: &filter_factory TSRMLS_CC)) { ! 2834: return PHP_ICONV_ERR_UNKNOWN; ! 2835: } ! 2836: return PHP_ICONV_ERR_SUCCESS; ! 2837: } ! 2838: /* }}} */ ! 2839: ! 2840: /* {{{ php_iconv_stream_unregister_factory */ ! 2841: static php_iconv_err_t php_iconv_stream_filter_unregister_factory(TSRMLS_D) ! 2842: { ! 2843: if (FAILURE == php_stream_filter_unregister_factory( ! 2844: php_iconv_stream_filter_ops.label TSRMLS_CC)) { ! 2845: return PHP_ICONV_ERR_UNKNOWN; ! 2846: } ! 2847: return PHP_ICONV_ERR_SUCCESS; ! 2848: } ! 2849: /* }}} */ ! 2850: /* }}} */ ! 2851: #endif ! 2852: ! 2853: /* ! 2854: * Local variables: ! 2855: * tab-width: 4 ! 2856: * c-basic-offset: 4 ! 2857: * End: ! 2858: * vim600: sw=4 ts=4 fdm=marker ! 2859: * vim<600: sw=4 ts=4 ! 2860: */