]> git.proxmox.com Git - libgit2.git/blob - src/win32/utf-conv.c
Merge pull request #2761 from libgit2/cmn/fetch-prune
[libgit2.git] / src / win32 / utf-conv.c
1 /*
2 * Copyright (C) the libgit2 contributors. All rights reserved.
3 *
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
6 */
7
8 #include "common.h"
9 #include "utf-conv.h"
10
11 #ifndef WC_ERR_INVALID_CHARS
12 # define WC_ERR_INVALID_CHARS 0x80
13 #endif
14
15 GIT_INLINE(DWORD) get_wc_flags(void)
16 {
17 static char inited = 0;
18 static DWORD flags;
19
20 /* Invalid code point check supported on Vista+ only */
21 if (!inited) {
22 flags = git_has_win32_version(6, 0, 0) ? WC_ERR_INVALID_CHARS : 0;
23 inited = 1;
24 }
25
26 return flags;
27 }
28
29 GIT_INLINE(void) git__set_errno(void)
30 {
31 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
32 errno = ENAMETOOLONG;
33 else
34 errno = EINVAL;
35 }
36
37 /**
38 * Converts a UTF-8 string to wide characters.
39 *
40 * @param dest The buffer to receive the wide string.
41 * @param dest_size The size of the buffer, in characters.
42 * @param src The UTF-8 string to convert.
43 * @return The length of the wide string, in characters (not counting the NULL terminator), or < 0 for failure
44 */
45 int git__utf8_to_16(wchar_t *dest, size_t dest_size, const char *src)
46 {
47 int len;
48
49 /* Length of -1 indicates NULL termination of the input string. Subtract 1 from the result to
50 * turn 0 into -1 (an error code) and to not count the NULL terminator as part of the string's
51 * length. MultiByteToWideChar never returns int's minvalue, so underflow is not possible */
52 if ((len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src, -1, dest, (int)dest_size) - 1) < 0)
53 git__set_errno();
54
55 return len;
56 }
57
58 /**
59 * Converts a wide string to UTF-8.
60 *
61 * @param dest The buffer to receive the UTF-8 string.
62 * @param dest_size The size of the buffer, in bytes.
63 * @param src The wide string to convert.
64 * @return The length of the UTF-8 string, in bytes (not counting the NULL terminator), or < 0 for failure
65 */
66 int git__utf16_to_8(char *dest, size_t dest_size, const wchar_t *src)
67 {
68 int len;
69
70 /* Length of -1 indicates NULL termination of the input string. Subtract 1 from the result to
71 * turn 0 into -1 (an error code) and to not count the NULL terminator as part of the string's
72 * length. WideCharToMultiByte never returns int's minvalue, so underflow is not possible */
73 if ((len = WideCharToMultiByte(CP_UTF8, get_wc_flags(), src, -1, dest, (int)dest_size, NULL, NULL) - 1) < 0)
74 git__set_errno();
75
76 return len;
77 }
78
79 /**
80 * Converts a UTF-8 string to wide characters.
81 * Memory is allocated to hold the converted string.
82 * The caller is responsible for freeing the string with git__free.
83 *
84 * @param dest Receives a pointer to the wide string.
85 * @param src The UTF-8 string to convert.
86 * @return The length of the wide string, in characters (not counting the NULL terminator), or < 0 for failure
87 */
88 int git__utf8_to_16_alloc(wchar_t **dest, const char *src)
89 {
90 int utf16_size;
91
92 *dest = NULL;
93
94 /* Length of -1 indicates NULL termination of the input string */
95 utf16_size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src, -1, NULL, 0);
96
97 if (!utf16_size) {
98 git__set_errno();
99 return -1;
100 }
101
102 *dest = git__malloc(utf16_size * sizeof(wchar_t));
103
104 if (!*dest) {
105 errno = ENOMEM;
106 return -1;
107 }
108
109 utf16_size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src, -1, *dest, utf16_size);
110
111 if (!utf16_size) {
112 git__set_errno();
113
114 git__free(*dest);
115 *dest = NULL;
116 }
117
118 /* Subtract 1 from the result to turn 0 into -1 (an error code) and to not count the NULL
119 * terminator as part of the string's length. MultiByteToWideChar never returns int's minvalue,
120 * so underflow is not possible */
121 return utf16_size - 1;
122 }
123
124 /**
125 * Converts a wide string to UTF-8.
126 * Memory is allocated to hold the converted string.
127 * The caller is responsible for freeing the string with git__free.
128 *
129 * @param dest Receives a pointer to the UTF-8 string.
130 * @param src The wide string to convert.
131 * @return The length of the UTF-8 string, in bytes (not counting the NULL terminator), or < 0 for failure
132 */
133 int git__utf16_to_8_alloc(char **dest, const wchar_t *src)
134 {
135 int utf8_size;
136 DWORD dwFlags = get_wc_flags();
137
138 *dest = NULL;
139
140 /* Length of -1 indicates NULL termination of the input string */
141 utf8_size = WideCharToMultiByte(CP_UTF8, dwFlags, src, -1, NULL, 0, NULL, NULL);
142
143 if (!utf8_size) {
144 git__set_errno();
145 return -1;
146 }
147
148 *dest = git__malloc(utf8_size);
149
150 if (!*dest) {
151 errno = ENOMEM;
152 return -1;
153 }
154
155 utf8_size = WideCharToMultiByte(CP_UTF8, dwFlags, src, -1, *dest, utf8_size, NULL, NULL);
156
157 if (!utf8_size) {
158 git__set_errno();
159
160 git__free(*dest);
161 *dest = NULL;
162 }
163
164 /* Subtract 1 from the result to turn 0 into -1 (an error code) and to not count the NULL
165 * terminator as part of the string's length. MultiByteToWideChar never returns int's minvalue,
166 * so underflow is not possible */
167 return utf8_size - 1;
168 }