Kaydet (Commit) d32506e9 authored tarafından Mike Kaganski's avatar Mike Kaganski

cppuhelper_detail_findSofficePath: use Unicode on Windows

On Windows, UTF-8 is never current locale encoding; so using 8-bit
strings will always fail for paths containing characters outside
of current codepage.
Also fix leaks caused by failing to release its result: previously
it could return either result of getenv (that shouldn't get freed),
or an allocated string, but never got freed; now the result is
always allocated and properly freed.

Change-Id: I8b255dea20040eec0572de2b34280749fe8f071c
Reviewed-on: https://gerrit.libreoffice.org/42743Tested-by: 's avatarJenkins <ci@libreoffice.org>
Reviewed-by: 's avatarMike Kaganski <mike.kaganski@collabora.com>
üst 892c719f
......@@ -87,21 +87,28 @@ Reference< XComponentContext > SAL_CALL bootstrap()
try
{
char const * p1 = cppuhelper_detail_findSofficePath();
auto* p1 = cppuhelper_detail_findSofficePath();
if (p1 == nullptr) {
throw BootstrapException(
"no soffice installation found!");
}
rtl::OUString p2;
if (!rtl_convertStringToUString(
#if defined(_WIN32)
p2 = SAL_U(p1);
free(p1);
#else
bool bOk = rtl_convertStringToUString(
&p2.pData, p1, std::strlen(p1), osl_getThreadTextEncoding(),
(RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR |
RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR |
RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)))
RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR));
free(p1);
if (!bOk)
{
throw BootstrapException(
"bad characters in soffice installation path!");
}
#endif
OUString path;
if (osl::FileBase::getFileURLFromSystemPath(p2, path) !=
osl::FileBase::E_None)
......
......@@ -39,36 +39,42 @@
* @return the installation path or NULL, if no installation was found or
* if an error occurred
*/
static char* getPathFromRegistryKey( HKEY hroot, const char* subKeyName )
static wchar_t* getPathFromRegistryKey( HKEY hroot, const wchar_t* subKeyName )
{
HKEY hkey;
DWORD type;
char* data = NULL;
wchar_t* data = NULL;
DWORD size;
/* open the specified registry key */
if ( RegOpenKeyEx( hroot, subKeyName, 0, KEY_READ, &hkey ) != ERROR_SUCCESS )
if ( RegOpenKeyExW( hroot, subKeyName, 0, KEY_READ, &hkey ) != ERROR_SUCCESS )
{
return NULL;
}
/* find the type and size of the default value */
if ( RegQueryValueEx( hkey, NULL, NULL, &type, NULL, &size) != ERROR_SUCCESS )
if ( RegQueryValueExW( hkey, NULL, NULL, &type, NULL, &size) != ERROR_SUCCESS )
{
RegCloseKey( hkey );
return NULL;
}
/* get memory to hold the default value */
data = (char*) malloc( size );
data = (wchar_t*) malloc( size + sizeof(wchar_t) );
/* read the default value */
if ( RegQueryValueEx( hkey, NULL, NULL, &type, (LPBYTE) data, &size ) != ERROR_SUCCESS )
if ( RegQueryValueExW( hkey, NULL, NULL, &type, (LPBYTE) data, &size ) != ERROR_SUCCESS )
{
RegCloseKey( hkey );
free( data );
return NULL;
}
// According to https://msdn.microsoft.com/en-us/ms724911, If the data has the REG_SZ,
// REG_MULTI_SZ or REG_EXPAND_SZ type, the string may not have been stored with the
// proper terminating null characters
data[size / sizeof(wchar_t)] = 0;
/* release registry key handle */
RegCloseKey( hkey );
......@@ -81,14 +87,22 @@ static char* getPathFromRegistryKey( HKEY hroot, const char* subKeyName )
* @return the installation path or NULL, if no installation was found or
* if an error occurred
*/
static char* platformSpecific()
static wchar_t* platformSpecific()
{
const char* SUBKEYNAME = "Software\\LibreOffice\\UNO\\InstallPath";
const wchar_t* UNOPATHVARNAME = L"UNO_PATH";
char* path = NULL;
/* get the installation path from the UNO_PATH environment variable */
wchar_t* env = _wgetenv(UNOPATHVARNAME);
if (env && env[0])
{
return wcsdup(env);
}
const wchar_t* SUBKEYNAME = L"Software\\LibreOffice\\UNO\\InstallPath";
/* read the key's default value from HKEY_CURRENT_USER */
path = getPathFromRegistryKey( HKEY_CURRENT_USER, SUBKEYNAME );
wchar_t* path = getPathFromRegistryKey( HKEY_CURRENT_USER, SUBKEYNAME );
if ( path == NULL )
{
......@@ -115,13 +129,17 @@ static char* platformSpecific()
*/
static char* platformSpecific(void)
{
const char* UNOPATHVARNAME = "UNO_PATH";
/* get the installation path from the UNO_PATH environment variable */
char* env = getenv(UNOPATHVARNAME);
const int SEPARATOR = '/';
const char* PATHSEPARATOR = ":";
const char* PATHVARNAME = "PATH";
const char* APPENDIX = "/libreoffice";
char* path = NULL;
char* env = NULL;
char* str = NULL;
char* dir = NULL;
char* sep = NULL;
......@@ -129,6 +147,11 @@ static char* platformSpecific(void)
char buffer[PATH_MAX];
int pos;
if (env && env[0])
{
return strdup(env);
}
/* get the value of the PATH environment variable */
env = getenv( PATHVARNAME );
if (env == NULL)
......@@ -184,19 +207,14 @@ static char* platformSpecific(void)
#endif
char const* cppuhelper_detail_findSofficePath()
#if defined(_WIN32)
wchar_t*
#else
char*
#endif
cppuhelper_detail_findSofficePath()
{
const char* UNOPATHVARNAME = "UNO_PATH";
char* path = NULL;
/* get the installation path from the UNO_PATH environment variable */
path = getenv( UNOPATHVARNAME );
if (!path || !path[0])
path = platformSpecific();
return path;
return platformSpecific();
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
......@@ -27,8 +27,14 @@ extern "C" {
#endif
/* Internal function to find an soffice installation.
Not to be called by client code */
char const* cppuhelper_detail_findSofficePath(void);
Not to be called by client code.
Returned pointer must be released with free() */
#if defined(_WIN32)
wchar_t*
#else
char*
#endif
cppuhelper_detail_findSofficePath(void);
#if defined __cplusplus
}
......
......@@ -32,7 +32,7 @@
#include "rtl/string.h"
#include "sal/types.h"
char const* getPath(void);
char* getPath(void);
char* createCommandName( char* argv0 );
static const int SEPARATOR = '/';
......@@ -63,7 +63,7 @@ static const char* PATHSEPARATOR = ":";
*/
int main( int argc, char *argv[] )
{
char const* path;
char* path;
char* cmdname;
(void) argc; /* avoid warning about unused parameter */
......@@ -80,9 +80,7 @@ int main( int argc, char *argv[] )
#else
static const char* ENVVARNAME = "LD_LIBRARY_PATH";
#endif
char * libpath;
int freeLibpath;
char* libpath;
char* value;
char* envstr;
int size;
......@@ -96,6 +94,7 @@ int main( int argc, char *argv[] )
pathlen + RTL_CONSTASCII_LENGTH(unoinfoSuffix) + 1);
/*TODO: overflow */
if (unoinfo == NULL) {
free(path);
fprintf(stderr, "Error: out of memory!\n");
exit(EXIT_FAILURE);
}
......@@ -168,13 +167,12 @@ int main( int argc, char *argv[] )
fprintf(stderr, "Error: executing unoinfo failed!\n");
exit(EXIT_FAILURE);
}
freeLibpath = 1;
free(path);
}
else
{
/* Assume an old OOo 2.x installation without unoinfo: */
libpath = (char *) path;
freeLibpath = 0;
libpath = path;
}
value = getenv( ENVVARNAME );
......@@ -196,10 +194,7 @@ int main( int argc, char *argv[] )
strcat( envstr, "=" );
#endif
strcat( envstr, libpath );
if ( freeLibpath != 0 )
{
free( libpath );
}
free( libpath );
if ( value != NULL )
{
strcat( envstr, PATHSEPARATOR );
......@@ -233,11 +228,12 @@ int main( int argc, char *argv[] )
* Gets the path of a UNO installation.
*
* @return the installation path or NULL, if no installation was specified or
* found, or if an error occurred
* found, or if an error occurred.
* Returned pointer must be released with free()
*/
char const* getPath(void)
char* getPath(void)
{
char const* path = cppuhelper_detail_findSofficePath();
char* path = cppuhelper_detail_findSofficePath();
if ( path == NULL )
{
......
......@@ -36,10 +36,11 @@
#include "cppuhelper/findsofficepath.h"
#include "sal/types.h"
#define MY_LENGTH(s) (sizeof (s) / sizeof *(s) - 1)
#define MY_SIZE(s) (sizeof (s) / sizeof *(s))
#define MY_LENGTH(s) (MY_SIZE(s) - 1)
char const* getPath(void);
char* createCommandLine( char const * lpCmdLine );
wchar_t* getPath(void);
wchar_t* createCommandLine( wchar_t const * lpCmdLine );
FILE* getErrorFile( int create );
void writeError( const char* errstr );
void closeErrorFile(void);
......@@ -64,28 +65,15 @@ void closeErrorFile(void);
* root key HKEY_CURRENT_USER in the Windows Registry. If this key is missing,
* the key is read from the root key HKEY_LOCAL_MACHINE.</p>
*/
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow )
int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPWSTR lpCmdLine, int nCmdShow )
{
const char* ENVVARNAME = "PATH";
const char* PATHSEPARATOR = ";";
char const* path = NULL;
char path2[MAX_PATH];
char* value = NULL;
char* envstr = NULL;
char* cmdline = NULL;
size_t size;
STARTUPINFO startup_info;
PROCESS_INFORMATION process_info;
BOOL bCreate;
(void) hInstance; /* unused */
(void) hPrevInstance; /* unused */
(void) nCmdShow; /* unused */
/* get the path of the UNO installation */
path = getPath();
wchar_t* path = getPath();
if ( path != NULL )
{
......@@ -93,56 +81,54 @@ int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
MY_LENGTH(L"\"") + MAX_PATH +
MY_LENGTH(L"\\unoinfo.exe\" c++")];
/* hopefully does not overflow */
int pathsize;
SECURITY_ATTRIBUTES sec;
HANDLE temp;
HANDLE stdoutRead;
HANDLE stdoutWrite;
STARTUPINFOW startinfo;
PROCESS_INFORMATION procinfo;
int ret;
cmd[0] = L'"';
pathsize = MultiByteToWideChar(CP_ACP, 0, path, -1, cmd + 1, MAX_PATH);
if (pathsize == 0) {
writeError("Error: MultiByteToWideChar failed!\n");
closeErrorFile();
return 1;
}
wcscpy(cmd + 1, path);
if (wcschr(cmd + 1, L'"') != NULL) {
free(path);
writeError("Error: bad characters in UNO installation path!\n");
closeErrorFile();
return 1;
}
size_t pathsize = wcslen(cmd);
wcscpy(
cmd + pathsize,
&L"\\unoinfo.exe\" c++"[
pathsize == 1 || cmd[pathsize - 1] != L'\\' ? 0 : 1]);
SECURITY_ATTRIBUTES sec;
sec.nLength = sizeof (SECURITY_ATTRIBUTES);
sec.lpSecurityDescriptor = NULL;
sec.bInheritHandle = TRUE;
HANDLE stdoutRead;
HANDLE stdoutWrite;
HANDLE temp;
if (CreatePipe(&temp, &stdoutWrite, &sec, 0) == 0 ||
DuplicateHandle(
GetCurrentProcess(), temp, GetCurrentProcess(), &stdoutRead, 0,
FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS) == 0)
{
free(path);
writeError("Error: CreatePipe/DuplicateHandle failed!\n");
closeErrorFile();
return 1;
}
memset(&startinfo, 0, sizeof (STARTUPINFOW));
startinfo.cb = sizeof (STARTUPINFOW);
STARTUPINFOW startinfo;
PROCESS_INFORMATION procinfo;
memset(&startinfo, 0, sizeof(startinfo));
startinfo.cb = sizeof(startinfo);
startinfo.lpDesktop = L"";
startinfo.dwFlags = STARTF_USESTDHANDLES;
startinfo.hStdOutput = stdoutWrite;
ret = CreateProcessW(
BOOL ret = CreateProcessW(
NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &startinfo, &procinfo);
if (ret != 0) {
if (ret != FALSE) {
// Release result of GetPath()
free(path);
char * buf = NULL;
char * tmp;
DWORD n = 1000;
DWORD k = 0;
DWORD exitcode;
int path2size;
CloseHandle(stdoutWrite);
CloseHandle(procinfo.hThread);
for (;;) {
......@@ -193,22 +179,19 @@ int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
closeErrorFile();
return 1;
}
if (k == 0) {
path2size = 0;
} else {
path2size = WideCharToMultiByte(
CP_ACP, 0, (wchar_t *) buf, k / 2, path2, MAX_PATH - 1,
NULL, NULL);
if (path2size == 0) {
writeError("Error: converting unoinfo output failed!\n");
closeErrorFile();
return 1;
}
path = (wchar_t*)realloc(buf, k + sizeof(wchar_t));
if (path == NULL)
{
free(buf);
writeError(
"Error: out of memory zero-terminating unoinfo output!\n");
closeErrorFile();
return 1;
}
path2[path2size] = '\0';
path = path2;
path[k / 2] = L'\0';
} else {
if (GetLastError() != ERROR_FILE_NOT_FOUND) {
free(path);
writeError("Error: calling unoinfo failed!\n");
closeErrorFile();
return 1;
......@@ -218,27 +201,30 @@ int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
}
/* get the value of the PATH environment variable */
value = getenv( ENVVARNAME );
const wchar_t* ENVVARNAME = L"PATH";
const wchar_t* PATHSEPARATOR = L";";
wchar_t* value = _wgetenv( ENVVARNAME );
/*
* add the UNO installation path to the PATH environment variable;
* note that this only affects the environment variable of the current
* process, the command processor's environment is not changed
*/
size = strlen( ENVVARNAME ) + strlen( "=" ) + strlen( path ) + 1;
size_t size = wcslen( ENVVARNAME ) + wcslen( L"=" ) + wcslen( path ) + 1;
if ( value != NULL )
size += strlen( PATHSEPARATOR ) + strlen( value );
envstr = (char*) malloc( size );
strcpy( envstr, ENVVARNAME );
strcat( envstr, "=" );
strcat( envstr, path );
size += wcslen( PATHSEPARATOR ) + wcslen( value );
wchar_t* envstr = (wchar_t*) malloc( size*sizeof(wchar_t) );
wcscpy( envstr, ENVVARNAME );
wcscat( envstr, L"=" );
wcscat( envstr, path );
if ( value != NULL )
{
strcat( envstr, PATHSEPARATOR );
strcat( envstr, value );
wcscat( envstr, PATHSEPARATOR );
wcscat( envstr, value );
}
_putenv( envstr );
_wputenv( envstr );
free( envstr );
free( path );
}
else
{
......@@ -246,7 +232,7 @@ int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
}
/* create the command line for the application process */
cmdline = createCommandLine( lpCmdLine );
wchar_t* cmdline = createCommandLine( lpCmdLine );
if ( cmdline == NULL )
{
writeError( "Error: cannot create command line!\n" );
......@@ -255,10 +241,12 @@ int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
}
/* create the application process */
memset( &startup_info, 0, sizeof( STARTUPINFO ) );
startup_info.cb = sizeof( STARTUPINFO );
bCreate = CreateProcess( NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL,
&startup_info, &process_info );
STARTUPINFOW startup_info;
PROCESS_INFORMATION process_info;
memset( &startup_info, 0, sizeof(startup_info) );
startup_info.cb = sizeof(startup_info);
BOOL bCreate = CreateProcessW( NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL,
&startup_info, &process_info );
free( cmdline );
if ( !bCreate )
{
......@@ -277,11 +265,12 @@ int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
* Gets the path of a UNO installation.
*
* @return the installation path or NULL, if no installation was specified or
* found, or if an error occurred
* found, or if an error occurred.
* Returned pointer must be released with free()
*/
char const* getPath()
wchar_t* getPath()
{
char const* path = cppuhelper_detail_findSofficePath();
wchar_t* path = cppuhelper_detail_findSofficePath();
if ( path == NULL )
writeError( "Warning: getting path from Windows Registry failed!\n" );
......@@ -302,38 +291,38 @@ char const* getPath()
* @return the command line for the application process or NULL, if an error
* occurred
*/
char* createCommandLine( char const * appendix )
wchar_t* createCommandLine( wchar_t const * appendix )
{
const char* CMDPREFIX = "_";
const char* DQUOTE = "\"";
const char* SPACE = " ";
const wchar_t* CMDPREFIX = L"_";
const wchar_t* DQUOTE = L"\"";
const wchar_t* SPACE = L" ";
char* cmdline = NULL;
wchar_t* cmdline = NULL;
char cmdname[ _MAX_PATH ];
char drive[ _MAX_DRIVE ];
char dir[ _MAX_PATH ];
char base[ _MAX_FNAME ];
char newbase[ _MAX_FNAME ];
char ext[ _MAX_EXT ];
wchar_t cmdname[ _MAX_PATH ];
wchar_t drive[ _MAX_DRIVE ];
wchar_t dir[ _MAX_PATH ];
wchar_t base[ _MAX_FNAME ];
wchar_t newbase[ _MAX_FNAME ];
wchar_t ext[ _MAX_EXT ];
/* get the absolute path of the executable file */
if ( GetModuleFileName( NULL, cmdname, sizeof( cmdname ) ) )
if ( GetModuleFileNameW( NULL, cmdname, MY_SIZE( cmdname ) ) )
{
/* prefix the executable file name by '_' */
_splitpath( cmdname, drive, dir, base, ext );
strcpy( newbase, CMDPREFIX );
strcat( newbase, base );
_makepath( cmdname, drive, dir, newbase, ext );
_wsplitpath( cmdname, drive, dir, base, ext );
wcscpy( newbase, CMDPREFIX );
wcscat( newbase, base );
_wmakepath( cmdname, drive, dir, newbase, ext );
/* create the command line */
cmdline = (char*) malloc( strlen( DQUOTE ) + strlen( cmdname ) +
strlen ( DQUOTE ) + strlen( SPACE ) + strlen( appendix ) + 1 );
strcpy( cmdline, DQUOTE );
strcat( cmdline, cmdname );
strcat( cmdline, DQUOTE );
strcat( cmdline, SPACE );
strcat( cmdline, appendix );
cmdline = (wchar_t*) malloc( (wcslen( DQUOTE ) + wcslen( cmdname ) +
wcslen ( DQUOTE ) + wcslen( SPACE ) + wcslen( appendix ) + 1) * sizeof(wchar_t) );
wcscpy( cmdline, DQUOTE );
wcscat( cmdline, cmdname );
wcscat( cmdline, DQUOTE );
wcscat( cmdline, SPACE );
wcscat( cmdline, appendix );
}
return cmdline;
......@@ -356,38 +345,38 @@ char* createCommandLine( char const * appendix )
*/
FILE* getErrorFile( int create )
{
const char* MODE = "w";
const char* BASEPOSTFIX = "-error";
const char* EXTENSION = ".log";
const wchar_t* MODE = L"w";
const wchar_t* BASEPOSTFIX = L"-error";
const wchar_t* EXTENSION = L".log";
static FILE* ferr = NULL;
char fname[ _MAX_PATH ];
char drive[ _MAX_DRIVE ];
char dir[ _MAX_PATH ];
char base[ _MAX_FNAME ];
char newbase[ _MAX_FNAME ];
char ext[ _MAX_EXT ];
wchar_t fname[ _MAX_PATH ];
wchar_t drive[ _MAX_DRIVE ];
wchar_t dir[ _MAX_PATH ];
wchar_t base[ _MAX_FNAME ];
wchar_t newbase[ _MAX_FNAME ];
wchar_t ext[ _MAX_EXT ];
if ( ferr == NULL && create )
{
/* get the absolute path of the executable file */
if ( GetModuleFileName( NULL, fname, sizeof( fname ) ) )
if ( GetModuleFileNameW( NULL, fname, MY_SIZE( fname ) ) )
{
/* create error file in the directory of the executable file */
_splitpath( fname, drive, dir, base, ext );
strcpy( newbase, base );
strcat( newbase, BASEPOSTFIX );
_makepath( fname, drive, dir, newbase, EXTENSION );
ferr = fopen( fname, MODE );
_wsplitpath( fname, drive, dir, base, ext );
wcscpy( newbase, base );
wcscat( newbase, BASEPOSTFIX );
_wmakepath( fname, drive, dir, newbase, EXTENSION );
ferr = _wfopen( fname, MODE );
if ( ferr == NULL )
{
/* create error file in the temp directory */
GetTempPath( sizeof( fname ), fname );
strcat( fname, newbase );
strcat( fname, EXTENSION );
ferr = fopen( fname, MODE );
GetTempPathW(MY_SIZE( fname ), fname );
wcscat( fname, newbase );
wcscat( fname, EXTENSION );
ferr = _wfopen( fname, MODE );
}
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment