Commit 4d383403 by Vicent Martí

Merge pull request #856 from libgit2/utf8-win

Windows: Perform UTF-8 path conversion on the Stack
parents c9d223f0 0f4c6175
/*
* Copyright (C) 2009-2012 the libgit2 contributors
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#ifndef INCLUDE_git_windows_h__
#define INCLUDE_git_windows_h__
#include "common.h"
/**
* @file git2/windows.h
* @brief Windows-specific functions
* @ingroup Git
* @{
*/
GIT_BEGIN_DECL
/**
* Set the active codepage for Windows syscalls
*
* All syscalls performed by the library will assume
* this codepage when converting paths and strings
* to use by the Windows kernel.
*
* The default value of UTF-8 will work automatically
* with most Git repositories created on Unix systems.
*
* This settings needs only be changed when working
* with repositories that contain paths in specific,
* non-UTF codepages.
*
* A full list of all available codepage identifiers may
* be found at:
*
* http://msdn.microsoft.com/en-us/library/windows/desktop/dd317756(v=vs.85).aspx
*
* @param codepage numeric codepage identifier
*/
GIT_EXTERN(void) gitwin_set_codepage(unsigned int codepage);
/**
* Return the active codepage for Windows syscalls
*
* @return numeric codepage identifier
*/
GIT_EXTERN(unsigned int) gitwin_get_codepage(void);
/**
* Set the active Windows codepage to UTF-8 (this is
* the default value)
*/
GIT_EXTERN(void) gitwin_set_utf8(void);
/** @} */
GIT_END_DECL
#endif
...@@ -54,11 +54,10 @@ int git_futils_creat_locked(const char *path, const mode_t mode) ...@@ -54,11 +54,10 @@ int git_futils_creat_locked(const char *path, const mode_t mode)
int fd; int fd;
#ifdef GIT_WIN32 #ifdef GIT_WIN32
wchar_t* buf; wchar_t buf[GIT_WIN_PATH];
buf = gitwin_to_utf16(path); git__utf8_to_16(buf, GIT_WIN_PATH, path);
fd = _wopen(buf, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_EXCL, mode); fd = _wopen(buf, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_EXCL, mode);
git__free(buf);
#else #else
fd = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_EXCL, mode); fd = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_EXCL, mode);
#endif #endif
...@@ -382,16 +381,16 @@ static int win32_expand_path(struct win32_path *s_root, const wchar_t *templ) ...@@ -382,16 +381,16 @@ static int win32_expand_path(struct win32_path *s_root, const wchar_t *templ)
static int win32_find_file(git_buf *path, const struct win32_path *root, const char *filename) static int win32_find_file(git_buf *path, const struct win32_path *root, const char *filename)
{ {
int error = 0; size_t len, alloc_len;
size_t len;
wchar_t *file_utf16 = NULL; wchar_t *file_utf16 = NULL;
char *file_utf8 = NULL; char file_utf8[GIT_PATH_MAX];
if (!root || !filename || (len = strlen(filename)) == 0) if (!root || !filename || (len = strlen(filename)) == 0)
return GIT_ENOTFOUND; return GIT_ENOTFOUND;
/* allocate space for wchar_t path to file */ /* allocate space for wchar_t path to file */
file_utf16 = git__calloc(root->len + len + 2, sizeof(wchar_t)); alloc_len = root->len + len + 2;
file_utf16 = git__calloc(alloc_len, sizeof(wchar_t));
GITERR_CHECK_ALLOC(file_utf16); GITERR_CHECK_ALLOC(file_utf16);
/* append root + '\\' + filename as wchar_t */ /* append root + '\\' + filename as wchar_t */
...@@ -400,29 +399,20 @@ static int win32_find_file(git_buf *path, const struct win32_path *root, const c ...@@ -400,29 +399,20 @@ static int win32_find_file(git_buf *path, const struct win32_path *root, const c
if (*filename == '/' || *filename == '\\') if (*filename == '/' || *filename == '\\')
filename++; filename++;
if (gitwin_append_utf16(file_utf16 + root->len - 1, filename, len + 1) != git__utf8_to_16(file_utf16 + root->len - 1, alloc_len, filename);
(int)len + 1) {
error = -1;
goto cleanup;
}
/* check access */ /* check access */
if (_waccess(file_utf16, F_OK) < 0) { if (_waccess(file_utf16, F_OK) < 0) {
error = GIT_ENOTFOUND; git__free(file_utf16);
goto cleanup; return GIT_ENOTFOUND;
} }
/* convert to utf8 */ git__utf16_to_8(file_utf8, file_utf16);
if ((file_utf8 = gitwin_from_utf16(file_utf16)) == NULL)
error = -1;
else {
git_path_mkposix(file_utf8); git_path_mkposix(file_utf8);
git_buf_attach(path, file_utf8, 0); git_buf_sets(path, file_utf8);
}
cleanup:
git__free(file_utf16); git__free(file_utf16);
return error; return 0;
} }
#endif #endif
......
...@@ -432,14 +432,14 @@ bool git_path_is_empty_dir(const char *path) ...@@ -432,14 +432,14 @@ bool git_path_is_empty_dir(const char *path)
{ {
git_buf pathbuf = GIT_BUF_INIT; git_buf pathbuf = GIT_BUF_INIT;
HANDLE hFind = INVALID_HANDLE_VALUE; HANDLE hFind = INVALID_HANDLE_VALUE;
wchar_t *wbuf; wchar_t wbuf[GIT_WIN_PATH];
WIN32_FIND_DATAW ffd; WIN32_FIND_DATAW ffd;
bool retval = true; bool retval = true;
if (!git_path_isdir(path)) return false; if (!git_path_isdir(path)) return false;
git_buf_printf(&pathbuf, "%s\\*", path); git_buf_printf(&pathbuf, "%s\\*", path);
wbuf = gitwin_to_utf16(git_buf_cstr(&pathbuf)); git__utf8_to_16(wbuf, GIT_WIN_PATH, git_buf_cstr(&pathbuf));
hFind = FindFirstFileW(wbuf, &ffd); hFind = FindFirstFileW(wbuf, &ffd);
if (INVALID_HANDLE_VALUE == hFind) { if (INVALID_HANDLE_VALUE == hFind) {
...@@ -455,7 +455,6 @@ bool git_path_is_empty_dir(const char *path) ...@@ -455,7 +455,6 @@ bool git_path_is_empty_dir(const char *path)
FindClose(hFind); FindClose(hFind);
git_buf_free(&pathbuf); git_buf_free(&pathbuf);
git__free(wbuf);
return retval; return retval;
} }
......
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
#define GIT__WIN32_NO_WRAP_DIR #define GIT__WIN32_NO_WRAP_DIR
#include "dir.h" #include "dir.h"
#include "utf-conv.h" #include "utf-conv.h"
#include "git2/windows.h"
static int init_filter(char *filter, size_t n, const char *dir) static int init_filter(char *filter, size_t n, const char *dir)
{ {
...@@ -26,8 +25,8 @@ static int init_filter(char *filter, size_t n, const char *dir) ...@@ -26,8 +25,8 @@ static int init_filter(char *filter, size_t n, const char *dir)
git__DIR *git__opendir(const char *dir) git__DIR *git__opendir(const char *dir)
{ {
char filter[4096]; char filter[GIT_WIN_PATH];
wchar_t* filter_w = NULL; wchar_t filter_w[GIT_WIN_PATH];
git__DIR *new = NULL; git__DIR *new = NULL;
if (!dir || !init_filter(filter, sizeof(filter), dir)) if (!dir || !init_filter(filter, sizeof(filter), dir))
...@@ -41,12 +40,8 @@ git__DIR *git__opendir(const char *dir) ...@@ -41,12 +40,8 @@ git__DIR *git__opendir(const char *dir)
if (!new->dir) if (!new->dir)
goto fail; goto fail;
filter_w = gitwin_to_utf16(filter); git__utf8_to_16(filter_w, GIT_WIN_PATH, filter);
if (!filter_w)
goto fail;
new->h = FindFirstFileW(filter_w, &new->f); new->h = FindFirstFileW(filter_w, &new->f);
git__free(filter_w);
if (new->h == INVALID_HANDLE_VALUE) { if (new->h == INVALID_HANDLE_VALUE) {
giterr_set(GITERR_OS, "Could not open directory '%s'", dir); giterr_set(GITERR_OS, "Could not open directory '%s'", dir);
...@@ -85,16 +80,9 @@ int git__readdir_ext( ...@@ -85,16 +80,9 @@ int git__readdir_ext(
if (wcslen(d->f.cFileName) >= sizeof(entry->d_name)) if (wcslen(d->f.cFileName) >= sizeof(entry->d_name))
return -1; return -1;
git__utf16_to_8(entry->d_name, d->f.cFileName);
entry->d_ino = 0; entry->d_ino = 0;
if (WideCharToMultiByte(
gitwin_get_codepage(), 0, d->f.cFileName, -1,
entry->d_name, GIT_PATH_MAX, NULL, NULL) == 0)
{
giterr_set(GITERR_OS, "Could not convert filename to UTF-8");
return -1;
}
*result = entry; *result = entry;
if (is_dir != NULL) if (is_dir != NULL)
...@@ -113,8 +101,8 @@ struct git__dirent *git__readdir(git__DIR *d) ...@@ -113,8 +101,8 @@ struct git__dirent *git__readdir(git__DIR *d)
void git__rewinddir(git__DIR *d) void git__rewinddir(git__DIR *d)
{ {
char filter[4096]; char filter[GIT_WIN_PATH];
wchar_t* filter_w; wchar_t filter_w[GIT_WIN_PATH];
if (!d) if (!d)
return; return;
...@@ -125,12 +113,11 @@ void git__rewinddir(git__DIR *d) ...@@ -125,12 +113,11 @@ void git__rewinddir(git__DIR *d)
d->first = 0; d->first = 0;
} }
if (!init_filter(filter, sizeof(filter), d->dir) || if (!init_filter(filter, sizeof(filter), d->dir))
(filter_w = gitwin_to_utf16(filter)) == NULL)
return; return;
git__utf8_to_16(filter_w, GIT_WIN_PATH, filter);
d->h = FindFirstFileW(filter_w, &d->f); d->h = FindFirstFileW(filter_w, &d->f);
git__free(filter_w);
if (d->h == INVALID_HANDLE_VALUE) if (d->h == INVALID_HANDLE_VALUE)
giterr_set(GITERR_OS, "Could not open directory '%s'", d->dir); giterr_set(GITERR_OS, "Could not open directory '%s'", d->dir);
......
...@@ -21,13 +21,10 @@ GIT_INLINE(int) p_link(const char *old, const char *new) ...@@ -21,13 +21,10 @@ GIT_INLINE(int) p_link(const char *old, const char *new)
GIT_INLINE(int) p_mkdir(const char *path, mode_t mode) GIT_INLINE(int) p_mkdir(const char *path, mode_t mode)
{ {
wchar_t* buf = gitwin_to_utf16(path); wchar_t buf[GIT_WIN_PATH];
int ret = _wmkdir(buf);
GIT_UNUSED(mode); GIT_UNUSED(mode);
git__utf8_to_16(buf, GIT_WIN_PATH, path);
git__free(buf); return _wmkdir(buf);
return ret;
} }
extern int p_unlink(const char *path); extern int p_unlink(const char *path);
......
...@@ -15,16 +15,10 @@ ...@@ -15,16 +15,10 @@
int p_unlink(const char *path) int p_unlink(const char *path)
{ {
int ret = 0; wchar_t buf[GIT_WIN_PATH];
wchar_t* buf; git__utf8_to_16(buf, GIT_WIN_PATH, path);
if ((buf = gitwin_to_utf16(path)) != NULL) {
_wchmod(buf, 0666); _wchmod(buf, 0666);
ret = _wunlink(buf); return _wunlink(buf);
git__free(buf);
}
return ret;
} }
int p_fsync(int fd) int p_fsync(int fd)
...@@ -61,10 +55,10 @@ GIT_INLINE(time_t) filetime_to_time_t(const FILETIME *ft) ...@@ -61,10 +55,10 @@ GIT_INLINE(time_t) filetime_to_time_t(const FILETIME *ft)
static int do_lstat(const char *file_name, struct stat *buf) static int do_lstat(const char *file_name, struct stat *buf)
{ {
WIN32_FILE_ATTRIBUTE_DATA fdata; WIN32_FILE_ATTRIBUTE_DATA fdata;
wchar_t fbuf[GIT_WIN_PATH];
DWORD last_error; DWORD last_error;
wchar_t* fbuf = gitwin_to_utf16(file_name);
if (!fbuf) git__utf8_to_16(fbuf, GIT_WIN_PATH, file_name);
return -1;
if (GetFileAttributesExW(fbuf, GetFileExInfoStandard, &fdata)) { if (GetFileAttributesExW(fbuf, GetFileExInfoStandard, &fdata)) {
int fMode = S_IREAD; int fMode = S_IREAD;
...@@ -90,8 +84,6 @@ static int do_lstat(const char *file_name, struct stat *buf) ...@@ -90,8 +84,6 @@ static int do_lstat(const char *file_name, struct stat *buf)
buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime));
buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
git__free(fbuf);
return 0; return 0;
} }
...@@ -101,7 +93,6 @@ static int do_lstat(const char *file_name, struct stat *buf) ...@@ -101,7 +93,6 @@ static int do_lstat(const char *file_name, struct stat *buf)
else if (last_error == ERROR_PATH_NOT_FOUND) else if (last_error == ERROR_PATH_NOT_FOUND)
errno = ENOTDIR; errno = ENOTDIR;
git__free(fbuf);
return -1; return -1;
} }
...@@ -143,7 +134,7 @@ int p_readlink(const char *link, char *target, size_t target_len) ...@@ -143,7 +134,7 @@ int p_readlink(const char *link, char *target, size_t target_len)
static fpath_func pGetFinalPath = NULL; static fpath_func pGetFinalPath = NULL;
HANDLE hFile; HANDLE hFile;
DWORD dwRet; DWORD dwRet;
wchar_t* link_w; wchar_t link_w[GIT_WIN_PATH];
wchar_t* target_w; wchar_t* target_w;
int error = 0; int error = 0;
...@@ -166,8 +157,7 @@ int p_readlink(const char *link, char *target, size_t target_len) ...@@ -166,8 +157,7 @@ int p_readlink(const char *link, char *target, size_t target_len)
} }
} }
link_w = gitwin_to_utf16(link); git__utf8_to_16(link_w, GIT_WIN_PATH, link);
GITERR_CHECK_ALLOC(link_w);
hFile = CreateFileW(link_w, // file to open hFile = CreateFileW(link_w, // file to open
GENERIC_READ, // open for reading GENERIC_READ, // open for reading
...@@ -177,8 +167,6 @@ int p_readlink(const char *link, char *target, size_t target_len) ...@@ -177,8 +167,6 @@ int p_readlink(const char *link, char *target, size_t target_len)
FILE_FLAG_BACKUP_SEMANTICS, // normal file FILE_FLAG_BACKUP_SEMANTICS, // normal file
NULL); // no attr. template NULL); // no attr. template
git__free(link_w);
if (hFile == INVALID_HANDLE_VALUE) { if (hFile == INVALID_HANDLE_VALUE) {
giterr_set(GITERR_OS, "Cannot open '%s' for reading", link); giterr_set(GITERR_OS, "Cannot open '%s' for reading", link);
return -1; return -1;
...@@ -235,16 +223,12 @@ int p_symlink(const char *old, const char *new) ...@@ -235,16 +223,12 @@ int p_symlink(const char *old, const char *new)
int p_open(const char *path, int flags, ...) int p_open(const char *path, int flags, ...)
{ {
int fd; wchar_t buf[GIT_WIN_PATH];
wchar_t* buf;
mode_t mode = 0; mode_t mode = 0;
buf = gitwin_to_utf16(path); git__utf8_to_16(buf, GIT_WIN_PATH, path);
if (!buf)
return -1;
if (flags & O_CREAT) if (flags & O_CREAT) {
{
va_list arg_list; va_list arg_list;
va_start(arg_list, flags); va_start(arg_list, flags);
...@@ -252,27 +236,20 @@ int p_open(const char *path, int flags, ...) ...@@ -252,27 +236,20 @@ int p_open(const char *path, int flags, ...)
va_end(arg_list); va_end(arg_list);
} }
fd = _wopen(buf, flags | _O_BINARY, mode); return _wopen(buf, flags | _O_BINARY, mode);
git__free(buf);
return fd;
} }
int p_creat(const char *path, mode_t mode) int p_creat(const char *path, mode_t mode)
{ {
int fd; wchar_t buf[GIT_WIN_PATH];
wchar_t* buf = gitwin_to_utf16(path); git__utf8_to_16(buf, GIT_WIN_PATH, path);
if (!buf) return _wopen(buf, _O_WRONLY | _O_CREAT | _O_TRUNC | _O_BINARY, mode);
return -1;
fd = _wopen(buf, _O_WRONLY | _O_CREAT | _O_TRUNC | _O_BINARY, mode);
git__free(buf);
return fd;
} }
int p_getcwd(char *buffer_out, size_t size) int p_getcwd(char *buffer_out, size_t size)
{ {
int ret; int ret;
wchar_t* buf; wchar_t *buf;
if ((size_t)((int)size) != size) if ((size_t)((int)size) != size)
return -1; return -1;
...@@ -296,64 +273,43 @@ int p_stat(const char* path, struct stat* buf) ...@@ -296,64 +273,43 @@ int p_stat(const char* path, struct stat* buf)
int p_chdir(const char* path) int p_chdir(const char* path)
{ {
wchar_t* buf = gitwin_to_utf16(path); wchar_t buf[GIT_WIN_PATH];
int ret; git__utf8_to_16(buf, GIT_WIN_PATH, path);
if (!buf) return _wchdir(buf);
return -1;
ret = _wchdir(buf);
git__free(buf);
return ret;
} }
int p_chmod(const char* path, mode_t mode) int p_chmod(const char* path, mode_t mode)
{ {
wchar_t* buf = gitwin_to_utf16(path); wchar_t buf[GIT_WIN_PATH];
int ret; git__utf8_to_16(buf, GIT_WIN_PATH, path);
if (!buf) return _wchmod(buf, mode);
return -1;
ret = _wchmod(buf, mode);
git__free(buf);
return ret;
} }
int p_rmdir(const char* path) int p_rmdir(const char* path)
{ {
wchar_t* buf = gitwin_to_utf16(path); wchar_t buf[GIT_WIN_PATH];
int ret; git__utf8_to_16(buf, GIT_WIN_PATH, path);
if (!buf) return _wrmdir(buf);
return -1;
ret = _wrmdir(buf);
git__free(buf);
return ret;
} }
int p_hide_directory__w32(const char *path) int p_hide_directory__w32(const char *path)
{ {
int res; wchar_t buf[GIT_WIN_PATH];
wchar_t* buf = gitwin_to_utf16(path); git__utf8_to_16(buf, GIT_WIN_PATH, path);
if (!buf) return (SetFileAttributesW(buf, FILE_ATTRIBUTE_HIDDEN) != 0) ? 0 : -1;
return -1;
res = SetFileAttributesW(buf, FILE_ATTRIBUTE_HIDDEN);
git__free(buf);
return (res != 0) ? 0 : -1; /* MSDN states a "non zero" value indicates a success */
} }
char *p_realpath(const char *orig_path, char *buffer) char *p_realpath(const char *orig_path, char *buffer)
{ {
int ret, buffer_sz = 0; int ret, buffer_sz = 0;
wchar_t* orig_path_w = gitwin_to_utf16(orig_path); wchar_t orig_path_w[GIT_WIN_PATH];
wchar_t* buffer_w = (wchar_t*)git__malloc(GIT_PATH_MAX * sizeof(wchar_t)); wchar_t buffer_w[GIT_WIN_PATH];
if (!orig_path_w || !buffer_w)
return NULL;
ret = GetFullPathNameW(orig_path_w, GIT_PATH_MAX, buffer_w, NULL); git__utf8_to_16(orig_path_w, GIT_WIN_PATH, orig_path);
git__free(orig_path_w); ret = GetFullPathNameW(orig_path_w, GIT_WIN_PATH, buffer_w, NULL);
/* According to MSDN, a return value equals to zero means a failure. */ /* According to MSDN, a return value equals to zero means a failure. */
if (ret == 0 || ret > GIT_PATH_MAX) { if (ret == 0 || ret > GIT_WIN_PATH) {
buffer = NULL; buffer = NULL;
goto done; goto done;
} }
...@@ -376,8 +332,7 @@ char *p_realpath(const char *orig_path, char *buffer) ...@@ -376,8 +332,7 @@ char *p_realpath(const char *orig_path, char *buffer)
} }
} }
if (!git_path_exists(buffer)) if (!git_path_exists(buffer)) {
{
if (buffer_sz > 0) if (buffer_sz > 0)
git__free(buffer); git__free(buffer);
...@@ -386,9 +341,9 @@ char *p_realpath(const char *orig_path, char *buffer) ...@@ -386,9 +341,9 @@ char *p_realpath(const char *orig_path, char *buffer)
} }
done: done:
git__free(buffer_w);
if (buffer) if (buffer)
git_path_mkposix(buffer); git_path_mkposix(buffer);
return buffer; return buffer;
} }
...@@ -443,32 +398,19 @@ int p_setenv(const char* name, const char* value, int overwrite) ...@@ -443,32 +398,19 @@ int p_setenv(const char* name, const char* value, int overwrite)
int p_access(const char* path, mode_t mode) int p_access(const char* path, mode_t mode)
{ {
wchar_t *buf = gitwin_to_utf16(path); wchar_t buf[GIT_WIN_PATH];
int ret; git__utf8_to_16(buf, GIT_WIN_PATH, path);
if (!buf) return _waccess(buf, mode);
return -1;
ret = _waccess(buf, mode);
git__free(buf);
return ret;
} }
int p_rename(const char *from, const char *to) int p_rename(const char *from, const char *to)
{ {
wchar_t *wfrom = gitwin_to_utf16(from); wchar_t wfrom[GIT_WIN_PATH];
wchar_t *wto = gitwin_to_utf16(to); wchar_t wto[GIT_WIN_PATH];
int ret;
if (!wfrom || !wto)
return -1;
ret = MoveFileExW(wfrom, wto, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED) ? 0 : -1;
git__free(wfrom);
git__free(wto);
return ret; git__utf8_to_16(wfrom, GIT_WIN_PATH, from);
git__utf8_to_16(wto, GIT_WIN_PATH, to);
return MoveFileExW(wfrom, wto, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED) ? 0 : -1;
} }
int p_recv(GIT_SOCKET socket, void *buffer, size_t length, int flags) int p_recv(GIT_SOCKET socket, void *buffer, size_t length, int flags)
......
...@@ -7,86 +7,75 @@ ...@@ -7,86 +7,75 @@
#include "common.h" #include "common.h"
#include "utf-conv.h" #include "utf-conv.h"
#include "git2/windows.h"
/* #define U16_LEAD(c) (wchar_t)(((c)>>10)+0xd7c0)
* Default codepage value #define U16_TRAIL(c) (wchar_t)(((c)&0x3ff)|0xdc00)
*/
static int _active_codepage = CP_UTF8;
void gitwin_set_codepage(unsigned int codepage) #if 0
void git__utf8_to_16(wchar_t *dest, size_t length, const char *src)
{ {
_active_codepage = codepage; wchar_t *pDest = dest;
} uint32_t ch;
const uint8_t* pSrc = (uint8_t*) src;
unsigned int gitwin_get_codepage(void) assert(dest && src && length);
{
return _active_codepage;
}
void gitwin_set_utf8(void) length--;
{
_active_codepage = CP_UTF8;
}
wchar_t* gitwin_to_utf16(const char* str)
{
wchar_t* ret;
int cb;
if (!str) while(*pSrc && length > 0) {
return NULL; ch = *pSrc++;
length--;
cb = MultiByteToWideChar(_active_codepage, 0, str, -1, NULL, 0); if(ch < 0xc0) {
if (cb == 0) /*
return (wchar_t *)git__calloc(1, sizeof(wchar_t)); * ASCII, or a trail byte in lead position which is treated like
* a single-byte sequence for better character boundary
ret = (wchar_t *)git__malloc(cb * sizeof(wchar_t)); * resynchronization after illegal sequences.
if (!ret) */
return NULL; *pDest++ = (wchar_t)ch;
continue;
} else if(ch < 0xe0) { /* U+0080..U+07FF */
if (pSrc[0]) {
/* 0x3080 = (0xc0 << 6) + 0x80 */
*pDest++ = (wchar_t)((ch << 6) + *pSrc++ - 0x3080);
continue;
}
} else if(ch < 0xf0) { /* U+0800..U+FFFF */
if (pSrc[0] && pSrc[1]) {
/* no need for (ch & 0xf) because the upper bits are truncated after <<12 in the cast to (UChar) */
/* 0x2080 = (0x80 << 6) + 0x80 */
ch = (ch << 12) + (*pSrc++ << 6);
*pDest++ = (wchar_t)(ch + *pSrc++ - 0x2080);
continue;
}
} else /* f0..f4 */ { /* U+10000..U+10FFFF */
if (length >= 1 && pSrc[0] && pSrc[1] && pSrc[2]) {
/* 0x3c82080 = (0xf0 << 18) + (0x80 << 12) + (0x80 << 6) + 0x80 */
ch = (ch << 18) + (*pSrc++ << 12);
ch += *pSrc++ << 6;
ch += *pSrc++ - 0x3c82080;
*(pDest++) = U16_LEAD(ch);
*(pDest++) = U16_TRAIL(ch);
length--; /* two bytes for this character */
continue;
}
}
if (MultiByteToWideChar(_active_codepage, 0, str, -1, ret, (int)cb) == 0) { /* truncated character at the end */
giterr_set(GITERR_OS, "Could not convert string to UTF-16"); *pDest++ = 0xfffd;
git__free(ret); break;
ret = NULL;
} }
return ret; *pDest++ = 0x0;
} }
#endif
int gitwin_append_utf16(wchar_t *buffer, const char *str, size_t len) void git__utf8_to_16(wchar_t *dest, size_t length, const char *src)
{ {
int result = MultiByteToWideChar( MultiByteToWideChar(CP_UTF8, 0, src, -1, dest, length);
_active_codepage, 0, str, -1, buffer, (int)len);
if (result == 0)
giterr_set(GITERR_OS, "Could not convert string to UTF-16");
return result;
} }
char* gitwin_from_utf16(const wchar_t* str) void git__utf16_to_8(char *out, const wchar_t *input)
{ {
char* ret; WideCharToMultiByte(CP_UTF8, 0, input, -1, out, GIT_WIN_PATH, NULL, NULL);
int cb;
if (!str)
return NULL;
cb = WideCharToMultiByte(_active_codepage, 0, str, -1, NULL, 0, NULL, NULL);
if (cb == 0)
return (char *)git__calloc(1, sizeof(char));
ret = (char*)git__malloc(cb);
if (!ret)
return NULL;
if (WideCharToMultiByte(
_active_codepage, 0, str, -1, ret, (int)cb, NULL, NULL) == 0)
{
giterr_set(GITERR_OS, "Could not convert string to UTF-8");
git__free(ret);
ret = NULL;
}
return ret;
} }
...@@ -10,9 +10,10 @@ ...@@ -10,9 +10,10 @@
#ifndef INCLUDE_git_utfconv_h__ #ifndef INCLUDE_git_utfconv_h__
#define INCLUDE_git_utfconv_h__ #define INCLUDE_git_utfconv_h__
wchar_t* gitwin_to_utf16(const char* str); #define GIT_WIN_PATH (260 + 1)
int gitwin_append_utf16(wchar_t *buffer, const char *str, size_t len);
char* gitwin_from_utf16(const wchar_t* str); void git__utf8_to_16(wchar_t *dest, size_t length, const char *src);
void git__utf16_to_8(char *dest, const wchar_t *src);
#endif #endif
...@@ -56,22 +56,23 @@ void cl_git_rewritefile(const char *filename, const char *new_content) ...@@ -56,22 +56,23 @@ void cl_git_rewritefile(const char *filename, const char *new_content)
char *cl_getenv(const char *name) char *cl_getenv(const char *name)
{ {
wchar_t *name_utf16 = gitwin_to_utf16(name); wchar_t name_utf16[GIT_WIN_PATH];
DWORD value_len, alloc_len; DWORD alloc_len;
wchar_t *value_utf16; wchar_t *value_utf16;
char *value_utf8; char *value_utf8;
cl_assert(name_utf16); git__utf8_to_16(name_utf16, GIT_WIN_PATH, name);
alloc_len = GetEnvironmentVariableW(name_utf16, NULL, 0); alloc_len = GetEnvironmentVariableW(name_utf16, NULL, 0);
if (alloc_len <= 0) if (alloc_len <= 0)
return NULL; return NULL;
alloc_len = GIT_WIN_PATH;
cl_assert(value_utf16 = git__calloc(alloc_len, sizeof(wchar_t))); cl_assert(value_utf16 = git__calloc(alloc_len, sizeof(wchar_t)));
value_len = GetEnvironmentVariableW(name_utf16, value_utf16, alloc_len); GetEnvironmentVariableW(name_utf16, value_utf16, alloc_len);
cl_assert_equal_i(value_len, alloc_len - 1);
cl_assert(value_utf8 = gitwin_from_utf16(value_utf16)); cl_assert(value_utf8 = git__malloc(alloc_len));
git__utf16_to_8(value_utf8, value_utf16);
git__free(value_utf16); git__free(value_utf16);
...@@ -80,17 +81,16 @@ char *cl_getenv(const char *name) ...@@ -80,17 +81,16 @@ char *cl_getenv(const char *name)
int cl_setenv(const char *name, const char *value) int cl_setenv(const char *name, const char *value)
{ {
wchar_t *name_utf16 = gitwin_to_utf16(name); wchar_t name_utf16[GIT_WIN_PATH];
wchar_t *value_utf16 = value ? gitwin_to_utf16(value) : NULL; wchar_t value_utf16[GIT_WIN_PATH];
cl_assert(name_utf16); git__utf8_to_16(name_utf16, GIT_WIN_PATH, name);
cl_assert(SetEnvironmentVariableW(name_utf16, value_utf16));
git__free(name_utf16); if (value != NULL)
git__free(value_utf16); git__utf8_to_16(value_utf16, GIT_WIN_PATH, value);
cl_assert(SetEnvironmentVariableW(name_utf16, value ? value_utf16 : NULL));
return 0; return 0;
} }
#else #else
......
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