Sync libsvn_diff from subversion r876937
[TortoiseGit.git] / src / TortoiseMerge / libsvn_diff / win32_xlate.c
blobc982e6bc2405c25e5de696d9aef37fd9ed342f58
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 /* We must include windows.h ourselves or apr.h includes it for us with
25 many ignore options set. Including Winsock is required to resolve IPv6
26 compilation errors. APR_HAVE_IPV6 is only defined after including
27 apr.h, so we can't detect this case here. */
29 /* winsock2.h includes windows.h */
30 #include <winsock2.h>
31 #include <Ws2tcpip.h>
32 #include <mlang.h>
34 #include <apr.h>
35 #include <apr_errno.h>
36 #include <apr_portable.h>
38 #include "svn_pools.h"
39 #include "svn_string.h"
40 #include "svn_utf.h"
42 #include "win32_xlate.h"
44 typedef struct win32_xlate_t
46 UINT from_page_id;
47 UINT to_page_id;
48 } win32_xlate_t;
50 static apr_status_t
51 get_page_id_from_name(UINT *page_id_p, const char *page_name, apr_pool_t *pool)
53 IMultiLanguage * mlang = NULL;
54 HRESULT hr;
55 MIMECSETINFO page_info;
56 WCHAR ucs2_page_name[128];
58 if (page_name == SVN_APR_DEFAULT_CHARSET)
60 *page_id_p = CP_ACP;
61 return APR_SUCCESS;
63 else if (page_name == SVN_APR_LOCALE_CHARSET)
65 OSVERSIONINFO ver_info;
66 ver_info.dwOSVersionInfoSize = sizeof(ver_info);
68 /* CP_THREAD_ACP supported only on Windows 2000 and later.*/
69 if (GetVersionEx(&ver_info) && ver_info.dwMajorVersion >= 5
70 && ver_info.dwPlatformId == VER_PLATFORM_WIN32_NT)
72 *page_id_p = CP_THREAD_ACP;
73 return APR_SUCCESS;
76 /* CP_THREAD_ACP isn't supported on current system, so get locale
77 encoding name from APR. */
78 page_name = apr_os_locale_encoding(pool);
80 else if (!strcmp(page_name, "UTF-8"))
82 *page_id_p = CP_UTF8;
83 return APR_SUCCESS;
86 /* Use codepage identifier nnn if the codepage name is in the form
87 of "CPnnn".
88 We need this code since apr_os_locale_encoding() and svn_cmdline_init()
89 generates such codepage names even if they are not valid IANA charset
90 name. */
91 if ((page_name[0] == 'c' || page_name[0] == 'C')
92 && (page_name[1] == 'p' || page_name[1] == 'P'))
94 *page_id_p = atoi(page_name + 2);
95 return APR_SUCCESS;
98 hr = CoCreateInstance(&CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER,
99 &IID_IMultiLanguage, (void **) &mlang);
101 if (FAILED(hr))
102 return APR_EGENERAL;
104 /* Convert page name to wide string. */
105 MultiByteToWideChar(CP_UTF8, 0, page_name, -1, ucs2_page_name,
106 sizeof(ucs2_page_name) / sizeof(ucs2_page_name[0]));
107 memset(&page_info, 0, sizeof(page_info));
108 hr = mlang->lpVtbl->GetCharsetInfo(mlang, ucs2_page_name, &page_info);
109 if (FAILED(hr))
111 mlang->lpVtbl->Release(mlang);
112 return APR_EINVAL;
115 if (page_info.uiInternetEncoding)
116 *page_id_p = page_info.uiInternetEncoding;
117 else
118 *page_id_p = page_info.uiCodePage;
120 mlang->lpVtbl->Release(mlang);
122 return APR_SUCCESS;
125 apr_status_t
126 svn_subr__win32_xlate_open(win32_xlate_t **xlate_p, const char *topage,
127 const char *frompage, apr_pool_t *pool)
129 UINT from_page_id, to_page_id;
130 apr_status_t apr_err = APR_SUCCESS;
131 win32_xlate_t *xlate;
132 HRESULT hr;
134 /* First try to initialize for apartment-threaded object concurrency. */
135 hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
136 if (hr == RPC_E_CHANGED_MODE)
138 /* COM already initalized for multi-threaded object concurrency. We are
139 neutral to object concurrency so try to initalize it in the same way
140 for us. */
141 hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
144 if (FAILED(hr))
145 return APR_EGENERAL;
147 apr_err = get_page_id_from_name(&to_page_id, topage, pool);
148 if (apr_err == APR_SUCCESS)
149 apr_err = get_page_id_from_name(&from_page_id, frompage, pool);
151 if (apr_err == APR_SUCCESS)
153 xlate = apr_palloc(pool, sizeof(*xlate));
154 xlate->from_page_id = from_page_id;
155 xlate->to_page_id = to_page_id;
157 *xlate_p = xlate;
160 CoUninitialize();
161 return apr_err;
164 apr_status_t
165 svn_subr__win32_xlate_to_stringbuf(win32_xlate_t *handle,
166 const char *src_data,
167 apr_size_t src_length,
168 svn_stringbuf_t **dest,
169 apr_pool_t *pool)
171 WCHAR * wide_str;
172 int retval, wide_size;
174 *dest = svn_stringbuf_create("", pool);
176 if (src_length == 0)
177 return APR_SUCCESS;
179 retval = MultiByteToWideChar(handle->from_page_id, 0, src_data, src_length,
180 NULL, 0);
181 if (retval == 0)
182 return apr_get_os_error();
184 wide_size = retval;
186 /* Allocate temporary buffer for small strings on stack instead of heap. */
187 if (wide_size <= MAX_PATH)
189 wide_str = _alloca(wide_size * sizeof(WCHAR));
191 else
193 wide_str = apr_palloc(pool, wide_size * sizeof(WCHAR));
196 retval = MultiByteToWideChar(handle->from_page_id, 0, src_data, src_length,
197 wide_str, wide_size);
199 if (retval == 0)
200 return apr_get_os_error();
202 retval = WideCharToMultiByte(handle->to_page_id, 0, wide_str, wide_size,
203 NULL, 0, NULL, NULL);
205 if (retval == 0)
206 return apr_get_os_error();
208 /* Ensure that buffer is enough to hold result string and termination
209 character. */
210 svn_stringbuf_ensure(*dest, retval + 1);
211 (*dest)->len = retval;
213 retval = WideCharToMultiByte(handle->to_page_id, 0, wide_str, wide_size,
214 (*dest)->data, (*dest)->len, NULL, NULL);
215 if (retval == 0)
216 return apr_get_os_error();
218 (*dest)->len = retval;
219 return APR_SUCCESS;
222 #endif /* WIN32 */