In the command-line client, forbid
[svn.git] / subversion / libsvn_subr / win32_xlate.c
blob965c3ab3eaf01a78ac82314cad0759fb80e26840
1 /*
2 * win32_xlate.c : Windows xlate stuff.
4 * ====================================================================
5 * Copyright (c) 2007 CollabNet. All rights reserved.
7 * This software is licensed as described in the file COPYING, which
8 * you should have received as part of this distribution. The terms
9 * are also available at http://subversion.tigris.org/license-1.html.
10 * If newer versions of this license are posted there, you may use a
11 * newer version instead, at your option.
13 * This software consists of voluntary contributions made by many
14 * individuals. For exact contribution history, see the revision
15 * history and logs, available at http://subversion.tigris.org/.
16 * ====================================================================
19 #ifdef WIN32
21 /* Define _WIN32_DCOM for CoInitializeEx(). */
22 #define _WIN32_DCOM
24 #ifdef APR_HAVE_IPV6
25 #include <winsock2.h>
26 #include <Ws2tcpip.h>
27 #include <Wspiapi.h>
28 #endif
29 #include <windows.h>
30 #include <mlang.h>
32 #include <apr.h>
33 #include <apr_errno.h>
34 #include <apr_portable.h>
36 #include "svn_pools.h"
37 #include "svn_string.h"
38 #include "svn_utf.h"
40 #include "win32_xlate.h"
42 typedef struct win32_xlate_t
44 UINT from_page_id;
45 UINT to_page_id;
46 } win32_xlate_t;
48 static apr_status_t
49 get_page_id_from_name(UINT *page_id_p, const char *page_name, apr_pool_t *pool)
51 IMultiLanguage * mlang = NULL;
52 HRESULT hr;
53 MIMECSETINFO page_info;
54 WCHAR ucs2_page_name[128];
56 if (page_name == SVN_APR_DEFAULT_CHARSET)
58 *page_id_p = CP_ACP;
59 return APR_SUCCESS;
61 else if (page_name == SVN_APR_LOCALE_CHARSET)
63 OSVERSIONINFO ver_info;
64 ver_info.dwOSVersionInfoSize = sizeof(ver_info);
66 /* CP_THREAD_ACP supported only on Windows 2000 and later.*/
67 if (GetVersionEx(&ver_info) && ver_info.dwMajorVersion >= 5
68 && ver_info.dwPlatformId == VER_PLATFORM_WIN32_NT)
70 *page_id_p = CP_THREAD_ACP;
71 return APR_SUCCESS;
74 /* CP_THREAD_ACP isn't supported on current system, so get locale
75 encoding name from APR. */
76 page_name = apr_os_locale_encoding(pool);
78 else if (!strcmp(page_name, "UTF-8"))
80 *page_id_p = CP_UTF8;
81 return APR_SUCCESS;
84 /* Use codepage identifier nnn if the codepage name is in the form
85 of "CPnnn".
86 We need this code since apr_os_locale_encoding() and svn_cmdline_init()
87 generates such codepage names even if they are not valid IANA charset
88 name. */
89 if ((page_name[0] == 'c' || page_name[0] == 'C')
90 && (page_name[1] == 'p' || page_name[1] == 'P'))
92 *page_id_p = atoi(page_name + 2);
93 return APR_SUCCESS;
96 hr = CoCreateInstance(&CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER,
97 &IID_IMultiLanguage, (void **) &mlang);
99 if (FAILED(hr))
100 return APR_EGENERAL;
102 /* Convert page name to wide string. */
103 MultiByteToWideChar(CP_UTF8, 0, page_name, -1, ucs2_page_name,
104 sizeof(ucs2_page_name) / sizeof(ucs2_page_name[0]));
105 memset(&page_info, 0, sizeof(page_info));
106 hr = mlang->lpVtbl->GetCharsetInfo(mlang, ucs2_page_name, &page_info);
107 if (FAILED(hr))
109 mlang->lpVtbl->Release(mlang);
110 return APR_EINVAL;
113 if (page_info.uiInternetEncoding)
114 *page_id_p = page_info.uiInternetEncoding;
115 else
116 *page_id_p = page_info.uiCodePage;
118 mlang->lpVtbl->Release(mlang);
120 return APR_SUCCESS;
123 apr_status_t
124 svn_subr__win32_xlate_open(win32_xlate_t **xlate_p, const char *topage,
125 const char *frompage, apr_pool_t *pool)
127 UINT from_page_id, to_page_id;
128 apr_status_t apr_err = APR_SUCCESS;
129 win32_xlate_t *xlate;
130 HRESULT hr;
132 /* First try to initialize for apartment-threaded object concurrency. */
133 hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
134 if (hr == RPC_E_CHANGED_MODE)
136 /* COM already initalized for multi-threaded object concurrency. We are
137 neutral to object concurrency so try to initalize it in the same way
138 for us. */
139 hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
142 if (FAILED(hr))
143 return APR_EGENERAL;
145 apr_err = get_page_id_from_name(&to_page_id, topage, pool);
146 if (apr_err == APR_SUCCESS)
147 apr_err = get_page_id_from_name(&from_page_id, frompage, pool);
149 if (apr_err == APR_SUCCESS)
151 xlate = apr_palloc(pool, sizeof(*xlate));
152 xlate->from_page_id = from_page_id;
153 xlate->to_page_id = to_page_id;
155 *xlate_p = xlate;
158 CoUninitialize();
159 return apr_err;
162 apr_status_t
163 svn_subr__win32_xlate_to_stringbuf(win32_xlate_t *handle,
164 const char *src_data,
165 apr_size_t src_length,
166 svn_stringbuf_t **dest,
167 apr_pool_t *pool)
169 WCHAR * wide_str;
170 int retval, wide_size;
172 *dest = svn_stringbuf_create("", pool);
174 if (src_length == 0)
175 return APR_SUCCESS;
177 retval = MultiByteToWideChar(handle->from_page_id, 0, src_data, src_length,
178 NULL, 0);
179 if (retval == 0)
180 return apr_get_os_error();
182 wide_size = retval;
184 /* Allocate temporary buffer for small strings on stack instead of heap. */
185 if (wide_size <= MAX_PATH)
187 wide_str = alloca(wide_size * sizeof(WCHAR));
189 else
191 wide_str = apr_palloc(pool, wide_size * sizeof(WCHAR));
194 retval = MultiByteToWideChar(handle->from_page_id, 0, src_data, src_length,
195 wide_str, wide_size);
197 if (retval == 0)
198 return apr_get_os_error();
200 retval = WideCharToMultiByte(handle->to_page_id, 0, wide_str, wide_size,
201 NULL, 0, NULL, NULL);
203 if (retval == 0)
204 return apr_get_os_error();
206 /* Ensure that buffer is enough to hold result string and termination
207 character. */
208 svn_stringbuf_ensure(*dest, retval + 1);
209 (*dest)->len = retval;
211 retval = WideCharToMultiByte(handle->to_page_id, 0, wide_str, wide_size,
212 (*dest)->data, (*dest)->len, NULL, NULL);
213 if (retval == 0)
214 return apr_get_os_error();
216 (*dest)->len = retval;
217 return APR_SUCCESS;
220 #endif /* WIN32 */