فهرست منبع

libobs: Use locale-independent double conversion

Prevents issues on specific locales, especially where decimal points are
represented by commas rather than periods.
jp9000 10 سال پیش
والد
کامیت
d44d3b1f0a
5فایلهای تغییر یافته به همراه110 افزوده شده و 8 حذف شده
  1. 2 1
      libobs/graphics/effect-parser.c
  2. 2 1
      libobs/graphics/shader-parser.c
  3. 5 6
      libobs/util/config-file.c
  4. 98 0
      libobs/util/platform.c
  5. 3 0
      libobs/util/platform.h

+ 2 - 1
libobs/graphics/effect-parser.c

@@ -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 {

+ 2 - 1
libobs/graphics/shader-parser.c

@@ -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 {

+ 5 - 6
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;
 }

+ 98 - 0
libobs/util/platform.c

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

+ 3 - 0
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);