|
|
@@ -28,6 +28,60 @@
|
|
|
|
|
|
#include "../DebugNew.h"
|
|
|
|
|
|
+// ATOMIC BEGIN
|
|
|
+
|
|
|
+// The built-in strtod() function uses the current locale for parsing strings. On certain
|
|
|
+// locales (German, Swedish, ...) a comma is used as decimal separator. For portable XML,
|
|
|
+// we need to parse floating point values the same way on all platforms no matter what
|
|
|
+// locale is set. The strtod_c_locale() is a workaround using the "C" locale explicitly,
|
|
|
+// which uses a dot as decimal separator.
|
|
|
+
|
|
|
+#include <locale.h>
|
|
|
+#ifdef ATOMIC_PLATFORM_OSX
|
|
|
+#include <xlocale.h>
|
|
|
+#endif
|
|
|
+
|
|
|
+#include <stdlib.h>
|
|
|
+
|
|
|
+#ifdef ATOMIC_PLATFORM_WINDOWS
|
|
|
+
|
|
|
+static _locale_t get_c_locale()
|
|
|
+{
|
|
|
+ static _locale_t loc = _create_locale(LC_ALL, "C");
|
|
|
+ return loc;
|
|
|
+}
|
|
|
+
|
|
|
+static double strtod_c_locale(const char* nptr, char** endptr)
|
|
|
+{
|
|
|
+ return _strtod_l(nptr, endptr, get_c_locale());
|
|
|
+}
|
|
|
+
|
|
|
+#elif defined(ATOMIC_PLATFORM_ANDROID) || defined(ATOMIC_PLATFORM_IOS)
|
|
|
+
|
|
|
+// Android NDK/iOS don't do locale, so just revert to strtod
|
|
|
+
|
|
|
+static double strtod_c_locale(const char* nptr, char** endptr)
|
|
|
+{
|
|
|
+ return strtod(nptr, endptr);
|
|
|
+}
|
|
|
+
|
|
|
+#else
|
|
|
+
|
|
|
+static locale_t get_c_locale()
|
|
|
+{
|
|
|
+ static locale_t loc = newlocale(LC_ALL_MASK, "C", NULL);
|
|
|
+ return loc;
|
|
|
+}
|
|
|
+
|
|
|
+static double strtod_c_locale(const char* nptr, char** endptr)
|
|
|
+{
|
|
|
+ return strtod_l(nptr, endptr, get_c_locale());
|
|
|
+}
|
|
|
+
|
|
|
+#endif // ATOMIC_PLATFORM_WINDOWS
|
|
|
+
|
|
|
+// ATOMIC END
|
|
|
+
|
|
|
namespace Atomic
|
|
|
{
|
|
|
|
|
|
@@ -146,7 +200,9 @@ float ToFloat(const char* source)
|
|
|
if (!source)
|
|
|
return 0;
|
|
|
|
|
|
- return (float)strtod(source, 0);
|
|
|
+ // ATOMIC BEGIN
|
|
|
+ return (float)strtod_c_locale(source, 0);
|
|
|
+ // ATOMIC END
|
|
|
}
|
|
|
|
|
|
double ToDouble(const String& source)
|
|
|
@@ -159,7 +215,9 @@ double ToDouble(const char* source)
|
|
|
if (!source)
|
|
|
return 0;
|
|
|
|
|
|
- return strtod(source, 0);
|
|
|
+ // ATOMIC BEGIN
|
|
|
+ return strtod_c_locale(source, 0);
|
|
|
+ // ATOMIC END
|
|
|
}
|
|
|
|
|
|
Color ToColor(const String& source)
|
|
|
@@ -176,11 +234,14 @@ Color ToColor(const char* source)
|
|
|
return ret;
|
|
|
|
|
|
char* ptr = (char*)source;
|
|
|
- ret.r_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.g_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.b_ = (float)strtod(ptr, &ptr);
|
|
|
+
|
|
|
+ // ATOMIC BEGIN
|
|
|
+ ret.r_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.g_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.b_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
if (elements > 3)
|
|
|
- ret.a_ = (float)strtod(ptr, &ptr);
|
|
|
+ ret.a_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ // ATOMIC END
|
|
|
|
|
|
return ret;
|
|
|
}
|
|
|
@@ -241,10 +302,13 @@ Rect ToRect(const char* source)
|
|
|
return ret;
|
|
|
|
|
|
char* ptr = (char*)source;
|
|
|
- ret.min_.x_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.min_.y_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.max_.x_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.max_.y_ = (float)strtod(ptr, &ptr);
|
|
|
+
|
|
|
+ // ATOMIC BEGIN
|
|
|
+ ret.min_.x_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.min_.y_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.max_.x_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.max_.y_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ // ATOMIC END
|
|
|
|
|
|
return ret;
|
|
|
}
|
|
|
@@ -265,9 +329,12 @@ Quaternion ToQuaternion(const char* source)
|
|
|
{
|
|
|
// 3 coords specified: conversion from Euler angles
|
|
|
float x, y, z;
|
|
|
- x = (float)strtod(ptr, &ptr);
|
|
|
- y = (float)strtod(ptr, &ptr);
|
|
|
- z = (float)strtod(ptr, &ptr);
|
|
|
+
|
|
|
+ // ATOMIC BEGIN
|
|
|
+ x = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ y = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ z = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ // ATOMIC END
|
|
|
|
|
|
return Quaternion(x, y, z);
|
|
|
}
|
|
|
@@ -275,10 +342,13 @@ Quaternion ToQuaternion(const char* source)
|
|
|
{
|
|
|
// 4 coords specified: full quaternion
|
|
|
Quaternion ret;
|
|
|
- ret.w_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.x_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.y_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.z_ = (float)strtod(ptr, &ptr);
|
|
|
+
|
|
|
+ // ATOMIC BEGIN
|
|
|
+ ret.w_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.x_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.y_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.z_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ // ATOMIC END
|
|
|
|
|
|
return ret;
|
|
|
}
|
|
|
@@ -298,8 +368,11 @@ Vector2 ToVector2(const char* source)
|
|
|
return ret;
|
|
|
|
|
|
char* ptr = (char*)source;
|
|
|
- ret.x_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.y_ = (float)strtod(ptr, &ptr);
|
|
|
+
|
|
|
+ // ATOMIC BEGIN
|
|
|
+ ret.x_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.y_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ // ATOMIC END
|
|
|
|
|
|
return ret;
|
|
|
}
|
|
|
@@ -318,9 +391,12 @@ Vector3 ToVector3(const char* source)
|
|
|
return ret;
|
|
|
|
|
|
char* ptr = (char*)source;
|
|
|
- ret.x_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.y_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.z_ = (float)strtod(ptr, &ptr);
|
|
|
+
|
|
|
+ // ATOMIC BEGIN
|
|
|
+ ret.x_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.y_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.z_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ // ATOMIC END
|
|
|
|
|
|
return ret;
|
|
|
}
|
|
|
@@ -337,31 +413,33 @@ Vector4 ToVector4(const char* source, bool allowMissingCoords)
|
|
|
unsigned elements = CountElements(source, ' ');
|
|
|
char* ptr = (char*)source;
|
|
|
|
|
|
+ // ATOMIC BEGIN
|
|
|
if (!allowMissingCoords)
|
|
|
{
|
|
|
if (elements < 4)
|
|
|
return ret;
|
|
|
|
|
|
- ret.x_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.y_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.z_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.w_ = (float)strtod(ptr, &ptr);
|
|
|
+ ret.x_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.y_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.z_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.w_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
|
|
|
return ret;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
if (elements > 0)
|
|
|
- ret.x_ = (float)strtod(ptr, &ptr);
|
|
|
+ ret.x_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
if (elements > 1)
|
|
|
- ret.y_ = (float)strtod(ptr, &ptr);
|
|
|
+ ret.y_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
if (elements > 2)
|
|
|
- ret.z_ = (float)strtod(ptr, &ptr);
|
|
|
+ ret.z_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
if (elements > 3)
|
|
|
- ret.w_ = (float)strtod(ptr, &ptr);
|
|
|
+ ret.w_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
|
|
|
return ret;
|
|
|
}
|
|
|
+ // ATOMIC END
|
|
|
}
|
|
|
|
|
|
Variant ToVectorVariant(const String& source)
|
|
|
@@ -426,15 +504,18 @@ Matrix3 ToMatrix3(const char* source)
|
|
|
return ret;
|
|
|
|
|
|
char* ptr = (char*)source;
|
|
|
- ret.m00_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.m01_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.m02_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.m10_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.m11_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.m12_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.m20_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.m21_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.m22_ = (float)strtod(ptr, &ptr);
|
|
|
+
|
|
|
+ // ATOMIC BEGIN
|
|
|
+ ret.m00_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.m01_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.m02_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.m10_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.m11_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.m12_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.m20_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.m21_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.m22_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ // ATOMIC END
|
|
|
|
|
|
return ret;
|
|
|
}
|
|
|
@@ -453,18 +534,21 @@ Matrix3x4 ToMatrix3x4(const char* source)
|
|
|
return ret;
|
|
|
|
|
|
char* ptr = (char*)source;
|
|
|
- ret.m00_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.m01_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.m02_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.m03_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.m10_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.m11_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.m12_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.m13_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.m20_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.m21_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.m22_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.m23_ = (float)strtod(ptr, &ptr);
|
|
|
+
|
|
|
+ // ATOMIC BEGIN
|
|
|
+ ret.m00_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.m01_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.m02_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.m03_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.m10_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.m11_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.m12_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.m13_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.m20_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.m21_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.m22_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.m23_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ // ATOMIC END
|
|
|
|
|
|
return ret;
|
|
|
}
|
|
|
@@ -483,22 +567,25 @@ Matrix4 ToMatrix4(const char* source)
|
|
|
return ret;
|
|
|
|
|
|
char* ptr = (char*)source;
|
|
|
- ret.m00_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.m01_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.m02_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.m03_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.m10_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.m11_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.m12_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.m13_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.m20_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.m21_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.m22_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.m23_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.m30_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.m31_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.m32_ = (float)strtod(ptr, &ptr);
|
|
|
- ret.m33_ = (float)strtod(ptr, &ptr);
|
|
|
+
|
|
|
+ // ATOMIC BEGIN
|
|
|
+ ret.m00_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.m01_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.m02_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.m03_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.m10_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.m11_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.m12_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.m13_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.m20_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.m21_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.m22_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.m23_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.m30_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.m31_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.m32_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ ret.m33_ = (float)strtod_c_locale(ptr, &ptr);
|
|
|
+ // ATOMIC END
|
|
|
|
|
|
return ret;
|
|
|
}
|