1251881Speter/* 2251881Speter * win32_xlate.c : Windows xlate stuff. 3251881Speter * 4251881Speter * ==================================================================== 5251881Speter * Licensed to the Apache Software Foundation (ASF) under one 6251881Speter * or more contributor license agreements. See the NOTICE file 7251881Speter * distributed with this work for additional information 8251881Speter * regarding copyright ownership. The ASF licenses this file 9251881Speter * to you under the Apache License, Version 2.0 (the 10251881Speter * "License"); you may not use this file except in compliance 11251881Speter * with the License. You may obtain a copy of the License at 12251881Speter * 13251881Speter * http://www.apache.org/licenses/LICENSE-2.0 14251881Speter * 15251881Speter * Unless required by applicable law or agreed to in writing, 16251881Speter * software distributed under the License is distributed on an 17251881Speter * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 18251881Speter * KIND, either express or implied. See the License for the 19251881Speter * specific language governing permissions and limitations 20251881Speter * under the License. 21251881Speter * ==================================================================== 22251881Speter */ 23251881Speter 24251881Speter/* prevent "empty compilation unit" warning on e.g. UNIX */ 25251881Spetertypedef int win32_xlate__dummy; 26251881Speter 27251881Speter#ifdef WIN32 28251881Speter 29251881Speter/* Define _WIN32_DCOM for CoInitializeEx(). */ 30251881Speter#define _WIN32_DCOM 31251881Speter 32251881Speter/* We must include windows.h ourselves or apr.h includes it for us with 33251881Speter many ignore options set. Including Winsock is required to resolve IPv6 34251881Speter compilation errors. APR_HAVE_IPV6 is only defined after including 35251881Speter apr.h, so we can't detect this case here. */ 36251881Speter 37251881Speter/* winsock2.h includes windows.h */ 38251881Speter#include <winsock2.h> 39251881Speter#include <Ws2tcpip.h> 40251881Speter#include <mlang.h> 41251881Speter 42251881Speter#include <apr.h> 43251881Speter#include <apr_errno.h> 44251881Speter#include <apr_portable.h> 45251881Speter 46251881Speter#include "svn_pools.h" 47251881Speter#include "svn_string.h" 48251881Speter#include "svn_utf.h" 49251881Speter#include "private/svn_atomic.h" 50251881Speter 51251881Speter#include "win32_xlate.h" 52251881Speter 53251881Speterstatic svn_atomic_t com_initialized = 0; 54251881Speter 55251881Speter/* Initializes COM and keeps COM available until process exit. 56251881Speter Implements svn_atomic__init_once init_func */ 57251881Speterstatic svn_error_t * 58251881Speterinitialize_com(void *baton, apr_pool_t* pool) 59251881Speter{ 60251881Speter /* Try to initialize for apartment-threaded object concurrency. */ 61251881Speter HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); 62251881Speter 63251881Speter if (hr == RPC_E_CHANGED_MODE) 64251881Speter { 65251881Speter /* COM already initalized for multi-threaded object concurrency. We are 66251881Speter neutral to object concurrency so try to initalize it in the same way 67251881Speter for us, to keep an handle open. */ 68251881Speter hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); 69251881Speter } 70251881Speter 71251881Speter if (FAILED(hr)) 72251881Speter return svn_error_create(APR_EGENERAL, NULL, NULL); 73251881Speter 74251881Speter return SVN_NO_ERROR; 75251881Speter} 76251881Speter 77251881Spetertypedef struct win32_xlate_t 78251881Speter{ 79251881Speter UINT from_page_id; 80251881Speter UINT to_page_id; 81251881Speter} win32_xlate_t; 82251881Speter 83251881Speterstatic apr_status_t 84251881Speterget_page_id_from_name(UINT *page_id_p, const char *page_name, apr_pool_t *pool) 85251881Speter{ 86251881Speter IMultiLanguage * mlang = NULL; 87251881Speter HRESULT hr; 88251881Speter MIMECSETINFO page_info; 89251881Speter WCHAR ucs2_page_name[128]; 90251881Speter svn_error_t *err; 91251881Speter 92251881Speter if (page_name == SVN_APR_DEFAULT_CHARSET) 93251881Speter { 94251881Speter *page_id_p = CP_ACP; 95251881Speter return APR_SUCCESS; 96251881Speter } 97251881Speter else if (page_name == SVN_APR_LOCALE_CHARSET) 98251881Speter { 99251881Speter *page_id_p = CP_THREAD_ACP; /* Valid on Windows 2000+ */ 100251881Speter return APR_SUCCESS; 101251881Speter } 102251881Speter else if (!strcmp(page_name, "UTF-8")) 103251881Speter { 104251881Speter *page_id_p = CP_UTF8; 105251881Speter return APR_SUCCESS; 106251881Speter } 107251881Speter 108251881Speter /* Use codepage identifier nnn if the codepage name is in the form 109251881Speter of "CPnnn". 110251881Speter We need this code since apr_os_locale_encoding() and svn_cmdline_init() 111251881Speter generates such codepage names even if they are not valid IANA charset 112251881Speter name. */ 113251881Speter if ((page_name[0] == 'c' || page_name[0] == 'C') 114251881Speter && (page_name[1] == 'p' || page_name[1] == 'P')) 115251881Speter { 116251881Speter *page_id_p = atoi(page_name + 2); 117251881Speter return APR_SUCCESS; 118251881Speter } 119251881Speter 120251881Speter err = svn_atomic__init_once(&com_initialized, initialize_com, NULL, pool); 121251881Speter 122251881Speter if (err) 123251881Speter { 124251881Speter svn_error_clear(err); 125251881Speter return APR_EGENERAL; 126251881Speter } 127251881Speter 128251881Speter hr = CoCreateInstance(&CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER, 129251881Speter &IID_IMultiLanguage, (void **) &mlang); 130251881Speter 131251881Speter if (FAILED(hr)) 132251881Speter return APR_EGENERAL; 133251881Speter 134251881Speter /* Convert page name to wide string. */ 135251881Speter MultiByteToWideChar(CP_UTF8, 0, page_name, -1, ucs2_page_name, 136251881Speter sizeof(ucs2_page_name) / sizeof(ucs2_page_name[0])); 137251881Speter memset(&page_info, 0, sizeof(page_info)); 138251881Speter hr = mlang->lpVtbl->GetCharsetInfo(mlang, ucs2_page_name, &page_info); 139251881Speter if (FAILED(hr)) 140251881Speter { 141251881Speter mlang->lpVtbl->Release(mlang); 142251881Speter return APR_EINVAL; 143251881Speter } 144251881Speter 145251881Speter if (page_info.uiInternetEncoding) 146251881Speter *page_id_p = page_info.uiInternetEncoding; 147251881Speter else 148251881Speter *page_id_p = page_info.uiCodePage; 149251881Speter 150251881Speter mlang->lpVtbl->Release(mlang); 151251881Speter 152251881Speter return APR_SUCCESS; 153251881Speter} 154251881Speter 155251881Speterapr_status_t 156251881Spetersvn_subr__win32_xlate_open(win32_xlate_t **xlate_p, const char *topage, 157251881Speter const char *frompage, apr_pool_t *pool) 158251881Speter{ 159251881Speter UINT from_page_id, to_page_id; 160251881Speter apr_status_t apr_err = APR_SUCCESS; 161251881Speter win32_xlate_t *xlate; 162251881Speter 163251881Speter apr_err = get_page_id_from_name(&to_page_id, topage, pool); 164251881Speter if (apr_err == APR_SUCCESS) 165251881Speter apr_err = get_page_id_from_name(&from_page_id, frompage, pool); 166251881Speter 167251881Speter if (apr_err == APR_SUCCESS) 168251881Speter { 169251881Speter xlate = apr_palloc(pool, sizeof(*xlate)); 170251881Speter xlate->from_page_id = from_page_id; 171251881Speter xlate->to_page_id = to_page_id; 172251881Speter 173251881Speter *xlate_p = xlate; 174251881Speter } 175251881Speter 176251881Speter return apr_err; 177251881Speter} 178251881Speter 179251881Speterapr_status_t 180251881Spetersvn_subr__win32_xlate_to_stringbuf(win32_xlate_t *handle, 181251881Speter const char *src_data, 182251881Speter apr_size_t src_length, 183251881Speter svn_stringbuf_t **dest, 184251881Speter apr_pool_t *pool) 185251881Speter{ 186251881Speter WCHAR * wide_str; 187251881Speter int retval, wide_size; 188251881Speter 189251881Speter if (src_length == 0) 190251881Speter { 191251881Speter *dest = svn_stringbuf_create_empty(pool); 192251881Speter return APR_SUCCESS; 193251881Speter } 194251881Speter 195251881Speter retval = MultiByteToWideChar(handle->from_page_id, 0, src_data, src_length, 196251881Speter NULL, 0); 197251881Speter if (retval == 0) 198251881Speter return apr_get_os_error(); 199251881Speter 200251881Speter wide_size = retval; 201251881Speter 202251881Speter /* Allocate temporary buffer for small strings on stack instead of heap. */ 203251881Speter if (wide_size <= MAX_PATH) 204251881Speter { 205251881Speter wide_str = alloca(wide_size * sizeof(WCHAR)); 206251881Speter } 207251881Speter else 208251881Speter { 209251881Speter wide_str = apr_palloc(pool, wide_size * sizeof(WCHAR)); 210251881Speter } 211251881Speter 212251881Speter retval = MultiByteToWideChar(handle->from_page_id, 0, src_data, src_length, 213251881Speter wide_str, wide_size); 214251881Speter 215251881Speter if (retval == 0) 216251881Speter return apr_get_os_error(); 217251881Speter 218251881Speter retval = WideCharToMultiByte(handle->to_page_id, 0, wide_str, wide_size, 219251881Speter NULL, 0, NULL, NULL); 220251881Speter 221251881Speter if (retval == 0) 222251881Speter return apr_get_os_error(); 223251881Speter 224251881Speter /* Ensure that buffer is enough to hold result string and termination 225251881Speter character. */ 226251881Speter *dest = svn_stringbuf_create_ensure(retval + 1, pool); 227251881Speter (*dest)->len = retval; 228251881Speter 229251881Speter retval = WideCharToMultiByte(handle->to_page_id, 0, wide_str, wide_size, 230251881Speter (*dest)->data, (*dest)->len, NULL, NULL); 231251881Speter if (retval == 0) 232251881Speter return apr_get_os_error(); 233251881Speter 234251881Speter (*dest)->len = retval; 235251881Speter return APR_SUCCESS; 236251881Speter} 237251881Speter 238251881Speter#endif /* WIN32 */ 239