Changeset - 8f1f90064cf0
[Not reviewed]
! ! !
Jan Kaluza - 10 years ago 2015-11-19 15:19:14
jkaluza@redhat.com
Remove O2, add cpprestsdk
7 files changed:
0 comments (0 inline, 0 general)
3rdparty/CMakeLists.txt
Show inline comments
 
ADD_SUBDIRECTORY(o2)
 
ADD_SUBDIRECTORY(cpprestsdk)
3rdparty/cpprestsdk/CMakeLists.txt
Show inline comments
 
new file 100644
 
set(CMAKE_LEGACY_CYGWIN_WIN32 0)
 
cmake_minimum_required(VERSION 2.6)
 

	
 
enable_testing()
 

	
 
set(WARNINGS)
 
set(ANDROID_STL_FLAGS)
 

	
 
# Platform (not compiler) specific settings
 
if(IOS)
 
  set(IOS_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../Build_iOS")
 
  set(Boost_FRAMEWORK "-F ${IOS_SOURCE_DIR} -framework boost")
 
  set(Boost_INCLUDE_DIR "${IOS_SOURCE_DIR}/boost.framework/Headers")
 

	
 
  set(OPENSSL_FOUND 1)
 
  set(OPENSSL_INCLUDE_DIR "${IOS_SOURCE_DIR}/openssl/include")
 
  set(OPENSSL_LIBRARIES
 
    "${IOS_SOURCE_DIR}/openssl/lib/libcrypto.a"
 
    "${IOS_SOURCE_DIR}/openssl/lib/libssl.a"
 
    )
 

	
 
  # The cxx_flags must be reset here, because the ios-cmake toolchain file unfortunately sets "-headerpad_max_install_names" which is not a valid clang flag.
 
  set(CMAKE_CXX_FLAGS "-fvisibility=hidden -fvisibility-inlines-hidden")
 

	
 
  set(BUILD_SHARED_LIBS OFF)
 
  set(BUILD_SAMPLES OFF)
 
  option(BUILD_TESTS "Build tests." ON)
 
elseif(ANDROID)
 
  set(Boost_COMPILER "-clang")
 
  set(Boost_USE_STATIC_LIBS ON)
 
  if(ARM)
 
    set(BOOST_ROOT "${CMAKE_BINARY_DIR}/../Boost-for-Android/build")
 
    set(BOOST_LIBRARYDIR "${CMAKE_BINARY_DIR}/../Boost-for-Android/build/lib")
 
  else()
 
    set(BOOST_ROOT "${CMAKE_BINARY_DIR}/../Boost-for-Android-x86/build")
 
    set(BOOST_LIBRARYDIR "${CMAKE_BINARY_DIR}/../Boost-for-Android-x86/build/lib")
 
  endif()
 
  find_host_package(Boost 1.55 EXACT REQUIRED COMPONENTS random system thread filesystem chrono atomic)
 

	
 
  set(OPENSSL_FOUND 1)
 
  if(ARM)
 
    set(OPENSSL_INCLUDE_DIR "${CMAKE_BINARY_DIR}/../openssl/armeabi-v7a/include")
 
    set(OPENSSL_LIBRARIES
 
      "${CMAKE_BINARY_DIR}/../openssl/armeabi-v7a/lib/libssl.a"
 
      "${CMAKE_BINARY_DIR}/../openssl/armeabi-v7a/lib/libcrypto.a"
 
      )
 
  else()
 
    set(OPENSSL_INCLUDE_DIR "${CMAKE_BINARY_DIR}/../openssl/x86/include")
 
    set(OPENSSL_LIBRARIES
 
      "${CMAKE_BINARY_DIR}/../openssl/x86/lib/libssl.a"
 
      "${CMAKE_BINARY_DIR}/../openssl/x86/lib/libcrypto.a"
 
      )
 
  endif()
 

	
 
  if(ARM)
 
    set(LIBCXX_STL "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/4.8/libs/armeabi-v7a/thumb/libgnustl_static.a")
 
  else()
 
    set(LIBCXX_STL "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/4.8/libs/x86/libgnustl_static.a")
 
  endif()
 
  # These are used in the shared library case
 
  set(ANDROID_STL_FLAGS
 
    ${LIBCXX_STL}
 
    atomic
 
    dl
 
    gcc
 
    c
 
    m
 
    -nodefaultlibs
 
    )
 

	
 
  option(BUILD_SHARED_LIBS "Build shared Libraries." OFF)
 
  set(BUILD_SAMPLES OFF)
 
  option(BUILD_TESTS "Build tests." ON)
 
elseif(UNIX) # This includes OSX
 
  find_package(Boost REQUIRED COMPONENTS random chrono system thread regex filesystem)
 
  find_package(Threads REQUIRED)
 
  if(APPLE AND NOT OPENSSL_ROOT_DIR)
 
    # Prefer a homebrew version of OpenSSL over the one in /usr/lib
 
    file(GLOB OPENSSL_ROOT_DIR /usr/local/Cellar/openssl/*)
 
    # Prefer the latest (make the latest one first)
 
    list(REVERSE OPENSSL_ROOT_DIR)
 
  endif()
 
  # This should prevent linking against the system provided 0.9.8y
 
  set(_OPENSSL_VERSION "")
 
  find_package(OpenSSL 1.0.0 REQUIRED)
 

	
 
  option(BUILD_SHARED_LIBS "Build shared Libraries." ON)
 
  option(BUILD_TESTS "Build tests." OFF)
 
  option(BUILD_SAMPLES "Build samples." OFF)
 
  option(CASA_INSTALL_HEADERS "Install header files." ON)
 
  if(CASA_INSTALL_HEADERS)
 
    file(GLOB CASA_HEADERS_CPPREST include/cpprest/*.hpp include/cpprest/*.h include/cpprest/*.dat)
 
    install(FILES ${CASA_HEADERS_CPPREST} DESTINATION include/cpprest)
 
    file(GLOB CASA_HEADERS_PPLX include/pplx/*.hpp include/pplx/*.h)
 
    install(FILES ${CASA_HEADERS_PPLX} DESTINATION include/pplx)
 
    file(GLOB CASA_HEADERS_DETAILS include/cpprest/details/*.hpp include/cpprest/details/*.h include/cpprest/details/*.dat)
 
    install(FILES ${CASA_HEADERS_DETAILS} DESTINATION include/cpprest/details)
 
  endif()
 
elseif(WIN32)
 
  option(BUILD_SHARED_LIBS "Build shared Libraries." ON)
 
  option(BUILD_TESTS "Build tests." ON)
 
  option(BUILD_SAMPLES "Build samples." ON)
 
  option(Boost_USE_STATIC_LIBS ON)
 

	
 
  add_definitions(-DUNICODE -D_UNICODE)
 

	
 
  if(NOT BUILD_SHARED_LIBS)
 
    # This causes cmake to not link the test libraries separately, but instead hold onto their object files.
 
    set(TEST_LIBRARY_TARGET_TYPE OBJECT)
 
    set(Casablanca_DEFINITIONS -D_NO_ASYNCRTIMP -D_NO_PPLXIMP CACHE INTERNAL "Definitions for consume casablanca library")
 
  else()
 
    set(Casablanca_DEFINITIONS "" CACHE INTERNAL "Definitions for consume casablanca library")
 
  endif()
 
  add_definitions(${Casablanca_DEFINITIONS} -D_WINSOCK_DEPRECATED_NO_WARNINGS -DWIN32)
 

	
 
  find_package(Boost 1.55 REQUIRED COMPONENTS random system thread filesystem chrono atomic)
 
  find_package(OpenSSL 1.0 REQUIRED)
 
else()
 
  message(FATAL_ERROR "-- Unsupported Build Platform.")
 
endif()
 

	
 
# Compiler (not platform) specific settings
 
if(ANDROID)
 
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fno-strict-aliasing")
 
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-pedantic")
 
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-attributes -Wno-pointer-arith")
 
  include_directories(
 
    "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/4.8/include"
 
    "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/4.8/libs/armeabi-v7a/include"
 
    "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/4.8/include/backward"
 
    )
 
elseif((CMAKE_CXX_COMPILER_ID MATCHES "Clang") OR IOS)
 
  message("-- Setting clang options")
 

	
 
  set(WARNINGS "-Wall -Wextra -Wcast-qual -Wconversion -Wformat=2 -Winit-self -Winvalid-pch -Wmissing-format-attribute -Wmissing-include-dirs -Wpacked -Wredundant-decls")
 
  set(OSX_SUPPRESSIONS "-Wno-overloaded-virtual -Wno-sign-conversion -Wno-deprecated -Wno-unknown-pragmas -Wno-reorder -Wno-char-subscripts -Wno-switch -Wno-unused-parameter -Wno-unused-variable -Wno-deprecated -Wno-unused-value -Wno-unknown-warning-option -Wno-return-type-c-linkage -Wno-unused-function -Wno-sign-compare -Wno-shorten-64-to-32 -Wno-reorder")
 
  set(WARNINGS "${WARNINGS} ${OSX_SUPPRESSIONS}")
 

	
 
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++ -Wno-return-type-c-linkage -Wno-unneeded-internal-declaration")
 
  set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++")
 
  set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++11")
 

	
 
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fno-strict-aliasing")
 
elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
 
  message("-- Setting gcc options")
 

	
 
  set(WARNINGS "-Wall -Wextra -Wunused-parameter -Wcast-align -Wcast-qual -Wconversion -Wformat=2 -Winit-self -Winvalid-pch -Wmissing-format-attribute -Wmissing-include-dirs -Wpacked -Wredundant-decls -Wunreachable-code")
 

	
 
  set(LD_FLAGS "${LD_FLAGS} -Wl,-z,defs")
 

	
 
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fno-strict-aliasing")
 
elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
 
  message("-- Setting msvc options")
 
  set(WARNINGS)
 
else()
 
  message("-- Unknown compiler, success is doubtful.")
 
  message("CMAKE_CXX_COMPILER_ID=${CMAKE_CXX_COMPILER_ID}")
 
endif()
 

	
 
# Reconfigure final output directory
 
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/Binaries)
 
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/Binaries)
 
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/Binaries)
 

	
 
# These settings can be used by the test targets
 
set(Casablanca_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include)
 
set(Casablanca_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include ${Boost_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/libs/websocketpp)
 

	
 
set(Casablanca_LIBRARY ${LIB}cpprest)
 
set(Casablanca_LIBRARIES ${Casablanca_LIBRARY} ${Boost_LIBRARIES} ${Boost_FRAMEWORK})
 

	
 
# Everything in the project needs access to the casablanca include directories
 
include_directories(${Casablanca_INCLUDE_DIRS})
 

	
 
# Finally, the tests all use the same style declaration to build themselves, so we use a function
 
function(add_casablanca_test NAME SOURCES_VAR)
 
  add_library(${NAME} ${TEST_LIBRARY_TARGET_TYPE} ${${SOURCES_VAR}})
 
  message("-- Added test library ${NAME}")
 
  if (NOT TEST_LIBRARY_TARGET_TYPE STREQUAL "OBJECT")
 
    target_link_libraries(${NAME}
 
      ${LIB}httptest_utilities
 
      ${LIB}common_utilities
 
      ${LIB}unittestpp
 
      ${Casablanca_LIBRARIES}
 
      ${ANDROID_STL_FLAGS}
 
      )
 
    if (BUILD_SHARED_LIBS)
 
      add_test(NAME ${NAME}
 
        WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
 
        COMMAND test_runner lib${NAME}${CMAKE_SHARED_LIBRARY_SUFFIX}
 
        )
 
    endif()
 
  endif()
 
endfunction()
 

	
 
add_subdirectory(src)
 

	
 
if(BUILD_TESTS)
 
  add_subdirectory(tests)
 
endif()
 

	
 
if(BUILD_SAMPLES)
 
  add_subdirectory(samples)
 
endif()
3rdparty/cpprestsdk/dirs.proj
Show inline comments
 
new file 100644
 
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
 

	
 
  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), build.root))\Build\Common.Build.settings" />
 

	
 
  <ItemGroup>
 
    <ProjectFile Include="src\dirs.proj"/>
 
  </ItemGroup>
 
  
 
  <ItemGroup Condition="'$(BuildTests)'!=''">
 
    <ProjectFile Include="tests\dirs.proj" Condition="'$(Platform)'!='ARM' or '$(WindowsSDKDesktopARMSupport)' == 'true'"/>
 
    <ProjectFile Include="samples\dirs.proj" Condition="'$(Platform)'!='ARM' or '$(WindowsSDKDesktopARMSupport)' == 'true'"/> 
 
  </ItemGroup>
 

	
 
  <Import Project="$(TargetsPath)\Common.Build.Traversal.targets" />
 

	
 
</Project>
3rdparty/cpprestsdk/include/cpprest/astreambuf.h
Show inline comments
 
new file 100644
 
/***
 
* ==++==
 
*
 
* Copyright (c) Microsoft Corporation. All rights reserved.
 
* Licensed under the Apache License, Version 2.0 (the "License");
 
* you may not use this file except in compliance with the License.
 
* You may obtain a copy of the License at
 
* http://www.apache.org/licenses/LICENSE-2.0
 
*
 
* Unless required by applicable law or agreed to in writing, software
 
* distributed under the License is distributed on an "AS IS" BASIS,
 
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
* See the License for the specific language governing permissions and
 
* limitations under the License.
 
*
 
* ==--==
 
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
 
*
 
* Asynchronous I/O: stream buffer. This is an extension to the PPL concurrency features and therefore
 
* lives in the Concurrency namespace.
 
*
 
* For the latest on this and related APIs, please see http://casablanca.codeplex.com.
 
*
 
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 
****/
 
#pragma once
 

	
 
#include <ios>
 
#include <memory>
 
#include <cstring>
 
#include <math.h>
 

	
 
#include "pplx/pplxtasks.h"
 
#include "cpprest/details/basic_types.h"
 
#include "cpprest/asyncrt_utils.h"
 

	
 
namespace Concurrency
 
{
 
/// Library for asynchronous streams.
 
namespace streams
 
{
 
    /// <summary>
 
    /// Extending the standard char_traits type with one that adds values and types
 
    /// that are unique to "C++ REST SDK" streams.
 
    /// </summary>
 
    /// <typeparam name="_CharType">
 
    /// The data type of the basic element of the stream.
 
    /// </typeparam>
 
    template<typename _CharType>
 
    struct char_traits : std::char_traits<_CharType>
 
    {
 
        /// <summary>
 
        /// Some synchronous functions will return this value if the operation
 
        /// requires an asynchronous call in a given situation.
 
        /// </summary>
 
        /// <returns>An <c>int_type</c> value which implies that an asynchronous call is required.</returns>
 
        static typename std::char_traits<_CharType>::int_type requires_async() { return std::char_traits<_CharType>::eof()-1; }
 
    };
 
#if !defined(_WIN32)
 
    template<>
 
    struct char_traits<unsigned char> : private std::char_traits<char>
 
    {
 
    public:
 
        typedef unsigned char char_type;
 

	
 
        using std::char_traits<char>::eof;
 
        using std::char_traits<char>::int_type;
 
        using std::char_traits<char>::off_type;
 
        using std::char_traits<char>::pos_type;
 

	
 
        static size_t length(const unsigned char* str)
 
        {
 
            return std::char_traits<char>::length(reinterpret_cast<const char*>(str));
 
        }
 

	
 
        static void assign(unsigned char& left, const unsigned char& right) { left = right; }
 
        static unsigned char* assign(unsigned char* left, size_t n, unsigned char value)
 
        {
 
            return reinterpret_cast<unsigned char*>(std::char_traits<char>::assign(reinterpret_cast<char*>(left), n, static_cast<char>(value)));
 
        }
 

	
 
        static unsigned char* copy(unsigned char* left, const unsigned char* right, size_t n)
 
        {
 
            return reinterpret_cast<unsigned char*>(std::char_traits<char>::copy(reinterpret_cast<char*>(left), reinterpret_cast<const char*>(right), n));
 
        }
 

	
 
        static unsigned char* move(unsigned char* left, const unsigned char* right, size_t n)
 
        {
 
            return reinterpret_cast<unsigned char*>(std::char_traits<char>::move(reinterpret_cast<char*>(left), reinterpret_cast<const char*>(right), n));
 
        }
 

	
 
        static int_type requires_async() { return eof() - 1; }
 
    };
 
#endif
 

	
 
    namespace details {
 

	
 
    /// <summary>
 
    /// Stream buffer base class.
 
    /// </summary>
 
    template<typename _CharType>
 
    class basic_streambuf
 
    {
 
    public:
 
        typedef _CharType char_type;
 
        typedef ::concurrency::streams::char_traits<_CharType> traits;
 

	
 
        typedef typename traits::int_type int_type;
 
        typedef typename traits::pos_type pos_type;
 
        typedef typename traits::off_type off_type;
 

	
 

	
 
        /// <summary>
 
        /// Virtual constructor for stream buffers.
 
        /// </summary>
 
        virtual ~basic_streambuf() { }
 

	
 
        /// <summary>
 
        /// <c>can_read</c> is used to determine whether a stream buffer will support read operations (get).
 
        /// </summary>
 
        virtual bool can_read() const = 0;
 

	
 
        /// <summary>
 
        /// <c>can_write</c> is used to determine whether a stream buffer will support write operations (put).
 
        /// </summary>
 
        virtual bool can_write() const = 0;
 

	
 
        /// <summary>
 
        /// <c>can_seek<c/> is used to determine whether a stream buffer supports seeking.
 
        /// </summary>
 
        virtual bool can_seek() const = 0;
 

	
 
        /// <summary>
 
        /// <c>has_size<c/> is used to determine whether a stream buffer supports size().
 
        /// </summary>
 
        virtual bool has_size() const = 0;
 

	
 
        /// <summary>
 
        /// <c>is_eof</c> is used to determine whether a read head has reached the end of the buffer.
 
        /// </summary>
 
        virtual bool is_eof() const = 0;
 

	
 
        /// <summary>
 
        /// Gets the stream buffer size, if one has been set.
 
        /// </summary>
 
        /// <param name="direction">The direction of buffering (in or out)</param>
 
        /// <returns>The size of the internal buffer (for the given direction).</returns>
 
        /// <remarks>An implementation that does not support buffering will always return 0.</remarks>
 
        virtual size_t buffer_size(std::ios_base::openmode direction = std::ios_base::in) const = 0;
 

	
 
        /// <summary>
 
        /// Sets the stream buffer implementation to buffer or not buffer.
 
        /// </summary>
 
        /// <param name="size">The size to use for internal buffering, 0 if no buffering should be done.</param>
 
        /// <param name="direction">The direction of buffering (in or out)</param>
 
        /// <remarks>An implementation that does not support buffering will silently ignore calls to this function and it will not have any effect on what is returned by subsequent calls to <see cref="::buffer_size method" />.</remarks>
 
        virtual void set_buffer_size(size_t size, std::ios_base::openmode direction = std::ios_base::in) = 0;
 

	
 
        /// <summary>
 
        /// For any input stream, <c>in_avail</c> returns the number of characters that are immediately available
 
        /// to be consumed without blocking. May be used in conjunction with <cref="::sbumpc method"/> to read data without
 
        /// incurring the overhead of using tasks.
 
        /// </summary>
 
        virtual size_t in_avail() const = 0;
 

	
 
        /// <summary>
 
        /// Checks if the stream buffer is open.
 
        /// </summary>
 
        /// <remarks>No separation is made between open for reading and open for writing.</remarks>
 
        virtual bool is_open() const = 0;
 

	
 
        /// <summary>
 
        /// Closes the stream buffer, preventing further read or write operations.
 
        /// </summary>
 
        /// <param name="mode">The I/O mode (in or out) to close for.</param>
 
        virtual pplx::task<void> close(std::ios_base::openmode mode = (std::ios_base::in | std::ios_base::out)) = 0;
 

	
 
        /// <summary>
 
        /// Closes the stream buffer with an exception.
 
        /// </summary>
 
        /// <param name="mode">The I/O mode (in or out) to close for.</param>
 
        /// <param name="eptr">Pointer to the exception.</param>
 
        virtual pplx::task<void> close(std::ios_base::openmode mode, std::exception_ptr eptr) = 0;
 

	
 
        /// <summary>
 
        /// Writes a single character to the stream.
 
        /// </summary>
 
        /// <param name="ch">The character to write</param>
 
        /// <returns>A <c>task</c> that holds the value of the character. This value is EOF if the write operation fails.</returns>
 
        virtual pplx::task<int_type> putc(_CharType ch) = 0;
 

	
 
        /// <summary>
 
        /// Writes a number of characters to the stream.
 
        /// </summary>
 
        /// <param name="ptr">A pointer to the block of data to be written.</param>
 
        /// <param name="count">The number of characters to write.</param>
 
        /// <returns>A <c>task</c> that holds the number of characters actually written, either 'count' or 0.</returns>
 
        virtual pplx::task<size_t> putn(const _CharType *ptr, size_t count) = 0;
 

	
 
        /// <summary>
 
        /// Writes a number of characters to the stream. Note: callers must make sure the data to be written is valid until
 
        /// the returned task completes.
 
        /// </summary>
 
        /// <param name="ptr">A pointer to the block of data to be written.</param>
 
        /// <param name="count">The number of characters to write.</param>
 
        /// <returns>A <c>task</c> that holds the number of characters actually written, either 'count' or 0.</returns>
 
        virtual pplx::task<size_t> putn_nocopy(const _CharType *ptr, size_t count) = 0;
 

	
 
        /// <summary>
 
        /// Reads a single character from the stream and advances the read position.
 
        /// </summary>
 
        /// <returns>A <c>task</c> that holds the value of the character. This value is EOF if the read fails.</returns>
 
        virtual pplx::task<int_type> bumpc() = 0;
 

	
 
        /// <summary>
 
        /// Reads a single character from the stream and advances the read position.
 
        /// </summary>
 
        /// <returns>The value of the character. <c>-1</c> if the read fails. <c>-2</c> if an asynchronous read is required</returns>
 
        /// <remarks>This is a synchronous operation, but is guaranteed to never block.</remarks>
 
        virtual int_type sbumpc() = 0;
 

	
 
        /// <summary>
 
        /// Reads a single character from the stream without advancing the read position.
 
        /// </summary>
 
            /// <returns>A <c>task</c> that holds the value of the byte. This value is EOF if the read fails.</returns>
 
        virtual pplx::task<int_type> getc() = 0;
 

	
 
        /// <summary>
 
        /// Reads a single character from the stream without advancing the read position.
 
        /// </summary>
 
        /// <returns>The value of the character. EOF if the read fails. <see cref="::requires_async method" /> if an asynchronous read is required</returns>
 
        /// <remarks>This is a synchronous operation, but is guaranteed to never block.</remarks>
 
        virtual int_type sgetc() = 0;
 

	
 
        /// <summary>
 
        /// Advances the read position, then returns the next character without advancing again.
 
        /// </summary>
 
        /// <returns>A <c>task</c> that holds the value of the character. This value is EOF if the read fails.</returns>
 
        virtual pplx::task<int_type> nextc() = 0;
 

	
 
        /// <summary>
 
        /// Retreats the read position, then returns the current character without advancing.
 
        /// </summary>
 
        /// <returns>A <c>task</c> that holds the value of the character. This value is EOF if the read fails, <c>requires_async</c> if an asynchronous read is required</returns>
 
        virtual pplx::task<int_type> ungetc() = 0;
 

	
 
        /// <summary>
 
        /// Reads up to a given number of characters from the stream.
 
        /// </summary>
 
        /// <param name="ptr">The address of the target memory area.</param>
 
        /// <param name="count">The maximum number of characters to read.</param>
 
            /// <returns>A <c>task</c> that holds the number of characters read. This value is O if the end of the stream is reached.</returns>
 
        virtual pplx::task<size_t> getn(_Out_writes_(count) _CharType *ptr, _In_ size_t count) = 0;
 

	
 
        /// <summary>
 
        /// Copies up to a given number of characters from the stream, synchronously.
 
        /// </summary>
 
        /// <param name="ptr">The address of the target memory area.</param>
 
        /// <param name="count">The maximum number of characters to read.</param>
 
        /// <returns>The number of characters copied. O if the end of the stream is reached or an asynchronous read is required.</returns>
 
        /// <remarks>This is a synchronous operation, but is guaranteed to never block.</remarks>
 
        virtual size_t scopy(_Out_writes_(count) _CharType *ptr, _In_ size_t count) = 0;
 

	
 
        /// <summary>
 
        /// Gets the current read or write position in the stream.
 
        /// </summary>
 
        /// <param name="direction">The I/O direction to seek (see remarks)</param>
 
        /// <returns>The current position. EOF if the operation fails.</returns>
 
        /// <remarks>Some streams may have separate write and read cursors.
 
        ///          For such streams, the direction parameter defines whether to move the read or the write cursor.</remarks>
 
        virtual pos_type getpos(std::ios_base::openmode direction) const = 0;
 

	
 
        /// <summary>
 
        /// Gets the size of the stream, if known. Calls to <c>has_size</c> will determine whether
 
        /// the result of <c>size</c> can be relied on.
 
        /// </summary>
 
        virtual utility::size64_t size() const = 0;
 

	
 
        /// <summary>
 
        /// Seeks to the given position.
 
        /// </summary>
 
        /// <param name="pos">The offset from the beginning of the stream.</param>
 
        /// <param name="direction">The I/O direction to seek (see remarks).</param>
 
        /// <returns>The position. EOF if the operation fails.</returns>
 
        /// <remarks>Some streams may have separate write and read cursors. For such streams, the direction parameter defines whether to move the read or the write cursor.</remarks>
 
        virtual pos_type seekpos(pos_type pos, std::ios_base::openmode direction) = 0;
 

	
 
        /// <summary>
 
        /// Seeks to a position given by a relative offset.
 
        /// </summary>
 
        /// <param name="offset">The relative position to seek to</param>
 
        /// <param name="way">The starting point (beginning, end, current) for the seek.</param>
 
        /// <param name="mode">The I/O direction to seek (see remarks)</param>
 
        /// <returns>The position. EOF if the operation fails.</returns>
 
        /// <remarks>Some streams may have separate write and read cursors.
 
        ///          For such streams, the mode parameter defines whether to move the read or the write cursor.</remarks>
 
        virtual pos_type seekoff(off_type offset, std::ios_base::seekdir way, std::ios_base::openmode mode) = 0;
 

	
 
        /// <summary>
 
        /// For output streams, flush any internally buffered data to the underlying medium.
 
        /// </summary>
 
        /// <returns>A <c>task</c> that returns <c>true</c> if the sync succeeds, <c>false</c> if not.</returns>
 
        virtual pplx::task<void> sync() = 0;
 

	
 
        //
 
        // Efficient read and write.
 
        //
 
        // The following routines are intended to be used for more efficient, copy-free, reading and
 
        // writing of data from/to the stream. Rather than having the caller provide a buffer into which
 
        // data is written or from which it is read, the stream buffer provides a pointer directly to the
 
        // internal data blocks that it is using. Since not all stream buffers use internal data structures
 
        // to copy data, the functions may not be supported by all. An application that wishes to use this
 
        // functionality should therefore first try them and check for failure to support. If there is
 
        // such failure, the application should fall back on the copying interfaces (putn / getn)
 
        //
 

	
 
        /// <summary>
 
        /// Allocates a contiguous memory block and returns it.
 
        /// </summary>
 
        /// <param name="count">The number of characters to allocate.</param>
 
        /// <returns>A pointer to a block to write to, null if the stream buffer implementation does not support alloc/commit.</returns>
 
        virtual _CharType* alloc(_In_ size_t count) = 0;
 

	
 
        /// <summary>
 
        /// Submits a block already allocated by the stream buffer.
 
        /// </summary>
 
        /// <param name="count">The number of characters to be committed.</param>
 
        virtual void commit(_In_ size_t count) = 0;
 

	
 
        /// <summary>
 
        /// Gets a pointer to the next already allocated contiguous block of data.
 
        /// </summary>
 
        /// <param name="ptr">A reference to a pointer variable that will hold the address of the block on success.</param>
 
        /// <param name="count">The number of contiguous characters available at the address in 'ptr.'</param>
 
        /// <returns><c>true</c> if the operation succeeded, <c>false</c> otherwise.</returns>
 
        /// <remarks>
 
        /// A return of false does not necessarily indicate that a subsequent read operation would fail, only that
 
        /// there is no block to return immediately or that the stream buffer does not support the operation.
 
        /// The stream buffer may not de-allocate the block until <see cref="::release method" /> is called.
 
        /// If the end of the stream is reached, the function will return <c>true</c>, a null pointer, and a count of zero;
 
        /// a subsequent read will not succeed.
 
        /// </remarks>
 
        virtual bool acquire(_Out_ _CharType*& ptr, _Out_ size_t& count) = 0;
 

	
 
        /// <summary>
 
        /// Releases a block of data acquired using <see cref="::acquire method"/>. This frees the stream buffer to de-allocate the
 
        /// memory, if it so desires. Move the read position ahead by the count.
 
        /// </summary>
 
        /// <param name="ptr">A pointer to the block of data to be released.</param>
 
        /// <param name="count">The number of characters that were read.</param>
 
        virtual void release(_Out_writes_(count) _CharType *ptr, _In_ size_t count) = 0;
 

	
 
        /// <summary>
 
        /// Retrieves the stream buffer exception_ptr if it has been set.
 
        /// </summary>
 
        /// <returns>Pointer to the exception, if it has been set; otherwise, <c>nullptr</c> will be returned</returns>
 
        virtual std::exception_ptr exception() const = 0;
 
    };
 

	
 

	
 
    template<typename _CharType>
 
    class streambuf_state_manager : public basic_streambuf<_CharType>, public std::enable_shared_from_this<streambuf_state_manager<_CharType>>
 
    {
 
    public:
 
        typedef typename details::basic_streambuf<_CharType>::traits traits;
 
        typedef typename details::basic_streambuf<_CharType>::int_type int_type;
 
        typedef typename details::basic_streambuf<_CharType>::pos_type pos_type;
 
        typedef typename details::basic_streambuf<_CharType>::off_type off_type;
 

	
 
        /// <summary>
 
        /// <c>can_read</c> is used to determine whether a stream buffer will support read operations (get).
 
        /// </summary>
 
        virtual bool can_read() const
 
        {
 
            return m_stream_can_read;
 
        }
 

	
 
        /// <summary>
 
        /// <c>can_write</c> is used to determine whether a stream buffer will support write operations (put).
 
        /// </summary>
 
        virtual bool can_write() const
 
        {
 
            return m_stream_can_write;
 
        }
 

	
 
        /// <summary>
 
        /// Checks if the stream buffer is open.
 
        /// </summary>
 
        /// <remarks>No separation is made between open for reading and open for writing.</remarks>
 
        virtual bool is_open() const
 
        {
 
            return can_read() || can_write();
 
        }
 

	
 
        /// <summary>
 
        /// Closes the stream buffer, preventing further read or write operations.
 
        /// </summary>
 
        /// <param name="mode">The I/O mode (in or out) to close for.</param>
 
        virtual pplx::task<void> close(std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out)
 
        {
 
            pplx::task<void> closeOp = pplx::task_from_result();
 

	
 
            if (mode & std::ios_base::in && can_read()) {
 
                closeOp = _close_read();
 
            }
 

	
 
            // After the flush_internal task completed, "this" object may have been destroyed,
 
            // accessing the members is invalid, use shared_from_this to avoid access violation exception.
 
            auto this_ptr = std::static_pointer_cast<streambuf_state_manager>(this->shared_from_this());
 

	
 
            if (mode & std::ios_base::out && can_write()) {
 
                if (closeOp.is_done())
 
                    closeOp = closeOp && _close_write().then([this_ptr]{}); // passing down exceptions from closeOp
 
                else
 
                    closeOp = closeOp.then([this_ptr] { return this_ptr->_close_write().then([this_ptr]{}); });
 
            }
 

	
 
            return closeOp;
 
        }
 

	
 
        /// <summary>
 
        /// Closes the stream buffer with an exception.
 
        /// </summary>
 
        /// <param name="mode">The I/O mode (in or out) to close for.</param>
 
        /// <param name="eptr">Pointer to the exception.</param>
 
        virtual pplx::task<void> close(std::ios_base::openmode mode, std::exception_ptr eptr)
 
        {
 
            if (m_currentException == nullptr)
 
                m_currentException = eptr;
 
            return close(mode);
 
        }
 

	
 
        /// <summary>
 
        /// <c>is_eof</c> is used to determine whether a read head has reached the end of the buffer.
 
        /// </summary>
 
        virtual bool is_eof() const
 
        {
 
            return m_stream_read_eof;
 
        }
 

	
 
        /// <summary>
 
        /// Writes a single character to the stream.
 
        /// </summary>
 
        /// <param name="ch">The character to write</param>
 
        /// <returns>The value of the character. EOF if the write operation fails</returns>
 
        virtual pplx::task<int_type> putc(_CharType ch)
 
        {
 
            if (!can_write())
 
                return create_exception_checked_value_task<int_type>(traits::eof());
 

	
 
            return create_exception_checked_task<int_type>(_putc(ch), [](int_type) {
 
                return false; // no EOF for write
 
            });
 
        }
 

	
 
        /// <summary>
 
        /// Writes a number of characters to the stream.
 
        /// </summary>
 
        /// <param name="ptr">A pointer to the block of data to be written.</param>
 
        /// <param name="count">The number of characters to write.</param>
 
        /// <returns>The number of characters actually written, either 'count' or 0.</returns>
 
//         CASABLANCA_DEPRECATED("This API in some cases performs a copy. It is deprecated and will be removed in a future release. Use putn_nocopy instead.")
 
        virtual pplx::task<size_t> putn(const _CharType *ptr, size_t count)
 
        {
 
            if (!can_write())
 
                return create_exception_checked_value_task<size_t>(0);
 
            if (count == 0)
 
                return pplx::task_from_result<size_t>(0);
 

	
 
            return create_exception_checked_task<size_t>(_putn(ptr, count, true), [](size_t) {
 
                return false; // no EOF for write
 
            });
 
        }
 

	
 
        /// <summary>
 
        /// Writes a number of characters to the stream. Note: callers must make sure the data to be written is valid until
 
        /// the returned task completes.
 
        /// </summary>
 
        /// <param name="ptr">A pointer to the block of data to be written.</param>
 
        /// <param name="count">The number of characters to write.</param>
 
        /// <returns>A <c>task</c> that holds the number of characters actually written, either 'count' or 0.</returns>
 
        virtual pplx::task<size_t> putn_nocopy(const _CharType *ptr, size_t count)
 
        {
 
            if (!can_write())
 
                return create_exception_checked_value_task<size_t>(0);
 
            if (count == 0)
 
                return pplx::task_from_result<size_t>(0);
 

	
 
            return create_exception_checked_task<size_t>(_putn(ptr, count), [](size_t) {
 
                return false; // no EOF for write
 
            });
 
        }
 

	
 
        /// <summary>
 
        /// Reads a single character from the stream and advances the read position.
 
        /// </summary>
 
        /// <returns>The value of the character. EOF if the read fails.</returns>
 
        virtual pplx::task<int_type> bumpc()
 
        {
 
            if (!can_read())
 
                return create_exception_checked_value_task<int_type>(streambuf_state_manager<_CharType>::traits::eof());
 

	
 
            return create_exception_checked_task<int_type>(_bumpc(), [](int_type val) {
 
                return val == streambuf_state_manager<_CharType>::traits::eof();
 
            });
 
        }
 

	
 
        /// <summary>
 
        /// Reads a single character from the stream and advances the read position.
 
        /// </summary>
 
        /// <returns>The value of the character. <c>-1</c> if the read fails. <c>-2</c> if an asynchronous read is required</returns>
 
        /// <remarks>This is a synchronous operation, but is guaranteed to never block.</remarks>
 
        virtual int_type sbumpc()
 
        {
 
            if ( !(m_currentException == nullptr) )
 
                std::rethrow_exception(m_currentException);
 
            if (!can_read())
 
                return traits::eof();
 
            return check_sync_read_eof(_sbumpc());
 
        }
 

	
 
        /// <summary>
 
        /// Reads a single character from the stream without advancing the read position.
 
        /// </summary>
 
        /// <returns>The value of the byte. EOF if the read fails.</returns>
 
        virtual pplx::task<int_type> getc()
 
        {
 
            if (!can_read())
 
                return create_exception_checked_value_task<int_type>(traits::eof());
 

	
 
            return create_exception_checked_task<int_type>(_getc(), [](int_type val) {
 
                return val == streambuf_state_manager<_CharType>::traits::eof();
 
            });
 
        }
 

	
 
        /// <summary>
 
        /// Reads a single character from the stream without advancing the read position.
 
        /// </summary>
 
        /// <returns>The value of the character. EOF if the read fails. <see cref="::requires_async method" /> if an asynchronous read is required</returns>
 
        /// <remarks>This is a synchronous operation, but is guaranteed to never block.</remarks>
 
        virtual int_type sgetc()
 
        {
 
            if ( !(m_currentException == nullptr) )
 
                std::rethrow_exception(m_currentException);
 
            if (!can_read())
 
                return traits::eof();
 
            return check_sync_read_eof(_sgetc());
 
        }
 

	
 
        /// <summary>
 
        /// Advances the read position, then returns the next character without advancing again.
 
        /// </summary>
 
        /// <returns>The value of the character. EOF if the read fails.</returns>
 
        virtual pplx::task<int_type> nextc()
 
        {
 
            if (!can_read())
 
                return create_exception_checked_value_task<int_type>(traits::eof());
 

	
 
            return create_exception_checked_task<int_type>(_nextc(), [](int_type val) {
 
                return val == streambuf_state_manager<_CharType>::traits::eof();
 
            });
 
        }
 

	
 
        /// <summary>
 
        /// Retreats the read position, then returns the current character without advancing.
 
        /// </summary>
 
        /// <returns>The value of the character. EOF if the read fails. <see cref="::requires_async method" /> if an asynchronous read is required</returns>
 
        virtual pplx::task<int_type> ungetc()
 
        {
 
            if (!can_read())
 
                return create_exception_checked_value_task<int_type>(traits::eof());
 

	
 
            return create_exception_checked_task<int_type>(_ungetc(), [](int_type) {
 
                return false;
 
            });
 
        }
 

	
 
        /// <summary>
 
        /// Reads up to a given number of characters from the stream.
 
        /// </summary>
 
        /// <param name="ptr">The address of the target memory area.</param>
 
        /// <param name="count">The maximum number of characters to read.</param>
 
        /// <returns>The number of characters read. O if the end of the stream is reached.</returns>
 
        virtual pplx::task<size_t> getn(_Out_writes_(count) _CharType *ptr, _In_ size_t count)
 
        {
 
            if (!can_read())
 
                return create_exception_checked_value_task<size_t>(0);
 
            if (count == 0)
 
                return pplx::task_from_result<size_t>(0);
 

	
 
            return create_exception_checked_task<size_t>(_getn(ptr, count), [](size_t val) {
 
                return val == 0;
 
            });
 
        }
 

	
 
        /// <summary>
 
        /// Copies up to a given number of characters from the stream, synchronously.
 
        /// </summary>
 
        /// <param name="ptr">The address of the target memory area.</param>
 
        /// <param name="count">The maximum number of characters to read.</param>
 
        /// <returns>The number of characters copied. O if the end of the stream is reached or an asynchronous read is required.</returns>
 
        /// <remarks>This is a synchronous operation, but is guaranteed to never block.</remarks>
 
        virtual size_t scopy(_Out_writes_(count) _CharType *ptr, _In_ size_t count)
 
        {
 
            if ( !(m_currentException == nullptr) )
 
                std::rethrow_exception(m_currentException);
 
            if (!can_read())
 
                return 0;
 

	
 
            return _scopy(ptr, count);
 
        }
 

	
 
        /// <summary>
 
        /// For output streams, flush any internally buffered data to the underlying medium.
 
        /// </summary>
 
        /// <returns><c>true</c> if the flush succeeds, <c>false</c> if not</returns>
 
        virtual pplx::task<void> sync()
 
        {
 
            if (!can_write())
 
            {
 
                if (m_currentException == nullptr)
 
                    return pplx::task_from_result();
 
                else
 
                    return pplx::task_from_exception<void>(m_currentException);
 
            }
 
            return create_exception_checked_task<bool>(_sync(), [](bool) {
 
                return false;
 
            }).then([](bool){});
 
        }
 

	
 
        /// <summary>
 
        /// Retrieves the stream buffer exception_ptr if it has been set.
 
        /// </summary>
 
        /// <returns>Pointer to the exception, if it has been set; otherwise, <c>nullptr</c> will be returned.</returns>
 
        virtual std::exception_ptr exception() const
 
        {
 
            return m_currentException;
 
        }
 

	
 
        /// <summary>
 
        /// Allocates a contiguous memory block and returns it.
 
        /// </summary>
 
        /// <param name="count">The number of characters to allocate.</param>
 
        /// <returns>A pointer to a block to write to, null if the stream buffer implementation does not support alloc/commit.</returns>
 
        /// <remarks>This is intended as an advanced API to be used only when it is important to avoid extra copies.</remarks>
 
        _CharType* alloc(size_t count)
 
        {
 
            if (m_alloced)
 
                throw std::logic_error("The buffer is already allocated, this maybe caused by overlap of stream read or write");
 

	
 
            _CharType* alloc_result = _alloc(count);
 

	
 
            if (alloc_result)
 
                m_alloced = true;
 

	
 
            return alloc_result;
 
        }
 

	
 
        /// <summary>
 
        /// Submits a block already allocated by the stream buffer.
 
        /// </summary>
 
        /// <param name="count">The number of characters to be committed.</param>
 
        /// <remarks>This is intended as an advanced API to be used only when it is important to avoid extra copies.</remarks>
 
        void commit(size_t count)
 
        {
 
            if (!m_alloced)
 
                throw std::logic_error("The buffer needs to allocate first");
 

	
 
            _commit(count);
 
            m_alloced = false;
 
        }
 

	
 
    public:
 
        virtual bool can_seek() const = 0;
 
        virtual bool has_size() const = 0;
 
        virtual utility::size64_t size() const { return 0; }
 
        virtual size_t buffer_size(std::ios_base::openmode direction = std::ios_base::in) const = 0;
 
        virtual void set_buffer_size(size_t size, std::ios_base::openmode direction = std::ios_base::in) = 0;
 
        virtual size_t in_avail() const = 0;
 
        virtual pos_type getpos(std::ios_base::openmode direction) const = 0;
 
        virtual pos_type seekpos(pos_type pos, std::ios_base::openmode direction) = 0;
 
        virtual pos_type seekoff(off_type offset, std::ios_base::seekdir way, std::ios_base::openmode mode) = 0;
 
        virtual bool acquire(_Out_writes_(count) _CharType*& ptr, _In_ size_t& count) = 0;
 
        virtual void release(_Out_writes_(count) _CharType *ptr, _In_ size_t count) = 0;
 
    protected:
 
        virtual pplx::task<int_type> _putc(_CharType ch) = 0;
 

	
 
        // This API is only needed for file streams and until we remove the deprecated stream buffer putn overload.
 
        virtual pplx::task<size_t> _putn(const _CharType *ptr, size_t count, bool)
 
        {
 
            // Default to no copy, only the file streams API overloads and performs a copy.
 
            return _putn(ptr, count);
 
        }
 
        virtual pplx::task<size_t> _putn(const _CharType *ptr, size_t count) = 0;
 

	
 
        virtual pplx::task<int_type> _bumpc() = 0;
 
        virtual int_type _sbumpc() = 0;
 
        virtual pplx::task<int_type> _getc() = 0;
 
        virtual int_type _sgetc() = 0;
 
        virtual pplx::task<int_type> _nextc() = 0;
 
        virtual pplx::task<int_type> _ungetc() = 0;
 
        virtual pplx::task<size_t> _getn(_Out_writes_(count) _CharType *ptr, _In_ size_t count) = 0;
 
        virtual size_t _scopy(_Out_writes_(count) _CharType *ptr, _In_ size_t count) = 0;
 
        virtual pplx::task<bool> _sync() = 0;
 
        virtual _CharType* _alloc(size_t count) = 0;
 
        virtual void _commit(size_t count) = 0;
 

	
 
        /// <summary>
 
        /// The real read head close operation, implementation should override it if there is any resource to be released.
 
        /// </summary>
 
        virtual pplx::task<void> _close_read()
 
        {
 
            m_stream_can_read = false;
 
            return pplx::task_from_result();
 
        }
 

	
 
        /// <summary>
 
        /// The real write head close operation, implementation should override it if there is any resource to be released.
 
        /// </summary>
 
        virtual pplx::task<void> _close_write()
 
        {
 
            m_stream_can_write = false;
 
            return pplx::task_from_result();
 
        }
 

	
 
    protected:
 
        streambuf_state_manager(std::ios_base::openmode mode)
 
        {
 
            m_stream_can_read = (mode & std::ios_base::in) != 0;
 
            m_stream_can_write = (mode & std::ios_base::out) != 0;
 
            m_stream_read_eof = false;
 
            m_alloced = false;
 
        }
 

	
 
        std::exception_ptr m_currentException;
 
        // The in/out mode for the buffer
 
        bool m_stream_can_read, m_stream_can_write, m_stream_read_eof, m_alloced;
 

	
 

	
 
    private:
 
        template<typename _CharType1>
 
        pplx::task<_CharType1> create_exception_checked_value_task(const _CharType1 &val) const
 
        {
 
            if (this->exception() == nullptr)
 
                return pplx::task_from_result<_CharType1>(static_cast<_CharType1>(val));
 
            else
 
                return pplx::task_from_exception<_CharType1>(this->exception());
 
        }
 

	
 
        // Set exception and eof states for async read
 
        template<typename _CharType1>
 
        pplx::task<_CharType1> create_exception_checked_task(pplx::task<_CharType1> result, std::function<bool(_CharType1)> eof_test, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out)
 
        {
 
            auto thisPointer = this->shared_from_this();
 

	
 
            auto func1 = [=](pplx::task<_CharType1> t1) -> pplx::task<_CharType1> {
 
                try {
 
                    thisPointer->m_stream_read_eof = eof_test(t1.get());
 
                } catch (...) {
 
                    thisPointer->close(mode, std::current_exception()).get();
 
                    return pplx::task_from_exception<_CharType1>(thisPointer->exception(), pplx::task_options());
 
                }
 
                if (thisPointer->m_stream_read_eof && !(thisPointer->exception() == nullptr))
 
                    return pplx::task_from_exception<_CharType1>(thisPointer->exception(), pplx::task_options());
 
                return t1;
 
            };
 

	
 
            if ( result.is_done() )
 
            {
 
                // If the data is already available, we should avoid scheduling a continuation, so we do it inline.
 
                return func1(result);
 
            }
 
            else
 
            {
 
                return result.then(func1);
 
            }
 
        }
 

	
 
        // Set eof states for sync read
 
        int_type check_sync_read_eof(int_type ch)
 
        {
 
            m_stream_read_eof = ch == traits::eof();
 
            return ch;
 
        }
 

	
 
    };
 

	
 
    } // namespace details
 

	
 
    // Forward declarations
 
    template<typename _CharType> class basic_istream;
 
    template<typename _CharType> class basic_ostream;
 

	
 
    /// <summary>
 
    /// Reference-counted stream buffer.
 
    /// </summary>
 
    /// <typeparam name="_CharType">
 
    /// The data type of the basic element of the <c>streambuf.</c>
 
    /// </typeparam>
 
    /// <typeparam name="_CharType2">
 
    /// The data type of the basic element of the <c>streambuf.</c>
 
    /// </typeparam>
 
    template<typename _CharType>
 
    class streambuf : public details::basic_streambuf<_CharType>
 
    {
 
    public:
 
        typedef typename details::basic_streambuf<_CharType>::traits    traits;
 
        typedef typename details::basic_streambuf<_CharType>::int_type  int_type;
 
        typedef typename details::basic_streambuf<_CharType>::pos_type  pos_type;
 
        typedef typename details::basic_streambuf<_CharType>::off_type  off_type;
 
        typedef typename details::basic_streambuf<_CharType>::char_type char_type;
 

	
 
        template <typename _CharType2> friend class streambuf;
 

	
 
        /// <summary>
 
        /// Constructor.
 
        /// </summary>
 
        /// <param name="ptr">A pointer to the concrete stream buffer implementation.</param>
 
        streambuf(_In_ const std::shared_ptr<details::basic_streambuf<_CharType>> &ptr) : m_buffer(ptr) {}
 

	
 
        /// <summary>
 
        /// Default constructor.
 
        /// </summary>
 
        streambuf() { }
 

	
 
        /// <summary>
 
        /// Converter Constructor.
 
        /// </summary>
 
        /// <typeparam name="AlterCharType">
 
        /// The data type of the basic element of the source <c>streambuf</c>.
 
        /// </typeparam>
 
        /// <param name="other">The source buffer to be converted.</param>
 
        template <typename AlterCharType>
 
        streambuf(const streambuf<AlterCharType> &other) :
 
            m_buffer(std::static_pointer_cast<details::basic_streambuf<_CharType>>(std::static_pointer_cast<void>(other.m_buffer)))
 
        {
 
            static_assert(std::is_same<pos_type, typename details::basic_streambuf<AlterCharType>::pos_type>::value
 
                && std::is_same<off_type, typename details::basic_streambuf<AlterCharType>::off_type>::value
 
                && std::is_integral<_CharType>::value && std::is_integral<AlterCharType>::value
 
                && std::is_integral<int_type>::value && std::is_integral<typename details::basic_streambuf<AlterCharType>::int_type>::value
 
                && sizeof(_CharType) == sizeof(AlterCharType)
 
                && sizeof(int_type) == sizeof(typename details::basic_streambuf<AlterCharType>::int_type),
 
                "incompatible stream character types");
 
        }
 

	
 
        /// <summary>
 
        /// Constructs an input stream head for this stream buffer.
 
        /// </summary>
 
        /// <returns><c>basic_istream</c>.</returns>
 
        concurrency::streams::basic_istream<_CharType> create_istream() const
 
        {
 
            if (!can_read()) throw std::runtime_error("stream buffer not set up for input of data");
 
            return concurrency::streams::basic_istream<_CharType>(*this);
 
        }
 

	
 
        /// <summary>
 
        /// Constructs an output stream for this stream buffer.
 
        /// </summary>
 
        /// <returns>basic_ostream</returns>
 
        concurrency::streams::basic_ostream<_CharType> create_ostream() const
 
        {
 
            if (!can_write()) throw std::runtime_error("stream buffer not set up for output of data");
 
            return concurrency::streams::basic_ostream<_CharType>(*this);
 
        }
 

	
 
        /// <summary>
 
        /// Checks if the stream buffer has been initialized or not.
 
        /// </summary>
 
        operator bool() const { return (bool)m_buffer; }
 

	
 
        /// <summary>
 
        /// Destructor
 
        /// </summary>
 
        virtual ~streambuf() { }
 

	
 
        const std::shared_ptr<details::basic_streambuf<_CharType>> & get_base() const
 
        {
 
            if (!m_buffer)
 
            {
 
                throw std::invalid_argument("Invalid streambuf object");
 
            }
 

	
 
            return m_buffer;
 
        }
 

	
 
        /// <summary>
 
        /// <c>can_read</c> is used to determine whether a stream buffer will support read operations (get).
 
        /// </summary>
 
        virtual bool can_read() const { return get_base()->can_read(); }
 

	
 
        /// <summary>
 
        /// <c>can_write</c> is used to determine whether a stream buffer will support write operations (put).
 
        /// </summary>
 
        virtual bool can_write() const { return  get_base()->can_write(); }
 

	
 
        /// <summary>
 
        /// <c>can_seek</c> is used to determine whether a stream buffer supports seeking.
 
        /// </summary>
 
        /// <returns>True if seeking is supported, false otherwise.</returns>
 
        virtual bool can_seek() const { return get_base()->can_seek(); }
 

	
 
        /// <summary>
 
        /// <c>has_size</c> is used to determine whether a stream buffer supports size().
 
        /// </summary>
 
        /// <returns>True if the <c>size</c> API is supported, false otherwise.</returns>
 
        virtual bool has_size() const { return get_base()->has_size(); }
 

	
 
        /// <summary>
 
        /// Gets the total number of characters in the stream buffer, if known. Calls to <c>has_size</c> will determine whether
 
        /// the result of <c>size</c> can be relied on.
 
        /// </summary>
 
        /// <returns>The total number of characters in the stream buffer.</returns>
 
        virtual utility::size64_t size() const { return get_base()->size(); }
 

	
 
        /// <summary>
 
        /// Gets the stream buffer size, if one has been set.
 
        /// </summary>
 
        /// <param name="direction">The direction of buffering (in or out)</param>
 
        /// <returns>The size of the internal buffer (for the given direction).</returns>
 
        /// <remarks>An implementation that does not support buffering will always return 0.</remarks>
 
        virtual size_t buffer_size(std::ios_base::openmode direction = std::ios_base::in) const { return get_base()->buffer_size(direction); }
 

	
 
        /// <summary>
 
        /// Sets the stream buffer implementation to buffer or not buffer.
 
        /// </summary>
 
        /// <param name="size">The size to use for internal buffering, 0 if no buffering should be done.</param>
 
        /// <param name="direction">The direction of buffering (in or out)</param>
 
        /// <remarks>An implementation that does not support buffering will silently ignore calls to this function and it will not have any effect on what is returned by subsequent calls to <see cref="::buffer_size method" />.</remarks>
 
        virtual void set_buffer_size(size_t size, std::ios_base::openmode direction = std::ios_base::in) { get_base()->set_buffer_size(size,direction); }
 

	
 
        /// <summary>
 
        /// For any input stream, <c>in_avail</c> returns the number of characters that are immediately available
 
        /// to be consumed without blocking. May be used in conjunction with <cref="::sbumpc method"/> to read data without
 
        /// incurring the overhead of using tasks.
 
        /// </summary>
 
        /// <returns>Number of characters that are ready to read.</returns>
 
        virtual size_t in_avail() const { return get_base()->in_avail(); }
 

	
 
        /// <summary>
 
        /// Checks if the stream buffer is open.
 
        /// </summary>
 
        /// <remarks>No separation is made between open for reading and open for writing.</remarks>
 
        /// <returns>True if the stream buffer is open for reading or writing, false otherwise.</returns>
 
        virtual bool is_open() const { return get_base()->is_open(); }
 

	
 
        /// <summary>
 
        /// <c>is_eof</c> is used to determine whether a read head has reached the end of the buffer.
 
        /// </summary>
 
        /// <returns>True if at the end of the buffer, false otherwise.</returns>
 
        virtual bool is_eof() const { return get_base()->is_eof(); }
 

	
 
        /// <summary>
 
        /// Closes the stream buffer, preventing further read or write operations.
 
        /// </summary>
 
        /// <param name="mode">The I/O mode (in or out) to close for.</param>
 
        virtual pplx::task<void> close(std::ios_base::openmode mode = (std::ios_base::in | std::ios_base::out))
 
        {
 
            // We preserve the check here to workaround a Dev10 compiler crash
 
            auto buffer = get_base();
 
            return buffer ? buffer->close(mode) : pplx::task_from_result();
 
        }
 

	
 
        /// <summary>
 
        /// Closes the stream buffer with an exception.
 
        /// </summary>
 
        /// <param name="mode">The I/O mode (in or out) to close for.</param>
 
        /// <param name="eptr">Pointer to the exception.</param>
 
        virtual pplx::task<void> close(std::ios_base::openmode mode, std::exception_ptr eptr)
 
        {
 
            // We preserve the check here to workaround a Dev10 compiler crash
 
            auto buffer = get_base();
 
            return buffer ? buffer->close(mode, eptr) : pplx::task_from_result();
 
        }
 

	
 
        /// <summary>
 
        /// Writes a single character to the stream.
 
        /// </summary>
 
        /// <param name="ch">The character to write</param>
 
        /// <returns>The value of the character. EOF if the write operation fails</returns>
 
        virtual pplx::task<int_type> putc(_CharType ch)
 
        {
 
            return get_base()->putc(ch);
 
        }
 

	
 
        /// <summary>
 
        /// Allocates a contiguous memory block and returns it.
 
        /// </summary>
 
        /// <param name="count">The number of characters to allocate.</param>
 
        /// <returns>A pointer to a block to write to, null if the stream buffer implementation does not support alloc/commit.</returns>
 
        virtual _CharType* alloc(size_t count)
 
        {
 
            return get_base()->alloc(count);
 
        }
 

	
 
        /// <summary>
 
        /// Submits a block already allocated by the stream buffer.
 
        /// </summary>
 
        /// <param name="count">The number of characters to be committed.</param>
 
        virtual void commit(size_t count)
 
        {
 
            get_base()->commit(count);
 
        }
 

	
 
        /// <summary>
 
        /// Gets a pointer to the next already allocated contiguous block of data.
 
        /// </summary>
 
        /// <param name="ptr">A reference to a pointer variable that will hold the address of the block on success.</param>
 
        /// <param name="count">The number of contiguous characters available at the address in 'ptr.'</param>
 
        /// <returns><c>true</c> if the operation succeeded, <c>false</c> otherwise.</returns>
 
        /// <remarks>
 
        /// A return of false does not necessarily indicate that a subsequent read operation would fail, only that
 
        /// there is no block to return immediately or that the stream buffer does not support the operation.
 
        /// The stream buffer may not de-allocate the block until <see cref="::release method" /> is called.
 
        /// If the end of the stream is reached, the function will return <c>true</c>, a null pointer, and a count of zero;
 
        /// a subsequent read will not succeed.
 
        /// </remarks>
 
        virtual bool acquire(_Out_ _CharType*& ptr, _Out_ size_t& count)
 
        {
 
            ptr = nullptr;
 
            count = 0;
 
            return get_base()->acquire(ptr, count);
 
        }
 

	
 
        /// <summary>
 
        /// Releases a block of data acquired using <see cref="::acquire method"/>. This frees the stream buffer to de-allocate the
 
        /// memory, if it so desires. Move the read position ahead by the count.
 
        /// </summary>
 
        /// <param name="ptr">A pointer to the block of data to be released.</param>
 
        /// <param name="count">The number of characters that were read.</param>
 
        virtual void release(_Out_writes_(count) _CharType *ptr, _In_ size_t count)
 
        {
 
            get_base()->release(ptr, count);
 
        }
 

	
 
        /// <summary>
 
        /// Writes a number of characters to the stream.
 
        /// </summary>
 
        /// <param name="ptr">A pointer to the block of data to be written.</param>
 
        /// <param name="count">The number of characters to write.</param>
 
        /// <returns>The number of characters actually written, either 'count' or 0.</returns>
 
//         CASABLANCA_DEPRECATED("This API in some cases performs a copy. It is deprecated and will be removed in a future release. Use putn_nocopy instead.")
 
        virtual pplx::task<size_t> putn(const _CharType *ptr, size_t count)
 
        {
 
            return get_base()->putn(ptr, count);
 
        }
 

	
 
        /// <summary>
 
        /// Writes a number of characters to the stream. Note: callers must make sure the data to be written is valid until
 
        /// the returned task completes.
 
        /// </summary>
 
        /// <param name="ptr">A pointer to the block of data to be written.</param>
 
        /// <param name="count">The number of characters to write.</param>
 
        /// <returns>The number of characters actually written, either 'count' or 0.</returns>
 
        virtual pplx::task<size_t> putn_nocopy(const _CharType *ptr, size_t count)
 
        {
 
            return get_base()->putn_nocopy(ptr, count);
 
        }
 

	
 
        /// <summary>
 
        /// Reads a single character from the stream and advances the read position.
 
        /// </summary>
 
        /// <returns>The value of the character. EOF if the read fails.</returns>
 
        virtual pplx::task<int_type> bumpc()
 
        {
 
            return get_base()->bumpc();
 
        }
 

	
 
        /// <summary>
 
        /// Reads a single character from the stream and advances the read position.
 
        /// </summary>
 
        /// <returns>The value of the character. <c>-1</c> if the read fails. <c>-2</c> if an asynchronous read is required</returns>
 
        /// <remarks>This is a synchronous operation, but is guaranteed to never block.</remarks>
 
        virtual typename details::basic_streambuf<_CharType>::int_type sbumpc()
 
        {
 
            return get_base()->sbumpc();
 
        }
 

	
 
        /// <summary>
 
        /// Reads a single character from the stream without advancing the read position.
 
        /// </summary>
 
        /// <returns>The value of the byte. EOF if the read fails.</returns>
 
        virtual pplx::task<int_type> getc()
 
        {
 
            return get_base()->getc();
 
        }
 

	
 
        /// <summary>
 
        /// Reads a single character from the stream without advancing the read position.
 
        /// </summary>
 
        /// <returns>The value of the character. EOF if the read fails. <see cref="::requires_async method" /> if an asynchronous read is required</returns>
 
        /// <remarks>This is a synchronous operation, but is guaranteed to never block.</remarks>
 
        virtual typename details::basic_streambuf<_CharType>::int_type sgetc()
 
        {
 
            return get_base()->sgetc();
 
        }
 

	
 
        /// <summary>
 
        /// Advances the read position, then returns the next character without advancing again.
 
        /// </summary>
 
        /// <returns>The value of the character. EOF if the read fails.</returns>
 
        pplx::task<int_type> nextc()
 
        {
 
            return get_base()->nextc();
 
        }
 

	
 
        /// <summary>
 
        /// Retreats the read position, then returns the current character without advancing.
 
        /// </summary>
 
        /// <returns>The value of the character. EOF if the read fails. <see cref="::requires_async method" /> if an asynchronous read is required</returns>
 
        pplx::task<int_type> ungetc()
 
        {
 
            return get_base()->ungetc();
 
        }
 

	
 
        /// <summary>
 
        /// Reads up to a given number of characters from the stream.
 
        /// </summary>
 
        /// <param name="ptr">The address of the target memory area.</param>
 
        /// <param name="count">The maximum number of characters to read.</param>
 
        /// <returns>The number of characters read. O if the end of the stream is reached.</returns>
 
        virtual pplx::task<size_t> getn(_Out_writes_(count) _CharType *ptr, _In_ size_t count)
 
        {
 
            return get_base()->getn(ptr, count);
 
        }
 

	
 
        /// <summary>
 
        /// Copies up to a given number of characters from the stream, synchronously.
 
        /// </summary>
 
        /// <param name="ptr">The address of the target memory area.</param>
 
        /// <param name="count">The maximum number of characters to read.</param>
 
        /// <returns>The number of characters copied. O if the end of the stream is reached or an asynchronous read is required.</returns>
 
        /// <remarks>This is a synchronous operation, but is guaranteed to never block.</remarks>
 
        virtual size_t scopy(_Out_writes_(count) _CharType *ptr, _In_ size_t count)
 
        {
 
            return get_base()->scopy(ptr, count);
 
        }
 

	
 
        /// <summary>
 
        /// Gets the current read or write position in the stream.
 
        /// </summary>
 
        /// <param name="direction">The I/O direction to seek (see remarks)</param>
 
        /// <returns>The current position. EOF if the operation fails.</returns>
 
        /// <remarks>Some streams may have separate write and read cursors.
 
        ///          For such streams, the direction parameter defines whether to move the read or the write cursor.</remarks>
 
        virtual typename details::basic_streambuf<_CharType>::pos_type getpos(std::ios_base::openmode direction) const
 
        {
 
            return get_base()->getpos(direction);
 
        }
 

	
 
        /// <summary>
 
        /// Seeks to the given position.
 
        /// </summary>
 
        /// <param name="pos">The offset from the beginning of the stream.</param>
 
        /// <param name="direction">The I/O direction to seek (see remarks).</param>
 
        /// <returns>The position. EOF if the operation fails.</returns>
 
        /// <remarks>Some streams may have separate write and read cursors. For such streams, the direction parameter defines whether to move the read or the write cursor.</remarks>
 
        virtual typename details::basic_streambuf<_CharType>::pos_type seekpos(typename details::basic_streambuf<_CharType>::pos_type pos, std::ios_base::openmode direction)
 
        {
 
            return get_base()->seekpos(pos, direction);
 
        }
 

	
 
        /// <summary>
 
        /// Seeks to a position given by a relative offset.
 
        /// </summary>
 
        /// <param name="offset">The relative position to seek to</param>
 
        /// <param name="way">The starting point (beginning, end, current) for the seek.</param>
 
        /// <param name="mode">The I/O direction to seek (see remarks)</param>
 
        /// <returns>The position. EOF if the operation fails.</returns>
 
        /// <remarks>Some streams may have separate write and read cursors.
 
        ///          For such streams, the mode parameter defines whether to move the read or the write cursor.</remarks>
 
        virtual typename details::basic_streambuf<_CharType>::pos_type seekoff(typename details::basic_streambuf<_CharType>::off_type offset, std::ios_base::seekdir way, std::ios_base::openmode mode)
 
        {
 
            return get_base()->seekoff(offset, way, mode);
 
        }
 

	
 
        /// <summary>
 
        /// For output streams, flush any internally buffered data to the underlying medium.
 
        /// </summary>
 
        /// <returns><c>true</c> if the flush succeeds, <c>false</c> if not</returns>
 
        virtual pplx::task<void> sync()
 
        {
 
            return get_base()->sync();
 
        }
 

	
 
        /// <summary>
 
        /// Retrieves the stream buffer exception_ptr if it has been set.
 
        /// </summary>
 
        /// <returns>Pointer to the exception, if it has been set; otherwise, <c>nullptr</c> will be returned</returns>
 
        virtual std::exception_ptr exception() const
 
        {
 
            return get_base()->exception();
 
        }
 

	
 
    private:
 
        std::shared_ptr<details::basic_streambuf<_CharType>> m_buffer;
 

	
 
    };
 

	
 
}}
3rdparty/cpprestsdk/include/cpprest/asyncrt_utils.h
Show inline comments
 
new file 100644
 
/***
 
* ==++==
 
*
 
* Copyright (c) Microsoft Corporation. All rights reserved.
 
* Licensed under the Apache License, Version 2.0 (the "License");
 
* you may not use this file except in compliance with the License.
 
* You may obtain a copy of the License at
 
* http://www.apache.org/licenses/LICENSE-2.0
 
*
 
* Unless required by applicable law or agreed to in writing, software
 
* distributed under the License is distributed on an "AS IS" BASIS,
 
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
* See the License for the specific language governing permissions and
 
* limitations under the License.
 
*
 
* ==--==
 
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
 
*
 
* Various common utilities.
 
*
 
* For the latest on this and related APIs, please see http://casablanca.codeplex.com.
 
*
 
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 
****/
 

	
 
#pragma once
 

	
 
#include <string>
 
#include <vector>
 
#include <cstdint>
 
#include <system_error>
 
#include <random>
 
#include <locale.h>
 

	
 
#include "pplx/pplxtasks.h"
 
#include "cpprest/details/basic_types.h"
 

	
 
#if !defined(_WIN32) || (_MSC_VER >= 1700)
 
#include <chrono>
 
#endif
 

	
 
#ifndef _WIN32
 
#include <boost/algorithm/string.hpp>
 
#if !defined(ANDROID) && !defined(__ANDROID__) // CodePlex 269
 
#include <xlocale.h>
 
#endif
 
#endif
 

	
 
/// 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
 
{
 
    /// <summary>
 
    /// Converts a timespan/interval in seconds to xml duration string as specified by
 
    /// http://www.w3.org/TR/xmlschema-2/#duration
 
    /// </summary>
 
    _ASYNCRTIMP utility::string_t __cdecl seconds_to_xml_duration(utility::seconds numSecs);
 

	
 
    /// <summary>
 
    /// Converts an xml duration to timespan/interval in seconds
 
    /// http://www.w3.org/TR/xmlschema-2/#duration
 
    /// </summary>
 
    _ASYNCRTIMP utility::seconds __cdecl xml_duration_to_seconds(const utility::string_t &timespanString);
 
}
 

	
 
/// Functions for Unicode string conversions.
 
namespace conversions
 
{
 
    /// <summary>
 
    /// Converts a UTF-16 string to a UTF-8 string.
 
    /// </summary>
 
    /// <param name="w">A two byte character UTF-16 string.</param>
 
    /// <returns>A single byte character UTF-8 string.</returns>
 
    _ASYNCRTIMP std::string __cdecl utf16_to_utf8(const utf16string &w);
 

	
 
    /// <summary>
 
    /// Converts a UTF-8 string to a UTF-16
 
    /// </summary>
 
    /// <param name="s">A single byte character UTF-8 string.</param>
 
    /// <returns>A two byte character UTF-16 string.</returns>
 
    _ASYNCRTIMP utf16string __cdecl utf8_to_utf16(const std::string &s);
 

	
 
    /// <summary>
 
    /// Converts a ASCII (us-ascii) string to a UTF-16 string.
 
    /// </summary>
 
    /// <param name="s">A single byte character us-ascii string.</param>
 
    /// <returns>A two byte character UTF-16 string.</returns>
 
    _ASYNCRTIMP utf16string __cdecl usascii_to_utf16(const std::string &s);
 

	
 
    /// <summary>
 
    /// Converts a Latin1 (iso-8859-1) string to a UTF-16 string.
 
    /// </summary>
 
    /// <param name="s">A single byte character UTF-8 string.</param>
 
    /// <returns>A two byte character UTF-16 string.</returns>
 
    _ASYNCRTIMP utf16string __cdecl latin1_to_utf16(const std::string &s);
 

	
 
    /// <summary>
 
    /// Converts a Latin1 (iso-8859-1) string to a UTF-8 string.
 
    /// </summary>
 
    /// <param name="s">A single byte character UTF-8 string.</param>
 
    /// <returns>A single byte character UTF-8 string.</returns>
 
    _ASYNCRTIMP utf8string __cdecl latin1_to_utf8(const std::string &s);
 

	
 
    /// <summary>
 
    /// Converts to a platform dependent Unicode string type.
 
    /// </summary>
 
    /// <param name="s">A single byte character UTF-8 string.</param>
 
    /// <returns>A platform dependent string type.</returns>
 
    _ASYNCRTIMP utility::string_t __cdecl to_string_t(std::string &&s);
 

	
 
    /// <summary>
 
    /// Converts to a platform dependent Unicode string type.
 
    /// </summary>
 
    /// <param name="s">A two byte character UTF-16 string.</param>
 
    /// <returns>A platform dependent string type.</returns>
 
    _ASYNCRTIMP utility::string_t __cdecl to_string_t(utf16string &&s);
 

	
 
    /// <summary>
 
    /// Converts to a platform dependent Unicode string type.
 
    /// </summary>
 
    /// <param name="s">A single byte character UTF-8 string.</param>
 
    /// <returns>A platform dependent string type.</returns>
 
    _ASYNCRTIMP utility::string_t __cdecl to_string_t(const std::string &s);
 

	
 
    /// <summary>
 
    /// Converts to a platform dependent Unicode string type.
 
    /// </summary>
 
    /// <param name="s">A two byte character UTF-16 string.</param>
 
    /// <returns>A platform dependent string type.</returns>
 
    _ASYNCRTIMP utility::string_t __cdecl to_string_t(const utf16string &s);
 

	
 
    /// <summary>
 
    /// Converts to a UTF-16 from string.
 
    /// </summary>
 
    /// <param name="value">A single byte character UTF-8 string.</param>
 
    /// <returns>A two byte character UTF-16 string.</returns>
 
    _ASYNCRTIMP utf16string __cdecl to_utf16string(const std::string &value);
 

	
 
    /// <summary>
 
    /// Converts to a UTF-16 from string.
 
    /// </summary>
 
    /// <param name="value">A two byte character UTF-16 string.</param>
 
    /// <returns>A two byte character UTF-16 string.</returns>
 
    _ASYNCRTIMP utf16string __cdecl to_utf16string(utf16string value);
 

	
 
    /// <summary>
 
    /// Converts to a UTF-8 string.
 
    /// </summary>
 
    /// <param name="value">A single byte character UTF-8 string.</param>
 
    /// <returns>A single byte character UTF-8 string.</returns>
 
    _ASYNCRTIMP std::string __cdecl to_utf8string(std::string value);
 

	
 
    /// <summary>
 
    /// Converts to a UTF-8 string.
 
    /// </summary>
 
    /// <param name="value">A two byte character UTF-16 string.</param>
 
    /// <returns>A single byte character UTF-8 string.</returns>
 
    _ASYNCRTIMP std::string __cdecl to_utf8string(const utf16string &value);
 

	
 
    /// <summary>
 
    /// Encode the given byte array into a base64 string
 
    /// </summary>
 
    _ASYNCRTIMP utility::string_t __cdecl to_base64(const std::vector<unsigned char>& data);
 

	
 
    /// <summary>
 
    /// Encode the given 8-byte integer into a base64 string
 
    /// </summary>
 
    _ASYNCRTIMP utility::string_t __cdecl to_base64(uint64_t data);
 

	
 
    /// <summary>
 
    /// Decode the given base64 string to a byte array
 
    /// </summary>
 
    _ASYNCRTIMP std::vector<unsigned char> __cdecl from_base64(const utility::string_t& str);
 

	
 
    template <typename Source>
 
    utility::string_t print_string(const Source &val, const std::locale &loc)
 
    {
 
        utility::ostringstream_t oss;
 
        oss.imbue(loc);
 
        oss << val;
 
        if (oss.bad())
 
        {
 
            throw std::bad_cast();
 
        }
 
        return oss.str();
 
    }
 

	
 
    template <typename Source>
 
    utility::string_t print_string(const Source &val)
 
    {
 
        return print_string(val, std::locale());
 
    }
 

	
 
    template <typename Target>
 
    Target scan_string(const utility::string_t &str, const std::locale &loc)
 
    {
 
        Target t;
 
        utility::istringstream_t iss(str);
 
        iss.imbue(loc);
 
        iss >> t;
 
        if (iss.bad())
 
        {
 
            throw std::bad_cast();
 
        }
 
        return t;
 
    }
 

	
 
    template <typename Target>
 
    Target scan_string(const utility::string_t &str)
 
    {
 
        return scan_string<Target>(str, std::locale());
 
    }
 
}
 

	
 
namespace details
 
{
 
    /// <summary>
 
    /// Cross platform RAII container for setting thread local locale.
 
    /// </summary>
 
    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 &);
 
    };
 

	
 
    /// <summary>
 
    /// Our own implementation of alpha numeric instead of std::isalnum to avoid
 
    /// taking global lock for performance reasons.
 
    /// </summary>
 
    inline bool __cdecl is_alnum(char ch)
 
    {
 
        return (ch >= '0' && ch <= '9')
 
            || (ch >= 'A' && ch <= 'Z')
 
            || (ch >= 'a' && ch <= 'z');
 
    }
 

	
 
    /// <summary>
 
    /// Simplistic implementation of make_unique. A better implementation would be based on variadic templates
 
    /// and therefore not be compatible with Dev10.
 
    /// </summary>
 
    template <typename _Type>
 
    std::unique_ptr<_Type> make_unique() {
 
        return std::unique_ptr<_Type>(new _Type());
 
    }
 

	
 
    template <typename _Type, typename _Arg1>
 
    std::unique_ptr<_Type> make_unique(_Arg1&& arg1) {
 
        return std::unique_ptr<_Type>(new _Type(std::forward<_Arg1>(arg1)));
 
    }
 

	
 
    template <typename _Type, typename _Arg1, typename _Arg2>
 
    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 <typename _Type, typename _Arg1, typename _Arg2, typename _Arg3>
 
    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)));
 
    }
 

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

	
 
#ifdef _WIN32
 

	
 
/// <summary>
 
/// Category error type for Windows OS errors.
 
/// </summary>
 
class windows_category_impl : public std::error_category
 
{
 
public:
 
    virtual const char *name() const CPPREST_NOEXCEPT { return "windows"; }
 

	
 
    _ASYNCRTIMP virtual std::string message(int errorCode) const CPPREST_NOEXCEPT;
 

	
 
    _ASYNCRTIMP virtual std::error_condition default_error_condition(int errorCode) const CPPREST_NOEXCEPT;
 
};
 

	
 
/// <summary>
 
/// Gets the one global instance of the windows error category.
 
/// </summary>
 
/// </returns>An error category instance.</returns>
 
_ASYNCRTIMP const std::error_category & __cdecl windows_category();
 

	
 
#else
 

	
 
/// <summary>
 
/// Gets the one global instance of the linux error category.
 
/// </summary>
 
/// </returns>An error category instance.</returns>
 
_ASYNCRTIMP const std::error_category & __cdecl linux_category();
 

	
 
#endif
 

	
 
/// <summary>
 
/// Gets the one global instance of the current platform's error category.
 
/// <summary>
 
_ASYNCRTIMP const std::error_category & __cdecl platform_category();
 

	
 
/// <summary>
 
/// Creates an instance of std::system_error from a OS error code.
 
/// </summary>
 
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());
 
}
 

	
 
/// <summary>
 
/// Creates a std::error_code from a OS error code.
 
/// </summary>
 
inline std::error_code __cdecl create_error_code(unsigned long errorCode)
 
{
 
    return std::error_code((int)errorCode, platform_category());
 
}
 

	
 
/// <summary>
 
/// Creates the corresponding error message from a OS error code.
 
/// </summary>
 
inline utility::string_t __cdecl create_error_message(unsigned long errorCode)
 
{
 
    return utility::conversions::to_string_t(create_error_code(errorCode).message());
 
}
 

	
 
}
 

	
 
class datetime
 
{
 
public:
 
    typedef uint64_t interval_type;
 

	
 
    /// <summary>
 
    /// Defines the supported date and time string formats.
 
    /// </summary>
 
    enum date_format { RFC_1123, ISO_8601 };
 

	
 
    /// <summary>
 
    /// Returns the current UTC time.
 
    /// </summary>
 
    static _ASYNCRTIMP datetime __cdecl utc_now();
 

	
 
    /// <summary>
 
    /// An invalid UTC timestamp value.
 
    /// </summary>
 
    enum:interval_type { utc_timestamp_invalid = static_cast<interval_type>(-1) };
 

	
 
    /// <summary>
 
    /// Returns seconds since Unix/POSIX time epoch at 01-01-1970 00:00:00.
 
    /// If time is before epoch, utc_timestamp_invalid is returned.
 
    /// </summary>
 
    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)
 
    {
 
    }
 

	
 
    /// <summary>
 
    /// Creates <c>datetime</c> from a string representing time in UTC in RFC 1123 format.
 
    /// </summary>
 
    /// <returns>Returns a <c>datetime</c> of zero if not successful.</returns>
 
    static _ASYNCRTIMP datetime __cdecl from_string(const utility::string_t& timestring, date_format format = RFC_1123);
 

	
 
    /// <summary>
 
    /// Returns a string representation of the <c>datetime</c>.
 
    /// </summary>
 
    _ASYNCRTIMP utility::string_t to_string(date_format format = RFC_1123) const;
 

	
 
    /// <summary>
 
    /// Returns the integral time value.
 
    /// </summary>
 
    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<interval_type>(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;
 

	
 

	
 
#ifdef _WIN32
 
    // void* to avoid pulling in windows.h
 
    static _ASYNCRTIMP bool __cdecl datetime::system_type_to_datetime(/*SYSTEMTIME*/ void* psysTime, uint64_t seconds, datetime * pdt);
 
#else
 
    static datetime timeval_to_datetime(const timeval &time);
 
#endif
 

	
 
    // 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;
 
};
 

	
 
#ifndef _WIN32
 

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

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

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

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

	
 
#endif
 

	
 
inline int operator- (datetime t1, datetime t2)
 
{
 
    auto diff = (t1.m_interval - t2.m_interval);
 

	
 
    // Round it down to seconds
 
    diff /= 10 * 1000 * 1000;
 

	
 
    return static_cast<int>(diff);
 
}
 

	
 
/// <summary>
 
/// Nonce string generator class.
 
/// </summary>
 
class nonce_generator
 
{
 
public:
 

	
 
    /// <summary>
 
    /// Define default nonce length.
 
    /// </summary>
 
    enum { default_length = 32 };
 

	
 
    /// <summary>
 
    /// Nonce generator constructor.
 
    /// </summary>
 
    /// <param name="length">Length of the generated nonce string.</param>
 
    nonce_generator(int length=default_length) :
 
        m_random(static_cast<unsigned int>(utility::datetime::utc_timestamp())),
 
        m_length(length)
 
    {}
 

	
 
    /// <summary>
 
    /// Generate a nonce string containing random alphanumeric characters (A-Za-z0-9).
 
    /// Length of the generated string is set by length().
 
    /// </summary>
 
    /// <returns>The generated nonce string.</returns>
 
    _ASYNCRTIMP utility::string_t generate();
 

	
 
    /// <summary>
 
    /// Get length of generated nonce string.
 
    /// </summary>
 
    /// <returns>Nonce string length.</returns>
 
    int length() const { return m_length; }
 

	
 
    /// <summary>
 
    /// Set length of the generated nonce string.
 
    /// </summary>
 
    /// <param name="length">Lenght of nonce string.</param>
 
    void set_length(int length) { m_length = length; }
 

	
 
private:
 
    static const utility::string_t c_allowed_chars;
 
    std::mt19937 m_random;
 
    int m_length;
 
};
 

	
 
} // namespace utility;
3rdparty/cpprestsdk/include/cpprest/base_uri.h
Show inline comments
 
new file 100644
 
/***
 
* ==++==
 
*
 
* Copyright (c) Microsoft Corporation. All rights reserved.
 
* Licensed under the Apache License, Version 2.0 (the "License");
 
* you may not use this file except in compliance with the License.
 
* You may obtain a copy of the License at
 
* http://www.apache.org/licenses/LICENSE-2.0
 
*
 
* Unless required by applicable law or agreed to in writing, software
 
* distributed under the License is distributed on an "AS IS" BASIS,
 
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
* See the License for the specific language governing permissions and
 
* limitations under the License.
 
*
 
* ==--==
 
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
 
*
 
* Protocol independent support for URIs.
 
*
 
* For the latest on this and related APIs, please see http://casablanca.codeplex.com.
 
*
 
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 
****/
 

	
 
#pragma once
 

	
 
#include <map>
 
#include <memory>
 
#include <string>
 
#include <vector>
 
#include <functional>
 

	
 
#include "cpprest/asyncrt_utils.h"
 
#include "cpprest/details/basic_types.h"
 

	
 
namespace web {
 
    namespace details
 
    {
 
        struct uri_components
 
        {
 
            uri_components() : m_path(_XPLATSTR("/")), m_port(-1)
 
            {}
 

	
 
            uri_components(const uri_components &other) :
 
                m_scheme(other.m_scheme),
 
                m_host(other.m_host),
 
                m_user_info(other.m_user_info),
 
                m_path(other.m_path),
 
                m_query(other.m_query),
 
                m_fragment(other.m_fragment),
 
                m_port(other.m_port)
 
            {}
 

	
 
            uri_components & operator=(const uri_components &other)
 
            {
 
                if (this != &other)
 
                {
 
                    m_scheme = other.m_scheme;
 
                    m_host = other.m_host;
 
                    m_user_info = other.m_user_info;
 
                    m_path = other.m_path;
 
                    m_query = other.m_query;
 
                    m_fragment = other.m_fragment;
 
                    m_port = other.m_port;
 
                }
 
                return *this;
 
            }
 

	
 
            uri_components(uri_components &&other) CPPREST_NOEXCEPT :
 
                m_scheme(std::move(other.m_scheme)),
 
                m_host(std::move(other.m_host)),
 
                m_user_info(std::move(other.m_user_info)),
 
                m_path(std::move(other.m_path)),
 
                m_query(std::move(other.m_query)),
 
                m_fragment(std::move(other.m_fragment)),
 
                m_port(other.m_port)
 
            {}
 

	
 
            uri_components & operator=(uri_components &&other) CPPREST_NOEXCEPT
 
            {
 
                if (this != &other)
 
                {
 
                    m_scheme = std::move(other.m_scheme);
 
                    m_host = std::move(other.m_host);
 
                    m_user_info = std::move(other.m_user_info);
 
                    m_path = std::move(other.m_path);
 
                    m_query = std::move(other.m_query);
 
                    m_fragment = std::move(other.m_fragment);
 
                    m_port = other.m_port;
 
                }
 
                return *this;
 
            }
 

	
 
            _ASYNCRTIMP utility::string_t join();
 

	
 
            utility::string_t m_scheme;
 
            utility::string_t m_host;
 
            utility::string_t m_user_info;
 
            utility::string_t m_path;
 
            utility::string_t m_query;
 
            utility::string_t m_fragment;
 
            int m_port;
 
        };
 
    }
 

	
 
    /// <summary>
 
    /// A single exception type to represent errors in parsing, encoding, and decoding URIs.
 
    /// </summary>
 
    class uri_exception : public std::exception
 
    {
 
    public:
 

	
 
        uri_exception(std::string msg) : m_msg(std::move(msg)) {}
 

	
 
        ~uri_exception() CPPREST_NOEXCEPT {}
 

	
 
        const char* what() const CPPREST_NOEXCEPT
 
        {
 
            return m_msg.c_str();
 
        }
 

	
 
    private:
 
        std::string m_msg;
 
    };
 

	
 
    /// <summary>
 
    /// A flexible, protocol independent URI implementation.
 
    ///
 
    /// URI instances are immutable. Querying the various fields on an emtpy URI will return empty strings. Querying
 
    /// various diagnostic members on an empty URI will return false.
 
    /// </summary>
 
    /// <remarks>
 
    /// This implementation accepts both URIs ('http://msn.com/path') and URI relative-references
 
    /// ('/path?query#frag').
 
    ///
 
    /// This implementation does not provide any scheme-specific handling -- an example of this
 
    /// would be the following: 'http://path1/path'. This is a valid URI, but it's not a valid
 
    /// http-uri -- that is, it's syntactically correct but does not conform to the requirements
 
    /// of the http scheme (http requires a host).
 
    /// We could provide this by allowing a pluggable 'scheme' policy-class, which would provide
 
    /// extra capability for validating and canonicalizing a URI according to scheme, and would
 
    /// introduce a layer of type-safety for URIs of differing schemes, and thus differing semantics.
 
    ///
 
    /// One issue with implementing a scheme-independent URI facility is that of comparing for equality.
 
    /// For instance, these URIs are considered equal 'http://msn.com', 'http://msn.com:80'. That is --
 
    /// the 'default' port can be either omitted or explicit. Since we don't have a way to map a scheme
 
    /// to it's default port, we don't have a way to know these are equal. This is just one of a class of
 
    /// issues with regard to scheme-specific behavior.
 
    /// </remarks>
 
    class uri
 
    {
 
    public:
 

	
 
        /// <summary>
 
        /// The various components of a URI. This enum is used to indicate which
 
        /// URI component is being encoded to the encode_uri_component. This allows
 
        /// specific encoding to be performed.
 
        ///
 
        /// Scheme and port don't allow '%' so they don't need to be encoded.
 
        /// </summary>
 
        class components
 
        {
 
        public:
 
            enum component
 
            {
 
                user_info,
 
                host,
 
                path,
 
                query,
 
                fragment,
 
                full_uri
 
            };
 
        };
 

	
 
        /// <summary>
 
        /// Encodes a URI component according to RFC 3986.
 
        /// Note if a full URI is specified instead of an individual URI component all
 
        /// characters not in the unreserved set are escaped.
 
        /// </summary>
 
        /// <param name="raw">The URI as a string.</param>
 
        /// <returns>The encoded string.</returns>
 
        _ASYNCRTIMP static utility::string_t __cdecl encode_uri(const utility::string_t &raw, uri::components::component = components::full_uri);
 

	
 
        /// <summary>
 
        /// Encodes a string by converting all characters except for RFC 3986 unreserved characters to their
 
        /// hexadecimal representation.
 
        /// </summary>
 
        /// <param name="utf8data">The UTF-8 string data.</param>
 
        /// <returns>The encoded string.</returns>
 
        _ASYNCRTIMP static utility::string_t __cdecl encode_data_string(const utility::string_t &utf8data);
 

	
 
        /// <summary>
 
        /// Decodes an encoded string.
 
        /// </summary>
 
        /// <param name="encoded">The URI as a string.</param>
 
        /// <returns>The decoded string.</returns>
 
        _ASYNCRTIMP static utility::string_t __cdecl decode(const utility::string_t &encoded);
 

	
 
        /// <summary>
 
        /// Splits a path into its hierarchical components.
 
        /// </summary>
 
        /// <param name="path">The path as a string</param>
 
        /// <returns>A <c>std::vector&lt;utility::string_t&gt;</c> containing the segments in the path.</returns>
 
        _ASYNCRTIMP static std::vector<utility::string_t> __cdecl split_path(const utility::string_t &path);
 

	
 
        /// <summary>
 
        /// Splits a query into its key-value components.
 
        /// </summary>
 
        /// <param name="query">The query string</param>
 
        /// <returns>A <c>std::map&lt;utility::string_t, utility::string_t&gt;</c> containing the key-value components of the query.</returns>
 
        _ASYNCRTIMP static std::map<utility::string_t, utility::string_t> __cdecl split_query(const utility::string_t &query);
 

	
 
        /// <summary>
 
        /// Validates a string as a URI.
 
        /// </summary>
 
        /// <param name="uri_string">The URI string to be validated.</param>
 
        /// <returns><c>true</c> if the given string represents a valid URI, <c>false</c> otherwise.</returns>
 
        _ASYNCRTIMP static bool __cdecl validate(const utility::string_t &uri_string);
 

	
 
        /// <summary>
 
        /// Creates an empty uri
 
        /// </summary>
 
        uri() { m_uri = _XPLATSTR("/");};
 

	
 
        /// <summary>
 
        /// Creates a URI from the given encoded string. This will throw an exception if the string
 
        /// does not contain a valid URI. Use uri::validate if processing user-input.
 
        /// </summary>
 
        /// <param name="uri_string">A pointer to an encoded string to create the URI instance.</param>
 
        _ASYNCRTIMP uri(const utility::char_t *uri_string);
 

	
 
        /// <summary>
 
        /// Creates a URI from the given encoded string. This will throw an exception if the string
 
        /// does not contain a valid URI. Use uri::validate if processing user-input.
 
        /// </summary>
 
        /// <param name="uri_string">An encoded URI string to create the URI instance.</param>
 
        _ASYNCRTIMP uri(const utility::string_t &uri_string);
 

	
 
        /// <summary>
 
        /// Copy constructor.
 
        /// </summary>
 
        uri(const uri &other) :
 
            m_uri(other.m_uri),
 
            m_components(other.m_components)
 
        {}
 

	
 
        /// <summary>
 
        /// Copy assignment operator.
 
        /// </summary>
 
        uri & operator=(const uri &other)
 
        {
 
            if (this != &other)
 
            {
 
                m_uri = other.m_uri;
 
                m_components = other.m_components;
 
            }
 
            return *this;
 
        }
 

	
 
        /// <summary>
 
        /// Move constructor.
 
        /// </summary>
 
        uri(uri &&other) CPPREST_NOEXCEPT :
 
            m_uri(std::move(other.m_uri)),
 
            m_components(std::move(other.m_components))
 
        {}
 

	
 
        /// <summary>
 
        /// Move assignment operator
 
        /// </summary>
 
        uri & operator=(uri &&other) CPPREST_NOEXCEPT
 
        {
 
            if (this != &other)
 
            {
 
                m_uri = std::move(other.m_uri);
 
                m_components = std::move(other.m_components);
 
            }
 
            return *this;
 
        }
 

	
 
        /// <summary>
 
        /// Get the scheme component of the URI as an encoded string.
 
        /// </summary>
 
        /// <returns>The URI scheme as a string.</returns>
 
        const utility::string_t &scheme() const { return m_components.m_scheme; }
 

	
 
        /// <summary>
 
        /// Get the user information component of the URI as an encoded string.
 
        /// </summary>
 
        /// <returns>The URI user information as a string.</returns>
 
        const utility::string_t &user_info() const { return m_components.m_user_info; }
 

	
 
        /// <summary>
 
        /// Get the host component of the URI as an encoded string.
 
        /// </summary>
 
        /// <returns>The URI host as a string.</returns>
 
        const utility::string_t &host() const { return m_components.m_host; }
 

	
 
        /// <summary>
 
        /// Get the port component of the URI. Returns -1 if no port is specified.
 
        /// </summary>
 
        /// <returns>The URI port as an integer.</returns>
 
        int port() const { return m_components.m_port; }
 

	
 
        /// <summary>
 
        /// Get the path component of the URI as an encoded string.
 
        /// </summary>
 
        /// <returns>The URI path as a string.</returns>
 
        const utility::string_t &path() const { return m_components.m_path; }
 

	
 
        /// <summary>
 
        /// Get the query component of the URI as an encoded string.
 
        /// </summary>
 
        /// <returns>The URI query as a string.</returns>
 
        const utility::string_t &query() const { return m_components.m_query; }
 

	
 
        /// <summary>
 
        /// Get the fragment component of the URI as an encoded string.
 
        /// </summary>
 
        /// <returns>The URI fragment as a string.</returns>
 
        const utility::string_t &fragment() const { return m_components.m_fragment; }
 

	
 
        /// <summary>
 
        /// Creates a new uri object with the same authority portion as this one, omitting the resource and query portions.
 
        /// </summary>
 
        /// <returns>The new uri object with the same authority.</returns>
 
        _ASYNCRTIMP uri authority() const;
 

	
 
        /// <summary>
 
        /// Gets the path, query, and fragment portion of this uri, which may be empty.
 
        /// </summary>
 
        /// <returns>The new URI object with the path, query and fragment portion of this URI.</returns>
 
        _ASYNCRTIMP uri resource() const;
 

	
 
        /// <summary>
 
        /// An empty URI specifies no components, and serves as a default value
 
        /// </summary>
 
        bool is_empty() const
 
        {
 
            return this->m_uri.empty() || this->m_uri == _XPLATSTR("/");
 
        }
 

	
 
        /// <summary>
 
        /// A loopback URI is one which refers to a hostname or ip address with meaning only on the local machine.
 
        /// </summary>
 
        /// <remarks>
 
        /// Examples include "locahost", or ip addresses in the loopback range (127.0.0.0/24).
 
        /// </remarks>
 
        /// <returns><c>true</c> if this URI references the local host, <c>false</c> otherwise.</returns>
 
        bool is_host_loopback() const
 
        {
 
            return !is_empty() && ((host() == _XPLATSTR("localhost")) || (host().size() > 4 && host().substr(0,4) == _XPLATSTR("127.")));
 
        }
 

	
 
        /// <summary>
 
        /// A wildcard URI is one which refers to all hostnames that resolve to the local machine (using the * or +)
 
        /// </summary>
 
        /// <example>
 
        /// http://*:80
 
        /// </example>
 
        bool is_host_wildcard() const
 
        {
 
            return !is_empty() && (this->host() == _XPLATSTR("*") || this->host() == _XPLATSTR("+"));
 
        }
 

	
 
        /// <summary>
 
        /// A portable URI is one with a hostname that can be resolved globally (used from another machine).
 
        /// </summary>
 
        /// <returns><c>true</c> if this URI can be resolved globally (used from another machine), <c>false</c> otherwise.</returns>
 
        /// <remarks>
 
        /// The hostname "localhost" is a reserved name that is guaranteed to resolve to the local machine,
 
        /// and cannot be used for inter-machine communication. Likewise the hostnames "*" and "+" on Windows
 
        /// represent wildcards, and do not map to a resolvable address.
 
        /// </remarks>
 
        bool is_host_portable() const
 
        {
 
            return !(is_empty() || is_host_loopback() || is_host_wildcard());
 
        }
 

	
 
        // <summary>
 
        /// A default port is one where the port is unspecified, and will be determined by the operating system.
 
        /// The choice of default port may be dictated by the scheme (http -> 80) or not.
 
        /// </summary>
 
        /// <returns><c>true</c> if this URI instance has a default port, <c>false</c> otherwise.</returns>
 
        bool is_port_default() const
 
        {
 
            return !is_empty() && this->port() == 0;
 
        }
 

	
 
        /// <summary>
 
        /// An "authority" URI is one with only a scheme, optional userinfo, hostname, and (optional) port.
 
        /// </summary>
 
        /// <returns><c>true</c> if this is an "authority" URI, <c>false</c> otherwise.</returns>
 
        bool is_authority() const
 
        {
 
            return !is_empty() && is_path_empty() && query().empty() && fragment().empty();
 
        }
 

	
 
        /// <summary>
 
        /// Returns whether the other URI has the same authority as this one
 
        /// </summary>
 
        /// <param name="other">The URI to compare the authority with.</param>
 
        /// <returns><c>true</c> if both the URI's have the same authority, <c>false</c> otherwise.</returns>
 
        bool has_same_authority(const uri &other) const
 
        {
 
            return !is_empty() && this->authority() == other.authority();
 
        }
 

	
 
        /// <summary>
 
        /// Returns whether the path portion of this URI is empty
 
        /// </summary>
 
        /// <returns><c>true</c> if the path portion of this URI is empty, <c>false</c> otherwise.</returns>
 
        bool is_path_empty() const
 
        {
 
            return path().empty() || path() == _XPLATSTR("/");
 
        }
 

	
 
        /// <summary>
 
        /// Returns the full (encoded) URI as a string.
 
        /// </summary>
 
         /// <returns>The full encoded URI string.</returns>
 
        utility::string_t to_string() const
 
        {
 
            return m_uri;
 
        }
 

	
 
        _ASYNCRTIMP bool operator == (const uri &other) const;
 

	
 
        bool operator < (const uri &other) const
 
        {
 
            return m_uri < other.m_uri;
 
        }
 

	
 
        bool operator != (const uri &other) const
 
        {
 
            return !(this->operator == (other));
 
        }
 

	
 
    private:
 
        friend class uri_builder;
 

	
 
        // Encodes all characters not in given set determined by given function.
 
        static utility::string_t encode_impl(const utility::string_t &raw, const std::function<bool(int)>& should_encode);
 

	
 
        utility::string_t m_uri;
 
        details::uri_components m_components;
 
    };
 

	
 
} // namespace web
3rdparty/cpprestsdk/include/cpprest/containerstream.h
Show inline comments
 
new file 100644
 
/***
 
* ==++==
 
*
 
* Copyright (c) Microsoft Corporation. All rights reserved.
 
* Licensed under the Apache License, Version 2.0 (the "License");
 
* you may not use this file except in compliance with the License.
 
* You may obtain a copy of the License at
 
* http://www.apache.org/licenses/LICENSE-2.0
 
*
 
* Unless required by applicable law or agreed to in writing, software
 
* distributed under the License is distributed on an "AS IS" BASIS,
 
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
* See the License for the specific language governing permissions and
 
* limitations under the License.
 
*
 
* ==--==
 
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
 
*
 
* This file defines a basic STL-container-based stream buffer. Reading from the buffer will not remove any data
 
* from it and seeking is thus supported.
 
*
 
* For the latest on this and related APIs, please see http://casablanca.codeplex.com.
 
*
 
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 
****/
 
#pragma once
 

	
 
#include <vector>
 
#include <queue>
 
#include <algorithm>
 
#include <iterator>
 

	
 
#include "pplx/pplxtasks.h"
 
#include "cpprest/astreambuf.h"
 
#include "cpprest/streams.h"
 

	
 
namespace Concurrency { namespace streams {
 

	
 
    // Forward declarations
 

	
 
    template<typename _CollectionType> class container_buffer;
 

	
 
    namespace details {
 

	
 
    /// <summary>
 
    /// The basic_container_buffer class serves as a memory-based steam buffer that supports writing or reading
 
    /// sequences of characters.
 
    /// The class itself should not be used in application code, it is used by the stream definitions farther down in the header file.
 
    /// </summary>
 
    /// <remarks> When closed, neither writing nor reading is supported any longer. <c>basic_container_buffer</c> does not support simultaneous use of the buffer
 
    /// for reading and writing.</remarks>
 
    template<typename _CollectionType>
 
    class basic_container_buffer : public streams::details::streambuf_state_manager<typename _CollectionType::value_type>
 
    {
 
    public:
 
        typedef typename _CollectionType::value_type _CharType;
 
        typedef typename basic_streambuf<_CharType>::traits traits;
 
        typedef typename basic_streambuf<_CharType>::int_type int_type;
 
        typedef typename basic_streambuf<_CharType>::pos_type pos_type;
 
        typedef typename basic_streambuf<_CharType>::off_type off_type;
 

	
 
        /// <summary>
 
        /// Returns the underlying data container
 
        /// </summary>
 
        _CollectionType& collection()
 
        {
 
            return m_data;
 
        }
 

	
 
        /// <summary>
 
        /// Destructor
 
        /// </summary>
 
        virtual ~basic_container_buffer()
 
        {
 
            // Invoke the synchronous versions since we need to
 
            // purge the request queue before deleting the buffer
 
            this->_close_read();
 
            this->_close_write();
 
        }
 

	
 

	
 
    protected:
 
        /// <summary>
 
        /// can_seek is used to determine whether a stream buffer supports seeking.
 
        /// </summary>
 
        virtual bool can_seek() const { return this->is_open(); }
 

	
 
        /// <summary>
 
        /// <c>has_size<c/> is used to determine whether a stream buffer supports size().
 
        /// </summary>
 
        virtual bool has_size() const { return this->is_open(); }
 

	
 
        /// <summary>
 
        /// Gets the size of the stream, if known. Calls to <c>has_size</c> will determine whether
 
        /// the result of <c>size</c> can be relied on.
 
        /// </summary>
 
        virtual utility::size64_t size() const
 
        {
 
            return utility::size64_t(m_data.size());
 
        }
 

	
 
        /// <summary>
 
        /// Get the stream buffer size, if one has been set.
 
        /// </summary>
 
        /// <param name="direction">The direction of buffering (in or out)</param>
 
        /// <remarks>An implementation that does not support buffering will always return '0'.</remarks>
 
        virtual size_t buffer_size(std::ios_base::openmode = std::ios_base::in) const
 
        {
 
            return 0;
 
        }
 

	
 
        /// <summary>
 
        /// Sets the stream buffer implementation to buffer or not buffer.
 
        /// </summary>
 
        /// <param name="size">The size to use for internal buffering, 0 if no buffering should be done.</param>
 
        /// <param name="direction">The direction of buffering (in or out)</param>
 
        /// <remarks>An implementation that does not support buffering will silently ignore calls to this function and it will not have any effect on what is returned by subsequent calls to <see cref="::buffer_size method" />.</remarks>
 
        virtual void set_buffer_size(size_t , std::ios_base::openmode = std::ios_base::in)
 
        {
 
            return;
 
        }
 

	
 
        /// <summary>
 
        /// For any input stream, <c>in_avail</c> returns the number of characters that are immediately available
 
        /// to be consumed without blocking. May be used in conjunction with <cref="::sbumpc method"/> to read data without
 
        /// incurring the overhead of using tasks.
 
        /// </summary>
 
        virtual size_t in_avail() const
 
        {
 
            // See the comment in seek around the restriction that we do not allow read head to
 
            // seek beyond the current write_end.
 
            _ASSERTE(m_current_position <= m_data.size());
 

	
 
            msl::safeint3::SafeInt<size_t> readhead(m_current_position);
 
            msl::safeint3::SafeInt<size_t> writeend(m_data.size());
 
            return (size_t)(writeend - readhead);
 
        }
 

	
 
        virtual pplx::task<bool> _sync()
 
        {
 
            return pplx::task_from_result(true);
 
        }
 

	
 
        virtual pplx::task<int_type> _putc(_CharType ch)
 
        {
 
            int_type retVal = (this->write(&ch, 1) == 1) ? static_cast<int_type>(ch) : traits::eof();
 
            return pplx::task_from_result<int_type>(retVal);
 
        }
 

	
 
        virtual pplx::task<size_t> _putn(const _CharType *ptr, size_t count)
 
        {
 
            return pplx::task_from_result<size_t>(this->write(ptr, count));
 
        }
 

	
 
        /// <summary>
 
        /// Allocates a contiguous memory block and returns it.
 
        /// </summary>
 
        /// <param name="count">The number of characters to allocate.</param>
 
        /// <returns>A pointer to a block to write to, null if the stream buffer implementation does not support alloc/commit.</returns>
 
        _CharType* _alloc(size_t count)
 
        {
 
            if (!this->can_write()) return nullptr;
 

	
 
            // Allocate space
 
            resize_for_write(m_current_position+count);
 

	
 
            // Let the caller copy the data
 
            return (_CharType*)&m_data[m_current_position];
 
        }
 

	
 
        /// <summary>
 
        /// Submits a block already allocated by the stream buffer.
 
        /// </summary>
 
        /// <param name="count">The number of characters to be committed.</param>
 
        void _commit(size_t actual )
 
        {
 
            // Update the write position and satisfy any pending reads
 
            update_current_position(m_current_position+actual);
 
        }
 

	
 
        /// <summary>
 
        /// Gets a pointer to the next already allocated contiguous block of data.
 
        /// </summary>
 
        /// <param name="ptr">A reference to a pointer variable that will hold the address of the block on success.</param>
 
        /// <param name="count">The number of contiguous characters available at the address in 'ptr.'</param>
 
        /// <returns><c>true</c> if the operation succeeded, <c>false</c> otherwise.</returns>
 
        /// <remarks>
 
        /// A return of false does not necessarily indicate that a subsequent read operation would fail, only that
 
        /// there is no block to return immediately or that the stream buffer does not support the operation.
 
        /// The stream buffer may not de-allocate the block until <see cref="::release method" /> is called.
 
        /// If the end of the stream is reached, the function will return <c>true</c>, a null pointer, and a count of zero;
 
        /// a subsequent read will not succeed.
 
        /// </remarks>
 
        virtual bool acquire(_Out_ _CharType*& ptr, _Out_ size_t& count)
 
        {
 
            ptr = nullptr;
 
            count = 0;
 

	
 
            if (!this->can_read()) return false;
 

	
 
            count = in_avail();
 

	
 
            if (count > 0)
 
            {
 
                ptr = (_CharType*)&m_data[m_current_position];
 
                return true;
 
            }
 
            else
 
            {
 
                // Can only be open for read OR write, not both. If there is no data then
 
                // we have reached the end of the stream so indicate such with true.
 
                return true;
 
            }
 
        }
 

	
 
        /// <summary>
 
        /// Releases a block of data acquired using <see cref="::acquire method"/>. This frees the stream buffer to de-allocate the
 
        /// memory, if it so desires. Move the read position ahead by the count.
 
        /// </summary>
 
        /// <param name="ptr">A pointer to the block of data to be released.</param>
 
        /// <param name="count">The number of characters that were read.</param>
 
        virtual void release(_Out_writes_opt_ (count) _CharType *ptr, _In_ size_t count)
 
        {
 
            if (ptr != nullptr)
 
                update_current_position(m_current_position + count);
 
        }
 

	
 
        virtual pplx::task<size_t> _getn(_Out_writes_ (count) _CharType *ptr, _In_ size_t count)
 
        {
 
            return pplx::task_from_result(this->read(ptr, count));
 
        }
 

	
 
        size_t _sgetn(_Out_writes_ (count) _CharType *ptr, _In_ size_t count)
 
        {
 
            return this->read(ptr, count);
 
        }
 

	
 
        virtual size_t _scopy(_Out_writes_ (count) _CharType *ptr, _In_ size_t count)
 
        {
 
            return this->read(ptr, count, false);
 
        }
 

	
 
        virtual pplx::task<int_type> _bumpc()
 
        {
 
            return pplx::task_from_result(this->read_byte(true));
 
        }
 

	
 
        virtual int_type _sbumpc()
 
        {
 
            return this->read_byte(true);
 
        }
 

	
 
        virtual pplx::task<int_type> _getc()
 
        {
 
            return pplx::task_from_result(this->read_byte(false));
 
        }
 

	
 
        int_type _sgetc()
 
        {
 
            return this->read_byte(false);
 
        }
 

	
 
        virtual pplx::task<int_type> _nextc()
 
        {
 
            this->read_byte(true);
 
            return pplx::task_from_result(this->read_byte(false));
 
        }
 

	
 
        virtual pplx::task<int_type> _ungetc()
 
        {
 
            auto pos = seekoff(-1, std::ios_base::cur, std::ios_base::in);
 
            if ( pos == (pos_type)traits::eof())
 
                return pplx::task_from_result(traits::eof());
 
            return this->getc();
 
        }
 

	
 
        /// <summary>
 
        /// Gets the current read or write position in the stream.
 
        /// </summary>
 
        /// <param name="direction">The I/O direction to seek (see remarks)</param>
 
        /// <returns>The current position. EOF if the operation fails.</returns>
 
        /// <remarks>Some streams may have separate write and read cursors.
 
        ///          For such streams, the direction parameter defines whether to move the read or the write cursor.</remarks>
 
        virtual pos_type getpos(std::ios_base::openmode mode) const
 
        {
 
            if ( ((mode & std::ios_base::in) && !this->can_read()) ||
 
                 ((mode & std::ios_base::out) && !this->can_write()))
 
                 return static_cast<pos_type>(traits::eof());
 

	
 
            return static_cast<pos_type>(m_current_position);
 
        }
 

	
 
        /// <summary>
 
        /// Seeks to the given position.
 
        /// </summary>
 
        /// <param name="pos">The offset from the beginning of the stream.</param>
 
        /// <param name="direction">The I/O direction to seek (see remarks).</param>
 
        /// <returns>The position. EOF if the operation fails.</returns>
 
        /// <remarks>Some streams may have separate write and read cursors. For such streams, the direction parameter defines whether to move the read or the write cursor.</remarks>
 
        virtual pos_type seekpos(pos_type position, std::ios_base::openmode mode)
 
        {
 
            pos_type beg(0);
 

	
 
            // In order to support relative seeking from the end position we need to fix an end position.
 
            // Technically, there is no end for the stream buffer as new writes would just expand the buffer.
 
            // For now, we assume that the current write_end is the end of the buffer. We use this artificial
 
            // end to restrict the read head from seeking beyond what is available.
 

	
 
            pos_type end(m_data.size());
 

	
 
            if (position >= beg)
 
            {
 
                auto pos = static_cast<size_t>(position);
 

	
 
                // Read head
 
                if ((mode & std::ios_base::in) && this->can_read())
 
                {
 
                    if (position <= end)
 
                    {
 
                        // We do not allow reads to seek beyond the end or before the start position.
 
                        update_current_position(pos);
 
                        return static_cast<pos_type>(m_current_position);
 
                    }
 
                }
 

	
 
                // Write head
 
                if ((mode & std::ios_base::out) && this->can_write())
 
                {
 
                    // Allocate space
 
                    resize_for_write(pos);
 

	
 
                    // Nothing to really copy
 

	
 
                    // Update write head and satisfy read requests if any
 
                    update_current_position(pos);
 

	
 
                    return static_cast<pos_type>(m_current_position);
 
                }
 
            }
 

	
 
            return static_cast<pos_type>(traits::eof());
 
        }
 

	
 
        /// <summary>
 
        /// Seeks to a position given by a relative offset.
 
        /// </summary>
 
        /// <param name="offset">The relative position to seek to</param>
 
        /// <param name="way">The starting point (beginning, end, current) for the seek.</param>
 
        /// <param name="mode">The I/O direction to seek (see remarks)</param>
 
        /// <returns>The position. EOF if the operation fails.</returns>
 
        /// <remarks>Some streams may have separate write and read cursors.
 
        ///          For such streams, the mode parameter defines whether to move the read or the write cursor.</remarks>
 
        virtual pos_type seekoff(off_type offset, std::ios_base::seekdir way, std::ios_base::openmode mode)
 
        {
 
            pos_type beg = 0;
 
            pos_type cur = static_cast<pos_type>(m_current_position);
 
            pos_type end = static_cast<pos_type>(m_data.size());
 

	
 
            switch ( way )
 
            {
 
            case std::ios_base::beg:
 
                return seekpos(beg + offset, mode);
 

	
 
            case std::ios_base::cur:
 
                return seekpos(cur + offset, mode);
 

	
 
            case std::ios_base::end:
 
                return seekpos(end + offset, mode);
 

	
 
            default:
 
                return static_cast<pos_type>(traits::eof());
 
            }
 
        }
 

	
 
    private:
 
        template<typename _CollectionType1> friend class streams::container_buffer;
 

	
 
        /// <summary>
 
        /// Constructor
 
        /// </summary>
 
        basic_container_buffer(std::ios_base::openmode mode)
 
            : streambuf_state_manager<typename _CollectionType::value_type>(mode),
 
              m_current_position(0)
 
        {
 
            validate_mode(mode);
 
        }
 

	
 
        /// <summary>
 
        /// Constructor
 
        /// </summary>
 
        basic_container_buffer(_CollectionType data, std::ios_base::openmode mode)
 
            : streambuf_state_manager<typename _CollectionType::value_type>(mode),
 
              m_data(std::move(data)),
 
              m_current_position((mode & std::ios_base::in) ? 0 : m_data.size())
 
        {
 
            validate_mode(mode);
 
        }
 

	
 
        static void validate_mode(std::ios_base::openmode mode)
 
        {
 
            // Disallow simultaneous use of the stream buffer for writing and reading.
 
            if ((mode & std::ios_base::in) && (mode & std::ios_base::out))
 
                throw std::invalid_argument("this combination of modes on container stream not supported");
 
        }
 

	
 
        /// <summary>
 
        /// Determine if the request can be satisfied.
 
        /// </summary>
 
        bool can_satisfy(size_t)
 
        {
 
            // We can always satisfy a read, at least partially, unless the
 
            // read position is at the very end of the buffer.
 
            return (in_avail() > 0);
 
        }
 

	
 
        /// <summary>
 
        /// Reads a byte from the stream and returns it as int_type.
 
        /// Note: This routine shall only be called if can_satisfy() returned true.
 
        /// </summary>
 
        int_type read_byte(bool advance = true)
 
        {
 
            _CharType value;
 
            auto read_size = this->read(&value, 1, advance);
 
            return read_size == 1 ? static_cast<int_type>(value) : traits::eof();
 
        }
 

	
 
        /// <summary>
 
        /// Reads up to count characters into ptr and returns the count of characters copied.
 
        /// The return value (actual characters copied) could be <= count.
 
        /// Note: This routine shall only be called if can_satisfy() returned true.
 
        /// </summary>
 
        size_t read(_Out_writes_ (count) _CharType *ptr, _In_ size_t count, bool advance = true)
 
        {
 
            if (!can_satisfy(count))
 
                return 0;
 

	
 
            msl::safeint3::SafeInt<size_t> request_size(count);
 
            msl::safeint3::SafeInt<size_t> read_size = request_size.Min(in_avail());
 

	
 
            size_t newPos = m_current_position + read_size;
 

	
 
            auto readBegin = begin(m_data) + m_current_position;
 
            auto readEnd = begin(m_data) + newPos;
 

	
 
#ifdef _WIN32
 
            // Avoid warning C4996: Use checked iterators under SECURE_SCL
 
            std::copy(readBegin, readEnd, stdext::checked_array_iterator<_CharType *>(ptr, count));
 
#else
 
            std::copy(readBegin, readEnd, ptr);
 
#endif // _WIN32
 

	
 
            if (advance)
 
            {
 
                update_current_position(newPos);
 
            }
 

	
 
            return (size_t) read_size;
 
        }
 

	
 
        /// <summary>
 
        /// Write count characters from the ptr into the stream buffer
 
        /// </summary>
 
        size_t write(const _CharType *ptr, size_t count)
 
        {
 
            if (!this->can_write() || (count == 0)) return 0;
 

	
 
            auto newSize = m_current_position + count;
 

	
 
            // Allocate space
 
            resize_for_write(newSize);
 

	
 
            // Copy the data
 
            std::copy(ptr, ptr + count, begin(m_data) + m_current_position);
 

	
 
            // Update write head and satisfy pending reads if any
 
            update_current_position(newSize);
 

	
 
            return count;
 
        }
 

	
 
        /// <summary>
 
        /// Resize the underlying container to match the new write head
 
        /// </summary>
 
        void resize_for_write(size_t newPos)
 
        {
 
            // Resize the container if required
 
            if (newPos > m_data.size())
 
            {
 
                m_data.resize(newPos);
 
            }
 
        }
 

	
 
        /// <summary>
 
        /// Updates the write head to the new position
 
        /// </summary>
 
        void update_current_position(size_t newPos)
 
        {
 
            // The new write head
 
            m_current_position = newPos;
 
            _ASSERTE(m_current_position <= m_data.size());
 
        }
 

	
 
        // The actual data store
 
        _CollectionType m_data;
 

	
 
        // Read/write head
 
        size_t m_current_position;
 
    };
 

	
 
    } // namespace details
 

	
 
    /// <summary>
 
    /// The basic_container_buffer class serves as a memory-based steam buffer that supports writing or reading
 
    /// sequences of characters. Note that it cannot be used as a consumer producer buffer.
 
    /// </summary>
 
    /// <typeparam name="_CollectionType">
 
    /// The type of the container.
 
    /// </typeparam>
 
    /// <remarks>
 
    /// This is a reference-counted version of <c>basic_container_buffer</c>.
 
    /// </remarks>
 
    template<typename _CollectionType>
 
    class container_buffer : public streambuf<typename _CollectionType::value_type>
 
    {
 
    public:
 
        typedef typename _CollectionType::value_type char_type;
 

	
 
        /// <summary>
 
        /// Creates a container_buffer given a collection, copying its data into the buffer.
 
        /// </summary>
 
        /// <param name="data">The collection that is the starting point for the buffer</param>
 
        /// <param name="mode">The I/O mode that the buffer should use (in / out)</param>
 
        container_buffer(_CollectionType data, std::ios_base::openmode mode = std::ios_base::in)
 
            : streambuf<typename _CollectionType::value_type>(
 
                std::shared_ptr<details::basic_container_buffer<_CollectionType>>(new streams::details::basic_container_buffer<_CollectionType>(std::move(data), mode)))
 
        {
 
        }
 

	
 
        /// <summary>
 
        /// Creates a container_buffer starting from an empty collection.
 
        /// </summary>
 
        /// <param name="mode">The I/O mode that the buffer should use (in / out)</param>
 
        container_buffer(std::ios_base::openmode mode = std::ios_base::out)
 
            : streambuf<typename _CollectionType::value_type>(
 
                std::shared_ptr<details::basic_container_buffer<_CollectionType>>(new details::basic_container_buffer<_CollectionType>(mode)))
 
        {
 
        }
 

	
 
        _CollectionType& collection() const
 
        {
 
            auto listBuf = static_cast<details::basic_container_buffer<_CollectionType> *>(this->get_base().get());
 
            return listBuf->collection();
 
        }
 
    };
 

	
 
    /// <summary>
 
    /// A static class to allow users to create input and out streams based off STL
 
    /// collections. The sole purpose of this class to avoid users from having to know
 
    /// anything about stream buffers.
 
    /// </summary>
 
    /// <typeparam name="_CollectionType">The type of the STL collection.</typeparam>
 
    template<typename _CollectionType>
 
    class container_stream
 
    {
 
    public:
 

	
 
        typedef typename _CollectionType::value_type char_type;
 
        typedef container_buffer<_CollectionType> buffer_type;
 

	
 
        /// <summary>
 
        /// Creates an input stream given an STL container.
 
        /// </summary>
 
        /// </param name="data">STL container to back the input stream.</param>
 
        /// <returns>An input stream.</returns>
 
        static concurrency::streams::basic_istream<char_type> open_istream(_CollectionType data)
 
        {
 
            return concurrency::streams::basic_istream<char_type>(buffer_type(std::move(data), std::ios_base::in));
 
        }
 

	
 
        /// <summary>
 
        /// Creates an output stream using an STL container as the storage.
 
        /// </summary>
 
        /// <returns>An output stream.</returns>
 
        static concurrency::streams::basic_ostream<char_type> open_ostream()
 
        {
 
            return concurrency::streams::basic_ostream<char_type>(buffer_type(std::ios_base::out));
 
        }
 
    };
 

	
 
    /// <summary>
 
    /// The stringstream allows an input stream to be constructed from std::string or std::wstring
 
    /// For output streams the underlying string container could be retrieved using <c>buf-&gt;collection().</c>
 
    /// </summary>
 
    typedef container_stream<std::basic_string<char>> stringstream;
 
    typedef stringstream::buffer_type stringstreambuf;
 

	
 
    typedef container_stream<utility::string_t> wstringstream;
 
    typedef wstringstream::buffer_type wstringstreambuf;
 

	
 
    /// <summary>
 
    /// The <c>bytestream</c> is a static class that allows an input stream to be constructed from any STL container.
 
    /// </summary>
 
    class bytestream
 
    {
 
    public:
 

	
 
        /// <summary>
 
        /// Creates a single byte character input stream given an STL container.
 
        /// </summary>
 
        /// <typeparam name="_CollectionType">The type of the STL collection.</typeparam>
 
        /// <param name="data">STL container to back the input stream.</param>
 
        /// <returns>An single byte character input stream.</returns>
 
        template<typename _CollectionType>
 
        static concurrency::streams::istream open_istream(_CollectionType data)
 
        {
 
            return concurrency::streams::istream(streams::container_buffer<_CollectionType>(std::move(data), std::ios_base::in));
 
        }
 

	
 
        /// <summary>
 
        /// Creates a single byte character output stream using an STL container as storage.
 
        /// </summary>
 
        /// <typeparam name="_CollectionType">The type of the STL collection.</typeparam>
 
        /// <returns>A single byte character output stream.</returns>
 
        template<typename _CollectionType>
 
        static concurrency::streams::ostream open_ostream()
 
        {
 
            return concurrency::streams::ostream(streams::container_buffer<_CollectionType>());
 
        }
 
};
 

	
 

	
 
}} // namespaces

Changeset was too big and was cut off... Show full diff anyway

0 comments (0 inline, 0 general)