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