1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 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
19 #include <assert.h>
20
21 #include "php.h"
22 #include "SAPI.h"
23 #include <emmintrin.h>
24
25 #include "win32/console.h"
26
27 ZEND_TLS const struct php_win32_cp *cur_cp = NULL;
28 ZEND_TLS const struct php_win32_cp *orig_cp = NULL;
29 ZEND_TLS const struct php_win32_cp *cur_out_cp = NULL;
30 ZEND_TLS const struct php_win32_cp *orig_out_cp = NULL;
31 ZEND_TLS const struct php_win32_cp *cur_in_cp = NULL;
32 ZEND_TLS const struct php_win32_cp *orig_in_cp = NULL;
33
34 #include "cp_enc_map.c"
35
php_win32_cp_to_w_int(const char * in,size_t in_len,size_t * out_len,UINT cp,DWORD flags)36 __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)
37 {/*{{{*/
38 wchar_t *ret;
39 int ret_len, tmp_len;
40
41 if (!in || in_len > (size_t)INT_MAX) {
42 SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER);
43 return NULL;
44 }
45 assert(in_len ? (in[in_len] == L'\0') : 1);
46
47 tmp_len = !in_len ? -1 : (int)in_len + 1;
48
49 ret_len = MultiByteToWideChar(cp, flags, in, tmp_len, NULL, 0);
50 if (ret_len == 0) {
51 SET_ERRNO_FROM_WIN32_CODE(GetLastError());
52 return NULL;
53 }
54
55 ret = malloc(ret_len * sizeof(wchar_t));
56 if (!ret) {
57 SET_ERRNO_FROM_WIN32_CODE(ERROR_OUTOFMEMORY);
58 return NULL;
59 }
60
61 tmp_len = MultiByteToWideChar(cp, flags, in, tmp_len, ret, ret_len);
62 if (tmp_len == 0) {
63 free(ret);
64 SET_ERRNO_FROM_WIN32_CODE(GetLastError());
65 return NULL;
66 }
67
68 assert(ret ? tmp_len == ret_len : 1);
69 assert(ret && !in_len ? wcslen(ret) == ret_len - 1 : 1);
70
71 ret[ret_len-1] = L'\0';
72
73 if (PHP_WIN32_CP_IGNORE_LEN_P != out_len) {
74 *out_len = ret_len - 1;
75 }
76
77 return ret;
78 }/*}}}*/
79
php_win32_cp_conv_utf8_to_w(const char * in,size_t in_len,size_t * out_len)80 PW32CP wchar_t *php_win32_cp_conv_utf8_to_w(const char* in, size_t in_len, size_t *out_len)
81 {/*{{{*/
82 return php_win32_cp_to_w_int(in, in_len, out_len, CP_UTF8, MB_ERR_INVALID_CHARS);
83 }/*}}}*/
84
php_win32_cp_conv_cur_to_w(const char * in,size_t in_len,size_t * out_len)85 PW32CP wchar_t *php_win32_cp_conv_cur_to_w(const char* in, size_t in_len, size_t *out_len)
86 {/*{{{*/
87 wchar_t *ret;
88
89 ret = php_win32_cp_to_w_int(in, in_len, out_len, cur_cp->id, cur_cp->from_w_fl);
90
91 return ret;
92 }/*}}}*/
93
php_win32_cp_conv_to_w(DWORD cp,DWORD flags,const char * in,size_t in_len,size_t * out_len)94 PW32CP wchar_t *php_win32_cp_conv_to_w(DWORD cp, DWORD flags, const char* in, size_t in_len, size_t *out_len)
95 {/*{{{*/
96 return php_win32_cp_to_w_int(in, in_len, out_len, cp, flags);
97 }/*}}}*/
98
99 #define ASCII_FAIL_RETURN() \
100 if (PHP_WIN32_CP_IGNORE_LEN_P != out_len) { \
101 *out_len = 0; \
102 } \
103 return NULL;
php_win32_cp_conv_ascii_to_w(const char * in,size_t in_len,size_t * out_len)104 PW32CP wchar_t *php_win32_cp_conv_ascii_to_w(const char* in, size_t in_len, size_t *out_len)
105 {/*{{{*/
106 wchar_t *ret, *ret_idx;
107 const char *idx = in, *end;
108 char ch_err = 0;
109
110 #if PHP_DEBUG
111 size_t save_in_len = in_len;
112 #endif
113
114 assert(in && in_len ? in[in_len] == '\0' : 1);
115
116 if (!in) {
117 SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER);
118 return NULL;
119 } else if (0 == in_len) {
120 /* Not binary safe. */
121 in_len = strlen(in);
122 }
123
124 end = in + in_len;
125
126 if (in_len > 15) {
127 const char *aidx = (const char *)ZEND_SLIDE_TO_ALIGNED16(in);
128
129 /* Process unaligned chunk. */
130 while (idx < aidx) {
131 ch_err |= *idx;
132 idx++;
133 }
134 if (ch_err & 0x80) {
135 ASCII_FAIL_RETURN()
136 }
137
138 /* Process aligned chunk. */
139 __m128i vec_err = _mm_setzero_si128();
140 while (end - idx > 15) {
141 const __m128i block = _mm_load_si128((__m128i *)idx);
142 vec_err = _mm_or_si128(vec_err, block);
143 idx += 16;
144 }
145 if (_mm_movemask_epi8(vec_err)) {
146 ASCII_FAIL_RETURN()
147 }
148 }
149
150 /* Process the trailing part, or otherwise process string < 16 bytes. */
151 while (idx < end) {
152 ch_err |= *idx;
153 idx++;
154 }
155 if (ch_err & 0x80) {
156 ASCII_FAIL_RETURN()
157 }
158
159 ret = malloc((in_len+1)*sizeof(wchar_t));
160 if (!ret) {
161 SET_ERRNO_FROM_WIN32_CODE(ERROR_OUTOFMEMORY);
162 return NULL;
163 }
164
165 ret_idx = ret;
166 idx = in;
167
168 if (in_len > 15) {
169 const char *aidx = (const char *)ZEND_SLIDE_TO_ALIGNED16(in);
170
171 /* Process unaligned chunk. */
172 while (idx < aidx) {
173 *ret_idx++ = (wchar_t)*idx++;
174 }
175
176 /* Process aligned chunk. */
177 if (end - idx > 15) {
178 const __m128i mask = _mm_set1_epi32(0);
179 while (end - idx > 15) {
180 const __m128i block = _mm_load_si128((__m128i *)idx);
181
182 {
183 const __m128i lo = _mm_unpacklo_epi8(block, mask);
184 _mm_storeu_si128((__m128i *)ret_idx, lo);
185 }
186
187 ret_idx += 8;
188 {
189 const __m128i hi = _mm_unpackhi_epi8(block, mask);
190 _mm_storeu_si128((__m128i *)ret_idx, hi);
191 }
192
193 idx += 16;
194 ret_idx += 8;
195 }
196 }
197 }
198
199 /* Process the trailing part, or otherwise process string < 16 bytes. */
200 while (idx < end) {
201 *ret_idx++ = (wchar_t)*idx++;
202 }
203
204 ret[in_len] = L'\0';
205
206 assert(ret && !save_in_len ? wcslen(ret) == in_len : 1);
207
208 if (PHP_WIN32_CP_IGNORE_LEN_P != out_len) {
209 *out_len = in_len;
210 }
211
212 return ret;
213 }/*}}}*/
214 #undef ASCII_FAIL_RETURN
215
php_win32_cp_from_w_int(const wchar_t * in,size_t in_len,size_t * out_len,UINT cp,DWORD flags)216 __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)
217 {/*{{{*/
218 int r;
219 int target_len, tmp_len;
220 char* target;
221
222 if (!in || in_len > INT_MAX) {
223 SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER);
224 return NULL;
225 }
226 assert(in_len ? in[in_len] == '\0' : 1);
227
228 tmp_len = !in_len ? -1 : (int)in_len + 1;
229
230 target_len = WideCharToMultiByte(cp, flags, in, tmp_len, NULL, 0, NULL, NULL);
231 if (target_len == 0) {
232 SET_ERRNO_FROM_WIN32_CODE(GetLastError());
233 return NULL;
234 }
235
236 target = malloc(target_len);
237 if (target == NULL) {
238 SET_ERRNO_FROM_WIN32_CODE(ERROR_OUTOFMEMORY);
239 return NULL;
240 }
241
242 r = WideCharToMultiByte(cp, flags, in, tmp_len, target, target_len, NULL, NULL);
243 if (r == 0) {
244 free(target);
245 SET_ERRNO_FROM_WIN32_CODE(GetLastError());
246 return NULL;
247 }
248
249 assert(target ? r == target_len : 1);
250 assert(target && !in_len ? strlen(target) == target_len - 1 : 1);
251
252 target[target_len-1] = '\0';
253
254 if (PHP_WIN32_CP_IGNORE_LEN_P != out_len) {
255 *out_len = target_len - 1;
256 }
257
258 return target;
259 }/*}}}*/
260
php_win32_cp_conv_w_to_utf8(const wchar_t * in,size_t in_len,size_t * out_len)261 PW32CP char *php_win32_cp_conv_w_to_utf8(const wchar_t* in, size_t in_len, size_t *out_len)
262 {/*{{{*/
263 return php_win32_cp_from_w_int(in, in_len, out_len, CP_UTF8, WC_ERR_INVALID_CHARS);
264 }/*}}}*/
265
php_win32_cp_conv_w_to_cur(const wchar_t * in,size_t in_len,size_t * out_len)266 PW32CP char *php_win32_cp_conv_w_to_cur(const wchar_t* in, size_t in_len, size_t *out_len)
267 {/*{{{*/
268 char *ret;
269
270 ret = php_win32_cp_from_w_int(in, in_len, out_len, cur_cp->id, cur_cp->from_w_fl);
271
272 return ret;
273 }/*}}}*/
274
php_win32_cp_conv_from_w(DWORD cp,DWORD flags,const wchar_t * in,size_t in_len,size_t * out_len)275 PW32CP char *php_win32_cp_conv_from_w(DWORD cp, DWORD flags, const wchar_t* in, size_t in_len, size_t *out_len)
276 {/*{{{*/
277 return php_win32_cp_from_w_int(in, in_len, out_len, cp, flags);
278 }/*}}}*/
279
280 /* This is only usable after the startup phase*/
php_win32_cp_get_enc(void)281 __forceinline static char *php_win32_cp_get_enc(void)
282 {/*{{{*/
283 char *enc = NULL;
284 const zend_encoding *zenc;
285
286 if (PG(internal_encoding) && PG(internal_encoding)[0]) {
287 enc = PG(internal_encoding);
288 } else if (SG(default_charset) && SG(default_charset)[0] ) {
289 enc = SG(default_charset);
290 } else {
291 zenc = zend_multibyte_get_internal_encoding();
292 if (zenc) {
293 enc = (char *)zend_multibyte_get_encoding_name(zenc);
294 }
295 }
296
297 return enc;
298 }/*}}}*/
299
php_win32_cp_get_current(void)300 PW32CP const struct php_win32_cp *php_win32_cp_get_current(void)
301 {/*{{{*/
302 return cur_cp;
303 }/*}}}*/
304
php_win32_cp_get_orig(void)305 PW32CP const struct php_win32_cp *php_win32_cp_get_orig(void)
306 {/*{{{*/
307 return orig_cp;
308 }/*}}}*/
309
php_win32_cp_get_by_id(DWORD id)310 PW32CP const struct php_win32_cp *php_win32_cp_get_by_id(DWORD id)
311 {/*{{{*/
312 size_t i;
313
314 if (id < php_win32_cp_map[0].id) {
315 switch (id) {
316 case CP_ACP:
317 id = GetACP();
318 break;
319 case CP_OEMCP:
320 id = GetOEMCP();
321 break;
322 }
323 }
324
325 for (i = 0; i < sizeof(php_win32_cp_map)/sizeof(struct php_win32_cp); i++) {
326 if (php_win32_cp_map[i].id == id) {
327 return &php_win32_cp_map[i];
328 }
329 }
330
331 SET_ERRNO_FROM_WIN32_CODE(ERROR_NOT_FOUND);
332
333 return NULL;
334 }/*}}}*/
335
php_win32_cp_get_by_enc(const char * enc)336 PW32CP const struct php_win32_cp *php_win32_cp_get_by_enc(const char *enc)
337 {/*{{{*/
338 size_t enc_len = 0, i;
339
340 if (!enc || !enc[0]) {
341 return php_win32_cp_get_by_id(65001U);
342 }
343
344 enc_len = strlen(enc);
345
346 for (i = 0; i < sizeof(php_win32_cp_map)/sizeof(struct php_win32_cp); i++) {
347 const struct php_win32_cp *cp = &php_win32_cp_map[i];
348
349 if (!cp->name || !cp->name[0]) {
350 continue;
351 }
352
353 if (0 == zend_binary_strcasecmp(enc, enc_len, cp->name, strlen(cp->name))) {
354 return cp;
355 }
356
357 if (cp->enc) {
358 char *start = cp->enc, *idx;
359
360 idx = strpbrk(start, "|");
361
362 while (NULL != idx) {
363 if (0 == zend_binary_strcasecmp(enc, enc_len, start, idx - start)) {
364 return cp;
365 }
366 start = idx + 1;
367 idx = strpbrk(start, "|");
368 }
369 /* Last in the list, or single charset specified. */
370 if (0 == zend_binary_strcasecmp(enc, enc_len, start, strlen(start))) {
371 return cp;
372 }
373 }
374 }
375
376 return php_win32_cp_get_by_id(GetACP());
377 }/*}}}*/
378
php_win32_cp_set_by_id(DWORD id)379 PW32CP const struct php_win32_cp *php_win32_cp_set_by_id(DWORD id)
380 {/*{{{*/
381 const struct php_win32_cp *tmp;
382 if (!IsValidCodePage(id)) {
383 SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER);
384 return NULL;
385 }
386
387 tmp = php_win32_cp_get_by_id(id);
388 if (tmp) {
389 cur_cp = tmp;
390 }
391
392 return cur_cp;
393 }/*}}}*/
394
php_win32_cp_use_unicode(void)395 PW32CP BOOL php_win32_cp_use_unicode(void)
396 {/*{{{*/
397 return 65001 == cur_cp->id;
398 }/*}}}*/
399
php_win32_cp_env_any_to_w(const char * env)400 PW32CP wchar_t *php_win32_cp_env_any_to_w(const char* env)
401 {/*{{{*/
402 wchar_t *envw = NULL, ew[32760];
403 char *cur = (char *)env, *prev;
404 size_t bin_len = 0;
405
406 if (!env) {
407 SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER);
408 return NULL;
409 }
410
411 do {
412 wchar_t *tmp;
413
414 tmp = php_win32_cp_any_to_w(cur);
415 if (tmp) {
416 size_t tmp_len = wcslen(tmp) + 1;
417 memmove(ew + bin_len, tmp, tmp_len * sizeof(wchar_t));
418 free(tmp);
419
420 bin_len += tmp_len;
421 }
422
423 prev = cur;
424
425 } while (NULL != (cur = strchr(prev, '\0')) && cur++ && *cur && bin_len + (cur - prev) < 32760);
426
427 envw = (wchar_t *) malloc((bin_len + 3) * sizeof(wchar_t));
428 if (!envw) {
429 SET_ERRNO_FROM_WIN32_CODE(ERROR_OUTOFMEMORY);
430 return NULL;
431 }
432 memmove(envw, ew, bin_len * sizeof(wchar_t));
433 envw[bin_len] = L'\0';
434 envw[bin_len + 1] = L'\0';
435 envw[bin_len + 2] = L'\0';
436
437 return envw;
438 }/*}}}*/
439
php_win32_cp_cli_io_setup(void)440 static BOOL php_win32_cp_cli_io_setup(void)
441 {/*{{{*/
442 BOOL ret = TRUE;
443
444 if (PG(input_encoding) && PG(input_encoding)[0]) {
445 cur_in_cp = php_win32_cp_get_by_enc(PG(input_encoding));
446 if (!cur_in_cp) {
447 cur_in_cp = cur_cp;
448 }
449 } else {
450 cur_in_cp = cur_cp;
451 }
452
453 if (PG(output_encoding) && PG(output_encoding)[0]) {
454 cur_out_cp = php_win32_cp_get_by_enc(PG(output_encoding));
455 if (!cur_out_cp) {
456 cur_out_cp = cur_cp;
457 }
458 } else {
459 cur_out_cp = cur_cp;
460 }
461
462 if(php_get_module_initialized()) {
463 ret = SetConsoleCP(cur_in_cp->id) && SetConsoleOutputCP(cur_out_cp->id);
464 }
465
466 return ret;
467 }/*}}}*/
468
php_win32_cp_do_setup(const char * enc)469 PW32CP const struct php_win32_cp *php_win32_cp_do_setup(const char *enc)
470 {/*{{{*/
471 if (!enc) {
472 enc = php_win32_cp_get_enc();
473 }
474
475 cur_cp = php_win32_cp_get_by_enc(enc);
476 if (!orig_cp) {
477 orig_cp = php_win32_cp_get_by_id(GetACP());
478 }
479 if (php_win32_console_is_cli_sapi()) {
480 if (!orig_in_cp) {
481 orig_in_cp = php_win32_cp_get_by_id(GetConsoleCP());
482 if (!orig_in_cp) {
483 orig_in_cp = orig_cp;
484 }
485 }
486 if (!orig_out_cp) {
487 orig_out_cp = php_win32_cp_get_by_id(GetConsoleOutputCP());
488 if (!orig_out_cp) {
489 orig_out_cp = orig_cp;
490 }
491 }
492 php_win32_cp_cli_io_setup();
493 }
494
495 return cur_cp;
496 }/*}}}*/
497
php_win32_cp_do_update(const char * enc)498 PW32CP const struct php_win32_cp *php_win32_cp_do_update(const char *enc)
499 {/*{{{*/
500 if (!enc) {
501 enc = php_win32_cp_get_enc();
502 }
503 cur_cp = php_win32_cp_get_by_enc(enc);
504
505 if (php_win32_console_is_cli_sapi()) {
506 php_win32_cp_cli_do_setup(cur_cp->id);
507 }
508
509 return cur_cp;
510 }/*}}}*/
511
php_win32_cp_shutdown(void)512 PW32CP const struct php_win32_cp *php_win32_cp_shutdown(void)
513 {/*{{{*/
514 return orig_cp;
515 }/*}}}*/
516
517 /* php_win32_cp_setup() needs to have run before! */
php_win32_cp_cli_do_setup(DWORD id)518 PW32CP const struct php_win32_cp *php_win32_cp_cli_do_setup(DWORD id)
519 {/*{{{*/
520 const struct php_win32_cp *cp;
521
522 if (!orig_cp) {
523 php_win32_cp_setup();
524 }
525
526 if (id) {
527 cp = php_win32_cp_set_by_id(id);
528 } else {
529 cp = cur_cp;
530 }
531
532 if (!cp) {
533 return NULL;
534 }
535
536 if (php_win32_cp_cli_io_setup()) {
537 return cp;
538 }
539
540 return cp;
541 }/*}}}*/
542
php_win32_cp_cli_do_restore(DWORD id)543 PW32CP const struct php_win32_cp *php_win32_cp_cli_do_restore(DWORD id)
544 {/*{{{*/
545 BOOL cli_io_restored = TRUE;
546
547 if (orig_in_cp) {
548 cli_io_restored = cli_io_restored && SetConsoleCP(orig_in_cp->id);
549 }
550
551 if (orig_out_cp) {
552 cli_io_restored = cli_io_restored && SetConsoleOutputCP(orig_out_cp->id);
553 }
554
555 if (cli_io_restored && id) {
556 return php_win32_cp_set_by_id(id);
557 }
558
559 return NULL;
560 }/*}}}*/
561
562 /* Userspace functions, see basic_functions.* for arginfo and decls. */
563
564 /* {{{ proto bool sapi_windows_cp_set(int cp)
565 * Set process codepage. */
PHP_FUNCTION(sapi_windows_cp_set)566 PHP_FUNCTION(sapi_windows_cp_set)
567 {
568 zend_long id;
569 const struct php_win32_cp *cp;
570
571 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &id) == FAILURE) {
572 return;
573 }
574
575 if (ZEND_LONG_UINT_OVFL(id)) {
576 php_error_docref(NULL, E_WARNING, "Argument %d is out of range", id);
577 RETURN_FALSE;
578 }
579
580 if (php_win32_console_is_cli_sapi()) {
581 cp = php_win32_cp_cli_do_setup((DWORD)id);
582 } else {
583 cp = php_win32_cp_set_by_id((DWORD)id);
584 }
585 if (!cp) {
586 php_error_docref(NULL, E_WARNING, "Failed to switch to codepage %d", id);
587 RETURN_FALSE;
588 }
589
590 RETURN_BOOL(cp->id == id);
591 }
592 /* }}} */
593
594 /* {{{ proto int sapi_windows_cp_get([string kind])
595 * Get process codepage. */
PHP_FUNCTION(sapi_windows_cp_get)596 PHP_FUNCTION(sapi_windows_cp_get)
597 {
598 char *kind;
599 size_t kind_len = 0;
600
601 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s", &kind, &kind_len) == FAILURE) {
602 return;
603 }
604
605 if (kind_len == sizeof("ansi")-1 && !strncasecmp(kind, "ansi", kind_len)) {
606 RETURN_LONG(GetACP());
607 } else if (kind_len == sizeof("oem")-1 && !strncasecmp(kind, "oem", kind_len)) {
608 RETURN_LONG(GetOEMCP());
609 } else {
610 const struct php_win32_cp *cp = php_win32_cp_get_current();
611 RETURN_LONG(cp->id);
612 }
613 }
614 /* }}} */
615
616
617 /* {{{ proto bool sapi_windows_cp_is_utf8(void)
618 * Indicates whether the codepage is UTF-8 compatible. */
PHP_FUNCTION(sapi_windows_cp_is_utf8)619 PHP_FUNCTION(sapi_windows_cp_is_utf8)
620 {
621 if (zend_parse_parameters_none() == FAILURE) {
622 return;
623 }
624
625 RETURN_BOOL(php_win32_cp_use_unicode());
626 }
627 /* }}} */
628
629 /* {{{ proto string sapi_windows_cp_conv(int|string in_codepage, int|string out_codepage, string subject)
630 * Convert string from one codepage to another. */
PHP_FUNCTION(sapi_windows_cp_conv)631 PHP_FUNCTION(sapi_windows_cp_conv)
632 {
633 char *subj, *ret;
634 size_t subj_len, ret_len, tmpw_len;
635 wchar_t *tmpw;
636 const struct php_win32_cp *in_cp, *out_cp;
637 zval *z_in_cp, *z_out_cp;
638
639 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zzs", &z_in_cp, &z_out_cp, &subj, &subj_len) == FAILURE) {
640 return;
641 }
642
643 if (ZEND_SIZE_T_INT_OVFL(subj_len)) {
644 php_error_docref(NULL, E_WARNING, "String is too long");
645 RETURN_NULL();
646 }
647
648 if (IS_LONG == Z_TYPE_P(z_in_cp)) {
649 if (ZEND_LONG_UINT_OVFL(Z_LVAL_P(z_in_cp))) {
650 php_error_docref(NULL, E_WARNING, "Argument %d is out of range", Z_LVAL_P(z_in_cp));
651 RETURN_NULL();
652 }
653
654 in_cp = php_win32_cp_get_by_id((DWORD)Z_LVAL_P(z_in_cp));
655 if (!in_cp) {
656 php_error_docref(NULL, E_WARNING, "Invalid codepage %d", Z_LVAL_P(z_in_cp));
657 RETURN_NULL();
658 }
659 } else {
660 if (!try_convert_to_string(z_in_cp)) {
661 return;
662 }
663
664 in_cp = php_win32_cp_get_by_enc(Z_STRVAL_P(z_in_cp));
665 if (!in_cp) {
666 php_error_docref(NULL, E_WARNING, "Invalid charset %s", Z_STRVAL_P(z_in_cp));
667 RETURN_NULL();
668 }
669 }
670
671 if (IS_LONG == Z_TYPE_P(z_out_cp)) {
672 if (ZEND_LONG_UINT_OVFL(Z_LVAL_P(z_out_cp))) {
673 php_error_docref(NULL, E_WARNING, "Argument %d is out of range", Z_LVAL_P(z_out_cp));
674 RETURN_NULL();
675 }
676
677 out_cp = php_win32_cp_get_by_id((DWORD)Z_LVAL_P(z_out_cp));
678 if (!out_cp) {
679 php_error_docref(NULL, E_WARNING, "Invalid codepage %d", Z_LVAL_P(z_out_cp));
680 RETURN_NULL();
681 }
682 } else {
683 if (!try_convert_to_string(z_out_cp)) {
684 return;
685 }
686
687 out_cp = php_win32_cp_get_by_enc(Z_STRVAL_P(z_out_cp));
688 if (!out_cp) {
689 php_error_docref(NULL, E_WARNING, "Invalid charset %s", Z_STRVAL_P(z_out_cp));
690 RETURN_NULL();
691 }
692 }
693
694 tmpw = php_win32_cp_conv_to_w(in_cp->id, in_cp->to_w_fl, subj, subj_len, &tmpw_len);
695 if (!tmpw) {
696 php_error_docref(NULL, E_WARNING, "Wide char conversion failed");
697 RETURN_NULL();
698 }
699
700 ret = php_win32_cp_conv_from_w(out_cp->id, out_cp->from_w_fl, tmpw, tmpw_len, &ret_len);
701 if (!ret) {
702 free(tmpw);
703 php_error_docref(NULL, E_WARNING, "Wide char conversion failed");
704 RETURN_NULL();
705 }
706
707 RETVAL_STRINGL(ret, ret_len);
708
709 free(tmpw);
710 free(ret);
711 }
712 /* }}} */
713
714 /* }}} */
715