This source file includes following definitions.
- ZEND_GET_MODULE
- 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 "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
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 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
171 static PHP_GINIT_FUNCTION(iconv)
172 {
173 iconv_globals->input_encoding = NULL;
174 iconv_globals->output_encoding = NULL;
175 iconv_globals->internal_encoding = NULL;
176 }
177
178
179 #if defined(HAVE_LIBICONV) && defined(ICONV_ALIASED_LIBICONV)
180 #define iconv libiconv
181 #endif
182
183
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
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(const char *handler_name, size_t handler_name_len TSRMLS_DC);
213 static php_output_handler *php_iconv_output_handler_init(const char *name, size_t name_len, size_t chunk_size, int flags TSRMLS_DC);
214 static int php_iconv_output_handler(void **nothing, php_output_context *output_context);
215
216
217
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
224 static PHP_INI_MH(OnUpdateInputEncoding)
225 {
226 if (new_value_length >= ICONV_CSNMAXLEN) {
227 return FAILURE;
228 }
229 if (stage & (PHP_INI_STAGE_ACTIVATE | PHP_INI_STAGE_RUNTIME)) {
230 php_error_docref("ref.iconv" TSRMLS_CC, E_DEPRECATED, "Use of iconv.input_encoding is deprecated");
231 }
232 OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
233 return SUCCESS;
234 }
235
236
237 static PHP_INI_MH(OnUpdateOutputEncoding)
238 {
239 if(new_value_length >= ICONV_CSNMAXLEN) {
240 return FAILURE;
241 }
242 if (stage & (PHP_INI_STAGE_ACTIVATE | PHP_INI_STAGE_RUNTIME)) {
243 php_error_docref("ref.iconv" TSRMLS_CC, E_DEPRECATED, "Use of iconv.output_encoding is deprecated");
244 }
245 OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
246 return SUCCESS;
247 }
248
249
250 static PHP_INI_MH(OnUpdateInternalEncoding)
251 {
252 if(new_value_length >= ICONV_CSNMAXLEN) {
253 return FAILURE;
254 }
255 if (stage & (PHP_INI_STAGE_ACTIVATE | PHP_INI_STAGE_RUNTIME)) {
256 php_error_docref("ref.iconv" TSRMLS_CC, E_DEPRECATED, "Use of iconv.internal_encoding is deprecated");
257 }
258 OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
259 return SUCCESS;
260 }
261
262
263
264
265 PHP_INI_BEGIN()
266 STD_PHP_INI_ENTRY("iconv.input_encoding", "", PHP_INI_ALL, OnUpdateInputEncoding, input_encoding, zend_iconv_globals, iconv_globals)
267 STD_PHP_INI_ENTRY("iconv.output_encoding", "", PHP_INI_ALL, OnUpdateOutputEncoding, output_encoding, zend_iconv_globals, iconv_globals)
268 STD_PHP_INI_ENTRY("iconv.internal_encoding", "", PHP_INI_ALL, OnUpdateInternalEncoding, internal_encoding, zend_iconv_globals, iconv_globals)
269 PHP_INI_END()
270
271
272
273 PHP_MINIT_FUNCTION(miconv)
274 {
275 char *version = "unknown";
276
277 REGISTER_INI_ENTRIES();
278
279 #if HAVE_LIBICONV
280 {
281 static char buf[16];
282 snprintf(buf, sizeof(buf), "%d.%d",
283 ((_libiconv_version >> 8) & 0x0f), (_libiconv_version & 0x0f));
284 version = buf;
285 }
286 #elif HAVE_GLIBC_ICONV
287 version = (char *)gnu_get_libc_version();
288 #elif defined(NETWARE)
289 version = "OS built-in";
290 #endif
291
292 #ifdef PHP_ICONV_IMPL
293 REGISTER_STRING_CONSTANT("ICONV_IMPL", PHP_ICONV_IMPL, CONST_CS | CONST_PERSISTENT);
294 #elif HAVE_LIBICONV
295 REGISTER_STRING_CONSTANT("ICONV_IMPL", "libiconv", CONST_CS | CONST_PERSISTENT);
296 #elif defined(NETWARE)
297 REGISTER_STRING_CONSTANT("ICONV_IMPL", "Novell", CONST_CS | CONST_PERSISTENT);
298 #else
299 REGISTER_STRING_CONSTANT("ICONV_IMPL", "unknown", CONST_CS | CONST_PERSISTENT);
300 #endif
301 REGISTER_STRING_CONSTANT("ICONV_VERSION", version, CONST_CS | CONST_PERSISTENT);
302
303 REGISTER_LONG_CONSTANT("ICONV_MIME_DECODE_STRICT", PHP_ICONV_MIME_DECODE_STRICT, CONST_CS | CONST_PERSISTENT);
304 REGISTER_LONG_CONSTANT("ICONV_MIME_DECODE_CONTINUE_ON_ERROR", PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR, CONST_CS | CONST_PERSISTENT);
305
306 if (php_iconv_stream_filter_register_factory(TSRMLS_C) != PHP_ICONV_ERR_SUCCESS) {
307 return FAILURE;
308 }
309
310 php_output_handler_alias_register(ZEND_STRL("ob_iconv_handler"), php_iconv_output_handler_init TSRMLS_CC);
311 php_output_handler_conflict_register(ZEND_STRL("ob_iconv_handler"), php_iconv_output_conflict TSRMLS_CC);
312
313 return SUCCESS;
314 }
315
316
317
318 PHP_MSHUTDOWN_FUNCTION(miconv)
319 {
320 php_iconv_stream_filter_unregister_factory(TSRMLS_C);
321 UNREGISTER_INI_ENTRIES();
322 return SUCCESS;
323 }
324
325
326
327 PHP_MINFO_FUNCTION(miconv)
328 {
329 zval iconv_impl, iconv_ver;
330
331 zend_get_constant("ICONV_IMPL", sizeof("ICONV_IMPL")-1, &iconv_impl TSRMLS_CC);
332 zend_get_constant("ICONV_VERSION", sizeof("ICONV_VERSION")-1, &iconv_ver TSRMLS_CC);
333
334 php_info_print_table_start();
335 php_info_print_table_row(2, "iconv support", "enabled");
336 php_info_print_table_row(2, "iconv implementation", Z_STRVAL(iconv_impl));
337 php_info_print_table_row(2, "iconv library version", Z_STRVAL(iconv_ver));
338 php_info_print_table_end();
339
340 DISPLAY_INI_ENTRIES();
341
342 zval_dtor(&iconv_impl);
343 zval_dtor(&iconv_ver);
344 }
345
346
347 static char *get_internal_encoding(TSRMLS_D) {
348 if (ICONVG(internal_encoding) && ICONVG(internal_encoding)[0]) {
349 return ICONVG(internal_encoding);
350 } else if (PG(internal_encoding) && PG(internal_encoding)[0]) {
351 return PG(internal_encoding);
352 } else if (SG(default_charset)) {
353 return SG(default_charset);
354 }
355 return "";
356 }
357
358 static char *get_input_encoding(TSRMLS_D) {
359 if (ICONVG(input_encoding) && ICONVG(input_encoding)[0]) {
360 return ICONVG(input_encoding);
361 } else if (PG(input_encoding) && PG(input_encoding)[0]) {
362 return PG(input_encoding);
363 } else if (SG(default_charset)) {
364 return SG(default_charset);
365 }
366 return "";
367 }
368
369 static char *get_output_encoding(TSRMLS_D) {
370 if (ICONVG(output_encoding) && ICONVG(output_encoding)[0]) {
371 return ICONVG(output_encoding);
372 } else if (PG(output_encoding) && PG(output_encoding)[0]) {
373 return PG(output_encoding);
374 } else if (SG(default_charset)) {
375 return SG(default_charset);
376 }
377 return "";
378 }
379
380
381 static int php_iconv_output_conflict(const char *handler_name, size_t handler_name_len TSRMLS_DC)
382 {
383 if (php_output_get_level(TSRMLS_C)) {
384 if (php_output_handler_conflict(handler_name, handler_name_len, ZEND_STRL("ob_iconv_handler") TSRMLS_CC)
385 || php_output_handler_conflict(handler_name, handler_name_len, ZEND_STRL("mb_output_handler") TSRMLS_CC)) {
386 return FAILURE;
387 }
388 }
389 return SUCCESS;
390 }
391
392 static php_output_handler *php_iconv_output_handler_init(const char *handler_name, size_t handler_name_len, size_t chunk_size, int flags TSRMLS_DC)
393 {
394 return php_output_handler_create_internal(handler_name, handler_name_len, php_iconv_output_handler, chunk_size, flags TSRMLS_CC);
395 }
396
397 static int php_iconv_output_handler(void **nothing, php_output_context *output_context)
398 {
399 char *s, *content_type, *mimetype = NULL;
400 int output_status, mimetype_len = 0;
401 PHP_OUTPUT_TSRMLS(output_context);
402
403 if (output_context->op & PHP_OUTPUT_HANDLER_START) {
404 output_status = php_output_get_status(TSRMLS_C);
405 if (output_status & PHP_OUTPUT_SENT) {
406 return FAILURE;
407 }
408
409 if (SG(sapi_headers).mimetype && !strncasecmp(SG(sapi_headers).mimetype, "text/", 5)) {
410 if ((s = strchr(SG(sapi_headers).mimetype,';')) == NULL){
411 mimetype = SG(sapi_headers).mimetype;
412 } else {
413 mimetype = SG(sapi_headers).mimetype;
414 mimetype_len = s - SG(sapi_headers).mimetype;
415 }
416 } else if (SG(sapi_headers).send_default_content_type) {
417 mimetype = SG(default_mimetype) ? SG(default_mimetype) : SAPI_DEFAULT_MIMETYPE;
418 }
419
420 if (mimetype != NULL && !(output_context->op & PHP_OUTPUT_HANDLER_CLEAN)) {
421 int len;
422 char *p = strstr(get_output_encoding(TSRMLS_C), "//");
423
424 if (p) {
425 len = spprintf(&content_type, 0, "Content-Type:%.*s; charset=%.*s", mimetype_len ? mimetype_len : (int) strlen(mimetype), mimetype, (int)(p - get_output_encoding(TSRMLS_C)), get_output_encoding(TSRMLS_C));
426 } else {
427 len = spprintf(&content_type, 0, "Content-Type:%.*s; charset=%s", mimetype_len ? mimetype_len : (int) strlen(mimetype), mimetype, get_output_encoding(TSRMLS_C));
428 }
429 if (content_type && SUCCESS == sapi_add_header(content_type, len, 0)) {
430 SG(sapi_headers).send_default_content_type = 0;
431 php_output_handler_hook(PHP_OUTPUT_HANDLER_HOOK_IMMUTABLE, NULL TSRMLS_CC);
432 }
433 }
434 }
435
436 if (output_context->in.used) {
437 output_context->out.free = 1;
438 _php_iconv_show_error(php_iconv_string(output_context->in.data, output_context->in.used, &output_context->out.data, &output_context->out.used, get_output_encoding(TSRMLS_C), get_internal_encoding(TSRMLS_C)), get_output_encoding(TSRMLS_C), get_internal_encoding(TSRMLS_C) TSRMLS_CC);
439 }
440
441 return SUCCESS;
442 }
443
444
445 static php_iconv_err_t _php_iconv_appendl(smart_str *d, const char *s, size_t l, iconv_t cd)
446 {
447 const char *in_p = s;
448 size_t in_left = l;
449 char *out_p;
450 size_t out_left = 0;
451 size_t buf_growth = 128;
452 #if !ICONV_SUPPORTS_ERRNO
453 size_t prev_in_left = in_left;
454 #endif
455
456 if (in_p != NULL) {
457 while (in_left > 0) {
458 out_left = buf_growth - out_left;
459 {
460 size_t newlen;
461 smart_str_alloc((d), out_left, 0);
462 }
463
464 out_p = (d)->c + (d)->len;
465
466 if (iconv(cd, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) {
467 #if ICONV_SUPPORTS_ERRNO
468 switch (errno) {
469 case EINVAL:
470 return PHP_ICONV_ERR_ILLEGAL_CHAR;
471
472 case EILSEQ:
473 return PHP_ICONV_ERR_ILLEGAL_SEQ;
474
475 case E2BIG:
476 break;
477
478 default:
479 return PHP_ICONV_ERR_UNKNOWN;
480 }
481 #else
482 if (prev_in_left == in_left) {
483 return PHP_ICONV_ERR_UNKNOWN;
484 }
485 #endif
486 }
487 #if !ICONV_SUPPORTS_ERRNO
488 prev_in_left = in_left;
489 #endif
490 (d)->len += (buf_growth - out_left);
491 buf_growth <<= 1;
492 }
493 } else {
494 for (;;) {
495 out_left = buf_growth - out_left;
496 {
497 size_t newlen;
498 smart_str_alloc((d), out_left, 0);
499 }
500
501 out_p = (d)->c + (d)->len;
502
503 if (iconv(cd, NULL, NULL, (char **) &out_p, &out_left) == (size_t)0) {
504 (d)->len += (buf_growth - out_left);
505 break;
506 } else {
507 #if ICONV_SUPPORTS_ERRNO
508 if (errno != E2BIG) {
509 return PHP_ICONV_ERR_UNKNOWN;
510 }
511 #else
512 if (out_left != 0) {
513 return PHP_ICONV_ERR_UNKNOWN;
514 }
515 #endif
516 }
517 (d)->len += (buf_growth - out_left);
518 buf_growth <<= 1;
519 }
520 }
521 return PHP_ICONV_ERR_SUCCESS;
522 }
523
524
525
526 static php_iconv_err_t _php_iconv_appendc(smart_str *d, const char c, iconv_t cd)
527 {
528 return _php_iconv_appendl(d, &c, 1, cd);
529 }
530
531
532
533 #if ICONV_BROKEN_IGNORE
534 static int _php_check_ignore(const char *charset)
535 {
536 size_t clen = strlen(charset);
537 if (clen >= 9 && strcmp("//IGNORE", charset+clen-8) == 0) {
538 return 1;
539 }
540 if (clen >= 19 && strcmp("//IGNORE//TRANSLIT", charset+clen-18) == 0) {
541 return 1;
542 }
543 return 0;
544 }
545 #else
546 #define _php_check_ignore(x) (0)
547 #endif
548
549
550
551
552 PHP_ICONV_API php_iconv_err_t php_iconv_string(const char *in_p, size_t in_len,
553 char **out, size_t *out_len,
554 const char *out_charset, const char *in_charset)
555 {
556 #if !ICONV_SUPPORTS_ERRNO
557 size_t in_size, out_size, out_left;
558 char *out_buffer, *out_p;
559 iconv_t cd;
560 size_t result;
561
562 *out = NULL;
563 *out_len = 0;
564
565
566
567
568
569
570
571
572 out_size = in_len * sizeof(int) + 15;
573 out_left = out_size;
574
575 in_size = in_len;
576
577 cd = iconv_open(out_charset, in_charset);
578
579 if (cd == (iconv_t)(-1)) {
580 return PHP_ICONV_ERR_UNKNOWN;
581 }
582
583 out_buffer = (char *) emalloc(out_size + 1);
584 out_p = out_buffer;
585
586 #ifdef NETWARE
587 result = iconv(cd, (char **) &in_p, &in_size, (char **)
588 #else
589 result = iconv(cd, (const char **) &in_p, &in_size, (char **)
590 #endif
591 &out_p, &out_left);
592
593 if (result == (size_t)(-1)) {
594 efree(out_buffer);
595 return PHP_ICONV_ERR_UNKNOWN;
596 }
597
598 if (out_left < 8) {
599 size_t pos = out_p - out_buffer;
600 out_buffer = (char *) safe_erealloc(out_buffer, out_size, 1, 8);
601 out_p = out_buffer+pos;
602 out_size += 7;
603 out_left += 7;
604 }
605
606
607 result = iconv(cd, NULL, NULL, &out_p, &out_left);
608
609 if (result == (size_t)(-1)) {
610 efree(out_buffer);
611 return PHP_ICONV_ERR_UNKNOWN;
612 }
613
614 *out_len = out_size - out_left;
615 out_buffer[*out_len] = '\0';
616 *out = out_buffer;
617
618 iconv_close(cd);
619
620 return PHP_ICONV_ERR_SUCCESS;
621
622 #else
623
624
625
626 iconv_t cd;
627 size_t in_left, out_size, out_left;
628 char *out_p, *out_buf, *tmp_buf;
629 size_t bsz, result = 0;
630 php_iconv_err_t retval = PHP_ICONV_ERR_SUCCESS;
631 int ignore_ilseq = _php_check_ignore(out_charset);
632
633 *out = NULL;
634 *out_len = 0;
635
636 cd = iconv_open(out_charset, in_charset);
637
638 if (cd == (iconv_t)(-1)) {
639 if (errno == EINVAL) {
640 return PHP_ICONV_ERR_WRONG_CHARSET;
641 } else {
642 return PHP_ICONV_ERR_CONVERTER;
643 }
644 }
645 in_left= in_len;
646 out_left = in_len + 32;
647 out_size = 0;
648 bsz = out_left;
649 out_buf = (char *) emalloc(bsz+1);
650 out_p = out_buf;
651
652 while (in_left > 0) {
653 result = iconv(cd, (char **) &in_p, &in_left, (char **) &out_p, &out_left);
654 out_size = bsz - out_left;
655 if (result == (size_t)(-1)) {
656 if (ignore_ilseq && errno == EILSEQ) {
657 if (in_left <= 1) {
658 result = 0;
659 } else {
660 errno = 0;
661 in_p++;
662 in_left--;
663 continue;
664 }
665 }
666
667 if (errno == E2BIG && in_left > 0) {
668
669 bsz += in_len;
670
671 tmp_buf = (char*) erealloc(out_buf, bsz+1);
672 out_p = out_buf = tmp_buf;
673 out_p += out_size;
674 out_left = bsz - out_size;
675 continue;
676 }
677 }
678 break;
679 }
680
681 if (result != (size_t)(-1)) {
682
683 for (;;) {
684 result = iconv(cd, NULL, NULL, (char **) &out_p, &out_left);
685 out_size = bsz - out_left;
686
687 if (result != (size_t)(-1)) {
688 break;
689 }
690
691 if (errno == E2BIG) {
692 bsz += 16;
693 tmp_buf = (char *) erealloc(out_buf, bsz);
694
695 out_p = out_buf = tmp_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 efree(out_buf);
725 return PHP_ICONV_ERR_UNKNOWN;
726 }
727 }
728 *out_p = '\0';
729 *out = out_buf;
730 *out_len = out_size;
731 return retval;
732 #endif
733 }
734
735
736
737 static php_iconv_err_t _php_iconv_strlen(unsigned int *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 unsigned int cnt;
752
753 *pretval = (unsigned int)-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 = out_left = 0;
770
771 for (in_p = str, in_left = nbytes, cnt = 0; in_left > 0; cnt+=2) {
772 size_t prev_in_left;
773 out_p = buf;
774 out_left = sizeof(buf);
775
776 prev_in_left = in_left;
777
778 if (iconv(cd, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) {
779 if (prev_in_left == in_left) {
780 break;
781 }
782 }
783 }
784
785 if (out_left > 0) {
786 cnt -= out_left / GENERIC_SUPERSET_NBYTES;
787 }
788
789 #if ICONV_SUPPORTS_ERRNO
790 switch (errno) {
791 case EINVAL:
792 err = PHP_ICONV_ERR_ILLEGAL_CHAR;
793 break;
794
795 case EILSEQ:
796 err = PHP_ICONV_ERR_ILLEGAL_SEQ;
797 break;
798
799 case E2BIG:
800 case 0:
801 *pretval = cnt;
802 break;
803
804 default:
805 err = PHP_ICONV_ERR_UNKNOWN;
806 break;
807 }
808 #else
809 *pretval = cnt;
810 #endif
811
812 iconv_close(cd);
813
814 return err;
815 }
816
817
818
819
820 static php_iconv_err_t _php_iconv_substr(smart_str *pretval,
821 const char *str, size_t nbytes, int offset, int len, const char *enc)
822 {
823 char buf[GENERIC_SUPERSET_NBYTES];
824
825 php_iconv_err_t err = PHP_ICONV_ERR_SUCCESS;
826
827 iconv_t cd1, cd2;
828
829 const char *in_p;
830 size_t in_left;
831
832 char *out_p;
833 size_t out_left;
834
835 unsigned int cnt;
836 int total_len;
837
838 err = _php_iconv_strlen(&total_len, str, nbytes, enc);
839 if (err != PHP_ICONV_ERR_SUCCESS) {
840 return err;
841 }
842
843 if (len < 0) {
844 if ((len += (total_len - offset)) < 0) {
845 return PHP_ICONV_ERR_SUCCESS;
846 }
847 }
848
849 if (offset < 0) {
850 if ((offset += total_len) < 0) {
851 return PHP_ICONV_ERR_SUCCESS;
852 }
853 }
854
855 if(len > total_len) {
856 len = total_len;
857 }
858
859
860 if (offset >= total_len) {
861 return PHP_ICONV_ERR_SUCCESS;
862 }
863
864 if ((offset + len) > total_len ) {
865
866 len = total_len - offset;
867 }
868
869 if (len == 0) {
870 smart_str_appendl(pretval, "", 0);
871 smart_str_0(pretval);
872 return PHP_ICONV_ERR_SUCCESS;
873 }
874
875 cd1 = iconv_open(GENERIC_SUPERSET_NAME, enc);
876
877 if (cd1 == (iconv_t)(-1)) {
878 #if ICONV_SUPPORTS_ERRNO
879 if (errno == EINVAL) {
880 return PHP_ICONV_ERR_WRONG_CHARSET;
881 } else {
882 return PHP_ICONV_ERR_CONVERTER;
883 }
884 #else
885 return PHP_ICONV_ERR_UNKNOWN;
886 #endif
887 }
888
889 cd2 = (iconv_t)NULL;
890 errno = 0;
891
892 for (in_p = str, in_left = nbytes, cnt = 0; in_left > 0 && len > 0; ++cnt) {
893 size_t prev_in_left;
894 out_p = buf;
895 out_left = sizeof(buf);
896
897 prev_in_left = in_left;
898
899 if (iconv(cd1, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) {
900 if (prev_in_left == in_left) {
901 break;
902 }
903 }
904
905 if (cnt >= (unsigned int)offset) {
906 if (cd2 == (iconv_t)NULL) {
907 cd2 = iconv_open(enc, GENERIC_SUPERSET_NAME);
908
909 if (cd2 == (iconv_t)(-1)) {
910 cd2 = (iconv_t)NULL;
911 #if ICONV_SUPPORTS_ERRNO
912 if (errno == EINVAL) {
913 err = PHP_ICONV_ERR_WRONG_CHARSET;
914 } else {
915 err = PHP_ICONV_ERR_CONVERTER;
916 }
917 #else
918 err = PHP_ICONV_ERR_UNKNOWN;
919 #endif
920 break;
921 }
922 }
923
924 if (_php_iconv_appendl(pretval, buf, sizeof(buf), cd2) != PHP_ICONV_ERR_SUCCESS) {
925 break;
926 }
927 --len;
928 }
929
930 }
931
932 #if ICONV_SUPPORTS_ERRNO
933 switch (errno) {
934 case EINVAL:
935 err = PHP_ICONV_ERR_ILLEGAL_CHAR;
936 break;
937
938 case EILSEQ:
939 err = PHP_ICONV_ERR_ILLEGAL_SEQ;
940 break;
941
942 case E2BIG:
943 break;
944 }
945 #endif
946 if (err == PHP_ICONV_ERR_SUCCESS) {
947 if (cd2 != (iconv_t)NULL) {
948 _php_iconv_appendl(pretval, NULL, 0, cd2);
949 }
950 smart_str_0(pretval);
951 }
952
953 if (cd1 != (iconv_t)NULL) {
954 iconv_close(cd1);
955 }
956
957 if (cd2 != (iconv_t)NULL) {
958 iconv_close(cd2);
959 }
960 return err;
961 }
962
963
964
965
966 static php_iconv_err_t _php_iconv_strpos(unsigned int *pretval,
967 const char *haystk, size_t haystk_nbytes,
968 const char *ndl, size_t ndl_nbytes,
969 int offset, const char *enc)
970 {
971 char buf[GENERIC_SUPERSET_NBYTES];
972
973 php_iconv_err_t err = PHP_ICONV_ERR_SUCCESS;
974
975 iconv_t cd;
976
977 const char *in_p;
978 size_t in_left;
979
980 char *out_p;
981 size_t out_left;
982
983 unsigned int cnt;
984
985 char *ndl_buf;
986 const char *ndl_buf_p;
987 size_t ndl_buf_len, ndl_buf_left;
988
989 unsigned int match_ofs;
990
991 *pretval = (unsigned int)-1;
992
993 err = php_iconv_string(ndl, ndl_nbytes,
994 &ndl_buf, &ndl_buf_len, GENERIC_SUPERSET_NAME, enc);
995
996 if (err != PHP_ICONV_ERR_SUCCESS) {
997 if (ndl_buf != NULL) {
998 efree(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 efree(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 = ndl_buf;
1021 ndl_buf_left = ndl_buf_len;
1022 match_ofs = (unsigned int)-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 >= (unsigned int)offset) {
1056 if (_php_iconv_memequal(buf, ndl_buf_p, sizeof(buf))) {
1057 if (match_ofs == (unsigned int)-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 unsigned int i, j, lim;
1068
1069 i = 0;
1070 j = GENERIC_SUPERSET_NBYTES;
1071 lim = (unsigned int)(ndl_buf_p - ndl_buf);
1072
1073 while (j < lim) {
1074 if (_php_iconv_memequal(&ndl_buf[j], &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, &ndl_buf[i], sizeof(buf))) {
1085 match_ofs += (lim - i) / GENERIC_SUPERSET_NBYTES;
1086 i += GENERIC_SUPERSET_NBYTES;
1087 ndl_buf_p = &ndl_buf[i];
1088 ndl_buf_left = ndl_buf_len - i;
1089 } else {
1090 match_ofs = (unsigned int)-1;
1091 ndl_buf_p = ndl_buf;
1092 ndl_buf_left = ndl_buf_len;
1093 }
1094 }
1095 }
1096 } else {
1097 if (_php_iconv_memequal(buf, ndl_buf_p, sizeof(buf))) {
1098 if (match_ofs == (unsigned int)-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 = ndl_buf;
1106 ndl_buf_left = ndl_buf_len;
1107 match_ofs = -1;
1108 }
1109 } else {
1110 unsigned int i, j, lim;
1111
1112 i = 0;
1113 j = GENERIC_SUPERSET_NBYTES;
1114 lim = (unsigned int)(ndl_buf_p - ndl_buf);
1115
1116 while (j < lim) {
1117 if (_php_iconv_memequal(&ndl_buf[j], &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, &ndl_buf[i], sizeof(buf))) {
1128 match_ofs += (lim - i) / GENERIC_SUPERSET_NBYTES;
1129 i += GENERIC_SUPERSET_NBYTES;
1130 ndl_buf_p = &ndl_buf[i];
1131 ndl_buf_left = ndl_buf_len - i;
1132 } else {
1133 match_ofs = (unsigned int)-1;
1134 ndl_buf_p = ndl_buf;
1135 ndl_buf_left = ndl_buf_len;
1136 }
1137 }
1138 }
1139 }
1140
1141 if (ndl_buf) {
1142 efree(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, unsigned int 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 unsigned int char_cnt = 0;
1157 size_t out_charset_len;
1158 size_t lfchars_len;
1159 char *buf = NULL;
1160 char *encoded = NULL;
1161 size_t encoded_len;
1162 const char *in_p;
1163 size_t in_left;
1164 char *out_p;
1165 size_t out_left;
1166 static int qp_table[256] = {
1167 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
1168 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
1169 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1170 1, 1, 1, 1, 1, 1, 1 ,1, 1, 1, 1, 1, 1, 3, 1, 3,
1171 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1172 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3,
1173 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1174 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
1183 };
1184
1185 out_charset_len = strlen(out_charset);
1186 lfchars_len = strlen(lfchars);
1187
1188 if ((fname_nbytes + 2) >= max_line_len
1189 || (out_charset_len + 12) >= max_line_len) {
1190
1191 err = PHP_ICONV_ERR_TOO_BIG;
1192 goto out;
1193 }
1194
1195 cd_pl = iconv_open(ICONV_ASCII_ENCODING, enc);
1196 if (cd_pl == (iconv_t)(-1)) {
1197 #if ICONV_SUPPORTS_ERRNO
1198 if (errno == EINVAL) {
1199 err = PHP_ICONV_ERR_WRONG_CHARSET;
1200 } else {
1201 err = PHP_ICONV_ERR_CONVERTER;
1202 }
1203 #else
1204 err = PHP_ICONV_ERR_UNKNOWN;
1205 #endif
1206 goto out;
1207 }
1208
1209 cd = iconv_open(out_charset, enc);
1210 if (cd == (iconv_t)(-1)) {
1211 #if ICONV_SUPPORTS_ERRNO
1212 if (errno == EINVAL) {
1213 err = PHP_ICONV_ERR_WRONG_CHARSET;
1214 } else {
1215 err = PHP_ICONV_ERR_CONVERTER;
1216 }
1217 #else
1218 err = PHP_ICONV_ERR_UNKNOWN;
1219 #endif
1220 goto out;
1221 }
1222
1223 buf = safe_emalloc(1, max_line_len, 5);
1224
1225 char_cnt = max_line_len;
1226
1227 _php_iconv_appendl(pretval, fname, fname_nbytes, cd_pl);
1228 char_cnt -= fname_nbytes;
1229 smart_str_appendl(pretval, ": ", sizeof(": ") - 1);
1230 char_cnt -= 2;
1231
1232 in_p = fval;
1233 in_left = fval_nbytes;
1234
1235 do {
1236 size_t prev_in_left;
1237 size_t out_size;
1238
1239 if (char_cnt < (out_charset_len + 12)) {
1240
1241 smart_str_appendl(pretval, lfchars, lfchars_len);
1242 smart_str_appendc(pretval, ' ');
1243 char_cnt = max_line_len - 1;
1244 }
1245
1246 smart_str_appendl(pretval, "=?", sizeof("=?") - 1);
1247 char_cnt -= 2;
1248 smart_str_appendl(pretval, out_charset, out_charset_len);
1249 char_cnt -= out_charset_len;
1250 smart_str_appendc(pretval, '?');
1251 char_cnt --;
1252
1253 switch (enc_scheme) {
1254 case PHP_ICONV_ENC_SCHEME_BASE64: {
1255 size_t ini_in_left;
1256 const char *ini_in_p;
1257 size_t out_reserved = 4;
1258 int dummy;
1259
1260 smart_str_appendc(pretval, 'B');
1261 char_cnt--;
1262 smart_str_appendc(pretval, '?');
1263 char_cnt--;
1264
1265 prev_in_left = ini_in_left = in_left;
1266 ini_in_p = in_p;
1267
1268 out_size = (char_cnt - 2) / 4 * 3;
1269
1270 for (;;) {
1271 out_p = buf;
1272
1273 if (out_size <= out_reserved) {
1274 err = PHP_ICONV_ERR_TOO_BIG;
1275 goto out;
1276 }
1277
1278 out_left = out_size - out_reserved;
1279
1280 if (iconv(cd, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) {
1281 #if ICONV_SUPPORTS_ERRNO
1282 switch (errno) {
1283 case EINVAL:
1284 err = PHP_ICONV_ERR_ILLEGAL_CHAR;
1285 goto out;
1286
1287 case EILSEQ:
1288 err = PHP_ICONV_ERR_ILLEGAL_SEQ;
1289 goto out;
1290
1291 case E2BIG:
1292 if (prev_in_left == in_left) {
1293 err = PHP_ICONV_ERR_TOO_BIG;
1294 goto out;
1295 }
1296 break;
1297
1298 default:
1299 err = PHP_ICONV_ERR_UNKNOWN;
1300 goto out;
1301 }
1302 #else
1303 if (prev_in_left == in_left) {
1304 err = PHP_ICONV_ERR_UNKNOWN;
1305 goto out;
1306 }
1307 #endif
1308 }
1309
1310 out_left += out_reserved;
1311
1312 if (iconv(cd, NULL, NULL, (char **) &out_p, &out_left) == (size_t)-1) {
1313 #if ICONV_SUPPORTS_ERRNO
1314 if (errno != E2BIG) {
1315 err = PHP_ICONV_ERR_UNKNOWN;
1316 goto out;
1317 }
1318 #else
1319 if (out_left != 0) {
1320 err = PHP_ICONV_ERR_UNKNOWN;
1321 goto out;
1322 }
1323 #endif
1324 } else {
1325 break;
1326 }
1327
1328 if (iconv(cd, NULL, NULL, NULL, NULL) == (size_t)-1) {
1329 err = PHP_ICONV_ERR_UNKNOWN;
1330 goto out;
1331 }
1332
1333 out_reserved += 4;
1334 in_left = ini_in_left;
1335 in_p = ini_in_p;
1336 }
1337
1338 prev_in_left = in_left;
1339
1340 encoded = (char *) php_base64_encode((unsigned char *) buf, (int)(out_size - out_left), &dummy);
1341 encoded_len = (size_t)dummy;
1342
1343 if (char_cnt < encoded_len) {
1344
1345 err = PHP_ICONV_ERR_UNKNOWN;
1346 goto out;
1347 }
1348
1349 smart_str_appendl(pretval, encoded, encoded_len);
1350 char_cnt -= encoded_len;
1351 smart_str_appendl(pretval, "?=", sizeof("?=") - 1);
1352 char_cnt -= 2;
1353
1354 efree(encoded);
1355 encoded = NULL;
1356 } break;
1357
1358 case PHP_ICONV_ENC_SCHEME_QPRINT: {
1359 size_t ini_in_left;
1360 const char *ini_in_p;
1361 const unsigned char *p;
1362 size_t nbytes_required;
1363
1364 smart_str_appendc(pretval, 'Q');
1365 char_cnt--;
1366 smart_str_appendc(pretval, '?');
1367 char_cnt--;
1368
1369 prev_in_left = ini_in_left = in_left;
1370 ini_in_p = in_p;
1371
1372 for (out_size = (char_cnt - 2) / 3; out_size > 0;) {
1373 size_t prev_out_left;
1374
1375 nbytes_required = 0;
1376
1377 out_p = buf;
1378 out_left = out_size;
1379
1380 if (iconv(cd, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) {
1381 #if ICONV_SUPPORTS_ERRNO
1382 switch (errno) {
1383 case EINVAL:
1384 err = PHP_ICONV_ERR_ILLEGAL_CHAR;
1385 goto out;
1386
1387 case EILSEQ:
1388 err = PHP_ICONV_ERR_ILLEGAL_SEQ;
1389 goto out;
1390
1391 case E2BIG:
1392 if (prev_in_left == in_left) {
1393 err = PHP_ICONV_ERR_UNKNOWN;
1394 goto out;
1395 }
1396 break;
1397
1398 default:
1399 err = PHP_ICONV_ERR_UNKNOWN;
1400 goto out;
1401 }
1402 #else
1403 if (prev_in_left == in_left) {
1404 err = PHP_ICONV_ERR_UNKNOWN;
1405 goto out;
1406 }
1407 #endif
1408 }
1409
1410 prev_out_left = out_left;
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 efree(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 char *decoded_text;
1820 size_t decoded_text_len;
1821 int dummy;
1822
1823 switch (enc_scheme) {
1824 case PHP_ICONV_ENC_SCHEME_BASE64:
1825 decoded_text = (char *)php_base64_decode((unsigned char*)encoded_text, (int)encoded_text_len, &dummy);
1826 decoded_text_len = (size_t)dummy;
1827 break;
1828
1829 case PHP_ICONV_ENC_SCHEME_QPRINT:
1830 decoded_text = (char *)php_quot_print_decode((unsigned char*)encoded_text, (int)encoded_text_len, &decoded_text_len, 1);
1831 break;
1832 default:
1833 decoded_text = NULL;
1834 break;
1835 }
1836
1837 if (decoded_text == NULL) {
1838 if ((mode & PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR)) {
1839
1840 err = _php_iconv_appendl(pretval, encoded_word, (size_t)((p1 + 1) - encoded_word), cd_pl);
1841 if (err != PHP_ICONV_ERR_SUCCESS) {
1842 goto out;
1843 }
1844 encoded_word = NULL;
1845 if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) {
1846 scan_stat = 12;
1847 } else {
1848 scan_stat = 0;
1849 }
1850 break;
1851 } else {
1852 err = PHP_ICONV_ERR_UNKNOWN;
1853 goto out;
1854 }
1855 }
1856
1857 err = _php_iconv_appendl(pretval, decoded_text, decoded_text_len, cd);
1858 efree(decoded_text);
1859
1860 if (err != PHP_ICONV_ERR_SUCCESS) {
1861 if ((mode & PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR)) {
1862
1863 err = _php_iconv_appendl(pretval, encoded_word, (size_t)(p1 - encoded_word), cd_pl);
1864 encoded_word = NULL;
1865 if (err != PHP_ICONV_ERR_SUCCESS) {
1866 break;
1867 }
1868 } else {
1869 goto out;
1870 }
1871 }
1872
1873 if (eos) {
1874 scan_stat = 0;
1875 break;
1876 }
1877
1878 switch (*p1) {
1879 case '\r':
1880 scan_stat = 7;
1881 break;
1882
1883 case '\n':
1884 scan_stat = 8;
1885 break;
1886
1887 case '=':
1888 scan_stat = 1;
1889 break;
1890
1891 case ' ': case '\t':
1892 spaces = p1;
1893 scan_stat = 11;
1894 break;
1895
1896 default:
1897 _php_iconv_appendc(pretval, *p1, cd_pl);
1898 scan_stat = 12;
1899 break;
1900 }
1901 } break;
1902 }
1903 break;
1904
1905 case 10:
1906 if (*p1 == '?') {
1907 scan_stat = 3;
1908 }
1909 break;
1910
1911 case 11:
1912 switch (*p1) {
1913 case '\r':
1914 scan_stat = 7;
1915 break;
1916
1917 case '\n':
1918 scan_stat = 8;
1919 break;
1920
1921 case '=':
1922 if (spaces != NULL && encoded_word == NULL) {
1923 _php_iconv_appendl(pretval, spaces, (size_t)(p1 - spaces), cd_pl);
1924 spaces = NULL;
1925 }
1926 encoded_word = p1;
1927 scan_stat = 1;
1928 break;
1929
1930 case ' ': case '\t':
1931 break;
1932
1933 default:
1934 if (spaces != NULL) {
1935 _php_iconv_appendl(pretval, spaces, (size_t)(p1 - spaces), cd_pl);
1936 spaces = NULL;
1937 }
1938 _php_iconv_appendc(pretval, *p1, cd_pl);
1939 encoded_word = NULL;
1940 if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) {
1941 scan_stat = 12;
1942 } else {
1943 scan_stat = 0;
1944 }
1945 break;
1946 }
1947 break;
1948
1949 case 12:
1950 switch (*p1) {
1951 case '\r':
1952 scan_stat = 7;
1953 break;
1954
1955 case '\n':
1956 scan_stat = 8;
1957 break;
1958
1959 case ' ': case '\t':
1960 spaces = p1;
1961 scan_stat = 11;
1962 break;
1963
1964 case '=':
1965 if (!(mode & PHP_ICONV_MIME_DECODE_STRICT)) {
1966 encoded_word = p1;
1967 scan_stat = 1;
1968 break;
1969 }
1970
1971
1972 default:
1973 _php_iconv_appendc(pretval, *p1, cd_pl);
1974 break;
1975 }
1976 break;
1977 }
1978 }
1979 switch (scan_stat) {
1980 case 0: case 8: case 11: case 12:
1981 break;
1982 default:
1983 if ((mode & PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR)) {
1984 if (scan_stat == 1) {
1985 _php_iconv_appendc(pretval, '=', cd_pl);
1986 }
1987 err = PHP_ICONV_ERR_SUCCESS;
1988 } else {
1989 err = PHP_ICONV_ERR_MALFORMED;
1990 goto out;
1991 }
1992 }
1993
1994 if (next_pos != NULL) {
1995 *next_pos = p1;
1996 }
1997
1998 smart_str_0(pretval);
1999 out:
2000 if (cd != (iconv_t)(-1)) {
2001 iconv_close(cd);
2002 }
2003 if (cd_pl != (iconv_t)(-1)) {
2004 iconv_close(cd_pl);
2005 }
2006 return err;
2007 }
2008
2009
2010
2011 static void _php_iconv_show_error(php_iconv_err_t err, const char *out_charset, const char *in_charset TSRMLS_DC)
2012 {
2013 switch (err) {
2014 case PHP_ICONV_ERR_SUCCESS:
2015 break;
2016
2017 case PHP_ICONV_ERR_CONVERTER:
2018 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot open converter");
2019 break;
2020
2021 case PHP_ICONV_ERR_WRONG_CHARSET:
2022 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Wrong charset, conversion from `%s' to `%s' is not allowed",
2023 in_charset, out_charset);
2024 break;
2025
2026 case PHP_ICONV_ERR_ILLEGAL_CHAR:
2027 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected an incomplete multibyte character in input string");
2028 break;
2029
2030 case PHP_ICONV_ERR_ILLEGAL_SEQ:
2031 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected an illegal character in input string");
2032 break;
2033
2034 case PHP_ICONV_ERR_TOO_BIG:
2035
2036 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Buffer length exceeded");
2037 break;
2038
2039 case PHP_ICONV_ERR_MALFORMED:
2040 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Malformed string");
2041 break;
2042
2043 default:
2044
2045 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Unknown error (%d)", errno);
2046 break;
2047 }
2048 }
2049
2050
2051
2052
2053 PHP_FUNCTION(iconv_strlen)
2054 {
2055 char *charset = get_internal_encoding(TSRMLS_C);
2056 int charset_len = 0;
2057 char *str;
2058 int str_len;
2059
2060 php_iconv_err_t err;
2061
2062 unsigned int retval;
2063
2064 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s",
2065 &str, &str_len, &charset, &charset_len) == FAILURE) {
2066 RETURN_FALSE;
2067 }
2068
2069 if (charset_len >= ICONV_CSNMAXLEN) {
2070 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN);
2071 RETURN_FALSE;
2072 }
2073
2074 err = _php_iconv_strlen(&retval, str, str_len, charset);
2075 _php_iconv_show_error(err, GENERIC_SUPERSET_NAME, charset TSRMLS_CC);
2076 if (err == PHP_ICONV_ERR_SUCCESS) {
2077 RETVAL_LONG(retval);
2078 } else {
2079 RETVAL_FALSE;
2080 }
2081 }
2082
2083
2084
2085
2086 PHP_FUNCTION(iconv_substr)
2087 {
2088 char *charset = get_internal_encoding(TSRMLS_C);
2089 int charset_len = 0;
2090 char *str;
2091 int str_len;
2092 long offset, length = 0;
2093
2094 php_iconv_err_t err;
2095
2096 smart_str retval = {0};
2097
2098 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl|ls",
2099 &str, &str_len, &offset, &length,
2100 &charset, &charset_len) == FAILURE) {
2101 RETURN_FALSE;
2102 }
2103
2104 if (charset_len >= ICONV_CSNMAXLEN) {
2105 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN);
2106 RETURN_FALSE;
2107 }
2108
2109 if (ZEND_NUM_ARGS() < 3) {
2110 length = str_len;
2111 }
2112
2113 err = _php_iconv_substr(&retval, str, str_len, offset, length, charset);
2114 _php_iconv_show_error(err, GENERIC_SUPERSET_NAME, charset TSRMLS_CC);
2115
2116 if (err == PHP_ICONV_ERR_SUCCESS && str != NULL && retval.c != NULL) {
2117 RETURN_STRINGL(retval.c, retval.len, 0);
2118 }
2119 smart_str_free(&retval);
2120 RETURN_FALSE;
2121 }
2122
2123
2124
2125
2126 PHP_FUNCTION(iconv_strpos)
2127 {
2128 char *charset = get_internal_encoding(TSRMLS_C);
2129 int charset_len = 0;
2130 char *haystk;
2131 int haystk_len;
2132 char *ndl;
2133 int ndl_len;
2134 long offset = 0;
2135
2136 php_iconv_err_t err;
2137
2138 unsigned int retval;
2139
2140 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|ls",
2141 &haystk, &haystk_len, &ndl, &ndl_len,
2142 &offset, &charset, &charset_len) == FAILURE) {
2143 RETURN_FALSE;
2144 }
2145
2146 if (charset_len >= ICONV_CSNMAXLEN) {
2147 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN);
2148 RETURN_FALSE;
2149 }
2150
2151 if (offset < 0) {
2152 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset not contained in string.");
2153 RETURN_FALSE;
2154 }
2155
2156 if (ndl_len < 1) {
2157 RETURN_FALSE;
2158 }
2159
2160 err = _php_iconv_strpos(&retval, haystk, haystk_len, ndl, ndl_len,
2161 offset, charset);
2162 _php_iconv_show_error(err, GENERIC_SUPERSET_NAME, charset TSRMLS_CC);
2163
2164 if (err == PHP_ICONV_ERR_SUCCESS && retval != (unsigned int)-1) {
2165 RETVAL_LONG((long)retval);
2166 } else {
2167 RETVAL_FALSE;
2168 }
2169 }
2170
2171
2172
2173
2174 PHP_FUNCTION(iconv_strrpos)
2175 {
2176 char *charset = get_internal_encoding(TSRMLS_C);
2177 int charset_len = 0;
2178 char *haystk;
2179 int haystk_len;
2180 char *ndl;
2181 int ndl_len;
2182
2183 php_iconv_err_t err;
2184
2185 unsigned int retval;
2186
2187 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|s",
2188 &haystk, &haystk_len, &ndl, &ndl_len,
2189 &charset, &charset_len) == FAILURE) {
2190 RETURN_FALSE;
2191 }
2192
2193 if (ndl_len < 1) {
2194 RETURN_FALSE;
2195 }
2196
2197 if (charset_len >= ICONV_CSNMAXLEN) {
2198 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN);
2199 RETURN_FALSE;
2200 }
2201
2202 err = _php_iconv_strpos(&retval, haystk, haystk_len, ndl, ndl_len,
2203 -1, charset);
2204 _php_iconv_show_error(err, GENERIC_SUPERSET_NAME, charset TSRMLS_CC);
2205
2206 if (err == PHP_ICONV_ERR_SUCCESS && retval != (unsigned int)-1) {
2207 RETVAL_LONG((long)retval);
2208 } else {
2209 RETVAL_FALSE;
2210 }
2211 }
2212
2213
2214
2215
2216 PHP_FUNCTION(iconv_mime_encode)
2217 {
2218 const char *field_name = NULL;
2219 int field_name_len;
2220 const char *field_value = NULL;
2221 int field_value_len;
2222 zval *pref = NULL;
2223 zval tmp_zv, *tmp_zv_p = NULL;
2224 smart_str retval = {0};
2225 php_iconv_err_t err;
2226
2227 const char *in_charset = get_internal_encoding(TSRMLS_C);
2228 const char *out_charset = in_charset;
2229 long line_len = 76;
2230 const char *lfchars = "\r\n";
2231 php_iconv_enc_scheme_t scheme_id = PHP_ICONV_ENC_SCHEME_BASE64;
2232
2233 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a",
2234 &field_name, &field_name_len, &field_value, &field_value_len,
2235 &pref) == FAILURE) {
2236
2237 RETURN_FALSE;
2238 }
2239
2240 if (pref != NULL) {
2241 zval **ppval;
2242
2243 if (zend_hash_find(Z_ARRVAL_P(pref), "scheme", sizeof("scheme"), (void **)&ppval) == SUCCESS) {
2244 if (Z_TYPE_PP(ppval) == IS_STRING && Z_STRLEN_PP(ppval) > 0) {
2245 switch (Z_STRVAL_PP(ppval)[0]) {
2246 case 'B': case 'b':
2247 scheme_id = PHP_ICONV_ENC_SCHEME_BASE64;
2248 break;
2249
2250 case 'Q': case 'q':
2251 scheme_id = PHP_ICONV_ENC_SCHEME_QPRINT;
2252 break;
2253 }
2254 }
2255 }
2256
2257 if (zend_hash_find(Z_ARRVAL_P(pref), "input-charset", sizeof("input-charset"), (void **)&ppval) == SUCCESS) {
2258 if (Z_STRLEN_PP(ppval) >= ICONV_CSNMAXLEN) {
2259 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN);
2260 RETURN_FALSE;
2261 }
2262
2263 if (Z_TYPE_PP(ppval) == IS_STRING && Z_STRLEN_PP(ppval) > 0) {
2264 in_charset = Z_STRVAL_PP(ppval);
2265 }
2266 }
2267
2268
2269 if (zend_hash_find(Z_ARRVAL_P(pref), "output-charset", sizeof("output-charset"), (void **)&ppval) == SUCCESS) {
2270 if (Z_STRLEN_PP(ppval) >= ICONV_CSNMAXLEN) {
2271 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN);
2272 RETURN_FALSE;
2273 }
2274
2275 if (Z_TYPE_PP(ppval) == IS_STRING && Z_STRLEN_PP(ppval) > 0) {
2276 out_charset = Z_STRVAL_PP(ppval);
2277 }
2278 }
2279
2280 if (zend_hash_find(Z_ARRVAL_P(pref), "line-length", sizeof("line-length"), (void **)&ppval) == SUCCESS) {
2281 zval val, *pval = *ppval;
2282
2283 if (Z_TYPE_P(pval) != IS_LONG) {
2284 val = *pval;
2285 zval_copy_ctor(&val);
2286 convert_to_long(&val);
2287 pval = &val;
2288 }
2289
2290 line_len = Z_LVAL_P(pval);
2291
2292 if (pval == &val) {
2293 zval_dtor(&val);
2294 }
2295 }
2296
2297 if (zend_hash_find(Z_ARRVAL_P(pref), "line-break-chars", sizeof("line-break-chars"), (void **)&ppval) == SUCCESS) {
2298 if (Z_TYPE_PP(ppval) != IS_STRING) {
2299 tmp_zv = **ppval;
2300 zval_copy_ctor(&tmp_zv);
2301 convert_to_string(&tmp_zv);
2302
2303 lfchars = Z_STRVAL(tmp_zv);
2304
2305 tmp_zv_p = &tmp_zv;
2306 } else {
2307 lfchars = Z_STRVAL_PP(ppval);
2308 }
2309 }
2310 }
2311
2312 err = _php_iconv_mime_encode(&retval, field_name, field_name_len,
2313 field_value, field_value_len, line_len, lfchars, scheme_id,
2314 out_charset, in_charset);
2315 _php_iconv_show_error(err, out_charset, in_charset TSRMLS_CC);
2316
2317 if (err == PHP_ICONV_ERR_SUCCESS) {
2318 if (retval.c != NULL) {
2319 RETVAL_STRINGL(retval.c, retval.len, 0);
2320 } else {
2321 RETVAL_EMPTY_STRING();
2322 }
2323 } else {
2324 smart_str_free(&retval);
2325 RETVAL_FALSE;
2326 }
2327
2328 if (tmp_zv_p != NULL) {
2329 zval_dtor(tmp_zv_p);
2330 }
2331 }
2332
2333
2334
2335
2336 PHP_FUNCTION(iconv_mime_decode)
2337 {
2338 char *encoded_str;
2339 int encoded_str_len;
2340 char *charset = get_internal_encoding(TSRMLS_C);
2341 int charset_len = 0;
2342 long mode = 0;
2343
2344 smart_str retval = {0};
2345
2346 php_iconv_err_t err;
2347
2348 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ls",
2349 &encoded_str, &encoded_str_len, &mode, &charset, &charset_len) == FAILURE) {
2350
2351 RETURN_FALSE;
2352 }
2353
2354 if (charset_len >= ICONV_CSNMAXLEN) {
2355 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN);
2356 RETURN_FALSE;
2357 }
2358
2359 err = _php_iconv_mime_decode(&retval, encoded_str, encoded_str_len, charset, NULL, mode);
2360 _php_iconv_show_error(err, charset, "???" TSRMLS_CC);
2361
2362 if (err == PHP_ICONV_ERR_SUCCESS) {
2363 if (retval.c != NULL) {
2364 RETVAL_STRINGL(retval.c, retval.len, 0);
2365 } else {
2366 RETVAL_EMPTY_STRING();
2367 }
2368 } else {
2369 smart_str_free(&retval);
2370 RETVAL_FALSE;
2371 }
2372 }
2373
2374
2375
2376
2377 PHP_FUNCTION(iconv_mime_decode_headers)
2378 {
2379 const char *encoded_str;
2380 int encoded_str_len;
2381 char *charset = get_internal_encoding(TSRMLS_C);
2382 int charset_len = 0;
2383 long mode = 0;
2384
2385 php_iconv_err_t err = PHP_ICONV_ERR_SUCCESS;
2386
2387 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ls",
2388 &encoded_str, &encoded_str_len, &mode, &charset, &charset_len) == FAILURE) {
2389
2390 RETURN_FALSE;
2391 }
2392
2393 if (charset_len >= ICONV_CSNMAXLEN) {
2394 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN);
2395 RETURN_FALSE;
2396 }
2397
2398 array_init(return_value);
2399
2400 while (encoded_str_len > 0) {
2401 smart_str decoded_header = {0};
2402 char *header_name = NULL;
2403 size_t header_name_len = 0;
2404 char *header_value = NULL;
2405 size_t header_value_len = 0;
2406 char *p, *limit;
2407 const char *next_pos;
2408
2409 if (PHP_ICONV_ERR_SUCCESS != (err = _php_iconv_mime_decode(&decoded_header, encoded_str, encoded_str_len, charset, &next_pos, mode))) {
2410 smart_str_free(&decoded_header);
2411 break;
2412 }
2413
2414 if (decoded_header.c == NULL) {
2415 break;
2416 }
2417
2418 limit = decoded_header.c + decoded_header.len;
2419 for (p = decoded_header.c; p < limit; p++) {
2420 if (*p == ':') {
2421 *p = '\0';
2422 header_name = decoded_header.c;
2423 header_name_len = (p - decoded_header.c) + 1;
2424
2425 while (++p < limit) {
2426 if (*p != ' ' && *p != '\t') {
2427 break;
2428 }
2429 }
2430
2431 header_value = p;
2432 header_value_len = limit - p;
2433
2434 break;
2435 }
2436 }
2437
2438 if (header_name != NULL) {
2439 zval **elem, *new_elem;
2440
2441 if (zend_hash_find(Z_ARRVAL_P(return_value), header_name, header_name_len, (void **)&elem) == SUCCESS) {
2442 if (Z_TYPE_PP(elem) != IS_ARRAY) {
2443 MAKE_STD_ZVAL(new_elem);
2444 array_init(new_elem);
2445
2446 Z_ADDREF_PP(elem);
2447 add_next_index_zval(new_elem, *elem);
2448
2449 zend_hash_update(Z_ARRVAL_P(return_value), header_name, header_name_len, (void *)&new_elem, sizeof(new_elem), NULL);
2450
2451 elem = &new_elem;
2452 }
2453 add_next_index_stringl(*elem, header_value, header_value_len, 1);
2454 } else {
2455 add_assoc_stringl_ex(return_value, header_name, header_name_len, header_value, header_value_len, 1);
2456 }
2457 }
2458 encoded_str_len -= next_pos - encoded_str;
2459 encoded_str = next_pos;
2460
2461 smart_str_free(&decoded_header);
2462 }
2463
2464 if (err != PHP_ICONV_ERR_SUCCESS) {
2465 _php_iconv_show_error(err, charset, "???" TSRMLS_CC);
2466 zval_dtor(return_value);
2467 RETVAL_FALSE;
2468 }
2469 }
2470
2471
2472
2473
2474 PHP_NAMED_FUNCTION(php_if_iconv)
2475 {
2476 char *in_charset, *out_charset, *in_buffer, *out_buffer;
2477 size_t out_len;
2478 int in_charset_len = 0, out_charset_len = 0, in_buffer_len;
2479 php_iconv_err_t err;
2480
2481 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss",
2482 &in_charset, &in_charset_len, &out_charset, &out_charset_len, &in_buffer, &in_buffer_len) == FAILURE)
2483 return;
2484
2485 if (in_charset_len >= ICONV_CSNMAXLEN || out_charset_len >= ICONV_CSNMAXLEN) {
2486 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN);
2487 RETURN_FALSE;
2488 }
2489
2490 err = php_iconv_string(in_buffer, (size_t)in_buffer_len,
2491 &out_buffer, &out_len, out_charset, in_charset);
2492 _php_iconv_show_error(err, out_charset, in_charset TSRMLS_CC);
2493 if (err == PHP_ICONV_ERR_SUCCESS && out_buffer != NULL) {
2494 RETVAL_STRINGL(out_buffer, out_len, 0);
2495 } else {
2496 if (out_buffer != NULL) {
2497 efree(out_buffer);
2498 }
2499 RETURN_FALSE;
2500 }
2501 }
2502
2503
2504
2505
2506 PHP_FUNCTION(iconv_set_encoding)
2507 {
2508 char *type, *charset;
2509 int type_len, charset_len =0, retval;
2510
2511 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &type, &type_len, &charset, &charset_len) == FAILURE)
2512 return;
2513
2514 if (charset_len >= ICONV_CSNMAXLEN) {
2515 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN);
2516 RETURN_FALSE;
2517 }
2518
2519 if(!strcasecmp("input_encoding", type)) {
2520 retval = zend_alter_ini_entry("iconv.input_encoding", sizeof("iconv.input_encoding"), charset, charset_len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
2521 } else if(!strcasecmp("output_encoding", type)) {
2522 retval = zend_alter_ini_entry("iconv.output_encoding", sizeof("iconv.output_encoding"), charset, charset_len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
2523 } else if(!strcasecmp("internal_encoding", type)) {
2524 retval = zend_alter_ini_entry("iconv.internal_encoding", sizeof("iconv.internal_encoding"), charset, charset_len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
2525 } else {
2526 RETURN_FALSE;
2527 }
2528
2529 if (retval == SUCCESS) {
2530 RETURN_TRUE;
2531 } else {
2532 RETURN_FALSE;
2533 }
2534 }
2535
2536
2537
2538
2539 PHP_FUNCTION(iconv_get_encoding)
2540 {
2541 char *type = "all";
2542 int type_len = sizeof("all")-1;
2543
2544 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &type, &type_len) == FAILURE)
2545 return;
2546
2547 if (!strcasecmp("all", type)) {
2548 array_init(return_value);
2549 add_assoc_string(return_value, "input_encoding", get_input_encoding(TSRMLS_C), 1);
2550 add_assoc_string(return_value, "output_encoding", get_output_encoding(TSRMLS_C), 1);
2551 add_assoc_string(return_value, "internal_encoding", get_internal_encoding(TSRMLS_C), 1);
2552 } else if (!strcasecmp("input_encoding", type)) {
2553 RETVAL_STRING(get_input_encoding(TSRMLS_C), 1);
2554 } else if (!strcasecmp("output_encoding", type)) {
2555 RETVAL_STRING(get_output_encoding(TSRMLS_C), 1);
2556 } else if (!strcasecmp("internal_encoding", type)) {
2557 RETVAL_STRING(get_internal_encoding(TSRMLS_C), 1);
2558 } else {
2559 RETURN_FALSE;
2560 }
2561
2562 }
2563
2564
2565
2566 typedef struct _php_iconv_stream_filter {
2567 iconv_t cd;
2568 int persistent;
2569 char *to_charset;
2570 size_t to_charset_len;
2571 char *from_charset;
2572 size_t from_charset_len;
2573 char stub[128];
2574 size_t stub_len;
2575 } php_iconv_stream_filter;
2576
2577
2578
2579 static void php_iconv_stream_filter_dtor(php_iconv_stream_filter *self)
2580 {
2581 iconv_close(self->cd);
2582 pefree(self->to_charset, self->persistent);
2583 pefree(self->from_charset, self->persistent);
2584 }
2585
2586
2587
2588 static php_iconv_err_t php_iconv_stream_filter_ctor(php_iconv_stream_filter *self,
2589 const char *to_charset, size_t to_charset_len,
2590 const char *from_charset, size_t from_charset_len, int persistent)
2591 {
2592 if (NULL == (self->to_charset = pemalloc(to_charset_len + 1, persistent))) {
2593 return PHP_ICONV_ERR_ALLOC;
2594 }
2595 self->to_charset_len = to_charset_len;
2596 if (NULL == (self->from_charset = pemalloc(from_charset_len + 1, persistent))) {
2597 pefree(self->to_charset, persistent);
2598 return PHP_ICONV_ERR_ALLOC;
2599 }
2600 self->from_charset_len = from_charset_len;
2601
2602 memcpy(self->to_charset, to_charset, to_charset_len);
2603 self->to_charset[to_charset_len] = '\0';
2604 memcpy(self->from_charset, from_charset, from_charset_len);
2605 self->from_charset[from_charset_len] = '\0';
2606
2607 if ((iconv_t)-1 == (self->cd = iconv_open(self->to_charset, self->from_charset))) {
2608 pefree(self->from_charset, persistent);
2609 pefree(self->to_charset, persistent);
2610 return PHP_ICONV_ERR_UNKNOWN;
2611 }
2612 self->persistent = persistent;
2613 self->stub_len = 0;
2614 return PHP_ICONV_ERR_SUCCESS;
2615 }
2616
2617
2618
2619 static int php_iconv_stream_filter_append_bucket(
2620 php_iconv_stream_filter *self,
2621 php_stream *stream, php_stream_filter *filter,
2622 php_stream_bucket_brigade *buckets_out,
2623 const char *ps, size_t buf_len, size_t *consumed,
2624 int persistent TSRMLS_DC)
2625 {
2626 php_stream_bucket *new_bucket;
2627 char *out_buf = NULL;
2628 size_t out_buf_size;
2629 char *pd, *pt;
2630 size_t ocnt, prev_ocnt, icnt, tcnt;
2631 size_t initial_out_buf_size;
2632
2633 if (ps == NULL) {
2634 initial_out_buf_size = 64;
2635 icnt = 1;
2636 } else {
2637 initial_out_buf_size = buf_len;
2638 icnt = buf_len;
2639 }
2640
2641 out_buf_size = ocnt = prev_ocnt = initial_out_buf_size;
2642 if (NULL == (out_buf = pemalloc(out_buf_size, persistent))) {
2643 return FAILURE;
2644 }
2645
2646 pd = out_buf;
2647
2648 if (self->stub_len > 0) {
2649 pt = self->stub;
2650 tcnt = self->stub_len;
2651
2652 while (tcnt > 0) {
2653 if (iconv(self->cd, &pt, &tcnt, &pd, &ocnt) == (size_t)-1) {
2654 #if ICONV_SUPPORTS_ERRNO
2655 switch (errno) {
2656 case EILSEQ:
2657 php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): invalid multibyte sequence", self->from_charset, self->to_charset);
2658 goto out_failure;
2659
2660 case EINVAL:
2661 if (ps != NULL) {
2662 if (icnt > 0) {
2663 if (self->stub_len >= sizeof(self->stub)) {
2664 php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): insufficient buffer", self->from_charset, self->to_charset);
2665 goto out_failure;
2666 }
2667 self->stub[self->stub_len++] = *(ps++);
2668 icnt--;
2669 pt = self->stub;
2670 tcnt = self->stub_len;
2671 } else {
2672 tcnt = 0;
2673 break;
2674 }
2675 }
2676 break;
2677
2678 case E2BIG: {
2679 char *new_out_buf;
2680 size_t new_out_buf_size;
2681
2682 new_out_buf_size = out_buf_size << 1;
2683
2684 if (new_out_buf_size < out_buf_size) {
2685
2686 if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) {
2687 goto out_failure;
2688 }
2689
2690 php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC);
2691
2692 out_buf_size = ocnt = initial_out_buf_size;
2693 if (NULL == (out_buf = pemalloc(out_buf_size, persistent))) {
2694 return FAILURE;
2695 }
2696 pd = out_buf;
2697 } else {
2698 if (NULL == (new_out_buf = perealloc(out_buf, new_out_buf_size, persistent))) {
2699 if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) {
2700 goto out_failure;
2701 }
2702
2703 php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC);
2704 return FAILURE;
2705 }
2706 pd = new_out_buf + (pd - out_buf);
2707 ocnt += (new_out_buf_size - out_buf_size);
2708 out_buf = new_out_buf;
2709 out_buf_size = new_out_buf_size;
2710 }
2711 } break;
2712
2713 default:
2714 php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): unknown error", self->from_charset, self->to_charset);
2715 goto out_failure;
2716 }
2717 #else
2718 if (ocnt == prev_ocnt) {
2719 php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): unknown error", self->from_charset, self->to_charset);
2720 goto out_failure;
2721 }
2722 #endif
2723 }
2724 prev_ocnt = ocnt;
2725 }
2726 memmove(self->stub, pt, tcnt);
2727 self->stub_len = tcnt;
2728 }
2729
2730 while (icnt > 0) {
2731 if ((ps == NULL ? iconv(self->cd, NULL, NULL, &pd, &ocnt):
2732 iconv(self->cd, (char **)&ps, &icnt, &pd, &ocnt)) == (size_t)-1) {
2733 #if ICONV_SUPPORTS_ERRNO
2734 switch (errno) {
2735 case EILSEQ:
2736 php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): invalid multibyte sequence", self->from_charset, self->to_charset);
2737 goto out_failure;
2738
2739 case EINVAL:
2740 if (ps != NULL) {
2741 if (icnt > sizeof(self->stub)) {
2742 php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): insufficient buffer", self->from_charset, self->to_charset);
2743 goto out_failure;
2744 }
2745 memcpy(self->stub, ps, icnt);
2746 self->stub_len = icnt;
2747 ps += icnt;
2748 icnt = 0;
2749 } else {
2750 php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): unexpected octet values", self->from_charset, self->to_charset);
2751 goto out_failure;
2752 }
2753 break;
2754
2755 case E2BIG: {
2756 char *new_out_buf;
2757 size_t new_out_buf_size;
2758
2759 new_out_buf_size = out_buf_size << 1;
2760
2761 if (new_out_buf_size < out_buf_size) {
2762
2763 if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) {
2764 goto out_failure;
2765 }
2766
2767 php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC);
2768
2769 out_buf_size = ocnt = initial_out_buf_size;
2770 if (NULL == (out_buf = pemalloc(out_buf_size, persistent))) {
2771 return FAILURE;
2772 }
2773 pd = out_buf;
2774 } else {
2775 if (NULL == (new_out_buf = perealloc(out_buf, new_out_buf_size, persistent))) {
2776 if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) {
2777 goto out_failure;
2778 }
2779
2780 php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC);
2781 return FAILURE;
2782 }
2783 pd = new_out_buf + (pd - out_buf);
2784 ocnt += (new_out_buf_size - out_buf_size);
2785 out_buf = new_out_buf;
2786 out_buf_size = new_out_buf_size;
2787 }
2788 } break;
2789
2790 default:
2791 php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): unknown error", self->from_charset, self->to_charset);
2792 goto out_failure;
2793 }
2794 #else
2795 if (ocnt == prev_ocnt) {
2796 php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): unknown error", self->from_charset, self->to_charset);
2797 goto out_failure;
2798 }
2799 #endif
2800 } else {
2801 if (ps == NULL) {
2802 break;
2803 }
2804 }
2805 prev_ocnt = ocnt;
2806 }
2807
2808 if (out_buf_size - ocnt > 0) {
2809 if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) {
2810 goto out_failure;
2811 }
2812 php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC);
2813 } else {
2814 pefree(out_buf, persistent);
2815 }
2816 *consumed += buf_len - icnt;
2817
2818 return SUCCESS;
2819
2820 out_failure:
2821 pefree(out_buf, persistent);
2822 return FAILURE;
2823 }
2824
2825
2826
2827 static php_stream_filter_status_t php_iconv_stream_filter_do_filter(
2828 php_stream *stream, php_stream_filter *filter,
2829 php_stream_bucket_brigade *buckets_in,
2830 php_stream_bucket_brigade *buckets_out,
2831 size_t *bytes_consumed, int flags TSRMLS_DC)
2832 {
2833 php_stream_bucket *bucket = NULL;
2834 size_t consumed = 0;
2835 php_iconv_stream_filter *self = (php_iconv_stream_filter *)filter->abstract;
2836
2837 while (buckets_in->head != NULL) {
2838 bucket = buckets_in->head;
2839
2840 php_stream_bucket_unlink(bucket TSRMLS_CC);
2841
2842 if (php_iconv_stream_filter_append_bucket(self, stream, filter,
2843 buckets_out, bucket->buf, bucket->buflen, &consumed,
2844 php_stream_is_persistent(stream) TSRMLS_CC) != SUCCESS) {
2845 goto out_failure;
2846 }
2847
2848 php_stream_bucket_delref(bucket TSRMLS_CC);
2849 }
2850
2851 if (flags != PSFS_FLAG_NORMAL) {
2852 if (php_iconv_stream_filter_append_bucket(self, stream, filter,
2853 buckets_out, NULL, 0, &consumed,
2854 php_stream_is_persistent(stream) TSRMLS_CC) != SUCCESS) {
2855 goto out_failure;
2856 }
2857 }
2858
2859 if (bytes_consumed != NULL) {
2860 *bytes_consumed = consumed;
2861 }
2862
2863 return PSFS_PASS_ON;
2864
2865 out_failure:
2866 if (bucket != NULL) {
2867 php_stream_bucket_delref(bucket TSRMLS_CC);
2868 }
2869 return PSFS_ERR_FATAL;
2870 }
2871
2872
2873
2874 static void php_iconv_stream_filter_cleanup(php_stream_filter *filter TSRMLS_DC)
2875 {
2876 php_iconv_stream_filter_dtor((php_iconv_stream_filter *)filter->abstract);
2877 pefree(filter->abstract, ((php_iconv_stream_filter *)filter->abstract)->persistent);
2878 }
2879
2880
2881 static php_stream_filter_ops php_iconv_stream_filter_ops = {
2882 php_iconv_stream_filter_do_filter,
2883 php_iconv_stream_filter_cleanup,
2884 "convert.iconv.*"
2885 };
2886
2887
2888 static php_stream_filter *php_iconv_stream_filter_factory_create(const char *name, zval *params, int persistent TSRMLS_DC)
2889 {
2890 php_stream_filter *retval = NULL;
2891 php_iconv_stream_filter *inst;
2892 char *from_charset = NULL, *to_charset = NULL;
2893 size_t from_charset_len, to_charset_len;
2894
2895 if ((from_charset = strchr(name, '.')) == NULL) {
2896 return NULL;
2897 }
2898 ++from_charset;
2899 if ((from_charset = strchr(from_charset, '.')) == NULL) {
2900 return NULL;
2901 }
2902 ++from_charset;
2903 if ((to_charset = strpbrk(from_charset, "/.")) == NULL) {
2904 return NULL;
2905 }
2906 from_charset_len = to_charset - from_charset;
2907 ++to_charset;
2908 to_charset_len = strlen(to_charset);
2909
2910 if (from_charset_len >= ICONV_CSNMAXLEN || to_charset_len >= ICONV_CSNMAXLEN) {
2911 return NULL;
2912 }
2913
2914 if (NULL == (inst = pemalloc(sizeof(php_iconv_stream_filter), persistent))) {
2915 return NULL;
2916 }
2917
2918 if (php_iconv_stream_filter_ctor(inst, to_charset, to_charset_len, from_charset, from_charset_len, persistent) != PHP_ICONV_ERR_SUCCESS) {
2919 pefree(inst, persistent);
2920 return NULL;
2921 }
2922
2923 if (NULL == (retval = php_stream_filter_alloc(&php_iconv_stream_filter_ops, inst, persistent))) {
2924 php_iconv_stream_filter_dtor(inst);
2925 pefree(inst, persistent);
2926 }
2927
2928 return retval;
2929 }
2930
2931
2932
2933 static php_iconv_err_t php_iconv_stream_filter_register_factory(TSRMLS_D)
2934 {
2935 static php_stream_filter_factory filter_factory = {
2936 php_iconv_stream_filter_factory_create
2937 };
2938
2939 if (FAILURE == php_stream_filter_register_factory(
2940 php_iconv_stream_filter_ops.label,
2941 &filter_factory TSRMLS_CC)) {
2942 return PHP_ICONV_ERR_UNKNOWN;
2943 }
2944 return PHP_ICONV_ERR_SUCCESS;
2945 }
2946
2947
2948
2949 static php_iconv_err_t php_iconv_stream_filter_unregister_factory(TSRMLS_D)
2950 {
2951 if (FAILURE == php_stream_filter_unregister_factory(
2952 php_iconv_stream_filter_ops.label TSRMLS_CC)) {
2953 return PHP_ICONV_ERR_UNKNOWN;
2954 }
2955 return PHP_ICONV_ERR_SUCCESS;
2956 }
2957
2958
2959 #endif
2960
2961
2962
2963
2964
2965
2966
2967
2968