From 363168a6f431693001fe6b7e7bb3c8434643f0ed Mon Sep 17 00:00:00 2001 From: Jason Hartman Date: Wed, 10 Jul 2019 11:00:43 -0700 Subject: [PATCH 01/18] 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/18] 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/18] 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/18] 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/18] 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/18] 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/18] 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/18] 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/18] nudge pipeline to rerun From 1a29dba4ca2aac7f19f9e9de535baae83523f6ae Mon Sep 17 00:00:00 2001 From: Jason Hartman Date: Tue, 23 Jul 2019 12:37:03 -0700 Subject: [PATCH 10/18] On isolated_components: Add option to build components in isolated libraries fixup includes from not using a common precompiled header - separate windows header config to be usable outside of pch --- Release/CMakeLists.txt | 10 +- .../include/cpprest/details/web_utilities.h | 1 + Release/include/pplx/pplxlinux.h | 4 + Release/include/pplx/pplxwin.h | 4 + Release/src/CMakeLists.txt | 194 +++++++++++++++--- Release/src/internal/windows_config.h | 40 ++++ Release/src/json/json.cpp | 2 + Release/src/json/json_parsing.cpp | 3 + Release/src/json/json_serialization.cpp | 3 + Release/src/nopch/stdafx.h | 17 ++ Release/src/pch/stdafx.h | 25 +-- Release/src/pplx/pplxwin.cpp | 9 +- Release/src/pplx/threadpool.cpp | 6 +- Release/src/streams/fileio_win32.cpp | 6 +- Release/src/utilities/asyncrt_utils.cpp | 4 + Release/src/utilities/web_utilities.cpp | 11 +- .../tests/common/UnitTestpp/CMakeLists.txt | 2 +- Release/tests/functional/json/CMakeLists.txt | 6 +- .../functional/pplx/pplx_test/CMakeLists.txt | 2 +- .../tests/functional/streams/CMakeLists.txt | 2 +- Release/tests/functional/utils/CMakeLists.txt | 2 +- Release/tests/functional/utils/macro_test.cpp | 1 + Release/tests/functional/utils/stdafx.h | 1 - azure-pipelines.yml | 30 ++- 24 files changed, 315 insertions(+), 70 deletions(-) create mode 100644 Release/src/internal/windows_config.h create mode 100644 Release/src/nopch/stdafx.h diff --git a/Release/CMakeLists.txt b/Release/CMakeLists.txt index 65d2114063..f7a557aa1b 100644 --- a/Release/CMakeLists.txt +++ b/Release/CMakeLists.txt @@ -23,6 +23,7 @@ set(CPPREST_EXPORT_DIR cpprestsdk CACHE STRING "Directory to install CMake confi option(CPPREST_FORCE_NARROW_STRINGS "Keep strings narrow/UTF8 (even if WIN32)" OFF) set(CPPREST_INSTALL_HEADERS ON CACHE BOOL "Install header files.") set(CPPREST_INSTALL ON CACHE BOOL "Add install commands.") +option(CPPREST_ISOLATE_COMPONENTS "Build cpprest components as individual libraries" OFF) if(IOS OR ANDROID) set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build shared libraries") @@ -235,7 +236,8 @@ if(NOT PARENT_DIR STREQUAL "") endif() # Finally, the tests all use the same style declaration to build themselves, so we use a function -function(add_casablanca_test NAME SOURCES_VAR) +# Tests that don't specify IMPLEMENTATION_TARGETS are assumed to depend on whole of cpprest. +function(add_casablanca_test NAME SOURCES_VAR) # [optional] IMPLEMENTATION_TARGETS... add_library(${NAME} ${TEST_LIBRARY_TARGET_TYPE} ${${SOURCES_VAR}}) message("-- Added test library ${NAME}") if(TEST_LIBRARY_TARGET_TYPE STREQUAL "OBJECT") @@ -244,8 +246,12 @@ function(add_casablanca_test NAME SOURCES_VAR) target_compile_definitions(${NAME} PRIVATE $) endforeach() else() + set(IMPLEMENTATION_TARGETS cpprest) + if(CPPREST_ISOLATE_COMPONENTS AND ${ARGC} GREATER 2) + set(IMPLEMENTATION_TARGETS ${ARGN}) + endif() target_link_libraries(${NAME} PRIVATE - cpprest + ${IMPLEMENTATION_TARGETS} common_utilities unittestpp ${ANDROID_LIBS} diff --git a/Release/include/cpprest/details/web_utilities.h b/Release/include/cpprest/details/web_utilities.h index d7c7fdb36b..f697add4f8 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 "pplx/pplxtasks.h" #include namespace web diff --git a/Release/include/pplx/pplxlinux.h b/Release/include/pplx/pplxlinux.h index 5aca316e45..7a0027b0f3 100644 --- a/Release/include/pplx/pplxlinux.h +++ b/Release/include/pplx/pplxlinux.h @@ -17,6 +17,10 @@ #error This file must not be included for Visual Studio #endif +#if !defined(_PPLX_H) +#error Include pplx.h instead of pplxlinux.h directly. +#endif + #ifndef _WIN32 #include "cpprest/details/cpprest_compat.h" diff --git a/Release/include/pplx/pplxwin.h b/Release/include/pplx/pplxwin.h index 95a23b3158..c52098a87a 100644 --- a/Release/include/pplx/pplxwin.h +++ b/Release/include/pplx/pplxwin.h @@ -13,6 +13,10 @@ #pragma once +#if !defined(_PPLX_H) +#error Include pplx.h instead of pplxwin.h directly. +#endif + #if !defined(_WIN32) || _MSC_VER < 1800 || CPPREST_FORCE_PPLX #include "cpprest/details/cpprest_compat.h" diff --git a/Release/src/CMakeLists.txt b/Release/src/CMakeLists.txt index 79af527c73..66feb7534b 100644 --- a/Release/src/CMakeLists.txt +++ b/Release/src/CMakeLists.txt @@ -15,13 +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) @@ -45,15 +38,149 @@ LIST(APPEND SOURCES ) endif() +# Targets for properties common to all cpprestsdk libraries +add_library(cpprest_interface_PUBLIC INTERFACE) +target_include_directories(cpprest_interface_PUBLIC + INTERFACE + $ +) +add_library(cpprest_interface_PRIVATE INTERFACE) +target_include_directories(cpprest_interface_PRIVATE + INTERFACE + $ +) + add_library(cpprest ${SOURCES}) target_include_directories(cpprest PUBLIC - $ $ + $ PRIVATE pch ) +target_link_libraries(cpprest PUBLIC cpprest_interface_PUBLIC PRIVATE cpprest_interface_PRIVATE) +set(CPPREST_TARGETS cpprest cpprest_interface_PUBLIC) ## Sub-components + +# add_sub_component(name sources...) +# When CPPREST_ISOLATE_COMPONENTS is ON: +# Creates library ${name} using given sources. Then adds respective +# object files to cpprest. +# Otherwise sources are added to cpprest directly. +function(add_sub_component name) # sources... + set(COMPONENT_SOURCES ${ARGN}) + + # cpprest and this new library inherit these properties publicly. + add_library(${name}_properties_PUBLIC INTERFACE) + target_link_libraries(${name}_properties_PUBLIC INTERFACE cpprest_interface_PUBLIC) + # cpprest and this new library inherit these properties privately. + add_library(${name}_properties_PRIVATE INTERFACE) + target_link_libraries(${name}_properties_PRIVATE INTERFACE cpprest_interface_PRIVATE) + + if(CPPREST_ISOLATE_COMPONENTS) + # isolated components are built as OBJECT_LIBRARY so that cpprest library + # may be self contained (apart from external dependencies) and sources are + # still only compiled once. + add_library(${name}_objects OBJECT ${COMPONENT_SOURCES}) + # disable pch for isolated builds to ensure dependencies are explict and + # to avoid contamination across components by setting include path to + # reach primitive (ideally empty) stdafx.h. + target_include_directories(${name}_objects + PRIVATE + nopch + ) + target_link_libraries(${name}_objects PRIVATE ${name}_properties_PUBLIC ${name}_properties_PRIVATE) + + # create library of sub-component + add_library(${name} $) + target_link_libraries(${name} PUBLIC ${name}_properties_PUBLIC PRIVATE ${name}_properties_PRIVATE) + + # connect sources to cpprest (main target) + target_sources(cpprest PRIVATE $) + else() + # no isolation, just build sources as part of cpprest + target_sources(cpprest PRIVATE ${COMPONENT_SOURCES}) + + # do create a dummy interface library for sub-components to specify other + # sub-components in sub_component_link_libraries + add_library(${name} INTERFACE) + # also add to target install list in case there is such use + list(APPEND CPPREST_TARGETS ${name}) + endif() + + target_link_libraries(cpprest PUBLIC ${name}_properties_PUBLIC PRIVATE ${name}_properties_PRIVATE) + + # append public properties (interface) target to install list + # sub-component libraries (isolation build only) are not installed + list(APPEND CPPREST_TARGETS ${name}_properties_PUBLIC) + set(CPPREST_TARGETS ${CPPREST_TARGETS} PARENT_SCOPE) +endfunction() + +# sub_component_sources(name sources...) +# Adds given sources to sub-component library and/or cpprest. +function(sub_component_sources name) # additional sources... + if(CPPREST_ISOLATE_COMPONENTS) + target_sources(${name}_objects ${ARGN}) + else() + # no actual sub-component targets built when not isolated; pass along + # sources to cpprest + target_sources(cpprest ${ARGN}) + endif() +endfunction() + +# sub_component_link_libraries(name link_dependencies...) +# Adds given link_dependencies to sub-component library and/or cpprest. +function(sub_component_link_libraries name) # link dependencies... + if(CPPREST_ISOLATE_COMPONENTS) + target_link_libraries(${name}_objects ${ARGN}) + target_link_libraries(${name} ${ARGN}) + # remove entries in list that are our own sub-components + # before passing up to cpprest + set(ALL_LINK_ARGS ${ARGN}) + foreach(LINK_ARG ${ALL_LINK_ARGS}) + if(TARGET ${LINK_ARG}_properties_PRIVATE) + list(REMOVE_ITEM ARGN ${LINK_ARG}) + endif() + endforeach() + else() + # no actual sub-component targets built when not isolated + endif() + # pass along dependencies to cpprest in all cases + # (in isolated case only objects are referenced, so dependencies + # need to be passed up too) + target_link_libraries(cpprest ${ARGN}) +endfunction() + + +# Utility components +add_sub_component(cpprest_utility_strings + utilities/string_utils.cpp +) + +add_sub_component(cpprest_utility_asyncrt + utilities/asyncrt_utils.cpp +) +sub_component_link_libraries(cpprest_utility_asyncrt PUBLIC cpprest_utility_strings) + +add_sub_component(cpprest_utilities + utilities/base64.cpp + utilities/web_utilities.cpp +) +sub_component_link_libraries(cpprest_utilities PUBLIC cpprest_utility_asyncrt cpprest_utility_strings) +if(WIN32 AND NOT WINDOWS_STORE AND NOT WINDOWS_PHONE) + sub_component_link_libraries(cpprest_utilities PRIVATE + crypt32.lib + ) +endif() + +# Json component +add_sub_component(cpprest_json + json/json.cpp + json/json_parsing.cpp + json/json_serialization.cpp +) +sub_component_link_libraries(cpprest_json PUBLIC cpprest_utility_strings) + # Websockets component if(CPPREST_WEBSOCKETS_IMPL STREQUAL "none") target_compile_definitions(cpprest PUBLIC -DCPPREST_EXCLUDE_WEBSOCKETS=1) @@ -100,35 +227,43 @@ endif() if(CPPREST_PPLX_IMPL STREQUAL "apple") find_library(COREFOUNDATION CoreFoundation "/") find_library(SECURITY Security "/") - target_link_libraries(cpprest PUBLIC ${COREFOUNDATION} ${SECURITY}) - target_sources(cpprest PRIVATE pplx/pplxapple.cpp pplx/pplx.cpp pplx/threadpool.cpp ../include/pplx/threadpool.h) + add_sub_component(cpprest_pplx pplx/pplxapple.cpp pplx/pplx.cpp pplx/threadpool.cpp ../include/pplx/threadpool.h) + sub_component_link_libraries(cpprest_pplx PUBLIC ${COREFOUNDATION} ${SECURITY}) if(CPPREST_INSTALL_HEADERS) install(FILES ../include/pplx/threadpool.h DESTINATION include/pplx) endif() elseif(CPPREST_PPLX_IMPL STREQUAL "linux") - target_sources(cpprest PRIVATE pplx/pplxlinux.cpp pplx/pplx.cpp pplx/threadpool.cpp ../include/pplx/threadpool.h) + add_sub_component(cpprest_pplx pplx/pplxlinux.cpp pplx/pplx.cpp pplx/threadpool.cpp ../include/pplx/threadpool.h) if(CPPREST_INSTALL_HEADERS) install(FILES ../include/pplx/threadpool.h DESTINATION include/pplx) endif() elseif(CPPREST_PPLX_IMPL STREQUAL "win") - target_sources(cpprest PRIVATE pplx/pplxwin.cpp) + add_sub_component(cpprest_pplx pplx/pplxwin.cpp) if(CPPREST_WEBSOCKETS_IMPL STREQUAL "wspp") - target_sources(cpprest PRIVATE pplx/threadpool.cpp ../include/pplx/threadpool.h) + sub_component_sources(cpprest_pplx PRIVATE pplx/threadpool.cpp ../include/pplx/threadpool.h) if(CPPREST_INSTALL_HEADERS) install(FILES ../include/pplx/threadpool.h DESTINATION include/pplx) endif() endif() elseif(CPPREST_PPLX_IMPL STREQUAL "winpplx") - target_compile_definitions(cpprest PUBLIC -DCPPREST_FORCE_PPLX=1) - target_sources(cpprest PRIVATE pplx/pplxwin.cpp pplx/pplx.cpp pplx/threadpool.cpp ../include/pplx/threadpool.h) - if(CPPREST_INSTALL_HEADERS) - install(FILES ../include/pplx/threadpool.h DESTINATION include/pplx) + add_sub_component(cpprest_pplx pplx/pplxwin.cpp pplx/pplx.cpp) + target_compile_definitions(cpprest_pplx_properties_PUBLIC INTERFACE -DCPPREST_FORCE_PPLX=1) + if(NOT CPPREST_WEBSOCKETS_IMPL STREQUAL "none") + sub_component_sources(cpprest_pplx PRIVATE pplx/threadpool.cpp ../include/pplx/threadpool.h) + if(CPPREST_INSTALL_HEADERS) + install(FILES ../include/pplx/threadpool.h DESTINATION include/pplx) + endif() endif() elseif(CPPREST_PPLX_IMPL STREQUAL "winrt") - target_sources(cpprest PRIVATE pplx/pplxwin.cpp) + add_sub_component(cpprest_pplx pplx/pplxwin.cpp) else() message(FATAL_ERROR "Invalid implementation") endif() +if(NOT CPPREST_PPLX_IMPL STREQUAL "winrt") + cpprest_find_boost() + sub_component_link_libraries(cpprest_pplx PUBLIC cpprestsdk_boost_internal) +endif() +sub_component_link_libraries(cpprest_pplx PUBLIC cpprest_utility_asyncrt) # Http client component if(NOT CPPREST_EXCLUDE_HTTP_NARROW_STRING_WIP) @@ -156,14 +291,15 @@ endif() # fileio streams component if(CPPREST_FILEIO_IMPL STREQUAL "win32") - target_sources(cpprest PRIVATE streams/fileio_win32.cpp) + add_sub_component(cpprest_streams streams/fileio_win32.cpp) elseif(CPPREST_FILEIO_IMPL STREQUAL "winrt") - target_sources(cpprest PRIVATE streams/fileio_winrt.cpp) + add_sub_component(cpprest_streams streams/fileio_winrt.cpp) elseif(CPPREST_FILEIO_IMPL STREQUAL "posix") - target_sources(cpprest PRIVATE streams/fileio_posix.cpp) + add_sub_component(cpprest_streams streams/fileio_posix.cpp) else() message(FATAL_ERROR "Invalid implementation") endif() +sub_component_link_libraries(cpprest_streams PUBLIC cpprest_utility_asyncrt) # http listener component if(CPPREST_HTTP_LISTENER_IMPL STREQUAL "asio") @@ -197,12 +333,12 @@ endif() if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU") if(WERROR) - target_compile_options(cpprest PRIVATE -Werror) + target_compile_options(cpprest_interface_PRIVATE INTERFACE -Werror) endif() - target_compile_options(cpprest PRIVATE -pedantic ${WARNINGS}) + target_compile_options(cpprest_interface_PRIVATE INTERFACE -pedantic ${WARNINGS}) elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") if(WERROR) - target_compile_options(cpprest PRIVATE /WX ${WARNINGS}) + target_compile_options(cpprest_interface_PRIVATE INTERFACE /WX ${WARNINGS}) endif() else() message(FATAL_ERROR "Unknown compiler") @@ -210,22 +346,21 @@ endif() if(WIN32) if (BUILD_SHARED_LIBS) - target_compile_definitions(cpprest PRIVATE -D_ASYNCRT_EXPORT -D_PPLX_EXPORT -D_USRDLL) + target_compile_definitions(cpprest_interface_PRIVATE INTERFACE -D_ASYNCRT_EXPORT -D_PPLX_EXPORT -D_USRDLL) else() - target_compile_definitions(cpprest PUBLIC -D_NO_ASYNCRTIMP -D_NO_PPLXIMP) + target_compile_definitions(cpprest_interface_PUBLIC INTERFACE -D_NO_ASYNCRTIMP -D_NO_PPLXIMP) endif() elseif(ANDROID) - target_link_libraries(cpprest PRIVATE ${ANDROID_STL_FLAGS}) + target_link_libraries(cpprest_interface_PRIVATE INTERFACE ${ANDROID_STL_FLAGS}) endif() if (WIN32 AND NOT WINDOWS_STORE AND NOT WINDOWS_PHONE) target_link_libraries(cpprest PRIVATE bcrypt.lib - crypt32.lib ) elseif(WINDOWS_STORE) if(NOT CMAKE_GENERATOR MATCHES "Visual Studio .*") - target_compile_definitions(cpprest PRIVATE -DWINAPI_FAMILY=WINAPI_FAMILY_PC_APP) + target_compile_definitions(cpprest_interface_PRIVATE INTERFACE -DWINAPI_FAMILY=WINAPI_FAMILY_PC_APP) get_target_property(LINK_FLAGS cpprest LINK_FLAGS) if(NOT LINK_FLAGS) set(LINK_FLAGS "") @@ -257,7 +392,6 @@ if(CPPREST_INSTALL) set(CPPREST_USES_BROTLI OFF) set(CPPREST_USES_OPENSSL OFF) - set(CPPREST_TARGETS cpprest) if(TARGET cpprestsdk_boost_internal) list(APPEND CPPREST_TARGETS cpprestsdk_boost_internal) set(CPPREST_USES_BOOST ON) diff --git a/Release/src/internal/windows_config.h b/Release/src/internal/windows_config.h new file mode 100644 index 0000000000..a726e4f17b --- /dev/null +++ b/Release/src/internal/windows_config.h @@ -0,0 +1,40 @@ +/*** +* Copyright (C) Microsoft. All rights reserved. +* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. +* +* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +* +* Internal headers +* +* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk +* +* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +****/ + +#pragma once + +#if !defined(_WIN32) +#error windows_config.h use only expected for Windows builds. (_WIN32 is not defined) +#endif + +// use the debug version of the CRT if _DEBUG is defined +#ifdef _DEBUG +#define _CRTDBG_MAP_ALLOC +#include +#endif // _DEBUG + +#include +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers + +#if CPPREST_TARGET_XP && _WIN32_WINNT != 0x0501 +#error CPPREST_TARGET_XP implies _WIN32_WINNT == 0x0501 +#endif // CPPREST_TARGET_XP && _WIN32_WINNT != 0x0501 + +#include + +#include + +// Windows Header Files: +#ifndef __cplusplus_winrt +#include +#endif !__cplusplus_winrt diff --git a/Release/src/json/json.cpp b/Release/src/json/json.cpp index ae640ae26d..b5262d26aa 100644 --- a/Release/src/json/json.cpp +++ b/Release/src/json/json.cpp @@ -13,6 +13,8 @@ #include "stdafx.h" +#include "cpprest/json.h" + using namespace web; bool json::details::g_keep_json_object_unsorted = false; diff --git a/Release/src/json/json_parsing.cpp b/Release/src/json/json_parsing.cpp index 2e0d71e6d3..b6ab5e2ac1 100644 --- a/Release/src/json/json_parsing.cpp +++ b/Release/src/json/json_parsing.cpp @@ -13,6 +13,9 @@ #include "stdafx.h" +#include "cpprest/json.h" + +#include #include #if defined(_MSC_VER) diff --git a/Release/src/json/json_serialization.cpp b/Release/src/json/json_serialization.cpp index 83c1086e1f..7a9617ec49 100644 --- a/Release/src/json/json_serialization.cpp +++ b/Release/src/json/json_serialization.cpp @@ -13,6 +13,9 @@ #include "stdafx.h" +#include "cpprest/json.h" + +#include #include #ifndef _WIN32 diff --git a/Release/src/nopch/stdafx.h b/Release/src/nopch/stdafx.h new file mode 100644 index 0000000000..d32bbd5137 --- /dev/null +++ b/Release/src/nopch/stdafx.h @@ -0,0 +1,17 @@ +/*** +* Copyright (C) Microsoft. All rights reserved. +* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. +* +* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +* +* Pre-compiled headers +* +* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk +* +* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +****/ + +#pragma once + +// There are no contents here -- in support of component isolation builds. + diff --git a/Release/src/pch/stdafx.h b/Release/src/pch/stdafx.h index 372bc561ff..ff414674e9 100644 --- a/Release/src/pch/stdafx.h +++ b/Release/src/pch/stdafx.h @@ -20,29 +20,8 @@ #endif #ifdef _WIN32 -// use the debug version of the CRT if _DEBUG is defined -#ifdef _DEBUG -#define _CRTDBG_MAP_ALLOC -#include -#endif // _DEBUG - -#include -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers - -#if CPPREST_TARGET_XP && _WIN32_WINNT != 0x0501 -#error CPPREST_TARGET_XP implies _WIN32_WINNT == 0x0501 -#endif // CPPREST_TARGET_XP && _WIN32_WINNT != 0x0501 - -#include - -#include - -// Windows Header Files: -#ifndef __cplusplus_winrt -#include -#endif !__cplusplus_winrt - -#else // LINUX or APPLE +#include "windows_config.h" +#else // LINUX or APPLE #define __STDC_LIMIT_MACROS #include "pthread.h" #include diff --git a/Release/src/pplx/pplxwin.cpp b/Release/src/pplx/pplxwin.cpp index e25d9acf34..c81b074472 100644 --- a/Release/src/pplx/pplxwin.cpp +++ b/Release/src/pplx/pplxwin.cpp @@ -15,7 +15,11 @@ #if !defined(_WIN32) || CPPREST_FORCE_PPLX -#include "pplx/pplxwin.h" +#include "pplx/pplx.h" +#include "pplx/pplxwin.h" // Note: Should already be included by way of pplx.h + +#include "cpprest/asyncrt_utils.h" +#include "windows_config.h" // Disable false alarm code analysis warning #pragma warning(disable : 26165 26110) @@ -242,6 +246,9 @@ _PPLXIMP void windows_scheduler::schedule(TaskProc_t proc, _In_ void* param) } // namespace pplx #else // ^^^ !defined(_WIN32) || CPPREST_FORCE_PPLX ^^^ // vvv defined(_WIN32) && !CPPREST_FORCE_PPLX vvv + +#include "pplx/pplxtasks.h" + namespace Concurrency { void __cdecl set_cpprestsdk_ambient_scheduler(const std::shared_ptr& _Scheduler) diff --git a/Release/src/pplx/threadpool.cpp b/Release/src/pplx/threadpool.cpp index ba38a1a12f..4fbea1ed93 100644 --- a/Release/src/pplx/threadpool.cpp +++ b/Release/src/pplx/threadpool.cpp @@ -4,7 +4,10 @@ **/ #include "stdafx.h" -#if !defined(CPPREST_EXCLUDE_WEBSOCKETS) || !defined(_WIN32) +#if defined(CPPREST_EXCLUDE_WEBSOCKETS) && defined(_WIN32) +#error CPPREST_EXCLUDE_WEBSOCKETS and WIN32, but still compiling threadpool.cpp +#endif + #include "pplx/threadpool.h" #include #include @@ -232,4 +235,3 @@ std::unique_ptr crossplat::threadpool::construct(size_t n { return std::unique_ptr(new threadpool_impl(num_threads)); } -#endif // !defined(CPPREST_EXCLUDE_WEBSOCKETS) || !defined(_WIN32) diff --git a/Release/src/streams/fileio_win32.cpp b/Release/src/streams/fileio_win32.cpp index 129fd991de..5ff5976754 100644 --- a/Release/src/streams/fileio_win32.cpp +++ b/Release/src/streams/fileio_win32.cpp @@ -19,10 +19,12 @@ #include "cpprest/details/fileio.h" -using namespace web; +#include "cpprest/asyncrt_utils.h" + +#include "windows_config.h" + using namespace utility; using namespace concurrency; -using namespace utility::conversions; namespace Concurrency { diff --git a/Release/src/utilities/asyncrt_utils.cpp b/Release/src/utilities/asyncrt_utils.cpp index d16531ce7a..72f3d97c3a 100644 --- a/Release/src/utilities/asyncrt_utils.cpp +++ b/Release/src/utilities/asyncrt_utils.cpp @@ -20,6 +20,10 @@ #include #include +#if defined(_WIN32) +#include "windows_config.h" +#endif + using namespace utility; namespace utility diff --git a/Release/src/utilities/web_utilities.cpp b/Release/src/utilities/web_utilities.cpp index 67d15a343b..39f09629d4 100644 --- a/Release/src/utilities/web_utilities.cpp +++ b/Release/src/utilities/web_utilities.cpp @@ -13,14 +13,19 @@ #include "stdafx.h" +#include "cpprest/details/web_utilities.h" + #include -#if defined(_WIN32) && !defined(__cplusplus_winrt) +#if defined(_WIN32) +#include "windows_config.h" + +#if !defined(__cplusplus_winrt) #include +#else +#include #endif -#if defined(__cplusplus_winrt) -#include #endif namespace web diff --git a/Release/tests/common/UnitTestpp/CMakeLists.txt b/Release/tests/common/UnitTestpp/CMakeLists.txt index 309c5f28fa..8cbda5b284 100644 --- a/Release/tests/common/UnitTestpp/CMakeLists.txt +++ b/Release/tests/common/UnitTestpp/CMakeLists.txt @@ -47,7 +47,7 @@ elseif(WIN32) endif() add_library(unittestpp ${UT_SOURCES}) -target_link_libraries(unittestpp PUBLIC cpprest) +target_link_libraries(unittestpp PUBLIC cpprest_interface_PUBLIC) if(UNIX) cpprest_find_boost() diff --git a/Release/tests/functional/json/CMakeLists.txt b/Release/tests/functional/json/CMakeLists.txt index 1d44a99ce6..61d443c69a 100644 --- a/Release/tests/functional/json/CMakeLists.txt +++ b/Release/tests/functional/json/CMakeLists.txt @@ -10,7 +10,11 @@ if(NOT WINDOWS_STORE AND NOT WINDOWS_PHONE) list(APPEND SOURCES fuzz_tests.cpp) endif() -add_casablanca_test(json_test SOURCES) +set(ADDITIONAL_COMPONENTS) +if(WIN32) + set(ADDITIONAL_COMPONENTS cpprest_streams) +endif() +add_casablanca_test(json_test SOURCES cpprest_json ${ADDITIONAL_COMPONENTS}) if(UNIX AND NOT APPLE) cpprest_find_boost() target_link_libraries(json_test PRIVATE cpprestsdk_boost_internal) diff --git a/Release/tests/functional/pplx/pplx_test/CMakeLists.txt b/Release/tests/functional/pplx/pplx_test/CMakeLists.txt index 0e2672b73e..a0d92f42e6 100644 --- a/Release/tests/functional/pplx/pplx_test/CMakeLists.txt +++ b/Release/tests/functional/pplx/pplx_test/CMakeLists.txt @@ -4,7 +4,7 @@ set(SOURCES pplxtask_tests.cpp ) -add_casablanca_test(pplx_test SOURCES) +add_casablanca_test(pplx_test SOURCES cpprest_pplx) if(MSVC) get_target_property(_srcs pplx_test SOURCES) diff --git a/Release/tests/functional/streams/CMakeLists.txt b/Release/tests/functional/streams/CMakeLists.txt index 29d09bbac8..7b16ed8466 100644 --- a/Release/tests/functional/streams/CMakeLists.txt +++ b/Release/tests/functional/streams/CMakeLists.txt @@ -14,7 +14,7 @@ else() endif() endif() -add_casablanca_test(streams_test SOURCES) +add_casablanca_test(streams_test SOURCES cpprest_streams) if(NOT WIN32 OR CPPREST_WEBSOCKETS_IMPL STREQUAL "wspp") cpprest_find_boost() if(NOT TEST_LIBRARY_TARGET_TYPE STREQUAL "OBJECT") diff --git a/Release/tests/functional/utils/CMakeLists.txt b/Release/tests/functional/utils/CMakeLists.txt index 201af77039..b3fa2dc7d6 100644 --- a/Release/tests/functional/utils/CMakeLists.txt +++ b/Release/tests/functional/utils/CMakeLists.txt @@ -7,7 +7,7 @@ set(SOURCES win32_encryption_tests.cpp ) -add_casablanca_test(utils_test SOURCES) +add_casablanca_test(utils_test SOURCES cpprest_utilities) if(CMAKE_COMPILER_IS_GNUCXX) target_compile_options(utils_test PRIVATE "-Wno-deprecated-declarations") diff --git a/Release/tests/functional/utils/macro_test.cpp b/Release/tests/functional/utils/macro_test.cpp index f45bc9f237..c27f0a29ed 100644 --- a/Release/tests/functional/utils/macro_test.cpp +++ b/Release/tests/functional/utils/macro_test.cpp @@ -15,6 +15,7 @@ #include "cpprest/http_client.h" #include "cpprest/http_msg.h" #include "cpprest/json.h" +#include "cpprest/uri.h" #include "cpprest/uri_builder.h" namespace tests diff --git a/Release/tests/functional/utils/stdafx.h b/Release/tests/functional/utils/stdafx.h index 40eb75f5a0..7f53de66f3 100644 --- a/Release/tests/functional/utils/stdafx.h +++ b/Release/tests/functional/utils/stdafx.h @@ -16,6 +16,5 @@ #include "cpprest/asyncrt_utils.h" #include "cpprest/details/web_utilities.h" -#include "cpprest/uri.h" #include "unittestpp.h" #include "utils_tests.h" diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 8c878f0901..5237d2c896 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -65,7 +65,28 @@ jobs: cd build.common\Release\Binaries\Release .\test_runner.exe *test.dll displayName: 'Run tests, release' - - job: Windows_VS2017_UWP + - script: mkdir build.isolated + displayName: Make Isolated Build Directory + - task: CMake@1 + inputs: + workingDirectory: 'build.isolated' + cmakeArgs: '-A x64 -DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake -DCPPREST_EXCLUDE_BROTLI=OFF -DCPPREST_ISOLATE_COMPONENTS=ON ..' + - task: MSBuild@1 + inputs: + solution: 'build.isolated/ALL_BUILD.vcxproj' + maximumCpuCount: true + platform: 'x64' + - script: | + cd build.isolated\Release\Binaries\Debug + .\test_runner.exe *testd.dll + displayName: 'Run isolated tests, debug' + - task: MSBuild@1 + inputs: + solution: 'build.isolated/ALL_BUILD.vcxproj' + maximumCpuCount: true + platform: 'x64' + configuration: 'Release' +- job: Windows_VS2017_UWP pool: vmImage: 'vs2017-win2016' steps: @@ -166,12 +187,19 @@ jobs: cd build.release /usr/local/bin/cmake -G Ninja -DCMAKE_BUILD_TYPE=Release .. cd .. + mkdir build.debug.isolated + cd build.debug.isolated + /usr/local/bin/cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug -DCPPREST_ISOLATE_COMPONENTS=ON .. + cd .. ninja -C build.debug ninja -C build.release + ninja -C build.debug.isolated cd build.debug/Release/Binaries ./test_runner *test.so cd ../../../build.release/Release/Binaries ./test_runner *test.so + cd ../../../build.debug.isolated/Release/Binaries + ./test_runner *test.so displayName: Run build - job: Ubuntu_1604_Vcpkg pool: From d2479ea1dae10f99c4e4bc9a9bd577338384ccee Mon Sep 17 00:00:00 2001 From: Jason Hartman Date: Tue, 23 Jul 2019 15:45:04 -0700 Subject: [PATCH 11/18] fix yaml indent --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 5237d2c896..35bbad6822 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -86,7 +86,7 @@ jobs: maximumCpuCount: true platform: 'x64' configuration: 'Release' -- job: Windows_VS2017_UWP + - job: Windows_VS2017_UWP pool: vmImage: 'vs2017-win2016' steps: From 734a1f117d409d8fa9ae2a49455ff21d3965cb32 Mon Sep 17 00:00:00 2001 From: Jason Hartman Date: Wed, 24 Jul 2019 12:04:20 -0700 Subject: [PATCH 12/18] fix build breaks - missing headers (stl/config dependent) - correct install for static lib builds also add isolation build to Ubuntu Vcpkg and break up Ubuntu Apt --- Release/src/CMakeLists.txt | 11 ++++++ Release/src/utilities/base64.cpp | 5 ++- Release/src/utilities/string_utils.cpp | 1 + azure-pipelines.yml | 51 +++++++++++++++++++++++++- 4 files changed, 64 insertions(+), 4 deletions(-) diff --git a/Release/src/CMakeLists.txt b/Release/src/CMakeLists.txt index 66feb7534b..1746b490ff 100644 --- a/Release/src/CMakeLists.txt +++ b/Release/src/CMakeLists.txt @@ -59,6 +59,12 @@ target_include_directories(cpprest ) target_link_libraries(cpprest PUBLIC cpprest_interface_PUBLIC PRIVATE cpprest_interface_PRIVATE) set(CPPREST_TARGETS cpprest cpprest_interface_PUBLIC) +if(NOT BUILD_SHARED_LIBS) + # for installed static libraries the private dependencies must also be + # installed, though those should be interfaces only. + list(APPEND CPPREST_TARGETS cpprest_interface_PRIVATE) +endif() + ## Sub-components @@ -113,6 +119,11 @@ function(add_sub_component name) # sources... # append public properties (interface) target to install list # sub-component libraries (isolation build only) are not installed list(APPEND CPPREST_TARGETS ${name}_properties_PUBLIC) + if(NOT BUILD_SHARED_LIBS) + # for installed static libraries the private dependencies must also be + # installed, though those should be interfaces only. + list(APPEND CPPREST_TARGETS ${name}_properties_PRIVATE) + endif() set(CPPREST_TARGETS ${CPPREST_TARGETS} PARENT_SCOPE) endfunction() diff --git a/Release/src/utilities/base64.cpp b/Release/src/utilities/base64.cpp index 89ccf43674..429c3ff24c 100644 --- a/Release/src/utilities/base64.cpp +++ b/Release/src/utilities/base64.cpp @@ -13,6 +13,7 @@ #include "cpprest/base64_utils.h" #include +#include using namespace utility; @@ -138,7 +139,7 @@ std::vector _from_base64(const utility::string_t& input) for (; size > 4; ++idx) { unsigned char target[3]; - memset(target, 0, sizeof(target)); + std::memset(target, 0, sizeof(target)); _triple_byte* record = reinterpret_cast<_triple_byte*>(target); unsigned char val0 = _base64_dectbl[ptr[0]]; @@ -167,7 +168,7 @@ std::vector _from_base64(const utility::string_t& input) { unsigned char target[3]; - memset(target, 0, sizeof(target)); + std::memset(target, 0, sizeof(target)); _triple_byte* record = reinterpret_cast<_triple_byte*>(target); unsigned char val0 = _base64_dectbl[ptr[0]]; diff --git a/Release/src/utilities/string_utils.cpp b/Release/src/utilities/string_utils.cpp index 51751f224d..87f0edb415 100644 --- a/Release/src/utilities/string_utils.cpp +++ b/Release/src/utilities/string_utils.cpp @@ -15,6 +15,7 @@ #include +#include #include #include #include diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 35bbad6822..3d3c676863 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -191,16 +191,39 @@ jobs: cd build.debug.isolated /usr/local/bin/cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug -DCPPREST_ISOLATE_COMPONENTS=ON .. cd .. + mkdir build.release.isolated + cd build.release.isolated + /usr/local/bin/cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DCPPREST_ISOLATE_COMPONENTS=ON .. + cd .. + displayName: Run build generate + - script: | ninja -C build.debug + displayName: 'Run ninja, debug' + - script: | ninja -C build.release + displayName: 'Run ninja, release' + - script: | ninja -C build.debug.isolated + displayName: 'Run ninja, isolated debug' + - script: | + ninja -C build.release.isolated + displayName: 'Run ninja, isolated release' + - script: | cd build.debug/Release/Binaries ./test_runner *test.so - cd ../../../build.release/Release/Binaries + displayName: 'Run tests, debug' + - script: | + cd build.release/Release/Binaries ./test_runner *test.so + displayName: 'Run tests, release' + - script: | cd ../../../build.debug.isolated/Release/Binaries ./test_runner *test.so - displayName: Run build + displayName: 'Run tests, isolated debug' + - script: | + cd ../../../build.release.isolated/Release/Binaries + ./test_runner *test.so + displayName: 'Run tests, isolated release' - job: Ubuntu_1604_Vcpkg pool: vmImage: 'Ubuntu 16.04' @@ -224,6 +247,14 @@ jobs: inputs: workingDirectory: 'build.release' cmakeArgs: '-G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake ..' + - task: CMake@1 + inputs: + workingDirectory: 'build.debug.isolated' + cmakeArgs: '-G Ninja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake ..' + - task: CMake@1 + inputs: + workingDirectory: 'build.release.isolated' + cmakeArgs: '-G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake ..' - script: | cd build.debug ninja @@ -240,6 +271,22 @@ jobs: cd build.release/Release/Binaries ./test_runner *test.so displayName: 'Run tests, release' + - script: | + cd build.debug.isolated + ninja + displayName: 'Run ninja, isolated debug' + - script: | + cd build.debug.isolated/Release/Binaries + ./test_runner *test.so + displayName: 'Run Tests, isolated debug' + - script: | + cd build.release.isolated + ninja + displayName: 'Run ninja, isolated release' + - script: | + cd build.release.isolated/Release/Binaries + ./test_runner *test.so + displayName: 'Run tests, isolated release' - job: Android pool: vmImage: 'Ubuntu 16.04' From 052890e3e5b84d62eb562971d34c87adf649a8bb Mon Sep 17 00:00:00 2001 From: Jason Hartman Date: Wed, 24 Jul 2019 13:58:02 -0700 Subject: [PATCH 13/18] isolated component build fixes per Ubuntu - more explicit includes +cmake comment tweak --- Release/src/CMakeLists.txt | 4 ++-- Release/src/utilities/asyncrt_utils.cpp | 3 ++- Release/src/utilities/string_utils.cpp | 1 + 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Release/src/CMakeLists.txt b/Release/src/CMakeLists.txt index 1746b490ff..3d34fc9f35 100644 --- a/Release/src/CMakeLists.txt +++ b/Release/src/CMakeLists.txt @@ -61,7 +61,7 @@ target_link_libraries(cpprest PUBLIC cpprest_interface_PUBLIC PRIVATE cpprest_in set(CPPREST_TARGETS cpprest cpprest_interface_PUBLIC) if(NOT BUILD_SHARED_LIBS) # for installed static libraries the private dependencies must also be - # installed, though those should be interfaces only. + # "installed". As an interface it should not actually impact install. list(APPEND CPPREST_TARGETS cpprest_interface_PRIVATE) endif() @@ -121,7 +121,7 @@ function(add_sub_component name) # sources... list(APPEND CPPREST_TARGETS ${name}_properties_PUBLIC) if(NOT BUILD_SHARED_LIBS) # for installed static libraries the private dependencies must also be - # installed, though those should be interfaces only. + # "installed". Should be interfaces and not actually impact install. list(APPEND CPPREST_TARGETS ${name}_properties_PRIVATE) endif() set(CPPREST_TARGETS ${CPPREST_TARGETS} PARENT_SCOPE) diff --git a/Release/src/utilities/asyncrt_utils.cpp b/Release/src/utilities/asyncrt_utils.cpp index 72f3d97c3a..849d930ff1 100644 --- a/Release/src/utilities/asyncrt_utils.cpp +++ b/Release/src/utilities/asyncrt_utils.cpp @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -306,7 +307,7 @@ utility::string_t datetime::to_string(date_format format) const leftover); #endif // _MSC_VER outCursor += 25; - memcpy(outCursor, " GMT", 4); + std::memcpy(outCursor, " GMT", 4); outCursor += 4; return utility::string_t(outBuffer, outCursor); case ISO_8601: diff --git a/Release/src/utilities/string_utils.cpp b/Release/src/utilities/string_utils.cpp index 87f0edb415..5100546a6e 100644 --- a/Release/src/utilities/string_utils.cpp +++ b/Release/src/utilities/string_utils.cpp @@ -15,6 +15,7 @@ #include +#include #include #include #include From beaa3585b8b8a9d4426686767e9b499bb985c594 Mon Sep 17 00:00:00 2001 From: Jason Hartman Date: Wed, 24 Jul 2019 15:22:38 -0700 Subject: [PATCH 14/18] compile isolated components with -fPIC --- Release/src/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Release/src/CMakeLists.txt b/Release/src/CMakeLists.txt index 3d34fc9f35..8d46b3c2c4 100644 --- a/Release/src/CMakeLists.txt +++ b/Release/src/CMakeLists.txt @@ -95,6 +95,7 @@ function(add_sub_component name) # sources... PRIVATE nopch ) + set_target_properties(${name}_objects PROPERTIES POSITION_INDEPENDENT_CODE ON) target_link_libraries(${name}_objects PRIVATE ${name}_properties_PUBLIC ${name}_properties_PRIVATE) # create library of sub-component From 164309d3e0ceeb1baddcae542190c1ec6279d2e7 Mon Sep 17 00:00:00 2001 From: Jason Hartman Date: Wed, 24 Jul 2019 16:29:46 -0700 Subject: [PATCH 15/18] include boost/asio/ssl.hpp that fileio_posix.cpp used to get from stdafx.h's include of everything The exact dependency was not reviewed when making this fix. --- Release/src/streams/fileio_posix.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Release/src/streams/fileio_posix.cpp b/Release/src/streams/fileio_posix.cpp index 2404196423..0210660a9d 100644 --- a/Release/src/streams/fileio_posix.cpp +++ b/Release/src/streams/fileio_posix.cpp @@ -19,6 +19,8 @@ #include "cpprest/details/fileio.h" +#include + using namespace boost::asio; using namespace Concurrency::streams::details; From 690b36fc4a9601d8314162a9d35f2160e2076c81 Mon Sep 17 00:00:00 2001 From: Jason Hartman Date: Thu, 25 Jul 2019 11:05:33 -0700 Subject: [PATCH 16/18] more includes per isolated Ubuntu build --- Release/src/pplx/pplxlinux.cpp | 1 + Release/src/pplx/threadpool.cpp | 1 + Release/src/streams/fileio_posix.cpp | 2 ++ 3 files changed, 4 insertions(+) diff --git a/Release/src/pplx/pplxlinux.cpp b/Release/src/pplx/pplxlinux.cpp index 630a9e477f..ac5d92ecf9 100644 --- a/Release/src/pplx/pplxlinux.cpp +++ b/Release/src/pplx/pplxlinux.cpp @@ -16,6 +16,7 @@ #include "pplx/pplx.h" #include "pplx/threadpool.h" #include "sys/syscall.h" +#include #include #ifdef _WIN32 diff --git a/Release/src/pplx/threadpool.cpp b/Release/src/pplx/threadpool.cpp index 4fbea1ed93..a2fd471945 100644 --- a/Release/src/pplx/threadpool.cpp +++ b/Release/src/pplx/threadpool.cpp @@ -10,6 +10,7 @@ #include "pplx/threadpool.h" #include +#include #include #include #include diff --git a/Release/src/streams/fileio_posix.cpp b/Release/src/streams/fileio_posix.cpp index 0210660a9d..7396bd7b93 100644 --- a/Release/src/streams/fileio_posix.cpp +++ b/Release/src/streams/fileio_posix.cpp @@ -19,7 +19,9 @@ #include "cpprest/details/fileio.h" +#include "cpprest/asyncrt_utils.h" #include +#include using namespace boost::asio; using namespace Concurrency::streams::details; From 3caf23dcfcf573b79f5a820b7413d9bf8aecbe31 Mon Sep 17 00:00:00 2001 From: Jason Hartman Date: Thu, 25 Jul 2019 15:00:45 -0700 Subject: [PATCH 17/18] last of memcpy updates for isolated components --- Release/src/json/json_parsing.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Release/src/json/json_parsing.cpp b/Release/src/json/json_parsing.cpp index b6ab5e2ac1..8dd1b0585a 100644 --- a/Release/src/json/json_parsing.cpp +++ b/Release/src/json/json_parsing.cpp @@ -17,6 +17,7 @@ #include #include +#include #if defined(_MSC_VER) #pragma warning(disable : 4127) // allow expressions like while(true) pass @@ -826,7 +827,7 @@ bool JSON_StringParser::CompleteStringLiteral(typename JSON_Parser(token.string_val.c_str() + prevSize), start, numChars * sizeof(CharType)); + std::memcpy(const_cast(token.string_val.c_str() + prevSize), start, numChars * sizeof(CharType)); if (!JSON_StringParser::handle_unescape_char(token)) { @@ -847,7 +848,7 @@ bool JSON_StringParser::CompleteStringLiteral(typename JSON_Parser(token.string_val.c_str() + prevSize), start, numChars * sizeof(CharType)); + std::memcpy(const_cast(token.string_val.c_str() + prevSize), start, numChars * sizeof(CharType)); token.kind = JSON_Parser::Token::TKN_StringLiteral; From 5bd4d98ec6827173d2a5196100c94e8fcf4016db Mon Sep 17 00:00:00 2001 From: Jason Hartman Date: Thu, 25 Jul 2019 17:11:56 -0700 Subject: [PATCH 18/18] fix yaml for Ubuntu test step breakup --- azure-pipelines.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 3d3c676863..7b7aa47253 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -217,11 +217,11 @@ jobs: ./test_runner *test.so displayName: 'Run tests, release' - script: | - cd ../../../build.debug.isolated/Release/Binaries + cd build.debug.isolated/Release/Binaries ./test_runner *test.so displayName: 'Run tests, isolated debug' - script: | - cd ../../../build.release.isolated/Release/Binaries + cd build.release.isolated/Release/Binaries ./test_runner *test.so displayName: 'Run tests, isolated release' - job: Ubuntu_1604_Vcpkg