Skip to content

Commit fe1a299

Browse files
committed
Fixing json library locale issues on Windows.
1 parent 8e0a969 commit fe1a299

File tree

6 files changed

+84
-15
lines changed

6 files changed

+84
-15
lines changed

Release/include/cpprest/asyncrt_utils.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,37 @@ namespace conversions
159159

160160
namespace details
161161
{
162+
/// <summary>
163+
/// Cross platform RAII container for setting thread local locale.
164+
/// </summary>
165+
class thread_local_locale
166+
{
167+
public:
168+
169+
thread_local_locale(const char * locale)
170+
{
171+
#ifdef _MS_WINDOWS
172+
_configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
173+
m_prevLocale = setlocale(LC_ALL, locale);
174+
#endif
175+
}
176+
177+
~thread_local_locale()
178+
{
179+
if (m_prevLocale != nullptr)
180+
{
181+
#ifdef _MS_WINDOWS
182+
setlocale(LC_ALL, m_prevLocale);
183+
#endif
184+
}
185+
}
186+
187+
private:
188+
#ifdef _MS_WINDOWS
189+
char * m_prevLocale;
190+
#endif
191+
};
192+
162193
/// <summary>
163194
/// Our own implementation of alpha numeric instead of std::isalnum to avoid
164195
/// taking global lock for performance reasons.

Release/include/cpprest/json.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ namespace web
4444
/// Library for parsing and serializing JSON values to and from C++ types.
4545
namespace json
4646
{
47-
4847
// Various forward declarations.
4948
namespace details
5049
{
@@ -64,8 +63,11 @@ namespace json
6463
}
6564

6665
/// <summary>
67-
/// Preserve the order of the name/value pairs when parsing a JSON object
66+
/// Preserve the order of the name/value pairs when parsing a JSON object.
67+
/// The default is false, which can yield better performance.
6868
/// </summary>
69+
/// <param name="keep_order"><c>true</c> if ordering should be preserved when parsing, <c>false</c> otherwise.</param>
70+
/// <remarks>Note this is a global setting and affects all JSON parsing done.</remarks>
6971
void _ASYNCRTIMP keep_object_element_order(bool keep_order);
7072

7173
#ifdef _MS_WINDOWS
@@ -1415,8 +1417,7 @@ namespace json
14151417
virtual void serialize_impl(std::wstring& str) const
14161418
{
14171419
serialize_impl_char_type(str);
1418-
}
1419-
1420+
}
14201421
#endif
14211422

14221423
protected:

Release/src/json/json.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ web::json::value::value(utility::string_t value) :
106106
{ }
107107

108108
web::json::value::value(const utility::char_t* value) :
109-
m_value(utility::details::make_unique<web::json::details::_String>(utility::string_t(value)))
109+
m_value(utility::details::make_unique<web::json::details::_String>(value))
110110
#ifdef ENABLE_JSON_VALUE_VISUALIZER
111111
,m_kind(value::String)
112112
#endif
@@ -363,7 +363,11 @@ bool web::json::details::_Object::has_field(const utility::string_t &key) const
363363
return m_object.find(key) != m_object.end();
364364
}
365365

366-
utility::string_t json::value::to_string() const { return m_value->to_string(); }
366+
utility::string_t json::value::to_string() const
367+
{
368+
utility::details::thread_local_locale("C");
369+
return m_value->to_string();
370+
}
367371

368372
bool json::value::operator==(const json::value &other) const
369373
{
@@ -411,7 +415,6 @@ const web::json::value& web::json::value::at(const utility::string_t& key) const
411415
return this->as_object().at(key);
412416
}
413417

414-
415418
web::json::value& web::json::value::operator [] (const utility::string_t &key)
416419
{
417420
if ( this->is_null() )

Release/src/json/json_parsing.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,6 @@ void CreateError(const Token &tk, const utility::string_t &message)
6767
throw web::json::json_exception(os.str().c_str());
6868
}
6969

70-
7170
template <typename CharType>
7271
class JSON_Parser
7372
{
@@ -195,7 +194,7 @@ class JSON_StreamParser : public JSON_Parser<CharType>
195194
{
196195
public:
197196
JSON_StreamParser(std::basic_istream<CharType> &stream)
198-
: m_streambuf(stream.rdbuf())
197+
: m_streambuf(stream.rdbuf()), m_locale("C")
199198
{
200199
}
201200

@@ -206,14 +205,16 @@ class JSON_StreamParser : public JSON_Parser<CharType>
206205

207206
private:
208207
typename std::basic_streambuf<CharType, std::char_traits<CharType>>* m_streambuf;
208+
209+
::utility::details::thread_local_locale m_locale;
209210
};
210211

211212
template <typename CharType>
212213
class JSON_StringParser : public JSON_Parser<CharType>
213214
{
214215
public:
215-
JSON_StringParser(const std::basic_string<CharType>& string)
216-
: m_position(&string[0])
216+
JSON_StringParser(const std::basic_string<CharType>& string)
217+
: m_position(&string[0]), m_locale("C")
217218
{
218219
m_startpos = m_position;
219220
m_endpos = m_position+string.size();
@@ -232,6 +233,7 @@ class JSON_StringParser : public JSON_Parser<CharType>
232233
const CharType* m_position;
233234
const CharType* m_startpos;
234235
const CharType* m_endpos;
236+
::utility::details::thread_local_locale m_locale;
235237
};
236238

237239

Release/src/json/json_serialization.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,20 +28,20 @@
2828
#include "stdafx.h"
2929
#include <stdio.h>
3030

31-
#pragma warning(disable : 4127) // allow expressions like while(true) pass
3231
using namespace web;
3332
using namespace web::json;
3433
using namespace utility;
3534
using namespace utility::conversions;
3635

37-
3836
//
3937
// JSON Serialization
4038
//
4139

4240
#ifdef _MS_WINDOWS
4341
void web::json::value::serialize(std::ostream& stream) const
4442
{
43+
utility::details::thread_local_locale("C");
44+
4545
// This has better performance than writing directly to stream.
4646
std::string str;
4747
m_value->serialize_impl(str);
@@ -55,6 +55,8 @@ void web::json::value::format(std::basic_string<wchar_t> &string) const
5555

5656
void web::json::value::serialize(utility::ostream_t &stream) const
5757
{
58+
utility::details::thread_local_locale("C");
59+
5860
// This has better performance than writing directly to stream.
5961
utility::string_t str;
6062
m_value->serialize_impl(str);
@@ -157,7 +159,7 @@ void web::json::details::_Number::format(std::basic_string<char>& stream) const
157159
const auto numChars = strnlen_s(tempBuffer, tempSize);
158160
stream.append(tempBuffer, numChars);
159161
#else
160-
std::stringstream ss;
162+
std::stringstream ss; // TODO - also consider replacing with snprintf...
161163
if (m_number.m_type == number::type::signed_type)
162164
ss << m_number.m_intval;
163165
else
@@ -235,4 +237,8 @@ utility::string_t web::json::value::as_string() const
235237
return m_value->as_string();
236238
}
237239

238-
utility::string_t json::value::serialize() const { return m_value->to_string(); }
240+
utility::string_t json::value::serialize() const
241+
{
242+
utility::details::thread_local_locale("C");
243+
return m_value->to_string();
244+
}

Release/tests/Functional/json/parsing_tests.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,32 @@ TEST(keep_order_while_parsing)
566566
VERIFY_ARE_EQUAL(obj[U("a")].as_integer(), 4);
567567
}
568568

569+
TEST(non_default_locale)
570+
{
571+
char * prevLocale = setlocale(LC_ALL, "fr-FR");
572+
573+
// string serialize
574+
utility::string_t str(U("[true,false,-1.55,5,null,{\"abc\":5555}]"));
575+
json::value v = json::value::parse(str);
576+
VERIFY_ARE_EQUAL(str, v.serialize());
577+
578+
// cpprestsdk stream serialize
579+
utility::stringstream_t stream;
580+
stream << v;
581+
utility::string_t serializedStr;
582+
stream >> serializedStr;
583+
VERIFY_ARE_EQUAL(str, serializedStr);
584+
585+
// std stream serialize
586+
std::stringstream stdStream;
587+
v.serialize(stdStream);
588+
std::string stdStr;
589+
stdStream >> stdStr;
590+
VERIFY_ARE_EQUAL(str, utility::conversions::to_string_t(stdStr));
591+
592+
setlocale(LC_ALL, prevLocale);
593+
}
594+
569595
} // SUITE(parsing_tests)
570596

571597
}}}

0 commit comments

Comments
 (0)