2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
6 | Copyright (c) 1997-2010 The PHP Group |
7 +----------------------------------------------------------------------+
8 | This source file is subject to version 3.01 of the PHP license, |
9 | that is bundled with this package in the file LICENSE, and is |
10 | available through the world-wide-web at the following url: |
11 | http://www.php.net/license/3_01.txt |
12 | If you did not receive a copy of the PHP license and are unable to |
13 | obtain it through the world-wide-web, please send a note to |
14 | license@php.net so we can mail you a copy immediately. |
15 +----------------------------------------------------------------------+
18 #include "hphp/runtime/ext/ext_iconv.h"
19 #include "hphp/runtime/base/string_buffer.h"
20 #include "hphp/runtime/base/request_local.h"
21 #include "hphp/runtime/base/zend-functions.h"
22 #include "hphp/runtime/base/zend-string.h"
24 #define ICONV_SUPPORTS_ERRNO 1
28 * libiconv sometimes defines the second parameter of its
29 * main function as (char**), and sometimes as (const char**) but
30 * provides no means to detect this. Let build system determine
31 * which is appropriate and (optionally) define ICONV_CONST=const
32 * if such is needed in the cast.
39 IMPLEMENT_DEFAULT_EXTENSION(iconv
);
40 ///////////////////////////////////////////////////////////////////////////////
42 #define _php_iconv_memequal(a, b, c) \
43 ((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))
45 static char _generic_superset_name
[] = "UCS-4LE";
46 #define GENERIC_SUPERSET_NAME _generic_superset_name
47 #define GENERIC_SUPERSET_NBYTES 4
49 #define PHP_ICONV_MIME_DECODE_STRICT (1<<0)
50 #define PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR (1<<1)
52 typedef enum _php_iconv_enc_scheme_t
{
53 PHP_ICONV_ENC_SCHEME_BASE64
,
54 PHP_ICONV_ENC_SCHEME_QPRINT
55 } php_iconv_enc_scheme_t
;
57 typedef enum _php_iconv_err_t
{
58 PHP_ICONV_ERR_SUCCESS
= 0,
59 PHP_ICONV_ERR_CONVERTER
= 1,
60 PHP_ICONV_ERR_WRONG_CHARSET
= 2,
61 PHP_ICONV_ERR_TOO_BIG
= 3,
62 PHP_ICONV_ERR_ILLEGAL_SEQ
= 4,
63 PHP_ICONV_ERR_ILLEGAL_CHAR
= 5,
64 PHP_ICONV_ERR_UNKNOWN
= 6,
65 PHP_ICONV_ERR_MALFORMED
= 7,
66 PHP_ICONV_ERR_ALLOC
= 8
69 static void _php_iconv_show_error(php_iconv_err_t err
, const char *out_charset
,
70 const char *in_charset
) {
72 case PHP_ICONV_ERR_SUCCESS
:
74 case PHP_ICONV_ERR_CONVERTER
:
75 raise_warning("iconv: Cannot open converter");
77 case PHP_ICONV_ERR_WRONG_CHARSET
:
78 raise_warning("iconv: Wrong charset, "
79 "conversion from `%s' to `%s' is not allowed",
80 in_charset
, out_charset
);
82 case PHP_ICONV_ERR_ILLEGAL_CHAR
:
83 raise_notice("iconv: Detected an incomplete multibyte character "
86 case PHP_ICONV_ERR_ILLEGAL_SEQ
:
87 raise_notice("iconv: Detected an illegal character in input string");
89 case PHP_ICONV_ERR_TOO_BIG
:
91 raise_warning("iconv: Buffer length exceeded");
93 case PHP_ICONV_ERR_MALFORMED
:
94 raise_notice("iconv: Malformed string");
98 raise_notice("iconv: Unknown error (%d)", errno
);
103 class ICONVGlobals
: public RequestEventHandler
{
105 String input_encoding
;
106 String output_encoding
;
107 String internal_encoding
;
111 virtual void requestInit() {
112 input_encoding
= "ISO-8859-1";
113 output_encoding
= "ISO-8859-1";
114 internal_encoding
= "ISO-8859-1";
117 virtual void requestShutdown() {
118 input_encoding
.reset();
119 output_encoding
.reset();
120 internal_encoding
.reset();
123 IMPLEMENT_STATIC_REQUEST_LOCAL(ICONVGlobals
, s_iconv_globals
);
124 #define ICONVG(name) s_iconv_globals->name
126 ///////////////////////////////////////////////////////////////////////////////
129 #ifndef ICONV_CSNMAXLEN
130 #define ICONV_CSNMAXLEN 64
132 static bool validate_charset(CStrRef charset
) {
133 if (charset
.size() >= ICONV_CSNMAXLEN
) {
134 throw_invalid_argument
135 ("Charset parameter exceeds the maximum allowed "
136 "length of %d characters", ICONV_CSNMAXLEN
);
142 static Variant
check_charset(CStrRef charset
) {
143 if (!validate_charset(charset
)) return false;
144 if (charset
.empty()) {
145 return ICONVG(internal_encoding
);
150 static php_iconv_err_t
_php_iconv_appendl(StringBuffer
&d
, const char *s
,
151 size_t l
, iconv_t cd
) {
152 const char *in_p
= s
;
155 size_t buf_growth
= 128;
157 #if !ICONV_SUPPORTS_ERRNO
158 size_t prev_in_left
= in_left
;
162 while (in_left
> 0) {
163 out_left
= buf_growth
- out_left
;
164 out_p
= d
.reserve(out_left
);
166 if (iconv(cd
, (ICONV_CONST
char **)&in_p
, &in_left
, (char **)&out_p
, &out_left
) ==
168 #if ICONV_SUPPORTS_ERRNO
170 case EINVAL
: return PHP_ICONV_ERR_ILLEGAL_CHAR
;
171 case EILSEQ
: return PHP_ICONV_ERR_ILLEGAL_SEQ
;
174 return PHP_ICONV_ERR_UNKNOWN
;
177 if (prev_in_left
== in_left
) {
178 return PHP_ICONV_ERR_UNKNOWN
;
182 #if !ICONV_SUPPORTS_ERRNO
183 prev_in_left
= in_left
;
185 d
.resize(d
.size() + buf_growth
- out_left
);
190 out_left
= buf_growth
- out_left
;
191 out_p
= d
.reserve(out_left
);
193 if (iconv(cd
, NULL
, NULL
, (char **)&out_p
, &out_left
) == (size_t)0) {
194 d
.resize(d
.size() + buf_growth
- out_left
);
197 #if ICONV_SUPPORTS_ERRNO
198 if (errno
!= E2BIG
) {
199 return PHP_ICONV_ERR_UNKNOWN
;
203 return PHP_ICONV_ERR_UNKNOWN
;
207 d
.resize(d
.size() + buf_growth
- out_left
);
211 return PHP_ICONV_ERR_SUCCESS
;
214 static php_iconv_err_t
_php_iconv_appendc(StringBuffer
&d
, const char c
,
216 return _php_iconv_appendl(d
, &c
, 1, cd
);
219 static php_iconv_err_t
php_iconv_string(const char *in_p
, size_t in_len
,
220 char **out
, size_t *out_len
,
221 const char *out_charset
,
222 const char *in_charset
) {
223 #if !ICONV_SUPPORTS_ERRNO
224 size_t in_size
, out_size
, out_left
;
225 char *out_buffer
, *out_p
;
233 * This is not the right way to get output size...
234 * This is not space efficient for large text.
235 * This is also problem for encoding like UTF-7/UTF-8/ISO-2022 which
236 * a single char can be more than 4 bytes.
237 * I added 15 extra bytes for safety. <yohgaki@php.net>
239 out_size
= in_len
* sizeof(int) + 15;
244 cd
= iconv_open(out_charset
, in_charset
);
246 if (cd
== (iconv_t
)(-1)) {
247 return PHP_ICONV_ERR_UNKNOWN
;
250 out_buffer
= (char *)malloc(out_size
+ 1);
253 result
= iconv(cd
, (char **)&in_p
, &in_size
, (char **)&out_p
, &out_left
);
254 if (result
== (size_t)(-1)) {
256 return PHP_ICONV_ERR_UNKNOWN
;
260 out_buffer
= (char *)realloc(out_buffer
, out_size
+ 8);
263 // flush the shift-out sequences
264 result
= iconv(cd
, NULL
, NULL
, &out_p
, &out_left
);
266 if (result
== (size_t)(-1)) {
268 return PHP_ICONV_ERR_UNKNOWN
;
271 *out_len
= out_size
- out_left
;
272 out_buffer
[*out_len
] = '\0';
277 return PHP_ICONV_ERR_SUCCESS
;
279 #else // iconv supports errno. Handle it better way.
282 size_t in_left
, out_size
, out_left
;
283 char *out_p
, *out_buf
, *tmp_buf
;
284 size_t bsz
, result
= 0;
285 php_iconv_err_t retval
= PHP_ICONV_ERR_SUCCESS
;
290 cd
= iconv_open(out_charset
, in_charset
);
292 if (cd
== (iconv_t
)(-1)) {
293 if (errno
== EINVAL
) {
294 return PHP_ICONV_ERR_WRONG_CHARSET
;
296 return PHP_ICONV_ERR_CONVERTER
;
300 out_left
= in_len
+ 32; // Avoid realloc() most cases
303 out_buf
= (char *)malloc(bsz
+ 1);
306 while (in_left
> 0) {
307 result
= iconv(cd
, (ICONV_CONST
char **)&in_p
, &in_left
, (char **)&out_p
, &out_left
);
308 out_size
= bsz
- out_left
;
309 if (result
== (size_t)(-1)) {
310 if (errno
== E2BIG
&& in_left
> 0) {
311 // converted string is longer than out buffer
314 tmp_buf
= (char*)realloc(out_buf
, bsz
+ 1);
315 out_p
= out_buf
= tmp_buf
;
317 out_left
= bsz
- out_size
;
324 if (result
!= (size_t)(-1)) {
325 // flush the shift-out sequences
327 result
= iconv(cd
, NULL
, NULL
, (char **)&out_p
, &out_left
);
328 out_size
= bsz
- out_left
;
330 if (result
!= (size_t)(-1)) {
334 if (errno
== E2BIG
) {
336 tmp_buf
= (char *)realloc(out_buf
, bsz
);
338 out_p
= out_buf
= tmp_buf
;
340 out_left
= bsz
- out_size
;
349 if (result
== (size_t)(-1)) {
351 case EINVAL
: retval
= PHP_ICONV_ERR_ILLEGAL_CHAR
; break;
352 case EILSEQ
: retval
= PHP_ICONV_ERR_ILLEGAL_SEQ
; break;
355 retval
= PHP_ICONV_ERR_TOO_BIG
;
359 retval
= PHP_ICONV_ERR_UNKNOWN
;
361 return PHP_ICONV_ERR_UNKNOWN
;
371 static php_iconv_err_t
_php_iconv_strlen(unsigned int *pretval
,
372 const char *str
, size_t nbytes
,
374 char buf
[GENERIC_SUPERSET_NBYTES
*2];
375 php_iconv_err_t err
= PHP_ICONV_ERR_SUCCESS
;
383 *pretval
= (unsigned int)-1;
385 cd
= iconv_open(GENERIC_SUPERSET_NAME
, enc
);
386 if (cd
== (iconv_t
)(-1)) {
387 #if ICONV_SUPPORTS_ERRNO
388 if (errno
== EINVAL
) {
389 return PHP_ICONV_ERR_WRONG_CHARSET
;
391 return PHP_ICONV_ERR_CONVERTER
;
394 return PHP_ICONV_ERR_UNKNOWN
;
398 errno
= out_left
= 0;
400 for (in_p
= str
, in_left
= nbytes
, cnt
= 0; in_left
> 0; cnt
+=2) {
403 out_left
= sizeof(buf
);
405 prev_in_left
= in_left
;
407 if (iconv(cd
, (ICONV_CONST
char **)&in_p
, &in_left
, (char **) &out_p
, &out_left
)
409 if (prev_in_left
== in_left
) {
416 cnt
-= out_left
/ GENERIC_SUPERSET_NBYTES
;
419 #if ICONV_SUPPORTS_ERRNO
421 case EINVAL
: err
= PHP_ICONV_ERR_ILLEGAL_CHAR
; break;
422 case EILSEQ
: err
= PHP_ICONV_ERR_ILLEGAL_SEQ
; break;
428 err
= PHP_ICONV_ERR_UNKNOWN
;
439 static php_iconv_err_t
_php_iconv_substr(StringBuffer
&pretval
,
440 const char *str
, size_t nbytes
,
441 int offset
, int len
, const char *enc
){
442 char buf
[GENERIC_SUPERSET_NBYTES
];
443 php_iconv_err_t err
= PHP_ICONV_ERR_SUCCESS
;
450 unsigned int total_len
;
452 err
= _php_iconv_strlen(&total_len
, str
, nbytes
, enc
);
453 if (err
!= PHP_ICONV_ERR_SUCCESS
) {
458 if ((len
+= (total_len
- offset
)) < 0) {
459 return PHP_ICONV_ERR_SUCCESS
;
464 if ((offset
+= total_len
) < 0) {
465 return PHP_ICONV_ERR_SUCCESS
;
469 if (len
> (int)total_len
) {
474 if (offset
>= (int)total_len
) {
475 return PHP_ICONV_ERR_SUCCESS
;
478 if ((offset
+ len
) > (int)total_len
) {
479 /* trying to compute the length */
480 len
= total_len
- offset
;
484 return PHP_ICONV_ERR_SUCCESS
;
487 cd1
= iconv_open(GENERIC_SUPERSET_NAME
, enc
);
489 if (cd1
== (iconv_t
)(-1)) {
490 #if ICONV_SUPPORTS_ERRNO
491 if (errno
== EINVAL
) {
492 return PHP_ICONV_ERR_WRONG_CHARSET
;
494 return PHP_ICONV_ERR_CONVERTER
;
497 return PHP_ICONV_ERR_UNKNOWN
;
504 for (in_p
= str
, in_left
= nbytes
, cnt
= 0; in_left
> 0 && len
> 0; ++cnt
) {
507 out_left
= sizeof(buf
);
509 prev_in_left
= in_left
;
511 if (iconv(cd1
, (ICONV_CONST
char **)&in_p
, &in_left
, (char **) &out_p
, &out_left
) ==
513 if (prev_in_left
== in_left
) {
518 if (cnt
>= (unsigned int)offset
) {
519 if (cd2
== (iconv_t
)NULL
) {
520 cd2
= iconv_open(enc
, GENERIC_SUPERSET_NAME
);
522 if (cd2
== (iconv_t
)(-1)) {
524 #if ICONV_SUPPORTS_ERRNO
525 if (errno
== EINVAL
) {
526 err
= PHP_ICONV_ERR_WRONG_CHARSET
;
528 err
= PHP_ICONV_ERR_CONVERTER
;
531 err
= PHP_ICONV_ERR_UNKNOWN
;
537 if (_php_iconv_appendl(pretval
, buf
, sizeof(buf
), cd2
) !=
538 PHP_ICONV_ERR_SUCCESS
) {
545 #if ICONV_SUPPORTS_ERRNO
548 err
= PHP_ICONV_ERR_ILLEGAL_CHAR
;
552 err
= PHP_ICONV_ERR_ILLEGAL_SEQ
;
559 if (err
== PHP_ICONV_ERR_SUCCESS
) {
560 if (cd2
!= (iconv_t
)NULL
) {
561 _php_iconv_appendl(pretval
, NULL
, 0, cd2
);
565 if (cd1
!= (iconv_t
)NULL
) {
569 if (cd2
!= (iconv_t
)NULL
) {
575 static php_iconv_err_t
_php_iconv_strpos(unsigned int *pretval
,
577 size_t haystk_nbytes
,
578 const char *ndl
, size_t ndl_nbytes
,
579 int offset
, const char *enc
) {
580 char buf
[GENERIC_SUPERSET_NBYTES
];
581 php_iconv_err_t err
= PHP_ICONV_ERR_SUCCESS
;
589 const char *ndl_buf_p
;
590 size_t ndl_buf_len
, ndl_buf_left
;
591 unsigned int match_ofs
;
593 *pretval
= (unsigned int)-1;
595 err
= php_iconv_string(ndl
, ndl_nbytes
,
596 &ndl_buf
, &ndl_buf_len
, GENERIC_SUPERSET_NAME
, enc
);
598 if (err
!= PHP_ICONV_ERR_SUCCESS
) {
599 if (ndl_buf
!= NULL
) {
605 cd
= iconv_open(GENERIC_SUPERSET_NAME
, enc
);
607 if (cd
== (iconv_t
)(-1)) {
608 if (ndl_buf
!= NULL
) {
611 #if ICONV_SUPPORTS_ERRNO
612 if (errno
== EINVAL
) {
613 return PHP_ICONV_ERR_WRONG_CHARSET
;
615 return PHP_ICONV_ERR_CONVERTER
;
618 return PHP_ICONV_ERR_UNKNOWN
;
623 ndl_buf_left
= ndl_buf_len
;
624 match_ofs
= (unsigned int)-1;
626 for (in_p
= haystk
, in_left
= haystk_nbytes
, cnt
= 0; in_left
> 0; ++cnt
) {
629 out_left
= sizeof(buf
);
631 prev_in_left
= in_left
;
633 if (iconv(cd
, (ICONV_CONST
char **)&in_p
, &in_left
, (char **) &out_p
, &out_left
) ==
635 if (prev_in_left
== in_left
) {
636 #if ICONV_SUPPORTS_ERRNO
638 case EINVAL
: err
= PHP_ICONV_ERR_ILLEGAL_CHAR
; break;
639 case EILSEQ
: err
= PHP_ICONV_ERR_ILLEGAL_SEQ
; break;
643 err
= PHP_ICONV_ERR_UNKNOWN
;
651 if (cnt
>= (unsigned int)offset
) {
652 if (_php_iconv_memequal(buf
, ndl_buf_p
, sizeof(buf
))) {
653 if (match_ofs
== (unsigned int)-1) {
656 ndl_buf_p
+= GENERIC_SUPERSET_NBYTES
;
657 ndl_buf_left
-= GENERIC_SUPERSET_NBYTES
;
658 if (ndl_buf_left
== 0) {
659 *pretval
= match_ofs
;
663 unsigned int i
, j
, lim
;
666 j
= GENERIC_SUPERSET_NBYTES
;
667 lim
= (unsigned int)(ndl_buf_p
- ndl_buf
);
670 if (_php_iconv_memequal(&ndl_buf
[j
], &ndl_buf
[i
],
671 GENERIC_SUPERSET_NBYTES
)) {
672 i
+= GENERIC_SUPERSET_NBYTES
;
677 j
+= GENERIC_SUPERSET_NBYTES
;
680 if (_php_iconv_memequal(buf
, &ndl_buf
[i
], sizeof(buf
))) {
681 match_ofs
+= (lim
- i
) / GENERIC_SUPERSET_NBYTES
;
682 i
+= GENERIC_SUPERSET_NBYTES
;
683 ndl_buf_p
= &ndl_buf
[i
];
684 ndl_buf_left
= ndl_buf_len
- i
;
686 match_ofs
= (unsigned int)-1;
688 ndl_buf_left
= ndl_buf_len
;
693 if (_php_iconv_memequal(buf
, ndl_buf_p
, sizeof(buf
))) {
694 if (match_ofs
== (unsigned int)-1) {
697 ndl_buf_p
+= GENERIC_SUPERSET_NBYTES
;
698 ndl_buf_left
-= GENERIC_SUPERSET_NBYTES
;
699 if (ndl_buf_left
== 0) {
700 *pretval
= match_ofs
;
702 ndl_buf_left
= ndl_buf_len
;
703 match_ofs
= (unsigned int)-1;
706 unsigned int i
, j
, lim
;
709 j
= GENERIC_SUPERSET_NBYTES
;
710 lim
= (unsigned int)(ndl_buf_p
- ndl_buf
);
713 if (_php_iconv_memequal(&ndl_buf
[j
], &ndl_buf
[i
],
714 GENERIC_SUPERSET_NBYTES
)) {
715 i
+= GENERIC_SUPERSET_NBYTES
;
720 j
+= GENERIC_SUPERSET_NBYTES
;
723 if (_php_iconv_memequal(buf
, &ndl_buf
[i
], sizeof(buf
))) {
724 match_ofs
+= (lim
- i
) / GENERIC_SUPERSET_NBYTES
;
725 i
+= GENERIC_SUPERSET_NBYTES
;
726 ndl_buf_p
= &ndl_buf
[i
];
727 ndl_buf_left
= ndl_buf_len
- i
;
729 match_ofs
= (unsigned int)-1;
731 ndl_buf_left
= ndl_buf_len
;
745 static php_iconv_err_t
_php_iconv_mime_decode(StringBuffer
&retval
,
749 const char **next_pos
,
751 php_iconv_err_t err
= PHP_ICONV_ERR_SUCCESS
;
753 iconv_t cd
= (iconv_t
)(-1), cd_pl
= (iconv_t
)(-1);
757 unsigned int scan_stat
= 0;
758 const char *csname
= NULL
;
760 const char *encoded_text
= NULL
;
761 size_t encoded_text_len
= 0;
762 const char *encoded_word
= NULL
;
763 const char *spaces
= NULL
;
765 php_iconv_enc_scheme_t enc_scheme
= PHP_ICONV_ENC_SCHEME_BASE64
;
767 if (next_pos
!= NULL
) {
770 cd_pl
= iconv_open(enc
, "ASCII");
772 if (cd_pl
== (iconv_t
)(-1)) {
773 #if ICONV_SUPPORTS_ERRNO
774 if (errno
== EINVAL
) {
775 err
= PHP_ICONV_ERR_WRONG_CHARSET
;
777 err
= PHP_ICONV_ERR_CONVERTER
;
780 err
= PHP_ICONV_ERR_UNKNOWN
;
786 for (str_left
= str_nbytes
; str_left
> 0; str_left
--, p1
++) {
790 case 0: /* expecting any character */
792 case '\r': /* part of an EOL sequence? */
800 case '=': /* first letter of an encoded chunk */
805 case ' ': case '\t': /* a chunk of whitespaces */
810 default: /* first letter of a non-encoded word */
811 _php_iconv_appendc(retval
, *p1
, cd_pl
);
813 if ((mode
& PHP_ICONV_MIME_DECODE_STRICT
)) {
820 case 1: /* expecting a delimiter */
822 err
= _php_iconv_appendl(retval
, encoded_word
,
823 (size_t)((p1
+ 1) - encoded_word
), cd_pl
);
824 if (err
!= PHP_ICONV_ERR_SUCCESS
) {
828 if ((mode
& PHP_ICONV_MIME_DECODE_STRICT
)) {
839 case 2: /* expecting a charset name */
841 case '?': /* normal delimiter: encoding scheme follows */
845 case '*': /* new style delimiter: locale id follows */
849 if (scan_stat
!= 2) {
852 if (csname
== NULL
) {
853 err
= PHP_ICONV_ERR_MALFORMED
;
857 csname_len
= (size_t)(p1
- csname
);
859 if (csname_len
> sizeof(tmpbuf
) - 1) {
860 if ((mode
& PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR
)) {
861 err
= _php_iconv_appendl(retval
, encoded_word
,
862 (size_t)((p1
+ 1) - encoded_word
), cd_pl
);
863 if (err
!= PHP_ICONV_ERR_SUCCESS
) {
867 if ((mode
& PHP_ICONV_MIME_DECODE_STRICT
)) {
874 err
= PHP_ICONV_ERR_MALFORMED
;
879 memcpy(tmpbuf
, csname
, csname_len
);
880 tmpbuf
[csname_len
] = '\0';
882 if (cd
!= (iconv_t
)(-1)) {
886 cd
= iconv_open(enc
, tmpbuf
);
888 if (cd
== (iconv_t
)(-1)) {
889 if ((mode
& PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR
)) {
890 err
= _php_iconv_appendl(retval
, encoded_word
,
891 (size_t)((p1
+ 1) - encoded_word
), cd_pl
);
892 if (err
!= PHP_ICONV_ERR_SUCCESS
) {
896 if ((mode
& PHP_ICONV_MIME_DECODE_STRICT
)) {
903 #if ICONV_SUPPORTS_ERRNO
904 if (errno
== EINVAL
) {
905 err
= PHP_ICONV_ERR_WRONG_CHARSET
;
907 err
= PHP_ICONV_ERR_CONVERTER
;
910 err
= PHP_ICONV_ERR_UNKNOWN
;
918 case 3: /* expecting a encoding scheme specifier */
922 enc_scheme
= PHP_ICONV_ENC_SCHEME_BASE64
;
928 enc_scheme
= PHP_ICONV_ENC_SCHEME_QPRINT
;
933 if ((mode
& PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR
)) {
934 err
= _php_iconv_appendl(retval
, encoded_word
,
935 (size_t)((p1
+ 1) - encoded_word
), cd_pl
);
936 if (err
!= PHP_ICONV_ERR_SUCCESS
) {
940 if ((mode
& PHP_ICONV_MIME_DECODE_STRICT
)) {
947 err
= PHP_ICONV_ERR_MALFORMED
;
953 case 4: /* expecting a delimiter */
955 if ((mode
& PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR
)) {
956 /* pass the entire chunk through the converter */
957 err
= _php_iconv_appendl(retval
, encoded_word
,
958 (size_t)((p1
+ 1) - encoded_word
), cd_pl
);
959 if (err
!= PHP_ICONV_ERR_SUCCESS
) {
963 if ((mode
& PHP_ICONV_MIME_DECODE_STRICT
)) {
970 err
= PHP_ICONV_ERR_MALFORMED
;
974 encoded_text
= p1
+ 1;
978 case 5: /* expecting an encoded portion */
980 encoded_text_len
= (size_t)(p1
- encoded_text
);
985 case 7: /* expecting a "\n" character */
990 _php_iconv_appendc(retval
, '\r', cd_pl
);
991 _php_iconv_appendc(retval
, *p1
, cd_pl
);
996 case 8: /* checking whether the following line is part of a
998 if (*p1
!= ' ' && *p1
!= '\t') {
1000 str_left
= 1; /* quit_loop */
1003 if (encoded_word
== NULL
) {
1004 _php_iconv_appendc(retval
, ' ', cd_pl
);
1010 case 6: /* expecting a End-Of-Chunk character "=" */
1012 if ((mode
& PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR
)) {
1013 /* pass the entire chunk through the converter */
1014 err
= _php_iconv_appendl(retval
, encoded_word
,
1015 (size_t)((p1
+ 1) - encoded_word
), cd_pl
);
1016 if (err
!= PHP_ICONV_ERR_SUCCESS
) {
1019 encoded_word
= NULL
;
1020 if ((mode
& PHP_ICONV_MIME_DECODE_STRICT
)) {
1027 err
= PHP_ICONV_ERR_MALFORMED
;
1032 if (str_left
== 1) {
1038 case 9: /* choice point, seeing what to do next.*/
1041 /* Handle non-RFC-compliant formats
1043 * RFC2047 requires the character that comes right
1044 * after an encoded word (chunk) to be a whitespace,
1045 * while there are lots of broken implementations that
1046 * generate such malformed headers that don't fulfill
1050 if ((mode
& PHP_ICONV_MIME_DECODE_STRICT
)) {
1051 /* pass the entire chunk through the converter */
1052 err
= _php_iconv_appendl(retval
, encoded_word
,
1053 (size_t)((p1
+ 1) - encoded_word
), cd_pl
);
1054 if (err
!= PHP_ICONV_ERR_SUCCESS
) {
1061 /* break is omitted intentionally */
1063 case '\r': case '\n': case ' ': case '\t': {
1065 switch (enc_scheme
) {
1066 case PHP_ICONV_ENC_SCHEME_BASE64
:
1068 int len
= encoded_text_len
;
1069 char *ret
= string_base64_decode(encoded_text
, len
, false);
1070 decoded
= String(ret
, len
, AttachString
);
1073 case PHP_ICONV_ENC_SCHEME_QPRINT
:
1075 int len
= encoded_text_len
;
1076 char *ret
= string_quoted_printable_decode(encoded_text
, len
, true);
1077 decoded
= String(ret
, len
, AttachString
);
1084 if (decoded
.isNull()) {
1085 if ((mode
& PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR
)) {
1086 /* pass the entire chunk through the converter */
1087 err
= _php_iconv_appendl(retval
, encoded_word
,
1088 (size_t)((p1
+ 1) - encoded_word
), cd_pl
);
1089 if (err
!= PHP_ICONV_ERR_SUCCESS
) {
1092 encoded_word
= NULL
;
1093 if ((mode
& PHP_ICONV_MIME_DECODE_STRICT
)) {
1100 err
= PHP_ICONV_ERR_UNKNOWN
;
1105 err
= _php_iconv_appendl(retval
, decoded
.data(), decoded
.size(), cd
);
1106 if (err
!= PHP_ICONV_ERR_SUCCESS
) {
1107 if ((mode
& PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR
)) {
1108 /* pass the entire chunk through the converter */
1109 err
= _php_iconv_appendl(retval
, encoded_word
,
1110 (size_t)(p1
- encoded_word
), cd_pl
);
1111 if (err
!= PHP_ICONV_ERR_SUCCESS
) {
1114 encoded_word
= NULL
;
1120 if (eos
) { /* reached end-of-string. done. */
1126 case '\r': /* part of an EOL sequence? */
1134 case '=': /* first letter of an encoded chunk */
1138 case ' ': case '\t': /* medial whitespaces */
1143 default: /* first letter of a non-encoded word */
1144 _php_iconv_appendc(retval
, *p1
, cd_pl
);
1152 case 10: /* expects a language specifier. dismiss it for now */
1158 case 11: /* expecting a chunk of whitespaces */
1160 case '\r': /* part of an EOL sequence? */
1168 case '=': /* first letter of an encoded chunk */
1169 if (spaces
!= NULL
&& encoded_word
== NULL
) {
1170 _php_iconv_appendl(retval
, spaces
, (size_t)(p1
- spaces
), cd_pl
);
1177 case ' ': case '\t':
1180 default: /* first letter of a non-encoded word */
1181 if (spaces
!= NULL
) {
1182 _php_iconv_appendl(retval
, spaces
, (size_t)(p1
- spaces
), cd_pl
);
1185 _php_iconv_appendc(retval
, *p1
, cd_pl
);
1186 encoded_word
= NULL
;
1187 if ((mode
& PHP_ICONV_MIME_DECODE_STRICT
)) {
1196 case 12: /* expecting a non-encoded word */
1198 case '\r': /* part of an EOL sequence? */
1206 case ' ': case '\t':
1211 case '=': /* first letter of an encoded chunk */
1212 if (!(mode
& PHP_ICONV_MIME_DECODE_STRICT
)) {
1217 /* break is omitted intentionally */
1220 _php_iconv_appendc(retval
, *p1
, cd_pl
);
1226 switch (scan_stat
) {
1227 case 0: case 8: case 11: case 12:
1230 if ((mode
& PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR
)) {
1231 if (scan_stat
== 1) {
1232 _php_iconv_appendc(retval
, '=', cd_pl
);
1234 err
= PHP_ICONV_ERR_SUCCESS
;
1236 err
= PHP_ICONV_ERR_MALFORMED
;
1241 if (next_pos
!= NULL
) {
1246 if (cd
!= (iconv_t
)(-1)) {
1249 if (cd_pl
!= (iconv_t
)(-1)) {
1255 ///////////////////////////////////////////////////////////////////////////////
1259 s_input_charset("input-charset"),
1260 s_output_charset("output-charset"),
1261 s_line_length("line-length"),
1262 s_line_break_chars("line-break-chars");
1264 Variant
f_iconv_mime_encode(CStrRef field_name
, CStrRef field_value
,
1265 CVarRef preferences
/* = null_variant */) {
1266 php_iconv_enc_scheme_t scheme_id
= PHP_ICONV_ENC_SCHEME_BASE64
;
1270 String lfchars
= "\r\n";
1274 if (!preferences
.isNull()) {
1275 Variant scheme
= preferences
[s_scheme
];
1276 if (scheme
.isString()) {
1277 String s
= scheme
.toString();
1278 switch (*s
.data()) {
1280 scheme_id
= PHP_ICONV_ENC_SCHEME_BASE64
;
1283 scheme_id
= PHP_ICONV_ENC_SCHEME_QPRINT
;
1288 Variant input_charset
= preferences
[s_input_charset
];
1289 if (input_charset
.isString()) {
1290 in_charset
= input_charset
.toString();
1291 if (!validate_charset(in_charset
)) return false;
1294 Variant output_charset
= preferences
[s_output_charset
];
1295 if (output_charset
.isString()) {
1296 out_charset
= output_charset
.toString();
1297 if (!validate_charset(out_charset
)) return false;
1300 Variant line_length
= preferences
[s_line_length
];
1301 if (!line_length
.isNull()) {
1302 line_len
= line_length
.toInt64();
1305 Variant line_break_chars
= preferences
[s_line_break_chars
];
1306 if (!line_break_chars
.isNull()) {
1307 lfchars
= line_break_chars
.toString();
1311 static int qp_table
[256] = {
1312 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x00 */
1313 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x10 */
1314 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x20 */
1315 1, 1, 1, 1, 1, 1, 1 ,1, 1, 1, 1, 1, 1, 3, 1, 3, /* 0x30 */
1316 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40 */
1317 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, /* 0x50 */
1318 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60 */
1319 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, /* 0x70 */
1320 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x80 */
1321 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x90 */
1322 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xA0 */
1323 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xB0 */
1324 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xC0 */
1325 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xD0 */
1326 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xE0 */
1327 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 /* 0xF0 */
1330 php_iconv_err_t err
= PHP_ICONV_ERR_SUCCESS
;
1331 iconv_t cd
= (iconv_t
)(-1), cd_pl
= (iconv_t
)(-1);
1333 if ((field_name
.size() + 2) >= line_len
||
1334 (out_charset
.size() + 12) >= line_len
) {
1335 /* field name is too long */
1336 err
= PHP_ICONV_ERR_TOO_BIG
;
1340 cd_pl
= iconv_open("ASCII", in_charset
.data());
1341 if (cd_pl
== (iconv_t
)(-1)) {
1342 #if ICONV_SUPPORTS_ERRNO
1343 if (errno
== EINVAL
) {
1344 err
= PHP_ICONV_ERR_WRONG_CHARSET
;
1346 err
= PHP_ICONV_ERR_CONVERTER
;
1349 err
= PHP_ICONV_ERR_UNKNOWN
;
1354 cd
= iconv_open(out_charset
.data(), in_charset
.data());
1355 if (cd
== (iconv_t
)(-1)) {
1356 #if ICONV_SUPPORTS_ERRNO
1357 if (errno
== EINVAL
) {
1358 err
= PHP_ICONV_ERR_WRONG_CHARSET
;
1360 err
= PHP_ICONV_ERR_CONVERTER
;
1363 err
= PHP_ICONV_ERR_UNKNOWN
;
1373 buf
= (char*)malloc(line_len
+ 5);
1374 unsigned int char_cnt
;
1375 char_cnt
= line_len
;
1377 _php_iconv_appendl(ret
, field_name
.data(), field_name
.size(), cd_pl
);
1378 char_cnt
-= field_name
.size();
1382 in_p
= field_value
.data();
1383 in_left
= field_value
.size();
1386 size_t prev_in_left
;
1389 if ((int)char_cnt
< (out_charset
.size() + 12)) {
1390 ret
.append(lfchars
); // lfchars must be encoded in ASCII here
1392 char_cnt
= line_len
- 1;
1397 ret
.append(out_charset
);
1398 char_cnt
-= out_charset
.size();
1402 switch (scheme_id
) {
1403 case PHP_ICONV_ENC_SCHEME_BASE64
:
1406 const char *ini_in_p
;
1407 size_t out_reserved
= 4;
1414 prev_in_left
= ini_in_left
= in_left
;
1417 out_size
= (char_cnt
- 2) / 4 * 3;
1422 if (out_size
<= out_reserved
) {
1423 err
= PHP_ICONV_ERR_TOO_BIG
;
1427 out_left
= out_size
- out_reserved
;
1429 if (iconv(cd
, (ICONV_CONST
char **)&in_p
, &in_left
,
1430 (char **)&out_p
, &out_left
) == (size_t)-1) {
1431 #if ICONV_SUPPORTS_ERRNO
1433 case EINVAL
: err
= PHP_ICONV_ERR_ILLEGAL_CHAR
; goto out
;
1434 case EILSEQ
: err
= PHP_ICONV_ERR_ILLEGAL_SEQ
; goto out
;
1436 if (prev_in_left
== in_left
) {
1437 err
= PHP_ICONV_ERR_TOO_BIG
;
1442 err
= PHP_ICONV_ERR_UNKNOWN
;
1446 if (prev_in_left
== in_left
) {
1447 err
= PHP_ICONV_ERR_UNKNOWN
;
1453 out_left
+= out_reserved
;
1455 if (iconv(cd
, NULL
, NULL
, (char **)&out_p
, &out_left
) ==
1457 #if ICONV_SUPPORTS_ERRNO
1458 if (errno
!= E2BIG
) {
1459 err
= PHP_ICONV_ERR_UNKNOWN
;
1463 if (out_left
!= 0) {
1464 err
= PHP_ICONV_ERR_UNKNOWN
;
1472 if (iconv(cd
, NULL
, NULL
, NULL
, NULL
) == (size_t)-1) {
1473 err
= PHP_ICONV_ERR_UNKNOWN
;
1478 in_left
= ini_in_left
;
1482 prev_in_left
= in_left
;
1485 int encoded_len
= out_size
- out_left
;
1486 char *encoded_str
= string_base64_encode(buf
, encoded_len
);
1487 String
encoded(encoded_str
, encoded_len
, AttachString
);
1488 if ((int)char_cnt
< encoded
.size()) {
1489 /* something went wrong! */
1490 err
= PHP_ICONV_ERR_UNKNOWN
;
1494 ret
.append(encoded
);
1495 char_cnt
-= encoded
.size();
1499 break; /* case PHP_ICONV_ENC_SCHEME_BASE64: */
1501 case PHP_ICONV_ENC_SCHEME_QPRINT
:
1504 const char *ini_in_p
;
1505 const unsigned char *p
;
1506 size_t nbytes_required
;
1513 prev_in_left
= ini_in_left
= in_left
;
1516 for (out_size
= char_cnt
; out_size
> 0;) {
1517 size_t prev_out_left ATTRIBUTE_UNUSED
;
1519 nbytes_required
= 0;
1522 out_left
= out_size
;
1524 if (iconv(cd
, (ICONV_CONST
char **)&in_p
, &in_left
,
1525 (char **)&out_p
, &out_left
) == (size_t)-1) {
1526 #if ICONV_SUPPORTS_ERRNO
1528 case EINVAL
: err
= PHP_ICONV_ERR_ILLEGAL_CHAR
; goto out
;
1529 case EILSEQ
: err
= PHP_ICONV_ERR_ILLEGAL_SEQ
; goto out
;
1531 if (prev_in_left
== in_left
) {
1532 err
= PHP_ICONV_ERR_UNKNOWN
;
1537 err
= PHP_ICONV_ERR_UNKNOWN
;
1541 if (prev_in_left
== in_left
) {
1542 err
= PHP_ICONV_ERR_UNKNOWN
;
1548 prev_out_left
= out_left
;
1549 if (iconv(cd
, NULL
, NULL
, (char **)&out_p
, &out_left
) ==
1551 #if ICONV_SUPPORTS_ERRNO
1552 if (errno
!= E2BIG
) {
1553 err
= PHP_ICONV_ERR_UNKNOWN
;
1557 if (out_left
== prev_out_left
) {
1558 err
= PHP_ICONV_ERR_UNKNOWN
;
1564 for (p
= (unsigned char *)buf
; p
< (unsigned char *)out_p
; p
++) {
1565 nbytes_required
+= qp_table
[*p
];
1568 if (nbytes_required
<= char_cnt
- 2) {
1572 out_size
-= ((nbytes_required
- (char_cnt
- 2)) + 1) / (3 - 1);
1573 in_left
= ini_in_left
;
1577 for (p
= (unsigned char *)buf
; p
< (unsigned char *)out_p
; p
++) {
1578 if (qp_table
[*p
] == 1) {
1579 ret
.append(*(char*)p
);
1582 static char qp_digits
[] = "0123456789ABCDEF";
1584 ret
.append(qp_digits
[(*p
>> 4) & 0x0f]);
1585 ret
.append(qp_digits
[(*p
& 0x0f)]);
1589 prev_in_left
= in_left
;
1594 if (iconv(cd
, NULL
, NULL
, NULL
, NULL
) == (size_t)-1) {
1595 err
= PHP_ICONV_ERR_UNKNOWN
;
1599 } break; /* case PHP_ICONV_ENC_SCHEME_QPRINT: */
1601 } while (in_left
> 0);
1604 if (cd
!= (iconv_t
)(-1)) {
1607 if (cd_pl
!= (iconv_t
)(-1)) {
1614 if (err
!= PHP_ICONV_ERR_SUCCESS
) {
1617 return ret
.detach();
1620 Variant
f_iconv_mime_decode(CStrRef encoded_string
, int mode
/* = 0 */,
1621 CStrRef charset
/* = null_string */) {
1622 Variant encoded
= check_charset(charset
);
1623 if (same(encoded
, false)) return false;
1624 String enc
= encoded
.toString();
1625 StringBuffer retval
;
1626 php_iconv_err_t err
=
1627 _php_iconv_mime_decode(retval
, encoded_string
.data(),
1628 encoded_string
.size(), enc
.data(), NULL
, mode
);
1629 _php_iconv_show_error(err
, enc
.data(), "???");
1631 if (err
== PHP_ICONV_ERR_SUCCESS
) {
1632 return retval
.detach();
1637 Variant
f_iconv_mime_decode_headers(CStrRef encoded_headers
,
1639 CStrRef charset
/* = null_string */) {
1640 Variant encoded
= check_charset(charset
);
1641 if (same(encoded
, false)) return false;
1642 String enc
= encoded
.toString();
1644 php_iconv_err_t err
= PHP_ICONV_ERR_SUCCESS
;
1645 const char *encoded_str
= encoded_headers
.data();
1646 int encoded_str_len
= encoded_headers
.size();
1647 while (encoded_str_len
> 0) {
1648 StringBuffer decoded_header
;
1650 const char *header_name
= NULL
;
1651 size_t header_name_len
= 0;
1652 const char *header_value
= NULL
;
1653 size_t header_value_len
= 0;
1654 const char *p
, *limit
;
1656 const char *next_pos
;
1657 err
= _php_iconv_mime_decode(decoded_header
, encoded_str
, encoded_str_len
,
1658 enc
.data(), &next_pos
, mode
);
1659 if (err
!= PHP_ICONV_ERR_SUCCESS
|| decoded_header
.data() == NULL
) {
1663 limit
= decoded_header
.data() + decoded_header
.size();
1664 for (p
= decoded_header
.data(); p
< limit
; p
++) {
1667 header_name
= decoded_header
.data();
1668 header_name_len
= p
- decoded_header
.data();
1670 while (++p
< limit
) {
1671 if (*p
!= ' ' && *p
!= '\t') {
1677 header_value_len
= limit
- p
;
1682 if (header_name
!= NULL
) {
1683 String
header(header_name
, header_name_len
, CopyString
);
1684 String
value(header_value
, header_value_len
, CopyString
);
1685 if (ret
.exists(header
)) {
1686 Variant elem
= ret
[header
];
1687 if (!elem
.is(KindOfArray
)) {
1688 ret
.set(header
, CREATE_VECTOR2(elem
, value
));
1691 ret
.set(header
, elem
);
1694 ret
.set(header
, value
);
1697 encoded_str_len
-= next_pos
- encoded_str
;
1698 encoded_str
= next_pos
;
1701 if (err
!= PHP_ICONV_ERR_SUCCESS
) {
1702 _php_iconv_show_error(err
, enc
.data(), "???");
1709 s_input_encoding("input_encoding"),
1710 s_output_encoding("output_encoding"),
1711 s_internal_encoding("internal_encoding"),
1715 Variant
f_iconv_get_encoding(CStrRef type
/* = "all" */) {
1716 if (type
== s_all
) {
1718 ret
.set(s_input_encoding
, ICONVG(input_encoding
));
1719 ret
.set(s_output_encoding
, ICONVG(output_encoding
));
1720 ret
.set(s_internal_encoding
, ICONVG(internal_encoding
));
1723 if (type
== s_input_encoding
) return ICONVG(input_encoding
);
1724 if (type
== s_output_encoding
) return ICONVG(output_encoding
);
1725 if (type
== s_internal_encoding
) return ICONVG(internal_encoding
);
1729 bool f_iconv_set_encoding(CStrRef type
, CStrRef charset
) {
1730 if (!validate_charset(charset
)) return false;
1731 if (type
== s_input_encoding
) {
1732 ICONVG(input_encoding
) = charset
;
1733 } else if (type
== s_output_encoding
) {
1734 ICONVG(output_encoding
) = charset
;
1735 } else if (type
== s_internal_encoding
) {
1736 ICONVG(internal_encoding
) = charset
;
1743 Variant
f_iconv(CStrRef in_charset
, CStrRef out_charset
, CStrRef str
) {
1744 if (!validate_charset(in_charset
)) return false;
1745 if (!validate_charset(out_charset
)) return false;
1749 php_iconv_err_t err
=
1750 php_iconv_string(str
.data(), str
.size(), &out_buffer
, &out_len
,
1751 out_charset
.data(), in_charset
.data());
1752 _php_iconv_show_error(err
, out_charset
.data(), in_charset
.data());
1753 if (out_buffer
!= NULL
) {
1754 return String(out_buffer
, out_len
, AttachString
);
1759 Variant
f_iconv_strlen(CStrRef str
, CStrRef charset
/* = null_string */) {
1760 Variant encoded
= check_charset(charset
);
1761 if (same(encoded
, false)) return false;
1762 String enc
= encoded
.toString();
1763 unsigned int retval
;
1764 php_iconv_err_t err
= _php_iconv_strlen(&retval
, str
.data(), str
.size(),
1766 _php_iconv_show_error(err
, GENERIC_SUPERSET_NAME
, enc
.data());
1767 if (err
== PHP_ICONV_ERR_SUCCESS
) {
1768 return (int64_t)retval
;
1773 Variant
f_iconv_strpos(CStrRef haystack
, CStrRef needle
, int offset
/* = 0 */,
1774 CStrRef charset
/* = null_string */) {
1776 raise_warning("Offset not contained in string.");
1779 if (needle
.size() < 1) {
1783 Variant encoded
= check_charset(charset
);
1784 if (same(encoded
, false)) return false;
1785 String enc
= encoded
.toString();
1786 unsigned int retval
;
1787 php_iconv_err_t err
=
1788 _php_iconv_strpos(&retval
, haystack
.data(), haystack
.size(),
1789 needle
.data(), needle
.size(), offset
, enc
.data());
1790 _php_iconv_show_error(err
, GENERIC_SUPERSET_NAME
, enc
.data());
1791 if (err
== PHP_ICONV_ERR_SUCCESS
&& retval
!= (unsigned int)-1) {
1792 return (long)retval
;
1797 Variant
f_iconv_strrpos(CStrRef haystack
, CStrRef needle
,
1798 CStrRef charset
/* = null_string */) {
1799 if (needle
.size() < 1) {
1803 Variant encoded
= check_charset(charset
);
1804 if (same(encoded
, false)) return false;
1805 String enc
= encoded
.toString();
1806 unsigned int retval
;
1807 php_iconv_err_t err
=
1808 _php_iconv_strpos(&retval
, haystack
.data(), haystack
.size(),
1809 needle
.data(), needle
.size(), -1, enc
.data());
1810 _php_iconv_show_error(err
, GENERIC_SUPERSET_NAME
, enc
.data());
1811 if (err
== PHP_ICONV_ERR_SUCCESS
&& retval
!= (unsigned int)-1) {
1812 return (long)retval
;
1817 Variant
f_iconv_substr(CStrRef str
, int offset
, int length
/* = INT_MAX */,
1818 CStrRef charset
/* = null_string */) {
1819 Variant encoded
= check_charset(charset
);
1820 if (same(encoded
, false)) return false;
1821 String enc
= encoded
.toString();
1822 StringBuffer retval
;
1823 php_iconv_err_t err
= _php_iconv_substr(retval
, str
.data(), str
.size(),
1824 offset
, length
, enc
.data());
1825 _php_iconv_show_error(err
, GENERIC_SUPERSET_NAME
, enc
.data());
1826 if (err
== PHP_ICONV_ERR_SUCCESS
&& !str
.empty() && retval
.data()) {
1827 return retval
.detach();
1832 String
f_ob_iconv_handler(CStrRef contents
, int status
) {
1833 String mimetype
= g_context
->getMimeType();
1834 if (!mimetype
.empty()) {
1837 php_iconv_err_t err
=
1838 php_iconv_string(contents
.data(), contents
.size(), &out_buffer
, &out_len
,
1839 ICONVG(output_encoding
).c_str(),
1840 ICONVG(internal_encoding
).c_str());
1841 _php_iconv_show_error(err
, ICONVG(output_encoding
).c_str(),
1842 ICONVG(internal_encoding
).c_str());
1843 if (out_buffer
!= NULL
) {
1844 g_context
->setContentType(mimetype
, ICONVG(output_encoding
));
1845 return String(out_buffer
, out_len
, AttachString
);
1851 ///////////////////////////////////////////////////////////////////////////////