mirror of
https://github.com/php/php-src.git
synced 2024-12-16 05:15:03 +08:00
Fix #16069. Patch by Moriyoshi Koizumi <readjust@deneb.freemail.ne.jp>
@ Made iconv() work well with libiconv or libgconv. (Moriyoshi, Yasuo)
This commit is contained in:
parent
4d69e91806
commit
2e77bb3072
@ -8,6 +8,41 @@ PHP_ARG_WITH(iconv, for iconv support,
|
||||
if test "$PHP_ICONV" != "no"; then
|
||||
|
||||
PHP_SETUP_ICONV(ICONV_SHARED_LIBADD, [
|
||||
AC_MSG_CHECKING([if iconv supports errno])
|
||||
AC_TRY_RUN([
|
||||
#define LIBICONV_PLUG
|
||||
#include <iconv.h>
|
||||
#include <errno.h>
|
||||
#if defined(_LIBICONV_H)
|
||||
#define icv_open(a, b) libiconv_open(a, b)
|
||||
#define icv_close(a) libiconv_close(a)
|
||||
#define icv(a, b, c, d, e) libiconv(a, b, c, d, e)
|
||||
#else
|
||||
#define icv_open(a, b) iconv_open(a, b)
|
||||
#define icv_close(a) iconv_close(a)
|
||||
#define icv(a, b, c, d, e) iconv(a, b, c, d, e)
|
||||
#endif
|
||||
|
||||
int main() {
|
||||
iconv_t cd;
|
||||
cd = icv_open( "*blahblah*", "*blahblah*" );
|
||||
if( cd == (iconv_t)(-1) ) {
|
||||
if( errno == EINVAL ) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
icv_close( cd );
|
||||
return 2;
|
||||
}
|
||||
],[
|
||||
AC_MSG_RESULT(yes)
|
||||
PHP_DEFINE(ICONV_SUPPORTS_ERRNO)
|
||||
],[
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
|
||||
PHP_NEW_EXTENSION(iconv, iconv.c, $ext_shared)
|
||||
PHP_SUBST(ICONV_SHARED_LIBADD)
|
||||
], [
|
||||
|
@ -28,6 +28,7 @@
|
||||
#ifdef PHP_ATOM_INC
|
||||
#include "php_have_iconv.h"
|
||||
#include "php_have_libiconv.h"
|
||||
#include "php_iconv_supports_errno.h"
|
||||
#endif
|
||||
|
||||
#if HAVE_ICONV
|
||||
@ -49,6 +50,7 @@
|
||||
|
||||
|
||||
#if HAVE_LIBICONV
|
||||
#define LIBICONV_PLUG
|
||||
#define icv_open(a, b) libiconv_open(a, b)
|
||||
#define icv_close(a) libiconv_close(a)
|
||||
#define icv(a, b, c, d, e) libiconv(a, b, c, d, e)
|
||||
@ -145,8 +147,7 @@ static int php_iconv_string(const char *in_p, size_t in_len,
|
||||
char **out, size_t *out_len,
|
||||
const char *in_charset, const char *out_charset, int *err TSRMLS_DC)
|
||||
{
|
||||
#if HAVE_LIBICONV
|
||||
/* No errno for libiconv(?) */
|
||||
#if !defined(ICONV_SUPPORTS_ERRNO)
|
||||
unsigned int in_size, out_size, out_left;
|
||||
char *out_buffer, *out_p;
|
||||
iconv_t cd;
|
||||
@ -163,9 +164,9 @@ static int php_iconv_string(const char *in_p, size_t in_len,
|
||||
a single char can be more than 4 bytes.
|
||||
I added 15 extra bytes for safety. <yohgaki@php.net>
|
||||
*/
|
||||
out_size = in_len * sizeof(ucs4_t) + 16;
|
||||
out_buffer = (char *) emalloc(out_size);
|
||||
|
||||
out_size = in_len * sizeof(ucs4_t) + 15;
|
||||
out_buffer = (char *) emalloc(out_size + 1);
|
||||
|
||||
*out = out_buffer;
|
||||
out_p = out_buffer;
|
||||
out_left = out_size;
|
||||
@ -197,71 +198,78 @@ static int php_iconv_string(const char *in_p, size_t in_len,
|
||||
|
||||
#else
|
||||
/*
|
||||
libc iconv should support errno. Handle it better way.
|
||||
iconv supports errno. Handle it better way.
|
||||
*/
|
||||
iconv_t cd;
|
||||
size_t in_left, out_size, out_left;
|
||||
char *out_p, *out_buf, *tmp_buf;
|
||||
size_t i, bsz, result;
|
||||
size_t bsz, result;
|
||||
|
||||
*err = 0;
|
||||
cd = iconv_open(out_charset, in_charset);
|
||||
cd = icv_open(out_charset, in_charset);
|
||||
|
||||
if (cd == (iconv_t)(-1)) {
|
||||
if (errno == EINVAL) {
|
||||
*err = PHP_ICONV_WRONG_CHARSET;
|
||||
php_error(E_NOTICE, "%s() wrong charset, cannot convert from `%s' to `%s'",
|
||||
php_error(E_NOTICE, "%s(): wrong charset, cannot convert from `%s' to `%s'",
|
||||
get_active_function_name(TSRMLS_C), in_charset, out_charset);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
*err = PHP_ICONV_CONVERTER;
|
||||
php_error(E_NOTICE, "%s() cannot open converter",
|
||||
php_error(E_NOTICE, "%s(): cannot open converter",
|
||||
get_active_function_name(TSRMLS_C));
|
||||
}
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
in_left= in_len;
|
||||
out_left = in_len + 32; /* Avoid realloc() most cases */
|
||||
out_size = 0;
|
||||
bsz = out_left;
|
||||
out_buf = (char *) emalloc(bsz+1);
|
||||
out_p = out_buf;
|
||||
result = iconv(cd, (char **)&in_p, &in_left, (char **) &out_p, &out_left);
|
||||
out_size = bsz - out_left;
|
||||
for (i = 2;in_left > 0 && errno == E2BIG; i++) {
|
||||
/* converted string is longer than out buffer */
|
||||
tmp_buf = (char*)erealloc(out_buf, bsz*i+1);
|
||||
if (tmp_buf == NULL) {
|
||||
break;
|
||||
|
||||
while(in_left > 0) {
|
||||
result = icv(cd, (char **)&in_p, &in_left, (char **) &out_p, &out_left);
|
||||
out_size = bsz - out_left;
|
||||
if( result == (size_t)(-1) ) {
|
||||
if( errno == E2BIG && in_left > 0 ) {
|
||||
/* converted string is longer than out buffer */
|
||||
bsz += in_len;
|
||||
|
||||
tmp_buf = (char*) erealloc(out_buf, bsz+1);
|
||||
|
||||
if (tmp_buf != NULL) {
|
||||
out_p = out_buf = tmp_buf;
|
||||
out_p += out_size;
|
||||
out_left = bsz - out_size;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
out_buf = tmp_buf;
|
||||
out_p = tmp_buf;
|
||||
out_p += out_size;
|
||||
out_left = bsz;
|
||||
result = iconv(cd, (char **)&in_p, &in_left, &out_p, &out_left);
|
||||
out_size += bsz - out_left;
|
||||
break;
|
||||
}
|
||||
iconv_close(cd);
|
||||
icv_close(cd);
|
||||
|
||||
if (result == (size_t)(-1)) {
|
||||
switch (errno) {
|
||||
case EINVAL:
|
||||
php_error(E_NOTICE, "%s() detected incomplete character in input string",
|
||||
php_error(E_NOTICE, "%s(): detected incomplete character in input string",
|
||||
get_active_function_name(TSRMLS_C));
|
||||
*err = PHP_ICONV_ILLEGAL_CHAR;
|
||||
break;
|
||||
case EILSEQ:
|
||||
php_error(E_NOTICE, "%s() detected illegal character in input string",
|
||||
php_error(E_NOTICE, "%s(): detected illegal character in input string",
|
||||
get_active_function_name(TSRMLS_C));
|
||||
*err = PHP_ICONV_ILLEGAL_SEQ;
|
||||
break;
|
||||
case E2BIG:
|
||||
/* should not happen */
|
||||
php_error(E_WARNING, "%s() run out buffer",
|
||||
php_error(E_WARNING, "%s(): run out buffer",
|
||||
get_active_function_name(TSRMLS_C));
|
||||
*err = PHP_ICONV_TOO_BIG;
|
||||
break;
|
||||
default:
|
||||
/* other error */
|
||||
php_error(E_NOTICE, "%s() unknown error (%d)",
|
||||
php_error(E_NOTICE, "%s(): unknown error (%d)",
|
||||
get_active_function_name(TSRMLS_C), errno);
|
||||
*err = PHP_ICONV_UNKNOWN;
|
||||
efree(out_buf);
|
||||
|
Loading…
Reference in New Issue
Block a user