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