xref: /PHP-7.2/win32/codepage.c (revision 27f168cf)
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