diff --git a/.gitignore b/.gitignore index 3a3fea4411..1f77d34f37 100644 --- a/.gitignore +++ b/.gitignore @@ -67,6 +67,7 @@ Intermediate/ # Ignore cmake building directories build.*/ docs/ +out/ # Ignore NuGet artifacts .nuget/ Build_android/build/ diff --git a/Release/CMakeLists.txt b/Release/CMakeLists.txt index dd5d1daca2..f7a557aa1b 100644 --- a/Release/CMakeLists.txt +++ b/Release/CMakeLists.txt @@ -20,8 +20,10 @@ set(CPPREST_EXCLUDE_WEBSOCKETS OFF CACHE BOOL "Exclude websockets functionality. set(CPPREST_EXCLUDE_COMPRESSION OFF CACHE BOOL "Exclude compression functionality.") set(CPPREST_EXCLUDE_BROTLI ON CACHE BOOL "Exclude Brotli compression functionality.") set(CPPREST_EXPORT_DIR cpprestsdk CACHE STRING "Directory to install CMake config files.") +option(CPPREST_FORCE_NARROW_STRINGS "Keep strings narrow/UTF8 (even if WIN32)" OFF) set(CPPREST_INSTALL_HEADERS ON CACHE BOOL "Install header files.") set(CPPREST_INSTALL ON CACHE BOOL "Add install commands.") +option(CPPREST_ISOLATE_COMPONENTS "Build cpprest components as individual libraries" OFF) if(IOS OR ANDROID) set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build shared libraries") @@ -112,9 +114,31 @@ else() message(FATAL_ERROR "Unknown platform. Cannot determine appropriate feature implementations.") endif() +# CPPREST_EXCLUDE_HTTP_NARROW_STRING_WIP is not a formal option. It exists to +# allow a successfull Windows build with CPPREST_FORCE_NARROW_STRINGS enabled +# until HTTP related code can be updated with support. +set(CPPREST_EXCLUDE_HTTP_NARROW_STRING_WIP OFF) +if(CPPREST_FORCE_NARROW_STRINGS AND WIN32) + if(NOT CPPREST_EXCLUDE_WEBSOCKETS) + message(FATAL_ERROR "CPPREST_EXCLUDE_WEBSOCKETS must be OFF when forcing narrow strings on Windows (WIP)") + endif() + if(NOT CPPREST_HTTP_LISTENER_IMPL STREQUAL "none") + message(FATAL_ERROR "CPPREST_HTTP_LISTENER_IMPL must be 'none' when forcing narrow strings on Windows (per http_server_httpsys.cpp WIP)") + endif() + set(CPPREST_EXCLUDE_HTTP_NARROW_STRING_WIP ON) + if(BUILD_SAMPLES) + message(WARNING "Most samples will fail build when forcing narrow strings on Windows (WIP)") + endif() +endif() + set(WARNINGS) set(ANDROID_LIBS) +# Generic build settings +if(CPPREST_FORCE_NARROW_STRINGS) + add_definitions(-DCPPREST_FORCE_NARROW_STRINGS) +endif() + # Platform (not compiler) specific settings if(ANDROID) # These are used in the shared library case @@ -212,7 +236,8 @@ if(NOT PARENT_DIR STREQUAL "") endif() # Finally, the tests all use the same style declaration to build themselves, so we use a function -function(add_casablanca_test NAME SOURCES_VAR) +# Tests that don't specify IMPLEMENTATION_TARGETS are assumed to depend on whole of cpprest. +function(add_casablanca_test NAME SOURCES_VAR) # [optional] IMPLEMENTATION_TARGETS... add_library(${NAME} ${TEST_LIBRARY_TARGET_TYPE} ${${SOURCES_VAR}}) message("-- Added test library ${NAME}") if(TEST_LIBRARY_TARGET_TYPE STREQUAL "OBJECT") @@ -221,8 +246,12 @@ function(add_casablanca_test NAME SOURCES_VAR) target_compile_definitions(${NAME} PRIVATE $) endforeach() else() + set(IMPLEMENTATION_TARGETS cpprest) + if(CPPREST_ISOLATE_COMPONENTS AND ${ARGC} GREATER 2) + set(IMPLEMENTATION_TARGETS ${ARGN}) + endif() target_link_libraries(${NAME} PRIVATE - cpprest + ${IMPLEMENTATION_TARGETS} common_utilities unittestpp ${ANDROID_LIBS} diff --git a/Release/include/cpprest/asyncrt_utils.h b/Release/include/cpprest/asyncrt_utils.h index a38702f412..349012ddda 100644 --- a/Release/include/cpprest/asyncrt_utils.h +++ b/Release/include/cpprest/asyncrt_utils.h @@ -14,25 +14,12 @@ #pragma once #include "cpprest/details/basic_types.h" -#include "pplx/pplxtasks.h" +#include "cpprest/string_utils.h" #include #include -#include -#include #include #include #include -#include - -#ifndef _WIN32 -#include -#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 - Further details: https://sourceware.org/git/?p=glibc.git;a=commit;h=f0be25b6336db7492e47d2e8e72eb8af53b5506d */ -#include -#endif -#endif /// Various utilities for string conversions and date and time manipulation. namespace utility @@ -56,425 +43,8 @@ _ASYNCRTIMP utility::string_t __cdecl seconds_to_xml_duration(utility::seconds n _ASYNCRTIMP utility::seconds __cdecl xml_duration_to_seconds(const utility::string_t& timespanString); } // namespace timespan -/// Functions for Unicode string conversions. -namespace conversions -{ -/// -/// Converts a UTF-16 string to a UTF-8 string. -/// -/// A two byte character UTF-16 string. -/// A single byte character UTF-8 string. -_ASYNCRTIMP std::string __cdecl utf16_to_utf8(const utf16string& w); - -/// -/// Converts a UTF-8 string to a UTF-16 -/// -/// A single byte character UTF-8 string. -/// A two byte character UTF-16 string. -_ASYNCRTIMP utf16string __cdecl utf8_to_utf16(const std::string& s); - -/// -/// Converts a ASCII (us-ascii) string to a UTF-16 string. -/// -/// A single byte character us-ascii string. -/// A two byte character UTF-16 string. -_ASYNCRTIMP utf16string __cdecl usascii_to_utf16(const std::string& s); - -/// -/// Converts a Latin1 (iso-8859-1) string to a UTF-16 string. -/// -/// A single byte character UTF-8 string. -/// A two byte character UTF-16 string. -_ASYNCRTIMP utf16string __cdecl latin1_to_utf16(const std::string& s); - -/// -/// Converts a Latin1 (iso-8859-1) string to a UTF-8 string. -/// -/// A single byte character UTF-8 string. -/// A single byte character UTF-8 string. -_ASYNCRTIMP utf8string __cdecl latin1_to_utf8(const std::string& s); - -/// -/// Converts to a platform dependent Unicode string type. -/// -/// A single byte character UTF-8 string. -/// A platform dependent string type. -#ifdef _UTF16_STRINGS -_ASYNCRTIMP utility::string_t __cdecl to_string_t(std::string&& s); -#else -inline utility::string_t&& to_string_t(std::string&& s) { return std::move(s); } -#endif - -/// -/// Converts to a platform dependent Unicode string type. -/// -/// A two byte character UTF-16 string. -/// A platform dependent string type. -#ifdef _UTF16_STRINGS -inline utility::string_t&& to_string_t(utf16string&& s) { return std::move(s); } -#else -_ASYNCRTIMP utility::string_t __cdecl to_string_t(utf16string&& s); -#endif -/// -/// Converts to a platform dependent Unicode string type. -/// -/// A single byte character UTF-8 string. -/// A platform dependent string type. -#ifdef _UTF16_STRINGS -_ASYNCRTIMP utility::string_t __cdecl to_string_t(const std::string& s); -#else -inline const utility::string_t& to_string_t(const std::string& s) { return s; } -#endif - -/// -/// Converts to a platform dependent Unicode string type. -/// -/// A two byte character UTF-16 string. -/// A platform dependent string type. -#ifdef _UTF16_STRINGS -inline const utility::string_t& to_string_t(const utf16string& s) { return s; } -#else -_ASYNCRTIMP utility::string_t __cdecl to_string_t(const utf16string& s); -#endif - -/// -/// Converts to a UTF-16 from string. -/// -/// A single byte character UTF-8 string. -/// A two byte character UTF-16 string. -_ASYNCRTIMP utf16string __cdecl to_utf16string(const std::string& value); - -/// -/// Converts to a UTF-16 from string. -/// -/// A two byte character UTF-16 string. -/// A two byte character UTF-16 string. -inline const utf16string& to_utf16string(const utf16string& value) { return value; } -/// -/// Converts to a UTF-16 from string. -/// -/// A two byte character UTF-16 string. -/// A two byte character UTF-16 string. -inline utf16string&& to_utf16string(utf16string&& value) { return std::move(value); } - -/// -/// Converts to a UTF-8 string. -/// -/// A single byte character UTF-8 string. -/// A single byte character UTF-8 string. -inline std::string&& to_utf8string(std::string&& value) { return std::move(value); } - -/// -/// Converts to a UTF-8 string. -/// -/// A single byte character UTF-8 string. -/// A single byte character UTF-8 string. -inline const std::string& to_utf8string(const std::string& value) { return value; } - -/// -/// Converts to a UTF-8 string. -/// -/// A two byte character UTF-16 string. -/// A single byte character UTF-8 string. -_ASYNCRTIMP std::string __cdecl to_utf8string(const utf16string& value); - -/// -/// Encode the given byte array into a base64 string -/// -_ASYNCRTIMP utility::string_t __cdecl to_base64(const std::vector& data); - -/// -/// Encode the given 8-byte integer into a base64 string -/// -_ASYNCRTIMP utility::string_t __cdecl to_base64(uint64_t data); - -/// -/// Decode the given base64 string to a byte array -/// -_ASYNCRTIMP std::vector __cdecl from_base64(const utility::string_t& str); - -template -CASABLANCA_DEPRECATED("All locale-sensitive APIs will be removed in a future update. Use stringstreams directly if " - "locale support is required.") -utility::string_t print_string(const Source& val, const std::locale& loc = std::locale()) -{ - utility::ostringstream_t oss; - oss.imbue(loc); - oss << val; - if (oss.bad()) - { - throw std::bad_cast(); - } - return oss.str(); -} - -CASABLANCA_DEPRECATED("All locale-sensitive APIs will be removed in a future update. Use stringstreams directly if " - "locale support is required.") -inline utility::string_t print_string(const utility::string_t& val) { return val; } - namespace details { -#if defined(__ANDROID__) -template -inline std::string to_string(const T t) -{ - std::ostringstream os; - os.imbue(std::locale::classic()); - os << t; - return os.str(); -} -#endif - -template -inline utility::string_t to_string_t(const T t) -{ -#ifdef _UTF16_STRINGS - using std::to_wstring; - return to_wstring(t); -#else -#if !defined(__ANDROID__) - using std::to_string; -#endif - return to_string(t); -#endif -} - -template -utility::string_t print_string(const Source& val) -{ - utility::ostringstream_t oss; - oss.imbue(std::locale::classic()); - oss << val; - if (oss.bad()) - { - throw std::bad_cast(); - } - return oss.str(); -} - -inline const utility::string_t& print_string(const utility::string_t& val) { return val; } - -template -utf8string print_utf8string(const Source& val) -{ - return conversions::to_utf8string(print_string(val)); -} -inline const utf8string& print_utf8string(const utf8string& val) { return val; } - -template -Target scan_string(const utility::string_t& str) -{ - Target t; - utility::istringstream_t iss(str); - iss.imbue(std::locale::classic()); - iss >> t; - if (iss.bad()) - { - throw std::bad_cast(); - } - return t; -} - -inline const utility::string_t& scan_string(const utility::string_t& str) { return str; } -} // namespace details - -template -CASABLANCA_DEPRECATED("All locale-sensitive APIs will be removed in a future update. Use stringstreams directly if " - "locale support is required.") -Target scan_string(const utility::string_t& str, const std::locale& loc = std::locale()) -{ - Target t; - utility::istringstream_t iss(str); - iss.imbue(loc); - iss >> t; - if (iss.bad()) - { - throw std::bad_cast(); - } - return t; -} - -CASABLANCA_DEPRECATED("All locale-sensitive APIs will be removed in a future update. Use stringstreams directly if " - "locale support is required.") -inline utility::string_t scan_string(const utility::string_t& str) { return str; } -} // namespace conversions - -namespace details -{ -/// -/// Cross platform RAII container for setting thread local locale. -/// -class scoped_c_thread_locale -{ -public: - _ASYNCRTIMP scoped_c_thread_locale(); - _ASYNCRTIMP ~scoped_c_thread_locale(); - -#if !defined(ANDROID) && !defined(__ANDROID__) // CodePlex 269 -#ifdef _WIN32 - typedef _locale_t xplat_locale; -#else - typedef locale_t xplat_locale; -#endif - - static _ASYNCRTIMP xplat_locale __cdecl c_locale(); -#endif -private: -#ifdef _WIN32 - std::string m_prevLocale; - int m_prevThreadSetting; -#elif !(defined(ANDROID) || defined(__ANDROID__)) - locale_t m_prevLocale; -#endif - scoped_c_thread_locale(const scoped_c_thread_locale&); - scoped_c_thread_locale& operator=(const scoped_c_thread_locale&); -}; - -/// -/// Our own implementation of alpha numeric instead of std::isalnum to avoid -/// taking global lock for performance reasons. -/// -inline bool __cdecl is_alnum(const unsigned char uch) CPPREST_NOEXCEPT -{ // test if uch is an alnum character - // special casing char to avoid branches - // clang-format off - static CPPREST_CONSTEXPR bool is_alnum_table[UCHAR_MAX + 1] = { - /* X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 XA XB XC XD XE XF */ - /* 0X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 1X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 2X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 3X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 0-9 */ - /* 4X */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* A-Z */ - /* 5X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, - /* 6X */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* a-z */ - /* 7X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 - /* non-ASCII values initialized to 0 */ - }; - // clang-format on - return (is_alnum_table[uch]); -} - -/// -/// Our own implementation of alpha numeric instead of std::isalnum to avoid -/// taking global lock for performance reasons. -/// -inline bool __cdecl is_alnum(const char ch) CPPREST_NOEXCEPT { return (is_alnum(static_cast(ch))); } - -/// -/// Our own implementation of alpha numeric instead of std::isalnum to avoid -/// taking global lock for performance reasons. -/// -template -inline bool __cdecl is_alnum(Elem ch) CPPREST_NOEXCEPT -{ - // assumes 'x' == L'x' for the ASCII range - typedef typename std::make_unsigned::type UElem; - const auto uch = static_cast(ch); - return (uch <= static_cast('z') && is_alnum(static_cast(uch))); -} - -/// -/// Simplistic implementation of make_unique. A better implementation would be based on variadic templates -/// and therefore not be compatible with Dev10. -/// -template -std::unique_ptr<_Type> make_unique() -{ - return std::unique_ptr<_Type>(new _Type()); -} - -template -std::unique_ptr<_Type> make_unique(_Arg1&& arg1) -{ - return std::unique_ptr<_Type>(new _Type(std::forward<_Arg1>(arg1))); -} - -template -std::unique_ptr<_Type> make_unique(_Arg1&& arg1, _Arg2&& arg2) -{ - return std::unique_ptr<_Type>(new _Type(std::forward<_Arg1>(arg1), std::forward<_Arg2>(arg2))); -} - -template -std::unique_ptr<_Type> make_unique(_Arg1&& arg1, _Arg2&& arg2, _Arg3&& arg3) -{ - return std::unique_ptr<_Type>( - new _Type(std::forward<_Arg1>(arg1), std::forward<_Arg2>(arg2), std::forward<_Arg3>(arg3))); -} - -template -std::unique_ptr<_Type> make_unique(_Arg1&& arg1, _Arg2&& arg2, _Arg3&& arg3, _Arg4&& arg4) -{ - return std::unique_ptr<_Type>(new _Type( - std::forward<_Arg1>(arg1), std::forward<_Arg2>(arg2), std::forward<_Arg3>(arg3), std::forward<_Arg4>(arg4))); -} - -template -std::unique_ptr<_Type> make_unique(_Arg1&& arg1, _Arg2&& arg2, _Arg3&& arg3, _Arg4&& arg4, _Arg5&& arg5) -{ - return std::unique_ptr<_Type>(new _Type(std::forward<_Arg1>(arg1), - std::forward<_Arg2>(arg2), - std::forward<_Arg3>(arg3), - std::forward<_Arg4>(arg4), - std::forward<_Arg5>(arg5))); -} - -template -std::unique_ptr<_Type> make_unique(_Arg1&& arg1, _Arg2&& arg2, _Arg3&& arg3, _Arg4&& arg4, _Arg5&& arg5, _Arg6&& arg6) -{ - return std::unique_ptr<_Type>(new _Type(std::forward<_Arg1>(arg1), - std::forward<_Arg2>(arg2), - std::forward<_Arg3>(arg3), - std::forward<_Arg4>(arg4), - std::forward<_Arg5>(arg5), - std::forward<_Arg6>(arg6))); -} - -/// -/// Cross platform utility function for performing case insensitive string equality comparison. -/// -/// First string to compare. -/// Second strong to compare. -/// true if the strings are equivalent, false otherwise -_ASYNCRTIMP bool __cdecl str_iequal(const std::string& left, const std::string& right) CPPREST_NOEXCEPT; - -/// -/// Cross platform utility function for performing case insensitive string equality comparison. -/// -/// First string to compare. -/// Second strong to compare. -/// true if the strings are equivalent, false otherwise -_ASYNCRTIMP bool __cdecl str_iequal(const std::wstring& left, const std::wstring& right) CPPREST_NOEXCEPT; - -/// -/// Cross platform utility function for performing case insensitive string less-than comparison. -/// -/// First string to compare. -/// Second strong to compare. -/// true if a lowercase view of left is lexicographically less than a lowercase view of right; otherwise, -/// false. -_ASYNCRTIMP bool __cdecl str_iless(const std::string& left, const std::string& right) CPPREST_NOEXCEPT; - -/// -/// Cross platform utility function for performing case insensitive string less-than comparison. -/// -/// First string to compare. -/// Second strong to compare. -/// true if a lowercase view of left is lexicographically less than a lowercase view of right; otherwise, -/// false. -_ASYNCRTIMP bool __cdecl str_iless(const std::wstring& left, const std::wstring& right) CPPREST_NOEXCEPT; - -/// -/// Convert a string to lowercase in place. -/// -/// The string to convert to lowercase. -_ASYNCRTIMP void __cdecl inplace_tolower(std::string& target) CPPREST_NOEXCEPT; - -/// -/// Convert a string to lowercase in place. -/// -/// The string to convert to lowercase. -_ASYNCRTIMP void __cdecl inplace_tolower(std::wstring& target) CPPREST_NOEXCEPT; #ifdef _WIN32 diff --git a/Release/include/cpprest/base64_utils.h b/Release/include/cpprest/base64_utils.h new file mode 100644 index 0000000000..d986b5973d --- /dev/null +++ b/Release/include/cpprest/base64_utils.h @@ -0,0 +1,43 @@ +/*** + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Base64 utilities. + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ + +#pragma once + +#include "cpprest/details/basic_types.h" +#include +#include + +/// Various utilities for string conversions and date and time manipulation. +namespace utility +{ +/// Functions for Unicode string conversions. +namespace conversions +{ +/// +/// Encode the given byte array into a base64 string +/// +_ASYNCRTIMP utility::string_t __cdecl to_base64(const std::vector& data); + +/// +/// Encode the given 8-byte integer into a base64 string +/// +_ASYNCRTIMP utility::string_t __cdecl to_base64(uint64_t data); + +/// +/// Decode the given base64 string to a byte array +/// +_ASYNCRTIMP std::vector __cdecl from_base64(const utility::string_t& str); + +} // namespace conversions + +} // namespace utility diff --git a/Release/include/cpprest/details/basic_types.h b/Release/include/cpprest/details/basic_types.h index d2ceb87189..71b4f78aad 100644 --- a/Release/include/cpprest/details/basic_types.h +++ b/Release/include/cpprest/details/basic_types.h @@ -32,7 +32,7 @@ namespace utility { -#ifdef _WIN32 +#if defined(_WIN32) && !defined(CPPREST_FORCE_NARROW_STRINGS) #define _UTF16_STRINGS #endif @@ -97,7 +97,7 @@ typedef std::ostream utf8ostream; typedef std::istream utf8istream; typedef std::istringstream utf8istringstream; -#ifdef _UTF16_STRINGS +#if defined(_UTF16_STRINGS) || defined(_WIN32) typedef wchar_t utf16char; typedef std::wstring utf16string; typedef std::wstringstream utf16stringstream; diff --git a/Release/include/cpprest/details/web_utilities.h b/Release/include/cpprest/details/web_utilities.h index 853d7614b1..f697add4f8 100644 --- a/Release/include/cpprest/details/web_utilities.h +++ b/Release/include/cpprest/details/web_utilities.h @@ -12,6 +12,8 @@ #include "cpprest/asyncrt_utils.h" #include "cpprest/uri.h" +#include "pplx/pplxtasks.h" +#include namespace web { @@ -31,7 +33,7 @@ class winrt_encryption { public: winrt_encryption() = default; - _ASYNCRTIMP winrt_encryption(const std::wstring& data); + _ASYNCRTIMP winrt_encryption(const ::utility::string_t& data); _ASYNCRTIMP plaintext_string decrypt() const; private: @@ -42,7 +44,7 @@ class win32_encryption { public: win32_encryption() = default; - _ASYNCRTIMP win32_encryption(const std::wstring& data); + _ASYNCRTIMP win32_encryption(const ::utility::string_t& data); _ASYNCRTIMP ~win32_encryption(); _ASYNCRTIMP plaintext_string decrypt() const; diff --git a/Release/include/cpprest/filestream.h b/Release/include/cpprest/filestream.h index 1e4a0f278e..a9e6351caa 100644 --- a/Release/include/cpprest/filestream.h +++ b/Release/include/cpprest/filestream.h @@ -17,6 +17,7 @@ #include "cpprest/astreambuf.h" #include "cpprest/details/fileio.h" +#include "cpprest/memory_utils.h" #include "cpprest/streams.h" #include diff --git a/Release/include/cpprest/http_compression.h b/Release/include/cpprest/http_compression.h index b0059a6419..6f5a44a079 100644 --- a/Release/include/cpprest/http_compression.h +++ b/Release/include/cpprest/http_compression.h @@ -12,6 +12,11 @@ ****/ #pragma once +#include "cpprest/details/basic_types.h" +#include "pplx/pplxtasks.h" +#include +#include + namespace web { namespace http diff --git a/Release/include/cpprest/http_listener.h b/Release/include/cpprest/http_listener.h index a5457c0135..7febdb9029 100644 --- a/Release/include/cpprest/http_listener.h +++ b/Release/include/cpprest/http_listener.h @@ -14,6 +14,7 @@ #define CASA_HTTP_LISTENER_H #include "cpprest/http_msg.h" +#include "cpprest/memory_utils.h" #include #include #if !defined(_WIN32) && !defined(__cplusplus_winrt) || defined(CPPREST_FORCE_HTTP_LISTENER_ASIO) diff --git a/Release/include/cpprest/http_msg.h b/Release/include/cpprest/http_msg.h index 50f05ef213..0ae159071a 100644 --- a/Release/include/cpprest/http_msg.h +++ b/Release/include/cpprest/http_msg.h @@ -196,7 +196,7 @@ class http_exception : public std::exception /// Error message string. http_exception(const utility::string_t& whatArg) : m_msg(utility::conversions::to_utf8string(whatArg)) {} -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) /// /// Creates an http_exception with just a string message and no error code. /// @@ -225,8 +225,8 @@ class http_exception : public std::exception { } -#ifdef _WIN32 - /// +#if defined(_UTF16_STRINGS) + /// /// Creates an http_exception with from a error code using the current platform error category. /// /// Error code value. @@ -258,8 +258,8 @@ class http_exception : public std::exception { } -#ifdef _WIN32 - /// +#if defined(_UTF16_STRINGS) + /// /// Creates an http_exception with from a error code with a category, and a string message. /// /// Error code value. diff --git a/Release/include/cpprest/json.h b/Release/include/cpprest/json.h index 4095be50ea..b97d4a0c28 100644 --- a/Release/include/cpprest/json.h +++ b/Release/include/cpprest/json.h @@ -15,8 +15,11 @@ #ifndef CASA_JSON_H #define CASA_JSON_H -#include "cpprest/asyncrt_utils.h" #include "cpprest/details/basic_types.h" +#include "cpprest/memory_utils.h" +#include "cpprest/string_utils.h" + +#include #include #include #include @@ -275,7 +278,7 @@ class value /// static _ASYNCRTIMP value __cdecl string(utility::string_t value, bool has_escape_chars); -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) private: // Only used internally by JSON parser. static _ASYNCRTIMP value __cdecl string(const std::string& value); @@ -436,7 +439,7 @@ class value /// The stream that the JSON string representation should be written to. _ASYNCRTIMP void serialize(utility::ostream_t& stream) const; -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) /// /// Parses a JSON value from the contents of a single-byte (UTF8) stream. /// @@ -643,7 +646,7 @@ class value /// A reference to the value kept in the field. _ASYNCRTIMP value& operator[](const utility::string_t& key); -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) private: // Only used internally by JSON parser _ASYNCRTIMP value& operator[](const std::string& key) @@ -677,7 +680,7 @@ class value template friend class web::json::details::JSON_Parser; -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) /// /// Writes the current JSON value as a double-byte string to a string instance. /// @@ -957,7 +960,7 @@ class object { if (!keep_order) { - sort(m_elements.begin(), m_elements.end(), compare_pairs); + std::sort(m_elements.begin(), m_elements.end(), compare_pairs); } } @@ -1366,7 +1369,7 @@ class _Value // Common function used for serialization to strings and streams. virtual void serialize_impl(std::string& str) const { format(str); } -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) virtual void serialize_impl(std::wstring& str) const { format(str); } #endif @@ -1400,7 +1403,7 @@ class _Value _Value() {} virtual void format(std::basic_string& stream) const { stream.append("null"); } -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) virtual void format(std::basic_string& stream) const { stream.append(L"null"); } #endif private: @@ -1438,7 +1441,7 @@ class _Number : public _Value protected: virtual void format(std::basic_string& stream) const; -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) virtual void format(std::basic_string& stream) const; #endif private: @@ -1462,7 +1465,7 @@ class _Boolean : public _Value protected: virtual void format(std::basic_string& stream) const { stream.append(m_value ? "true" : "false"); } -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) virtual void format(std::basic_string& stream) const { stream.append(m_value ? L"true" : L"false"); } #endif private: @@ -1479,7 +1482,7 @@ class _String : public _Value { } -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) _String(std::string&& value) : m_string(utility::conversions::to_utf16string(std::move(value))) { m_has_escape_char = has_escape_chars(*this); @@ -1497,13 +1500,13 @@ class _String : public _Value virtual const utility::string_t& as_string() const; virtual void serialize_impl(std::string& str) const { serialize_impl_char_type(str); } -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) virtual void serialize_impl(std::wstring& str) const { serialize_impl_char_type(str); } #endif protected: virtual void format(std::basic_string& str) const; -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) virtual void format(std::basic_string& str) const; #endif @@ -1538,7 +1541,7 @@ _ASYNCRTIMP void append_escape_string(std::basic_string& str, const st void format_string(const utility::string_t& key, utility::string_t& str); -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) void format_string(const utility::string_t& key, std::string& str); #endif @@ -1573,7 +1576,7 @@ class _Object : public _Value str.reserve(get_reserve_size()); format(str); } -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) virtual void serialize_impl(std::wstring& str) const { // To avoid repeated allocations reserve some space all up front. @@ -1585,7 +1588,7 @@ class _Object : public _Value protected: virtual void format(std::basic_string& str) const { format_impl(str); } -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) virtual void format(std::basic_string& str) const { format_impl(str); } #endif @@ -1682,7 +1685,7 @@ class _Array : public _Value str.reserve(get_reserve_size()); format(str); } -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) virtual void serialize_impl(std::wstring& str) const { // To avoid repeated allocations reserve some space all up front. @@ -1694,7 +1697,7 @@ class _Array : public _Value protected: virtual void format(std::basic_string& str) const { format_impl(str); } -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) virtual void format(std::basic_string& str) const { format_impl(str); } #endif private: diff --git a/Release/include/cpprest/memory_utils.h b/Release/include/cpprest/memory_utils.h new file mode 100644 index 0000000000..20fff2b250 --- /dev/null +++ b/Release/include/cpprest/memory_utils.h @@ -0,0 +1,85 @@ +/*** + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Memory utilities. + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ + +#pragma once + +#include +#include + +/// Various utilities for string conversions and date and time manipulation. +namespace utility +{ + +namespace details +{ + +/// +/// Simplistic implementation of make_unique. A better implementation would be based on variadic templates +/// and therefore not be compatible with Dev10. +/// +template +std::unique_ptr<_Type> make_unique() +{ + return std::unique_ptr<_Type>(new _Type()); +} + +template +std::unique_ptr<_Type> make_unique(_Arg1&& arg1) +{ + return std::unique_ptr<_Type>(new _Type(std::forward<_Arg1>(arg1))); +} + +template +std::unique_ptr<_Type> make_unique(_Arg1&& arg1, _Arg2&& arg2) +{ + return std::unique_ptr<_Type>(new _Type(std::forward<_Arg1>(arg1), std::forward<_Arg2>(arg2))); +} + +template +std::unique_ptr<_Type> make_unique(_Arg1&& arg1, _Arg2&& arg2, _Arg3&& arg3) +{ + return std::unique_ptr<_Type>( + new _Type(std::forward<_Arg1>(arg1), std::forward<_Arg2>(arg2), std::forward<_Arg3>(arg3))); +} + +template +std::unique_ptr<_Type> make_unique(_Arg1&& arg1, _Arg2&& arg2, _Arg3&& arg3, _Arg4&& arg4) +{ + return std::unique_ptr<_Type>(new _Type( + std::forward<_Arg1>(arg1), std::forward<_Arg2>(arg2), std::forward<_Arg3>(arg3), std::forward<_Arg4>(arg4))); +} + +template +std::unique_ptr<_Type> make_unique(_Arg1&& arg1, _Arg2&& arg2, _Arg3&& arg3, _Arg4&& arg4, _Arg5&& arg5) +{ + return std::unique_ptr<_Type>(new _Type(std::forward<_Arg1>(arg1), + std::forward<_Arg2>(arg2), + std::forward<_Arg3>(arg3), + std::forward<_Arg4>(arg4), + std::forward<_Arg5>(arg5))); +} + +template +std::unique_ptr<_Type> make_unique(_Arg1&& arg1, _Arg2&& arg2, _Arg3&& arg3, _Arg4&& arg4, _Arg5&& arg5, _Arg6&& arg6) +{ + return std::unique_ptr<_Type>(new _Type(std::forward<_Arg1>(arg1), + std::forward<_Arg2>(arg2), + std::forward<_Arg3>(arg3), + std::forward<_Arg4>(arg4), + std::forward<_Arg5>(arg5), + std::forward<_Arg6>(arg6))); +} + +} // namespace details + +} // namespace utility diff --git a/Release/include/cpprest/oauth1.h b/Release/include/cpprest/oauth1.h index dbc45bdd71..bf779d91ae 100644 --- a/Release/include/cpprest/oauth1.h +++ b/Release/include/cpprest/oauth1.h @@ -15,8 +15,10 @@ #ifndef CASA_OAUTH1_H #define CASA_OAUTH1_H +#include "cpprest/base64_utils.h" #include "cpprest/details/web_utilities.h" #include "cpprest/http_msg.h" +#include "cpprest/string_utils.h" namespace web { diff --git a/Release/include/cpprest/string_utils.h b/Release/include/cpprest/string_utils.h new file mode 100644 index 0000000000..4b27cc9c5b --- /dev/null +++ b/Release/include/cpprest/string_utils.h @@ -0,0 +1,388 @@ +/*** + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * String utilities. + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ + +#pragma once + +#include "cpprest/details/basic_types.h" +#include +#include +#include +#include +#include +#include + +#ifndef _WIN32 +#include +#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 + Further details: https://sourceware.org/git/?p=glibc.git;a=commit;h=f0be25b6336db7492e47d2e8e72eb8af53b5506d */ +#include +#endif +#endif + +/// Various utilities for string conversions and date and time manipulation. +namespace utility +{ +/// Functions for Unicode string conversions. +namespace conversions +{ +/// +/// Converts a UTF-16 string to a UTF-8 string. +/// +/// A two byte character UTF-16 string. +/// A single byte character UTF-8 string. +_ASYNCRTIMP std::string __cdecl utf16_to_utf8(const utf16string& w); + +/// +/// Converts a UTF-8 string to a UTF-16 +/// +/// A single byte character UTF-8 string. +/// A two byte character UTF-16 string. +_ASYNCRTIMP utf16string __cdecl utf8_to_utf16(const std::string& s); + +/// +/// Converts a ASCII (us-ascii) string to a UTF-16 string. +/// +/// A single byte character us-ascii string. +/// A two byte character UTF-16 string. +_ASYNCRTIMP utf16string __cdecl usascii_to_utf16(const std::string& s); + +/// +/// Converts a Latin1 (iso-8859-1) string to a UTF-16 string. +/// +/// A single byte character UTF-8 string. +/// A two byte character UTF-16 string. +_ASYNCRTIMP utf16string __cdecl latin1_to_utf16(const std::string& s); + +/// +/// Converts a Latin1 (iso-8859-1) string to a UTF-8 string. +/// +/// A single byte character UTF-8 string. +/// A single byte character UTF-8 string. +_ASYNCRTIMP utf8string __cdecl latin1_to_utf8(const std::string& s); + +/// +/// Converts to a platform dependent Unicode string type. +/// +/// A single byte character UTF-8 string. +/// A platform dependent string type. +#ifdef _UTF16_STRINGS +_ASYNCRTIMP utility::string_t __cdecl to_string_t(std::string&& s); +#else +inline utility::string_t&& to_string_t(std::string&& s) { return std::move(s); } +#endif + +/// +/// Converts to a platform dependent Unicode string type. +/// +/// A two byte character UTF-16 string. +/// A platform dependent string type. +#ifdef _UTF16_STRINGS +inline utility::string_t&& to_string_t(utf16string&& s) { return std::move(s); } +#else +_ASYNCRTIMP utility::string_t __cdecl to_string_t(utf16string&& s); +#endif +/// +/// Converts to a platform dependent Unicode string type. +/// +/// A single byte character UTF-8 string. +/// A platform dependent string type. +#ifdef _UTF16_STRINGS +_ASYNCRTIMP utility::string_t __cdecl to_string_t(const std::string& s); +#else +inline const utility::string_t& to_string_t(const std::string& s) { return s; } +#endif + +/// +/// Converts to a platform dependent Unicode string type. +/// +/// A two byte character UTF-16 string. +/// A platform dependent string type. +#ifdef _UTF16_STRINGS +inline const utility::string_t& to_string_t(const utf16string& s) { return s; } +#else +_ASYNCRTIMP utility::string_t __cdecl to_string_t(const utf16string& s); +#endif + +/// +/// Converts to a UTF-16 from string. +/// +/// A single byte character UTF-8 string. +/// A two byte character UTF-16 string. +_ASYNCRTIMP utf16string __cdecl to_utf16string(const std::string& value); + +/// +/// Converts to a UTF-16 from string. +/// +/// A two byte character UTF-16 string. +/// A two byte character UTF-16 string. +inline const utf16string& to_utf16string(const utf16string& value) { return value; } +/// +/// Converts to a UTF-16 from string. +/// +/// A two byte character UTF-16 string. +/// A two byte character UTF-16 string. +inline utf16string&& to_utf16string(utf16string&& value) { return std::move(value); } + +/// +/// Converts to a UTF-8 string. +/// +/// A single byte character UTF-8 string. +/// A single byte character UTF-8 string. +inline std::string&& to_utf8string(std::string&& value) { return std::move(value); } + +/// +/// Converts to a UTF-8 string. +/// +/// A single byte character UTF-8 string. +/// A single byte character UTF-8 string. +inline const std::string& to_utf8string(const std::string& value) { return value; } + +/// +/// Converts to a UTF-8 string. +/// +/// A two byte character UTF-16 string. +/// A single byte character UTF-8 string. +_ASYNCRTIMP std::string __cdecl to_utf8string(const utf16string& value); + +template +CASABLANCA_DEPRECATED("All locale-sensitive APIs will be removed in a future update. Use stringstreams directly if " + "locale support is required.") +utility::string_t print_string(const Source& val, const std::locale& loc = std::locale()) +{ + utility::ostringstream_t oss; + oss.imbue(loc); + oss << val; + if (oss.bad()) + { + throw std::bad_cast(); + } + return oss.str(); +} + +CASABLANCA_DEPRECATED("All locale-sensitive APIs will be removed in a future update. Use stringstreams directly if " + "locale support is required.") +inline utility::string_t print_string(const utility::string_t& val) { return val; } + +namespace details +{ +#if defined(__ANDROID__) +template +inline std::string to_string(const T t) +{ + std::ostringstream os; + os.imbue(std::locale::classic()); + os << t; + return os.str(); +} +#endif + +template +inline utility::string_t to_string_t(const T t) +{ +#ifdef _UTF16_STRINGS + using std::to_wstring; + return to_wstring(t); +#else +#if !defined(__ANDROID__) + using std::to_string; +#endif + return to_string(t); +#endif +} + +template +utility::string_t print_string(const Source& val) +{ + utility::ostringstream_t oss; + oss.imbue(std::locale::classic()); + oss << val; + if (oss.bad()) + { + throw std::bad_cast(); + } + return oss.str(); +} + +inline const utility::string_t& print_string(const utility::string_t& val) { return val; } + +template +utf8string print_utf8string(const Source& val) +{ + return conversions::to_utf8string(print_string(val)); +} +inline const utf8string& print_utf8string(const utf8string& val) { return val; } + +template +Target scan_string(const utility::string_t& str) +{ + Target t; + utility::istringstream_t iss(str); + iss.imbue(std::locale::classic()); + iss >> t; + if (iss.bad()) + { + throw std::bad_cast(); + } + return t; +} + +inline const utility::string_t& scan_string(const utility::string_t& str) { return str; } +} // namespace details + +template +CASABLANCA_DEPRECATED("All locale-sensitive APIs will be removed in a future update. Use stringstreams directly if " + "locale support is required.") +Target scan_string(const utility::string_t& str, const std::locale& loc = std::locale()) +{ + Target t; + utility::istringstream_t iss(str); + iss.imbue(loc); + iss >> t; + if (iss.bad()) + { + throw std::bad_cast(); + } + return t; +} + +CASABLANCA_DEPRECATED("All locale-sensitive APIs will be removed in a future update. Use stringstreams directly if " + "locale support is required.") +inline utility::string_t scan_string(const utility::string_t& str) { return str; } +} // namespace conversions + +namespace details +{ +/// +/// Cross platform RAII container for setting thread local locale. +/// +class scoped_c_thread_locale +{ +public: + _ASYNCRTIMP scoped_c_thread_locale(); + _ASYNCRTIMP ~scoped_c_thread_locale(); + +#if !defined(ANDROID) && !defined(__ANDROID__) // CodePlex 269 +#ifdef _WIN32 + typedef _locale_t xplat_locale; +#else + typedef locale_t xplat_locale; +#endif + + static _ASYNCRTIMP xplat_locale __cdecl c_locale(); +#endif +private: +#ifdef _WIN32 + std::string m_prevLocale; + int m_prevThreadSetting; +#elif !(defined(ANDROID) || defined(__ANDROID__)) + locale_t m_prevLocale; +#endif + scoped_c_thread_locale(const scoped_c_thread_locale&); + scoped_c_thread_locale& operator=(const scoped_c_thread_locale&); +}; + +/// +/// Our own implementation of alpha numeric instead of std::isalnum to avoid +/// taking global lock for performance reasons. +/// +inline bool __cdecl is_alnum(const unsigned char uch) CPPREST_NOEXCEPT +{ // test if uch is an alnum character + // special casing char to avoid branches + // clang-format off + static CPPREST_CONSTEXPR bool is_alnum_table[UCHAR_MAX + 1] = { + /* X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 XA XB XC XD XE XF */ + /* 0X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 1X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 2X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 3X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 0-9 */ + /* 4X */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* A-Z */ + /* 5X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, + /* 6X */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* a-z */ + /* 7X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 + /* non-ASCII values initialized to 0 */ + }; + // clang-format on + return (is_alnum_table[uch]); +} + +/// +/// Our own implementation of alpha numeric instead of std::isalnum to avoid +/// taking global lock for performance reasons. +/// +inline bool __cdecl is_alnum(const char ch) CPPREST_NOEXCEPT { return (is_alnum(static_cast(ch))); } + +/// +/// Our own implementation of alpha numeric instead of std::isalnum to avoid +/// taking global lock for performance reasons. +/// +template +inline bool __cdecl is_alnum(Elem ch) CPPREST_NOEXCEPT +{ + // assumes 'x' == L'x' for the ASCII range + typedef typename std::make_unsigned::type UElem; + const auto uch = static_cast(ch); + return (uch <= static_cast('z') && is_alnum(static_cast(uch))); +} + + +/// +/// Cross platform utility function for performing case insensitive string equality comparison. +/// +/// First string to compare. +/// Second strong to compare. +/// true if the strings are equivalent, false otherwise +_ASYNCRTIMP bool __cdecl str_iequal(const std::string& left, const std::string& right) CPPREST_NOEXCEPT; + +/// +/// Cross platform utility function for performing case insensitive string equality comparison. +/// +/// First string to compare. +/// Second strong to compare. +/// true if the strings are equivalent, false otherwise +_ASYNCRTIMP bool __cdecl str_iequal(const std::wstring& left, const std::wstring& right) CPPREST_NOEXCEPT; + +/// +/// Cross platform utility function for performing case insensitive string less-than comparison. +/// +/// First string to compare. +/// Second strong to compare. +/// true if a lowercase view of left is lexicographically less than a lowercase view of right; otherwise, +/// false. +_ASYNCRTIMP bool __cdecl str_iless(const std::string& left, const std::string& right) CPPREST_NOEXCEPT; + +/// +/// Cross platform utility function for performing case insensitive string less-than comparison. +/// +/// First string to compare. +/// Second strong to compare. +/// true if a lowercase view of left is lexicographically less than a lowercase view of right; otherwise, +/// false. +_ASYNCRTIMP bool __cdecl str_iless(const std::wstring& left, const std::wstring& right) CPPREST_NOEXCEPT; + +/// +/// Convert a string to lowercase in place. +/// +/// The string to convert to lowercase. +_ASYNCRTIMP void __cdecl inplace_tolower(std::string& target) CPPREST_NOEXCEPT; + +/// +/// Convert a string to lowercase in place. +/// +/// The string to convert to lowercase. +_ASYNCRTIMP void __cdecl inplace_tolower(std::wstring& target) CPPREST_NOEXCEPT; + +} // namespace details + +} // namespace utility diff --git a/Release/include/pplx/pplxlinux.h b/Release/include/pplx/pplxlinux.h index 5aca316e45..7a0027b0f3 100644 --- a/Release/include/pplx/pplxlinux.h +++ b/Release/include/pplx/pplxlinux.h @@ -17,6 +17,10 @@ #error This file must not be included for Visual Studio #endif +#if !defined(_PPLX_H) +#error Include pplx.h instead of pplxlinux.h directly. +#endif + #ifndef _WIN32 #include "cpprest/details/cpprest_compat.h" diff --git a/Release/include/pplx/pplxwin.h b/Release/include/pplx/pplxwin.h index 95a23b3158..c52098a87a 100644 --- a/Release/include/pplx/pplxwin.h +++ b/Release/include/pplx/pplxwin.h @@ -13,6 +13,10 @@ #pragma once +#if !defined(_PPLX_H) +#error Include pplx.h instead of pplxwin.h directly. +#endif + #if !defined(_WIN32) || _MSC_VER < 1800 || CPPREST_FORCE_PPLX #include "cpprest/details/cpprest_compat.h" diff --git a/Release/include/pplx/threadpool.h b/Release/include/pplx/threadpool.h index b297ff6bc8..bd77a27038 100644 --- a/Release/include/pplx/threadpool.h +++ b/Release/include/pplx/threadpool.h @@ -29,6 +29,7 @@ #endif #include "cpprest/details/cpprest_compat.h" +#include namespace crossplat { diff --git a/Release/samples/Oauth1Client/Oauth1Client.cpp b/Release/samples/Oauth1Client/Oauth1Client.cpp index dec9b342b5..ba96ad20bf 100644 --- a/Release/samples/Oauth1Client/Oauth1Client.cpp +++ b/Release/samples/Oauth1Client/Oauth1Client.cpp @@ -62,7 +62,7 @@ static void open_browser(utility::string_t auth_uri) { #if defined(_WIN32) && !defined(__cplusplus_winrt) // NOTE: Windows desktop only. - auto r = ShellExecuteA(NULL, "open", conversions::utf16_to_utf8(auth_uri).c_str(), NULL, NULL, SW_SHOWNORMAL); + auto r = ShellExecuteA(NULL, "open", conversions::to_utf8string(auth_uri).c_str(), NULL, NULL, SW_SHOWNORMAL); #elif defined(__APPLE__) // NOTE: OS X only. string_t browser_cmd(U("open \"") + auth_uri + U("\"")); diff --git a/Release/samples/Oauth2Client/Oauth2Client.cpp b/Release/samples/Oauth2Client/Oauth2Client.cpp index 19072cf6c6..e2e5c275ff 100644 --- a/Release/samples/Oauth2Client/Oauth2Client.cpp +++ b/Release/samples/Oauth2Client/Oauth2Client.cpp @@ -65,7 +65,7 @@ static void open_browser(utility::string_t auth_uri) { #if defined(_WIN32) && !defined(__cplusplus_winrt) // NOTE: Windows desktop only. - auto r = ShellExecuteA(NULL, "open", conversions::utf16_to_utf8(auth_uri).c_str(), NULL, NULL, SW_SHOWNORMAL); + auto r = ShellExecuteA(NULL, "open", conversions::to_utf8string(auth_uri).c_str(), NULL, NULL, SW_SHOWNORMAL); #elif defined(__APPLE__) // NOTE: OS X only. string_t browser_cmd(U("open \"") + auth_uri + U("\"")); diff --git a/Release/samples/SearchFile/searchfile.cpp b/Release/samples/SearchFile/searchfile.cpp index dfcc38bc2c..7200f05dc8 100644 --- a/Release/samples/SearchFile/searchfile.cpp +++ b/Release/samples/SearchFile/searchfile.cpp @@ -162,9 +162,9 @@ int main(int argc, char* args[]) printf("Usage: SearchFile.exe input_file search_string output_file\n"); return -1; } - const string_t inFileName = args[1]; + const string_t inFileName = utility::conversions::to_string_t(args[1]); const std::string searchString = utility::conversions::to_utf8string(args[2]); - const string_t outFileName = args[3]; + const string_t outFileName = utility::conversions::to_string_t(args[3]); producer_consumer_buffer lineResultsBuffer; // Find all matches in file. diff --git a/Release/src/CMakeLists.txt b/Release/src/CMakeLists.txt index 89d2bc55c3..8d46b3c2c4 100644 --- a/Release/src/CMakeLists.txt +++ b/Release/src/CMakeLists.txt @@ -15,6 +15,10 @@ set(SOURCES ${HEADERS_PPLX} ${HEADERS_DETAILS} pch/stdafx.h +) + +if(NOT CPPREST_EXCLUDE_HTTP_NARROW_STRING_WIP) +LIST(APPEND SOURCES http/client/http_client.cpp http/client/http_client_impl.h http/client/http_client_msg.cpp @@ -29,25 +33,166 @@ set(SOURCES http/listener/http_server_impl.h http/oauth/oauth1.cpp http/oauth/oauth2.cpp - json/json.cpp - json/json_parsing.cpp - json/json_serialization.cpp uri/uri.cpp uri/uri_builder.cpp - utilities/asyncrt_utils.cpp - utilities/base64.cpp - utilities/web_utilities.cpp +) +endif() + +# Targets for properties common to all cpprestsdk libraries +add_library(cpprest_interface_PUBLIC INTERFACE) +target_include_directories(cpprest_interface_PUBLIC + INTERFACE + $ +) +add_library(cpprest_interface_PRIVATE INTERFACE) +target_include_directories(cpprest_interface_PRIVATE + INTERFACE + $ ) add_library(cpprest ${SOURCES}) target_include_directories(cpprest PUBLIC - $ $ + $ PRIVATE pch ) +target_link_libraries(cpprest PUBLIC cpprest_interface_PUBLIC PRIVATE cpprest_interface_PRIVATE) +set(CPPREST_TARGETS cpprest cpprest_interface_PUBLIC) +if(NOT BUILD_SHARED_LIBS) + # for installed static libraries the private dependencies must also be + # "installed". As an interface it should not actually impact install. + list(APPEND CPPREST_TARGETS cpprest_interface_PRIVATE) +endif() + ## Sub-components + +# add_sub_component(name sources...) +# When CPPREST_ISOLATE_COMPONENTS is ON: +# Creates library ${name} using given sources. Then adds respective +# object files to cpprest. +# Otherwise sources are added to cpprest directly. +function(add_sub_component name) # sources... + set(COMPONENT_SOURCES ${ARGN}) + + # cpprest and this new library inherit these properties publicly. + add_library(${name}_properties_PUBLIC INTERFACE) + target_link_libraries(${name}_properties_PUBLIC INTERFACE cpprest_interface_PUBLIC) + # cpprest and this new library inherit these properties privately. + add_library(${name}_properties_PRIVATE INTERFACE) + target_link_libraries(${name}_properties_PRIVATE INTERFACE cpprest_interface_PRIVATE) + + if(CPPREST_ISOLATE_COMPONENTS) + # isolated components are built as OBJECT_LIBRARY so that cpprest library + # may be self contained (apart from external dependencies) and sources are + # still only compiled once. + add_library(${name}_objects OBJECT ${COMPONENT_SOURCES}) + # disable pch for isolated builds to ensure dependencies are explict and + # to avoid contamination across components by setting include path to + # reach primitive (ideally empty) stdafx.h. + target_include_directories(${name}_objects + PRIVATE + nopch + ) + set_target_properties(${name}_objects PROPERTIES POSITION_INDEPENDENT_CODE ON) + target_link_libraries(${name}_objects PRIVATE ${name}_properties_PUBLIC ${name}_properties_PRIVATE) + + # create library of sub-component + add_library(${name} $) + target_link_libraries(${name} PUBLIC ${name}_properties_PUBLIC PRIVATE ${name}_properties_PRIVATE) + + # connect sources to cpprest (main target) + target_sources(cpprest PRIVATE $) + else() + # no isolation, just build sources as part of cpprest + target_sources(cpprest PRIVATE ${COMPONENT_SOURCES}) + + # do create a dummy interface library for sub-components to specify other + # sub-components in sub_component_link_libraries + add_library(${name} INTERFACE) + # also add to target install list in case there is such use + list(APPEND CPPREST_TARGETS ${name}) + endif() + + target_link_libraries(cpprest PUBLIC ${name}_properties_PUBLIC PRIVATE ${name}_properties_PRIVATE) + + # append public properties (interface) target to install list + # sub-component libraries (isolation build only) are not installed + list(APPEND CPPREST_TARGETS ${name}_properties_PUBLIC) + if(NOT BUILD_SHARED_LIBS) + # for installed static libraries the private dependencies must also be + # "installed". Should be interfaces and not actually impact install. + list(APPEND CPPREST_TARGETS ${name}_properties_PRIVATE) + endif() + set(CPPREST_TARGETS ${CPPREST_TARGETS} PARENT_SCOPE) +endfunction() + +# sub_component_sources(name sources...) +# Adds given sources to sub-component library and/or cpprest. +function(sub_component_sources name) # additional sources... + if(CPPREST_ISOLATE_COMPONENTS) + target_sources(${name}_objects ${ARGN}) + else() + # no actual sub-component targets built when not isolated; pass along + # sources to cpprest + target_sources(cpprest ${ARGN}) + endif() +endfunction() + +# sub_component_link_libraries(name link_dependencies...) +# Adds given link_dependencies to sub-component library and/or cpprest. +function(sub_component_link_libraries name) # link dependencies... + if(CPPREST_ISOLATE_COMPONENTS) + target_link_libraries(${name}_objects ${ARGN}) + target_link_libraries(${name} ${ARGN}) + # remove entries in list that are our own sub-components + # before passing up to cpprest + set(ALL_LINK_ARGS ${ARGN}) + foreach(LINK_ARG ${ALL_LINK_ARGS}) + if(TARGET ${LINK_ARG}_properties_PRIVATE) + list(REMOVE_ITEM ARGN ${LINK_ARG}) + endif() + endforeach() + else() + # no actual sub-component targets built when not isolated + endif() + # pass along dependencies to cpprest in all cases + # (in isolated case only objects are referenced, so dependencies + # need to be passed up too) + target_link_libraries(cpprest ${ARGN}) +endfunction() + + +# Utility components +add_sub_component(cpprest_utility_strings + utilities/string_utils.cpp +) + +add_sub_component(cpprest_utility_asyncrt + utilities/asyncrt_utils.cpp +) +sub_component_link_libraries(cpprest_utility_asyncrt PUBLIC cpprest_utility_strings) + +add_sub_component(cpprest_utilities + utilities/base64.cpp + utilities/web_utilities.cpp +) +sub_component_link_libraries(cpprest_utilities PUBLIC cpprest_utility_asyncrt cpprest_utility_strings) +if(WIN32 AND NOT WINDOWS_STORE AND NOT WINDOWS_PHONE) + sub_component_link_libraries(cpprest_utilities PRIVATE + crypt32.lib + ) +endif() + +# Json component +add_sub_component(cpprest_json + json/json.cpp + json/json_parsing.cpp + json/json_serialization.cpp +) +sub_component_link_libraries(cpprest_json PUBLIC cpprest_utility_strings) + # Websockets component if(CPPREST_WEBSOCKETS_IMPL STREQUAL "none") target_compile_definitions(cpprest PUBLIC -DCPPREST_EXCLUDE_WEBSOCKETS=1) @@ -94,37 +239,46 @@ endif() if(CPPREST_PPLX_IMPL STREQUAL "apple") find_library(COREFOUNDATION CoreFoundation "/") find_library(SECURITY Security "/") - target_link_libraries(cpprest PUBLIC ${COREFOUNDATION} ${SECURITY}) - target_sources(cpprest PRIVATE pplx/pplxapple.cpp pplx/pplx.cpp pplx/threadpool.cpp ../include/pplx/threadpool.h) + add_sub_component(cpprest_pplx pplx/pplxapple.cpp pplx/pplx.cpp pplx/threadpool.cpp ../include/pplx/threadpool.h) + sub_component_link_libraries(cpprest_pplx PUBLIC ${COREFOUNDATION} ${SECURITY}) if(CPPREST_INSTALL_HEADERS) install(FILES ../include/pplx/threadpool.h DESTINATION include/pplx) endif() elseif(CPPREST_PPLX_IMPL STREQUAL "linux") - target_sources(cpprest PRIVATE pplx/pplxlinux.cpp pplx/pplx.cpp pplx/threadpool.cpp ../include/pplx/threadpool.h) + add_sub_component(cpprest_pplx pplx/pplxlinux.cpp pplx/pplx.cpp pplx/threadpool.cpp ../include/pplx/threadpool.h) if(CPPREST_INSTALL_HEADERS) install(FILES ../include/pplx/threadpool.h DESTINATION include/pplx) endif() elseif(CPPREST_PPLX_IMPL STREQUAL "win") - target_sources(cpprest PRIVATE pplx/pplxwin.cpp) + add_sub_component(cpprest_pplx pplx/pplxwin.cpp) if(CPPREST_WEBSOCKETS_IMPL STREQUAL "wspp") - target_sources(cpprest PRIVATE pplx/threadpool.cpp ../include/pplx/threadpool.h) + sub_component_sources(cpprest_pplx PRIVATE pplx/threadpool.cpp ../include/pplx/threadpool.h) if(CPPREST_INSTALL_HEADERS) install(FILES ../include/pplx/threadpool.h DESTINATION include/pplx) endif() endif() elseif(CPPREST_PPLX_IMPL STREQUAL "winpplx") - target_compile_definitions(cpprest PUBLIC -DCPPREST_FORCE_PPLX=1) - target_sources(cpprest PRIVATE pplx/pplxwin.cpp pplx/pplx.cpp pplx/threadpool.cpp ../include/pplx/threadpool.h) - if(CPPREST_INSTALL_HEADERS) - install(FILES ../include/pplx/threadpool.h DESTINATION include/pplx) + add_sub_component(cpprest_pplx pplx/pplxwin.cpp pplx/pplx.cpp) + target_compile_definitions(cpprest_pplx_properties_PUBLIC INTERFACE -DCPPREST_FORCE_PPLX=1) + if(NOT CPPREST_WEBSOCKETS_IMPL STREQUAL "none") + sub_component_sources(cpprest_pplx PRIVATE pplx/threadpool.cpp ../include/pplx/threadpool.h) + if(CPPREST_INSTALL_HEADERS) + install(FILES ../include/pplx/threadpool.h DESTINATION include/pplx) + endif() endif() elseif(CPPREST_PPLX_IMPL STREQUAL "winrt") - target_sources(cpprest PRIVATE pplx/pplxwin.cpp) + add_sub_component(cpprest_pplx pplx/pplxwin.cpp) else() message(FATAL_ERROR "Invalid implementation") endif() +if(NOT CPPREST_PPLX_IMPL STREQUAL "winrt") + cpprest_find_boost() + sub_component_link_libraries(cpprest_pplx PUBLIC cpprestsdk_boost_internal) +endif() +sub_component_link_libraries(cpprest_pplx PUBLIC cpprest_utility_asyncrt) # Http client component +if(NOT CPPREST_EXCLUDE_HTTP_NARROW_STRING_WIP) if(CPPREST_HTTP_CLIENT_IMPL STREQUAL "asio") cpprest_find_boost() cpprest_find_openssl() @@ -145,17 +299,19 @@ elseif(CPPREST_HTTP_CLIENT_IMPL STREQUAL "winrt") else() message(FATAL_ERROR "Invalid implementation") endif() +endif() # fileio streams component if(CPPREST_FILEIO_IMPL STREQUAL "win32") - target_sources(cpprest PRIVATE streams/fileio_win32.cpp) + add_sub_component(cpprest_streams streams/fileio_win32.cpp) elseif(CPPREST_FILEIO_IMPL STREQUAL "winrt") - target_sources(cpprest PRIVATE streams/fileio_winrt.cpp) + add_sub_component(cpprest_streams streams/fileio_winrt.cpp) elseif(CPPREST_FILEIO_IMPL STREQUAL "posix") - target_sources(cpprest PRIVATE streams/fileio_posix.cpp) + add_sub_component(cpprest_streams streams/fileio_posix.cpp) else() message(FATAL_ERROR "Invalid implementation") endif() +sub_component_link_libraries(cpprest_streams PUBLIC cpprest_utility_asyncrt) # http listener component if(CPPREST_HTTP_LISTENER_IMPL STREQUAL "asio") @@ -189,12 +345,12 @@ endif() if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU") if(WERROR) - target_compile_options(cpprest PRIVATE -Werror) + target_compile_options(cpprest_interface_PRIVATE INTERFACE -Werror) endif() - target_compile_options(cpprest PRIVATE -pedantic ${WARNINGS}) + target_compile_options(cpprest_interface_PRIVATE INTERFACE -pedantic ${WARNINGS}) elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") if(WERROR) - target_compile_options(cpprest PRIVATE /WX ${WARNINGS}) + target_compile_options(cpprest_interface_PRIVATE INTERFACE /WX ${WARNINGS}) endif() else() message(FATAL_ERROR "Unknown compiler") @@ -202,22 +358,21 @@ endif() if(WIN32) if (BUILD_SHARED_LIBS) - target_compile_definitions(cpprest PRIVATE -D_ASYNCRT_EXPORT -D_PPLX_EXPORT -D_USRDLL) + target_compile_definitions(cpprest_interface_PRIVATE INTERFACE -D_ASYNCRT_EXPORT -D_PPLX_EXPORT -D_USRDLL) else() - target_compile_definitions(cpprest PUBLIC -D_NO_ASYNCRTIMP -D_NO_PPLXIMP) + target_compile_definitions(cpprest_interface_PUBLIC INTERFACE -D_NO_ASYNCRTIMP -D_NO_PPLXIMP) endif() elseif(ANDROID) - target_link_libraries(cpprest PRIVATE ${ANDROID_STL_FLAGS}) + target_link_libraries(cpprest_interface_PRIVATE INTERFACE ${ANDROID_STL_FLAGS}) endif() if (WIN32 AND NOT WINDOWS_STORE AND NOT WINDOWS_PHONE) target_link_libraries(cpprest PRIVATE bcrypt.lib - crypt32.lib ) elseif(WINDOWS_STORE) if(NOT CMAKE_GENERATOR MATCHES "Visual Studio .*") - target_compile_definitions(cpprest PRIVATE -DWINAPI_FAMILY=WINAPI_FAMILY_PC_APP) + target_compile_definitions(cpprest_interface_PRIVATE INTERFACE -DWINAPI_FAMILY=WINAPI_FAMILY_PC_APP) get_target_property(LINK_FLAGS cpprest LINK_FLAGS) if(NOT LINK_FLAGS) set(LINK_FLAGS "") @@ -249,7 +404,6 @@ if(CPPREST_INSTALL) set(CPPREST_USES_BROTLI OFF) set(CPPREST_USES_OPENSSL OFF) - set(CPPREST_TARGETS cpprest) if(TARGET cpprestsdk_boost_internal) list(APPEND CPPREST_TARGETS cpprestsdk_boost_internal) set(CPPREST_USES_BOOST ON) diff --git a/Release/src/http/common/http_msg.cpp b/Release/src/http/common/http_msg.cpp index c32dfcfaaa..c1c062b999 100644 --- a/Release/src/http/common/http_msg.cpp +++ b/Release/src/http/common/http_msg.cpp @@ -225,7 +225,7 @@ utility::string_t flatten_http_headers(const http_headers& headers) return flattened_headers; } -#if defined(_WIN32) +#if defined(_UTF16_STRINGS) void parse_headers_string(_Inout_z_ utf16char* headersStr, http_headers& headers) { utf16char* context = nullptr; diff --git a/Release/src/http/oauth/oauth1.cpp b/Release/src/http/oauth/oauth1.cpp index b313cfcdb3..4db2d6e80c 100644 --- a/Release/src/http/oauth/oauth1.cpp +++ b/Release/src/http/oauth/oauth1.cpp @@ -62,8 +62,8 @@ std::vector oauth1_config::_hmac_sha1(const utility::string_t& ke DWORD hash_len = 0; ULONG result_len = 0; - const auto& key_c = conversions::utf16_to_utf8(key); - const auto& data_c = conversions::utf16_to_utf8(data); + const auto& key_c = conversions::to_utf8string(key); + const auto& data_c = conversions::to_utf8string(data); status = BCryptOpenAlgorithmProvider(&alg_handle, BCRYPT_SHA1_ALGORITHM, nullptr, BCRYPT_ALG_HANDLE_HMAC_FLAG); if (!NT_SUCCESS(status)) diff --git a/Release/src/internal/windows_config.h b/Release/src/internal/windows_config.h new file mode 100644 index 0000000000..a726e4f17b --- /dev/null +++ b/Release/src/internal/windows_config.h @@ -0,0 +1,40 @@ +/*** +* Copyright (C) Microsoft. All rights reserved. +* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. +* +* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +* +* Internal headers +* +* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk +* +* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +****/ + +#pragma once + +#if !defined(_WIN32) +#error windows_config.h use only expected for Windows builds. (_WIN32 is not defined) +#endif + +// use the debug version of the CRT if _DEBUG is defined +#ifdef _DEBUG +#define _CRTDBG_MAP_ALLOC +#include +#endif // _DEBUG + +#include +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers + +#if CPPREST_TARGET_XP && _WIN32_WINNT != 0x0501 +#error CPPREST_TARGET_XP implies _WIN32_WINNT == 0x0501 +#endif // CPPREST_TARGET_XP && _WIN32_WINNT != 0x0501 + +#include + +#include + +// Windows Header Files: +#ifndef __cplusplus_winrt +#include +#endif !__cplusplus_winrt diff --git a/Release/src/json/json.cpp b/Release/src/json/json.cpp index 7614866acc..b5262d26aa 100644 --- a/Release/src/json/json.cpp +++ b/Release/src/json/json.cpp @@ -13,6 +13,8 @@ #include "stdafx.h" +#include "cpprest/json.h" + using namespace web; bool json::details::g_keep_json_object_unsorted = false; @@ -195,7 +197,7 @@ web::json::value web::json::value::string(utility::string_t value, bool has_esca ); } -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) web::json::value web::json::value::string(const std::string& value) { std::unique_ptr ptr = diff --git a/Release/src/json/json_parsing.cpp b/Release/src/json/json_parsing.cpp index 30873fd36d..8dd1b0585a 100644 --- a/Release/src/json/json_parsing.cpp +++ b/Release/src/json/json_parsing.cpp @@ -13,7 +13,11 @@ #include "stdafx.h" +#include "cpprest/json.h" + +#include #include +#include #if defined(_MSC_VER) #pragma warning(disable : 4127) // allow expressions like while(true) pass @@ -356,24 +360,32 @@ inline bool JSON_Parser::ParseInt64(CharType first, uint64_t& value) // This namespace hides the x-plat helper functions namespace { -#if defined(_WIN32) +#ifdef _WIN32 + static int print_llu(char* ptr, size_t n, uint64_t val64) { return _snprintf_s_l(ptr, n, _TRUNCATE, "%I64u", utility::details::scoped_c_thread_locale::c_locale(), val64); } +#if defined(_UTF16_STRINGS) static int print_llu(wchar_t* ptr, size_t n, uint64_t val64) { return _snwprintf_s_l(ptr, n, _TRUNCATE, L"%I64u", utility::details::scoped_c_thread_locale::c_locale(), val64); } +#endif + static double anystod(const char* str) { return _strtod_l(str, nullptr, utility::details::scoped_c_thread_locale::c_locale()); } + +#if defined(_UTF16_STRINGS) static double anystod(const wchar_t* str) { return _wcstod_l(str, nullptr, utility::details::scoped_c_thread_locale::c_locale()); } +#endif + #else static int __attribute__((__unused__)) print_llu(char* ptr, size_t n, unsigned long long val64) { @@ -815,7 +827,7 @@ bool JSON_StringParser::CompleteStringLiteral(typename JSON_Parser(token.string_val.c_str() + prevSize), start, numChars * sizeof(CharType)); + std::memcpy(const_cast(token.string_val.c_str() + prevSize), start, numChars * sizeof(CharType)); if (!JSON_StringParser::handle_unescape_char(token)) { @@ -836,7 +848,7 @@ bool JSON_StringParser::CompleteStringLiteral(typename JSON_Parser(token.string_val.c_str() + prevSize), start, numChars * sizeof(CharType)); + std::memcpy(const_cast(token.string_val.c_str() + prevSize), start, numChars * sizeof(CharType)); token.kind = JSON_Parser::Token::TKN_StringLiteral; @@ -1166,7 +1178,7 @@ static web::json::value _parse_stream(utility::istream_t& stream, std::error_cod return returnObject; } -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) static web::json::value _parse_narrow_stream(std::istream& stream) { web::json::details::JSON_StreamParser parser(stream); @@ -1269,7 +1281,7 @@ web::json::value web::json::value::parse(utility::istream_t& stream, std::error_ return _parse_stream(stream, error); } -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) web::json::value web::json::value::parse(std::istream& stream) { return _parse_narrow_stream(stream); } web::json::value web::json::value::parse(std::istream& stream, std::error_code& error) diff --git a/Release/src/json/json_serialization.cpp b/Release/src/json/json_serialization.cpp index 3aa0c50ceb..7a9617ec49 100644 --- a/Release/src/json/json_serialization.cpp +++ b/Release/src/json/json_serialization.cpp @@ -13,6 +13,9 @@ #include "stdafx.h" +#include "cpprest/json.h" + +#include #include #ifndef _WIN32 @@ -29,7 +32,7 @@ using namespace utility::conversions; // JSON Serialization // -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) void web::json::value::serialize(std::ostream& stream) const { // This has better performance than writing directly to stream. @@ -119,7 +122,7 @@ void web::json::details::format_string(const utility::string_t& key, utility::st str.push_back('"'); } -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) void web::json::details::format_string(const utility::string_t& key, std::string& str) { str.push_back('"'); @@ -190,7 +193,7 @@ void web::json::details::_Number::format(std::basic_string& stream) const } } -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) void web::json::details::_String::format(std::basic_string& str) const { diff --git a/Release/src/nopch/stdafx.h b/Release/src/nopch/stdafx.h new file mode 100644 index 0000000000..d32bbd5137 --- /dev/null +++ b/Release/src/nopch/stdafx.h @@ -0,0 +1,17 @@ +/*** +* Copyright (C) Microsoft. All rights reserved. +* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. +* +* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +* +* Pre-compiled headers +* +* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk +* +* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +****/ + +#pragma once + +// There are no contents here -- in support of component isolation builds. + diff --git a/Release/src/pch/stdafx.h b/Release/src/pch/stdafx.h index 2061bea7f6..ff414674e9 100644 --- a/Release/src/pch/stdafx.h +++ b/Release/src/pch/stdafx.h @@ -20,29 +20,8 @@ #endif #ifdef _WIN32 -// use the debug version of the CRT if _DEBUG is defined -#ifdef _DEBUG -#define _CRTDBG_MAP_ALLOC -#include -#endif // _DEBUG - -#include -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers - -#if CPPREST_TARGET_XP && _WIN32_WINNT != 0x0501 -#error CPPREST_TARGET_XP implies _WIN32_WINNT == 0x0501 -#endif // CPPREST_TARGET_XP && _WIN32_WINNT != 0x0501 - -#include - -#include - -// Windows Header Files: -#ifndef __cplusplus_winrt -#include -#endif !__cplusplus_winrt - -#else // LINUX or APPLE +#include "windows_config.h" +#else // LINUX or APPLE #define __STDC_LIMIT_MACROS #include "pthread.h" #include @@ -92,7 +71,10 @@ // utilities #include "cpprest/asyncrt_utils.h" +#include "cpprest/base64_utils.h" #include "cpprest/details/web_utilities.h" +#include "cpprest/memory_utils.h" +#include "cpprest/string_utils.h" // http #include "cpprest/details/http_helpers.h" diff --git a/Release/src/pplx/pplxlinux.cpp b/Release/src/pplx/pplxlinux.cpp index 630a9e477f..ac5d92ecf9 100644 --- a/Release/src/pplx/pplxlinux.cpp +++ b/Release/src/pplx/pplxlinux.cpp @@ -16,6 +16,7 @@ #include "pplx/pplx.h" #include "pplx/threadpool.h" #include "sys/syscall.h" +#include #include #ifdef _WIN32 diff --git a/Release/src/pplx/pplxwin.cpp b/Release/src/pplx/pplxwin.cpp index e25d9acf34..c81b074472 100644 --- a/Release/src/pplx/pplxwin.cpp +++ b/Release/src/pplx/pplxwin.cpp @@ -15,7 +15,11 @@ #if !defined(_WIN32) || CPPREST_FORCE_PPLX -#include "pplx/pplxwin.h" +#include "pplx/pplx.h" +#include "pplx/pplxwin.h" // Note: Should already be included by way of pplx.h + +#include "cpprest/asyncrt_utils.h" +#include "windows_config.h" // Disable false alarm code analysis warning #pragma warning(disable : 26165 26110) @@ -242,6 +246,9 @@ _PPLXIMP void windows_scheduler::schedule(TaskProc_t proc, _In_ void* param) } // namespace pplx #else // ^^^ !defined(_WIN32) || CPPREST_FORCE_PPLX ^^^ // vvv defined(_WIN32) && !CPPREST_FORCE_PPLX vvv + +#include "pplx/pplxtasks.h" + namespace Concurrency { void __cdecl set_cpprestsdk_ambient_scheduler(const std::shared_ptr& _Scheduler) diff --git a/Release/src/pplx/threadpool.cpp b/Release/src/pplx/threadpool.cpp index ba38a1a12f..a2fd471945 100644 --- a/Release/src/pplx/threadpool.cpp +++ b/Release/src/pplx/threadpool.cpp @@ -4,9 +4,13 @@ **/ #include "stdafx.h" -#if !defined(CPPREST_EXCLUDE_WEBSOCKETS) || !defined(_WIN32) +#if defined(CPPREST_EXCLUDE_WEBSOCKETS) && defined(_WIN32) +#error CPPREST_EXCLUDE_WEBSOCKETS and WIN32, but still compiling threadpool.cpp +#endif + #include "pplx/threadpool.h" #include +#include #include #include #include @@ -232,4 +236,3 @@ std::unique_ptr crossplat::threadpool::construct(size_t n { return std::unique_ptr(new threadpool_impl(num_threads)); } -#endif // !defined(CPPREST_EXCLUDE_WEBSOCKETS) || !defined(_WIN32) diff --git a/Release/src/streams/fileio_posix.cpp b/Release/src/streams/fileio_posix.cpp index 2404196423..7396bd7b93 100644 --- a/Release/src/streams/fileio_posix.cpp +++ b/Release/src/streams/fileio_posix.cpp @@ -19,6 +19,10 @@ #include "cpprest/details/fileio.h" +#include "cpprest/asyncrt_utils.h" +#include +#include + using namespace boost::asio; using namespace Concurrency::streams::details; diff --git a/Release/src/streams/fileio_win32.cpp b/Release/src/streams/fileio_win32.cpp index 97cd6e5e6d..5ff5976754 100644 --- a/Release/src/streams/fileio_win32.cpp +++ b/Release/src/streams/fileio_win32.cpp @@ -19,10 +19,12 @@ #include "cpprest/details/fileio.h" -using namespace web; +#include "cpprest/asyncrt_utils.h" + +#include "windows_config.h" + using namespace utility; using namespace concurrency; -using namespace utility::conversions; namespace Concurrency { @@ -228,7 +230,7 @@ bool __cdecl _open_fsb_str(_In_ _filestream_callback* callback, _ASSERTE(callback != nullptr); _ASSERTE(filename != nullptr); - std::wstring name(filename); + std::wstring name = conversions::to_utf16string(filename); pplx::create_task([=]() { DWORD dwDesiredAccess, dwCreationDisposition, dwShareMode; diff --git a/Release/src/utilities/asyncrt_utils.cpp b/Release/src/utilities/asyncrt_utils.cpp index 5263c8d5d5..849d930ff1 100644 --- a/Release/src/utilities/asyncrt_utils.cpp +++ b/Release/src/utilities/asyncrt_utils.cpp @@ -13,201 +13,22 @@ #include "stdafx.h" -#include #include + +#include +#include #include #include #include -using namespace web; -using namespace utility; -using namespace utility::conversions; - -namespace -{ -struct to_lower_ch_impl -{ - char operator()(char c) const CPPREST_NOEXCEPT - { - if (c >= 'A' && c <= 'Z') return static_cast(c - 'A' + 'a'); - return c; - } - - wchar_t operator()(wchar_t c) const CPPREST_NOEXCEPT - { - if (c >= L'A' && c <= L'Z') return static_cast(c - L'A' + L'a'); - return c; - } -}; - -CPPREST_CONSTEXPR to_lower_ch_impl to_lower_ch {}; - -struct eq_lower_ch_impl -{ - template - inline CharT operator()(const CharT left, const CharT right) const CPPREST_NOEXCEPT - { - return to_lower_ch(left) == to_lower_ch(right); - } -}; - -CPPREST_CONSTEXPR eq_lower_ch_impl eq_lower_ch {}; - -struct lt_lower_ch_impl -{ - template - inline CharT operator()(const CharT left, const CharT right) const CPPREST_NOEXCEPT - { - return to_lower_ch(left) < to_lower_ch(right); - } -}; - -CPPREST_CONSTEXPR lt_lower_ch_impl lt_lower_ch {}; -} // namespace - -namespace utility -{ -namespace details -{ -_ASYNCRTIMP bool __cdecl str_iequal(const std::string& left, const std::string& right) CPPREST_NOEXCEPT -{ - return left.size() == right.size() && std::equal(left.cbegin(), left.cend(), right.cbegin(), eq_lower_ch); -} - -_ASYNCRTIMP bool __cdecl str_iequal(const std::wstring& left, const std::wstring& right) CPPREST_NOEXCEPT -{ - return left.size() == right.size() && std::equal(left.cbegin(), left.cend(), right.cbegin(), eq_lower_ch); -} - -_ASYNCRTIMP bool __cdecl str_iless(const std::string& left, const std::string& right) CPPREST_NOEXCEPT -{ - return std::lexicographical_compare(left.cbegin(), left.cend(), right.cbegin(), right.cend(), lt_lower_ch); -} - -_ASYNCRTIMP bool __cdecl str_iless(const std::wstring& left, const std::wstring& right) CPPREST_NOEXCEPT -{ - return std::lexicographical_compare(left.cbegin(), left.cend(), right.cbegin(), right.cend(), lt_lower_ch); -} - -_ASYNCRTIMP void __cdecl inplace_tolower(std::string& target) CPPREST_NOEXCEPT -{ - for (auto& ch : target) - { - ch = to_lower_ch(ch); - } -} - -_ASYNCRTIMP void __cdecl inplace_tolower(std::wstring& target) CPPREST_NOEXCEPT -{ - for (auto& ch : target) - { - ch = to_lower_ch(ch); - } -} - -#if !defined(ANDROID) && !defined(__ANDROID__) -std::once_flag g_c_localeFlag; -std::unique_ptr g_c_locale( - nullptr, [](scoped_c_thread_locale::xplat_locale*) {}); -scoped_c_thread_locale::xplat_locale scoped_c_thread_locale::c_locale() -{ - std::call_once(g_c_localeFlag, [&]() { - scoped_c_thread_locale::xplat_locale* clocale = new scoped_c_thread_locale::xplat_locale(); -#ifdef _WIN32 - *clocale = _create_locale(LC_ALL, "C"); - if (clocale == nullptr || *clocale == nullptr) - { - throw std::runtime_error("Unable to create 'C' locale."); - } - auto deleter = [](scoped_c_thread_locale::xplat_locale* clocale) { - _free_locale(*clocale); - delete clocale; - }; -#else - *clocale = newlocale(LC_ALL, "C", nullptr); - if (clocale == nullptr || *clocale == nullptr) - { - throw std::runtime_error("Unable to create 'C' locale."); - } - auto deleter = [](scoped_c_thread_locale::xplat_locale *clocale) - { - freelocale(*clocale); - delete clocale; - }; -#endif - g_c_locale = - std::unique_ptr( - clocale, deleter); - }); - return *g_c_locale; -} +#if defined(_WIN32) +#include "windows_config.h" #endif -#ifdef _WIN32 -scoped_c_thread_locale::scoped_c_thread_locale() : m_prevLocale(), m_prevThreadSetting(-1) -{ - char* prevLocale = setlocale(LC_ALL, nullptr); - if (prevLocale == nullptr) - { - throw std::runtime_error("Unable to retrieve current locale."); - } - - if (std::strcmp(prevLocale, "C") != 0) - { - m_prevLocale = prevLocale; - m_prevThreadSetting = _configthreadlocale(_ENABLE_PER_THREAD_LOCALE); - if (m_prevThreadSetting == -1) - { - throw std::runtime_error("Unable to enable per thread locale."); - } - if (setlocale(LC_ALL, "C") == nullptr) - { - _configthreadlocale(m_prevThreadSetting); - throw std::runtime_error("Unable to set locale"); - } - } -} - -scoped_c_thread_locale::~scoped_c_thread_locale() -{ - if (m_prevThreadSetting != -1) - { - setlocale(LC_ALL, m_prevLocale.c_str()); - _configthreadlocale(m_prevThreadSetting); - } -} -#elif (defined(ANDROID) || defined(__ANDROID__)) -scoped_c_thread_locale::scoped_c_thread_locale() {} -scoped_c_thread_locale::~scoped_c_thread_locale() {} -#else -scoped_c_thread_locale::scoped_c_thread_locale() : m_prevLocale(nullptr) -{ - char* prevLocale = setlocale(LC_ALL, nullptr); - if (prevLocale == nullptr) - { - throw std::runtime_error("Unable to retrieve current locale."); - } - - if (std::strcmp(prevLocale, "C") != 0) - { - m_prevLocale = uselocale(c_locale()); - if (m_prevLocale == nullptr) - { - throw std::runtime_error("Unable to set locale"); - } - } -} +using namespace utility; -scoped_c_thread_locale::~scoped_c_thread_locale() +namespace utility { - if (m_prevLocale != nullptr) - { - uselocale(m_prevLocale); - } -} -#endif -} // namespace details - namespace details { const std::error_category& __cdecl platform_category() @@ -302,321 +123,6 @@ const std::error_category& __cdecl linux_category() } // namespace details -#define LOW_3BITS 0x7 -#define LOW_4BITS 0xF -#define LOW_5BITS 0x1F -#define LOW_6BITS 0x3F -#define BIT4 0x8 -#define BIT5 0x10 -#define BIT6 0x20 -#define BIT7 0x40 -#define BIT8 0x80 -#define L_SURROGATE_START 0xDC00 -#define L_SURROGATE_END 0xDFFF -#define H_SURROGATE_START 0xD800 -#define H_SURROGATE_END 0xDBFF -#define SURROGATE_PAIR_START 0x10000 - -// Create a dedicated type for characters to avoid the issue -// of different platforms defaulting char to be either signed -// or unsigned. -using UtilCharInternal_t = signed char; - -inline size_t count_utf8_to_utf16(const std::string& s) -{ - const size_t sSize = s.size(); - auto const sData = reinterpret_cast(s.data()); - size_t result {sSize}; - - for (size_t index = 0; index < sSize;) - { - if (sData[index] >= 0) - { - // use fast inner loop to skip single byte code points (which are - // expected to be the most frequent) - while ((++index < sSize) && (sData[index] >= 0)) - ; - - if (index >= sSize) break; - } - - // start special handling for multi-byte code points - const UtilCharInternal_t c {sData[index++]}; - - if ((c & BIT7) == 0) - { - throw std::range_error("UTF-8 string character can never start with 10xxxxxx"); - } - else if ((c & BIT6) == 0) // 2 byte character, 0x80 to 0x7FF - { - if (index == sSize) - { - throw std::range_error("UTF-8 string is missing bytes in character"); - } - - const UtilCharInternal_t c2 {sData[index++]}; - if ((c2 & 0xC0) != BIT8) - { - throw std::range_error("UTF-8 continuation byte is missing leading bit mask"); - } - - // can't require surrogates for 7FF - --result; - } - else if ((c & BIT5) == 0) // 3 byte character, 0x800 to 0xFFFF - { - if (sSize - index < 2) - { - throw std::range_error("UTF-8 string is missing bytes in character"); - } - - const UtilCharInternal_t c2 {sData[index++]}; - const UtilCharInternal_t c3 {sData[index++]}; - if (((c2 | c3) & 0xC0) != BIT8) - { - throw std::range_error("UTF-8 continuation byte is missing leading bit mask"); - } - - result -= 2; - } - else if ((c & BIT4) == 0) // 4 byte character, 0x10000 to 0x10FFFF - { - if (sSize - index < 3) - { - throw std::range_error("UTF-8 string is missing bytes in character"); - } - - const UtilCharInternal_t c2 {sData[index++]}; - const UtilCharInternal_t c3 {sData[index++]}; - const UtilCharInternal_t c4 {sData[index++]}; - if (((c2 | c3 | c4) & 0xC0) != BIT8) - { - throw std::range_error("UTF-8 continuation byte is missing leading bit mask"); - } - - const uint32_t codePoint = - ((c & LOW_3BITS) << 18) | ((c2 & LOW_6BITS) << 12) | ((c3 & LOW_6BITS) << 6) | (c4 & LOW_6BITS); - result -= (3 - (codePoint >= SURROGATE_PAIR_START)); - } - else - { - throw std::range_error("UTF-8 string has invalid Unicode code point"); - } - } - - return result; -} - -utf16string __cdecl conversions::utf8_to_utf16(const std::string& s) -{ - // Save repeated heap allocations, use the length of resulting sequence. - const size_t srcSize = s.size(); - auto const srcData = reinterpret_cast(s.data()); - utf16string dest(count_utf8_to_utf16(s), L'\0'); - utf16string::value_type* const destData = &dest[0]; - size_t destIndex = 0; - - for (size_t index = 0; index < srcSize; ++index) - { - UtilCharInternal_t src = srcData[index]; - switch (src & 0xF0) - { - case 0xF0: // 4 byte character, 0x10000 to 0x10FFFF - { - const UtilCharInternal_t c2 {srcData[++index]}; - const UtilCharInternal_t c3 {srcData[++index]}; - const UtilCharInternal_t c4 {srcData[++index]}; - uint32_t codePoint = - ((src & LOW_3BITS) << 18) | ((c2 & LOW_6BITS) << 12) | ((c3 & LOW_6BITS) << 6) | (c4 & LOW_6BITS); - if (codePoint >= SURROGATE_PAIR_START) - { - // In UTF-16 U+10000 to U+10FFFF are represented as two 16-bit code units, surrogate pairs. - // - 0x10000 is subtracted from the code point - // - high surrogate is 0xD800 added to the top ten bits - // - low surrogate is 0xDC00 added to the low ten bits - codePoint -= SURROGATE_PAIR_START; - destData[destIndex++] = static_cast((codePoint >> 10) | H_SURROGATE_START); - destData[destIndex++] = - static_cast((codePoint & 0x3FF) | L_SURROGATE_START); - } - else - { - // In UTF-16 U+0000 to U+D7FF and U+E000 to U+FFFF are represented exactly as the Unicode code point - // value. U+D800 to U+DFFF are not valid characters, for simplicity we assume they are not present - // but will encode them if encountered. - destData[destIndex++] = static_cast(codePoint); - } - } - break; - case 0xE0: // 3 byte character, 0x800 to 0xFFFF - { - const UtilCharInternal_t c2 {srcData[++index]}; - const UtilCharInternal_t c3 {srcData[++index]}; - destData[destIndex++] = static_cast( - ((src & LOW_4BITS) << 12) | ((c2 & LOW_6BITS) << 6) | (c3 & LOW_6BITS)); - } - break; - case 0xD0: // 2 byte character, 0x80 to 0x7FF - case 0xC0: - { - const UtilCharInternal_t c2 {srcData[++index]}; - destData[destIndex++] = - static_cast(((src & LOW_5BITS) << 6) | (c2 & LOW_6BITS)); - } - break; - default: // single byte character, 0x0 to 0x7F - // try to use a fast inner loop for following single byte characters, - // since they are quite probable - do - { - destData[destIndex++] = static_cast(srcData[index++]); - } while (index < srcSize && srcData[index] > 0); - // adjust index since it will be incremented by the for loop - --index; - } - } - return dest; -} - -inline size_t count_utf16_to_utf8(const utf16string& w) -{ - const utf16string::value_type* const srcData = &w[0]; - const size_t srcSize = w.size(); - size_t destSize(srcSize); - for (size_t index = 0; index < srcSize; ++index) - { - const utf16string::value_type ch(srcData[index]); - if (ch <= 0x7FF) - { - if (ch > 0x7F) // 2 bytes needed (11 bits used) - { - ++destSize; - } - } - // Check for high surrogate. - else if (ch >= H_SURROGATE_START && ch <= H_SURROGATE_END) // 4 bytes needed (21 bits used) - { - ++index; - if (index == srcSize) - { - throw std::range_error("UTF-16 string is missing low surrogate"); - } - - const auto lowSurrogate = srcData[index]; - if (lowSurrogate < L_SURROGATE_START || lowSurrogate > L_SURROGATE_END) - { - throw std::range_error("UTF-16 string has invalid low surrogate"); - } - - destSize += 2; - } - else // 3 bytes needed (16 bits used) - { - destSize += 2; - } - } - - return destSize; -} - -std::string __cdecl conversions::utf16_to_utf8(const utf16string& w) -{ - const size_t srcSize = w.size(); - const utf16string::value_type* const srcData = &w[0]; - std::string dest(count_utf16_to_utf8(w), '\0'); - std::string::value_type* const destData = &dest[0]; - size_t destIndex(0); - - for (size_t index = 0; index < srcSize; ++index) - { - const utf16string::value_type src = srcData[index]; - if (src <= 0x7FF) - { - if (src <= 0x7F) // single byte character - { - destData[destIndex++] = static_cast(src); - } - else // 2 bytes needed (11 bits used) - { - destData[destIndex++] = static_cast(char((src >> 6) | 0xC0)); // leading 5 bits - destData[destIndex++] = static_cast(char((src & LOW_6BITS) | BIT8)); // trailing 6 bits - } - } - // Check for high surrogate. - else if (src >= H_SURROGATE_START && src <= H_SURROGATE_END) - { - const auto highSurrogate = src; - const auto lowSurrogate = srcData[++index]; - - // To get from surrogate pair to Unicode code point: - // - subtract 0xD800 from high surrogate, this forms top ten bits - // - subtract 0xDC00 from low surrogate, this forms low ten bits - // - add 0x10000 - // Leaves a code point in U+10000 to U+10FFFF range. - uint32_t codePoint = highSurrogate - H_SURROGATE_START; - codePoint <<= 10; - codePoint |= lowSurrogate - L_SURROGATE_START; - codePoint += SURROGATE_PAIR_START; - - // 4 bytes needed (21 bits used) - destData[destIndex++] = static_cast((codePoint >> 18) | 0xF0); // leading 3 bits - destData[destIndex++] = static_cast(((codePoint >> 12) & LOW_6BITS) | BIT8); // next 6 bits - destData[destIndex++] = static_cast(((codePoint >> 6) & LOW_6BITS) | BIT8); // next 6 bits - destData[destIndex++] = static_cast((codePoint & LOW_6BITS) | BIT8); // trailing 6 bits - } - else // 3 bytes needed (16 bits used) - { - destData[destIndex++] = static_cast((src >> 12) | 0xE0); // leading 4 bits - destData[destIndex++] = static_cast(((src >> 6) & LOW_6BITS) | BIT8); // middle 6 bits - destData[destIndex++] = static_cast((src & LOW_6BITS) | BIT8); // trailing 6 bits - } - } - - return dest; -} - -utf16string __cdecl conversions::usascii_to_utf16(const std::string& s) -{ - // Ascii is a subset of UTF-8 so just convert to UTF-16 - return utf8_to_utf16(s); -} - -utf16string __cdecl conversions::latin1_to_utf16(const std::string& s) -{ - // Latin1 is the first 256 code points in Unicode. - // In UTF-16 encoding each of these is represented as exactly the numeric code point. - utf16string dest; - // Prefer resize combined with for-loop over constructor dest(s.begin(), s.end()) - // for faster assignment. - dest.resize(s.size()); - for (size_t i = 0; i < s.size(); ++i) - { - dest[i] = utf16char(static_cast(s[i])); - } - return dest; -} - -utf8string __cdecl conversions::latin1_to_utf8(const std::string& s) { return utf16_to_utf8(latin1_to_utf16(s)); } - -#ifndef _UTF16_STRINGS -utility::string_t __cdecl conversions::to_string_t(utf16string&& s) { return utf16_to_utf8(std::move(s)); } -#endif - -#ifdef _UTF16_STRINGS -utility::string_t __cdecl conversions::to_string_t(std::string&& s) { return utf8_to_utf16(std::move(s)); } -#endif - -#ifndef _UTF16_STRINGS -utility::string_t __cdecl conversions::to_string_t(const utf16string& s) { return utf16_to_utf8(s); } -#endif - -#ifdef _UTF16_STRINGS -utility::string_t __cdecl conversions::to_string_t(const std::string& s) { return utf8_to_utf16(s); } -#endif - -std::string __cdecl conversions::to_utf8string(const utf16string& value) { return utf16_to_utf8(value); } - -utf16string __cdecl conversions::to_utf16string(const std::string& value) { return utf8_to_utf16(value); } static const int64_t NtToUnixOffsetSeconds = 11644473600; // diff between windows and unix epochs (seconds) @@ -801,7 +307,7 @@ utility::string_t datetime::to_string(date_format format) const leftover); #endif // _MSC_VER outCursor += 25; - memcpy(outCursor, " GMT", 4); + std::memcpy(outCursor, " GMT", 4); outCursor += 4; return utility::string_t(outBuffer, outCursor); case ISO_8601: diff --git a/Release/src/utilities/base64.cpp b/Release/src/utilities/base64.cpp index 1cb235c3b5..429c3ff24c 100644 --- a/Release/src/utilities/base64.cpp +++ b/Release/src/utilities/base64.cpp @@ -10,7 +10,11 @@ ****/ #include "stdafx.h" -using namespace web; +#include "cpprest/base64_utils.h" + +#include +#include + using namespace utility; std::vector _from_base64(const utility::string_t& str); @@ -135,7 +139,7 @@ std::vector _from_base64(const utility::string_t& input) for (; size > 4; ++idx) { unsigned char target[3]; - memset(target, 0, sizeof(target)); + std::memset(target, 0, sizeof(target)); _triple_byte* record = reinterpret_cast<_triple_byte*>(target); unsigned char val0 = _base64_dectbl[ptr[0]]; @@ -164,7 +168,7 @@ std::vector _from_base64(const utility::string_t& input) { unsigned char target[3]; - memset(target, 0, sizeof(target)); + std::memset(target, 0, sizeof(target)); _triple_byte* record = reinterpret_cast<_triple_byte*>(target); unsigned char val0 = _base64_dectbl[ptr[0]]; diff --git a/Release/src/utilities/string_utils.cpp b/Release/src/utilities/string_utils.cpp new file mode 100644 index 0000000000..5100546a6e --- /dev/null +++ b/Release/src/utilities/string_utils.cpp @@ -0,0 +1,529 @@ +/*** + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Utilities + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ + +#include "stdafx.h" + +#include + +#include +#include +#include +#include +#include + +using namespace utility; +using namespace utility::conversions; + +namespace +{ +struct to_lower_ch_impl +{ + char operator()(char c) const CPPREST_NOEXCEPT + { + if (c >= 'A' && c <= 'Z') return static_cast(c - 'A' + 'a'); + return c; + } + + wchar_t operator()(wchar_t c) const CPPREST_NOEXCEPT + { + if (c >= L'A' && c <= L'Z') return static_cast(c - L'A' + L'a'); + return c; + } +}; + +CPPREST_CONSTEXPR to_lower_ch_impl to_lower_ch {}; + +struct eq_lower_ch_impl +{ + template + inline CharT operator()(const CharT left, const CharT right) const CPPREST_NOEXCEPT + { + return to_lower_ch(left) == to_lower_ch(right); + } +}; + +CPPREST_CONSTEXPR eq_lower_ch_impl eq_lower_ch {}; + +struct lt_lower_ch_impl +{ + template + inline CharT operator()(const CharT left, const CharT right) const CPPREST_NOEXCEPT + { + return to_lower_ch(left) < to_lower_ch(right); + } +}; + +CPPREST_CONSTEXPR lt_lower_ch_impl lt_lower_ch {}; +} // namespace + +namespace utility +{ +namespace details +{ +_ASYNCRTIMP bool __cdecl str_iequal(const std::string& left, const std::string& right) CPPREST_NOEXCEPT +{ + return left.size() == right.size() && std::equal(left.cbegin(), left.cend(), right.cbegin(), eq_lower_ch); +} + +_ASYNCRTIMP bool __cdecl str_iequal(const std::wstring& left, const std::wstring& right) CPPREST_NOEXCEPT +{ + return left.size() == right.size() && std::equal(left.cbegin(), left.cend(), right.cbegin(), eq_lower_ch); +} + +_ASYNCRTIMP bool __cdecl str_iless(const std::string& left, const std::string& right) CPPREST_NOEXCEPT +{ + return std::lexicographical_compare(left.cbegin(), left.cend(), right.cbegin(), right.cend(), lt_lower_ch); +} + +_ASYNCRTIMP bool __cdecl str_iless(const std::wstring& left, const std::wstring& right) CPPREST_NOEXCEPT +{ + return std::lexicographical_compare(left.cbegin(), left.cend(), right.cbegin(), right.cend(), lt_lower_ch); +} + +_ASYNCRTIMP void __cdecl inplace_tolower(std::string& target) CPPREST_NOEXCEPT +{ + for (auto& ch : target) + { + ch = to_lower_ch(ch); + } +} + +_ASYNCRTIMP void __cdecl inplace_tolower(std::wstring& target) CPPREST_NOEXCEPT +{ + for (auto& ch : target) + { + ch = to_lower_ch(ch); + } +} + +#if !defined(ANDROID) && !defined(__ANDROID__) +std::once_flag g_c_localeFlag; +std::unique_ptr g_c_locale( + nullptr, [](scoped_c_thread_locale::xplat_locale*) {}); +scoped_c_thread_locale::xplat_locale scoped_c_thread_locale::c_locale() +{ + std::call_once(g_c_localeFlag, [&]() { + scoped_c_thread_locale::xplat_locale* clocale = new scoped_c_thread_locale::xplat_locale(); +#ifdef _WIN32 + *clocale = _create_locale(LC_ALL, "C"); + if (clocale == nullptr || *clocale == nullptr) + { + throw std::runtime_error("Unable to create 'C' locale."); + } + auto deleter = [](scoped_c_thread_locale::xplat_locale* clocale) { + _free_locale(*clocale); + delete clocale; + }; +#else + *clocale = newlocale(LC_ALL, "C", nullptr); + if (clocale == nullptr || *clocale == nullptr) + { + throw std::runtime_error("Unable to create 'C' locale."); + } + auto deleter = [](scoped_c_thread_locale::xplat_locale *clocale) + { + freelocale(*clocale); + delete clocale; + }; +#endif + g_c_locale = + std::unique_ptr( + clocale, deleter); + }); + return *g_c_locale; +} +#endif + +#ifdef _WIN32 +scoped_c_thread_locale::scoped_c_thread_locale() : m_prevLocale(), m_prevThreadSetting(-1) +{ + char* prevLocale = setlocale(LC_ALL, nullptr); + if (prevLocale == nullptr) + { + throw std::runtime_error("Unable to retrieve current locale."); + } + + if (std::strcmp(prevLocale, "C") != 0) + { + m_prevLocale = prevLocale; + m_prevThreadSetting = _configthreadlocale(_ENABLE_PER_THREAD_LOCALE); + if (m_prevThreadSetting == -1) + { + throw std::runtime_error("Unable to enable per thread locale."); + } + if (setlocale(LC_ALL, "C") == nullptr) + { + _configthreadlocale(m_prevThreadSetting); + throw std::runtime_error("Unable to set locale"); + } + } +} + +scoped_c_thread_locale::~scoped_c_thread_locale() +{ + if (m_prevThreadSetting != -1) + { + setlocale(LC_ALL, m_prevLocale.c_str()); + _configthreadlocale(m_prevThreadSetting); + } +} +#elif (defined(ANDROID) || defined(__ANDROID__)) +scoped_c_thread_locale::scoped_c_thread_locale() {} +scoped_c_thread_locale::~scoped_c_thread_locale() {} +#else +scoped_c_thread_locale::scoped_c_thread_locale() : m_prevLocale(nullptr) +{ + char* prevLocale = setlocale(LC_ALL, nullptr); + if (prevLocale == nullptr) + { + throw std::runtime_error("Unable to retrieve current locale."); + } + + if (std::strcmp(prevLocale, "C") != 0) + { + m_prevLocale = uselocale(c_locale()); + if (m_prevLocale == nullptr) + { + throw std::runtime_error("Unable to set locale"); + } + } +} + +scoped_c_thread_locale::~scoped_c_thread_locale() +{ + if (m_prevLocale != nullptr) + { + uselocale(m_prevLocale); + } +} +#endif +} // namespace details + + +#define LOW_3BITS 0x7 +#define LOW_4BITS 0xF +#define LOW_5BITS 0x1F +#define LOW_6BITS 0x3F +#define BIT4 0x8 +#define BIT5 0x10 +#define BIT6 0x20 +#define BIT7 0x40 +#define BIT8 0x80 +#define L_SURROGATE_START 0xDC00 +#define L_SURROGATE_END 0xDFFF +#define H_SURROGATE_START 0xD800 +#define H_SURROGATE_END 0xDBFF +#define SURROGATE_PAIR_START 0x10000 + +// Create a dedicated type for characters to avoid the issue +// of different platforms defaulting char to be either signed +// or unsigned. +using UtilCharInternal_t = signed char; + +inline size_t count_utf8_to_utf16(const std::string& s) +{ + const size_t sSize = s.size(); + auto const sData = reinterpret_cast(s.data()); + size_t result {sSize}; + + for (size_t index = 0; index < sSize;) + { + if (sData[index] >= 0) + { + // use fast inner loop to skip single byte code points (which are + // expected to be the most frequent) + while ((++index < sSize) && (sData[index] >= 0)) + ; + + if (index >= sSize) break; + } + + // start special handling for multi-byte code points + const UtilCharInternal_t c {sData[index++]}; + + if ((c & BIT7) == 0) + { + throw std::range_error("UTF-8 string character can never start with 10xxxxxx"); + } + else if ((c & BIT6) == 0) // 2 byte character, 0x80 to 0x7FF + { + if (index == sSize) + { + throw std::range_error("UTF-8 string is missing bytes in character"); + } + + const UtilCharInternal_t c2 {sData[index++]}; + if ((c2 & 0xC0) != BIT8) + { + throw std::range_error("UTF-8 continuation byte is missing leading bit mask"); + } + + // can't require surrogates for 7FF + --result; + } + else if ((c & BIT5) == 0) // 3 byte character, 0x800 to 0xFFFF + { + if (sSize - index < 2) + { + throw std::range_error("UTF-8 string is missing bytes in character"); + } + + const UtilCharInternal_t c2 {sData[index++]}; + const UtilCharInternal_t c3 {sData[index++]}; + if (((c2 | c3) & 0xC0) != BIT8) + { + throw std::range_error("UTF-8 continuation byte is missing leading bit mask"); + } + + result -= 2; + } + else if ((c & BIT4) == 0) // 4 byte character, 0x10000 to 0x10FFFF + { + if (sSize - index < 3) + { + throw std::range_error("UTF-8 string is missing bytes in character"); + } + + const UtilCharInternal_t c2 {sData[index++]}; + const UtilCharInternal_t c3 {sData[index++]}; + const UtilCharInternal_t c4 {sData[index++]}; + if (((c2 | c3 | c4) & 0xC0) != BIT8) + { + throw std::range_error("UTF-8 continuation byte is missing leading bit mask"); + } + + const uint32_t codePoint = + ((c & LOW_3BITS) << 18) | ((c2 & LOW_6BITS) << 12) | ((c3 & LOW_6BITS) << 6) | (c4 & LOW_6BITS); + result -= (3 - (codePoint >= SURROGATE_PAIR_START)); + } + else + { + throw std::range_error("UTF-8 string has invalid Unicode code point"); + } + } + + return result; +} + +utf16string __cdecl conversions::utf8_to_utf16(const std::string& s) +{ + // Save repeated heap allocations, use the length of resulting sequence. + const size_t srcSize = s.size(); + auto const srcData = reinterpret_cast(s.data()); + utf16string dest(count_utf8_to_utf16(s), L'\0'); + utf16string::value_type* const destData = &dest[0]; + size_t destIndex = 0; + + for (size_t index = 0; index < srcSize; ++index) + { + UtilCharInternal_t src = srcData[index]; + switch (src & 0xF0) + { + case 0xF0: // 4 byte character, 0x10000 to 0x10FFFF + { + const UtilCharInternal_t c2 {srcData[++index]}; + const UtilCharInternal_t c3 {srcData[++index]}; + const UtilCharInternal_t c4 {srcData[++index]}; + uint32_t codePoint = + ((src & LOW_3BITS) << 18) | ((c2 & LOW_6BITS) << 12) | ((c3 & LOW_6BITS) << 6) | (c4 & LOW_6BITS); + if (codePoint >= SURROGATE_PAIR_START) + { + // In UTF-16 U+10000 to U+10FFFF are represented as two 16-bit code units, surrogate pairs. + // - 0x10000 is subtracted from the code point + // - high surrogate is 0xD800 added to the top ten bits + // - low surrogate is 0xDC00 added to the low ten bits + codePoint -= SURROGATE_PAIR_START; + destData[destIndex++] = static_cast((codePoint >> 10) | H_SURROGATE_START); + destData[destIndex++] = + static_cast((codePoint & 0x3FF) | L_SURROGATE_START); + } + else + { + // In UTF-16 U+0000 to U+D7FF and U+E000 to U+FFFF are represented exactly as the Unicode code point + // value. U+D800 to U+DFFF are not valid characters, for simplicity we assume they are not present + // but will encode them if encountered. + destData[destIndex++] = static_cast(codePoint); + } + } + break; + case 0xE0: // 3 byte character, 0x800 to 0xFFFF + { + const UtilCharInternal_t c2 {srcData[++index]}; + const UtilCharInternal_t c3 {srcData[++index]}; + destData[destIndex++] = static_cast( + ((src & LOW_4BITS) << 12) | ((c2 & LOW_6BITS) << 6) | (c3 & LOW_6BITS)); + } + break; + case 0xD0: // 2 byte character, 0x80 to 0x7FF + case 0xC0: + { + const UtilCharInternal_t c2 {srcData[++index]}; + destData[destIndex++] = + static_cast(((src & LOW_5BITS) << 6) | (c2 & LOW_6BITS)); + } + break; + default: // single byte character, 0x0 to 0x7F + // try to use a fast inner loop for following single byte characters, + // since they are quite probable + do + { + destData[destIndex++] = static_cast(srcData[index++]); + } while (index < srcSize && srcData[index] > 0); + // adjust index since it will be incremented by the for loop + --index; + } + } + return dest; +} + +inline size_t count_utf16_to_utf8(const utf16string& w) +{ + const utf16string::value_type* const srcData = &w[0]; + const size_t srcSize = w.size(); + size_t destSize(srcSize); + for (size_t index = 0; index < srcSize; ++index) + { + const utf16string::value_type ch(srcData[index]); + if (ch <= 0x7FF) + { + if (ch > 0x7F) // 2 bytes needed (11 bits used) + { + ++destSize; + } + } + // Check for high surrogate. + else if (ch >= H_SURROGATE_START && ch <= H_SURROGATE_END) // 4 bytes needed (21 bits used) + { + ++index; + if (index == srcSize) + { + throw std::range_error("UTF-16 string is missing low surrogate"); + } + + const auto lowSurrogate = srcData[index]; + if (lowSurrogate < L_SURROGATE_START || lowSurrogate > L_SURROGATE_END) + { + throw std::range_error("UTF-16 string has invalid low surrogate"); + } + + destSize += 2; + } + else // 3 bytes needed (16 bits used) + { + destSize += 2; + } + } + + return destSize; +} + +std::string __cdecl conversions::utf16_to_utf8(const utf16string& w) +{ + const size_t srcSize = w.size(); + const utf16string::value_type* const srcData = &w[0]; + std::string dest(count_utf16_to_utf8(w), '\0'); + std::string::value_type* const destData = &dest[0]; + size_t destIndex(0); + + for (size_t index = 0; index < srcSize; ++index) + { + const utf16string::value_type src = srcData[index]; + if (src <= 0x7FF) + { + if (src <= 0x7F) // single byte character + { + destData[destIndex++] = static_cast(src); + } + else // 2 bytes needed (11 bits used) + { + destData[destIndex++] = static_cast(char((src >> 6) | 0xC0)); // leading 5 bits + destData[destIndex++] = static_cast(char((src & LOW_6BITS) | BIT8)); // trailing 6 bits + } + } + // Check for high surrogate. + else if (src >= H_SURROGATE_START && src <= H_SURROGATE_END) + { + const auto highSurrogate = src; + const auto lowSurrogate = srcData[++index]; + + // To get from surrogate pair to Unicode code point: + // - subtract 0xD800 from high surrogate, this forms top ten bits + // - subtract 0xDC00 from low surrogate, this forms low ten bits + // - add 0x10000 + // Leaves a code point in U+10000 to U+10FFFF range. + uint32_t codePoint = highSurrogate - H_SURROGATE_START; + codePoint <<= 10; + codePoint |= lowSurrogate - L_SURROGATE_START; + codePoint += SURROGATE_PAIR_START; + + // 4 bytes needed (21 bits used) + destData[destIndex++] = static_cast((codePoint >> 18) | 0xF0); // leading 3 bits + destData[destIndex++] = static_cast(((codePoint >> 12) & LOW_6BITS) | BIT8); // next 6 bits + destData[destIndex++] = static_cast(((codePoint >> 6) & LOW_6BITS) | BIT8); // next 6 bits + destData[destIndex++] = static_cast((codePoint & LOW_6BITS) | BIT8); // trailing 6 bits + } + else // 3 bytes needed (16 bits used) + { + destData[destIndex++] = static_cast((src >> 12) | 0xE0); // leading 4 bits + destData[destIndex++] = static_cast(((src >> 6) & LOW_6BITS) | BIT8); // middle 6 bits + destData[destIndex++] = static_cast((src & LOW_6BITS) | BIT8); // trailing 6 bits + } + } + + return dest; +} + +utf16string __cdecl conversions::usascii_to_utf16(const std::string& s) +{ + // Ascii is a subset of UTF-8 so just convert to UTF-16 + return utf8_to_utf16(s); +} + +utf16string __cdecl conversions::latin1_to_utf16(const std::string& s) +{ + // Latin1 is the first 256 code points in Unicode. + // In UTF-16 encoding each of these is represented as exactly the numeric code point. + utf16string dest; + // Prefer resize combined with for-loop over constructor dest(s.begin(), s.end()) + // for faster assignment. + dest.resize(s.size()); + for (size_t i = 0; i < s.size(); ++i) + { + dest[i] = utf16char(static_cast(s[i])); + } + return dest; +} + +utf8string __cdecl conversions::latin1_to_utf8(const std::string& s) { return utf16_to_utf8(latin1_to_utf16(s)); } + +#ifndef _UTF16_STRINGS +utility::string_t __cdecl conversions::to_string_t(utf16string&& s) { return utf16_to_utf8(std::move(s)); } +#endif + +#ifdef _UTF16_STRINGS +utility::string_t __cdecl conversions::to_string_t(std::string&& s) { return utf8_to_utf16(std::move(s)); } +#endif + +#ifndef _UTF16_STRINGS +utility::string_t __cdecl conversions::to_string_t(const utf16string& s) { return utf16_to_utf8(s); } +#endif + +#ifdef _UTF16_STRINGS +utility::string_t __cdecl conversions::to_string_t(const std::string& s) { return utf8_to_utf16(s); } +#endif + +std::string __cdecl conversions::to_utf8string(const utf16string& value) { return utf16_to_utf8(value); } + +utf16string __cdecl conversions::to_utf16string(const std::string& value) { return utf8_to_utf16(value); } + +} // namespace utility diff --git a/Release/src/utilities/web_utilities.cpp b/Release/src/utilities/web_utilities.cpp index ce00078b79..39f09629d4 100644 --- a/Release/src/utilities/web_utilities.cpp +++ b/Release/src/utilities/web_utilities.cpp @@ -13,14 +13,19 @@ #include "stdafx.h" +#include "cpprest/details/web_utilities.h" + #include -#if defined(_WIN32) && !defined(__cplusplus_winrt) +#if defined(_WIN32) +#include "windows_config.h" + +#if !defined(__cplusplus_winrt) #include +#else +#include #endif -#if defined(__cplusplus_winrt) -#include #endif namespace web @@ -47,15 +52,15 @@ void winrt_secure_zero_buffer(Windows::Storage::Streams::IBuffer ^ buffer) } } -winrt_encryption::winrt_encryption(const std::wstring& data) +winrt_encryption::winrt_encryption(const ::utility::string_t& data) { auto provider = ref new Windows::Security::Cryptography::DataProtection::DataProtectionProvider( ref new Platform::String(L"Local=user")); // Create buffer containing plain text password. Platform::ArrayReference arrayref( - reinterpret_cast(const_cast(data.c_str())), - static_cast(data.size()) * sizeof(std::wstring::value_type)); + reinterpret_cast(const_cast<::utility::string_t::value_type*>(data.c_str())), + static_cast(data.size()) * sizeof(::utility::string_t::value_type)); Windows::Storage::Streams::IBuffer ^ plaintext = Windows::Security::Cryptography::CryptographicBuffer::CreateFromByteArray(arrayref); m_buffer = pplx::create_task(provider->ProtectAsync(plaintext)); @@ -84,14 +89,14 @@ plaintext_string winrt_encryption::decrypt() const // Construct string and zero out memory from plain text buffer. auto data = plaintext_string( - new std::wstring(reinterpret_cast(rawPlaintext), plaintext->Length / 2)); + new ::utility::string_t(reinterpret_cast(rawPlaintext), plaintext->Length / 2)); SecureZeroMemory(rawPlaintext, plaintext->Length); return std::move(data); } #else // ^^^ __cplusplus_winrt ^^^ // vvv !__cplusplus_winrt vvv -win32_encryption::win32_encryption(const std::wstring& data) : m_numCharacters(data.size()) +win32_encryption::win32_encryption(const ::utility::string_t& data) : m_numCharacters(data.size()) { // Early return because CryptProtectMemory crashes with empty string if (m_numCharacters == 0) @@ -99,12 +104,12 @@ win32_encryption::win32_encryption(const std::wstring& data) : m_numCharacters(d return; } - if (data.size() > (std::numeric_limits::max)() / sizeof(wchar_t)) + if (data.size() > (std::numeric_limits::max)() / sizeof(::utility::string_t::value_type)) { throw std::length_error("Encryption string too long"); } - const auto dataSizeDword = static_cast(data.size() * sizeof(wchar_t)); + const auto dataSizeDword = static_cast(data.size() * sizeof(::utility::string_t::value_type)); // Round up dataSizeDword to be a multiple of CRYPTPROTECTMEMORY_BLOCK_SIZE static_assert(CRYPTPROTECTMEMORY_BLOCK_SIZE == 16, "Power of 2 assumptions in this bit masking violated"); @@ -125,8 +130,8 @@ win32_encryption::~win32_encryption() { SecureZeroMemory(m_buffer.data(), m_buff plaintext_string win32_encryption::decrypt() const { // Copy the buffer and decrypt to avoid having to re-encrypt. - auto result = plaintext_string(new std::wstring(reinterpret_cast(m_buffer.data()), - m_buffer.size() / sizeof(wchar_t))); + auto result = plaintext_string(new ::utility::string_t(reinterpret_cast(m_buffer.data()), + m_buffer.size() / sizeof(::utility::string_t::value_type))); auto& data = *result; if (!m_buffer.empty()) { diff --git a/Release/tests/common/UnitTestpp/CMakeLists.txt b/Release/tests/common/UnitTestpp/CMakeLists.txt index 309c5f28fa..8cbda5b284 100644 --- a/Release/tests/common/UnitTestpp/CMakeLists.txt +++ b/Release/tests/common/UnitTestpp/CMakeLists.txt @@ -47,7 +47,7 @@ elseif(WIN32) endif() add_library(unittestpp ${UT_SOURCES}) -target_link_libraries(unittestpp PUBLIC cpprest) +target_link_libraries(unittestpp PUBLIC cpprest_interface_PUBLIC) if(UNIX) cpprest_find_boost() diff --git a/Release/tests/functional/CMakeLists.txt b/Release/tests/functional/CMakeLists.txt index cc89052590..9fa83f0a68 100644 --- a/Release/tests/functional/CMakeLists.txt +++ b/Release/tests/functional/CMakeLists.txt @@ -1,7 +1,13 @@ +if(NOT CPPREST_EXCLUDE_HTTP_NARROW_STRING_WIP) add_subdirectory(http) +endif() add_subdirectory(json) add_subdirectory(pplx) add_subdirectory(streams) +if(NOT CPPREST_EXCLUDE_HTTP_NARROW_STRING_WIP) add_subdirectory(uri) +endif() add_subdirectory(utils) -add_subdirectory(websockets) \ No newline at end of file +if(NOT CPPREST_EXCLUDE_HTTP_NARROW_STRING_WIP) +add_subdirectory(websockets) +endif() diff --git a/Release/tests/functional/json/CMakeLists.txt b/Release/tests/functional/json/CMakeLists.txt index 1d44a99ce6..61d443c69a 100644 --- a/Release/tests/functional/json/CMakeLists.txt +++ b/Release/tests/functional/json/CMakeLists.txt @@ -10,7 +10,11 @@ if(NOT WINDOWS_STORE AND NOT WINDOWS_PHONE) list(APPEND SOURCES fuzz_tests.cpp) endif() -add_casablanca_test(json_test SOURCES) +set(ADDITIONAL_COMPONENTS) +if(WIN32) + set(ADDITIONAL_COMPONENTS cpprest_streams) +endif() +add_casablanca_test(json_test SOURCES cpprest_json ${ADDITIONAL_COMPONENTS}) if(UNIX AND NOT APPLE) cpprest_find_boost() target_link_libraries(json_test PRIVATE cpprestsdk_boost_internal) diff --git a/Release/tests/functional/json/fuzz_tests.cpp b/Release/tests/functional/json/fuzz_tests.cpp index a925bf9dfb..f9ee113aaa 100644 --- a/Release/tests/functional/json/fuzz_tests.cpp +++ b/Release/tests/functional/json/fuzz_tests.cpp @@ -41,7 +41,7 @@ SUITE(json_fuzz_tests) TEST(fuzz_json_parser, "Requires", "fuzzedinputfile") { - std::wstring ipfile = utility::conversions::to_utf16string(get_fuzzed_file_path()); + utility::string_t ipfile = utility::conversions::to_string_t(get_fuzzed_file_path()); if (true == ipfile.empty()) { VERIFY_IS_TRUE(false, "Input file is empty"); @@ -52,22 +52,27 @@ SUITE(json_fuzz_tests) concurrency::streams::container_buffer cbuf; fs.read_to_end(cbuf).get(); fs.close().get(); - auto json_str = cbuf.collection(); + auto utf8_json_str = cbuf.collection(); // Look for UTF-8 BOM - if ((uint8_t)json_str[0] != 0xEF || (uint8_t)json_str[1] != 0xBB || (uint8_t)json_str[2] != 0xBF) + if ((uint8_t)utf8_json_str[0] != 0xEF || (uint8_t)utf8_json_str[1] != 0xBB || (uint8_t)utf8_json_str[2] != 0xBF) { VERIFY_IS_TRUE(false, "Input file encoding is not UTF-8. Test will not parse the file."); return; } - auto utf16_json_str = utility::conversions::utf8_to_utf16(json_str); + auto json_str = utility::conversions::to_string_t(utf8_json_str); +#if defined(_UTF16_STRINGS) // UTF8 to UTF16 conversion will retain the BOM, remove it. - if (utf16_json_str.front() == 0xFEFF) utf16_json_str.erase(0, 1); + if (json_str.front() == 0xFEFF) json_str.erase(0, 1); +#else + // remove the BOM + json_str.erase(0, 3); +#endif try { - json::value::parse(std::move(utf16_json_str)); + json::value::parse(std::move(json_str)); std::cout << "Input file parsed successfully."; } catch (const json::json_exception& ex) diff --git a/Release/tests/functional/json/json_numbers_tests.cpp b/Release/tests/functional/json/json_numbers_tests.cpp index 538d44d367..79905a1de8 100644 --- a/Release/tests/functional/json/json_numbers_tests.cpp +++ b/Release/tests/functional/json/json_numbers_tests.cpp @@ -196,7 +196,7 @@ SUITE(json_numbers_tests) "Fails due to double conversion issues") { // JSON uses the C locale always and should therefore not be impacted by the process locale -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) std::string changedLocale("fr-FR"); #else std::string changedLocale("fr_FR.UTF-8"); diff --git a/Release/tests/functional/json/negative_parsing_tests.cpp b/Release/tests/functional/json/negative_parsing_tests.cpp index 33a678ab16..ef99cc5cb7 100644 --- a/Release/tests/functional/json/negative_parsing_tests.cpp +++ b/Release/tests/functional/json/negative_parsing_tests.cpp @@ -147,8 +147,7 @@ SUITE(negative_parsing_tests) verify_json_throws(stream); } -// Test using Windows only API. -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) TEST(wstream_left_over_chars) { std::wstringbuf buf; diff --git a/Release/tests/functional/json/parsing_tests.cpp b/Release/tests/functional/json/parsing_tests.cpp index cf5a261bf0..08d9be9315 100644 --- a/Release/tests/functional/json/parsing_tests.cpp +++ b/Release/tests/functional/json/parsing_tests.cpp @@ -649,7 +649,7 @@ SUITE(parsing_tests) TEST(non_default_locale, "Ignore:Android", "Locale unsupported on Android") { std::string originalLocale = setlocale(LC_ALL, nullptr); -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) std::string changedLocale("fr-FR"); #else std::string changedLocale("fr_FR.utf8"); @@ -718,7 +718,7 @@ SUITE(parsing_tests) error_code_helper(arrayStringStream); error_code_helper(objStringStream); -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) std::wstringbuf buf; buf.sputn(valueStr.c_str(), valueStr.size()); @@ -752,7 +752,7 @@ SUITE(parsing_tests) VERIFY_IS_TRUE(streamErr.value() > 0); VERIFY_IS_TRUE(parsedObject.is_null()); -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) std::wstringbuf buf; buf.sputn(str.c_str(), str.size()); std::wistream iStream(&buf); diff --git a/Release/tests/functional/json/to_as_and_operators_tests.cpp b/Release/tests/functional/json/to_as_and_operators_tests.cpp index 6103adf6a4..797dbe15b0 100644 --- a/Release/tests/functional/json/to_as_and_operators_tests.cpp +++ b/Release/tests/functional/json/to_as_and_operators_tests.cpp @@ -499,7 +499,7 @@ SUITE(to_as_and_operators_tests) value.serialize(ss); VERIFY_ARE_EQUAL(len, ss.str().length()); -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) // Check wide string implementation std::basic_stringstream wss; value.serialize(wss); diff --git a/Release/tests/functional/pplx/pplx_test/CMakeLists.txt b/Release/tests/functional/pplx/pplx_test/CMakeLists.txt index 0e2672b73e..a0d92f42e6 100644 --- a/Release/tests/functional/pplx/pplx_test/CMakeLists.txt +++ b/Release/tests/functional/pplx/pplx_test/CMakeLists.txt @@ -4,7 +4,7 @@ set(SOURCES pplxtask_tests.cpp ) -add_casablanca_test(pplx_test SOURCES) +add_casablanca_test(pplx_test SOURCES cpprest_pplx) if(MSVC) get_target_property(_srcs pplx_test SOURCES) diff --git a/Release/tests/functional/streams/CMakeLists.txt b/Release/tests/functional/streams/CMakeLists.txt index 29d09bbac8..7b16ed8466 100644 --- a/Release/tests/functional/streams/CMakeLists.txt +++ b/Release/tests/functional/streams/CMakeLists.txt @@ -14,7 +14,7 @@ else() endif() endif() -add_casablanca_test(streams_test SOURCES) +add_casablanca_test(streams_test SOURCES cpprest_streams) if(NOT WIN32 OR CPPREST_WEBSOCKETS_IMPL STREQUAL "wspp") cpprest_find_boost() if(NOT TEST_LIBRARY_TARGET_TYPE STREQUAL "OBJECT") diff --git a/Release/tests/functional/streams/fstreambuf_tests.cpp b/Release/tests/functional/streams/fstreambuf_tests.cpp index 190eb66b0c..ea8902d4ba 100644 --- a/Release/tests/functional/streams/fstreambuf_tests.cpp +++ b/Release/tests/functional/streams/fstreambuf_tests.cpp @@ -39,7 +39,7 @@ using namespace ::pplx; utility::string_t get_full_name(const utility::string_t& name); void fill_file(const utility::string_t& name, size_t repetitions = 1); -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) void fill_file_w(const utility::string_t& name, size_t repetitions = 1); #endif @@ -179,7 +179,7 @@ SUITE(file_buffer_tests) VERIFY_IS_TRUE(close.is_done()); VERIFY_IS_FALSE(stream.is_open()); } -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) TEST(WriteSingleCharTest1w) { auto open = OPEN_W(U("WriteSingleCharTest1w.txt")); @@ -227,7 +227,7 @@ SUITE(file_buffer_tests) VERIFY_IS_TRUE(close.is_done()); VERIFY_IS_FALSE(stream.is_open()); } -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) TEST(WriteBufferTest1w) { auto open = OPEN_W(U("WriteBufferTest1w.txt")); @@ -345,7 +345,7 @@ SUITE(file_buffer_tests) t[i].wait(); } -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) TEST(ReadSingleChar_bumpcw) { utility::string_t fname = U("ReadSingleChar_bumpcw.txt"); @@ -467,7 +467,7 @@ SUITE(file_buffer_tests) VERIFY_IS_FALSE(stream.is_open()); } -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) TEST(ReadSingleChar_nextcw) { utility::string_t fname = U("ReadSingleChar_nextcw.txt"); @@ -558,7 +558,7 @@ SUITE(file_buffer_tests) VERIFY_IS_FALSE(stream.is_open()); } -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) TEST(ReadSingleChar_getc1w) { utility::string_t fname = U("ReadSingleChar_getc1w.txt"); @@ -669,7 +669,7 @@ SUITE(file_buffer_tests) VERIFY_IS_FALSE(stream.is_open()); } -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) TEST(ReadBuffer1w) { // Test that seeking works. @@ -881,7 +881,7 @@ SUITE(file_buffer_tests) VERIFY_ARE_EQUAL(istream.size(), 2600); } -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) TEST(file_size_w) { utility::string_t fname = U("file_size_w.txt"); @@ -912,9 +912,8 @@ SUITE(file_buffer_tests) TEST(read_one_byte_at_4G) { // Create a file with one byte. - string_t filename = U("read_one_byte_at_4G.txt"); // create a sparse file with sparse file apis - auto handle = CreateSparseFile(filename.c_str()); + auto handle = CreateSparseFile(TEXT("read_one_byte_at_4G.txt")); VERIFY_ARE_NOT_EQUAL(handle, INVALID_HANDLE_VALUE); // write 1 byte @@ -930,7 +929,7 @@ SUITE(file_buffer_tests) CloseHandle(handle); // read the file with casablanca streams - concurrency::streams::streambuf file_buf = OPEN(filename, std::ios_base::in).get(); + concurrency::streams::streambuf file_buf = OPEN(U("read_one_byte_at_4G.txt"), std::ios_base::in).get(); file_buf.seekoff(4 * 1024 * 1024 * 1024ll, ::std::ios_base::beg, ::std::ios_base::in); int aCharacter = file_buf.getc().get(); diff --git a/Release/tests/functional/streams/istream_tests.cpp b/Release/tests/functional/streams/istream_tests.cpp index 32cb545aa2..1067120967 100644 --- a/Release/tests/functional/streams/istream_tests.cpp +++ b/Release/tests/functional/streams/istream_tests.cpp @@ -69,7 +69,7 @@ void fill_file_with_lines(const utility::string_t& name, const std::string& end, stream << "abcdefghijklmnopqrstuvwxyz" << end; } -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) // Disabling warning in test because we check for nullptr. #pragma warning(push) @@ -820,7 +820,7 @@ SUITE(istream_tests) VERIFY_ARE_EQUAL(str1, "abc"); VERIFY_ARE_EQUAL(str2, "defgsf"); } -#ifdef _WIN32 // On Linux, this becomes the exact copy of istream_extract_string1, hence disabled +#if defined(_UTF16_STRINGS) TEST(istream_extract_wstring_1) { producer_consumer_buffer rbuf; @@ -905,7 +905,7 @@ SUITE(istream_tests) VERIFY_ARE_EQUAL(i1, 1024); VERIFY_ARE_EQUAL(i2, (uint64_t)12000000000); } -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) TEST(istream_extract_int64w) { producer_consumer_buffer rbuf; @@ -972,7 +972,7 @@ SUITE(istream_tests) VERIFY_ARE_EQUAL(i2, (uint32_t)3000000000); VERIFY_THROWS(is.extract().get(), std::range_error); } -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) TEST(istream_extract_int32w) { producer_consumer_buffer rbuf; @@ -1042,7 +1042,7 @@ SUITE(istream_tests) VERIFY_THROWS(is.extract().get(), std::range_error); } -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) TEST(istream_extract_int16w) { producer_consumer_buffer rbuf; @@ -1110,7 +1110,7 @@ SUITE(istream_tests) VERIFY_ARE_EQUAL(i2, '1'); } -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) TEST(istream_extract_int8w) { producer_consumer_buffer rbuf; @@ -1181,7 +1181,7 @@ SUITE(istream_tests) VERIFY_THROWS(is.extract().get(), std::runtime_error); } -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) TEST(istream_extract_bool_w) { producer_consumer_buffer rbuf; @@ -1237,7 +1237,7 @@ SUITE(istream_tests) { istream_extract_long_impl( container_buffer("123 -567 120000000000000000000000000000000000000000000000")); -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) istream_extract_long_impl(container_buffer(L"123 -567 12000000000")); #endif } @@ -1257,7 +1257,7 @@ SUITE(istream_tests) TEST(istream_extract_unsigned_long) { istream_extract_unsigned_long_impl(container_buffer("876 3 -44")); -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) istream_extract_unsigned_long_impl(container_buffer(L"876 3 -44")); #endif } @@ -1265,7 +1265,7 @@ SUITE(istream_tests) TEST(istream_extract_long_long) { istream_extract_long_impl(container_buffer("123 -567 92233720368547758078")); -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) istream_extract_long_impl(container_buffer(L"123 -567 92233720368547758078")); #endif } @@ -1273,7 +1273,7 @@ SUITE(istream_tests) TEST(istream_extract_unsigned_long_long) { istream_extract_unsigned_long_impl(container_buffer("876 3 -44")); -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) istream_extract_unsigned_long_impl(container_buffer(L"876 3 -44")); #endif } @@ -1555,7 +1555,7 @@ SUITE(istream_tests) const std::string strValue = inStream.extract().get(); VERIFY_ARE_EQUAL("", strValue); -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) const std::wstring wstrValue = inStream.extract().get(); VERIFY_ARE_EQUAL(L"", wstrValue); #endif diff --git a/Release/tests/functional/utils/CMakeLists.txt b/Release/tests/functional/utils/CMakeLists.txt index 201af77039..b3fa2dc7d6 100644 --- a/Release/tests/functional/utils/CMakeLists.txt +++ b/Release/tests/functional/utils/CMakeLists.txt @@ -7,7 +7,7 @@ set(SOURCES win32_encryption_tests.cpp ) -add_casablanca_test(utils_test SOURCES) +add_casablanca_test(utils_test SOURCES cpprest_utilities) if(CMAKE_COMPILER_IS_GNUCXX) target_compile_options(utils_test PRIVATE "-Wno-deprecated-declarations") diff --git a/Release/tests/functional/utils/base64.cpp b/Release/tests/functional/utils/base64.cpp index 30ec199ef2..70225d24eb 100644 --- a/Release/tests/functional/utils/base64.cpp +++ b/Release/tests/functional/utils/base64.cpp @@ -13,6 +13,8 @@ #include "stdafx.h" +#include "cpprest/base64_utils.h" + using namespace utility; namespace tests diff --git a/Release/tests/functional/utils/macro_test.cpp b/Release/tests/functional/utils/macro_test.cpp index f45bc9f237..c27f0a29ed 100644 --- a/Release/tests/functional/utils/macro_test.cpp +++ b/Release/tests/functional/utils/macro_test.cpp @@ -15,6 +15,7 @@ #include "cpprest/http_client.h" #include "cpprest/http_msg.h" #include "cpprest/json.h" +#include "cpprest/uri.h" #include "cpprest/uri_builder.h" namespace tests diff --git a/Release/tests/functional/utils/nonce_generator_tests.cpp b/Release/tests/functional/utils/nonce_generator_tests.cpp index 92c4ea0f6c..99cf45fc93 100644 --- a/Release/tests/functional/utils/nonce_generator_tests.cpp +++ b/Release/tests/functional/utils/nonce_generator_tests.cpp @@ -13,6 +13,8 @@ #include "stdafx.h" +#include + using namespace utility; namespace tests diff --git a/Release/tests/functional/utils/stdafx.h b/Release/tests/functional/utils/stdafx.h index 40eb75f5a0..7f53de66f3 100644 --- a/Release/tests/functional/utils/stdafx.h +++ b/Release/tests/functional/utils/stdafx.h @@ -16,6 +16,5 @@ #include "cpprest/asyncrt_utils.h" #include "cpprest/details/web_utilities.h" -#include "cpprest/uri.h" #include "unittestpp.h" #include "utils_tests.h" diff --git a/Release/tests/functional/utils/strings.cpp b/Release/tests/functional/utils/strings.cpp index 261714333d..a754a8e4d8 100644 --- a/Release/tests/functional/utils/strings.cpp +++ b/Release/tests/functional/utils/strings.cpp @@ -333,7 +333,7 @@ SUITE(strings) std::locale changedLocale; try { -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) changedLocale = std::locale("fr-FR"); #else changedLocale = std::locale("fr_FR.UTF-8"); @@ -358,7 +358,7 @@ SUITE(strings) std::locale changedLocale; try { -#ifdef _WIN32 +#if defined(_UTF16_STRINGS) changedLocale = std::locale("fr-FR"); #else changedLocale = std::locale("fr_FR.UTF-8"); diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 8c878f0901..7b7aa47253 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -65,6 +65,27 @@ jobs: cd build.common\Release\Binaries\Release .\test_runner.exe *test.dll displayName: 'Run tests, release' + - script: mkdir build.isolated + displayName: Make Isolated Build Directory + - task: CMake@1 + inputs: + workingDirectory: 'build.isolated' + cmakeArgs: '-A x64 -DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake -DCPPREST_EXCLUDE_BROTLI=OFF -DCPPREST_ISOLATE_COMPONENTS=ON ..' + - task: MSBuild@1 + inputs: + solution: 'build.isolated/ALL_BUILD.vcxproj' + maximumCpuCount: true + platform: 'x64' + - script: | + cd build.isolated\Release\Binaries\Debug + .\test_runner.exe *testd.dll + displayName: 'Run isolated tests, debug' + - task: MSBuild@1 + inputs: + solution: 'build.isolated/ALL_BUILD.vcxproj' + maximumCpuCount: true + platform: 'x64' + configuration: 'Release' - job: Windows_VS2017_UWP pool: vmImage: 'vs2017-win2016' @@ -166,13 +187,43 @@ jobs: cd build.release /usr/local/bin/cmake -G Ninja -DCMAKE_BUILD_TYPE=Release .. cd .. + mkdir build.debug.isolated + cd build.debug.isolated + /usr/local/bin/cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug -DCPPREST_ISOLATE_COMPONENTS=ON .. + cd .. + mkdir build.release.isolated + cd build.release.isolated + /usr/local/bin/cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DCPPREST_ISOLATE_COMPONENTS=ON .. + cd .. + displayName: Run build generate + - script: | ninja -C build.debug + displayName: 'Run ninja, debug' + - script: | ninja -C build.release + displayName: 'Run ninja, release' + - script: | + ninja -C build.debug.isolated + displayName: 'Run ninja, isolated debug' + - script: | + ninja -C build.release.isolated + displayName: 'Run ninja, isolated release' + - script: | cd build.debug/Release/Binaries ./test_runner *test.so - cd ../../../build.release/Release/Binaries + displayName: 'Run tests, debug' + - script: | + cd build.release/Release/Binaries + ./test_runner *test.so + displayName: 'Run tests, release' + - script: | + cd build.debug.isolated/Release/Binaries ./test_runner *test.so - displayName: Run build + displayName: 'Run tests, isolated debug' + - script: | + cd build.release.isolated/Release/Binaries + ./test_runner *test.so + displayName: 'Run tests, isolated release' - job: Ubuntu_1604_Vcpkg pool: vmImage: 'Ubuntu 16.04' @@ -196,6 +247,14 @@ jobs: inputs: workingDirectory: 'build.release' cmakeArgs: '-G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake ..' + - task: CMake@1 + inputs: + workingDirectory: 'build.debug.isolated' + cmakeArgs: '-G Ninja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake ..' + - task: CMake@1 + inputs: + workingDirectory: 'build.release.isolated' + cmakeArgs: '-G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake ..' - script: | cd build.debug ninja @@ -212,6 +271,22 @@ jobs: cd build.release/Release/Binaries ./test_runner *test.so displayName: 'Run tests, release' + - script: | + cd build.debug.isolated + ninja + displayName: 'Run ninja, isolated debug' + - script: | + cd build.debug.isolated/Release/Binaries + ./test_runner *test.so + displayName: 'Run Tests, isolated debug' + - script: | + cd build.release.isolated + ninja + displayName: 'Run ninja, isolated release' + - script: | + cd build.release.isolated/Release/Binaries + ./test_runner *test.so + displayName: 'Run tests, isolated release' - job: Android pool: vmImage: 'Ubuntu 16.04'