diff options
Diffstat (limited to 'win32')
-rw-r--r-- | win32/build/buildconf.js | 2 | ||||
-rw-r--r-- | win32/build/config.w32 | 3 | ||||
-rw-r--r-- | win32/build/config.w32.h.in | 10 | ||||
-rw-r--r-- | win32/build/confutils.js | 13 | ||||
-rw-r--r-- | win32/build/default.manifest | 9 | ||||
-rw-r--r-- | win32/codepage.c | 618 | ||||
-rw-r--r-- | win32/codepage.h | 162 | ||||
-rw-r--r-- | win32/cp_enc_map.c | 156 | ||||
-rw-r--r-- | win32/cp_enc_map_gen.c | 250 | ||||
-rw-r--r-- | win32/dllmain.c | 7 | ||||
-rw-r--r-- | win32/ftok.c | 52 | ||||
-rw-r--r-- | win32/ioutil.c | 611 | ||||
-rw-r--r-- | win32/ioutil.h | 501 | ||||
-rw-r--r-- | win32/ipc.h | 29 | ||||
-rw-r--r-- | win32/param.h | 3 | ||||
-rw-r--r-- | win32/readdir.c | 126 | ||||
-rw-r--r-- | win32/readdir.h | 24 | ||||
-rw-r--r-- | win32/winutil.c | 319 | ||||
-rw-r--r-- | win32/winutil.h | 29 |
19 files changed, 2853 insertions, 71 deletions
diff --git a/win32/build/buildconf.js b/win32/build/buildconf.js index a3a4f1e9aa..d7975d0139 100644 --- a/win32/build/buildconf.js +++ b/win32/build/buildconf.js @@ -244,6 +244,8 @@ for (i = 0; i < calls.length; i++) { }
C.WriteBlankLines(1);
+C.WriteLine("STDOUT.WriteLine(\"PHP Version: \" + PHP_VERSION_STRING);");
+C.WriteLine("STDOUT.WriteBlankLines(1);");
C.WriteLine("conf_process_args();");
C.WriteBlankLines(1);
diff --git a/win32/build/config.w32 b/win32/build/config.w32 index b7e5e49220..58b1420b89 100644 --- a/win32/build/config.w32 +++ b/win32/build/config.w32 @@ -160,7 +160,8 @@ ADD_SOURCES("main/streams", "streams.c cast.c memory.c filter.c plain_wrapper.c ADD_FLAG("CFLAGS_BD_MAIN_STREAMS", "/D ZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); ADD_SOURCES("win32", "dllmain.c glob.c readdir.c \ - registry.c select.c sendmail.c time.c winutil.c wsyslog.c globals.c getrusage.c"); + registry.c select.c sendmail.c time.c winutil.c wsyslog.c globals.c \ + getrusage.c ftok.c ioutil.c codepage.c"); ADD_FLAG("CFLAGS_BD_WIN32", "/D ZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); diff --git a/win32/build/config.w32.h.in b/win32/build/config.w32.h.in index fd02cc7878..2a8297a144 100644 --- a/win32/build/config.w32.h.in +++ b/win32/build/config.w32.h.in @@ -22,15 +22,6 @@ #define PHP_PREFIX "@PREFIX@" #define PHP_SYSCONFDIR "@PREFIX@" -/* Enable / Disable crypt() function (default: enabled) */ -#define HAVE_CRYPT 1 -#define PHP_STD_DES_CRYPT 1 -#define PHP_EXT_DES_CRYPT 1 -#define PHP_MD5_CRYPT 1 -#define PHP_BLOWFISH_CRYPT 1 -#define PHP_SHA512_CRYPT 1 -#define PHP_SHA256_CRYPT 1 - /* PHP Runtime Configuration */ #define PHP_URL_FOPEN 1 #define USE_CONFIG_FILE 1 @@ -183,3 +174,4 @@ #define HAVE_GETRUSAGE +#define HAVE_FTOK 1 diff --git a/win32/build/confutils.js b/win32/build/confutils.js index 8ab4b7b0e9..038692911c 100644 --- a/win32/build/confutils.js +++ b/win32/build/confutils.js @@ -100,10 +100,10 @@ if (typeof(CWD) == "undefined") { /* defaults; we pick up the precise versions from configure.in */ var PHP_VERSION = 7; -var PHP_MINOR_VERSION = 0; +var PHP_MINOR_VERSION = 1; var PHP_RELEASE_VERSION = 0; var PHP_EXTRA_VERSION = ""; -var PHP_VERSION_STRING = "7.0.0"; +var PHP_VERSION_STRING = "7.1.0"; /* Get version numbers and DEFINE as a string */ function get_version_numbers() @@ -2694,6 +2694,15 @@ function toolset_setup_common_cflags() if (VCVERS >= 1900) { ADD_FLAG('CFLAGS', "/guard:cf"); } + if (VCVERS >= 1800) { + if (PHP_PGI != "yes" && PHP_PGO != "yes") { + ADD_FLAG('CFLAGS', "/Zc:inline"); + } + /* We enable /opt:icf only with the debug pack, so /Gw only makes sense there, too. */ + if (PHP_DEBUG_PACK == "yes") { + ADD_FLAG('CFLAGS', "/Gw"); + } + } } } else if (CLANG_TOOLSET) { diff --git a/win32/build/default.manifest b/win32/build/default.manifest index 77b2a2165a..992f41c738 100644 --- a/win32/build/default.manifest +++ b/win32/build/default.manifest @@ -1,6 +1,13 @@ <?xml version='1.0' encoding='UTF-8' standalone='yes'?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" > - <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> + <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2"> + <security> + <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3"> + <requestedExecutionLevel level="asInvoker" uiAccess="false" /> + </requestedPrivileges> + </security> + </trustInfo> + <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> <application> <!-- Windows Vista --> <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/> diff --git a/win32/codepage.c b/win32/codepage.c new file mode 100644 index 0000000000..d9291305bc --- /dev/null +++ b/win32/codepage.c @@ -0,0 +1,618 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 7 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2016 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Anatol Belski <ab@php.net> | + +----------------------------------------------------------------------+ +*/ + +#include <assert.h> + +#include "php.h" +#include "SAPI.h" + +ZEND_TLS const struct php_win32_cp *cur_cp = NULL; +ZEND_TLS const struct php_win32_cp *orig_cp = NULL; + +#include "cp_enc_map.c" + +__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) +{/*{{{*/ + wchar_t *ret; + int ret_len, tmp_len; + + if (!in || in_len > (size_t)INT_MAX) { + SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER); + return NULL; + } + assert(in_len ? in[in_len] == L'\0' : 1); + + tmp_len = !in_len ? -1 : (int)in_len + 1; + + ret_len = MultiByteToWideChar(cp, flags, in, tmp_len, NULL, 0); + if (ret_len == 0) { + SET_ERRNO_FROM_WIN32_CODE(GetLastError()); + return NULL; + } + + ret = malloc(ret_len * sizeof(wchar_t)); + if (!ret) { + SET_ERRNO_FROM_WIN32_CODE(ERROR_OUTOFMEMORY); + return NULL; + } + + tmp_len = MultiByteToWideChar(cp, flags, in, tmp_len, ret, ret_len); + if (tmp_len == 0) { + free(ret); + SET_ERRNO_FROM_WIN32_CODE(GetLastError()); + return NULL; + } + + assert(ret ? tmp_len == ret_len : 1); + assert(ret ? wcslen(ret) == ret_len - 1 : 1); + + ret[ret_len-1] = L'\0'; + + if (PHP_WIN32_CP_IGNORE_LEN_P != out_len) { + *out_len = ret_len - 1; + } + + return ret; +}/*}}}*/ + +PW32CP wchar_t *php_win32_cp_conv_utf8_to_w(const char* in, size_t in_len, size_t *out_len) +{/*{{{*/ + return php_win32_cp_to_w_int(in, in_len, out_len, CP_UTF8, MB_ERR_INVALID_CHARS); +}/*}}}*/ + +PW32CP wchar_t *php_win32_cp_conv_cur_to_w(const char* in, size_t in_len, size_t *out_len) +{/*{{{*/ + wchar_t *ret; + + ret = php_win32_cp_to_w_int(in, in_len, out_len, cur_cp->id, cur_cp->from_w_fl); + + return ret; +}/*}}}*/ + +PW32CP wchar_t *php_win32_cp_conv_to_w(DWORD cp, DWORD flags, const char* in, size_t in_len, size_t *out_len) +{/*{{{*/ + return php_win32_cp_to_w_int(in, in_len, out_len, cp, flags); +}/*}}}*/ + +PW32CP wchar_t *php_win32_cp_conv_ascii_to_w(const char* in, size_t in_len, size_t *out_len) +{/*{{{*/ + wchar_t *ret = NULL; + const char *idx = in, *end; + + assert(in && in_len ? in[in_len] == '\0' : 1); + + if (!in) { + SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER); + return NULL; + } else if (0 == in_len) { + /* Not binary safe. */ + in_len = strlen(in); + if (in_len > (size_t)INT_MAX) { + SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER); + return NULL; + } + } + + end = in + in_len; + + while (idx != end) { + if (!__isascii(*idx) && '\0' != *idx) { + break; + } + idx++; + } + + if (idx == end) { + size_t i = 0; + int k = 0; + wchar_t *ret_idx; + + ret = malloc((in_len+1)*sizeof(wchar_t)); + if (!ret) { + SET_ERRNO_FROM_WIN32_CODE(ERROR_OUTOFMEMORY); + return NULL; + } + + ret_idx = ret; + do { + k = _snwprintf(ret_idx, in_len - i, L"%.*hs", (int)(in_len - i), in); + + if (-1 == k) { + free(ret); + SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER); + return NULL; + } + + i += k + 1; + + if (i < in_len) { + /* Advance as this seems to be a string with \0 in it. */ + in += k + 1; + ret_idx += k + 1; + } + + + } while (i < in_len); + ret[in_len] = L'\0'; + + assert(ret ? wcslen(ret) == in_len : 1); + + if (PHP_WIN32_CP_IGNORE_LEN_P != out_len) { + *out_len = in_len; + } + } else { + if (PHP_WIN32_CP_IGNORE_LEN_P != out_len) { + *out_len = 0; + } + } + + return ret; +}/*}}}*/ + +__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) +{/*{{{*/ + int r; + int target_len, tmp_len; + char* target; + + if (!in || in_len > INT_MAX) { + SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER); + return NULL; + } + assert(in_len ? in[in_len] == '\0' : 1); + + tmp_len = !in_len ? -1 : (int)in_len + 1; + + target_len = WideCharToMultiByte(cp, flags, in, tmp_len, NULL, 0, NULL, NULL); + if (target_len == 0) { + SET_ERRNO_FROM_WIN32_CODE(GetLastError()); + return NULL; + } + + target = malloc(target_len); + if (target == NULL) { + SET_ERRNO_FROM_WIN32_CODE(ERROR_OUTOFMEMORY); + return NULL; + } + + r = WideCharToMultiByte(cp, flags, in, tmp_len, target, target_len, NULL, NULL); + if (r == 0) { + free(target); + SET_ERRNO_FROM_WIN32_CODE(GetLastError()); + return NULL; + } + + assert(target ? r == target_len : 1); + assert(target ? strlen(target) == target_len - 1 : 1); + + target[target_len-1] = '\0'; + + if (PHP_WIN32_CP_IGNORE_LEN_P != out_len) { + *out_len = target_len - 1; + } + + return target; +}/*}}}*/ + +PW32CP char *php_win32_cp_conv_w_to_utf8(const wchar_t* in, size_t in_len, size_t *out_len) +{/*{{{*/ + return php_win32_cp_from_w_int(in, in_len, out_len, CP_UTF8, WC_ERR_INVALID_CHARS); +}/*}}}*/ + +PW32CP char *php_win32_cp_conv_w_to_cur(const wchar_t* in, size_t in_len, size_t *out_len) +{/*{{{*/ + char *ret; + + ret = php_win32_cp_from_w_int(in, in_len, out_len, cur_cp->id, cur_cp->from_w_fl); + + return ret; +}/*}}}*/ + +PW32CP char *php_win32_cp_conv_from_w(DWORD cp, DWORD flags, const wchar_t* in, size_t in_len, size_t *out_len) +{/*{{{*/ + return php_win32_cp_from_w_int(in, in_len, out_len, cp, flags); +}/*}}}*/ + +/* This is only usable after the startup phase*/ +__forceinline static char *php_win32_cp_get_enc(void) +{/*{{{*/ + char *enc = NULL; + const zend_encoding *zenc; + + if (PG(internal_encoding) && PG(internal_encoding)[0]) { + enc = PG(internal_encoding); + } else if (SG(default_charset) && SG(default_charset)[0] ) { + enc = SG(default_charset); + } else { + zenc = zend_multibyte_get_internal_encoding(); + if (zenc) { + enc = (char *)zend_multibyte_get_encoding_name(zenc); + } + } + + return enc; +}/*}}}*/ + +PW32CP const struct php_win32_cp *php_win32_cp_get_current(void) +{/*{{{*/ + return cur_cp; +}/*}}}*/ + +PW32CP const struct php_win32_cp *php_win32_cp_get_orig(void) +{/*{{{*/ + return orig_cp; +}/*}}}*/ + +PW32CP const struct php_win32_cp *php_win32_cp_get_by_id(DWORD id) +{/*{{{*/ + size_t i; + + for (i = 0; i < sizeof(php_win32_cp_map)/sizeof(struct php_win32_cp); i++) { + if (php_win32_cp_map[i].id == id) { + return &php_win32_cp_map[i]; + } + } + + SET_ERRNO_FROM_WIN32_CODE(ERROR_NOT_FOUND); + + return NULL; +}/*}}}*/ + +PW32CP const struct php_win32_cp *php_win32_cp_get_by_enc(const char *enc) +{/*{{{*/ + size_t enc_len = 0, i; + + if (!enc || !enc[0]) { + return php_win32_cp_get_by_id(65001U); + } + + enc_len = strlen(enc); + + for (i = 0; i < sizeof(php_win32_cp_map)/sizeof(struct php_win32_cp); i++) { + const struct php_win32_cp *cp = &php_win32_cp_map[i]; + + if (!cp->name || !cp->name[0]) { + continue; + } + + if (0 == zend_binary_strcasecmp(enc, enc_len, cp->name, strlen(cp->name))) { + cur_cp = cp; + return cp; + } + + if (cp->enc) { + char *start = cp->enc, *idx; + + idx = strpbrk(start, "|"); + + while (NULL != idx) { + if (0 == zend_binary_strcasecmp(enc, enc_len, start, idx - start)) { + cur_cp = cp; + return cp; + } + start = idx + 1; + idx = strpbrk(start, "|"); + } + /* Last in the list, or single charset specified. */ + if (0 == zend_binary_strcasecmp(enc, enc_len, start, strlen(start))) { + cur_cp = cp; + return cp; + } + } + } + + return php_win32_cp_get_by_id(GetACP()); +}/*}}}*/ + +PW32CP const struct php_win32_cp *php_win32_cp_set_by_id(DWORD id) +{/*{{{*/ + const struct php_win32_cp *tmp; + if (!IsValidCodePage(id)) { + SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER); + return NULL; + } + + tmp = php_win32_cp_get_by_id(id); + if (tmp) { + cur_cp = tmp; + } + + return cur_cp; +}/*}}}*/ + +PW32CP BOOL php_win32_cp_use_unicode(void) +{/*{{{*/ + return 65001 == cur_cp->id; +}/*}}}*/ + +PW32CP wchar_t *php_win32_cp_env_any_to_w(const char* env) +{/*{{{*/ + wchar_t *envw = NULL, ew[32760]; + char *cur = (char *)env, *prev; + size_t bin_len = 0; + + if (!env) { + SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER); + return NULL; + } + + do { + wchar_t *tmp; + size_t tmp_len; + + tmp = php_win32_cp_any_to_w(cur); + if (tmp) { + tmp_len = wcslen(tmp) + 1; + memmove(ew + bin_len, tmp, tmp_len * sizeof(wchar_t)); + free(tmp); + + bin_len += tmp_len; + } + + prev = cur; + + } while (NULL != (cur = strchr(prev, '\0')) && cur++ && *cur && bin_len + (cur - prev) < 32760); + + envw = (wchar_t *) malloc((bin_len + 3) * sizeof(wchar_t)); + if (!envw) { + SET_ERRNO_FROM_WIN32_CODE(ERROR_OUTOFMEMORY); + return NULL; + } + memmove(envw, ew, bin_len * sizeof(wchar_t)); + envw[bin_len] = L'\0'; + envw[bin_len + 1] = L'\0'; + envw[bin_len + 2] = L'\0'; + + return envw; +}/*}}}*/ + +PW32CP const struct php_win32_cp *php_win32_cp_do_setup(const char *enc) +{/*{{{*/ + if (!enc) { + enc = php_win32_cp_get_enc(); + } + + if (!strcmp(sapi_module.name, "cli")) { + orig_cp = php_win32_cp_get_by_id(GetConsoleCP()); + } else { + orig_cp = php_win32_cp_get_by_id(GetACP()); + } + cur_cp = php_win32_cp_get_by_enc(enc); + + return cur_cp; +}/*}}}*/ + +PW32CP const struct php_win32_cp *php_win32_cp_do_update(const char *enc) +{/*{{{*/ + if (!enc) { + enc = php_win32_cp_get_enc(); + } + cur_cp = php_win32_cp_get_by_enc(enc); + + if (!strcmp(sapi_module.name, "cli")) { + php_win32_cp_cli_do_setup(cur_cp->id); + } + + return cur_cp; +}/*}}}*/ + +PW32CP const struct php_win32_cp *php_win32_cp_shutdown(void) +{/*{{{*/ + return orig_cp; +}/*}}}*/ + +/* php_win32_cp_setup() needs to have run before! */ +PW32CP const struct php_win32_cp *php_win32_cp_cli_do_setup(DWORD id) +{/*{{{*/ + const struct php_win32_cp *cp; + + if (!orig_cp) { + php_win32_cp_setup(); + } + + if (id) { + cp = php_win32_cp_set_by_id(id); + } else { + cp = cur_cp; + } + + if (!cp) { + return NULL; + } + + if (SetConsoleOutputCP(cp->id) && SetConsoleCP(cp->id)) { + return cp; + } + + return cp; +}/*}}}*/ + +PW32CP const struct php_win32_cp *php_win32_cp_cli_do_restore(DWORD id) +{/*{{{*/ + if (!id && orig_cp) { + id = orig_cp->id; + } + + if (SetConsoleOutputCP(id) && SetConsoleCP(id)) { + if (orig_cp) { + return orig_cp; + } else { + return php_win32_cp_set_by_id(id); + } + } + + return NULL; +}/*}}}*/ + +/* Userspace functions, see basic_functions.* for arginfo and decls. */ + +/* {{{ proto bool sapi_windows_cp_set(int cp) + * Set process codepage. */ +PHP_FUNCTION(sapi_windows_cp_set) +{ + zend_long id; + const struct php_win32_cp *cp; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &id) == FAILURE) { + return; + } + + if (ZEND_LONG_UINT_OVFL(id)) { + php_error_docref(NULL, E_WARNING, "Argument %d is out of range", id); + RETURN_FALSE; + } + + if (!strcmp(sapi_module.name, "cli")) { + cp = php_win32_cp_cli_do_setup((DWORD)id); + } else { + cp = php_win32_cp_set_by_id((DWORD)id); + } + if (!cp) { + php_error_docref(NULL, E_WARNING, "Failed to switch to codepage %d", id); + RETURN_FALSE; + } + + RETURN_BOOL(cp->id == id); +} +/* }}} */ + +/* {{{ proto int sapi_windows_cp_get([string kind]) + * Get process codepage. */ +PHP_FUNCTION(sapi_windows_cp_get) +{ + char *kind; + size_t kind_len = 0; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s", &kind, &kind_len) == FAILURE) { + return; + } + + if (kind_len == sizeof("ansi")-1 && !strncasecmp(kind, "ansi", kind_len)) { + RETURN_LONG(GetACP()); + } else if (kind_len == sizeof("oem")-1 && !strncasecmp(kind, "oem", kind_len)) { + RETURN_LONG(GetOEMCP()); + } else { + const struct php_win32_cp *cp = php_win32_cp_get_current(); + RETURN_LONG(cp->id); + } +} +/* }}} */ + + +/* {{{ proto bool sapi_windows_cp_is_utf8(void) + * Indicates whether the codepage is UTF-8 compatible. */ +PHP_FUNCTION(sapi_windows_cp_is_utf8) +{ + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + RETURN_BOOL(php_win32_cp_use_unicode()); +} +/* }}} */ + +/* {{{ proto string sapi_windows_cp_conv(int|string in_codepage, int|string out_codepage, string subject) + * Convert string from one codepage to another. */ +PHP_FUNCTION(sapi_windows_cp_conv) +{ + char *subj, *ret; + size_t subj_len, ret_len, tmpw_len; + wchar_t *tmpw; + const struct php_win32_cp *in_cp, *out_cp; + zval *z_in_cp, *z_out_cp; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "zzs", &z_in_cp, &z_out_cp, &subj, &subj_len) == FAILURE) { + return; + } + + if (ZEND_SIZE_T_INT_OVFL(subj_len)) { + php_error_docref(NULL, E_WARNING, "String is too long"); + RETURN_NULL(); + } + + if (IS_LONG == Z_TYPE_P(z_in_cp)) { + if (ZEND_LONG_UINT_OVFL(Z_LVAL_P(z_in_cp))) { + php_error_docref(NULL, E_WARNING, "Argument %d is out of range", Z_LVAL_P(z_in_cp)); + RETURN_NULL(); + } + + in_cp = php_win32_cp_get_by_id((DWORD)Z_LVAL_P(z_in_cp)); + if (!in_cp) { + php_error_docref(NULL, E_WARNING, "Invalid codepage %d", Z_LVAL_P(z_in_cp)); + RETURN_NULL(); + } + } else { + convert_to_string(z_in_cp); + + in_cp = php_win32_cp_get_by_enc(Z_STRVAL_P(z_in_cp)); + if (!in_cp) { + php_error_docref(NULL, E_WARNING, "Invalid charset %s", Z_STRVAL_P(z_in_cp)); + RETURN_NULL(); + } + } + + if (IS_LONG == Z_TYPE_P(z_out_cp)) { + if (ZEND_LONG_UINT_OVFL(Z_LVAL_P(z_out_cp))) { + php_error_docref(NULL, E_WARNING, "Argument %d is out of range", Z_LVAL_P(z_out_cp)); + RETURN_NULL(); + } + + out_cp = php_win32_cp_get_by_id((DWORD)Z_LVAL_P(z_out_cp)); + if (!out_cp) { + php_error_docref(NULL, E_WARNING, "Invalid codepage %d", Z_LVAL_P(z_out_cp)); + RETURN_NULL(); + } + } else { + convert_to_string(z_out_cp); + + out_cp = php_win32_cp_get_by_enc(Z_STRVAL_P(z_out_cp)); + if (!out_cp) { + php_error_docref(NULL, E_WARNING, "Invalid charset %s", Z_STRVAL_P(z_out_cp)); + RETURN_NULL(); + } + } + + tmpw = php_win32_cp_conv_to_w(in_cp->id, in_cp->to_w_fl, subj, subj_len, &tmpw_len); + if (!tmpw) { + php_error_docref(NULL, E_WARNING, "Wide char conversion failed"); + RETURN_NULL(); + } + + ret = php_win32_cp_conv_from_w(out_cp->id, out_cp->from_w_fl, tmpw, tmpw_len, &ret_len); + if (!ret) { + free(tmpw); + php_error_docref(NULL, E_WARNING, "Wide char conversion failed"); + RETURN_NULL(); + } + + RETVAL_STRINGL(ret, ret_len); + + free(tmpw); + free(ret); +} +/* }}} */ + +/* }}} */ +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: sw=4 ts=4 fdm=marker + * vim<600: sw=4 ts=4 + */ diff --git a/win32/codepage.h b/win32/codepage.h new file mode 100644 index 0000000000..96afd443ec --- /dev/null +++ b/win32/codepage.h @@ -0,0 +1,162 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 7 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2016 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Anatol Belski <ab@php.net> | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHP_WIN32_CODEPAGE_H +#define PHP_WIN32_CODEPAGE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef PHP_EXPORTS +# define PW32CP __declspec(dllexport) +#else +# define PW32CP __declspec(dllimport) +#endif + +#define PHP_WIN32_CP_IGNORE_LEN (0) +#define PHP_WIN32_CP_IGNORE_LEN_P ((size_t *)-1) + +struct php_win32_cp { + DWORD id; + DWORD to_w_fl; + DWORD from_w_fl; + DWORD char_size; + char *name; + char *enc; + char *desc; +}; + +PW32CP BOOL php_win32_cp_use_unicode(void); +PW32CP const struct php_win32_cp *php_win32_cp_do_setup(const char *); +#define php_win32_cp_setup() php_win32_cp_do_setup(NULL) +PW32CP const struct php_win32_cp *php_win32_cp_do_update(const char *); +#define php_win32_cp_update() php_win32_cp_do_update(NULL) +PW32CP const struct php_win32_cp *php_win32_cp_shutdown(void); +PW32CP const struct php_win32_cp *php_win32_cp_get_current(void); +PW32CP const struct php_win32_cp *php_win32_cp_get_orig(void); +PW32CP const struct php_win32_cp *php_win32_cp_get_by_id(DWORD id); +PW32CP const struct php_win32_cp *php_win32_cp_set_by_id(DWORD id); +PW32CP const struct php_win32_cp *php_win32_cp_get_by_enc(const char *enc); +PW32CP const struct php_win32_cp *php_win32_cp_cli_do_setup(DWORD); +#define php_win32_cp_cli_setup() php_win32_cp_cli_do_setup(0) +#define php_win32_cp_cli_update() php_win32_cp_cli_do_setup(0) +PW32CP const struct php_win32_cp *php_win32_cp_cli_do_restore(DWORD); +#define php_win32_cp_cli_restore() php_win32_cp_cli_do_restore(0) + +/* This API is binary safe and expects a \0 terminated input. + The returned out is \0 terminated, but the length doesn't count \0. */ +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); +PW32CP wchar_t *php_win32_cp_conv_utf8_to_w(const char* in, size_t in_len, size_t *out_len); +#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) +PW32CP wchar_t *php_win32_cp_conv_cur_to_w(const char* in, size_t in_len, size_t *out_len); +#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) +PW32CP wchar_t *php_win32_cp_conv_ascii_to_w(const char* in, size_t in_len, size_t *out_len); +#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) +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); +PW32CP char *php_win32_cp_conv_w_to_utf8(const wchar_t* in, size_t in_len, size_t *out_len); +#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) +PW32CP char *php_win32_cp_conv_w_to_cur(const wchar_t* in, size_t in_len, size_t *out_len); +#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) +PW32CP wchar_t *php_win32_cp_env_any_to_w(const char* env); + +/* This function tries to make the best guess to convert any + given string to a wide char, also prefering the fastest code + path to unicode. It returns NULL on fail. */ +__forceinline static wchar_t *php_win32_cp_conv_any_to_w(const char* in, size_t in_len, size_t *out_len) +{/*{{{*/ + wchar_t *ret = NULL; + + if (php_win32_cp_use_unicode()) { + /* First try the pure ascii conversion. This is the fastest way to do the + thing. Only applicable if the source string is UTF-8 in general. + While it could possibly be ok with European encodings, usage with + Asian encodings can cause unintended side effects. Lookup the term + "mojibake" if need more. */ + ret = php_win32_cp_conv_ascii_to_w(in, in_len, out_len); + + /* If that failed, try to convert to multibyte. */ + if (!ret) { + ret = php_win32_cp_conv_utf8_to_w(in, in_len, out_len); + + /* Still need this fallback with regard to possible broken data + in the existing scripts. Broken data might be hardcoded in + the user scripts, as UTF-8 settings was de facto ignored in + older PHP versions. The fallback can be removed later for + the sake of purity, keep now for BC reasons. */ + if (!ret) { + const struct php_win32_cp *acp = php_win32_cp_get_by_id(GetACP()); + + if (acp) { + ret = php_win32_cp_conv_to_w(acp->id, acp->to_w_fl, in, in_len, out_len); + } + } + } + } else { + /* No unicode, convert from the current thread cp. */ + ret = php_win32_cp_conv_cur_to_w(in, in_len, out_len); + } + + return ret; +}/*}}}*/ +#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) + +/* This function converts from unicode function output back to PHP. If + the PHP's current charset is not compatible with unicode, so the currently + configured CP will be used. */ +__forceinline static char *php_win32_cp_conv_w_to_any(const wchar_t* in, size_t in_len, size_t *out_len) +{/*{{{*/ + return php_win32_cp_conv_w_to_cur(in, in_len, out_len); +}/*}}}*/ +#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) + +#define PHP_WIN32_CP_W_TO_ANY_ARRAY(aw, aw_len, aa, aa_len) do { \ + int i; \ + aa_len = aw_len; \ + aa = (char **) malloc(aw_len * sizeof(char *)); \ + if (!aa) { \ + break; \ + } \ + for (i = 0; i < aw_len; i++) { \ + aa[i] = php_win32_cp_w_to_any(aw[i]); \ + } \ +} while (0); + + +#define PHP_WIN32_CP_FREE_ARRAY(a, a_len) do { \ + int i; \ + for (i = 0; i < a_len; i++) { \ + free(a[i]); \ + } \ + free(a); \ +} while (0); + +#ifdef __cplusplus +} +#endif + +#endif /* PHP_WIN32_CODEPAGE_H */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: sw=4 ts=4 fdm=marker + * vim<600: sw=4 ts=4 + */ diff --git a/win32/cp_enc_map.c b/win32/cp_enc_map.c new file mode 100644 index 0000000000..08a71fdc5e --- /dev/null +++ b/win32/cp_enc_map.c @@ -0,0 +1,156 @@ +/* Autogenerated file. Update cp_enc_map_gen.c and regen like + cp_enc_map_gen.exe > cp_enc_map.c +*/ + +static const struct php_win32_cp php_win32_cp_map[] = { { 37, 0, 0, 1, "IBM037", NULL, "37 (IBM EBCDIC - U.S./Canada)" }, + { 437, 0, 0, 1, "IBM437", NULL, "437 (OEM - United States)" }, + { 500, 0, 0, 1, "IBM500", NULL, "500 (IBM EBCDIC - International)" }, + { 708, 0, 0, 1, "ASMO-708", NULL, "708 (Arabic - ASMO)" }, + /* 709 is invalid */ + /* 710 is invalid */ + { 720, 0, 0, 1, "DOS-720", NULL, "720 (Arabic - Transparent ASMO)" }, + { 737, 0, 0, 1, "ibm737", NULL, "737 (OEM - Greek 437G)" }, + { 775, 0, 0, 1, "ibm775", NULL, "775 (OEM - Baltic)" }, + { 850, 0, 0, 1, "ibm850", "850|CP850|IBM850|CSPC850MULTILINGUAL", "850 (OEM - Multilingual Latin I)" }, + { 852, 0, 0, 1, "ibm852", NULL, "852 (OEM - Latin II)" }, + { 855, 0, 0, 1, "IBM855", NULL, "855 (OEM - Cyrillic)" }, + { 857, 0, 0, 1, "ibm857", NULL, "857 (OEM - Turkish)" }, + { 858, 0, 0, 1, "IBM00858", NULL, "858 (OEM - Multilingual Latin I + Euro)" }, + { 860, 0, 0, 1, "IBM860", NULL, "860 (OEM - Portuguese)" }, + { 861, 0, 0, 1, "ibm861", NULL, "861 (OEM - Icelandic)" }, + { 862, 0, 0, 1, "DOS-862", "862|CP862|IBM862|CSPC862LATINHEBREW", "862 (OEM - Hebrew)" }, + { 863, 0, 0, 1, "IBM863", NULL, "863 (OEM - Canadian French)" }, + { 864, 0, 0, 1, "IBM864", NULL, "864 (OEM - Arabic)" }, + { 865, 0, 0, 1, "IBM865", NULL, "865 (OEM - Nordic)" }, + { 866, 0, 0, 1, "cp866", "866|CP866|IBM866|CSIBM866", "866 (OEM - Russian)" }, + { 869, 0, 0, 1, "ibm869", NULL, "869 (OEM - Modern Greek)" }, + { 870, 0, 0, 1, "IBM870", NULL, "870 (IBM EBCDIC - Multilingual/ROECE (Latin-2))" }, + { 874, 0, 0, 1, "windows-874", "CP874", "874 (ANSI/OEM - Thai)" }, + { 875, 0, 0, 1, "cp875", NULL, "875 (IBM EBCDIC - Modern Greek)" }, + { 932, 0, 0, 2, "shift_jis", "CP932|SHIFT_JIS|MS_KANJI|CSSHIFTJIS", "932 (ANSI/OEM - Japanese Shift-JIS)" }, + { 936, 0, 0, 2, "gb2312", "GB2312|GBK|CP936|MS936|WINDOWS-936", "936 (ANSI/OEM - Simplified Chinese GBK)" }, + { 949, 0, 0, 2, "ks_c_5601-1987", "CP949|UHC", "949 (ANSI/OEM - Korean)" }, + { 950, 0, 0, 2, "big5", "CP950|BIG-5", "950 (ANSI/OEM - Traditional Chinese Big5)" }, + { 1026, 0, 0, 1, "IBM1026", NULL, "1026 (IBM EBCDIC - Turkish (Latin-5))" }, + { 1047, 0, 0, 1, "IBM01047", NULL, "1047 (IBM EBCDIC - Latin-1/Open System)" }, + { 1140, 0, 0, 1, "IBM01140", NULL, "1140 (IBM EBCDIC - U.S./Canada (37 + Euro))" }, + { 1141, 0, 0, 1, "IBM01141", NULL, "1141 (IBM EBCDIC - Germany (20273 + Euro))" }, + { 1142, 0, 0, 1, "IBM01142", NULL, "1142 (IBM EBCDIC - Denmark/Norway (20277 + Euro))" }, + { 1143, 0, 0, 1, "IBM01143", NULL, "1143 (IBM EBCDIC - Finland/Sweden (20278 + Euro))" }, + { 1144, 0, 0, 1, "IBM01144", NULL, "1144 (IBM EBCDIC - Italy (20280 + Euro))" }, + { 1145, 0, 0, 1, "IBM01145", NULL, "1145 (IBM EBCDIC - Latin America/Spain (20284 + Euro))" }, + { 1146, 0, 0, 1, "IBM01146", NULL, "1146 (IBM EBCDIC - United Kingdom (20285 + Euro))" }, + { 1148, 0, 0, 1, "IBM01148", NULL, "1148 (IBM EBCDIC - International (500 + Euro))" }, + { 1149, 0, 0, 1, "IBM01149", NULL, "1149 (IBM EBCDIC - Icelandic (20871 + Euro))" }, + /* 1200 is invalid */ + /* 1201 is invalid */ + { 1250, 0, 0, 1, "windows-1250", "CP1250|MS-EE|WINDOWS-1250", "1250 (ANSI - Central Europe)" }, + { 1251, 0, 0, 1, "windows-1251", "CP1251|MS-CYRL|WINDOWS-1251", "1251 (ANSI - Cyrillic)" }, + { 1252, 0, 0, 1, "windows-1252", "CP1252|MS-ANSI|WINDOWS-1252", "1252 (ANSI - Latin I)" }, + { 1253, 0, 0, 1, "windows-1253", "CP1253|MS-GREEK|WINDOWS-1253", "1253 (ANSI - Greek)" }, + { 1254, 0, 0, 1, "windows-1254", "CP1254|MS-TURK|WINDOWS-1254", "1254 (ANSI - Turkish)" }, + { 1255, 0, 0, 1, "windows-1255", "CP1255|MS-HEBR|WINDOWS-1255", "1255 (ANSI - Hebrew)" }, + { 1256, 0, 0, 1, "windows-1256", "CP1256|MS-ARAB|WINDOWS-1256", "1256 (ANSI - Arabic)" }, + { 1257, 0, 0, 1, "windows-1257", "CP1257|WINBALTRIM|WINDOWS-1257", "1257 (ANSI - Baltic)" }, + { 1258, 0, 0, 1, "windows-1258", "CP1258|WINDOWS-1258", "1258 (ANSI/OEM - Viet Nam)" }, + { 1361, 0, 0, 2, "Johab", "CP1361|JOHAB", "1361 (Korean - Johab)" }, + { 10000, 0, 0, 1, "macintosh", "MAC|MACINTOSH|MACROMAN|CSMACINTOSH", "10000 (MAC - Roman)" }, + { 10001, 0, 0, 2, "x-mac-japanese", NULL, "10001 (MAC - Japanese)" }, + { 10002, 0, 0, 2, "x-mac-chinesetrad", NULL, "10002 (MAC - Traditional Chinese Big5)" }, + { 10003, 0, 0, 2, "x-mac-korean", NULL, "10003 (MAC - Korean)" }, + { 10004, 0, 0, 1, "x-mac-arabic", "MACARABIC", "10004 (MAC - Arabic)" }, + { 10005, 0, 0, 1, "x-mac-hebrew", "MACHEBREW", "10005 (MAC - Hebrew)" }, + { 10006, 0, 0, 1, "x-mac-greek", "MACGREEK", "10006 (MAC - Greek I)" }, + { 10007, 0, 0, 1, "x-mac-cyrillic", "MACCYRILLIC", "10007 (MAC - Cyrillic)" }, + { 10008, 0, 0, 2, "x-mac-chinesesimp", NULL, "10008 (MAC - Simplified Chinese GB 2312)" }, + { 10010, 0, 0, 1, "x-mac-romanian", "MACROMANIA", "10010 (MAC - Romania)" }, + { 10017, 0, 0, 1, "x-mac-ukrainian", "MACUKRAINE", "10017 (MAC - Ukraine)" }, + { 10021, 0, 0, 1, "x-mac-thai", "MACTHAI", "10021 (MAC - Thai)" }, + { 10029, 0, 0, 1, "x-mac-ce", "MACCENTRALEUROPE", "10029 (MAC - Latin II)" }, + { 10079, 0, 0, 1, "x-mac-icelandic", "MACICELAND", "10079 (MAC - Icelandic)" }, + { 10081, 0, 0, 1, "x-mac-turkish", "MACTURKISH", "10081 (MAC - Turkish)" }, + { 10082, 0, 0, 1, "x-mac-croatian", "MACCROATIAN", "10082 (MAC - Croatia)" }, + /* 12000 is invalid */ + /* 12001 is invalid */ + { 20000, 0, 0, 2, "x-Chinese_CNS", NULL, "20000 (CNS - Taiwan)" }, + { 20001, 0, 0, 2, "x-cp20001", NULL, "20001 (TCA - Taiwan)" }, + { 20002, 0, 0, 2, "x_Chinese-Eten", NULL, "20002 (Eten - Taiwan)" }, + { 20003, 0, 0, 2, "x-cp20003", NULL, "20003 (IBM5550 - Taiwan)" }, + { 20004, 0, 0, 2, "x-cp20004", NULL, "20004 (TeleText - Taiwan)" }, + { 20005, 0, 0, 2, "x-cp20005", NULL, "20005 (Wang - Taiwan)" }, + { 20105, 0, 0, 1, "x-IA5", NULL, "20105 (IA5 IRV International Alphabet No.5)" }, + { 20106, 0, 0, 1, "x-IA5-German", NULL, "20106 (IA5 German)" }, + { 20107, 0, 0, 1, "x-IA5-Swedish", NULL, "20107 (IA5 Swedish)" }, + { 20108, 0, 0, 1, "x-IA5-Norwegian", NULL, "20108 (IA5 Norwegian)" }, + { 20127, 0, 0, 1, "us-ascii", NULL, "20127 (US-ASCII)" }, + { 20261, 0, 0, 2, "x-cp20261", NULL, "20261 (T.61)" }, + { 20269, 0, 0, 1, "x-cp20269", NULL, "20269 (ISO 6937 Non-Spacing Accent)" }, + { 20273, 0, 0, 1, "IBM273", NULL, "20273 (IBM EBCDIC - Germany)" }, + { 20277, 0, 0, 1, "IBM277", NULL, "20277 (IBM EBCDIC - Denmark/Norway)" }, + { 20278, 0, 0, 1, "IBM278", NULL, "20278 (IBM EBCDIC - Finland/Sweden)" }, + { 20280, 0, 0, 1, "IBM280", NULL, "20280 (IBM EBCDIC - Italy)" }, + { 20284, 0, 0, 1, "IBM284", NULL, "20284 (IBM EBCDIC - Latin America/Spain)" }, + { 20285, 0, 0, 1, "IBM285", NULL, "20285 (IBM EBCDIC - United Kingdom)" }, + { 20290, 0, 0, 1, "IBM290", NULL, "20290 (IBM EBCDIC - Japanese Katakana Extended)" }, + { 20297, 0, 0, 1, "IBM297", NULL, "20297 (IBM EBCDIC - France)" }, + { 20420, 0, 0, 1, "IBM420", NULL, "20420 (IBM EBCDIC - Arabic)" }, + { 20423, 0, 0, 1, "IBM423", NULL, "20423 (IBM EBCDIC - Greek)" }, + { 20424, 0, 0, 1, "IBM424", NULL, "20424 (IBM EBCDIC - Hebrew)" }, + { 20833, 0, 0, 1, "x-EBCDIC-KoreanExtended", NULL, "20833 (IBM EBCDIC - Korean Extended)" }, + { 20838, 0, 0, 1, "IBM-Thai", NULL, "20838 (IBM EBCDIC - Thai)" }, + { 20866, 0, 0, 1, "koi8-r", "KOI8-R|CSKOI8R", "20866 (Russian - KOI8)" }, + { 20871, 0, 0, 1, "IBM871", NULL, "20871 (IBM EBCDIC - Icelandic)" }, + { 20880, 0, 0, 1, "IBM880", NULL, "20880 (IBM EBCDIC - Cyrillic (Russian))" }, + { 20905, 0, 0, 1, "IBM905", NULL, "20905 (IBM EBCDIC - Turkish)" }, + { 20924, 0, 0, 1, "IBM00924", NULL, "20924 (IBM EBCDIC - Latin-1/Open System (1047 + Euro))" }, + { 20932, 0, 0, 2, "EUC-JP", "EUC-JP|EUCJP|EXTENDED_UNIX_CODE_PACKED_FORMAT_FOR_JAPANESE|CSEUCPKDFMTJAPANESE", "20932 (JIS X 0208-1990 & 0212-1990)" }, + { 20936, 0, 0, 2, "x-cp20936", NULL, "20936 (Simplified Chinese GB2312)" }, + { 21025, 0, 0, 1, "cp1025", NULL, "21025 (IBM EBCDIC - Cyrillic (Serbian, Bulgarian))" }, + { 21027, 0, 0, 1, "", NULL, "21027 (Ext Alpha Lowercase)" }, + { 21866, 0, 0, 1, "koi8-u", "KOI8-U", "21866 (Ukrainian - KOI8-U)" }, + { 28591, 0, 0, 1, "iso-8859-1", "CP819|IBM819|ISO-8859-1|ISO-IR-100|ISO8859-1|ISO_8859-1|ISO_8859-1:1987|L1|LATIN1|CSISOLATIN1", "28591 (ISO 8859-1 Latin I)" }, + { 28592, 0, 0, 1, "iso-8859-2", "ISO-8859-2|ISO-IR-101|ISO8859-2|ISO_8859-2|ISO_8859-2:1987|L2|LATIN2|CSISOLATIN2", "28592 (ISO 8859-2 Central Europe)" }, + { 28593, 0, 0, 1, "iso-8859-3", "ISO-8859-3|ISO-IR-109|ISO8859-3|ISO_8859-3|ISO_8859-3:1988|L3|LATIN3|CSISOLATIN3", "28593 (ISO 8859-3 Latin 3)" }, + { 28594, 0, 0, 1, "iso-8859-4", "ISO-8859-4|ISO-IR-110|ISO8859-4|ISO_8859-4|ISO_8859-4:1988|L4|LATIN4|CSISOLATIN4", "28594 (ISO 8859-4 Baltic)" }, + { 28595, 0, 0, 1, "iso-8859-5", "CYRILLIC|ISO-8859-5|ISO-IR-144|ISO8859-5|ISO_8859-5|ISO_8859-5:1988|CSISOLATINCYRILLIC", "28595 (ISO 8859-5 Cyrillic)" }, + { 28596, 0, 0, 1, "iso-8859-6", "ARABIC|ASMO-708|ECMA-114|ISO-8859-6|ISO-IR-127|ISO8859-6|ISO_8859-6|ISO_8859-6:1987|CSISOLATINARABIC", "28596 (ISO 8859-6 Arabic)" }, + { 28597, 0, 0, 1, "iso-8859-7", "ECMA-118|ELOT_928|GREEK|GREEK8|ISO-8859-7|ISO-IR-126|ISO8859-7|ISO_8859-7|ISO_8859-7:1987|ISO_8859-7:2003|CSISOLATINGREEK", "28597 (ISO 8859-7 Greek)" }, + { 28598, 0, 0, 1, "iso-8859-8", "HEBREW|ISO-8859-8|ISO-IR-138|ISO8859-8|ISO_8859-8|ISO_8859-8:1988|CSISOLATINHEBREW", "28598 (ISO 8859-8 Hebrew: Visual Ordering)" }, + { 28599, 0, 0, 1, "iso-8859-9", "ISO-8859-9|ISO-IR-148|ISO8859-9|ISO_8859-9|ISO_8859-9:1989|L5|LATIN5|CSISOLATIN5", "28599 (ISO 8859-9 Latin 5)" }, + { 28603, 0, 0, 1, "iso-8859-13", "ISO-8859-13|ISO-IR-179|ISO8859-13|ISO_8859-13|L7|LATIN7", "28603 (ISO 8859-13 Latin 7)" }, + { 28605, 0, 0, 1, "iso-8859-15", "ISO-8859-15|ISO-IR-203|ISO8859-15|ISO_8859-15|ISO_8859-15:1998|LATIN-9", "28605 (ISO 8859-15 Latin 9)" }, + /* 29001 is invalid */ + { 38598, 0, 0, 1, "iso-8859-8-i", NULL, "38598 (ISO 8859-8 Hebrew: Logical Ordering)" }, + { 50220, 0, 0, 5, "iso-2022-jp", "CP50220", "50220 (ISO-2022 Japanese with no halfwidth Katakana)" }, + { 50221, 0, 0, 5, "csISO2022JP", "CP50221", "50221 (ISO-2022 Japanese with halfwidth Katakana)" }, + { 50222, 0, 0, 5, "iso-2022-jp", "ISO-2022-JP|CP50222", "50222 (ISO-2022 Japanese JIS X 0201-1989)" }, + { 50225, 0, 0, 5, "iso-2022-kr", "ISO-2022-KR|CSISO2022KR", "50225 (ISO-2022 Korean)" }, + { 50227, 0, 0, 5, "x-cp50227", NULL, "50227 (ISO-2022 Simplified Chinese)" }, + { 50229, 0, 0, 5, "", NULL, "50229 (ISO-2022 Traditional Chinese)" }, + /* 50930 is invalid */ + /* 50931 is invalid */ + /* 50933 is invalid */ + /* 50935 is invalid */ + /* 50936 is invalid */ + /* 50937 is invalid */ + /* 50939 is invalid */ + /* 51932 is invalid */ + /* 51936 is invalid */ + { 51949, 0, 0, 2, "euc-kr", "EUC-KR|EUCKR|CSEUCKR", "51949 (EUC-Korean)" }, + /* 51950 is invalid */ + { 52936, 0, 0, 5, "hz-gb-2312", "HZ|HZ-GB-2312", "52936 (HZ-GB2312 Simplified Chinese)" }, + { 54936, 8, 128, 4, "GB18030", "GB18030|CSGB18030", "54936 (GB18030 Simplified Chinese)" }, + { 57002, 0, 0, 4, "x-iscii-de", NULL, "57002 (ISCII - Devanagari)" }, + { 57003, 0, 0, 4, "x-iscii-be", NULL, "57003 (ISCII - Bengali)" }, + { 57004, 0, 0, 4, "x-iscii-ta", NULL, "57004 (ISCII - Tamil)" }, + { 57005, 0, 0, 4, "x-iscii-te", NULL, "57005 (ISCII - Telugu)" }, + { 57006, 0, 0, 4, "x-iscii-as", NULL, "57006 (ISCII - Assamese)" }, + { 57007, 0, 0, 4, "x-iscii-or", NULL, "57007 (ISCII - Odia (Oriya))" }, + { 57008, 0, 0, 4, "x-iscii-ka", NULL, "57008 (ISCII - Kannada)" }, + { 57009, 0, 0, 4, "x-iscii-ma", NULL, "57009 (ISCII - Malayalam)" }, + { 57010, 0, 0, 4, "x-iscii-gu", NULL, "57010 (ISCII - Gujarati)" }, + { 57011, 0, 0, 4, "x-iscii-pa", NULL, "57011 (ISCII - Punjabi (Gurmukhi))" }, + { 65000, 0, 0, 5, "utf-7", "UTF-7", "65000 (UTF-7)" }, + { 65001, 8, 128, 4, "utf-8", "UTF-8", "65001 (UTF-8)" }, +}; + diff --git a/win32/cp_enc_map_gen.c b/win32/cp_enc_map_gen.c new file mode 100644 index 0000000000..e99ef75faa --- /dev/null +++ b/win32/cp_enc_map_gen.c @@ -0,0 +1,250 @@ + +#include <stdio.h> + +#include <windows.h> + +struct cp { + DWORD id; + char *name; + char *enc; + char *desc; +}; + +static const struct cp cp_map[] = { + { 37, "IBM037", "", "IBM EBCDIC US-Canada" }, + { 437, "IBM437", "", "OEM United States" }, + { 500, "IBM500", "", "IBM EBCDIC International" }, + { 708, "ASMO-708", "", "Arabic (ASMO 708)" }, + { 709, "", "", "Arabic (ASMO-449+, BCON V4)" }, + { 710, "", "", "Arabic - Transparent Arabic" }, + { 720, "DOS-720", "", "Arabic (Transparent ASMO); Arabic (DOS)" }, + { 737, "ibm737", "", "OEM Greek (formerly 437G); Greek (DOS)" }, + { 775, "ibm775", "", "OEM Baltic; Baltic (DOS)" }, + { 850, "ibm850", "850|CP850|IBM850|CSPC850MULTILINGUAL", "OEM Multilingual Latin 1; Western European (DOS)" }, + { 852, "ibm852", "", "OEM Latin 2; Central European (DOS)" }, + { 855, "IBM855", "", "OEM Cyrillic (primarily Russian)" }, + { 857, "ibm857", "", "OEM Turkish; Turkish (DOS)" }, + { 858, "IBM00858", "", "OEM Multilingual Latin 1 + Euro symbol" }, + { 860, "IBM860", "", "OEM Portuguese; Portuguese (DOS)" }, + { 861, "ibm861", "", "OEM Icelandic; Icelandic (DOS)" }, + { 862, "DOS-862", "862|CP862|IBM862|CSPC862LATINHEBREW", "OEM Hebrew; Hebrew (DOS)" }, + { 863, "IBM863", "", "OEM French Canadian; French Canadian (DOS)" }, + { 864, "IBM864", "", "OEM Arabic; Arabic (864)" }, + { 865, "IBM865", "", "OEM Nordic; Nordic (DOS)" }, + { 866, "cp866", "866|CP866|IBM866|CSIBM866", "OEM Russian; Cyrillic (DOS)" }, + { 869, "ibm869", "", "OEM Modern Greek; Greek, Modern (DOS)" }, + { 870, "IBM870", "", "IBM EBCDIC Multilingual/ROECE (Latin 2); IBM EBCDIC Multilingual Latin 2" }, + { 874, "windows-874", "CP874", "ANSI/OEM Thai (ISO 8859-11); Thai (Windows)" }, + { 875, "cp875", "", "IBM EBCDIC Greek Modern" }, + { 932, "shift_jis", "CP932|SHIFT_JIS|MS_KANJI|CSSHIFTJIS", "ANSI/OEM Japanese; Japanese (Shift-JIS)" }, + { 936, "gb2312", "GB2312|GBK|CP936|MS936|WINDOWS-936", "ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312)" }, + { 949, "ks_c_5601-1987", "CP949|UHC", "ANSI/OEM Korean (Unified Hangul Code)" }, + { 950, "big5", "CP950|BIG-5", "ANSI/OEM Traditional Chinese (Taiwan; Hong Kong SAR, PRC); Chinese Traditional (Big5)" }, + { 1026, "IBM1026", "", "IBM EBCDIC Turkish (Latin 5)" }, + { 1047, "IBM01047", "", "IBM EBCDIC Latin 1/Open System" }, + { 1140, "IBM01140", "", "IBM EBCDIC US-Canada (037 + Euro symbol); IBM EBCDIC (US-Canada-Euro)" }, + { 1141, "IBM01141", "", "IBM EBCDIC Germany (20273 + Euro symbol); IBM EBCDIC (Germany-Euro)" }, + { 1142, "IBM01142", "", "IBM EBCDIC Denmark-Norway (20277 + Euro symbol); IBM EBCDIC (Denmark-Norway-Euro)" }, + { 1143, "IBM01143", "", "IBM EBCDIC Finland-Sweden (20278 + Euro symbol); IBM EBCDIC (Finland-Sweden-Euro)" }, + { 1144, "IBM01144", "", "IBM EBCDIC Italy (20280 + Euro symbol); IBM EBCDIC (Italy-Euro)" }, + { 1145, "IBM01145", "", "IBM EBCDIC Latin America-Spain (20284 + Euro symbol); IBM EBCDIC (Spain-Euro)" }, + { 1146, "IBM01146", "", "IBM EBCDIC United Kingdom (20285 + Euro symbol); IBM EBCDIC (UK-Euro)" }, + { 1147, "IBM01147", "", "IBM EBCDIC France (20297 + Euro symbol); IBM EBCDIC (France-Euro)" }, + { 1148, "IBM01148", "", "IBM EBCDIC International (500 + Euro symbol); IBM EBCDIC (International-Euro)" }, + { 1149, "IBM01149", "", "IBM EBCDIC Icelandic (20871 + Euro symbol); IBM EBCDIC (Icelandic-Euro)" }, + { 1200, "utf-16", "", "Unicode UTF-16, little endian byte order (BMP of ISO 10646); available only to managed applications" }, + { 1201, "unicodeFFFE", "", "Unicode UTF-16, big endian byte order; available only to managed applications" }, + { 1250, "windows-1250", "CP1250|MS-EE|WINDOWS-1250", "ANSI Central European; Central European (Windows)" }, + { 1251, "windows-1251", "CP1251|MS-CYRL|WINDOWS-1251", "ANSI Cyrillic; Cyrillic (Windows)" }, + { 1252, "windows-1252", "CP1252|MS-ANSI|WINDOWS-1252", "ANSI Latin 1; Western European (Windows)" }, + { 1253, "windows-1253", "CP1253|MS-GREEK|WINDOWS-1253", "ANSI Greek; Greek (Windows)" }, + { 1254, "windows-1254", "CP1254|MS-TURK|WINDOWS-1254", "ANSI Turkish; Turkish (Windows)" }, + { 1255, "windows-1255", "CP1255|MS-HEBR|WINDOWS-1255", "ANSI Hebrew; Hebrew (Windows)" }, + { 1256, "windows-1256", "CP1256|MS-ARAB|WINDOWS-1256", "ANSI Arabic; Arabic (Windows)" }, + { 1257, "windows-1257", "CP1257|WINBALTRIM|WINDOWS-1257", "ANSI Baltic; Baltic (Windows)" }, + { 1258, "windows-1258", "CP1258|WINDOWS-1258", "ANSI/OEM Vietnamese; Vietnamese (Windows)" }, + { 1361, "Johab", "CP1361|JOHAB", "Korean (Johab)" }, + { 10000, "macintosh", "MAC|MACINTOSH|MACROMAN|CSMACINTOSH", "MAC Roman; Western European (Mac)" }, + { 10001, "x-mac-japanese", "", "Japanese (Mac)" }, + { 10002, "x-mac-chinesetrad", "", "MAC Traditional Chinese (Big5); Chinese Traditional (Mac)" }, + { 10003, "x-mac-korean", "", "Korean (Mac)" }, + { 10004, "x-mac-arabic", "MACARABIC", "Arabic (Mac)" }, + { 10005, "x-mac-hebrew", "MACHEBREW", "Hebrew (Mac)" }, + { 10006, "x-mac-greek", "MACGREEK", "Greek (Mac)" }, + { 10007, "x-mac-cyrillic", "MACCYRILLIC", "Cyrillic (Mac)" }, + { 10008, "x-mac-chinesesimp", "", "MAC Simplified Chinese (GB 2312); Chinese Simplified (Mac)" }, + { 10010, "x-mac-romanian", "MACROMANIA", "Romanian (Mac)" }, + { 10017, "x-mac-ukrainian", "MACUKRAINE", "Ukrainian (Mac)" }, + { 10021, "x-mac-thai", "MACTHAI", "Thai (Mac)" }, + { 10029, "x-mac-ce", "MACCENTRALEUROPE", "MAC Latin 2; Central European (Mac)" }, + { 10079, "x-mac-icelandic", "MACICELAND", "Icelandic (Mac)" }, + { 10081, "x-mac-turkish", "MACTURKISH", "Turkish (Mac)" }, + { 10082, "x-mac-croatian", "MACCROATIAN", "Croatian (Mac)" }, + { 12000, "utf-32", "", "Unicode UTF-32, little endian byte order; available only to managed applications" }, + { 12001, "utf-32BE", "", "Unicode UTF-32, big endian byte order; available only to managed applications" }, + { 20000, "x-Chinese_CNS", "", "CNS Taiwan; Chinese Traditional (CNS)" }, + { 20001, "x-cp20001", "", "TCA Taiwan" }, + { 20002, "x_Chinese-Eten", "", "Eten Taiwan; Chinese Traditional (Eten)" }, + { 20003, "x-cp20003", "", "IBM5550 Taiwan" }, + { 20004, "x-cp20004", "", "TeleText Taiwan" }, + { 20005, "x-cp20005", "", "Wang Taiwan" }, + { 20105, "x-IA5", "", "IA5 (IRV International Alphabet No. 5, 7-bit); Western European (IA5)" }, + { 20106, "x-IA5-German", "", "IA5 German (7-bit)" }, + { 20107, "x-IA5-Swedish", "", "IA5 Swedish (7-bit)" }, + { 20108, "x-IA5-Norwegian", "", "IA5 Norwegian (7-bit)" }, + { 20127, "us-ascii", "", "US-ASCII (7-bit)" }, + { 20261, "x-cp20261", "", "T.61" }, + { 20269, "x-cp20269", "", "ISO 6937 Non-Spacing Accent" }, + { 20273, "IBM273", "", "IBM EBCDIC Germany" }, + { 20277, "IBM277", "", "IBM EBCDIC Denmark-Norway" }, + { 20278, "IBM278", "", "IBM EBCDIC Finland-Sweden" }, + { 20280, "IBM280", "", "IBM EBCDIC Italy" }, + { 20284, "IBM284", "", "IBM EBCDIC Latin America-Spain" }, + { 20285, "IBM285", "", "IBM EBCDIC United Kingdom" }, + { 20290, "IBM290", "", "IBM EBCDIC Japanese Katakana Extended" }, + { 20297, "IBM297", "", "IBM EBCDIC France" }, + { 20420, "IBM420", "", "IBM EBCDIC Arabic" }, + { 20423, "IBM423", "", "IBM EBCDIC Greek" }, + { 20424, "IBM424", "", "IBM EBCDIC Hebrew" }, + { 20833, "x-EBCDIC-KoreanExtended", "", "IBM EBCDIC Korean Extended" }, + { 20838, "IBM-Thai", "", "IBM EBCDIC Thai" }, + { 20866, "koi8-r", "KOI8-R|CSKOI8R", "Russian (KOI8-R); Cyrillic (KOI8-R)" }, + { 20871, "IBM871", "", "IBM EBCDIC Icelandic" }, + { 20880, "IBM880", "", "IBM EBCDIC Cyrillic Russian" }, + { 20905, "IBM905", "", "IBM EBCDIC Turkish" }, + { 20924, "IBM00924", "", "IBM EBCDIC Latin 1/Open System (1047 + Euro symbol)" }, + { 20932, "EUC-JP", "EUC-JP|EUCJP|EXTENDED_UNIX_CODE_PACKED_FORMAT_FOR_JAPANESE|CSEUCPKDFMTJAPANESE", "Japanese (JIS 0208-1990 and 0212-1990)" }, + { 20936, "x-cp20936", "", "Simplified Chinese (GB2312); Chinese Simplified (GB2312-80)" }, + { 20949, "x-cp20949", "", "Korean Wansung" }, + { 21025, "cp1025", "", "IBM EBCDIC Cyrillic Serbian-Bulgarian" }, + { 21027, "", "", "(deprecated)" }, + { 21866, "koi8-u", "KOI8-U", "Ukrainian (KOI8-U); Cyrillic (KOI8-U)" }, + { 28591, "iso-8859-1", "CP819|IBM819|ISO-8859-1|ISO-IR-100|ISO8859-1|ISO_8859-1|ISO_8859-1:1987|L1|LATIN1|CSISOLATIN1", "ISO 8859-1 Latin 1; Western European (ISO)" }, + { 28592, "iso-8859-2", "ISO-8859-2|ISO-IR-101|ISO8859-2|ISO_8859-2|ISO_8859-2:1987|L2|LATIN2|CSISOLATIN2", "ISO 8859-2 Central European; Central European (ISO)" }, + { 28593, "iso-8859-3", "ISO-8859-3|ISO-IR-109|ISO8859-3|ISO_8859-3|ISO_8859-3:1988|L3|LATIN3|CSISOLATIN3", "ISO 8859-3 Latin 3" }, + { 28594, "iso-8859-4", "ISO-8859-4|ISO-IR-110|ISO8859-4|ISO_8859-4|ISO_8859-4:1988|L4|LATIN4|CSISOLATIN4", "ISO 8859-4 Baltic" }, + { 28595, "iso-8859-5", "CYRILLIC|ISO-8859-5|ISO-IR-144|ISO8859-5|ISO_8859-5|ISO_8859-5:1988|CSISOLATINCYRILLIC", "ISO 8859-5 Cyrillic" }, + { 28596, "iso-8859-6", "ARABIC|ASMO-708|ECMA-114|ISO-8859-6|ISO-IR-127|ISO8859-6|ISO_8859-6|ISO_8859-6:1987|CSISOLATINARABIC", "ISO 8859-6 Arabic" }, + { 28597, "iso-8859-7", "ECMA-118|ELOT_928|GREEK|GREEK8|ISO-8859-7|ISO-IR-126|ISO8859-7|ISO_8859-7|ISO_8859-7:1987|ISO_8859-7:2003|CSISOLATINGREEK", "ISO 8859-7 Greek" }, + { 28598, "iso-8859-8", "HEBREW|ISO-8859-8|ISO-IR-138|ISO8859-8|ISO_8859-8|ISO_8859-8:1988|CSISOLATINHEBREW", "ISO 8859-8 Hebrew; Hebrew (ISO-Visual)" }, + { 28599, "iso-8859-9", "ISO-8859-9|ISO-IR-148|ISO8859-9|ISO_8859-9|ISO_8859-9:1989|L5|LATIN5|CSISOLATIN5", "ISO 8859-9 Turkish" }, + { 28603, "iso-8859-13", "ISO-8859-13|ISO-IR-179|ISO8859-13|ISO_8859-13|L7|LATIN7", "ISO 8859-13 Estonian" }, + { 28605, "iso-8859-15", "ISO-8859-15|ISO-IR-203|ISO8859-15|ISO_8859-15|ISO_8859-15:1998|LATIN-9", "ISO 8859-15 Latin 9" }, + { 29001, "x-Europa", "", "Europa 3" }, + { 38598, "iso-8859-8-i", "", "ISO 8859-8 Hebrew; Hebrew (ISO-Logical)" }, + { 50220, "iso-2022-jp", "CP50220", "ISO 2022 Japanese with no halfwidth Katakana; Japanese (JIS)" }, + { 50221, "csISO2022JP", "CP50221", "ISO 2022 Japanese with halfwidth Katakana; Japanese (JIS-Allow 1 byte Kana)" }, + { 50222, "iso-2022-jp", "ISO-2022-JP|CP50222", "ISO 2022 Japanese JIS X 0201-1989; Japanese (JIS-Allow 1 byte Kana - SO/SI)" }, + { 50225, "iso-2022-kr", "ISO-2022-KR|CSISO2022KR", "ISO 2022 Korean" }, + { 50227, "x-cp50227", "", "ISO 2022 Simplified Chinese; Chinese Simplified (ISO 2022)" }, + { 50229, "", "", "ISO 2022 Traditional Chinese" }, + { 50930, "", "", "EBCDIC Japanese (Katakana) Extended" }, + { 50931, "", "", "EBCDIC US-Canada and Japanese" }, + { 50933, "", "", "EBCDIC Korean Extended and Korean" }, + { 50935, "", "", "EBCDIC Simplified Chinese Extended and Simplified Chinese" }, + { 50936, "", "", "EBCDIC Simplified Chinese" }, + { 50937, "", "", "EBCDIC US-Canada and Traditional Chinese" }, + { 50939, "", "", "EBCDIC Japanese (Latin) Extended and Japanese" }, + { 51932, "euc-jp", "", "EUC Japanese" }, + { 51936, "EUC-CN", "", "EUC Simplified Chinese; Chinese Simplified (EUC)" }, + { 51949, "euc-kr", "EUC-KR|EUCKR|CSEUCKR", "EUC Korean" }, + { 51950, "", "", "EUC Traditional Chinese" }, + { 52936, "hz-gb-2312", "HZ|HZ-GB-2312", "HZ-GB2312 Simplified Chinese; Chinese Simplified (HZ)" }, + { 54936, "GB18030", "GB18030|CSGB18030", "Windows XP and later: GB18030 Simplified Chinese (4 byte); Chinese Simplified (GB18030)" }, + { 57002, "x-iscii-de", "", "ISCII Devanagari" }, + { 57003, "x-iscii-be", "", "ISCII Bangla" }, + { 57004, "x-iscii-ta", "", "ISCII Tamil" }, + { 57005, "x-iscii-te", "", "ISCII Telugu" }, + { 57006, "x-iscii-as", "", "ISCII Assamese" }, + { 57007, "x-iscii-or", "", "ISCII Odia" }, + { 57008, "x-iscii-ka", "", "ISCII Kannada" }, + { 57009, "x-iscii-ma", "", "ISCII Malayalam" }, + { 57010, "x-iscii-gu", "", "ISCII Gujarati" }, + { 57011, "x-iscii-pa", "", "ISCII Punjabi" }, + { 65000, "utf-7", "UTF-7", "Unicode (UTF-7)" }, + { 65001, "utf-8", "UTF-8", "Unicode (UTF-8)" }, + { 0, NULL, NULL }, +}; + + + + +int +main(int argc, char **argv) +{ + DWORD cp; + CPINFOEX info; + struct cp *cur; + int rnd = 0; + + /*if (argc < 2) { + printf("Usage: cpinfoex cp_id\n"); + return 0; + } + + cp = atoi(argv[1]);*/ +#if 0 +/* Ref: + http://www.iana.org/assignments/character-sets/character-sets.xhtml + https://msdn.microsoft.com/en-us/goglobal/bb964653 + http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/ + */ +#endif + /* + struct php_win32_cp { + DWORD id; + DWORD to_w_fl; + DWORD from_w_fl; + DWORD char_size; + char *name; + char *enc; + char *desc; + }; + */ + /*printf("struct php_win32_cp {\n\tDWORD id;\n\tDWORD to_w_fl;\n\tDWORD from_w_fl;\n\tDWORD char_size;\n\tchar *name;\n\tchar *enc;\n\tchar *desc;\n};\n\n"); */ + printf("/* Autogenerated file. Update cp_enc_map_gen.c and regen like \n" + " cp_enc_map_gen.exe > cp_enc_map.c \n*/\n\n"); + printf("static const struct php_win32_cp php_win32_cp_map[] = {"); + + cur = &cp_map[0]; + +#ifdef ORDER_IT + while (rnd <= 2 && ++rnd && (cur = &cp_map[0])) +#endif + while (cur->desc != NULL) { + if (!IsValidCodePage(cur->id)) { +#ifdef ORDER_IT + if (2 == rnd) +#endif + printf("\t/* %u is invalid */\n", cur->id); + //printf("#if 0\n\t{ %u, 0, \"%s\", \"%s\" },\n#endif\n", cur->id, cur->name, cur->desc); + } else if (GetCPInfoEx(cur->id, 0, &info)) { + DWORD to_w_fl = 0, from_w_fl = 0; + + if (65001U == cur->id || 54936U == cur->id) { + from_w_fl = WC_ERR_INVALID_CHARS; + to_w_fl = MB_ERR_INVALID_CHARS; + } + + //printf("\t{ %u, %u, \"%s\", \"%s\" },\n", cur->id, info.MaxCharSize, cur->name, cur->desc); + if (!cur->enc[0]) { +#ifdef ORDER_IT + if (2 == rnd) +#endif + //printf("\t/* { %u, %u, \"%s\", NULL, \"%s\" }, */\n", info.CodePage, info.MaxCharSize, cur->name, info.CodePageName); + printf("\t{ %u, %u, %u, %u, \"%s\", NULL, \"%s\" },\n", info.CodePage, to_w_fl, from_w_fl, info.MaxCharSize, cur->name, info.CodePageName); + } else { +#ifdef ORDER_IT + if (1 == rnd) +#endif + printf("\t{ %u, %u, %u, %u, \"%s\", \"%s\", \"%s\" },\n", info.CodePage, to_w_fl, from_w_fl, info.MaxCharSize, cur->name, cur->enc, info.CodePageName); + } + } + cur++; + } + + printf("};\n\n"); + + return 0; +} + diff --git a/win32/dllmain.c b/win32/dllmain.c index a398b2201d..37408f1e76 100644 --- a/win32/dllmain.c +++ b/win32/dllmain.c @@ -19,6 +19,7 @@ #include <config.w32.h> #include <win32/time.h> +#include <win32/ioutil.h> #include <php.h> #ifdef HAVE_LIBXML @@ -44,6 +45,12 @@ BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, LPVOID dummy) fprintf(stderr, "gettimeofday() initialization failed"); return ret; } + + ret = ret && php_win32_ioutil_init(); + if (!ret) { + fprintf(stderr, "ioutil initialization failed"); + return ret; + } break; #if 0 /* prepared */ case DLL_PROCESS_DETACH: diff --git a/win32/ftok.c b/win32/ftok.c new file mode 100644 index 0000000000..842da78192 --- /dev/null +++ b/win32/ftok.c @@ -0,0 +1,52 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 7 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2016 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Anatol Belski <ab@php.net> | + +----------------------------------------------------------------------+ + */ + +#include "ipc.h" + +#include <windows.h> +#include <sys/stat.h> + + +PHPAPI key_t +ftok(const char *pathname, int proj_id) +{ + HANDLE fh; + struct stat st; + BY_HANDLE_FILE_INFORMATION bhfi; + key_t ret; + + if (stat(pathname, &st) < 0) { + return (key_t)-1; + } + + if ((fh = CreateFile(pathname, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) { + return (key_t)-1; + } + + if (!GetFileInformationByHandle(fh, &bhfi)) { + CloseHandle(fh); + return (key_t)-1; + } + + ret = (key_t) ((proj_id & 0xff) << 24 | (st.st_dev & 0xff) << 16 | ((bhfi.nFileIndexLow | (__int64)bhfi.nFileIndexHigh << 32) & 0xffff)); + + CloseHandle(fh); + + return ret; +} + diff --git a/win32/ioutil.c b/win32/ioutil.c new file mode 100644 index 0000000000..b661a150af --- /dev/null +++ b/win32/ioutil.c @@ -0,0 +1,611 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 7 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2016 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Anatol Belski <ab@php.net> | + +----------------------------------------------------------------------+ +*/ + +/* This file integrates several modified parts from the libuv project, which + * is copyrighted to + * + * Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include <assert.h> +#include <stdlib.h> +#include <direct.h> +#include <errno.h> +#include <fcntl.h> +#include <io.h> +#include <limits.h> +#include <sys/stat.h> +#include <sys/utime.h> +#include <stdio.h> + +#include "php.h" +#include "SAPI.h" +#include "win32/winutil.h" +#include "win32/time.h" +#include "win32/ioutil.h" +#include "win32/codepage.h" + +#include <pathcch.h> + +/* +#undef NONLS +#undef _WINNLS_ +#include <winnls.h> +*/ + +typedef HRESULT (__stdcall *MyPathCchCanonicalizeEx)(wchar_t *pszPathOut, size_t cchPathOut, const wchar_t *pszPathIn, unsigned long dwFlags); + +static MyPathCchCanonicalizeEx canonicalize_path_w = NULL; + +PW32IO BOOL php_win32_ioutil_posix_to_open_opts(int flags, mode_t mode, php_ioutil_open_opts *opts) +{/*{{{*/ + int current_umask; + + opts->attributes = 0; + + /* Obtain the active umask. umask() never fails and returns the previous */ + /* umask. */ + current_umask = umask(0); + umask(current_umask); + + /* convert flags and mode to CreateFile parameters */ + switch (flags & (_O_RDONLY | _O_WRONLY | _O_RDWR)) { + case _O_RDONLY: + opts->access = FILE_GENERIC_READ; + /* XXX not opening dirs yet, see also at the bottom of this function. Should be evaluated properly. */ + /*opts->attributes |= FILE_FLAG_BACKUP_SEMANTICS;*/ + break; + case _O_WRONLY: + opts->access = FILE_GENERIC_WRITE; + break; + case _O_RDWR: + opts->access = FILE_GENERIC_READ | FILE_GENERIC_WRITE; + break; + default: + goto einval; + } + + if (flags & _O_APPEND) { + /* XXX this might look wrong, but i just leave it here. Disabling FILE_WRITE_DATA prevents the current truncate behaviors for files opened with "a". */ + /* access &= ~FILE_WRITE_DATA;*/ + opts->access |= FILE_APPEND_DATA; + opts->attributes &= ~FILE_FLAG_BACKUP_SEMANTICS; + } + + /* + * Here is where we deviate significantly from what CRT's _open() + * does. We indiscriminately use all the sharing modes, to match + * UNIX semantics. In particular, this ensures that the file can + * be deleted even whilst it's open. + */ + /* opts->share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; */ + /* XXX No UINX behavior Good to know it's doable. + Not being done as this means a behavior change. Should be evaluated properly. */ + opts->share = FILE_SHARE_READ | FILE_SHARE_WRITE; + + switch (flags & (_O_CREAT | _O_EXCL | _O_TRUNC)) { + case 0: + case _O_EXCL: + opts->disposition = OPEN_EXISTING; + break; + case _O_CREAT: + opts->disposition = OPEN_ALWAYS; + break; + case _O_CREAT | _O_EXCL: + case _O_CREAT | _O_TRUNC | _O_EXCL: + opts->disposition = CREATE_NEW; + break; + case _O_TRUNC: + case _O_TRUNC | _O_EXCL: + opts->disposition = TRUNCATE_EXISTING; + break; + case _O_CREAT | _O_TRUNC: + opts->disposition = CREATE_ALWAYS; + break; + default: + goto einval; + } + + opts->attributes |= FILE_ATTRIBUTE_NORMAL; + if (flags & _O_CREAT) { + if (!((mode & ~current_umask) & _S_IWRITE)) { + opts->attributes |= FILE_ATTRIBUTE_READONLY; + } + } + + if (flags & _O_TEMPORARY ) { + opts->attributes |= FILE_FLAG_DELETE_ON_CLOSE | FILE_ATTRIBUTE_TEMPORARY; + opts->access |= DELETE; + } + + if (flags & _O_SHORT_LIVED) { + opts->attributes |= FILE_ATTRIBUTE_TEMPORARY; + } + + switch (flags & (_O_SEQUENTIAL | _O_RANDOM)) { + case 0: + break; + case _O_SEQUENTIAL: + opts->attributes |= FILE_FLAG_SEQUENTIAL_SCAN; + break; + case _O_RANDOM: + opts->attributes |= FILE_FLAG_RANDOM_ACCESS; + break; + default: + goto einval; + } + + /* Very compat options */ + /*if (flags & O_ASYNC) { + opts->attributes |= FILE_FLAG_OVERLAPPED; + } else if (flags & O_SYNC) { + opts->attributes &= ~FILE_FLAG_OVERLAPPED; + }*/ + + /* Setting this flag makes it possible to open a directory. */ + /* XXX not being done as this means a behavior change. Should be evaluated properly. */ + /* opts->attributes |= FILE_FLAG_BACKUP_SEMANTICS; */ + + return 1; + +einval: + _set_errno(EINVAL); + return 0; +}/*}}}*/ + +PW32IO int php_win32_ioutil_open_w(const wchar_t *path, int flags, ...) +{/*{{{*/ + php_ioutil_open_opts open_opts; + HANDLE file; + int fd; + mode_t mode = 0; + + PHP_WIN32_IOUTIL_CHECK_PATH_W(path, -1) + + if (flags & O_CREAT) { + va_list arg; + + va_start(arg, flags); + mode = (mode_t) va_arg(arg, int); + va_end(arg); + } + + if (!php_win32_ioutil_posix_to_open_opts(flags, mode, &open_opts)) { + goto einval; + } + + /* XXX care about security attributes here if needed, see tsrm_win32_access() */ + file = CreateFileW(path, + open_opts.access, + open_opts.share, + NULL, + open_opts.disposition, + open_opts.attributes, + NULL); + + if (file == INVALID_HANDLE_VALUE) { + DWORD error = GetLastError(); + + if (error == ERROR_FILE_EXISTS && (flags & _O_CREAT) && + !(flags & _O_EXCL)) { + /* Special case: when ERROR_FILE_EXISTS happens and O_CREAT was */ + /* specified, it means the path referred to a directory. */ + _set_errno(EISDIR); + } else { + SET_ERRNO_FROM_WIN32_CODE(error); + } + return -1; + } + + fd = _open_osfhandle((intptr_t) file, flags); + if (fd < 0) { + DWORD error = GetLastError(); + + /* The only known failure mode for _open_osfhandle() is EMFILE, in which + * case GetLastError() will return zero. However we'll try to handle other + * errors as well, should they ever occur. + */ + if (errno == EMFILE) { + _set_errno(EMFILE); + } else if (error != ERROR_SUCCESS) { + SET_ERRNO_FROM_WIN32_CODE(error); + } + CloseHandle(file); + return -1; + } + + if (flags & _O_TEXT) { + _setmode(fd, _O_TEXT); + } else if (flags & _O_BINARY) { + _setmode(fd, _O_BINARY); + } + + return fd; + + einval: + _set_errno(EINVAL); + return -1; +}/*}}}*/ + +PW32IO int php_win32_ioutil_close(int fd) +{/*{{{*/ + int result = -1; + + if (-1 == fd) { + _set_errno(EBADF); + return result; + } + + if (fd > 2) { + result = _close(fd); + } else { + result = 0; + } + + /* _close doesn't set _doserrno on failure, but it does always set errno + * to EBADF on failure. + */ + if (result == -1) { + _set_errno(EBADF); + } + + return result; +}/*}}}*/ + +#if 0 +PW32IO int php_win32_ioutil_mkdir_w(const wchar_t *path, mode_t mode) +{/*{{{*/ + int ret = 0; + DWORD err = 0; + + PHP_WIN32_IOUTIL_CHECK_PATH_W(path, -1) + + /* TODO extend with mode usage */ + if (!CreateDirectoryW(path, NULL)) { + err = GetLastError(); + ret = -1; + SET_ERRNO_FROM_WIN32_CODE(err); + } + + return ret; +}/*}}}*/ +#endif + +PW32IO int php_win32_ioutil_mkdir(const char *path, mode_t mode) +{/*{{{*/ + wchar_t *pathw = php_win32_ioutil_any_to_w(path); + int ret = 0; + DWORD err = 0; + + /* TODO extend with mode usage */ + if (!pathw) { + SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER); + return -1; + } + + PHP_WIN32_IOUTIL_CHECK_PATH_W(pathw, -1) + + if (!CreateDirectoryW(pathw, NULL)) { + err = GetLastError(); + ret = -1; + } + free(pathw); + + if (0 > ret) { + SET_ERRNO_FROM_WIN32_CODE(err); + } + + return ret; +}/*}}}*/ + +PW32IO int php_win32_ioutil_unlink_w(const wchar_t *path) +{/*{{{*/ + int ret = 0; + DWORD err = 0; + + PHP_WIN32_IOUTIL_CHECK_PATH_W(path, -1) + + if (!DeleteFileW(path)) { + err = GetLastError(); + ret = -1; + SET_ERRNO_FROM_WIN32_CODE(err); + } + + return ret; +}/*}}}*/ + +PW32IO int php_win32_ioutil_rmdir_w(const wchar_t *path) +{/*{{{*/ + int ret = 0; + DWORD err = 0; + + PHP_WIN32_IOUTIL_CHECK_PATH_W(path, -1) + + if (!RemoveDirectoryW(path)) { + err = GetLastError(); + ret = -1; + SET_ERRNO_FROM_WIN32_CODE(err); + } + + return ret; +}/*}}}*/ + +PW32IO int php_win32_ioutil_chdir_w(const wchar_t *path) +{/*{{{*/ + int ret = 0; + DWORD err = 0; + + if (!SetCurrentDirectoryW(path)) { + err = GetLastError(); + ret = -1; + SET_ERRNO_FROM_WIN32_CODE(err); + } + + return ret; +}/*}}}*/ + +PW32IO int php_win32_ioutil_rename_w(const wchar_t *oldname, const wchar_t *newname) +{/*{{{*/ + int ret = 0; + DWORD err = 0; + + PHP_WIN32_IOUTIL_CHECK_PATH_W(oldname, -1) + PHP_WIN32_IOUTIL_CHECK_PATH_W(newname, -1) + + + if (!MoveFileExW(oldname, newname, MOVEFILE_REPLACE_EXISTING|MOVEFILE_COPY_ALLOWED)) { + err = GetLastError(); + ret = -1; + SET_ERRNO_FROM_WIN32_CODE(err); + } + + return ret; +}/*}}}*/ + +PW32IO wchar_t *php_win32_ioutil_getcwd_w(const wchar_t *buf, int len) +{/*{{{*/ + DWORD err = 0; + wchar_t *tmp_buf = NULL; + + /* If buf was NULL, the result has to be freed outside here. */ + if (!buf) { + DWORD tmp_len = GetCurrentDirectoryW(0, NULL) + 1; + if (!tmp_len) { + err = GetLastError(); + SET_ERRNO_FROM_WIN32_CODE(err); + return NULL; + } else if (tmp_len > len) { + SET_ERRNO_FROM_WIN32_CODE(ERROR_INSUFFICIENT_BUFFER); + return NULL; + } + + len = tmp_len; + + tmp_buf = (wchar_t *)malloc((len)*sizeof(wchar_t)); + if (!tmp_buf) { + SET_ERRNO_FROM_WIN32_CODE(ERROR_NOT_ENOUGH_MEMORY); + return NULL; + } + buf = tmp_buf; + } + + if (!GetCurrentDirectoryW(len, buf)) { + err = GetLastError(); + SET_ERRNO_FROM_WIN32_CODE(err); + return NULL; + } + + return (wchar_t *)buf; +}/*}}}*/ + +/* based on zend_dirname(). */ +PW32IO size_t php_win32_ioutil_dirname(char *path, size_t len) +{/*{{{*/ + char *ret = NULL, *start; + size_t ret_len, len_adjust = 0, pathw_len; + wchar_t *endw, *pathw, *startw; + + if (len == 0) { + return 0; + } + + start = path; + + startw = pathw = php_win32_ioutil_conv_any_to_w(path, len, &pathw_len); + if (!pathw) { + return 0; + } + + endw = pathw + pathw_len - 1; + + if ((2 <= len) && isalpha((int)((unsigned char *)path)[0]) && (':' == path[1])) { + pathw += 2; + path += 2; + len_adjust += 2; + if (2 == len) { + free(startw); + return len; + } + } + + /* Strip trailing slashes */ + while (endw >= pathw && PHP_WIN32_IOUTIL_IS_SLASHW(*endw)) { + endw--; + } + if (endw < pathw) { + /* The path only contained slashes */ + path[0] = PHP_WIN32_IOUTIL_DEFAULT_SLASH; + path[1] = '\0'; + return 1 + len_adjust; + } + + /* Strip filename */ + while (endw >= pathw && !PHP_WIN32_IOUTIL_IS_SLASHW(*endw)) { + endw--; + } + if (endw < pathw) { + path[0] = '.'; + path[1] = '\0'; + return 1 + len_adjust; + } + + /* Strip slashes which came before the file name */ + while (endw >= pathw && PHP_WIN32_IOUTIL_IS_SLASHW(*endw)) { + endw--; + } + if (endw < pathw) { + path[0] = PHP_WIN32_IOUTIL_DEFAULT_SLASH; + path[1] = '\0'; + return 1 + len_adjust; + } + *(endw+1) = L'\0'; + + ret_len = (endw + 1 - startw); + if (PHP_WIN32_IOUTIL_IS_LONG_PATHW(startw, ret_len)) { + ret = php_win32_ioutil_conv_w_to_any(startw + PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW, ret_len - PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW, &ret_len); + } else { + ret = php_win32_ioutil_conv_w_to_any(startw, ret_len, &ret_len); + } + memmove(start, ret, ret_len+1); + assert(start[ret_len] == '\0'); + free(ret); + free(startw); + + return ret_len; +}/*}}}*/ + +PW32IO php_win32_ioutil_normalization_result php_win32_ioutil_normalize_path_w(wchar_t **buf, size_t len, size_t *new_len) +{/*{{{*/ + wchar_t *pos, *idx = *buf, canonicalw[MAXPATHLEN]; + size_t ret_len = len; + + if (len >= MAXPATHLEN) { + SET_ERRNO_FROM_WIN32_CODE(ERROR_BAD_LENGTH); + return PHP_WIN32_IOUTIL_NORM_FAIL; + } + + while (NULL != (pos = wcschr(idx, PHP_WIN32_IOUTIL_FW_SLASHW)) && idx - *buf <= len) { + *pos = PHP_WIN32_IOUTIL_DEFAULT_SLASHW; + idx = pos++; + } + + if (S_OK != canonicalize_path_w(canonicalw, MAXPATHLEN, *buf, PATHCCH_ALLOW_LONG_PATHS)) { + return PHP_WIN32_IOUTIL_NORM_PARTIAL; + } + ret_len = wcslen(canonicalw); + if (ret_len != len) { + if (ret_len > len) { + wchar_t *tmp = realloc(*buf, (ret_len + 1) * sizeof(wchar_t)); + if (!tmp) { + SET_ERRNO_FROM_WIN32_CODE(ERROR_NOT_ENOUGH_MEMORY); + return PHP_WIN32_IOUTIL_NORM_PARTIAL; + } + *buf = tmp; + } + memmove(*buf, canonicalw, (ret_len + 1) * sizeof(wchar_t)); + } + *new_len = ret_len; + + return PHP_WIN32_IOUTIL_NORM_OK; +}/*}}}*/ + +static HRESULT __stdcall MyPathCchCanonicalizeExFallback(wchar_t *pszPathOut, size_t cchPathOut, const wchar_t *pszPathIn, unsigned long dwFlags) +{/*{{{*/ + return -42; +}/*}}}*/ + +BOOL php_win32_ioutil_init(void) +{/*{{{*/ + HMODULE hMod = GetModuleHandle("api-ms-win-core-path-l1-1-0"); + + if (hMod) { + canonicalize_path_w = (MyPathCchCanonicalizeEx)GetProcAddress(hMod, "PathCchCanonicalizeEx"); + if (!canonicalize_path_w) { + canonicalize_path_w = (MyPathCchCanonicalizeEx)MyPathCchCanonicalizeExFallback; + } + } else { + canonicalize_path_w = (MyPathCchCanonicalizeEx)MyPathCchCanonicalizeExFallback; + } + + return TRUE; +}/*}}}*/ + +/* an extended version could be implemented, for now direct functions can be used. */ +#if 0 +PW32IO int php_win32_ioutil_access_w(const wchar_t *path, mode_t mode) +{ + return _waccess(path, mode); +} +#endif + +#if 0 +PW32IO HANDLE php_win32_ioutil_findfirstfile_w(char *path, WIN32_FIND_DATA *data) +{ + HANDLE ret = INVALID_HANDLE_VALUE; + DWORD err; + + if (!path) { + SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER); + return ret; + } + + pathw = php_win32_ioutil_any_to_w(path); + + if (!pathw) { + err = GetLastError(); + SET_ERRNO_FROM_WIN32_CODE(ret); + return ret; + } + + ret = FindFirstFileW(pathw, data); + + if (INVALID_HANDLE_VALUE == ret && path) { + ret = FindFirstFileA(path, data); + } + + /* XXX set errno */ + return ret; +} +#endif + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: sw=4 ts=4 fdm=marker + * vim<600: sw=4 ts=4 + */ diff --git a/win32/ioutil.h b/win32/ioutil.h new file mode 100644 index 0000000000..ea40db4c66 --- /dev/null +++ b/win32/ioutil.h @@ -0,0 +1,501 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 7 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2016 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Anatol Belski <ab@php.net> | + +----------------------------------------------------------------------+ +*/ + +/* This file integrates several modified parts from the libuv project, which + * is copyrighted to + * + * Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef PHP_WIN32_IOUTIL_H +#define PHP_WIN32_IOUTIL_H + +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <io.h> +#include <stdio.h> +#include <stdlib.h> + +#include "win32/winutil.h" +#include "win32/codepage.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef PHP_EXPORTS +# define PW32IO __declspec(dllexport) +#else +# define PW32IO __declspec(dllimport) +#endif + +#define PHP_WIN32_IOUTIL_MAXPATHLEN 2048 + +#if !defined(MAXPATHLEN) || MAXPATHLEN < PHP_WIN32_IOUTIL_MAXPATHLEN +# undef MAXPATHLEN +# define MAXPATHLEN PHP_WIN32_IOUTIL_MAXPATHLEN +#endif + +#ifndef mode_t +typedef unsigned short mode_t; +#endif + +typedef struct { + DWORD access; + DWORD share; + DWORD disposition; + DWORD attributes; +} php_ioutil_open_opts; + +typedef enum { + PHP_WIN32_IOUTIL_IS_ASCII, + PHP_WIN32_IOUTIL_IS_ANSI, + PHP_WIN32_IOUTIL_IS_UTF8 +} php_win32_ioutil_encoding; + +typedef enum { + PHP_WIN32_IOUTIL_NORM_OK, + PHP_WIN32_IOUTIL_NORM_PARTIAL, + PHP_WIN32_IOUTIL_NORM_FAIL, +} php_win32_ioutil_normalization_result; + +#define PHP_WIN32_IOUTIL_FW_SLASHW L'/' +#define PHP_WIN32_IOUTIL_FW_SLASH '/' +#define PHP_WIN32_IOUTIL_BW_SLASHW L'\\' +#define PHP_WIN32_IOUTIL_BW_SLASH '\\' +#define PHP_WIN32_IOUTIL_DEFAULT_SLASHW PHP_WIN32_IOUTIL_BW_SLASHW +#define PHP_WIN32_IOUTIL_DEFAULT_SLASH PHP_WIN32_IOUTIL_BW_SLASH + +#define PHP_WIN32_IOUTIL_DEFAULT_DIR_SEPARATORW L';' +#define PHP_WIN32_IOUTIL_IS_SLASHW(c) ((c) == PHP_WIN32_IOUTIL_BW_SLASHW || (c) == PHP_WIN32_IOUTIL_FW_SLASHW) +#define PHP_WIN32_IOUTIL_IS_LETTERW(c) (((c) >= L'a' && (c) <= L'z') || ((c) >= L'A' && (c) <= L'Z')) +#define PHP_WIN32_IOUTIL_JUNCTION_PREFIXW L"\\??\\" +#define PHP_WIN32_IOUTIL_JUNCTION_PREFIX_LENW 4 +#define PHP_WIN32_IOUTIL_LONG_PATH_PREFIXW L"\\\\?\\" +#define PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW 4 +#define PHP_WIN32_IOUTIL_UNC_PATH_PREFIXW L"\\\\?\\UNC\\" +#define PHP_WIN32_IOUTIL_UNC_PATH_PREFIX_LENW 8 + +#define PHP_WIN32_IOUTIL_IS_LONG_PATHW(pathw, path_lenw) (path_lenw >= PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW \ + && 0 == wcsncmp((pathw), PHP_WIN32_IOUTIL_LONG_PATH_PREFIXW, PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW)) +#define PHP_WIN32_IOUTIL_IS_ABSOLUTEW(pathw, path_lenw) (PHP_WIN32_IOUTIL_IS_LONG_PATHW(pathw, path_lenw) \ + || path_lenw >= 3 && PHP_WIN32_IOUTIL_IS_LETTERW(pathw[0]) && L':' == pathw[1] && IS_SLASHW(pathw[2])) + +#define PHP_WIN32_IOUTIL_INIT_W(path) \ + wchar_t *pathw = php_win32_ioutil_any_to_w(path); \ + +#define PHP_WIN32_IOUTIL_CLEANUP_W() do { \ + free(pathw); \ + pathw = NULL; \ +} while (0); + +#define PHP_WIN32_IOUTIL_REINIT_W(path) do { \ + PHP_WIN32_IOUTIL_CLEANUP_W() \ + pathw = php_win32_ioutil_any_to_w(path); \ +} while (0); + +#define PHP_WIN32_IOUTIL_CHECK_PATH_W(pathw, ret) do { \ + size_t len = wcslen(pathw); \ + if (len >= 1 && L' ' == pathw[len-1] || \ + len > 1 && !PHP_WIN32_IOUTIL_IS_SLASHW(pathw[len-2]) && L'.' != pathw[len-2] && L'.' == pathw[len-1] \ + ) { \ + SET_ERRNO_FROM_WIN32_CODE(ERROR_ACCESS_DENIED); \ + return ret; \ + } \ +} while (0); + +PW32IO php_win32_ioutil_normalization_result php_win32_ioutil_normalize_path_w(wchar_t **buf, size_t len, size_t *new_len); +#ifdef PHP_EXPORTS +/* This symbols are needed only for the DllMain, but should not be exported + or be available when used with PHP binaries. */ +BOOL php_win32_ioutil_init(void); +#endif + +/* Keep these functions aliased for case some additional handling + is needed later. */ +__forceinline static wchar_t *php_win32_ioutil_conv_any_to_w(const char* in, size_t in_len, size_t *out_len) +{/*{{{*/ + wchar_t *mb, *ret; + size_t mb_len; + + mb = php_win32_cp_conv_any_to_w(in, in_len, &mb_len); + if (!mb) { + return NULL; + } + + /* Only prefix with long if it's needed. */ + if (mb_len > _MAX_PATH) { + ret = (wchar_t *) malloc((mb_len + PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW + 1) * sizeof(wchar_t)); + if (!ret) { + free(mb); + return NULL; + } + + /* The return can be ignored here, as the normalization can fail for + various reasons not directly related to the operation itself. + Partial normalization could still do a better job further. And + otherwise, the path might be unchanged which is ok if the path + was valid long one. */ + (void)php_win32_ioutil_normalize_path_w(&mb, mb_len, &mb_len); + + if (PHP_WIN32_IOUTIL_IS_LONG_PATHW(mb, mb_len)) { + memmove(ret, mb, mb_len * sizeof(wchar_t)); + ret[mb_len] = L'\0'; + } else { + memmove(ret, PHP_WIN32_IOUTIL_LONG_PATH_PREFIXW, PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW * sizeof(wchar_t)); + memmove(ret+PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW, mb, mb_len * sizeof(wchar_t)); + ret[mb_len + PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW] = L'\0'; + + mb_len += PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW; + } + + free(mb); + } else { + ret = mb; + } + + if (PHP_WIN32_CP_IGNORE_LEN_P != out_len) { + *out_len = mb_len; + } + + return ret; +}/*}}}*/ +#define php_win32_ioutil_any_to_w(in) php_win32_ioutil_conv_any_to_w(in, PHP_WIN32_CP_IGNORE_LEN, PHP_WIN32_CP_IGNORE_LEN_P) + +#define php_win32_ioutil_ascii_to_w php_win32_cp_ascii_to_w +#define php_win32_ioutil_utf8_to_w php_win32_cp_utf8_to_w +#define php_win32_ioutil_cur_to_w php_win32_cp_cur_to_w +#define php_win32_ioutil_w_to_any php_win32_cp_w_to_any +#define php_win32_ioutil_conv_w_to_any php_win32_cp_conv_w_to_any +/*__forceinline static char *php_win32_ioutil_w_to_any(wchar_t* w_source_ptr) +{ + return php_win32_cp_w_to_any(w_source_ptr); +}*/ +#define php_win32_ioutil_w_to_utf8 php_win32_cp_w_to_utf8 +#define php_win32_ioutil_w_to_thread php_win32_cp_w_to_thread + +PW32IO int php_win32_ioutil_close(int fd); +PW32IO BOOL php_win32_ioutil_posix_to_open_opts(int flags, mode_t mode, php_ioutil_open_opts *opts); +PW32IO int php_win32_ioutil_mkdir(const char *path, mode_t mode); +PW32IO size_t php_win32_ioutil_dirname(char *buf, size_t len); + +PW32IO int php_win32_ioutil_open_w(const wchar_t *path, int flags, ...); +PW32IO int php_win32_ioutil_chdir_w(const wchar_t *path); +PW32IO int php_win32_ioutil_rename_w(const wchar_t *oldname, const wchar_t *newname); +PW32IO wchar_t *php_win32_ioutil_getcwd_w(const wchar_t *buf, int len); + +#if 0 +PW32IO int php_win32_ioutil_mkdir_w(const wchar_t *path, mode_t mode); +PW32IO int php_win32_ioutil_access_w(const wchar_t *path, mode_t mode); +#endif + +#define php_win32_ioutil_access_cond(path, mode) _waccess(pathw, mode) +#define php_win32_ioutil_unlink_cond(path) php_win32_ioutil_unlink_w(pathw) +#define php_win32_ioutil_rmdir_cond(path) php_win32_ioutil_rmdir_w(pathw) + +__forceinline static int php_win32_ioutil_access(const char *path, mode_t mode) +{/*{{{*/ + PHP_WIN32_IOUTIL_INIT_W(path) + int ret, err; + + if (!pathw) { + SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER); + return -1; + } + + PHP_WIN32_IOUTIL_CHECK_PATH_W(pathw, -1) + + ret = _waccess(pathw, mode); + _get_errno(&err); + PHP_WIN32_IOUTIL_CLEANUP_W() + + if (0 > ret) { + _set_errno(err); + } + + return ret; +}/*}}}*/ + +__forceinline static int php_win32_ioutil_open(const char *path, int flags, ...) +{/*{{{*/ + mode_t mode = 0; + PHP_WIN32_IOUTIL_INIT_W(path) + int ret = -1; + DWORD err; + + if (!pathw) { + SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER); + return -1; + } + + PHP_WIN32_IOUTIL_CHECK_PATH_W(pathw, -1) + + if (flags & O_CREAT) { + va_list arg; + + va_start(arg, flags); + mode = (mode_t) va_arg(arg, int); + va_end(arg); + } + + ret = php_win32_ioutil_open_w(pathw, flags, mode); + err = GetLastError(); + PHP_WIN32_IOUTIL_CLEANUP_W() + + if (0 > ret) { + SET_ERRNO_FROM_WIN32_CODE(err); + } + + return ret; +}/*}}}*/ + +__forceinline static int php_win32_ioutil_unlink(const char *path) +{/*{{{*/ + PHP_WIN32_IOUTIL_INIT_W(path) + int ret = 0; + DWORD err = 0; + + if (!pathw) { + SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER); + return -1; + } + + PHP_WIN32_IOUTIL_CHECK_PATH_W(pathw, -1) + + if (!DeleteFileW(pathw)) { + err = GetLastError(); + ret = -1; + } + PHP_WIN32_IOUTIL_CLEANUP_W() + + if (0 > ret) { + SET_ERRNO_FROM_WIN32_CODE(err); + } + + return ret; +}/*}}}*/ + +__forceinline static int php_win32_ioutil_rmdir(const char *path) +{/*{{{*/ + PHP_WIN32_IOUTIL_INIT_W(path) + int ret = 0; + DWORD err = 0; + + if (!pathw) { + SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER); + return -1; + } + + PHP_WIN32_IOUTIL_CHECK_PATH_W(pathw, -1) + + if (!RemoveDirectoryW(pathw)) { + err = GetLastError(); + ret = -1; + } + + PHP_WIN32_IOUTIL_CLEANUP_W() + + if (0 > ret) { + SET_ERRNO_FROM_WIN32_CODE(err); + } + + return ret; +}/*}}}*/ + +/* This needs to be improved once long path support is implemented. Use ioutil_open() and then +fdopen() might be the way, if we learn how to convert the mode options (maybe grab the routine + from the streams). That will allow to split for _a and _w. */ +__forceinline static FILE *php_win32_ioutil_fopen(const char *patha, const char *modea) +{/*{{{*/ + FILE *ret; + wchar_t *pathw = php_win32_ioutil_any_to_w(patha); + wchar_t *modew = php_win32_ioutil_ascii_to_w(modea); + int err = 0; + + if (!pathw || !modew) { + free(pathw); + free(modew); + SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER); + return NULL; + } + + PHP_WIN32_IOUTIL_CHECK_PATH_W(pathw, NULL) + + ret = _wfopen(pathw, modew); + _get_errno(&err); + free(pathw); + free(modew); + + if (0 > ret) { + _set_errno(err); + } + return ret; +}/*}}}*/ + +__forceinline static int php_win32_ioutil_rename(const char *oldnamea, const char *newnamea) +{/*{{{*/ + wchar_t *oldnamew = php_win32_ioutil_any_to_w(oldnamea); + wchar_t *newnamew = php_win32_ioutil_any_to_w(newnamea); + int ret; + DWORD err = 0; + + if (!oldnamew || !newnamew) { + free(oldnamew); + free(newnamew); + SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER); + return -1; + } + + PHP_WIN32_IOUTIL_CHECK_PATH_W(oldnamew, -1) + PHP_WIN32_IOUTIL_CHECK_PATH_W(newnamew, -1) + + ret = php_win32_ioutil_rename_w(oldnamew, newnamew); + err = GetLastError(); + + free(oldnamew); + free(newnamew); + + if (0 > ret) { + SET_ERRNO_FROM_WIN32_CODE(err); + } + + return ret; +}/*}}}*/ + +__forceinline static int php_win32_ioutil_chdir(const char *patha) +{/*{{{*/ + int ret; + wchar_t *pathw = php_win32_ioutil_any_to_w(patha); + DWORD err = 0; + + if (!pathw) { + SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER); + return -1; + } + + ret = php_win32_ioutil_chdir_w(pathw); + err = GetLastError(); + + free(pathw); + + if (0 > ret) { + SET_ERRNO_FROM_WIN32_CODE(err); + } + + return ret; +}/*}}}*/ + +__forceinline static char *php_win32_ioutil_getcwd(char *buf, int len) +{/*{{{*/ + wchar_t tmp_bufw[PHP_WIN32_IOUTIL_MAXPATHLEN]; + char *tmp_bufa = NULL; + size_t tmp_bufa_len; + DWORD err = 0; + + if (php_win32_ioutil_getcwd_w(tmp_bufw, PHP_WIN32_IOUTIL_MAXPATHLEN) == NULL) { + err = GetLastError(); + SET_ERRNO_FROM_WIN32_CODE(err); + return NULL; + } + + tmp_bufa = php_win32_cp_conv_w_to_any(tmp_bufw, wcslen(tmp_bufw), &tmp_bufa_len); + if (!tmp_bufa) { + err = GetLastError(); + SET_ERRNO_FROM_WIN32_CODE(err); + return NULL; + } else if (tmp_bufa_len + 1 > PHP_WIN32_IOUTIL_MAXPATHLEN) { + free(tmp_bufa); + SET_ERRNO_FROM_WIN32_CODE(ERROR_BAD_LENGTH); + return NULL; + } + + if (!buf) { + /* If buf was NULL, the result has to be freed outside here. */ + buf = tmp_bufa; + } else { + if (tmp_bufa_len + 1 > len) { + free(tmp_bufa); + SET_ERRNO_FROM_WIN32_CODE(ERROR_INSUFFICIENT_BUFFER); + return NULL; + } + memmove(buf, tmp_bufa, tmp_bufa_len + 1); + free(tmp_bufa); + } + + return buf; +}/*}}}*/ + +/* TODO improve with usage of native APIs, split for _a and _w. */ +__forceinline static int php_win32_ioutil_chmod(const char *patha, int mode) +{/*{{{*/ + wchar_t *pathw = php_win32_ioutil_any_to_w(patha); + int err = 0; + int ret; + + if (!pathw) { + SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER); + return -1; + } + + PHP_WIN32_IOUTIL_CHECK_PATH_W(pathw, -1) + + ret = _wchmod(pathw, mode); + _get_errno(&err); + + free(pathw); + + if (0 > ret) { + _set_errno(err); + } + + return ret; +}/*}}}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* PHP_WIN32_IOUTIL_H */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: sw=4 ts=4 fdm=marker + * vim<600: sw=4 ts=4 + */ diff --git a/win32/ipc.h b/win32/ipc.h new file mode 100644 index 0000000000..cafcf4f85e --- /dev/null +++ b/win32/ipc.h @@ -0,0 +1,29 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 7 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2016 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Anatol Belski <ab@php.net> | + +----------------------------------------------------------------------+ + */ + +#ifndef PHP_WIN32_IPC_H +#define PHP_WIN32_IPC_H 1 + +#include "php.h" + +typedef int key_t; + +PHPAPI key_t ftok(const char *path, int id); + + +#endif /* PHP_WIN32_IPC_H */ diff --git a/win32/param.h b/win32/param.h index 3d0da1e8d3..f312b03b18 100644 --- a/win32/param.h +++ b/win32/param.h @@ -9,7 +9,8 @@ * * *****************************************************************************/ #ifndef MAXPATHLEN -#define MAXPATHLEN _MAX_PATH +#include "win32/ioutil.h" +#define MAXPATHLEN PHP_WIN32_IOUTIL_MAXPATHLEN #endif #define MAXHOSTNAMELEN 64 #define howmany(x,y) (((x)+((y)-1))/(y)) diff --git a/win32/readdir.c b/win32/readdir.c index fc2c4357ff..35afea429b 100644 --- a/win32/readdir.c +++ b/win32/readdir.c @@ -4,7 +4,8 @@ #include "php.h" #include "readdir.h" -#include "TSRM.h" +#include "win32/ioutil.h" + /********************************************************************** * Implement dirent-style opendir/readdir/rewinddir/closedir on Win32 * @@ -19,70 +20,104 @@ * The DIR typedef is not compatible with Unix. **********************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif + +/* typedef DIR - not the same as Unix */ +struct DIR_W32 { + HANDLE handle; /* _findfirst/_findnext handle */ + int offset; /* offset into directory */ + short finished; /* 1 if there are not more files */ + WIN32_FIND_DATAW fileinfo; /* from _findfirst/_findnext */ + wchar_t *dirw; /* the dir we are reading */ + struct dirent dent; /* the dirent to return */ +}; + DIR *opendir(const char *dir) { DIR *dp; - char *filespec; + wchar_t *filespecw, *resolvedw; HANDLE handle; int index; char resolved_path_buff[MAXPATHLEN]; + size_t resolvedw_len, filespecw_len; if (!VCWD_REALPATH(dir, resolved_path_buff)) { return NULL; } - filespec = (char *)malloc(strlen(resolved_path_buff) + 2 + 1); - if (filespec == NULL) { + dp = (DIR *) malloc(sizeof(DIR)); + if (dp == NULL) { return NULL; } - strcpy(filespec, resolved_path_buff); - index = (int)strlen(filespec) - 1; - if (index >= 0 && (filespec[index] == '/' || - (filespec[index] == '\\' && (index == 0 || !IsDBCSLeadByte(filespec[index-1]))))) - filespec[index] = '\0'; - strcat(filespec, "\\*"); - dp = (DIR *) malloc(sizeof(DIR)); - if (dp == NULL) { - free(filespec); + resolvedw = php_win32_ioutil_conv_any_to_w(resolved_path_buff, PHP_WIN32_CP_IGNORE_LEN, &resolvedw_len); + if (!resolvedw) { + return NULL; + } + + filespecw_len = resolvedw_len + 2; + filespecw = (wchar_t *)malloc((filespecw_len + 1)*sizeof(wchar_t)); + if (filespecw == NULL) { + free(resolvedw); return NULL; } - dp->offset = 0; - dp->finished = 0; - if ((handle = FindFirstFile(filespec, &(dp->fileinfo))) == INVALID_HANDLE_VALUE) { + wcscpy(filespecw, resolvedw); + index = (int)filespecw_len - 1; + if (index >= 0 && filespecw[index] == L'/' || index == 0 && filespecw[index] == L'\\') + filespecw[index] = L'\0'; + wcscat(filespecw, L"\\*"); + + if ((handle = FindFirstFileW(filespecw, &(dp->fileinfo))) == INVALID_HANDLE_VALUE) { DWORD err = GetLastError(); if (err == ERROR_NO_MORE_FILES || err == ERROR_FILE_NOT_FOUND) { dp->finished = 1; } else { free(dp); - free(filespec); + free(filespecw); + free(resolvedw); return NULL; } } - dp->dir = strdup(resolved_path_buff); + dp->dirw = _wcsdup(resolvedw); dp->handle = handle; - free(filespec); + dp->offset = 0; + dp->finished = 0; + + free(filespecw); + free(resolvedw); return dp; } struct dirent *readdir(DIR *dp) { + char *_tmp; + if (!dp || dp->finished) return NULL; if (dp->offset != 0) { - if (FindNextFile(dp->handle, &(dp->fileinfo)) == 0) { + if (FindNextFileW(dp->handle, &(dp->fileinfo)) == 0) { dp->finished = 1; return NULL; } } + + _tmp = php_win32_ioutil_w_to_any(dp->fileinfo.cFileName); + if (!_tmp) { + /* wide to utf8 failed, should never happen. */ + return NULL; + } + strlcpy(dp->dent.d_name, _tmp, _MAX_FNAME+1); + dp->dent.d_reclen = (unsigned short)strlen(dp->dent.d_name); + free(_tmp); + dp->offset++; - strlcpy(dp->dent.d_name, dp->fileinfo.cFileName, _MAX_FNAME+1); dp->dent.d_ino = 1; - dp->dent.d_reclen = (unsigned short)strlen(dp->dent.d_name); dp->dent.d_off = dp->offset; return &(dp->dent); @@ -90,23 +125,34 @@ struct dirent *readdir(DIR *dp) int readdir_r(DIR *dp, struct dirent *entry, struct dirent **result) { + char *_tmp; + if (!dp || dp->finished) { *result = NULL; return 0; } if (dp->offset != 0) { - if (FindNextFile(dp->handle, &(dp->fileinfo)) == 0) { + if (FindNextFileW(dp->handle, &(dp->fileinfo)) == 0) { dp->finished = 1; *result = NULL; return 0; } } + + _tmp = php_win32_ioutil_w_to_any(dp->fileinfo.cFileName); + if (!_tmp) { + /* wide to utf8 failed, should never happen. */ + result = NULL; + return 0; + } + strlcpy(dp->dent.d_name, _tmp, _MAX_FNAME+1); + dp->dent.d_reclen = (unsigned short)strlen(dp->dent.d_name); + free(_tmp); + dp->offset++; - strlcpy(dp->dent.d_name, dp->fileinfo.cFileName, _MAX_FNAME+1); dp->dent.d_ino = 1; - dp->dent.d_reclen = (unsigned short)strlen(dp->dent.d_name); dp->dent.d_off = dp->offset; memcpy(entry, &dp->dent, sizeof(*entry)); @@ -125,8 +171,8 @@ int closedir(DIR *dp) if (dp->handle != INVALID_HANDLE_VALUE) { FindClose(dp->handle); } - if (dp->dir) - free(dp->dir); + if (dp->dirw) + free(dp->dirw); if (dp) free(dp); @@ -136,7 +182,7 @@ int closedir(DIR *dp) int rewinddir(DIR *dp) { /* Re-set to the beginning */ - char *filespec; + wchar_t *filespecw; HANDLE handle; int index; @@ -145,28 +191,32 @@ int rewinddir(DIR *dp) dp->offset = 0; dp->finished = 0; - filespec = (char *)malloc(strlen(dp->dir) + 2 + 1); - if (filespec == NULL) { + filespecw = (wchar_t *)malloc((wcslen((wchar_t *)dp->dirw) + 2 + 1)*sizeof(wchar_t)); + if (filespecw == NULL) { return -1; } - strcpy(filespec, dp->dir); - index = (int)strlen(filespec) - 1; - if (index >= 0 && (filespec[index] == '/' || - (filespec[index] == '\\' && (index == 0 || !IsDBCSLeadByte(filespec[index-1]))))) - filespec[index] = '\0'; - strcat(filespec, "/*"); + wcscpy(filespecw, (wchar_t *)dp->dirw); + index = (int)wcslen(filespecw) - 1; + if (index >= 0 && (filespecw[index] == L'/' || + (filespecw[index] == L'\\' && index == 0))) + filespecw[index] = L'\0'; + wcscat(filespecw, L"/*"); - if ((handle = FindFirstFile(filespec, &(dp->fileinfo))) == INVALID_HANDLE_VALUE) { + if ((handle = FindFirstFileW(filespecw, &(dp->fileinfo))) == INVALID_HANDLE_VALUE) { dp->finished = 1; } + free(filespecw); dp->handle = handle; - free(filespec); return 0; } +#ifdef __cplusplus +} +#endif + /* * Local variables: * tab-width: 4 diff --git a/win32/readdir.h b/win32/readdir.h index d9ae477af0..4158ffc84a 100644 --- a/win32/readdir.h +++ b/win32/readdir.h @@ -2,6 +2,10 @@ #define READDIR_H +#ifdef __cplusplus +extern "C" { +#endif + /* * Structures and types used to implement opendir/readdir/closedir * on Windows 95/NT. @@ -9,18 +13,12 @@ #include <config.w32.h> -#include <windows.h> - -#include <io.h> -#include <stdio.h> #include <stdlib.h> #include <sys/types.h> -#include <direct.h> #define php_readdir_r readdir_r /* struct dirent - same as Unix */ - struct dirent { long d_ino; /* inode (always 1 in WIN32) */ off_t d_off; /* offset to this dirent */ @@ -28,16 +26,8 @@ struct dirent { char d_name[_MAX_FNAME + 1]; /* filename (null terminated) */ }; - /* typedef DIR - not the same as Unix */ -typedef struct { - HANDLE handle; /* _findfirst/_findnext handle */ - int offset; /* offset into directory */ - short finished; /* 1 if there are not more files */ - WIN32_FIND_DATA fileinfo; /* from _findfirst/_findnext */ - char *dir; /* the dir we are reading */ - struct dirent dent; /* the dirent to return */ -} DIR; +typedef struct DIR_W32 DIR; /* Function prototypes */ DIR *opendir(const char *); @@ -46,4 +36,8 @@ int readdir_r(DIR *, struct dirent *, struct dirent **); int closedir(DIR *); int rewinddir(DIR *); +#ifdef __cplusplus +} +#endif + #endif /* READDIR_H */ diff --git a/win32/winutil.c b/win32/winutil.c index e59e049775..cd009cadc0 100644 --- a/win32/winutil.c +++ b/win32/winutil.c @@ -20,9 +20,11 @@ /* $Id$ */ #include "php.h" +#include "winutil.h" #include <wincrypt.h> +#include <lmcons.h> -PHPAPI char *php_win32_error_to_msg(HRESULT error) +PHP_WINUTIL_API char *php_win32_error_to_msg(HRESULT error) { char *buf = NULL; @@ -77,7 +79,7 @@ void php_win32_free_rng_lock() -PHPAPI int php_win32_get_random_bytes(unsigned char *buf, size_t size) { /* {{{ */ +PHP_WINUTIL_API int php_win32_get_random_bytes(unsigned char *buf, size_t size) { /* {{{ */ BOOL ret; @@ -123,6 +125,319 @@ PHPAPI int php_win32_get_random_bytes(unsigned char *buf, size_t size) { /* {{{ } /* }}} */ + +/* +* This functions based on the code from the UNIXem project under +* the BSD like license. Modified for PHP by ab@php.net +* +* Home: http://synesis.com.au/software/ +* +* Copyright (c) 2005-2010, Matthew Wilson and Synesis Software +*/ + +PHP_WINUTIL_API int php_win32_code_to_errno(unsigned long w32Err) +{ + size_t i; + + struct code_to_errno_map + { + unsigned long w32Err; + int eerrno; + }; + + static const struct code_to_errno_map errmap[] = + { + /* 1 */ { ERROR_INVALID_FUNCTION , EINVAL } + /* 2 */ , { ERROR_FILE_NOT_FOUND , ENOENT } + /* 3 */ , { ERROR_PATH_NOT_FOUND , ENOENT } + /* 4 */ , { ERROR_TOO_MANY_OPEN_FILES , EMFILE } + /* 5 */ , { ERROR_ACCESS_DENIED , EACCES } + /* 6 */ , { ERROR_INVALID_HANDLE , EBADF } + /* 7 */ , { ERROR_ARENA_TRASHED , ENOMEM } + /* 8 */ , { ERROR_NOT_ENOUGH_MEMORY , ENOMEM } + /* 9 */ , { ERROR_INVALID_BLOCK , ENOMEM } + /* 10 */ , { ERROR_BAD_ENVIRONMENT , E2BIG } + /* 11 */ , { ERROR_BAD_FORMAT , ENOEXEC } + /* 12 */ , { ERROR_INVALID_ACCESS , EINVAL } + /* 13 */ , { ERROR_INVALID_DATA , EINVAL } + /* 14 */ , { ERROR_OUTOFMEMORY , ENOMEM } + /* 15 */ , { ERROR_INVALID_DRIVE , ENOENT } + /* 16 */ , { ERROR_CURRENT_DIRECTORY , ECURDIR } + /* 17 */ , { ERROR_NOT_SAME_DEVICE , EXDEV } + /* 18 */ , { ERROR_NO_MORE_FILES , ENOENT } + /* 19 */ , { ERROR_WRITE_PROTECT , EROFS } + /* 20 */ , { ERROR_BAD_UNIT , ENXIO } + /* 21 */ , { ERROR_NOT_READY , EBUSY } + /* 22 */ , { ERROR_BAD_COMMAND , EIO } + /* 23 */ , { ERROR_CRC , EIO } + /* 24 */ , { ERROR_BAD_LENGTH , EIO } + /* 25 */ , { ERROR_SEEK , EIO } + /* 26 */ , { ERROR_NOT_DOS_DISK , EIO } + /* 27 */ , { ERROR_SECTOR_NOT_FOUND , ENXIO } + /* 28 */ , { ERROR_OUT_OF_PAPER , EBUSY } + /* 29 */ , { ERROR_WRITE_FAULT , EIO } + /* 30 */ , { ERROR_READ_FAULT , EIO } + /* 31 */ , { ERROR_GEN_FAILURE , EIO } + /* 32 */ , { ERROR_SHARING_VIOLATION , EAGAIN } + /* 33 */ , { ERROR_LOCK_VIOLATION , EACCES } + /* 34 */ , { ERROR_WRONG_DISK , ENXIO } + /* 35 */ , { 35 , ENFILE } + /* 36 */ , { ERROR_SHARING_BUFFER_EXCEEDED , ENFILE } + /* 37 */ , { ERROR_HANDLE_EOF , EINVAL } + /* 38 */ , { ERROR_HANDLE_DISK_FULL , ENOSPC } +#if 0 + /* 39 */ , { 0 , 0 } + /* 40 */ , { 0 , 0 } + /* 41 */ , { 0 , 0 } + /* 42 */ , { 0 , 0 } + /* 43 */ , { 0 , 0 } + /* 44 */ , { 0 , 0 } + /* 45 */ , { 0 , 0 } + /* 46 */ , { 0 , 0 } + /* 47 */ , { 0 , 0 } + /* 48 */ , { 0 , 0 } + /* 49 */ , { 0 , 0 } +#endif + /* 50 */ , { ERROR_NOT_SUPPORTED , ENOSYS } +#if 0 + /* 51 */ , { 0 , 0 } + /* 52 */ , { 0 , 0 } +#endif + /* 53 */ , { ERROR_BAD_NETPATH , ENOENT } +#if 0 + /* 54 */ , { 0 , 0 } + /* 55 */ , { 0 , 0 } + /* 56 */ , { 0 , 0 } + /* 57 */ , { 0 , 0 } + /* 58 */ , { 0 , 0 } + /* 59 */ , { 0 , 0 } + /* 60 */ , { 0 , 0 } + /* 61 */ , { 0 , 0 } + /* 62 */ , { 0 , 0 } + /* 63 */ , { 0 , 0 } + /* 64 */ , { 0 , 0 } +#endif + /* 65 */ , { ERROR_NETWORK_ACCESS_DENIED , EACCES } +#if 0 + /* 66 */ , { 0 , 0 } +#endif + /* 67 */ , { ERROR_BAD_NET_NAME , ENOENT } +#if 0 + /* 68 */ , { 0 , 0 } + /* 69 */ , { 0 , 0 } + /* 70 */ , { 0 , 0 } + /* 71 */ , { 0 , 0 } + /* 72 */ , { 0 , 0 } + /* 73 */ , { 0 , 0 } + /* 74 */ , { 0 , 0 } + /* 75 */ , { 0 , 0 } + /* 76 */ , { 0 , 0 } + /* 77 */ , { 0 , 0 } + /* 78 */ , { 0 , 0 } + /* 79 */ , { 0 , 0 } +#endif + /* 80 */ , { ERROR_FILE_EXISTS , EEXIST } +#if 0 + /* 81 */ , { 0 , 0 } +#endif + /* 82 */ , { ERROR_CANNOT_MAKE , EACCES } + /* 83 */ , { ERROR_FAIL_I24 , EACCES } +#if 0 + /* 84 */ , { 0 , 0 } + /* 85 */ , { 0 , 0 } + /* 86 */ , { 0 , 0 } +#endif + /* 87 */ , { ERROR_INVALID_PARAMETER , EINVAL } +#if 0 + /* 88 */ , { 0 , 0 } +#endif + /* 89 */ , { ERROR_NO_PROC_SLOTS , EAGAIN } +#if 0 + /* 90 */ , { 0 , 0 } + /* 91 */ , { 0 , 0 } + /* 92 */ , { 0 , 0 } + /* 93 */ , { 0 , 0 } + /* 94 */ , { 0 , 0 } + /* 95 */ , { 0 , 0 } + /* 96 */ , { 0 , 0 } + /* 97 */ , { 0 , 0 } + /* 98 */ , { 0 , 0 } + /* 99 */ , { 0 , 0 } + /* 100 */ , { 0 , 0 } + /* 101 */ , { 0 , 0 } + /* 102 */ , { 0 , 0 } + /* 103 */ , { 0 , 0 } + /* 104 */ , { 0 , 0 } + /* 105 */ , { 0 , 0 } + /* 106 */ , { 0 , 0 } + /* 107 */ , { 0 , 0 } +#endif + /* 108 */ , { ERROR_DRIVE_LOCKED , EACCES } + /* 109 */ , { ERROR_BROKEN_PIPE , EPIPE } +#if 0 + /* 110 */ , { 0 , 0 } +#endif + /* 111 */ , { ERROR_BUFFER_OVERFLOW , ENAMETOOLONG } + /* 112 */ , { ERROR_DISK_FULL , ENOSPC } +#if 0 + /* 113 */ , { 0 , 0 } +#endif + /* 114 */ , { ERROR_INVALID_TARGET_HANDLE , EBADF } +#if 0 + /* 115 */ , { 0 , 0 } + /* 116 */ , { 0 , 0 } + /* 117 */ , { 0 , 0 } + /* 118 */ , { 0 , 0 } + /* 119 */ , { 0 , 0 } + /* 120 */ , { 0 , 0 } + /* 121 */ , { 0 , 0 } +#endif + /* 122 */ , { ERROR_INSUFFICIENT_BUFFER , ERANGE } + /* 123 */ , { ERROR_INVALID_NAME , ENOENT } + /* 124 */ , { ERROR_INVALID_HANDLE , EINVAL } +#if 0 + /* 125 */ , { 0 , 0 } + /* 126 */ , { 0 , 0 } + /* 127 */ , { 0 , 0 } +#endif + /* 128 */ , { ERROR_WAIT_NO_CHILDREN , ECHILD } + /* 129 */ , { ERROR_CHILD_NOT_COMPLETE , ECHILD } + /* 130 */ , { ERROR_DIRECT_ACCESS_HANDLE , EBADF } + /* 131 */ , { ERROR_NEGATIVE_SEEK , EINVAL } + /* 132 */ , { ERROR_SEEK_ON_DEVICE , EACCES } +#if 0 + /* 133 */ , { 0 , 0 } + /* 134 */ , { 0 , 0 } + /* 135 */ , { 0 , 0 } + /* 136 */ , { 0 , 0 } + /* 137 */ , { 0 , 0 } + /* 138 */ , { 0 , 0 } + /* 139 */ , { 0 , 0 } + /* 140 */ , { 0 , 0 } + /* 141 */ , { 0 , 0 } + /* 142 */ , { 0 , 0 } + /* 143 */ , { 0 , 0 } + /* 144 */ , { 0 , 0 } +#endif + /* 145 */ , { ERROR_DIR_NOT_EMPTY , ENOTEMPTY } +#if 0 + /* 146 */ , { 0 , 0 } + /* 147 */ , { 0 , 0 } + /* 148 */ , { 0 , 0 } + /* 149 */ , { 0 , 0 } + /* 150 */ , { 0 , 0 } + /* 151 */ , { 0 , 0 } + /* 152 */ , { 0 , 0 } + /* 153 */ , { 0 , 0 } + /* 154 */ , { 0 , 0 } + /* 155 */ , { 0 , 0 } + /* 156 */ , { 0 , 0 } + /* 157 */ , { 0 , 0 } +#endif + /* 158 */ , { ERROR_NOT_LOCKED , EACCES } +#if 0 + /* 159 */ , { 0 , 0 } + /* 160 */ , { 0 , 0 } +#endif + /* 161 */ , { ERROR_BAD_PATHNAME , ENOENT } +#if 0 + /* 162 */ , { 0 , 0 } + /* 163 */ , { 0 , 0 } +#endif + /* 164 */ , { ERROR_MAX_THRDS_REACHED , EAGAIN } +#if 0 + /* 165 */ , { 0 , 0 } + /* 166 */ , { 0 , 0 } +#endif + /* 167 */ , { ERROR_LOCK_FAILED , EACCES } +#if 0 + /* 168 */ , { 0 , 0 } + /* 169 */ , { 0 , 0 } + /* 170 */ , { 0 , 0 } + /* 171 */ , { 0 , 0 } + /* 172 */ , { 0 , 0 } + /* 173 */ , { 0 , 0 } + /* 174 */ , { 0 , 0 } + /* 175 */ , { 0 , 0 } + /* 176 */ , { 0 , 0 } + /* 177 */ , { 0 , 0 } + /* 178 */ , { 0 , 0 } + /* 179 */ , { 0 , 0 } + /* 180 */ , { 0 , 0 } + /* 181 */ , { 0 , 0 } + /* 182 */ , { 0 , 0 } +#endif + /* 183 */ , { ERROR_ALREADY_EXISTS , EEXIST } +#if 0 + /* 184 */ , { 0 , 0 } + /* 185 */ , { 0 , 0 } + /* 186 */ , { 0 , 0 } + /* 187 */ , { 0 , 0 } + /* 188 */ , { 0 , 0 } + /* 189 */ , { 0 , 0 } + /* 190 */ , { 0 , 0 } + /* 191 */ , { 0 , 0 } + /* 192 */ , { 0 , 0 } + /* 193 */ , { 0 , 0 } + /* 194 */ , { 0 , 0 } + /* 195 */ , { 0 , 0 } + /* 196 */ , { 0 , 0 } + /* 197 */ , { 0 , 0 } + /* 198 */ , { 0 , 0 } + /* 199 */ , { 0 , 0 } +#endif + + /* 206 */ , { ERROR_FILENAME_EXCED_RANGE , ENAMETOOLONG } + + /* 215 */ , { ERROR_NESTING_NOT_ALLOWED , EAGAIN } + /* 258 */ , { WAIT_TIMEOUT, ETIME} + + /* 267 */ , { ERROR_DIRECTORY , ENOTDIR } + + /* 996 */ , { ERROR_IO_INCOMPLETE , EAGAIN } + /* 997 */ , { ERROR_IO_PENDING , EAGAIN } + + /* 1004 */ , { ERROR_INVALID_FLAGS , EINVAL } + /* 1113 */ , { ERROR_NO_UNICODE_TRANSLATION , EINVAL } + /* 1168 */ , { ERROR_NOT_FOUND , ENOENT } + /* 1816 */ , { ERROR_NOT_ENOUGH_QUOTA , ENOMEM } + , { ERROR_ABANDONED_WAIT_0 , EIO } + }; + + for(i = 0; i < sizeof(errmap)/sizeof(struct code_to_errno_map); ++i) + { + if(w32Err == errmap[i].w32Err) + { + return errmap[i].eerrno; + } + } + + assert(!"Unrecognised value"); + + return EINVAL; +} + +PHP_WINUTIL_API char *php_win32_get_username(void) +{ + wchar_t unamew[UNLEN + 1]; + size_t uname_len; + char *uname; + DWORD unsize = UNLEN; + + GetUserNameW(unamew, &unsize); + uname = php_win32_cp_conv_w_to_any(unamew, unsize - 1, &uname_len); + if (!uname) { + return NULL; + } + + /* Ensure the length doesn't overflow. */ + if (uname_len > UNLEN) { + uname[uname_len] = '\0'; + } + + return uname; +} + /* * Local variables: * tab-width: 4 diff --git a/win32/winutil.h b/win32/winutil.h index bdb0f8702b..2edccaab4f 100644 --- a/win32/winutil.h +++ b/win32/winutil.h @@ -16,11 +16,17 @@ +----------------------------------------------------------------------+ */ -PHPAPI char *php_win32_error_to_msg(HRESULT error); +#ifdef PHP_EXPORTS +# define PHP_WINUTIL_API __declspec(dllexport) +#else +# define PHP_WINUTIL_API __declspec(dllimport) +#endif + +PHP_WINUTIL_API char *php_win32_error_to_msg(HRESULT error); #define php_win_err() php_win32_error_to_msg(GetLastError()) int php_win32_check_trailing_space(const char * path, const int path_len); -PHPAPI int php_win32_get_random_bytes(unsigned char *buf, size_t size); +PHP_WINUTIL_API int php_win32_get_random_bytes(unsigned char *buf, size_t size); #ifdef ZTS void php_win32_init_rng_lock(); @@ -29,3 +35,22 @@ void php_win32_free_rng_lock(); #define php_win32_init_rng_lock(); #define php_win32_free_rng_lock(); #endif + +#if !defined(ECURDIR) +# define ECURDIR EACCES +#endif /* !ECURDIR */ +#if !defined(ENOSYS) +# define ENOSYS EPERM +#endif /* !ENOSYS */ + +PHP_WINUTIL_API int php_win32_code_to_errno(unsigned long w32Err); + +#define SET_ERRNO_FROM_WIN32_CODE(err) \ + do { \ + int ern = php_win32_code_to_errno(err); \ + SetLastError(err); \ + _set_errno(ern); \ + } while (0) + +PHP_WINUTIL_API char *php_win32_get_username(void); + |