Fix T97906: OpenEXR files with lower case xyz channel names not read correctly

Adds some utility functions to avoid using toupper() which depends on the
locale and should not be used for this type of parsing.
This commit is contained in:
Brecht Van Lommel 2022-05-09 17:17:03 +02:00
parent 686abf1850
commit 78f61bf8c1
Notes: blender-bot 2023-02-14 10:29:32 +01:00
Referenced by issue #97906, EXR Image: Normal and position passes from other render engine are not readable in blender
3 changed files with 36 additions and 21 deletions

View File

@ -343,8 +343,16 @@ int BLI_strcmp_ignore_pad(const char *str1, const char *str2, char pad) ATTR_WAR
*/
size_t BLI_strnlen(const char *str, size_t maxlen) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/**
* String case conversion, not affected by locale.
*/
void BLI_str_tolower_ascii(char *str, size_t len) ATTR_NONNULL();
void BLI_str_toupper_ascii(char *str, size_t len) ATTR_NONNULL();
char BLI_tolower_ascii(const char c);
char BLI_toupper_ascii(const char c);
/**
* Strip white-space from end of the string.
*/

View File

@ -914,14 +914,22 @@ size_t BLI_strnlen(const char *s, const size_t maxlen)
/** \name String Case Conversion
* \{ */
char BLI_tolower_ascii(const char c)
{
return (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c;
}
char BLI_toupper_ascii(const char c)
{
return (c >= 'a' && c <= 'z') ? c - ('a' - 'A') : c;
}
void BLI_str_tolower_ascii(char *str, const size_t len)
{
size_t i;
for (i = 0; (i < len) && str[i]; i++) {
if (str[i] >= 'A' && str[i] <= 'Z') {
str[i] += 'a' - 'A';
}
str[i] = BLI_tolower_ascii(str[i]);
}
}
@ -930,9 +938,7 @@ void BLI_str_toupper_ascii(char *str, const size_t len)
size_t i;
for (i = 0; (i < len) && str[i]; i++) {
if (str[i] >= 'a' && str[i] <= 'z') {
str[i] -= 'a' - 'A';
}
str[i] = BLI_toupper_ascii(str[i]);
}
}

View File

@ -1394,12 +1394,10 @@ static int imb_exr_split_channel_name(ExrChannel *echan, char *layname, char *pa
const char *name = echan->m->name.c_str();
const char *end = name + strlen(name);
const char *token;
char tokenbuf[EXR_TOT_MAXNAME];
int len;
/* some multilayers have the combined buffer with names A B G R saved */
if (name[1] == 0) {
echan->chan_id = name[0];
echan->chan_id = BLI_toupper_ascii(name[0]);
layname[0] = '\0';
if (ELEM(name[0], 'R', 'G', 'B', 'A')) {
@ -1416,13 +1414,17 @@ static int imb_exr_split_channel_name(ExrChannel *echan, char *layname, char *pa
}
/* last token is channel identifier */
len = imb_exr_split_token(name, end, &token);
size_t len = imb_exr_split_token(name, end, &token);
if (len == 0) {
printf("multilayer read: bad channel name: %s\n", name);
return 0;
}
char channelname[EXR_TOT_MAXNAME];
BLI_strncpy(channelname, token, std::min(len + 1, sizeof(channelname)));
if (len == 1) {
echan->chan_id = token[0];
echan->chan_id = BLI_toupper_ascii(channelname[0]);
}
else if (len > 1) {
bool ok = false;
@ -1436,36 +1438,35 @@ static int imb_exr_split_channel_name(ExrChannel *echan, char *layname, char *pa
*
* Here we do some magic to distinguish such cases.
*/
if (ELEM(token[1], 'X', 'Y', 'Z') || ELEM(token[1], 'R', 'G', 'B') ||
ELEM(token[1], 'U', 'V', 'A')) {
echan->chan_id = token[1];
const char chan_id = BLI_toupper_ascii(channelname[1]);
if (ELEM(chan_id, 'X', 'Y', 'Z', 'R', 'G', 'B', 'U', 'V', 'A')) {
echan->chan_id = chan_id;
ok = true;
}
}
else if (BLI_strcaseeq(token, "red")) {
else if (BLI_strcaseeq(channelname, "red")) {
echan->chan_id = 'R';
ok = true;
}
else if (BLI_strcaseeq(token, "green")) {
else if (BLI_strcaseeq(channelname, "green")) {
echan->chan_id = 'G';
ok = true;
}
else if (BLI_strcaseeq(token, "blue")) {
else if (BLI_strcaseeq(channelname, "blue")) {
echan->chan_id = 'B';
ok = true;
}
else if (BLI_strcaseeq(token, "alpha")) {
else if (BLI_strcaseeq(channelname, "alpha")) {
echan->chan_id = 'A';
ok = true;
}
else if (BLI_strcaseeq(token, "depth")) {
else if (BLI_strcaseeq(channelname, "depth")) {
echan->chan_id = 'Z';
ok = true;
}
if (ok == false) {
BLI_strncpy(tokenbuf, token, std::min(len + 1, EXR_TOT_MAXNAME));
printf("multilayer read: unknown channel token: %s\n", tokenbuf);
printf("multilayer read: unknown channel token: %s\n", channelname);
return 0;
}
}