From 363168a6f431693001fe6b7e7bb3c8434643f0ed Mon Sep 17 00:00:00 2001 From: Jason Hartman Date: Wed, 10 Jul 2019 11:00:43 -0700 Subject: [PATCH 01/19] add option to directly support narrow strings on win32 independent of UNICODE vs MBCS setting Set CPPREST_FORCE_NARROW_STRINGS=ON to enable. Simplistic cleanup throughout project is not possible as some Windows APIs require utf16 such as HTTPSPolicyCallbackData in http_client_winhttp.cpp. HTTP related code is not completely updated so a full package may not be produced, though settings exist to have a clean build. Use: -DCPPREST_FORCE_NARROW_STRING=ON -DCPPREST_EXCLUDE_WEBSOCKETS=ON -DCPPREST_HTTP_LISTENER_IMPL=none -DBUILD_SAMPLES=OFF --- .gitignore | 1 + Release/CMakeLists.txt | 23 +++++++++++++ Release/include/cpprest/details/basic_types.h | 4 +-- .../include/cpprest/details/web_utilities.h | 4 +-- Release/include/cpprest/http_msg.h | 10 +++--- Release/include/cpprest/json.h | 32 +++++++++---------- Release/samples/Oauth1Client/Oauth1Client.cpp | 2 +- Release/samples/Oauth2Client/Oauth2Client.cpp | 2 +- Release/samples/SearchFile/searchfile.cpp | 4 +-- Release/src/CMakeLists.txt | 19 +++++++---- Release/src/http/common/http_msg.cpp | 2 +- Release/src/http/oauth/oauth1.cpp | 4 +-- Release/src/json/json.cpp | 2 +- Release/src/json/json_parsing.cpp | 14 ++++++-- Release/src/json/json_serialization.cpp | 6 ++-- Release/src/streams/fileio_win32.cpp | 2 +- Release/src/utilities/web_utilities.cpp | 18 +++++------ Release/tests/functional/CMakeLists.txt | 8 ++++- Release/tests/functional/json/fuzz_tests.cpp | 17 ++++++---- .../functional/json/json_numbers_tests.cpp | 2 +- .../json/negative_parsing_tests.cpp | 3 +- .../tests/functional/json/parsing_tests.cpp | 6 ++-- .../json/to_as_and_operators_tests.cpp | 2 +- .../functional/streams/fstreambuf_tests.cpp | 21 ++++++------ .../functional/streams/istream_tests.cpp | 24 +++++++------- Release/tests/functional/utils/strings.cpp | 4 +-- 26 files changed, 142 insertions(+), 94 deletions(-) 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..65d2114063 100644 --- a/Release/CMakeLists.txt +++ b/Release/CMakeLists.txt @@ -20,6 +20,7 @@ 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.") @@ -112,9 +113,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 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..cc96662333 100644 --- a/Release/include/cpprest/details/web_utilities.h +++ b/Release/include/cpprest/details/web_utilities.h @@ -31,7 +31,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 +42,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/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..60a18f7df0 100644 --- a/Release/include/cpprest/json.h +++ b/Release/include/cpprest/json.h @@ -275,7 +275,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 +436,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 +643,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 +677,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. /// @@ -1366,7 +1366,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 +1400,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 +1438,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 +1462,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 +1479,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 +1497,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 +1538,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 +1573,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 +1585,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 +1682,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 +1694,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/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..425d7f731a 100644 --- a/Release/src/CMakeLists.txt +++ b/Release/src/CMakeLists.txt @@ -15,6 +15,16 @@ set(SOURCES ${HEADERS_PPLX} ${HEADERS_DETAILS} pch/stdafx.h + json/json.cpp + json/json_parsing.cpp + json/json_serialization.cpp + utilities/asyncrt_utils.cpp + utilities/base64.cpp + utilities/web_utilities.cpp +) + +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,15 +39,10 @@ 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() add_library(cpprest ${SOURCES}) target_include_directories(cpprest @@ -125,6 +130,7 @@ else() endif() # 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,6 +151,7 @@ elseif(CPPREST_HTTP_CLIENT_IMPL STREQUAL "winrt") else() message(FATAL_ERROR "Invalid implementation") endif() +endif() # fileio streams component if(CPPREST_FILEIO_IMPL STREQUAL "win32") 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/json/json.cpp b/Release/src/json/json.cpp index 7614866acc..ae640ae26d 100644 --- a/Release/src/json/json.cpp +++ b/Release/src/json/json.cpp @@ -195,7 +195,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..2e0d71e6d3 100644 --- a/Release/src/json/json_parsing.cpp +++ b/Release/src/json/json_parsing.cpp @@ -356,24 +356,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) { @@ -1166,7 +1174,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 +1277,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..83c1086e1f 100644 --- a/Release/src/json/json_serialization.cpp +++ b/Release/src/json/json_serialization.cpp @@ -29,7 +29,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 +119,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 +190,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/streams/fileio_win32.cpp b/Release/src/streams/fileio_win32.cpp index 97cd6e5e6d..129fd991de 100644 --- a/Release/src/streams/fileio_win32.cpp +++ b/Release/src/streams/fileio_win32.cpp @@ -228,7 +228,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/web_utilities.cpp b/Release/src/utilities/web_utilities.cpp index ce00078b79..67d15a343b 100644 --- a/Release/src/utilities/web_utilities.cpp +++ b/Release/src/utilities/web_utilities.cpp @@ -47,15 +47,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 +84,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 +99,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 +125,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/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/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/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/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"); From 35744556eb6261a777c365c579d744286874d3e1 Mon Sep 17 00:00:00 2001 From: Jason Hartman Date: Fri, 19 Jul 2019 12:11:06 -0700 Subject: [PATCH 02/19] refactor strings_utils from asyncrt_utils --- Release/include/cpprest/{asyncrt_utils.h => string_utils.h} | 0 Release/src/utilities/{asyncrt_utils.cpp => string_utils.cpp} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename Release/include/cpprest/{asyncrt_utils.h => string_utils.h} (100%) rename Release/src/utilities/{asyncrt_utils.cpp => string_utils.cpp} (100%) diff --git a/Release/include/cpprest/asyncrt_utils.h b/Release/include/cpprest/string_utils.h similarity index 100% rename from Release/include/cpprest/asyncrt_utils.h rename to Release/include/cpprest/string_utils.h diff --git a/Release/src/utilities/asyncrt_utils.cpp b/Release/src/utilities/string_utils.cpp similarity index 100% rename from Release/src/utilities/asyncrt_utils.cpp rename to Release/src/utilities/string_utils.cpp From be44557e410ff9c694700b5145f11aa82a962ca4 Mon Sep 17 00:00:00 2001 From: Jason Hartman Date: Fri, 19 Jul 2019 12:14:29 -0700 Subject: [PATCH 03/19] temp rename asyncrt_utils for split preserving history --- .../cpprest/{asyncrt_utils.h => asyncrt_utils-temp_rename.h} | 0 .../{asyncrt_utils.cpp => asyncrt_utils-temp_rename.cpp} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename Release/include/cpprest/{asyncrt_utils.h => asyncrt_utils-temp_rename.h} (100%) rename Release/src/utilities/{asyncrt_utils.cpp => asyncrt_utils-temp_rename.cpp} (100%) diff --git a/Release/include/cpprest/asyncrt_utils.h b/Release/include/cpprest/asyncrt_utils-temp_rename.h similarity index 100% rename from Release/include/cpprest/asyncrt_utils.h rename to Release/include/cpprest/asyncrt_utils-temp_rename.h diff --git a/Release/src/utilities/asyncrt_utils.cpp b/Release/src/utilities/asyncrt_utils-temp_rename.cpp similarity index 100% rename from Release/src/utilities/asyncrt_utils.cpp rename to Release/src/utilities/asyncrt_utils-temp_rename.cpp From 926f4310ac9735cd424e091072cc2ef1d874cd02 Mon Sep 17 00:00:00 2001 From: Jason Hartman Date: Fri, 19 Jul 2019 13:47:10 -0700 Subject: [PATCH 04/19] refactor memory_utils from asyncrt_utils --- Release/include/cpprest/{asyncrt_utils.h => memory_utils.h} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Release/include/cpprest/{asyncrt_utils.h => memory_utils.h} (100%) diff --git a/Release/include/cpprest/asyncrt_utils.h b/Release/include/cpprest/memory_utils.h similarity index 100% rename from Release/include/cpprest/asyncrt_utils.h rename to Release/include/cpprest/memory_utils.h From 2479267f1593f7ca8dae4b8dbeb647fc337ad908 Mon Sep 17 00:00:00 2001 From: Jason Hartman Date: Fri, 19 Jul 2019 16:41:31 -0700 Subject: [PATCH 05/19] breakout pieces of asyncrt_utils enabling custom building of select components like just json support extractions from asyncrt_utils.h: base64_utils.h (to/form base64) memory_utils.h (details::make_unique) string_utils.cpp (string utils) asyncrt_utils retains error, date-time, and nounce utils --- Release/include/cpprest/asyncrt_utils.h | 432 +------- Release/include/cpprest/base64_utils.h | 43 + Release/include/cpprest/filestream.h | 1 + Release/include/cpprest/http_listener.h | 1 + Release/include/cpprest/json.h | 7 +- Release/include/cpprest/memory_utils.h | 618 +---------- Release/include/cpprest/oauth1.h | 2 + Release/include/cpprest/string_utils.h | 312 +----- Release/src/CMakeLists.txt | 1 + Release/src/pch/stdafx.h | 3 + ...tils-temp_rename.cpp => asyncrt_utils.cpp} | 503 +-------- Release/src/utilities/base64.cpp | 5 +- Release/src/utilities/string_utils.cpp | 967 +----------------- Release/tests/functional/utils/base64.cpp | 2 + 14 files changed, 72 insertions(+), 2825 deletions(-) create mode 100644 Release/include/cpprest/base64_utils.h rename Release/src/utilities/{asyncrt_utils-temp_rename.cpp => asyncrt_utils.cpp} (61%) 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/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_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/json.h b/Release/include/cpprest/json.h index 60a18f7df0..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 @@ -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); } } diff --git a/Release/include/cpprest/memory_utils.h b/Release/include/cpprest/memory_utils.h index a38702f412..20fff2b250 100644 --- a/Release/include/cpprest/memory_utils.h +++ b/Release/include/cpprest/memory_utils.h @@ -4,7 +4,7 @@ * * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ * - * Various common utilities. + * Memory utilities. * * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk * @@ -13,365 +13,15 @@ #pragma once -#include "cpprest/details/basic_types.h" -#include "pplx/pplxtasks.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 +#include +#include /// Various utilities for string conversions and date and time manipulation. namespace utility { -// Left over from VS2010 support, remains to avoid breaking. -typedef std::chrono::seconds seconds; - -/// Functions for converting to/from std::chrono::seconds to xml string. -namespace timespan -{ -/// -/// Converts a timespan/interval in seconds to xml duration string as specified by -/// http://www.w3.org/TR/xmlschema-2/#duration -/// -_ASYNCRTIMP utility::string_t __cdecl seconds_to_xml_duration(utility::seconds numSecs); - -/// -/// Converts an xml duration to timespan/interval in seconds -/// http://www.w3.org/TR/xmlschema-2/#duration -/// -_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 @@ -430,268 +80,6 @@ std::unique_ptr<_Type> make_unique(_Arg1&& arg1, _Arg2&& arg2, _Arg3&& arg3, _Ar 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 - -/// -/// Category error type for Windows OS errors. -/// -class windows_category_impl : public std::error_category -{ -public: - virtual const char* name() const CPPREST_NOEXCEPT { return "windows"; } - - virtual std::string message(int errorCode) const CPPREST_NOEXCEPT; - - virtual std::error_condition default_error_condition(int errorCode) const CPPREST_NOEXCEPT; -}; - -/// -/// Gets the one global instance of the windows error category. -/// -/// An error category instance. -_ASYNCRTIMP const std::error_category& __cdecl windows_category(); - -#else - -/// -/// Gets the one global instance of the linux error category. -/// -/// An error category instance. -_ASYNCRTIMP const std::error_category& __cdecl linux_category(); - -#endif - -/// -/// Gets the one global instance of the current platform's error category. -/// -_ASYNCRTIMP const std::error_category& __cdecl platform_category(); - -/// -/// Creates an instance of std::system_error from a OS error code. -/// -inline std::system_error __cdecl create_system_error(unsigned long errorCode) -{ - std::error_code code((int)errorCode, platform_category()); - return std::system_error(code, code.message()); -} - -/// -/// Creates a std::error_code from a OS error code. -/// -inline std::error_code __cdecl create_error_code(unsigned long errorCode) -{ - return std::error_code((int)errorCode, platform_category()); -} - -/// -/// Creates the corresponding error message from a OS error code. -/// -inline utility::string_t __cdecl create_error_message(unsigned long errorCode) -{ - return utility::conversions::to_string_t(create_error_code(errorCode).message()); -} - } // namespace details -class datetime -{ -public: - typedef uint64_t interval_type; - - /// - /// Defines the supported date and time string formats. - /// - enum date_format - { - RFC_1123, - ISO_8601 - }; - - /// - /// Returns the current UTC time. - /// - static _ASYNCRTIMP datetime __cdecl utc_now(); - - /// - /// An invalid UTC timestamp value. - /// - enum : interval_type - { - utc_timestamp_invalid = static_cast(-1) - }; - - /// - /// Returns seconds since Unix/POSIX time epoch at 01-01-1970 00:00:00. - /// If time is before epoch, utc_timestamp_invalid is returned. - /// - static interval_type utc_timestamp() - { - const auto seconds = utc_now().to_interval() / _secondTicks; - if (seconds >= 11644473600LL) - { - return seconds - 11644473600LL; - } - else - { - return utc_timestamp_invalid; - } - } - - datetime() : m_interval(0) {} - - /// - /// Creates datetime from a string representing time in UTC in RFC 1123 format. - /// - /// Returns a datetime of zero if not successful. - static _ASYNCRTIMP datetime __cdecl from_string(const utility::string_t& timestring, date_format format = RFC_1123); - - /// - /// Returns a string representation of the datetime. - /// - _ASYNCRTIMP utility::string_t to_string(date_format format = RFC_1123) const; - - /// - /// Returns the integral time value. - /// - interval_type to_interval() const { return m_interval; } - - datetime operator-(interval_type value) const { return datetime(m_interval - value); } - - datetime operator+(interval_type value) const { return datetime(m_interval + value); } - - bool operator==(datetime dt) const { return m_interval == dt.m_interval; } - - bool operator!=(const datetime& dt) const { return !(*this == dt); } - - static interval_type from_milliseconds(unsigned int milliseconds) { return milliseconds * _msTicks; } - - static interval_type from_seconds(unsigned int seconds) { return seconds * _secondTicks; } - - static interval_type from_minutes(unsigned int minutes) { return minutes * _minuteTicks; } - - static interval_type from_hours(unsigned int hours) { return hours * _hourTicks; } - - static interval_type from_days(unsigned int days) { return days * _dayTicks; } - - bool is_initialized() const { return m_interval != 0; } - -private: - friend int operator-(datetime t1, datetime t2); - - static const interval_type _msTicks = static_cast(10000); - static const interval_type _secondTicks = 1000 * _msTicks; - static const interval_type _minuteTicks = 60 * _secondTicks; - static const interval_type _hourTicks = 60 * 60 * _secondTicks; - static const interval_type _dayTicks = 24 * 60 * 60 * _secondTicks; - - // Private constructor. Use static methods to create an instance. - datetime(interval_type interval) : m_interval(interval) {} - - // Storing as hundreds of nanoseconds 10e-7, i.e. 1 here equals 100ns. - interval_type m_interval; -}; - -inline int operator-(datetime t1, datetime t2) -{ - auto diff = (t1.m_interval - t2.m_interval); - - // Round it down to seconds - diff /= 10 * 1000 * 1000; - - return static_cast(diff); -} - -/// -/// Nonce string generator class. -/// -class nonce_generator -{ -public: - /// - /// Define default nonce length. - /// - enum - { - default_length = 32 - }; - - /// - /// Nonce generator constructor. - /// - /// Length of the generated nonce string. - nonce_generator(int length = default_length) - : m_random(static_cast(utility::datetime::utc_timestamp())), m_length(length) - { - } - - /// - /// Generate a nonce string containing random alphanumeric characters (A-Za-z0-9). - /// Length of the generated string is set by length(). - /// - /// The generated nonce string. - _ASYNCRTIMP utility::string_t generate(); - - /// - /// Get length of generated nonce string. - /// - /// Nonce string length. - int length() const { return m_length; } - - /// - /// Set length of the generated nonce string. - /// - /// Lenght of nonce string. - void set_length(int length) { m_length = length; } - -private: - std::mt19937 m_random; - int m_length; -}; - } // 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 index a38702f412..5761aa9018 100644 --- a/Release/include/cpprest/string_utils.h +++ b/Release/include/cpprest/string_utils.h @@ -4,7 +4,7 @@ * * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ * - * Various common utilities. + * String utilities. * * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk * @@ -14,14 +14,10 @@ #pragma once #include "cpprest/details/basic_types.h" -#include "pplx/pplxtasks.h" -#include #include #include #include -#include #include -#include #include #ifndef _WIN32 @@ -37,25 +33,6 @@ /// Various utilities for string conversions and date and time manipulation. namespace utility { -// Left over from VS2010 support, remains to avoid breaking. -typedef std::chrono::seconds seconds; - -/// Functions for converting to/from std::chrono::seconds to xml string. -namespace timespan -{ -/// -/// Converts a timespan/interval in seconds to xml duration string as specified by -/// http://www.w3.org/TR/xmlschema-2/#duration -/// -_ASYNCRTIMP utility::string_t __cdecl seconds_to_xml_duration(utility::seconds numSecs); - -/// -/// Converts an xml duration to timespan/interval in seconds -/// http://www.w3.org/TR/xmlschema-2/#duration -/// -_ASYNCRTIMP utility::seconds __cdecl xml_duration_to_seconds(const utility::string_t& timespanString); -} // namespace timespan - /// Functions for Unicode string conversions. namespace conversions { @@ -178,21 +155,6 @@ inline const std::string& to_utf8string(const std::string& value) { return value /// 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.") @@ -373,62 +335,6 @@ inline bool __cdecl is_alnum(Elem ch) CPPREST_NOEXCEPT 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. @@ -476,222 +382,6 @@ _ASYNCRTIMP void __cdecl inplace_tolower(std::string& target) CPPREST_NOEXCEPT; /// The string to convert to lowercase. _ASYNCRTIMP void __cdecl inplace_tolower(std::wstring& target) CPPREST_NOEXCEPT; -#ifdef _WIN32 - -/// -/// Category error type for Windows OS errors. -/// -class windows_category_impl : public std::error_category -{ -public: - virtual const char* name() const CPPREST_NOEXCEPT { return "windows"; } - - virtual std::string message(int errorCode) const CPPREST_NOEXCEPT; - - virtual std::error_condition default_error_condition(int errorCode) const CPPREST_NOEXCEPT; -}; - -/// -/// Gets the one global instance of the windows error category. -/// -/// An error category instance. -_ASYNCRTIMP const std::error_category& __cdecl windows_category(); - -#else - -/// -/// Gets the one global instance of the linux error category. -/// -/// An error category instance. -_ASYNCRTIMP const std::error_category& __cdecl linux_category(); - -#endif - -/// -/// Gets the one global instance of the current platform's error category. -/// -_ASYNCRTIMP const std::error_category& __cdecl platform_category(); - -/// -/// Creates an instance of std::system_error from a OS error code. -/// -inline std::system_error __cdecl create_system_error(unsigned long errorCode) -{ - std::error_code code((int)errorCode, platform_category()); - return std::system_error(code, code.message()); -} - -/// -/// Creates a std::error_code from a OS error code. -/// -inline std::error_code __cdecl create_error_code(unsigned long errorCode) -{ - return std::error_code((int)errorCode, platform_category()); -} - -/// -/// Creates the corresponding error message from a OS error code. -/// -inline utility::string_t __cdecl create_error_message(unsigned long errorCode) -{ - return utility::conversions::to_string_t(create_error_code(errorCode).message()); -} - } // namespace details -class datetime -{ -public: - typedef uint64_t interval_type; - - /// - /// Defines the supported date and time string formats. - /// - enum date_format - { - RFC_1123, - ISO_8601 - }; - - /// - /// Returns the current UTC time. - /// - static _ASYNCRTIMP datetime __cdecl utc_now(); - - /// - /// An invalid UTC timestamp value. - /// - enum : interval_type - { - utc_timestamp_invalid = static_cast(-1) - }; - - /// - /// Returns seconds since Unix/POSIX time epoch at 01-01-1970 00:00:00. - /// If time is before epoch, utc_timestamp_invalid is returned. - /// - static interval_type utc_timestamp() - { - const auto seconds = utc_now().to_interval() / _secondTicks; - if (seconds >= 11644473600LL) - { - return seconds - 11644473600LL; - } - else - { - return utc_timestamp_invalid; - } - } - - datetime() : m_interval(0) {} - - /// - /// Creates datetime from a string representing time in UTC in RFC 1123 format. - /// - /// Returns a datetime of zero if not successful. - static _ASYNCRTIMP datetime __cdecl from_string(const utility::string_t& timestring, date_format format = RFC_1123); - - /// - /// Returns a string representation of the datetime. - /// - _ASYNCRTIMP utility::string_t to_string(date_format format = RFC_1123) const; - - /// - /// Returns the integral time value. - /// - interval_type to_interval() const { return m_interval; } - - datetime operator-(interval_type value) const { return datetime(m_interval - value); } - - datetime operator+(interval_type value) const { return datetime(m_interval + value); } - - bool operator==(datetime dt) const { return m_interval == dt.m_interval; } - - bool operator!=(const datetime& dt) const { return !(*this == dt); } - - static interval_type from_milliseconds(unsigned int milliseconds) { return milliseconds * _msTicks; } - - static interval_type from_seconds(unsigned int seconds) { return seconds * _secondTicks; } - - static interval_type from_minutes(unsigned int minutes) { return minutes * _minuteTicks; } - - static interval_type from_hours(unsigned int hours) { return hours * _hourTicks; } - - static interval_type from_days(unsigned int days) { return days * _dayTicks; } - - bool is_initialized() const { return m_interval != 0; } - -private: - friend int operator-(datetime t1, datetime t2); - - static const interval_type _msTicks = static_cast(10000); - static const interval_type _secondTicks = 1000 * _msTicks; - static const interval_type _minuteTicks = 60 * _secondTicks; - static const interval_type _hourTicks = 60 * 60 * _secondTicks; - static const interval_type _dayTicks = 24 * 60 * 60 * _secondTicks; - - // Private constructor. Use static methods to create an instance. - datetime(interval_type interval) : m_interval(interval) {} - - // Storing as hundreds of nanoseconds 10e-7, i.e. 1 here equals 100ns. - interval_type m_interval; -}; - -inline int operator-(datetime t1, datetime t2) -{ - auto diff = (t1.m_interval - t2.m_interval); - - // Round it down to seconds - diff /= 10 * 1000 * 1000; - - return static_cast(diff); -} - -/// -/// Nonce string generator class. -/// -class nonce_generator -{ -public: - /// - /// Define default nonce length. - /// - enum - { - default_length = 32 - }; - - /// - /// Nonce generator constructor. - /// - /// Length of the generated nonce string. - nonce_generator(int length = default_length) - : m_random(static_cast(utility::datetime::utc_timestamp())), m_length(length) - { - } - - /// - /// Generate a nonce string containing random alphanumeric characters (A-Za-z0-9). - /// Length of the generated string is set by length(). - /// - /// The generated nonce string. - _ASYNCRTIMP utility::string_t generate(); - - /// - /// Get length of generated nonce string. - /// - /// Nonce string length. - int length() const { return m_length; } - - /// - /// Set length of the generated nonce string. - /// - /// Lenght of nonce string. - void set_length(int length) { m_length = length; } - -private: - std::mt19937 m_random; - int m_length; -}; - } // namespace utility diff --git a/Release/src/CMakeLists.txt b/Release/src/CMakeLists.txt index 425d7f731a..79af527c73 100644 --- a/Release/src/CMakeLists.txt +++ b/Release/src/CMakeLists.txt @@ -20,6 +20,7 @@ set(SOURCES json/json_serialization.cpp utilities/asyncrt_utils.cpp utilities/base64.cpp + utilities/string_utils.cpp utilities/web_utilities.cpp ) diff --git a/Release/src/pch/stdafx.h b/Release/src/pch/stdafx.h index 2061bea7f6..372bc561ff 100644 --- a/Release/src/pch/stdafx.h +++ b/Release/src/pch/stdafx.h @@ -92,7 +92,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/utilities/asyncrt_utils-temp_rename.cpp b/Release/src/utilities/asyncrt_utils.cpp similarity index 61% rename from Release/src/utilities/asyncrt_utils-temp_rename.cpp rename to Release/src/utilities/asyncrt_utils.cpp index 5263c8d5d5..d16531ce7a 100644 --- a/Release/src/utilities/asyncrt_utils-temp_rename.cpp +++ b/Release/src/utilities/asyncrt_utils.cpp @@ -13,201 +13,17 @@ #include "stdafx.h" -#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; -} -#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 - namespace details { const std::error_category& __cdecl platform_category() @@ -302,321 +118,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) diff --git a/Release/src/utilities/base64.cpp b/Release/src/utilities/base64.cpp index 1cb235c3b5..89ccf43674 100644 --- a/Release/src/utilities/base64.cpp +++ b/Release/src/utilities/base64.cpp @@ -10,7 +10,10 @@ ****/ #include "stdafx.h" -using namespace web; +#include "cpprest/base64_utils.h" + +#include + using namespace utility; std::vector _from_base64(const utility::string_t& str); diff --git a/Release/src/utilities/string_utils.cpp b/Release/src/utilities/string_utils.cpp index 5263c8d5d5..51751f224d 100644 --- a/Release/src/utilities/string_utils.cpp +++ b/Release/src/utilities/string_utils.cpp @@ -13,13 +13,12 @@ #include "stdafx.h" -#include -#include +#include + +#include #include #include -#include -using namespace web; using namespace utility; using namespace utility::conversions; @@ -208,99 +207,6 @@ scoped_c_thread_locale::~scoped_c_thread_locale() #endif } // namespace details -namespace details -{ -const std::error_category& __cdecl platform_category() -{ -#ifdef _WIN32 - return windows_category(); -#else - return linux_category(); -#endif -} - -#ifdef _WIN32 - -// Remove once VS 2013 is no longer supported. -#if _MSC_VER < 1900 -static details::windows_category_impl instance; -#endif -const std::error_category& __cdecl windows_category() -{ -#if _MSC_VER >= 1900 - static details::windows_category_impl instance; -#endif - return instance; -} - -std::string windows_category_impl::message(int errorCode) const CPPREST_NOEXCEPT -{ - const size_t buffer_size = 4096; - DWORD dwFlags = FORMAT_MESSAGE_FROM_SYSTEM; - LPCVOID lpSource = NULL; - -#if !defined(__cplusplus_winrt) - if (errorCode >= 12000) - { - dwFlags = FORMAT_MESSAGE_FROM_HMODULE; - lpSource = GetModuleHandleA("winhttp.dll"); // this handle DOES NOT need to be freed - } -#endif - - std::wstring buffer(buffer_size, 0); - - const auto result = ::FormatMessageW(dwFlags, lpSource, errorCode, 0, &buffer[0], buffer_size, NULL); - - if (result == 0) - { - return "Unable to get an error message for error code: " + std::to_string(errorCode) + "."; - } - - // strip exceeding characters of the initial resize call - buffer.resize(result); - - return utility::conversions::to_utf8string(buffer); -} - -std::error_condition windows_category_impl::default_error_condition(int errorCode) const CPPREST_NOEXCEPT -{ - // First see if the STL implementation can handle the mapping for common cases. - const std::error_condition errCondition = std::system_category().default_error_condition(errorCode); - const std::string errConditionMsg = errCondition.message(); - if (!utility::details::str_iequal(errConditionMsg, "unknown error")) - { - return errCondition; - } - - switch (errorCode) - { -#ifndef __cplusplus_winrt - case ERROR_WINHTTP_TIMEOUT: return std::errc::timed_out; - case ERROR_WINHTTP_CANNOT_CONNECT: return std::errc::host_unreachable; - case ERROR_WINHTTP_CONNECTION_ERROR: return std::errc::connection_aborted; -#endif - case INET_E_RESOURCE_NOT_FOUND: - case INET_E_CANNOT_CONNECT: return std::errc::host_unreachable; - case INET_E_CONNECTION_TIMEOUT: return std::errc::timed_out; - case INET_E_DOWNLOAD_FAILURE: return std::errc::connection_aborted; - default: break; - } - - return std::error_condition(errorCode, *this); -} - -#else - -const std::error_category& __cdecl linux_category() -{ - // On Linux we are using boost error codes which have the exact same - // mapping and are equivalent with std::generic_category error codes. - return std::generic_category(); -} - -#endif - -} // namespace details #define LOW_3BITS 0x7 #define LOW_4BITS 0xF @@ -618,871 +524,4 @@ std::string __cdecl conversions::to_utf8string(const utf16string& value) { retur 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) - -static bool year_is_leap_year(int year) { return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)); } - -static const int SecondsInMinute = 60; -static const int SecondsInHour = SecondsInMinute * 60; -static const int SecondsInDay = SecondsInHour * 24; - -static const int DaysInYear = 365; -static const int DaysIn4Years = DaysInYear * 4 + 1; -static const int DaysIn100Years = DaysIn4Years * 25 - 1; -static const int DaysIn400Years = DaysIn100Years * 4 + 1; - -static const int SecondsInYear = SecondsInDay * DaysInYear; -static const int SecondsIn4Years = SecondsInDay * DaysIn4Years; -static const int64_t SecondsIn100Years = static_cast(SecondsInDay) * DaysIn100Years; -static const int64_t SecondsIn400Years = static_cast(SecondsInDay) * DaysIn400Years; -static const int64_t SecondsFrom1900To2001 = INT64_C(3187296000); - -static const int64_t NtTo1900OffsetInterval = INT64_C(0x014F373BFDE04000); - -static int count_leap_years(const int yearsSince1900) -{ - int tmpYears = yearsSince1900 + 299; // shift into 1601, the first 400 year cycle including 1900 - - int year400 = tmpYears / 400; - tmpYears -= year400 * 400; - int result = year400 * 97; - - int year100 = tmpYears / 100; - tmpYears -= year100 * 100; - result += year100 * 24; - - result += tmpYears / 4; - - // subtract off leap years from 1601 - result -= 72; - - return result; -} - -// The following table assumes no leap year; leap year is added separately -static const unsigned short cumulative_days_to_month[12] = { - 0, // Jan - 31, // Feb - 59, // Mar - 90, // Apr - 120, // May - 151, // Jun - 181, // Jul - 212, // Aug - 243, // Sep - 273, // Oct - 304, // Nov - 334 // Dec -}; - -static const unsigned short cumulative_days_to_month_leap[12] = { - 0, // Jan - 31, // Feb - 60, // Mar - 91, // Apr - 121, // May - 152, // Jun - 182, // Jul - 213, // Aug - 244, // Sep - 274, // Oct - 305, // Nov - 335 // Dec -}; - -datetime __cdecl datetime::utc_now() -{ -#ifdef _WIN32 - ULARGE_INTEGER largeInt; - FILETIME fileTime; - GetSystemTimeAsFileTime(&fileTime); - - largeInt.LowPart = fileTime.dwLowDateTime; - largeInt.HighPart = fileTime.dwHighDateTime; - - return datetime(largeInt.QuadPart); -#else // LINUX - struct timeval time; - gettimeofday(&time, nullptr); - int64_t result = NtToUnixOffsetSeconds + time.tv_sec; - result *= _secondTicks; // convert to 10e-7 - result += time.tv_usec * 10; // convert and add microseconds, 10e-6 to 10e-7 - return datetime(static_cast(result)); -#endif -} - -static const char dayNames[] = "Sun\0Mon\0Tue\0Wed\0Thu\0Fri\0Sat"; -static const char monthNames[] = "Jan\0Feb\0Mar\0Apr\0May\0Jun\0Jul\0Aug\0Sep\0Oct\0Nov\0Dec"; - -struct compute_year_result -{ - int year; - int secondsLeftThisYear; -}; - -static const int64_t secondsFrom1601To1900 = INT64_C(9435484800); - -static compute_year_result compute_year(int64_t secondsSince1900) -{ - int64_t secondsLeft = secondsSince1900 + secondsFrom1601To1900; // shift to start of this 400 year cycle - - int year400 = static_cast(secondsLeft / SecondsIn400Years); - secondsLeft -= year400 * SecondsIn400Years; - - int year100 = static_cast(secondsLeft / SecondsIn100Years); - secondsLeft -= year100 * SecondsIn100Years; - - int year4 = static_cast(secondsLeft / SecondsIn4Years); - int secondsInt = static_cast(secondsLeft - year4 * SecondsIn4Years); - - int year1 = secondsInt / SecondsInYear; - secondsInt -= year1 * SecondsInYear; - - // shift back to 1900 base from 1601: - return {year400 * 400 + year100 * 100 + year4 * 4 + year1 - 299, secondsInt}; -} - -utility::string_t datetime::to_string(date_format format) const -{ - if (m_interval > INT64_C(2650467743990000000)) - { - throw std::out_of_range("The requested year exceeds the year 9999."); - } - - const int64_t epochAdjusted = static_cast(m_interval) - NtTo1900OffsetInterval; - const int64_t secondsSince1900 = epochAdjusted / _secondTicks; // convert to seconds - const int fracSec = static_cast(epochAdjusted % _secondTicks); - - const auto yearData = compute_year(secondsSince1900); - const int year = yearData.year; - const int yearDay = yearData.secondsLeftThisYear / SecondsInDay; - int leftover = yearData.secondsLeftThisYear % SecondsInDay; - const int hour = leftover / SecondsInHour; - leftover = leftover % SecondsInHour; - const int minute = leftover / SecondsInMinute; - leftover = leftover % SecondsInMinute; - - const auto& monthTable = year_is_leap_year(year) ? cumulative_days_to_month_leap : cumulative_days_to_month; - int month = 0; - while (month < 11 && monthTable[month + 1] <= yearDay) - { - ++month; - } - - const auto monthDay = yearDay - monthTable[month] + 1; - const auto weekday = static_cast((secondsSince1900 / SecondsInDay + 1) % 7); - - char outBuffer[38]; // Thu, 01 Jan 1970 00:00:00 GMT\0 - // 1970-01-01T00:00:00.1234567Z\0 - char* outCursor = outBuffer; - switch (format) - { - case RFC_1123: -#ifdef _MSC_VER - sprintf_s(outCursor, - 26, - "%s, %02d %s %04d %02d:%02d:%02d", - dayNames + 4 * weekday, - monthDay, - monthNames + 4 * month, - year + 1900, - hour, - minute, - leftover); -#else // ^^^ _MSC_VER // !_MSC_VER vvv - sprintf(outCursor, - "%s, %02d %s %04d %02d:%02d:%02d", - dayNames + 4 * weekday, - monthDay, - monthNames + 4 * month, - year + 1900, - hour, - minute, - leftover); -#endif // _MSC_VER - outCursor += 25; - memcpy(outCursor, " GMT", 4); - outCursor += 4; - return utility::string_t(outBuffer, outCursor); - case ISO_8601: -#ifdef _MSC_VER - sprintf_s(outCursor, - 20, - "%04d-%02d-%02dT%02d:%02d:%02d", - year + 1900, - month + 1, - monthDay, - hour, - minute, - leftover); -#else // ^^^ _MSC_VER // !_MSC_VER vvv - sprintf( - outCursor, "%04d-%02d-%02dT%02d:%02d:%02d", year + 1900, month + 1, monthDay, hour, minute, leftover); -#endif // _MSC_VER - outCursor += 19; - if (fracSec != 0) - { - // Append fractional second, which is a 7-digit value with no trailing zeros - // This way, '1200' becomes '00012' -#ifdef _MSC_VER - size_t appended = sprintf_s(outCursor, 9, ".%07d", fracSec); -#else // ^^^ _MSC_VER // !_MSC_VER vvv - size_t appended = sprintf(outCursor, ".%07d", fracSec); -#endif // _MSC_VER - while (outCursor[appended - 1] == '0') - { - --appended; // trim trailing zeros - } - - outCursor += appended; - } - - *outCursor = 'Z'; - ++outCursor; - return utility::string_t(outBuffer, outCursor); - default: throw std::invalid_argument("Unrecognized date format."); - } -} - -template -static bool string_starts_with(const CharT* haystack, const char* needle) -{ - while (*needle) - { - if (*haystack != static_cast(*needle)) - { - return false; - } - - ++haystack; - ++needle; - } - - return true; -} - -#define ascii_isdigit(c) ((unsigned char)((unsigned char)(c) - '0') <= 9) -#define ascii_isdigit6(c) ((unsigned char)((unsigned char)(c) - '0') <= 6) -#define ascii_isdigit5(c) ((unsigned char)((unsigned char)(c) - '0') <= 5) -#define ascii_isdigit3(c) ((unsigned char)((unsigned char)(c) - '0') <= 3) -#define ascii_isdigit2(c) ((unsigned char)((unsigned char)(c) - '0') <= 2) -#define ascii_isdigit1(c) ((unsigned char)((unsigned char)(c) - '0') <= 1) - -static const unsigned char max_days_in_month[12] = { - 31, // Jan - 00, // Feb, special handling for leap years - 31, // Mar - 30, // Apr - 31, // May - 30, // Jun - 31, // Jul - 31, // Aug - 30, // Sep - 31, // Oct - 30, // Nov - 31 // Dec -}; - -static bool validate_day_month(int day, int month, int year) -{ - int maxDaysThisMonth; - if (month == 1) - { // Feb needs leap year testing - maxDaysThisMonth = 28 + year_is_leap_year(year); - } - else - { - maxDaysThisMonth = max_days_in_month[month]; - } - - return day >= 1 && day <= maxDaysThisMonth; -} - -static int get_year_day(int month, int monthDay, int year) -{ - return cumulative_days_to_month[month] + monthDay + (year_is_leap_year(year) && month > 1) - 1; -} - -template -static int atoi2(const CharT* str) -{ - return (static_cast(str[0]) - '0') * 10 + (static_cast(str[1]) - '0'); -} - -static int64_t timezone_adjust(int64_t result, unsigned char chSign, int adjustHours, int adjustMinutes) -{ - if (adjustHours > 23) - { - return -1; - } - - // adjustMinutes > 59 is impossible due to digit 5 check - const int tzAdjust = adjustMinutes * 60 + adjustHours * 60 * 60; - if (chSign == '-') - { - if (INT64_MAX - result < tzAdjust) - { - return -1; - } - - result += tzAdjust; - } - else - { - if (tzAdjust > result) - { - return -1; - } - - result -= tzAdjust; - } - - return result; -} - -/* -https://tools.ietf.org/html/rfc822 -https://tools.ietf.org/html/rfc1123 - -date-time = [ day "," ] date time ; dd mm yy - ; hh:mm:ss zzz - -day = "Mon" / "Tue" / "Wed" / "Thu" - / "Fri" / "Sat" / "Sun" - -date = 1*2DIGIT month 2DIGIT ; day month year - ; e.g. 20 Jun 82 -RFC1123 changes this to: -date = 1*2DIGIT month 2*4DIGIT ; day month year - ; e.g. 20 Jun 1982 -This implementation only accepts 4 digit years. - -month = "Jan" / "Feb" / "Mar" / "Apr" - / "May" / "Jun" / "Jul" / "Aug" - / "Sep" / "Oct" / "Nov" / "Dec" - -time = hour zone ; ANSI and Military - -hour = 2DIGIT ":" 2DIGIT [":" 2DIGIT] - ; 00:00:00 - 23:59:59 - -zone = "UT" / "GMT" ; Universal Time - ; North American : UT - / "EST" / "EDT" ; Eastern: - 5/ - 4 - / "CST" / "CDT" ; Central: - 6/ - 5 - / "MST" / "MDT" ; Mountain: - 7/ - 6 - / "PST" / "PDT" ; Pacific: - 8/ - 7 - -// military time deleted by RFC 1123 - - / ( ("+" / "-") 4DIGIT ) ; Local differential - ; hours+min. (HHMM) -*/ - - -datetime __cdecl datetime::from_string(const utility::string_t& dateString, date_format format) -{ - datetime result; - int64_t secondsSince1900; - uint64_t fracSec = 0; - auto str = dateString.c_str(); - if (format == RFC_1123) - { - int parsedWeekday = 0; - for (; parsedWeekday < 7; ++parsedWeekday) - { - if (string_starts_with(str, dayNames + parsedWeekday * 4) && str[3] == _XPLATSTR(',') && - str[4] == _XPLATSTR(' ')) - { - str += 5; // parsed day of week - break; - } - } - - int monthDay; - if (ascii_isdigit3(str[0]) && ascii_isdigit(str[1]) && str[2] == _XPLATSTR(' ')) - { - monthDay = atoi2(str); // validity checked later - str += 3; // parsed day - } - else if (ascii_isdigit(str[0]) && str[1] == _XPLATSTR(' ')) - { - monthDay = str[0] - _XPLATSTR('0'); - str += 2; // parsed day - } - else - { - return result; - } - - if (monthDay == 0) - { - return result; - } - - int month = 0; - for (;;) - { - if (string_starts_with(str, monthNames + month * 4)) - { - break; - } - - ++month; - if (month == 12) - { - return result; - } - } - - if (str[3] != _XPLATSTR(' ')) - { - return result; - } - - str += 4; // parsed month - - if (!ascii_isdigit(str[0]) || !ascii_isdigit(str[1]) || !ascii_isdigit(str[2]) || !ascii_isdigit(str[3]) || - str[4] != ' ') - { - return result; - } - - int year = (str[0] - _XPLATSTR('0')) * 1000 + (str[1] - _XPLATSTR('0')) * 100 + (str[2] - _XPLATSTR('0')) * 10 + - (str[3] - _XPLATSTR('0')); - if (year < 1900) - { - return result; - } - - // days in month validity check - if (!validate_day_month(monthDay, month, year)) - { - return result; - } - - str += 5; // parsed year - const int yearDay = get_year_day(month, monthDay, year); - - if (!ascii_isdigit2(str[0]) || !ascii_isdigit(str[1]) || str[2] != _XPLATSTR(':') || !ascii_isdigit5(str[3]) || - !ascii_isdigit(str[4])) - { - return result; - } - - const int hour = atoi2(str); - if (hour > 23) - { - return result; - } - - str += 3; // parsed hour - const int minute = atoi2(str); - str += 2; // parsed mins - - int sec; - if (str[0] == ':') - { - if (!ascii_isdigit6(str[1]) || !ascii_isdigit(str[2]) || str[3] != _XPLATSTR(' ')) - { - return result; - } - - sec = atoi2(str + 1); - str += 4; // parsed seconds - } - else if (str[0] == _XPLATSTR(' ')) - { - sec = 0; - str += 1; // parsed seconds - } - else - { - return result; - } - - if (sec > 60) - { // 60 to allow leap seconds - return result; - } - - year -= 1900; - int daysSince1900 = year * DaysInYear + count_leap_years(year) + yearDay; - - if (parsedWeekday != 7) - { - const int actualWeekday = (daysSince1900 + 1) % 7; - - if (parsedWeekday != actualWeekday) - { - return result; - } - } - - secondsSince1900 = - static_cast(daysSince1900) * SecondsInDay + hour * SecondsInHour + minute * SecondsInMinute + sec; - - if (!string_starts_with(str, "GMT") && !string_starts_with(str, "UT")) - { - // some timezone adjustment necessary - auto tzCh = _XPLATSTR('-'); - int tzHours; - int tzMinutes = 0; - if (string_starts_with(str, "EDT")) - { - tzHours = 4; - } - else if (string_starts_with(str, "EST") || string_starts_with(str, "CDT")) - { - tzHours = 5; - } - else if (string_starts_with(str, "CST") || string_starts_with(str, "MDT")) - { - tzHours = 6; - } - else if (string_starts_with(str, "MST") || string_starts_with(str, "PDT")) - { - tzHours = 7; - } - else if (string_starts_with(str, "PST")) - { - tzHours = 8; - } - else if ((tzCh == _XPLATSTR('+') || tzCh == _XPLATSTR('-')) && ascii_isdigit2(str[1]) && - ascii_isdigit(str[2]) && ascii_isdigit5(str[3]) && ascii_isdigit(str[4])) - { - tzCh = str[0]; - tzHours = atoi2(str + 1); - tzMinutes = atoi2(str + 3); - } - else - { - return result; - } - - secondsSince1900 = timezone_adjust(secondsSince1900, static_cast(tzCh), tzHours, tzMinutes); - if (secondsSince1900 < 0) - { - return result; - } - } - } - else if (format == ISO_8601) - { - // parse year - if (!ascii_isdigit(str[0]) || !ascii_isdigit(str[1]) || !ascii_isdigit(str[2]) || !ascii_isdigit(str[3])) - { - return result; - } - - int year = (str[0] - _XPLATSTR('0')) * 1000 + (str[1] - _XPLATSTR('0')) * 100 + (str[2] - _XPLATSTR('0')) * 10 + - (str[3] - _XPLATSTR('0')); - if (year < 1900) - { - return result; - } - - str += 4; - if (*str == _XPLATSTR('-')) - { - ++str; - } - - // parse month - if (!ascii_isdigit1(str[0]) || !ascii_isdigit(str[1])) - { - return result; - } - - int month = atoi2(str); - if (month < 1 || month > 12) - { - return result; - } - - month -= 1; - str += 2; - - if (*str == _XPLATSTR('-')) - { - ++str; - } - - // parse day - if (!ascii_isdigit3(str[0]) || !ascii_isdigit(str[1])) - { - return result; - } - - int monthDay = atoi2(str); - if (!validate_day_month(monthDay, month, year)) - { - return result; - } - - const int yearDay = get_year_day(month, monthDay, year); - - str += 2; - year -= 1900; - int daysSince1900 = year * DaysInYear + count_leap_years(year) + yearDay; - - if (str[0] != _XPLATSTR('T') && str[0] != _XPLATSTR('t')) - { - // No time - secondsSince1900 = static_cast(daysSince1900) * SecondsInDay; - - result.m_interval = - static_cast(secondsSince1900 * _secondTicks + fracSec + NtTo1900OffsetInterval); - return result; - } - - ++str; // skip 'T' - - // parse hour - if (!ascii_isdigit2(str[0]) || !ascii_isdigit(str[1])) - { - return result; - } - - const int hour = atoi2(str); - str += 2; - if (hour > 23) - { - return result; - } - - if (*str == _XPLATSTR(':')) - { - ++str; - } - - // parse minute - if (!ascii_isdigit5(str[0]) || !ascii_isdigit(str[1])) - { - return result; - } - - const int minute = atoi2(str); - // minute > 59 is impossible because we checked that the first digit is <= 5 in the basic format - // check above - - str += 2; - - if (*str == _XPLATSTR(':')) - { - ++str; - } - - // parse seconds - if (!ascii_isdigit6(str[0]) || !ascii_isdigit(str[1])) - { - return result; - } - - const int sec = atoi2(str); - // We allow 60 to account for leap seconds - if (sec > 60) - { - return result; - } - - str += 2; - if (str[0] == _XPLATSTR('.') && ascii_isdigit(str[1])) - { - ++str; - int digits = 7; - for (;;) - { - fracSec *= 10; - fracSec += *str - _XPLATSTR('0'); - --digits; - ++str; - if (digits == 0) - { - while (ascii_isdigit(*str)) - { - // consume remaining fractional second digits we can't use - ++str; - } - - break; - } - - if (!ascii_isdigit(*str)) - { - // no more digits in the input, do the remaining multiplies we need - for (; digits != 0; --digits) - { - fracSec *= 10; - } - - break; - } - } - } - - secondsSince1900 = - static_cast(daysSince1900) * SecondsInDay + hour * SecondsInHour + minute * SecondsInMinute + sec; - - if (str[0] == _XPLATSTR('Z') || str[0] == _XPLATSTR('z')) - { - // no adjustment needed for zulu time - } - else if (str[0] == _XPLATSTR('+') || str[0] == _XPLATSTR('-')) - { - const unsigned char offsetDirection = static_cast(str[0]); - if (!ascii_isdigit2(str[1]) || !ascii_isdigit(str[2]) || str[3] != _XPLATSTR(':') || - !ascii_isdigit5(str[4]) || !ascii_isdigit(str[5])) - { - return result; - } - - secondsSince1900 = timezone_adjust(secondsSince1900, offsetDirection, atoi2(str + 1), atoi2(str + 4)); - if (secondsSince1900 < 0) - { - return result; - } - } - else - { - // the timezone is malformed, but cpprestsdk currently accepts this as no timezone - } - } - else - { - throw std::invalid_argument("unrecognized date format"); - } - - result.m_interval = static_cast(secondsSince1900 * _secondTicks + fracSec + NtTo1900OffsetInterval); - return result; -} - -/// -/// Converts a timespan/interval in seconds to xml duration string as specified by -/// http://www.w3.org/TR/xmlschema-2/#duration -/// -utility::string_t __cdecl timespan::seconds_to_xml_duration(utility::seconds durationSecs) -{ - auto numSecs = durationSecs.count(); - - // Find the number of minutes - auto numMins = numSecs / 60; - if (numMins > 0) - { - numSecs = numSecs % 60; - } - - // Hours - auto numHours = numMins / 60; - if (numHours > 0) - { - numMins = numMins % 60; - } - - // Days - auto numDays = numHours / 24; - if (numDays > 0) - { - numHours = numHours % 24; - } - - // The format is: - // PdaysDThoursHminutesMsecondsS - utility::string_t result; - // (approximate mins/hours/secs as 2 digits each + 1 prefix character) + 1 for P prefix + 1 for T - size_t baseReserveSize = ((numHours > 0) + (numMins > 0) + (numSecs > 0)) * 3 + 1; - if (numDays > 0) - { - utility::string_t daysStr = utility::conversions::details::to_string_t(numDays); - result.reserve(baseReserveSize + daysStr.size() + 1); - result += _XPLATSTR('P'); - result += daysStr; - result += _XPLATSTR('D'); - } - else - { - result.reserve(baseReserveSize); - result += _XPLATSTR('P'); - } - - result += _XPLATSTR('T'); - - if (numHours > 0) - { - result += utility::conversions::details::to_string_t(numHours); - result += _XPLATSTR('H'); - } - - if (numMins > 0) - { - result += utility::conversions::details::to_string_t(numMins); - result += _XPLATSTR('M'); - } - - if (numSecs > 0) - { - result += utility::conversions::details::to_string_t(numSecs); - result += _XPLATSTR('S'); - } - - return result; -} - -utility::seconds __cdecl timespan::xml_duration_to_seconds(const utility::string_t& timespanString) -{ - // The format is: - // PnDTnHnMnS - // if n == 0 then the field could be omitted - // The final S could be omitted - - int64_t numSecs = 0; - auto cursor = timespanString.c_str(); - auto c = *cursor++; // skip 'P' - while (c) - { - int val = 0; - c = *cursor++; - - while (ascii_isdigit(c)) - { - val = val * 10 + (c - _XPLATSTR('0')); - c = *cursor++; - - if (c == _XPLATSTR('.')) - { - // decimal point is not handled - do - { - c = *cursor++; - } while (ascii_isdigit(c)); - } - } - - if (c == _XPLATSTR('D')) numSecs += val * 24 * 3600; // days - if (c == _XPLATSTR('H')) numSecs += val * 3600; // Hours - if (c == _XPLATSTR('M')) numSecs += val * 60; // Minutes - if (c == _XPLATSTR('S') || c == _XPLATSTR('\0')) - { - numSecs += val; // seconds - break; - } - } - - return utility::seconds(numSecs); -} - -static const char c_allowed_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; -static const int chars_count = static_cast(sizeof(c_allowed_chars) - 1); - -utility::string_t nonce_generator::generate() -{ - std::uniform_int_distribution<> distr(0, chars_count - 1); - utility::string_t result; - result.reserve(length()); - std::generate_n(std::back_inserter(result), length(), [&] { - return static_cast(c_allowed_chars[distr(m_random)]); - }); - return result; -} - } // namespace utility 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 From f4f3f948c98864edaf736c90cfac09b4f6648359 Mon Sep 17 00:00:00 2001 From: Jason Hartman Date: Tue, 23 Jul 2019 11:57:03 -0700 Subject: [PATCH 06/19] add includes in header with explicit dependencies --- Release/include/cpprest/details/web_utilities.h | 1 + Release/include/cpprest/http_compression.h | 5 +++++ Release/include/pplx/threadpool.h | 1 + 3 files changed, 7 insertions(+) diff --git a/Release/include/cpprest/details/web_utilities.h b/Release/include/cpprest/details/web_utilities.h index cc96662333..d7c7fdb36b 100644 --- a/Release/include/cpprest/details/web_utilities.h +++ b/Release/include/cpprest/details/web_utilities.h @@ -12,6 +12,7 @@ #include "cpprest/asyncrt_utils.h" #include "cpprest/uri.h" +#include namespace web { 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/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 { From 665e00e3967348199052de0865680524d74cf5d3 Mon Sep 17 00:00:00 2001 From: Jason Hartman Date: Tue, 23 Jul 2019 12:13:29 -0700 Subject: [PATCH 07/19] add include for bad_cast in string_utils.h --- Release/include/cpprest/string_utils.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Release/include/cpprest/string_utils.h b/Release/include/cpprest/string_utils.h index 5761aa9018..4b27cc9c5b 100644 --- a/Release/include/cpprest/string_utils.h +++ b/Release/include/cpprest/string_utils.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #ifndef _WIN32 From df2bbe91f41f7fa9e9dac1ac3163befb688756af Mon Sep 17 00:00:00 2001 From: Jason Hartman Date: Tue, 23 Jul 2019 12:40:37 -0700 Subject: [PATCH 08/19] add for std::count in nonce_generator_tests.cpp --- Release/tests/functional/utils/nonce_generator_tests.cpp | 2 ++ 1 file changed, 2 insertions(+) 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 From d2ad8662d9c14a2015bdf70c348d19a9f9a727f2 Mon Sep 17 00:00:00 2001 From: Jason Hartman Date: Tue, 23 Jul 2019 15:21:10 -0700 Subject: [PATCH 09/19] nudge pipeline to rerun From 71dea745e1f77db74f25624e2abaa061592713fa Mon Sep 17 00:00:00 2001 From: Jason Hartman Date: Wed, 31 Jul 2019 17:07:22 -0700 Subject: [PATCH 10/19] Add CPPREST_USE_STRING_VIEWS option to accept string_views as input - default to enable CPPREST_USE_STRING_VIEWS when compiler supports C++ 17 most string utility and json APIs are changed to support string_views (deprecated APIs left alone) primary argument replacements: const utility::string_t& -> utility::string_view_t const std::string& -> utility::nstring_view_t const std::wstring& -> utility::wstring_view_t const utf16string& -> utf16string_view potential client fallout when enabling option: For clients passing char* to conversion that does not require conversion, string_view will be the result. If string type is actually required then an explicit ctor would need to be added. Otherwise client may be able to use more string_view in own code and futher reduce memory copies. See searchfile.cpp in Samples for example. Use of foo.c_str() and &foo[0] on a potential string_view is now foo.data(). --- Release/CMakeLists.txt | 14 +++- Release/include/cpprest/base64_utils.h | 2 +- Release/include/cpprest/details/basic_types.h | 22 ++++++ .../include/cpprest/details/web_utilities.h | 6 +- Release/include/cpprest/filestream.h | 10 +-- Release/include/cpprest/json.h | 70 +++++++++---------- Release/include/cpprest/string_utils.h | 47 +++++++++---- Release/samples/SearchFile/searchfile.cpp | 12 ++-- Release/src/CMakeLists.txt | 4 ++ Release/src/json/json.cpp | 28 ++++---- Release/src/json/json_parsing.cpp | 8 +-- Release/src/json/json_serialization.cpp | 14 ++-- Release/src/streams/fileio_win32.cpp | 6 +- Release/src/utilities/base64.cpp | 10 +-- Release/src/utilities/string_utils.cpp | 34 ++++----- Release/src/utilities/web_utilities.cpp | 8 +-- .../utils/win32_encryption_tests.cpp | 4 +- 17 files changed, 181 insertions(+), 118 deletions(-) diff --git a/Release/CMakeLists.txt b/Release/CMakeLists.txt index 65d2114063..9798985e8b 100644 --- a/Release/CMakeLists.txt +++ b/Release/CMakeLists.txt @@ -13,6 +13,14 @@ set(CPPREST_VERSION_MAJOR 2) set(CPPREST_VERSION_MINOR 10) set(CPPREST_VERSION_REVISION 14) +# Note: when bumping CMake version to 3.3 or higher if(... IN_LIST ...) may be used +list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_std_17 COMPILER_HAS_CXX_STD_17) +if(COMPILER_HAS_CXX_STD_17 EQUAL "-1") + set(CPPREST_USE_STRING_VIEWS_DEFAULT_PER_CXX_STANDARD OFF) +else() + set(CPPREST_USE_STRING_VIEWS_DEFAULT_PER_CXX_STANDARD ON) +endif() + enable_testing() set(WERROR ON CACHE BOOL "Treat Warnings as Errors.") @@ -21,6 +29,7 @@ set(CPPREST_EXCLUDE_COMPRESSION OFF CACHE BOOL "Exclude compression functionalit 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) +option(CPPREST_USE_STRING_VIEWS "Use string_view types" ${CPPREST_USE_STRING_VIEWS_DEFAULT_PER_CXX_STANDARD}) set(CPPREST_INSTALL_HEADERS ON CACHE BOOL "Install header files.") set(CPPREST_INSTALL ON CACHE BOOL "Add install commands.") @@ -135,7 +144,10 @@ set(ANDROID_LIBS) # Generic build settings if(CPPREST_FORCE_NARROW_STRINGS) - add_definitions(-DCPPREST_FORCE_NARROW_STRINGS) + add_definitions(-DCPPREST_FORCE_NARROW_STRINGS) +endif() +if(CPPREST_USE_STRING_VIEWS) + add_definitions(-DCPPREST_USE_STRING_VIEWS) endif() # Platform (not compiler) specific settings diff --git a/Release/include/cpprest/base64_utils.h b/Release/include/cpprest/base64_utils.h index d986b5973d..a5c0823664 100644 --- a/Release/include/cpprest/base64_utils.h +++ b/Release/include/cpprest/base64_utils.h @@ -36,7 +36,7 @@ _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); +_ASYNCRTIMP std::vector __cdecl from_base64(utility::string_view_t str); } // namespace conversions diff --git a/Release/include/cpprest/details/basic_types.h b/Release/include/cpprest/details/basic_types.h index 71b4f78aad..9cc621c187 100644 --- a/Release/include/cpprest/details/basic_types.h +++ b/Release/include/cpprest/details/basic_types.h @@ -18,6 +18,9 @@ #include #include #include +#if defined(CPPREST_USE_STRING_VIEWS) +#include +#endif #ifndef _WIN32 #ifndef __STDC_LIMIT_MACROS @@ -44,11 +47,22 @@ typedef uint64_t size64_t; typedef uint32_t HRESULT; // Needed for PPLX #endif +#if defined(CPPREST_USE_STRING_VIEWS) +typedef std::string_view nstring_view_t; +typedef std::wstring_view wstring_view_t; +template using string_view = std::basic_string_view; +#else +typedef const std::string & nstring_view_t; +typedef const std::wstring & wstring_view_t; +template using string_view = const std::basic_string &; +#endif + #ifdef _UTF16_STRINGS // // On Windows, all strings are wide // typedef wchar_t char_t; +typedef wstring_view_t string_view_t; typedef std::wstring string_t; #define _XPLATSTR(x) L##x typedef std::wostringstream ostringstream_t; @@ -66,6 +80,7 @@ typedef std::wstringstream stringstream_t; // On POSIX platforms, all strings are narrow // typedef char char_t; +typedef nstring_view_t string_view_t; typedef std::string string_t; #define _XPLATSTR(x) x typedef std::ostringstream ostringstream_t; @@ -90,6 +105,7 @@ typedef std::stringstream stringstream_t; } // namespace utility typedef char utf8char; +typedef utility::nstring_view_t utf8string_view; typedef std::string utf8string; typedef std::stringstream utf8stringstream; typedef std::ostringstream utf8ostringstream; @@ -99,6 +115,7 @@ typedef std::istringstream utf8istringstream; #if defined(_UTF16_STRINGS) || defined(_WIN32) typedef wchar_t utf16char; +typedef utility::wstring_view_t utf16string_view; typedef std::wstring utf16string; typedef std::wstringstream utf16stringstream; typedef std::wostringstream utf16ostringstream; @@ -107,6 +124,11 @@ typedef std::wistream utf16istream; typedef std::wistringstream utf16istringstream; #else typedef char16_t utf16char; +#if defined(CPPREST_USE_STRING_VIEWS) +typedef std::u16string_view utf16string_view; +#else +typedef const std::u16string & utf16string_view; +#endif typedef std::u16string utf16string; typedef std::basic_stringstream utf16stringstream; typedef std::basic_ostringstream utf16ostringstream; diff --git a/Release/include/cpprest/details/web_utilities.h b/Release/include/cpprest/details/web_utilities.h index d7c7fdb36b..441775cf62 100644 --- a/Release/include/cpprest/details/web_utilities.h +++ b/Release/include/cpprest/details/web_utilities.h @@ -32,7 +32,7 @@ class winrt_encryption { public: winrt_encryption() = default; - _ASYNCRTIMP winrt_encryption(const ::utility::string_t& data); + _ASYNCRTIMP winrt_encryption(utility::string_view_t data); _ASYNCRTIMP plaintext_string decrypt() const; private: @@ -43,7 +43,7 @@ class win32_encryption { public: win32_encryption() = default; - _ASYNCRTIMP win32_encryption(const ::utility::string_t& data); + _ASYNCRTIMP win32_encryption(::utility::string_view_t data); _ASYNCRTIMP ~win32_encryption(); _ASYNCRTIMP plaintext_string decrypt() const; @@ -73,7 +73,7 @@ class credentials /// /// User name as a string. /// Password as a string. - credentials(utility::string_t username, const utility::string_t& password) + credentials(utility::string_t username, utility::string_view_t password) : m_username(std::move(username)), m_password(password) { } diff --git a/Release/include/cpprest/filestream.h b/Release/include/cpprest/filestream.h index a9e6351caa..d71f9c20a7 100644 --- a/Release/include/cpprest/filestream.h +++ b/Release/include/cpprest/filestream.h @@ -713,7 +713,7 @@ class basic_file_buffer : public details::streambuf_state_manager<_CharType> #if !defined(__cplusplus_winrt) static pplx::task>> open( - const utility::string_t& _Filename, + utility::string_view_t _Filename, std::ios_base::openmode _Mode = std::ios_base::out, #ifdef _WIN32 int _Prot = (int)std::ios_base::_Openprot @@ -724,7 +724,7 @@ class basic_file_buffer : public details::streambuf_state_manager<_CharType> { auto result_tce = pplx::task_completion_event>>(); auto callback = new _filestream_callback_open(result_tce); - _open_fsb_str(callback, _Filename.c_str(), _Mode, _Prot); + _open_fsb_str(callback, _Filename.data(), _Mode, _Prot); return pplx::create_task(result_tce); } @@ -955,7 +955,7 @@ class file_buffer /// The opening mode of the file /// The file protection mode /// A task that returns an opened stream buffer on completion. - static pplx::task> open(const utility::string_t& file_name, + static pplx::task> open(utility::string_view_t file_name, std::ios_base::openmode mode = std::ios_base::out, #ifdef _WIN32 int prot = _SH_DENYRD @@ -1010,7 +1010,7 @@ class file_stream /// The opening mode of the file /// The file protection mode /// A task that returns an opened input stream on completion. - static pplx::task> open_istream(const utility::string_t& file_name, + static pplx::task> open_istream(utility::string_view_t file_name, std::ios_base::openmode mode = std::ios_base::in, #ifdef _WIN32 int prot = (int)std::ios_base::_Openprot @@ -1035,7 +1035,7 @@ class file_stream /// The opening mode of the file /// The file protection mode /// A task that returns an opened output stream on completion. - static pplx::task> open_ostream(const utility::string_t& file_name, + static pplx::task> open_ostream(utility::string_view_t file_name, std::ios_base::openmode mode = std::ios_base::out, #ifdef _WIN32 int prot = (int)std::ios_base::_Openprot diff --git a/Release/include/cpprest/json.h b/Release/include/cpprest/json.h index b97d4a0c28..ca75463a1c 100644 --- a/Release/include/cpprest/json.h +++ b/Release/include/cpprest/json.h @@ -281,7 +281,7 @@ class value #if defined(_UTF16_STRINGS) private: // Only used internally by JSON parser. - static _ASYNCRTIMP value __cdecl string(const std::string& value); + static _ASYNCRTIMP value __cdecl string(utility::nstring_view_t value); public: #endif @@ -394,7 +394,7 @@ class value /// Parses a string and construct a JSON value. /// /// The C++ value to create a JSON value from, a C++ STL double-byte string - _ASYNCRTIMP static value __cdecl parse(const utility::string_t& value); + _ASYNCRTIMP static value __cdecl parse(utility::string_view_t value); /// /// Attempts to parse a string and construct a JSON value. @@ -402,7 +402,7 @@ class value /// The C++ value to create a JSON value from, a C++ STL double-byte string /// If parsing fails, the error code is greater than 0 /// The parsed object. Returns web::json::value::null if failed - _ASYNCRTIMP static value __cdecl parse(const utility::string_t& value, std::error_code& errorCode); + _ASYNCRTIMP static value __cdecl parse(utility::string_view_t value, std::error_code& errorCode); /// /// Serializes the current JSON value to a C++ string. @@ -539,56 +539,56 @@ class value /// /// The name of the field /// True if the field exists, false otherwise. - bool has_field(const utility::string_t& key) const; + bool has_field(utility::string_view_t key) const; /// /// Tests for the presence of a number field /// /// The name of the field /// True if the field exists, false otherwise. - _ASYNCRTIMP bool has_number_field(const utility::string_t& key) const; + _ASYNCRTIMP bool has_number_field(utility::string_view_t key) const; /// /// Tests for the presence of an integer field /// /// The name of the field /// True if the field exists, false otherwise. - _ASYNCRTIMP bool has_integer_field(const utility::string_t& key) const; + _ASYNCRTIMP bool has_integer_field(utility::string_view_t key) const; /// /// Tests for the presence of a double field /// /// The name of the field /// True if the field exists, false otherwise. - _ASYNCRTIMP bool has_double_field(const utility::string_t& key) const; + _ASYNCRTIMP bool has_double_field(utility::string_view_t key) const; /// /// Tests for the presence of a boolean field /// /// The name of the field /// True if the field exists, false otherwise. - _ASYNCRTIMP bool has_boolean_field(const utility::string_t& key) const; + _ASYNCRTIMP bool has_boolean_field(utility::string_view_t key) const; /// /// Tests for the presence of a string field /// /// The name of the field /// True if the field exists, false otherwise. - _ASYNCRTIMP bool has_string_field(const utility::string_t& key) const; + _ASYNCRTIMP bool has_string_field(utility::string_view_t key) const; /// /// Tests for the presence of an array field /// /// The name of the field /// True if the field exists, false otherwise. - _ASYNCRTIMP bool has_array_field(const utility::string_t& key) const; + _ASYNCRTIMP bool has_array_field(utility::string_view_t key) const; /// /// Tests for the presence of an object field /// /// The name of the field /// True if the field exists, false otherwise. - _ASYNCRTIMP bool has_object_field(const utility::string_t& key) const; + _ASYNCRTIMP bool has_object_field(utility::string_view_t key) const; /// /// Accesses a field of a JSON object. @@ -609,7 +609,7 @@ class value /// Erases an element of a JSON object. Throws if the key doesn't exist. /// /// The key of the element to erase in the JSON object. - _ASYNCRTIMP void erase(const utility::string_t& key); + _ASYNCRTIMP void erase(utility::string_view_t key); /// /// Accesses an element of a JSON array. Throws when index out of bounds. @@ -630,26 +630,26 @@ class value /// /// The key of an element in the JSON object. /// If the key exists, a reference to the value. - _ASYNCRTIMP json::value& at(const utility::string_t& key); + _ASYNCRTIMP json::value& at(utility::string_view_t key); /// /// Accesses an element of a JSON object. If the key doesn't exist, this method throws. /// /// The key of an element in the JSON object. /// If the key exists, a reference to the value. - _ASYNCRTIMP const json::value& at(const utility::string_t& key) const; + _ASYNCRTIMP const json::value& at(utility::string_view_t key) const; /// /// Accesses a field of a JSON object. /// /// The name of the field /// A reference to the value kept in the field. - _ASYNCRTIMP value& operator[](const utility::string_t& key); + _ASYNCRTIMP value& operator[](utility::string_view_t key); #if defined(_UTF16_STRINGS) private: // Only used internally by JSON parser - _ASYNCRTIMP value& operator[](const std::string& key) + _ASYNCRTIMP value& operator[](utility::nstring_view_t key) { // JSON object stores its field map as a unordered_map of string_t, so this conversion is hard to avoid return operator[](utility::conversions::to_string_t(key)); @@ -1050,7 +1050,7 @@ class object /// Deletes an element of the JSON object. If the key doesn't exist, this method throws. /// /// The key of an element in the JSON object. - void erase(const utility::string_t& key) + void erase(utility::string_view_t key) { auto iter = find_by_key(key); if (iter == m_elements.end()) @@ -1066,7 +1066,7 @@ class object /// /// The key of an element in the JSON object. /// If the key exists, a reference to the value kept in the field. - json::value& at(const utility::string_t& key) + json::value& at(utility::string_view_t key) { auto iter = find_by_key(key); if (iter == m_elements.end()) @@ -1082,7 +1082,7 @@ class object /// /// The key of an element in the JSON object. /// If the key exists, a reference to the value kept in the field. - const json::value& at(const utility::string_t& key) const + const json::value& at(utility::string_view_t key) const { auto iter = find_by_key(key); if (iter == m_elements.end()) @@ -1099,7 +1099,7 @@ class object /// The key of an element in the JSON object. /// If the key exists, a reference to the value kept in the field, otherwise a newly created null value /// that will be stored for the given key. - json::value& operator[](const utility::string_t& key) + json::value& operator[](utility::string_view_t key) { auto iter = find_insert_location(key); @@ -1116,7 +1116,7 @@ class object /// /// The key of an element in the JSON object. /// A const iterator to the value kept in the field. - const_iterator find(const utility::string_t& key) const { return find_by_key(key); } + const_iterator find(utility::string_view_t key) const { return find_by_key(key); } /// /// Gets the number of elements of the object. @@ -1136,12 +1136,12 @@ class object { return p1.first < p2.first; } - static bool compare_with_key(const std::pair& p1, const utility::string_t& key) + static bool compare_with_key(const std::pair& p1, utility::string_view_t key) { return p1.first < key; } - storage_type::iterator find_insert_location(const utility::string_t& key) + storage_type::iterator find_insert_location(utility::string_view_t key) { if (m_keep_order) { @@ -1155,7 +1155,7 @@ class object } } - storage_type::const_iterator find_by_key(const utility::string_t& key) const + storage_type::const_iterator find_by_key(utility::string_view_t key) const { if (m_keep_order) { @@ -1174,7 +1174,7 @@ class object } } - storage_type::iterator find_by_key(const utility::string_t& key) + storage_type::iterator find_by_key(utility::string_view_t key) { auto iter = find_insert_location(key); if (iter != m_elements.end() && key != iter->first) @@ -1357,14 +1357,14 @@ class _Value public: virtual std::unique_ptr<_Value> _copy_value() = 0; - virtual bool has_field(const utility::string_t&) const { return false; } - virtual value get_field(const utility::string_t&) const { throw json_exception("not an object"); } + virtual bool has_field(utility::string_view_t) const { return false; } + virtual value get_field(utility::string_view_t) const { throw json_exception("not an object"); } virtual value get_element(array::size_type) const { throw json_exception("not an array"); } - virtual value& index(const utility::string_t&) { throw json_exception("not an object"); } + virtual value& index(utility::string_view_t) { throw json_exception("not an object"); } virtual value& index(array::size_type) { throw json_exception("not an array"); } - virtual const value& cnst_index(const utility::string_t&) const { throw json_exception("not an object"); } + virtual const value& cnst_index(utility::string_view_t) const { throw json_exception("not an object"); } virtual const value& cnst_index(array::size_type) const { throw json_exception("not an array"); } // Common function used for serialization to strings and streams. @@ -1537,12 +1537,12 @@ class _String : public _Value }; template -_ASYNCRTIMP void append_escape_string(std::basic_string& str, const std::basic_string& escaped); +_ASYNCRTIMP void append_escape_string(std::basic_string& str, utility::string_view escaped); -void format_string(const utility::string_t& key, utility::string_t& str); +void format_string(utility::string_view_t key, utility::string_t& str); #if defined(_UTF16_STRINGS) -void format_string(const utility::string_t& key, std::string& str); +void format_string(utility::string_view_t key, std::string& str); #endif class _Object : public _Value @@ -1559,9 +1559,9 @@ class _Object : public _Value virtual json::value::value_type type() const { return json::value::Object; } - virtual bool has_field(const utility::string_t&) const; + virtual bool has_field(utility::string_view_t) const; - virtual json::value& index(const utility::string_t& key); + virtual json::value& index(utility::string_view_t key); bool is_equal(const _Object* other) const { @@ -1752,7 +1752,7 @@ inline size_t json::value::size() const { return m_value->size(); } /// /// The name of the field /// True if the field exists, false otherwise. -inline bool json::value::has_field(const utility::string_t& key) const { return m_value->has_field(key); } +inline bool json::value::has_field(utility::string_view_t key) const { return m_value->has_field(key); } /// /// Access a field of a JSON object. diff --git a/Release/include/cpprest/string_utils.h b/Release/include/cpprest/string_utils.h index 4b27cc9c5b..5149b488f8 100644 --- a/Release/include/cpprest/string_utils.h +++ b/Release/include/cpprest/string_utils.h @@ -42,35 +42,35 @@ namespace conversions /// /// A two byte character UTF-16 string. /// A single byte character UTF-8 string. -_ASYNCRTIMP std::string __cdecl utf16_to_utf8(const utf16string& w); +_ASYNCRTIMP std::string __cdecl utf16_to_utf8(utf16string_view 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); +_ASYNCRTIMP utf16string __cdecl utf8_to_utf16(utility::nstring_view_t 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); +_ASYNCRTIMP utf16string __cdecl usascii_to_utf16(utility::nstring_view_t 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); +_ASYNCRTIMP utf16string __cdecl latin1_to_utf16(utility::nstring_view_t 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); +_ASYNCRTIMP utf8string __cdecl latin1_to_utf8(utility::nstring_view_t s); /// /// Converts to a platform dependent Unicode string type. @@ -99,9 +99,18 @@ _ASYNCRTIMP utility::string_t __cdecl to_string_t(utf16string&& s); /// 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); +_ASYNCRTIMP utility::string_t __cdecl to_string_t(utility::nstring_view_t s); #else inline const utility::string_t& to_string_t(const std::string& s) { return s; } +#if CPPREST_USE_STRING_VIEWS +inline utility::string_view_t to_string_t(utility::nstring_view_t s) { return s; } +#endif +#endif + +#if CPPREST_USE_STRING_VIEWS +// Provide precise overload for string literals to resolve ambiguity of other overloads. +template +inline auto to_string_t(const CharType * s) { return to_string_t(std::basic_string_view(s)); } #endif /// @@ -111,8 +120,11 @@ inline const utility::string_t& to_string_t(const std::string& s) { return s; } /// A platform dependent string type. #ifdef _UTF16_STRINGS inline const utility::string_t& to_string_t(const utf16string& s) { return s; } +#if CPPREST_USE_STRING_VIEWS +inline utf16string_view to_string_t(utf16string_view s) { return s; } +#endif #else -_ASYNCRTIMP utility::string_t __cdecl to_string_t(const utf16string& s); +_ASYNCRTIMP utility::string_t __cdecl to_string_t(utf16string_view s); #endif /// @@ -120,7 +132,7 @@ _ASYNCRTIMP utility::string_t __cdecl to_string_t(const utf16string& s); /// /// A single byte character UTF-8 string. /// A two byte character UTF-16 string. -_ASYNCRTIMP utf16string __cdecl to_utf16string(const std::string& value); +_ASYNCRTIMP utf16string __cdecl to_utf16string(utility::nstring_view_t value); /// /// Converts to a UTF-16 from string. @@ -128,6 +140,9 @@ _ASYNCRTIMP utf16string __cdecl to_utf16string(const std::string& value); /// A two byte character UTF-16 string. /// A two byte character UTF-16 string. inline const utf16string& to_utf16string(const utf16string& value) { return value; } +#if CPPREST_USE_STRING_VIEWS +inline utf16string_view to_utf16string(utf16string_view value) { return value; } +#endif /// /// Converts to a UTF-16 from string. /// @@ -148,13 +163,16 @@ inline std::string&& to_utf8string(std::string&& value) { return std::move(value /// 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; } +#if CPPREST_USE_STRING_VIEWS +inline utility::nstring_view_t to_utf8string(utility::nstring_view_t value) { return value; } +#endif /// /// 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); +_ASYNCRTIMP std::string __cdecl to_utf8string(utf16string_view value); template CASABLANCA_DEPRECATED("All locale-sensitive APIs will be removed in a future update. Use stringstreams directly if " @@ -216,6 +234,9 @@ utility::string_t print_string(const Source& val) } inline const utility::string_t& print_string(const utility::string_t& val) { return val; } +#if CPPREST_USE_STRING_VIEWS +inline utility::string_view_t print_string(utility::string_view_t val) { return val; } +#endif template utf8string print_utf8string(const Source& val) @@ -343,7 +364,7 @@ inline bool __cdecl is_alnum(Elem ch) CPPREST_NOEXCEPT /// 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; +_ASYNCRTIMP bool __cdecl str_iequal(utility::nstring_view_t left, utility::nstring_view_t right) CPPREST_NOEXCEPT; /// /// Cross platform utility function for performing case insensitive string equality comparison. @@ -351,7 +372,7 @@ _ASYNCRTIMP bool __cdecl str_iequal(const std::string& left, const std::string& /// 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; +_ASYNCRTIMP bool __cdecl str_iequal(utility::wstring_view_t left, utility::wstring_view_t right) CPPREST_NOEXCEPT; /// /// Cross platform utility function for performing case insensitive string less-than comparison. @@ -360,7 +381,7 @@ _ASYNCRTIMP bool __cdecl str_iequal(const std::wstring& left, const std::wstring /// 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; +_ASYNCRTIMP bool __cdecl str_iless(utility::nstring_view_t left, utility::nstring_view_t right) CPPREST_NOEXCEPT; /// /// Cross platform utility function for performing case insensitive string less-than comparison. @@ -369,7 +390,7 @@ _ASYNCRTIMP bool __cdecl str_iless(const std::string& left, const std::string& r /// 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; +_ASYNCRTIMP bool __cdecl str_iless(utility::wstring_view_t left, utility::wstring_view_t right) CPPREST_NOEXCEPT; /// /// Convert a string to lowercase in place. diff --git a/Release/samples/SearchFile/searchfile.cpp b/Release/samples/SearchFile/searchfile.cpp index 7200f05dc8..480fe96752 100644 --- a/Release/samples/SearchFile/searchfile.cpp +++ b/Release/samples/SearchFile/searchfile.cpp @@ -86,8 +86,8 @@ class type_parser /// Function to create in data from a file and search for a given string writing all lines containing the string to /// memory_buffer. /// -static pplx::task find_matches_in_file(const string_t& fileName, - const std::string& searchString, +static pplx::task find_matches_in_file(utility::string_view_t fileName, + utility::nstring_view_t searchString, basic_ostream results) { return file_stream::open_istream(fileName).then([=](basic_istream inFile) { @@ -130,7 +130,7 @@ static pplx::task find_matches_in_file(const string_t& fileName, /// /// Function to write out results from matched_lines type to file /// -static pplx::task write_matches_to_file(const string_t& fileName, matched_lines results) +static pplx::task write_matches_to_file(utility::string_view_t fileName, matched_lines results) { // Create a shared pointer to the matched_lines structure to copying repeatedly. auto sharedResults = std::make_shared(std::move(results)); @@ -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 = utility::conversions::to_string_t(args[1]); - const std::string searchString = utility::conversions::to_utf8string(args[2]); - const string_t outFileName = utility::conversions::to_string_t(args[3]); + const auto inFileName = utility::conversions::to_string_t(args[1]); + const auto searchString = utility::conversions::to_utf8string(args[2]); + const auto 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 79af527c73..aa47d21113 100644 --- a/Release/src/CMakeLists.txt +++ b/Release/src/CMakeLists.txt @@ -53,6 +53,10 @@ target_include_directories(cpprest pch ) +if(CPPREST_USE_STRING_VIEWS) + target_compile_features(cpprest PUBLIC cxx_std_17) +endif() + ## Sub-components # Websockets component if(CPPREST_WEBSOCKETS_IMPL STREQUAL "none") diff --git a/Release/src/json/json.cpp b/Release/src/json/json.cpp index ae640ae26d..a8ffbb059c 100644 --- a/Release/src/json/json.cpp +++ b/Release/src/json/json.cpp @@ -196,7 +196,7 @@ web::json::value web::json::value::string(utility::string_t value, bool has_esca } #if defined(_UTF16_STRINGS) -web::json::value web::json::value::string(const std::string& value) +web::json::value web::json::value::string(utility::nstring_view_t value) { std::unique_ptr ptr = utility::details::make_unique(utility::conversions::to_utf16string(value)); @@ -355,44 +355,44 @@ bool json::value::is_double() const return m_value->is_double(); } -json::value& web::json::details::_Object::index(const utility::string_t& key) { return m_object[key]; } +json::value& web::json::details::_Object::index(utility::string_view_t key) { return m_object[key]; } -bool web::json::details::_Object::has_field(const utility::string_t& key) const +bool web::json::details::_Object::has_field(utility::string_view_t key) const { return m_object.find(key) != m_object.end(); } -bool web::json::value::has_number_field(const utility::string_t& key) const +bool web::json::value::has_number_field(utility::string_view_t key) const { return has_field(key) && at(key).is_number(); } -bool web::json::value::has_integer_field(const utility::string_t& key) const +bool web::json::value::has_integer_field(utility::string_view_t key) const { return has_field(key) && at(key).is_integer(); } -bool web::json::value::has_double_field(const utility::string_t& key) const +bool web::json::value::has_double_field(utility::string_view_t key) const { return has_field(key) && at(key).is_double(); } -bool web::json::value::has_boolean_field(const utility::string_t& key) const +bool web::json::value::has_boolean_field(utility::string_view_t key) const { return has_field(key) && at(key).is_boolean(); } -bool web::json::value::has_string_field(const utility::string_t& key) const +bool web::json::value::has_string_field(utility::string_view_t key) const { return has_field(key) && at(key).is_string(); } -bool web::json::value::has_array_field(const utility::string_t& key) const +bool web::json::value::has_array_field(utility::string_view_t key) const { return has_field(key) && at(key).is_array(); } -bool web::json::value::has_object_field(const utility::string_t& key) const +bool web::json::value::has_object_field(utility::string_view_t key) const { return has_field(key) && at(key).is_object(); } @@ -428,18 +428,18 @@ bool json::value::operator==(const json::value& other) const void web::json::value::erase(size_t index) { return this->as_array().erase(index); } -void web::json::value::erase(const utility::string_t& key) { return this->as_object().erase(key); } +void web::json::value::erase(utility::string_view_t key) { return this->as_object().erase(key); } // at() overloads web::json::value& web::json::value::at(size_t index) { return this->as_array().at(index); } const web::json::value& web::json::value::at(size_t index) const { return this->as_array().at(index); } -web::json::value& web::json::value::at(const utility::string_t& key) { return this->as_object().at(key); } +web::json::value& web::json::value::at(utility::string_view_t key) { return this->as_object().at(key); } -const web::json::value& web::json::value::at(const utility::string_t& key) const { return this->as_object().at(key); } +const web::json::value& web::json::value::at(utility::string_view_t key) const { return this->as_object().at(key); } -web::json::value& web::json::value::operator[](const utility::string_t& key) +web::json::value& web::json::value::operator[](utility::string_view_t key) { if (this->is_null()) { diff --git a/Release/src/json/json_parsing.cpp b/Release/src/json/json_parsing.cpp index 2e0d71e6d3..e5719d3494 100644 --- a/Release/src/json/json_parsing.cpp +++ b/Release/src/json/json_parsing.cpp @@ -46,7 +46,7 @@ __declspec(noreturn) #else __attribute__((noreturn)) #endif - void CreateException(const Token& tk, const utility::string_t& message) + void CreateException(const Token& tk, utility::string_view_t message) { std::string str("* Line "); str += std::to_string(tk.start.m_line); @@ -211,7 +211,7 @@ template class JSON_StringParser : public JSON_Parser { public: - JSON_StringParser(const std::basic_string& string) : m_position(&string[0]) + JSON_StringParser(utility::string_view string) : m_position(string.data()) { m_startpos = m_position; m_endpos = m_position + string.size(); @@ -1223,7 +1223,7 @@ static web::json::value _parse_narrow_stream(std::istream& stream, std::error_co } #endif -web::json::value web::json::value::parse(const utility::string_t& str) +web::json::value web::json::value::parse(utility::string_view_t str) { web::json::details::JSON_StringParser parser(str); web::json::details::JSON_Parser::Token tkn; @@ -1247,7 +1247,7 @@ web::json::value web::json::value::parse(const utility::string_t& str) return value; } -web::json::value web::json::value::parse(const utility::string_t& str, std::error_code& error) +web::json::value web::json::value::parse(utility::string_view_t str, std::error_code& error) { web::json::details::JSON_StringParser parser(str); web::json::details::JSON_Parser::Token tkn; diff --git a/Release/src/json/json_serialization.cpp b/Release/src/json/json_serialization.cpp index 83c1086e1f..9652bc23db 100644 --- a/Release/src/json/json_serialization.cpp +++ b/Release/src/json/json_serialization.cpp @@ -56,7 +56,7 @@ void web::json::value::format(std::basic_string& string) const { m_value-> template void web::json::details::append_escape_string(std::basic_string& str, - const std::basic_string& escaped) + utility::string_view escaped) { for (const auto& ch : escaped) { @@ -112,18 +112,18 @@ void web::json::details::append_escape_string(std::basic_string& str, } } -void web::json::details::format_string(const utility::string_t& key, utility::string_t& str) +void web::json::details::format_string(utility::string_view_t key, utility::string_t& str) { str.push_back('"'); - append_escape_string(str, key); + append_escape_string(str, key); str.push_back('"'); } #if defined(_UTF16_STRINGS) -void web::json::details::format_string(const utility::string_t& key, std::string& str) +void web::json::details::format_string(utility::string_view_t key, std::string& str) { str.push_back('"'); - append_escape_string(str, utility::conversions::to_utf8string(key)); + append_escape_string(str, utility::conversions::to_utf8string(key)); str.push_back('"'); } #endif @@ -134,7 +134,7 @@ void web::json::details::_String::format(std::basic_string& str) const if (m_has_escape_char) { - append_escape_string(str, utility::conversions::to_utf8string(m_string)); + append_escape_string(str, utility::conversions::to_utf8string(m_string)); } else { @@ -198,7 +198,7 @@ void web::json::details::_String::format(std::basic_string& str) const if (m_has_escape_char) { - append_escape_string(str, m_string); + append_escape_string(str, m_string); } else { diff --git a/Release/src/streams/fileio_win32.cpp b/Release/src/streams/fileio_win32.cpp index 129fd991de..82657d61bd 100644 --- a/Release/src/streams/fileio_win32.cpp +++ b/Release/src/streams/fileio_win32.cpp @@ -228,7 +228,11 @@ bool __cdecl _open_fsb_str(_In_ _filestream_callback* callback, _ASSERTE(callback != nullptr); _ASSERTE(filename != nullptr); - std::wstring name = conversions::to_utf16string(filename); + std::wstring name( +#if defined(CPPREST_FORCE_NARROW_STRINGS) + conversions::to_utf16string +#endif + (filename)); pplx::create_task([=]() { DWORD dwDesiredAccess, dwCreationDisposition, dwShareMode; diff --git a/Release/src/utilities/base64.cpp b/Release/src/utilities/base64.cpp index 89ccf43674..db419d5ec9 100644 --- a/Release/src/utilities/base64.cpp +++ b/Release/src/utilities/base64.cpp @@ -16,10 +16,10 @@ using namespace utility; -std::vector _from_base64(const utility::string_t& str); +std::vector _from_base64(utility::string_view_t str); utility::string_t _to_base64(const unsigned char* ptr, size_t size); -std::vector __cdecl conversions::from_base64(const utility::string_t& str) { return _from_base64(str); } +std::vector __cdecl conversions::from_base64(utility::string_view_t str) { return _from_base64(str); } utility::string_t __cdecl conversions::to_base64(const std::vector& input) { @@ -29,7 +29,7 @@ utility::string_t __cdecl conversions::to_base64(const std::vector _from_base64(const utility::string_t& input) +std::vector _from_base64(utility::string_view_t input) { std::vector result; @@ -127,7 +127,7 @@ std::vector _from_base64(const utility::string_t& input) } auto size = input.size(); - const char_t* ptr = &input[0]; + const char_t* ptr = input.data(); auto outsz = (size / 4) * 3; outsz -= padding; diff --git a/Release/src/utilities/string_utils.cpp b/Release/src/utilities/string_utils.cpp index 51751f224d..03f94f5e32 100644 --- a/Release/src/utilities/string_utils.cpp +++ b/Release/src/utilities/string_utils.cpp @@ -68,22 +68,22 @@ namespace utility { namespace details { -_ASYNCRTIMP bool __cdecl str_iequal(const std::string& left, const std::string& right) CPPREST_NOEXCEPT +_ASYNCRTIMP bool __cdecl str_iequal(utility::nstring_view_t left, utility::nstring_view_t 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 +_ASYNCRTIMP bool __cdecl str_iequal(utility::wstring_view_t left, utility::wstring_view_t 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 +_ASYNCRTIMP bool __cdecl str_iless(utility::nstring_view_t left, utility::nstring_view_t 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 +_ASYNCRTIMP bool __cdecl str_iless(utility::wstring_view_t left, utility::wstring_view_t right) CPPREST_NOEXCEPT { return std::lexicographical_compare(left.cbegin(), left.cend(), right.cbegin(), right.cend(), lt_lower_ch); } @@ -228,7 +228,7 @@ scoped_c_thread_locale::~scoped_c_thread_locale() // or unsigned. using UtilCharInternal_t = signed char; -inline size_t count_utf8_to_utf16(const std::string& s) +inline size_t count_utf8_to_utf16(utility::nstring_view_t s) { const size_t sSize = s.size(); auto const sData = reinterpret_cast(s.data()); @@ -313,7 +313,7 @@ inline size_t count_utf8_to_utf16(const std::string& s) return result; } -utf16string __cdecl conversions::utf8_to_utf16(const std::string& s) +utf16string __cdecl conversions::utf8_to_utf16(utility::nstring_view_t s) { // Save repeated heap allocations, use the length of resulting sequence. const size_t srcSize = s.size(); @@ -384,9 +384,9 @@ utf16string __cdecl conversions::utf8_to_utf16(const std::string& s) return dest; } -inline size_t count_utf16_to_utf8(const utf16string& w) +inline size_t count_utf16_to_utf8(utf16string_view w) { - const utf16string::value_type* const srcData = &w[0]; + const utf16string::value_type* const srcData = w.data(); const size_t srcSize = w.size(); size_t destSize(srcSize); for (size_t index = 0; index < srcSize; ++index) @@ -425,10 +425,10 @@ inline size_t count_utf16_to_utf8(const utf16string& w) return destSize; } -std::string __cdecl conversions::utf16_to_utf8(const utf16string& w) +std::string __cdecl conversions::utf16_to_utf8(utf16string_view w) { const size_t srcSize = w.size(); - const utf16string::value_type* const srcData = &w[0]; + const utf16string::value_type* const srcData = w.data(); std::string dest(count_utf16_to_utf8(w), '\0'); std::string::value_type* const destData = &dest[0]; size_t destIndex(0); @@ -481,13 +481,13 @@ std::string __cdecl conversions::utf16_to_utf8(const utf16string& w) return dest; } -utf16string __cdecl conversions::usascii_to_utf16(const std::string& s) +utf16string __cdecl conversions::usascii_to_utf16(utility::nstring_view_t 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) +utf16string __cdecl conversions::latin1_to_utf16(utility::nstring_view_t 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. @@ -502,7 +502,7 @@ utf16string __cdecl conversions::latin1_to_utf16(const std::string& s) return dest; } -utf8string __cdecl conversions::latin1_to_utf8(const std::string& s) { return utf16_to_utf8(latin1_to_utf16(s)); } +utf8string __cdecl conversions::latin1_to_utf8(utility::nstring_view_t 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)); } @@ -513,15 +513,15 @@ utility::string_t __cdecl conversions::to_string_t(std::string&& s) { return utf #endif #ifndef _UTF16_STRINGS -utility::string_t __cdecl conversions::to_string_t(const utf16string& s) { return utf16_to_utf8(s); } +utility::string_t __cdecl conversions::to_string_t(utf16string_view 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); } +utility::string_t __cdecl conversions::to_string_t(utility::nstring_view_t s) { return utf8_to_utf16(s); } #endif -std::string __cdecl conversions::to_utf8string(const utf16string& value) { return utf16_to_utf8(value); } +std::string __cdecl conversions::to_utf8string(utf16string_view value) { return utf16_to_utf8(value); } -utf16string __cdecl conversions::to_utf16string(const std::string& value) { return utf8_to_utf16(value); } +utf16string __cdecl conversions::to_utf16string(utility::nstring_view_t 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 67d15a343b..2096396e47 100644 --- a/Release/src/utilities/web_utilities.cpp +++ b/Release/src/utilities/web_utilities.cpp @@ -47,14 +47,14 @@ void winrt_secure_zero_buffer(Windows::Storage::Streams::IBuffer ^ buffer) } } -winrt_encryption::winrt_encryption(const ::utility::string_t& data) +winrt_encryption::winrt_encryption(utility::string_view_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<::utility::string_t::value_type*>(data.c_str())), + reinterpret_cast(const_cast<::utility::string_t::value_type*>(data.data())), static_cast(data.size()) * sizeof(::utility::string_t::value_type)); Windows::Storage::Streams::IBuffer ^ plaintext = Windows::Security::Cryptography::CryptographicBuffer::CreateFromByteArray(arrayref); @@ -91,7 +91,7 @@ plaintext_string winrt_encryption::decrypt() const #else // ^^^ __cplusplus_winrt ^^^ // vvv !__cplusplus_winrt vvv -win32_encryption::win32_encryption(const ::utility::string_t& data) : m_numCharacters(data.size()) +win32_encryption::win32_encryption(::utility::string_view_t data) : m_numCharacters(data.size()) { // Early return because CryptProtectMemory crashes with empty string if (m_numCharacters == 0) @@ -113,7 +113,7 @@ win32_encryption::win32_encryption(const ::utility::string_t& data) : m_numChara assert((dataNumBytes % CRYPTPROTECTMEMORY_BLOCK_SIZE) == 0); assert(dataNumBytes >= dataSizeDword); m_buffer.resize(dataNumBytes); - memcpy_s(m_buffer.data(), m_buffer.size(), data.c_str(), dataNumBytes); + memcpy_s(m_buffer.data(), m_buffer.size(), data.data(), dataNumBytes); if (!CryptProtectMemory(m_buffer.data(), dataNumBytes, CRYPTPROTECTMEMORY_SAME_PROCESS)) { throw ::utility::details::create_system_error(GetLastError()); diff --git a/Release/tests/functional/utils/win32_encryption_tests.cpp b/Release/tests/functional/utils/win32_encryption_tests.cpp index a2be7cde5a..8b77d18988 100644 --- a/Release/tests/functional/utils/win32_encryption_tests.cpp +++ b/Release/tests/functional/utils/win32_encryption_tests.cpp @@ -26,7 +26,7 @@ SUITE(win32_encryption) { TEST(win32_encryption_random_string) { - utility::string_t rndStr = utility::conversions::to_string_t("random string"); + const auto rndStr = utility::conversions::to_string_t("random string"); web::details::win32_encryption enc(rndStr); VERIFY_ARE_EQUAL(*enc.decrypt(), rndStr); @@ -34,7 +34,7 @@ SUITE(win32_encryption) TEST(win32_encryption_empty_string) { - utility::string_t emptyStr = utility::conversions::to_string_t(""); + const auto emptyStr = utility::conversions::to_string_t(""); web::details::win32_encryption enc(emptyStr); VERIFY_ARE_EQUAL(*enc.decrypt(), emptyStr); From 8c79add5a68e89038421260e5e696914f2a95769 Mon Sep 17 00:00:00 2001 From: Jason Hartman Date: Wed, 31 Jul 2019 17:20:01 -0700 Subject: [PATCH 11/19] Specify pipeline build options for CPPREST_USE_STRING_VIEWS - forced on for VS 2017 - forced off for VS 2015 - default for all others --- azure-pipelines.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 8c878f0901..eed202cd94 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -14,7 +14,7 @@ jobs: - task: CMake@1 inputs: workingDirectory: 'build.common' - cmakeArgs: '-DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake -DCPPREST_EXCLUDE_BROTLI=OFF ..' + cmakeArgs: '-DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake -DCPPREST_EXCLUDE_BROTLI=OFF -DCPPREST_USE_STRING_VIEWS=ON ..' - task: MSBuild@1 inputs: solution: 'build.common/ALL_BUILD.vcxproj' @@ -45,7 +45,7 @@ jobs: - task: CMake@1 inputs: workingDirectory: 'build.common' - cmakeArgs: '-A x64 -DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake -DCPPREST_EXCLUDE_BROTLI=OFF ..' + cmakeArgs: '-A x64 -DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake -DCPPREST_EXCLUDE_BROTLI=OFF -DCPPREST_USE_STRING_VIEWS=ON ..' - task: MSBuild@1 inputs: solution: 'build.common/ALL_BUILD.vcxproj' @@ -78,7 +78,7 @@ jobs: - task: CMake@1 inputs: workingDirectory: 'build.common' - cmakeArgs: '-A x64 -DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION=10.0 ..' + cmakeArgs: '-A x64 -DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION=10.0 -DCPPREST_USE_STRING_VIEWS=ON ..' - task: MSBuild@1 inputs: solution: 'build.common/ALL_BUILD.vcxproj' @@ -97,7 +97,7 @@ jobs: - task: CMake@1 inputs: workingDirectory: 'build.common' - cmakeArgs: '-DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake -DCPPREST_EXCLUDE_BROTLI=OFF ..' + cmakeArgs: '-DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake -DCPPREST_EXCLUDE_BROTLI=OFF -DCPPREST_USE_STRING_VIEWS=OFF ..' - task: MSBuild@1 inputs: solution: 'build.common/ALL_BUILD.vcxproj' @@ -128,7 +128,7 @@ jobs: - task: CMake@1 inputs: workingDirectory: 'build.common' - cmakeArgs: '-A x64 -DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake -DCPPREST_EXCLUDE_BROTLI=OFF ..' + cmakeArgs: '-A x64 -DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake -DCPPREST_EXCLUDE_BROTLI=OFF -DCPPREST_USE_STRING_VIEWS=OFF ..' - task: MSBuild@1 inputs: solution: 'build.common/ALL_BUILD.vcxproj' From 1dd421a0115d7e07ffb70338f046351aab4a8999 Mon Sep 17 00:00:00 2001 From: Jason Hartman Date: Fri, 2 Aug 2019 17:51:23 -0700 Subject: [PATCH 12/19] provide overload guidance for to_utf8/16string --- Release/include/cpprest/string_utils.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Release/include/cpprest/string_utils.h b/Release/include/cpprest/string_utils.h index 5149b488f8..e276194a68 100644 --- a/Release/include/cpprest/string_utils.h +++ b/Release/include/cpprest/string_utils.h @@ -150,6 +150,12 @@ inline utf16string_view to_utf16string(utf16string_view value) { return value; } /// A two byte character UTF-16 string. inline utf16string&& to_utf16string(utf16string&& value) { return std::move(value); } +#if CPPREST_USE_STRING_VIEWS +// Provide precise overload for string literals to resolve ambiguity of other overloads. +template +inline auto to_utf16string(const CharType * s) { return to_utf16string(std::basic_string_view(s)); } +#endif + /// /// Converts to a UTF-8 string. /// @@ -174,6 +180,12 @@ inline utility::nstring_view_t to_utf8string(utility::nstring_view_t value) { re /// A single byte character UTF-8 string. _ASYNCRTIMP std::string __cdecl to_utf8string(utf16string_view value); +#if CPPREST_USE_STRING_VIEWS +// Provide precise overload for string literals to resolve ambiguity of other overloads. +template +inline auto to_utf8string(const CharType * s) { return to_utf8string(std::basic_string_view(s)); } +#endif + template CASABLANCA_DEPRECATED("All locale-sensitive APIs will be removed in a future update. Use stringstreams directly if " "locale support is required.") From 252889b53c55d87e0877fc66c6f4c29a256cedfd Mon Sep 17 00:00:00 2001 From: Jason Hartman Date: Fri, 2 Aug 2019 17:52:37 -0700 Subject: [PATCH 13/19] account for C++11 standard default for some toolsets + add respect for CMAKE_CXX_STANDARD when set --- Release/CMakeLists.txt | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/Release/CMakeLists.txt b/Release/CMakeLists.txt index 9798985e8b..c15bc7df6e 100644 --- a/Release/CMakeLists.txt +++ b/Release/CMakeLists.txt @@ -15,8 +15,23 @@ set(CPPREST_VERSION_REVISION 14) # Note: when bumping CMake version to 3.3 or higher if(... IN_LIST ...) may be used list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_std_17 COMPILER_HAS_CXX_STD_17) +set(CPPREST_USE_STRING_VIEWS_DEFAULT_PER_CXX_STANDARD OFF) if(COMPILER_HAS_CXX_STD_17 EQUAL "-1") - set(CPPREST_USE_STRING_VIEWS_DEFAULT_PER_CXX_STANDARD OFF) + if(CPPREST_USE_STRING_VIEWS) + if(CMAKE_VERSION VERSION_LESS 3.8) + message(FATAL_ERROR "CPPREST_USE_STRING_VIEWS cannot be enabled. CMake 3.8 or higher required to support C++17.") + else() + message(FATAL_ERROR "CPPREST_USE_STRING_VIEWS cannot be enabled. Compiler (${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}) does not support C++17.") + endif() + endif() +elseif(CMAKE_CXX_STANDARD LESS 17) + if(CPPREST_USE_STRING_VIEWS) + message(FATAL_ERROR "CPPREST_USE_STRING_VIEWS cannot be enabled when C++ standard is less than 17") + endif() +elseif((NOT CMAKE_CXX_STANDARD GREATER 16.99) AND (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR IOS OR CMAKE_CXX_COMPILER_ID MATCHES "GNU")) + if(CPPREST_USE_STRING_VIEWS) + message(FATAL_ERROR "CPPREST_USE_STRING_VIEWS cannot be enabled without setting C++ standard to 17 or greater for current configuration") # see compiler specific settings below + endif() else() set(CPPREST_USE_STRING_VIEWS_DEFAULT_PER_CXX_STANDARD ON) endif() @@ -174,6 +189,15 @@ else() endif() # Compiler (not platform) specific settings +if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR IOS OR CMAKE_CXX_COMPILER_ID MATCHES "GNU") + if(NOT CMAKE_CXX_STANDARD GREATER 0) + if(CPPREST_USE_STRING_VIEWS) + message(FATAL_ERROR "internal cpprestsdk cmake error: CPPREST_USE_STRING_VIEWS ON while C++ standard not set") + endif() + set(CMAKE_CXX_STANDARD 11) + set(CMAKE_CXX_STANDARD_REQUIRED ON) + endif() +endif() if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR IOS) message("-- Setting clang options") @@ -191,10 +215,10 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR IOS) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++ -Wno-return-type-c-linkage -Wno-unneeded-internal-declaration") set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++") - set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++11") + set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++${CMAKE_CXX_STANDARD}") endif() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fno-strict-aliasing") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-strict-aliasing") elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU") message("-- Setting gcc options") @@ -202,7 +226,7 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU") set(WARNINGS -Wall -Wextra -Wunused-parameter -Wcast-align -Wcast-qual -Wconversion -Wformat=2 -Winit-self -Winvalid-pch -Wmissing-format-attribute -Wmissing-include-dirs -Wpacked -Wredundant-decls -Wunreachable-code) set(LD_FLAGS "${LD_FLAGS} -Wl,-z,defs") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fno-strict-aliasing") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-strict-aliasing") if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.8) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive -D_GLIBCXX_USE_SCHED_YIELD -D_GLIBCXX_USE_NANOSLEEP") endif() From 1db820847d34a18e2dc1736ab6cfc03b9163d446 Mon Sep 17 00:00:00 2001 From: Jason Hartman Date: Fri, 2 Aug 2019 18:49:49 -0700 Subject: [PATCH 14/19] suppress errorneous MSVC [15.6,16.0) C++17 deprecation warnings with asio --- Release/src/pch/stdafx.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Release/src/pch/stdafx.h b/Release/src/pch/stdafx.h index 372bc561ff..32ec27f36d 100644 --- a/Release/src/pch/stdafx.h +++ b/Release/src/pch/stdafx.h @@ -66,6 +66,15 @@ #include #endif // _WIN32 +// Suppress C++17 deprecation warning in aiso per https://github.com/chriskohlhoff/asio/issues/290#issuecomment-371867040 +// MSVC has address issue in 16.0 per https://devblogs.microsoft.com/cppblog/cpp17-20-features-and-fixes-in-vs-2019/ +#if _HAS_CXX17 && _MSC_VER >= 1913 && _MSC_VER < 1920 +#pragma push_macro("_SILENCE_CXX17_ALLOCATOR_VOID_DEPRECATION_WARNING") +#define _SILENCE_CXX17_ALLOCATOR_VOID_DEPRECATION_WARNING +#include +#pragma pop_macro("_SILENCE_CXX17_ALLOCATOR_VOID_DEPRECATION_WARNING") +#endif + // Macro indicating the C++ Rest SDK product itself is being built. // This is to help track how many developers are directly building from source themselves. #define _CASA_BUILD_FROM_SRC From 097873d0df0de12bce8dd7fbf45831e521c2cbfb Mon Sep 17 00:00:00 2001 From: Jason Hartman Date: Mon, 5 Aug 2019 11:09:49 -0700 Subject: [PATCH 15/19] alternate MSVC warning suppression --- Release/CMakeLists.txt | 7 +++++++ Release/src/pch/stdafx.h | 9 --------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/Release/CMakeLists.txt b/Release/CMakeLists.txt index c15bc7df6e..50e66725f5 100644 --- a/Release/CMakeLists.txt +++ b/Release/CMakeLists.txt @@ -251,6 +251,13 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") if (NOT (MSVC_VERSION LESS 1920)) add_compile_options(/permissive-) endif() + + # Suppress C++17 deprecation warning in aiso per https://github.com/chriskohlhoff/asio/issues/290#issuecomment-371867040 + # MSVC has addressed issue in 16.0 per https://devblogs.microsoft.com/cppblog/cpp17-20-features-and-fixes-in-vs-2019/ + if(MSVC_VERSION GREATER 1912 AND MSVC_VERSION LESS 1920) + add_definitions(-D_SILENCE_CXX17_ALLOCATOR_VOID_DEPRECATION_WARNING) + endif() + else() message("-- Unknown compiler, success is doubtful.") message("CMAKE_CXX_COMPILER_ID=${CMAKE_CXX_COMPILER_ID}") diff --git a/Release/src/pch/stdafx.h b/Release/src/pch/stdafx.h index 32ec27f36d..372bc561ff 100644 --- a/Release/src/pch/stdafx.h +++ b/Release/src/pch/stdafx.h @@ -66,15 +66,6 @@ #include #endif // _WIN32 -// Suppress C++17 deprecation warning in aiso per https://github.com/chriskohlhoff/asio/issues/290#issuecomment-371867040 -// MSVC has address issue in 16.0 per https://devblogs.microsoft.com/cppblog/cpp17-20-features-and-fixes-in-vs-2019/ -#if _HAS_CXX17 && _MSC_VER >= 1913 && _MSC_VER < 1920 -#pragma push_macro("_SILENCE_CXX17_ALLOCATOR_VOID_DEPRECATION_WARNING") -#define _SILENCE_CXX17_ALLOCATOR_VOID_DEPRECATION_WARNING -#include -#pragma pop_macro("_SILENCE_CXX17_ALLOCATOR_VOID_DEPRECATION_WARNING") -#endif - // Macro indicating the C++ Rest SDK product itself is being built. // This is to help track how many developers are directly building from source themselves. #define _CASA_BUILD_FROM_SRC From 357d3b7cb3cd2a2827b2578b879da8138ac74f35 Mon Sep 17 00:00:00 2001 From: Jason Hartman Date: Fri, 23 Aug 2019 14:05:32 -0700 Subject: [PATCH 16/19] remove CPPREST_FORCE_NARROW_STRINGS option --- Release/CMakeLists.txt | 23 ------------------- Release/include/cpprest/details/basic_types.h | 2 +- Release/src/CMakeLists.txt | 21 ++++++----------- Release/tests/functional/CMakeLists.txt | 8 +------ 4 files changed, 9 insertions(+), 45 deletions(-) diff --git a/Release/CMakeLists.txt b/Release/CMakeLists.txt index c6011dcf5a..4b6433a93a 100644 --- a/Release/CMakeLists.txt +++ b/Release/CMakeLists.txt @@ -20,7 +20,6 @@ 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.") @@ -113,31 +112,9 @@ 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 diff --git a/Release/include/cpprest/details/basic_types.h b/Release/include/cpprest/details/basic_types.h index 71b4f78aad..5630d61cb1 100644 --- a/Release/include/cpprest/details/basic_types.h +++ b/Release/include/cpprest/details/basic_types.h @@ -32,7 +32,7 @@ namespace utility { -#if defined(_WIN32) && !defined(CPPREST_FORCE_NARROW_STRINGS) +#if defined(_WIN32) #define _UTF16_STRINGS #endif diff --git a/Release/src/CMakeLists.txt b/Release/src/CMakeLists.txt index 3d958cd506..9fd55fe882 100644 --- a/Release/src/CMakeLists.txt +++ b/Release/src/CMakeLists.txt @@ -15,17 +15,6 @@ set(SOURCES ${HEADERS_PPLX} ${HEADERS_DETAILS} pch/stdafx.h - json/json.cpp - json/json_parsing.cpp - json/json_serialization.cpp - utilities/asyncrt_utils.cpp - utilities/base64.cpp - utilities/string_utils.cpp - utilities/web_utilities.cpp -) - -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 @@ -40,10 +29,16 @@ LIST(APPEND 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/string_utils.cpp + utilities/web_utilities.cpp ) -endif() add_library(cpprest ${SOURCES}) target_include_directories(cpprest @@ -131,7 +126,6 @@ else() endif() # Http client component -if(NOT CPPREST_EXCLUDE_HTTP_NARROW_STRING_WIP) if(CPPREST_HTTP_CLIENT_IMPL STREQUAL "asio") cpprest_find_boost() cpprest_find_openssl() @@ -152,7 +146,6 @@ elseif(CPPREST_HTTP_CLIENT_IMPL STREQUAL "winrt") else() message(FATAL_ERROR "Invalid implementation") endif() -endif() # fileio streams component if(CPPREST_FILEIO_IMPL STREQUAL "win32") diff --git a/Release/tests/functional/CMakeLists.txt b/Release/tests/functional/CMakeLists.txt index 9fa83f0a68..cc89052590 100644 --- a/Release/tests/functional/CMakeLists.txt +++ b/Release/tests/functional/CMakeLists.txt @@ -1,13 +1,7 @@ -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) -if(NOT CPPREST_EXCLUDE_HTTP_NARROW_STRING_WIP) -add_subdirectory(websockets) -endif() +add_subdirectory(websockets) \ No newline at end of file From 1c5f829b9343b1ee8722d9e29f1f5d0fb84ba2fb Mon Sep 17 00:00:00 2001 From: Jason Hartman Date: Mon, 26 Aug 2019 15:07:26 -0700 Subject: [PATCH 17/19] nudge pipeline to rerun From 697050f5c8e7df89c6da31b0bd1494fdd57f5b6d Mon Sep 17 00:00:00 2001 From: Jason Hartman Date: Mon, 26 Aug 2019 16:25:00 -0700 Subject: [PATCH 18/19] nudge pipeline to rerun From 5957e3a6c3d44a159c846be363d17897ce46ab3c Mon Sep 17 00:00:00 2001 From: Jason Hartman Date: Fri, 30 Aug 2019 11:50:25 -0700 Subject: [PATCH 19/19] nudge pipeline to rerun