Commit 0d7f3f52 by Edward Thomson Committed by Edward Thomson

utf8: add conversion with size and refactor names

Add functions to use convert a string with length, instead of assuming
NUL termination.

In addition, move the utf8 to 16 conversion routines into the `git_utf8`
namespace instead of using namespaceless `git__` prefixed names.
parent cff0d9b1
...@@ -661,7 +661,7 @@ static int schannel_stream_wrap( ...@@ -661,7 +661,7 @@ static int schannel_stream_wrap(
st->io = in; st->io = in;
st->owned = owned; st->owned = owned;
if (git__utf8_to_16_alloc(&st->host_w, host) < 0) { if (git_utf8_to_16_alloc(&st->host_w, host) < 0) {
git__free(st); git__free(st);
return -1; return -1;
} }
......
...@@ -158,10 +158,10 @@ static int apply_userpass_credentials(HINTERNET request, DWORD target, int mecha ...@@ -158,10 +158,10 @@ static int apply_userpass_credentials(HINTERNET request, DWORD target, int mecha
goto done; goto done;
} }
if ((error = user_len = git__utf8_to_16_alloc(&user, c->username)) < 0) if ((error = user_len = git_utf8_to_16_alloc(&user, c->username)) < 0)
goto done; goto done;
if ((error = pass_len = git__utf8_to_16_alloc(&pass, c->password)) < 0) if ((error = pass_len = git_utf8_to_16_alloc(&pass, c->password)) < 0)
goto done; goto done;
if (!WinHttpSetCredentials(request, target, native_scheme, user, pass, NULL)) { if (!WinHttpSetCredentials(request, target, native_scheme, user, pass, NULL)) {
...@@ -242,7 +242,7 @@ static int acquire_fallback_cred( ...@@ -242,7 +242,7 @@ static int acquire_fallback_cred(
HRESULT hCoInitResult; HRESULT hCoInitResult;
/* Convert URL to wide characters */ /* Convert URL to wide characters */
if (git__utf8_to_16_alloc(&wide_url, url) < 0) { if (git_utf8_to_16_alloc(&wide_url, url) < 0) {
git_error_set(GIT_ERROR_OS, "failed to convert string to wide form"); git_error_set(GIT_ERROR_OS, "failed to convert string to wide form");
return -1; return -1;
} }
...@@ -397,7 +397,7 @@ static int winhttp_stream_connect(winhttp_stream *s) ...@@ -397,7 +397,7 @@ static int winhttp_stream_connect(winhttp_stream *s)
return -1; return -1;
/* Convert URL to wide characters */ /* Convert URL to wide characters */
if (git__utf8_to_16_alloc(&s->request_uri, git_str_cstr(&buf)) < 0) { if (git_utf8_to_16_alloc(&s->request_uri, git_str_cstr(&buf)) < 0) {
git_error_set(GIT_ERROR_OS, "failed to convert string to wide form"); git_error_set(GIT_ERROR_OS, "failed to convert string to wide form");
goto on_error; goto on_error;
} }
...@@ -473,7 +473,7 @@ static int winhttp_stream_connect(winhttp_stream *s) ...@@ -473,7 +473,7 @@ static int winhttp_stream_connect(winhttp_stream *s)
} }
/* Convert URL to wide characters */ /* Convert URL to wide characters */
error = git__utf8_to_16_alloc(&proxy_wide, processed_url.ptr); error = git_utf8_to_16_alloc(&proxy_wide, processed_url.ptr);
git_str_dispose(&processed_url); git_str_dispose(&processed_url);
if (error < 0) if (error < 0)
goto on_error; goto on_error;
...@@ -531,7 +531,7 @@ static int winhttp_stream_connect(winhttp_stream *s) ...@@ -531,7 +531,7 @@ static int winhttp_stream_connect(winhttp_stream *s)
s->service) < 0) s->service) < 0)
goto on_error; goto on_error;
if (git__utf8_to_16(ct, MAX_CONTENT_TYPE_LEN, git_str_cstr(&buf)) < 0) { if (git_utf8_to_16(ct, MAX_CONTENT_TYPE_LEN, git_str_cstr(&buf)) < 0) {
git_error_set(GIT_ERROR_OS, "failed to convert content-type to wide characters"); git_error_set(GIT_ERROR_OS, "failed to convert content-type to wide characters");
goto on_error; goto on_error;
} }
...@@ -548,7 +548,7 @@ static int winhttp_stream_connect(winhttp_stream *s) ...@@ -548,7 +548,7 @@ static int winhttp_stream_connect(winhttp_stream *s)
s->service) < 0) s->service) < 0)
goto on_error; goto on_error;
if (git__utf8_to_16(ct, MAX_CONTENT_TYPE_LEN, git_str_cstr(&buf)) < 0) { if (git_utf8_to_16(ct, MAX_CONTENT_TYPE_LEN, git_str_cstr(&buf)) < 0) {
git_error_set(GIT_ERROR_OS, "failed to convert accept header to wide characters"); git_error_set(GIT_ERROR_OS, "failed to convert accept header to wide characters");
goto on_error; goto on_error;
} }
...@@ -568,7 +568,7 @@ static int winhttp_stream_connect(winhttp_stream *s) ...@@ -568,7 +568,7 @@ static int winhttp_stream_connect(winhttp_stream *s)
git_str_puts(&buf, t->owner->connect_opts.custom_headers.strings[i]); git_str_puts(&buf, t->owner->connect_opts.custom_headers.strings[i]);
/* Convert header to wide characters */ /* Convert header to wide characters */
if ((error = git__utf8_to_16_alloc(&custom_header_wide, git_str_cstr(&buf))) < 0) if ((error = git_utf8_to_16_alloc(&custom_header_wide, git_str_cstr(&buf))) < 0)
goto on_error; goto on_error;
if (!WinHttpAddRequestHeaders(s->request, custom_header_wide, (ULONG)-1L, if (!WinHttpAddRequestHeaders(s->request, custom_header_wide, (ULONG)-1L,
...@@ -783,7 +783,7 @@ static int winhttp_connect( ...@@ -783,7 +783,7 @@ static int winhttp_connect(
} }
/* Prepare host */ /* Prepare host */
if (git__utf8_to_16_alloc(&wide_host, host) < 0) { if (git_utf8_to_16_alloc(&wide_host, host) < 0) {
git_error_set(GIT_ERROR_OS, "unable to convert host to wide characters"); git_error_set(GIT_ERROR_OS, "unable to convert host to wide characters");
goto on_error; goto on_error;
} }
...@@ -792,7 +792,7 @@ static int winhttp_connect( ...@@ -792,7 +792,7 @@ static int winhttp_connect(
if (git_http__user_agent(&ua) < 0) if (git_http__user_agent(&ua) < 0)
goto on_error; goto on_error;
if (git__utf8_to_16_alloc(&wide_ua, git_str_cstr(&ua)) < 0) { if (git_utf8_to_16_alloc(&wide_ua, git_str_cstr(&ua)) < 0) {
git_error_set(GIT_ERROR_OS, "unable to convert host to wide characters"); git_error_set(GIT_ERROR_OS, "unable to convert host to wide characters");
goto on_error; goto on_error;
} }
...@@ -1182,7 +1182,7 @@ replay: ...@@ -1182,7 +1182,7 @@ replay:
} }
/* Convert the Location header to UTF-8 */ /* Convert the Location header to UTF-8 */
if (git__utf16_to_8_alloc(&location8, location) < 0) { if (git_utf8_from_16_alloc(&location8, location) < 0) {
git_error_set(GIT_ERROR_OS, "failed to convert Location header to UTF-8"); git_error_set(GIT_ERROR_OS, "failed to convert Location header to UTF-8");
git__free(location); git__free(location);
return -1; return -1;
...@@ -1254,7 +1254,7 @@ replay: ...@@ -1254,7 +1254,7 @@ replay:
else else
p_snprintf(expected_content_type_8, MAX_CONTENT_TYPE_LEN, "application/x-git-%s-advertisement", s->service); p_snprintf(expected_content_type_8, MAX_CONTENT_TYPE_LEN, "application/x-git-%s-advertisement", s->service);
if (git__utf8_to_16(expected_content_type, MAX_CONTENT_TYPE_LEN, expected_content_type_8) < 0) { if (git_utf8_to_16(expected_content_type, MAX_CONTENT_TYPE_LEN, expected_content_type_8) < 0) {
git_error_set(GIT_ERROR_OS, "failed to convert expected content-type to wide characters"); git_error_set(GIT_ERROR_OS, "failed to convert expected content-type to wide characters");
return -1; return -1;
} }
......
...@@ -2015,7 +2015,7 @@ int git_fs_path_find_executable(git_str *fullpath, const char *executable) ...@@ -2015,7 +2015,7 @@ int git_fs_path_find_executable(git_str *fullpath, const char *executable)
git_win32_path fullpath_w, executable_w; git_win32_path fullpath_w, executable_w;
int error; int error;
if (git__utf8_to_16(executable_w, GIT_WIN_PATH_MAX, executable) < 0) if (git_utf8_to_16(executable_w, GIT_WIN_PATH_MAX, executable) < 0)
return -1; return -1;
error = git_win32_path_find_executable(fullpath_w, executable_w); error = git_win32_path_find_executable(fullpath_w, executable_w);
......
...@@ -743,7 +743,7 @@ int git__getenv(git_str *out, const char *name) ...@@ -743,7 +743,7 @@ int git__getenv(git_str *out, const char *name)
git_str_clear(out); git_str_clear(out);
if (git__utf8_to_16_alloc(&wide_name, name) < 0) if (git_utf8_to_16_alloc(&wide_name, name) < 0)
return -1; return -1;
if ((value_len = GetEnvironmentVariableW(wide_name, NULL, 0)) > 0) { if ((value_len = GetEnvironmentVariableW(wide_name, NULL, 0)) > 0) {
......
...@@ -43,7 +43,7 @@ char *git_win32_get_error_message(DWORD error_code) ...@@ -43,7 +43,7 @@ char *git_win32_get_error_message(DWORD error_code)
(LPWSTR)&lpMsgBuf, 0, NULL)) { (LPWSTR)&lpMsgBuf, 0, NULL)) {
/* Convert the message to UTF-8. If this fails, we will /* Convert the message to UTF-8. If this fails, we will
* return NULL, which is a condition expected by the caller */ * return NULL, which is a condition expected by the caller */
if (git__utf16_to_8_alloc(&utf8_msg, lpMsgBuf) < 0) if (git_utf8_from_16_alloc(&utf8_msg, lpMsgBuf) < 0)
utf8_msg = NULL; utf8_msg = NULL;
LocalFree(lpMsgBuf); LocalFree(lpMsgBuf);
......
...@@ -336,13 +336,13 @@ int git_win32_path_from_utf8(git_win32_path out, const char *src) ...@@ -336,13 +336,13 @@ int git_win32_path_from_utf8(git_win32_path out, const char *src)
/* See if this is an absolute path (beginning with a drive letter) */ /* See if this is an absolute path (beginning with a drive letter) */
if (git_fs_path_is_absolute(src)) { if (git_fs_path_is_absolute(src)) {
if (git__utf8_to_16(dest, GIT_WIN_PATH_MAX, src) < 0) if (git_utf8_to_16(dest, GIT_WIN_PATH_MAX, src) < 0)
goto on_error; goto on_error;
} }
/* File-prefixed NT-style paths beginning with \\?\ */ /* File-prefixed NT-style paths beginning with \\?\ */
else if (path__is_nt_namespace(src)) { else if (path__is_nt_namespace(src)) {
/* Skip the NT prefix, the destination already contains it */ /* Skip the NT prefix, the destination already contains it */
if (git__utf8_to_16(dest, GIT_WIN_PATH_MAX, src + PATH__NT_NAMESPACE_LEN) < 0) if (git_utf8_to_16(dest, GIT_WIN_PATH_MAX, src + PATH__NT_NAMESPACE_LEN) < 0)
goto on_error; goto on_error;
} }
/* UNC paths */ /* UNC paths */
...@@ -351,7 +351,7 @@ int git_win32_path_from_utf8(git_win32_path out, const char *src) ...@@ -351,7 +351,7 @@ int git_win32_path_from_utf8(git_win32_path out, const char *src)
dest += 4; dest += 4;
/* Skip the leading "\\" */ /* Skip the leading "\\" */
if (git__utf8_to_16(dest, GIT_WIN_PATH_MAX - 2, src + 2) < 0) if (git_utf8_to_16(dest, GIT_WIN_PATH_MAX - 2, src + 2) < 0)
goto on_error; goto on_error;
} }
/* Absolute paths omitting the drive letter */ /* Absolute paths omitting the drive letter */
...@@ -365,7 +365,7 @@ int git_win32_path_from_utf8(git_win32_path out, const char *src) ...@@ -365,7 +365,7 @@ int git_win32_path_from_utf8(git_win32_path out, const char *src)
} }
/* Skip the drive letter specification ("C:") */ /* Skip the drive letter specification ("C:") */
if (git__utf8_to_16(dest + 2, GIT_WIN_PATH_MAX - 2, src) < 0) if (git_utf8_to_16(dest + 2, GIT_WIN_PATH_MAX - 2, src) < 0)
goto on_error; goto on_error;
} }
/* Relative paths */ /* Relative paths */
...@@ -377,7 +377,7 @@ int git_win32_path_from_utf8(git_win32_path out, const char *src) ...@@ -377,7 +377,7 @@ int git_win32_path_from_utf8(git_win32_path out, const char *src)
dest[cwd_len++] = L'\\'; dest[cwd_len++] = L'\\';
if (git__utf8_to_16(dest + cwd_len, GIT_WIN_PATH_MAX - cwd_len, src) < 0) if (git_utf8_to_16(dest + cwd_len, GIT_WIN_PATH_MAX - cwd_len, src) < 0)
goto on_error; goto on_error;
} }
...@@ -404,7 +404,7 @@ int git_win32_path_relative_from_utf8(git_win32_path out, const char *src) ...@@ -404,7 +404,7 @@ int git_win32_path_relative_from_utf8(git_win32_path out, const char *src)
return git_win32_path_from_utf8(out, src); return git_win32_path_from_utf8(out, src);
} }
if ((len = git__utf8_to_16(dest, GIT_WIN_PATH_MAX, src)) < 0) if ((len = git_utf8_to_16(dest, GIT_WIN_PATH_MAX, src)) < 0)
return -1; return -1;
for (p = dest; p < (dest + len); p++) { for (p = dest; p < (dest + len); p++) {
...@@ -433,7 +433,7 @@ int git_win32_path_to_utf8(git_win32_utf8_path dest, const wchar_t *src) ...@@ -433,7 +433,7 @@ int git_win32_path_to_utf8(git_win32_utf8_path dest, const wchar_t *src)
} }
} }
if ((len = git__utf16_to_8(out, GIT_WIN_PATH_UTF8, src)) < 0) if ((len = git_utf8_from_16(out, GIT_WIN_PATH_UTF8, src)) < 0)
return len; return len;
git_fs_path_mkposix(dest); git_fs_path_mkposix(dest);
...@@ -471,7 +471,7 @@ char *git_win32_path_8dot3_name(const char *path) ...@@ -471,7 +471,7 @@ char *git_win32_path_8dot3_name(const char *path)
if (namelen > 12 || (shortname = git__malloc(namelen + 1)) == NULL) if (namelen > 12 || (shortname = git__malloc(namelen + 1)) == NULL)
return NULL; return NULL;
if ((len = git__utf16_to_8(shortname, namelen + 1, start)) < 0) if ((len = git_utf8_from_16(shortname, namelen + 1, start)) < 0)
return NULL; return NULL;
return shortname; return shortname;
......
...@@ -649,7 +649,7 @@ int p_getcwd(char *buffer_out, size_t size) ...@@ -649,7 +649,7 @@ int p_getcwd(char *buffer_out, size_t size)
git_win32_path_remove_namespace(cwd, wcslen(cwd)); git_win32_path_remove_namespace(cwd, wcslen(cwd));
/* Convert the working directory back to UTF-8 */ /* Convert the working directory back to UTF-8 */
if (git__utf16_to_8(buffer_out, size, cwd) < 0) { if (git_utf8_from_16(buffer_out, size, cwd) < 0) {
DWORD code = GetLastError(); DWORD code = GetLastError();
if (code == ERROR_INSUFFICIENT_BUFFER) if (code == ERROR_INSUFFICIENT_BUFFER)
......
...@@ -15,108 +15,114 @@ GIT_INLINE(void) git__set_errno(void) ...@@ -15,108 +15,114 @@ GIT_INLINE(void) git__set_errno(void)
errno = EINVAL; errno = EINVAL;
} }
/** int git_utf8_to_16(wchar_t *dest, size_t dest_size, const char *src)
* Converts a UTF-8 string to wide characters. {
* /* Length of -1 indicates NULL termination of the input string. */
* @param dest The buffer to receive the wide string. return git_utf8_to_16_with_len(dest, dest_size, src, -1);
* @param dest_size The size of the buffer, in characters. }
* @param src The UTF-8 string to convert.
* @return The length of the wide string, in characters (not counting the NULL terminator), or < 0 for failure int git_utf8_to_16_with_len(
*/ wchar_t *dest,
int git__utf8_to_16(wchar_t *dest, size_t dest_size, const char *src) size_t _dest_size,
const char *src,
int src_len)
{ {
int dest_size = (int)min(_dest_size, INT_MAX);
int len; int len;
/* Length of -1 indicates NULL termination of the input string. Subtract 1 from the result to /*
* turn 0 into -1 (an error code) and to not count the NULL terminator as part of the string's * Subtract 1 from the result to turn 0 into -1 (an error code) and
* length. MultiByteToWideChar never returns int's minvalue, so underflow is not possible */ * to not count the NULL terminator as part of the string's length.
if ((len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src, -1, dest, (int)dest_size) - 1) < 0) * MultiByteToWideChar never returns int's minvalue, so underflow
* is not possible.
*/
len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
src, src_len, dest, dest_size) - 1;
if (len < 0)
git__set_errno(); git__set_errno();
return len; return len;
} }
/** int git_utf8_from_16(char *dest, size_t dest_size, const wchar_t *src)
* Converts a wide string to UTF-8.
*
* @param dest The buffer to receive the UTF-8 string.
* @param dest_size The size of the buffer, in bytes.
* @param src The wide string to convert.
* @return The length of the UTF-8 string, in bytes (not counting the NULL terminator), or < 0 for failure
*/
int git__utf16_to_8(char *dest, size_t dest_size, const wchar_t *src)
{ {
/* Length of -1 indicates NULL termination of the input string. */
return git_utf8_from_16_with_len(dest, dest_size, src, -1);
}
int git_utf8_from_16_with_len(
char *dest,
size_t _dest_size,
const wchar_t *src,
int src_len)
{
int dest_size = (int)min(_dest_size, INT_MAX);
int len; int len;
/* Length of -1 indicates NULL termination of the input string. Subtract 1 from the result to /*
* turn 0 into -1 (an error code) and to not count the NULL terminator as part of the string's * Subtract 1 from the result to turn 0 into -1 (an error code) and
* length. WideCharToMultiByte never returns int's minvalue, so underflow is not possible */ * to not count the NULL terminator as part of the string's length.
if ((len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, src, -1, dest, (int)dest_size, NULL, NULL) - 1) < 0) * WideCharToMultiByte never returns int's minvalue, so underflow
* is not possible.
*/
len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS,
src, src_len, dest, dest_size, NULL, NULL) - 1;
if (len < 0)
git__set_errno(); git__set_errno();
return len; return len;
} }
/** int git_utf8_to_16_alloc(wchar_t **dest, const char *src)
* Converts a UTF-8 string to wide characters. {
* Memory is allocated to hold the converted string. /* Length of -1 indicates NULL termination of the input string. */
* The caller is responsible for freeing the string with git__free. return git_utf8_to_16_alloc_with_len(dest, src, -1);
* }
* @param dest Receives a pointer to the wide string.
* @param src The UTF-8 string to convert. int git_utf8_to_16_alloc_with_len(wchar_t **dest, const char *src, int src_len)
* @return The length of the wide string, in characters (not counting the NULL terminator), or < 0 for failure
*/
int git__utf8_to_16_alloc(wchar_t **dest, const char *src)
{ {
int utf16_size; int utf16_size;
*dest = NULL; *dest = NULL;
/* Length of -1 indicates NULL termination of the input string */ utf16_size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
utf16_size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src, -1, NULL, 0); src, src_len, NULL, 0);
if (!utf16_size) { if (!utf16_size) {
git__set_errno(); git__set_errno();
return -1; return -1;
} }
if (!(*dest = git__mallocarray(utf16_size, sizeof(wchar_t)))) { *dest = git__mallocarray(utf16_size, sizeof(wchar_t));
errno = ENOMEM; GIT_ERROR_CHECK_ALLOC(*dest);
return -1;
}
utf16_size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src, -1, *dest, utf16_size); utf16_size = git_utf8_to_16_with_len(*dest, (size_t)utf16_size,
src, src_len);
if (!utf16_size) {
git__set_errno();
if (utf16_size < 0) {
git__free(*dest); git__free(*dest);
*dest = NULL; *dest = NULL;
} }
/* Subtract 1 from the result to turn 0 into -1 (an error code) and to not count the NULL return utf16_size;
* terminator as part of the string's length. MultiByteToWideChar never returns int's minvalue,
* so underflow is not possible */
return utf16_size - 1;
} }
/** int git_utf8_from_16_alloc(char **dest, const wchar_t *src)
* Converts a wide string to UTF-8. {
* Memory is allocated to hold the converted string. /* Length of -1 indicates NULL termination of the input string. */
* The caller is responsible for freeing the string with git__free. return git_utf8_from_16_alloc_with_len(dest, src, -1);
* }
* @param dest Receives a pointer to the UTF-8 string.
* @param src The wide string to convert. int git_utf8_from_16_alloc_with_len(char **dest, const wchar_t *src, int src_len)
* @return The length of the UTF-8 string, in bytes (not counting the NULL terminator), or < 0 for failure
*/
int git__utf16_to_8_alloc(char **dest, const wchar_t *src)
{ {
int utf8_size; int utf8_size;
*dest = NULL; *dest = NULL;
/* Length of -1 indicates NULL termination of the input string */ utf8_size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS,
utf8_size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, src, -1, NULL, 0, NULL, NULL); src, src_len, NULL, 0, NULL, NULL);
if (!utf8_size) { if (!utf8_size) {
git__set_errno(); git__set_errno();
...@@ -124,23 +130,15 @@ int git__utf16_to_8_alloc(char **dest, const wchar_t *src) ...@@ -124,23 +130,15 @@ int git__utf16_to_8_alloc(char **dest, const wchar_t *src)
} }
*dest = git__malloc(utf8_size); *dest = git__malloc(utf8_size);
GIT_ERROR_CHECK_ALLOC(*dest);
if (!*dest) { utf8_size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS,
errno = ENOMEM; src, src_len, *dest, utf8_size, NULL, NULL);
return -1;
}
utf8_size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, src, -1, *dest, utf8_size, NULL, NULL);
if (!utf8_size) {
git__set_errno();
if (utf8_size < 0) {
git__free(*dest); git__free(*dest);
*dest = NULL; *dest = NULL;
} }
/* Subtract 1 from the result to turn 0 into -1 (an error code) and to not count the NULL return utf8_size;
* terminator as part of the string's length. MultiByteToWideChar never returns int's minvalue,
* so underflow is not possible */
return utf8_size - 1;
} }
...@@ -16,14 +16,45 @@ ...@@ -16,14 +16,45 @@
#endif #endif
/** /**
* Converts a NUL-terminated UTF-8 string to wide characters. This is a
* convenience function for `git_utf8_to_16_with_len`.
*
* @param dest The buffer to receive the wide string.
* @param dest_size The size of the buffer, in characters.
* @param src The UTF-8 string to convert.
* @return The length of the wide string, in characters
* (not counting the NULL terminator), or < 0 for failure
*/
int git_utf8_to_16(wchar_t *dest, size_t dest_size, const char *src);
/**
* Converts a UTF-8 string to wide characters. * Converts a UTF-8 string to wide characters.
* *
* @param dest The buffer to receive the wide string. * @param dest The buffer to receive the wide string.
* @param dest_size The size of the buffer, in characters. * @param dest_size The size of the buffer, in characters.
* @param src The UTF-8 string to convert. * @param src The UTF-8 string to convert.
* @return The length of the wide string, in characters (not counting the NULL terminator), or < 0 for failure * @param src_len The length of the string to convert.
* @return The length of the wide string, in characters
* (not counting the NULL terminator), or < 0 for failure
*/
int git_utf8_to_16_with_len(
wchar_t *dest,
size_t dest_size,
const char *src,
int src_len);
/**
* Converts a NUL-terminated wide string to UTF-8. This is a convenience
* function for `git_utf8_from_16_with_len`.
*
* @param dest The buffer to receive the UTF-8 string.
* @param dest_size The size of the buffer, in bytes.
* @param src The wide string to convert.
* @param src_len The length of the string to convert.
* @return The length of the UTF-8 string, in bytes
* (not counting the NULL terminator), or < 0 for failure
*/ */
int git__utf8_to_16(wchar_t *dest, size_t dest_size, const char *src); int git_utf8_from_16(char *dest, size_t dest_size, const wchar_t *src);
/** /**
* Converts a wide string to UTF-8. * Converts a wide string to UTF-8.
...@@ -31,30 +62,66 @@ int git__utf8_to_16(wchar_t *dest, size_t dest_size, const char *src); ...@@ -31,30 +62,66 @@ int git__utf8_to_16(wchar_t *dest, size_t dest_size, const char *src);
* @param dest The buffer to receive the UTF-8 string. * @param dest The buffer to receive the UTF-8 string.
* @param dest_size The size of the buffer, in bytes. * @param dest_size The size of the buffer, in bytes.
* @param src The wide string to convert. * @param src The wide string to convert.
* @return The length of the UTF-8 string, in bytes (not counting the NULL terminator), or < 0 for failure * @param src_len The length of the string to convert.
* @return The length of the UTF-8 string, in bytes
* (not counting the NULL terminator), or < 0 for failure
*/ */
int git__utf16_to_8(char *dest, size_t dest_size, const wchar_t *src); int git_utf8_from_16_with_len(char *dest, size_t dest_size, const wchar_t *src, int src_len);
/** /**
* Converts a UTF-8 string to wide characters. * Converts a UTF-8 string to wide characters. Memory is allocated to hold
* Memory is allocated to hold the converted string. * the converted string. The caller is responsible for freeing the string
* The caller is responsible for freeing the string with git__free. * with git__free.
* *
* @param dest Receives a pointer to the wide string. * @param dest Receives a pointer to the wide string.
* @param src The UTF-8 string to convert. * @param src The UTF-8 string to convert.
* @return The length of the wide string, in characters (not counting the NULL terminator), or < 0 for failure * @return The length of the wide string, in characters
* (not counting the NULL terminator), or < 0 for failure
*/ */
int git__utf8_to_16_alloc(wchar_t **dest, const char *src); int git_utf8_to_16_alloc(wchar_t **dest, const char *src);
/** /**
* Converts a wide string to UTF-8. * Converts a UTF-8 string to wide characters. Memory is allocated to hold
* Memory is allocated to hold the converted string. * the converted string. The caller is responsible for freeing the string
* The caller is responsible for freeing the string with git__free. * with git__free.
*
* @param dest Receives a pointer to the wide string.
* @param src The UTF-8 string to convert.
* @param src_len The length of the string.
* @return The length of the wide string, in characters
* (not counting the NULL terminator), or < 0 for failure
*/
int git_utf8_to_16_alloc_with_len(
wchar_t **dest,
const char *src,
int src_len);
/**
* Converts a wide string to UTF-8. Memory is allocated to hold the
* converted string. The caller is responsible for freeing the string
* with git__free.
*
* @param dest Receives a pointer to the UTF-8 string.
* @param src The wide string to convert.
* @return The length of the UTF-8 string, in bytes
* (not counting the NULL terminator), or < 0 for failure
*/
int git_utf8_from_16_alloc(char **dest, const wchar_t *src);
/**
* Converts a wide string to UTF-8. Memory is allocated to hold the
* converted string. The caller is responsible for freeing the string
* with git__free.
* *
* @param dest Receives a pointer to the UTF-8 string. * @param dest Receives a pointer to the UTF-8 string.
* @param src The wide string to convert. * @param src The wide string to convert.
* @return The length of the UTF-8 string, in bytes (not counting the NULL terminator), or < 0 for failure * @param src_len The length of the wide string.
* @return The length of the UTF-8 string, in bytes
* (not counting the NULL terminator), or < 0 for failure
*/ */
int git__utf16_to_8_alloc(char **dest, const wchar_t *src); int git_utf8_from_16_alloc_with_len(
char **dest,
const wchar_t *src,
int src_len);
#endif #endif
...@@ -115,7 +115,7 @@ int git_win32__file_attribute_to_stat( ...@@ -115,7 +115,7 @@ int git_win32__file_attribute_to_stat(
/* st_size gets the UTF-8 length of the target name, in bytes, /* st_size gets the UTF-8 length of the target name, in bytes,
* not counting the NULL terminator */ * not counting the NULL terminator */
if ((st->st_size = git__utf16_to_8(NULL, 0, target)) < 0) { if ((st->st_size = git_utf8_from_16(NULL, 0, target)) < 0) {
git_error_set(GIT_ERROR_OS, "could not convert reparse point name for '%ls'", path); git_error_set(GIT_ERROR_OS, "could not convert reparse point name for '%ls'", path);
return -1; return -1;
} }
......
...@@ -103,10 +103,10 @@ int cl_setenv(const char *name, const char *value) ...@@ -103,10 +103,10 @@ int cl_setenv(const char *name, const char *value)
{ {
wchar_t *wide_name, *wide_value = NULL; wchar_t *wide_name, *wide_value = NULL;
cl_assert(git__utf8_to_16_alloc(&wide_name, name) >= 0); cl_assert(git_utf8_to_16_alloc(&wide_name, name) >= 0);
if (value) { if (value) {
cl_assert(git__utf8_to_16_alloc(&wide_value, value) >= 0); cl_assert(git_utf8_to_16_alloc(&wide_value, value) >= 0);
cl_assert(SetEnvironmentVariableW(wide_name, wide_value)); cl_assert(SetEnvironmentVariableW(wide_name, wide_value));
} else { } else {
/* Windows XP returns 0 (failed) when passing NULL for lpValue when /* Windows XP returns 0 (failed) when passing NULL for lpValue when
......
...@@ -98,7 +98,7 @@ static void do_junction(const char *old, const char *new) ...@@ -98,7 +98,7 @@ static void do_junction(const char *old, const char *new)
git_str_putc(&unparsed_buf, '\\'); git_str_putc(&unparsed_buf, '\\');
subst_utf16_len = git__utf8_to_16(NULL, 0, git_str_cstr(&unparsed_buf)); subst_utf16_len = git_utf8_to_16(NULL, 0, git_str_cstr(&unparsed_buf));
subst_byte_len = subst_utf16_len * sizeof(WCHAR); subst_byte_len = subst_utf16_len * sizeof(WCHAR);
print_utf16_len = subst_utf16_len - 4; print_utf16_len = subst_utf16_len - 4;
...@@ -124,11 +124,11 @@ static void do_junction(const char *old, const char *new) ...@@ -124,11 +124,11 @@ static void do_junction(const char *old, const char *new)
subst_utf16 = reparse_buf->ReparseBuffer.MountPoint.PathBuffer; subst_utf16 = reparse_buf->ReparseBuffer.MountPoint.PathBuffer;
print_utf16 = subst_utf16 + subst_utf16_len + 1; print_utf16 = subst_utf16 + subst_utf16_len + 1;
ret = git__utf8_to_16(subst_utf16, subst_utf16_len + 1, ret = git_utf8_to_16(subst_utf16, subst_utf16_len + 1,
git_str_cstr(&unparsed_buf)); git_str_cstr(&unparsed_buf));
cl_assert_equal_i(subst_utf16_len, ret); cl_assert_equal_i(subst_utf16_len, ret);
ret = git__utf8_to_16(print_utf16, ret = git_utf8_to_16(print_utf16,
print_utf16_len + 1, git_str_cstr(&unparsed_buf) + 4); print_utf16_len + 1, git_str_cstr(&unparsed_buf) + 4);
cl_assert_equal_i(print_utf16_len, ret); cl_assert_equal_i(print_utf16_len, ret);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment