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