PageRenderTime 54ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/ext/iconv/iconv.c

http://github.com/php/php-src
C | 2702 lines | 2121 code | 426 blank | 155 comment | 609 complexity | af2b4d2a1daf2d7583a1132eb7171bd7 MD5 | raw file
Possible License(s): BSD-2-Clause, BSD-3-Clause, MPL-2.0-no-copyleft-exception, LGPL-2.1

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. +----------------------------------------------------------------------+
  3. | Copyright (c) The PHP Group |
  4. +----------------------------------------------------------------------+
  5. | This source file is subject to version 3.01 of the PHP license, |
  6. | that is bundled with this package in the file LICENSE, and is |
  7. | available through the world-wide-web at the following url: |
  8. | http://www.php.net/license/3_01.txt |
  9. | If you did not receive a copy of the PHP license and are unable to |
  10. | obtain it through the world-wide-web, please send a note to |
  11. | license@php.net so we can mail you a copy immediately. |
  12. +----------------------------------------------------------------------+
  13. | Authors: Rui Hirokawa <rui_hirokawa@ybb.ne.jp> |
  14. | Stig Bakken <ssb@php.net> |
  15. | Moriyoshi Koizumi <moriyoshi@php.net> |
  16. +----------------------------------------------------------------------+
  17. */
  18. #ifdef HAVE_CONFIG_H
  19. #include "config.h"
  20. #endif
  21. #include "php.h"
  22. #include "php_globals.h"
  23. #include "ext/standard/info.h"
  24. #include "main/php_output.h"
  25. #include "SAPI.h"
  26. #include "php_ini.h"
  27. #include <stdlib.h>
  28. #include <errno.h>
  29. #include "php_iconv.h"
  30. #ifdef HAVE_ICONV
  31. #ifdef PHP_ICONV_H_PATH
  32. #include PHP_ICONV_H_PATH
  33. #else
  34. #include <iconv.h>
  35. #endif
  36. #ifdef HAVE_GLIBC_ICONV
  37. #include <gnu/libc-version.h>
  38. #endif
  39. #ifdef HAVE_LIBICONV
  40. #undef iconv
  41. #endif
  42. #include "zend_smart_str.h"
  43. #include "ext/standard/base64.h"
  44. #include "ext/standard/quot_print.h"
  45. #include "iconv_arginfo.h"
  46. #define _php_iconv_memequal(a, b, c) \
  47. (memcmp(a, b, c) == 0)
  48. ZEND_DECLARE_MODULE_GLOBALS(iconv)
  49. static PHP_GINIT_FUNCTION(iconv);
  50. /* {{{ iconv_module_entry
  51. */
  52. zend_module_entry iconv_module_entry = {
  53. STANDARD_MODULE_HEADER,
  54. "iconv",
  55. ext_functions,
  56. PHP_MINIT(miconv),
  57. PHP_MSHUTDOWN(miconv),
  58. NULL,
  59. NULL,
  60. PHP_MINFO(miconv),
  61. PHP_ICONV_VERSION,
  62. PHP_MODULE_GLOBALS(iconv),
  63. PHP_GINIT(iconv),
  64. NULL,
  65. NULL,
  66. STANDARD_MODULE_PROPERTIES_EX
  67. };
  68. /* }}} */
  69. #ifdef COMPILE_DL_ICONV
  70. #ifdef ZTS
  71. ZEND_TSRMLS_CACHE_DEFINE()
  72. #endif
  73. ZEND_GET_MODULE(iconv)
  74. #endif
  75. /* {{{ PHP_GINIT_FUNCTION */
  76. static PHP_GINIT_FUNCTION(iconv)
  77. {
  78. #if defined(COMPILE_DL_ICONV) && defined(ZTS)
  79. ZEND_TSRMLS_CACHE_UPDATE();
  80. #endif
  81. iconv_globals->input_encoding = NULL;
  82. iconv_globals->output_encoding = NULL;
  83. iconv_globals->internal_encoding = NULL;
  84. }
  85. /* }}} */
  86. #if defined(HAVE_LIBICONV) && defined(ICONV_ALIASED_LIBICONV)
  87. #define iconv libiconv
  88. #endif
  89. /* {{{ typedef enum php_iconv_enc_scheme_t */
  90. typedef enum _php_iconv_enc_scheme_t {
  91. PHP_ICONV_ENC_SCHEME_BASE64,
  92. PHP_ICONV_ENC_SCHEME_QPRINT
  93. } php_iconv_enc_scheme_t;
  94. /* }}} */
  95. #define PHP_ICONV_MIME_DECODE_STRICT (1<<0)
  96. #define PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR (1<<1)
  97. /* {{{ prototypes */
  98. static php_iconv_err_t _php_iconv_appendl(smart_str *d, const char *s, size_t l, iconv_t cd);
  99. static php_iconv_err_t _php_iconv_appendc(smart_str *d, const char c, iconv_t cd);
  100. static void _php_iconv_show_error(php_iconv_err_t err, const char *out_charset, const char *in_charset);
  101. static php_iconv_err_t _php_iconv_strlen(size_t *pretval, const char *str, size_t nbytes, const char *enc);
  102. static php_iconv_err_t _php_iconv_substr(smart_str *pretval, const char *str, size_t nbytes, zend_long offset, zend_long len, const char *enc);
  103. static php_iconv_err_t _php_iconv_strpos(size_t *pretval, const char *haystk, size_t haystk_nbytes, const char *ndl, size_t ndl_nbytes, zend_long offset, const char *enc);
  104. static php_iconv_err_t _php_iconv_mime_encode(smart_str *pretval, const char *fname, size_t fname_nbytes, const char *fval, size_t fval_nbytes, size_t max_line_len, const char *lfchars, php_iconv_enc_scheme_t enc_scheme, const char *out_charset, const char *enc);
  105. 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);
  106. static php_iconv_err_t php_iconv_stream_filter_register_factory(void);
  107. static php_iconv_err_t php_iconv_stream_filter_unregister_factory(void);
  108. static int php_iconv_output_conflict(const char *handler_name, size_t handler_name_len);
  109. static php_output_handler *php_iconv_output_handler_init(const char *name, size_t name_len, size_t chunk_size, int flags);
  110. static int php_iconv_output_handler(void **nothing, php_output_context *output_context);
  111. /* }}} */
  112. /* {{{ static globals */
  113. static const char _generic_superset_name[] = ICONV_UCS4_ENCODING;
  114. #define GENERIC_SUPERSET_NAME _generic_superset_name
  115. #define GENERIC_SUPERSET_NBYTES 4
  116. /* }}} */
  117. static PHP_INI_MH(OnUpdateInputEncoding)
  118. {
  119. if (ZSTR_LEN(new_value) >= ICONV_CSNMAXLEN) {
  120. return FAILURE;
  121. }
  122. if (stage & (PHP_INI_STAGE_ACTIVATE | PHP_INI_STAGE_RUNTIME)) {
  123. php_error_docref("ref.iconv", E_DEPRECATED, "Use of iconv.input_encoding is deprecated");
  124. }
  125. OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
  126. return SUCCESS;
  127. }
  128. static PHP_INI_MH(OnUpdateOutputEncoding)
  129. {
  130. if (ZSTR_LEN(new_value) >= ICONV_CSNMAXLEN) {
  131. return FAILURE;
  132. }
  133. if (stage & (PHP_INI_STAGE_ACTIVATE | PHP_INI_STAGE_RUNTIME)) {
  134. php_error_docref("ref.iconv", E_DEPRECATED, "Use of iconv.output_encoding is deprecated");
  135. }
  136. OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
  137. return SUCCESS;
  138. }
  139. static PHP_INI_MH(OnUpdateInternalEncoding)
  140. {
  141. if (ZSTR_LEN(new_value) >= ICONV_CSNMAXLEN) {
  142. return FAILURE;
  143. }
  144. if (stage & (PHP_INI_STAGE_ACTIVATE | PHP_INI_STAGE_RUNTIME)) {
  145. php_error_docref("ref.iconv", E_DEPRECATED, "Use of iconv.internal_encoding is deprecated");
  146. }
  147. OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
  148. return SUCCESS;
  149. }
  150. /* {{{ PHP_INI
  151. */
  152. PHP_INI_BEGIN()
  153. STD_PHP_INI_ENTRY("iconv.input_encoding", "", PHP_INI_ALL, OnUpdateInputEncoding, input_encoding, zend_iconv_globals, iconv_globals)
  154. STD_PHP_INI_ENTRY("iconv.output_encoding", "", PHP_INI_ALL, OnUpdateOutputEncoding, output_encoding, zend_iconv_globals, iconv_globals)
  155. STD_PHP_INI_ENTRY("iconv.internal_encoding", "", PHP_INI_ALL, OnUpdateInternalEncoding, internal_encoding, zend_iconv_globals, iconv_globals)
  156. PHP_INI_END()
  157. /* }}} */
  158. /* {{{ PHP_MINIT_FUNCTION */
  159. PHP_MINIT_FUNCTION(miconv)
  160. {
  161. char *version = "unknown";
  162. REGISTER_INI_ENTRIES();
  163. #if HAVE_LIBICONV
  164. {
  165. static char buf[16];
  166. snprintf(buf, sizeof(buf), "%d.%d",
  167. _libiconv_version >> 8, _libiconv_version & 0xff);
  168. version = buf;
  169. }
  170. #elif HAVE_GLIBC_ICONV
  171. version = (char *)gnu_get_libc_version();
  172. #endif
  173. #ifdef PHP_ICONV_IMPL
  174. REGISTER_STRING_CONSTANT("ICONV_IMPL", PHP_ICONV_IMPL, CONST_CS | CONST_PERSISTENT);
  175. #elif HAVE_LIBICONV
  176. REGISTER_STRING_CONSTANT("ICONV_IMPL", "libiconv", CONST_CS | CONST_PERSISTENT);
  177. #else
  178. REGISTER_STRING_CONSTANT("ICONV_IMPL", "unknown", CONST_CS | CONST_PERSISTENT);
  179. #endif
  180. REGISTER_STRING_CONSTANT("ICONV_VERSION", version, CONST_CS | CONST_PERSISTENT);
  181. REGISTER_LONG_CONSTANT("ICONV_MIME_DECODE_STRICT", PHP_ICONV_MIME_DECODE_STRICT, CONST_CS | CONST_PERSISTENT);
  182. REGISTER_LONG_CONSTANT("ICONV_MIME_DECODE_CONTINUE_ON_ERROR", PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR, CONST_CS | CONST_PERSISTENT);
  183. if (php_iconv_stream_filter_register_factory() != PHP_ICONV_ERR_SUCCESS) {
  184. return FAILURE;
  185. }
  186. php_output_handler_alias_register(ZEND_STRL("ob_iconv_handler"), php_iconv_output_handler_init);
  187. php_output_handler_conflict_register(ZEND_STRL("ob_iconv_handler"), php_iconv_output_conflict);
  188. return SUCCESS;
  189. }
  190. /* }}} */
  191. /* {{{ PHP_MSHUTDOWN_FUNCTION */
  192. PHP_MSHUTDOWN_FUNCTION(miconv)
  193. {
  194. php_iconv_stream_filter_unregister_factory();
  195. UNREGISTER_INI_ENTRIES();
  196. return SUCCESS;
  197. }
  198. /* }}} */
  199. /* {{{ PHP_MINFO_FUNCTION */
  200. PHP_MINFO_FUNCTION(miconv)
  201. {
  202. zval *iconv_impl, *iconv_ver;
  203. iconv_impl = zend_get_constant_str("ICONV_IMPL", sizeof("ICONV_IMPL")-1);
  204. iconv_ver = zend_get_constant_str("ICONV_VERSION", sizeof("ICONV_VERSION")-1);
  205. php_info_print_table_start();
  206. php_info_print_table_row(2, "iconv support", "enabled");
  207. php_info_print_table_row(2, "iconv implementation", Z_STRVAL_P(iconv_impl));
  208. php_info_print_table_row(2, "iconv library version", Z_STRVAL_P(iconv_ver));
  209. php_info_print_table_end();
  210. DISPLAY_INI_ENTRIES();
  211. }
  212. /* }}} */
  213. static const char *get_internal_encoding(void) {
  214. if (ICONVG(internal_encoding) && ICONVG(internal_encoding)[0]) {
  215. return ICONVG(internal_encoding);
  216. }
  217. return php_get_internal_encoding();
  218. }
  219. static const char *get_input_encoding(void) {
  220. if (ICONVG(input_encoding) && ICONVG(input_encoding)[0]) {
  221. return ICONVG(input_encoding);
  222. }
  223. return php_get_input_encoding();
  224. }
  225. static const char *get_output_encoding(void) {
  226. if (ICONVG(output_encoding) && ICONVG(output_encoding)[0]) {
  227. return ICONVG(output_encoding);
  228. }
  229. return php_get_output_encoding();
  230. }
  231. static int php_iconv_output_conflict(const char *handler_name, size_t handler_name_len)
  232. {
  233. if (php_output_get_level()) {
  234. if (php_output_handler_conflict(handler_name, handler_name_len, ZEND_STRL("ob_iconv_handler"))
  235. || php_output_handler_conflict(handler_name, handler_name_len, ZEND_STRL("mb_output_handler"))) {
  236. return FAILURE;
  237. }
  238. }
  239. return SUCCESS;
  240. }
  241. static php_output_handler *php_iconv_output_handler_init(const char *handler_name, size_t handler_name_len, size_t chunk_size, int flags)
  242. {
  243. return php_output_handler_create_internal(handler_name, handler_name_len, php_iconv_output_handler, chunk_size, flags);
  244. }
  245. static int php_iconv_output_handler(void **nothing, php_output_context *output_context)
  246. {
  247. char *s, *content_type, *mimetype = NULL;
  248. int output_status, mimetype_len = 0;
  249. if (output_context->op & PHP_OUTPUT_HANDLER_START) {
  250. output_status = php_output_get_status();
  251. if (output_status & PHP_OUTPUT_SENT) {
  252. return FAILURE;
  253. }
  254. if (SG(sapi_headers).mimetype && !strncasecmp(SG(sapi_headers).mimetype, "text/", 5)) {
  255. if ((s = strchr(SG(sapi_headers).mimetype,';')) == NULL){
  256. mimetype = SG(sapi_headers).mimetype;
  257. } else {
  258. mimetype = SG(sapi_headers).mimetype;
  259. mimetype_len = (int)(s - SG(sapi_headers).mimetype);
  260. }
  261. } else if (SG(sapi_headers).send_default_content_type) {
  262. mimetype = SG(default_mimetype) ? SG(default_mimetype) : SAPI_DEFAULT_MIMETYPE;
  263. }
  264. if (mimetype != NULL && !(output_context->op & PHP_OUTPUT_HANDLER_CLEAN)) {
  265. size_t len;
  266. char *p = strstr(get_output_encoding(), "//");
  267. if (p) {
  268. len = spprintf(&content_type, 0, "Content-Type:%.*s; charset=%.*s", mimetype_len ? mimetype_len : (int) strlen(mimetype), mimetype, (int) (p - get_output_encoding()), get_output_encoding());
  269. } else {
  270. len = spprintf(&content_type, 0, "Content-Type:%.*s; charset=%s", mimetype_len ? mimetype_len : (int) strlen(mimetype), mimetype, get_output_encoding());
  271. }
  272. if (content_type && SUCCESS == sapi_add_header(content_type, len, 0)) {
  273. SG(sapi_headers).send_default_content_type = 0;
  274. php_output_handler_hook(PHP_OUTPUT_HANDLER_HOOK_IMMUTABLE, NULL);
  275. }
  276. }
  277. }
  278. if (output_context->in.used) {
  279. zend_string *out;
  280. output_context->out.free = 1;
  281. _php_iconv_show_error(php_iconv_string(output_context->in.data, output_context->in.used, &out, get_output_encoding(), get_internal_encoding()), get_output_encoding(), get_internal_encoding());
  282. if (out) {
  283. output_context->out.data = estrndup(ZSTR_VAL(out), ZSTR_LEN(out));
  284. output_context->out.used = ZSTR_LEN(out);
  285. zend_string_efree(out);
  286. } else {
  287. output_context->out.data = NULL;
  288. output_context->out.used = 0;
  289. }
  290. }
  291. return SUCCESS;
  292. }
  293. /* {{{ _php_iconv_appendl() */
  294. static php_iconv_err_t _php_iconv_appendl(smart_str *d, const char *s, size_t l, iconv_t cd)
  295. {
  296. const char *in_p = s;
  297. size_t in_left = l;
  298. char *out_p;
  299. size_t out_left = 0;
  300. size_t buf_growth = 128;
  301. if (in_p != NULL) {
  302. while (in_left > 0) {
  303. out_left = buf_growth;
  304. smart_str_alloc(d, out_left, 0);
  305. out_p = ZSTR_VAL((d)->s) + ZSTR_LEN((d)->s);
  306. if (iconv(cd, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) {
  307. switch (errno) {
  308. case EINVAL:
  309. return PHP_ICONV_ERR_ILLEGAL_CHAR;
  310. case EILSEQ:
  311. return PHP_ICONV_ERR_ILLEGAL_SEQ;
  312. case E2BIG:
  313. break;
  314. default:
  315. return PHP_ICONV_ERR_UNKNOWN;
  316. }
  317. }
  318. ZSTR_LEN((d)->s) += (buf_growth - out_left);
  319. buf_growth <<= 1;
  320. }
  321. } else {
  322. for (;;) {
  323. out_left = buf_growth;
  324. smart_str_alloc(d, out_left, 0);
  325. out_p = ZSTR_VAL((d)->s) + ZSTR_LEN((d)->s);
  326. if (iconv(cd, NULL, NULL, (char **) &out_p, &out_left) == (size_t)0) {
  327. ZSTR_LEN((d)->s) += (buf_growth - out_left);
  328. break;
  329. } else {
  330. if (errno != E2BIG) {
  331. return PHP_ICONV_ERR_UNKNOWN;
  332. }
  333. }
  334. ZSTR_LEN((d)->s) += (buf_growth - out_left);
  335. buf_growth <<= 1;
  336. }
  337. }
  338. return PHP_ICONV_ERR_SUCCESS;
  339. }
  340. /* }}} */
  341. /* {{{ _php_iconv_appendc() */
  342. static php_iconv_err_t _php_iconv_appendc(smart_str *d, const char c, iconv_t cd)
  343. {
  344. return _php_iconv_appendl(d, &c, 1, cd);
  345. }
  346. /* }}} */
  347. /* {{{ */
  348. #if ICONV_BROKEN_IGNORE
  349. static int _php_check_ignore(const char *charset)
  350. {
  351. size_t clen = strlen(charset);
  352. if (clen >= 9 && strcmp("//IGNORE", charset+clen-8) == 0) {
  353. return 1;
  354. }
  355. if (clen >= 19 && strcmp("//IGNORE//TRANSLIT", charset+clen-18) == 0) {
  356. return 1;
  357. }
  358. return 0;
  359. }
  360. #else
  361. #define _php_check_ignore(x) (0)
  362. #endif
  363. /* }}} */
  364. /* {{{ php_iconv_string()
  365. */
  366. PHP_ICONV_API php_iconv_err_t php_iconv_string(const char *in_p, size_t in_len, zend_string **out, const char *out_charset, const char *in_charset)
  367. {
  368. iconv_t cd;
  369. size_t in_left, out_size, out_left;
  370. char *out_p;
  371. size_t bsz, result = 0;
  372. php_iconv_err_t retval = PHP_ICONV_ERR_SUCCESS;
  373. zend_string *out_buf;
  374. int ignore_ilseq = _php_check_ignore(out_charset);
  375. *out = NULL;
  376. cd = iconv_open(out_charset, in_charset);
  377. if (cd == (iconv_t)(-1)) {
  378. if (errno == EINVAL) {
  379. return PHP_ICONV_ERR_WRONG_CHARSET;
  380. } else {
  381. return PHP_ICONV_ERR_CONVERTER;
  382. }
  383. }
  384. in_left= in_len;
  385. out_left = in_len + 32; /* Avoid realloc() most cases */
  386. out_size = 0;
  387. bsz = out_left;
  388. out_buf = zend_string_alloc(bsz, 0);
  389. out_p = ZSTR_VAL(out_buf);
  390. while (in_left > 0) {
  391. result = iconv(cd, (char **) &in_p, &in_left, (char **) &out_p, &out_left);
  392. out_size = bsz - out_left;
  393. if (result == (size_t)(-1)) {
  394. if (ignore_ilseq && errno == EILSEQ) {
  395. if (in_left <= 1) {
  396. result = 0;
  397. } else {
  398. errno = 0;
  399. in_p++;
  400. in_left--;
  401. continue;
  402. }
  403. }
  404. if (errno == E2BIG && in_left > 0) {
  405. /* converted string is longer than out buffer */
  406. bsz += in_len;
  407. out_buf = zend_string_extend(out_buf, bsz, 0);
  408. out_p = ZSTR_VAL(out_buf);
  409. out_p += out_size;
  410. out_left = bsz - out_size;
  411. continue;
  412. }
  413. }
  414. break;
  415. }
  416. if (result != (size_t)(-1)) {
  417. /* flush the shift-out sequences */
  418. for (;;) {
  419. result = iconv(cd, NULL, NULL, (char **) &out_p, &out_left);
  420. out_size = bsz - out_left;
  421. if (result != (size_t)(-1)) {
  422. break;
  423. }
  424. if (errno == E2BIG) {
  425. bsz += 16;
  426. out_buf = zend_string_extend(out_buf, bsz, 0);
  427. out_p = ZSTR_VAL(out_buf);
  428. out_p += out_size;
  429. out_left = bsz - out_size;
  430. } else {
  431. break;
  432. }
  433. }
  434. }
  435. iconv_close(cd);
  436. if (result == (size_t)(-1)) {
  437. switch (errno) {
  438. case EINVAL:
  439. retval = PHP_ICONV_ERR_ILLEGAL_CHAR;
  440. break;
  441. case EILSEQ:
  442. retval = PHP_ICONV_ERR_ILLEGAL_SEQ;
  443. break;
  444. case E2BIG:
  445. /* should not happen */
  446. retval = PHP_ICONV_ERR_TOO_BIG;
  447. break;
  448. default:
  449. /* other error */
  450. zend_string_efree(out_buf);
  451. return PHP_ICONV_ERR_UNKNOWN;
  452. }
  453. }
  454. *out_p = '\0';
  455. ZSTR_LEN(out_buf) = out_size;
  456. *out = out_buf;
  457. return retval;
  458. }
  459. /* }}} */
  460. /* {{{ _php_iconv_strlen() */
  461. static php_iconv_err_t _php_iconv_strlen(size_t *pretval, const char *str, size_t nbytes, const char *enc)
  462. {
  463. char buf[GENERIC_SUPERSET_NBYTES*2];
  464. php_iconv_err_t err = PHP_ICONV_ERR_SUCCESS;
  465. iconv_t cd;
  466. const char *in_p;
  467. size_t in_left;
  468. char *out_p;
  469. size_t out_left;
  470. size_t cnt;
  471. int more;
  472. *pretval = (size_t)-1;
  473. cd = iconv_open(GENERIC_SUPERSET_NAME, enc);
  474. if (cd == (iconv_t)(-1)) {
  475. if (errno == EINVAL) {
  476. return PHP_ICONV_ERR_WRONG_CHARSET;
  477. } else {
  478. return PHP_ICONV_ERR_CONVERTER;
  479. }
  480. }
  481. errno = 0;
  482. out_left = 0;
  483. more = nbytes > 0;
  484. for (in_p = str, in_left = nbytes, cnt = 0; more;) {
  485. out_p = buf;
  486. out_left = sizeof(buf);
  487. more = in_left > 0;
  488. iconv(cd, more ? (char **)&in_p : NULL, more ? &in_left : NULL, (char **) &out_p, &out_left);
  489. if (out_left == sizeof(buf)) {
  490. break;
  491. } else {
  492. ZEND_ASSERT((sizeof(buf) - out_left) % GENERIC_SUPERSET_NBYTES == 0);
  493. cnt += (sizeof(buf) - out_left) / GENERIC_SUPERSET_NBYTES;
  494. }
  495. }
  496. switch (errno) {
  497. case EINVAL:
  498. err = PHP_ICONV_ERR_ILLEGAL_CHAR;
  499. break;
  500. case EILSEQ:
  501. err = PHP_ICONV_ERR_ILLEGAL_SEQ;
  502. break;
  503. case E2BIG:
  504. case 0:
  505. *pretval = cnt;
  506. break;
  507. default:
  508. err = PHP_ICONV_ERR_UNKNOWN;
  509. break;
  510. }
  511. iconv_close(cd);
  512. return err;
  513. }
  514. /* }}} */
  515. /* {{{ _php_iconv_substr() */
  516. static php_iconv_err_t _php_iconv_substr(smart_str *pretval,
  517. const char *str, size_t nbytes, zend_long offset, zend_long len, const char *enc)
  518. {
  519. char buf[GENERIC_SUPERSET_NBYTES];
  520. php_iconv_err_t err = PHP_ICONV_ERR_SUCCESS;
  521. iconv_t cd1, cd2;
  522. const char *in_p;
  523. size_t in_left;
  524. char *out_p;
  525. size_t out_left;
  526. size_t cnt;
  527. size_t total_len;
  528. int more;
  529. err = _php_iconv_strlen(&total_len, str, nbytes, enc);
  530. if (err != PHP_ICONV_ERR_SUCCESS) {
  531. return err;
  532. }
  533. if (len < 0) {
  534. if ((len += (total_len - offset)) < 0) {
  535. return PHP_ICONV_ERR_SUCCESS;
  536. }
  537. }
  538. if (offset < 0) {
  539. if ((offset += total_len) < 0) {
  540. return PHP_ICONV_ERR_SUCCESS;
  541. }
  542. }
  543. if((size_t)len > total_len) {
  544. len = total_len;
  545. }
  546. if ((size_t)offset > total_len) {
  547. return PHP_ICONV_ERR_SUCCESS;
  548. }
  549. if ((size_t)(offset + len) > total_len ) {
  550. /* trying to compute the length */
  551. len = total_len - offset;
  552. }
  553. if (len == 0) {
  554. smart_str_appendl(pretval, "", 0);
  555. smart_str_0(pretval);
  556. return PHP_ICONV_ERR_SUCCESS;
  557. }
  558. cd1 = iconv_open(GENERIC_SUPERSET_NAME, enc);
  559. if (cd1 == (iconv_t)(-1)) {
  560. if (errno == EINVAL) {
  561. return PHP_ICONV_ERR_WRONG_CHARSET;
  562. } else {
  563. return PHP_ICONV_ERR_CONVERTER;
  564. }
  565. }
  566. cd2 = (iconv_t)NULL;
  567. errno = 0;
  568. more = nbytes > 0 && len > 0;
  569. for (in_p = str, in_left = nbytes, cnt = 0; more; ++cnt) {
  570. out_p = buf;
  571. out_left = sizeof(buf);
  572. more = in_left > 0 && len > 0;
  573. iconv(cd1, more ? (char **)&in_p : NULL, more ? &in_left : NULL, (char **) &out_p, &out_left);
  574. if (out_left == sizeof(buf)) {
  575. break;
  576. }
  577. if ((zend_long)cnt >= offset) {
  578. if (cd2 == (iconv_t)NULL) {
  579. cd2 = iconv_open(enc, GENERIC_SUPERSET_NAME);
  580. if (cd2 == (iconv_t)(-1)) {
  581. cd2 = (iconv_t)NULL;
  582. if (errno == EINVAL) {
  583. err = PHP_ICONV_ERR_WRONG_CHARSET;
  584. } else {
  585. err = PHP_ICONV_ERR_CONVERTER;
  586. }
  587. break;
  588. }
  589. }
  590. if (_php_iconv_appendl(pretval, buf, sizeof(buf), cd2) != PHP_ICONV_ERR_SUCCESS) {
  591. break;
  592. }
  593. --len;
  594. }
  595. }
  596. switch (errno) {
  597. case EINVAL:
  598. err = PHP_ICONV_ERR_ILLEGAL_CHAR;
  599. break;
  600. case EILSEQ:
  601. err = PHP_ICONV_ERR_ILLEGAL_SEQ;
  602. break;
  603. case E2BIG:
  604. break;
  605. }
  606. if (err == PHP_ICONV_ERR_SUCCESS) {
  607. if (cd2 != (iconv_t)NULL) {
  608. _php_iconv_appendl(pretval, NULL, 0, cd2);
  609. }
  610. smart_str_0(pretval);
  611. }
  612. if (cd1 != (iconv_t)NULL) {
  613. iconv_close(cd1);
  614. }
  615. if (cd2 != (iconv_t)NULL) {
  616. iconv_close(cd2);
  617. }
  618. return err;
  619. }
  620. /* }}} */
  621. /* {{{ _php_iconv_strpos() */
  622. static php_iconv_err_t _php_iconv_strpos(size_t *pretval,
  623. const char *haystk, size_t haystk_nbytes,
  624. const char *ndl, size_t ndl_nbytes,
  625. zend_long offset, const char *enc)
  626. {
  627. char buf[GENERIC_SUPERSET_NBYTES];
  628. php_iconv_err_t err = PHP_ICONV_ERR_SUCCESS;
  629. iconv_t cd;
  630. const char *in_p;
  631. size_t in_left;
  632. char *out_p;
  633. size_t out_left;
  634. size_t cnt;
  635. zend_string *ndl_buf;
  636. const char *ndl_buf_p;
  637. size_t ndl_buf_left;
  638. size_t match_ofs;
  639. int more;
  640. size_t iconv_ret;
  641. *pretval = (size_t)-1;
  642. err = php_iconv_string(ndl, ndl_nbytes, &ndl_buf, GENERIC_SUPERSET_NAME, enc);
  643. if (err != PHP_ICONV_ERR_SUCCESS) {
  644. if (ndl_buf != NULL) {
  645. zend_string_efree(ndl_buf);
  646. }
  647. return err;
  648. }
  649. cd = iconv_open(GENERIC_SUPERSET_NAME, enc);
  650. if (cd == (iconv_t)(-1)) {
  651. if (ndl_buf != NULL) {
  652. zend_string_efree(ndl_buf);
  653. }
  654. if (errno == EINVAL) {
  655. return PHP_ICONV_ERR_WRONG_CHARSET;
  656. } else {
  657. return PHP_ICONV_ERR_CONVERTER;
  658. }
  659. }
  660. ndl_buf_p = ZSTR_VAL(ndl_buf);
  661. ndl_buf_left = ZSTR_LEN(ndl_buf);
  662. match_ofs = (size_t)-1;
  663. more = haystk_nbytes > 0;
  664. for (in_p = haystk, in_left = haystk_nbytes, cnt = 0; more; ++cnt) {
  665. out_p = buf;
  666. out_left = sizeof(buf);
  667. more = in_left > 0;
  668. iconv_ret = iconv(cd, more ? (char **)&in_p : NULL, more ? &in_left : NULL, (char **) &out_p, &out_left);
  669. if (out_left == sizeof(buf)) {
  670. break;
  671. }
  672. if (iconv_ret == (size_t)-1) {
  673. switch (errno) {
  674. case EINVAL:
  675. err = PHP_ICONV_ERR_ILLEGAL_CHAR;
  676. break;
  677. case EILSEQ:
  678. err = PHP_ICONV_ERR_ILLEGAL_SEQ;
  679. break;
  680. case E2BIG:
  681. break;
  682. default:
  683. err = PHP_ICONV_ERR_UNKNOWN;
  684. break;
  685. }
  686. }
  687. if (offset >= 0) {
  688. if (cnt >= (size_t)offset) {
  689. if (_php_iconv_memequal(buf, ndl_buf_p, sizeof(buf))) {
  690. if (match_ofs == (size_t)-1) {
  691. match_ofs = cnt;
  692. }
  693. ndl_buf_p += GENERIC_SUPERSET_NBYTES;
  694. ndl_buf_left -= GENERIC_SUPERSET_NBYTES;
  695. if (ndl_buf_left == 0) {
  696. *pretval = match_ofs;
  697. break;
  698. }
  699. } else {
  700. size_t i, j, lim;
  701. i = 0;
  702. j = GENERIC_SUPERSET_NBYTES;
  703. lim = (size_t)(ndl_buf_p - ZSTR_VAL(ndl_buf));
  704. while (j < lim) {
  705. if (_php_iconv_memequal(&ZSTR_VAL(ndl_buf)[j], &ZSTR_VAL(ndl_buf)[i],
  706. GENERIC_SUPERSET_NBYTES)) {
  707. i += GENERIC_SUPERSET_NBYTES;
  708. } else {
  709. j -= i;
  710. i = 0;
  711. }
  712. j += GENERIC_SUPERSET_NBYTES;
  713. }
  714. if (_php_iconv_memequal(buf, &ZSTR_VAL(ndl_buf)[i], sizeof(buf))) {
  715. match_ofs += (lim - i) / GENERIC_SUPERSET_NBYTES;
  716. i += GENERIC_SUPERSET_NBYTES;
  717. ndl_buf_p = &ZSTR_VAL(ndl_buf)[i];
  718. ndl_buf_left = ZSTR_LEN(ndl_buf) - i;
  719. } else {
  720. match_ofs = (size_t)-1;
  721. ndl_buf_p = ZSTR_VAL(ndl_buf);
  722. ndl_buf_left = ZSTR_LEN(ndl_buf);
  723. }
  724. }
  725. }
  726. } else {
  727. if (_php_iconv_memequal(buf, ndl_buf_p, sizeof(buf))) {
  728. if (match_ofs == (size_t)-1) {
  729. match_ofs = cnt;
  730. }
  731. ndl_buf_p += GENERIC_SUPERSET_NBYTES;
  732. ndl_buf_left -= GENERIC_SUPERSET_NBYTES;
  733. if (ndl_buf_left == 0) {
  734. *pretval = match_ofs;
  735. ndl_buf_p = ZSTR_VAL(ndl_buf);
  736. ndl_buf_left = ZSTR_LEN(ndl_buf);
  737. match_ofs = -1;
  738. }
  739. } else {
  740. size_t i, j, lim;
  741. i = 0;
  742. j = GENERIC_SUPERSET_NBYTES;
  743. lim = (size_t)(ndl_buf_p - ZSTR_VAL(ndl_buf));
  744. while (j < lim) {
  745. if (_php_iconv_memequal(&ZSTR_VAL(ndl_buf)[j], &ZSTR_VAL(ndl_buf)[i],
  746. GENERIC_SUPERSET_NBYTES)) {
  747. i += GENERIC_SUPERSET_NBYTES;
  748. } else {
  749. j -= i;
  750. i = 0;
  751. }
  752. j += GENERIC_SUPERSET_NBYTES;
  753. }
  754. if (_php_iconv_memequal(buf, &ZSTR_VAL(ndl_buf)[i], sizeof(buf))) {
  755. match_ofs += (lim - i) / GENERIC_SUPERSET_NBYTES;
  756. i += GENERIC_SUPERSET_NBYTES;
  757. ndl_buf_p = &ZSTR_VAL(ndl_buf)[i];
  758. ndl_buf_left = ZSTR_LEN(ndl_buf) - i;
  759. } else {
  760. match_ofs = (size_t)-1;
  761. ndl_buf_p = ZSTR_VAL(ndl_buf);
  762. ndl_buf_left = ZSTR_LEN(ndl_buf);
  763. }
  764. }
  765. }
  766. }
  767. if (ndl_buf) {
  768. zend_string_efree(ndl_buf);
  769. }
  770. iconv_close(cd);
  771. return err;
  772. }
  773. /* }}} */
  774. /* {{{ _php_iconv_mime_encode() */
  775. static php_iconv_err_t _php_iconv_mime_encode(smart_str *pretval, const char *fname, size_t fname_nbytes, const char *fval, size_t fval_nbytes, size_t max_line_len, const char *lfchars, php_iconv_enc_scheme_t enc_scheme, const char *out_charset, const char *enc)
  776. {
  777. php_iconv_err_t err = PHP_ICONV_ERR_SUCCESS;
  778. iconv_t cd = (iconv_t)(-1), cd_pl = (iconv_t)(-1);
  779. size_t char_cnt = 0;
  780. size_t out_charset_len;
  781. size_t lfchars_len;
  782. char *buf = NULL;
  783. const char *in_p;
  784. size_t in_left;
  785. char *out_p;
  786. size_t out_left;
  787. zend_string *encoded = NULL;
  788. static int qp_table[256] = {
  789. 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x00 */
  790. 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x10 */
  791. 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x20 */
  792. 1, 1, 1, 1, 1, 1, 1 ,1, 1, 1, 1, 1, 1, 3, 1, 3, /* 0x30 */
  793. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40 */
  794. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, /* 0x50 */
  795. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60 */
  796. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, /* 0x70 */
  797. 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x80 */
  798. 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x90 */
  799. 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xA0 */
  800. 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xB0 */
  801. 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xC0 */
  802. 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xD0 */
  803. 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xE0 */
  804. 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 /* 0xF0 */
  805. };
  806. out_charset_len = strlen(out_charset);
  807. lfchars_len = strlen(lfchars);
  808. if ((fname_nbytes + 2) >= max_line_len
  809. || (out_charset_len + 12) >= max_line_len) {
  810. /* field name is too long */
  811. err = PHP_ICONV_ERR_TOO_BIG;
  812. goto out;
  813. }
  814. cd_pl = iconv_open(ICONV_ASCII_ENCODING, enc);
  815. if (cd_pl == (iconv_t)(-1)) {
  816. if (errno == EINVAL) {
  817. err = PHP_ICONV_ERR_WRONG_CHARSET;
  818. } else {
  819. err = PHP_ICONV_ERR_CONVERTER;
  820. }
  821. goto out;
  822. }
  823. cd = iconv_open(out_charset, enc);
  824. if (cd == (iconv_t)(-1)) {
  825. if (errno == EINVAL) {
  826. err = PHP_ICONV_ERR_WRONG_CHARSET;
  827. } else {
  828. err = PHP_ICONV_ERR_CONVERTER;
  829. }
  830. goto out;
  831. }
  832. buf = safe_emalloc(1, max_line_len, 5);
  833. char_cnt = max_line_len;
  834. _php_iconv_appendl(pretval, fname, fname_nbytes, cd_pl);
  835. char_cnt -= fname_nbytes;
  836. smart_str_appendl(pretval, ": ", sizeof(": ") - 1);
  837. char_cnt -= 2;
  838. in_p = fval;
  839. in_left = fval_nbytes;
  840. do {
  841. size_t prev_in_left;
  842. size_t out_size;
  843. size_t encoded_word_min_len = sizeof("=\?\?X\?\?=")-1 + out_charset_len + (enc_scheme == PHP_ICONV_ENC_SCHEME_BASE64 ? 4 : 3);
  844. if (char_cnt < encoded_word_min_len + lfchars_len + 1) {
  845. /* lfchars must be encoded in ASCII here*/
  846. smart_str_appendl(pretval, lfchars, lfchars_len);
  847. smart_str_appendc(pretval, ' ');
  848. char_cnt = max_line_len - 1;
  849. }
  850. smart_str_appendl(pretval, "=?", sizeof("=?") - 1);
  851. char_cnt -= 2;
  852. smart_str_appendl(pretval, out_charset, out_charset_len);
  853. char_cnt -= out_charset_len;
  854. smart_str_appendc(pretval, '?');
  855. char_cnt --;
  856. switch (enc_scheme) {
  857. case PHP_ICONV_ENC_SCHEME_BASE64: {
  858. size_t ini_in_left;
  859. const char *ini_in_p;
  860. size_t out_reserved = 4;
  861. smart_str_appendc(pretval, 'B');
  862. char_cnt--;
  863. smart_str_appendc(pretval, '?');
  864. char_cnt--;
  865. prev_in_left = ini_in_left = in_left;
  866. ini_in_p = in_p;
  867. out_size = (char_cnt - 2) / 4 * 3;
  868. for (;;) {
  869. out_p = buf;
  870. if (out_size <= out_reserved) {
  871. err = PHP_ICONV_ERR_TOO_BIG;
  872. goto out;
  873. }
  874. out_left = out_size - out_reserved;
  875. if (iconv(cd, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) {
  876. switch (errno) {
  877. case EINVAL:
  878. err = PHP_ICONV_ERR_ILLEGAL_CHAR;
  879. goto out;
  880. case EILSEQ:
  881. err = PHP_ICONV_ERR_ILLEGAL_SEQ;
  882. goto out;
  883. case E2BIG:
  884. if (prev_in_left == in_left) {
  885. err = PHP_ICONV_ERR_TOO_BIG;
  886. goto out;
  887. }
  888. break;
  889. default:
  890. err = PHP_ICONV_ERR_UNKNOWN;
  891. goto out;
  892. }
  893. }
  894. out_left += out_reserved;
  895. if (iconv(cd, NULL, NULL, (char **) &out_p, &out_left) == (size_t)-1) {
  896. if (errno != E2BIG) {
  897. err = PHP_ICONV_ERR_UNKNOWN;
  898. goto out;
  899. }
  900. } else {
  901. break;
  902. }
  903. if (iconv(cd, NULL, NULL, NULL, NULL) == (size_t)-1) {
  904. err = PHP_ICONV_ERR_UNKNOWN;
  905. goto out;
  906. }
  907. out_reserved += 4;
  908. in_left = ini_in_left;
  909. in_p = ini_in_p;
  910. }
  911. prev_in_left = in_left;
  912. encoded = php_base64_encode((unsigned char *) buf, (out_size - out_left));
  913. if (char_cnt < ZSTR_LEN(encoded)) {
  914. /* something went wrong! */
  915. err = PHP_ICONV_ERR_UNKNOWN;
  916. goto out;
  917. }
  918. smart_str_appendl(pretval, ZSTR_VAL(encoded), ZSTR_LEN(encoded));
  919. char_cnt -= ZSTR_LEN(encoded);
  920. smart_str_appendl(pretval, "?=", sizeof("?=") - 1);
  921. char_cnt -= 2;
  922. zend_string_release_ex(encoded, 0);
  923. encoded = NULL;
  924. } break; /* case PHP_ICONV_ENC_SCHEME_BASE64: */
  925. case PHP_ICONV_ENC_SCHEME_QPRINT: {
  926. size_t ini_in_left;
  927. const char *ini_in_p;
  928. const unsigned char *p;
  929. size_t nbytes_required;
  930. smart_str_appendc(pretval, 'Q');
  931. char_cnt--;
  932. smart_str_appendc(pretval, '?');
  933. char_cnt--;
  934. prev_in_left = ini_in_left = in_left;
  935. ini_in_p = in_p;
  936. for (out_size = (char_cnt - 2); out_size > 0;) {
  937. nbytes_required = 0;
  938. out_p = buf;
  939. out_left = out_size;
  940. if (iconv(cd, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) {
  941. switch (errno) {
  942. case EINVAL:
  943. err = PHP_ICONV_ERR_ILLEGAL_CHAR;
  944. goto out;
  945. case EILSEQ:
  946. err = PHP_ICONV_ERR_ILLEGAL_SEQ;
  947. goto out;
  948. case E2BIG:
  949. if (prev_in_left == in_left) {
  950. err = PHP_ICONV_ERR_UNKNOWN;
  951. goto out;
  952. }
  953. break;
  954. default:
  955. err = PHP_ICONV_ERR_UNKNOWN;
  956. goto out;
  957. }
  958. }
  959. if (iconv(cd, NULL, NULL, (char **) &out_p, &out_left) == (size_t)-1) {
  960. if (errno != E2BIG) {
  961. err = PHP_ICONV_ERR_UNKNOWN;
  962. goto out;
  963. }
  964. }
  965. for (p = (unsigned char *)buf; p < (unsigned char *)out_p; p++) {
  966. nbytes_required += qp_table[*p];
  967. }
  968. if (nbytes_required <= char_cnt - 2) {
  969. break;
  970. }
  971. out_size -= ((nbytes_required - (char_cnt - 2)) + 2) / 3;
  972. in_left = ini_in_left;
  973. in_p = ini_in_p;
  974. }
  975. for (p = (unsigned char *)buf; p < (unsigned char *)out_p; p++) {
  976. if (qp_table[*p] == 1) {
  977. smart_str_appendc(pretval, *(char *)p);
  978. char_cnt--;
  979. } else {
  980. static char qp_digits[] = "0123456789ABCDEF";
  981. smart_str_appendc(pretval, '=');
  982. smart_str_appendc(pretval, qp_digits[(*p >> 4) & 0x0f]);
  983. smart_str_appendc(pretval, qp_digits[(*p & 0x0f)]);
  984. char_cnt -= 3;
  985. }
  986. }
  987. smart_str_appendl(pretval, "?=", sizeof("?=") - 1);
  988. char_cnt -= 2;
  989. if (iconv(cd, NULL, NULL, NULL, NULL) == (size_t)-1) {
  990. err = PHP_ICONV_ERR_UNKNOWN;
  991. goto out;
  992. }
  993. } break; /* case PHP_ICONV_ENC_SCHEME_QPRINT: */
  994. }
  995. } while (in_left > 0);
  996. smart_str_0(pretval);
  997. out:
  998. if (cd != (iconv_t)(-1)) {
  999. iconv_close(cd);
  1000. }
  1001. if (cd_pl != (iconv_t)(-1)) {
  1002. iconv_close(cd_pl);
  1003. }
  1004. if (encoded != NULL) {
  1005. zend_string_release_ex(encoded, 0);
  1006. }
  1007. if (buf != NULL) {
  1008. efree(buf);
  1009. }
  1010. return err;
  1011. }
  1012. /* }}} */
  1013. /* {{{ _php_iconv_mime_decode() */
  1014. 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)
  1015. {
  1016. php_iconv_err_t err = PHP_ICONV_ERR_SUCCESS;
  1017. iconv_t cd = (iconv_t)(-1), cd_pl = (iconv_t)(-1);
  1018. const char *p1;
  1019. size_t str_left;
  1020. unsigned int scan_stat = 0;
  1021. const char *csname = NULL;
  1022. size_t csname_len;
  1023. const char *encoded_text = NULL;
  1024. size_t encoded_text_len = 0;
  1025. const char *encoded_word = NULL;
  1026. const char *spaces = NULL;
  1027. php_iconv_enc_scheme_t enc_scheme = PHP_ICONV_ENC_SCHEME_BASE64;
  1028. if (next_pos != NULL) {
  1029. *next_pos = NULL;
  1030. }
  1031. cd_pl = iconv_open(enc, ICONV_ASCII_ENCODING);
  1032. if (cd_pl == (iconv_t)(-1)) {
  1033. if (errno == EINVAL) {
  1034. err = PHP_ICONV_ERR_WRONG_CHARSET;
  1035. } else {
  1036. err = PHP_ICONV_ERR_CONVERTER;
  1037. }
  1038. goto out;
  1039. }
  1040. p1 = str;
  1041. for (str_left = str_nbytes; str_left > 0; str_left--, p1++) {
  1042. int eos = 0;
  1043. switch (scan_stat) {
  1044. case 0: /* expecting any character */
  1045. switch (*p1) {
  1046. case '\r': /* part of an EOL sequence? */
  1047. scan_stat = 7;
  1048. break;
  1049. case '\n':
  1050. scan_stat = 8;
  1051. break;
  1052. case '=': /* first letter of an encoded chunk */
  1053. encoded_word = p1;
  1054. scan_stat = 1;
  1055. break;
  1056. case ' ': case '\t': /* a chunk of whitespaces */
  1057. spaces = p1;
  1058. scan_stat = 11;
  1059. break;
  1060. default: /* first letter of a non-encoded word */
  1061. err = _php_iconv_appendc(pretval, *p1, cd_pl);
  1062. if (err != PHP_ICONV_ERR_SUCCESS) {
  1063. if (mode & PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR) {
  1064. err = PHP_ICONV_ERR_SUCCESS;
  1065. } else {
  1066. goto out;
  1067. }
  1068. }
  1069. encoded_word = NULL;
  1070. if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) {
  1071. scan_stat = 12;
  1072. }
  1073. break;
  1074. }
  1075. break;
  1076. case 1: /* expecting a delimiter */
  1077. if (*p1 != '?') {
  1078. if (*p1 == '\r' || *p1 == '\n') {
  1079. --p1;
  1080. }
  1081. err = _php_iconv_appendl(pretval, encoded_word, (size_t)((p1 + 1) - encoded_word), cd_pl);
  1082. if (err != PHP_ICONV_ERR_SUCCESS) {
  1083. goto out;
  1084. }
  1085. encoded_word = NULL;
  1086. if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) {
  1087. scan_stat = 12;
  1088. } else {
  1089. scan_stat = 0;
  1090. }
  1091. break;
  1092. }
  1093. csname = p1 + 1;
  1094. scan_stat = 2;
  1095. break;
  1096. case 2: /* expecting a charset name */
  1097. switch (*p1) {
  1098. case '?': /* normal delimiter: encoding scheme follows */
  1099. scan_stat = 3;
  1100. break;
  1101. case '*': /* new style delimiter: locale id follows */
  1102. scan_stat = 10;
  1103. break;
  1104. case '\r': case '\n': /* not an encoded-word */
  1105. --p1;
  1106. _php_iconv_appendc(pretval, '=', cd_pl);
  1107. _php_iconv_appendc(pretval, '?', cd_pl);
  1108. err = _php_iconv_appendl(pretval, csname, (size_t)((p1 + 1) - csname), cd_pl);
  1109. if (err != PHP_ICONV_ERR_SUCCESS) {
  1110. goto out;
  1111. }
  1112. csname = NULL;
  1113. if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) {
  1114. scan_stat = 12;
  1115. }
  1116. else {
  1117. scan_stat = 0;
  1118. }
  1119. continue;
  1120. }
  1121. if (scan_stat != 2) {
  1122. char tmpbuf[80];
  1123. if (csname == NULL) {
  1124. err = PHP_ICONV_ERR_MALFORMED;
  1125. goto out;
  1126. }
  1127. csname_len = (size_t)(p1 - csname);
  1128. if (csname_len > sizeof(tmpbuf) - 1) {
  1129. if ((mode & PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR)) {
  1130. err = _php_iconv_appendl(pretval, encoded_word, (size_t)((p1 + 1) - encoded_word), cd_pl);
  1131. if (err != PHP_ICONV_ERR_SUCCESS) {
  1132. goto out;
  1133. }
  1134. encoded_word = NULL;
  1135. if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) {
  1136. scan_stat = 12;
  1137. } else {
  1138. scan_stat = 0;
  1139. }
  1140. break;
  1141. } else {
  1142. err = PHP_ICONV_ERR_MALFORMED;
  1143. goto out;
  1144. }
  1145. }
  1146. memcpy(tmpbuf, csname, csname_len);
  1147. tmpbuf[csname_len] = '\0';
  1148. if (cd != (iconv_t)(-1)) {
  1149. iconv_close(cd);
  1150. }
  1151. cd = iconv_open(enc, tmpbuf);
  1152. if (cd == (iconv_t)(-1)) {
  1153. if ((mode & PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR)) {
  1154. /* Bad character set, but the user wants us to
  1155. * press on. In this case, we'll just insert the
  1156. * undecoded encoded word, since there isn't really
  1157. * a more sensible behaviour available; the only
  1158. * other options are to swallow the encoded word
  1159. * entirely or decode it with an arbitrarily chosen
  1160. * single byte encoding, both of which seem to have
  1161. * a higher WTF factor than leaving it undecoded.
  1162. *
  1163. * Given this approach, we need to skip ahead to
  1164. * the end of the encoded word. */
  1165. int qmarks = 2;
  1166. while (qmarks > 0 && str_left > 1) {
  1167. if (*(++p1) == '?') {
  1168. --qmarks;
  1169. }
  1170. --str_left;
  1171. }
  1172. /* Look ahead to check for the terminating = that
  1173. * should be there as well; if it's there, we'll
  1174. * also include that. If it's not, there isn't much
  1175. * we can do at this point. */
  1176. if (*(p1 + 1) == '=') {
  1177. ++p1;
  1178. if (str_left > 1) {
  1179. --str_left;
  1180. }
  1181. }
  1182. err = _php_iconv_appendl(pretval, encoded_word, (size_t)((p1 + 1) - encoded_word), cd_pl);
  1183. if (err != PHP_ICONV_ERR_SUCCESS) {
  1184. goto out;
  1185. }
  1186. /* Let's go back and see if there are further
  1187. * encoded words or bare content, and hope they
  1188. * might actually have a valid character set. */
  1189. scan_stat = 12;
  1190. break;
  1191. } else {
  1192. if (errno == EINVAL) {
  1193. err = PHP_ICONV_ERR_WRONG_CHARSET;
  1194. } else {
  1195. err = PHP_ICONV_ERR_CONVERTER;
  1196. }
  1197. goto out;
  1198. }
  1199. }
  1200. }
  1201. break;
  1202. case 3: /* expecting a encoding scheme specifier */
  1203. switch (*p1) {
  1204. case 'b':
  1205. case 'B':
  1206. enc_scheme = PHP_ICONV_ENC_SCHEME_BASE64;
  1207. scan_stat = 4;
  1208. break;
  1209. case 'q':
  1210. case 'Q':
  1211. enc_scheme = PHP_ICONV_ENC_SCHEME_QPRINT;
  1212. scan_stat = 4;
  1213. break;
  1214. default:
  1215. if ((mode & PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR)) {
  1216. err = _php_iconv_appendl(pretval, encoded_word, (size_t)((p1 + 1) - encoded_word), cd_pl);
  1217. if (err != PHP_ICONV_ERR_SUCCESS) {
  1218. goto out;
  1219. }
  1220. encoded_word = NULL;
  1221. if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) {
  1222. scan_stat = 12;
  1223. } else {
  1224. scan_stat = 0;
  1225. }
  1226. break;
  1227. } else {
  1228. err = PHP_ICONV_ERR_MALFORMED;
  1229. goto out;
  1230. }
  1231. }
  1232. break;
  1233. case 4: /* expecting a delimiter */
  1234. if (*p1 != '?') {
  1235. if ((mode & PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR)) {
  1236. /* pass the entire chunk through the converter */
  1237. err = _php_iconv_appendl(pretval, encoded_word, (size_t)((p1 + 1) - encoded_word), cd_pl);
  1238. if (err != PHP_ICONV_ERR_SUCCESS) {
  1239. goto out;
  1240. }
  1241. encoded_word = NULL;
  1242. if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) {
  1243. scan_stat = 12;
  1244. } else {
  1245. scan_stat = 0;
  1246. }
  1247. break;
  1248. } else {
  1249. err = PHP_ICONV_ERR_MALFORMED;
  1250. goto out;
  1251. }
  1252. }
  1253. encoded_text = p1 + 1;
  1254. scan_stat = 5;
  1255. break;
  1256. case 5: /* expecting an encoded portion */
  1257. if (*p1 == '?') {
  1258. encoded_text_len = (size_t)(p1 - encoded_text);
  1259. scan_stat = 6;
  1260. }
  1261. break;
  1262. case 7: /* expecting a "\n" character */
  1263. if (*p1 == '\n') {
  1264. scan_stat = 8;
  1265. } else {
  1266. /* bare CR */
  1267. _php_iconv_appendc(pretval, '\r', cd_pl);
  1268. _php_iconv_appendc(pretval, *p1, cd_pl);
  1269. scan_stat = 0;
  1270. }
  1271. break;
  1272. case 8: /* checking whether the following line is part of a
  1273. folded header */
  1274. if (*p1 != ' ' && *p1 != '\t') {
  1275. --p1;
  1276. str_left = 1; /* quit_loop */
  1277. break;
  1278. }
  1279. if (encoded_word == NULL) {
  1280. _php_iconv_appendc(pretval, ' ', cd_pl);
  1281. }
  1282. spaces = NULL;
  1283. scan_stat = 11;
  1284. break;
  1285. case 6: /* expecting a End-Of-Chunk character "=" */
  1286. if (*p1 != '=') {
  1287. if ((mode & PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR)) {
  1288. /* pass the entire chunk through the converter */
  1289. err = _php_iconv_appendl(pretval, encoded_word, (size_t)((p1 + 1) - encoded_word), cd_pl);
  1290. if (err != PHP_ICONV_ERR_SUCCESS) {
  1291. goto out;
  1292. }
  1293. encoded_word = NULL;
  1294. if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) {
  1295. scan_stat = 12;
  1296. } else {
  1297. scan_stat = 0;
  1298. }
  1299. break;
  1300. } else {
  1301. err = PHP_ICONV_ERR_MALFORMED;
  1302. goto out;
  1303. }
  1304. }
  1305. scan_stat = 9;
  1306. if (str_left == 1) {
  1307. eos = 1;
  1308. } else {
  1309. break;
  1310. }
  1311. case 9: /* choice point, seeing what to do next.*/
  1312. switch (*p1) {
  1313. default:
  1314. /* Handle non-RFC-compliant formats
  1315. *
  1316. * RFC2047 requires the character that comes right
  1317. * after an encoded word (chunk) to be a whitespace,
  1318. * while there are lots of broken implementations that
  1319. * generate such malformed headers that don't fulfill
  1320. * that requirement.
  1321. */
  1322. if (!eos) {
  1323. if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) {
  1324. /* pass the entire chunk through the converter */
  1325. err = _php_iconv_appendl(pretval, encoded_word, (size_t)((p1 + 1) - encoded_word), cd_pl);
  1326. if (err != PHP_ICONV_ERR_SUCCESS) {
  1327. goto out;
  1328. }
  1329. scan_stat = 12;
  1330. break;
  1331. }
  1332. }
  1333. /* break is omitted intentionally */
  1334. case '\r': case '\n': case ' ': case '\t': {
  1335. zend_string *decoded_text;
  1336. switch (enc_scheme) {
  1337. case PHP_ICONV_ENC_SCHEME_BASE64:
  1338. decoded_text = php_base64_decode((unsigned char*)encoded_text, encoded_text_len);
  1339. break;
  1340. case PHP_ICONV_ENC_SCHEME_QPRINT:
  1341. decoded_text = php_quot_print_decode((unsigned char*)encoded_text, encoded_text_len, 1);
  1342. break;
  1343. default:
  1344. decoded_text = NULL;
  1345. break;
  1346. }
  1347. if (decoded_text == NULL) {
  1348. if ((mode & PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR)) {
  1349. /* pass the entire chunk through the converter */
  1350. err = _php_iconv_appendl(pretval, encoded_word, (size_t)((p1 + 1) - encoded_word), cd_pl);
  1351. if (err != PHP_ICONV_ERR_SUCCESS) {
  1352. goto out;
  1353. }
  1354. encoded_word = NULL;
  1355. if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) {
  1356. scan_stat = 12;
  1357. } else {
  1358. scan_stat = 0;
  1359. }
  1360. break;
  1361. } else {
  1362. err = PHP_ICONV_ERR_UNKNOWN;
  1363. goto out;
  1364. }
  1365. }
  1366. err = _php_iconv_appendl(pretval, ZSTR_VAL(decoded_text), ZSTR_LEN(decoded_text), cd);
  1367. zend_string_release_ex(decoded_text, 0);
  1368. if (err != PHP_ICONV_ERR_SUCCESS) {
  1369. if ((mode & PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR)) {
  1370. /* pass the entire chunk through the converter */
  1371. err = _php_iconv_appendl(pretval, encoded_word, (size_t)(p1 - encoded_word), cd_pl);
  1372. encoded_word = NULL;
  1373. if (err != PHP_ICONV_ERR_SUCCESS) {
  1374. break;
  1375. }
  1376. } else {
  1377. goto out;
  1378. }
  1379. }
  1380. if (eos) { /* reached end-of-string. done. */
  1381. scan_stat = 0;
  1382. break;
  1383. }
  1384. switch (*p1) {
  1385. case '\r': /* part of an EOL sequence? */
  1386. scan_stat = 7;
  1387. break;
  1388. case '\n':
  1389. scan_stat = 8;
  1390. break;
  1391. case '=': /* first letter of an encoded chunk */
  1392. scan_stat = 1;
  1393. break;
  1394. case ' ': case '\t': /* medial whitespaces */
  1395. spaces = p1;
  1396. scan_stat = 11;
  1397. break;
  1398. default: /* first letter of a non-encoded word */
  1399. _php_iconv_appendc(pretval, *p1, cd_pl);
  1400. scan_stat = 12;
  1401. break;
  1402. }
  1403. } break;
  1404. }
  1405. break;
  1406. case 10: /* expects a language specifier. dismiss it for now */
  1407. if (*p1 == '?') {
  1408. scan_stat = 3;
  1409. }
  1410. break;
  1411. case 11: /* expecting a chunk of whitespaces */
  1412. switch (*p1) {
  1413. case '\r': /* part of an EOL sequence? */
  1414. scan_stat = 7;
  1415. break;
  1416. case '\n':
  1417. scan_stat = 8;
  1418. break;
  1419. case '=': /* first letter of an encoded chunk */
  1420. if (spaces != NULL && encoded_word == NULL) {
  1421. _php_iconv_appendl(pretval, spaces, (size_t)(p1 - spaces), cd_pl);
  1422. spaces = NULL;
  1423. }
  1424. encoded_word = p1;
  1425. scan_stat = 1;
  1426. break;
  1427. case ' ': case '\t':
  1428. break;
  1429. default: /* first letter of a non-encoded word */
  1430. if (spaces != NULL) {
  1431. _php_iconv_appendl(pretval, spaces, (size_t)(p1 - spaces), cd_pl);
  1432. spaces = NULL;
  1433. }
  1434. _php_iconv_appendc(pretval, *p1, cd_pl);
  1435. encoded_word = NULL;
  1436. if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) {
  1437. scan_stat = 12;
  1438. } else {
  1439. scan_stat = 0;
  1440. }
  1441. break;
  1442. }
  1443. break;
  1444. case 12: /* expecting a non-encoded word */
  1445. switch (*p1) {
  1446. case '\r': /* part of an EOL sequence? */
  1447. scan_stat = 7;
  1448. break;
  1449. case '\n':
  1450. scan_stat = 8;
  1451. break;
  1452. case ' ': case '\t':
  1453. spaces = p1;
  1454. scan_stat = 11;
  1455. break;
  1456. case '=': /* first letter of an encoded chunk */
  1457. if (!(mode & PHP_ICONV_MIME_DECODE_STRICT)) {
  1458. encoded_word = p1;
  1459. scan_stat = 1;
  1460. break;
  1461. }
  1462. /* break is omitted intentionally */
  1463. default:
  1464. _php_iconv_appendc(pretval, *p1, cd_pl);
  1465. break;
  1466. }
  1467. break;
  1468. }
  1469. }
  1470. switch (scan_stat) {
  1471. case 0: case 8: case 11: case 12:
  1472. break;
  1473. default:
  1474. if ((mode & PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR)) {
  1475. if (scan_stat == 1) {
  1476. _php_iconv_appendc(pretval, '=', cd_pl);
  1477. }
  1478. err = PHP_ICONV_ERR_SUCCESS;
  1479. } else {
  1480. err = PHP_ICONV_ERR_MALFORMED;
  1481. goto out;
  1482. }
  1483. }
  1484. if (next_pos != NULL) {
  1485. *next_pos = p1;
  1486. }
  1487. if (cd != (iconv_t)(-1)) {
  1488. _php_iconv_appendl(pretval, NULL, 0, cd);
  1489. }
  1490. if (cd_pl != (iconv_t)(-1)) {
  1491. _php_iconv_appendl(pretval, NULL, 0, cd_pl);
  1492. }
  1493. smart_str_0(pretval);
  1494. out:
  1495. if (cd != (iconv_t)(-1)) {
  1496. iconv_close(cd);
  1497. }
  1498. if (cd_pl != (iconv_t)(-1)) {
  1499. iconv_close(cd_pl);
  1500. }
  1501. return err;
  1502. }
  1503. /* }}} */
  1504. /* {{{ php_iconv_show_error() */
  1505. static void _php_iconv_show_error(php_iconv_err_t err, const char *out_charset, const char *in_charset)
  1506. {
  1507. switch (err) {
  1508. case PHP_ICONV_ERR_SUCCESS:
  1509. break;
  1510. case PHP_ICONV_ERR_CONVERTER:
  1511. php_error_docref(NULL, E_NOTICE, "Cannot open converter");
  1512. break;
  1513. case PHP_ICONV_ERR_WRONG_CHARSET:
  1514. php_error_docref(NULL, E_NOTICE, "Wrong charset, conversion from `%s' to `%s' is not allowed",
  1515. in_charset, out_charset);
  1516. break;
  1517. case PHP_ICONV_ERR_ILLEGAL_CHAR:
  1518. php_error_docref(NULL, E_NOTICE, "Detected an incomplete multibyte character in input string");
  1519. break;
  1520. case PHP_ICONV_ERR_ILLEGAL_SEQ:
  1521. php_error_docref(NULL, E_NOTICE, "Detected an illegal character in input string");
  1522. break;
  1523. case PHP_ICONV_ERR_TOO_BIG:
  1524. /* should not happen */
  1525. php_error_docref(NULL, E_WARNING, "Buffer length exceeded");
  1526. break;
  1527. case PHP_ICONV_ERR_MALFORMED:
  1528. php_error_docref(NULL, E_WARNING, "Malformed string");
  1529. break;
  1530. default:
  1531. /* other error */
  1532. php_error_docref(NULL, E_NOTICE, "Unknown error (%d)", errno);
  1533. break;
  1534. }
  1535. }
  1536. /* }}} */
  1537. /* {{{ proto int iconv_strlen(string str [, string charset])
  1538. Returns the character count of str */
  1539. PHP_FUNCTION(iconv_strlen)
  1540. {
  1541. const char *charset = NULL;
  1542. size_t charset_len;
  1543. zend_string *str;
  1544. php_iconv_err_t err;
  1545. size_t retval;
  1546. if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|s!",
  1547. &str, &charset, &charset_len) == FAILURE) {
  1548. RETURN_THROWS();
  1549. }
  1550. if (charset == NULL) {
  1551. charset = get_internal_encoding();
  1552. } else if (charset_len >= ICONV_CSNMAXLEN) {
  1553. php_error_docref(NULL, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN);
  1554. RETURN_FALSE;
  1555. }
  1556. err = _php_iconv_strlen(&retval, ZSTR_VAL(str), ZSTR_LEN(str), charset);
  1557. _php_iconv_show_error(err, GENERIC_SUPERSET_NAME, charset);
  1558. if (err == PHP_ICONV_ERR_SUCCESS) {
  1559. RETVAL_LONG(retval);
  1560. } else {
  1561. RETVAL_FALSE;
  1562. }
  1563. }
  1564. /* }}} */
  1565. /* {{{ proto string iconv_substr(string str, int offset, [int length, string charset])
  1566. Returns specified part of a string */
  1567. PHP_FUNCTION(iconv_substr)
  1568. {
  1569. const char *charset = NULL;
  1570. size_t charset_len;
  1571. zend_string *str;
  1572. zend_long offset, length = 0;
  1573. zend_bool len_is_null = 1;
  1574. php_iconv_err_t err;
  1575. smart_str retval = {0};
  1576. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sl|l!s!",
  1577. &str, &offset, &length, &len_is_null,
  1578. &charset, &charset_len) == FAILURE) {
  1579. RETURN_THROWS();
  1580. }
  1581. if (charset == NULL) {
  1582. charset = get_internal_encoding();
  1583. } else if (charset_len >= ICONV_CSNMAXLEN) {
  1584. php_error_docref(NULL, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN);
  1585. RETURN_FALSE;
  1586. }
  1587. if (len_is_null) {
  1588. length = ZSTR_LEN(str);
  1589. }
  1590. err = _php_iconv_substr(&retval, ZSTR_VAL(str), ZSTR_LEN(str), offset, length, charset);
  1591. _php_iconv_show_error(err, GENERIC_SUPERSET_NAME, charset);
  1592. if (err == PHP_ICONV_ERR_SUCCESS && retval.s != NULL) {
  1593. RETURN_NEW_STR(retval.s);
  1594. }
  1595. smart_str_free(&retval);
  1596. RETURN_FALSE;
  1597. }
  1598. /* }}} */
  1599. /* {{{ proto int iconv_strpos(string haystack, string needle [, int offset [, string charset]])
  1600. Finds position of first occurrence of needle within part of haystack beginning with offset */
  1601. PHP_FUNCTION(iconv_strpos)
  1602. {
  1603. const char *charset = NULL;
  1604. size_t charset_len, haystk_len;
  1605. zend_string *haystk;
  1606. zend_string *ndl;
  1607. zend_long offset = 0;
  1608. php_iconv_err_t err;
  1609. size_t retval;
  1610. if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS|ls!",
  1611. &haystk, &ndl,
  1612. &offset, &charset, &charset_len) == FAILURE) {
  1613. RETURN_THROWS();
  1614. }
  1615. if (charset == NULL) {
  1616. charset = get_internal_encoding();
  1617. } else if (charset_len >= ICONV_CSNMAXLEN) {
  1618. php_error_docref(NULL, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN);
  1619. RETURN_FALSE;
  1620. }
  1621. if (offset < 0) {
  1622. /* Convert negative offset (counted from the end of string) */
  1623. err = _php_iconv_strlen(&haystk_len, ZSTR_VAL(haystk), ZSTR_LEN(haystk), charset);
  1624. if (err != PHP_ICONV_ERR_SUCCESS) {
  1625. _php_iconv_show_error(err, GENERIC_SUPERSET_NAME, charset);
  1626. RETURN_FALSE;
  1627. }
  1628. offset += haystk_len;
  1629. if (offset < 0) { /* If offset before start */
  1630. php_error_docref(NULL, E_WARNING, "Offset not contained in string.");
  1631. RETURN_FALSE;
  1632. }
  1633. }
  1634. if (ZSTR_LEN(ndl) < 1) {
  1635. RETURN_FALSE;
  1636. }
  1637. err = _php_iconv_strpos(&retval, ZSTR_VAL(haystk), ZSTR_LEN(haystk), ZSTR_VAL(ndl), ZSTR_LEN(ndl),
  1638. offset, charset);
  1639. _php_iconv_show_error(err, GENERIC_SUPERSET_NAME, charset);
  1640. if (err == PHP_ICONV_ERR_SUCCESS && retval != (size_t)-1) {
  1641. RETVAL_LONG((zend_long)retval);
  1642. } else {
  1643. RETVAL_FALSE;
  1644. }
  1645. }
  1646. /* }}} */
  1647. /* {{{ proto int iconv_strrpos(string haystack, string needle [, string charset])
  1648. Finds position of last occurrence of needle within part of haystack beginning with offset */
  1649. PHP_FUNCTION(iconv_strrpos)
  1650. {
  1651. const char *charset = NULL;
  1652. size_t charset_len;
  1653. zend_string *haystk;

Large files files are truncated, but you can click here to view the full file