Fix: BLI_getenv returns ascii not UTF8 on windows

BLI_getenv has always incorrectly returned ascii rather
than UTF-8. This change corrects this behaviour.

This resolves issues when the `BLENDER_USER_CONFIG`
environment variable contains a path with Unicode characters
on windows as reported in T74510 (but unlikely the root
cause for the issue at hand there)

Differential Revision: https://developer.blender.org/D9831

Reviewed by: brecht
This commit is contained in:
Ray molenkamp 2020-12-11 11:59:14 -07:00
parent 92ab76c38f
commit 87b19b3aba
Notes: blender-bot 2023-02-13 23:16:01 +01:00
Referenced by commit 0dbbcaf1e6, Fix: Fix potential memory leak in BLI_getenv
Referenced by issue #74510, Various Addons using filesystem properties (PROP_FILEPATH etc): UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe0 in position 24: invalid continuation byte
1 changed files with 20 additions and 7 deletions

View File

@ -32,6 +32,7 @@
#include "BLI_fnmatch.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
#include "BLI_string_utf8.h"
#include "BLI_utildefines.h"
#ifdef WIN32
@ -1307,18 +1308,30 @@ void BLI_setenv_if_new(const char *env, const char *val)
* On windows getenv gets its variables from a static copy of the environment variables taken at
* process start-up, causing it to not pick up on environment variables created during runtime.
* This function uses an alternative method to get environment variables that does pick up on
* runtime environment variables.
* runtime environment variables. The result will be UTF-8 encoded.
*/
const char *BLI_getenv(const char *env)
{
#ifdef _MSC_VER
static char buffer[32767]; /* 32767 is the total size of the environment block on windows*/
if (GetEnvironmentVariableA(env, buffer, sizeof(buffer))) {
return buffer;
}
else {
return NULL;
const char *result = NULL;
static wchar_t buffer[32768]; /* 32767 is the maximum size of the environment variable on
windows, reserve one more character for the zero terminator. */
wchar_t *env_16 = alloc_utf16_from_8(env, 0);
if (env_16) {
if (GetEnvironmentVariableW(env_16, buffer, ARRAY_SIZE(buffer))) {
char *res_utf8 = alloc_utf_8_from_16(buffer, 0);
// make sure the result is valid, and will fit into our temporary storage buffer
if (res_utf8 && (strlen(res_utf8) + 1) < sizeof(buffer)) {
// We are re-using the utf16 buffer here, since allocating a second static buffer to
// contain the UTF-8 version to return would be wasteful.
memcpy(buffer, res_utf8, strlen(res_utf8) + 1);
free(res_utf8);
result = (const char *)buffer;
}
}
}
return result;
#else
return getenv(env);
#endif