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