From d44d3b1f0abb743893c5e07ceb802ca8a7b5a0de Mon Sep 17 00:00:00 2001 From: jp9000 Date: Sat, 21 Mar 2015 13:23:41 -0700 Subject: [PATCH] libobs: Use locale-independent double conversion Prevents issues on specific locales, especially where decimal points are represented by commas rather than periods. --- libobs/graphics/effect-parser.c | 3 +- libobs/graphics/shader-parser.c | 3 +- libobs/util/config-file.c | 11 ++-- libobs/util/platform.c | 98 +++++++++++++++++++++++++++++++++ libobs/util/platform.h | 3 + 5 files changed, 110 insertions(+), 8 deletions(-) diff --git a/libobs/graphics/effect-parser.c b/libobs/graphics/effect-parser.c index feaaad9d0..3db1eeeb2 100644 --- a/libobs/graphics/effect-parser.c +++ b/libobs/graphics/effect-parser.c @@ -16,6 +16,7 @@ ******************************************************************************/ #include +#include "../util/platform.h" #include "effect-parser.h" #include "effect.h" @@ -735,7 +736,7 @@ static inline int ep_parse_param_assign_intfloat(struct effect_parser *ep, return code; if (is_float) { - float f = (float)strtod(ep->cfp.cur_token->str.array, NULL); + float f = (float)os_strtod(ep->cfp.cur_token->str.array); if (is_negative) f = -f; da_push_back_array(param->default_val, &f, sizeof(float)); } else { diff --git a/libobs/graphics/shader-parser.c b/libobs/graphics/shader-parser.c index d87ae8129..485929425 100644 --- a/libobs/graphics/shader-parser.c +++ b/libobs/graphics/shader-parser.c @@ -15,6 +15,7 @@ along with this program. If not, see . ******************************************************************************/ +#include "../util/platform.h" #include "shader-parser.h" enum gs_shader_param_type get_shader_param_type(const char *type) @@ -489,7 +490,7 @@ static inline int sp_parse_param_assign_intfloat(struct shader_parser *sp, return code; if (is_float) { - float f = (float)strtod(sp->cfp.cur_token->str.array, NULL); + float f = (float)os_strtod(sp->cfp.cur_token->str.array); if (is_negative) f = -f; da_push_back_array(param->default_val, &f, sizeof(float)); } else { diff --git a/libobs/util/config-file.c b/libobs/util/config-file.c index 353cfd570..50a85a631 100644 --- a/libobs/util/config-file.c +++ b/libobs/util/config-file.c @@ -472,10 +472,9 @@ void config_set_bool(config_t *config, const char *section, void config_set_double(config_t *config, const char *section, const char *name, double value) { - struct dstr str; - dstr_init(&str); - dstr_printf(&str, "%g", value); - config_set_item(&config->sections, section, name, str.array); + char *str = bzalloc(64); + os_dtostr(value, str, 64); + config_set_item(&config->sections, section, name, str); } void config_set_default_string(config_t *config, const char *section, @@ -591,7 +590,7 @@ double config_get_double(const config_t *config, const char *section, { const char *value = config_get_string(config, section, name); if (value) - return strtod(value, NULL); + return os_strtod(value); return 0.0; } @@ -644,7 +643,7 @@ double config_get_default_double(const config_t *config, const char *section, { const char *value = config_get_default_string(config, section, name); if (value) - return strtod(value, NULL); + return os_strtod(value); return 0.0; } diff --git a/libobs/util/platform.c b/libobs/util/platform.c index 93e0c837e..e6d82a7d7 100644 --- a/libobs/util/platform.c +++ b/libobs/util/platform.c @@ -18,6 +18,7 @@ #include #include +#include #include "c99defs.h" #include "platform.h" #include "bmem.h" @@ -414,3 +415,100 @@ size_t os_mbs_to_utf8_ptr(const char *str, size_t len, char **pstr) *pstr = dst; return out_len; } + +/* locale independent double conversion from jansson, credit goes to them */ + +static inline void to_locale(char *str) +{ + const char *point; + char *pos; + + point = localeconv()->decimal_point; + if(*point == '.') { + /* No conversion needed */ + return; + } + + pos = strchr(str, '.'); + if(pos) + *pos = *point; +} + +static inline void from_locale(char *buffer) +{ + const char *point; + char *pos; + + point = localeconv()->decimal_point; + if(*point == '.') { + /* No conversion needed */ + return; + } + + pos = strchr(buffer, *point); + if(pos) + *pos = '.'; +} + +#ifdef _WIN32 +#define snprintf _snprintf +#endif + +double os_strtod(const char *str) +{ + char buf[64]; + snprintf(buf, 64, "%s", str); + to_locale(buf); + return strtod(buf, NULL); +} + +int os_dtostr(double value, char *dst, size_t size) +{ + int ret; + char *start, *end; + size_t length; + + ret = snprintf(dst, size, "%.17g", value); + if(ret < 0) + return -1; + + length = (size_t)ret; + if(length >= size) + return -1; + + from_locale(dst); + + /* Make sure there's a dot or 'e' in the output. Otherwise + a real is converted to an integer when decoding */ + if(strchr(dst, '.') == NULL && strchr(dst, 'e') == NULL) { + if(length + 3 >= size) { + /* No space to append ".0" */ + return -1; + } + dst[length] = '.'; + dst[length + 1] = '0'; + dst[length + 2] = '\0'; + length += 2; + } + + /* Remove leading '+' from positive exponent. Also remove leading + zeros from exponents (added by some printf() implementations) */ + start = strchr(dst, 'e'); + if(start) { + start++; + end = start + 1; + + if(*start == '-') + start++; + + while(*end == '0') + end++; + + if(end != start) { + memmove(start, end, length - (size_t)(end - dst)); + length -= (size_t)(end - start); + } + } + + return (int)length; +} diff --git a/libobs/util/platform.h b/libobs/util/platform.h index f0786e013..634189f63 100644 --- a/libobs/util/platform.h +++ b/libobs/util/platform.h @@ -65,6 +65,9 @@ EXPORT size_t os_wcs_to_utf8_ptr(const wchar_t *str, size_t len, char **pstr); EXPORT size_t os_utf8_to_mbs_ptr(const char *str, size_t len, char **pstr); EXPORT size_t os_mbs_to_utf8_ptr(const char *str, size_t len, char **pstr); +EXPORT double os_strtod(const char *str); +EXPORT int os_dtostr(double value, char *dst, size_t size); + EXPORT void *os_dlopen(const char *path); EXPORT void *os_dlsym(void *module, const char *func); EXPORT void os_dlclose(void *module);