/* * Test every possible word value. * Once we are finished, retest every possible word value. * if the test fails on the following null word, iterate test_nrange * again, appending another word. * This assures the output order of the two tests are in sync. */ void test_wrange(struct testval *p) { struct testval f, l, s; apr_status_t rc; int success = 0; memcpy (&s, p, sizeof(s)); ++s.wl; do { apr_size_t nl = sizeof(s.n), wl = s.wl; rc = apr_conv_ucs2_to_utf8(s.w, &wl, s.n, &nl); s.nl = sizeof(s.n) - nl; if (!wl && rc == APR_SUCCESS) { if (!success) { memcpy(&f, &s, sizeof(s)); success = -1; } else { if (s.nl != l.nl || memcmp(s.n, l.n, s.nl - 1) != 0 || s.n[s.nl - 1] != l.n[l.nl - 1] + 1) { displaynw(&f, &l); memcpy(&f, &s, sizeof(s)); } } memcpy(&l, &s, sizeof(s)); } else { if (success) { displaynw(&f, &l); success = 0; } } } while (++s.w[s.wl - 1]); if (success) { displaynw(&f, &l); success = 0; } do { int wl = s.wl, nl = sizeof(s.n); rc = apr_conv_ucs2_to_utf8(s.w, &wl, s.n, &nl); s.nl = sizeof(s.n) - s.nl; if (rc == APR_INCOMPLETE) { test_wrange(&s); } } while (++s.w[s.wl - 1]); }
/* Used by apr_app_initialize to reprocess the environment * * An internal apr function to convert a double-null terminated set * of single-null terminated strings from wide Unicode to narrow utf-8 * as a list of strings. These are allocated from the MSVCRT's * _CRT_BLOCK to trick the system into trusting our store. */ static int warrsztoastr(const char * const * *retarr, const wchar_t * arrsz, int args) { const apr_wchar_t *wch; apr_size_t totlen; apr_size_t newlen; apr_size_t wsize; char **env; char *pstrs; char *strs; int arg; if (args < 0) { for (args = 1, wch = arrsz; wch[0] || wch[1]; ++wch) if (!*wch) ++args; } wsize = 1 + wch - arrsz; /* This is a safe max allocation, we will alloc each * string exactly after processing and return this * temporary buffer to the free store. * 3 ucs bytes hold any single wchar_t value (16 bits) * 4 ucs bytes will hold a wchar_t pair value (20 bits) */ newlen = totlen = wsize * 3 + 1; pstrs = strs = apr_malloc_dbg(newlen * sizeof(char), __FILE__, __LINE__); (void)apr_conv_ucs2_to_utf8(arrsz, &wsize, strs, &newlen); assert(newlen && !wsize); *retarr = env = apr_malloc_dbg((args + 1) * sizeof(char*), __FILE__, __LINE__); for (arg = 0; arg < args; ++arg) { char* p = pstrs; int len = 0; while (*p++) ++len; len += 1; *env = apr_malloc_dbg(len * sizeof(char), __FILE__, __LINE__); memcpy(*env, pstrs, len * sizeof(char)); pstrs += len; ++env; } *env = NULL; free(strs); return args; }
static apr_status_t TextConsoleRead( void *opaque, apr_byte_t *buffer, apr_size_t bytesToRead, apr_size_t *bytesRead ) { apr_status_t status; apr_size_t bytesRemaining = bytesToRead; apr_size_t charsRemaining; apr_wchar_t inBuffer[1]; char *offset; HANDLE console = opaque; ASSERT(opaque != NULL); ASSERT(buffer != NULL); ASSERT(console != INVALID_HANDLE_VALUE); ASSERT(EncGetCurrent() == ENCODING_UTF8); do { // Read one character at a time so we don't over-request if (!ReadConsoleFullW(console, inBuffer, 1, (DWORD *)&charsRemaining)) { status = apr_get_os_error(); } else { // Convert the UCS-2 character to UTF-8 offset = (char *)buffer + (bytesToRead - bytesRemaining); status = apr_conv_ucs2_to_utf8(inBuffer, &charsRemaining, offset, &bytesRemaining); } } while (status == APR_SUCCESS && bytesRemaining > 0); if (bytesRead != NULL) { *bytesRead = bytesToRead - bytesRemaining; } return status; }
AP_DECLARE(apr_status_t) ap_os_proc_filepath(char **binpath, apr_pool_t *p) { apr_wchar_t wbinpath[APR_PATH_MAX]; #if APR_HAS_UNICODE_FS IF_WIN_OS_IS_UNICODE { apr_size_t binlen; apr_size_t wbinlen; apr_status_t rv; if (!GetModuleFileNameW(NULL, wbinpath, sizeof(wbinpath) / sizeof(apr_wchar_t))) { return apr_get_os_error(); } wbinlen = wcslen(wbinpath) + 1; binlen = (wbinlen - 1) * 3 + 1; *binpath = apr_palloc(p, binlen); rv = apr_conv_ucs2_to_utf8(wbinpath, &wbinlen, *binpath, &binlen); if (rv != APR_SUCCESS) return rv; else if (wbinlen) return APR_ENAMETOOLONG; } #endif /* APR_HAS_UNICODE_FS */ #if APR_HAS_ANSI_FS ELSE_WIN_OS_IS_ANSI { /* share the same scratch buffer */ char *pathbuf = (char*) wbinpath; if (!GetModuleFileName(NULL, pathbuf, sizeof(wbinpath))) { return apr_get_os_error(); } *binpath = apr_pstrdup(p, pathbuf); } #endif return APR_SUCCESS; }
AP_DECLARE(apr_status_t) ap_regkey_value_array_get(apr_array_header_t **result, ap_regkey_t *key, const char *valuename, apr_pool_t *pool) { /* Retrieve a registry string value, and explode any envvars * that the system has configured (e.g. %SystemRoot%/someapp.exe) */ apr_status_t rv; void *value; char *buf; char *tmp; apr_int32_t type; apr_size_t size = 0; rv = ap_regkey_value_raw_get(&value, &size, &type, key, valuename, pool); if (rv != APR_SUCCESS) { return rv; } else if (type != REG_MULTI_SZ) { return APR_EINVAL; } #if APR_HAS_UNICODE_FS IF_WIN_OS_IS_UNICODE { apr_size_t alloclen; apr_size_t valuelen = strlen(valuename) + 1; /* ###: deliberately overallocate plus two extra nulls. * We could precalculate the exact buffer here instead, the question * is a matter of storage v.s. cpu cycles. */ size /= 2; alloclen = valuelen = size * 3 + 2; buf = apr_palloc(pool, valuelen); rv = apr_conv_ucs2_to_utf8(value, &size, buf, &valuelen); if (rv != APR_SUCCESS) return rv; else if (size) return APR_ENAMETOOLONG; buf[(alloclen - valuelen)] = '\0'; buf[(alloclen - valuelen) + 1] = '\0'; } #endif /* APR_HAS_UNICODE_FS */ #if APR_HAS_ANSI_FS ELSE_WIN_OS_IS_ANSI { /* Small possiblity the array is either unterminated * or single NULL terminated. Avert. */ buf = (char *)value; if (size < 2 || buf[size - 1] != '\0' || buf[size - 2] != '\0') { buf = apr_palloc(pool, size + 2); memcpy(buf, value, size); buf[size + 1] = '\0'; buf[size] = '\0'; } } #endif size = 0; /* Element Count */ for (tmp = buf; *tmp; ++tmp) { ++size; while (*tmp) { ++tmp; } } *result = apr_array_make(pool, (int)size, sizeof(char *)); for (tmp = buf; *tmp; ++tmp) { char **newelem = (char **) apr_array_push(*result); *newelem = tmp; while (*tmp) { ++tmp; } } return APR_SUCCESS; }
AP_DECLARE(apr_status_t) ap_regkey_value_get(char **result, ap_regkey_t *key, const char *valuename, apr_pool_t *pool) { /* Retrieve a registry string value, and explode any envvars * that the system has configured (e.g. %SystemRoot%/someapp.exe) */ LONG rc; DWORD type; apr_size_t size = 0; #if APR_HAS_UNICODE_FS IF_WIN_OS_IS_UNICODE { apr_size_t valuelen = strlen(valuename) + 1; apr_size_t wvallen = 256; apr_wchar_t wvalname[256]; apr_wchar_t *wvalue; apr_status_t rv; rv = apr_conv_utf8_to_ucs2(valuename, &valuelen, wvalname, &wvallen); if (rv != APR_SUCCESS) return rv; else if (valuelen) return APR_ENAMETOOLONG; /* Read to NULL buffer to determine value size */ rc = RegQueryValueExW(key->hkey, wvalname, 0, &type, NULL, (DWORD *)&size); if (rc != ERROR_SUCCESS) { return APR_FROM_OS_ERROR(rc); } if ((size < 2) || (type != REG_SZ && type != REG_EXPAND_SZ)) { return APR_FROM_OS_ERROR(ERROR_INVALID_PARAMETER); } wvalue = apr_palloc(pool, size); /* Read value based on size query above */ rc = RegQueryValueExW(key->hkey, wvalname, 0, &type, (LPBYTE)wvalue, (DWORD *)&size); if (rc != ERROR_SUCCESS) { return APR_FROM_OS_ERROR(rc); } if (type == REG_EXPAND_SZ) { apr_wchar_t zbuf[1]; size = ExpandEnvironmentStringsW(wvalue, zbuf, 0); if (size) { apr_wchar_t *tmp = wvalue; /* The size returned by ExpandEnvironmentStringsW is wchars */ wvalue = apr_palloc(pool, size * 2); size = ExpandEnvironmentStringsW(tmp, wvalue, (DWORD)size); } } else { /* count wchars from RegQueryValueExW, rather than bytes */ size /= 2; } /* ###: deliberately overallocate all but the trailing null. * We could precalculate the exact buffer here instead, the question * is a matter of storage v.s. cpu cycles. */ valuelen = (size - 1) * 3 + 1; *result = apr_palloc(pool, valuelen); rv = apr_conv_ucs2_to_utf8(wvalue, &size, *result, &valuelen); if (rv != APR_SUCCESS) return rv; else if (size) return APR_ENAMETOOLONG; } #endif /* APR_HAS_UNICODE_FS */ #if APR_HAS_ANSI_FS ELSE_WIN_OS_IS_ANSI { /* Read to NULL buffer to determine value size */ rc = RegQueryValueEx(key->hkey, valuename, 0, &type, NULL, (DWORD *)&size); if (rc != ERROR_SUCCESS) return APR_FROM_OS_ERROR(rc); if ((size < 1) || (type != REG_SZ && type != REG_EXPAND_SZ)) { return APR_FROM_OS_ERROR(ERROR_INVALID_PARAMETER); } *result = apr_palloc(pool, size); /* Read value based on size query above */ rc = RegQueryValueEx(key->hkey, valuename, 0, &type, *result, (DWORD *)&size); if (rc != ERROR_SUCCESS) return APR_FROM_OS_ERROR(rc); if (type == REG_EXPAND_SZ) { /* Advise ExpandEnvironmentStrings that we have a zero char * buffer to force computation of the required length. */ char zbuf[1]; size = ExpandEnvironmentStrings(*result, zbuf, 0); if (size) { char *tmp = *result; *result = apr_palloc(pool, size); size = ExpandEnvironmentStrings(tmp, *result, (DWORD)size); } } } #endif return APR_SUCCESS; }
/* Shared by apr_app.c and start.c * * An internal apr function to convert an array of strings (either * a counted or NULL terminated list, such as an argv[argc] or env[] * list respectively) from wide Unicode strings to narrow utf-8 strings. * These are allocated from the MSVCRT's _CRT_BLOCK to trick the system * into trusting our store. */ int apr_wastrtoastr(char const * const * *retarr, wchar_t const * const *arr, int args) { apr_size_t elesize = 0; char **newarr; char *elements; char *ele; int arg; if (args < 0) { for (args = 0; arr[args]; ++args) ; } newarr = _malloc_dbg((args + 1) * sizeof(char *), _CRT_BLOCK, __FILE__, __LINE__); for (arg = 0; arg < args; ++arg) { newarr[arg] = (void*)(wcslen(arr[arg]) + 1); elesize += (apr_size_t)newarr[arg]; } /* This is a safe max allocation, we will realloc after * processing and return the excess to the free store. * 3 ucs bytes hold any single wchar_t value (16 bits) * 4 ucs bytes will hold a wchar_t pair value (20 bits) */ elesize = elesize * 3 + 1; ele = elements = _malloc_dbg(elesize * sizeof(char), _CRT_BLOCK, __FILE__, __LINE__); for (arg = 0; arg < args; ++arg) { apr_size_t len = (apr_size_t)newarr[arg]; apr_size_t newlen = elesize; newarr[arg] = ele; (void)apr_conv_ucs2_to_utf8(arr[arg], &len, newarr[arg], &elesize); newlen -= elesize; ele += newlen; assert(elesize && (len == 0)); } newarr[arg] = NULL; *(ele++) = '\0'; /* Return to the free store if the heap realloc is the least bit optimized */ ele = _realloc_dbg(elements, ele - elements, _CRT_BLOCK, __FILE__, __LINE__); if (ele != elements) { apr_size_t diff = ele - elements; for (arg = 0; arg < args; ++arg) { newarr[arg] += diff; } } *retarr = newarr; return args; }
svn_error_t * svn_nls_init(void) { svn_error_t *err = SVN_NO_ERROR; #ifdef ENABLE_NLS #ifdef WIN32 { WCHAR ucs2_path[MAX_PATH]; char* utf8_path; const char* internal_path; apr_pool_t* pool; apr_status_t apr_err; apr_size_t inwords, outbytes, outlength; apr_pool_create(&pool, 0); /* get exe name - our locale info will be in '../share/locale' */ inwords = GetModuleFileNameW(0, ucs2_path, sizeof(ucs2_path) / sizeof(ucs2_path[0])); if (! inwords) { /* We must be on a Win9x machine, so attempt to get an ANSI path, and convert it to Unicode. */ CHAR ansi_path[MAX_PATH]; if (GetModuleFileNameA(0, ansi_path, sizeof(ansi_path))) { inwords = MultiByteToWideChar(CP_ACP, 0, ansi_path, -1, ucs2_path, sizeof(ucs2_path) / sizeof(ucs2_path[0])); if (! inwords) { err = svn_error_createf(APR_EINVAL, NULL, _("Can't convert string to UCS-2: '%s'"), ansi_path); } } else { err = svn_error_create(APR_EINVAL, NULL, _("Can't get module file name")); } } if (! err) { outbytes = outlength = 3 * (inwords + 1); utf8_path = apr_palloc(pool, outlength); apr_err = apr_conv_ucs2_to_utf8(ucs2_path, &inwords, utf8_path, &outbytes); if (!apr_err && (inwords > 0 || outbytes == 0)) apr_err = APR_INCOMPLETE; if (apr_err) { err = svn_error_createf(apr_err, NULL, _("Can't convert module path " "to UTF-8 from UCS-2: '%s'"), ucs2_path); } else { utf8_path[outlength - outbytes] = '\0'; internal_path = svn_path_internal_style(utf8_path, pool); /* get base path name */ internal_path = svn_path_dirname(internal_path, pool); internal_path = svn_path_join(internal_path, SVN_LOCALE_RELATIVE_PATH, pool); bindtextdomain(PACKAGE_NAME, internal_path); } } svn_pool_destroy(pool); } #else bindtextdomain(PACKAGE_NAME, SVN_LOCALE_DIR); #ifdef HAVE_BIND_TEXTDOMAIN_CODESET bind_textdomain_codeset(PACKAGE_NAME, "UTF-8"); #endif #endif #endif return err; }
/** * Initialize the environment for all requests. * @param env the JNI environment for this request */ bool JNIUtil::JNIGlobalInit(JNIEnv *env) { // This method has to be run only once during the run a program. static bool run = false; svn_error_t *err; if (run) // already run return true; run = true; // Do not run this part more than one time. This leaves a small // time window when two threads create their first SVNClient and // SVNAdmin at the same time, but I do not see a better option // without APR already initialized if (g_inInit) return false; g_inInit = true; g_initEnv = env; apr_status_t status; /* Initialize the APR subsystem, and register an atexit() function * to Uninitialize that subsystem at program exit. */ status = apr_initialize(); if (status) { if (stderr) { char buf[1024]; apr_strerror(status, buf, sizeof(buf) - 1); fprintf(stderr, "%s: error: cannot initialize APR: %s\n", "svnjavahl", buf); } return FALSE; } /* This has to happen before any pools are created. */ if ((err = svn_dso_initialize2())) { if (stderr && err->message) fprintf(stderr, "%s", err->message); svn_error_clear(err); return FALSE; } if (0 > atexit(apr_terminate)) { if (stderr) fprintf(stderr, "%s: error: atexit registration failed\n", "svnjavahl"); return FALSE; } /* Create our top-level pool. */ g_pool = svn_pool_create(NULL); apr_allocator_t* allocator = apr_pool_allocator_get(g_pool); if (allocator) { /* Keep a maximum of 1 free block, to release memory back to the JVM (and other modules). */ apr_allocator_max_free_set(allocator, 1); } svn_utf_initialize2(FALSE, g_pool); /* Optimize character conversions */ svn_fs_initialize(g_pool); /* Avoid some theoretical issues */ svn_ra_initialize(g_pool); /* We shouldn't fill the JVMs memory with FS cache data unless explictly requested. */ { svn_cache_config_t settings = *svn_cache_config_get(); settings.cache_size = 0; settings.file_handle_count = 0; settings.single_threaded = FALSE; svn_cache_config_set(&settings); } #ifdef ENABLE_NLS #ifdef WIN32 { WCHAR ucs2_path[MAX_PATH]; char *utf8_path; const char *internal_path; apr_pool_t *pool; apr_status_t apr_err; apr_size_t inwords, outbytes; unsigned int outlength; pool = svn_pool_create(g_pool); /* get dll name - our locale info will be in '../share/locale' */ inwords = sizeof(ucs2_path) / sizeof(ucs2_path[0]); HINSTANCE moduleHandle = GetModuleHandle("libsvnjavahl-1"); GetModuleFileNameW(moduleHandle, ucs2_path, inwords); inwords = lstrlenW(ucs2_path); outbytes = outlength = 3 * (inwords + 1); utf8_path = reinterpret_cast<char *>(apr_palloc(pool, outlength)); apr_err = apr_conv_ucs2_to_utf8((const apr_wchar_t *) ucs2_path, &inwords, utf8_path, &outbytes); if (!apr_err && (inwords > 0 || outbytes == 0)) apr_err = APR_INCOMPLETE; if (apr_err) { if (stderr) fprintf(stderr, "Can't convert module path to UTF-8"); return FALSE; } utf8_path[outlength - outbytes] = '\0'; internal_path = svn_dirent_internal_style(utf8_path, pool); /* get base path name */ internal_path = svn_dirent_dirname(internal_path, pool); internal_path = svn_dirent_join(internal_path, SVN_LOCALE_RELATIVE_PATH, pool); bindtextdomain(PACKAGE_NAME, internal_path); svn_pool_destroy(pool); } #else bindtextdomain(PACKAGE_NAME, SVN_LOCALE_DIR); #endif #endif #if defined(WIN32) || defined(__CYGWIN__) /* See http://svn.apache.org/repos/asf/subversion/trunk/notes/asp-dot-net-hack.txt */ /* ### This code really only needs to be invoked by consumers of ### the libsvn_wc library, which basically means SVNClient. */ if (getenv("SVN_ASP_DOT_NET_HACK")) { err = svn_wc_set_adm_dir("_svn", g_pool); if (err) { if (stderr) { fprintf(stderr, "%s: error: SVN_ASP_DOT_NET_HACK failed: %s\n", "svnjavahl", err->message); } svn_error_clear(err); return FALSE; } } #endif svn_error_set_malfunction_handler(svn_error_raise_on_malfunction); // Build all mutexes. g_finalizedObjectsMutex = new JNIMutex(g_pool); if (isExceptionThrown()) return false; g_logMutex = new JNIMutex(g_pool); if (isExceptionThrown()) return false; // initialized the thread local storage if (!JNIThreadData::initThreadData()) return false; setEnv(env); if (isExceptionThrown()) return false; g_initEnv = NULL; g_inInit = false; return true; }
/* * Test every possible byte value. * If the test passes or fails at this byte value we are done. * Otherwise iterate test_nrange again, appending another byte. */ void test_ranges() { struct testval ntest, wtest; apr_status_t nrc, wrc; apr_size_t inlen; unsigned long matches = 0; memset(&ntest, 0, sizeof(ntest)); ++ntest.nl; memset(&wtest, 0, sizeof(wtest)); ++wtest.wl; do { do { inlen = ntest.nl; ntest.wl = sizeof(ntest.w) / 2; nrc = apr_conv_utf8_to_ucs2(ntest.n, &inlen, ntest.w, &ntest.wl); if (nrc == APR_SUCCESS) { ntest.wl = (sizeof(ntest.w) / 2) - ntest.wl; break; } if (nrc == APR_INCOMPLETE) { ++ntest.nl; if (ntest.nl > 6) { printf ("\n\nUnexpected utf8 sequence of >6 bytes;\n"); exit(255); } continue; } else { while (!(++ntest.n[ntest.nl - 1])) { if (!(--ntest.nl)) break; } } } while (ntest.nl); do { inlen = wtest.wl; wtest.nl = sizeof(wtest.n); wrc = apr_conv_ucs2_to_utf8(wtest.w, &inlen, wtest.n, &wtest.nl); if (wrc == APR_SUCCESS) { wtest.nl = sizeof(wtest.n) - wtest.nl; break; } else { if (!(++wtest.w[wtest.wl - 1])) { if (wtest.wl == 1) ++wtest.wl; else ++wtest.w[0]; /* On the second pass, ensure lead word is incomplete */ do { inlen = 1; wtest.nl = sizeof(wtest.n); if (apr_conv_ucs2_to_utf8(wtest.w, &inlen, wtest.n, &wtest.nl) == APR_INCOMPLETE) break; if (!(++wtest.w[0])) { wtest.wl = 0; break; } } while (1); } } } while (wtest.wl); if (!ntest.nl && !wtest.wl) break; /* Identical? */ if ((wtest.nl != ntest.nl) || (memcmp(wtest.n, ntest.n, ntest.nl) != 0) || (wtest.wl != ntest.wl) || (memcmp(ntest.w, wtest.w, wtest.wl * 2) != 0)) { printf ("\n\nMismatch of w/n conversion at;\n"); displaynw(&ntest, &wtest); exit(255); } ++matches; while (!(++ntest.n[ntest.nl - 1])) { if (!(--ntest.nl)) break; } if (!(++wtest.w[wtest.wl - 1])) { if (wtest.wl == 1) ++wtest.wl; else ++wtest.w[0]; /* On the second pass, ensure lead word is incomplete */ do { inlen = 1; wtest.nl = sizeof(wtest.n); if (apr_conv_ucs2_to_utf8(wtest.w, &inlen, wtest.n, &wtest.nl) == APR_INCOMPLETE) break; if (!(++wtest.w[0])) { wtest.wl = 0; break; } } while (1); } } while (wtest.wl || ntest.nl); printf ("\n\nutf8 and ucs2 sequences of %lu transformations matched OK.\n", matches); }
svn_error_t * svn_config__win_config_path(const char **folder, int system_path, apr_pool_t *pool) { /* ### Adding CSIDL_FLAG_CREATE here, because those folders really must exist. I'm not too sure about the SHGFP_TYPE_CURRENT semancics, though; maybe we should use ..._DEFAULT instead? */ const int csidl = ((system_path ? CSIDL_COMMON_APPDATA : CSIDL_APPDATA) | CSIDL_FLAG_CREATE); int style; apr_status_t apr_err = apr_filepath_encoding(&style, pool); if (apr_err) return svn_error_wrap_apr(apr_err, "Can't determine the native path encoding"); if (style == APR_FILEPATH_ENCODING_UTF8) { WCHAR folder_ucs2[MAX_PATH]; apr_size_t inwords, outbytes, outlength; char *folder_utf8; if (S_OK != SHGetFolderPathW(NULL, csidl, NULL, SHGFP_TYPE_CURRENT, folder_ucs2)) goto no_folder_path; /* ### When mapping from UCS-2 to UTF-8, we need at most 3 bytes per wide char, plus extra space for the nul terminator. */ inwords = lstrlenW(folder_ucs2); outbytes = outlength = 3 * (inwords + 1); folder_utf8 = apr_palloc(pool, outlength); apr_err = apr_conv_ucs2_to_utf8(folder_ucs2, &inwords, folder_utf8, &outbytes); if (!apr_err && (inwords > 0 || outbytes == 0)) apr_err = APR_INCOMPLETE; if (apr_err) return svn_error_wrap_apr(apr_err, "Can't convert config path to UTF-8"); /* Note that apr_conv_ucs2_to_utf8 does _not_ terminate the outgoing buffer. */ folder_utf8[outlength - outbytes] = '\0'; *folder = folder_utf8; } else if (style == APR_FILEPATH_ENCODING_LOCALE) { char folder_ansi[MAX_PATH]; if (S_OK != SHGetFolderPathA(NULL, csidl, NULL, SHGFP_TYPE_CURRENT, folder_ansi)) goto no_folder_path; SVN_ERR(svn_utf_cstring_to_utf8(folder, folder_ansi, pool)); } else { /* There is no third option on Windows; we should never get here. */ return svn_error_createf(APR_EINVAL, NULL, "Unknown native path encoding (%d)", style); } *folder = svn_path_internal_style(*folder, pool); return SVN_NO_ERROR; no_folder_path: return svn_error_create(SVN_ERR_BAD_FILENAME, NULL, (system_path ? "Can't determine the system config path" : "Can't determine the user's config path")); }