codepage.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 7 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2018 The PHP Group |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_01.txt |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. | Author: Anatol Belski <ab@php.net> |
  16. +----------------------------------------------------------------------+
  17. */
  18. #include <assert.h>
  19. #include "php.h"
  20. #include "SAPI.h"
  21. #include <emmintrin.h>
  22. ZEND_TLS const struct php_win32_cp *cur_cp = NULL;
  23. ZEND_TLS const struct php_win32_cp *orig_cp = NULL;
  24. ZEND_TLS const struct php_win32_cp *cur_out_cp = NULL;
  25. ZEND_TLS const struct php_win32_cp *orig_out_cp = NULL;
  26. ZEND_TLS const struct php_win32_cp *cur_in_cp = NULL;
  27. ZEND_TLS const struct php_win32_cp *orig_in_cp = NULL;
  28. #include "cp_enc_map.c"
  29. __forceinline static wchar_t *php_win32_cp_to_w_int(const char* in, size_t in_len, size_t *out_len, UINT cp, DWORD flags)
  30. {/*{{{*/
  31. wchar_t *ret;
  32. int ret_len, tmp_len;
  33. if (!in || in_len > (size_t)INT_MAX) {
  34. SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER);
  35. return NULL;
  36. }
  37. assert(in_len ? (in[in_len] == L'\0') : 1);
  38. tmp_len = !in_len ? -1 : (int)in_len + 1;
  39. ret_len = MultiByteToWideChar(cp, flags, in, tmp_len, NULL, 0);
  40. if (ret_len == 0) {
  41. SET_ERRNO_FROM_WIN32_CODE(GetLastError());
  42. return NULL;
  43. }
  44. ret = malloc(ret_len * sizeof(wchar_t));
  45. if (!ret) {
  46. SET_ERRNO_FROM_WIN32_CODE(ERROR_OUTOFMEMORY);
  47. return NULL;
  48. }
  49. tmp_len = MultiByteToWideChar(cp, flags, in, tmp_len, ret, ret_len);
  50. if (tmp_len == 0) {
  51. free(ret);
  52. SET_ERRNO_FROM_WIN32_CODE(GetLastError());
  53. return NULL;
  54. }
  55. assert(ret ? tmp_len == ret_len : 1);
  56. assert(ret && !in_len ? wcslen(ret) == ret_len - 1 : 1);
  57. ret[ret_len-1] = L'\0';
  58. if (PHP_WIN32_CP_IGNORE_LEN_P != out_len) {
  59. *out_len = ret_len - 1;
  60. }
  61. return ret;
  62. }/*}}}*/
  63. PW32CP wchar_t *php_win32_cp_conv_utf8_to_w(const char* in, size_t in_len, size_t *out_len)
  64. {/*{{{*/
  65. return php_win32_cp_to_w_int(in, in_len, out_len, CP_UTF8, MB_ERR_INVALID_CHARS);
  66. }/*}}}*/
  67. PW32CP wchar_t *php_win32_cp_conv_cur_to_w(const char* in, size_t in_len, size_t *out_len)
  68. {/*{{{*/
  69. wchar_t *ret;
  70. ret = php_win32_cp_to_w_int(in, in_len, out_len, cur_cp->id, cur_cp->from_w_fl);
  71. return ret;
  72. }/*}}}*/
  73. PW32CP wchar_t *php_win32_cp_conv_to_w(DWORD cp, DWORD flags, const char* in, size_t in_len, size_t *out_len)
  74. {/*{{{*/
  75. return php_win32_cp_to_w_int(in, in_len, out_len, cp, flags);
  76. }/*}}}*/
  77. #define ASCII_FAIL_RETURN() \
  78. if (PHP_WIN32_CP_IGNORE_LEN_P != out_len) { \
  79. *out_len = 0; \
  80. } \
  81. return NULL;
  82. PW32CP wchar_t *php_win32_cp_conv_ascii_to_w(const char* in, size_t in_len, size_t *out_len)
  83. {/*{{{*/
  84. wchar_t *ret, *ret_idx;
  85. const char *idx = in, *end;
  86. #if PHP_DEBUG
  87. size_t save_in_len = in_len;
  88. #endif
  89. assert(in && in_len ? in[in_len] == '\0' : 1);
  90. if (!in) {
  91. SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER);
  92. return NULL;
  93. } else if (0 == in_len) {
  94. /* Not binary safe. */
  95. in_len = strlen(in);
  96. }
  97. end = in + in_len;
  98. if (in_len > 15) {
  99. const char *aidx = (const char *)ZEND_SLIDE_TO_ALIGNED16(in);
  100. /* Process unaligned chunk. */
  101. while (idx < aidx) {
  102. if (!__isascii(*idx) && '\0' != *idx) {
  103. ASCII_FAIL_RETURN()
  104. }
  105. idx++;
  106. }
  107. /* Process aligned chunk. */
  108. while (end - idx > 15) {
  109. const __m128i block = _mm_load_si128((__m128i *)idx);
  110. if (_mm_movemask_epi8(block)) {
  111. ASCII_FAIL_RETURN()
  112. }
  113. idx += 16;
  114. }
  115. }
  116. /* Process the trailing part, or otherwise process string < 16 bytes. */
  117. while (idx < end) {
  118. if (!__isascii(*idx) && '\0' != *idx) {
  119. ASCII_FAIL_RETURN()
  120. }
  121. idx++;
  122. }
  123. ret = malloc((in_len+1)*sizeof(wchar_t));
  124. if (!ret) {
  125. SET_ERRNO_FROM_WIN32_CODE(ERROR_OUTOFMEMORY);
  126. return NULL;
  127. }
  128. ret_idx = ret;
  129. idx = in;
  130. /* Check and conversion could be merged. This however would
  131. be more expencive, if a non ASCII string was passed.
  132. TODO check whether the impact is acceptable. */
  133. if (in_len > 15) {
  134. const char *aidx = (const char *)ZEND_SLIDE_TO_ALIGNED16(in);
  135. /* Process unaligned chunk. */
  136. while (idx < aidx) {
  137. *ret_idx++ = (wchar_t)*idx++;
  138. }
  139. /* Process aligned chunk. */
  140. if (end - idx > 15) {
  141. const __m128i mask = _mm_set1_epi32(0);
  142. while (end - idx > 15) {
  143. const __m128i block = _mm_load_si128((__m128i *)idx);
  144. {
  145. const __m128i lo = _mm_unpacklo_epi8(block, mask);
  146. _mm_storeu_si128((__m128i *)ret_idx, lo);
  147. }
  148. ret_idx += 8;
  149. {
  150. const __m128i hi = _mm_unpackhi_epi8(block, mask);
  151. _mm_storeu_si128((__m128i *)ret_idx, hi);
  152. }
  153. idx += 16;
  154. ret_idx += 8;
  155. }
  156. }
  157. }
  158. /* Process the trailing part, or otherwise process string < 16 bytes. */
  159. while (idx < end) {
  160. *ret_idx++ = (wchar_t)*idx++;
  161. }
  162. ret[in_len] = L'\0';
  163. assert(ret && !save_in_len ? wcslen(ret) == in_len : 1);
  164. if (PHP_WIN32_CP_IGNORE_LEN_P != out_len) {
  165. *out_len = in_len;
  166. }
  167. return ret;
  168. }/*}}}*/
  169. #undef ASCII_FAIL_RETURN
  170. __forceinline static char *php_win32_cp_from_w_int(const wchar_t* in, size_t in_len, size_t *out_len, UINT cp, DWORD flags)
  171. {/*{{{*/
  172. int r;
  173. int target_len, tmp_len;
  174. char* target;
  175. if (!in || in_len > INT_MAX) {
  176. SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER);
  177. return NULL;
  178. }
  179. assert(in_len ? in[in_len] == '\0' : 1);
  180. tmp_len = !in_len ? -1 : (int)in_len + 1;
  181. target_len = WideCharToMultiByte(cp, flags, in, tmp_len, NULL, 0, NULL, NULL);
  182. if (target_len == 0) {
  183. SET_ERRNO_FROM_WIN32_CODE(GetLastError());
  184. return NULL;
  185. }
  186. target = malloc(target_len);
  187. if (target == NULL) {
  188. SET_ERRNO_FROM_WIN32_CODE(ERROR_OUTOFMEMORY);
  189. return NULL;
  190. }
  191. r = WideCharToMultiByte(cp, flags, in, tmp_len, target, target_len, NULL, NULL);
  192. if (r == 0) {
  193. free(target);
  194. SET_ERRNO_FROM_WIN32_CODE(GetLastError());
  195. return NULL;
  196. }
  197. assert(target ? r == target_len : 1);
  198. assert(target && !in_len ? strlen(target) == target_len - 1 : 1);
  199. target[target_len-1] = '\0';
  200. if (PHP_WIN32_CP_IGNORE_LEN_P != out_len) {
  201. *out_len = target_len - 1;
  202. }
  203. return target;
  204. }/*}}}*/
  205. PW32CP char *php_win32_cp_conv_w_to_utf8(const wchar_t* in, size_t in_len, size_t *out_len)
  206. {/*{{{*/
  207. return php_win32_cp_from_w_int(in, in_len, out_len, CP_UTF8, WC_ERR_INVALID_CHARS);
  208. }/*}}}*/
  209. PW32CP char *php_win32_cp_conv_w_to_cur(const wchar_t* in, size_t in_len, size_t *out_len)
  210. {/*{{{*/
  211. char *ret;
  212. ret = php_win32_cp_from_w_int(in, in_len, out_len, cur_cp->id, cur_cp->from_w_fl);
  213. return ret;
  214. }/*}}}*/
  215. PW32CP char *php_win32_cp_conv_from_w(DWORD cp, DWORD flags, const wchar_t* in, size_t in_len, size_t *out_len)
  216. {/*{{{*/
  217. return php_win32_cp_from_w_int(in, in_len, out_len, cp, flags);
  218. }/*}}}*/
  219. /* This is only usable after the startup phase*/
  220. __forceinline static char *php_win32_cp_get_enc(void)
  221. {/*{{{*/
  222. char *enc = NULL;
  223. const zend_encoding *zenc;
  224. if (PG(internal_encoding) && PG(internal_encoding)[0]) {
  225. enc = PG(internal_encoding);
  226. } else if (SG(default_charset) && SG(default_charset)[0] ) {
  227. enc = SG(default_charset);
  228. } else {
  229. zenc = zend_multibyte_get_internal_encoding();
  230. if (zenc) {
  231. enc = (char *)zend_multibyte_get_encoding_name(zenc);
  232. }
  233. }
  234. return enc;
  235. }/*}}}*/
  236. __forceinline static BOOL php_win32_cp_is_cli_sapi()
  237. {/*{{{*/
  238. return strlen(sapi_module.name) >= sizeof("cli") - 1 && !strncmp(sapi_module.name, "cli", sizeof("cli") - 1);
  239. }/*}}}*/
  240. PW32CP const struct php_win32_cp *php_win32_cp_get_current(void)
  241. {/*{{{*/
  242. return cur_cp;
  243. }/*}}}*/
  244. PW32CP const struct php_win32_cp *php_win32_cp_get_orig(void)
  245. {/*{{{*/
  246. return orig_cp;
  247. }/*}}}*/
  248. PW32CP const struct php_win32_cp *php_win32_cp_get_by_id(DWORD id)
  249. {/*{{{*/
  250. size_t i;
  251. if (id < php_win32_cp_map[0].id) {
  252. switch (id) {
  253. case CP_ACP:
  254. id = GetACP();
  255. break;
  256. case CP_OEMCP:
  257. id = GetOEMCP();
  258. break;
  259. }
  260. }
  261. for (i = 0; i < sizeof(php_win32_cp_map)/sizeof(struct php_win32_cp); i++) {
  262. if (php_win32_cp_map[i].id == id) {
  263. return &php_win32_cp_map[i];
  264. }
  265. }
  266. SET_ERRNO_FROM_WIN32_CODE(ERROR_NOT_FOUND);
  267. return NULL;
  268. }/*}}}*/
  269. PW32CP const struct php_win32_cp *php_win32_cp_get_by_enc(const char *enc)
  270. {/*{{{*/
  271. size_t enc_len = 0, i;
  272. if (!enc || !enc[0]) {
  273. return php_win32_cp_get_by_id(65001U);
  274. }
  275. enc_len = strlen(enc);
  276. for (i = 0; i < sizeof(php_win32_cp_map)/sizeof(struct php_win32_cp); i++) {
  277. const struct php_win32_cp *cp = &php_win32_cp_map[i];
  278. if (!cp->name || !cp->name[0]) {
  279. continue;
  280. }
  281. if (0 == zend_binary_strcasecmp(enc, enc_len, cp->name, strlen(cp->name))) {
  282. return cp;
  283. }
  284. if (cp->enc) {
  285. char *start = cp->enc, *idx;
  286. idx = strpbrk(start, "|");
  287. while (NULL != idx) {
  288. if (0 == zend_binary_strcasecmp(enc, enc_len, start, idx - start)) {
  289. return cp;
  290. }
  291. start = idx + 1;
  292. idx = strpbrk(start, "|");
  293. }
  294. /* Last in the list, or single charset specified. */
  295. if (0 == zend_binary_strcasecmp(enc, enc_len, start, strlen(start))) {
  296. return cp;
  297. }
  298. }
  299. }
  300. return php_win32_cp_get_by_id(GetACP());
  301. }/*}}}*/
  302. PW32CP const struct php_win32_cp *php_win32_cp_set_by_id(DWORD id)
  303. {/*{{{*/
  304. const struct php_win32_cp *tmp;
  305. if (!IsValidCodePage(id)) {
  306. SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER);
  307. return NULL;
  308. }
  309. tmp = php_win32_cp_get_by_id(id);
  310. if (tmp) {
  311. cur_cp = tmp;
  312. }
  313. return cur_cp;
  314. }/*}}}*/
  315. PW32CP BOOL php_win32_cp_use_unicode(void)
  316. {/*{{{*/
  317. return 65001 == cur_cp->id;
  318. }/*}}}*/
  319. PW32CP wchar_t *php_win32_cp_env_any_to_w(const char* env)
  320. {/*{{{*/
  321. wchar_t *envw = NULL, ew[32760];
  322. char *cur = (char *)env, *prev;
  323. size_t bin_len = 0;
  324. if (!env) {
  325. SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER);
  326. return NULL;
  327. }
  328. do {
  329. wchar_t *tmp;
  330. tmp = php_win32_cp_any_to_w(cur);
  331. if (tmp) {
  332. size_t tmp_len = wcslen(tmp) + 1;
  333. memmove(ew + bin_len, tmp, tmp_len * sizeof(wchar_t));
  334. free(tmp);
  335. bin_len += tmp_len;
  336. }
  337. prev = cur;
  338. } while (NULL != (cur = strchr(prev, '\0')) && cur++ && *cur && bin_len + (cur - prev) < 32760);
  339. envw = (wchar_t *) malloc((bin_len + 3) * sizeof(wchar_t));
  340. if (!envw) {
  341. SET_ERRNO_FROM_WIN32_CODE(ERROR_OUTOFMEMORY);
  342. return NULL;
  343. }
  344. memmove(envw, ew, bin_len * sizeof(wchar_t));
  345. envw[bin_len] = L'\0';
  346. envw[bin_len + 1] = L'\0';
  347. envw[bin_len + 2] = L'\0';
  348. return envw;
  349. }/*}}}*/
  350. static BOOL php_win32_cp_cli_io_setup(void)
  351. {/*{{{*/
  352. BOOL ret = TRUE;
  353. if (PG(input_encoding) && PG(input_encoding)[0]) {
  354. cur_in_cp = php_win32_cp_get_by_enc(PG(input_encoding));
  355. if (!cur_in_cp) {
  356. cur_in_cp = cur_cp;
  357. }
  358. } else {
  359. cur_in_cp = cur_cp;
  360. }
  361. if (PG(output_encoding) && PG(output_encoding)[0]) {
  362. cur_out_cp = php_win32_cp_get_by_enc(PG(output_encoding));
  363. if (!cur_out_cp) {
  364. cur_out_cp = cur_cp;
  365. }
  366. } else {
  367. cur_out_cp = cur_cp;
  368. }
  369. if(php_get_module_initialized()) {
  370. ret = SetConsoleCP(cur_in_cp->id) && SetConsoleOutputCP(cur_out_cp->id);
  371. }
  372. return ret;
  373. }/*}}}*/
  374. PW32CP const struct php_win32_cp *php_win32_cp_do_setup(const char *enc)
  375. {/*{{{*/
  376. if (!enc) {
  377. enc = php_win32_cp_get_enc();
  378. }
  379. cur_cp = php_win32_cp_get_by_enc(enc);
  380. if (!orig_cp) {
  381. orig_cp = php_win32_cp_get_by_id(GetACP());
  382. }
  383. if (php_win32_cp_is_cli_sapi()) {
  384. if (!orig_in_cp) {
  385. orig_in_cp = php_win32_cp_get_by_id(GetConsoleCP());
  386. if (!orig_in_cp) {
  387. orig_in_cp = orig_cp;
  388. }
  389. }
  390. if (!orig_out_cp) {
  391. orig_out_cp = php_win32_cp_get_by_id(GetConsoleOutputCP());
  392. if (!orig_out_cp) {
  393. orig_out_cp = orig_cp;
  394. }
  395. }
  396. php_win32_cp_cli_io_setup();
  397. }
  398. return cur_cp;
  399. }/*}}}*/
  400. PW32CP const struct php_win32_cp *php_win32_cp_do_update(const char *enc)
  401. {/*{{{*/
  402. if (!enc) {
  403. enc = php_win32_cp_get_enc();
  404. }
  405. cur_cp = php_win32_cp_get_by_enc(enc);
  406. if (php_win32_cp_is_cli_sapi()) {
  407. php_win32_cp_cli_do_setup(cur_cp->id);
  408. }
  409. return cur_cp;
  410. }/*}}}*/
  411. PW32CP const struct php_win32_cp *php_win32_cp_shutdown(void)
  412. {/*{{{*/
  413. return orig_cp;
  414. }/*}}}*/
  415. /* php_win32_cp_setup() needs to have run before! */
  416. PW32CP const struct php_win32_cp *php_win32_cp_cli_do_setup(DWORD id)
  417. {/*{{{*/
  418. const struct php_win32_cp *cp;
  419. if (!orig_cp) {
  420. php_win32_cp_setup();
  421. }
  422. if (id) {
  423. cp = php_win32_cp_set_by_id(id);
  424. } else {
  425. cp = cur_cp;
  426. }
  427. if (!cp) {
  428. return NULL;
  429. }
  430. if (php_win32_cp_cli_io_setup()) {
  431. return cp;
  432. }
  433. return cp;
  434. }/*}}}*/
  435. PW32CP const struct php_win32_cp *php_win32_cp_cli_do_restore(DWORD id)
  436. {/*{{{*/
  437. BOOL cli_io_restored = TRUE;
  438. if (orig_in_cp) {
  439. cli_io_restored = cli_io_restored && SetConsoleCP(orig_in_cp->id);
  440. }
  441. if (orig_out_cp) {
  442. cli_io_restored = cli_io_restored && SetConsoleOutputCP(orig_out_cp->id);
  443. }
  444. if (cli_io_restored && id) {
  445. return php_win32_cp_set_by_id(id);
  446. }
  447. return NULL;
  448. }/*}}}*/
  449. /* Userspace functions, see basic_functions.* for arginfo and decls. */
  450. /* {{{ proto bool sapi_windows_cp_set(int cp)
  451. * Set process codepage. */
  452. PHP_FUNCTION(sapi_windows_cp_set)
  453. {
  454. zend_long id;
  455. const struct php_win32_cp *cp;
  456. if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &id) == FAILURE) {
  457. return;
  458. }
  459. if (ZEND_LONG_UINT_OVFL(id)) {
  460. php_error_docref(NULL, E_WARNING, "Argument %d is out of range", id);
  461. RETURN_FALSE;
  462. }
  463. if (php_win32_cp_is_cli_sapi()) {
  464. cp = php_win32_cp_cli_do_setup((DWORD)id);
  465. } else {
  466. cp = php_win32_cp_set_by_id((DWORD)id);
  467. }
  468. if (!cp) {
  469. php_error_docref(NULL, E_WARNING, "Failed to switch to codepage %d", id);
  470. RETURN_FALSE;
  471. }
  472. RETURN_BOOL(cp->id == id);
  473. }
  474. /* }}} */
  475. /* {{{ proto int sapi_windows_cp_get([string kind])
  476. * Get process codepage. */
  477. PHP_FUNCTION(sapi_windows_cp_get)
  478. {
  479. char *kind;
  480. size_t kind_len = 0;
  481. if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s", &kind, &kind_len) == FAILURE) {
  482. return;
  483. }
  484. if (kind_len == sizeof("ansi")-1 && !strncasecmp(kind, "ansi", kind_len)) {
  485. RETURN_LONG(GetACP());
  486. } else if (kind_len == sizeof("oem")-1 && !strncasecmp(kind, "oem", kind_len)) {
  487. RETURN_LONG(GetOEMCP());
  488. } else {
  489. const struct php_win32_cp *cp = php_win32_cp_get_current();
  490. RETURN_LONG(cp->id);
  491. }
  492. }
  493. /* }}} */
  494. /* {{{ proto bool sapi_windows_cp_is_utf8(void)
  495. * Indicates whether the codepage is UTF-8 compatible. */
  496. PHP_FUNCTION(sapi_windows_cp_is_utf8)
  497. {
  498. if (zend_parse_parameters_none() == FAILURE) {
  499. return;
  500. }
  501. RETURN_BOOL(php_win32_cp_use_unicode());
  502. }
  503. /* }}} */
  504. /* {{{ proto string sapi_windows_cp_conv(int|string in_codepage, int|string out_codepage, string subject)
  505. * Convert string from one codepage to another. */
  506. PHP_FUNCTION(sapi_windows_cp_conv)
  507. {
  508. char *subj, *ret;
  509. size_t subj_len, ret_len, tmpw_len;
  510. wchar_t *tmpw;
  511. const struct php_win32_cp *in_cp, *out_cp;
  512. zval *z_in_cp, *z_out_cp;
  513. if (zend_parse_parameters(ZEND_NUM_ARGS(), "zzs", &z_in_cp, &z_out_cp, &subj, &subj_len) == FAILURE) {
  514. return;
  515. }
  516. if (ZEND_SIZE_T_INT_OVFL(subj_len)) {
  517. php_error_docref(NULL, E_WARNING, "String is too long");
  518. RETURN_NULL();
  519. }
  520. if (IS_LONG == Z_TYPE_P(z_in_cp)) {
  521. if (ZEND_LONG_UINT_OVFL(Z_LVAL_P(z_in_cp))) {
  522. php_error_docref(NULL, E_WARNING, "Argument %d is out of range", Z_LVAL_P(z_in_cp));
  523. RETURN_NULL();
  524. }
  525. in_cp = php_win32_cp_get_by_id((DWORD)Z_LVAL_P(z_in_cp));
  526. if (!in_cp) {
  527. php_error_docref(NULL, E_WARNING, "Invalid codepage %d", Z_LVAL_P(z_in_cp));
  528. RETURN_NULL();
  529. }
  530. } else {
  531. convert_to_string(z_in_cp);
  532. in_cp = php_win32_cp_get_by_enc(Z_STRVAL_P(z_in_cp));
  533. if (!in_cp) {
  534. php_error_docref(NULL, E_WARNING, "Invalid charset %s", Z_STRVAL_P(z_in_cp));
  535. RETURN_NULL();
  536. }
  537. }
  538. if (IS_LONG == Z_TYPE_P(z_out_cp)) {
  539. if (ZEND_LONG_UINT_OVFL(Z_LVAL_P(z_out_cp))) {
  540. php_error_docref(NULL, E_WARNING, "Argument %d is out of range", Z_LVAL_P(z_out_cp));
  541. RETURN_NULL();
  542. }
  543. out_cp = php_win32_cp_get_by_id((DWORD)Z_LVAL_P(z_out_cp));
  544. if (!out_cp) {
  545. php_error_docref(NULL, E_WARNING, "Invalid codepage %d", Z_LVAL_P(z_out_cp));
  546. RETURN_NULL();
  547. }
  548. } else {
  549. convert_to_string(z_out_cp);
  550. out_cp = php_win32_cp_get_by_enc(Z_STRVAL_P(z_out_cp));
  551. if (!out_cp) {
  552. php_error_docref(NULL, E_WARNING, "Invalid charset %s", Z_STRVAL_P(z_out_cp));
  553. RETURN_NULL();
  554. }
  555. }
  556. tmpw = php_win32_cp_conv_to_w(in_cp->id, in_cp->to_w_fl, subj, subj_len, &tmpw_len);
  557. if (!tmpw) {
  558. php_error_docref(NULL, E_WARNING, "Wide char conversion failed");
  559. RETURN_NULL();
  560. }
  561. ret = php_win32_cp_conv_from_w(out_cp->id, out_cp->from_w_fl, tmpw, tmpw_len, &ret_len);
  562. if (!ret) {
  563. free(tmpw);
  564. php_error_docref(NULL, E_WARNING, "Wide char conversion failed");
  565. RETURN_NULL();
  566. }
  567. RETVAL_STRINGL(ret, ret_len);
  568. free(tmpw);
  569. free(ret);
  570. }
  571. /* }}} */
  572. /* }}} */
  573. /*
  574. * Local variables:
  575. * tab-width: 4
  576. * c-basic-offset: 4
  577. * End:
  578. * vim600: sw=4 ts=4 fdm=marker
  579. * vim<600: sw=4 ts=4
  580. */