libobs: Use locale-independent double conversion

Prevents issues on specific locales, especially where decimal points are
represented by commas rather than periods.
This commit is contained in:
jp9000 2015-03-21 13:23:41 -07:00
parent 4abae186ce
commit d44d3b1f0a
5 changed files with 110 additions and 8 deletions

View File

@ -16,6 +16,7 @@
******************************************************************************/
#include <assert.h>
#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 {

View File

@ -15,6 +15,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
#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 {

View File

@ -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;
}

View File

@ -18,6 +18,7 @@
#include <errno.h>
#include <stdlib.h>
#include <locale.h>
#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;
}

View File

@ -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);