1 /*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | https://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Author: Anatol Belski <ab@php.net> |
14 +----------------------------------------------------------------------+
15 */
16
17 #ifndef PHP_WIN32_CODEPAGE_H
18 #define PHP_WIN32_CODEPAGE_H
19
20 #ifdef __cplusplus
21 extern "C" {
22 #endif
23
24 #ifdef PHP_EXPORTS
25 # define PW32CP __declspec(dllexport)
26 #else
27 # define PW32CP __declspec(dllimport)
28 #endif
29
30 #define PHP_WIN32_CP_IGNORE_LEN (0)
31 #define PHP_WIN32_CP_IGNORE_LEN_P ((size_t *)-1)
32
33 struct php_win32_cp {
34 DWORD id;
35 DWORD to_w_fl;
36 DWORD from_w_fl;
37 DWORD char_size;
38 char *name;
39 char *enc;
40 char *desc;
41 };
42
43 PW32CP BOOL php_win32_cp_use_unicode(void);
44 PW32CP const struct php_win32_cp *php_win32_cp_do_setup(const char *);
45 #define php_win32_cp_setup() php_win32_cp_do_setup(NULL)
46 PW32CP const struct php_win32_cp *php_win32_cp_do_update(const char *);
47 #define php_win32_cp_update() php_win32_cp_do_update(NULL)
48 PW32CP const struct php_win32_cp *php_win32_cp_shutdown(void);
49 PW32CP const struct php_win32_cp *php_win32_cp_get_current(void);
50 PW32CP const struct php_win32_cp *php_win32_cp_get_orig(void);
51 PW32CP const struct php_win32_cp *php_win32_cp_get_by_id(DWORD id);
52 PW32CP const struct php_win32_cp *php_win32_cp_set_by_id(DWORD id);
53 PW32CP const struct php_win32_cp *php_win32_cp_get_by_enc(const char *enc);
54 PW32CP const struct php_win32_cp *php_win32_cp_cli_do_setup(DWORD);
55 #define php_win32_cp_cli_setup() php_win32_cp_cli_do_setup(0)
56 #define php_win32_cp_cli_update() php_win32_cp_cli_do_setup(0)
57 PW32CP const struct php_win32_cp *php_win32_cp_cli_do_restore(DWORD);
58 #define php_win32_cp_cli_restore() php_win32_cp_cli_do_restore(0)
59
60 /* This API is binary safe and expects a \0 terminated input.
61 The returned out is \0 terminated, but the length doesn't count \0. */
62 PW32CP wchar_t *php_win32_cp_conv_to_w(DWORD in_cp, DWORD flags, const char* in, size_t in_len, size_t *out_len);
63 PW32CP wchar_t *php_win32_cp_conv_utf8_to_w(const char* in, size_t in_len, size_t *out_len);
64 #define php_win32_cp_utf8_to_w(in) php_win32_cp_conv_utf8_to_w(in, PHP_WIN32_CP_IGNORE_LEN, PHP_WIN32_CP_IGNORE_LEN_P)
65 PW32CP wchar_t *php_win32_cp_conv_cur_to_w(const char* in, size_t in_len, size_t *out_len);
66 #define php_win32_cp_cur_to_w(in) php_win32_cp_conv_cur_to_w(in, PHP_WIN32_CP_IGNORE_LEN, PHP_WIN32_CP_IGNORE_LEN_P)
67 PW32CP wchar_t *php_win32_cp_conv_ascii_to_w(const char* in, size_t in_len, size_t *out_len);
68 #define php_win32_cp_ascii_to_w(in) php_win32_cp_conv_ascii_to_w(in, PHP_WIN32_CP_IGNORE_LEN, PHP_WIN32_CP_IGNORE_LEN_P)
69 PW32CP char *php_win32_cp_conv_from_w(DWORD out_cp, DWORD flags, const wchar_t* in, size_t in_len, size_t *out_len);
70 PW32CP char *php_win32_cp_conv_w_to_utf8(const wchar_t* in, size_t in_len, size_t *out_len);
71 #define php_win32_cp_w_to_utf8(in) php_win32_cp_conv_w_to_utf8(in, PHP_WIN32_CP_IGNORE_LEN, PHP_WIN32_CP_IGNORE_LEN_P)
72 PW32CP char *php_win32_cp_conv_w_to_cur(const wchar_t* in, size_t in_len, size_t *out_len);
73 #define php_win32_cp_w_to_cur(in) php_win32_cp_conv_w_to_cur(in, PHP_WIN32_CP_IGNORE_LEN, PHP_WIN32_CP_IGNORE_LEN_P)
74 PW32CP wchar_t *php_win32_cp_env_any_to_w(const char* env);
75
76 /* This function tries to make the best guess to convert any
77 given string to a wide char, also preferring the fastest code
78 path to unicode. It returns NULL on fail. */
php_win32_cp_conv_any_to_w(const char * in,size_t in_len,size_t * out_len)79 __forceinline static wchar_t *php_win32_cp_conv_any_to_w(const char* in, size_t in_len, size_t *out_len)
80 {/*{{{*/
81 wchar_t *ret = NULL;
82
83 if (php_win32_cp_use_unicode()) {
84 /* First try the pure ascii conversion. This is the fastest way to do the
85 thing. Only applicable if the source string is UTF-8 in general.
86 While it could possibly be ok with European encodings, usage with
87 Asian encodings can cause unintended side effects. Lookup the term
88 "mojibake" if need more. */
89 ret = php_win32_cp_conv_ascii_to_w(in, in_len, out_len);
90
91 /* If that failed, try to convert to multibyte. */
92 if (!ret) {
93 ret = php_win32_cp_conv_utf8_to_w(in, in_len, out_len);
94
95 /* Still need this fallback with regard to possible broken data
96 in the existing scripts. Broken data might be hardcoded in
97 the user scripts, as UTF-8 settings was de facto ignored in
98 older PHP versions. The fallback can be removed later for
99 the sake of purity, keep now for BC reasons. */
100 if (!ret) {
101 const struct php_win32_cp *acp = php_win32_cp_get_by_id(GetACP());
102
103 if (acp) {
104 ret = php_win32_cp_conv_to_w(acp->id, acp->to_w_fl, in, in_len, out_len);
105 }
106 }
107 }
108 } else {
109 /* No unicode, convert from the current thread cp. */
110 ret = php_win32_cp_conv_cur_to_w(in, in_len, out_len);
111 }
112
113 return ret;
114 }/*}}}*/
115 #define php_win32_cp_any_to_w(in) php_win32_cp_conv_any_to_w(in, PHP_WIN32_CP_IGNORE_LEN, PHP_WIN32_CP_IGNORE_LEN_P)
116
117 /* This function converts from unicode function output back to PHP. If
118 the PHP's current charset is not compatible with unicode, so the currently
119 configured CP will be used. */
php_win32_cp_conv_w_to_any(const wchar_t * in,size_t in_len,size_t * out_len)120 __forceinline static char *php_win32_cp_conv_w_to_any(const wchar_t* in, size_t in_len, size_t *out_len)
121 {/*{{{*/
122 return php_win32_cp_conv_w_to_cur(in, in_len, out_len);
123 }/*}}}*/
124 #define php_win32_cp_w_to_any(in) php_win32_cp_conv_w_to_any(in, PHP_WIN32_CP_IGNORE_LEN, PHP_WIN32_CP_IGNORE_LEN_P)
125
126 #define PHP_WIN32_CP_W_TO_ANY_ARRAY(aw, aw_len, aa, aa_len) do { \
127 int i; \
128 aa_len = aw_len; \
129 aa = (char **) malloc(aw_len * sizeof(char *)); \
130 if (!aa) { \
131 break; \
132 } \
133 for (i = 0; i < aw_len; i++) { \
134 aa[i] = php_win32_cp_w_to_any(aw[i]); \
135 } \
136 } while (0);
137
138
139 #define PHP_WIN32_CP_FREE_ARRAY(a, a_len) do { \
140 int i; \
141 for (i = 0; i < a_len; i++) { \
142 free(a[i]); \
143 } \
144 free(a); \
145 } while (0);
146
147 #ifdef __cplusplus
148 }
149 #endif
150
151 #endif /* PHP_WIN32_CODEPAGE_H */
152