diff --git a/docs/src/misc.rst b/docs/src/misc.rst index 8c3a00e9..98961830 100644 --- a/docs/src/misc.rst +++ b/docs/src/misc.rst @@ -839,3 +839,50 @@ API Causes the calling thread to sleep for `msec` milliseconds. .. versionadded:: 1.34.0 + +String manipulation functions +----------------------------- + +These string utilities are needed internally for dealing with Windows, and are +exported to allow clients to work uniformly with this data when the libuv API +is not complete. + +.. c:function:: size_t uv_utf16_length_as_wtf8(const uint16_t* utf16, ssize_t utf16_len) + + Get the length of a UTF-16 (or UCS-2) `utf16` value after converting it to + WTF-8. If `utf16` is NUL terminated, `utf16_len` can be set to -1, + otherwise it must be specified. + + .. versionadded:: 1.47.0 + +.. c:function:: int uv_utf16_to_wtf8(const uint16_t* utf16, ssize_t utf16_len, char** wtf8_ptr, size_t* wtf8_len_ptr) + + Convert UTF-16 (or UCS-2) data in `utf16` to WTF-8 data in `*wtf8_ptr`. The + `utf16_len` count (in characters) gives the length of `utf16`. If `utf16` + is NUL terminated, `utf16_len` can be set to -1, otherwise it must be + specified. If `wtf8_ptr` is `NULL`, no result will be computed, but the + length (equal to `uv_utf16_length_as_wtf8`) will be stored in `wtf8_ptr`. + If `*wtf8_ptr` is `NULL`, space for the conversion will be allocated and + returned in `wtf8_ptr` and the length will be returned in `wtf8_len_ptr`. + Otherwise, the length of `*wtf8_ptr` must be passed in `wtf8_len_ptr`. The + `wtf8_ptr` must contain an extra space for an extra NUL after the result. + If the result is truncated, `UV_ENOBUFS` will be returned and + `wtf8_len_ptr` will be the length of the required `wtf8_ptr` to contain the + whole result. + + .. versionadded:: 1.47.0 + +.. c:function:: ssize_t uv_wtf8_length_as_utf16(const char* wtf8) + + Get the length in characters of a NUL-terminated WTF-8 `wtf8` value + after converting it to UTF-16 (or UCS-2), including NUL terminator. + + .. versionadded:: 1.47.0 + +.. c:function:: void uv_wtf8_to_utf16(const char* utf8, uint16_t* utf16, size_t utf16_len) + + Convert NUL-terminated WTF-8 data in `wtf8` to UTF-16 (or UCS-2) data + in `utf16`. The `utf16_len` count (in characters) must include space + for the NUL terminator. + + .. versionadded:: 1.47.0 diff --git a/include/uv.h b/include/uv.h index 02397dd0..5642101c 100644 --- a/include/uv.h +++ b/include/uv.h @@ -1885,6 +1885,18 @@ struct uv_loop_s { UV_EXTERN void* uv_loop_get_data(const uv_loop_t*); UV_EXTERN void uv_loop_set_data(uv_loop_t*, void* data); +/* String utilities needed internally for dealing with Windows. */ +size_t uv_utf16_length_as_wtf8(const uint16_t* utf16, + ssize_t utf16_len); +int uv_utf16_to_wtf8(const uint16_t* utf16, + ssize_t utf16_len, + char** wtf8_ptr, + size_t* wtf8_len_ptr); +ssize_t uv_wtf8_length_as_utf16(const char* wtf8); +void uv_wtf8_to_utf16(const char* wtf8, + uint16_t* utf16, + size_t utf16_len); + /* Don't export the private CPP symbols. */ #undef UV_HANDLE_TYPE_PRIVATE #undef UV_REQ_TYPE_PRIVATE diff --git a/src/idna.c b/src/idna.c index 93d982ca..1c0a60cf 100644 --- a/src/idna.c +++ b/src/idna.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011, 2018 Ben Noordhuis +/* Copyright libuv contributors. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -18,11 +18,56 @@ */ #include "uv.h" +#include "uv-common.h" #include "idna.h" #include #include #include /* UINT_MAX */ + +static int32_t uv__wtf8_decode1(const char** input) { + uint32_t code_point; + uint8_t b1; + uint8_t b2; + uint8_t b3; + uint8_t b4; + + b1 = **input; + if (b1 <= 0x7F) + return b1; /* ASCII code point */ + if (b1 < 0xC2) + return -1; /* invalid: continuation byte */ + code_point = b1; + + b2 = *++*input; + if ((b2 & 0xC0) != 0x80) + return -1; /* invalid: not a continuation byte */ + code_point = (code_point << 6) | (b2 & 0x3F); + if (b1 <= 0xDF) + return 0x7FF & code_point; /* two-byte character */ + + b3 = *++*input; + if ((b3 & 0xC0) != 0x80) + return -1; /* invalid: not a continuation byte */ + code_point = (code_point << 6) | (b3 & 0x3F); + if (b1 <= 0xEF) + return 0xFFFF & code_point; /* three-byte character */ + + b4 = *++*input; + if ((b4 & 0xC0) != 0x80) + return -1; /* invalid: not a continuation byte */ + code_point = (code_point << 6) | (b4 & 0x3F); + if (b1 <= 0xF4) { + code_point &= 0x1FFFFF; + if (code_point <= 0x10FFFF) + return code_point; /* four-byte character */ + } + + /* code point too large */ + return -1; +} + + static unsigned uv__utf8_decode1_slow(const char** p, const char* pe, unsigned a) { @@ -89,6 +134,7 @@ static unsigned uv__utf8_decode1_slow(const char** p, return a; } + unsigned uv__utf8_decode1(const char** p, const char* pe) { unsigned a; @@ -102,6 +148,7 @@ unsigned uv__utf8_decode1(const char** p, const char* pe) { return uv__utf8_decode1_slow(p, pe, a); } + static int uv__idna_toascii_label(const char* s, const char* se, char** d, char* de) { static const char alphabet[] = "abcdefghijklmnopqrstuvwxyz0123456789"; @@ -267,7 +314,8 @@ static int uv__idna_toascii_label(const char* s, const char* se, return 0; } -long uv__idna_toascii(const char* s, const char* se, char* d, char* de) { + +ssize_t uv__idna_toascii(const char* s, const char* se, char* d, char* de) { const char* si; const char* st; unsigned c; @@ -313,3 +361,195 @@ long uv__idna_toascii(const char* s, const char* se, char* d, char* de) { return d - ds; /* Number of bytes written. */ } + + +ssize_t uv_wtf8_length_as_utf16(const char* source_ptr) { + size_t w_target_len = 0; + int32_t code_point; + + do { + code_point = uv__wtf8_decode1(&source_ptr); + if (code_point < 0) + return -1; + if (code_point > 0xFFFF) + w_target_len++; + w_target_len++; + } while (*source_ptr++); + + return w_target_len; +} + + +void uv_wtf8_to_utf16(const char* source_ptr, + uint16_t* w_target, + size_t w_target_len) { + int32_t code_point; + + do { + code_point = uv__wtf8_decode1(&source_ptr); + /* uv_wtf8_length_as_utf16 should have been called and checked first. */ + assert(code_point >= 0); + if (code_point > 0x10000) { + assert(code_point < 0x10FFFF); + *w_target++ = (((code_point - 0x10000) >> 10) + 0xD800); + *w_target++ = ((code_point - 0x10000) & 0x3FF) + 0xDC00; + w_target_len -= 2; + } else { + *w_target++ = code_point; + w_target_len -= 1; + } + } while (*source_ptr++); + + assert(w_target_len == 0); +} + + +static int32_t uv__get_surrogate_value(const uint16_t* w_source_ptr, + ssize_t w_source_len) { + uint16_t u; + uint16_t next; + + u = w_source_ptr[0]; + if (u >= 0xD800 && u <= 0xDBFF && w_source_len != 1) { + next = w_source_ptr[1]; + if (next >= 0xDC00 && next <= 0xDFFF) + return 0x10000 + ((u - 0xD800) << 10) + (next - 0xDC00); + } + return u; +} + + +size_t uv_utf16_length_as_wtf8(const uint16_t* w_source_ptr, + ssize_t w_source_len) { + size_t target_len; + int32_t code_point; + + target_len = 0; + while (w_source_len) { + code_point = uv__get_surrogate_value(w_source_ptr, w_source_len); + /* Can be invalid UTF-8 but must be valid WTF-8. */ + assert(code_point >= 0); + if (w_source_len < 0 && code_point == 0) + break; + if (code_point < 0x80) + target_len += 1; + else if (code_point < 0x800) + target_len += 2; + else if (code_point < 0x10000) + target_len += 3; + else { + target_len += 4; + w_source_ptr++; + if (w_source_len > 0) + w_source_len--; + } + w_source_ptr++; + if (w_source_len > 0) + w_source_len--; + } + + return target_len; +} + + +int uv_utf16_to_wtf8(const uint16_t* w_source_ptr, + ssize_t w_source_len, + char** target_ptr, + size_t* target_len_ptr) { + size_t target_len; + char* target; + char* target_end; + int32_t code_point; + + /* If *target_ptr is provided, then *target_len_ptr must be its length + * (excluding space for NUL), otherwise we will compute the target_len_ptr + * length and may return a new allocation in *target_ptr if target_ptr is + * provided. */ + if (target_ptr == NULL || *target_ptr == NULL) { + target_len = uv_utf16_length_as_wtf8(w_source_ptr, w_source_len); + if (target_len_ptr != NULL) + *target_len_ptr = target_len; + } else { + target_len = *target_len_ptr; + } + + if (target_ptr == NULL) + return 0; + + if (*target_ptr == NULL) { + target = uv__malloc(target_len + 1); + if (target == NULL) { + return UV_ENOMEM; + } + *target_ptr = target; + } else { + target = *target_ptr; + } + + target_end = target + target_len; + + while (target != target_end && w_source_len) { + code_point = uv__get_surrogate_value(w_source_ptr, w_source_len); + /* Can be invalid UTF-8 but must be valid WTF-8. */ + assert(code_point >= 0); + if (w_source_len < 0 && code_point == 0) { + w_source_len = 0; + break; + } + if (code_point < 0x80) { + *target++ = code_point; + } else if (code_point < 0x800) { + *target++ = 0xC0 | (code_point >> 6); + if (target == target_end) + break; + *target++ = 0x80 | (code_point & 0x3F); + } else if (code_point < 0x10000) { + *target++ = 0xE0 | (code_point >> 12); + if (target == target_end) + break; + *target++ = 0x80 | ((code_point >> 6) & 0x3F); + if (target == target_end) + break; + *target++ = 0x80 | (code_point & 0x3F); + } else { + *target++ = 0xF0 | (code_point >> 18); + if (target == target_end) + break; + *target++ = 0x80 | ((code_point >> 12) & 0x3F); + if (target == target_end) + break; + *target++ = 0x80 | ((code_point >> 6) & 0x3F); + if (target == target_end) + break; + *target++ = 0x80 | (code_point & 0x3F); + /* uv__get_surrogate_value consumed 2 input characters */ + w_source_ptr++; + if (w_source_len > 0) + w_source_len--; + } + target_len = target - *target_ptr; + w_source_ptr++; + if (w_source_len > 0) + w_source_len--; + } + + if (target != target_end && target_len_ptr != NULL) + /* Did not fill all of the provided buffer, so update the target_len_ptr + * output with the space used. */ + *target_len_ptr = target - *target_ptr; + + /* Check if input fit into target exactly. */ + if (w_source_len < 0 && target == target_end && w_source_ptr[0] == 0) + w_source_len = 0; + + *target++ = '\0'; + + /* Characters remained after filling the buffer, compute the remaining length now. */ + if (w_source_len) { + if (target_len_ptr != NULL) + *target_len_ptr = target_len + uv_utf16_length_as_wtf8(w_source_ptr, w_source_len); + return UV_ENOBUFS; + } + + return 0; +} diff --git a/src/idna.h b/src/idna.h index 8e0c592f..ea6b4df9 100644 --- a/src/idna.h +++ b/src/idna.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011, 2018 Ben Noordhuis +/* Copyright libuv contributors. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -26,6 +26,6 @@ unsigned uv__utf8_decode1(const char** p, const char* pe); * is the number of bytes written to |d|, including the trailing nul byte. * A return value < 0 is a libuv error code. |s| and |d| can not overlap. */ -long uv__idna_toascii(const char* s, const char* se, char* d, char* de); +ssize_t uv__idna_toascii(const char* s, const char* se, char* d, char* de); #endif /* UV_SRC_IDNA_H_ */ diff --git a/src/win/dl.c b/src/win/dl.c index 676be4dc..7880c959 100644 --- a/src/win/dl.c +++ b/src/win/dl.c @@ -27,18 +27,17 @@ static int uv__dlerror(uv_lib_t* lib, const char* filename, DWORD errorno); int uv_dlopen(const char* filename, uv_lib_t* lib) { WCHAR filename_w[32768]; + ssize_t r; lib->handle = NULL; lib->errmsg = NULL; - if (!MultiByteToWideChar(CP_UTF8, - 0, - filename, - -1, - filename_w, - ARRAY_SIZE(filename_w))) { - return uv__dlerror(lib, filename, GetLastError()); - } + r = uv_wtf8_length_as_utf16(filename); + if (r < 0) + return uv__dlerror(lib, filename, ERROR_NO_UNICODE_TRANSLATION); + if ((size_t) r > ARRAY_SIZE(filename_w)) + return uv__dlerror(lib, filename, ERROR_INSUFFICIENT_BUFFER); + uv_wtf8_to_utf16(filename, filename_w, r); lib->handle = LoadLibraryExW(filename_w, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); if (lib->handle == NULL) { diff --git a/src/win/fs-event.c b/src/win/fs-event.c index 6758c7c7..4a0ca1f7 100644 --- a/src/win/fs-event.c +++ b/src/win/fs-event.c @@ -157,7 +157,8 @@ int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb, const char* path, unsigned int flags) { - int name_size, is_path_dir, size; + int is_path_dir; + size_t size; DWORD attr, last_error; WCHAR* dir = NULL, *dir_to_watch, *pathw = NULL; DWORD short_path_buffer_len; @@ -176,23 +177,9 @@ int uv_fs_event_start(uv_fs_event_t* handle, uv__handle_start(handle); - /* Convert name to UTF16. */ - - name_size = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0) * - sizeof(WCHAR); - pathw = (WCHAR*)uv__malloc(name_size); - if (!pathw) { - uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); - } - - if (!MultiByteToWideChar(CP_UTF8, - 0, - path, - -1, - pathw, - name_size / sizeof(WCHAR))) { - return uv_translate_sys_error(GetLastError()); - } + last_error = uv__convert_utf8_to_utf16(path, &pathw); + if (last_error) + goto error_uv; /* Determine whether path is a file or a directory. */ attr = GetFileAttributesW(pathw); @@ -333,6 +320,9 @@ short_path_done: return 0; error: + last_error = uv_translate_sys_error(last_error); + +error_uv: if (handle->path) { uv__free(handle->path); handle->path = NULL; @@ -365,7 +355,7 @@ error: uv__free(short_path); - return uv_translate_sys_error(last_error); + return last_error; } diff --git a/src/win/fs.c b/src/win/fs.c index 314a3543..99c8a2bf 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -147,281 +147,6 @@ void uv__fs_init(void) { } -static int32_t fs__decode_wtf8_char(const char** input) { - uint32_t code_point; - uint8_t b1; - uint8_t b2; - uint8_t b3; - uint8_t b4; - - b1 = **input; - if (b1 <= 0x7F) - return b1; /* ASCII code point */ - if (b1 < 0xC2) - return -1; /* invalid: continuation byte */ - code_point = b1; - - b2 = *++*input; - if ((b2 & 0xC0) != 0x80) - return -1; /* invalid: not a continuation byte */ - code_point = (code_point << 6) | (b2 & 0x3F); - if (b1 <= 0xDF) - return 0x7FF & code_point; /* two-byte character */ - - b3 = *++*input; - if ((b3 & 0xC0) != 0x80) - return -1; /* invalid: not a continuation byte */ - code_point = (code_point << 6) | (b3 & 0x3F); - if (b1 <= 0xEF) - return 0xFFFF & code_point; /* three-byte character */ - - b4 = *++*input; - if ((b4 & 0xC0) != 0x80) - return -1; /* invalid: not a continuation byte */ - code_point = (code_point << 6) | (b4 & 0x3F); - if (b1 <= 0xF4) { - code_point &= 0x1FFFFF; - if (code_point <= 0x10FFFF) - return code_point; /* four-byte character */ - } - - /* code point too large */ - return -1; -} - - -static ssize_t fs__get_length_wtf8(const char* source_ptr) { - size_t w_target_len = 0; - int32_t code_point; - - do { - code_point = fs__decode_wtf8_char(&source_ptr); - if (code_point < 0) - return -1; - if (code_point > 0xFFFF) - w_target_len++; - w_target_len++; - } while (*source_ptr++); - return w_target_len; -} - - -static void fs__wtf8_to_wide(const char* source_ptr, WCHAR* w_target) { - int32_t code_point; - - do { - code_point = fs__decode_wtf8_char(&source_ptr); - /* fs__get_length_wtf8 should have been called and checked first. */ - assert(code_point >= 0); - if (code_point > 0x10000) { - assert(code_point < 0x10FFFF); - *w_target++ = (((code_point - 0x10000) >> 10) + 0xD800); - *w_target++ = ((code_point - 0x10000) & 0x3FF) + 0xDC00; - } else { - *w_target++ = code_point; - } - } while (*source_ptr++); -} - - -INLINE static int fs__capture_path(uv_fs_t* req, const char* path, - const char* new_path, const int copy_path) { - WCHAR* buf; - WCHAR* pos; - size_t buf_sz = 0; - size_t path_len = 0; - ssize_t pathw_len = 0; - ssize_t new_pathw_len = 0; - - /* new_path can only be set if path is also set. */ - assert(new_path == NULL || path != NULL); - - if (path != NULL) { - pathw_len = fs__get_length_wtf8(path); - if (pathw_len < 0) - return ERROR_INVALID_NAME; - buf_sz += pathw_len * sizeof(WCHAR); - } - - if (path != NULL && copy_path) { - path_len = 1 + strlen(path); - buf_sz += path_len; - } - - if (new_path != NULL) { - new_pathw_len = fs__get_length_wtf8(new_path); - if (new_pathw_len < 0) - return ERROR_INVALID_NAME; - buf_sz += new_pathw_len * sizeof(WCHAR); - } - - - if (buf_sz == 0) { - req->file.pathw = NULL; - req->fs.info.new_pathw = NULL; - req->path = NULL; - return 0; - } - - buf = uv__malloc(buf_sz); - if (buf == NULL) { - return ERROR_OUTOFMEMORY; - } - - pos = buf; - - if (path != NULL) { - fs__wtf8_to_wide(path, pos); - req->file.pathw = pos; - pos += pathw_len; - } else { - req->file.pathw = NULL; - } - - if (new_path != NULL) { - fs__wtf8_to_wide(new_path, pos); - req->fs.info.new_pathw = pos; - pos += new_pathw_len; - } else { - req->fs.info.new_pathw = NULL; - } - - req->path = path; - if (path != NULL && copy_path) { - memcpy(pos, path, path_len); - assert(path_len == buf_sz - (pos - buf) * sizeof(WCHAR)); - req->path = (char*) pos; - } - - req->flags |= UV_FS_FREE_PATHS; - - return 0; -} - - - -INLINE static void uv__fs_req_init(uv_loop_t* loop, uv_fs_t* req, - uv_fs_type fs_type, const uv_fs_cb cb) { - uv__once_init(); - UV_REQ_INIT(req, UV_FS); - req->loop = loop; - req->flags = 0; - req->fs_type = fs_type; - req->sys_errno_ = 0; - req->result = 0; - req->ptr = NULL; - req->path = NULL; - req->cb = cb; - memset(&req->fs, 0, sizeof(req->fs)); -} - - -static int32_t fs__get_surrogate_value(const WCHAR* w_source_ptr, - size_t w_source_len) { - WCHAR u; - WCHAR next; - - u = w_source_ptr[0]; - if (u >= 0xD800 && u <= 0xDBFF && w_source_len > 1) { - next = w_source_ptr[1]; - if (next >= 0xDC00 && next <= 0xDFFF) - return 0x10000 + ((u - 0xD800) << 10) + (next - 0xDC00); - } - return u; -} - - -static size_t fs__get_length_wide(const WCHAR* w_source_ptr, - size_t w_source_len) { - size_t target_len; - int32_t code_point; - - target_len = 0; - for (; w_source_len; w_source_len--, w_source_ptr++) { - code_point = fs__get_surrogate_value(w_source_ptr, w_source_len); - /* Can be invalid UTF-8 but must be valid WTF-8. */ - assert(code_point >= 0); - if (code_point < 0x80) - target_len += 1; - else if (code_point < 0x800) - target_len += 2; - else if (code_point < 0x10000) - target_len += 3; - else { - target_len += 4; - w_source_ptr++; - w_source_len--; - } - } - return target_len; -} - - -static int fs__wide_to_wtf8(WCHAR* w_source_ptr, - size_t w_source_len, - char** target_ptr, - size_t* target_len_ptr) { - size_t target_len; - char* target; - int32_t code_point; - - /* If *target_ptr is provided, then *target_len_ptr must be its length - * (excluding space for null), otherwise we will compute the target_len_ptr - * length and may return a new allocation in *target_ptr if target_ptr is - * provided. */ - if (target_ptr == NULL || *target_ptr == NULL) { - target_len = fs__get_length_wide(w_source_ptr, w_source_len); - if (target_len_ptr != NULL) - *target_len_ptr = target_len; - } else { - target_len = *target_len_ptr; - } - - if (target_ptr == NULL) - return 0; - - if (*target_ptr == NULL) { - target = uv__malloc(target_len + 1); - if (target == NULL) { - SetLastError(ERROR_OUTOFMEMORY); - return -1; - } - *target_ptr = target; - } else { - target = *target_ptr; - } - - for (; w_source_len; w_source_len--, w_source_ptr++) { - code_point = fs__get_surrogate_value(w_source_ptr, w_source_len); - /* Can be invalid UTF-8 but must be valid WTF-8. */ - assert(code_point >= 0); - - if (code_point < 0x80) { - *target++ = code_point; - } else if (code_point < 0x800) { - *target++ = 0xC0 | (code_point >> 6); - *target++ = 0x80 | (code_point & 0x3F); - } else if (code_point < 0x10000) { - *target++ = 0xE0 | (code_point >> 12); - *target++ = 0x80 | ((code_point >> 6) & 0x3F); - *target++ = 0x80 | (code_point & 0x3F); - } else { - *target++ = 0xF0 | (code_point >> 18); - *target++ = 0x80 | ((code_point >> 12) & 0x3F); - *target++ = 0x80 | ((code_point >> 6) & 0x3F); - *target++ = 0x80 | (code_point & 0x3F); - w_source_ptr++; - w_source_len--; - } - } - assert((size_t) (target - *target_ptr) == target_len); - - *target++ = '\0'; - - return 0; -} - - INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr, size_t* target_len_ptr) { @@ -555,7 +280,98 @@ INLINE static int fs__readlink_handle(HANDLE handle, } assert(target_ptr == NULL || *target_ptr == NULL); - return fs__wide_to_wtf8(w_target, w_target_len, target_ptr, target_len_ptr); + return uv_utf16_to_wtf8(w_target, w_target_len, target_ptr, target_len_ptr); +} + + +INLINE static int fs__capture_path(uv_fs_t* req, const char* path, + const char* new_path, const int copy_path) { + WCHAR* buf; + WCHAR* pos; + size_t buf_sz = 0; + size_t path_len = 0; + ssize_t pathw_len = 0; + ssize_t new_pathw_len = 0; + + /* new_path can only be set if path is also set. */ + assert(new_path == NULL || path != NULL); + + if (path != NULL) { + pathw_len = uv_wtf8_length_as_utf16(path); + if (pathw_len < 0) + return ERROR_INVALID_NAME; + buf_sz += pathw_len * sizeof(WCHAR); + } + + if (path != NULL && copy_path) { + path_len = 1 + strlen(path); + buf_sz += path_len; + } + + if (new_path != NULL) { + new_pathw_len = uv_wtf8_length_as_utf16(new_path); + if (new_pathw_len < 0) + return ERROR_INVALID_NAME; + buf_sz += new_pathw_len * sizeof(WCHAR); + } + + + if (buf_sz == 0) { + req->file.pathw = NULL; + req->fs.info.new_pathw = NULL; + req->path = NULL; + return 0; + } + + buf = uv__malloc(buf_sz); + if (buf == NULL) { + return ERROR_OUTOFMEMORY; + } + + pos = buf; + + if (path != NULL) { + uv_wtf8_to_utf16(path, pos, pathw_len); + req->file.pathw = pos; + pos += pathw_len; + } else { + req->file.pathw = NULL; + } + + if (new_path != NULL) { + uv_wtf8_to_utf16(new_path, pos, new_pathw_len); + req->fs.info.new_pathw = pos; + pos += new_pathw_len; + } else { + req->fs.info.new_pathw = NULL; + } + + req->path = path; + if (path != NULL && copy_path) { + memcpy(pos, path, path_len); + assert(path_len == buf_sz - (pos - buf) * sizeof(WCHAR)); + req->path = (char*) pos; + } + + req->flags |= UV_FS_FREE_PATHS; + + return 0; +} + + +INLINE static void uv__fs_req_init(uv_loop_t* loop, uv_fs_t* req, + uv_fs_type fs_type, const uv_fs_cb cb) { + uv__once_init(); + UV_REQ_INIT(req, UV_FS); + req->loop = loop; + req->flags = 0; + req->fs_type = fs_type; + req->sys_errno_ = 0; + req->result = 0; + req->ptr = NULL; + req->path = NULL; + req->cb = cb; + memset(&req->fs, 0, sizeof(req->fs)); } @@ -1574,7 +1390,7 @@ void fs__scandir(uv_fs_t* req) { continue; /* Compute the space required to store the filename as WTF-8. */ - wtf8_len = fs__get_length_wide(&info->FileName[0], wchar_len); + wtf8_len = uv_utf16_length_as_wtf8(&info->FileName[0], wchar_len); /* Resize the dirent array if needed. */ if (dirents_used >= dirents_size) { @@ -1602,8 +1418,8 @@ void fs__scandir(uv_fs_t* req) { /* Convert file name to UTF-8. */ wtf8 = &dirent->d_name[0]; - if (fs__wide_to_wtf8(&info->FileName[0], wchar_len, &wtf8, &wtf8_len) == -1) - goto win32_error; + if (uv_utf16_to_wtf8(&info->FileName[0], wchar_len, &wtf8, &wtf8_len) != 0) + goto out_of_memory_error; /* Fill out the type field. */ if (info->FileAttributes & FILE_ATTRIBUTE_DEVICE) @@ -2829,7 +2645,7 @@ static ssize_t fs__realpath_handle(HANDLE handle, char** realpath_ptr) { } assert(*realpath_ptr == NULL); - r = fs__wide_to_wtf8(w_realpath_ptr, w_realpath_len, realpath_ptr, NULL); + r = uv_utf16_to_wtf8(w_realpath_ptr, w_realpath_len, realpath_ptr, NULL); uv__free(w_realpath_buf); return r; } diff --git a/src/win/getaddrinfo.c b/src/win/getaddrinfo.c index dfab860a..8b8406ad 100644 --- a/src/win/getaddrinfo.c +++ b/src/win/getaddrinfo.c @@ -104,13 +104,14 @@ static void uv__getaddrinfo_work(struct uv__work* w) { */ static void uv__getaddrinfo_done(struct uv__work* w, int status) { uv_getaddrinfo_t* req; - int addrinfo_len = 0; - int name_len = 0; + size_t addrinfo_len = 0; + ssize_t name_len = 0; size_t addrinfo_struct_len = ALIGNED_SIZE(sizeof(struct addrinfo)); struct addrinfoW* addrinfow_ptr; struct addrinfo* addrinfo_ptr; char* alloc_ptr = NULL; char* cur_ptr = NULL; + int r; req = container_of(w, uv_getaddrinfo_t, work_req); @@ -131,19 +132,12 @@ static void uv__getaddrinfo_done(struct uv__work* w, int status) { addrinfo_len += addrinfo_struct_len + ALIGNED_SIZE(addrinfow_ptr->ai_addrlen); if (addrinfow_ptr->ai_canonname != NULL) { - name_len = WideCharToMultiByte(CP_UTF8, - 0, - addrinfow_ptr->ai_canonname, - -1, - NULL, - 0, - NULL, - NULL); - if (name_len == 0) { - req->retcode = uv_translate_sys_error(GetLastError()); + name_len = uv_utf16_length_as_wtf8(addrinfow_ptr->ai_canonname, -1); + if (name_len < 0) { + req->retcode = name_len; goto complete; } - addrinfo_len += ALIGNED_SIZE(name_len); + addrinfo_len += ALIGNED_SIZE(name_len + 1); } addrinfow_ptr = addrinfow_ptr->ai_next; } @@ -182,27 +176,14 @@ static void uv__getaddrinfo_done(struct uv__work* w, int status) { /* convert canonical name to UTF-8 */ if (addrinfow_ptr->ai_canonname != NULL) { - name_len = WideCharToMultiByte(CP_UTF8, - 0, - addrinfow_ptr->ai_canonname, - -1, - NULL, - 0, - NULL, - NULL); - assert(name_len > 0); - assert(cur_ptr + name_len <= alloc_ptr + addrinfo_len); - name_len = WideCharToMultiByte(CP_UTF8, - 0, - addrinfow_ptr->ai_canonname, - -1, - cur_ptr, - name_len, - NULL, - NULL); - assert(name_len > 0); + name_len = alloc_ptr + addrinfo_len - cur_ptr; + r = uv__copy_utf16_to_utf8(addrinfow_ptr->ai_canonname, + -1, + cur_ptr, + (size_t*)&name_len); + assert(r == 0); addrinfo_ptr->ai_canonname = cur_ptr; - cur_ptr += ALIGNED_SIZE(name_len); + cur_ptr += ALIGNED_SIZE(name_len + 1); } assert(cur_ptr <= alloc_ptr + addrinfo_len); @@ -261,12 +242,11 @@ int uv_getaddrinfo(uv_loop_t* loop, const char* service, const struct addrinfo* hints) { char hostname_ascii[256]; - int nodesize = 0; - int servicesize = 0; - int hintssize = 0; + size_t nodesize = 0; + size_t servicesize = 0; + size_t hintssize = 0; char* alloc_ptr = NULL; - int err; - long rc; + ssize_t rc; if (req == NULL || (node == NULL && service == NULL)) { return UV_EINVAL; @@ -286,56 +266,36 @@ int uv_getaddrinfo(uv_loop_t* loop, hostname_ascii + sizeof(hostname_ascii)); if (rc < 0) return rc; - nodesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8, 0, hostname_ascii, - -1, NULL, 0) * sizeof(WCHAR)); - if (nodesize == 0) { - err = GetLastError(); - goto error; - } + nodesize = strlen(hostname_ascii) + 1; node = hostname_ascii; } if (service != NULL) { - servicesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8, - 0, - service, - -1, - NULL, - 0) * - sizeof(WCHAR)); - if (servicesize == 0) { - err = GetLastError(); - goto error; - } + rc = uv_wtf8_length_as_utf16(service); + if (rc < 0) + return rc; + servicesize = rc; } if (hints != NULL) { hintssize = ALIGNED_SIZE(sizeof(struct addrinfoW)); } /* allocate memory for inputs, and partition it as needed */ - alloc_ptr = (char*)uv__malloc(nodesize + servicesize + hintssize); - if (!alloc_ptr) { - err = WSAENOBUFS; - goto error; - } + alloc_ptr = uv__malloc(ALIGNED_SIZE(nodesize * sizeof(WCHAR)) + + ALIGNED_SIZE(servicesize * sizeof(WCHAR)) + + hintssize); + if (!alloc_ptr) + return UV_ENOMEM; /* save alloc_ptr now so we can free if error */ - req->alloc = (void*)alloc_ptr; + req->alloc = (void*) alloc_ptr; /* Convert node string to UTF16 into allocated memory and save pointer in the - * request. */ + * request. The node here has been converted to ascii. */ if (node != NULL) { - req->node = (WCHAR*)alloc_ptr; - if (MultiByteToWideChar(CP_UTF8, - 0, - node, - -1, - (WCHAR*) alloc_ptr, - nodesize / sizeof(WCHAR)) == 0) { - err = GetLastError(); - goto error; - } - alloc_ptr += nodesize; + req->node = (WCHAR*) alloc_ptr; + uv_wtf8_to_utf16(node, (WCHAR*) alloc_ptr, nodesize); + alloc_ptr += ALIGNED_SIZE(nodesize * sizeof(WCHAR)); } else { req->node = NULL; } @@ -343,24 +303,16 @@ int uv_getaddrinfo(uv_loop_t* loop, /* Convert service string to UTF16 into allocated memory and save pointer in * the req. */ if (service != NULL) { - req->service = (WCHAR*)alloc_ptr; - if (MultiByteToWideChar(CP_UTF8, - 0, - service, - -1, - (WCHAR*) alloc_ptr, - servicesize / sizeof(WCHAR)) == 0) { - err = GetLastError(); - goto error; - } - alloc_ptr += servicesize; + req->service = (WCHAR*) alloc_ptr; + uv_wtf8_to_utf16(service, (WCHAR*) alloc_ptr, servicesize); + alloc_ptr += ALIGNED_SIZE(servicesize * sizeof(WCHAR)); } else { req->service = NULL; } /* copy hints to allocated memory and save pointer in req */ if (hints != NULL) { - req->addrinfow = (struct addrinfoW*)alloc_ptr; + req->addrinfow = (struct addrinfoW*) alloc_ptr; req->addrinfow->ai_family = hints->ai_family; req->addrinfow->ai_socktype = hints->ai_socktype; req->addrinfow->ai_protocol = hints->ai_protocol; @@ -387,19 +339,11 @@ int uv_getaddrinfo(uv_loop_t* loop, uv__getaddrinfo_done(&req->work_req, 0); return req->retcode; } - -error: - if (req != NULL) { - uv__free(req->alloc); - req->alloc = NULL; - } - return uv_translate_sys_error(err); } int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) { NET_LUID luid; wchar_t wname[NDIS_IF_MAX_STRING_SIZE + 1]; /* Add one for the NUL. */ - DWORD bufsize; int r; if (buffer == NULL || size == NULL || *size == 0) @@ -415,31 +359,7 @@ int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) { if (r != 0) return uv_translate_sys_error(r); - /* Check how much space we need */ - bufsize = WideCharToMultiByte(CP_UTF8, 0, wname, -1, NULL, 0, NULL, NULL); - - if (bufsize == 0) { - return uv_translate_sys_error(GetLastError()); - } else if (bufsize > *size) { - *size = bufsize; - return UV_ENOBUFS; - } - - /* Convert to UTF-8 */ - bufsize = WideCharToMultiByte(CP_UTF8, - 0, - wname, - -1, - buffer, - *size, - NULL, - NULL); - - if (bufsize == 0) - return uv_translate_sys_error(GetLastError()); - - *size = bufsize - 1; - return 0; + return uv__copy_utf16_to_utf8(wname, -1, buffer, size); } int uv_if_indextoiid(unsigned int ifindex, char* buffer, size_t* size) { diff --git a/src/win/getnameinfo.c b/src/win/getnameinfo.c index b3773380..32863176 100644 --- a/src/win/getnameinfo.c +++ b/src/win/getnameinfo.c @@ -42,6 +42,7 @@ static void uv__getnameinfo_work(struct uv__work* w) { uv_getnameinfo_t* req; WCHAR host[NI_MAXHOST]; WCHAR service[NI_MAXSERV]; + size_t size; int ret; req = container_of(w, uv_getnameinfo_t, work_req); @@ -57,29 +58,17 @@ static void uv__getnameinfo_work(struct uv__work* w) { return; } - ret = WideCharToMultiByte(CP_UTF8, - 0, - host, - -1, - req->host, - sizeof(req->host), - NULL, - NULL); - if (ret == 0) { - req->retcode = uv_translate_sys_error(GetLastError()); + size = sizeof(req->host); + ret = uv__copy_utf16_to_utf8(host, -1, req->host, &size); + if (ret < 0) { + req->retcode = ret; return; } - ret = WideCharToMultiByte(CP_UTF8, - 0, - service, - -1, - req->service, - sizeof(req->service), - NULL, - NULL); - if (ret == 0) { - req->retcode = uv_translate_sys_error(GetLastError()); + size = sizeof(req->service); + ret = uv__copy_utf16_to_utf8(service, -1, req->service, &size); + if (ret < 0) { + req->retcode = ret; } } diff --git a/src/win/internal.h b/src/win/internal.h index 9672fbc6..867dea5e 100644 --- a/src/win/internal.h +++ b/src/win/internal.h @@ -257,8 +257,9 @@ void uv__util_init(void); uint64_t uv__hrtime(unsigned int scale); __declspec(noreturn) void uv_fatal_error(const int errorno, const char* syscall); -int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8); -int uv__convert_utf8_to_utf16(const char* utf8, int utf8len, WCHAR** utf16); +int uv__convert_utf16_to_utf8(const WCHAR* utf16, size_t utf16len, char** utf8); +int uv__copy_utf16_to_utf8(const WCHAR* utf16, size_t utf16len, char* utf8, size_t *size); +int uv__convert_utf8_to_utf16(const char* utf8, WCHAR** utf16); typedef int (WINAPI *uv__peersockfunc)(SOCKET, struct sockaddr*, int*); diff --git a/src/win/pipe.c b/src/win/pipe.c index f0cac382..cec72ff7 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -49,7 +49,7 @@ static const int default_pending_pipe_instances = 4; /* Pipe prefix */ static char pipe_prefix[] = "\\\\?\\pipe"; -static const int pipe_prefix_len = sizeof(pipe_prefix) - 1; +static const size_t pipe_prefix_len = sizeof(pipe_prefix) - 1; /* IPC incoming xfer queue item. */ typedef struct { @@ -703,7 +703,7 @@ int uv_pipe_bind2(uv_pipe_t* handle, size_t namelen, unsigned int flags) { uv_loop_t* loop = handle->loop; - int i, err, nameSize; + int i, err; uv_pipe_accept_t* req; if (flags & ~UV_PIPE_NO_TRUNCATE) { @@ -742,9 +742,8 @@ int uv_pipe_bind2(uv_pipe_t* handle, handle->pipe.serv.accept_reqs = (uv_pipe_accept_t*) uv__malloc(sizeof(uv_pipe_accept_t) * handle->pipe.serv.pending_instances); - if (!handle->pipe.serv.accept_reqs) { - uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); - } + if (!handle->pipe.serv.accept_reqs) + return UV_ENOMEM; for (i = 0; i < handle->pipe.serv.pending_instances; i++) { req = &handle->pipe.serv.accept_reqs[i]; @@ -754,22 +753,9 @@ int uv_pipe_bind2(uv_pipe_t* handle, req->next_pending = NULL; } - /* Convert name to UTF16. */ - nameSize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0) * sizeof(WCHAR); - handle->name = uv__malloc(nameSize); - if (!handle->name) { - uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); - } - - if (!MultiByteToWideChar(CP_UTF8, - 0, - name, - -1, - handle->name, - nameSize / sizeof(WCHAR))) { - err = GetLastError(); - goto error; - } + err = uv__convert_utf8_to_utf16(name, &handle->name); + if (err) + return err; /* * Attempt to create the first pipe with FILE_FLAG_FIRST_PIPE_INSTANCE. @@ -795,10 +781,8 @@ int uv_pipe_bind2(uv_pipe_t* handle, return 0; error: - if (handle->name) { - uv__free(handle->name); - handle->name = NULL; - } + uv__free(handle->name); + handle->name = NULL; return uv_translate_sys_error(err); } @@ -861,7 +845,8 @@ int uv_pipe_connect2(uv_connect_t* req, unsigned int flags, uv_connect_cb cb) { uv_loop_t* loop = handle->loop; - int err, nameSize; + int err; + size_t nameSize; HANDLE pipeHandle = INVALID_HANDLE_VALUE; DWORD duplex_flags; @@ -904,26 +889,16 @@ int uv_pipe_connect2(uv_connect_t* req, } uv__pipe_connection_init(handle); - /* Convert name to UTF16. */ - nameSize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0) * sizeof(WCHAR); - handle->name = uv__malloc(nameSize); - if (!handle->name) { - uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); - } - - if (!MultiByteToWideChar(CP_UTF8, - 0, - name, - -1, - handle->name, - nameSize / sizeof(WCHAR))) { - err = GetLastError(); + err = uv__convert_utf8_to_utf16(name, &handle->name); + if (err) { + err = ERROR_NO_UNICODE_TRANSLATION; goto error; } pipeHandle = open_named_pipe(handle->name, &duplex_flags); if (pipeHandle == INVALID_HANDLE_VALUE) { if (GetLastError() == ERROR_PIPE_BUSY) { + nameSize = (wcslen(handle->name) + 1) * sizeof(WCHAR); req->u.connect.name = uv__malloc(nameSize); if (!req->u.connect.name) { uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); @@ -2439,7 +2414,6 @@ static int uv__pipe_getname(const uv_pipe_t* handle, char* buffer, size_t* size) FILE_NAME_INFORMATION tmp_name_info; FILE_NAME_INFORMATION* name_info; WCHAR* name_buf; - unsigned int addrlen; unsigned int name_size; unsigned int name_len; int err; @@ -2450,46 +2424,7 @@ static int uv__pipe_getname(const uv_pipe_t* handle, char* buffer, size_t* size) if (handle->name != NULL) { /* The user might try to query the name before we are connected, * and this is just easier to return the cached value if we have it. */ - name_buf = handle->name; - name_len = wcslen(name_buf); - - /* check how much space we need */ - addrlen = WideCharToMultiByte(CP_UTF8, - 0, - name_buf, - name_len, - NULL, - 0, - NULL, - NULL); - if (!addrlen) { - *size = 0; - err = uv_translate_sys_error(GetLastError()); - return err; - } else if (addrlen >= *size) { - *size = addrlen + 1; - err = UV_ENOBUFS; - goto error; - } - - addrlen = WideCharToMultiByte(CP_UTF8, - 0, - name_buf, - name_len, - buffer, - addrlen, - NULL, - NULL); - if (!addrlen) { - *size = 0; - err = uv_translate_sys_error(GetLastError()); - return err; - } - - *size = addrlen; - buffer[addrlen] = '\0'; - - return 0; + return uv__copy_utf16_to_utf8(handle->name, -1, buffer, size); } if (handle->handle == INVALID_HANDLE_VALUE) { @@ -2517,8 +2452,7 @@ static int uv__pipe_getname(const uv_pipe_t* handle, char* buffer, size_t* size) name_info = uv__malloc(name_size); if (!name_info) { *size = 0; - err = UV_ENOMEM; - goto cleanup; + return UV_ENOMEM; } nt_status = pNtQueryInformationFile(handle->handle, @@ -2551,51 +2485,19 @@ static int uv__pipe_getname(const uv_pipe_t* handle, char* buffer, size_t* size) name_len /= sizeof(WCHAR); - /* check how much space we need */ - addrlen = WideCharToMultiByte(CP_UTF8, - 0, - name_buf, - name_len, - NULL, - 0, - NULL, - NULL); - if (!addrlen) { + /* "\\\\.\\pipe" + name */ + if (*size < pipe_prefix_len) { *size = 0; - err = uv_translate_sys_error(GetLastError()); - goto error; - } else if (pipe_prefix_len + addrlen >= *size) { - /* "\\\\.\\pipe" + name */ - *size = pipe_prefix_len + addrlen + 1; - err = UV_ENOBUFS; - goto error; } - - memcpy(buffer, pipe_prefix, pipe_prefix_len); - addrlen = WideCharToMultiByte(CP_UTF8, - 0, - name_buf, - name_len, - buffer+pipe_prefix_len, - *size-pipe_prefix_len, - NULL, - NULL); - if (!addrlen) { - *size = 0; - err = uv_translate_sys_error(GetLastError()); - goto error; + else { + memcpy(buffer, pipe_prefix, pipe_prefix_len); + *size -= pipe_prefix_len; } - - addrlen += pipe_prefix_len; - *size = addrlen; - buffer[addrlen] = '\0'; - - err = 0; + err = uv__copy_utf16_to_utf8(name_buf, name_len, buffer+pipe_prefix_len, size); + *size += pipe_prefix_len; error: uv__free(name_info); - -cleanup: return err; } diff --git a/src/win/process.c b/src/win/process.c index 8f1b665a..43059858 100644 --- a/src/win/process.c +++ b/src/win/process.c @@ -124,34 +124,7 @@ static void uv__init_global_job_handle(void) { static int uv__utf8_to_utf16_alloc(const char* s, WCHAR** ws_ptr) { - int ws_len, r; - WCHAR* ws; - - ws_len = MultiByteToWideChar(CP_UTF8, - 0, - s, - -1, - NULL, - 0); - if (ws_len <= 0) { - return GetLastError(); - } - - ws = (WCHAR*) uv__malloc(ws_len * sizeof(WCHAR)); - if (ws == NULL) { - return ERROR_OUTOFMEMORY; - } - - r = MultiByteToWideChar(CP_UTF8, - 0, - s, - -1, - ws, - ws_len); - assert(r == ws_len); - - *ws_ptr = ws; - return 0; + return uv__convert_utf8_to_utf16(s, ws_ptr); } @@ -554,21 +527,15 @@ int make_program_args(char** args, int verbatim_arguments, WCHAR** dst_ptr) { /* Count the required size. */ for (arg = args; *arg; arg++) { - DWORD arg_len; + ssize_t arg_len; - arg_len = MultiByteToWideChar(CP_UTF8, - 0, - *arg, - -1, - NULL, - 0); - if (arg_len == 0) { - return GetLastError(); - } + arg_len = uv_wtf8_length_as_utf16(*arg); + if (arg_len < 0) + return arg_len; dst_len += arg_len; - if (arg_len > temp_buffer_len) + if ((size_t) arg_len > temp_buffer_len) temp_buffer_len = arg_len; arg_count++; @@ -579,34 +546,28 @@ int make_program_args(char** args, int verbatim_arguments, WCHAR** dst_ptr) { dst_len = dst_len * 2 + arg_count * 2; /* Allocate buffer for the final command line. */ - dst = (WCHAR*) uv__malloc(dst_len * sizeof(WCHAR)); + dst = uv__malloc(dst_len * sizeof(WCHAR)); if (dst == NULL) { - err = ERROR_OUTOFMEMORY; + err = UV_ENOMEM; goto error; } /* Allocate temporary working buffer. */ - temp_buffer = (WCHAR*) uv__malloc(temp_buffer_len * sizeof(WCHAR)); + temp_buffer = uv__malloc(temp_buffer_len * sizeof(WCHAR)); if (temp_buffer == NULL) { - err = ERROR_OUTOFMEMORY; + err = UV_ENOMEM; goto error; } pos = dst; for (arg = args; *arg; arg++) { - DWORD arg_len; + ssize_t arg_len; /* Convert argument to wide char. */ - arg_len = MultiByteToWideChar(CP_UTF8, - 0, - *arg, - -1, - temp_buffer, - (int) (dst + dst_len - pos)); - if (arg_len == 0) { - err = GetLastError(); - goto error; - } + arg_len = uv_wtf8_length_as_utf16(*arg); + assert(arg_len > 0); + assert(temp_buffer_len >= (size_t) arg_len); + uv_wtf8_to_utf16(*arg, temp_buffer, arg_len); if (verbatim_arguments) { /* Copy verbatim. */ @@ -618,6 +579,7 @@ int make_program_args(char** args, int verbatim_arguments, WCHAR** dst_ptr) { } *pos++ = *(arg + 1) ? L' ' : L'\0'; + assert(pos <= dst + dst_len); } uv__free(temp_buffer); @@ -703,55 +665,43 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) { WCHAR* ptr; char** env; size_t env_len = 0; - int len; + size_t len; size_t i; - DWORD var_size; + size_t var_size; size_t env_block_count = 1; /* 1 for null-terminator */ WCHAR* dst_copy; WCHAR** ptr_copy; WCHAR** env_copy; - DWORD required_vars_value_len[ARRAY_SIZE(required_vars)]; + size_t required_vars_value_len[ARRAY_SIZE(required_vars)]; /* first pass: determine size in UTF-16 */ for (env = env_block; *env; env++) { - int len; + ssize_t len; if (strchr(*env, '=')) { - len = MultiByteToWideChar(CP_UTF8, - 0, - *env, - -1, - NULL, - 0); - if (len <= 0) { - return GetLastError(); - } + len = uv_wtf8_length_as_utf16(*env); + if (len < 0) + return len; env_len += len; env_block_count++; } } /* second pass: copy to UTF-16 environment block */ - dst_copy = (WCHAR*)uv__malloc(env_len * sizeof(WCHAR)); + dst_copy = uv__malloc(env_len * sizeof(WCHAR)); if (dst_copy == NULL && env_len > 0) { - return ERROR_OUTOFMEMORY; + return UV_ENOMEM; } env_copy = alloca(env_block_count * sizeof(WCHAR*)); ptr = dst_copy; ptr_copy = env_copy; for (env = env_block; *env; env++) { + ssize_t len; if (strchr(*env, '=')) { - len = MultiByteToWideChar(CP_UTF8, - 0, - *env, - -1, - ptr, - (int) (env_len - (ptr - dst_copy))); - if (len <= 0) { - DWORD err = GetLastError(); - uv__free(dst_copy); - return err; - } + len = uv_wtf8_length_as_utf16(*env); + assert(len > 0); + assert((size_t) len <= env_len - (ptr - dst_copy)); + uv_wtf8_to_utf16(*env, ptr, len); *ptr_copy++ = ptr; ptr += len; } @@ -769,7 +719,7 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) { cmp = -1; } else { cmp = env_strncmp(required_vars[i].wide_eq, - required_vars[i].len, + required_vars[i].len, *ptr_copy); } if (cmp < 0) { @@ -792,7 +742,7 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) { dst = uv__malloc((1+env_len) * sizeof(WCHAR)); if (!dst) { uv__free(dst_copy); - return ERROR_OUTOFMEMORY; + return UV_ENOMEM; } for (ptr = dst, ptr_copy = env_copy, i = 0; @@ -990,26 +940,26 @@ int uv_spawn(uv_loop_t* loop, err = uv__utf8_to_utf16_alloc(options->file, &application); if (err) - goto done; + goto done_uv; err = make_program_args( options->args, options->flags & UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS, &arguments); if (err) - goto done; + goto done_uv; if (options->env) { err = make_program_env(options->env, &env); if (err) - goto done; + goto done_uv; } if (options->cwd) { /* Explicit cwd */ err = uv__utf8_to_utf16_alloc(options->cwd, &cwd); if (err) - goto done; + goto done_uv; } else { /* Inherit cwd */ @@ -1194,8 +1144,13 @@ int uv_spawn(uv_loop_t* loop, * made or the handle is closed, whichever happens first. */ uv__handle_start(process); + goto done_uv; + /* Cleanup, whether we succeeded or failed. */ done: + err = uv_translate_sys_error(err); + + done_uv: uv__free(application); uv__free(application_path); uv__free(arguments); @@ -1209,7 +1164,7 @@ int uv_spawn(uv_loop_t* loop, child_stdio_buffer = NULL; } - return uv_translate_sys_error(err); + return err; } diff --git a/src/win/tty.c b/src/win/tty.c index 7e1f1554..ac836930 100644 --- a/src/win/tty.c +++ b/src/win/tty.c @@ -482,9 +482,11 @@ static DWORD CALLBACK uv_tty_line_read_thread(void* data) { uv_loop_t* loop; uv_tty_t* handle; uv_req_t* req; - DWORD bytes, read_bytes; + DWORD bytes; + size_t read_bytes; WCHAR utf16[MAX_INPUT_BUFFER_LENGTH / 3]; - DWORD chars, read_chars; + DWORD chars; + DWORD read_chars; LONG status; COORD pos; BOOL read_console_success; @@ -525,16 +527,13 @@ static DWORD CALLBACK uv_tty_line_read_thread(void* data) { NULL); if (read_console_success) { - read_bytes = WideCharToMultiByte(CP_UTF8, - 0, - utf16, - read_chars, - handle->tty.rd.read_line_buffer.base, - bytes, - NULL, - NULL); + read_bytes = bytes; + uv_utf16_to_wtf8(utf16, + read_chars, + &handle->tty.rd.read_line_buffer.base, + &read_bytes); SET_REQ_SUCCESS(req); - req->u.io.overlapped.InternalHigh = read_bytes; + req->u.io.overlapped.InternalHigh = (DWORD) read_bytes; } else { SET_REQ_ERROR(req, GetLastError()); } @@ -798,7 +797,9 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle, } if (KEV.uChar.UnicodeChar != 0) { - int prefix_len, char_len; + int prefix_len; + size_t char_len; + char* last_key_buf; /* Character key pressed */ if (KEV.uChar.UnicodeChar >= 0xD800 && @@ -819,38 +820,31 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle, prefix_len = 0; } - if (KEV.uChar.UnicodeChar >= 0xDC00 && - KEV.uChar.UnicodeChar < 0xE000) { + char_len = sizeof handle->tty.rd.last_key; + last_key_buf = &handle->tty.rd.last_key[prefix_len]; + if (handle->tty.rd.last_utf16_high_surrogate) { /* UTF-16 surrogate pair */ WCHAR utf16_buffer[2]; utf16_buffer[0] = handle->tty.rd.last_utf16_high_surrogate; utf16_buffer[1] = KEV.uChar.UnicodeChar; - char_len = WideCharToMultiByte(CP_UTF8, - 0, - utf16_buffer, - 2, - &handle->tty.rd.last_key[prefix_len], - sizeof handle->tty.rd.last_key, - NULL, - NULL); + if (uv_utf16_to_wtf8(utf16_buffer, + 2, + &last_key_buf, + &char_len)) + char_len = 0; + handle->tty.rd.last_utf16_high_surrogate = 0; } else { /* Single UTF-16 character */ - char_len = WideCharToMultiByte(CP_UTF8, - 0, - &KEV.uChar.UnicodeChar, - 1, - &handle->tty.rd.last_key[prefix_len], - sizeof handle->tty.rd.last_key, - NULL, - NULL); + if (uv_utf16_to_wtf8(&KEV.uChar.UnicodeChar, + 1, + &last_key_buf, + &char_len)) + char_len = 0; } - /* Whatever happened, the last character wasn't a high surrogate. */ - handle->tty.rd.last_utf16_high_surrogate = 0; - /* If the utf16 character(s) couldn't be converted something must be * wrong. */ - if (!char_len) { + if (char_len == 0) { handle->flags &= ~UV_HANDLE_READING; DECREASE_ACTIVE_COUNT(loop, handle); handle->read_cb((uv_stream_t*) handle, diff --git a/src/win/util.c b/src/win/util.c index f6ec79cd..58b8e106 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -95,7 +95,7 @@ void uv__util_init(void) { int uv_exepath(char* buffer, size_t* size_ptr) { - int utf8_len, utf16_buffer_len, utf16_len; + size_t utf8_len, utf16_buffer_len, utf16_len; WCHAR* utf16_buffer; int err; @@ -123,25 +123,17 @@ int uv_exepath(char* buffer, size_t* size_ptr) { } /* Convert to UTF-8 */ - utf8_len = WideCharToMultiByte(CP_UTF8, - 0, - utf16_buffer, - -1, - buffer, - (int) *size_ptr, - NULL, - NULL); - if (utf8_len == 0) { - err = GetLastError(); - goto error; + utf8_len = *size_ptr - 1; /* Reserve space for NUL */ + err = uv_utf16_to_wtf8(utf16_buffer, utf16_len, &buffer, &utf8_len); + if (err == UV_ENOBUFS) { + utf8_len = *size_ptr - 1; + err = 0; } + *size_ptr = utf8_len; uv__free(utf16_buffer); - /* utf8_len *does* include the terminating null at this point, but the - * returned size shouldn't. */ - *size_ptr = utf8_len - 1; - return 0; + return err; error: uv__free(utf16_buffer); @@ -204,45 +196,14 @@ int uv_cwd(char* buffer, size_t* size) { } r = uv__cwd(&utf16_buffer, &utf16_len); - if (r < 0) { + if (r < 0) return r; - } - /* Check how much space we need */ - r = WideCharToMultiByte(CP_UTF8, - 0, - utf16_buffer, - -1, - NULL, - 0, - NULL, - NULL); - if (r == 0) { - uv__free(utf16_buffer); - return uv_translate_sys_error(GetLastError()); - } else if (r > (int) *size) { - uv__free(utf16_buffer); - *size = r; - return UV_ENOBUFS; - } + r = uv__copy_utf16_to_utf8(utf16_buffer, utf16_len, buffer, size); - /* Convert to UTF-8 */ - r = WideCharToMultiByte(CP_UTF8, - 0, - utf16_buffer, - -1, - buffer, - *size > INT_MAX ? INT_MAX : (int) *size, - NULL, - NULL); uv__free(utf16_buffer); - if (r == 0) { - return uv_translate_sys_error(GetLastError()); - } - - *size = r - 1; - return 0; + return r; } @@ -252,33 +213,10 @@ int uv_chdir(const char* dir) { WCHAR drive_letter, env_var[4]; int r; - if (dir == NULL) { - return UV_EINVAL; - } - - utf16_len = MultiByteToWideChar(CP_UTF8, - 0, - dir, - -1, - NULL, - 0); - if (utf16_len == 0) { - return uv_translate_sys_error(GetLastError()); - } - utf16_buffer = uv__malloc(utf16_len * sizeof(WCHAR)); - if (utf16_buffer == NULL) { - return UV_ENOMEM; - } - - if (MultiByteToWideChar(CP_UTF8, - 0, - dir, - -1, - utf16_buffer, - utf16_len) == 0) { - uv__free(utf16_buffer); - return uv_translate_sys_error(GetLastError()); - } + /* Convert to UTF-16 */ + r = uv__convert_utf8_to_utf16(dir, &utf16_buffer); + if (r) + return r; if (!SetCurrentDirectoryW(utf16_buffer)) { uv__free(utf16_buffer); @@ -416,29 +354,14 @@ int uv_set_process_title(const char* title) { uv__once_init(); - /* Find out how big the buffer for the wide-char title must be */ - length = MultiByteToWideChar(CP_UTF8, 0, title, -1, NULL, 0); - if (!length) { - err = GetLastError(); - goto done; - } - - /* Convert to wide-char string */ - title_w = (WCHAR*)uv__malloc(sizeof(WCHAR) * length); - if (!title_w) { - uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); - } - - length = MultiByteToWideChar(CP_UTF8, 0, title, -1, title_w, length); - if (!length) { - err = GetLastError(); - goto done; - } + err = uv__convert_utf8_to_utf16(title, &title_w); + if (err) + return err; /* If the title must be truncated insert a \0 terminator there */ - if (length > MAX_TITLE_LENGTH) { + length = wcslen(title_w); + if (length >= MAX_TITLE_LENGTH) title_w[MAX_TITLE_LENGTH - 1] = L'\0'; - } if (!SetConsoleTitleW(title_w)) { err = GetLastError(); @@ -460,20 +383,19 @@ done: static int uv__get_process_title(void) { WCHAR title_w[MAX_TITLE_LENGTH]; + DWORD wlen; - if (!GetConsoleTitleW(title_w, sizeof(title_w) / sizeof(WCHAR))) { - return -1; - } + wlen = GetConsoleTitleW(title_w, sizeof(title_w) / sizeof(WCHAR)); + if (wlen == 0) + return uv_translate_sys_error(GetLastError()); - if (uv__convert_utf16_to_utf8(title_w, -1, &process_title) != 0) - return -1; - - return 0; + return uv__convert_utf16_to_utf8(title_w, wlen, &process_title); } int uv_get_process_title(char* buffer, size_t size) { size_t len; + int r; if (buffer == NULL || size == 0) return UV_EINVAL; @@ -485,9 +407,12 @@ int uv_get_process_title(char* buffer, size_t size) { * If the process_title was never read before nor explicitly set, * we must query it with getConsoleTitleW */ - if (!process_title && uv__get_process_title() == -1) { - LeaveCriticalSection(&process_title_lock); - return uv_translate_sys_error(GetLastError()); + if (process_title == NULL) { + r = uv__get_process_title(); + if (r) { + LeaveCriticalSection(&process_title_lock); + return r; + } } assert(process_title); @@ -833,19 +758,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr, continue; /* Compute the size of the interface name. */ - name_size = WideCharToMultiByte(CP_UTF8, - 0, - adapter->FriendlyName, - -1, - NULL, - 0, - NULL, - FALSE); - if (name_size <= 0) { - uv__free(win_address_buf); - return uv_translate_sys_error(GetLastError()); - } - uv_address_buf_size += name_size; + name_size = uv_utf16_length_as_wtf8(adapter->FriendlyName, -1); + uv_address_buf_size += name_size + 1; /* Count the number of addresses associated with this interface, and * compute the size. */ @@ -875,30 +789,25 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr, adapter != NULL; adapter = adapter->Next) { IP_ADAPTER_UNICAST_ADDRESS* unicast_address; - int name_size; - size_t max_name_size; + size_t name_size; + int r; if (adapter->OperStatus != IfOperStatusUp || adapter->FirstUnicastAddress == NULL) continue; /* Convert the interface name to UTF8. */ - max_name_size = (char*) uv_address_buf + uv_address_buf_size - name_buf; - if (max_name_size > (size_t) INT_MAX) - max_name_size = INT_MAX; - name_size = WideCharToMultiByte(CP_UTF8, - 0, - adapter->FriendlyName, - -1, - name_buf, - (int) max_name_size, - NULL, - FALSE); - if (name_size <= 0) { + name_size = (char*) uv_address_buf + uv_address_buf_size - name_buf; + r = uv__copy_utf16_to_utf8(adapter->FriendlyName, + -1, + name_buf, + &name_size); + if (r) { uv__free(win_address_buf); uv__free(uv_address_buf); - return uv_translate_sys_error(GetLastError()); + return r; } + name_size += 1; /* Add NUL byte. */ /* Add an uv_interface_address_t element for every unicast address. */ for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS*) @@ -1061,7 +970,6 @@ int uv_os_homedir(char* buffer, size_t* size) { int uv_os_tmpdir(char* buffer, size_t* size) { wchar_t *path; - DWORD bufsize; size_t len; if (buffer == NULL || size == NULL || *size == 0) @@ -1078,7 +986,7 @@ int uv_os_tmpdir(char* buffer, size_t* size) { if (path == NULL) { return UV_ENOMEM; } - len = GetTempPathW(len, path); + len = GetTempPathW(len, path); if (len == 0) { uv__free(path); @@ -1093,34 +1001,7 @@ int uv_os_tmpdir(char* buffer, size_t* size) { path[len] = L'\0'; } - /* Check how much space we need */ - bufsize = WideCharToMultiByte(CP_UTF8, 0, path, -1, NULL, 0, NULL, NULL); - - if (bufsize == 0) { - uv__free(path); - return uv_translate_sys_error(GetLastError()); - } else if (bufsize > *size) { - uv__free(path); - *size = bufsize; - return UV_ENOBUFS; - } - - /* Convert to UTF-8 */ - bufsize = WideCharToMultiByte(CP_UTF8, - 0, - path, - -1, - buffer, - *size, - NULL, - NULL); - uv__free(path); - - if (bufsize == 0) - return uv_translate_sys_error(GetLastError()); - - *size = bufsize - 1; - return 0; + return uv__copy_utf16_to_utf8(path, len, buffer, size); } @@ -1131,95 +1012,71 @@ int uv_os_tmpdir(char* buffer, size_t* size) { * If utf16 is null terminated, utf16len can be set to -1, otherwise it must * be specified. */ -int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8) { - DWORD bufsize; +int uv__convert_utf16_to_utf8(const WCHAR* utf16, size_t utf16len, char** utf8) { + size_t utf8_len = 0; if (utf16 == NULL) return UV_EINVAL; - /* Check how much space we need */ - bufsize = WideCharToMultiByte(CP_UTF8, - 0, - utf16, - utf16len, - NULL, - 0, - NULL, - NULL); - - if (bufsize == 0) - return uv_translate_sys_error(GetLastError()); - - /* Allocate the destination buffer adding an extra byte for the terminating - * NULL. If utf16len is not -1 WideCharToMultiByte will not add it, so - * we do it ourselves always, just in case. */ - *utf8 = uv__malloc(bufsize + 1); - - if (*utf8 == NULL) - return UV_ENOMEM; - - /* Convert to UTF-8 */ - bufsize = WideCharToMultiByte(CP_UTF8, - 0, - utf16, - utf16len, - *utf8, - bufsize, - NULL, - NULL); - - if (bufsize == 0) { - uv__free(*utf8); - *utf8 = NULL; - return uv_translate_sys_error(GetLastError()); - } - - (*utf8)[bufsize] = '\0'; - return 0; + *utf8 = NULL; + return uv_utf16_to_wtf8(utf16, utf16len, utf8, &utf8_len); } /* * Converts a UTF-8 string into a UTF-16 one. The resulting string is * null-terminated. - * - * If utf8 is null terminated, utf8len can be set to -1, otherwise it must - * be specified. */ -int uv__convert_utf8_to_utf16(const char* utf8, int utf8len, WCHAR** utf16) { +int uv__convert_utf8_to_utf16(const char* utf8, WCHAR** utf16) { int bufsize; if (utf8 == NULL) return UV_EINVAL; - /* Check how much space we need */ - bufsize = MultiByteToWideChar(CP_UTF8, 0, utf8, utf8len, NULL, 0); + /* Check how much space we need (including NUL). */ + bufsize = uv_wtf8_length_as_utf16(utf8); + if (bufsize < 0) + return UV__EINVAL; - if (bufsize == 0) - return uv_translate_sys_error(GetLastError()); - - /* Allocate the destination buffer adding an extra byte for the terminating - * NULL. If utf8len is not -1 MultiByteToWideChar will not add it, so - * we do it ourselves always, just in case. */ - *utf16 = uv__malloc(sizeof(WCHAR) * (bufsize + 1)); + /* Allocate the destination buffer. */ + *utf16 = uv__malloc(sizeof(WCHAR) * bufsize); if (*utf16 == NULL) return UV_ENOMEM; /* Convert to UTF-16 */ - bufsize = MultiByteToWideChar(CP_UTF8, 0, utf8, utf8len, *utf16, bufsize); + uv_wtf8_to_utf16(utf8, *utf16, bufsize); - if (bufsize == 0) { - uv__free(*utf16); - *utf16 = NULL; - return uv_translate_sys_error(GetLastError()); - } - - (*utf16)[bufsize] = L'\0'; return 0; } +/* + * Converts a UTF-16 string into a UTF-8 one in an existing buffer. The + * resulting string is null-terminated. + * + * If utf16 is null terminated, utf16len can be set to -1, otherwise it must + * be specified. + */ +int uv__copy_utf16_to_utf8(const WCHAR* utf16buffer, size_t utf16len, char* utf8, size_t *size) { + int r; + + if (utf8 == NULL || size == NULL) + return UV_EINVAL; + + if (*size == 0) { + *size = uv_utf16_length_as_wtf8(utf16buffer, utf16len); + r = UV_ENOBUFS; + } else { + *size -= 1; /* Reserve space for NUL. */ + r = uv_utf16_to_wtf8(utf16buffer, utf16len, &utf8, size); + } + if (r == UV_ENOBUFS) + *size += 1; /* Add space for NUL. */ + return r; +} + + static int uv__getpwuid_r(uv_passwd_t* pwd) { HANDLE token; wchar_t username[UNLEN + 1]; @@ -1384,14 +1241,13 @@ int uv_os_getenv(const char* name, char* buffer, size_t* size) { wchar_t* var; DWORD varlen; wchar_t* name_w; - DWORD bufsize; size_t len; int r; if (name == NULL || buffer == NULL || size == NULL || *size == 0) return UV_EINVAL; - r = uv__convert_utf8_to_utf16(name, -1, &name_w); + r = uv__convert_utf8_to_utf16(name, &name_w); if (r != 0) return r; @@ -1432,35 +1288,7 @@ int uv_os_getenv(const char* name, char* buffer, size_t* size) { } } - /* Check how much space we need */ - bufsize = WideCharToMultiByte(CP_UTF8, 0, var, -1, NULL, 0, NULL, NULL); - - if (bufsize == 0) { - r = uv_translate_sys_error(GetLastError()); - goto fail; - } else if (bufsize > *size) { - *size = bufsize; - r = UV_ENOBUFS; - goto fail; - } - - /* Convert to UTF-8 */ - bufsize = WideCharToMultiByte(CP_UTF8, - 0, - var, - -1, - buffer, - *size, - NULL, - NULL); - - if (bufsize == 0) { - r = uv_translate_sys_error(GetLastError()); - goto fail; - } - - *size = bufsize - 1; - r = 0; + r = uv__copy_utf16_to_utf8(var, len, buffer, size); fail: @@ -1482,12 +1310,12 @@ int uv_os_setenv(const char* name, const char* value) { if (name == NULL || value == NULL) return UV_EINVAL; - r = uv__convert_utf8_to_utf16(name, -1, &name_w); + r = uv__convert_utf8_to_utf16(name, &name_w); if (r != 0) return r; - r = uv__convert_utf8_to_utf16(value, -1, &value_w); + r = uv__convert_utf8_to_utf16(value, &value_w); if (r != 0) { uv__free(name_w); @@ -1512,7 +1340,7 @@ int uv_os_unsetenv(const char* name) { if (name == NULL) return UV_EINVAL; - r = uv__convert_utf8_to_utf16(name, -1, &name_w); + r = uv__convert_utf8_to_utf16(name, &name_w); if (r != 0) return r; @@ -1529,9 +1357,6 @@ int uv_os_unsetenv(const char* name) { int uv_os_gethostname(char* buffer, size_t* size) { WCHAR buf[UV_MAXHOSTNAMESIZE]; - size_t len; - char* utf8_str; - int convert_result; if (buffer == NULL || size == NULL || *size == 0) return UV_EINVAL; @@ -1544,22 +1369,7 @@ int uv_os_gethostname(char* buffer, size_t* size) { if (pGetHostNameW(buf, UV_MAXHOSTNAMESIZE) != 0) return uv_translate_sys_error(WSAGetLastError()); - convert_result = uv__convert_utf16_to_utf8(buf, -1, &utf8_str); - - if (convert_result != 0) - return convert_result; - - len = strlen(utf8_str); - if (len >= *size) { - *size = len + 1; - uv__free(utf8_str); - return UV_ENOBUFS; - } - - memcpy(buffer, utf8_str, len + 1); - uv__free(utf8_str); - *size = len; - return 0; + return uv__copy_utf16_to_utf8(buf, -1, buffer, size); } @@ -1665,7 +1475,7 @@ int uv_os_uname(uv_utsname_t* buffer) { HKEY registry_key; WCHAR product_name_w[256]; DWORD product_name_w_size; - int version_size; + size_t version_size; int processor_level; int r; @@ -1727,37 +1537,29 @@ int uv_os_uname(uv_utsname_t* buffer) { } } - version_size = WideCharToMultiByte(CP_UTF8, - 0, - product_name_w, - -1, - buffer->version, - sizeof(buffer->version), - NULL, - NULL); - if (version_size == 0) { - r = uv_translate_sys_error(GetLastError()); + version_size = sizeof(buffer->version); + r = uv__copy_utf16_to_utf8(product_name_w, + -1, + buffer->version, + &version_size); + if (r) goto error; - } } } /* Append service pack information to the version if present. */ if (os_info.szCSDVersion[0] != L'\0') { if (version_size > 0) - buffer->version[version_size - 1] = ' '; + buffer->version[version_size++] = ' '; - if (WideCharToMultiByte(CP_UTF8, - 0, - os_info.szCSDVersion, - -1, - buffer->version + version_size, - sizeof(buffer->version) - version_size, - NULL, - NULL) == 0) { - r = uv_translate_sys_error(GetLastError()); + version_size = sizeof(buffer->version) - version_size; + r = uv__copy_utf16_to_utf8(os_info.szCSDVersion, + -1, + buffer->version + + sizeof(buffer->version) - version_size, + &version_size); + if (r) goto error; - } } /* Populate the sysname field. */ diff --git a/test/test-idna.c b/test/test-idna.c index 371b2d58..bcacfc8a 100644 --- a/test/test-idna.c +++ b/test/test-idna.c @@ -20,6 +20,7 @@ */ #include "task.h" +#define uv__malloc malloc #include "../src/idna.c" #include