Skip to content

Unify handling of tolower operations to avoid locale sensitivity. #822

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 2, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 38 additions & 45 deletions Release/include/cpprest/asyncrt_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@

#ifndef _WIN32
#include <sys/time.h>
#include <boost/algorithm/string.hpp>
#if !defined(ANDROID) && !defined(__ANDROID__) && defined(HAVE_XLOCALE_H) // CodePlex 269
/* Systems using glibc: xlocale.h has been removed from glibc 2.26
The above include of locale.h is sufficient
Expand Down Expand Up @@ -393,19 +392,48 @@ namespace details
}

/// <summary>
/// Cross platform utility function for performing case insensitive string comparision.
/// Cross platform utility function for performing case insensitive string equality comparision.
/// </summary>
/// <param name="left">First string to compare.</param>
/// <param name="right">Second strong to compare.</param>
/// <returns>true if the strings are equivalent, false otherwise</returns>
inline bool str_icmp(const utility::string_t &left, const utility::string_t &right)
{
#ifdef _WIN32
return _wcsicmp(left.c_str(), right.c_str()) == 0;
#else
return boost::iequals(left, right);
#endif
}
_ASYNCRTIMP bool __cdecl str_iequal(const std::string &left, const std::string &right) CPPREST_NOEXCEPT;

/// <summary>
/// Cross platform utility function for performing case insensitive string equality comparision.
/// </summary>
/// <param name="left">First string to compare.</param>
/// <param name="right">Second strong to compare.</param>
/// <returns>true if the strings are equivalent, false otherwise</returns>
_ASYNCRTIMP bool __cdecl str_iequal(const std::wstring &left, const std::wstring &right) CPPREST_NOEXCEPT;

/// <summary>
/// Cross platform utility function for performing case insensitive string less-than comparision.
/// </summary>
/// <param name="left">First string to compare.</param>
/// <param name="right">Second strong to compare.</param>
/// <returns>true if a lowercase view of left is lexicographically less than a lowercase view of right; otherwise, false.</returns>
_ASYNCRTIMP bool __cdecl str_iless(const std::string &left, const std::string &right) CPPREST_NOEXCEPT;

/// <summary>
/// Cross platform utility function for performing case insensitive string less-than comparision.
/// </summary>
/// <param name="left">First string to compare.</param>
/// <param name="right">Second strong to compare.</param>
/// <returns>true if a lowercase view of left is lexicographically less than a lowercase view of right; otherwise, false.</returns>
_ASYNCRTIMP bool __cdecl str_iless(const std::wstring &left, const std::wstring &right) CPPREST_NOEXCEPT;

/// <summary>
/// Convert a string to lowercase in place.
/// </summary>
/// <param name="target">The string to convert to lowercase.</param>
_ASYNCRTIMP void __cdecl inplace_tolower(std::string &target) CPPREST_NOEXCEPT;

/// <summary>
/// Convert a string to lowercase in place.
/// </summary>
/// <param name="target">The string to convert to lowercase.</param>
_ASYNCRTIMP void __cdecl inplace_tolower(std::wstring &target) CPPREST_NOEXCEPT;

#ifdef _WIN32

Expand Down Expand Up @@ -607,41 +635,6 @@ class datetime
interval_type m_interval;
};

#ifndef _WIN32

// temporary workaround for the fact that
// utf16char is not fully supported in GCC
class cmp
{
public:

static int icmp(std::string left, std::string right)
{
size_t i;
for (i = 0; i < left.size(); ++i)
{
if (i == right.size()) return 1;

auto l = cmp::tolower(left[i]);
auto r = cmp::tolower(right[i]);
if (l > r) return 1;
if (l < r) return -1;
}
if (i < right.size()) return -1;
return 0;
}

private:
static char tolower(char c)
{
if (c >= 'A' && c <= 'Z')
return static_cast<char>(c - 'A' + 'a');
return c;
}
};

#endif

inline int operator- (datetime t1, datetime t2)
{
auto diff = (t1.m_interval - t2.m_interval);
Expand Down
40 changes: 20 additions & 20 deletions Release/include/cpprest/http_headers.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,30 +68,30 @@ class http_headers
{
bool operator()(const utility::string_t &str1, const utility::string_t &str2) const
{
#ifdef _WIN32
return _wcsicmp(str1.c_str(), str2.c_str()) < 0;
#else
return utility::cmp::icmp(str1, str2) < 0;
#endif
return utility::details::str_iless(str1, str2);
}
};

private:
typedef std::map<utility::string_t, utility::string_t, _case_insensitive_cmp> inner_container;
public:

/// <summary>
/// STL-style typedefs
/// </summary>
typedef std::map<utility::string_t, utility::string_t, _case_insensitive_cmp>::key_type key_type;
typedef std::map<utility::string_t, utility::string_t, _case_insensitive_cmp>::key_compare key_compare;
typedef std::map<utility::string_t, utility::string_t, _case_insensitive_cmp>::allocator_type allocator_type;
typedef std::map<utility::string_t, utility::string_t, _case_insensitive_cmp>::size_type size_type;
typedef std::map<utility::string_t, utility::string_t, _case_insensitive_cmp>::difference_type difference_type;
typedef std::map<utility::string_t, utility::string_t, _case_insensitive_cmp>::pointer pointer;
typedef std::map<utility::string_t, utility::string_t, _case_insensitive_cmp>::const_pointer const_pointer;
typedef std::map<utility::string_t, utility::string_t, _case_insensitive_cmp>::reference reference;
typedef std::map<utility::string_t, utility::string_t, _case_insensitive_cmp>::const_reference const_reference;
typedef std::map<utility::string_t, utility::string_t, _case_insensitive_cmp>::iterator iterator;
typedef std::map<utility::string_t, utility::string_t, _case_insensitive_cmp>::const_iterator const_iterator;
typedef std::map<utility::string_t, utility::string_t, _case_insensitive_cmp>::reverse_iterator reverse_iterator;
typedef std::map<utility::string_t, utility::string_t, _case_insensitive_cmp>::const_reverse_iterator const_reverse_iterator;
typedef typename inner_container::key_type key_type;
typedef typename inner_container::key_compare key_compare;
typedef typename inner_container::allocator_type allocator_type;
typedef typename inner_container::size_type size_type;
typedef typename inner_container::difference_type difference_type;
typedef typename inner_container::pointer pointer;
typedef typename inner_container::const_pointer const_pointer;
typedef typename inner_container::reference reference;
typedef typename inner_container::const_reference const_reference;
typedef typename inner_container::iterator iterator;
typedef typename inner_container::const_iterator const_iterator;
typedef typename inner_container::reverse_iterator reverse_iterator;
typedef typename inner_container::const_reverse_iterator const_reverse_iterator;

/// <summary>
/// Constructs an empty set of HTTP headers.
Expand Down Expand Up @@ -318,7 +318,7 @@ class http_headers
}

// Headers are stored in a map with case insensitive key.
std::map<utility::string_t, utility::string_t, _case_insensitive_cmp> m_headers;
inner_container m_headers;
};

}}
}}
38 changes: 18 additions & 20 deletions Release/samples/BlackJack/BlackJack_Client/BlackJackClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,12 @@
#include <iostream>
#include <streambuf>
#include <sstream>
#include <locale>
#include <fstream>
#include "../BlackJack_Server/messagetypes.h"

#ifdef _WIN32
# define iequals(x, y) (_stricmp((x), (y))==0)
#else
# define iequals(x, y) boost::iequals((x), (y))
#endif

using namespace std;
using namespace web;
using namespace web;
using namespace utility;
using namespace http;
using namespace http::client;
Expand Down Expand Up @@ -134,7 +129,7 @@ void PrintTable(const http_response &response, bool &refresh)
}
}

//
//
// Entry point for the blackjack client.
// Arguments: BlackJack_Client.exe <port>
// If port is not specified, client will assume that the server is listening on port 34568
Expand Down Expand Up @@ -179,7 +174,11 @@ int main(int argc, char *argv[])
ucout << "Enter method:";
cin >> method;

if ( iequals(method.c_str(), "quit") )
const auto methodFirst = &method[0];
const auto methodLast = methodFirst + method.size();
std::use_facet<std::ctype<char>>(std::locale::classic()).tolower(methodFirst, methodLast);

if (method == "quit")
{
if ( !userName.empty() && !table.empty() )
{
Expand All @@ -190,12 +189,12 @@ int main(int argc, char *argv[])
break;
}

if ( iequals(method.c_str(), "name") )
if (method == "name")
{
ucout << "Enter user name:";
ucin >> userName;
}
else if ( iequals(method.c_str(), "join") )
else if (method == "join")
{
ucout << "Enter table name:";
ucin >> table;
Expand All @@ -206,16 +205,16 @@ int main(int argc, char *argv[])
buf << table << U("?name=") << userName;
CheckResponse("blackjack/dealer", bjDealer.request(methods::POST, buf.str()).get(), was_refresh);
}
else if ( iequals(method.c_str(), "hit")
|| iequals(method.c_str(), "stay")
|| iequals(method.c_str(), "double") )
else if (method == "hit"
|| method == "stay"
|| method == "double")
{
utility::ostringstream_t buf;
buf << table << U("?request=") << utility::conversions::to_string_t(method) << U("&name=") << userName;
PrintTable(CheckResponse("blackjack/dealer", bjDealer.request(methods::PUT, buf.str()).get()), was_refresh);
}
else if ( iequals(method.c_str(), "bet")
|| iequals(method.c_str(), "insure") )
else if (method == "bet"
||method == "insure")
{
utility::string_t bet;
ucout << "Enter bet:";
Expand All @@ -227,11 +226,11 @@ int main(int argc, char *argv[])
buf << table << U("?request=") << utility::conversions::to_string_t(method) << U("&name=") << userName << U("&amount=") << bet;
PrintTable(CheckResponse("blackjack/dealer", bjDealer.request(methods::PUT, buf.str()).get()), was_refresh);
}
else if ( iequals(method.c_str(), "newtbl") )
else if (method == "newtbl")
{
CheckResponse("blackjack/dealer", bjDealer.request(methods::POST).get(), was_refresh);
}
else if ( iequals(method.c_str(), "leave") )
else if (method == "leave")
{
ucout << "Enter table:";
ucin >> table;
Expand All @@ -242,7 +241,7 @@ int main(int argc, char *argv[])
buf << table << U("?name=") << userName;
CheckResponse("blackjack/dealer", bjDealer.request(methods::DEL, buf.str()).get(), was_refresh);
}
else if ( iequals(method.c_str(), "list") )
else if (method == "list")
{
was_refresh = false;
http_response response = CheckResponse("blackjack/dealer", bjDealer.request(methods::GET).get());
Expand All @@ -268,4 +267,3 @@ int main(int argc, char *argv[])

return 0;
}

Loading