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 #include <emmintrin.h>
24
25 ZEND_TLS const struct php_win32_cp *cur_cp = NULL;
26 ZEND_TLS const struct php_win32_cp *orig_cp = NULL;
27 ZEND_TLS const struct php_win32_cp *cur_out_cp = NULL;
28 ZEND_TLS const struct php_win32_cp *orig_out_cp = NULL;
29 ZEND_TLS const struct php_win32_cp *cur_in_cp = NULL;
30 ZEND_TLS const struct php_win32_cp *orig_in_cp = NULL;
31
32 #include "cp_enc_map.c"
33
php_win32_cp_to_w_int(const char * in,size_t in_len,size_t * out_len,UINT cp,DWORD flags)34 __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)
35 {/*{{{*/
36 wchar_t *ret;
37 int ret_len, tmp_len;
38
39 if (!in || in_len > (size_t)INT_MAX) {
40 SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER);
41 return NULL;
42 }
43 assert(in_len ? (in[in_len] == L'\0') : 1);
44
45 tmp_len = !in_len ? -1 : (int)in_len + 1;
46
47 ret_len = MultiByteToWideChar(cp, flags, in, tmp_len, NULL, 0);
48 if (ret_len == 0) {
49 SET_ERRNO_FROM_WIN32_CODE(GetLastError());
50 return NULL;
51 }
52
53 ret = malloc(ret_len * sizeof(wchar_t));
54 if (!ret) {
55 SET_ERRNO_FROM_WIN32_CODE(ERROR_OUTOFMEMORY);
56 return NULL;
57 }
58
59 tmp_len = MultiByteToWideChar(cp, flags, in, tmp_len, ret, ret_len);
60 if (tmp_len == 0) {
61 free(ret);
62 SET_ERRNO_FROM_WIN32_CODE(GetLastError());
63 return NULL;
64 }
65
66 assert(ret ? tmp_len == ret_len : 1);
67 assert(ret && !in_len ? wcslen(ret) == ret_len - 1 : 1);
68
69 ret[ret_len-1] = L'\0';
70
71 if (PHP_WIN32_CP_IGNORE_LEN_P != out_len) {
72 *out_len = ret_len - 1;
73 }
74
75 return ret;
76 }/*}}}*/
77
php_win32_cp_conv_utf8_to_w(const char * in,size_t in_len,size_t * out_len)78 PW32CP wchar_t *php_win32_cp_conv_utf8_to_w(const char* in, size_t in_len, size_t *out_len)
79 {/*{{{*/
80 return php_win32_cp_to_w_int(in, in_len, out_len, CP_UTF8, MB_ERR_INVALID_CHARS);
81 }/*}}}*/
82
php_win32_cp_conv_cur_to_w(const char * in,size_t in_len,size_t * out_len)83 PW32CP wchar_t *php_win32_cp_conv_cur_to_w(const char* in, size_t in_len, size_t *out_len)
84 {/*{{{*/
85 wchar_t *ret;
86
87 ret = php_win32_cp_to_w_int(in, in_len, out_len, cur_cp->id, cur_cp->from_w_fl);
88
89 return ret;
90 }/*}}}*/
91
php_win32_cp_conv_to_w(DWORD cp,DWORD flags,const char * in,size_t in_len,size_t * out_len)92 PW32CP wchar_t *php_win32_cp_conv_to_w(DWORD cp, DWORD flags, const char* in, size_t in_len, size_t *out_len)
93 {/*{{{*/
94 return php_win32_cp_to_w_int(in, in_len, out_len, cp, flags);
95 }/*}}}*/
96
97 #define ASCII_FAIL_RETURN() \
98 if (PHP_WIN32_CP_IGNORE_LEN_P != out_len) { \
99 *out_len = 0; \
100 } \
101 return NULL;
php_win32_cp_conv_ascii_to_w(const char * in,size_t in_len,size_t * out_len)102 PW32CP wchar_t *php_win32_cp_conv_ascii_to_w(const char* in, size_t in_len, size_t *out_len)
103 {/*{{{*/
104 wchar_t *ret, *ret_idx;
105 const char *idx = in, *end;
106 #if PHP_DEBUG
107 size_t save_in_len = in_len;
108 #endif
109
110 assert(in && in_len ? in[in_len] == '\0' : 1);
111
112 if (!in) {
113 SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER);
114 return NULL;
115 } else if (0 == in_len) {
116 /* Not binary safe. */
117 in_len = strlen(in);
118 }
119
120 end = in + in_len;
121
122 if (in_len > 15) {
123 const char *aidx = (const char *)ZEND_SLIDE_TO_ALIGNED16(in);
124
125 /* Process unaligned chunk. */
126 while (idx < aidx) {
127 if (!__isascii(*idx) && '\0' != *idx) {
128 ASCII_FAIL_RETURN()
129 }
130 idx++;
131 }
132
133 /* Process aligned chunk. */
134 while (end - idx > 15) {
135 const __m128i block = _mm_load_si128((__m128i *)idx);
136 if (_mm_movemask_epi8(block)) {
137 ASCII_FAIL_RETURN()
138 }
139 idx += 16;
140 }
141 }
142
143 /* Process the trailing part, or otherwise process string < 16 bytes. */
144 while (idx < end) {
145 if (!__isascii(*idx) && '\0' != *idx) {
146 ASCII_FAIL_RETURN()
147 }
148 idx++;
149 }
150
151 ret = malloc((in_len+1)*sizeof(wchar_t));
152 if (!ret) {
153 SET_ERRNO_FROM_WIN32_CODE(ERROR_OUTOFMEMORY);
154 return NULL;
155 }
156
157 ret_idx = ret;
158 idx = in;
159
160 /* Check and conversion could be merged. This however would
161 be more expencive, if a non ASCII string was passed.
162 TODO check whether the impact is acceptable. */
163 if (in_len > 15) {
164 const char *aidx = (const char *)ZEND_SLIDE_TO_ALIGNED16(in);
165
166 /* Process unaligned chunk. */
167 while (idx < aidx) {
168 *ret_idx++ = (wchar_t)*idx++;
169 }
170
171 /* Process aligned chunk. */
172 if (end - idx > 15) {
173 const __m128i mask = _mm_set1_epi32(0);
174 while (end - idx > 15) {
175 const __m128i block = _mm_load_si128((__m128i *)idx);
176
177 {
178 const __m128i lo = _mm_unpacklo_epi8(block, mask);
179 _mm_storeu_si128((__m128i *)ret_idx, lo);
180 }
181
182 ret_idx += 8;
183 {
184 const __m128i hi = _mm_unpackhi_epi8(block, mask);
185 _mm_storeu_si128((__m128i *)ret_idx, hi);
186 }
187
188 idx += 16;
189 ret_idx += 8;
190 }
191 }
192 }
193
194 /* Process the trailing part, or otherwise process string < 16 bytes. */
195 while (idx < end) {
196 *ret_idx++ = (wchar_t)*idx++;
197 }
198
199 ret[in_len] = L'\0';
200
201 assert(ret && !save_in_len ? wcslen(ret) == in_len : 1);
202
203 if (PHP_WIN32_CP_IGNORE_LEN_P != out_len) {
204 *out_len = in_len;
205 }
206
207 return ret;
208 }/*}}}*/
209 #undef ASCII_FAIL_RETURN
210
php_win32_cp_from_w_int(const wchar_t * in,size_t in_len,size_t * out_len,UINT cp,DWORD flags)211 __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)
212 {/*{{{*/
213 int r;
214 int target_len, tmp_len;
215 char* target;
216
217 if (!in || in_len > INT_MAX) {
218 SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER);
219 return NULL;
220 }
221 assert(in_len ? in[in_len] == '\0' : 1);
222
223 tmp_len = !in_len ? -1 : (int)in_len + 1;
224
225 target_len = WideCharToMultiByte(cp, flags, in, tmp_len, NULL, 0, NULL, NULL);
226 if (target_len == 0) {
227 SET_ERRNO_FROM_WIN32_CODE(GetLastError());
228 return NULL;
229 }
230
231 target = malloc(target_len);
232 if (target == NULL) {
233 SET_ERRNO_FROM_WIN32_CODE(ERROR_OUTOFMEMORY);
234 return NULL;
235 }
236
237 r = WideCharToMultiByte(cp, flags, in, tmp_len, target, target_len, NULL, NULL);
238 if (r == 0) {
239 free(target);
240 SET_ERRNO_FROM_WIN32_CODE(GetLastError());
241 return NULL;
242 }
243
244 assert(target ? r == target_len : 1);
245 assert(target && !in_len ? strlen(target) == target_len - 1 : 1);
246
247 target[target_len-1] = '\0';
248
249 if (PHP_WIN32_CP_IGNORE_LEN_P != out_len) {
250 *out_len = target_len - 1;
251 }
252
253 return target;
254 }/*}}}*/
255
php_win32_cp_conv_w_to_utf8(const wchar_t * in,size_t in_len,size_t * out_len)256 PW32CP char *php_win32_cp_conv_w_to_utf8(const wchar_t* in, size_t in_len, size_t *out_len)
257 {/*{{{*/
258 return php_win32_cp_from_w_int(in, in_len, out_len, CP_UTF8, WC_ERR_INVALID_CHARS);
259 }/*}}}*/
260
php_win32_cp_conv_w_to_cur(const wchar_t * in,size_t in_len,size_t * out_len)261 PW32CP char *php_win32_cp_conv_w_to_cur(const wchar_t* in, size_t in_len, size_t *out_len)
262 {/*{{{*/
263 char *ret;
264
265 ret = php_win32_cp_from_w_int(in, in_len, out_len, cur_cp->id, cur_cp->from_w_fl);
266
267 return ret;
268 }/*}}}*/
269
php_win32_cp_conv_from_w(DWORD cp,DWORD flags,const wchar_t * in,size_t in_len,size_t * out_len)270 PW32CP char *php_win32_cp_conv_from_w(DWORD cp, DWORD flags, const wchar_t* in, size_t in_len, size_t *out_len)
271 {/*{{{*/
272 return php_win32_cp_from_w_int(in, in_len, out_len, cp, flags);
273 }/*}}}*/
274
275 /* This is only usable after the startup phase*/
php_win32_cp_get_enc(void)276 __forceinline static char *php_win32_cp_get_enc(void)
277 {/*{{{*/
278 char *enc = NULL;
279 const zend_encoding *zenc;
280
281 if (PG(internal_encoding) && PG(internal_encoding)[0]) {
282 enc = PG(internal_encoding);
283 } else if (SG(default_charset) && SG(default_charset)[0] ) {
284 enc = SG(default_charset);
285 } else {
286 zenc = zend_multibyte_get_internal_encoding();
287 if (zenc) {
288 enc = (char *)zend_multibyte_get_encoding_name(zenc);
289 }
290 }
291
292 return enc;
293 }/*}}}*/
294
php_win32_cp_is_cli_sapi()295 __forceinline static BOOL php_win32_cp_is_cli_sapi()
296 {/*{{{*/
297 return strlen(sapi_module.name) >= sizeof("cli") - 1 && !strncmp(sapi_module.name, "cli", sizeof("cli") - 1);
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_cp_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_cp_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_cp_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 convert_to_string(z_in_cp);
661
662 in_cp = php_win32_cp_get_by_enc(Z_STRVAL_P(z_in_cp));
663 if (!in_cp) {
664 php_error_docref(NULL, E_WARNING, "Invalid charset %s", Z_STRVAL_P(z_in_cp));
665 RETURN_NULL();
666 }
667 }
668
669 if (IS_LONG == Z_TYPE_P(z_out_cp)) {
670 if (ZEND_LONG_UINT_OVFL(Z_LVAL_P(z_out_cp))) {
671 php_error_docref(NULL, E_WARNING, "Argument %d is out of range", Z_LVAL_P(z_out_cp));
672 RETURN_NULL();
673 }
674
675 out_cp = php_win32_cp_get_by_id((DWORD)Z_LVAL_P(z_out_cp));
676 if (!out_cp) {
677 php_error_docref(NULL, E_WARNING, "Invalid codepage %d", Z_LVAL_P(z_out_cp));
678 RETURN_NULL();
679 }
680 } else {
681 convert_to_string(z_out_cp);
682
683 out_cp = php_win32_cp_get_by_enc(Z_STRVAL_P(z_out_cp));
684 if (!out_cp) {
685 php_error_docref(NULL, E_WARNING, "Invalid charset %s", Z_STRVAL_P(z_out_cp));
686 RETURN_NULL();
687 }
688 }
689
690 tmpw = php_win32_cp_conv_to_w(in_cp->id, in_cp->to_w_fl, subj, subj_len, &tmpw_len);
691 if (!tmpw) {
692 php_error_docref(NULL, E_WARNING, "Wide char conversion failed");
693 RETURN_NULL();
694 }
695
696 ret = php_win32_cp_conv_from_w(out_cp->id, out_cp->from_w_fl, tmpw, tmpw_len, &ret_len);
697 if (!ret) {
698 free(tmpw);
699 php_error_docref(NULL, E_WARNING, "Wide char conversion failed");
700 RETURN_NULL();
701 }
702
703 RETVAL_STRINGL(ret, ret_len);
704
705 free(tmpw);
706 free(ret);
707 }
708 /* }}} */
709
710 /* }}} */
711 /*
712 * Local variables:
713 * tab-width: 4
714 * c-basic-offset: 4
715 * End:
716 * vim600: sw=4 ts=4 fdm=marker
717 * vim<600: sw=4 ts=4
718 */
719