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